changeset 1227:a1e990947172

(issue38) Add long time error handling. A Long Time Error is an error that will be shown to the user if it happened at least seven times with an interval of at least a day between occurances. After one success a long time error will be reset.
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 24 Sep 2014 15:12:40 +0200
parents e401680b0cbd
children 206eb5006c56
files ui/downloader.cpp ui/mainwindow.cpp ui/mainwindow.h
diffstat 3 files changed, 157 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/ui/downloader.cpp	Wed Sep 24 15:05:53 2014 +0200
+++ b/ui/downloader.cpp	Wed Sep 24 15:12:40 2014 +0200
@@ -157,7 +157,9 @@
 
         if (mDownloadSW) {
             if (!mSSLConnection->downloadFile(mResourceSW, fileName, MAX_SW_SIZE)) {
-                emit error(tr("Failed to download File"), SSLConnection::ConnectionLost);
+                emit error(tr("Failed to download File.") + "\n"
+                        + tr("The connection to the update server was lost or"
+                            " the disk is full."), SSLConnection::ConnectionLost);
                 qDebug() << "Failed to download software update.";
                 return;
             }
--- a/ui/mainwindow.cpp	Wed Sep 24 15:05:53 2014 +0200
+++ b/ui/mainwindow.cpp	Wed Sep 24 15:12:40 2014 +0200
@@ -196,13 +196,13 @@
     if (!availableFileName.isEmpty()) {
         mListToInstall.readList(availableFileName.toUtf8().constData());
         if (!mListToInstall.isValid()) {
+            handleLTE(lteInvalidList);
             mCurState = TransferError;
-            // Probably a bug when Qt fileName is encoded and cFileName
-            // fails because of this. This needs a unit test!
-            // Maybe check that the file is in our data directory
             QFile::remove(availableFileName);
             mSettings.remove("List/available");
             mSettings.remove("List/availableDate");
+        } else {
+            handleLTE(lteInvalidList, true);
         }
     } else {
         // Make sure the available notation is also removed
@@ -254,12 +254,14 @@
             swFileName.toUtf8().size());
     qDebug() << "Binary verify result: " << verifyResult.result;
     if (verifyResult.result != VerifyValid) {
+        handleLTE(lteInvalidSoftware);
         qDebug() << "Failed to verify downloaded data.";
         QFile::remove(swFileName);
         mSettings.remove("Software/available");
         mSettings.remove("Software/availableDate");
         return;
     }
+    handleLTE(lteInvalidSoftware, true); /* Reset error state */
     fclose(verifyResult.fptr);
 }
 
@@ -270,9 +272,8 @@
 
     verifyListData();
     if (!mListToInstall.isValid()) {
+        handleLTE(lteInvalidList);
         /* Downloader provided invalid files */
-        /* TODO (issue38): Error count. Error handling. Otherwise
-         * we can go into an endless loop here */
 
         /* Retry the download again in 10 - 20 minutes */
         QTimer::singleShot(600000 + (qrand() % 60000), this, SLOT(checkUpdates()));
@@ -306,10 +307,14 @@
     showMessage();
 }
 
