aboutsummaryrefslogtreecommitdiffstats
path: root/src/stanza/client
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/stanza/client/error.rs83
-rw-r--r--src/stanza/client/iq.rs124
-rw-r--r--src/stanza/client/message.rs37
-rw-r--r--src/stanza/client/mod.rs6
-rw-r--r--src/stanza/client/presence.rs48
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);