From 20a94117d3ce9732e985aafebe3acdf04889af45 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Sat, 31 Oct 2020 13:27:58 +0100 Subject: [PATCH] Handle extensions element in bookmarks2 --- xmpp-parsers/src/bookmarks2.rs | 118 +++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 21 deletions(-) diff --git a/xmpp-parsers/src/bookmarks2.rs b/xmpp-parsers/src/bookmarks2.rs index ae81974d38e7ed79cd050ab8e9951480aa2a1e22..4a850b07f4682ba3b88d880102abb11ac3283624 100644 --- a/xmpp-parsers/src/bookmarks2.rs +++ b/xmpp-parsers/src/bookmarks2.rs @@ -3,6 +3,10 @@ // 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::ns; +use crate::util::error::Error; +use crate::Element; +use std::convert::TryFrom; generate_attribute!( /// Whether a conference bookmark should be joined automatically. @@ -11,24 +15,24 @@ generate_attribute!( bool ); -generate_element!( - /// A conference bookmark. - Conference, "conference", BOOKMARKS2, - attributes: [ - /// Whether a conference bookmark should be joined automatically. - autojoin: Default = "autojoin", - - /// A user-defined name for this conference. - name: Option = "name", - ], - children: [ - /// The nick the user will use to join this conference. - nick: Option = ("nick", BOOKMARKS2) => String, - - /// The password required to join this conference. - password: Option = ("password", BOOKMARKS2) => String - ] -); +/// A conference bookmark. +#[derive(Debug, Clone)] +pub struct Conference { + /// Whether a conference bookmark should be joined automatically. + pub autojoin: Autojoin, + + /// A user-defined name for this conference. + pub name: Option, + + /// The nick the user will use to join this conference. + pub nick: Option, + + /// The password required to join this conference. + pub password: Option, + + /// Extensions elements. + pub extensions: Vec, +} impl Conference { /// Create a new conference. @@ -38,7 +42,74 @@ impl Conference { name: None, nick: None, password: None, + extensions: vec![], + } + } +} + +impl TryFrom for Conference { + type Error = Error; + + fn try_from(root: Element) -> Result { + check_self!(root, "conference", BOOKMARKS2, "Conference"); + check_no_unknown_attributes!(root, "Conference", ["autojoin", "name"]); + + let mut conference = Conference { + autojoin: get_attr!(root, "autojoin", Default), + name: get_attr!(root, "name", Option), + nick: None, + password: None, + extensions: vec![], + }; + + for child in root.children().cloned() { + if child.is("extensions", ns::BOOKMARKS2) { + if conference.extensions.len() > 0 { + return Err(Error::ParseError( + "Conference must not have more than one extensions element.", + )); + } + conference.extensions.extend(child.children().cloned()); + } else if child.is("nick", ns::BOOKMARKS2) { + if conference.nick.is_some() { + return Err(Error::ParseError( + "Conference must not have more than one nick.", + )); + } + check_no_children!(child, "nick"); + conference.nick = Some(child.text()); + } else if child.is("password", ns::BOOKMARKS2) { + if conference.password.is_some() { + return Err(Error::ParseError( + "Conference must not have more than one password.", + )); + } + check_no_children!(child, "password"); + conference.password = Some(child.text()); + } } + + Ok(conference) + } +} + +impl From for Element { + fn from(conference: Conference) -> Element { + Element::builder("conference", ns::BOOKMARKS2) + .attr("autojoin", conference.autojoin) + .attr("name", conference.name) + .append_all( + conference + .nick + .map(|nick| Element::builder("nick", ns::BOOKMARKS2).append(nick)), + ) + .append_all( + conference + .password + .map(|password| Element::builder("password", ns::BOOKMARKS2).append(password)), + ) + .append_all(conference.extensions) + .build() } } @@ -52,13 +123,13 @@ mod tests { #[cfg(target_pointer_width = "32")] #[test] fn test_size() { - assert_size!(Conference, 40); + assert_size!(Conference, 52); } #[cfg(target_pointer_width = "64")] #[test] fn test_size() { - assert_size!(Conference, 80); + assert_size!(Conference, 104); } #[test] @@ -79,12 +150,17 @@ mod tests { #[test] fn complete() { - let elem: Element = "Coucousecret".parse().unwrap(); + let elem: Element = "Coucousecret".parse().unwrap(); let conference = Conference::try_from(elem).unwrap(); assert_eq!(conference.autojoin, Autojoin::True); assert_eq!(conference.name, Some(String::from("Test MUC"))); assert_eq!(conference.clone().nick.unwrap(), "Coucou"); assert_eq!(conference.clone().password.unwrap(), "secret"); + assert_eq!(conference.clone().extensions.len(), 1); + assert_eq!( + conference.clone().extensions[0], + Element::builder("test", "urn:xmpp:unknown").build() + ); } #[test]