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