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        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}