From 3efa970fce3482a1b46767c2b8d2cedb48077076 Mon Sep 17 00:00:00 2001 From: liuch Date: Fri, 12 Apr 2019 04:13:06 +0300 Subject: [PATCH 01/16] mam in progress --- include/iris/xmpp_carbons.h | 1 + src/xmpp/CMakeLists.txt | 4 + src/xmpp/xmpp-im/client.cpp | 18 ++- src/xmpp/xmpp-im/types.cpp | 58 ++++--- src/xmpp/xmpp-im/xmpp_carbons.cpp | 187 +++++++++++++++++++++ src/xmpp/xmpp-im/xmpp_carbons.h | 88 ++++++++++ src/xmpp/xmpp-im/xmpp_client.h | 4 + src/xmpp/xmpp-im/xmpp_forwarding.cpp | 233 +++++++++++++++++++++++++++ src/xmpp/xmpp-im/xmpp_forwarding.h | 90 +++++++++++ src/xmpp/xmpp-im/xmpp_message.h | 20 +-- src/xmpp/xmpp-im/xmpp_tasks.cpp | 221 +++++++++++++++---------- src/xmpp/xmpp-im/xmpp_tasks.h | 34 ++-- src/xmpp/xmpp.pri | 4 + 13 files changed, 829 insertions(+), 133 deletions(-) create mode 100644 include/iris/xmpp_carbons.h create mode 100644 src/xmpp/xmpp-im/xmpp_carbons.cpp create mode 100644 src/xmpp/xmpp-im/xmpp_carbons.h create mode 100644 src/xmpp/xmpp-im/xmpp_forwarding.cpp create mode 100644 src/xmpp/xmpp-im/xmpp_forwarding.h diff --git a/include/iris/xmpp_carbons.h b/include/iris/xmpp_carbons.h new file mode 100644 index 00000000..444f2293 --- /dev/null +++ b/include/iris/xmpp_carbons.h @@ -0,0 +1 @@ +#include "../../src/xmpp/xmpp-im/xmpp_carbons.h" diff --git a/src/xmpp/CMakeLists.txt b/src/xmpp/CMakeLists.txt index 593b5dc1..3ec1b6a9 100644 --- a/src/xmpp/CMakeLists.txt +++ b/src/xmpp/CMakeLists.txt @@ -26,9 +26,11 @@ set(HEADERS xmpp-im/xmpp_thumbs.h xmpp-im/xmpp_agentitem.h xmpp-im/xmpp_captcha.h + xmpp-im/xmpp_carbons.h xmpp-im/xmpp_chatstate.h xmpp-im/xmpp_discoitem.h xmpp-im/xmpp_features.h + xmpp-im/xmpp_forwarding.h xmpp-im/xmpp_htmlelement.h xmpp-im/xmpp_httpauthrequest.h xmpp-im/xmpp_liveroster.h @@ -113,9 +115,11 @@ set(SOURCES xmpp-im/xmpp_bitsofbinary.cpp xmpp-im/xmpp_bytestream.cpp xmpp-im/xmpp_caps.cpp + xmpp-im/xmpp_carbons.cpp xmpp-im/xmpp_discoinfotask.cpp xmpp-im/xmpp_discoitem.cpp xmpp-im/xmpp_ibb.cpp + xmpp-im/xmpp_forwarding.cpp xmpp-im/xmpp_serverinfomanager.cpp xmpp-im/xmpp_subsets.cpp xmpp-im/xmpp_task.cpp diff --git a/src/xmpp/xmpp-im/client.cpp b/src/xmpp/xmpp-im/client.cpp index d8573bfa..ad55ea17 100644 --- a/src/xmpp/xmpp-im/client.cpp +++ b/src/xmpp/xmpp-im/client.cpp @@ -79,6 +79,7 @@ #include "xmpp_bitsofbinary.h" #include "filetransfer.h" #include "xmpp_caps.h" +#include "xmpp_carbons.h" #include "xmpp_hash.h" #include "xmpp_serverinfomanager.h" #include "protocol.h" @@ -132,6 +133,7 @@ class Client::ClientPrivate LiveRoster roster; ResourceList resourceList; CapsManager *capsman = nullptr; + CarbonsManager *carbonsman = nullptr; S5BManager *s5bman = nullptr; Jingle::S5B::Manager *jingleS5BManager = nullptr; IBBManager *ibbman = nullptr; @@ -142,6 +144,7 @@ class Client::ClientPrivate Jingle::Manager *jingleManager = nullptr; QList groupChatList; EncryptionHandler *encryptionHandler = nullptr; + JT_PushMessage *pushMessage = nullptr; }; @@ -225,8 +228,9 @@ void Client::start(const QString &host, const QString &user, const QString &pass connect(pp, SIGNAL(subscription(Jid,QString,QString)), SLOT(ppSubscription(Jid,QString,QString))); connect(pp, SIGNAL(presence(Jid,Status)), SLOT(ppPresence(Jid,Status))); - JT_PushMessage *pm = new JT_PushMessage(rootTask(), d->encryptionHandler); - connect(pm, SIGNAL(message(Message)), SLOT(pmMessage(Message))); + d->pushMessage = new JT_PushMessage(rootTask(), d->encryptionHandler); + connect(d->pushMessage, SIGNAL(message(Message)), SLOT(pmMessage(Message))); + d->carbonsman = new CarbonsManager(d->pushMessage); JT_PushRoster *pr = new JT_PushRoster(rootTask()); connect(pr, SIGNAL(roster(Roster)), SLOT(prRoster(Roster))); @@ -286,6 +290,16 @@ ServerInfoManager *Client::serverInfoManager() const return d->serverInfoManager; } +CarbonsManager *Client::carbonsManager() const +{ + return d->carbonsman; +} + +JT_PushMessage *Client::pushMessage() const +{ + return d->pushMessage; +} + HttpFileUploadManager *Client::httpFileUploadManager() const { return d->httpFileUploadManager; diff --git a/src/xmpp/xmpp-im/types.cpp b/src/xmpp/xmpp-im/types.cpp index fff9eb0c..41c8a851 100644 --- a/src/xmpp/xmpp-im/types.cpp +++ b/src/xmpp/xmpp-im/types.cpp @@ -26,6 +26,8 @@ #include "xmpp_bitsofbinary.h" #include "xmpp_ibb.h" #include "xmpp_captcha.h" +#include "xmpp_forwarding.h" +#include "xmpp_carbons.h" #include "protocol.h" #include "xmpp/blake2/blake2qt.h" #define NS_XML "http://www.w3.org/XML/1998/namespace" @@ -1056,7 +1058,6 @@ class Message::Private : public QSharedData QMap htmlElements; QDomElement sxe; QList bobDataList; - Jid forwardedFrom; QList mucStatuses; QList mucInvites; @@ -1067,12 +1068,12 @@ class Message::Private : public QSharedData bool spooled = false, wasEncrypted = false; //XEP-0280 Message Carbons - bool isDisabledCarbons = false; - Message::CarbonDir carbonDir = Message::NoCarbon; // it's a forwarded message + bool carbonsPrivate = false; Message::ProcessingHints processingHints; QString replaceId; QString originId; // XEP-0359 Message::StanzaId stanzaId; // XEP-0359 + Forwarding forwarding; }; //! \brief Constructs Message with given Jid information. @@ -1611,34 +1612,51 @@ const IBBData& Message::ibbData() const return d->ibbData; } -void Message::setDisabledCarbons(bool disabled) +Jid Message::displayJid() const { - d->isDisabledCarbons = disabled; + switch (d->forwarding.type()) { + case Forwarding::ForwardedCarbonsSent: + return d->forwarding.message()->to(); + case Forwarding::ForwardedCarbonsReceived: + return d->forwarding.message()->from(); + default: + break; + } + return from(); } -bool Message::isDisabledCarbons() const +const Message &Message::displayMessage() const { - return d->isDisabledCarbons; + if (d->forwarding.isCarbons() && d->forwarding.message()) + return *d->forwarding.message(); + return *this; } -void Message::setCarbonDirection(Message::CarbonDir cd) +Message &Message::displayMessage() { - d->carbonDir = cd; + if (d->forwarding.isCarbons() && d->forwarding.message()) + return *d->forwarding.message(); + return *this; } -Message::CarbonDir Message::carbonDirection() const +void Message::setCarbonsPrivate(bool privare) { - return d->carbonDir; + d->carbonsPrivate = privare; } -void Message::setForwardedFrom(const Jid &jid) +bool Message::carbonsPrivate() const { - d->forwardedFrom = jid; + return d->carbonsPrivate; } -const Jid &Message::forwardedFrom() const +void Message::setForwarded(const Forwarding &frw) { - return d->forwardedFrom; + d->forwarding = frw; +} + +const Forwarding &Message::forwarded() const +{ + return d->forwarding; } bool Message::spooled() const @@ -1905,10 +1923,10 @@ Stanza Message::toStanza(Stream *stream) const } // Avoiding Carbons - if (isDisabledCarbons() || wasEncrypted()) { - QDomElement e = s.createElement("urn:xmpp:carbons:2","private"); - s.appendChild(e); + if (d->carbonsPrivate || d->wasEncrypted) { + s.appendChild(CarbonsManager::privateElement(stream->doc())); } + if (!d->replaceId.isEmpty()) { QDomElement e = s.createElement("urn:xmpp:message-correct:0", "replace"); e.setAttribute("id", d->replaceId); @@ -1945,6 +1963,10 @@ Stanza Message::toStanza(Stream *stream) const s.appendChild(e); } + // XEP-0297: Stanza Forwarding + if (d->forwarding.type() != Forwarding::ForwardedNone) + s.appendChild(d->forwarding.toXml(stream)); + return s; } diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp new file mode 100644 index 00000000..25c8dc4d --- /dev/null +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -0,0 +1,187 @@ +/* + * xmpp_carbons.cpp - Message Carbons (XEP-0280) + * Copyright (C) 2019 Aleksey Andreev + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include "xmpp_carbons.h" +#include "xmpp_xmlcommon.h" +#include "xmpp_message.h" +#include "xmpp_forwarding.h" + +using namespace XMPP; + +static const QLatin1String xmlns_carbons("urn:xmpp:carbons:2"); + +//---------------------------------------------------------------------------- +// JT_MessageCarbons +//---------------------------------------------------------------------------- +JT_MessageCarbons::JT_MessageCarbons(Task *parent) + : Task(parent) +{ +} + +void JT_MessageCarbons::enable() +{ + iq = createIQ(doc(), QLatin1String("set"), QString::null, id()); + QDomElement enable = doc()->createElement(QLatin1String("enable")); + enable.setAttribute(QLatin1String("xmlns"), xmlns_carbons); + iq.appendChild(enable); +} + +void JT_MessageCarbons::disable() +{ + iq = createIQ(doc(), QLatin1String("set"), QString::null, id()); + QDomElement disable = doc()->createElement(QLatin1String("disable")); + disable.setAttribute(QLatin1String("xmlns"), xmlns_carbons); + iq.appendChild(disable); +} + +void JT_MessageCarbons::onGo() +{ + if (!iq.isNull()) + send(iq); +} + +bool JT_MessageCarbons::take(const QDomElement &e) +{ + if (iqVerify(e, Jid(), id())) { + if (e.attribute(QLatin1String("type")) != QLatin1String("result")) + setError(e); + else + setSuccess(); + return true; + } + return false; +} + +//-------------------------------------------------- +// class CarbonsSubscriber +//-------------------------------------------------- + +bool CarbonsSubscriber::xmlEvent(const QDomElement &root, QDomElement &e, Client *client, int userData, bool nested) +{ + Q_UNUSED(root); + bool drop = false; + frw.setType(Forwarding::ForwardedNone); + if (!nested) { + Jid from(root.attribute(QLatin1String("from"))); + Jid to(root.attribute(QLatin1String("to"))); + if (from.resource().isEmpty() && from.compare(to, false)) { + QDomElement child = e.firstChildElement(); + while (!child.isNull()) { + if (frw.fromXml(child, client)) { + frw.setType(static_cast(userData)); + break; + } + child = child.nextSiblingElement(); + } + } + else + drop = true; + e = QDomElement(); + } + return drop; +} + +bool CarbonsSubscriber::messageEvent(Message &msg, int userData, bool nested) +{ + Q_UNUSED(userData) + if (!nested && frw.type() != Forwarding::ForwardedNone) { + msg.setForwarded(frw); + frw.setType(Forwarding::ForwardedNone); + } + return false; +} + +//-------------------------------------------------- +// class CarbonsManager +//-------------------------------------------------- + +class CarbonsManager::Private { +public: + void subscribe() { + push_m->subscribeXml(sbs.get(), QLatin1String("received"), xmlns_carbons, Forwarding::ForwardedCarbonsReceived); + push_m->subscribeXml(sbs.get(), QLatin1String("sent"), xmlns_carbons, Forwarding::ForwardedCarbonsSent); + push_m->subscribeMessage(sbs.get(), 0); + } + + void unsubscribe() { + push_m->unsubscribeXml(sbs.get(), QLatin1String("received"), xmlns_carbons); + push_m->unsubscribeXml(sbs.get(), QLatin1String("sent"), xmlns_carbons); + push_m->unsubscribeMessage(sbs.get()); + } + + JT_PushMessage *push_m; + std::unique_ptr sbs; + bool enable = false; +}; + +CarbonsManager::CarbonsManager(JT_PushMessage *push_m) + : QObject(push_m) + , d(new Private) +{ + d->push_m = push_m; + d->sbs.reset(new CarbonsSubscriber()); +} + +CarbonsManager::~CarbonsManager() +{ +// if (d->sbs.get()) +// d->unsubscribe(); +} + +QDomElement CarbonsManager::privateElement(QDomDocument &doc) +{ + return doc.createElementNS(xmlns_carbons, QLatin1String("private")); +} + +void CarbonsManager::setEnabled(bool enable) +{ + if (d->enable == enable) + return; + + if (enable) { + d->subscribe(); + JT_MessageCarbons *jt = new JT_MessageCarbons(d->push_m->client()->rootTask()); + connect(jt, &JT_MessageCarbons::finished, this, [=]() { + if (jt->success()) + d->enable = true; + else + d->unsubscribe(); + emit finished(); + }, Qt::QueuedConnection); + jt->enable(); + jt->go(true); + } + else if (d->sbs.get()) { + JT_MessageCarbons *jt = new JT_MessageCarbons(d->push_m->client()->rootTask()); + connect(jt, &JT_MessageCarbons::finished, this, [=]() { + d->enable = false; + d->unsubscribe(); + emit finished(); + }, Qt::QueuedConnection); + jt->disable(); + jt->go(true); + } +} + +bool CarbonsManager::isEnabled() const { + return d->enable; +} diff --git a/src/xmpp/xmpp-im/xmpp_carbons.h b/src/xmpp/xmpp-im/xmpp_carbons.h new file mode 100644 index 00000000..098caf6b --- /dev/null +++ b/src/xmpp/xmpp-im/xmpp_carbons.h @@ -0,0 +1,88 @@ +/* + * xmpp_carbons.h - Message Carbons (XEP-0280) + * Copyright (C) 2019 Aleksey Andreev + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef XMPP_CARBONS_H +#define XMPP_CARBONS_H + +#include +#include +#include + +#include "xmpp_task.h" +#include "xmpp_tasks.h" + + +namespace XMPP +{ + class Task; + class Client; + + class CarbonsSubscriber : public JT_PushMessage::Subscriber + { + public: + bool xmlEvent(const QDomElement &root, QDomElement &e, Client *client, int userData, bool nested) override; + bool messageEvent(Message &msg, int userData, bool nested) override; + + private: + Forwarding frw; + }; + + class CarbonsManager : public QObject + { + Q_OBJECT + + public: + CarbonsManager(JT_PushMessage *push_m); + CarbonsManager(const CarbonsManager &) = delete; + CarbonsManager & operator=(const CarbonsManager &) = delete; + ~CarbonsManager(); + + static QDomElement privateElement(QDomDocument &doc); + + void setEnabled(bool enable); + bool isEnabled() const; + + signals: + void finished(); + + private: + class Private; + std::unique_ptr d; + }; + + class JT_MessageCarbons : public Task + { + Q_OBJECT + + public: + JT_MessageCarbons(Task *parent); + + void enable(); + void disable(); + + void onGo(); + bool take(const QDomElement &e); + + private: + QDomElement iq; + }; +} + +#endif diff --git a/src/xmpp/xmpp-im/xmpp_client.h b/src/xmpp/xmpp-im/xmpp_client.h index 897d31cf..60c852f3 100644 --- a/src/xmpp/xmpp-im/xmpp_client.h +++ b/src/xmpp/xmpp-im/xmpp_client.h @@ -50,9 +50,11 @@ namespace XMPP { class Stream; class Task; class CapsManager; + class CarbonsManager; class EncryptionHandler; class ServerInfoManager; class HttpFileUploadManager; + class JT_PushMessage; namespace Jingle { class Manager; @@ -138,6 +140,8 @@ namespace XMPP BoBManager *bobManager() const; JidLinkManager *jidLinkManager() const; CapsManager *capsManager() const; + CarbonsManager *carbonsManager() const; + JT_PushMessage *pushMessage() const; ServerInfoManager *serverInfoManager() const; HttpFileUploadManager *httpFileUploadManager() const; Jingle::Manager* jingleManager() const; diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.cpp b/src/xmpp/xmpp-im/xmpp_forwarding.cpp new file mode 100644 index 00000000..4d7b77bd --- /dev/null +++ b/src/xmpp/xmpp-im/xmpp_forwarding.cpp @@ -0,0 +1,233 @@ +/* + * xmpp_forwarding.cpp - Stanza Forwarding (XEP-0297) + * Copyright (C) 2019 Aleksey Andreev + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "xmpp_forwarding.h" +#include "xmpp_xmlcommon.h" +#include "xmpp_tasks.h" +#include "xmpp_client.h" +#include "xmpp_stream.h" +#include "xmpp_message.h" + +using namespace XMPP; + +static const QLatin1String xmlns_forward("urn:xmpp:forward:0"); +static const QLatin1String xmlns_delay("urn:xmpp:delay"); + +//-------------------------------------------------- +// class Forwarding +//-------------------------------------------------- + +Forwarding::Forwarding() + : type_(ForwardedNone) +{ +} + +Forwarding::Forwarding(const Forwarding &other) + : type_(other.type_) + , ts_(other.ts_) +{ + if (other.msg_.get()) + msg_.reset(new Message(*other.msg_.get())); +} + +Forwarding::~Forwarding() +{ +} + +Forwarding & Forwarding::operator=(const Forwarding &from) +{ + type_ = from.type_; + ts_ = from.ts_; + if (from.msg_.get()) + msg_.reset(new Message(*from.msg_.get())); + else + msg_.reset(nullptr); + return *this; +} + +Forwarding::Type Forwarding::type() const +{ + return type_; +} +void Forwarding::setType(Type type) +{ + if (type_ != type) { + type_ = type; + if (type == ForwardedNone) { + ts_ = QDateTime(); + ts_.isNull(); + msg_.reset(nullptr); + } + } +} + +bool Forwarding::isCarbons() const +{ + return (type_ == ForwardedCarbonsSent || type_ == ForwardedCarbonsReceived); +} + +QDateTime Forwarding::timeStamp() const +{ + if (!ts_.isNull()) + return ts_; + return msg_.get() ? msg_->timeStamp() : QDateTime(); +} + +void Forwarding::setTimeStamp(QDateTime ts) +{ + ts_ = ts; +} + +Message *Forwarding::message() const +{ + return msg_.get(); +} + +void Forwarding::setMessage(const Message &msg) +{ + msg_.reset(new Message(msg)); +} + +bool Forwarding::fromXml(const QDomElement &e, Client *client) +{ + if (e.tagName() != QLatin1String("forwarded") || e.attribute(QLatin1String("xmlns")) != xmlns_forward) + return false; + + bool correct = false; + type_ = Forwarding::ForwardedNone; + QDomElement child = e.firstChildElement(); + while (!child.isNull()) { + if (child.tagName() == QLatin1String("message")) { + if (client->pushMessage()->processXmlSubscribers(child, client, true)) + break; + Stanza s = client->stream().createStanza(addCorrectNS(child)); + std::unique_ptr msg(new Message()); + if (msg->fromStanza(s, client->manualTimeZoneOffset(), client->timeZoneOffset())) { + if (client->pushMessage()->processMessageSubscribers(*msg.get(), true)) + break; + msg_ = std::move(msg); + type_ = ForwardedMessage; + correct = true; + } + } + else if (child.tagName() == QLatin1String("delay") && child.attribute(QLatin1String("xmlns")) == xmlns_delay) { + ts_ = QDateTime::fromString(child.attribute(QLatin1String("stamp")).left(19), Qt::ISODate); + } + child = child.nextSiblingElement(); + } + return correct; +} + +QDomElement Forwarding::toXml(Stream *stream) const +{ + if (type_ == ForwardedNone || !msg_.get()) + return QDomElement(); + + QDomElement e = stream->doc().createElement(QLatin1String("forwarded")); + e.setAttribute(QLatin1String("xmlns"), xmlns_forward); + if (ts_.isValid()) { + QDomElement delay = stream->doc().createElement(QLatin1String("delay")); + delay.setAttribute(QLatin1String("xmlns"), xmlns_delay); + delay.setAttribute(QLatin1String("stamp"), ts_.toUTC().toString(Qt::ISODate) + "Z"); + e.appendChild(delay); + } + e.appendChild(msg_->toStanza(stream).element()); + return e; +} + +//-------------------------------------------------- +// class ForwardingManager +//-------------------------------------------------- + +class ForwardingSubscriber : public JT_PushMessage::Subscriber { +public: + bool xmlEvent(const QDomElement &root, QDomElement &e, Client *c, int userData, bool nested) override { + Q_UNUSED(root) + Q_UNUSED(userData) + frw.setType(Forwarding::ForwardedNone); + if (!nested) { + Stanza stanza = c->stream().createStanza(e); + if (!stanza.isNull() && stanza.kind() == Stanza::Message) { + frw.fromXml(e, c); + } + } + return false; + } + + bool messageEvent(Message &msg, int userData, bool nested) override { + Q_UNUSED(userData) + if (!nested && frw.type() != Forwarding::ForwardedNone) { + msg.setForwarded(frw); + frw.setType(Forwarding::ForwardedNone); + } + return false; + } + +private: + Forwarding frw; +}; + +//-------------------------------------------------- +// class ForwardingManager +//-------------------------------------------------- + +class ForwardingManager::Private { +public: + JT_PushMessage *push_m; + std::unique_ptr sbs; + bool enabled = false; +}; + +ForwardingManager::ForwardingManager(JT_PushMessage *push_m) + : QObject(push_m) + , d(new Private) +{ + d->push_m = push_m; +} + +ForwardingManager::~ForwardingManager() +{ +// if (d->sbs.get()) { +// d->push_m->unsubscribeXml(d->sbs.get(), QLatin1String("forwarded"), xmlns_forward); +// d->push_m->unsubscribeMessage(d->sbs.get()); +// } +} + +void ForwardingManager::setEnabled(bool enabled) +{ + if (d->enabled == enabled) + return; + + if (enabled) { + d->sbs.reset(new ForwardingSubscriber()); + d->push_m->subscribeXml(d->sbs.get(), QLatin1String("forwarded"), xmlns_forward, 0); + d->push_m->subscribeMessage(d->sbs.get(), 0); + } + else { + d->push_m->unsubscribeXml(d->sbs.get(), QLatin1String("forwarded"), xmlns_forward); + d->push_m->unsubscribeMessage(d->sbs.get()); + d->sbs.release(); + } + d->enabled = enabled; +} + +bool ForwardingManager::isEnabled() const { + return d->enabled; +} diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.h b/src/xmpp/xmpp-im/xmpp_forwarding.h new file mode 100644 index 00000000..37f6dec9 --- /dev/null +++ b/src/xmpp/xmpp-im/xmpp_forwarding.h @@ -0,0 +1,90 @@ +/* + * xmpp_forwarding.h - Stanza Forwarding (XEP-0297) + * Copyright (C) 2019 Aleksey Andreev + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef XMPP_FORWARDING_H +#define XMPP_FORWARDING_H + +#include +#include +#include +#include + +namespace XMPP +{ + class Client; + class Stream; + class Message; + class JT_PushMessage; + + class Forwarding + { + public: + Forwarding(); + Forwarding(const Forwarding &); + ~Forwarding(); + + Forwarding & operator=(const Forwarding &); + + enum Type { + ForwardedNone, + ForwardedMessage, // XEP-0297 + ForwardedCarbonsReceived, // XEP-0280 + ForwardedCarbonsSent, // XEP-0280 + }; + Type type() const; + void setType(Type type); + bool isCarbons() const; + + QDateTime timeStamp() const; + void setTimeStamp(QDateTime ts); + + Message *message() const; + void setMessage(const Message &msg); + + bool fromXml(const QDomElement &e, Client *client); + QDomElement toXml(Stream *stream) const; + + private: + Type type_; + QDateTime ts_; + std::unique_ptr msg_; + }; + + class ForwardingManager : public QObject + { + Q_OBJECT + + public: + ForwardingManager(JT_PushMessage *push_m); + ForwardingManager(const ForwardingManager &) = delete; + ForwardingManager & operator=(const ForwardingManager &) = delete; + ~ForwardingManager(); + + void setEnabled(bool enabled); + bool isEnabled() const; + + private: + class Private; + std::unique_ptr d; + }; + +} + +#endif diff --git a/src/xmpp/xmpp-im/xmpp_message.h b/src/xmpp/xmpp-im/xmpp_message.h index 8a194d0e..695ac0b5 100644 --- a/src/xmpp/xmpp-im/xmpp_message.h +++ b/src/xmpp/xmpp-im/xmpp_message.h @@ -25,6 +25,7 @@ #include "xmpp_receipts.h" #include "xmpp_address.h" #include "xmpp_rosterx.h" +#include "xmpp_forwarding.h" #include "xmpp_muc.h" #include @@ -50,12 +51,6 @@ namespace XMPP { class Message { public: - enum CarbonDir : quint8 { - NoCarbon, - Received, // other party messages are sent to another own client - Sent // own messages are sent from other clients - }; - // XEP-0334 enum ProcessingHint { NoPermanentStore = 1, @@ -177,14 +172,15 @@ namespace XMPP { const IBBData& ibbData() const; // XEP-0280 Message Carbons - void setDisabledCarbons(bool disabled); - bool isDisabledCarbons() const; - void setCarbonDirection(CarbonDir); - CarbonDir carbonDirection() const; + Jid displayJid() const; + const Message &displayMessage() const; + Message &displayMessage(); + void setCarbonsPrivate(bool privare); + bool carbonsPrivate() const; // XEP-0297 - void setForwardedFrom(const Jid &jid); - const Jid &forwardedFrom() const; + void setForwarded(const Forwarding &frw); + const Forwarding &forwarded() const; // XEP-0308 QString replaceId() const; diff --git a/src/xmpp/xmpp-im/xmpp_tasks.cpp b/src/xmpp/xmpp-im/xmpp_tasks.cpp index aa569a6d..7f284692 100644 --- a/src/xmpp/xmpp-im/xmpp_tasks.cpp +++ b/src/xmpp/xmpp-im/xmpp_tasks.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "xmpp_tasks.h" @@ -891,19 +892,145 @@ void JT_Message::onGo() //---------------------------------------------------------------------------- class JT_PushMessage::Private { public: + struct SubsData { + Subscriber *sbs; + int userData; + }; EncryptionHandler *m_encryptionHandler; + QHash > subsData; + QList subsMData; + + QString genKey(const QString &s1, const QString &s2) + { + return QString("%1&%2").arg(s1).arg(s2); + } + + bool processXml(const QDomElement &root, QDomElement &e, Client *c, bool nested) + { + QString tagName = e.tagName(); + QString xmlnsStr = e.attribute(QLatin1String("xmlns")); + QString key = genKey(tagName, xmlnsStr); + if (subsData.contains(key)) { + QList sdl = subsData.value(key); + foreach (const SubsData &sd, sdl) { + if (sd.sbs->xmlEvent(root, e, c, sd.userData, nested)) + return true; + if (e.tagName() != tagName || e.attribute(QLatin1String("xmlns")) != tagName) + return false; + } + } + return false; + } + + bool processMessage(Message &msg, bool nested) { + foreach (const SubsData &sd, subsMData) { + if (sd.sbs->messageEvent(msg, sd.userData, nested)) + return true; + } + return false; + } }; +JT_PushMessage::Subscriber::~Subscriber() +{ +} + +bool JT_PushMessage::Subscriber::xmlEvent(const QDomElement &root, QDomElement &e, Client *c, int userData, bool nested) +{ + Q_UNUSED(root) + Q_UNUSED(e) + Q_UNUSED(c) + Q_UNUSED(userData) + Q_UNUSED(nested) + return false; +} + +bool JT_PushMessage::Subscriber::messageEvent(Message &msg, int userData, bool nested) +{ + Q_UNUSED(msg); + Q_UNUSED(userData); + Q_UNUSED(nested) + return false; +} + JT_PushMessage::JT_PushMessage(Task *parent, EncryptionHandler *encryptionHandler) -:Task(parent) + : Task(parent) + , d(new Private) { - d = new Private; d->m_encryptionHandler = encryptionHandler; } JT_PushMessage::~JT_PushMessage() { - delete d; +} + +void JT_PushMessage::subscribeXml(Subscriber *sbs, const QString &tagName, const QString &xmlnsStr, int userData) +{ + QString key = d->genKey(tagName, xmlnsStr); + QList list = d->subsData.value(key); + foreach (const Private::SubsData &sd, list) { + if (sd.sbs == sbs) + return; + } + list.append({ sbs, userData }); + d->subsData.insert(key, list); +} + +void JT_PushMessage::unsubscribeXml(Subscriber *sbs, const QString &tagName, const QString &xmlnsStr) +{ + QString key = d->genKey(tagName, xmlnsStr); + QList list = d->subsData.value(key); + for (int i = 0; i < list.count(); ++i) { + if (list.at(i).sbs == sbs) { + list.removeAt(i); + if (list.count() > 0) + d->subsData.insert(key, list); + else + d->subsData.remove(key); + break; + } + } +} + +void JT_PushMessage::subscribeMessage(Subscriber *sbs, int userData) +{ + foreach (const Private::SubsData &sd, d->subsMData) { + if (sd.sbs == sbs) + return; + } + d->subsMData.append({ sbs, userData }); +} + +void JT_PushMessage::unsubscribeMessage(Subscriber *sbs) +{ + int sz = d->subsMData.size(); + for (int i = 0; i < sz; ++i) { + if (d->subsMData.at(i).sbs == sbs) { + d->subsMData.removeAt(i); + break; + } + } +} + +bool JT_PushMessage::processXmlSubscribers(QDomElement &el, Client *client, bool nested) +{ + bool processed = false; + QDomElement ch = el.firstChildElement(); + while (!ch.isNull()) { + QDomElement next = ch.nextSiblingElement(); + bool res = d->processXml(el, ch, client, nested); + if (res) + processed = true; + if (res || ch.isNull()) + el.removeChild(ch); + ch = next; + } + return (processed && el.childNodes().length() == 0); +} + +bool JT_PushMessage::processMessageSubscribers(Message &msg, bool nested) +{ + return d->processMessage(msg, nested); } bool JT_PushMessage::take(const QDomElement &e) @@ -919,40 +1046,10 @@ bool JT_PushMessage::take(const QDomElement &e) return true; } - QDomElement forward; - Message::CarbonDir cd = Message::NoCarbon; - - Jid fromJid = Jid(e1.attribute(QLatin1String("from"))); - // Check for Carbon - QDomNodeList list = e1.childNodes(); - for (int i = 0; i < list.size(); ++i) { - QDomElement el = list.at(i).toElement(); - - if (el.attribute("xmlns") == QLatin1String("urn:xmpp:carbons:2") - && (el.tagName() == QLatin1String("received") || el.tagName() == QLatin1String("sent")) - && fromJid.compare(Jid(e1.attribute(QLatin1String("to"))), false)) { - QDomElement el1 = el.firstChildElement(); - if (el1.tagName() == QLatin1String("forwarded") - && el1.attribute(QLatin1String("xmlns")) == QLatin1String("urn:xmpp:forward:0")) { - QDomElement el2 = el1.firstChildElement(QLatin1String("message")); - if (!el2.isNull()) { - forward = el2; - cd = el.tagName() == QLatin1String("received")? Message::Received : Message::Sent; - break; - } - } - } - else if (el.tagName() == QLatin1String("forwarded") - && el.attribute(QLatin1String("xmlns")) == QLatin1String("urn:xmpp:forward:0")) { - forward = el.firstChildElement(QLatin1String("message")); // currently only messages are supportted - // TODO element support - if (!forward.isNull()) { - break; - } - } - } + if (processXmlSubscribers(e1, client(), false)) + return true; - Stanza s = client()->stream().createStanza(addCorrectNS(forward.isNull()? e1 : forward)); + Stanza s = client()->stream().createStanza(addCorrectNS(e1)); if(s.isNull()) { //printf("take: bad stanza??\n"); return false; @@ -963,10 +1060,10 @@ bool JT_PushMessage::take(const QDomElement &e) //printf("bad message\n"); return false; } - if (!forward.isNull()) { - m.setForwardedFrom(fromJid); - m.setCarbonDirection(cd); - } + + if (processMessageSubscribers(m, false)) + return true; + m.setWasEncrypted(wasEncrypted); emit message(m); @@ -2061,47 +2158,3 @@ bool JT_CaptchaSender::take(const QDomElement &x) return true; } - -//---------------------------------------------------------------------------- -// JT_MessageCarbons -//---------------------------------------------------------------------------- -JT_MessageCarbons::JT_MessageCarbons(Task *parent) - : Task(parent) -{ - -} - -void JT_MessageCarbons::enable() -{ - _iq = createIQ(doc(), "set", "", id()); - - QDomElement enable = doc()->createElement("enable"); - enable.setAttribute("xmlns", "urn:xmpp:carbons:2"); - - _iq.appendChild(enable); -} - -void JT_MessageCarbons::disable() -{ - _iq = createIQ(doc(), "set", "", id()); - - QDomElement disable = doc()->createElement("disable"); - disable.setAttribute("xmlns", "urn:xmpp:carbons:2"); - - _iq.appendChild(disable); -} - -void JT_MessageCarbons::onGo() -{ - send(_iq); - setSuccess(); -} - -bool JT_MessageCarbons::take(const QDomElement &e) -{ - if (e.tagName() != "iq" || e.attribute("type") != "result") - return false; - - bool res = iqVerify(e, Jid(), id()); - return res; -} diff --git a/src/xmpp/xmpp-im/xmpp_tasks.h b/src/xmpp/xmpp-im/xmpp_tasks.h index 01e4e568..036e7fe1 100644 --- a/src/xmpp/xmpp-im/xmpp_tasks.h +++ b/src/xmpp/xmpp-im/xmpp_tasks.h @@ -34,6 +34,7 @@ namespace XMPP { class Roster; class Status; + class Client; class BoBData; class CaptchaChallenge; @@ -202,9 +203,24 @@ namespace XMPP { Q_OBJECT public: + class Subscriber + { + public: + virtual ~Subscriber(); + virtual bool xmlEvent(const QDomElement &root, QDomElement &e, Client *c, int userData, bool nested); + virtual bool messageEvent(Message &msg, int userData, bool nested); + }; + JT_PushMessage(Task *parent, EncryptionHandler *encryptionHandler = nullptr); ~JT_PushMessage(); + void subscribeXml(Subscriber *sbs, const QString &tagName, const QString &xmlnsStr, int userData); + void unsubscribeXml(Subscriber *sbs, const QString &tagName, const QString &xmlnsStr); + void subscribeMessage(Subscriber *sbs, int userData); + void unsubscribeMessage(Subscriber *sbs); + bool processXmlSubscribers(QDomElement &el, Client *client, bool nested); + bool processMessageSubscribers(Message &msg, bool nested); + bool take(const QDomElement &); signals: @@ -212,7 +228,7 @@ namespace XMPP private: class Private; - Private *d = nullptr; + std::unique_ptr d; }; class JT_VCard : public Task @@ -420,22 +436,6 @@ namespace XMPP bool take(const QDomElement &); }; - class JT_MessageCarbons : public Task - { - Q_OBJECT - - public: - JT_MessageCarbons(Task *parent); - void enable(); - void disable(); - - void onGo(); - bool take(const QDomElement &e); - - private: - QDomElement _iq; - }; - class JT_CaptchaChallenger : public Task { Q_OBJECT diff --git a/src/xmpp/xmpp.pri b/src/xmpp/xmpp.pri index 8dd342d8..0a7a5d40 100644 --- a/src/xmpp/xmpp.pri +++ b/src/xmpp/xmpp.pri @@ -72,6 +72,8 @@ HEADERS += \ $$PWD/xmpp-im/xmpp_subsets.h \ $$PWD/xmpp-im/xmpp_captcha.h \ $$PWD/xmpp-im/xmpp_features.h \ + $$PWD/xmpp-im/xmpp_forwarding.h \ + $$PWD/xmpp-im/xmpp_carbons.h \ $$PWD/xmpp-im/xmpp_agentitem.h \ $$PWD/xmpp-im/xmpp_discoitem.h \ $$PWD/xmpp-im/xmpp_bitsofbinary.h \ @@ -97,6 +99,8 @@ SOURCES += \ $$PWD/xmpp-im/types.cpp \ $$PWD/xmpp-im/client.cpp \ $$PWD/xmpp-im/xmpp_features.cpp \ + $$PWD/xmpp-im/xmpp_forwarding.cpp \ + $$PWD/xmpp-im/xmpp_carbons.cpp \ $$PWD/xmpp-im/xmpp_discoitem.cpp \ $$PWD/xmpp-im/xmpp_discoinfotask.cpp \ $$PWD/xmpp-im/xmpp_xdata.cpp \ From e1244cbb9a557db32c9f82d8128823ef405ff2c7 Mon Sep 17 00:00:00 2001 From: liuch Date: Sun, 14 Apr 2019 00:44:03 +0300 Subject: [PATCH 02/16] replaced QLatin1String with QStringLiteral --- src/xmpp/xmpp-im/xmpp_carbons.cpp | 2 +- src/xmpp/xmpp-im/xmpp_forwarding.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index 25c8dc4d..ecceace3 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -27,7 +27,7 @@ using namespace XMPP; -static const QLatin1String xmlns_carbons("urn:xmpp:carbons:2"); +static const QString xmlns_carbons(QStringLiteral("urn:xmpp:carbons:2")); //---------------------------------------------------------------------------- // JT_MessageCarbons diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.cpp b/src/xmpp/xmpp-im/xmpp_forwarding.cpp index 4d7b77bd..a70c1bf9 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.cpp +++ b/src/xmpp/xmpp-im/xmpp_forwarding.cpp @@ -27,8 +27,8 @@ using namespace XMPP; -static const QLatin1String xmlns_forward("urn:xmpp:forward:0"); -static const QLatin1String xmlns_delay("urn:xmpp:delay"); +static const QString xmlns_forward(QStringLiteral("urn:xmpp:forward:0")); +static const QString xmlns_delay(QStringLiteral("urn:xmpp:delay")); //-------------------------------------------------- // class Forwarding From cf06ec09178457e4489b3c43fe3939f561c9c8a5 Mon Sep 17 00:00:00 2001 From: liuch Date: Sun, 14 Apr 2019 01:08:15 +0300 Subject: [PATCH 03/16] replaced QString::null with QString() --- src/xmpp/xmpp-im/xmpp_carbons.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index ecceace3..bf3d6bb3 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -39,7 +39,7 @@ JT_MessageCarbons::JT_MessageCarbons(Task *parent) void JT_MessageCarbons::enable() { - iq = createIQ(doc(), QLatin1String("set"), QString::null, id()); + iq = createIQ(doc(), QLatin1String("set"), QString(), id()); QDomElement enable = doc()->createElement(QLatin1String("enable")); enable.setAttribute(QLatin1String("xmlns"), xmlns_carbons); iq.appendChild(enable); @@ -47,7 +47,7 @@ void JT_MessageCarbons::enable() void JT_MessageCarbons::disable() { - iq = createIQ(doc(), QLatin1String("set"), QString::null, id()); + iq = createIQ(doc(), QLatin1String("set"), QString(), id()); QDomElement disable = doc()->createElement(QLatin1String("disable")); disable.setAttribute(QLatin1String("xmlns"), xmlns_carbons); iq.appendChild(disable); From f191ef8801aa46b0a7b32edee988f43304cce011 Mon Sep 17 00:00:00 2001 From: liuch Date: Tue, 16 Apr 2019 04:40:07 +0300 Subject: [PATCH 04/16] a few minor changes --- src/xmpp/xmpp-im/types.cpp | 4 ++-- src/xmpp/xmpp-im/xmpp_carbons.cpp | 5 ++++- src/xmpp/xmpp-im/xmpp_forwarding.cpp | 5 ++++- src/xmpp/xmpp-im/xmpp_message.h | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/xmpp/xmpp-im/types.cpp b/src/xmpp/xmpp-im/types.cpp index 41c8a851..b2070887 100644 --- a/src/xmpp/xmpp-im/types.cpp +++ b/src/xmpp/xmpp-im/types.cpp @@ -1639,9 +1639,9 @@ Message &Message::displayMessage() return *this; } -void Message::setCarbonsPrivate(bool privare) +void Message::setCarbonsPrivate(bool enable) { - d->carbonsPrivate = privare; + d->carbonsPrivate = enable; } bool Message::carbonsPrivate() const diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index bf3d6bb3..a6a3920b 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -25,7 +25,8 @@ #include "xmpp_message.h" #include "xmpp_forwarding.h" -using namespace XMPP; +namespace XMPP +{ static const QString xmlns_carbons(QStringLiteral("urn:xmpp:carbons:2")); @@ -185,3 +186,5 @@ void CarbonsManager::setEnabled(bool enable) bool CarbonsManager::isEnabled() const { return d->enable; } + +} //namespace XMPP diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.cpp b/src/xmpp/xmpp-im/xmpp_forwarding.cpp index a70c1bf9..1fa3d66e 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.cpp +++ b/src/xmpp/xmpp-im/xmpp_forwarding.cpp @@ -25,7 +25,8 @@ #include "xmpp_stream.h" #include "xmpp_message.h" -using namespace XMPP; +namespace XMPP +{ static const QString xmlns_forward(QStringLiteral("urn:xmpp:forward:0")); static const QString xmlns_delay(QStringLiteral("urn:xmpp:delay")); @@ -231,3 +232,5 @@ void ForwardingManager::setEnabled(bool enabled) bool ForwardingManager::isEnabled() const { return d->enabled; } + +} // namespace XMPP diff --git a/src/xmpp/xmpp-im/xmpp_message.h b/src/xmpp/xmpp-im/xmpp_message.h index 695ac0b5..aa920dc9 100644 --- a/src/xmpp/xmpp-im/xmpp_message.h +++ b/src/xmpp/xmpp-im/xmpp_message.h @@ -175,7 +175,7 @@ namespace XMPP { Jid displayJid() const; const Message &displayMessage() const; Message &displayMessage(); - void setCarbonsPrivate(bool privare); + void setCarbonsPrivate(bool enable); bool carbonsPrivate() const; // XEP-0297 From 3b63df35c23a48cc607086e879ec5fa934184406 Mon Sep 17 00:00:00 2001 From: liuch Date: Thu, 18 Apr 2019 03:23:28 +0300 Subject: [PATCH 05/16] added comments --- src/xmpp/xmpp-im/types.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/xmpp/xmpp-im/types.cpp b/src/xmpp/xmpp-im/types.cpp index 6b896525..54af981e 100644 --- a/src/xmpp/xmpp-im/types.cpp +++ b/src/xmpp/xmpp-im/types.cpp @@ -1625,6 +1625,12 @@ IBBData Message::ibbData() const return d? d->ibbData: IBBData(); } +//! \brief Returns Jid of the remote contact +//! +//! Returns Jid of the remote contact for the original message +//! which may be wrapped using carbons. It is useful when a client +//! needs to know in which window it should display the message. +//! So it is not always just from(). Jid Message::displayJid() const { if (!d) @@ -1641,6 +1647,7 @@ Jid Message::displayJid() const return from(); } +//! \brief Returns either the message inside the carbons or itself. const Message &Message::displayMessage() const { if (d && d->forwarding.isCarbons() && d->forwarding.message()) From e1c64f9f57b413d885f2c7f0917b41369b035ce9 Mon Sep 17 00:00:00 2001 From: liuch Date: Thu, 18 Apr 2019 04:07:55 +0300 Subject: [PATCH 06/16] some refactoring and optimization --- src/xmpp/xmpp-im/xmpp_carbons.h | 5 ++--- src/xmpp/xmpp-im/xmpp_forwarding.cpp | 2 +- src/xmpp/xmpp-im/xmpp_forwarding.h | 4 ++-- src/xmpp/xmpp-im/xmpp_tasks.cpp | 6 +++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/xmpp/xmpp-im/xmpp_carbons.h b/src/xmpp/xmpp-im/xmpp_carbons.h index 098caf6b..8e8f5fd4 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.h +++ b/src/xmpp/xmpp-im/xmpp_carbons.h @@ -22,7 +22,6 @@ #define XMPP_CARBONS_H #include -#include #include #include "xmpp_task.h" @@ -77,8 +76,8 @@ namespace XMPP void enable(); void disable(); - void onGo(); - bool take(const QDomElement &e); + void onGo() override; + bool take(const QDomElement &e) override; private: QDomElement iq; diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.cpp b/src/xmpp/xmpp-im/xmpp_forwarding.cpp index 1fa3d66e..5b561e6e 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.cpp +++ b/src/xmpp/xmpp-im/xmpp_forwarding.cpp @@ -91,7 +91,7 @@ QDateTime Forwarding::timeStamp() const return msg_.get() ? msg_->timeStamp() : QDateTime(); } -void Forwarding::setTimeStamp(QDateTime ts) +void Forwarding::setTimeStamp(const QDateTime &ts) { ts_ = ts; } diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.h b/src/xmpp/xmpp-im/xmpp_forwarding.h index 37f6dec9..a1adb018 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.h +++ b/src/xmpp/xmpp-im/xmpp_forwarding.h @@ -22,7 +22,7 @@ #define XMPP_FORWARDING_H #include -#include +#include #include #include @@ -53,7 +53,7 @@ namespace XMPP bool isCarbons() const; QDateTime timeStamp() const; - void setTimeStamp(QDateTime ts); + void setTimeStamp(const QDateTime &ts); Message *message() const; void setMessage(const Message &msg); diff --git a/src/xmpp/xmpp-im/xmpp_tasks.cpp b/src/xmpp/xmpp-im/xmpp_tasks.cpp index 7f284692..2cc221b1 100644 --- a/src/xmpp/xmpp-im/xmpp_tasks.cpp +++ b/src/xmpp/xmpp-im/xmpp_tasks.cpp @@ -902,10 +902,10 @@ class JT_PushMessage::Private { QString genKey(const QString &s1, const QString &s2) { - return QString("%1&%2").arg(s1).arg(s2); + return QString(QLatin1String("%1&%2")).arg(s1, s2); } - bool processXml(const QDomElement &root, QDomElement &e, Client *c, bool nested) + bool processChildStanzaNode(const QDomElement &root, QDomElement &e, Client *c, bool nested) { QString tagName = e.tagName(); QString xmlnsStr = e.attribute(QLatin1String("xmlns")); @@ -1018,7 +1018,7 @@ bool JT_PushMessage::processXmlSubscribers(QDomElement &el, Client *client, bool QDomElement ch = el.firstChildElement(); while (!ch.isNull()) { QDomElement next = ch.nextSiblingElement(); - bool res = d->processXml(el, ch, client, nested); + bool res = d->processChildStanzaNode(el, ch, client, nested); if (res) processed = true; if (res || ch.isNull()) From 2535f55c69204dd3f2304ccf5299439120b18108 Mon Sep 17 00:00:00 2001 From: Sergey Ilinykh Date: Sat, 20 Apr 2019 09:38:17 +0300 Subject: [PATCH 07/16] Resolve some pointer magic conflicts --- include/iris/xmpp_forwarding.h | 1 + src/xmpp/xmpp-im/types.cpp | 16 ++++--------- src/xmpp/xmpp-im/xmpp_carbons.cpp | 30 ++++++++++++++++++++++++ src/xmpp/xmpp-im/xmpp_carbons.h | 35 ++++------------------------ src/xmpp/xmpp-im/xmpp_forwarding.cpp | 31 +++++++++++------------- src/xmpp/xmpp-im/xmpp_forwarding.h | 6 +++-- src/xmpp/xmpp-im/xmpp_message.h | 6 ++--- 7 files changed, 59 insertions(+), 66 deletions(-) create mode 100644 include/iris/xmpp_forwarding.h diff --git a/include/iris/xmpp_forwarding.h b/include/iris/xmpp_forwarding.h new file mode 100644 index 00000000..6225ec94 --- /dev/null +++ b/include/iris/xmpp_forwarding.h @@ -0,0 +1 @@ +#include "../../src/xmpp/xmpp-im/xmpp_forwarding.h" diff --git a/src/xmpp/xmpp-im/types.cpp b/src/xmpp/xmpp-im/types.cpp index 54af981e..80e76b78 100644 --- a/src/xmpp/xmpp-im/types.cpp +++ b/src/xmpp/xmpp-im/types.cpp @@ -1638,9 +1638,9 @@ Jid Message::displayJid() const switch (d->forwarding.type()) { case Forwarding::ForwardedCarbonsSent: - return d->forwarding.message()->to(); + return d->forwarding.message().to(); case Forwarding::ForwardedCarbonsReceived: - return d->forwarding.message()->from(); + return d->forwarding.message().from(); default: break; } @@ -1648,18 +1648,10 @@ Jid Message::displayJid() const } //! \brief Returns either the message inside the carbons or itself. -const Message &Message::displayMessage() const +Message Message::displayMessage() const { if (d && d->forwarding.isCarbons() && d->forwarding.message()) - return *d->forwarding.message(); - - return *this; -} - -Message &Message::displayMessage() -{ - if (d && d->forwarding.isCarbons() && d->forwarding.message()) - return *d->forwarding.message(); + return d->forwarding.message(); return *this; } diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index a6a3920b..f72aa26f 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -24,12 +24,42 @@ #include "xmpp_xmlcommon.h" #include "xmpp_message.h" #include "xmpp_forwarding.h" +#include "xmpp_task.h" +#include "xmpp_tasks.h" namespace XMPP { static const QString xmlns_carbons(QStringLiteral("urn:xmpp:carbons:2")); + +class CarbonsSubscriber : public JT_PushMessage::Subscriber +{ +public: + bool xmlEvent(const QDomElement &root, QDomElement &e, Client *client, int userData, bool nested) override; + bool messageEvent(Message &msg, int userData, bool nested) override; + +private: + Forwarding frw; +}; + +class JT_MessageCarbons : public Task +{ + Q_OBJECT + +public: + JT_MessageCarbons(Task *parent); + + void enable(); + void disable(); + + void onGo() override; + bool take(const QDomElement &e) override; + +private: + QDomElement iq; +}; + //---------------------------------------------------------------------------- // JT_MessageCarbons //---------------------------------------------------------------------------- diff --git a/src/xmpp/xmpp-im/xmpp_carbons.h b/src/xmpp/xmpp-im/xmpp_carbons.h index 8e8f5fd4..20cbc671 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.h +++ b/src/xmpp/xmpp-im/xmpp_carbons.h @@ -22,26 +22,16 @@ #define XMPP_CARBONS_H #include -#include - -#include "xmpp_task.h" -#include "xmpp_tasks.h" +#include +class QDomDocument; +class QDomElement; namespace XMPP { class Task; class Client; - - class CarbonsSubscriber : public JT_PushMessage::Subscriber - { - public: - bool xmlEvent(const QDomElement &root, QDomElement &e, Client *client, int userData, bool nested) override; - bool messageEvent(Message &msg, int userData, bool nested) override; - - private: - Forwarding frw; - }; + class JT_PushMessage; class CarbonsManager : public QObject { @@ -65,23 +55,6 @@ namespace XMPP class Private; std::unique_ptr d; }; - - class JT_MessageCarbons : public Task - { - Q_OBJECT - - public: - JT_MessageCarbons(Task *parent); - - void enable(); - void disable(); - - void onGo() override; - bool take(const QDomElement &e) override; - - private: - QDomElement iq; - }; } #endif diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.cpp b/src/xmpp/xmpp-im/xmpp_forwarding.cpp index 5b561e6e..6dba6e19 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.cpp +++ b/src/xmpp/xmpp-im/xmpp_forwarding.cpp @@ -43,9 +43,8 @@ Forwarding::Forwarding() Forwarding::Forwarding(const Forwarding &other) : type_(other.type_) , ts_(other.ts_) + , msg_(other.msg_) { - if (other.msg_.get()) - msg_.reset(new Message(*other.msg_.get())); } Forwarding::~Forwarding() @@ -56,10 +55,7 @@ Forwarding & Forwarding::operator=(const Forwarding &from) { type_ = from.type_; ts_ = from.ts_; - if (from.msg_.get()) - msg_.reset(new Message(*from.msg_.get())); - else - msg_.reset(nullptr); + msg_ = from.msg_; return *this; } @@ -73,8 +69,7 @@ void Forwarding::setType(Type type) type_ = type; if (type == ForwardedNone) { ts_ = QDateTime(); - ts_.isNull(); - msg_.reset(nullptr); + msg_ = Message(); } } } @@ -88,7 +83,7 @@ QDateTime Forwarding::timeStamp() const { if (!ts_.isNull()) return ts_; - return msg_.get() ? msg_->timeStamp() : QDateTime(); + return msg_.timeStamp(); } void Forwarding::setTimeStamp(const QDateTime &ts) @@ -96,14 +91,14 @@ void Forwarding::setTimeStamp(const QDateTime &ts) ts_ = ts; } -Message *Forwarding::message() const +Message Forwarding::message() const { - return msg_.get(); + return msg_; } void Forwarding::setMessage(const Message &msg) { - msg_.reset(new Message(msg)); + msg_ = msg; } bool Forwarding::fromXml(const QDomElement &e, Client *client) @@ -119,11 +114,11 @@ bool Forwarding::fromXml(const QDomElement &e, Client *client) if (client->pushMessage()->processXmlSubscribers(child, client, true)) break; Stanza s = client->stream().createStanza(addCorrectNS(child)); - std::unique_ptr msg(new Message()); - if (msg->fromStanza(s, client->manualTimeZoneOffset(), client->timeZoneOffset())) { - if (client->pushMessage()->processMessageSubscribers(*msg.get(), true)) + Message msg; + if (msg.fromStanza(s, client->manualTimeZoneOffset(), client->timeZoneOffset())) { + if (client->pushMessage()->processMessageSubscribers(msg, true)) break; - msg_ = std::move(msg); + msg_ = msg; type_ = ForwardedMessage; correct = true; } @@ -138,7 +133,7 @@ bool Forwarding::fromXml(const QDomElement &e, Client *client) QDomElement Forwarding::toXml(Stream *stream) const { - if (type_ == ForwardedNone || !msg_.get()) + if (type_ == ForwardedNone || !msg_) return QDomElement(); QDomElement e = stream->doc().createElement(QLatin1String("forwarded")); @@ -149,7 +144,7 @@ QDomElement Forwarding::toXml(Stream *stream) const delay.setAttribute(QLatin1String("stamp"), ts_.toUTC().toString(Qt::ISODate) + "Z"); e.appendChild(delay); } - e.appendChild(msg_->toStanza(stream).element()); + e.appendChild(msg_.toStanza(stream).element()); return e; } diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.h b/src/xmpp/xmpp-im/xmpp_forwarding.h index a1adb018..c9f37bce 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.h +++ b/src/xmpp/xmpp-im/xmpp_forwarding.h @@ -26,6 +26,8 @@ #include #include +#include "xmpp_message.h" + namespace XMPP { class Client; @@ -55,7 +57,7 @@ namespace XMPP QDateTime timeStamp() const; void setTimeStamp(const QDateTime &ts); - Message *message() const; + Message message() const; void setMessage(const Message &msg); bool fromXml(const QDomElement &e, Client *client); @@ -64,7 +66,7 @@ namespace XMPP private: Type type_; QDateTime ts_; - std::unique_ptr msg_; + Message msg_; }; class ForwardingManager : public QObject diff --git a/src/xmpp/xmpp-im/xmpp_message.h b/src/xmpp/xmpp-im/xmpp_message.h index 0b442dda..7433cf3a 100644 --- a/src/xmpp/xmpp-im/xmpp_message.h +++ b/src/xmpp/xmpp-im/xmpp_message.h @@ -25,7 +25,6 @@ #include "xmpp_receipts.h" #include "xmpp_address.h" #include "xmpp_rosterx.h" -#include "xmpp_forwarding.h" #include "xmpp_muc.h" #include @@ -42,6 +41,7 @@ namespace XMPP { class XData; class BoBData; class IBBData; + class Forwarding; typedef QMap StringMap; @@ -72,6 +72,7 @@ namespace XMPP { ~Message(); bool operator ==(const Message &from) const; inline bool isNull() const { return d == nullptr; } + inline operator bool() const { return d != nullptr; } Jid to() const; Jid from() const; @@ -175,8 +176,7 @@ namespace XMPP { // XEP-0280 Message Carbons Jid displayJid() const; - const Message &displayMessage() const; - Message &displayMessage(); + Message displayMessage() const; void setCarbonsPrivate(bool enable); bool carbonsPrivate() const; From 57f1a35807be33dea7d1a18fbd39405addbdea1d Mon Sep 17 00:00:00 2001 From: Sergey Ilinykh Date: Sat, 20 Apr 2019 09:53:56 +0300 Subject: [PATCH 08/16] Added forgotten moc include --- src/xmpp/xmpp-im/xmpp_carbons.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index f72aa26f..94c14d45 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -218,3 +218,5 @@ bool CarbonsManager::isEnabled() const { } } //namespace XMPP + +#include "xmpp_carbons.moc" From ff171f79f29510cbe498e1161538d92fe60e4e30 Mon Sep 17 00:00:00 2001 From: Sergey Ilinykh Date: Sat, 20 Apr 2019 10:02:16 +0300 Subject: [PATCH 09/16] Return potentionally uninitialized Forwarding instead of static magic. --- src/xmpp/xmpp-im/types.cpp | 3 +-- src/xmpp/xmpp-im/xmpp_message.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xmpp/xmpp-im/types.cpp b/src/xmpp/xmpp-im/types.cpp index 80e76b78..34e7bbed 100644 --- a/src/xmpp/xmpp-im/types.cpp +++ b/src/xmpp/xmpp-im/types.cpp @@ -1673,8 +1673,7 @@ void Message::setForwarded(const Forwarding &frw) const Forwarding &Message::forwarded() const { - static Forwarding f; - return d ? d->forwarding : f; + return d->forwarding; } bool Message::spooled() const diff --git a/src/xmpp/xmpp-im/xmpp_message.h b/src/xmpp/xmpp-im/xmpp_message.h index 7433cf3a..46023696 100644 --- a/src/xmpp/xmpp-im/xmpp_message.h +++ b/src/xmpp/xmpp-im/xmpp_message.h @@ -182,6 +182,7 @@ namespace XMPP { // XEP-0297 void setForwarded(const Forwarding &frw); + // note, the next method has to be called only on not-null message const Forwarding &forwarded() const; // XEP-0308 From be8ba7f7c7d081c1807904ccebeac34ba028c6b2 Mon Sep 17 00:00:00 2001 From: liuch Date: Wed, 24 Apr 2019 01:45:02 +0300 Subject: [PATCH 10/16] some fixes. Thanks to @pasnox --- src/xmpp/xmpp-im/types.cpp | 4 +-- src/xmpp/xmpp-im/xmpp_carbons.cpp | 10 ++++--- src/xmpp/xmpp-im/xmpp_forwarding.cpp | 22 +++++++++----- src/xmpp/xmpp-im/xmpp_tasks.cpp | 44 ++++++++++++++++------------ 4 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/xmpp/xmpp-im/types.cpp b/src/xmpp/xmpp-im/types.cpp index 34e7bbed..9386a018 100644 --- a/src/xmpp/xmpp-im/types.cpp +++ b/src/xmpp/xmpp-im/types.cpp @@ -1073,7 +1073,7 @@ class Message::Private : public QSharedData QString replaceId; QString originId; // XEP-0359 Message::StanzaId stanzaId; // XEP-0359 - Forwarding forwarding; + Forwarding forwarding; // XEP-0297 }; #define MessageD() (d? d : (d = new Private)) @@ -1650,7 +1650,7 @@ Jid Message::displayJid() const //! \brief Returns either the message inside the carbons or itself. Message Message::displayMessage() const { - if (d && d->forwarding.isCarbons() && d->forwarding.message()) + if (d && d->forwarding.isCarbons()) return d->forwarding.message(); return *this; diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index 94c14d45..ac4d757c 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -108,7 +108,6 @@ bool JT_MessageCarbons::take(const QDomElement &e) bool CarbonsSubscriber::xmlEvent(const QDomElement &root, QDomElement &e, Client *client, int userData, bool nested) { - Q_UNUSED(root); bool drop = false; frw.setType(Forwarding::ForwardedNone); if (!nested) { @@ -147,6 +146,11 @@ bool CarbonsSubscriber::messageEvent(Message &msg, int userData, bool nested) class CarbonsManager::Private { public: + ~Private() { +// if (sbs.get()) +// unsubscribe(); + } + void subscribe() { push_m->subscribeXml(sbs.get(), QLatin1String("received"), xmlns_carbons, Forwarding::ForwardedCarbonsReceived); push_m->subscribeXml(sbs.get(), QLatin1String("sent"), xmlns_carbons, Forwarding::ForwardedCarbonsSent); @@ -174,8 +178,6 @@ CarbonsManager::CarbonsManager(JT_PushMessage *push_m) CarbonsManager::~CarbonsManager() { -// if (d->sbs.get()) -// d->unsubscribe(); } QDomElement CarbonsManager::privateElement(QDomDocument &doc) @@ -201,7 +203,7 @@ void CarbonsManager::setEnabled(bool enable) jt->enable(); jt->go(true); } - else if (d->sbs.get()) { + else { JT_MessageCarbons *jt = new JT_MessageCarbons(d->push_m->client()->rootTask()); connect(jt, &JT_MessageCarbons::finished, this, [=]() { d->enable = false; diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.cpp b/src/xmpp/xmpp-im/xmpp_forwarding.cpp index 6dba6e19..3f7f0787 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.cpp +++ b/src/xmpp/xmpp-im/xmpp_forwarding.cpp @@ -53,9 +53,11 @@ Forwarding::~Forwarding() Forwarding & Forwarding::operator=(const Forwarding &from) { - type_ = from.type_; - ts_ = from.ts_; - msg_ = from.msg_; + if (this != &from) { + type_ = from.type_; + ts_ = from.ts_; + msg_ = from.msg_; + } return *this; } @@ -63,6 +65,7 @@ Forwarding::Type Forwarding::type() const { return type_; } + void Forwarding::setType(Type type) { if (type_ != type) { @@ -186,6 +189,13 @@ class ForwardingSubscriber : public JT_PushMessage::Subscriber { class ForwardingManager::Private { public: + ~Private() { +// if (sbs.get()) { +// push_m->unsubscribeXml(sbs.get(), QLatin1String("forwarded"), xmlns_forward); +// push_m->unsubscribeMessage(sbs.get()); +// } + } + JT_PushMessage *push_m; std::unique_ptr sbs; bool enabled = false; @@ -200,10 +210,6 @@ ForwardingManager::ForwardingManager(JT_PushMessage *push_m) ForwardingManager::~ForwardingManager() { -// if (d->sbs.get()) { -// d->push_m->unsubscribeXml(d->sbs.get(), QLatin1String("forwarded"), xmlns_forward); -// d->push_m->unsubscribeMessage(d->sbs.get()); -// } } void ForwardingManager::setEnabled(bool enabled) @@ -219,7 +225,7 @@ void ForwardingManager::setEnabled(bool enabled) else { d->push_m->unsubscribeXml(d->sbs.get(), QLatin1String("forwarded"), xmlns_forward); d->push_m->unsubscribeMessage(d->sbs.get()); - d->sbs.release(); + d->sbs.reset(); } d->enabled = enabled; } diff --git a/src/xmpp/xmpp-im/xmpp_tasks.cpp b/src/xmpp/xmpp-im/xmpp_tasks.cpp index 2cc221b1..92a055a5 100644 --- a/src/xmpp/xmpp-im/xmpp_tasks.cpp +++ b/src/xmpp/xmpp-im/xmpp_tasks.cpp @@ -893,8 +893,8 @@ void JT_Message::onGo() class JT_PushMessage::Private { public: struct SubsData { - Subscriber *sbs; - int userData; + Subscriber *sbs = nullptr; + int userData = -1; }; EncryptionHandler *m_encryptionHandler; QHash > subsData; @@ -910,9 +910,9 @@ class JT_PushMessage::Private { QString tagName = e.tagName(); QString xmlnsStr = e.attribute(QLatin1String("xmlns")); QString key = genKey(tagName, xmlnsStr); - if (subsData.contains(key)) { - QList sdl = subsData.value(key); - foreach (const SubsData &sd, sdl) { + auto it = subsData.constFind(key); + if (it != subsData.constEnd()) { + foreach (const SubsData &sd, it.value()) { if (sd.sbs->xmlEvent(root, e, c, sd.userData, nested)) return true; if (e.tagName() != tagName || e.attribute(QLatin1String("xmlns")) != tagName) @@ -967,27 +967,35 @@ JT_PushMessage::~JT_PushMessage() void JT_PushMessage::subscribeXml(Subscriber *sbs, const QString &tagName, const QString &xmlnsStr, int userData) { QString key = d->genKey(tagName, xmlnsStr); - QList list = d->subsData.value(key); - foreach (const Private::SubsData &sd, list) { + auto it = d->subsData.find(key); + if (it == d->subsData.constEnd()) { + d->subsData.insert(key, {{ sbs, userData }}); + return; + } + + foreach (const Private::SubsData &sd, it.value()) { if (sd.sbs == sbs) return; } - list.append({ sbs, userData }); - d->subsData.insert(key, list); + + it.value().append({ sbs, userData }); } void JT_PushMessage::unsubscribeXml(Subscriber *sbs, const QString &tagName, const QString &xmlnsStr) { QString key = d->genKey(tagName, xmlnsStr); - QList list = d->subsData.value(key); - for (int i = 0; i < list.count(); ++i) { - if (list.at(i).sbs == sbs) { - list.removeAt(i); - if (list.count() > 0) - d->subsData.insert(key, list); - else - d->subsData.remove(key); - break; + auto it = d->subsData.find(key); + if (it != d->subsData.end()) { + QList &list = it.value(); + int cnt = list.count(); + for (int i = 0; i < cnt; ++i) { + if (list.at(i).sbs == sbs) { + if (cnt == 1) + d->subsData.erase(it); + else + list.removeAt(i); + break; + } } } } From 74961f941ac07853c350dfb1930525a2c3c598f3 Mon Sep 17 00:00:00 2001 From: Filipe Azevedo Date: Mon, 22 Apr 2019 22:04:54 +0200 Subject: [PATCH 11/16] Small code enhancements --- .gitignore | 1 + src/xmpp/xmpp-im/xmpp_carbons.cpp | 28 ++++++------- src/xmpp/xmpp-im/xmpp_forwarding.cpp | 22 +++++----- src/xmpp/xmpp-im/xmpp_tasks.cpp | 63 ++++++++++++---------------- 4 files changed, 53 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index f5a83e70..d764ff90 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ object_script.* /bin /lib /plugins +*.user* diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index ac4d757c..18d0b7f0 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -70,17 +70,17 @@ JT_MessageCarbons::JT_MessageCarbons(Task *parent) void JT_MessageCarbons::enable() { - iq = createIQ(doc(), QLatin1String("set"), QString(), id()); - QDomElement enable = doc()->createElement(QLatin1String("enable")); - enable.setAttribute(QLatin1String("xmlns"), xmlns_carbons); + iq = createIQ(doc(), QString::fromLatin1("set"), QString(), id()); + QDomElement enable = doc()->createElement(QString::fromLatin1("enable")); + enable.setAttribute(QString::fromLatin1("xmlns"), xmlns_carbons); iq.appendChild(enable); } void JT_MessageCarbons::disable() { - iq = createIQ(doc(), QLatin1String("set"), QString(), id()); - QDomElement disable = doc()->createElement(QLatin1String("disable")); - disable.setAttribute(QLatin1String("xmlns"), xmlns_carbons); + iq = createIQ(doc(), QString::fromLatin1("set"), QString(), id()); + QDomElement disable = doc()->createElement(QString::fromLatin1("disable")); + disable.setAttribute(QString::fromLatin1("xmlns"), xmlns_carbons); iq.appendChild(disable); } @@ -93,7 +93,7 @@ void JT_MessageCarbons::onGo() bool JT_MessageCarbons::take(const QDomElement &e) { if (iqVerify(e, Jid(), id())) { - if (e.attribute(QLatin1String("type")) != QLatin1String("result")) + if (e.attribute(QString::fromLatin1("type")) != QString::fromLatin1("result")) setError(e); else setSuccess(); @@ -111,8 +111,8 @@ bool CarbonsSubscriber::xmlEvent(const QDomElement &root, QDomElement &e, Client bool drop = false; frw.setType(Forwarding::ForwardedNone); if (!nested) { - Jid from(root.attribute(QLatin1String("from"))); - Jid to(root.attribute(QLatin1String("to"))); + Jid from(root.attribute(QStringLiteral("from"))); + Jid to(root.attribute(QStringLiteral("to"))); if (from.resource().isEmpty() && from.compare(to, false)) { QDomElement child = e.firstChildElement(); while (!child.isNull()) { @@ -152,14 +152,14 @@ class CarbonsManager::Private { } void subscribe() { - push_m->subscribeXml(sbs.get(), QLatin1String("received"), xmlns_carbons, Forwarding::ForwardedCarbonsReceived); - push_m->subscribeXml(sbs.get(), QLatin1String("sent"), xmlns_carbons, Forwarding::ForwardedCarbonsSent); + push_m->subscribeXml(sbs.get(), QString::fromLatin1("received"), xmlns_carbons, Forwarding::ForwardedCarbonsReceived); + push_m->subscribeXml(sbs.get(), QString::fromLatin1("sent"), xmlns_carbons, Forwarding::ForwardedCarbonsSent); push_m->subscribeMessage(sbs.get(), 0); } void unsubscribe() { - push_m->unsubscribeXml(sbs.get(), QLatin1String("received"), xmlns_carbons); - push_m->unsubscribeXml(sbs.get(), QLatin1String("sent"), xmlns_carbons); + push_m->unsubscribeXml(sbs.get(), QString::fromLatin1("received"), xmlns_carbons); + push_m->unsubscribeXml(sbs.get(), QString::fromLatin1("sent"), xmlns_carbons); push_m->unsubscribeMessage(sbs.get()); } @@ -182,7 +182,7 @@ CarbonsManager::~CarbonsManager() QDomElement CarbonsManager::privateElement(QDomDocument &doc) { - return doc.createElementNS(xmlns_carbons, QLatin1String("private")); + return doc.createElementNS(xmlns_carbons, QString::fromLatin1("private")); } void CarbonsManager::setEnabled(bool enable) diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.cpp b/src/xmpp/xmpp-im/xmpp_forwarding.cpp index 3f7f0787..fe949e9f 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.cpp +++ b/src/xmpp/xmpp-im/xmpp_forwarding.cpp @@ -106,14 +106,14 @@ void Forwarding::setMessage(const Message &msg) bool Forwarding::fromXml(const QDomElement &e, Client *client) { - if (e.tagName() != QLatin1String("forwarded") || e.attribute(QLatin1String("xmlns")) != xmlns_forward) + if (e.tagName() != QString::fromLatin1("forwarded") || e.attribute(QString::fromLatin1("xmlns")) != xmlns_forward) return false; bool correct = false; type_ = Forwarding::ForwardedNone; QDomElement child = e.firstChildElement(); while (!child.isNull()) { - if (child.tagName() == QLatin1String("message")) { + if (child.tagName() == QString::fromLatin1("message")) { if (client->pushMessage()->processXmlSubscribers(child, client, true)) break; Stanza s = client->stream().createStanza(addCorrectNS(child)); @@ -126,8 +126,8 @@ bool Forwarding::fromXml(const QDomElement &e, Client *client) correct = true; } } - else if (child.tagName() == QLatin1String("delay") && child.attribute(QLatin1String("xmlns")) == xmlns_delay) { - ts_ = QDateTime::fromString(child.attribute(QLatin1String("stamp")).left(19), Qt::ISODate); + else if (child.tagName() == QString::fromLatin1("delay") && child.attribute(QString::fromLatin1("xmlns")) == xmlns_delay) { + ts_ = QDateTime::fromString(child.attribute(QString::fromLatin1("stamp")).left(19), Qt::ISODate); } child = child.nextSiblingElement(); } @@ -139,12 +139,12 @@ QDomElement Forwarding::toXml(Stream *stream) const if (type_ == ForwardedNone || !msg_) return QDomElement(); - QDomElement e = stream->doc().createElement(QLatin1String("forwarded")); - e.setAttribute(QLatin1String("xmlns"), xmlns_forward); + QDomElement e = stream->doc().createElement(QString::fromLatin1("forwarded")); + e.setAttribute(QString::fromLatin1("xmlns"), xmlns_forward); if (ts_.isValid()) { - QDomElement delay = stream->doc().createElement(QLatin1String("delay")); - delay.setAttribute(QLatin1String("xmlns"), xmlns_delay); - delay.setAttribute(QLatin1String("stamp"), ts_.toUTC().toString(Qt::ISODate) + "Z"); + QDomElement delay = stream->doc().createElement(QString::fromLatin1("delay")); + delay.setAttribute(QString::fromLatin1("xmlns"), xmlns_delay); + delay.setAttribute(QString::fromLatin1("stamp"), ts_.toUTC().toString(Qt::ISODate) + "Z"); e.appendChild(delay); } e.appendChild(msg_.toStanza(stream).element()); @@ -219,11 +219,11 @@ void ForwardingManager::setEnabled(bool enabled) if (enabled) { d->sbs.reset(new ForwardingSubscriber()); - d->push_m->subscribeXml(d->sbs.get(), QLatin1String("forwarded"), xmlns_forward, 0); + d->push_m->subscribeXml(d->sbs.get(), QString::fromLatin1("forwarded"), xmlns_forward, 0); d->push_m->subscribeMessage(d->sbs.get(), 0); } else { - d->push_m->unsubscribeXml(d->sbs.get(), QLatin1String("forwarded"), xmlns_forward); + d->push_m->unsubscribeXml(d->sbs.get(), QString::fromLatin1("forwarded"), xmlns_forward); d->push_m->unsubscribeMessage(d->sbs.get()); d->sbs.reset(); } diff --git a/src/xmpp/xmpp-im/xmpp_tasks.cpp b/src/xmpp/xmpp-im/xmpp_tasks.cpp index 92a055a5..ea863af4 100644 --- a/src/xmpp/xmpp-im/xmpp_tasks.cpp +++ b/src/xmpp/xmpp-im/xmpp_tasks.cpp @@ -32,6 +32,7 @@ using namespace XMPP; +#define GET_SUBSCRIBER_ITERATOR(list, sbs) std::find_if(list.begin(), list.end(), [sbs](const Private::SubsData &value) { return value.sbs == sbs; }) static QString lineEncode(QString str) { @@ -896,26 +897,27 @@ class JT_PushMessage::Private { Subscriber *sbs = nullptr; int userData = -1; }; + using SubsDataList = QVector; EncryptionHandler *m_encryptionHandler; - QHash > subsData; - QList subsMData; + QHash subsData; + SubsDataList subsMData; QString genKey(const QString &s1, const QString &s2) { - return QString(QLatin1String("%1&%2")).arg(s1, s2); + return QString::fromLatin1("%1&%2").arg(s1, s2); } bool processChildStanzaNode(const QDomElement &root, QDomElement &e, Client *c, bool nested) { QString tagName = e.tagName(); - QString xmlnsStr = e.attribute(QLatin1String("xmlns")); + QString xmlnsStr = e.attribute(QString::fromLatin1("xmlns")); QString key = genKey(tagName, xmlnsStr); auto it = subsData.constFind(key); if (it != subsData.constEnd()) { foreach (const SubsData &sd, it.value()) { if (sd.sbs->xmlEvent(root, e, c, sd.userData, nested)) return true; - if (e.tagName() != tagName || e.attribute(QLatin1String("xmlns")) != tagName) + if (e.tagName() != tagName || e.attribute(QString::fromLatin1("xmlns")) != tagName) return false; } } @@ -968,17 +970,14 @@ void JT_PushMessage::subscribeXml(Subscriber *sbs, const QString &tagName, const { QString key = d->genKey(tagName, xmlnsStr); auto it = d->subsData.find(key); - if (it == d->subsData.constEnd()) { + if (it != d->subsData.end()) { + Private::SubsDataList &list = it.value(); + auto lit = GET_SUBSCRIBER_ITERATOR(list, sbs); + if (lit == list.end()) + list.append({ sbs, userData }); + } else { d->subsData.insert(key, {{ sbs, userData }}); - return; } - - foreach (const Private::SubsData &sd, it.value()) { - if (sd.sbs == sbs) - return; - } - - it.value().append({ sbs, userData }); } void JT_PushMessage::unsubscribeXml(Subscriber *sbs, const QString &tagName, const QString &xmlnsStr) @@ -986,38 +985,30 @@ void JT_PushMessage::unsubscribeXml(Subscriber *sbs, const QString &tagName, con QString key = d->genKey(tagName, xmlnsStr); auto it = d->subsData.find(key); if (it != d->subsData.end()) { - QList &list = it.value(); - int cnt = list.count(); - for (int i = 0; i < cnt; ++i) { - if (list.at(i).sbs == sbs) { - if (cnt == 1) - d->subsData.erase(it); - else - list.removeAt(i); - break; - } + Private::SubsDataList &list = it.value(); + auto lit = GET_SUBSCRIBER_ITERATOR(list, sbs); + if (lit != list.end()) { + list.erase(lit); + if (list.isEmpty()) + d->subsData.erase(it); } } } void JT_PushMessage::subscribeMessage(Subscriber *sbs, int userData) { - foreach (const Private::SubsData &sd, d->subsMData) { - if (sd.sbs == sbs) - return; - } - d->subsMData.append({ sbs, userData }); + auto &list = d->subsMData; + auto lit = GET_SUBSCRIBER_ITERATOR(list, sbs); + if (lit == list.end()) + list.append({ sbs, userData }); } void JT_PushMessage::unsubscribeMessage(Subscriber *sbs) { - int sz = d->subsMData.size(); - for (int i = 0; i < sz; ++i) { - if (d->subsMData.at(i).sbs == sbs) { - d->subsMData.removeAt(i); - break; - } - } + auto &list = d->subsMData; + auto lit = GET_SUBSCRIBER_ITERATOR(list, sbs); + if (lit != list.end()) + list.erase(lit); } bool JT_PushMessage::processXmlSubscribers(QDomElement &el, Client *client, bool nested) From 635c56b59b3b3eb7ad322aea07d2daad5a5563aa Mon Sep 17 00:00:00 2001 From: Sergei Ilinykh Date: Wed, 10 Apr 2024 18:50:58 +0300 Subject: [PATCH 12/16] Build fixes after master merging --- src/xmpp/xmpp-im/types.cpp | 8 - src/xmpp/xmpp-im/xmpp_carbons.cpp | 100 ++++---- src/xmpp/xmpp-im/xmpp_client.h | 346 +++++++++++++------------- src/xmpp/xmpp-im/xmpp_discoinfotask.h | 1 - src/xmpp/xmpp-im/xmpp_forwarding.cpp | 115 +++------ src/xmpp/xmpp-im/xmpp_tasks.cpp | 38 --- 6 files changed, 262 insertions(+), 346 deletions(-) diff --git a/src/xmpp/xmpp-im/types.cpp b/src/xmpp/xmpp-im/types.cpp index 0d2e5c93..68137fa9 100644 --- a/src/xmpp/xmpp-im/types.cpp +++ b/src/xmpp/xmpp-im/types.cpp @@ -1140,14 +1140,6 @@ void Message::setForwarded(const Forwarding &frw) { MessageD()->forwarding = frw const Forwarding &Message::forwarded() const { return d->forwarding; } -void Message::setCarbonDirection(Message::CarbonDir cd) { MessageD()->carbonDir = cd; } - -Message::CarbonDir Message::carbonDirection() const { return d ? d->carbonDir : NoCarbon; } - -void Message::setForwardedFrom(const Jid &jid) { MessageD()->forwardedFrom = jid; } - -Jid Message::forwardedFrom() const { return d ? d->forwardedFrom : Jid(); } - bool Message::spooled() const { return d && d->spooled; } void Message::setSpooled(bool b) { MessageD()->spooled = b; } diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index 18d0b7f0..829bac56 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -21,30 +21,27 @@ #include #include "xmpp_carbons.h" -#include "xmpp_xmlcommon.h" -#include "xmpp_message.h" +#include "xmpp_client.h" #include "xmpp_forwarding.h" +#include "xmpp_message.h" #include "xmpp_task.h" #include "xmpp_tasks.h" +#include "xmpp_xmlcommon.h" -namespace XMPP -{ +namespace XMPP { static const QString xmlns_carbons(QStringLiteral("urn:xmpp:carbons:2")); - -class CarbonsSubscriber : public JT_PushMessage::Subscriber -{ +class CarbonsSubscriber : public JT_PushMessage::Subscriber { public: - bool xmlEvent(const QDomElement &root, QDomElement &e, Client *client, int userData, bool nested) override; - bool messageEvent(Message &msg, int userData, bool nested) override; + bool xmlEvent(const QDomElement &root, QDomElement &e, Client *client, int userData, bool nested) override; + bool messageEvent(Message &msg, int userData, bool nested) override; private: - Forwarding frw; + Forwarding frw; }; -class JT_MessageCarbons : public Task -{ +class JT_MessageCarbons : public Task { Q_OBJECT public: @@ -63,14 +60,11 @@ class JT_MessageCarbons : public Task //---------------------------------------------------------------------------- // JT_MessageCarbons //---------------------------------------------------------------------------- -JT_MessageCarbons::JT_MessageCarbons(Task *parent) - : Task(parent) -{ -} +JT_MessageCarbons::JT_MessageCarbons(Task *parent) : Task(parent) { } void JT_MessageCarbons::enable() { - iq = createIQ(doc(), QString::fromLatin1("set"), QString(), id()); + iq = createIQ(doc(), QString::fromLatin1("set"), QString(), id()); QDomElement enable = doc()->createElement(QString::fromLatin1("enable")); enable.setAttribute(QString::fromLatin1("xmlns"), xmlns_carbons); iq.appendChild(enable); @@ -78,7 +72,7 @@ void JT_MessageCarbons::enable() void JT_MessageCarbons::disable() { - iq = createIQ(doc(), QString::fromLatin1("set"), QString(), id()); + iq = createIQ(doc(), QString::fromLatin1("set"), QString(), id()); QDomElement disable = doc()->createElement(QString::fromLatin1("disable")); disable.setAttribute(QString::fromLatin1("xmlns"), xmlns_carbons); iq.appendChild(disable); @@ -122,8 +116,7 @@ bool CarbonsSubscriber::xmlEvent(const QDomElement &root, QDomElement &e, Client } child = child.nextSiblingElement(); } - } - else + } else drop = true; e = QDomElement(); } @@ -146,39 +139,39 @@ bool CarbonsSubscriber::messageEvent(Message &msg, int userData, bool nested) class CarbonsManager::Private { public: - ~Private() { -// if (sbs.get()) -// unsubscribe(); + ~Private() + { + // if (sbs.get()) + // unsubscribe(); } - void subscribe() { - push_m->subscribeXml(sbs.get(), QString::fromLatin1("received"), xmlns_carbons, Forwarding::ForwardedCarbonsReceived); + void subscribe() + { + push_m->subscribeXml(sbs.get(), QString::fromLatin1("received"), xmlns_carbons, + Forwarding::ForwardedCarbonsReceived); push_m->subscribeXml(sbs.get(), QString::fromLatin1("sent"), xmlns_carbons, Forwarding::ForwardedCarbonsSent); push_m->subscribeMessage(sbs.get(), 0); } - void unsubscribe() { + void unsubscribe() + { push_m->unsubscribeXml(sbs.get(), QString::fromLatin1("received"), xmlns_carbons); push_m->unsubscribeXml(sbs.get(), QString::fromLatin1("sent"), xmlns_carbons); push_m->unsubscribeMessage(sbs.get()); } - JT_PushMessage *push_m; + JT_PushMessage *push_m; std::unique_ptr sbs; - bool enable = false; + bool enable = false; }; -CarbonsManager::CarbonsManager(JT_PushMessage *push_m) - : QObject(push_m) - , d(new Private) +CarbonsManager::CarbonsManager(JT_PushMessage *push_m) : QObject(push_m), d(new Private) { d->push_m = push_m; d->sbs.reset(new CarbonsSubscriber()); } -CarbonsManager::~CarbonsManager() -{ -} +CarbonsManager::~CarbonsManager() { } QDomElement CarbonsManager::privateElement(QDomDocument &doc) { @@ -193,32 +186,35 @@ void CarbonsManager::setEnabled(bool enable) if (enable) { d->subscribe(); JT_MessageCarbons *jt = new JT_MessageCarbons(d->push_m->client()->rootTask()); - connect(jt, &JT_MessageCarbons::finished, this, [=]() { - if (jt->success()) - d->enable = true; - else - d->unsubscribe(); - emit finished(); - }, Qt::QueuedConnection); + connect( + jt, &JT_MessageCarbons::finished, this, + [=]() { + if (jt->success()) + d->enable = true; + else + d->unsubscribe(); + emit finished(); + }, + Qt::QueuedConnection); jt->enable(); jt->go(true); - } - else { + } else { JT_MessageCarbons *jt = new JT_MessageCarbons(d->push_m->client()->rootTask()); - connect(jt, &JT_MessageCarbons::finished, this, [=]() { - d->enable = false; - d->unsubscribe(); - emit finished(); - }, Qt::QueuedConnection); + connect( + jt, &JT_MessageCarbons::finished, this, + [=]() { + d->enable = false; + d->unsubscribe(); + emit finished(); + }, + Qt::QueuedConnection); jt->disable(); jt->go(true); } } -bool CarbonsManager::isEnabled() const { - return d->enable; -} +bool CarbonsManager::isEnabled() const { return d->enable; } -} //namespace XMPP +} // namespace XMPP #include "xmpp_carbons.moc" diff --git a/src/xmpp/xmpp-im/xmpp_client.h b/src/xmpp/xmpp-im/xmpp_client.h index 5a1431b2..1cd7e39a 100644 --- a/src/xmpp/xmpp-im/xmpp_client.h +++ b/src/xmpp/xmpp-im/xmpp_client.h @@ -35,7 +35,8 @@ class QNetworkAccessManager; namespace XMPP { class BSConnection; class CapsManager; -class CarbonsManager class ClientStream; +class CarbonsManager; +class ClientStream; class EncryptionHandler; class Features; class FileTransferManager; @@ -71,178 +72,177 @@ namespace Jingle { } } -namespace XMPP { - class Client : public QObject { - Q_OBJECT - - public: - Client(QObject *parent = nullptr); - ~Client(); - - bool isActive() const; - void connectToServer(ClientStream *s, const Jid &j, bool auth = true); - void start(const QString &host, const QString &user, const QString &pass, const QString &resource); - void close(bool fast = false); - - bool hasStream() const; - Stream &stream(); - QString streamBaseNS() const; - const LiveRoster &roster() const; - const ResourceList &resourceList() const; - bool isSessionRequired() const; - - void send(const QDomElement &); - void send(const QString &); - void clearSendQueue(); - - QString host() const; - QString user() const; - QString pass() const; - QString resource() const; - Jid jid() const; - - void setNetworkAccessManager(QNetworkAccessManager *qnam); - QNetworkAccessManager *networkAccessManager() const; - - void rosterRequest(bool withGroupsDelimiter = true); - void sendMessage(Message &); - void sendSubscription(const Jid &, const QString &, const QString &nick = QString()); - void setPresence(const Status &); - - void debug(const QString &); - QString genUniqueId(); - Task *rootTask(); - QDomDocument *doc() const; - - QString OSName() const; - QString OSVersion() const; - QString timeZone() const; - int timeZoneOffset() const; - bool manualTimeZoneOffset() const; - QString clientName() const; - QString clientVersion() const; - CapsSpec caps() const; - CapsSpec serverCaps() const; - - void setOSName(const QString &); - void setOSVersion(const QString &); - void setTimeZone(const QString &, int); - void setClientName(const QString &); - void setClientVersion(const QString &); - void setCaps(const CapsSpec &); - void setEncryptionHandler(EncryptionHandler *); - EncryptionHandler *encryptionHandler() const; - - void setIdentity(const DiscoItem::Identity &); - DiscoItem::Identity identity() const; - - void setFeatures(const Features &f); - const Features &features() const; - DiscoItem makeDiscoResult(const QString &node = QString()) const; - void setCapsOptimizationAllowed(bool allowed); - bool capsOptimizationAllowed() const; - - void setTcpPortReserver(TcpPortReserver *portReserver); - TcpPortReserver *tcpPortReserver() const; - S5BManager *s5bManager() const; - IBBManager *ibbManager() const; - BoBManager *bobManager() const; - JidLinkManager *jidLinkManager() const; - CapsManager *capsManager() const; - CarbonsManager *carbonsManager() const; - JT_PushMessage *pushMessage() const; - ServerInfoManager *serverInfoManager() const; - ExternalServiceDiscovery *externalServiceDiscovery() const; - StunDiscoManager *stunDiscoManager() const; - HttpFileUploadManager *httpFileUploadManager() const; - Jingle::Manager *jingleManager() const; - Jingle::S5B::Manager *jingleS5BManager() const; - Jingle::IBB::Manager *jingleIBBManager() const; - Jingle::ICE::Manager *jingleICEManager() const; - - void setFileTransferEnabled(bool b); - FileTransferManager *fileTransferManager() const; - - QString groupChatPassword(const QString &host, const QString &room) const; - bool groupChatJoin(const QString &host, const QString &room, const QString &nick, - const QString &password = QString(), int maxchars = -1, int maxstanzas = -1, - int seconds = -1, const QDateTime &since = QDateTime(), const Status & = Status()); - void groupChatSetStatus(const QString &host, const QString &room, const Status &); - void groupChatChangeNick(const QString &host, const QString &room, const QString &nick, const Status &); - void groupChatLeave(const QString &host, const QString &room, const QString &statusStr = QString()); - void groupChatLeaveAll(const QString &statusStr = QString()); - QString groupChatNick(const QString &host, const QString &room) const; - - signals: - void activated(); - void disconnected(); - // void authFinished(bool, int, const QString &); - void rosterGroupsDelimiterRequestFinished(const QString &); - void rosterRequestFinished(bool, int, const QString &); - void rosterItemAdded(const RosterItem &); - void rosterItemUpdated(const RosterItem &); - void rosterItemRemoved(const RosterItem &); - void resourceAvailable(const Jid &, const Resource &); - void resourceUnavailable(const Jid &, const Resource &); - void presenceError(const Jid &, int, const QString &); - void subscription(const Jid &, const QString &, const QString &); - void messageReceived(const Message &); - void debugText(const QString &); - void xmlIncoming(const QString &); - void xmlOutgoing(const QString &); - void stanzaElementOutgoing(QDomElement &); - void groupChatJoined(const Jid &); - void groupChatLeft(const Jid &); - void groupChatPresence(const Jid &, const Status &); - void groupChatError(const Jid &, int, const QString &); - - void incomingJidLink(); - - void beginImportRoster(); - void endImportRoster(); - - private slots: - // void streamConnected(); - // void streamHandshaken(); - // void streamError(const StreamError &); - // void streamSSLCertificateReady(const QSSLCert &); - // void streamCloseFinished(); - void streamError(int); - void streamReadyRead(); - void streamIncomingXml(const QString &); - void streamOutgoingXml(const QString &); - - void slotRosterRequestFinished(); - - // basic daemons - void ppSubscription(const Jid &, const QString &, const QString &); - void ppPresence(const Jid &, const Status &); - void pmMessage(const Message &); - void prRoster(const Roster &); - - void s5b_incomingReady(); - void ibb_incomingReady(); - - void handleSMAckResponse(int); - void parseUnhandledStreamFeatures(); - - public: - class GroupChat; - - private: - void cleanup(); - void distribute(const QDomElement &); - void importRoster(const Roster &); - void importRosterItem(const RosterItem &); - void updateSelfPresence(const Jid &, const Status &); - void updatePresence(LiveRosterItem *, const Jid &, const Status &); - void handleIncoming(BSConnection *); - - void sendAckRequest(); - - class ClientPrivate; - ClientPrivate *d; - }; +class Client : public QObject { + Q_OBJECT + +public: + Client(QObject *parent = nullptr); + ~Client(); + + bool isActive() const; + void connectToServer(ClientStream *s, const Jid &j, bool auth = true); + void start(const QString &host, const QString &user, const QString &pass, const QString &resource); + void close(bool fast = false); + + bool hasStream() const; + Stream &stream(); + QString streamBaseNS() const; + const LiveRoster &roster() const; + const ResourceList &resourceList() const; + bool isSessionRequired() const; + + void send(const QDomElement &); + void send(const QString &); + void clearSendQueue(); + + QString host() const; + QString user() const; + QString pass() const; + QString resource() const; + Jid jid() const; + + void setNetworkAccessManager(QNetworkAccessManager *qnam); + QNetworkAccessManager *networkAccessManager() const; + + void rosterRequest(bool withGroupsDelimiter = true); + void sendMessage(Message &); + void sendSubscription(const Jid &, const QString &, const QString &nick = QString()); + void setPresence(const Status &); + + void debug(const QString &); + QString genUniqueId(); + Task *rootTask(); + QDomDocument *doc() const; + + QString OSName() const; + QString OSVersion() const; + QString timeZone() const; + int timeZoneOffset() const; + bool manualTimeZoneOffset() const; + QString clientName() const; + QString clientVersion() const; + CapsSpec caps() const; + CapsSpec serverCaps() const; + + void setOSName(const QString &); + void setOSVersion(const QString &); + void setTimeZone(const QString &, int); + void setClientName(const QString &); + void setClientVersion(const QString &); + void setCaps(const CapsSpec &); + void setEncryptionHandler(EncryptionHandler *); + EncryptionHandler *encryptionHandler() const; + + void setIdentity(const DiscoItem::Identity &); + DiscoItem::Identity identity() const; + + void setFeatures(const Features &f); + const Features &features() const; + DiscoItem makeDiscoResult(const QString &node = QString()) const; + void setCapsOptimizationAllowed(bool allowed); + bool capsOptimizationAllowed() const; + + void setTcpPortReserver(TcpPortReserver *portReserver); + TcpPortReserver *tcpPortReserver() const; + S5BManager *s5bManager() const; + IBBManager *ibbManager() const; + BoBManager *bobManager() const; + JidLinkManager *jidLinkManager() const; + CapsManager *capsManager() const; + CarbonsManager *carbonsManager() const; + JT_PushMessage *pushMessage() const; + ServerInfoManager *serverInfoManager() const; + ExternalServiceDiscovery *externalServiceDiscovery() const; + StunDiscoManager *stunDiscoManager() const; + HttpFileUploadManager *httpFileUploadManager() const; + Jingle::Manager *jingleManager() const; + Jingle::S5B::Manager *jingleS5BManager() const; + Jingle::IBB::Manager *jingleIBBManager() const; + Jingle::ICE::Manager *jingleICEManager() const; + + void setFileTransferEnabled(bool b); + FileTransferManager *fileTransferManager() const; + + QString groupChatPassword(const QString &host, const QString &room) const; + bool groupChatJoin(const QString &host, const QString &room, const QString &nick, + const QString &password = QString(), int maxchars = -1, int maxstanzas = -1, int seconds = -1, + const QDateTime &since = QDateTime(), const Status & = Status()); + void groupChatSetStatus(const QString &host, const QString &room, const Status &); + void groupChatChangeNick(const QString &host, const QString &room, const QString &nick, const Status &); + void groupChatLeave(const QString &host, const QString &room, const QString &statusStr = QString()); + void groupChatLeaveAll(const QString &statusStr = QString()); + QString groupChatNick(const QString &host, const QString &room) const; + +signals: + void activated(); + void disconnected(); + // void authFinished(bool, int, const QString &); + void rosterGroupsDelimiterRequestFinished(const QString &); + void rosterRequestFinished(bool, int, const QString &); + void rosterItemAdded(const RosterItem &); + void rosterItemUpdated(const RosterItem &); + void rosterItemRemoved(const RosterItem &); + void resourceAvailable(const Jid &, const Resource &); + void resourceUnavailable(const Jid &, const Resource &); + void presenceError(const Jid &, int, const QString &); + void subscription(const Jid &, const QString &, const QString &); + void messageReceived(const Message &); + void debugText(const QString &); + void xmlIncoming(const QString &); + void xmlOutgoing(const QString &); + void stanzaElementOutgoing(QDomElement &); + void groupChatJoined(const Jid &); + void groupChatLeft(const Jid &); + void groupChatPresence(const Jid &, const Status &); + void groupChatError(const Jid &, int, const QString &); + + void incomingJidLink(); + + void beginImportRoster(); + void endImportRoster(); + +private slots: + // void streamConnected(); + // void streamHandshaken(); + // void streamError(const StreamError &); + // void streamSSLCertificateReady(const QSSLCert &); + // void streamCloseFinished(); + void streamError(int); + void streamReadyRead(); + void streamIncomingXml(const QString &); + void streamOutgoingXml(const QString &); + + void slotRosterRequestFinished(); + + // basic daemons + void ppSubscription(const Jid &, const QString &, const QString &); + void ppPresence(const Jid &, const Status &); + void pmMessage(const Message &); + void prRoster(const Roster &); + + void s5b_incomingReady(); + void ibb_incomingReady(); + + void handleSMAckResponse(int); + void parseUnhandledStreamFeatures(); + +public: + class GroupChat; + +private: + void cleanup(); + void distribute(const QDomElement &); + void importRoster(const Roster &); + void importRosterItem(const RosterItem &); + void updateSelfPresence(const Jid &, const Status &); + void updatePresence(LiveRosterItem *, const Jid &, const Status &); + void handleIncoming(BSConnection *); + + void sendAckRequest(); + + class ClientPrivate; + ClientPrivate *d; +}; } // namespace XMPP #endif // XMPP_CLIENT_H diff --git a/src/xmpp/xmpp-im/xmpp_discoinfotask.h b/src/xmpp/xmpp-im/xmpp_discoinfotask.h index 81023223..c651fe8c 100644 --- a/src/xmpp/xmpp-im/xmpp_discoinfotask.h +++ b/src/xmpp/xmpp-im/xmpp_discoinfotask.h @@ -23,7 +23,6 @@ #include "xmpp_task.h" class QDomElement; -class QString; namespace XMPP { class Jid; diff --git a/src/xmpp/xmpp-im/xmpp_forwarding.cpp b/src/xmpp/xmpp-im/xmpp_forwarding.cpp index fe949e9f..09a93504 100644 --- a/src/xmpp/xmpp-im/xmpp_forwarding.cpp +++ b/src/xmpp/xmpp-im/xmpp_forwarding.cpp @@ -19,14 +19,13 @@ */ #include "xmpp_forwarding.h" -#include "xmpp_xmlcommon.h" -#include "xmpp_tasks.h" #include "xmpp_client.h" -#include "xmpp_stream.h" #include "xmpp_message.h" +#include "xmpp_stream.h" +#include "xmpp_tasks.h" +#include "xmpp_xmlcommon.h" -namespace XMPP -{ +namespace XMPP { static const QString xmlns_forward(QStringLiteral("urn:xmpp:forward:0")); static const QString xmlns_delay(QStringLiteral("urn:xmpp:delay")); @@ -35,52 +34,36 @@ static const QString xmlns_delay(QStringLiteral("urn:xmpp:delay")); // class Forwarding //-------------------------------------------------- -Forwarding::Forwarding() - : type_(ForwardedNone) -{ -} +Forwarding::Forwarding() : type_(ForwardedNone) { } -Forwarding::Forwarding(const Forwarding &other) - : type_(other.type_) - , ts_(other.ts_) - , msg_(other.msg_) -{ -} +Forwarding::Forwarding(const Forwarding &other) : type_(other.type_), ts_(other.ts_), msg_(other.msg_) { } -Forwarding::~Forwarding() -{ -} +Forwarding::~Forwarding() { } -Forwarding & Forwarding::operator=(const Forwarding &from) +Forwarding &Forwarding::operator=(const Forwarding &from) { if (this != &from) { type_ = from.type_; - ts_ = from.ts_; - msg_ = from.msg_; + ts_ = from.ts_; + msg_ = from.msg_; } return *this; } -Forwarding::Type Forwarding::type() const -{ - return type_; -} +Forwarding::Type Forwarding::type() const { return type_; } void Forwarding::setType(Type type) { if (type_ != type) { type_ = type; if (type == ForwardedNone) { - ts_ = QDateTime(); + ts_ = QDateTime(); msg_ = Message(); } } } -bool Forwarding::isCarbons() const -{ - return (type_ == ForwardedCarbonsSent || type_ == ForwardedCarbonsReceived); -} +bool Forwarding::isCarbons() const { return (type_ == ForwardedCarbonsSent || type_ == ForwardedCarbonsReceived); } QDateTime Forwarding::timeStamp() const { @@ -89,44 +72,35 @@ QDateTime Forwarding::timeStamp() const return msg_.timeStamp(); } -void Forwarding::setTimeStamp(const QDateTime &ts) -{ - ts_ = ts; -} +void Forwarding::setTimeStamp(const QDateTime &ts) { ts_ = ts; } -Message Forwarding::message() const -{ - return msg_; -} +Message Forwarding::message() const { return msg_; } -void Forwarding::setMessage(const Message &msg) -{ - msg_ = msg; -} +void Forwarding::setMessage(const Message &msg) { msg_ = msg; } bool Forwarding::fromXml(const QDomElement &e, Client *client) { if (e.tagName() != QString::fromLatin1("forwarded") || e.attribute(QString::fromLatin1("xmlns")) != xmlns_forward) return false; - bool correct = false; - type_ = Forwarding::ForwardedNone; + bool correct = false; + type_ = Forwarding::ForwardedNone; QDomElement child = e.firstChildElement(); while (!child.isNull()) { if (child.tagName() == QString::fromLatin1("message")) { if (client->pushMessage()->processXmlSubscribers(child, client, true)) break; - Stanza s = client->stream().createStanza(addCorrectNS(child)); + Stanza s = client->stream().createStanza(addCorrectNS(child)); Message msg; if (msg.fromStanza(s, client->manualTimeZoneOffset(), client->timeZoneOffset())) { if (client->pushMessage()->processMessageSubscribers(msg, true)) break; - msg_ = msg; - type_ = ForwardedMessage; + msg_ = msg; + type_ = ForwardedMessage; correct = true; } - } - else if (child.tagName() == QString::fromLatin1("delay") && child.attribute(QString::fromLatin1("xmlns")) == xmlns_delay) { + } else if (child.tagName() == QString::fromLatin1("delay") + && child.attribute(QString::fromLatin1("xmlns")) == xmlns_delay) { ts_ = QDateTime::fromString(child.attribute(QString::fromLatin1("stamp")).left(19), Qt::ISODate); } child = child.nextSiblingElement(); @@ -136,7 +110,7 @@ bool Forwarding::fromXml(const QDomElement &e, Client *client) QDomElement Forwarding::toXml(Stream *stream) const { - if (type_ == ForwardedNone || !msg_) + if (type_ == ForwardedNone || msg_.isNull()) return QDomElement(); QDomElement e = stream->doc().createElement(QString::fromLatin1("forwarded")); @@ -155,9 +129,10 @@ QDomElement Forwarding::toXml(Stream *stream) const // class ForwardingManager //-------------------------------------------------- -class ForwardingSubscriber : public JT_PushMessage::Subscriber { +class ForwardingSubscriber : public JT_PushMessage::Subscriber { public: - bool xmlEvent(const QDomElement &root, QDomElement &e, Client *c, int userData, bool nested) override { + bool xmlEvent(const QDomElement &root, QDomElement &e, Client *c, int userData, bool nested) override + { Q_UNUSED(root) Q_UNUSED(userData) frw.setType(Forwarding::ForwardedNone); @@ -170,7 +145,8 @@ class ForwardingSubscriber : public JT_PushMessage::Subscriber { return false; } - bool messageEvent(Message &msg, int userData, bool nested) override { + bool messageEvent(Message &msg, int userData, bool nested) override + { Q_UNUSED(userData) if (!nested && frw.type() != Forwarding::ForwardedNone) { msg.setForwarded(frw); @@ -189,28 +165,22 @@ class ForwardingSubscriber : public JT_PushMessage::Subscriber { class ForwardingManager::Private { public: - ~Private() { -// if (sbs.get()) { -// push_m->unsubscribeXml(sbs.get(), QLatin1String("forwarded"), xmlns_forward); -// push_m->unsubscribeMessage(sbs.get()); -// } + ~Private() + { + // if (sbs.get()) { + // push_m->unsubscribeXml(sbs.get(), QLatin1String("forwarded"), xmlns_forward); + // push_m->unsubscribeMessage(sbs.get()); + // } } - JT_PushMessage *push_m; + JT_PushMessage *push_m; std::unique_ptr sbs; - bool enabled = false; + bool enabled = false; }; -ForwardingManager::ForwardingManager(JT_PushMessage *push_m) - : QObject(push_m) - , d(new Private) -{ - d->push_m = push_m; -} +ForwardingManager::ForwardingManager(JT_PushMessage *push_m) : QObject(push_m), d(new Private) { d->push_m = push_m; } -ForwardingManager::~ForwardingManager() -{ -} +ForwardingManager::~ForwardingManager() { } void ForwardingManager::setEnabled(bool enabled) { @@ -221,8 +191,7 @@ void ForwardingManager::setEnabled(bool enabled) d->sbs.reset(new ForwardingSubscriber()); d->push_m->subscribeXml(d->sbs.get(), QString::fromLatin1("forwarded"), xmlns_forward, 0); d->push_m->subscribeMessage(d->sbs.get(), 0); - } - else { + } else { d->push_m->unsubscribeXml(d->sbs.get(), QString::fromLatin1("forwarded"), xmlns_forward); d->push_m->unsubscribeMessage(d->sbs.get()); d->sbs.reset(); @@ -230,8 +199,6 @@ void ForwardingManager::setEnabled(bool enabled) d->enabled = enabled; } -bool ForwardingManager::isEnabled() const { - return d->enabled; -} +bool ForwardingManager::isEnabled() const { return d->enabled; } } // namespace XMPP diff --git a/src/xmpp/xmpp-im/xmpp_tasks.cpp b/src/xmpp/xmpp-im/xmpp_tasks.cpp index 429b95f9..bef94b4b 100644 --- a/src/xmpp/xmpp-im/xmpp_tasks.cpp +++ b/src/xmpp/xmpp-im/xmpp_tasks.cpp @@ -1921,41 +1921,3 @@ bool JT_CaptchaSender::take(const QDomElement &x) return true; } - -//---------------------------------------------------------------------------- -// JT_MessageCarbons -//---------------------------------------------------------------------------- -JT_MessageCarbons::JT_MessageCarbons(Task *parent) : Task(parent) { } - -void JT_MessageCarbons::enable() -{ - _iq = createIQ(doc(), "set", "", id()); - - QDomElement enable = doc()->createElementNS("urn:xmpp:carbons:2", "enable"); - - _iq.appendChild(enable); -} - -void JT_MessageCarbons::disable() -{ - _iq = createIQ(doc(), "set", "", id()); - - QDomElement disable = doc()->createElementNS("urn:xmpp:carbons:2", "disable"); - - _iq.appendChild(disable); -} - -void JT_MessageCarbons::onGo() -{ - send(_iq); - setSuccess(); -} - -bool JT_MessageCarbons::take(const QDomElement &e) -{ - if (e.tagName() != "iq" || e.attribute("type") != "result") - return false; - - bool res = iqVerify(e, Jid(), id()); - return res; -} From 6d76ccde9dfd6752b79c2d3b9966351c91821415 Mon Sep 17 00:00:00 2001 From: Sergei Ilinykh Date: Wed, 10 Apr 2024 19:20:24 +0300 Subject: [PATCH 13/16] Remove not needed header --- src/xmpp/xmpp-im/xmpp_message.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xmpp/xmpp-im/xmpp_message.h b/src/xmpp/xmpp-im/xmpp_message.h index e062f834..176797c3 100644 --- a/src/xmpp/xmpp-im/xmpp_message.h +++ b/src/xmpp/xmpp-im/xmpp_message.h @@ -25,7 +25,6 @@ #include "xmpp_receipts.h" #include "xmpp_reference.h" #include "xmpp_rosterx.h" -#include "xmpp_stanza.h" #include "xmpp_url.h" #include From f57dd8761ae53e0cf7812704e442ea16189c5a7b Mon Sep 17 00:00:00 2001 From: Sergei Ilinykh Date: Sun, 14 Jul 2024 01:25:35 +0300 Subject: [PATCH 14/16] Fix lambda capture deprecation warning --- src/xmpp/xmpp-im/xmpp_carbons.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xmpp/xmpp-im/xmpp_carbons.cpp b/src/xmpp/xmpp-im/xmpp_carbons.cpp index 829bac56..ba4cd211 100644 --- a/src/xmpp/xmpp-im/xmpp_carbons.cpp +++ b/src/xmpp/xmpp-im/xmpp_carbons.cpp @@ -188,7 +188,7 @@ void CarbonsManager::setEnabled(bool enable) JT_MessageCarbons *jt = new JT_MessageCarbons(d->push_m->client()->rootTask()); connect( jt, &JT_MessageCarbons::finished, this, - [=]() { + [this, jt]() { if (jt->success()) d->enable = true; else @@ -202,7 +202,7 @@ void CarbonsManager::setEnabled(bool enable) JT_MessageCarbons *jt = new JT_MessageCarbons(d->push_m->client()->rootTask()); connect( jt, &JT_MessageCarbons::finished, this, - [=]() { + [this]() { d->enable = false; d->unsubscribe(); emit finished(); From 5ab9c31f25875a18a600c521b485a2e7ae17f4d4 Mon Sep 17 00:00:00 2001 From: mcneb10 <37050201+mcneb10@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:33:00 -0500 Subject: [PATCH 15/16] MAM: rough draft (#73) * move here from the mam branch, fix filtering, semantics, logic, etc * add id filter * actually add the id filtering logic * some code cleanup * add better error handling * add `xmpp_mamtask` to cmake and fix compilation errors * add mam manager (untested, compiles) * add ability to get last messages from archive, fix some naming * add ability to get messages before id * make the manager just return the activated MAM task instead of handling the result * fix archive behavior and return value for mam manager --------- Co-authored-by: mcneb10 --- include/iris/xmpp_mammanager.h | 1 + include/iris/xmpp_mamtask.h | 1 + src/xmpp/CMakeLists.txt | 4 + src/xmpp/xmpp-im/xmpp_mammanager.cpp | 88 +++++++++ src/xmpp/xmpp-im/xmpp_mammanager.h | 53 +++++ src/xmpp/xmpp-im/xmpp_mamtask.cpp | 278 +++++++++++++++++++++++++++ src/xmpp/xmpp-im/xmpp_mamtask.h | 67 +++++++ src/xmpp/xmpp-im/xmpp_subsets.cpp | 2 + src/xmpp/xmpp-im/xmpp_subsets.h | 2 + src/xmpp/xmpp-im/xmpp_task.cpp | 2 + src/xmpp/xmpp-im/xmpp_task.h | 1 + 11 files changed, 499 insertions(+) create mode 100644 include/iris/xmpp_mammanager.h create mode 100644 include/iris/xmpp_mamtask.h create mode 100644 src/xmpp/xmpp-im/xmpp_mammanager.cpp create mode 100644 src/xmpp/xmpp-im/xmpp_mammanager.h create mode 100644 src/xmpp/xmpp-im/xmpp_mamtask.cpp create mode 100644 src/xmpp/xmpp-im/xmpp_mamtask.h diff --git a/include/iris/xmpp_mammanager.h b/include/iris/xmpp_mammanager.h new file mode 100644 index 00000000..15450e52 --- /dev/null +++ b/include/iris/xmpp_mammanager.h @@ -0,0 +1 @@ +#include "xmpp/xmpp-im/xmpp_mammanager.h" diff --git a/include/iris/xmpp_mamtask.h b/include/iris/xmpp_mamtask.h new file mode 100644 index 00000000..f9ccc0c8 --- /dev/null +++ b/include/iris/xmpp_mamtask.h @@ -0,0 +1 @@ +#include "xmpp/xmpp-im/xmpp_mamtask.h" diff --git a/src/xmpp/CMakeLists.txt b/src/xmpp/CMakeLists.txt index 963ef04f..69b4b74f 100644 --- a/src/xmpp/CMakeLists.txt +++ b/src/xmpp/CMakeLists.txt @@ -71,6 +71,8 @@ set(XMPP_IM_HEADERS xmpp-im/xmpp_bytestream.h xmpp-im/xmpp_client.h xmpp-im/xmpp_discoinfotask.h + xmpp-im/xmpp_mamtask.h + xmpp-im/xmpp_mammanager.h xmpp-im/xmpp_ibb.h xmpp-im/xmpp_serverinfomanager.h xmpp-im/xmpp_task.h @@ -129,6 +131,8 @@ target_sources(iris PRIVATE xmpp-im/xmpp_hash.cpp xmpp-im/xmpp_ibb.cpp xmpp-im/xmpp_forwarding.cpp + xmpp-im/xmpp_mamtask.cpp + xmpp-im/xmpp_mammanager.cpp xmpp-im/xmpp_reference.cpp xmpp-im/xmpp_serverinfomanager.cpp xmpp-im/xmpp_subsets.cpp diff --git a/src/xmpp/xmpp-im/xmpp_mammanager.cpp b/src/xmpp/xmpp-im/xmpp_mammanager.cpp new file mode 100644 index 00000000..04c228fd --- /dev/null +++ b/src/xmpp/xmpp-im/xmpp_mammanager.cpp @@ -0,0 +1,88 @@ +/* + * xmpp_mammanager.cpp - XEP-0313 Message Archive Management + * Copyright (C) 2024 mcneb10 + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "xmpp_mammanager.h" + +using namespace XMPP; + +class MAMManager::Private { +public: + int mamPageSize; + int mamMaxMessages; + bool flipPages; + bool backwards; + Client *client; +}; + +MAMManager::MAMManager(Client *client, int mamPageSize, int mamMaxMessages, bool flipPages, bool backwards) +{ + d = new Private; + + d->client = client; + d->mamPageSize = mamPageSize; + d->mamMaxMessages = mamMaxMessages; + d->flipPages = flipPages; + d->backwards = backwards; +} + +MAMManager::~MAMManager() { delete d; } + +// TODO: review the safety of these methods/object lifetimes +MAMTask MAMManager::getFullArchive(const Jid &j, const bool allowMUCArchives) +{ + MAMTask task = new MAMTask(d->client->rootTask()); + + task.get(j, QString(), QString(), allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); + return task; +} + +MAMTask MAMManager::getArchiveByIDRange(const Jid &j, const QString &fromID, const QString &toID, + const bool allowMUCArchives) +{ + MAMTask task = new MAMTask(d->client->rootTask()); + + task.get(j, fromID, toID, allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); + return task; +} + +MAMTask MAMManager::getArchiveByTimeRange(const Jid &j, const QDateTime &from, const QDateTime &to, + const bool allowMUCArchives) +{ + MAMTask task = new MAMTask(d->client->rootTask()); + + task.get(j, from, to, allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); + return task; +} + +MAMTask MAMManager::getLatestMessagesFromArchive(const Jid &j, const QString &fromID, const bool allowMUCArchives, + int amount) +{ + MAMTask task = new MAMTask(d->client->rootTask()); + + task.get(j, fromID, QString(), allowMUCArchives, d->mamPageSize, amount, true, true); + return task; +} + +MAMTask MAMManager::getMessagesBeforeID(const Jid &j, const QString &toID, const bool allowMUCArchives, int amount) +{ + MAMTask task = new MAMTask(d->client->rootTask()); + + task.get(j, QString(), toID, allowMUCArchives, d->mamPageSize, amount, true, true); + return task; +} diff --git a/src/xmpp/xmpp-im/xmpp_mammanager.h b/src/xmpp/xmpp-im/xmpp_mammanager.h new file mode 100644 index 00000000..bf80adae --- /dev/null +++ b/src/xmpp/xmpp-im/xmpp_mammanager.h @@ -0,0 +1,53 @@ +/* + * xmpp_mammanager.h - XEP-0313 Message Archive Management + * Copyright (C) 2024 mcneb10 + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef XMPP_MAM_MANAGER_H +#define XMPP_MAM_MANAGER_H + +#include "xmpp_client.h" +#include "xmpp_mamtask.h" + +#include +#include + +namespace XMPP { +class MAMManager : public QObject { + Q_OBJECT +public: + MAMManager(Client *client, int mamPageSize = 10, int mamMaxMessages = 0, bool flipPages = true, + bool backwards = true); + ~MAMManager(); + + MAMTask getFullArchive(const Jid &j, const bool allowMUCArchives = true); + MAMTask getArchiveByIDRange(const Jid &j, const QString &fromID, const QString &toID, + const bool allowMUCArchives = true); + MAMTask getArchiveByTimeRange(const Jid &j, const QDateTime &from, const QDateTime &to, + const bool allowMUCArchives = true); + MAMTask getLatestMessagesFromArchive(const Jid &j, const QString &fromID, const bool allowMUCArchives = true, + int amount = 100); + MAMTask getMessagesBeforeID(const Jid &j, const QString &toID, const bool allowMUCArchives = true, + int amount = 100); + +private: + class Private; + Private *d; +}; +} + +#endif diff --git a/src/xmpp/xmpp-im/xmpp_mamtask.cpp b/src/xmpp/xmpp-im/xmpp_mamtask.cpp new file mode 100644 index 00000000..87eee3d3 --- /dev/null +++ b/src/xmpp/xmpp-im/xmpp_mamtask.cpp @@ -0,0 +1,278 @@ +/* + * xmpp_mamtask.cpp - XEP-0313 Message Archive Management + * Copyright (C) 2024 mcneb10 + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "xmpp_mamtask.h" + +using namespace XMLHelper; +using namespace XMPP; + +class MAMTask::Private { +public: + int mamPageSize; // TODO: this is the max page size for MAM request. Should be made into a config option in Psi+ + int mamMaxMessages; // maximum mam pages total, also should be config. zero means unlimited + int messagesFetched; + bool flipPages; + bool backwards; + bool allowMUCArchives; + bool metadataFetched; + Jid j; + MAMTask *q; + QString firstID; + QString lastID; + QString lastArchiveID; + QString fromID; + QString toID; + QString mainQueryID; + QString currentPageQueryID; + QString currentPageQueryIQID; + QDateTime from; + QDateTime to; + QList archive; + + void getPage(); + void getArchiveMetadata(); + XData makeMAMFilter(); +}; + +MAMTask::MAMTask(Task *parent) : Task(parent) { d = new Private; } +MAMTask::MAMTask(const MAMTask &x) : Task(x.parent()) { d = x.d; } +MAMTask::~MAMTask() { delete d; } + +const QList &MAMTask::archive() const { return d->archive; } + +XData MAMTask::Private::makeMAMFilter() +{ + XData::FieldList fl; + + XData::Field with; + with.setType(XData::Field::Field_JidSingle); + with.setVar(QLatin1String("with")); + with.setValue(QStringList(j.full())); + fl.append(with); + + XData::Field includeGroupchat; + includeGroupchat.setType(XData::Field::Field_Boolean); + includeGroupchat.setVar(QLatin1String("include-groupchat")); + includeGroupchat.setValue(QStringList(QLatin1String(allowMUCArchives ? "true" : "false"))); + fl.append(includeGroupchat); + + if (from.isValid()) { + XData::Field start; + start.setType(XData::Field::Field_TextSingle); + start.setVar(QLatin1String("start")); + from.setTimeSpec(Qt::UTC); + start.setValue(QStringList(from.toString())); + fl.append(start); + } + + if (to.isValid()) { + XData::Field end; + end.setType(XData::Field::Field_TextSingle); + end.setVar(QLatin1String("end")); + to.setTimeSpec(Qt::UTC); + end.setValue(QStringList(to.toString())); + fl.append(end); + } + + if (!fromID.isNull()) { + XData::Field start_id; + start_id.setType(XData::Field::Field_TextSingle); + start_id.setVar(QLatin1String("after-id")); + start_id.setValue(QStringList(fromID)); + fl.append(start_id); + } + + if (!toID.isNull()) { + XData::Field end_id; + end_id.setType(XData::Field::Field_TextSingle); + end_id.setVar(QLatin1String("before-id")); + end_id.setValue(QStringList(toID)); + fl.append(end_id); + } + + XData x; + x.setType(XData::Data_Submit); + x.setFields(fl); + x.setRegistrarType(XMPP_MAM_NAMESPACE); + + return x; +} + +void MAMTask::Private::getPage() +{ + currentPageQueryIQID = q->genUniqueID(); + QDomElement iq = createIQ(q->doc(), QLatin1String("set"), QLatin1String(), currentPageQueryIQID); + QDomElement query = q->doc()->createElementNS(XMPP_MAM_NAMESPACE, QLatin1String("query")); + currentPageQueryID = q->genUniqueID(); + query.setAttribute(QLatin1String("queryid"), currentPageQueryID); + XData x = makeMAMFilter(); + + SubsetsClientManager rsm; + rsm.setMax(mamMaxMessages); + + if (flipPages) + query.appendChild(emptyTag(q->doc(), QLatin1String("flip-page"))); + + if (lastArchiveID.isNull()) { + if (backwards) { + rsm.getLast(); + } else { + rsm.getFirst(); + } + } else { + if (backwards) { + rsm.setFirstID(lastArchiveID); + rsm.getPrevious(); + } else { + rsm.setLastID(lastArchiveID); + rsm.getNext(); + } + } + + query.appendChild(x.toXml(q->doc())); + query.appendChild(rsm.makeQueryElement(q->doc())); + iq.appendChild(query); + q->send(iq); +} + +void MAMTask::Private::getArchiveMetadata() +{ + // Craft a query to get the first and last messages in an archive + mainQueryID = q->genUniqueID(); + QDomElement iq = createIQ(q->doc(), QLatin1String("get"), QLatin1String(), mainQueryID); + QDomElement metadata = emptyTag(q->doc(), QLatin1String("metadata")); + metadata.setAttribute(QLatin1String("xmlns"), XMPP_MAM_NAMESPACE); + iq.appendChild(metadata); + + q->send(iq); +} + +// Note: Set `j` to a resource if you just want to query that resource +// if you want to query all resources, set `j` to the bare JID + +// Filter by time range +void MAMTask::get(const Jid &j, const QDateTime &from, const QDateTime &to, const bool allowMUCArchives, + int mamPageSize, int mamMaxMessages, bool flipPages, bool backwards) +{ + d->archive = {}; + d->messagesFetched = 0; + d->metadataFetched = false; + + d->j = j; + d->from = from; + d->to = to; + d->allowMUCArchives = allowMUCArchives; + d->mamPageSize = mamPageSize; + d->mamMaxMessages = mamMaxMessages; + d->flipPages = flipPages; + d->backwards = backwards; + d->q = this; +} + +// Filter by id range +void MAMTask::get(const Jid &j, const QString &fromID, const QString &toID, const bool allowMUCArchives, + int mamPageSize, int mamMaxMessages, bool flipPages, bool backwards) +{ + d->archive = {}; + d->messagesFetched = 0; + d->metadataFetched = false; + + d->j = j; + d->fromID = fromID; + d->toID = toID; + d->allowMUCArchives = allowMUCArchives; + d->mamPageSize = mamPageSize; + d->mamMaxMessages = mamMaxMessages; + d->flipPages = flipPages; + d->backwards = backwards; +} + +void MAMTask::onGo() { d->getArchiveMetadata(); } + +bool MAMTask::take(const QDomElement &x) +{ + if (d->metadataFetched) { + if (iqVerify(x, QString(), d->currentPageQueryIQID)) { + if (!x.elementsByTagNameNS(QLatin1String("urn:ietf:params:xml:ns:xmpp-stanzas"), + QLatin1String("item-not-found")) + .isEmpty()) { + setError(2, "First or last stanza UID of filter was not found in the archive"); + return true; + } else if (!x.elementsByTagNameNS(XMPP_MAM_NAMESPACE, QLatin1String("fin")).isEmpty()) { + // We are done? + //setSuccess(); + //return true; + return false; // TODO: testing + } + // Probably ignore it + return false; + } + + QDomElement result = x.firstChildElement("result"); + if (result != QDomElement() && result.namespaceURI() == XMPP_MAM_NAMESPACE + && result.attribute(QLatin1String("queryid")) == d->currentPageQueryID) { + + d->archive.append(result); + d->lastArchiveID = result.attribute(QLatin1String("id")); + d->messagesFetched = d->messagesFetched + 1; + + // Check if we are done + if (result.attribute(QLatin1String("id")) == d->lastID || d->messagesFetched >= d->mamMaxMessages) { + setSuccess(); + } else if (d->messagesFetched % d->mamPageSize == 0) { + d->getPage(); + } + } + } else { + if (!iqVerify(x, QString(), d->mainQueryID)) + return false; + + // Return if the archive is empty + QDomElement queryMetadata = x.firstChildElement(QLatin1String("metadata")); + if(queryMetadata == QDomElement()) { + setError(1, "Malformed server metadata response"); + return true; + } + if (!queryMetadata.hasChildNodes()) { + // No data in archive + setSuccess(); + return true; + } + + QDomElement start_id = queryMetadata.firstChildElement(QLatin1String("start")); + QDomElement end_id = queryMetadata.firstChildElement(QLatin1String("end")); + + if (start_id.isNull() || end_id.isNull()) { + setError(1, "Malformed server metadata response"); + return true; + } + + if (d->backwards) { + d->lastID = start_id.attribute(QLatin1String("id")); + d->firstID = end_id.attribute(QLatin1String("id")); + } else { + d->firstID = start_id.attribute(QLatin1String("id")); + d->lastID = end_id.attribute(QLatin1String("id")); + } + d->metadataFetched = true; + d->getPage(); + } + + return true; +} diff --git a/src/xmpp/xmpp-im/xmpp_mamtask.h b/src/xmpp/xmpp-im/xmpp_mamtask.h new file mode 100644 index 00000000..d163e50f --- /dev/null +++ b/src/xmpp/xmpp-im/xmpp_mamtask.h @@ -0,0 +1,67 @@ +/* + * xmpp_mamtask.h - XEP-0313 Message Archive Management + * Copyright (C) 2024 mcneb10 + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef XMPP_MAM_TASK_H +#define XMPP_MAM_TASK_H + +#include "xmpp/jid/jid.h" +#include "xmpp_subsets.h" +#include "xmpp_task.h" +#include "xmpp_xdata.h" +#include "xmpp_xmlcommon.h" + +#include + +#define XMPP_MAM_NAMESPACE QLatin1String("urn:xmpp:mam:2") + +class QDomElement; +class QString; + +namespace XMPP { +class Jid; + +class MAMTask : public Task { + Q_OBJECT +public: + MAMTask(Task *); + MAMTask(const MAMTask &x); + ~MAMTask(); + + const QList &archive() const; + + // Time filter + void get(const Jid &j, const QDateTime &from = QDateTime(), const QDateTime &to = QDateTime(), + const bool allowMUCArchives = true, int mamPageSize = 10, int mamMaxMessages = 0, bool flipPages = true, + bool backwards = true); + + // ID Filter + void get(const Jid &j, const QString &fromID = QString(), const QString &toID = QString(), + const bool allowMUCArchives = true, int mamPageSize = 10, int mamMaxMessages = 0, bool flipPages = true, + bool backwards = true); + + void onGo(); + bool take(const QDomElement &); + +private: + class Private; + Private *d; +}; +} // namespace XMPP + +#endif diff --git a/src/xmpp/xmpp-im/xmpp_subsets.cpp b/src/xmpp/xmpp-im/xmpp_subsets.cpp index 5925bbab..f1f75fdc 100644 --- a/src/xmpp/xmpp-im/xmpp_subsets.cpp +++ b/src/xmpp/xmpp-im/xmpp_subsets.cpp @@ -165,6 +165,8 @@ bool SubsetsClientManager::isLast() const { return d->result.last; } int SubsetsClientManager::count() const { return d->result.count; } void SubsetsClientManager::setMax(int max) { d->query.max = max; } +void SubsetsClientManager::setFirstID(const QString& a) { d->result.firstId = a; } +void SubsetsClientManager::setLastID(const QString& a) { d->result.lastId = a; } QDomElement SubsetsClientManager::findElement(const QDomElement &el, bool child) { diff --git a/src/xmpp/xmpp-im/xmpp_subsets.h b/src/xmpp/xmpp-im/xmpp_subsets.h index 4e6bbd24..a940b035 100644 --- a/src/xmpp/xmpp-im/xmpp_subsets.h +++ b/src/xmpp/xmpp-im/xmpp_subsets.h @@ -34,6 +34,8 @@ class SubsetsClientManager { bool isLast() const; int count() const; void setMax(int max); + void setFirstID(const QString&); + void setLastID(const QString&); void getCount(); void getFirst(); diff --git a/src/xmpp/xmpp-im/xmpp_task.cpp b/src/xmpp/xmpp-im/xmpp_task.cpp index 7c4c2a02..f50842a6 100644 --- a/src/xmpp/xmpp-im/xmpp_task.cpp +++ b/src/xmpp/xmpp-im/xmpp_task.cpp @@ -83,6 +83,8 @@ QDomDocument *Task::doc() const { return client()->doc(); } QString Task::id() const { return d->id; } +QString Task::genUniqueID() { return client()->genUniqueId(); } + bool Task::success() const { return d->success; } int Task::statusCode() const { return d->statusCode; } diff --git a/src/xmpp/xmpp-im/xmpp_task.h b/src/xmpp/xmpp-im/xmpp_task.h index 15e2d260..a0b031de 100644 --- a/src/xmpp/xmpp-im/xmpp_task.h +++ b/src/xmpp/xmpp-im/xmpp_task.h @@ -44,6 +44,7 @@ class Task : public QObject { Client *client() const; QDomDocument *doc() const; QString id() const; + QString genUniqueID(); bool success() const; int statusCode() const; From 35cd90c51f7325c7e95ec1b1fe75469a3c22f0bd Mon Sep 17 00:00:00 2001 From: Sergei Ilinykh Date: Wed, 11 Sep 2024 23:41:50 +0300 Subject: [PATCH 16/16] compilation fixes --- src/xmpp/xmpp-im/xmpp_mammanager.cpp | 36 ++++++++++++++-------------- src/xmpp/xmpp-im/xmpp_mammanager.h | 18 +++++++------- src/xmpp/xmpp-im/xmpp_mamtask.h | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/xmpp/xmpp-im/xmpp_mammanager.cpp b/src/xmpp/xmpp-im/xmpp_mammanager.cpp index 04c228fd..a0e686ee 100644 --- a/src/xmpp/xmpp-im/xmpp_mammanager.cpp +++ b/src/xmpp/xmpp-im/xmpp_mammanager.cpp @@ -44,45 +44,45 @@ MAMManager::MAMManager(Client *client, int mamPageSize, int mamMaxMessages, bool MAMManager::~MAMManager() { delete d; } // TODO: review the safety of these methods/object lifetimes -MAMTask MAMManager::getFullArchive(const Jid &j, const bool allowMUCArchives) +MAMTask *MAMManager::getFullArchive(const Jid &j, const bool allowMUCArchives) { - MAMTask task = new MAMTask(d->client->rootTask()); + auto task = new MAMTask(d->client->rootTask()); - task.get(j, QString(), QString(), allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); + task->get(j, QString(), QString(), allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); return task; } -MAMTask MAMManager::getArchiveByIDRange(const Jid &j, const QString &fromID, const QString &toID, - const bool allowMUCArchives) +MAMTask *MAMManager::getArchiveByIDRange(const Jid &j, const QString &fromID, const QString &toID, + const bool allowMUCArchives) { - MAMTask task = new MAMTask(d->client->rootTask()); + auto task = new MAMTask(d->client->rootTask()); - task.get(j, fromID, toID, allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); + task->get(j, fromID, toID, allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); return task; } -MAMTask MAMManager::getArchiveByTimeRange(const Jid &j, const QDateTime &from, const QDateTime &to, - const bool allowMUCArchives) +MAMTask *MAMManager::getArchiveByTimeRange(const Jid &j, const QDateTime &from, const QDateTime &to, + const bool allowMUCArchives) { - MAMTask task = new MAMTask(d->client->rootTask()); + auto task = new MAMTask(d->client->rootTask()); - task.get(j, from, to, allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); + task->get(j, from, to, allowMUCArchives, d->mamPageSize, d->mamMaxMessages, d->flipPages, d->backwards); return task; } -MAMTask MAMManager::getLatestMessagesFromArchive(const Jid &j, const QString &fromID, const bool allowMUCArchives, - int amount) +MAMTask *MAMManager::getLatestMessagesFromArchive(const Jid &j, const QString &fromID, const bool allowMUCArchives, + int amount) { - MAMTask task = new MAMTask(d->client->rootTask()); + auto task = new MAMTask(d->client->rootTask()); - task.get(j, fromID, QString(), allowMUCArchives, d->mamPageSize, amount, true, true); + task->get(j, fromID, QString(), allowMUCArchives, d->mamPageSize, amount, true, true); return task; } -MAMTask MAMManager::getMessagesBeforeID(const Jid &j, const QString &toID, const bool allowMUCArchives, int amount) +MAMTask *MAMManager::getMessagesBeforeID(const Jid &j, const QString &toID, const bool allowMUCArchives, int amount) { - MAMTask task = new MAMTask(d->client->rootTask()); + auto task = new MAMTask(d->client->rootTask()); - task.get(j, QString(), toID, allowMUCArchives, d->mamPageSize, amount, true, true); + task->get(j, QString(), toID, allowMUCArchives, d->mamPageSize, amount, true, true); return task; } diff --git a/src/xmpp/xmpp-im/xmpp_mammanager.h b/src/xmpp/xmpp-im/xmpp_mammanager.h index bf80adae..9c87e660 100644 --- a/src/xmpp/xmpp-im/xmpp_mammanager.h +++ b/src/xmpp/xmpp-im/xmpp_mammanager.h @@ -34,15 +34,15 @@ class MAMManager : public QObject { bool backwards = true); ~MAMManager(); - MAMTask getFullArchive(const Jid &j, const bool allowMUCArchives = true); - MAMTask getArchiveByIDRange(const Jid &j, const QString &fromID, const QString &toID, - const bool allowMUCArchives = true); - MAMTask getArchiveByTimeRange(const Jid &j, const QDateTime &from, const QDateTime &to, - const bool allowMUCArchives = true); - MAMTask getLatestMessagesFromArchive(const Jid &j, const QString &fromID, const bool allowMUCArchives = true, - int amount = 100); - MAMTask getMessagesBeforeID(const Jid &j, const QString &toID, const bool allowMUCArchives = true, - int amount = 100); + MAMTask *getFullArchive(const Jid &j, const bool allowMUCArchives = true); + MAMTask *getArchiveByIDRange(const Jid &j, const QString &fromID, const QString &toID, + const bool allowMUCArchives = true); + MAMTask *getArchiveByTimeRange(const Jid &j, const QDateTime &from, const QDateTime &to, + const bool allowMUCArchives = true); + MAMTask *getLatestMessagesFromArchive(const Jid &j, const QString &fromID, const bool allowMUCArchives = true, + int amount = 100); + MAMTask *getMessagesBeforeID(const Jid &j, const QString &toID, const bool allowMUCArchives = true, + int amount = 100); private: class Private; diff --git a/src/xmpp/xmpp-im/xmpp_mamtask.h b/src/xmpp/xmpp-im/xmpp_mamtask.h index d163e50f..63e8535a 100644 --- a/src/xmpp/xmpp-im/xmpp_mamtask.h +++ b/src/xmpp/xmpp-im/xmpp_mamtask.h @@ -39,7 +39,7 @@ class Jid; class MAMTask : public Task { Q_OBJECT public: - MAMTask(Task *); + explicit MAMTask(Task *); MAMTask(const MAMTask &x); ~MAMTask();