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