xmpp_parsers::jingle: make ReasonElement::texts into an Option

The Jingle XEP says [1]:

> The <reason/> element MAY contain a <text/> element that provides
> human-readable information about the reason for the action.

It says nowhere that there may be more than one `<text/>` element in
there, or that they may be qualified by xml:lang. The schema [2] also
agrees with that:

> ```
>   <xs:complexType name='reasonElementType'>
>     <xs:sequence>
>       <xs:choice>
>         <!-- … omitted … -->
>       </xs:choice>
>       <xs:element name='text' type='xs:string' minOccurs='0' maxOccurs='1'/>
>       <!-- … omitted … -->
>     </xs:sequence>
>   </xs:complexType>
> ```

   [1]: https://xmpp.org/extensions/xep-0166.html#def-reason
   [2]: https://xmpp.org/extensions/xep-0166.html#schema-jingle
This commit is contained in:
Jonas Schäfer 2024-03-30 09:55:57 +01:00
parent 1293e9a3eb
commit ed0a1cd8cf
1 changed files with 16 additions and 22 deletions

View File

@ -14,7 +14,6 @@ use crate::ns;
use crate::util::error::Error;
use crate::Element;
use jid::Jid;
use std::collections::BTreeMap;
use std::fmt;
use std::str::FromStr;
@ -461,8 +460,6 @@ impl From<Reason> for Element {
}
}
type Lang = String;
/// Informs the recipient of something.
#[derive(Debug, Clone, PartialEq)]
pub struct ReasonElement {
@ -470,15 +467,13 @@ pub struct ReasonElement {
pub reason: Reason,
/// A human-readable description of this reason.
pub texts: BTreeMap<Lang, String>,
pub text: Option<String>,
}
impl fmt::Display for ReasonElement {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", Element::from(self.reason.clone()).name())?;
if let Some(text) = self.texts.get("en") {
write!(fmt, ": {}", text)?;
} else if let Some(text) = self.texts.get("") {
if let Some(text) = self.text.as_ref() {
write!(fmt, ": {}", text)?;
}
Ok(())
@ -492,17 +487,15 @@ impl TryFrom<Element> for ReasonElement {
check_self!(elem, "reason", JINGLE);
check_no_attributes!(elem, "reason");
let mut reason = None;
let mut texts = BTreeMap::new();
let mut text = None;
for child in elem.children() {
if child.is("text", ns::JINGLE) {
check_no_children!(child, "text");
check_no_unknown_attributes!(child, "text", ["xml:lang"]);
let lang = get_attr!(elem, "xml:lang", Default);
if texts.insert(lang, child.text()).is_some() {
return Err(Error::ParseError(
"Text element present twice for the same xml:lang.",
));
if text.is_some() {
return Err(Error::ParseError("Multiple reason texts."));
}
text = Some(child.text());
} else if child.has_ns(ns::JINGLE) {
if reason.is_some() {
return Err(Error::ParseError(
@ -517,7 +510,7 @@ impl TryFrom<Element> for ReasonElement {
}
}
let reason = reason.ok_or(Error::ParseError("Reason doesnt contain a valid reason."))?;
Ok(ReasonElement { reason, texts })
Ok(ReasonElement { reason, text })
}
}
@ -525,11 +518,12 @@ impl From<ReasonElement> for Element {
fn from(reason: ReasonElement) -> Element {
Element::builder("reason", ns::JINGLE)
.append(Element::from(reason.reason))
.append_all(reason.texts.into_iter().map(|(lang, text)| {
Element::builder("text", ns::JINGLE)
.attr("xml:lang", lang)
.append(text)
}))
.append_all(
reason
.text
.into_iter()
.map(|text| Element::builder("text", ns::JINGLE).append(text)),
)
.build()
}
}
@ -823,13 +817,13 @@ mod tests {
let jingle = Jingle::try_from(elem).unwrap();
let reason = jingle.reason.unwrap();
assert_eq!(reason.reason, Reason::Success);
assert_eq!(reason.texts, BTreeMap::new());
assert_eq!(reason.text, None);
let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><reason><success/><text>coucou</text></reason></jingle>".parse().unwrap();
let jingle = Jingle::try_from(elem).unwrap();
let reason = jingle.reason.unwrap();
assert_eq!(reason.reason, Reason::Success);
assert_eq!(reason.texts.get(""), Some(&String::from("coucou")));
assert_eq!(reason.text, Some(String::from("coucou")));
}
#[test]
@ -872,7 +866,7 @@ mod tests {
Error::ParseError(string) => string,
_ => panic!(),
};
assert_eq!(message, "Text element present twice for the same xml:lang.");
assert_eq!(message, "Multiple reason texts.");
}
#[test]