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