Add a Bookmarks 2 (This Time it's Serious) parser.

Emmanuel Gil Peyrot created

Change summary

ChangeLog         |   1 
doap.xml          |   8 +++
src/bookmarks2.rs | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
src/lib.rs        |   3 +
src/ns.rs         |   5 ++
5 files changed, 136 insertions(+)

Detailed changes

ChangeLog 🔗

@@ -5,6 +5,7 @@ DATE  Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
         - JID Prep (XEP-0328)
         - Client State Indication (XEP-0352)
         - OpenPGP for XMPP (XEP-0373)
+        - Bookmarks 2 (This Time it's Serious) (XEP-0402)
         - Anonymous unique occupant identifiers for MUCs (XEP-0421)
     * Breaking changes:
         - Presence constructors now take Into<Jid> and assume Some.

doap.xml 🔗

@@ -465,6 +465,14 @@
             <xmpp:since>0.1.0</xmpp:since>
         </xmpp:SupportedXep>
     </implements>
+    <implements>
+        <xmpp:SupportedXep>
+            <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0402.html"/>
+            <xmpp:status>complete</xmpp:status>
+            <xmpp:version>0.3.0</xmpp:version>
+            <xmpp:since>NEXT</xmpp:since>
+        </xmpp:SupportedXep>
+    </implements>
     <implements>
         <xmpp:SupportedXep>
             <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0421.html"/>

src/bookmarks2.rs 🔗

@@ -0,0 +1,119 @@
+// Copyright (c) 2019 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+//
+// 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/.
+
+generate_attribute!(
+    /// Whether a conference bookmark should be joined automatically.
+    Autojoin,
+    "autojoin",
+    bool
+);
+
+generate_element!(
+    /// A conference bookmark.
+    Conference, "conference", BOOKMARKS2,
+    attributes: [
+        /// Whether a conference bookmark should be joined automatically.
+        autojoin: Default<Autojoin> = "autojoin",
+
+        /// A user-defined name for this conference.
+        name: Option<String> = "name",
+    ],
+    children: [
+        /// The nick the user will use to join this conference.
+        nick: Option<String> = ("nick", BOOKMARKS2) => String,
+
+        /// The password required to join this conference.
+        password: Option<String> = ("password", BOOKMARKS2) => String
+    ]
+);
+
+impl Conference {
+    /// Create a new conference.
+    pub fn new() -> Conference {
+        Conference {
+            autojoin: Autojoin::False,
+            name: None,
+            nick: None,
+            password: None,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::util::compare_elements::NamespaceAwareCompare;
+    use crate::Element;
+    use std::convert::TryFrom;
+    use crate::pubsub::pubsub::Item as PubSubItem;
+    use crate::pubsub::event::PubSubEvent;
+    use crate::ns;
+
+    #[cfg(target_pointer_width = "32")]
+    #[test]
+    fn test_size() {
+        assert_size!(Conference, 40);
+    }
+
+    #[cfg(target_pointer_width = "64")]
+    #[test]
+    fn test_size() {
+        assert_size!(Conference, 80);
+    }
+
+    #[test]
+    fn simple() {
+        let elem: Element = "<conference xmlns='urn:xmpp:bookmarks:0'/>".parse().unwrap();
+        let elem1 = elem.clone();
+        let conference = Conference::try_from(elem).unwrap();
+        assert_eq!(conference.autojoin, Autojoin::False);
+        assert_eq!(conference.name, None);
+        assert_eq!(conference.nick, None);
+        assert_eq!(conference.password, None);
+
+        let elem2 = Element::from(Conference::new());
+        assert!(elem1.compare_to(&elem2));
+    }
+
+    #[test]
+    fn complete() {
+        let elem: Element = "<conference xmlns='urn:xmpp:bookmarks:0' autojoin='true' name='Test MUC'><nick>Coucou</nick><password>secret</password></conference>".parse().unwrap();
+        let conference = Conference::try_from(elem).unwrap();
+        assert_eq!(conference.autojoin, Autojoin::True);
+        assert_eq!(conference.name, Some(String::from("Test MUC")));
+        assert_eq!(conference.clone().nick.unwrap(), "Coucou");
+        assert_eq!(conference.clone().password.unwrap(), "secret");
+    }
+
+    #[test]
+    fn wrapped() {
+        let elem: Element = "<item xmlns='http://jabber.org/protocol/pubsub' id='test-muc@muc.localhost'><conference xmlns='urn:xmpp:bookmarks:0' autojoin='true' name='Test MUC'><nick>Coucou</nick><password>secret</password></conference></item>".parse().unwrap();
+        let item = PubSubItem::try_from(elem).unwrap();
+        let payload = item.payload.clone().unwrap();
+        let conference = Conference::try_from(payload).unwrap();
+        assert_eq!(conference.autojoin, Autojoin::True);
+        assert_eq!(conference.name, Some(String::from("Test MUC")));
+        assert_eq!(conference.clone().nick.unwrap(), "Coucou");
+        assert_eq!(conference.clone().password.unwrap(), "secret");
+
+        let elem: Element = "<event xmlns='http://jabber.org/protocol/pubsub#event'><items node='urn:xmpp:bookmarks:0'><item xmlns='http://jabber.org/protocol/pubsub#event' id='test-muc@muc.localhost'><conference xmlns='urn:xmpp:bookmarks:0' autojoin='true' name='Test MUC'><nick>Coucou</nick><password>secret</password></conference></item></items></event>".parse().unwrap();
+        let mut items = match PubSubEvent::try_from(elem) {
+            Ok(PubSubEvent::PublishedItems { node, items }) => {
+                assert_eq!(&node.0, ns::BOOKMARKS2);
+                items
+            },
+            _ => panic!(),
+        };
+        assert_eq!(items.len(), 1);
+        let item = items.pop().unwrap();
+        let payload = item.payload.clone().unwrap();
+        let conference = Conference::try_from(payload).unwrap();
+        assert_eq!(conference.autojoin, Autojoin::True);
+        assert_eq!(conference.name, Some(String::from("Test MUC")));
+        assert_eq!(conference.clone().nick.unwrap(), "Coucou");
+        assert_eq!(conference.clone().password.unwrap(), "secret");
+    }
+}

src/lib.rs 🔗

@@ -201,5 +201,8 @@ pub mod eme;
 /// XEP-0390: Entity Capabilities 2.0
 pub mod ecaps2;
 
+/// XEP-0402: Bookmarks 2 (This Time it's Serious)
+pub mod bookmarks2;
+
 /// XEP-0421: Anonymous unique occupant identifiers for MUCs
 pub mod occupant_id;

src/ns.rs 🔗

@@ -210,6 +210,11 @@ pub const ECAPS2: &str = "urn:xmpp:caps";
 /// XEP-0390: Entity Capabilities 2.0
 pub const ECAPS2_OPTIMIZE: &str = "urn:xmpp:caps:optimize";
 
+/// XEP-0402: Bookmarks 2 (This Time it's Serious)
+pub const BOOKMARKS2: &str = "urn:xmpp:bookmarks:0";
+/// XEP-0402: Bookmarks 2 (This Time it's Serious)
+pub const BOOKMARKS2_COMPAT: &str = "urn:xmpp:bookmarks:0#compat";
+
 /// XEP-0421: Anonymous unique occupant identifiers for MUCs
 pub const OID: &str = "urn:xmpp:occupant-id:0";