From 74f67b958557164a2147d8e890f1fe27fe80cb5d Mon Sep 17 00:00:00 2001 From: Link Mauve Date: Mon, 19 May 2025 20:01:02 +0200 Subject: [PATCH] xmpp-parsers: Port Jingle MI to use the derive macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only missing check is that #[xml(element)] doesn’t support filtering on elements with a specific name yet. skip-changelog: This isn’t a user-visible change. --- parsers/src/jingle_message.rs | 90 +++++++---------------------------- 1 file changed, 18 insertions(+), 72 deletions(-) diff --git a/parsers/src/jingle_message.rs b/parsers/src/jingle_message.rs index fb3c81e3d3b1b2f2ad9036e29729425446908899..2a3f744095420d5f473166515d2fa6cba29a44a3 100644 --- a/parsers/src/jingle_message.rs +++ b/parsers/src/jingle_message.rs @@ -4,107 +4,51 @@ // 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::jingle::SessionId; use crate::ns; use minidom::Element; -use xso::error::{Error, FromElementError}; /// Defines a protocol for broadcasting Jingle requests to all of the clients /// of a user. -#[derive(Debug, Clone)] +#[derive(FromXml, AsXml, Debug, Clone)] +#[xml(namespace = ns::JINGLE_MESSAGE, exhaustive)] pub enum JingleMI { /// Indicates we want to start a Jingle session. + #[xml(name = "propose")] Propose { /// The generated session identifier, must be unique between two users. + #[xml(attribute = "id")] sid: SessionId, /// The application description of the proposed session. // TODO: Use a more specialised type here. + #[xml(element)] description: Element, }, /// Cancels a previously proposed session. - Retract(SessionId), + #[xml(name = "retract")] + Retract(#[xml(attribute = "id")] SessionId), /// Accepts a session proposed by the other party. - Accept(SessionId), + #[xml(name = "accept")] + Accept(#[xml(attribute = "id")] SessionId), /// Proceed with a previously proposed session. - Proceed(SessionId), + #[xml(name = "proceed")] + Proceed(#[xml(attribute = "id")] SessionId), /// Rejects a session proposed by the other party. - Reject(SessionId), -} - -fn get_sid(elem: Element) -> Result { - check_no_unknown_attributes!(elem, "Jingle message", ["id"]); - Ok(SessionId(get_attr!(elem, "id", Required))) -} - -fn check_empty_and_get_sid(elem: Element) -> Result { - check_no_children!(elem, "Jingle message"); - get_sid(elem) -} - -impl TryFrom for JingleMI { - type Error = FromElementError; - - fn try_from(elem: Element) -> Result { - if !elem.has_ns(ns::JINGLE_MESSAGE) { - return Err(Error::Other("This is not a Jingle message element.").into()); - } - Ok(match elem.name() { - "propose" => { - let mut description = None; - for child in elem.children() { - if child.name() != "description" { - return Err(Error::Other("Unknown child in propose element.").into()); - } - if description.is_some() { - return Err(Error::Other("Too many children in propose element.").into()); - } - description = Some(child.clone()); - } - JingleMI::Propose { - sid: get_sid(elem)?, - description: description.ok_or(Error::Other( - "Propose element doesn’t contain a description.", - ))?, - } - } - "retract" => JingleMI::Retract(check_empty_and_get_sid(elem)?), - "accept" => JingleMI::Accept(check_empty_and_get_sid(elem)?), - "proceed" => JingleMI::Proceed(check_empty_and_get_sid(elem)?), - "reject" => JingleMI::Reject(check_empty_and_get_sid(elem)?), - _ => return Err(Error::Other("This is not a Jingle message element.").into()), - }) - } -} - -impl From for Element { - fn from(jingle_mi: JingleMI) -> Element { - match jingle_mi { - JingleMI::Propose { sid, description } => { - Element::builder("propose", ns::JINGLE_MESSAGE) - .attr("id", sid) - .append(description) - } - JingleMI::Retract(sid) => { - Element::builder("retract", ns::JINGLE_MESSAGE).attr("id", sid) - } - JingleMI::Accept(sid) => Element::builder("accept", ns::JINGLE_MESSAGE).attr("id", sid), - JingleMI::Proceed(sid) => { - Element::builder("proceed", ns::JINGLE_MESSAGE).attr("id", sid) - } - JingleMI::Reject(sid) => Element::builder("reject", ns::JINGLE_MESSAGE).attr("id", sid), - } - .build() - } + #[xml(name = "reject")] + Reject(#[xml(attribute = "id")] SessionId), } #[cfg(test)] mod tests { use super::*; + use xso::error::{Error, FromElementError}; #[cfg(target_pointer_width = "32")] #[test] @@ -126,7 +70,9 @@ mod tests { JingleMI::try_from(elem).unwrap(); } + // TODO: Enable this test again once #[xml(element)] supports filtering on the element name. #[test] + #[ignore] fn test_invalid_child() { let elem: Element = ""