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