mam.rs

  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}