aboutsummaryrefslogtreecommitdiff
path: root/src/client/QXmppTransferManager.h
blob: 4ab0d237eb85a2d069c714d7007ea8088305562e (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
// SPDX-FileCopyrightText: 2010 Jeremy Lainé <jeremy.laine@m4x.org>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#ifndef QXMPPTRANSFERMANAGER_H
#define QXMPPTRANSFERMANAGER_H

#include "QXmppClientExtension.h"

#include <QDateTime>
#include <QSharedData>
#include <QUrl>
#include <QVariant>

class QTcpSocket;
class QXmppByteStreamIq;
class QXmppIbbCloseIq;
class QXmppIbbDataIq;
class QXmppIbbOpenIq;
class QXmppIq;
class QXmppStreamInitiationIq;
class QXmppTransferFileInfoPrivate;
class QXmppTransferJobPrivate;
class QXmppTransferManager;
class QXmppTransferManagerPrivate;

class QXMPP_EXPORT QXmppTransferFileInfo
{
public:
    QXmppTransferFileInfo();
    QXmppTransferFileInfo(const QXmppTransferFileInfo &other);
    ~QXmppTransferFileInfo();

    QDateTime date() const;
    void setDate(const QDateTime &date);

    QByteArray hash() const;
    void setHash(const QByteArray &hash);

    QString name() const;
    void setName(const QString &name);

    QString description() const;
    void setDescription(const QString &description);

    qint64 size() const;
    void setSize(qint64 size);

    bool isNull() const;
    QXmppTransferFileInfo &operator=(const QXmppTransferFileInfo &other);
    bool operator==(const QXmppTransferFileInfo &other) const;

    /// \cond
    void parse(const QDomElement &element);
    void toXml(QXmlStreamWriter *writer) const;
    /// \endcond

private:
    QSharedDataPointer<QXmppTransferFileInfoPrivate> d;
};

class QXMPP_EXPORT QXmppTransferJob : public QXmppLoggable
{
    Q_OBJECT
    Q_FLAGS(Method Methods)
    /// The job's transfer direction
    Q_PROPERTY(Direction direction READ direction CONSTANT)
    /// The local file URL
    Q_PROPERTY(QUrl localFileUrl READ localFileUrl WRITE setLocalFileUrl NOTIFY localFileUrlChanged)
    /// The remote party's JID
    Q_PROPERTY(QString jid READ jid CONSTANT)
    /// The job's transfer method
    Q_PROPERTY(Method method READ method CONSTANT)
    /// The job's state
    Q_PROPERTY(State state READ state NOTIFY stateChanged)

    /// The name of the file
    Q_PROPERTY(QString fileName READ fileName CONSTANT)
    /// The size of the file
    Q_PROPERTY(qint64 fileSize READ fileSize CONSTANT)

public:
    /// This enum is used to describe the direction of a transfer job.
    enum Direction {
        IncomingDirection,  ///< The file is being received.
        OutgoingDirection   ///< The file is being sent.
    };
    Q_ENUM(Direction)

    /// This enum is used to describe the type of error encountered by a transfer job.
    enum Error {
        NoError = 0,       ///< No error occurred.
        AbortError,        ///< The file transfer was aborted.
        FileAccessError,   ///< An error was encountered trying to access a local file.
        FileCorruptError,  ///< The file is corrupt: the file size or hash do not match.
        ProtocolError      ///< An error was encountered in the file transfer protocol.
    };
    Q_ENUM(Error)

    /// This enum is used to describe a transfer method.
    enum Method {
        NoMethod = 0,      ///< No transfer method.
        InBandMethod = 1,  ///< \xep{0047}: In-Band Bytestreams
        SocksMethod = 2,   ///< \xep{0065}: SOCKS5 Bytestreams
        AnyMethod = 3      ///< Any supported transfer method.
    };
    Q_ENUM(Method)
    Q_DECLARE_FLAGS(Methods, Method)

    /// This enum is used to describe the state of a transfer job.
    enum State {
        OfferState = 0,     ///< The transfer is being offered to the remote party.
        StartState = 1,     ///< The transfer is being connected.
        TransferState = 2,  ///< The transfer is ongoing.
        FinishedState = 3   ///< The transfer is finished.
    };
    Q_ENUM(State)

    ~QXmppTransferJob() override;

    // documentation needs to be here, see https://stackoverflow.com/questions/49192523/
    /// Returns the job's transfer direction.
    QXmppTransferJob::Direction direction() const;
    /// Returns the remote party's JID.
    QString jid() const;
    /// Returns the job's transfer method.
    QXmppTransferJob::Method method() const;
    /// Returns the job's state.
    QXmppTransferJob::State state() const;

    QXmppTransferJob::Error error() const;
    QString sid() const;
    qint64 speed() const;

    // XEP-0096 : File transfer
    QXmppTransferFileInfo fileInfo() const;
    // documentation needs to be here, see https://stackoverflow.com/questions/49192523/
    /// Returns the local file URL.
    QUrl localFileUrl() const;
    void setLocalFileUrl(const QUrl &localFileUrl);

    /// \cond
    QDateTime fileDate() const;
    QByteArray fileHash() const;
    QString fileName() const;
    qint64 fileSize() const;
    /// \endcond

Q_SIGNALS:
    /// This signal is emitted when an error is encountered while
    /// processing the transfer job.
    void error(QXmppTransferJob::Error error);

    /// This signal is emitted when the transfer job is finished.
    ///
    /// You can determine if the job completed successfully by testing whether
    /// error() returns QXmppTransferJob::NoError.
    ///
    /// Note: Do not delete the job in the slot connected to this signal,
    /// instead use deleteLater().
    void finished();

    /// This signal is emitted when the local file URL changes.
    void localFileUrlChanged(const QUrl &localFileUrl);

    /// This signal is emitted to indicate the progress of this transfer job.
    void progress(qint64 done, qint64 total);

    /// This signal is emitted when the transfer job changes state.
    void stateChanged(QXmppTransferJob::State state);

public Q_SLOTS:
    void abort();
    void accept(const QString &filePath);
    void accept(QIODevice *output);

private Q_SLOTS:
    void _q_terminated();

private:
    QXmppTransferJob(const QString &jid, QXmppTransferJob::Direction direction, QXmppClient *client, QObject *parent);
    void setState(QXmppTransferJob::State state);
    void terminate(QXmppTransferJob::Error error);

    const std::unique_ptr<QXmppTransferJobPrivate> d;
    friend class QXmppTransferManager;
    friend class QXmppTransferManagerPrivate;
    friend class QXmppTransferIncomingJob;
    friend class QXmppTransferOutgoingJob;
};

class QXMPP_EXPORT QXmppTransferManager : public QXmppClientExtension
{
    Q_OBJECT

    /// The JID of the bytestream proxy to use for outgoing transfers
    Q_PROPERTY(QString proxy READ proxy WRITE setProxy)
    /// Whether the proxy will systematically be used for outgoing SOCKS5 bytestream transfers
    Q_PROPERTY(bool proxyOnly READ proxyOnly WRITE setProxyOnly)
    /// The supported stream methods
    Q_PROPERTY(QXmppTransferJob::Methods supportedMethods READ supportedMethods WRITE setSupportedMethods)

public:
    QXmppTransferManager();
    ~QXmppTransferManager() override;

    // documentation needs to be here, see https://stackoverflow.com/questions/49192523/
    /// Return the JID of the bytestream proxy to use for outgoing transfers.
    QString proxy() const;
    void setProxy(const QString &proxyJid);

    // documentation needs to be here, see https://stackoverflow.com/questions/49192523/
    /// Return whether the proxy will systematically be used for outgoing
    /// SOCKS5 bytestream transfers.
    bool proxyOnly() const;
    void setProxyOnly(bool proxyOnly);

    // documentation needs to be here, see https://stackoverflow.com/questions/49192523/
    /// Return the supported stream methods.
    ///
    /// The methods are a combination of zero or more QXmppTransferJob::Method.
    QXmppTransferJob::Methods supportedMethods() const;
    void setSupportedMethods(QXmppTransferJob::Methods methods);

    /// \cond
    QStringList discoveryFeatures() const override;
    bool handleStanza(const QDomElement &element) override;
    /// \endcond

Q_SIGNALS:
    /// This signal is emitted when a new file transfer offer is received.
    ///
    /// To accept the transfer job, call the job's QXmppTransferJob::accept() method.
    /// To refuse the transfer job, call the job's QXmppTransferJob::abort() method.
    void fileReceived(QXmppTransferJob *job);

    /// This signal is emitted whenever a transfer job is started.
    void jobStarted(QXmppTransferJob *job);

    /// This signal is emitted whenever a transfer job is finished.
    ///
    /// \sa QXmppTransferJob::finished()
    void jobFinished(QXmppTransferJob *job);

public Q_SLOTS:
    QXmppTransferJob *sendFile(const QString &jid, const QString &filePath, const QString &description = QString());
    QXmppTransferJob *sendFile(const QString &jid, QIODevice *device, const QXmppTransferFileInfo &fileInfo, const QString &sid = QString());

protected:
    /// \cond
    void setClient(QXmppClient *client) override;
    /// \endcond

private Q_SLOTS:
    void _q_iqReceived(const QXmppIq &);
    void _q_jobDestroyed(QObject *object);
    void _q_jobError(QXmppTransferJob::Error error);
    void _q_jobFinished();
    void _q_jobStateChanged(QXmppTransferJob::State state);
    void _q_socksServerConnected(QTcpSocket *socket, const QString &hostName, quint16 port);

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

    void byteStreamIqReceived(const QXmppByteStreamIq &);
    void byteStreamResponseReceived(const QXmppIq &);
    void byteStreamResultReceived(const QXmppByteStreamIq &);
    void byteStreamSetReceived(const QXmppByteStreamIq &);
    void ibbCloseIqReceived(const QXmppIbbCloseIq &);
    void ibbDataIqReceived(const QXmppIbbDataIq &);
    void ibbOpenIqReceived(const QXmppIbbOpenIq &);
    void ibbResponseReceived(const QXmppIq &);
    void streamInitiationIqReceived(const QXmppStreamInitiationIq &);
    void streamInitiationResultReceived(const QXmppStreamInitiationIq &);
    void streamInitiationSetReceived(const QXmppStreamInitiationIq &);
    void socksServerSendOffer(QXmppTransferJob *job);

    friend class QXmppTransferManagerPrivate;
};

Q_DECLARE_OPERATORS_FOR_FLAGS(QXmppTransferJob::Methods)

#endif