diff options
Diffstat (limited to 'stanza/src/client/presence.rs')
-rw-r--r-- | stanza/src/client/presence.rs | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/stanza/src/client/presence.rs b/stanza/src/client/presence.rs new file mode 100644 index 0000000..dd14bff --- /dev/null +++ b/stanza/src/client/presence.rs @@ -0,0 +1,225 @@ +use std::str::FromStr; + +use jid::JID; +use peanuts::{ + element::{FromElement, IntoElement}, + DeserializeError, Element, XML_NS, +}; + +use super::{error::Error, XMLNS}; + +pub struct Presence { + from: Option<JID>, + id: Option<String>, + to: Option<JID>, + r#type: Option<PresenceType>, + lang: Option<String>, + // children + show: Option<Show>, + status: Option<Status>, + priority: Option<Priority>, + // TODO: ##other + // other: Vec<Other>, + errors: Vec<Error>, +} + +impl FromElement for Presence { + fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { + element.check_name("presence")?; + element.check_namespace(XMLNS)?; + + let from = element.attribute_opt("from")?; + let id = element.attribute_opt("id")?; + let to = element.attribute_opt("to")?; + let r#type = element.attribute_opt("type")?; + let lang = element.attribute_opt_namespaced("lang", XML_NS)?; + + let show = element.child_opt()?; + let status = element.child_opt()?; + let priority = element.child_opt()?; + let errors = element.children()?; + + Ok(Presence { + from, + id, + to, + r#type, + lang, + show, + status, + priority, + errors, + }) + } +} + +impl IntoElement for Presence { + fn builder(&self) -> peanuts::element::ElementBuilder { + Element::builder("presence", Some(XMLNS)) + .push_attribute_opt("from", self.from.clone()) + .push_attribute_opt("id", self.id.clone()) + .push_attribute_opt("to", self.to.clone()) + .push_attribute_opt("type", self.r#type) + .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone()) + .push_child_opt(self.show) + .push_child_opt(self.status.clone()) + .push_child_opt(self.priority) + .push_children(self.errors.clone()) + } +} + +pub enum Other {} + +#[derive(Copy, Clone)] +pub enum PresenceType { + Error, + Probe, + Subscribe, + Subscribed, + Unavailable, + Unsubscribe, + Unsubscribed, +} + +impl FromStr for PresenceType { + type Err = DeserializeError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "error" => Ok(PresenceType::Error), + "probe" => Ok(PresenceType::Probe), + "subscribe" => Ok(PresenceType::Subscribe), + "subscribed" => Ok(PresenceType::Subscribed), + "unavailable" => Ok(PresenceType::Unavailable), + "unsubscribe" => Ok(PresenceType::Unsubscribe), + "unsubscribed" => Ok(PresenceType::Unsubscribed), + s => Err(DeserializeError::FromStr(s.to_string())), + } + } +} + +impl ToString for PresenceType { + fn to_string(&self) -> String { + match self { + PresenceType::Error => "error".to_string(), + PresenceType::Probe => "probe".to_string(), + PresenceType::Subscribe => "subscribe".to_string(), + PresenceType::Subscribed => "subscribed".to_string(), + PresenceType::Unavailable => "unavailable".to_string(), + PresenceType::Unsubscribe => "unsubscribe".to_string(), + PresenceType::Unsubscribed => "unsubscribed".to_string(), + } + } +} + +#[derive(Copy, Clone)] +pub enum Show { + Away, + Chat, + Dnd, + Xa, +} + +impl FromElement for Show { + fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { + element.check_name("show")?; + element.check_namespace(XMLNS)?; + + Ok(element.pop_value()?) + } +} + +impl FromStr for Show { + type Err = DeserializeError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "away" => Ok(Show::Away), + "chat" => Ok(Show::Chat), + "dnd" => Ok(Show::Dnd), + "xa" => Ok(Show::Xa), + s => Err(DeserializeError::FromStr(s.to_string())), + } + } +} + +impl IntoElement for Show { + fn builder(&self) -> peanuts::element::ElementBuilder { + Element::builder("show", Some(XMLNS)).push_text(*self) + } +} + +impl ToString for Show { + fn to_string(&self) -> String { + match self { + Show::Away => "away".to_string(), + Show::Chat => "chat".to_string(), + Show::Dnd => "dnd".to_string(), + Show::Xa => "xa".to_string(), + } + } +} + +#[derive(Clone)] +pub struct Status { + lang: Option<String>, + status: String1024, +} + +impl FromElement for Status { + fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { + element.check_name("status")?; + element.check_namespace(XMLNS)?; + + let lang = element.attribute_opt_namespaced("lang", XML_NS)?; + let status = element.pop_value()?; + + Ok(Status { lang, status }) + } +} + +impl IntoElement for Status { + fn builder(&self) -> peanuts::element::ElementBuilder { + Element::builder("status", Some(XMLNS)) + .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone()) + .push_text(self.status.clone()) + } +} + +// TODO: enforce? +/// minLength 1 maxLength 1024 +#[derive(Clone)] +pub struct String1024(pub String); + +impl FromStr for String1024 { + type Err = DeserializeError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(String1024(s.to_string())) + } +} + +impl ToString for String1024 { + fn to_string(&self) -> String { + self.0.clone() + } +} + +// xs:byte +#[derive(Clone, Copy)] +pub struct Priority(pub i8); + +impl FromElement for Priority { + fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> { + element.check_name("priority")?; + element.check_namespace(XMLNS)?; + + Ok(Priority(element.pop_value()?)) + } +} + +impl IntoElement for Priority { + fn builder(&self) -> peanuts::element::ElementBuilder { + Element::builder("priority", Some(XMLNS)).push_text(self.0) + } +} |