summaryrefslogtreecommitdiffstats
path: root/src/stanza/bind.rs
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2023-08-02 00:56:38 +0100
committerLibravatar cel 🌸 <cel@blos.sm>2023-08-02 00:56:38 +0100
commitcd7bb95c0a31d187bfe25bad15043f0b33b111cf (patch)
treec5be0c651198abf736f8867a36906f9345f3a0ac /src/stanza/bind.rs
parent322b2a3b46348ec1c5acbc538de93310c9030b96 (diff)
downloadluz-cd7bb95c0a31d187bfe25bad15043f0b33b111cf.tar.gz
luz-cd7bb95c0a31d187bfe25bad15043f0b33b111cf.tar.bz2
luz-cd7bb95c0a31d187bfe25bad15043f0b33b111cf.zip
implement resource binding
Diffstat (limited to 'src/stanza/bind.rs')
-rw-r--r--src/stanza/bind.rs111
1 files changed, 111 insertions, 0 deletions
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<String>,
+ pub jid: Option<JID>,
+}
+
+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<Vec<Element<'static>>> {
+ 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<Element<'static>> for Bind {
+ type Error = JabberError;
+
+ fn try_from(element: Element<'static>) -> Result<Self, Self::Error> {
+ if let Event::Start(start) = &element.event {
+ let buf: Vec<u8> = 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<u8> = 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)
+ }
+}