changeset 551:15121735805e

Start implementation of software update installation
author Andre Heinecke <aheinecke@intevation.de>
date Tue, 20 May 2014 16:40:28 +0000
parents 0ec3516bf65c
children fc61ef6612b0
files ui/mainwindow.cpp ui/mainwindow.h
diffstat 2 files changed, 98 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/ui/mainwindow.cpp	Tue May 20 16:39:51 2014 +0000
+++ b/ui/mainwindow.cpp	Tue May 20 16:40:28 2014 +0000
@@ -8,6 +8,7 @@
 #include "mainwindow.h"
 
 #include <QDebug>
+#include <QProcess>
 #include <QProgressDialog>
 #include <QMessageBox>
 #include <QSystemTrayIcon>
@@ -35,7 +36,7 @@
 
 #define SERVER_URL "https://files.intevation.de:443"
 #define LIST_RESOURCE "/users/aheinecke/zertifikatsliste.txt"
-#define SW_RESOURCE   "/users/aheinecke/zertifikatsliste.txt"
+#define SW_RESOURCE   "/users/aheinecke/trustbridge.exe"
 #ifdef Q_OS_WIN
 #define SW_RESOURCE_VERSION "/users/aheinecke/trustbridge-%1.exe"
 #else
@@ -50,6 +51,7 @@
 #include "separatoritemdelegate.h"
 #include "installwrapper.h"
 #include "util.h"
+#include "logging.h"
 
 MainWindow::MainWindow(bool trayMode):
     mTrayMode(trayMode)
@@ -97,6 +99,11 @@
     if (mCurState == NewListAvailable) {
         show();
     }
+
+    if (mCurState == NewSoftwareAvailable) {
+        checkUpdates(true);
+        mCurState = DownloadingSW;
+    }
 }
 
 void MainWindow::showMessage()
@@ -148,7 +155,7 @@
     }
 
     if (!swFileName.isEmpty()) {
-        // TODO
+        // TODO Verify integrity of the software
     } else {
         mSettings.remove("Software/available");
         mSettings.remove("Software/availableDate");
@@ -176,7 +183,8 @@
 }
 
 void MainWindow::handleNewSW(const QString& fileName, const QDateTime& modDate) {
-    mCurMessage = tr("An update for %1 is available. Click here to install.").arg(
+    mCurMessage = tr("<h3>An update for %1 is available.</h3>\n"
+            "Click here to download and install the update.").arg(
                 QApplication::applicationName());
     setState(NewSoftwareAvailable);
     mSettings.setValue("Software/available", fileName);
@@ -186,12 +194,61 @@
     showMessage();
 }
 
+void MainWindow::installNewSW(const QString& fileName, const QDateTime& modDate) {
+    QFileInfo instProcInfo = QFileInfo(fileName);
+    if (!instProcInfo.isExecutable()) {
+        qWarning() << "Downloaded file: " << fileName << " is not executable.";
+        setState(TransferError);
+        return;
+    }
+#ifdef WIN32
+    SHELLEXECUTEINFOW shExecInfo;
+    shExecInfo.lpFile = reinterpret_cast<LPCWSTR> (fileName.utf16());
+
+    if (!is_admin()) {
+        shExecInfo.lpVerb = L"open";
+    } else {
+        shExecInfo.lpVerb = L"runas";
+    }
+
+    qDebug() << "Starting process " << fileName;
+
+    if (!ShellExecuteExW(&shExecInfo)) {
+        /* Execution failed, maybe the user aborted the UAC check? */
+        char* errmsg = getLastErrorMsg();
+        QString qerrmsg = QString::fromUtf8(errmsg);
+        free(errmsg);
+        qDebug() << "Failed to start process: " << qerrmsg;
+        setState(NewSoftwareAvailable);
+        return;
+    }
+
+#else /* WIN32 */
+    QProcess installerProcess;
+    installerProcess.setProgram(fileName);
+
+    qDebug() << "Starting process " << fileName;
+
+    if (!installerProcess.waitForStarted() ||
+        installerProcess.state() == QProcess::NotRunning) {
+        qDebug() << "Failed to start process.";
+        return;
+    }
+#endif
+    /* Installer process should now be running. We exit */
+
+    closeApp();
+}
+
 void MainWindow::checkUpdates(bool downloadSW)
 {
     verifyAvailableData();
 
-    if (!mSettings.contains("Software/installedDate")) {
-        lookUpDateForVersion();
+    if (!mSettings.contains("Software/installedDate") ||
+          mSettings.value("Software/installedVersion").toString() != QApplication::applicationVersion()) {
+        /* This should only happen on initial startup and after an update has
+         * been installed */
+        getLastModForCurrentVersion();
         return;
     }
     QDateTime listInstalledLastMod = mSettings.value("List/installedDate").toDateTime();
@@ -210,8 +267,7 @@
     Downloader* downloader = new Downloader(this,
                                             QString::fromLatin1(SERVER_URL),
                                             QByteArray(),
-                                            QDateTime::currentDateTime(),
-// TODO                                       swInstalledLastMod,
+                                            swInstalledLastMod,
                                             listInstalledLastMod,
                                             swResource,
                                             listResource,
@@ -221,19 +277,19 @@
             this, SLOT(handleNewList(const QString&, const QDateTime&)));
     if (!downloadSW) {
         connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)),
-                this, SLOT(newSWAvailable(const QString&, const QDateTime&)));
+                this, SLOT(handleNewSW(const QString&, const QDateTime&)));
+    } else {
+        connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)),
+                this, SLOT(installNewSW(const QString&, const QDateTime&)));
     }
