diff --git a/xmpp/src/lib.rs b/xmpp/src/lib.rs index 6054e6a2..c5f71fb6 100644 --- a/xmpp/src/lib.rs +++ b/xmpp/src/lib.rs @@ -459,22 +459,43 @@ impl Agent { events } + /// Translate a `Presence` stanza into a list of higher-level `Event`s. async fn handle_presence(&mut self, presence: Presence) -> Vec { + // Allocate an empty vector to store the events. let mut events = vec![]; + + // Extract the JID of the sender (i.e. the one whose presence is being sent). let from = presence.from.unwrap().to_bare(); - for payload in presence.payloads.into_iter() { - let muc_user = match MucUser::try_from(payload) { - Ok(muc_user) => muc_user, - _ => continue, - }; - for status in muc_user.status.into_iter() { - if status == Status::SelfPresence { - events.push(Event::RoomJoined(from.clone())); - break; + + // Search through the payloads for a MUC user status. + + if let Some(muc) = presence + .payloads + .iter() + .filter_map(|p| MucUser::try_from(p.clone()).ok()) + .next() + { + // If a MUC user status was found, search through the statuses for a self-presence. + if muc.status.iter().any(|s| *s == Status::SelfPresence) { + // If a self-presence was found, then the stanza is about the client's own presence. + + match presence.type_ { + PresenceType::None => { + // According to https://xmpp.org/extensions/xep-0045.html#enter-pres, no type should be seen as "available". + events.push(Event::RoomJoined(from.clone())); + } + PresenceType::Unavailable => { + // According to https://xmpp.org/extensions/xep-0045.html#exit, the server will use type "unavailable" to notify the client that it has left the room/ + events.push(Event::RoomLeft(from.clone())); + } + _ => unimplemented!("Presence type {:?}", presence.type_), // TODO: What to do here? } + + events.push(Event::RoomJoined(from.clone())); } } + // Return the list of events. events }