1
0
forked from blue/squawk

some new shared classes, little reorganization, preparation to cache client info

This commit is contained in:
Blue 2022-08-22 23:29:43 +03:00
parent 2ae75a4b91
commit 037dabbe06
Signed by untrusted user: blue
GPG Key ID: 9B203B252A63EE38
20 changed files with 297 additions and 32 deletions

View File

@ -12,8 +12,6 @@ target_sources(squawk PRIVATE
conference.h conference.h
contact.cpp contact.cpp
contact.h contact.h
networkaccess.cpp
networkaccess.h
rosteritem.cpp rosteritem.cpp
rosteritem.h rosteritem.h
${SIGNALCATCHER_SOURCE} ${SIGNALCATCHER_SOURCE}
@ -27,3 +25,4 @@ target_include_directories(squawk PRIVATE ${LMDB_INCLUDE_DIRS})
add_subdirectory(handlers) add_subdirectory(handlers)
add_subdirectory(storage) add_subdirectory(storage)
add_subdirectory(passwordStorageEngines) add_subdirectory(passwordStorageEngines)
add_subdirectory(components)

View File

@ -285,7 +285,10 @@ void Core::Account::onPresenceReceived(const QXmppPresence& p_presence)
emit addPresence(jid, resource, { emit addPresence(jid, resource, {
{"lastActivity", lastInteraction}, {"lastActivity", lastInteraction},
{"availability", p_presence.availableStatusType()}, //TODO check and handle invisible {"availability", p_presence.availableStatusType()}, //TODO check and handle invisible
{"status", p_presence.statusText()} {"status", p_presence.statusText()},
{"capabilityNode", p_presence.capabilityNode()},
{"capabilityVer", p_presence.capabilityVer().toBase64()},
{"capabilityHash", p_presence.capabilityHash()}
}); });
} }
break; break;
@ -594,7 +597,8 @@ void Core::Account::onDiscoveryItemsReceived(const QXmppDiscoveryIq& items)
void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info) void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info)
{ {
if (info.from() == getServer()) { QString from = info.from();
if (from == getServer()) {
bool enableCC = false; bool enableCC = false;
qDebug() << "Server info received for account" << name; qDebug() << "Server info received for account" << name;
QStringList features = info.features(); QStringList features = info.features();
@ -613,7 +617,7 @@ void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info)
qDebug() << "Requesting account" << name << "capabilities"; qDebug() << "Requesting account" << name << "capabilities";
dm->requestInfo(getBareJid()); dm->requestInfo(getBareJid());
} else if (info.from() == getBareJid()) { } else if (from == getBareJid()) {
qDebug() << "Received capabilities for account" << name << ":"; qDebug() << "Received capabilities for account" << name << ":";
QList<QXmppDiscoveryIq::Identity> identities = info.identities(); QList<QXmppDiscoveryIq::Identity> identities = info.identities();
bool pepSupported = false; bool pepSupported = false;
@ -626,10 +630,27 @@ void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info)
} }
rh->setPepSupport(pepSupported); rh->setPepSupport(pepSupported);
} else { } else {
qDebug() << "Received info for account" << name << "about" << info.from(); qDebug() << "Received info for account" << name << "about" << from;
QList<QXmppDiscoveryIq::Identity> identities = info.identities(); QString node = info.queryNode();
for (const QXmppDiscoveryIq::Identity& identity : identities) { if (!node.isEmpty()) {
qDebug() << " " << identity.name() << identity.category() << identity.type(); QStringList feats = info.features();
std::list<Shared::Identity> identities;
std::set<QString> features(feats.begin(), feats.end());
QList<QXmppDiscoveryIq::Identity> idents = info.identities();
for (const QXmppDiscoveryIq::Identity& ident : idents) {
identities.emplace_back();
Shared::Identity& identity = identities.back();
identity.category = ident.category();
identity.language = ident.language();
identity.name = ident.name();
identity.type = ident.type();
qDebug() << " " << identity.name << identity.category << identity.type;
}
for (const QString& feat : features) {
qDebug() << " " << feat;
}
emit infoDiscovered(from, node, identities, features);
} }
} }
} }

View File

