From 9ce3827a7d25714d17f266f0f50bb29f41090175 Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Tue, 1 Apr 2025 21:40:23 +0100 Subject: feat(stanza): xep-0131: stanza headers --- stanza/Cargo.toml | 1 + stanza/src/client/message.rs | 12 ++++++++++ stanza/src/client/presence.rs | 12 ++++++++++ stanza/src/lib.rs | 2 ++ stanza/src/xep_0131.rs | 56 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+) create mode 100644 stanza/src/xep_0131.rs diff --git a/stanza/Cargo.toml b/stanza/Cargo.toml index ad3bd0b..64962b6 100644 --- a/stanza/Cargo.toml +++ b/stanza/Cargo.toml @@ -15,5 +15,6 @@ xep_0004 = [] xep_0030 = [] xep_0059 = [] xep_0060 = ["xep_0004", "dep:chrono"] +xep_0131 = [] xep_0199 = [] xep_0203 = ["dep:chrono"] diff --git a/stanza/src/client/message.rs b/stanza/src/client/message.rs index 192390b..e521613 100644 --- a/stanza/src/client/message.rs +++ b/stanza/src/client/message.rs @@ -6,6 +6,8 @@ use peanuts::{ DeserializeError, Element, XML_NS, }; +#[cfg(feature = "xep_0131")] +use crate::xep_0131::Headers; #[cfg(feature = "xep_0203")] use crate::xep_0203::Delay; @@ -25,6 +27,8 @@ pub struct Message { pub thread: Option, #[cfg(feature = "xep_0203")] pub delay: Option, + #[cfg(feature = "xep_0131")] + pub headers: Option, } impl FromElement for Message { @@ -45,6 +49,9 @@ impl FromElement for Message { #[cfg(feature = "xep_0203")] let delay = element.child_opt()?; + #[cfg(feature = "xep_0131")] + let headers = element.child_opt()?; + Ok(Message { from, id, @@ -56,6 +63,8 @@ impl FromElement for Message { thread, #[cfg(feature = "xep_0203")] delay, + #[cfg(feature = "xep_0131")] + headers, }) } } @@ -81,6 +90,9 @@ impl IntoElement for Message { #[cfg(feature = "xep_0203")] let builder = builder.push_child_opt(self.delay.clone()); + #[cfg(feature = "xep_0131")] + let builder = builder.push_child_opt(self.headers.clone()); + builder } } diff --git a/stanza/src/client/presence.rs b/stanza/src/client/presence.rs index ae38756..8fb96be 100644 --- a/stanza/src/client/presence.rs +++ b/stanza/src/client/presence.rs @@ -6,6 +6,8 @@ use peanuts::{ DeserializeError, Element, XML_NS, }; +#[cfg(feature = "xep_0131")] +use crate::xep_0131::Headers; #[cfg(feature = "xep_0203")] use crate::xep_0203::Delay; @@ -24,6 +26,8 @@ pub struct Presence { pub priority: Option, #[cfg(feature = "xep_0203")] pub delay: Option, + #[cfg(feature = "xep_0131")] + pub headers: Option, // TODO: ##other // other: Vec, pub errors: Vec, @@ -48,6 +52,9 @@ impl FromElement for Presence { #[cfg(feature = "xep_0203")] let delay = element.child_opt()?; + #[cfg(feature = "xep_0131")] + let headers = element.child_opt()?; + Ok(Presence { from, id, @@ -60,6 +67,8 @@ impl FromElement for Presence { errors, #[cfg(feature = "xep_0203")] delay, + #[cfg(feature = "xep_0131")] + headers, }) } } @@ -80,6 +89,9 @@ impl IntoElement for Presence { #[cfg(feature = "xep_0203")] let builder = builder.push_child_opt(self.delay.clone()); + #[cfg(feature = "xep_0131")] + let builder = builder.push_child_opt(self.headers.clone()); + builder } } diff --git a/stanza/src/lib.rs b/stanza/src/lib.rs index 0bae7f7..0a71a26 100644 --- a/stanza/src/lib.rs +++ b/stanza/src/lib.rs @@ -17,6 +17,8 @@ pub mod xep_0030; pub mod xep_0059; #[cfg(feature = "xep_0060")] pub mod xep_0060; +#[cfg(feature = "xep_0131")] +pub mod xep_0131; #[cfg(feature = "xep_0199")] pub mod xep_0199; #[cfg(feature = "xep_0203")] diff --git a/stanza/src/xep_0131.rs b/stanza/src/xep_0131.rs new file mode 100644 index 0000000..27fc962 --- /dev/null +++ b/stanza/src/xep_0131.rs @@ -0,0 +1,56 @@ +use peanuts::{ + element::{FromElement, IntoElement}, + Element, +}; + +pub const XMLNS: &str = "http://jabber.org/protocol/disco#info"; + +#[derive(Clone, Debug)] +pub struct Headers(pub Vec
); + +impl FromElement for Headers { + fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { + element.check_name("headers")?; + element.check_namespace(XMLNS)?; + + Ok(Self(element.pop_children()?)) + } +} + +impl IntoElement for Headers { + fn builder(&self) -> peanuts::element::ElementBuilder { + Element::builder("headers", Some(XMLNS)).push_children(self.0.clone()) + } +} + +#[derive(Clone, Debug)] +pub struct Header { + name: String, + header: String, +} + +impl FromElement for Header { + fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { + element.check_name("header")?; + element.check_namespace(XMLNS)?; + + let name = element.attribute("name")?; + + let header = element.pop_value_opt()?.unwrap_or_default(); + + Ok(Self { name, header }) + } +} + +impl IntoElement for Header { + fn builder(&self) -> peanuts::element::ElementBuilder { + let builder = + Element::builder("header", Some(XMLNS)).push_attribute("name", self.name.clone()); + + if self.header.is_empty() { + builder + } else { + builder.push_text(self.header.clone()) + } + } +} -- cgit