aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rw-r--r--CHANGELOG.md11
-rw-r--r--CMakeLists.txt5
-rw-r--r--README.md20
-rw-r--r--doc/Doxyfile.in4
-rw-r--r--doc/xep.doc7
-rw-r--r--examples/example_1_echoClient/example_1_echoClient.h4
-rw-r--r--examples/example_2_rosterHandling/example_2_rosterHandling.h4
-rw-r--r--examples/example_3_transferHandling/example_3_transferHandling.cpp2
-rw-r--r--examples/example_3_transferHandling/example_3_transferHandling.h2
-rw-r--r--examples/example_5_rpcInterface/remoteinterface.h4
-rw-r--r--examples/example_6_rpcClient/rpcClient.h4
-rw-r--r--examples/example_7_archiveHandling/example_7_archiveHandling.h4
-rw-r--r--examples/example_8_server/example_8_server.cpp4
-rw-r--r--examples/example_9_vCard/example_9_vCard.h4
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/base/QXmppArchiveIq.h20
-rw-r--r--src/base/QXmppBindIq.h4
-rw-r--r--src/base/QXmppByteStreamIq.h4
-rw-r--r--src/base/QXmppCodec_p.h8
-rw-r--r--src/base/QXmppConstants.cpp32
-rw-r--r--src/base/QXmppConstants_p.h32
-rw-r--r--src/base/QXmppDataForm.cpp2
-rw-r--r--src/base/QXmppDiscoveryIq.cpp6
-rw-r--r--src/base/QXmppDiscoveryIq.h4
-rw-r--r--src/base/QXmppElement.cpp6
-rw-r--r--src/base/QXmppElement.h2
-rw-r--r--src/base/QXmppEntityTimeIq.h4
-rw-r--r--src/base/QXmppGlobal.h.in10
-rw-r--r--src/base/QXmppHttpUploadIq.cpp250
-rw-r--r--src/base/QXmppHttpUploadIq.h100
-rw-r--r--src/base/QXmppIbbIq.h12
-rw-r--r--src/base/QXmppIq.h8
-rw-r--r--src/base/QXmppJingleIq.cpp2
-rw-r--r--src/base/QXmppJingleIq.h8
-rw-r--r--src/base/QXmppLogger.cpp6
-rw-r--r--src/base/QXmppLogger.h8
-rw-r--r--src/base/QXmppMamIq.h8
-rw-r--r--src/base/QXmppMessage.cpp301
-rw-r--r--src/base/QXmppMessage.h72
-rw-r--r--src/base/QXmppMixIq.cpp202
-rw-r--r--src/base/QXmppMixIq.h85
-rw-r--r--src/base/QXmppMixItem.cpp226
-rw-r--r--src/base/QXmppMixItem.h87
-rw-r--r--src/base/QXmppMucIq.h8
-rw-r--r--src/base/QXmppNonSASLAuth.h4
-rw-r--r--src/base/QXmppPingIq.h2
-rw-r--r--src/base/QXmppPresence.cpp50
-rw-r--r--src/base/QXmppPresence.h15
-rw-r--r--src/base/QXmppPubSubIq.h4
-rw-r--r--src/base/QXmppRegisterIq.h4
-rw-r--r--src/base/QXmppRosterIq.cpp177
-rw-r--r--src/base/QXmppRosterIq.h36
-rw-r--r--src/base/QXmppRpcIq.h12
-rw-r--r--src/base/QXmppRtpChannel.cpp18
-rw-r--r--src/base/QXmppRtpChannel.h32
-rw-r--r--src/base/QXmppSasl.cpp128
-rw-r--r--src/base/QXmppSasl_p.h111
-rw-r--r--src/base/QXmppSessionIq.h2
-rw-r--r--src/base/QXmppSocks.h4
-rw-r--r--src/base/QXmppStream.cpp2
-rw-r--r--src/base/QXmppStream.h2
-rw-r--r--src/base/QXmppStreamFeatures.cpp12
-rw-r--r--src/base/QXmppStreamFeatures.h13
-rw-r--r--src/base/QXmppStreamInitiationIq_p.h4
-rw-r--r--src/base/QXmppStun.cpp34
-rw-r--r--src/base/QXmppStun.h12
-rw-r--r--src/base/QXmppStun_p.h24
-rw-r--r--src/base/QXmppVCardIq.h6
-rw-r--r--src/base/QXmppVersionIq.h4
-rw-r--r--src/client/QXmppArchiveManager.h4
-rw-r--r--src/client/QXmppBookmarkManager.cpp4
-rw-r--r--src/client/QXmppBookmarkManager.h6
-rw-r--r--src/client/QXmppCallManager.cpp24
-rw-r--r--src/client/QXmppCallManager.h10
-rw-r--r--src/client/QXmppCarbonManager.h6
-rw-r--r--src/client/QXmppClient.cpp13
-rw-r--r--src/client/QXmppClient.h13
-rw-r--r--src/client/QXmppClientExtension.cpp2
-rw-r--r--src/client/QXmppClientExtension.h2
-rw-r--r--src/client/QXmppConfiguration.cpp6
-rw-r--r--src/client/QXmppDiscoveryManager.h6
-rw-r--r--src/client/QXmppEntityTimeManager.h4
-rw-r--r--src/client/QXmppInvokable.cpp2
-rw-r--r--src/client/QXmppInvokable.h4
-rw-r--r--src/client/QXmppMamManager.h4
-rw-r--r--src/client/QXmppMessageReceiptManager.cpp8
-rw-r--r--src/client/QXmppMessageReceiptManager.h4
-rw-r--r--src/client/QXmppMucManager.h10
-rw-r--r--src/client/QXmppOutgoingClient.cpp31
-rw-r--r--src/client/QXmppOutgoingClient.h12
-rw-r--r--src/client/QXmppRosterManager.h4
-rw-r--r--src/client/QXmppRpcManager.h6
-rw-r--r--src/client/QXmppTransferManager.cpp30
-rw-r--r--src/client/QXmppTransferManager.h10
-rw-r--r--src/client/QXmppVCardManager.h6
-rw-r--r--src/client/QXmppVersionManager.h6
-rw-r--r--src/server/QXmppDialback.h4
-rw-r--r--src/server/QXmppIncomingClient.cpp10
-rw-r--r--src/server/QXmppIncomingClient.h10
-rw-r--r--src/server/QXmppIncomingServer.h8
-rw-r--r--src/server/QXmppOutgoingServer.h10
-rw-r--r--src/server/QXmppPasswordChecker.h2
-rw-r--r--src/server/QXmppServer.cpp6
-rw-r--r--src/server/QXmppServer.h8
-rw-r--r--src/server/QXmppServerExtension.cpp2
-rw-r--r--src/server/QXmppServerExtension.h2
-rw-r--r--src/server/QXmppServerPlugin.h4
-rw-r--r--tests/CMakeLists.txt4
-rw-r--r--tests/qxmppcallmanager/tst_qxmppcallmanager.cpp2
-rw-r--r--tests/qxmpphttpuploadiq/tst_qxmpphttpuploadiq.cpp172
-rw-r--r--tests/qxmppmessage/tst_qxmppmessage.cpp184
-rw-r--r--tests/qxmppmessagereceiptmanager/tst_qxmppmessagereceiptmanager.cpp98
-rw-r--r--tests/qxmppmixiq/tst_qxmppmixiq.cpp419
-rw-r--r--tests/qxmppmixitem/tst_qxmppmixitem.cpp159
-rw-r--r--tests/qxmpppresence/tst_qxmpppresence.cpp28
-rw-r--r--tests/qxmpprosteriq/tst_qxmpprosteriq.cpp42
-rw-r--r--tests/qxmppsasl/tst_qxmppsasl.cpp93
-rw-r--r--tests/qxmppsocks/tst_qxmppsocks.cpp2
-rw-r--r--tests/qxmppstreamfeatures/tst_qxmppstreamfeatures.cpp44
-rw-r--r--tests/qxmpptransfermanager/tst_qxmpptransfermanager.cpp2
-rwxr-xr-xtests/travis/build-and-test10
-rw-r--r--tests/util.h4
123 files changed, 3447 insertions, 436 deletions
diff --git a/AUTHORS b/AUTHORS
index ff4469f7..a5d71fc3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,6 +7,9 @@ Manjeet Dahiya <manjeetdahiya@gmail.com>
Jeremy Lainé <jeremy.laine@m4x.org>
* Co-author of QXmpp.
+Linus Jahn <lnj@kaidan.im>
+ * Current lead developer of QXmpp.
+
Ian Reinhart Geiser <geiseri@kde.org>
* Initial author of Jabber-RPC support.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 96239d57..d6dce3a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+QXmpp 1.1.0 (UNRELEASED)
+------------------------
+
+New features:
+ - Add support for SCRAM-SHA-1 and SCRAM-SHA-256 (#183, @jlaine)
+ - Add XEP-0334: Message Processing Hints (v0.3.0) (#212, @lnjX, @jaragont,
+ @sam-truscott)
+ - Add XEP-0367: Message Attaching (v0.3.0) (#196, @lnjX)
+ - Add XEP-0380: Explicit Message Encryption (v0.3.0) (#199, @lnjX)
+ - Add XEP-0382: Spoiler messages (v0.2.0) (#195, @lnjX)
+
QXmpp 1.0.1 (Oct 14, 2019)
--------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 99ab6ce9..12a11706 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,11 +1,10 @@
+cmake_minimum_required(VERSION 3.3)
project(qxmpp)
-cmake_minimum_required(VERSION 3.2)
-
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)
set(VERSION_PATCH 1)
-set(SO_VERSION 1)
+set(SO_VERSION 2)
set(VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH VERSION_STRING)
diff --git a/README.md b/README.md
index 4b311208..12dce062 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
[![Build Status](https://img.shields.io/travis/qxmpp-project/qxmpp.svg)](https://travis-ci.org/qxmpp-project/qxmpp)
[![Code Coverage](https://img.shields.io/codecov/c/github/qxmpp-project/qxmpp.svg)](https://codecov.io/gh/qxmpp-project/qxmpp)
-ABOUT QXMPP
+About QXmpp
===========
QXmpp is a cross-platform C++ XMPP client and server library. It is written
@@ -21,7 +21,7 @@ libraries such as speex and theora enable additional features.
QXmpp is released under the terms of the GNU Lesser General Public License,
version 2.1 or later.
-BUILDING QXMPP
+Building QXmpp
==============
QXmpp requires Qt 5.0 or higher with SSL enabled.
@@ -45,7 +45,7 @@ You can pass the following arguments to CMake:
WITH_THEORA to enable theora video codec (default: false)
WITH_VPX to enable vpx video codec (default: false)
-INSTALLING QXMPP
+Installing QXmpp
================
After building QXmpp, you can install the Headers, Libraries
@@ -55,7 +55,7 @@ Install from command line:
cmake --build . --target install
-EXAMPLES
+Examples
========
Look at the example directory for various examples. Here is a description of
@@ -71,18 +71,14 @@ This is a very simple bot which echoes the message sent to it. Run this
example, send it a message from a friend of this bot and you will
receive the message back. This example shows how to receive and send messages.
-* *GuiClient*
-This is a full fledged Graphical XMPP client. This example will uses most of
-the part of this library.
-
-DOCUMENTATION
+Documentation
=============
You can find the API documentation for the latest QXmpp version here:
http://doc.qxmpp.org/
-SUPPORTED PLATFORMS
+Supported Platforms
===================
It should work on all the platforms supported by Qt. For a complete list of
@@ -90,7 +86,7 @@ platforms support by Qt, see:
https://doc.qt.io/qt-5/supported-platforms.html
-HOW TO REPORT A BUG
+How to report a bug
===================
If you think you have found a bug in QXmpp, we would like to hear about
@@ -99,7 +95,7 @@ is already know at:
https://github.com/qxmpp-project/qxmpp/issues
-DISCUSSION GROUP
+Discussion Group
================
Join QXmpp Discussion Group for queries, discussions and updates.
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index 97a4e1de..b5765cd0 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -13,3 +13,7 @@ GENERATE_LATEX = NO
HTML_TIMESTAMP = NO
QUIET = YES
RECURSIVE = YES
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = YES
+PREDEFINED = "QXMPP_DEPRECATED_SINCE(major, minor)="
diff --git a/doc/xep.doc b/doc/xep.doc
index 1a5bd147..27da33c3 100644
--- a/doc/xep.doc
+++ b/doc/xep.doc
@@ -40,11 +40,18 @@ Complete:
- XEP-0308: Last Message Correction
- XEP-0313: Message Archive Management
- XEP-0319: Last User Interaction in Presence
+- XEP-0334: Message Processing Hints (v0.3.0)
- XEP-0352: Client State Indication
+- XEP-0367: Message Attaching (v0.3.0)
+- XEP-0380: Explicit Message Encryption (v0.3.0)
+- XEP-0382: Spoiler messages (v0.2.0)
Ongoing:
- XEP-0009: Jabber-RPC (API is not finalized yet)
- XEP-0060: Publish-Subscribe (Only basic IQ implemented)
- XEP-0077: In-Band Registration (Only basic IQ implemented)
+- XEP-0363: HTTP File Upload (v0.9.0)
+- XEP-0369: Mediated Information eXchange (MIX) (Only IQ queries implemented) (v0.14.2)
+- XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements (Only IQ queries implemented) (v0.4.0)
*/
diff --git a/examples/example_1_echoClient/example_1_echoClient.h b/examples/example_1_echoClient/example_1_echoClient.h
index b10d74a0..b02d8394 100644
--- a/examples/example_1_echoClient/example_1_echoClient.h
+++ b/examples/example_1_echoClient/example_1_echoClient.h
@@ -32,8 +32,8 @@ class echoClient : public QXmppClient
Q_OBJECT
public:
- echoClient(QObject *parent = 0);
- ~echoClient();
+ echoClient(QObject *parent = nullptr);
+ ~echoClient() override;
public slots:
void messageReceived(const QXmppMessage&);
diff --git a/examples/example_2_rosterHandling/example_2_rosterHandling.h b/examples/example_2_rosterHandling/example_2_rosterHandling.h
index b53d5451..06bcc6d1 100644
--- a/examples/example_2_rosterHandling/example_2_rosterHandling.h
+++ b/examples/example_2_rosterHandling/example_2_rosterHandling.h
@@ -32,8 +32,8 @@ class xmppClient : public QXmppClient
Q_OBJECT
public:
- xmppClient(QObject *parent = 0);
- ~xmppClient();
+ xmppClient(QObject *parent = nullptr);
+ ~xmppClient() override;
public slots:
void clientConnected();
diff --git a/examples/example_3_transferHandling/example_3_transferHandling.cpp b/examples/example_3_transferHandling/example_3_transferHandling.cpp
index f6621ba2..dc4c81c8 100644
--- a/examples/example_3_transferHandling/example_3_transferHandling.cpp
+++ b/examples/example_3_transferHandling/example_3_transferHandling.cpp
@@ -35,7 +35,7 @@
#include "example_3_transferHandling.h"
xmppClient::xmppClient(QObject *parent)
- : QXmppClient(parent), transferManager(0)
+ : QXmppClient(parent), transferManager(nullptr)
{
bool check;
Q_UNUSED(check);
diff --git a/examples/example_3_transferHandling/example_3_transferHandling.h b/examples/example_3_transferHandling/example_3_transferHandling.h
index 969f7a80..e8ade267 100644
--- a/examples/example_3_transferHandling/example_3_transferHandling.h
+++ b/examples/example_3_transferHandling/example_3_transferHandling.h
@@ -33,7 +33,7 @@ class xmppClient : public QXmppClient
Q_OBJECT
public:
- xmppClient(QObject *parent = 0);
+ xmppClient(QObject *parent = nullptr);
void setRecipient(const QString &recipient);
private slots:
diff --git a/examples/example_5_rpcInterface/remoteinterface.h b/examples/example_5_rpcInterface/remoteinterface.h
index cc1fb9e8..9c63d3f8 100644
--- a/examples/example_5_rpcInterface/remoteinterface.h
+++ b/examples/example_5_rpcInterface/remoteinterface.h
@@ -7,9 +7,9 @@ class RemoteInterface : public QXmppInvokable
{
Q_OBJECT
public:
- RemoteInterface(QObject *parent = 0);
+ RemoteInterface(QObject *parent = nullptr);
- bool isAuthorized( const QString &jid ) const;
+ bool isAuthorized( const QString &jid ) const override;
// RPC Interface
public slots:
diff --git a/examples/example_6_rpcClient/rpcClient.h b/examples/example_6_rpcClient/rpcClient.h
index 126e8568..d68b7382 100644
--- a/examples/example_6_rpcClient/rpcClient.h
+++ b/examples/example_6_rpcClient/rpcClient.h
@@ -35,8 +35,8 @@ class rpcClient : public QXmppClient
Q_OBJECT
public:
- rpcClient(QObject *parent = 0);
- ~rpcClient();
+ rpcClient(QObject *parent = nullptr);
+ ~rpcClient() override;
private slots:
void slotInvokeRemoteMethod();
diff --git a/examples/example_7_archiveHandling/example_7_archiveHandling.h b/examples/example_7_archiveHandling/example_7_archiveHandling.h
index 70623e8a..a1cc5f7c 100644
--- a/examples/example_7_archiveHandling/example_7_archiveHandling.h
+++ b/examples/example_7_archiveHandling/example_7_archiveHandling.h
@@ -43,8 +43,8 @@ public:
PageBackwards
};
- xmppClient(QObject *parent = 0);
- ~xmppClient();
+ xmppClient(QObject *parent = nullptr);
+ ~xmppClient() override;
void setPageDirection(PageDirection direction);
void setPageSize(int size);
diff --git a/examples/example_8_server/example_8_server.cpp b/examples/example_8_server/example_8_server.cpp
index a9346a58..f1d00cef 100644
--- a/examples/example_8_server/example_8_server.cpp
+++ b/examples/example_8_server/example_8_server.cpp
@@ -33,7 +33,7 @@
class passwordChecker : public QXmppPasswordChecker
{
/// Retrieves the password for the given username.
- QXmppPasswordReply::Error getPassword(const QXmppPasswordRequest &request, QString &password)
+ QXmppPasswordReply::Error getPassword(const QXmppPasswordRequest &request, QString &password) override
{
if (request.username() == USERNAME)
{
@@ -45,7 +45,7 @@ class passwordChecker : public QXmppPasswordChecker
};
/// Returns true as we implemented getPassword().
- bool hasGetPassword() const
+ bool hasGetPassword() const override
{
return true;
};
diff --git a/examples/example_9_vCard/example_9_vCard.h b/examples/example_9_vCard/example_9_vCard.h
index 854baba7..24fc4b6c 100644
--- a/examples/example_9_vCard/example_9_vCard.h
+++ b/examples/example_9_vCard/example_9_vCard.h
@@ -34,8 +34,8 @@ class xmppClient : public QXmppClient
Q_OBJECT
public:
- xmppClient(QObject *parent = 0);
- ~xmppClient();
+ xmppClient(QObject *parent = nullptr);
+ ~xmppClient() override;
public slots:
void clientConnected();
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 976f069e..6af69786 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -19,12 +19,15 @@ set(INSTALL_HEADER_FILES
base/QXmppDiscoveryIq.h
base/QXmppElement.h
base/QXmppEntityTimeIq.h
+ base/QXmppHttpUploadIq.h
base/QXmppIbbIq.h
base/QXmppIq.h
base/QXmppJingleIq.h
base/QXmppLogger.h
base/QXmppMamIq.h
base/QXmppMessage.h
+ base/QXmppMixIq.h
+ base/QXmppMixItem.h
base/QXmppMucIq.h
base/QXmppNonSASLAuth.h
base/QXmppPingIq.h
@@ -93,12 +96,15 @@ set(SOURCE_FILES
base/QXmppDiscoveryIq.cpp
base/QXmppElement.cpp
base/QXmppEntityTimeIq.cpp
+ base/QXmppHttpUploadIq.cpp
base/QXmppIbbIq.cpp
base/QXmppIq.cpp
base/QXmppJingleIq.cpp
base/QXmppLogger.cpp
base/QXmppMamIq.cpp
base/QXmppMessage.cpp
+ base/QXmppMixIq.cpp
+ base/QXmppMixItem.cpp
base/QXmppMucIq.cpp
base/QXmppNonSASLAuth.cpp
base/QXmppPingIq.cpp
diff --git a/src/base/QXmppArchiveIq.h b/src/base/QXmppArchiveIq.h
index 1f82174a..a631e096 100644
--- a/src/base/QXmppArchiveIq.h
+++ b/src/base/QXmppArchiveIq.h
@@ -111,8 +111,8 @@ public:
static bool isArchiveChatIq(const QDomElement &element);
protected:
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -153,8 +153,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -186,8 +186,8 @@ public:
static bool isArchiveRemoveIq(const QDomElement &element);
protected:
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -218,8 +218,8 @@ public:
static bool isArchiveRetrieveIq(const QDomElement &element);
protected:
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -239,8 +239,8 @@ public:
static bool isArchivePrefIq(const QDomElement &element);
protected:
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
};
diff --git a/src/base/QXmppBindIq.h b/src/base/QXmppBindIq.h
index c1434d54..fec856c9 100644
--- a/src/base/QXmppBindIq.h
+++ b/src/base/QXmppBindIq.h
@@ -48,8 +48,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppByteStreamIq.h b/src/base/QXmppByteStreamIq.h
index 67a25fea..c94f1d9b 100644
--- a/src/base/QXmppByteStreamIq.h
+++ b/src/base/QXmppByteStreamIq.h
@@ -78,8 +78,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppCodec_p.h b/src/base/QXmppCodec_p.h
index 8ee51f4f..d7f80d7e 100644
--- a/src/base/QXmppCodec_p.h
+++ b/src/base/QXmppCodec_p.h
@@ -60,8 +60,8 @@ class QXmppG711aCodec : public QXmppCodec
public:
QXmppG711aCodec(int clockrate);
- qint64 encode(QDataStream &input, QDataStream &output);
- qint64 decode(QDataStream &input, QDataStream &output);
+ qint64 encode(QDataStream &input, QDataStream &output) override;
+ qint64 decode(QDataStream &input, QDataStream &output) override;
private:
int m_frequency;
@@ -76,8 +76,8 @@ class QXmppG711uCodec : public QXmppCodec
public:
QXmppG711uCodec(int clockrate);
- qint64 encode(QDataStream &input, QDataStream &output);
- qint64 decode(QDataStream &input, QDataStream &output);
+ qint64 encode(QDataStream &input, QDataStream &output) override;
+ qint64 decode(QDataStream &input, QDataStream &output) override;
private:
int m_frequency;
diff --git a/src/base/QXmppConstants.cpp b/src/base/QXmppConstants.cpp
index 513476de..92ff8689 100644
--- a/src/base/QXmppConstants.cpp
+++ b/src/base/QXmppConstants.cpp
@@ -37,6 +37,8 @@ const char* ns_stanza = "urn:ietf:params:xml:ns:xmpp-stanzas";
const char* ns_rpc = "jabber:iq:rpc";
// XEP-0020: Feature Negotiation
const char* ns_feature_negotiation = "http://jabber.org/protocol/feature-neg";
+// XEP-0027: Current Jabber OpenPGP Usage
+const char* ns_legacy_openpgp = "jabber:x:encrypted";
// XEP-0030: Service Discovery
const char* ns_disco_info = "http://jabber.org/protocol/disco#info";
const char* ns_disco_items = "http://jabber.org/protocol/disco#items";
@@ -63,6 +65,7 @@ const char* ns_oob = "jabber:x:oob";
const char *ns_xhtml_im = "http://jabber.org/protocol/xhtml-im";
// XEP-0077: In-Band Registration
const char* ns_register = "jabber:iq:register";
+const char* ns_register_feature = "http://jabber.org/features/iq-register";
// XEP-0078: Non-SASL Authentication
const char* ns_auth = "jabber:iq:auth";
const char* ns_authFeature = "http://jabber.org/features/iq-auth";
@@ -130,5 +133,34 @@ const char* ns_mam = "urn:xmpp:mam:1";
const char* ns_idle = "urn:xmpp:idle:1";
// XEP-0333: Chat Markers
const char* ns_chat_markers = "urn:xmpp:chat-markers:0";
+// XEP-0334: Message Processing Hints
+const char* ns_message_processing_hints = "urn:xmpp:hints";
// XEP-0352: Client State Indication
const char* ns_csi = "urn:xmpp:csi:0";
+// XEP-0363: HTTP File Upload
+const char* ns_http_upload = "urn:xmpp:http:upload:0";
+// XEP-0364: Current Off-the-Record Messaging Usage
+const char* ns_otr = "urn:xmpp:otr:0";
+// XEP-0367: Message Attaching
+const char* ns_message_attaching = "urn:xmpp:message-attaching:1";
+// XEP-0369: Mediated Information eXchange (MIX)
+const char* ns_mix = "urn:xmpp:mix:core:1";
+const char* ns_mix_create_channel = "urn:xmpp:mix:core:1#create-channel";
+const char* ns_mix_searchable = "urn:xmpp:mix:core:1#searchable";
+const char* ns_mix_node_messages = "urn:xmpp:mix:nodes:messages";
+const char* ns_mix_node_participants = "urn:xmpp:mix:nodes:participants";
+const char* ns_mix_node_presence = "urn:xmpp:mix:nodes:presence";
+const char* ns_mix_node_config = "urn:xmpp:mix:nodes:config";
+const char* ns_mix_node_info = "urn:xmpp:mix:nodes:info";
+// XEP-0373: OpenPGP for XMPP
+const char* ns_ox = "urn:xmpp:openpgp:0";
+// XEP-0380: Explicit Message Encryption
+const char* ns_eme = "urn:xmpp:eme:0";
+// XEP-0382: Spoiler messages
+const char* ns_spoiler = "urn:xmpp:spoiler:0";
+// XEP-0384: OMEMO Encryption
+const char* ns_omemo = "eu.siacs.conversations.axolotl";
+// XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+const char* ns_mix_pam = "urn:xmpp:mix:pam:1";
+const char* ns_mix_roster = "urn:xmpp:mix:roster:0";
+const char* ns_mix_presence = "urn:xmpp:presence:0";
diff --git a/src/base/QXmppConstants_p.h b/src/base/QXmppConstants_p.h
index 1de6355d..ba39ee05 100644
--- a/src/base/QXmppConstants_p.h
+++ b/src/base/QXmppConstants_p.h
@@ -49,6 +49,8 @@ extern const char* ns_stanza;
extern const char* ns_rpc;
// XEP-0020: Feature Negotiation
extern const char* ns_feature_negotiation;
+// XEP-0027: Current Jabber OpenPGP Usage
+extern const char* ns_legacy_openpgp;
// XEP-0030: Service Discovery
extern const char* ns_disco_info;
extern const char* ns_disco_items;
@@ -75,6 +77,7 @@ extern const char* ns_oob;
extern const char *ns_xhtml_im;
// XEP-0077: In-Band Registration
extern const char* ns_register;
+extern const char* ns_register_feature;
// XEP-0078: Non-SASL Authentication
extern const char* ns_auth;
extern const char* ns_authFeature;
@@ -142,7 +145,36 @@ extern const char* ns_mam;
extern const char* ns_idle;
// XEP-0333: Char Markers
extern const char* ns_chat_markers;
+// XEP-0334: Message Processing Hints:
+extern const char* ns_message_processing_hints;
// XEP-0352: Client State Indication
extern const char* ns_csi;
+// XEP-0363: HTTP File Upload
+extern const char* ns_http_upload;
+// XEP-0364: Current Off-the-Record Messaging Usage
+extern const char* ns_otr;
+// XEP-0367: Message Attaching
+extern const char* ns_message_attaching;
+// XEP-0369: Mediated Information eXchange (MIX)
+extern const char* ns_mix;
+extern const char* ns_mix_create_channel;
+extern const char* ns_mix_searchable;
+extern const char* ns_mix_node_messages;
+extern const char* ns_mix_node_participants;
+extern const char* ns_mix_node_presence;
+extern const char* ns_mix_node_config;
+extern const char* ns_mix_node_info;
+// XEP-0373: OpenPGP for XMPP
+extern const char* ns_ox;
+// XEP-0380: Explicit Message Encryption
+extern const char* ns_eme;
+// XEP-0382: Spoiler messages
+extern const char* ns_spoiler;
+// XEP-0384: OMEMO Encryption
+extern const char* ns_omemo;
+// XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+extern const char* ns_mix_pam;
+extern const char* ns_mix_roster;
+extern const char* ns_mix_presence;
#endif // QXMPPCONSTANTS_H
diff --git a/src/base/QXmppDataForm.cpp b/src/base/QXmppDataForm.cpp
index b500785c..0e909259 100644
--- a/src/base/QXmppDataForm.cpp
+++ b/src/base/QXmppDataForm.cpp
@@ -46,7 +46,7 @@ static field_type field_types[] = {
{QXmppDataForm::Field::TextMultiField, "text-multi"},
{QXmppDataForm::Field::TextPrivateField, "text-private"},
{QXmppDataForm::Field::TextSingleField, "text-single"},
- {static_cast<QXmppDataForm::Field::Type>(-1), NULL},
+ {static_cast<QXmppDataForm::Field::Type>(-1), nullptr},
};
class QXmppDataFormMediaPrivate : public QSharedData
diff --git a/src/base/QXmppDiscoveryIq.cpp b/src/base/QXmppDiscoveryIq.cpp
index 2f8af810..98fa195e 100644
--- a/src/base/QXmppDiscoveryIq.cpp
+++ b/src/base/QXmppDiscoveryIq.cpp
@@ -199,9 +199,9 @@ QByteArray QXmppDiscoveryIq::verificationString() const
{
QString S;
QList<QXmppDiscoveryIq::Identity> sortedIdentities = m_identities;
- qSort(sortedIdentities.begin(), sortedIdentities.end(), identityLessThan);
+ std::sort(sortedIdentities.begin(), sortedIdentities.end(), identityLessThan);
QStringList sortedFeatures = m_features;
- qSort(sortedFeatures);
+ std::sort(sortedFeatures.begin(), sortedFeatures.end());
sortedFeatures.removeDuplicates();
foreach (const QXmppDiscoveryIq::Identity &identity, sortedIdentities)
S += QString("%1/%2/%3/%4<").arg(identity.category(), identity.type(), identity.language(), identity.name());
@@ -219,7 +219,7 @@ QByteArray QXmppDiscoveryIq::verificationString() const
S += field.value().toString() + QLatin1String("<");
QStringList keys = fieldMap.keys();
- qSort(keys);
+ std::sort(keys.begin(), keys.end());
foreach (const QString &key, keys) {
const QXmppDataForm::Field field = fieldMap.value(key);
S += key + QLatin1String("<");
diff --git a/src/base/QXmppDiscoveryIq.h b/src/base/QXmppDiscoveryIq.h
index 8de64dc7..edc2669d 100644
--- a/src/base/QXmppDiscoveryIq.h
+++ b/src/base/QXmppDiscoveryIq.h
@@ -99,8 +99,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppElement.cpp b/src/base/QXmppElement.cpp
index cd977817..7d0e33fa 100644
--- a/src/base/QXmppElement.cpp
+++ b/src/base/QXmppElement.cpp
@@ -46,12 +46,12 @@ public:
};
QXmppElementPrivate::QXmppElementPrivate()
- : counter(1), parent(NULL)
+ : counter(1), parent(nullptr)
{
}
QXmppElementPrivate::QXmppElementPrivate(const QDomElement &element)
- : counter(1), parent(NULL)
+ : counter(1), parent(nullptr)
{
if (element.isNull())
return;
@@ -207,7 +207,7 @@ void QXmppElement::removeChild(const QXmppElement &child)
d->children.removeAll(child.d);
child.d->counter.deref();
- child.d->parent = NULL;
+ child.d->parent = nullptr;
}
QString QXmppElement::tagName() const
diff --git a/src/base/QXmppElement.h b/src/base/QXmppElement.h
index e7cc5596..a3647d0d 100644
--- a/src/base/QXmppElement.h
+++ b/src/base/QXmppElement.h
@@ -34,7 +34,7 @@ class QDomElement;
class QXmppElement;
class QXmppElementPrivate;
-typedef QList<QXmppElement> QXmppElementList;
+using QXmppElementList = QList<QXmppElement>;
class QXMPP_EXPORT QXmppElement
{
public:
diff --git a/src/base/QXmppEntityTimeIq.h b/src/base/QXmppEntityTimeIq.h
index a5b7e2d5..1379ebce 100644
--- a/src/base/QXmppEntityTimeIq.h
+++ b/src/base/QXmppEntityTimeIq.h
@@ -44,8 +44,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppGlobal.h.in b/src/base/QXmppGlobal.h.in
index f562eb04..992e02b1 100644
--- a/src/base/QXmppGlobal.h.in
+++ b/src/base/QXmppGlobal.h.in
@@ -4,6 +4,7 @@
* Author:
* Manjeet Dahiya
* Niels Ole Salscheider
+ * Linus Jahn
*
* Source:
* https://github.com/qxmpp-project/qxmpp
@@ -52,5 +53,14 @@ inline QLatin1String QXmppVersion()
return QLatin1String("@VERSION_STRING@");
}
+// This sets which deprecated functions should still be usable
+// It works exactly like QT_DISABLE_DEPRECATED_BEFORE
+#ifndef QXMPP_DISABLE_DEPRECATED_BEFORE
+# define QXMPP_DISABLE_DEPRECATED_BEFORE 0x@VERSION_MAJOR@ << 16
+#endif
+
+// This works exactly like QT_DEPRECATED_SINCE, but checks QXMPP_DISABLE_DEPRECATED_BEFORE instead.
+#define QXMPP_DEPRECATED_SINCE(major, minor) (QT_VERSION_CHECK(major, minor, 0) > QXMPP_DISABLE_DEPRECATED_BEFORE)
+
#endif //QXMPPGLOBAL_H
diff --git a/src/base/QXmppHttpUploadIq.cpp b/src/base/QXmppHttpUploadIq.cpp
new file mode 100644
index 00000000..4754cd3e
--- /dev/null
+++ b/src/base/QXmppHttpUploadIq.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Authors:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include <QDomElement>
+#include <QMimeDatabase>
+
+#include "QXmppHttpUploadIq.h"
+#include "QXmppConstants_p.h"
+
+class QXmppHttpUploadRequestIqPrivate
+{
+public:
+ QString fileName;
+ qint64 size;
+ QMimeType contentType;
+};
+
+QXmppHttpUploadRequestIq::QXmppHttpUploadRequestIq()
+ : d(new QXmppHttpUploadRequestIqPrivate())
+{
+}
+
+QXmppHttpUploadRequestIq::~QXmppHttpUploadRequestIq()
+{
+ delete d;
+}
+
+/// Returns the file name of the file to be uploaded.
+
+QString QXmppHttpUploadRequestIq::fileName() const
+{
+ return d->fileName;
+}
+
+/// Sets the file name. The upload service will use this to create the upload/
+/// download URLs. This may also differ from the actual file name to get a
+/// different URL. It's not required to replace special characters (this is the
+/// server's job).
+
+void QXmppHttpUploadRequestIq::setFileName(const QString &fileName)
+{
+ d->fileName = fileName;
+}
+
+/// Returns the file's size in bytes.
+
+qint64 QXmppHttpUploadRequestIq::size() const
+{
+ return d->size;
+}
+
+/// Sets the file's size in bytes.
+
+void QXmppHttpUploadRequestIq::setSize(qint64 size)
+{
+ d->size = size;
+}
+
+/// Returns the (optional) MIME-type of the file.
+
+QMimeType QXmppHttpUploadRequestIq::contentType() const
+{
+ return d->contentType;
+}
+
+/// Sets the MIME-type of the file. This is optional.
+
+void QXmppHttpUploadRequestIq::setContentType(const QMimeType &type)
+{
+ d->contentType = type;
+}
+
+bool QXmppHttpUploadRequestIq::isHttpUploadRequestIq(const QDomElement &element)
+{
+ if (element.tagName() == "iq") {
+ QDomElement request = element.firstChildElement("request");
+ return !request.isNull() && request.namespaceURI() == ns_http_upload;
+ }
+ return false;
+}
+
+/// \cond
+void QXmppHttpUploadRequestIq::parseElementFromChild(const QDomElement &element)
+{
+ QDomElement request = element.firstChildElement("request");
+ d->fileName = request.attribute("filename");
+ d->size = request.attribute("size").toLongLong();
+ if (request.hasAttribute("content-type")) {
+ QMimeDatabase mimeDb;
+ QMimeType type = mimeDb.mimeTypeForName(request.attribute("content-type"));
+ if (!type.isDefault() && type.isValid())
+ d->contentType = type;
+ }
+}
+
+void QXmppHttpUploadRequestIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("request");
+ writer->writeAttribute("xmlns", ns_http_upload);
+ // filename and size are required
+ writer->writeAttribute("filename", d->fileName);
+ writer->writeAttribute("size", QString::number(d->size));
+ // content-type is optional
+ if (!d->contentType.isDefault() && d->contentType.isValid())
+ writer->writeAttribute("content-type", d->contentType.name());
+ writer->writeEndElement();
+}
+/// \endcond
+
+class QXmppHttpUploadSlotIqPrivate
+{
+public:
+ QUrl putUrl;
+ QUrl getUrl;
+ QMap<QString, QString> putHeaders;
+};
+
+QXmppHttpUploadSlotIq::QXmppHttpUploadSlotIq()
+ : d(new QXmppHttpUploadSlotIqPrivate())
+{
+}
+
+QXmppHttpUploadSlotIq::~QXmppHttpUploadSlotIq()
+{
+ delete d;
+}
+
+/// Returns the URL for uploading via. HTTP PUT.
+
+QUrl QXmppHttpUploadSlotIq::putUrl() const
+{
+ return d->putUrl;
+}
+
+/// Sets the URL the client should use for uploading.
+
+void QXmppHttpUploadSlotIq::setPutUrl(const QUrl &putUrl)
+{
+ d->putUrl = putUrl;
+}
+
+/// Returns the URL to where the file will be served.
+
+QUrl QXmppHttpUploadSlotIq::getUrl() const
+{
+ return d->getUrl;
+}
+
+/// Sets the download URL.
+
+void QXmppHttpUploadSlotIq::setGetUrl(const QUrl &getUrl)
+{
+ d->getUrl = getUrl;
+}
+
+/// Returns a map of header fields (header name -> value) that need to be
+/// included in the PUT (upload) request. This won't contain any other fields
+/// than: "Authorization", "Cookie" or "Expires".
+
+QMap<QString, QString> QXmppHttpUploadSlotIq::putHeaders() const
+{
+ return d->putHeaders;
+}
+
+/// Sets the header fields the client needs to include in the PUT (upload)
+/// request. All fields other than "Authorization", "Cookie" or "Expires" will
+/// be ignored.
+
+void QXmppHttpUploadSlotIq::setPutHeaders(const QMap<QString, QString> &putHeaders)
+{
+ d->putHeaders.clear();
+ for (QString &name : putHeaders.keys()) {
+ if (name == "Authorization" || name == "Cookie" || name == "Expires")
+ d->putHeaders[name] = putHeaders[name];
+ }
+}
+
+bool QXmppHttpUploadSlotIq::isHttpUploadSlotIq(const QDomElement &element)
+{
+ if (element.tagName() == "iq") {
+ QDomElement slot = element.firstChildElement("slot");
+ return !slot.isNull() && slot.namespaceURI() == ns_http_upload;
+ }
+ return false;
+}
+
+/// \cond
+void QXmppHttpUploadSlotIq::parseElementFromChild(const QDomElement &element)
+{
+ QDomElement slot = element.firstChildElement("slot");
+ QDomElement put = slot.firstChildElement("put");
+ d->getUrl = QUrl::fromEncoded(slot.firstChildElement("get").attribute("url").toUtf8());
+ d->putUrl = QUrl::fromEncoded(put.attribute("url").toUtf8());
+ if (put.hasChildNodes()) {
+ QMap<QString, QString> headers;
+ QDomElement header = put.firstChildElement("header");
+ while (!header.isNull()) {
+ headers[header.attribute("name")] = header.text();
+
+ header = header.nextSiblingElement("header");
+ }
+
+ setPutHeaders(headers);
+ }
+}
+
+void QXmppHttpUploadSlotIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("slot");
+ writer->writeAttribute("xmlns", ns_http_upload);
+
+ writer->writeStartElement("put");
+ writer->writeAttribute("url", d->putUrl.toEncoded());
+ if (!d->putHeaders.isEmpty()) {
+ for (const QString &name : d->putHeaders.keys()) {
+ writer->writeStartElement("header");
+ writer->writeAttribute("name", name);
+ writer->writeCharacters(d->putHeaders[name]);
+ writer->writeEndElement();
+ }
+ }
+ writer->writeEndElement();
+
+ writer->writeStartElement("get");
+ writer->writeAttribute("url", d->getUrl.toEncoded());
+ writer->writeEndElement();
+
+ writer->writeEndElement();
+}
+/// \endcond
diff --git a/src/base/QXmppHttpUploadIq.h b/src/base/QXmppHttpUploadIq.h
new file mode 100644
index 00000000..63c2da23
--- /dev/null
+++ b/src/base/QXmppHttpUploadIq.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Authors:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef QXMPPHTTPUPLOADIQ_H
+#define QXMPPHTTPUPLOADIQ_H
+
+#include <QMap>
+#include <QMimeType>
+#include <QUrl>
+
+#include "QXmppIq.h"
+
+class QXmppHttpUploadRequestIqPrivate;
+class QXmppHttpUploadSlotIqPrivate;
+
+/// \brief Represents an HTTP File Upload IQ for requesting an upload slot as
+/// defined by XEP-0363: HTTP File Upload [v0.9.0].
+///
+/// \ingroup Stanzas
+
+class QXMPP_EXPORT QXmppHttpUploadRequestIq : public QXmppIq
+{
+public:
+ QXmppHttpUploadRequestIq();
+ ~QXmppHttpUploadRequestIq() override;
+
+ QString fileName() const;
+ void setFileName(const QString &filename);
+
+ qint64 size() const;
+ void setSize(qint64 size);
+
+ QMimeType contentType() const;
+ void setContentType(const QMimeType &type);
+
+ static bool isHttpUploadRequestIq(const QDomElement &element);
+
+protected:
+ /// \cond
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
+ /// \endcond
+
+private:
+ QXmppHttpUploadRequestIqPrivate* const d;
+};
+
+/// \brief Represents an HTTP File Upload IQ result for receiving an upload slot as
+/// defined by XEP-0363: HTTP File Upload [v0.9.0].
+///
+/// \ingroup Stanzas
+
+class QXMPP_EXPORT QXmppHttpUploadSlotIq : public QXmppIq
+{
+public:
+ QXmppHttpUploadSlotIq();
+ ~QXmppHttpUploadSlotIq() override;
+
+ QUrl putUrl() const;
+ void setPutUrl(const QUrl &putUrl);
+
+ QUrl getUrl() const;
+ void setGetUrl(const QUrl &getUrl);
+
+ QMap<QString, QString> putHeaders() const;
+ void setPutHeaders(const QMap<QString, QString> &putHeaders);
+
+ static bool isHttpUploadSlotIq(const QDomElement &element);
+
+protected:
+ /// \cond
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
+ /// \endcond
+
+private:
+ QXmppHttpUploadSlotIqPrivate* const d;
+};
+
+#endif // QXMPPHTTPUPLOADIQ_H
diff --git a/src/base/QXmppIbbIq.h b/src/base/QXmppIbbIq.h
index 732936c7..92828095 100644
--- a/src/base/QXmppIbbIq.h
+++ b/src/base/QXmppIbbIq.h
@@ -42,8 +42,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -63,8 +63,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -89,8 +89,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppIq.h b/src/base/QXmppIq.h
index c147bb78..e7451e7c 100644
--- a/src/base/QXmppIq.h
+++ b/src/base/QXmppIq.h
@@ -53,18 +53,18 @@ public:
QXmppIq(QXmppIq::Type type = QXmppIq::Get);
QXmppIq(const QXmppIq &other);
- ~QXmppIq();
+ ~QXmppIq() override;
QXmppIq& operator=(const QXmppIq &other);
QXmppIq::Type type() const;
void setType(QXmppIq::Type);
- bool isXmppStanza() const;
+ bool isXmppStanza() const override;
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
protected:
virtual void parseElementFromChild(const QDomElement &element);
diff --git a/src/base/QXmppJingleIq.cpp b/src/base/QXmppJingleIq.cpp
index c652887e..4fcd5bec 100644
--- a/src/base/QXmppJingleIq.cpp
+++ b/src/base/QXmppJingleIq.cpp
@@ -576,7 +576,7 @@ QString QXmppJingleIq::Content::toSdp() const
QHostAddress localRtpAddress = QHostAddress::Any;
quint16 localRtpPort = 0;
QList<QXmppJingleCandidate> sortedCandidates = d->transportCandidates;
- qSort(sortedCandidates.begin(), sortedCandidates.end(), candidateLessThan);
+ std::sort(sortedCandidates.begin(), sortedCandidates.end(), candidateLessThan);
foreach (const QXmppJingleCandidate &candidate, sortedCandidates) {
if (candidate.component() == RTP_COMPONENT) {
localRtpAddress = candidate.host();
diff --git a/src/base/QXmppJingleIq.h b/src/base/QXmppJingleIq.h
index ea5d84ef..75a37e04 100644
--- a/src/base/QXmppJingleIq.h
+++ b/src/base/QXmppJingleIq.h
@@ -138,7 +138,7 @@ public:
void parse(const QDomElement &element);
void toXml(QXmlStreamWriter *writer) const;
- static QXmppJingleCandidate::Type typeFromString(const QString &typeStr, bool *ok = 0);
+ static QXmppJingleCandidate::Type typeFromString(const QString &typeStr, bool *ok = nullptr);
static QString typeToString(QXmppJingleCandidate::Type type);
/// \endcond
@@ -289,7 +289,7 @@ public:
QXmppJingleIq();
QXmppJingleIq(const QXmppJingleIq &other);
- ~QXmppJingleIq();
+ ~QXmppJingleIq() override;
QXmppJingleIq& operator=(const QXmppJingleIq &other);
@@ -322,8 +322,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppLogger.cpp b/src/base/QXmppLogger.cpp
index 4b602b38..f429b969 100644
--- a/src/base/QXmppLogger.cpp
+++ b/src/base/QXmppLogger.cpp
@@ -32,7 +32,7 @@
#include "QXmppLogger.h"
-QXmppLogger* QXmppLogger::m_logger = 0;
+QXmppLogger* QXmppLogger::m_logger = nullptr;
static const char *typeName(QXmppLogger::MessageType type)
{
@@ -116,7 +116,7 @@ public:
QXmppLoggerPrivate::QXmppLoggerPrivate()
: loggingType(QXmppLogger::NoLogging)
- , logFile(0)
+ , logFile(nullptr)
, logFilePath("QXmppClientLog.log")
, messageTypes(QXmppLogger::AnyMessage)
{
@@ -268,7 +268,7 @@ void QXmppLogger::reopen()
{
if (d->logFile) {
delete d->logFile;
- d->logFile = 0;
+ d->logFile = nullptr;
}
}
diff --git a/src/base/QXmppLogger.h b/src/base/QXmppLogger.h
index a75623b1..912dbd4c 100644
--- a/src/base/QXmppLogger.h
+++ b/src/base/QXmppLogger.h
@@ -74,8 +74,8 @@ public:
};
Q_DECLARE_FLAGS(MessageTypes, MessageType)
- QXmppLogger(QObject *parent = 0);
- ~QXmppLogger();
+ QXmppLogger(QObject *parent = nullptr);
+ ~QXmppLogger() override;
static QXmppLogger* getLogger();
@@ -113,11 +113,11 @@ class QXMPP_EXPORT QXmppLoggable : public QObject
Q_OBJECT
public:
- QXmppLoggable(QObject *parent = 0);
+ QXmppLoggable(QObject *parent = nullptr);
protected:
/// \cond
- virtual void childEvent(QChildEvent *event);
+ void childEvent(QChildEvent *event) override;
/// \endcond
/// Logs a debugging message.
diff --git a/src/base/QXmppMamIq.h b/src/base/QXmppMamIq.h
index 78a6f943..65f0b3f5 100644
--- a/src/base/QXmppMamIq.h
+++ b/src/base/QXmppMamIq.h
@@ -47,8 +47,8 @@ public:
static bool isMamQueryIq(const QDomElement &element);
protected:
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
private:
QXmppDataForm m_form;
@@ -72,8 +72,8 @@ public:
static bool isMamResultIq(const QDomElement &element);
protected:
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
private:
QXmppResultSetReply m_resultSetReply;
diff --git a/src/base/QXmppMessage.cpp b/src/base/QXmppMessage.cpp
index f5869bf4..9806edf0 100644
--- a/src/base/QXmppMessage.cpp
+++ b/src/base/QXmppMessage.cpp
@@ -55,6 +55,31 @@ static const char* marker_types[] = {
"acknowledged"
};
+static const QStringList ENCRYPTION_NAMESPACES = {
+ QString(),
+ QString(),
+ ns_otr,
+ ns_legacy_openpgp,
+ ns_ox,
+ ns_omemo
+};
+
+static const QStringList HINT_TYPES = {
+ QStringLiteral("no-permanent-store"),
+ QStringLiteral("no-store"),
+ QStringLiteral("no-copy"),
+ QStringLiteral("store")
+};
+
+static const QStringList ENCRYPTION_NAMES = {
+ QString(),
+ QString(),
+ QStringLiteral("OTR"),
+ QStringLiteral("Legacy OpenPGP"),
+ QStringLiteral("OpenPGP for XMPP (OX)"),
+ QStringLiteral("OMEMO")
+};
+
static const char *ns_xhtml = "http://www.w3.org/1999/xhtml";
enum StampType
@@ -102,6 +127,24 @@ public:
// XEP-0308: Last Message Correction
QString replaceId;
+
+ // XEP-0334: Message Processing Hints
+ quint8 hints;
+
+ // XEP-0367: Message Attaching
+ QString attachId;
+
+ // XEP-0369: Mediated Information eXchange (MIX)
+ QString mixUserJid;
+ QString mixUserNick;
+
+ // XEP-0380: Explicit Message Encryption
+ QString encryptionMethod;
+ QString encryptionName;
+
+ // XEP-0382: Spoiler messages
+ bool isSpoiler = false;
+ QString spoilerHint;
};
/// Constructs a QXmppMessage.
@@ -112,7 +155,7 @@ public:
/// \param thread
QXmppMessage::QXmppMessage(const QString& from, const QString& to, const
- QString& body, const QString& thread)
+ QString& body, const QString& thread)
: QXmppStanza(from, to)
, d(new QXmppMessagePrivate)
{
@@ -128,6 +171,8 @@ QXmppMessage::QXmppMessage(const QString& from, const QString& to, const
d->marker = NoMarker;
d->privatemsg = false;
+
+ d->hints = 0;
}
/// Constructs a copy of \a other.
@@ -513,6 +558,199 @@ void QXmppMessage::setReplaceId(const QString &replaceId)
d->replaceId = replaceId;
}
+/// Returns true if the message contains the hint passed, as defined in
+/// XEP-0334: Message Processing Hints
+
+bool QXmppMessage::hasHint(const Hint hint) const
+{
+ return d->hints & hint;
+}
+
+/// Adds a hint to the message, as defined in XEP-0334: Message Processing
+/// Hints
+
+void QXmppMessage::addHint(const Hint hint)
+{
+ d->hints |= hint;
+}
+
+/// Removes a hint from the message, as defined in XEP-0334: Message Processing
+/// Hints
+
+void QXmppMessage::removeHint(const Hint hint)
+{
+ d->hints &= ~hint;
+}
+
+/// Removes all hints from the message, as defined in XEP-0334: Message
+/// Processing Hints
+
+void QXmppMessage::removeAllHints()
+{
+ d->hints = 0;
+}
+
+/// Returns the message id this message is linked/attached to. See XEP-0367:
+/// Message Attaching for details.
+
+QString QXmppMessage::attachId() const
+{
+ return d->attachId;
+}
+
+/// Sets the id of the attached message as in XEP-0367: Message Attaching. This
+/// can be used for a "reply to" or "reaction" function.
+///
+/// The used message id depends on the message context, see the Business rules
+/// section of the XEP for details about when to use which id.
+
+void QXmppMessage::setAttachId(const QString &attachId)
+{
+ d->attachId = attachId;
+}
+
+/// Returns the actual JID of a MIX channel participant.
+
+QString QXmppMessage::mixUserJid() const
+{
+ return d->mixUserJid;
+}
+
+/// Sets the actual JID of a MIX channel participant.
+
+void QXmppMessage::setMixUserJid(const QString& mixUserJid)
+{
+ d->mixUserJid = mixUserJid;
+}
+
+/// Returns the MIX participant's nickname.
+
+QString QXmppMessage::mixUserNick() const
+{
+ return d->mixUserNick;
+}
+
+/// Sets the MIX participant's nickname.
+
+void QXmppMessage::setMixUserNick(const QString& mixUserNick)
+{
+ d->mixUserNick = mixUserNick;
+}
+
+/// Returns the encryption method this message is advertised to be encrypted
+/// with.
+///
+/// \note QXmppMessage::NoEncryption does not necesserily mean that the message
+/// is not encrypted; it may also be that the author of the message does not
+/// support XEP-0380: Explicit Message Encryption.
+///
+/// \note If this returns QXmppMessage::UnknownEncryption, you can still get
+/// the namespace of the encryption with \c encryptionMethodNs() and possibly
+/// also a name with \c encryptionName().
+
+QXmppMessage::EncryptionMethod QXmppMessage::encryptionMethod() const
+{
+ if (d->encryptionMethod.isEmpty())
+ return QXmppMessage::NoEncryption;
+
+ int index = ENCRYPTION_NAMESPACES.indexOf(d->encryptionMethod);
+ if (index < 0)
+ return QXmppMessage::UnknownEncryption;
+ return static_cast<QXmppMessage::EncryptionMethod>(index);
+}
+
+/// Advertises that this message is encrypted with the given encryption method.
+/// See XEP-0380: Explicit Message Encryption for details.
+
+void QXmppMessage::setEncryptionMethod(QXmppMessage::EncryptionMethod method)
+{
+ d->encryptionMethod = ENCRYPTION_NAMESPACES.at(int(method));
+}
+
+/// Returns the namespace of the advertised encryption method via. XEP-0380:
+/// Explicit Message Encryption.
+
+QString QXmppMessage::encryptionMethodNs() const
+{
+ return d->encryptionMethod;
+}
+
+/// Sets the namespace of the encryption method this message advertises to be
+/// encrypted with. See XEP-0380: Explicit Message Encryption for details.
+
+void QXmppMessage::setEncryptionMethodNs(const QString &encryptionMethod)
+{
+ d->encryptionMethod = encryptionMethod;
+}
+
+/// Returns the associated name of the encryption method this message
+/// advertises to be encrypted with. See XEP-0380: Explicit Message Encryption
+/// for details.
+
+QString QXmppMessage::encryptionName() const
+{
+ if (!d->encryptionName.isEmpty())
+ return d->encryptionName;
+ return ENCRYPTION_NAMES.at(int(encryptionMethod()));
+}
+
+/// Sets the name of the encryption method for XEP-0380: Explicit Message
+/// Encryption.
+///
+/// \note This should only be used, if the encryption method is custom and is
+/// not one of the methods listed in the XEP.
+
+void QXmppMessage::setEncryptionName(const QString &encryptionName)
+{
+ d->encryptionName = encryptionName;
+}
+
+/// Returns true, if this is a spoiler message according to XEP-0382: Spoiler
+/// messages. The spoiler hint however can still be empty.
+///
+/// A spoiler message's content should not be visible to the user by default.
+
+bool QXmppMessage::isSpoiler() const
+{
+ return d->isSpoiler;
+}
+
+/// Sets whether this is a spoiler message as specified in XEP-0382: Spoiler
+/// messages.
+///
+/// The content of spoiler messages will not be displayed by default to the
+/// user. However, clients not supporting spoiler messages will still display
+/// the content as usual.
+
+void QXmppMessage::setIsSpoiler(bool isSpoiler)
+{
+ d->isSpoiler = isSpoiler;
+}
+
+/// Returns the spoiler hint as specified in XEP-0382: Spoiler messages.
+///
+/// The hint may be empty, even if isSpoiler is true.
+
+QString QXmppMessage::spoilerHint() const
+{
+ return d->spoilerHint;
+}
+
+/// Sets a spoiler hint for XEP-0382: Spoiler messages. If the spoiler hint
+/// is not empty, isSpoiler will be set to true.
+///
+/// A spoiler hint is optional for spoiler messages.
+///
+/// Keep in mind that the spoiler hint is not displayed at all by clients not
+/// supporting spoiler messages.
+
+void QXmppMessage::setSpoilerHint(const QString &spoilerHint)
+{
+ d->spoilerHint = spoilerHint;
+ if (!spoilerHint.isEmpty())
+ d->isSpoiler = true;
+}
+
/// \cond
void QXmppMessage::parse(const QDomElement &element)
{
@@ -654,6 +892,24 @@ void QXmppMessage::parse(const QDomElement &element)
else {
extensions << QXmppElement(xElement);
}
+ // XEP-0334: Message Processing Hints
+ } else if (xElement.namespaceURI() == ns_message_processing_hints && HINT_TYPES.contains(xElement.tagName())) {
+ addHint(Hint(1 << HINT_TYPES.indexOf(xElement.tagName())));
+ // XEP-0367: Message Attaching
+ } else if (xElement.tagName() == "attach-to" && xElement.namespaceURI() == ns_message_attaching) {
+ d->attachId = xElement.attribute("id");
+ // XEP-0369: Mediated Information eXchange (MIX)
+ } else if (xElement.tagName() == "mix" && xElement.namespaceURI() == ns_mix) {
+ d->mixUserJid = xElement.firstChildElement("jid").text();
+ d->mixUserNick = xElement.firstChildElement("nick").text();
+ // XEP-0380: Explicit Message Encryption
+ } else if (xElement.tagName() == "encryption" && xElement.namespaceURI() == ns_eme) {
+ d->encryptionMethod = xElement.attribute("namespace");
+ d->encryptionName = xElement.attribute("name");
+ // XEP-0382: Spoiler messages
+ } else if (xElement.tagName() == "spoiler" && xElement.namespaceURI() == ns_spoiler) {
+ d->isSpoiler = true;
+ d->spoilerHint = xElement.text();
} else if (!knownElems.contains(qMakePair(xElement.tagName(), xElement.namespaceURI())) &&
!knownElems.contains(qMakePair(xElement.tagName(), QString()))) {
// other extensions
@@ -791,6 +1047,49 @@ void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const
xmlWriter->writeEndElement();
}
+ // XEP-0334: Message Processing Hints
+ for (quint8 i = 0; i < HINT_TYPES.size(); i++) {
+ if (hasHint(Hint(1 << i))) {
+ xmlWriter->writeStartElement(HINT_TYPES.at(i));
+ xmlWriter->writeAttribute("xmlns", ns_message_processing_hints);
+ xmlWriter->writeEndElement();
+ }
+ }
+
+ // XEP-0367: Message Attaching
+ if (!d->attachId.isEmpty()) {
+ xmlWriter->writeStartElement("attach-to");
+ xmlWriter->writeAttribute("xmlns", ns_message_attaching);
+ xmlWriter->writeAttribute("id", d->attachId);
+ xmlWriter->writeEndElement();
+ }
+
+ // XEP-0369: Mediated Information eXchange (MIX)
+ if (!d->mixUserJid.isEmpty() || !d->mixUserNick.isEmpty()) {
+ xmlWriter->writeStartElement("mix");
+ xmlWriter->writeAttribute("xmlns", ns_mix);
+ helperToXmlAddTextElement(xmlWriter, "jid", d->mixUserJid);
+ helperToXmlAddTextElement(xmlWriter, "nick", d->mixUserNick);
+ xmlWriter->writeEndElement();
+ }
+
+ // XEP-0380: Explicit Message Encryption
+ if (!d->encryptionMethod.isEmpty()) {
+ xmlWriter->writeStartElement("encryption");
+ xmlWriter->writeAttribute("xmlns", ns_eme);
+ xmlWriter->writeAttribute("namespace", d->encryptionMethod);
+ helperToXmlAddAttribute(xmlWriter, "name", d->encryptionName);
+ xmlWriter->writeEndElement();
+ }
+
+ // XEP-0382: Spoiler messages
+ if (d->isSpoiler) {
+ xmlWriter->writeStartElement("spoiler");
+ xmlWriter->writeAttribute("xmlns", ns_spoiler);
+ xmlWriter->writeCharacters(d->spoilerHint);
+ xmlWriter->writeEndElement();
+ }
+
// other extensions
QXmppStanza::extensionsToXml(xmlWriter);
diff --git a/src/base/QXmppMessage.h b/src/base/QXmppMessage.h
index e0c3d831..2743ca13 100644
--- a/src/base/QXmppMessage.h
+++ b/src/base/QXmppMessage.h
@@ -21,7 +21,6 @@
*
*/
-
#ifndef QXMPPMESSAGE_H
#define QXMPPMESSAGE_H
@@ -33,7 +32,6 @@ class QXmppMessagePrivate;
/// \brief The QXmppMessage class represents an XMPP message.
///
/// \ingroup Stanzas
-///
class QXMPP_EXPORT QXmppMessage : public QXmppStanza
{
@@ -48,8 +46,8 @@ public:
Headline
};
- /// This enum describes a chat state as defined by
- /// XEP-0085 : Chat State Notifications.
+ /// This enum describes a chat state as defined by XEP-0085: Chat State
+ /// Notifications.
enum State
{
None = 0, ///< The message does not contain any chat state information.
@@ -60,8 +58,7 @@ public:
Paused ///< User had been composing but now has stopped.
};
- /// This enum describes a chat marker as defined by
- /// XEP-0333 : Char Markers
+ /// This enum describes a chat marker as defined by XEP-0333: Chat Markers.
enum Marker {
NoMarker = 0,
Received,
@@ -69,11 +66,31 @@ public:
Acknowledged
};
+ /// XEP-0334: Message Processing Hints
+ enum Hint {
+ NoPermanentStore = 1 << 0, ///< Do not allow permanent storage
+ NoStore = 1 << 1, ///< Do not store at all
+ NoCopy = 1 << 2, ///< Do not copy the message
+ Store = 1 << 3 ///< Do store the message
+ };
+
+ /// This enum describes different end-to-end encryption methods. These can
+ /// be used to mark a message explicitly as encrypted with a specific
+ /// algothim. See XEP-0380: Explicit Message Encryption for details.
+ enum EncryptionMethod {
+ NoEncryption, ///< No encryption
+ UnknownEncryption, ///< Unknown encryption
+ OTR, ///< XEP-0364: Current Off-the-Record Messaging Usage
+ LegacyOpenPGP, ///< XEP-0027: Current Jabber OpenPGP Usage
+ OX, ///< XEP-0373: OpenPGP for XMPP
+ OMEMO ///< XEP-0384: OMEMO Encryption
+ };
+
QXmppMessage(const QString& from = QString(), const QString& to = QString(),
const QString& body = QString(), const QString& thread = QString());
QXmppMessage(const QXmppMessage &other);
- ~QXmppMessage();
+ ~QXmppMessage() override;
QXmppMessage& operator=(const QXmppMessage &other);
@@ -116,7 +133,7 @@ public:
QString xhtml() const;
void setXhtml(const QString &xhtml);
- // XEP-0333
+ // XEP-0333: Chat Markers
bool isMarkable() const;
void setMarkable(const bool);
@@ -133,7 +150,7 @@ public:
bool isPrivate() const;
void setPrivate(const bool);
- bool isXmppStanza() const;
+ bool isXmppStanza() const override;
// XEP-0066: Out of Band Data
QString outOfBandUrl() const;
@@ -143,9 +160,42 @@ public:
QString replaceId() const;
void setReplaceId(const QString&);
+ // XEP-0334: Message Processing Hints
+ bool hasHint(const Hint hint) const;
+ void addHint(const Hint hint);
+ void removeHint(const Hint hint);
+ void removeAllHints();
+
+ // XEP-0367: Message Attaching
+ QString attachId() const;
+ void setAttachId(const QString&);
+
+ // XEP-0369: Mediated Information eXchange (MIX)
+ QString mixUserJid() const;
+ void setMixUserJid(const QString&);
+
+ QString mixUserNick() const;
+ void setMixUserNick(const QString&);
+
+ // XEP-0380: Explicit Message Encryption
+ EncryptionMethod encryptionMethod() const;
+ void setEncryptionMethod(EncryptionMethod);
+ QString encryptionMethodNs() const;
+ void setEncryptionMethodNs(const QString&);
+
+ QString encryptionName() const;
+ void setEncryptionName(const QString&);
+
+ // XEP-0382: Spoiler messages
+ bool isSpoiler() const;
+ void setIsSpoiler(bool);
+
+ QString spoilerHint() const;
+ void setSpoilerHint(const QString&);
+
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppMixIq.cpp b/src/base/QXmppMixIq.cpp
new file mode 100644
index 00000000..7cc316e2
--- /dev/null
+++ b/src/base/QXmppMixIq.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include "QXmppMixIq.h"
+#include "QXmppDataForm.h"
+#include "QXmppConstants_p.h"
+#include "QXmppUtils.h"
+#include <QDomElement>
+
+static const QStringList MIX_ACTION_TYPES = QStringList() << ""
+ << "client-join" << "client-leave" << "join" << "leave"
+ << "update-subscription" << "setnick" << "create" << "destroy";
+
+class QXmppMixIqPrivate : QSharedData
+{
+public:
+ QString jid;
+ QString channelName;
+ QStringList nodes;
+ QString nick;
+ QXmppMixIq::Type actionType = QXmppMixIq::None;
+};
+
+QXmppMixIq::QXmppMixIq()
+ : d(new QXmppMixIqPrivate)
+{
+}
+
+QXmppMixIq::~QXmppMixIq()
+{
+}
+
+/// Returns the channel JID. It also contains a participant id for Join/
+/// ClientJoin results.
+
+QString QXmppMixIq::jid() const
+{
+ return d->jid;
+}
+
+/// Sets the channel JID. For results of Join/ClientJoin queries this also
+/// needs to contain a participant id.
+
+void QXmppMixIq::setJid(const QString& jid)
+{
+ d->jid = jid;
+}
+
+/// Returns the channel name (the name part of the channel JID). This may still
+/// be empty, if a JID was set.
+
+QString QXmppMixIq::channelName() const
+{
+ return d->channelName;
+}
+
+/// Sets the channel name for creating/destroying specific channels. When you
+/// create a new channel, this can also be left empty to let the server
+/// generate a name.
+
+void QXmppMixIq::setChannelName(const QString& channelName)
+{
+ d->channelName = channelName;
+}
+
+/// Returns the list of nodes to subscribe to.
+
+QStringList QXmppMixIq::nodes() const
+{
+ return d->nodes;
+}
+
+/// Sets the nodes to subscribe to. Note that for UpdateSubscription queries
+/// you only need to include the new subscriptions.
+
+void QXmppMixIq::setNodes(const QStringList& nodes)
+{
+ d->nodes = nodes;
+}
+
+/// Returns the user's nickname in the channel.
+
+QString QXmppMixIq::nick() const
+{
+ return d->nick;
+}
+
+/// Sets the nickname for the channel.
+
+void QXmppMixIq::setNick(const QString& nick)
+{
+ d->nick = nick;
+}
+
+/// Returns the MIX channel action type.
+
+QXmppMixIq::Type QXmppMixIq::actionType() const
+{
+ return d->actionType;
+}
+
+/// Sets the channel action.
+
+void QXmppMixIq::setActionType(QXmppMixIq::Type type)
+{
+ d->actionType = type;
+}
+
+/// \cond
+bool QXmppMixIq::isMixIq(const QDomElement& element)
+{
+ const QDomElement& child = element.firstChildElement();
+ return !child.isNull() && (child.namespaceURI() == ns_mix
+ || child.namespaceURI() == ns_mix_pam);
+}
+
+void QXmppMixIq::parseElementFromChild(const QDomElement& element)
+{
+ QDomElement child = element.firstChildElement();
+ // determine action type
+ d->actionType = (QXmppMixIq::Type) MIX_ACTION_TYPES.indexOf(child.tagName());
+
+ if (child.namespaceURI() == ns_mix_pam) {
+ if (child.hasAttribute("channel"))
+ d->jid = child.attribute("channel");
+
+ child = child.firstChildElement();
+ }
+
+ if (!child.isNull() && child.namespaceURI() == ns_mix) {
+ if (child.hasAttribute("jid"))
+ d->jid = child.attribute("jid");
+ if (child.hasAttribute("channel"))
+ d->channelName = child.attribute("channel");
+
+ QDomElement subChild = child.firstChildElement();
+ while (!subChild.isNull()) {
+ if (subChild.tagName() == "subscribe")
+ d->nodes << subChild.attribute("node");
+ else if (subChild.tagName() == "nick")
+ d->nick = subChild.text();
+
+ subChild = subChild.nextSiblingElement();
+ }
+ }
+}
+
+void QXmppMixIq::toXmlElementFromChild(QXmlStreamWriter* writer) const
+{
+ if (d->actionType == None)
+ return;
+
+ writer->writeStartElement(MIX_ACTION_TYPES.at(d->actionType));
+ if (d->actionType == ClientJoin || d->actionType == ClientLeave) {
+ writer->writeAttribute("xmlns", ns_mix_pam);
+ if (type() == Set)
+ helperToXmlAddAttribute(writer, "channel", d->jid);
+
+ if (d->actionType == ClientJoin)
+ writer->writeStartElement("join");
+ else if (d->actionType == ClientLeave)
+ writer->writeStartElement("leave");
+ }
+
+ writer->writeAttribute("xmlns", ns_mix);
+ helperToXmlAddAttribute(writer, "channel", d->channelName);
+ if (type() == Result)
+ helperToXmlAddAttribute(writer, "jid", d->jid);
+
+ for (const auto &node : d->nodes) {
+ writer->writeStartElement("subscribe");
+ writer->writeAttribute("node", node);
+ writer->writeEndElement();
+ }
+ if (!d->nick.isEmpty())
+ writer->writeTextElement("nick", d->nick);
+
+ writer->writeEndElement();
+ if (d->actionType == ClientJoin || d->actionType == ClientLeave)
+ writer->writeEndElement();
+}
+/// \endcond
diff --git a/src/base/QXmppMixIq.h b/src/base/QXmppMixIq.h
new file mode 100644
index 00000000..4e3b71f8
--- /dev/null
+++ b/src/base/QXmppMixIq.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef QXMPPMIXIQ_H
+#define QXMPPMIXIQ_H
+
+#include "QXmppIq.h"
+
+class QXmppMixIqPrivate;
+
+/// \brief The QXmppMixIq class represents an IQ used to do actions on a MIX
+/// channel as defined by XEP-0369: Mediated Information eXchange (MIX) and
+/// XEP-0405: Mediated Information eXchange (MIX): Participant Server
+/// Requirements.
+///
+/// \ingroup Stanzas
+
+class QXMPP_EXPORT QXmppMixIq : public QXmppIq
+{
+public:
+ enum Type {
+ None,
+ ClientJoin,
+ ClientLeave,
+ Join,
+ Leave,
+ UpdateSubscription,
+ SetNick,
+ Create,
+ Destroy
+ };
+
+ QXmppMixIq();
+ ~QXmppMixIq() override;
+
+ QXmppMixIq::Type actionType() const;
+ void setActionType(QXmppMixIq::Type);
+
+ QString jid() const;
+ void setJid(const QString&);
+
+ QString channelName() const;
+ void setChannelName(const QString&);
+
+ QStringList nodes() const;
+ void setNodes(const QStringList&);
+
+ QString nick() const;
+ void setNick(const QString&);
+
+ /// \cond
+ static bool isMixIq(const QDomElement&);
+ /// \endcond
+
+protected:
+ /// \cond
+ void parseElementFromChild(const QDomElement&) override;
+ void toXmlElementFromChild(QXmlStreamWriter*) const override;
+ /// \endcond
+
+private:
+ QXmppMixIqPrivate *d;
+};
+
+#endif // QXMPPMIXIQ_H
diff --git a/src/base/QXmppMixItem.cpp b/src/base/QXmppMixItem.cpp
new file mode 100644
index 00000000..5b1d7c00
--- /dev/null
+++ b/src/base/QXmppMixItem.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include "QXmppMixItem.h"
+#include "QXmppDataForm.h"
+#include "QXmppConstants_p.h"
+#include "QXmppUtils.h"
+#include <QDomElement>
+#include <QBuffer>
+
+class QXmppMixInfoItemPrivate : QSharedData
+{
+public:
+ QString name;
+ QString description;
+ QStringList contactJids;
+};
+
+QXmppMixInfoItem::QXmppMixInfoItem()
+ : d(new QXmppMixInfoItemPrivate)
+{
+}
+
+/// Returns the user-specified name of the MIX channel. This is not the name
+/// part of the channel's JID.
+
+QString QXmppMixInfoItem::name() const
+{
+ return d->name;
+}
+
+/// Sets the name of the channel.
+
+void QXmppMixInfoItem::setName(const QString& name)
+{
+ d->name = name;
+}
+
+/// Returns the description of the channel. This string might be very long.
+
+QString QXmppMixInfoItem::description() const
+{
+ return d->description;
+}
+
+/// Sets the longer channel description.
+
+void QXmppMixInfoItem::setDescription(const QString& description)
+{
+ d->description = description;
+}
+
+/// Returns a list of JIDs that are responsible for this channel.
+
+QStringList QXmppMixInfoItem::contactJids() const
+{
+ return d->contactJids;
+}
+
+/// Sets a list of public JIDs that are responsible for this channel.
+
+void QXmppMixInfoItem::setContactJids(const QStringList& contactJids)
+{
+ d->contactJids = contactJids;
+}
+
+/// Returns true, if the given dom element is a MIX channel info item.
+
+bool QXmppMixInfoItem::isMixChannelInfo(const QDomElement& element)
+{
+ QXmppDataForm form;
+ form.parse(element);
+ for (const auto &field : form.fields()) {
+ if (field.key() == "FORM_TYPE")
+ return field.value() == ns_mix;
+ }
+ return false;
+}
+
+void QXmppMixInfoItem::parse(const QXmppElement& element)
+{
+ QXmppDataForm form;
+ form.parse(element.sourceDomElement());
+
+ for (auto& field : form.fields()) {
+ if (field.key() == "Name")
+ d->name = field.value().toString();
+ else if (field.key() == "Description")
+ d->description = field.value().toString();
+ else if (field.key() == "Contact")
+ d->contactJids = field.value().toStringList();
+ }
+}
+
+QXmppElement QXmppMixInfoItem::toElement() const
+{
+ QXmppDataForm form;
+ form.setType(QXmppDataForm::Result);
+ QList<QXmppDataForm::Field> fields;
+
+ QXmppDataForm::Field formType;
+ formType.setType(QXmppDataForm::Field::HiddenField);
+ formType.setKey("FORM_TYPE");
+ formType.setValue(ns_mix);
+ fields << formType;
+
+ QXmppDataForm::Field nameField;
+ nameField.setKey("Name");
+ nameField.setValue(d->name);
+ fields << nameField;
+
+ QXmppDataForm::Field descriptionField;
+ descriptionField.setKey("Description");
+ descriptionField.setValue(d->description);
+ fields << descriptionField;
+
+ QXmppDataForm::Field contactsField;
+ contactsField.setKey("Contact");
+ contactsField.setValue(d->contactJids);
+ contactsField.setType(QXmppDataForm::Field::JidMultiField);
+ fields << contactsField;
+
+ form.setFields(fields);
+
+ // FIXME: this is too complicated; maybe don't use QXmppElement in QXmppPubSubItem?
+ QBuffer buffer;
+ buffer.open(QIODevice::ReadWrite);
+ QXmlStreamWriter writer(&buffer);
+ form.toXml(&writer);
+
+ QDomDocument doc;
+ doc.setContent(buffer.data());
+ return QXmppElement(doc.documentElement());
+}
+
+class QXmppMixParticipantItemPrivate : QSharedData
+{
+public:
+ QString nick;
+ QString jid;
+};
+
+QXmppMixParticipantItem::QXmppMixParticipantItem()
+ : d(new QXmppMixParticipantItemPrivate)
+{
+}
+
+/// Returns the participant's nickname.
+
+QString QXmppMixParticipantItem::nick() const
+{
+ return d->nick;
+}
+
+/// Sets the participants nickname.
+
+void QXmppMixParticipantItem::setNick(const QString& nick)
+{
+ d->nick = nick;
+}
+
+/// Returns the participant's JID.
+
+QString QXmppMixParticipantItem::jid() const
+{
+ return d->jid;
+}
+
+/// Sets the participant's JID.
+
+void QXmppMixParticipantItem::setJid(const QString& jid)
+{
+ d->jid = jid;
+}
+
+void QXmppMixParticipantItem::parse(const QXmppElement& itemContent)
+{
+ d->nick = itemContent.firstChildElement("nick").value();
+ d->jid = itemContent.firstChildElement("jid").value();
+}
+
+QXmppElement QXmppMixParticipantItem::toElement() const
+{
+ QXmppElement element;
+ element.setTagName("participant");
+ element.setAttribute("xmlns", ns_mix);
+
+ QXmppElement jid;
+ jid.setTagName("jid");
+ jid.setValue(d->jid);
+ element.appendChild(jid);
+
+ QXmppElement nick;
+ nick.setTagName("nick");
+ nick.setValue(d->nick);
+ element.appendChild(nick);
+
+ return element;
+}
+
+/// Returns true, if this dom element is a MIX participant item.
+
+bool QXmppMixParticipantItem::isMixParticipantItem(const QDomElement &element)
+{
+ return element.tagName() == "participant" && element.namespaceURI() == ns_mix;
+}
diff --git a/src/base/QXmppMixItem.h b/src/base/QXmppMixItem.h
new file mode 100644
index 00000000..d4f046c1
--- /dev/null
+++ b/src/base/QXmppMixItem.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef QXMPPMIXITEM_H
+#define QXMPPMIXITEM_H
+
+#include "QXmppElement.h"
+
+class QXmppMixInfoItemPrivate;
+class QXmppMixParticipantItemPrivate;
+
+/// \brief The QXmppMixInfoItem class represents a PubSub item of a MIX
+/// channel containing channel information as defined by XEP-0369: Mediated
+/// Information eXchange (MIX).
+///
+/// \ingroup Stanzas
+
+class QXMPP_EXPORT QXmppMixInfoItem
+{
+public:
+ QXmppMixInfoItem();
+
+ QString name() const;
+ void setName(const QString&);
+
+ QString description() const;
+ void setDescription(const QString&);
+
+ QStringList contactJids() const;
+ void setContactJids(const QStringList&);
+
+ void parse(const QXmppElement& itemContent);
+ QXmppElement toElement() const;
+
+ static bool isMixChannelInfo(const QDomElement&);
+
+private:
+ QXmppMixInfoItemPrivate *d;
+};
+
+/// \brief The QXmppMixParticipantItem class represents a PubSub item of a MIX
+/// channel participant as defined by XEP-0369: Mediated Information eXchange
+/// (MIX).
+///
+/// \ingroup Stanzas
+
+class QXMPP_EXPORT QXmppMixParticipantItem
+{
+public:
+ QXmppMixParticipantItem();
+
+ QString nick() const;
+ void setNick(const QString&);
+
+ QString jid() const;
+ void setJid(const QString&);
+
+ void parse(const QXmppElement& itemContent);
+ QXmppElement toElement() const;
+
+ static bool isMixParticipantItem(const QDomElement&);
+
+private:
+ QXmppMixParticipantItemPrivate *d;
+};
+
+#endif // QXMPPMIXITEM_H
diff --git a/src/base/QXmppMucIq.h b/src/base/QXmppMucIq.h
index 7a87eddc..b9b715f8 100644
--- a/src/base/QXmppMucIq.h
+++ b/src/base/QXmppMucIq.h
@@ -113,8 +113,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -141,8 +141,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppNonSASLAuth.h b/src/base/QXmppNonSASLAuth.h
index e888d4c2..4a457fe6 100644
--- a/src/base/QXmppNonSASLAuth.h
+++ b/src/base/QXmppNonSASLAuth.h
@@ -47,8 +47,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppPingIq.h b/src/base/QXmppPingIq.h
index c23381c5..3139dc13 100644
--- a/src/base/QXmppPingIq.h
+++ b/src/base/QXmppPingIq.h
@@ -30,7 +30,7 @@ class QXMPP_EXPORT QXmppPingIq : public QXmppIq
{
public:
QXmppPingIq();
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
static bool isPingIq(const QDomElement &element);
};
diff --git a/src/base/QXmppPresence.cpp b/src/base/QXmppPresence.cpp
index f8a27f43..ad0b1c60 100644
--- a/src/base/QXmppPresence.cpp
+++ b/src/base/QXmppPresence.cpp
@@ -80,6 +80,10 @@ public:
// XEP-0319: Last User Interaction in Presence
QDateTime lastUserInteraction;
+
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ QString mixUserJid;
+ QString mixUserNick;
};
/// Constructs a QXmppPresence.
@@ -265,6 +269,11 @@ void QXmppPresence::parse(const QDomElement &element)
d->lastUserInteraction = QXmppUtils::datetimeFromString(since);
}
}
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ else if (xElement.tagName() == "mix" && xElement.namespaceURI() == ns_mix_presence) {
+ d->mixUserJid = xElement.firstChildElement("jid").text();
+ d->mixUserNick = xElement.firstChildElement("nick").text();
+ }
else if (xElement.tagName() != "addresses" && xElement.tagName() != "error"
&& xElement.tagName() != "show" && xElement.tagName() != "status"
&& xElement.tagName() != "priority")
@@ -361,6 +370,17 @@ void QXmppPresence::toXml(QXmlStreamWriter *xmlWriter) const
xmlWriter->writeEndElement();
}
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ if (!d->mixUserJid.isEmpty() || !d->mixUserNick.isEmpty()) {
+ xmlWriter->writeStartElement("mix");
+ xmlWriter->writeAttribute("xmlns", ns_mix_presence);
+ if (!d->mixUserJid.isEmpty())
+ xmlWriter->writeTextElement("jid", d->mixUserJid);
+ if (!d->mixUserNick.isEmpty())
+ xmlWriter->writeTextElement("nick", d->mixUserNick);
+ xmlWriter->writeEndElement();
+ }
+
// other extensions
QXmppStanza::extensionsToXml(xmlWriter);
@@ -522,7 +542,35 @@ void QXmppPresence::setLastUserInteraction(const QDateTime& lastUserInteraction)
d->lastUserInteraction = lastUserInteraction;
}
-/// Indicates if the QXmppStanza is a stanza in the XMPP sense (i. e. a message,
+/// Returns the actual (full) JID of the MIX channel participant.
+
+QString QXmppPresence::mixUserJid() const
+{
+ return d->mixUserJid;
+}
+
+/// Sets the actual (full) JID of the MIX channel participant.
+
+void QXmppPresence::setMixUserJid(const QString& mixUserJid)
+{
+ d->mixUserJid = mixUserJid;
+}
+
+/// Returns the MIX participant's nickname.
+
+QString QXmppPresence::mixUserNick() const
+{
+ return d->mixUserNick;
+}
+
+/// Sets the MIX participant's nickname.
+
+void QXmppPresence::setMixUserNick(const QString& mixUserNick)
+{
+ d->mixUserNick = mixUserNick;
+}
+
+/// Indicates if the QXmppStanza is a stanza in the XMPP sence (i. e. a message,
/// iq or presence)
bool QXmppPresence::isXmppStanza() const
diff --git a/src/base/QXmppPresence.h b/src/base/QXmppPresence.h
index bda272af..d6ab980d 100644
--- a/src/base/QXmppPresence.h
+++ b/src/base/QXmppPresence.h
@@ -75,7 +75,7 @@ public:
QXmppPresence(QXmppPresence::Type type = QXmppPresence::Available);
QXmppPresence(const QXmppPresence &other);
- ~QXmppPresence();
+ ~QXmppPresence() override;
QXmppPresence& operator=(const QXmppPresence &other);
@@ -92,8 +92,8 @@ public:
void setStatusText(const QString& statusText);
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
/// \endcond
// XEP-0045: Multi-User Chat
@@ -132,7 +132,14 @@ public:
QDateTime lastUserInteraction() const;
void setLastUserInteraction(const QDateTime&);
- bool isXmppStanza() const;
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ QString mixUserJid() const;
+ void setMixUserJid(const QString&);
+
+ QString mixUserNick() const;
+ void setMixUserNick(const QString&);
+
+ bool isXmppStanza() const override;
private:
QSharedDataPointer<QXmppPresencePrivate> d;
diff --git a/src/base/QXmppPubSubIq.h b/src/base/QXmppPubSubIq.h
index 77cd234e..741b25da 100644
--- a/src/base/QXmppPubSubIq.h
+++ b/src/base/QXmppPubSubIq.h
@@ -92,8 +92,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement&);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement&) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppRegisterIq.h b/src/base/QXmppRegisterIq.h
index c51035da..47fe12cc 100644
--- a/src/base/QXmppRegisterIq.h
+++ b/src/base/QXmppRegisterIq.h
@@ -59,8 +59,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppRosterIq.cpp b/src/base/QXmppRosterIq.cpp
index 081cb753..3dfb32b4 100644
--- a/src/base/QXmppRosterIq.cpp
+++ b/src/base/QXmppRosterIq.cpp
@@ -29,20 +29,39 @@
#include "QXmppConstants_p.h"
#include "QXmppUtils.h"
+class QXmppRosterIqPrivate : public QSharedData
+{
+public:
+ QList<QXmppRosterIq::Item> items;
+ // XEP-0237 Roster Versioning
+ QString version;
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ bool mixAnnotate = false;
+};
+
+QXmppRosterIq::QXmppRosterIq()
+ : d(new QXmppRosterIqPrivate)
+{
+}
+
+QXmppRosterIq::~QXmppRosterIq()
+{
+}
+
/// Adds an item to the roster IQ.
///
/// \param item
void QXmppRosterIq::addItem(const Item& item)
{
- m_items.append(item);
+ d->items.append(item);
}
/// Returns the roster IQ's items.
QList<QXmppRosterIq::Item> QXmppRosterIq::items() const
{
- return m_items;
+ return d->items;
}
/// Returns the roster version of IQ.
@@ -52,7 +71,7 @@ QList<QXmppRosterIq::Item> QXmppRosterIq::items() const
QString QXmppRosterIq::version() const
{
- return m_version;
+ return d->version;
}
/// Sets the roster version of IQ.
@@ -62,7 +81,22 @@ QString QXmppRosterIq::version() const
void QXmppRosterIq::setVersion(const QString &version)
{
- m_version = version;
+ d->version = version;
+}
+
+/// Whether to annotate which items are MIX channels.
+
+bool QXmppRosterIq::mixAnnotate() const
+{
+ return d->mixAnnotate;
+}
+
+/// Sets whether to include which roster items are MIX channels. This MUST only
+/// be enabled in get requests.
+
+void QXmppRosterIq::setMixAnnotate(bool mixAnnotate)
+{
+ d->mixAnnotate = mixAnnotate;
}
/// \cond
@@ -74,16 +108,20 @@ bool QXmppRosterIq::isRosterIq(const QDomElement &element)
void QXmppRosterIq::parseElementFromChild(const QDomElement &element)
{
QDomElement queryElement = element.firstChildElement("query");
- QDomElement itemElement = queryElement.firstChildElement("item");
-
setVersion(queryElement.attribute("ver"));
+
+ QDomElement itemElement = queryElement.firstChildElement("item");
while(!itemElement.isNull())
{
QXmppRosterIq::Item item;
item.parse(itemElement);
- m_items.append(item);
- itemElement = itemElement.nextSiblingElement();
+ d->items.append(item);
+ itemElement = itemElement.nextSiblingElement("item");
}
+
+ QDomElement annotateElement = queryElement.firstChildElement("annotate");
+ setMixAnnotate(!annotateElement.isNull() && annotateElement.namespaceURI()
+ == ns_mix_roster);
}
void QXmppRosterIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
@@ -92,19 +130,52 @@ void QXmppRosterIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
writer->writeAttribute( "xmlns", ns_roster);
// XEP-0237 roster versioning - If the server does not advertise support for roster versioning, the client MUST NOT include the 'ver' attribute.
- if(!version().isEmpty())
- writer->writeAttribute( "ver", version());
- for(int i = 0; i < m_items.count(); ++i)
- m_items.at(i).toXml(writer);
+ if (!version().isEmpty())
+ writer->writeAttribute("ver", version());
+
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ if (d->mixAnnotate) {
+ writer->writeStartElement("annotate");
+ writer->writeAttribute("xmlns", ns_mix_roster);
+ writer->writeEndElement();
+ }
+
+ for (int i = 0; i < d->items.count(); ++i)
+ d->items.at(i).toXml(writer);
writer->writeEndElement();
}
/// \endcond
+class QXmppRosterIq::ItemPrivate : public QSharedData
+{
+public:
+ QString bareJid;
+ Item::SubscriptionType type;
+ QString name;
+ // can be subscribe/unsubscribe (attribute "ask")
+ QString subscriptionStatus;
+ QSet<QString> groups;
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ bool isMixChannel = false;
+ QString mixParticipantId;
+};
+
/// Constructs a new roster entry.
QXmppRosterIq::Item::Item()
- : m_type(NotSet)
+ : d(new ItemPrivate)
{
+ d->type = NotSet;
+}
+
+QXmppRosterIq::Item::~Item()
+{
+}
+
+QXmppRosterIq::Item& QXmppRosterIq::Item::operator=(const Item &other)
+{
+ d = other.d;
+ return *this;
}
/// Returns the bareJid of the roster entry.
@@ -114,7 +185,7 @@ QXmppRosterIq::Item::Item()
QString QXmppRosterIq::Item::bareJid() const
{
- return m_bareJid;
+ return d->bareJid;
}
/// Sets the bareJid of the roster entry.
@@ -124,7 +195,7 @@ QString QXmppRosterIq::Item::bareJid() const
void QXmppRosterIq::Item::setBareJid(const QString &bareJid)
{
- m_bareJid = bareJid;
+ d->bareJid = bareJid;
}
/// Returns the groups of the roster entry.
@@ -134,7 +205,7 @@ void QXmppRosterIq::Item::setBareJid(const QString &bareJid)
QSet<QString> QXmppRosterIq::Item::groups() const
{
- return m_groups;
+ return d->groups;
}
/// Sets the groups of the roster entry.
@@ -144,7 +215,7 @@ QSet<QString> QXmppRosterIq::Item::groups() const
void QXmppRosterIq::Item::setGroups(const QSet<QString>& groups)
{
- m_groups = groups;
+ d->groups = groups;
}
/// Returns the name of the roster entry.
@@ -154,7 +225,7 @@ void QXmppRosterIq::Item::setGroups(const QSet<QString>& groups)
QString QXmppRosterIq::Item::name() const
{
- return m_name;
+ return d->name;
}
/// Sets the name of the roster entry.
@@ -164,7 +235,7 @@ QString QXmppRosterIq::Item::name() const
void QXmppRosterIq::Item::setName(const QString &name)
{
- m_name = name;
+ d->name = name;
}
/// Returns the subscription status of the roster entry. It is the "ask"
@@ -177,7 +248,7 @@ void QXmppRosterIq::Item::setName(const QString &name)
QString QXmppRosterIq::Item::subscriptionStatus() const
{
- return m_subscriptionStatus;
+ return d->subscriptionStatus;
}
/// Sets the subscription status of the roster entry. It is the "ask"
@@ -189,7 +260,7 @@ QString QXmppRosterIq::Item::subscriptionStatus() const
void QXmppRosterIq::Item::setSubscriptionStatus(const QString &status)
{
- m_subscriptionStatus = status;
+ d->subscriptionStatus = status;
}
/// Returns the subscription type of the roster entry.
@@ -198,7 +269,7 @@ void QXmppRosterIq::Item::setSubscriptionStatus(const QString &status)
QXmppRosterIq::Item::SubscriptionType
QXmppRosterIq::Item::subscriptionType() const
{
- return m_type;
+ return d->type;
}
/// Sets the subscription type of the roster entry.
@@ -208,12 +279,12 @@ QXmppRosterIq::Item::SubscriptionType
void QXmppRosterIq::Item::setSubscriptionType(SubscriptionType type)
{
- m_type = type;
+ d->type = type;
}
QString QXmppRosterIq::Item::getSubscriptionTypeStr() const
{
- switch(m_type)
+ switch(d->type)
{
case NotSet:
return "";
@@ -253,36 +324,80 @@ void QXmppRosterIq::Item::setSubscriptionTypeFromStr(const QString& type)
qWarning("QXmppRosterIq::Item::setTypeFromStr(): invalid type");
}
+/// Returns whether this is a MIX channel.
+
+bool QXmppRosterIq::Item::isMixChannel() const
+{
+ return d->isMixChannel;
+}
+
+/// Sets whether this is a MIX channel.
+
+void QXmppRosterIq::Item::setIsMixChannel(bool isMixChannel)
+{
+ d->isMixChannel = isMixChannel;
+}
+
+/// Returns the participant id for this MIX channel.
+
+QString QXmppRosterIq::Item::mixParticipantId() const
+{
+ return d->mixParticipantId;
+}
+
+/// Sets the participant id for this MIX channel.
+
+void QXmppRosterIq::Item::setMixParticipantId(const QString& participantId)
+{
+ d->mixParticipantId = participantId;
+}
+
/// \cond
void QXmppRosterIq::Item::parse(const QDomElement &element)
{
- m_name = element.attribute("name");
- m_bareJid = element.attribute("jid");
+ d->name = element.attribute("name");
+ d->bareJid = element.attribute("jid");
setSubscriptionTypeFromStr(element.attribute("subscription"));
setSubscriptionStatus(element.attribute("ask"));
QDomElement groupElement = element.firstChildElement("group");
while(!groupElement.isNull())
{
- m_groups << groupElement.text();
+ d->groups << groupElement.text();
groupElement = groupElement.nextSiblingElement("group");
}
+
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ QDomElement channelElement = element.firstChildElement("channel");
+ if (!channelElement.isNull() && channelElement.namespaceURI() == ns_mix_roster) {
+ d->isMixChannel = true;
+ d->mixParticipantId = channelElement.attribute("participant-id");
+ }
}
void QXmppRosterIq::Item::toXml(QXmlStreamWriter *writer) const
{
writer->writeStartElement("item");
- helperToXmlAddAttribute(writer,"jid", m_bareJid);
- helperToXmlAddAttribute(writer,"name", m_name);
+ helperToXmlAddAttribute(writer,"jid", d->bareJid);
+ helperToXmlAddAttribute(writer,"name", d->name);
helperToXmlAddAttribute(writer,"subscription", getSubscriptionTypeStr());
helperToXmlAddAttribute(writer, "ask", subscriptionStatus());
- QSet<QString>::const_iterator i = m_groups.constBegin();
- while(i != m_groups.constEnd())
+ QSet<QString>::const_iterator i = d->groups.constBegin();
+ while(i != d->groups.constEnd())
{
helperToXmlAddTextElement(writer,"group", *i);
++i;
}
+
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ if (d->isMixChannel) {
+ writer->writeStartElement("channel");
+ writer->writeAttribute("xmlns", ns_mix_roster);
+ helperToXmlAddAttribute(writer, "participant-id", d->mixParticipantId);
+ writer->writeEndElement();
+ }
+
writer->writeEndElement();
}
/// \endcond
diff --git a/src/base/QXmppRosterIq.h b/src/base/QXmppRosterIq.h
index b2883557..4d0205d4 100644
--- a/src/base/QXmppRosterIq.h
+++ b/src/base/QXmppRosterIq.h
@@ -30,6 +30,8 @@
#include <QList>
#include <QSet>
+class QXmppRosterIqPrivate;
+
/// \brief The QXmppRosterIq class represents a roster IQ.
///
/// \ingroup Stanzas
@@ -37,6 +39,7 @@
class QXMPP_EXPORT QXmppRosterIq : public QXmppIq
{
public:
+ class ItemPrivate;
/// \brief The QXmppRosterIq::Item class represents a roster entry.
class QXMPP_EXPORT Item
@@ -59,6 +62,10 @@ public:
};
Item();
+ ~Item();
+
+ Item& operator=(const Item &other);
+
QString bareJid() const;
QSet<QString> groups() const;
QString name() const;
@@ -71,6 +78,13 @@ public:
void setSubscriptionStatus(const QString&);
void setSubscriptionType(SubscriptionType);
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ bool isMixChannel() const;
+ void setIsMixChannel(bool);
+
+ QString mixParticipantId() const;
+ void setMixParticipantId(const QString&);
+
/// \cond
void parse(const QDomElement &element);
void toXml(QXmlStreamWriter *writer) const;
@@ -80,34 +94,34 @@ public:
QString getSubscriptionTypeStr() const;
void setSubscriptionTypeFromStr(const QString&);
- QString m_bareJid;
- SubscriptionType m_type;
- QString m_name;
- // can be subscribe/unsubscribe (attribute "ask")
- QString m_subscriptionStatus;
- QSet<QString> m_groups;
+ ItemPrivate *d;
};
+ QXmppRosterIq();
+ ~QXmppRosterIq() override;
+
QString version() const;
void setVersion(const QString&);
void addItem(const Item&);
QList<Item> items() const;
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ bool mixAnnotate() const;
+ void setMixAnnotate(bool);
+
/// \cond
static bool isRosterIq(const QDomElement &element);
/// \endcond
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
- QList<Item> m_items;
- // XEP-0237 Roster Versioning
- QString m_version;
+ QXmppRosterIqPrivate *d;
};
#endif // QXMPPROSTERIQ_H
diff --git a/src/base/QXmppRpcIq.h b/src/base/QXmppRpcIq.h
index ce406d4f..1edd31aa 100644
--- a/src/base/QXmppRpcIq.h
+++ b/src/base/QXmppRpcIq.h
@@ -60,8 +60,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -92,8 +92,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -117,8 +117,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppRtpChannel.cpp b/src/base/QXmppRtpChannel.cpp
index 61bf10f7..f80c7c4d 100644
--- a/src/base/QXmppRtpChannel.cpp
+++ b/src/base/QXmppRtpChannel.cpp
@@ -213,12 +213,12 @@ QXmppRtpAudioChannelPrivate::QXmppRtpAudioChannelPrivate()
, incomingMaximum(0)
, incomingPos(0)
, incomingSequence(0)
- , outgoingCodec(0)
+ , outgoingCodec(nullptr)
, outgoingMarker(true)
, outgoingPayloadNumbered(false)
, outgoingSequence(1)
, outgoingStamp(0)
- , outgoingTimer(0)
+ , outgoingTimer(nullptr)
{
qRegisterMetaType<QXmppRtpAudioChannel::Tone>("QXmppRtpAudioChannel::Tone");
}
@@ -240,7 +240,7 @@ QXmppCodec *QXmppRtpAudioChannelPrivate::codecForPayloadType(const QXmppJinglePa
else if (payloadType.name().toLower() == "opus")
return new QXmppOpusCodec(payloadType.clockrate(), payloadType.channels());
#endif
- return 0;
+ return nullptr;
}
/// Constructs a new RTP audio channel with the given \a parent.
@@ -349,7 +349,7 @@ void QXmppRtpAudioChannel::datagramReceived(const QByteArray &ba)
d->incomingSequence = packet.sequence();
// get or create codec
- QXmppCodec *codec = 0;
+ QXmppCodec *codec = nullptr;
const quint8 packetType = packet.type();
if (!d->incomingCodecs.contains(packetType)) {
foreach (const QXmppJinglePayloadType &payload, m_incomingPayloadTypes) {
@@ -497,7 +497,7 @@ void QXmppRtpAudioChannel::payloadTypesChanged()
// delete outgoing codec
if (d->outgoingCodec) {
delete d->outgoingCodec;
- d->outgoingCodec = 0;
+ d->outgoingCodec = nullptr;
}
// create outgoing codec
@@ -797,7 +797,7 @@ public:
};
QXmppRtpVideoChannelPrivate::QXmppRtpVideoChannelPrivate()
- : encoder(0),
+ : encoder(nullptr),
outgoingId(0),
outgoingSequence(1),
outgoingStamp(0)
@@ -925,7 +925,7 @@ void QXmppRtpVideoChannel::payloadTypesChanged()
delete decoder;
d->decoders.clear();
foreach (const QXmppJinglePayloadType &payload, m_incomingPayloadTypes) {
- QXmppVideoDecoder *decoder = 0;
+ QXmppVideoDecoder *decoder = nullptr;
if (false)
{}
#ifdef QXMPP_USE_THEORA
@@ -945,10 +945,10 @@ void QXmppRtpVideoChannel::payloadTypesChanged()
// refresh encoder
if (d->encoder) {
delete d->encoder;
- d->encoder = 0;
+ d->encoder = nullptr;
}
foreach (const QXmppJinglePayloadType &payload, m_outgoingPayloadTypes) {
- QXmppVideoEncoder *encoder = 0;
+ QXmppVideoEncoder *encoder = nullptr;
if (false)
{}
#ifdef QXMPP_USE_THEORA
diff --git a/src/base/QXmppRtpChannel.h b/src/base/QXmppRtpChannel.h
index 0e0789da..9b68c7bc 100644
--- a/src/base/QXmppRtpChannel.h
+++ b/src/base/QXmppRtpChannel.h
@@ -98,16 +98,16 @@ public:
Tone_D ///< Tone for the D key.
};
- QXmppRtpAudioChannel(QObject *parent = 0);
- ~QXmppRtpAudioChannel();
+ QXmppRtpAudioChannel(QObject *parent = nullptr);
+ ~QXmppRtpAudioChannel() override;
- qint64 bytesAvailable() const;
- void close();
- bool isSequential() const;
- QIODevice::OpenMode openMode() const;
+ qint64 bytesAvailable() const override;
+ void close() override;
+ bool isSequential() const override;
+ QIODevice::OpenMode openMode() const override;
QXmppJinglePayloadType payloadType() const;
- qint64 pos() const;
- bool seek(qint64 pos);
+ qint64 pos() const override;
+ bool seek(qint64 pos) override;
signals:
/// \brief This signal is emitted when a datagram needs to be sent.
@@ -143,9 +143,9 @@ protected:
emit logMessage(QXmppLogger::SentMessage, qxmpp_loggable_trace(message));
}
- void payloadTypesChanged();
- qint64 readData(char * data, qint64 maxSize);
- qint64 writeData(const char * data, qint64 maxSize);
+ void payloadTypesChanged() override;
+ qint64 readData(char * data, qint64 maxSize) override;
+ qint64 writeData(const char * data, qint64 maxSize) override;
/// \endcond
private slots:
@@ -263,11 +263,11 @@ class QXMPP_EXPORT QXmppRtpVideoChannel : public QXmppLoggable, public QXmppRtpC
Q_OBJECT
public:
- QXmppRtpVideoChannel(QObject *parent = 0);
- ~QXmppRtpVideoChannel();
+ QXmppRtpVideoChannel(QObject *parent = nullptr);
+ ~QXmppRtpVideoChannel() override;
- void close();
- QIODevice::OpenMode openMode() const;
+ void close() override;
+ QIODevice::OpenMode openMode() const override;
// incoming stream
QXmppVideoFormat decoderFormat() const;
@@ -287,7 +287,7 @@ public slots:
protected:
/// \cond
- void payloadTypesChanged();
+ void payloadTypesChanged() override;
/// \endcond
private:
diff --git a/src/base/QXmppSasl.cpp b/src/base/QXmppSasl.cpp
index d6dbb04a..497fadf5 100644
--- a/src/base/QXmppSasl.cpp
+++ b/src/base/QXmppSasl.cpp
@@ -24,9 +24,10 @@
#include <cstdlib>
-#include <QCryptographicHash>
#include <QDomElement>
+#include <QMessageAuthenticationCode>
#include <QStringList>
+#include <QtEndian>
#include <QUrlQuery>
#include "QXmppSasl_p.h"
@@ -49,6 +50,36 @@ static QByteArray calculateDigest(const QByteArray &method, const QByteArray &di
return QCryptographicHash::hash(KD, QCryptographicHash::Md5).toHex();
}
+// Perform PBKFD2 key derivation, code taken from Qt 5.12
+
+static QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algorithm,
+ const QByteArray &data, const QByteArray &salt,
+ int iterations, quint64 dkLen)
+{
+ QByteArray key;
+ quint32 currentIteration = 1;
+ QMessageAuthenticationCode hmac(algorithm, data);
+ QByteArray index(4, Qt::Uninitialized);
+ while (quint64(key.length()) < dkLen) {
+ hmac.addData(salt);
+ qToBigEndian(currentIteration, reinterpret_cast<uchar*>(index.data()));
+ hmac.addData(index);
+ QByteArray u = hmac.result();
+ hmac.reset();
+ QByteArray tkey = u;
+ for (int iter = 1; iter < iterations; iter++) {
+ hmac.addData(u);
+ u = hmac.result();
+ hmac.reset();
+ std::transform(tkey.cbegin(), tkey.cend(), u.cbegin(), tkey.begin(),
+ std::bit_xor<char>());
+ }
+ key += tkey;
+ currentIteration++;
+ }
+ return key.left(dkLen);
+}
+
static QByteArray generateNonce()
{
if (!forcedNonce.isEmpty())
@@ -61,6 +92,17 @@ static QByteArray generateNonce()
return nonce.toBase64();
}
+static QMap<char, QByteArray> parseGS2(const QByteArray &ba)
+{
+ QMap<char, QByteArray> map;
+ foreach (const QByteArray &keyValue, ba.split(',')) {
+ if (keyValue.size() >= 2 && keyValue[1] == '=') {
+ map[keyValue[0]] = keyValue.mid(2);
+ }
+ }
+ return map;
+}
+
QXmppSaslAuth::QXmppSaslAuth(const QString &mechanism, const QByteArray &value)
: m_mechanism(mechanism)
, m_value(value)
@@ -230,7 +272,9 @@ QXmppSaslClient::~QXmppSaslClient()
QStringList QXmppSaslClient::availableMechanisms()
{
- return QStringList() << "PLAIN" << "DIGEST-MD5" << "ANONYMOUS" << "X-FACEBOOK-PLATFORM" << "X-MESSENGER-OAUTH2" << "X-OAUTH2";
+ return QStringList() << "SCRAM-SHA-256" << "SCRAM-SHA-1" << "DIGEST-MD5"
+ << "PLAIN" << "ANONYMOUS"
+ << "X-FACEBOOK-PLATFORM" << "X-MESSENGER-OAUTH2" << "X-OAUTH2";
}
/// Creates an SASL client for the given mechanism.
@@ -243,6 +287,10 @@ QXmppSaslClient* QXmppSaslClient::create(const QString &mechanism, QObject *pare
return new QXmppSaslClientDigestMd5(parent);
} else if (mechanism == "ANONYMOUS") {
return new QXmppSaslClientAnonymous(parent);
+ } else if (mechanism == "SCRAM-SHA-1") {
+ return new QXmppSaslClientScram(QCryptographicHash::Sha1, parent);
+ } else if (mechanism == "SCRAM-SHA-256") {
+ return new QXmppSaslClientScram(QCryptographicHash::Sha256, parent);
} else if (mechanism == "X-FACEBOOK-PLATFORM") {
return new QXmppSaslClientFacebook(parent);
} else if (mechanism == "X-MESSENGER-OAUTH2") {
@@ -250,7 +298,7 @@ QXmppSaslClient* QXmppSaslClient::create(const QString &mechanism, QObject *pare
} else if (mechanism == "X-OAUTH2") {
return new QXmppSaslClientGoogle(parent);
} else {
- return 0;
+ return nullptr;
}
}
@@ -443,7 +491,7 @@ bool QXmppSaslClientFacebook::respond(const QByteArray &challenge, QByteArray &r
QUrlQuery responseUrl;
responseUrl.addQueryItem("access_token", password());
responseUrl.addQueryItem("api_key", username());
- responseUrl.addQueryItem("call_id", 0);
+ responseUrl.addQueryItem("call_id", nullptr);
responseUrl.addQueryItem("method", requestUrl.queryItemValue("method"));
responseUrl.addQueryItem("nonce", requestUrl.queryItemValue("nonce"));
responseUrl.addQueryItem("v", "1.0");
@@ -507,6 +555,76 @@ bool QXmppSaslClientPlain::respond(const QByteArray &challenge, QByteArray &resp
}
}
+QXmppSaslClientScram::QXmppSaslClientScram(QCryptographicHash::Algorithm algorithm, QObject *parent)
+ : QXmppSaslClient(parent)
+ , m_algorithm(algorithm)
+ , m_step(0)
+{
+ Q_ASSERT(m_algorithm == QCryptographicHash::Sha1 || m_algorithm == QCryptographicHash::Sha256);
+ m_nonce = generateNonce();
+
+ if (m_algorithm == QCryptographicHash::Sha256) {
+ m_dklen = 32;
+ m_mechanism = "SCRAM-SHA-256";
+ } else {
+ m_dklen = 20;
+ m_mechanism = "SCRAM-SHA-1";
+ }
+}
+
+QString QXmppSaslClientScram::mechanism() const
+{
+ return m_mechanism;
+}
+
+bool QXmppSaslClientScram::respond(const QByteArray &challenge, QByteArray &response)
+{
+ Q_UNUSED(challenge);
+ if (m_step == 0) {
+ m_gs2Header = "n,,";
+ m_clientFirstMessageBare = "n=" + username().toUtf8() + ",r=" + m_nonce;
+
+ response = m_gs2Header + m_clientFirstMessageBare;
+ m_step++;
+ return true;
+ } else if (m_step == 1) {
+ // validate input
+ const QMap<char, QByteArray> input = parseGS2(challenge);
+ const QByteArray nonce = input.value('r');
+ const QByteArray salt = QByteArray::fromBase64(input.value('s'));
+ const int iterations = input.value('i').toInt();
+ if (!nonce.startsWith(m_nonce) || salt.isEmpty() || iterations < 1) {
+ return false;
+ }
+
+ // calculate proofs
+ const QByteArray clientFinalMessageBare = "c=" + m_gs2Header.toBase64() + ",r=" + nonce;
+ const QByteArray saltedPassword = deriveKeyPbkdf2(m_algorithm, password().toUtf8(), salt,
+ iterations, m_dklen);
+ const QByteArray clientKey = QMessageAuthenticationCode::hash("Client Key", saltedPassword, m_algorithm);
+ const QByteArray storedKey = QCryptographicHash::hash(clientKey, m_algorithm);
+ const QByteArray authMessage = m_clientFirstMessageBare + "," + challenge + "," + clientFinalMessageBare;
+ QByteArray clientProof = QMessageAuthenticationCode::hash(authMessage, storedKey, m_algorithm);
+ std::transform(clientProof.cbegin(), clientProof.cend(), clientKey.cbegin(),
+ clientProof.begin(), std::bit_xor<char>());
+
+ const QByteArray serverKey = QMessageAuthenticationCode::hash("Server Key", saltedPassword, m_algorithm);
+ m_serverSignature = QMessageAuthenticationCode::hash(authMessage, serverKey, m_algorithm);
+
+ response = clientFinalMessageBare + ",p=" + clientProof.toBase64();
+ m_step++;
+ return true;
+ } else if (m_step == 2) {
+ const QMap<char, QByteArray> input = parseGS2(challenge);
+ response = QByteArray();
+ m_step++;
+ return QByteArray::fromBase64(input.value('v')) == m_serverSignature;
+ } else {
+ warning("QXmppSaslClientPlain : Invalid step");
+ return false;
+ }
+}
+
QXmppSaslClientWindowsLive::QXmppSaslClientWindowsLive(QObject *parent)
: QXmppSaslClient(parent)
, m_step(0)
@@ -563,7 +681,7 @@ QXmppSaslServer* QXmppSaslServer::create(const QString &mechanism, QObject *pare
} else if (mechanism == "ANONYMOUS") {
return new QXmppSaslServerAnonymous(parent);
} else {
- return 0;
+ return nullptr;
}
}
diff --git a/src/base/QXmppSasl_p.h b/src/base/QXmppSasl_p.h
index ac8d911b..1d460f01 100644
--- a/src/base/QXmppSasl_p.h
+++ b/src/base/QXmppSasl_p.h
@@ -26,6 +26,7 @@
#define QXMPPSASL_P_H
#include <QByteArray>
+#include <QCryptographicHash>
#include <QMap>
#include "QXmppGlobal.h"
@@ -51,8 +52,8 @@ class QXmppSaslServerPrivate;
class QXMPP_AUTOTEST_EXPORT QXmppSaslClient : public QXmppLoggable
{
public:
- QXmppSaslClient(QObject *parent = 0);
- virtual ~QXmppSaslClient();
+ QXmppSaslClient(QObject *parent = nullptr);
+ ~QXmppSaslClient() override;
QString host() const;
void setHost(const QString &host);
@@ -70,7 +71,7 @@ public:
virtual bool respond(const QByteArray &challenge, QByteArray &response) = 0;
static QStringList availableMechanisms();
- static QXmppSaslClient* create(const QString &mechanism, QObject *parent = 0);
+ static QXmppSaslClient* create(const QString &mechanism, QObject *parent = nullptr);
private:
QXmppSaslClientPrivate *d;
@@ -86,8 +87,8 @@ public:
InputNeeded = 3
};
- QXmppSaslServer(QObject *parent = 0);
- virtual ~QXmppSaslServer();
+ QXmppSaslServer(QObject *parent = nullptr);
+ ~QXmppSaslServer() override;
QString username() const;
void setUsername(const QString &username);
@@ -104,7 +105,7 @@ public:
virtual QString mechanism() const = 0;
virtual Response respond(const QByteArray &challenge, QByteArray &response) = 0;
- static QXmppSaslServer* create(const QString &mechanism, QObject *parent = 0);
+ static QXmppSaslServer* create(const QString &mechanism, QObject *parent = nullptr);
private:
QXmppSaslServerPrivate *d;
@@ -132,8 +133,8 @@ public:
void setValue(const QByteArray &value);
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -150,8 +151,8 @@ public:
void setValue(const QByteArray &value);
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -167,8 +168,8 @@ public:
void setCondition(const QString &condition);
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -184,8 +185,8 @@ public:
void setValue(const QByteArray &value);
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
/// \endcond
private:
@@ -198,17 +199,17 @@ public:
QXmppSaslSuccess();
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
/// \endcond
};
class QXmppSaslClientAnonymous : public QXmppSaslClient
{
public:
- QXmppSaslClientAnonymous(QObject *parent = 0);
- QString mechanism() const;
- bool respond(const QByteArray &challenge, QByteArray &response);
+ QXmppSaslClientAnonymous(QObject *parent = nullptr);
+ QString mechanism() const override;
+ bool respond(const QByteArray &challenge, QByteArray &response) override;
private:
int m_step;
@@ -217,9 +218,9 @@ private:
class QXmppSaslClientDigestMd5 : public QXmppSaslClient
{
public:
- QXmppSaslClientDigestMd5(QObject *parent = 0);
- QString mechanism() const;
- bool respond(const QByteArray &challenge, QByteArray &response);
+ QXmppSaslClientDigestMd5(QObject *parent = nullptr);
+ QString mechanism() const override;
+ bool respond(const QByteArray &challenge, QByteArray &response) override;
private:
QByteArray m_cnonce;
@@ -232,9 +233,9 @@ private:
class QXmppSaslClientFacebook : public QXmppSaslClient
{
public:
- QXmppSaslClientFacebook(QObject *parent = 0);
- QString mechanism() const;
- bool respond(const QByteArray &challenge, QByteArray &response);
+ QXmppSaslClientFacebook(QObject *parent = nullptr);
+ QString mechanism() const override;
+ bool respond(const QByteArray &challenge, QByteArray &response) override;
private:
int m_step;
@@ -243,9 +244,9 @@ private:
class QXmppSaslClientGoogle : public QXmppSaslClient
{
public:
- QXmppSaslClientGoogle(QObject *parent = 0);
- QString mechanism() const;
- bool respond(const QByteArray &challenge, QByteArray &response);
+ QXmppSaslClientGoogle(QObject *parent = nullptr);
+ QString mechanism() const override;
+ bool respond(const QByteArray &challenge, QByteArray &response) override;
private:
int m_step;
@@ -254,20 +255,38 @@ private:
class QXmppSaslClientPlain : public QXmppSaslClient
{
public:
- QXmppSaslClientPlain(QObject *parent = 0);
- QString mechanism() const;
- bool respond(const QByteArray &challenge, QByteArray &response);
+ QXmppSaslClientPlain(QObject *parent = nullptr);
+ QString mechanism() const override;
+ bool respond(const QByteArray &challenge, QByteArray &response) override;
private:
int m_step;
};
+class QXmppSaslClientScram : public QXmppSaslClient
+{
+public:
+ QXmppSaslClientScram(QCryptographicHash::Algorithm algorithm, QObject *parent = nullptr);
+ QString mechanism() const override;
+ bool respond(const QByteArray &challenge, QByteArray &response) override;
+
+private:
+ QCryptographicHash::Algorithm m_algorithm;
+ int m_step;
+ int m_dklen;
+ QString m_mechanism;
+ QByteArray m_gs2Header;
+ QByteArray m_clientFirstMessageBare;
+ QByteArray m_serverSignature;
+ QByteArray m_nonce;
+};
+
class QXmppSaslClientWindowsLive : public QXmppSaslClient
{
public:
- QXmppSaslClientWindowsLive(QObject *parent = 0);
- QString mechanism() const;
- bool respond(const QByteArray &challenge, QByteArray &response);
+ QXmppSaslClientWindowsLive(QObject *parent = nullptr);
+ QString mechanism() const override;
+ bool respond(const QByteArray &challenge, QByteArray &response) override;
private:
int m_step;
@@ -276,10 +295,10 @@ private:
class QXmppSaslServerAnonymous : public QXmppSaslServer
{
public:
- QXmppSaslServerAnonymous(QObject *parent = 0);
- QString mechanism() const;
+ QXmppSaslServerAnonymous(QObject *parent = nullptr);
+ QString mechanism() const override;
- Response respond(const QByteArray &challenge, QByteArray &response);
+ Response respond(const QByteArray &challenge, QByteArray &response) override;
private:
int m_step;
@@ -288,10 +307,10 @@ private:
class QXmppSaslServerDigestMd5 : public QXmppSaslServer
{
public:
- QXmppSaslServerDigestMd5(QObject *parent = 0);
- QString mechanism() const;
+ QXmppSaslServerDigestMd5(QObject *parent = nullptr);
+ QString mechanism() const override;
- Response respond(const QByteArray &challenge, QByteArray &response);
+ Response respond(const QByteArray &challenge, QByteArray &response) override;
private:
QByteArray m_cnonce;
@@ -304,10 +323,10 @@ private:
class QXmppSaslServerFacebook : public QXmppSaslServer
{
public:
- QXmppSaslServerFacebook(QObject *parent = 0);
- QString mechanism() const;
+ QXmppSaslServerFacebook(QObject *parent = nullptr);
+ QString mechanism() const override;
- Response respond(const QByteArray &challenge, QByteArray &response);
+ Response respond(const QByteArray &challenge, QByteArray &response) override;
private:
int m_step;
@@ -316,10 +335,10 @@ private:
class QXmppSaslServerPlain : public QXmppSaslServer
{
public:
- QXmppSaslServerPlain(QObject *parent = 0);
- QString mechanism() const;
+ QXmppSaslServerPlain(QObject *parent = nullptr);
+ QString mechanism() const override;
- Response respond(const QByteArray &challenge, QByteArray &response);
+ Response respond(const QByteArray &challenge, QByteArray &response) override;
private:
int m_step;
diff --git a/src/base/QXmppSessionIq.h b/src/base/QXmppSessionIq.h
index 7a1b444b..7cc375fb 100644
--- a/src/base/QXmppSessionIq.h
+++ b/src/base/QXmppSessionIq.h
@@ -42,7 +42,7 @@ public:
private:
/// \cond
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
};
diff --git a/src/base/QXmppSocks.h b/src/base/QXmppSocks.h
index 114c7ab9..31af8ca9 100644
--- a/src/base/QXmppSocks.h
+++ b/src/base/QXmppSocks.h
@@ -36,7 +36,7 @@ class QXMPP_EXPORT QXmppSocksClient : public QTcpSocket
Q_OBJECT
public:
- QXmppSocksClient(const QString &proxyHost, quint16 proxyPort, QObject *parent=0);
+ QXmppSocksClient(const QString &proxyHost, quint16 proxyPort, QObject *parent=nullptr);
void connectToHost(const QString &hostName, quint16 hostPort);
signals:
@@ -59,7 +59,7 @@ class QXMPP_EXPORT QXmppSocksServer : public QObject
Q_OBJECT
public:
- QXmppSocksServer(QObject *parent=0);
+ QXmppSocksServer(QObject *parent=nullptr);
void close();
bool listen(quint16 port = 0);
diff --git a/src/base/QXmppStream.cpp b/src/base/QXmppStream.cpp
index 000f3b75..e3fa5bfd 100644
--- a/src/base/QXmppStream.cpp
+++ b/src/base/QXmppStream.cpp
@@ -61,7 +61,7 @@ public:
};
QXmppStreamPrivate::QXmppStreamPrivate()
- : socket(0), streamManagementEnabled(false), lastOutgoingSequenceNumber(0), lastIncomingSequenceNumber(0)
+ : socket(nullptr), streamManagementEnabled(false), lastOutgoingSequenceNumber(0), lastIncomingSequenceNumber(0)
{
}
diff --git a/src/base/QXmppStream.h b/src/base/QXmppStream.h
index d05b29fa..271b3400 100644
--- a/src/base/QXmppStream.h
+++ b/src/base/QXmppStream.h
@@ -44,7 +44,7 @@ class QXMPP_EXPORT QXmppStream : public QXmppLoggable
public:
QXmppStream(QObject *parent);
- ~QXmppStream();
+ ~QXmppStream() override;
virtual bool isConnected() const;
bool sendPacket(const QXmppStanza&);
diff --git a/src/base/QXmppStreamFeatures.cpp b/src/base/QXmppStreamFeatures.cpp
index 214cbd9f..8079962a 100644
--- a/src/base/QXmppStreamFeatures.cpp
+++ b/src/base/QXmppStreamFeatures.cpp
@@ -116,6 +116,16 @@ void QXmppStreamFeatures::setClientStateIndicationMode(QXmppStreamFeatures::Mode
m_csiMode = mode;
}
+QXmppStreamFeatures::Mode QXmppStreamFeatures::registerMode() const
+{
+ return m_registerMode;
+}
+
+void QXmppStreamFeatures::setRegisterMode(const QXmppStreamFeatures::Mode &registerMode)
+{
+ m_registerMode = registerMode;
+}
+
/// \cond
bool QXmppStreamFeatures::isStreamFeatures(const QDomElement &element)
{
@@ -148,6 +158,7 @@ void QXmppStreamFeatures::parse(const QDomElement &element)
m_tlsMode = readFeature(element, "starttls", ns_tls);
m_streamManagementMode = readFeature(element, "sm", ns_stream_management);
m_csiMode = readFeature(element, "csi", ns_csi);
+ m_registerMode = readFeature(element, "register", ns_register_feature);
// parse advertised compression methods
QDomElement compression = element.firstChildElement("compression");
@@ -194,6 +205,7 @@ void QXmppStreamFeatures::toXml(QXmlStreamWriter *writer) const
writeFeature(writer, "starttls", ns_tls, m_tlsMode);
writeFeature(writer, "sm", ns_stream_management, m_streamManagementMode);
writeFeature(writer, "csi", ns_csi, m_csiMode);
+ writeFeature(writer, "register", ns_register_feature, m_registerMode);
if (!m_compressionMethods.isEmpty())
{
diff --git a/src/base/QXmppStreamFeatures.h b/src/base/QXmppStreamFeatures.h
index 952e8c84..5a697b83 100644
--- a/src/base/QXmppStreamFeatures.h
+++ b/src/base/QXmppStreamFeatures.h
@@ -73,9 +73,17 @@ public:
/// \pa mode The mode to set.
void setClientStateIndicationMode(Mode mode);
+ /// Returns the mode for XEP-0077: In-Band Registration
+ Mode registerMode() const;
+
+ /// Sets the mode for XEP-0077: In-Band Registration
+ ///
+ /// \pa mode The mode to set.
+ void setRegisterMode(const Mode &registerMode);
+
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
/// \endcond
static bool isStreamFeatures(const QDomElement &element);
@@ -87,6 +95,7 @@ private:
Mode m_tlsMode;
Mode m_streamManagementMode;
Mode m_csiMode;
+ Mode m_registerMode;
QStringList m_authMechanisms;
QStringList m_compressionMethods;
};
diff --git a/src/base/QXmppStreamInitiationIq_p.h b/src/base/QXmppStreamInitiationIq_p.h
index efff0d29..8f227020 100644
--- a/src/base/QXmppStreamInitiationIq_p.h
+++ b/src/base/QXmppStreamInitiationIq_p.h
@@ -70,8 +70,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppStun.cpp b/src/base/QXmppStun.cpp
index 7ab90c8b..36fc4d26 100644
--- a/src/base/QXmppStun.cpp
+++ b/src/base/QXmppStun.cpp
@@ -1683,8 +1683,8 @@ CandidatePair::CandidatePair(int component, bool controlling, QObject *parent)
: QXmppLoggable(parent)
, nominated(false)
, nominating(false)
- , transport(0)
- , transaction(0)
+ , transport(nullptr)
+ , transaction(nullptr)
, m_component(component)
, m_controlling(controlling)
, m_state(WaitingState)
@@ -1790,14 +1790,14 @@ private:
};
QXmppIceComponentPrivate::QXmppIceComponentPrivate(int component_, QXmppIcePrivate *config_, QXmppIceComponent *qq)
- : activePair(0)
+ : activePair(nullptr)
, component(component_)
, config(config_)
- , fallbackPair(0)
+ , fallbackPair(nullptr)
, gatheringState(QXmppIceConnection::NewGatheringState)
, peerReflexivePriority(0)
- , timer(0)
- , turnAllocation(0)
+ , timer(nullptr)
+ , turnAllocation(nullptr)
, turnConfigured(false)
, q(qq)
{
@@ -1834,7 +1834,7 @@ bool QXmppIceComponentPrivate::addRemoteCandidate(const QXmppJingleCandidate &ca
fallbackPair = pair;
}
- qSort(pairs.begin(), pairs.end(), candidatePairPtrLessThan);
+ std::sort(pairs.begin(), pairs.end(), candidatePairPtrLessThan);
return true;
}
@@ -1845,7 +1845,7 @@ CandidatePair* QXmppIceComponentPrivate::findPair(QXmppStunTransaction *transact
if (pair->transaction == transaction)
return pair;
}
- return 0;
+ return nullptr;
}
void QXmppIceComponentPrivate::performCheck(CandidatePair *pair, bool nominate)
@@ -2029,7 +2029,7 @@ void QXmppIceComponent::close()
transport->disconnectFromHost();
d->turnAllocation->disconnectFromHost();
d->timer->stop();
- d->activePair = 0;
+ d->activePair = nullptr;
}
/// Starts ICE connectivity checks.
@@ -2047,7 +2047,7 @@ void QXmppIceComponent::connectToHost()
bool QXmppIceComponent::isConnected() const
{
- return d->activePair != 0;
+ return d->activePair != nullptr;
}
/// Returns the list of local candidates.
@@ -2082,7 +2082,7 @@ void QXmppIceComponent::handleDatagram(const QByteArray &buffer, const QHostAddr
}
// check if it's STUN
- QXmppStunTransaction *stunTransaction = 0;
+ QXmppStunTransaction *stunTransaction = nullptr;
foreach (QXmppStunTransaction *t, d->stunTransactions.keys()) {
if (t->request().id() == messageId &&
d->stunTransactions.value(t) == transport) {
@@ -2125,7 +2125,7 @@ void QXmppIceComponent::handleDatagram(const QByteArray &buffer, const QHostAddr
}
// process message from peer
- CandidatePair *pair = 0;
+ CandidatePair *pair = nullptr;
if (message.messageClass() == QXmppStunMessage::Request)
{
// check for role conflict
@@ -2184,7 +2184,7 @@ void QXmppIceComponent::handleDatagram(const QByteArray &buffer, const QHostAddr
pair->transport = transport;
d->pairs << pair;
- qSort(d->pairs.begin(), d->pairs.end(), candidatePairPtrLessThan);
+ std::sort(d->pairs.begin(), d->pairs.end(), candidatePairPtrLessThan);
}
switch (pair->state()) {
@@ -2238,7 +2238,7 @@ void QXmppIceComponent::handleDatagram(const QByteArray &buffer, const QHostAddr
if (!d->activePair || pair->priority() > d->activePair->priority()) {
info(QString("ICE pair selected %1 (priority: %2)").arg(
pair->toString(), QString::number(pair->priority())));
- const bool wasConnected = (d->activePair != 0);
+ const bool wasConnected = (d->activePair != nullptr);
d->activePair = pair;
if (!wasConnected)
emit connected();
@@ -2273,7 +2273,7 @@ void QXmppIceComponent::transactionFinished()
transaction->response().errorPhrase));
pair->setState(CandidatePair::FailedState);
}
- pair->transaction = 0;
+ pair->transaction = nullptr;
return;
}
@@ -2518,7 +2518,7 @@ public:
};
QXmppIceConnectionPrivate::QXmppIceConnectionPrivate()
- : connectTimer(NULL)
+ : connectTimer(nullptr)
, gatheringState(QXmppIceConnection::NewGatheringState)
, turnPort(0)
{
@@ -2621,7 +2621,7 @@ bool QXmppIceConnection::bind(const QList<QHostAddress> &addresses)
// assign sockets
QList<int> keys = d->components.keys();
- qSort(keys);
+ std::sort(keys.begin(), keys.end());
int s = 0;
foreach (int k, keys) {
d->components[k]->d->setSockets(sockets.mid(s, addresses.size()));
diff --git a/src/base/QXmppStun.h b/src/base/QXmppStun.h
index 973e1f90..4fa3e34b 100644
--- a/src/base/QXmppStun.h
+++ b/src/base/QXmppStun.h
@@ -113,7 +113,7 @@ public:
void setUsername(const QString &username);
QByteArray encode(const QByteArray &key = QByteArray(), bool addFingerprint = true) const;
- bool decode(const QByteArray &buffer, const QByteArray &key = QByteArray(), QStringList *errors = 0);
+ bool decode(const QByteArray &buffer, const QByteArray &key = QByteArray(), QStringList *errors = nullptr);
QString toString() const;
static quint16 peekType(const QByteArray &buffer, quint32 &cookie, QByteArray &id);
@@ -167,14 +167,14 @@ class QXMPP_EXPORT QXmppIceComponent : public QXmppLoggable
Q_OBJECT
public:
- ~QXmppIceComponent();
+ ~QXmppIceComponent() override;
int component() const;
bool isConnected() const;
QList<QXmppJingleCandidate> localCandidates() const;
static QList<QHostAddress> discoverAddresses();
- static QList<QUdpSocket*> reservePorts(const QList<QHostAddress> &addresses, int count, QObject *parent = 0);
+ static QList<QUdpSocket*> reservePorts(const QList<QHostAddress> &addresses, int count, QObject *parent = nullptr);
public slots:
void close();
@@ -203,7 +203,7 @@ signals:
void localCandidatesChanged();
private:
- QXmppIceComponent(int component, QXmppIcePrivate *config, QObject *parent=0);
+ QXmppIceComponent(int component, QXmppIcePrivate *config, QObject *parent=nullptr);
QXmppIceComponentPrivate *d;
friend class QXmppIceComponentPrivate;
@@ -252,8 +252,8 @@ public:
CompleteGatheringState
};
- QXmppIceConnection(QObject *parent = 0);
- ~QXmppIceConnection();
+ QXmppIceConnection(QObject *parent = nullptr);
+ ~QXmppIceConnection() override;
QXmppIceComponent *component(int component);
void addComponent(int component);
diff --git a/src/base/QXmppStun_p.h b/src/base/QXmppStun_p.h
index ea87234f..c3c8eb1d 100644
--- a/src/base/QXmppStun_p.h
+++ b/src/base/QXmppStun_p.h
@@ -77,8 +77,8 @@ class QXMPP_EXPORT QXmppIceTransport : public QXmppLoggable
Q_OBJECT
public:
- QXmppIceTransport(QObject *parent = 0);
- ~QXmppIceTransport();
+ QXmppIceTransport(QObject *parent = nullptr);
+ ~QXmppIceTransport() override;
virtual QXmppJingleCandidate localCandidate(int component) const = 0;
virtual qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port) = 0;
@@ -110,8 +110,8 @@ public:
ClosingState
};
- QXmppTurnAllocation(QObject *parent = 0);
- ~QXmppTurnAllocation();
+ QXmppTurnAllocation(QObject *parent = nullptr);
+ ~QXmppTurnAllocation() override;
QHostAddress relayedHost() const;
quint16 relayedPort() const;
@@ -121,8 +121,8 @@ public:
void setUser(const QString &user);
void setPassword(const QString &password);
- QXmppJingleCandidate localCandidate(int component) const;
- qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port);
+ QXmppJingleCandidate localCandidate(int component) const override;
+ qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port) override;
signals:
/// \brief This signal is emitted once TURN allocation succeeds.
@@ -133,7 +133,7 @@ signals:
public slots:
void connectToHost();
- void disconnectFromHost();
+ void disconnectFromHost() override;
private slots:
void readyRead();
@@ -180,14 +180,14 @@ class QXMPP_EXPORT QXmppUdpTransport : public QXmppIceTransport
Q_OBJECT
public:
- QXmppUdpTransport(QUdpSocket *socket, QObject *parent = 0);
- ~QXmppUdpTransport();
+ QXmppUdpTransport(QUdpSocket *socket, QObject *parent = nullptr);
+ ~QXmppUdpTransport() override;
- QXmppJingleCandidate localCandidate(int component) const;
- qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port);
+ QXmppJingleCandidate localCandidate(int component) const override;
+ qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port) override;
public slots:
- void disconnectFromHost();
+ void disconnectFromHost() override;
private slots:
void readyRead();
diff --git a/src/base/QXmppVCardIq.h b/src/base/QXmppVCardIq.h
index 26456d00..e0b9ec87 100644
--- a/src/base/QXmppVCardIq.h
+++ b/src/base/QXmppVCardIq.h
@@ -228,7 +228,7 @@ class QXMPP_EXPORT QXmppVCardIq : public QXmppIq
public:
QXmppVCardIq(const QString& bareJid = QString());
QXmppVCardIq(const QXmppVCardIq &other);
- ~QXmppVCardIq();
+ ~QXmppVCardIq() override;
QXmppVCardIq& operator=(const QXmppVCardIq &other);
@@ -283,8 +283,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement&);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement&) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/base/QXmppVersionIq.h b/src/base/QXmppVersionIq.h
index 2d953a99..3f558165 100644
--- a/src/base/QXmppVersionIq.h
+++ b/src/base/QXmppVersionIq.h
@@ -49,8 +49,8 @@ public:
protected:
/// \cond
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
/// \endcond
private:
diff --git a/src/client/QXmppArchiveManager.h b/src/client/QXmppArchiveManager.h
index 6e365397..03fd1d91 100644
--- a/src/client/QXmppArchiveManager.h
+++ b/src/client/QXmppArchiveManager.h
@@ -63,8 +63,8 @@ public:
void retrieveCollection(const QString &jid, const QDateTime &start, int max);
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
diff --git a/src/client/QXmppBookmarkManager.cpp b/src/client/QXmppBookmarkManager.cpp
index 6fb72d73..0e8fdbf5 100644
--- a/src/client/QXmppBookmarkManager.cpp
+++ b/src/client/QXmppBookmarkManager.cpp
@@ -44,8 +44,8 @@ public:
static bool isPrivateStorageIq(const QDomElement &element);
protected:
- void parseElementFromChild(const QDomElement &element);
- void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parseElementFromChild(const QDomElement &element) override;
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const override;
private:
QXmppBookmarkSet m_bookmarks;
diff --git a/src/client/QXmppBookmarkManager.h b/src/client/QXmppBookmarkManager.h
index 94d60d74..71e2c1ae 100644
--- a/src/client/QXmppBookmarkManager.h
+++ b/src/client/QXmppBookmarkManager.h
@@ -41,14 +41,14 @@ class QXMPP_EXPORT QXmppBookmarkManager : public QXmppClientExtension
public:
QXmppBookmarkManager();
- ~QXmppBookmarkManager();
+ ~QXmppBookmarkManager() override;
bool areBookmarksReceived() const;
QXmppBookmarkSet bookmarks() const;
bool setBookmarks(const QXmppBookmarkSet &bookmarks);
/// \cond
- bool handleStanza(const QDomElement &stanza);
+ bool handleStanza(const QDomElement &stanza) override;
/// \endcond
signals:
@@ -57,7 +57,7 @@ signals:
protected:
/// \cond
- void setClient(QXmppClient* client);
+ void setClient(QXmppClient* client) override;
/// \endcond
private slots:
diff --git a/src/client/QXmppCallManager.cpp b/src/client/QXmppCallManager.cpp
index 2c35f439..0a1d490f 100644
--- a/src/client/QXmppCallManager.cpp
+++ b/src/client/QXmppCallManager.cpp
@@ -105,7 +105,7 @@ private:
QXmppCallPrivate::QXmppCallPrivate(QXmppCall *qq)
: direction(QXmppCall::IncomingDirection),
- manager(0),
+ manager(nullptr),
state(QXmppCall::ConnectingState),
sendVideo(false),
audioMode(QIODevice::NotOpen),
@@ -120,7 +120,7 @@ QXmppCallPrivate::Stream *QXmppCallPrivate::findStreamByMedia(const QString &med
foreach (Stream *stream, streams)
if (stream->media == media)
return stream;
- return 0;
+ return nullptr;
}
QXmppCallPrivate::Stream *QXmppCallPrivate::findStreamByName(const QString &name)
@@ -128,7 +128,7 @@ QXmppCallPrivate::Stream *QXmppCallPrivate::findStreamByName(const QString &name
foreach (Stream *stream, streams)
if (stream->name == name)
return stream;
- return 0;
+ return nullptr;
}
void QXmppCallPrivate::handleAck(const QXmppIq &ack)
@@ -297,7 +297,7 @@ QXmppCallPrivate::Stream *QXmppCallPrivate::createStream(const QString &media)
stream->media = media;
// RTP channel
- QObject *channelObject = 0;
+ QObject *channelObject = nullptr;
if (media == AUDIO_MEDIA) {
QXmppRtpAudioChannel *audioChannel = new QXmppRtpAudioChannel(q);
stream->channel = audioChannel;
@@ -309,7 +309,7 @@ QXmppCallPrivate::Stream *QXmppCallPrivate::createStream(const QString &media)
} else {
q->warning(QString("Unsupported media type %1").arg(media));
delete stream;
- return 0;
+ return nullptr;
}
// ICE connection
@@ -510,7 +510,7 @@ QXmppRtpAudioChannel *QXmppCall::audioChannel() const
if (stream)
return static_cast<QXmppRtpAudioChannel*>(stream->channel);
else
- return 0;
+ return nullptr;
}
/// Returns the audio mode.
@@ -529,7 +529,7 @@ QXmppRtpVideoChannel *QXmppCall::videoChannel() const
if (stream)
return static_cast<QXmppRtpVideoChannel*>(stream->channel);
else
- return 0;
+ return nullptr;
}
/// Returns the video mode.
@@ -574,7 +574,7 @@ void QXmppCall::localCandidatesChanged()
{
// find the stream
QXmppIceConnection *conn = qobject_cast<QXmppIceConnection*>(sender());
- QXmppCallPrivate::Stream *stream = 0;
+ QXmppCallPrivate::Stream *stream = nullptr;
foreach (QXmppCallPrivate::Stream *ptr, d->streams) {
if (ptr->connection == conn) {
stream = ptr;
@@ -704,7 +704,7 @@ QXmppCall *QXmppCallManagerPrivate::findCall(const QString &sid) const
foreach (QXmppCall *call, calls)
if (call->sid() == sid)
return call;
- return 0;
+ return nullptr;
}
QXmppCall *QXmppCallManagerPrivate::findCall(const QString &sid, QXmppCall::Direction direction) const
@@ -712,7 +712,7 @@ QXmppCall *QXmppCallManagerPrivate::findCall(const QString &sid, QXmppCall::Dire
foreach (QXmppCall *call, calls)
if (call->sid() == sid && call->direction() == direction)
return call;
- return 0;
+ return nullptr;
}
/// Constructs a QXmppCallManager object to handle incoming and outgoing
@@ -791,12 +791,12 @@ QXmppCall *QXmppCallManager::call(const QString &jid)
if (jid.isEmpty()) {
warning("Refusing to call an empty jid");
- return 0;
+ return nullptr;
}
if (jid == client()->configuration().jid()) {
warning("Refusing to call self");
- return 0;
+ return nullptr;
}
QXmppCall *call = new QXmppCall(jid, QXmppCall::OutgoingDirection, this);
diff --git a/src/client/QXmppCallManager.h b/src/client/QXmppCallManager.h
index 0399ba61..220bd31f 100644
--- a/src/client/QXmppCallManager.h
+++ b/src/client/QXmppCallManager.h
@@ -78,7 +78,7 @@ public:
FinishedState = 3 ///< The call is finished.
};
- ~QXmppCall();
+ ~QXmppCall() override;
QXmppCall::Direction direction() const;
QString jid() const;
@@ -163,15 +163,15 @@ class QXMPP_EXPORT QXmppCallManager : public QXmppClientExtension
public:
QXmppCallManager();
- ~QXmppCallManager();
+ ~QXmppCallManager() override;
void setStunServer(const QHostAddress &host, quint16 port = 3478);
void setTurnServer(const QHostAddress &host, quint16 port = 3478);
void setTurnUser(const QString &user);
void setTurnPassword(const QString &password);
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
@@ -189,7 +189,7 @@ public slots:
protected:
/// \cond
- void setClient(QXmppClient* client);
+ void setClient(QXmppClient* client) override;
/// \endcond
private slots:
diff --git a/src/client/QXmppCarbonManager.h b/src/client/QXmppCarbonManager.h
index edc00f99..821c56df 100644
--- a/src/client/QXmppCarbonManager.h
+++ b/src/client/QXmppCarbonManager.h
@@ -43,14 +43,14 @@ class QXMPP_EXPORT QXmppCarbonManager : public QXmppClientExtension
public:
QXmppCarbonManager();
- ~QXmppCarbonManager();
+ ~QXmppCarbonManager() override;
bool carbonsEnabled() const;
void setCarbonsEnabled(bool enabled);
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
diff --git a/src/client/QXmppClient.cpp b/src/client/QXmppClient.cpp
index fe3ddf68..e5bd5473 100644
--- a/src/client/QXmppClient.cpp
+++ b/src/client/QXmppClient.cpp
@@ -66,11 +66,11 @@ private:
QXmppClientPrivate::QXmppClientPrivate(QXmppClient *qq)
: clientPresence(QXmppPresence::Available)
- , logger(0)
- , stream(0)
+ , logger(nullptr)
+ , stream(nullptr)
, receivedConflict(false)
, reconnectionTries(0)
- , reconnectionTimer(0)
+ , reconnectionTimer(nullptr)
, isActive(true)
, q(qq)
{
@@ -344,9 +344,12 @@ void QXmppClient::setActive(bool active)
}
/// Returns the reference to QXmppRosterManager object of the client.
+///
/// \return Reference to the roster object of the connected client. Use this to
/// get the list of friends in the roster and their presence information.
///
+/// \deprecated This method is deprecated since QXmpp 1.1. Use
+/// \c QXmppClient::findExtension<QXmppRosterManager>() instead.
QXmppRosterManager& QXmppClient::rosterManager()
{
@@ -461,6 +464,8 @@ QXmppStanza::Error::Condition QXmppClient::xmppStreamError()
/// Returns the reference to QXmppVCardManager, implementation of XEP-0054.
/// http://xmpp.org/extensions/xep-0054.html
///
+/// \deprecated This method is deprecated since QXmpp 1.1. Use
+/// \c QXmppClient::findExtension<QXmppVCardManager>() instead.
QXmppVCardManager& QXmppClient::vCardManager()
{
@@ -470,6 +475,8 @@ QXmppVCardManager& QXmppClient::vCardManager()
/// Returns the reference to QXmppVersionManager, implementation of XEP-0092.
/// http://xmpp.org/extensions/xep-0092.html
///
+/// \deprecated This method is deprecated since QXmpp 1.1. Use
+/// \c QXmppClient::findExtension<QXmppVersionManager>() instead.
QXmppVersionManager& QXmppClient::versionManager()
{
diff --git a/src/client/QXmppClient.h b/src/client/QXmppClient.h
index a3da7cf6..de4bb3d5 100644
--- a/src/client/QXmppClient.h
+++ b/src/client/QXmppClient.h
@@ -103,8 +103,8 @@ public:
ConnectedState ///< Connected to the server.
};
- QXmppClient(QObject *parent = 0);
- ~QXmppClient();
+ QXmppClient(QObject *parent = nullptr);
+ ~QXmppClient() override;
bool addExtension(QXmppClientExtension* extension);
bool insertExtension(int index, QXmppClientExtension* extension);
@@ -134,7 +134,7 @@ public:
if(extension)
return extension;
}
- return 0;
+ return nullptr;
}
bool isAuthenticated() const;
@@ -155,9 +155,16 @@ public:
State state() const;
QXmppStanza::Error::Condition xmppStreamError();
+#if QXMPP_DEPRECATED_SINCE(1, 1)
+ QT_DEPRECATED_X("Use QXmppClient::findExtension<QXmppRosterManager>() instead")
QXmppRosterManager& rosterManager();
+
+ QT_DEPRECATED_X("Use QXmppClient::findExtension<QXmppVCardManager>() instead")
QXmppVCardManager& vCardManager();
+
+ QT_DEPRECATED_X("Use QXmppClient::findExtension<QXmppVersionManager>() instead")
QXmppVersionManager& versionManager();
+#endif
signals:
diff --git a/src/client/QXmppClientExtension.cpp b/src/client/QXmppClientExtension.cpp
index 3c52415d..cd11f2d2 100644
--- a/src/client/QXmppClientExtension.cpp
+++ b/src/client/QXmppClientExtension.cpp
@@ -37,7 +37,7 @@ public:
QXmppClientExtension::QXmppClientExtension()
: d(new QXmppClientExtensionPrivate)
{
- d->client = 0;
+ d->client = nullptr;
}
/// Destroys a QXmppClient extension.
diff --git a/src/client/QXmppClientExtension.h b/src/client/QXmppClientExtension.h
index d2e94af9..9f777194 100644
--- a/src/client/QXmppClientExtension.h
+++ b/src/client/QXmppClientExtension.h
@@ -50,7 +50,7 @@ class QXMPP_EXPORT QXmppClientExtension : public QXmppLoggable
public:
QXmppClientExtension();
- virtual ~QXmppClientExtension();
+ ~QXmppClientExtension() override;
virtual QStringList discoveryFeatures() const;
virtual QList<QXmppDiscoveryIq::Identity> discoveryIdentities() const;
diff --git a/src/client/QXmppConfiguration.cpp b/src/client/QXmppConfiguration.cpp
index 817e8ee6..9b56b7c5 100644
--- a/src/client/QXmppConfiguration.cpp
+++ b/src/client/QXmppConfiguration.cpp
@@ -90,7 +90,6 @@ QXmppConfigurationPrivate::QXmppConfigurationPrivate()
, ignoreSslErrors(false)
, streamSecurityMode(QXmppConfiguration::TLSEnabled)
, nonSASLAuthMechanism(QXmppConfiguration::NonSASLDigest)
- , saslAuthMechanism("DIGEST-MD5")
{
}
@@ -501,8 +500,6 @@ void QXmppConfiguration::setNonSASLAuthMechanism(
}
/// Returns the preferred SASL authentication mechanism.
-///
-/// Default value: "DIGEST-MD5"
QString QXmppConfiguration::saslAuthMechanism() const
{
@@ -511,7 +508,8 @@ QString QXmppConfiguration::saslAuthMechanism() const
/// Sets the preferred SASL authentication \a mechanism.
///
-/// Valid values: "PLAIN", "DIGEST-MD5", "ANONYMOUS", "X-FACEBOOK-PLATFORM"
+/// Valid values: "SCRAM-SHA-256", "SCRAM-SHA-1", "DIGEST-MD5", "PLAIN", "ANONYMOUS",
+// "X-FACEBOOK-PLATFORM", "X-MESSENGER-OAUTH2", "X-OAUTH2"
void QXmppConfiguration::setSaslAuthMechanism(const QString &mechanism)
{
diff --git a/src/client/QXmppDiscoveryManager.h b/src/client/QXmppDiscoveryManager.h
index 16f3d0ac..33c8a660 100644
--- a/src/client/QXmppDiscoveryManager.h
+++ b/src/client/QXmppDiscoveryManager.h
@@ -41,7 +41,7 @@ class QXMPP_EXPORT QXmppDiscoveryManager : public QXmppClientExtension
public:
QXmppDiscoveryManager();
- ~QXmppDiscoveryManager();
+ ~QXmppDiscoveryManager() override;
QXmppDiscoveryIq capabilities();
@@ -65,8 +65,8 @@ public:
void setClientInfoForm(const QXmppDataForm &form);
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
diff --git a/src/client/QXmppEntityTimeManager.h b/src/client/QXmppEntityTimeManager.h
index 7d9e91a1..7f16cb17 100644
--- a/src/client/QXmppEntityTimeManager.h
+++ b/src/client/QXmppEntityTimeManager.h
@@ -42,8 +42,8 @@ public:
QString requestTime(const QString& jid);
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
diff --git a/src/client/QXmppInvokable.cpp b/src/client/QXmppInvokable.cpp
index a70378f4..91c646db 100644
--- a/src/client/QXmppInvokable.cpp
+++ b/src/client/QXmppInvokable.cpp
@@ -58,7 +58,7 @@ QVariant QXmppInvokable::dispatch( const QByteArray & method, const QList< QVari
const char *typeName = metaObject()->method(idx).typeName();
int resultType = QMetaType::type(typeName);
- void *result = QMetaType::create(resultType, 0);
+ void *result = QMetaType::create(resultType, nullptr);
QGenericReturnArgument ret( typeName, result );
QList<QGenericArgument> genericArgs;
diff --git a/src/client/QXmppInvokable.h b/src/client/QXmppInvokable.h
index 6edd511e..fbb52978 100644
--- a/src/client/QXmppInvokable.h
+++ b/src/client/QXmppInvokable.h
@@ -41,9 +41,9 @@ class QXMPP_EXPORT QXmppInvokable : public QObject
{
Q_OBJECT
public:
- QXmppInvokable( QObject *parent = 0 );
+ QXmppInvokable( QObject *parent = nullptr );
- ~QXmppInvokable();
+ ~QXmppInvokable() override;
/**
* Execute a method on an object. with a set of arguments. This method is reentrant, and the method
diff --git a/src/client/QXmppMamManager.h b/src/client/QXmppMamManager.h
index ca9aa816..c686c686 100644
--- a/src/client/QXmppMamManager.h
+++ b/src/client/QXmppMamManager.h
@@ -57,8 +57,8 @@ public:
const QXmppResultSetQuery &resultSetQuery = QXmppResultSetQuery());
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
diff --git a/src/client/QXmppMessageReceiptManager.cpp b/src/client/QXmppMessageReceiptManager.cpp
index 2abe32a6..c010eadf 100644
--- a/src/client/QXmppMessageReceiptManager.cpp
+++ b/src/client/QXmppMessageReceiptManager.cpp
@@ -29,6 +29,7 @@
#include "QXmppConstants_p.h"
#include "QXmppMessage.h"
#include "QXmppClient.h"
+#include "QXmppUtils.h"
/// Constructs a QXmppMessageReceiptManager to handle incoming and outgoing
/// message delivery receipts.
@@ -54,7 +55,12 @@ bool QXmppMessageReceiptManager::handleStanza(const QDomElement &stanza)
// Handle receipts and cancel any further processing.
if (!message.receiptId().isEmpty()) {
- emit messageDelivered(message.from(), message.receiptId());
+ // Buggy clients also mark carbon messages as received; to avoid this
+ // we check whether sender and receiver have the same bare JID.
+ if (QXmppUtils::jidToBareJid(message.from())
+ != QXmppUtils::jidToBareJid(message.to())) {
+ emit messageDelivered(message.from(), message.receiptId());
+ }
return true;
}
diff --git a/src/client/QXmppMessageReceiptManager.h b/src/client/QXmppMessageReceiptManager.h
index a7e5c36d..cef7ca27 100644
--- a/src/client/QXmppMessageReceiptManager.h
+++ b/src/client/QXmppMessageReceiptManager.h
@@ -40,8 +40,8 @@ public:
QXmppMessageReceiptManager();
/// \cond
- virtual QStringList discoveryFeatures() const;
- virtual bool handleStanza(const QDomElement &stanza);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &stanza) override;
/// \endcond
signals:
diff --git a/src/client/QXmppMucManager.h b/src/client/QXmppMucManager.h
index 58864d01..ca9ea1cb 100644
--- a/src/client/QXmppMucManager.h
+++ b/src/client/QXmppMucManager.h
@@ -63,14 +63,14 @@ class QXMPP_EXPORT QXmppMucManager : public QXmppClientExtension
public:
QXmppMucManager();
- ~QXmppMucManager();
+ ~QXmppMucManager() override;
QXmppMucRoom *addRoom(const QString &roomJid);
QList<QXmppMucRoom*> rooms() const;
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
@@ -82,7 +82,7 @@ signals:
protected:
/// \cond
- void setClient(QXmppClient* client);
+ void setClient(QXmppClient* client) override;
/// \endcond
private slots:
@@ -123,7 +123,7 @@ public:
};
Q_DECLARE_FLAGS(Actions, Action)
- ~QXmppMucRoom();
+ ~QXmppMucRoom() override;
Actions allowedActions() const;
bool isJoined() const;
diff --git a/src/client/QXmppOutgoingClient.cpp b/src/client/QXmppOutgoingClient.cpp
index b9f01188..3e8b4034 100644
--- a/src/client/QXmppOutgoingClient.cpp
+++ b/src/client/QXmppOutgoingClient.cpp
@@ -25,6 +25,7 @@
#include <QCryptographicHash>
#include <QNetworkProxy>
#include <QSslSocket>
+#include <QSslConfiguration>
#include <QUrl>
#include <QDnsLookup>
@@ -124,14 +125,14 @@ QXmppOutgoingClientPrivate::QXmppOutgoingClientPrivate(QXmppOutgoingClient *qq)
, sessionAvailable(false)
, sessionStarted(false)
, isAuthenticated(false)
- , saslClient(0)
+ , saslClient(nullptr)
, streamManagementAvailable(false)
, canResume(false)
, isResuming(false)
, resumePort(0)
, clientStateIndicationEnabled(false)
- , pingTimer(0)
- , timeoutTimer(0)
+ , pingTimer(nullptr)
+ , timeoutTimer(nullptr)
, q(qq)
{
}
@@ -141,8 +142,11 @@ void QXmppOutgoingClientPrivate::connectToHost(const QString &host, quint16 port
q->info(QString("Connecting to %1:%2").arg(host, QString::number(port)));
// override CA certificates if requested
- if (!config.caCertificates().isEmpty())
- q->socket()->setCaCertificates(config.caCertificates());
+ if (!config.caCertificates().isEmpty()) {
+ QSslConfiguration newSslConfig;
+ newSslConfig.setCaCertificates(config.caCertificates());
+ q->socket()->setSslConfiguration(newSslConfig);
+ }
// respect proxy
q->socket()->setProxy(config.networkProxy());
@@ -358,7 +362,7 @@ void QXmppOutgoingClient::handleStart()
// reset authentication step
if (d->saslClient) {
delete d->saslClient;
- d->saslClient = 0;
+ d->saslClient = nullptr;
}
// reset session information
@@ -450,8 +454,12 @@ void QXmppOutgoingClient::handleStanza(const QDomElement &nodeRecv)
if (saslAvailable && configuration().useSASLAuthentication())
{
// supported and preferred SASL auth mechanisms
- QStringList supportedMechanisms = QXmppSaslClient::availableMechanisms();
const QString preferredMechanism = configuration().saslAuthMechanism();
+ QStringList supportedMechanisms = QXmppSaslClient::availableMechanisms();
+ if (supportedMechanisms.contains(preferredMechanism)) {
+ supportedMechanisms.removeAll(preferredMechanism);
+ supportedMechanisms.prepend(preferredMechanism);
+ }
if (configuration().facebookAppId().isEmpty() || configuration().facebookAccessToken().isEmpty())
supportedMechanisms.removeAll("X-FACEBOOK-PLATFORM");
if (configuration().windowsLiveAccessToken().isEmpty())
@@ -462,19 +470,16 @@ void QXmppOutgoingClient::handleStanza(const QDomElement &nodeRecv)
// determine SASL Authentication mechanism to use
QStringList commonMechanisms;
QString usedMechanism;
- foreach (const QString &mechanism, features.authMechanisms()) {
- if (supportedMechanisms.contains(mechanism))
+ foreach (const QString &mechanism, supportedMechanisms) {
+ if (features.authMechanisms().contains(mechanism))
commonMechanisms << mechanism;
}
if (commonMechanisms.isEmpty()) {
warning("No supported SASL Authentication mechanism available");
disconnectFromHost();
return;
- } else if (!commonMechanisms.contains(preferredMechanism)) {
- info(QString("Desired SASL Auth mechanism '%1' is not available, selecting first available one").arg(preferredMechanism));
- usedMechanism = commonMechanisms.first();
} else {
- usedMechanism = preferredMechanism;
+ usedMechanism = commonMechanisms.first();
}
d->saslClient = QXmppSaslClient::create(usedMechanism, this);
diff --git a/src/client/QXmppOutgoingClient.h b/src/client/QXmppOutgoingClient.h
index 961dee73..52dae4a1 100644
--- a/src/client/QXmppOutgoingClient.h
+++ b/src/client/QXmppOutgoingClient.h
@@ -50,11 +50,11 @@ class QXMPP_EXPORT QXmppOutgoingClient : public QXmppStream
public:
QXmppOutgoingClient(QObject *parent);
- ~QXmppOutgoingClient();
+ ~QXmppOutgoingClient() override;
void connectToHost();
bool isAuthenticated() const;
- bool isConnected() const;
+ bool isConnected() const override;
bool isClientStateIndicationEnabled() const;
QSslSocket *socket() const { return QXmppStream::socket(); };
@@ -84,13 +84,13 @@ signals:
protected:
/// \cond
// Overridable methods
- virtual void handleStart();
- virtual void handleStanza(const QDomElement &element);
- virtual void handleStream(const QDomElement &element);
+ void handleStart() override;
+ void handleStanza(const QDomElement &element) override;
+ void handleStream(const QDomElement &element) override;
/// \endcond
public slots:
- virtual void disconnectFromHost();
+ void disconnectFromHost() override;
private slots:
void _q_dnsLookupFinished();
diff --git a/src/client/QXmppRosterManager.h b/src/client/QXmppRosterManager.h
index 94750c1a..869b6b42 100644
--- a/src/client/QXmppRosterManager.h
+++ b/src/client/QXmppRosterManager.h
@@ -67,7 +67,7 @@ class QXMPP_EXPORT QXmppRosterManager : public QXmppClientExtension
public:
QXmppRosterManager(QXmppClient* stream);
- ~QXmppRosterManager();
+ ~QXmppRosterManager() override;
bool isRosterReceived() const;
QStringList getRosterBareJids() const;
@@ -80,7 +80,7 @@ public:
const QString& resource) const;
/// \cond
- bool handleStanza(const QDomElement &element);
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
public slots:
diff --git a/src/client/QXmppRpcManager.h b/src/client/QXmppRpcManager.h
index 864dbc1f..0d2afdf0 100644
--- a/src/client/QXmppRpcManager.h
+++ b/src/client/QXmppRpcManager.h
@@ -73,9 +73,9 @@ public:
const QVariant &arg10 = QVariant() );
/// \cond
- QStringList discoveryFeatures() const;
- virtual QList<QXmppDiscoveryIq::Identity> discoveryIdentities() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ QList<QXmppDiscoveryIq::Identity> discoveryIdentities() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
diff --git a/src/client/QXmppTransferManager.cpp b/src/client/QXmppTransferManager.cpp
index 7251b53c..309fe4bf 100644
--- a/src/client/QXmppTransferManager.cpp
+++ b/src/client/QXmppTransferManager.cpp
@@ -219,17 +219,17 @@ public:
QXmppTransferJobPrivate::QXmppTransferJobPrivate()
: blockSize(16384),
- client(0),
+ client(nullptr),
direction(QXmppTransferJob::IncomingDirection),
done(0),
error(QXmppTransferJob::NoError),
hash(QCryptographicHash::Md5),
- iodevice(0),
+ iodevice(nullptr),
method(QXmppTransferJob::NoMethod),
state(QXmppTransferJob::OfferState),
deviceIsOwn(false),
ibbSequence(0),
- socksSocket(0)
+ socksSocket(nullptr)
{
}
@@ -446,8 +446,8 @@ void QXmppTransferJob::terminate(QXmppTransferJob::Error cause)
/// \cond
QXmppTransferIncomingJob::QXmppTransferIncomingJob(const QString& jid, QXmppClient* client, QObject* parent)
: QXmppTransferJob(jid, IncomingDirection, client, parent)
- , m_candidateClient(0)
- , m_candidateTimer(0)
+ , m_candidateClient(nullptr)
+ , m_candidateTimer(nullptr)
{
}
@@ -551,9 +551,9 @@ void QXmppTransferIncomingJob::_q_candidateReady()
setState(QXmppTransferJob::TransferState);
d->socksSocket = m_candidateClient;
- m_candidateClient = 0;
+ m_candidateClient = nullptr;
m_candidateTimer->deleteLater();
- m_candidateTimer = 0;
+ m_candidateTimer = nullptr;
check = connect(d->socksSocket, SIGNAL(readyRead()),
this, SLOT(_q_receiveData()));
@@ -583,9 +583,9 @@ void QXmppTransferIncomingJob::_q_candidateDisconnected()
QString::number(m_candidateHost.port())));
m_candidateClient->deleteLater();
- m_candidateClient = 0;
+ m_candidateClient = nullptr;
m_candidateTimer->deleteLater();
- m_candidateTimer = 0;
+ m_candidateTimer = nullptr;
// try next host
connectToNextHost();
@@ -749,7 +749,7 @@ private:
QXmppTransferManagerPrivate::QXmppTransferManagerPrivate(QXmppTransferManager *qq)
: ibbBlockSize(4096)
, proxyOnly(false)
- , socksServer(0)
+ , socksServer(nullptr)
, supportedMethods(QXmppTransferJob::AnyMethod)
, q(qq)
{
@@ -762,7 +762,7 @@ QXmppTransferJob* QXmppTransferManagerPrivate::getJobByRequestId(QXmppTransferJo
job->d->jid == jid &&
job->d->requestId == id)
return job;
- return 0;
+ return nullptr;
}
QXmppTransferIncomingJob *QXmppTransferManagerPrivate::getIncomingJobByRequestId(const QString &jid, const QString &id)
@@ -777,7 +777,7 @@ QXmppTransferIncomingJob* QXmppTransferManagerPrivate::getIncomingJobBySid(const
job->d->jid == jid &&
job->d->sid == sid)
return static_cast<QXmppTransferIncomingJob*>(job);
- return 0;
+ return nullptr;
}
QXmppTransferOutgoingJob *QXmppTransferManagerPrivate::getOutgoingJobByRequestId(const QString &jid, const QString &id)
@@ -1298,7 +1298,7 @@ QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, const QStri
{
if (QXmppUtils::jidToResource(jid).isEmpty()) {
warning("The file recipient's JID must be a full JID");
- return 0;
+ return nullptr;
}
QFileInfo info(filePath);
@@ -1315,7 +1315,7 @@ QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, const QStri
{
warning(QString("Could not read from %1").arg(filePath));
delete device;
- device = 0;
+ device = nullptr;
}
// hash file
@@ -1356,7 +1356,7 @@ QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, QIODevice *
if (QXmppUtils::jidToResource(jid).isEmpty()) {
warning("The file recipient's JID must be a full JID");
- return 0;
+ return nullptr;
}
QXmppTransferOutgoingJob *job = new QXmppTransferOutgoingJob(jid, client(), this);
diff --git a/src/client/QXmppTransferManager.h b/src/client/QXmppTransferManager.h
index 3b571b18..8202ea91 100644
--- a/src/client/QXmppTransferManager.h
+++ b/src/client/QXmppTransferManager.h
@@ -134,7 +134,7 @@ public:
FinishedState = 3 ///< The transfer is finished.
};
- ~QXmppTransferJob();
+ ~QXmppTransferJob() override;
QXmppTransferJob::Direction direction() const;
QXmppTransferJob::Error error() const;
@@ -225,7 +225,7 @@ class QXMPP_EXPORT QXmppTransferManager : public QXmppClientExtension
public:
QXmppTransferManager();
- ~QXmppTransferManager();
+ ~QXmppTransferManager() override;
QString proxy() const;
void setProxy(const QString &proxyJid);
@@ -237,8 +237,8 @@ public:
void setSupportedMethods(QXmppTransferJob::Methods methods);
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
@@ -262,7 +262,7 @@ public slots:
protected:
/// \cond
- void setClient(QXmppClient* client);
+ void setClient(QXmppClient* client) override;
/// \endcond
private slots:
diff --git a/src/client/QXmppVCardManager.h b/src/client/QXmppVCardManager.h
index fcb16a7f..328fe4a0 100644
--- a/src/client/QXmppVCardManager.h
+++ b/src/client/QXmppVCardManager.h
@@ -59,7 +59,7 @@ class QXMPP_EXPORT QXmppVCardManager : public QXmppClientExtension
public:
QXmppVCardManager();
- ~QXmppVCardManager();
+ ~QXmppVCardManager() override;
QString requestVCard(const QString& bareJid = QString());
@@ -70,8 +70,8 @@ public:
bool isClientVCardReceived() const;
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
diff --git a/src/client/QXmppVersionManager.h b/src/client/QXmppVersionManager.h
index effaed17..eb992611 100644
--- a/src/client/QXmppVersionManager.h
+++ b/src/client/QXmppVersionManager.h
@@ -40,7 +40,7 @@ class QXMPP_EXPORT QXmppVersionManager : public QXmppClientExtension
public:
QXmppVersionManager();
- ~QXmppVersionManager();
+ ~QXmppVersionManager() override;
QString requestVersion(const QString& jid);
@@ -53,8 +53,8 @@ public:
QString clientOs() const;
/// \cond
- QStringList discoveryFeatures() const;
- bool handleStanza(const QDomElement &element);
+ QStringList discoveryFeatures() const override;
+ bool handleStanza(const QDomElement &element) override;
/// \endcond
signals:
diff --git a/src/server/QXmppDialback.h b/src/server/QXmppDialback.h
index f8da6aeb..5166df51 100644
--- a/src/server/QXmppDialback.h
+++ b/src/server/QXmppDialback.h
@@ -54,8 +54,8 @@ public:
void setType(const QString &type);
/// \cond
- void parse(const QDomElement &element);
- void toXml(QXmlStreamWriter *writer) const;
+ void parse(const QDomElement &element) override;
+ void toXml(QXmlStreamWriter *writer) const override;
static bool isDialback(const QDomElement &element);
/// \endcond
diff --git a/src/server/QXmppIncomingClient.cpp b/src/server/QXmppIncomingClient.cpp
index b1b95ec5..e563ef1c 100644
--- a/src/server/QXmppIncomingClient.cpp
+++ b/src/server/QXmppIncomingClient.cpp
@@ -58,9 +58,9 @@ private:
};
QXmppIncomingClientPrivate::QXmppIncomingClientPrivate(QXmppIncomingClient *qq)
- : idleTimer(0)
- , passwordChecker(0)
- , saslServer(0)
+ : idleTimer(nullptr)
+ , passwordChecker(nullptr)
+ , saslServer(nullptr)
, q(qq)
{
}
@@ -184,9 +184,9 @@ void QXmppIncomingClient::handleStream(const QDomElement &streamElement)
{
if (d->idleTimer->interval())
d->idleTimer->start();
- if (d->saslServer != 0) {
+ if (d->saslServer != nullptr) {
delete d->saslServer;
- d->saslServer = 0;
+ d->saslServer = nullptr;
}
// start stream
diff --git a/src/server/QXmppIncomingClient.h b/src/server/QXmppIncomingClient.h
index 9c1e4afd..374fabd4 100644
--- a/src/server/QXmppIncomingClient.h
+++ b/src/server/QXmppIncomingClient.h
@@ -41,10 +41,10 @@ class QXMPP_EXPORT QXmppIncomingClient : public QXmppStream
Q_OBJECT
public:
- QXmppIncomingClient(QSslSocket *socket, const QString &domain, QObject *parent = 0);
- ~QXmppIncomingClient();
+ QXmppIncomingClient(QSslSocket *socket, const QString &domain, QObject *parent = nullptr);
+ ~QXmppIncomingClient() override;
- bool isConnected() const;
+ bool isConnected() const override;
QString jid() const;
void setInactivityTimeout(int secs);
@@ -56,8 +56,8 @@ signals:
protected:
/// \cond
- void handleStream(const QDomElement &element);
- void handleStanza(const QDomElement &element);
+ void handleStream(const QDomElement &element) override;
+ void handleStanza(const QDomElement &element) override;
/// \endcond
private slots:
diff --git a/src/server/QXmppIncomingServer.h b/src/server/QXmppIncomingServer.h
index f0d1a54a..883d9f01 100644
--- a/src/server/QXmppIncomingServer.h
+++ b/src/server/QXmppIncomingServer.h
@@ -40,9 +40,9 @@ class QXMPP_EXPORT QXmppIncomingServer : public QXmppStream
public:
QXmppIncomingServer(QSslSocket *socket, const QString &domain, QObject *parent);
- ~QXmppIncomingServer();
+ ~QXmppIncomingServer() override;
- bool isConnected() const;
+ bool isConnected() const override;
QString localStreamId() const;
signals:
@@ -54,8 +54,8 @@ signals:
protected:
/// \cond
- void handleStanza(const QDomElement &stanzaElement);
- void handleStream(const QDomElement &streamElement);
+ void handleStanza(const QDomElement &stanzaElement) override;
+ void handleStream(const QDomElement &streamElement) override;
/// \endcond
private slots:
diff --git a/src/server/QXmppOutgoingServer.h b/src/server/QXmppOutgoingServer.h
index 690dff1a..139a2f22 100644
--- a/src/server/QXmppOutgoingServer.h
+++ b/src/server/QXmppOutgoingServer.h
@@ -43,9 +43,9 @@ class QXMPP_EXPORT QXmppOutgoingServer : public QXmppStream
public:
QXmppOutgoingServer(const QString &domain, QObject *parent);
- ~QXmppOutgoingServer();
+ ~QXmppOutgoingServer() override;
- bool isConnected() const;
+ bool isConnected() const override;
QString localStreamKey() const;
void setLocalStreamKey(const QString &key);
@@ -59,9 +59,9 @@ signals:
protected:
/// \cond
- void handleStart();
- void handleStream(const QDomElement &streamElement);
- void handleStanza(const QDomElement &stanzaElement);
+ void handleStart() override;
+ void handleStream(const QDomElement &streamElement) override;
+ void handleStanza(const QDomElement &stanzaElement) override;
/// \endcond
public slots:
diff --git a/src/server/QXmppPasswordChecker.h b/src/server/QXmppPasswordChecker.h
index f8cf16ef..2bdbc9c5 100644
--- a/src/server/QXmppPasswordChecker.h
+++ b/src/server/QXmppPasswordChecker.h
@@ -67,7 +67,7 @@ public:
TemporaryError
};
- QXmppPasswordReply(QObject *parent = 0);
+ QXmppPasswordReply(QObject *parent = nullptr);
QByteArray digest() const;
void setDigest(const QByteArray &digest);
diff --git a/src/server/QXmppServer.cpp b/src/server/QXmppServer.cpp
index 511b32a4..82bc5d37 100644
--- a/src/server/QXmppServer.cpp
+++ b/src/server/QXmppServer.cpp
@@ -111,8 +111,8 @@ private:
};
QXmppServerPrivate::QXmppServerPrivate(QXmppServer *qq)
- : logger(0),
- passwordChecker(0),
+ : logger(nullptr),
+ passwordChecker(nullptr),
loaded(false),
started(false),
q(qq)
@@ -166,7 +166,7 @@ bool QXmppServerPrivate::routeData(const QString &to, const QByteArray &data)
// if we did not find an outgoing server,
// we need to establish the S2S connection
- QXmppOutgoingServer *conn = new QXmppOutgoingServer(domain, 0);
+ QXmppOutgoingServer *conn = new QXmppOutgoingServer(domain, nullptr);
conn->setLocalStreamKey(QXmppUtils::generateStanzaHash().toLatin1());
conn->moveToThread(q->thread());
conn->setParent(q);
diff --git a/src/server/QXmppServer.h b/src/server/QXmppServer.h
index ef4f5a6e..2f9bca8e 100644
--- a/src/server/QXmppServer.h
+++ b/src/server/QXmppServer.h
@@ -62,8 +62,8 @@ class QXMPP_EXPORT QXmppServer : public QXmppLoggable
Q_PROPERTY(QXmppLogger* logger READ logger WRITE setLogger NOTIFY loggerChanged)
public:
- QXmppServer(QObject *parent = 0);
- ~QXmppServer();
+ QXmppServer(QObject *parent = nullptr);
+ ~QXmppServer() override;
void addExtension(QXmppServerExtension *extension);
QList<QXmppServerExtension*> extensions();
@@ -131,8 +131,8 @@ class QXMPP_EXPORT QXmppSslServer : public QTcpServer
Q_OBJECT
public:
- QXmppSslServer(QObject *parent = 0);
- ~QXmppSslServer();
+ QXmppSslServer(QObject *parent = nullptr);
+ ~QXmppSslServer() override;
void addCaCertificates(const QList<QSslCertificate> &certificates);
void setLocalCertificate(const QSslCertificate &certificate);
diff --git a/src/server/QXmppServerExtension.cpp b/src/server/QXmppServerExtension.cpp
index 3629f590..81a23b12 100644
--- a/src/server/QXmppServerExtension.cpp
+++ b/src/server/QXmppServerExtension.cpp
@@ -38,7 +38,7 @@ public:
QXmppServerExtension::QXmppServerExtension()
: d(new QXmppServerExtensionPrivate)
{
- d->server = 0;
+ d->server = nullptr;
}
QXmppServerExtension::~QXmppServerExtension()
diff --git a/src/server/QXmppServerExtension.h b/src/server/QXmppServerExtension.h
index ec9edb2a..bfdde5d8 100644
--- a/src/server/QXmppServerExtension.h
+++ b/src/server/QXmppServerExtension.h
@@ -51,7 +51,7 @@ class QXMPP_EXPORT QXmppServerExtension : public QXmppLoggable
public:
QXmppServerExtension();
- ~QXmppServerExtension();
+ ~QXmppServerExtension() override;
virtual QString extensionName() const;
virtual int extensionPriority() const;
diff --git a/src/server/QXmppServerPlugin.h b/src/server/QXmppServerPlugin.h
index a07e7ca8..73b10631 100644
--- a/src/server/QXmppServerPlugin.h
+++ b/src/server/QXmppServerPlugin.h
@@ -55,11 +55,11 @@ public:
/// Creates and returns the specified QXmppServerExtension.
///
/// \param key The key for the QXmppServerExtension.
- virtual QXmppServerExtension *create(const QString &key) = 0;
+ QXmppServerExtension *create(const QString &key) override = 0;
/// Returns the list of keys supported by this plugin.
///
- virtual QStringList keys() const = 0;
+ QStringList keys() const override = 0;
};
#endif
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index df125219..67ad4966 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -21,11 +21,15 @@ add_simple_test(qxmppcarbonmanager)
add_simple_test(qxmppdataform)
add_simple_test(qxmppdiscoveryiq)
add_simple_test(qxmppentitytimeiq)
+add_simple_test(qxmpphttpuploadiq)
add_simple_test(qxmppiceconnection)
add_simple_test(qxmppiq)
add_simple_test(qxmppjingleiq)
add_simple_test(qxmppmammanager)
+add_simple_test(qxmppmixitem)
add_simple_test(qxmppmessage)
+add_simple_test(qxmppmessagereceiptmanager)
+add_simple_test(qxmppmixiq)
add_simple_test(qxmppnonsaslauthiq)
add_simple_test(qxmpppresence)
add_simple_test(qxmpppubsubiq)
diff --git a/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp b/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp
index 66a9e431..d5542c8e 100644
--- a/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp
+++ b/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp
@@ -47,7 +47,7 @@ private:
void tst_QXmppCallManager::init()
{
- receiverCall = 0;
+ receiverCall = nullptr;
}
void tst_QXmppCallManager::acceptCall(QXmppCall *call)
diff --git a/tests/qxmpphttpuploadiq/tst_qxmpphttpuploadiq.cpp b/tests/qxmpphttpuploadiq/tst_qxmpphttpuploadiq.cpp
new file mode 100644
index 00000000..d88a113c
--- /dev/null
+++ b/tests/qxmpphttpuploadiq/tst_qxmpphttpuploadiq.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include <QObject>
+#include "QXmppHttpUploadIq.h"
+#include "util.h"
+
+class tst_QXmppHttpUploadIq : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testRequest();
+ void testIsRequest_data();
+ void testIsRequest();
+ void testSlot();
+ void testIsSlot_data();
+ void testIsSlot();
+};
+
+void tst_QXmppHttpUploadIq::testRequest()
+{
+ const QByteArray xml(
+ "<iq id=\"step_03\" "
+ "to=\"upload.montague.tld\" "
+ "from=\"romeo@montague.tld/garden\" "
+ "type=\"get\">"
+ "<request xmlns=\"urn:xmpp:http:upload:0\" "
+ "filename=\"très cool.jpg\" "
+ "size=\"23456\" "
+ "content-type=\"image/jpeg\"/>"
+ "</iq>"
+ );
+
+ QXmppHttpUploadRequestIq iq;
+ parsePacket(iq, xml);
+ QCOMPARE(iq.fileName(), QString("très cool.jpg"));
+ QCOMPARE(iq.size(), 23456);
+ QCOMPARE(iq.contentType().name(), QString("image/jpeg"));
+ serializePacket(iq, xml);
+
+ // test setters
+ iq.setFileName("icon.png");
+ QCOMPARE(iq.fileName(), QString("icon.png"));
+ iq.setSize(23421337);
+ QCOMPARE(iq.size(), 23421337);
+ iq.setContentType(QMimeDatabase().mimeTypeForName("image/png"));
+ QCOMPARE(iq.contentType().name(), QString("image/png"));
+}
+
+void tst_QXmppHttpUploadIq::testIsRequest_data()
+{
+ QTest::addColumn<QByteArray>("xml");
+ QTest::addColumn<bool>("isRequest");
+
+ QTest::newRow("wrong-stanza")
+ << QByteArray("<message><request xmlns=\"urn:xmpp:http:upload:0\"/></message>")
+ << false;
+ QTest::newRow("empty-iq")
+ << QByteArray("<iq/>")
+ << false;
+ QTest::newRow("wrong-ns")
+ << QByteArray("<iq><request xmlns=\"some:other:request\"/></iq>")
+ << false;
+ QTest::newRow("correct")
+ << QByteArray("<iq><request xmlns=\"urn:xmpp:http:upload:0\"/></iq>")
+ << true;
+}
+
+void tst_QXmppHttpUploadIq::testIsRequest()
+{
+ QFETCH(QByteArray, xml);
+ QFETCH(bool, isRequest);
+
+ QDomDocument doc;
+ QCOMPARE(doc.setContent(xml, true), true);
+ QCOMPARE(QXmppHttpUploadRequestIq::isHttpUploadRequestIq(doc.documentElement()), isRequest);
+}
+
+void tst_QXmppHttpUploadIq::testSlot()
+{
+ const QByteArray xml(
+ "<iq id=\"step_03\" "
+ "to=\"romeo@montague.tld/garden\" "
+ "from=\"upload.montague.tld\" "
+ "type=\"result\">"
+ "<slot xmlns=\"urn:xmpp:http:upload:0\">"
+ "<put url=\"https://upload.montague.tld/4a771ac1-f0b2-4a4a-970"
+ "0-f2a26fa2bb67/tr%C3%A8s%20cool.jpg\">"
+ "<header name=\"Authorization\">Basic Base64String==</header>"
+ "<header name=\"Cookie\">foo=bar; user=romeo</header>"
+ "</put>"
+ "<get url=\"https://download.montague.tld/4a771ac1-f0b2-4a4a-9"
+ "700-f2a26fa2bb67/tr%C3%A8s%20cool.jpg\"/>"
+ "</slot>"
+ "</iq>"
+ );
+
+ QXmppHttpUploadSlotIq iq;
+ parsePacket(iq, xml);
+ QCOMPARE(iq.putUrl(), QUrl("https://upload.montague.tld/4a771ac1-f0b2-4a4a"
+ "-9700-f2a26fa2bb67/tr%C3%A8s%20cool.jpg"));
+ QCOMPARE(iq.getUrl(), QUrl("https://download.montague.tld/4a771ac1-f0b2-4a"
+ "4a-9700-f2a26fa2bb67/tr%C3%A8s%20cool.jpg"));
+ QMap<QString, QString> headers;
+ headers["Authorization"] = "Basic Base64String==";
+ headers["Cookie"] = "foo=bar; user=romeo";
+ QCOMPARE(iq.putHeaders(), headers);
+ serializePacket(iq, xml);
+
+ // test setters
+ iq.setGetUrl(QUrl("https://dl.example.org/user/file"));
+ QCOMPARE(iq.getUrl(), QUrl("https://dl.example.org/user/file"));
+ iq.setPutUrl(QUrl("https://ul.example.org/user/file"));
+ QCOMPARE(iq.putUrl(), QUrl("https://ul.example.org/user/file"));
+ QMap<QString, QString> emptyMap;
+ iq.setPutHeaders(emptyMap);
+ QCOMPARE(iq.putHeaders(), emptyMap);
+
+}
+
+void tst_QXmppHttpUploadIq::testIsSlot_data()
+{
+ QTest::addColumn<QByteArray>("xml");
+ QTest::addColumn<bool>("isSlot");
+
+ QTest::newRow("wrong-stanza")
+ << QByteArray("<message><slot xmlns=\"urn:xmpp:http:upload:0\"/></message>")
+ << false;
+ QTest::newRow("empty-iq")
+ << QByteArray("<iq/>")
+ << false;
+ QTest::newRow("wrong-ns")
+ << QByteArray("<iq><slot xmlns=\"some:other:slot\"/></iq>")
+ << false;
+ QTest::newRow("correct")
+ << QByteArray("<iq><slot xmlns=\"urn:xmpp:http:upload:0\"/></iq>")
+ << true;
+}
+
+void tst_QXmppHttpUploadIq::testIsSlot()
+{
+ QFETCH(QByteArray, xml);
+ QFETCH(bool, isSlot);
+
+ QDomDocument doc;
+ QCOMPARE(doc.setContent(xml, true), true);
+ QCOMPARE(QXmppHttpUploadSlotIq::isHttpUploadSlotIq(doc.documentElement()), isSlot);
+}
+
+QTEST_MAIN(tst_QXmppHttpUploadIq)
+#include "tst_qxmpphttpuploadiq.moc"
diff --git a/tests/qxmppmessage/tst_qxmppmessage.cpp b/tests/qxmppmessage/tst_qxmppmessage.cpp
index 0218bb93..a57ffab2 100644
--- a/tests/qxmppmessage/tst_qxmppmessage.cpp
+++ b/tests/qxmppmessage/tst_qxmppmessage.cpp
@@ -48,6 +48,11 @@ private slots:
void testPrivateMessage();
void testOutOfBandUrl();
void testMessageCorrect();
+ void testMessageAttaching();
+ void testMix();
+ void testEme();
+ void testSpoiler();
+ void testProcessingHints();
};
void tst_QXmppMessage::testBasic_data()
@@ -111,6 +116,12 @@ void tst_QXmppMessage::testBasic()
QCOMPARE(message.isReceiptRequested(), false);
QCOMPARE(message.receiptId(), QString());
QCOMPARE(message.xhtml(), QString());
+ QCOMPARE(message.encryptionMethod(), QXmppMessage::NoEncryption);
+ QVERIFY(!message.isSpoiler());
+ QVERIFY(!message.hasHint(QXmppMessage::NoPermanentStore));
+ QVERIFY(!message.hasHint(QXmppMessage::NoStore));
+ QVERIFY(!message.hasHint(QXmppMessage::NoCopy));
+ QVERIFY(!message.hasHint(QXmppMessage::Store));
serializePacket(message, xml);
}
@@ -615,5 +626,178 @@ void tst_QXmppMessage::testMessageCorrect()
QCOMPARE(message.replaceId(), QString("someotherid"));
}
+void tst_QXmppMessage::testMessageAttaching()
+{
+ const QByteArray xml(
+ "<message to=\"foo@example.com/QXmpp\" from=\"bar@example.com/QXmpp\" type=\"normal\">"
+ "<body>This is the corrected version.</body>"
+ "<attach-to xmlns=\"urn:xmpp:message-attaching:1\" id=\"SD24VCzSYQ\"/>"
+ "</message>");
+
+ QXmppMessage message;
+ parsePacket(message, xml);
+ QCOMPARE(message.attachId(), QString("SD24VCzSYQ"));
+ serializePacket(message, xml);
+
+ message.setAttachId("someotherid");
+ QCOMPARE(message.attachId(), QString("someotherid"));
+}
+
+void tst_QXmppMessage::testMix()
+{
+ const QByteArray xml(
+ "<message to=\"hag66@shakespeare.example\" "
+ "from=\"coven@mix.shakespeare.example/123456\" "
+ "type=\"groupchat\">"
+ "<body>Harpier cries: 'tis time, 'tis time.</body>"
+ "<mix xmlns=\"urn:xmpp:mix:core:1\">"
+ "<jid>hag66@shakespeare.example</jid>"
+ "<nick>thirdwitch</nick>"
+ "</mix>"
+ "</message>"
+ );
+
+ QXmppMessage message;
+ parsePacket(message, xml);
+ serializePacket(message, xml);
+
+ QCOMPARE(message.mixUserJid(), QString("hag66@shakespeare.example"));
+ QCOMPARE(message.mixUserNick(), QString("thirdwitch"));
+
+ message.setMixUserJid("alexander@example.org");
+ QCOMPARE(message.mixUserJid(), QString("alexander@example.org"));
+ message.setMixUserNick("erik");
+ QCOMPARE(message.mixUserNick(), QString("erik"));
+}
+
+void tst_QXmppMessage::testEme()
+{
+ // test standard encryption: OMEMO
+ const QByteArray xmlOmemo(
+ "<message to=\"foo@example.com/QXmpp\" from=\"bar@example.com/QXmpp\" type=\"normal\">"
+ "<body>This message is encrypted with OMEMO, but your client doesn't seem to support that.</body>"
+ "<encryption xmlns=\"urn:xmpp:eme:0\" namespace=\"eu.siacs.conversations.axolotl\"/>"
+ "</message>");
+
+ QXmppMessage messageOmemo;
+ parsePacket(messageOmemo, xmlOmemo);
+ QCOMPARE(messageOmemo.encryptionMethodNs(), QString("eu.siacs.conversations.axolotl"));
+ QCOMPARE(messageOmemo.encryptionMethod(), QXmppMessage::OMEMO);
+ QCOMPARE(messageOmemo.encryptionName(), QString("OMEMO"));
+ serializePacket(messageOmemo, xmlOmemo);
+
+ // test custom encryption
+ const QByteArray xmlCustom(
+ "<message to=\"foo@example.com/QXmpp\" from=\"bar@example.com/QXmpp\" type=\"normal\">"
+ "<body>This message is encrypted with CustomCrypt, but your client doesn't seem to support that.</body>"
+ "<encryption xmlns=\"urn:xmpp:eme:0\" namespace=\"im:example:customcrypt:1\" name=\"CustomCrypt\"/>"
+ "</message>");
+
+ QXmppMessage messageCustom;
+ parsePacket(messageCustom, xmlCustom);
+ QCOMPARE(messageCustom.encryptionMethodNs(), QString("im:example:customcrypt:1"));
+ QCOMPARE(messageCustom.encryptionMethod(), QXmppMessage::UnknownEncryption);
+ QCOMPARE(messageCustom.encryptionName(), QString("CustomCrypt"));
+ serializePacket(messageCustom, xmlCustom);
+
+ // test setters/getters
+ QXmppMessage message;
+ message.setEncryptionMethod(QXmppMessage::LegacyOpenPGP);
+ QCOMPARE(message.encryptionMethod(), QXmppMessage::LegacyOpenPGP);
+ QCOMPARE(message.encryptionMethodNs(), QString("jabber:x:encrypted"));
+ QCOMPARE(message.encryptionName(), QString("Legacy OpenPGP"));
+
+ message.setEncryptionMethodNs("fancyorg:encryption:fancycrypt:0");
+ message.setEncryptionName("FancyCrypt");
+ QCOMPARE(message.encryptionMethod(), QXmppMessage::UnknownEncryption);
+ QCOMPARE(message.encryptionMethodNs(), QString("fancyorg:encryption:fancycrypt:0"));
+ QCOMPARE(message.encryptionName(), QString("FancyCrypt"));
+}
+
+void tst_QXmppMessage::testSpoiler()
+{
+ // test parsing with hint
+ const QByteArray xmlWithHint(
+ "<message to=\"foo@example.com/QXmpp\" from=\"bar@example.com/QXmpp\" type=\"normal\">"
+ "<body>And at the end of the story, both of them die! It is so tragic!</body>"
+ "<spoiler xmlns=\"urn:xmpp:spoiler:0\">Love story end</spoiler>"
+ "</message>");
+
+ QXmppMessage messageWithHint;
+ parsePacket(messageWithHint, xmlWithHint);
+ QVERIFY(messageWithHint.isSpoiler());
+ QCOMPARE(messageWithHint.spoilerHint(), QString("Love story end"));
+ serializePacket(messageWithHint, xmlWithHint);
+
+ // test parsing without hint
+ const QByteArray xmlWithoutHint(
+ "<message to=\"foo@example.com/QXmpp\" from=\"bar@example.com/QXmpp\" type=\"normal\">"
+ "<body>And at the end of the story, both of them die! It is so tragic!</body>"
+ "<spoiler xmlns=\"urn:xmpp:spoiler:0\"></spoiler>"
+ "</message>");
+
+ QXmppMessage messageWithoutHint;
+ parsePacket(messageWithoutHint, xmlWithoutHint);
+ QVERIFY(messageWithoutHint.isSpoiler());
+ QCOMPARE(messageWithoutHint.spoilerHint(), QString(""));
+ serializePacket(messageWithoutHint, xmlWithoutHint);
+
+ // test setters
+ QXmppMessage message;
+ message.setIsSpoiler(true);
+ QVERIFY(message.isSpoiler());
+
+ message.setIsSpoiler(false);
+ message.setSpoilerHint("test hint");
+ QCOMPARE(message.spoilerHint(), QString("test hint"));
+ QVERIFY(message.isSpoiler());
+}
+
+void tst_QXmppMessage::testProcessingHints()
+{
+ const QByteArray xml(
+ "<message to=\"juliet@capulet.lit/laptop\" "
+ "from=\"romeo@montague.lit/laptop\" "
+ "type=\"chat\">"
+ "<body>V unir avtug'f pybnx gb uvqr zr sebz gurve fvtug</body>"
+ "<no-permanent-store xmlns=\"urn:xmpp:hints\"/>"
+ "<no-store xmlns=\"urn:xmpp:hints\"/>"
+ "<no-copy xmlns=\"urn:xmpp:hints\"/>"
+ "<store xmlns=\"urn:xmpp:hints\"/>"
+ "</message>"
+ );
+
+ // test parsing
+ QXmppMessage message;
+ parsePacket(message, xml);
+ QVERIFY(message.hasHint(QXmppMessage::NoPermanentStore));
+ QVERIFY(message.hasHint(QXmppMessage::NoStore));
+ QVERIFY(message.hasHint(QXmppMessage::NoCopy));
+ QVERIFY(message.hasHint(QXmppMessage::Store));
+
+ // test serialization
+ QXmppMessage message2;
+ message2.setType(QXmppMessage::Chat);
+ message2.setFrom(QString("romeo@montague.lit/laptop"));
+ message2.setTo(QString("juliet@capulet.lit/laptop"));
+ message2.setBody(QString("V unir avtug'f pybnx gb uvqr zr sebz gurve fvtug"));
+ message2.addHint(QXmppMessage::NoPermanentStore);
+ message2.addHint(QXmppMessage::NoStore);
+ message2.addHint(QXmppMessage::NoCopy);
+ message2.addHint(QXmppMessage::Store);
+ serializePacket(message2, xml);
+
+ // test remove hint
+ message2.removeHint(QXmppMessage::NoCopy);
+ QVERIFY(!message2.hasHint(QXmppMessage::NoCopy));
+
+ // test remove all hints
+ message2.removeAllHints();
+ QVERIFY(!message2.hasHint(QXmppMessage::NoPermanentStore));
+ QVERIFY(!message2.hasHint(QXmppMessage::NoStore));
+ QVERIFY(!message2.hasHint(QXmppMessage::NoCopy));
+ QVERIFY(!message2.hasHint(QXmppMessage::Store));
+}
+
QTEST_MAIN(tst_QXmppMessage)
#include "tst_qxmppmessage.moc"
diff --git a/tests/qxmppmessagereceiptmanager/tst_qxmppmessagereceiptmanager.cpp b/tests/qxmppmessagereceiptmanager/tst_qxmppmessagereceiptmanager.cpp
new file mode 100644
index 00000000..ebcfd18c
--- /dev/null
+++ b/tests/qxmppmessagereceiptmanager/tst_qxmppmessagereceiptmanager.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Authors:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include <QObject>
+#include "QXmppClient.h"
+#include "QXmppMessageReceiptManager.h"
+#include "util.h"
+
+class tst_QXmppMessageReceiptManager : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void testReceipt_data();
+ void testReceipt();
+
+ void handleMessageDelivered(const QString&, const QString&)
+ {
+ m_messageDelivered = true;
+ }
+
+private:
+ QXmppMessageReceiptManager m_manager;
+ bool m_messageDelivered = false;
+};
+
+void tst_QXmppMessageReceiptManager::initTestCase()
+{
+ connect(&m_manager, &QXmppMessageReceiptManager::messageDelivered,
+ this, &tst_QXmppMessageReceiptManager::handleMessageDelivered);
+}
+
+void tst_QXmppMessageReceiptManager::testReceipt_data()
+{
+ QTest::addColumn<QByteArray>("xml");
+ QTest::addColumn<bool>("accept");
+
+ QTest::newRow("correct")
+ << QByteArray(
+ "<message id=\"bi29sg183b4v\" "
+ "to=\"northumberland@shakespeare.lit/westminster\" "
+ "from=\"kingrichard@royalty.england.lit/throne\" "
+ "type=\"normal\">"
+ "<received xmlns=\"urn:xmpp:receipts\" id=\"richard2-4.1.247\"/>"
+ "</message>"
+ )
+ << true;
+ QTest::newRow("from-to-equal")
+ << QByteArray(
+ "<message id=\"bi29sg183b4v\" "
+ "to=\"kingrichard@royalty.england.lit/westminster\" "
+ "from=\"kingrichard@royalty.england.lit/throne\" "
+ "type=\"normal\">"
+ "<received xmlns=\"urn:xmpp:receipts\" id=\"richard2-4.1.247\"/>"
+ "</message>"
+ )
+ << false;
+}
+
+void tst_QXmppMessageReceiptManager::testReceipt()
+{
+ m_messageDelivered = false;
+
+ QFETCH(QByteArray, xml);
+ QFETCH(bool, accept);
+
+ QDomDocument doc;
+ QCOMPARE(doc.setContent(xml, true), true);
+ QDomElement element = doc.documentElement();
+
+ QVERIFY(m_manager.handleStanza(element));
+ QCOMPARE(m_messageDelivered, accept);
+}
+
+QTEST_MAIN(tst_QXmppMessageReceiptManager)
+#include "tst_qxmppmessagereceiptmanager.moc"
diff --git a/tests/qxmppmixiq/tst_qxmppmixiq.cpp b/tests/qxmppmixiq/tst_qxmppmixiq.cpp
new file mode 100644
index 00000000..0eb52576
--- /dev/null
+++ b/tests/qxmppmixiq/tst_qxmppmixiq.cpp
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include <QObject>
+
+#include "QXmppMixIq.h"
+#include "util.h"
+
+Q_DECLARE_METATYPE(QXmppIq::Type);
+Q_DECLARE_METATYPE(QXmppMixIq::Type);
+
+class tst_QXmppMixIq : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testBase_data();
+ void testBase();
+ void testDefaults();
+ void testSetters();
+ void testIsMixIq();
+};
+
+void tst_QXmppMixIq::testBase_data()
+{
+ QByteArray joinC2sSetXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<client-join xmlns=\"urn:xmpp:mix:pam:1\" channel=\"coven@mix.shakespeare.example\">"
+ "<join xmlns=\"urn:xmpp:mix:core:1\">"
+ "<subscribe node=\"urn:xmpp:mix:nodes:messages\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:presence\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:participants\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:info\"/>"
+ "<nick>third witch</nick>"
+ "</join>"
+ "</client-join>"
+ "</iq>"
+ );
+ QByteArray joinS2sSetXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"coven@mix.shakespeare.example\" "
+ "from=\"hag66@shakespeare.example\" "
+ "type=\"set\">"
+ "<join xmlns=\"urn:xmpp:mix:core:1\">"
+ "<subscribe node=\"urn:xmpp:mix:nodes:messages\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:presence\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:participants\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:info\"/>"
+ "<nick>stpeter</nick>"
+ "</join>"
+ "</iq>"
+ );
+ QByteArray joinS2sResultXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"coven@mix.shakespeare.example\" "
+ "type=\"result\">"
+ "<join xmlns=\"urn:xmpp:mix:core:1\" jid=\"123456#coven@mix.shakespeare.example\">"
+ "<subscribe node=\"urn:xmpp:mix:nodes:messages\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:presence\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:participants\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:info\"/>"
+ "<nick>third witch</nick>"
+ "</join>"
+ "</iq>"
+ );
+ QByteArray joinC2sResultXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "from=\"hag66@shakespeare.example\" "
+ "type=\"result\">"
+ "<client-join xmlns=\"urn:xmpp:mix:pam:1\">"
+ "<join xmlns=\"urn:xmpp:mix:core:1\" "
+ "jid=\"123456#coven@mix.shakespeare.example\">"
+ "<subscribe node=\"urn:xmpp:mix:nodes:messages\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:presence\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:participants\"/>"
+ "<subscribe node=\"urn:xmpp:mix:nodes:info\"/>"
+ "</join>"
+ "</client-join>"
+ "</iq>"
+ );
+ QByteArray leaveC2sSetXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<client-leave xmlns=\"urn:xmpp:mix:pam:1\" channel=\"coven@mix.shakespeare.example\">"
+ "<leave xmlns=\"urn:xmpp:mix:core:1\"/>"
+ "</client-leave>"
+ "</iq>"
+ );
+ QByteArray leaveS2sSetXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"coven@mix.shakespeare.example\" "
+ "from=\"hag66@shakespeare.example\" "
+ "type=\"set\">"
+ "<leave xmlns=\"urn:xmpp:mix:core:1\"/>"
+ "</iq>"
+ );
+ QByteArray leaveS2sResultXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"coven@mix.shakespeare.example\" "
+ "type=\"result\">"
+ "<leave xmlns=\"urn:xmpp:mix:core:1\"/>"
+ "</iq>"
+ );
+ QByteArray leaveC2sResultXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "from=\"hag66@shakespeare.example\" "
+ "type=\"result\">"
+ "<client-leave xmlns=\"urn:xmpp:mix:pam:1\">"
+ "<leave xmlns=\"urn:xmpp:mix:core:1\"/>"
+ "</client-leave>"
+ "</iq>"
+ );
+ QByteArray updateSubscriptionSetXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<update-subscription xmlns=\"urn:xmpp:mix:core:1\">"
+ "<subscribe node=\"urn:xmpp:mix:nodes:messages\"/>"
+ "</update-subscription>"
+ "</iq>"
+ );
+ QByteArray updateSubscriptionResultXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "from=\"hag66@shakespeare.example\" "
+ "type=\"result\">"
+ "<update-subscription xmlns=\"urn:xmpp:mix:core:1\" jid=\"hag66@shakespeare.example\">"
+ "<subscribe node=\"urn:xmpp:mix:nodes:messages\"/>"
+ "</update-subscription>"
+ "</iq>"
+ );
+ QByteArray setNickSetXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<setnick xmlns=\"urn:xmpp:mix:core:1\">"
+ "<nick>thirdwitch</nick>"
+ "</setnick>"
+ "</iq>"
+ );
+ QByteArray setNickResultXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "from=\"hag66@shakespeare.example\" "
+ "type=\"result\">"
+ "<setnick xmlns=\"urn:xmpp:mix:core:1\">"
+ "<nick>thirdwitch</nick>"
+ "</setnick>"
+ "</iq>"
+ );
+ QByteArray createXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<create xmlns=\"urn:xmpp:mix:core:1\" channel=\"coven\"/>"
+ "</iq>"
+ );
+ QByteArray createWithoutNameXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<create xmlns=\"urn:xmpp:mix:core:1\"/>"
+ "</iq>"
+ );
+ QByteArray destroyXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<destroy xmlns=\"urn:xmpp:mix:core:1\" channel=\"coven\"/>"
+ "</iq>"
+ );
+ QByteArray emptyXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\"/>"
+ );
+
+ QStringList emptyNodes;
+ QStringList defaultNodes;
+ defaultNodes << "urn:xmpp:mix:nodes:messages" << "urn:xmpp:mix:nodes:presence"
+ << "urn:xmpp:mix:nodes:participants" << "urn:xmpp:mix:nodes:info";
+
+ QTest::addColumn<QByteArray>("xml");
+ QTest::addColumn<QXmppIq::Type>("type");
+ QTest::addColumn<QXmppMixIq::Type>("actionType");
+ QTest::addColumn<QString>("jid");
+ QTest::addColumn<QString>("channelName");
+ QTest::addColumn<QStringList>("nodes");
+ QTest::addColumn<QString>("nick");
+
+ QTest::newRow("join-c2s-set")
+ << joinC2sSetXml
+ << QXmppIq::Set
+ << QXmppMixIq::ClientJoin
+ << "coven@mix.shakespeare.example"
+ << ""
+ << defaultNodes
+ << "third witch";
+ QTest::newRow("join-s2s-set")
+ << joinS2sSetXml
+ << QXmppIq::Set
+ << QXmppMixIq::Join
+ << ""
+ << ""
+ << defaultNodes
+ << "stpeter";
+ QTest::newRow("join-s2s-result")
+ << joinS2sResultXml
+ << QXmppIq::Result
+ << QXmppMixIq::Join
+ << "123456#coven@mix.shakespeare.example"
+ << ""
+ << defaultNodes
+ << "third witch";
+ QTest::newRow("join-c2s-result")
+ << joinC2sResultXml
+ << QXmppIq::Result
+ << QXmppMixIq::ClientJoin
+ << "123456#coven@mix.shakespeare.example"
+ << ""
+ << defaultNodes
+ << "";
+ QTest::newRow("leave-c2s-set")
+ << leaveC2sSetXml
+ << QXmppIq::Set
+ << QXmppMixIq::ClientLeave
+ << "coven@mix.shakespeare.example"
+ << "" << emptyNodes << "";
+ QTest::newRow("leave-s2s-set")
+ << leaveS2sSetXml
+ << QXmppIq::Set
+ << QXmppMixIq::Leave
+ << "" << "" << emptyNodes << "";
+ QTest::newRow("leave-s2s-result")
+ << leaveS2sResultXml
+ << QXmppIq::Result
+ << QXmppMixIq::Leave
+ << "" << "" << emptyNodes << "";
+ QTest::newRow("leave-c2s-result")
+ << leaveC2sResultXml
+ << QXmppIq::Result
+ << QXmppMixIq::ClientLeave
+ << "" << "" << emptyNodes << "";
+ QTest::newRow("update-subscription-set")
+ << updateSubscriptionSetXml
+ << QXmppIq::Set
+ << QXmppMixIq::UpdateSubscription
+ << ""
+ << ""
+ << (QStringList() << "urn:xmpp:mix:nodes:messages")
+ << "";
+ QTest::newRow("update-subscription-result")
+ << updateSubscriptionResultXml
+ << QXmppIq::Result
+ << QXmppMixIq::UpdateSubscription
+ << "hag66@shakespeare.example"
+ << ""
+ << (QStringList() << "urn:xmpp:mix:nodes:messages")
+ << "";
+ QTest::newRow("setnick-set")
+ << setNickSetXml
+ << QXmppIq::Set
+ << QXmppMixIq::SetNick
+ << "" << "" << emptyNodes
+ << "thirdwitch";
+ QTest::newRow("setnick-result")
+ << setNickResultXml
+ << QXmppIq::Result
+ << QXmppMixIq::SetNick
+ << "" << "" << emptyNodes
+ << "thirdwitch";
+ QTest::newRow("create")
+ << createXml
+ << QXmppIq::Set
+ << QXmppMixIq::Create
+ << "" << "coven" << emptyNodes << "";
+ QTest::newRow("create-without-name")
+ << createWithoutNameXml
+ << QXmppIq::Set
+ << QXmppMixIq::Create
+ << "" << "" << emptyNodes << "";
+ QTest::newRow("destroy")
+ << destroyXml
+ << QXmppIq::Set
+ << QXmppMixIq::Destroy
+ << "" << "coven" << emptyNodes << "";
+ QTest::newRow("empty")
+ << emptyXml
+ << QXmppIq::Set
+ << QXmppMixIq::None
+ << "" << "" << emptyNodes << "";
+}
+
+void tst_QXmppMixIq::testBase()
+{
+ QFETCH(QByteArray, xml);
+ QFETCH(QXmppIq::Type, type);
+ QFETCH(QXmppMixIq::Type, actionType);
+ QFETCH(QString, jid);
+ QFETCH(QString, channelName);
+ QFETCH(QStringList, nodes);
+ QFETCH(QString, nick);
+
+ QXmppMixIq iq;
+ parsePacket(iq, xml);
+ QCOMPARE(iq.type(), type);
+ QCOMPARE(iq.actionType(), actionType);
+ QCOMPARE(iq.jid(), jid);
+ QCOMPARE(iq.channelName(), channelName);
+ QCOMPARE(iq.nodes(), nodes);
+ QCOMPARE(iq.nick(), nick);
+ serializePacket(iq, xml);
+}
+
+void tst_QXmppMixIq::testDefaults()
+{
+ QXmppMixIq iq;
+ QCOMPARE(iq.actionType(), QXmppMixIq::None);
+ QCOMPARE(iq.jid(), QString());
+ QCOMPARE(iq.channelName(), QString());
+ QCOMPARE(iq.nodes(), QStringList());
+ QCOMPARE(iq.nick(), QString());
+}
+
+void tst_QXmppMixIq::testSetters()
+{
+ QXmppMixIq iq;
+ iq.setActionType(QXmppMixIq::Join);
+ QCOMPARE(iq.actionType(), QXmppMixIq::Join);
+ iq.setJid("interestingnews@mix.example.com");
+ QCOMPARE(iq.jid(), QString("interestingnews@mix.example.com"));
+ iq.setChannelName("interestingnews");
+ QCOMPARE(iq.channelName(), QString("interestingnews"));
+ iq.setNodes(QStringList() << "com:example:mix:node:custom");
+ QCOMPARE(iq.nodes(), QStringList() << "com:example:mix:node:custom");
+ iq.setNick("SMUDO");
+ QCOMPARE(iq.nick(), QString("SMUDO"));
+}
+
+void tst_QXmppMixIq::testIsMixIq()
+{
+ const QByteArray trueXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<destroy xmlns=\"urn:xmpp:mix:core:1\" channel=\"coven\"/>"
+ "</iq>"
+ );
+ const QByteArray truePamXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<client-leave xmlns=\"urn:xmpp:mix:pam:1\" channel=\"coven@mix.shakespeare.example\">"
+ "<leave xmlns=\"urn:xmpp:mix:core:1\"/>"
+ "</client-leave>"
+ "</iq>"
+ );
+ const QByteArray falseXml(
+ "<iq id=\"E6E10350-76CF-40C6-B91B-1EA08C332FC7\" "
+ "to=\"hag66@shakespeare.example\" "
+ "from=\"hag66@shakespeare.example/UUID-a1j/7533\" "
+ "type=\"set\">"
+ "<destroy xmlns=\"something:else\" channel=\"coven\"/>"
+ "</iq>"
+ );
+
+ QDomDocument doc;
+ doc.setContent(trueXml, true);
+ QDomElement trueElement = doc.documentElement();
+ QVERIFY(QXmppMixIq::isMixIq(trueElement));
+
+ doc.setContent(truePamXml, true);
+ QDomElement truePamElement = doc.documentElement();
+ QVERIFY(QXmppMixIq::isMixIq(truePamElement));
+
+ doc.setContent(falseXml, true);
+ QDomElement falseElement = doc.documentElement();
+ QVERIFY(!QXmppMixIq::isMixIq(falseElement));
+}
+
+QTEST_MAIN(tst_QXmppMixIq)
+#include "tst_qxmppmixiq.moc"
diff --git a/tests/qxmppmixitem/tst_qxmppmixitem.cpp b/tests/qxmppmixitem/tst_qxmppmixitem.cpp
new file mode 100644
index 00000000..e1d73744
--- /dev/null
+++ b/tests/qxmppmixitem/tst_qxmppmixitem.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2008-2019 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn <lnj@kaidan.im>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include <QObject>
+#include <QDomDocument>
+#include "QXmppMixItem.h"
+#include "QXmppPubSubIq.h"
+#include "util.h"
+
+class tst_QXmppMixItem : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testInfo();
+ void testIsInfoItem();
+ void testParticipant();
+ void testIsParticipantItem();
+};
+
+void tst_QXmppMixItem::testInfo()
+{
+ const QByteArray xml(
+ "<x xmlns=\"jabber:x:data\" type=\"result\">"
+ "<field type=\"hidden\" var=\"FORM_TYPE\">"
+ "<value>urn:xmpp:mix:core:1</value>"
+ "</field>"
+ "<field type=\"text-single\" var=\"Name\">"
+ "<value>Witches Coven</value>"
+ "</field>"
+ "<field type=\"text-single\" var=\"Description\">"
+ "<value>A location not far from the blasted heath where the "
+ "three witches meet</value>"
+ "</field>"
+ "<field type=\"jid-multi\" var=\"Contact\">"
+ "<value>greymalkin@shakespeare.example</value>"
+ "<value>joan@shakespeare.example</value>"
+ "</field>"
+ "</x>"
+ );
+
+ QXmppMixInfoItem item;
+ parsePacket(item, xml);
+
+ QCOMPARE(item.name(), QString("Witches Coven"));
+ QCOMPARE(item.description(), QString("A location not far from the blasted "
+ "heath where the three witches meet"));
+ QCOMPARE(item.contactJids(), QStringList() << "greymalkin@shakespeare.example"
+ << "joan@shakespeare.example");
+
+ QXmppElement element = item.toElement();
+ serializePacket(element, xml);
+
+ // test setters
+ item.setName("Skynet Development");
+ QCOMPARE(item.name(), QString("Skynet Development"));
+ item.setDescription("Very cool development group.");
+ QCOMPARE(item.description(), QString("Very cool development group."));
+ item.setContactJids(QStringList() << "somebody@example.org");
+ QCOMPARE(item.contactJids(), QStringList() << "somebody@example.org");
+}
+
+void tst_QXmppMixItem::testIsInfoItem()
+{
+ QDomDocument doc;
+ QDomElement element;
+
+ const QByteArray xmlCorrect(
+ "<x xmlns=\"jabber:x:data\" type=\"result\">"
+ "<field type=\"hidden\" var=\"FORM_TYPE\">"
+ "<value>urn:xmpp:mix:core:1</value>"
+ "</field>"
+ "</x>"
+ );
+ QCOMPARE(doc.setContent(xmlCorrect, true), true);
+ element = doc.documentElement();
+ QVERIFY(QXmppMixInfoItem::isMixChannelInfo(element));
+
+ const QByteArray xmlWrong(
+ "<x xmlns=\"jabber:x:data\" type=\"result\">"
+ "<field type=\"hidden\" var=\"FORM_TYPE\">"
+ "<value>other:namespace</value>"
+ "</field>"
+ "</x>"
+ );
+ QCOMPARE(doc.setContent(xmlWrong, true), true);
+ element = doc.documentElement();
+ QVERIFY(!QXmppMixInfoItem::isMixChannelInfo(element));
+}
+
+void tst_QXmppMixItem::testParticipant()
+{
+ const QByteArray xml(
+ "<participant xmlns=\"urn:xmpp:mix:core:1\">"
+ "<jid>hag66@shakespeare.example</jid>"
+ "<nick>thirdwitch</nick>"
+ "</participant>"
+ );
+
+ QXmppMixParticipantItem item;
+ parsePacket(item, xml);
+
+ QCOMPARE(item.nick(), QString("thirdwitch"));
+ QCOMPARE(item.jid(), QString("hag66@shakespeare.example"));
+
+ QXmppElement element = item.toElement();
+ serializePacket(element, xml);
+
+ // test setters
+ item.setNick("thomasd");
+ QCOMPARE(item.nick(), QString("thomasd"));
+ item.setJid("thomas@d.example");
+ QCOMPARE(item.jid(), QString("thomas@d.example"));
+}
+
+void tst_QXmppMixItem::testIsParticipantItem()
+{
+ QDomDocument doc;
+ QDomElement element;
+
+ const QByteArray xmlCorrect(
+ "<participant xmlns=\"urn:xmpp:mix:core:1\">"
+ "</participant>"
+ );
+ QCOMPARE(doc.setContent(xmlCorrect, true), true);
+ element = doc.documentElement();
+ QVERIFY(QXmppMixParticipantItem::isMixParticipantItem(element));
+
+ const QByteArray xmlWrong(
+ "<participant xmlns=\"other:namespace:1\">"
+ "</participant>"
+ );
+ QCOMPARE(doc.setContent(xmlWrong, true), true);
+ element = doc.documentElement();
+ QVERIFY(!QXmppMixParticipantItem::isMixParticipantItem(element));
+}
+
+QTEST_MAIN(tst_QXmppMixItem)
+#include "tst_qxmppmixitem.moc"
diff --git a/tests/qxmpppresence/tst_qxmpppresence.cpp b/tests/qxmpppresence/tst_qxmpppresence.cpp
index af144f26..4144467a 100644
--- a/tests/qxmpppresence/tst_qxmpppresence.cpp
+++ b/tests/qxmpppresence/tst_qxmpppresence.cpp
@@ -42,6 +42,7 @@ private slots:
void testPresenceWithMucPassword();
void testPresenceWithMucSupport();
void testPresenceWithLastUserInteraction();
+ void testPresenceWithMix();
};
void tst_QXmppPresence::testPresence_data()
@@ -254,5 +255,32 @@ void tst_QXmppPresence::testPresenceWithLastUserInteraction()
QCOMPARE(presence.lastUserInteraction(), another);
}
+void tst_QXmppPresence::testPresenceWithMix()
+{
+ const QByteArray xml(
+ "<presence to=\"hag99@shakespeare.example\" "
+ "from=\"123435#coven@mix.shakespeare.example/UUID-a1j/7533\">"
+ "<show>dnd</show>"
+ "<status>Making a Brew</status>"
+ "<mix xmlns=\"urn:xmpp:presence:0\">"
+ "<jid>hecate@shakespeare.example/UUID-x4r/2491</jid>"
+ "<nick>thirdwitch</nick>"
+ "</mix>"
+ "</presence>"
+ );
+
+ QXmppPresence presence;
+ parsePacket(presence, xml);
+
+ QCOMPARE(presence.mixUserJid(), QString("hecate@shakespeare.example/UUID-x4r/2491"));
+ QCOMPARE(presence.mixUserNick(), QString("thirdwitch"));
+ serializePacket(presence, xml);
+
+ presence.setMixUserJid("alexander@example.org");
+ QCOMPARE(presence.mixUserJid(), QString("alexander@example.org"));
+ presence.setMixUserNick("erik");
+ QCOMPARE(presence.mixUserNick(), QString("erik"));
+}
+
QTEST_MAIN(tst_QXmppPresence)
#include "tst_qxmpppresence.moc"
diff --git a/tests/qxmpprosteriq/tst_qxmpprosteriq.cpp b/tests/qxmpprosteriq/tst_qxmpprosteriq.cpp
index f8db1dea..33d511b5 100644
--- a/tests/qxmpprosteriq/tst_qxmpprosteriq.cpp
+++ b/tests/qxmpprosteriq/tst_qxmpprosteriq.cpp
@@ -34,6 +34,8 @@ private slots:
void testItem();
void testVersion_data();
void testVersion();
+ void testMixAnnotate();
+ void testMixChannel();
};
void tst_QXmppRosterIq::testItem_data()
@@ -114,5 +116,45 @@ void tst_QXmppRosterIq::testVersion()
serializePacket(iq, xml);
}
+void tst_QXmppRosterIq::testMixAnnotate()
+{
+ const QByteArray xml(
+ "<iq from=\"juliet@example.com/balcony\" "
+ "type=\"get\">"
+ "<query xmlns=\"jabber:iq:roster\">"
+ "<annotate xmlns=\"urn:xmpp:mix:roster:0\"/>"
+ "</query>"
+ "</iq>"
+ );
+
+ QXmppRosterIq iq;
+ parsePacket(iq, xml);
+ QCOMPARE(iq.mixAnnotate(), true);
+ serializePacket(iq, xml);
+
+ iq.setMixAnnotate(false);
+ QCOMPARE(iq.mixAnnotate(), false);
+}
+
+void tst_QXmppRosterIq::testMixChannel()
+{
+ const QByteArray xml(
+ "<item jid=\"balcony@example.net\">"
+ "<channel xmlns=\"urn:xmpp:mix:roster:0\" participant-id=\"123456\"/>"
+ "</item>"
+ );
+
+ QXmppRosterIq::Item item;
+ parsePacket(item, xml);
+ QCOMPARE(item.isMixChannel(), true);
+ QCOMPARE(item.mixParticipantId(), QString("123456"));
+ serializePacket(item, xml);
+
+ item.setIsMixChannel(false);
+ QCOMPARE(item.isMixChannel(), false);
+ item.setMixParticipantId("23a7n");
+ QCOMPARE(item.mixParticipantId(), QString("23a7n"));
+}
+
QTEST_MAIN(tst_QXmppRosterIq)
#include "tst_qxmpprosteriq.moc"
diff --git a/tests/qxmppsasl/tst_qxmppsasl.cpp b/tests/qxmppsasl/tst_qxmppsasl.cpp
index 3beabf00..1626c59f 100644
--- a/tests/qxmppsasl/tst_qxmppsasl.cpp
+++ b/tests/qxmppsasl/tst_qxmppsasl.cpp
@@ -49,6 +49,9 @@ private slots:
void testClientFacebook();
void testClientGoogle();
void testClientPlain();
+ void testClientScramSha1();
+ void testClientScramSha1_bad();
+ void testClientScramSha256();
void testClientWindowsLive();
// server
@@ -186,7 +189,7 @@ void tst_QXmppSasl::testSuccess()
void tst_QXmppSasl::testClientAvailableMechanisms()
{
- QCOMPARE(QXmppSaslClient::availableMechanisms(), QStringList() << "PLAIN" << "DIGEST-MD5" << "ANONYMOUS" << "X-FACEBOOK-PLATFORM" << "X-MESSENGER-OAUTH2" << "X-OAUTH2");
+ QCOMPARE(QXmppSaslClient::availableMechanisms(), QStringList() << "SCRAM-SHA-256" << "SCRAM-SHA-1" << "DIGEST-MD5" << "PLAIN" << "ANONYMOUS" << "X-FACEBOOK-PLATFORM" << "X-MESSENGER-OAUTH2" << "X-OAUTH2");
}
void tst_QXmppSasl::testClientBadMechanism()
@@ -316,6 +319,94 @@ void tst_QXmppSasl::testClientPlain()
delete client;
}
+void tst_QXmppSasl::testClientScramSha1()
+{
+ QXmppSaslDigestMd5::setNonce("fyko+d2lbbFgONRv9qkxdawL");
+
+ QXmppSaslClient *client = QXmppSaslClient::create("SCRAM-SHA-1");
+ QVERIFY(client != 0);
+ QCOMPARE(client->mechanism(), QLatin1String("SCRAM-SHA-1"));
+
+ client->setUsername("user");
+ client->setPassword("pencil");
+
+ // first step
+ QByteArray response;
+ QVERIFY(client->respond(QByteArray(), response));
+ QCOMPARE(response, QByteArray("n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL"));
+
+ // second step
+ QVERIFY(client->respond(QByteArray("r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096"), response));
+ QCOMPARE(response, QByteArray("c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts="));
+
+ // third step
+ QVERIFY(client->respond(QByteArray("v=rmF9pqV8S7suAoZWja4dJRkFsKQ"), response));
+ QCOMPARE(response, QByteArray());
+
+ // any further step is an error
+ QVERIFY(!client->respond(QByteArray(), response));
+
+ delete client;
+}
+
+void tst_QXmppSasl::testClientScramSha1_bad()
+{
+ QXmppSaslDigestMd5::setNonce("fyko+d2lbbFgONRv9qkxdawL");
+
+ QXmppSaslClient *client = QXmppSaslClient::create("SCRAM-SHA-1");
+ QVERIFY(client != 0);
+ QCOMPARE(client->mechanism(), QLatin1String("SCRAM-SHA-1"));
+
+ client->setUsername("user");
+ client->setPassword("pencil");
+
+ // first step
+ QByteArray response;
+ QVERIFY(client->respond(QByteArray(), response));
+ QCOMPARE(response, QByteArray("n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL"));
+
+ // no nonce
+ QVERIFY(!client->respond(QByteArray("s=QSXCR+Q6sek8bf92,i=4096"), response));
+
+ // no salt
+ QVERIFY(!client->respond(QByteArray("r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,i=4096"), response));
+
+ // no iterations
+ QVERIFY(!client->respond(QByteArray("r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92"), response));
+
+ delete client;
+}
+
+void tst_QXmppSasl::testClientScramSha256()
+{
+ QXmppSaslDigestMd5::setNonce("rOprNGfwEbeRWgbNEkqO");
+
+ QXmppSaslClient *client = QXmppSaslClient::create("SCRAM-SHA-256");
+ QVERIFY(client != 0);
+ QCOMPARE(client->mechanism(), QLatin1String("SCRAM-SHA-256"));
+
+ client->setUsername("user");
+ client->setPassword("pencil");
+
+ // first step
+ QByteArray response;
+ QVERIFY(client->respond(QByteArray(), response));
+ QCOMPARE(response, QByteArray("n,,n=user,r=rOprNGfwEbeRWgbNEkqO"));
+
+ // second step
+ QVERIFY(client->respond(QByteArray("r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096"), response));
+ QCOMPARE(response, QByteArray("c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ="));
+
+ // third step
+ QVERIFY(client->respond(QByteArray("v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4="), response));
+ QCOMPARE(response, QByteArray());
+
+ // any further step is an error
+ QVERIFY(!client->respond(QByteArray(), response));
+
+ delete client;
+}
+
void tst_QXmppSasl::testClientWindowsLive()
{
QXmppSaslClient *client = QXmppSaslClient::create("X-MESSENGER-OAUTH2");
diff --git a/tests/qxmppsocks/tst_qxmppsocks.cpp b/tests/qxmppsocks/tst_qxmppsocks.cpp
index 76bffbd4..2632c4c3 100644
--- a/tests/qxmppsocks/tst_qxmppsocks.cpp
+++ b/tests/qxmppsocks/tst_qxmppsocks.cpp
@@ -48,7 +48,7 @@ private:
void tst_QXmppSocks::init()
{
- m_connectionSocket = 0;
+ m_connectionSocket = nullptr;
m_connectionHostName = QString();
m_connectionPort = 0;
}
diff --git a/tests/qxmppstreamfeatures/tst_qxmppstreamfeatures.cpp b/tests/qxmppstreamfeatures/tst_qxmppstreamfeatures.cpp
index 4646d354..57932e89 100644
--- a/tests/qxmppstreamfeatures/tst_qxmppstreamfeatures.cpp
+++ b/tests/qxmppstreamfeatures/tst_qxmppstreamfeatures.cpp
@@ -30,7 +30,9 @@ class tst_QXmppStreamFeatures : public QObject
private slots:
void testEmpty();
+ void testRequired();
void testFull();
+ void testSetters();
};
void tst_QXmppStreamFeatures::testEmpty()
@@ -44,11 +46,27 @@ void tst_QXmppStreamFeatures::testEmpty()
QCOMPARE(features.nonSaslAuthMode(), QXmppStreamFeatures::Disabled);
QCOMPARE(features.tlsMode(), QXmppStreamFeatures::Disabled);
QCOMPARE(features.clientStateIndicationMode(), QXmppStreamFeatures::Disabled);
+ QCOMPARE(features.registerMode(), QXmppStreamFeatures::Disabled);
QCOMPARE(features.authMechanisms(), QStringList());
QCOMPARE(features.compressionMethods(), QStringList());
serializePacket(features, xml);
}
+void tst_QXmppStreamFeatures::testRequired()
+{
+ const QByteArray xml(
+ "<stream:features>"
+ "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">"
+ "<required/>"
+ "</starttls>"
+ "</stream:features>");
+
+ QXmppStreamFeatures features;
+ parsePacket(features, xml);
+ QCOMPARE(features.tlsMode(), QXmppStreamFeatures::Required);
+ serializePacket(features, xml);
+}
+
void tst_QXmppStreamFeatures::testFull()
{
const QByteArray xml("<stream:features>"
@@ -57,6 +75,7 @@ void tst_QXmppStreamFeatures::testFull()
"<auth xmlns=\"http://jabber.org/features/iq-auth\"/>"
"<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"
"<csi xmlns=\"urn:xmpp:csi:0\"/>"
+ "<register xmlns=\"http://jabber.org/features/iq-register\"/>"
"<compression xmlns=\"http://jabber.org/features/compress\"><method>zlib</method></compression>"
"<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"><mechanism>PLAIN</mechanism></mechanisms>"
"</stream:features>");
@@ -68,10 +87,35 @@ void tst_QXmppStreamFeatures::testFull()
QCOMPARE(features.nonSaslAuthMode(), QXmppStreamFeatures::Enabled);
QCOMPARE(features.tlsMode(), QXmppStreamFeatures::Enabled);
QCOMPARE(features.clientStateIndicationMode(), QXmppStreamFeatures::Enabled);
+ QCOMPARE(features.registerMode(), QXmppStreamFeatures::Enabled);
QCOMPARE(features.authMechanisms(), QStringList() << "PLAIN");
QCOMPARE(features.compressionMethods(), QStringList() << "zlib");
serializePacket(features, xml);
}
+void tst_QXmppStreamFeatures::testSetters()
+{
+ QXmppStreamFeatures features;
+ features.setBindMode(QXmppStreamFeatures::Enabled);
+ QCOMPARE(features.bindMode(), QXmppStreamFeatures::Enabled);
+ features.setSessionMode(QXmppStreamFeatures::Enabled);
+ QCOMPARE(features.sessionMode(), QXmppStreamFeatures::Enabled);
+ features.setNonSaslAuthMode(QXmppStreamFeatures::Enabled);
+ QCOMPARE(features.nonSaslAuthMode(), QXmppStreamFeatures::Enabled);
+ features.setTlsMode(QXmppStreamFeatures::Enabled);
+ QCOMPARE(features.tlsMode(), QXmppStreamFeatures::Enabled);
+ features.setClientStateIndicationMode(QXmppStreamFeatures::Enabled);
+ QCOMPARE(features.clientStateIndicationMode(), QXmppStreamFeatures::Enabled);
+ features.setClientStateIndicationMode(QXmppStreamFeatures::Enabled);
+ QCOMPARE(features.clientStateIndicationMode(), QXmppStreamFeatures::Enabled);
+ features.setRegisterMode(QXmppStreamFeatures::Enabled);
+ QCOMPARE(features.registerMode(), QXmppStreamFeatures::Enabled);
+
+ features.setAuthMechanisms(QStringList() << "custom-mechanism");
+ QCOMPARE(features.authMechanisms(), QStringList() << "custom-mechanism");
+ features.setCompressionMethods(QStringList() << "compression-methods");
+ QCOMPARE(features.compressionMethods(), QStringList() << "compression-methods");
+}
+
QTEST_MAIN(tst_QXmppStreamFeatures)
#include "tst_qxmppstreamfeatures.moc"
diff --git a/tests/qxmpptransfermanager/tst_qxmpptransfermanager.cpp b/tests/qxmpptransfermanager/tst_qxmpptransfermanager.cpp
index b34a73a1..3d1d6f00 100644
--- a/tests/qxmpptransfermanager/tst_qxmpptransfermanager.cpp
+++ b/tests/qxmpptransfermanager/tst_qxmpptransfermanager.cpp
@@ -51,7 +51,7 @@ void tst_QXmppTransferManager::init()
{
receiverBuffer.close();
receiverBuffer.setData(QByteArray());
- receiverJob = 0;
+ receiverJob = nullptr;
}
void tst_QXmppTransferManager::acceptFile(QXmppTransferJob *job)
diff --git a/tests/travis/build-and-test b/tests/travis/build-and-test
index f677f4a8..65972231 100755
--- a/tests/travis/build-and-test
+++ b/tests/travis/build-and-test
@@ -1,6 +1,7 @@
#!/bin/sh
set -e
+HOST_SYSTEM=$(uname -s)
CMAKE_ARGS="-DBUILD_TESTS:BOOL=True"
case "$CONFIG" in
@@ -15,7 +16,7 @@ case "$CONFIG" in
;;
esac
-if [ "$(uname -s)" = "Darwin" ]; then
+if [ $HOST_SYSTEM = "Darwin" ]; then
# pick up cmake files from homebrew
CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5"
else
@@ -33,7 +34,12 @@ fi
mkdir build
cd build
cmake .. $CMAKE_ARGS
-make
+
+if [ $HOST_SYSTEM = "Darwin" ]; then
+ make -k -j$(sysctl -n hw.logicalcpu)
+else
+ make -k -j$(nproc)
+fi
# run tests
make test
diff --git a/tests/util.h b/tests/util.h
index d0c55e89..91f59c61 100644
--- a/tests/util.h
+++ b/tests/util.h
@@ -57,7 +57,7 @@ public:
};
/// Retrieves the password for the given username.
- QXmppPasswordReply::Error getPassword(const QXmppPasswordRequest &request, QString &password)
+ QXmppPasswordReply::Error getPassword(const QXmppPasswordRequest &request, QString &password) override
{
if (m_credentials.contains(request.username()))
{
@@ -69,7 +69,7 @@ public:
};
/// Returns whether getPassword() is enabled.
- bool hasGetPassword() const
+ bool hasGetPassword() const override
{
return true;
};