Added an attempt to fix the bug where the client misinterprets "unavailable" status (or any other self-status, really) as a RoomJoined event.

Werner Kroneman created

Change summary

xmpp/src/lib.rs | 39 ++++++++++++++++++++++++++++++---------
1 file changed, 30 insertions(+), 9 deletions(-)

Detailed changes

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<Event> {
+        // 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
     }