WIP OMEMO

This commit is contained in:
Xavier Del Campo Romero 2023-06-29 14:10:06 +02:00
parent 48cfe26383
commit 6ecc6b6f02
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
9 changed files with 778 additions and 9 deletions

View File

@ -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)

View File

@ -1,10 +1,17 @@
#include "client.h"
#include <QXmppMamManager.h>
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()

View File

@ -1,15 +1,30 @@
#ifndef CLIENT_H
#define CLIENT_H
#include "omemo_db.h"
#include "trust_db.h"
#include <QObject>
#include <QString>
#include <QXmppClient.h>
#include <QXmppOmemoManager.h>
#include <QXmppOmemoStorage.h>
#include <QXmppPubSubManager.h>
#include <QXmppTrustManager.h>
#include <QXmppTrustStorage.h>
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

View File

@ -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)

374
omemo_db.cpp Normal file
View File

@ -0,0 +1,374 @@
#include "omemo_db.h"
#include <QXmppConfiguration.h>
#include <QXmppFutureUtils_p.h>
#include <QXmppPromise.h>
#include <qt5keychain/keychain.h>
#include <QEventLoop>
#include <QtConcurrent>
#include <QString>
#include <iostream>
#include <optional>
static const QString service_ns = "xxcc/omemo/";
OmemoDb::OmemoDb(const QString &jid) :
jid(jid)
{
}
QString OmemoDb::service() const
{
return service_ns + jid;
}
QXmppTask<QXmppOmemoStorage::OmemoData> 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<void> OmemoDb::setOwnDevice(const std::optional<OwnDevice> &device)
{
if (!device.has_value())
return QXmpp::Private::makeReadyTask();
QXmppPromise<void> 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<void> OmemoDb::addSignedPreKeyPair(const uint32_t keyId,
const SignedPreKeyPair &keyPair)
{
return QXmpp::Private::makeReadyTask();
}
QXmppTask<void> OmemoDb::removeSignedPreKeyPair(uint32_t keyId)
{
return QXmpp::Private::makeReadyTask();
}
QXmppTask<void> OmemoDb::addPreKeyPairs(
const QHash<uint32_t, QByteArray> &keyPairs)
{
return QXmpp::Private::makeReadyTask();
}
QXmppTask<void> 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<void> OmemoDb::addDevice(const QString &jid,
const uint32_t deviceId, const Device &device)
{
const QString fullservice = service_ns + jid;
QXmppPromise<void> 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<void> 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<void> OmemoDb::removeDevices(const QString &jid)
{
return QXmpp::Private::makeReadyTask();
}
QXmppTask<void> OmemoDb::resetAll()
{
return QXmpp::Private::makeReadyTask();
}

54
omemo_db.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef OMEMO_DB_H
#define OMEMO_DB_H
#include <QXmppOmemoStorage.h>
#include <QXmppTask.h>
#include <QDateTime>
#include <QByteArray>
#include <QString>
#include <cstdint>
class OmemoDb : public QXmppOmemoStorage
{
public:
OmemoDb(const QString &jid);
QXmppTask<OmemoData> allData() override;
QXmppTask<void> setOwnDevice(
const std::optional<OwnDevice> &device) override;
QXmppTask<void> addSignedPreKeyPair(uint32_t keyId,
const SignedPreKeyPair &keyPair) override;
QXmppTask<void> removeSignedPreKeyPair(uint32_t keyId) override;
QXmppTask<void> addPreKeyPairs(
const QHash<uint32_t, QByteArray> &keyPairs) override;
QXmppTask<void> removePreKeyPair(uint32_t keyId) override;
QXmppTask<void> addDevice(const QString &jid,
uint32_t deviceId, const Device &device) override;
QXmppTask<void> removeDevice(const QString &jid,
uint32_t deviceId) override;
QXmppTask<void> removeDevices(const QString &jid) override;
QXmppTask<void> 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

246
trust_db.cpp Normal file
View File

@ -0,0 +1,246 @@
#include "trust_db.h"
#include <QXmppConfiguration.h>
#include <QXmppFutureUtils_p.h>
#include <QXmppPromise.h>
#include <qt5keychain/keychain.h>
#include <QEventLoop>
#include <QtConcurrent>
#include <iostream>
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<void> 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<void> 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<QXmpp::TrustSecurityPolicy> 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<void> 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<void> 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<QByteArray> 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<void> TrustDb::addKeys(const QString &encryption,
const QString &keyOwnerJid, const QList<QByteArray> &keyIds,
const QXmpp::TrustLevel trustLevel)
{
return QXmpp::Private::makeReadyTask();
}
QXmppTask<void> TrustDb::removeKeys(const QString &encryption,
const QList<QByteArray> &keyIds)
{
return QXmpp::Private::makeReadyTask();
}
QXmppTask<void> TrustDb::removeKeys(const QString &encryption,
const QString &keyOwnerJid)
{
return QXmpp::Private::makeReadyTask();
}
QXmppTask<void> TrustDb::removeKeys(const QString &encryption)
{
return QXmpp::Private::makeReadyTask();
}
QXmppTask<QHash<QXmpp::TrustLevel,
QMultiHash<QString, QByteArray>>> TrustDb::keys(const QString &encryption,
const QXmpp::TrustLevels trustLevels)
{
return QXmpp::Private::makeReadyTask(QHash<QXmpp::TrustLevel,
QMultiHash<QString, QByteArray>>());
}
QXmppTask<QHash<QString,
QHash<QByteArray, QXmpp::TrustLevel>>> TrustDb::keys(const QString &encryption,
const QList<QString> &keyOwnerJids,
const QXmpp::TrustLevels trustLevels)
{
return QXmpp::Private::makeReadyTask(QHash<QString,
QHash<QByteArray, QXmpp::TrustLevel>>());
}
QXmppTask<bool> TrustDb::hasKey(const QString &encryption,
const QString &keyOwnerJid, QXmpp::TrustLevels trustLevels)
{
return QXmpp::Private::makeReadyTask(bool());
}
QXmppTask<QHash<QString,
QMultiHash<QString, QByteArray>>> TrustDb::setTrustLevel(
const QString &encryption,
const QMultiHash<QString, QByteArray> &keyIds,
const QXmpp::TrustLevel trustLevel)
{
return QXmpp::Private::makeReadyTask(QHash<QString,
QMultiHash<QString, QByteArray>>());
}
QXmppTask<QHash<QString,
QMultiHash<QString, QByteArray>>> TrustDb::setTrustLevel(
const QString &encryption,
const QList<QString> &keyOwnerJids,
const QXmpp::TrustLevel oldTrustLevel,
const QXmpp::TrustLevel newTrustLevel)
{
return QXmpp::Private::makeReadyTask(QHash<QString,
QMultiHash<QString, QByteArray>>());
}
QXmppTask<QXmpp::TrustLevel> TrustDb::trustLevel(const QString &encryption,
const QString &keyOwnerJid, const QByteArray &keyId)
{
return QXmpp::Private::makeReadyTask(QXmpp::TrustLevel());
}
QXmppTask<void> TrustDb::resetAll(const QString &encryption)
{
return QXmpp::Private::makeReadyTask();
}

70
trust_db.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef TRUST_DB_H
#define TRUST_DB_H
#include <QXmppClient.h>
#include <QXmppTask.h>
#include <QXmppTrustLevel.h>
#include <QXmppTrustStorage.h>
#include <QByteArray>
#include <QHash>
#include <QList>
#include <QMultiHash>
#include <QString>
class TrustDb : virtual public QXmppTrustStorage
{
public:
TrustDb(const QString &jid);
QXmppTask<void> setSecurityPolicy(const QString &encryption,
QXmpp::TrustSecurityPolicy securityPolicy) override;
QXmppTask<void> resetSecurityPolicy(const QString &encryption) override;
QXmppTask<QXmpp::TrustSecurityPolicy> securityPolicy(
const QString &encryption) override;
QXmppTask<void> setOwnKey(const QString &encryption,
const QByteArray &keyId) override;
QXmppTask<void> resetOwnKey(const QString &encryption) override;
QXmppTask<QByteArray> ownKey(const QString &encryption) override;
QXmppTask<void> addKeys(const QString &encryption,
const QString &keyOwnerJid, const QList<QByteArray> &keyIds,
QXmpp::TrustLevel trustLevel
= QXmpp::TrustLevel::AutomaticallyDistrusted) override;
QXmppTask<void> removeKeys(const QString &encryption,
const QList<QByteArray> &keyIds) override;
QXmppTask<void> removeKeys(const QString &encryption,
const QString &keyOwnerJid) override;
QXmppTask<void> removeKeys(const QString &encryption) override;
QXmppTask<QHash<QXmpp::TrustLevel,
QMultiHash<QString, QByteArray>>> keys(const QString &encryption,
QXmpp::TrustLevels trustLevels = {}) override;
QXmppTask<QHash<QString,
QHash<QByteArray, QXmpp::TrustLevel>>> keys(const QString &encryption,
const QList<QString> &keyOwnerJids,
QXmpp::TrustLevels trustLevels = {}) override;
QXmppTask<bool> hasKey(const QString &encryption,
const QString &keyOwnerJid, QXmpp::TrustLevels trustLevels) override;
QXmppTask<QHash<QString,
QMultiHash<QString, QByteArray>>> setTrustLevel(
const QString &encryption,
const QMultiHash<QString, QByteArray> &keyIds,
QXmpp::TrustLevel trustLevel) override;
QXmppTask<QHash<QString,
QMultiHash<QString, QByteArray>>> setTrustLevel(
const QString &encryption,
const QList<QString> &keyOwnerJids,
QXmpp::TrustLevel oldTrustLevel,
QXmpp::TrustLevel newTrustLevel) override;
QXmppTask<QXmpp::TrustLevel> trustLevel(const QString &encryption,
const QString &keyOwnerJid, const QByteArray &keyId) override;
QXmppTask<void> resetAll(const QString &encryption) override;
private:
const QString &jid;
QString service() const;
};
#endif

View File

@ -115,7 +115,7 @@ void xxcc::connectAccounts(const QList<Credentials::Pair> &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);