From cb2c4133fef1bd6d062fb3aa6d5638c0ebdebb87 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Fri, 9 Aug 2024 15:38:49 +0200 Subject: [PATCH] xmpp-parsers: Convert Forwarded to xso --- parsers/ChangeLog | 5 ++++ parsers/src/carbons.rs | 19 ++++++++++++-- parsers/src/forwarding.rs | 54 ++++++++++++++++++++++----------------- parsers/src/message.rs | 22 ++++++++++++++++ 4 files changed, 75 insertions(+), 25 deletions(-) diff --git a/parsers/ChangeLog b/parsers/ChangeLog index 423cfacfe1e4633d43d836fdfb9cbe9d947a8a77..3e0cbc191563306270e5b424aee7277591f24440 100644 --- a/parsers/ChangeLog +++ b/parsers/ChangeLog @@ -19,6 +19,11 @@ XXXX-YY-ZZ RELEASER check whether a child element is present or not, as this is currently implemented in xso. We might revert that change if we implement flag metas in xso before the next release. + - The forwarding module now hardcodes that its child is a message in the + jabber:client namespace. It previously half-followed the schema, but + nothing so far uses it for anything but this message. We can always + change it again once any other specification allows e.g. presences or + iqs. * New parsers/serialisers: - Stream Features (RFC 6120) (!400) - Extensible SASL Profile (XEP-0388) diff --git a/parsers/src/carbons.rs b/parsers/src/carbons.rs index 5fa5c7736d86020888ddfa077fdb815cc2b2f699..2225f5bb3a832cf0dd29742349dae52d9d8af393 100644 --- a/parsers/src/carbons.rs +++ b/parsers/src/carbons.rs @@ -58,6 +58,7 @@ impl MessagePayload for Sent {} #[cfg(test)] mod tests { use super::*; + use jid::Jid; use minidom::Element; #[cfg(target_pointer_width = "32")] @@ -104,7 +105,14 @@ mod tests { .parse() .unwrap(); let received = Received::try_from(elem).unwrap(); - assert!(received.forwarded.stanza.is_some()); + assert_eq!( + received.forwarded.message.to.unwrap(), + Jid::new("juliet@capulet.example/balcony").unwrap() + ); + assert_eq!( + received.forwarded.message.from.unwrap(), + Jid::new("romeo@montague.example/home").unwrap() + ); let elem: Element = " @@ -116,7 +124,14 @@ mod tests { .parse() .unwrap(); let sent = Sent::try_from(elem).unwrap(); - assert!(sent.forwarded.stanza.is_some()); + assert_eq!( + sent.forwarded.message.to.unwrap(), + Jid::new("juliet@capulet.example/balcony").unwrap() + ); + assert_eq!( + sent.forwarded.message.from.unwrap(), + Jid::new("romeo@montague.example/home").unwrap() + ); } #[test] diff --git a/parsers/src/forwarding.rs b/parsers/src/forwarding.rs index 01635358ba024cc015de6465683b62305f02754d..4963b2a705352405b5094afe7f1d2e00c6e24dfa 100644 --- a/parsers/src/forwarding.rs +++ b/parsers/src/forwarding.rs @@ -4,24 +4,29 @@ // 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 xso::{AsXml, FromXml}; + use crate::delay::Delay; use crate::message::Message; - -generate_element!( - /// Contains a forwarded stanza, either standalone or part of another - /// extension (such as carbons). - Forwarded, "forwarded", FORWARD, - children: [ - /// When the stanza originally got sent. - delay: Option = ("delay", DELAY) => Delay, - - // XXX: really? Option? - /// The stanza being forwarded. - stanza: Option = ("message", DEFAULT_NS) => Message - - // TODO: also handle the two other stanza possibilities. - ] -); +use crate::ns; + +/// Contains a forwarded stanza, either standalone or part of another +/// extension (such as carbons). +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] +#[xml(namespace = ns::FORWARD, name = "forwarded")] +pub struct Forwarded { + /// When the stanza originally got sent. + #[xml(child(default))] + pub delay: Option, + + /// The stanza being forwarded. + // The schema says that we should allow either a Message, Presence or Iq, in either + // jabber:client or jabber:server, but in the wild so far we’ve only seen Message being + // transmitted, so let’s hardcode that for now. The schema also makes it optional, but so far + // it’s always present (or this wrapper is useless). + #[xml(child)] + pub message: Message, +} #[cfg(test)] mod tests { @@ -43,7 +48,10 @@ mod tests { #[test] fn test_simple() { - let elem: Element = "".parse().unwrap(); + let elem: Element = + "" + .parse() + .unwrap(); Forwarded::try_from(elem).unwrap(); } @@ -57,15 +65,15 @@ mod tests { FromElementError::Invalid(Error::Other(string)) => string, _ => panic!(), }; - assert_eq!(message, "Unknown child in forwarded element."); + assert_eq!(message, "Unknown child in Forwarded element."); } #[test] fn test_serialise() { - let elem: Element = "".parse().unwrap(); + let elem: Element = "".parse().unwrap(); let forwarded = Forwarded { delay: None, - stanza: None, + message: Message::new(None), }; let elem2 = forwarded.into(); assert_eq!(elem, elem2); @@ -90,7 +98,7 @@ mod tests { let forwarded = Forwarded { delay: Some(delay), - stanza: Some(message), + message, }; let serialized: Element = forwarded.into(); @@ -109,7 +117,7 @@ mod tests { }; assert_eq!( message, - "Element forwarded must not have more than one delay child." + "Forwarded element must not have more than one child in field 'delay'." ); } @@ -125,7 +133,7 @@ mod tests { }; assert_eq!( message, - "Element forwarded must not have more than one message child." + "Forwarded element must not have more than one child in field 'message'." ); } } diff --git a/parsers/src/message.rs b/parsers/src/message.rs index 30222a43516d075029cae1978bbe824e6b0d028d..ffa4f1e7b05e4dca37dc99e805bcd0c0bf7ca2f9 100644 --- a/parsers/src/message.rs +++ b/parsers/src/message.rs @@ -330,6 +330,28 @@ impl From for Element { } } +impl ::xso::FromXml for Message { + type Builder = ::xso::minidom_compat::FromEventsViaElement; + + fn from_events( + qname: ::xso::exports::rxml::QName, + attrs: ::xso::exports::rxml::AttrMap, + ) -> Result { + if qname.0 != crate::ns::DEFAULT_NS || qname.1 != "message" { + return Err(::xso::error::FromEventsError::Mismatch { name: qname, attrs }); + } + Self::Builder::new(qname, attrs) + } +} + +impl ::xso::AsXml for Message { + type ItemIter<'x> = ::xso::minidom_compat::AsItemsViaElement<'x>; + + fn as_xml_iter(&self) -> Result, ::xso::error::Error> { + ::xso::minidom_compat::AsItemsViaElement::new(self.clone()) + } +} + #[cfg(test)] mod tests { use super::*;