2024-12-03 03:51:26 +00:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
2024-12-04 18:18:37 +00:00
|
|
|
use jid::JID;
|
2024-12-03 03:51:26 +00:00
|
|
|
use peanuts::{
|
|
|
|
element::{FromElement, IntoElement},
|
|
|
|
DeserializeError, Element, XML_NS,
|
|
|
|
};
|
|
|
|
|
|
|
|
use super::XMLNS;
|
|
|
|
|
2024-12-22 18:58:28 +00:00
|
|
|
#[derive(Debug)]
|
2024-12-02 21:50:15 +00:00
|
|
|
pub struct Message {
|
|
|
|
from: Option<JID>,
|
|
|
|
id: Option<String>,
|
|
|
|
to: Option<JID>,
|
2024-12-03 03:51:26 +00:00
|
|
|
// can be omitted, if so default to normal
|
|
|
|
r#type: MessageType,
|
|
|
|
lang: Option<String>,
|
2024-12-02 21:50:15 +00:00
|
|
|
// children
|
|
|
|
subject: Option<Subject>,
|
|
|
|
body: Option<Body>,
|
|
|
|
thread: Option<Thread>,
|
|
|
|
}
|
|
|
|
|
2024-12-03 03:51:26 +00:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-22 18:58:28 +00:00
|
|
|
#[derive(Default, PartialEq, Eq, Copy, Clone, Debug)]
|
2024-12-02 21:50:15 +00:00
|
|
|
pub enum MessageType {
|
|
|
|
Chat,
|
|
|
|
Error,
|
|
|
|
Groupchat,
|
|
|
|
Headline,
|
2024-12-03 03:51:26 +00:00
|
|
|
#[default]
|
2024-12-02 21:50:15 +00:00
|
|
|
Normal,
|
|
|
|
}
|
|
|
|
|
2024-12-03 03:51:26 +00:00
|
|
|
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(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-22 18:58:28 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2024-12-02 21:50:15 +00:00
|
|
|
pub struct Body {
|
|
|
|
lang: Option<String>,
|
|
|
|
body: Option<String>,
|
|
|
|
}
|
|
|
|
|
2024-12-03 03:51:26 +00:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-22 18:58:28 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2024-12-02 21:50:15 +00:00
|
|
|
pub struct Subject {
|
|
|
|
lang: Option<String>,
|
|
|
|
subject: Option<String>,
|
|
|
|
}
|
|
|
|
|
2024-12-03 03:51:26 +00:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-22 18:58:28 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2024-12-02 21:50:15 +00:00
|
|
|
pub struct Thread {
|
|
|
|
parent: Option<String>,
|
|
|
|
thread: Option<String>,
|
|
|
|
}
|
2024-12-03 03:51:26 +00:00
|
|
|
|
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|