From 20e4bc455ad96355b71a51c2bf06c31a760854fd Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 29 Sep 2021 20:08:08 +0200 Subject: [PATCH] xmpp-parsers/mam: Split into mam_prefs following XEP-0411 --- xmpp-parsers/doap.xml | 10 +- xmpp-parsers/src/lib.rs | 3 + xmpp-parsers/src/mam.rs | 158 +----------------------------- xmpp-parsers/src/mam_prefs.rs | 175 ++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+), 155 deletions(-) create mode 100644 xmpp-parsers/src/mam_prefs.rs diff --git a/xmpp-parsers/doap.xml b/xmpp-parsers/doap.xml index bb6352f..31d6e13 100644 --- a/xmpp-parsers/doap.xml +++ b/xmpp-parsers/doap.xml @@ -415,7 +415,7 @@ complete - 0.6.3 + 0.7.5 0.1.0 @@ -531,6 +531,14 @@ 0.16.0 + + + + complete + 0.2.0 + 0.1.0 + + diff --git a/xmpp-parsers/src/lib.rs b/xmpp-parsers/src/lib.rs index 673e7e4..d18f399 100644 --- a/xmpp-parsers/src/lib.rs +++ b/xmpp-parsers/src/lib.rs @@ -224,3 +224,6 @@ pub mod bookmarks2; /// XEP-0421: Anonymous unique occupant identifiers for MUCs pub mod occupant_id; + +/// XEP-0441: Message Archive Management Preferences +pub mod mam_prefs; diff --git a/xmpp-parsers/src/mam.rs b/xmpp-parsers/src/mam.rs index b77aac3..eff0065 100644 --- a/xmpp-parsers/src/mam.rs +++ b/xmpp-parsers/src/mam.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Emmanuel Gil Peyrot +// Copyright (c) 2017-2021 Emmanuel Gil Peyrot // // 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 @@ -8,13 +8,8 @@ use crate::data_forms::DataForm; use crate::forwarding::Forwarded; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::message::MessagePayload; -use crate::ns; use crate::pubsub::NodeName; use crate::rsm::{SetQuery, SetResult}; -use crate::util::error::Error; -use jid::Jid; -use minidom::{Element, Node}; -use std::convert::TryFrom; generate_id!( /// An identifier matching a result message to the query requesting it. @@ -92,105 +87,12 @@ generate_element!( impl IqResultPayload for Fin {} -generate_attribute!( - /// Notes the default archiving preference for the user. - DefaultPrefs, "default", { - /// The default is to always log messages in the archive. - Always => "always", - - /// The default is to never log messages in the archive. - Never => "never", - - /// The default is to log messages in the archive only for contacts - /// present in the user’s [roster](../roster/index.html). - Roster => "roster", - } -); - -/// Controls the archiving preferences of the user. -#[derive(Debug, Clone)] -pub struct Prefs { - /// The default preference for JIDs in neither - /// [always](#structfield.always) or [never](#structfield.never) lists. - pub default_: DefaultPrefs, - - /// The set of JIDs for which to always store messages in the archive. - pub always: Vec, - - /// The set of JIDs for which to never store messages in the archive. - pub never: Vec, -} - -impl IqGetPayload for Prefs {} -impl IqSetPayload for Prefs {} -impl IqResultPayload for Prefs {} - -impl TryFrom for Prefs { - type Error = Error; - - fn try_from(elem: Element) -> Result { - check_self!(elem, "prefs", MAM); - check_no_unknown_attributes!(elem, "prefs", ["default"]); - let mut always = vec![]; - let mut never = vec![]; - for child in elem.children() { - if child.is("always", ns::MAM) { - for jid_elem in child.children() { - if !jid_elem.is("jid", ns::MAM) { - return Err(Error::ParseError("Invalid jid element in always.")); - } - always.push(jid_elem.text().parse()?); - } - } else if child.is("never", ns::MAM) { - for jid_elem in child.children() { - if !jid_elem.is("jid", ns::MAM) { - return Err(Error::ParseError("Invalid jid element in never.")); - } - never.push(jid_elem.text().parse()?); - } - } else { - return Err(Error::ParseError("Unknown child in prefs element.")); - } - } - let default_ = get_attr!(elem, "default", Required); - Ok(Prefs { - default_, - always, - never, - }) - } -} - -fn serialise_jid_list(name: &str, jids: Vec) -> ::std::option::IntoIter { - if jids.is_empty() { - None.into_iter() - } else { - Some( - Element::builder(name, ns::MAM) - .append_all( - jids.into_iter() - .map(|jid| Element::builder("jid", ns::MAM).append(String::from(jid))), - ) - .into(), - ) - .into_iter() - } -} - -impl From for Element { - fn from(prefs: Prefs) -> Element { - Element::builder("prefs", ns::MAM) - .attr("default", prefs.default_) - .append_all(serialise_jid_list("always", prefs.always)) - .append_all(serialise_jid_list("never", prefs.never)) - .build() - } -} - #[cfg(test)] mod tests { use super::*; - use jid::BareJid; + use crate::util::error::Error; + use minidom::Element; + use std::convert::TryFrom; #[cfg(target_pointer_width = "32")] #[test] @@ -200,8 +102,6 @@ mod tests { assert_size!(Result_, 236); assert_size!(Complete, 1); assert_size!(Fin, 44); - assert_size!(DefaultPrefs, 1); - assert_size!(Prefs, 28); } #[cfg(target_pointer_width = "64")] @@ -212,8 +112,6 @@ mod tests { assert_size!(Result_, 456); assert_size!(Complete, 1); assert_size!(Fin, 88); - assert_size!(DefaultPrefs, 1); - assert_size!(Prefs, 56); } #[test] @@ -307,54 +205,6 @@ mod tests { Query::try_from(elem).unwrap(); } - #[test] - fn test_prefs_get() { - let elem: Element = "" - .parse() - .unwrap(); - let prefs = Prefs::try_from(elem).unwrap(); - assert!(prefs.always.is_empty()); - assert!(prefs.never.is_empty()); - - let elem: Element = r#" - - - - -"# - .parse() - .unwrap(); - let prefs = Prefs::try_from(elem).unwrap(); - assert!(prefs.always.is_empty()); - assert!(prefs.never.is_empty()); - } - - #[test] - fn test_prefs_result() { - let elem: Element = r#" - - - romeo@montague.lit - - - montague@montague.lit - - -"# - .parse() - .unwrap(); - let prefs = Prefs::try_from(elem).unwrap(); - assert_eq!(prefs.always, [BareJid::new("romeo", "montague.lit")]); - assert_eq!(prefs.never, [BareJid::new("montague", "montague.lit")]); - - let elem2 = Element::from(prefs.clone()); - println!("{:?}", elem2); - let prefs2 = Prefs::try_from(elem2).unwrap(); - assert_eq!(prefs.default_, prefs2.default_); - assert_eq!(prefs.always, prefs2.always); - assert_eq!(prefs.never, prefs2.never); - } - #[test] fn test_invalid_child() { let elem: Element = "" diff --git a/xmpp-parsers/src/mam_prefs.rs b/xmpp-parsers/src/mam_prefs.rs new file mode 100644 index 0000000..04e8663 --- /dev/null +++ b/xmpp-parsers/src/mam_prefs.rs @@ -0,0 +1,175 @@ +// Copyright (c) 2021 Emmanuel Gil Peyrot +// +// 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/. + +use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; +use crate::ns; +use crate::util::error::Error; +use jid::Jid; +use minidom::{Element, Node}; +use std::convert::TryFrom; + +generate_attribute!( + /// Notes the default archiving preference for the user. + DefaultPrefs, "default", { + /// The default is to always log messages in the archive. + Always => "always", + + /// The default is to never log messages in the archive. + Never => "never", + + /// The default is to log messages in the archive only for contacts + /// present in the user’s [roster](../roster/index.html). + Roster => "roster", + } +); + +/// Controls the archiving preferences of the user. +#[derive(Debug, Clone)] +pub struct Prefs { + /// The default preference for JIDs in neither + /// [always](#structfield.always) or [never](#structfield.never) lists. + pub default_: DefaultPrefs, + + /// The set of JIDs for which to always store messages in the archive. + pub always: Vec, + + /// The set of JIDs for which to never store messages in the archive. + pub never: Vec, +} + +impl IqGetPayload for Prefs {} +impl IqSetPayload for Prefs {} +impl IqResultPayload for Prefs {} + +impl TryFrom for Prefs { + type Error = Error; + + fn try_from(elem: Element) -> Result { + check_self!(elem, "prefs", MAM); + check_no_unknown_attributes!(elem, "prefs", ["default"]); + let mut always = vec![]; + let mut never = vec![]; + for child in elem.children() { + if child.is("always", ns::MAM) { + for jid_elem in child.children() { + if !jid_elem.is("jid", ns::MAM) { + return Err(Error::ParseError("Invalid jid element in always.")); + } + always.push(jid_elem.text().parse()?); + } + } else if child.is("never", ns::MAM) { + for jid_elem in child.children() { + if !jid_elem.is("jid", ns::MAM) { + return Err(Error::ParseError("Invalid jid element in never.")); + } + never.push(jid_elem.text().parse()?); + } + } else { + return Err(Error::ParseError("Unknown child in prefs element.")); + } + } + let default_ = get_attr!(elem, "default", Required); + Ok(Prefs { + default_, + always, + never, + }) + } +} + +fn serialise_jid_list(name: &str, jids: Vec) -> ::std::option::IntoIter { + if jids.is_empty() { + None.into_iter() + } else { + Some( + Element::builder(name, ns::MAM) + .append_all( + jids.into_iter() + .map(|jid| Element::builder("jid", ns::MAM).append(String::from(jid))), + ) + .into(), + ) + .into_iter() + } +} + +impl From for Element { + fn from(prefs: Prefs) -> Element { + Element::builder("prefs", ns::MAM) + .attr("default", prefs.default_) + .append_all(serialise_jid_list("always", prefs.always)) + .append_all(serialise_jid_list("never", prefs.never)) + .build() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use jid::BareJid; + + #[cfg(target_pointer_width = "32")] + #[test] + fn test_size() { + assert_size!(DefaultPrefs, 1); + assert_size!(Prefs, 28); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_size() { + assert_size!(DefaultPrefs, 1); + assert_size!(Prefs, 56); + } + + #[test] + fn test_prefs_get() { + let elem: Element = "" + .parse() + .unwrap(); + let prefs = Prefs::try_from(elem).unwrap(); + assert!(prefs.always.is_empty()); + assert!(prefs.never.is_empty()); + + let elem: Element = r#" + + + + +"# + .parse() + .unwrap(); + let prefs = Prefs::try_from(elem).unwrap(); + assert!(prefs.always.is_empty()); + assert!(prefs.never.is_empty()); + } + + #[test] + fn test_prefs_result() { + let elem: Element = r#" + + + romeo@montague.lit + + + montague@montague.lit + + +"# + .parse() + .unwrap(); + let prefs = Prefs::try_from(elem).unwrap(); + assert_eq!(prefs.always, [BareJid::new("romeo", "montague.lit")]); + assert_eq!(prefs.never, [BareJid::new("montague", "montague.lit")]); + + let elem2 = Element::from(prefs.clone()); + println!("{:?}", elem2); + let prefs2 = Prefs::try_from(elem2).unwrap(); + assert_eq!(prefs.default_, prefs2.default_); + assert_eq!(prefs.always, prefs2.always); + assert_eq!(prefs.never, prefs2.never); + } +}