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