diff --git a/src/jingle.rs b/src/jingle.rs index 4c568bfc..fbccce0d 100644 --- a/src/jingle.rs +++ b/src/jingle.rs @@ -6,6 +6,9 @@ use crate::util::error::Error; use crate::iq::IqSetPayload; +use crate::jingle_ice_udp::Transport as IceUdpTransport; +use crate::jingle_ibb::Transport as IbbTransport; +use crate::jingle_s5b::Transport as Socks5Transport; use crate::ns; use jid::Jid; use crate::Element; @@ -164,6 +167,78 @@ generate_id!( ContentId ); +/// Enum wrapping all of the various supported transports of a Content. +#[derive(Debug, Clone)] +pub enum Transport { + /// Jingle ICE-UDP Bytestreams (XEP-0176) transport. + IceUdp(IceUdpTransport), + + /// Jingle In-Band Bytestreams (XEP-0261) transport. + Ibb(IbbTransport), + + /// Jingle SOCKS5 Bytestreams (XEP-0260) transport. + Socks5(Socks5Transport), + + /// To be used for any transport that isn’t known at compile-time. + Unknown(Element), +} + +impl TryFrom for Transport { + type Error = Error; + + fn try_from(elem: Element) -> Result { + Ok(if elem.is("transport", ns::JINGLE_ICE_UDP) { + Transport::IceUdp(IceUdpTransport::try_from(elem)?) + } else if elem.is("transport", ns::JINGLE_IBB) { + Transport::Ibb(IbbTransport::try_from(elem)?) + } else if elem.is("transport", ns::JINGLE_S5B) { + Transport::Socks5(Socks5Transport::try_from(elem)?) + } else { + Transport::Unknown(elem) + }) + } +} + +impl From for Transport { + fn from(transport: IceUdpTransport) -> Transport { + Transport::IceUdp(transport) + } +} + +impl From for Transport { + fn from(transport: IbbTransport) -> Transport { + Transport::Ibb(transport) + } +} + +impl From for Transport { + fn from(transport: Socks5Transport) -> Transport { + Transport::Socks5(transport) + } +} + +impl From for Element { + fn from(transport: Transport) -> Element { + match transport { + Transport::IceUdp(transport) => transport.into(), + Transport::Ibb(transport) => transport.into(), + Transport::Socks5(transport) => transport.into(), + Transport::Unknown(elem) => elem, + } + } +} + +impl Transport { + fn get_ns(&self) -> String { + match self { + Transport::IceUdp(_) => String::from(ns::JINGLE_ICE_UDP), + Transport::Ibb(_) => String::from(ns::JINGLE_IBB), + Transport::Socks5(_) => String::from(ns::JINGLE_S5B), + Transport::Unknown(elem) => elem.ns().unwrap_or_else(|| String::new()), + } + } +} + generate_element!( /// Describes a session’s content, there can be multiple content in one /// session. @@ -186,7 +261,7 @@ generate_element!( description: Option = ("description", JINGLE) => Element, /// How to send it. - transport: Option = ("transport", JINGLE) => Element, + transport: Option = ("transport", *) => Transport, /// With which security. security: Option = ("security", JINGLE) => Element @@ -226,8 +301,8 @@ impl Content { } /// Set the transport of this content. - pub fn with_transport(mut self, transport: Element) -> Content { - self.transport = Some(transport); + pub fn with_transport>(mut self, transport: T) -> Content { + self.transport = Some(transport.into()); self } @@ -575,7 +650,7 @@ mod tests { assert_size!(Senders, 1); assert_size!(Disposition, 1); assert_size!(ContentId, 24); - assert_size!(Content, 344); + assert_size!(Content, 384); assert_size!(Reason, 1); assert_size!(ReasonElement, 32); assert_size!(SessionId, 24); @@ -626,18 +701,18 @@ mod tests { #[test] fn test_content() { - let elem: Element = "".parse().unwrap(); + let elem: Element = "".parse().unwrap(); let jingle = Jingle::try_from(elem).unwrap(); assert_eq!(jingle.contents[0].creator, Creator::Initiator); assert_eq!(jingle.contents[0].name, ContentId(String::from("coucou"))); assert_eq!(jingle.contents[0].senders, Senders::Both); assert_eq!(jingle.contents[0].disposition, Disposition::Session); - let elem: Element = "".parse().unwrap(); + let elem: Element = "".parse().unwrap(); let jingle = Jingle::try_from(elem).unwrap(); assert_eq!(jingle.contents[0].senders, Senders::Both); - let elem: Element = "".parse().unwrap(); + let elem: Element = "".parse().unwrap(); let jingle = Jingle::try_from(elem).unwrap(); assert_eq!(jingle.contents[0].disposition, Disposition::EarlySession); }