2015-06-04 05:20:47 +08:00
|
|
|
#include "profile.h"
|
2015-06-04 07:30:17 +08:00
|
|
|
#include "profilelocker.h"
|
2015-06-04 05:20:47 +08:00
|
|
|
#include "src/misc/settings.h"
|
2015-06-04 07:30:17 +08:00
|
|
|
#include "src/core/core.h"
|
2015-06-04 05:20:47 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QFileInfo>
|
2015-06-04 16:56:48 +08:00
|
|
|
#include <QSaveFile>
|
2015-06-04 07:30:17 +08:00
|
|
|
#include <QThread>
|
|
|
|
#include <QObject>
|
|
|
|
#include <QDebug>
|
2015-06-04 05:20:47 +08:00
|
|
|
QVector<QString> Profile::profiles;
|
|
|
|
|
2015-06-04 08:10:06 +08:00
|
|
|
Profile::Profile(QString name, QString password, bool isNewProfile)
|
2015-06-04 08:43:07 +08:00
|
|
|
: name{name}, password{password}, newProfile{isNewProfile}
|
2015-06-04 05:20:47 +08:00
|
|
|
{
|
2015-06-04 07:30:17 +08:00
|
|
|
coreThread = new QThread();
|
|
|
|
coreThread->setObjectName("qTox Core");
|
|
|
|
core = new Core(coreThread, *this);
|
|
|
|
core->moveToThread(coreThread);
|
|
|
|
QObject::connect(coreThread, &QThread::started, core, &Core::start);
|
|
|
|
}
|
|
|
|
|
|
|
|
Profile* Profile::loadProfile(QString name, QString password)
|
|
|
|
{
|
|
|
|
if (ProfileLocker::hasLock())
|
|
|
|
{
|
2015-06-04 08:10:06 +08:00
|
|
|
qCritical() << "Tried to load profile "<<name<<", but another profile is already locked!";
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ProfileLocker::lock(name))
|
|
|
|
{
|
|
|
|
qWarning() << "Failed to lock profile "<<name;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Profile(name, password, false);
|
|
|
|
}
|
2015-06-04 07:30:17 +08:00
|
|
|
|
2015-06-04 08:10:06 +08:00
|
|
|
Profile* Profile::createProfile(QString name, QString password)
|
|
|
|
{
|
|
|
|
if (ProfileLocker::hasLock())
|
|
|
|
{
|
|
|
|
qCritical() << "Tried to create profile "<<name<<", but another profile is already locked!";
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (profileExists(name))
|
|
|
|
{
|
|
|
|
qCritical() << "Tried to create profile "<<name<<", but it already exists!";
|
|
|
|
return nullptr;
|
2015-06-04 07:30:17 +08:00
|
|
|
}
|
2015-06-04 05:20:47 +08:00
|
|
|
|
2015-06-04 07:30:17 +08:00
|
|
|
if (!ProfileLocker::lock(name))
|
|
|
|
{
|
|
|
|
qWarning() << "Failed to lock profile "<<name;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-06-04 08:10:06 +08:00
|
|
|
Settings::getInstance().createPersonal(name);
|
|
|
|
return new Profile(name, password, true);
|
2015-06-04 05:20:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Profile::~Profile()
|
|
|
|
{
|
2015-06-04 07:30:17 +08:00
|
|
|
delete core;
|
|
|
|
delete coreThread;
|
|
|
|
assert(ProfileLocker::getCurLockName() == name);
|
|
|
|
ProfileLocker::unlock();
|
2015-06-04 05:20:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QVector<QString> Profile::getFilesByExt(QString extension)
|
|
|
|
{
|
|
|
|
QDir dir(Settings::getInstance().getSettingsDirPath());
|
|
|
|
QVector<QString> out;
|
|
|
|
dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
|
|
|
|
dir.setNameFilters(QStringList("*."+extension));
|
|
|
|
QFileInfoList list = dir.entryInfoList();
|
|
|
|
out.reserve(list.size());
|
|
|
|
for (QFileInfo file : list)
|
|
|
|
out += file.completeBaseName();
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profile::scanProfiles()
|
|
|
|
{
|
|
|
|
profiles.clear();
|
|
|
|
QVector<QString> toxfiles = getFilesByExt("tox"), inifiles = getFilesByExt("ini");
|
|
|
|
for (QString toxfile : toxfiles)
|
|
|
|
{
|
|
|
|
if (!inifiles.contains(toxfile))
|
|
|
|
importProfile(toxfile);
|
|
|
|
profiles.append(toxfile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profile::importProfile(QString name)
|
|
|
|
{
|
2015-06-04 08:10:06 +08:00
|
|
|
assert(!profileExists(name));
|
|
|
|
Settings::getInstance().createPersonal(name);
|
2015-06-04 05:20:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QVector<QString> Profile::getProfiles()
|
|
|
|
{
|
|
|
|
return profiles;
|
|
|
|
}
|
2015-06-04 07:30:17 +08:00
|
|
|
|
|
|
|
Core* Profile::getCore()
|
|
|
|
{
|
|
|
|
return core;
|
|
|
|
}
|
|
|
|
|
2015-06-04 08:43:07 +08:00
|
|
|
QString Profile::getName()
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2015-06-04 07:30:17 +08:00
|
|
|
void Profile::startCore()
|
|
|
|
{
|
|
|
|
coreThread->start();
|
|
|
|
}
|
|
|
|
|
2015-06-04 08:43:07 +08:00
|
|
|
bool Profile::isNewProfile()
|
|
|
|
{
|
|
|
|
return newProfile;
|
|
|
|
}
|
|
|
|
|
2015-06-04 07:30:17 +08:00
|
|
|
QByteArray Profile::loadToxSave()
|
|
|
|
{
|
2015-06-04 08:43:07 +08:00
|
|
|
/// TODO: Cache the data, invalidate it only when we save
|
2015-06-04 07:30:17 +08:00
|
|
|
QByteArray data;
|
|
|
|
|
2015-06-04 08:10:06 +08:00
|
|
|
QString path = Settings::getSettingsDirPath() + QDir::separator() + name + ".tox";
|
2015-06-04 07:30:17 +08:00
|
|
|
QFile saveFile(path);
|
|
|
|
qint64 fileSize;
|
|
|
|
qDebug() << "Loading tox save "<<path;
|
|
|
|
|
|
|
|
if (!saveFile.exists())
|
|
|
|
{
|
|
|
|
qWarning() << "The tox save file "<<path<<" was not found";
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!saveFile.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
qCritical() << "The tox save file " << path << " couldn't' be opened";
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileSize = saveFile.size();
|
|
|
|
if (fileSize <= 0)
|
|
|
|
{
|
|
|
|
qWarning() << "The tox save file"<<path<<" is empty!";
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = saveFile.readAll();
|
|
|
|
if (tox_is_data_encrypted((uint8_t*)data.data()))
|
|
|
|
{
|
|
|
|
if (password.isEmpty())
|
|
|
|
{
|
|
|
|
qCritical() << "The tox save file is encrypted, but we don't have a password!";
|
2015-06-04 08:43:07 +08:00
|
|
|
data.clear();
|
2015-06-04 07:30:17 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t salt[TOX_PASS_SALT_LENGTH];
|
|
|
|
tox_get_salt(reinterpret_cast<uint8_t *>(data.data()), salt);
|
|
|
|
core->setPassword(password, Core::ptMain, salt);
|
|
|
|
|
|
|
|
data = core->decryptData(data, Core::ptMain);
|
|
|
|
if (data.isEmpty())
|
|
|
|
qCritical() << "Failed to decrypt the tox save file";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!password.isEmpty())
|
|
|
|
qWarning() << "We have a password, but the tox save file is not encrypted";
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
saveFile.close();
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2015-06-04 17:37:54 +08:00
|
|
|
void Profile::saveToxSave()
|
|
|
|
{
|
|
|
|
saveToxSave(core->getToxSaveData());
|
|
|
|
}
|
|
|
|
|
2015-06-04 16:56:48 +08:00
|
|
|
void Profile::saveToxSave(QByteArray data)
|
|
|
|
{
|
|
|
|
ProfileLocker::assertLock();
|
|
|
|
assert(ProfileLocker::getCurLockName() == name);
|
|
|
|
|
|
|
|
QString path = Settings::getSettingsDirPath() + QDir::separator() + name + ".tox";
|
2015-06-04 17:42:49 +08:00
|
|
|
qDebug() << "Saving tox save to "<<path;
|
2015-06-04 16:56:48 +08:00
|
|
|
QSaveFile saveFile(path);
|
|
|
|
if (!saveFile.open(QIODevice::WriteOnly))
|
|
|
|
{
|
|
|
|
qCritical() << "Tox save file " << path << " couldn't be opened";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!password.isEmpty())
|
|
|
|
{
|
|
|
|
core->setPassword(password, Core::ptMain);
|
|
|
|
data = core->encryptData(data, Core::ptMain);
|
|
|
|
if (data.isEmpty())
|
|
|
|
{
|
|
|
|
qCritical() << "Failed to encrypt, can't save!";
|
|
|
|
saveFile.cancelWriting();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
saveFile.write(data);
|
|
|
|
saveFile.commit();
|
|
|
|
newProfile = false;
|
|
|
|
}
|
|
|
|
|
2015-06-04 08:10:06 +08:00
|
|
|
bool Profile::profileExists(QString name)
|
|
|
|
{
|
|
|
|
QString path = Settings::getSettingsDirPath() + QDir::separator() + name;
|
|
|
|
return QFile::exists(path+".tox") && QFile::exists(path+".ini");
|
|
|
|
}
|
|
|
|
|
2015-06-04 07:30:17 +08:00
|
|
|
bool Profile::isProfileEncrypted(QString name)
|
|
|
|
{
|
|
|
|
uint8_t data[encryptHeaderSize] = {0};
|
|
|
|
QString path = Settings::getSettingsDirPath() + QDir::separator() + name + ".tox";
|
|
|
|
QFile saveFile(path);
|
|
|
|
if (!saveFile.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
qWarning() << "Couldn't open tox save "<<path;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
saveFile.read((char*)data, encryptHeaderSize);
|
|
|
|
saveFile.close();
|
|
|
|
|
|
|
|
return tox_is_data_encrypted(data);
|
|
|
|
}
|