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), SecondarySession(Session),
/// Raised when a JID was supposed to be present /// Raised when a JID was supposed to be present
MissingJid, MissingJid,
/// Unhandled Iq with error description
UnhandledIq(String),
/// Jid Parse errors /// Jid Parse errors
Jid(Box<JidParseError>), Jid(Box<JidParseError>),
/// TokioXMPP errors /// TokioXMPP errors
@ -58,6 +60,7 @@ impl fmt::Display for Error {
Error::ParticipantNotFound(err) => write!(f, "Participant not found: {}", err), Error::ParticipantNotFound(err) => write!(f, "Participant not found: {}", err),
Error::SecondarySession(err) => write!(f, "Secondary session: {:?}", err), Error::SecondarySession(err) => write!(f, "Secondary session: {:?}", err),
Error::MissingJid => write!(f, "Missing JID"), Error::MissingJid => write!(f, "Missing JID"),
Error::UnhandledIq(err) => write!(f, "Unhandled Iq: {:?}", err),
Error::Jid(err) => write!(f, "Jid Parse error: {}", err), Error::Jid(err) => write!(f, "Jid Parse error: {}", err),
Error::Xmpp(err) => write!(f, "XMPP error: {}", err), Error::Xmpp(err) => write!(f, "XMPP error: {}", err),
Error::Parser(err) => write!(f, "Parser 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()) let success = Iq::empty_result(iq.from.as_ref().unwrap().clone(), iq.id.clone())
.with_to(from.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() { if let Jid::Full(participant) = to.clone() {
// TODO: Reply from participant if joined and nick is correct // TODO: Reply from participant if joined and nick is correct
let bare = BareJid::from(to.clone()); 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 domain = BareJid::from_str(&to.domain).unwrap();
let success = success.clone().with_from(Jid::Bare(domain)); let success = success.clone().with_from(Jid::Bare(domain));
component.send_stanza(success).await?; 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 { } else {
if let Some(room) = rooms.get(&to) { return Err(Error::UnhandledIq(String::from(
if room.is_joined(&from) { "Pinging a room is not yet supported",
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 Ok(()); return Ok(());
@ -158,23 +153,39 @@ async fn handle_iq<C: ComponentTrait>(
) -> Result<(), Error> { ) -> Result<(), Error> {
match iq.payload { match iq.payload {
IqType::Get(ref payload) => { IqType::Get(ref payload) => {
let iq_result = {
if payload.is("query", ns::DISCO_INFO) { if payload.is("query", ns::DISCO_INFO) {
handle_iq_disco(component, iq.clone(), payload.clone()).await? handle_iq_disco(component, iq.clone(), payload.clone()).await
} else if payload.is("ping", ns::PING) { } else if payload.is("ping", ns::PING) {
handle_iq_ping(component, iq.clone(), payload.clone(), rooms).await? handle_iq_ping(component, iq.clone(), payload.clone(), rooms).await
} else { } else {
// We MUST answer unhandled get iqs with a service-unavailable error. // We MUST answer unhandled get iqs with a service-unavailable error.
let error = StanzaError::new( handle_unhandled_iq(
ErrorType::Cancel, component,
DefinedCondition::ServiceUnavailable, iq.id.clone(),
iq.to.clone().unwrap(),
iq.from.clone().unwrap(),
"en", "en",
"No handler defined for this kind of iq.", "No handler defined for this kind of iq.",
); )
let iq: Element = Iq::from_error(iq.id, error) .await
.with_from(iq.to.unwrap()) }
.with_to(iq.from.unwrap()) };
.into();
component.send_stanza(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), _ => error!("Not handled iq: {:?}", iq),
@ -183,6 +194,24 @@ async fn handle_iq<C: ComponentTrait>(
Ok(()) 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>( async fn handle_presence<C: ComponentTrait>(
component: &mut C, component: &mut C,
presence: Presence, presence: Presence,

View file

@ -150,3 +150,40 @@ async fn test_self_ping_participant_non_existing() {
handle_stanza(&mut component, &mut rooms).await.unwrap(); 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();
}