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..107f7f17f 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 @@ -258,8 +265,7 @@ bool QXmppRegistrationManager::handleStanza(const QDomElement &stanza) switch (iq.type()) { case QXmppIq::Result: - info(u"Account deleted successfully."_s); - Q_EMIT accountDeleted(); + handleAccountDeleted(); client()->disconnectFromServer(); break; case QXmppIq::Error: @@ -291,8 +297,14 @@ 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()) { + handleAccountDeleted(); + d->deleteAccountIqId.clear(); + } }); } @@ -319,3 +331,9 @@ void QXmppRegistrationManager::setSupportedByServer(bool registrationSupported) Q_EMIT supportedByServerChanged(); } } + +void QXmppRegistrationManager::handleAccountDeleted() +{ + info(u"Account deleted successfully."_s); + Q_EMIT accountDeleted(); +} diff --git a/src/client/QXmppRegistrationManager.h b/src/client/QXmppRegistrationManager.h index cf4033bba..3ef16de4d 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. @@ -339,11 +337,10 @@ class QXMPP_EXPORT QXmppRegistrationManager : public QXmppClientExtension void onRegistered(QXmppClient *client) override; void onUnregistered(QXmppClient *client) override; -private Q_SLOTS: - void handleDiscoInfo(const QXmppDiscoveryIq &iq); - private: + void handleDiscoInfo(const QXmppDiscoveryIq &iq); void setSupportedByServer(bool supportedByServer); + void handleAccountDeleted(); const std::unique_ptr d; };