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
00893 QString filter = QString("*.crl *.arl *-crl.der *-arl.der|") + i18n("Certificate Revocation List, DER encoded (*.crl *.arl *-crl.der *-arl.der)");
00894 KURL url = KFileDialog::getOpenURL( QString::null,
00895 filter,
00896 this,
00897 i18n( "Select CRL File" ) );
00898 if ( url.isValid() ) {
00899 updateImportActions( false );
00900 if ( url.isLocalFile() ) {
00901 startImportCRL( url.path(), false );
00902 updateImportActions( true );
00903 } else {
00904 KTempFile tempFile;
00905 KURL destURL;
00906 destURL.setPath( tempFile.name() );
00907 KIO::Job* copyJob = KIO::file_copy( url, destURL, 0600, true, false );
00908 copyJob->setWindow( this );
00909 connect( copyJob, SIGNAL( result( KIO::Job * ) ),
00910 SLOT( slotImportCRLJobFinished( KIO::Job * ) ) );
00911 }
00912 }
00913 }
00914
00915 void CertManager::slotImportCRLJobFinished( KIO::Job *job )
00916 {
00917 KIO::FileCopyJob* fcjob = static_cast<KIO::FileCopyJob*>( job );
00918 QString tempFilePath = fcjob->destURL().path();
00919 if ( job->error() ) {
00920 job->showErrorDialog();
00921 QFile::remove( tempFilePath );
00922 updateImportActions( true );
00923 return;
00924 }
00925 startImportCRL( tempFilePath, true );
00926 }
00927
00928 bool CertManager::connectAndStartDirmngr( const char * slot, const char * processname ) {
00929 assert( slot );
00930 assert( processname );
00931 assert( mDirmngrProc );
00932 mErrorbuffer = QString::null;
00933 connect( mDirmngrProc, SIGNAL(processExited(KProcess*)), slot );
00934 connect( mDirmngrProc, SIGNAL(receivedStderr(KProcess*,char*,int) ),
00935 this, SLOT(slotStderr(KProcess*,char*,int)) );
00936 if( !mDirmngrProc->start( KProcess::NotifyOnExit, KProcess::Stderr ) ) {
00937 delete mDirmngrProc; mDirmngrProc = 0;
00938 KMessageBox::error( this, i18n( "Unable to start %1 process. Please check your installation." ).arg( processname ), i18n( "Certificate Manager Error" ) );
00939 return false;
00940 }
00941 return true;
00942 }
00943
00944 void CertManager::startImportCRL( const QString& filename, bool isTempFile )
00945 {
00946 assert( !mDirmngrProc );
00947 mImportCRLTempFile = isTempFile ? filename : QString::null;
00948 mDirmngrProc = new KProcess();
00949 *mDirmngrProc << "gpgsm" << "--call-dirmngr" << "loadcrl" << filename;
00950 if ( !connectAndStartDirmngr( SLOT(slotDirmngrExited()), "gpgsm" ) ) {
00951 updateImportActions( true );
00952 if ( isTempFile )
00953 QFile::remove( mImportCRLTempFile );
00954 }
00955 }
00956
00957 void CertManager::startClearCRLs() {
00958 assert( !mDirmngrProc );
00959 mDirmngrProc = new KProcess();
00960 *mDirmngrProc << "dirmngr" << "--flush";
00961
00962 connectAndStartDirmngr( SLOT(slotClearCRLsResult()), "dirmngr" );
00963 }
00964
00965 void CertManager::slotStderr( KProcess*, char* buf, int len ) {
00966 mErrorbuffer += QString::fromLocal8Bit( buf, len );
00967 }
00968
00972 void CertManager::importCRLFromLDAP()
00973 {
00974 qDebug("Not Yet Implemented");
00975 }
00976
00977 void CertManager::slotViewCRLs() {
00978 if ( !mCrlView )
00979 mCrlView = new CRLView( this );
00980
00981 mCrlView->show();
00982 mCrlView->slotUpdateView();
00983 }
00984
00985
00986 void CertManager::slotClearCRLs() {
00987 startClearCRLs();
00988 }
00989
00990 void CertManager::slotClearCRLsResult() {
00991 assert( mDirmngrProc );
00992 if ( !mDirmngrProc->normalExit() )
00993 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" ) );
00994 else if ( mDirmngrProc->exitStatus() )
00995 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" ) );
00996 else
00997 KMessageBox::information( this, i18n( "CRL cache cleared successfully." ), i18n( "Certificate Manager Information" ) );
00998 delete mDirmngrProc; mDirmngrProc = 0;
00999 }
01000
01001 static void showDeleteError( QWidget * parent, const GpgME::Error & err ) {
01002 assert( err );
01003 const QString msg = i18n("<qt><p>An error occurred while trying to delete "
01004 "the certificates:</p>"
01005 "<p><b>%1</b></p></qt>")
01006 .arg( QString::fromLocal8Bit( err.asString() ) );
01007 KMessageBox::error( parent, msg, i18n("Certificate Deletion Failed") );
01008 }
01009
01010 static bool ByFingerprint( const GpgME::Key & left, const GpgME::Key & right ) {
01011 return qstricmp( left.primaryFingerprint(), right.primaryFingerprint() ) < 0 ;
01012 }
01013
01014 static bool WithRespectToFingerprints( const GpgME::Key & left, const GpgME::Key & right ) {
01015 return qstricmp( left.primaryFingerprint(), right.primaryFingerprint() ) == 0;
01016 }
01017
01018 void CertManager::slotDeleteCertificate() {
01019 mItemsToDelete = mKeyListView->selectedItems();
01020 if ( mItemsToDelete.isEmpty() )
01021 return;
01022 std::vector<GpgME::Key> keys;
01023 keys.reserve( mItemsToDelete.count() );
01024 QStringList keyDisplayNames;
01025 for ( QPtrListIterator<Kleo::KeyListViewItem> it( mItemsToDelete ) ; it.current() ; ++it )
01026 if ( !it.current()->key().isNull() ) {
01027 keys.push_back( it.current()->key() );
01028 keyDisplayNames.push_back( it.current()->text( 0 ) );
01029 }
01030 if ( keys.empty() )
01031 return;
01032
01033 if ( !mHierarchyAnalyser ) {
01034 mHierarchyAnalyser = new HierarchyAnalyser( this, "mHierarchyAnalyser" );
01035 Kleo::KeyListJob * job = Kleo::CryptoBackendFactory::instance()->smime()->keyListJob();
01036 assert( job );
01037 connect( job, SIGNAL(nextKey(const GpgME::Key&)),
01038 mHierarchyAnalyser, SLOT(slotNextKey(const GpgME::Key&)) );
01039 connect( job, SIGNAL(result(const GpgME::KeyListResult&)),
01040 this, SLOT(slotDeleteCertificate()) );
01041 connectJobToStatusBarProgress( job, i18n("Checking key dependencies...") );
01042 if ( const GpgME::Error error = job->start( QStringList() ) ) {
01043 showKeyListError( this, error );
01044 delete mHierarchyAnalyser; mHierarchyAnalyser = 0;
01045 }
01046 return;
01047 } else
01048 disconnectJobFromStatusBarProgress( 0 );
01049
01050 std::vector<GpgME::Key> keysToDelete = keys;
01051 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it )
01052 if ( !it->isNull() ) {
01053 const std::vector<GpgME::Key> subjects
01054 = mHierarchyAnalyser->subjectsForIssuerRecursive( it->primaryFingerprint() );
01055 keysToDelete.insert( keysToDelete.end(), subjects.begin(), subjects.end() );
01056 }
01057
01058 std::sort( keysToDelete.begin(), keysToDelete.end(), ByFingerprint );
01059 keysToDelete.erase( std::unique( keysToDelete.begin(), keysToDelete.end(),
01060 WithRespectToFingerprints ),
01061 keysToDelete.end() );
01062
01063 delete mHierarchyAnalyser; mHierarchyAnalyser = 0;
01064
01065 if ( keysToDelete.size() > keys.size() )
01066 if ( KMessageBox::warningContinueCancel( this,
01067 i18n("Some or all of the selected "
01068 "certificates are issuers (CA certificates) "
01069 "for other, non-selected certificates.\n"
01070 "Deleting a CA certificate will also delete "
01071 "all certificates issued by it."),
01072 i18n("Deleting CA Certificates") )
01073 != KMessageBox::Continue )
01074 return;
01075
01076 const QString msg = keysToDelete.size() > keys.size()
01077 ? i18n("Do you really want to delete this certificate and the %1 certificates it certified?",
01078 "Do you really want to delete these %n certificates and the %1 certificates they certified?",
01079 keys.size() ).arg( keysToDelete.size() - keys.size() )
01080 : i18n("Do you really want to delete this certificate?",
01081 "Do you really want to delete these %n certificates?", keys.size() ) ;
01082
01083 if ( KMessageBox::warningContinueCancelList( this, msg, keyDisplayNames,
01084 i18n( "Delete Certificates" ),
01085 KGuiItem( i18n( "Delete" ), "editdelete" ),
01086 "ConfirmDeleteCert", KMessageBox::Dangerous )
01087 != KMessageBox::Continue )
01088 return;
01089
01090 if ( Kleo::DeleteJob * job = Kleo::CryptoBackendFactory::instance()->smime()->deleteJob() )
01091 job->slotCancel();
01092 else {
01093 QString str = keys.size() == 1
01094 ? i18n("<qt><p>An error occurred while trying to delete "
01095 "the certificate:</p>"
01096 "<p><b>%1</b><p></qt>" )
01097 : i18n( "<qt><p>An error occurred while trying to delete "
01098 "the certificates:</p>"
01099 "<p><b>%1</b><p></qt>" );
01100 KMessageBox::error( this,
01101 str.arg( i18n("Operation not supported by the backend.") ),
01102 i18n("Certificate Deletion Failed") );
01103 }
01104
01105 mItemsToDelete.clear();
01106 for ( std::vector<GpgME::Key>::const_iterator it = keysToDelete.begin() ; it != keysToDelete.end() ; ++it )
01107 if ( Kleo::KeyListViewItem * item = mKeyListView->itemByFingerprint( it->primaryFingerprint() ) )
01108 mItemsToDelete.append( item );
01109
01110 Kleo::MultiDeleteJob * job = new Kleo::MultiDeleteJob( Kleo::CryptoBackendFactory::instance()->smime() );
01111 assert( job );
01112
01113 connect( job, SIGNAL(result(const GpgME::Error&,const GpgME::Key&)),
01114 SLOT(slotDeleteResult(const GpgME::Error&,const GpgME::Key&)) );
01115
01116 connectJobToStatusBarProgress( job, i18n("Deleting keys...") );
01117
01118 const GpgME::Error err = job->start( keys, true );
01119 if ( err )
01120 showDeleteError( this, err );
01121 else
01122 mProgressBar->setProgress( 0, 0 );
01123 }
01124
01125 void CertManager::slotDeleteResult( const GpgME::Error & err, const GpgME::Key & ) {
01126 if ( err )
01127 showDeleteError( this, err );
01128 else {
01129 const int infinity = 100;
01130 mItemsToDelete.setAutoDelete( true );
01131 for ( int i = 0 ; i < infinity ; ++i ) {
01132 QPtrListIterator<Kleo::KeyListViewItem> it( mItemsToDelete );
01133 while ( Kleo::KeyListViewItem * cur = it.current() ) {
01134 ++it;
01135 if ( cur->childCount() == 0 ) {
01136 mItemsToDelete.remove( cur );
01137 }
01138 }
01139 if ( mItemsToDelete.isEmpty() )
01140 break;
01141 }
01142 mItemsToDelete.setAutoDelete( false );
01143 Q_ASSERT( mItemsToDelete.isEmpty() );
01144 mItemsToDelete.clear();
01145 }
01146 disconnectJobFromStatusBarProgress( err );
01147 }
01148
01149 void CertManager::slotViewDetails( Kleo::KeyListViewItem * item ) {
01150 if ( !item || item->key().isNull() )
01151 return;
01152
01153
01154 KDialogBase * dialog = new KDialogBase( this, "dialog", false, i18n("Additional Information for Key"), KDialogBase::Close, KDialogBase::Close );
01155
01156 CertificateInfoWidgetImpl * top = new CertificateInfoWidgetImpl( item->key(), isRemote(), dialog );
01157 dialog->setMainWidget( top );
01158
01159 connect( top, SIGNAL(requestCertificateDownload(const QString&, const QString&)),
01160 SLOT(slotStartCertificateDownload(const QString&, const QString&)) );
01161 dialog->show();
01162 }
01163
01164 void CertManager::slotViewDetails()
01165 {
01166 QPtrList<Kleo::KeyListViewItem> items = mKeyListView->selectedItems();
01167 if ( items.isEmpty() )
01168 return;
01169
01170
01171
01172 slotViewDetails( items.first() );
01173 }
01174
01175 void CertManager::slotSelectionChanged()
01176 {
01177 mKeyListView->flushKeys();
01178 bool b = mKeyListView->hasSelection();
01179 mExportCertificateAction->setEnabled( b );
01180 mViewCertDetailsAction->setEnabled( b );
01181 mDeleteCertificateAction->setEnabled( b );
01182 #ifdef NOT_IMPLEMENTED_ANYWAY
01183 mRevokeCertificateAction->setEnabled( b );
01184 mExtendCertificateAction->setEnabled( b );
01185 #endif
01186 mDownloadCertificateAction->setEnabled( b && mRemote );
01187 mValidateCertificateAction->setEnabled( !mRemote );
01188 }
01189
01190 void CertManager::slotExportCertificate() {
01191 QPtrList<Kleo::KeyListViewItem> items = mKeyListView->selectedItems();
01192 if ( items.isEmpty() )
01193 return;
01194
01195 QStringList fingerprints;
01196 for ( QPtrListIterator<Kleo::KeyListViewItem> it( items ) ; it.current() ; ++it )
01197 if ( !it.current()->key().isNull() )
01198 if ( const char * fpr = it.current()->key().primaryFingerprint() )
01199 fingerprints.push_back( fpr );
01200
01201 startCertificateExport( fingerprints );
01202 }
01203
01204 static void showCertificateExportError( QWidget * parent, const GpgME::Error & err ) {
01205 assert( err );
01206 const QString msg = i18n("<qt><p>An error occurred while trying to export "
01207 "the certificate:</p>"
01208 "<p><b>%1</b></p></qt>")
01209 .arg( QString::fromLocal8Bit( err.asString() ) );
01210 KMessageBox::error( parent, msg, i18n("Certificate Export Failed") );
01211 }
01212
01213 void CertManager::startCertificateExport( const QStringList & fingerprints ) {
01214 if ( fingerprints.empty() )
01215 return;
01216
01217
01218
01219 Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->smime()->publicKeyExportJob( true );
01220 assert( job );
01221
01222 connect( job, SIGNAL(result(const GpgME::Error&,const QByteArray&)),
01223 SLOT(slotCertificateExportResult(const GpgME::Error&,const QByteArray&)) );
01224
01225 connectJobToStatusBarProgress( job, i18n("Exporting certificate...") );
01226
01227 const GpgME::Error err = job->start( fingerprints );
01228 if ( err )
01229 showCertificateExportError( this, err );
01230 else
01231 mProgressBar->setProgress( 0, 0 );
01232 }
01233
01234
01235 static bool checkOverwrite( const KURL& url, bool& overwrite, QWidget* w )
01236 {
01237 if ( KIO::NetAccess::exists( url, false , w ) ) {
01238 if ( KMessageBox::Cancel ==
01239 KMessageBox::warningContinueCancel(
01240 w,
01241 i18n( "A file named \"%1\" already exists. "
01242 "Are you sure you want to overwrite it?" ).arg( url.prettyURL() ),
01243 i18n( "Overwrite File?" ),
01244 i18n( "&Overwrite" ) ) )
01245 return false;
01246 overwrite = true;
01247 }
01248 return true;
01249 }
01250
01251 void CertManager::slotCertificateExportResult( const GpgME::Error & err, const QByteArray & data ) {
01252 disconnectJobFromStatusBarProgress( err );
01253 if ( err ) {
01254 showCertificateExportError( this, err );
01255 return;
01256 }
01257
01258 kdDebug() << "CertManager::slotCertificateExportResult(): got " << data.size() << " bytes" << endl;
01259
01260 const QString filter = QString("*.pem|") + i18n("ASCII Armored Certificate Bundles (*.pem)");
01261 const KURL url = KFileDialog::getOpenURL( QString::null,
01262 filter,
01263 this,
01264 i18n( "Save Certificate" ) );
01265 if ( !url.isValid() )
01266 return;
01267
01268 bool overwrite = false;
01269 if ( !checkOverwrite( url, overwrite, this ) )
01270 return;
01271
01272 KIO::Job* uploadJob = KIOext::put( data, url, -1, overwrite, false );
01273 uploadJob->setWindow( this );
01274 connect( uploadJob, SIGNAL( result( KIO::Job* ) ),
01275 this, SLOT( slotUploadResult( KIO::Job* ) ) );
01276 }
01277
01278
01279 void CertManager::slotExportSecretKey() {
01280 Kleo::KeySelectionDialog dlg( i18n("Secret Key Export"),
01281 i18n("Select the secret key to export "
01282 "(<b>Warning: The PKCS#12 format is insecure; "
01283 "exporting secret keys is discouraged</b>):"),
01284 std::vector<GpgME::Key>(),
01285 Kleo::KeySelectionDialog::SecretKeys|Kleo::KeySelectionDialog::SMIMEKeys,
01286 false ,
01287 false ,
01288 this, "secret key export key selection dialog" );
01289
01290
01291 if ( dlg.exec() != QDialog::Accepted )
01292 return;
01293
01294 startSecretKeyExport( dlg.fingerprint() );
01295 }
01296
01297 static void showSecretKeyExportError( QWidget * parent, const GpgME::Error & err ) {
01298 assert( err );
01299 const QString msg = i18n("<qt><p>An error occurred while trying to export "
01300 "the secret key:</p>"
01301 "<p><b>%1</b></p></qt>")
01302 .arg( QString::fromLocal8Bit( err.asString() ) );
01303 KMessageBox::error( parent, msg, i18n("Secret-Key Export Failed") );
01304 }
01305
01306 void CertManager::startSecretKeyExport( const QString & fingerprint ) {
01307 if ( fingerprint.isEmpty() )
01308 return;
01309
01310
01311
01312
01313 Kleo::CryptoConfig* config = Kleo::CryptoBackendFactory::instance()->config();
01314 QString charset;
01315 if ( config && config->entry( "gpgsm", "Configuration", "p12-charset" ) ) {
01316
01317
01318 static const char *charsets[] = {
01319 "utf8",
01320 "iso-8859-1",
01321 "iso-8859-15",
01322 "iso-8859-2",
01323 "iso-8859-3",
01324 "iso-8859-4",
01325 "iso-8859-5",
01326 "iso-8859-6",
01327 "iso-8859-7",
01328 "iso-8859-8",
01329 "iso-8859-9",
01330 "koi8-r",
01331 "ibm437",
01332 "ibm850",
01333 "euc-jp",
01334 "big5",
01335 NULL
01336 };
01337 QStringList charsetList;
01338 for ( const char** c = charsets; *c; ++c ) {
01339 charsetList.append( QString::fromLatin1( *c ) );
01340 }
01341
01342
01343
01344 bool ok;
01345 charset = KInputDialog::getItem( i18n("Exporting secret key..."),
01346 i18n("Choose a charset for encoding the pkcs#12 passphrase (utf8 is recommended)"),
01347 charsetList,
01348 0, false ,
01349 &ok, this );
01350 if ( !ok )
01351 return;
01352 }
01353
01354 Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->smime()->secretKeyExportJob( false, charset );
01355 assert( job );
01356
01357 connect( job, SIGNAL(result(const GpgME::Error&,const QByteArray&)),
01358 SLOT(slotSecretKeyExportResult(const GpgME::Error&,const QByteArray&)) );
01359
01360 connectJobToStatusBarProgress( job, i18n("Exporting secret key...") );
01361
01362 const GpgME::Error err = job->start( fingerprint );
01363 if ( err )
01364 showSecretKeyExportError( this, err );
01365 else
01366 mProgressBar->setProgress( 0, 0 );
01367 }
01368
01369 void CertManager::slotSecretKeyExportResult( const GpgME::Error & err, const QByteArray & data ) {
01370 disconnectJobFromStatusBarProgress( err );
01371 if ( err ) {
01372 showSecretKeyExportError( this, err );
01373 return;
01374 }
01375
01376 kdDebug() << "CertManager::slotSecretKeyExportResult(): got " << data.size() << " bytes" << endl;
01377 QString filter = QString("*.p12|") + i18n("PKCS#12 Key Bundle (*.p12)");
01378 KURL url = KFileDialog::getOpenURL( QString::null,
01379 filter,
01380 this,
01381 i18n( "Save Certificate" ) );
01382 if ( !url.isValid() )
01383 return;
01384
01385 bool overwrite = false;
01386 if ( !checkOverwrite( url, overwrite, this ) )
01387 return;
01388
01389 KIO::Job* uploadJob = KIOext::put( data, url, -1, overwrite, false );
01390 uploadJob->setWindow( this );
01391 connect( uploadJob, SIGNAL( result( KIO::Job* ) ),
01392 this, SLOT( slotUploadResult( KIO::Job* ) ) );
01393 }
01394
01395 void CertManager::slotUploadResult( KIO::Job* job )
01396 {
01397 if ( job->error() )
01398 job->showErrorDialog();
01399 }
01400
01401 void CertManager::slotDropped(const KURL::List& lst)
01402 {
01403 mURLsToImport = lst;
01404 if ( !lst.empty() )
01405 importNextURLOrRedisplay();
01406 }
01407
01408 void CertManager::importNextURLOrRedisplay()
01409 {
01410 if ( !mURLsToImport.empty() ) {
01411
01412 KURL url = mURLsToImport.front();
01413 mURLsToImport.pop_front();
01414 slotImportCertFromFile( url );
01415 } else {
01416 if ( isRemote() )
01417 return;
01418 startKeyListing( false, true, mPreviouslySelectedFingerprints );
01419 }
01420 }
01421
01422 void CertManager::slotStartWatchGnuPG()
01423 {
01424 KProcess certManagerProc;
01425 certManagerProc << "kwatchgnupg";
01426
01427 if( !certManagerProc.start( KProcess::DontCare ) )
01428 KMessageBox::error( this, i18n( "Could not start GnuPG LogViewer (kwatchgnupg). "
01429 "Please check your installation!" ),
01430 i18n( "Kleopatra Error" ) );
01431 }
01432
01433 #include "certmanager.moc"