use std::str::FromStr; use jid::JID; use peanuts::{ element::{FromElement, IntoElement}, DeserializeError, Element, XML_NS, }; use super::XMLNS; #[derive(Debug)] pub struct Message { from: Option, id: Option, to: Option, // can be omitted, if so default to normal r#type: MessageType, lang: Option, // children subject: Option, body: Option, thread: Option, } impl FromElement for Message { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { 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, Debug)] pub enum MessageType { Chat, Error, Groupchat, Headline, #[default] Normal, } impl FromStr for MessageType { type Err = DeserializeError; fn from_str(s: &str) -> Result { 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, Debug)] pub struct Body { lang: Option, body: Option, } impl FromElement for Body { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { 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, Debug)] pub struct Subject { lang: Option, subject: Option, } impl FromElement for Subject { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { 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, Debug)] pub struct Thread { parent: Option, thread: Option, } impl FromElement for Thread { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { 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()) } }