aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
aheinecke@404:  * Software engineering by Intevation GmbH
aheinecke@404:  *
aheinecke@404:  * This file is Free Software under the GNU GPL (v>=2)
aheinecke@404:  * and comes with ABSOLUTELY NO WARRANTY!
aheinecke@404:  * See LICENSE.txt for details.
aheinecke@404:  */
aheinecke@0: #include "mainwindow.h"
aheinecke@0: 
aheinecke@0: #include <QDebug>
aheinecke@551: #include <QProcess>
aheinecke@365: #include <QProgressDialog>
aheinecke@0: #include <QMessageBox>
aheinecke@0: #include <QAction>
aheinecke@0: #include <QDialog>
aheinecke@563: #include <QDir>
aheinecke@0: #include <QMenu>
aheinecke@2: #include <QApplication>
aheinecke@16: #include <QFile>
andre@1116: #include <QTemporaryDir>
aheinecke@19: #include <QTimer>
rrenkert@187: #include <QHBoxLayout>
rrenkert@187: #include <QVBoxLayout>
emanuel@709: #include <QGridLayout>
rrenkert@187: #include <QGroupBox>
rrenkert@189: #include <QSplitter>
rrenkert@205: #include <QLabel>
rrenkert@205: #include <QImage>
rrenkert@250: #include <QCheckBox>
rrenkert@584: #include <QButtonGroup>
rrenkert@584: #include <QToolButton>
andre@857: #include <QStandardPaths>
andre@940: #include <QDesktopServices>
aheinecke@19: 
andre@609: #include "certificatelist.h"
andre@1234: #include "certificateitemwidget.h"
andre@609: #include "downloader.h"
andre@609: #include "helpdialog.h"
andre@609: #include "aboutdialog.h"
andre@609: #include "separatoritemdelegate.h"
andre@609: #include "installwrapper.h"
andre@609: #include "util.h"
andre@609: #include "logging.h"
andre@609: #include "binverify.h"
andre@609: #include "processhelp.h"
andre@609: #include "processwaitdialog.h"
andre@871: #include "trayicon.h"
andre@956: #include "proxysettingsdlg.h"
andre@609: 
aheinecke@19: // The amount of time in minutes stay silent if we have
aheinecke@19: // something to say
aheinecke@548: #define NAG_INTERVAL_MINUTES 70
aheinecke@0: 
emanuel@1104: #define DATETIME_FORMAT "d. MMM yyyy HH:mm"
andre@714: 
aheinecke@409: #ifndef APPNAME
aheinecke@409: #define APPNAME "TrustBridge"
aheinecke@409: #endif
aheinecke@409: 
andre@994: #ifndef SERVER_URL
andre@994: #error "DOWNLOAD_SERVER option not set or invalid."
andre@994: #endif
aheinecke@72: 
andre@885: #if defined(_X86_) || defined(__i386__)
andre@885: #define TB_ARCH_STRING "-i386"
andre@885: #else
andre@885: #define TB_ARCH_STRING "-amd64"
andre@885: #endif
andre@885: 
andre@1127: #ifdef IS_TAG_BUILD
andre@1088: # define LIST_RESOURCE "/zertifikatsliste.txt"
andre@607: # ifdef Q_OS_WIN
andre@1088: #  define SW_RESOURCE_VERSION "/TrustBridge-%1.exe"
andre@1088: #  define SW_RESOURCE "/TrustBridge.exe"
andre@607: # else
andre@1088: #  define SW_RESOURCE_VERSION "/TrustBridge-%1" TB_ARCH_STRING ".sh"
andre@1088: #  define SW_RESOURCE "/TrustBridge" TB_ARCH_STRING ".sh"
andre@607: # endif
andre@1127: #else // Not tag build means develpment build
andre@1088: # define LIST_RESOURCE "/zertifikatsliste.txt"
andre@607: # ifdef Q_OS_WIN
andre@1127: #  define SW_RESOURCE_VERSION "/development/TrustBridge-%1.exe"
andre@1088: #  define SW_RESOURCE "/development/TrustBridge.exe"
andre@607: # else
andre@1127: #  define SW_RESOURCE_VERSION "/development/TrustBridge-%1" TB_ARCH_STRING ".sh"
andre@1088: #  define SW_RESOURCE "/development/TrustBridge" TB_ARCH_STRING ".sh"
andre@607: # endif
rrenkert@486: #endif
aheinecke@7: 
andre@940: /* Help installation path the path relative to the installation directory where
andre@940:  * the help is placed.*/
andre@940: #ifdef WIN32
andre@940: #define HELP_PATH "/doc/index.html"
andre@940: #else
andre@940: #define HELP_PATH "/../share/doc/trustbridge/index.html"
andre@940: #endif
andre@940: 
andre@1109: static void activateDetailsButton(QPushButton *);
andre@1109: static void deactivateDetailsButton(QPushButton *);
andre@1109: 
aheinecke@365: MainWindow::MainWindow(bool trayMode):
andre@1109:     mTrayMode(trayMode),
andre@1109:     mManualDetailsShown(false)
aheinecke@365: {
aheinecke@0:     createActions();
aheinecke@0:     createTrayIcon();
andre@739:     setupGUI();
andre@790:     resize(900, 600);
emanuel@709:     setMinimumWidth(760);
aheinecke@45:     qRegisterMetaType<SSLConnection::ErrorCode>("SSLConnection::ErrorCode");
rrenkert@265:     qRegisterMetaType<Certificate::Status>("Certificate::Status");
aheinecke@0: 
aheinecke@0:     connect(mTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
aheinecke@0:             this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
aheinecke@19: 
aheinecke@19:     mMessageTimer = new QTimer(this);
aheinecke@19:     connect(mMessageTimer, SIGNAL(timeout()), this, SLOT(showMessage()));
aheinecke@19:     mMessageTimer->setInterval(NAG_INTERVAL_MINUTES * 60 * 1000);
aheinecke@19:     mMessageTimer->start();
aheinecke@71:     checkUpdates();
andre@389:     loadUnselectedCertificates();
andre@389:     loadCertificateList();
andre@1125: 
andre@1125:     if (mSettings.value("ShowOnNextStart").toBool()) {
andre@1125:         mSettings.remove("ShowOnNextStart");
andre@1125:         show();
andre@1125:     } else if (!trayMode) {
aheinecke@365:         show();
aheinecke@365:     }
aheinecke@0: }
aheinecke@0: 
aheinecke@0: void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
aheinecke@0: {
aheinecke@0:     switch (reason) {
aheinecke@0:     case QSystemTrayIcon::Trigger:
aheinecke@0:     case QSystemTrayIcon::MiddleClick:
aheinecke@0:         showMessage();
aheinecke@0:         break;
aheinecke@16:     case QSystemTrayIcon::DoubleClick:
aheinecke@365:         show();
aheinecke@16:         break;
aheinecke@0:     default:
aheinecke@0:         ;
aheinecke@0:     }
aheinecke@0: }
aheinecke@0: 
aheinecke@71: void MainWindow::messageClicked()
aheinecke@71: {
aheinecke@551:     if (mCurState == NewSoftwareAvailable) {
aheinecke@587:         verifySWData();
aheinecke@587:         QString swFileName = mSettings.value("Software/available").toString();
aheinecke@587:         if (swFileName.isEmpty()) {
aheinecke@587:             checkUpdates(true);
aheinecke@587:             mCurState = DownloadingSW;
aheinecke@587:             return;
aheinecke@587:         }
aheinecke@587:         installNewSW(swFileName,
aheinecke@587:                 mSettings.value("Software/availableDate").toDateTime());
andre@965:     } else {
andre@965:         show();
aheinecke@551:     }
aheinecke@71: }
aheinecke@71: 
aheinecke@0: void MainWindow::showMessage()
aheinecke@0: {
aheinecke@591:     if (mCurMessage.isEmpty()) {
aheinecke@591:         return;
aheinecke@591:     }
andre@961: 
andre@961:     if (!mTrayIcon->isVisible() && !mTrayIcon->isAlternative()) {
andre@961:         mTrayIcon->show();
andre@961:         /* When the message is shown before the tray icon is fully visble
andre@961:          * and becoming visible may be delayed on some desktop environments
andre@961:          * the message will pop up somehere on the screen and not over
andre@961:          * the trayicon. So we delay here.*/
andre@961:         QTimer::singleShot(2000, this, SLOT(showMessage()));
andre@961:     } else if (mCurState == NewSoftwareAvailable || !isVisible()) {
andre@1144:         if (mCurState == NewListAvailable) {
andre@1144:             mTrayIcon->showMessage(QApplication::applicationName(), mCurMessage,
andre@1144:                                    QSystemTrayIcon::Information, 10000,
andre@1144:                                    tr("Show recommendations"));
andre@1144:         } else if (mCurState == NewSoftwareAvailable || !mTrayIcon->isAlternative()) {
andre@1144:             /* Only show new list or new software in alternative as
andre@1144:              * the current tray icon alternative is too invasive for pure
andre@1144:              * informational messages. */
andre@1144:             mTrayIcon->showMessage(QApplication::applicationName(), mCurMessage,
andre@1144:                                    QSystemTrayIcon::Information, 10000);
andre@1144:         }
aheinecke@19:         mMessageTimer->start(); // Restart the timer so that we don't spam
aheinecke@16:     }
aheinecke@0: }
aheinecke@16: 
aheinecke@587: void MainWindow::verifyListData()
aheinecke@0: {
andre@389:     QString availableFileName = mSettings.value("List/available").toString();
andre@389:     QString installedFileName = mSettings.value("List/installed").toString();
andre@389:     if (!availableFileName.isEmpty()) {
andre@1153:         mListToInstall.readList(availableFileName.toUtf8().constData());
aheinecke@71:         if (!mListToInstall.isValid()) {
andre@1227:             handleLTE(lteInvalidList);
aheinecke@82:             mCurState = TransferError;
andre@389:             QFile::remove(availableFileName);
aheinecke@16:             mSettings.remove("List/available");
aheinecke@16:             mSettings.remove("List/availableDate");
andre@1227:         } else {
andre@1227:             handleLTE(lteInvalidList, true);
aheinecke@16:         }
aheinecke@16:     } else {
aheinecke@16:         // Make sure the available notation is also removed
aheinecke@16:         mSettings.remove("List/available");
aheinecke@16:         mSettings.remove("List/availableDate");
aheinecke@16:     }
aheinecke@16: 
andre@389:     if (!installedFileName.isEmpty()) {
andre@1153:         mInstalledList.readList(installedFileName.toUtf8().constData());
andre@389:         if (!mInstalledList.isValid()) {
andre@389:             // Probably a bug when Qt fileName is encoded and cFileName
andre@389:             // fails because of this. This needs a unit test!
andre@389:             // Maybe check that the file is in our data directory
andre@389:             QFile::remove(installedFileName);
andre@389:             mSettings.remove("List/installed");
andre@389:             mSettings.remove("List/installedDate");
andre@389:         }
andre@389:     } else {
andre@389:         mSettings.remove("List/installed");
andre@389:         mSettings.remove("List/installedDate");
andre@389:     }
aheinecke@587: }
andre@389: 
aheinecke@587: void MainWindow::verifySWData()
aheinecke@587: {
aheinecke@587:     QString swFileName = mSettings.value("Software/available").toString();
andre@389: 
aheinecke@591:     if (swFileName.isEmpty()) {
andre@1127:         qDebug() << "Date set but no fileName";
aheinecke@591:         mSettings.remove("Software/availableDate");
aheinecke@591:         return;
aheinecke@591:     }
aheinecke@591: 
aheinecke@591:     QFileInfo fi(swFileName);
aheinecke@591:     if (!fi.exists()) {
aheinecke@16:         mSettings.remove("Software/available");
aheinecke@16:         mSettings.remove("Software/availableDate");
aheinecke@591:         qDebug() << "Software does not yet exist.";
aheinecke@591:         return;
aheinecke@591:     }
aheinecke@591:     if (!fi.isExecutable()) {
aheinecke@591:         qWarning() << "Downloaded file: " << swFileName << " is not executable.";
aheinecke@591:         QFile::remove(swFileName);
aheinecke@591:         mSettings.remove("Software/available");
aheinecke@591:         mSettings.remove("Software/availableDate");
aheinecke@591:         return;
aheinecke@591:     }
aheinecke@591:     bin_verify_result verifyResult = verify_binary(swFileName.toUtf8().constData(),
aheinecke@591:             swFileName.toUtf8().size());
andre@1081:     qDebug() << "Binary verify result: " << verifyResult.result;
andre@1081:     if (verifyResult.result != VerifyValid) {
andre@1227:         handleLTE(lteInvalidSoftware);
aheinecke@591:         qDebug() << "Failed to verify downloaded data.";
aheinecke@591:         QFile::remove(swFileName);
aheinecke@591:         mSettings.remove("Software/available");
aheinecke@591:         mSettings.remove("Software/availableDate");
aheinecke@591:         return;
aheinecke@16:     }
andre@1227:     handleLTE(lteInvalidSoftware, true); /* Reset error state */
andre@1081:     fclose(verifyResult.fptr);
aheinecke@16: }
aheinecke@16: 
aheinecke@16: void MainWindow::handleNewList(const QString& fileName, const QDateTime& modDate) {
andre@1232: 
andre@1232:     if (mSettings.value("List/available").toString() == fileName &&
andre@1232:         getState() == NewListAvailable) {
andre@1232:         qDebug() << "List already handled";
andre@1232:         return;
andre@1232:     } else {
andre@1232:         qDebug() << "Handling list";
andre@1232:     }
aheinecke@71:     mSettings.setValue("List/available", fileName);
aheinecke@71:     mSettings.setValue("List/availableDate", modDate);
aheinecke@16: 
aheinecke@587:     verifyListData();
aheinecke@71:     if (!mListToInstall.isValid()) {
andre@1227:         handleLTE(lteInvalidList);
aheinecke@71:         /* Downloader provided invalid files */
aheinecke@71: 
aheinecke@71:         /* Retry the download again in 10 - 20 minutes */
aheinecke@71:         QTimer::singleShot(600000 + (qrand() % 60000), this, SLOT(checkUpdates()));
andre@1153:         qDebug() << "Failed to verify list.";
aheinecke@82:     } else {
andre@1154:         if (mTrayIcon->isAlternative()) {
andre@1154:             mCurMessage = tr("An updated certificate list is available.");
andre@1154:         } else {
andre@1154:             mCurMessage = tr("An updated certificate list is available.") +" " + tr("Click here to install.");
andre@1154:         }
aheinecke@82:         setState(NewListAvailable);
aheinecke@82:         showMessage();
rrenkert@189:         loadCertificateList();
aheinecke@71:     }
aheinecke@16: }
aheinecke@16: 
aheinecke@16: void MainWindow::handleNewSW(const QString& fileName, const QDateTime& modDate) {
andre@871:     if (mTrayIcon->isAlternative()) {
andre@871:         mCurMessage = tr("An update for %1 is available.").arg(
aheinecke@16:                 QApplication::applicationName());
andre@871:     } else {
andre@904:         mCurMessage = QString(tr("An update for %1 is available.") + "\n" +
andre@871:                 tr("Click here to download and install the update.")).arg(
andre@871:                 QApplication::applicationName());
andre@871:     }
aheinecke@16:     setState(NewSoftwareAvailable);
aheinecke@16:     mSettings.setValue("Software/available", fileName);
aheinecke@16:     mSettings.setValue("Software/availableDate", modDate);
aheinecke@16: 
aheinecke@16:     mSettings.sync();
aheinecke@16:     showMessage();
aheinecke@16: }
aheinecke@16: 
andre@1227: QString MainWindow::getPrettyInstallerName(QString realFileName) {
andre@1116:     QTemporaryDir tDir;
andre@1116:     if (!tDir.isValid()) {
andre@1116:         qDebug () << "Failed to create temporary directory.";
andre@1227:         showErrorMessage (tr("Failed to create temporary directory.") + "\n" +
andre@1227:                 tr("Please ensure that you have the access rights to write in "
andre@1227:                    "the temporary directory and that there is at least 20MB free "
andre@1227:                    "disk space available."));
andre@1116:         return QString();
andre@1116:     }
andre@1126:     QString targetPath = tDir.path() + "/" + QObject::tr("TrustBridge-Updater",
andre@1116:             "Used as filename for the updater. Only use ASCII please.");
andre@1116: 
andre@1116:     tDir.setAutoRemove(false);
andre@1116: #ifdef WIN32
andre@1116:     targetPath += ".exe";
andre@1116: #endif
andre@1116:     if (!QFile::copy(realFileName, targetPath)) {
andre@1227:         showErrorMessage (tr("Failed to create a temporary copy of the installer.") + "\n" +
andre@1227:                 tr("Please ensure that you have the access rights to write in "
andre@1227:                    "the temporary directory and that there is at least 20MB free "
andre@1227:                    "disk space available."));
andre@1116:         qDebug() << "Failed to create temporary copy of installer.";
andre@1116:     }
andre@1116:     return targetPath;
andre@1116: }
andre@1116: 
andre@1252: void MainWindow::updaterFinished(int exitCode, QProcess::ExitStatus status)
andre@1252: {
andre@1252:     if (status != QProcess::NormalExit) {
andre@1252:         syslog_error_printf("Update failed.\n");
andre@1252:         qDebug() << "Failed to install update.";
andre@1252:         return;
andre@1252:     }
andre@1252:     if (exitCode != 0) {
andre@1252:         qDebug() << "Update not installed with error: " << exitCode;
andre@1252:         return;
andre@1252:     }
andre@1252:     qDebug() << "Restarting";
andre@1252:     ProcessHelp::cleanUp();
andre@1252:     QProcess::startDetached(qApp->applicationFilePath());
andre@1252:     qApp->quit();
andre@1252: }
andre@1252: 
aheinecke@551: void MainWindow::installNewSW(const QString& fileName, const QDateTime& modDate) {
aheinecke@551:     QFileInfo instProcInfo = QFileInfo(fileName);
aheinecke@563:     QString filePath = QDir::toNativeSeparators(instProcInfo.absoluteFilePath());
andre@1116: 
andre@1116:     /* Copy the file to a temporary name for installation */
andre@1116:     filePath = getPrettyInstallerName(filePath);
andre@1116: 
andre@1116:     if (filePath.isEmpty()) {
andre@1116:         qDebug() << "Failed to copy updater to temporary location.";
andre@1116:         return;
andre@1116:     }
andre@1116:     mSettings.setValue("Software/Updater", filePath); /* So it can be deleted
andre@1116:                                                          on next start */
andre@1116:     mSettings.sync();
andre@1116: 
andre@1081:     bin_verify_result vres = verify_binary(filePath.toUtf8().constData(),
andre@1081:             filePath.toUtf8().size());
aheinecke@592: 
andre@1081:     if (vres.result != VerifyValid) {
andre@1227:         handleLTE(lteInvalidSoftware);
aheinecke@592:         qDebug() << "Invalid software. Not installing";
aheinecke@551:         return;
andre@1227:     }
andre@1227:     handleLTE(lteInvalidSoftware, true);
aheinecke@592:     QFileInfo fi(QCoreApplication::applicationFilePath());
aheinecke@592:     QDir installDir = fi.absoluteDir();
aheinecke@592: 
aheinecke@551: #ifdef WIN32
aheinecke@594:     QString parameters = QString::fromLatin1("/S /UPDATE=1 /D=") +
aheinecke@594:         installDir.path().replace("/", "\\") + "";
aheinecke@594: 
aheinecke@551:     SHELLEXECUTEINFOW shExecInfo;
aheinecke@563:     memset (&shExecInfo, 0, sizeof(SHELLEXECUTEINFOW));
aheinecke@563:     shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
aheinecke@563: 
aheinecke@563:     shExecInfo.lpFile = reinterpret_cast<LPCWSTR> (filePath.utf16());
aheinecke@594:     shExecInfo.lpParameters = reinterpret_cast<LPCWSTR> (parameters.utf16());
aheinecke@563: 
aheinecke@594:   //  shExecInfo.fMask = SEE_MASK_NOASYNC;
aheinecke@594:     shExecInfo.nShow = SW_SHOWDEFAULT;
aheinecke@551: 
andre@1003:     if (!is_system_install()) {
aheinecke@551:         shExecInfo.lpVerb = L"open";
aheinecke@551:     } else {
aheinecke@551:         shExecInfo.lpVerb = L"runas";
aheinecke@551:     }
aheinecke@551: 
aheinecke@594:     qDebug() << "Starting process: " << filePath
aheinecke@594:              << " with arguments: " << parameters;
aheinecke@551: 
aheinecke@551:     if (!ShellExecuteExW(&shExecInfo)) {
aheinecke@551:         /* Execution failed, maybe the user aborted the UAC check? */
aheinecke@551:         char* errmsg = getLastErrorMsg();
aheinecke@551:         QString qerrmsg = QString::fromUtf8(errmsg);
aheinecke@551:         free(errmsg);
aheinecke@551:         qDebug() << "Failed to start process: " << qerrmsg;
aheinecke@551:         setState(NewSoftwareAvailable);
andre@1081:         fclose(vres.fptr);
aheinecke@551:         return;
aheinecke@551:     }
aheinecke@551: #else /* WIN32 */
andre@894:     /* On linux installDir is <prefix>/bin */
aheinecke@594:     QStringList parameters;
andre@894:     installDir.cdUp();
andre@810:     parameters << "--prefix" << installDir.path();
andre@1067:     parameters << "--update";
andre@810:     bool sudo_started = false;
andre@841:     bool use_sudo = is_admin() && is_system_install();
andre@1252: 
andre@1252:     QProcess *updaterProcess = new QProcess();
andre@1252: 
andre@810:     if (use_sudo) {
andre@810:         QStringList sudoPrograms;
andre@987:         sudoPrograms << "pkexec" << "kdesudo" << "sudo";
andre@810:         QStringList sudoParams;
andre@1252:         sudoParams << filePath;
andre@1252:         sudoParams << parameters;
andre@1252:         updaterProcess->setArguments(sudoParams);
aheinecke@551: 
andre@1260: #if 0
andre@1260:         updaterProcess->setStandardErrorFile("/tmp/tb-inst-err.log");
andre@1260:         updaterProcess->setStandardOutputFile("/tmp/tb-inst-out.log");
andre@1260: #endif
andre@1260: 
andre@810:         foreach (const QString &sProg, sudoPrograms) {
andre@810:             qDebug() << "Starting process " << sProg <<" params: " << sudoParams;
andre@1252:             updaterProcess->setProgram(sProg);
andre@1252:             updaterProcess->start();
andre@1252:             if (!updaterProcess->waitForStarted() ||
andre@1252:                 updaterProcess->state() == QProcess::NotRunning) {
andre@810:                 continue;
andre@810:             } else {
andre@810:                 sudo_started = true;
andre@1252:                 connect(updaterProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
andre@1252:                         this, SLOT(updaterFinished(int, QProcess::ExitStatus)));
andre@810:                 break;
andre@810:             }
andre@810:         }
andre@810:     }
andre@1252:     if (!sudo_started) {
andre@1252:         qDebug() << "Starting process " << filePath <<" params: " << parameters;
andre@1252:         updaterProcess->setArguments(parameters);
andre@1252:         updaterProcess->setProgram(filePath);
andre@1252:         updaterProcess->start();
andre@1252: 
andre@1252:         if (!updaterProcess->waitForStarted() ||
andre@1252:             updaterProcess->state() == QProcess::NotRunning) {
andre@1252:             qDebug() << "Failed to start process.";
andre@1252:         }
andre@1252:         connect(updaterProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
andre@1272:                 this, SLOT(updaterFinished(int, QProcess::ExitStatus)));
aheinecke@551:         return;
aheinecke@551:     }
andre@810: 
aheinecke@551: #endif
andre@1125:     if (isVisible()) {
andre@1125:         mSettings.setValue("ShowOnNextStart", true);
andre@1125:         mSettings.sync();
andre@1125:     }
andre@1081: 
andre@1081:     syslog_info_printf ("Installing update: %s\n", fileName.toUtf8().constData());
aheinecke@551:     /* Installer process should now be running. We exit */
andre@1081:     fclose(vres.fptr);
andre@1252: #ifdef WIN32
aheinecke@551:     closeApp();
andre@1252: #endif
aheinecke@551: }
aheinecke@551: 
rrenkert@461: void MainWindow::checkUpdates(bool downloadSW)
aheinecke@16: {
aheinecke@587:     verifyListData();
aheinecke@16: 
andre@1116:     /* Delete old temporary installers if they exist */
andre@1116:     QString oldUpdater = mSettings.value("Software/Updater").toString();
andre@1116: 
andre@1116:     if (!oldUpdater.isEmpty()) {
andre@1116:         qDebug() << "Removing old updater: " << oldUpdater;
andre@1116:         QFileInfo fiUpdater(oldUpdater);
andre@1116:         if (!QFile::remove(fiUpdater.absoluteFilePath())) {
andre@1116:             qDebug() << "Failed to remove file";
andre@1116:         } else {
andre@1116:             if (!fiUpdater.absoluteDir().rmdir(fiUpdater.absoluteDir().absolutePath())) {
andre@1116:                 qDebug() << "Failed to remove temporary directory.";
andre@1116:             }
andre@1116:         }
andre@1116:         mSettings.remove("Software/Updater");
andre@1116:     }
andre@1116: 
aheinecke@551:     if (!mSettings.contains("Software/installedDate") ||
aheinecke@551:           mSettings.value("Software/installedVersion").toString() != QApplication::applicationVersion()) {
aheinecke@551:         /* This should only happen on initial startup and after an update has
aheinecke@551:          * been installed */
aheinecke@551:         getLastModForCurrentVersion();
rrenkert@486:         return;
rrenkert@486:     }
aheinecke@17:     QDateTime listInstalledLastMod = mSettings.value("List/installedDate").toDateTime();
aheinecke@17:     QDateTime swInstalledLastMod = mSettings.value("Software/installedDate").toDateTime();
andre@389:     QString listResource = QString::fromLatin1(LIST_RESOURCE);
andre@389:     QString swResource = QString::fromLatin1(SW_RESOURCE);
andre@389: 
andre@389: #ifndef RELEASE_BUILD
andre@389:     /* Use this for testing to specify another file name for updates */
andre@389:     listResource = mSettings.value("List/resource", listResource).toString();
andre@389:     swResource = mSettings.value("Software/resource", swResource).toString();
andre@389: #endif
andre@389: 
aheinecke@72:     Downloader* downloader = new Downloader(this,
aheinecke@72:                                             QString::fromLatin1(SERVER_URL),
aheinecke@72:                                             QByteArray(),
aheinecke@551:                                             swInstalledLastMod,
aheinecke@72:                                             listInstalledLastMod,
aheinecke@437:                                             swResource,
rrenkert@461:                                             listResource,
rrenkert@461:                                             downloadSW);
aheinecke@17: 
aheinecke@16:     connect(downloader, SIGNAL(newListAvailable(const QString&, const QDateTime&)),
aheinecke@16:             this, SLOT(handleNewList(const QString&, const QDateTime&)));
rrenkert@461:     if (!downloadSW) {
rrenkert@461:         connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)),
aheinecke@551:                 this, SLOT(handleNewSW(const QString&, const QDateTime&)));
aheinecke@551:     } else {
andre@708:         setState(DownloadingSW);
aheinecke@551:         connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)),
aheinecke@551:                 this, SLOT(installNewSW(const QString&, const QDateTime&)));
rrenkert@461:     }
aheinecke@551: 
aheinecke@16:     connect(downloader, SIGNAL(finished()), downloader, SLOT(deleteLater()));
andre@708:     connect(downloader, SIGNAL(finished()), this, SLOT(updateCheckSuccess()));
aheinecke@45:     connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)),
aheinecke@45:             this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode)));
aheinecke@10:     downloader->start();
andre@1126: 
andre@1126:     if (downloadSW && getState() == DownloadingSW && isVisible()) {
andre@1126:         QProgressDialog *progDlg = new QProgressDialog(this);
andre@1126:         progDlg->setCancelButton(0);
andre@1126:         progDlg->setRange(0,0);
andre@1126:         progDlg->setMinimumDuration(0);
andre@1126:         progDlg->setLabelText(tr("Downloading update..."));
andre@1126:         progDlg->show();
andre@1126:         connect(downloader, SIGNAL(finished()), progDlg, SLOT(deleteLater()));
andre@1126:         connect(downloader, SIGNAL(finished()), progDlg, SLOT(cancel()));
andre@1126:     }
aheinecke@0: }
aheinecke@0: 
aheinecke@551: void MainWindow::getLastModForCurrentVersion()
rrenkert@486: {
rrenkert@486:     QString softwareVersion = QString::fromLatin1(SW_RESOURCE_VERSION).arg(
rrenkert@486:         QApplication::applicationVersion());
rrenkert@486:     qDebug() << softwareVersion;
rrenkert@486:     QString listResource = QString::fromLatin1(LIST_RESOURCE);
rrenkert@486:     Downloader* downloader = new Downloader(this,
rrenkert@486:                                             QString::fromLatin1(SERVER_URL),
rrenkert@486:                                             QByteArray(),
rrenkert@486:                                             QDateTime::currentDateTime(),
rrenkert@486:                                             QDateTime::currentDateTime(),
rrenkert@486:                                             softwareVersion,
rrenkert@486:                                             listResource,
rrenkert@486:                                             false);
rrenkert@486:     connect(downloader, SIGNAL(finished()), downloader, SLOT(deleteLater()));
rrenkert@486:     connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)),
rrenkert@486:             this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode)));
rrenkert@486:     connect(downloader, SIGNAL(lastModifiedDate(const QDateTime&)),
aheinecke@551:         this, SLOT(setLastModifiedSWDate(const QDateTime&)));
andre@1155:     connect(this, SIGNAL(destroyed(QObject*)), downloader, SLOT(quit()));
rrenkert@486:     downloader->start();
rrenkert@486: }
rrenkert@486: 
aheinecke@551: void MainWindow::setLastModifiedSWDate(const QDateTime &date)
rrenkert@486: {
andre@1259:     QDateTime swAvailableLastMod = mSettings.value("Software/availableDate").toDateTime();
andre@1259: 
andre@1259:     if (swAvailableLastMod.isValid() && date.isValid()) {
andre@1259:         if (date >= swAvailableLastMod) {
andre@1259:             qDebug() << "Installed an update: " << date <<
andre@1259:                 " available was " << swAvailableLastMod;
andre@1259:             syslog_info_printf ("Software has been updated to version: %s\n",
andre@1259:                 QApplication::applicationVersion().toUtf8().constData());
andre@1259:             QString fileName = mSettings.value("Software/available").toString();
andre@1259:             if (fileName.isEmpty()) {
andre@1259:                 qDebug() << "Software marked as available but no filename set.";
andre@1259:             } else {
andre@1259:                 if (QFile::remove(fileName)) {
andre@1259:                     qDebug() << "Removed: " << fileName;
andre@1259:                 } else {
andre@1259:                     qDebug() << "Failed to remove: " << fileName;
andre@1259:                 }
andre@1259:             }
andre@1259:             /* Clear out available data. */
andre@1259:             mSettings.remove("Software/available");
andre@1259:             mSettings.remove("Software/availableDate");
andre@1259:         }
andre@1259:     }
andre@1259: 
rrenkert@486:     mSettings.beginGroup("Software");
andre@1145: #ifdef IS_TAG_BUILD
andre@1145:     /* We accept an invalid date to force installing any avialable update
andre@1145:      * in release mode. Otherwise we default to current datetime when we
andre@1145:      * did not find out version.*/
rrenkert@486:     mSettings.setValue("installedDate", date);
andre@1145: #else
andre@1145:     mSettings.setValue("installedDate", date.isValid() ? date : QDateTime::currentDateTime());
andre@1145: #endif
aheinecke@551:     mSettings.setValue("installedVersion", QApplication::applicationVersion());
rrenkert@486:     mSettings.endGroup();
rrenkert@486:     checkUpdates();
rrenkert@486: }
rrenkert@486: 
aheinecke@45: void MainWindow::downloaderError(const QString &message, SSLConnection::ErrorCode error)
aheinecke@16: {
andre@708:     syslog_error_printf ("Failed to check for updates: %s", message.toUtf8().constData());
andre@1230:     qDebug() << "Downloader error: " << error;
andre@1227:     if (error == SSLConnection::InvalidCertificate) {
andre@1227:         handleLTE(lteInvalidCertificate);
andre@1227:     } else {
andre@1227:         handleLTE(lteNoConnection);
andre@1227:     }
andre@1145: #ifdef IS_TAG_BUILD
andre@1145:     /* During tag build it should never happen that an url checked is not available
andre@1145:      * during development this is normal as each revision produces a new url. */
andre@1145:     setState(TransferError);
andre@1061:     if (!isVisible()) {
andre@1061:         mCurMessage = message;
andre@1061:         mTrayIcon->show();
andre@1061:         showMessage();
andre@1061:     } else {
andre@1061:         showErrorMessage(tr("Failed to check for updates:") + "\n"  + message);
andre@1061:     }
andre@1127: #endif
aheinecke@16: }
aheinecke@16: 
aheinecke@0: void MainWindow::createActions()
aheinecke@0: {
aheinecke@0:     mCheckUpdates = new QAction(tr("Check for Updates"), this);
aheinecke@16:     connect(mCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdates()));
aheinecke@2:     mQuitAction = new QAction(tr("Quit"), this);
aheinecke@2:     connect(mQuitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
aheinecke@0: }
aheinecke@0: 
aheinecke@0: void MainWindow::createTrayIcon()
aheinecke@0: {
aheinecke@11:     QIcon trayImg(":/img/tray_22.png");
andre@970:     trayImg.addFile(":/img/tray_48.png", QSize(48,48));
aheinecke@0: 
aheinecke@0:     mTrayMenu = new QMenu(this);
aheinecke@0:     mTrayMenu->addAction(mCheckUpdates);
aheinecke@2:     mTrayMenu->addAction(mQuitAction);
aheinecke@0: 
andre@871:     mTrayIcon = new TrayIcon(this);
aheinecke@0:     mTrayIcon->setContextMenu(mTrayMenu);
aheinecke@0: 
aheinecke@0:     mTrayIcon->setIcon(trayImg);
aheinecke@0:     setWindowIcon(trayImg);
aheinecke@407:     mTrayIcon->setToolTip(tr("TrustBridge"));
aheinecke@71: 
aheinecke@71:     connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked()));
aheinecke@0: }
rrenkert@155: 
andre@743: QWidget * MainWindow::createInfoWidget()
andre@739: {
andre@743:     QWidget *theWidget = new QWidget;
andre@739:     QVBoxLayout *infoPanelLayout = new QVBoxLayout;
andre@739:     QHBoxLayout *infoHeaderLayout = new QHBoxLayout;
andre@739:     QVBoxLayout *infoHeaderTextLayout = new QVBoxLayout;
andre@739:     QVBoxLayout *infoCenterLayout = new QVBoxLayout;
andre@739: 
andre@743:     QString infoVersion = tr("Version: ");
andre@739:     infoVersion.append(QApplication::applicationVersion());
andre@739:     QLabel *appVersion = new QLabel(infoVersion);
andre@739:     appVersion->setTextInteractionFlags(
andre@739:         Qt::TextSelectableByMouse |
andre@739:         Qt::TextSelectableByKeyboard);
andre@739: 
andre@739:     QFrame *infoHeaderSeparator = new QFrame();
andre@739:     infoHeaderSeparator->setFrameShape(QFrame::HLine);
andre@739:     infoHeaderSeparator->setFrameShadow(QFrame::Sunken);
andre@739: 
andre@739:     infoHeaderTextLayout->addWidget(appVersion);
andre@739:     infoHeaderLayout->addLayout(infoHeaderTextLayout);
andre@739:     infoHeaderLayout->insertStretch(2, 10);
andre@739: 
andre@743:     QLabel *textDesc = new QLabel(tr("TrustBridge is a root certificate"
andre@807:         " installer for Windows and GNU/Linux.<br/>") +
andre@807:     tr("The root certificate lists are managed"
andre@739:         " by the German <a href=\"https://www.bsi.bund.de\">"
andre@807:         "Federal Office for Information Security (BSI)</a>.<br/><br/>") +
andre@807:     tr("The software was developed by the companies"
andre@739:         " <a href=\"http://www.intevation.de\">Intevation GmbH</a> and "
andre@739:         " <a href=\"http://www.dn-systems.de\">DN-Systems GmbH</a>, <br>"
emanuel@1215:         " contracted by the BSI.<br/><br/>") +
andre@807:     tr("TrustBridge is Free Software licensed"
emanuel@1215:         " under GNU GPL v>=3.<br/>Copyright (C) 2014 by Bundesamt für Sicherheit"
emanuel@1215:         " in der Informationstechnik<br/><br/>") +
emanuel@1215:     tr("TrustBridge uses several Free Software components with different licenses:") +
emanuel@1215: 	"<ul><li>TrustBridge source code (GPL v>=2)" +
emanuel@1215: 	"<li>Qt (LGPL v==2.1)" +
emanuel@1215: 	"<li>PolarSSL (GPL v>=2)" +
emanuel@1215: 	"<li>Oxygen-Icons (LGPL v==3)" +
emanuel@1215: 	"<li>Mozilla NSS (Mozilla Public License v2)" +
emanuel@1215: 	"<li>libcurl (The curl license)</ul>" +
emanuel@1275:     tr("You will find the legally binding details in the 'licenses' directory "
emanuel@1275:        "where TrustBridge is installed<br/>"
emanuel@1275:        "or in the corresponding revision of the "
emanuel@1215:        "<a href=\"https://wald.intevation.org/hg/trustbridge/file/tip/licenses\">TrustBridge code repository</a>."));
andre@807:     textDesc->setTextFormat(Qt::RichText);
andre@807:     textDesc->setTextInteractionFlags(
andre@739:         Qt::TextSelectableByMouse |
andre@844:         Qt::TextSelectableByKeyboard |
andre@844:         Qt::LinksAccessibleByMouse);
andre@844:     textDesc->setOpenExternalLinks(true);
andre@739: 
andre@739:     infoCenterLayout->addWidget(infoHeaderSeparator);
andre@739:     infoCenterLayout->addWidget(textDesc);
andre@739:     infoCenterLayout->insertSpacing(2, 10);
andre@739:     infoCenterLayout->insertSpacing(4, 10);
andre@739:     infoCenterLayout->insertSpacing(6, 10);
andre@940: 
andre@940:     QHBoxLayout *helpButtonLayout = new QHBoxLayout();
emanuel@996:     QPushButton *helpButton = new QPushButton(" " + tr("Show Help"));
andre@964:     helpButton->setIcon(QIcon(":/img/show-help_16.png"));
andre@940:     connect(helpButton, SIGNAL(clicked()), this, SLOT(showHelp()));
andre@940:     helpButtonLayout->addWidget(helpButton);
andre@956: #ifdef USE_CURL
emanuel@996:     QPushButton *proxySettingsButton = new QPushButton(" " + tr("Proxy settings"));
andre@956:     proxySettingsButton->setIcon(QIcon(":/img/preferences-network_16.png"));
andre@956:     connect(proxySettingsButton, SIGNAL(clicked()), this, SLOT(showProxySettings()));
andre@956:     helpButtonLayout->addWidget(proxySettingsButton);
andre@956: #endif
andre@940:     helpButtonLayout->addStretch();
andre@940:     infoCenterLayout->addLayout(helpButtonLayout);
andre@940: 
andre@739:     infoCenterLayout->insertStretch(8, 10);
andre@739: 
andre@739:     infoPanelLayout->addLayout(infoHeaderLayout);
andre@739:     infoPanelLayout->addLayout(infoCenterLayout);
andre@743:     theWidget->setLayout(infoPanelLayout);
andre@743: 
andre@743:     return theWidget;
andre@743: }
andre@743: 
andre@743: QWidget * MainWindow::createUpdatesWidget()
andre@743: {
andre@743:     QWidget * theWidget = new QWidget;
andre@743:     QVBoxLayout *updatesMainLayout = new QVBoxLayout;
andre@743: 
andre@743:     /* The header */
andre@1096:     QVBoxLayout *updatesHeaderLayout = new QVBoxLayout;
andre@1096: 
andre@1098:     QGridLayout *detailsLayout = new QGridLayout;
andre@743: 
andre@1098:     /* Header 1: Action buttons and summary*/
andre@743:     mUpdatesHeader =
andre@743:         new QLabel("<h2>" + tr("Certificates unchanged")+ "</h2>");
andre@1098:     updatesHeaderLayout->addWidget(mUpdatesHeader);
andre@743: 
andre@743:     QHBoxLayout *updatesHeaderActionButtonLayout = new QHBoxLayout;
andre@743:     mQuitButton = new QPushButton(" " + tr("Quit without saving"));
andre@743:     mQuitButton->setIcon(QIcon(":/img/application-exit.png"));
andre@743:     mQuitButton->setFixedHeight(30);
andre@743: 
andre@743:     mInstallButton = new QPushButton(" " + tr("Install certificates again"));
andre@743:     mInstallButton->setFixedHeight(30);
andre@743: #ifdef Q_OS_WIN
andre@1003:     if (is_system_install()) {
andre@743:         QIcon uacShield = QApplication::style()->standardIcon(QStyle::SP_VistaShield);
andre@743:         mInstallButton->setIcon(uacShield);
andre@743:     }
andre@743: #else
bernhard@1211:     mInstallButton->setIcon(QIcon(":/img/do-changes-16.png"));
andre@743: #endif
andre@743:     connect(mQuitButton, SIGNAL(clicked()), this, SLOT(closeApp()));
andre@743:     connect(mInstallButton, SIGNAL(clicked()), this, SLOT(checkAndInstallCerts()));
andre@743: 
andre@743:     updatesHeaderActionButtonLayout->addWidget(mInstallButton);
andre@743:     updatesHeaderActionButtonLayout->addWidget(mQuitButton);
andre@1096:     updatesHeaderActionButtonLayout->addStretch(-1);
andre@1098: 
andre@1096:     updatesHeaderLayout->addLayout(updatesHeaderActionButtonLayout);
andre@1096:     updatesHeaderLayout->addSpacing(20);
andre@1096: 
andre@1096:     /* The splitter line */
andre@1096:     QFrame *line = new QFrame();
andre@1096:     line->setFrameShape(QFrame::HLine);
andre@1096:     line->setFrameShadow(QFrame::Sunken);
andre@1096:     updatesHeaderLayout->addWidget(line);
andre@743: 
andre@1098:     updatesMainLayout->addLayout(updatesHeaderLayout);
andre@1103: 
andre@1103:     /* Central Header Details and update button. Part of the scroll area */
andre@1103:     QScrollArea *centralScrollArea = new QScrollArea;
andre@1103:     QVBoxLayout *updatesCenterLayout = new QVBoxLayout;
andre@1098:     mUpdatesDetailsHeader = new QLabel(QString());
andre@1098: 
andre@1098:     QHBoxLayout *updateDateAndSearchButton = new QHBoxLayout;
andre@1098:     mCertListVersion =
andre@1098:         new QLabel(QString());
andre@1098:     mCertListVersionContents = new QLabel(QString());
andre@1098:     const QDateTime lastCheck = mSettings.value("lastUpdateCheck").toDateTime().toLocalTime();
emanuel@1104:     mLastUpdateCheck = new QLabel(tr("Last update check:"));
andre@1098:     if (lastCheck.isValid()) {
andre@1098:         const QString lastUpdateCheck = QLocale::system().toString(lastCheck, DATETIME_FORMAT);
andre@1098:         mLastUpdateCheckContents = new QLabel(lastUpdateCheck);
andre@1098:     } else {
andre@1098:         mLastUpdateCheckContents = new QLabel(tr("No connection with the updateserver."));
andre@1098:     }
andre@1098:     QPushButton *searchUpdates = new QPushButton(" " + tr("Update"));
emanuel@1104:     searchUpdates->setFixedHeight(22);
andre@1098:     searchUpdates->setToolTip(tr("Check for Updates"));
andre@1098:     searchUpdates->setStyleSheet("font-size: 10px;");
andre@1098:     searchUpdates->setIcon(QIcon(":/img/update-list.png"));
andre@1098:     connect(searchUpdates, SIGNAL(clicked()), this, SLOT(checkUpdates()));
andre@1098:     updateDateAndSearchButton->addWidget(mLastUpdateCheckContents);
andre@1098:     updateDateAndSearchButton->addWidget(searchUpdates);
andre@1098: 
andre@1098:     mUpdatesTip =
andre@1098:         new QLabel(QString());
andre@1098:     mUpdatesTip->setWordWrap(true);
andre@1098: 
andre@1098:     // addWidget(*Widget, row, column, rowspan, colspan)
andre@1103:     updatesCenterLayout->addWidget(mUpdatesDetailsHeader);
andre@1098:     detailsLayout->addWidget(mLastUpdateCheck, 0, 0, 1, 1);
andre@1098:     detailsLayout->addLayout(updateDateAndSearchButton, 0, 1, 1, 1);
andre@1098:     detailsLayout->addWidget(mCertListVersion, 1, 0, 1, 1);
andre@1098:     detailsLayout->addWidget(mCertListVersionContents, 1, 1, 1, 1);
andre@1098:     detailsLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum), 2, 2, 1, 1);
andre@1098:     detailsLayout->setColumnStretch(2, 1);
andre@1098: 
andre@1103:     updatesCenterLayout->addLayout(detailsLayout);
andre@1098: 
andre@1103:     updatesCenterLayout->addItem(new QSpacerItem(100, 10));
andre@1103:     updatesCenterLayout->addWidget(mUpdatesTip);
andre@1098: 
andre@743:     /* The central panels. */
andre@743:     QHBoxLayout *updatesNewLayout = new QHBoxLayout;
andre@743:     QHBoxLayout *updatesRemoveLayout = new QHBoxLayout;
andre@743:     QHBoxLayout *updatesManualLayout = new QHBoxLayout;
andre@743:     mUpdatesNewCertificates =
andre@743:         new QLabel("<h3>" +
andre@743:             tr("Install new trusted certificates (%1/%2)").arg(0).arg(0) +
andre@743:             "</h3>");
andre@790:     mUpdatesDetailsNew = new QPushButton();
emanuel@845:     mUpdatesDetailsNew->setText(" " + tr("Details"));
andre@790:     mUpdatesDetailsNew->setToolTip(tr("Show details"));
emanuel@845:     mUpdatesDetailsNew->setStyleSheet("font-size: 10px;");
emanuel@845:     mUpdatesDetailsNew->setFixedHeight(22);
emanuel@845:     mUpdatesDetailsNew->setIcon(QIcon(":/img/dialog-information_16px.png"));
andre@743:     connect(mUpdatesDetailsNew,
andre@743:         SIGNAL(clicked()),
andre@743:         this,
andre@743:         SLOT(toggleUpdatesNew()));
andre@743:     updatesNewLayout->addWidget(mUpdatesNewCertificates);
andre@790:     updatesNewLayout->addWidget(mUpdatesDetailsNew);
andre@743:     updatesNewLayout->addStretch(1);
andre@743:     mUpdatesNew = new CertificateListWidget(this);
andre@743:     connect(mUpdatesNew, SIGNAL(certListChanged(int)),
andre@743:         this, SLOT(listChanged(int)));
andre@743:     mUpdatesNew->hide();
andre@743: 
andre@743:     mUpdatesRemoveCertificates =
andre@743:         new QLabel("<h3>" +
andre@743:             tr("Remove revoked certificates (%1/%2)").arg(0).arg(0) +
andre@743:             "</h3>");
andre@790:     mUpdatesDetailsRemove = new QPushButton();
emanuel@845:     mUpdatesDetailsRemove->setText(" " + tr("Details"));
andre@790:     mUpdatesDetailsRemove->setToolTip(tr("Show details"));
emanuel@845:     mUpdatesDetailsRemove->setStyleSheet("font-size: 10px;");
emanuel@845:     mUpdatesDetailsRemove->setFixedHeight(22);
emanuel@845:     mUpdatesDetailsRemove->setIcon(QIcon(":/img/dialog-information_16px.png"));
andre@743:     connect(mUpdatesDetailsRemove,
andre@743:         SIGNAL(clicked()),
andre@743:         this,
andre@743:         SLOT(toggleUpdatesRemove()));
andre@743:     updatesRemoveLayout->addWidget(mUpdatesRemoveCertificates);
andre@790:     updatesRemoveLayout->addWidget(mUpdatesDetailsRemove);
andre@746:     updatesRemoveLayout->addStretch(1);
andre@743:     mUpdatesRemove = new CertificateListWidget(this);
andre@743:     connect(mUpdatesRemove, SIGNAL(certListChanged(int)),
andre@743:         this, SLOT(listChanged(int)));
andre@743:     mUpdatesRemove->hide();
andre@743: 
andre@1098:     mUpdatesManualCertificates = new QLabel(QString());
andre@790:     mUpdatesDetailsManual = new QPushButton();
emanuel@845:     mUpdatesDetailsManual->setText(" " + tr("Details"));
andre@790:     mUpdatesDetailsManual->setToolTip(tr("Show details"));
emanuel@845:     mUpdatesDetailsManual->setStyleSheet("font-size: 10px;");
emanuel@845:     mUpdatesDetailsManual->setFixedHeight(22);
emanuel@845:     mUpdatesDetailsManual->setIcon(QIcon(":/img/dialog-information_16px.png"));
andre@743:     connect(mUpdatesDetailsManual,
andre@743:         SIGNAL(clicked()),
andre@743:         this,
andre@743:         SLOT(toggleUpdatesManual()));
andre@743:     mUpdatesDetailsManual->hide();
andre@743:     updatesManualLayout->addWidget(mUpdatesManualCertificates);
andre@790:     updatesManualLayout->addWidget(mUpdatesDetailsManual);
andre@747:     updatesManualLayout->addStretch(1);
andre@743:     mUpdatesManual = new CertificateListWidget(this);
andre@743:     mUpdatesManual->hide();
andre@743:     connect(mUpdatesManual, SIGNAL(certChanged(bool, const Certificate&)),
andre@743:         this, SLOT(removeFromManual(bool, const Certificate&)));
andre@743:     connect(mUpdatesManual, SIGNAL(certListChanged(int)),
andre@743:         this, SLOT(listChanged(int)));
andre@743: 
andre@743:     updatesNewLayout->setAlignment(Qt::AlignTop);
andre@743:     updatesRemoveLayout->setAlignment(Qt::AlignTop);
andre@743:     updatesManualLayout->setAlignment(Qt::AlignTop);
andre@743:     updatesCenterLayout->addLayout(updatesNewLayout);
andre@743:     updatesCenterLayout->addWidget(mUpdatesNew);
andre@743:     updatesCenterLayout->addLayout(updatesRemoveLayout);
andre@743:     updatesCenterLayout->addWidget(mUpdatesRemove);
andre@1098:     updatesCenterLayout->addSpacing(10);
andre@743:     updatesCenterLayout->addLayout(updatesManualLayout);
andre@743:     updatesCenterLayout->addWidget(mUpdatesManual);
andre@743: 
andre@743:     QWidget *dummyWidget = new QWidget;
andre@743:     dummyWidget->setLayout(updatesCenterLayout);
andre@743:     centralScrollArea->setWidgetResizable(true);
andre@743:     centralScrollArea->setWidget(dummyWidget);
andre@743:     centralScrollArea->setFrameShape(QFrame::NoFrame);
andre@743:     centralScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
andre@743: 
andre@743:     updatesMainLayout->addWidget(centralScrollArea);
andre@743:     updatesCenterLayout->addSpacerItem(new QSpacerItem(0, 0,
andre@743:                 QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
andre@743:     theWidget->setLayout(updatesMainLayout);
andre@743:     return theWidget;
andre@743: }
andre@743: 
andre@743: 
andre@743: QWidget *MainWindow::createInstallWidget()
andre@743: {
andre@743:     QWidget *theWidget = new QWidget;
andre@743:     QScrollArea *scrollArea = new QScrollArea;
andre@743:     QVBoxLayout *installPanelLayout = new QVBoxLayout;
andre@743:     QVBoxLayout *installHeaderLayout = new QVBoxLayout;
andre@743:     QVBoxLayout *installCenterLayout = new QVBoxLayout;
andre@743: 
andre@743:     QLabel *installHeaderLabel =
andre@743:         new QLabel("<h2>" + tr("Trusted certificates") + "</h2>");
andre@743:     QLabel *installHeaderText = new QLabel(tr("The following list of trusted root"
andre@743:         " certificates is managed by the BSI. The BSI validates independently the"
andre@743:         " authenticity, security and actuality of these certificates."));
andre@743:     installHeaderText->setWordWrap(true);
andre@743:     installHeaderLayout->addWidget(installHeaderLabel);
andre@743:     installHeaderLayout->addWidget(installHeaderText);
andre@743: 
andre@743:     QLabel *installCenterText = new QLabel(tr("Please choose the certificates"
andre@743:         " you want to trust or untrust. TrustBridge will install these certificates for your"
andre@743:         " secure communication for email and internet."));
andre@743:     installCenterText->setWordWrap(true);
andre@743:     installCenterLayout->addWidget(installCenterText);
andre@743: 
andre@743:     installPanelLayout->addLayout(installHeaderLayout);
andre@743:     installPanelLayout->addLayout(installCenterLayout);
andre@743: 
andre@743:     mInstallList = new CertificateListWidget(this);
andre@743:     connect(mInstallList, SIGNAL(certChanged(bool, const Certificate&)),
andre@743:         this, SLOT(toggleInManual(bool, const Certificate&)));
andre@743: 
andre@743:     scrollArea->setWidgetResizable(true);
andre@743:     scrollArea->setWidget(mInstallList);
andre@743:     scrollArea->setFrameShape(QFrame::NoFrame);
andre@743: 
andre@743:     installPanelLayout->addWidget(scrollArea);
andre@743: 
andre@743:     theWidget->setLayout(installPanelLayout);
andre@743: 
andre@743:     return theWidget;
andre@743: }
andre@743: 
andre@743: QWidget *MainWindow::createRemoveWidget()
andre@743: {
andre@743:     QWidget * theWidget = new QWidget;
andre@743:     QScrollArea *scrollArea = new QScrollArea;
andre@743:     QVBoxLayout *removePanelLayout = new QVBoxLayout;
andre@743:     QVBoxLayout *removeHeaderLayout = new QVBoxLayout;
andre@743:     QVBoxLayout *removeCenterLayout = new QVBoxLayout;
andre@743: 
andre@743:     QLabel *removeHeaderLabel =
andre@743:         new QLabel("<h2>" + tr("Revoked certificates") + "</h2>");
andre@743:     QLabel *removeHeaderText = new QLabel(tr("Certificates can be corrupted"
andre@743:         " or stolen and misused in many ways. Therefore the BSI recommends"
andre@743:         " to remove all revoked certificates from your system."));
andre@743:     removeHeaderText->setWordWrap(true);
andre@743:     removeHeaderLayout->addWidget(removeHeaderLabel);
andre@743:     removeHeaderLayout->addWidget(removeHeaderText);
andre@743: 
bernhard@805:     QLabel *removeCenterText = new QLabel(tr("The following unsecure certificates were"
andre@743:         " revoked by the BSI. Already uninstalled certificates cannot be reinstalled."
andre@743:         " It is recommended that you select all certificates to uninstall if you still"
andre@743:         " have revoked certificates installed."));
andre@743:     removeCenterText->setWordWrap(true);
andre@743:     removeCenterLayout->addWidget(removeCenterText);
andre@743:     mRemoveList = new CertificateListWidget(this);
andre@743:     connect(mRemoveList, SIGNAL(certChanged(bool, const Certificate&)),
andre@743:         this, SLOT(toggleInManual(bool, const Certificate&)));
andre@743: 
andre@743:     removePanelLayout->addLayout(removeHeaderLayout);
andre@743:     removePanelLayout->addLayout(removeCenterLayout);
andre@743: 
andre@743:     scrollArea->setWidgetResizable(true);
andre@743:     scrollArea->setWidget(mRemoveList);
andre@743:     scrollArea->setFrameShape(QFrame::NoFrame);
andre@743:     removePanelLayout->addWidget(scrollArea);
andre@743:     theWidget->setLayout(removePanelLayout);
andre@743: 
andre@743:     return theWidget;
andre@739: }
andre@739: 
andre@739: void MainWindow::setupGUI()
rrenkert@187: {
rrenkert@187:     // Create a central widget containing the main layout.
rrenkert@187:     QWidget *base = new QWidget;
rrenkert@187: 
rrenkert@250:     // Layouts and Container
rrenkert@584:     QVBoxLayout *mainLayout = new QVBoxLayout;
rrenkert@205:     QHBoxLayout *headerLayout = new QHBoxLayout;
rrenkert@205:     QVBoxLayout *headerTextLayout = new QVBoxLayout;
andre@1094:     QHBoxLayout *headerSubtitleLayout = new QHBoxLayout;
rrenkert@584:     QHBoxLayout *centerLayout = new QHBoxLayout;
rrenkert@584:     QVBoxLayout *buttonBarLayout = new QVBoxLayout;
rrenkert@271:     QHBoxLayout *bottomLayout = new QHBoxLayout;
rrenkert@584:     QHBoxLayout *containerLayout = new QHBoxLayout;
rrenkert@187: 
rrenkert@584:     // The header (icon, about text)
rrenkert@584:     QImage *logoImage = new QImage(":/img/logo.png");
rrenkert@584:     QLabel *logo = new QLabel;
rrenkert@584:     logo->setBackgroundRole(QPalette::Base);
rrenkert@584:     logo->setPixmap(QPixmap::fromImage(*logoImage));
rrenkert@584:     QLabel *title = new QLabel("<h1>" + QString::fromLatin1(APPNAME) + "</h1>");
emanuel@1104:     QLabel *subTitle = new QLabel(tr("Trust in your digital communication"));
andre@1094:     QLabel *swVersion = new QLabel(QString::fromLatin1("<i>") +
andre@1094:             tr("Version") + " " + QApplication::applicationVersion() +
andre@1095:             QString::fromLatin1(" </i>"));
andre@1094: 
andre@1094:     swVersion->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
andre@1094:     swVersion->setTextFormat(Qt::RichText);
andre@1094: 
andre@1094:     headerSubtitleLayout->addWidget(subTitle);
andre@1094:     headerSubtitleLayout->addStretch(-1);
andre@1094:     headerSubtitleLayout->addWidget(swVersion);
andre@1094: 
rrenkert@584:     headerTextLayout->addWidget(title);
andre@1094:     headerTextLayout->addLayout(headerSubtitleLayout);
rrenkert@584:     headerLayout->addWidget(logo);
rrenkert@584:     headerLayout->addLayout(headerTextLayout);
rrenkert@584:     headerLayout->setStretch(0, 0);
rrenkert@584:     headerLayout->setStretch(1, 10);
rrenkert@584: 
rrenkert@652:     /***********************************
rrenkert@652:      * The Buttonbar on the left side.
rrenkert@652:      ***********************************/
rrenkert@584:     mButtonGroup = new QButtonGroup;
rrenkert@584: 
andre@722:     TextOverlayButton *updatesButton = new TextOverlayButton;
rrenkert@584:     updatesButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
andre@932:     updatesButton->setBackgroundIcon(":/img/red-circle.png");
bernhard@1202:     updatesButton->setIcon(QIcon(":/img/pending-changes-overview-48.png"));
emanuel@732:     updatesButton->setIconSize(QSize(48, 48));
andre@1099:     updatesButton->setText(tr("Pending\nchanges"));
emanuel@663:     updatesButton->setFixedWidth(120);
emanuel@732:     updatesButton->setFixedHeight(90);
rrenkert@584:     updatesButton->setCheckable(true);
rrenkert@584:     updatesButton->setChecked(true);
rrenkert@584: 
andre@722:     connect(this, SIGNAL(changesChanged(const QString&)),
andre@722:             updatesButton, SLOT(setOverlay(const QString&)));
andre@722: 
rrenkert@584:     QToolButton *allInstallButton = new QToolButton;
rrenkert@584:     allInstallButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
rrenkert@584:     allInstallButton->setIcon(QIcon(":/img/document-encrypt.png"));
emanuel@732:     allInstallButton->setIconSize(QSize(48, 48));
emanuel@659:     allInstallButton->setText(tr("Trusted\ncertificates"));
emanuel@663:     allInstallButton->setFixedWidth(120);
emanuel@732:     allInstallButton->setFixedHeight(90);
rrenkert@584:     allInstallButton->setCheckable(true);
rrenkert@584: 
rrenkert@584:     QToolButton *allRemoveButton = new QToolButton;
rrenkert@584:     allRemoveButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
emanuel@673:     allRemoveButton->setIcon(QIcon(":/img/dialog-warning.png"));
emanuel@732:     allRemoveButton->setIconSize(QSize(48, 48));
emanuel@661:     allRemoveButton->setText(tr("Revoked\ncertificates"));
emanuel@663:     allRemoveButton->setFixedWidth(120);
emanuel@732:     allRemoveButton->setFixedHeight(90);
rrenkert@584:     allRemoveButton->setCheckable(true);
rrenkert@584: 
rrenkert@584:     QToolButton *infoButton = new QToolButton;
rrenkert@584:     infoButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
rrenkert@584:     infoButton->setIcon(QIcon(":/img/dialog-information.png"));
emanuel@732:     infoButton->setIconSize(QSize(48, 48));
emanuel@659:     infoButton->setText(tr("Information\nand help"));
emanuel@663:     infoButton->setFixedWidth(120);
emanuel@732:     infoButton->setFixedHeight(90);
rrenkert@584:     infoButton->setCheckable(true);
rrenkert@584: 
rrenkert@584:     mButtonGroup->addButton(updatesButton);
rrenkert@584:     mButtonGroup->addButton(allInstallButton);
rrenkert@584:     mButtonGroup->addButton(allRemoveButton);
rrenkert@584:     mButtonGroup->addButton(infoButton);
rrenkert@584:     mButtonGroup->setId(updatesButton, 0);
rrenkert@584:     mButtonGroup->setId(allInstallButton, 1);
rrenkert@584:     mButtonGroup->setId(allRemoveButton, 2);
rrenkert@584:     mButtonGroup->setId(infoButton, 3);
rrenkert@584: 
rrenkert@584:     connect(mButtonGroup, SIGNAL(buttonClicked(int)),
rrenkert@584:         this, SLOT(togglePages(int)));
rrenkert@584:     buttonBarLayout->addWidget(updatesButton);
rrenkert@584:     buttonBarLayout->addWidget(allInstallButton);
rrenkert@584:     buttonBarLayout->addWidget(allRemoveButton);
rrenkert@584:     buttonBarLayout->insertStretch(3, 10);
rrenkert@584:     buttonBarLayout->addWidget(infoButton);
rrenkert@584: 
andre@743:     /* The main pages.*/
rrenkert@584: 
andre@743:     /* The updates page. */
andre@743:     mUpdatesWidget = createUpdatesWidget();
rrenkert@584: 
andre@743:     /* Install (trusted certs) Page */
andre@743:     mInstallWidget = createInstallWidget();
rrenkert@584: 
rrenkert@652:     /**********************************
andre@743:      * Page for certificates to be removed.
rrenkert@652:      **********************************/
andre@743:     mRemoveWidget = createRemoveWidget();
rrenkert@584: 
rrenkert@652:     /**********************************
andre@743:      * The info page.
rrenkert@652:      **********************************/
andre@743:     mInfoWidget = createInfoWidget();
rrenkert@584: 
rrenkert@652:     /********************************
rrenkert@652:      * The main layout for pages.
rrenkert@652:      ********************************/
andre@743:     mInstallWidget->hide();
andre@743:     mRemoveWidget->hide();
andre@743:     mInfoWidget->hide();
andre@743:     containerLayout->addWidget(mUpdatesWidget);
andre@743:     containerLayout->addWidget(mInstallWidget);
andre@743:     containerLayout->addWidget(mRemoveWidget);
andre@743:     containerLayout->addWidget(mInfoWidget);
rrenkert@584: 
rrenkert@584:     centerLayout->addLayout(buttonBarLayout);
rrenkert@584:     centerLayout->addLayout(containerLayout);
rrenkert@584: 
rrenkert@584:     mainLayout->addLayout(headerLayout);
rrenkert@584:     mainLayout->addLayout(centerLayout);
rrenkert@584:     mainLayout->addLayout(bottomLayout);
rrenkert@187:     base->setLayout(mainLayout);
rrenkert@187:     setCentralWidget(base);
rrenkert@187: }
rrenkert@187: 
rrenkert@628: void MainWindow::listChanged(int selected)
rrenkert@628: {
andre@716:     Q_UNUSED (selected);
andre@722:     setChangeCount(mUpdatesRemove->selectedCertCount() +
andre@1107:         mUpdatesNew->selectedCertCount() + mUpdatesManual->certificates().size());
andre@696: 
andre@718:     /* Show a different tip in case of manual changes, updates aviailable, updates and manual
andre@718:      * changes available */
andre@1107:     if (changeCount() && !mUpdatesManual->certificates().size()) {
andre@718:         mUpdatesTip->setText(
emanuel@1104:                 tr("You should apply the following, recommended changes to your certificate stores:"));
andre@718:     } else {
andre@1236:         mUpdatesTip->setText("");
andre@718:     }
andre@718: 
andre@716:     if (!changeCount()) {
andre@693:         /* No changes */
andre@702:         mQuitButton->setText(" " + tr("Quit"));
andre@696:         mUpdatesHeader->setText("<h2>" + tr("Certificates unchanged") +
andre@696:                 "</h2>");
andre@718:         mInstallButton->setText(" " + tr("Install certificates again"));
andre@693:     } else {
andre@702:         mQuitButton->setText(" " + tr("Quit without saving"));
emanuel@1104:         mUpdatesHeader->setText("<h2>" + tr("Pending changes (%1)")
andre@716:                 .arg(changeCount()) +
andre@696:                 "</h2>");
andre@718:         mInstallButton->setText(" " + tr("Apply changes"));
andre@693:     }
andre@693: 
andre@719:     if (mUpdatesManual->certificates().size()) {
andre@719:         mUpdatesDetailsManual->show();
andre@1109:         if (mManualDetailsShown) {
andre@1109:             mUpdatesManual->show();
andre@1109:             deactivateDetailsButton(mUpdatesDetailsManual);
andre@1109:         } else {
andre@1109:             activateDetailsButton(mUpdatesDetailsManual);
andre@1109:         }
andre@719:     } else {
andre@719:         mUpdatesDetailsManual->hide();
andre@719:         mUpdatesManual->hide();
andre@719:     }
andre@1098:     mUpdatesManualCertificates->setText("<h2>" +
andre@1109:             tr("Manual changes (%1)").arg(mUpdatesManual->certificates().size()) +
andre@1098:             "</h2>");
andre@719: 
andre@717:     if (mUpdatesNew->certificates().size()) {
andre@717:         mUpdatesNewCertificates->setText("<h3>" +
andre@717:                 tr("Install new trusted certificates (%1/%2)")
andre@717:                 .arg(mUpdatesNew->selectedCertCount())
andre@717:                 .arg(mUpdatesNew->certificates().size()) +
andre@717:                 "</h3>");
andre@717:         mUpdatesDetailsNew->show();
emanuel@845:         mUpdatesDetailsNew->setIcon(QIcon(":/img/dialog-information_16px.png"));
andre@790:         mUpdatesDetailsNew->setToolTip(tr("Show details"));
andre@717:         mUpdatesNewCertificates->show();
andre@717:     } else {
andre@717:         mUpdatesDetailsNew->hide();
andre@719:         mUpdatesNew->hide();
andre@717:         mUpdatesNewCertificates->hide();
andre@717:     }
andre@717: 
andre@717:     if (mUpdatesRemove->certificates().size()) {
andre@717:         mUpdatesRemoveCertificates->setText("<h3>" +
andre@717:                 tr("Remove revoked certificates (%1/%2)")
andre@717:                 .arg(mUpdatesRemove->selectedCertCount())
andre@717:                 .arg(mUpdatesRemove->certificates().size()) +
andre@717:                 "</h3>");
andre@717:         mUpdatesRemoveCertificates->show();
emanuel@845:         mUpdatesDetailsRemove->setIcon(QIcon(":/img/dialog-information_16px.png"));
andre@790:         mUpdatesDetailsRemove->setToolTip(tr("Show details"));
andre@717:         mUpdatesDetailsRemove->show();
andre@717:     } else {
andre@717:         mUpdatesRemoveCertificates->hide();
andre@717:         mUpdatesDetailsRemove->hide();
andre@719:         mUpdatesRemove->hide();
andre@717:     }
andre@1098: 
andre@1098:     /* Update the details header */
andre@1098:     if (mUpdatesRemove->certificates().size() ||
andre@1098:         mUpdatesNew->certificates().size()) {
andre@1098:         mUpdatesDetailsHeader->setText("<h2>" +
andre@1098:                 tr("New, recommended changes (%1/%2)")
andre@1098:                 .arg(mUpdatesRemove->selectedCertCount() +
andre@1098:                      mUpdatesNew->selectedCertCount())
andre@1098:                 .arg(mUpdatesRemove->certificates().size() +
andre@1098:                      mUpdatesNew->certificates().size()) +
andre@1098:                 "</h2>");
andre@1098:     } else {
andre@1098:         mUpdatesDetailsHeader->setText(QString::fromLatin1("<h2>") +
andre@1098:             tr("No new recommendations") + QString::fromLatin1("</h2>"));
andre@1098:     }
andre@1098: 
andre@1098:     if (mListToInstall.isValid()) {
emanuel@1104:         mCertListVersion->setText(tr("Certificate list from:"));
andre@1098:         mCertListVersionContents->setText(QLocale::system().toString(
andre@1098:                 mListToInstall.date().toLocalTime(), DATETIME_FORMAT));
andre@1098:     } else {
andre@1098:         if (mInstalledList.isValid()) {
emanuel@1104:             mCertListVersion->setText(tr("Currently installed certificate list:"));
andre@1098:             mCertListVersionContents->setText(QLocale::system().toString(
andre@1098:                     mInstalledList.date().toLocalTime(), DATETIME_FORMAT));
andre@1098:         } else {
emanuel@1104:             mCertListVersion->setText(tr("No certificate list installed."));
andre@1098:             mCertListVersionContents->setText("");
andre@1098:         }
andre@1098:     }
rrenkert@628: }
rrenkert@628: 
rrenkert@189: void MainWindow::loadCertificateList()
rrenkert@189: {
andre@1162:     /* TODO (issue134): if nothing is available (neither old nor new) add some progress
andre@389:      * indication */
andre@1233:     setUpdatesEnabled(false);
rrenkert@628:     mInstallList->clear();
andre@684:     mRemoveList->clear();
rrenkert@628:     mUpdatesNew->clear();
rrenkert@628:     mUpdatesRemove->clear();
rrenkert@445:     QList<Certificate> newInstallCerts;
rrenkert@445:     QList<Certificate> newRemoveCerts;
rrenkert@445:     QList<Certificate> oldInstallCerts;
rrenkert@445:     QList<Certificate> oldRemoveCerts;
andre@389: 
rrenkert@445:     if (mListToInstall.getCertificates().isEmpty()) {
rrenkert@445:         // No new list available, add old certificates.
rrenkert@445:         foreach (const Certificate &cert, mInstalledList.getCertificates()) {
rrenkert@640:             bool state = !mPreviouslyUnselected.contains(cert.base64Line());
rrenkert@445:             if (cert.isInstallCert()) {
rrenkert@445:                 oldInstallCerts.append(cert);
andre@1234:                 CheckLessToolBtn* actionBtn = new CheckLessToolBtn();
andre@1106:                 QIcon btnIcon;
andre@1106:                 if (!state) {
bernhard@1209:                     btnIcon.addFile(":/img/cert-to-be-installed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
andre@1148:                     btnIcon.addFile(":/img/cert-not-installed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
andre@1110:                     actionBtn->setProperty("ToolTip_Off", tr("Certificate will be installed."));
andre@1110:                     actionBtn->setProperty("ToolTip_On", tr("Certifcate is not installed."));
andre@1106:                 } else {
andre@1110:                     actionBtn->setProperty("ToolTip_Off", tr("Certificate is installed."));
andre@1110:                     actionBtn->setProperty("ToolTip_On", tr("Certificate will be removed."));
andre@1148:                     btnIcon.addFile(":/img/cert-is-installed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
bernhard@1209:                     btnIcon.addFile(":/img/cert-to-be-removed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
andre@1106:                 }
andre@1106:                 actionBtn->setIcon(btnIcon);
andre@1106:                 mInstallList->addCertificate(cert, state, actionBtn);
rrenkert@267:             }
rrenkert@267:             else {
rrenkert@445:                 oldRemoveCerts.append(cert);
andre@1234:                 CheckLessToolBtn* actionBtn = new CheckLessToolBtn();
andre@1106:                 QIcon btnIcon;
andre@1110:                 actionBtn->setProperty("ToolTip_Off", tr("Certificate will be removed."));
andre@1110:                 actionBtn->setProperty("ToolTip_On", tr("Certificate has not been removed."));
bernhard@1209:                 btnIcon.addFile(":/img/cert-to-be-removed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
andre@1148:                 btnIcon.addFile(":/img/cert-is-installed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
andre@1148:                 btnIcon.addFile(":/img/cert-not-installed-good-48.png", QSize(48, 48), QIcon::Disabled, QIcon::Off);
andre@1106:                 actionBtn->setIcon(btnIcon);
andre@1106:                 if (state) {
andre@1106:                     actionBtn->setEnabled(false);
andre@1110:                     actionBtn->setToolTip(tr("Certificate has been removed."));
andre@1106:                 }
andre@1106:                 mRemoveList->addCertificate(cert, state, actionBtn);
rrenkert@267:             }
rrenkert@267:         }
rrenkert@445:     }
rrenkert@445:     else {
rrenkert@445:         // Sort and filter both lists.
rrenkert@445:         foreach (const Certificate &cert, mListToInstall.getCertificates()) {
rrenkert@640:             bool state = !mPreviouslyUnselected.contains(cert.base64Line());
rrenkert@445:             if (cert.isInstallCert()) {
rrenkert@445:                 // Certificate with status "install".
rrenkert@445:                 if (mInstalledList.getCertificates().contains(cert)) {
rrenkert@445:                     // Was in the old list.
rrenkert@445:                     oldInstallCerts.append(cert);
andre@1234:                     CheckLessToolBtn* actionBtn = new CheckLessToolBtn();
andre@1106:                     QIcon btnIcon;
andre@1110:                     actionBtn->setProperty("ToolTip_Off", tr("Certificate is installed."));
andre@1110:                     actionBtn->setProperty("ToolTip_On", tr("Certifcate is not installed."));
andre@1148:                     btnIcon.addFile(":/img/cert-is-installed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
andre@1148:                     btnIcon.addFile(":/img/cert-not-installed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
andre@1106:                     actionBtn->setIcon(btnIcon);
andre@1106:                     mInstallList->addCertificate(cert, state, actionBtn);
rrenkert@445:                 }
rrenkert@445:                 else {
rrenkert@445:                     // Is a brand new certificate
rrenkert@445:                     newInstallCerts.append(cert);
andre@1234:                     CheckLessToolBtn* actionBtn = new CheckLessToolBtn();
andre@1106:                     QIcon btnIcon;
andre@1110:                     actionBtn->setProperty("ToolTip_Off", tr("Certificate will be installed."));
andre@1110:                     actionBtn->setProperty("ToolTip_On", tr("Certificate will not be installed."));
bernhard@1209:                     btnIcon.addFile(":/img/cert-to-be-installed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
andre@1148:                     btnIcon.addFile(":/img/cert-not-installed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
andre@1106:                     actionBtn->setIcon(btnIcon);
andre@1106:                     mUpdatesNew->addCertificate(cert, state, actionBtn);
rrenkert@445:                 }
rrenkert@267:             }
rrenkert@267:             else {
rrenkert@445:                 // Certificate with status "remove".
rrenkert@445:                 if (mInstalledList.getCertificates().contains(cert)) {
rrenkert@445:                     // Was in the old list.
rrenkert@445:                     oldRemoveCerts.append(cert);
rrenkert@640:                     // Is removed, so set editable to false.
andre@1234:                     CheckLessToolBtn* actionBtn = new CheckLessToolBtn();
andre@1106:                     QIcon btnIcon;
andre@1110:                     actionBtn->setProperty("ToolTip_Off", tr("Certificate will be removed."));
andre@1110:                     actionBtn->setProperty("ToolTip_On", tr("Certificate has not been removed."));
bernhard@1209:                     btnIcon.addFile(":/img/cert-to-be-removed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
andre@1148:                     btnIcon.addFile(":/img/cert-is-installed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
andre@1148:                     btnIcon.addFile(":/img/cert-not-installed-good-48.png", QSize(48, 48), QIcon::Disabled, QIcon::Off);
andre@1106:                     actionBtn->setIcon(btnIcon);
andre@1106:                     if (state) {
andre@1106:                         actionBtn->setEnabled(false);
andre@1110:                         actionBtn->setToolTip(tr("Certificate has been removed."));
andre@1106:                     }
andre@1106:                     mRemoveList->addCertificate(cert, state, actionBtn);
rrenkert@445:                 }
rrenkert@445:                 else {
rrenkert@445:                     // Was in the old list with status "install" and now has the
rrenkert@445:                     // status "remove".
rrenkert@445:                     newRemoveCerts.append(cert);
andre@1234:                     CheckLessToolBtn* actionBtn = new CheckLessToolBtn();
andre@1106:                     QIcon btnIcon;
andre@1110:                     actionBtn->setProperty("ToolTip_Off", tr("Certificate will be removed."));
andre@1110:                     actionBtn->setProperty("ToolTip_On", tr("Certificate will not be removed."));
bernhard@1209:                     btnIcon.addFile(":/img/cert-to-be-removed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
andre@1148:                     btnIcon.addFile(":/img/cert-is-installed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
andre@1106:                     actionBtn->setIcon(btnIcon);
andre@1106:                     mUpdatesRemove->addCertificate(cert, state, actionBtn);
rrenkert@445:                 }
rrenkert@267:             }
rrenkert@267:         }
andre@691:     }
andre@692: 
andre@692:     listChanged(0);
andre@1233:     setUpdatesEnabled(true);
rrenkert@271: }
aheinecke@365: 
aheinecke@365: void MainWindow::installerError(const QString& errMsg) {
aheinecke@365:     QMessageBox::warning(this, tr("Error executing update"), errMsg);
aheinecke@365: }
aheinecke@365: 
andre@389: void MainWindow::installerSuccess() {
andre@997:     if (mCurState == NewListAvailable ) {
andre@389:         mCurState = NothingChanged;
andre@389:         mCurMessage = QString();
andre@997:     }
andre@389: 
andre@997:     QString listFileName = mSettings.value("List/available").toString();
andre@997:     QDateTime listFileDate = mSettings.value("List/availableDate").toDateTime();
andre@997:     if (!listFileName.isEmpty() && listFileDate.isValid()) {
andre@389:         mSettings.remove("List/available");
andre@389:         mSettings.remove("List/availableDate");
andre@389: 
andre@857:         /* Rename the installed list to list-installed.txt so that external
andre@857:          * programs (like the uninstaller can easily recognize it). */
andre@857:         QString dataLoc =
andre@857:             QStandardPaths::writableLocation(QStandardPaths::DataLocation);
andre@857:         QDir dataDir(dataLoc);
andre@857:         if (!dataDir.exists()) {
andre@857:             /* Should not happen */
andre@857:             qWarning() << "Data dir removed.";
andre@857:             return;
andre@857:         }
andre@389: 
andre@857:         QFileInfo oldList (dataDir.absoluteFilePath("list-installed.txt"));
andre@857:         if (oldList.exists()) {
andre@857:             qDebug() << "Removing old list: " << oldList.filePath();
andre@857:             if (!QFile::remove(oldList.filePath())) {
andre@857:                 qWarning() << "Removal of old list failed.";
andre@857:                 return;
andre@857:             }
andre@857:         }
andre@857:         QFile newList(listFileName);
andre@857:         if (!newList.rename(oldList.filePath())) {
andre@857:             qWarning() << "Failed to rename new list.";
andre@857:             return;
andre@857:         }
andre@857: 
andre@857:         mSettings.setValue("List/installed", oldList.filePath());
andre@389:         mSettings.setValue("List/installedDate", listFileDate);
andre@857:         mInstalledList = CertificateList(oldList.filePath().toUtf8().constData());
andre@857:         if (!mInstalledList.isValid()) {
andre@857:             /* Something went wrong. Go back to square one. */
andre@857:             qWarning () << "List corrupted after installation";
andre@857:             mInstalledList = CertificateList();
andre@857:             QFile::remove(oldList.filePath());
andre@857:             mSettings.remove("List/installed");
andre@857:             mSettings.remove("List/installedDate");
andre@857:         }
andre@389:     }
andre@997:     mListToInstall = CertificateList();
andre@684:     mUpdatesManual->clear();
rrenkert@628:     loadCertificateList();
andre@389: }
andre@389: 
aheinecke@365: void MainWindow::installCerts() {
aheinecke@365:     QStringList choices;
rrenkert@640:     QStringList unselected;
aheinecke@365: 
rrenkert@640:     choices << mUpdatesNew->selectedCertificates();
rrenkert@640:     choices << mUpdatesRemove->selectedCertificates();
rrenkert@640: 
andre@669:     choices << mUpdatesManual->selectedCertificates();
andre@669: 
andre@669:     /* Also include the old certificates */
andre@669:     choices << mInstallList->selectedCertificates();
andre@669:     choices << mRemoveList->selectedCertificates();
andre@669: 
rrenkert@640:     QStringList unselectedManuals = mUpdatesManual->unselectedCertificates();
rrenkert@640:     for(int i = 0; i < unselectedManuals.size(); i++) {
rrenkert@640:         if (unselectedManuals.at(i).startsWith("I:")) {
rrenkert@640:             QString certLine = unselectedManuals.at(i);
rrenkert@640:             certLine[0] = 'R';
rrenkert@640:             choices << certLine;
rrenkert@640:         }
rrenkert@640:     }
rrenkert@640: 
rrenkert@640:     unselected << mUpdatesNew->unselectedCertificates();
rrenkert@640:     unselected << mUpdatesRemove->unselectedCertificates();
rrenkert@640:     unselected << mInstallList->unselectedCertificates();
rrenkert@640:     unselected << mRemoveList->unselectedCertificates();
rrenkert@628: 
andre@918: #ifdef Q_OS_WIN
andre@1003:     if (!is_system_install()) {
andre@1003:         QMessageBox::warning(this,
emanuel@926:                 tr("Installation with standard user account"),
emanuel@1006: 	        tr("Windows will now ask you to confirm each root certificate modification "
emanuel@926: 		   "because TrustBridge does not have the necessary privileges to install "
emanuel@926: 		   "root certificates into the Windows certificate store silently."));
andre@918:     }
andre@918: #endif
andre@918: 
aheinecke@365:     QProgressDialog *progress = new QProgressDialog(this);
aheinecke@365:     progress->setWindowModality(Qt::WindowModal);
aheinecke@365:     progress->setLabelText(tr("Installing certificates..."));
aheinecke@365:     progress->setCancelButton(0);
aheinecke@365:     progress->setRange(0,0);
aheinecke@365:     progress->setMinimumDuration(0);
aheinecke@365:     progress->show();
aheinecke@365: 
andre@1082:     CertificateList *instList = mListToInstall.isValid() ?
andre@1082:                                 &mListToInstall :
andre@1082:                                 &mInstalledList;
andre@1082: 
aheinecke@365:     InstallWrapper *instWrap = new InstallWrapper(this,
andre@1082:                                                   instList->fileName(),
aheinecke@365:                                                   choices);
andre@1082: 
andre@1082:     syslog_info_printf ("Installing certificate list: '%s' Version '%s'\n",
andre@1082:             instList->fileName().toUtf8().constData(),
andre@1082:             instList->date().toString().toUtf8().constData());
aheinecke@365:     /* Clean up object and progress dialog */
aheinecke@365:     connect(instWrap, SIGNAL(finished()), instWrap, SLOT(deleteLater()));
aheinecke@365:     connect(instWrap, SIGNAL(finished()), progress, SLOT(deleteLater()));
aheinecke@365:     connect(instWrap, SIGNAL(finished()), progress, SLOT(cancel()));
andre@389:     connect(instWrap, SIGNAL(installationSuccessful()),
andre@389:             this, SLOT(installerSuccess()));
aheinecke@365:     connect(instWrap, SIGNAL(error(const QString &)),
andre@389:             this, SLOT(installerError(const QString &)));
aheinecke@365:     instWrap->start();
rrenkert@640: 
rrenkert@640:     if (!saveUnselectedCertificates(unselected)) {
andre@372:         qWarning() << "Failed to save previosly unselected certificates.";
andre@372:     }
rrenkert@640: 
aheinecke@365: }
andre@372: 
andre@372: void MainWindow::loadUnselectedCertificates()
andre@372: {
andre@372:     mPreviouslyUnselected.clear();
andre@372:     mSettings.beginGroup("unselected");
andre@372:     QStringList keys = mSettings.allKeys();
andre@372:     foreach (const QString &key, keys) {
andre@372:         mPreviouslyUnselected << mSettings.value(key, QString()).toString();
andre@372:     }
andre@372:     mSettings.endGroup();
andre@372: }
andre@372: 
rrenkert@640: bool MainWindow::saveUnselectedCertificates(QStringList unselected)
andre@372: {
rrenkert@479:     mPreviouslyUnselected.clear();
andre@372:     mSettings.beginGroup("unselected");
andre@372:     mSettings.remove(""); /* Clears old choices */
rrenkert@640:     for (int i = 0; i < unselected.size(); i++) {
rrenkert@640:         QString key = QString::fromLatin1("cert%1").arg(i);
rrenkert@640:         QString value = unselected.at(i);
rrenkert@640:         mSettings.setValue(key, value);
rrenkert@640:         mPreviouslyUnselected << value;
andre@372:     }
andre@372:     mSettings.endGroup();
andre@372:     mSettings.sync();
andre@372:     return mSettings.status() == QSettings::NoError;
andre@372: }
rrenkert@447: 
rrenkert@640: void MainWindow::toggleInManual(bool state, const Certificate &cert)
rrenkert@640: {
rrenkert@640:     if (!mUpdatesManual->contains(cert)) {
andre@1106:         QToolButton* actionBtn = new QToolButton();
andre@1106:         QIcon btnIcon;
andre@1201:         if (mRemoveList->contains(cert)) {
bernhard@1209:             btnIcon.addFile(":/img/cert-to-be-removed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
andre@1201:             btnIcon.addFile(":/img/cert-is-installed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
andre@1201:             actionBtn->setProperty("ToolTip_On", tr("Certificate will be removed."));
andre@1201:             /* Off should never be possible here
andre@1201:              * As the manual change of removed certificates is disabled */
andre@1201:             actionBtn->setProperty("ToolTip_Off", tr("Certificate will not be removed."));
andre@1201:         } else {
bernhard@1209:             btnIcon.addFile(":/img/cert-to-be-installed-good-48.png", QSize(48, 48), QIcon::Normal, QIcon::On);
bernhard@1209:             btnIcon.addFile(":/img/cert-to-be-removed-bad-48.png", QSize(48, 48), QIcon::Normal, QIcon::Off);
andre@1201:             actionBtn->setProperty("ToolTip_On", tr("Certificate will be installed."));
andre@1201:             actionBtn->setProperty("ToolTip_Off", tr("Certificate will be removed."));
andre@1201:         }
andre@1106:         actionBtn->setIcon(btnIcon);
andre@1106:         mUpdatesManual->addCertificate(cert, state, actionBtn);
rrenkert@640:     }
rrenkert@640:     else {
andre@1107:         mUpdatesManual->removeCertificate(cert);
rrenkert@640:     }
rrenkert@640: }
rrenkert@640: 
rrenkert@640: void MainWindow::removeFromManual(bool state, const Certificate &cert)
rrenkert@640: {
andre@1107:     mUpdatesManual->removeCertificate(cert);
rrenkert@640: 
rrenkert@640:     if (cert.isInstallCert()) {
rrenkert@640:         mInstallList->setCertState(state, cert);
rrenkert@640:     }
rrenkert@640:     else {
rrenkert@640:         mRemoveList->setCertState(state, cert);
rrenkert@640:     }
rrenkert@640: }
rrenkert@640: 
rrenkert@447: void MainWindow::closeApp()
rrenkert@447: {
wilde@782:     ProcessHelp::cleanUp();
rrenkert@447:     qApp->quit();
rrenkert@447: }
rrenkert@584: 
andre@609: void MainWindow::checkAndInstallCerts()
andre@609: {
andre@1246: #ifdef WIN32
andre@609:     /* Checking before opening the dialog should be cheaper */
andre@609:     QList<int> pids = ProcessHelp::getProcessesIdForName("firefox");
andre@609:     pids.append(ProcessHelp::getProcessesIdForName("thunderbird"));
andre@609: 
andre@609:     if (pids.isEmpty()) {
andre@609:         installCerts();
andre@609:         return;
andre@609:     }
andre@609: 
andre@609:     QStringList pNames;
andre@609:     pNames << "firefox" << "thunderbird";
andre@609: 
andre@609:     ProcessWaitDialog *waitDialog = new ProcessWaitDialog(this, pNames);
andre@609: 
andre@609:     connect(waitDialog, SIGNAL(accepted()), this, SLOT(installCerts()));
andre@609:     connect(waitDialog, SIGNAL(accepted()), waitDialog, SLOT(deleteLater()));
andre@609: 
andre@609:     waitDialog->exec();
andre@609:     return;
andre@1246: #else
andre@1246:     /* On GNU Linux finding all firefox / thunderbird instances which
andre@1246:      * could be found on the filesystem is more difficult. So
andre@1246:      * for now we just show a generic warning dialog. */
andre@1246:     QMessageBox* warnMessage = new QMessageBox (QMessageBox::Information,
andre@1246:             tr("Firefox and Thunderbird certificate installation."),
andre@1246:             tr("Please close all running Firefox and Thunderbird instances "
andre@1246:                 "before continuing with the installation."), QMessageBox::Ok | QMessageBox::No,
andre@1246:             this);
andre@1246:     warnMessage->button(QMessageBox::Ok)->setText(tr("Continue"));
andre@1246:     warnMessage->setDefaultButton(QMessageBox::Ok);
andre@1246:     warnMessage->button(QMessageBox::No)->setText(tr("Cancel"));
andre@1246:     warnMessage->setWindowIcon(windowIcon());
andre@1246:     warnMessage->setIconPixmap(QIcon(":/img/dialog-warning.png").pixmap(QSize(48,48)));
andre@1246: 
andre@1246:     connect(warnMessage->button(QMessageBox::Ok), SIGNAL(clicked()), this, SLOT(installCerts()));
andre@1246:     warnMessage->exec();
andre@1246:     return;
andre@1246: #endif
andre@609: }
andre@654: 
rrenkert@584: void MainWindow::togglePages(int button)
rrenkert@584: {
andre@743:     mUpdatesWidget->hide();
andre@743:     mInstallWidget->hide();
andre@743:     mRemoveWidget->hide();
andre@743:     mInfoWidget->hide();
rrenkert@584:     switch(button) {
andre@743:     case 0: mUpdatesWidget->show(); break;
andre@743:     case 1: mInstallWidget->show(); break;
andre@743:     case 2: mRemoveWidget->show(); break;
andre@743:     case 3: mInfoWidget->show(); break;
andre@743:     default: mUpdatesWidget->show(); break;
rrenkert@584:     }
rrenkert@584:     return;
rrenkert@584: }
rrenkert@584: 
andre@1098: static void deactivateDetailsButton(QPushButton *btn) {
andre@1098:     btn->setToolTip(QObject::tr("Hide details"));
emanuel@1104:     btn->setText(" " + QObject::tr("Less"));
andre@1098:     btn->setIcon(QIcon(":/img/dialog-information_grey_16px.png"));
andre@1098: }
andre@1098: 
andre@1098: static void activateDetailsButton(QPushButton *btn) {
andre@1098:     btn->setToolTip(QObject::tr("Show details"));
emanuel@1104:     btn->setText(" " + QObject::tr("Details"));
andre@1098:     btn->setIcon(QIcon(":/img/dialog-information_16px.png"));
andre@1098: }
andre@1098: 
rrenkert@584: void MainWindow::toggleUpdatesNew() {
rrenkert@584:     if (!mUpdatesNew->isVisible()) {
rrenkert@584:         mUpdatesNew->show();
andre@1098:         deactivateDetailsButton(mUpdatesDetailsNew);
rrenkert@584:     }
rrenkert@584:     else {
rrenkert@653:         mUpdatesNew->hide();
andre@1098:         activateDetailsButton(mUpdatesDetailsNew);
rrenkert@584:     }
rrenkert@584: }
rrenkert@584: 
rrenkert@584: void MainWindow::toggleUpdatesRemove() {
rrenkert@584:     if (!mUpdatesRemove->isVisible()) {
rrenkert@584:         mUpdatesRemove->show();
andre@1098:         deactivateDetailsButton(mUpdatesDetailsRemove);
rrenkert@584:     }
rrenkert@584:     else {
rrenkert@653:         mUpdatesRemove->hide();
andre@1098:         activateDetailsButton(mUpdatesDetailsRemove);
rrenkert@584:     }
rrenkert@584: }
rrenkert@584: 
rrenkert@584: void MainWindow::toggleUpdatesManual() {
rrenkert@584:     if (!mUpdatesManual->isVisible()) {
rrenkert@584:         mUpdatesManual->show();
andre@1109:         mManualDetailsShown = true;
andre@1098:         deactivateDetailsButton(mUpdatesDetailsManual);
rrenkert@584:     }
rrenkert@584:     else {
rrenkert@653:         mUpdatesManual->hide();
andre@1109:         mManualDetailsShown = false;
andre@1098:         activateDetailsButton(mUpdatesDetailsManual);
rrenkert@584:     }
rrenkert@584: }
andre@690: 
andre@690: void MainWindow::closeEvent(QCloseEvent *event)
andre@690: {
andre@690:     if (getState() == NewListAvailable) {
andre@690:         /* Only minimize to tray if there is a new list */
andre@690:         QMainWindow::closeEvent(event);
andre@965:         mTrayIcon->show();
andre@690:         return;
andre@690:     }
andre@690:     return closeApp();
andre@690: }
andre@708: 
andre@708: void MainWindow::updateCheckSuccess()
andre@708: {
andre@708:     if (getState() != TransferError) {
andre@708:         const QDateTime now = QDateTime::currentDateTime();
andre@708:         mSettings.setValue("lastUpdateCheck", now);
andre@754:         mLastUpdateCheckContents->setText(QLocale::system().toString(now, DATETIME_FORMAT));
andre@754:         mLastUpdateCheckContents->show();
andre@708:         mLastUpdateCheck->show();
andre@708:         syslog_info_printf(tr("Sucessfully checked for updates.").toUtf8().constData());
andre@1227:         handleLTE(lteNoConnection, true); /* Reset error state */
andre@1227:         handleLTE(lteInvalidCertificate, true);
andre@708:     }
andre@1042:     if ((getState() != NewSoftwareAvailable && getState() != NewListAvailable && mTrayMode)
andre@1042:             && !isVisible()) {
andre@962:         qDebug() << "Shutting down as no list or Software is available.";
andre@962:         closeApp();
andre@962:     } else {
andre@962:         mTrayIcon->show();
andre@962:     }
andre@708: }
andre@716: 
andre@716: int MainWindow::changeCount()
andre@716: {
andre@716:     return mChangeCount;
andre@716: }
andre@722: 
andre@722: void MainWindow::setChangeCount(int cnt)
andre@722: {
andre@722:     if (mChangeCount != cnt) {
andre@722:         mChangeCount = cnt;
andre@722:         emit changesChanged(QString("%1").arg(cnt));
andre@722:     }
andre@722: }
andre@940: 
andre@956: void MainWindow::showProxySettings()
andre@956: {
andre@956:     ProxySettingsDlg *dlg = new ProxySettingsDlg(this);
andre@956:     dlg->exec();
andre@956: }
andre@956: 
andre@940: void MainWindow::showHelp()
andre@940: {
andre@940:     char *inst_dir = get_install_dir();
andre@940:     if (!inst_dir) {
andre@940:         qDebug() << "Failed to find install dir";
andre@940:         return;
andre@940:     }
andre@940:     QString helpPath = QString::fromUtf8(inst_dir);
andre@940:     helpPath += HELP_PATH;
andre@940:     QFileInfo fiHelp(helpPath);
andre@940:     qDebug() << "Opening help: " << fiHelp.absoluteFilePath();
andre@940:     if (!fiHelp.exists()) {
andre@940:         QMessageBox::warning(this, tr("Error!"), tr ("Failed to find the manual"));
andre@940:         return;
andre@940:     }
andre@966: #ifdef Q_OS_WIN
andre@966:     QDesktopServices::openUrl(QUrl("file:///" + fiHelp.absoluteFilePath()));
andre@966: #else
andre@940:     QDesktopServices::openUrl(QUrl(fiHelp.absoluteFilePath()));
andre@966: #endif
andre@940:     free (inst_dir);
andre@940:     return;
andre@940: }
andre@1061: 
andre@1061: void MainWindow::showErrorMessage(const QString &msg)
andre@1061: {
andre@1061:     QMessageBox::warning(this, tr("TrustBridge error"), msg);
andre@1061: }
andre@1227: 
andre@1227: void MainWindow::handleLTE(LongTimeErrors lte, bool reset)
andre@1227: {
andre@1227:     QString settingPrefix;
andre@1230:  //   qDebug() << "Handle LTE for " << lte << " Reset? : " << reset;
andre@1227:     switch (lte) {
andre@1227:         case lteInvalidSoftware:
andre@1227:             settingPrefix = "LTE/invalidSW";
andre@1227:             break;
andre@1227:         case lteInvalidList:
andre@1227:             settingPrefix = "LTE/invalidList";
andre@1227:             break;
andre@1227:         case lteInvalidCertificate:
andre@1227:             settingPrefix = "LTE/invalidCertificate";
andre@1227:             break;
andre@1227:         case lteNoConnection:
andre@1227:             settingPrefix = "LTE/noConnection";
andre@1227:             break;
andre@1227:         default:
andre@1227:             qDebug() << "Unhandled error. " << lte;
andre@1227:     }
andre@1227: 
andre@1227:     if (reset) {
andre@1227:         /* delete all values and be done */
andre@1227:         mSettings.remove(settingPrefix + "_lastSaved");
andre@1227:         mSettings.remove(settingPrefix + "_count");
andre@1230:         mSettings.remove(settingPrefix + "_lastShown");
andre@1227:         return;
andre@1227:     }
andre@1227: 
andre@1227:     QDateTime lastSaved = mSettings.value(settingPrefix + "_lastSaved").toDateTime();
andre@1227:     bool cnt_valid;
andre@1227:     int cnt = mSettings.value(settingPrefix + "_count").toInt(&cnt_valid);
andre@1227:     if (!cnt_valid) {
andre@1227:         cnt = 0;
andre@1227:     }
andre@1227: 
andre@1227:     if (!lastSaved.isValid() || lastSaved.daysTo(QDateTime::currentDateTime()) >= 1) {
andre@1227:         /* The error count is increased at most once a day */
andre@1227:         mSettings.setValue(settingPrefix + "_lastSaved", QDateTime::currentDateTime());
andre@1227:         mSettings.setValue(settingPrefix + "_count", ++cnt);
andre@1227:     }
andre@1227: 
andre@1227: 
andre@1227:     if (cnt < 7) {
andre@1227:         /* We are done */
andre@1227:         return;
andre@1227:     }
andre@1227:     /* A week has passed. Start showing the error. */
andre@1227:     QDateTime lastShown = mSettings.value(settingPrefix + "_lastShown").toDateTime();
andre@1227:     if (lastShown.isValid() && lastShown.daysTo(QDateTime::currentDateTime()) < 1) {
andre@1227:         /* Only show the error message once a day */
andre@1227:         return;
andre@1227:     }
andre@1227: 
andre@1227:     mSettings.setValue(settingPrefix + "_lastShown", QDateTime::currentDateTime());
andre@1227: 
andre@1227:     switch (lte) {
andre@1227:         case lteInvalidSoftware:
andre@1227:             showErrorMessage(tr("The integrity check for the available software update has "
andre@1227:                         "failed repeatedly.") + "\n" +
andre@1227:                         tr("Please contact your Support or the publisher of the Software."));
andre@1227:             break;
andre@1227:         case lteInvalidList:
andre@1227:             showErrorMessage(tr("The integrity check of the available certificates has "
andre@1227:                         "failed repeatedly.") + "\n" +
andre@1227:                         tr("Please contact your Support or the publisher of the Software."));
andre@1227:             break;
andre@1227:         case lteInvalidCertificate:
emanuel@1275:             showErrorMessage(tr("The authentication of the update server has "
andre@1227:                         "failed repeatedly.") + "\n" +
andre@1227:                         tr("Please contact your Support or the publisher of the Software."));
andre@1227:             break;
andre@1227:         case lteNoConnection:
andre@1227:             bool useProxy = mSettings.value("UseProxy", false).toBool();
andre@1227:             if (useProxy) {
emanuel@1275:                 showErrorMessage(tr("The connection to the update server has "
andre@1227:                             "failed repeatedly.") + "\n" +
andre@1227:                             tr("Please check that the Proxy Server \"%1\" is available.").arg(
andre@1227:                                 mSettings.value("ProxyURL").toString()));
andre@1227:             } else {
emanuel@1275:                 showErrorMessage(tr("The connection to the update server has "
andre@1227:                             "failed repeatedly.") + "\n" +
andre@1227:                             tr("Please check your internet connection."));
andre@1227:             }
andre@1227:             break;
andre@1227:     }
andre@1227: }