Muc <x xmlns='http://jabber.org/protocol/muc#user'/> and <status /> parser
This commit is contained in:
parent
c4c6528197
commit
bd19341f69
2 changed files with 271 additions and 5 deletions
274
src/muc.rs
274
src/muc.rs
|
@ -6,7 +6,7 @@
|
|||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use minidom::Element;
|
||||
use minidom::{Element, IntoElements, ElementEmitter};
|
||||
|
||||
use error::Error;
|
||||
|
||||
|
@ -40,18 +40,189 @@ impl Into<Element> for Muc {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Status {
|
||||
// 100
|
||||
NonAnonymousRoom,
|
||||
|
||||
// 101
|
||||
AffiliationChange,
|
||||
|
||||
// 102
|
||||
ConfigShowsUnavailableMembers,
|
||||
|
||||
// 103
|
||||
ConfigHidesUnavailableMembers,
|
||||
|
||||
// 104
|
||||
ConfigNonPrivacyRelated,
|
||||
|
||||
// 110
|
||||
SelfPresence,
|
||||
|
||||
// 170
|
||||
ConfigRoomLoggingEnabled,
|
||||
|
||||
// 171
|
||||
ConfigRoomLoggingDisabled,
|
||||
|
||||
// 172
|
||||
ConfigRoomNonAnonymous,
|
||||
|
||||
// 173
|
||||
ConfigRoomSemiAnonymous,
|
||||
|
||||
// 201
|
||||
RoomHasBeenCreated,
|
||||
|
||||
// 210
|
||||
AssignedNick,
|
||||
|
||||
// 301
|
||||
Banned,
|
||||
|
||||
// 303
|
||||
NewNick,
|
||||
|
||||
// 307
|
||||
Kicked,
|
||||
|
||||
// 321
|
||||
RemovalFromRoom,
|
||||
|
||||
// 322
|
||||
ConfigMembersOnly,
|
||||
|
||||
// 332
|
||||
ServiceShutdown,
|
||||
}
|
||||
|
||||
impl TryFrom<Element> for Status {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(elem: Element) -> Result<Status, Error> {
|
||||
if !elem.is("status", ns::MUC_USER) {
|
||||
return Err(Error::ParseError("This is not a status element."));
|
||||
}
|
||||
for _ in elem.children() {
|
||||
return Err(Error::ParseError("Unknown child in status element."));
|
||||
}
|
||||
for (attr, _) in elem.attrs() {
|
||||
if attr != "code" {
|
||||
return Err(Error::ParseError("Unknown attribute in status element."));
|
||||
}
|
||||
}
|
||||
let code = get_attr!(elem, "code", required);
|
||||
|
||||
Ok(match code {
|
||||
100 => Status::NonAnonymousRoom,
|
||||
101 => Status::AffiliationChange,
|
||||
102 => Status::ConfigShowsUnavailableMembers,
|
||||
103 => Status::ConfigHidesUnavailableMembers,
|
||||
104 => Status::ConfigNonPrivacyRelated,
|
||||
110 => Status::SelfPresence,
|
||||
170 => Status::ConfigRoomLoggingEnabled,
|
||||
171 => Status::ConfigRoomLoggingDisabled,
|
||||
172 => Status::ConfigRoomNonAnonymous,
|
||||
173 => Status::ConfigRoomSemiAnonymous,
|
||||
201 => Status::RoomHasBeenCreated,
|
||||
210 => Status::AssignedNick,
|
||||
301 => Status::Banned,
|
||||
303 => Status::NewNick,
|
||||
307 => Status::Kicked,
|
||||
321 => Status::RemovalFromRoom,
|
||||
322 => Status::ConfigMembersOnly,
|
||||
332 => Status::ServiceShutdown,
|
||||
_ => return Err(Error::ParseError("Invalid status code.")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Element> for Status {
|
||||
fn into(self) -> Element {
|
||||
Element::builder("status")
|
||||
.ns(ns::MUC_USER)
|
||||
.attr("code", match self {
|
||||
Status::NonAnonymousRoom => 100,
|
||||
Status::AffiliationChange => 101,
|
||||
Status::ConfigShowsUnavailableMembers => 102,
|
||||
Status::ConfigHidesUnavailableMembers => 103,
|
||||
Status::ConfigNonPrivacyRelated => 104,
|
||||
Status::SelfPresence => 110,
|
||||
Status::ConfigRoomLoggingEnabled => 170,
|
||||
Status::ConfigRoomLoggingDisabled => 171,
|
||||
Status::ConfigRoomNonAnonymous => 172,
|
||||
Status::ConfigRoomSemiAnonymous => 173,
|
||||
Status::RoomHasBeenCreated => 201,
|
||||
Status::AssignedNick => 210,
|
||||
Status::Banned => 301,
|
||||
Status::NewNick => 303,
|
||||
Status::Kicked => 307,
|
||||
Status::RemovalFromRoom => 321,
|
||||
Status::ConfigMembersOnly => 322,
|
||||
Status::ServiceShutdown => 332,
|
||||
})
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoElements for Status {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
emitter.append_child(self.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MucUser {
|
||||
status: Vec<Status>,
|
||||
}
|
||||
|
||||
impl TryFrom<Element> for MucUser {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(elem: Element) -> Result<MucUser, Error> {
|
||||
if !elem.is("x", ns::MUC_USER) {
|
||||
return Err(Error::ParseError("This is not an x element."));
|
||||
}
|
||||
let mut status = vec!();
|
||||
for child in elem.children() {
|
||||
if child.is("status", ns::MUC_USER) {
|
||||
status.push(Status::try_from(child.clone())?);
|
||||
} else {
|
||||
return Err(Error::ParseError("Unknown child in x element."));
|
||||
}
|
||||
}
|
||||
for _ in elem.attrs() {
|
||||
return Err(Error::ParseError("Unknown attribute in x element."));
|
||||
}
|
||||
Ok(MucUser {
|
||||
status: status,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Element> for MucUser {
|
||||
fn into(self) -> Element {
|
||||
Element::builder("x")
|
||||
.ns(ns::MUC_USER)
|
||||
.append(self.status)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::error::Error as StdError;
|
||||
|
||||
#[test]
|
||||
fn test_simple() {
|
||||
fn test_muc_simple() {
|
||||
let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'/>".parse().unwrap();
|
||||
Muc::try_from(elem).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_child() {
|
||||
fn test_muc_invalid_child() {
|
||||
let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'><coucou/></x>".parse().unwrap();
|
||||
let error = Muc::try_from(elem).unwrap_err();
|
||||
let message = match error {
|
||||
|
@ -62,7 +233,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialise() {
|
||||
fn test_muc_serialise() {
|
||||
let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'/>".parse().unwrap();
|
||||
let muc = Muc;
|
||||
let elem2 = muc.into();
|
||||
|
@ -70,7 +241,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_attribute() {
|
||||
fn test_muc_invalid_attribute() {
|
||||
let elem: Element = "<x xmlns='http://jabber.org/protocol/muc' coucou=''/>".parse().unwrap();
|
||||
let error = Muc::try_from(elem).unwrap_err();
|
||||
let message = match error {
|
||||
|
@ -79,4 +250,97 @@ mod tests {
|
|||
};
|
||||
assert_eq!(message, "Unknown attribute in x element.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_muc_user_simple() {
|
||||
let elem: Element = "<x xmlns='http://jabber.org/protocol/muc#user'/>".parse().unwrap();
|
||||
MucUser::try_from(elem).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_muc_user_invalid_child() {
|
||||
let elem: Element = "<x xmlns='http://jabber.org/protocol/muc#user'><coucou/></x>".parse().unwrap();
|
||||
let error = MucUser::try_from(elem).unwrap_err();
|
||||
let message = match error {
|
||||
Error::ParseError(string) => string,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert_eq!(message, "Unknown child in x element.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_muc_user_serialise() {
|
||||
let elem: Element = "<x xmlns='http://jabber.org/protocol/muc#user'/>".parse().unwrap();
|
||||
let muc = MucUser { status: vec!() };
|
||||
let elem2 = muc.into();
|
||||
assert_eq!(elem, elem2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_muc_user_invalid_attribute() {
|
||||
let elem: Element = "<x xmlns='http://jabber.org/protocol/muc#user' coucou=''/>".parse().unwrap();
|
||||
let error = MucUser::try_from(elem).unwrap_err();
|
||||
let message = match error {
|
||||
Error::ParseError(string) => string,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert_eq!(message, "Unknown attribute in x element.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_simple() {
|
||||
let elem: Element = "<status xmlns='http://jabber.org/protocol/muc#user' code='110'/>".parse().unwrap();
|
||||
Status::try_from(elem).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_invalid() {
|
||||
let elem: Element = "<status xmlns='http://jabber.org/protocol/muc#user'/>".parse().unwrap();
|
||||
let error = Status::try_from(elem).unwrap_err();
|
||||
let message = match error {
|
||||
Error::ParseError(string) => string,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert_eq!(message, "Required attribute 'code' missing.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_invalid_child() {
|
||||
let elem: Element = "<status xmlns='http://jabber.org/protocol/muc#user' code='110'><foo/></status>".parse().unwrap();
|
||||
let error = Status::try_from(elem).unwrap_err();
|
||||
let message = match error {
|
||||
Error::ParseError(string) => string,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert_eq!(message, "Unknown child in status element.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_simple_code() {
|
||||
let elem: Element = "<status xmlns='http://jabber.org/protocol/muc#user' code='307'/>".parse().unwrap();
|
||||
let status = Status::try_from(elem).unwrap();
|
||||
assert_eq!(status, Status::Kicked);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_invalid_code() {
|
||||
let elem: Element = "<status xmlns='http://jabber.org/protocol/muc#user' code='666'/>".parse().unwrap();
|
||||
let error = Status::try_from(elem).unwrap_err();
|
||||
let message = match error {
|
||||
Error::ParseError(string) => string,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert_eq!(message, "Invalid status code.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_invalid_code2() {
|
||||
let elem: Element = "<status xmlns='http://jabber.org/protocol/muc#user' code='coucou'/>".parse().unwrap();
|
||||
let error = Status::try_from(elem).unwrap_err();
|
||||
let error = match error {
|
||||
Error::ParseIntError(error) => error,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert_eq!(error.description(), "invalid digit found in string");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ pub const DISCO_INFO: &'static str = "http://jabber.org/protocol/disco#info";
|
|||
|
||||
/// XEP-0045: Multi-User Chat
|
||||
pub const MUC: &'static str = "http://jabber.org/protocol/muc";
|
||||
/// XEP-0045: Multi-User Chat
|
||||
pub const MUC_USER: &'static str = "http://jabber.org/protocol/muc#user";
|
||||
|
||||
/// XEP-0047: In-Band Bytestreams
|
||||
pub const IBB: &'static str = "http://jabber.org/protocol/ibb";
|
||||
|
|
Loading…
Reference in a new issue