1// Copyright (c) 2018 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::str::FromStr;
8use try_from::TryFrom;
9
10use minidom::Element;
11
12use error::Error;
13use jid::Jid;
14use ns;
15
16#[derive(Debug, Clone, PartialEq)]
17pub enum Bind {
18 None,
19 Resource(String),
20 Jid(Jid),
21}
22
23impl Bind {
24 pub fn new(resource: Option<String>) -> Bind {
25 match resource {
26 None => Bind::None,
27 Some(resource) => Bind::Resource(resource),
28 }
29 }
30}
31
32impl TryFrom<Element> for Bind {
33 type Err = Error;
34
35 fn try_from(elem: Element) -> Result<Bind, Error> {
36 check_self!(elem, "bind", ns::BIND);
37 check_no_attributes!(elem, "bind");
38
39 let mut bind = Bind::None;
40 for child in elem.children() {
41 if bind != Bind::None {
42 return Err(Error::ParseError("Bind can only have one child."));
43 }
44 if child.is("resource", ns::BIND) {
45 check_no_children!(child, "resource");
46 bind = Bind::Resource(child.text());
47 } else if child.is("jid", ns::BIND) {
48 check_no_children!(child, "jid");
49 bind = Bind::Jid(Jid::from_str(&child.text())?);
50 } else {
51 return Err(Error::ParseError("Unknown element in bind."));
52 }
53 }
54
55 Ok(bind)
56 }
57}
58
59impl From<Bind> for Element {
60 fn from(bind: Bind) -> Element {
61 Element::builder("bind")
62 .ns(ns::BIND)
63 .append(match bind {
64 Bind::None => vec!(),
65 Bind::Resource(resource) => vec!(
66 Element::builder("resource")
67 .ns(ns::BIND)
68 .append(resource)
69 .build()
70 ),
71 Bind::Jid(jid) => vec!(
72 Element::builder("jid")
73 .ns(ns::BIND)
74 .append(jid)
75 .build()
76 ),
77 })
78 .build()
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_simple() {
88 let elem: Element = "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>".parse().unwrap();
89 let bind = Bind::try_from(elem).unwrap();
90 assert_eq!(bind, Bind::None);
91 }
92}