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}