Mercurial > trustbridge
view ui/mainwindow.cpp @ 636:2fd4f9980a2a
Add test for authenticode verificate (binverify)
Still incomplete
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 23 Jun 2014 18:00:45 +0200 |
parents | 292c590ba9cb |
children | 129e611eaf50 |
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "mainwindow.h" #include <QDebug> #include <QProcess> #include <QProgressDialog> #include <QMessageBox> #include <QSystemTrayIcon> #include <QAction> #include <QDialog> #include <QDir> #include <QMenu> #include <QApplication> #include <QFile> #include <QTimer> #include <QHBoxLayout> #include <QVBoxLayout> #include <QGroupBox> #include <QSplitter> #include <QLabel> #include <QImage> #include <QCheckBox> #include "certificatelist.h" #include "downloader.h" #include "helpdialog.h" #include "aboutdialog.h" #include "certificateitemdelegate.h" #include "separatoritemdelegate.h" #include "installwrapper.h" #include "util.h" #include "logging.h" #include "binverify.h" #include "processhelp.h" #include "processwaitdialog.h" // The amount of time in minutes stay silent if we have // something to say #define NAG_INTERVAL_MINUTES 70 #ifndef APPNAME #define APPNAME "TrustBridge" #endif #define SERVER_URL "https://files.intevation.de:443" #ifdef RELEASE_BUILD # define LIST_RESOURCE "/users/aheinecke/zertifikatsliste.txt" # define SW_RESOURCE "/users/aheinecke/TrustBridge.exe" # ifdef Q_OS_WIN # define SW_RESOURCE_VERSION "/users/aheinecke/TrustBridge-%1.exe" # else # define SW_RESOURCE_VERSION "/users/aheinecke/TrustBridge-%1.sh" # endif #else // RELEASE_BUILD # define LIST_RESOURCE "/users/aheinecke/development/zertifikatsliste.txt" # define SW_RESOURCE "/users/aheinecke/development/TrustBridge.exe" # ifdef Q_OS_WIN # define SW_RESOURCE_VERSION "/users/aheinecke/development/TrustBridge-development.exe" # else # define SW_RESOURCE_VERSION "/users/aheinecke/development/TrustBridge-development.sh" # endif #endif MainWindow::MainWindow(bool trayMode): mTrayMode(trayMode) { createActions(); createTrayIcon(); createMenuBar(); createContent(); resize(950, 540); qRegisterMetaType<SSLConnection::ErrorCode>("SSLConnection::ErrorCode"); qRegisterMetaType<Certificate::Status>("Certificate::Status"); connect(mTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); mMessageTimer = new QTimer(this); connect(mMessageTimer, SIGNAL(timeout()), this, SLOT(showMessage())); mMessageTimer->setInterval(NAG_INTERVAL_MINUTES * 60 * 1000); mMessageTimer->start(); checkUpdates(); loadUnselectedCertificates(); loadCertificateList(); if (!trayMode) { show(); } } void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { switch (reason) { case QSystemTrayIcon::Trigger: case QSystemTrayIcon::MiddleClick: showMessage(); break; case QSystemTrayIcon::DoubleClick: show(); break; default: ; } } void MainWindow::messageClicked() { if (mCurState == NewListAvailable) { show(); } if (mCurState == NewSoftwareAvailable) { verifySWData(); QString swFileName = mSettings.value("Software/available").toString(); if (swFileName.isEmpty()) { checkUpdates(true); mCurState = DownloadingSW; return; } installNewSW(swFileName, mSettings.value("Software/availableDate").toDateTime()); } } void MainWindow::showMessage() { if (mCurMessage.isEmpty()) { return; } if (mCurState == NewSoftwareAvailable || !isVisible()) { mTrayIcon->showMessage(QApplication::applicationName(), mCurMessage, QSystemTrayIcon::Information, 10000); mMessageTimer->start(); // Restart the timer so that we don't spam } } void MainWindow::verifyListData() { QString availableFileName = mSettings.value("List/available").toString(); QString installedFileName = mSettings.value("List/installed").toString(); if (!availableFileName.isEmpty()) { mListToInstall.readList(availableFileName.toLocal8Bit().constData()); if (!mListToInstall.isValid()) { mCurState = TransferError; // Probably a bug when Qt fileName is encoded and cFileName // fails because of this. This needs a unit test! // Maybe check that the file is in our data directory QFile::remove(availableFileName); mSettings.remove("List/available"); mSettings.remove("List/availableDate"); } } else { // Make sure the available notation is also removed mSettings.remove("List/available"); mSettings.remove("List/availableDate"); } if (!installedFileName.isEmpty()) { mInstalledList.readList(installedFileName.toLocal8Bit().constData()); if (!mInstalledList.isValid()) { // Probably a bug when Qt fileName is encoded and cFileName // fails because of this. This needs a unit test! // Maybe check that the file is in our data directory QFile::remove(installedFileName); mSettings.remove("List/installed"); mSettings.remove("List/installedDate"); } } else { mSettings.remove("List/installed"); mSettings.remove("List/installedDate"); } } void MainWindow::verifySWData() { QString swFileName = mSettings.value("Software/available").toString(); if (swFileName.isEmpty()) { mSettings.remove("Software/availableDate"); return; } QFileInfo fi(swFileName); if (!fi.exists()) { mSettings.remove("Software/available"); mSettings.remove("Software/availableDate"); qDebug() << "Software does not yet exist."; return; } if (!fi.isExecutable()) { qWarning() << "Downloaded file: " << swFileName << " is not executable."; QFile::remove(swFileName); mSettings.remove("Software/available"); mSettings.remove("Software/availableDate"); return; } bin_verify_result verifyResult = verify_binary(swFileName.toUtf8().constData(), swFileName.toUtf8().size()); qDebug() << "Binary verify result: " << verifyResult; if (verifyResult != VerifyValid) { qDebug() << "Failed to verify downloaded data."; QFile::remove(swFileName); mSettings.remove("Software/available"); mSettings.remove("Software/availableDate"); return; } } void MainWindow::handleNewList(const QString& fileName, const QDateTime& modDate) { mSettings.setValue("List/available", fileName); mSettings.setValue("List/availableDate", modDate); verifyListData(); if (!mListToInstall.isValid()) { /* Downloader provided invalid files */ /* TODO: Error count. Error handling. Otherwise * we can go into an endless loop here */ /* Retry the download again in 10 - 20 minutes */ QTimer::singleShot(600000 + (qrand() % 60000), this, SLOT(checkUpdates())); } else { mCurMessage = tr("An updated certificate list is available. Click here to install."); setState(NewListAvailable); showMessage(); loadCertificateList(); } } void MainWindow::handleNewSW(const QString& fileName, const QDateTime& modDate) { mCurMessage = tr("An update for %1 is available.\n" "Click here to download and install the update.").arg( QApplication::applicationName()); setState(NewSoftwareAvailable); mSettings.setValue("Software/available", fileName); mSettings.setValue("Software/availableDate", modDate); mSettings.sync(); showMessage(); } void MainWindow::installNewSW(const QString& fileName, const QDateTime& modDate) { QFileInfo instProcInfo = QFileInfo(fileName); QString filePath = QDir::toNativeSeparators(instProcInfo.absoluteFilePath()); if (verify_binary(filePath.toUtf8().constData(), filePath.toUtf8().size()) != VerifyValid) { qDebug() << "Invalid software. Not installing"; return; } QFileInfo fi(QCoreApplication::applicationFilePath()); QDir installDir = fi.absoluteDir(); #ifdef WIN32 QString parameters = QString::fromLatin1("/S /UPDATE=1 /D=") + installDir.path().replace("/", "\\") + ""; SHELLEXECUTEINFOW shExecInfo; memset (&shExecInfo, 0, sizeof(SHELLEXECUTEINFOW)); shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW); shExecInfo.lpFile = reinterpret_cast<LPCWSTR> (filePath.utf16()); shExecInfo.lpParameters = reinterpret_cast<LPCWSTR> (parameters.utf16()); // shExecInfo.fMask = SEE_MASK_NOASYNC; shExecInfo.nShow = SW_SHOWDEFAULT; if (!is_admin()) { shExecInfo.lpVerb = L"open"; } else { shExecInfo.lpVerb = L"runas"; } qDebug() << "Starting process: " << filePath << " with arguments: " << parameters; if (!ShellExecuteExW(&shExecInfo)) { /* Execution failed, maybe the user aborted the UAC check? */ char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); qDebug() << "Failed to start process: " << qerrmsg; setState(NewSoftwareAvailable); return; } #else /* WIN32 */ QStringList parameters; parameters << "/S" << "/UPDATE=1" << QString::fromLatin1("/D=%1").arg(installDir.path()); qDebug() << "Starting process " << filePath << " args: " << parameters; if (!QProcess::startDetached(filePath, parameters)) { qDebug() << "Failed to start process."; return; } #endif /* Installer process should now be running. We exit */ closeApp(); } void MainWindow::checkUpdates(bool downloadSW) { verifyListData(); if (!mSettings.contains("Software/installedDate") || mSettings.value("Software/installedVersion").toString() != QApplication::applicationVersion()) { /* This should only happen on initial startup and after an update has * been installed */ getLastModForCurrentVersion(); return; } QDateTime listInstalledLastMod = mSettings.value("List/installedDate").toDateTime(); QDateTime swInstalledLastMod = mSettings.value("Software/installedDate").toDateTime(); QString listResource = QString::fromLatin1(LIST_RESOURCE); QString swResource = QString::fromLatin1(SW_RESOURCE); #ifndef RELEASE_BUILD /* Use this for testing to specify another file name for updates */ listResource = mSettings.value("List/resource", listResource).toString(); swResource = mSettings.value("Software/resource", swResource).toString(); #endif Downloader* downloader = new Downloader(this, QString::fromLatin1(SERVER_URL), QByteArray(), swInstalledLastMod, listInstalledLastMod, swResource, listResource, downloadSW); connect(downloader, SIGNAL(newListAvailable(const QString&, const QDateTime&)), this, SLOT(handleNewList(const QString&, const QDateTime&))); if (!downloadSW) { connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)), this, SLOT(handleNewSW(const QString&, const QDateTime&))); } else { connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)), this, SLOT(installNewSW(const QString&, const QDateTime&))); } connect(downloader, SIGNAL(finished()), downloader, SLOT(deleteLater())); connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)), this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode))); downloader->start(); } void MainWindow::getLastModForCurrentVersion() { QString softwareVersion = QString::fromLatin1(SW_RESOURCE_VERSION).arg( QApplication::applicationVersion()); qDebug() << softwareVersion; QString listResource = QString::fromLatin1(LIST_RESOURCE); Downloader* downloader = new Downloader(this, QString::fromLatin1(SERVER_URL), QByteArray(), QDateTime::currentDateTime(), QDateTime::currentDateTime(), softwareVersion, listResource, false); connect(downloader, SIGNAL(finished()), downloader, SLOT(deleteLater())); connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)), this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode))); connect(downloader, SIGNAL(lastModifiedDate(const QDateTime&)), this, SLOT(setLastModifiedSWDate(const QDateTime&))); downloader->start(); } void MainWindow::setLastModifiedSWDate(const QDateTime &date) { mSettings.beginGroup("Software"); mSettings.setValue("installedDate", date); mSettings.setValue("installedVersion", QApplication::applicationVersion()); mSettings.endGroup(); checkUpdates(); } void MainWindow::downloaderError(const QString &message, SSLConnection::ErrorCode error) { /* TODO logging and handle error according to a plan */ mCurMessage = message; showMessage(); setState(TransferError); } void MainWindow::createActions() { mCheckUpdates = new QAction(tr("Check for Updates"), this); connect(mCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdates())); mQuitAction = new QAction(tr("Quit"), this); connect(mQuitAction, SIGNAL(triggered()), qApp, SLOT(quit())); } void MainWindow::createTrayIcon() { QIcon trayImg(":/img/tray_22.png"); mTrayMenu = new QMenu(this); mTrayMenu->addAction(mCheckUpdates); mTrayMenu->addAction(mQuitAction); mTrayIcon = new QSystemTrayIcon(this); mTrayIcon->setContextMenu(mTrayMenu); mTrayIcon->setIcon(trayImg); setWindowIcon(trayImg); mTrayIcon->show(); mTrayIcon->setToolTip(tr("TrustBridge")); connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked())); } void MainWindow::createMenuBar() { mMenuBar = new QMenuBar(this); QMenu *mMenu = new QMenu(tr("Menu"), mMenuBar); mMenuBar->addMenu(mMenu); QAction *update = mMenu->addAction(tr("Force Update")); mMenu->addSeparator(); QAction *help = mMenu->addAction(tr("Help")); QAction *about = mMenu->addAction(tr("About")); mMenu->addSeparator(); QAction *quit = mMenu->addAction(tr("Quit")); connect(update, SIGNAL(triggered()), this, SLOT(checkUpdates())); connect(help, SIGNAL(triggered()), this, SLOT(showHelp())); connect(about, SIGNAL(triggered()), this, SLOT(showAbout())); connect(quit, SIGNAL(triggered()), this, SLOT(closeApp())); setMenuBar(mMenuBar); } void MainWindow::createContent() { // Create a central widget containing the main layout. QWidget *base = new QWidget; // Layouts and Container QHBoxLayout *mainLayout = new QHBoxLayout; QVBoxLayout *infoLayout = new QVBoxLayout; QVBoxLayout *certLayout = new QVBoxLayout; QHBoxLayout *detailLayout = new QHBoxLayout; QVBoxLayout *detailLabelLayout = new QVBoxLayout; QVBoxLayout *detailContentLayout = new QVBoxLayout; QHBoxLayout *headerLayout = new QHBoxLayout; QVBoxLayout *headerTextLayout = new QVBoxLayout; QHBoxLayout *bottomLayout = new QHBoxLayout; QVBoxLayout *settingsLayout = new QVBoxLayout; QVBoxLayout *listInfoLayout = new QVBoxLayout; // The certificate list QGroupBox *certBox = new QGroupBox(tr("Managed Certificates")); mCertListWidget = new QListWidget; connect(mCertListWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(showDetails(QListWidgetItem*))); certLayout->addWidget(mCertListWidget); mCurrentListDate = new QLabel(tr("Current List Date: %1").arg("")); mNewListDate = new QLabel(""); listInfoLayout->addWidget(mCurrentListDate); listInfoLayout->addWidget(mNewListDate); certLayout->addLayout(listInfoLayout); certBox->setLayout(certLayout); // The header (icon, about text) QImage *logoImage = new QImage(":/img/logo.png"); QLabel *logo = new QLabel; logo->setBackgroundRole(QPalette::Base); logo->setPixmap(QPixmap::fromImage(*logoImage)); QLabel *title = new QLabel("<h2>" + QString::fromLatin1(APPNAME) + "</h2>"); QLabel *subTitle = new QLabel("This Software installs and removes Certificates"); headerTextLayout->addWidget(title); headerTextLayout->addWidget(subTitle); headerLayout->addWidget(logo); headerLayout->addLayout(headerTextLayout); headerLayout->setStretch(0, 0); headerLayout->setStretch(1, 10); // The settings. QGroupBox *settingsBox = new QGroupBox(tr("Settings")); mAutoUpdateOption = new QCheckBox(tr("Autoupdate")); mAutoStartOption = new QCheckBox(tr("Autostart")); settingsLayout->addWidget(mAutoUpdateOption); settingsLayout->addWidget(mAutoStartOption); settingsBox->setLayout(settingsLayout); connect(mAutoUpdateOption, SIGNAL(stateChanged(int)), this, SLOT(saveAutoUpdate(int))); connect(mAutoStartOption, SIGNAL(stateChanged(int)), this, SLOT(saveAutoStart(int))); mSettings.beginGroup("settings"); bool autoUpdate = mSettings.value("autoupdate", false).toBool(); bool autoStart = mSettings.value("autostart", true).toBool(); mSettings.endGroup(); mAutoUpdateOption->setCheckState(autoUpdate ? Qt::Checked : Qt::Unchecked); mAutoStartOption->setCheckState(autoStart ? Qt::Checked : Qt::Unchecked); // The buttons. bottomLayout->setAlignment(Qt::AlignBottom); installButton = new QPushButton(tr("Install selected")); installButton->setFixedHeight(80); connect(installButton, SIGNAL(clicked()), this, SLOT(resizeButtons())); connect(installButton, SIGNAL(clicked()), this, SLOT(checkAndInstallCerts())); quitButton = new QPushButton(tr("Quit")); quitButton->setFixedHeight(20); connect(quitButton, SIGNAL(clicked()), this, SLOT(closeApp())); bottomLayout->insertStretch(0, 10); bottomLayout->addWidget(installButton); bottomLayout->setAlignment(installButton, Qt::AlignBottom); bottomLayout->addWidget(quitButton); bottomLayout->setAlignment(quitButton, Qt::AlignBottom); #ifdef Q_OS_WIN if (is_admin()) { QIcon uacShield = QApplication::style()->standardIcon(QStyle::SP_VistaShield); installButton->setIcon(uacShield); } #endif // The certificate details QGroupBox *detailBox = new QGroupBox(tr("Details")); QLabel *subjectCN = new QLabel(tr("Subject Common Name:")); QLabel *subjectOU = new QLabel(tr("Subject Organisation:")); QLabel *issuerCN = new QLabel(tr("Issuer Common Name:")); QLabel *issuerOU = new QLabel(tr("Issuer Organisation:")); QLabel *validFrom = new QLabel(tr("Valid from:")); QLabel *validTo = new QLabel(tr("Valid to:")); QLabel *fingerprint = new QLabel(tr("Fingerprint:")); detailLabelLayout->addWidget(subjectCN); detailLabelLayout->addWidget(subjectOU); detailLabelLayout->addWidget(issuerCN); detailLabelLayout->addWidget(issuerOU); detailLabelLayout->addWidget(validFrom); detailLabelLayout->addWidget(validTo); detailLabelLayout->addWidget(fingerprint); mSubjectCN = new QLabel(tr("")); mSubjectO = new QLabel(tr("")); mIssuerCN = new QLabel(tr("")); mIssuerO = new QLabel(tr("")); mValidFrom = new QLabel(tr("")); mValidTo = new QLabel(tr("")); mFingerprint = new QLabel(tr("")); mFingerprint->setFont(QFont("DejaVu Sans Mono")); detailContentLayout->addWidget(mSubjectCN); detailContentLayout->addWidget(mSubjectO); detailContentLayout->addWidget(mIssuerCN); detailContentLayout->addWidget(mIssuerO); detailContentLayout->addWidget(mValidFrom); detailContentLayout->addWidget(mValidTo); detailContentLayout->addWidget(mFingerprint); detailLayout->addLayout(detailLabelLayout); detailLayout->addLayout(detailContentLayout); detailBox->setLayout(detailLayout); infoLayout->addSpacing(20); infoLayout->addLayout(headerLayout); infoLayout->addWidget(detailBox); infoLayout->addWidget(settingsBox); infoLayout->addLayout(bottomLayout); mainLayout->addWidget(certBox); mainLayout->addLayout(infoLayout); mainLayout->setStretchFactor(certBox, 37); mainLayout->setStretchFactor(infoLayout, 63); // QMainWindow allready has a layout. All child layouts and widgets are // managed in the central widget. base->setLayout(mainLayout); setCentralWidget(base); } void MainWindow::loadCertificateList() { mCertListWidget->clear(); int i = 0; /* TODO: if nothing is available (neither old nor new) add some progress * indication */ QList<Certificate> newInstallCerts; QList<Certificate> newRemoveCerts; QList<Certificate> oldInstallCerts; QList<Certificate> oldRemoveCerts; if (mListToInstall.getCertificates().isEmpty()) { // No new list available, add old certificates. foreach (const Certificate &cert, mInstalledList.getCertificates()) { if (cert.isInstallCert()) { oldInstallCerts.append(cert); } else { oldRemoveCerts.append(cert); } } // Set the date of the old list. mCurrentListDate->setText(tr("Current List Date: %1") .arg(mInstalledList.date().toString())); } else { // Sort and filter both lists. foreach (const Certificate &cert, mListToInstall.getCertificates()) { if (cert.isInstallCert()) { // Certificate with status "install". if (mInstalledList.getCertificates().contains(cert)) { // Was in the old list. oldInstallCerts.append(cert); } else { // Is a brand new certificate newInstallCerts.append(cert); } } else { // Certificate with status "remove". if (mInstalledList.getCertificates().contains(cert)) { // Was in the old list. oldRemoveCerts.append(cert); } else { // Was in the old list with status "install" and now has the // status "remove". newRemoveCerts.append(cert); } } } mCurrentListDate->setText(tr("Current List Date: %1") .arg(mInstalledList.date().toString())); mNewListDate->setText(tr("New List Date: %1").arg(mListToInstall.date().toString())); } // Add separators and certificates to list widget. if (!newInstallCerts.isEmpty()) { mCertListWidget->addItem(createSeparator(tr("New certificates to install"), i++)); foreach (const Certificate &cert, newInstallCerts) { mCertListWidget->addItem(createListItem(cert, Certificate::InstallNew, i++)); } } if (!newRemoveCerts.isEmpty()) { mCertListWidget->addItem(createSeparator(tr("New certificates to remove"), i++)); foreach (const Certificate &cert, newRemoveCerts) { mCertListWidget->addItem(createListItem(cert, Certificate::RemoveNew, i++)); } } if (!oldInstallCerts.isEmpty()) { mCertListWidget->addItem(createSeparator(tr("Old certificates to install"), i++)); foreach (const Certificate &cert, oldInstallCerts) { mCertListWidget->addItem(createListItem(cert, Certificate::InstallOld, i++)); } } if (!oldRemoveCerts.isEmpty()) { mCertListWidget->addItem(createSeparator(tr("Old certificates to remove"), i++)); foreach (const Certificate &cert, oldRemoveCerts) { mCertListWidget->addItem(createListItem(cert, Certificate::RemoveOld, i++)); } } } QListWidgetItem* MainWindow::createSeparator(const QString &text, int index) { SeparatorItemDelegate *separatorDelegate = new SeparatorItemDelegate(); QListWidgetItem *separator = new QListWidgetItem(text); mCertListWidget->setItemDelegateForRow(index, separatorDelegate); separator->setFlags(separator->flags() ^ Qt::ItemIsUserCheckable); return separator; } QListWidgetItem* MainWindow::createListItem(const Certificate &certificate, Certificate::Status status, int index) { CertificateItemDelegate *certDelegate = new CertificateItemDelegate(); QListWidgetItem* item = new QListWidgetItem(certificate.shortDescription()); item->setData(CertificateItemDelegate::DataRole, QVariant::fromValue(certificate)); item->setData(CertificateItemDelegate::StatusRole, status); if (!mPreviouslyUnselected.contains(certificate.base64Line()) && status == Certificate::RemoveOld) { item->setFlags(item->flags() ^ Qt::ItemIsUserCheckable); } else { Qt::CheckState checkedState = mPreviouslyUnselected.contains(certificate.base64Line()) ? Qt::Unchecked : Qt::Checked; item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setCheckState(checkedState); } mCertListWidget->setItemDelegateForRow(index, certDelegate); return item; } void MainWindow::showHelp() { qDebug() << "show helpdialog"; HelpDialog *help = new HelpDialog(this); help->show(); } void MainWindow::showAbout() { qDebug() << "show aboutdialog"; AboutDialog *about = new AboutDialog(this); about->show(); } void MainWindow::showDetails(QListWidgetItem *item) { if (item == NULL) { return; } Certificate cert = item->data(CertificateItemDelegate::DataRole).value<Certificate>(); mSubjectCN->setText(cert.subjectCN()); mSubjectO->setText(cert.subjectO()); mIssuerCN->setText(cert.issuerCN()); mIssuerO->setText(cert.issuerO()); mValidFrom->setText(cert.validFrom().toString()); mValidTo->setText(cert.validTo().toString()); mFingerprint->setText(cert.fingerprint()); } void MainWindow::resizeButtons() { installButton->setFixedHeight(20); quitButton->setFixedHeight(80); } void MainWindow::installerError(const QString& errMsg) { QMessageBox::warning(this, tr("Error executing update"), errMsg); } void MainWindow::installerSuccess() { if (mCurState == NewListAvailable) { mCurState = NothingChanged; mCurMessage = QString(); QString listFileName = mSettings.value("List/available").toString(); QDateTime listFileDate = mSettings.value("List/availableDate").toDateTime(); mSettings.remove("List/available"); mSettings.remove("List/availableDate"); if (listFileName.isEmpty() || !listFileDate.isValid()) { qWarning() << "Error accessing settings"; return; /* Try again with next check */ } mSettings.setValue("List/installed", listFileName); mSettings.setValue("List/installedDate", listFileDate); mInstalledList = mListToInstall; mListToInstall = CertificateList(); } loadCertificateList(); } void MainWindow::installCerts() { QStringList choices; for (int i = 0; i < mCertListWidget->count(); i++) { QListWidgetItem *item = mCertListWidget->item(i); if (item->checkState() == Qt::Checked) { choices << item->data(CertificateItemDelegate::DataRole).value<Certificate>().base64Line(); continue; } QString certLine = item->data(CertificateItemDelegate::DataRole).value<Certificate>().base64Line(); if (certLine.startsWith("I:")) { certLine[0] = 'R'; choices << certLine; } } QProgressDialog *progress = new QProgressDialog(this); progress->setWindowModality(Qt::WindowModal); progress->setLabelText(tr("Installing certificates...")); progress->setCancelButton(0); progress->setRange(0,0); progress->setMinimumDuration(0); progress->show(); InstallWrapper *instWrap = new InstallWrapper(this, mListToInstall.isValid() ? mListToInstall.fileName() : mInstalledList.fileName(), choices); /* Clean up object and progress dialog */ connect(instWrap, SIGNAL(finished()), instWrap, SLOT(deleteLater())); connect(instWrap, SIGNAL(finished()), progress, SLOT(deleteLater())); connect(instWrap, SIGNAL(finished()), progress, SLOT(cancel())); connect(instWrap, SIGNAL(installationSuccessful()), this, SLOT(installerSuccess())); connect(instWrap, SIGNAL(error(const QString &)), this, SLOT(installerError(const QString &))); instWrap->start(); if (!saveUnselectedCertificates()) { qWarning() << "Failed to save previosly unselected certificates."; } } void MainWindow::loadUnselectedCertificates() { mPreviouslyUnselected.clear(); mSettings.beginGroup("unselected"); QStringList keys = mSettings.allKeys(); foreach (const QString &key, keys) { mPreviouslyUnselected << mSettings.value(key, QString()).toString(); } mSettings.endGroup(); } bool MainWindow::saveUnselectedCertificates() { mPreviouslyUnselected.clear(); mSettings.beginGroup("unselected"); mSettings.remove(""); /* Clears old choices */ for (int i = 0; i < mCertListWidget->count(); i++) { QListWidgetItem *item = mCertListWidget->item(i); if (item->checkState() != Qt::Checked && (item->flags() & Qt::ItemIsUserCheckable)) { QString key = QString::fromLatin1("cert%1").arg(i); QString value = item->data(CertificateItemDelegate::DataRole).value<Certificate>().base64Line(); mSettings.setValue(key, value); mPreviouslyUnselected << value; } } mSettings.endGroup(); mSettings.sync(); return mSettings.status() == QSettings::NoError; } void MainWindow::saveAutoUpdate(int state) { mSettings.beginGroup("settings"); mSettings.setValue("autoupdate", state != Qt::Unchecked); mSettings.endGroup(); } void MainWindow::saveAutoStart(int state) { mSettings.beginGroup("settings"); mSettings.setValue("autostart", state != Qt::Unchecked); mSettings.endGroup(); } void MainWindow::closeApp() { saveUnselectedCertificates(); qApp->quit(); } void MainWindow::checkAndInstallCerts() { /* Checking before opening the dialog should be cheaper */ QList<int> pids = ProcessHelp::getProcessesIdForName("firefox"); pids.append(ProcessHelp::getProcessesIdForName("thunderbird")); if (pids.isEmpty()) { installCerts(); return; } QStringList pNames; pNames << "firefox" << "thunderbird"; ProcessWaitDialog *waitDialog = new ProcessWaitDialog(this, pNames); connect(waitDialog, SIGNAL(accepted()), this, SLOT(installCerts())); connect(waitDialog, SIGNAL(accepted()), waitDialog, SLOT(deleteLater())); waitDialog->exec(); return; }