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 mCheckSelectionTimer = new QTimer( this );
00336 mStartSearchTimer = new QTimer( this );
00337
00338 QFrame *page = makeMainWidget();
00339 mTopLayout = new QVBoxLayout( page, 0, spacingHint() );
00340
00341 if ( !text.isEmpty() ) {
00342 QLabel* textLabel = new QLabel( text, page );
00343 textLabel->setAlignment( textLabel->alignment() | Qt::WordBreak );
00344 mTopLayout->addWidget( textLabel );
00345 }
00346
00347 QHBoxLayout * hlay = new QHBoxLayout( mTopLayout );
00348 QLineEdit * le = new QLineEdit( page );
00349 le->setText( initialQuery );
00350 QToolButton *clearButton = new QToolButton( page );
00351 clearButton->setIconSet( KGlobal::iconLoader()->loadIconSet(
00352 KApplication::reverseLayout() ? "clear_left":"locationbar_erase", KIcon::Small, 0 ) );
00353 hlay->addWidget( clearButton );
00354 hlay->addWidget( new QLabel( le, i18n("&Search for:"), page ) );
00355 hlay->addWidget( le, 1 );
00356 le->setFocus();
00357
00358 connect( clearButton, SIGNAL( clicked() ), le, SLOT( clear() ) );
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 );
00368 mKeyListView->setShowToolTips( true );
00369 if ( extendedSelection )
00370 mKeyListView->setSelectionMode( QListView::Extended );
00371 mTopLayout->addWidget( mKeyListView, 10 );
00372
00373 if ( rememberChoice ) {
00374 mRememberCB = new QCheckBox( i18n("&Remember choice"), page );
00375 mTopLayout->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 mTopLayout->activate();
00399
00400 if ( kapp ) {
00401 KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
00402 QSize dialogSize( sizeHint() );
00403
00404 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
00405 dialogSize = dialogConfig.readSizeEntry( "Dialog size", &dialogSize );
00406 resize( dialogSize );
00407 }
00408 }
00409
00410 Kleo::KeySelectionDialog::~KeySelectionDialog() {
00411 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
00412 dialogConfig.writeEntry( "Dialog size", size() );
00413 dialogConfig.sync();
00414 }
00415
00416
00417 void Kleo::KeySelectionDialog::connectSignals() {
00418 if ( mKeyListView->isMultiSelection() )
00419 connect( mKeyListView, SIGNAL(selectionChanged()),
00420 SLOT(slotSelectionChanged()) );
00421 else
00422 connect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00423 SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00424 }
00425
00426 void Kleo::KeySelectionDialog::disconnectSignals() {
00427 if ( mKeyListView->isMultiSelection() )
00428 disconnect( mKeyListView, SIGNAL(selectionChanged()),
00429 this, SLOT(slotSelectionChanged()) );
00430 else
00431 disconnect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00432 this, SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00433 }
00434
00435 const GpgME::Key & Kleo::KeySelectionDialog::selectedKey() const {
00436 if ( mKeyListView->isMultiSelection() || !mKeyListView->selectedItem() )
00437 return GpgME::Key::null;
00438 return mKeyListView->selectedItem()->key();
00439 }
00440
00441 QString Kleo::KeySelectionDialog::fingerprint() const {
00442 return selectedKey().primaryFingerprint();
00443 }
00444
00445 QStringList Kleo::KeySelectionDialog::fingerprints() const {
00446 QStringList result;
00447 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00448 if ( const char * fpr = it->primaryFingerprint() )
00449 result.push_back( fpr );
00450 return result;
00451 }
00452
00453 QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const {
00454 QStringList result;
00455 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00456 if ( it->protocol() == GpgME::Context::OpenPGP )
00457 if ( const char * fpr = it->primaryFingerprint() )
00458 result.push_back( fpr );
00459 return result;
00460 }
00461
00462 QStringList Kleo::KeySelectionDialog::smimeFingerprints() const {
00463 QStringList result;
00464 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00465 if ( it->protocol() == GpgME::Context::CMS )
00466 if ( const char * fpr = it->primaryFingerprint() )
00467 result.push_back( fpr );
00468 return result;
00469 }
00470
00471 void Kleo::KeySelectionDialog::slotRereadKeys() {
00472 mKeyListView->clear();
00473 mListJobCount = 0;
00474 mTruncated = 0;
00475 mSavedOffsetY = mKeyListView->contentsY();
00476
00477 disconnectSignals();
00478 mKeyListView->setEnabled( false );
00479
00480
00481 if ( mOpenPGPBackend )
00482 startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false );
00483 if ( mSMIMEBackend )
00484 startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false );
00485
00486 if ( mListJobCount == 0 ) {
00487 mKeyListView->setEnabled( true );
00488 KMessageBox::information( this,
00489 i18n("No backends found for listing keys. "
00490 "Check your installation."),
00491 i18n("Key Listing Failed") );
00492 connectSignals();
00493 }
00494 }
00495
00496 #ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00497 #define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00498 static void showKeyListError( QWidget * parent, const GpgME::Error & err ) {
00499 assert( err );
00500 const QString msg = i18n( "<qt><p>An error occurred while fetching "
00501 "the keys from the backend:</p>"
00502 "<p><b>%1</b></p></qt>" )
00503 .arg( QString::fromLocal8Bit( err.asString() ) );
00504
00505 KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) );
00506 }
00507 #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00508
00509 namespace {
00510 struct ExtractFingerprint {
00511 QString operator()( const GpgME::Key & key ) {
00512 return key.primaryFingerprint();
00513 }
00514 };
00515 }
00516
00517 void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) {
00518 assert( backend );
00519 KeyListJob * job = backend->keyListJob( false, false, validate );
00520 if ( !job )
00521 return;
00522
00523 connect( job, SIGNAL(result(const GpgME::KeyListResult&)),
00524 SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
00525 connect( job, SIGNAL(nextKey(const GpgME::Key&)),
00526 mKeyListView, validate ?
00527 SLOT(slotRefreshKey(const GpgME::Key&)) :
00528 SLOT(slotAddKey(const GpgME::Key&)) );
00529
00530 QStringList fprs;
00531 std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() );
00532 const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) );
00533
00534 if ( err )
00535 return showKeyListError( this, err );
00536
00537
00538 (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this );
00539 ++mListJobCount;
00540 }
00541
00542 static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) {
00543 klv->clearSelection();
00544 if ( selectedKeys.empty() )
00545 return;
00546 for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it )
00547 if ( Kleo::KeyListViewItem * item = klv->itemByFingerprint( it->primaryFingerprint() ) )
00548 item->setSelected( true );
00549 }
00550
00551 void Kleo::KeySelectionDialog::slotKeyListResult( const GpgME::KeyListResult & res ) {
00552 if ( res.error() )
00553 showKeyListError( this, res.error() );
00554 else if ( res.isTruncated() )
00555 ++mTruncated;
00556
00557 if ( --mListJobCount > 0 )
00558 return;
00559
00560 if ( mTruncated > 0 )
00561 KMessageBox::information( this,
00562 i18n("<qt>One backend returned truncated output.<br>"
00563 "Not all available keys are shown</qt>",
00564 "<qt>%n backends returned truncated output.<br>"
00565 "Not all available keys are shown</qt>",
00566 mTruncated),
00567 i18n("Key List Result") );
00568
00569 mKeyListView->flushKeys();
00570
00571 mKeyListView->setEnabled( true );
00572 mListJobCount = mTruncated = 0;
00573 mKeysToCheck.clear();
00574
00575 selectKeys( mKeyListView, mSelectedKeys );
00576
00577 slotFilter();
00578
00579 connectSignals();
00580
00581 slotSelectionChanged();
00582
00583
00584 mKeyListView->setContentsPos( 0, mSavedOffsetY ); mSavedOffsetY = 0;
00585 }
00586
00587 void Kleo::KeySelectionDialog::slotSelectionChanged() {
00588 kdDebug(5150) << "KeySelectionDialog::slotSelectionChanged()" << endl;
00589
00590
00591
00592
00593 mCheckSelectionTimer->start( sCheckSelectionDelay );
00594 }
00595
00596 namespace {
00597 struct AlreadyChecked {
00598 bool operator()( const GpgME::Key & key ) const {
00599 return key.keyListMode() & GpgME::Context::Validate ;
00600 }
00601 };
00602 }
00603
00604 void Kleo::KeySelectionDialog::slotCheckSelection( KeyListViewItem * item ) {
00605 kdDebug(5150) << "KeySelectionDialog::slotCheckSelection()\n";
00606
00607 mCheckSelectionTimer->stop();
00608
00609 mSelectedKeys.clear();
00610
00611 if ( !mKeyListView->isMultiSelection() ) {
00612 if ( item )
00613 mSelectedKeys.push_back( item->key() );
00614 }
00615
00616 for ( KeyListViewItem * it = mKeyListView->firstChild() ; it ; it = it->nextSibling() )
00617 if ( it->isSelected() )
00618 mSelectedKeys.push_back( it->key() );
00619
00620 mKeysToCheck.clear();
00621 std::remove_copy_if( mSelectedKeys.begin(), mSelectedKeys.end(),
00622 std::back_inserter( mKeysToCheck ),
00623 AlreadyChecked() );
00624 if ( mKeysToCheck.empty() ) {
00625 enableButtonOK( !mSelectedKeys.empty() &&
00626 checkKeyUsage( mSelectedKeys, mKeyUsage ) );
00627 return;
00628 }
00629
00630
00631 startValidatingKeyListing();
00632 }
00633
00634 void Kleo::KeySelectionDialog::startValidatingKeyListing() {
00635 if ( mKeysToCheck.empty() )
00636 return;
00637
00638 mListJobCount = 0;
00639 mTruncated = 0;
00640 mSavedOffsetY = mKeyListView->contentsY();
00641
00642 disconnectSignals();
00643 mKeyListView->setEnabled( false );
00644
00645 std::vector<GpgME::Key> smime, openpgp;
00646 for ( std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin() ; it != mKeysToCheck.end() ; ++it )
00647 if ( it->protocol() == GpgME::Context::OpenPGP )
00648 openpgp.push_back( *it );
00649 else
00650 smime.push_back( *it );
00651
00652 if ( !openpgp.empty() ) {
00653 assert( mOpenPGPBackend );
00654 startKeyListJobForBackend( mOpenPGPBackend, openpgp, true );
00655 }
00656 if ( !smime.empty() ) {
00657 assert( mSMIMEBackend );
00658 startKeyListJobForBackend( mSMIMEBackend, smime, true );
00659 }
00660
00661 assert( mListJobCount > 0 );
00662 }
00663
00664 bool Kleo::KeySelectionDialog::rememberSelection() const {
00665 return mRememberCB && mRememberCB->isChecked() ;
00666 }
00667
00668 void Kleo::KeySelectionDialog::slotRMB( Kleo::KeyListViewItem * item, const QPoint & p ) {
00669 if ( !item ) return;
00670
00671 mCurrentContextMenuItem = item;
00672
00673 QPopupMenu menu;
00674 menu.insertItem( i18n( "Recheck Key" ), this, SLOT(slotRecheckKey()) );
00675 menu.exec( p );
00676 }
00677
00678 void Kleo::KeySelectionDialog::slotRecheckKey() {
00679 if ( !mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull() )
00680 return;
00681
00682 mKeysToCheck.clear();
00683 mKeysToCheck.push_back( mCurrentContextMenuItem->key() );
00684 }
00685
00686 void Kleo::KeySelectionDialog::slotTryOk() {
00687 if ( actionButton( Ok )->isEnabled() )
00688 slotOk();
00689 }
00690
00691 void Kleo::KeySelectionDialog::slotOk() {
00692 if ( mCheckSelectionTimer->isActive() )
00693 slotCheckSelection();
00694
00695 if ( !actionButton( Ok )->isEnabled() )
00696 return;
00697 mStartSearchTimer->stop();
00698 accept();
00699 }
00700
00701
00702 void Kleo::KeySelectionDialog::slotCancel() {
00703 mCheckSelectionTimer->stop();
00704 mStartSearchTimer->stop();
00705 reject();
00706 }
00707
00708 void Kleo::KeySelectionDialog::slotSearch( const QString & text ) {
00709 mSearchText = text.stripWhiteSpace().upper();
00710 slotSearch();
00711 }
00712
00713 void Kleo::KeySelectionDialog::slotSearch() {
00714 mStartSearchTimer->start( sCheckSelectionDelay, true );
00715 }
00716
00717 void Kleo::KeySelectionDialog::slotFilter() {
00718 if ( mSearchText.isEmpty() ) {
00719 showAllItems();
00720 return;
00721 }
00722
00723
00724 QRegExp keyIdRegExp( "(?:0x)?[A-F0-9]{1,8}", false );
00725 if ( keyIdRegExp.exactMatch( mSearchText ) ) {
00726 if ( mSearchText.startsWith( "0X" ) )
00727
00728 filterByKeyID( mSearchText.mid( 2 ) );
00729 else
00730
00731 filterByKeyIDOrUID( mSearchText );
00732 } else {
00733
00734 filterByUID( mSearchText );
00735 }
00736 }
00737
00738 void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) {
00739 assert( keyID.length() <= 8 );
00740 assert( !keyID.isEmpty() );
00741 if ( keyID.isEmpty() )
00742 showAllItems();
00743 else
00744 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00745 item->setVisible( item->text( 0 ).upper().startsWith( keyID ) );
00746 }
00747
00748 static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) {
00749 if ( !item )
00750 return false;
00751
00752 const std::vector<GpgME::UserID> uids = item->key().userIDs();
00753 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
00754 if ( it->id() && rx.search( QString::fromUtf8( it->id() ) ) >= 0 )
00755 return true;
00756 return false;
00757 }
00758
00759 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const QString & str ) {
00760 assert( !str.isEmpty() );
00761
00762
00763 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00764
00765 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00766 item->setVisible( item->text( 0 ).upper().startsWith( str ) || anyUIDMatches( item, rx ) );
00767
00768 }
00769
00770 void Kleo::KeySelectionDialog::filterByUID( const QString & str ) {
00771 assert( !str.isEmpty() );
00772
00773
00774 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00775
00776 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00777 item->setVisible( anyUIDMatches( item, rx ) );
00778 }
00779
00780
00781 void Kleo::KeySelectionDialog::showAllItems() {
00782 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00783 item->setVisible( true );
00784 }
00785
00786 #include "keyselectiondialog.moc"