From cd7bb95c0a31d187bfe25bad15043f0b33b111cf Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Wed, 2 Aug 2023 00:56:38 +0100 Subject: implement resource binding --- src/stanza/bind.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/stanza/bind.rs (limited to 'src/stanza/bind.rs') diff --git a/src/stanza/bind.rs b/src/stanza/bind.rs new file mode 100644 index 0000000..f1bdc2d --- /dev/null +++ b/src/stanza/bind.rs @@ -0,0 +1,111 @@ +use quick_xml::{ + events::{BytesStart, BytesText, Event}, + name::QName, + Reader, +}; + +use super::{Element, IntoElement}; +use crate::{JabberError, JID}; + +const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-bind"; + +pub struct Bind { + pub resource: Option, + pub jid: Option, +} + +impl<'e> IntoElement<'e> for Bind { + fn event(&self) -> quick_xml::events::Event<'static> { + let mut bind_event = BytesStart::new("bind"); + bind_event.push_attribute(("xmlns", XMLNS)); + if self.resource.is_none() && self.jid.is_none() { + return Event::Empty(bind_event); + } else { + return Event::Start(bind_event); + } + } + + fn children(&self) -> Option>> { + if let Some(resource) = &self.resource { + let resource_event: BytesStart<'static> = BytesStart::new("resource"); + let resource_child: BytesText<'static> = BytesText::new(resource).into_owned(); + let resource_child: Element<'static> = Element { + event: Event::Text(resource_child), + children: None, + }; + let resource_element: Element<'static> = Element { + event: Event::Start(resource_event), + children: Some(vec![resource_child]), + }; + return Some(vec![resource_element]); + } else if let Some(jid) = &self.jid { + let jid_event = BytesStart::new("jid"); + let jid_child = BytesText::new(&jid.to_string()).into_owned(); + let jid_child = Element { + event: Event::Text(jid_child), + children: None, + }; + let jid_element = Element { + event: Event::Start(jid_event), + children: Some(vec![jid_child]), + }; + return Some(vec![jid_element]); + } + None + } +} + +impl TryFrom> for Bind { + type Error = JabberError; + + fn try_from(element: Element<'static>) -> Result { + if let Event::Start(start) = &element.event { + let buf: Vec = Vec::new(); + let reader = Reader::from_reader(buf); + if start.name() == QName(b"bind") + && start.try_get_attribute("xmlns")?.is_some_and(|attribute| { + attribute.decode_and_unescape_value(&reader).unwrap() == XMLNS + }) + { + let child: Element<'static> = element.child()?.clone(); + if let Event::Start(start) = &child.event { + match start.name() { + QName(b"resource") => { + let resource_text = child.child()?; + if let Event::Text(text) = &resource_text.event { + return Ok(Self { + resource: Some(text.unescape()?.into_owned()), + jid: None, + }); + } + } + QName(b"jid") => { + let jid_text = child.child()?; + if let Event::Text(text) = &jid_text.event { + return Ok(Self { + jid: Some(text.unescape()?.into_owned().try_into()?), + resource: None, + }); + } + } + _ => return Err(JabberError::UnexpectedElement), + } + } + } + } else if let Event::Empty(start) = &element.event { + let buf: Vec = Vec::new(); + let reader = Reader::from_reader(buf); + if start.name() == QName(b"bind") + && start.try_get_attribute("xmlns")?.is_some_and(|attribute| { + attribute.decode_and_unescape_value(&reader).unwrap() == XMLNS + }) + { + return Ok(Bind { + resource: None, + jid: None, + }); + } + } + Err(JabberError::UnexpectedElement) + } +} -- cgit