aboutsummaryrefslogtreecommitdiff
path: root/src/base
diff options
context:
space:
mode:
authorLinus Jahn <lnj@kaidan.im>2022-09-13 23:11:19 +0200
committerGitHub <noreply@github.com>2022-09-13 23:11:19 +0200
commita780d365fe9740d6533f4667fc8220eac148cd7d (patch)
tree32842f8342e8a001aef03c3dcf22a7199b597805 /src/base
parentc846f91c1750a35c17dbddcfd9176460765d5997 (diff)
downloadqxmpp-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.cpp4
-rw-r--r--src/base/QXmppConstants_p.h4
-rw-r--r--src/base/QXmppFileShare.cpp151
-rw-r--r--src/base/QXmppFileShare.h52
-rw-r--r--src/base/QXmppMessage.cpp37
-rw-r--r--src/base/QXmppMessage.h5
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