aboutsummaryrefslogtreecommitdiff
path: root/src/client/QXmppRegistrationManager.cpp
diff options
context:
space:
mode:
authorLinus Jahn <lnj@kaidan.im>2019-06-25 18:57:43 +0200
committerLNJ <lnj@kaidan.im>2020-02-04 13:07:23 +0100
commit1580a6b1582171b7141b072b774faeb387671282 (patch)
tree325eaf173de03f6f551aa1254270412240537dc4 /src/client/QXmppRegistrationManager.cpp
parent4adbb82142d3830a7d9d71291895d918a7242e79 (diff)
downloadqxmpp-1580a6b1582171b7141b072b774faeb387671282.tar.gz
Add new QXmppRegistrationManager
Diffstat (limited to 'src/client/QXmppRegistrationManager.cpp')
-rw-r--r--src/client/QXmppRegistrationManager.cpp301
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();
+ }
+}