File indexing completed on 2024-05-12 05:20:02

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     systemtrayicon.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-kleopatra.h>
0011 
0012 #include "systrayicon.h"
0013 
0014 #ifndef QT_NO_SYSTEMTRAYICON
0015 
0016 #include "kleopatraapplication.h"
0017 #include "mainwindow.h"
0018 
0019 #include <smartcard/readerstatus.h>
0020 
0021 #include <utils/clipboardmenu.h>
0022 
0023 #include <commands/decryptverifyclipboardcommand.h>
0024 #include <commands/encryptclipboardcommand.h>
0025 #include <commands/importcertificatefromclipboardcommand.h>
0026 #include <commands/learncardkeyscommand.h>
0027 #include <commands/setinitialpincommand.h>
0028 #include <commands/signclipboardcommand.h>
0029 
0030 #include <KAboutApplicationDialog>
0031 #include <KAboutData>
0032 #include <KActionMenu>
0033 #include <KLocalizedString>
0034 #include <QEventLoopLocker>
0035 #include <QIcon>
0036 
0037 #include <QAction>
0038 #include <QApplication>
0039 #include <QMenu>
0040 #include <QPointer>
0041 #include <QSignalBlocker>
0042 
0043 using namespace Kleo;
0044 using namespace Kleo::Commands;
0045 using namespace Kleo::SmartCard;
0046 
0047 class SysTrayIcon::Private
0048 {
0049     friend class ::SysTrayIcon;
0050     SysTrayIcon *const q;
0051 
0052 public:
0053     explicit Private(SysTrayIcon *qq);
0054     ~Private();
0055 
0056 private:
0057     void slotAbout()
0058     {
0059         if (!aboutDialog) {
0060             aboutDialog = new KAboutApplicationDialog(KAboutData::applicationData());
0061             aboutDialog->setAttribute(Qt::WA_DeleteOnClose);
0062         }
0063 
0064         if (aboutDialog->isVisible()) {
0065             aboutDialog->raise();
0066         } else {
0067             aboutDialog->show();
0068         }
0069     }
0070 
0071     void enableDisableActions()
0072     {
0073         openCertificateManagerAction.setEnabled(!q->mainWindow() || !q->mainWindow()->isVisible());
0074         setInitialPinAction.setEnabled(!firstCardWithNullPin.empty());
0075         learnCertificatesAction.setEnabled(anyCardCanLearnKeys);
0076 
0077         q->setAttentionWanted((!firstCardWithNullPin.empty() || anyCardCanLearnKeys) && !q->attentionWindow());
0078     }
0079 
0080     void slotSetInitialPin()
0081     {
0082         if (!firstCardWithNullPin.empty()) {
0083             auto cmd = new SetInitialPinCommand(firstCardWithNullPin);
0084             q->setAttentionWindow(cmd->dialog());
0085             startCommand(cmd);
0086         }
0087     }
0088 
0089     void slotLearnCertificates()
0090     {
0091         auto cmd = new LearnCardKeysCommand(GpgME::CMS);
0092         q->setAttentionWindow(cmd->dialog());
0093         startCommand(cmd);
0094     }
0095     void startCommand(Command *cmd)
0096     {
0097         Q_ASSERT(cmd);
0098         cmd->setParent(q->mainWindow());
0099         cmd->start();
0100     }
0101 
0102 private:
0103     std::string firstCardWithNullPin;
0104     bool anyCardCanLearnKeys = false;
0105     bool learningInProgress = false;
0106 
0107     QMenu menu;
0108     QAction openCertificateManagerAction;
0109     QAction configureAction;
0110     QAction aboutAction;
0111     QAction quitAction;
0112 
0113     ClipboardMenu clipboardMenu;
0114 
0115     QMenu cardMenu;
0116     QAction updateCardStatusAction;
0117     QAction setInitialPinAction;
0118     QAction learnCertificatesAction;
0119 
0120     QPointer<KAboutApplicationDialog> aboutDialog;
0121     QEventLoopLocker eventLoopLocker;
0122 };
0123 
0124 SysTrayIcon::Private::Private(SysTrayIcon *qq)
0125     : q(qq)
0126     , menu()
0127     , openCertificateManagerAction(i18nc("@action:inmenu", "&Open Certificate Manager..."), q)
0128     , configureAction(QIcon::fromTheme(QStringLiteral("configure")),
0129                       xi18nc("@action:inmenu", "&Configure <application>%1</application>...", KAboutData::applicationData().displayName()),
0130                       q)
0131     , aboutAction(QIcon::fromTheme(QStringLiteral("kleopatra")),
0132                   xi18nc("@action:inmenu", "&About <application>%1</application>...", KAboutData::applicationData().displayName()),
0133                   q)
0134     , quitAction(QIcon::fromTheme(QStringLiteral("application-exit")),
0135                  xi18nc("@action:inmenu", "&Shutdown <application>%1</application>", KAboutData::applicationData().displayName()),
0136                  q)
0137     , clipboardMenu(q)
0138     , cardMenu(i18nc("@title:menu", "SmartCard"))
0139     , updateCardStatusAction(i18nc("@action:inmenu", "Update Card Status"), q)
0140     , setInitialPinAction(i18nc("@action:inmenu", "Set NetKey v3 Initial PIN..."), q)
0141     , learnCertificatesAction(i18nc("@action:inmenu", "Learn NetKey v3 Card Certificates"), q)
0142     , aboutDialog()
0143 {
0144     q->setNormalIcon(QIcon::fromTheme(QStringLiteral("kleopatra")));
0145     q->setAttentionIcon(QIcon::fromTheme(QStringLiteral("auth-sim-locked")));
0146 
0147     KDAB_SET_OBJECT_NAME(menu);
0148     KDAB_SET_OBJECT_NAME(openCertificateManagerAction);
0149     KDAB_SET_OBJECT_NAME(configureAction);
0150     KDAB_SET_OBJECT_NAME(aboutAction);
0151     KDAB_SET_OBJECT_NAME(quitAction);
0152     KDAB_SET_OBJECT_NAME(clipboardMenu);
0153     KDAB_SET_OBJECT_NAME(cardMenu);
0154     KDAB_SET_OBJECT_NAME(setInitialPinAction);
0155     KDAB_SET_OBJECT_NAME(learnCertificatesAction);
0156 
0157     connect(&openCertificateManagerAction, SIGNAL(triggered()), qApp, SLOT(openOrRaiseMainWindow()));
0158     connect(&configureAction, SIGNAL(triggered()), qApp, SLOT(openOrRaiseConfigDialog()));
0159     connect(&aboutAction, SIGNAL(triggered()), q, SLOT(slotAbout()));
0160     connect(&quitAction, &QAction::triggered, QCoreApplication::instance(), &QCoreApplication::quit);
0161     connect(&updateCardStatusAction, &QAction::triggered, ReaderStatus::instance(), &ReaderStatus::updateStatus);
0162     connect(&setInitialPinAction, SIGNAL(triggered()), q, SLOT(slotSetInitialPin()));
0163     connect(&learnCertificatesAction, SIGNAL(triggered()), q, SLOT(slotLearnCertificates()));
0164 
0165     menu.addAction(&openCertificateManagerAction);
0166     menu.addAction(&configureAction);
0167     menu.addAction(&aboutAction);
0168     menu.addSeparator();
0169     menu.addMenu(clipboardMenu.clipboardMenu()->menu());
0170     menu.addSeparator();
0171     menu.addMenu(&cardMenu);
0172     cardMenu.addAction(&updateCardStatusAction);
0173     cardMenu.addAction(&setInitialPinAction);
0174     cardMenu.addAction(&learnCertificatesAction);
0175     menu.addSeparator();
0176     menu.addAction(&quitAction);
0177 
0178     q->setContextMenu(&menu);
0179     clipboardMenu.setMainWindow(q->mainWindow());
0180 }
0181 
0182 SysTrayIcon::Private::~Private()
0183 {
0184 }
0185 
0186 SysTrayIcon::SysTrayIcon(QObject *p)
0187     : SystemTrayIcon(p)
0188     , d(new Private(this))
0189 {
0190     slotEnableDisableActions();
0191 }
0192 
0193 SysTrayIcon::~SysTrayIcon()
0194 {
0195 }
0196 
0197 MainWindow *SysTrayIcon::mainWindow() const
0198 {
0199     return static_cast<MainWindow *>(SystemTrayIcon::mainWindow());
0200 }
0201 
0202 QDialog *SysTrayIcon::attentionWindow() const
0203 {
0204     return static_cast<QDialog *>(SystemTrayIcon::attentionWindow());
0205 }
0206 
0207 void SysTrayIcon::doActivated()
0208 {
0209     if (const QWidget *const aw = attentionWindow())
0210         if (aw->isVisible()) {
0211             return; // ignore clicks while an attention window is open.
0212         }
0213     if (!d->firstCardWithNullPin.empty()) {
0214         d->slotSetInitialPin();
0215     } else if (d->anyCardCanLearnKeys) {
0216         d->slotLearnCertificates();
0217     } else {
0218         // Toggle visibility of MainWindow
0219         KleopatraApplication::instance()->toggleMainWindowVisibility();
0220     }
0221 }
0222 
0223 void SysTrayIcon::setFirstCardWithNullPin(const std::string &serialNumber)
0224 {
0225     if (d->firstCardWithNullPin == serialNumber) {
0226         return;
0227     }
0228     d->firstCardWithNullPin = serialNumber;
0229     slotEnableDisableActions();
0230 }
0231 
0232 void SysTrayIcon::setAnyCardCanLearnKeys(bool on)
0233 {
0234     if (d->anyCardCanLearnKeys == on || d->learningInProgress) {
0235         return;
0236     }
0237     d->anyCardCanLearnKeys = on;
0238     slotEnableDisableActions();
0239 }
0240 
0241 void SysTrayIcon::slotEnableDisableActions()
0242 {
0243     d->enableDisableActions();
0244 }
0245 
0246 /* We need this as the readerstatus might update even
0247  * while the loading is in progress. */
0248 void SysTrayIcon::setLearningInProgress(bool value)
0249 {
0250     if (value) {
0251         setAnyCardCanLearnKeys(false);
0252     }
0253     d->learningInProgress = value;
0254 }
0255 
0256 #include "moc_systrayicon.cpp"
0257 
0258 #endif // QT_NO_SYSTEMTRAYICON