certmanager Library API Documentation

certmanager.cpp

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