aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/QXmppArchiveManager.h6
-rw-r--r--src/client/QXmppAttentionManager.cpp296
-rw-r--r--src/client/QXmppAttentionManager.h68
-rw-r--r--src/client/QXmppClient.cpp2
-rw-r--r--src/client/QXmppClient.h13
-rw-r--r--src/client/QXmppOutgoingClient.cpp4
-rw-r--r--src/client/QXmppOutgoingClient.h3
7 files changed, 378 insertions, 14 deletions
diff --git a/src/client/QXmppArchiveManager.h b/src/client/QXmppArchiveManager.h
index 773d6fc3..ef1d7ea2 100644
--- a/src/client/QXmppArchiveManager.h
+++ b/src/client/QXmppArchiveManager.h
@@ -24,16 +24,12 @@
#ifndef QXMPPARCHIVEMANAGER_H
#define QXMPPARCHIVEMANAGER_H
+#include "QXmppArchiveIq.h"
#include "QXmppClientExtension.h"
#include "QXmppResultSet.h"
#include <QDateTime>
-class QXmppArchiveChat;
-class QXmppArchiveChatIq;
-class QXmppArchiveListIq;
-class QXmppArchivePrefIq;
-
/// \brief The QXmppArchiveManager class makes it possible to access message
/// archives as defined by \xep{0136}: Message Archiving.
///
diff --git a/src/client/QXmppAttentionManager.cpp b/src/client/QXmppAttentionManager.cpp
new file mode 100644
index 00000000..a4012ac7
--- /dev/null
+++ b/src/client/QXmppAttentionManager.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2008-2020 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn
+ *
+ * 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 "QXmppAttentionManager.h"
+
+// Qt
+#include <QTimer>
+// QXmpp
+#include "QXmppClient.h"
+#include "QXmppConstants_p.h"
+#include "QXmppMessage.h"
+#include "QXmppRosterManager.h"
+#include "QXmppUtils.h"
+
+///
+/// \class QXmppAttentionManager
+///
+/// \brief The QXmppAttentionManager class manages attention requests as defined
+/// by \xep{0224}: Attention.
+///
+/// The manager also does some checks, including rate limiting and checking
+/// whether the senders are trusted (aka. in the roster).
+///
+/// Rate limited messages are not emitted on the normal attentionRequested()
+/// signal and are sent on the attentionRequestRateLimited() signal instead.
+///
+/// To use this manager you still need to instantiate it and register it with
+/// the QXmppClient:
+///
+/// \code
+/// auto *attentionManager = new QXmppAttentionManager();
+/// client->addExtension(attentionManager);
+/// \endcode
+///
+/// \since QXmpp 1.4
+///
+
+///
+/// \fn QXmppAttentionManager::attentionRequested
+///
+/// This signal is emitted when an attention request was received and it passed
+/// the rate limiter.
+///
+/// \param message The message with the attention request that was received.
+/// \param isTrusted Whether the sender of the message exists in the user's
+/// roster.
+///
+
+///
+/// \fn QXmppAttentionManager::attentionRequestRateLimited
+///
+/// This signal is emitted when an attention request did not pass the rate
+/// limiter.
+///
+/// \param message The message with the attention request that did not pass the
+/// rate limiter.
+///
+
+struct PastRequest {
+ QString bareJid;
+ QDateTime timestamp;
+};
+
+class QXmppAttentionManagerPrivate : public QObject
+{
+public:
+ QXmppAttentionManagerPrivate(QXmppAttentionManager *parent, quint8 allowedAttempts, QTime timeFrame);
+
+ bool checkRateLimit(const QString &bareJid);
+ void cleanUp();
+
+ quint8 allowedAttempts;
+ QTime allowedAttemptsTimeInterval;
+
+ // map of bare JIDs and time of previous requests
+ QVector<PastRequest> previousRequests;
+ QTimer *cleanUpTimer;
+};
+
+///
+/// \brief QXmppAttentionManager::QXmppAttentionManager
+/// \param allowedAttempts
+/// \param timeFrame
+///
+QXmppAttentionManager::QXmppAttentionManager(quint8 allowedAttempts, QTime timeFrame)
+ : d(new QXmppAttentionManagerPrivate(this, allowedAttempts, timeFrame))
+{
+}
+
+///
+/// Destructor
+///
+QXmppAttentionManager::~QXmppAttentionManager()
+{
+ delete d;
+}
+
+///
+/// Returns the \xep{0224}: Attention feature.
+///
+QStringList QXmppAttentionManager::discoveryFeatures() const
+{
+ return {
+ ns_attention
+ };
+}
+
+///
+/// Returns the number of allowed attempts of attentions from a bare JID in the
+/// set time frame.
+///
+/// \sa setAllowedAttempts()
+/// \sa allowedAttemptsTimeInterval()
+/// \sa setAllowedAttemptsTimeInterval()
+///
+quint8 QXmppAttentionManager::allowedAttempts() const
+{
+ return d->allowedAttempts;
+}
+
+///
+/// Sets the number of allowed attempts of attentions from a bare JID in the set
+/// time frame.
+///
+/// \sa allowedAttempts()
+/// \sa allowedAttemptsTimeInterval()
+/// \sa setAllowedAttemptsTimeInterval()
+///
+void QXmppAttentionManager::setAllowedAttempts(quint8 allowedAttempts)
+{
+ d->allowedAttempts = allowedAttempts;
+}
+
+///
+/// Returns the time interval for the allowed attempts for rate limiting.
+///
+/// \sa setAllowedAttemptsTimeInterval()
+/// \sa allowedAttempts()
+/// \sa setAllowedAttemptsTimeInterval()
+///
+QTime QXmppAttentionManager::allowedAttemptsTimeInterval() const
+{
+ return d->allowedAttemptsTimeInterval;
+}
+
+///
+/// Returns the time interval for the allowed attempts for rate limiting.
+///
+/// \sa allowedAttemptsTimeInterval()
+/// \sa allowedAttempts()
+/// \sa setAllowedAttempts()
+///
+void QXmppAttentionManager::setAllowedAttemptsTimeInterval(QTime interval)
+{
+ d->allowedAttemptsTimeInterval = interval;
+}
+
+///
+/// Sends a message of type chat with an attention request to the specified JID.
+///
+/// \xep{0224} allows to include other elements with an attention request, but
+/// the QXmppAttentionManager has no method for this purpose. However, such a
+/// request can still be made manually.
+///
+/// \param jid The address to which the request should be sent.
+/// \param message The message body to include in the attention request.
+///
+/// \return The ID of the sent message, if sent successfully, a null string
+/// otherwise. In case an ID is returned, it also corresponds to the origin ID
+/// of the message as defined by \xep{0359}: Unique and Stable Stanza IDs.
+///
+QString QXmppAttentionManager::requestAttention(const QString &jid, const QString &message)
+{
+ QXmppMessage msg;
+ // The XEP recommends to use type headline, but the message body might still
+ // be of interest later, so we use type chat to allow caching.
+ msg.setType(QXmppMessage::Chat);
+ msg.setId(QXmppUtils::generateStanzaUuid());
+ msg.setOriginId(msg.id());
+ msg.setTo(jid);
+ msg.setBody(message);
+ msg.setAttentionRequested(true);
+
+ if (client()->sendPacket(msg))
+ return msg.id();
+ return {};
+}
+
+void QXmppAttentionManager::setClient(QXmppClient *client)
+{
+ QXmppClientExtension::setClient(client);
+
+ connect(client, &QXmppClient::messageReceived,
+ this, &QXmppAttentionManager::handleMessageReceived);
+}
+
+///
+/// Empty reimplementation
+///
+bool QXmppAttentionManager::handleStanza(const QDomElement &)
+{
+ return false;
+}
+
+void QXmppAttentionManager::handleMessageReceived(const QXmppMessage &message)
+{
+ if (!message.isAttentionRequested() || !message.stamp().isNull())
+ return;
+
+ const QString bareJid = QXmppUtils::jidToBareJid(message.from());
+
+ // ignore messages from our own bare JID (e.g. carbon or IM-NG message)
+ if (bareJid == client()->configuration().jidBare())
+ return;
+
+ // check rate limit
+ if (!d->checkRateLimit(bareJid)) {
+ emit attentionRequestRateLimited(message);
+ return;
+ }
+
+ bool isTrusted = false;
+ if (auto *rosterManager = client()->findExtension<QXmppRosterManager>()) {
+ isTrusted = rosterManager->getRosterBareJids().contains(bareJid);
+ }
+
+ emit attentionRequested(message, isTrusted);
+}
+
+QXmppAttentionManagerPrivate::QXmppAttentionManagerPrivate(QXmppAttentionManager *parent, quint8 allowedAttempts, QTime timeFrame)
+ : allowedAttempts(allowedAttempts),
+ allowedAttemptsTimeInterval(timeFrame),
+ cleanUpTimer(new QTimer(parent))
+{
+ QObject::connect(cleanUpTimer, &QTimer::timeout, [this]() {
+ cleanUp();
+ });
+}
+
+///
+/// Returns true if the request passes the rate limit.
+///
+bool QXmppAttentionManagerPrivate::checkRateLimit(const QString &bareJid)
+{
+ // add to request to cache
+ previousRequests << PastRequest { bareJid, QDateTime::currentDateTimeUtc() };
+
+ // start timer to remove request again
+ if (!cleanUpTimer->isActive())
+ cleanUpTimer->start(allowedAttemptsTimeInterval.msecsSinceStartOfDay());
+
+ // check whether there are too many requests
+ int count = std::count_if(previousRequests.cbegin(), previousRequests.cend(), [=](const PastRequest &request) {
+ return request.bareJid == bareJid;
+ });
+ return count <= allowedAttempts;
+}
+
+///
+/// Removes the first entry and reschedules the timer to remove the next.
+///
+void QXmppAttentionManagerPrivate::cleanUp()
+{
+ previousRequests.removeFirst();
+
+ if (!previousRequests.isEmpty()) {
+ // reschedule timer for next removal
+ int next = allowedAttemptsTimeInterval.msecsSinceStartOfDay() -
+ previousRequests.first().timestamp.msecsTo(QDateTime::currentDateTimeUtc());
+
+ if (next < 1)
+ cleanUp();
+ else
+ cleanUpTimer->start(next);
+ }
+}
diff --git a/src/client/QXmppAttentionManager.h b/src/client/QXmppAttentionManager.h
new file mode 100644
index 00000000..ddbf38be
--- /dev/null
+++ b/src/client/QXmppAttentionManager.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008-2020 The QXmpp developers
+ *
+ * Author:
+ * Linus Jahn
+ *
+ * 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 QXMPPATTENTIONMANAGER_H
+#define QXMPPATTENTIONMANAGER_H
+
+#include "QXmppClientExtension.h"
+
+#include <QTime>
+
+class QXmppAttentionManagerPrivate;
+class QXmppMessage;
+
+class QXMPP_EXPORT QXmppAttentionManager : public QXmppClientExtension
+{
+ Q_OBJECT
+
+public:
+ QXmppAttentionManager(quint8 allowedAttempts = 3, QTime timeFrame = QTime(0, 15, 0));
+ ~QXmppAttentionManager();
+
+ QStringList discoveryFeatures() const override;
+
+ quint8 allowedAttempts() const;
+ void setAllowedAttempts(quint8 allowedAttempts);
+
+ QTime allowedAttemptsTimeInterval() const;
+ void setAllowedAttemptsTimeInterval(QTime interval);
+
+public Q_SLOTS:
+ QString requestAttention(const QString &jid, const QString &message = {});
+
+Q_SIGNALS:
+ void attentionRequested(const QXmppMessage &message, bool isTrusted);
+ void attentionRequestRateLimited(const QXmppMessage &message);
+
+protected:
+ void setClient(QXmppClient *client) override;
+ bool handleStanza(const QDomElement &stanza) override;
+
+private Q_SLOTS:
+ void handleMessageReceived(const QXmppMessage &message);
+
+private:
+ QXmppAttentionManagerPrivate *const d;
+};
+
+#endif // QXMPPATTENTIONMANAGER_H
diff --git a/src/client/QXmppClient.cpp b/src/client/QXmppClient.cpp
index a377c55e..926a9463 100644
--- a/src/client/QXmppClient.cpp
+++ b/src/client/QXmppClient.cpp
@@ -86,8 +86,6 @@ QStringList QXmppClientPrivate::discoveryFeatures()
ns_capabilities,
// XEP-0199: XMPP Ping
ns_ping,
- // XEP-0224: Attention
- ns_attention,
// XEP-0249: Direct MUC Invitations
ns_conference,
// XEP-0308: Last Message Correction
diff --git a/src/client/QXmppClient.h b/src/client/QXmppClient.h
index 1f6f206b..02c580c3 100644
--- a/src/client/QXmppClient.h
+++ b/src/client/QXmppClient.h
@@ -30,8 +30,7 @@
#include <QAbstractSocket>
#include <QObject>
-
-class QSslError;
+#include <QSslError>
class QXmppClientExtension;
class QXmppClientPrivate;
@@ -261,10 +260,12 @@ Q_SIGNALS:
/// changes Busy, Idle, Invisible etc.
void presenceReceived(const QXmppPresence &presence);
- /// Notifies that an XMPP iq stanza is received. The QXmppIq
- /// parameter contains the details of the iq sent to this client.
- /// IQ stanzas provide a structured request-response mechanism. Roster
- /// management, setting-getting vCards etc is done using iq stanzas.
+ /// This signal is emitted when IQs of type result or error are received by
+ /// the client and no registered QXmppClientExtension could handle it.
+ ///
+ /// This is useful when it is only important to check whether the response
+ /// of an IQ was successful. However, the recommended way is still to use an
+ /// additional QXmppClientExtension for this kind of tasks.
void iqReceived(const QXmppIq &iq);
/// This signal is emitted to indicate that one or more SSL errors were
diff --git a/src/client/QXmppOutgoingClient.cpp b/src/client/QXmppOutgoingClient.cpp
index 058b629e..2a16b719 100644
--- a/src/client/QXmppOutgoingClient.cpp
+++ b/src/client/QXmppOutgoingClient.cpp
@@ -176,7 +176,11 @@ QXmppOutgoingClient::QXmppOutgoingClient(QObject *parent)
connect(socket, &QAbstractSocket::disconnected, this, &QXmppOutgoingClient::_q_socketDisconnected);
connect(socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), this, &QXmppOutgoingClient::socketSslErrors);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ connect(socket, &QSslSocket::errorOccurred, this, &QXmppOutgoingClient::socketError);
+#else
connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QSslSocket::error), this, &QXmppOutgoingClient::socketError);
+#endif
// DNS lookups
connect(&d->dns, &QDnsLookup::finished, this, &QXmppOutgoingClient::_q_dnsLookupFinished);
diff --git a/src/client/QXmppOutgoingClient.h b/src/client/QXmppOutgoingClient.h
index 623fb7b3..abb044f3 100644
--- a/src/client/QXmppOutgoingClient.h
+++ b/src/client/QXmppOutgoingClient.h
@@ -74,7 +74,8 @@ Q_SIGNALS:
/// This signal is emitted when a message is received.
void messageReceived(const QXmppMessage &);
- /// This signal is emitted when an IQ is received.
+ /// This signal is emitted when an IQ response (type result or error) has
+ /// been received that was not handled by elementReceived().
void iqReceived(const QXmppIq &);
/// This signal is emitted when SSL errors are encountered.