add jabber:iq:stanza parsers

This commit is contained in:
cel 🌸 2024-12-22 20:40:59 +00:00
parent 27f90bd85f
commit 89351e9563
2 changed files with 154 additions and 0 deletions

View File

@ -2,6 +2,7 @@ use peanuts::declaration::VersionInfo;
pub mod bind;
pub mod client;
pub mod roster;
pub mod sasl;
pub mod stanza_error;
pub mod starttls;

153
stanza/src/roster.rs Normal file
View File

@ -0,0 +1,153 @@
use std::str::FromStr;
use jid::JID;
use peanuts::{
element::{FromElement, IntoElement},
DeserializeError, Element,
};
pub const XMLNS: &str = "jabber:iq:roster";
pub struct Query {
ver: Option<String>,
items: Vec<Item>,
}
impl FromElement for Query {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("query")?;
element.check_namespace(XMLNS)?;
let ver = element.attribute_opt("ver")?;
let items = element.pop_children()?;
Ok(Self { ver, items })
}
}
impl IntoElement for Query {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("query", Some(XMLNS))
.push_attribute_opt("ver", self.ver.clone())
.push_children(self.items.clone())
}
}
#[derive(Clone)]
pub struct Item {
approved: Option<bool>,
ask: bool,
jid: JID,
name: Option<String>,
subscription: Subscription,
groups: Vec<Group>,
}
impl FromElement for Item {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("item")?;
element.check_namespace(XMLNS)?;
let approved = element.attribute_opt("approved")?;
let ask = if let Some(result) = element.attribute_opt("ask")?.map(|v| {
if v == "subscribe" {
Ok(true)
} else {
Err(DeserializeError::FromStr(v))
}
}) {
result?
} else {
false
};
let jid = element.attribute("jid")?;
let name = element.attribute_opt("name")?;
let subscription = element.attribute_opt("subscription")?.unwrap_or_default();
let groups = element.pop_children()?;
Ok(Self {
approved,
ask,
jid,
name,
subscription,
groups,
})
}
}
impl IntoElement for Item {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("item", Some(XMLNS))
.push_attribute_opt("approved", self.approved)
.push_attribute_opt(
"ask",
if self.ask {
Some("subscribe".to_string())
} else {
None
},
)
.push_attribute("jid", self.jid.clone())
.push_attribute_opt("name", self.name.clone())
.push_attribute("subscription", self.subscription)
.push_children(self.groups.clone())
}
}
#[derive(Default, Clone, Copy)]
pub enum Subscription {
Both,
From,
#[default]
None,
Remove,
To,
}
impl FromStr for Subscription {
type Err = DeserializeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"both" => Ok(Self::Both),
"from" => Ok(Self::From),
"none" => Ok(Self::None),
"remove" => Ok(Self::Remove),
"to" => Ok(Self::To),
s => Err(DeserializeError::FromStr(s.to_string())),
}
}
}
impl ToString for Subscription {
fn to_string(&self) -> String {
match self {
Subscription::Both => "both".to_string(),
Subscription::From => "from".to_string(),
Subscription::None => "none".to_string(),
Subscription::Remove => "remove".to_string(),
Subscription::To => "to".to_string(),
}
}
}
#[derive(Clone)]
pub struct Group(Option<String>);
impl FromElement for Group {
fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("group")?;
element.check_namespace(XMLNS)?;
let group = element.pop_value_opt()?;
Ok(Self(group))
}
}
impl IntoElement for Group {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("group", Some(XMLNS)).push_text_opt(self.0.clone())
}
}