00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
00051 #include <gpgmepp/key.h>
00052 #include <gpgmepp/keylistresult.h>
00053
00054
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
00065 #include <qcheckbox.h>
00066 #include <qtoolbutton.h>
00067 #include <qlabel.h>
00068 #include <qpixmap.h>
00069 #include <qtimer.h>
00070 #include <qlayout.h>
00071 #include <qlineedit.h>
00072 #include <qwhatsthis.h>
00073 #include <qpopupmenu.h>
00074 #include <qregexp.h>
00075 #include <qpushbutton.h>
00076
00077 #include <algorithm>
00078 #include <iterator>
00079
00080 #include <string.h>
00081 #include <assert.h>
00082
00083 static bool checkKeyUsage( const GpgME::Key & key, unsigned int keyUsage ) {
00084
00085 if ( keyUsage & Kleo::KeySelectionDialog::ValidKeys ) {
00086 if ( key.isInvalid() )
00087 kdDebug() << "key is invalid - ignoring" << endl;
00088 if ( key.isExpired() ) {
00089 kdDebug() << "key is expired" << endl;
00090 return false;
00091 } else if ( key.isRevoked() ) {
00092 kdDebug() << "key is revoked" << endl;
00093 return false;
00094 } else if ( key.isDisabled() ) {
00095 kdDebug() << "key is disabled" << endl;
00096 return false;
00097 }
00098 }
00099
00100 if ( keyUsage & Kleo::KeySelectionDialog::EncryptionKeys &&
00101 !key.canEncrypt() ) {
00102 kdDebug() << "key can't encrypt" << endl;
00103 return false;
00104 }
00105 if ( keyUsage & Kleo::KeySelectionDialog::SigningKeys &&
00106 !key.canSign() ) {
00107 kdDebug() << "key can't sign" << endl;
00108 return false;
00109 }
00110 if ( keyUsage & Kleo::KeySelectionDialog::CertificationKeys &&
00111 !key.canCertify() ) {
00112 kdDebug() << "key can't certify" << endl;
00113 return false;
00114 }
00115 if ( keyUsage & Kleo::KeySelectionDialog::AuthenticationKeys &&
00116 !key.canAuthenticate() ) {
00117 kdDebug() << "key can't authenticate" << endl;
00118 return false;
00119 }
00120
00121 if ( keyUsage & Kleo::KeySelectionDialog::SecretKeys &&
00122 !( keyUsage & Kleo::KeySelectionDialog::PublicKeys ) &&
00123 !key.isSecret() ) {
00124 kdDebug() << "key isn't secret" << endl;
00125 return false;
00126 }
00127
00128 if ( keyUsage & Kleo::KeySelectionDialog::TrustedKeys &&
00129 key.protocol() == GpgME::Context::OpenPGP &&
00130
00131
00132 !key.isSecret() ) {
00133 std::vector<GpgME::UserID> uids = key.userIDs();
00134 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
00135 if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal )
00136 return true;
00137 kdDebug() << "key has no UIDs with validity >= Marginal" << endl;
00138 return false;
00139 }
00140
00141
00142
00143 return true;
00144 }
00145
00146 static bool checkKeyUsage( const std::vector<GpgME::Key> & keys, unsigned int keyUsage ) {
00147 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it )
00148 if ( !checkKeyUsage( *it, keyUsage ) )
00149 return false;
00150 return true;
00151 }
00152
00153 static inline QString time_t2string( time_t t ) {
00154 QDateTime dt;
00155 dt.setTime_t( t );
00156 return dt.toString();
00157 }
00158
00159 namespace {
00160
00161 class ColumnStrategy : public Kleo::KeyListView::ColumnStrategy {
00162 public:
00163 ColumnStrategy( unsigned int keyUsage );
00164
00165 QString title( int col ) const;
00166 int width( int col, const QFontMetrics & fm ) const;
00167
00168 QString text( const GpgME::Key & key, int col ) const;
00169 QString toolTip( const GpgME::Key & key, int col ) const;
00170 const QPixmap * pixmap( const GpgME::Key & key, int col ) const;
00171
00172 private:
00173 const QPixmap mKeyGoodPix, mKeyBadPix, mKeyUnknownPix, mKeyValidPix;
00174 const unsigned int mKeyUsage;
00175 };
00176
00177 ColumnStrategy::ColumnStrategy( unsigned int keyUsage )
00178 : Kleo::KeyListView::ColumnStrategy(),
00179 mKeyGoodPix( UserIcon( "key_ok" ) ),
00180 mKeyBadPix( UserIcon( "key_bad" ) ),
00181 mKeyUnknownPix( UserIcon( "key_unknown" ) ),
00182 mKeyValidPix( UserIcon( "key" ) ),
00183 mKeyUsage( keyUsage )
00184 {
00185 kdWarning( keyUsage == 0, 5150 )
00186 << "KeySelectionDialog: keyUsage == 0. You want to use AllKeys instead." << endl;
00187 }
00188
00189 QString ColumnStrategy::title( int col ) const {
00190 switch ( col ) {
00191 case 0: return i18n("Key ID");
00192 case 1: return i18n("User ID");
00193 default: return QString::null;
00194 }
00195 }
00196
00197 int ColumnStrategy::width( int col, const QFontMetrics & fm ) const {
00198 if ( col == 0 ) {
00199 static const char hexchars[] = "0123456789ABCDEF";
00200 int maxWidth = 0;
00201 for ( unsigned int i = 0 ; i < 16 ; ++i )
00202 maxWidth = kMax( fm.width( QChar( hexchars[i] ) ), maxWidth );
00203 return 8 * maxWidth + 2 * mKeyGoodPix.width();
00204 }
00205 return Kleo::KeyListView::ColumnStrategy::width( col, fm );
00206 }
00207
00208 QString ColumnStrategy::text( const GpgME::Key & key, int col ) const {
00209 switch ( col ) {
00210 case 0:
00211 {
00212 if ( key.shortKeyID() )
00213 return QString::fromUtf8( key.shortKeyID() );
00214 else
00215 return i18n("<unknown>");
00216 }
00217 break;
00218 case 1:
00219 {
00220 const char * uid = key.userID(0).id();
00221 if ( key.protocol() == GpgME::Context::OpenPGP )
00222 return uid && *uid ? QString::fromUtf8( uid ) : QString::null ;
00223 else
00224 return Kleo::DN( uid ).prettyDN();
00225 }
00226 break;
00227 default: return QString::null;
00228 }
00229 }
00230
00231 QString ColumnStrategy::toolTip( const GpgME::Key & key, int ) const {
00232 const char * uid = key.userID(0).id();
00233 const char * fpr = key.primaryFingerprint();
00234 const char * issuer = key.issuerName();
00235 const GpgME::Subkey subkey = key.subkey(0);
00236 const QString expiry = subkey.neverExpires() ? i18n("never") : time_t2string( subkey.expirationTime() ) ;
00237 const QString creation = time_t2string( subkey.creationTime() );
00238 if ( key.protocol() == GpgME::Context::OpenPGP )
00239 return i18n( "OpenPGP key for %1\n"
00240 "Created: %2\n"
00241 "Expiry: %3\n"
00242 "Fingerprint: %4" )
00243 .arg( uid ? QString::fromUtf8( uid ) : i18n("unknown"),
00244 creation, expiry,
00245 fpr ? QString::fromLatin1( fpr ) : i18n("unknown") );
00246 else
00247 return i18n( "S/MIME key for %1\n"
00248 "Created: %2\n"
00249 "Expiry: %3\n"
00250 "Fingerprint: %4\n"
00251 "Issuer: %5" )
00252 .arg( uid ? Kleo::DN( uid ).prettyDN() : i18n("unknown"),
00253 creation, expiry,
00254 fpr ? QString::fromLatin1( fpr ) : i18n("unknown") )
00255 .arg( issuer ? Kleo::DN( issuer ).prettyDN() : i18n("unknown") );
00256 }
00257
00258 const QPixmap * ColumnStrategy::pixmap( const GpgME::Key & key, int col ) const {
00259 if ( col != 0 )
00260 return 0;
00261
00262 if ( !( key.keyListMode() & GpgME::Context::Validate ) )
00263 return &mKeyUnknownPix;
00264
00265 if ( !checkKeyUsage( key, mKeyUsage ) )
00266 return &mKeyBadPix;
00267
00268 if ( key.protocol() == GpgME::Context::CMS )
00269 return &mKeyGoodPix;
00270
00271 switch ( key.userID(0).validity() ) {
00272 default:
00273 case GpgME::UserID::Unknown:
00274 case GpgME::UserID::Undefined:
00275 return &mKeyUnknownPix;
00276 case GpgME::UserID::Never:
00277 return &mKeyValidPix;
00278 case GpgME::UserID::Marginal:
00279 case GpgME::UserID::Full:
00280 case GpgME::UserID::Ultimate:
00281 return &mKeyGoodPix;
00282 }
00283 }
00284
00285 }
00286
00287
00288 static const int sCheckSelectionDelay = 250;
00289
00290 Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title,
00291 const QString & text,
00292 const std::vector<GpgME::Key> & selectedKeys,
00293 unsigned int keyUsage,
00294 bool extendedSelection,
00295 bool rememberChoice,
00296 QWidget * parent, const char * name,
00297 bool modal )
00298 : KDialogBase( parent, name, modal, title, Default|Ok|Cancel, Ok ),
00299 mOpenPGPBackend( 0 ),
00300 mSMIMEBackend( 0 ),
00301 mRememberCB( 0 ),
00302 mSelectedKeys( selectedKeys ),
00303 mKeyUsage( keyUsage ),
00304 mCurrentContextMenuItem( 0 )
00305 {
00306 init( rememberChoice, extendedSelection, text, QString::null );
00307 }
00308
00309 Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title,
00310 const QString & text,
00311 const QString & initialQuery,
00312 unsigned int keyUsage,
00313 bool extendedSelection,
00314 bool rememberChoice,
00315 QWidget * parent, const char * name,
00316 bool modal )
00317 : KDialogBase( parent, name, modal, title, Default|Ok|Cancel, Ok ),
00318 mOpenPGPBackend( 0 ),
00319 mSMIMEBackend( 0 ),
00320 mRememberCB( 0 ),
00321 mKeyUsage( keyUsage ),
00322 mSearchText( initialQuery ),
00323 mCurrentContextMenuItem( 0 )
00324 {
00325 init( rememberChoice, extendedSelection, text, initialQuery );
00326 }
00327
00328 void Kleo::KeySelectionDialog::init( bool rememberChoice, bool extendedSelection,
00329 const QString & text, const QString & initialQuery ) {
00330 if ( mKeyUsage & OpenPGPKeys )
00331 mOpenPGPBackend = Kleo::CryptoBackendFactory::instance()->openpgp();
00332 if ( mKeyUsage & SMIMEKeys )
00333 mSMIMEBackend = Kleo::CryptoBackendFactory::instance()->smime();
00334
00335 QSize dialogSize( 580, 400 );
00336 if ( kapp ) {
00337 KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
00338
00339 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
00340 dialogSize = dialogConfig.readSizeEntry( "Dialog size", &dialogSize );
00341 }
00342 resize( dialogSize );
00343
00344 mCheckSelectionTimer = new QTimer( this );
00345 mStartSearchTimer = new QTimer( this );
00346
00347 QFrame *page = makeMainWidget();
00348 QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
00349
00350 if ( !text.isEmpty() )
00351 topLayout->addWidget( new QLabel( text, page ) );
00352
00353 QHBoxLayout * hlay = new QHBoxLayout( topLayout );
00354 QLineEdit * le = new QLineEdit( page );
00355 le->setText( initialQuery );
00356 QToolButton *clearButton = new QToolButton( page );
00357 clearButton->setIconSet( KGlobal::iconLoader()->loadIconSet(
00358 KApplication::reverseLayout() ? "clear_left":"locationbar_erase", KIcon::Small, 0 ) );
00359 hlay->addWidget( clearButton );
00360 hlay->addWidget( new QLabel( le, i18n("&Search for:"), page ) );
00361 hlay->addWidget( le, 1 );
00362 le->setFocus();
00363
00364 connect( clearButton, SIGNAL( clicked() ), le, SLOT( clear() ) );
00365 connect( le, SIGNAL(textChanged(const QString&)),
00366 this, SLOT(slotSearch(const QString&)) );
00367 connect( mStartSearchTimer, SIGNAL(timeout()), SLOT(slotFilter()) );
00368
00369 mKeyListView = new KeyListView( new ColumnStrategy( mKeyUsage ), 0, page, "mKeyListView" );
00370 mKeyListView->setResizeMode( QListView::LastColumn );
00371 mKeyListView->setRootIsDecorated( true );
00372 mKeyListView->setShowSortIndicator( true );
00373 mKeyListView->setSorting( 1, true );
00374 mKeyListView->setShowToolTips( true );
00375 if ( extendedSelection )
00376 mKeyListView->setSelectionMode( QListView::Extended );
00377 topLayout->addWidget( mKeyListView, 10 );
00378
00379 if ( rememberChoice ) {
00380 mRememberCB = new QCheckBox( i18n("&Remember choice"), page );
00381 topLayout->addWidget( mRememberCB );
00382 QWhatsThis::add( mRememberCB,
00383 i18n("<qt><p>If you check this box your choice will "
00384 "be stored and you will not be asked again."
00385 "</p></qt>") );
00386 }
00387
00388 connect( mCheckSelectionTimer, SIGNAL(timeout()),
00389 SLOT(slotCheckSelection()) );
00390 connectSignals();
00391
00392 connect( mKeyListView,
00393 SIGNAL(doubleClicked(Kleo::KeyListViewItem*,const QPoint&,int)),
00394 SLOT(slotTryOk()) );
00395 connect( mKeyListView,
00396 SIGNAL(contextMenu(Kleo::KeyListViewItem*,const QPoint&)),
00397 SLOT(slotRMB(Kleo::KeyListViewItem*,const QPoint&)) );
00398
00399 setButtonText( KDialogBase::Default, i18n("&Reread Keys") );
00400 connect( this, SIGNAL(defaultClicked()),
00401 this, SLOT(slotRereadKeys()) );
00402
00403 slotRereadKeys();
00404 }
00405
00406 Kleo::KeySelectionDialog::~KeySelectionDialog() {
00407 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
00408 dialogConfig.writeEntry( "Dialog size", size() );
00409 dialogConfig.sync();
00410 }
00411
00412
00413 void Kleo::KeySelectionDialog::connectSignals() {
00414 if ( mKeyListView->isMultiSelection() )
00415 connect( mKeyListView, SIGNAL(selectionChanged()),
00416 SLOT(slotSelectionChanged()) );
00417 else
00418 connect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00419 SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00420 }
00421
00422 void Kleo::KeySelectionDialog::disconnectSignals() {
00423 if ( mKeyListView->isMultiSelection() )
00424 disconnect( mKeyListView, SIGNAL(selectionChanged()),
00425 this, SLOT(slotSelectionChanged()) );
00426 else
00427 disconnect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00428 this, SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00429 }
00430
00431 const GpgME::Key & Kleo::KeySelectionDialog::selectedKey() const {
00432 if ( mKeyListView->isMultiSelection() || !mKeyListView->selectedItem() )
00433 return GpgME::Key::null;
00434 return mKeyListView->selectedItem()->key();
00435 }
00436
00437 QString Kleo::KeySelectionDialog::fingerprint() const {
00438 return selectedKey().primaryFingerprint();
00439 }
00440
00441 QStringList Kleo::KeySelectionDialog::fingerprints() const {
00442 QStringList result;
00443 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00444 if ( const char * fpr = it->primaryFingerprint() )
00445 result.push_back( fpr );
00446 return result;
00447 }
00448
00449 QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const {
00450 QStringList result;
00451 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00452 if ( it->protocol() == GpgME::Context::OpenPGP )
00453 if ( const char * fpr = it->primaryFingerprint() )
00454 result.push_back( fpr );
00455 return result;
00456 }
00457
00458 QStringList Kleo::KeySelectionDialog::smimeFingerprints() const {
00459 QStringList result;
00460 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00461 if ( it->protocol() == GpgME::Context::CMS )
00462 if ( const char * fpr = it->primaryFingerprint() )
00463 result.push_back( fpr );
00464 return result;
00465 }
00466
00467 void Kleo::KeySelectionDialog::slotRereadKeys() {
00468 mKeyListView->clear();
00469 mListJobCount = 0;
00470 mTruncated = 0;
00471 mSavedOffsetY = mKeyListView->contentsY();
00472
00473 disconnectSignals();
00474 mKeyListView->setEnabled( false );
00475
00476
00477 if ( mOpenPGPBackend )
00478 startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false );
00479 if ( mSMIMEBackend )
00480 startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false );
00481
00482 if ( mListJobCount == 0 ) {
00483 mKeyListView->setEnabled( true );
00484 KMessageBox::information( this,
00485 i18n("No backends found for listing keys. "
00486 "Check your installation."),
00487 i18n("Key Listing Failed") );
00488 connectSignals();
00489 }
00490 }
00491
00492 #ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00493 #define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
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 keys from the backend:</p>"
00498 "<p><b>%1</b></p></qt>" )
00499 .arg( QString::fromLocal8Bit( err.asString() ) );
00500
00501 KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) );
00502 }
00503 #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00504
00505 namespace {
00506 struct ExtractFingerprint {
00507 QString operator()( const GpgME::Key & key ) {
00508 return key.primaryFingerprint();
00509 }
00510 };
00511 }
00512
00513 void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) {
00514 assert( backend );
00515 KeyListJob * job = backend->keyListJob( false, false, validate );
00516 if ( !job )
00517 return;
00518
00519 connect( job, SIGNAL(result(const GpgME::KeyListResult&)),
00520 SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
00521 connect( job, SIGNAL(nextKey(const GpgME::Key&)),
00522 mKeyListView, validate ?
00523 SLOT(slotRefreshKey(const GpgME::Key&)) :
00524 SLOT(slotAddKey(const GpgME::Key&)) );
00525
00526 QStringList fprs;
00527 std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() );
00528 const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) );
00529
00530 if ( err )
00531 return showKeyListError( this, err );
00532
00533
00534 (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this );
00535 ++mListJobCount;
00536 }
00537
00538 static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) {
00539 klv->clearSelection();
00540 if ( selectedKeys.empty() )
00541 return;
00542 for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it )
00543 if ( Kleo::KeyListViewItem * item = klv->itemByFingerprint( it->primaryFingerprint() ) )
00544 item->setSelected( true );
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;
00555
00556 if ( mTruncated > 0 )
00557 KMessageBox::information( this,
00558 i18n("<qt>One backend returned truncated output.<br>"
00559 "Not all available keys are shown</qt>",
00560 "<qt>%n backends returned truncated output.<br>"
00561 "Not all available keys are shown</qt>",
00562 mTruncated),
00563 i18n("Key List Result") );
00564
00565 mKeyListView->flushKeys();
00566
00567 mKeyListView->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
00580 mKeyListView->setContentsPos( 0, mSavedOffsetY ); mSavedOffsetY = 0;
00581 }
00582
00583 void Kleo::KeySelectionDialog::slotSelectionChanged() {
00584 kdDebug(5150) << "KeySelectionDialog::slotSelectionChanged()" << endl;
00585
00586
00587
00588
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
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 mKeyListView->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 );
00651 }
00652 if ( !smime.empty() ) {
00653 assert( mSMIMEBackend );
00654 startKeyListJobForBackend( mSMIMEBackend, smime, true );
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
00691 if ( !actionButton( Ok )->isEnabled() )
00692 return;
00693 mStartSearchTimer->stop();
00694 accept();
00695 }
00696
00697
00698 void Kleo::KeySelectionDialog::slotCancel() {
00699 mCheckSelectionTimer->stop();
00700 mStartSearchTimer->stop();
00701 reject();
00702 }
00703
00704 void Kleo::KeySelectionDialog::slotSearch( const QString & text ) {
00705 mSearchText = text.stripWhiteSpace().upper();
00706 slotSearch();
00707 }
00708
00709 void Kleo::KeySelectionDialog::slotSearch() {
00710 mStartSearchTimer->start( sCheckSelectionDelay, true );
00711 }
00712
00713 void Kleo::KeySelectionDialog::slotFilter() {
00714 if ( mSearchText.isEmpty() ) {
00715 showAllItems();
00716 return;
00717 }
00718
00719
00720 QRegExp keyIdRegExp( "(?:0x)?[A-F0-9]{1,8}", false );
00721 if ( keyIdRegExp.exactMatch( mSearchText ) ) {
00722 if ( mSearchText.startsWith( "0X" ) )
00723
00724 filterByKeyID( mSearchText.mid( 2 ) );
00725 else
00726
00727 filterByKeyIDOrUID( mSearchText );
00728 } else {
00729
00730 filterByUID( mSearchText );
00731 }
00732 }
00733
00734 void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) {
00735 assert( keyID.length() <= 8 );
00736 assert( !keyID.isEmpty() );
00737 if ( keyID.isEmpty() )
00738 showAllItems();
00739 else
00740 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00741 item->setVisible( item->text( 0 ).upper().startsWith( keyID ) );
00742 }
00743
00744 static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) {
00745 if ( !item )
00746 return false;
00747
00748 const std::vector<GpgME::UserID> uids = item->key().userIDs();
00749 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
00750 if ( it->id() && rx.search( QString::fromUtf8( it->id() ) ) >= 0 )
00751 return true;
00752 return false;
00753 }
00754
00755 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const QString & str ) {
00756 assert( !str.isEmpty() );
00757
00758
00759 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00760
00761 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00762 item->setVisible( item->text( 0 ).upper().startsWith( str ) || anyUIDMatches( item, rx ) );
00763
00764 }
00765
00766 void Kleo::KeySelectionDialog::filterByUID( const QString & str ) {
00767 assert( !str.isEmpty() );
00768
00769
00770 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00771
00772 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00773 item->setVisible( anyUIDMatches( item, rx ) );
00774 }
00775
00776
00777 void Kleo::KeySelectionDialog::showAllItems() {
00778 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00779 item->setVisible( true );
00780 }
00781
00782 #include "keyselectiondialog.moc"