X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fwin_updater.cpp;h=24a92bb9f94d86540a3bf1444ae161667723f95c;hb=9d2a9fe83669c7e281b2c2aa7ba3b814842d17c2;hp=86ec9b7116ffaee113a6c85e1f4f69eb1d502c1f;hpb=d4d0882a1076e4510042999b39783512311b4091;p=x264-launcher%2Fx264-launcher.git diff --git a/src/win_updater.cpp b/src/win_updater.cpp index 86ec9b7..24a92bb 100644 --- a/src/win_updater.cpp +++ b/src/win_updater.cpp @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// // Simple x264 Launcher -// Copyright (C) 2004-2015 LoRd_MuldeR +// Copyright (C) 2004-2020 LoRd_MuldeR // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -20,13 +20,20 @@ /////////////////////////////////////////////////////////////////////////////// #include "win_updater.h" -#include "uic_win_updater.h" +#include "UIC_win_updater.h" +//Internal #include "global.h" #include "model_sysinfo.h" -#include "thread_updater.h" -#include "checksum.h" +//MUtils +#include +#include +#include +#include +#include + +//Qt #include #include #include @@ -37,15 +44,18 @@ #include #include #include +#include /////////////////////////////////////////////////////////////////////////////// +static const char *const DIGEST_KEY = "~Dv/bW3/7t>6?RXVwkaZk-hmS0#O4JS/5YQAO>\\8hvr0B~7[n!X~KMYruemu:MDq"; + const UpdaterDialog::binary_t UpdaterDialog::BINARIES[] = { - { "wget.exe", "7b522345239bcb95b5b0f7f50a883ba5957894a1feb769763e38ed789a8a0f63fead0155f54b9ffd0f1cdc5dfd855d207a6e7a8e4fd192589a8838ce646c504e", 1 }, - { "gpgv.exe", "97eebd656ad2799cbb69250ea9434b5afc8bcf578097703594277451f4e752166464a077ba71d5960824fa71e52f2a9e94c6368ae70a93d86a10720b3fced2fd", 1 }, - { "gpgv.gpg", "58e0f0e462bbd0b5aa4f638801c1097da7da4b3eb38c8c88ad1db23705c0f11e174b083fa55fe76bd3ba196341c967833a6f3427d6f63ad8565900745535d8fa", 0 }, - { "wupd.exe", "1156dd9aa47df35dfeb68cb9bea26cf5236c1bf4c29c22676b450e827aa8e4419858d2b9a2c9e94747ad43704a145724ec5b0280d16922e52c6c47e324739571", 1 }, + { "curl.exe", "16cf6c857df62440b68ff40d44b3870cf503a18f3b6a3ce611812c7d91c55e40afbc0eaae72f702e9a1a37587455899fe7e1b49b571b8ff887dd90cf309a8b7c", 1 }, + { "gpgv.exe", "d0869bd858294520c992b66e1c7594176ebfb51bd64c4f50f782a4749118498a29c9fc70da5ed08cda9837ff7099d950428ca9f1968fa69883929bd0dba8c9e5", 1 }, + { "gpgv.gpg", "1a2f528e551b9abfb064f08674fdd421d3abe403469ddfee2beafd007775a6c684212a6274dc2b41a0b20dd5c2200021c91320e737f7a90b2ac5a40a6221d93f", 0 }, + { "wupd.exe", "018a8d0d848407fb0cb530b4540c6f025fd4c280885becd37f83feed8aeb3af6f8e8e0d45066a36549efac7e64706ac1ef09aaa5c75ab8d12c4a70f41518a894", 1 }, { NULL, NULL, 0 } }; @@ -62,6 +72,20 @@ const UpdaterDialog::binary_t UpdaterDialog::BINARIES[] = } \ while(0) +static inline QString getBin(const QMap> &binaries, const QString &nameName) +{ + const QSharedPointer file = binaries.value(nameName); + return file.isNull() ? QString() : file->fileName(); +} + +static void qFileDeleter(QFile *const file) +{ + if(file) + { + file->close(); + delete file; + } +} /////////////////////////////////////////////////////////////////////////////// // Constructor & Destructor @@ -73,7 +97,7 @@ UpdaterDialog::UpdaterDialog(QWidget *parent, const SysinfoModel *sysinfo, const ui(new Ui::UpdaterDialog()), m_sysinfo(sysinfo), m_updateUrl(updateUrl), - m_status(UpdateCheckThread::UpdateStatus_NotStartedYet), + m_status(MUtils::UpdateChecker::UpdateStatus_NotStartedYet), m_thread(NULL), m_updaterProcess(NULL), m_success(false), @@ -83,7 +107,8 @@ UpdaterDialog::UpdaterDialog(QWidget *parent, const SysinfoModel *sysinfo, const ui->setupUi(this); setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); - //Fix size + //Scale and fix size + MUtils::GUI::scale_widget(this); setFixedSize(size()); //Enable buttons @@ -95,13 +120,14 @@ UpdaterDialog::UpdaterDialog(QWidget *parent, const SysinfoModel *sysinfo, const connect(ui->labelUrl, SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString))); //Init animation - m_animator = new QMovie(":/images/loading.gif"); - ui->labelLoadingCenter->setMovie(m_animator); + m_animator.reset(new QMovie(":/images/loading.gif")); + ui->labelLoadingCenter->setMovie(m_animator.data()); //Init buttons ui->buttonCancel->setEnabled(false); ui->buttonRetry->hide(); ui->buttonDownload->hide(); + ui->labelCancel->hide(); //Start animation SHOW_ANIMATION(true); @@ -109,35 +135,18 @@ UpdaterDialog::UpdaterDialog(QWidget *parent, const SysinfoModel *sysinfo, const UpdaterDialog::~UpdaterDialog(void) { - if(m_thread) + if(!m_thread.isNull()) { - if(!m_thread->wait(1000)) + if(!m_thread->wait(5000)) { m_thread->terminate(); m_thread->wait(); } } - - if((!m_keysFile.isEmpty()) && QFile::exists(m_keysFile)) - { - QFile::setPermissions(m_keysFile, QFile::ReadOwner | QFile::WriteOwner); - QFile::remove(m_keysFile); - m_keysFile.clear(); - } - - X264_DELETE(m_thread); - X264_DELETE(m_animator); - delete ui; } /////////////////////////////////////////////////////////////////////////////// -// Public Functions -/////////////////////////////////////////////////////////////////////////////// - -/*None yet*/ - -/////////////////////////////////////////////////////////////////////////////// // Events /////////////////////////////////////////////////////////////////////////////// @@ -145,7 +154,7 @@ bool UpdaterDialog::event(QEvent *e) { if((e->type() == QEvent::ActivationChange) && (m_updaterProcess != NULL)) { - x264_bring_process_to_front(m_updaterProcess); + MUtils::GUI::bring_to_front(m_updaterProcess); } return QDialog::event(e); } @@ -169,20 +178,45 @@ void UpdaterDialog::closeEvent(QCloseEvent *e) void UpdaterDialog::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_F11) + switch (event->key()) { - QFile logFile(QString("%1/%2.log").arg(x264_temp_directory(), x264_rand_str())); - if(logFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) + case Qt::Key_Escape: + if ((!m_thread.isNull()) && m_thread->isRunning()) { - logFile.write("\xEF\xBB\xBF"); - for(QStringList::ConstIterator iter = m_logFile.constBegin(); iter != m_logFile.constEnd(); iter++) + if (m_status >= MUtils::UpdateChecker::UpdateStatus_FetchingUpdates) + { + UPDATE_TEXT(2, tr("Cancellation requested...")); + } + else { - logFile.write(iter->toUtf8()); - logFile.write("\r\n"); + UPDATE_TEXT(1, tr("Cancellation requested...")); } - logFile.close(); - QDesktopServices::openUrl(QUrl::fromLocalFile(logFile.fileName())); + m_thread->cancel(); } + break; + case Qt::Key_F11: + { + const QString logFilePath = MUtils::make_temp_file(MUtils::temp_folder(), "txt", true); + if (!logFilePath.isEmpty()) + { + qWarning("Write log to: '%s'", MUTILS_UTF8(logFilePath)); + QFile logFile(logFilePath); + if (logFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + logFile.write("\xEF\xBB\xBF"); + for (QStringList::ConstIterator iter = m_logFile.constBegin(); iter != m_logFile.constEnd(); iter++) + { + logFile.write(iter->toUtf8()); + logFile.write("\r\n"); + } + logFile.close(); + QDesktopServices::openUrl(QUrl::fromLocalFile(logFile.fileName())); + } + } + } + break; + default: + QDialog::keyPressEvent(event); } } @@ -193,8 +227,7 @@ void UpdaterDialog::keyPressEvent(QKeyEvent *event) void UpdaterDialog::initUpdate(void) { //Check binary files - QString wgetBin, gpgvBin; - if(!checkBinaries(wgetBin, gpgvBin)) + if(!checkBinaries()) { ui->buttonCancel->setEnabled(true); const QString message = QString("%1

