2017-06-25 20:03:48 +00:00
|
|
|
|
// Copyright (c) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
|
|
|
|
//
|
|
|
|
|
// 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/.
|
|
|
|
|
|
2018-12-18 14:27:30 +00:00
|
|
|
|
use crate::data_forms::DataForm;
|
2019-01-13 11:39:51 +00:00
|
|
|
|
use crate::util::error::Error;
|
2018-12-18 14:32:05 +00:00
|
|
|
|
use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
|
2018-12-18 14:27:30 +00:00
|
|
|
|
use crate::ns;
|
2019-07-24 22:20:38 +00:00
|
|
|
|
use minidom::{Element, Node};
|
2018-12-18 14:32:05 +00:00
|
|
|
|
use std::collections::HashMap;
|
2019-04-12 08:58:42 +00:00
|
|
|
|
use std::convert::TryFrom;
|
2017-06-25 20:03:48 +00:00
|
|
|
|
|
2018-08-08 17:15:25 +00:00
|
|
|
|
/// Query for registering against a service.
|
2017-06-25 20:03:48 +00:00
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Query {
|
2018-08-08 17:15:25 +00:00
|
|
|
|
/// Deprecated fixed list of possible fields to fill before the user can
|
|
|
|
|
/// register.
|
2017-06-25 20:03:48 +00:00
|
|
|
|
pub fields: HashMap<String, String>,
|
2018-08-08 17:15:25 +00:00
|
|
|
|
|
|
|
|
|
/// Whether this account is already registered.
|
2017-06-25 20:03:48 +00:00
|
|
|
|
pub registered: bool,
|
2018-08-08 17:15:25 +00:00
|
|
|
|
|
|
|
|
|
/// Whether to remove this account.
|
2017-06-25 20:03:48 +00:00
|
|
|
|
pub remove: bool,
|
2018-08-08 17:15:25 +00:00
|
|
|
|
|
|
|
|
|
/// A data form the user must fill before being allowed to register.
|
2017-06-25 20:03:48 +00:00
|
|
|
|
pub form: Option<DataForm>,
|
|
|
|
|
// Not yet implemented.
|
|
|
|
|
//pub oob: Option<Oob>,
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 13:16:15 +00:00
|
|
|
|
impl IqGetPayload for Query {}
|
|
|
|
|
impl IqSetPayload for Query {}
|
|
|
|
|
impl IqResultPayload for Query {}
|
2018-05-16 13:08:17 +00:00
|
|
|
|
|
2017-06-25 20:03:48 +00:00
|
|
|
|
impl TryFrom<Element> for Query {
|
2019-04-12 08:58:42 +00:00
|
|
|
|
type Error = Error;
|
2017-06-25 20:03:48 +00:00
|
|
|
|
|
|
|
|
|
fn try_from(elem: Element) -> Result<Query, Error> {
|
2018-05-14 14:30:28 +00:00
|
|
|
|
check_self!(elem, "query", REGISTER, "IBR query");
|
2017-06-25 20:03:48 +00:00
|
|
|
|
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();
|
2018-12-18 14:32:05 +00:00
|
|
|
|
let fields = vec![
|
|
|
|
|
"address",
|
|
|
|
|
"city",
|
|
|
|
|
"date",
|
|
|
|
|
"email",
|
|
|
|
|
"first",
|
|
|
|
|
"instructions",
|
|
|
|
|
"key",
|
|
|
|
|
"last",
|
|
|
|
|
"misc",
|
|
|
|
|
"name",
|
|
|
|
|
"nick",
|
|
|
|
|
"password",
|
|
|
|
|
"phone",
|
|
|
|
|
"state",
|
|
|
|
|
"text",
|
|
|
|
|
"url",
|
|
|
|
|
"username",
|
|
|
|
|
"zip",
|
|
|
|
|
];
|
2017-06-25 20:03:48 +00:00
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-20 19:36:13 +00:00
|
|
|
|
impl From<Query> for Element {
|
|
|
|
|
fn from(query: Query) -> Element {
|
2017-06-25 20:03:48 +00:00
|
|
|
|
Element::builder("query")
|
2018-12-18 14:32:05 +00:00
|
|
|
|
.ns(ns::REGISTER)
|
2019-07-24 22:20:38 +00:00
|
|
|
|
.append_all((if query.registered {
|
2018-12-18 14:32:05 +00:00
|
|
|
|
Some(Element::builder("registered").ns(ns::REGISTER))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
2019-07-24 22:20:38 +00:00
|
|
|
|
}).into_iter())
|
|
|
|
|
.append_all(
|
2018-12-18 14:32:05 +00:00
|
|
|
|
query
|
|
|
|
|
.fields
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(name, value)| Element::builder(name).ns(ns::REGISTER).append(value))
|
|
|
|
|
)
|
2019-07-24 22:20:38 +00:00
|
|
|
|
.append_all((if query.remove {
|
2018-12-18 14:32:05 +00:00
|
|
|
|
Some(Element::builder("remove").ns(ns::REGISTER))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
2019-07-24 22:20:38 +00:00
|
|
|
|
}).into_iter())
|
|
|
|
|
.append_all(query.form.map(Element::from).map(Node::Element).into_iter())
|
2018-12-18 14:32:05 +00:00
|
|
|
|
.build()
|
2017-06-25 20:03:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2019-01-13 11:39:51 +00:00
|
|
|
|
use crate::util::compare_elements::NamespaceAwareCompare;
|
2017-06-25 20:03:48 +00:00
|
|
|
|
|
2018-10-28 12:10:48 +00:00
|
|
|
|
#[cfg(target_pointer_width = "32")]
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_size() {
|
2019-07-30 19:30:34 +00:00
|
|
|
|
assert_size!(Query, 96);
|
2018-10-28 12:10:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_pointer_width = "64")]
|
2018-10-26 12:26:16 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_size() {
|
2019-07-30 19:30:34 +00:00
|
|
|
|
assert_size!(Query, 168);
|
2018-10-26 12:26:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-25 20:03:48 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_simple() {
|
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:register'/>".parse().unwrap();
|
|
|
|
|
Query::try_from(elem).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_ex2() {
|
|
|
|
|
let elem: Element = r#"
|
|
|
|
|
<query xmlns='jabber:iq:register'>
|
|
|
|
|
<instructions>
|
|
|
|
|
Choose a username and password for use with this service.
|
|
|
|
|
Please also provide your email address.
|
|
|
|
|
</instructions>
|
|
|
|
|
<username/>
|
|
|
|
|
<password/>
|
|
|
|
|
<email/>
|
|
|
|
|
</query>
|
2018-12-18 14:32:05 +00:00
|
|
|
|
"#
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap();
|
2017-06-25 20:03:48 +00:00
|
|
|
|
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#"
|
|
|
|
|
<query xmlns='jabber:iq:register'>
|
|
|
|
|
<instructions>
|
|
|
|
|
Use the enclosed form to register. If your Jabber client does not
|
|
|
|
|
support Data Forms, visit http://www.shakespeare.lit/contests.php
|
|
|
|
|
</instructions>
|
|
|
|
|
<x xmlns='jabber:x:data' type='form'>
|
|
|
|
|
<title>Contest Registration</title>
|
|
|
|
|
<instructions>
|
|
|
|
|
Please provide the following information
|
|
|
|
|
to sign up for our special contests!
|
|
|
|
|
</instructions>
|
|
|
|
|
<field type='hidden' var='FORM_TYPE'>
|
|
|
|
|
<value>jabber:iq:register</value>
|
|
|
|
|
</field>
|
|
|
|
|
<field label='Given Name' var='first'>
|
|
|
|
|
<required/>
|
|
|
|
|
</field>
|
|
|
|
|
<field label='Family Name' var='last'>
|
|
|
|
|
<required/>
|
|
|
|
|
</field>
|
|
|
|
|
<field label='Email Address' var='email'>
|
|
|
|
|
<required/>
|
|
|
|
|
</field>
|
|
|
|
|
<field type='list-single' label='Gender' var='x-gender'>
|
|
|
|
|
<option label='Male'><value>M</value></option>
|
|
|
|
|
<option label='Female'><value>F</value></option>
|
|
|
|
|
</field>
|
|
|
|
|
</x>
|
|
|
|
|
</query>
|
2018-12-18 14:32:05 +00:00
|
|
|
|
"#
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap();
|
2017-06-25 20:03:48 +00:00
|
|
|
|
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();
|
2017-08-18 23:04:18 +00:00
|
|
|
|
assert!(elem1.compare_to(&elem2));
|
2017-06-25 20:03:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_ex10() {
|
|
|
|
|
let elem: Element = r#"
|
|
|
|
|
<query xmlns='jabber:iq:register'>
|
|
|
|
|
<x xmlns='jabber:x:data' type='submit'>
|
|
|
|
|
<field type='hidden' var='FORM_TYPE'>
|
|
|
|
|
<value>jabber:iq:register</value>
|
|
|
|
|
</field>
|
|
|
|
|
<field label='Given Name' var='first'>
|
|
|
|
|
<value>Juliet</value>
|
|
|
|
|
</field>
|
|
|
|
|
<field label='Family Name' var='last'>
|
|
|
|
|
<value>Capulet</value>
|
|
|
|
|
</field>
|
|
|
|
|
<field label='Email Address' var='email'>
|
|
|
|
|
<value>juliet@capulet.com</value>
|
|
|
|
|
</field>
|
|
|
|
|
<field type='list-single' label='Gender' var='x-gender'>
|
|
|
|
|
<value>F</value>
|
|
|
|
|
</field>
|
|
|
|
|
</x>
|
|
|
|
|
</query>
|
2018-12-18 14:32:05 +00:00
|
|
|
|
"#
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap();
|
2017-06-25 20:03:48 +00:00
|
|
|
|
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();
|
2017-08-18 23:04:18 +00:00
|
|
|
|
assert!(elem1.compare_to(&elem2));
|
2017-06-25 20:03:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|