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