view ui/mainwindow.h @ 1373:00fcb9c4d16b

(issue179) Handle SW verify failures and try to redownload the update
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 24 Nov 2014 16:46:08 +0100
parents 23df332b2a4c
children
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.
 */
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

/**
 * @file mainwindow.h
 * @brief Main UI controller
 */

#include <QMainWindow>
#include <QSettings>
#include <QMenuBar>
#include <QListWidget>
#include <QTextEdit>
#include <QPushButton>
#include <QLabel>
#include <QCheckBox>
#include <QScrollArea>
#include <QProcess>
#include <QDateTime>

#include "downloader.h"
#include "certificatelist.h"
#include "certificatelistwidget.h"
#include "textoverlaybutton.h"
#include "trayicon.h"
class QMenu;
class QAction;
class QTimer;
class QPushButton;


/** @brief Main UI controller
 *
 * The MainWindow controls the logic of the Application
 * it is the central piece that controls the state and starts
 * updates / certificate installation.
 * It also controls the UI widgets for the various certificate lists.
 */
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    /**@brief create a new Main Window object
     *
     * In tray mode this window is not shown and only shows
     * notification messages if there is some actionable state
     * reached. If tray mode is true it also exits after
     * an update check.
     *
     * The sigDt parameter is used to determine if a software
     * update should be installed.
     *
     * @param[in] trayMode set the tray mode
     * @param[in] sigDt the datetime when the binary was signed.
     * */
    MainWindow(bool trayMode, const QDateTime& sigDt = QDateTime());

    /**@brief set the current message to be shown
     *
     * The message will be shown at intervals in the system tray
     * or as a messagebox if no stystemtray is available.
     *
     * @param [in] message The message to show.
     */
    void setMessage(const QString message) {mCurMessage = message;}
    /**@brief accessor for the current message.
     *
     * @returns the currently shown message.*/
    QString getMessage() {return mCurMessage;}

    /**
     * @enum CurrentState
     * @brief The internal state of the application
     */
    enum CurrentState {
         /*! A new certificate list is available. */
        NewListAvailable,
         /*! A new Software is avaialable. */
        NewSoftwareAvailable,
         /*! Download in progress. */
        DownloadingSW,
         /*! An error happened on the last connection. */
        TransferError,
         /*! Update was susccessfull but nothing new is available. */
        NothingChanged
    };

    /**
     * @enum LongTimeErrors
     * @brief Errors that should be stored and only shown after some time has elapsed.
     */
    enum LongTimeErrors {
        /*! The downloaded Software was invalid. */
        lteInvalidSoftware,
        /*! The SSL certificate of the download server was wrong. */
        lteInvalidCertificate,
        /*! The downloaded Certificate List was invalid. */
        lteInvalidList,
        /*! No connection to the server could be established. */
        lteNoConnection
    };

    /** @brief accessor for the current state. */
    CurrentState getState() {return mCurState;}
    /** @brief set the current state. */
    void setState(CurrentState state) {mCurState = state;}

