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 ;
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 ;
2024-07-24 18:28:22 +00:00
use minidom ::Element ;
2018-12-18 14:32:05 +00:00
use std ::collections ::HashMap ;
2024-06-21 14:27:43 +00:00
use xso ::error ::{ Error , FromElementError } ;
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 {
2024-06-21 14:27:43 +00:00
type Error = FromElementError ;
2017-06-25 20:03:48 +00:00
2024-06-21 14:27:43 +00:00
fn try_from ( elem : Element ) -> Result < Query , FromElementError > {
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 ( ) {
2020-03-28 12:07:26 +00:00
let namespace = child . ns ( ) ;
2017-06-25 20:03:48 +00:00
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 {
2024-06-21 14:27:43 +00:00
return Err ( Error ::Other ( " Wrong field in ibr element. " ) . into ( ) ) ;
2017-06-25 20:03:48 +00:00
}
} else if child . is ( " x " , ns ::DATA_FORMS ) {
query . form = Some ( DataForm ::try_from ( child . clone ( ) ) ? ) ;
} else {
2024-06-21 14:27:43 +00:00
return Err ( Error ::Other ( " Unknown child in ibr element. " ) . into ( ) ) ;
2017-06-25 20:03:48 +00:00
}
}
Ok ( query )
}
}
2017-07-20 19:36:13 +00:00
impl From < Query > for Element {
fn from ( query : Query ) -> Element {
2020-03-28 12:07:26 +00:00
Element ::builder ( " query " , ns ::REGISTER )
2019-09-06 14:03:58 +00:00
. append_all ( if query . registered {
2020-03-28 12:07:26 +00:00
Some ( Element ::builder ( " registered " , ns ::REGISTER ) )
2018-12-18 14:32:05 +00:00
} else {
None
2019-09-06 14:03:58 +00:00
} )
2019-07-24 22:20:38 +00:00
. append_all (
2018-12-18 14:32:05 +00:00
query
. fields
. into_iter ( )
2020-03-28 12:07:26 +00:00
. map ( | ( name , value ) | Element ::builder ( name , ns ::REGISTER ) . append ( value ) ) ,
2018-12-18 14:32:05 +00:00
)
2019-09-06 14:03:58 +00:00
. append_all ( if query . remove {
2020-03-28 12:07:26 +00:00
Some ( Element ::builder ( " remove " , ns ::REGISTER ) )
2018-12-18 14:32:05 +00:00
} else {
None
2019-09-06 14:03:58 +00:00
} )
. append_all ( query . form . map ( Element ::from ) )
2018-12-18 14:32:05 +00:00
. build ( )
2017-06-25 20:03:48 +00:00
}
}
#[ cfg(test) ]
mod tests {
use super ::* ;
2018-10-28 12:10:48 +00:00
#[ cfg(target_pointer_width = " 32 " ) ]
#[ test ]
fn test_size ( ) {
2020-10-29 17:39:22 +00:00
assert_size! ( Query , 88 ) ;
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 ( ) {
2020-10-29 17:39:48 +00:00
assert_size! ( Query , 160 ) ;
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 ( ) {
2022-03-22 22:29:25 +00:00
let elem : Element = r #" <query xmlns='jabber:iq:register'>
2017-06-25 20:03:48 +00:00
< 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 ( ) {
2019-12-07 19:37:33 +00:00
let elem : Element = " <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 ( ) ;
2019-11-29 13:33:17 +00:00
assert_eq! ( elem1 , elem2 ) ;
2017-06-25 20:03:48 +00:00
}
#[ test ]
fn test_ex10 ( ) {
2019-12-07 19:37:33 +00:00
let elem : Element = " <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 ( ) ;
2019-11-29 13:33:17 +00:00
assert_eq! ( elem1 , elem2 ) ;
2017-06-25 20:03:48 +00:00
}
}