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