summaryrefslogtreecommitdiffstats
path: root/src/stanza/bind.rs
blob: f1bdc2d822c461d92f25979c59c3746fbef873b9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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)
    }
}