-QString getPrettyInstallerName(QString realFileName) {
+QString MainWindow::getPrettyInstallerName(QString realFileName) {
     QTemporaryDir tDir;
     if (!tDir.isValid()) {
         qDebug () << "Failed to create temporary directory.";
+        showErrorMessage (tr("Failed to create temporary directory.") + "\n" +
+                tr("Please ensure that you have the access rights to write in "
+                   "the temporary directory and that there is at least 20MB free "
+                   "disk space available."));
         return QString();
     }
     QString targetPath = tDir.path() + "/" + QObject::tr("TrustBridge-Updater",
@@ -320,6 +325,10 @@
     targetPath += ".exe";
 #endif
     if (!QFile::copy(realFileName, targetPath)) {
+        showErrorMessage (tr("Failed to create a temporary copy of the installer.") + "\n" +
+                tr("Please ensure that you have the access rights to write in "
+                   "the temporary directory and that there is at least 20MB free "
+                   "disk space available."));
         qDebug() << "Failed to create temporary copy of installer.";
     }
     return targetPath;
@@ -334,8 +343,6 @@
 
     if (filePath.isEmpty()) {
         qDebug() << "Failed to copy updater to temporary location.";
-        showErrorMessage(tr("Failed to create update process.") + "\n" +
-                tr("This could be caused by not enough disk space or invalid permissions."));
         return;
     }
     mSettings.setValue("Software/Updater", filePath); /* So it can be deleted
@@ -346,9 +353,11 @@
             filePath.toUtf8().size());
 
     if (vres.result != VerifyValid) {
+        handleLTE(lteInvalidSoftware);
         qDebug() << "Invalid software. Not installing";
         return;
-      }
+    }
+    handleLTE(lteInvalidSoftware, true);
     QFileInfo fi(QCoreApplication::applicationFilePath());
     QDir installDir = fi.absoluteDir();
 
@@ -571,8 +580,12 @@
 
 void MainWindow::downloaderError(const QString &message, SSLConnection::ErrorCode error)
 {
-    /* TODO (issue38) handle error according to a plan */
     syslog_error_printf ("Failed to check for updates: %s", message.toUtf8().constData());
+    if (error == SSLConnection::InvalidCertificate) {
+        handleLTE(lteInvalidCertificate);
+    } else {
+        handleLTE(lteNoConnection);
+    }
 #ifdef IS_TAG_BUILD
     /* During tag build it should never happen that an url checked is not available
      * during development this is normal as each revision produces a new url. */
@@ -1647,6 +1660,8 @@
         mLastUpdateCheckContents->show();
         mLastUpdateCheck->show();
         syslog_info_printf(tr("Sucessfully checked for updates.").toUtf8().constData());
+        handleLTE(lteNoConnection, true); /* Reset error state */
+        handleLTE(lteInvalidCertificate, true);
     }
     if ((getState() != NewSoftwareAvailable && getState() != NewListAvailable && mTrayMode)
             && !isVisible()) {
@@ -1704,3 +1719,90 @@
 {
     QMessageBox::warning(this, tr("TrustBridge error"), msg);
 }
+
+void MainWindow::handleLTE(LongTimeErrors lte, bool reset)
+{
+    QString settingPrefix;
+    switch (lte) {
+        case lteInvalidSoftware:
+            settingPrefix = "LTE/invalidSW";
+            break;
+        case lteInvalidList:
+            settingPrefix = "LTE/invalidList";
+            break;
+        case lteInvalidCertificate:
+            settingPrefix = "LTE/invalidCertificate";
+            break;
+        case lteNoConnection:
+            settingPrefix = "LTE/noConnection";
+            break;
+        default:
+            qDebug() << "Unhandled error. " << lte;
+    }
+
+    if (reset) {
+        /* delete all values and be done */
+        mSettings.remove(settingPrefix + "_lastSaved");
+        mSettings.remove(settingPrefix + "_count");
+        mSettings.remove(settingPrefix + "_lastMsgShown");
+        return;
+    }
+
+    QDateTime lastSaved = mSettings.value(settingPrefix + "_lastSaved").toDateTime();
+    bool cnt_valid;
+    int cnt = mSettings.value(settingPrefix + "_count").toInt(&cnt_valid);
+    if (!cnt_valid) {
+        cnt = 0;
+    }
+
+    if (!lastSaved.isValid() || lastSaved.daysTo(QDateTime::currentDateTime()) >= 1) {
+        /* The error count is increased at most once a day */
+        mSettings.setValue(settingPrefix + "_lastSaved", QDateTime::currentDateTime());
+        mSettings.setValue(settingPrefix + "_count", ++cnt);
+    }
+
+
+    if (cnt < 7) {
+        /* We are done */
+        return;
+    }
+    /* A week has passed. Start showing the error. */
+    QDateTime lastShown = mSettings.value(settingPrefix + "_lastShown").toDateTime();
+    if (lastShown.isValid() && lastShown.daysTo(QDateTime::currentDateTime()) < 1) {
+        /* Only show the error message once a day */
+        return;
+    }
+
+    mSettings.setValue(settingPrefix + "_lastShown", QDateTime::currentDateTime());
+
+    switch (lte) {
+        case lteInvalidSoftware:
+            showErrorMessage(tr("The integrity check for the available software update has "
+                        "failed repeatedly.") + "\n" +
+                        tr("Please contact your Support or the publisher of the Software."));
+            break;
+        case lteInvalidList:
+            showErrorMessage(tr("The integrity check of the available certificates has "
+                        "failed repeatedly.") + "\n" +
+                        tr("Please contact your Support or the publisher of the Software."));
+            break;
+        case lteInvalidCertificate:
+            showErrorMessage(tr("The authentication of the download server has "
+                        "failed repeatedly.") + "\n" +
+                        tr("Please contact your Support or the publisher of the Software."));
+            break;
+        case lteNoConnection:
+            bool useProxy = mSettings.value("UseProxy", false).toBool();
+            if (useProxy) {
+                showErrorMessage(tr("The connection to the download server has "
+                            "failed repeatedly.") + "\n" +
+                            tr("Please check that the Proxy Server \"%1\" is available.").arg(
+                                mSettings.value("ProxyURL").toString()));
+            } else {
+                showErrorMessage(tr("The connection to the download server has "
+                            "failed repeatedly.") + "\n" +
+                            tr("Please check your internet connection."));
+            }
+            break;
+    }
+}
--- a/ui/mainwindow.h	Wed Sep 24 15:05:53 2014 +0200
+++ b/ui/mainwindow.h	Wed Sep 24 15:12:40 2014 +0200
@@ -61,6 +61,19 @@
         TransferError,
         NothingChanged
     };
+
+    /**
+     * @enum LongTimeErrors
+     * @brief Errors that should be stored and only shown after some time has elapsed.
+     */
+    enum LongTimeErrors {
+        lteInvalidSoftware, /*! The downloaded Software was invalid. */
+        lteInvalidCertificate, /*! The SSL certificate of the download server was wrong. */
+        lteInvalidList, /*! The downloaded Certificate List was invalid. */
+        lteNoConnection
+    };
+
+    /** @brief accessor for the current state. */
     CurrentState getState() {return mCurState;}
     void setState(CurrentState state) {mCurState = state;}
 
@@ -181,6 +194,18 @@
     void changesChanged(const QString& cnt);
 
 private:
+    /** @brief Get a installer file name that can be shown to a user.
+     *
+     * This copys the real file to a temporary location with a user
+     * visible localized file name. Does error Handling.
+     *
+     * @param [in] realFileName The original file name.
+     *
+     * @returns a null string in case on errors. The new filename
+     * otherwise.
+     */
+    QString getPrettyInstallerName(QString realFileName);
+
     /** @brief the combined number of changes made in all lists */
     int changeCount();
 
@@ -206,6 +231,23 @@
      */
     void verifySWData();
 
+    /** @brief note an long time error in the settings and show a message.
+     *
+     * Saves a software verify error in the settings and notifies the
+     * user if necessary.
+     *
+     * @param [in] lte The error to handle.
+     * @param [in] reset weather or not the error count should be reset.
+     *
+     **/
+    void handleLTE(LongTimeErrors lte, bool reset = false);
+
+    /** @brief note a verify error in the settings and show a message
+     *
+     * Saves a software verify error in the settings and notifies the
+     * user if necessary.*/
+    void swVerifyError();
+
     void createTrayIcon();
     void createActions();
     void loadCertificateList();

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