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 error::Error;
172    use jid::Jid;
173    use message;
174
175    #[test]
176    fn test_simple() {
177        let elem: Element = "<message xmlns='jabber:client'/>".parse().unwrap();
178        let message = message::parse_message(&elem).unwrap();
179        assert_eq!(message.from, None);
180        assert_eq!(message.to, None);
181        assert_eq!(message.id, None);
182        assert_eq!(message.type_, message::MessageType::Normal);
183        assert!(message.payloads.is_empty());
184    }
185
186    #[test]
187    fn test_serialise() {
188        let elem: Element = "<message xmlns='jabber:client' type='normal'/>".parse().unwrap();
189        let message = message::parse_message(&elem).unwrap();
190        let message2 = message::Message {
191            from: None,
192            to: None,
193            id: None,
194            type_: message::MessageType::Normal,
195            payloads: vec!(),
196        };
197        let elem2 = message::serialise(&message2);
198        assert_eq!(elem, elem2);
199        println!("{:#?}", message);
200    }
201
202    #[test]
203    fn test_body() {
204        let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
205        let message = message::parse_message(&elem).unwrap();
206        println!("{:#?}", message);
207    }
208
209    #[test]
210    fn test_serialise_body() {
211        let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
212        let message = message::parse_message(&elem).unwrap();
213        let message2 = message::Message {
214            from: None,
215            to: Some(Jid::from_str("coucou@example.org").unwrap()),
216            id: None,
217            type_: message::MessageType::Chat,
218            payloads: vec!(
219                message::MessagePayloadType::Parsed(message::MessagePayload::Body("Hello world!".to_owned())),
220            ),
221        };
222        let elem2 = message::serialise(&message2);
223        assert_eq!(elem, elem2);
224        println!("{:#?}", message);
225    }
226
227    #[test]
228    fn test_attention() {
229        let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><attention xmlns='urn:xmpp:attention:0'/></message>".parse().unwrap();
230        let message = message::parse_message(&elem).unwrap();
231        let elem2 = message::serialise(&message);
232        assert_eq!(elem, elem2);
233    }
234}