diff --git a/src/presence.rs b/src/presence.rs index e1212c7..67ca5fa 100644 --- a/src/presence.rs +++ b/src/presence.rs @@ -53,6 +53,34 @@ pub enum PresencePayload { ECaps2(ECaps2), } +impl<'a> TryFrom<&'a Element> for PresencePayload { + type Error = Error; + + fn try_from(elem: &'a Element) -> Result { + Ok(match (elem.name().as_ref(), elem.ns().unwrap().as_ref()) { + ("error", ns::JABBER_CLIENT) => PresencePayload::StanzaError(StanzaError::try_from(elem)?), + + // XEP-0203 + ("delay", ns::DELAY) => PresencePayload::Delay(Delay::try_from(elem)?), + + // XEP-0390 + ("c", ns::ECAPS2) => PresencePayload::ECaps2(ECaps2::try_from(elem)?), + + _ => return Err(Error::ParseError("Unknown presence payload.")) + }) + } +} + +impl<'a> Into for &'a PresencePayload { + fn into(self) -> Element { + match *self { + PresencePayload::StanzaError(ref stanza_error) => stanza_error.into(), + PresencePayload::Delay(ref delay) => delay.into(), + PresencePayload::ECaps2(ref ecaps2) => ecaps2.into(), + } + } +} + #[derive(Debug, Clone, PartialEq)] pub enum PresenceType { /// This value is not an acceptable 'type' attribute, it is only used @@ -107,12 +135,6 @@ impl IntoAttributeValue for PresenceType { } } -#[derive(Debug, Clone)] -pub enum PresencePayloadType { - XML(Element), - Parsed(PresencePayload), -} - #[derive(Debug, Clone)] pub struct Presence { pub from: Option, @@ -122,7 +144,7 @@ pub struct Presence { pub show: Option, pub statuses: BTreeMap, pub priority: Priority, - pub payloads: Vec, + pub payloads: Vec, } impl<'a> TryFrom<&'a Element> for Presence { @@ -179,19 +201,7 @@ impl<'a> TryFrom<&'a Element> for Presence { } priority = Some(Priority::from_str(elem.text().as_ref())?); } else { - let payload = if let Ok(stanza_error) = StanzaError::try_from(elem) { - Some(PresencePayload::StanzaError(stanza_error)) - } else if let Ok(delay) = Delay::try_from(elem) { - Some(PresencePayload::Delay(delay)) - } else if let Ok(ecaps2) = ECaps2::try_from(elem) { - Some(PresencePayload::ECaps2(ecaps2)) - } else { - None - }; - payloads.push(match payload { - Some(payload) => PresencePayloadType::Parsed(payload), - None => PresencePayloadType::XML(elem.clone()), - }); + payloads.push(elem.clone()); } } Ok(Presence { @@ -207,16 +217,6 @@ impl<'a> TryFrom<&'a Element> for Presence { } } -impl<'a> Into for &'a PresencePayload { - fn into(self) -> Element { - match *self { - PresencePayload::StanzaError(ref stanza_error) => stanza_error.into(), - PresencePayload::Delay(ref delay) => delay.into(), - PresencePayload::ECaps2(ref ecaps2) => ecaps2.into(), - } - } -} - impl<'a> Into for &'a Presence { fn into(self) -> Element { let mut stanza = Element::builder("presence") @@ -225,13 +225,20 @@ impl<'a> Into for &'a Presence { .attr("to", self.to.clone().and_then(|value| Some(String::from(value)))) .attr("id", self.id.clone()) .attr("type", self.type_.clone()) + .append(self.show.clone()) + .append(self.statuses.iter().map(|(lang, status)| { + Element::builder("status") + .attr("xml:lang", match lang.as_ref() { + "" => None, + lang => Some(lang), + }) + .append(status.clone()) + .build() + }).collect::>()) + .append(if self.priority == 0 { None } else { Some(format!("{}", self.priority)) }) .build(); for child in self.payloads.clone() { - let elem = match child { - PresencePayloadType::XML(elem) => elem, - PresencePayloadType::Parsed(payload) => (&payload).into(), - }; - stanza.append_child(elem); + stanza.append_child(child); } stanza } @@ -241,7 +248,6 @@ impl<'a> Into for &'a Presence { mod tests { use std::collections::BTreeMap; use super::*; - use ns; #[test] fn test_simple() { @@ -364,11 +370,8 @@ mod tests { fn test_unknown_child() { let elem: Element = "".parse().unwrap(); let presence = Presence::try_from(&elem).unwrap(); - if let PresencePayloadType::XML(ref payload) = presence.payloads[0] { - assert!(payload.is("test", "invalid")); - } else { - panic!("Did successfully parse an invalid element."); - } + let payload = &presence.payloads[0]; + assert!(payload.is("test", "invalid")); } #[test] @@ -398,16 +401,17 @@ mod tests { #[test] fn test_serialise_status() { let status = Status::from("Hello world!"); - let payloads = vec!(PresencePayloadType::Parsed(PresencePayload::Status(status))); + let mut statuses = BTreeMap::new(); + statuses.insert(String::from(""), status); let presence = Presence { from: None, to: None, id: None, type_: PresenceType::Unavailable, show: None, - statuses: BTreeMap::new(), + statuses: statuses, priority: 0i8, - payloads: payloads, + payloads: vec!(), }; let elem: Element = (&presence).into(); assert!(elem.is("presence", ns::JABBER_CLIENT));