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        check_self!(elem, "query", ns::MAM);
 60        check_no_unknown_attributes!(elem, "query", ["queryid", "node"]);
 61        let mut form = None;
 62        let mut set = None;
 63        for child in elem.children() {
 64            if child.is("x", ns::DATA_FORMS) {
 65                form = Some(DataForm::try_from(child.clone())?);
 66            } else if child.is("set", ns::RSM) {
 67                set = Some(Set::try_from(child.clone())?);
 68            } else {
 69                return Err(Error::ParseError("Unknown child in query element."));
 70            }
 71        }
 72        let queryid = get_attr!(elem, "queryid", optional);
 73        let node = get_attr!(elem, "node", optional);
 74        Ok(Query { queryid, node, form, set })
 75    }
 76}
 77
 78impl TryFrom<Element> for Result_ {
 79    type Err = Error;
 80
 81    fn try_from(elem: Element) -> Result<Result_, Error> {
 82        check_self!(elem, "result", ns::MAM);
 83        check_no_unknown_attributes!(elem, "result", ["queryid", "id"]);
 84        let mut forwarded = None;
 85        for child in elem.children() {
 86            if child.is("forwarded", ns::FORWARD) {
 87                forwarded = Some(Forwarded::try_from(child.clone())?);
 88            } else {
 89                return Err(Error::ParseError("Unknown child in result element."));
 90            }
 91        }
 92        let forwarded = forwarded.ok_or(Error::ParseError("Mandatory forwarded element missing in result."))?;
 93        let queryid = get_attr!(elem, "queryid", required);
 94        let id = get_attr!(elem, "id", required);
 95        Ok(Result_ {
 96            queryid,
 97            id,
 98            forwarded,
 99        })
100    }
101}
102
103impl TryFrom<Element> for Fin {
104    type Err = Error;
105
106    fn try_from(elem: Element) -> Result<Fin, Error> {
107        check_self!(elem, "fin", ns::MAM);
108        check_no_unknown_attributes!(elem, "fin", ["complete"]);
109        let mut set = None;
110        for child in elem.children() {
111            if child.is("set", ns::RSM) {
112                set = Some(Set::try_from(child.clone())?);
113            } else {
114                return Err(Error::ParseError("Unknown child in fin element."));
115            }
116        }
117        let set = set.ok_or(Error::ParseError("Mandatory set element missing in fin."))?;
118        let complete = match elem.attr("complete") {
119            Some(complete) if complete == "true" => true,
120            Some(complete) if complete == "false" => false,
121            None => false,
122            Some(_) => return Err(Error::ParseError("Invalid value for 'complete' attribute.")),
123        };
124        Ok(Fin { complete, set })
125    }
126}
127
128impl TryFrom<Element> for Prefs {
129    type Err = Error;
130
131    fn try_from(elem: Element) -> Result<Prefs, Error> {
132        check_self!(elem, "prefs", ns::MAM);
133        check_no_unknown_attributes!(elem, "prefs", ["default"]);
134        let mut always = vec!();
135        let mut never = vec!();
136        for child in elem.children() {
137            if child.is("always", ns::MAM) {
138                for jid_elem in child.children() {
139                    if !jid_elem.is("jid", ns::MAM) {
140                        return Err(Error::ParseError("Invalid jid element in always."));
141                    }
142                    always.push(jid_elem.text().parse()?);
143                }
144            } else if child.is("never", ns::MAM) {
145                for jid_elem in child.children() {
146                    if !jid_elem.is("jid", ns::MAM) {
147                        return Err(Error::ParseError("Invalid jid element in never."));
148                    }
149                    never.push(jid_elem.text().parse()?);
150                }
151            } else {
152                return Err(Error::ParseError("Unknown child in prefs element."));
153            }
154        }
155        let default_ = get_attr!(elem, "default", required);
156        Ok(Prefs { default_, always, never })
157    }
158}
159
160impl From<Query> for Element {
161    fn from(query: Query) -> Element {
162        Element::builder("query")
163                .ns(ns::MAM)
164                .attr("queryid", query.queryid)
165                .attr("node", query.node)
166                //.append(query.form)
167                .append(query.set)
168                .build()
169    }
170}
171
172impl From<Result_> for Element {
173    fn from(result: Result_) -> Element {
174        Element::builder("result")
175                .ns(ns::MAM)
176                .attr("queryid", result.queryid)
177                .attr("id", result.id)
178                .append(result.forwarded)
179                .build()
180    }
181}
182
183impl From<Fin> for Element {
184    fn from(fin: Fin) -> Element {
185        Element::builder("fin")
186                .ns(ns::MAM)
187                .attr("complete", if fin.complete { Some("true") } else { None })
188                .append(fin.set)
189                .build()
190    }
191}
192
193fn serialise_jid_list(name: &str, jids: Vec<Jid>) -> Option<Element> {
194    if jids.is_empty() {
195        None
196    } else {
197        Some(Element::builder(name)
198                     .ns(ns::MAM)
199                     .append(jids.into_iter()
200                                 .map(|jid| Element::builder("jid")
201                                                    .ns(ns::MAM)
202                                                    .append(jid)
203                                                    .build())
204                                 .collect::<Vec<_>>())
205                     .build())
206    }
207}
208
209impl From<Prefs> for Element {
210    fn from(prefs: Prefs) -> Element {
211        Element::builder("prefs")
212                .ns(ns::MAM)
213                .attr("default", prefs.default_)
214                .append(serialise_jid_list("always", prefs.always))
215                .append(serialise_jid_list("never", prefs.never))
216                .build()
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use super::*;
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}