mam_prefs.rs

  1// Copyright (c) 2021 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  2//
  3// This Source Code Form is subject to the terms of the Mozilla Public
  4// License, v. 2.0. If a copy of the MPL was not distributed with this
  5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6
  7use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
  8use crate::ns;
  9use crate::util::error::Error;
 10use jid::Jid;
 11use minidom::{Element, Node};
 12use std::convert::TryFrom;
 13
 14generate_attribute!(
 15    /// Notes the default archiving preference for the user.
 16    DefaultPrefs, "default", {
 17        /// The default is to always log messages in the archive.
 18        Always => "always",
 19
 20        /// The default is to never log messages in the archive.
 21        Never => "never",
 22
 23        /// The default is to log messages in the archive only for contacts
 24        /// present in the user’s [roster](../roster/index.html).
 25        Roster => "roster",
 26    }
 27);
 28
 29/// Controls the archiving preferences of the user.
 30#[derive(Debug, Clone)]
 31pub struct Prefs {
 32    /// The default preference for JIDs in neither
 33    /// [always](#structfield.always) or [never](#structfield.never) lists.
 34    pub default_: DefaultPrefs,
 35
 36    /// The set of JIDs for which to always store messages in the archive.
 37    pub always: Vec<Jid>,
 38
 39    /// The set of JIDs for which to never store messages in the archive.
 40    pub never: Vec<Jid>,
 41}
 42
 43impl IqGetPayload for Prefs {}
 44impl IqSetPayload for Prefs {}
 45impl IqResultPayload for Prefs {}
 46
 47impl TryFrom<Element> for Prefs {
 48    type Error = Error;
 49
 50    fn try_from(elem: Element) -> Result<Prefs, Error> {
 51        check_self!(elem, "prefs", MAM);
 52        check_no_unknown_attributes!(elem, "prefs", ["default"]);
 53        let mut always = vec![];
 54        let mut never = vec![];
 55        for child in elem.children() {
 56            if child.is("always", ns::MAM) {
 57                for jid_elem in child.children() {
 58                    if !jid_elem.is("jid", ns::MAM) {
 59                        return Err(Error::ParseError("Invalid jid element in always."));
 60                    }
 61                    always.push(jid_elem.text().parse()?);
 62                }
 63            } else if child.is("never", ns::MAM) {
 64                for jid_elem in child.children() {
 65                    if !jid_elem.is("jid", ns::MAM) {
 66                        return Err(Error::ParseError("Invalid jid element in never."));
 67                    }
 68                    never.push(jid_elem.text().parse()?);
 69                }
 70            } else {
 71                return Err(Error::ParseError("Unknown child in prefs element."));
 72            }
 73        }
 74        let default_ = get_attr!(elem, "default", Required);
 75        Ok(Prefs {
 76            default_,
 77            always,
 78            never,
 79        })
 80    }
 81}
 82
 83fn serialise_jid_list(name: &str, jids: Vec<Jid>) -> ::std::option::IntoIter<Node> {
 84    if jids.is_empty() {
 85        None.into_iter()
 86    } else {
 87        Some(
 88            Element::builder(name, ns::MAM)
 89                .append_all(
 90                    jids.into_iter()
 91                        .map(|jid| Element::builder("jid", ns::MAM).append(String::from(jid))),
 92                )
 93                .into(),
 94        )
 95        .into_iter()
 96    }
 97}
 98
 99impl From<Prefs> for Element {
100    fn from(prefs: Prefs) -> Element {
101        Element::builder("prefs", ns::MAM)
102            .attr("default", prefs.default_)
103            .append_all(serialise_jid_list("always", prefs.always))
104            .append_all(serialise_jid_list("never", prefs.never))
105            .build()
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112    use jid::BareJid;
113
114    #[cfg(target_pointer_width = "32")]
115    #[test]
116    fn test_size() {
117        assert_size!(DefaultPrefs, 1);
118        assert_size!(Prefs, 28);
119    }
120
121    #[cfg(target_pointer_width = "64")]
122    #[test]
123    fn test_size() {
124        assert_size!(DefaultPrefs, 1);
125        assert_size!(Prefs, 56);
126    }
127
128    #[test]
129    fn test_prefs_get() {
130        let elem: Element = "<prefs xmlns='urn:xmpp:mam:2' default='always'/>"
131            .parse()
132            .unwrap();
133        let prefs = Prefs::try_from(elem).unwrap();
134        assert!(prefs.always.is_empty());
135        assert!(prefs.never.is_empty());
136
137        let elem: Element = r#"<prefs xmlns='urn:xmpp:mam:2' default='roster'>
138  <always/>
139  <never/>
140</prefs>
141"#
142        .parse()
143        .unwrap();
144        let prefs = Prefs::try_from(elem).unwrap();
145        assert!(prefs.always.is_empty());
146        assert!(prefs.never.is_empty());
147    }
148
149    #[test]
150    fn test_prefs_result() {
151        let elem: Element = r#"<prefs xmlns='urn:xmpp:mam:2' default='roster'>
152  <always>
153    <jid>romeo@montague.lit</jid>
154  </always>
155  <never>
156    <jid>montague@montague.lit</jid>
157  </never>
158</prefs>
159"#
160        .parse()
161        .unwrap();
162        let prefs = Prefs::try_from(elem).unwrap();
163        assert_eq!(prefs.always, [BareJid::new("romeo", "montague.lit")]);
164        assert_eq!(prefs.never, [BareJid::new("montague", "montague.lit")]);
165
166        let elem2 = Element::from(prefs.clone());
167        println!("{:?}", elem2);
168        let prefs2 = Prefs::try_from(elem2).unwrap();
169        assert_eq!(prefs.default_, prefs2.default_);
170        assert_eq!(prefs.always, prefs2.always);
171        assert_eq!(prefs.never, prefs2.never);
172    }
173}