diff options
Diffstat (limited to 'src/stanza/client/message.rs')
-rw-r--r-- | src/stanza/client/message.rs | 155 |
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()) + } +} |