aboutsummaryrefslogblamecommitdiffstats
path: root/stanza/src/client/presence.rs
blob: 1603ace7514a06ab3ef4a3f1e0f4c85b11dd6739 (plain) (tree)
1
2
3
4
5
6
7
8
9

                      
             



                                        
 
                                 
 
                       
                     




                                     
               


                                   

                         
                           

 














































                                                                                        
                             









                       






























                                                                     
                             


               
                      
        
                     


       







































                                                                                        
                       
                   

                             

 





















                                                                                        
                       














                                                     

          
                             















                                                                                                 
use std::str::FromStr;

use jid::JID;
use peanuts::{
    element::{FromElement, IntoElement},
    DeserializeError, Element, XML_NS,
};

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>,
    // 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()?;

        Ok(Presence {
            from,
            id,
            to,
            r#type,
            lang,
            show,
            status,
            priority,
            errors,
        })
    }
}

impl IntoElement for Presence {
    fn builder(&self) -> peanuts::element::ElementBuilder {
        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())
    }
}

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)
    }
}