00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifdef HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036
00037 #include "certmanager.h"
00038
00039 #include "certlistview.h"
00040 #include "certificatewizardimpl.h"
00041 #include "certificateinfowidgetimpl.h"
00042 #include "crlview.h"
00043 #include "customactions.h"
00044 #include "hierarchyanalyser.h"
00045 #include "storedtransferjob.h"
00046 #include "conf/configuredialog.h"
00047
00048
00049 #include <kleo/cryptobackendfactory.h>
00050 #include <kleo/downloadjob.h>
00051 #include <kleo/importjob.h>
00052 #include <kleo/exportjob.h>
00053 #include <kleo/multideletejob.h>
00054 #include <kleo/deletejob.h>
00055 #include <kleo/keylistjob.h>
00056 #include <kleo/dn.h>
00057 #include <kleo/keyfilter.h>
00058 #include <kleo/keyfiltermanager.h>
00059 #include <kleo/hierarchicalkeylistjob.h>
00060 #include <kleo/refreshkeysjob.h>
00061 #include <kleo/cryptoconfig.h>
00062
00063 #include <ui/progressdialog.h>
00064 #include <ui/progressbar.h>
00065 #include <ui/keyselectiondialog.h>
00066 #include <ui/cryptoconfigdialog.h>
00067
00068
00069 #include <gpgmepp/importresult.h>
00070 #include <gpgmepp/keylistresult.h>
00071 #include <gpgmepp/key.h>
00072
00073
00074 #include <kfiledialog.h>
00075 #include <kprocess.h>
00076 #include <kaction.h>
00077 #include <kapplication.h>
00078 #include <klocale.h>
00079 #include <kmessagebox.h>
00080 #include <dcopclient.h>
00081 #include <ktoolbar.h>
00082 #include <kstatusbar.h>
00083 #include <kstandarddirs.h>
00084 #include <kdebug.h>
00085 #include <kdialogbase.h>
00086 #include <kkeydialog.h>
00087 #include <ktempfile.h>
00088 #include <kio/job.h>
00089 #include <kio/netaccess.h>
00090 #include <kstdaccel.h>
00091
00092
00093 #include <qfontmetrics.h>
00094 #include <qpopupmenu.h>
00095
00096
00097 #include <algorithm>
00098 #include <assert.h>
00099 #include <kdepimmacros.h>
00100 namespace {
00101
00102 class KDE_EXPORT DisplayStrategy : public Kleo::KeyListView::DisplayStrategy{
00103 public:
00104 ~DisplayStrategy() {}
00105
00106 virtual QFont keyFont( const GpgME::Key& key, const QFont& font ) const {
00107 const Kleo::KeyFilter* filter = Kleo::KeyFilterManager::instance()->filterMatching( key );
00108 return filter ? filter->font( font ) : font;
00109 }
00110 virtual QColor keyForeground( const GpgME::Key& key, const QColor& c ) const {
00111 const Kleo::KeyFilter* filter = Kleo::KeyFilterManager::instance()->filterMatching( key );
00112 if ( filter && filter->fgColor().isValid() )
00113 return filter->fgColor();
00114 return c;
00115 }
00116 virtual QColor keyBackground( const GpgME::Key& key, const QColor& c ) const {
00117 const Kleo::KeyFilter* filter = Kleo::KeyFilterManager::instance()->filterMatching( key );
00118 if ( filter && filter->bgColor().isValid() )
00119 return filter->bgColor();
00120 return c;
00121 }
00122 };
00123
00124 class KDE_EXPORT ColumnStrategy : public Kleo::KeyListView::ColumnStrategy {
00125 public:
00126 ~ColumnStrategy() {}
00127
00128 QString title( int col ) const;
00129 QString text( const GpgME::Key & key, int col ) const;
00130 int width( int col, const QFontMetrics & fm ) const;
00131 };
00132
00133 QString ColumnStrategy::title( int col ) const {
00134 switch ( col ) {
00135 case 0: return i18n("Subject");
00136 case 1: return i18n("Issuer");
00137 case 2: return i18n("Serial");
00138 default: return QString::null;
00139 }
00140 }
00141
00142 QString ColumnStrategy::text( const GpgME::Key & key, int col ) const {
00143 switch ( col ) {
00144 case 0: return Kleo::DN( key.userID(0).id() ).prettyDN();
00145 case 1: return Kleo::DN( key.issuerName() ).prettyDN();
00146 case 2: return key.issuerSerial() ? QString::fromUtf8( key.issuerSerial() ) : QString::null ;
00147 default: return QString::null;
00148 }
00149 }
00150
00151 int ColumnStrategy::width( int col, const QFontMetrics & fm ) const {
00152 int factor = -1;
00153 switch ( col ) {
00154 case 0: factor = 6; break;
00155 case 1: factor = 4; break;
00156 default: return -1;
00157 }
00158 return fm.width( title( col ) ) * factor;
00159 }
00160 }
00161
00162 CertManager::CertManager( bool remote, const QString& query, const QString & import,
00163 QWidget* parent, const char* name, WFlags f )
00164 : KMainWindow( parent, name, f|WDestructiveClose ),
00165 mCrlView( 0 ),
00166 mDirmngrProc( 0 ),
00167 mHierarchyAnalyser( 0 ),
00168 mLineEditAction( 0 ),
00169 mComboAction( 0 ),
00170 mFindAction( 0 ),
00171 mImportCertFromFileAction( 0 ),
00172 mImportCRLFromFileAction( 0 ),
00173 mNextFindRemote( remote ),
00174 mRemote( remote ),
00175 mDirMngrFound( false )
00176 {
00177 readConfig( query.isEmpty() );
00178 createStatusBar();
00179 createActions();
00180
00181 createGUI();
00182 setAutoSaveSettings();
00183
00184
00185 mKeyListView = new CertKeyListView( new ColumnStrategy(), new DisplayStrategy(), this, "mKeyListView" );
00186 mKeyListView->setSelectionMode( QListView::Extended );
00187 setCentralWidget( mKeyListView );
00188
00189 connect( mKeyListView, SIGNAL(doubleClicked(Kleo::KeyListViewItem*,const QPoint&,int)),
00190 SLOT(slotViewDetails(Kleo::KeyListViewItem*)) );
00191 connect( mKeyListView, SIGNAL(returnPressed(Kleo::KeyListViewItem*)),
00192 SLOT(slotViewDetails(Kleo::KeyListViewItem*)) );
00193 connect( mKeyListView, SIGNAL(selectionChanged()),
00194 SLOT(slotSelectionChanged()) );
00195 connect( mKeyListView, SIGNAL(contextMenu(Kleo::KeyListViewItem*, const QPoint&)),
00196 SLOT(slotContextMenu(Kleo::KeyListViewItem*, const QPoint&)) );
00197
00198 connect( mKeyListView, SIGNAL(dropped(const KURL::List&) ),
00199 SLOT( slotDropped(const KURL::List&) ) );
00200
00201 mLineEditAction->setText(query);
00202 if ( !mRemote || !query.isEmpty() )
00203 slotSearch();
00204
00205 if ( !import.isEmpty() )
00206 slotImportCertFromFile( KURL( import ) );
00207
00208 slotToggleHierarchicalView( mHierarchicalView );
00209 updateStatusBarLabels();
00210 slotSelectionChanged();
00211 }
00212
00213 CertManager::~CertManager() {
00214 writeConfig();
00215 delete mDirmngrProc; mDirmngrProc = 0;
00216 delete mHierarchyAnalyser; mHierarchyAnalyser = 0;
00217 }
00218
00219 void CertManager::readConfig( bool noQueryGiven ) {
00220 KConfig config( "kleopatrarc" );
00221 config.setGroup( "Display Options" );
00222 mHierarchicalView = config.readBoolEntry( "hierarchicalView", false );
00223 if ( noQueryGiven ) {
00224 mNextFindRemote = config.readBoolEntry( "startInRemoteMode", false );
00225 }
00226 }
00227
00228 void CertManager::writeConfig() {
00229 KConfig config( "kleopatrarc" );
00230 config.setGroup( "Display Options" );
00231 config.writeEntry( "hierarchicalView", mKeyListView->hierarchical() );
00232 config.writeEntry( "startInRemoteMode", mNextFindRemote );
00233 }
00234
00235 void CertManager::createStatusBar() {
00236 KStatusBar * bar = statusBar();
00237 mProgressBar = new Kleo::ProgressBar( bar, "mProgressBar" );
00238 mProgressBar->reset();
00239 mProgressBar->setFixedSize( QSize( 100, mProgressBar->height() * 3 / 5 ) );
00240 bar->addWidget( mProgressBar, 0, true );
00241 mStatusLabel = new QLabel( bar, "mStatusLabel" );
00242 bar->addWidget( mStatusLabel, 1, false );
00243 }
00244
00245 static inline void connectEnableOperationSignal( QObject * s, QObject * d ) {
00246 QObject::connect( s, SIGNAL(enableOperations(bool)),
00247 d, SLOT(setEnabled(bool)) );
00248 }
00249
00250
00251 void CertManager::createActions() {
00252 KAction * action = 0;
00253
00254 (void)KStdAction::quit( this, SLOT(close()), actionCollection() );
00255
00256 action = KStdAction::redisplay( this, SLOT(slotRedisplay()), actionCollection() );
00257
00258 KShortcut reloadShortcut = KStdAccel::shortcut(KStdAccel::Reload);
00259 reloadShortcut.append(KKey(CTRL + Key_R));
00260 action->setShortcut( reloadShortcut );
00261
00262 connectEnableOperationSignal( this, action );
00263
00264 action = new KAction( i18n("Stop Operation"), "stop", Key_Escape,
00265 this, SIGNAL(stopOperations()),
00266 actionCollection(), "view_stop_operations" );
00267 action->setEnabled( false );
00268
00269 (void) new KAction( i18n("New Key Pair..."), "filenew", 0,
00270 this, SLOT(newCertificate()),
00271 actionCollection(), "file_new_certificate" );
00272
00273 connect( new KToggleAction( i18n("Hierarchical Key List"), 0,
00274 actionCollection(), "view_hierarchical" ),
00275 SIGNAL(toggled(bool)), SLOT(slotToggleHierarchicalView(bool)) );
00276
00277 action = new KAction( i18n("Expand All"), 0, CTRL+Key_Period,
00278 this, SLOT(slotExpandAll()),
00279 actionCollection(), "view_expandall" );
00280 action = new KAction( i18n("Collapse All"), 0, CTRL+Key_Comma,
00281 this, SLOT(slotCollapseAll()),
00282 actionCollection(), "view_collapseall" );
00283
00284 (void) new KAction( i18n("Refresh CRLs"), 0, 0,
00285 this, SLOT(slotRefreshKeys()),
00286 actionCollection(), "certificates_refresh_clr" );
00287
00288 #ifdef NOT_IMPLEMENTED_ANYWAY
00289 mRevokeCertificateAction = new KAction( i18n("Revoke"), 0,
00290 this, SLOT(revokeCertificate()),
00291 actionCollection(), "edit_revoke_certificate" );
00292 connectEnableOperationSignal( this, mRevokeCertificateAction );
00293
00294 mExtendCertificateAction = new KAction( i18n("Extend"), 0,
00295 this, SLOT(extendCertificate()),
00296 actionCollection(), "edit_extend_certificate" );
00297 connectEnableOperationSignal( this, mExtendCertificateAction );
00298 #endif
00299
00300 mDeleteCertificateAction = new KAction( i18n("Delete"), "editdelete", Key_Delete,
00301 this, SLOT(slotDeleteCertificate()),
00302 actionCollection(), "edit_delete_certificate" );
00303 connectEnableOperationSignal( this, mDeleteCertificateAction );
00304
00305 mValidateCertificateAction = new KAction( i18n("Validate"), "reload", SHIFT + Key_F5,
00306 this, SLOT(slotValidate()),
00307 actionCollection(), "certificates_validate" );
00308 connectEnableOperationSignal( this, mValidateCertificateAction );
00309
00310 mImportCertFromFileAction = new KAction( i18n("Import Certificates..."), 0,
00311 this, SLOT(slotImportCertFromFile()),
00312 actionCollection(), "file_import_certificates" );
00313 connectEnableOperationSignal( this, mImportCertFromFileAction );
00314
00315 mImportCRLFromFileAction = new KAction( i18n("Import CRLs..."), 0,
00316 this, SLOT(importCRLFromFile()),
00317 actionCollection(), "file_import_crls" );
00318 connectEnableOperationSignal( this, mImportCRLFromFileAction );
00319
00320 mExportCertificateAction = new KAction( i18n("Export Certificates..."), "export", 0,
00321 this, SLOT(slotExportCertificate()),
00322 actionCollection(), "file_export_certificate" );
00323
00324 mExportSecretKeyAction = new KAction( i18n("Export Secret Key..."), "export", 0,
00325 this, SLOT(slotExportSecretKey()),
00326 actionCollection(), "file_export_secret_keys" );
00327 connectEnableOperationSignal( this, mExportSecretKeyAction );
00328
00329 mViewCertDetailsAction = new KAction( i18n("Certificate Details..."), 0, 0,
00330 this, SLOT(slotViewDetails()), actionCollection(),
00331 "view_certificate_details" );
00332 mDownloadCertificateAction = new KAction( i18n( "Download"), 0, 0,
00333 this, SLOT(slotDownloadCertificate()), actionCollection(),
00334 "download_certificate" );
00335
00336 const QString dirmngr = KStandardDirs::findExe( "gpgsm" );
00337 mDirMngrFound = !dirmngr.isEmpty();
00338
00339 action = new KAction( i18n("Dump CRL Cache..."), 0,
00340 this, SLOT(slotViewCRLs()),
00341 actionCollection(), "crl_dump_crl_cache" );
00342 action->setEnabled( mDirMngrFound );
00343
00344 action = new KAction( i18n("Clear CRL Cache..."), 0,
00345 this, SLOT(slotClearCRLs()),
00346 actionCollection(), "crl_clear_crl_cache" );
00347 action->setEnabled( mDirMngrFound );
00348
00349 action = new KAction( i18n("GnuPG Log Viewer..."), "pgp-keys", 0, this,
00350 SLOT(slotStartWatchGnuPG()), actionCollection(), "tools_start_kwatchgnupg");
00351
00352 if (KStandardDirs::findExe("kwatchgnupg").isEmpty()) action->setEnabled(false);
00353
00354 (void)new LabelAction( i18n("Search:"), actionCollection(), "label_action" );
00355
00356 mLineEditAction = new LineEditAction( QString::null, actionCollection(), this,
00357 SLOT(slotSearch()),
00358 "query_lineedit_action");
00359
00360 QStringList lst;
00361 lst << i18n("In Local Certificates") << i18n("In External Certificates");
00362 mComboAction = new ComboAction( lst, actionCollection(), this, SLOT( slotToggleRemote(int) ),
00363 "location_combo_action", mNextFindRemote? 1 : 0 );
00364
00365 mFindAction = new KAction( i18n("Find"), "find", 0, this, SLOT(slotSearch()),
00366 actionCollection(), "find" );
00367
00368 KStdAction::keyBindings( this, SLOT(slotEditKeybindings()), actionCollection() );
00369 KStdAction::preferences( this, SLOT(slotShowConfigurationDialog()), actionCollection() );
00370
00371 new KAction( i18n( "Configure &GpgME Backend" ), 0, 0, this, SLOT(slotConfigureGpgME()),
00372 actionCollection(), "configure_gpgme" );
00373
00374 createStandardStatusBarAction();
00375 updateImportActions( true );
00376 }
00377
00378 void CertManager::updateImportActions( bool enable ) {
00379 mImportCRLFromFileAction->setEnabled( mDirMngrFound && enable );
00380 mImportCertFromFileAction->setEnabled( enable );
00381 }
00382
00383 void CertManager::slotEditKeybindings() {
00384 KKeyDialog::configure( actionCollection(), true );
00385 }
00386
00387 void CertManager::slotShowConfigurationDialog() {
00388 ConfigureDialog dlg( this );
00389 connect( &dlg, SIGNAL( configCommitted() ), SLOT( slotRepaint() ) );
00390 dlg.exec();
00391 }
00392
00393 void CertManager::slotConfigureGpgME() {
00394 Kleo::CryptoConfig* config = Kleo::CryptoBackendFactory::instance()->config();
00395 if ( config ) {
00396 Kleo::CryptoConfigDialog dlg( config );
00397
00398 int result = dlg.exec();
00399
00400
00401
00402 config->clear();
00403
00404 if ( result == QDialog::Accepted )
00405 {
00406
00407 kapp->dcopClient()->emitDCOPSignal( "KPIM::CryptoConfig", "changed()", QByteArray() );
00408 }
00409 }
00410 }
00411
00412 void CertManager::slotRepaint()
00413 {
00414 mKeyListView->repaintContents();
00415 }
00416
00417 void CertManager::slotToggleRemote( int idx ) {
00418 mNextFindRemote = idx != 0;
00419 }
00420
00421 void CertManager::slotToggleHierarchicalView( bool hier ) {
00422 mHierarchicalView = hier;
00423 mKeyListView->setHierarchical( hier );
00424 mKeyListView->setRootIsDecorated( hier );
00425 if ( KAction * act = action("view_expandall") )
00426 act->setEnabled( hier );
00427 if ( KAction * act = action("view_collapseall" ) )
00428 act->setEnabled( hier );
00429 if ( KToggleAction * act =
00430 static_cast<KToggleAction*>( action("view_hierarchical") ) )
00431 act->setChecked( hier );
00432
00433 if ( hier && !mCurrentQuery.isEmpty() )
00434 startRedisplay( false );
00435 }
00436
00437 void CertManager::slotExpandAll() {
00438 for ( QListViewItemIterator it( mKeyListView ) ; it.current() ; ++it )
00439 it.current()->setOpen( true );
00440 }
00441
00442 void CertManager::slotCollapseAll() {
00443 for ( QListViewItemIterator it( mKeyListView ) ; it.current() ; ++it )
00444 it.current()->setOpen( false );
00445 }
00446
00447 void CertManager::connectJobToStatusBarProgress( Kleo::Job * job, const QString & initialText ) {
00448 assert( mProgressBar );
00449 if ( !job )
00450 return;
00451 if ( !initialText.isEmpty() )
00452 statusBar()->message( initialText );
00453 connect( job, SIGNAL(progress(const QString&,int,int)),
00454 mProgressBar, SLOT(slotProgress(const QString&,int,int)) );
00455 connect( job, SIGNAL(done()), mProgressBar, SLOT(reset()) );
00456 connect( this, SIGNAL(stopOperations()), job, SLOT(slotCancel()) );
00457
00458 action("view_stop_operations")->setEnabled( true );
00459 emit enableOperations( false );
00460 }
00461
00462 void CertManager::disconnectJobFromStatusBarProgress( const GpgME::Error & err ) {
00463 updateStatusBarLabels();
00464 const QString msg = err.isCanceled() ? i18n("Canceled.")
00465 : err ? i18n("Failed.")
00466 : i18n("Done.") ;
00467 statusBar()->message( msg, 4000 );
00468
00469 action("view_stop_operations")->setEnabled( false );
00470 emit enableOperations( true );
00471 slotSelectionChanged();
00472 }
00473
00474 void CertManager::updateStatusBarLabels() {
00475 mKeyListView->flushKeys();
00476 int total = 0;
00477 for ( QListViewItemIterator it( mKeyListView ) ; it.current() ; ++it )
00478 ++total;
00479 mStatusLabel->setText( i18n( "%n Key.","%n Keys.", total ) );
00480 }
00481
00482
00483
00484
00485
00486
00487
00488
00489 static std::set<std::string> extractKeyFingerprints( const QPtrList<Kleo::KeyListViewItem> & items ) {
00490 std::set<std::string> result;
00491 for ( QPtrListIterator<Kleo::KeyListViewItem> it( items ) ; it.current() ; ++it )
00492 if ( const char * fpr = it.current()->key().primaryFingerprint() )
00493 result.insert( fpr );
00494 return result;
00495 }
00496
00497 static QStringList stringlistFromSet( const std::set<std::string> & set ) {
00498
00499 QStringList sl;
00500 for ( std::set<std::string>::const_iterator it = set.begin() ; it != set.end() ; ++it )
00501
00502 sl.push_back( QString::fromLatin1( it->c_str() ) );
00503 return sl;
00504 }
00505
00506 void CertManager::slotRefreshKeys() {
00507 const QStringList keys = stringlistFromSet( extractKeyFingerprints( mKeyListView->selectedItems() ) );
00508 Kleo::RefreshKeysJob * job = Kleo::CryptoBackendFactory::instance()->smime()->refreshKeysJob();
00509 assert( job );
00510
00511 connect( job, SIGNAL(result(const GpgME::Error&)),
00512 this, SLOT(slotRefreshKeysResult(const GpgME::Error&)) );
00513
00514 connectJobToStatusBarProgress( job, i18n("Refreshing keys...") );
00515 if ( const GpgME::Error err = job->start( keys ) )
00516 slotRefreshKeysResult( err );
00517 }
00518
00519 void CertManager::slotRefreshKeysResult( const GpgME::Error & err ) {
00520 disconnectJobFromStatusBarProgress( err );
00521 if ( err.isCanceled() )
00522 return;
00523 if ( err )
00524 KMessageBox::error( this, i18n("An error occurred while trying to refresh "
00525 "keys:\n%1").arg( QString::fromLocal8Bit( err.asString() ) ),
00526 i18n("Refreshing Keys Failed") );
00527 }
00528
00529 static void showKeyListError( QWidget * parent, const GpgME::Error & err ) {
00530 assert( err );
00531 const QString msg = i18n( "<qt><p>An error occurred while fetching "
00532 "the certificates from the backend:</p>"
00533 "<p><b>%1</b></p></qt>" )
00534 .arg( QString::fromLocal8Bit( err.asString() ) );
00535
00536 KMessageBox::error( parent, msg, i18n( "Certificate Listing Failed" ) );
00537 }
00538
00539 void CertManager::slotSearch() {
00540 mPreviouslySelectedFingerprints.clear();
00541
00542 mKeyListView->clear();
00543 mCurrentQuery = mLineEditAction->text();
00544 startKeyListing( false, false, mCurrentQuery );
00545 }
00546
00547 void CertManager::startRedisplay( bool validate ) {
00548 mPreviouslySelectedFingerprints = extractKeyFingerprints( mKeyListView->selectedItems() );
00549 if ( mPreviouslySelectedFingerprints.empty() )
00550 startKeyListing( validate, true, mCurrentQuery );
00551 else
00552 startKeyListing( validate, true, mPreviouslySelectedFingerprints );
00553 }
00554
00555 void CertManager::startKeyListing( bool validating, bool refresh, const std::set<std::string> & patterns ) {
00556 startKeyListing( validating, refresh, stringlistFromSet( patterns ) );
00557 }
00558
00559 void CertManager::startKeyListing( bool validating, bool refresh, const QStringList & patterns ) {
00560 mRemote = mNextFindRemote;
00561 mLineEditAction->setEnabled( false );
00562 mComboAction->setEnabled( false );
00563 mFindAction->setEnabled( false );
00564
00565 Kleo::KeyListJob * job = 0;
00566 if ( !validating && !refresh && mKeyListView->hierarchical() && !patterns.empty() )
00567 job = new Kleo::HierarchicalKeyListJob( Kleo::CryptoBackendFactory::instance()->smime(),
00568 mRemote, false, validating );
00569 else
00570 job = Kleo::CryptoBackendFactory::instance()->smime()->keyListJob( mRemote, false, validating );
00571 assert( job );
00572
00573 connect( job, SIGNAL(nextKey(const GpgME::Key&)),
00574 mKeyListView, refresh ? SLOT(slotRefreshKey(const GpgME::Key&)) : SLOT(slotAddKey(const GpgME::Key&)) );
00575 connect( job, SIGNAL(result(const GpgME::KeyListResult&)),
00576 this, SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
00577
00578 connectJobToStatusBarProgress( job, i18n("Fetching keys...") );
00579
00580 const GpgME::Error err = job->start( patterns ) ;
00581 if ( err ) {
00582 showKeyListError( this, err );
00583 return;
00584 }
00585 mProgressBar->setProgress( 0, 0 );
00586 }
00587
00588 static void selectKeys( Kleo::KeyListView * lv, const std::set<std::string> & fprs ) {
00589 if ( !lv || fprs.empty() )
00590 return;
00591 for ( QListViewItemIterator it( lv ) ; it.current() ; ++it )
00592 if ( Kleo::KeyListViewItem * item = Kleo::lvi_cast<Kleo::KeyListViewItem>( it.current() ) ) {
00593 const char * fpr = item->key().primaryFingerprint();
00594 item->setSelected( fpr && fprs.find( fpr ) != fprs.end() );
00595 }
00596 }
00597
00598 void CertManager::slotKeyListResult( const GpgME::KeyListResult & res ) {
00599 if ( res.error() )
00600 showKeyListError( this, res.error() );
00601 else if ( res.isTruncated() )
00602 KMessageBox::information( this,
00603 i18n("The query result has been truncated.\n"
00604 "Either the local or a remote limit on "
00605 "the maximum number of returned hits has "
00606 "been exceeded.\n"
00607 "You can try to increase the local limit "
00608 "in the configuration dialog, but if one "
00609 "of the configured servers is the limiting "
00610 "factor, you have to refine your search.") );
00611
00612 mLineEditAction->setEnabled( true );
00613 mComboAction->setEnabled( true );
00614 mFindAction->setEnabled( true );
00615
00616 mLineEditAction->focusAll();
00617 disconnectJobFromStatusBarProgress( res.error() );
00618 selectKeys( mKeyListView, mPreviouslySelectedFingerprints );
00619 }
00620
00621 void CertManager::slotContextMenu(Kleo::KeyListViewItem* item, const QPoint& point) {
00622 if ( !item )
00623 return;
00624 if ( QPopupMenu * popup = static_cast<QPopupMenu*>(factory()->container("listview_popup",this)) )
00625 popup->exec( point );
00626 }
00627
00631 void CertManager::newCertificate()
00632 {
00633 CertificateWizardImpl wizard( this );
00634 wizard.exec();
00635 }
00636
00641 void CertManager::revokeCertificate()
00642 {
00643 qDebug("Not Yet Implemented");
00644 }
00645
00650 void CertManager::extendCertificate()
00651 {
00652 qDebug("Not Yet Implemented");
00653 }
00654
00655
00656
00657
00658
00659
00660
00661
00662
00666 void CertManager::slotImportCertFromFile()
00667 {
00668 const QString filter = "application/x-x509-ca-cert application/x-pkcs12 application/pkcs7-mime";
00669
00670 slotImportCertFromFile( KFileDialog::getOpenURL( QString::null, filter, this,
00671 i18n( "Select Certificate File" ) ) );
00672 }
00673
00674 void CertManager::slotImportCertFromFile( const KURL & certURL )
00675 {
00676 if ( !certURL.isValid() )
00677 return;
00678
00679 mPreviouslySelectedFingerprints.clear();
00680
00681
00682 updateImportActions( false );
00683
00684
00685 KIOext::StoredTransferJob* importJob = KIOext::storedGet( certURL );
00686 importJob->setWindow( this );
00687 connect( importJob, SIGNAL(result(KIO::Job*)), SLOT(slotImportResult(KIO::Job*)) );
00688 }
00689
00690 void CertManager::slotImportResult( KIO::Job* job )
00691 {
00692 if ( job->error() ) {
00693 job->showErrorDialog();
00694 } else {
00695 KIOext::StoredTransferJob* trJob = static_cast<KIOext::StoredTransferJob *>( job );
00696 startCertificateImport( trJob->data(), trJob->url().fileName() );
00697 }
00698
00699 updateImportActions( true );
00700 }
00701
00702 static void showCertificateDownloadError( QWidget * parent, const GpgME::Error & err, const QString& certDisplayName ) {
00703 assert( err );
00704 const QString msg = i18n( "<qt><p>An error occurred while trying "
00705 "to download the certificate %1:</p>"
00706 "<p><b>%2</b></p></qt>" )
00707 .arg( certDisplayName )
00708 .arg( QString::fromLocal8Bit( err.asString() ) );
00709
00710 KMessageBox::error( parent, msg, i18n( "Certificate Download Failed" ) );
00711 }
00712
00713 void CertManager::slotDownloadCertificate() {
00714 mPreviouslySelectedFingerprints.clear();
00715 QPtrList<Kleo::KeyListViewItem> items = mKeyListView->selectedItems();
00716 for ( QPtrListIterator<Kleo::KeyListViewItem> it( items ) ; it.current() ; ++it )
00717 if ( !it.current()->key().isNull() )
00718 if ( const char * fpr = it.current()->key().primaryFingerprint() )
00719 slotStartCertificateDownload( fpr, it.current()->text(0) );
00720 }
00721
00722
00723 void CertManager::slotStartCertificateDownload( const QString& fingerprint, const QString& displayName ) {
00724 if ( fingerprint.isEmpty() )
00725 return;
00726
00727 Kleo::DownloadJob * job =
00728 Kleo::CryptoBackendFactory::instance()->smime()->downloadJob( false );
00729 assert( job );
00730
00731 connect( job, SIGNAL(result(const GpgME::Error&,const QByteArray&)),
00732 SLOT(slotCertificateDownloadResult(const GpgME::Error&,const QByteArray&)) );
00733
00734 connectJobToStatusBarProgress( job, i18n("Fetching certificate from server...") );
00735
00736 const GpgME::Error err = job->start( fingerprint );
00737 if ( err )
00738 showCertificateDownloadError( this, err, displayName );
00739 else {
00740 mProgressBar->setProgress( 0, 0 );
00741 mJobsDisplayNameMap.insert( job, displayName );
00742 }
00743 }
00744
00745 QString CertManager::displayNameForJob( const Kleo::Job *job )
00746 {
00747 JobsDisplayNameMap::iterator it = mJobsDisplayNameMap.find( job );
00748 QString displayName;
00749 if ( it != mJobsDisplayNameMap.end() ) {
00750 displayName = *it;
00751 mJobsDisplayNameMap.remove( it );
00752 } else {
00753 kdWarning() << "Job not found in map: " << job << endl;
00754 }
00755 return displayName;
00756 }
00757
00758
00759 void CertManager::slotCertificateDownloadResult( const GpgME::Error & err, const QByteArray & keyData ) {
00760
00761 QString displayName = displayNameForJob( static_cast<const Kleo::Job *>( sender() ) );
00762
00763 if ( err )
00764 showCertificateDownloadError( this, err, displayName );
00765 else
00766 startCertificateImport( keyData, displayName );
00767 disconnectJobFromStatusBarProgress( err );
00768 }
00769
00770 static void showCertificateImportError( QWidget * parent, const GpgME::Error & err, const QString& certDisplayName ) {
00771 assert( err );
00772 const QString msg = i18n( "<qt><p>An error occurred while trying "
00773 "to import the certificate %1:</p>"
00774 "<p><b>%2</b></p></qt>" )
00775 .arg( certDisplayName )
00776 .arg( QString::fromLocal8Bit( err.asString() ) );
00777 KMessageBox::error( parent, msg, i18n( "Certificate Import Failed" ) );
00778 }
00779
00780 void CertManager::startCertificateImport( const QByteArray & keyData, const QString& certDisplayName ) {
00781 Kleo::ImportJob * job = Kleo::CryptoBackendFactory::instance()->smime()->importJob();
00782 assert( job );
00783
00784 connect( job, SIGNAL(result(const GpgME::ImportResult&)),
00785 SLOT(slotCertificateImportResult(const GpgME::ImportResult&)) );
00786
00787 connectJobToStatusBarProgress( job, i18n("Importing certificates...") );
00788
00789 kdDebug() << "Importing certificate. keyData size:" << keyData.size() << endl;
00790 const GpgME::Error err = job->start( keyData );
00791 if ( err )
00792 showCertificateImportError( this, err, certDisplayName );
00793 else {
00794 mProgressBar->setProgress( 0, 0 );
00795 mJobsDisplayNameMap.insert( job, certDisplayName );
00796 }
00797 }
00798
00799 void CertManager::slotCertificateImportResult( const GpgME::ImportResult & res ) {
00800 QString displayName = displayNameForJob( static_cast<const Kleo::Job *>( sender() ) );
00801
00802 if ( res.error().isCanceled() ) {
00803
00804 } else if ( res.error() ) {
00805 showCertificateImportError( this, res.error(), displayName );
00806 } else {
00807
00808 const QString normalLine = i18n("<tr><td align=\"right\">%1</td><td>%2</td></tr>");
00809 const QString boldLine = i18n("<tr><td align=\"right\"><b>%1</b></td><td>%2</td></tr>");
00810
00811 QStringList lines;
00812 lines.push_back( normalLine.arg( i18n("Total number processed:"),
00813 QString::number( res.numConsidered() ) ) );
00814 lines.push_back( normalLine.arg( i18n("Imported:"),
00815 QString::number( res.numImported() ) ) );
00816 if ( res.newSignatures() )
00817 lines.push_back( normalLine.arg( i18n("New signatures:"),
00818 QString::number( res.newSignatures() ) ) );
00819 if ( res.newUserIDs() )
00820 lines.push_back( normalLine.arg( i18n("New user IDs:"),
00821 QString::number( res.newUserIDs() ) ) );
00822 if ( res.numKeysWithoutUserID() )
00823 lines.push_back( normalLine.arg( i18n("Keys without user IDs:"),
00824 QString::number( res.numKeysWithoutUserID() ) ) );
00825 if ( res.newSubkeys() )
00826 lines.push_back( normalLine.arg( i18n("New subkeys:"),
00827 QString::number( res.newSubkeys() ) ) );
00828 if ( res.newRevocations() )
00829 lines.push_back( boldLine.arg( i18n("Newly revoked:"),
00830 QString::number( res.newRevocations() ) ) );
00831 if ( res.notImported() )
00832 lines.push_back( boldLine.arg( i18n("Not imported:"),
00833 QString::number( res.notImported() ) ) );
00834 if ( res.numUnchanged() )
00835 lines.push_back( normalLine.arg( i18n("Unchanged:"),
00836 QString::number( res.numUnchanged() ) ) );
00837 if ( res.numSecretKeysConsidered() )
00838 lines.push_back( normalLine.arg( i18n("Secret keys processed:"),
00839 QString::number( res.numSecretKeysConsidered() ) ) );
00840 if ( res.numSecretKeysImported() )
00841 lines.push_back( normalLine.arg( i18n("Secret keys imported:"),
00842 QString::number( res.numSecretKeysImported() ) ) );
00843 if ( res.numSecretKeysConsidered() - res.numSecretKeysImported() - res.numSecretKeysUnchanged() > 0 )
00844 lines.push_back( boldLine.arg( i18n("Secret keys <em>not</em> imported:"),
00845 QString::number( res.numSecretKeysConsidered()
00846 - res.numSecretKeysImported()
00847 - res.numSecretKeysUnchanged() ) ) );
00848 if ( res.numSecretKeysUnchanged() )
00849 lines.push_back( normalLine.arg( i18n("Secret keys unchanged:"),
00850 QString::number( res.numSecretKeysUnchanged() ) ) );
00851
00852 KMessageBox::information( this,
00853 i18n( "<qt><p>Detailed results of importing %1:</p>"
00854 "<table>%2</table></qt>" )
00855 .arg( displayName ).arg( lines.join( QString::null ) ),
00856 i18n( "Certificate Import Result" ) );
00857
00858 disconnectJobFromStatusBarProgress( res.error() );
00859
00860 const std::vector<GpgME::Import> imports = res.imports();
00861 for ( std::vector<GpgME::Import>::const_iterator it = imports.begin() ; it != imports.end() ; ++it )
00862 mPreviouslySelectedFingerprints.insert( it->fingerprint() );
00863 }
00864 importNextURLOrRedisplay();
00865 }
00866
00867
00868
00873 void CertManager::slotDirmngrExited() {
00874 if ( !mDirmngrProc->normalExit() )
00875 KMessageBox::error( this, i18n( "The GpgSM process that tried to import the CRL file ended prematurely because of an unexpected error." ), i18n( "Certificate Manager Error" ) );
00876 else if ( mDirmngrProc->exitStatus() )
00877 KMessageBox::error( this, i18n( "An error occurred when trying to import the CRL file. The output from GpgSM was:\n%1").arg( mErrorbuffer ), i18n( "Certificate Manager Error" ) );
00878 else
00879 KMessageBox::information( this, i18n( "CRL file imported successfully." ), i18n( "Certificate Manager Information" ) );
00880
00881 delete mDirmngrProc; mDirmngrProc = 0;
00882 if ( !mImportCRLTempFile.isEmpty() )
00883 QFile::remove( mImportCRLTempFile );
00884 updateImportActions( true );
00885 }
00886
00890 void CertManager::importCRLFromFile() {
00891 QString filter = QString("*.crl *.arl *-crl.der *-arl.der|") + i18n("Certificate Revocation List (*.crl *.arl *-crl.der *-arl.der)");
00892 KURL url = KFileDialog::getOpenURL( QString::null,
00893 filter,
00894 this,
00895 i18n( "Select CRL File" ) );
00896 if ( url.isValid() ) {
00897 updateImportActions( false );
00898 if ( url.isLocalFile() ) {
00899 startImportCRL( url.path(), false );
00900 updateImportActions( true );
00901 } else {
00902 KTempFile tempFile;
00903 KURL destURL;
00904 destURL.setPath( tempFile.name() );
00905 KIO::Job* copyJob = KIO::file_copy( url, destURL, 0600, true, false );
00906 copyJob->setWindow( this );
00907 connect( copyJob, SIGNAL( result( KIO::Job * ) ),
00908 SLOT( slotImportCRLJobFinished( KIO::Job * ) ) );
00909 }
00910 }
00911 }
00912
00913 void CertManager::slotImportCRLJobFinished( KIO::Job *job )
00914 {
00915 KIO::FileCopyJob* fcjob = static_cast<KIO::FileCopyJob*>( job );
00916 QString tempFilePath = fcjob->destURL().path();
00917 if ( job->error() ) {
00918 job->showErrorDialog();
00919 QFile::remove( tempFilePath );
00920 updateImportActions( true );
00921 return;
00922 }
00923 startImportCRL( tempFilePath, true );
00924 }
00925
00926 bool CertManager::connectAndStartDirmngr( const char * slot, const char * processname ) {
00927 assert( slot );
00928 assert( processname );
00929 assert( mDirmngrProc );
00930 mErrorbuffer = QString::null;
00931 connect( mDirmngrProc, SIGNAL(processExited(KProcess*)), slot );
00932 connect( mDirmngrProc, SIGNAL(receivedStderr(KProcess*,char*,int) ),
00933 this, SLOT(slotStderr(KProcess*,char*,int)) );
00934 if( !mDirmngrProc->start( KProcess::NotifyOnExit, KProcess::Stderr ) ) {
00935 delete mDirmngrProc; mDirmngrProc = 0;
00936 KMessageBox::error( this, i18n( "Unable to start %1 process. Please check your installation." ).arg( processname ), i18n( "Certificate Manager Error" ) );
00937 return false;
00938 }
00939 return true;
00940 }
00941
00942 void CertManager::startImportCRL( const QString& filename, bool isTempFile )
00943 {
00944 assert( !mDirmngrProc );
00945 mImportCRLTempFile = isTempFile ? filename : QString::null;
00946 mDirmngrProc = new KProcess();
00947 *mDirmngrProc << "gpgsm" << "--call-dirmngr" << "loadcrl" << filename;
00948 if ( !connectAndStartDirmngr( SLOT(slotDirmngrExited()), "gpgsm" ) ) {
00949 updateImportActions( true );
00950 if ( isTempFile )
00951 QFile::remove( mImportCRLTempFile );
00952 }
00953 }
00954
00955 void CertManager::startClearCRLs() {
00956 assert( !mDirmngrProc );
00957 mDirmngrProc = new KProcess();
00958 *mDirmngrProc << "dirmngr" << "--flush";
00959
00960 connectAndStartDirmngr( SLOT(slotClearCRLsResult()), "dirmngr" );
00961 }
00962
00963 void CertManager::slotStderr( KProcess*, char* buf, int len ) {
00964 mErrorbuffer += QString::fromLocal8Bit( buf, len );
00965 }
00966
00970 void CertManager::importCRLFromLDAP()
00971 {
00972 qDebug("Not Yet Implemented");
00973 }
00974
00975 void CertManager::slotViewCRLs() {
00976 if ( !mCrlView )
00977 mCrlView = new CRLView( this );
00978
00979 mCrlView->show();
00980 mCrlView->slotUpdateView();
00981 }
00982
00983
00984 void CertManager::slotClearCRLs() {
00985 startClearCRLs();
00986 }
00987
00988 void CertManager::slotClearCRLsResult() {
00989 assert( mDirmngrProc );
00990 if ( !mDirmngrProc->normalExit() )
00991 KMessageBox::error( this, i18n( "The DirMngr process that tried to clear the CRL cache ended prematurely because of an unexpected error." ), i18n( "Certificate Manager Error" ) );
00992 else if ( mDirmngrProc->exitStatus() )
00993 KMessageBox::error( this, i18n( "An error occurred when trying to clear the CRL cache. The output from DirMngr was:\n%1").arg( mErrorbuffer ), i18n( "Certificate Manager Error" ) );
00994 else
00995 KMessageBox::information( this, i18n( "CRL cache cleared successfully." ), i18n( "Certificate Manager Information" ) );
00996 delete mDirmngrProc; mDirmngrProc = 0;
00997 }
00998
00999 static void showDeleteError( QWidget * parent, const GpgME::Error & err ) {
01000 assert( err );
01001 const QString msg = i18n("<qt><p>An error occurred while trying to delete "
01002 "the certificates:</p>"
01003 "<p><b>%1</b></p></qt>")
01004 .arg( QString::fromLocal8Bit( err.asString() ) );
01005 KMessageBox::error( parent, msg, i18n("Certificate Deletion Failed") );
01006 }
01007
01008 static bool ByFingerprint( const GpgME::Key & left, const GpgME::Key & right ) {
01009 return qstricmp( left.primaryFingerprint(), right.primaryFingerprint() ) < 0 ;
01010 }
01011
01012 static bool WithRespectToFingerprints( const GpgME::Key & left, const GpgME::Key & right ) {
01013 return qstricmp( left.primaryFingerprint(), right.primaryFingerprint() ) == 0;
01014 }
01015
01016 void CertManager::slotDeleteCertificate() {
01017 mItemsToDelete = mKeyListView->selectedItems();
01018 if ( mItemsToDelete.isEmpty() )
01019 return;
01020 std::vector<GpgME::Key> keys;
01021 keys.reserve( mItemsToDelete.count() );
01022 QStringList keyDisplayNames;
01023 for ( QPtrListIterator<Kleo::KeyListViewItem> it( mItemsToDelete ) ; it.current() ; ++it )
01024 if ( !it.current()->key().isNull() ) {
01025 keys.push_back( it.current()->key() );
01026 keyDisplayNames.push_back( it.current()->text( 0 ) );
01027 }
01028 if ( keys.empty() )
01029 return;
01030
01031 if ( !mHierarchyAnalyser ) {
01032 mHierarchyAnalyser = new HierarchyAnalyser( this, "mHierarchyAnalyser" );
01033 Kleo::KeyListJob * job = Kleo::CryptoBackendFactory::instance()->smime()->keyListJob();
01034 assert( job );
01035 connect( job, SIGNAL(nextKey(const GpgME::Key&)),
01036 mHierarchyAnalyser, SLOT(slotNextKey(const GpgME::Key&)) );
01037 connect( job, SIGNAL(result(const GpgME::KeyListResult&)),
01038 this, SLOT(slotDeleteCertificate()) );
01039 connectJobToStatusBarProgress( job, i18n("Checking key dependencies...") );
01040 if ( const GpgME::Error error = job->start( QStringList() ) ) {
01041 showKeyListError( this, error );
01042 delete mHierarchyAnalyser; mHierarchyAnalyser = 0;
01043 }
01044 return;
01045 } else
01046 disconnectJobFromStatusBarProgress( 0 );
01047
01048 std::vector<GpgME::Key> keysToDelete = keys;
01049 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it )
01050 if ( !it->isNull() ) {
01051 const std::vector<GpgME::Key> subjects
01052 = mHierarchyAnalyser->subjectsForIssuerRecursive( it->primaryFingerprint() );
01053 keysToDelete.insert( keysToDelete.end(), subjects.begin(), subjects.end() );
01054 }
01055
01056 std::sort( keysToDelete.begin(), keysToDelete.end(), ByFingerprint );
01057 keysToDelete.erase( std::unique( keysToDelete.begin(), keysToDelete.end(),
01058 WithRespectToFingerprints ),
01059 keysToDelete.end() );
01060
01061 delete mHierarchyAnalyser; mHierarchyAnalyser = 0;
01062
01063 if ( keysToDelete.size() > keys.size() )
01064 if ( KMessageBox::warningContinueCancel( this,
01065 i18n("Some or all of the selected "
01066 "certificates are issuers (CA certificates) "
01067 "for other, non-selected certificates.\n"
01068 "Deleting a CA certificate will also delete "
01069 "all certificates issued by it."),
01070 i18n("Deleting CA Certificates") )
01071 != KMessageBox::Continue )
01072 return;
01073
01074 const QString msg = keysToDelete.size() > keys.size()
01075 ? i18n("Do you really want to delete this certificate and the %1 certificates it certified?",
01076 "Do you really want to delete these %n certificates and the %1 certificates they certified?",
01077 keys.size() ).arg( keysToDelete.size() - keys.size() )
01078 : i18n("Do you really want to delete this certificate?",
01079 "Do you really want to delete these %n certificates?", keys.size() ) ;
01080
01081 if ( KMessageBox::warningContinueCancelList( this, msg, keyDisplayNames,
01082 i18n( "Delete Certificates" ),
01083 KGuiItem( i18n( "Delete" ), "editdelete" ),
01084 "ConfirmDeleteCert", KMessageBox::Dangerous )
01085 != KMessageBox::Continue )
01086 return;
01087
01088 if ( Kleo::DeleteJob * job = Kleo::CryptoBackendFactory::instance()->smime()->deleteJob() )
01089 job->slotCancel();
01090 else {
01091 QString str = keys.size() == 1
01092 ? i18n("<qt><p>An error occurred while trying to delete "
01093 "the certificate:</p>"
01094 "<p><b>%1</b><p></qt>" )
01095 : i18n( "<qt><p>An error occurred while trying to delete "
01096 "the certificates:</p>"
01097 "<p><b>%1</b><p></qt>" );
01098 KMessageBox::error( this,
01099 str.arg( i18n("Operation not supported by the backend.") ),
01100 i18n("Certificate Deletion Failed") );
01101 }
01102
01103 mItemsToDelete.clear();
01104 for ( std::vector<GpgME::Key>::const_iterator it = keysToDelete.begin() ; it != keysToDelete.end() ; ++it )
01105 if ( Kleo::KeyListViewItem * item = mKeyListView->itemByFingerprint( it->primaryFingerprint() ) )
01106 mItemsToDelete.append( item );
01107
01108 Kleo::MultiDeleteJob * job = new Kleo::MultiDeleteJob( Kleo::CryptoBackendFactory::instance()->smime() );
01109 assert( job );
01110
01111 connect( job, SIGNAL(result(const GpgME::Error&,const GpgME::Key&)),
01112 SLOT(slotDeleteResult(const GpgME::Error&,const GpgME::Key&)) );
01113
01114 connectJobToStatusBarProgress( job, i18n("Deleting keys...") );
01115
01116 const GpgME::Error err = job->start( keys, true );
01117 if ( err )
01118 showDeleteError( this, err );
01119 else
01120 mProgressBar->setProgress( 0, 0 );
01121 }
01122
01123 void CertManager::slotDeleteResult( const GpgME::Error & err, const GpgME::Key & ) {
01124 if ( err )
01125 showDeleteError( this, err );
01126 else {
01127 const int infinity = 100;
01128 mItemsToDelete.setAutoDelete( true );
01129 for ( int i = 0 ; i < infinity ; ++i ) {
01130 QPtrListIterator<Kleo::KeyListViewItem> it( mItemsToDelete );
01131 while ( Kleo::KeyListViewItem * cur = it.current() ) {
01132 ++it;
01133 if ( cur->childCount() == 0 ) {
01134 mItemsToDelete.remove( cur );
01135 }
01136 }
01137 if ( mItemsToDelete.isEmpty() )
01138 break;
01139 }
01140 mItemsToDelete.setAutoDelete( false );
01141 Q_ASSERT( mItemsToDelete.isEmpty() );
01142 mItemsToDelete.clear();
01143 }
01144 disconnectJobFromStatusBarProgress( err );
01145 }
01146
01147 void CertManager::slotViewDetails( Kleo::KeyListViewItem * item ) {
01148 if ( !item || item->key().isNull() )
01149 return;
01150
01151
01152 KDialogBase * dialog = new KDialogBase( this, "dialog", false, i18n("Additional Information for Key"), KDialogBase::Close, KDialogBase::Close );
01153
01154 CertificateInfoWidgetImpl * top = new CertificateInfoWidgetImpl( item->key(), isRemote(), dialog );
01155 dialog->setMainWidget( top );
01156
01157 connect( top, SIGNAL(requestCertificateDownload(const QString&, const QString&)),
01158 SLOT(slotStartCertificateDownload(const QString&, const QString&)) );
01159 dialog->show();
01160 }
01161
01162 void CertManager::slotViewDetails()
01163 {
01164 QPtrList<Kleo::KeyListViewItem> items = mKeyListView->selectedItems();
01165 if ( items.isEmpty() )
01166 return;
01167
01168
01169
01170 slotViewDetails( items.first() );
01171 }
01172
01173 void CertManager::slotSelectionChanged()
01174 {
01175 mKeyListView->flushKeys();
01176 bool b = mKeyListView->hasSelection();
01177 mExportCertificateAction->setEnabled( b );
01178 mViewCertDetailsAction->setEnabled( b );
01179 mDeleteCertificateAction->setEnabled( b );
01180 #ifdef NOT_IMPLEMENTED_ANYWAY
01181 mRevokeCertificateAction->setEnabled( b );
01182 mExtendCertificateAction->setEnabled( b );
01183 #endif
01184 mDownloadCertificateAction->setEnabled( b && mRemote );
01185 mValidateCertificateAction->setEnabled( !mRemote );
01186 }
01187
01188 void CertManager::slotExportCertificate() {
01189 QPtrList<Kleo::KeyListViewItem> items = mKeyListView->selectedItems();
01190 if ( items.isEmpty() )
01191 return;
01192
01193 QStringList fingerprints;
01194 for ( QPtrListIterator<Kleo::KeyListViewItem> it( items ) ; it.current() ; ++it )
01195 if ( !it.current()->key().isNull() )
01196 if ( const char * fpr = it.current()->key().primaryFingerprint() )
01197 fingerprints.push_back( fpr );
01198
01199 startCertificateExport( fingerprints );
01200 }
01201
01202 static void showCertificateExportError( QWidget * parent, const GpgME::Error & err ) {
01203 assert( err );
01204 const QString msg = i18n("<qt><p>An error occurred while trying to export "
01205 "the certificate:</p>"
01206 "<p><b>%1</b></p></qt>")
01207 .arg( QString::fromLocal8Bit( err.asString() ) );
01208 KMessageBox::error( parent, msg, i18n("Certificate Export Failed") );
01209 }
01210
01211 void CertManager::startCertificateExport( const QStringList & fingerprints ) {
01212 if ( fingerprints.empty() )
01213 return;
01214
01215
01216
01217 Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->smime()->publicKeyExportJob( true );
01218 assert( job );
01219
01220 connect( job, SIGNAL(result(const GpgME::Error&,const QByteArray&)),
01221 SLOT(slotCertificateExportResult(const GpgME::Error&,const QByteArray&)) );
01222
01223 connectJobToStatusBarProgress( job, i18n("Exporting certificate...") );
01224
01225 const GpgME::Error err = job->start( fingerprints );
01226 if ( err )
01227 showCertificateExportError( this, err );
01228 else
01229 mProgressBar->setProgress( 0, 0 );
01230 }
01231
01232
01233 static bool checkOverwrite( const KURL& url, bool& overwrite, QWidget* w )
01234 {
01235 if ( KIO::NetAccess::exists( url, false , w ) ) {
01236 if ( KMessageBox::Cancel ==
01237 KMessageBox::warningContinueCancel(
01238 w,
01239 i18n( "A file named \"%1\" already exists. "
01240 "Are you sure you want to overwrite it?" ).arg( url.prettyURL() ),
01241 i18n( "Overwrite File?" ),
01242 i18n( "&Overwrite" ) ) )
01243 return false;
01244 overwrite = true;
01245 }
01246 return true;
01247 }
01248
01249 void CertManager::slotCertificateExportResult( const GpgME::Error & err, const QByteArray & data ) {
01250 disconnectJobFromStatusBarProgress( err );
01251 if ( err ) {
01252 showCertificateExportError( this, err );
01253 return;
01254 }
01255
01256 kdDebug() << "CertManager::slotCertificateExportResult(): got " << data.size() << " bytes" << endl;
01257
01258 const QString filter = QString("*.pem|") + i18n("ASCII Armored Certificate Bundles (*.pem)");
01259 const KURL url = KFileDialog::getOpenURL( QString::null,
01260 filter,
01261 this,
01262 i18n( "Save Certificate" ) );
01263 if ( !url.isValid() )
01264 return;
01265
01266 bool overwrite = false;
01267 if ( !checkOverwrite( url, overwrite, this ) )
01268 return;
01269
01270 KIO::Job* uploadJob = KIOext::put( data, url, -1, overwrite, false );
01271 uploadJob->setWindow( this );
01272 connect( uploadJob, SIGNAL( result( KIO::Job* ) ),
01273 this, SLOT( slotUploadResult( KIO::Job* ) ) );
01274 }
01275
01276
01277 void CertManager::slotExportSecretKey() {
01278 Kleo::KeySelectionDialog dlg( i18n("Secret Key Export"),
01279 i18n("Select the secret key to export "
01280 "(<b>Warning: The PKCS#12 format is insecure; "
01281 "exporting secret keys is discouraged</b>):"),
01282 std::vector<GpgME::Key>(),
01283 Kleo::KeySelectionDialog::SecretKeys|Kleo::KeySelectionDialog::SMIMEKeys,
01284 false ,
01285 false ,
01286 this, "secret key export key selection dialog" );
01287
01288
01289 if ( dlg.exec() != QDialog::Accepted )
01290 return;
01291
01292 startSecretKeyExport( dlg.fingerprint() );
01293 }
01294
01295 static void showSecretKeyExportError( QWidget * parent, const GpgME::Error & err ) {
01296 assert( err );
01297 const QString msg = i18n("<qt><p>An error occurred while trying to export "
01298 "the secret key:</p>"
01299 "<p><b>%1</b></p></qt>")
01300 .arg( QString::fromLocal8Bit( err.asString() ) );
01301 KMessageBox::error( parent, msg, i18n("Secret-Key Export Failed") );
01302 }
01303
01304 void CertManager::startSecretKeyExport( const QString & fingerprint ) {
01305 if ( fingerprint.isEmpty() )
01306 return;
01307
01308
01309 Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->smime()->secretKeyExportJob( false );
01310 assert( job );
01311
01312 connect( job, SIGNAL(result(const GpgME::Error&,const QByteArray&)),
01313 SLOT(slotSecretKeyExportResult(const GpgME::Error&,const QByteArray&)) );
01314
01315 connectJobToStatusBarProgress( job, i18n("Exporting secret key...") );
01316
01317 const GpgME::Error err = job->start( fingerprint );
01318 if ( err )
01319 showSecretKeyExportError( this, err );
01320 else
01321 mProgressBar->setProgress( 0, 0 );
01322 }
01323
01324 void CertManager::slotSecretKeyExportResult( const GpgME::Error & err, const QByteArray & data ) {
01325 disconnectJobFromStatusBarProgress( err );
01326 if ( err ) {
01327 showSecretKeyExportError( this, err );
01328 return;
01329 }
01330
01331 kdDebug() << "CertManager::slotSecretKeyExportResult(): got " << data.size() << " bytes" << endl;
01332 QString filter = QString("*.p12|") + i18n("PKCS#12 Key Bundle (*.p12)");
01333 KURL url = KFileDialog::getOpenURL( QString::null,
01334 filter,
01335 this,
01336 i18n( "Save Certificate" ) );
01337 if ( !url.isValid() )
01338 return;
01339
01340 bool overwrite = false;
01341 if ( !checkOverwrite( url, overwrite, this ) )
01342 return;
01343
01344 KIO::Job* uploadJob = KIOext::put( data, url, -1, overwrite, false );
01345 uploadJob->setWindow( this );
01346 connect( uploadJob, SIGNAL( result( KIO::Job* ) ),
01347 this, SLOT( slotUploadResult( KIO::Job* ) ) );
01348 }
01349
01350 void CertManager::slotUploadResult( KIO::Job* job )
01351 {
01352 if ( job->error() )
01353 job->showErrorDialog();
01354 }
01355
01356 void CertManager::slotDropped(const KURL::List& lst)
01357 {
01358 mURLsToImport = lst;
01359 if ( !lst.empty() )
01360 importNextURLOrRedisplay();
01361 }
01362
01363 void CertManager::importNextURLOrRedisplay()
01364 {
01365 if ( !mURLsToImport.empty() ) {
01366
01367 KURL url = mURLsToImport.front();
01368 mURLsToImport.pop_front();
01369 slotImportCertFromFile( url );
01370 } else {
01371 if ( isRemote() )
01372 return;
01373 startKeyListing( false, true, mPreviouslySelectedFingerprints );
01374 }
01375 }
01376
01377 void CertManager::slotStartWatchGnuPG()
01378 {
01379 KProcess certManagerProc;
01380 certManagerProc << "kwatchgnupg";
01381
01382 if( !certManagerProc.start( KProcess::DontCare ) )
01383 KMessageBox::error( this, i18n( "Could not start GnuPG LogViewer (kwatchgnupg). "
01384 "Please check your installation!" ),
01385 i18n( "Kleopatra Error" ) );
01386 }
01387
01388 #include "certmanager.moc"