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