diff --git a/src/jingle_message.rs b/src/jingle_message.rs new file mode 100644 index 00000000..d6113342 --- /dev/null +++ b/src/jingle_message.rs @@ -0,0 +1,132 @@ +// Copyright (c) 2017 Emmanuel Gil Peyrot +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use std::convert::TryFrom; + +use minidom::Element; + +use error::Error; + +use jingle::SessionId; + +use ns; + +#[derive(Debug, Clone)] +pub enum JingleMI { + Propose { + sid: SessionId, + // TODO: Use a more specialised type here. + description: Element, + }, + Retract(SessionId), + Accept(SessionId), + Proceed(SessionId), + Reject(SessionId), +} + +fn get_sid(elem: Element) -> Result { + for (attr, _) in elem.attrs() { + if attr != "id" { + return Err(Error::ParseError("Unknown attribute in Jingle message element.")); + } + } + Ok(SessionId(get_attr!(elem, "id", required))) +} + +fn check_empty_and_get_sid(elem: Element) -> Result { + for _ in elem.children() { + return Err(Error::ParseError("Unknown child in Jingle message element.")); + } + get_sid(elem) +} + +impl TryFrom for JingleMI { + type Error = Error; + + fn try_from(elem: Element) -> Result { + if elem.ns() != Some(ns::JINGLE_MESSAGE) { + return Err(Error::ParseError("This is not a Jingle message element.")); + } + Ok(match elem.name() { + "propose" => { + let mut description = None; + for child in elem.children() { + if child.name() != "description" { + return Err(Error::ParseError("Unknown child in propose element.")); + } + if description.is_some() { + return Err(Error::ParseError("Too many children in propose element.")); + } + description = Some(child.clone()); + } + JingleMI::Propose { + sid: get_sid(elem)?, + description: description.ok_or(Error::ParseError("Propose element doesn’t contain a description."))?, + } + }, + "retract" => JingleMI::Retract(check_empty_and_get_sid(elem)?), + "accept" => JingleMI::Accept(check_empty_and_get_sid(elem)?), + "proceed" => JingleMI::Proceed(check_empty_and_get_sid(elem)?), + "reject" => JingleMI::Reject(check_empty_and_get_sid(elem)?), + _ => return Err(Error::ParseError("This is not a Jingle message element.")), + }) + } +} + +impl From for Element { + fn from(jingle_mi: JingleMI) -> Element { + match jingle_mi { + JingleMI::Propose { sid, description } => { + Element::builder("propose") + .ns(ns::JINGLE_MESSAGE) + .attr("id", sid) + .append(description) + }, + JingleMI::Retract(sid) => { + Element::builder("retract") + .ns(ns::JINGLE_MESSAGE) + .attr("id", sid) + } + JingleMI::Accept(sid) => { + Element::builder("accept") + .ns(ns::JINGLE_MESSAGE) + .attr("id", sid) + } + JingleMI::Proceed(sid) => { + Element::builder("proceed") + .ns(ns::JINGLE_MESSAGE) + .attr("id", sid) + } + JingleMI::Reject(sid) => { + Element::builder("reject") + .ns(ns::JINGLE_MESSAGE) + .attr("id", sid) + } + }.build() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_simple() { + let elem: Element = "".parse().unwrap(); + JingleMI::try_from(elem).unwrap(); + } + + #[test] + fn test_invalid_child() { + let elem: Element = "".parse().unwrap(); + let error = JingleMI::try_from(elem).unwrap_err(); + let message = match error { + Error::ParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message, "Unknown child in propose element."); + } +} diff --git a/src/lib.rs b/src/lib.rs index cb8b9d4a..f82e6df3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,7 +112,7 @@ macro_rules! generate_attribute { macro_rules! generate_id { ($elem:ident) => ( #[derive(Debug, Clone, PartialEq, Eq, Hash)] - pub struct $elem(String); + pub struct $elem(pub String); impl FromStr for $elem { type Err = Error; fn from_str(s: &str) -> Result<$elem, Error> { @@ -214,6 +214,9 @@ pub mod mam; /// XEP-0319: Last User Interaction in Presence pub mod idle; +/// XEP-0353: Jingle Message Initiation +pub mod jingle_message; + /// XEP-0359: Unique and Stable Stanza IDs pub mod stanza_id; diff --git a/src/ns.rs b/src/ns.rs index fbc0048f..7edee1e4 100644 --- a/src/ns.rs +++ b/src/ns.rs @@ -104,6 +104,9 @@ pub const MAM: &str = "urn:xmpp:mam:2"; /// XEP-0319: Last User Interaction in Presence pub const IDLE: &str = "urn:xmpp:idle:1"; +/// XEP-0353: Jingle Message Initiation +pub const JINGLE_MESSAGE: &str = "urn:xmpp:jingle-message:0"; + /// XEP-0359: Unique and Stable Stanza IDs pub const SID: &str = "urn:xmpp:sid:0";