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