luz/stanza/src/client/message.rs

187 lines
5.1 KiB
Rust
Raw Normal View History

use std::str::FromStr;
2024-12-04 18:18:37 +00:00
use jid::JID;
use peanuts::{
element::{FromElement, IntoElement},
DeserializeError, Element, XML_NS,
};
use super::XMLNS;
#[derive(Debug)]
2024-12-02 21:50:15 +00:00
pub struct Message {
from: Option<JID>,
id: Option<String>,
to: Option<JID>,
// 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>,
}
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, Debug)]
2024-12-02 21:50:15 +00:00
pub enum MessageType {
Chat,
Error,
Groupchat,
Headline,
#[default]
2024-12-02 21:50:15 +00:00
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, Debug)]
2024-12-02 21:50:15 +00:00
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, Debug)]
2024-12-02 21:50:15 +00:00
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, Debug)]
2024-12-02 21:50:15 +00:00
pub struct Thread {
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())
}
}