From 72a6eee2fd9600c28bb70609b9911074fac509a4 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 29 Apr 2017 04:37:18 +0100 Subject: [PATCH] Add a RSM parser and serialiser. --- src/lib.rs | 3 + src/ns.rs | 3 + src/rsm.rs | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 src/rsm.rs diff --git a/src/lib.rs b/src/lib.rs index 0dde87af..81f62e2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,9 @@ pub mod disco; /// XEP-0047: In-Band Bytestreams pub mod ibb; +/// XEP-0059: Result Set Management +pub mod rsm; + /// XEP-0085: Chat State Notifications pub mod chatstates; diff --git a/src/ns.rs b/src/ns.rs index 16f73394..d06aff62 100644 --- a/src/ns.rs +++ b/src/ns.rs @@ -10,6 +10,9 @@ pub const DISCO_INFO: &'static str = "http://jabber.org/protocol/disco#info"; /// XEP-0047: In-Band Bytestreams pub const IBB: &'static str = "http://jabber.org/protocol/ibb"; +/// XEP-0059: Result Set Management +pub const RSM: &'static str = "http://jabber.org/protocol/rsm"; + /// XEP-0085: Chat State Notifications pub const CHATSTATES: &'static str = "http://jabber.org/protocol/chatstates"; diff --git a/src/rsm.rs b/src/rsm.rs new file mode 100644 index 00000000..a70bdd89 --- /dev/null +++ b/src/rsm.rs @@ -0,0 +1,186 @@ +use minidom::Element; + +use error::Error; + +use ns; + +#[derive(Debug, Clone)] +pub struct First { + pub index: Option, + pub base: String, +} + +#[derive(Debug, Clone)] +pub struct Set { + pub after: Option, + pub before: Option, + pub count: Option, + pub first: Option, + pub index: Option, + pub last: Option, + pub max: Option, +} + +pub fn parse_rsm(root: &Element) -> Result { + if !root.is("set", ns::RSM) { + return Err(Error::ParseError("This is not a RSM element.")); + } + let mut after = None; + let mut before = None; + let mut count = None; + let mut first = None; + let mut index = None; + let mut last = None; + let mut max = None; + for child in root.children() { + if child.is("after", ns::RSM) { + if after.is_some() { + return Err(Error::ParseError("Set can’t have more than one after.")); + } + after = Some(child.text()); + } else if child.is("before", ns::RSM) { + if before.is_some() { + return Err(Error::ParseError("Set can’t have more than one before.")); + } + before = Some(child.text()); + } else if child.is("count", ns::RSM) { + if count.is_some() { + return Err(Error::ParseError("Set can’t have more than one count.")); + } + count = Some(child.text().parse()?); + } else if child.is("first", ns::RSM) { + if first.is_some() { + return Err(Error::ParseError("Set can’t have more than one first.")); + } + first = Some(First { + index: match child.attr("index") { + Some(index) => Some(index.parse()?), + None => None, + }, + base: child.text(), + }); + } else if child.is("index", ns::RSM) { + if index.is_some() { + return Err(Error::ParseError("Set can’t have more than one index.")); + } + index = Some(child.text().parse()?); + } else if child.is("last", ns::RSM) { + if last.is_some() { + return Err(Error::ParseError("Set can’t have more than one last.")); + } + last = Some(child.text()); + } else if child.is("max", ns::RSM) { + if max.is_some() { + return Err(Error::ParseError("Set can’t have more than one max.")); + } + max = Some(child.text().parse()?); + } else { + return Err(Error::ParseError("Unknown child in set element.")); + } + } + Ok(Set { + after: after, + before: before, + count: count, + first: first, + index: index, + last: last, + max: max, + }) +} + +pub fn serialise(rsm: &Set) -> Element { + let mut elem = Element::builder("set") + .ns(ns::RSM) + .build(); + if rsm.after.is_some() { + elem.append_child(Element::builder("after").ns(ns::RSM).append(rsm.after.clone()).build()); + } + if rsm.before.is_some() { + elem.append_child(Element::builder("before").ns(ns::RSM).append(rsm.before.clone()).build()); + } + if rsm.count.is_some() { + elem.append_child(Element::builder("count").ns(ns::RSM).append(format!("{}", rsm.count.unwrap())).build()); + } + if rsm.first.is_some() { + let first = rsm.first.clone().unwrap(); + elem.append_child(Element::builder("first") + .ns(ns::RSM) + .attr("index", match first.index { + Some(index) => Some(format!("{}", index)), + None => None, + }) + .append(first.base.clone()).build()); + } + if rsm.index.is_some() { + elem.append_child(Element::builder("index").ns(ns::RSM).append(format!("{}", rsm.index.unwrap())).build()); + } + if rsm.last.is_some() { + elem.append_child(Element::builder("last").ns(ns::RSM).append(rsm.last.clone()).build()); + } + if rsm.max.is_some() { + elem.append_child(Element::builder("max").ns(ns::RSM).append(format!("{}", rsm.max.unwrap())).build()); + } + elem +} + +#[cfg(test)] +mod tests { + use minidom::Element; + use error::Error; + use rsm; + + #[test] + fn test_simple() { + let elem: Element = "".parse().unwrap(); + let set = rsm::parse_rsm(&elem).unwrap(); + assert_eq!(set.after, None); + assert_eq!(set.before, None); + assert_eq!(set.count, None); + match set.first { + Some(_) => panic!(), + None => (), + } + assert_eq!(set.index, None); + assert_eq!(set.last, None); + assert_eq!(set.max, None); + } + + #[test] + fn test_unknown() { + let elem: Element = "".parse().unwrap(); + let error = rsm::parse_rsm(&elem).unwrap_err(); + let message = match error { + Error::ParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message, "This is not a RSM element."); + } + + #[test] + fn test_invalid_child() { + let elem: Element = "".parse().unwrap(); + let error = rsm::parse_rsm(&elem).unwrap_err(); + let message = match error { + Error::ParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message, "Unknown child in set element."); + } + + #[test] + fn test_serialise() { + let elem: Element = "".parse().unwrap(); + let rsm = rsm::Set { + after: None, + before: None, + count: None, + first: None, + index: None, + last: None, + max: None, + }; + let elem2 = rsm::serialise(&rsm); + assert_eq!(elem, elem2); + } +}