2024-12-22 20:40:59 +00:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
use jid::JID;
|
|
|
|
use peanuts::{
|
|
|
|
element::{FromElement, IntoElement},
|
|
|
|
DeserializeError, Element,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const XMLNS: &str = "jabber:iq:roster";
|
|
|
|
|
2025-01-02 17:48:12 +00:00
|
|
|
#[derive(Debug, Clone)]
|
2024-12-22 20:40:59 +00:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-02 17:48:12 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2024-12-22 20:40:59 +00:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-02 17:48:12 +00:00
|
|
|
#[derive(Default, Clone, Copy, Debug)]
|
2024-12-22 20:40:59 +00:00
|
|
|
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(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-02 17:48:12 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2024-12-22 20:40:59 +00:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|