mod.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::{
 8    parsers::{
 9        bookmarks,
10        disco::{DiscoInfoResult, Feature},
11        iq::Iq,
12        ns,
13        private::Query as PrivateXMLQuery,
14        pubsub::pubsub::{Items, PubSub},
15        Error as ParsersError,
16    },
17    Element, Jid,
18};
19
20use crate::Agent;
21
22// This method is a workaround due to prosody bug https://issues.prosody.im/1664
23// FIXME: To be removed in the future
24// The server doesn't return disco#info feature when querying the account
25// so we add it manually because we know it's true
26pub async fn handle_disco_info_result_payload(agent: &mut Agent, payload: Element, from: Jid) {
27    match DiscoInfoResult::try_from(payload.clone()) {
28        Ok(disco) => {
29            handle_disco_info_result(agent, disco, from).await;
30        }
31        Err(e) => match e {
32            ParsersError::ParseError(reason) => {
33                if reason == "disco#info feature not present in disco#info." {
34                    let mut payload = payload.clone();
35                    let disco_feature =
36                        Feature::new("http://jabber.org/protocol/disco#info").into();
37                    payload.append_child(disco_feature);
38                    match DiscoInfoResult::try_from(payload) {
39                        Ok(disco) => {
40                            handle_disco_info_result(agent, disco, from).await;
41                        }
42                        Err(e) => {
43                            panic!("Wrong disco#info format after workaround: {}", e)
44                        }
45                    }
46                } else {
47                    panic!(
48                        "Wrong disco#info format (reason cannot be worked around): {}",
49                        e
50                    )
51                }
52            }
53            _ => panic!("Wrong disco#info format: {}", e),
54        },
55    }
56}
57
58pub async fn handle_disco_info_result(agent: &mut Agent, disco: DiscoInfoResult, from: Jid) {
59    // Safe unwrap because no DISCO is received when we are not online
60    if from == agent.client.bound_jid().unwrap().to_bare() && agent.awaiting_disco_bookmarks_type {
61        info!("Received disco info about bookmarks type");
62        // Trigger bookmarks query
63        // TODO: only send this when the JoinRooms feature is enabled.
64        agent.awaiting_disco_bookmarks_type = false;
65        let mut perform_bookmarks2 = false;
66        info!("{:#?}", disco.features);
67        for feature in disco.features {
68            if feature.var == "urn:xmpp:bookmarks:1#compat" {
69                perform_bookmarks2 = true;
70            }
71        }
72
73        if perform_bookmarks2 {
74            // XEP-0402 bookmarks (modern)
75            let iq = Iq::from_get("bookmarks", PubSub::Items(Items::new(ns::BOOKMARKS2))).into();
76            let _ = agent.client.send_stanza(iq).await;
77        } else {
78            // XEP-0048 v1.0 bookmarks (legacy)
79            let iq = Iq::from_get(
80                "bookmarks-legacy",
81                PrivateXMLQuery {
82                    storage: bookmarks::Storage::new(),
83                },
84            )
85            .into();
86            let _ = agent.client.send_stanza(iq).await;
87        }
88    } else {
89        unimplemented!("Ignored disco#info response from {}", from);
90    }
91}