@ -29,6 +29,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <list>
#include <QXmppRosterManager.h> #include <QXmppRosterManager.h>
#include <QXmppCarbonManager.h> #include <QXmppCarbonManager.h>
@ -42,10 +43,11 @@
#include <QXmppVCardManager.h> #include <QXmppVCardManager.h>
#include <QXmppMessageReceiptManager.h> #include <QXmppMessageReceiptManager.h>
#include "shared/shared.h" #include <shared/shared.h>
#include <shared/identity.h>
#include "contact.h" #include "contact.h"
#include "conference.h" #include "conference.h"
#include "networkaccess.h" #include <core/components/networkaccess.h>
#include "handlers/messagehandler.h" #include "handlers/messagehandler.h"
#include "handlers/rosterhandler.h" #include "handlers/rosterhandler.h"
@ -118,6 +120,8 @@ public:
void resendMessage(const QString& jid, const QString& id); void resendMessage(const QString& jid, const QString& id);
void replaceMessage(const QString& originalId, const Shared::Message& data); void replaceMessage(const QString& originalId, const Shared::Message& data);
void invalidatePassword(); void invalidatePassword();
void discoverInfo(const QString& address, const QString& node);
public slots: public slots:
void connect(); void connect();
@ -151,6 +155,7 @@ signals:
void uploadFile(const QFileInfo& file, const QUrl& set, const QUrl& get, QMap<QString, QString> headers); void uploadFile(const QFileInfo& file, const QUrl& set, const QUrl& get, QMap<QString, QString> headers);
void uploadFileError(const QString& jid, const QString& messageId, const QString& error); void uploadFileError(const QString& jid, const QString& messageId, const QString& error);
void needPassword(); void needPassword();
void infoDiscovered(const QString& address, const QString& node, const std::list<Shared::Identity>& identities, const std::set<QString>& features);
private: private:
QString name; QString name;

View File

@ -0,0 +1,6 @@
target_sources(squawk PRIVATE
networkaccess.cpp
networkaccess.h
clientcache.cpp
clientcache.h
)

View File

@ -0,0 +1,55 @@
// 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
// 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
// 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/>.
#include "clientcache.h"
Core::ClientCache::ClientCache():
requested(),
cache("clients")
{
cache.open();
}
Core::ClientCache::~ClientCache() {
cache.close();
}
void Core::ClientCache::open() {
cache.open();}
void Core::ClientCache::close() {
cache.close();}
bool Core::ClientCache::checkClient(const QString& node, const QString& ver, const QString& hash) {
QString id = node + "/" + ver;
if (requested.count(id) == 0 && !cache.checkRecord(id)) {
Shared::ClientInfo& info = requested.insert(std::make_pair(id, Shared::ClientInfo())).first->second;
info.capabilitiesNode = node;
info.capabilitiesVerification = ver;
info.capabilitiesHash = hash;
emit requestClientInfo(id);
return false;
}
return true;
}
bool Core::ClientCache::registerClientInfo(const QString& sourceFullJid, const QString& id, const Shared::Identity& identity, const std::set<QString>& features) {
}

View File

@ -0,0 +1,56 @@
// 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
// 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
// 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/>.
#ifndef CORE_CLIENTCACHE_H
#define CORE_CLIENTCACHE_H
#include <map>
#include <set>
#include <QObject>
#include <QString>
#include <core/storage/cache.h>
#include <shared/clientinfo.h>
#include <shared/identity.h>
namespace Core {
class ClientCache : public QObject {
Q_OBJECT
public:
ClientCache();
~ClientCache();
void open();
void close();
signals:
void requestClientInfo(const QString& id);
public slots:
bool checkClient(const QString& node, const QString& ver, const QString& hash);
bool registerClientInfo(const QString& sourceFullJid, const QString& id, const Shared::Identity& identity, const std::set<QString>& features);
private:
std::map<QString, Shared::ClientInfo> requested;
Cache<Shared::ClientInfo> cache;
};
}
#endif // CORE_CLIENTCACHE_H

View File

