diff options
| author | Linus Jahn <lnj@kaidan.im> | 2023-03-11 00:29:02 +0100 |
|---|---|---|
| committer | Linus Jahn <lnj@kaidan.im> | 2023-03-11 00:29:02 +0100 |
| commit | 463111576fb1476192acd2d8fe415b8482a8a696 (patch) | |
| tree | e87e3bb8f8724f019954692ac22b0d6386dfa5e7 /src | |
| parent | 6ea3edfd83a0bf1558d43e48eac563730276c175 (diff) | |
| parent | 4897c9b6a36e961fb44d2bce04a698f979a423d5 (diff) | |
Merge branch '1.5'
Diffstat (limited to 'src')
36 files changed, 602 insertions, 226 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc463303..82e99619 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,7 +54,7 @@ set(INSTALL_HEADER_FILES base/QXmppPubSubAffiliation.h base/QXmppPubSubEvent.h base/QXmppPubSubIq_p.h - base/QXmppPubSubItem.h + base/QXmppPubSubBaseItem.h base/QXmppPubSubMetadata.h base/QXmppPubSubNodeConfig.h base/QXmppPubSubPublishOptions.h @@ -83,6 +83,8 @@ set(INSTALL_HEADER_FILES base/QXmppUtils.h base/QXmppVCardIq.h base/QXmppVersionIq.h + base/compat/QXmppPubSubIq.h + base/compat/QXmppPubSubItem.h # Client client/QXmppArchiveManager.h @@ -188,7 +190,7 @@ set(SOURCE_FILES base/QXmppPubSubAffiliation.cpp base/QXmppPubSubEvent.cpp base/QXmppPubSubIq.cpp - base/QXmppPubSubItem.cpp + base/QXmppPubSubBaseItem.cpp base/QXmppPubSubMetadata.cpp base/QXmppPubSubNodeConfig.cpp base/QXmppPubSubSubscribeOptions.cpp @@ -216,6 +218,8 @@ set(SOURCE_FILES base/QXmppUtils.cpp base/QXmppVCardIq.cpp base/QXmppVersionIq.cpp + base/compat/QXmppPubSubIq.cpp + base/compat/QXmppPubSubItem.cpp # Client client/QXmppArchiveManager.cpp @@ -365,8 +369,10 @@ generate_export_header(qxmpp install( TARGETS qxmpp - DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT QXmppTarget + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install( diff --git a/src/base/QXmppGeolocItem.cpp b/src/base/QXmppGeolocItem.cpp index b6bf0b85..32e08189 100644 --- a/src/base/QXmppGeolocItem.cpp +++ b/src/base/QXmppGeolocItem.cpp @@ -146,7 +146,7 @@ bool QXmppGeolocItem::isItem(const QDomElement &itemElement) payload.namespaceURI() == ns_geoloc;
};
- return QXmppPubSubItem::isItem(itemElement, isPayloadValid);
+ return QXmppPubSubBaseItem::isItem(itemElement, isPayloadValid);
}
/// \cond
diff --git a/src/base/QXmppGeolocItem.h b/src/base/QXmppGeolocItem.h index 05d42dba..58914b1b 100644 --- a/src/base/QXmppGeolocItem.h +++ b/src/base/QXmppGeolocItem.h @@ -5,7 +5,7 @@ #ifndef QXMPPGEOLOCITEM_H #define QXMPPGEOLOCITEM_H -#include "QXmppPubSubItem.h" +#include "QXmppPubSubBaseItem.h" #include <optional> @@ -13,7 +13,7 @@ class QXmppGeolocItemPrivate; -class QXMPP_EXPORT QXmppGeolocItem : public QXmppPubSubItem +class QXMPP_EXPORT QXmppGeolocItem : public QXmppPubSubBaseItem { public: QXmppGeolocItem(); diff --git a/src/base/QXmppMixInfoItem.h b/src/base/QXmppMixInfoItem.h index 9a28decb..313c3e14 100644 --- a/src/base/QXmppMixInfoItem.h +++ b/src/base/QXmppMixInfoItem.h @@ -5,11 +5,11 @@ #ifndef QXMPPMIXINFOITEM_H #define QXMPPMIXINFOITEM_H -#include "QXmppPubSubItem.h" +#include "QXmppPubSubBaseItem.h" class QXmppMixInfoItemPrivate; -class QXMPP_EXPORT QXmppMixInfoItem : public QXmppPubSubItem +class QXMPP_EXPORT QXmppMixInfoItem : public QXmppPubSubBaseItem { public: QXmppMixInfoItem(); diff --git a/src/base/QXmppMixItems.cpp b/src/base/QXmppMixItems.cpp index e08dd3f2..a19edbb0 100644 --- a/src/base/QXmppMixItems.cpp +++ b/src/base/QXmppMixItems.cpp @@ -138,7 +138,7 @@ void QXmppMixInfoItem::setContactJids(QStringList contactJids) /// bool QXmppMixInfoItem::isItem(const QDomElement &element) { - return QXmppPubSubItem::isItem(element, [](const QDomElement &payload) { + return QXmppPubSubBaseItem::isItem(element, [](const QDomElement &payload) { // check FORM_TYPE without parsing a full QXmppDataForm if (payload.tagName() != u'x' || payload.namespaceURI() != ns_data) { return false; @@ -264,7 +264,7 @@ void QXmppMixParticipantItem::serializePayload(QXmlStreamWriter *writer) const /// bool QXmppMixParticipantItem::isItem(const QDomElement &element) { - return QXmppPubSubItem::isItem(element, [](const QDomElement &payload) { + return QXmppPubSubBaseItem::isItem(element, [](const QDomElement &payload) { return payload.tagName() == QStringLiteral("participant") && payload.namespaceURI() == ns_mix; }); diff --git a/src/base/QXmppMixParticipantItem.h b/src/base/QXmppMixParticipantItem.h index f0f2abaa..ce179fbe 100644 --- a/src/base/QXmppMixParticipantItem.h +++ b/src/base/QXmppMixParticipantItem.h @@ -5,11 +5,11 @@ #ifndef QXMPPMIXPARTICIPANTITEM_H #define QXMPPMIXPARTICIPANTITEM_H -#include "QXmppPubSubItem.h" +#include "QXmppPubSubBaseItem.h" class QXmppMixParticipantItemPrivate; -class QXMPP_EXPORT QXmppMixParticipantItem : public QXmppPubSubItem +class QXMPP_EXPORT QXmppMixParticipantItem : public QXmppPubSubBaseItem { public: QXmppMixParticipantItem(); diff --git a/src/base/QXmppOmemoElement_p.h b/src/base/QXmppOmemoElement_p.h index 1e160479..cd95ea00 100644 --- a/src/base/QXmppOmemoElement_p.h +++ b/src/base/QXmppOmemoElement_p.h @@ -7,13 +7,13 @@ #define QXMPPOMEMOELEMENT_H #include "QXmppGlobal.h" +#include "QXmppOmemoEnvelope_p.h" #include <optional> #include <QMultiMap> class QDomElement; -class QXmppOmemoEnvelope; class QXmlStreamWriter; class QXMPP_EXPORT QXmppOmemoElement diff --git a/src/base/QXmppPromise.h b/src/base/QXmppPromise.h index 4900dae1..6408ad0c 100644 --- a/src/base/QXmppPromise.h +++ b/src/base/QXmppPromise.h @@ -45,7 +45,7 @@ public: #ifdef QXMPP_DOC void reportFinished(T &&value) #else - template<typename U, std::enable_if_t<!std::is_void_v<T> && std::is_same_v<T, U>> * = nullptr> + template<typename U, typename TT = T, std::enable_if_t<!std::is_void_v<TT> && std::is_same_v<TT, U>> * = nullptr> void finish(U &&value) #endif { @@ -61,7 +61,7 @@ public: } /// \cond - template<typename U, std::enable_if_t<!std::is_void_v<T> && std::is_constructible_v<T, U> && !std::is_same_v<T, U>> * = nullptr> + template<typename U, typename TT = T, std::enable_if_t<!std::is_void_v<TT> && std::is_constructible_v<TT, U> && !std::is_same_v<TT, U>> * = nullptr> void finish(U &&value) { Q_ASSERT(!d.isFinished()); diff --git a/src/base/QXmppPubSubItem.cpp b/src/base/QXmppPubSubBaseItem.cpp index f87c5d6e..43b1aa88 100644 --- a/src/base/QXmppPubSubItem.cpp +++ b/src/base/QXmppPubSubBaseItem.cpp @@ -3,47 +3,47 @@ // // SPDX-License-Identifier: LGPL-2.1-or-later -#include "QXmppPubSubItem.h" +#include "QXmppPubSubBaseItem.h" #include "QXmppElement.h" #include "QXmppUtils.h" #include <QDomElement> -class QXmppPubSubItemPrivate : public QSharedData +class QXmppPubSubBaseItemPrivate : public QSharedData { public: - QXmppPubSubItemPrivate(const QString &id, const QString &publisher); + QXmppPubSubBaseItemPrivate(const QString &id, const QString &publisher); QString id; QString publisher; }; -QXmppPubSubItemPrivate::QXmppPubSubItemPrivate(const QString &id, const QString &publisher) +QXmppPubSubBaseItemPrivate::QXmppPubSubBaseItemPrivate(const QString &id, const QString &publisher) : id(id), publisher(publisher) { } /// -/// \class QXmppPubSubItem +/// \class QXmppPubSubBaseItem /// -/// The QXmppPubSubItem class represents a publish-subscribe item as defined by +/// The QXmppPubSubBaseItem class represents a publish-subscribe item as defined by /// \xep{0060, Publish-Subscribe}. /// /// To access the payload of an item, you need to create a derived class of this -/// and override QXmppPubSubItem::parsePayload() and -/// QXmppPubSubItem::serializePayload(). +/// and override QXmppPubSubBaseItem::parsePayload() and +/// QXmppPubSubBaseItem::serializePayload(). /// -/// It is also required that you override QXmppPubSubItem::isItem() and also +/// It is also required that you override QXmppPubSubBaseItem::isItem() and also /// check for the correct payload of the PubSub item. This can be easily done by /// using the protected overload of isItem() with an function that checks the /// tag name and namespace of the payload. The function is only called if a /// payload exists. /// /// In short, you need to reimplement these methods: -/// * QXmppPubSubItem::parsePayload() -/// * QXmppPubSubItem::serializePayload() -/// * QXmppPubSubItem::isItem() +/// * QXmppPubSubBaseItem::parsePayload() +/// * QXmppPubSubBaseItem::serializePayload() +/// * QXmppPubSubBaseItem::isItem() /// /// \since QXmpp 1.5 /// @@ -54,25 +54,25 @@ QXmppPubSubItemPrivate::QXmppPubSubItemPrivate(const QString &id, const QString /// \param id /// \param publisher /// -QXmppPubSubItem::QXmppPubSubItem(const QString &id, const QString &publisher) - : d(new QXmppPubSubItemPrivate(id, publisher)) +QXmppPubSubBaseItem::QXmppPubSubBaseItem(const QString &id, const QString &publisher) + : d(new QXmppPubSubBaseItemPrivate(id, publisher)) { } /// Default copy-constructor -QXmppPubSubItem::QXmppPubSubItem(const QXmppPubSubItem &iq) = default; +QXmppPubSubBaseItem::QXmppPubSubBaseItem(const QXmppPubSubBaseItem &iq) = default; /// Default move-constructor -QXmppPubSubItem::QXmppPubSubItem(QXmppPubSubItem &&) = default; -QXmppPubSubItem::~QXmppPubSubItem() = default; +QXmppPubSubBaseItem::QXmppPubSubBaseItem(QXmppPubSubBaseItem &&) = default; +QXmppPubSubBaseItem::~QXmppPubSubBaseItem() = default; /// Default assignment operator -QXmppPubSubItem &QXmppPubSubItem::operator=(const QXmppPubSubItem &iq) = default; +QXmppPubSubBaseItem &QXmppPubSubBaseItem::operator=(const QXmppPubSubBaseItem &iq) = default; /// Default move-assignment operator -QXmppPubSubItem &QXmppPubSubItem::operator=(QXmppPubSubItem &&iq) = default; +QXmppPubSubBaseItem &QXmppPubSubBaseItem::operator=(QXmppPubSubBaseItem &&iq) = default; /// /// Returns the ID of the PubSub item. /// -QString QXmppPubSubItem::id() const +QString QXmppPubSubBaseItem::id() const { return d->id; } @@ -82,7 +82,7 @@ QString QXmppPubSubItem::id() const /// /// \param id /// -void QXmppPubSubItem::setId(const QString &id) +void QXmppPubSubBaseItem::setId(const QString &id) { d->id = id; } @@ -90,7 +90,7 @@ void QXmppPubSubItem::setId(const QString &id) /// /// Returns the JID of the publisher of the item. /// -QString QXmppPubSubItem::publisher() const +QString QXmppPubSubBaseItem::publisher() const { return d->publisher; } @@ -98,13 +98,13 @@ QString QXmppPubSubItem::publisher() const /// /// Sets the JID of the publisher of the item. /// -void QXmppPubSubItem::setPublisher(const QString &publisher) +void QXmppPubSubBaseItem::setPublisher(const QString &publisher) { d->publisher = publisher; } /// \cond -void QXmppPubSubItem::parse(const QDomElement &element) +void QXmppPubSubBaseItem::parse(const QDomElement &element) { d->id = element.attribute(QStringLiteral("id")); d->publisher = element.attribute(QStringLiteral("publisher")); @@ -112,7 +112,7 @@ void QXmppPubSubItem::parse(const QDomElement &element) parsePayload(element.firstChildElement()); } -void QXmppPubSubItem::toXml(QXmlStreamWriter *writer) const +void QXmppPubSubBaseItem::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("item")); helperToXmlAddAttribute(writer, QStringLiteral("id"), d->id); @@ -127,7 +127,7 @@ void QXmppPubSubItem::toXml(QXmlStreamWriter *writer) const /// /// Returns true, if the element is possibly a PubSub item. /// -bool QXmppPubSubItem::isItem(const QDomElement &element) +bool QXmppPubSubBaseItem::isItem(const QDomElement &element) { return element.tagName() == QStringLiteral("item"); } @@ -137,7 +137,7 @@ bool QXmppPubSubItem::isItem(const QDomElement &element) /// /// This method needs to be overriden to perform the payload-specific parsing. /// -void QXmppPubSubItem::parsePayload(const QDomElement &) +void QXmppPubSubBaseItem::parsePayload(const QDomElement &) { } @@ -147,6 +147,6 @@ void QXmppPubSubItem::parsePayload(const QDomElement &) /// This method needs to be overriden to perform the payload-specific /// serialization. /// -void QXmppPubSubItem::serializePayload(QXmlStreamWriter *) const +void QXmppPubSubBaseItem::serializePayload(QXmlStreamWriter *) const { } diff --git a/src/base/QXmppPubSubItem.h b/src/base/QXmppPubSubBaseItem.h index e585de9d..20702662 100644 --- a/src/base/QXmppPubSubItem.h +++ b/src/base/QXmppPubSubBaseItem.h @@ -3,8 +3,7 @@ // // SPDX-License-Identifier: LGPL-2.1-or-later -#ifndef QXMPPPUBSUBITEM_H -#define QXMPPPUBSUBITEM_H +#pragma once #include "QXmppGlobal.h" @@ -13,18 +12,18 @@ #include <QSharedDataPointer> class QXmlStreamWriter; -class QXmppPubSubItemPrivate; +class QXmppPubSubBaseItemPrivate; -class QXMPP_EXPORT QXmppPubSubItem +class QXMPP_EXPORT QXmppPubSubBaseItem { public: - QXmppPubSubItem(const QString &id = {}, const QString &publisher = {}); - QXmppPubSubItem(const QXmppPubSubItem &); - QXmppPubSubItem(QXmppPubSubItem &&); - virtual ~QXmppPubSubItem(); + QXmppPubSubBaseItem(const QString &id = {}, const QString &publisher = {}); + QXmppPubSubBaseItem(const QXmppPubSubBaseItem &); + QXmppPubSubBaseItem(QXmppPubSubBaseItem &&); + virtual ~QXmppPubSubBaseItem(); - QXmppPubSubItem &operator=(const QXmppPubSubItem &); - QXmppPubSubItem &operator=(QXmppPubSubItem &&); + QXmppPubSubBaseItem &operator=(const QXmppPubSubBaseItem &); + QXmppPubSubBaseItem &operator=(QXmppPubSubBaseItem &&); QString id() const; void setId(const QString &id); @@ -47,7 +46,7 @@ protected: static bool isItem(const QDomElement &element, PayloadChecker isPayloadValid); private: - QSharedDataPointer<QXmppPubSubItemPrivate> d; + QSharedDataPointer<QXmppPubSubBaseItemPrivate> d; }; /// @@ -70,7 +69,7 @@ private: /// \endcode /// template<typename PayloadChecker> -bool QXmppPubSubItem::isItem(const QDomElement &element, PayloadChecker isPayloadValid) +bool QXmppPubSubBaseItem::isItem(const QDomElement &element, PayloadChecker isPayloadValid) { if (!isItem(element)) { return false; @@ -85,6 +84,4 @@ bool QXmppPubSubItem::isItem(const QDomElement &element, PayloadChecker isPayloa return true; } -Q_DECLARE_METATYPE(QXmppPubSubItem) - -#endif // QXMPPPUBSUBITEM_H +Q_DECLARE_METATYPE(QXmppPubSubBaseItem) diff --git a/src/base/QXmppPubSubEvent.h b/src/base/QXmppPubSubEvent.h index 0faf62b6..3625c8aa 100644 --- a/src/base/QXmppPubSubEvent.h +++ b/src/base/QXmppPubSubEvent.h @@ -15,7 +15,7 @@ class QXmppDataForm; class QXmppPubSubEventPrivate; -class QXmppPubSubItem; +class QXmppPubSubBaseItem; class QXMPP_EXPORT QXmppPubSubEventBase : public QXmppMessage { @@ -73,7 +73,7 @@ private: QSharedDataPointer<QXmppPubSubEventPrivate> d; }; -template<typename T = QXmppPubSubItem> +template<typename T = QXmppPubSubBaseItem> class QXmppPubSubEvent : public QXmppPubSubEventBase { public: diff --git a/src/base/QXmppPubSubIq.cpp b/src/base/QXmppPubSubIq.cpp index d45df2d3..27da0e4b 100644 --- a/src/base/QXmppPubSubIq.cpp +++ b/src/base/QXmppPubSubIq.cpp @@ -81,7 +81,9 @@ static const QStringList PUBSUB_QUERIES = { QStringLiteral("unsubscribe"), }; -class QXmppPubSubIqPrivate : public QSharedData +namespace QXmpp::Private { + +class PubSubIqPrivate : public QSharedData { public: PubSubIqBase::QueryType queryType = PubSubIqBase::Items; @@ -95,11 +97,13 @@ public: std::optional<QXmppResultSetReply> itemsContinuation; }; +} + /// /// Constructs a PubSub IQ. /// PubSubIqBase::PubSubIqBase() - : d(new QXmppPubSubIqPrivate) + : d(new PubSubIqPrivate) { } diff --git a/src/base/QXmppPubSubIq_p.h b/src/base/QXmppPubSubIq_p.h index eb5ed43f..c8828579 100644 --- a/src/base/QXmppPubSubIq_p.h +++ b/src/base/QXmppPubSubIq_p.h @@ -14,14 +14,15 @@ #include <QSharedDataPointer> class QXmppDataForm; -class QXmppPubSubIqPrivate; -class QXmppPubSubItem; +class QXmppPubSubBaseItem; class QXmppPubSubSubscription; class QXmppPubSubAffiliation; class QXmppResultSetReply; namespace QXmpp::Private { +class PubSubIqPrivate; + class QXMPP_EXPORT PubSubIqBase : public QXmppIq { public: @@ -100,10 +101,10 @@ private: static std::optional<QueryType> queryTypeFromDomElement(const QDomElement &element); static bool queryTypeIsOwnerIq(QueryType type); - QSharedDataPointer<QXmppPubSubIqPrivate> d; + QSharedDataPointer<PubSubIqPrivate> d; }; -template<typename T = QXmppPubSubItem> +template<typename T = QXmppPubSubBaseItem> class PubSubIq : public PubSubIqBase { public: diff --git a/src/base/QXmppSasl.cpp b/src/base/QXmppSasl.cpp index d566dc5c..184732a3 100644 --- a/src/base/QXmppSasl.cpp +++ b/src/base/QXmppSasl.cpp @@ -876,8 +876,12 @@ QMap<QByteArray, QByteArray> QXmppSaslDigestMd5::parseMessage(const QByteArray & const QByteArray key = ba.mid(startIndex, pos - startIndex).trimmed(); pos++; - // check whether string is quoted - if (ba.at(pos) == '"') { + if (pos == ba.size()) { + // end of the input + map.insert(key, QByteArray()); + startIndex = pos; + } else if (ba.at(pos) == '"') { + // check whether string is quoted // skip opening quote pos++; int endPos = ba.indexOf('"', pos); diff --git a/src/base/QXmppUserTuneItem.cpp b/src/base/QXmppUserTuneItem.cpp index 6d8fb8bf..55d30333 100644 --- a/src/base/QXmppUserTuneItem.cpp +++ b/src/base/QXmppUserTuneItem.cpp @@ -224,7 +224,7 @@ bool QXmppTuneItem::isItem(const QDomElement &itemElement) payload.namespaceURI() == ns_tune; }; - return QXmppPubSubItem::isItem(itemElement, isPayloadValid); + return QXmppPubSubBaseItem::isItem(itemElement, isPayloadValid); } /// \cond diff --git a/src/base/QXmppUserTuneItem.h b/src/base/QXmppUserTuneItem.h index 03bafb1e..c4b1f0a8 100644 --- a/src/base/QXmppUserTuneItem.h +++ b/src/base/QXmppUserTuneItem.h @@ -5,7 +5,7 @@ #ifndef QXMPPUSERTUNEITEM_H #define QXMPPUSERTUNEITEM_H -#include "QXmppPubSubItem.h" +#include "QXmppPubSubBaseItem.h" #include <chrono> #include <optional> @@ -16,7 +16,7 @@ class QXmppTuneItemPrivate; class QUrl; -class QXMPP_EXPORT QXmppTuneItem : public QXmppPubSubItem +class QXMPP_EXPORT QXmppTuneItem : public QXmppPubSubBaseItem { public: QXmppTuneItem(); diff --git a/src/base/compat/QXmppPubSubIq.cpp b/src/base/compat/QXmppPubSubIq.cpp new file mode 100644 index 00000000..9df2fdf1 --- /dev/null +++ b/src/base/compat/QXmppPubSubIq.cpp @@ -0,0 +1,210 @@ +// SPDX-FileCopyrightText: 2010 Jeremy Lainé <jeremy.laine@m4x.org> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "QXmppPubSubIq.h" + +#include "QXmppConstants_p.h" +#include "QXmppUtils.h" + +#include <QDomElement> +#include <QSharedData> + +/// \cond +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + +static const QStringList PUBSUB_QUERIES = { + QStringLiteral("affiliations"), + QStringLiteral("default"), + QStringLiteral("items"), + QStringLiteral("publish"), + QStringLiteral("retract"), + QStringLiteral("subscribe"), + QStringLiteral("subscription"), + QStringLiteral("subscriptions"), + QStringLiteral("unsubscribe"), +}; + +class QXmppPubSubIqPrivate : public QSharedData +{ +public: + QXmppPubSubIqPrivate(); + + QXmppPubSubIq::QueryType queryType; + QString queryJid; + QString queryNode; + QList<QXmppPubSubItem> items; + QString subscriptionId; + QString subscriptionType; +}; + +QXmppPubSubIqPrivate::QXmppPubSubIqPrivate() + : queryType(QXmppPubSubIq::ItemsQuery) +{ +} + +QXmppPubSubIq::QXmppPubSubIq() + : d(new QXmppPubSubIqPrivate) +{ +} + +QXmppPubSubIq::QXmppPubSubIq(const QXmppPubSubIq &iq) = default; + +QXmppPubSubIq::~QXmppPubSubIq() = default; + +QXmppPubSubIq &QXmppPubSubIq::operator=(const QXmppPubSubIq &iq) = default; + +/// Returns the PubSub queryType for this IQ. + +QXmppPubSubIq::QueryType QXmppPubSubIq::queryType() const +{ + return d->queryType; +} + +/// Sets the PubSub queryType for this IQ. +/// +/// \param queryType + +void QXmppPubSubIq::setQueryType(QXmppPubSubIq::QueryType queryType) +{ + d->queryType = queryType; +} + +/// Returns the JID being queried. + +QString QXmppPubSubIq::queryJid() const +{ + return d->queryJid; +} + +/// Sets the JID being queried. +/// +/// \param queryJid + +void QXmppPubSubIq::setQueryJid(const QString &queryJid) +{ + d->queryJid = queryJid; +} + +/// Returns the node being queried. + +QString QXmppPubSubIq::queryNode() const +{ + return d->queryNode; +} + +/// Sets the node being queried. +/// +/// \param queryNode + +void QXmppPubSubIq::setQueryNode(const QString &queryNode) +{ + d->queryNode = queryNode; +} + +/// Returns the subscription ID. + +QString QXmppPubSubIq::subscriptionId() const +{ + return d->subscriptionId; +} + +/// Sets the subscription ID. +/// +/// \param subscriptionId + +void QXmppPubSubIq::setSubscriptionId(const QString &subscriptionId) +{ + d->subscriptionId = subscriptionId; +} + +/// Returns the IQ's items. + +QList<QXmppPubSubItem> QXmppPubSubIq::items() const +{ + return d->items; +} + +/// Sets the IQ's items. +/// +/// \param items + +void QXmppPubSubIq::setItems(const QList<QXmppPubSubItem> &items) +{ + d->items = items; +} + +bool QXmppPubSubIq::isPubSubIq(const QDomElement &element) +{ + return element.firstChildElement(QStringLiteral("pubsub")).namespaceURI() == ns_pubsub; +} + +void QXmppPubSubIq::parseElementFromChild(const QDomElement &element) +{ + const QDomElement pubSubElement = element.firstChildElement(QStringLiteral("pubsub")); + + const QDomElement queryElement = pubSubElement.firstChildElement(); + + // determine query type + const QString tagName = queryElement.tagName(); + int queryType = PUBSUB_QUERIES.indexOf(queryElement.tagName()); + if (queryType > -1) + d->queryType = QueryType(queryType); + + d->queryJid = queryElement.attribute(QStringLiteral("jid")); + d->queryNode = queryElement.attribute(QStringLiteral("node")); + + // parse contents + QDomElement childElement; + switch (d->queryType) { + case QXmppPubSubIq::ItemsQuery: + case QXmppPubSubIq::PublishQuery: + case QXmppPubSubIq::RetractQuery: + childElement = queryElement.firstChildElement(QStringLiteral("item")); + while (!childElement.isNull()) { + QXmppPubSubItem item; + item.parse(childElement); + d->items << item; + childElement = childElement.nextSiblingElement(QStringLiteral("item")); + } + break; + case QXmppPubSubIq::SubscriptionQuery: + d->subscriptionId = queryElement.attribute(QStringLiteral("subid")); + d->subscriptionType = queryElement.attribute(QStringLiteral("subscription")); + break; + default: + break; + } +} + +void QXmppPubSubIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement(QStringLiteral("pubsub")); + writer->writeDefaultNamespace(ns_pubsub); + + // write query type + writer->writeStartElement(PUBSUB_QUERIES.at(d->queryType)); + helperToXmlAddAttribute(writer, QStringLiteral("jid"), d->queryJid); + helperToXmlAddAttribute(writer, QStringLiteral("node"), d->queryNode); + + // write contents + switch (d->queryType) { + case QXmppPubSubIq::ItemsQuery: + case QXmppPubSubIq::PublishQuery: + case QXmppPubSubIq::RetractQuery: + for (const auto &item : d->items) + item.toXml(writer); + break; + case QXmppPubSubIq::SubscriptionQuery: + helperToXmlAddAttribute(writer, QStringLiteral("subid"), d->subscriptionId); + helperToXmlAddAttribute(writer, QStringLiteral("subscription"), d->subscriptionType); + break; + default: + break; + } + writer->writeEndElement(); + writer->writeEndElement(); +} +QT_WARNING_POP +/// \endcond diff --git a/src/base/compat/QXmppPubSubIq.h b/src/base/compat/QXmppPubSubIq.h new file mode 100644 index 00000000..057efa98 --- /dev/null +++ b/src/base/compat/QXmppPubSubIq.h @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2010 Jeremy Lainé <jeremy.laine@m4x.org> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPPUBSUBIQ_H +#define QXMPPPUBSUBIQ_H + +#include "QXmppIq.h" + +#include <QSharedDataPointer> + +#if QXMPP_DEPRECATED_SINCE(1, 2) +#include "QXmppPubSubItem.h" +#endif + +class QXmppPubSubIqPrivate; + +#if QXMPP_DEPRECATED_SINCE(1, 5) +class QXMPP_EXPORT QXmppPubSubIq : public QXmppIq +{ +public: + enum [[deprecated]] QueryType { + AffiliationsQuery, + DefaultQuery, + ItemsQuery, + PublishQuery, + RetractQuery, + SubscribeQuery, + SubscriptionQuery, + SubscriptionsQuery, + UnsubscribeQuery + }; + + [[deprecated]] QXmppPubSubIq(); + QXmppPubSubIq(const QXmppPubSubIq &iq); + ~QXmppPubSubIq(); + + QXmppPubSubIq &operator=(const QXmppPubSubIq &iq); + + [[deprecated]] QXmppPubSubIq::QueryType queryType() const; + [[deprecated]] void setQueryType(QXmppPubSubIq::QueryType queryType); + + [[deprecated]] QString queryJid() const; + [[deprecated]] void setQueryJid(const QString &jid); + + [[deprecated]] QString queryNode() const; + [[deprecated]] void setQueryNode(const QString &node); + + [[deprecated]] QList<QXmppPubSubItem> items() const; + [[deprecated]] void setItems(const QList<QXmppPubSubItem> &items); + + [[deprecated]] QString subscriptionId() const; + [[deprecated]] void setSubscriptionId(const QString &id); + + [[deprecated]] static bool isPubSubIq(const QDomElement &element); + +protected: + void parseElementFromChild(const QDomElement &) override; + void toXmlElementFromChild(QXmlStreamWriter *writer) const override; + +private: + QSharedDataPointer<QXmppPubSubIqPrivate> d; +}; +#endif + +#endif // QXMPPPUBSUBIQ_H diff --git a/src/base/compat/QXmppPubSubItem.cpp b/src/base/compat/QXmppPubSubItem.cpp new file mode 100644 index 00000000..cfd2724e --- /dev/null +++ b/src/base/compat/QXmppPubSubItem.cpp @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: 2010 Jeremy Lainé <jeremy.laine@m4x.org> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "QXmppPubSubItem.h" + +#include "QXmppElement.h" +#include "QXmppUtils.h" + +#include <QDomElement> + +/// \cond +class QXmppPubSubItemPrivate : public QSharedData +{ +public: + QString id; + QXmppElement contents; +}; + +QXmppPubSubItem::QXmppPubSubItem() + : d(new QXmppPubSubItemPrivate) +{ +} + +QXmppPubSubItem::QXmppPubSubItem(const QXmppPubSubItem &iq) = default; + +QXmppPubSubItem::~QXmppPubSubItem() = default; + +QXmppPubSubItem &QXmppPubSubItem::operator=(const QXmppPubSubItem &iq) = default; + +/// Returns the ID of the PubSub item. + +QString QXmppPubSubItem::id() const +{ + return d->id; +} + +/// Sets the ID of the PubSub item. +/// +/// \param id + +void QXmppPubSubItem::setId(const QString &id) +{ + d->id = id; +} + +/// Returns the contents of the PubSub item. + +QXmppElement QXmppPubSubItem::contents() const +{ + return d->contents; +} + +/// Sets the contents of the PubSub item. +/// +/// \param contents + +void QXmppPubSubItem::setContents(const QXmppElement &contents) +{ + d->contents = contents; +} + +void QXmppPubSubItem::parse(const QDomElement &element) +{ + d->id = element.attribute(QStringLiteral("id")); + d->contents = QXmppElement(element.firstChildElement()); +} + +void QXmppPubSubItem::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement(QStringLiteral("item")); + helperToXmlAddAttribute(writer, QStringLiteral("id"), d->id); + d->contents.toXml(writer); + writer->writeEndElement(); +} +/// \endcond diff --git a/src/base/compat/QXmppPubSubItem.h b/src/base/compat/QXmppPubSubItem.h new file mode 100644 index 00000000..1d8dc4d3 --- /dev/null +++ b/src/base/compat/QXmppPubSubItem.h @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2010 Jeremy Lainé <jeremy.laine@m4x.org> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPPUBSUBITEM_H +#define QXMPPPUBSUBITEM_H + +#include "QXmppGlobal.h" + +#include <QSharedDataPointer> + +class QDomElement; +class QXmlStreamWriter; + +class QXmppElement; +class QXmppPubSubItemPrivate; + +#if QXMPP_DEPRECATED_SINCE(1, 5) +class QXMPP_EXPORT QXmppPubSubItem +{ +public: + [[deprecated]] QXmppPubSubItem(); + QXmppPubSubItem(const QXmppPubSubItem &iq); + ~QXmppPubSubItem(); + + QXmppPubSubItem &operator=(const QXmppPubSubItem &iq); + + [[deprecated]] QString id() const; + [[deprecated]] void setId(const QString &id); + + [[deprecated]] QXmppElement contents() const; + [[deprecated]] void setContents(const QXmppElement &contents); + + [[deprecated]] void parse(const QDomElement &element); + [[deprecated]] void toXml(QXmlStreamWriter *writer) const; + +private: + QSharedDataPointer<QXmppPubSubItemPrivate> d; +}; +#endif + +#endif // QXMPPPUBSUBITEM_H diff --git a/src/client/QXmppCarbonManagerV2.cpp b/src/client/QXmppCarbonManagerV2.cpp index 0f48370e..7959cab3 100644 --- a/src/client/QXmppCarbonManagerV2.cpp +++ b/src/client/QXmppCarbonManagerV2.cpp @@ -18,9 +18,10 @@ using namespace QXmpp::Private; class CarbonEnableIq : public QXmppIq { public: - CarbonEnableIq() + CarbonEnableIq(const QString &jid) : QXmppIq() { + setTo(jid); setType(QXmppIq::Set); } @@ -30,7 +31,8 @@ public: } void toXmlElementFromChild(QXmlStreamWriter *writer) const override { - writer->writeStartElement(ns_carbons, "enable"); + writer->writeStartElement(QStringLiteral("enable")); + writer->writeDefaultNamespace(ns_carbons); writer->writeEndElement(); } }; @@ -163,7 +165,7 @@ void QXmppCarbonManagerV2::enableCarbons() return; } - client()->sendIq(CarbonEnableIq()).then(this, [this](QXmppClient::IqResult domResult) { + client()->sendIq(CarbonEnableIq(client()->configuration().jidBare())).then(this, [this](QXmppClient::IqResult domResult) { if (auto err = parseIq(std::move(domResult))) { warning("Could not enable message carbons: " % err->description); } else { diff --git a/src/client/QXmppDiscoveryManager.h b/src/client/QXmppDiscoveryManager.h index 10744a0d..d45e63a4 100644 --- a/src/client/QXmppDiscoveryManager.h +++ b/src/client/QXmppDiscoveryManager.h @@ -15,7 +15,7 @@ class QXmppTask; class QXmppDataForm; class QXmppDiscoveryIq; class QXmppDiscoveryManagerPrivate; -class QXmppError; +struct QXmppError; /// \brief The QXmppDiscoveryManager class makes it possible to discover information /// about other entities as defined by \xep{0030}: Service Discovery. diff --git a/src/client/QXmppEntityTimeManager.h b/src/client/QXmppEntityTimeManager.h index 3b090feb..87219122 100644 --- a/src/client/QXmppEntityTimeManager.h +++ b/src/client/QXmppEntityTimeManager.h @@ -13,7 +13,7 @@ template<class T> class QXmppTask; class QXmppEntityTimeIq; -class QXmppError; +struct QXmppError; /// /// \brief The QXmppEntityTimeManager class provided the functionality to get diff --git a/src/client/QXmppFileEncryption.cpp b/src/client/QXmppFileEncryption.cpp index ba78821e..e767769a 100644 --- a/src/client/QXmppFileEncryption.cpp +++ b/src/client/QXmppFileEncryption.cpp @@ -7,6 +7,8 @@ #include <QByteArray> #include <QtCrypto> +#undef min + using namespace QCA; constexpr std::size_t AES128_BLOCK_SIZE = 128 / 8; diff --git a/src/client/QXmppFileEncryption.h b/src/client/QXmppFileEncryption.h index 5bd52c7e..e50bf83c 100644 --- a/src/client/QXmppFileEncryption.h +++ b/src/client/QXmppFileEncryption.h @@ -23,9 +23,9 @@ enum Direction { Decode, }; -QByteArray process(const QByteArray &data, Cipher cipherConfig, Direction direction, const QByteArray &key, const QByteArray &iv); -QByteArray generateKey(Cipher cipher); -QByteArray generateInitializationVector(Cipher); +QXMPP_EXPORT QByteArray process(const QByteArray &data, Cipher cipherConfig, Direction direction, const QByteArray &key, const QByteArray &iv); +QXMPP_EXPORT QByteArray generateKey(Cipher cipher); +QXMPP_EXPORT QByteArray generateInitializationVector(Cipher); // export for tests class QXMPP_EXPORT EncryptionDevice : public QIODevice @@ -50,7 +50,7 @@ private: std::unique_ptr<QCA::Cipher> m_cipher; }; -class DecryptionDevice : public QIODevice +class QXMPP_EXPORT DecryptionDevice : public QIODevice { public: DecryptionDevice(std::unique_ptr<QIODevice> output, Cipher config, const QByteArray &key, const QByteArray &iv); diff --git a/src/client/QXmppMamManager.cpp b/src/client/QXmppMamManager.cpp index f173aa01..c39a3411 100644 --- a/src/client/QXmppMamManager.cpp +++ b/src/client/QXmppMamManager.cpp @@ -264,11 +264,14 @@ QXmppTask<QXmppMamManager::RetrieveResult> QXmppMamManager::retrieveMessages(con if (auto *e2eeExt = client()->encryptionExtension()) { auto &messages = itr->second.messages; auto running = std::make_shared<uint>(0); + // handle case when no message is encrypted + auto hasEncryptedMessages = false; for (auto i = 0; i < messages.size(); i++) { if (!e2eeExt->isEncrypted(messages.at(i))) { continue; } + hasEncryptedMessages = true; auto message = messages.at(i); (*running)++; @@ -290,6 +293,12 @@ QXmppTask<QXmppMamManager::RetrieveResult> QXmppMamManager::retrieveMessages(con } }); } + + if (!hasEncryptedMessages) { + // finish here, no decryptMessage callback will do it + itr->second.finish(); + d->ongoingRequests.erase(itr); + } } else { itr->second.finish(); d->ongoingRequests.erase(itr); diff --git a/src/client/QXmppPubSubManager.cpp b/src/client/QXmppPubSubManager.cpp index 18ad9d7a..de7a9db0 100644 --- a/src/client/QXmppPubSubManager.cpp +++ b/src/client/QXmppPubSubManager.cpp @@ -10,7 +10,7 @@ #include "QXmppConstants_p.h" #include "QXmppPubSubAffiliation.h" #include "QXmppPubSubEventHandler.h" -#include "QXmppPubSubItem.h" +#include "QXmppPubSubBaseItem.h" #include "QXmppPubSubSubscribeOptions.h" #include "QXmppPubSubSubscription.h" #include "QXmppStanza.h" @@ -435,7 +435,7 @@ auto QXmppPubSubManager::retractItem(const QString &jid, const QString &nodeName request.setType(QXmppIq::Set); request.setQueryType(PubSubIq<>::Retract); request.setQueryNode(nodeName); - request.setItems({ QXmppPubSubItem(itemId) }); + request.setItems({ QXmppPubSubBaseItem(itemId) }); request.setTo(jid); return client()->sendGenericIq(std::move(request)); @@ -1006,10 +1006,10 @@ PubSubIq<> QXmppPubSubManager::requestItemsIq(const QString &jid, const QString request.setQueryNode(nodeName); if (!itemIds.isEmpty()) { - QVector<QXmppPubSubItem> items; + QVector<QXmppPubSubBaseItem> items; items.reserve(itemIds.size()); for (const auto &id : itemIds) { - items << QXmppPubSubItem(id); + items << QXmppPubSubBaseItem(id); } request.setItems(items); } @@ -1038,7 +1038,7 @@ auto QXmppPubSubManager::publishItems(PubSubIqBase &&request) -> QXmppTask<Publi return chainIq(client()->sendIq(std::move(request)), this, [](const PubSubIq<> &iq) -> PublishItemsResult { - const auto itemToId = [](const QXmppPubSubItem &item) { + const auto itemToId = [](const QXmppPubSubBaseItem &item) { return item.id(); }; diff --git a/src/client/QXmppPubSubManager.h b/src/client/QXmppPubSubManager.h index 73a5b4d4..154f585d 100644 --- a/src/client/QXmppPubSubManager.h +++ b/src/client/QXmppPubSubManager.h @@ -79,13 +79,13 @@ public: QXmppTask<InstantNodeResult> createInstantNode(const QString &jid, const QXmppPubSubNodeConfig &config); QXmppTask<Result> deleteNode(const QString &jid, const QString &nodeName); QXmppTask<ItemIdsResult> requestItemIds(const QString &serviceJid, const QString &nodeName); - template<typename T = QXmppPubSubItem> + template<typename T = QXmppPubSubBaseItem> QXmppTask<ItemResult<T>> requestItem(const QString &jid, const QString &nodeName, const QString &itemId); - template<typename T = QXmppPubSubItem> + template<typename T = QXmppPubSubBaseItem> QXmppTask<ItemResult<T>> requestItem(const QString &jid, const QString &nodeName, StandardItemId itemId); - template<typename T = QXmppPubSubItem> + template<typename T = QXmppPubSubBaseItem> QXmppTask<ItemsResult<T>> requestItems(const QString &jid, const QString &nodeName); - template<typename T = QXmppPubSubItem> + template<typename T = QXmppPubSubBaseItem> QXmppTask<ItemsResult<T>> requestItems(const QString &jid, const QString &nodeName, const QStringList &itemIds); template<typename T> QXmppTask<PublishItemResult> publishItem(const QString &jid, const QString &nodeName, const T &item); @@ -118,11 +118,11 @@ public: QXmppTask<Result> createOwnPepNode(const QString &nodeName) { return createNode(client()->configuration().jidBare(), nodeName); } QXmppTask<Result> createOwnPepNode(const QString &nodeName, const QXmppPubSubNodeConfig &config) { return createNode(client()->configuration().jidBare(), nodeName, config); } QXmppTask<Result> deleteOwnPepNode(const QString &nodeName) { return deleteNode(client()->configuration().jidBare(), nodeName); } - template<typename T = QXmppPubSubItem> + template<typename T = QXmppPubSubBaseItem> QXmppTask<ItemResult<T>> requestOwnPepItem(const QString &nodeName, const QString &itemId) { return requestItem<T>(client()->configuration().jidBare(), nodeName, itemId); } - template<typename T = QXmppPubSubItem> + template<typename T = QXmppPubSubBaseItem> QXmppTask<ItemResult<T>> requestOwnPepItem(const QString &nodeName, StandardItemId itemId) { return requestItem<T>(client()->configuration().jidBare(), nodeName, itemId); } - template<typename T = QXmppPubSubItem> + template<typename T = QXmppPubSubBaseItem> QXmppTask<ItemsResult<T>> requestOwnPepItems(const QString &nodeName) { return requestItems(client()->configuration().jidBare(), nodeName); } QXmppTask<ItemIdsResult> requestOwnPepItemIds(const QString &nodeName) { return requestItemIds(client()->configuration().jidBare(), nodeName); } template<typename T> diff --git a/src/client/QXmppSceEnvelope_p.h b/src/client/QXmppSceEnvelope_p.h index 4a92378d..b40da9fd 100644 --- a/src/client/QXmppSceEnvelope_p.h +++ b/src/client/QXmppSceEnvelope_p.h @@ -25,8 +25,8 @@ class QXmppSceEnvelopeReader { public: - QXmppSceEnvelopeReader(const QDomElement &element) - : element(element) + QXmppSceEnvelopeReader(QDomElement &&element) + : element(std::move(element)) { } @@ -51,7 +51,7 @@ public: // rpad is usually not needed (but can be parsed manually if really needed) private: - const QDomElement &element; + QDomElement element; }; class QXmppSceEnvelopeWriter diff --git a/src/omemo/CMakeLists.txt b/src/omemo/CMakeLists.txt index 0ec3c0f0..89e1f06c 100644 --- a/src/omemo/CMakeLists.txt +++ b/src/omemo/CMakeLists.txt @@ -54,8 +54,10 @@ set_target_properties(QXmppOmemo PROPERTIES install( TARGETS QXmppOmemo - DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT QXmppOmemoTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install( diff --git a/src/omemo/QXmppOmemoData.cpp b/src/omemo/QXmppOmemoData.cpp index d1dd2a88..43e00c35 100644 --- a/src/omemo/QXmppOmemoData.cpp +++ b/src/omemo/QXmppOmemoData.cpp @@ -3,19 +3,18 @@ // // SPDX-License-Identifier: LGPL-2.1-or-later -#include "QXmppConstants_p.h" #include "QXmppOmemoDeviceBundle_p.h" #include "QXmppOmemoDeviceElement_p.h" #include "QXmppOmemoDeviceList_p.h" #include "QXmppOmemoElement_p.h" -#include "QXmppOmemoEnvelope_p.h" #include "QXmppOmemoIq_p.h" #include "QXmppOmemoItems_p.h" -#include "QXmppUtils.h" #include <QDomElement> #include <QHash> +const char *ns_omemo_2 = "urn:xmpp:omemo:2"; + /// \cond /// /// \class QXmppOmemoDeviceElement @@ -425,7 +424,7 @@ void QXmppOmemoDeviceBundleItem::setDeviceBundle(const QXmppOmemoDeviceBundle &d bool QXmppOmemoDeviceBundleItem::isItem(const QDomElement &itemElement) { - return QXmppPubSubItem::isItem(itemElement, QXmppOmemoDeviceBundle::isOmemoDeviceBundle); + return QXmppPubSubBaseItem::isItem(itemElement, QXmppOmemoDeviceBundle::isOmemoDeviceBundle); } void QXmppOmemoDeviceBundleItem::parsePayload(const QDomElement &payloadElement) @@ -450,7 +449,7 @@ void QXmppOmemoDeviceListItem::setDeviceList(const QXmppOmemoDeviceList &deviceL bool QXmppOmemoDeviceListItem::isItem(const QDomElement &itemElement) { - return QXmppPubSubItem::isItem(itemElement, QXmppOmemoDeviceList::isOmemoDeviceList); + return QXmppPubSubBaseItem::isItem(itemElement, QXmppOmemoDeviceList::isOmemoDeviceList); } void QXmppOmemoDeviceListItem::parsePayload(const QDomElement &payloadElement) diff --git a/src/omemo/QXmppOmemoDeviceList_p.h b/src/omemo/QXmppOmemoDeviceList_p.h index 76bff435..46ac724d 100644 --- a/src/omemo/QXmppOmemoDeviceList_p.h +++ b/src/omemo/QXmppOmemoDeviceList_p.h @@ -7,12 +7,12 @@ #define QXMPPOMEMODEVICELIST_H #include "QXmppGlobal.h" +#include "QXmppOmemoDeviceElement_p.h" #include "QList" class QDomElement; class QXmlStreamWriter; -class QXmppOmemoDeviceElement; class QXMPP_AUTOTEST_EXPORT QXmppOmemoDeviceList : public QList<QXmppOmemoDeviceElement> { diff --git a/src/omemo/QXmppOmemoItems_p.h b/src/omemo/QXmppOmemoItems_p.h index 9b816ed8..abc6a65f 100644 --- a/src/omemo/QXmppOmemoItems_p.h +++ b/src/omemo/QXmppOmemoItems_p.h @@ -7,9 +7,9 @@ #include "QXmppOmemoDeviceBundle_p.h" #include "QXmppOmemoDeviceList_p.h" -#include "QXmppPubSubItem.h" +#include "QXmppPubSubBaseItem.h" -class QXmppOmemoDeviceBundleItem : public QXmppPubSubItem +class QXmppOmemoDeviceBundleItem : public QXmppPubSubBaseItem { public: QXmppOmemoDeviceBundle deviceBundle() const; @@ -25,7 +25,7 @@ private: QXmppOmemoDeviceBundle m_deviceBundle; }; -class QXmppOmemoDeviceListItem : public QXmppPubSubItem +class QXmppOmemoDeviceListItem : public QXmppPubSubBaseItem { public: QXmppOmemoDeviceList deviceList() const; diff --git a/src/omemo/QXmppOmemoManager.cpp b/src/omemo/QXmppOmemoManager.cpp index 55a21190..0aab152d 100644 --- a/src/omemo/QXmppOmemoManager.cpp +++ b/src/omemo/QXmppOmemoManager.cpp @@ -4,11 +4,7 @@ // SPDX-License-Identifier: LGPL-2.1-or-later #include "QXmppClient.h" -#include "QXmppConstants_p.h" -#include "QXmppOmemoDeviceElement_p.h" -#include "QXmppOmemoDeviceList_p.h" #include "QXmppOmemoElement_p.h" -#include "QXmppOmemoEnvelope_p.h" #include "QXmppOmemoIq_p.h" #include "QXmppOmemoItems_p.h" #include "QXmppOmemoManager_p.h" @@ -18,6 +14,9 @@ #include <QStringBuilder> +#undef max +#undef interface + using namespace QXmpp; using namespace QXmpp::Private; using namespace QXmpp::Omemo::Private; @@ -669,7 +668,7 @@ QXmppOmemoOwnDevice Manager::ownDevice() QXmppOmemoOwnDevice device; device.setLabel(ownDevice.label); - device.setKeyId(createKeyId(ownDevice.publicIdentityKey)); + device.setKeyId(ownDevice.publicIdentityKey); return device; } @@ -885,13 +884,16 @@ QXmppTask<void> Manager::buildMissingSessions(const QList<QString> &jids) auto future = d->buildSessionWithDeviceBundle(jid, deviceId, device); future.then(this, [=](auto) mutable { if (++(*processedDevicesCount) == devicesCount) { + interface.finish(); } }); } else if (++(*processedDevicesCount) == devicesCount) { + interface.finish(); } } } } else { + interface.finish(); } return interface.task(); diff --git a/src/omemo/QXmppOmemoManager_p.cpp b/src/omemo/QXmppOmemoManager_p.cpp index 2e08da04..1c86d80b 100644 --- a/src/omemo/QXmppOmemoManager_p.cpp +++ b/src/omemo/QXmppOmemoManager_p.cpp @@ -7,13 +7,12 @@ #include "QXmppOmemoManager_p.h" -#include "QXmppConstants_p.h" #include "QXmppOmemoDeviceElement_p.h" #include "QXmppOmemoElement_p.h" #include "QXmppOmemoEnvelope_p.h" #include "QXmppOmemoIq_p.h" #include "QXmppOmemoItems_p.h" -#include "QXmppPubSubItem.h" +#include "QXmppPubSubBaseItem.h" #include "QXmppSceEnvelope_p.h" #include "QXmppTrustManager.h" #include "QXmppUtils.h" @@ -25,6 +24,9 @@ #include <QRandomGenerator> #include <QStringBuilder> +#undef max +#undef interface + using namespace QXmpp; using namespace QXmpp::Private; using namespace QXmpp::Omemo::Private; @@ -33,27 +35,19 @@ using Error = QXmppStanza::Error; using Manager = QXmppOmemoManager; using ManagerPrivate = QXmppOmemoManagerPrivate; +const char *ns_client = "jabber:client"; +const char *ns_pubsub_auto_create = "http://jabber.org/protocol/pubsub#auto-create"; +const char *ns_pubsub_config_node = "http://jabber.org/protocol/pubsub#config-node"; +const char *ns_pubsub_config_node_max = "http://jabber.org/protocol/pubsub#config-node-max"; +const char *ns_pubsub_create_and_configure = "http://jabber.org/protocol/pubsub#create-and-configure"; +const char *ns_pubsub_create_nodes = "http://jabber.org/protocol/pubsub#create-nodes"; +const char *ns_pubsub_publish = "http://jabber.org/protocol/pubsub#publish"; +const char *ns_pubsub_publish_options = "http://jabber.org/protocol/pubsub#publish-options"; + namespace QXmpp::Omemo::Private { const QString PAYLOAD_MESSAGE_AUTHENTICATION_CODE_TYPE = QStringLiteral("hmac(sha256)"); -// -// Creates a key ID. -// -// The first byte representing a version string used by the OMEMO library but -// not needed for trust management is removed. -// It corresponds to the fingerprint shown to users which also does not contain -// the first byte. -// -// \param key key for whom its ID is created -// -// \return the key ID -// -QByteArray createKeyId(const QByteArray &key) -{ - return QByteArray(key).remove(0, 1); -} - } // namespace QXmpp::Omemo::Private // @@ -710,13 +704,7 @@ bool ManagerPrivate::setUpIdentityKeyPair(ratchet_identity_key_pair **identityKe const auto privateIdentityKey = privateIdentityKeyBuffer.toByteArray(); ownDevice.privateIdentityKey = privateIdentityKey; - BufferPtr publicIdentityKeyBuffer; - - if (ec_public_key_serialize(publicIdentityKeyBuffer.ptrRef(), ratchet_identity_key_pair_get_public(*identityKeyPair)) < 0) { - warning("Public identity key could not be serialized"); - return false; - } - + BufferPtr publicIdentityKeyBuffer(ec_public_key_get_ed(ratchet_identity_key_pair_get_public(*identityKeyPair))); const auto publicIdentityKey = publicIdentityKeyBuffer.toByteArray(); deviceBundle.setPublicIdentityKey(publicIdentityKey); ownDevice.publicIdentityKey = publicIdentityKey; @@ -832,18 +820,12 @@ bool ManagerPrivate::updateSignedPreKeyPair(ratchet_identity_key_pair *identityK signedPreKeyPairs.insert(latestSignedPreKeyId, signedPreKeyPairForStorage); omemoStorage->addSignedPreKeyPair(latestSignedPreKeyId, signedPreKeyPairForStorage); - BufferPtr signedPublicPreKeyBuffer; - - if (ec_public_key_serialize(signedPublicPreKeyBuffer.ptrRef(), ec_key_pair_get_public(session_signed_pre_key_get_key_pair(signedPreKeyPair.get()))) < 0) { - warning("Signed public pre key could not be serialized"); - return false; - } - + BufferPtr signedPublicPreKeyBuffer(ec_public_key_get_mont(ec_key_pair_get_public(session_signed_pre_key_get_key_pair(signedPreKeyPair.get())))); const auto signedPublicPreKeyByteArray = signedPublicPreKeyBuffer.toByteArray(); deviceBundle.setSignedPublicPreKeyId(latestSignedPreKeyId); deviceBundle.setSignedPublicPreKey(signedPublicPreKeyByteArray); - deviceBundle.setSignedPublicPreKeySignature(QByteArray(reinterpret_cast<const char *>(session_signed_pre_key_get_signature(signedPreKeyPair.get())), session_signed_pre_key_get_signature_len(signedPreKeyPair.get()))); + deviceBundle.setSignedPublicPreKeySignature(QByteArray(reinterpret_cast<const char *>(session_signed_pre_key_get_signature_omemo(signedPreKeyPair.get())), session_signed_pre_key_get_signature_omemo_len(signedPreKeyPair.get()))); ownDevice.latestSignedPreKeyId = latestSignedPreKeyId; @@ -921,7 +903,6 @@ bool ManagerPrivate::updatePreKeyPairs(uint32_t count) node != nullptr; node = signal_protocol_key_helper_key_list_next(node)) { BufferSecurePtr preKeyPairBuffer; - BufferPtr publicPreKeyBuffer; auto preKeyPair = signal_protocol_key_helper_key_list_element(node); @@ -934,11 +915,7 @@ bool ManagerPrivate::updatePreKeyPairs(uint32_t count) serializedPreKeyPairs.insert(preKeyId, preKeyPairBuffer.toByteArray()); - if (ec_public_key_serialize(publicPreKeyBuffer.ptrRef(), ec_key_pair_get_public(session_pre_key_get_key_pair(preKeyPair))) < 0) { - warning("Public pre key could not be serialized"); - return false; - } - + BufferPtr publicPreKeyBuffer(ec_public_key_get_mont(ec_key_pair_get_public(session_pre_key_get_key_pair(preKeyPair)))); const auto serializedPublicPreKey = publicPreKeyBuffer.toByteArray(); deviceBundle.addPublicPreKey(preKeyId, serializedPublicPreKey); } @@ -1017,7 +994,7 @@ bool ManagerPrivate::generateIdentityKeyPair(ratchet_identity_key_pair **identit RefCountedPtr<ec_public_key> publicIdentityKey; - if (curve_decode_point(publicIdentityKey.ptrRef(), signal_buffer_data(publicIdentityKeyBuffer.get()), signal_buffer_len(publicIdentityKeyBuffer.get()), globalContext.get()) < 0) { + if (curve_decode_point_ed(publicIdentityKey.ptrRef(), signal_buffer_data(publicIdentityKeyBuffer.get()), signal_buffer_len(publicIdentityKeyBuffer.get()), globalContext.get()) < 0) { warning("Public identity key could not be deserialized"); return false; } @@ -1234,15 +1211,14 @@ QXmppTask<std::optional<QXmppOmemoElement>> ManagerPrivate::encryptStanza(const if (optionalDeviceBundle && devices.value(jid).contains(deviceId)) { auto &deviceBeingModified = devices[jid][deviceId]; const auto &deviceBundle = *optionalDeviceBundle; - const auto key = deviceBundle.publicIdentityKey(); - deviceBeingModified.keyId = createKeyId(key); + deviceBeingModified.keyId = deviceBundle.publicIdentityKey(); auto future = q->trustLevel(jid, deviceBeingModified.keyId); future.then(q, [=](TrustLevel trustLevel) mutable { // Store the retrieved key's trust level if it is not stored // yet. if (trustLevel == TrustLevel::Undecided) { - auto future = storeKeyDependingOnSecurityPolicy(jid, key); + auto future = storeKeyDependingOnSecurityPolicy(jid, deviceBeingModified.keyId); future.then(q, [=](TrustLevel trustLevel) mutable { omemoStorage->addDevice(jid, deviceId, deviceBeingModified); Q_EMIT q->deviceChanged(jid, deviceId); @@ -1473,8 +1449,6 @@ QXmppTask<std::optional<QXmppMessage>> ManagerPrivate::decryptMessage(QXmppMessa future.then(q, [=](std::optional<QCA::SecureArray> payloadDecryptionData) mutable { if (!payloadDecryptionData) { warning("Empty OMEMO message could not be successfully processed"); - } else if (payloadDecryptionData->isEmpty()) { - warning("Empty OMEMO message could not be successfully processed"); } else { q->debug("Successfully processed empty OMEMO message"); } @@ -1576,48 +1550,38 @@ QXmppTask<std::optional<DecryptionResult>> ManagerPrivate::decryptStanza(T stanz QXmppSceEnvelopeReader sceEnvelopeReader(document.documentElement()); if (sceEnvelopeReader.from() != senderJid) { - warning("Sender '" % senderJid % "' of stanza does not match SCE 'from' affix element '" % sceEnvelopeReader.from() % "'"); - interface.finish(std::nullopt); - } else { - const auto recipientJid = QXmppUtils::jidToBareJid(stanza.to()); - auto isSceAffixElementValid = true; + q->info("Sender '" % senderJid % "' of stanza does not match SCE 'from' affix element '" % sceEnvelopeReader.from() % "'"); + } - if (isMessageStanza) { - if (const auto &message = dynamic_cast<const QXmppMessage &>(stanza); message.type() == QXmppMessage::GroupChat && (sceEnvelopeReader.to() != recipientJid)) { - warning("Recipient of group chat message does not match SCE affix element '<to/>'"); - isSceAffixElementValid = false; - } - } else { - if (sceEnvelopeReader.to() != recipientJid) { - warning("Recipient of IQ does not match SCE affix element '<to/>'"); - isSceAffixElementValid = false; - } + if (const auto recipientJid = QXmppUtils::jidToBareJid(stanza.to()); isMessageStanza) { + if (const auto &message = dynamic_cast<const QXmppMessage &>(stanza); message.type() == QXmppMessage::GroupChat && (sceEnvelopeReader.to() != recipientJid)) { + warning("Recipient of group chat message does not match SCE affix element '<to/>'"); + interface.finish(std::nullopt); + return; } + } else if (sceEnvelopeReader.to() != recipientJid) { + q->info("Recipient of IQ does not match SCE affix element '<to/>'"); + } - if (!isSceAffixElementValid) { - interface.finish(std::nullopt); - } else { - auto &device = devices[senderJid][senderDeviceId]; - device.unrespondedSentStanzasCount = 0; + auto &device = devices[senderJid][senderDeviceId]; + device.unrespondedSentStanzasCount = 0; - // Send a heartbeat message to the sender if too many stanzas were - // received responding to none. - if (device.unrespondedReceivedStanzasCount == UNRESPONDED_STANZAS_UNTIL_HEARTBEAT_MESSAGE_IS_SENT) { - sendEmptyMessage(senderJid, senderDeviceId); - device.unrespondedReceivedStanzasCount = 0; - } else { - ++device.unrespondedReceivedStanzasCount; - } + // Send a heartbeat message to the sender if too many stanzas were + // received responding to none. + if (device.unrespondedReceivedStanzasCount == UNRESPONDED_STANZAS_UNTIL_HEARTBEAT_MESSAGE_IS_SENT) { + sendEmptyMessage(senderJid, senderDeviceId); + device.unrespondedReceivedStanzasCount = 0; + } else { + ++device.unrespondedReceivedStanzasCount; + } - QXmppE2eeMetadata e2eeMetadata; - e2eeMetadata.setSceTimestamp(sceEnvelopeReader.timestamp()); - e2eeMetadata.setEncryption(QXmpp::Omemo2); - const auto &senderDevice = devices.value(senderJid).value(senderDeviceId); - e2eeMetadata.setSenderKey(senderDevice.keyId); + QXmppE2eeMetadata e2eeMetadata; + e2eeMetadata.setSceTimestamp(sceEnvelopeReader.timestamp()); + e2eeMetadata.setEncryption(QXmpp::Omemo2); + const auto &senderDevice = devices.value(senderJid).value(senderDeviceId); + e2eeMetadata.setSenderKey(senderDevice.keyId); - interface.finish(DecryptionResult { sceEnvelopeReader.contentElement(), e2eeMetadata }); - } - } + interface.finish(DecryptionResult { sceEnvelopeReader.contentElement(), e2eeMetadata }); } }); @@ -1648,9 +1612,6 @@ QXmppTask<QByteArray> ManagerPrivate::extractSceEnvelope(const QString &senderJi if (!payloadDecryptionData) { warning("Data for decrypting OMEMO payload could not be extracted"); interface.finish(QByteArray()); - } else if (payloadDecryptionData->isEmpty()) { - warning("Data for decrypting OMEMO payload could not be extracted"); - interface.finish(QByteArray()); } else { interface.finish(decryptPayload(*payloadDecryptionData, omemoPayload)); } @@ -1669,8 +1630,7 @@ QXmppTask<QByteArray> ManagerPrivate::extractSceEnvelope(const QString &senderJi // \param omemoEnvelope OMEMO envelope containing the payload decryption data // \param isMessageStanza whether the received stanza is a message stanza // -// \return the serialized payload decryption data if it could be extracted, otherwise a -// default-constructed secure array +// \return the serialized payload decryption data if it could be extracted, otherwise std::nullopt // QXmppTask<std::optional<QCA::SecureArray>> ManagerPrivate::extractPayloadDecryptionData(const QString &senderJid, uint32_t senderDeviceId, const QXmppOmemoEnvelope &omemoEnvelope, bool isMessageStanza) { @@ -1728,11 +1688,10 @@ QXmppTask<std::optional<QCA::SecureArray>> ManagerPrivate::extractPayloadDecrypt const auto key = publicIdentityKeyBuffer.toByteArray(); auto &device = devices[senderJid][senderDeviceId]; auto &storedKeyId = device.keyId; - const auto createdKeyId = createKeyId(key); // Store the key if its ID has changed. - if (storedKeyId != createdKeyId) { - storedKeyId = createdKeyId; + if (storedKeyId != key) { + storedKeyId = key; omemoStorage->addDevice(senderJid, senderDeviceId, device); Q_EMIT q->deviceChanged(senderJid, senderDeviceId); } @@ -1781,12 +1740,7 @@ QXmppTask<std::optional<QCA::SecureArray>> ManagerPrivate::extractPayloadDecrypt auto future = q->trustLevel(senderJid, storedKeyId); future.then(q, [=](TrustLevel trustLevel) mutable { if (trustLevel == TrustLevel::Undecided) { - auto future = storeKeyDependingOnSecurityPolicy(senderJid, key); - future.then(q, [=](auto) mutable { - interface.finish(std::nullopt); - }); - } else { - interface.finish(std::nullopt); + storeKeyDependingOnSecurityPolicy(senderJid, key); } }); } @@ -3338,8 +3292,7 @@ QXmppTask<bool> ManagerPrivate::buildSessionWithDeviceBundle(const QString &jid, future.then(q, [=, &device](std::optional<QXmppOmemoDeviceBundle> optionalDeviceBundle) mutable { if (optionalDeviceBundle) { const auto &deviceBundle = *optionalDeviceBundle; - const auto key = deviceBundle.publicIdentityKey(); - device.keyId = createKeyId(key); + device.keyId = deviceBundle.publicIdentityKey(); auto future = q->trustLevel(jid, device.keyId); future.then(q, [=](TrustLevel trustLevel) mutable { @@ -3372,7 +3325,7 @@ QXmppTask<bool> ManagerPrivate::buildSessionWithDeviceBundle(const QString &jid, if (trustLevel == TrustLevel::Undecided) { // Store the key's trust level if it is not stored yet. - auto future = storeKeyDependingOnSecurityPolicy(jid, key); + auto future = storeKeyDependingOnSecurityPolicy(jid, device.keyId); future.then(q, [=](TrustLevel trustLevel) mutable { buildSessionDependingOnTrustLevel(trustLevel); }); @@ -3517,7 +3470,7 @@ bool ManagerPrivate::deserializePublicIdentityKey(ec_public_key **publicIdentity return false; } - if (curve_decode_point(publicIdentityKey, signal_buffer_data(publicIdentityKeyBuffer.get()), signal_buffer_len(publicIdentityKeyBuffer.get()), globalContext.get()) < 0) { + if (curve_decode_point_ed(publicIdentityKey, signal_buffer_data(publicIdentityKeyBuffer.get()), signal_buffer_len(publicIdentityKeyBuffer.get()), globalContext.get()) < 0) { warning("Public identity key could not be deserialized"); return false; } @@ -3542,7 +3495,7 @@ bool ManagerPrivate::deserializeSignedPublicPreKey(ec_public_key **signedPublicP return false; } - if (curve_decode_point(signedPublicPreKey, signal_buffer_data(signedPublicPreKeyBuffer.get()), signal_buffer_len(signedPublicPreKeyBuffer.get()), globalContext.get()) < 0) { + if (curve_decode_point_mont(signedPublicPreKey, signal_buffer_data(signedPublicPreKeyBuffer.get()), signal_buffer_len(signedPublicPreKeyBuffer.get()), globalContext.get()) < 0) { warning("Signed public pre key could not be deserialized"); return false; } @@ -3567,7 +3520,7 @@ bool ManagerPrivate::deserializePublicPreKey(ec_public_key **publicPreKey, const return false; } - if (curve_decode_point(publicPreKey, signal_buffer_data(publicPreKeyBuffer.get()), signal_buffer_len(publicPreKeyBuffer.get()), globalContext.get()) < 0) { + if (curve_decode_point_mont(publicPreKey, signal_buffer_data(publicPreKeyBuffer.get()), signal_buffer_len(publicPreKeyBuffer.get()), globalContext.get()) < 0) { warning("Public pre key could not be deserialized"); return false; } @@ -3633,16 +3586,11 @@ QXmppTask<QXmpp::SendResult> ManagerPrivate::sendEmptyMessage(const QString &rec // // Sets the key of this client instance's device. // -// The first byte representing a version string used by the OMEMO library but -// not needed for trust management is removed before storing it. -// It corresponds to the fingerprint shown to users which also does not contain -// the first byte. -// QXmppTask<void> ManagerPrivate::storeOwnKey() const { QXmppPromise<void> interface; - auto future = trustManager->setOwnKey(ns_omemo_2, createKeyId(ownDevice.publicIdentityKey)); + auto future = trustManager->setOwnKey(ns_omemo_2, ownDevice.publicIdentityKey); future.then(q, [=]() mutable { interface.finish(); }); @@ -3715,7 +3663,7 @@ QXmppTask<TrustLevel> ManagerPrivate::storeKey(const QString &keyOwnerJid, const { QXmppPromise<TrustLevel> interface; - auto future = trustManager->addKeys(ns_omemo_2, keyOwnerJid, { createKeyId(key) }, trustLevel); + auto future = trustManager->addKeys(ns_omemo_2, keyOwnerJid, { key }, trustLevel); future.then(q, [=]() mutable { Q_EMIT q->trustLevelsChanged({ { keyOwnerJid, key } }); interface.finish(std::move(trustLevel)); diff --git a/src/omemo/QXmppOmemoManager_p.h b/src/omemo/QXmppOmemoManager_p.h index 6875a571..96f10f94 100644 --- a/src/omemo/QXmppOmemoManager_p.h +++ b/src/omemo/QXmppOmemoManager_p.h @@ -18,6 +18,8 @@ #include <QTimer> #include <QtCrypto> +#undef max + class QXmppTrustManager; class QXmppOmemoManager; class QXmppPubSubManager; @@ -34,6 +36,11 @@ using namespace std::chrono_literals; namespace QXmpp::Omemo::Private { +// XMPP namespaces +constexpr auto ns_omemo_2 = "urn:xmpp:omemo:2"; +constexpr auto ns_omemo_2_bundles = "urn:xmpp:omemo:2:bundles"; +constexpr auto ns_omemo_2_devices = "urn:xmpp:omemo:2:devices"; + // default possible trust levels a key must have to be used for encryption // The class documentation must be adapted if the trust levels are modified. constexpr auto ACCEPTED_TRUST_LEVELS = TrustLevel::AutomaticallyTrusted | TrustLevel::ManuallyTrusted | TrustLevel::Authenticated; @@ -84,14 +91,14 @@ constexpr QCA::Cipher::Padding PAYLOAD_CIPHER_PADDING = QCA::Cipher::PKCS7; constexpr auto HKDF_INFO = "OMEMO Payload"; constexpr int HKDF_KEY_SIZE = 32; constexpr int HKDF_SALT_SIZE = 32; -constexpr int HKDF_OUTPUT_SIZE = 60; +constexpr int HKDF_OUTPUT_SIZE = 80; extern const QString PAYLOAD_MESSAGE_AUTHENTICATION_CODE_TYPE; constexpr uint32_t PAYLOAD_MESSAGE_AUTHENTICATION_CODE_SIZE = 16; constexpr int PAYLOAD_KEY_SIZE = 32; constexpr uint32_t PAYLOAD_INITIALIZATION_VECTOR_SIZE = 16; -constexpr uint32_t PAYLOAD_AUTHENTICATION_KEY_SIZE = 16; +constexpr uint32_t PAYLOAD_AUTHENTICATION_KEY_SIZE = 32; // boundaries for the count of characters in SCE's <rpad/> element constexpr uint32_t SCE_RPAD_SIZE_MIN = 0; @@ -115,8 +122,6 @@ struct IqDecryptionResult QXmppE2eeMetadata e2eeMetadata; }; -QByteArray createKeyId(const QByteArray &key); - } // namespace QXmpp::Omemo::Private using namespace QXmpp::Private; @@ -168,9 +173,10 @@ public: QXmppOmemoManagerPrivate(QXmppOmemoManager *parent, QXmppOmemoStorage *omemoStorage); void init(); - bool initGlobalContext(); - bool initLocking(); - bool initCryptoProvider(); + // exports for unit tests + QXMPP_EXPORT bool initGlobalContext(); + QXMPP_EXPORT bool initLocking(); + QXMPP_EXPORT bool initCryptoProvider(); void initStores(); signal_protocol_identity_key_store createIdentityKeyStore() const; |
