handlers: pinging room unsupported until affiliations are implemented

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
Maxime “pep” Buquet 2022-12-16 10:23:56 +01:00
parent 2a2d8cd051
commit 132757c8b3
Signed by: pep
GPG key ID: DEDA74AEECA9D0F2
3 changed files with 97 additions and 28 deletions

View file

@ -38,6 +38,8 @@ pub enum Error {
SecondarySession(Session),
/// Raised when a JID was supposed to be present
MissingJid,
/// Unhandled Iq with error description
UnhandledIq(String),
/// Jid Parse errors
Jid(Box<JidParseError>),
/// TokioXMPP errors
@ -58,6 +60,7 @@ impl fmt::Display for Error {
Error::ParticipantNotFound(err) => write!(f, "Participant not found: {}", err),
Error::SecondarySession(err) => write!(f, "Secondary session: {:?}", err),
Error::MissingJid => write!(f, "Missing JID"),
Error::UnhandledIq(err) => write!(f, "Unhandled Iq: {:?}", err),
Error::Jid(err) => write!(f, "Jid Parse error: {}", err),
Error::Xmpp(err) => write!(f, "XMPP error: {}", err),
Error::Parser(err) => write!(f, "Parser error: {}", err),

View file

@ -91,7 +91,7 @@ async fn handle_iq_ping<C: ComponentTrait>(
let success = Iq::empty_result(iq.from.as_ref().unwrap().clone(), iq.id.clone())
.with_to(from.clone());
// Pinging a participant
// Pinging a participant. The resource needs to be currently joined.
if let Jid::Full(participant) = to.clone() {
// TODO: Reply from participant if joined and nick is correct
let bare = BareJid::from(to.clone());
@ -112,17 +112,12 @@ async fn handle_iq_ping<C: ComponentTrait>(
let domain = BareJid::from_str(&to.domain).unwrap();
let success = success.clone().with_from(Jid::Bare(domain));
component.send_stanza(success).await?;
// Pinging a room
// Pinging a room. User is required to have an affiliation other than none if
// member-only.
} else {
if let Some(room) = rooms.get(&to) {
if room.is_joined(&from) {
let success = success.clone().with_from(Jid::Bare(to));
component.send_stanza(success).await?;
return Ok(());
}
}
let success = success.clone().with_from(Jid::Bare(to));
component.send_stanza(success).await?;
return Err(Error::UnhandledIq(String::from(
"Pinging a room is not yet supported",
)));
}
return Ok(());
@ -158,23 +153,39 @@ async fn handle_iq<C: ComponentTrait>(
) -> Result<(), Error> {
match iq.payload {
IqType::Get(ref payload) => {
if payload.is("query", ns::DISCO_INFO) {
handle_iq_disco(component, iq.clone(), payload.clone()).await?
} else if payload.is("ping", ns::PING) {
handle_iq_ping(component, iq.clone(), payload.clone(), rooms).await?
} else {
// We MUST answer unhandled get iqs with a service-unavailable error.
let error = StanzaError::new(
ErrorType::Cancel,
DefinedCondition::ServiceUnavailable,
"en",
"No handler defined for this kind of iq.",
);
let iq: Element = Iq::from_error(iq.id, error)
.with_from(iq.to.unwrap())
.with_to(iq.from.unwrap())
.into();
component.send_stanza(iq).await?;
let iq_result = {
if payload.is("query", ns::DISCO_INFO) {
handle_iq_disco(component, iq.clone(), payload.clone()).await
} else if payload.is("ping", ns::PING) {
handle_iq_ping(component, iq.clone(), payload.clone(), rooms).await
} else {
// We MUST answer unhandled get iqs with a service-unavailable error.
handle_unhandled_iq(
component,
iq.id.clone(),
iq.to.clone().unwrap(),
iq.from.clone().unwrap(),
"en",
"No handler defined for this kind of iq.",
)
.await
}
};
match iq_result {
Ok(()) => (),
Err(Error::UnhandledIq(desc)) => {
handle_unhandled_iq(
component,
iq.id,
iq.to.unwrap(),
iq.from.unwrap(),
"en",
desc.as_str(),
)
.await?
}
err => err?,
}
}
_ => error!("Not handled iq: {:?}", iq),
@ -183,6 +194,24 @@ async fn handle_iq<C: ComponentTrait>(
Ok(())
}
async fn handle_unhandled_iq<C: ComponentTrait>(
component: &mut C,
id: String,
from: Jid,
to: Jid,
lang: &str,
desc: &str,
) -> Result<(), Error> {
let error = StanzaError::new(
ErrorType::Cancel,
DefinedCondition::ServiceUnavailable,
lang,
desc,
);
let iq: Element = Iq::from_error(id, error).with_from(from).with_to(to).into();
component.send_stanza(iq).await
}
async fn handle_presence<C: ComponentTrait>(
component: &mut C,
presence: Presence,

View file

@ -150,3 +150,40 @@ async fn test_self_ping_participant_non_existing() {
handle_stanza(&mut component, &mut rooms).await.unwrap();
}
#[tokio::test]
async fn test_ping_room() {
let realjid1 = Jid::Full(FullJid::from_str("foo@bar/qxx").unwrap());
let roomjid = COMPONENT_JID.clone().with_node("room");
let ping: Element = Iq {
from: Some(realjid1.clone()),
to: Some(Jid::Bare(roomjid.clone())),
id: String::from("ping"),
payload: IqType::Get(Ping {}.into()),
}
.into();
let mut component = TestComponent::new(vec![ping]);
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
component.expect_iq(
realjid1.clone(),
move |iq| {
let from = roomjid.clone();
let to = realjid1.clone();
assert_eq!(iq.from.unwrap(), Jid::Bare(from));
assert_eq!(iq.to.unwrap(), to);
match iq.payload {
IqType::Error(err) => {
assert_eq!(err.type_, ErrorType::Cancel);
assert_eq!(err.defined_condition, DefinedCondition::ServiceUnavailable);
}
payload => panic!("Unexpected payload for iq ping reply: {:?}", payload),
}
},
"ServiceUnavailable iq error",
);
handle_stanza(&mut component, &mut rooms).await.unwrap();
}