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}, }; use super::XMLNS; #[derive(Debug)] pub struct Iq { pub from: Option, pub id: String, pub to: Option, pub r#type: IqType, pub lang: Option, // children // ##other pub query: Option, pub errors: Vec, } #[derive(Clone, Debug)] pub enum Query { Bind(Bind), Ping(Ping), Roster(roster::Query), Unsupported, } impl FromElement for Query { fn from_element(element: peanuts::Element) -> peanuts::element::DeserializeResult { 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)?)) } _ => 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!(), } } } impl FromElement for Iq { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { 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 { 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(), } } }