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 aheinecke@551: #include aheinecke@365: #include aheinecke@0: #include aheinecke@0: #include aheinecke@0: #include aheinecke@0: #include aheinecke@563: #include aheinecke@0: #include aheinecke@2: #include aheinecke@16: #include aheinecke@19: #include rrenkert@187: #include rrenkert@187: #include rrenkert@187: #include rrenkert@189: #include rrenkert@205: #include rrenkert@205: #include rrenkert@250: #include rrenkert@584: #include rrenkert@584: #include aheinecke@19: andre@609: #include "certificatelist.h" andre@609: #include "downloader.h" andre@609: #include "helpdialog.h" andre@609: #include "aboutdialog.h" andre@609: #include "certificateitemdelegate.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@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: aheinecke@409: #ifndef APPNAME aheinecke@409: #define APPNAME "TrustBridge" aheinecke@409: #endif aheinecke@409: aheinecke@409: #define SERVER_URL "https://files.intevation.de:443" aheinecke@72: andre@607: #ifdef RELEASE_BUILD andre@607: # define LIST_RESOURCE "/users/aheinecke/zertifikatsliste.txt" andre@607: # ifdef Q_OS_WIN andre@607: # define SW_RESOURCE_VERSION "/users/aheinecke/TrustBridge-%1.exe" andre@664: # define SW_RESOURCE "/users/aheinecke/TrustBridge.exe" andre@607: # else andre@607: # define SW_RESOURCE_VERSION "/users/aheinecke/TrustBridge-%1.sh" andre@664: # define SW_RESOURCE "/users/aheinecke/TrustBridge.sh" andre@607: # endif andre@607: #else // RELEASE_BUILD andre@607: # define LIST_RESOURCE "/users/aheinecke/development/zertifikatsliste.txt" andre@607: # ifdef Q_OS_WIN andre@607: # define SW_RESOURCE_VERSION "/users/aheinecke/development/TrustBridge-development.exe" andre@664: # define SW_RESOURCE "/users/aheinecke/development/TrustBridge.exe" andre@607: # else andre@607: # define SW_RESOURCE_VERSION "/users/aheinecke/development/TrustBridge-development.sh" andre@664: # define SW_RESOURCE "/users/aheinecke/development/TrustBridge.sh" andre@607: # endif rrenkert@486: #endif aheinecke@7: aheinecke@365: MainWindow::MainWindow(bool trayMode): aheinecke@365: mTrayMode(trayMode) aheinecke@365: { aheinecke@0: createActions(); aheinecke@0: createTrayIcon(); rrenkert@187: createContent(); rrenkert@450: resize(950, 540); aheinecke@45: qRegisterMetaType("SSLConnection::ErrorCode"); rrenkert@265: qRegisterMetaType("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(); aheinecke@365: 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@71: if (mCurState == NewListAvailable) { aheinecke@365: show(); aheinecke@71: } aheinecke@551: 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()); aheinecke@551: } aheinecke@71: } aheinecke@71: aheinecke@0: void MainWindow::showMessage() aheinecke@0: { aheinecke@591: if (mCurMessage.isEmpty()) { aheinecke@591: return; aheinecke@591: } aheinecke@591: if (mCurState == NewSoftwareAvailable || !isVisible()) { aheinecke@16: mTrayIcon->showMessage(QApplication::applicationName(), mCurMessage, aheinecke@591: QSystemTrayIcon::Information, 10000); 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@389: mListToInstall.readList(availableFileName.toLocal8Bit().constData()); aheinecke@71: if (!mListToInstall.isValid()) { aheinecke@82: mCurState = TransferError; aheinecke@16: // Probably a bug when Qt fileName is encoded and cFileName aheinecke@16: // fails because of this. This needs a unit test! aheinecke@16: // Maybe check that the file is in our data directory andre@389: QFile::remove(availableFileName); aheinecke@16: mSettings.remove("List/available"); aheinecke@16: mSettings.remove("List/availableDate"); 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@389: mInstalledList.readList(installedFileName.toLocal8Bit().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()) { 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()); aheinecke@591: qDebug() << "Binary verify result: " << verifyResult; aheinecke@591: if (verifyResult != VerifyValid) { 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: } aheinecke@16: } aheinecke@16: aheinecke@16: void MainWindow::handleNewList(const QString& fileName, const QDateTime& modDate) { rrenkert@628: qDebug() << "new list available"; aheinecke@71: mSettings.setValue("List/available", fileName); aheinecke@71: mSettings.setValue("List/availableDate", modDate); aheinecke@16: aheinecke@587: verifyListData(); aheinecke@71: if (!mListToInstall.isValid()) { aheinecke@71: /* Downloader provided invalid files */ aheinecke@71: /* TODO: Error count. Error handling. Otherwise aheinecke@71: * we can go into an endless loop here */ aheinecke@71: aheinecke@71: /* Retry the download again in 10 - 20 minutes */ aheinecke@71: QTimer::singleShot(600000 + (qrand() % 60000), this, SLOT(checkUpdates())); aheinecke@82: } else { aheinecke@82: mCurMessage = tr("An updated certificate list is available. Click here to install."); 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) { aheinecke@555: mCurMessage = tr("An update for %1 is available.\n" aheinecke@551: "Click here to download and install the update.").arg( aheinecke@16: QApplication::applicationName()); 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: 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()); aheinecke@592: aheinecke@592: if (verify_binary(filePath.toUtf8().constData(), aheinecke@592: filePath.toUtf8().size()) != VerifyValid) { aheinecke@592: qDebug() << "Invalid software. Not installing"; aheinecke@551: return; aheinecke@592: } 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 (filePath.utf16()); aheinecke@594: shExecInfo.lpParameters = reinterpret_cast (parameters.utf16()); aheinecke@563: aheinecke@594: // shExecInfo.fMask = SEE_MASK_NOASYNC; aheinecke@594: shExecInfo.nShow = SW_SHOWDEFAULT; aheinecke@551: aheinecke@551: if (!is_admin()) { 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); aheinecke@551: return; aheinecke@551: } aheinecke@551: #else /* WIN32 */ aheinecke@594: QStringList parameters; aheinecke@594: parameters << "/S" << "/UPDATE=1" aheinecke@594: << QString::fromLatin1("/D=%1").arg(installDir.path()); aheinecke@551: aheinecke@594: qDebug() << "Starting process " << filePath << " args: " << parameters; aheinecke@594: aheinecke@594: if (!QProcess::startDetached(filePath, parameters)) { aheinecke@551: qDebug() << "Failed to start process."; aheinecke@551: return; aheinecke@551: } aheinecke@551: #endif aheinecke@551: /* Installer process should now be running. We exit */ aheinecke@551: aheinecke@551: closeApp(); aheinecke@551: } aheinecke@551: rrenkert@461: void MainWindow::checkUpdates(bool downloadSW) aheinecke@16: { aheinecke@587: verifyListData(); aheinecke@16: 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(); aheinecke@16: 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: 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 { 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())); aheinecke@45: connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)), aheinecke@45: this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode))); aheinecke@10: downloader->start(); 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&))); rrenkert@486: rrenkert@486: downloader->start(); rrenkert@486: } rrenkert@486: aheinecke@551: void MainWindow::setLastModifiedSWDate(const QDateTime &date) rrenkert@486: { rrenkert@486: mSettings.beginGroup("Software"); rrenkert@486: mSettings.setValue("installedDate", date); 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: { aheinecke@551: /* TODO logging and handle error according to a plan */ aheinecke@16: mCurMessage = message; andre@27: showMessage(); aheinecke@551: setState(TransferError); 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"); aheinecke@0: aheinecke@0: mTrayMenu = new QMenu(this); aheinecke@0: mTrayMenu->addAction(mCheckUpdates); aheinecke@2: mTrayMenu->addAction(mQuitAction); aheinecke@0: aheinecke@0: mTrayIcon = new QSystemTrayIcon(this); aheinecke@0: mTrayIcon->setContextMenu(mTrayMenu); aheinecke@0: aheinecke@0: mTrayIcon->setIcon(trayImg); aheinecke@0: setWindowIcon(trayImg); aheinecke@0: mTrayIcon->show(); aheinecke@407: mTrayIcon->setToolTip(tr("TrustBridge")); aheinecke@71: aheinecke@71: connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked())); aheinecke@0: } rrenkert@155: rrenkert@187: void MainWindow::createContent() 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; 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("

