some refactoring, some improvements

This commit is contained in:
Blue 2023-11-10 19:26:16 -03:00
parent be466fbad1
commit e31ef78e71
Signed by: blue
GPG Key ID: 9B203B252A63EE38
13 changed files with 188 additions and 147 deletions

View File

@ -266,6 +266,7 @@ void Core::Account::onClientStateChange(QXmppClient::State st) {
#ifdef WITH_OMEMO #ifdef WITH_OMEMO
if (!oh->hasOwnDevice()) { if (!oh->hasOwnDevice()) {
qDebug() << "setting up OMEMO data for account" << getName(); qDebug() << "setting up OMEMO data for account" << getName();
om->changeDeviceLabel(QGuiApplication::applicationDisplayName() + " - " + QSysInfo::productType());
QXmppTask<bool> future = om->setUp(); QXmppTask<bool> future = om->setUp();
future.then(this, [this] (bool result) { future.then(this, [this] (bool result) {
if (result) if (result)
@ -342,9 +343,8 @@ void Core::Account::setAvailability(Shared::Availability avail) {
QXmppPresence::AvailableStatusType pres = static_cast<QXmppPresence::AvailableStatusType>(avail); QXmppPresence::AvailableStatusType pres = static_cast<QXmppPresence::AvailableStatusType>(avail);
presence.setAvailableStatusType(pres); presence.setAvailableStatusType(pres);
if (state != Shared::ConnectionState::disconnected) { if (state != Shared::ConnectionState::disconnected)
client.setClientPresence(presence); client.setClientPresence(presence);
}
} }
} }
@ -437,9 +437,9 @@ void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMess
void Core::Account::requestArchive(const QString& jid, int count, const QString& before) { void Core::Account::requestArchive(const QString& jid, int count, const QString& before) {
qDebug() << "An archive request for " << jid << ", before " << before; qDebug() << "An archive request for " << jid << ", before " << before;
RosterItem* contact = rh->getRosterItem(jid); RosterItem* item = rh->getRosterItem(jid);
if (contact == nullptr) { if (item == nullptr) {
qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the contact with such id wasn't found, skipping"; qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the contact with such id wasn't found, skipping";
emit responseArchive(jid, std::list<Shared::Message>(), true); emit responseArchive(jid, std::list<Shared::Message>(), true);
return; return;
@ -447,10 +447,18 @@ void Core::Account::requestArchive(const QString& jid, int count, const QString&
if (state != Shared::ConnectionState::connected) { if (state != Shared::ConnectionState::connected) {
qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the account is not online, skipping"; qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the account is not online, skipping";
emit responseArchive(contact->jid, std::list<Shared::Message>(), false); emit responseArchive(jid, std::list<Shared::Message>(), false);
return;
} }
contact->requestHistory(count, before); #ifdef WITH_OMEMO
if (!item->isMuc()) {
Contact* contact = static_cast<Contact*>(item);
if (contact->omemoBundles == Shared::Possible::unknown)
oh->requestBundles(jid);
}
#endif
item->requestHistory(count, before);
} }
void Core::Account::onContactNeedHistory(const QString& before, const QString& after, const QDateTime& at) { void Core::Account::onContactNeedHistory(const QString& before, const QString& after, const QDateTime& at) {

View File

@ -15,9 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once
#ifndef CORE_ACCOUNT_H
#define CORE_ACCOUNT_H
#include <QObject> #include <QObject>
#include <QCryptographicHash> #include <QCryptographicHash>
@ -248,6 +246,3 @@ private:
void runDiscoveryService(); void runDiscoveryService();
}; };
} }
#endif // CORE_ACCOUNT_H

View File

@ -24,6 +24,10 @@ Core::Contact::Contact(const QString& pJid, const QString& account, QObject* par
groups(), groups(),
subscriptionState(Shared::SubscriptionState::unknown), subscriptionState(Shared::SubscriptionState::unknown),
pep(Shared::Support::unknown) pep(Shared::Support::unknown)
#ifdef WITH_OMEMO
,omemoBundles(Shared::Possible::unknown)
#endif
{} {}
Core::Contact::~Contact() {} Core::Contact::~Contact() {}

View File

@ -16,8 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef CORE_CONTACT_H #pragma once
#define CORE_CONTACT_H
#include <QObject> #include <QObject>
#include <QSet> #include <QSet>
@ -28,8 +27,7 @@
namespace Core { namespace Core {
class Contact : public RosterItem class Contact : public RosterItem {
{
Q_OBJECT Q_OBJECT
public: public:
Contact(const QString& pJid, const QString& account, QObject* parent = 0); Contact(const QString& pJid, const QString& account, QObject* parent = 0);
@ -56,7 +54,10 @@ private:
QSet<QString> groups; QSet<QString> groups;
Shared::SubscriptionState subscriptionState; Shared::SubscriptionState subscriptionState;
Shared::Support pep; Shared::Support pep;
#ifdef WITH_OMEMO
public:
Shared::Possible omemoBundles;
#endif
}; };
} }
#endif // CORE_CONTACT_H

View File

@ -1,21 +1,21 @@
// Squawk messenger. /*
// Copyright (C) 2019 Yury Gubich <blue@macaw.me> * Squawk messenger.
// * Copyright (C) 2019 Yury Gubich <blue@macaw.me>
// This program is free software: you can redistribute it and/or modify *
// it under the terms of the GNU General Public License as published by * This program is free software: you can redistribute it and/or modify
// the Free Software Foundation, either version 3 of the License, or * it under the terms of the GNU General Public License as published by
// (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or
// * (at your option) any later version.
// This program is distributed in the hope that it will be useful, *
// but WITHOUT ANY WARRANTY; without even the implied warranty of * This program is distributed in the hope that it will be useful,
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * but WITHOUT ANY WARRANTY; without even the implied warranty of
// GNU General Public License for more details. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// You should have received a copy of the GNU General Public License *
// along with this program. If not, see <http://www.gnu.org/licenses/>. * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef CORE_DELAYMANAGER_MANAGER_H */
#define CORE_DELAYMANAGER_MANAGER_H #pragma once
#include <list> #include <list>
#include <set> #include <set>
@ -38,8 +38,7 @@
namespace Core { namespace Core {
namespace DelayManager { namespace DelayManager {
class Manager : public QObject class Manager : public QObject {
{
Q_OBJECT Q_OBJECT
public: public:
Manager(const QString& ownJid, Job::Id maxParallelJobs = 5, QObject* parent = nullptr); Manager(const QString& ownJid, Job::Id maxParallelJobs = 5, QObject* parent = nullptr);
@ -146,5 +145,3 @@ public:
} }
} }
#endif // CORE_DELAYMANAGER_MANAGER_H

View File

@ -358,8 +358,8 @@ std::pair<Shared::Message::State, QString> Core::MessageHandler::scheduleSending
const QXmppE2eeExtension::MessageEncryptResult& res = task.result(); const QXmppE2eeExtension::MessageEncryptResult& res = task.result();
if (std::holds_alternative<std::unique_ptr<QXmppMessage>>(res)) { if (std::holds_alternative<std::unique_ptr<QXmppMessage>>(res)) {
const std::unique_ptr<QXmppMessage>& encrypted = std::get<std::unique_ptr<QXmppMessage>>(res); const std::unique_ptr<QXmppMessage>& encrypted = std::get<std::unique_ptr<QXmppMessage>>(res);
encrypted->setBody("This message is encrypted with OMEMO 2 but could not be decrypted"); encrypted->setBody(QString());
encrypted->setOutOfBandUrl(""); encrypted->setOutOfBandUrl(QString());
bool success = acc->client.sendPacket(*encrypted.get()); bool success = acc->client.sendPacket(*encrypted.get());
if (success) if (success)
return {Shared::Message::State::sent, ""}; return {Shared::Message::State::sent, ""};
@ -375,8 +375,8 @@ std::pair<Shared::Message::State, QString> Core::MessageHandler::scheduleSending
task.then(this, [this, id] (QXmppE2eeExtension::MessageEncryptResult&& result) { task.then(this, [this, id] (QXmppE2eeExtension::MessageEncryptResult&& result) {
if (std::holds_alternative<std::unique_ptr<QXmppMessage>>(result)) { if (std::holds_alternative<std::unique_ptr<QXmppMessage>>(result)) {
const std::unique_ptr<QXmppMessage>& encrypted = std::get<std::unique_ptr<QXmppMessage>>(result); const std::unique_ptr<QXmppMessage>& encrypted = std::get<std::unique_ptr<QXmppMessage>>(result);
encrypted->setBody("This message is encrypted with OMEMO 2 but could not be decrypted"); encrypted->setBody(QString());
encrypted->setOutOfBandUrl(""); encrypted->setOutOfBandUrl(QString());
bool success = acc->client.sendPacket(*encrypted.get()); bool success = acc->client.sendPacket(*encrypted.get());
if (success) { if (success) {
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(id, false); std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(id, false);
@ -602,7 +602,7 @@ void Core::MessageHandler::onUploadFileComplete(const std::list<Shared::MessageI
void Core::MessageHandler::sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url, bool newMessage) { void Core::MessageHandler::sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url, bool newMessage) {
msg.setOutOfBandUrl(url); msg.setOutOfBandUrl(url);
if (msg.getBody().size() == 0) //not sure why, but most messages do that if (msg.getBody().size() == 0) //not sure why, but most messengers do that
msg.setBody(url); //they duplicate oob in body, some of them wouldn't even show an attachment if you don't do that msg.setBody(url); //they duplicate oob in body, some of them wouldn't even show an attachment if you don't do that
performSending(msg, pendingCorrectionMessages.at(msg.getId()), newMessage); performSending(msg, pendingCorrectionMessages.at(msg.getId()), newMessage);

View File

@ -52,6 +52,7 @@ QXmppTask<QXmppOmemoStorage::OmemoData> Core::OmemoHandler::allData() {
OmemoData data; OmemoData data;
data.ownDevice = ownDevice; data.ownDevice = ownDevice;
// LMDBAL::Transaction txn = db.beginReadOnlyTransaction(); TODO need to enable transaction after fixing LMDBAL
std::map<uint32_t, QByteArray> pkeys = preKeyPairs->readAll(); std::map<uint32_t, QByteArray> pkeys = preKeyPairs->readAll();
for (const std::pair<const uint32_t, QByteArray>& pair : pkeys) { for (const std::pair<const uint32_t, QByteArray>& pair : pkeys) {
data.preKeyPairs.insert(pair.first, pair.second); data.preKeyPairs.insert(pair.first, pair.second);
@ -73,28 +74,30 @@ QXmppTask<QXmppOmemoStorage::OmemoData> Core::OmemoHandler::allData() {
QXmppTask<void> Core::OmemoHandler::addDevice(const QString& jid, uint32_t deviceId, const QXmppOmemoStorage::Device& device) { QXmppTask<void> Core::OmemoHandler::addDevice(const QString& jid, uint32_t deviceId, const QXmppOmemoStorage::Device& device) {
QHash<uint32_t, Device> devs; QHash<uint32_t, Device> devs;
LMDBAL::WriteTransaction txn = db.beginTransaction();
bool had = true; bool had = true;
try { try {
devs = devices->getRecord(jid); devices->getRecord(jid, devs, txn);
} catch (const LMDBAL::NotFound& error) { } catch (const LMDBAL::NotFound& error) {
had = false; had = false;
} }
devs.insert(deviceId, device); devs.insert(deviceId, device); //overwrites
if (had) { if (had)
devices->changeRecord(jid, devs); devices->changeRecord(jid, devs, txn);
} else { else
devices->addRecord(jid, devs); devices->addRecord(jid, devs, txn);
}
txn.commit();
return Core::makeReadyTask(); return Core::makeReadyTask();
} }
QXmppTask<void> Core::OmemoHandler::addPreKeyPairs(const QHash<uint32_t, QByteArray>& keyPairs) { QXmppTask<void> Core::OmemoHandler::addPreKeyPairs(const QHash<uint32_t, QByteArray>& keyPairs) {
for (QHash<uint32_t, QByteArray>::const_iterator itr = keyPairs.begin(), end = keyPairs.end(); itr != end; ++itr) { LMDBAL::WriteTransaction txn = db.beginTransaction();
preKeyPairs->forceRecord(itr.key(), itr.value()); for (QHash<uint32_t, QByteArray>::const_iterator itr = keyPairs.begin(), end = keyPairs.end(); itr != end; ++itr)
} preKeyPairs->forceRecord(itr.key(), itr.value(), txn);
txn.commit();
return Core::makeReadyTask(); return Core::makeReadyTask();
} }
@ -104,13 +107,15 @@ QXmppTask<void> Core::OmemoHandler::addSignedPreKeyPair(uint32_t keyId, const QX
} }
QXmppTask<void> Core::OmemoHandler::removeDevice(const QString& jid, uint32_t deviceId) { QXmppTask<void> Core::OmemoHandler::removeDevice(const QString& jid, uint32_t deviceId) {
QHash<uint32_t, Device> devs = devices->getRecord(jid); LMDBAL::WriteTransaction txn = db.beginTransaction();
QHash<uint32_t, Device> devs = devices->getRecord(jid, txn);
devs.remove(deviceId); devs.remove(deviceId);
if (devs.isEmpty()) { if (devs.isEmpty())
devices->removeRecord(jid); devices->removeRecord(jid, txn);
} else { else
devices->changeRecord(jid, devs); devices->changeRecord(jid, devs, txn);
}
txn.commit();
return Core::makeReadyTask(); return Core::makeReadyTask();
} }
@ -120,7 +125,11 @@ QXmppTask<void> Core::OmemoHandler::removeDevices(const QString& jid) {
} }
QXmppTask<void> Core::OmemoHandler::removePreKeyPair(uint32_t keyId) { QXmppTask<void> Core::OmemoHandler::removePreKeyPair(uint32_t keyId) {
preKeyPairs->removeRecord(keyId); try {
preKeyPairs->removeRecord(keyId);
} catch (const LMDBAL::NotFound& e) {
qDebug() << "Couldn't remove preKeyPair " << e.what();
}
return Core::makeReadyTask(); return Core::makeReadyTask();
} }
@ -135,15 +144,12 @@ QXmppTask<void> Core::OmemoHandler::setOwnDevice(const std::optional<OwnDevice>&
bool had = ownDevice.has_value(); bool had = ownDevice.has_value();
ownDevice = device; ownDevice = device;
if (ownDevice.has_value()) { if (ownDevice.has_value()) {
if (had) { if (had)
meta->changeRecord("ownDevice", QVariant::fromValue(ownDevice.value())); meta->changeRecord("ownDevice", QVariant::fromValue(ownDevice.value()));
} else { else
meta->addRecord("ownDevice", QVariant::fromValue(ownDevice.value())); meta->addRecord("ownDevice", QVariant::fromValue(ownDevice.value()));
} } else if (had) {
} else { meta->removeRecord("ownDevice");
if (had) {
meta->removeRecord("ownDevice");
}
} }
return Core::makeReadyTask(); return Core::makeReadyTask();
} }
@ -158,7 +164,7 @@ QXmppTask<void> Core::OmemoHandler::resetAll() {
void Core::OmemoHandler::getDevices(const QString& jid, std::list<Shared::KeyInfo>& out) const { void Core::OmemoHandler::getDevices(const QString& jid, std::list<Shared::KeyInfo>& out) const {
QHash<uint32_t, Device> devs; QHash<uint32_t, Device> devs;
try { try {
devs = devices->getRecord(jid); devices->getRecord(jid, devs);
} catch (const LMDBAL::NotFound& error) {} } catch (const LMDBAL::NotFound& error) {}
for (QHash<uint32_t, Device>::const_iterator itr = devs.begin(), end = devs.end(); itr != end; ++itr) { for (QHash<uint32_t, Device>::const_iterator itr = devs.begin(), end = devs.end(); itr != end; ++itr) {
@ -169,6 +175,10 @@ void Core::OmemoHandler::getDevices(const QString& jid, std::list<Shared::KeyInf
void Core::OmemoHandler::requestBundles(const QString& jid) { void Core::OmemoHandler::requestBundles(const QString& jid) {
QXmppTask<void> task = acc->om->buildMissingSessions({jid}); QXmppTask<void> task = acc->om->buildMissingSessions({jid});
Contact* cnt = acc->rh->getContact(jid);
if (cnt)
cnt->omemoBundles = Shared::Possible::discovering;
task.then(this, std::bind(&OmemoHandler::onBundlesReceived, this, jid)); task.then(this, std::bind(&OmemoHandler::onBundlesReceived, this, jid));
} }
@ -191,6 +201,10 @@ void Core::OmemoHandler::onBundlesReceived(const QString& jid) {
} }
} }
Contact* cnt = acc->rh->getContact(jid);
if (cnt)
cnt->omemoBundles = Shared::Possible::present;
acc->delay->receivedBundles(jid, keys); acc->delay->receivedBundles(jid, keys);
} }
@ -217,7 +231,6 @@ void Core::OmemoHandler::onOmemoDeviceAdded(const QString& jid, uint32_t id) {
qDebug() << "OMEMO device added for" << jid; qDebug() << "OMEMO device added for" << jid;
} }
QDataStream & operator >> (QDataStream& in, QXmppOmemoStorage::Device& device) { QDataStream & operator >> (QDataStream& in, QXmppOmemoStorage::Device& device) {
in >> device.label; in >> device.label;
in >> device.keyId; in >> device.keyId;

View File

@ -1,21 +1,21 @@
// Squawk messenger. /*
// Copyright (C) 2019 Yury Gubich <blue@macaw.me> * Squawk messenger.
// * Copyright (C) 2019 Yury Gubich <blue@macaw.me>
// This program is free software: you can redistribute it and/or modify *
// it under the terms of the GNU General Public License as published by * This program is free software: you can redistribute it and/or modify
// the Free Software Foundation, either version 3 of the License, or * it under the terms of the GNU General Public License as published by
// (at your option) any later version. * the Free Software Foundation, either version 3 of the License, or
// * (at your option) any later version.
// This program is distributed in the hope that it will be useful, *
// but WITHOUT ANY WARRANTY; without even the implied warranty of * This program is distributed in the hope that it will be useful,
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * but WITHOUT ANY WARRANTY; without even the implied warranty of
// GNU General Public License for more details. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// You should have received a copy of the GNU General Public License *
// along with this program. If not, see <http://www.gnu.org/licenses/>. * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef CORE_OMEMOHANDLER_H */
#define CORE_OMEMOHANDLER_H #pragma once
#include <map> #include <map>
#include <list> #include <list>
@ -87,5 +87,3 @@ QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::Device& device);
QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::OwnDevice& device); QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::OwnDevice& device);
QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::OwnDevice& device); QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::OwnDevice& device);
#endif // CORE_OMEMOHANDLER_H

View File

@ -28,9 +28,8 @@ Core::TrustHandler::TrustHandler(Account* account):
ownKeys(db.addCache<QString, QByteArray>("ownKeys")), ownKeys(db.addCache<QString, QByteArray>("ownKeys")),
keysByProtocol() keysByProtocol()
{ {
if (!protocols.open(QIODevice::ReadWrite | QIODevice::Text)) { //never supposed to happen since I have just created a directory; if (!protocols.open(QIODevice::ReadWrite | QIODevice::Text)) //never supposed to happen since I have just created a directory;
throw LMDBAL::Directory(protocols.fileName().toStdString()); throw LMDBAL::Directory(protocols.fileName().toStdString());
}
QTextStream in(&protocols); QTextStream in(&protocols);
while(!in.atEnd()) { while(!in.atEnd()) {
@ -53,11 +52,10 @@ Core::TrustHandler::~TrustHandler() {
Core::TrustHandler::KeyCache * Core::TrustHandler::getCache(const QString& encryption) { Core::TrustHandler::KeyCache * Core::TrustHandler::getCache(const QString& encryption) {
std::map<QString, KeyCache*>::iterator itr = keysByProtocol.find(encryption); std::map<QString, KeyCache*>::iterator itr = keysByProtocol.find(encryption);
if (itr == keysByProtocol.end()) { if (itr == keysByProtocol.end())
return createNewCache(encryption); return createNewCache(encryption);
} else { else
return itr->second; return itr->second;
}
} }
Core::TrustHandler::KeyCache * Core::TrustHandler::createNewCache(const QString& encryption) { Core::TrustHandler::KeyCache * Core::TrustHandler::createNewCache(const QString& encryption) {
@ -65,9 +63,9 @@ Core::TrustHandler::KeyCache * Core::TrustHandler::createNewCache(const QString&
KeyCache* cache = db.addCache<QString, Keys>(encryption.toStdString()); KeyCache* cache = db.addCache<QString, Keys>(encryption.toStdString());
keysByProtocol.insert(std::make_pair(encryption, cache)); keysByProtocol.insert(std::make_pair(encryption, cache));
if(!protocols.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { if (!protocols.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
throw LMDBAL::Directory(protocols.fileName().toStdString()); throw LMDBAL::Directory(protocols.fileName().toStdString());
}
QTextStream out(&protocols); QTextStream out(&protocols);
out << encryption + "\n"; out << encryption + "\n";
protocols.close(); protocols.close();
@ -83,10 +81,12 @@ QXmppTask<void> Core::TrustHandler::resetAll(const QString& encryption) {
if (itr == keysByProtocol.end()) if (itr == keysByProtocol.end())
return Core::makeReadyTask(); return Core::makeReadyTask();
LMDBAL::WriteTransaction txn = db.beginTransaction();
KeyCache* cache = itr->second; KeyCache* cache = itr->second;
std::map<QString, Keys> keys = cache->readAll(); std::map<QString, Keys> keys = cache->readAll(txn);
cache->drop(); cache->drop(txn);
txn.commit();
for (const std::pair<const QString, Keys>& pair : keys) { for (const std::pair<const QString, Keys>& pair : keys) {
bool empty = true; bool empty = true;
for (const std::pair<const QByteArray, Shared::TrustLevel>& trust : pair.second) { for (const std::pair<const QByteArray, Shared::TrustLevel>& trust : pair.second) {
@ -105,8 +105,8 @@ QXmppTask<void> Core::TrustHandler::resetAll(const QString& encryption) {
QXmppTask<QXmpp::TrustLevel> Core::TrustHandler::trustLevel( QXmppTask<QXmpp::TrustLevel> Core::TrustHandler::trustLevel(
const QString& encryption, const QString& encryption,
const QString& keyOwnerJid, const QString& keyOwnerJid,
const QByteArray& keyId) const QByteArray& keyId
{ ) {
KeyCache* cache = getCache(encryption); KeyCache* cache = getCache(encryption);
Shared::TrustLevel level = Shared::TrustLevel::undecided; Shared::TrustLevel level = Shared::TrustLevel::undecided;
try { try {
@ -122,15 +122,17 @@ QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::s
const QString& encryption, const QString& encryption,
const QList<QString>& keyOwnerJids, const QList<QString>& keyOwnerJids,
QXmpp::TrustLevel oldTrustLevel, QXmpp::TrustLevel oldTrustLevel,
QXmpp::TrustLevel newTrustLevel) QXmpp::TrustLevel newTrustLevel
{ ) {
QHash<QString, QMultiHash<QString, QByteArray>> modifiedKeys; QHash<QString, QMultiHash<QString, QByteArray>> modifiedKeys;
Shared::TrustLevel oldLevel = convert(oldTrustLevel); Shared::TrustLevel oldLevel = convert(oldTrustLevel);
Shared::TrustLevel newLevel = convert(newTrustLevel); Shared::TrustLevel newLevel = convert(newTrustLevel);
std::set<QString> modifiedJids; std::set<QString> modifiedJids;
KeyCache* cache = getCache(encryption); KeyCache* cache = getCache(encryption);
LMDBAL::WriteTransaction txn = db.beginTransaction();
for (const QString& keyOwnerJid : keyOwnerJids) { for (const QString& keyOwnerJid : keyOwnerJids) {
Keys map = cache->getRecord(keyOwnerJid); Keys map = cache->getRecord(keyOwnerJid, txn);
uint count = 0; uint count = 0;
for (std::pair<const QByteArray, Shared::TrustLevel>& pair : map) { for (std::pair<const QByteArray, Shared::TrustLevel>& pair : map) {
Shared::TrustLevel& current = pair.second; Shared::TrustLevel& current = pair.second;
@ -142,8 +144,9 @@ QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::s
} }
} }
if (count > 0) if (count > 0)
cache->changeRecord(keyOwnerJid, map); cache->changeRecord(keyOwnerJid, map, txn);
} }
txn.commit();
for (const QString& jid : modifiedJids) for (const QString& jid : modifiedJids)
emit trustLevelsChanged(jid, getSummary(jid)); emit trustLevelsChanged(jid, getSummary(jid));
@ -153,18 +156,19 @@ QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::s
QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::setTrustLevel( QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::setTrustLevel(
const QString& encryption, const QString& encryption,
const QMultiHash<QString, QByteArray>& keyIds, const QMultiHash<QString, QByteArray>& keyIds,
QXmpp::TrustLevel trustLevel) QXmpp::TrustLevel trustLevel
{ ) {
QHash<QString, QMultiHash<QString, QByteArray>> modifiedKeys; QHash<QString, QMultiHash<QString, QByteArray>> modifiedKeys;
Shared::TrustLevel level = convert(trustLevel); Shared::TrustLevel level = convert(trustLevel);
std::set<QString> modifiedJids; std::set<QString> modifiedJids;
KeyCache* cache = getCache(encryption); KeyCache* cache = getCache(encryption);
LMDBAL::WriteTransaction txn = db.beginTransaction();
for (MultySB::const_iterator itr = keyIds.begin(), end = keyIds.end(); itr != end; ++itr) { for (MultySB::const_iterator itr = keyIds.begin(), end = keyIds.end(); itr != end; ++itr) {
const QString& keyOwnerJid = itr.key(); const QString& keyOwnerJid = itr.key();
const QByteArray& keyId = itr.value(); const QByteArray& keyId = itr.value();
try { try {
Keys map = cache->getRecord(keyOwnerJid); Keys map = cache->getRecord(keyOwnerJid, txn);
std::pair<Keys::iterator, bool> result = map.insert(std::make_pair(keyId, level)); std::pair<Keys::iterator, bool> result = map.insert(std::make_pair(keyId, level));
bool changed = result.second; bool changed = result.second;
if (!changed && result.first->second != level) { if (!changed && result.first->second != level) {
@ -174,15 +178,16 @@ QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::s
if (changed) { if (changed) {
modifiedKeys[encryption].insert(keyOwnerJid, keyId); modifiedKeys[encryption].insert(keyOwnerJid, keyId);
modifiedJids.insert(keyOwnerJid); modifiedJids.insert(keyOwnerJid);
cache->changeRecord(keyOwnerJid, map); cache->changeRecord(keyOwnerJid, map, txn);
} }
} catch (const LMDBAL::NotFound& e) { } catch (const LMDBAL::NotFound& e) {
Keys map({{keyId, level}}); Keys map({{keyId, level}});
modifiedKeys[encryption].insert(keyOwnerJid, keyId); modifiedKeys[encryption].insert(keyOwnerJid, keyId);
modifiedJids.insert(keyOwnerJid); modifiedJids.insert(keyOwnerJid);
cache->addRecord(keyOwnerJid, map); cache->addRecord(keyOwnerJid, map, txn);
} }
} }
txn.commit();
for (const QString& jid : modifiedJids) for (const QString& jid : modifiedJids)
emit trustLevelsChanged(jid, getSummary(jid)); emit trustLevelsChanged(jid, getSummary(jid));
@ -190,10 +195,11 @@ QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::s
return Core::makeReadyTask(std::move(modifiedKeys)); return Core::makeReadyTask(std::move(modifiedKeys));
} }
QXmppTask<bool> Core::TrustHandler::hasKey(const QString& encryption, QXmppTask<bool> Core::TrustHandler::hasKey(
const QString& keyOwnerJid, const QString& encryption,
QXmpp::TrustLevels trustLevels) const QString& keyOwnerJid,
{ QXmpp::TrustLevels trustLevels
) {
KeyCache* cache = getCache(encryption); KeyCache* cache = getCache(encryption);
bool found = false; bool found = false;
try { try {
@ -211,8 +217,8 @@ QXmppTask<bool> Core::TrustHandler::hasKey(const QString& encryption,
QXmppTask<QHash<QString, QHash<QByteArray, QXmpp::TrustLevel>>> Core::TrustHandler::keys( QXmppTask<QHash<QString, QHash<QByteArray, QXmpp::TrustLevel>>> Core::TrustHandler::keys(
const QString& encryption, const QString& encryption,
const QList<QString>& keyOwnerJids, const QList<QString>& keyOwnerJids,
QXmpp::TrustLevels trustLevels) QXmpp::TrustLevels trustLevels
{ ) {
HSHBTL res; HSHBTL res;
KeyCache* cache = getCache(encryption); KeyCache* cache = getCache(encryption);
@ -233,8 +239,8 @@ QXmppTask<QHash<QString, QHash<QByteArray, QXmpp::TrustLevel>>> Core::TrustHandl
QXmppTask<QHash<QXmpp::TrustLevel, QMultiHash<QString, QByteArray>>> Core::TrustHandler::keys( QXmppTask<QHash<QXmpp::TrustLevel, QMultiHash<QString, QByteArray>>> Core::TrustHandler::keys(
const QString& encryption, const QString& encryption,
QXmpp::TrustLevels trustLevels) QXmpp::TrustLevels trustLevels
{ ) {
QHash<TL, MultySB> res; QHash<TL, MultySB> res;
KeyCache* cache = getCache(encryption); KeyCache* cache = getCache(encryption);
std::map<QString, Keys> storage = cache->readAll(); std::map<QString, Keys> storage = cache->readAll();
@ -253,9 +259,11 @@ QXmppTask<void> Core::TrustHandler::removeKeys(const QString& encryption) {
if (itr == keysByProtocol.end()) if (itr == keysByProtocol.end())
return Core::makeReadyTask(); return Core::makeReadyTask();
LMDBAL::WriteTransaction txn = db.beginTransaction();
KeyCache* cache = itr->second; KeyCache* cache = itr->second;
std::map<QString, Keys> keys = cache->readAll(); std::map<QString, Keys> keys = cache->readAll(txn);
cache->drop(); cache->drop(txn);
txn.commit();
for (const std::pair<const QString, Keys>& pair : keys) { for (const std::pair<const QString, Keys>& pair : keys) {
bool empty = true; bool empty = true;
@ -292,8 +300,9 @@ QXmppTask<void> Core::TrustHandler::removeKeys(const QString& encryption, const
for (const QByteArray& keyId : keyIds) for (const QByteArray& keyId : keyIds)
set.insert(keyId); set.insert(keyId);
LMDBAL::WriteTransaction txn = db.beginTransaction();
KeyCache* cache = getCache(encryption); KeyCache* cache = getCache(encryption);
std::map<QString, Keys> data = cache->readAll(); std::map<QString, Keys> data = cache->readAll(txn);
std::set<QString> modifiedJids; std::set<QString> modifiedJids;
for (std::map<QString, Keys>::iterator cItr = data.begin(), cEnd = data.end(); cItr != cEnd; /*no increment*/) { for (std::map<QString, Keys>::iterator cItr = data.begin(), cEnd = data.end(); cItr != cEnd; /*no increment*/) {
@ -311,10 +320,10 @@ QXmppTask<void> Core::TrustHandler::removeKeys(const QString& encryption, const
else else
++cItr; ++cItr;
} }
if (modifiedJids.size() > 0) { if (modifiedJids.size() > 0)
cache->replaceAll(data); cache->replaceAll(data, txn);
}
txn.commit();
for (const QString& jid : modifiedJids) for (const QString& jid : modifiedJids)
emit trustLevelsChanged(jid, getSummary(jid)); emit trustLevelsChanged(jid, getSummary(jid));
@ -325,14 +334,15 @@ QXmppTask<void> Core::TrustHandler::addKeys(
const QString& encryption, const QString& encryption,
const QString& keyOwnerJid, const QString& keyOwnerJid,
const QList<QByteArray>& keyIds, const QList<QByteArray>& keyIds,
QXmpp::TrustLevel trustLevel) QXmpp::TrustLevel trustLevel
{ ) {
KeyCache* cache = getCache(encryption); KeyCache* cache = getCache(encryption);
Shared::TrustLevel level = convert(trustLevel); Shared::TrustLevel level = convert(trustLevel);
Keys data; Keys data;
bool had = false; bool had = false;
LMDBAL::WriteTransaction txn = db.beginTransaction();
try { try {
data = cache->getRecord(keyOwnerJid); data = cache->getRecord(keyOwnerJid, txn);
had = true; had = true;
} catch (const LMDBAL::NotFound& e) {} } catch (const LMDBAL::NotFound& e) {}
for (const QByteArray& keyId : keyIds) { for (const QByteArray& keyId : keyIds) {
@ -342,10 +352,11 @@ QXmppTask<void> Core::TrustHandler::addKeys(
} }
if (had) if (had)
cache->changeRecord(keyOwnerJid, data); cache->changeRecord(keyOwnerJid, data, txn);
else else
cache->addRecord(keyOwnerJid, data); cache->addRecord(keyOwnerJid, data, txn);
txn.commit();
emit trustLevelsChanged(keyOwnerJid, getSummary(keyOwnerJid)); emit trustLevelsChanged(keyOwnerJid, getSummary(keyOwnerJid));
return Core::makeReadyTask(); return Core::makeReadyTask();
@ -418,9 +429,9 @@ Shared::TrustSummary Core::TrustHandler::getSummary(const QString& jid) const {
try { try {
Keys keys = pair.second->getRecord(jid); Keys keys = pair.second->getRecord(jid);
Shared::EncryptionProtocol protocol = Shared::TrustSummary::protocolValues.at(pair.first); Shared::EncryptionProtocol protocol = Shared::TrustSummary::protocolValues.at(pair.first);
for (const std::pair<const QByteArray, Shared::TrustLevel>& trust : keys) { for (const std::pair<const QByteArray, Shared::TrustLevel>& trust : keys)
result.increment(protocol, trust.second); result.increment(protocol, trust.second);
}
} catch (const LMDBAL::NotFound& e) {} } catch (const LMDBAL::NotFound& e) {}
} }

2
external/qxmpp vendored

@ -1 +1 @@
Subproject commit 9e9c22b16a39c7370fed31c6deea56d8abf72440 Subproject commit 8dda3c9921c34b9e33883b0d140e8de12edc0736

View File

@ -136,6 +136,14 @@ enum class Support {
}; };
Q_ENUM_NS(Support) Q_ENUM_NS(Support)
enum class Possible {
unknown,
discovering,
present,
abscent
};
Q_ENUM_NS(Possible)
enum class TrustLevel { enum class TrustLevel {
/// The key's trust is not decided. /// The key's trust is not decided.
undecided, undecided,

View File

@ -268,7 +268,9 @@ QDataStream& operator<<(QDataStream& out, const Shared::Message& info) {
out << info.rTo; out << info.rTo;
out << info.id; out << info.id;
out << info.body; out << info.body;
out << info.time; quint64 msecs = info.time.toMSecsSinceEpoch();
out << msecs;
out << info.thread; out << info.thread;
out << (quint8)info.type; out << (quint8)info.type;
out << info.outgoing; out << info.outgoing;
@ -297,7 +299,11 @@ QDataStream & operator>>(QDataStream& in, Shared::Message& info) {
in >> info.rTo; in >> info.rTo;
in >> info.id; in >> info.id;
in >> info.body; in >> info.body;
in >> info.time;
quint64 msecs;
in >> msecs;
info.time = QDateTime::fromMSecsSinceEpoch(msecs);
in >> info.thread; in >> info.thread;
quint8 t; quint8 t;
in >> t; in >> t;

View File

@ -32,10 +32,7 @@ Chat::Chat(Models::Account* acc, Models::Contact* p_contact, QWidget* parent):
connect(contact, &Models::Contact::childChanged, this, &Chat::onContactChanged); connect(contact, &Models::Contact::childChanged, this, &Chat::onContactChanged);
#ifdef WITH_OMEMO #ifdef WITH_OMEMO
if (p_contact->hasKeys(Shared::EncryptionProtocol::omemo2)) { updateEncryptionState();
m_ui->encryptionButton->setVisible(true);
updateEncryptionState();
}
#endif #endif
} }
@ -59,9 +56,7 @@ void Chat::onContactChanged(Models::Item* item, int row, int col) {
setAvatar(contact->getAvatarPath()); setAvatar(contact->getAvatarPath());
break; break;
#ifdef WITH_OMEMO #ifdef WITH_OMEMO
case 8: case 8: //[fallthrough]
m_ui->encryptionButton->setVisible(contact->hasKeys(Shared::EncryptionProtocol::omemo2));
break;
case 9: case 9:
updateEncryptionState(); updateEncryptionState();
break; break;
@ -77,11 +72,16 @@ void Chat::updateState() {
} }
void Chat::updateEncryptionState() { void Chat::updateEncryptionState() {
m_ui->encryptionButton->setEnabled(true); if (contact->hasKeys(Shared::EncryptionProtocol::omemo2)) {
if (contact->getEncryption() == Shared::EncryptionProtocol::omemo2) m_ui->encryptionButton->setVisible(true);
m_ui->encryptionButton->setIcon(Shared::icon("lock")); m_ui->encryptionButton->setEnabled(true);
else if (contact->getEncryption() == Shared::EncryptionProtocol::omemo2)
m_ui->encryptionButton->setIcon(Shared::icon("unlock")); m_ui->encryptionButton->setIcon(Shared::icon("lock"));
else
m_ui->encryptionButton->setIcon(Shared::icon("unlock"));
} else {
m_ui->encryptionButton->setVisible(false);
}
} }