1 /* -*- mode: c++; c-basic-offset:4 -*-
2 systemtrayicon.cpp
3
4 This file is part of Kleopatra, the KDE keymanager
5 SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include <config-kleopatra.h>
11
12 #include "systrayicon.h"
13
14 #ifndef QT_NO_SYSTEMTRAYICON
15
16 #include "mainwindow.h"
17 #include "kleopatraapplication.h"
18
19 #include <smartcard/readerstatus.h>
20
21 #include <utils/clipboardmenu.h>
22
23 #include <commands/importcertificatefromclipboardcommand.h>
24 #include <commands/encryptclipboardcommand.h>
25 #include <commands/signclipboardcommand.h>
26 #include <commands/decryptverifyclipboardcommand.h>
27 #include <commands/setinitialpincommand.h>
28 #include <commands/learncardkeyscommand.h>
29
30 #include <QIcon>
31 #include <KLocalizedString>
32 #include <KAboutApplicationDialog>
33 #include <KAboutData>
34 #include <KActionMenu>
35 #include <QEventLoopLocker>
36
37 #include <QMenu>
38 #include <QAction>
39 #include <QApplication>
40 #include <QClipboard>
41 #include <QPointer>
42 #include <QSignalBlocker>
43
44
45 using namespace Kleo;
46 using namespace Kleo::Commands;
47 using namespace Kleo::SmartCard;
48
49 class SysTrayIcon::Private
50 {
51 friend class ::SysTrayIcon;
52 SysTrayIcon *const q;
53 public:
54 explicit Private(SysTrayIcon *qq);
55 ~Private();
56
57 private:
slotAbout()58 void slotAbout()
59 {
60 if (!aboutDialog) {
61 aboutDialog = new KAboutApplicationDialog(KAboutData::applicationData());
62 aboutDialog->setAttribute(Qt::WA_DeleteOnClose);
63 }
64
65 if (aboutDialog->isVisible()) {
66 aboutDialog->raise();
67 } else {
68 aboutDialog->show();
69 }
70 }
71
enableDisableActions()72 void enableDisableActions()
73 {
74 //work around a Qt bug (seen with Qt 4.4.0, Windows): QClipBoard->mimeData() triggers QClipboard::changed(),
75 //triggering slotEnableDisableActions again
76 const QSignalBlocker blocker(QApplication::clipboard());
77 openCertificateManagerAction.setEnabled(!q->mainWindow() || !q->mainWindow()->isVisible());
78 setInitialPinAction.setEnabled(!firstCardWithNullPin.empty());
79 learnCertificatesAction.setEnabled(anyCardCanLearnKeys);
80
81 q->setAttentionWanted((!firstCardWithNullPin.empty() || anyCardCanLearnKeys) && !q->attentionWindow());
82 }
83
slotSetInitialPin()84 void slotSetInitialPin()
85 {
86 if (!firstCardWithNullPin.empty()) {
87 auto cmd = new SetInitialPinCommand(firstCardWithNullPin);
88 q->setAttentionWindow(cmd->dialog());
89 startCommand(cmd);
90 }
91 }
92
slotLearnCertificates()93 void slotLearnCertificates()
94 {
95 auto cmd = new LearnCardKeysCommand(GpgME::CMS);
96 q->setAttentionWindow(cmd->dialog());
97 startCommand(cmd);
98 }
startCommand(Command * cmd)99 void startCommand(Command *cmd)
100 {
101 Q_ASSERT(cmd);
102 cmd->setParent(q->mainWindow());
103 cmd->start();
104 }
105
106 private:
107 std::string firstCardWithNullPin;
108 bool anyCardCanLearnKeys = false;
109 bool learningInProgress = false;
110
111 QMenu menu;
112 QAction openCertificateManagerAction;
113 QAction configureAction;
114 QAction aboutAction;
115 QAction quitAction;
116
117 ClipboardMenu clipboardMenu;
118
119 QMenu cardMenu;
120 QAction updateCardStatusAction;
121 QAction setInitialPinAction;
122 QAction learnCertificatesAction;
123
124 QPointer<KAboutApplicationDialog> aboutDialog;
125 QEventLoopLocker eventLoopLocker;
126 };
127
Private(SysTrayIcon * qq)128 SysTrayIcon::Private::Private(SysTrayIcon *qq)
129 : q(qq),
130 menu(),
131 openCertificateManagerAction(i18n("&Open Certificate Manager..."), q),
132 configureAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("&Configure %1...", KAboutData::applicationData().componentName()), q),
133 aboutAction(QIcon::fromTheme(QStringLiteral("kleopatra")), i18n("&About %1...", KAboutData::applicationData().componentName()), q),
134 quitAction(QIcon::fromTheme(QStringLiteral("application-exit")),i18n("&Shutdown Kleopatra"), q),
135 clipboardMenu(q),
136 cardMenu(i18n("SmartCard")),
137 updateCardStatusAction(i18n("Update Card Status"), q),
138 setInitialPinAction(i18n("Set NetKey v3 Initial PIN..."), q),
139 learnCertificatesAction(i18n("Learn NetKey v3 Card Certificates"), q),
140 aboutDialog()
141 {
142 q->setNormalIcon(QIcon::fromTheme(QStringLiteral("kleopatra")));
143 q->setAttentionIcon(QIcon::fromTheme(QStringLiteral("auth-sim-locked")));
144
145 KDAB_SET_OBJECT_NAME(menu);
146 KDAB_SET_OBJECT_NAME(openCertificateManagerAction);
147 KDAB_SET_OBJECT_NAME(configureAction);
148 KDAB_SET_OBJECT_NAME(aboutAction);
149 KDAB_SET_OBJECT_NAME(quitAction);
150 KDAB_SET_OBJECT_NAME(clipboardMenu);
151 KDAB_SET_OBJECT_NAME(cardMenu);
152 KDAB_SET_OBJECT_NAME(setInitialPinAction);
153 KDAB_SET_OBJECT_NAME(learnCertificatesAction);
154
155 connect(&openCertificateManagerAction, SIGNAL(triggered()), qApp, SLOT(openOrRaiseMainWindow()));
156 connect(&configureAction, SIGNAL(triggered()), qApp, SLOT(openOrRaiseConfigDialog()));
157 connect(&aboutAction, SIGNAL(triggered()), q, SLOT(slotAbout()));
158 connect(&quitAction, &QAction::triggered, QCoreApplication::instance(), &QCoreApplication::quit);
159 connect(&updateCardStatusAction, &QAction::triggered, ReaderStatus::instance(), &ReaderStatus::updateStatus);
160 connect(&setInitialPinAction, SIGNAL(triggered()), q, SLOT(slotSetInitialPin()));
161 connect(&learnCertificatesAction, SIGNAL(triggered()), q, SLOT(slotLearnCertificates()));
162
163 connect(QApplication::clipboard(), SIGNAL(changed(QClipboard::Mode)),
164 q, SLOT(slotEnableDisableActions()));
165
166 menu.addAction(&openCertificateManagerAction);
167 menu.addAction(&configureAction);
168 menu.addAction(&aboutAction);
169 menu.addSeparator();
170 menu.addMenu(clipboardMenu.clipboardMenu()->menu());
171 menu.addSeparator();
172 menu.addMenu(&cardMenu);
173 cardMenu.addAction(&updateCardStatusAction);
174 cardMenu.addAction(&setInitialPinAction);
175 cardMenu.addAction(&learnCertificatesAction);
176 menu.addSeparator();
177 menu.addAction(&quitAction);
178
179 q->setContextMenu(&menu);
180 clipboardMenu.setMainWindow(q->mainWindow());
181 }
182
~Private()183 SysTrayIcon::Private::~Private() {}
184
SysTrayIcon(QObject * p)185 SysTrayIcon::SysTrayIcon(QObject *p)
186 : SystemTrayIcon(p), d(new Private(this))
187 {
188 slotEnableDisableActions();
189 }
190
~SysTrayIcon()191 SysTrayIcon::~SysTrayIcon()
192 {
193 }
194
mainWindow() const195 MainWindow *SysTrayIcon::mainWindow() const
196 {
197 return static_cast<MainWindow *>(SystemTrayIcon::mainWindow());
198 }
199
attentionWindow() const200 QDialog *SysTrayIcon::attentionWindow() const
201 {
202 return static_cast<QDialog *>(SystemTrayIcon::attentionWindow());
203 }
204
doActivated()205 void SysTrayIcon::doActivated()
206 {
207 if (const QWidget *const aw = attentionWindow())
208 if (aw->isVisible()) {
209 return; // ignore clicks while an attention window is open.
210 }
211 if (!d->firstCardWithNullPin.empty()) {
212 d->slotSetInitialPin();
213 } else if (d->anyCardCanLearnKeys) {
214 d->slotLearnCertificates();
215 } else {
216 // Toggle visibility of MainWindow
217 KleopatraApplication::instance()->toggleMainWindowVisibility();
218 }
219 }
220
setFirstCardWithNullPin(const std::string & serialNumber)221 void SysTrayIcon::setFirstCardWithNullPin(const std::string &serialNumber)
222 {
223 if (d->firstCardWithNullPin == serialNumber) {
224 return;
225 }
226 d->firstCardWithNullPin = serialNumber;
227 slotEnableDisableActions();
228 }
229
setAnyCardCanLearnKeys(bool on)230 void SysTrayIcon::setAnyCardCanLearnKeys(bool on)
231 {
232 if (d->anyCardCanLearnKeys == on || d->learningInProgress) {
233 return;
234 }
235 d->anyCardCanLearnKeys = on;
236 slotEnableDisableActions();
237 }
238
slotEnableDisableActions()239 void SysTrayIcon::slotEnableDisableActions()
240 {
241 d->enableDisableActions();
242 }
243
244 /* We need this as the readerstatus might update even
245 * while the loading is in progress. */
setLearningInProgress(bool value)246 void SysTrayIcon::setLearningInProgress(bool value)
247 {
248 if (value) {
249 setAnyCardCanLearnKeys(false);
250 }
251 d->learningInProgress = value;
252 }
253
254 #include "moc_systrayicon.cpp"
255
256 #endif // QT_NO_SYSTEMTRAYICON
257