diff options
author | 2024-12-02 21:50:15 +0000 | |
---|---|---|
committer | 2024-12-02 21:50:15 +0000 | |
commit | be198ca15bbaf633c1535db5bae7091520546aed (patch) | |
tree | e7c33435851c4421bfb950818b285a00e63d93a0 /src/stanza/client | |
parent | 859a19820d69eca5fca87fc01acad72a6355f97e (diff) | |
download | luz-be198ca15bbaf633c1535db5bae7091520546aed.tar.gz luz-be198ca15bbaf633c1535db5bae7091520546aed.tar.bz2 luz-be198ca15bbaf633c1535db5bae7091520546aed.zip |
implement bind
Diffstat (limited to '')
-rw-r--r-- | src/stanza/client/error.rs | 83 | ||||
-rw-r--r-- | src/stanza/client/iq.rs | 124 | ||||
-rw-r--r-- | src/stanza/client/message.rs | 37 | ||||
-rw-r--r-- | src/stanza/client/mod.rs | 6 | ||||
-rw-r--r-- | src/stanza/client/presence.rs | 48 |
5 files changed, 298 insertions, 0 deletions
diff --git a/src/stanza/client/error.rs b/src/stanza/client/error.rs new file mode 100644 index 0000000..fc5ed21 --- /dev/null +++ b/src/stanza/client/error.rs @@ -0,0 +1,83 @@ +use std::str::FromStr; + +use peanuts::element::{FromElement, IntoElement}; +use peanuts::{DeserializeError, Element}; + +use crate::stanza::error::Text; +use crate::stanza::Error as StanzaError; + +use super::XMLNS; + +#[derive(Clone, Debug)] +pub struct Error { + by: Option<String>, + r#type: ErrorType, + // children (sequence) + error: StanzaError, + text: Option<Text>, +} + +impl FromElement for Error { + fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> { + element.check_name("error")?; + element.check_name(XMLNS)?; + + let by = element.attribute_opt("by")?; + let r#type = element.attribute("type")?; + let error = element.pop_child_one()?; + let text = element.pop_child_opt()?; + + Ok(Error { + by, + r#type, + error, + text, + }) + } +} + +impl IntoElement for Error { + fn builder(&self) -> peanuts::element::ElementBuilder { + Element::builder("error", Some(XMLNS)) + .push_attribute_opt("by", self.by.clone()) + .push_attribute("type", self.r#type) + .push_child(self.error.clone()) + .push_child_opt(self.text.clone()) + } +} + +#[derive(Copy, Clone, Debug)] +pub enum ErrorType { + Auth, + Cancel, + Continue, + Modify, + Wait, +} + +impl FromStr for ErrorType { + type Err = DeserializeError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "auth" => Ok(ErrorType::Auth), + "cancel" => Ok(ErrorType::Cancel), + "continue" => Ok(ErrorType::Continue), + "modify" => Ok(ErrorType::Modify), + "wait" => Ok(ErrorType::Wait), + _ => Err(DeserializeError::FromStr(s.to_string())), + } + } +} + +impl ToString for ErrorType { + fn to_string(&self) -> String { + match self { + ErrorType::Auth => "auth".to_string(), + ErrorType::Cancel => "cancel".to_string(), + ErrorType::Continue => "continue".to_string(), + ErrorType::Modify => "modify".to_string(), + ErrorType::Wait => "wait".to_string(), + } + } +} diff --git a/src/stanza/client/iq.rs b/src/stanza/client/iq.rs new file mode 100644 index 0000000..b23f8b7 --- /dev/null +++ b/src/stanza/client/iq.rs @@ -0,0 +1,124 @@ +use std::str::FromStr; + +use peanuts::{ + element::{FromElement, IntoElement}, + DeserializeError, Element, XML_NS, +}; + +use crate::{ + stanza::{ + bind::{self, Bind}, + client::error::Error, + }, + JID, +}; + +use super::XMLNS; + +pub struct Iq { + pub from: Option<JID>, + pub id: String, + pub to: Option<JID>, + pub r#type: IqType, + pub lang: Option<String>, + // children + // ##other + pub query: Option<Query>, + pub errors: Vec<Error>, +} + +#[derive(Clone)] +pub enum Query { + Bind(Bind), + Unsupported, +} + +impl FromElement for Query { + fn from_element(element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> { + match element.identify() { + (Some(bind::XMLNS), "bind") => Ok(Query::Bind(Bind::from_element(element)?)), + _ => Ok(Query::Unsupported), + } + } +} + +impl IntoElement for Query { + fn builder(&self) -> peanuts::element::ElementBuilder { + match self { + Query::Bind(bind) => bind.builder(), + // TODO: consider what to do if attempt to serialize unsupported + Query::Unsupported => todo!(), + } + } +} + +impl FromElement for Iq { + fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> { + element.check_name("iq")?; + element.check_namespace(XMLNS)?; + + let from = element.attribute_opt("from")?; + let id = element.attribute("id")?; + let to = element.attribute_opt("to")?; + let r#type = element.attribute("type")?; + let lang = element.attribute_opt_namespaced("lang", XML_NS)?; + let query = element.pop_child_opt()?; + let errors = element.pop_children()?; + + Ok(Iq { + from, + id, + to, + r#type, + lang, + query, + errors, + }) + } +} + +impl IntoElement for Iq { + fn builder(&self) -> peanuts::element::ElementBuilder { + Element::builder("iq", Some(XMLNS)) + .push_attribute_opt("from", self.from.clone()) + .push_attribute("id", self.id.clone()) + .push_attribute_opt("to", self.to.clone()) + .push_attribute("type", self.r#type) + .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone()) + .push_child_opt(self.query.clone()) + .push_children(self.errors.clone()) + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum IqType { + Error, + Get, + Result, + Set, +} + +impl FromStr for IqType { + type Err = DeserializeError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "error" => Ok(IqType::Error), + "get" => Ok(IqType::Get), + "result" => Ok(IqType::Result), + "set" => Ok(IqType::Set), + _ => Err(DeserializeError::FromStr(s.to_string())), + } + } +} + +impl ToString for IqType { + fn to_string(&self) -> String { + match self { + IqType::Error => "error".to_string(), + IqType::Get => "get".to_string(), + IqType::Result => "result".to_string(), + IqType::Set => "set".to_string(), + } + } +} diff --git a/src/stanza/client/message.rs b/src/stanza/client/message.rs new file mode 100644 index 0000000..cdfda5d --- /dev/null +++ b/src/stanza/client/message.rs @@ -0,0 +1,37 @@ +use crate::JID; + +pub struct Message { + from: Option<JID>, + id: Option<String>, + to: Option<JID>, + r#type: Option<MessageType>, + // children + subject: Option<Subject>, + body: Option<Body>, + thread: Option<Thread>, + lang: Option<String>, +} + +pub enum MessageType { + Chat, + Error, + Groupchat, + Headline, + Normal, +} + +pub struct Body { + lang: Option<String>, + body: Option<String>, +} + +pub struct Subject { + lang: Option<String>, + subject: Option<String>, +} + +pub struct Thread { + // TODO: NOT DONE + parent: Option<String>, + thread: Option<String>, +} diff --git a/src/stanza/client/mod.rs b/src/stanza/client/mod.rs new file mode 100644 index 0000000..7b25b15 --- /dev/null +++ b/src/stanza/client/mod.rs @@ -0,0 +1,6 @@ +pub mod error; +pub mod iq; +pub mod message; +pub mod presence; + +pub const XMLNS: &str = "jabber:client"; diff --git a/src/stanza/client/presence.rs b/src/stanza/client/presence.rs new file mode 100644 index 0000000..46194f3 --- /dev/null +++ b/src/stanza/client/presence.rs @@ -0,0 +1,48 @@ +use peanuts::element::{FromElement, IntoElement}; + +use crate::JID; + +use super::error::Error; + +pub struct Presence { + from: Option<JID>, + id: Option<String>, + to: Option<JID>, + r#type: PresenceType, + lang: Option<String>, + // children + show: Option<Show>, + status: Option<Status>, + priority: Option<Priority>, + errors: Vec<Error>, + // ##other + // content: Vec<Box<dyn AsElement>>, +} + +pub enum PresenceType { + Error, + Probe, + Subscribe, + Subscribed, + Unavailable, + Unsubscribe, + Unsubscribed, +} + +pub enum Show { + Away, + Chat, + Dnd, + Xa, +} + +pub struct Status { + lang: Option<String>, + status: String1024, +} + +// minLength 1 maxLength 1024 +pub struct String1024(String); + +// xs:byte +pub struct Priority(u8); |