summaryrefslogtreecommitdiffstats
path: root/src/stanza/stream.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/stanza/stream.rs')
-rw-r--r--src/stanza/stream.rs197
1 files changed, 169 insertions, 28 deletions
diff --git a/src/stanza/stream.rs b/src/stanza/stream.rs
index 4c0addd..f0fb6a1 100644
--- a/src/stanza/stream.rs
+++ b/src/stanza/stream.rs
@@ -1,41 +1,182 @@
-use serde::{Deserialize, Serialize};
+use std::str;
-use super::sasl::Mechanisms;
+use quick_xml::{
+ events::{BytesStart, Event},
+ name::QName,
+};
-#[derive(Serialize, Deserialize)]
-#[serde(rename = "stream:stream")]
-struct Stream {
- #[serde(rename = "@from")]
- from: Option<String>,
- #[serde(rename = "@id")]
+use crate::{element::Element, JabberError, Result, JID};
+
+const XMLNS_STREAM: &str = "http://etherx.jabber.org/streams";
+const VERSION: &str = "1.0";
+
+enum XMLNS {
+ Client,
+ Server,
+}
+
+impl From<XMLNS> for &str {
+ fn from(xmlns: XMLNS) -> Self {
+ match xmlns {
+ XMLNS::Client => return "jabber:client",
+ XMLNS::Server => return "jabber:server",
+ }
+ }
+}
+
+impl TryInto<XMLNS> for &str {
+ type Error = JabberError;
+
+ fn try_into(self) -> Result<XMLNS> {
+ match self {
+ "jabber:client" => Ok(XMLNS::Client),
+ "jabber:server" => Ok(XMLNS::Server),
+ _ => Err(JabberError::UnknownNamespace),
+ }
+ }
+}
+
+pub struct Stream {
+ from: Option<JID>,
id: Option<String>,
- #[serde(rename = "@to")]
- to: Option<String>,
- #[serde(rename = "@version")]
- version: Option<f32>,
- #[serde(rename = "@xml:lang")]
+ to: Option<JID>,
+ version: Option<String>,
lang: Option<String>,
- #[serde(rename = "@xmlns")]
- namespace: Option<String>,
- #[serde(rename = "@xmlns:stream")]
- stream_namespace: Option<String>,
+ _ns: XMLNS,
}
-#[derive(Deserialize, Debug)]
-#[serde(rename = "stream:features")]
-pub struct StreamFeatures {
- #[serde(rename = "$value")]
- pub features: Vec<StreamFeature>,
+impl Stream {
+ pub fn new_client(from: &JID, to: &JID, id: Option<String>, lang: Option<String>) -> Self {
+ Self {
+ from: Some(from.clone()),
+ id,
+ to: Some(to.clone()),
+ version: Some(VERSION.to_owned()),
+ lang,
+ _ns: XMLNS::Client,
+ }
+ }
+
+ fn build(&self) -> BytesStart {
+ let mut start = BytesStart::new("stream:stream");
+ if let Some(from) = &self.from {
+ start.push_attribute(("from", from.to_string().as_str()));
+ }
+ if let Some(id) = &self.id {
+ start.push_attribute(("id", id.as_str()));
+ }
+ if let Some(to) = &self.to {
+ start.push_attribute(("to", to.to_string().as_str()));
+ }
+ if let Some(version) = &self.version {
+ start.push_attribute(("version", version.to_string().as_str()));
+ }
+ if let Some(lang) = &self.lang {
+ start.push_attribute(("xml:lang", lang.as_str()));
+ }
+ start.push_attribute(("xmlns", XMLNS::Client.into()));
+ start.push_attribute(("xmlns:stream", XMLNS_STREAM));
+ start
+ }
+}
+
+impl<'e> Into<Element<'e>> for Stream {
+ fn into(self) -> Element<'e> {
+ Element {
+ event: Event::Start(self.build().to_owned()),
+ content: None,
+ }
+ }
}
-#[derive(Deserialize, PartialEq, Debug)]
+impl<'e> TryFrom<Element<'e>> for Stream {
+ type Error = JabberError;
+
+ fn try_from(value: Element<'e>) -> Result<Stream> {
+ let (mut from, mut id, mut to, mut version, mut lang, mut ns) =
+ (None, None, None, None, None, XMLNS::Client);
+ if let Event::Start(e) = value.event.as_ref() {
+ for attribute in e.attributes() {
+ let attribute = attribute?;
+ match attribute.key {
+ QName(b"from") => {
+ from = Some(str::from_utf8(&attribute.value)?.to_string().try_into()?);
+ }
+ QName(b"id") => {
+ id = Some(str::from_utf8(&attribute.value)?.to_owned());
+ }
+ QName(b"to") => {
+ to = Some(str::from_utf8(&attribute.value)?.to_string().try_into()?);
+ }
+ QName(b"version") => {
+ version = Some(str::from_utf8(&attribute.value)?.to_owned());
+ }
+ QName(b"lang") => {
+ lang = Some(str::from_utf8(&attribute.value)?.to_owned());
+ }
+ QName(b"xmlns") => {
+ ns = str::from_utf8(&attribute.value)?.try_into()?;
+ }
+ _ => {
+ println!("unknown attribute: {:?}", attribute)
+ }
+ }
+ }
+ Ok(Stream {
+ from,
+ id,
+ to,
+ version,
+ lang,
+ _ns: ns,
+ })
+ } else {
+ Err(JabberError::ParseError)
+ }
+ }
+}
+
+#[derive(PartialEq, Debug)]
pub enum StreamFeature {
- #[serde(rename = "starttls")]
StartTls,
- // TODO: other stream features
- #[serde(rename = "mechanisms")]
- Sasl(Mechanisms),
+ Sasl(Vec<String>),
Bind,
- #[serde(other)]
Unknown,
}
+
+impl<'e> TryFrom<Element<'e>> for Vec<StreamFeature> {
+ type Error = JabberError;
+
+ fn try_from(features_element: Element) -> Result<Self> {
+ let mut features = Vec::new();
+ if let Some(content) = features_element.content {
+ for feature_element in content {
+ match feature_element.event {
+ Event::Start(e) => match e.name() {
+ QName(b"starttls") => features.push(StreamFeature::StartTls),
+ QName(b"mechanisms") => {
+ let mut mechanisms = Vec::new();
+ if let Some(content) = feature_element.content {
+ for mechanism_element in content {
+ if let Some(content) = mechanism_element.content {
+ for mechanism_text in content {
+ match mechanism_text.event {
+ Event::Text(e) => mechanisms
+ .push(str::from_utf8(e.as_ref())?.to_owned()),
+ _ => {}
+ }
+ }
+ }
+ }
+ }
+ features.push(StreamFeature::Sasl(mechanisms))
+ }
+ _ => {}
+ },
+ _ => features.push(StreamFeature::Unknown),
+ }
+ }
+ }
+ Ok(features)
+ }
+}