From 4f11d2fe5c0e133a9d00966dfbf2dc86bb1e6d1c Mon Sep 17 00:00:00 2001 From: Link Mauve Date: Tue, 10 Feb 2026 13:20:19 +0100 Subject: [PATCH] xmpp-parsers: Implement XEP-0507: Jingle Content Category This gives the semantic of each video contents in a Jingle session. --- parsers/ChangeLog | 2 + parsers/doap.xml | 8 ++++ parsers/src/jingle_content.rs | 86 +++++++++++++++++++++++++++++++++++ parsers/src/lib.rs | 3 ++ parsers/src/ns.rs | 3 ++ 5 files changed, 102 insertions(+) create mode 100644 parsers/src/jingle_content.rs diff --git a/parsers/ChangeLog b/parsers/ChangeLog index 51d03925..28e19280 100644 --- a/parsers/ChangeLog +++ b/parsers/ChangeLog @@ -1,5 +1,7 @@ Version NEXT: XXXX-YY-ZZ RELEASER + * New parsers/serialisers: + - Jingle Content Category (XEP-0507) * Breaking - The type of jingle_rtp::Description::ssrc has been changed from Option to Option, in accordance with XEP-0167 version diff --git a/parsers/doap.xml b/parsers/doap.xml index 03f927c3..b0b001f2 100644 --- a/parsers/doap.xml +++ b/parsers/doap.xml @@ -706,6 +706,14 @@ 0.22.0 + + + + complete + 0.1.0 + NEXT + + diff --git a/parsers/src/jingle_content.rs b/parsers/src/jingle_content.rs new file mode 100644 index 00000000..89e413de --- /dev/null +++ b/parsers/src/jingle_content.rs @@ -0,0 +1,86 @@ +// Copyright (c) 2026 Link Mauve +// +// 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::ns; + +generate_attribute!( + /// The RFC4796 SDP 'content' attribute. + Name, "name", { + /// The media stream includes presentation slides. + Slides => "slides", + + /// The media stream contains the image of the speaker. + Speaker => "speaker", + + /// The media stream contains sign language. + Sl => "sl", + + /// The media stream is taken from the main source. + Main => "main", + + /// The media stream is taken from the alternative source. + Alt => "alt", + } +); + +/// Wrapper element around the Jingle content category. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::JINGLE_CONTENT, name = "category")] +pub struct Category { + /// The actual category being specified. + #[xml(attribute)] + name: Name, +} + +#[cfg(test)] +mod tests { + use super::*; + use minidom::Element; + use xso::error::{Error, FromElementError}; + + #[test] + fn test_size() { + assert_size!(Category, 1); + assert_size!(Name, 1); + } + + #[test] + fn parse_category() { + let elem: Element = "" + .parse() + .unwrap(); + let category = Category::try_from(elem).unwrap(); + assert_eq!(category.name, Name::Slides); + } + + #[test] + fn invalid_category() { + let elem: Element = "" + .parse() + .unwrap(); + let error = Category::try_from(elem).unwrap_err(); + let message = match error { + FromElementError::Invalid(Error::Other(string)) => string, + _ => panic!(), + }; + assert_eq!( + message, + "Required attribute field 'name' on Category element missing." + ); + + let elem: Element = "" + .parse() + .unwrap(); + let error = Category::try_from(elem).unwrap_err(); + let message = match error { + FromElementError::Invalid(Error::TextParseError(string)) => string, + _ => panic!(), + }; + assert_eq!(message.to_string(), "Unknown value for 'name' attribute."); + } +} diff --git a/parsers/src/lib.rs b/parsers/src/lib.rs index e81cbffe..a59e5792 100644 --- a/parsers/src/lib.rs +++ b/parsers/src/lib.rs @@ -314,6 +314,9 @@ pub mod fast; /// XEP-0490: Message Displayed Synchronization pub mod message_displayed; +/// XEP-0507: Jingle Content Category +pub mod jingle_content; + #[cfg(test)] mod tests { #[test] diff --git a/parsers/src/ns.rs b/parsers/src/ns.rs index 3d08d35a..157a7d73 100644 --- a/parsers/src/ns.rs +++ b/parsers/src/ns.rs @@ -310,6 +310,9 @@ pub const FAST: &str = "urn:xmpp:fast:0"; /// XEP-0490: Message Displayed Synchronization pub const MDS: &str = "urn:xmpp:mds:displayed:0"; +/// XEP-0507: Jingle Content Category +pub const JINGLE_CONTENT: &str = "urn:xmpp:jingle:apps:category:0"; + /// Alias for the main namespace of the stream, that is "jabber:client" when /// the component feature isn’t enabled. #[cfg(not(feature = "component"))]