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 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 TQString time_t2string( time_t t ) {
00162 TQDateTime 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 TQString title( int col ) const;
00174 int width( int col, const TQFontMetrics & fm ) const;
00175
00176 TQString text( const GpgME::Key & key, int col ) const;
00177 TQString toolTip( const GpgME::Key & key, int col ) const;
00178 const TQPixmap * pixmap( const GpgME::Key & key, int col ) const;
00179
00180 private:
00181 const TQPixmap 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 TQString 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 TQString::null;
00202 }
00203 }
00204
00205 int ColumnStrategy::width( int col, const TQFontMetrics & 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( TQChar( hexchars[i] ) ), maxWidth );
00211 return 8 * maxWidth + 2 * mKeyGoodPix.width();
00212 }
00213 return Kleo::KeyListView::ColumnStrategy::width( col, fm );
00214 }
00215
00216 TQString ColumnStrategy::text( const GpgME::Key & key, int col ) const {
00217 switch ( col ) {
00218 case 0:
00219 {
00220 if ( key.shortKeyID() )
00221 return TQString::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 ? TQString::fromUtf8( uid ) : TQString::null ;
00231 else
00232 return Kleo::DN( uid ).prettyDN();
00233 }
00234 break;
00235 default: return TQString::null;
00236 }
00237 }
00238
00239 TQString 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 TQString expiry = subkey.neverExpires() ? i18n("never") : time_t2string( subkey.expirationTime() ) ;
00245 const TQString 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 ? TQString::fromUtf8( uid ) : i18n("unknown"),
00252 creation, expiry,
00253 fpr ? TQString::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 ? TQString::fromLatin1( fpr ) : i18n("unknown") )
00263 .arg( issuer ? Kleo::DN( issuer ).prettyDN() : i18n("unknown") );
00264 }
00265
00266 const TQPixmap * 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 TQString & title,
00299 const TQString & text,
00300 const std::vector<GpgME::Key> & selectedKeys,
00301 unsigned int keyUsage,
00302 bool extendedSelection,
00303 bool rememberChoice,
00304 TQWidget * 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, TQString::null );
00315 }
00316
00317 Kleo::KeySelectionDialog::KeySelectionDialog( const TQString & title,
00318 const TQString & text,
00319 const TQString & initialQuery,
00320 const std::vector<GpgME::Key> & selectedKeys,
00321 unsigned int keyUsage,
00322 bool extendedSelection,
00323 bool rememberChoice,
00324 TQWidget * 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 TQString & title,
00340 const TQString & text,
00341 const TQString & initialQuery,
00342 unsigned int keyUsage,
00343 bool extendedSelection,
00344 bool rememberChoice,
00345 TQWidget * 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 TQString & text, const TQString & 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 TQTimer( this );
00367 mStartSearchTimer = new TQTimer( this );
00368
00369 TQFrame *page = makeMainWidget();
00370 mTopLayout = new TQVBoxLayout( page, 0, spacingHint() );
00371
00372 if ( !text.isEmpty() ) {
00373 if ( text.startsWith( "<qt>" ) ) {
00374 KActiveLabel *textLabel = new KActiveLabel( text, page );
00375 disconnect( textLabel, TQT_SIGNAL(linkClicked(const TQString&)), textLabel, TQT_SLOT(openLink(const TQString&)) );
00376 connect( textLabel, TQT_SIGNAL(linkClicked(const TQString&)), TQT_SLOT(slotStartCertificateManager(const TQString&)) );
00377 textLabel->setAlignment( textLabel->alignment() | TQt::WordBreak );
00378 mTopLayout->addWidget( textLabel );
00379 } else {
00380 KActiveLabel *textLabel = new KActiveLabel( text, page );
00381 textLabel->setAlignment( textLabel->alignment() | TQt::WordBreak );
00382 mTopLayout->addWidget( textLabel );
00383 }
00384 }
00385
00386 TQPushButton * const searchExternalPB
00387 = new TQPushButton( i18n("Search for &External Certificates"), page );
00388 mTopLayout->addWidget( searchExternalPB, 0, TQt::AlignLeft );
00389 connect( searchExternalPB, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotStartSearchForExternalCertificates()) );
00390 if ( initialQuery.isEmpty() )
00391 searchExternalPB->hide();
00392
00393 TQHBoxLayout * hlay = new TQHBoxLayout( mTopLayout );
00394 TQLineEdit * le = new TQLineEdit( page );
00395 le->setText( initialQuery );
00396 TQToolButton *clearButton = new TQToolButton( 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 TQLabel( le, i18n("&Search for:"), page ) );
00401 hlay->addWidget( le, 1 );
00402 le->setFocus();
00403
00404 connect( clearButton, TQT_SIGNAL( clicked() ), le, TQT_SLOT( clear() ) );
00405 connect( le, TQT_SIGNAL(textChanged(const TQString&)),
00406 this, TQT_SLOT(slotSearch(const TQString&)) );
00407 connect( mStartSearchTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotFilter()) );
00408
00409 mKeyListView = new KeyListView( new ColumnStrategy( mKeyUsage ), 0, page, "mKeyListView" );
00410 mKeyListView->setResizeMode( TQListView::LastColumn );
00411 mKeyListView->setRootIsDecorated( true );
00412 mKeyListView->setShowSortIndicator( true );
00413 mKeyListView->setSorting( 1, true );
00414 mKeyListView->setShowToolTips( true );
00415 if ( extendedSelection )
00416 mKeyListView->setSelectionMode( TQListView::Extended );
00417 mTopLayout->addWidget( mKeyListView, 10 );
00418
00419 if ( rememberChoice ) {
00420 mRememberCB = new TQCheckBox( i18n("&Remember choice"), page );
00421 mTopLayout->addWidget( mRememberCB );
00422 TQWhatsThis::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, TQT_SIGNAL(timeout()),
00429 TQT_SLOT(slotCheckSelection()) );
00430 connectSignals();
00431
00432 connect( mKeyListView,
00433 TQT_SIGNAL(doubleClicked(Kleo::KeyListViewItem*,const TQPoint&,int)),
00434 TQT_SLOT(slotTryOk()) );
00435 connect( mKeyListView,
00436 TQT_SIGNAL(contextMenu(Kleo::KeyListViewItem*,const TQPoint&)),
00437 TQT_SLOT(slotRMB(Kleo::KeyListViewItem*,const TQPoint&)) );
00438
00439 setButtonText( KDialogBase::Default, i18n("&Reread Keys") );
00440 setButtonGuiItem( KDialogBase::Help, i18n("&Start Certificate Manager") );
00441 connect( this, TQT_SIGNAL(defaultClicked()), this, TQT_SLOT(slotRereadKeys()) );
00442 connect( this, TQT_SIGNAL(helpClicked()), this, TQT_SLOT(slotStartCertificateManager()) );
00443
00444 slotRereadKeys();
00445 mTopLayout->activate();
00446
00447 if ( kapp ) {
00448 KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
00449 TQSize 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, TQT_SIGNAL(selectionChanged()),
00467 TQT_SLOT(slotSelectionChanged()) );
00468 else
00469 connect( mKeyListView, TQT_SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00470 TQT_SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
00471 }
00472
00473 void Kleo::KeySelectionDialog::disconnectSignals() {
00474 if ( mKeyListView->isMultiSelection() )
00475 disconnect( mKeyListView, TQT_SIGNAL(selectionChanged()),
00476 this, TQT_SLOT(slotSelectionChanged()) );
00477 else
00478 disconnect( mKeyListView, TQT_SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
00479 this, TQT_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 TQString Kleo::KeySelectionDialog::fingerprint() const {
00489 return selectedKey().primaryFingerprint();
00490 }
00491
00492 TQStringList Kleo::KeySelectionDialog::fingerprints() const {
00493 TQStringList 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 TQStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const {
00501 TQStringList 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 TQStringList Kleo::KeySelectionDialog::smimeFingerprints() const {
00510 TQStringList 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 TQString &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( TQWidget * parent, const GpgME::Error & err ) {
00566 assert( err );
00567 const TQString 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( TQString::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 TQString 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, TQT_SIGNAL(result(const GpgME::KeyListResult&)),
00591 TQT_SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
00592 connect( job, TQT_SIGNAL(nextKey(const GpgME::Key&)),
00593 mKeyListView, validate ?
00594 TQT_SLOT(slotRefreshKey(const GpgME::Key&)) :
00595 TQT_SLOT(slotAddKey(const GpgME::Key&)) );
00596
00597 TQStringList 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 TQPoint & p ) {
00736 if ( !item ) return;
00737
00738 mCurrentContextMenuItem = item;
00739
00740 TQPopupMenu menu;
00741 menu.insertItem( i18n( "Recheck Key" ), this, TQT_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 TQString & 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 TQRegExp 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 TQString & 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, TQRegExp & 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( TQString::fromUtf8( it->id() ) ) >= 0 )
00822 return true;
00823 return false;
00824 }
00825
00826 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const TQString & str ) {
00827 assert( !str.isEmpty() );
00828
00829
00830 TQRegExp rx( "\\b" + TQRegExp::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 TQString & str ) {
00838 assert( !str.isEmpty() );
00839
00840
00841 TQRegExp rx( "\\b" + TQRegExp::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"