private slots:
    /** @brief Shows the current message to the user. */
    void showMessage();
    /** @brief User has clicked on the message notification. */
    void iconActivated(QSystemTrayIcon::ActivationReason reason);
    /** @brief Check if new updates are available.
     *
     * Wether the software should be downloaded or not is determined by
     * the mDownloadSWAccepted value.
     */
    void checkUpdates();
    /**@brief parse a new certificate list and update the UI*/
    void handleNewList(const QString& fileName, const QDateTime& modDate);
    /**@brief handle a Software update, update state and inform the user */
    void handleNewSW(const QString& fileName, const QDateTime& modDate);
    /**@brief an error occured while downloading.*/
    void downloaderError(const QString &message, SSLConnection::ErrorCode error);
    /** @brief Trigger the appropiate action depending on the state */
    void messageClicked();
    /** @brief An error occured during certificate installation .*/
    void installerError(const QString& errMsg);
    /** @brief Certificate installation was successful. */
    void installerSuccess();
    /** @brief Install the currently selected certificates */
    void installCerts();
    /** @brief Handle a toggle action in the manual certificate list */
    void toggleInManual(bool state, const Certificate &cert);
    /** @brief Remove a certificate from the manual list. */
    void removeFromManual(bool state, const Certificate &cert);
    /** @brief Restart the application */
    void updaterFinished(int exitCode, QProcess::ExitStatus status);

    void togglePages(int button);
    void toggleUpdatesNew();
    void toggleUpdatesRemove();
    void toggleUpdatesManual();

    /** Reflect change list states in the UI
     *
     * This slot should be called each time the contents or selection
     * state of one of the certificate lists change to update the
     * UI elements accordingly.
     *
     * @param[in] selected unused. */
    void listChanged(int selected);

    /** @brief check for running software that needs to close before installing
     *
     * This function calls installCerts if no software is running otherwise
     * it informs the user about the software that still needs to be closed.
     */
    void checkAndInstallCerts();

    /** @brief get the last modified date on the download server for
     * the current version.
     *
     * After the initial installation this function can be used to
     * determine the DateTime that corresponds to the currently installed
     * version on the download server.
     *
     * Calls setLastModifiedSWDate on success. Otherwise downloaderError
     * is triggered. */
    void getLastModForCurrentVersion();

    /** @brief set the last modified software date/time
     *
     * The last modifiedSWDate is the corresponding last modified
     * timestamp from the download server vor the currently installed version.
     */
    void setLastModifiedSWDate(const QDateTime &date);

    /** @brief saves the currently unselected certificates
     *
     * This creates / updates a qsettings section that
     * [unselected] that contains the certificates that
     * were unselected previously.
     *
     * Unselected are certificates that are unchecked
     * in the certListWidget
     *
     * Returns false on error.
     */
    bool saveUnselectedCertificates(QStringList unselected);

    /** @brief loads previously unselected certificates from settings
     *
     * The certificates are strored in the list mPreviouslyUnselected.
     *
     * On error mPreviouslyUnselected is empty after this call.
     */
    void loadUnselectedCertificates();

    /** @brief log / store a successful downloader run
     *
     * A downloader run is successful if the finished signal
     * is emited and the state is not TransferError
     */
    void updateCheckSuccess();

    /** @brief open the manual in an external browser window
     */
    void showHelp();

    /** @brief open the proxy settings dialog */
    void showProxySettings();

protected:
    virtual void closeEvent(QCloseEvent *event);

protected slots:
    /** @brief cleanup and close the main window
     *
     * Perform a clean exit (saving state etc.) and close
     * the application */
    virtual void closeApp();

    /* @brief Execute the file fileName to install the softwareupdate.
     *
     * Once the installer process is started this function terminates
     * the application. */
    void installNewSW(const QString& fileName, const QDateTime& modDate);

    /** @brief show an error message
     *
     * This is a wrapper around QMessageBox to allow for central
     * styling of error messages.
     */
    void showErrorMessage(const QString &msg);

signals:
    /** @brief emits the changecount as a string when it changes */
    void changesChanged(const QString& cnt);

