aboutsummaryrefslogtreecommitdiffstats
path: root/src/stanza/client/message.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/stanza/client/message.rs')
-rw-r--r--src/stanza/client/message.rs155
1 files changed, 152 insertions, 3 deletions
diff --git a/src/stanza/client/message.rs b/src/stanza/client/message.rs
index cdfda5d..626d781 100644
--- a/src/stanza/client/message.rs
+++ b/src/stanza/client/message.rs
@@ -1,37 +1,186 @@
+use std::str::FromStr;
+
+use peanuts::{
+ element::{FromElement, IntoElement},
+ DeserializeError, Element, XML_NS,
+};
+
use crate::JID;
+use super::XMLNS;
+
pub struct Message {
from: Option<JID>,
id: Option<String>,
to: Option<JID>,
- r#type: Option<MessageType>,
+ // can be omitted, if so default to normal
+ r#type: MessageType,
+ lang: Option<String>,
// children
subject: Option<Subject>,
body: Option<Body>,
thread: Option<Thread>,
- lang: Option<String>,
}
+impl FromElement for Message {
+ fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
+ element.check_name("message")?;
+ 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")?.unwrap_or_default();
+ let lang = element.attribute_opt_namespaced("lang", XML_NS)?;
+
+ let subject = element.child_opt()?;
+ let body = element.child_opt()?;
+ let thread = element.child_opt()?;
+
+ Ok(Message {
+ from,
+ id,
+ to,
+ r#type,
+ lang,
+ subject,
+ body,
+ thread,
+ })
+ }
+}
+
+impl IntoElement for Message {
+ fn builder(&self) -> peanuts::element::ElementBuilder {
+ Element::builder("message", 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", {
+ if self.r#type == MessageType::Normal {
+ None
+ } else {
+ Some(self.r#type)
+ }
+ })
+ .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone())
+ .push_child_opt(self.subject.clone())
+ .push_child_opt(self.body.clone())
+ .push_child_opt(self.thread.clone())
+ }
+}
+
+#[derive(Default, PartialEq, Eq, Copy, Clone)]
pub enum MessageType {
Chat,
Error,
Groupchat,
Headline,
+ #[default]
Normal,
}
+impl FromStr for MessageType {
+ type Err = DeserializeError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "chat" => Ok(MessageType::Chat),
+ "error" => Ok(MessageType::Error),
+ "groupchat" => Ok(MessageType::Groupchat),
+ "headline" => Ok(MessageType::Headline),
+ "normal" => Ok(MessageType::Normal),
+ _ => Err(DeserializeError::FromStr(s.to_string())),
+ }
+ }
+}
+
+impl ToString for MessageType {
+ fn to_string(&self) -> String {
+ match self {
+ MessageType::Chat => "chat".to_string(),
+ MessageType::Error => "error".to_string(),
+ MessageType::Groupchat => "groupchat".to_string(),
+ MessageType::Headline => "headline".to_string(),
+ MessageType::Normal => "normal".to_string(),
+ }
+ }
+}
+
+#[derive(Clone)]
pub struct Body {
lang: Option<String>,
body: Option<String>,
}
+impl FromElement for Body {
+ fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> {
+ element.check_name("body")?;
+ element.check_namespace(XMLNS)?;
+
+ let lang = element.attribute_opt_namespaced("lang", XML_NS)?;
+ let body = element.pop_value_opt()?;
+
+ Ok(Body { lang, body })
+ }
+}
+
+impl IntoElement for Body {
+ fn builder(&self) -> peanuts::element::ElementBuilder {
+ Element::builder("body", Some(XMLNS))
+ .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone())
+ .push_text_opt(self.body.clone())
+ }
+}
+
+#[derive(Clone)]
pub struct Subject {
lang: Option<String>,
subject: Option<String>,
}
+impl FromElement for Subject {
+ fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> {
+ element.check_name("subject")?;
+ element.check_namespace(XMLNS)?;
+
+ let lang = element.attribute_opt_namespaced("lang", XML_NS)?;
+ let subject = element.pop_value_opt()?;
+
+ Ok(Subject { lang, subject })
+ }
+}
+
+impl IntoElement for Subject {
+ fn builder(&self) -> peanuts::element::ElementBuilder {
+ Element::builder("subject", Some(XMLNS))
+ .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone())
+ .push_text_opt(self.subject.clone())
+ }
+}
+
+#[derive(Clone)]
pub struct Thread {
- // TODO: NOT DONE
parent: Option<String>,
thread: Option<String>,
}
+
+impl FromElement for Thread {
+ fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> {
+ element.check_name("thread")?;
+ element.check_namespace(XMLNS)?;
+
+ let parent = element.attribute_opt("parent")?;
+ let thread = element.pop_value_opt()?;
+
+ Ok(Thread { parent, thread })
+ }
+}
+
+impl IntoElement for Thread {
+ fn builder(&self) -> peanuts::element::ElementBuilder {
+ Element::builder("thread", Some(XMLNS))
+ .push_attribute_opt("parent", self.parent.clone())
+ .push_text_opt(self.thread.clone())
+ }
+}