SVN_SILENT made messages (.desktop file) - always resolve ours
[kdepim.git] / kleopatra / main.cpp
blob4b909d553a1cd4eb52ba12497d95091650f6a247
1 /*
2 main.cpp
4 This file is part of Kleopatra, the KDE keymanager
5 Copyright (c) 2001,2002,2004,2008 Klar�vdalens Datakonsult AB
7 Kleopatra is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 Kleopatra is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 In addition, as a special exception, the copyright holders give
22 permission to link the code of this program with any edition of
23 the Qt library by Trolltech AS, Norway (or with modified versions
24 of Qt that use the same license as Qt), and distribute linked
25 combinations including the two. You must obey the GNU General
26 Public License in all respects for all of the code used other than
27 Qt. If you modify this file, you may extend this exception to
28 your version of the file, but you are not obligated to do so. If
29 you do not wish to do so, delete this exception statement from
30 your version.
33 #include <config-kleopatra.h>
35 #include "aboutdata.h"
36 #include "kleopatraapplication.h"
37 #include "mainwindow.h"
39 #include <kdelibs4configmigrator.h>
41 #include <commands/reloadkeyscommand.h>
42 #include <commands/selftestcommand.h>
44 #include <utils/gnupg-helper.h>
45 #include <utils/archivedefinition.h>
47 #ifdef HAVE_USABLE_ASSUAN
48 # include <uiserver/uiserver.h>
49 # include <uiserver/assuancommand.h>
50 # include <uiserver/echocommand.h>
51 # include <uiserver/decryptcommand.h>
52 # include <uiserver/verifycommand.h>
53 # include <uiserver/decryptverifyfilescommand.h>
54 # include <uiserver/decryptfilescommand.h>
55 # include <uiserver/verifyfilescommand.h>
56 # include <uiserver/prepencryptcommand.h>
57 # include <uiserver/prepsigncommand.h>
58 # include <uiserver/encryptcommand.h>
59 # include <uiserver/signcommand.h>
60 # include <uiserver/signencryptfilescommand.h>
61 # include <uiserver/selectcertificatecommand.h>
62 # include <uiserver/importfilescommand.h>
63 # include <uiserver/createchecksumscommand.h>
64 # include <uiserver/verifychecksumscommand.h>
65 #else
66 namespace Kleo
68 class UiServer;
70 #endif
72 #include <Libkleo/ChecksumDefinition>
74 #include "kleopatra_debug.h"
75 #include "kleopatra_options.h"
77 #include <KDBusService>
79 #include <KLocalizedString>
80 #include <kiconloader.h>
81 #include <QSplashScreen>
82 #include <kmessagebox.h>
84 #include <QTextDocument> // for Qt::escape
85 #include <QMessageBox>
86 #include <QTimer>
87 #include <QTime>
88 #include <QEventLoop>
89 #include <QThreadPool>
91 #include <gpgme++/global.h>
92 #include <gpgme++/error.h>
94 #include <boost/shared_ptr.hpp>
96 #include <cassert>
97 #include <iostream>
98 #include <QCommandLineParser>
100 using namespace boost;
102 static const int SPLASHSCREEN_TIMEOUT = 5000; // 5s
104 namespace
106 template <typename T>
107 boost::shared_ptr<T> make_shared_ptr(T *t)
109 return t ? boost::shared_ptr<T>(t) : boost::shared_ptr<T>();
113 static QPixmap UserIcon_nocached(const char *name)
115 // KIconLoader insists on caching all pixmaps. Since the splash
116 // screen is a particularly large 'icon' and used only once,
117 // caching is unneccesary and just hurts startup performance.
118 KIconLoader *const il = KIconLoader::global();
119 assert(il);
120 const QString iconPath = il->iconPath(QLatin1String(name), KIconLoader::User);
121 return iconPath.isEmpty() ? il->unknown() : QPixmap(iconPath);
124 #ifndef QT_NO_SPLASHSCREEN
125 class SplashScreen : public QSplashScreen
127 QBasicTimer m_timer;
128 public:
129 SplashScreen()
130 : QSplashScreen(UserIcon_nocached("kleopatra_splashscreen"), Qt::WindowStaysOnTopHint),
131 m_timer()
133 m_timer.start(SPLASHSCREEN_TIMEOUT, this);
136 protected:
137 void timerEvent(QTimerEvent *ev) Q_DECL_OVERRIDE {
138 if (ev->timerId() == m_timer.timerId())
140 m_timer.stop();
141 hide();
142 } else {
143 QSplashScreen::timerEvent(ev);
148 #else
149 class SplashScreen {};
150 #endif // QT_NO_SPLASHSCREEN
152 static bool selfCheck(SplashScreen &splash)
154 #ifndef QT_NO_SPLASHSCREEN
155 splash.showMessage(i18n("Performing Self-Check..."));
156 #endif
157 Kleo::Commands::SelfTestCommand cmd(0);
158 cmd.setAutoDelete(false);
159 cmd.setAutomaticMode(true);
160 #ifndef QT_NO_SPLASHSCREEN
161 cmd.setSplashScreen(&splash);
162 #endif
163 QEventLoop loop;
164 QObject::connect(&cmd, &Kleo::Commands::SelfTestCommand::finished, &loop, &QEventLoop::quit);
165 #ifndef QT_NO_SPLASHSCREEN
166 QObject::connect(&cmd, SIGNAL(info(QString)), &splash, SLOT(showMessage(QString)));
167 #endif
168 QTimer::singleShot(0, &cmd, &Kleo::Command::start); // start() may Q_EMIT finished()...
169 loop.exec();
170 if (cmd.isCanceled()) {
171 #ifndef QT_NO_SPLASHSCREEN
172 splash.showMessage(i18nc("did not pass", "Self-Check Failed"));
173 #endif
174 return false;
175 } else {
176 #ifndef QT_NO_SPLASHSCREEN
177 splash.showMessage(i18n("Self-Check Passed"));
178 #endif
179 return true;
183 static void fillKeyCache(SplashScreen *splash, Kleo::UiServer *server)
186 QEventLoop loop;
187 Kleo::ReloadKeysCommand *cmd = new Kleo::ReloadKeysCommand(0);
188 QObject::connect(cmd, &Kleo::Commands::SelfTestCommand::finished, &loop, &QEventLoop::quit);
189 #ifdef HAVE_USABLE_ASSUAN
190 QObject::connect(cmd, SIGNAL(finished()), server, SLOT(enableCryptoCommands()));
191 #else
192 Q_UNUSED(server);
193 #endif
194 #ifndef QT_NO_SPLASHSCREEN
195 splash->showMessage(i18n("Loading certificate cache..."));
196 #else
197 Q_UNUSED(splash);
198 #endif
199 cmd->start();
200 loop.exec();
201 #ifndef QT_NO_SPLASHSCREEN
202 splash->showMessage(i18n("Certificate cache loaded."));
203 #endif
206 int main(int argc, char **argv)
208 KleopatraApplication app(argc, argv);
209 app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
211 QTime timer;
212 timer.start();
214 KLocalizedString::setApplicationDomain("kleopatra");
216 KDBusService service(KDBusService::Unique);
217 QObject::connect(&service, &KDBusService::activateRequested,
218 &app, &KleopatraApplication::slotActivateRequested);
219 QObject::connect(&app, &KleopatraApplication::setExitValue,
220 &service, [&service](int i) {
221 service.setExitValue(i);
224 AboutData aboutData;
226 KAboutData::setApplicationData(aboutData);
228 QCommandLineParser parser;
229 aboutData.setupCommandLine(&parser);
230 kleopatra_options(&parser);
232 parser.process(QApplication::arguments());
233 aboutData.processCommandLine(&parser);
235 Kdelibs4ConfigMigrator migrate(QStringLiteral("kleopatra"));
236 migrate.setConfigFiles(QStringList() << QStringLiteral("kleopatrarc")
237 << QStringLiteral("libkleopatrarc"));
238 migrate.setUiFiles(QStringList() << QStringLiteral("kleopatra.rc"));
239 migrate.migrate();
241 qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: Application created";
243 // Initialize GpgME
244 const GpgME::Error gpgmeInitError = GpgME::initializeLibrary(0);
247 const unsigned int threads = QThreadPool::globalInstance()->maxThreadCount();
248 QThreadPool::globalInstance()->setMaxThreadCount(qMax(2U, threads));
250 if (gpgmeInitError) {
251 KMessageBox::sorry(0, xi18nc("@info",
252 "<para>The version of the <application>GpgME</application> library you are running against "
253 "is older than the one that the <application>GpgME++</application> library was built against.</para>"
254 "<para><application>Kleopatra</application> will not function in this setting.</para>"
255 "<para>Please ask your administrator for help in resolving this issue.</para>"),
256 i18nc("@title", "GpgME Too Old"));
257 return EXIT_FAILURE;
260 SplashScreen splash;
262 Kleo::ChecksumDefinition::setInstallPath(Kleo::gpg4winInstallPath());
263 Kleo::ArchiveDefinition::setInstallPath(Kleo::gnupgInstallPath());
265 int rc;
266 #ifdef HAVE_USABLE_ASSUAN
267 try {
268 Kleo::UiServer server(parser.value(QStringLiteral("uiserver-socket")));
270 qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: UiServer created";
272 QObject::connect(&server, &Kleo::UiServer::startKeyManagerRequested, &app, &KleopatraApplication::openOrRaiseMainWindow);
274 QObject::connect(&server, &Kleo::UiServer::startConfigDialogRequested, &app, &KleopatraApplication::openOrRaiseConfigDialog);
276 #define REGISTER( Command ) server.registerCommandFactory( boost::shared_ptr<Kleo::AssuanCommandFactory>( new Kleo::GenericAssuanCommandFactory<Kleo::Command> ) )
277 REGISTER(CreateChecksumsCommand);
278 REGISTER(DecryptCommand);
279 REGISTER(DecryptFilesCommand);
280 REGISTER(DecryptVerifyFilesCommand);
281 REGISTER(EchoCommand);
282 REGISTER(EncryptCommand);
283 REGISTER(EncryptFilesCommand);
284 REGISTER(EncryptSignFilesCommand);
285 REGISTER(ImportFilesCommand);
286 REGISTER(PrepEncryptCommand);
287 REGISTER(PrepSignCommand);
288 REGISTER(SelectCertificateCommand);
289 REGISTER(SignCommand);
290 REGISTER(SignEncryptFilesCommand);
291 REGISTER(SignFilesCommand);
292 #ifndef QT_NO_DIRMODEL
293 REGISTER(VerifyChecksumsCommand);
294 #endif // QT_NO_DIRMODEL
295 REGISTER(VerifyCommand);
296 REGISTER(VerifyFilesCommand);
297 #undef REGISTER
299 server.start();
300 qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: UiServer started";
301 #endif
303 const bool daemon = parser.isSet(QStringLiteral("daemon"));
304 if (!daemon && app.isSessionRestored()) {
305 app.restoreMainWindow();
308 #ifndef QT_NO_SPLASHSCREEN
309 // Don't show splash screen if daemon or session restore
310 if (!(daemon || app.isSessionRestored())) {
311 splash.show();
313 #endif
314 if (!selfCheck(splash)) {
315 return 1;
317 qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: SelfCheck completed";
319 #ifdef HAVE_USABLE_ASSUAN
320 fillKeyCache(&splash, &server);
321 #else
322 fillKeyCache(&splash, 0);
323 #endif
324 qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: KeyCache loaded";
326 #ifndef QT_NO_SYSTEMTRAYICON
327 app.startMonitoringSmartCard();
328 #endif
330 app.setIgnoreNewInstance(false);
332 if (!daemon) {
333 const QString err = app.newInstance(parser);
334 if (!err.isEmpty()) {
335 std::cerr << i18n("Invalid arguments: %1", err).toLocal8Bit().constData() << "\n";
336 exit(1);
338 qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: new instance created";
339 #ifndef QT_NO_SPLASHSCREEN
340 splash.finish(app.mainWindow());
341 #endif // QT_NO_SPLASHSCREEN
344 rc = app.exec();
346 #ifdef HAVE_USABLE_ASSUAN
347 app.setIgnoreNewInstance(true);
348 QObject::disconnect(&server, &Kleo::UiServer::startKeyManagerRequested, &app, &KleopatraApplication::openOrRaiseMainWindow);
349 QObject::disconnect(&server, &Kleo::UiServer::startConfigDialogRequested, &app, &KleopatraApplication::openOrRaiseConfigDialog);
351 server.stop();
352 server.waitForStopped();
353 } catch (const std::exception &e) {
354 QMessageBox::information(0, i18n("GPG UI Server Error"),
355 i18n("<qt>The Kleopatra GPG UI Server Module could not be initialized.<br/>"
356 "The error given was: <b>%1</b><br/>"
357 "You can use Kleopatra as a certificate manager, but cryptographic plugins that "
358 "rely on a GPG UI Server being present might not work correctly, or at all.</qt>",
359 QString::fromUtf8(e.what()).toHtmlEscaped()));
360 #ifndef QT_NO_SYSTEMTRAYICON
361 app.startMonitoringSmartCard();
362 #endif
363 app.setIgnoreNewInstance(false);
364 rc = app.exec();
365 app.setIgnoreNewInstance(true);
367 #endif
369 return rc;