" + QString::fromLatin1(APPNAME) + "

"); emanuel@689: QLabel *subTitle = new QLabel(tr("Trust in your digital communication")); rrenkert@584: headerTextLayout->addWidget(title); rrenkert@584: headerTextLayout->addWidget(subTitle); 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: rrenkert@584: QToolButton *updatesButton = new QToolButton; rrenkert@584: updatesButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); rrenkert@584: updatesButton->setIcon(QIcon(":/img/view-refresh.png")); emanuel@673: updatesButton->setIconSize(QSize(40, 40)); rrenkert@584: updatesButton->setText(tr("Updates")); emanuel@663: updatesButton->setFixedWidth(120); emanuel@673: updatesButton->setFixedHeight(80); rrenkert@584: updatesButton->setCheckable(true); rrenkert@584: updatesButton->setChecked(true); rrenkert@584: rrenkert@584: QToolButton *allInstallButton = new QToolButton; rrenkert@584: allInstallButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); rrenkert@584: allInstallButton->setIcon(QIcon(":/img/document-encrypt.png")); emanuel@673: allInstallButton->setIconSize(QSize(40, 40)); emanuel@659: allInstallButton->setText(tr("Trusted\ncertificates")); emanuel@663: allInstallButton->setFixedWidth(120); emanuel@673: allInstallButton->setFixedHeight(80); 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@673: allRemoveButton->setIconSize(QSize(40, 40)); emanuel@661: allRemoveButton->setText(tr("Revoked\ncertificates")); emanuel@663: allRemoveButton->setFixedWidth(120); emanuel@673: allRemoveButton->setFixedHeight(80); 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@673: infoButton->setIconSize(QSize(40, 40)); emanuel@659: infoButton->setText(tr("Information\nand help")); emanuel@663: infoButton->setFixedWidth(120); emanuel@673: infoButton->setFixedHeight(80); 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: rrenkert@652: /******************************** rrenkert@652: * The main pages. rrenkert@652: ********************************/ rrenkert@652: rrenkert@652: /******************************** rrenkert@652: * The updates page. rrenkert@652: ********************************/ rrenkert@652: QVBoxLayout *updatesMainLayout = new QVBoxLayout; rrenkert@584: mUpdatesPanel = new QScrollArea; rrenkert@652: QScrollArea *updatesContent = new QScrollArea; rrenkert@652: // updatesContent->setFrameShape(QFrame::NoFrame); rrenkert@584: mUpdatesWidget = new QWidget; rrenkert@652: rrenkert@652: /* The updates header */ rrenkert@584: QHBoxLayout *updatesHeaderLayout = new QHBoxLayout; rrenkert@584: QVBoxLayout *updatesHeaderTextLayout = new QVBoxLayout; rrenkert@652: QVBoxLayout *updatesHeaderButtonLayout = new QVBoxLayout; rrenkert@652: QHBoxLayout *updatesHeaderActionLayout = new QHBoxLayout; rrenkert@652: QHBoxLayout *updatesHeaderSearchLayout = new QHBoxLayout; rrenkert@584: rrenkert@628: mUpdatesHeader = rrenkert@652: new QLabel("