-    else {
-        connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)),
-                this, SLOT(handleNewSW(const QString&, const QDateTime&)));
-    }
+
     connect(downloader, SIGNAL(finished()), downloader, SLOT(deleteLater()));
     connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)),
             this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode)));
     downloader->start();
 }
 
-void MainWindow::lookUpDateForVersion()
+void MainWindow::getLastModForCurrentVersion()
 {
     QString softwareVersion = QString::fromLatin1(SW_RESOURCE_VERSION).arg(
         QApplication::applicationVersion());
@@ -251,39 +307,28 @@
     connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)),
             this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode)));
     connect(downloader, SIGNAL(lastModifiedDate(const QDateTime&)),
-        this, SLOT(setLastModifiedDate(const QDateTime&)));
+        this, SLOT(setLastModifiedSWDate(const QDateTime&)));
 
     downloader->start();
 }
 
-void MainWindow::setLastModifiedDate(const QDateTime &date)
+void MainWindow::setLastModifiedSWDate(const QDateTime &date)
 {
     mSettings.beginGroup("Software");
     mSettings.setValue("installedDate", date);
+    mSettings.setValue("installedVersion", QApplication::applicationVersion());
     mSettings.endGroup();
     checkUpdates();
 }
 
-void MainWindow::newSWAvailable(const QString &fileName, const QDateTime &date) {
-    QMessageBox msgBox;
-    msgBox.setIcon(QMessageBox::Information);
-    msgBox.setText("<h3>" + tr("New Software version is available.") + "</h3>");
-    msgBox.setInformativeText(tr("Do you want to install the new Version?"));
-    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
-    msgBox.setDefaultButton(QMessageBox::Yes);
-    int selection = msgBox.exec();
-    if (selection == QMessageBox::Yes) {
-        checkUpdates(true);
-    }
-}
-
 void MainWindow::downloaderError(const QString &message, SSLConnection::ErrorCode error)
 {
+    /* TODO logging and handle error according to a plan */
     mCurMessage = message;
     showMessage();
+    setState(TransferError);
 }
 
-
 void MainWindow::createActions()
 {
     mCheckUpdates = new QAction(tr("Check for Updates"), this);
--- a/ui/mainwindow.h	Tue May 20 16:39:51 2014 +0000
+++ b/ui/mainwindow.h	Tue May 20 16:40:28 2014 +0000
@@ -54,6 +54,7 @@
         BeforeDownload,
         NewListAvailable,
         NewSoftwareAvailable,
+        DownloadingSW,
         TransferError,
         NothingChanged
     };
@@ -76,13 +77,33 @@
     void installerError(const QString& errMsg);
     void installerSuccess();
     void installCerts();
-    void newSWAvailable(const QString& fileName, const QDateTime& modDate);
+
+    /* @brief Execute the file fileName to install the softwareupdate.
+     *
+     * Once the installer process is started this function terminates
+     * the application. */
+    void installNewSW(const QString& fileName, const QDateTime& modDate);
 
     void saveAutoUpdate(int state);
     void saveAutoStart(int state);
 
-    void lookUpDateForVersion();
-    void setLastModifiedDate(const QDateTime &date);
+    /** @brief get the last modified date on the download server for
+     * the current version.
+     *
+     * After the initial installation this function can be used to
+     * determine the DateTime that corresponds to the currently installed
+     * version on the download server.
+     *
+     * Calls setLastModifiedSWDate on success. Otherwise downloaderError
+     * is triggered. */
+    void getLastModForCurrentVersion();
+
+    /** @brief set the last modified software date/time
+     *
+     * The last modifiedSWDate is the corresponding last modified
+     * timestamp from the download server vor the currently installed version.
+     */
+    void setLastModifiedSWDate(const QDateTime &date);
 
     /** @brief saves the currently unselected certificates
      *

http://wald.intevation.org/projects/trustbridge/