xmpp-rs/src/ibr.rs
Emmanuel Gil Peyrot f428ee070d Add an IBR parser.
2017-06-25 21:03:48 +01:00

201 lines
6.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 std::collections::HashMap;
use std::convert::TryFrom;
use minidom::{Element, IntoElements, ElementEmitter};
use error::Error;
use data_forms::DataForm;
use ns;
#[derive(Debug, Clone)]
pub struct Query {
pub fields: HashMap<String, String>,
pub registered: bool,
pub remove: bool,
pub form: Option<DataForm>,
// Not yet implemented.
//pub oob: Option<Oob>,
}
impl TryFrom<Element> for Query {
type Error = Error;
fn try_from(elem: Element) -> Result<Query, Error> {
if !elem.is("query", ns::REGISTER) {
return Err(Error::ParseError("This is not an ibr element."));
}
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 Into<Element> for Query {
fn into(self) -> Element {
Element::builder("query")
.ns(ns::REGISTER)
.append(if self.registered { Some(Element::builder("registered").ns(ns::REGISTER)) } else { None })
.append(self.fields.iter().map(|(name, value)| {
Element::builder(name.clone()).ns(ns::REGISTER).append(value.clone())
}).collect::<Vec<_>>())
.append(if self.remove { Some(Element::builder("remove").ns(ns::REGISTER)) } else { None })
.append(self.form)
.build()
}
}
impl IntoElements for Query {
fn into_elements(self, emitter: &mut ElementEmitter) {
emitter.append_child(self.into());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[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>
"#.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 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>
"#.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());
assert!(form.fields.binary_search_by(|field| field.var.cmp(&String::from("first"))).is_ok());
assert!(form.fields.binary_search_by(|field| field.var.cmp(&String::from("x-gender"))).is_ok());
assert!(form.fields.binary_search_by(|field| field.var.cmp(&String::from("coucou"))).is_err());
let elem2 = query.into();
assert_eq!(elem1, elem2);
}
#[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>
"#.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_eq!(elem1, elem2);
}
}