diff options
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/QXmppArchiveManager.h | 6 | ||||
| -rw-r--r-- | src/client/QXmppAttentionManager.cpp | 296 | ||||
| -rw-r--r-- | src/client/QXmppAttentionManager.h | 68 | ||||
| -rw-r--r-- | src/client/QXmppClient.cpp | 2 | ||||
| -rw-r--r-- | src/client/QXmppClient.h | 13 | ||||
| -rw-r--r-- | src/client/QXmppOutgoingClient.cpp | 4 | ||||
| -rw-r--r-- | src/client/QXmppOutgoingClient.h | 3 |
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. |
