aboutsummaryrefslogtreecommitdiff
path: root/src/client/QXmppClient.h
blob: 31a990306ee7e1c88fb2e6eb518a4546af30e23e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
// SPDX-FileCopyrightText: 2009 Manjeet Dahiya <manjeetdahiya@gmail.com>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#ifndef QXMPPCLIENT_H
#define QXMPPCLIENT_H

#include "QXmppConfiguration.h"
#include "QXmppLogger.h"
#include "QXmppPresence.h"
#include "QXmppSendResult.h"
#include "QXmppSendStanzaParams.h"

#include <memory>
#include <variant>

#include <QAbstractSocket>
#include <QObject>
#include <QSslError>

template<typename T>
class QXmppTask;

class QXmppE2eeExtension;
class QXmppClientExtension;
class QXmppClientPrivate;
class QXmppPresence;
class QXmppMessage;
class QXmppIq;
class QXmppStream;
class QXmppInternalClientExtension;

// managers
class QXmppDiscoveryIq;
class QXmppRosterManager;
class QXmppVCardManager;
class QXmppVersionManager;

///
/// \defgroup Core Core classes
///
/// Core classes include all necessary classes to build a basic client or
/// server application. This for example also includes the logging class
/// QXmppLogger.
///

///
/// \defgroup Managers Managers
///
/// Managers are used to extend the basic QXmppClient. Some of them are loaded
/// by default, others need to be added to the client using
/// QXmppClient::addExtension().
///

///
/// \brief The QXmppClient class is the main class for using QXmpp.
///
/// It provides the user all the required functionality to connect to the
/// server and perform operations afterwards.
///
/// This class will provide the handle/reference to QXmppRosterManager
/// (roster management), QXmppVCardManager (vCard manager), and
/// QXmppVersionManager (software version information).
///
/// By default, the client will automatically try reconnecting to the server.
/// You can change that behaviour using
/// QXmppConfiguration::setAutoReconnectionEnabled().
///
/// Not all the managers or extensions have been enabled by default. One can
/// enable/disable the managers using the functions \c addExtension() and
/// \c removeExtension(). \c findExtension() can be used to find a
/// reference/pointer to a particular instantiated and enabled manager.
///
/// List of managers enabled by default:
/// - QXmppRosterManager
/// - QXmppVCardManager
/// - QXmppVersionManager
/// - QXmppDiscoveryManager
/// - QXmppEntityTimeManager
///
/// \ingroup Core
///
class QXMPP_EXPORT QXmppClient : public QXmppLoggable
{
    Q_OBJECT

    /// The QXmppLogger associated with the current QXmppClient
    Q_PROPERTY(QXmppLogger *logger READ logger WRITE setLogger NOTIFY loggerChanged)
    /// The client's current state
    Q_PROPERTY(State state READ state NOTIFY stateChanged)

public:
    using IqResult = std::variant<QDomElement, QXmppError>;
    using EmptyResult = std::variant<QXmpp::Success, QXmppError>;

    /// An enumeration for type of error.
    /// Error could come due a TCP socket or XML stream or due to various stanzas.
    enum Error {
        NoError,          ///< No error.
        SocketError,      ///< Error due to TCP socket.
        KeepAliveError,   ///< Error due to no response to a keep alive.
        XmppStreamError,  ///< Error due to XML stream.
    };
    Q_ENUM(Error)

    /// This enumeration describes a client state.
    enum State {
        DisconnectedState,  ///< Disconnected from the server.
        ConnectingState,    ///< Trying to connect to the server.
        ConnectedState      ///< Connected to the server.
    };
    Q_ENUM(State)

    /// Describes the use of \xep{0198}: Stream Management
    enum StreamManagementState {
        /// Stream Management is not used.
        NoStreamManagement,
        /// Stream Management is used and the previous stream has not been resumed.
        NewStream,
        /// Stream Management is used and the previous stream has been resumed.
        ResumedStream
    };

