diff options
| author | Linus Jahn <lnj@kaidan.im> | 2019-05-05 14:58:42 +0200 |
|---|---|---|
| committer | LNJ <lnj@kaidan.im> | 2019-10-20 17:01:35 +0200 |
| commit | 6b3e41ee933b260a80b3ec197c7e76a14eb4ba4a (patch) | |
| tree | 35b4af6bf99d5c22e55984ac54508fef2938b970 /src/client/QXmppUploadRequestManager.cpp | |
| parent | a4ac49e2e3c69ba2d42558fbfb52eaa931ca8e28 (diff) | |
| download | qxmpp-6b3e41ee933b260a80b3ec197c7e76a14eb4ba4a.tar.gz | |
Implement XEP-0363: HTTP File Upload: UploadRequestManager
This adds a manager to simplify service discovery and IQ sending for
XEP-0363: HTTP File Upload.
Diffstat (limited to 'src/client/QXmppUploadRequestManager.cpp')
| -rw-r--r-- | src/client/QXmppUploadRequestManager.cpp | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/src/client/QXmppUploadRequestManager.cpp b/src/client/QXmppUploadRequestManager.cpp new file mode 100644 index 00000000..09268637 --- /dev/null +++ b/src/client/QXmppUploadRequestManager.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2008-2019 The QXmpp developers + * + * Author: + * Linus Jahn <lnj@kaidan.im> + * + * 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 <QFileInfo> +#include <QMimeDatabase> + +#include "QXmppClient.h" +#include "QXmppConstants_p.h" +#include "QXmppDiscoveryManager.h" +#include "QXmppDiscoveryIq.h" +#include "QXmppDataForm.h" +#include "QXmppHttpUploadIq.h" + +#include "QXmppUploadRequestManager.h" + +class QXmppUploadServicePrivate : public QSharedData +{ +public: + QString jid; + qint64 sizeLimit = -1; +}; + +QXmppUploadService::QXmppUploadService() + : d(new QXmppUploadServicePrivate) +{ +} + +QXmppUploadService::QXmppUploadService(const QXmppUploadService &) = default; + +QXmppUploadService::~QXmppUploadService() = default; + +QXmppUploadService &QXmppUploadService::operator=(const QXmppUploadService &) = default; + +/// Returns the JID of the HTTP File Upload service. + +QString QXmppUploadService::jid() const +{ + return d->jid; +} + +/// Sets the JID of the HTTP File Upload service. + +void QXmppUploadService::setJid(const QString &jid) +{ + d->jid = jid; +} + +/// Returns the size limit of files that can be uploaded to this upload +/// service. +/// +/// A size limit of -1 means that there is no file size limit or it could not +/// be determined. + +qint64 QXmppUploadService::sizeLimit() const +{ + return d->sizeLimit; +} + +/// Sets the size limit of files that can be uploaded to this upload service. + +void QXmppUploadService::setSizeLimit(qint64 sizeLimit) +{ + d->sizeLimit = sizeLimit; +} + +class QXmppUploadRequestManagerPrivate : public QSharedData +{ +public: + QVector<QXmppUploadService> uploadServices; +}; + +QXmppUploadRequestManager::QXmppUploadRequestManager() + : d(new QXmppUploadRequestManagerPrivate) +{ +} + +QXmppUploadRequestManager::~QXmppUploadRequestManager() = default; + +/// Requests an upload slot from the server. +/// +/// \param file The info of the file to be uploaded. +/// \param uploadService The HTTP File Upload service that is used to request +/// the upload slot. If this is empty, the first +/// discovered one is used. +/// \return The id of the sent IQ. If sendPacket() isn't successful or no +/// upload service has been discovered yet, an empty string will be +/// returned. + +QString QXmppUploadRequestManager::requestUploadSlot(const QFileInfo &file, + const QString &uploadService) +{ + return requestUploadSlot(file, file.fileName(), uploadService); +} + +/// Requests an upload slot from the server. +/// +/// \param file The info of the file to be uploaded. +/// \param customFileName This name is used instead of the file's actual name +/// for requesting the upload slot. +/// \param uploadService The HTTP File Upload service that is used to request +/// the upload slot. If this is empty, the first +/// discovered one is used. +/// \return The id of the sent IQ. If sendPacket() isn't successful or no +/// upload service has been discovered yet, an empty string will be +/// returned. + +QString QXmppUploadRequestManager::requestUploadSlot(const QFileInfo &file, + const QString &customFileName, + const QString &uploadService) +{ + return requestUploadSlot(customFileName, file.size(), + QMimeDatabase().mimeTypeForFile(file), + uploadService); +} + +/// Requests an upload slot from the server. +/// +/// \param fileName The name of the file to be uploaded. This may be used by +/// the server to generate the URL. +/// \param fileSize The size of the file to be uploaded. The server may reject +/// too large files. +/// \param mimeType The content-type of the file. This can be used by the +/// server to set the HTTP MIME-type of the URL. +/// \param uploadService The HTTP File Upload service that is used to request +/// the upload slot. If this is empty, the first +/// discovered one is used. +/// \return The id of the sent IQ. If sendPacket() isn't successful or no +/// upload service has been discovered yet, an empty string will be +/// returned. + +QString QXmppUploadRequestManager::requestUploadSlot(const QString &fileName, + qint64 fileSize, + const QMimeType &mimeType, + const QString &uploadService) +{ + if (!serviceFound() && uploadService.isEmpty()) + return {}; + + QXmppHttpUploadRequestIq iq; + if (uploadService.isEmpty()) + iq.setTo(d->uploadServices.first().jid()); + else + iq.setTo(uploadService); + iq.setType(QXmppIq::Get); + iq.setFileName(fileName); + iq.setSize(fileSize); + iq.setContentType(mimeType); + + if (client()->sendPacket(iq)) + return iq.id(); + return {}; +} + +/// Returns true, if an HTTP File Upload service has been discovered. + +bool QXmppUploadRequestManager::serviceFound() const +{ + return !d->uploadServices.isEmpty(); +} + +/// Returns all discovered HTTP File Upload services. + +QVector<QXmppUploadService> QXmppUploadRequestManager::uploadServices() const +{ + return d->uploadServices; +} + +bool QXmppUploadRequestManager::handleStanza(const QDomElement &element) +{ + if (QXmppHttpUploadSlotIq::isHttpUploadSlotIq(element)) { + QXmppHttpUploadSlotIq slot; + slot.parse(element); + + emit slotReceived(slot); + return true; + } else if (QXmppHttpUploadRequestIq::isHttpUploadRequestIq(element)) { + QXmppHttpUploadRequestIq requestError; + requestError.parse(element); + + emit requestFailed(requestError); + return true; + } + return false; +} + +void QXmppUploadRequestManager::handleDiscoInfo(const QXmppDiscoveryIq &iq) +{ + if (!iq.features().contains(ns_http_upload)) + return; + + for (const QXmppDiscoveryIq::Identity &identity : iq.identities()) { + if (identity.category() == QStringLiteral("store") && + identity.type() == QStringLiteral("file")) { + QXmppUploadService service; + service.setJid(iq.from()); + + // get size limit + bool isFormNsCorrect = false; + for (const QXmppDataForm::Field &field : iq.form().fields()) { + if (field.key() == QStringLiteral("FORM_TYPE")) { + isFormNsCorrect = field.value() == ns_http_upload; + } else if (isFormNsCorrect && field.key() == QStringLiteral("max-file-size")) { + service.setSizeLimit(field.value().toLongLong()); + } + } + + d->uploadServices.append(service); + emit serviceFoundChanged(); + } + } + return; +} + +void QXmppUploadRequestManager::setClient(QXmppClient *client) +{ + QXmppClientExtension::setClient(client); + // connect to service discovery manager + auto *disco = client->findExtension<QXmppDiscoveryManager>(); + if (disco) { + // scan info of all entities for upload services + connect(disco, &QXmppDiscoveryManager::infoReceived, + this, &QXmppUploadRequestManager::handleDiscoInfo); + + // on client disconnect remove all upload services + connect(client, &QXmppClient::disconnected, [=] () { + d->uploadServices.clear(); + emit serviceFoundChanged(); + }); + } +} |
