Add an IBR parser.
This commit is contained in:
parent
a48565e171
commit
f428ee070d
3 changed files with 207 additions and 0 deletions
201
src/ibr.rs
Normal file
201
src/ibr.rs
Normal file
|
@ -0,0 +1,201 @@
|
|||
// 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 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>
|
||||
"#.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);
|
||||
}
|
||||
}
|
|
@ -144,6 +144,9 @@ pub mod rsm;
|
|||
/// XEP-0060: Publish-Subscribe
|
||||
pub mod pubsub;
|
||||
|
||||
/// XEP-0077: In-Band Registration
|
||||
pub mod ibr;
|
||||
|
||||
/// XEP-0085: Chat State Notifications
|
||||
pub mod chatstates;
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@ pub const PUBSUB_EVENT: &str = "http://jabber.org/protocol/pubsub#event";
|
|||
/// XEP-0060: Publish-Subscribe
|
||||
pub const PUBSUB_OWNER: &str = "http://jabber.org/protocol/pubsub#owner";
|
||||
|
||||
/// XEP-0077: In-Band Registration
|
||||
pub const REGISTER: &str = "jabber:iq:register";
|
||||
|
||||
/// XEP-0085: Chat State Notifications
|
||||
pub const CHATSTATES: &str = "http://jabber.org/protocol/chatstates";
|
||||
|
||||
|
|
Loading…
Reference in a new issue