" + tr("Updates (%1/%2)").arg(0).arg(0)+ "

"); rrenkert@628: mLastCertUpdate = emanuel@659: new QLabel(tr("Last update of certificates: %1").arg("")); rrenkert@628: mLastSWupdate = emanuel@659: new QLabel(tr("Last update of TrustBridge: %1").arg("")); rrenkert@652: QLabel *updatesTip = emanuel@659: new QLabel(tr("You should apply the following changes to your root certificates:")); rrenkert@652: rrenkert@628: updatesHeaderTextLayout->addWidget(mUpdatesHeader); rrenkert@628: updatesHeaderTextLayout->addWidget(mLastCertUpdate); rrenkert@628: updatesHeaderTextLayout->addWidget(mLastSWupdate); rrenkert@652: updatesHeaderTextLayout->addSpacing(10); rrenkert@652: updatesHeaderTextLayout->addWidget(updatesTip); rrenkert@584: emanuel@659: QPushButton *searchUpdates = new QPushButton(tr("Check for updates")); emanuel@673: searchUpdates->setIcon(QIcon(":/img/edit-find.png")); rrenkert@652: QPushButton *quitButton = new QPushButton(tr("Quit without saving")); emanuel@673: quitButton->setIcon(QIcon(":/img/application-exit.png")); emanuel@659: QPushButton *installButton = new QPushButton(tr("Install updates")); rrenkert@652: #ifdef Q_OS_WIN rrenkert@652: if (is_admin()) { rrenkert@652: QIcon uacShield = QApplication::style()->standardIcon(QStyle::SP_VistaShield); rrenkert@652: installButton->setIcon(uacShield); rrenkert@652: } rrenkert@652: #else emanuel@673: installButton->setIcon(QIcon(":/img/view-refresh.png")); rrenkert@652: #endif rrenkert@652: connect(quitButton, SIGNAL(clicked()), this, SLOT(closeApp())); andre@654: connect(installButton, SIGNAL(clicked()), this, SLOT(checkAndInstallCerts())); rrenkert@628: connect(searchUpdates, SIGNAL(clicked()), this, SLOT(checkUpdates())); rrenkert@652: rrenkert@652: updatesHeaderActionLayout->addWidget(installButton); rrenkert@652: updatesHeaderActionLayout->addWidget(quitButton); rrenkert@652: updatesHeaderSearchLayout->insertStretch(0, 1); rrenkert@652: updatesHeaderSearchLayout->addWidget(searchUpdates); rrenkert@652: rrenkert@652: updatesHeaderButtonLayout->addLayout(updatesHeaderSearchLayout); rrenkert@652: updatesHeaderButtonLayout->addLayout(updatesHeaderActionLayout); rrenkert@652: rrenkert@584: updatesHeaderLayout->addLayout(updatesHeaderTextLayout); rrenkert@584: updatesHeaderLayout->insertStretch(1, 10); rrenkert@652: updatesHeaderLayout->addLayout(updatesHeaderButtonLayout); rrenkert@584: rrenkert@652: /* The central panels. */ rrenkert@584: QVBoxLayout *updatesCenterLayout = new QVBoxLayout; rrenkert@584: QHBoxLayout *updatesNewLayout = new QHBoxLayout; rrenkert@584: QHBoxLayout *updatesRemoveLayout = new QHBoxLayout; rrenkert@584: QHBoxLayout *updatesManualLayout = new QHBoxLayout; rrenkert@628: mUpdatesNewCertificates = rrenkert@584: new QLabel("

