xmpp-rs/src/ibr.rs

256 lines
7.6 KiB
Rust
Raw Normal View History

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/.
use crate::data_forms::DataForm;
use crate::util::error::Error;
2018-12-18 14:32:05 +00:00
use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
use crate::ns;
2018-12-18 14:32:05 +00:00
use minidom::Element;
use std::collections::HashMap;
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 {}
2017-06-25 20:03:48 +00:00
impl TryFrom<Element> for Query {
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)
}
}
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)
.append(if query.registered {
Some(Element::builder("registered").ns(ns::REGISTER))
} else {
None
})
.append(
query
.fields
.into_iter()
.map(|(name, value)| Element::builder(name).ns(ns::REGISTER).append(value))
.collect::<Vec<_>>(),
)
.append(if query.remove {
Some(Element::builder("remove").ns(ns::REGISTER))
} else {
None
})
.append(query.form)
.build()
2017-06-25 20:03:48 +00:00
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::compare_elements::NamespaceAwareCompare;
2017-06-25 20:03:48 +00:00
// TODO: These size tests are sensible to the size of HashMap, which recently grew of two
// pointers and is thus different on stable and nightly. Lets wait for this issue before
// attempting a fix:
// https://github.com/rust-lang/hashbrown/issues/69
2018-10-28 12:10:48 +00:00
#[cfg(target_pointer_width = "32")]
#[test]
#[ignore]
2018-10-28 12:10:48 +00:00
fn test_size() {
assert_size!(Query, 88);
}
#[cfg(target_pointer_width = "64")]
#[test]
#[ignore]
fn test_size() {
assert_size!(Query, 152);
}
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 doesnt 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();
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();
assert!(elem1.compare_to(&elem2));
2017-06-25 20:03:48 +00:00
}
}