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 Element::builder("query")
192 .ns(ns::MAM)
193 .attr("queryid", self.queryid)
194 .attr("node", self.node)
195 //.append(self.form.map(|form| -> Element { form.into() }))
196 .append(self.set.map(|set| -> Element { set.into() }))
197 .build()
198 }
199}
200
201impl Into<Element> for Result_ {
202 fn into(self) -> Element {
203 let mut elem = Element::builder("result")
204 .ns(ns::MAM)
205 .attr("queryid", self.queryid)
206 .attr("id", self.id)
207 .build();
208 elem.append_child(self.forwarded.into());
209 elem
210 }
211}
212
213impl Into<Element> for Fin {
214 fn into(self) -> Element {
215 let mut elem = Element::builder("fin")
216 .ns(ns::MAM)
217 .attr("complete", if self.complete { Some("true") } else { None })
218 .build();
219 elem.append_child(self.set.into());
220 elem
221 }
222}
223
224impl Into<Element> for Prefs {
225 fn into(self) -> Element {
226 let mut elem = Element::builder("prefs")
227 .ns(ns::MAM)
228 .attr("default", self.default_)
229 .build();
230 if !self.always.is_empty() {
231 let mut always = Element::builder("always")
232 .ns(ns::RSM)
233 .build();
234 for jid in self.always {
235 always.append_child(Element::builder("jid")
236 .ns(ns::RSM)
237 .append(String::from(jid))
238 .build());
239 }
240 elem.append_child(always);
241 }
242 if !self.never.is_empty() {
243 let mut never = Element::builder("never")
244 .ns(ns::RSM)
245 .build();
246 for jid in self.never {
247 never.append_child(Element::builder("jid")
248 .ns(ns::RSM)
249 .append(String::from(jid))
250 .build());
251 }
252 elem.append_child(never);
253 }
254 elem
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261
262 #[test]
263 fn test_query() {
264 let elem: Element = "<query xmlns='urn:xmpp:mam:2'/>".parse().unwrap();
265 Query::try_from(elem).unwrap();
266 }
267
268 #[test]
269 fn test_result() {
270 let elem: Element = r#"
271<result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
272 <forwarded xmlns='urn:xmpp:forward:0'>
273 <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
274 <message xmlns='jabber:client' from="witch@shakespeare.lit" to="macbeth@shakespeare.lit">
275 <body>Hail to thee</body>
276 </message>
277 </forwarded>
278</result>
279"#.parse().unwrap();
280 Result_::try_from(elem).unwrap();
281 }
282
283 #[test]
284 fn test_fin() {
285 let elem: Element = r#"
286<fin xmlns='urn:xmpp:mam:2'>
287 <set xmlns='http://jabber.org/protocol/rsm'>
288 <first index='0'>28482-98726-73623</first>
289 <last>09af3-cc343-b409f</last>
290 </set>
291</fin>
292"#.parse().unwrap();
293 Fin::try_from(elem).unwrap();
294 }
295
296 #[test]
297 fn test_query_x() {
298 let elem: Element = r#"
299<query xmlns='urn:xmpp:mam:2'>
300 <x xmlns='jabber:x:data' type='submit'>
301 <field var='FORM_TYPE' type='hidden'>
302 <value>urn:xmpp:mam:2</value>
303 </field>
304 <field var='with'>
305 <value>juliet@capulet.lit</value>
306 </field>
307 </x>
308</query>
309"#.parse().unwrap();
310 Query::try_from(elem).unwrap();
311 }
312
313 #[test]
314 fn test_query_x_set() {
315 let elem: Element = r#"
316<query xmlns='urn:xmpp:mam:2'>
317 <x xmlns='jabber:x:data' type='submit'>
318 <field var='FORM_TYPE' type='hidden'>
319 <value>urn:xmpp:mam:2</value>
320 </field>
321 <field var='start'>
322 <value>2010-08-07T00:00:00Z</value>
323 </field>
324 </x>
325 <set xmlns='http://jabber.org/protocol/rsm'>
326 <max>10</max>
327 </set>
328</query>
329"#.parse().unwrap();
330 Query::try_from(elem).unwrap();
331 }
332
333 #[test]
334 fn test_prefs_get() {
335 let elem: Element = "<prefs xmlns='urn:xmpp:mam:2' default='always'/>".parse().unwrap();
336 Prefs::try_from(elem).unwrap();
337
338 let elem: Element = r#"
339<prefs xmlns='urn:xmpp:mam:2' default='roster'>
340 <always/>
341 <never/>
342</prefs>
343"#.parse().unwrap();
344 Prefs::try_from(elem).unwrap();
345 }
346
347 #[test]
348 fn test_prefs_result() {
349 let elem: Element = r#"
350<prefs xmlns='urn:xmpp:mam:2' default='roster'>
351 <always>
352 <jid>romeo@montague.lit</jid>
353 </always>
354 <never>
355 <jid>montague@montague.lit</jid>
356 </never>
357</prefs>
358"#.parse().unwrap();
359 Prefs::try_from(elem).unwrap();
360 }
361
362 #[test]
363 fn test_invalid_child() {
364 let elem: Element = "<query xmlns='urn:xmpp:mam:2'><coucou/></query>".parse().unwrap();
365 let error = Query::try_from(elem).unwrap_err();
366 let message = match error {
367 Error::ParseError(string) => string,
368 _ => panic!(),
369 };
370 assert_eq!(message, "Unknown child in query element.");
371 }
372
373 #[test]
374 fn test_serialise() {
375 let elem: Element = "<query xmlns='urn:xmpp:mam:2'/>".parse().unwrap();
376 let replace = Query { queryid: None, node: None, form: None, set: None };
377 let elem2 = replace.into();
378 assert_eq!(elem, elem2);
379 }
380}