Merge branch 'messaging' into 'master'

lumi created

Rewrite the messaging plugin

See merge request !14

Change summary

examples/client.rs       |   2 
src/plugins/messaging.rs | 120 ++++++++++++++++++++++++++++++++++-------
2 files changed, 100 insertions(+), 22 deletions(-)

Detailed changes

examples/client.rs 🔗

@@ -7,7 +7,7 @@ use xmpp::plugins::unhandled_iq::UnhandledIqPlugin;
 use xmpp::plugins::messaging::{MessagingPlugin, MessageEvent};
 use xmpp::plugins::presence::{PresencePlugin, Type};
 use xmpp::plugins::ibb::IbbPlugin;
-use xmpp::plugins::ping::{PingPlugin, PingEvent};
+use xmpp::plugins::ping::PingPlugin;
 use xmpp::event::{Priority, Propagation};
 
 use std::env;

src/plugins/messaging.rs 🔗

@@ -1,18 +1,55 @@
+use std::convert::TryFrom;
+use std::collections::BTreeMap;
+
 use plugin::PluginProxy;
-use event::{Event, ReceiveElement, Priority, Propagation};
-use minidom::Element;
+use event::{Event, Priority, Propagation};
 use error::Error;
 use jid::Jid;
-use ns;
 
+use plugins::stanza::Message;
+use xmpp_parsers::message::{MessagePayload, MessageType};
+use xmpp_parsers::chatstates::ChatState;
+use xmpp_parsers::receipts::Receipt;
+use xmpp_parsers::stanza_id::StanzaId;
+
+// TODO: use the id (maybe even stanza-id) to identify every message.
 #[derive(Debug)]
 pub struct MessageEvent {
     pub from: Jid,
-    pub to: Jid,
     pub body: String,
+    pub subject: Option<String>,
+    pub thread: Option<String>,
+}
+
+#[derive(Debug)]
+pub struct ChatStateEvent {
+    pub from: Jid,
+    pub chat_state: ChatState,
+}
+
+#[derive(Debug)]
+pub struct ReceiptRequestEvent {
+    pub from: Jid,
+}
+
+#[derive(Debug)]
+pub struct ReceiptReceivedEvent {
+    pub from: Jid,
+    pub id: String,
+}
+
+#[derive(Debug)]
+pub struct StanzaIdEvent {
+    pub from: Jid,
+    pub stanza_id: StanzaId,
+    pub message: Message,
 }
 
 impl Event for MessageEvent {}
+impl Event for ChatStateEvent {}
+impl Event for ReceiptRequestEvent {}
+impl Event for ReceiptReceivedEvent {}
+impl Event for StanzaIdEvent {}
 
 pub struct MessagingPlugin {
     proxy: PluginProxy,
@@ -26,30 +63,71 @@ impl MessagingPlugin {
     }
 
     pub fn send_message(&self, to: &Jid, body: &str) -> Result<(), Error> {
-        let mut elem = Element::builder("message")
-                               .attr("type", "chat")
-                               .attr("to", to.to_string())
-                               .build();
-        elem.append_child(Element::builder("body").append(body).build());
-        self.proxy.send(elem);
+        let message = Message {
+            from: None,
+            to: Some(to.clone()),
+            type_: MessageType::Chat,
+            // TODO: always use an id.
+            id: None,
+            bodies: {
+                let mut bodies = BTreeMap::new();
+                bodies.insert(String::new(), String::from(body));
+                bodies
+            },
+            subjects: BTreeMap::new(),
+            thread: None,
+            payloads: vec!(),
+        };
+        self.proxy.send(message.into());
         Ok(())
     }
 
-    fn handle_receive_element(&self, evt: &ReceiveElement) -> Propagation {
-        let elem = &evt.0;
-        if elem.is("message", ns::CLIENT) && elem.attr("type") == Some("chat") {
-            if let Some(body) = elem.get_child("body", ns::CLIENT) {
-                self.proxy.dispatch(MessageEvent { // TODO: safety!!!
-                    from: elem.attr("from").unwrap().parse().unwrap(),
-                    to: elem.attr("to").unwrap().parse().unwrap(),
-                    body: body.text(),
-                });
+    fn handle_message(&self, message: &Message) -> Propagation {
+        let from = message.from.clone().unwrap();
+        for payload in message.payloads.clone() {
+            let payload = match MessagePayload::try_from(payload) {
+                Ok(payload) => payload,
+                Err(err) => {
+                    println!("MessagePayload: {:?}", err);
+                    continue;
+                }
+            };
+            match payload {
+                // XEP-0085
+                MessagePayload::ChatState(chat_state) => self.proxy.dispatch(ChatStateEvent {
+                    from: from.clone(),
+                    chat_state: chat_state,
+                }),
+                // XEP-0184
+                MessagePayload::Receipt(Receipt::Request) => self.proxy.dispatch(ReceiptRequestEvent {
+                    from: from.clone(),
+                }),
+                // XEP-0184
+                MessagePayload::Receipt(Receipt::Received(id)) => self.proxy.dispatch(ReceiptReceivedEvent {
+                    from: from.clone(),
+                    id: id.unwrap(),
+                }),
+                // XEP-0359
+                MessagePayload::StanzaId(stanza_id) => self.proxy.dispatch(StanzaIdEvent {
+                    from: from.clone(),
+                    stanza_id: stanza_id,
+                    message: message.clone(),
+                }),
+                payload => println!("Unhandled payload: {:?}", payload),
             }
         }
-        Propagation::Continue
+        if message.bodies.contains_key("") {
+            self.proxy.dispatch(MessageEvent {
+                from: from,
+                body: message.bodies[""].clone(),
+                subject: if message.subjects.contains_key("") { Some(message.subjects[""].clone()) } else { None },
+                thread: message.thread.clone(),
+            });
+        }
+        Propagation::Stop
     }
 }
 
 impl_plugin!(MessagingPlugin, proxy, [
-    (ReceiveElement, Priority::Default) => handle_receive_element,
+    (Message, Priority::Default) => handle_message,
 ]);