diff options
Diffstat (limited to 'src/stanza/stream.rs')
-rw-r--r-- | src/stanza/stream.rs | 169 |
1 files changed, 132 insertions, 37 deletions
diff --git a/src/stanza/stream.rs b/src/stanza/stream.rs index 9a21373..ac4badc 100644 --- a/src/stanza/stream.rs +++ b/src/stanza/stream.rs @@ -1,37 +1,141 @@ -use serde::Serialize; +use std::collections::{HashMap, HashSet}; -use crate::JID; +use peanuts::element::{Content, FromElement, IntoElement, NamespaceDeclaration}; +use peanuts::XML_NS; +use peanuts::{element::Name, Element}; -pub static XMLNS: &str = "http://etherx.jabber.org/streams"; -pub static XMLNS_CLIENT: &str = "jabber:client"; +use crate::{Error, JID}; + +pub const XMLNS: &str = "http://etherx.jabber.org/streams"; +pub const XMLNS_CLIENT: &str = "jabber:client"; // MUST be qualified by stream namespace -#[derive(Serialize)] -pub struct Stream<'s> { - #[serde(rename = "@from")] - from: Option<&'s JID>, - #[serde(rename = "@to")] - to: Option<&'s JID>, - #[serde(rename = "@id")] - id: Option<&'s str>, - #[serde(rename = "@version")] - version: Option<&'s str>, +// #[derive(XmlSerialize, XmlDeserialize)] +// #[peanuts(xmlns = XMLNS)] +pub struct Stream { + pub from: Option<JID>, + to: Option<JID>, + id: Option<String>, + version: Option<String>, // TODO: lang enum - #[serde(rename = "@lang")] - lang: Option<&'s str>, - #[serde(rename = "@xmlns")] - xmlns: &'s str, - #[serde(rename = "@xmlns:stream")] - xmlns_stream: &'s str, + lang: Option<String>, + // #[peanuts(content)] + // content: Message, +} + +impl FromElement for Stream { + fn from_element(element: Element) -> peanuts::Result<Self> { + let Name { + namespace, + local_name, + } = element.name; + if namespace.as_deref() == Some(XMLNS) && &local_name == "stream" { + let (mut from, mut to, mut id, mut version, mut lang) = (None, None, None, None, None); + for (name, value) in element.attributes { + match (name.namespace.as_deref(), name.local_name.as_str()) { + (None, "from") => from = Some(value.try_into()?), + (None, "to") => to = Some(value.try_into()?), + (None, "id") => id = Some(value), + (None, "version") => version = Some(value), + (Some(XML_NS), "lang") => lang = Some(value), + _ => return Err(peanuts::Error::UnexpectedAttribute(name)), + } + } + return Ok(Stream { + from, + to, + id, + version, + lang, + }); + } else { + return Err(peanuts::Error::IncorrectName(Name { + namespace, + local_name, + })); + } + } +} + +impl IntoElement for Stream { + fn into_element(&self) -> Element { + let mut namespace_declarations = HashSet::new(); + namespace_declarations.insert(NamespaceDeclaration { + prefix: Some("stream".to_string()), + namespace: XMLNS.to_string(), + }); + namespace_declarations.insert(NamespaceDeclaration { + prefix: None, + // TODO: don't default to client + 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: "version".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(), + } + } } -impl<'s> Stream<'s> { +impl<'s> Stream { pub fn new( - from: Option<&'s JID>, - to: Option<&'s JID>, - id: Option<&'s str>, - version: Option<&'s str>, - lang: Option<&'s str>, + from: Option<JID>, + to: Option<JID>, + id: Option<String>, + version: Option<String>, + lang: Option<String>, ) -> Self { Self { from, @@ -39,27 +143,18 @@ impl<'s> Stream<'s> { id, version, lang, - xmlns: XMLNS_CLIENT, - xmlns_stream: XMLNS, } } /// For initial stream headers, the initiating entity SHOULD include the 'xml:lang' attribute. /// For privacy, it is better to not set `from` when sending a client stanza over an unencrypted connection. - pub fn new_client( - from: Option<&'s JID>, - to: &'s JID, - id: Option<&'s str>, - lang: &'s str, - ) -> Self { + pub fn new_client(from: Option<JID>, to: JID, id: Option<String>, lang: String) -> Self { Self { from, to: Some(to), id, - version: Some("1.0"), + version: Some("1.0".to_string()), lang: Some(lang), - xmlns: XMLNS_CLIENT, - xmlns_stream: XMLNS, } } } |