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 #include <kprocess.h>
00064
00065
00066 #include <qcheckbox.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 qDebug( "key is invalid - ignoring" );
00088 if ( key.isExpired() ) {
00089 qDebug( "key is expired" );
00090 return false;
00091 } else if ( key.isRevoked() ) {
00092 qDebug( "key is revoked" );
00093 return false;
00094 } else if ( key.isDisabled() ) {
00095 qDebug( "key is disabled" );
00096 return false;
00097 }
00098 }
00099
00100 if ( keyUsage & Kleo::KeySelectionDialog::EncryptionKeys &&
00101 !key.canEncrypt() ) {
00102 qDebug( "key can't encrypt" );
00103 return false;
00104 }
00105 if ( keyUsage & Kleo::KeySelectionDialog::SigningKeys &&
00106 !key.canSign() ) {
00107 qDebug( "key can't sign" );
00108 return false;
00109 }
00110 if ( keyUsage & Kleo::KeySelectionDialog::CertificationKeys &&
00111 !key.canCertify() ) {
00112 qDebug( "key can't certify" );
00113 return false;
00114 }
00115 if ( keyUsage & Kleo::KeySelectionDialog::AuthenticationKeys &&
00116 !key.canAuthenticate() ) {
00117 qDebug( "key can't authenticate" );
00118 return false;
00119 }
00120
00121 if ( keyUsage & Kleo::KeySelectionDialog::SecretKeys &&
00122 !( keyUsage & Kleo::KeySelectionDialog::PublicKeys ) &&
00123 !key.isSecret() ) {
00124 qDebug( "key isn't secret" );
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 qDebug( "key has no UIDs with validity >= Marginal" );
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|Help, 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|Help, 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 mTopLayout = new QVBoxLayout( page, 0, spacingHint() );
00349
00350 if ( !text.isEmpty() )
00351 mTopLayout->addWidget( new QLabel( text, page ) );
00352
00353 QHBoxLayout * hlay = new QHBoxLayout( mTopLayout );
00354 QLineEdit * le = new QLineEdit( page );
00355 le->setText( initialQuery );
00356 hlay->addWidget( new QLabel( le, i18n("&Search for:"), page ) );
00357 hlay->addWidget( le, 1 );
00358 le->setFocus();
00359
00360 connect( le, SIGNAL(textChanged(const QString&)),
00361 this, SLOT(slotSearch(const QString&)) );
00362 connect( mStartSearchTimer, SIGNAL(timeout()), SLOT(slotFilter()) );
00363
00364 mKeyListView = new KeyListView( new ColumnStrategy( mKeyUsage ), 0, page, "mKeyListView" );
00365 mKeyListView->setResizeMode( QListView::LastColumn );
00366 mKeyListView->setRootIsDecorated( true );
00367 mKeyListView->setShowSortIndicator( true );
00368 mKeyListView->setSorting( 1, true );
00369 mKeyListView->setShowToolTips( true );
00370 if ( extendedSelection )
00371 mKeyListView->setSelectionMode( QListView::Extended );
00372 mTopLayout->addWidget( mKeyListView, 10 );
00373
00374 if ( rememberChoice ) {
00375 mRememberCB = new QCheckBox( i18n("&Remember choice"), page );
00376 mTopLayout->addWidget( mRememberCB );
00377 QWhatsThis::add( mRememberCB,
00378 i18n("<qt><p>If you check this box your choice will "
00379 "be stored and you will not be asked again."
00380 "</p></qt>") );
00381 }
00382
00383 connect( mCheckSelectionTimer, SIGNAL(timeout()),
00384 SLOT(slotCheckSelection()) );
00385 connectSignals();
00386
00387 connect( mKeyListView,
00388 SIGNAL(doubleClicked(Kleo::KeyListViewItem*,const QPoint&,int)),
00389 SLOT(slotTryOk()) );
00390 connect( mKeyListView,
00391 SIGNAL(contextMenu(Kleo::KeyListViewItem*,const QPoint&)),
00392 SLOT(slotRMB(Kleo::KeyListViewItem*,const QPoint&)) );
00393
00394 setButtonText( KDialogBase::Default, i18n("&Reread Keys") );
00395 setButtonText( KDialogBase::Help, i18n("&Start Certificate Manager") );
00396 connect( this, SIGNAL(defaultClicked()), this, SLOT(slotRereadKeys()) );
00397 connect( this, SIGNAL(helpClicked()), this, SLOT(slotStartCertificateManager()) );
00398
00399 slotRereadKeys();
00400 }
00401
00402 Kleo::KeySelectionDialog::~KeySelectionDialog() {
00403 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
00404 dialogConfig.writeEntry( "Dialog size", size() );
00405 dialogConfig.sync();
00406 }
00407
00408
00409 void Kleo::KeySelectionDialog::connectSignals() {
00410 if ( mKeyListView->isMultiSelection() )
00411 connect( mKeyListView, SIGNAL(selectionChanged()),
00412 SLOT(slotSelectionChanged()) );
00413 else
00414 connect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00415 SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00416 }
00417
00418 void Kleo::KeySelectionDialog::disconnectSignals() {
00419 if ( mKeyListView->isMultiSelection() )
00420 disconnect( mKeyListView, SIGNAL(selectionChanged()),
00421 this, SLOT(slotSelectionChanged()) );
00422 else
00423 disconnect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00424 this, SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00425 }
00426
00427 const GpgME::Key & Kleo::KeySelectionDialog::selectedKey() const {
00428 if ( mKeyListView->isMultiSelection() || !mKeyListView->selectedItem() )
00429 return GpgME::Key::null;
00430 return mKeyListView->selectedItem()->key();
00431 }
00432
00433 QString Kleo::KeySelectionDialog::fingerprint() const {
00434 return selectedKey().primaryFingerprint();
00435 }
00436
00437 QStringList Kleo::KeySelectionDialog::fingerprints() const {
00438 QStringList result;
00439 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00440 if ( const char * fpr = it->primaryFingerprint() )
00441 result.push_back( fpr );
00442 return result;
00443 }
00444
00445 QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const {
00446 QStringList result;
00447 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00448 if ( it->protocol() == GpgME::Context::OpenPGP )
00449 if ( const char * fpr = it->primaryFingerprint() )
00450 result.push_back( fpr );
00451 return result;
00452 }
00453
00454 QStringList Kleo::KeySelectionDialog::smimeFingerprints() const {
00455 QStringList result;
00456 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00457 if ( it->protocol() == GpgME::Context::CMS )
00458 if ( const char * fpr = it->primaryFingerprint() )
00459 result.push_back( fpr );
00460 return result;
00461 }
00462
00463 void Kleo::KeySelectionDialog::slotRereadKeys() {
00464 mKeyListView->clear();
00465 mListJobCount = 0;
00466 mTruncated = 0;
00467 mSavedOffsetY = mKeyListView->contentsY();
00468
00469 disconnectSignals();
00470 mKeyListView->setEnabled( false );
00471
00472
00473 if ( mOpenPGPBackend )
00474 startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false );
00475 if ( mSMIMEBackend )
00476 startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false );
00477
00478 if ( mListJobCount == 0 ) {
00479 mKeyListView->setEnabled( true );
00480 KMessageBox::information( this,
00481 i18n("No backends found for listing keys. "
00482 "Check your installation."),
00483 i18n("Key Listing Failed") );
00484 connectSignals();
00485 }
00486 }
00487
00488 void Kleo::KeySelectionDialog::slotHelp()
00489 {
00490 emit helpClicked();
00491 }
00492
00493 void Kleo::KeySelectionDialog::slotStartCertificateManager()
00494 {
00495 KProcess certManagerProc;
00496 certManagerProc << "kleopatra";
00497
00498 if( !certManagerProc.start( KProcess::DontCare ) )
00499 KMessageBox::error( this, i18n( "Could not start certificate manager; "
00500 "please check your installation." ),
00501 i18n( "Certificate Manager Error" ) );
00502 else
00503 kdDebug(5006) << "\nslotStartCertManager(): certificate manager started.\n" << endl;
00504 }
00505
00506 #ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00507 #define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00508 static void showKeyListError( QWidget * parent, const GpgME::Error & err ) {
00509 assert( err );
00510 const QString msg = i18n( "<qt><p>An error occurred while fetching "
00511 "the keys from the backend:</p>"
00512 "<p><b>%1</b></p></qt>" )
00513 .arg( QString::fromLocal8Bit( err.asString() ) );
00514
00515 KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) );
00516 }
00517 #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00518
00519 namespace {
00520 struct ExtractFingerprint {
00521 QString operator()( const GpgME::Key & key ) {
00522 return key.primaryFingerprint();
00523 }
00524 };
00525 }
00526
00527 void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) {
00528 assert( backend );
00529 KeyListJob * job = backend->keyListJob( false, false, validate );
00530 if ( !job )
00531 return;
00532
00533 connect( job, SIGNAL(result(const GpgME::KeyListResult&)),
00534 SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
00535 connect( job, SIGNAL(nextKey(const GpgME::Key&)),
00536 mKeyListView, validate ?
00537 SLOT(slotRefreshKey(const GpgME::Key&)) :
00538 SLOT(slotAddKey(const GpgME::Key&)) );
00539
00540 QStringList fprs;
00541 std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() );
00542 const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) );
00543
00544 if ( err )
00545 return showKeyListError( this, err );
00546
00547
00548 (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this );
00549 ++mListJobCount;
00550 }
00551
00552 static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) {
00553 klv->clearSelection();
00554 if ( selectedKeys.empty() )
00555 return;
00556 for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it )
00557 if ( Kleo::KeyListViewItem * item = klv->itemByFingerprint( it->primaryFingerprint() ) )
00558 item->setSelected( true );
00559 }
00560
00561 void Kleo::KeySelectionDialog::slotKeyListResult( const GpgME::KeyListResult & res ) {
00562 if ( res.error() )
00563 showKeyListError( this, res.error() );
00564 else if ( res.isTruncated() )
00565 ++mTruncated;
00566
00567 if ( --mListJobCount > 0 )
00568 return;
00569
00570 if ( mTruncated > 0 )
00571 KMessageBox::information( this,
00572 i18n("<qt>One backend returned truncated output.<br>"
00573 "Not all available keys are shown</qt>",
00574 "<qt>%n backends returned truncated output.<br>"
00575 "Not all available keys are shown</qt>",
00576 mTruncated),
00577 i18n("Key List Result") );
00578
00579 mKeyListView->flushKeys();
00580
00581 mKeyListView->setEnabled( true );
00582 mListJobCount = mTruncated = 0;
00583 mKeysToCheck.clear();
00584
00585 selectKeys( mKeyListView, mSelectedKeys );
00586
00587 slotFilter();
00588
00589 connectSignals();
00590
00591 slotSelectionChanged();
00592
00593
00594 mKeyListView->setContentsPos( 0, mSavedOffsetY ); mSavedOffsetY = 0;
00595 }
00596
00597 void Kleo::KeySelectionDialog::slotSelectionChanged() {
00598 kdDebug(5150) << "KeySelectionDialog::slotSelectionChanged()" << endl;
00599
00600
00601
00602
00603 mCheckSelectionTimer->start( sCheckSelectionDelay );
00604 }
00605
00606 namespace {
00607 struct AlreadyChecked {
00608 bool operator()( const GpgME::Key & key ) const {
00609 return key.keyListMode() & GpgME::Context::Validate ;
00610 }
00611 };
00612 }
00613
00614 void Kleo::KeySelectionDialog::slotCheckSelection( KeyListViewItem * item ) {
00615 kdDebug(5150) << "KeySelectionDialog::slotCheckSelection()\n";
00616
00617 mCheckSelectionTimer->stop();
00618
00619 mSelectedKeys.clear();
00620
00621 if ( !mKeyListView->isMultiSelection() ) {
00622 if ( item )
00623 mSelectedKeys.push_back( item->key() );
00624 }
00625
00626 for ( KeyListViewItem * it = mKeyListView->firstChild() ; it ; it = it->nextSibling() )
00627 if ( it->isSelected() )
00628 mSelectedKeys.push_back( it->key() );
00629
00630 mKeysToCheck.clear();
00631 std::remove_copy_if( mSelectedKeys.begin(), mSelectedKeys.end(),
00632 std::back_inserter( mKeysToCheck ),
00633 AlreadyChecked() );
00634 if ( mKeysToCheck.empty() ) {
00635 enableButtonOK( !mSelectedKeys.empty() &&
00636 checkKeyUsage( mSelectedKeys, mKeyUsage ) );
00637 return;
00638 }
00639
00640
00641 startValidatingKeyListing();
00642 }
00643
00644 void Kleo::KeySelectionDialog::startValidatingKeyListing() {
00645 if ( mKeysToCheck.empty() )
00646 return;
00647
00648 mListJobCount = 0;
00649 mTruncated = 0;
00650 mSavedOffsetY = mKeyListView->contentsY();
00651
00652 disconnectSignals();
00653 mKeyListView->setEnabled( false );
00654
00655 std::vector<GpgME::Key> smime, openpgp;
00656 for ( std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin() ; it != mKeysToCheck.end() ; ++it )
00657 if ( it->protocol() == GpgME::Context::OpenPGP )
00658 openpgp.push_back( *it );
00659 else
00660 smime.push_back( *it );
00661
00662 if ( !openpgp.empty() ) {
00663 assert( mOpenPGPBackend );
00664 startKeyListJobForBackend( mOpenPGPBackend, openpgp, true );
00665 }
00666 if ( !smime.empty() ) {
00667 assert( mSMIMEBackend );
00668 startKeyListJobForBackend( mSMIMEBackend, smime, true );
00669 }
00670
00671 assert( mListJobCount > 0 );
00672 }
00673
00674 bool Kleo::KeySelectionDialog::rememberSelection() const {
00675 return mRememberCB && mRememberCB->isChecked() ;
00676 }
00677
00678 void Kleo::KeySelectionDialog::slotRMB( Kleo::KeyListViewItem * item, const QPoint & p ) {
00679 if ( !item ) return;
00680
00681 mCurrentContextMenuItem = item;
00682
00683 QPopupMenu menu;
00684 menu.insertItem( i18n( "Recheck Key" ), this, SLOT(slotRecheckKey()) );
00685 menu.exec( p );
00686 }
00687
00688 void Kleo::KeySelectionDialog::slotRecheckKey() {
00689 if ( !mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull() )
00690 return;
00691
00692 mKeysToCheck.clear();
00693 mKeysToCheck.push_back( mCurrentContextMenuItem->key() );
00694 }
00695
00696 void Kleo::KeySelectionDialog::slotTryOk() {
00697 if ( actionButton( Ok )->isEnabled() )
00698 slotOk();
00699 }
00700
00701 void Kleo::KeySelectionDialog::slotOk() {
00702 if ( mCheckSelectionTimer->isActive() )
00703 slotCheckSelection();
00704 mStartSearchTimer->stop();
00705 accept();
00706 }
00707
00708
00709 void Kleo::KeySelectionDialog::slotCancel() {
00710 mCheckSelectionTimer->stop();
00711 mStartSearchTimer->stop();
00712 reject();
00713 }
00714
00715 void Kleo::KeySelectionDialog::slotSearch( const QString & text ) {
00716 mSearchText = text.stripWhiteSpace().upper();
00717 slotSearch();
00718 }
00719
00720 void Kleo::KeySelectionDialog::slotSearch() {
00721 mStartSearchTimer->start( sCheckSelectionDelay, true );
00722 }
00723
00724 void Kleo::KeySelectionDialog::slotFilter() {
00725 if ( mSearchText.isEmpty() ) {
00726 showAllItems();
00727 return;
00728 }
00729
00730
00731 QRegExp keyIdRegExp( "(?:0x)?[A-F0-9]{1,8}", false );
00732 if ( keyIdRegExp.exactMatch( mSearchText ) ) {
00733 if ( mSearchText.startsWith( "0X" ) )
00734
00735 filterByKeyID( mSearchText.mid( 2 ) );
00736 else
00737
00738 filterByKeyIDOrUID( mSearchText );
00739 } else {
00740
00741 filterByUID( mSearchText );
00742 }
00743 }
00744
00745 void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) {
00746 assert( keyID.length() <= 8 );
00747 assert( !keyID.isEmpty() );
00748 if ( keyID.isEmpty() )
00749 showAllItems();
00750 else
00751 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00752 item->setVisible( item->text( 0 ).upper().startsWith( keyID ) );
00753 }
00754
00755 static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) {
00756 if ( !item )
00757 return false;
00758
00759 const std::vector<GpgME::UserID> uids = item->key().userIDs();
00760 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
00761 if ( it->id() && rx.search( QString::fromUtf8( it->id() ) ) >= 0 )
00762 return true;
00763 return false;
00764 }
00765
00766 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( 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( item->text( 0 ).upper().startsWith( str ) || anyUIDMatches( item, rx ) );
00774
00775 }
00776
00777 void Kleo::KeySelectionDialog::filterByUID( const QString & str ) {
00778 assert( !str.isEmpty() );
00779
00780
00781 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00782
00783 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00784 item->setVisible( anyUIDMatches( item, rx ) );
00785 }
00786
00787
00788 void Kleo::KeySelectionDialog::showAllItems() {
00789 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00790 item->setVisible( true );
00791 }
00792
00793 #include "keyselectiondialog.moc"