QXmppRegistrationManager Class

The QXmppRegistrationManager class manages in-band registration and account management tasks like changing the password as defined in XEP-0077: In-Band Registration. More...

Header: #include <QXmppRegistrationManager.h>
Since: QXmpp 1.2
Inherits: QXmppClientExtension

Properties

Public Functions

QXmppRegistrationManager()
void changePassword(const QString &newPassword)
void deleteAccount()
bool registerOnConnectEnabled() const
void requestRegistrationForm(const QString &service = {})
void sendCachedRegistrationForm()
void setRegisterOnConnectEnabled(bool enabled)
void setRegistrationFormToSend(const QXmppDataForm &dataForm)
void setRegistrationFormToSend(const QXmppRegisterIq &iq)
bool supportedByServer() const

Reimplemented Public Functions

virtual QStringList discoveryFeatures() const override

Signals

void accountDeleted()
void accountDeletionFailed(QXmppStanza::Error error)
void passwordChangeFailed(QXmppStanza::Error error)
void passwordChanged(const QString &newPassword)
void registrationFailed(const QXmppStanza::Error &error)
void registrationFormReceived(const QXmppRegisterIq &iq)
void registrationSucceeded()
void supportedByServerChanged()

Detailed Description

<h3 id="activation">Activating the manager</h3>

To make use of this manager, you need to instantiate it and load it into the QXmppClient instance as follows:

auto *registrationManager = new QXmppRegistrationManager;
client->addExtension(registrationManager);

<h3>Setting up service discovery correctly for this manager</h3>

This manager automatically recognizes whether the local server supports XEP-0077: In-Band Registration. As soon as the result is retrieved, the supportedByServer() property should be correct and could be used to display the user whether account management tasks can be performed on this server.

However, this is not relevant if you only want to <a href="#register-account">register a new account on a server</a>.

<h3>Changing the account's password</h3>

To change the password of the current account changePassword() can be used. Upon that either passwordChanged() or passwordChangeFailed() is emitted.

If changing the password was successful, the new password is automatically set in the QXmppClient::configuration(), so reconnecting works properly.

Example:

auto *registrationManager = client->findExtension<QXmppRegistrationManager>();
connect(registrationManager, &QXmppRegistrationManager::passwordChanged, [=](const QString &newPassword) {
qDebug() << "Password changed to:" << newPassword;
});
connect(registrationManager, &QXmppRegistrationManager::passwordChangeFailed, [=](QXmppStanza::Error error) {
qDebug() << "Couldn't change the password:" << error.text();
});

registrationManager->changePassword(client->configuration().user(), "m1cr0$0ft");

<h3>Unregistration with the server</h3>

If you want to delete your account on the server, you can do that using deleteAccount(). When the result is received either accountDeleted() or accountDeletionFailed() is emitted. In case it was successful, the manager automatically disconnects from the client. If the server takes too much time to confirm the account deletion, you may disconnect manually after a reasonable timeout.

QXmpp periodically sends pings to the server. If the server does not respond to it within QXmppConfiguration::keepAliveInterval(), QXmpp disconnects from the server. Make sure to handle that case if it happens during account deletion. E.g., you could try to connect to the server again with the same account and check whether QXmpp::AuthenticationError::NotAuthorized occurs. In that case, the account can be considered as deleted.

auto *registrationManager = client->findExtension<QXmppRegistrationManager>();
connect(registrationManager, &QXmppRegistrationManager::accountDeleted, [=]() {
qDebug() << "Account deleted successfully, the client is disconnecting now";
});
connect(registrationManager, &QXmppRegistrationManager::accountDeletionFailed, [=](QXmppStanza::Error error) {
qDebug() << "Couldn't delete account:" << error.text();
});
registrationManager->deleteAccount();

<h3 id="register-account">Registering with a server</h3>

Registering with a server consists of multiple steps:

  1. Requesting the registration form from the server.
  2. Filling out the registration form.
  3. Sending the completed form to the server. On failure (e.g. because of a username conflict), the process continues at step 1 again.
  4. Connecting with the newly created account.

<h4>Requesting the registration form from the server</h4>

First of all, you need to enable the registration process in the registration manager, which of course needs to be <a href="#activation"> activated</a> in the client.

auto *registrationManager = client->findExtension<QXmppRegistrationManager>();
registrationManager->setRegisterOnConnectEnabled(true);

After that you can start to connect to the server you want to register with. No JID is set in the QXmppConfiguration for the client and instead only the server is set.

QXmppConfiguration config;
config.setDomain("example.org");

client->connectToServer(config);

Alternatively, you can also provide a domain-only JID and no password to connectToServer():

client->connectToServer("example.org", QString());

Now as soon as (START)TLS was handled, the registration manager interrupts the normal connection process. The manager checks whether the server supports in-band registration and whether the server advertises this as a stream feature.

If the server does not support in-band registration, the manager will abort the connection at this point and emit the registrationFailed() signal with a fixed QXmppStanza::Error of type QXmppStanza::Error::Cancel and with a condition of QXmppStanza::Error::FeatureNotImplemented.

The manager will now request the registration form. This will either result in an error (reported by registrationFailed()) or, if everything went well, the registration form is reported by registrationFormReceived().

To handle everything correctly, you need to connect to both signals:

connect(registrationManager, &QXmppRegistrationManager::registrationFormReceived, [=](const QXmppRegisterIq &iq) {
qDebug() << "Form received:" << iq.instructions().
// you now need to complete the form
});
connect(registrationManager, &QXmppRegistrationManager::registrationFailed, [=](const QXmppStanza::Error &error) {
qDebug() << "Requesting the registration form failed:" << error.text();
});

<h4>Filling out the registration form</h4>

