aboutsummaryrefslogtreecommitdiff
path: root/src/base
diff options
context:
space:
mode:
authorJonah Brüchert <jbb@kaidan.im>2022-09-05 19:23:07 +0200
committerLinus Jahn <lnj@kaidan.im>2022-09-06 00:46:56 +0200
commite2e27c8c953d6650a1ede2596a3537e5ebd5cea5 (patch)
tree71229ce7f6a0fe437e69103e0c5355721264ad00 /src/base
parent6685217ac78c7588aaea67059a0844d51713dcd5 (diff)
downloadqxmpp-e2e27c8c953d6650a1ede2596a3537e5ebd5cea5.tar.gz
Add parsing of XEP-0446: File metadata element
This implements version 0.2.0 https://xmpp.org/extensions/xep-0446.html
Diffstat (limited to 'src/base')
-rw-r--r--src/base/QXmppConstants.cpp2
-rw-r--r--src/base/QXmppConstants_p.h2
-rw-r--r--src/base/QXmppFileMetadata.cpp276
-rw-r--r--src/base/QXmppFileMetadata.h66
4 files changed, 346 insertions, 0 deletions
diff --git a/src/base/QXmppConstants.cpp b/src/base/QXmppConstants.cpp
index 30eb8d22..86438f15 100644
--- a/src/base/QXmppConstants.cpp
+++ b/src/base/QXmppConstants.cpp
@@ -186,5 +186,7 @@ const char *ns_mix_misc = "urn:xmpp:mix:misc:0";
const char *ns_fallback_indication = "urn:xmpp:fallback:0";
// XEP-0434: Trust Messages (TM)
const char *ns_tm = "urn:xmpp:tm:1";
+// XEP-0446: File metadata element
+const char *ns_file_metadata = "urn:xmpp:file:metadata: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 32c1cdbd..4f8dd2ed 100644
--- a/src/base/QXmppConstants_p.h
+++ b/src/base/QXmppConstants_p.h
@@ -198,6 +198,8 @@ extern const char *ns_mix_misc;
extern const char *ns_fallback_indication;
// XEP-0434: Trust Messages (TM)
extern const char *ns_tm;
+// XEP-0446: File metadata element
+extern const char *ns_file_metadata;
// XEP-0450: Automatic Trust Management (ATM)
extern const char *ns_atm;
diff --git a/src/base/QXmppFileMetadata.cpp b/src/base/QXmppFileMetadata.cpp
new file mode 100644
index 00000000..35b5b040
--- /dev/null
+++ b/src/base/QXmppFileMetadata.cpp
@@ -0,0 +1,276 @@
+// SPDX-FileCopyrightText: 2022 Jonah Brüchert <jbb@kaidan.im>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "QXmppFileMetadata.h"
+
+#include "QXmppConstants_p.h"
+#include "QXmppHash.h"
+#include "QXmppUtils.h"
+#include "QXmppThumbnail.h"
+
+#include <utility>
+
+#include <QDateTime>
+#include <QDomElement>
+#include <QMimeDatabase>
+#include <QMimeType>
+#include <QSharedData>
+
+class QXmppFileMetadataPrivate : public QSharedData
+{
+public:
+ std::optional<QDateTime> date;
+ std::optional<QString> desc;
+ QVector<QXmppHash> hashes;
+ std::optional<uint32_t> height;
+ std::optional<uint32_t> length;
+ std::optional<QMimeType> mediaType;
+ std::optional<QString> name;
+ std::optional<uint64_t> size;
+ std::optional<QXmppThumbnail> thumbnail;
+ std::optional<uint32_t> width;
+};
+
+///
+/// \class QXmppFileMetadata
+///
+/// File metadata from \xep{0446, File metadata element}.
+///
+/// \since QXmpp 1.5
+///
+
+QXmppFileMetadata::QXmppFileMetadata()
+ : d(new QXmppFileMetadataPrivate())
+{
+}
+
+QXMPP_PRIVATE_DEFINE_ROLE_OF_SIX(QXmppFileMetadata)
+
+/// \cond
+QVector<QDomElement> allChildElements(const QDomElement &el, const QString &name)
+{
+ QVector<QDomElement> out;
+
+ for (auto childEl = el.firstChildElement(name); !childEl.isNull(); childEl = childEl.nextSiblingElement(name)) {
+ out.push_back(childEl);
+ }
+
+ return out;
+}
+
+template<typename Func>
+QVector<std::invoke_result_t<Func, QDomElement>> forAllChildElements(const QDomElement &el, const QString &name, Func func)
+{
+ auto elements = allChildElements(el, name);
+ QVector<std::invoke_result_t<Func, QDomElement>> out;
+ std::transform(elements.begin(), elements.end(), std::back_inserter(out), func);
+ return out;
+}
+
+bool QXmppFileMetadata::parse(const QDomElement &el)
+{
+ if (el.isNull())
+ return false;
+
+ if (auto dateEl = el.firstChildElement("date"); !dateEl.isNull()) {
+ d->date = QXmppUtils::datetimeFromString(dateEl.text());
+ }
+
+ if (auto descEl = el.firstChildElement("desc"); !descEl.isNull()) {
+ d->desc = descEl.text();
+ }
+
+ d->hashes = forAllChildElements(el, "hash", [](const auto &el) {
+ QXmppHash hash;
+ hash.parse(el);
+ return hash;
+ });
+
+ if (auto heightEl = el.firstChildElement("height"); !heightEl.isNull()) {
+ d->height = el.firstChildElement("height").text().toUInt();
+ }
+ if (auto lengthEl = el.firstChildElement("length"); !lengthEl.isNull()) {
+ d->length = lengthEl.text().toUInt();
+ }
+ if (auto mediaTypeEl = el.firstChildElement("media-type"); !mediaTypeEl.isNull()) {
+ d->mediaType = QMimeDatabase().mimeTypeForName(mediaTypeEl.text());
+ }
+ if (auto nameEl = el.firstChildElement("name"); !nameEl.isNull()) {
+ d->name = nameEl.text();
+ }
+ if (auto sizeEl = el.firstChildElement("size"); !sizeEl.isNull()) {
+ d->size = sizeEl.text().toULong();
+ }
+ if (auto thumbEl = el.firstChildElement("thumbnail"); !thumbEl.isNull()) {
+ d->thumbnail = QXmppThumbnail();
+ if (!d->thumbnail->parse(thumbEl)) {
+ d->thumbnail.reset();
+ }
+ }
+ if (auto widthEl = el.firstChildElement("width"); !widthEl.isNull()) {
+ d->width = widthEl.text().toUInt();
+ }
+ return true;
+}
+
+void QXmppFileMetadata::toXml(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("file");
+ writer->writeDefaultNamespace(ns_file_metadata);
+ if (d->date) {
+ writer->writeTextElement("date", QXmppUtils::datetimeToString(*d->date));
+ }
+
+ if (d->desc) {
+ writer->writeTextElement("desc", *d->desc);
+ }
+
+ for (const auto &hash : d->hashes) {
+ hash.toXml(writer);
+ }
+
+ if (d->height) {
+ writer->writeTextElement("height", QString::number(*d->height));
+ }
+ if (d->length) {
+ writer->writeTextElement("length", QString::number(*d->length));
+ }
+ if (d->mediaType) {
+ writer->writeTextElement("media-type", d->mediaType->name());
+ }
+ if (d->name) {
+ writer->writeTextElement("name", *d->name);
+ }
+ if (d->size) {
+ writer->writeTextElement("size", QString::number(*d->size));
+ }
+ if (d->thumbnail) {
+ d->thumbnail->toXml(writer);
+ }
+ if (d->width) {
+ writer->writeTextElement("width", QString::number(*d->width));
+ }
+ writer->writeEndElement();
+}
+/// \endcond
+
+/// Returns when the file was last modified
+const std::optional<QDateTime> &QXmppFileMetadata::lastModified() const
+{
+ return d->date;
+}
+
+/// Sets when the file was last modified
+void QXmppFileMetadata::setLastModified(const std::optional<QDateTime> &date)
+{
+ d->date = date;
+}
+
+/// Returns the description of the file
+const std::optional<QString> &QXmppFileMetadata::description() const
+{
+ return d->desc;
+}
+
+/// Sets the description of the file
+void QXmppFileMetadata::setDescription(const std::optional<QString> &description)
+{
+ d->desc = description;
+}
+
+/// Returns the hashes of the file
+const QVector<QXmppHash> &QXmppFileMetadata::hashes() const
+{
+ return d->hashes;
+}
+
+/// Sets the hashes of the file
+void QXmppFileMetadata::setHashes(const QVector<QXmppHash> &hashes)
+{
+ d->hashes = hashes;
+}
+
+/// Returns the height of the image
+std::optional<uint32_t> QXmppFileMetadata::height() const
+{
+ return d->height;
+}
+
+/// Sets the height of the image
+void QXmppFileMetadata::setHeight(std::optional<uint32_t> height)
+{
+ d->height = height;
+}
+
+/// Returns the length of a video or audio file
+std::optional<uint32_t> QXmppFileMetadata::length() const
+{
+ return d->length;
+}
+
+/// Sets the length of a video or audio file
+void QXmppFileMetadata::setLength(std::optional<uint32_t> length)
+{
+ d->length = length;
+}
+
+/// Returns the media type of the file
+const std::optional<QMimeType> &QXmppFileMetadata::mediaType() const
+{
+ return d->mediaType;
+}
+
+/// Sets the media type of the file
+void QXmppFileMetadata::setMediaType(std::optional<QMimeType> mediaType)
+{
+ d->mediaType = std::move(mediaType);
+}
+
+/// Returns the filename
+std::optional<QString> QXmppFileMetadata::filename() const
+{
+ return d->name;
+}
+
+/// Sets the filename
+void QXmppFileMetadata::setFilename(std::optional<QString> name)
+{
+ d->name = std::move(name);
+}
+
+/// Returns the size of the file in bytes
+std::optional<uint64_t> QXmppFileMetadata::size() const
+{
+ return d->size;
+}
+
+/// Sets the size of the file in bytes
+void QXmppFileMetadata::setSize(std::optional<uint64_t> size)
+{
+ d->size = size;
+}
+
+/// Returns the thumbnail reference.
+const std::optional<QXmppThumbnail> &QXmppFileMetadata::thumbnail() const
+{
+ return d->thumbnail;
+}
+
+/// Sets the thumbnail reference.
+void QXmppFileMetadata::setThumbnail(const std::optional<QXmppThumbnail> &thumbnail)
+{
+ d->thumbnail = thumbnail;
+}
+
+/// Returns the width of the image or video.
+std::optional<uint32_t> QXmppFileMetadata::width() const
+{
+ return d->width;
+}
+
+/// Sets the width of the image or video.
+void QXmppFileMetadata::setWidth(std::optional<uint32_t> width)
+{
+ d->width = width;
+}
diff --git a/src/base/QXmppFileMetadata.h b/src/base/QXmppFileMetadata.h
new file mode 100644
index 00000000..e45e6506
--- /dev/null
+++ b/src/base/QXmppFileMetadata.h
@@ -0,0 +1,66 @@
+// SPDX-FileCopyrightText: 2022 Jonah Brüchert <jbb@kaidan.im>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#ifndef QXMPPFILEMETADATA_H
+#define QXMPPFILEMETADATA_H
+
+#include "QXmppGlobal.h"
+#include "QXmppHash.h"
+
+#include <optional>
+
+#include <QMimeType>
+#include <QSharedDataPointer>
+
+class QDomElement;
+class QDateTime;
+class QXmlStreamWriter;
+class QXmppThumbnail;
+class QXmppFileMetadataPrivate;
+
+class QXMPP_EXPORT QXmppFileMetadata
+{
+public:
+ QXmppFileMetadata();
+
+ /// \cond
+ bool parse(const QDomElement &el);
+ void toXml(QXmlStreamWriter *writer) const;
+ /// \endcond
+
+ const std::optional<QDateTime> &lastModified() const;
+ void setLastModified(const std::optional<QDateTime> &date);
+
+ const std::optional<QString> &description() const;
+ void setDescription(const std::optional<QString> &description);
+
+ const QVector<QXmppHash> &hashes() const;
+ void setHashes(const QVector<QXmppHash> &hashes);
+
+ std::optional<uint32_t> height() const;
+ void setHeight(std::optional<uint32_t> height);
+
+ std::optional<uint32_t> length() const;
+ void setLength(std::optional<uint32_t> length);
+
+ const std::optional<QMimeType> &mediaType() const;
+ void setMediaType(std::optional<QMimeType> mediaType);
+
+ std::optional<QString> filename() const;
+ void setFilename(std::optional<QString>);
+
+ std::optional<uint64_t> size() const;
+ void setSize(std::optional<uint64_t> size);
+
+ const std::optional<QXmppThumbnail> &thumbnail() const;
+ void setThumbnail(const std::optional<QXmppThumbnail> &thumbnail);
+
+ std::optional<uint32_t> width() const;
+ void setWidth(std::optional<uint32_t> width);
+
+private:
+ QSharedDataPointer<QXmppFileMetadataPrivate> d;
+};
+
+#endif