use std::str::FromStr;
use jid::JID;
use peanuts::{
element::{FromElement, IntoElement},
DeserializeError, Element, XML_NS,
};
#[cfg(feature = "xep_0203")]
use crate::xep_0203::Delay;
use super::{error::Error, XMLNS};
#[derive(Debug, Clone)]
pub struct Presence {
pub from: Option<JID>,
pub id: Option<String>,
pub to: Option<JID>,
pub r#type: Option<PresenceType>,
pub lang: Option<String>,
// children
pub show: Option<Show>,
pub status: Option<Status>,
pub priority: Option<Priority>,
#[cfg(feature = "xep_0203")]
pub delay: Option<Delay>,
// TODO: ##other
// other: Vec<Other>,
pub errors: Vec<Error>,
}
impl FromElement for Presence {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("presence")?;
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")?;
let lang = element.attribute_opt_namespaced("lang", XML_NS)?;
let show = element.child_opt()?;
let status = element.child_opt()?;
let priority = element.child_opt()?;
let errors = element.children()?;
#[cfg(feature = "xep_0203")]
let delay = element.child_opt()?;
Ok(Presence {
from,
id,
to,
r#type,
lang,
show,
status,
priority,
errors,
#[cfg(feature = "xep_0203")]
delay,
})
}
}
impl IntoElement for Presence {
fn builder(&self) -> peanuts::element::ElementBuilder {
let builder = Element::builder("presence", 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", self.r#type)
.push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone())
.push_child_opt(self.show)
.push_child_opt(self.status.clone())
.push_child_opt(self.priority)
.push_children(self.errors.clone());
#[cfg(feature = "xep_0203")]
let builder = builder.push_child_opt(self.delay.clone());
builder
}
}
pub enum Other {}
#[derive(Copy, Clone, Debug)]
pub enum PresenceType {
Error,
Probe,
Subscribe,
Subscribed,
Unavailable,
Unsubscribe,
Unsubscribed,
}
impl FromStr for PresenceType {
type Err = DeserializeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"error" => Ok(PresenceType::Error),
"probe" => Ok(PresenceType::Probe),
"subscribe" => Ok(PresenceType::Subscribe),
"subscribed" => Ok(PresenceType::Subscribed),
"unavailable" => Ok(PresenceType::Unavailable),
"unsubscribe" => Ok(PresenceType::Unsubscribe),
"unsubscribed" => Ok(PresenceType::Unsubscribed),
s => Err(DeserializeError::FromStr(s.to_string())),
}
}
}
impl ToString for PresenceType {
fn to_string(&self) -> String {
match self {
PresenceType::Error => "error".to_string(),
PresenceType::Probe => "probe".to_string(),
PresenceType::Subscribe => "subscribe".to_string(),
PresenceType::Subscribed => "subscribed".to_string(),
PresenceType::Unavailable => "unavailable".to_string(),
PresenceType::Unsubscribe => "unsubscribe".to_string(),
PresenceType::Unsubscribed => "unsubscribed".to_string(),
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum Show {
Away,
Chat,
/// do not disturb
Dnd,
/// extended away
Xa,
}
impl FromElement for Show {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("show")?;
element.check_namespace(XMLNS)?;
Ok(element.pop_value()?)
}
}
impl FromStr for Show {
type Err = DeserializeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"away" => Ok(Show::Away),
"chat" => Ok(Show::Chat),
"dnd" => Ok(Show::Dnd),
"xa" => Ok(Show::Xa),
s => Err(DeserializeError::FromStr(s.to_string())),
}
}
}
impl IntoElement for Show {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("show", Some(XMLNS)).push_text(*self)
}
}
impl ToString for Show {
fn to_string(&self) -> String {
match self {
Show::Away => "away".to_string(),
Show::Chat => "chat".to_string(),
Show::Dnd => "dnd".to_string(),
Show::Xa => "xa".to_string(),
}
}
}
#[derive(Clone, Debug)]
pub struct Status {
pub lang: Option<String>,
pub status: String1024,
}
impl FromElement for Status {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("status")?;
element.check_namespace(XMLNS)?;
let lang = element.attribute_opt_namespaced("lang", XML_NS)?;
let status = element.pop_value()?;
Ok(Status { lang, status })
}
}
impl IntoElement for Status {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("status", Some(XMLNS))
.push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone())
.push_text(self.status.clone())
}
}
// TODO: enforce?
/// minLength 1 maxLength 1024
#[derive(Clone, Debug)]
pub struct String1024(pub String);
impl FromStr for String1024 {
type Err = DeserializeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(String1024(s.to_string()))
}
}
impl ToString for String1024 {
fn to_string(&self) -> String {
self.0.clone()
}
}
// xs:byte
#[derive(Clone, Copy, Debug)]
pub struct Priority(pub i8);
impl FromElement for Priority {
fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("priority")?;
element.check_namespace(XMLNS)?;
Ok(Priority(element.pop_value()?))
}
}
impl IntoElement for Priority {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("priority", Some(XMLNS)).push_text(self.0)
}
}