certmanager Library API Documentation

keyselectiondialog.cpp

00001 /* -*- c++ -*- 00002 keyselectiondialog.cpp 00003 00004 This file is part of libkleopatra, the KDE keymanagement library 00005 Copyright (c) 2004 Klarälvdalens Datakonsult AB 00006 00007 Based on kpgpui.cpp 00008 Copyright (C) 2001,2002 the KPGP authors 00009 See file libkdenetwork/AUTHORS.kpgp for details 00010 00011 Libkleopatra is free software; you can redistribute it and/or 00012 modify it under the terms of the GNU General Public License as 00013 published by the Free Software Foundation; either version 2 of the 00014 License, or (at your option) any later version. 00015 00016 Libkleopatra is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 General Public License for more details. 00020 00021 You should have received a copy of the GNU General Public License 00022 along with this program; if not, write to the Free Software 00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00024 00025 In addition, as a special exception, the copyright holders give 00026 permission to link the code of this program with any edition of 00027 the Qt library by Trolltech AS, Norway (or with modified versions 00028 of Qt that use the same license as Qt), and distribute linked 00029 combinations including the two. You must obey the GNU General 00030 Public License in all respects for all of the code used other than 00031 Qt. If you modify this file, you may extend this exception to 00032 your version of the file, but you are not obligated to do so. If 00033 you do not wish to do so, delete this exception statement from 00034 your version. 00035 */ 00036 00037 #ifdef HAVE_CONFIG_H 00038 #include <config.h> 00039 #endif 00040 00041 #include "keyselectiondialog.h" 00042 00043 #include "keylistview.h" 00044 #include "progressdialog.h" 00045 00046 #include <kleo/dn.h> 00047 #include <kleo/keylistjob.h> 00048 #include <kleo/cryptobackendfactory.h> 00049 00050 // gpgme++ 00051 #include <gpgmepp/key.h> 00052 #include <gpgmepp/keylistresult.h> 00053 00054 // KDE 00055 #include <klocale.h> 00056 #include <kapplication.h> 00057 #include <kglobal.h> 00058 #include <kiconloader.h> 00059 #include <kdebug.h> 00060 #include <kwin.h> 00061 #include <kconfig.h> 00062 #include <kmessagebox.h> 00063 00064 // Qt 00065 #include <qcheckbox.h> 00066 #include <qlabel.h> 00067 #include <qpixmap.h> 00068 #include <qtimer.h> 00069 #include <qlayout.h> 00070 #include <qlineedit.h> 00071 #include <qwhatsthis.h> 00072 #include <qpopupmenu.h> 00073 #include <qregexp.h> 00074 #include <qpushbutton.h> 00075 00076 #include <algorithm> 00077 #include <iterator> 00078 00079 #include <string.h> 00080 #include <assert.h> 00081 00082 static bool checkKeyUsage( const GpgME::Key & key, unsigned int keyUsage ) { 00083 00084 if ( keyUsage & Kleo::KeySelectionDialog::ValidKeys ) 00085 if ( key.isInvalid() ) 00086 qDebug( "key is invalid - ignoring" ); 00087 if ( key.isExpired() ) { 00088 qDebug( "key is expired" ); 00089 return false; 00090 } else if ( key.isRevoked() ) { 00091 qDebug( "key is revoked" ); 00092 return false; 00093 } else if ( key.isDisabled() ) { 00094 qDebug( "key is disabled" ); 00095 return false; 00096 } 00097 00098 if ( keyUsage & Kleo::KeySelectionDialog::EncryptionKeys && 00099 !key.canEncrypt() ) { 00100 qDebug( "key can't encrypt" ); 00101 return false; 00102 } 00103 if ( keyUsage & Kleo::KeySelectionDialog::SigningKeys && 00104 !key.canSign() ) { 00105 qDebug( "key can't sign" ); 00106 return false; 00107 } 00108 if ( keyUsage & Kleo::KeySelectionDialog::CertificationKeys && 00109 !key.canCertify() ) { 00110 qDebug( "key can't certify" ); 00111 return false; 00112 } 00113 if ( keyUsage & Kleo::KeySelectionDialog::AuthenticationKeys && 00114 !key.canAuthenticate() ) { 00115 qDebug( "key can't authenticate" ); 00116 return false; 00117 } 00118 00119 if ( keyUsage & Kleo::KeySelectionDialog::SecretKeys && 00120 !( keyUsage & Kleo::KeySelectionDialog::PublicKeys ) && 00121 !key.isSecret() ) { 00122 qDebug( "key isn't secret" ); 00123 return false; 00124 } 00125 00126 if ( keyUsage & Kleo::KeySelectionDialog::TrustedKeys && 00127 key.protocol() == GpgME::Context::OpenPGP && 00128 // only check this for secret keys for now. 00129 // Seems validity isn't checked for secret keylistings... 00130 !key.isSecret() ) { 00131 std::vector<GpgME::UserID> uids = key.userIDs(); 00132 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) 00133 if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal ) 00134 return true; 00135 qDebug( "key has no UIDs with validity >= Marginal" ); 00136 return false; 00137 } 00138 // X.509 keys are always trusted, else they won't be the keybox. 00139 // PENDING(marc) check that this ^ is correct 00140 00141 return true; 00142 } 00143 00144 static bool checkKeyUsage( const std::vector<GpgME::Key> & keys, unsigned int keyUsage ) { 00145 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) 00146 if ( !checkKeyUsage( *it, keyUsage ) ) 00147 return false; 00148 return true; 00149 } 00150 00151 static inline QString time_t2string( time_t t ) { 00152 QDateTime dt; 00153 dt.setTime_t( t ); 00154 return dt.toString(); 00155 } 00156 00157 namespace { 00158 00159 class ColumnStrategy : public Kleo::KeyListView::ColumnStrategy { 00160 public: 00161 ColumnStrategy( unsigned int keyUsage ); 00162 00163 QString title( int col ) const; 00164 int width( int col, const QFontMetrics & fm ) const; 00165 00166 QString text( const GpgME::Key & key, int col ) const; 00167 QString toolTip( const GpgME::Key & key, int col ) const; 00168 const QPixmap * pixmap( const GpgME::Key & key, int col ) const; 00169 00170 private: 00171 const QPixmap mKeyGoodPix, mKeyBadPix, mKeyUnknownPix, mKeyValidPix; 00172 const unsigned int mKeyUsage; 00173 }; 00174 00175 ColumnStrategy::ColumnStrategy( unsigned int keyUsage ) 00176 : Kleo::KeyListView::ColumnStrategy(), 00177 mKeyGoodPix( UserIcon( "key_ok" ) ), 00178 mKeyBadPix( UserIcon( "key_bad" ) ), 00179 mKeyUnknownPix( UserIcon( "key_unknown" ) ), 00180 mKeyValidPix( UserIcon( "key" ) ), 00181 mKeyUsage( keyUsage ) 00182 { 00183 kdWarning( keyUsage == 0, 5150 ) 00184 << "KeySelectionDialog: keyUsage == 0. You want to use AllKeys instead." << endl; 00185 } 00186 00187 QString ColumnStrategy::title( int col ) const { 00188 switch ( col ) { 00189 case 0: return i18n("Key ID"); 00190 case 1: return i18n("User ID"); 00191 default: return QString::null; 00192 } 00193 } 00194 00195 int ColumnStrategy::width( int col, const QFontMetrics & fm ) const { 00196 if ( col == 0 ) { 00197 static const char hexchars[] = "0123456789ABCDEF"; 00198 int maxWidth = 0; 00199 for ( unsigned int i = 0 ; i < 16 ; ++i ) 00200 maxWidth = kMax( fm.width( QChar( hexchars[i] ) ), maxWidth ); 00201 return 8 * maxWidth + 2 * mKeyGoodPix.width(); 00202 } 00203 return Kleo::KeyListView::ColumnStrategy::width( col, fm ); 00204 } 00205 00206 QString ColumnStrategy::text( const GpgME::Key & key, int col ) const { 00207 switch ( col ) { 00208 case 0: 00209 { 00210 if ( key.shortKeyID() ) 00211 return QString::fromUtf8( key.shortKeyID() ); 00212 else 00213 return i18n("<unknown>"); 00214 } 00215 break; 00216 case 1: 00217 { 00218 const char * uid = key.userID(0).id(); 00219 if ( key.protocol() == GpgME::Context::OpenPGP ) 00220 return uid && *uid ? QString::fromUtf8( uid ) : QString::null ; 00221 else // CMS 00222 return Kleo::DN( uid ).prettyDN(); 00223 } 00224 break; 00225 default: return QString::null; 00226 } 00227 } 00228 00229 QString ColumnStrategy::toolTip( const GpgME::Key & key, int ) const { 00230 const char * uid = key.userID(0).id(); 00231 const char * fpr = key.subkey(0).fingerprint(); 00232 const char * issuer = key.issuerName(); 00233 const GpgME::Subkey subkey = key.subkey(0); 00234 const QString expiry = subkey.neverExpires() ? i18n("never") : time_t2string( subkey.expirationTime() ) ; 00235 const QString creation = time_t2string( subkey.creationTime() ); 00236 if ( key.protocol() == GpgME::Context::OpenPGP ) 00237 return i18n( "OpenPGP key for %1\n" 00238 "Created: %2\n" 00239 "Expiry: %3\n" 00240 "Fingerprint: %4" ) 00241 .arg( uid ? QString::fromUtf8( uid ) : i18n("unknown"), 00242 creation, expiry, 00243 fpr ? QString::fromLatin1( fpr ) : i18n("unknown") ); 00244 else 00245 return i18n( "S/MIME key for %1\n" 00246 "Created: %2\n" 00247 "Expiry: %3\n" 00248 "Fingerprint: %4\n" 00249 "Issuer: %5" ) 00250 .arg( uid ? Kleo::DN( uid ).prettyDN() : i18n("unknown"), 00251 creation, expiry, 00252 fpr ? QString::fromLatin1( fpr ) : i18n("unknown") ) 00253 .arg( issuer ? Kleo::DN( issuer ).prettyDN() : i18n("unknown") ); 00254 } 00255 00256 const QPixmap * ColumnStrategy::pixmap( const GpgME::Key & key, int col ) const { 00257 if ( col != 0 ) 00258 return 0; 00259 // this key did not undergo a validating keylisting yet: 00260 if ( !( key.keyListMode() & GpgME::Context::Validate ) ) 00261 return &mKeyUnknownPix; 00262 00263 if ( !checkKeyUsage( key, mKeyUsage ) ) 00264 return &mKeyBadPix; 00265 00266 if ( key.protocol() == GpgME::Context::CMS ) 00267 return &mKeyGoodPix; 00268 00269 switch ( key.userID(0).validity() ) { 00270 default: 00271 case GpgME::UserID::Unknown: 00272 case GpgME::UserID::Undefined: 00273 return &mKeyUnknownPix; 00274 case GpgME::UserID::Never: 00275 return &mKeyValidPix; 00276 case GpgME::UserID::Marginal: 00277 case GpgME::UserID::Full: 00278 case GpgME::UserID::Ultimate: 00279 return &mKeyGoodPix; 00280 } 00281 } 00282 00283 } 00284 00285 00286 static const int sCheckSelectionDelay = 250; 00287 00288 Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title, 00289 const QString & text, 00290 const std::vector<GpgME::Key> & selectedKeys, 00291 unsigned int keyUsage, 00292 bool extendedSelection, 00293 bool rememberChoice, 00294 QWidget * parent, const char * name, 00295 bool modal ) 00296 : KDialogBase( parent, name, modal, title, Default|Ok|Cancel, Ok ), 00297 mOpenPGPBackend( 0 ), 00298 mSMIMEBackend( 0 ), 00299 mRememberCB( 0 ), 00300 mSelectedKeys( selectedKeys ), 00301 mKeyUsage( keyUsage ), 00302 mCurrentContextMenuItem( 0 ) 00303 { 00304 init( rememberChoice, extendedSelection, text, QString::null ); 00305 } 00306 00307 Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title, 00308 const QString & text, 00309 const QString & initialQuery, 00310 unsigned int keyUsage, 00311 bool extendedSelection, 00312 bool rememberChoice, 00313 QWidget * parent, const char * name, 00314 bool modal ) 00315 : KDialogBase( parent, name, modal, title, Default|Ok|Cancel, Ok ), 00316 mOpenPGPBackend( 0 ), 00317 mSMIMEBackend( 0 ), 00318 mRememberCB( 0 ), 00319 mKeyUsage( keyUsage ), 00320 mSearchText( initialQuery ), 00321 mCurrentContextMenuItem( 0 ) 00322 { 00323 init( rememberChoice, extendedSelection, text, initialQuery ); 00324 } 00325 00326 void Kleo::KeySelectionDialog::init( bool rememberChoice, bool extendedSelection, 00327 const QString & text, const QString & initialQuery ) { 00328 if ( mKeyUsage & OpenPGPKeys ) 00329 mOpenPGPBackend = Kleo::CryptoBackendFactory::instance()->openpgp(); 00330 if ( mKeyUsage & SMIMEKeys ) 00331 mSMIMEBackend = Kleo::CryptoBackendFactory::instance()->smime(); 00332 00333 QSize dialogSize( 580, 400 ); 00334 if ( kapp ) { 00335 KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() ); 00336 00337 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" ); 00338 dialogSize = dialogConfig.readSizeEntry( "Dialog size", &dialogSize ); 00339 } 00340 resize( dialogSize ); 00341 00342 mCheckSelectionTimer = new QTimer( this ); 00343 mStartSearchTimer = new QTimer( this ); 00344 00345 QFrame *page = makeMainWidget(); 00346 QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); 00347 00348 if ( !text.isEmpty() ) 00349 topLayout->addWidget( new QLabel( text, page ) ); 00350 00351 QHBoxLayout * hlay = new QHBoxLayout( topLayout ); // inherits spacing 00352 QLineEdit * le = new QLineEdit( page ); 00353 le->setText( initialQuery ); 00354 hlay->addWidget( new QLabel( le, i18n("&Search for:"), page ) ); 00355 hlay->addWidget( le, 1 ); 00356 le->setFocus(); 00357 00358 connect( le, SIGNAL(textChanged(const QString&)), 00359 this, SLOT(slotSearch(const QString&)) ); 00360 connect( mStartSearchTimer, SIGNAL(timeout()), SLOT(slotFilter()) ); 00361 00362 mKeyListView = new KeyListView( new ColumnStrategy( mKeyUsage ), 0, page, "mKeyListView" ); 00363 mKeyListView->setResizeMode( QListView::LastColumn ); 00364 mKeyListView->setRootIsDecorated( true ); 00365 mKeyListView->setShowSortIndicator( true ); 00366 mKeyListView->setSorting( 1, true ); // sort by User ID 00367 mKeyListView->setShowToolTips( true ); 00368 if ( extendedSelection ) 00369 mKeyListView->setSelectionMode( QListView::Extended ); 00370 topLayout->addWidget( mKeyListView, 10 ); 00371 00372 if ( rememberChoice ) { 00373 mRememberCB = new QCheckBox( i18n("&Remember choice"), page ); 00374 topLayout->addWidget( mRememberCB ); 00375 QWhatsThis::add( mRememberCB, 00376 i18n("<qt><p>If you check this box your choice will " 00377 "be stored and you will not be asked again." 00378 "</p></qt>") ); 00379 } 00380 00381 connect( mCheckSelectionTimer, SIGNAL(timeout()), 00382 SLOT(slotCheckSelection()) ); 00383 connectSignals(); 00384 00385 connect( mKeyListView, 00386 SIGNAL(doubleClicked(Kleo::KeyListViewItem*,const QPoint&,int)), 00387 SLOT(slotTryOk()) ); 00388 connect( mKeyListView, 00389 SIGNAL(contextMenu(Kleo::KeyListViewItem*,const QPoint&)), 00390 SLOT(slotRMB(Kleo::KeyListViewItem*,const QPoint&)) ); 00391 00392 setButtonText( KDialogBase::Default, i18n("&Reread Keys") ); 00393 connect( this, SIGNAL(defaultClicked()), 00394 this, SLOT(slotRereadKeys()) ); 00395 00396 slotRereadKeys(); 00397 } 00398 00399 Kleo::KeySelectionDialog::~KeySelectionDialog() { 00400 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" ); 00401 dialogConfig.writeEntry( "Dialog size", size() ); 00402 dialogConfig.sync(); 00403 } 00404 00405 00406 void Kleo::KeySelectionDialog::connectSignals() { 00407 if ( mKeyListView->isMultiSelection() ) 00408 connect( mKeyListView, SIGNAL(selectionChanged()), 00409 SLOT(slotSelectionChanged()) ); 00410 else 00411 connect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)), 00412 SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) ); 00413 } 00414 00415 void Kleo::KeySelectionDialog::disconnectSignals() { 00416 if ( mKeyListView->isMultiSelection() ) 00417 disconnect( mKeyListView, SIGNAL(selectionChanged()), 00418 this, SLOT(slotSelectionChanged()) ); 00419 else 00420 disconnect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)), 00421 this, SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) ); 00422 } 00423 00424 const GpgME::Key & Kleo::KeySelectionDialog::selectedKey() const { 00425 if ( mKeyListView->isMultiSelection() || !mKeyListView->selectedItem() ) 00426 return GpgME::Key::null; 00427 return mKeyListView->selectedItem()->key(); 00428 } 00429 00430 QString Kleo::KeySelectionDialog::fingerprint() const { 00431 return selectedKey().subkey(0).fingerprint(); 00432 } 00433 00434 QStringList Kleo::KeySelectionDialog::fingerprints() const { 00435 QStringList result; 00436 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it ) 00437 if ( const char * fpr = it->subkey(0).fingerprint() ) 00438 result.push_back( fpr ); 00439 return result; 00440 } 00441 00442 QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const { 00443 QStringList result; 00444 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it ) 00445 if ( it->protocol() == GpgME::Context::OpenPGP ) 00446 if ( const char * fpr = it->subkey(0).fingerprint() ) 00447 result.push_back( fpr ); 00448 return result; 00449 } 00450 00451 QStringList Kleo::KeySelectionDialog::smimeFingerprints() const { 00452 QStringList result; 00453 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it ) 00454 if ( it->protocol() == GpgME::Context::CMS ) 00455 if ( const char * fpr = it->subkey(0).fingerprint() ) 00456 result.push_back( fpr ); 00457 return result; 00458 } 00459 00460 void Kleo::KeySelectionDialog::slotRereadKeys() { 00461 mKeyListView->clear(); 00462 mListJobCount = 0; 00463 mTruncated = 0; 00464 mSavedOffsetY = mKeyListView->contentsY(); 00465 00466 disconnectSignals(); 00467 this->setEnabled( false ); 00468 00469 // FIXME: save current selection 00470 if ( mOpenPGPBackend ) 00471 startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false /*non-validating*/ ); 00472 if ( mSMIMEBackend ) 00473 startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false /*non-validating*/ ); 00474 00475 if ( mListJobCount == 0 ) { 00476 this->setEnabled( true ); 00477 KMessageBox::information( this, 00478 i18n("No backends found for listing keys. " 00479 "Check your installation."), 00480 i18n("Key Listing Failed") ); 00481 connectSignals(); 00482 } 00483 } 00484 00485 static void showKeyListError( QWidget * parent, const GpgME::Error & err ) { 00486 assert( err ); 00487 const QString msg = i18n( "<qt><p>An error occurred while fetching " 00488 "the keys from the backend:</p>" 00489 "<p><b>%1</b></p></qt>" ) 00490 .arg( QString::fromLocal8Bit( err.asString() ) ); 00491 00492 KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) ); 00493 } 00494 00495 namespace { 00496 struct ExtractFingerprint { 00497 QString operator()( const GpgME::Key & key ) { 00498 return key.subkey(0).fingerprint(); 00499 } 00500 }; 00501 } 00502 00503 void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) { 00504 assert( backend ); 00505 KeyListJob * job = backend->keyListJob( false, false, validate ); // local, w/o sigs, validation as givem 00506 if ( !job ) 00507 return; 00508 00509 connect( job, SIGNAL(result(const GpgME::KeyListResult&)), 00510 SLOT(slotKeyListResult(const GpgME::KeyListResult&)) ); 00511 connect( job, SIGNAL(nextKey(const GpgME::Key&)), 00512 mKeyListView, validate ? 00513 SLOT(slotRefreshKey(const GpgME::Key&)) : 00514 SLOT(slotAddKey(const GpgME::Key&)) ); 00515 00516 QStringList fprs; 00517 std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() ); 00518 const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) ); 00519 00520 if ( err ) 00521 return showKeyListError( this, err ); 00522 00523 // FIXME: create a MultiProgressDialog: 00524 (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this ); 00525 ++mListJobCount; 00526 } 00527 00528 static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) { 00529 if ( selectedKeys.empty() ) 00530 return; 00531 int selectedKeysCount = selectedKeys.size(); 00532 for ( Kleo::KeyListViewItem * item = klv->firstChild() ; item ; item = item->nextSibling() ) { 00533 const char * fpr = item->key().subkey(0).fingerprint(); 00534 if ( !fpr || !*fpr ) 00535 continue; 00536 for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it ) 00537 if ( qstrcmp( fpr, it->subkey(0).fingerprint() ) == 0 ) { 00538 item->setSelected( true ); 00539 if ( --selectedKeysCount <= 0 ) 00540 return; 00541 else 00542 break; 00543 } 00544 } 00545 } 00546 00547 void Kleo::KeySelectionDialog::slotKeyListResult( const GpgME::KeyListResult & res ) { 00548 if ( res.error() ) 00549 showKeyListError( this, res.error() ); 00550 else if ( res.isTruncated() ) 00551 ++mTruncated; 00552 00553 if ( --mListJobCount > 0 ) 00554 return; // not yet finished... 00555 00556 if ( mTruncated > 0 ) 00557 KMessageBox::information( this, 00558 i18n("One backend returned truncated output.\n" 00559 "Not all available keys are shown", 00560 "%n backends returned truncated output.\n" 00561 "Not all available keys are shown", 00562 mTruncated), 00563 i18n("Key List Result") ); 00564 00565 mKeyListView->flushKeys(); 00566 00567 this->setEnabled( true ); 00568 mListJobCount = mTruncated = 0; 00569 mKeysToCheck.clear(); 00570 00571 selectKeys( mKeyListView, mSelectedKeys ); 00572 00573 slotFilter(); 00574 00575 connectSignals(); 00576 00577 slotSelectionChanged(); 00578 00579 // restore the saved position of the contents 00580 mKeyListView->setContentsPos( 0, mSavedOffsetY ); mSavedOffsetY = 0; 00581 } 00582 00583 void Kleo::KeySelectionDialog::slotSelectionChanged() { 00584 kdDebug(5150) << "KeySelectionDialog::slotSelectionChanged()" << endl; 00585 00586 // (re)start the check selection timer. Checking the selection is delayed 00587 // because else drag-selection doesn't work very good (checking key trust 00588 // is slow). 00589 mCheckSelectionTimer->start( sCheckSelectionDelay ); 00590 } 00591 00592 namespace { 00593 struct AlreadyChecked { 00594 bool operator()( const GpgME::Key & key ) const { 00595 return key.keyListMode() & GpgME::Context::Validate ; 00596 } 00597 }; 00598 } 00599 00600 void Kleo::KeySelectionDialog::slotCheckSelection( KeyListViewItem * item ) { 00601 kdDebug(5150) << "KeySelectionDialog::slotCheckSelection()\n"; 00602 00603 mCheckSelectionTimer->stop(); 00604 00605 mSelectedKeys.clear(); 00606 00607 if ( !mKeyListView->isMultiSelection() ) { 00608 if ( item ) 00609 mSelectedKeys.push_back( item->key() ); 00610 } 00611 00612 for ( KeyListViewItem * it = mKeyListView->firstChild() ; it ; it = it->nextSibling() ) 00613 if ( it->isSelected() ) 00614 mSelectedKeys.push_back( it->key() ); 00615 00616 mKeysToCheck.clear(); 00617 std::remove_copy_if( mSelectedKeys.begin(), mSelectedKeys.end(), 00618 std::back_inserter( mKeysToCheck ), 00619 AlreadyChecked() ); 00620 if ( mKeysToCheck.empty() ) { 00621 enableButtonOK( !mSelectedKeys.empty() && 00622 checkKeyUsage( mSelectedKeys, mKeyUsage ) ); 00623 return; 00624 } 00625 00626 // performed all fast checks - now for validating key listing: 00627 startValidatingKeyListing(); 00628 } 00629 00630 void Kleo::KeySelectionDialog::startValidatingKeyListing() { 00631 if ( mKeysToCheck.empty() ) 00632 return; 00633 00634 mListJobCount = 0; 00635 mTruncated = 0; 00636 mSavedOffsetY = mKeyListView->contentsY(); 00637 00638 disconnectSignals(); 00639 this->setEnabled( false ); 00640 00641 std::vector<GpgME::Key> smime, openpgp; 00642 for ( std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin() ; it != mKeysToCheck.end() ; ++it ) 00643 if ( it->protocol() == GpgME::Context::OpenPGP ) 00644 openpgp.push_back( *it ); 00645 else 00646 smime.push_back( *it ); 00647 00648 if ( !openpgp.empty() ) { 00649 assert( mOpenPGPBackend ); 00650 startKeyListJobForBackend( mOpenPGPBackend, openpgp, true /*validate*/ ); 00651 } 00652 if ( !smime.empty() ) { 00653 assert( mSMIMEBackend ); 00654 startKeyListJobForBackend( mSMIMEBackend, smime, true /*validate*/ ); 00655 } 00656 00657 assert( mListJobCount > 0 ); 00658 } 00659 00660 bool Kleo::KeySelectionDialog::rememberSelection() const { 00661 return mRememberCB && mRememberCB->isChecked() ; 00662 } 00663 00664 void Kleo::KeySelectionDialog::slotRMB( Kleo::KeyListViewItem * item, const QPoint & p ) { 00665 if ( !item ) return; 00666 00667 mCurrentContextMenuItem = item; 00668 00669 QPopupMenu menu; 00670 menu.insertItem( i18n( "Recheck Key" ), this, SLOT(slotRecheckKey()) ); 00671 menu.exec( p ); 00672 } 00673 00674 void Kleo::KeySelectionDialog::slotRecheckKey() { 00675 if ( !mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull() ) 00676 return; 00677 00678 mKeysToCheck.clear(); 00679 mKeysToCheck.push_back( mCurrentContextMenuItem->key() ); 00680 } 00681 00682 void Kleo::KeySelectionDialog::slotTryOk() { 00683 if ( actionButton( Ok )->isEnabled() ) 00684 slotOk(); 00685 } 00686 00687 void Kleo::KeySelectionDialog::slotOk() { 00688 if ( mCheckSelectionTimer->isActive() ) 00689 slotCheckSelection(); 00690 mStartSearchTimer->stop(); 00691 accept(); 00692 } 00693 00694 00695 void Kleo::KeySelectionDialog::slotCancel() { 00696 mCheckSelectionTimer->stop(); 00697 mStartSearchTimer->stop(); 00698 reject(); 00699 } 00700 00701 void Kleo::KeySelectionDialog::slotSearch( const QString & text ) { 00702 mSearchText = text.stripWhiteSpace().upper(); 00703 slotSearch(); 00704 } 00705 00706 void Kleo::KeySelectionDialog::slotSearch() { 00707 mStartSearchTimer->start( sCheckSelectionDelay, true /*single-shot*/ ); 00708 } 00709 00710 void Kleo::KeySelectionDialog::slotFilter() { 00711 if ( mSearchText.isEmpty() ) { 00712 showAllItems(); 00713 return; 00714 } 00715 00716 // OK, so we need to filter: 00717 QRegExp keyIdRegExp( "(?:0x)?[A-F0-9]{1,8}", false /*case-insens.*/ ); 00718 if ( keyIdRegExp.exactMatch( mSearchText ) ) { 00719 if ( mSearchText.startsWith( "0X" ) ) 00720 // search for keyID only: 00721 filterByKeyID( mSearchText.mid( 2 ) ); 00722 else 00723 // search for UID and keyID: 00724 filterByKeyIDOrUID( mSearchText ); 00725 } else { 00726 // search in UID: 00727 filterByUID( mSearchText ); 00728 } 00729 } 00730 00731 void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) { 00732 assert( keyID.length() <= 8 ); 00733 assert( !keyID.isEmpty() ); // regexp in slotFilter should prevent these 00734 if ( keyID.isEmpty() ) 00735 showAllItems(); 00736 else 00737 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() ) 00738 item->setVisible( item->text( 0 ).upper().startsWith( keyID ) ); 00739 } 00740 00741 static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) { 00742 if ( !item ) 00743 return false; 00744 00745 const std::vector<GpgME::UserID> uids = item->key().userIDs(); 00746 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) 00747 if ( it->id() && rx.search( QString::fromUtf8( it->id() ) ) >= 0 ) 00748 return true; 00749 return false; 00750 } 00751 00752 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const QString & str ) { 00753 assert( !str.isEmpty() ); 00754 00755 // match beginnings of words: 00756 QRegExp rx( "\\b" + QRegExp::escape( str ), false ); 00757 00758 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() ) 00759 item->setVisible( item->text( 0 ).upper().startsWith( str ) || anyUIDMatches( item, rx ) ); 00760 00761 } 00762 00763 void Kleo::KeySelectionDialog::filterByUID( const QString & str ) { 00764 assert( !str.isEmpty() ); 00765 00766 // match beginnings of words: 00767 QRegExp rx( "\\b" + QRegExp::escape( str ), false ); 00768 00769 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() ) 00770 item->setVisible( anyUIDMatches( item, rx ) ); 00771 } 00772 00773 00774 void Kleo::KeySelectionDialog::showAllItems() { 00775 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() ) 00776 item->setVisible( true ); 00777 } 00778 00779 #include "keyselectiondialog.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:33 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003