Make it a slot
[kdepim.git] / kleopatra / kleopatraapplication.cpp
blobb39c0e50ad6dedf08029e66a3f4ba4102b1c9d58
1 /*
2 kleopatraapplication.cpp
4 This file is part of Kleopatra, the KDE keymanager
5 Copyright (c) 2008 Klarälvdalens 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 "kleopatraapplication.h"
37 #include "mainwindow.h"
38 #include "systrayicon.h"
40 #include <smartcard/readerstatus.h>
41 #include <conf/configuredialog.h>
43 #include <utils/gnupg-helper.h>
44 #include <utils/filesystemwatcher.h>
45 #include <utils/kdpipeiodevice.h>
46 #include <utils/log.h>
47 #include <utils/getpid.h>
49 #include <models/keycache.h>
51 #ifdef HAVE_USABLE_ASSUAN
52 # include <uiserver/uiserver.h>
53 #endif
55 #include <commands/signencryptfilescommand.h>
56 #include <commands/decryptverifyfilescommand.h>
58 #include <KGlobal>
59 #include <KIconLoader>
60 #include <KLocale>
61 #include <KCmdLineOptions>
62 #include <KDebug>
63 #include <KUrl>
64 #include <KWindowSystem>
66 #include <QFile>
67 #include <QDir>
68 #include <QPointer>
70 #include <boost/shared_ptr.hpp>
71 #include <boost/range.hpp>
72 #include <boost/bind.hpp>
73 #include <boost/mem_fn.hpp>
75 #include <memory>
77 using namespace Kleo;
78 using namespace Kleo::Commands;
79 using namespace boost;
81 static void add_resources() {
82 KGlobal::locale()->insertCatalog( "libkleopatra" );
83 KIconLoader::global()->addAppDir( "libkleopatra" );
84 KIconLoader::global()->addAppDir( "kwatchgnupg" );
85 KIconLoader::global()->addAppDir( "kdepim" );
88 static const struct {
89 const char * option;
90 const char * description;
91 char short_option[4];
92 } kleo_options[] = {
93 { "daemon", I18N_NOOP("Run UI server only, hide main window"), "" },
94 { "openpgp", I18N_NOOP("Use OpenPGP for the following operation"), "p" },
95 { "cms", I18N_NOOP("Use CMS (X.509, S/MIME) for the following operation"), "c" },
96 { "import-certificate", I18N_NOOP("Import certificate file(s)"), "i" },
97 { "encrypt", I18N_NOOP("Encrypt file(s)"), "e" },
98 { "sign", I18N_NOOP("Sign file(s)"), "s" },
99 { "sign-encrypt", I18N_NOOP("Sign and/or encrypt file(s)"), "E" },
100 { "encrypt-sign", I18N_NOOP("Same as --sign-encrypt, do not use"), "" },
101 { "decrypt", I18N_NOOP("Decrypt file(s)"), "d" },
102 { "verify", I18N_NOOP("Verify file/signature"), "V" },
103 { "decrypt-verify", I18N_NOOP("Decrypt and/or verify file(s)"), "D" },
104 //{ "show-certificate", I18N_NOOP("Show Certificate(s) by fingerprint(s)"), "" },
108 static KCmdLineOptions make_kleopatra_args() {
109 KCmdLineOptions options;
110 #ifdef HAVE_USABLE_ASSUAN
111 options.add("uiserver-socket <argument>", ki18n("Location of the socket the ui server is listening on" ));
112 #endif
113 for ( unsigned int i = 0 ; i < sizeof kleo_options / sizeof *kleo_options ; ++i ) {
114 if ( *kleo_options[i].short_option )
115 options.add( kleo_options[i].short_option );
116 options.add( kleo_options[i].option, ki18n( kleo_options[i].description ) );
118 options.add("+[File]", ki18n("File(s) to process"));
119 return options;
122 // static
123 KCmdLineOptions KleopatraApplication::commandLineOptions() {
124 static KCmdLineOptions options = make_kleopatra_args();
125 return options;
128 static QList<QByteArray> default_logging_options() {
129 QList<QByteArray> result;
130 result.push_back( "io" );
131 return result;
134 class KleopatraApplication::Private {
135 friend class ::KleopatraApplication;
136 KleopatraApplication * const q;
137 public:
138 explicit Private( KleopatraApplication * qq )
139 : q( qq ),
140 ignoreNewInstance( true )
142 #ifndef _WIN32_WCE
143 KDAB_SET_OBJECT_NAME( readerStatus );
144 #endif
145 #ifndef QT_NO_SYSTEMTRAYICON
146 KDAB_SET_OBJECT_NAME( sysTray );
148 sysTray.setAnyCardHasNullPin( readerStatus.anyCardHasNullPin() );
149 sysTray.setAnyCardCanLearnKeys( readerStatus.anyCardCanLearnKeys() );
151 connect( &readerStatus, SIGNAL(anyCardHasNullPinChanged(bool)),
152 &sysTray, SLOT(setAnyCardHasNullPin(bool)) );
153 connect( &readerStatus, SIGNAL(anyCardCanLearnKeysChanged(bool)),
154 &sysTray, SLOT(setAnyCardCanLearnKeys(bool)) );
155 #endif
158 private:
159 void connectConfigureDialog() {
160 if ( configureDialog && q->mainWindow() )
161 connect( configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()) );
163 void disconnectConfigureDialog() {
164 if ( configureDialog && q->mainWindow() )
165 disconnect( configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()) );
168 public:
169 bool ignoreNewInstance;
170 QPointer<ConfigureDialog> configureDialog;
171 QPointer<MainWindow> mainWindow;
172 #ifndef _WIN32_WCE
173 SmartCard::ReaderStatus readerStatus;
174 #endif
175 #ifndef QT_NO_SYSTEMTRAYICON
176 SysTrayIcon sysTray;
177 #endif
178 shared_ptr<KeyCache> keyCache;
179 shared_ptr<Log> log;
180 shared_ptr<FileSystemWatcher> watcher;
182 public:
183 void setupKeyCache() {
184 keyCache = KeyCache::mutableInstance();
185 watcher.reset( new FileSystemWatcher );
187 watcher->blacklistFiles( gnupgFileBlacklist() );
188 watcher->addPath( gnupgHomeDirectory() );
189 watcher->setDelay( 1000 );
190 keyCache->addFileSystemWatcher( watcher );
193 void setupLogging() {
194 log = Log::mutableInstance();
196 const QByteArray envOptions = qgetenv( "KLEOPATRA_LOGOPTIONS" );
197 const bool logAll = envOptions.trimmed() == "all";
198 const QList<QByteArray> options = envOptions.isEmpty() ? default_logging_options() : envOptions.split( ',' ) ;
200 const QByteArray dirNative = qgetenv( "KLEOPATRA_LOGDIR" );
201 if ( dirNative.isEmpty() )
202 return;
203 const QString dir = QFile::decodeName( dirNative );
204 const QString logFileName = QDir( dir ).absoluteFilePath( QString::fromLatin1( "kleopatra.log.%1" ).arg( mygetpid() ) );
205 std::auto_ptr<QFile> logFile( new QFile( logFileName ) );
206 if ( !logFile->open( QIODevice::WriteOnly | QIODevice::Append ) ) {
207 kDebug() << "Could not open file for logging: " << logFileName << "\nLogging disabled";
208 return;
211 log->setOutputDirectory( dir );
212 if ( logAll || options.contains( "io" ) )
213 log->setIOLoggingEnabled( true );
214 qInstallMsgHandler( Log::messageHandler );
216 #ifdef HAVE_USABLE_ASSUAN
217 if ( logAll || options.contains( "pipeio" ) )
218 KDPipeIODevice::setDebugLevel( KDPipeIODevice::Debug );
219 UiServer::setLogStream( log->logFile() );
220 #endif
226 KleopatraApplication::KleopatraApplication()
227 : KUniqueApplication(), d( new Private( this ) )
229 add_resources();
230 d->setupKeyCache();
231 d->setupLogging();
232 #ifndef QT_NO_SYSTEMTRAYICON
233 d->sysTray.show();
234 #endif
235 setQuitOnLastWindowClosed( false );
236 KWindowSystem::allowExternalProcessWindowActivation();
239 KleopatraApplication::~KleopatraApplication() {
240 // work around kdelibs bug https://bugs.kde.org/show_bug.cgi?id=162514
241 KGlobal::config()->sync();
244 static QStringList files_from_args( const shared_ptr<const KCmdLineArgs> & args ) {
245 QStringList result;
246 for ( int i = 0, end = args->count() ; i < end ; ++i ) {
247 const KUrl url = args->url(i);
248 if ( url.protocol() == QLatin1String("file") )
249 result.push_back( url.toLocalFile() );
251 return result;
254 namespace {
255 typedef void (KleopatraApplication::*Func)( const QStringList &, GpgME::Protocol );
256 struct _Funcs {
257 const char * opt;
258 Func func;
262 int KleopatraApplication::newInstance() {
263 kDebug() << "ignoreNewInstance =" << d->ignoreNewInstance;
264 if ( d->ignoreNewInstance )
265 return 0;
267 const shared_ptr<KCmdLineArgs> args( KCmdLineArgs::parsedArgs(), mem_fn( &KCmdLineArgs::clear ) );
269 const QStringList files = files_from_args( args );
271 const bool openpgp = args->isSet( "openpgp" );
272 const bool cms = args->isSet( "cms" );
274 kDebug( openpgp ) << "found OpenPGP";
275 kDebug( cms ) << "found CMS";
277 if ( openpgp && cms ) {
278 kDebug() << "ambigious protocol: --openpgp and --cms";
279 return 1;
282 static const _Funcs funcs[] = {
283 #ifndef QT_NO_SYSTEMTRAYICON
284 { "import-certificate", &KleopatraApplication::importCertificatesFromFile },
285 #endif
286 { "encrypt", &KleopatraApplication::encryptFiles },
287 { "sign", &KleopatraApplication::signFiles },
288 { "encrypt-sign", &KleopatraApplication::signEncryptFiles },
289 { "sign-encrypt", &KleopatraApplication::signEncryptFiles },
290 { "decrypt", &KleopatraApplication::decryptFiles },
291 { "verify", &KleopatraApplication::verifyFiles },
292 { "decrypt-verify", &KleopatraApplication::decryptVerifyFiles },
295 const _Funcs * const it1 = std::find_if( begin( funcs ), end( funcs ),
296 boost::bind( &KCmdLineArgs::isSet, args, boost::bind( &_Funcs::opt, _1 ) ) );
298 if ( const Func func = it1 == end( funcs ) ? 0 : it1->func ) {
299 const _Funcs * it2 = std::find_if( it1+1, end( funcs ),
300 boost::bind( &KCmdLineArgs::isSet, args, boost::bind( &_Funcs::opt, _1 ) ) );
301 if ( it2 != end( funcs ) ) {
302 kDebug() << "ambiguous command" << it1->opt << "vs." << it2->opt;
303 return 1;
305 if ( files.empty() ) {
306 kDebug() << it1->opt << "without arguments";
307 return 1;
309 kDebug() << "found" << it1->opt;
310 (this->*func)( files, openpgp ? GpgME::OpenPGP : cms ? GpgME::CMS : GpgME::UnknownProtocol );
311 } else {
312 if ( files.empty() ) {
313 kDebug() << "openOrRaiseMainWindow";
314 openOrRaiseMainWindow();
315 } else {
316 kDebug() << "files without command"; // possible?
317 return 1;
321 return 0;
324 #ifndef QT_NO_SYSTEMTRAYICON
325 const SysTrayIcon * KleopatraApplication::sysTrayIcon() const {
326 return &d->sysTray;
329 SysTrayIcon * KleopatraApplication::sysTrayIcon() {
330 return &d->sysTray;
332 #endif
334 const MainWindow * KleopatraApplication::mainWindow() const {
335 return d->mainWindow;
338 MainWindow * KleopatraApplication::mainWindow() {
339 return d->mainWindow;
342 void KleopatraApplication::setMainWindow( MainWindow * mainWindow ) {
343 if ( mainWindow == d->mainWindow )
344 return;
346 d->disconnectConfigureDialog();
348 d->mainWindow = mainWindow;
349 #ifndef QT_NO_SYSTEMTRAYICON
350 d->sysTray.setMainWindow( mainWindow );
351 #endif
353 d->connectConfigureDialog();
356 static void open_or_raise( QWidget * w ) {
357 if ( w->isMinimized() ) {
358 KWindowSystem::unminimizeWindow( w->winId());
359 w->raise();
360 } else if ( w->isVisible() ) {
361 w->raise();
362 } else {
363 w->show();
367 void KleopatraApplication::openOrRaiseMainWindow() {
368 MainWindow * mw = mainWindow();
369 if ( !mw ) {
370 mw = new MainWindow;
371 mw->setAttribute( Qt::WA_DeleteOnClose );
372 setMainWindow( mw );
373 d->connectConfigureDialog();
375 open_or_raise( mw );
378 void KleopatraApplication::openOrRaiseConfigDialog() {
379 if ( !d->configureDialog ) {
380 d->configureDialog = new ConfigureDialog;
381 d->configureDialog->setAttribute( Qt::WA_DeleteOnClose );
382 d->connectConfigureDialog();
384 open_or_raise( d->configureDialog );
387 #ifndef QT_NO_SYSTEMTRAYICON
388 void KleopatraApplication::startMonitoringSmartCard() {
389 d->readerStatus.startMonitoring();
392 void KleopatraApplication::importCertificatesFromFile( const QStringList & files, GpgME::Protocol /*proto*/) {
393 openOrRaiseMainWindow();
394 if ( !files.empty() )
395 d->sysTray.mainWindow()->importCertificatesFromFile( files );
397 #endif // QT_NO_SYSTEMTRAYICON
399 void KleopatraApplication::encryptFiles( const QStringList & files, GpgME::Protocol proto ) {
400 SignEncryptFilesCommand * const cmd = new SignEncryptFilesCommand( files, 0 );
401 cmd->setEncryptionPolicy( Force );
402 cmd->setSigningPolicy( Allow );
403 if ( proto != GpgME::UnknownProtocol )
404 cmd->setProtocol( proto );
405 cmd->start();
408 void KleopatraApplication::signFiles( const QStringList & files, GpgME::Protocol proto ) {
409 SignEncryptFilesCommand * const cmd = new SignEncryptFilesCommand( files, 0 );
410 cmd->setSigningPolicy( Force );
411 cmd->setEncryptionPolicy( Deny );
412 if ( proto != GpgME::UnknownProtocol )
413 cmd->setProtocol( proto );
414 cmd->start();
417 void KleopatraApplication::signEncryptFiles( const QStringList & files, GpgME::Protocol proto ) {
418 SignEncryptFilesCommand * const cmd = new SignEncryptFilesCommand( files, 0 );
419 if ( proto != GpgME::UnknownProtocol )
420 cmd->setProtocol( proto );
421 cmd->start();
424 void KleopatraApplication::decryptFiles( const QStringList & files, GpgME::Protocol /*proto*/ ) {
425 DecryptVerifyFilesCommand * const cmd = new DecryptVerifyFilesCommand( files, 0 );
426 cmd->setOperation( Decrypt );
427 cmd->start();
430 void KleopatraApplication::verifyFiles( const QStringList & files, GpgME::Protocol /*proto*/ ) {
431 DecryptVerifyFilesCommand * const cmd = new DecryptVerifyFilesCommand( files, 0 );
432 cmd->setOperation( Verify );
433 cmd->start();
436 void KleopatraApplication::decryptVerifyFiles( const QStringList & files, GpgME::Protocol /*proto*/ ) {
437 DecryptVerifyFilesCommand * const cmd = new DecryptVerifyFilesCommand( files, 0 );
438 cmd->start();
441 void KleopatraApplication::setIgnoreNewInstance( bool ignore ) {
442 d->ignoreNewInstance = ignore;
445 bool KleopatraApplication::ignoreNewInstance() const {
446 return d->ignoreNewInstance;
449 #include "moc_kleopatraapplication.cpp"