    QXmppClient(QObject *parent = nullptr);
    ~QXmppClient() override;

    bool addExtension(QXmppClientExtension *extension);
    template<typename T, typename... Args>
    T *addNewExtension(Args... args)
    {
        // it's impossible that addExtension() returns false: ext is a new object
        auto *ext = new T(args...);
        addExtension(ext);
        return ext;
    }
    bool insertExtension(int index, QXmppClientExtension *extension);
    bool removeExtension(QXmppClientExtension *extension);
    QXmppE2eeExtension *encryptionExtension() const;
    void setEncryptionExtension(QXmppE2eeExtension *);

    QList<QXmppClientExtension *> extensions();

    ///
    /// \brief Returns the extension which can be cast into type T*, or 0
    /// if there is no such extension.
    ///
    /// Usage example:
    /// \code
    /// QXmppDiscoveryManager* ext = client->findExtension<QXmppDiscoveryManager>();
    /// if(ext)
    /// {
    ///     //extension found, do stuff...
    /// }
    /// \endcode
    ///
    template<typename T>
    T *findExtension()
    {
        const QList<QXmppClientExtension *> list = extensions();
        for (auto ext : list) {
            T *extension = qobject_cast<T *>(ext);
            if (extension) {
                return extension;
            }
        }
        return nullptr;
    }

    ///
    /// \brief Returns the index of an extension
    ///
    /// Usage example:
    /// \code
    /// int index = client->indexOfExtension<QXmppDiscoveryManager>();
    /// if (index > 0) {
    ///     // extension found, do stuff...
    /// } else {
    ///     // extension not found
    /// }
    /// \endcode
    ///
    /// \since QXmpp 1.2
    ///
    template<typename T>
    int indexOfExtension()
    {
        auto list = extensions();
        for (int i = 0; i < list.size(); ++i) {
            if (qobject_cast<T *>(list.at(i)) != nullptr) {
                return i;
            }
        }
        return -1;
    }

    bool isAuthenticated() const;
    bool isConnected() const;

    bool isActive() const;
    void setActive(bool active);

    StreamManagementState streamManagementState() const;

    QXmppPresence clientPresence() const;
    void setClientPresence(const QXmppPresence &presence);

    QXmppConfiguration &configuration();

    // documentation needs to be here, see https://stackoverflow.com/questions/49192523/
    /// Returns the QXmppLogger associated with the current QXmppClient.
    QXmppLogger *logger() const;
    void setLogger(QXmppLogger *logger);

    QAbstractSocket::SocketError socketError();
    QString socketErrorString() const;

    // documentation needs to be here, see https://stackoverflow.com/questions/49192523/
    /// Returns the client's current state.
    State state() const;
    QXmppStanza::Error::Condition xmppStreamError();

    QXmppTask<QXmpp::SendResult> sendSensitive(QXmppStanza &&, const std::optional<QXmppSendStanzaParams> & = {});
    QXmppTask<QXmpp::SendResult> send(QXmppStanza &&, const std::optional<QXmppSendStanzaParams> & = {});
    QXmppTask<QXmpp::SendResult> reply(QXmppStanza &&stanza, const std::optional<QXmppE2eeMetadata> &e2eeMetadata, const std::optional<QXmppSendStanzaParams> & = {});
    QXmppTask<IqResult> sendIq(QXmppIq &&, const std::optional<QXmppSendStanzaParams> & = {});
    QXmppTask<IqResult> sendSensitiveIq(QXmppIq &&, const std::optional<QXmppSendStanzaParams> & = {});
    QXmppTask<EmptyResult> sendGenericIq(QXmppIq &&, const std::optional<QXmppSendStanzaParams> & = {});

#if QXMPP_DEPRECATED_SINCE(1, 1)
    QT_DEPRECATED_X("Use QXmppClient::findExtension<QXmppRosterManager>() instead")
    QXmppRosterManager &rosterManager();

