// Copyright (c) 2017 Emmanuel Gil Peyrot // // 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; use crate::util::error::Error; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::ns; use crate::Element; use std::collections::HashMap; use std::convert::TryFrom; /// Query for registering against a service. #[derive(Debug, Clone)] pub struct Query { /// Deprecated fixed list of possible fields to fill before the user can /// register. pub fields: HashMap, /// Whether this account is already registered. pub registered: bool, /// Whether to remove this account. pub remove: bool, /// A data form the user must fill before being allowed to register. pub form: Option, // Not yet implemented. //pub oob: Option, } impl IqGetPayload for Query {} impl IqSetPayload for Query {} impl IqResultPayload for Query {} impl TryFrom for Query { type Error = Error; fn try_from(elem: Element) -> Result { check_self!(elem, "query", REGISTER, "IBR query"); let mut query = Query { registered: false, fields: HashMap::new(), remove: false, form: None, }; for child in elem.children() { let namespace = child.ns().unwrap(); if namespace == ns::REGISTER { let name = child.name(); let fields = vec![ "address", "city", "date", "email", "first", "instructions", "key", "last", "misc", "name", "nick", "password", "phone", "state", "text", "url", "username", "zip", ]; if fields.binary_search(&name).is_ok() { query.fields.insert(name.to_owned(), child.text()); } else if name == "registered" { query.registered = true; } else if name == "remove" { query.remove = true; } else { return Err(Error::ParseError("Wrong field in ibr element.")); } } else if child.is("x", ns::DATA_FORMS) { query.form = Some(DataForm::try_from(child.clone())?); } else { return Err(Error::ParseError("Unknown child in ibr element.")); } } Ok(query) } } impl From for Element { fn from(query: Query) -> Element { Element::builder("query") .ns(ns::REGISTER) .append_all(if query.registered { Some(Element::builder("registered").ns(ns::REGISTER)) } else { None }) .append_all( query .fields .into_iter() .map(|(name, value)| Element::builder(name).ns(ns::REGISTER).append(value)) ) .append_all(if query.remove { Some(Element::builder("remove").ns(ns::REGISTER)) } else { None }) .append_all(query.form.map(Element::from)) .build() } } #[cfg(test)] mod tests { use super::*; use crate::util::compare_elements::NamespaceAwareCompare; #[cfg(target_pointer_width = "32")] #[test] fn test_size() { assert_size!(Query, 96); } #[cfg(target_pointer_width = "64")] #[test] fn test_size() { assert_size!(Query, 168); } #[test] fn test_simple() { let elem: Element = "".parse().unwrap(); Query::try_from(elem).unwrap(); } #[test] fn test_ex2() { let elem: Element = r#" Choose a username and password for use with this service. Please also provide your email address. "# .parse() .unwrap(); let query = Query::try_from(elem).unwrap(); assert_eq!(query.registered, false); assert_eq!(query.fields["instructions"], "\n Choose a username and password for use with this service.\n Please also provide your email address.\n "); assert_eq!(query.fields["username"], ""); assert_eq!(query.fields["password"], ""); assert_eq!(query.fields["email"], ""); assert_eq!(query.fields.contains_key("name"), false); // FIXME: HashMap doesn’t keep the order right. //let elem2 = query.into(); //assert_eq!(elem, elem2); } #[test] fn test_ex9() { let elem: Element = r#" Use the enclosed form to register. If your Jabber client does not support Data Forms, visit http://www.shakespeare.lit/contests.php Contest Registration Please provide the following information to sign up for our special contests! jabber:iq:register "# .parse() .unwrap(); let elem1 = elem.clone(); let query = Query::try_from(elem).unwrap(); assert_eq!(query.registered, false); assert!(!query.fields["instructions"].is_empty()); let form = query.form.clone().unwrap(); assert!(!form.instructions.unwrap().is_empty()); let elem2 = query.into(); assert!(elem1.compare_to(&elem2)); } #[test] fn test_ex10() { let elem: Element = r#" jabber:iq:register Juliet Capulet juliet@capulet.com F "# .parse() .unwrap(); let elem1 = elem.clone(); let query = Query::try_from(elem).unwrap(); assert_eq!(query.registered, false); for _ in &query.fields { panic!(); } let elem2 = query.into(); assert!(elem1.compare_to(&elem2)); } }