xmpp-parsers: Implement XEP-0507: Jingle Content Category

This gives the semantic of each video contents in a Jingle session.
This commit is contained in:
Link Mauve 2026-02-10 13:20:19 +01:00 committed by pep
commit 4f11d2fe5c
5 changed files with 102 additions and 0 deletions

View file

@ -1,5 +1,7 @@
Version NEXT:
XXXX-YY-ZZ RELEASER <admin@example.com>
* New parsers/serialisers:
- Jingle Content Category (XEP-0507)
* Breaking
- The type of jingle_rtp::Description::ssrc has been changed from
Option<String> to Option<u32>, in accordance with XEP-0167 version

View file

@ -706,6 +706,14 @@
<xmpp:since>0.22.0</xmpp:since>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0507.html"/>
<xmpp:status>complete</xmpp:status>
<xmpp:version>0.1.0</xmpp:version>
<xmpp:since>NEXT</xmpp:since>
</xmpp:SupportedXep>
</implements>
<release>
<Version>

View file

@ -0,0 +1,86 @@
// Copyright (c) 2026 Link Mauve <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::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 = "<category xmlns='urn:xmpp:jingle:apps:category:0' name='slides'/>"
.parse()
.unwrap();
let category = Category::try_from(elem).unwrap();
assert_eq!(category.name, Name::Slides);
}
#[test]
fn invalid_category() {
let elem: Element = "<category xmlns='urn:xmpp:jingle:apps:category:0'/>"
.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 = "<category xmlns='urn:xmpp:jingle:apps:category:0' name='anime'/>"
.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.");
}
}

View file

@ -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]

View file

@ -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 isnt enabled.
#[cfg(not(feature = "component"))]