diff options
Diffstat (limited to '')
| -rw-r--r-- | src/stanza/mod.rs | 8 | ||||
| -rw-r--r-- | src/stanza/stream.rs | 169 | 
2 files changed, 135 insertions, 42 deletions
| diff --git a/src/stanza/mod.rs b/src/stanza/mod.rs index e4f080f..4f1ce48 100644 --- a/src/stanza/mod.rs +++ b/src/stanza/mod.rs @@ -1,3 +1,5 @@ +use peanuts::declaration::VersionInfo; +  pub mod bind;  pub mod iq;  pub mod message; @@ -6,8 +8,4 @@ pub mod sasl;  pub mod starttls;  pub mod stream; -use quick_xml::events::{BytesDecl, Event}; - -lazy_static! { -    pub static ref DECLARATION: Event<'static> = Event::Decl(BytesDecl::new("1.0", None, None)); -} +pub static XML_VERSION: VersionInfo = VersionInfo::One; 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,          }      }  } | 