" + emanuel@659: tr("Install new trusted certificates (%1/%2)").arg(0).arg(0) + rrenkert@584: "

"); emanuel@659: mUpdatesDetailsNew = new QPushButton(tr("Show details")); rrenkert@652: connect(mUpdatesDetailsNew, rrenkert@584: SIGNAL(clicked()), rrenkert@584: this, rrenkert@584: SLOT(toggleUpdatesNew())); rrenkert@628: updatesNewLayout->addWidget(mUpdatesNewCertificates); rrenkert@652: updatesNewLayout->addWidget(mUpdatesDetailsNew); rrenkert@584: updatesNewLayout->insertStretch(2, 10); rrenkert@584: mUpdatesNew = new CertificateListWidget(this); rrenkert@628: connect(mUpdatesNew, SIGNAL(certListChanged(int)), rrenkert@628: this, SLOT(listChanged(int))); rrenkert@584: mUpdatesNew->hide(); rrenkert@584: rrenkert@628: mUpdatesRemoveCertificates = rrenkert@584: new QLabel("

" + emanuel@661: tr("Remove revoked certificates (%1/%2)").arg(0).arg(0) + rrenkert@584: "

"); emanuel@659: mUpdatesDetailsRemove = new QPushButton(tr("Show details")); rrenkert@652: connect(mUpdatesDetailsRemove, rrenkert@584: SIGNAL(clicked()), rrenkert@584: this, rrenkert@584: SLOT(toggleUpdatesRemove())); rrenkert@628: updatesRemoveLayout->addWidget(mUpdatesRemoveCertificates); rrenkert@652: updatesRemoveLayout->addWidget(mUpdatesDetailsRemove); rrenkert@584: updatesRemoveLayout->insertStretch(2, 10); rrenkert@584: mUpdatesRemove = new CertificateListWidget(this); rrenkert@642: connect(mUpdatesRemove, SIGNAL(certListChanged(int)), rrenkert@642: this, SLOT(listChanged(int))); rrenkert@584: mUpdatesRemove->hide(); rrenkert@584: rrenkert@628: mUpdatesManualCertificates = rrenkert@584: new QLabel("

" + emanuel@659: tr("Manually changed certificates (%1)").arg(0) + rrenkert@584: "

