// 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 xso::{AsXml, FromXml}; use crate::data_forms::DataForm; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::ns; /// Entity requests registration fields from host. #[derive(FromXml, AsXml, Debug, Clone)] #[xml(namespace = ns::REGISTER, name = "query")] pub struct FieldsQuery; impl IqGetPayload for FieldsQuery {} /// Entity requests cancellation of existing registration. #[derive(FromXml, AsXml, Debug, Clone)] #[xml(namespace = ns::REGISTER, name = "query")] pub struct RemoveQuery { /// Whether to remove that registration. // TODO: we should be able to remove that flag and make this type a zero-sized type. #[xml(flag)] pub remove: bool, } impl IqSetPayload for RemoveQuery {} /// Query for registering against a service, the legacy way. #[derive(FromXml, AsXml, Debug, Clone)] #[xml(namespace = ns::REGISTER, name = "query")] pub struct LegacyQuery { /// Whether this account is already registered #[xml(flag)] pub registered: bool, /// Instructions to be presented to entities implementing this legacy element. #[xml(extract(default, fields(text(type_ = String))))] pub instructions: Option, /// Account name associated with the user #[xml(extract(default, fields(text(type_ = String))))] pub username: Option, /// Familiar name of the user #[xml(extract(default, fields(text(type_ = String))))] pub nick: Option, /// Password or secret for the user #[xml(extract(default, fields(text(type_ = String))))] pub password: Option, /// Full name of the user #[xml(extract(default, fields(text(type_ = String))))] pub name: Option, /// Given name of the user #[xml(extract(default, fields(text(type_ = String))))] pub first: Option, /// Family name of the user #[xml(extract(default, fields(text(type_ = String))))] pub last: Option, /// Email address of the user #[xml(extract(default, fields(text(type_ = String))))] pub email: Option, /// Street portion of a physical or mailing address #[xml(extract(default, fields(text(type_ = String))))] pub address: Option, /// Locality portion of a physical or mailing address #[xml(extract(default, fields(text(type_ = String))))] pub city: Option, /// Region portion of a physical or mailing address #[xml(extract(default, fields(text(type_ = String))))] pub state: Option, /// Postal code portion of a physical or mailing address #[xml(extract(default, fields(text(type_ = String))))] pub zip: Option, /// Telephone number of the user #[xml(extract(default, fields(text(type_ = String))))] pub phone: Option, /// URL to web page describing the user #[xml(extract(default, fields(text(type_ = String))))] pub url: Option, /// Some date (e.g., birth date, hire date, sign-up date) #[xml(extract(default, fields(text(type_ = String))))] pub date: Option, /// Free-form text field (obsolete) #[xml(extract(default, fields(text(type_ = String))))] pub misc: Option, /// Free-form text field (obsolete) #[xml(extract(default, fields(text(type_ = String))))] pub text: Option, /// Session key for transaction (obsolete) #[xml(extract(default, fields(text(type_ = String))))] pub key: Option, } impl IqSetPayload for LegacyQuery {} impl IqResultPayload for LegacyQuery {} /// Query for registering against a service. #[derive(FromXml, AsXml, Debug, Clone)] #[xml(namespace = ns::REGISTER, name = "query")] pub struct FormQuery { /// Legacy instructions fallback for entities which don’t understand the form. #[xml(extract(default, fields(text(type_ = String))))] pub instructions: Option, /// A data form the user must fill before being allowed to register. #[xml(child)] pub form: DataForm, // Not yet implemented. //pub oob: Option, } impl IqSetPayload for FormQuery {} impl IqResultPayload for FormQuery {} #[cfg(test)] mod tests { use super::*; use crate::data_forms::DataFormType; use minidom::Element; #[cfg(target_pointer_width = "32")] #[test] fn test_size() { assert_size!(RemoveQuery, 1); assert_size!(LegacyQuery, 220); assert_size!(FormQuery, 52); } #[cfg(target_pointer_width = "64")] #[test] fn test_size() { assert_size!(RemoveQuery, 1); assert_size!(LegacyQuery, 440); assert_size!(FormQuery, 104); } #[test] fn test_simple() { let elem: Element = "".parse().unwrap(); FieldsQuery::try_from(elem).unwrap(); let elem: Element = "" .parse() .unwrap(); let query = RemoveQuery::try_from(elem).unwrap(); assert_eq!(query.remove, true); let elem: Element = "".parse().unwrap(); let query = LegacyQuery::try_from(elem).unwrap(); assert_eq!(query.first, None); let elem: Element = "" .parse() .unwrap(); let query = FormQuery::try_from(elem).unwrap(); assert!(query.instructions.is_none()); assert!(query.form.fields.is_empty()); } #[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 = LegacyQuery::try_from(elem).unwrap(); assert_eq!(query.registered, false); assert_eq!(query.instructions.unwrap(), "\n Choose a username and password for use with this service.\n Please also provide your email address.\n "); assert_eq!(query.username.unwrap(), ""); assert_eq!(query.password.unwrap(), ""); assert_eq!(query.email.unwrap(), ""); assert_eq!(query.name, None); // FIXME: HashMap doesn’t keep the order right. //let elem2 = query.into(); //assert_eq!(elem, elem2); } #[test] fn test_ex9() { let elem: Element = "Use the enclosed form to register. If your Jabber client does not support Data Forms, visit http://www.shakespeare.lit/contests.phpContest RegistrationPlease provide the following information to sign up for our special contests!jabber:iq:register" .parse() .unwrap(); let elem1 = elem.clone(); let query = FormQuery::try_from(elem).unwrap(); assert!(query.instructions.is_some()); let form = query.form.clone(); assert_eq!( form.instructions.unwrap(), "Please provide the following information to sign up for our special contests!" ); assert_eq!(form.type_, DataFormType::Form); let elem2 = query.into(); assert_eq!(elem1, elem2); } #[test] fn test_ex10() { let elem: Element = "jabber:iq:registerJulietCapuletjuliet@capulet.comF" .parse() .unwrap(); let elem1 = elem.clone(); let query = FormQuery::try_from(elem).unwrap(); let elem2 = query.into(); assert_eq!(elem1, elem2); } }