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
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>
55 #include <commands/signencryptfilescommand.h>
56 #include <commands/decryptverifyfilescommand.h>
59 #include <KIconLoader>
61 #include <KCmdLineOptions>
64 #include <KWindowSystem>
70 #include <boost/shared_ptr.hpp>
71 #include <boost/range.hpp>
72 #include <boost/bind.hpp>
73 #include <boost/mem_fn.hpp>
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" );
90 const char * description
;
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" ));
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"));
123 KCmdLineOptions
KleopatraApplication::commandLineOptions() {
124 static KCmdLineOptions options
= make_kleopatra_args();
128 static QList
<QByteArray
> default_logging_options() {
129 QList
<QByteArray
> result
;
130 result
.push_back( "io" );
134 class KleopatraApplication::Private
{
135 friend class ::KleopatraApplication
;
136 KleopatraApplication
* const q
;
138 explicit Private( KleopatraApplication
* qq
)
140 ignoreNewInstance( true )
143 KDAB_SET_OBJECT_NAME( readerStatus
);
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)) );
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()) );
169 bool ignoreNewInstance
;
170 QPointer
<ConfigureDialog
> configureDialog
;
171 QPointer
<MainWindow
> mainWindow
;
173 SmartCard::ReaderStatus readerStatus
;
175 #ifndef QT_NO_SYSTEMTRAYICON
178 shared_ptr
<KeyCache
> keyCache
;
180 shared_ptr
<FileSystemWatcher
> watcher
;
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() )
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";
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() );
226 KleopatraApplication::KleopatraApplication()
227 : KUniqueApplication(), d( new Private( this ) )
232 #ifndef QT_NO_SYSTEMTRAYICON
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
) {
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() );
255 typedef void (KleopatraApplication::*Func
)( const QStringList
&, GpgME::Protocol
);
262 int KleopatraApplication::newInstance() {
263 kDebug() << "ignoreNewInstance =" << d
->ignoreNewInstance
;
264 if ( d
->ignoreNewInstance
)
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";
282 static const _Funcs funcs
[] = {
283 #ifndef QT_NO_SYSTEMTRAYICON
284 { "import-certificate", &KleopatraApplication::importCertificatesFromFile
},
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
;
305 if ( files
.empty() ) {
306 kDebug() << it1
->opt
<< "without arguments";
309 kDebug() << "found" << it1
->opt
;
310 (this->*func
)( files
, openpgp
? GpgME::OpenPGP
: cms
? GpgME::CMS
: GpgME::UnknownProtocol
);
312 if ( files
.empty() ) {
313 kDebug() << "openOrRaiseMainWindow";
314 openOrRaiseMainWindow();
316 kDebug() << "files without command"; // possible?
324 #ifndef QT_NO_SYSTEMTRAYICON
325 const SysTrayIcon
* KleopatraApplication::sysTrayIcon() const {
329 SysTrayIcon
* KleopatraApplication::sysTrayIcon() {
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
)
346 d
->disconnectConfigureDialog();
348 d
->mainWindow
= mainWindow
;
349 #ifndef QT_NO_SYSTEMTRAYICON
350 d
->sysTray
.setMainWindow( mainWindow
);
353 d
->connectConfigureDialog();
356 static void open_or_raise( QWidget
* w
) {
357 if ( w
->isMinimized() ) {
358 KWindowSystem::unminimizeWindow( w
->winId());
360 } else if ( w
->isVisible() ) {
367 void KleopatraApplication::openOrRaiseMainWindow() {
368 MainWindow
* mw
= mainWindow();
371 mw
->setAttribute( Qt::WA_DeleteOnClose
);
373 d
->connectConfigureDialog();
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
);
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
);
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
);
424 void KleopatraApplication::decryptFiles( const QStringList
& files
, GpgME::Protocol
/*proto*/ ) {
425 DecryptVerifyFilesCommand
* const cmd
= new DecryptVerifyFilesCommand( files
, 0 );
426 cmd
->setOperation( Decrypt
);
430 void KleopatraApplication::verifyFiles( const QStringList
& files
, GpgME::Protocol
/*proto*/ ) {
431 DecryptVerifyFilesCommand
* const cmd
= new DecryptVerifyFilesCommand( files
, 0 );
432 cmd
->setOperation( Verify
);
436 void KleopatraApplication::decryptVerifyFiles( const QStringList
& files
, GpgME::Protocol
/*proto*/ ) {
437 DecryptVerifyFilesCommand
* const cmd
= new DecryptVerifyFilesCommand( files
, 0 );
441 void KleopatraApplication::setIgnoreNewInstance( bool ignore
) {
442 d
->ignoreNewInstance
= ignore
;
445 bool KleopatraApplication::ignoreNewInstance() const {
446 return d
->ignoreNewInstance
;
449 #include "moc_kleopatraapplication.cpp"