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