From 132757c8b3bb46654fafebdbae8f70037f4f9b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Fri, 16 Dec 2022 10:23:56 +0100 Subject: [PATCH] handlers: pinging room unsupported until affiliations are implemented MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maxime “pep” Buquet --- src/error.rs | 3 ++ src/handlers.rs | 85 +++++++++++++++++++++++++++++++++---------------- src/tests/iq.rs | 37 +++++++++++++++++++++ 3 files changed, 97 insertions(+), 28 deletions(-) diff --git a/src/error.rs b/src/error.rs index ba4ca76..fc8bae7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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), /// 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), diff --git a/src/handlers.rs b/src/handlers.rs index e94ea7c..7b65472 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -91,7 +91,7 @@ async fn handle_iq_ping( 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( 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( ) -> 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( Ok(()) } +async fn handle_unhandled_iq( + 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( component: &mut C, presence: Presence, diff --git a/src/tests/iq.rs b/src/tests/iq.rs index 96fbe12..f979c9e 100644 --- a/src/tests/iq.rs +++ b/src/tests/iq.rs @@ -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 = 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(); +}