message.rs

  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}