aboutsummaryrefslogblamecommitdiffstats
path: root/stanza/src/client/iq.rs
blob: 5f5ccd2fc49f5f9eb404b585935b29734407beb3 (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 crate::{
    bind::{self, Bind},
    client::error::Error,
    roster,
    xep_0199::{self, Ping},
};

#[cfg(feature = "xep_0030")]
use crate::xep_0030::{self, info, items};

use super::XMLNS;

#[derive(Debug, Clone)]
pub struct Iq {
    pub from: Option<JID>,
    pub id: String,
    pub to: Option<JID>,
    pub r#type: IqType,
    pub lang: Option<String>,
    // children
    // ##other
    pub query: Option<Query>,
    pub errors: Vec<Error>,
}

#[derive(Clone, Debug)]
pub enum Query {
    Bind(Bind),
    #[cfg(feature = "xep_0030")]
    DiscoInfo(info::Query),
    #[cfg(feature = "xep_0030")]
    DiscoItems(items::Query),
    Ping(Ping),
    Roster(roster::Query),
    Unsupported,
}

impl FromElement for Query {
    fn from_element(element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> {
        match element.identify() {
            (Some(bind::XMLNS), "bind") => Ok(Query::Bind(Bind::from_element(element)?)),
            (Some(xep_0199::XMLNS), "ping") => Ok(Query::Ping(Ping::from_element(element)?)),
            (Some(roster::XMLNS), "query") => {
                Ok(Query::Roster(roster::Query::from_element(element)?))
            }
            #[cfg(feature = "xep_0030")]
            (Some(xep_0030::info::XMLNS), "query") => {
                Ok(Query::DiscoInfo(info::Query::from_element(element)?))
            }
            #[cfg(feature = "xep_0030")]
            (Some(xep_0030::items::XMLNS), "query") => {
                Ok(Query::DiscoItems(items::Query::from_element(element)?))
            }
            _ => Ok(Query::Unsupported),
        }
    }
}

impl IntoElement for Query {
    fn builder(&self) -> peanuts::element::ElementBuilder {
        match self {
            Query::Bind(bind) => bind.builder(),
            Query::Ping(ping) => ping.builder(),
            Query::Roster(query) => query.builder(),
            // TODO: consider what to do if attempt to serialize unsupported
            Query::Unsupported => todo!(),
            #[cfg(feature = "xep_0030")]
            Query::DiscoInfo(query) => query.builder(),
            #[cfg(feature = "xep_0030")]
            Query::DiscoItems(query) => query.builder(),
        }
    }
}

impl FromElement for Iq {
    fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> {
        element.check_name("iq")?;
        element.check_namespace(XMLNS)?;

        let from = element.attribute_opt("from")?;
        let id = element.attribute("id")?;
        let to = element.attribute_opt("to")?;
        let r#type = element.attribute("type")?;
        let lang = element.attribute_opt_namespaced("lang", XML_NS)?;
        let query = element.pop_child_opt()?;
        let errors = element.pop_children()?;

        Ok(Iq {
            from,
            id,
            to,
            r#type,
            lang,
            query,
            errors,
        })
    }
}

impl IntoElement for Iq {
    fn builder(&self) -> peanuts::element::ElementBuilder {
        Element::builder("iq", Some(XMLNS))
            .push_attribute_opt("from", self.from.clone())
            .push_attribute("id", self.id.clone())
            .push_attribute_opt("to", self.to.clone())
            .push_attribute("type", self.r#type)
            .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone())
            .push_child_opt(self.query.clone())
            .push_children(self.errors.clone())
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum IqType {
    Error,
    Get,
    Result,
    Set,
}

impl FromStr for IqType {
    type Err = DeserializeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "error" => Ok(IqType::Error),
            "get" => Ok(IqType::Get),
            "result" => Ok(IqType::Result),
            "set" => Ok(IqType::Set),
            _ => Err(DeserializeError::FromStr(s.to_string())),
        }
    }
}

impl ToString for IqType {
    fn to_string(&self) -> String {
        match self {
            IqType::Error => "error".to_string(),
            IqType::Get => "get".to_string(),
            IqType::Result => "result".to_string(),
            IqType::Set => "set".to_string(),
        }
    }
}