Move handle_iq to iq module

xmppftw created

Change summary

xmpp/src/iq/mod.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++++
xmpp/src/lib.rs    |  95 +------------------------------------------
2 files changed, 108 insertions(+), 92 deletions(-)

Detailed changes

xmpp/src/iq/mod.rs 🔗

@@ -0,0 +1,105 @@
+// Copyright (c) 2023 xmpp-rs contributors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use tokio_xmpp::parsers::{
+    disco::DiscoInfoQuery,
+    iq::{Iq, IqType},
+    ns,
+    private::Query as PrivateXMLQuery,
+    roster::Roster,
+    stanza_error::{DefinedCondition, ErrorType, StanzaError},
+};
+
+use crate::{handle_upload_result, pubsub, Agent, Event};
+
+pub async fn handle_iq(agent: &mut Agent, iq: Iq) -> Vec<Event> {
+    let mut events = vec![];
+    let from = iq
+        .from
+        .clone()
+        .unwrap_or_else(|| agent.client.bound_jid().unwrap().clone());
+    if let IqType::Get(payload) = iq.payload {
+        if payload.is("query", ns::DISCO_INFO) {
+            let query = DiscoInfoQuery::try_from(payload);
+            match query {
+                Ok(query) => {
+                    let mut disco_info = agent.disco.clone();
+                    disco_info.node = query.node;
+                    let iq = Iq::from_result(iq.id, Some(disco_info))
+                        .with_to(iq.from.unwrap())
+                        .into();
+                    let _ = agent.client.send_stanza(iq).await;
+                }
+                Err(err) => {
+                    let error = StanzaError::new(
+                        ErrorType::Modify,
+                        DefinedCondition::BadRequest,
+                        "en",
+                        &format!("{}", err),
+                    );
+                    let iq = Iq::from_error(iq.id, error)
+                        .with_to(iq.from.unwrap())
+                        .into();
+                    let _ = agent.client.send_stanza(iq).await;
+                }
+            }
+        } else {
+            // We MUST answer unhandled get iqs with a service-unavailable error.
+            let error = StanzaError::new(
+                ErrorType::Cancel,
+                DefinedCondition::ServiceUnavailable,
+                "en",
+                "No handler defined for this kind of iq.",
+            );
+            let iq = Iq::from_error(iq.id, error)
+                .with_to(iq.from.unwrap())
+                .into();
+            let _ = agent.client.send_stanza(iq).await;
+        }
+    } else if let IqType::Result(Some(payload)) = iq.payload {
+        // TODO: move private iqs like this one somewhere else, for
+        // security reasons.
+        if payload.is("query", ns::ROSTER) && Some(from.clone()) == iq.from {
+            let roster = Roster::try_from(payload).unwrap();
+            for item in roster.items.into_iter() {
+                events.push(Event::ContactAdded(item));
+            }
+        } else if payload.is("pubsub", ns::PUBSUB) {
+            let new_events = pubsub::handle_iq_result(&from, payload);
+            events.extend(new_events);
+        } else if payload.is("slot", ns::HTTP_UPLOAD) {
+            let new_events = handle_upload_result(&from, iq.id, payload, agent).await;
+            events.extend(new_events);
+        } else if payload.is("query", ns::PRIVATE) {
+            match PrivateXMLQuery::try_from(payload) {
+                Ok(query) => {
+                    for conf in query.storage.conferences {
+                        let (jid, room) = conf.into_bookmarks2();
+                        events.push(Event::JoinRoom(jid, room));
+                    }
+                }
+                Err(e) => {
+                    panic!("Wrong XEP-0048 v1.0 Bookmark format: {}", e);
+                }
+            }
+        } else if payload.is("query", ns::DISCO_INFO) {
+            agent.handle_disco_info_result_payload(payload, from).await;
+        }
+    } else if let IqType::Set(_) = iq.payload {
+        // We MUST answer unhandled set iqs with a service-unavailable error.
+        let error = StanzaError::new(
+            ErrorType::Cancel,
+            DefinedCondition::ServiceUnavailable,
+            "en",
+            "No handler defined for this kind of iq.",
+        );
+        let iq = Iq::from_error(iq.id, error)
+            .with_to(iq.from.unwrap())
+            .into();
+        let _ = agent.client.send_stanza(iq).await;
+    }
+    events
+}

xmpp/src/lib.rs 🔗

