use std::str::FromStr; use jid::JID; use peanuts::{ element::{FromElement, IntoElement}, DeserializeError, Element, }; use crate::xep_0004::X; pub const XMLNS: &str = "http://jabber.org/protocol/pubsub#owner"; #[derive(Clone, Debug)] pub enum Pubsub { Affiliations(Affiliations), Configure(Configure), Default(Default), Delete(Delete), Purge(Purge), Subscriptions(Subscriptions), } impl FromElement for Pubsub { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { element.check_name("pubsub")?; element.check_namespace(XMLNS)?; let child = element.pop_child_one::()?; match child.identify() { (Some(XMLNS), "affiliations") => { Ok(Self::Affiliations(Affiliations::from_element(child)?)) } (Some(XMLNS), "configure") => Ok(Self::Configure(Configure::from_element(child)?)), (Some(XMLNS), "default") => Ok(Self::Default(Default::from_element(child)?)), (Some(XMLNS), "delete") => Ok(Self::Delete(Delete::from_element(child)?)), (Some(XMLNS), "purge") => Ok(Self::Purge(Purge::from_element(child)?)), (Some(XMLNS), "subscriptions") => { Ok(Self::Subscriptions(Subscriptions::from_element(child)?)) } _ => Err(DeserializeError::UnexpectedElement(child)), } } } impl IntoElement for Pubsub { fn builder(&self) -> peanuts::element::ElementBuilder { let builder = Element::builder("pubsub", Some(XMLNS)); match self { Pubsub::Affiliations(affiliations) => builder.push_child(affiliations.clone()), Pubsub::Configure(configure) => builder.push_child(configure.clone()), Pubsub::Default(default) => builder.push_child(default.clone()), Pubsub::Delete(delete) => builder.push_child(delete.clone()), Pubsub::Purge(purge) => builder.push_child(purge.clone()), Pubsub::Subscriptions(subscriptions) => builder.push_child(subscriptions.clone()), } } } #[derive(Clone, Debug)] pub struct Affiliations { node: String, affiliations: Vec, } impl FromElement for Affiliations { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("affiliations")?; element.check_namespace(XMLNS)?; let node = element.attribute("node")?; let affiliations = element.pop_children()?; Ok(Self { node, affiliations }) } } impl IntoElement for Affiliations { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("affiliations", Some(XMLNS)) .push_attribute("node", self.node.clone()) .push_children(self.affiliations.clone()) } } #[derive(Clone, Debug)] pub struct Affiliation { affiliation: AffiliationType, jid: JID, } impl FromElement for Affiliation { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("affiliation")?; element.check_namespace(XMLNS)?; let affiliation = element.attribute("affiliation")?; let jid = element.attribute("jid")?; Ok(Self { affiliation, jid }) } } impl IntoElement for Affiliation { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("affiliation", Some(XMLNS)) .push_attribute("affiliation", self.affiliation.clone()) .push_attribute("jid", self.jid.clone()) } } #[derive(Clone, Debug)] pub enum AffiliationType { Member, None, Outcast, Owner, Publisher, PublishOnly, } impl FromStr for AffiliationType { type Err = DeserializeError; fn from_str(s: &str) -> Result { match s { "member" => Ok(Self::Member), "none" => Ok(Self::None), "outcast" => Ok(Self::Outcast), "owner" => Ok(Self::Owner), "publisher" => Ok(Self::Publisher), "publish-only" => Ok(Self::PublishOnly), s => Err(DeserializeError::FromStr(s.to_owned())), } } } impl ToString for AffiliationType { fn to_string(&self) -> String { match self { AffiliationType::Member => "member", AffiliationType::None => "none", AffiliationType::Outcast => "outcast", AffiliationType::Owner => "owner", AffiliationType::Publisher => "publisher", AffiliationType::PublishOnly => "publish-only", } .to_owned() } } #[derive(Clone, Debug)] pub struct Configure { node: Option, configure: Option, } impl FromElement for Configure { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("configure")?; element.check_namespace(XMLNS)?; let node = element.attribute_opt("node")?; let configure = element.pop_child_opt()?; Ok(Self { node, configure }) } } impl IntoElement for Configure { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("configure", Some(XMLNS)) .push_attribute_opt("node", self.node.clone()) .push_child_opt(self.configure.clone()) } } #[derive(Clone, Debug)] pub struct Default(Option); impl FromElement for Default { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("default")?; element.check_namespace(XMLNS)?; Ok(Self(element.pop_child_opt()?)) } } impl IntoElement for Default { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("default", Some(XMLNS)).push_child_opt(self.0.clone()) } } #[derive(Clone, Debug)] pub struct Delete { node: String, redirect: Option, } impl FromElement for Delete { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("delete")?; element.check_namespace(XMLNS)?; let node = element.attribute("node")?; let redirect = element.pop_child_opt()?; Ok(Self { node, redirect }) } } impl IntoElement for Delete { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("delete", Some(XMLNS)) .push_attribute("node", self.node.clone()) .push_child_opt(self.redirect.clone()) } } #[derive(Clone, Debug)] pub struct Purge { node: String, } impl FromElement for Purge { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("purge")?; element.check_namespace(XMLNS)?; let node = element.attribute("node")?; Ok(Self { node }) } } impl IntoElement for Purge { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("purge", Some(XMLNS)).push_attribute("node", self.node.clone()) } } #[derive(Clone, Debug)] pub struct Redirect { uri: String, } impl FromElement for Redirect { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("redirect")?; element.check_namespace(XMLNS)?; let uri = element.attribute("uri")?; Ok(Self { uri }) } } impl IntoElement for Redirect { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("redirect", Some(XMLNS)).push_attribute("uri", self.uri.clone()) } } #[derive(Clone, Debug)] pub struct Subscriptions { node: String, subscriptions: Vec, } impl FromElement for Subscriptions { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("subscriptions")?; element.check_namespace(XMLNS)?; let node = element.attribute("node")?; let subscriptions = element.pop_children()?; Ok(Self { node, subscriptions, }) } } impl IntoElement for Subscriptions { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("subscriptions", Some(XMLNS)) .push_attribute("node", self.node.clone()) .push_children(self.subscriptions.clone()) } } #[derive(Clone, Debug)] pub struct Subscription { subscription: SubscriptionState, jid: JID, } impl FromElement for Subscription { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("subscription")?; element.check_namespace(XMLNS)?; let subscription = element.attribute("subscription")?; let jid = element.attribute("jid")?; Ok(Self { subscription, jid }) } } impl IntoElement for Subscription { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("subscription", Some(XMLNS)) .push_attribute("subscription", self.subscription.clone()) .push_attribute("jid", self.jid.clone()) } } #[derive(Clone, Debug)] pub enum SubscriptionState { None, Pending, Subscribed, Unconfigured, } impl FromStr for SubscriptionState { type Err = DeserializeError; fn from_str(s: &str) -> Result { match s { "none" => Ok(Self::None), "pending" => Ok(Self::Pending), "subscribed" => Ok(Self::Subscribed), "unconfigured" => Ok(Self::Unconfigured), s => Err(DeserializeError::FromStr(s.to_owned())), } } } impl ToString for SubscriptionState { fn to_string(&self) -> String { match self { SubscriptionState::None => "none", SubscriptionState::Pending => "pending", SubscriptionState::Subscribed => "subscribed", SubscriptionState::Unconfigured => "unconfigured", } .to_owned() } }