diff --git a/src/lib.rs b/src/lib.rs index 2a6c3ab..eb3cc3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,6 +101,9 @@ pub mod component; /// XEP-0115: Entity Capabilities pub mod caps; +/// XEP-0157: Contact Addresses for XMPP Services +pub mod server_info; + /// XEP-0166: Jingle pub mod jingle; diff --git a/src/ns.rs b/src/ns.rs index 1897dbb..4f3d2d2 100644 --- a/src/ns.rs +++ b/src/ns.rs @@ -79,6 +79,9 @@ pub const COMPONENT: &str = "jabber:component:accept"; /// XEP-0115: Entity Capabilities pub const CAPS: &str = "http://jabber.org/protocol/caps"; +/// XEP-0157: Contact Addresses for XMPP Services +pub const SERVER_INFO: &str = "http://jabber.org/network/serverinfo"; + /// XEP-0166: Jingle pub const JINGLE: &str = "urn:xmpp:jingle:1"; diff --git a/src/server_info.rs b/src/server_info.rs new file mode 100644 index 0000000..cf1b75c --- /dev/null +++ b/src/server_info.rs @@ -0,0 +1,234 @@ +// Copyright (C) 2019 Maxime “pep” Buquet +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use crate::data_forms::{DataForm, DataFormType, Field, FieldType}; +use crate::ns; +use crate::util::error::Error; +use try_from::TryFrom; + +/// Structure representing a `http://jabber.org/network/serverinfo` form type. +#[derive(Debug, Clone)] +pub struct ServerInfo { + /// Abuse addresses + pub abuse: Vec, + + /// Admin addresses + pub admin: Vec, + + /// Feedback addresses + pub feedback: Vec, + + /// Sales addresses + pub sales: Vec, + + /// Security addresses + pub security: Vec, + + /// Support addresses + pub support: Vec, +} + +impl TryFrom for ServerInfo { + type Err = Error; + + fn try_from(form: DataForm) -> Result { + if form.type_ != DataFormType::Result_ { + return Err(Error::ParseError("Wrong type of form.")); + } + if form.form_type != Some(String::from(ns::SERVER_INFO)) { + return Err(Error::ParseError("Wrong FORM_TYPE for form.")); + } + let mut server_info = ServerInfo { + abuse: vec![], + admin: vec![], + feedback: vec![], + sales: vec![], + security: vec![], + support: vec![], + }; + for field in form.fields { + if field.type_ != FieldType::ListMulti { + return Err(Error::ParseError("Field is not of the required type.")); + } + if field.var == "abuse-addresses" { + server_info.abuse = field.values; + } else if field.var == "admin-addresses" { + server_info.admin = field.values; + } else if field.var == "feedback-addresses" { + server_info.feedback = field.values; + } else if field.var == "sales-addresses" { + server_info.sales = field.values; + } else if field.var == "security-addresses" { + server_info.security = field.values; + } else if field.var == "support-addresses" { + server_info.support = field.values; + } else { + return Err(Error::ParseError("Unknown form field var.")); + } + } + + Ok(server_info) + } +} + +impl From for DataForm { + fn from(server_info: ServerInfo) -> DataForm { + DataForm { + type_: DataFormType::Result_, + form_type: Some(String::from(ns::SERVER_INFO)), + title: None, + instructions: None, + fields: vec![ + Field { + var: String::from("FORM_TYPE"), + type_: FieldType::Hidden, + label: None, + required: false, + options: vec![], + values: vec![String::from(ns::SERVER_INFO)], + media: vec![], + }, + generate_address_field("abuse-addresses", server_info.abuse), + generate_address_field("admin-addresses", server_info.admin), + generate_address_field("feedback-addresses", server_info.feedback), + generate_address_field("sales-addresses", server_info.sales), + generate_address_field("security-addresses", server_info.security), + generate_address_field("support-addresses", server_info.support), + ], + } + } +} + +/// Generate `Field` for addresses +pub fn generate_address_field>(var: S, values: Vec) -> Field { + Field { + var: var.into(), + type_: FieldType::ListMulti, + label: None, + required: false, + options: vec![], + values, + media: vec![], + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::data_forms::{DataForm, DataFormType, Field, FieldType}; + + #[cfg(target_pointer_width = "32")] + #[test] + fn test_size() { + assert_size!(ServerInfo, 72); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_size() { + assert_size!(ServerInfo, 144); + } + + #[test] + fn test_simple() { + let form = DataForm { + type_: DataFormType::Result_, + form_type: Some(String::from(ns::SERVER_INFO)), + title: None, + instructions: None, + fields: vec![ + Field { + var: String::from("FORM_TYPE"), + type_: FieldType::Hidden, + label: None, + required: false, + options: vec![], + values: vec![String::from(ns::SERVER_INFO)], + media: vec![], + }, + Field { + var: String::from("abuse-addresses"), + type_: FieldType::ListMulti, + label: None, + required: false, + options: vec![], + values: vec![], + media: vec![], + }, + Field { + var: String::from("admin-addresses"), + type_: FieldType::ListMulti, + label: None, + required: false, + options: vec![], + values: vec![ + String::from("xmpp:admin@foo.bar"), + String::from("https://foo.bar/chat/"), + String::from("mailto:admin@foo.bar"), + ], + media: vec![], + }, + Field { + var: String::from("feedback-addresses"), + type_: FieldType::ListMulti, + label: None, + required: false, + options: vec![], + values: vec![], + media: vec![], + }, + Field { + var: String::from("sales-addresses"), + type_: FieldType::ListMulti, + label: None, + required: false, + options: vec![], + values: vec![], + media: vec![], + }, + Field { + var: String::from("security-addresses"), + type_: FieldType::ListMulti, + label: None, + required: false, + options: vec![], + values: vec![ + String::from("xmpp:security@foo.bar"), + String::from("mailto:security@foo.bar"), + ], + media: vec![], + }, + Field { + var: String::from("support-addresses"), + type_: FieldType::ListMulti, + label: None, + required: false, + options: vec![], + values: vec![String::from("mailto:support@foo.bar")], + media: vec![], + }, + ], + }; + + let server_info = ServerInfo { + abuse: vec![], + admin: vec![ + String::from("xmpp:admin@foo.bar"), + String::from("https://foo.bar/chat/"), + String::from("mailto:admin@foo.bar"), + ], + feedback: vec![], + sales: vec![], + security: vec![ + String::from("xmpp:security@foo.bar"), + String::from("mailto:security@foo.bar"), + ], + support: vec![String::from("mailto:support@foo.bar")], + }; + + // assert_eq!(DataForm::from(server_info), form); + // assert_eq!(ServerInfo::try_from(form), Ok(form)); + } +}