diff options
author | 2024-11-24 02:04:45 +0000 | |
---|---|---|
committer | 2024-11-24 02:04:45 +0000 | |
commit | 35f164cdb6324c6dfb635f8de93a8221861a5991 (patch) | |
tree | f858e55999007046e511acce17b9e35bc1585ba4 /src/stanza | |
parent | 40024d2dadba9e70edb2f3448204565ce3f68ab7 (diff) | |
download | luz-35f164cdb6324c6dfb635f8de93a8221861a5991.tar.gz luz-35f164cdb6324c6dfb635f8de93a8221861a5991.tar.bz2 luz-35f164cdb6324c6dfb635f8de93a8221861a5991.zip |
implement starttls
Diffstat (limited to '')
-rw-r--r-- | src/stanza/starttls.rs | 162 | ||||
-rw-r--r-- | src/stanza/stream.rs | 73 |
2 files changed, 234 insertions, 1 deletions
diff --git a/src/stanza/starttls.rs b/src/stanza/starttls.rs index 8b13789..874ae66 100644 --- a/src/stanza/starttls.rs +++ b/src/stanza/starttls.rs @@ -1 +1,163 @@ +use std::collections::{HashMap, HashSet}; +use peanuts::{ + element::{Content, FromElement, IntoElement, Name, NamespaceDeclaration}, + Element, +}; + +pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-tls"; + +#[derive(Debug)] +pub struct StartTls { + pub required: bool, +} + +impl IntoElement for StartTls { + fn into_element(&self) -> peanuts::Element { + let content; + if self.required == true { + let element = Content::Element(Element { + name: Name { + namespace: Some(XMLNS.to_string()), + local_name: "required".to_string(), + }, + namespace_declarations: HashSet::new(), + attributes: HashMap::new(), + content: Vec::new(), + }); + content = vec![element]; + } else { + content = Vec::new(); + } + let mut namespace_declarations = HashSet::new(); + namespace_declarations.insert(NamespaceDeclaration { + prefix: None, + namespace: XMLNS.to_string(), + }); + Element { + name: Name { + namespace: Some(XMLNS.to_string()), + local_name: "starttls".to_string(), + }, + namespace_declarations, + attributes: HashMap::new(), + content, + } + } +} + +impl FromElement for StartTls { + fn from_element(element: peanuts::Element) -> peanuts::Result<Self> { + let Name { + namespace, + local_name, + } = element.name; + if namespace.as_deref() == Some(XMLNS) && &local_name == "starttls" { + let mut required = false; + if element.content.len() == 1 { + match element.content.first().unwrap() { + Content::Element(element) => { + let Name { + namespace, + local_name, + } = &element.name; + + if namespace.as_deref() == Some(XMLNS) && local_name == "required" { + required = true + } else { + return Err(peanuts::Error::UnexpectedElement(element.name.clone())); + } + } + c => return Err(peanuts::Error::UnexpectedContent((*c).clone())), + } + } else { + return Err(peanuts::Error::UnexpectedNumberOfContents( + element.content.len(), + )); + } + return Ok(StartTls { required }); + } else { + return Err(peanuts::Error::IncorrectName(Name { + namespace, + local_name, + })); + } + } +} + +#[derive(Debug)] +pub struct Proceed; + +impl IntoElement for Proceed { + fn into_element(&self) -> Element { + let mut namespace_declarations = HashSet::new(); + namespace_declarations.insert(NamespaceDeclaration { + prefix: None, + namespace: XMLNS.to_string(), + }); + Element { + name: Name { + namespace: Some(XMLNS.to_string()), + local_name: "proceed".to_string(), + }, + namespace_declarations, + attributes: HashMap::new(), + content: Vec::new(), + } + } +} + +impl FromElement for Proceed { + fn from_element(element: Element) -> peanuts::Result<Self> { + let Name { + namespace, + local_name, + } = element.name; + if namespace.as_deref() == Some(XMLNS) && &local_name == "proceed" { + return Ok(Proceed); + } else { + return Err(peanuts::Error::IncorrectName(Name { + namespace, + local_name, + })); + } + } +} + +pub struct Failure; + +impl IntoElement for Failure { + fn into_element(&self) -> Element { + let mut namespace_declarations = HashSet::new(); + namespace_declarations.insert(NamespaceDeclaration { + prefix: None, + namespace: XMLNS.to_string(), + }); + Element { + name: Name { + namespace: Some(XMLNS.to_string()), + local_name: "failure".to_string(), + }, + namespace_declarations, + attributes: HashMap::new(), + content: Vec::new(), + } + } +} + +impl FromElement for Failure { + fn from_element(element: Element) -> peanuts::Result<Self> { + let Name { + namespace, + local_name, + } = element.name; + if namespace.as_deref() == Some(XMLNS) && &local_name == "failure" { + return Ok(Failure); + } else { + return Err(peanuts::Error::IncorrectName(Name { + namespace, + local_name, + })); + } + } +} diff --git a/src/stanza/stream.rs b/src/stanza/stream.rs index ac4badc..4516682 100644 --- a/src/stanza/stream.rs +++ b/src/stanza/stream.rs @@ -6,12 +6,15 @@ use peanuts::{element::Name, Element}; use crate::{Error, JID}; +use super::starttls::StartTls; + pub const XMLNS: &str = "http://etherx.jabber.org/streams"; pub const XMLNS_CLIENT: &str = "jabber:client"; // MUST be qualified by stream namespace // #[derive(XmlSerialize, XmlDeserialize)] // #[peanuts(xmlns = XMLNS)] +#[derive(Debug)] pub struct Stream { pub from: Option<JID>, to: Option<JID>, @@ -93,7 +96,7 @@ impl IntoElement for Stream { attributes.insert( Name { namespace: None, - local_name: "version".to_string(), + local_name: "id".to_string(), }, id.clone(), ); @@ -158,3 +161,71 @@ impl<'s> Stream { } } } + +#[derive(Debug)] +pub struct Features { + features: Vec<Feature>, +} + +impl IntoElement for Features { + fn into_element(&self) -> Element { + let mut content = Vec::new(); + for feature in &self.features { + match feature { + Feature::StartTls(start_tls) => { + content.push(Content::Element(start_tls.into_element())) + } + Feature::Sasl => {} + Feature::Bind => {} + Feature::Unknown => {} + } + } + Element { + name: Name { + namespace: Some(XMLNS.to_string()), + local_name: "features".to_string(), + }, + namespace_declarations: HashSet::new(), + attributes: HashMap::new(), + content, + } + } +} + +impl FromElement for Features { + fn from_element(element: Element) -> peanuts::Result<Self> { + let Name { + namespace, + local_name, + } = element.name; + if namespace.as_deref() == Some(XMLNS) && &local_name == "features" { + let mut features = Vec::new(); + for feature in element.content { + match feature { + Content::Element(element) => { + if let Ok(start_tls) = FromElement::from_element(element) { + features.push(Feature::StartTls(start_tls)) + } else { + features.push(Feature::Unknown) + } + } + c => return Err(peanuts::Error::UnexpectedContent(c.clone())), + } + } + return Ok(Self { features }); + } else { + return Err(peanuts::Error::IncorrectName(Name { + namespace, + local_name, + })); + } + } +} + +#[derive(Debug)] +pub enum Feature { + StartTls(StartTls), + Sasl, + Bind, + Unknown, +} |