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