presence.rs

  1use std::str::FromStr;
  2
  3use minidom::Element;
  4use minidom::IntoAttributeValue;
  5
  6use jid::Jid;
  7
  8use error::Error;
  9
 10use ns;
 11
 12use status;
 13use delay;
 14use ecaps2;
 15
 16/// Lists every known payload of a `<presence/>`.
 17#[derive(Debug, Clone)]
 18pub enum PresencePayload {
 19    Status(status::Status),
 20    Delay(delay::Delay),
 21    ECaps2(ecaps2::ECaps2),
 22}
 23
 24#[derive(Debug, Clone, PartialEq)]
 25pub enum PresenceType {
 26    /// This value is not an acceptable 'type' attribute, it is only used
 27    /// internally to signal the absence of 'type'.
 28    Available,
 29    Error,
 30    Probe,
 31    Subscribe,
 32    Subscribed,
 33    Unavailable,
 34    Unsubscribe,
 35    Unsubscribed,
 36}
 37
 38impl Default for PresenceType {
 39    fn default() -> PresenceType {
 40        PresenceType::Available
 41    }
 42}
 43
 44impl FromStr for PresenceType {
 45    type Err = Error;
 46
 47    fn from_str(s: &str) -> Result<PresenceType, Error> {
 48        Ok(match s {
 49            "error" => PresenceType::Error,
 50            "probe" => PresenceType::Probe,
 51            "subscribe" => PresenceType::Subscribe,
 52            "subscribed" => PresenceType::Subscribed,
 53            "unavailable" => PresenceType::Unavailable,
 54            "unsubscribe" => PresenceType::Unsubscribe,
 55            "unsubscribed" => PresenceType::Unsubscribed,
 56
 57            _ => return Err(Error::ParseError("Invalid 'type' attribute on presence element.")),
 58        })
 59    }
 60}
 61
 62impl IntoAttributeValue for PresenceType {
 63    fn into_attribute_value(self) -> Option<String> {
 64        Some(match self {
 65            PresenceType::Available => return None,
 66
 67            PresenceType::Error => "error",
 68            PresenceType::Probe => "probe",
 69            PresenceType::Subscribe => "subscribe",
 70            PresenceType::Subscribed => "subscribed",
 71            PresenceType::Unavailable => "unavailable",
 72            PresenceType::Unsubscribe => "unsubscribe",
 73            PresenceType::Unsubscribed => "unsubscribed",
 74        }.to_owned())
 75    }
 76}
 77
 78#[derive(Debug, Clone)]
 79pub enum PresencePayloadType {
 80    XML(Element),
 81    Parsed(PresencePayload),
 82}
 83
 84#[derive(Debug, Clone)]
 85pub struct Presence {
 86    pub from: Option<Jid>,
 87    pub to: Option<Jid>,
 88    pub id: Option<String>,
 89    pub type_: PresenceType,
 90    pub payloads: Vec<PresencePayloadType>,
 91}
 92
 93pub fn parse_presence(root: &Element) -> Result<Presence, Error> {
 94    if !root.is("presence", ns::JABBER_CLIENT) {
 95        return Err(Error::ParseError("This is not a presence element."));
 96    }
 97    let from = root.attr("from")
 98        .and_then(|value| value.parse().ok());
 99    let to = root.attr("to")
100        .and_then(|value| value.parse().ok());
101    let id = root.attr("id")
102        .and_then(|value| value.parse().ok());
103    let type_ = match root.attr("type") {
104        Some(type_) => type_.parse()?,
105        None => Default::default(),
106    };
107    let mut payloads = vec!();
108    for elem in root.children() {
109        let payload = if let Ok(status) = status::parse_status(elem) {
110            Some(PresencePayload::Status(status))
111        } else if let Ok(delay) = delay::parse_delay(elem) {
112            Some(PresencePayload::Delay(delay))
113        } else if let Ok(ecaps2) = ecaps2::parse_ecaps2(elem) {
114            Some(PresencePayload::ECaps2(ecaps2))
115        } else {
116            None
117        };
118        payloads.push(match payload {
119            Some(payload) => PresencePayloadType::Parsed(payload),
120            None => PresencePayloadType::XML(elem.clone()),
121        });
122    }
123    Ok(Presence {
124        from: from,
125        to: to,
126        id: id,
127        type_: type_,
128        payloads: payloads,
129    })
130}
131
132pub fn serialise_payload(payload: &PresencePayload) -> Element {
133    match *payload {
134        PresencePayload::Status(ref status) => status::serialise(status),
135        PresencePayload::Delay(ref delay) => delay::serialise(delay),
136        PresencePayload::ECaps2(ref ecaps2) => ecaps2::serialise(ecaps2),
137    }
138}
139
140pub fn serialise(presence: &Presence) -> Element {
141    let mut stanza = Element::builder("presence")
142                             .ns(ns::JABBER_CLIENT)
143                             .attr("from", presence.from.clone().and_then(|value| Some(String::from(value))))
144                             .attr("to", presence.to.clone().and_then(|value| Some(String::from(value))))
145                             .attr("id", presence.id.clone())
146                             .attr("type", presence.type_.clone())
147                             .build();
148    for child in presence.payloads.clone() {
149        let elem = match child {
150            PresencePayloadType::XML(elem) => elem,
151            PresencePayloadType::Parsed(payload) => serialise_payload(&payload),
152        };
153        stanza.append_child(elem);
154    }
155    stanza
156}
157
158#[cfg(test)]
159mod tests {
160    use minidom::Element;
161    use presence;
162
163    #[test]
164    fn test_simple() {
165        let elem: Element = "<presence xmlns='jabber:client'/>".parse().unwrap();
166        let presence = presence::parse_presence(&elem).unwrap();
167        assert_eq!(presence.from, None);
168        assert_eq!(presence.to, None);
169        assert_eq!(presence.id, None);
170        assert_eq!(presence.type_, presence::PresenceType::Available);
171        assert!(presence.payloads.is_empty());
172    }
173
174    #[test]
175    fn test_serialise() {
176        let elem: Element = "<presence xmlns='jabber:client' type='unavailable'/>".parse().unwrap();
177        let presence = presence::parse_presence(&elem).unwrap();
178        let presence2 = presence::Presence {
179            from: None,
180            to: None,
181            id: None,
182            type_: presence::PresenceType::Unavailable,
183            payloads: vec!(),
184        };
185        let elem2 = presence::serialise(&presence2);
186        assert_eq!(elem, elem2);
187        println!("{:#?}", presence);
188    }
189}