diff options
| author | 2024-12-22 20:40:59 +0000 | |
|---|---|---|
| committer | 2024-12-22 20:40:59 +0000 | |
| commit | 89351e956368ad3112127570ef03dd2547730ce5 (patch) | |
| tree | 457143801922e23c9e72a7d59e7ca8e6b24a1c9b | |
| parent | 27f90bd85f2abf2ecdac69880801d657f125b6ce (diff) | |
| download | luz-89351e956368ad3112127570ef03dd2547730ce5.tar.gz luz-89351e956368ad3112127570ef03dd2547730ce5.tar.bz2 luz-89351e956368ad3112127570ef03dd2547730ce5.zip  | |
add jabber:iq:stanza parsers
Diffstat (limited to '')
| -rw-r--r-- | stanza/src/lib.rs | 1 | ||||
| -rw-r--r-- | stanza/src/roster.rs | 153 | 
2 files changed, 154 insertions, 0 deletions
diff --git a/stanza/src/lib.rs b/stanza/src/lib.rs index f3b0dca..4120207 100644 --- a/stanza/src/lib.rs +++ b/stanza/src/lib.rs @@ -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; diff --git a/stanza/src/roster.rs b/stanza/src/roster.rs new file mode 100644 index 0000000..b49fcc3 --- /dev/null +++ b/stanza/src/roster.rs @@ -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()) +    } +}  | 
