1// Copyright (c) 2017 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 try_from::TryFrom;
8
9use minidom::Element;
10use jid::Jid;
11
12use error::Error;
13
14use iq::{IqGetPayload, IqSetPayload, IqResultPayload};
15use data_forms::DataForm;
16use rsm::Set;
17use forwarding::Forwarded;
18
19use ns;
20
21generate_element!(
22 Query, "query", MAM,
23 attributes: [
24 queryid: Option<String> = "queryid" => optional,
25 node: Option<String> = "node" => optional
26 ],
27 children: [
28 form: Option<DataForm> = ("x", DATA_FORMS) => DataForm,
29 set: Option<Set> = ("set", RSM) => Set
30 ]
31);
32
33impl IqGetPayload for Query {}
34impl IqSetPayload for Query {}
35impl IqResultPayload for Query {}
36
37generate_element!(
38 Result_, "result", MAM,
39 attributes: [
40 id: String = "id" => required,
41 queryid: String = "queryid" => required,
42 ],
43 children: [
44 forwarded: Required<Forwarded> = ("forwarded", FORWARD) => Forwarded
45 ]
46);
47
48generate_attribute!(
49 Complete, "complete", bool
50);
51
52generate_element!(
53 Fin, "fin", MAM,
54 attributes: [
55 complete: Complete = "complete" => default
56 ],
57 children: [
58 set: Required<Set> = ("set", RSM) => Set
59 ]
60);
61
62impl IqResultPayload for Fin {}
63
64generate_attribute!(DefaultPrefs, "default", {
65 Always => "always",
66 Never => "never",
67 Roster => "roster",
68});
69
70#[derive(Debug, Clone)]
71pub struct Prefs {
72 pub default_: DefaultPrefs,
73 pub always: Vec<Jid>,
74 pub never: Vec<Jid>,
75}
76
77impl IqGetPayload for Prefs {}
78impl IqSetPayload for Prefs {}
79impl IqResultPayload for Prefs {}
80
81impl TryFrom<Element> for Prefs {
82 type Err = Error;
83
84 fn try_from(elem: Element) -> Result<Prefs, Error> {
85 check_self!(elem, "prefs", MAM);
86 check_no_unknown_attributes!(elem, "prefs", ["default"]);
87 let mut always = vec!();
88 let mut never = vec!();
89 for child in elem.children() {
90 if child.is("always", ns::MAM) {
91 for jid_elem in child.children() {
92 if !jid_elem.is("jid", ns::MAM) {
93 return Err(Error::ParseError("Invalid jid element in always."));
94 }
95 always.push(jid_elem.text().parse()?);
96 }
97 } else if child.is("never", ns::MAM) {
98 for jid_elem in child.children() {
99 if !jid_elem.is("jid", ns::MAM) {
100 return Err(Error::ParseError("Invalid jid element in never."));
101 }
102 never.push(jid_elem.text().parse()?);
103 }
104 } else {
105 return Err(Error::ParseError("Unknown child in prefs element."));
106 }
107 }
108 let default_ = get_attr!(elem, "default", required);
109 Ok(Prefs { default_, always, never })
110 }
111}
112
113fn serialise_jid_list(name: &str, jids: Vec<Jid>) -> Option<Element> {
114 if jids.is_empty() {
115 None
116 } else {
117 Some(Element::builder(name)
118 .ns(ns::MAM)
119 .append(jids.into_iter()
120 .map(|jid| Element::builder("jid")
121 .ns(ns::MAM)
122 .append(jid)
123 .build())
124 .collect::<Vec<_>>())
125 .build())
126 }
127}
128
129impl From<Prefs> for Element {
130 fn from(prefs: Prefs) -> Element {
131 Element::builder("prefs")
132 .ns(ns::MAM)
133 .attr("default", prefs.default_)
134 .append(serialise_jid_list("always", prefs.always))
135 .append(serialise_jid_list("never", prefs.never))
136 .build()
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use std::str::FromStr;
144
145 #[test]
146 fn test_query() {
147 let elem: Element = "<query xmlns='urn:xmpp:mam:2'/>".parse().unwrap();
148 Query::try_from(elem).unwrap();
149 }
150
151 #[test]
152 fn test_result() {
153 #[cfg(not(feature = "component"))]
154 let elem: Element = r#"
155<result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
156 <forwarded xmlns='urn:xmpp:forward:0'>
157 <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
158 <message xmlns='jabber:client' from="witch@shakespeare.lit" to="macbeth@shakespeare.lit">
159 <body>Hail to thee</body>
160 </message>
161 </forwarded>
162</result>
163"#.parse().unwrap();
164 #[cfg(feature = "component")]
165 let elem: Element = r#"
166<result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
167 <forwarded xmlns='urn:xmpp:forward:0'>
168 <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
169 <message xmlns='jabber:component:accept' from="witch@shakespeare.lit" to="macbeth@shakespeare.lit">
170 <body>Hail to thee</body>
171 </message>
172 </forwarded>
173</result>
174"#.parse().unwrap();
175 Result_::try_from(elem).unwrap();
176 }
177
178 #[test]
179 fn test_fin() {
180 let elem: Element = r#"
181<fin xmlns='urn:xmpp:mam:2'>
182 <set xmlns='http://jabber.org/protocol/rsm'>
183 <first index='0'>28482-98726-73623</first>
184 <last>09af3-cc343-b409f</last>
185 </set>
186</fin>
187"#.parse().unwrap();
188 Fin::try_from(elem).unwrap();
189 }
190
191 #[test]
192 fn test_query_x() {
193 let elem: Element = r#"
194<query xmlns='urn:xmpp:mam:2'>
195 <x xmlns='jabber:x:data' type='submit'>
196 <field var='FORM_TYPE' type='hidden'>
197 <value>urn:xmpp:mam:2</value>
198 </field>
199 <field var='with'>
200 <value>juliet@capulet.lit</value>
201 </field>
202 </x>
203</query>
204"#.parse().unwrap();
205 Query::try_from(elem).unwrap();
206 }
207
208 #[test]
209 fn test_query_x_set() {
210 let elem: Element = r#"
211<query xmlns='urn:xmpp:mam:2'>
212 <x xmlns='jabber:x:data' type='submit'>
213 <field var='FORM_TYPE' type='hidden'>
214 <value>urn:xmpp:mam:2</value>
215 </field>
216 <field var='start'>
217 <value>2010-08-07T00:00:00Z</value>
218 </field>
219 </x>
220 <set xmlns='http://jabber.org/protocol/rsm'>
221 <max>10</max>
222 </set>
223</query>
224"#.parse().unwrap();
225 Query::try_from(elem).unwrap();
226 }
227
228 #[test]
229 fn test_prefs_get() {
230 let elem: Element = "<prefs xmlns='urn:xmpp:mam:2' default='always'/>".parse().unwrap();
231 let prefs = Prefs::try_from(elem).unwrap();
232 assert_eq!(prefs.always, vec!());
233 assert_eq!(prefs.never, vec!());
234
235 let elem: Element = r#"
236<prefs xmlns='urn:xmpp:mam:2' default='roster'>
237 <always/>
238 <never/>
239</prefs>
240"#.parse().unwrap();
241 let prefs = Prefs::try_from(elem).unwrap();
242 assert_eq!(prefs.always, vec!());
243 assert_eq!(prefs.never, vec!());
244 }
245
246 #[test]
247 fn test_prefs_result() {
248 let elem: Element = r#"
249<prefs xmlns='urn:xmpp:mam:2' default='roster'>
250 <always>
251 <jid>romeo@montague.lit</jid>
252 </always>
253 <never>
254 <jid>montague@montague.lit</jid>
255 </never>
256</prefs>
257"#.parse().unwrap();
258 let prefs = Prefs::try_from(elem).unwrap();
259 assert_eq!(prefs.always, vec!(Jid::from_str("romeo@montague.lit").unwrap()));
260 assert_eq!(prefs.never, vec!(Jid::from_str("montague@montague.lit").unwrap()));
261
262 let elem2 = Element::from(prefs.clone());
263 println!("{:?}", elem2);
264 let prefs2 = Prefs::try_from(elem2).unwrap();
265 assert_eq!(prefs.default_, prefs2.default_);
266 assert_eq!(prefs.always, prefs2.always);
267 assert_eq!(prefs.never, prefs2.never);
268 }
269
270 #[test]
271 fn test_invalid_child() {
272 let elem: Element = "<query xmlns='urn:xmpp:mam:2'><coucou/></query>".parse().unwrap();
273 let error = Query::try_from(elem).unwrap_err();
274 let message = match error {
275 Error::ParseError(string) => string,
276 _ => panic!(),
277 };
278 assert_eq!(message, "Unknown child in query element.");
279 }
280
281 #[test]
282 fn test_serialise() {
283 let elem: Element = "<query xmlns='urn:xmpp:mam:2'/>".parse().unwrap();
284 let replace = Query { queryid: None, node: None, form: None, set: None };
285 let elem2 = replace.into();
286 assert_eq!(elem, elem2);
287 }
288}