aboutsummaryrefslogtreecommitdiffstats
path: root/stanza/src/client/presence.rs
diff options
context:
space:
mode:
Diffstat (limited to 'stanza/src/client/presence.rs')
-rw-r--r--stanza/src/client/presence.rs225
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)
+ }
+}