"); emanuel@659: mUpdatesDetailsManual = new QPushButton(tr("Show details")); rrenkert@652: connect(mUpdatesDetailsManual, rrenkert@584: SIGNAL(clicked()), rrenkert@584: this, rrenkert@584: SLOT(toggleUpdatesManual())); rrenkert@628: updatesManualLayout->addWidget(mUpdatesManualCertificates); rrenkert@652: updatesManualLayout->addWidget(mUpdatesDetailsManual); rrenkert@584: updatesManualLayout->insertStretch(2, 10); rrenkert@584: mUpdatesManual = new CertificateListWidget(this); rrenkert@584: mUpdatesManual->hide(); rrenkert@640: connect(mUpdatesManual, SIGNAL(certChanged(bool, const Certificate&)), rrenkert@640: this, SLOT(removeFromManual(bool, const Certificate&))); andre@692: connect(mUpdatesManual, SIGNAL(certListChanged(int)), andre@692: this, SLOT(listChanged(int))); rrenkert@584: rrenkert@640: updatesNewLayout->setAlignment(Qt::AlignTop); rrenkert@640: updatesRemoveLayout->setAlignment(Qt::AlignTop); rrenkert@640: updatesManualLayout->setAlignment(Qt::AlignTop); rrenkert@640: updatesCenterLayout->addLayout(updatesNewLayout); rrenkert@652: updatesCenterLayout->addWidget(mUpdatesNew); rrenkert@640: updatesCenterLayout->addLayout(updatesRemoveLayout); rrenkert@652: updatesCenterLayout->addWidget(mUpdatesRemove); rrenkert@640: updatesCenterLayout->addLayout(updatesManualLayout); rrenkert@652: updatesCenterLayout->addWidget(mUpdatesManual); rrenkert@652: updatesCenterLayout->addStretch(1); rrenkert@584: rrenkert@652: updatesCenterLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); rrenkert@652: mUpdatesWidget->setLayout(updatesCenterLayout); rrenkert@652: updatesContent->setWidget(mUpdatesWidget); rrenkert@584: rrenkert@652: updatesMainLayout->addLayout(updatesHeaderLayout); rrenkert@652: updatesMainLayout->addWidget(updatesContent); rrenkert@652: mUpdatesPanel->setLayout(updatesMainLayout); rrenkert@652: rrenkert@652: /********************************* rrenkert@652: * Panel for trusted certificates. rrenkert@652: *********************************/ rrenkert@584: mInstallPanel = new QScrollArea; rrenkert@584: rrenkert@584: QVBoxLayout *installPanelLayout = new QVBoxLayout; rrenkert@584: QVBoxLayout *installHeaderLayout = new QVBoxLayout; rrenkert@584: QVBoxLayout *installCenterLayout = new QVBoxLayout; rrenkert@584: rrenkert@584: QLabel *installHeaderLabel = emanuel@659: new QLabel("

" + tr("Trusted certificates") + "

"); emanuel@659: QLabel *installHeaderText = new QLabel(tr("The following list of trusted root" emanuel@659: " certificates is managed by the BSI. The BSI validates independently the" emanuel@659: " authenticity, security and actuality of these certificates.")); rrenkert@584: installHeaderLayout->addWidget(installHeaderLabel); rrenkert@584: installHeaderLayout->addWidget(installHeaderText); rrenkert@584: rrenkert@584: QLabel *installCenterText = new QLabel(tr("Please choose the certificates" emanuel@659: " you want to trust or untrust. TrustBridge will install these certificates for your" emanuel@659: " secure communication for email and internet.")); rrenkert@584: installCenterLayout->addWidget(installCenterText); rrenkert@584: mInstallList = new CertificateListWidget(this); rrenkert@640: connect(mInstallList, SIGNAL(certChanged(bool, const Certificate&)), rrenkert@640: this, SLOT(toggleInManual(bool, const Certificate&))); rrenkert@584: rrenkert@584: installPanelLayout->addLayout(installHeaderLayout); rrenkert@584: installPanelLayout->addLayout(installCenterLayout); rrenkert@584: installPanelLayout->addWidget(mInstallList); rrenkert@584: mInstallPanel->setLayout(installPanelLayout); rrenkert@584: rrenkert@652: /********************************** andre@656: * Panel for certificates to be removed. rrenkert@652: **********************************/ rrenkert@584: mRemovePanel = new QScrollArea; rrenkert@584: QVBoxLayout *removePanelLayout = new QVBoxLayout; rrenkert@584: QVBoxLayout *removeHeaderLayout = new QVBoxLayout; rrenkert@584: QVBoxLayout *removeCenterLayout = new QVBoxLayout; rrenkert@584: rrenkert@584: QLabel *removeHeaderLabel = emanuel@661: new QLabel("

" + tr("Revoked certificates") + "

