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 const std::vector<GpgME::Key> & selectedKeys,
00321 unsigned int keyUsage,
00322 bool extendedSelection,
00323 bool rememberChoice,
00324 QWidget * parent, const char * name,
00325 bool modal )
00326 : KDialogBase( parent, name, modal, title, Default|Ok|Cancel|Help, Ok ),
00327 mOpenPGPBackend( 0 ),
00328 mSMIMEBackend( 0 ),
00329 mRememberCB( 0 ),
00330 mSelectedKeys( selectedKeys ),
00331 mKeyUsage( keyUsage ),
00332 mSearchText( initialQuery ),
00333 mInitialQuery( initialQuery ),
00334 mCurrentContextMenuItem( 0 )
00335 {
00336 init( rememberChoice, extendedSelection, text, initialQuery );
00337 }
00338
00339 Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title,
00340 const QString & text,
00341 const QString & initialQuery,
00342 unsigned int keyUsage,
00343 bool extendedSelection,
00344 bool rememberChoice,
00345 QWidget * parent, const char * name,
00346 bool modal )
00347 : KDialogBase( parent, name, modal, title, Default|Ok|Cancel|Help, Ok ),
00348 mOpenPGPBackend( 0 ),
00349 mSMIMEBackend( 0 ),
00350 mRememberCB( 0 ),
00351 mKeyUsage( keyUsage ),
00352 mSearchText( initialQuery ),
00353 mInitialQuery( initialQuery ),
00354 mCurrentContextMenuItem( 0 )
00355 {
00356 init( rememberChoice, extendedSelection, text, initialQuery );
00357 }
00358
00359 void Kleo::KeySelectionDialog::init( bool rememberChoice, bool extendedSelection,
00360 const QString & text, const QString & initialQuery ) {
00361 if ( mKeyUsage & OpenPGPKeys )
00362 mOpenPGPBackend = Kleo::CryptoBackendFactory::instance()->openpgp();
00363 if ( mKeyUsage & SMIMEKeys )
00364 mSMIMEBackend = Kleo::CryptoBackendFactory::instance()->smime();
00365
00366 mCheckSelectionTimer = new QTimer( this );
00367 mStartSearchTimer = new QTimer( this );
00368
00369 QFrame *page = makeMainWidget();
00370 mTopLayout = new QVBoxLayout( page, 0, spacingHint() );
00371
00372 if ( !text.isEmpty() ) {
00373 if ( text.startsWith( "<qt>" ) ) {
00374 KActiveLabel *textLabel = new KActiveLabel( text, page );
00375 disconnect( textLabel, SIGNAL(linkClicked(const QString&)), textLabel, SLOT(openLink(const QString&)) );
00376 connect( textLabel, SIGNAL(linkClicked(const QString&)), SLOT(slotStartCertificateManager(const QString&)) );
00377 textLabel->setAlignment( textLabel->alignment() | Qt::WordBreak );
00378 mTopLayout->addWidget( textLabel );
00379 } else {
00380 KActiveLabel *textLabel = new KActiveLabel( text, page );
00381 textLabel->setAlignment( textLabel->alignment() | Qt::WordBreak );
00382 mTopLayout->addWidget( textLabel );
00383 }
00384 }
00385
00386 QPushButton * const searchExternalPB
00387 = new QPushButton( i18n("Search for &External Certificates"), page );
00388 mTopLayout->addWidget( searchExternalPB, 0, Qt::AlignLeft );
00389 connect( searchExternalPB, SIGNAL(clicked()), this, SLOT(slotStartSearchForExternalCertificates()) );
00390 if ( initialQuery.isEmpty() )
00391 searchExternalPB->hide();
00392
00393 QHBoxLayout * hlay = new QHBoxLayout( mTopLayout );
00394 QLineEdit * le = new QLineEdit( page );
00395 le->setText( initialQuery );
00396 QToolButton *clearButton = new QToolButton( page );
00397 clearButton->setIconSet( KGlobal::iconLoader()->loadIconSet(
00398 KApplication::reverseLayout() ? "clear_left":"locationbar_erase", KIcon::Small, 0 ) );
00399 hlay->addWidget( clearButton );
00400 hlay->addWidget( new QLabel( le, i18n("&Search for:"), page ) );
00401 hlay->addWidget( le, 1 );
00402 le->setFocus();
00403
00404 connect( clearButton, SIGNAL( clicked() ), le, SLOT( clear() ) );
00405 connect( le, SIGNAL(textChanged(const QString&)),
00406 this, SLOT(slotSearch(const QString&)) );
00407 connect( mStartSearchTimer, SIGNAL(timeout()), SLOT(slotFilter()) );
00408
00409 mKeyListView = new KeyListView( new ColumnStrategy( mKeyUsage ), 0, page, "mKeyListView" );
00410 mKeyListView->setResizeMode( QListView::LastColumn );
00411 mKeyListView->setRootIsDecorated( true );
00412 mKeyListView->setShowSortIndicator( true );
00413 mKeyListView->setSorting( 1, true );
00414 mKeyListView->setShowToolTips( true );
00415 if ( extendedSelection )
00416 mKeyListView->setSelectionMode( QListView::Extended );
00417 mTopLayout->addWidget( mKeyListView, 10 );
00418
00419 if ( rememberChoice ) {
00420 mRememberCB = new QCheckBox( i18n("&Remember choice"), page );
00421 mTopLayout->addWidget( mRememberCB );
00422 QWhatsThis::add( mRememberCB,
00423 i18n("<qt><p>If you check this box your choice will "
00424 "be stored and you will not be asked again."
00425 "</p></qt>") );
00426 }
00427
00428 connect( mCheckSelectionTimer, SIGNAL(timeout()),
00429 SLOT(slotCheckSelection()) );
00430 connectSignals();
00431
00432 connect( mKeyListView,
00433 SIGNAL(doubleClicked(Kleo::KeyListViewItem*,const QPoint&,int)),
00434 SLOT(slotTryOk()) );
00435 connect( mKeyListView,
00436 SIGNAL(contextMenu(Kleo::KeyListViewItem*,const QPoint&)),
00437 SLOT(slotRMB(Kleo::KeyListViewItem*,const QPoint&)) );
00438
00439 setButtonText( KDialogBase::Default, i18n("&Reread Keys") );
00440 setButtonGuiItem( KDialogBase::Help, i18n("&Start Certificate Manager") );
00441 connect( this, SIGNAL(defaultClicked()), this, SLOT(slotRereadKeys()) );
00442 connect( this, SIGNAL(helpClicked()), this, SLOT(slotStartCertificateManager()) );
00443
00444 slotRereadKeys();
00445 mTopLayout->activate();
00446
00447 if ( kapp ) {
00448 KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
00449 QSize dialogSize( 500, 400 );
00450
00451 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
00452 dialogSize = dialogConfig.readSizeEntry( "Dialog size", &dialogSize );
00453 resize( dialogSize );
00454 }
00455 }
00456
00457 Kleo::KeySelectionDialog::~KeySelectionDialog() {
00458 KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
00459 dialogConfig.writeEntry( "Dialog size", size() );
00460 dialogConfig.sync();
00461 }
00462
00463
00464 void Kleo::KeySelectionDialog::connectSignals() {
00465 if ( mKeyListView->isMultiSelection() )
00466 connect( mKeyListView, SIGNAL(selectionChanged()),
00467 SLOT(slotSelectionChanged()) );
00468 else
00469 connect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00470 SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00471 }
00472
00473 void Kleo::KeySelectionDialog::disconnectSignals() {
00474 if ( mKeyListView->isMultiSelection() )
00475 disconnect( mKeyListView, SIGNAL(selectionChanged()),
00476 this, SLOT(slotSelectionChanged()) );
00477 else
00478 disconnect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00479 this, SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00480 }
00481
00482 const GpgME::Key & Kleo::KeySelectionDialog::selectedKey() const {
00483 if ( mKeyListView->isMultiSelection() || !mKeyListView->selectedItem() )
00484 return GpgME::Key::null;
00485 return mKeyListView->selectedItem()->key();
00486 }
00487
00488 QString Kleo::KeySelectionDialog::fingerprint() const {
00489 return selectedKey().primaryFingerprint();
00490 }
00491
00492 QStringList Kleo::KeySelectionDialog::fingerprints() const {
00493 QStringList result;
00494 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00495 if ( const char * fpr = it->primaryFingerprint() )
00496 result.push_back( fpr );
00497 return result;
00498 }
00499
00500 QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const {
00501 QStringList result;
00502 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00503 if ( it->protocol() == GpgME::Context::OpenPGP )
00504 if ( const char * fpr = it->primaryFingerprint() )
00505 result.push_back( fpr );
00506 return result;
00507 }
00508
00509 QStringList Kleo::KeySelectionDialog::smimeFingerprints() const {
00510 QStringList result;
00511 for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
00512 if ( it->protocol() == GpgME::Context::CMS )
00513 if ( const char * fpr = it->primaryFingerprint() )
00514 result.push_back( fpr );
00515 return result;
00516 }
00517
00518 void Kleo::KeySelectionDialog::slotRereadKeys() {
00519 mKeyListView->clear();
00520 mListJobCount = 0;
00521 mTruncated = 0;
00522 mSavedOffsetY = mKeyListView->contentsY();
00523
00524 disconnectSignals();
00525 mKeyListView->setEnabled( false );
00526
00527
00528 if ( mOpenPGPBackend )
00529 startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false );
00530 if ( mSMIMEBackend )
00531 startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false );
00532
00533 if ( mListJobCount == 0 ) {
00534 mKeyListView->setEnabled( true );
00535 KMessageBox::information( this,
00536 i18n("No backends found for listing keys. "
00537 "Check your installation."),
00538 i18n("Key Listing Failed") );
00539 connectSignals();
00540 }
00541 }
00542
00543 void Kleo::KeySelectionDialog::slotHelp()
00544 {
00545 emit helpClicked();
00546 }
00547
00548 void Kleo::KeySelectionDialog::slotStartCertificateManager( const QString &query )
00549 {
00550 KProcess certManagerProc;
00551 certManagerProc << "kleopatra";
00552 if ( !query.isEmpty() )
00553 certManagerProc << "--external" << "--query" << KURL::decode_string( query );
00554
00555 if( !certManagerProc.start( KProcess::DontCare ) )
00556 KMessageBox::error( this, i18n( "Could not start certificate manager; "
00557 "please check your installation." ),
00558 i18n( "Certificate Manager Error" ) );
00559 else
00560 kdDebug(5006) << "\nslotStartCertManager(): certificate manager started.\n" << endl;
00561 }
00562
00563 #ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00564 #define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00565 static void showKeyListError( QWidget * parent, const GpgME::Error & err ) {
00566 assert( err );
00567 const QString msg = i18n( "<qt><p>An error occurred while fetching "
00568 "the keys from the backend:</p>"
00569 "<p><b>%1</b></p></qt>" )
00570 .arg( QString::fromLocal8Bit( err.asString() ) );
00571
00572 KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) );
00573 }
00574 #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
00575
00576 namespace {
00577 struct ExtractFingerprint {
00578 QString operator()( const GpgME::Key & key ) {
00579 return key.primaryFingerprint();
00580 }
00581 };
00582 }
00583
00584 void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) {
00585 assert( backend );
00586 KeyListJob * job = backend->keyListJob( false, false, validate );
00587 if ( !job )
00588 return;
00589
00590 connect( job, SIGNAL(result(const GpgME::KeyListResult&)),
00591 SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
00592 connect( job, SIGNAL(nextKey(const GpgME::Key&)),
00593 mKeyListView, validate ?
00594 SLOT(slotRefreshKey(const GpgME::Key&)) :
00595 SLOT(slotAddKey(const GpgME::Key&)) );
00596
00597 QStringList fprs;
00598 std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() );
00599 const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) );
00600
00601 if ( err )
00602 return showKeyListError( this, err );
00603
00604
00605 (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this );
00606 ++mListJobCount;
00607 }
00608
00609 static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) {
00610 klv->clearSelection();
00611 if ( selectedKeys.empty() )
00612 return;
00613 for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it )
00614 if ( Kleo::KeyListViewItem * item = klv->itemByFingerprint( it->primaryFingerprint() ) )
00615 item->setSelected( true );
00616 }
00617
00618 void Kleo::KeySelectionDialog::slotKeyListResult( const GpgME::KeyListResult & res ) {
00619 if ( res.error() )
00620 showKeyListError( this, res.error() );
00621 else if ( res.isTruncated() )
00622 ++mTruncated;
00623
00624 if ( --mListJobCount > 0 )
00625 return;
00626
00627 if ( mTruncated > 0 )
00628 KMessageBox::information( this,
00629 i18n("<qt>One backend returned truncated output.<br>"
00630 "Not all available keys are shown</qt>",
00631 "<qt>%n backends returned truncated output.<br>"
00632 "Not all available keys are shown</qt>",
00633 mTruncated),
00634 i18n("Key List Result") );
00635
00636 mKeyListView->flushKeys();
00637
00638 mKeyListView->setEnabled( true );
00639 mListJobCount = mTruncated = 0;
00640 mKeysToCheck.clear();
00641
00642 selectKeys( mKeyListView, mSelectedKeys );
00643
00644 slotFilter();
00645
00646 connectSignals();
00647
00648 slotSelectionChanged();
00649
00650
00651 mKeyListView->setContentsPos( 0, mSavedOffsetY ); mSavedOffsetY = 0;
00652 }
00653
00654 void Kleo::KeySelectionDialog::slotSelectionChanged() {
00655 kdDebug(5150) << "KeySelectionDialog::slotSelectionChanged()" << endl;
00656
00657
00658
00659
00660 mCheckSelectionTimer->start( sCheckSelectionDelay );
00661 }
00662
00663 namespace {
00664 struct AlreadyChecked {
00665 bool operator()( const GpgME::Key & key ) const {
00666 return key.keyListMode() & GpgME::Context::Validate ;
00667 }
00668 };
00669 }
00670
00671 void Kleo::KeySelectionDialog::slotCheckSelection( KeyListViewItem * item ) {
00672 kdDebug(5150) << "KeySelectionDialog::slotCheckSelection()\n";
00673
00674 mCheckSelectionTimer->stop();
00675
00676 mSelectedKeys.clear();
00677
00678 if ( !mKeyListView->isMultiSelection() ) {
00679 if ( item )
00680 mSelectedKeys.push_back( item->key() );
00681 }
00682
00683 for ( KeyListViewItem * it = mKeyListView->firstChild() ; it ; it = it->nextSibling() )
00684 if ( it->isSelected() )
00685 mSelectedKeys.push_back( it->key() );
00686
00687 mKeysToCheck.clear();
00688 std::remove_copy_if( mSelectedKeys.begin(), mSelectedKeys.end(),
00689 std::back_inserter( mKeysToCheck ),
00690 AlreadyChecked() );
00691 if ( mKeysToCheck.empty() ) {
00692 enableButtonOK( !mSelectedKeys.empty() &&
00693 checkKeyUsage( mSelectedKeys, mKeyUsage ) );
00694 return;
00695 }
00696
00697
00698 startValidatingKeyListing();
00699 }
00700
00701 void Kleo::KeySelectionDialog::startValidatingKeyListing() {
00702 if ( mKeysToCheck.empty() )
00703 return;
00704
00705 mListJobCount = 0;
00706 mTruncated = 0;
00707 mSavedOffsetY = mKeyListView->contentsY();
00708
00709 disconnectSignals();
00710 mKeyListView->setEnabled( false );
00711
00712 std::vector<GpgME::Key> smime, openpgp;
00713 for ( std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin() ; it != mKeysToCheck.end() ; ++it )
00714 if ( it->protocol() == GpgME::Context::OpenPGP )
00715 openpgp.push_back( *it );
00716 else
00717 smime.push_back( *it );
00718
00719 if ( !openpgp.empty() ) {
00720 assert( mOpenPGPBackend );
00721 startKeyListJobForBackend( mOpenPGPBackend, openpgp, true );
00722 }
00723 if ( !smime.empty() ) {
00724 assert( mSMIMEBackend );
00725 startKeyListJobForBackend( mSMIMEBackend, smime, true );
00726 }
00727
00728 assert( mListJobCount > 0 );
00729 }
00730
00731 bool Kleo::KeySelectionDialog::rememberSelection() const {
00732 return mRememberCB && mRememberCB->isChecked() ;
00733 }
00734
00735 void Kleo::KeySelectionDialog::slotRMB( Kleo::KeyListViewItem * item, const QPoint & p ) {
00736 if ( !item ) return;
00737
00738 mCurrentContextMenuItem = item;
00739
00740 QPopupMenu menu;
00741 menu.insertItem( i18n( "Recheck Key" ), this, SLOT(slotRecheckKey()) );
00742 menu.exec( p );
00743 }
00744
00745 void Kleo::KeySelectionDialog::slotRecheckKey() {
00746 if ( !mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull() )
00747 return;
00748
00749 mKeysToCheck.clear();
00750 mKeysToCheck.push_back( mCurrentContextMenuItem->key() );
00751 }
00752
00753 void Kleo::KeySelectionDialog::slotTryOk() {
00754 if ( actionButton( Ok )->isEnabled() )
00755 slotOk();
00756 }
00757
00758 void Kleo::KeySelectionDialog::slotOk() {
00759 if ( mCheckSelectionTimer->isActive() )
00760 slotCheckSelection();
00761
00762 if ( !actionButton( Ok )->isEnabled() )
00763 return;
00764 mStartSearchTimer->stop();
00765 accept();
00766 }
00767
00768
00769 void Kleo::KeySelectionDialog::slotCancel() {
00770 mCheckSelectionTimer->stop();
00771 mStartSearchTimer->stop();
00772 reject();
00773 }
00774
00775 void Kleo::KeySelectionDialog::slotSearch( const QString & text ) {
00776 mSearchText = text.stripWhiteSpace().upper();
00777 slotSearch();
00778 }
00779
00780 void Kleo::KeySelectionDialog::slotSearch() {
00781 mStartSearchTimer->start( sCheckSelectionDelay, true );
00782 }
00783
00784 void Kleo::KeySelectionDialog::slotFilter() {
00785 if ( mSearchText.isEmpty() ) {
00786 showAllItems();
00787 return;
00788 }
00789
00790
00791 QRegExp keyIdRegExp( "(?:0x)?[A-F0-9]{1,8}", false );
00792 if ( keyIdRegExp.exactMatch( mSearchText ) ) {
00793 if ( mSearchText.startsWith( "0X" ) )
00794
00795 filterByKeyID( mSearchText.mid( 2 ) );
00796 else
00797
00798 filterByKeyIDOrUID( mSearchText );
00799 } else {
00800
00801 filterByUID( mSearchText );
00802 }
00803 }
00804
00805 void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) {
00806 assert( keyID.length() <= 8 );
00807 assert( !keyID.isEmpty() );
00808 if ( keyID.isEmpty() )
00809 showAllItems();
00810 else
00811 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00812 item->setVisible( item->text( 0 ).upper().startsWith( keyID ) );
00813 }
00814
00815 static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) {
00816 if ( !item )
00817 return false;
00818
00819 const std::vector<GpgME::UserID> uids = item->key().userIDs();
00820 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
00821 if ( it->id() && rx.search( QString::fromUtf8( it->id() ) ) >= 0 )
00822 return true;
00823 return false;
00824 }
00825
00826 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const QString & str ) {
00827 assert( !str.isEmpty() );
00828
00829
00830 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00831
00832 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00833 item->setVisible( item->text( 0 ).upper().startsWith( str ) || anyUIDMatches( item, rx ) );
00834
00835 }
00836
00837 void Kleo::KeySelectionDialog::filterByUID( const QString & str ) {
00838 assert( !str.isEmpty() );
00839
00840
00841 QRegExp rx( "\\b" + QRegExp::escape( str ), false );
00842
00843 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00844 item->setVisible( anyUIDMatches( item, rx ) );
00845 }
00846
00847
00848 void Kleo::KeySelectionDialog::showAllItems() {
00849 for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
00850 item->setVisible( true );
00851 }
00852
00853 #include "keyselectiondialog.moc"