1use std::str::FromStr;
2
3use minidom::Element;
4
5use error::Error;
6
7use ns;
8
9#[derive(Debug)]
10pub enum Stanza {
11 Iq,
12 Message,
13}
14
15impl Default for Stanza {
16 fn default() -> Stanza {
17 Stanza::Iq
18 }
19}
20
21impl FromStr for Stanza {
22 type Err = Error;
23
24 fn from_str(s: &str) -> Result<Stanza, Error> {
25 if s == "iq" {
26 Ok(Stanza::Iq)
27 } else if s == "message" {
28 Ok(Stanza::Message)
29 } else {
30 Err(Error::ParseError("Unknown 'stanza' attribute."))
31 }
32 }
33}
34
35#[derive(Debug)]
36pub enum IBB {
37 Open { block_size: u16, sid: String, stanza: Stanza },
38 Data(u16, String, Vec<u8>),
39 Close(String),
40}
41
42fn optional_attr<T: FromStr>(root: &Element, attr: &str) -> Option<T> {
43 root.attr(attr)
44 .and_then(|value| value.parse().ok())
45}
46
47fn required_attr<T: FromStr>(root: &Element, attr: &str, err: Error) -> Result<T, Error> {
48 optional_attr(root, attr).ok_or(err)
49}
50
51pub fn parse_ibb(root: &Element) -> Result<IBB, Error> {
52 if root.is("open", ns::IBB) {
53 let block_size = required_attr(root, "block-size", Error::ParseError("Required attribute 'block-size' missing in open element."))?;
54 let sid = required_attr(root, "sid", Error::ParseError("Required attribute 'sid' missing in open element."))?;
55 let stanza = root.attr("stanza")
56 .and_then(|value| value.parse().ok())
57 .unwrap_or(Default::default());
58 for _ in root.children() {
59 return Err(Error::ParseError("Unknown child in open element."));
60 }
61 Ok(IBB::Open {
62 block_size: block_size,
63 sid: sid,
64 stanza: stanza
65 })
66 } else {
67 Err(Error::ParseError("This is not an ibb element."))
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use minidom::Element;
74 use error::Error;
75 use ibb;
76
77 #[test]
78 fn test_simple() {
79 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb' block-size='128' sid='coucou'/>".parse().unwrap();
80 ibb::parse_ibb(&elem).unwrap();
81 }
82
83 #[test]
84 fn test_invalid() {
85 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb'/>".parse().unwrap();
86 let error = ibb::parse_ibb(&elem).unwrap_err();
87 let message = match error {
88 Error::ParseError(string) => string,
89 _ => panic!(),
90 };
91 assert_eq!(message, "Required attribute 'block-size' missing in open element.");
92
93 // TODO: maybe make a better error message here.
94 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb' block-size='-5'/>".parse().unwrap();
95 let error = ibb::parse_ibb(&elem).unwrap_err();
96 let message = match error {
97 Error::ParseError(string) => string,
98 _ => panic!(),
99 };
100 assert_eq!(message, "Required attribute 'block-size' missing in open element.");
101
102 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb' block-size='128'/>".parse().unwrap();
103 let error = ibb::parse_ibb(&elem).unwrap_err();
104 let message = match error {
105 Error::ParseError(string) => string,
106 _ => panic!(),
107 };
108 assert_eq!(message, "Required attribute 'sid' missing in open element.");
109 }
110
111 #[test]
112 #[ignore]
113 fn test_invalid_stanza() {
114 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb' block-size='128' sid='coucou' stanza='fdsq'/>".parse().unwrap();
115 let error = ibb::parse_ibb(&elem).unwrap_err();
116 let message = match error {
117 Error::ParseError(string) => string,
118 _ => panic!(),
119 };
120 assert_eq!(message, "Wrong value for 'stanza' attribute in open.");
121 }
122}