From 9d688e85964c64c20d59fa40d87ce69ea66bd0e1 Mon Sep 17 00:00:00 2001 From: blue Date: Thu, 2 Nov 2023 19:55:11 -0300 Subject: [PATCH] full transition to lmdbal, DOESNT WORK, DONT TAKE! --- CMakeLists.txt | 11 +- core/account.h | 2 +- core/components/urlstorage.cpp | 96 +-- core/components/urlstorage.h | 2 +- core/handlers/messagehandler.cpp | 2 +- core/handlers/omemohandler.h | 2 +- core/rosteritem.cpp | 34 +- core/storage/archive.cpp | 1181 +++++++-------------------- core/storage/archive.h | 143 +--- core/storage/cache.h | 55 -- core/storage/cache.hpp | 102 --- core/storage/storage.h | 70 -- core/storage/storage.hpp | 226 ----- external/qxmpp | 2 +- external/simpleCrypt/CMakeLists.txt | 2 +- main/main.cpp | 2 +- shared/message.cpp | 306 +++---- shared/message.h | 11 +- 18 files changed, 497 insertions(+), 1752 deletions(-) delete mode 100644 core/storage/cache.h delete mode 100644 core/storage/cache.hpp delete mode 100644 core/storage/storage.h delete mode 100644 core/storage/storage.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d29bb4f..5950c36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ if (WITH_OMEMO) if (PKG_CONFIG_FOUND) pkg_check_modules(OMEMO libomemo-c) if (OMEMO_FOUND) + target_compile_definitions(squawk PRIVATE WITH_OMEMO) message("Building with support of OMEMO") else () message("libomemo-c package wasn't found, trying to build without OMEMO support") @@ -73,7 +74,11 @@ endif () ## QXmpp if (SYSTEM_QXMPP) - find_package(QXmpp CONFIG) + if (WITH_OMEMO) + find_package(QXmpp CONFIG COMPONENTS Omemo) + else () + find_package(QXmpp CONFIG) + endif () if (NOT QXmpp_FOUND) set(SYSTEM_QXMPP OFF) @@ -138,7 +143,6 @@ if (NOT SYSTEM_QXMPP) target_include_directories(squawk PRIVATE ${CMAKE_SOURCE_DIR}/external/qxmpp/src/omemo) target_include_directories(squawk PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/external/qxmpp/src/omemo) set(BUILD_OMEMO ON) - target_compile_definitions(squawk PRIVATE WITH_OMEMO) else () set(BUILD_OMEMO OFF) endif () @@ -150,6 +154,9 @@ if (NOT SYSTEM_QXMPP) endif () else () target_link_libraries(squawk PRIVATE QXmpp::QXmpp) + if (WITH_OMEMO) + target_link_libraries(squawk PRIVATE QXmpp::Omemo) + endif () endif () ## LMDBAL diff --git a/core/account.h b/core/account.h index fe3988c..a9425e7 100644 --- a/core/account.h +++ b/core/account.h @@ -63,7 +63,7 @@ #include "handlers/discoveryhandler.h" #ifdef WITH_OMEMO -#include +#include #include #include "handlers/trusthandler.h" #include "handlers/omemohandler.h" diff --git a/core/components/urlstorage.cpp b/core/components/urlstorage.cpp index c745236..31f36ad 100644 --- a/core/components/urlstorage.cpp +++ b/core/components/urlstorage.cpp @@ -41,18 +41,12 @@ void Core::UrlStorage::close() { } void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, bool overwrite) { - LMDBAL::TransactionID txn = base.beginTransaction(); - - try { - writeInfo(key, info, txn, overwrite); - base.commitTransaction(txn); - } catch (...) { - base.abortTransaction(txn); - throw; - } + LMDBAL::WriteTransaction txn = base.beginTransaction(); + writeInfo(key, info, txn, overwrite); + txn.commit(); } -void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, MDB_txn* txn, bool overwrite) { +void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, const LMDBAL::WriteTransaction& txn, bool overwrite) { if (overwrite) urlToInfo->forceRecord(key, info, txn); else @@ -95,15 +89,11 @@ Core::UrlStorage::UrlInfo Core::UrlStorage::addToInfo( const QString& path ) { UrlInfo info; - LMDBAL::TransactionID txn = base.beginTransaction(); + LMDBAL::WriteTransaction txn = base.beginTransaction(); try { urlToInfo->getRecord(url, info, txn); - } catch (const LMDBAL::NotFound& e) { - } catch (...) { - base.abortTransaction(txn); - throw; - } + } catch (const LMDBAL::NotFound& e) {} bool pathChange = false; bool listChange = false; @@ -118,15 +108,8 @@ Core::UrlStorage::UrlInfo Core::UrlStorage::addToInfo( listChange = info.addMessage(account, jid, id); if (pathChange || listChange) { - try { - writeInfo(url, info, txn, true); - base.commitTransaction(txn); - } catch (...) { - base.abortTransaction(txn); - throw; - } - } else { - base.abortTransaction(txn); + writeInfo(url, info, txn, true); + txn.commit(); } return info; @@ -134,70 +117,51 @@ Core::UrlStorage::UrlInfo Core::UrlStorage::addToInfo( std::list Core::UrlStorage::setPath(const QString& url, const QString& path) { std::list list; - LMDBAL::TransactionID txn = base.beginTransaction(); + LMDBAL::WriteTransaction txn = base.beginTransaction(); UrlInfo info; try { urlToInfo->getRecord(url, info, txn); info.getMessages(list); - } catch (const LMDBAL::NotFound& e) { - } catch (...) { - base.abortTransaction(txn); - throw; - } + } catch (const LMDBAL::NotFound& e) {} info.setPath(path); - try { - writeInfo(url, info, txn, true); - base.commitTransaction(txn); - } catch (...) { - base.abortTransaction(txn); - throw; - } + writeInfo(url, info, txn, true); + txn.commit(); return list; } std::list Core::UrlStorage::removeFile(const QString& url) { std::list list; - LMDBAL::TransactionID txn = base.beginTransaction(); + LMDBAL::WriteTransaction txn = base.beginTransaction(); UrlInfo info; - try { - urlToInfo->getRecord(url, info, txn); - urlToInfo->removeRecord(url); - info.getMessages(list); - - if (info.hasPath()) - pathToUrl->removeRecord(info.getPath()); + urlToInfo->getRecord(url, info, txn); + urlToInfo->removeRecord(url, txn); + info.getMessages(list); - base.commitTransaction(txn); - } catch (...) { - base.abortTransaction(txn); - throw; - } + if (info.hasPath()) + pathToUrl->removeRecord(info.getPath(), txn); + + txn.commit(); return list; } std::list Core::UrlStorage::deletedFile(const QString& path) { std::list list; - LMDBAL::TransactionID txn = base.beginTransaction(); + LMDBAL::WriteTransaction txn = base.beginTransaction(); - try { - QString url = pathToUrl->getRecord(path, txn); - pathToUrl->removeRecord(path); - - UrlInfo info = urlToInfo->getRecord(url, txn); - info.getMessages(list); - info.setPath(QString()); - urlToInfo->changeRecord(url, info, txn); - - base.commitTransaction(txn); - } catch (...) { - base.abortTransaction(txn); - throw; - } + QString url = pathToUrl->getRecord(path, txn); + pathToUrl->removeRecord(path, txn); + + UrlInfo info = urlToInfo->getRecord(url, txn); + info.getMessages(list); + info.setPath(QString()); + urlToInfo->changeRecord(url, info, txn); + + txn.commit(); return list; } diff --git a/core/components/urlstorage.h b/core/components/urlstorage.h index ee8e30d..fc9d71d 100644 --- a/core/components/urlstorage.h +++ b/core/components/urlstorage.h @@ -60,7 +60,7 @@ private: private: void writeInfo(const QString& key, const UrlInfo& info, bool overwrite = false); - void writeInfo(const QString& key, const UrlInfo& info, MDB_txn* txn, bool overwrite = false); + void writeInfo(const QString& key, const UrlInfo& info, const LMDBAL::WriteTransaction& txn, bool overwrite = false); UrlInfo addToInfo(const QString& url, const QString& account, const QString& jid, const QString& id, const QString& path = "-s"); public: diff --git a/core/handlers/messagehandler.cpp b/core/handlers/messagehandler.cpp index 3ed8dec..2632848 100644 --- a/core/handlers/messagehandler.cpp +++ b/core/handlers/messagehandler.cpp @@ -591,7 +591,7 @@ void Core::MessageHandler::resendMessage(const QString& jid, const QString& id) } else { qDebug() << "An attempt to resend a message to" << jid << "by account" << acc->getName() << ", but this message seems to have been normally sent, this method was made to retry sending failed to be sent messages, skipping"; } - } catch (const Archive::NotFound& err) { + } catch (const LMDBAL::NotFound& err) { qDebug() << "An attempt to resend a message to" << jid << "by account" << acc->getName() << ", but this message wasn't found in history, skipping"; } } else { diff --git a/core/handlers/omemohandler.h b/core/handlers/omemohandler.h index 1ea1f26..e626b4c 100644 --- a/core/handlers/omemohandler.h +++ b/core/handlers/omemohandler.h @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include diff --git a/core/rosteritem.cpp b/core/rosteritem.cpp index 545e47f..afbf836 100644 --- a/core/rosteritem.cpp +++ b/core/rosteritem.cpp @@ -27,7 +27,7 @@ Core::RosterItem::RosterItem(const QString& pJid, const QString& pAccount, QObje account(pAccount), name(), archiveState(empty), - archive(new Archive(jid)), + archive(new Archive(account, jid)), syncronizing(false), requestedCount(0), requestedBefore(), @@ -38,7 +38,7 @@ Core::RosterItem::RosterItem(const QString& pJid, const QString& pAccount, QObje toCorrect(), muc(false) { - archive->open(account); + archive->open(); if (archive->size() != 0) { if (archive->isFromTheBeginning()) @@ -126,7 +126,8 @@ void Core::RosterItem::nextRequest() { last = true; } } - } catch (const Archive::Empty& e) { + //} catch (const Archive::Empty& e) { + } catch (const LMDBAL::NotFound& e) { last = true; } } else if (archiveState == empty && responseCache.size() == 0) { @@ -168,7 +169,8 @@ void Core::RosterItem::performRequest(int count, const QString& before) { try { Shared::Message msg = archive->newest(); emit needHistory("", getId(msg), msg.getTime()); - } catch (const Archive::Empty& e) { //this can happen when the only message in archive is not server stored (error, for example) + //} catch (const Archive::Empty& e) { + } catch (const LMDBAL::NotFound& e) { //this can happen when the only message in archive is not server stored (error, for example) emit needHistory(before, ""); } } @@ -186,14 +188,14 @@ void Core::RosterItem::performRequest(int count, const QString& before) { std::list arc = archive->getBefore(requestedCount - responseCache.size(), lBefore); responseCache.insert(responseCache.begin(), arc.begin(), arc.end()); found = true; - } catch (const Archive::NotFound& e) { - requestCache.emplace_back(requestedCount, before); - requestedCount = -1; - emit needHistory(getId(archive->oldest()), ""); - } catch (const Archive::Empty& e) { + } catch (const LMDBAL::NotFound& e) { requestCache.emplace_back(requestedCount, before); requestedCount = -1; emit needHistory(getId(archive->oldest()), ""); + // } catch (const Archive::Empty& e) { + // requestCache.emplace_back(requestedCount, before); + // requestedCount = -1; + // emit needHistory(getId(archive->oldest()), ""); } if (found) { @@ -226,10 +228,10 @@ void Core::RosterItem::performRequest(int count, const QString& before) { try { std::list arc = archive->getBefore(requestedCount - responseCache.size(), before); responseCache.insert(responseCache.begin(), arc.begin(), arc.end()); - } catch (const Archive::NotFound& e) { - qDebug("requesting id hasn't been found in archive, skipping"); - } catch (const Archive::Empty& e) { + } catch (const LMDBAL::NotFound& e) { qDebug("requesting id hasn't been found in archive, skipping"); + // } catch (const Archive::Empty& e) { + // qDebug("requesting id hasn't been found in archive, skipping"); } nextRequest(); break; @@ -311,7 +313,7 @@ bool Core::RosterItem::changeMessage(const QString& id, const QMapchangeMessage(id, data); found = true; - } catch (const Archive::NotFound& e) { + } catch (const LMDBAL::NotFound& e) { qDebug() << "An attempt to change state to the message" << id << "but it couldn't be found"; } } @@ -387,10 +389,8 @@ void Core::RosterItem::flushMessagesToArchive(bool finished, const QString& firs std::list arc = archive->getBefore(requestedCount - responseCache.size(), before); responseCache.insert(responseCache.begin(), arc.begin(), arc.end()); found = true; - } catch (const Archive::NotFound& e) { - - } catch (const Archive::Empty& e) { - + } catch (const LMDBAL::NotFound& e) { + // } catch (const Archive::Empty& e) { } if (!found || requestedCount > int(responseCache.size())) { if (archiveState == complete) { diff --git a/core/storage/archive.cpp b/core/storage/archive.cpp index 8330cff..6b00f37 100644 --- a/core/storage/archive.cpp +++ b/core/storage/archive.cpp @@ -24,858 +24,310 @@ #include #include -Core::Archive::Archive(const QString& p_jid, QObject* parent): +Core::Archive::Archive(const QString& account, const QString& p_jid, QObject* parent): QObject(parent), jid(p_jid), + account(account), opened(false), - fromTheBeginning(false), - encryptionEnabled(false), - environment(), - main(), - order(), - stats(), - avatars() -{ -} + db(account + "/" + jid), + messages(db.addStorage("messages")), + order(db.addStorage("order")), + stats(db.addStorage("stats")), + avatars(db.addStorage("avatars")), + stanzaIdToId(db.addStorage("stanzaIdToId")), + cursor(order->createCursor()) +{} -Core::Archive::~Archive() -{ +Core::Archive::~Archive() { close(); } -void Core::Archive::open(const QString& account) -{ - if (!opened) { - mdb_env_create(&environment); - QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); - path += "/" + account + "/" + jid; - QDir cache(path); - - if (!cache.exists()) { - bool res = cache.mkpath(path); - if (!res) { - throw Directory(path.toStdString()); - } - } - - mdb_env_set_maxdbs(environment, 5); - mdb_env_set_mapsize(environment, -#ifdef Q_OS_WIN - // On Windows, the file is immediately allocated. - // So we have to limit the size. - 80UL * 1024UL * 1024UL -#else - 512UL * 1024UL * 1024UL -#endif - ); - mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - mdb_dbi_open(txn, "main", MDB_CREATE, &main); - mdb_dbi_open(txn, "order", MDB_CREATE | MDB_INTEGERKEY | MDB_INTEGERDUP | MDB_DUPSORT, &order); - mdb_dbi_open(txn, "stats", MDB_CREATE, &stats); - mdb_dbi_open(txn, "avatars", MDB_CREATE, &avatars); - mdb_dbi_open(txn, "sid", MDB_CREATE, &sid); - mdb_txn_commit(txn); - - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - try { - fromTheBeginning = getStatBoolValue("beginning", txn); - } catch (const NotFound& e) { - fromTheBeginning = false; - } +void Core::Archive::open() { + db.open(); + LMDBAL::WriteTransaction txn = db.beginTransaction(); - try { - encryptionEnabled = getStatBoolValue("encryptionEnabled", txn); - } catch (const NotFound& e) { - encryptionEnabled = false; - } - - std::string sJid = jid.toStdString(); - AvatarInfo info; - bool hasAvatar = readAvatarInfo(info, sJid, txn); - mdb_txn_abort(txn); - - if (hasAvatar) { - QFile ava(path + "/" + sJid.c_str() + "." + info.type); - if (!ava.exists()) { - bool success = dropAvatar(sJid); - if (!success) { - qDebug() << "error opening archive" << jid << "for account" << account - << ". There is supposed to be avatar but the file doesn't exist, couldn't even drop it, it surely will lead to an error"; - } - } - } - - opened = true; - } -} - -void Core::Archive::close() -{ - if (opened) { - mdb_dbi_close(environment, sid); - mdb_dbi_close(environment, avatars); - mdb_dbi_close(environment, stats); - mdb_dbi_close(environment, order); - mdb_dbi_close(environment, main); - mdb_env_close(environment); - opened = false; - } -} - -bool Core::Archive::addElement(const Shared::Message& message) -{ - if (!opened) { - throw Closed("addElement", jid.toStdString()); - } - qDebug() << "Adding message with id " << message.getId(); - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - message.serialize(ds); - quint64 stamp = message.getTime().toMSecsSinceEpoch(); - const std::string& id = message.getId().toStdString(); - - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - lmdbData.mv_size = ba.size(); - lmdbData.mv_data = (uint8_t*)ba.data(); - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - int rc; - rc = mdb_put(txn, main, &lmdbKey, &lmdbData, MDB_NOOVERWRITE); - if (rc == 0) { - MDB_val orderKey; - orderKey.mv_size = 8; - orderKey.mv_data = (uint8_t*) &stamp; - - rc = mdb_put(txn, order, &orderKey, &lmdbKey, 0); - if (rc) { - qDebug() << "An element couldn't be inserted into the index" << mdb_strerror(rc); - mdb_txn_abort(txn); - return false; - } else { - if (message.getStanzaId().size() > 0) { - const std::string& szid = message.getStanzaId().toStdString(); - - lmdbKey.mv_size = szid.size(); - lmdbKey.mv_data = (char*)szid.c_str(); - lmdbData.mv_size = id.size(); - lmdbData.mv_data = (uint8_t*)id.data(); - rc = mdb_put(txn, sid, &lmdbKey, &lmdbData, MDB_NOOVERWRITE); - - if (rc) { - qDebug() << "An element stanzaId to id pair couldn't be inserted into the archive" << mdb_strerror(rc); - mdb_txn_abort(txn); - return false; - } else { - rc = mdb_txn_commit(txn); - if (rc) { - qDebug() << "A transaction error: " << mdb_strerror(rc); - return false; - } - return true; - } - - } else { - rc = mdb_txn_commit(txn); - if (rc) { - qDebug() << "A transaction error: " << mdb_strerror(rc); - return false; - } - return true; - } - } - } else { - qDebug() << "An element couldn't been added to the archive, skipping" << mdb_strerror(rc); - mdb_txn_abort(txn); - return false; - } -} - -void Core::Archive::clear() -{ - if (!opened) { - throw Closed("clear", jid.toStdString()); - } - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - mdb_drop(txn, main, 0); - mdb_drop(txn, order, 0); - mdb_drop(txn, stats, 0); - mdb_drop(txn, avatars, 0); - mdb_drop(txn, sid, 0); - mdb_txn_commit(txn); -} - -Shared::Message Core::Archive::getElement(const QString& id) const -{ - if (!opened) { - throw Closed("getElement", jid.toStdString()); - } - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - + AvatarInfo info; + bool hasAvatar = false; try { - Shared::Message msg = getMessage(id.toStdString(), txn); - mdb_txn_abort(txn); - return msg; + avatars->getRecord(jid, info, txn); + hasAvatar = true; + } catch (const LMDBAL::NotFound& e) {} + + if (!hasAvatar) + return; + + QFile ava(db.getPath() + "/" + jid + "." + info.type); + if (ava.exists()) + return; + + try { + avatars->removeRecord(jid, txn); + txn.commit(); + } catch (const std::exception& e) { + qDebug() << e.what(); + qDebug() << "error opening archive" << jid << "for account" << account + << ". There is supposed to be avatar but the file doesn't exist, couldn't even drop it, it surely will lead to an error"; + } +} + +void Core::Archive::close() { + db.close(); +} + +bool Core::Archive::addElement(const Shared::Message& message) { + QString id = message.getId(); + qDebug() << "Adding message with id " << id; + + try { + LMDBAL::WriteTransaction txn = db.beginTransaction(); + messages->addRecord(id, message, txn); + order->addRecord(message.getTime().toMSecsSinceEpoch(), id, txn); + QString stanzaId = message.getStanzaId(); + if (!stanzaId.isEmpty()) + stanzaIdToId->addRecord(stanzaId, id); + + txn.commit(); + return true; + } catch (const std::exception& e) { + qDebug() << "Could not add message with id " + id; + qDebug() << e.what(); + } + + return false; +} + +void Core::Archive::clear() { + db.drop(); +} + +Shared::Message Core::Archive::getElement(const QString& id) const { + return messages->getRecord(id); +} + +bool Core::Archive::hasElement(const QString& id) const { + return messages->checkRecord(id); +} + +void Core::Archive::changeMessage(const QString& id, const QMap& data) { + LMDBAL::WriteTransaction txn = db.beginTransaction(); + Shared::Message msg = messages->getRecord(id, txn); + + bool hadStanzaId = !msg.getStanzaId().isEmpty(); + QDateTime oTime = msg.getTime(); + bool idChange = msg.change(data); + QString newId = msg.getId(); + QDateTime nTime = msg.getTime(); + + bool orderChange = oTime != nTime; + if (idChange || orderChange) { + if (idChange) + messages->removeRecord(id, txn); + + if (orderChange) + order->removeRecord(oTime.toMSecsSinceEpoch(), txn); + + order->forceRecord(nTime.toMSecsSinceEpoch(), newId, txn); + } + + QString sid = msg.getStanzaId(); + if (!sid.isEmpty() && (idChange || !hadStanzaId)) + stanzaIdToId->forceRecord(sid, newId, txn); + + messages->forceRecord(newId, msg, txn); + txn.commit(); +} + +Shared::Message Core::Archive::newest() const { + LMDBAL::Transaction txn = db.beginReadOnlyTransaction(); + + try { + cursor.open(txn); + while (true) { + std::pair pair = cursor.prev(); + Shared::Message msg = messages->getRecord(pair.second, txn); + if (msg.serverStored()) { + cursor.close(); + return msg; + } + } } catch (...) { - mdb_txn_abort(txn); + cursor.close(); throw; } } -bool Core::Archive::hasElement(const QString& id) const -{ - if (!opened) { - throw Closed("hasElement", jid.toStdString()); - } - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - - bool has; - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.toStdString().c_str(); - int rc = mdb_get(txn, main, &lmdbKey, &lmdbData); - has = rc == 0; - mdb_txn_abort(txn); - - return has; -} - -Shared::Message Core::Archive::getMessage(const std::string& id, MDB_txn* txn) const -{ - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - int rc = mdb_get(txn, main, &lmdbKey, &lmdbData); - - if (rc == 0) { - QByteArray ba((char*)lmdbData.mv_data, lmdbData.mv_size); - QDataStream ds(&ba, QIODevice::ReadOnly); - - Shared::Message msg; - msg.deserialize(ds); - - return msg; - } else if (rc == MDB_NOTFOUND) { - throw NotFound(id, jid.toStdString()); - } else { - throw Unknown(jid.toStdString(), mdb_strerror(rc)); - } -} - -void Core::Archive::changeMessage(const QString& id, const QMap& data) -{ - if (!opened) { - throw Closed("setMessageState", jid.toStdString()); - } - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - - std::string strId(id.toStdString()); - try { - Shared::Message msg = getMessage(strId, txn); - bool hadStanzaId = msg.getStanzaId().size() > 0; - QDateTime oTime = msg.getTime(); - bool idChange = msg.change(data); - QDateTime nTime = msg.getTime(); - bool orderChange = oTime != nTime; - - MDB_val lmdbKey, lmdbData; - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - msg.serialize(ds); - - lmdbKey.mv_size = strId.size(); - lmdbKey.mv_data = (char*)strId.c_str(); - int rc; - if (idChange || orderChange) { - if (idChange) { - rc = mdb_del(txn, main, &lmdbKey, &lmdbData); - } else { - quint64 ostamp = oTime.toMSecsSinceEpoch(); - lmdbData.mv_data = (quint8*)&ostamp; - lmdbData.mv_size = 8; - rc = mdb_del(txn, order, &lmdbData, &lmdbKey); - } - if (rc == 0) { - strId = msg.getId().toStdString(); - lmdbKey.mv_size = strId.size(); - lmdbKey.mv_data = (char*)strId.c_str(); - - quint64 stamp = nTime.toMSecsSinceEpoch(); - lmdbData.mv_data = (quint8*)&stamp; - lmdbData.mv_size = 8; - rc = mdb_put(txn, order, &lmdbData, &lmdbKey, 0); - if (rc != 0) { - throw Unknown(jid.toStdString(), mdb_strerror(rc)); - } - } else { - throw Unknown(jid.toStdString(), mdb_strerror(rc)); - } - } - - QString qsid = msg.getStanzaId(); - if (qsid.size() > 0 && (idChange || !hadStanzaId)) { - std::string szid = qsid.toStdString(); - - lmdbData.mv_size = szid.size(); - lmdbData.mv_data = (char*)szid.c_str(); - rc = mdb_put(txn, sid, &lmdbData, &lmdbKey, 0); - - if (rc != 0) { - throw Unknown(jid.toStdString(), mdb_strerror(rc)); - } - }; - - lmdbData.mv_size = ba.size(); - lmdbData.mv_data = (uint8_t*)ba.data(); - rc = mdb_put(txn, main, &lmdbKey, &lmdbData, 0); - if (rc == 0) { - rc = mdb_txn_commit(txn); - } else { - throw Unknown(jid.toStdString(), mdb_strerror(rc)); - } - - } catch (...) { - mdb_txn_abort(txn); - throw; - } -} - -Shared::Message Core::Archive::newest() -{ - return edge(true); -} - -QString Core::Archive::newestId() -{ - if (!opened) { - throw Closed("newestId", jid.toStdString()); - } +QString Core::Archive::newestId() const { Shared::Message msg = newest(); return msg.getId(); } -QString Core::Archive::oldestId() -{ - if (!opened) { - throw Closed("oldestId", jid.toStdString()); - } +QString Core::Archive::oldestId() const { Shared::Message msg = oldest(); return msg.getId(); } -Shared::Message Core::Archive::oldest() -{ - return edge(false); -} +Shared::Message Core::Archive::oldest() const { + LMDBAL::Transaction txn = db.beginReadOnlyTransaction(); -Shared::Message Core::Archive::edge(bool end) -{ - QString name; - MDB_cursor_op begin; - MDB_cursor_op iteration; - if (end) { - name = "newest"; - begin = MDB_LAST; - iteration = MDB_PREV; - } else { - name = "oldest"; - begin = MDB_FIRST; - iteration = MDB_NEXT; - } - - - if (!opened) { - throw Closed(name.toStdString(), jid.toStdString()); - } - - MDB_txn *txn; - MDB_cursor* cursor; - MDB_val lmdbKey, lmdbData; - int rc; - rc = mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - rc = mdb_cursor_open(txn, order, &cursor); - rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, begin); - - Shared::Message msg = getStoredMessage(txn, cursor, iteration, &lmdbKey, &lmdbData, rc); - - mdb_cursor_close(cursor); - mdb_txn_abort(txn); - - if (rc) { - qDebug() << "Error geting" << name << "message" << mdb_strerror(rc); - throw Empty(jid.toStdString()); - } else { - return msg; - } -} - -Shared::Message Core::Archive::getStoredMessage(MDB_txn *txn, MDB_cursor* cursor, MDB_cursor_op op, MDB_val* key, MDB_val* value, int& rc) -{ - Shared::Message msg; - std::string sId; - while (true) { - if (rc) { - break; - } - sId = std::string((char*)value->mv_data, value->mv_size); - - try { - msg = getMessage(sId, txn); + try { + cursor.open(txn); + while (true) { + std::pair pair = cursor.next(); + Shared::Message msg = messages->getRecord(pair.second, txn); if (msg.serverStored()) { - break; - } else { - rc = mdb_cursor_get(cursor, key, value, op); + cursor.close(); + return msg; } - } catch (...) { - break; } + } catch (...) { + cursor.close(); + throw; } - - return msg; } -unsigned int Core::Archive::addElements(const std::list& messages) -{ - if (!opened) { - throw Closed("addElements", jid.toStdString()); - } - - int success = 0; - int rc = 0; - MDB_val lmdbKey, lmdbData; - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - std::list::const_iterator itr = messages.begin(); - while (rc == 0 && itr != messages.end()) { - const Shared::Message& message = *itr; - - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - message.serialize(ds); - quint64 stamp = message.getTime().toMSecsSinceEpoch(); - const std::string& id = message.getId().toStdString(); - - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - lmdbData.mv_size = ba.size(); - lmdbData.mv_data = (uint8_t*)ba.data(); - - rc = mdb_put(txn, main, &lmdbKey, &lmdbData, MDB_NOOVERWRITE); - if (rc == 0) { - MDB_val orderKey; - orderKey.mv_size = 8; - orderKey.mv_data = (uint8_t*) &stamp; - - rc = mdb_put(txn, order, &orderKey, &lmdbKey, 0); - if (rc) { - qDebug() << "An element couldn't be inserted into the index, aborting the transaction" << mdb_strerror(rc); - } else { - if (message.getStanzaId().size() > 0) { - const std::string& szid = message.getStanzaId().toStdString(); - - lmdbKey.mv_size = szid.size(); - lmdbKey.mv_data = (char*)szid.c_str(); - lmdbData.mv_size = id.size(); - lmdbData.mv_data = (uint8_t*)id.data(); - rc = mdb_put(txn, sid, &lmdbKey, &lmdbData, MDB_NOOVERWRITE); - - if (rc) { - qDebug() << "During bulk add an element stanzaId to id pair couldn't be inserted into the archive, continuing without stanzaId" << mdb_strerror(rc); - } - - } - success++; - } - } else { - if (rc == MDB_KEYEXIST) { - rc = 0; - } else { - qDebug() << "An element couldn't been added to the archive, aborting the transaction" << mdb_strerror(rc); - } - } - itr++; - } - - if (rc != 0) { - mdb_txn_abort(txn); - success = 0; - } else { - mdb_txn_commit(txn); +unsigned int Core::Archive::addElements(const std::list& messages) { + unsigned int success = 0; + LMDBAL::WriteTransaction txn = db.beginTransaction(); + for (const Shared::Message& message : messages) { + QString id = message.getId(); + bool added = false; + try { + Core::Archive::messages->addRecord(id, message, txn); + added = true; + } catch (const LMDBAL::Exist& e) {} + + if (!added) + continue; + + order->addRecord(message.getTime().toMSecsSinceEpoch(), id); + + QString sid = message.getStanzaId(); + if (!sid.isEmpty()) + stanzaIdToId->addRecord(sid, id); + + ++success; } return success; } -long unsigned int Core::Archive::size() const -{ - if (!opened) { - throw Closed("size", jid.toStdString()); - } - MDB_txn *txn; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - MDB_stat stat; - mdb_stat(txn, order, &stat); - size_t amount = stat.ms_entries; - mdb_txn_abort(txn); - return amount; +long unsigned int Core::Archive::size() const { + return order->count(); } -std::list Core::Archive::getBefore(int count, const QString& id) -{ - if (!opened) { - throw Closed("getBefore", jid.toStdString()); - } - std::list res; - MDB_cursor* cursor; - MDB_txn *txn; - MDB_val lmdbKey, lmdbData; - int rc; - rc = mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - rc = mdb_cursor_open(txn, order, &cursor); - if (id == "") { - rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_LAST); - if (rc) { - qDebug() << "Error getting before" << mdb_strerror(rc) << ", id:" << id; - mdb_cursor_close(cursor); - mdb_txn_abort(txn); - - throw Empty(jid.toStdString()); - } - } else { - std::string stdId(id.toStdString()); - try { - Shared::Message msg = getMessage(stdId, txn); - quint64 stamp = msg.getTime().toMSecsSinceEpoch(); - lmdbKey.mv_data = (quint8*)&stamp; - lmdbKey.mv_size = 8; - - rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_SET); - - if (rc) { - qDebug() << "Error getting before: couldn't set " << mdb_strerror(rc); - throw NotFound(stdId, jid.toStdString()); - } else { - rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_PREV); - if (rc) { - qDebug() << "Error getting before, couldn't prev " << mdb_strerror(rc); - throw NotFound(stdId, jid.toStdString()); - } - } - - } catch (...) { - mdb_cursor_close(cursor); - mdb_txn_abort(txn); - throw; - } - } - - do { - MDB_val dKey, dData; - dKey.mv_size = lmdbData.mv_size; - dKey.mv_data = lmdbData.mv_data; - rc = mdb_get(txn, main, &dKey, &dData); - if (rc) { - qDebug() <<"Get error: " << mdb_strerror(rc); - std::string sId((char*)lmdbData.mv_data, lmdbData.mv_size); - mdb_cursor_close(cursor); - mdb_txn_abort(txn); - throw NotFound(sId, jid.toStdString()); +std::list Core::Archive::getBefore(unsigned int count, const QString& id) { + LMDBAL::Transaction txn = db.beginReadOnlyTransaction(); + try { + cursor.open(txn); + if (id.isEmpty()) { + cursor.last(); } else { - QByteArray ba((char*)dData.mv_data, dData.mv_size); - QDataStream ds(&ba, QIODevice::ReadOnly); - + Shared::Message reference = messages->getRecord(id, txn); + uint64_t stamp = reference.getTime().toMSecsSinceEpoch(); + cursor.set(stamp); + cursor.prev(); + } + + std::list res; + for (unsigned int i = 0; i < count; ++i) { + std::pair pair; + if (i == 0) + cursor.current(pair.first, pair.second); + else + cursor.prev(pair.first, pair.second); + res.emplace_back(); Shared::Message& msg = res.back(); - msg.deserialize(ds); + messages->getRecord(pair.second, msg, txn); } - - --count; - - } while (count > 0 && mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_PREV) == 0); - - mdb_cursor_close(cursor); - mdb_txn_abort(txn); - return res; -} + cursor.close(); -bool Core::Archive::isFromTheBeginning() const -{ - if (!opened) { - throw Closed("isFromTheBeginning", jid.toStdString()); - } - return fromTheBeginning; -} - -void Core::Archive::setFromTheBeginning(bool is) -{ - if (!opened) { - throw Closed("setFromTheBeginning", jid.toStdString()); - } - if (fromTheBeginning != is) { - fromTheBeginning = is; - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - bool success = setStatValue("beginning", is, txn); - if (success) { - mdb_txn_commit(txn); - } else { - mdb_txn_abort(txn); - } - } -} - -bool Core::Archive::isEncryptionEnabled() const -{ - if (!opened) { - throw Closed("isEncryptionEnabled", jid.toStdString()); - } - return encryptionEnabled; -} - -bool Core::Archive::setEncryptionEnabled(bool is) -{ - if (!opened) { - throw Closed("setEncryptionEnabled", jid.toStdString()); - } - if (encryptionEnabled != is) { - encryptionEnabled = is; - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - bool success = setStatValue("encryptionEnabled", is, txn); - if (success) { - mdb_txn_commit(txn); - return true; - } else { - mdb_txn_abort(txn); - } - } - return false; -} - -QString Core::Archive::idByStanzaId(const QString& stanzaId) const -{ - if (!opened) { - throw Closed("idByStanzaId", jid.toStdString()); - } - QString id; - std::string ssid = stanzaId.toStdString(); - - MDB_txn *txn; - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = ssid.size(); - lmdbKey.mv_data = (char*)ssid.c_str(); - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - int rc = mdb_get(txn, sid, &lmdbKey, &lmdbData); - if (rc == 0) { - id = QString::fromStdString(std::string((char*)lmdbData.mv_data, lmdbData.mv_size)); - } - mdb_txn_abort(txn); - - return id; -} - -QString Core::Archive::stanzaIdById(const QString& id) const -{ - if (!opened) { - throw Closed("stanzaIdById", jid.toStdString()); - } - - try { - Shared::Message msg = getElement(id); - return msg.getStanzaId(); - } catch (const NotFound& e) { - return QString(); - } catch (const Empty& e) { - return QString(); + return res; } catch (...) { + cursor.close(); throw; } } -void Core::Archive::printOrder() -{ - qDebug() << "Printing order"; - MDB_txn *txn; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - MDB_cursor* cursor; - mdb_cursor_open(txn, order, &cursor); - MDB_val lmdbKey, lmdbData; - - mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_FIRST); - - do { - std::string sId((char*)lmdbData.mv_data, lmdbData.mv_size); - qDebug() << QString(sId.c_str()); - } while (mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_NEXT) == 0); - - mdb_cursor_close(cursor); - mdb_txn_abort(txn); -} - -void Core::Archive::printKeys() -{ - MDB_txn *txn; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - MDB_cursor* cursor; - mdb_cursor_open(txn, main, &cursor); - MDB_val lmdbKey, lmdbData; - - mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_FIRST); - - do { - std::string sId((char*)lmdbKey.mv_data, lmdbKey.mv_size); - qDebug() << QString(sId.c_str()); - } while (mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_NEXT) == 0); - - mdb_cursor_close(cursor); - mdb_txn_abort(txn); -} - -bool Core::Archive::getStatBoolValue(const std::string& id, MDB_txn* txn) -{ - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - - int rc; - rc = mdb_get(txn, stats, &lmdbKey, &lmdbData); - if (rc == MDB_NOTFOUND) { - throw NotFound(id, jid.toStdString()); - } else if (rc) { - std::string err(mdb_strerror(rc)); - qDebug() << "error retrieving" << id.c_str() << "from stats db of" << jid << err.c_str(); - throw Unknown(jid.toStdString(), err); - } else { - uint8_t value = *(uint8_t*)(lmdbData.mv_data); - bool is; - if (value == 144) { - is = false; - } else if (value == 72) { - is = true; - } else { - qDebug() << "error retrieving boolean stat" << id.c_str() << ": stored value doesn't match any magic number, the answer is most probably wrong"; - throw NotFound(id, jid.toStdString()); - } - return is; - } -} - -std::string Core::Archive::getStatStringValue(const std::string& id, MDB_txn* txn) -{ - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - - int rc; - rc = mdb_get(txn, stats, &lmdbKey, &lmdbData); - if (rc == MDB_NOTFOUND) { - throw NotFound(id, jid.toStdString()); - } else if (rc) { - std::string err(mdb_strerror(rc)); - qDebug() << "error retrieving" << id.c_str() << "from stats db of" << jid << err.c_str(); - throw Unknown(jid.toStdString(), err); - } else { - std::string value((char*)lmdbData.mv_data, lmdbData.mv_size); - return value; - } -} - -bool Core::Archive::setStatValue(const std::string& id, bool value, MDB_txn* txn) -{ - uint8_t binvalue = 144; - if (value) { - binvalue = 72; - } - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - lmdbData.mv_size = sizeof binvalue; - lmdbData.mv_data = &binvalue; - int rc = mdb_put(txn, stats, &lmdbKey, &lmdbData, 0); - if (rc != 0) { - qDebug() << "Couldn't store" << id.c_str() << "key into stat database:" << mdb_strerror(rc); +bool Core::Archive::isFromTheBeginning() const { + try { + return stats->getRecord("fromTheBeginning").toBool(); + } catch (const LMDBAL::NotFound& e) { return false; } - return true; } -bool Core::Archive::setStatValue(const std::string& id, const std::string& value, MDB_txn* txn) -{ - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - lmdbData.mv_size = value.size(); - lmdbData.mv_data = (char*)value.c_str(); - int rc = mdb_put(txn, stats, &lmdbKey, &lmdbData, 0); - if (rc != 0) { - qDebug() << "Couldn't store" << id.c_str() << "key into stat database:" << mdb_strerror(rc); +void Core::Archive::setFromTheBeginning(bool is) { + stats->forceRecord("fromTheBeginning", is); +} + +bool Core::Archive::isEncryptionEnabled() const { + try { + return stats->getRecord("isEncryptionEnabled").toBool(); + } catch (const LMDBAL::NotFound& e) { return false; } - return true; } -bool Core::Archive::dropAvatar(const std::string& resource) -{ - MDB_txn *txn; - MDB_val lmdbKey; - mdb_txn_begin(environment, NULL, 0, &txn); - lmdbKey.mv_size = resource.size(); - lmdbKey.mv_data = (char*)resource.c_str(); - int rc = mdb_del(txn, avatars, &lmdbKey, NULL); - if (rc != 0) { - mdb_txn_abort(txn); - return false; - } else { - mdb_txn_commit(txn); +bool Core::Archive::setEncryptionEnabled(bool is) { + LMDBAL::WriteTransaction txn = db.beginTransaction(); + bool current = false; + try { + current = stats->getRecord("isEncryptionEnabled").toBool(); + } catch (const LMDBAL::NotFound& e) {} + + if (is != current) { + stats->forceRecord("isEncryptionEnabled", is, txn); + txn.commit(); return true; } + + return false; } -bool Core::Archive::setAvatar(const QByteArray& data, AvatarInfo& newInfo, bool generated, const QString& resource) -{ - if (!opened) { - throw Closed("setAvatar", jid.toStdString()); +QString Core::Archive::idByStanzaId(const QString& stanzaId) const { + return stanzaIdToId->getRecord(stanzaId); +} + +QString Core::Archive::stanzaIdById(const QString& id) const { + try { + Shared::Message msg = getElement(id); + return msg.getStanzaId(); + } catch (const LMDBAL::NotFound& e) { + return QString(); } - +} + +bool Core::Archive::setAvatar(const QByteArray& data, AvatarInfo& newInfo, bool generated, const QString& resource) { + LMDBAL::WriteTransaction txn = db.beginTransaction(); AvatarInfo oldInfo; - bool hasAvatar = readAvatarInfo(oldInfo, resource); - std::string res = resource.size() == 0 ? jid.toStdString() : resource.toStdString(); + bool haveAvatar = false; + QString res = resource.isEmpty() ? jid : resource; + try { + avatars->getRecord(res, oldInfo, txn); + haveAvatar = true; + } catch (const LMDBAL::NotFound& e) {} if (data.size() == 0) { - if (!hasAvatar) { + if (!haveAvatar) return false; - } else { - return dropAvatar(res); - } + + avatars->removeRecord(res, txn); + txn.commit(); + return true; } else { - const char* cep; - mdb_env_get_path(environment, &cep); - QString currentPath(cep); + QString currentPath = db.getPath(); bool needToRemoveOld = false; QCryptographicHash hash(QCryptographicHash::Sha1); hash.addData(data); QByteArray newHash(hash.result()); - if (hasAvatar) { - if (!generated && !oldInfo.autogenerated && oldInfo.hash == newHash) { + if (haveAvatar) { + if (!generated && !oldInfo.autogenerated && oldInfo.hash == newHash) return false; - } - QFile oldAvatar(currentPath + "/" + res.c_str() + "." + oldInfo.type); + + QFile oldAvatar(currentPath + "/" + res + "." + oldInfo.type); if (oldAvatar.exists()) { - if (oldAvatar.rename(currentPath + "/" + res.c_str() + "." + oldInfo.type + ".bak")) { + if (oldAvatar.rename(currentPath + "/" + res + "." + oldInfo.type + ".bak")) { needToRemoveOld = true; } else { qDebug() << "Can't change avatar: couldn't get rid of the old avatar" << oldAvatar.fileName(); @@ -883,161 +335,86 @@ bool Core::Archive::setAvatar(const QByteArray& data, AvatarInfo& newInfo, bool } } } - QMimeDatabase db; - QMimeType type = db.mimeTypeForData(data); + QMimeDatabase mimedb; + QMimeType type = mimedb.mimeTypeForData(data); QString ext = type.preferredSuffix(); - QFile newAvatar(currentPath + "/" + res.c_str() + "." + ext); + QFile newAvatar(currentPath + "/" + res + "." + ext); if (newAvatar.open(QFile::WriteOnly)) { newAvatar.write(data); newAvatar.close(); - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - - MDB_val lmdbKey, lmdbData; - QByteArray value; newInfo.type = ext; newInfo.hash = newHash; newInfo.autogenerated = generated; - newInfo.serialize(&value); - lmdbKey.mv_size = res.size(); - lmdbKey.mv_data = (char*)res.c_str(); - lmdbData.mv_size = value.size(); - lmdbData.mv_data = value.data(); - int rc = mdb_put(txn, avatars, &lmdbKey, &lmdbData, 0); - - if (rc != 0) { + try { + avatars->forceRecord(res, newInfo, txn); + txn.commit(); + } catch (...) { qDebug() << "Can't change avatar: couldn't store changes to database for" << newAvatar.fileName() << "rolling back to the previous state"; if (needToRemoveOld) { - QFile oldAvatar(currentPath + "/" + res.c_str() + "." + oldInfo.type + ".bak"); - oldAvatar.rename(currentPath + "/" + res.c_str() + "." + oldInfo.type); + QFile oldAvatar(currentPath + "/" + res + "." + oldInfo.type + ".bak"); + oldAvatar.rename(currentPath + "/" + res + "." + oldInfo.type); } - mdb_txn_abort(txn); return false; - } else { - mdb_txn_commit(txn); - if (needToRemoveOld) { - QFile oldAvatar(currentPath + "/" + res.c_str() + "." + oldInfo.type + ".bak"); - oldAvatar.remove(); - } - return true; } + + if (needToRemoveOld) { + QFile oldAvatar(currentPath + "/" + res + "." + oldInfo.type + ".bak"); + oldAvatar.remove(); + } + return true; } else { qDebug() << "Can't change avatar: cant open file to write" << newAvatar.fileName() << "rolling back to the previous state"; if (needToRemoveOld) { - QFile oldAvatar(currentPath + "/" + res.c_str() + "." + oldInfo.type + ".bak"); - oldAvatar.rename(currentPath + "/" + res.c_str() + "." + oldInfo.type); + QFile oldAvatar(currentPath + "/" + res + "." + oldInfo.type + ".bak"); + oldAvatar.rename(currentPath + "/" + res + "." + oldInfo.type); } return false; } } } -bool Core::Archive::readAvatarInfo(Core::Archive::AvatarInfo& target, const QString& resource) const -{ - if (!opened) { - throw Closed("readAvatarInfo", jid.toStdString()); - } - std::string res = resource.size() == 0 ? jid.toStdString() : resource.toStdString(); - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - +bool Core::Archive::readAvatarInfo(Core::Archive::AvatarInfo& target, const QString& resource) const { try { - bool success = readAvatarInfo(target, res, txn); - mdb_txn_abort(txn); - return success; - } catch (...) { - mdb_txn_abort(txn); - throw; - } - -} - -bool Core::Archive::readAvatarInfo(Core::Archive::AvatarInfo& target, const std::string& res, MDB_txn* txn) const -{ - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = res.size(); - lmdbKey.mv_data = (char*)res.c_str(); - - int rc; - rc = mdb_get(txn, avatars, &lmdbKey, &lmdbData); - if (rc == MDB_NOTFOUND) { - return false; - } else if (rc) { - std::string err(mdb_strerror(rc)); - qDebug() << "error reading avatar info for" << res.c_str() << "resource of" << jid << err.c_str(); - throw Unknown(jid.toStdString(), err); - } else { - target.deserialize((char*)lmdbData.mv_data, lmdbData.mv_size); + avatars->getRecord(resource.isEmpty() ? jid : resource, target); return true; + } catch (const LMDBAL::NotFound& e) { + return false; } } -void Core::Archive::readAllResourcesAvatars(std::map& data) const -{ - if (!opened) { - throw Closed("readAllResourcesAvatars", jid.toStdString()); - } - - int rc; - MDB_val lmdbKey, lmdbData; - MDB_txn *txn; - MDB_cursor* cursor; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - mdb_cursor_open(txn, avatars, &cursor); - rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_FIRST); - if (rc == 0) { //the db might be empty yet - do { - std::string sId((char*)lmdbKey.mv_data, lmdbKey.mv_size); - QString res(sId.c_str()); - if (res != jid) { - data.emplace(res, AvatarInfo()); - data[res].deserialize((char*)lmdbData.mv_data, lmdbData.mv_size); - } - } while (mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_NEXT) == 0); - } - - mdb_cursor_close(cursor); - mdb_txn_abort(txn); +void Core::Archive::readAllResourcesAvatars(std::map& data) const { + avatars->readAll(data); } -Core::Archive::AvatarInfo Core::Archive::getAvatarInfo(const QString& resource) const -{ - if (!opened) { - throw Closed("readAvatarInfo", jid.toStdString()); - } - - AvatarInfo info; - bool success = readAvatarInfo(info, resource); - if (success) { - return info; - } else { - throw NoAvatar(jid.toStdString(), resource.toStdString()); - } +Core::Archive::AvatarInfo Core::Archive::getAvatarInfo(const QString& resource) const { + return avatars->getRecord(resource); } Core::Archive::AvatarInfo::AvatarInfo(): -type(), -hash(), -autogenerated(false) {} + type(), + hash(), + autogenerated(false) +{} Core::Archive::AvatarInfo::AvatarInfo(const QString& p_type, const QByteArray& p_hash, bool p_autogenerated): -type(p_type), -hash(p_hash), -autogenerated(p_autogenerated) {} + type(p_type), + hash(p_hash), + autogenerated(p_autogenerated) +{} -void Core::Archive::AvatarInfo::deserialize(char* pointer, uint32_t size) -{ - QByteArray data = QByteArray::fromRawData(pointer, size); - QDataStream in(&data, QIODevice::ReadOnly); - - in >> type >> hash >> autogenerated; +QDataStream & operator<<(QDataStream& out, const Core::Archive::AvatarInfo& info) { + out << info.type; + out << info.hash; + out << info.autogenerated; + + return out; } -void Core::Archive::AvatarInfo::serialize(QByteArray* ba) const -{ - QDataStream out(ba, QIODevice::WriteOnly); - - out << type << hash << autogenerated; +QDataStream & operator>>(QDataStream& in, Core::Archive::AvatarInfo& info) { + in >> info.type; + in >> info.hash; + in >> info.autogenerated; + + return in; } diff --git a/core/storage/archive.h b/core/storage/archive.h index ef10555..6f3c9eb 100644 --- a/core/storage/archive.h +++ b/core/storage/archive.h @@ -29,18 +29,21 @@ #include #include +#include +#include +#include + namespace Core { -class Archive : public QObject -{ +class Archive : public QObject { Q_OBJECT public: class AvatarInfo; - Archive(const QString& jid, QObject* parent = 0); + Archive(const QString& account, const QString& jid, QObject* parent = 0); ~Archive(); - void open(const QString& account); + void open(); void close(); bool addElement(const Shared::Message& message); @@ -48,13 +51,13 @@ public: Shared::Message getElement(const QString& id) const; bool hasElement(const QString& id) const; void changeMessage(const QString& id, const QMap& data); - Shared::Message oldest(); - QString oldestId(); - Shared::Message newest(); - QString newestId(); + Shared::Message oldest() const; + QString oldestId() const; + Shared::Message newest() const; + QString newestId() const; void clear(); long unsigned int size() const; - std::list getBefore(int count, const QString& id); + std::list getBefore(unsigned int count, const QString& id); bool isFromTheBeginning() const; void setFromTheBeginning(bool is); bool isEncryptionEnabled() const; @@ -68,103 +71,14 @@ public: public: const QString jid; + const QString account; public: - class Directory: - public Utils::Exception - { - public: - Directory(const std::string& p_path):Exception(), path(p_path){} - - std::string getMessage() const{return "Can't create directory for database at " + path;} - private: - std::string path; - }; - - class Closed: - public Utils::Exception - { - public: - Closed(const std::string& op, const std::string& acc):Exception(), operation(op), account(acc){} - - std::string getMessage() const{return "An attempt to perform operation " + operation + " on closed archive for " + account;} - private: - std::string operation; - std::string account; - }; - - class NotFound: - public Utils::Exception - { - public: - NotFound(const std::string& k, const std::string& acc):Exception(), key(k), account(acc){} - - std::string getMessage() const{return "Element for id " + key + " wasn't found in database " + account;} - private: - std::string key; - std::string account; - }; - - class Empty: - public Utils::Exception - { - public: - Empty(const std::string& acc):Exception(), account(acc){} - - std::string getMessage() const{return "An attempt to read ordered elements from database " + account + " but it's empty";} - private: - std::string account; - }; - - class Exist: - public Utils::Exception - { - public: - Exist(const std::string& acc, const std::string& p_key):Exception(), account(acc), key(p_key){} - - std::string getMessage() const{return "An attempt to insert element " + key + " to database " + account + " but it already has an element with given id";} - private: - std::string account; - std::string key; - }; - - class NoAvatar: - public Utils::Exception - { - public: - NoAvatar(const std::string& el, const std::string& res):Exception(), element(el), resource(res){ - if (resource.size() == 0) { - resource = "for himself"; - } - } - - std::string getMessage() const{return "Element " + element + " has no avatar for " + resource ;} - private: - std::string element; - std::string resource; - }; - - class Unknown: - public Utils::Exception - { - public: - Unknown(const std::string& acc, const std::string& message):Exception(), account(acc), msg(message){} - - std::string getMessage() const{return "Unknown error on database " + account + ": " + msg;} - private: - std::string account; - std::string msg; - }; - - class AvatarInfo { public: AvatarInfo(); AvatarInfo(const QString& type, const QByteArray& hash, bool autogenerated); - void deserialize(char* pointer, uint32_t size); - void serialize(QByteArray* ba) const; - QString type; QByteArray hash; bool autogenerated; @@ -172,29 +86,18 @@ public: private: bool opened; - bool fromTheBeginning; - bool encryptionEnabled; - MDB_env* environment; - MDB_dbi main; //id to message - MDB_dbi order; //time to id - MDB_dbi stats; - MDB_dbi avatars; - MDB_dbi sid; //stanzaId to id - - bool getStatBoolValue(const std::string& id, MDB_txn* txn); - std::string getStatStringValue(const std::string& id, MDB_txn* txn); - - bool setStatValue(const std::string& id, bool value, MDB_txn* txn); - bool setStatValue(const std::string& id, const std::string& value, MDB_txn* txn); - bool readAvatarInfo(AvatarInfo& target, const std::string& res, MDB_txn* txn) const; - void printOrder(); - void printKeys(); - bool dropAvatar(const std::string& resource); - Shared::Message getMessage(const std::string& id, MDB_txn* txn) const; - Shared::Message getStoredMessage(MDB_txn *txn, MDB_cursor* cursor, MDB_cursor_op op, MDB_val* key, MDB_val* value, int& rc); - Shared::Message edge(bool end); + LMDBAL::Base db; + LMDBAL::Storage* messages; + LMDBAL::Storage* order; + LMDBAL::Storage* stats; + LMDBAL::Storage* avatars; + LMDBAL::Storage* stanzaIdToId; + mutable LMDBAL::Cursor cursor; }; } +QDataStream& operator << (QDataStream &out, const Core::Archive::AvatarInfo& info); +QDataStream& operator >> (QDataStream &in, Core::Archive::AvatarInfo& info); + #endif // CORE_ARCHIVE_H diff --git a/core/storage/cache.h b/core/storage/cache.h deleted file mode 100644 index 23f72f0..0000000 --- a/core/storage/cache.h +++ /dev/null @@ -1,55 +0,0 @@ -// Squawk messenger. -// Copyright (C) 2019 Yury Gubich -// -// 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 . - -#ifndef CORE_CACHE_H -#define CORE_CACHE_H - -#include -#include - -#include - -#include - -namespace Core { - -template -class Cache -{ -public: - Cache(const QString& name); - ~Cache(); - - void open(); - void close(); - - void addRecord(const K& key, const V& value); - void changeRecord(const K& key, const V& value); - void removeRecord(const K& key); - V getRecord(const K& key) const; - bool checkRecord(const K& key) const; - -private: - Core::Storage storage; - std::map* cache; - std::set* abscent; -}; - -} - -#include "cache.hpp" - -#endif // CORE_CACHE_H diff --git a/core/storage/cache.hpp b/core/storage/cache.hpp deleted file mode 100644 index 9491de2..0000000 --- a/core/storage/cache.hpp +++ /dev/null @@ -1,102 +0,0 @@ -// Squawk messenger. -// Copyright (C) 2019 Yury Gubich -// -// 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 . - -#ifndef CORE_CACHE_HPP -#define CORE_CACHE_HPP -#include "cache.h" - -template -Core::Cache::Cache(const QString& name): - storage(name), - cache(new std::map ()), - abscent(new std::set ()) {} - -template -Core::Cache::~Cache() { - close(); - delete cache; - delete abscent; -} - -template -void Core::Cache::open() { - storage.open();} - -template -void Core::Cache::close() { - storage.close();} - -template -void Core::Cache::addRecord(const K& key, const V& value) { - storage.addRecord(key, value); - cache->insert(std::make_pair(key, value)); - abscent->erase(key); -} - -template -V Core::Cache::getRecord(const K& key) const { - typename std::map::const_iterator itr = cache->find(key); - if (itr == cache->end()) { - if (abscent->count(key) > 0) { - throw Archive::NotFound(std::to_string(key), storage.getName().toStdString()); - } - - try { - V 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; -} - -template -bool Core::Cache::checkRecord(const K& key) const { - typename std::map::const_iterator itr = cache->find(key); - if (itr != cache->end()) - return true; - - if (abscent->count(key) > 0) - return false; - - try { - V value = storage.getRecord(key); - itr = cache->insert(std::make_pair(key, value)).first; - } catch (const Archive::NotFound& error) { - return false; - } - - return true; -} - -template -void Core::Cache::changeRecord(const K& key, const V& 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; - abscent->erase(key); //so... this line here is to make it coherent with the storage -} - -template -void Core::Cache::removeRecord(const K& key) { - storage.removeRecord(key); - cache->erase(key); - abscent->insert(key); -} - -#endif //CORE_CACHE_HPP diff --git a/core/storage/storage.h b/core/storage/storage.h deleted file mode 100644 index e43ae1a..0000000 --- a/core/storage/storage.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Squawk messenger. - * Copyright (C) 2019 Yury Gubich - * - * 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 . - */ - -#ifndef CORE_STORAGE_H -#define CORE_STORAGE_H - -#include -#include - -#include "archive.h" - -namespace Core { - -/** - * @todo write docs - */ -template -class Storage -{ -public: - Storage(const QString& name); - ~Storage(); - - void open(); - void close(); - - void addRecord(const K& key, const V& value); - void changeRecord(const K& key, const V& value); - void removeRecord(const K& key); - V getRecord(const K& key) const; - QString getName() const; - - -private: - QString name; - bool opened; - MDB_env* environment; - MDB_dbi base; -}; - -} - -MDB_val& operator << (MDB_val& data, QString& value); -MDB_val& operator >> (MDB_val& data, QString& value); - -MDB_val& operator << (MDB_val& data, uint32_t& value); -MDB_val& operator >> (MDB_val& data, uint32_t& value); - -namespace std { - std::string to_string(const QString& str); -} - -#include "storage.hpp" - -#endif // CORE_STORAGE_H diff --git a/core/storage/storage.hpp b/core/storage/storage.hpp deleted file mode 100644 index 33b8b56..0000000 --- a/core/storage/storage.hpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Squawk messenger. - * Copyright (C) 2019 Yury Gubich - * - * 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 . - */ -#ifndef CORE_STORAGE_HPP -#define CORE_STORAGE_HPP - -#include -#include - -#include "storage.h" -#include - -template -Core::Storage::Storage(const QString& p_name): - name(p_name), - opened(false), - environment(), - base() -{ -} - -template -Core::Storage::~Storage() -{ - close(); -} - -template -void Core::Storage::open() -{ - if (!opened) { - mdb_env_create(&environment); - QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); - path += "/" + name; - QDir cache(path); - - if (!cache.exists()) { - bool res = cache.mkpath(path); - if (!res) { - throw Archive::Directory(path.toStdString()); - } - } - - mdb_env_set_maxdbs(environment, 1); - mdb_env_set_mapsize(environment, 10UL * 1024UL * 1024UL); - mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - mdb_dbi_open(txn, "base", MDB_CREATE, &base); - mdb_txn_commit(txn); - opened = true; - } -} - -template -void Core::Storage::close() -{ - if (opened) { - mdb_dbi_close(environment, base); - mdb_env_close(environment); - opened = false; - } -} - -template -void Core::Storage::addRecord(const K& key, const V& value) -{ - if (!opened) { - throw Archive::Closed("addRecord", name.toStdString()); - } - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - ds << value; - - MDB_val lmdbKey, lmdbData; - lmdbKey << key; - - lmdbData.mv_size = ba.size(); - lmdbData.mv_data = (uint8_t*)ba.data(); - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - int rc; - rc = mdb_put(txn, base, &lmdbKey, &lmdbData, MDB_NOOVERWRITE); - if (rc != 0) { - mdb_txn_abort(txn); - if (rc == MDB_KEYEXIST) { - throw Archive::Exist(name.toStdString(), std::to_string(key)); - } else { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - } else { - mdb_txn_commit(txn); - } -} - -template -void Core::Storage::changeRecord(const K& key, const V& value) -{ - if (!opened) { - throw Archive::Closed("changeRecord", name.toStdString()); - } - - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - ds << value; - - MDB_val lmdbKey, lmdbData; - lmdbKey << key; - lmdbData.mv_size = ba.size(); - lmdbData.mv_data = (uint8_t*)ba.data(); - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - int rc; - rc = mdb_put(txn, base, &lmdbKey, &lmdbData, 0); - if (rc != 0) { - mdb_txn_abort(txn); - if (rc) { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - } else { - mdb_txn_commit(txn); - } -} - -template -V Core::Storage::getRecord(const K& key) const -{ - if (!opened) { - throw Archive::Closed("addElement", name.toStdString()); - } - - MDB_val lmdbKey, lmdbData; - lmdbKey << key; - - MDB_txn *txn; - int rc; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - rc = mdb_get(txn, base, &lmdbKey, &lmdbData); - if (rc) { - mdb_txn_abort(txn); - if (rc == MDB_NOTFOUND) { - throw Archive::NotFound(std::to_string(key), name.toStdString()); - } else { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - } else { - QByteArray ba((char*)lmdbData.mv_data, lmdbData.mv_size); - QDataStream ds(&ba, QIODevice::ReadOnly); - V value; - ds >> value; - mdb_txn_abort(txn); - - return value; - } -} - -template -void Core::Storage::removeRecord(const K& key) -{ - if (!opened) { - throw Archive::Closed("addElement", name.toStdString()); - } - - MDB_val lmdbKey; - lmdbKey << key; - - MDB_txn *txn; - int rc; - mdb_txn_begin(environment, NULL, 0, &txn); - rc = mdb_del(txn, base, &lmdbKey, NULL); - if (rc) { - mdb_txn_abort(txn); - if (rc == MDB_NOTFOUND) { - throw Archive::NotFound(std::to_string(key), name.toStdString()); - } else { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - } else { - mdb_txn_commit(txn); - } -} - -template -QString Core::Storage::getName() const { - return name;} - -MDB_val& operator << (MDB_val& data, const QString& value) { - QByteArray ba = value.toUtf8(); - data.mv_size = ba.size(); - data.mv_data = ba.data(); - return data; -} -MDB_val& operator >> (MDB_val& data, QString& value) { - value = QString::fromUtf8((const char*)data.mv_data, data.mv_size); - return data; -} - -MDB_val& operator << (MDB_val& data, uint32_t& value) { - data.mv_size = 4; - data.mv_data = &value; - return data; -} -MDB_val& operator >> (MDB_val& data, uint32_t& value) { - std::memcpy(&value, data.mv_data, data.mv_size); - return data; -} - -std::string std::to_string(const QString& str) { - return str.toStdString(); -} -#endif //CORE_STORAGE_HPP diff --git a/external/qxmpp b/external/qxmpp index ab4bdf2..9e9c22b 160000 --- a/external/qxmpp +++ b/external/qxmpp @@ -1 +1 @@ -Subproject commit ab4bdf2da41a26f462fe3a333a34e32c999e2a6d +Subproject commit 9e9c22b16a39c7370fed31c6deea56d8abf72440 diff --git a/external/simpleCrypt/CMakeLists.txt b/external/simpleCrypt/CMakeLists.txt index 274d304..5f274ba 100644 --- a/external/simpleCrypt/CMakeLists.txt +++ b/external/simpleCrypt/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) project(simplecrypt LANGUAGES CXX) set(CMAKE_AUTOMOC ON) diff --git a/main/main.cpp b/main/main.cpp index d9ad4cc..c8e962f 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -24,7 +24,7 @@ #include #ifdef WITH_OMEMO -#include +#include #endif int main(int argc, char *argv[]) diff --git a/shared/message.cpp b/shared/message.cpp index 0e1b3c5..dab03a3 100644 --- a/shared/message.cpp +++ b/shared/message.cpp @@ -61,50 +61,42 @@ Shared::Message::Message(): attachPath() {} -QString Shared::Message::getBody() const -{ +QString Shared::Message::getBody() const { return body; } -QString Shared::Message::getFrom() const -{ +QString Shared::Message::getFrom() const { QString from = jFrom; - if (rFrom.size() > 0) { + if (rFrom.size() > 0) from += "/" + rFrom; - } + return from; } -QString Shared::Message::getTo() const -{ +QString Shared::Message::getTo() const { QString to = jTo; - if (rTo.size() > 0) { + if (rTo.size() > 0) to += "/" + rTo; - } + return to; } -QString Shared::Message::getId() const -{ - if (id.size() > 0) { +QString Shared::Message::getId() const { + if (id.size() > 0) return id; - } else { + else return stanzaId; - } } -QDateTime Shared::Message::getTime() const -{ +QDateTime Shared::Message::getTime() const { return time; } -void Shared::Message::setBody(const QString& p_body) -{ +void Shared::Message::setBody(const QString& p_body) { body = p_body; } -void Shared::Message::setFrom(const QString& from) -{ +void Shared::Message::setFrom(const QString& from) { QStringList list = from.split("/"); if (list.size() == 1) { jFrom = from.toLower(); @@ -114,8 +106,7 @@ void Shared::Message::setFrom(const QString& from) } } -void Shared::Message::setTo(const QString& to) -{ +void Shared::Message::setTo(const QString& to) { QStringList list = to.split("/"); if (list.size() == 1) { jTo = to.toLower(); @@ -125,153 +116,122 @@ void Shared::Message::setTo(const QString& to) } } -void Shared::Message::setId(const QString& p_id) -{ +void Shared::Message::setId(const QString& p_id) { id = p_id; } -void Shared::Message::setTime(const QDateTime& p_time) -{ +void Shared::Message::setTime(const QDateTime& p_time) { time = p_time; } -QString Shared::Message::getFromJid() const -{ +QString Shared::Message::getFromJid() const { return jFrom; } -QString Shared::Message::getFromResource() const -{ +QString Shared::Message::getFromResource() const { return rFrom; } -QString Shared::Message::getToJid() const -{ +QString Shared::Message::getToJid() const { return jTo; } -QString Shared::Message::getToResource() const -{ +QString Shared::Message::getToResource() const { return rTo; } -QString Shared::Message::getErrorText() const -{ +QString Shared::Message::getErrorText() const { return errorText; } -QString Shared::Message::getPenPalJid() const -{ - if (outgoing) { +QString Shared::Message::getPenPalJid() const { + if (outgoing) return jTo; - } else { + else return jFrom; - } } -QString Shared::Message::getPenPalResource() const -{ - if (outgoing) { +QString Shared::Message::getPenPalResource() const { + if (outgoing) return rTo; - } else { + else return rFrom; - } } -Shared::Message::State Shared::Message::getState() const -{ +Shared::Message::State Shared::Message::getState() const { return state; } -bool Shared::Message::getEdited() const -{ +bool Shared::Message::getEdited() const { return edited; } -void Shared::Message::setFromJid(const QString& from) -{ +void Shared::Message::setFromJid(const QString& from) { jFrom = from.toLower(); } -void Shared::Message::setFromResource(const QString& from) -{ +void Shared::Message::setFromResource(const QString& from) { rFrom = from; } -void Shared::Message::setToJid(const QString& to) -{ +void Shared::Message::setToJid(const QString& to) { jTo = to.toLower(); } -void Shared::Message::setToResource(const QString& to) -{ +void Shared::Message::setToResource(const QString& to) { rTo = to; } -void Shared::Message::setErrorText(const QString& err) -{ - if (state == State::error) { +void Shared::Message::setErrorText(const QString& err) { + if (state == State::error) errorText = err; - } } -bool Shared::Message::getOutgoing() const -{ +bool Shared::Message::getOutgoing() const { return outgoing; } -void Shared::Message::setOutgoing(bool og) -{ +void Shared::Message::setOutgoing(bool og) { outgoing = og; } -bool Shared::Message::getForwarded() const -{ +bool Shared::Message::getForwarded() const { return forwarded; } -void Shared::Message::generateRandomId() -{ +void Shared::Message::generateRandomId() { id = generateUUID(); } -QString Shared::Message::getThread() const -{ +QString Shared::Message::getThread() const { return thread; } -void Shared::Message::setForwarded(bool fwd) -{ +void Shared::Message::setForwarded(bool fwd) { forwarded = fwd; } -void Shared::Message::setThread(const QString& p_body) -{ +void Shared::Message::setThread(const QString& p_body) { thread = p_body; } -QDateTime Shared::Message::getLastModified() const -{ +QDateTime Shared::Message::getLastModified() const { return lastModified; } -QString Shared::Message::getOriginalBody() const -{ +QString Shared::Message::getOriginalBody() const { return originalMessage; } -Shared::Message::Type Shared::Message::getType() const -{ +Shared::Message::Type Shared::Message::getType() const { return type; } -void Shared::Message::setType(Shared::Message::Type t) -{ +void Shared::Message::setType(Shared::Message::Type t) { type = t; } -void Shared::Message::setState(Shared::Message::State p_state) -{ +void Shared::Message::setState(Shared::Message::State p_state) { state = p_state; if (state != State::error) { @@ -279,96 +239,92 @@ void Shared::Message::setState(Shared::Message::State p_state) } } -bool Shared::Message::serverStored() const -{ +bool Shared::Message::serverStored() const { return state == State::delivered || state == State::sent; } -void Shared::Message::setEdited(bool p_edited) -{ +void Shared::Message::setEdited(bool p_edited) { edited = p_edited; } -void Shared::Message::serialize(QDataStream& data) const -{ - data << jFrom; - data << rFrom; - data << jTo; - data << rTo; - data << id; - data << body; - data << time; - data << thread; - data << (quint8)type; - data << outgoing; - data << forwarded; - data << oob; - data << (quint8)state; - data << edited; - if (state == State::error) { - data << errorText; +QDataStream& operator<<(QDataStream& out, const Shared::Message& info) { + out << info.jFrom; + out << info.rFrom; + out << info.jTo; + out << info.rTo; + out << info.id; + out << info.body; + out << info.time; + out << info.thread; + out << (quint8)info.type; + out << info.outgoing; + out << info.forwarded; + out << info.oob; + out << (quint8)info.state; + out << info.edited; + if (info.state == Shared::Message::State::error) + out << info.errorText; + + if (info.edited) { + out << info.originalMessage; + out << info.lastModified; } - if (edited) { - data << originalMessage; - data << lastModified; - } - data << stanzaId; - data << attachPath; + out << info.stanzaId; + out << info.attachPath; + + return out; } -void Shared::Message::deserialize(QDataStream& data) -{ - data >> jFrom; - data >> rFrom; - data >> jTo; - data >> rTo; - data >> id; - data >> body; - data >> time; - data >> thread; +QDataStream & operator>>(QDataStream& in, Shared::Message& info) { + in >> info.jFrom; + in >> info.rFrom; + in >> info.jTo; + in >> info.rTo; + in >> info.id; + in >> info.body; + in >> info.time; + in >> info.thread; quint8 t; - data >> t; - type = static_cast(t); - data >> outgoing; - data >> forwarded; - data >> oob; + in >> t; + info.type = static_cast(t); + in >> info.outgoing; + in >> info.forwarded; + in >> info.oob; quint8 s; - data >> s; - state = static_cast(s); - data >> edited; - if (state == State::error) { - data >> errorText; + in >> s; + info.state = static_cast(s); + in >> info.edited; + if (info.state == Shared::Message::State::error) + in >> info.errorText; + + if (info.edited) { + in >> info.originalMessage; + in >> info.lastModified; } - if (edited) { - data >> originalMessage; - data >> lastModified; - } - data >> stanzaId; - data >> attachPath; + in >> info.stanzaId; + in >> info.attachPath; + + return in; } bool Shared::Message::change(const QMap& data) { QMap::const_iterator itr = data.find("state"); - if (itr != data.end()) { + if (itr != data.end()) setState(static_cast(itr.value().toUInt())); - } itr = data.find("outOfBandUrl"); - if (itr != data.end()) { + if (itr != data.end()) setOutOfBandUrl(itr.value().toString()); - } itr = data.find("attachPath"); - if (itr != data.end()) { + if (itr != data.end()) setAttachPath(itr.value().toString()); - } if (state == State::error) { itr = data.find("errorText"); - if (itr != data.end()) { + if (itr != data.end()) setErrorText(itr.value().toString()); - } } bool idChanged = false; @@ -386,9 +342,8 @@ bool Shared::Message::change(const QMap& data) QString newId = itr.value().toString(); if (stanzaId != newId) { setStanzaId(newId); - if (id.size() == 0) { + if (id.size() == 0) idChanged = true; - } } } @@ -398,15 +353,15 @@ bool Shared::Message::change(const QMap& data) if (body != b) { QMap::const_iterator dItr = data.find("stamp"); QDateTime correctionDate; - if (dItr != data.end()) { + if (dItr != data.end()) correctionDate = dItr.value().toDateTime(); - } else { + else correctionDate = QDateTime::currentDateTimeUtc(); //in case there is no information about time of this correction it's applied - } + if (!edited || lastModified < correctionDate) { - if (!edited) { + if (!edited) originalMessage = body; - } + lastModified = correctionDate; setBody(b); setEdited(true); @@ -416,57 +371,47 @@ bool Shared::Message::change(const QMap& data) QMap::const_iterator dItr = data.find("stamp"); if (dItr != data.end()) { QDateTime ntime = dItr.value().toDateTime(); - if (time != ntime) { + if (time != ntime) setTime(ntime); - } } } return idChanged; } -void Shared::Message::setCurrentTime() -{ +void Shared::Message::setCurrentTime() { time = QDateTime::currentDateTimeUtc(); } -QString Shared::Message::getOutOfBandUrl() const -{ +QString Shared::Message::getOutOfBandUrl() const { return oob; } -bool Shared::Message::hasOutOfBandUrl() const -{ +bool Shared::Message::hasOutOfBandUrl() const { return oob.size() > 0; } -void Shared::Message::setOutOfBandUrl(const QString& url) -{ +void Shared::Message::setOutOfBandUrl(const QString& url) { oob = url; } -bool Shared::Message::storable() const -{ +bool Shared::Message::storable() const { return id.size() > 0 && (body.size() > 0 || oob.size() > 0 || attachPath.size() > 0); } -void Shared::Message::setStanzaId(const QString& sid) -{ +void Shared::Message::setStanzaId(const QString& sid) { stanzaId = sid; } -QString Shared::Message::getStanzaId() const -{ +QString Shared::Message::getStanzaId() const { return stanzaId; } -QString Shared::Message::getAttachPath() const -{ +QString Shared::Message::getAttachPath() const { return attachPath; } -void Shared::Message::setAttachPath(const QString& path) -{ +void Shared::Message::setAttachPath(const QString& path) { attachPath = path; } @@ -474,18 +419,15 @@ Shared::Message::Change::Change(const QMap& _data): data(_data), idModified(false) {} -void Shared::Message::Change::operator()(Shared::Message& msg) -{ +void Shared::Message::Change::operator()(Shared::Message& msg) { idModified = msg.change(data); } -void Shared::Message::Change::operator()(Shared::Message* msg) -{ +void Shared::Message::Change::operator()(Shared::Message* msg) { idModified = msg->change(data); } -bool Shared::Message::Change::hasIdBeenModified() const -{ +bool Shared::Message::Change::hasIdBeenModified() const { return idModified; } diff --git a/shared/message.h b/shared/message.h index aa91af6..557b1b3 100644 --- a/shared/message.h +++ b/shared/message.h @@ -25,12 +25,20 @@ #include #include +namespace Shared { + class Message; +} + +QDataStream& operator << (QDataStream& out, const Shared::Message& info); +QDataStream& operator >> (QDataStream& in, Shared::Message& info); namespace Shared { /** * @todo write docs */ class Message { + friend QDataStream& ::operator << (QDataStream& out, const Shared::Message& info); + friend QDataStream& ::operator >> (QDataStream& in, Shared::Message& info); public: enum Type { error, @@ -116,9 +124,6 @@ public: QString getStanzaId() const; QString getAttachPath() const; - void serialize(QDataStream& data) const; - void deserialize(QDataStream& data); - private: QString jFrom; QString rFrom;