Skip to content

Commit

Permalink
Set errors to be ignored during account creation/deletion
Browse files Browse the repository at this point in the history
Some servers close the connection during account creation with a
<connection-timeout/> stream error which can be ignored.

https://xmpp.org/extensions/xep-0077.html#usecases-cancel specifies the
usage of the stream error <not-authorized/>.
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 <conflict> stream error is now handled as well since some servers send
it instead of the <not-authorized/> stream error.

The KeepAliveError was emitted during testing between requesting the deletion
of an account and the server's response.
That seems to be due to an XMPP ping that could not be handled appropriately
by the server.
The error is now handled as a response to a successful account deletion.
  • Loading branch information
melvo committed Dec 2, 2023
1 parent d53d6f9 commit aa4a8de
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 5 deletions.
20 changes: 20 additions & 0 deletions src/client/QXmppClient.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2009 Manjeet Dahiya <[email protected]>
// SPDX-FileCopyrightText: 2023 Melvin Keskin <[email protected]>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

Expand Down Expand Up @@ -891,6 +892,18 @@ bool QXmppClient::injectMessage(QXmppMessage &&message)
return handled;
}

///
/// Sets errors that are ignored if they occur.
///
/// \param ignoredErrors errors to be ignored
///
/// \since QXmpp 1.6
///
void QXmppClient::setIgnoredErrors(const QMap<QXmppClient::Error, QVector<QXmppStanza::Error::Condition>> &ignoredErrors)
{
d->ignoredErrors = ignoredErrors;
}

///
/// Give extensions a chance to handle incoming stanzas.
///
Expand Down Expand Up @@ -943,6 +956,13 @@ void QXmppClient::_q_streamDisconnected()

void QXmppClient::_q_streamError(QXmppClient::Error err)
{
// SKip errors that are valid during special procedures such as account creation/deletion.
if (d->ignoredErrors.contains(err) &&
(err != QXmppClient::XmppStreamError ||
d->ignoredErrors.value(err).contains(d->stream->xmppStreamError()))) {
return;
}

if (d->stream->configuration().autoReconnectionEnabled()) {
if (err == QXmppClient::XmppStreamError) {
// if we receive a resource conflict, inhibit reconnection
Expand Down
4 changes: 4 additions & 0 deletions src/client/QXmppClient.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2009 Manjeet Dahiya <[email protected]>
// SPDX-FileCopyrightText: 2023 Melvin Keskin <[email protected]>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

Expand Down Expand Up @@ -325,6 +326,8 @@ public Q_SLOTS:
void injectIq(const QDomElement &element, const std::optional<QXmppE2eeMetadata> &e2eeMetadata);
bool injectMessage(QXmppMessage &&message);

void setIgnoredErrors(const QMap<QXmppClient::Error, QVector<QXmppStanza::Error::Condition>> &ignoredErrors);

private Q_SLOTS:
void _q_elementReceived(const QDomElement &element, bool &handled);
void _q_reconnect();
Expand All @@ -339,6 +342,7 @@ private Q_SLOTS:
friend class QXmppClientExtension;
friend class QXmppInternalClientExtension;
friend class TestClient;
friend class QXmppRegistrationManager;
};

#endif // QXMPPCLIENT_H
4 changes: 3 additions & 1 deletion src/client/QXmppClient_p.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-FileCopyrightText: 2020 Manjeet Dahiya <[email protected]>
// SPDX-FileCopyrightText: 2020 Linus Jahn <[email protected]>
// SPDX-FileCopyrightText: 2023 Melvin Keskin <[email protected]>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

Expand All @@ -18,9 +19,9 @@
#ifndef QXMPPCLIENT_P_H
#define QXMPPCLIENT_P_H

#include "QXmppClient.h"
#include "QXmppPresence.h"

class QXmppClient;
class QXmppClientExtension;
class QXmppE2eeExtension;
class QXmppLogger;
Expand All @@ -38,6 +39,7 @@ class QXmppClientPrivate
QXmppLogger *logger;
/// Pointer to the XMPP stream
QXmppOutgoingClient *stream;
QMap<QXmppClient::Error, QVector<QXmppStanza::Error::Condition>> ignoredErrors;

QXmppE2eeExtension *encryptionExtension;

Expand Down
17 changes: 16 additions & 1 deletion src/client/QXmppRegistrationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ void QXmppRegistrationManager::deleteAccount()
auto iq = QXmppRegisterIq::createUnregistrationRequest();
d->deleteAccountIqId = iq.id();

client()->setIgnoredErrors({ { QXmppClient::KeepAliveError, {} },
{ QXmppClient::XmppStreamError, { QXmppStanza::Error::Conflict, QXmppStanza::Error::NotAuthorized } } });
client()->sendPacket(iq);
}

Expand Down Expand Up @@ -170,6 +172,12 @@ bool QXmppRegistrationManager::registerOnConnectEnabled() const
void QXmppRegistrationManager::setRegisterOnConnectEnabled(bool enabled)
{
d->registerOnConnectEnabled = enabled;

if (enabled) {
client()->setIgnoredErrors({ { QXmppClient::XmppStreamError, { QXmppStanza::Error::ConnectionTimeout } } });
} else {
client()->setIgnoredErrors({});
}
}

/// \cond
Expand Down Expand Up @@ -282,8 +290,15 @@ void QXmppRegistrationManager::setClient(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->setIgnoredErrors({});

if (!d->deleteAccountIqId.isEmpty()) {
info(QStringLiteral("Account deleted successfully."));
Q_EMIT accountDeleted();
d->deleteAccountIqId.clear();
}
});
}

Expand Down
5 changes: 2 additions & 3 deletions src/client/QXmppRegistrationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,8 @@ class QXmppRegistrationManagerPrivate;
/// <h4>Filling out the registration form</h4>
///
/// Now you need to fill out the registration form. If that takes some time, which is often the case
/// when user interaction is required, the server can close the connection triggering
/// QXmppClient::error() to emit QXmppStanza::Error::ConnectionTimeout before the completed form is
/// submitted to the server. That is due to some servers kicking unauthorized clients after a few
/// when user interaction is required, the server can close the connection before the completed form
/// is submitted to the server. That is due to some servers kicking unauthorized clients after a few
/// seconds when they are inactive. In order to support account creation for both servers closing
/// the connection and servers keeping it open, you need to handle those cases appropriately.
///
Expand Down

0 comments on commit aa4a8de

Please sign in to comment.