From 69cc83c4562f92fe9e8e8637c374005e58a48380 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 29 Jul 2017 06:49:02 +0100 Subject: [PATCH] message, iq, presence, stanza_error, forwarded: Add support for components hidden behind the component feature flag. --- Cargo.toml | 4 +++ src/forwarding.rs | 4 +-- src/iq.rs | 48 +++++++++++++++++++++++++++++++---- src/mam.rs | 12 +++++++++ src/message.rs | 36 +++++++++++++++++++------- src/ns.rs | 8 ++++++ src/presence.rs | 61 +++++++++++++++++++++++++++++++++++++-------- src/stanza_error.rs | 16 ++++++++++-- 8 files changed, 161 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c1f48c00..a7011854 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,3 +26,7 @@ try_from = "0.2.2" [dependencies.jid] version = "0.2.3" features = ["minidom"] + +[features] +# Build xmpp-parsers to make components instead of clients. +component = [] diff --git a/src/forwarding.rs b/src/forwarding.rs index 86474dd1..2348068b 100644 --- a/src/forwarding.rs +++ b/src/forwarding.rs @@ -34,9 +34,9 @@ impl TryFrom for Forwarded { for child in elem.children() { if child.is("delay", ns::DELAY) { delay = Some(Delay::try_from(child.clone())?); - } else if child.is("message", ns::JABBER_CLIENT) { + } else if child.is("message", ns::DEFAULT_NS) { stanza = Some(Message::try_from(child.clone())?); - // TODO: also handle the five other possibilities. + // TODO: also handle the two other possibilities. } else { return Err(Error::ParseError("Unknown child in forwarded element.")); } diff --git a/src/iq.rs b/src/iq.rs index 1fd308c0..7e919985 100644 --- a/src/iq.rs +++ b/src/iq.rs @@ -207,7 +207,7 @@ impl TryFrom for Iq { type Err = Error; fn try_from(root: Element) -> Result { - if !root.is("iq", ns::JABBER_CLIENT) { + if !root.is("iq", ns::DEFAULT_NS) { return Err(Error::ParseError("This is not an iq element.")); } let from = get_attr!(root, "from", optional); @@ -222,7 +222,7 @@ impl TryFrom for Iq { return Err(Error::ParseError("Wrong number of children in iq element.")); } if type_ == "error" { - if elem.is("error", ns::JABBER_CLIENT) { + if elem.is("error", ns::DEFAULT_NS) { if error_payload.is_some() { return Err(Error::ParseError("Wrong number of children in iq element.")); } @@ -275,7 +275,7 @@ impl TryFrom for Iq { impl From for Element { fn from(iq: Iq) -> Element { let mut stanza = Element::builder("iq") - .ns(ns::JABBER_CLIENT) + .ns(ns::DEFAULT_NS) .attr("from", iq.from) .attr("to", iq.to) .attr("id", iq.id) @@ -300,7 +300,10 @@ mod tests { #[test] fn test_require_type() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = Iq::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -311,11 +314,16 @@ mod tests { #[test] fn test_get() { + #[cfg(not(feature = "component"))] let elem: Element = " - + + ".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = " + ".parse().unwrap(); let iq = Iq::try_from(elem).unwrap(); - let query: Element = "".parse().unwrap(); + let query: Element = "".parse().unwrap(); assert_eq!(iq.from, None); assert_eq!(iq.to, None); assert_eq!(iq.id, None); @@ -327,9 +335,14 @@ mod tests { #[test] fn test_set() { + #[cfg(not(feature = "component"))] let elem: Element = " ".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = " + + ".parse().unwrap(); let iq = Iq::try_from(elem).unwrap(); let vcard: Element = "".parse().unwrap(); assert_eq!(iq.from, None); @@ -343,7 +356,10 @@ mod tests { #[test] fn test_result_empty() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let iq = Iq::try_from(elem).unwrap(); assert_eq!(iq.from, None); assert_eq!(iq.to, None); @@ -356,9 +372,14 @@ mod tests { #[test] fn test_result() { + #[cfg(not(feature = "component"))] let elem: Element = " ".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = " + + ".parse().unwrap(); let iq = Iq::try_from(elem).unwrap(); let query: Element = "".parse().unwrap(); assert_eq!(iq.from, None); @@ -372,12 +393,20 @@ mod tests { #[test] fn test_error() { + #[cfg(not(feature = "component"))] let elem: Element = " ".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = " + + + + + ".parse().unwrap(); let iq = Iq::try_from(elem).unwrap(); assert_eq!(iq.from, None); assert_eq!(iq.to, None); @@ -396,7 +425,10 @@ mod tests { #[test] fn test_children_invalid() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = Iq::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -407,7 +439,10 @@ mod tests { #[test] fn test_serialise() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let iq2 = Iq { from: None, to: None, @@ -420,7 +455,10 @@ mod tests { #[test] fn test_disco() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let iq = Iq::try_from(elem).unwrap(); let payload = match iq.payload { IqType::Get(payload) => IqGetPayload::try_from(payload).unwrap(), diff --git a/src/mam.rs b/src/mam.rs index b52e8041..65299b70 100644 --- a/src/mam.rs +++ b/src/mam.rs @@ -242,6 +242,7 @@ mod tests { #[test] fn test_result() { + #[cfg(not(feature = "component"))] let elem: Element = r#" @@ -251,6 +252,17 @@ mod tests { +"#.parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = r#" + + + + + Hail to thee + + + "#.parse().unwrap(); Result_::try_from(elem).unwrap(); } diff --git a/src/message.rs b/src/message.rs index 3bf73ae8..5dba839e 100644 --- a/src/message.rs +++ b/src/message.rs @@ -49,7 +49,7 @@ impl TryFrom for MessagePayload { fn try_from(elem: Element) -> Result { Ok(match (elem.name().as_ref(), elem.ns().unwrap().as_ref()) { - ("error", ns::JABBER_CLIENT) => MessagePayload::StanzaError(StanzaError::try_from(elem)?), + ("error", ns::DEFAULT_NS) => MessagePayload::StanzaError(StanzaError::try_from(elem)?), // XEP-0085 ("active", ns::CHATSTATES) @@ -116,9 +116,9 @@ generate_attribute!(MessageType, "type", { type Lang = String; -generate_elem_id!(Body, "body", ns::JABBER_CLIENT); -generate_elem_id!(Subject, "subject", ns::JABBER_CLIENT); -generate_elem_id!(Thread, "thread", ns::JABBER_CLIENT); +generate_elem_id!(Body, "body", ns::DEFAULT_NS); +generate_elem_id!(Subject, "subject", ns::DEFAULT_NS); +generate_elem_id!(Thread, "thread", ns::DEFAULT_NS); /// The main structure representing the `` stanza. #[derive(Debug, Clone)] @@ -152,7 +152,7 @@ impl TryFrom for Message { type Err = Error; fn try_from(root: Element) -> Result { - if !root.is("message", ns::JABBER_CLIENT) { + if !root.is("message", ns::DEFAULT_NS) { return Err(Error::ParseError("This is not a message element.")); } let from = get_attr!(root, "from", optional); @@ -164,7 +164,7 @@ impl TryFrom for Message { let mut thread = None; let mut payloads = vec!(); for elem in root.children() { - if elem.is("body", ns::JABBER_CLIENT) { + if elem.is("body", ns::DEFAULT_NS) { for _ in elem.children() { return Err(Error::ParseError("Unknown child in body element.")); } @@ -173,7 +173,7 @@ impl TryFrom for Message { if bodies.insert(lang, body).is_some() { return Err(Error::ParseError("Body element present twice for the same xml:lang.")); } - } else if elem.is("subject", ns::JABBER_CLIENT) { + } else if elem.is("subject", ns::DEFAULT_NS) { for _ in elem.children() { return Err(Error::ParseError("Unknown child in subject element.")); } @@ -182,7 +182,7 @@ impl TryFrom for Message { if subjects.insert(lang, subject).is_some() { return Err(Error::ParseError("Subject element present twice for the same xml:lang.")); } - } else if elem.is("thread", ns::JABBER_CLIENT) { + } else if elem.is("thread", ns::DEFAULT_NS) { if thread.is_some() { return Err(Error::ParseError("Thread element present twice.")); } @@ -210,7 +210,7 @@ impl TryFrom for Message { impl From for Element { fn from(message: Message) -> Element { Element::builder("message") - .ns(ns::JABBER_CLIENT) + .ns(ns::DEFAULT_NS) .attr("from", message.from) .attr("to", message.to) .attr("id", message.id) @@ -246,7 +246,10 @@ mod tests { #[test] fn test_simple() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let message = Message::try_from(elem).unwrap(); assert_eq!(message.from, None); assert_eq!(message.to, None); @@ -257,7 +260,10 @@ mod tests { #[test] fn test_serialise() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let mut message = Message::new(None); message.type_ = MessageType::Normal; let elem2 = message.into(); @@ -266,7 +272,10 @@ mod tests { #[test] fn test_body() { + #[cfg(not(feature = "component"))] let elem: Element = "Hello world!".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "Hello world!".parse().unwrap(); let elem1 = elem.clone(); let message = Message::try_from(elem).unwrap(); assert_eq!(message.bodies[""], Body::from_str("Hello world!").unwrap()); @@ -277,7 +286,10 @@ mod tests { #[test] fn test_serialise_body() { + #[cfg(not(feature = "component"))] let elem: Element = "Hello world!".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "Hello world!".parse().unwrap(); let mut message = Message::new(Some(Jid::from_str("coucou@example.org").unwrap())); message.bodies.insert(String::from(""), Body::from_str("Hello world!").unwrap()); let elem2 = message.into(); @@ -286,7 +298,10 @@ mod tests { #[test] fn test_subject() { + #[cfg(not(feature = "component"))] let elem: Element = "Hello world!".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "Hello world!".parse().unwrap(); let elem1 = elem.clone(); let message = Message::try_from(elem).unwrap(); assert_eq!(message.subjects[""], Subject::from_str("Hello world!").unwrap()); @@ -297,7 +312,10 @@ mod tests { #[test] fn test_attention() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let elem1 = elem.clone(); let message = Message::try_from(elem).unwrap(); let elem2 = message.into(); diff --git a/src/ns.rs b/src/ns.rs index 0d06a1d7..5df077e1 100644 --- a/src/ns.rs +++ b/src/ns.rs @@ -47,6 +47,9 @@ pub const REGISTER: &str = "jabber:iq:register"; /// XEP-0085: Chat State Notifications pub const CHATSTATES: &str = "http://jabber.org/protocol/chatstates"; +/// XEP-0114: Jabber Component Protocol +pub const COMPONENT_ACCEPT: &str = "jabber:component:accept"; + /// XEP-0115: Entity Capabilities pub const CAPS: &str = "http://jabber.org/protocol/caps"; @@ -119,3 +122,8 @@ pub const EME: &str = "urn:xmpp:eme:0"; pub const ECAPS2: &str = "urn:xmpp:caps"; /// XEP-0390: Entity Capabilities 2.0 pub const ECAPS2_OPTIMIZE: &str = "urn:xmpp:caps:optimize"; + +#[cfg(not(feature = "component"))] +pub const DEFAULT_NS: &str = JABBER_CLIENT; +#[cfg(feature = "component")] +pub const DEFAULT_NS: &str = COMPONENT_ACCEPT; diff --git a/src/presence.rs b/src/presence.rs index 958a82b3..a1f11fa6 100644 --- a/src/presence.rs +++ b/src/presence.rs @@ -95,7 +95,7 @@ impl TryFrom for PresencePayload { fn try_from(elem: Element) -> Result { Ok(match (elem.name().as_ref(), elem.ns().unwrap().as_ref()) { - ("error", ns::JABBER_CLIENT) => PresencePayload::StanzaError(StanzaError::try_from(elem)?), + ("error", ns::DEFAULT_NS) => PresencePayload::StanzaError(StanzaError::try_from(elem)?), // XEP-0045 ("x", ns::MUC) => PresencePayload::Muc(Muc::try_from(elem)?), @@ -248,7 +248,7 @@ impl TryFrom for Presence { type Err = Error; fn try_from(root: Element) -> Result { - if !root.is("presence", ns::JABBER_CLIENT) { + if !root.is("presence", ns::DEFAULT_NS) { return Err(Error::ParseError("This is not a presence element.")); } let mut show = None; @@ -264,7 +264,7 @@ impl TryFrom for Presence { payloads: vec!(), }; for elem in root.children() { - if elem.is("show", ns::JABBER_CLIENT) { + if elem.is("show", ns::DEFAULT_NS) { if show.is_some() { return Err(Error::ParseError("More than one show element in a presence.")); } @@ -275,7 +275,7 @@ impl TryFrom for Presence { return Err(Error::ParseError("Unknown attribute in show element.")); } show = Some(Show::from_str(elem.text().as_ref())?); - } else if elem.is("status", ns::JABBER_CLIENT) { + } else if elem.is("status", ns::DEFAULT_NS) { for _ in elem.children() { return Err(Error::ParseError("Unknown child in status element.")); } @@ -288,7 +288,7 @@ impl TryFrom for Presence { if presence.statuses.insert(lang, elem.text()).is_some() { return Err(Error::ParseError("Status element present twice for the same xml:lang.")); } - } else if elem.is("priority", ns::JABBER_CLIENT) { + } else if elem.is("priority", ns::DEFAULT_NS) { if priority.is_some() { return Err(Error::ParseError("More than one priority element in a presence.")); } @@ -316,7 +316,7 @@ impl TryFrom for Presence { impl From for Element { fn from(presence: Presence) -> Element { Element::builder("presence") - .ns(ns::JABBER_CLIENT) + .ns(ns::DEFAULT_NS) .attr("from", presence.from) .attr("to", presence.to) .attr("id", presence.id) @@ -343,7 +343,10 @@ mod tests { #[test] fn test_simple() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let presence = Presence::try_from(elem).unwrap(); assert_eq!(presence.from, None); assert_eq!(presence.to, None); @@ -354,7 +357,10 @@ mod tests { #[test] fn test_serialise() { - let elem: Element = "".parse().unwrap(); + #[cfg(not(feature = "component"))] + let elem: Element = "/>".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "/>".parse().unwrap(); let presence = Presence::new(Type::Unavailable); let elem2 = presence.into(); assert_eq!(elem, elem2); @@ -362,7 +368,10 @@ mod tests { #[test] fn test_show() { + #[cfg(not(feature = "component"))] let elem: Element = "chat".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "chat".parse().unwrap(); let presence = Presence::try_from(elem).unwrap(); assert_eq!(presence.payloads.len(), 0); assert_eq!(presence.show, Show::Chat); @@ -370,8 +379,10 @@ mod tests { #[test] fn test_missing_show_value() { - // "online" used to be a pretty common mistake. + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = Presence::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -383,7 +394,10 @@ mod tests { #[test] fn test_invalid_show() { // "online" used to be a pretty common mistake. + #[cfg(not(feature = "component"))] let elem: Element = "online".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "online".parse().unwrap(); let error = Presence::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -394,7 +408,10 @@ mod tests { #[test] fn test_empty_status() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let presence = Presence::try_from(elem).unwrap(); assert_eq!(presence.payloads.len(), 0); assert_eq!(presence.statuses.len(), 1); @@ -403,7 +420,10 @@ mod tests { #[test] fn test_status() { + #[cfg(not(feature = "component"))] let elem: Element = "Here!".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "Here!".parse().unwrap(); let presence = Presence::try_from(elem).unwrap(); assert_eq!(presence.payloads.len(), 0); assert_eq!(presence.statuses.len(), 1); @@ -412,7 +432,10 @@ mod tests { #[test] fn test_multiple_statuses() { + #[cfg(not(feature = "component"))] let elem: Element = "Here!Là!".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "Here!Là!".parse().unwrap(); let presence = Presence::try_from(elem).unwrap(); assert_eq!(presence.payloads.len(), 0); assert_eq!(presence.statuses.len(), 2); @@ -422,7 +445,10 @@ mod tests { #[test] fn test_invalid_multiple_statuses() { + #[cfg(not(feature = "component"))] let elem: Element = "Here!Là!".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "Here!Là!".parse().unwrap(); let error = Presence::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -433,7 +459,10 @@ mod tests { #[test] fn test_priority() { + #[cfg(not(feature = "component"))] let elem: Element = "-1".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "-1".parse().unwrap(); let presence = Presence::try_from(elem).unwrap(); assert_eq!(presence.payloads.len(), 0); assert_eq!(presence.priority, -1i8); @@ -441,7 +470,10 @@ mod tests { #[test] fn test_invalid_priority() { + #[cfg(not(feature = "component"))] let elem: Element = "128".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "128".parse().unwrap(); let error = Presence::try_from(elem).unwrap_err(); match error { Error::ParseIntError(_) => (), @@ -451,7 +483,10 @@ mod tests { #[test] fn test_unknown_child() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let presence = Presence::try_from(elem).unwrap(); let payload = &presence.payloads[0]; assert!(payload.is("test", "invalid")); @@ -459,7 +494,10 @@ mod tests { #[test] fn test_invalid_status_child() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = Presence::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -470,7 +508,10 @@ mod tests { #[test] fn test_invalid_attribute() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = Presence::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -485,7 +526,7 @@ mod tests { let mut presence = Presence::new(Type::Unavailable); presence.statuses.insert(String::from(""), status); let elem: Element = presence.into(); - assert!(elem.is("presence", ns::JABBER_CLIENT)); - assert!(elem.children().next().unwrap().is("status", ns::JABBER_CLIENT)); + assert!(elem.is("presence", ns::DEFAULT_NS)); + assert!(elem.children().next().unwrap().is("status", ns::DEFAULT_NS)); } } diff --git a/src/stanza_error.rs b/src/stanza_error.rs index 0c7ca7e8..8ca9c862 100644 --- a/src/stanza_error.rs +++ b/src/stanza_error.rs @@ -125,7 +125,7 @@ impl TryFrom for StanzaError { type Err = Error; fn try_from(elem: Element) -> Result { - if !elem.is("error", ns::JABBER_CLIENT) { + if !elem.is("error", ns::DEFAULT_NS) { return Err(Error::ParseError("This is not an error element.")); } @@ -175,7 +175,7 @@ impl TryFrom for StanzaError { impl From for Element { fn from(err: StanzaError) -> Element { let mut root = Element::builder("error") - .ns(ns::JABBER_CLIENT) + .ns(ns::DEFAULT_NS) .attr("type", err.type_) .attr("by", err.by) .append(err.defined_condition) @@ -201,7 +201,10 @@ mod tests { #[test] fn test_simple() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = StanzaError::try_from(elem).unwrap(); assert_eq!(error.type_, ErrorType::Cancel); assert_eq!(error.defined_condition, DefinedCondition::UndefinedCondition); @@ -209,7 +212,10 @@ mod tests { #[test] fn test_invalid_type() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = StanzaError::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -217,7 +223,10 @@ mod tests { }; assert_eq!(message, "Required attribute 'type' missing."); + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = StanzaError::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, @@ -228,7 +237,10 @@ mod tests { #[test] fn test_invalid_condition() { + #[cfg(not(feature = "component"))] let elem: Element = "".parse().unwrap(); + #[cfg(feature = "component")] + let elem: Element = "".parse().unwrap(); let error = StanzaError::try_from(elem).unwrap_err(); let message = match error { Error::ParseError(string) => string,