mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
refactor(history): remove deprecated historykeeper
This commit removes historykeeper and code only used by it. BREAKING CHANGE: qTox can't open old historykeeper chatlogs after this commit. Use previous versions to migrate to the new database.
This commit is contained in:
parent
fb43e30677
commit
38cecdc780
|
@ -232,18 +232,10 @@ set(${PROJECT_NAME}_SOURCES
|
|||
src/net/toxuri.h
|
||||
src/nexus.cpp
|
||||
src/nexus.h
|
||||
src/persistence/db/encrypteddb.cpp
|
||||
src/persistence/db/encrypteddb.h
|
||||
src/persistence/db/genericddinterface.cpp
|
||||
src/persistence/db/genericddinterface.h
|
||||
src/persistence/db/plaindb.cpp
|
||||
src/persistence/db/plaindb.h
|
||||
src/persistence/db/rawdatabase.cpp
|
||||
src/persistence/db/rawdatabase.h
|
||||
src/persistence/history.cpp
|
||||
src/persistence/history.h
|
||||
src/persistence/historykeeper.cpp
|
||||
src/persistence/historykeeper.h
|
||||
src/persistence/offlinemsgengine.cpp
|
||||
src/persistence/offlinemsgengine.h
|
||||
src/persistence/profile.cpp
|
||||
|
|
8
qtox.pro
8
qtox.pro
|
@ -458,12 +458,8 @@ HEADERS += \
|
|||
src/net/toxme.h \
|
||||
src/net/toxuri.h \
|
||||
src/nexus.h \
|
||||
src/persistence/db/encrypteddb.h \
|
||||
src/persistence/db/genericddinterface.h \
|
||||
src/persistence/db/plaindb.h \
|
||||
src/persistence/db/rawdatabase.h \
|
||||
src/persistence/history.h \
|
||||
src/persistence/historykeeper.h \
|
||||
src/persistence/offlinemsgengine.h \
|
||||
src/persistence/profile.h \
|
||||
src/persistence/profilelocker.h \
|
||||
|
@ -580,12 +576,8 @@ SOURCES += \
|
|||
src/net/toxme.cpp \
|
||||
src/net/toxuri.cpp \
|
||||
src/nexus.cpp \
|
||||
src/persistence/db/encrypteddb.cpp \
|
||||
src/persistence/db/genericddinterface.cpp \
|
||||
src/persistence/db/plaindb.cpp \
|
||||
src/persistence/db/rawdatabase.cpp \
|
||||
src/persistence/history.cpp \
|
||||
src/persistence/historykeeper.cpp \
|
||||
src/persistence/offlinemsgengine.cpp \
|
||||
src/persistence/profile.cpp \
|
||||
src/persistence/profilelocker.cpp \
|
||||
|
|
|
@ -280,11 +280,6 @@ void Core::start()
|
|||
if (id.isValid()) // TODO: probably useless check, comes basically directly from toxcore
|
||||
emit idSet(id);
|
||||
|
||||
// TODO: This is a backwards compatibility check,
|
||||
// once most people have been upgraded away from the old HistoryKeeper, remove this
|
||||
if (Nexus::getProfile()->isEncrypted())
|
||||
checkEncryptedHistory();
|
||||
|
||||
loadFriends();
|
||||
|
||||
tox_callback_friend_request(tox, onFriendRequest);
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "src/core/cstring.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/profile.h"
|
||||
#include "src/persistence/historykeeper.h"
|
||||
#include <tox/tox.h>
|
||||
#include <tox/toxencryptsave.h>
|
||||
#include <QApplication>
|
||||
|
@ -124,52 +123,3 @@ QByteArray Core::getSaltFromFile(QString filename)
|
|||
QByteArray res(reinterpret_cast<const char*>(salt), TOX_PASS_SALT_LENGTH);
|
||||
return res;
|
||||
}
|
||||
|
||||
void Core::checkEncryptedHistory()
|
||||
{
|
||||
QString path = HistoryKeeper::getHistoryPath();
|
||||
bool exists = QFile::exists(path) && QFile(path).size()>0;
|
||||
if (!exists)
|
||||
return;
|
||||
|
||||
QByteArray salt = getSaltFromFile(path);
|
||||
if (exists && salt.size() == 0)
|
||||
{ // maybe we should handle this better
|
||||
GUI::showWarning(tr("Encrypted chat history"), tr("No encrypted chat history file found, or it was corrupted.\nHistory will be disabled!"));
|
||||
HistoryKeeper::resetInstance();
|
||||
return;
|
||||
}
|
||||
|
||||
auto passkey = createPasskey(Nexus::getProfile()->getPassword(), reinterpret_cast<uint8_t*>(salt.data()));
|
||||
|
||||
QString a(tr("Please enter the password for the chat history for the profile \"%1\".", "used in load() when no hist pw set").arg(Nexus::getProfile()->getName()));
|
||||
QString b(tr("The previous password is incorrect; please try again:", "used on retries in load()"));
|
||||
QString c(tr("\nDisabling chat history now will leave the encrypted history intact (but not usable); if you later remember the password, you may re-enable encryption from the Privacy tab with the correct password to use the history.", "part of history password dialog"));
|
||||
QString dialogtxt;
|
||||
|
||||
|
||||
if (!exists || HistoryKeeper::checkPassword(passkey))
|
||||
return;
|
||||
|
||||
dialogtxt = tr("The chat history password failed. Please try another?", "used only when pw set before load() doesn't work");
|
||||
dialogtxt += "\n" + c;
|
||||
|
||||
bool error = true;
|
||||
do
|
||||
{
|
||||
QString pw = GUI::passwordDialog(tr("Disable chat history"), dialogtxt);
|
||||
|
||||
if (pw.isEmpty())
|
||||
{
|
||||
Settings::getInstance().setEnableLogging(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
passkey = createPasskey(pw, reinterpret_cast<uint8_t*>(salt.data()));
|
||||
}
|
||||
|
||||
error = exists && !HistoryKeeper::checkPassword(passkey);
|
||||
dialogtxt = a + "\n" + c + "\n" + b;
|
||||
} while (error);
|
||||
}
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
Copyright © 2014-2015 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "encrypteddb.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/profile.h"
|
||||
|
||||
#include <tox/toxencryptsave.h>
|
||||
|
||||
#include <QSqlQuery>
|
||||
#include <QDebug>
|
||||
#include <QSqlError>
|
||||
|
||||
/**
|
||||
* @var static std::shared_ptr<Tox_Pass_Key> EncryptedDb::decryptionKey
|
||||
* @note When importing, the decryption key may not be the same as the profile key
|
||||
*/
|
||||
|
||||
qint64 EncryptedDb::encryptedChunkSize = 4096;
|
||||
qint64 EncryptedDb::plainChunkSize = EncryptedDb::encryptedChunkSize - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
|
||||
|
||||
std::shared_ptr<Tox_Pass_Key> EncryptedDb::decryptionKey;
|
||||
|
||||
EncryptedDb::EncryptedDb(const QString &fname, QList<QString> initList) :
|
||||
PlainDb(":memory:", initList), fileName(fname)
|
||||
{
|
||||
QByteArray fileContent;
|
||||
if (pullFileContent(fileName, buffer))
|
||||
{
|
||||
qDebug() << "writing old data";
|
||||
encrFile.setFileName(fileName);
|
||||
encrFile.open(QIODevice::ReadOnly);
|
||||
fileContent = encrFile.readAll();
|
||||
chunkPosition = encrFile.size() / encryptedChunkSize;
|
||||
encrFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkPosition = 0;
|
||||
}
|
||||
|
||||
encrFile.setFileName(fileName);
|
||||
|
||||
if (!encrFile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
qWarning() << "can't open file:" << fileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
encrFile.write(fileContent);
|
||||
encrFile.flush();
|
||||
}
|
||||
}
|
||||
|
||||
EncryptedDb::~EncryptedDb()
|
||||
{
|
||||
encrFile.close(); // Q: what if program is killed without being able to clean up?
|
||||
// A: cleanup isn't necessary, everything handled int appendToEncrypted(..) function
|
||||
}
|
||||
|
||||
QSqlQuery EncryptedDb::exec(const QString &query)
|
||||
{
|
||||
QSqlQuery retQSqlQuery = PlainDb::exec(query);
|
||||
if (checkCmd(query))
|
||||
appendToEncrypted(query);
|
||||
|
||||
return retQSqlQuery;
|
||||
}
|
||||
|
||||
bool EncryptedDb::pullFileContent(const QString &fname, QByteArray &buf)
|
||||
{
|
||||
QFile dbFile(fname);
|
||||
if (!dbFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
qDebug() << "pullFileContent: file doesn't exist";
|
||||
buf = QByteArray();
|
||||
return false;
|
||||
}
|
||||
QByteArray fileContent;
|
||||
|
||||
while (!dbFile.atEnd())
|
||||
{
|
||||
QByteArray encrChunk = dbFile.read(encryptedChunkSize);
|
||||
buf = Core::getInstance()->decryptData(encrChunk, *decryptionKey);
|
||||
if (buf.size() > 0)
|
||||
{
|
||||
fileContent += buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "pullFileContent: Encrypted history log is corrupted: can't decrypt, will be deleted";
|
||||
buf = QByteArray();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QList<QByteArray> splittedBA = fileContent.split('\n');
|
||||
QList<QString> sqlCmds;
|
||||
|
||||
for (auto ba_line : splittedBA)
|
||||
{
|
||||
QString line = QByteArray::fromBase64(ba_line);
|
||||
sqlCmds.append(line);
|
||||
}
|
||||
|
||||
PlainDb::exec("BEGIN TRANSACTION;");
|
||||
for (auto line : sqlCmds)
|
||||
QSqlQuery r = PlainDb::exec(line);
|
||||
|
||||
PlainDb::exec("COMMIT TRANSACTION;");
|
||||
|
||||
dbFile.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EncryptedDb::appendToEncrypted(const QString &sql)
|
||||
{
|
||||
QByteArray b64Str;
|
||||
b64Str.append(sql);
|
||||
b64Str = b64Str.toBase64(); // much easier to parse strings like this from file
|
||||
|
||||
buffer += b64Str + "\n";
|
||||
|
||||
while (buffer.size() > plainChunkSize)
|
||||
{
|
||||
QByteArray filledChunk = buffer.left(plainChunkSize);
|
||||
encrFile.seek(chunkPosition * encryptedChunkSize);
|
||||
QByteArray encr = Core::getInstance()->encryptData(filledChunk);
|
||||
if (encr.size() > 0)
|
||||
{
|
||||
encrFile.write(encr);
|
||||
encrFile.flush();
|
||||
}
|
||||
|
||||
buffer = buffer.right(buffer.size() - plainChunkSize);
|
||||
++chunkPosition;
|
||||
}
|
||||
encrFile.seek(chunkPosition * encryptedChunkSize);
|
||||
|
||||
QByteArray encr = Core::getInstance()->encryptData(buffer);
|
||||
if (encr.size() > 0)
|
||||
encrFile.write(encr);
|
||||
|
||||
encrFile.flush();
|
||||
}
|
||||
|
||||
bool EncryptedDb::check(std::shared_ptr<Tox_Pass_Key> passkey, const QString &fname)
|
||||
{
|
||||
QFile file(fname);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
bool state = true;
|
||||
|
||||
if (file.size() > 0)
|
||||
{
|
||||
QByteArray encrChunk = file.read(encryptedChunkSize);
|
||||
QByteArray buf = Core::getInstance()->decryptData(encrChunk, *passkey);
|
||||
if (buf.size() == 0)
|
||||
state = false;
|
||||
else
|
||||
decryptionKey = passkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.close();
|
||||
file.open(QIODevice::WriteOnly);
|
||||
}
|
||||
|
||||
file.close();
|
||||
return state;
|
||||
}
|
||||
|
||||
bool EncryptedDb::checkCmd(const QString &cmd)
|
||||
{
|
||||
if (cmd.startsWith("INSERT", Qt::CaseInsensitive) || cmd.startsWith("UPDATE", Qt::CaseInsensitive)
|
||||
|| cmd.startsWith("DELETE", Qt::CaseInsensitive))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
Copyright © 2014 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ENCRYPTEDDB_H
|
||||
#define ENCRYPTEDDB_H
|
||||
|
||||
#include "plaindb.h"
|
||||
#include <tox/toxencryptsave.h>
|
||||
|
||||
#include <QList>
|
||||
#include <QFile>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class EncryptedDb : public PlainDb
|
||||
{
|
||||
public:
|
||||
EncryptedDb(const QString& fname, QList<QString> initList);
|
||||
virtual ~EncryptedDb();
|
||||
|
||||
virtual QSqlQuery exec(const QString &query);
|
||||
static bool check(std::shared_ptr<Tox_Pass_Key> passkey, const QString &fname);
|
||||
|
||||
private:
|
||||
bool pullFileContent(const QString& fname, QByteArray &buf);
|
||||
void appendToEncrypted(const QString &sql);
|
||||
bool checkCmd(const QString &cmd);
|
||||
|
||||
QFile encrFile;
|
||||
QString fileName;
|
||||
|
||||
static qint64 plainChunkSize;
|
||||
static qint64 encryptedChunkSize;
|
||||
|
||||
static std::shared_ptr<Tox_Pass_Key> decryptionKey;
|
||||
|
||||
qint64 chunkPosition;
|
||||
QByteArray buffer;
|
||||
};
|
||||
|
||||
#endif // ENCRYPTEDDB_H
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
Copyright © 2014 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "genericddinterface.h"
|
||||
|
||||
GenericDdInterface::~GenericDdInterface()
|
||||
{
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
Copyright © 2014 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GENERICDDINTERFACE_H
|
||||
#define GENERICDDINTERFACE_H
|
||||
|
||||
class QSqlQuery;
|
||||
class QString;
|
||||
|
||||
class GenericDdInterface
|
||||
{
|
||||
public:
|
||||
virtual ~GenericDdInterface();
|
||||
|
||||
virtual QSqlQuery exec(const QString &query) = 0;
|
||||
};
|
||||
|
||||
#endif // GENERICDDINTERFACE_H
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright © 2014 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "plaindb.h"
|
||||
#include <QDebug>
|
||||
#include <QSqlQuery>
|
||||
#include <QString>
|
||||
|
||||
PlainDb::PlainDb(const QString &db_name, QList<QString> initList)
|
||||
{
|
||||
db = new QSqlDatabase();
|
||||
*db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE=1");
|
||||
db->setDatabaseName(db_name);
|
||||
|
||||
if (!db->open())
|
||||
{
|
||||
qWarning() << QString("Can't open file: %1, history will not be saved!").arg(db_name);
|
||||
db->setDatabaseName(":memory:");
|
||||
db->setConnectOptions();
|
||||
db->open();
|
||||
}
|
||||
|
||||
for (const QString &cmd : initList)
|
||||
{
|
||||
db->exec(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
PlainDb::~PlainDb()
|
||||
{
|
||||
db->close();
|
||||
QString dbConName = db->connectionName();
|
||||
delete db;
|
||||
|
||||
QSqlDatabase::removeDatabase(dbConName);
|
||||
}
|
||||
|
||||
QSqlQuery PlainDb::exec(const QString &query)
|
||||
{
|
||||
return db->exec(query);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
Copyright © 2014 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PLAINDB_H
|
||||
#define PLAINDB_H
|
||||
|
||||
#include "genericddinterface.h"
|
||||
|
||||
#include <QSqlDatabase>
|
||||
|
||||
namespace Db {
|
||||
enum class syncType {stOff = 0, stNormal = 1, stFull = 2};
|
||||
}
|
||||
|
||||
class PlainDb : public GenericDdInterface
|
||||
{
|
||||
public:
|
||||
PlainDb(const QString &db_name, QList<QString> initList);
|
||||
virtual ~PlainDb();
|
||||
|
||||
virtual QSqlQuery exec(const QString &query);
|
||||
|
||||
private:
|
||||
QSqlDatabase *db;
|
||||
};
|
||||
|
||||
#endif // PLAINDB_H
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include "db/rawdatabase.h"
|
||||
#include "history.h"
|
||||
#include "historykeeper.h"
|
||||
#include "profile.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
@ -316,37 +315,3 @@ void History::markAsSent(qint64 messageId)
|
|||
db->execLater(QString("DELETE FROM faux_offline_pending WHERE id=%1;")
|
||||
.arg(messageId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Imports messages from the old history file.
|
||||
* @param oldHistory Old history to import.
|
||||
*/
|
||||
void History::import(const HistoryKeeper& oldHistory)
|
||||
{
|
||||
if (!isValid())
|
||||
{
|
||||
qWarning() << "New database not open, import failed";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Importing old database...";
|
||||
QTime t = QTime::currentTime();
|
||||
t.start();
|
||||
QVector<RawDatabase::Query> queries;
|
||||
constexpr int batchSize = 1000;
|
||||
queries.reserve(batchSize);
|
||||
QList<HistoryKeeper::HistMessage> oldMessages = oldHistory.exportMessagesDeleteFile();
|
||||
for (const HistoryKeeper::HistMessage& msg : oldMessages)
|
||||
{
|
||||
queries += generateNewMessageQueries(msg.chat, msg.message, msg.sender,
|
||||
msg.timestamp, true, msg.dispName);
|
||||
if (queries.size() >= batchSize)
|
||||
{
|
||||
db->execLater(queries);
|
||||
queries.clear();
|
||||
}
|
||||
}
|
||||
db->execLater(queries);
|
||||
db->sync();
|
||||
qDebug() << "Imported old database in" << t.elapsed() << "ms";
|
||||
}
|
||||
|
|
|
@ -1,236 +0,0 @@
|
|||
/*
|
||||
Copyright © 2014-2015 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "historykeeper.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/profile.h"
|
||||
|
||||
#include <QSqlError>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QSqlQuery>
|
||||
#include <QVariant>
|
||||
#include <QBuffer>
|
||||
#include <QDebug>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
#include "src/persistence/db/plaindb.h"
|
||||
#include "src/persistence/db/encrypteddb.h"
|
||||
|
||||
/**
|
||||
* @class HistoryKeeper
|
||||
* @brief THIS IS A LEGACY CLASS KEPT FOR BACKWARDS COMPATIBILITY
|
||||
* @deprecated See the History class instead
|
||||
* @warning DO NOT USE!
|
||||
*/
|
||||
// TODO: remove backwards compatibility in 2018
|
||||
|
||||
static HistoryKeeper *historyInstance = nullptr;
|
||||
QMutex HistoryKeeper::historyMutex;
|
||||
|
||||
/**
|
||||
* @brief Returns the singleton instance.
|
||||
*/
|
||||
HistoryKeeper *HistoryKeeper::getInstance(const Profile& profile)
|
||||
{
|
||||
historyMutex.lock();
|
||||
if (historyInstance == nullptr)
|
||||
{
|
||||
QList<QString> initLst;
|
||||
initLst.push_back(QString("CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, ") +
|
||||
QString("chat_id INTEGER NOT NULL, sender INTEGER NOT NULL, message TEXT NOT NULL, alias TEXT);"));
|
||||
initLst.push_back(QString("CREATE TABLE IF NOT EXISTS aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT UNIQUE NOT NULL);"));
|
||||
initLst.push_back(QString("CREATE TABLE IF NOT EXISTS chats (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, ctype INTEGER NOT NULL);"));
|
||||
initLst.push_back(QString("CREATE TABLE IF NOT EXISTS sent_status (id INTEGER PRIMARY KEY AUTOINCREMENT, status INTEGER NOT NULL DEFAULT 0);"));
|
||||
|
||||
QString path(":memory:");
|
||||
GenericDdInterface *dbIntf;
|
||||
|
||||
if (profile.isEncrypted())
|
||||
{
|
||||
path = getHistoryPath({}, 1);
|
||||
dbIntf = new EncryptedDb(path, initLst);
|
||||
|
||||
historyInstance = new HistoryKeeper(dbIntf);
|
||||
historyMutex.unlock();
|
||||
return historyInstance;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = getHistoryPath({}, 0);
|
||||
}
|
||||
|
||||
dbIntf = new PlainDb(path, initLst);
|
||||
historyInstance = new HistoryKeeper(dbIntf);
|
||||
}
|
||||
historyMutex.unlock();
|
||||
|
||||
return historyInstance;
|
||||
}
|
||||
|
||||
bool HistoryKeeper::checkPassword(std::shared_ptr<Tox_Pass_Key> passkey, int encrypted)
|
||||
{
|
||||
if (!Settings::getInstance().getEnableLogging() && (encrypted == -1))
|
||||
return true;
|
||||
|
||||
if ((encrypted == 1) || (encrypted == -1))
|
||||
return EncryptedDb::check(passkey, getHistoryPath(Nexus::getProfile()->getName(), encrypted));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
|
||||
oldDb(db_)
|
||||
{
|
||||
/*
|
||||
DB format
|
||||
chats:
|
||||
* name -> id map
|
||||
id -- auto-incrementing number
|
||||
name -- chat's name (for user to user conversation it is opposite user public key)
|
||||
ctype -- chat type, reserved for group chats
|
||||
|
||||
aliases:
|
||||
* user_id -> id map
|
||||
id -- auto-incrementing number
|
||||
user_id -- user's public key
|
||||
av_hash -- hash of user's avatar
|
||||
avatar -- user's avatar
|
||||
|
||||
history:
|
||||
id -- auto-incrementing number
|
||||
timestamp
|
||||
chat_id -- current chat ID (resolves from chats table)
|
||||
sender -- sender's ID (resolves from aliases table)
|
||||
message
|
||||
alias -- sender's alias in
|
||||
*/
|
||||
|
||||
// for old tables:
|
||||
QSqlQuery ans = oldDb->exec("SELECT seq FROM sqlite_sequence WHERE name=\"history\";");
|
||||
if (ans.first())
|
||||
{
|
||||
int idMax = ans.value(0).toInt();
|
||||
QSqlQuery ret = oldDb->exec("SELECT seq FROM sqlite_sequence WHERE name=\"sent_status\";");
|
||||
int idCur = 0;
|
||||
if (ret.first())
|
||||
idCur = ret.value(0).toInt();
|
||||
|
||||
if (idCur != idMax)
|
||||
{
|
||||
QString cmd = QString("INSERT INTO sent_status (id, status) VALUES (%1, 1);").arg(idMax);
|
||||
oldDb->exec(cmd);
|
||||
}
|
||||
}
|
||||
//check table stuct
|
||||
ans = oldDb->exec("PRAGMA table_info (\"history\")");
|
||||
ans.seek(5);
|
||||
if (!ans.value(1).toString().contains("alias"))
|
||||
{
|
||||
//add collum in table
|
||||
oldDb->exec("ALTER TABLE history ADD COLUMN alias TEXT");
|
||||
qDebug() << "Struct DB updated: Added column alias in table history.";
|
||||
}
|
||||
}
|
||||
|
||||
HistoryKeeper::~HistoryKeeper()
|
||||
{
|
||||
delete oldDb;
|
||||
}
|
||||
|
||||
QList<HistoryKeeper::HistMessage> HistoryKeeper::exportMessages()
|
||||
{
|
||||
QSqlQuery dbAnswer;
|
||||
dbAnswer = oldDb->exec(QString("SELECT history.id, timestamp, user_id, message, status, name, alias FROM history LEFT JOIN sent_status ON history.id = sent_status.id ") +
|
||||
QString("INNER JOIN aliases ON history.sender = aliases.id INNER JOIN chats ON history.chat_id = chats.id;"));
|
||||
|
||||
QList<HistMessage> res;
|
||||
|
||||
while (dbAnswer.next())
|
||||
{
|
||||
qint64 id = dbAnswer.value(0).toLongLong();
|
||||
qint64 timeInt = dbAnswer.value(1).toLongLong();
|
||||
QString sender = dbAnswer.value(2).toString();
|
||||
QString message = unWrapMessage(dbAnswer.value(3).toString());
|
||||
bool isSent = true;
|
||||
if (!dbAnswer.value(4).isNull())
|
||||
isSent = dbAnswer.value(4).toBool();
|
||||
QString chat = dbAnswer.value(5).toString();
|
||||
QString dispName = dbAnswer.value(6).toString();
|
||||
QDateTime time = QDateTime::fromMSecsSinceEpoch(timeInt);
|
||||
|
||||
res.push_back(HistMessage(id, chat, sender, message, time, isSent, dispName));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
QString HistoryKeeper::unWrapMessage(const QString &str)
|
||||
{
|
||||
QString unWrappedMessage(str);
|
||||
unWrappedMessage.replace("''", "'");
|
||||
return unWrappedMessage;
|
||||
}
|
||||
|
||||
void HistoryKeeper::resetInstance()
|
||||
{
|
||||
if (historyInstance == nullptr)
|
||||
return;
|
||||
|
||||
delete historyInstance;
|
||||
historyInstance = nullptr;
|
||||
}
|
||||
|
||||
QString HistoryKeeper::getHistoryPath(QString currentProfile, int encrypted)
|
||||
{
|
||||
QDir baseDir(Settings::getInstance().getSettingsDirPath());
|
||||
if (currentProfile.isEmpty())
|
||||
currentProfile = Settings::getInstance().getCurrentProfile();
|
||||
|
||||
if (encrypted == 1 || (encrypted == -1 && Nexus::getProfile()->isEncrypted()))
|
||||
return baseDir.filePath(currentProfile + ".qtox_history.encrypted");
|
||||
else
|
||||
return baseDir.filePath(currentProfile + ".qtox_history");
|
||||
}
|
||||
|
||||
bool HistoryKeeper::isFileExist(bool encrypted)
|
||||
{
|
||||
QString path = getHistoryPath({}, encrypted ? 1 : 0);
|
||||
QFile file(path);
|
||||
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
void HistoryKeeper::removeHistory()
|
||||
{
|
||||
resetInstance();
|
||||
QFile::remove(getHistoryPath({}, 0));
|
||||
QFile::remove(getHistoryPath({}, 1));
|
||||
}
|
||||
|
||||
QList<HistoryKeeper::HistMessage> HistoryKeeper::exportMessagesDeleteFile()
|
||||
{
|
||||
auto msgs = getInstance(*Nexus::getProfile())->exportMessages();
|
||||
qDebug() << "Messages exported";
|
||||
getInstance(*Nexus::getProfile())->removeHistory();
|
||||
|
||||
return msgs;
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
Copyright © 2014-2015 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HISTORYKEEPER_H
|
||||
#define HISTORYKEEPER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QList>
|
||||
#include <QDateTime>
|
||||
#include <QPixmap>
|
||||
#include <QMutex>
|
||||
#include <tox/toxencryptsave.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Profile;
|
||||
class GenericDdInterface;
|
||||
|
||||
namespace Db {
|
||||
enum class syncType;
|
||||
}
|
||||
|
||||
class HistoryKeeper
|
||||
{
|
||||
public:
|
||||
static QMutex historyMutex;
|
||||
|
||||
struct HistMessage
|
||||
{
|
||||
HistMessage(qint64 id, QString chat, QString sender, QString message, QDateTime timestamp, bool isSent, QString dispName) :
|
||||
id(id), chat(chat), sender(sender), message(message), timestamp(timestamp), isSent(isSent), dispName(dispName) {}
|
||||
|
||||
qint64 id;
|
||||
QString chat;
|
||||
QString sender;
|
||||
QString message;
|
||||
QDateTime timestamp;
|
||||
bool isSent;
|
||||
QString dispName;
|
||||
};
|
||||
|
||||
virtual ~HistoryKeeper();
|
||||
|
||||
static HistoryKeeper* getInstance(const Profile& profile);
|
||||
static void resetInstance();
|
||||
|
||||
static QString getHistoryPath(QString currentProfile = QString(), int encrypted = -1); // -1 defaults to checking settings, 0 or 1 to specify
|
||||
static bool checkPassword(std::shared_ptr<Tox_Pass_Key> passkey, int encrypted = -1);
|
||||
static bool isFileExist(bool encrypted);
|
||||
void removeHistory();
|
||||
static QList<HistMessage> exportMessagesDeleteFile();
|
||||
QList<HistMessage> exportMessages();
|
||||
|
||||
private:
|
||||
explicit HistoryKeeper(GenericDdInterface *db_);
|
||||
HistoryKeeper(HistoryKeeper &hk) = delete;
|
||||
HistoryKeeper& operator=(const HistoryKeeper&) = delete;
|
||||
QString unWrapMessage(const QString &str);
|
||||
|
||||
GenericDdInterface *oldDb;
|
||||
};
|
||||
|
||||
#endif // HISTORYKEEPER_H
|
|
@ -31,7 +31,6 @@
|
|||
#include "profile.h"
|
||||
#include "profilelocker.h"
|
||||
#include "settings.h"
|
||||
#include "historykeeper.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/widget/gui.h"
|
||||
|
@ -153,11 +152,6 @@ Profile* Profile::loadProfile(QString name, const QString& password)
|
|||
}
|
||||
|
||||
Profile* p = new Profile(name, password, false);
|
||||
if (p->history && HistoryKeeper::isFileExist(!password.isEmpty()))
|
||||
{
|
||||
p->history->import(*HistoryKeeper::getInstance(*p));
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -671,8 +665,6 @@ QVector<QString> Profile::remove()
|
|||
|
||||
QFile profileMain {path + ".tox"};
|
||||
QFile profileConfig {path + ".ini"};
|
||||
QFile historyLegacyUnencrypted {HistoryKeeper::getHistoryPath(name, 0)};
|
||||
QFile historyLegacyEncrypted {HistoryKeeper::getHistoryPath(name, 1)};
|
||||
|
||||
QVector<QString> ret;
|
||||
|
||||
|
@ -687,17 +679,6 @@ QVector<QString> Profile::remove()
|
|||
qWarning() << "Could not remove file " << profileConfig.fileName();
|
||||
}
|
||||
|
||||
if (!historyLegacyUnencrypted.remove() && historyLegacyUnencrypted.exists())
|
||||
{
|
||||
ret.push_back(historyLegacyUnencrypted.fileName());
|
||||
qWarning() << "Could not remove file " << historyLegacyUnencrypted.fileName();
|
||||
}
|
||||
if (!historyLegacyEncrypted.remove() && historyLegacyEncrypted.exists())
|
||||
{
|
||||
ret.push_back(historyLegacyEncrypted.fileName());
|
||||
qWarning() << "Could not remove file " << historyLegacyUnencrypted.fileName();
|
||||
}
|
||||
|
||||
QString dbPath = getDbPath(name);
|
||||
if (database && database->isOpen() && !database->remove() && QFile::exists(dbPath))
|
||||
{
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "settings.h"
|
||||
#include "src/persistence/smileypack.h"
|
||||
#include "src/persistence/db/plaindb.h"
|
||||
#include "src/core/corestructs.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/widget/gui.h"
|
||||
|
@ -218,10 +217,6 @@ void Settings::loadGlobal()
|
|||
makeToxPortable = s.value("makeToxPortable", makeToxPortable).toBool();
|
||||
enableIPv6 = s.value("enableIPv6", enableIPv6).toBool();
|
||||
forceTCP = s.value("forceTCP", forceTCP).toBool();
|
||||
|
||||
int type = s.value("dbSyncType", static_cast<int>(Db::syncType::stFull)).toInt();
|
||||
Db::syncType sType = static_cast<Db::syncType>(type);
|
||||
setDbSyncType(sType);
|
||||
}
|
||||
s.endGroup();
|
||||
|
||||
|
@ -1387,23 +1382,6 @@ void Settings::setEnableLogging(bool newValue)
|
|||
}
|
||||
}
|
||||
|
||||
Db::syncType Settings::getDbSyncType() const
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
return dbSyncType;
|
||||
}
|
||||
|
||||
void Settings::setDbSyncType(Db::syncType newValue)
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
|
||||
if (newValue != dbSyncType)
|
||||
{
|
||||
dbSyncType = newValue;
|
||||
emit dbSyncTypeChanged(dbSyncType);
|
||||
}
|
||||
}
|
||||
|
||||
int Settings::getAutoAwayTime() const
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "src/core/recursivesignalblocker.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/persistence/db/plaindb.h"
|
||||
#include "src/persistence/profile.h"
|
||||
#include "src/widget/gui.h"
|
||||
#include "src/widget/translator.h"
|
||||
|
|
Loading…
Reference in New Issue
Block a user