@ -30,8 +30,8 @@
#include <set> #include <set>
#include "storage/urlstorage.h" #include <core/storage/urlstorage.h>
#include "shared/pathcheck.h" #include <shared/pathcheck.h>
namespace Core { namespace Core {

View File

@ -28,9 +28,10 @@ Core::Squawk::Squawk(QObject* parent):
amap(), amap(),
state(Shared::Availability::offline), state(Shared::Availability::offline),
network(), network(),
isInitialized(false) isInitialized(false),
clientCache(),
#ifdef WITH_KWALLET #ifdef WITH_KWALLET
,kwallet() kwallet()
#endif #endif
{ {
connect(&network, &NetworkAccess::loadFileProgress, this, &Squawk::fileProgress); connect(&network, &NetworkAccess::loadFileProgress, this, &Squawk::fileProgress);
@ -67,6 +68,7 @@ void Core::Squawk::stop()
{ {
qDebug("Stopping squawk core.."); qDebug("Stopping squawk core..");
network.stop(); network.stop();
clientCache.close();
if (isInitialized) { if (isInitialized) {
QSettings settings; QSettings settings;
@ -115,6 +117,7 @@ void Core::Squawk::start()
readSettings(); readSettings();
isInitialized = true; isInitialized = true;
network.start(); network.start();
clientCache.open();
} }
void Core::Squawk::newAccountRequest(const QMap<QString, QVariant>& map) void Core::Squawk::newAccountRequest(const QMap<QString, QVariant>& map)
@ -180,6 +183,8 @@ void Core::Squawk::addAccount(
connect(acc, &Account::receivedVCard, this, &Squawk::responseVCard); connect(acc, &Account::receivedVCard, this, &Squawk::responseVCard);
connect(acc, &Account::uploadFileError, this, &Squawk::onAccountUploadFileError); connect(acc, &Account::uploadFileError, this, &Squawk::onAccountUploadFileError);
connect(acc, &Account::infoDiscovered, this, &Squawk::onAccountInfoDiscovered);
QMap<QString, QVariant> map = { QMap<QString, QVariant> map = {
{"login", login}, {"login", login},
@ -314,6 +319,27 @@ void Core::Squawk::onAccountAddPresence(const QString& jid, const QString& name,
{ {
Account* acc = static_cast<Account*>(sender()); Account* acc = static_cast<Account*>(sender());
emit addPresence(acc->getName(), jid, name, data); emit addPresence(acc->getName(), jid, name, data);
QString node = data["capabilityNode"].toString();
QString ver = data["capabilityVer"].toString();
QString hash = data["capabilityHash"].toString();
if (!clientCache.checkClient(node, ver, hash)) {
acc->discoverInfo(jid + "/" + name, node + "/" + ver);
}
}
void Core::Squawk::onAccountInfoDiscovered(
const QString& address,
const QString& node,
const std::list<Shared::Identity>& identities,
const std::set<QString>& features)
{
Account* acc = static_cast<Account*>(sender());
if (identities.size() != 1 || clientCache.registerClientInfo(address, node, identities.back(), features)) {
qDebug() << "Account" << acc->getName() << "received an ill-formed client discovery response from" << address << "about" << node;
return;
}
} }
void Core::Squawk::onAccountRemovePresence(const QString& jid, const QString& name) void Core::Squawk::onAccountRemovePresence(const QString& jid, const QString& name)

View File

@ -32,9 +32,10 @@
#include "shared/message.h" #include "shared/message.h"
#include "shared/global.h" #include "shared/global.h"
#include "shared/clientinfo.h" #include "shared/clientinfo.h"
#include "networkaccess.h"
#include "external/simpleCrypt/simplecrypt.h" #include "external/simpleCrypt/simplecrypt.h"
#include <core/storage/cache.h>
#include <core/components/clientcache.h>
#include <core/components/networkaccess.h>
#ifdef WITH_KWALLET #ifdef WITH_KWALLET
#include "passwordStorageEngines/kwallet.h" #include "passwordStorageEngines/kwallet.h"
@ -137,7 +138,7 @@ private:
Shared::Availability state; Shared::Availability state;
NetworkAccess network; NetworkAccess network;
bool isInitialized; bool isInitialized;
//Cache<Shared::ClientInfo> clientCache; ClientCache clientCache;
#ifdef WITH_KWALLET #ifdef WITH_KWALLET
PSE::KWallet kwallet; PSE::KWallet kwallet;
@ -181,6 +182,8 @@ private slots:
void onWalletOpened(bool success); void onWalletOpened(bool success);
void onWalletRejectPassword(const QString& login); void onWalletRejectPassword(const QString& login);
void onAccountInfoDiscovered(const QString& address, const QString& node, const std::list<Shared::Identity>& identities, const std::set<QString>& features);
private: private:
void readSettings(); void readSettings();

View File

@ -1,10 +1,10 @@
target_sources(squawk PRIVATE target_sources(squawk PRIVATE
archive.cpp archive.cpp
archive.h archive.h
storage.cpp storage.hpp
storage.h storage.h
urlstorage.cpp urlstorage.cpp
urlstorage.h urlstorage.h
cache.cpp cache.hpp
cache.h cache.h
) )

View File

@ -18,6 +18,7 @@
#define CORE_CACHE_H #define CORE_CACHE_H
#include <map> #include <map>
#include <set>
#include <QString> #include <QString>
@ -39,12 +40,16 @@ public:
void changeRecord(const QString& key, const T& value); void changeRecord(const QString& key, const T& value);
void removeRecord(const QString& key); void removeRecord(const QString& key);
T getRecord(const QString& key) const; T getRecord(const QString& key) const;
bool checkRecord(const QString& key) const;
private: private:
Core::Storage<T> storage; Core::Storage<T> storage;
std::map<QString, T>* cache; std::map<QString, T>* cache;
std::set<QString>* abscent;
}; };
} }
#include "cache.hpp"
#endif // CORE_CACHE_H #endif // CORE_CACHE_H

View File

@ -14,21 +14,21 @@
// 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/>.
#ifndef CORE_CACHE_HPP
#define CORE_CACHE_HPP
#include "cache.h" #include "cache.h"
#include <shared/clientinfo.h>
template class Core::Cache<Shared::ClientInfo>;
template <class T> template <class T>
Core::Cache<T>::Cache(const QString& name): Core::Cache<T>::Cache(const QString& name):
storage(name), storage(name),
cache(new std::map<QString, T> ()) {} cache(new std::map<QString, T> ()),
abscent(new std::set<QString> ()) {}
template <class T> template <class T>
Core::Cache<T>::~Cache() { Core::Cache<T>::~Cache() {
close(); close();
delete cache; delete cache;
delete abscent;
} }
template <class T> template <class T>
@ -43,27 +43,60 @@ template <class T>
void Core::Cache<T>::addRecord(const QString& key, const T& value) { void Core::Cache<T>::addRecord(const QString& key, const T& value) {
storage.addRecord(key, value); storage.addRecord(key, value);
cache->insert(std::make_pair(key, value)); cache->insert(std::make_pair(key, value));
abscent->erase(key);
} }
template <class T> template <class T>
T Core::Cache<T>::getRecord(const QString& key) const { T Core::Cache<T>::getRecord(const QString& key) const {
typename std::map<QString, T>::const_iterator itr = cache->find(key); typename std::map<QString, T>::const_iterator itr = cache->find(key);
if (itr == cache->end()) { if (itr == cache->end()) {
T value = storage.getRecord(key); if (abscent->count(key) > 0) {
itr = cache->insert(std::make_pair(key, value)).first; throw Archive::NotFound(key, storage.getName().toStdString());
}
try {
T value = storage.getRecord(key);
itr = cache->insert(std::make_pair(key, value)).first;
} catch (const Archive::NotFound& error) {
abscent->insert(key);
throw error;
}
} }
return itr->second; return itr->second;
} }
template<class T>
bool Core::Cache<T>::checkRecord(const QString& key) const {
typename std::map<QString, T>::const_iterator itr = cache->find(key);
if (itr != cache->end())
return true;
if (abscent->count(key) > 0)
return false;
try {
T value = storage.getRecord(key);
itr = cache->insert(std::make_pair(key, value)).first;
} catch (const Archive::NotFound& error) {
return false;
}
return true;
}
template<typename T> template<typename T>
void Core::Cache<T>::changeRecord(const QString& key, const T& value) { void Core::Cache<T>::changeRecord(const QString& key, const T& value) {
storage.changeRecord(key, value); storage.changeRecord(key, value); //there is a non straightforward behaviour: if there was no element at the sorage it will be added
cache->at(key) = value; cache->at(key) = value;
abscent->erase(key); //so... this line here is to make it coherent with the storage
} }
template<typename T> template<typename T>
void Core::Cache<T>::removeRecord(const QString& key) { void Core::Cache<T>::removeRecord(const QString& key) {
storage.removeRecord(key); storage.removeRecord(key);
cache->erase(key); cache->erase(key);
abscent->insert(key);
} }
#endif //CORE_CACHE_HPP

View File

@ -43,6 +43,7 @@ public:
void changeRecord(const QString& key, const T& value); void changeRecord(const QString& key, const T& value);
void removeRecord(const QString& key); void removeRecord(const QString& key);
T getRecord(const QString& key) const; T getRecord(const QString& key) const;
QString getName() const;
private: private:
@ -54,4 +55,6 @@ private:
} }
#include "storage.hpp"
#endif // CORE_STORAGE_H #endif // CORE_STORAGE_H

View File

@ -15,16 +15,14 @@
* 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/>.
*/ */
#ifndef CORE_STORAGE_HPP
#define CORE_STORAGE_HPP
#include <QStandardPaths> #include <QStandardPaths>
#include <QDir> #include <QDir>
#include "storage.h" #include "storage.h"
#include <shared/clientinfo.h>
template class Core::Storage<Shared::ClientInfo>;
template <class T> template <class T>
Core::Storage<T>::Storage(const QString& p_name): Core::Storage<T>::Storage(const QString& p_name):
name(p_name), name(p_name),
@ -202,3 +200,9 @@ void Core::Storage<T>::removeRecord(const QString& key)
mdb_txn_commit(txn); mdb_txn_commit(txn);
} }
} }
template <class T>
QString Core::Storage<T>::getName() const {
return name;}
#endif //CORE_STORAGE_HPP