private:
    /** @brief Get a installer file name that can be shown to a user.
     *
     * This copys the real file to a temporary location with a user
     * visible localized file name. Does error Handling.
     *
     * @param [in] realFileName The original file name.
     *
     * @returns a null string in case on errors. The new filename
     * otherwise.
     */
    QString getPrettyInstallerName(QString realFileName);

    /** @brief the combined number of changes made in all lists */
    int changeCount();

    /** @brief use this to set the change count */
    void setChangeCount(int cnt);

    /** @brief check the integrity of available certificate lists.
     *
     * Note: Do not use this as a local trust check as this only works on
     * FileNames where the underlying files can change. This
     * is just meant to check if the downloaded data was somehow
     * removed or corrupted. It also initializes mListToInstall
     * and mInstalledList.
     */
    void verifyListData();

    /** @brief check the integrity of available software updates.
     *
     * Note: Do not use this as a local trust check as this only works on
     * FileNames where the underlying files can change. This
     * is just meant to check if the downloaded data was somehow
     * removed or corrupted.
     */
    void verifySWData();

    /** @brief note an long time error in the settings and show a message.
     *
     * Saves a software verify error in the settings and notifies the
     * user if necessary.
     *
     * @param [in] lte The error to handle.
     * @param [in] reset weather or not the error count should be reset.
     *
     **/
    void handleLTE(LongTimeErrors lte, bool reset = false);

    /** @brief schedule an update check retry or close the application.
     *
     * An update check retry is scheduled base on getNextUpdateInterval.
     * If getNextUpdateInterval returns a negative value the application
     * is closed if the parameter close is true.
     *
     * This function also increases the failed connection count.
     */
    void scheduleFailureRetryOrClose(bool close);

    /** @brief note a verify error in the settings and show a message
     *
     * Saves a software verify error in the settings and notifies the
     * user if necessary.*/
    void swVerifyError();

    void createTrayIcon();
    void createActions();
    void loadCertificateList();

    /** @brief UI setup */
    void setupGUI();

    /** @brief create and set up the info widget (accessible via button panel) */
    QWidget *createInfoWidget();
    /** @brief create and set up the updates widget (accessible via button panel) */
    QWidget *createUpdatesWidget();
    /** @brief create and set up the certifcates to install widget
     * (accessible via button panel) */
    QWidget *createInstallWidget();
    /** @brief create and set up the certifcates to remove widget
     * (accessible via button panel) */
    QWidget *createRemoveWidget();

    /** @brief true if the software is running in tray mode*/
    const bool mTrayMode;

    /** @brief The currently shown message */
    QString mCurMessage;
    /** @brief The version the Software thinks is installed */
    QString mInstalledSWVersion;
    /** @brief The certificate list the Software thinks is installed */
    QString mInstalledListVersion;

    QSettings mSettings;

    TrayIcon *mTrayIcon;
    QTimer *mMessageTimer;
    QMenu *mTrayMenu;
    QAction *mCheckUpdates;
    QAction *mQuitAction;
    CurrentState mCurState;
    QMenuBar *mMenuBar;
    QPushButton *mQuitButton;

    /* The current list that should be installed */
    CertificateList mListToInstall;
    /* The last list that we installed */
    CertificateList mInstalledList;
    /* Previously made "unselect" choices in the form of
     * base64lines with I:/R: prefix */
    QStringList mPreviouslyUnselected;

    QLabel *mCurrentListDate;
    QLabel *mNewListDate;

    QButtonGroup *mButtonGroup;
    QWidget *mUpdatesWidget;
    QWidget *mInstallWidget;
    QWidget *mRemoveWidget;
    QWidget *mInfoWidget;

    QLabel *mUpdatesHeader;
    QLabel *mUpdatesDetailsHeader;
    QLabel *mCertListVersion;
    QLabel *mCertListVersionContents;
    QLabel *mLastUpdateCheck;
    QLabel *mLastUpdateCheckContents;
    QLabel *mUpdatesNewCertificates;
    QLabel *mUpdatesRemoveCertificates;
    QLabel *mUpdatesManualCertificates;
    QLabel *mUpdatesTip;

    /* These are a bit of a pattern break, they should
     * be accessed over the according page widgets.
     *
     * They are initialized in the create*widget functions.*/
    CertificateListWidget *mUpdatesNew;
    CertificateListWidget *mUpdatesRemove;
    CertificateListWidget *mUpdatesManual;
    CertificateListWidget *mInstallList;
    CertificateListWidget *mRemoveList;

    QPushButton *mUpdatesDetailsNew;
    QPushButton *mUpdatesDetailsRemove;
    QPushButton *mUpdatesDetailsManual;

    QPushButton *mInstallButton;
    int mChangeCount;
    bool mManualDetailsShown;
    int mFailedConnections;
    QDateTime mSigDt;
    bool mDownloadSWAccepted;
};

#endif // MAINWINDOW_H

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