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 <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
00130
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
00140
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
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.primaryFingerprint();
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
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 );
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 );
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().primaryFingerprint();
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->primaryFingerprint() )
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->primaryFingerprint() )
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->primaryFingerprint() )
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
00471 if ( mOpenPGPBackend )
00472 startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false );
00473 if ( mSMIMEBackend )
00474 startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false );
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 #ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00487 #define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00488 static void showKeyListError( QWidget * parent, const GpgME::Error & err ) {
00489 assert( err );
00490 const QString msg = i18n( "<qt><p>An error occurred while fetching "
00491 "the keys from the backend:</p>"
00492 "<p><b>%1</b></p></qt>" )
00493 .arg( QString::fromLocal8Bit( err.asString() ) );
00494
00495 KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) );
00496 }
00497 #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00498
00499 namespace {
00500 struct ExtractFingerprint {
00501 QString operator()( const GpgME::Key & key ) {
00502 return key.primaryFingerprint();
00503 }
00504 };
00505 }
00506
00507 void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) {
00508 assert( backend );
00509 KeyListJob * job = backend->keyListJob( false, false, validate );
00510 if ( !job )
00511 return;
00512
00513 connect( job, SIGNAL(result(const GpgME::KeyListResult&)),
00514 SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
00515 connect( job, SIGNAL(nextKey(const GpgME::Key&)),
00516 mKeyListView, validate ?
00517 SLOT(slotRefreshKey(const GpgME::Key&)) :
00518 SLOT(slotAddKey(const GpgME::Key&)) );
00519
00520 QStringList fprs;
00521 std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() );
00522 const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) );
00523
00524 if ( err )
00525 return showKeyListError( this, err );
00526
00527
00528 (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this );
00529 ++mListJobCount;
00530 }
00531
00532 static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) {
00533 klv->clearSelection();
00534 if ( selectedKeys.empty() )
00535 return;
00536 for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it )
00537 if ( Kleo::KeyListViewItem * item = klv->itemByFingerprint( it->primaryFingerprint() ) )
00538 item->setSelected( true );
00539 }
00540
00541 void Kleo::KeySelectionDialog::slotKeyListResult( const GpgME::KeyListResult & res ) {
00542 if ( res.error() )
00543 showKeyListError( this, res.error() );
00544 else if ( res.isTruncated() )
00545 ++mTruncated;
00546
00547 if ( --mListJobCount > 0 )
00548 return;
00549
00550 if ( mTruncated > 0 )
00551 KMessageBox::information( this,
00552 i18n("<qt>One backend returned truncated output.<br>"
00553 "Not all available keys are shown</qt>",
00554 "<qt>%n backends returned truncated output.<br>"
00555 "Not all available keys are shown</qt>",
00556 mTruncated),
00557 i18n("Key List Result") );
00558
00559 mKeyListView->flushKeys();
00560
00561 this->setEnabled( true );
00562 mListJobCount = mTruncated = 0;
00563 mKeysToCheck.clear();
00564
00565 selectKeys( mKeyListView, mSelectedKeys );
00566
00567 slotFilter();
00568
00569 connectSignals();
00570
00571 slotSelectionChanged();
00572
00573
00574 mKeyListView->setContentsPos( 0, mSavedOffsetY ); mSavedOffsetY = 0;
00575 }
00576
00577 void Kleo::KeySelectionDialog::slotSelectionChanged() {
00578 kdDebug(5150) << "KeySelectionDialog::slotSelectionChanged()" << endl;
00579
00580
00581
00582
00583 mCheckSelectionTimer->start( sCheckSelectionDelay );
00584 }
00585
00586 namespace {
00587 struct AlreadyChecked {
00588 bool operator()( const GpgME::Key & key ) const {
00589 return key.keyListMode() & GpgME::Context::Validate ;
00590 }
00591 };
00592 }
00593
00594 void Kleo::KeySelectionDialog::slotCheckSelection( KeyListViewItem * item ) {
00595 kdDebug(5150) << "KeySelectionDialog::slotCheckSelection()\n";
00596
00597 mCheckSelectionTimer->stop();
00598
00599 mSelectedKeys.clear();
00600
00601 if ( !mKeyListView->isMultiSelection() ) {
00602 if ( item )
00603 mSelectedKeys.push_back( item->key() );
00604 }
00605
00606 for ( KeyListViewItem * it = mKeyListView->firstChild() ; it ; it = it->nextSibling() )
00607 if ( it->isSelected() )
00608 mSelectedKeys.push_back( it->key() );
00609
00610 mKeysToCheck.clear();
00611 std::remove_copy_if( mSelectedKeys.begin(), mSelectedKeys.end(),
00612 std::back_inserter( mKeysToCheck ),
00613 AlreadyChecked() );
00614 if ( mKeysToCheck.empty() ) {
00615 enableButtonOK( !mSelectedKeys.empty() &&
00616 checkKeyUsage( mSelectedKeys, mKeyUsage ) );
00617 return;
00618 }
00619
00620
00621 startValidatingKeyListing();
00622 }
00623
00624 void Kleo::KeySelectionDialog::startValidatingKeyListing() {
00625 if ( mKeysToCheck.empty() )
00626 return;
00627
00628 mListJobCount = 0;
00629 mTruncated = 0;
00630 mSavedOffsetY = mKeyListView->contentsY();
00631
00632 disconnectSignals();
00633 this->setEnabled( false );
00634
00635 std::vector<GpgME::Key> smime, openpgp;
00636 for ( std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin() ; it != mKeysToCheck.end() ; ++it )
00637 if ( it->protocol() == GpgME::Context::OpenPGP )
00638 openpgp.push_back( *it );
00639 else
00640 smime.push_back( *it );
00641
00642 if ( !openpgp.empty() ) {
00643 assert( mOpenPGPBackend );
00644 startKeyListJobForBackend( mOpenPGPBackend, openpgp, true );
00645 }
00646 if ( !smime.empty() ) {
00647 assert( mSMIMEBackend );
00648 startKeyListJobForBackend( mSMIMEBackend, smime, true );
00649 }
00650
00651 assert( mListJobCount > 0 );
00652 }
00653
00654 bool Kleo::KeySelectionDialog::rememberSelection() const {
00655 return mRememberCB && mRememberCB->isChecked() ;
00656 }
00657
00658 void Kleo::KeySelectionDialog::slotRMB( Kleo::KeyListViewItem * item, const QPoint & p ) {
00659 if ( !item ) return;
00660
00661 mCurrentContextMenuItem = item;
00662
00663 QPopupMenu menu;
00664 menu.insertItem( i18n( "Recheck Key" ), this, SLOT(slotRecheckKey()) );
00665 menu.exec( p );
00666 }
00667
00668 void Kleo::KeySelectionDialog::slotRecheckKey() {
00669 if ( !mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull() )
00670 return;
00671
00672 mKeysToCheck.clear();
00673 mKeysToCheck.push_back( mCurrentContextMenuItem->key() );
00674 }
00675
00676 void Kleo::KeySelectionDialog::slotTryOk() {
00677 if ( actionButton( Ok )->isEnabled() )
00678 slotOk();
00679 }
00680
00681 void Kleo::KeySelectionDialog::slotOk() {
00682 if ( mCheckSelectionTimer->isActive() )
00683 slotCheckSelection();
00684 mStartSearchTimer->stop();
00685 accept();
00686 }
00687
00688
00689 void Kleo::KeySelectionDialog::slotCancel() {
00690 mCheckSelectionTimer->stop();
00691 mStartSearchTimer->stop();
00692 reject();
00693 }
00694
00695 void Kleo::KeySelectionDialog::slotSearch( const QString & text ) {
00696 mSearchText = text.stripWhiteSpace().upper();
00697 slotSearch();
00698 }
00699
00700 void Kleo::KeySelectionDialog::slotSearch() {
00701 mStartSearchTimer->start( sCheckSelectionDelay, true );
00702 }
00703
00704 void Kleo::KeySelectionDialog::slotFilter() {
00705 if ( mSearchText.isEmpty() ) {
00706 showAllItems();
00707 return;
00708 }
00709
00710
00711 QRegExp keyIdRegExp( "(?:0x)?[A-F0-9]{1,8}", false );
00712 if ( keyIdRegExp.exactMatch( mSearchText ) ) {
00713 if ( mSearchText.startsWith( "0X" ) )
00714
00715 filterByKeyID( mSearchText.mid( 2 ) );
00716 else
00717
00718 filterByKeyIDOrUID( mSearchText );
00719 } else {
00720
00721 filterByUID( mSearchText );
00722 }
00723 }
00724
00725 void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) {
00726 assert( keyID.length() <= 8 );
00727 assert( !keyID.isEmpty() );
00728 if ( keyID.isEmpty() )
00729 showAllItems();
00730 else
00731 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00732 item->setVisible( item->text( 0 ).upper().startsWith( keyID ) );
00733 }
00734
00735 static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) {
00736 if ( !item )
00737 return false;
00738
00739 const std::vector<GpgME::UserID> uids = item->key().userIDs();
00740 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
00741 if ( it->id() && rx.search( QString::fromUtf8( it->id() ) ) >= 0 )
00742 return true;
00743 return false;
00744 }
00745
00746 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const QString & str ) {
00747 assert( !str.isEmpty() );
00748
00749
00750 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00751
00752 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00753 item->setVisible( item->text( 0 ).upper().startsWith( str ) || anyUIDMatches( item, rx ) );
00754
00755 }
00756
00757 void Kleo::KeySelectionDialog::filterByUID( const QString & str ) {
00758 assert( !str.isEmpty() );
00759
00760
00761 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00762
00763 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00764 item->setVisible( anyUIDMatches( item, rx ) );
00765 }
00766
00767
00768 void Kleo::KeySelectionDialog::showAllItems() {
00769 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00770 item->setVisible( true );
00771 }
00772
00773 #include "keyselectiondialog.moc"