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}