Set subscribe element optional and add corresponding parsing

Paul Fariello created

Change summary

xmpp-parsers/src/pubsub/pubsub.rs | 61 +++++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 2 deletions(-)

Detailed changes

xmpp-parsers/src/pubsub/pubsub.rs 🔗

@@ -297,7 +297,7 @@ pub enum PubSub {
     /// A subcribe request.
     Subscribe {
         /// The subscribe request.
-        subscribe: Subscribe,
+        subscribe: Option<Subscribe>,
 
         /// The options related to this subscribe request.
         options: Option<Options>,
@@ -358,6 +358,37 @@ impl TryFrom<Element> for PubSub {
                     create,
                     configure: None,
                 });
+            } else if child.is("subscribe", ns::PUBSUB) {
+                if payload.is_some() {
+                    return Err(Error::ParseError(
+                        "Payload is already defined in pubsub element.",
+                    ));
+                }
+                let subscribe = Subscribe::try_from(child.clone())?;
+                payload = Some(PubSub::Subscribe {
+                    subscribe: Some(subscribe),
+                    options: None,
+                });
+            } else if child.is("options", ns::PUBSUB) {
+                if let Some(PubSub::Subscribe { subscribe, options }) = payload {
+                    if options.is_some() {
+                        return Err(Error::ParseError(
+                            "Options is already defined in pubsub element.",
+                        ));
+                    }
+                    let options = Some(Options::try_from(child.clone())?);
+                    payload = Some(PubSub::Subscribe { subscribe, options });
+                } else if payload.is_none() {
+                    let options = Options::try_from(child.clone())?;
+                    payload = Some(PubSub::Subscribe {
+                        subscribe: None,
+                        options: Some(options),
+                    });
+                } else {
+                    return Err(Error::ParseError(
+                        "Payload is already defined in pubsub element.",
+                    ));
+                }
             } else if child.is("configure", ns::PUBSUB) {
                 if let Some(PubSub::Create { create, configure }) = payload {
                     if configure.is_some() {
@@ -479,6 +510,16 @@ impl From<PubSub> for Element {
                     }
                     elems
                 }
+                PubSub::Subscribe { subscribe, options } => {
+                    let mut elems = vec![];
+                    if let Some(subscribe) = subscribe {
+                        elems.push(Element::from(subscribe));
+                    }
+                    if let Some(options) = options {
+                        elems.push(Element::from(options));
+                    }
+                    elems
+                }
                 PubSub::Publish {
                     publish,
                     publish_options,
@@ -495,7 +536,6 @@ impl From<PubSub> for Element {
                 PubSub::Retract(retract) => vec![Element::from(retract)],
                 PubSub::Subscription(subscription) => vec![Element::from(subscription)],
                 PubSub::Subscriptions(subscriptions) => vec![Element::from(subscriptions)],
-                PubSub::Subscribe(subscribe) => vec![Element::from(subscribe)],
                 PubSub::Unsubscribe(unsubscribe) => vec![Element::from(unsubscribe)],
             })
             .build()
@@ -678,6 +718,23 @@ mod tests {
         assert_eq!(subscribe_options2.required, true);
     }
 
+    #[test]
+    fn test_options_without_subscribe() {
+        let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub'><options xmlns='http://jabber.org/protocol/pubsub' jid='juliet@capulet.lit/balcony'><x xmlns='jabber:x:data' type='submit'/></options></pubsub>".parse().unwrap();
+        let elem1 = elem.clone();
+        let pubsub = PubSub::try_from(elem).unwrap();
+        match pubsub.clone() {
+            PubSub::Subscribe { subscribe, options } => {
+                assert!(subscribe.is_none());
+                assert!(options.is_some());
+            }
+            _ => panic!(),
+        }
+
+        let elem2 = Element::from(pubsub);
+        assert_eq!(elem1, elem2);
+    }
+
     #[test]
     fn test_serialize_options() {
         let reference: Element = "<options xmlns='http://jabber.org/protocol/pubsub' jid='juliet@capulet.lit/balcony'><x xmlns='jabber:x:data' type='submit'/></options>"