message: Add support for the <subject/> element.

Emmanuel Gil Peyrot created

Change summary

src/message.rs | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)

Detailed changes

src/message.rs 🔗

@@ -87,6 +87,7 @@ pub enum MessagePayloadType {
 
 type Lang = String;
 type Body = String;
+type Subject = String;
 
 #[derive(Debug, Clone)]
 pub struct Message {
@@ -95,6 +96,7 @@ pub struct Message {
     pub id: Option<String>,
     pub type_: MessageType,
     pub bodies: BTreeMap<Lang, Body>,
+    pub subjects: BTreeMap<Lang, Subject>,
     pub payloads: Vec<MessagePayloadType>,
 }
 
@@ -116,6 +118,7 @@ impl<'a> TryFrom<&'a Element> for Message {
             None => Default::default(),
         };
         let mut bodies = BTreeMap::new();
+        let mut subjects = BTreeMap::new();
         let mut payloads = vec!();
         for elem in root.children() {
             if elem.is("body", ns::JABBER_CLIENT) {
@@ -126,6 +129,14 @@ impl<'a> TryFrom<&'a Element> for Message {
                 if let Some(_) = bodies.insert(lang, elem.text()) {
                     return Err(Error::ParseError("Body element present twice for the same xml:lang."));
                 }
+            } else if elem.is("subject", ns::JABBER_CLIENT) {
+                for _ in elem.children() {
+                    return Err(Error::ParseError("Unknown child in subject element."));
+                }
+                let lang = elem.attr("xml:lang").unwrap_or("").to_owned();
+                if let Some(_) = subjects.insert(lang, elem.text()) {
+                    return Err(Error::ParseError("Subject element present twice for the same xml:lang."));
+                }
             } else {
                 let payload = if let Ok(stanza_error) = StanzaError::try_from(elem) {
                     Some(MessagePayload::StanzaError(stanza_error))
@@ -156,6 +167,7 @@ impl<'a> TryFrom<&'a Element> for Message {
             id: id,
             type_: type_,
             bodies: BTreeMap::new(),
+            subjects: subjects,
             payloads: payloads,
         })
     }
@@ -183,6 +195,17 @@ impl<'a> Into<Element> for &'a Message {
                                  .attr("to", self.to.clone().and_then(|value| Some(String::from(value))))
                                  .attr("id", self.id.clone())
                                  .attr("type", self.type_.clone())
+                                 .append(self.subjects.iter()
+                                                    .map(|(lang, subject)| {
+                                                         Element::builder("subject")
+                                                                 .ns(ns::JABBER_CLIENT)
+                                                                 .attr("xml:lang", match lang.as_ref() {
+                                                                      "" => None,
+                                                                      lang => Some(lang),
+                                                                  })
+                                                                 .append(subject.clone())
+                                                                 .build() })
+                                                    .collect::<Vec<_>>())
                                  .append(self.bodies.iter()
                                                     .map(|(lang, body)| {
                                                          Element::builder("body")
@@ -230,6 +253,7 @@ mod tests {
             id: None,
             type_: MessageType::Normal,
             bodies: BTreeMap::new(),
+            subjects: BTreeMap::new(),
             payloads: vec!(),
         };
         let elem2 = (&message).into();
@@ -253,12 +277,23 @@ mod tests {
             id: None,
             type_: MessageType::Chat,
             bodies: bodies,
+            subjects: BTreeMap::new(),
             payloads: vec!(),
         };
         let elem2 = (&message).into();
         assert_eq!(elem, elem2);
     }
 
+    #[test]
+    fn test_subject() {
+        let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><subject>Hello world!</subject></message>".parse().unwrap();
+        let message = Message::try_from(&elem).unwrap();
+        assert_eq!(message.subjects[""], "Hello world!");
+
+        let elem2 = (&message).into();
+        assert_eq!(elem, elem2);
+    }
+
     #[test]
     fn test_attention() {
         let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><attention xmlns='urn:xmpp:attention:0'/></message>".parse().unwrap();