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