From 6ecc6b6f0272a47d41ce5d619eaa779a29fcf9df Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Thu, 29 Jun 2023 14:10:06 +0200 Subject: WIP OMEMO --- CMakeLists.txt | 7 +- client.cpp | 15 ++- client.h | 17 ++- login.cpp | 2 +- omemo_db.cpp | 374 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ omemo_db.h | 54 +++++++++ trust_db.cpp | 246 +++++++++++++++++++++++++++++++++++++ trust_db.h | 70 +++++++++++ xxcc.cpp | 2 +- 9 files changed, 778 insertions(+), 9 deletions(-) create mode 100644 omemo_db.cpp create mode 100644 omemo_db.h create mode 100644 trust_db.cpp create mode 100644 trust_db.h diff --git a/CMakeLists.txt b/CMakeLists.txt index dd3d1ae..497175b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,8 +15,8 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Sql REQUIRED) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Sql REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Concurrent Widgets Sql REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Concurrent Widgets Sql REQUIRED) set(PROJECT_SOURCES account.cpp @@ -37,6 +37,8 @@ set(PROJECT_SOURCES main.cpp message.cpp message.ui + omemo_db.cpp + trust_db.cpp xxcc.cpp xxcc.ui ) @@ -73,6 +75,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}Keychain::Qt${QT_VERSION_MAJOR}Keychain) target_link_libraries(${PROJECT_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Sql) diff --git a/client.cpp b/client.cpp index fd98a1a..74bb0c4 100644 --- a/client.cpp +++ b/client.cpp @@ -1,10 +1,17 @@ #include "client.h" -#include -Client::Client(QObject *const parent) : - QXmppClient(parent) +Client::Client(const QString &jid, QObject *const parent) : + QXmppClient(parent), + jid(jid), + trust_db(jid), + trust(&trust_db), + omemo_db(jid), + omemo(&omemo_db) { - // addExtension(new QXmppMamManager); + addExtension(&trust); + addExtension(&pubsub); + addExtension(&omemo); + omemo.setSecurityPolicy(QXmpp::TrustSecurityPolicy::Toakafa); } QString Client::jidBare() diff --git a/client.h b/client.h index 4d8e5ca..3991e90 100644 --- a/client.h +++ b/client.h @@ -1,15 +1,30 @@ #ifndef CLIENT_H #define CLIENT_H +#include "omemo_db.h" +#include "trust_db.h" #include #include #include +#include +#include +#include +#include +#include class Client : public QXmppClient { public: - Client(QObject *parent = nullptr); + Client(const QString &jid, QObject *parent = nullptr); QString jidBare(); + +private: + const QString jid; + TrustDb trust_db; + QXmppTrustManager trust; + QXmppPubSubManager pubsub; + OmemoDb omemo_db; + QXmppOmemoManager omemo; }; #endif diff --git a/login.cpp b/login.cpp index d762f48..dc5af86 100644 --- a/login.cpp +++ b/login.cpp @@ -105,7 +105,7 @@ void Login::setup(const QString &jid, const QString pwd, const QString &domain) cfg.setPassword(pwd); cfg.setAutoReconnectionEnabled(false); - const auto client = new Client; + const auto client = new Client(jid); connect(client, &Client::stateChanged, [d = domain, e = ui.error] (const Client::State state) diff --git a/omemo_db.cpp b/omemo_db.cpp new file mode 100644 index 0000000..bc8751b --- /dev/null +++ b/omemo_db.cpp @@ -0,0 +1,374 @@ +#include "omemo_db.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const QString service_ns = "xxcc/omemo/"; + +OmemoDb::OmemoDb(const QString &jid) : + jid(jid) +{ +} + +QString OmemoDb::service() const +{ + return service_ns + jid; +} + +QXmppTask OmemoDb::allData() +{ + return QXmpp::Private::makeReadyTask(QXmppOmemoStorage::OmemoData()); +} + +int OmemoDb::storeOwnKeyId(const QString &service, const uint32_t id) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/keyid"); + job.setTextData(QString::number(id, 16)); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store own key ID: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storePrivateIdentityKey(const QString &service, + const QByteArray &privateIdentityKey) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/privateIdentityKey"); + job.setBinaryData(privateIdentityKey); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store private identity key: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storePublicIdentityKey(const QString &service, + const QByteArray &publicIdentityKey) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/publicIdentityKey"); + job.setBinaryData(publicIdentityKey); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store public identity key: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storeLatestSignedPreKeyId(const QString &service, + const uint32_t latestSignedPreKeyId) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/latestSignedPreKeyId"); + job.setTextData(QString::number(latestSignedPreKeyId, 16)); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store latest signed prekey ID: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storeLatestPreKeyId(const QString &service, + const uint32_t latestPreKeyId) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/latestPreKeyId"); + job.setTextData(QString::number(latestPreKeyId, 16)); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store latest prekey ID: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +QXmppTask OmemoDb::setOwnDevice(const std::optional &device) +{ + if (!device.has_value()) + return QXmpp::Private::makeReadyTask(); + + QXmppPromise promise; + + auto future = QtConcurrent::run( + [=] () mutable + { + const auto &d = device.value(); + const auto srv = service(); + + storeDeviceLabel(srv, d.label) + || storeOwnKeyId(srv, d.id) + || storePrivateIdentityKey(srv, d.privateIdentityKey) + || storePublicIdentityKey(srv, d.publicIdentityKey) + || storeLatestSignedPreKeyId(srv, d.latestSignedPreKeyId) + || storeLatestPreKeyId(srv, d.latestPreKeyId); + + promise.finish(); + }); + + return promise.task(); +} + +QXmppTask OmemoDb::addSignedPreKeyPair(const uint32_t keyId, + const SignedPreKeyPair &keyPair) +{ + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask OmemoDb::removeSignedPreKeyPair(uint32_t keyId) +{ + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask OmemoDb::addPreKeyPairs( + const QHash &keyPairs) +{ + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask OmemoDb::removePreKeyPair(const uint32_t keyId) +{ + return QXmpp::Private::makeReadyTask(); +} + +int OmemoDb::storeDeviceLabel(const QString &service, const QString &label) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/label"); + job.setTextData(label); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store device label: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storeKeyId(const QString &service, const QByteArray &keyId) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/key_id"); + job.setBinaryData(keyId); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store device keyID: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storeSession(const QString &service, const QByteArray &session) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/session"); + job.setBinaryData(session); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store device session: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storeUnrespondedSentStanzasCount(const QString &service, + const int count) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/unresponded_sent_stanzas"); + job.setTextData(QString::number(count)); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store device unresponded sent stanzas: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storeUnrespondedReceivedStanzasCount(const QString &service, + const int count) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/unresponded_received_stanzas"); + job.setTextData(QString::number(count)); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store device unresponded received stanzas: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +int OmemoDb::storeRemovalFromDeviceListDate(const QString &service, + const QDateTime &dt) +{ + QKeychain::WritePasswordJob job(service); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/unresponded_received_stanzas"); + job.setTextData(QString::number(dt.currentMSecsSinceEpoch())); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store device unresponded received stanzas: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +} + +QXmppTask OmemoDb::addDevice(const QString &jid, + const uint32_t deviceId, const Device &device) +{ + const QString fullservice = service_ns + jid; + QXmppPromise promise; + + auto future = QtConcurrent::run( + [=] () mutable + { + storeDeviceLabel(fullservice, device.label) + || storeKeyId(fullservice, device.keyId) + || storeSession(fullservice, device.session) + || storeUnrespondedSentStanzasCount(fullservice, + device.unrespondedSentStanzasCount) + || storeUnrespondedReceivedStanzasCount(fullservice, + device.unrespondedSentStanzasCount) + || storeRemovalFromDeviceListDate(fullservice, + device.removalFromDeviceListDate); + + promise.finish(); + }); + + return promise.task(); +} + +QXmppTask OmemoDb::removeDevice(const QString &jid, + const uint32_t deviceId) +{ +#if 0 + const QString fullservice = service_ns + jid; + QKeychain::DeletePasswordJob job(fullservice); + QEventLoop loop; + + loop.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.setKey("device/unresponded_received_stanzas"); + job.setTextData(QString::number(dt.currentMSecsSinceEpoch())); + job.start(); + loop.exec(); + + if (job.error()) + { + std::cerr << "Failed to store device unresponded received stanzas: " + << qPrintable(job.errorString()) << std::endl; + return -1; + } + + return 0; +#endif + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask OmemoDb::removeDevices(const QString &jid) +{ + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask OmemoDb::resetAll() +{ + return QXmpp::Private::makeReadyTask(); +} diff --git a/omemo_db.h b/omemo_db.h new file mode 100644 index 0000000..d331d8f --- /dev/null +++ b/omemo_db.h @@ -0,0 +1,54 @@ +#ifndef OMEMO_DB_H +#define OMEMO_DB_H + +#include +#include +#include +#include +#include +#include + +class OmemoDb : public QXmppOmemoStorage +{ +public: + OmemoDb(const QString &jid); + QXmppTask allData() override; + QXmppTask setOwnDevice( + const std::optional &device) override; + QXmppTask addSignedPreKeyPair(uint32_t keyId, + const SignedPreKeyPair &keyPair) override; + QXmppTask removeSignedPreKeyPair(uint32_t keyId) override; + QXmppTask addPreKeyPairs( + const QHash &keyPairs) override; + QXmppTask removePreKeyPair(uint32_t keyId) override; + QXmppTask addDevice(const QString &jid, + uint32_t deviceId, const Device &device) override; + QXmppTask removeDevice(const QString &jid, + uint32_t deviceId) override; + QXmppTask removeDevices(const QString &jid) override; + QXmppTask resetAll() override; + +private: + const QString &jid; + QString service() const; + static int storeOwnKeyId(const QString &service, uint32_t id); + static int storePrivateIdentityKey(const QString &service, + const QByteArray &privateIdentityKey); + static int storePublicIdentityKey(const QString &service, + const QByteArray &publicIdentityKey); + static int storeLatestSignedPreKeyId(const QString &service, + uint32_t latestSignedPreKeyId); + static int storeLatestPreKeyId(const QString &service, + uint32_t latestPreKeyId); + static int storeDeviceLabel(const QString &service, const QString &label); + static int storeKeyId(const QString &service, const QByteArray &keyId); + static int storeSession(const QString &service, const QByteArray &session); + static int storeUnrespondedSentStanzasCount(const QString &service, + int count); + static int storeUnrespondedReceivedStanzasCount(const QString &service, + int count); + static int storeRemovalFromDeviceListDate(const QString &service, + const QDateTime &dt); +}; + +#endif diff --git a/trust_db.cpp b/trust_db.cpp new file mode 100644 index 0000000..d61397c --- /dev/null +++ b/trust_db.cpp @@ -0,0 +1,246 @@ +#include "trust_db.h" +#include +#include +#include +#include +#include +#include +#include + +TrustDb::TrustDb(const QString &jid) : + jid(jid) +{ +} + +static QString toString(const QXmpp::TrustSecurityPolicy securityPolicy) +{ + switch (securityPolicy) + { + case QXmpp::NoSecurityPolicy: + return "NoSecurityPolicy"; + + case QXmpp::Toakafa: + return "Toakafa"; + } + + return "unknown"; +} + +static int toSecurityPolicy(const QString &s, + QXmpp::TrustSecurityPolicy &securityPolicy) +{ + if (s == "NoSecurityPolicy") + { + securityPolicy = QXmpp::NoSecurityPolicy; + return 0; + } + else if (s == "Toakafa") + { + securityPolicy = QXmpp::Toakafa; + return 0; + } + + return -1; +} + +QString TrustDb::service() const +{ + return "xxcc/trust/" + jid; +} + +QXmppTask TrustDb::setSecurityPolicy(const QString &encryption, + const QXmpp::TrustSecurityPolicy securityPolicy) +{ + QKeychain::WritePasswordJob job(service()); + QEventLoop loop; + + job.setKey("securityPolicy/" + encryption); + job.setTextData(toString(securityPolicy)); + job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.start(); + loop.exec(); + + if (job.error()) + std::cerr << "Failed to store security policy: " + << qPrintable(job.errorString()) << std::endl; + + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask TrustDb::resetSecurityPolicy(const QString &encryption) +{ + QKeychain::DeletePasswordJob job(service()); + QEventLoop loop; + + job.setKey("securityPolicy/" + encryption); + job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.start(); + loop.exec(); + + if (job.error()) + std::cerr << "Failed to reset security policy: " + << qPrintable(job.errorString()) << std::endl; + + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask TrustDb::securityPolicy( + const QString &encryption) +{ + QKeychain::ReadPasswordJob job(service()); + QEventLoop loop; + + job.setKey("securityPolicy/" + encryption); + job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.start(); + loop.exec(); + + if (job.error()) + std::cerr << "Failed to read security policy: " + << qPrintable(job.errorString()) << std::endl; + + QXmpp::TrustSecurityPolicy policy = QXmpp::Toakafa; + const QString data = job.textData(); + + if (toSecurityPolicy(data, policy)) + std::cerr << "Invalid security policy " << qPrintable(data) + << std::endl; + + return QXmpp::Private::makeReadyTask(QXmpp::TrustSecurityPolicy(policy)); +} + +QXmppTask TrustDb::setOwnKey(const QString &encryption, + const QByteArray &keyId) +{ + QKeychain::WritePasswordJob job(service()); + QEventLoop loop; + + job.setKey("key/" + encryption); + job.setBinaryData(keyId); + job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.start(); + loop.exec(); + + if (job.error()) + std::cerr << "Failed to store own key: " + << qPrintable(job.errorString()) << std::endl; + + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask TrustDb::resetOwnKey(const QString &encryption) +{ + QKeychain::DeletePasswordJob job(service()); + QEventLoop loop; + + job.setKey("key/" + encryption); + job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.start(); + loop.exec(); + + if (job.error()) + std::cerr << "Failed to reset own key: " + << qPrintable(job.errorString()) << std::endl; + + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask TrustDb::ownKey(const QString &encryption) +{ + QKeychain::ReadPasswordJob job(service()); + QEventLoop loop; + + job.setKey("key/" + encryption); + job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); + job.start(); + loop.exec(); + + QByteArray ret; + + if (job.error()) + std::cerr << "Failed to read own key: " + << qPrintable(job.errorString()) << std::endl; + else + ret = job.binaryData(); + + return QXmpp::Private::makeReadyTask(QByteArray(ret)); +} + +QXmppTask TrustDb::addKeys(const QString &encryption, + const QString &keyOwnerJid, const QList &keyIds, + const QXmpp::TrustLevel trustLevel) +{ + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask TrustDb::removeKeys(const QString &encryption, + const QList &keyIds) +{ + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask TrustDb::removeKeys(const QString &encryption, + const QString &keyOwnerJid) +{ + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask TrustDb::removeKeys(const QString &encryption) +{ + return QXmpp::Private::makeReadyTask(); +} + +QXmppTask>> TrustDb::keys(const QString &encryption, + const QXmpp::TrustLevels trustLevels) +{ + return QXmpp::Private::makeReadyTask(QHash>()); +} + +QXmppTask>> TrustDb::keys(const QString &encryption, + const QList &keyOwnerJids, + const QXmpp::TrustLevels trustLevels) +{ + return QXmpp::Private::makeReadyTask(QHash>()); +} + +QXmppTask TrustDb::hasKey(const QString &encryption, + const QString &keyOwnerJid, QXmpp::TrustLevels trustLevels) +{ + return QXmpp::Private::makeReadyTask(bool()); +} + +QXmppTask>> TrustDb::setTrustLevel( + const QString &encryption, + const QMultiHash &keyIds, + const QXmpp::TrustLevel trustLevel) +{ + return QXmpp::Private::makeReadyTask(QHash>()); +} + +QXmppTask>> TrustDb::setTrustLevel( + const QString &encryption, + const QList &keyOwnerJids, + const QXmpp::TrustLevel oldTrustLevel, + const QXmpp::TrustLevel newTrustLevel) +{ + return QXmpp::Private::makeReadyTask(QHash>()); +} + +QXmppTask TrustDb::trustLevel(const QString &encryption, + const QString &keyOwnerJid, const QByteArray &keyId) +{ + return QXmpp::Private::makeReadyTask(QXmpp::TrustLevel()); +} + +QXmppTask TrustDb::resetAll(const QString &encryption) +{ + return QXmpp::Private::makeReadyTask(); +} diff --git a/trust_db.h b/trust_db.h new file mode 100644 index 0000000..d5d070a --- /dev/null +++ b/trust_db.h @@ -0,0 +1,70 @@ +#ifndef TRUST_DB_H +#define TRUST_DB_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class TrustDb : virtual public QXmppTrustStorage +{ +public: + TrustDb(const QString &jid); + + QXmppTask setSecurityPolicy(const QString &encryption, + QXmpp::TrustSecurityPolicy securityPolicy) override; + QXmppTask resetSecurityPolicy(const QString &encryption) override; + QXmppTask securityPolicy( + const QString &encryption) override; + + QXmppTask setOwnKey(const QString &encryption, + const QByteArray &keyId) override; + QXmppTask resetOwnKey(const QString &encryption) override; + QXmppTask ownKey(const QString &encryption) override; + + QXmppTask addKeys(const QString &encryption, + const QString &keyOwnerJid, const QList &keyIds, + QXmpp::TrustLevel trustLevel + = QXmpp::TrustLevel::AutomaticallyDistrusted) override; + QXmppTask removeKeys(const QString &encryption, + const QList &keyIds) override; + QXmppTask removeKeys(const QString &encryption, + const QString &keyOwnerJid) override; + QXmppTask removeKeys(const QString &encryption) override; + QXmppTask>> keys(const QString &encryption, + QXmpp::TrustLevels trustLevels = {}) override; + QXmppTask>> keys(const QString &encryption, + const QList &keyOwnerJids, + QXmpp::TrustLevels trustLevels = {}) override; + QXmppTask hasKey(const QString &encryption, + const QString &keyOwnerJid, QXmpp::TrustLevels trustLevels) override; + + QXmppTask>> setTrustLevel( + const QString &encryption, + const QMultiHash &keyIds, + QXmpp::TrustLevel trustLevel) override; + QXmppTask>> setTrustLevel( + const QString &encryption, + const QList &keyOwnerJids, + QXmpp::TrustLevel oldTrustLevel, + QXmpp::TrustLevel newTrustLevel) override; + QXmppTask trustLevel(const QString &encryption, + const QString &keyOwnerJid, const QByteArray &keyId) override; + + QXmppTask resetAll(const QString &encryption) override; + +private: + const QString &jid; + QString service() const; +}; + +#endif diff --git a/xxcc.cpp b/xxcc.cpp index 9001aaa..f0ed464 100644 --- a/xxcc.cpp +++ b/xxcc.cpp @@ -115,7 +115,7 @@ void xxcc::connectAccounts(const QList &pairs) cfg.setPassword(p.second); cfg.setAutoReconnectionEnabled(true); - const auto client = new Client; + const auto client = new Client(p.first); addAccount(client); client->connectToServer(cfg); -- cgit v1.2.3