From 41bf709cf5ef6608ea2dc1a9e3f0e775be8b62d6 Mon Sep 17 00:00:00 2001 From: Melvin Keskin Date: Mon, 27 Nov 2023 22:11:31 +0100 Subject: [PATCH] Set stream errors to be ignored during account creation/deletion https://xmpp.org/extensions/xep-0077.html#usecases-cancel specifies the usage of the stream error . That is now handled as a valid response to the account deletion request instead of a result IQ stanza or in addition to it. The same applies to the stream error since some servers send that instead of the stream error. There are servers closing the connection during account creation with a stream error. That is now ignored. --- src/client/QXmppClient.cpp | 20 ++++++++++++++++++++ src/client/QXmppClient.h | 5 +++++ src/client/QXmppClient_p.h | 2 ++ src/client/QXmppRegistrationManager.cpp | 16 +++++++++++++++- src/client/QXmppRegistrationManager.h | 10 ++++------ 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/client/QXmppClient.cpp b/src/client/QXmppClient.cpp index 97a5f80bf..bebe59519 100644 --- a/src/client/QXmppClient.cpp +++ b/src/client/QXmppClient.cpp @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2009 Manjeet Dahiya // SPDX-FileCopyrightText: 2019 Linus Jahn +// SPDX-FileCopyrightText: 2023 Melvin Keskin // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -123,6 +124,13 @@ QStringList QXmppClientPrivate::discoveryFeatures() void QXmppClientPrivate::onErrorOccurred(const QString &text, const QXmppOutgoingClient::ConnectionError &err, QXmppClient::Error oldError) { + // Skip stream errors that are valid during special procedures such as account + // creation/deletion. + if (const auto streamError = std::get_if(&err); + streamError && ignoredStreamErrors.contains(*streamError)) { + return; + } + if (q->configuration().autoReconnectionEnabled()) { if (oldError == QXmppClient::XmppStreamError) { // if we receive a resource conflict, inhibit reconnection @@ -931,6 +939,18 @@ bool QXmppClient::injectMessage(QXmppMessage &&message) return handled; } +/// +/// Sets stream errors that are ignored if they occur. +/// +/// \param errors stream errors to be ignored +/// +/// \since QXmpp 1.9 +/// +void QXmppClient::setIgnoredStreamErrors(const QVector &errors) +{ + d->ignoredStreamErrors = errors; +} + /// /// Give extensions a chance to handle incoming stanzas. /// diff --git a/src/client/QXmppClient.h b/src/client/QXmppClient.h index a0d9f07ac..591a4fdc4 100644 --- a/src/client/QXmppClient.h +++ b/src/client/QXmppClient.h @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2009 Manjeet Dahiya // SPDX-FileCopyrightText: 2019 Linus Jahn +// SPDX-FileCopyrightText: 2023 Melvin Keskin // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -11,6 +12,7 @@ #include "QXmppPresence.h" #include "QXmppSendResult.h" #include "QXmppSendStanzaParams.h" +#include "QXmppStreamError.h" #include #include @@ -321,6 +323,8 @@ public Q_SLOTS: void injectIq(const QDomElement &element, const std::optional &e2eeMetadata); bool injectMessage(QXmppMessage &&message); + void setIgnoredStreamErrors(const QVector &); + private Q_SLOTS: void _q_elementReceived(const QDomElement &element, bool &handled); void _q_reconnect(); @@ -335,6 +339,7 @@ private Q_SLOTS: friend class QXmppCarbonManagerV2; friend class QXmppRegistrationManager; friend class TestClient; + friend class QXmppRegistrationManager; }; #endif // QXMPPCLIENT_H diff --git a/src/client/QXmppClient_p.h b/src/client/QXmppClient_p.h index abf3fa2b7..691dca693 100644 --- a/src/client/QXmppClient_p.h +++ b/src/client/QXmppClient_p.h @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2020 Manjeet Dahiya // SPDX-FileCopyrightText: 2020 Linus Jahn +// SPDX-FileCopyrightText: 2023 Melvin Keskin // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -40,6 +41,7 @@ class QXmppClientPrivate QXmppLogger *logger; /// Pointer to the XMPP stream QXmppOutgoingClient *stream; + QVector ignoredStreamErrors; QXmppE2eeExtension *encryptionExtension; diff --git a/src/client/QXmppRegistrationManager.cpp b/src/client/QXmppRegistrationManager.cpp index 929354453..9b5d94236 100644 --- a/src/client/QXmppRegistrationManager.cpp +++ b/src/client/QXmppRegistrationManager.cpp @@ -91,6 +91,7 @@ void QXmppRegistrationManager::deleteAccount() auto iq = QXmppRegisterIq::createUnregistrationRequest(); d->deleteAccountIqId = iq.id(); + client()->setIgnoredStreamErrors({ QXmpp::StreamError::Conflict, QXmpp::StreamError::NotAuthorized }); client()->sendPacket(iq); } @@ -174,6 +175,12 @@ bool QXmppRegistrationManager::registerOnConnectEnabled() const void QXmppRegistrationManager::setRegisterOnConnectEnabled(bool enabled) { d->registerOnConnectEnabled = enabled; + + if (enabled) { + client()->setIgnoredStreamErrors({ QXmpp::StreamError::ConnectionTimeout }); + } else { + client()->setIgnoredStreamErrors({}); + } } /// \cond @@ -291,8 +298,15 @@ void QXmppRegistrationManager::onRegistered(QXmppClient *client) connect(disco, &QXmppDiscoveryManager::infoReceived, this, &QXmppRegistrationManager::handleDiscoInfo); } - connect(client, &QXmppClient::disconnected, this, [this]() { + connect(client, &QXmppClient::disconnected, this, [this, client]() { setSupportedByServer(false); + client->setIgnoredStreamErrors({}); + + if (!d->deleteAccountIqId.isEmpty()) { + info(QStringLiteral("Account deleted successfully.")); + Q_EMIT accountDeleted(); + d->deleteAccountIqId.clear(); + } }); } diff --git a/src/client/QXmppRegistrationManager.h b/src/client/QXmppRegistrationManager.h index cf4033bba..ceb7ef470 100644 --- a/src/client/QXmppRegistrationManager.h +++ b/src/client/QXmppRegistrationManager.h @@ -161,12 +161,10 @@ class QXmppRegistrationManagerPrivate; ///

Filling out the registration form

/// /// Now you need to fill out the registration form. The server can close the connection during that -/// time. If that happens, QXmppClient::errorOccurred() is emitted with -/// QXmpp::StreamError::ConnectionTimeout as its parameter. That is due to some servers kicking -/// unauthorized clients after some time when the clients are inactive. That is often the case when -/// user interaction is required before the completed form is submitted to the server. In order to -/// support account creation for both servers closing the connection and servers keeping it open, -/// you need to handle those cases appropriately. +/// time. It is due to some servers kicking unauthorized clients after some time when the clients +/// are inactive. That is often the case when user interaction is required before the completed form +/// is submitted to the server. In order to account creation for both servers closing the +/// connection and servers keeping it open, you need to handle those cases appropriately. /// /// If the returned IQ contains a data form, that can be displayed to a user or /// can be filled out in another way.