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