View File

@ -19,6 +19,7 @@
#include "shared/global.h" #include "shared/global.h"
#include "shared/messageinfo.h" #include "shared/messageinfo.h"
#include "shared/pathcheck.h" #include "shared/pathcheck.h"
#include "shared/identity.h"
#include "main/application.h" #include "main/application.h"
#include "core/signalcatcher.h" #include "core/signalcatcher.h"
#include "core/squawk.h" #include "core/squawk.h"
@ -39,6 +40,9 @@ int main(int argc, char *argv[])
qRegisterMetaType<Shared::VCard>("Shared::VCard"); qRegisterMetaType<Shared::VCard>("Shared::VCard");
qRegisterMetaType<std::list<Shared::Message>>("std::list<Shared::Message>"); qRegisterMetaType<std::list<Shared::Message>>("std::list<Shared::Message>");
qRegisterMetaType<std::list<Shared::MessageInfo>>("std::list<Shared::MessageInfo>"); qRegisterMetaType<std::list<Shared::MessageInfo>>("std::list<Shared::MessageInfo>");
qRegisterMetaType<std::list<Shared::MessageInfo>>("std::list<QString>");
qRegisterMetaType<std::list<Shared::MessageInfo>>("std::set<QString>");
qRegisterMetaType<std::list<Shared::MessageInfo>>("std::list<Shared::Identity>");
qRegisterMetaType<QSet<QString>>("QSet<QString>"); qRegisterMetaType<QSet<QString>>("QSet<QString>");
qRegisterMetaType<Shared::ConnectionState>("Shared::ConnectionState"); qRegisterMetaType<Shared::ConnectionState>("Shared::ConnectionState");
qRegisterMetaType<Shared::Availability>("Shared::Availability"); qRegisterMetaType<Shared::Availability>("Shared::Availability");

