use std::ops::Deref; use peanuts::{ element::{FromElement, IntoElement}, DeserializeError, Element, }; pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-sasl"; #[derive(Debug, Clone)] pub struct Mechanisms { pub mechanisms: Vec, } impl FromElement for Mechanisms { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("mechanisms")?; element.check_namespace(XMLNS)?; let mechanisms: Vec = element.pop_children()?; let mechanisms = mechanisms .into_iter() .map(|Mechanism(mechanism)| mechanism) .collect(); Ok(Mechanisms { mechanisms }) } } impl IntoElement for Mechanisms { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("mechanisms", Some(XMLNS)).push_children( self.mechanisms .iter() .map(|mechanism| Mechanism(mechanism.to_string())) .collect(), ) } } pub struct Mechanism(String); impl FromElement for Mechanism { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { element.check_name("mechanism")?; element.check_namespace(XMLNS)?; let mechanism = element.pop_value()?; Ok(Mechanism(mechanism)) } } impl IntoElement for Mechanism { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("mechanism", Some(XMLNS)).push_text(self.0.clone()) } } impl Deref for Mechanism { type Target = str; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Debug)] pub struct Auth { pub mechanism: String, pub sasl_data: String, } impl IntoElement for Auth { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("auth", Some(XMLNS)) .push_attribute("mechanism", self.mechanism.clone()) .push_text(self.sasl_data.clone()) } } #[derive(Debug)] pub struct Challenge(String); impl Deref for Challenge { type Target = str; fn deref(&self) -> &Self::Target { &self.0 } } impl FromElement for Challenge { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("challenge")?; element.check_namespace(XMLNS)?; let sasl_data = element.value()?; Ok(Challenge(sasl_data)) } } #[derive(Debug)] pub struct Success(Option); impl Deref for Success { type Target = Option; fn deref(&self) -> &Self::Target { &self.0 } } impl FromElement for Success { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("success")?; element.check_namespace(XMLNS)?; let sasl_data = element.value_opt()?; Ok(Success(sasl_data)) } } #[derive(Debug)] pub enum ServerResponse { Challenge(Challenge), Success(Success), Failure(Failure), } impl FromElement for ServerResponse { fn from_element(element: Element) -> peanuts::element::DeserializeResult { match element.identify() { (Some(XMLNS), "challenge") => { Ok(ServerResponse::Challenge(Challenge::from_element(element)?)) } (Some(XMLNS), "success") => { Ok(ServerResponse::Success(Success::from_element(element)?)) } (Some(XMLNS), "failure") => { Ok(ServerResponse::Failure(Failure::from_element(element)?)) } _ => Err(DeserializeError::UnexpectedElement(element)), } } } #[derive(Debug)] pub struct Response(String); impl Response { pub fn new(response: String) -> Self { Self(response) } } impl Deref for Response { type Target = str; fn deref(&self) -> &Self::Target { &self.0 } } impl IntoElement for Response { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("response", Some(XMLNS)).push_text(self.0.clone()) } } #[derive(Debug)] pub struct Failure { r#type: Option, text: Option, } impl FromElement for Failure { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("failure")?; element.check_namespace(XMLNS)?; let r#type = element.pop_child_opt()?; let text = element.pop_child_opt()?; Ok(Failure { r#type, text }) } } #[derive(Debug)] pub enum FailureType { Aborted, AccountDisabled, CredentialsExpired, EncryptionRequired, IncorrectEncoding, InvalidAuthzid, InvalidMechanism, MalformedRequest, MechanismTooWeak, NotAuthorized, TemporaryAuthFailure, } impl FromElement for FailureType { fn from_element(element: Element) -> peanuts::element::DeserializeResult { match element.identify() { (Some(XMLNS), "aborted") => Ok(FailureType::Aborted), (Some(XMLNS), "account-disabled") => Ok(FailureType::AccountDisabled), (Some(XMLNS), "credentials-expired") => Ok(FailureType::CredentialsExpired), (Some(XMLNS), "encryption-required") => Ok(FailureType::EncryptionRequired), (Some(XMLNS), "incorrect-encoding") => Ok(FailureType::IncorrectEncoding), (Some(XMLNS), "invalid-authzid") => Ok(FailureType::InvalidAuthzid), (Some(XMLNS), "invalid-mechanism") => Ok(FailureType::InvalidMechanism), (Some(XMLNS), "malformed-request") => Ok(FailureType::MalformedRequest), (Some(XMLNS), "mechanism-too-weak") => Ok(FailureType::MechanismTooWeak), (Some(XMLNS), "not-authorized") => Ok(FailureType::NotAuthorized), (Some(XMLNS), "temporary-auth-failure") => Ok(FailureType::TemporaryAuthFailure), _ => Err(DeserializeError::UnexpectedElement(element)), } } } #[derive(Debug)] pub struct Text { lang: Option, text: Option, } impl FromElement for Text { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("text")?; element.check_namespace(XMLNS)?; let lang = element.attribute_opt_namespaced("lang", peanuts::XML_NS)?; let text = element.pop_value_opt()?; Ok(Text { lang, text }) } }