Now you need to fill out the registration form. The server can close the connection during that 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 support 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.

If the server does not support data forms, you can check the standard fields of the QXmppRegisterIq. You need to search the fields for empty (non-null) strings. All fields that contain an empty string are required and can be filled out. You can just set values for those fields and send the form as described in the next step.

Note: QXmpp currently has only implemented the most important default fields in the QXmppRegisterIq. The other fields are not very widespread, because data forms are usually used for such purposes.

<h4>Sending the completed form to the server</h4>

<b>Option A</b>: If the connection is still open once the form is filled out, set the form using setRegistrationFormToSend() and then trigger the form to be directly sent using sendCachedRegistrationForm().

registrationManager->setRegistrationFormToSend(completedForm);
registrationManager->sendCachedRegistrationForm();

<b>Option B</b>: If the connection is closed before the form is filled out, set the form using setRegistrationFormToSend() and connect to the server again. The registration manager will automatically send the set form once connected.

registrationManager->setRegistrationFormToSend(completedForm);

// As before, you only need to provide a domain to connectToServer()
client->connectToServer(...);
// the registration manager sends the form automatically

The form is now sent to the server. As soon as the result is received, either registrationSucceeded() or registrationFailed() is emitted.

In case there was a conflict or another error, you should request a new form and restart the process. This is especially important, if the form can only be used once as with most CAPTCHA implementations.

<h4>Connecting with the newly created account</h4>

You need to disconnect now. The user can then enter their credentials and connect as usual.

It is also possible to extract username and password from the sent form, but that does not work always. There might also be forms that have no clear username or password fields.

Property Documentation

[read-only] supportedByServer : bool

Whether support of XEP-0077: In-band Registration has been discovered on the server.

Access functions:

bool supportedByServer() const

Notifier signal:

Member Function Documentation

QXmppRegistrationManager::QXmppRegistrationManager()

Default constructor.

[signal] void QXmppRegistrationManager::accountDeleted()

Emitted, when the account was deleted successfully.

[signal] void QXmppRegistrationManager::accountDeletionFailed(QXmppStanza::Error error)

Emitted, when the account could not be deleted.

error.

void QXmppRegistrationManager::changePassword(const QString &newPassword)

Changes the password of the user's account to newPassword. newPassword must not be empty.

Note: Be sure to only call this when any previous requests have finished.

void QXmppRegistrationManager::deleteAccount()

Cancels an existing registration on the server.

See also accountDeleted() and accountDeletionFailed().

[override virtual] QStringList QXmppRegistrationManager::discoveryFeatures() const

Reimplements: QXmppClientExtension::discoveryFeatures() const.

This adds the jabber:iq:register namespace to the features.

[signal] void QXmppRegistrationManager::passwordChangeFailed(QXmppStanza::Error error)

Emitted, when changing the password did not succeed. error is the error returned from the service.

[signal] void QXmppRegistrationManager::passwordChanged(const QString &newPassword)

Emitted, when the password of the account was changed successfully.

The new password is automatically set in QXmppClient::configuration().

newPassword is the new password that was set on the server.

bool QXmppRegistrationManager::registerOnConnectEnabled() const

Returns whether to only request the registration form and not to connect with username/password.

See also setRegisterOnConnectEnabled().

[signal] void QXmppRegistrationManager::registrationFailed(const QXmppStanza::Error &error)

Emitted, when the registration failed.

error is the returned error from the service. The reported errors might be different from server to server, but the common ones are the following:

  • type=Cancel and condition=Conflict: The username already exists.
  • type=Cancel and condition=NotAllowed: The CAPTCHA verification failed.
  • type=Modify and condition=NotAcceptable: Some required information was missing or the selected password was too weak.
  • type=Modify and condition=JidMalformed: No username was provided or the username has an illegal format.

[signal] void QXmppRegistrationManager::registrationFormReceived(const QXmppRegisterIq &iq)

Emitted, when a registration form has been received.

iq is the received form. If it does not contain a valid data form (see QXmppRegisterIq::form()), the required fields should be marked by empty (but not null) strings in the QXmppRegisterIq (i.e. QXmppRegisterIq::password().isNull() => false).

[signal] void QXmppRegistrationManager::registrationSucceeded()

Emitted, when the registration with a service completed successfully.

To connect with the account you still need to set the correct credentials in QXmppClient::configuration() and reconnect.

void QXmppRegistrationManager::requestRegistrationForm(const QString &service = {})

Requests the registration form for registering.

service is the service from which the registration form should be requested. If left empty, this will default to the local server.

void QXmppRegistrationManager::sendCachedRegistrationForm()

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::setRegisterOnConnectEnabled(bool enabled)

Sets whether to only request the registration form and not to connect with username/password. Set enabled to true to register, false to connect normally.

See also registerOnConnectEnabled().

void QXmppRegistrationManager::setRegistrationFormToSend(const QXmppDataForm &dataForm)

Sets the completed data form dataForm for registration to be sent on the next connect with the server.

void QXmppRegistrationManager::setRegistrationFormToSend(const QXmppRegisterIq &iq)

Sets the completed registration form iq to be sent on the next connect with the server.

bool QXmppRegistrationManager::supportedByServer() const

Returns whether the server supports registration.

By default this is set to false and only changes, if you request the service discovery info of the connected server using QXmppDiscoveryManager::requestInfo().

This is only relevant to actions that happen after authentication.

Note: Getter function for property supportedByServer.

See also QXmppRegistrationManager::supportedByServerChanged().

[signal] void QXmppRegistrationManager::supportedByServerChanged()

Emitted, when registrationSupported() changed.

This can happen after the service discovery info of the server was retrieved using QXmppDiscoveryManager::requestInfo() or on disconnect.

Note: Notifier signal for property supportedByServer.