xmpp-rs/parsers/src/ibr.rs
Link Mauve d0062d9931 xmpp-parsers: Split ibr::Query into multiple structs
This introduces FieldsQuery, RemoveQuery, LegacyQuery and FormsQuery,
making this module reflect more accurately how it gets used on XMPP.
2026-01-09 00:49:17 +01:00

235 lines
8.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 xso::{AsXml, FromXml};
use crate::data_forms::DataForm;
use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
use crate::ns;
/// Entity requests registration fields from host.
#[derive(FromXml, AsXml, Debug, Clone)]
#[xml(namespace = ns::REGISTER, name = "query")]
pub struct FieldsQuery;
impl IqGetPayload for FieldsQuery {}
/// Entity requests cancellation of existing registration.
#[derive(FromXml, AsXml, Debug, Clone)]
#[xml(namespace = ns::REGISTER, name = "query")]
pub struct RemoveQuery {
/// Whether to remove that registration.
// TODO: we should be able to remove that flag and make this type a zero-sized type.
#[xml(flag)]
pub remove: bool,
}
impl IqSetPayload for RemoveQuery {}
/// Query for registering against a service, the legacy way.
#[derive(FromXml, AsXml, Debug, Clone)]
#[xml(namespace = ns::REGISTER, name = "query")]
pub struct LegacyQuery {
/// Whether this account is already registered
#[xml(flag)]
pub registered: bool,
/// Instructions to be presented to entities implementing this legacy element.
#[xml(extract(default, fields(text(type_ = String))))]
pub instructions: Option<String>,
/// Account name associated with the user
#[xml(extract(default, fields(text(type_ = String))))]
pub username: Option<String>,
/// Familiar name of the user
#[xml(extract(default, fields(text(type_ = String))))]
pub nick: Option<String>,
/// Password or secret for the user
#[xml(extract(default, fields(text(type_ = String))))]
pub password: Option<String>,
/// Full name of the user
#[xml(extract(default, fields(text(type_ = String))))]
pub name: Option<String>,
/// Given name of the user
#[xml(extract(default, fields(text(type_ = String))))]
pub first: Option<String>,
/// Family name of the user
#[xml(extract(default, fields(text(type_ = String))))]
pub last: Option<String>,
/// Email address of the user
#[xml(extract(default, fields(text(type_ = String))))]
pub email: Option<String>,
/// Street portion of a physical or mailing address
#[xml(extract(default, fields(text(type_ = String))))]
pub address: Option<String>,
/// Locality portion of a physical or mailing address
#[xml(extract(default, fields(text(type_ = String))))]
pub city: Option<String>,
/// Region portion of a physical or mailing address
#[xml(extract(default, fields(text(type_ = String))))]
pub state: Option<String>,
/// Postal code portion of a physical or mailing address
#[xml(extract(default, fields(text(type_ = String))))]
pub zip: Option<String>,
/// Telephone number of the user
#[xml(extract(default, fields(text(type_ = String))))]
pub phone: Option<String>,
/// URL to web page describing the user
#[xml(extract(default, fields(text(type_ = String))))]
pub url: Option<String>,
/// Some date (e.g., birth date, hire date, sign-up date)
#[xml(extract(default, fields(text(type_ = String))))]
pub date: Option<String>,
/// Free-form text field (obsolete)
#[xml(extract(default, fields(text(type_ = String))))]
pub misc: Option<String>,
/// Free-form text field (obsolete)
#[xml(extract(default, fields(text(type_ = String))))]
pub text: Option<String>,
/// Session key for transaction (obsolete)
#[xml(extract(default, fields(text(type_ = String))))]
pub key: Option<String>,
}
impl IqSetPayload for LegacyQuery {}
impl IqResultPayload for LegacyQuery {}
/// Query for registering against a service.
#[derive(FromXml, AsXml, Debug, Clone)]
#[xml(namespace = ns::REGISTER, name = "query")]
pub struct FormQuery {
/// Legacy instructions fallback for entities which dont understand the form.
#[xml(extract(default, fields(text(type_ = String))))]
pub instructions: Option<String>,
/// A data form the user must fill before being allowed to register.
#[xml(child)]
pub form: DataForm,
// Not yet implemented.
//pub oob: Option<Oob>,
}
impl IqSetPayload for FormQuery {}
impl IqResultPayload for FormQuery {}
#[cfg(test)]
mod tests {
use super::*;
use crate::data_forms::DataFormType;
use minidom::Element;
#[cfg(target_pointer_width = "32")]
#[test]
fn test_size() {
assert_size!(RemoveQuery, 1);
assert_size!(LegacyQuery, 220);
assert_size!(FormQuery, 52);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(RemoveQuery, 1);
assert_size!(LegacyQuery, 440);
assert_size!(FormQuery, 104);
}
#[test]
fn test_simple() {
let elem: Element = "<query xmlns='jabber:iq:register'/>".parse().unwrap();
FieldsQuery::try_from(elem).unwrap();
let elem: Element = "<query xmlns='jabber:iq:register'><remove/></query>"
.parse()
.unwrap();
let query = RemoveQuery::try_from(elem).unwrap();
assert_eq!(query.remove, true);
let elem: Element = "<query xmlns='jabber:iq:register'/>".parse().unwrap();
let query = LegacyQuery::try_from(elem).unwrap();
assert_eq!(query.first, None);
let elem: Element =
"<query xmlns='jabber:iq:register'><x xmlns='jabber:x:data' type='submit'/></query>"
.parse()
.unwrap();
let query = FormQuery::try_from(elem).unwrap();
assert!(query.instructions.is_none());
assert!(query.form.fields.is_empty());
}
#[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 = LegacyQuery::try_from(elem).unwrap();
assert_eq!(query.registered, false);
assert_eq!(query.instructions.unwrap(), "\n Choose a username and password for use with this service.\n Please also provide your email address.\n ");
assert_eq!(query.username.unwrap(), "");
assert_eq!(query.password.unwrap(), "");
assert_eq!(query.email.unwrap(), "");
assert_eq!(query.name, None);
// FIXME: HashMap doesnt keep the order right.
//let elem2 = query.into();
//assert_eq!(elem, elem2);
}
#[test]
fn test_ex9() {
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>"
.parse()
.unwrap();
let elem1 = elem.clone();
let query = FormQuery::try_from(elem).unwrap();
assert!(query.instructions.is_some());
let form = query.form.clone();
assert_eq!(
form.instructions.unwrap(),
"Please provide the following information to sign up for our special contests!"
);
assert_eq!(form.type_, DataFormType::Form);
let elem2 = query.into();
assert_eq!(elem1, elem2);
}
#[test]
fn test_ex10() {
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>"
.parse()
.unwrap();
let elem1 = elem.clone();
let query = FormQuery::try_from(elem).unwrap();
let elem2 = query.into();
assert_eq!(elem1, elem2);
}
}