View File

@ -20,4 +20,5 @@ target_sources(squawk PRIVATE
pathcheck.h pathcheck.h
clientinfo.h clientinfo.h
clientinfo.cpp clientinfo.cpp
identity.h
) )

View File

@ -23,8 +23,14 @@ Shared::ClientInfo::ClientInfo():
capabilitiesNode(), capabilitiesNode(),
capabilitiesVerification(), capabilitiesVerification(),
capabilitiesHash(), capabilitiesHash(),
specificPresence(),
capabilitiesExtensions() {} capabilitiesExtensions() {}
QString Shared::ClientInfo::getId() const {
return capabilitiesNode + "/" + capabilitiesVerification;
}
QDataStream & Shared::ClientInfo::operator >> (QDataStream& stream) const { QDataStream & Shared::ClientInfo::operator >> (QDataStream& stream) const {
stream << name; stream << name;
stream << category; stream << category;

View File

@ -29,6 +29,8 @@ class ClientInfo
public: public:
ClientInfo(); ClientInfo();
QString getId() const;
QDataStream& operator << (QDataStream& stream); QDataStream& operator << (QDataStream& stream);
QDataStream& operator >> (QDataStream& stream) const; QDataStream& operator >> (QDataStream& stream) const;
@ -39,6 +41,7 @@ public:
QString capabilitiesNode; QString capabilitiesNode;
QString capabilitiesVerification; QString capabilitiesVerification;
QString capabilitiesHash; QString capabilitiesHash;
QString specificPresence;
std::set<QString> capabilitiesExtensions; std::set<QString> capabilitiesExtensions;
}; };

35
shared/identity.h Normal file
View File

@ -0,0 +1,35 @@
/*
* 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
* 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
* 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/>.
*/
#ifndef SHARED_IDENTITY_H
#define SHARED_IDENTITY_H
#include <QString>
namespace Shared {
struct Identity {
QString category;
QString language;
QString name;
QString type;
};
}
#endif //SHARED_IDENTITY_H