Compare commits

...

2 Commits

Author SHA1 Message Date
cel 🌸 668270429f use element builder and parse methods 2024-11-28 18:02:06 +00:00
cel 🌸 880194d811 fix: use namespace_declaration_overrides 2024-11-24 15:09:05 +00:00
2 changed files with 126 additions and 267 deletions

View File

@ -7,81 +7,48 @@ use peanuts::{
pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-tls"; pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-tls";
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct StartTls { pub struct StartTls {
pub required: bool, pub required: bool,
} }
impl IntoElement for StartTls { impl IntoElement for StartTls {
fn into_element(&self) -> peanuts::Element { fn builder(&self) -> peanuts::element::ElementBuilder {
let content; let mut builder = Element::builder("starttls", Some(XMLNS));
if self.required == true {
let element = Content::Element(Element { if self.required {
name: Name { builder = builder.push_child(Element::builder("required", Some(XMLNS)))
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,
} }
builder
} }
} }
impl FromElement for StartTls { impl FromElement for StartTls {
fn from_element(element: peanuts::Element) -> peanuts::Result<Self> { fn from_element(
let Name { mut element: peanuts::Element,
namespace, ) -> std::result::Result<StartTls, peanuts::DeserializeError> {
local_name, element.check_name("starttls")?;
} = element.name; element.check_namespace(XMLNS)?;
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" { let mut required = false;
required = true if let Some(_) = element.child_opt::<Required>()? {
} else { required = true;
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,
}));
} }
Ok(StartTls { required })
}
}
#[derive(Debug)]
pub struct Required;
impl FromElement for Required {
fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("required")?;
element.check_namespace(XMLNS)?;
Ok(Required)
} }
} }
@ -89,75 +56,33 @@ impl FromElement for StartTls {
pub struct Proceed; pub struct Proceed;
impl IntoElement for Proceed { impl IntoElement for Proceed {
fn into_element(&self) -> Element { fn builder(&self) -> peanuts::element::ElementBuilder {
let mut namespace_declarations = HashSet::new(); Element::builder("proceed", Some(XMLNS))
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 { impl FromElement for Proceed {
fn from_element(element: Element) -> peanuts::Result<Self> { fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> {
let Name { element.check_name("proceed")?;
namespace, element.check_namespace(XMLNS)?;
local_name,
} = element.name; Ok(Proceed)
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; pub struct Failure;
impl IntoElement for Failure { impl IntoElement for Failure {
fn into_element(&self) -> Element { fn builder(&self) -> peanuts::element::ElementBuilder {
let mut namespace_declarations = HashSet::new(); Element::builder("failure", Some(XMLNS))
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 { impl FromElement for Failure {
fn from_element(element: Element) -> peanuts::Result<Self> { fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> {
let Name { element.check_name("failure")?;
namespace, element.check_namespace(XMLNS)?;
local_name,
} = element.name; Ok(Failure)
if namespace.as_deref() == Some(XMLNS) && &local_name == "failure" {
return Ok(Failure);
} else {
return Err(peanuts::Error::IncorrectName(Name {
namespace,
local_name,
}));
}
} }
} }

View File

@ -1,12 +1,12 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use peanuts::element::{Content, FromElement, IntoElement, NamespaceDeclaration}; use peanuts::element::{Content, ElementBuilder, FromElement, IntoElement, NamespaceDeclaration};
use peanuts::XML_NS; use peanuts::XML_NS;
use peanuts::{element::Name, Element}; use peanuts::{element::Name, Element};
use crate::{Error, JID}; use crate::{Error, JID};
use super::starttls::StartTls; use super::starttls::{self, StartTls};
pub const XMLNS: &str = "http://etherx.jabber.org/streams"; pub const XMLNS: &str = "http://etherx.jabber.org/streams";
pub const XMLNS_CLIENT: &str = "jabber:client"; pub const XMLNS_CLIENT: &str = "jabber:client";
@ -27,108 +27,36 @@ pub struct Stream {
} }
impl FromElement for Stream { impl FromElement for Stream {
fn from_element(element: Element) -> peanuts::Result<Self> { fn from_element(mut element: Element) -> std::result::Result<Self, peanuts::DeserializeError> {
let Name { element.check_namespace(XMLNS)?;
namespace, element.check_name("stream")?;
local_name,
} = element.name; let from = element.attribute_opt("from")?;
if namespace.as_deref() == Some(XMLNS) && &local_name == "stream" { let to = element.attribute_opt("to")?;
let (mut from, mut to, mut id, mut version, mut lang) = (None, None, None, None, None); let id = element.attribute_opt("id")?;
for (name, value) in element.attributes { let version = element.attribute_opt("version")?;
match (name.namespace.as_deref(), name.local_name.as_str()) { let lang = element.attribute_opt_namespaced("lang", peanuts::XML_NS)?;
(None, "from") => from = Some(value.try_into()?),
(None, "to") => to = Some(value.try_into()?), Ok(Stream {
(None, "id") => id = Some(value), from,
(None, "version") => version = Some(value), to,
(Some(XML_NS), "lang") => lang = Some(value), id,
_ => return Err(peanuts::Error::UnexpectedAttribute(name)), version,
} lang,
} })
return Ok(Stream {
from,
to,
id,
version,
lang,
});
} else {
return Err(peanuts::Error::IncorrectName(Name {
namespace,
local_name,
}));
}
} }
} }
impl IntoElement for Stream { impl IntoElement for Stream {
fn into_element(&self) -> Element { fn builder(&self) -> ElementBuilder {
let mut namespace_declarations = HashSet::new(); Element::builder("stream", Some(XMLNS.to_string()))
namespace_declarations.insert(NamespaceDeclaration { .push_namespace_declaration_override(Some("stream"), XMLNS)
prefix: Some("stream".to_string()), .push_namespace_declaration_override(None::<&str>, XMLNS_CLIENT)
namespace: XMLNS.to_string(), .push_attribute_opt("to", self.to.clone())
}); .push_attribute_opt("from", self.from.clone())
namespace_declarations.insert(NamespaceDeclaration { .push_attribute_opt("id", self.id.clone())
prefix: None, .push_attribute_opt("version", self.version.clone())
// TODO: don't default to client .push_attribute_opt_namespaced(peanuts::XML_NS, "to", self.lang.clone())
namespace: XMLNS_CLIENT.to_string(),
});
let mut attributes = HashMap::new();
self.from.as_ref().map(|from| {
attributes.insert(
Name {
namespace: None,
local_name: "from".to_string(),
},
from.to_string(),
);
});
self.to.as_ref().map(|to| {
attributes.insert(
Name {
namespace: None,
local_name: "to".to_string(),
},
to.to_string(),
);
});
self.id.as_ref().map(|id| {
attributes.insert(
Name {
namespace: None,
local_name: "id".to_string(),
},
id.clone(),
);
});
self.version.as_ref().map(|version| {
attributes.insert(
Name {
namespace: None,
local_name: "version".to_string(),
},
version.clone(),
);
});
self.lang.as_ref().map(|lang| {
attributes.insert(
Name {
namespace: Some(XML_NS.to_string()),
local_name: "lang".to_string(),
},
lang.to_string(),
);
});
Element {
name: Name {
namespace: Some(XMLNS.to_string()),
local_name: "stream".to_string(),
},
namespace_declarations,
attributes,
content: Vec::new(),
}
} }
} }
@ -168,64 +96,70 @@ pub struct Features {
} }
impl IntoElement for Features { impl IntoElement for Features {
fn into_element(&self) -> Element { fn builder(&self) -> ElementBuilder {
let mut content = Vec::new(); Element::builder("features", Some(XMLNS)).push_children(self.features.clone())
for feature in &self.features { // let mut content = Vec::new();
match feature { // for feature in &self.features {
Feature::StartTls(start_tls) => { // match feature {
content.push(Content::Element(start_tls.into_element())) // Feature::StartTls(start_tls) => {
} // content.push(Content::Element(start_tls.into_element()))
Feature::Sasl => {} // }
Feature::Bind => {} // Feature::Sasl => {}
Feature::Unknown => {} // Feature::Bind => {}
} // Feature::Unknown => {}
} // }
Element { // }
name: Name { // Element {
namespace: Some(XMLNS.to_string()), // name: Name {
local_name: "features".to_string(), // namespace: Some(XMLNS.to_string()),
}, // local_name: "features".to_string(),
namespace_declarations: HashSet::new(), // },
attributes: HashMap::new(), // namespace_declaration_overrides: HashSet::new(),
content, // attributes: HashMap::new(),
} // content,
// }
} }
} }
impl FromElement for Features { impl FromElement for Features {
fn from_element(element: Element) -> peanuts::Result<Self> { fn from_element(
let Name { mut element: Element,
namespace, ) -> std::result::Result<Features, peanuts::DeserializeError> {
local_name, element.check_namespace(XMLNS)?;
} = element.name; element.check_name("features")?;
if namespace.as_deref() == Some(XMLNS) && &local_name == "features" {
let mut features = Vec::new(); let features = element.children()?;
for feature in element.content {
match feature { Ok(Features { features })
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)] #[derive(Debug, Clone)]
pub enum Feature { pub enum Feature {
StartTls(StartTls), StartTls(StartTls),
Sasl, Sasl,
Bind, Bind,
Unknown, Unknown,
} }
impl IntoElement for Feature {
fn builder(&self) -> ElementBuilder {
match self {
Feature::StartTls(start_tls) => start_tls.builder(),
Feature::Sasl => todo!(),
Feature::Bind => todo!(),
Feature::Unknown => todo!(),
}
}
}
impl FromElement for Feature {
fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> {
match element.identify() {
(Some(starttls::XMLNS), "starttls") => {
Ok(Feature::StartTls(StartTls::from_element(element)?))
}
_ => Ok(Feature::Unknown),
}
}
}