ibb.rs

  1use std::str::FromStr;
  2
  3use minidom::Element;
  4
  5use error::Error;
  6
  7use ns::IBB_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", IBB_NS) {
 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}