%3
").arg(tr("At least one file required by the web-update tool is missing or corrupted.
Please re-install this application and then try again!"), QString::fromLatin1(m_updateUrl), QString::fromLatin1(m_updateUrl).replace("-", "−")); @@ -202,11 +235,12 @@ void UpdaterDialog::initUpdate(void) { QDesktopServices::openUrl(QUrl(QString::fromLatin1(m_updateUrl))); } - close(); return; + close(); + return; } //Make sure user does have admin access - if(!x264_user_is_admin()) + if(!MUtils::OS::user_is_admin()) { qWarning("User is not in the \"admin\" group, cannot update!"); QString message; @@ -215,18 +249,19 @@ void UpdaterDialog::initUpdate(void) if(QMessageBox::critical(this, this->windowTitle(), message, tr("Discard"), tr("Ignore")) != 1) { ui->buttonCancel->setEnabled(true); - close(); return; + close(); + return; } } //Create and setup thread if(!m_thread) { - m_thread = new UpdateCheckThread(wgetBin, gpgvBin, m_keysFile, false); - connect(m_thread, SIGNAL(statusChanged(int)), this, SLOT(threadStatusChanged(int))); - connect(m_thread, SIGNAL(finished()), this, SLOT(threadFinished())); - connect(m_thread, SIGNAL(terminated()), this, SLOT(threadFinished())); - connect(m_thread, SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString))); + m_thread.reset(new MUtils::UpdateChecker(getBin(m_binaries, "curl.exe"), getBin(m_binaries, "gpgv.exe"), getBin(m_binaries, "gpgv.gpg"), "Simple x264 Launcher", x264_version_build(), false)); + connect(m_thread.data(), SIGNAL(statusChanged(int)), this, SLOT(threadStatusChanged(int))); + connect(m_thread.data(), SIGNAL(finished()), this, SLOT(threadFinished())); + connect(m_thread.data(), SIGNAL(terminated()), this, SLOT(threadFinished())); + connect(m_thread.data(), SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString))); } //Begin updater run @@ -252,9 +287,10 @@ void UpdaterDialog::checkForUpdates(void) //Hide labels ui->labelInfo->hide(); ui->labelUrl->hide(); + ui->labelCancel->show(); //Update status - threadStatusChanged(UpdateCheckThread::UpdateStatus_NotStartedYet); + threadStatusChanged(MUtils::UpdateChecker::UpdateStatus_NotStartedYet); //Start animation SHOW_ANIMATION(true); @@ -266,64 +302,92 @@ void UpdaterDialog::checkForUpdates(void) //Clear log m_logFile.clear(); + //Init timer + m_elapsed.reset(new QElapsedTimer()); + m_elapsed->start(); + //Start the updater thread - QTimer::singleShot(250, m_thread, SLOT(start())); + QTimer::singleShot(125, m_thread.data(), SLOT(start())); } void UpdaterDialog::threadStatusChanged(int status) { + const int prevStatus = m_status; switch(m_status = status) { - case UpdateCheckThread::UpdateStatus_NotStartedYet: + case MUtils::UpdateChecker::UpdateStatus_NotStartedYet: UPDATE_ICON(1, "clock"); UPDATE_ICON(2, "clock"); UPDATE_ICON(3, "clock"); break; - case UpdateCheckThread::UpdateStatus_CheckingConnection: + case MUtils::UpdateChecker::UpdateStatus_CheckingConnection: UPDATE_ICON(1, "play"); break; - case UpdateCheckThread::UpdateStatus_FetchingUpdates: + case MUtils::UpdateChecker::UpdateStatus_FetchingUpdates: UPDATE_ICON(1, "shield_green"); UPDATE_TEXT(1, tr("Internet connection is working.")); UPDATE_ICON(2, "play"); break; - case UpdateCheckThread::UpdateStatus_ErrorNoConnection: + case MUtils::UpdateChecker::UpdateStatus_ErrorNoConnection: UPDATE_ICON(1, "shield_error"); UPDATE_TEXT(1, tr("Computer is currently offline!")); UPDATE_ICON(2, "shield_grey"); UPDATE_ICON(3, "shield_grey"); break; - case UpdateCheckThread::UpdateStatus_ErrorConnectionTestFailed: + case MUtils::UpdateChecker::UpdateStatus_ErrorConnectionTestFailed: UPDATE_ICON(1, "shield_error"); UPDATE_TEXT(1, tr("Internet connectivity test failed!")); UPDATE_ICON(2, "shield_grey"); UPDATE_ICON(3, "shield_grey"); break; - case UpdateCheckThread::UpdateStatus_ErrorFetchUpdateInfo: + case MUtils::UpdateChecker::UpdateStatus_ErrorFetchUpdateInfo: UPDATE_ICON(2, "shield_error"); UPDATE_TEXT(2, tr("Failed to download the update information!")); UPDATE_ICON(3, "shield_grey"); break; - case UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable: - case UpdateCheckThread::UpdateStatus_CompletedNoUpdates: - case UpdateCheckThread::UpdateStatus_CompletedNewVersionOlder: + case MUtils::UpdateChecker::UpdateStatus_CompletedUpdateAvailable: + case MUtils::UpdateChecker::UpdateStatus_CompletedNoUpdates: + case MUtils::UpdateChecker::UpdateStatus_CompletedNewVersionOlder: UPDATE_ICON(2, "shield_green"); UPDATE_TEXT(2, tr("Update information received successfully.")); UPDATE_ICON(3, "play"); break; + case MUtils::UpdateChecker::UpdateStatus_CancelledByUser: + if (prevStatus >= MUtils::UpdateChecker::UpdateStatus_FetchingUpdates) + { + UPDATE_ICON(2, "shield_error"); + UPDATE_TEXT(2, tr("Operation was cancelled by the user!")); + UPDATE_ICON(3, "shield_grey"); + } + else + { + UPDATE_ICON(1, "shield_error"); + UPDATE_TEXT(1, tr("Operation was cancelled by the user!")); + UPDATE_ICON(2, "shield_grey"); + UPDATE_ICON(3, "shield_grey"); + } + break; default: - THROW("Unknown status code!"); + MUTILS_THROW("Unknown status code!"); } } void UpdaterDialog::threadFinished(void) { m_success = m_thread->getSuccess(); - QTimer::singleShot((m_success ? 1000 : 0), this, SLOT(updateFinished())); + ui->labelCancel->hide(); + QTimer::singleShot((m_success ? 500 : 0), this, SLOT(updateFinished())); } void UpdaterDialog::updateFinished(void) { + //Query the timer, if available + if (!m_elapsed.isNull()) + { + const quint64 elapsed = m_elapsed->restart(); + qDebug("Update check completed after %.2f seconds.", double(elapsed) / 1000.0); + } + //Restore cursor QApplication::restoreOverrideCursor(); @@ -332,16 +396,16 @@ void UpdaterDialog::updateFinished(void) { switch(m_status) { - case UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable: + case MUtils::UpdateChecker::UpdateStatus_CompletedUpdateAvailable: UPDATE_ICON(3, "shield_exclamation"); UPDATE_TEXT(3, tr("A newer version is available!")); ui->buttonDownload->show(); break; - case UpdateCheckThread::UpdateStatus_CompletedNoUpdates: + case MUtils::UpdateChecker::UpdateStatus_CompletedNoUpdates: UPDATE_ICON(3, "shield_green"); UPDATE_TEXT(3, tr("Your version is up-to-date.")); break; - case UpdateCheckThread::UpdateStatus_CompletedNewVersionOlder: + case MUtils::UpdateChecker::UpdateStatus_CompletedNewVersionOlder: UPDATE_ICON(3, "shield_blue"); UPDATE_TEXT(3, tr("You are using a pre-release version!")); break; @@ -353,16 +417,17 @@ void UpdaterDialog::updateFinished(void) //Show update info or retry button switch(m_status) { - case UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable: - case UpdateCheckThread::UpdateStatus_CompletedNoUpdates: - case UpdateCheckThread::UpdateStatus_CompletedNewVersionOlder: + case MUtils::UpdateChecker::UpdateStatus_CompletedUpdateAvailable: + case MUtils::UpdateChecker::UpdateStatus_CompletedNoUpdates: + case MUtils::UpdateChecker::UpdateStatus_CompletedNewVersionOlder: SHOW_ANIMATION(false); - ui->labelBuildNo->setText(tr("Installed build is #%1 | Latest build is #%2").arg(QString::number(x264_version_build()), QString::number(m_thread->getUpdateInfo()->m_buildNo))); - ui->labelUrl->setText(QString("%1").arg(m_thread->getUpdateInfo()->m_downloadSite)); + ui->labelBuildNo->setText(tr("Installed build is #%1 | Latest build is #%2").arg(QString::number(x264_version_build()), QString::number(m_thread->getUpdateInfo()->getBuildNo()))); + ui->labelUrl->setText(QString("%1").arg(m_thread->getUpdateInfo()->getDownloadSite())); break; - case UpdateCheckThread::UpdateStatus_ErrorNoConnection: - case UpdateCheckThread::UpdateStatus_ErrorConnectionTestFailed: - case UpdateCheckThread::UpdateStatus_ErrorFetchUpdateInfo: + case MUtils::UpdateChecker::UpdateStatus_ErrorNoConnection: + case MUtils::UpdateChecker::UpdateStatus_ErrorConnectionTestFailed: + case MUtils::UpdateChecker::UpdateStatus_ErrorFetchUpdateInfo: + case MUtils::UpdateChecker::UpdateStatus_CancelledByUser: m_animator->stop(); ui->buttonRetry->show(); break; @@ -399,25 +464,26 @@ void UpdaterDialog::installUpdate(void) ui->buttonCancel->setEnabled(false); SHOW_ANIMATION(true); - const UpdateInfo *updateInfo = m_thread->getUpdateInfo(); + const MUtils::UpdateCheckerInfo *updateInfo = m_thread->getUpdateInfo(); QProcess process; QStringList args; QEventLoop loop; - x264_init_process(process, x264_temp_directory(), false); + MUtils::init_process(process, MUtils::temp_folder(), false); connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit())); connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit())); - args << QString("/Location=%1").arg(updateInfo->m_downloadAddress); - args << QString("/Filename=%1").arg(updateInfo->m_downloadFilename); - args << QString("/TicketID=%1").arg(updateInfo->m_downloadFilecode); - args << QString("/ToFolder=%1").arg(QDir::toNativeSeparators(QDir(QApplication::applicationDirPath()).canonicalPath())); + args << QString("/Location=%1").arg(updateInfo->getDownloadAddress()); + args << QString("/Filename=%1").arg(updateInfo->getDownloadFilename()); + args << QString("/TicketID=%1").arg(updateInfo->getDownloadFilecode()); + args << QString("/CheckSum=%1").arg(updateInfo->getDownloadChecksum()); + args << QString("/ToFolder=%1").arg(QDir::toNativeSeparators(QDir(QApplication::applicationDirPath()).canonicalPath())); args << QString("/ToExFile=%1.exe").arg(QFileInfo(QFileInfo(QApplication::applicationFilePath()).canonicalFilePath()).completeBaseName()); - args << QString("/AppTitle=Simple x264 Launcher (Build #%1)").arg(QString::number(updateInfo->m_buildNo)); + args << QString("/AppTitle=Simple x264 Launcher (Build #%1)").arg(QString::number(updateInfo->getBuildNo())); - process.start(m_wupdFile, args); + process.start(getBin(m_binaries, "wupd.exe"), args); if(!process.waitForStarted()) { QApplication::restoreOverrideCursor(); @@ -428,7 +494,7 @@ void UpdaterDialog::installUpdate(void) return; } - m_updaterProcess = x264_process_id(process); + m_updaterProcess = MUtils::OS::process_id(&process); loop.exec(QEventLoop::ExcludeUserInputEvents); if(!process.waitForFinished()) @@ -453,55 +519,49 @@ void UpdaterDialog::installUpdate(void) // Private Functions /////////////////////////////////////////////////////////////////////////////// -bool UpdaterDialog::checkBinaries(QString &wgetBin, QString &gpgvBin) +bool UpdaterDialog::checkBinaries(void) { qDebug("[File Verification]"); - QMap binaries; - - m_keysFile.clear(); - m_wupdFile.clear(); - wgetBin.clear(); - gpgvBin.clear(); - - bool okay = true; - for(size_t i = 0; BINARIES[i].name; i++) { - const QString binPath = QString("%1/toolset/common/%2").arg(m_sysinfo->getAppPath(), QString::fromLatin1(BINARIES[i].name)); - if(okay = okay && checkFileHash(binPath, BINARIES[i].hash)) + const QString name = QString::fromLatin1(BINARIES[i].name); + if (!m_binaries.contains(name)) { - binaries.insert(BINARIES[i].name, binPath); - } - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - } - - if(okay) - { - wgetBin = binaries.value("wget.exe"); - gpgvBin = binaries.value("gpgv.exe"); - - m_wupdFile = binaries.value("wupd.exe"); - m_keysFile = QString("%1/%2.gpg").arg(x264_temp_directory(), x264_rand_str()); - - if(okay = QFile::copy(binaries.value("gpgv.gpg"), m_keysFile)) - { - QFile::setPermissions(m_keysFile, QFile::ReadOwner); + QScopedPointer binary(new QFile(QString("%1/toolset/common/%2").arg(m_sysinfo->getAppPath(), name))); + if (binary->open(QIODevice::ReadOnly)) + { + if (checkFileHash(binary->fileName(), BINARIES[i].hash)) + { + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + m_binaries.insert(name, QSharedPointer(binary.take(), qFileDeleter)); + } + else + { + qWarning("Verification of '%s' has failed!", MUTILS_UTF8(name)); + binary->close(); + return false; + } + } + else + { + qWarning("File '%s' could not be opened!", MUTILS_UTF8(name)); + return false; + } } - qDebug("%s\n", okay ? "Completed." : "Failed to copy GPG file!"); } - - return okay; + qDebug("File check completed.\n"); + return true; } bool UpdaterDialog::checkFileHash(const QString &filePath, const char *expectedHash) { - qDebug("Checking file: %s", filePath.toUtf8().constData()); - QBlake2Checksum checksum2; + qDebug("Checking file: %s", MUTILS_UTF8(filePath)); + QScopedPointer checksum(MUtils::Hash::create(MUtils::Hash::HASH_BLAKE2_512, DIGEST_KEY)); QFile file(filePath); if(file.open(QIODevice::ReadOnly)) { - checksum2.update(file); - const QByteArray fileHash = checksum2.finalize(); + checksum->update(file); + const QByteArray fileHash = checksum->digest(); if((strlen(expectedHash) != fileHash.size()) || (memcmp(fileHash.constData(), expectedHash, fileHash.size()) != 0)) { qWarning("\nFile appears to be corrupted:\n%s\n", filePath.toUtf8().constData());