diff options
Diffstat (limited to 'stanza')
39 files changed, 558 insertions, 17 deletions
diff --git a/stanza/Cargo.toml b/stanza/Cargo.toml index 884584a..9bbe3f3 100644 --- a/stanza/Cargo.toml +++ b/stanza/Cargo.toml @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +# +# SPDX-License-Identifier: AGPL-3.0-or-later + [package] name = "stanza" version = "0.1.0" @@ -24,5 +28,8 @@ xep_0156 = ["dep:chrono"] xep_0172 = [] xep_0199 = [] xep_0203 = ["dep:chrono"] +xep_0280 = ["xep_0297"] +xep_0297 = ["xep_0203"] xep_0300 = [] +xep_0334 = [] xep_0390 = ["xep_0300"] diff --git a/stanza/src/bind.rs b/stanza/src/bind.rs index 3ce2246..c04651c 100644 --- a/stanza/src/bind.rs +++ b/stanza/src/bind.rs @@ -1,4 +1,8 @@ -use jid::JID; +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use jid::FullJID; use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-bind"; @@ -54,7 +58,7 @@ impl IntoElement for BindType { // minLength 8 maxLength 3071 #[derive(Clone, Debug)] -pub struct FullJidType(pub JID); +pub struct FullJidType(pub FullJID); impl FromElement for FullJidType { fn from_element(mut element: peanuts::Element) -> peanuts::DeserializeResult<Self> { diff --git a/stanza/src/client/error.rs b/stanza/src/client/error.rs index 9cc85a9..7dac178 100644 --- a/stanza/src/client/error.rs +++ b/stanza/src/client/error.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::fmt::Display; use std::str::FromStr; diff --git a/stanza/src/client/iq.rs b/stanza/src/client/iq.rs index 478530a..be2a3f1 100644 --- a/stanza/src/client/iq.rs +++ b/stanza/src/client/iq.rs @@ -1,8 +1,14 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::str::FromStr; use jid::JID; use peanuts::{DeserializeError, Element, FromElement, IntoElement, XML_NS}; +#[cfg(feature = "xep_0280")] +use crate::xep_0280::{self, Disable, Enable}; use crate::{ bind::{self, Bind}, client::error::Error, @@ -53,6 +59,10 @@ pub enum Query { Ping(Ping), #[cfg(feature = "rfc_6121")] Roster(roster::Query), + #[cfg(feature = "xep_0280")] + CarbonsEnable(Enable), + #[cfg(feature = "xep_0280")] + CarbonsDisable(Disable), Unsupported, } @@ -80,6 +90,14 @@ impl FromElement for Query { (Some(xep_0060::owner::XMLNS), "pubsub") => Ok(Query::PubsubOwner( xep_0060::owner::Pubsub::from_element(element)?, )), + #[cfg(feature = "xep_0280")] + (Some(xep_0280::XMLNS), "enable") => { + Ok(Query::CarbonsEnable(Enable::from_element(element)?)) + } + #[cfg(feature = "xep_0280")] + (Some(xep_0280::XMLNS), "disable") => { + Ok(Query::CarbonsDisable(Disable::from_element(element)?)) + } _ => Ok(Query::Unsupported), } } @@ -103,6 +121,10 @@ impl IntoElement for Query { Query::Pubsub(pubsub) => pubsub.builder(), #[cfg(feature = "xep_0060")] Query::PubsubOwner(pubsub) => pubsub.builder(), + #[cfg(feature = "xep_0280")] + Query::CarbonsEnable(enable) => enable.builder(), + #[cfg(feature = "xep_0280")] + Query::CarbonsDisable(disable) => disable.builder(), } } } diff --git a/stanza/src/client/message.rs b/stanza/src/client/message.rs index 41761d2..a489201 100644 --- a/stanza/src/client/message.rs +++ b/stanza/src/client/message.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::str::FromStr; use jid::JID; @@ -11,6 +15,12 @@ use crate::xep_0131::Headers; use crate::xep_0172::Nick; #[cfg(feature = "xep_0203")] use crate::xep_0203::Delay; +#[cfg(feature = "xep_0280")] +use crate::xep_0280::{Private, Received, Sent}; +#[cfg(feature = "xep_0297")] +use crate::xep_0297::Forwarded; +#[cfg(feature = "xep_0334")] +use crate::xep_0334::{NoCopy, NoPermanentStore, NoStore, Store}; use super::XMLNS; @@ -34,6 +44,22 @@ pub struct Message { pub nick: Option<Nick>, #[cfg(feature = "xep_0060")] pub event: Option<Event>, + #[cfg(feature = "xep_0297")] + pub forwarded: Option<Forwarded>, + #[cfg(feature = "xep_0280")] + pub sent: Option<Sent>, + #[cfg(feature = "xep_0280")] + pub received: Option<Received>, + #[cfg(feature = "xep_0280")] + pub private: Option<Private>, + #[cfg(feature = "xep_0334")] + pub no_permanent_store: Option<NoPermanentStore>, + #[cfg(feature = "xep_0334")] + pub no_store: Option<NoStore>, + #[cfg(feature = "xep_0334")] + pub no_copy: Option<NoCopy>, + #[cfg(feature = "xep_0334")] + pub store: Option<Store>, } impl FromElement for Message { @@ -63,6 +89,30 @@ impl FromElement for Message { #[cfg(feature = "xep_0060")] let event = element.child_opt()?; + #[cfg(feature = "xep_0297")] + let forwarded = element.child_opt()?; + + #[cfg(feature = "xep_0280")] + let sent = element.child_opt()?; + + #[cfg(feature = "xep_0280")] + let received = element.child_opt()?; + + #[cfg(feature = "xep_0280")] + let private = element.child_opt()?; + + #[cfg(feature = "xep_0334")] + let no_permanent_store = element.child_opt()?; + + #[cfg(feature = "xep_0334")] + let no_store = element.child_opt()?; + + #[cfg(feature = "xep_0334")] + let no_copy = element.child_opt()?; + + #[cfg(feature = "xep_0334")] + let store = element.child_opt()?; + Ok(Message { from, id, @@ -80,6 +130,22 @@ impl FromElement for Message { nick, #[cfg(feature = "xep_0060")] event, + #[cfg(feature = "xep_0297")] + forwarded, + #[cfg(feature = "xep_0280")] + sent, + #[cfg(feature = "xep_0280")] + received, + #[cfg(feature = "xep_0280")] + private, + #[cfg(feature = "xep_0334")] + no_permanent_store, + #[cfg(feature = "xep_0334")] + no_store, + #[cfg(feature = "xep_0334")] + no_copy, + #[cfg(feature = "xep_0334")] + store, }) } } @@ -114,6 +180,30 @@ impl IntoElement for Message { #[cfg(feature = "xep_0060")] let builder = builder.push_child_opt(self.event.clone()); + #[cfg(feature = "xep_0297")] + let builder = builder.push_child_opt(self.forwarded.clone()); + + #[cfg(feature = "xep_0280")] + let builder = builder.push_child_opt(self.sent.clone()); + + #[cfg(feature = "xep_0280")] + let builder = builder.push_child_opt(self.received.clone()); + + #[cfg(feature = "xep_0280")] + let builder = builder.push_child_opt(self.private.clone()); + + #[cfg(feature = "xep_0334")] + let builder = builder.push_child_opt(self.no_permanent_store); + + #[cfg(feature = "xep_0334")] + let builder = builder.push_child_opt(self.no_store); + + #[cfg(feature = "xep_0334")] + let builder = builder.push_child_opt(self.no_copy); + + #[cfg(feature = "xep_0334")] + let builder = builder.push_child_opt(self.store); + builder } } diff --git a/stanza/src/client/mod.rs b/stanza/src/client/mod.rs index aca4fad..00ad3ed 100644 --- a/stanza/src/client/mod.rs +++ b/stanza/src/client/mod.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Content, ContentBuilder, DeserializeError, FromContent, FromElement, IntoContent}; use iq::Iq; diff --git a/stanza/src/client/presence.rs b/stanza/src/client/presence.rs index b0a0bc0..02de229 100644 --- a/stanza/src/client/presence.rs +++ b/stanza/src/client/presence.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::str::FromStr; use jid::JID; diff --git a/stanza/src/lib.rs b/stanza/src/lib.rs index 8f8d430..8cc3755 100644 --- a/stanza/src/lib.rs +++ b/stanza/src/lib.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::declaration::VersionInfo; pub mod bind; @@ -33,8 +37,14 @@ pub mod xep_0172; pub mod xep_0199; #[cfg(feature = "xep_0203")] pub mod xep_0203; +#[cfg(feature = "xep_0280")] +pub mod xep_0280; +#[cfg(feature = "xep_0297")] +pub mod xep_0297; #[cfg(feature = "xep_0300")] pub mod xep_0300; +#[cfg(feature = "xep_0334")] +pub mod xep_0334; #[cfg(feature = "xep_0390")] pub mod xep_0390; diff --git a/stanza/src/rfc_7395.rs b/stanza/src/rfc_7395.rs index 64d9f70..c632116 100644 --- a/stanza/src/rfc_7395.rs +++ b/stanza/src/rfc_7395.rs @@ -1,12 +1,16 @@ -use jid::JID; +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use jid::BareJID; use peanuts::{Element, ElementBuilder, FromElement, IntoElement}; pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-framing"; #[derive(Debug)] pub struct Open { - pub from: Option<JID>, - pub to: Option<JID>, + pub from: Option<BareJID>, + pub to: Option<BareJID>, pub id: Option<String>, pub version: Option<String>, pub lang: Option<String>, @@ -46,8 +50,8 @@ impl IntoElement for Open { #[derive(Debug, Default)] pub struct Close { - pub from: Option<JID>, - pub to: Option<JID>, + pub from: Option<BareJID>, + pub to: Option<BareJID>, pub id: Option<String>, pub version: Option<String>, pub lang: Option<String>, diff --git a/stanza/src/roster.rs b/stanza/src/roster.rs index 14f65ef..fe67ad1 100644 --- a/stanza/src/roster.rs +++ b/stanza/src/roster.rs @@ -1,6 +1,10 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::str::FromStr; -use jid::JID; +use jid::BareJID; use peanuts::{DeserializeError, Element, FromElement, IntoElement}; pub const XMLNS: &str = "jabber:iq:roster"; @@ -38,7 +42,7 @@ pub struct Item { /// signals subscription sub-states (server only) pub ask: bool, /// uniquely identifies item - pub jid: JID, + pub jid: BareJID, /// handle that is determined by user, not contact pub name: Option<String>, /// state of the presence subscription diff --git a/stanza/src/sasl.rs b/stanza/src/sasl.rs index 58aab84..2935923 100644 --- a/stanza/src/sasl.rs +++ b/stanza/src/sasl.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::{fmt::Display, ops::Deref}; use peanuts::{DeserializeError, Element, FromElement, IntoElement}; diff --git a/stanza/src/stanza_error.rs b/stanza/src/stanza_error.rs index 8fb862f..bb0c24f 100644 --- a/stanza/src/stanza_error.rs +++ b/stanza/src/stanza_error.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + // https://datatracker.ietf.org/doc/html/rfc6120#appendix-A.8 use peanuts::{Element, FromElement, IntoElement, XML_NS}; diff --git a/stanza/src/starttls.rs b/stanza/src/starttls.rs index 730c044..92ae315 100644 --- a/stanza/src/starttls.rs +++ b/stanza/src/starttls.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-tls"; diff --git a/stanza/src/stream.rs b/stanza/src/stream.rs index 5be235a..f8aef33 100644 --- a/stanza/src/stream.rs +++ b/stanza/src/stream.rs @@ -1,6 +1,10 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::fmt::Display; -use jid::JID; +use jid::BareJID; use peanuts::{Element, ElementBuilder, FromElement, IntoElement}; use thiserror::Error; @@ -18,8 +22,8 @@ pub const XMLNS: &str = "http://etherx.jabber.org/streams"; // #[peanuts(xmlns = XMLNS)] #[derive(Debug)] pub struct Stream { - pub from: Option<JID>, - to: Option<JID>, + pub from: Option<BareJID>, + to: Option<BareJID>, id: Option<String>, version: Option<String>, // TODO: lang enum @@ -64,8 +68,8 @@ impl IntoElement for Stream { impl<'s> Stream { pub fn new( - from: Option<JID>, - to: Option<JID>, + from: Option<BareJID>, + to: Option<BareJID>, id: Option<String>, version: Option<String>, lang: Option<String>, @@ -81,7 +85,12 @@ impl<'s> Stream { /// For initial stream headers, the initiating entity SHOULD include the 'xml:lang' attribute. /// For privacy, it is better to not set `from` when sending a client stanza over an unencrypted connection. - pub fn new_client(from: Option<JID>, to: JID, id: Option<String>, lang: String) -> Self { + pub fn new_client( + from: Option<BareJID>, + to: BareJID, + id: Option<String>, + lang: String, + ) -> Self { Self { from, to: Some(to), diff --git a/stanza/src/stream_error.rs b/stanza/src/stream_error.rs index 19ad1ae..e068cbf 100644 --- a/stanza/src/stream_error.rs +++ b/stanza/src/stream_error.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{DeserializeError, Element, FromElement, IntoElement, XML_NS}; use thiserror::Error; diff --git a/stanza/src/xep_0004.rs b/stanza/src/xep_0004.rs index f6ff7a0..b7b4878 100644 --- a/stanza/src/xep_0004.rs +++ b/stanza/src/xep_0004.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::str::FromStr; use peanuts::{DeserializeError, Element, FromElement, IntoElement}; diff --git a/stanza/src/xep_0030/info.rs b/stanza/src/xep_0030/info.rs index 0344ccb..69c795d 100644 --- a/stanza/src/xep_0030/info.rs +++ b/stanza/src/xep_0030/info.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{DeserializeError, Element, FromElement, IntoElement, XML_NS}; #[cfg(feature = "xep_0128")] diff --git a/stanza/src/xep_0030/items.rs b/stanza/src/xep_0030/items.rs index 7707eac..4096707 100644 --- a/stanza/src/xep_0030/items.rs +++ b/stanza/src/xep_0030/items.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use jid::JID; use peanuts::{Element, FromElement, IntoElement}; diff --git a/stanza/src/xep_0030/mod.rs b/stanza/src/xep_0030/mod.rs index 914c17b..0faaf04 100644 --- a/stanza/src/xep_0030/mod.rs +++ b/stanza/src/xep_0030/mod.rs @@ -1,2 +1,6 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + pub mod info; pub mod items; diff --git a/stanza/src/xep_0059.rs b/stanza/src/xep_0059.rs index 6490ad1..84f84ff 100644 --- a/stanza/src/xep_0059.rs +++ b/stanza/src/xep_0059.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "http://jabber.org/protocol/rsm"; diff --git a/stanza/src/xep_0060/errors.rs b/stanza/src/xep_0060/errors.rs index 6c6c530..a52ea85 100644 --- a/stanza/src/xep_0060/errors.rs +++ b/stanza/src/xep_0060/errors.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::{fmt::Display, str::FromStr}; use peanuts::{DeserializeError, Element, FromElement, IntoElement}; diff --git a/stanza/src/xep_0060/event.rs b/stanza/src/xep_0060/event.rs index 3cb124b..f3cae8b 100644 --- a/stanza/src/xep_0060/event.rs +++ b/stanza/src/xep_0060/event.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::str::FromStr; use chrono::{DateTime, Utc}; diff --git a/stanza/src/xep_0060/mod.rs b/stanza/src/xep_0060/mod.rs index 566310f..ac8a849 100644 --- a/stanza/src/xep_0060/mod.rs +++ b/stanza/src/xep_0060/mod.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + pub mod errors; pub mod event; pub mod owner; diff --git a/stanza/src/xep_0060/owner.rs b/stanza/src/xep_0060/owner.rs index 0617712..3b6c6f6 100644 --- a/stanza/src/xep_0060/owner.rs +++ b/stanza/src/xep_0060/owner.rs @@ -1,6 +1,10 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::str::FromStr; -use jid::JID; +use jid::{BareJID, JID}; use peanuts::{DeserializeError, Element, FromElement, IntoElement}; use crate::xep_0004::X; @@ -85,7 +89,7 @@ impl IntoElement for Affiliations { #[derive(Clone, Debug)] pub struct Affiliation { affiliation: AffiliationType, - jid: JID, + jid: BareJID, } impl FromElement for Affiliation { diff --git a/stanza/src/xep_0060/pubsub.rs b/stanza/src/xep_0060/pubsub.rs index 0416b78..94277b9 100644 --- a/stanza/src/xep_0060/pubsub.rs +++ b/stanza/src/xep_0060/pubsub.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::str::FromStr; use jid::JID; diff --git a/stanza/src/xep_0084/data.rs b/stanza/src/xep_0084/data.rs index 4b3223f..d147550 100644 --- a/stanza/src/xep_0084/data.rs +++ b/stanza/src/xep_0084/data.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "urn:xmpp:avatar:data"; diff --git a/stanza/src/xep_0084/metadata.rs b/stanza/src/xep_0084/metadata.rs index e4edb2f..b9d3e60 100644 --- a/stanza/src/xep_0084/metadata.rs +++ b/stanza/src/xep_0084/metadata.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "urn:xmpp:avatar:metadata"; diff --git a/stanza/src/xep_0084/mod.rs b/stanza/src/xep_0084/mod.rs index be7d5d7..1e80c9a 100644 --- a/stanza/src/xep_0084/mod.rs +++ b/stanza/src/xep_0084/mod.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + pub use data::Data; pub use metadata::Info; pub use metadata::Metadata; diff --git a/stanza/src/xep_0115.rs b/stanza/src/xep_0115.rs index 1c9cd6f..c983f2b 100644 --- a/stanza/src/xep_0115.rs +++ b/stanza/src/xep_0115.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "http://jabber.org/protocol/caps"; diff --git a/stanza/src/xep_0131.rs b/stanza/src/xep_0131.rs index 68e6e96..8d296b3 100644 --- a/stanza/src/xep_0131.rs +++ b/stanza/src/xep_0131.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "http://jabber.org/protocol/disco#info"; diff --git a/stanza/src/xep_0156.rs b/stanza/src/xep_0156.rs index bf6eac5..8b3d07c 100644 --- a/stanza/src/xep_0156.rs +++ b/stanza/src/xep_0156.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use chrono::{DateTime, Utc}; use peanuts::{Element, FromElement, IntoElement, XML_NS}; diff --git a/stanza/src/xep_0172.rs b/stanza/src/xep_0172.rs index 54846b8..8374bab 100644 --- a/stanza/src/xep_0172.rs +++ b/stanza/src/xep_0172.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "http://jabber.org/protocol/nick"; diff --git a/stanza/src/xep_0199.rs b/stanza/src/xep_0199.rs index 2ab3a86..17e9fd4 100644 --- a/stanza/src/xep_0199.rs +++ b/stanza/src/xep_0199.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use peanuts::{Element, FromElement, IntoElement}; pub const XMLNS: &str = "urn:xmpp:ping"; diff --git a/stanza/src/xep_0203.rs b/stanza/src/xep_0203.rs index 41ff196..0f4b298 100644 --- a/stanza/src/xep_0203.rs +++ b/stanza/src/xep_0203.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use chrono::{DateTime, Utc}; use jid::JID; use peanuts::{Element, FromElement, IntoElement}; diff --git a/stanza/src/xep_0280.rs b/stanza/src/xep_0280.rs new file mode 100644 index 0000000..74d2897 --- /dev/null +++ b/stanza/src/xep_0280.rs @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use peanuts::{Element, FromElement, IntoElement}; + +use crate::xep_0297::Forwarded; + +pub const XMLNS: &str = "urn:xmpp:carbons:2"; + +#[derive(Clone, Debug)] +pub struct Disable; + +impl FromElement for Disable { + fn from_element(element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("disable")?; + element.check_namespace(XMLNS)?; + + element.no_more_content()?; + + Ok(Self) + } +} + +impl IntoElement for Disable { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("disable", Some(XMLNS)) + } +} + +#[derive(Clone, Debug)] +pub struct Enable; + +impl FromElement for Enable { + fn from_element(element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("enable")?; + element.check_namespace(XMLNS)?; + + element.no_more_content()?; + + Ok(Self) + } +} + +impl IntoElement for Enable { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("enable", Some(XMLNS)) + } +} + +#[derive(Clone, Debug)] +pub struct Private; + +impl FromElement for Private { + fn from_element(element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("private")?; + element.check_namespace(XMLNS)?; + + element.no_more_content()?; + + Ok(Self) + } +} + +impl IntoElement for Private { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("private", Some(XMLNS)) + } +} + +#[derive(Clone, Debug)] +pub struct Received { + forwarded: Forwarded, +} + +impl FromElement for Received { + fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("received")?; + element.check_namespace(XMLNS)?; + + let forwarded = element.pop_child_one()?; + + Ok(Self { forwarded }) + } +} + +impl IntoElement for Received { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("received", Some(XMLNS)).push_child(self.forwarded.clone()) + } +} + +#[derive(Clone, Debug)] +pub struct Sent { + forwarded: Forwarded, +} + +impl FromElement for Sent { + fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("sent")?; + element.check_namespace(XMLNS)?; + + let forwarded = element.pop_child_one()?; + + Ok(Self { forwarded }) + } +} + +impl IntoElement for Sent { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("sent", Some(XMLNS)).push_child(self.forwarded.clone()) + } +} diff --git a/stanza/src/xep_0297.rs b/stanza/src/xep_0297.rs new file mode 100644 index 0000000..d686e49 --- /dev/null +++ b/stanza/src/xep_0297.rs @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use peanuts::{Element, FromElement, IntoElement}; + +use crate::{ + client::{self, iq::Iq, message::Message, presence::Presence}, + xep_0203::Delay, +}; + +pub const XMLNS: &str = "urn:xmpp:forward:0"; + +#[derive(Clone, Debug)] +pub struct Forwarded { + delay: Option<Delay>, + stanza: Option<Box<Stanza>>, +} + +// TODO: raw stanza source option +pub enum ForwardedStanza { + Parsed(Box<Stanza>), + Raw(String), +} + +impl FromElement for Forwarded { + fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("forwarded")?; + element.check_namespace(XMLNS)?; + + let delay = element.pop_child_opt()?; + let stanza = element.pop_child_opt()?; + let stanza = stanza.map(|stanza| Box::new(stanza)); + + Ok(Self { delay, stanza }) + } +} + +impl IntoElement for Forwarded { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("forwarded", Some(XMLNS)) + .push_child_opt(self.delay.clone()) + .push_child_opt(self.stanza.clone().map(|stanza| *stanza)) + } +} + +#[derive(Clone, Debug)] +pub enum Stanza { + Message(Message), + Presence(Presence), + Iq(Iq), + // TODO: raw elements are received with reads. + // Raw(Element), +} + +impl FromElement for Stanza { + fn from_element(element: Element) -> peanuts::DeserializeResult<Self> { + match element.identify() { + (Some(client::XMLNS), "message") => { + Ok(Stanza::Message(Message::from_element(element)?)) + } + (Some(client::XMLNS), "presence") => { + Ok(Stanza::Presence(Presence::from_element(element)?)) + } + (Some(client::XMLNS), "iq") => Ok(Stanza::Iq(Iq::from_element(element)?)), + _ => Err(peanuts::DeserializeError::UnexpectedElement(element)), + } + } +} + +impl IntoElement for Stanza { + fn builder(&self) -> peanuts::ElementBuilder { + match self { + Stanza::Message(message) => message.builder(), + Stanza::Presence(presence) => presence.builder(), + Stanza::Iq(iq) => iq.builder(), + } + } +} diff --git a/stanza/src/xep_0300.rs b/stanza/src/xep_0300.rs index f522f1c..5a2a88b 100644 --- a/stanza/src/xep_0300.rs +++ b/stanza/src/xep_0300.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::{convert::Infallible, str::FromStr}; use peanuts::{Element, FromElement, IntoElement}; diff --git a/stanza/src/xep_0334.rs b/stanza/src/xep_0334.rs new file mode 100644 index 0000000..a13e125 --- /dev/null +++ b/stanza/src/xep_0334.rs @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use peanuts::{Element, FromElement, IntoElement}; + +pub const XMLNS: &str = "urn:xmpp:hints"; + +#[derive(Clone, Copy, Debug)] +pub struct NoPermanentStore; + +impl FromElement for NoPermanentStore { + fn from_element(element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("no-permanent-store")?; + element.check_namespace(XMLNS)?; + + element.no_more_content()?; + + Ok(Self) + } +} + +impl IntoElement for NoPermanentStore { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("no-permanent-store", Some(XMLNS)) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct NoStore; + +impl FromElement for NoStore { + fn from_element(element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("no-store")?; + element.check_namespace(XMLNS)?; + + element.no_more_content()?; + + Ok(Self) + } +} + +impl IntoElement for NoStore { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("no-store", Some(XMLNS)) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct NoCopy; + +impl FromElement for NoCopy { + fn from_element(element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("no-copy")?; + element.check_namespace(XMLNS)?; + + element.no_more_content()?; + + Ok(Self) + } +} + +impl IntoElement for NoCopy { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("no-copy", Some(XMLNS)) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Store; + +impl FromElement for Store { + fn from_element(element: Element) -> peanuts::DeserializeResult<Self> { + element.check_name("store")?; + element.check_namespace(XMLNS)?; + + element.no_more_content()?; + + Ok(Self) + } +} + +impl IntoElement for Store { + fn builder(&self) -> peanuts::ElementBuilder { + Element::builder("store", Some(XMLNS)) + } +} diff --git a/stanza/src/xep_0390.rs b/stanza/src/xep_0390.rs index 1a079c2..248ff9a 100644 --- a/stanza/src/xep_0390.rs +++ b/stanza/src/xep_0390.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use crate::xep_0300::Hash; use peanuts::{Element, FromElement, IntoElement}; |
