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