"); emanuel@661: QLabel *removeHeaderText = new QLabel(tr("Certificates can be corrupted" emanuel@661: " or stolen and misused in many ways. Therefore the BSI recommends" emanuel@661: " to remove all revoked certificates from your system.")); rrenkert@584: removeHeaderLayout->addWidget(removeHeaderLabel); rrenkert@584: removeHeaderLayout->addWidget(removeHeaderText); rrenkert@584: emanuel@661: QLabel *removeCenterText = new QLabel(tr("The follwing unsecure certificates were" emanuel@661: " revoked by the BSI. Already uninstalled certificates cannot be reinstalled." emanuel@661: " It is recommended that you select all certificates to uninstall if you still" emanuel@661: " have revoked certificates installed.")); rrenkert@584: removeCenterLayout->addWidget(removeCenterText); rrenkert@628: mRemoveList = new CertificateListWidget(this); rrenkert@640: connect(mRemoveList, SIGNAL(certChanged(bool, const Certificate&)), rrenkert@640: this, SLOT(toggleInManual(bool, const Certificate&))); rrenkert@584: rrenkert@584: removePanelLayout->addLayout(removeHeaderLayout); rrenkert@584: removePanelLayout->addLayout(removeCenterLayout); rrenkert@628: removePanelLayout->addWidget(mRemoveList); rrenkert@584: mRemovePanel->setLayout(removePanelLayout); rrenkert@584: rrenkert@652: /********************************** rrenkert@652: * The info panel. rrenkert@652: **********************************/ rrenkert@584: mInfoPanel = new QScrollArea; rrenkert@584: rrenkert@643: QVBoxLayout *infoPanelLayout = new QVBoxLayout; rrenkert@584: QHBoxLayout *infoHeaderLayout = new QHBoxLayout; rrenkert@584: QVBoxLayout *infoHeaderTextLayout = new QVBoxLayout; rrenkert@584: QVBoxLayout *infoCenterLayout = new QVBoxLayout; rrenkert@584: rrenkert@584: QImage *infoLogoImage = new QImage(":/img/logo.png"); rrenkert@584: QLabel *infoLogo = new QLabel; rrenkert@584: infoLogo->setBackgroundRole(QPalette::Base); rrenkert@584: infoLogo->setPixmap(QPixmap::fromImage(*infoLogoImage)); rrenkert@584: QLabel *infoTitle = new QLabel("

" + tr("TrustBridge") + "

"); rrenkert@584: QString infoVersion = tr("Version: "); rrenkert@584: infoVersion.append(QApplication::applicationVersion()); rrenkert@584: QLabel *appVersion = new QLabel(infoVersion); rrenkert@584: appVersion->setTextInteractionFlags( rrenkert@584: Qt::TextSelectableByMouse | rrenkert@584: Qt::TextSelectableByKeyboard); rrenkert@584: rrenkert@584: QFrame *infoHeaderSeparator = new QFrame(); rrenkert@584: infoHeaderSeparator->setFrameShape(QFrame::HLine); rrenkert@584: infoHeaderSeparator->setFrameShadow(QFrame::Sunken); rrenkert@584: rrenkert@584: infoHeaderTextLayout->addWidget(infoTitle); rrenkert@584: infoHeaderTextLayout->addWidget(appVersion); rrenkert@584: infoHeaderLayout->addWidget(infoLogo); rrenkert@584: infoHeaderLayout->addLayout(infoHeaderTextLayout); rrenkert@584: infoHeaderLayout->insertStretch(2, 10); rrenkert@584: rrenkert@584: QLabel *textDesc = new QLabel(tr("TrustBridge is a root certificate" rrenkert@584: " installer for Windows and Linux.")); rrenkert@584: textDesc->setTextInteractionFlags( rrenkert@584: Qt::TextSelectableByMouse | rrenkert@584: Qt::TextSelectableByKeyboard); rrenkert@584: QLabel *textManage = new QLabel(tr("The root certificate lists are managed" rrenkert@584: " by the German " rrenkert@584: "Federal Office for Information Security (BSI).\n\n")); rrenkert@584: textManage->setTextInteractionFlags( rrenkert@584: Qt::TextBrowserInteraction | rrenkert@584: Qt::TextSelectableByKeyboard); rrenkert@584: QLabel *textDevel = new QLabel(tr("The software was developed by the companies" rrenkert@584: " Intevation GmbH and " rrenkert@584: " DN-Systems GmbH,
" rrenkert@584: " contracted by the German Federal Office for Information Security (BSI).\n\n")); rrenkert@584: textDevel->setTextInteractionFlags( rrenkert@584: Qt::TextBrowserInteraction | rrenkert@584: Qt::TextSelectableByKeyboard); rrenkert@584: QLabel *textLicense = new QLabel(tr("TrustBridge is Free Software licensed" rrenkert@584: " under GNU GPL v2+.\n\nCopyright (C) 2014 by Bundesamt für Sicherheit" rrenkert@584: " in der Informationstechnik")); rrenkert@584: textLicense->setTextInteractionFlags( rrenkert@584: Qt::TextSelectableByMouse | rrenkert@584: Qt::TextSelectableByKeyboard); rrenkert@584: rrenkert@584: infoCenterLayout->addWidget(infoHeaderSeparator); rrenkert@584: infoCenterLayout->addWidget(textDesc); rrenkert@584: infoCenterLayout->addWidget(textManage); rrenkert@584: infoCenterLayout->addWidget(textDevel); rrenkert@584: infoCenterLayout->addWidget(textLicense); rrenkert@584: infoCenterLayout->insertSpacing(2, 10); rrenkert@584: infoCenterLayout->insertSpacing(4, 10); rrenkert@584: infoCenterLayout->insertSpacing(6, 10); rrenkert@584: infoCenterLayout->insertStretch(8, 10); rrenkert@584: rrenkert@584: infoPanelLayout->addLayout(infoHeaderLayout); rrenkert@584: infoPanelLayout->addLayout(infoCenterLayout); rrenkert@584: mInfoPanel->setLayout(infoPanelLayout); rrenkert@584: rrenkert@652: /******************************** rrenkert@652: * The main layout for pages. rrenkert@652: ********************************/ rrenkert@584: mInstallPanel->hide(); rrenkert@584: mRemovePanel->hide(); rrenkert@584: mInfoPanel->hide(); rrenkert@584: containerLayout->addWidget(mUpdatesPanel); rrenkert@584: containerLayout->addWidget(mInstallPanel); rrenkert@584: containerLayout->addWidget(mRemovePanel); rrenkert@584: containerLayout->addWidget(mInfoPanel); 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: { rrenkert@628: mUpdatesHeader->setText("

