aboutsummaryrefslogtreecommitdiffstats
path: root/src/stanza/client/presence.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/stanza/client/presence.rs')
-rw-r--r--src/stanza/client/presence.rs194
1 files changed, 186 insertions, 8 deletions
diff --git a/src/stanza/client/presence.rs b/src/stanza/client/presence.rs
index 46194f3..bcb04d4 100644
--- a/src/stanza/client/presence.rs
+++ b/src/stanza/client/presence.rs
@@ -1,24 +1,77 @@
-use peanuts::element::{FromElement, IntoElement};
+use std::str::FromStr;
+
+use peanuts::{
+ element::{FromElement, IntoElement},
+ DeserializeError, Element, XML_NS,
+};
use crate::JID;
-use super::error::Error;
+use super::{error::Error, XMLNS};
pub struct Presence {
from: Option<JID>,
id: Option<String>,
to: Option<JID>,
- r#type: PresenceType,
+ 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>,
- // ##other
- // content: Vec<Box<dyn AsElement>>,
}
+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,
@@ -29,6 +82,38 @@ pub enum PresenceType {
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,
@@ -36,13 +121,106 @@ pub enum Show {
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,
}
-// minLength 1 maxLength 1024
-pub struct String1024(String);
+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
-pub struct Priority(u8);
+#[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)
+ }
+}