diff options
| author | Linus Jahn <lnj@kaidan.im> | 2019-06-25 18:57:43 +0200 |
|---|---|---|
| committer | LNJ <lnj@kaidan.im> | 2020-02-04 13:07:23 +0100 |
| commit | 1580a6b1582171b7141b072b774faeb387671282 (patch) | |
| tree | 325eaf173de03f6f551aa1254270412240537dc4 /src/client/QXmppRegistrationManager.cpp | |
| parent | 4adbb82142d3830a7d9d71291895d918a7242e79 (diff) | |
| download | qxmpp-1580a6b1582171b7141b072b774faeb387671282.tar.gz | |
Add new QXmppRegistrationManager
Diffstat (limited to 'src/client/QXmppRegistrationManager.cpp')
| -rw-r--r-- | src/client/QXmppRegistrationManager.cpp | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/src/client/QXmppRegistrationManager.cpp b/src/client/QXmppRegistrationManager.cpp new file mode 100644 index 00000000..48cd3d47 --- /dev/null +++ b/src/client/QXmppRegistrationManager.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2008-2020 The QXmpp developers + * + * Author: + * Melvin Keskin + * Linus Jahn + * + * Source: + * https://github.com/qxmpp-project/qxmpp + * + * This file is a part of QXmpp library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#include "QXmppRegistrationManager.h" + +#include "QXmppClient.h" +#include "QXmppConstants_p.h" +#include "QXmppDiscoveryManager.h" +#include "QXmppRegisterIq.h" +#include "QXmppStreamFeatures.h" +#include "QXmppUtils.h" + +#include <QDomElement> + +class QXmppRegistrationManagerPrivate +{ +public: + QXmppRegistrationManagerPrivate(); + + // whether to block login and request the registration form on connect + bool registerOnConnectEnabled; + // whether the server supports registration (after login) + bool supportedByServer; + + // caching + QString changePasswordIqId; + QString newPassword; + + QString registrationIqId; + + QXmppRegisterIq registrationFormToSend; +}; + +QXmppRegistrationManagerPrivate::QXmppRegistrationManagerPrivate() + : registerOnConnectEnabled(false), + supportedByServer(false) +{ +} + +/// +/// Default constructor. +/// +QXmppRegistrationManager::QXmppRegistrationManager() + : d(new QXmppRegistrationManagerPrivate) +{ +} + +QXmppRegistrationManager::~QXmppRegistrationManager() = default; + +/// +/// This adds the \c jabber:iq:register namespace to the features. +/// +QStringList QXmppRegistrationManager::discoveryFeatures() const +{ + return QStringList { + ns_register + }; +} + +/// +/// Changes the password of the user's account. +/// +/// \note Be sure to only call this when any previous requests have finished. +/// +/// \param newPassword The new password to be set. This must not be empty. +/// +void QXmppRegistrationManager::changePassword(const QString &newPassword) +{ + auto iq = QXmppRegisterIq::createChangePasswordRequest(client()->configuration().user(), newPassword); + + d->changePasswordIqId = iq.id(); + d->newPassword = newPassword; + + client()->sendPacket(iq); +} + +/// +/// Cancels an existing registration on the server. +/// +/// \returns The ID of the sent IQ, if it was sent successfully. A null string +/// is returned otherwise. +/// +QString QXmppRegistrationManager::deleteAccount() +{ + auto iq = QXmppRegisterIq::createUnregistrationRequest(); + + if (client()->sendPacket(iq)) + return iq.id(); + return {}; +} + +bool QXmppRegistrationManager::supportedByServer() const +{ + return d->supportedByServer; +} + +/// +/// Requests the registration form for registering. +/// +/// \param service The service which the registration form should be requested +/// from. If left empty, this will default to the local server. +/// +void QXmppRegistrationManager::requestRegistrationForm(const QString &service) +{ + QXmppRegisterIq iq; + iq.setType(QXmppIq::Get); + iq.setTo(service); + client()->sendPacket(iq); +} + +/// +/// Sets a registration form to be sent on the next connect with the server. +/// \param iq The completed registration form. +/// +void QXmppRegistrationManager::setRegistrationFormToSend(const QXmppRegisterIq &iq) +{ + d->registrationFormToSend = iq; +} + +/// +/// Sets a registration form to be sent on the next connect with the server. +/// \param dataForm The completed data form for registration. +/// +void QXmppRegistrationManager::setRegistrationFormToSend(const QXmppDataForm &dataForm) +{ + d->registrationFormToSend = QXmppRegisterIq(); + d->registrationFormToSend.setForm(dataForm); +} + +/// +/// Sends a completed registration form that was previously set using +/// setRegistrationFormToSend(). +/// +/// You usually only need to set the form and the manager will automatically +/// send it when connected. More details can be found in the documentation of +/// the QXmppRegistrationManager. +/// +void QXmppRegistrationManager::sendCachedRegistrationForm() +{ + if (!d->registrationFormToSend.form().isNull()) + d->registrationFormToSend.form().setType(QXmppDataForm::Submit); + + d->registrationFormToSend.setType(QXmppIq::Set); + + client()->sendPacket(d->registrationFormToSend); + d->registrationIqId = d->registrationFormToSend.id(); + + // clear cache + d->registrationFormToSend = QXmppRegisterIq(); +} + +/// +/// Returns whether to only request the registration form and not to connect +/// with username/password. +/// +bool QXmppRegistrationManager::registerOnConnectEnabled() const +{ + return d->registerOnConnectEnabled; +} + +/// +/// Sets whether to only request the registration form and not to connect with +/// username/password. +/// +/// \param enabled true to register, false to connect normally. +/// +void QXmppRegistrationManager::setRegisterOnConnectEnabled(bool enabled) +{ + d->registerOnConnectEnabled = enabled; +} + +/// \cond +bool QXmppRegistrationManager::handleStanza(const QDomElement &stanza) +{ + if (d->registerOnConnectEnabled && QXmppStreamFeatures::isStreamFeatures(stanza)) { + QXmppStreamFeatures features; + features.parse(stanza); + + if (features.registerMode() == QXmppStreamFeatures::Disabled) { + warning(QStringLiteral("Could not request the registration form, because the server does not advertise the register stream feature.")); + client()->disconnectFromServer(); + emit registrationFailed({ QXmppStanza::Error::Cancel, + QXmppStanza::Error::FeatureNotImplemented, + QStringLiteral("The server does not advertise the register stream feature.") }); + return true; + } + + if (!d->registrationFormToSend.form().isNull() || !d->registrationFormToSend.username().isNull()) { + info(QStringLiteral("Sending completed form.")); + sendCachedRegistrationForm(); + return true; + } + + info(QStringLiteral("Requesting registration form from server.")); + requestRegistrationForm(); + return true; + } + + if (stanza.tagName() == "iq") { + const QString &id = stanza.attribute(QStringLiteral("id")); + + if (!id.isEmpty() && id == d->registrationIqId) { + QXmppIq iq; + iq.parse(stanza); + + switch (iq.type()) { + case QXmppIq::Result: + info(QStringLiteral("Successfully registered with the service.")); + emit registrationSucceeded(); + case QXmppIq::Error: + warning(QStringLiteral("Registering with the service failed: ").append(iq.error().text())); + emit registrationFailed(iq.error()); + default: + break; // should never occur + } + + d->registrationIqId.clear(); + return true; + } else if (!id.isEmpty() && id == d->changePasswordIqId) { + QXmppIq iq; + iq.parse(stanza); + + switch (iq.type()) { + case QXmppIq::Result: + info(QStringLiteral("Changed password successfully.")); + client()->configuration().setPassword(d->newPassword); + emit passwordChanged(d->newPassword); + break; + case QXmppIq::Error: + warning(QStringLiteral("Failed to change password: ").append(iq.error().text())); + emit passwordChangeFailed(iq.error()); + break; + default: + break; // should never occur + } + + d->changePasswordIqId.clear(); + d->newPassword.clear(); + return true; + } else if (QXmppRegisterIq::isRegisterIq(stanza)) { + QXmppRegisterIq iq; + iq.parse(stanza); + + emit registrationFormReceived(iq); + } + } + return false; +} +/// \endcond + +void QXmppRegistrationManager::setClient(QXmppClient *client) +{ + QXmppClientExtension::setClient(client); + // get service discovery manager + auto *disco = client->findExtension<QXmppDiscoveryManager>(); + if (disco) { + connect(disco, &QXmppDiscoveryManager::infoReceived, this, &QXmppRegistrationManager::handleDiscoInfo); + } + + connect(client, &QXmppClient::disconnected, [=]() { + setSupportedByServer(false); + }); +} + +void QXmppRegistrationManager::handleDiscoInfo(const QXmppDiscoveryIq &iq) +{ + // check features of own server + if (iq.from().isEmpty() || iq.from() == client()->configuration().domain()) { + if (iq.features().contains(ns_register)) + setSupportedByServer(true); + } +} + +void QXmppRegistrationManager::setSupportedByServer(bool registrationSupported) +{ + if (d->supportedByServer != registrationSupported) { + d->supportedByServer = registrationSupported; + emit supportedByServerChanged(); + } +} |
