mirror of
https://gitlab.com/xmpp-rs/xmpp-rs.git
synced 2024-07-12 22:21:53 +00:00
message: Merge body in this module, and make it support xml:lang.
This commit is contained in:
parent
69cfb14c77
commit
4142107965
3 changed files with 53 additions and 117 deletions
86
src/body.rs
86
src/body.rs
|
@ -1,86 +0,0 @@
|
||||||
// Copyright (c) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
|
||||||
//
|
|
||||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
use minidom::Element;
|
|
||||||
|
|
||||||
use error::Error;
|
|
||||||
|
|
||||||
use ns;
|
|
||||||
|
|
||||||
pub type Body = String;
|
|
||||||
|
|
||||||
pub fn parse_body(root: &Element) -> Result<Body, Error> {
|
|
||||||
// TODO: also support components and servers.
|
|
||||||
if !root.is("body", ns::JABBER_CLIENT) {
|
|
||||||
return Err(Error::ParseError("This is not a body element."));
|
|
||||||
}
|
|
||||||
for _ in root.children() {
|
|
||||||
return Err(Error::ParseError("Unknown child in body element."));
|
|
||||||
}
|
|
||||||
Ok(root.text())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn serialise(body: &Body) -> Element {
|
|
||||||
Element::builder("body")
|
|
||||||
.ns(ns::JABBER_CLIENT)
|
|
||||||
.append(body.to_owned())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use minidom::Element;
|
|
||||||
use error::Error;
|
|
||||||
use body;
|
|
||||||
use ns;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_simple() {
|
|
||||||
let elem: Element = "<body xmlns='jabber:client'/>".parse().unwrap();
|
|
||||||
body::parse_body(&elem).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_invalid() {
|
|
||||||
let elem: Element = "<body xmlns='jabber:server'/>".parse().unwrap();
|
|
||||||
let error = body::parse_body(&elem).unwrap_err();
|
|
||||||
let message = match error {
|
|
||||||
Error::ParseError(string) => string,
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
|
||||||
assert_eq!(message, "This is not a body element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_invalid_child() {
|
|
||||||
let elem: Element = "<body xmlns='jabber:client'><coucou/></body>".parse().unwrap();
|
|
||||||
let error = body::parse_body(&elem).unwrap_err();
|
|
||||||
let message = match error {
|
|
||||||
Error::ParseError(string) => string,
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
|
||||||
assert_eq!(message, "Unknown child in body element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn test_invalid_attribute() {
|
|
||||||
let elem: Element = "<body xmlns='jabber:client' coucou=''/>".parse().unwrap();
|
|
||||||
let error = body::parse_body(&elem).unwrap_err();
|
|
||||||
let message = match error {
|
|
||||||
Error::ParseError(string) => string,
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
|
||||||
assert_eq!(message, "Unknown attribute in body element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_serialise() {
|
|
||||||
let body = body::Body::from("Hello world!");
|
|
||||||
let elem = body::serialise(&body);
|
|
||||||
assert!(elem.is("body", ns::JABBER_CLIENT));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -37,9 +37,6 @@ pub mod iq;
|
||||||
/// RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core
|
/// RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core
|
||||||
pub mod stanza_error;
|
pub mod stanza_error;
|
||||||
|
|
||||||
/// RFC 6121: Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence
|
|
||||||
pub mod body;
|
|
||||||
|
|
||||||
/// XEP-0004: Data Forms
|
/// XEP-0004: Data Forms
|
||||||
pub mod data_forms;
|
pub mod data_forms;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use minidom::{Element, IntoAttributeValue};
|
use minidom::{Element, IntoAttributeValue};
|
||||||
|
|
||||||
|
@ -15,7 +16,6 @@ use error::Error;
|
||||||
|
|
||||||
use ns;
|
use ns;
|
||||||
|
|
||||||
use body;
|
|
||||||
use stanza_error::StanzaError;
|
use stanza_error::StanzaError;
|
||||||
use chatstates::ChatState;
|
use chatstates::ChatState;
|
||||||
use receipts::Receipt;
|
use receipts::Receipt;
|
||||||
|
@ -27,7 +27,6 @@ use eme::ExplicitMessageEncryption;
|
||||||
/// Lists every known payload of a `<message/>`.
|
/// Lists every known payload of a `<message/>`.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum MessagePayload {
|
pub enum MessagePayload {
|
||||||
Body(body::Body),
|
|
||||||
StanzaError(StanzaError),
|
StanzaError(StanzaError),
|
||||||
ChatState(ChatState),
|
ChatState(ChatState),
|
||||||
Receipt(Receipt),
|
Receipt(Receipt),
|
||||||
|
@ -86,12 +85,16 @@ pub enum MessagePayloadType {
|
||||||
Parsed(MessagePayload),
|
Parsed(MessagePayload),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Lang = String;
|
||||||
|
type Body = String;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
pub from: Option<Jid>,
|
pub from: Option<Jid>,
|
||||||
pub to: Option<Jid>,
|
pub to: Option<Jid>,
|
||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
pub type_: MessageType,
|
pub type_: MessageType,
|
||||||
|
pub bodies: BTreeMap<Lang, Body>,
|
||||||
pub payloads: Vec<MessagePayloadType>,
|
pub payloads: Vec<MessagePayloadType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,11 +115,19 @@ impl<'a> TryFrom<&'a Element> for Message {
|
||||||
Some(type_) => type_.parse()?,
|
Some(type_) => type_.parse()?,
|
||||||
None => Default::default(),
|
None => Default::default(),
|
||||||
};
|
};
|
||||||
|
let mut bodies = BTreeMap::new();
|
||||||
let mut payloads = vec!();
|
let mut payloads = vec!();
|
||||||
for elem in root.children() {
|
for elem in root.children() {
|
||||||
let payload = if let Ok(body) = body::parse_body(elem) {
|
if elem.is("body", ns::JABBER_CLIENT) {
|
||||||
Some(MessagePayload::Body(body))
|
for _ in elem.children() {
|
||||||
} else if let Ok(stanza_error) = StanzaError::try_from(elem) {
|
return Err(Error::ParseError("Unknown child in body element."));
|
||||||
|
}
|
||||||
|
let lang = elem.attr("xml:lang").unwrap_or("").to_owned();
|
||||||
|
if let Some(_) = bodies.insert(lang, elem.text()) {
|
||||||
|
return Err(Error::ParseError("Body element present twice for the same xml:lang."));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let payload = if let Ok(stanza_error) = StanzaError::try_from(elem) {
|
||||||
Some(MessagePayload::StanzaError(stanza_error))
|
Some(MessagePayload::StanzaError(stanza_error))
|
||||||
} else if let Ok(chatstate) = ChatState::try_from(elem) {
|
} else if let Ok(chatstate) = ChatState::try_from(elem) {
|
||||||
Some(MessagePayload::ChatState(chatstate))
|
Some(MessagePayload::ChatState(chatstate))
|
||||||
|
@ -138,11 +149,13 @@ impl<'a> TryFrom<&'a Element> for Message {
|
||||||
None => MessagePayloadType::XML(elem.clone()),
|
None => MessagePayloadType::XML(elem.clone()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(Message {
|
Ok(Message {
|
||||||
from: from,
|
from: from,
|
||||||
to: to,
|
to: to,
|
||||||
id: id,
|
id: id,
|
||||||
type_: type_,
|
type_: type_,
|
||||||
|
bodies: BTreeMap::new(),
|
||||||
payloads: payloads,
|
payloads: payloads,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -151,7 +164,6 @@ impl<'a> TryFrom<&'a Element> for Message {
|
||||||
impl<'a> Into<Element> for &'a MessagePayload {
|
impl<'a> Into<Element> for &'a MessagePayload {
|
||||||
fn into(self) -> Element {
|
fn into(self) -> Element {
|
||||||
match *self {
|
match *self {
|
||||||
MessagePayload::Body(ref body) => body::serialise(body),
|
|
||||||
MessagePayload::StanzaError(ref stanza_error) => stanza_error.into(),
|
MessagePayload::StanzaError(ref stanza_error) => stanza_error.into(),
|
||||||
MessagePayload::Attention(ref attention) => attention.into(),
|
MessagePayload::Attention(ref attention) => attention.into(),
|
||||||
MessagePayload::ChatState(ref chatstate) => chatstate.into(),
|
MessagePayload::ChatState(ref chatstate) => chatstate.into(),
|
||||||
|
@ -171,6 +183,17 @@ impl<'a> Into<Element> for &'a Message {
|
||||||
.attr("to", self.to.clone().and_then(|value| Some(String::from(value))))
|
.attr("to", self.to.clone().and_then(|value| Some(String::from(value))))
|
||||||
.attr("id", self.id.clone())
|
.attr("id", self.id.clone())
|
||||||
.attr("type", self.type_.clone())
|
.attr("type", self.type_.clone())
|
||||||
|
.append(self.bodies.iter()
|
||||||
|
.map(|(lang, body)| {
|
||||||
|
Element::builder("body")
|
||||||
|
.ns(ns::JABBER_CLIENT)
|
||||||
|
.attr("xml:lang", match lang.as_ref() {
|
||||||
|
"" => None,
|
||||||
|
lang => Some(lang),
|
||||||
|
})
|
||||||
|
.append(body.clone())
|
||||||
|
.build() })
|
||||||
|
.collect::<Vec<_>>())
|
||||||
.build();
|
.build();
|
||||||
for child in self.payloads.clone() {
|
for child in self.payloads.clone() {
|
||||||
let elem = match child {
|
let elem = match child {
|
||||||
|
@ -206,6 +229,7 @@ mod tests {
|
||||||
to: None,
|
to: None,
|
||||||
id: None,
|
id: None,
|
||||||
type_: MessageType::Normal,
|
type_: MessageType::Normal,
|
||||||
|
bodies: BTreeMap::new(),
|
||||||
payloads: vec!(),
|
payloads: vec!(),
|
||||||
};
|
};
|
||||||
let elem2 = (&message).into();
|
let elem2 = (&message).into();
|
||||||
|
@ -221,14 +245,15 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialise_body() {
|
fn test_serialise_body() {
|
||||||
let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
|
let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
|
||||||
|
let mut bodies = BTreeMap::new();
|
||||||
|
bodies.insert(String::from(""), String::from("Hello world!"));
|
||||||
let message = Message {
|
let message = Message {
|
||||||
from: None,
|
from: None,
|
||||||
to: Some(Jid::from_str("coucou@example.org").unwrap()),
|
to: Some(Jid::from_str("coucou@example.org").unwrap()),
|
||||||
id: None,
|
id: None,
|
||||||
type_: MessageType::Chat,
|
type_: MessageType::Chat,
|
||||||
payloads: vec!(
|
bodies: bodies,
|
||||||
MessagePayloadType::Parsed(MessagePayload::Body("Hello world!".to_owned())),
|
payloads: vec!(),
|
||||||
),
|
|
||||||
};
|
};
|
||||||
let elem2 = (&message).into();
|
let elem2 = (&message).into();
|
||||||
assert_eq!(elem, elem2);
|
assert_eq!(elem, elem2);
|
||||||
|
|
Loading…
Reference in a new issue