diff options
| author | Linus Jahn <lnj@kaidan.im> | 2022-09-13 23:11:19 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-13 23:11:19 +0200 |
| commit | a780d365fe9740d6533f4667fc8220eac148cd7d (patch) | |
| tree | 32842f8342e8a001aef03c3dcf22a7199b597805 /src/base | |
| parent | c846f91c1750a35c17dbddcfd9176460765d5997 (diff) | |
| download | qxmpp-a780d365fe9740d6533f4667fc8220eac148cd7d.tar.gz | |
Implement XEP-0447: Stateless file sharing: File sharing element (#448)
Implements parsing for the file sharing element from XEP-0447:
Stateless files sharing version 0.2.
https://xmpp.org/extensions/xep-0447.html
Co-authored-by: Jonah BrĂ¼chert <jbb@kaidan.im>
Diffstat (limited to 'src/base')
| -rw-r--r-- | src/base/QXmppConstants.cpp | 4 | ||||
| -rw-r--r-- | src/base/QXmppConstants_p.h | 4 | ||||
| -rw-r--r-- | src/base/QXmppFileShare.cpp | 151 | ||||
| -rw-r--r-- | src/base/QXmppFileShare.h | 52 | ||||
| -rw-r--r-- | src/base/QXmppMessage.cpp | 37 | ||||
| -rw-r--r-- | src/base/QXmppMessage.h | 5 |
6 files changed, 253 insertions, 0 deletions
diff --git a/src/base/QXmppConstants.cpp b/src/base/QXmppConstants.cpp index 86438f15..7f58911c 100644 --- a/src/base/QXmppConstants.cpp +++ b/src/base/QXmppConstants.cpp @@ -80,6 +80,8 @@ const char *ns_data = "jabber:x:data"; // XEP-0095: Stream Initiation const char *ns_stream_initiation = "http://jabber.org/protocol/si"; const char *ns_stream_initiation_file_transfer = "http://jabber.org/protocol/si/profile/file-transfer"; +// XEP-0103: URL Address Information +const char *ns_url_data = "http://jabber.org/protocol/url-data"; // XEP-0108: User Activity const char *ns_activity = "http://jabber.org/protocol/activity"; // XEP-0115: Entity Capabilities @@ -188,5 +190,7 @@ const char *ns_fallback_indication = "urn:xmpp:fallback:0"; const char *ns_tm = "urn:xmpp:tm:1"; // XEP-0446: File metadata element const char *ns_file_metadata = "urn:xmpp:file:metadata:0"; +// XEP-0447: Stateless file sharing +const char *ns_sfs = "urn:xmpp:sfs:0"; // XEP-0450: Automatic Trust Management (ATM) const char *ns_atm = "urn:xmpp:atm:1"; diff --git a/src/base/QXmppConstants_p.h b/src/base/QXmppConstants_p.h index 4f8dd2ed..d040ed27 100644 --- a/src/base/QXmppConstants_p.h +++ b/src/base/QXmppConstants_p.h @@ -92,6 +92,8 @@ extern const char *ns_data; // XEP-0095: Stream Initiation extern const char *ns_stream_initiation; extern const char *ns_stream_initiation_file_transfer; +// XEP-0103: URL Address Information +extern const char *ns_url_data; // XEP-0108: User Activity extern const char *ns_activity; // XEP-0115: Entity Capabilities @@ -200,6 +202,8 @@ extern const char *ns_fallback_indication; extern const char *ns_tm; // XEP-0446: File metadata element extern const char *ns_file_metadata; +// XEP-0447: Stateless file sharing +extern const char *ns_sfs; // XEP-0450: Automatic Trust Management (ATM) extern const char *ns_atm; diff --git a/src/base/QXmppFileShare.cpp b/src/base/QXmppFileShare.cpp new file mode 100644 index 00000000..8d73dbe5 --- /dev/null +++ b/src/base/QXmppFileShare.cpp @@ -0,0 +1,151 @@ +// SPDX-FileCopyrightText: 2022 Linus Jahn <lnj@kaidan.im> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "QXmppFileShare.h" + +#include "QXmppConstants_p.h" +#include "QXmppFileMetadata.h" + +#include <optional> + +#include <QDomElement> +#include <QUrl> +#include <QXmlStreamWriter> + +using Disposition = QXmppFileShare::Disposition; + +static std::optional<Disposition> dispositionFromString(const QString &str) +{ + if (str == "inline") { + return Disposition::Inline; + } + if (str == "attachment") { + return Disposition::Attachment; + } + return {}; +} + +static QString dispositionToString(Disposition value) +{ + switch (value) { + case Disposition::Inline: + return QStringLiteral("inline"); + case Disposition::Attachment: + return QStringLiteral("attachment"); + } + Q_UNREACHABLE(); +} + +/// \cond +class QXmppFileSharePrivate : public QSharedData +{ +public: + QXmppFileMetadata metadata; + QVector<QUrl> httpSources; + QXmppFileShare::Disposition disposition = Disposition::Inline; +}; +/// \endcond + +/// +/// \class QXmppFileSharePrivate +/// +/// File sharing element from \xep{0447, Stateless file sharing}. Contains +/// metadata and source URLs. +/// +/// \note jinglepub references are currently missing +/// +/// \since QXmpp 1.5 +/// + +/// Default constructor +QXmppFileShare::QXmppFileShare() + : d(new QXmppFileSharePrivate) +{ +} + +QXmppFileShare::QXmppFileShare(const QXmppFileShare &) = default; +QXmppFileShare::QXmppFileShare(QXmppFileShare &&) noexcept = default; +QXmppFileShare::~QXmppFileShare() = default; +QXmppFileShare &QXmppFileShare::operator=(const QXmppFileShare &) = default; +QXmppFileShare &QXmppFileShare::operator=(QXmppFileShare &&) noexcept = default; + +/// Returns the disposition setting for this file. +QXmppFileShare::Disposition QXmppFileShare::disposition() const +{ + return d->disposition; +} + +/// Sets the disposition setting for this file. +void QXmppFileShare::setDisposition(Disposition disp) +{ + d->disposition = disp; +} + +const QXmppFileMetadata &QXmppFileShare::metadata() const +{ + return d->metadata; +} + +void QXmppFileShare::setMetadata(const QXmppFileMetadata &metadata) +{ + d->metadata = metadata; +} + +const QVector<QUrl> &QXmppFileShare::httpSources() const +{ + return d->httpSources; +} + +void QXmppFileShare::setHttpSources(const QVector<QUrl> &newHttpSources) +{ + d->httpSources = newHttpSources; +} + +/// \cond +bool QXmppFileShare::parse(const QDomElement &el) +{ + if (el.tagName() == "file-sharing" && el.namespaceURI() == ns_sfs) { + // disposition + d->disposition = dispositionFromString(el.attribute("disposition")) + .value_or(Disposition::Inline); + + // file metadata + auto fileEl = el.firstChildElement("file"); + d->metadata = QXmppFileMetadata(); + if (!d->metadata.parse(fileEl)) { + return false; + } + + // sources: + // expect that there's only one sources element with the correct namespace + auto sources = el.firstChildElement("sources"); + for (auto urlEl = sources.firstChildElement("url-data"); + !urlEl.isNull(); + urlEl = urlEl.nextSiblingElement("url-data")) { + if (urlEl.namespaceURI() == "http://jabber.org/protocol/url-data") { + d->httpSources.append(QUrl(urlEl.attribute("target"))); + } + } + return true; + } + return false; +} + +void QXmppFileShare::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("file-sharing"); + writer->writeDefaultNamespace(ns_sfs); + writer->writeAttribute("disposition", dispositionToString(d->disposition)); + d->metadata.toXml(writer); + writer->writeStartElement("sources"); + for (const auto &source : d->httpSources) { + writer->writeStartElement("url-data"); + writer->writeDefaultNamespace(ns_url_data); + writer->writeAttribute("target", source.toString()); + writer->writeEndElement(); + } + writer->writeEndElement(); + writer->writeEndElement(); +} +/// \endcond diff --git a/src/base/QXmppFileShare.h b/src/base/QXmppFileShare.h new file mode 100644 index 00000000..7d38df23 --- /dev/null +++ b/src/base/QXmppFileShare.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2022 Linus Jahn <lnj@kaidan.im> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPFILESHARE_H +#define QXMPPFILESHARE_H + +#include "QXmppGlobal.h" + +#include <QSharedDataPointer> + +class QDomElement; +class QUrl; +class QXmlStreamWriter; +class QXmppFileSharePrivate; +class QXmppFileMetadata; + +class QXMPP_EXPORT QXmppFileShare +{ +public: + enum Disposition { + Inline, + Attachment, + }; + + QXmppFileShare(); + QXmppFileShare(const QXmppFileShare &); + QXmppFileShare(QXmppFileShare &&) noexcept; + ~QXmppFileShare(); + + QXmppFileShare &operator=(const QXmppFileShare &); + QXmppFileShare &operator=(QXmppFileShare &&) noexcept; + + Disposition disposition() const; + void setDisposition(Disposition); + + const QXmppFileMetadata &metadata() const; + void setMetadata(const QXmppFileMetadata &); + + const QVector<QUrl> &httpSources() const; + void setHttpSources(const QVector<QUrl> &newHttpSources); + + /// \cond + bool parse(const QDomElement &el); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QSharedDataPointer<QXmppFileSharePrivate> d; +}; + +#endif // QXMPPFILESHARE_H diff --git a/src/base/QXmppMessage.cpp b/src/base/QXmppMessage.cpp index 74e18149..f45789f0 100644 --- a/src/base/QXmppMessage.cpp +++ b/src/base/QXmppMessage.cpp @@ -9,6 +9,7 @@ #include "QXmppBitsOfBinaryDataList.h" #include "QXmppConstants_p.h" +#include "QXmppFileShare.h" #include "QXmppGlobal_p.h" #include "QXmppMixInvitation.h" #ifdef BUILD_OMEMO @@ -151,6 +152,9 @@ public: // XEP-0434: Trust Messages (TM) std::optional<QXmppTrustMessageElement> trustMessageElement; + + // XEP-0448: Encryption for stateless file sharing + QVector<QXmppFileShare> sharedFiles; }; QXmppMessagePrivate::QXmppMessagePrivate() @@ -1205,6 +1209,26 @@ void QXmppMessage::setTrustMessageElement(const std::optional<QXmppTrustMessageE d->trustMessageElement = trustMessageElement; } +/// +/// Returns the via \xep{0447, Stateless file sharing} shared files attached to this message. +/// +/// \since QXmpp 1.5 +/// +const QVector<QXmppFileShare> &QXmppMessage::sharedFiles() const +{ + return d->sharedFiles; +} + +/// +/// Sets the via \xep{0447, Stateless file sharing} shared files attached to this message. +/// +/// \since QXmpp 1.5 +/// +void QXmppMessage::setSharedFiles(const QVector<QXmppFileShare> &sharedFiles) +{ + d->sharedFiles = sharedFiles; +} + /// \cond void QXmppMessage::parse(const QDomElement &element) { @@ -1489,6 +1513,14 @@ bool QXmppMessage::parseExtension(const QDomElement &element, QXmpp::SceMode sce d->trustMessageElement = trustMessageElement; return true; } + // XEP-0448: Stateless file sharing + if (checkElement(element, QStringLiteral("file-sharing"), ns_sfs)) { + QXmppFileShare share; + if (share.parse(element)) { + d->sharedFiles.push_back(std::move(share)); + } + return true; + } } return false; } @@ -1739,5 +1771,10 @@ void QXmppMessage::serializeExtensions(QXmlStreamWriter *writer, QXmpp::SceMode if (d->trustMessageElement) { d->trustMessageElement->toXml(writer); } + + // XEP-0448: Stateless file sharing + for (const auto &fileShare : d->sharedFiles) { + fileShare.toXml(writer); + } } } diff --git a/src/base/QXmppMessage.h b/src/base/QXmppMessage.h index 43949118..a4d4fcbe 100644 --- a/src/base/QXmppMessage.h +++ b/src/base/QXmppMessage.h @@ -8,6 +8,7 @@ #ifndef QXMPPMESSAGE_H #define QXMPPMESSAGE_H +#include "QXmppFileShare.h" #include "QXmppStanza.h" #include <optional> @@ -248,6 +249,10 @@ public: std::optional<QXmppTrustMessageElement> trustMessageElement() const; void setTrustMessageElement(const std::optional<QXmppTrustMessageElement> &trustMessageElement); + // XEP-0447: Stateless file sharing + const QVector<QXmppFileShare> &sharedFiles() const; + void setSharedFiles(const QVector<QXmppFileShare> &sharedFiles); + /// \cond #ifdef BUILD_OMEMO // XEP-0384: OMEMO Encryption |
