diff --git a/src/lib.rs b/src/lib.rs index da1af26c..06048c8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -194,3 +194,6 @@ pub mod eme; /// XEP-0390: Entity Capabilities 2.0 pub mod ecaps2; + +/// XEP-0421: Anonymous unique occupant identifiers for MUCs +pub mod occupant_id; diff --git a/src/ns.rs b/src/ns.rs index f5941258..ef785082 100644 --- a/src/ns.rs +++ b/src/ns.rs @@ -204,6 +204,9 @@ pub const ECAPS2: &str = "urn:xmpp:caps"; /// XEP-0390: Entity Capabilities 2.0 pub const ECAPS2_OPTIMIZE: &str = "urn:xmpp:caps:optimize"; +/// XEP-0421: Anonymous unique occupant identifiers for MUCs +pub const OID: &str = "urn:xmpp:occupant-id:0"; + /// Alias for the main namespace of the stream, that is "jabber:client" when /// the component feature isn’t enabled. #[cfg(not(feature = "component"))] diff --git a/src/occupant_id.rs b/src/occupant_id.rs new file mode 100644 index 00000000..73065294 --- /dev/null +++ b/src/occupant_id.rs @@ -0,0 +1,89 @@ +// Copyright (c) 2019 Emmanuel Gil Peyrot +// +// 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::message::MessagePayload; +use crate::presence::PresencePayload; + +generate_element!( + /// Unique identifier given to a MUC participant. + /// + /// It allows clients to identify a MUC participant across reconnects and + /// renames. It thus prevents impersonification of anonymous users. + OccupantId, "occupant-id", OID, + + attributes: [ + /// The id associated to the sending user by the MUC service. + id: Required = "id", + ] +); + +impl MessagePayload for OccupantId {} +impl PresencePayload for OccupantId {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::error::Error; + use minidom::Element; + use std::convert::TryFrom; + + #[cfg(target_pointer_width = "32")] + #[test] + fn test_size() { + assert_size!(OccupantId, 12); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_size() { + assert_size!(OccupantId, 24); + } + + #[test] + fn test_simple() { + let elem: Element = "" + .parse() + .unwrap(); + let origin_id = OccupantId::try_from(elem).unwrap(); + assert_eq!(origin_id.id, "coucou"); + } + + #[test] + fn test_invalid_child() { + let elem: Element = "" + .parse() + .unwrap(); + let error = OccupantId::try_from(elem).unwrap_err(); + let message = match error { + Error::ParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message, "Unknown child in occupant-id element."); + } + + #[test] + fn test_invalid_id() { + let elem: Element = "".parse().unwrap(); + let error = OccupantId::try_from(elem).unwrap_err(); + let message = match error { + Error::ParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message, "Required attribute 'id' missing."); + } + + #[test] + fn test_serialise() { + let elem: Element = "" + .parse() + .unwrap(); + let occupant_id = OccupantId { + id: String::from("coucou"), + }; + let elem2 = occupant_id.into(); + assert_eq!(elem, elem2); + } +}