XEP-0157: Contact Addresses for XMPP Services.

Maxime “pep” Buquet created

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>

Change summary

src/lib.rs         |   3 
src/ns.rs          |   3 
src/server_info.rs | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 240 insertions(+)

Detailed changes

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;
 

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";
 

src/server_info.rs 🔗

@@ -0,0 +1,234 @@
+// Copyright (C) 2019 Maxime “pep” Buquet <pep@bouah.net>
+// 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<String>,
+
+    /// Admin addresses
+    pub admin: Vec<String>,
+
+    /// Feedback addresses
+    pub feedback: Vec<String>,
+
+    /// Sales addresses
+    pub sales: Vec<String>,
+
+    /// Security addresses
+    pub security: Vec<String>,
+
+    /// Support addresses
+    pub support: Vec<String>,
+}
+
+impl TryFrom<DataForm> for ServerInfo {
+    type Err = Error;
+
+    fn try_from(form: DataForm) -> Result<ServerInfo, Error> {
+        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<ServerInfo> 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<S: Into<String>>(var: S, values: Vec<String>) -> 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));
+    }
+}