xmpp/presence/
receive.rs

1// Copyright (c) 2023 xmpp-rs contributors.
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7use tokio_xmpp::parsers::{
8    muc::user::{MucUser, Status},
9    presence::{Presence, Type as PresenceType},
10};
11
12use crate::{Agent, Event};
13
14/// Translate a `Presence` stanza into a list of higher-level `Event`s.
15pub async fn handle_presence(agent: &mut Agent, presence: Presence) -> Vec<Event> {
16    // Allocate an empty vector to store the events.
17    let mut events = vec![];
18
19    // Extract the JID of the sender (i.e. the one whose presence is being sent).
20    let from = presence.from.clone().unwrap().to_bare();
21
22    // Search through the payloads for a MUC user status.
23
24    if let Some(muc) = presence
25        .payloads
26        .iter()
27        .filter_map(|p| MucUser::try_from(p.clone()).ok())
28        .next()
29    {
30        // If a MUC user status was found, search through the statuses for a self-presence.
31        if muc.status.iter().any(|s| *s == Status::SelfPresence) {
32            // If a self-presence was found, then the stanza is about the client's own presence.
33
34            match presence.type_ {
35                PresenceType::None => {
36                    // According to https://xmpp.org/extensions/xep-0045.html#enter-pres, no type should be seen as "available".
37                    if let Some(nick) = agent.rooms_joining.get(&from) {
38                        agent.rooms_joined.insert(from.clone(), nick.clone());
39                        agent.rooms_joining.remove(&from);
40                    } else {
41                        warn!(
42                            "Received self-presence from {} while the room was not marked as joining.",
43                            presence.from.unwrap()
44                        );
45                    }
46                    events.push(Event::RoomJoined(from.clone()));
47                }
48                PresenceType::Unavailable => {
49                    // 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/
50                    if agent.rooms_leaving.contains_key(&from) {
51                        agent.rooms_joined.remove(&from);
52                        agent.rooms_leaving.remove(&from);
53                    } else {
54                        warn!(
55                            "Received self-presence unavailable from {} while the room was not marked as leaving.",
56                            presence.from.unwrap()
57                        );
58                    }
59                    events.push(Event::RoomLeft(from.clone()));
60                }
61                _ => unimplemented!("Presence type {:?}", presence.type_), // TODO: What to do here?
62            }
63        }
64    }
65
66    // Return the list of events.
67    events
68}