    QT_DEPRECATED_X("Use QXmppClient::findExtension<QXmppVCardManager>() instead")
    QXmppVCardManager &vCardManager();

    QT_DEPRECATED_X("Use QXmppClient::findExtension<QXmppVersionManager>() instead")
    QXmppVersionManager &versionManager();
#endif

Q_SIGNALS:

    /// This signal is emitted when the client connects successfully to the
    /// XMPP server i.e. when a successful XMPP connection is established.
    /// XMPP Connection involves following sequential steps:
    ///     - TCP socket connection
    ///     - Client sends start stream
    ///     - Server sends start stream
    ///     - TLS negotiation (encryption)
    ///     - Authentication
    ///     - Resource binding
    ///     - Session establishment
    ///
    /// After all these steps a successful XMPP connection is established and
    /// connected() signal is emitted.
    ///
    /// After the connected() signal is emitted QXmpp will send the roster
    /// request to the server. On receiving the roster, QXmpp will emit
    /// QXmppRosterManager::rosterReceived(). After this signal,
    /// QXmppRosterManager object gets populated and you can use
    /// \c findExtension<QXmppRosterManager>() to get the handle of
    /// QXmppRosterManager object.
    void connected();

    /// This signal is emitted when the XMPP connection disconnects.
    void disconnected();

    /// This signal is emitted when the XMPP connection encounters any error.
    /// The QXmppClient::Error parameter specifies the type of error occurred.
    /// It could be due to TCP socket or the xml stream or the stanza.
    /// Depending upon the type of error occurred use the respective get function to
    /// know the error.
    void error(QXmppClient::Error);

    /// This signal is emitted when the logger changes.
    void loggerChanged(QXmppLogger *logger);

    /// Notifies that an XMPP message stanza is received. The QXmppMessage
    /// parameter contains the details of the message sent to this client.
    /// In other words whenever someone sends you a message this signal is
    /// emitted.
    void messageReceived(const QXmppMessage &message);

    /// Notifies that an XMPP presence stanza is received. The QXmppPresence
    /// parameter contains the details of the presence sent to this client.
    /// This signal is emitted when someone login/logout or when someone's status
    /// changes Busy, Idle, Invisible etc.
    void presenceReceived(const QXmppPresence &presence);

    /// This signal is emitted when IQs of type result or error are received by
    /// the client and no registered QXmppClientExtension could handle it.
    ///
    /// This is useful when it is only important to check whether the response
    /// of an IQ was successful. However, the recommended way is still to use an
    /// additional QXmppClientExtension for this kind of tasks.
    void iqReceived(const QXmppIq &iq);

    /// This signal is emitted to indicate that one or more SSL errors were
    /// encountered while establishing the identity of the server.
    void sslErrors(const QList<QSslError> &errors);

    /// This signal is emitted when the client state changes.
    void stateChanged(QXmppClient::State state);

public Q_SLOTS:
    void connectToServer(const QXmppConfiguration &,
                         const QXmppPresence &initialPresence =
                             QXmppPresence());
    void connectToServer(const QString &jid,
                         const QString &password);
    void disconnectFromServer();
    bool sendPacket(const QXmppNonza &);
    void sendMessage(const QString &bareJid, const QString &message);

private:
    void injectIq(const QDomElement &element, const std::optional<QXmppE2eeMetadata> &e2eeMetadata);
    bool injectMessage(QXmppMessage &&message);

private Q_SLOTS:
    void _q_elementReceived(const QDomElement &element, bool &handled);
    void _q_reconnect();
    void _q_socketStateChanged(QAbstractSocket::SocketState state);
    void _q_streamConnected();
    void _q_streamDisconnected();
    void _q_streamError(QXmppClient::Error error);

private:
    const std::unique_ptr<QXmppClientPrivate> d;

    friend class QXmppClientExtension;
    friend class QXmppInternalClientExtension;
    friend class TestClient;
};

#endif  // QXMPPCLIENT_H