@@ -21,7 +21,7 @@ use tokio_xmpp::parsers::{
     disco::{DiscoInfoQuery, DiscoInfoResult, Feature, Identity},
     hashes::Algo,
     http_upload::{Header as HttpUploadHeader, SlotRequest, SlotResult},
-    iq::{Iq, IqType},
+    iq::Iq,
     message::{Body, Message, MessageType},
     muc::{user::MucUser, Muc},
     ns,
@@ -29,7 +29,6 @@ use tokio_xmpp::parsers::{
     private::Query as PrivateXMLQuery,
     pubsub::pubsub::{Items, PubSub},
     roster::{Item as RosterItem, Roster},
-    stanza_error::{DefinedCondition, ErrorType, StanzaError},
     Error as ParsersError,
 };
 use tokio_xmpp::{AsyncClient as TokioXmppClient, Event as TokioXmppEvent};
@@ -37,6 +36,7 @@ pub use tokio_xmpp::{BareJid, Element, FullJid, Jid};
 #[macro_use]
 extern crate log;
 
+pub mod iq;
 pub mod message;
 pub mod presence;
 pub mod pubsub;
@@ -333,95 +333,6 @@ impl Agent {
         presence
     }
 
-    async fn handle_iq(&mut self, iq: Iq) -> Vec<Event> {
-        let mut events = vec![];
-        let from = iq
-            .from
-            .clone()
-            .unwrap_or_else(|| self.client.bound_jid().unwrap().clone());
-        if let IqType::Get(payload) = iq.payload {
-            if payload.is("query", ns::DISCO_INFO) {
-                let query = DiscoInfoQuery::try_from(payload);
-                match query {
-                    Ok(query) => {
-                        let mut disco_info = self.disco.clone();
-                        disco_info.node = query.node;
-                        let iq = Iq::from_result(iq.id, Some(disco_info))
-                            .with_to(iq.from.unwrap())
-                            .into();
-                        let _ = self.client.send_stanza(iq).await;
-                    }
-                    Err(err) => {
-                        let error = StanzaError::new(
-                            ErrorType::Modify,
-                            DefinedCondition::BadRequest,
-                            "en",
-                            &format!("{}", err),
-                        );
-                        let iq = Iq::from_error(iq.id, error)
-                            .with_to(iq.from.unwrap())
-                            .into();
-                        let _ = self.client.send_stanza(iq).await;
-                    }
-                }
-            } else {
-                // We MUST answer unhandled get iqs with a service-unavailable error.
-                let error = StanzaError::new(
-                    ErrorType::Cancel,
-                    DefinedCondition::ServiceUnavailable,
-                    "en",
-                    "No handler defined for this kind of iq.",
-                );
-                let iq = Iq::from_error(iq.id, error)
-                    .with_to(iq.from.unwrap())
-                    .into();
-                let _ = self.client.send_stanza(iq).await;
-            }
-        } else if let IqType::Result(Some(payload)) = iq.payload {
-            // TODO: move private iqs like this one somewhere else, for
-            // security reasons.
-            if payload.is("query", ns::ROSTER) && Some(from.clone()) == iq.from {
-                let roster = Roster::try_from(payload).unwrap();
-                for item in roster.items.into_iter() {
-                    events.push(Event::ContactAdded(item));
-                }
-            } else if payload.is("pubsub", ns::PUBSUB) {
-                let new_events = pubsub::handle_iq_result(&from, payload);
-                events.extend(new_events);
-            } else if payload.is("slot", ns::HTTP_UPLOAD) {
-                let new_events = handle_upload_result(&from, iq.id, payload, self).await;
-                events.extend(new_events);
-            } else if payload.is("query", ns::PRIVATE) {
-                match PrivateXMLQuery::try_from(payload) {
-                    Ok(query) => {
-                        for conf in query.storage.conferences {
-                            let (jid, room) = conf.into_bookmarks2();
-                            events.push(Event::JoinRoom(jid, room));
-                        }
-                    }
-                    Err(e) => {
-                        panic!("Wrong XEP-0048 v1.0 Bookmark format: {}", e);
-                    }
-                }
-            } else if payload.is("query", ns::DISCO_INFO) {
-                self.handle_disco_info_result_payload(payload, from).await;
-            }
-        } else if let IqType::Set(_) = iq.payload {
-            // We MUST answer unhandled set iqs with a service-unavailable error.
-            let error = StanzaError::new(
-                ErrorType::Cancel,
-                DefinedCondition::ServiceUnavailable,
-                "en",
-                "No handler defined for this kind of iq.",
-            );
-            let iq = Iq::from_error(iq.id, error)
-                .with_to(iq.from.unwrap())
-                .into();
-            let _ = self.client.send_stanza(iq).await;
-        }
-        events
-    }
-
     // This method is a workaround due to prosody bug https://issues.prosody.im/1664
     // FIXME: To be removed in the future
     // The server doesn't return disco#info feature when querying the account
@@ -533,7 +444,7 @@ impl Agent {
                 TokioXmppEvent::Stanza(elem) => {
                     if elem.is("iq", "jabber:client") {
                         let iq = Iq::try_from(elem).unwrap();
-                        let new_events = self.handle_iq(iq).await;
+                        let new_events = iq::handle_iq(self, iq).await;
                         events.extend(new_events);
                     } else if elem.is("message", "jabber:client") {
                         let message = Message::try_from(elem).unwrap();