" + tr("Updates (%1/%2)") rrenkert@628: .arg(mUpdatesRemove->selectedCertCount() + mUpdatesNew->selectedCertCount()) rrenkert@628: .arg(mUpdatesRemove->certificates().size() + mUpdatesNew->certificates().size()) + rrenkert@628: "

"); rrenkert@628: mUpdatesNewCertificates->setText("

" + emanuel@659: tr("Install new trusted certificates (%1/%2)") rrenkert@628: .arg(mUpdatesNew->selectedCertCount()) rrenkert@628: .arg(mUpdatesNew->certificates().size()) + rrenkert@628: "

"); rrenkert@628: mUpdatesRemoveCertificates->setText("

" + emanuel@661: tr("Remove revoked certificates (%1/%2)") rrenkert@628: .arg(mUpdatesRemove->selectedCertCount()) rrenkert@628: .arg(mUpdatesRemove->certificates().size()) + rrenkert@628: "

"); rrenkert@628: } rrenkert@628: rrenkert@189: void MainWindow::loadCertificateList() rrenkert@189: { andre@389: /* TODO: if nothing is available (neither old nor new) add some progress andre@389: * indication */ rrenkert@628: mInstallList->clear(); andre@684: mRemoveList->clear(); rrenkert@628: mUpdatesNew->clear(); rrenkert@628: mUpdatesRemove->clear(); rrenkert@445: QList newInstallCerts; rrenkert@445: QList newRemoveCerts; rrenkert@445: QList oldInstallCerts; rrenkert@445: QList 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); rrenkert@640: mInstallList->addCertificate(cert, state); rrenkert@267: } rrenkert@267: else { rrenkert@445: oldRemoveCerts.append(cert); rrenkert@640: mRemoveList->addCertificate(cert, state, !state); 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); rrenkert@640: mInstallList->addCertificate(cert, state); rrenkert@445: } rrenkert@445: else { rrenkert@445: // Is a brand new certificate rrenkert@445: newInstallCerts.append(cert); andre@687: mUpdatesNew->addCertificate(cert, state, true, andre@687: tr("install"), tr("ignore")); 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. rrenkert@640: mRemoveList->addCertificate(cert, state, !state); 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); rrenkert@640: mUpdatesRemove->addCertificate(cert, state); rrenkert@445: } rrenkert@267: } rrenkert@267: } andre@691: } andre@692: andre@691: mLastCertUpdate->setText(tr("Last update of certificates: %1") rrenkert@628: .arg(mInstalledList.date().toString())); rrenkert@628: mUpdatesManualCertificates->setText("

" + emanuel@659: tr("Manually changed certificates (%1)").arg(0) + rrenkert@628: "

"); andre@692: listChanged(0); 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@389: if (mCurState == NewListAvailable) { andre@389: mCurState = NothingChanged; andre@389: mCurMessage = QString(); andre@389: andre@389: QString listFileName = mSettings.value("List/available").toString(); andre@389: QDateTime listFileDate = mSettings.value("List/availableDate").toDateTime(); andre@389: andre@389: mSettings.remove("List/available"); andre@389: mSettings.remove("List/availableDate"); andre@389: andre@389: if (listFileName.isEmpty() || !listFileDate.isValid()) { andre@389: qWarning() << "Error accessing settings"; andre@389: return; /* Try again with next check */ andre@389: } andre@389: andre@389: mSettings.setValue("List/installed", listFileName); andre@389: mSettings.setValue("List/installedDate", listFileDate); rrenkert@480: mInstalledList = mListToInstall; rrenkert@480: mListToInstall = CertificateList(); andre@389: } 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: 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: aheinecke@365: InstallWrapper *instWrap = new InstallWrapper(this, andre@393: mListToInstall.isValid() ? andre@393: mListToInstall.fileName() : andre@393: mInstalledList.fileName(), aheinecke@365: choices); 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)) { rrenkert@640: mUpdatesManual->addCertificate(cert, state); rrenkert@640: } rrenkert@640: else { rrenkert@640: mUpdatesManual->removeCertificate(cert); rrenkert@640: } rrenkert@640: rrenkert@640: mUpdatesManualCertificates->setText("

