mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge branch 'autoupdate'
This commit is contained in:
commit
55939e9563
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -8,3 +8,5 @@ Makefile
|
||||||
qtox
|
qtox
|
||||||
*.qm
|
*.qm
|
||||||
*.orig
|
*.orig
|
||||||
|
build-*-Release
|
||||||
|
build-*-Debug
|
||||||
|
|
12
qtox.pro
12
qtox.pro
|
@ -57,7 +57,7 @@ contains(JENKINS,YES) {
|
||||||
# Rules for Windows, Mac OSX, and Linux
|
# Rules for Windows, Mac OSX, and Linux
|
||||||
win32 {
|
win32 {
|
||||||
RC_FILE = windows/qtox.rc
|
RC_FILE = windows/qtox.rc
|
||||||
LIBS += -liphlpapi -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lvpx -lpthread
|
LIBS += -liphlpapi -L$$PWD/libs/lib -lsodium -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lvpx -lpthread
|
||||||
LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus
|
LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus
|
||||||
LIBS += -lz -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32
|
LIBS += -lz -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32
|
||||||
} else {
|
} else {
|
||||||
|
@ -76,7 +76,7 @@ win32 {
|
||||||
LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0
|
LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc
|
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lsodium -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc
|
||||||
}
|
}
|
||||||
|
|
||||||
contains(JENKINS, YES) {
|
contains(JENKINS, YES) {
|
||||||
|
@ -146,7 +146,9 @@ HEADERS += src/widget/form/addfriendform.h \
|
||||||
src/ipc.h \
|
src/ipc.h \
|
||||||
src/widget/toxuri.h \
|
src/widget/toxuri.h \
|
||||||
src/toxdns.h \
|
src/toxdns.h \
|
||||||
src/widget/toxsave.h
|
src/widget/toxsave.h \
|
||||||
|
src/autoupdate.h \
|
||||||
|
src/misc/serialize.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
src/widget/form/addfriendform.cpp \
|
src/widget/form/addfriendform.cpp \
|
||||||
|
@ -209,4 +211,6 @@ SOURCES += \
|
||||||
src/widget/toxuri.cpp \
|
src/widget/toxuri.cpp \
|
||||||
src/toxdns.cpp \
|
src/toxdns.cpp \
|
||||||
src/ipc.cpp \
|
src/ipc.cpp \
|
||||||
src/widget/toxsave.cpp
|
src/widget/toxsave.cpp \
|
||||||
|
src/autoupdate.cpp \
|
||||||
|
src/misc/serialize.cpp
|
||||||
|
|
414
src/autoupdate.cpp
Normal file
414
src/autoupdate.cpp
Normal file
|
@ -0,0 +1,414 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "src/autoupdate.h"
|
||||||
|
#include "src/misc/serialize.h"
|
||||||
|
#include "src/misc/settings.h"
|
||||||
|
#include "src/widget/widget.h"
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
const QString AutoUpdater::platform = "win32";
|
||||||
|
const QString AutoUpdater::updaterBin = "qtox-updater.exe";
|
||||||
|
#else
|
||||||
|
const QString AutoUpdater::platform;
|
||||||
|
const QString AutoUpdater::updaterBin;
|
||||||
|
#endif
|
||||||
|
const QString AutoUpdater::updateServer = "http://mlkj.bounceme.net";
|
||||||
|
const QString AutoUpdater::checkURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/version";
|
||||||
|
const QString AutoUpdater::flistURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/flist";
|
||||||
|
const QString AutoUpdater::filesURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/files/";
|
||||||
|
unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES] =
|
||||||
|
{
|
||||||
|
0xa5, 0x80, 0xf3, 0xb7, 0xd0, 0x10, 0xc0, 0xf9, 0xd6, 0xcf, 0x48, 0x15, 0x99, 0x70, 0x92, 0x49,
|
||||||
|
0xf6, 0xe8, 0xe5, 0xe2, 0x6c, 0x73, 0x8c, 0x48, 0x25, 0xed, 0x01, 0x72, 0xf7, 0x6c, 0x17, 0x28
|
||||||
|
};
|
||||||
|
|
||||||
|
bool AutoUpdater::isUpdateAvailable()
|
||||||
|
{
|
||||||
|
QString newVersion = getUpdateVersion();
|
||||||
|
if (newVersion.isEmpty() || newVersion == GIT_VERSION)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AutoUpdater::getUpdateVersion()
|
||||||
|
{
|
||||||
|
QString version;
|
||||||
|
|
||||||
|
// Updates only for supported platforms
|
||||||
|
if (platform.isEmpty())
|
||||||
|
return version;
|
||||||
|
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager;
|
||||||
|
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI)));
|
||||||
|
while (!reply->isFinished())
|
||||||
|
qApp->processEvents();
|
||||||
|
|
||||||
|
if (reply->error() != QNetworkReply::NoError)
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater: getUpdateVersion: network error: "<<reply->errorString();
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
if (data.size() < (int)(1+crypto_sign_BYTES))
|
||||||
|
return version;
|
||||||
|
|
||||||
|
// Check updater protocol version
|
||||||
|
if ((int)data[0] != '1')
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater: getUpdateVersion: Bad version "<<(uint8_t)data[0];
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the signature
|
||||||
|
QByteArray sigData = data.mid(1, crypto_sign_BYTES);
|
||||||
|
unsigned char* sig = (unsigned char*)sigData.data();
|
||||||
|
QByteArray msgData = data.mid(1+crypto_sign_BYTES);
|
||||||
|
unsigned char* msg = (unsigned char*)msgData.data();
|
||||||
|
|
||||||
|
if (crypto_sign_verify_detached(sig, msg, msgData.size(), key) != 0)
|
||||||
|
{
|
||||||
|
qCritical() << "AutoUpdater: getUpdateVersion: RECEIVED FORGED VERSION FILE FROM "<<updateServer;
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
version = msgData;
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<AutoUpdater::UpdateFileMeta> AutoUpdater::parseFlist(QByteArray flistData)
|
||||||
|
{
|
||||||
|
QList<UpdateFileMeta> flist;
|
||||||
|
|
||||||
|
if (flistData.isEmpty())
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::parseflist: Empty data";
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check version
|
||||||
|
if (flistData[0] != '1')
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater: parseflist: Bad version "<<(uint8_t)flistData[0];
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
flistData = flistData.mid(1);
|
||||||
|
|
||||||
|
// Check signature
|
||||||
|
if (flistData.size() < (int)(crypto_sign_BYTES))
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::parseflist: Truncated data";
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QByteArray msgData = flistData.mid(crypto_sign_BYTES);
|
||||||
|
unsigned char* msg = (unsigned char*)msgData.data();
|
||||||
|
if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key) != 0)
|
||||||
|
{
|
||||||
|
qCritical() << "AutoUpdater: parseflist: FORGED FLIST FILE";
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
flistData = flistData.mid(crypto_sign_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse. We assume no errors handling needed since the signature is valid.
|
||||||
|
while (!flistData.isEmpty())
|
||||||
|
{
|
||||||
|
UpdateFileMeta newFile;
|
||||||
|
|
||||||
|
memcpy(newFile.sig, flistData.data(), crypto_sign_BYTES);
|
||||||
|
flistData = flistData.mid(crypto_sign_BYTES);
|
||||||
|
|
||||||
|
newFile.id = dataToString(flistData);
|
||||||
|
flistData = flistData.mid(newFile.id.size() + getVUint32Size(flistData));
|
||||||
|
|
||||||
|
newFile.installpath = dataToString(flistData);
|
||||||
|
flistData = flistData.mid(newFile.installpath.size() + getVUint32Size(flistData));
|
||||||
|
|
||||||
|
newFile.size = dataToUint64(flistData);
|
||||||
|
flistData = flistData.mid(8);
|
||||||
|
|
||||||
|
flist += newFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray AutoUpdater::getUpdateFlist()
|
||||||
|
{
|
||||||
|
QByteArray flist;
|
||||||
|
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager;
|
||||||
|
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(flistURI)));
|
||||||
|
while (!reply->isFinished())
|
||||||
|
qApp->processEvents();
|
||||||
|
|
||||||
|
if (reply->error() != QNetworkReply::NoError)
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater: getUpdateFlist: network error: "<<reply->errorString();
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
flist = reply->readAll();
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray AutoUpdater::getLocalFlist()
|
||||||
|
{
|
||||||
|
QByteArray flist;
|
||||||
|
|
||||||
|
QFile flistFile("flist");
|
||||||
|
if (!flistFile.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::getLocalFlist: Can't open local flist";
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
flist = flistFile.readAll();
|
||||||
|
flistFile.close();
|
||||||
|
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<AutoUpdater::UpdateFileMeta> AutoUpdater::genUpdateDiff(QList<UpdateFileMeta> updateFlist)
|
||||||
|
{
|
||||||
|
QList<UpdateFileMeta> diff;
|
||||||
|
QList<UpdateFileMeta> localFlist = parseFlist(getLocalFlist());
|
||||||
|
|
||||||
|
for (UpdateFileMeta file : updateFlist)
|
||||||
|
if (!localFlist.contains(file))
|
||||||
|
diff += file;
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoUpdater::UpdateFile AutoUpdater::getUpdateFile(UpdateFileMeta fileMeta)
|
||||||
|
{
|
||||||
|
UpdateFile file;
|
||||||
|
file.metadata = fileMeta;
|
||||||
|
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager;
|
||||||
|
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(filesURI+fileMeta.id)));
|
||||||
|
while (!reply->isFinished())
|
||||||
|
qApp->processEvents();
|
||||||
|
|
||||||
|
if (reply->error() != QNetworkReply::NoError)
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater: getUpdateFile: network error: "<<reply->errorString();
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.data = reply->readAll();
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AutoUpdater::downloadUpdate()
|
||||||
|
{
|
||||||
|
// Updates only for supported platforms
|
||||||
|
if (platform.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Get a list of files to update
|
||||||
|
QByteArray newFlistData = getUpdateFlist();
|
||||||
|
QList<UpdateFileMeta> newFlist = parseFlist(newFlistData);
|
||||||
|
QList<UpdateFileMeta> diff = genUpdateDiff(newFlist);
|
||||||
|
|
||||||
|
qDebug() << "AutoUpdater: Need to update "<<diff.size()<<" files";
|
||||||
|
|
||||||
|
// Create an empty directory to download updates into
|
||||||
|
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
|
||||||
|
QDir updateDir(updateDirStr);
|
||||||
|
if (updateDir.exists())
|
||||||
|
updateDir.removeRecursively();
|
||||||
|
QDir().mkdir(updateDirStr);
|
||||||
|
updateDir = QDir(updateDirStr);
|
||||||
|
if (!updateDir.exists())
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::downloadUpdate: Can't create update directory, aborting...";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the new flist for the updater
|
||||||
|
QFile newFlistFile(updateDirStr+"flist");
|
||||||
|
if (!newFlistFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::downloadUpdate: Can't save new flist file, aborting...";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
newFlistFile.write(newFlistData);
|
||||||
|
newFlistFile.close();
|
||||||
|
|
||||||
|
// Download and write each new file
|
||||||
|
for (UpdateFileMeta fileMeta : diff)
|
||||||
|
{
|
||||||
|
qDebug() << "AutoUpdater: Downloading '"+fileMeta.installpath+"' ...";
|
||||||
|
|
||||||
|
// Create subdirs if necessary
|
||||||
|
QString fileDirStr{QFileInfo(updateDirStr+fileMeta.installpath).absolutePath()};
|
||||||
|
if (!QDir(fileDirStr).exists())
|
||||||
|
QDir().mkpath(fileDirStr);
|
||||||
|
|
||||||
|
// Download
|
||||||
|
UpdateFile file = getUpdateFile(fileMeta);
|
||||||
|
if (file.data.isNull())
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::downloadUpdate: Error downloading a file, aborting...";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check signature
|
||||||
|
if (crypto_sign_verify_detached(file.metadata.sig, (unsigned char*)file.data.data(),
|
||||||
|
file.data.size(), key) != 0)
|
||||||
|
{
|
||||||
|
qCritical() << "AutoUpdater: downloadUpdate: RECEIVED FORGED FILE, aborting...";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save
|
||||||
|
QFile fileFile(updateDirStr+fileMeta.installpath);
|
||||||
|
if (!fileFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::downloadUpdate: Can't save new update file, aborting...";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fileFile.write(file.data);
|
||||||
|
fileFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoUpdater::isLocalUpdateReady()
|
||||||
|
{
|
||||||
|
// Updates only for supported platforms
|
||||||
|
if (platform.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check that there's an update dir in the first place, valid or not
|
||||||
|
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
|
||||||
|
QDir updateDir(updateDirStr);
|
||||||
|
if (!updateDir.exists())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check that we have a flist and that every file on the diff exists
|
||||||
|
QFile updateFlistFile(updateDirStr+"flist");
|
||||||
|
if (!updateFlistFile.open(QIODevice::ReadOnly))
|
||||||
|
return false;
|
||||||
|
QByteArray updateFlistData = updateFlistFile.readAll();
|
||||||
|
updateFlistFile.close();
|
||||||
|
|
||||||
|
QList<UpdateFileMeta> updateFlist = parseFlist(updateFlistData);
|
||||||
|
QList<UpdateFileMeta> diff = genUpdateDiff(updateFlist);
|
||||||
|
|
||||||
|
for (UpdateFileMeta fileMeta : diff)
|
||||||
|
if (!QFile::exists(updateDirStr+fileMeta.installpath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoUpdater::installLocalUpdate()
|
||||||
|
{
|
||||||
|
qDebug() << "AutoUpdater: About to start the qTox updater to install a local update";
|
||||||
|
|
||||||
|
// Delete the update if we fail so we don't fail again.
|
||||||
|
|
||||||
|
// Updates only for supported platforms.
|
||||||
|
if (platform.isEmpty())
|
||||||
|
{
|
||||||
|
qCritical() << "AutoUpdater: Failed to start the qTox updater, removing the update and exiting";
|
||||||
|
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
|
||||||
|
QDir(updateDirStr).removeRecursively();
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround QTBUG-7645
|
||||||
|
// QProcess fails silently when elevation is required instead of showing a UAC prompt on Win7/Vista
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
int result = (int)::ShellExecuteA(0, "open", updaterBin.toUtf8().constData(), 0, 0, SW_SHOWNORMAL);
|
||||||
|
if (SE_ERR_ACCESSDENIED == result)
|
||||||
|
{
|
||||||
|
// Requesting elevation
|
||||||
|
result = (int)::ShellExecuteA(0, "runas", updaterBin.toUtf8().constData(), 0, 0, SW_SHOWNORMAL);
|
||||||
|
}
|
||||||
|
if (result <= 32)
|
||||||
|
{
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!QProcess::startDetached(updaterBin))
|
||||||
|
goto fail;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
// Centralized error handling
|
||||||
|
fail:
|
||||||
|
qCritical() << "AutoUpdater: Failed to start the qTox updater, removing the update and exiting";
|
||||||
|
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
|
||||||
|
QDir(updateDirStr).removeRecursively();
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoUpdater::checkUpdatesAsyncInteractive()
|
||||||
|
{
|
||||||
|
QtConcurrent::run(&AutoUpdater::checkUpdatesAsyncInteractiveWorker);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
|
||||||
|
{
|
||||||
|
if (!isUpdateAvailable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Widget::getInstance()->askMsgboxQuestion(QObject::tr("Update", "The title of a message box"),
|
||||||
|
QObject::tr("An update is available, do you want to download it now ?\nIt will be installed when qTox restarts.")))
|
||||||
|
{
|
||||||
|
downloadUpdate();
|
||||||
|
}
|
||||||
|
}
|
115
src/autoupdate.h
Normal file
115
src/autoupdate.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AUTOUPDATE_H
|
||||||
|
#define AUTOUPDATE_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
/// For now we only support auto updates on Windows, although extending it is not a technical issue.
|
||||||
|
/// Linux and Mac users are expected to use their package managers or update manually through official channels.
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#define AUTOUPDATE_ENABLED 1
|
||||||
|
#else
|
||||||
|
#define AUTOUPDATE_ENABLED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Handles checking and applying updates for qTox
|
||||||
|
/// Do *NOT* use auto update unless AUTOUPDATE_ENABLED is defined to 1
|
||||||
|
class AutoUpdater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct UpdateFileMeta
|
||||||
|
{
|
||||||
|
unsigned char sig[crypto_sign_BYTES]; ///< Signature of the file (ed25519)
|
||||||
|
QString id; ///< Unique id of the file
|
||||||
|
QString installpath; ///< Local path including the file name. May be relative to qtox-updater or absolute
|
||||||
|
uint64_t size; ///< Size in bytes of the file
|
||||||
|
|
||||||
|
bool operator==(const UpdateFileMeta& other)
|
||||||
|
{
|
||||||
|
return (size == other.size
|
||||||
|
&& id == other.id && installpath == other.installpath
|
||||||
|
&& memcmp(sig, other.sig, crypto_sign_BYTES) == 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UpdateFile
|
||||||
|
{
|
||||||
|
UpdateFileMeta metadata;
|
||||||
|
QByteArray data;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Connects to the qTox update server, if an updat is found shows a dialog to the user asking to download it
|
||||||
|
/// Runs asynchronously in its own thread, and will return immediatly
|
||||||
|
/// Will call isUpdateAvailable, and as such may processEvents
|
||||||
|
static void checkUpdatesAsyncInteractive();
|
||||||
|
/// Connects to the qTox update server, returns true if an update is available for download
|
||||||
|
/// Will call getUpdateVersion, and as such may block and processEvents
|
||||||
|
static bool isUpdateAvailable();
|
||||||
|
/// Fetch the version string of the last update available from the qTox update server
|
||||||
|
/// Will try to follow qTox's proxy settings, may block and processEvents
|
||||||
|
static QString getUpdateVersion();
|
||||||
|
/// Will try to download an update, if successful returns true and qTox will apply it after a restart
|
||||||
|
/// Will try to follow qTox's proxy settings, may block and processEvents
|
||||||
|
static bool downloadUpdate();
|
||||||
|
/// Returns true if an update is downloaded and ready to be installed
|
||||||
|
/// If so, call installLocalUpdate. If not, call downloadUpdate.
|
||||||
|
/// This only checks that we downloaded an update and didn't stop in the middle, not that every file is still valid
|
||||||
|
static bool isLocalUpdateReady();
|
||||||
|
/// Launches the qTox updater to try to install the local update and exits immediately
|
||||||
|
/// Will not check that the update actually exists, use isLocalUpdateReady first for that
|
||||||
|
/// The qTox updater will restart us after the update is done
|
||||||
|
/// Note: If we fail to start the qTox updater, we will delete the update and exit
|
||||||
|
[[ noreturn ]] static void installLocalUpdate();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Parses and validates a flist file. Returns an empty list on error
|
||||||
|
static QList<UpdateFileMeta> parseFlist(QByteArray flistData);
|
||||||
|
/// Gets the update server's flist. Returns an empty array on error
|
||||||
|
/// Will try to follow qTox's proxy settings, may block and processEvents
|
||||||
|
static QByteArray getUpdateFlist();
|
||||||
|
/// Gets the local flist. Returns an empty array on error
|
||||||
|
static QByteArray getLocalFlist();
|
||||||
|
/// Generates a list of files we need to update
|
||||||
|
static QList<UpdateFileMeta> genUpdateDiff(QList<UpdateFileMeta> updateFlist);
|
||||||
|
/// Tries to fetch the file from the update server. Returns a file with a null QByteArray on error.
|
||||||
|
/// Note that a file with an empty but non-null QByteArray is not an error, merely a file of size 0.
|
||||||
|
/// Will try to follow qTox's proxy settings, may block and processEvents
|
||||||
|
static UpdateFile getUpdateFile(UpdateFileMeta fileMeta);
|
||||||
|
/// Does the actual work for checkUpdatesAsyncInteractive
|
||||||
|
/// Blocking, but otherwise has the same properties than checkUpdatesAsyncInteractive
|
||||||
|
static void checkUpdatesAsyncInteractiveWorker();
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoUpdater() = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Constants
|
||||||
|
static const QString updateServer; ///< Hostname of the qTox update server
|
||||||
|
static const QString platform; ///< Name of platform we're trying to get updates for
|
||||||
|
static const QString checkURI; ///< URI of the file containing the latest version string
|
||||||
|
static const QString flistURI; ///< URI of the file containing info on each file (hash, signature, size, name, ..)
|
||||||
|
static const QString filesURI; ///< URI of the actual files of the latest version
|
||||||
|
static const QString updaterBin; ///< Path to the qtox-updater binary
|
||||||
|
static unsigned char key[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AUTOUPDATE_H
|
11
src/main.cpp
11
src/main.cpp
|
@ -19,6 +19,7 @@
|
||||||
#include "src/ipc.h"
|
#include "src/ipc.h"
|
||||||
#include "src/widget/toxuri.h"
|
#include "src/widget/toxuri.h"
|
||||||
#include "src/widget/toxsave.h"
|
#include "src/widget/toxsave.h"
|
||||||
|
#include "src/autoupdate.h"
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
@ -27,6 +28,8 @@
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
#ifdef LOG_TO_FILE
|
#ifdef LOG_TO_FILE
|
||||||
static QtMessageHandler dflt;
|
static QtMessageHandler dflt;
|
||||||
static QTextStream* logFile {nullptr};
|
static QTextStream* logFile {nullptr};
|
||||||
|
@ -55,6 +58,8 @@ int main(int argc, char *argv[])
|
||||||
a.setApplicationName("qTox");
|
a.setApplicationName("qTox");
|
||||||
a.setOrganizationName("Tox");
|
a.setOrganizationName("Tox");
|
||||||
|
|
||||||
|
sodium_init(); // For the auto-updater
|
||||||
|
|
||||||
#ifdef LOG_TO_FILE
|
#ifdef LOG_TO_FILE
|
||||||
logFile = new QTextStream;
|
logFile = new QTextStream;
|
||||||
dflt = qInstallMessageHandler(nullptr);
|
dflt = qInstallMessageHandler(nullptr);
|
||||||
|
@ -83,6 +88,12 @@ int main(int argc, char *argv[])
|
||||||
// Install Unicode 6.1 supporting font
|
// Install Unicode 6.1 supporting font
|
||||||
QFontDatabase::addApplicationFont("://DejaVuSans.ttf");
|
QFontDatabase::addApplicationFont("://DejaVuSans.ttf");
|
||||||
|
|
||||||
|
// Check whether we have an update waiting to be installed
|
||||||
|
#if AUTOUPDATE_ENABLED
|
||||||
|
if (AutoUpdater::isLocalUpdateReady())
|
||||||
|
AutoUpdater::installLocalUpdate(); ///< NORETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
// Inter-process communication
|
// Inter-process communication
|
||||||
IPC ipc;
|
IPC ipc;
|
||||||
ipc.registerEventHandler(&toxURIEventHandler);
|
ipc.registerEventHandler(&toxURIEventHandler);
|
||||||
|
|
254
src/misc/serialize.cpp
Normal file
254
src/misc/serialize.cpp
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "src/misc/serialize.h"
|
||||||
|
|
||||||
|
QByteArray doubleToData(double num)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[8];
|
||||||
|
double n;
|
||||||
|
} castUnion;
|
||||||
|
//char n[8];
|
||||||
|
//*((double*) n) = num;
|
||||||
|
|
||||||
|
castUnion.n=num;
|
||||||
|
return QByteArray(castUnion.tab,8);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray floatToData(float num)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[4];
|
||||||
|
float n;
|
||||||
|
} castUnion;
|
||||||
|
|
||||||
|
castUnion.n=num;
|
||||||
|
return QByteArray(castUnion.tab,4);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dataToFloat(QByteArray data)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[4];
|
||||||
|
float n;
|
||||||
|
} castUnion;
|
||||||
|
|
||||||
|
castUnion.tab[0]=data.data()[0];
|
||||||
|
castUnion.tab[1]=data.data()[1];
|
||||||
|
castUnion.tab[2]=data.data()[2];
|
||||||
|
castUnion.tab[3]=data.data()[3];
|
||||||
|
return castUnion.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a string into PNet string data
|
||||||
|
QByteArray stringToData(QString str)
|
||||||
|
{
|
||||||
|
QByteArray data(4,0);
|
||||||
|
// Write the size in a Uint of variable lenght (8-32 bits)
|
||||||
|
int i=0;
|
||||||
|
uint num1 = (uint)str.toUtf8().size();
|
||||||
|
while (num1 >= 0x80)
|
||||||
|
{
|
||||||
|
data[i] = (unsigned char)(num1 | 0x80); i++;
|
||||||
|
num1 = num1 >> 7;
|
||||||
|
}
|
||||||
|
data[i]=num1;
|
||||||
|
data.resize(i+1);
|
||||||
|
data+=str.toUtf8();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString dataToString(QByteArray data)
|
||||||
|
{
|
||||||
|
// Variable UInt32
|
||||||
|
unsigned char num3;
|
||||||
|
int num = 0;
|
||||||
|
int num2 = 0;
|
||||||
|
int i=0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
num3 = data[i]; i++;
|
||||||
|
num |= (num3 & 0x7f) << num2;
|
||||||
|
num2 += 7;
|
||||||
|
} while ((num3 & 0x80) != 0);
|
||||||
|
unsigned int strlen = (uint) num;
|
||||||
|
|
||||||
|
if (!strlen)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
data = data.right(data.size()-i); // Remove the strlen
|
||||||
|
data.truncate(strlen);
|
||||||
|
return QString(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data)
|
||||||
|
{
|
||||||
|
uint endvalue=0;
|
||||||
|
uint value=0;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
endvalue = (uchar)data[0];
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value = (uchar)data[0];
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
endvalue = (value | ((uint) ((uchar)data[1]) << 8));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value |= (uint) (((uchar)data[1]) << 8);
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
uint num2 = (uint) (((uchar)data[2]) << 0x10);
|
||||||
|
endvalue = (value | num2);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value |= (uint) (((uchar)data[2]) << 0x10);
|
||||||
|
numberOfBits -= 8;
|
||||||
|
endvalue = (value | ((uint) (((uchar)data[3]) << 0x18)));
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
float num = max - min;
|
||||||
|
int num2 = (((int) 1) << numberOfBits) - 1;
|
||||||
|
float num3 = endvalue;
|
||||||
|
float num4 = num3 / ((float) num2);
|
||||||
|
return (min + (num4 * num));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
float num = max - min;
|
||||||
|
float num2 = (value - min) / num;
|
||||||
|
int num3 = (((int) 1) << numberOfBits) - 1;
|
||||||
|
uint source = num3 * num2;
|
||||||
|
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source;
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source>>8;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source>>8;
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source>>16;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source>>16;
|
||||||
|
data += (unsigned char)source>>24;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dataToUint8(QByteArray data)
|
||||||
|
{
|
||||||
|
return (uint8_t)data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t dataToUint16(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint16_t)(uint8_t)data[0])
|
||||||
|
+(((uint16_t)(uint8_t)data[1])<<8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dataToUint32(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint32_t)(uint8_t)data[0])
|
||||||
|
+(((uint32_t)(uint8_t)data[1])<<8)
|
||||||
|
+(((uint32_t)(uint8_t)data[2])<<16)
|
||||||
|
+(((uint32_t)(uint8_t)data[3])<<24);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t dataToUint64(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint64_t)(uint8_t)data[0])
|
||||||
|
+(((uint64_t)(uint8_t)data[1])<<8)
|
||||||
|
+(((uint64_t)(uint8_t)data[2])<<16)
|
||||||
|
+(((uint64_t)(uint8_t)data[3])<<24)
|
||||||
|
+(((uint64_t)(uint8_t)data[4])<<32)
|
||||||
|
+(((uint64_t)(uint8_t)data[5])<<40)
|
||||||
|
+(((uint64_t)(uint8_t)data[6])<<48)
|
||||||
|
+(((uint64_t)(uint8_t)data[7])<<56);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getVUint32Size(QByteArray data)
|
||||||
|
{
|
||||||
|
unsigned lensize=0;
|
||||||
|
{
|
||||||
|
unsigned char num3;
|
||||||
|
do {
|
||||||
|
num3 = data[lensize];
|
||||||
|
lensize++;
|
||||||
|
} while ((num3 & 0x80) != 0);
|
||||||
|
}
|
||||||
|
return lensize;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint8ToData(uint8_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(1,0);
|
||||||
|
data[0] = (uint8_t)num;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint16ToData(uint16_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(2,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint32ToData(uint32_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(4,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
data[2] = (uint8_t)((num>>16) & 0xFF);
|
||||||
|
data[3] = (uint8_t)((num>>24) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint64ToData(uint64_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(8,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
data[2] = (uint8_t)((num>>16) & 0xFF);
|
||||||
|
data[3] = (uint8_t)((num>>24) & 0xFF);
|
||||||
|
data[4] = (uint8_t)((num>>32) & 0xFF);
|
||||||
|
data[5] = (uint8_t)((num>>40) & 0xFF);
|
||||||
|
data[6] = (uint8_t)((num>>48) & 0xFF);
|
||||||
|
data[7] = (uint8_t)((num>>56) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
45
src/misc/serialize.h
Normal file
45
src/misc/serialize.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SERIALIZE_H
|
||||||
|
#define SERIALIZE_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
/// Most of those functions are unsafe unless otherwise specified
|
||||||
|
/// Do not use them on untrusted data (e.g. check a signature first)
|
||||||
|
|
||||||
|
QByteArray doubleToData(double num);
|
||||||
|
QByteArray floatToData(float num);
|
||||||
|
float dataToFloat(QByteArray data);
|
||||||
|
QByteArray stringToData(QString str);
|
||||||
|
QString dataToString(QByteArray data);
|
||||||
|
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data);
|
||||||
|
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits);
|
||||||
|
uint8_t dataToUint8(QByteArray data);
|
||||||
|
uint16_t dataToUint16(QByteArray data);
|
||||||
|
uint32_t dataToUint32(QByteArray data);
|
||||||
|
uint64_t dataToUint64(QByteArray data);
|
||||||
|
unsigned getVUint32Size(QByteArray data);
|
||||||
|
QByteArray uint8ToData(uint8_t num);
|
||||||
|
QByteArray uint16ToData(uint16_t num);
|
||||||
|
QByteArray uint32ToData(uint32_t num);
|
||||||
|
QByteArray uint64ToData(uint64_t num);
|
||||||
|
|
||||||
|
#endif // SERIALIZE_H
|
|
@ -119,6 +119,7 @@ void Settings::load()
|
||||||
proxyPort = s.value("proxyPort", 0).toInt();
|
proxyPort = s.value("proxyPort", 0).toInt();
|
||||||
currentProfile = s.value("currentProfile", "").toString();
|
currentProfile = s.value("currentProfile", "").toString();
|
||||||
autoAwayTime = s.value("autoAwayTime", 10).toInt();
|
autoAwayTime = s.value("autoAwayTime", 10).toInt();
|
||||||
|
checkUpdates = s.value("checkUpdates", false).toBool();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
s.beginGroup("Widgets");
|
s.beginGroup("Widgets");
|
||||||
|
@ -255,6 +256,7 @@ void Settings::save(QString path)
|
||||||
s.setValue("proxyPort", proxyPort);
|
s.setValue("proxyPort", proxyPort);
|
||||||
s.setValue("currentProfile", currentProfile);
|
s.setValue("currentProfile", currentProfile);
|
||||||
s.setValue("autoAwayTime", autoAwayTime);
|
s.setValue("autoAwayTime", autoAwayTime);
|
||||||
|
s.setValue("checkUpdates", checkUpdates);
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
s.beginGroup("Widgets");
|
s.beginGroup("Widgets");
|
||||||
|
@ -727,6 +729,16 @@ void Settings::setWindowState(const QByteArray &value)
|
||||||
windowState = value;
|
windowState = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Settings::getCheckUpdates() const
|
||||||
|
{
|
||||||
|
return checkUpdates;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setCheckUpdates(bool newValue)
|
||||||
|
{
|
||||||
|
checkUpdates = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray Settings::getSplitterState() const
|
QByteArray Settings::getSplitterState() const
|
||||||
{
|
{
|
||||||
return splitterState;
|
return splitterState;
|
||||||
|
|
|
@ -99,6 +99,9 @@ public:
|
||||||
int getAutoAwayTime() const;
|
int getAutoAwayTime() const;
|
||||||
void setAutoAwayTime(int newValue);
|
void setAutoAwayTime(int newValue);
|
||||||
|
|
||||||
|
bool getCheckUpdates() const;
|
||||||
|
void setCheckUpdates(bool newValue);
|
||||||
|
|
||||||
QPixmap getSavedAvatar(const QString& ownerId);
|
QPixmap getSavedAvatar(const QString& ownerId);
|
||||||
void saveAvatar(QPixmap& pic, const QString& ownerId);
|
void saveAvatar(QPixmap& pic, const QString& ownerId);
|
||||||
|
|
||||||
|
@ -219,6 +222,7 @@ private:
|
||||||
bool closeToTray;
|
bool closeToTray;
|
||||||
bool minimizeToTray;
|
bool minimizeToTray;
|
||||||
bool useEmoticons;
|
bool useEmoticons;
|
||||||
|
bool checkUpdates;
|
||||||
|
|
||||||
bool forceTCP;
|
bool forceTCP;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#include "src/autoupdate.h"
|
||||||
|
|
||||||
static QStringList locales = {"bg", "de", "en", "fr", "it", "mannol", "pirate", "pl", "ru", "fi", "sv", "uk"};
|
static QStringList locales = {"bg", "de", "en", "fr", "it", "mannol", "pirate", "pl", "ru", "fi", "sv", "uk"};
|
||||||
static QStringList langs = {"Български", "Deustch", "English", "Français", "Italiano", "mannol", "Pirate", "Polski", "Русский", "Suomi", "Svenska", "Українська"};
|
static QStringList langs = {"Български", "Deustch", "English", "Français", "Italiano", "mannol", "Pirate", "Polski", "Русский", "Suomi", "Svenska", "Українська"};
|
||||||
|
|
||||||
|
@ -40,6 +42,9 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
||||||
bodyUI = new Ui::GeneralSettings;
|
bodyUI = new Ui::GeneralSettings;
|
||||||
bodyUI->setupUi(this);
|
bodyUI->setupUi(this);
|
||||||
|
|
||||||
|
bodyUI->checkUpdates->setVisible(AUTOUPDATE_ENABLED);
|
||||||
|
bodyUI->checkUpdates->setChecked(Settings::getInstance().getCheckUpdates());
|
||||||
|
|
||||||
bodyUI->cbEnableIPv6->setChecked(Settings::getInstance().getEnableIPv6());
|
bodyUI->cbEnableIPv6->setChecked(Settings::getInstance().getEnableIPv6());
|
||||||
for (int i = 0; i < langs.size(); i++)
|
for (int i = 0; i < langs.size(); i++)
|
||||||
bodyUI->transComboBox->insertItem(i, langs[i]);
|
bodyUI->transComboBox->insertItem(i, langs[i]);
|
||||||
|
@ -93,6 +98,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
||||||
onUseProxyUpdated();
|
onUseProxyUpdated();
|
||||||
|
|
||||||
//general
|
//general
|
||||||
|
connect(bodyUI->checkUpdates, &QCheckBox::stateChanged, this, &GeneralForm::onCheckUpdateChanged);
|
||||||
connect(bodyUI->transComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onTranslationUpdated()));
|
connect(bodyUI->transComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onTranslationUpdated()));
|
||||||
connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &GeneralForm::onMakeToxPortableUpdated);
|
connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &GeneralForm::onMakeToxPortableUpdated);
|
||||||
connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray);
|
connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray);
|
||||||
|
@ -280,3 +286,8 @@ void GeneralForm::reloadSmiles()
|
||||||
bodyUI->smile4->setToolTip(smiles[3]);
|
bodyUI->smile4->setToolTip(smiles[3]);
|
||||||
bodyUI->smile5->setToolTip(smiles[4]);
|
bodyUI->smile5->setToolTip(smiles[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneralForm::onCheckUpdateChanged()
|
||||||
|
{
|
||||||
|
Settings::getInstance().setCheckUpdates(bodyUI->checkUpdates->isChecked());
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ private slots:
|
||||||
void onReconnectClicked();
|
void onReconnectClicked();
|
||||||
void onAutoAcceptFileChange();
|
void onAutoAcceptFileChange();
|
||||||
void onAutoSaveDirChange();
|
void onAutoSaveDirChange();
|
||||||
|
void onCheckUpdateChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::GeneralSettings *bodyUI;
|
Ui::GeneralSettings *bodyUI;
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>511</width>
|
<width>511</width>
|
||||||
<height>739</height>
|
<height>720</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1">
|
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1">
|
||||||
|
@ -121,6 +121,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkUpdates">
|
||||||
|
<property name="text">
|
||||||
|
<string>Check for updates on startup (unstable)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item alignment="Qt::AlignLeft">
|
<item alignment="Qt::AlignLeft">
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
#include "src/video/camera.h"
|
#include "src/video/camera.h"
|
||||||
#include "form/chatform.h"
|
#include "form/chatform.h"
|
||||||
#include "maskablepixmapwidget.h"
|
#include "maskablepixmapwidget.h"
|
||||||
|
#include "src/historykeeper.h"
|
||||||
|
#include "form/inputpassworddialog.h"
|
||||||
|
#include "src/autoupdate.h"
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
@ -45,9 +48,7 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
#include "src/historykeeper.h"
|
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
#include "form/inputpassworddialog.h"
|
|
||||||
|
|
||||||
Widget *Widget::instance{nullptr};
|
Widget *Widget::instance{nullptr};
|
||||||
|
|
||||||
|
@ -244,6 +245,11 @@ void Widget::init()
|
||||||
coreThread->start();
|
coreThread->start();
|
||||||
|
|
||||||
addFriendForm->show(*ui);
|
addFriendForm->show(*ui);
|
||||||
|
|
||||||
|
#if (AUTOUPDATE_ENABLED)
|
||||||
|
if (Settings::getInstance().getCheckUpdates())
|
||||||
|
AutoUpdater::checkUpdatesAsyncInteractive();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::setTranslation()
|
void Widget::setTranslation()
|
||||||
|
@ -1095,3 +1101,20 @@ void Widget::setEnabledThreadsafe(bool enabled)
|
||||||
return setEnabled(enabled);
|
return setEnabled(enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Widget::askMsgboxQuestion(const QString& title, const QString& msg)
|
||||||
|
{
|
||||||
|
// We can only display widgets from the GUI thread
|
||||||
|
if (QThread::currentThread() != qApp->thread())
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
QMetaObject::invokeMethod(this, "askMsgboxQuestion", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(bool, ret),
|
||||||
|
Q_ARG(const QString&, title), Q_ARG(const QString&, msg));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return QMessageBox::question(this, title, msg) == QMessageBox::StandardButton::Yes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
Q_INVOKABLE QMessageBox::StandardButton showWarningMsgBox(const QString& title, const QString& msg,
|
Q_INVOKABLE QMessageBox::StandardButton showWarningMsgBox(const QString& title, const QString& msg,
|
||||||
QMessageBox::StandardButtons buttonss = QMessageBox::Ok);
|
QMessageBox::StandardButtons buttonss = QMessageBox::Ok);
|
||||||
Q_INVOKABLE void setEnabledThreadsafe(bool enabled);
|
Q_INVOKABLE void setEnabledThreadsafe(bool enabled);
|
||||||
|
Q_INVOKABLE bool askMsgboxQuestion(const QString& title, const QString& msg);
|
||||||
~Widget();
|
~Widget();
|
||||||
|
|
||||||
virtual void closeEvent(QCloseEvent *event);
|
virtual void closeEvent(QCloseEvent *event);
|
||||||
|
|
97
tools/update-server/qtox-updater-genflist/main.cpp
Normal file
97
tools/update-server/qtox-updater-genflist/main.cpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include <sodium.h>
|
||||||
|
#include "serialize.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
/// Pass the target folder as first argument, no spaces allowed. We'll call that dir $TARGET
|
||||||
|
/// Update the content of $TARGET/files/ before calling this tool
|
||||||
|
/// We'll generate $TARGET/flist and exit
|
||||||
|
/// We need qtox-updater-skey in our working directory to sign the flist
|
||||||
|
///
|
||||||
|
/// The generated flist is very simple and just installs everything in the working directory ...
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
cout << "qTox updater flist generator" << endl;
|
||||||
|
|
||||||
|
/// First some basic error handling, prepare our handles, ...
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
cout << "ERROR: qtox-updater-genflist takes the target path in argument" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile skeyFile("qtox-updater-skey");
|
||||||
|
if (!skeyFile.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
cout << "ERROR: qtox-updater-genflist can't open the secret (private) key file" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
QByteArray skeyData = skeyFile.readAll();
|
||||||
|
skeyData = QByteArray::fromHex(skeyData);
|
||||||
|
skeyFile.close();
|
||||||
|
|
||||||
|
QString target(argv[1]);
|
||||||
|
|
||||||
|
QFile flistFile(target+"/flist");
|
||||||
|
if (!flistFile.open(QIODevice::Truncate | QIODevice::WriteOnly))
|
||||||
|
{
|
||||||
|
cout << "ERROR: qtox-updater-genflist can't open the target flist" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir fdir(target+"/files/");
|
||||||
|
if (!fdir.isReadable())
|
||||||
|
{
|
||||||
|
cout << "ERROR: qtox-updater-genflist can't open the target files directory" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList filesListStr = fdir.entryList(QDir::Files);
|
||||||
|
|
||||||
|
/// Serialize the flist data
|
||||||
|
QByteArray flistData;
|
||||||
|
for (QString fileStr : filesListStr)
|
||||||
|
{
|
||||||
|
cout << "Adding "<<fileStr.toStdString()<<"..."<<endl;
|
||||||
|
|
||||||
|
QFile file(target+"/files/"+fileStr);
|
||||||
|
if (!file.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
cout << "ERROR: qtox-updater-genflist couldn't open a target file to sign it" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray fileData = file.readAll();
|
||||||
|
|
||||||
|
unsigned char sig[crypto_sign_BYTES];
|
||||||
|
crypto_sign_detached(sig, nullptr, (unsigned char*)fileData.data(), fileData.size(), (unsigned char*)skeyData.data());
|
||||||
|
|
||||||
|
flistData += QByteArray::fromRawData((char*)sig, crypto_sign_BYTES);
|
||||||
|
flistData += stringToData(QCryptographicHash::hash(fileStr.toUtf8(), QCryptographicHash::Sha3_224).toHex());
|
||||||
|
flistData += stringToData("./"+fileStr); ///< Always install in the working directory for now
|
||||||
|
flistData += uint64ToData(fileData.size());
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "Signing and writing the flist..."<<endl;
|
||||||
|
|
||||||
|
/// Sign our flist
|
||||||
|
unsigned char sig[crypto_sign_BYTES];
|
||||||
|
crypto_sign_detached(sig, nullptr, (unsigned char*)flistData.data(), flistData.size(), (unsigned char*)skeyData.data());
|
||||||
|
|
||||||
|
/// Write the flist
|
||||||
|
flistFile.write("1");
|
||||||
|
flistFile.write((char*)sig, crypto_sign_BYTES);
|
||||||
|
flistFile.write(flistData);
|
||||||
|
|
||||||
|
flistFile.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console c++11
|
||||||
|
QT += core
|
||||||
|
LIBS += -lsodium
|
||||||
|
|
||||||
|
SOURCES += main.cpp \
|
||||||
|
serialize.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
serialize.h
|
254
tools/update-server/qtox-updater-genflist/serialize.cpp
Normal file
254
tools/update-server/qtox-updater-genflist/serialize.cpp
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "serialize.h"
|
||||||
|
|
||||||
|
QByteArray doubleToData(double num)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[8];
|
||||||
|
double n;
|
||||||
|
} castUnion;
|
||||||
|
//char n[8];
|
||||||
|
//*((double*) n) = num;
|
||||||
|
|
||||||
|
castUnion.n=num;
|
||||||
|
return QByteArray(castUnion.tab,8);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray floatToData(float num)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[4];
|
||||||
|
float n;
|
||||||
|
} castUnion;
|
||||||
|
|
||||||
|
castUnion.n=num;
|
||||||
|
return QByteArray(castUnion.tab,4);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dataToFloat(QByteArray data)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[4];
|
||||||
|
float n;
|
||||||
|
} castUnion;
|
||||||
|
|
||||||
|
castUnion.tab[0]=data.data()[0];
|
||||||
|
castUnion.tab[1]=data.data()[1];
|
||||||
|
castUnion.tab[2]=data.data()[2];
|
||||||
|
castUnion.tab[3]=data.data()[3];
|
||||||
|
return castUnion.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a string into PNet string data
|
||||||
|
QByteArray stringToData(QString str)
|
||||||
|
{
|
||||||
|
QByteArray data(4,0);
|
||||||
|
// Write the size in a Uint of variable lenght (8-32 bits)
|
||||||
|
int i=0;
|
||||||
|
uint num1 = (uint)str.toUtf8().size();
|
||||||
|
while (num1 >= 0x80)
|
||||||
|
{
|
||||||
|
data[i] = (unsigned char)(num1 | 0x80); i++;
|
||||||
|
num1 = num1 >> 7;
|
||||||
|
}
|
||||||
|
data[i]=num1;
|
||||||
|
data.resize(i+1);
|
||||||
|
data+=str.toUtf8();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString dataToString(QByteArray data)
|
||||||
|
{
|
||||||
|
// Variable UInt32
|
||||||
|
unsigned char num3;
|
||||||
|
int num = 0;
|
||||||
|
int num2 = 0;
|
||||||
|
int i=0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
num3 = data[i]; i++;
|
||||||
|
num |= (num3 & 0x7f) << num2;
|
||||||
|
num2 += 7;
|
||||||
|
} while ((num3 & 0x80) != 0);
|
||||||
|
unsigned int strlen = (uint) num;
|
||||||
|
|
||||||
|
if (!strlen)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
data = data.right(data.size()-i); // Remove the strlen
|
||||||
|
data.truncate(strlen);
|
||||||
|
return QString(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data)
|
||||||
|
{
|
||||||
|
uint endvalue=0;
|
||||||
|
uint value=0;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
endvalue = (uchar)data[0];
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value = (uchar)data[0];
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
endvalue = (value | ((uint) ((uchar)data[1]) << 8));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value |= (uint) (((uchar)data[1]) << 8);
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
uint num2 = (uint) (((uchar)data[2]) << 0x10);
|
||||||
|
endvalue = (value | num2);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value |= (uint) (((uchar)data[2]) << 0x10);
|
||||||
|
numberOfBits -= 8;
|
||||||
|
endvalue = (value | ((uint) (((uchar)data[3]) << 0x18)));
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
float num = max - min;
|
||||||
|
int num2 = (((int) 1) << numberOfBits) - 1;
|
||||||
|
float num3 = endvalue;
|
||||||
|
float num4 = num3 / ((float) num2);
|
||||||
|
return (min + (num4 * num));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
float num = max - min;
|
||||||
|
float num2 = (value - min) / num;
|
||||||
|
int num3 = (((int) 1) << numberOfBits) - 1;
|
||||||
|
uint source = num3 * num2;
|
||||||
|
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source;
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source>>8;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source>>8;
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source>>16;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source>>16;
|
||||||
|
data += (unsigned char)source>>24;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dataToUint8(QByteArray data)
|
||||||
|
{
|
||||||
|
return (uint8_t)data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t dataToUint16(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint16_t)(uint8_t)data[0])
|
||||||
|
+(((uint16_t)(uint8_t)data[1])<<8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dataToUint32(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint32_t)(uint8_t)data[0])
|
||||||
|
+(((uint32_t)(uint8_t)data[1])<<8)
|
||||||
|
+(((uint32_t)(uint8_t)data[2])<<16)
|
||||||
|
+(((uint32_t)(uint8_t)data[3])<<24);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t dataToUint64(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint64_t)(uint8_t)data[0])
|
||||||
|
+(((uint64_t)(uint8_t)data[1])<<8)
|
||||||
|
+(((uint64_t)(uint8_t)data[2])<<16)
|
||||||
|
+(((uint64_t)(uint8_t)data[3])<<24)
|
||||||
|
+(((uint64_t)(uint8_t)data[4])<<32)
|
||||||
|
+(((uint64_t)(uint8_t)data[5])<<40)
|
||||||
|
+(((uint64_t)(uint8_t)data[6])<<48)
|
||||||
|
+(((uint64_t)(uint8_t)data[7])<<56);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getVUint32Size(QByteArray data)
|
||||||
|
{
|
||||||
|
unsigned lensize=0;
|
||||||
|
{
|
||||||
|
unsigned char num3;
|
||||||
|
do {
|
||||||
|
num3 = data[lensize];
|
||||||
|
lensize++;
|
||||||
|
} while ((num3 & 0x80) != 0);
|
||||||
|
}
|
||||||
|
return lensize;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint8ToData(uint8_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(1,0);
|
||||||
|
data[0] = (uint8_t)num;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint16ToData(uint16_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(2,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint32ToData(uint32_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(4,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
data[2] = (uint8_t)((num>>16) & 0xFF);
|
||||||
|
data[3] = (uint8_t)((num>>24) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint64ToData(uint64_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(8,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
data[2] = (uint8_t)((num>>16) & 0xFF);
|
||||||
|
data[3] = (uint8_t)((num>>24) & 0xFF);
|
||||||
|
data[4] = (uint8_t)((num>>32) & 0xFF);
|
||||||
|
data[5] = (uint8_t)((num>>40) & 0xFF);
|
||||||
|
data[6] = (uint8_t)((num>>48) & 0xFF);
|
||||||
|
data[7] = (uint8_t)((num>>56) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
45
tools/update-server/qtox-updater-genflist/serialize.h
Normal file
45
tools/update-server/qtox-updater-genflist/serialize.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SERIALIZE_H
|
||||||
|
#define SERIALIZE_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
/// Most of those functions are unsafe unless otherwise specified
|
||||||
|
/// Do not use them on untrusted data (e.g. check a signature first)
|
||||||
|
|
||||||
|
QByteArray doubleToData(double num);
|
||||||
|
QByteArray floatToData(float num);
|
||||||
|
float dataToFloat(QByteArray data);
|
||||||
|
QByteArray stringToData(QString str);
|
||||||
|
QString dataToString(QByteArray data);
|
||||||
|
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data);
|
||||||
|
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits);
|
||||||
|
uint8_t dataToUint8(QByteArray data);
|
||||||
|
uint16_t dataToUint16(QByteArray data);
|
||||||
|
uint32_t dataToUint32(QByteArray data);
|
||||||
|
uint64_t dataToUint64(QByteArray data);
|
||||||
|
unsigned getVUint32Size(QByteArray data);
|
||||||
|
QByteArray uint8ToData(uint8_t num);
|
||||||
|
QByteArray uint16ToData(uint16_t num);
|
||||||
|
QByteArray uint32ToData(uint32_t num);
|
||||||
|
QByteArray uint64ToData(uint64_t num);
|
||||||
|
|
||||||
|
#endif // SERIALIZE_H
|
43
tools/update-server/qtox-updater-sign/main.cpp
Normal file
43
tools/update-server/qtox-updater-sign/main.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include <sodium.h>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
QFile io;
|
||||||
|
QByteArray msg;
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
msg = QByteArray(argv[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
io.open(stdin, QIODevice::ReadOnly);
|
||||||
|
msg = io.readAll();
|
||||||
|
io.close();
|
||||||
|
}
|
||||||
|
io.open(stdout, QIODevice::WriteOnly);
|
||||||
|
|
||||||
|
QFile skeyFile("qtox-updater-skey");
|
||||||
|
if (!skeyFile.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
io.write("ERROR: qtox-updater-sign can't open the secret (private) key file\n");
|
||||||
|
io.close();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
QByteArray skeyData = skeyFile.readAll();
|
||||||
|
skeyData = QByteArray::fromHex(skeyData);
|
||||||
|
skeyFile.close();
|
||||||
|
|
||||||
|
unsigned char sig[crypto_sign_BYTES];
|
||||||
|
crypto_sign_detached(sig, nullptr, (unsigned char*)msg.data(), msg.size(), (unsigned char*)skeyData.data());
|
||||||
|
|
||||||
|
io.write((char*)sig, crypto_sign_BYTES);
|
||||||
|
io.write(msg);
|
||||||
|
io.close();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console c++11
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
||||||
|
|
||||||
|
LIBS += -lsodium
|
28
updater/main.cpp
Normal file
28
updater/main.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "widget.h"
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
Widget w;
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
5
updater/res.qrc
Normal file
5
updater/res.qrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>res/qtox-256x256.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
BIN
updater/res/qtox-256x256.png
Normal file
BIN
updater/res/qtox-256x256.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
254
updater/serialize.cpp
Normal file
254
updater/serialize.cpp
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "serialize.h"
|
||||||
|
|
||||||
|
QByteArray doubleToData(double num)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[8];
|
||||||
|
double n;
|
||||||
|
} castUnion;
|
||||||
|
//char n[8];
|
||||||
|
//*((double*) n) = num;
|
||||||
|
|
||||||
|
castUnion.n=num;
|
||||||
|
return QByteArray(castUnion.tab,8);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray floatToData(float num)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[4];
|
||||||
|
float n;
|
||||||
|
} castUnion;
|
||||||
|
|
||||||
|
castUnion.n=num;
|
||||||
|
return QByteArray(castUnion.tab,4);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dataToFloat(QByteArray data)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char tab[4];
|
||||||
|
float n;
|
||||||
|
} castUnion;
|
||||||
|
|
||||||
|
castUnion.tab[0]=data.data()[0];
|
||||||
|
castUnion.tab[1]=data.data()[1];
|
||||||
|
castUnion.tab[2]=data.data()[2];
|
||||||
|
castUnion.tab[3]=data.data()[3];
|
||||||
|
return castUnion.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a string into PNet string data
|
||||||
|
QByteArray stringToData(QString str)
|
||||||
|
{
|
||||||
|
QByteArray data(4,0);
|
||||||
|
// Write the size in a Uint of variable lenght (8-32 bits)
|
||||||
|
int i=0;
|
||||||
|
uint num1 = (uint)str.toUtf8().size();
|
||||||
|
while (num1 >= 0x80)
|
||||||
|
{
|
||||||
|
data[i] = (unsigned char)(num1 | 0x80); i++;
|
||||||
|
num1 = num1 >> 7;
|
||||||
|
}
|
||||||
|
data[i]=num1;
|
||||||
|
data.resize(i+1);
|
||||||
|
data+=str.toUtf8();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString dataToString(QByteArray data)
|
||||||
|
{
|
||||||
|
// Variable UInt32
|
||||||
|
unsigned char num3;
|
||||||
|
int num = 0;
|
||||||
|
int num2 = 0;
|
||||||
|
int i=0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
num3 = data[i]; i++;
|
||||||
|
num |= (num3 & 0x7f) << num2;
|
||||||
|
num2 += 7;
|
||||||
|
} while ((num3 & 0x80) != 0);
|
||||||
|
unsigned int strlen = (uint) num;
|
||||||
|
|
||||||
|
if (!strlen)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
data = data.right(data.size()-i); // Remove the strlen
|
||||||
|
data.truncate(strlen);
|
||||||
|
return QString(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data)
|
||||||
|
{
|
||||||
|
uint endvalue=0;
|
||||||
|
uint value=0;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
endvalue = (uchar)data[0];
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value = (uchar)data[0];
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
endvalue = (value | ((uint) ((uchar)data[1]) << 8));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value |= (uint) (((uchar)data[1]) << 8);
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
uint num2 = (uint) (((uchar)data[2]) << 0x10);
|
||||||
|
endvalue = (value | num2);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
value |= (uint) (((uchar)data[2]) << 0x10);
|
||||||
|
numberOfBits -= 8;
|
||||||
|
endvalue = (value | ((uint) (((uchar)data[3]) << 0x18)));
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
float num = max - min;
|
||||||
|
int num2 = (((int) 1) << numberOfBits) - 1;
|
||||||
|
float num3 = endvalue;
|
||||||
|
float num4 = num3 / ((float) num2);
|
||||||
|
return (min + (num4 * num));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
float num = max - min;
|
||||||
|
float num2 = (value - min) / num;
|
||||||
|
int num3 = (((int) 1) << numberOfBits) - 1;
|
||||||
|
uint source = num3 * num2;
|
||||||
|
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source;
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source>>8;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source>>8;
|
||||||
|
numberOfBits -= 8;
|
||||||
|
if (numberOfBits <= 8)
|
||||||
|
{
|
||||||
|
data += (unsigned char)source>>16;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data += (unsigned char)source>>16;
|
||||||
|
data += (unsigned char)source>>24;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dataToUint8(QByteArray data)
|
||||||
|
{
|
||||||
|
return (uint8_t)data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t dataToUint16(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint16_t)(uint8_t)data[0])
|
||||||
|
+(((uint16_t)(uint8_t)data[1])<<8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dataToUint32(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint32_t)(uint8_t)data[0])
|
||||||
|
+(((uint32_t)(uint8_t)data[1])<<8)
|
||||||
|
+(((uint32_t)(uint8_t)data[2])<<16)
|
||||||
|
+(((uint32_t)(uint8_t)data[3])<<24);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t dataToUint64(QByteArray data)
|
||||||
|
{
|
||||||
|
return ((uint64_t)(uint8_t)data[0])
|
||||||
|
+(((uint64_t)(uint8_t)data[1])<<8)
|
||||||
|
+(((uint64_t)(uint8_t)data[2])<<16)
|
||||||
|
+(((uint64_t)(uint8_t)data[3])<<24)
|
||||||
|
+(((uint64_t)(uint8_t)data[4])<<32)
|
||||||
|
+(((uint64_t)(uint8_t)data[5])<<40)
|
||||||
|
+(((uint64_t)(uint8_t)data[6])<<48)
|
||||||
|
+(((uint64_t)(uint8_t)data[7])<<56);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getVUint32Size(QByteArray data)
|
||||||
|
{
|
||||||
|
unsigned lensize=0;
|
||||||
|
{
|
||||||
|
unsigned char num3;
|
||||||
|
do {
|
||||||
|
num3 = data[lensize];
|
||||||
|
lensize++;
|
||||||
|
} while ((num3 & 0x80) != 0);
|
||||||
|
}
|
||||||
|
return lensize;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint8ToData(uint8_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(1,0);
|
||||||
|
data[0] = (uint8_t)num;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint16ToData(uint16_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(2,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint32ToData(uint32_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(4,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
data[2] = (uint8_t)((num>>16) & 0xFF);
|
||||||
|
data[3] = (uint8_t)((num>>24) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray uint64ToData(uint64_t num)
|
||||||
|
{
|
||||||
|
QByteArray data(8,0);
|
||||||
|
data[0] = (uint8_t)(num & 0xFF);
|
||||||
|
data[1] = (uint8_t)((num>>8) & 0xFF);
|
||||||
|
data[2] = (uint8_t)((num>>16) & 0xFF);
|
||||||
|
data[3] = (uint8_t)((num>>24) & 0xFF);
|
||||||
|
data[4] = (uint8_t)((num>>32) & 0xFF);
|
||||||
|
data[5] = (uint8_t)((num>>40) & 0xFF);
|
||||||
|
data[6] = (uint8_t)((num>>48) & 0xFF);
|
||||||
|
data[7] = (uint8_t)((num>>56) & 0xFF);
|
||||||
|
return data;
|
||||||
|
}
|
45
updater/serialize.h
Normal file
45
updater/serialize.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SERIALIZE_H
|
||||||
|
#define SERIALIZE_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
/// Most of those functions are unsafe unless otherwise specified
|
||||||
|
/// Do not use them on untrusted data (e.g. check a signature first)
|
||||||
|
|
||||||
|
QByteArray doubleToData(double num);
|
||||||
|
QByteArray floatToData(float num);
|
||||||
|
float dataToFloat(QByteArray data);
|
||||||
|
QByteArray stringToData(QString str);
|
||||||
|
QString dataToString(QByteArray data);
|
||||||
|
float dataToRangedSingle(float min, float max, int numberOfBits, QByteArray data);
|
||||||
|
QByteArray rangedSingleToData(float value, float min, float max, int numberOfBits);
|
||||||
|
uint8_t dataToUint8(QByteArray data);
|
||||||
|
uint16_t dataToUint16(QByteArray data);
|
||||||
|
uint32_t dataToUint32(QByteArray data);
|
||||||
|
uint64_t dataToUint64(QByteArray data);
|
||||||
|
unsigned getVUint32Size(QByteArray data);
|
||||||
|
QByteArray uint8ToData(uint8_t num);
|
||||||
|
QByteArray uint16ToData(uint16_t num);
|
||||||
|
QByteArray uint32ToData(uint32_t num);
|
||||||
|
QByteArray uint64ToData(uint64_t num);
|
||||||
|
|
||||||
|
#endif // SERIALIZE_H
|
52
updater/settingsDir.cpp
Normal file
52
updater/settingsDir.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "settingsDir.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
const QString FILENAME = "settings.ini";
|
||||||
|
|
||||||
|
QString getSettingsDirPath()
|
||||||
|
{
|
||||||
|
if (isToxPortableEnabled())
|
||||||
|
return ".";
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
|
||||||
|
+ QDir::separator() + "AppData" + QDir::separator() + "Roaming" + QDir::separator() + "tox");
|
||||||
|
#else
|
||||||
|
return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QDir::separator() + "tox");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isToxPortableEnabled()
|
||||||
|
{
|
||||||
|
QFile portableSettings(FILENAME);
|
||||||
|
if (portableSettings.exists())
|
||||||
|
{
|
||||||
|
QSettings ps(FILENAME, QSettings::IniFormat);
|
||||||
|
ps.beginGroup("General");
|
||||||
|
return ps.value("makeToxPortable", false).toBool();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
27
updater/settingsDir.h
Normal file
27
updater/settingsDir.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SETTINGSDIR_H
|
||||||
|
#define SETTINGSDIR_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
QString getSettingsDirPath();
|
||||||
|
|
||||||
|
bool isToxPortableEnabled();
|
||||||
|
|
||||||
|
#endif // SETTINGSDIR_H
|
115
updater/update.cpp
Normal file
115
updater/update.cpp
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "update.h"
|
||||||
|
#include "serialize.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
unsigned char key[crypto_sign_PUBLICKEYBYTES] =
|
||||||
|
{
|
||||||
|
0xa5, 0x80, 0xf3, 0xb7, 0xd0, 0x10, 0xc0, 0xf9, 0xd6, 0xcf, 0x48, 0x15, 0x99, 0x70, 0x92, 0x49,
|
||||||
|
0xf6, 0xe8, 0xe5, 0xe2, 0x6c, 0x73, 0x8c, 0x48, 0x25, 0xed, 0x01, 0x72, 0xf7, 0x6c, 0x17, 0x28
|
||||||
|
};
|
||||||
|
|
||||||
|
QByteArray getLocalFlist()
|
||||||
|
{
|
||||||
|
QByteArray flist;
|
||||||
|
|
||||||
|
QFile flistFile("flist");
|
||||||
|
if (!flistFile.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
qWarning() << "getLocalFlist: Can't open local flist";
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
flist = flistFile.readAll();
|
||||||
|
flistFile.close();
|
||||||
|
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<UpdateFileMeta> genUpdateDiff(QList<UpdateFileMeta> updateFlist)
|
||||||
|
{
|
||||||
|
QList<UpdateFileMeta> diff;
|
||||||
|
QList<UpdateFileMeta> localFlist = parseFlist(getLocalFlist());
|
||||||
|
|
||||||
|
for (UpdateFileMeta file : updateFlist)
|
||||||
|
if (!localFlist.contains(file))
|
||||||
|
diff += file;
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<UpdateFileMeta> parseFlist(QByteArray flistData)
|
||||||
|
{
|
||||||
|
QList<UpdateFileMeta> flist;
|
||||||
|
|
||||||
|
if (flistData.isEmpty())
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::parseflist: Empty data";
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check version
|
||||||
|
if (flistData[0] != '1')
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater: parseflist: Bad version "<<(uint8_t)flistData[0];
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
flistData = flistData.mid(1);
|
||||||
|
|
||||||
|
// Check signature
|
||||||
|
if (flistData.size() < (int)(crypto_sign_BYTES))
|
||||||
|
{
|
||||||
|
qWarning() << "AutoUpdater::parseflist: Truncated data";
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QByteArray msgData = flistData.mid(crypto_sign_BYTES);
|
||||||
|
unsigned char* msg = (unsigned char*)msgData.data();
|
||||||
|
if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key) != 0)
|
||||||
|
{
|
||||||
|
qCritical() << "AutoUpdater: parseflist: FORGED FLIST FILE";
|
||||||
|
return flist;
|
||||||
|
}
|
||||||
|
flistData = flistData.mid(crypto_sign_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse. We assume no errors handling needed since the signature is valid.
|
||||||
|
while (!flistData.isEmpty())
|
||||||
|
{
|
||||||
|
UpdateFileMeta newFile;
|
||||||
|
|
||||||
|
memcpy(newFile.sig, flistData.data(), crypto_sign_BYTES);
|
||||||
|
flistData = flistData.mid(crypto_sign_BYTES);
|
||||||
|
|
||||||
|
newFile.id = dataToString(flistData);
|
||||||
|
flistData = flistData.mid(newFile.id.size() + getVUint32Size(flistData));
|
||||||
|
|
||||||
|
newFile.installpath = dataToString(flistData);
|
||||||
|
flistData = flistData.mid(newFile.installpath.size() + getVUint32Size(flistData));
|
||||||
|
|
||||||
|
newFile.size = dataToUint64(flistData);
|
||||||
|
flistData = flistData.mid(8);
|
||||||
|
|
||||||
|
flist += newFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flist;
|
||||||
|
}
|
55
updater/update.h
Normal file
55
updater/update.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UPDATE_H
|
||||||
|
#define UPDATE_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
struct UpdateFileMeta
|
||||||
|
{
|
||||||
|
unsigned char sig[crypto_sign_BYTES]; ///< Signature of the file (ed25519)
|
||||||
|
QString id; ///< Unique id of the file
|
||||||
|
QString installpath; ///< Local path including the file name. May be relative to qtox-updater or absolute
|
||||||
|
uint64_t size; ///< Size in bytes of the file
|
||||||
|
|
||||||
|
bool operator==(const UpdateFileMeta& other)
|
||||||
|
{
|
||||||
|
return (size == other.size
|
||||||
|
&& id == other.id && installpath == other.installpath
|
||||||
|
&& memcmp(sig, other.sig, crypto_sign_BYTES) == 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UpdateFile
|
||||||
|
{
|
||||||
|
UpdateFileMeta metadata;
|
||||||
|
QByteArray data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Gets the local flist. Returns an empty array on error
|
||||||
|
QByteArray getLocalFlist();
|
||||||
|
/// Parses and validates a flist file. Returns an empty list on error
|
||||||
|
QList<UpdateFileMeta> parseFlist(QByteArray flistData);
|
||||||
|
/// Generates a list of files we need to update
|
||||||
|
QList<UpdateFileMeta> genUpdateDiff(QList<UpdateFileMeta> updateFlist);
|
||||||
|
|
||||||
|
extern unsigned char key[crypto_sign_PUBLICKEYBYTES];
|
||||||
|
|
||||||
|
#endif // UPDATE_H
|
36
updater/updater.pro
Normal file
36
updater/updater.pro
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#-------------------------------------------------
|
||||||
|
#
|
||||||
|
# Project created by QtCreator 2014-11-09T21:09:08
|
||||||
|
#
|
||||||
|
#-------------------------------------------------
|
||||||
|
|
||||||
|
QT += core gui
|
||||||
|
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
TARGET = qtox-updater
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
SOURCES += main.cpp\
|
||||||
|
widget.cpp \
|
||||||
|
settingsDir.cpp \
|
||||||
|
update.cpp \
|
||||||
|
serialize.cpp
|
||||||
|
|
||||||
|
HEADERS += widget.h \
|
||||||
|
settingsDir.h \
|
||||||
|
update.h \
|
||||||
|
serialize.h
|
||||||
|
|
||||||
|
FORMS += widget.ui
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
res.qrc
|
||||||
|
|
||||||
|
INCLUDEPATH += libs/include
|
||||||
|
|
||||||
|
RC_FILE = windows/updater.rc
|
||||||
|
|
||||||
|
LIBS += -L$$PWD/libs/lib/ -lsodium
|
156
updater/widget.cpp
Normal file
156
updater/widget.cpp
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "widget.h"
|
||||||
|
#include "ui_widget.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QMetaObject>
|
||||||
|
|
||||||
|
#include "settingsDir.h"
|
||||||
|
#include "update.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
const bool supported = true;
|
||||||
|
const QString QTOX_PATH = "qtox.exe";
|
||||||
|
#else
|
||||||
|
const bool supported = false;
|
||||||
|
const QString QTOX_PATH;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Widget::Widget(QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
ui(new Ui::Widget)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
// Updates only for supported platforms
|
||||||
|
if (!supported)
|
||||||
|
{
|
||||||
|
fatalError(tr("The qTox updater is not supported on this platform."));
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::~Widget()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setProgress(int value)
|
||||||
|
{
|
||||||
|
ui->progress->setValue(value);
|
||||||
|
qApp->processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::fatalError(QString message)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this,tr("Error"), message+'\n'+tr("qTox will restart now."));
|
||||||
|
deleteUpdate();
|
||||||
|
startQToxAndExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::deleteUpdate()
|
||||||
|
{
|
||||||
|
QDir updateDir(getSettingsDirPath()+"/update/");
|
||||||
|
updateDir.removeRecursively();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::startQToxAndExit()
|
||||||
|
{
|
||||||
|
QProcess::startDetached(QTOX_PATH);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::update()
|
||||||
|
{
|
||||||
|
/// 1. Find and parse the update (0-5%)
|
||||||
|
// Check that the dir exists
|
||||||
|
QString updateDirStr = getSettingsDirPath()+"/update/";
|
||||||
|
QDir updateDir(updateDirStr);
|
||||||
|
if (!updateDir.exists())
|
||||||
|
fatalError(tr("No update found."));
|
||||||
|
|
||||||
|
// Check that we have a flist and that every file on the diff exists
|
||||||
|
QFile updateFlistFile(updateDirStr+"flist");
|
||||||
|
if (!updateFlistFile.open(QIODevice::ReadOnly))
|
||||||
|
fatalError(tr("The update is incomplete."));
|
||||||
|
QByteArray updateFlistData = updateFlistFile.readAll();
|
||||||
|
updateFlistFile.close();
|
||||||
|
|
||||||
|
setProgress(1);
|
||||||
|
|
||||||
|
QList<UpdateFileMeta> updateFlist = parseFlist(updateFlistData);
|
||||||
|
setProgress(2);
|
||||||
|
QList<UpdateFileMeta> diff = genUpdateDiff(updateFlist);
|
||||||
|
setProgress(4);
|
||||||
|
for (UpdateFileMeta fileMeta : diff)
|
||||||
|
if (!QFile::exists(updateDirStr+fileMeta.installpath))
|
||||||
|
fatalError(tr("The update is incomplete."));
|
||||||
|
setProgress(5);
|
||||||
|
|
||||||
|
/// 2. Check the update (5-50%)
|
||||||
|
float checkProgressStep = 45/diff.size();
|
||||||
|
float checkProgress = 5;
|
||||||
|
for (UpdateFileMeta fileMeta : diff)
|
||||||
|
{
|
||||||
|
UpdateFile file;
|
||||||
|
file.metadata = fileMeta;
|
||||||
|
|
||||||
|
QFile fileFile(updateDirStr+fileMeta.installpath);
|
||||||
|
if (!fileFile.open(QIODevice::ReadOnly))
|
||||||
|
fatalError(tr("Update files are unreadable."));
|
||||||
|
file.data = fileFile.readAll();
|
||||||
|
fileFile.close();
|
||||||
|
|
||||||
|
if (file.data.size() != (int)fileMeta.size)
|
||||||
|
fatalError(tr("Update files are corrupted."));
|
||||||
|
|
||||||
|
if (crypto_sign_verify_detached(file.metadata.sig, (unsigned char*)file.data.data(),
|
||||||
|
file.data.size(), key) != 0)
|
||||||
|
fatalError(tr("Update files are corrupted."));
|
||||||
|
|
||||||
|
checkProgress += checkProgressStep;
|
||||||
|
setProgress(checkProgress);
|
||||||
|
}
|
||||||
|
setProgress(50);
|
||||||
|
|
||||||
|
/// 3. Install the update (50-95%)
|
||||||
|
float installProgressStep = 45/diff.size();
|
||||||
|
float installProgress = 50;
|
||||||
|
for (UpdateFileMeta fileMeta : diff)
|
||||||
|
{
|
||||||
|
QFile fileFile(updateDirStr+fileMeta.installpath);
|
||||||
|
if (!fileFile.copy(fileMeta.installpath))
|
||||||
|
fatalError(tr("Unable to copy the update's files."));
|
||||||
|
|
||||||
|
installProgress += installProgressStep;
|
||||||
|
setProgress(installProgress);
|
||||||
|
}
|
||||||
|
setProgress(95);
|
||||||
|
|
||||||
|
/// 4. Delete the update (95-100%)
|
||||||
|
deleteUpdate();
|
||||||
|
setProgress(100);
|
||||||
|
|
||||||
|
/// 5. Start qTox and exit
|
||||||
|
startQToxAndExit();
|
||||||
|
}
|
51
updater/widget.h
Normal file
51
updater/widget.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
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 COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef WIDGET_H
|
||||||
|
#define WIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class Widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Widget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Widget(QWidget *parent = 0);
|
||||||
|
~Widget();
|
||||||
|
|
||||||
|
// Utilities
|
||||||
|
void setProgress(int value);
|
||||||
|
|
||||||
|
// Noreturn
|
||||||
|
void fatalError(QString message); ///< Calls deleteUpdate and startQToxAndExit
|
||||||
|
void deleteUpdate();
|
||||||
|
void startQToxAndExit();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// Finds and applies the update
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::Widget *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WIDGET_H
|
139
updater/widget.ui
Normal file
139
updater/widget.ui
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Widget</class>
|
||||||
|
<widget class="QWidget" name="Widget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>401</width>
|
||||||
|
<height>224</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>qTox Updater</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/qtox-256x256.png</normaloff>:/res/qtox-256x256.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>13</y>
|
||||||
|
<width>191</width>
|
||||||
|
<height>191</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="res.qrc">:/res/qtox-256x256.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QProgressBar" name="progress">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>206</x>
|
||||||
|
<y>95</y>
|
||||||
|
<width>171</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="invertedAppearance">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>205</x>
|
||||||
|
<y>115</y>
|
||||||
|
<width>171</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Updating qTox ...</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>201</x>
|
||||||
|
<y>170</y>
|
||||||
|
<width>181</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><a href="https://tox.im">https://tox.im</a></string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>200</x>
|
||||||
|
<y>183</y>
|
||||||
|
<width>181</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><a href="https://github.com/tux3/qtox">https://github.com/tux3/qtox</a></string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>195</x>
|
||||||
|
<y>32</y>
|
||||||
|
<width>191</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>qTox Update</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources>
|
||||||
|
<include location="res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
12
updater/windows/updater.exe.manifest
Normal file
12
updater/windows/updater.exe.manifest
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel
|
||||||
|
level="requireAdministrator"
|
||||||
|
uiAccess="false"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
</assembly>
|
BIN
updater/windows/updater.ico
Normal file
BIN
updater/windows/updater.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
2
updater/windows/updater.rc
Normal file
2
updater/windows/updater.rc
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ID_ICON ICON DISCARDABLE "updater.ico"
|
||||||
|
1 24 "updater.exe.manifest"
|
Loading…
Reference in New Issue
Block a user