1// Copyright (c) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7use std::convert::TryFrom;
8use std::str::FromStr;
9
10use minidom::{Element, IntoElements, IntoAttributeValue, ElementEmitter};
11
12use jid::Jid;
13
14use error::Error;
15
16use ns;
17
18use body;
19use stanza_error;
20use chatstates;
21use receipts::Receipt;
22use delay;
23use attention::Attention;
24use message_correct::Replace;
25use eme;
26
27/// Lists every known payload of a `<message/>`.
28#[derive(Debug, Clone)]
29pub enum MessagePayload {
30 Body(body::Body),
31 StanzaError(stanza_error::StanzaError),
32 ChatState(chatstates::ChatState),
33 Receipt(Receipt),
34 Delay(delay::Delay),
35 Attention(Attention),
36 MessageCorrect(Replace),
37 ExplicitMessageEncryption(eme::ExplicitMessageEncryption),
38}
39
40#[derive(Debug, Clone, PartialEq)]
41pub enum MessageType {
42 Chat,
43 Error,
44 Groupchat,
45 Headline,
46 Normal,
47}
48
49impl Default for MessageType {
50 fn default() -> MessageType {
51 MessageType::Normal
52 }
53}
54
55impl FromStr for MessageType {
56 type Err = Error;
57
58 fn from_str(s: &str) -> Result<MessageType, Error> {
59 Ok(match s {
60 "chat" => MessageType::Chat,
61 "error" => MessageType::Error,
62 "groupchat" => MessageType::Groupchat,
63 "headline" => MessageType::Headline,
64 "normal" => MessageType::Normal,
65
66 _ => return Err(Error::ParseError("Invalid 'type' attribute on message element.")),
67 })
68 }
69}
70
71impl IntoAttributeValue for MessageType {
72 fn into_attribute_value(self) -> Option<String> {
73 Some(match self {
74 MessageType::Chat => "chat",
75 MessageType::Error => "error",
76 MessageType::Groupchat => "groupchat",
77 MessageType::Headline => "headline",
78 MessageType::Normal => "normal",
79 }.to_owned())
80 }
81}
82
83#[derive(Debug, Clone)]
84pub enum MessagePayloadType {
85 XML(Element),
86 Parsed(MessagePayload),
87}
88
89#[derive(Debug, Clone)]
90pub struct Message {
91 pub from: Option<Jid>,
92 pub to: Option<Jid>,
93 pub id: Option<String>,
94 pub type_: MessageType,
95 pub payloads: Vec<MessagePayloadType>,
96}
97
98pub fn parse_message(root: &Element) -> Result<Message, Error> {
99 if !root.is("message", ns::JABBER_CLIENT) {
100 return Err(Error::ParseError("This is not a message element."));
101 }
102 let from = root.attr("from")
103 .and_then(|value| value.parse().ok());
104 let to = root.attr("to")
105 .and_then(|value| value.parse().ok());
106 let id = root.attr("id")
107 .and_then(|value| value.parse().ok());
108 let type_ = match root.attr("type") {
109 Some(type_) => type_.parse()?,
110 None => Default::default(),
111 };
112 let mut payloads = vec!();
113 for elem in root.children() {
114 let payload = if let Ok(body) = body::parse_body(elem) {
115 Some(MessagePayload::Body(body))
116 } else if let Ok(stanza_error) = stanza_error::parse_stanza_error(elem) {
117 Some(MessagePayload::StanzaError(stanza_error))
118 } else if let Ok(chatstate) = chatstates::parse_chatstate(elem) {
119 Some(MessagePayload::ChatState(chatstate))
120 } else if let Ok(receipt) = Receipt::try_from(elem) {
121 Some(MessagePayload::Receipt(receipt))
122 } else if let Ok(delay) = delay::parse_delay(elem) {
123 Some(MessagePayload::Delay(delay))
124 } else if let Ok(attention) = Attention::try_from(elem) {
125 Some(MessagePayload::Attention(attention))
126 } else if let Ok(replace) = Replace::try_from(elem) {
127 Some(MessagePayload::MessageCorrect(replace))
128 } else if let Ok(eme) = eme::parse_explicit_message_encryption(elem) {
129 Some(MessagePayload::ExplicitMessageEncryption(eme))
130 } else {
131 None
132 };
133 payloads.push(match payload {
134 Some(payload) => MessagePayloadType::Parsed(payload),
135 None => MessagePayloadType::XML(elem.clone()),
136 });
137 }
138 Ok(Message {
139 from: from,
140 to: to,
141 id: id,
142 type_: type_,
143 payloads: payloads,
144 })
145}
146
147pub fn serialise_payload(payload: &MessagePayload) -> Element {
148 match *payload {
149 MessagePayload::Body(ref body) => body::serialise(body),
150 MessagePayload::StanzaError(ref stanza_error) => stanza_error::serialise(stanza_error),
151 MessagePayload::Attention(ref attention) => attention.into(),
152 MessagePayload::ChatState(ref chatstate) => chatstates::serialise(chatstate),
153 MessagePayload::Receipt(ref receipt) => receipt.into(),
154 MessagePayload::Delay(ref delay) => delay::serialise(delay),
155 MessagePayload::MessageCorrect(ref replace) => replace.into(),
156 MessagePayload::ExplicitMessageEncryption(ref eme) => eme::serialise(eme),
157 }
158}
159
160pub fn serialise(message: &Message) -> Element {
161 let mut stanza = Element::builder("message")
162 .ns(ns::JABBER_CLIENT)
163 .attr("from", message.from.clone().and_then(|value| Some(String::from(value))))
164 .attr("to", message.to.clone().and_then(|value| Some(String::from(value))))
165 .attr("id", message.id.clone())
166 .attr("type", message.type_.clone())
167 .build();
168 for child in message.payloads.clone() {
169 let elem = match child {
170 MessagePayloadType::XML(elem) => elem,
171 MessagePayloadType::Parsed(payload) => serialise_payload(&payload),
172 };
173 stanza.append_child(elem);
174 }
175 stanza
176}
177
178impl IntoElements for Message {
179 fn into_elements(self, emitter: &mut ElementEmitter) {
180 let elem = serialise(&self);
181 emitter.append_child(elem);
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use std::str::FromStr;
188 use minidom::Element;
189 use jid::Jid;
190 use message;
191
192 #[test]
193 fn test_simple() {
194 let elem: Element = "<message xmlns='jabber:client'/>".parse().unwrap();
195 let message = message::parse_message(&elem).unwrap();
196 assert_eq!(message.from, None);
197 assert_eq!(message.to, None);
198 assert_eq!(message.id, None);
199 assert_eq!(message.type_, message::MessageType::Normal);
200 assert!(message.payloads.is_empty());
201 }
202
203 #[test]
204 fn test_serialise() {
205 let elem: Element = "<message xmlns='jabber:client' type='normal'/>".parse().unwrap();
206 let message = message::Message {
207 from: None,
208 to: None,
209 id: None,
210 type_: message::MessageType::Normal,
211 payloads: vec!(),
212 };
213 let elem2 = message::serialise(&message);
214 assert_eq!(elem, elem2);
215 }
216
217 #[test]
218 fn test_body() {
219 let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
220 message::parse_message(&elem).unwrap();
221 }
222
223 #[test]
224 fn test_serialise_body() {
225 let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
226 let message = message::Message {
227 from: None,
228 to: Some(Jid::from_str("coucou@example.org").unwrap()),
229 id: None,
230 type_: message::MessageType::Chat,
231 payloads: vec!(
232 message::MessagePayloadType::Parsed(message::MessagePayload::Body("Hello world!".to_owned())),
233 ),
234 };
235 let elem2 = message::serialise(&message);
236 assert_eq!(elem, elem2);
237 }
238
239 #[test]
240 fn test_attention() {
241 let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><attention xmlns='urn:xmpp:attention:0'/></message>".parse().unwrap();
242 let message = message::parse_message(&elem).unwrap();
243 let elem2 = message::serialise(&message);
244 assert_eq!(elem, elem2);
245 }
246}