" + emanuel@661: tr("Manually changed certificates (%1)") rrenkert@640: .arg(mUpdatesManual->certificates().size()) + rrenkert@640: "

"); rrenkert@640: } rrenkert@640: rrenkert@640: void MainWindow::removeFromManual(bool state, const Certificate &cert) rrenkert@640: { rrenkert@640: mUpdatesManual->removeCertificate(cert); rrenkert@640: rrenkert@640: mUpdatesManualCertificates->setText("

" + emanuel@661: tr("Manually changed certificates (%1)") rrenkert@640: .arg(mUpdatesManual->certificates().size()) + rrenkert@640: "

"); 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: { rrenkert@447: qApp->quit(); rrenkert@447: } rrenkert@584: andre@609: void MainWindow::checkAndInstallCerts() andre@609: { andre@609: /* Checking before opening the dialog should be cheaper */ andre@609: QList 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@609: } andre@654: rrenkert@584: void MainWindow::togglePages(int button) rrenkert@584: { andre@657: mUpdatesPanel->hide(); rrenkert@584: mInstallPanel->hide(); rrenkert@584: mRemovePanel->hide(); rrenkert@584: mInfoPanel->hide(); rrenkert@584: switch(button) { rrenkert@584: case 0: mUpdatesPanel->show(); break; rrenkert@584: case 1: mInstallPanel->show(); break; rrenkert@584: case 2: mRemovePanel->show(); break; rrenkert@584: case 3: mInfoPanel->show(); break; rrenkert@584: default: mUpdatesPanel->show(); break; rrenkert@584: } rrenkert@584: return; rrenkert@584: } rrenkert@584: rrenkert@584: void MainWindow::toggleUpdatesNew() { rrenkert@584: if (!mUpdatesNew->isVisible()) { emanuel@659: mUpdatesDetailsNew->setText(tr("Hide details")); rrenkert@584: mUpdatesNew->show(); rrenkert@653: mUpdatesNew->setSelected(0); rrenkert@584: } rrenkert@584: else { rrenkert@653: mUpdatesNew->hide(); emanuel@659: mUpdatesDetailsNew->setText(tr("Show details")); rrenkert@653: QSize old = mUpdatesWidget->size(); rrenkert@584: mUpdatesWidget->resize(old.width(), old.height() - mUpdatesNew->height()); rrenkert@584: } rrenkert@584: } rrenkert@584: rrenkert@584: void MainWindow::toggleUpdatesRemove() { rrenkert@584: if (!mUpdatesRemove->isVisible()) { emanuel@659: mUpdatesDetailsRemove->setText(tr("Hide details")); rrenkert@584: mUpdatesRemove->show(); rrenkert@653: mUpdatesRemove->setSelected(0); rrenkert@584: } rrenkert@584: else { rrenkert@653: mUpdatesRemove->hide(); emanuel@659: mUpdatesDetailsRemove->setText(tr("Show details")); rrenkert@653: QSize old = mUpdatesWidget->size(); rrenkert@584: mUpdatesWidget->resize(old.width(), old.height() - mUpdatesRemove->height()); rrenkert@584: } rrenkert@584: } rrenkert@584: rrenkert@584: void MainWindow::toggleUpdatesManual() { rrenkert@584: if (!mUpdatesManual->isVisible()) { emanuel@659: mUpdatesDetailsManual->setText(tr("Hide details")); rrenkert@584: mUpdatesManual->show(); rrenkert@653: mUpdatesManual->setSelected(0); rrenkert@584: } rrenkert@584: else { emanuel@659: mUpdatesDetailsManual->setText(tr("Show details")); rrenkert@653: mUpdatesManual->hide(); rrenkert@653: QSize old = mUpdatesWidget->size(); rrenkert@640: mUpdatesWidget->resize(old.width(), old.height() - mUpdatesManual->height()); 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@690: return; andre@690: } andre@690: return closeApp(); andre@690: }