• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

libkleo

  • sources
  • kde-4.12
  • kdepim
  • libkleo
  • ui
keyselectiondialog.cpp
Go to the documentation of this file.
1 /* -*- c++ -*-
2  keyselectiondialog.cpp
3 
4  This file is part of libkleopatra, the KDE keymanagement library
5  Copyright (c) 2004 Klar�vdalens Datakonsult AB
6 
7  Based on kpgpui.cpp
8  Copyright (C) 2001,2002 the KPGP authors
9  See file libkdenetwork/AUTHORS.kpgp for details
10 
11  Libkleopatra is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 2 of the
14  License, or (at your option) any later version.
15 
16  Libkleopatra is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 
25  In addition, as a special exception, the copyright holders give
26  permission to link the code of this program with any edition of
27  the Qt library by Trolltech AS, Norway (or with modified versions
28  of Qt that use the same license as Qt), and distribute linked
29  combinations including the two. You must obey the GNU General
30  Public License in all respects for all of the code used other than
31  Qt. If you modify this file, you may extend this exception to
32  your version of the file, but you are not obligated to do so. If
33  you do not wish to do so, delete this exception statement from
34  your version.
35 */
36 
37 
38 #include "keyselectiondialog.h"
39 
40 #include "keylistview.h"
41 #include "progressdialog.h"
42 
43 #include "kleo/dn.h"
44 #include "kleo/keylistjob.h"
45 #include "kleo/cryptobackendfactory.h"
46 
47 // gpgme++
48 #include <gpgme++/key.h>
49 #include <gpgme++/keylistresult.h>
50 
51 // KDE
52 #include <klocale.h>
53 #include <kglobal.h>
54 #include <kiconloader.h>
55 #include <kdebug.h>
56 #include <kwindowsystem.h>
57 #include <kconfig.h>
58 #include <kmessagebox.h>
59 #include <kpushbutton.h>
60 #include <kconfiggroup.h>
61 #include <kmenu.h>
62 #include <klineedit.h>
63 #include <kurl.h>
64 
65 // Qt
66 #include <QCheckBox>
67 #include <QToolButton>
68 #include <QLabel>
69 #include <QPixmap>
70 #include <QTimer>
71 #include <QLayout>
72 #include <QLineEdit>
73 #include <QDateTime>
74 #include <QProcess>
75 
76 #include <QRegExp>
77 #include <QPushButton>
78 #include <QFrame>
79 #include <QApplication>
80 #include <QHBoxLayout>
81 #include <QVBoxLayout>
82 
83 #include <algorithm>
84 #include <iterator>
85 
86 #include <string.h>
87 #include <assert.h>
88 #include <qscrollbar.h>
89 
90 static bool checkKeyUsage( const GpgME::Key & key, unsigned int keyUsage ) {
91 
92  if ( keyUsage & Kleo::KeySelectionDialog::ValidKeys ) {
93  if ( key.isInvalid() ) {
94  if ( key.keyListMode() & GpgME::Validate ) {
95  kDebug(5150) << "key is invalid";
96  return false;
97  } else {
98  kDebug(5150) << "key is invalid - ignoring";
99  }
100  }
101  if ( key.isExpired() ) {
102  kDebug(5150) <<"key is expired";
103  return false;
104  } else if ( key.isRevoked() ) {
105  kDebug(5150) <<"key is revoked";
106  return false;
107  } else if ( key.isDisabled() ) {
108  kDebug(5150) <<"key is disabled";
109  return false;
110  }
111  }
112 
113  if ( keyUsage & Kleo::KeySelectionDialog::EncryptionKeys &&
114  !key.canEncrypt() ) {
115  kDebug(5150) <<"key can't encrypt";
116  return false;
117  }
118  if ( keyUsage & Kleo::KeySelectionDialog::SigningKeys &&
119  !key.canSign() ) {
120  kDebug(5150) <<"key can't sign";
121  return false;
122  }
123  if ( keyUsage & Kleo::KeySelectionDialog::CertificationKeys &&
124  !key.canCertify() ) {
125  kDebug(5150) <<"key can't certify";
126  return false;
127  }
128  if ( keyUsage & Kleo::KeySelectionDialog::AuthenticationKeys &&
129  !key.canAuthenticate() ) {
130  kDebug(5150) <<"key can't authenticate";
131  return false;
132  }
133 
134  if ( keyUsage & Kleo::KeySelectionDialog::SecretKeys &&
135  !( keyUsage & Kleo::KeySelectionDialog::PublicKeys ) &&
136  !key.hasSecret() ) {
137  kDebug(5150) <<"key isn't secret";
138  return false;
139  }
140 
141  if ( keyUsage & Kleo::KeySelectionDialog::TrustedKeys &&
142  key.protocol() == GpgME::OpenPGP &&
143  // only check this for secret keys for now.
144  // Seems validity isn't checked for secret keylistings...
145  !key.hasSecret() ) {
146  std::vector<GpgME::UserID> uids = key.userIDs();
147  for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
148  if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal )
149  return true;
150  kDebug(5150) <<"key has no UIDs with validity >= Marginal";
151  return false;
152  }
153  // X.509 keys are always trusted, else they won't be the keybox.
154  // PENDING(marc) check that this ^ is correct
155 
156  return true;
157 }
158 
159 static bool checkKeyUsage( const std::vector<GpgME::Key> & keys, unsigned int keyUsage ) {
160  for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it )
161  if ( !checkKeyUsage( *it, keyUsage ) )
162  return false;
163  return true;
164 }
165 
166 static inline QString time_t2string( time_t t ) {
167  QDateTime dt;
168  dt.setTime_t( t );
169  return dt.toString();
170 }
171 
172 namespace {
173 
174  class ColumnStrategy : public Kleo::KeyListView::ColumnStrategy {
175  public:
176  ColumnStrategy( unsigned int keyUsage );
177 
178  QString title( int col ) const;
179  int width( int col, const QFontMetrics & fm ) const;
180 
181  QString text( const GpgME::Key & key, int col ) const;
182  QString toolTip( const GpgME::Key & key, int col ) const;
183  KIcon icon( const GpgME::Key & key, int col ) const;
184 
185  private:
186  const KIcon mKeyGoodPix, mKeyBadPix, mKeyUnknownPix, mKeyValidPix;
187  const unsigned int mKeyUsage;
188  };
189 
190  ColumnStrategy::ColumnStrategy( unsigned int keyUsage )
191  : Kleo::KeyListView::ColumnStrategy(),
192  mKeyGoodPix( QLatin1String("key_ok") ),
193  mKeyBadPix( QLatin1String("key_bad") ),
194  mKeyUnknownPix( QLatin1String("key_unknown") ),
195  mKeyValidPix( QLatin1String("key") ),
196  mKeyUsage( keyUsage )
197  {
198  kWarning( keyUsage == 0, 5150 )
199  << "KeySelectionDialog: keyUsage == 0. You want to use AllKeys instead.";
200  }
201 
202  QString ColumnStrategy::title( int col ) const {
203  switch ( col ) {
204  case 0: return i18n("Key ID");
205  case 1: return i18n("User ID");
206  default: return QString();
207  }
208  }
209 
210  int ColumnStrategy::width( int col, const QFontMetrics & fm ) const {
211  if ( col == 0 ) {
212  static const char hexchars[] = "0123456789ABCDEF";
213  int maxWidth = 0;
214  for ( unsigned int i = 0 ; i < 16 ; ++i )
215  maxWidth = qMax( fm.width( QLatin1Char( hexchars[i] ) ), maxWidth );
216  return 8 * maxWidth + 2 * KIconLoader::SizeSmall;
217  }
218  return Kleo::KeyListView::ColumnStrategy::width( col, fm );
219  }
220 
221  QString ColumnStrategy::text( const GpgME::Key & key, int col ) const {
222  switch ( col ) {
223  case 0:
224  {
225  if ( key.shortKeyID() )
226  return QString::fromUtf8( key.shortKeyID() );
227  else
228  return i18n("<placeholder>unknown</placeholder>");
229  }
230  break;
231  case 1:
232  {
233  const char * uid = key.userID(0).id();
234  if ( key.protocol() == GpgME::OpenPGP )
235  return uid && *uid ? QString::fromUtf8( uid ) : QString() ;
236  else // CMS
237  return Kleo::DN( uid ).prettyDN();
238  }
239  break;
240  default: return QString();
241  }
242  }
243 
244  QString ColumnStrategy::toolTip( const GpgME::Key & key, int ) const {
245  const char * uid = key.userID(0).id();
246  const char * fpr = key.primaryFingerprint();
247  const char * issuer = key.issuerName();
248  const GpgME::Subkey subkey = key.subkey(0);
249  const QString expiry = subkey.neverExpires() ? i18n("never") : time_t2string( subkey.expirationTime() ) ;
250  const QString creation = time_t2string( subkey.creationTime() );
251  if ( key.protocol() == GpgME::OpenPGP )
252  return i18n( "OpenPGP key for %1\n"
253  "Created: %2\n"
254  "Expiry: %3\n"
255  "Fingerprint: %4",
256  uid ? QString::fromUtf8( uid ) : i18n("unknown"),
257  creation, expiry,
258  fpr ? QString::fromLatin1( fpr ) : i18n("unknown") );
259  else
260  return i18n( "S/MIME key for %1\n"
261  "Created: %2\n"
262  "Expiry: %3\n"
263  "Fingerprint: %4\n"
264  "Issuer: %5",
265  uid ? Kleo::DN( uid ).prettyDN() : i18n("unknown"),
266  creation, expiry,
267  fpr ? QString::fromLatin1( fpr ) : i18n("unknown"),
268  issuer ? Kleo::DN( issuer ).prettyDN() : i18n("unknown") );
269  }
270 
271  KIcon ColumnStrategy::icon( const GpgME::Key & key, int col ) const {
272  if ( col != 0 )
273  return KIcon();
274  // this key did not undergo a validating keylisting yet:
275  if ( !( key.keyListMode() & GpgME::Validate ) )
276  return mKeyUnknownPix;
277 
278  if ( !checkKeyUsage( key, mKeyUsage ) )
279  return mKeyBadPix;
280 
281  if ( key.protocol() == GpgME::CMS )
282  return mKeyGoodPix;
283 
284  switch ( key.userID(0).validity() ) {
285  default:
286  case GpgME::UserID::Unknown:
287  case GpgME::UserID::Undefined:
288  return mKeyUnknownPix;
289  case GpgME::UserID::Never:
290  return mKeyValidPix;
291  case GpgME::UserID::Marginal:
292  case GpgME::UserID::Full:
293  case GpgME::UserID::Ultimate:
294  return mKeyGoodPix;
295  }
296  }
297 
298 }
299 
300 
301 static const int sCheckSelectionDelay = 250;
302 
303 Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title,
304  const QString & text,
305  const std::vector<GpgME::Key> & selectedKeys,
306  unsigned int keyUsage,
307  bool extendedSelection,
308  bool rememberChoice,
309  QWidget * parent,
310  bool modal )
311  : KDialog( parent ),
312  mOpenPGPBackend( 0 ),
313  mSMIMEBackend( 0 ),
314  mRememberCB( 0 ),
315  mSelectedKeys( selectedKeys ),
316  mKeyUsage( keyUsage ),
317  mCurrentContextMenuItem( 0 )
318 {
319  setCaption( title );
320  setButtons( User1|User2|Ok|Cancel );
321  setDefaultButton( Ok );
322  setModal( modal );
323  init( rememberChoice, extendedSelection, text, QString() );
324 }
325 
326 Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title,
327  const QString & text,
328  const QString & initialQuery,
329  const std::vector<GpgME::Key> & selectedKeys,
330  unsigned int keyUsage,
331  bool extendedSelection,
332  bool rememberChoice,
333  QWidget * parent,
334  bool modal )
335  : KDialog( parent ),
336  mOpenPGPBackend( 0 ),
337  mSMIMEBackend( 0 ),
338  mRememberCB( 0 ),
339  mSelectedKeys( selectedKeys ),
340  mKeyUsage( keyUsage ),
341  mSearchText( initialQuery ),
342  mInitialQuery( initialQuery ),
343  mCurrentContextMenuItem( 0 )
344 {
345  setCaption( title );
346  setButtons( User1|User2|Ok|Cancel );
347  setDefaultButton( Ok );
348  setModal( modal );
349  init( rememberChoice, extendedSelection, text, initialQuery );
350 }
351 
352 Kleo::KeySelectionDialog::KeySelectionDialog( const QString & title,
353  const QString & text,
354  const QString & initialQuery,
355  unsigned int keyUsage,
356  bool extendedSelection,
357  bool rememberChoice,
358  QWidget * parent,
359  bool modal )
360  : KDialog( parent ),
361  mOpenPGPBackend( 0 ),
362  mSMIMEBackend( 0 ),
363  mRememberCB( 0 ),
364  mKeyUsage( keyUsage ),
365  mSearchText( initialQuery ),
366  mInitialQuery( initialQuery ),
367  mCurrentContextMenuItem( 0 )
368 {
369  setCaption( title );
370  setButtons( User1|User2|Ok|Cancel );
371  setDefaultButton( Ok );
372  setModal( modal );
373  init( rememberChoice, extendedSelection, text, initialQuery );
374 }
375 
376 void Kleo::KeySelectionDialog::init( bool rememberChoice, bool extendedSelection,
377  const QString & text, const QString & initialQuery ) {
378  if ( mKeyUsage & OpenPGPKeys )
379  mOpenPGPBackend = Kleo::CryptoBackendFactory::instance()->openpgp();
380  if ( mKeyUsage & SMIMEKeys )
381  mSMIMEBackend = Kleo::CryptoBackendFactory::instance()->smime();
382 
383  mCheckSelectionTimer = new QTimer( this );
384  mStartSearchTimer = new QTimer( this );
385 
386  QFrame *page = new QFrame( this );
387  setMainWidget( page );
388  mTopLayout = new QVBoxLayout( page );
389  mTopLayout->setMargin( 0 );
390  mTopLayout->setSpacing( spacingHint() );
391 
392  if ( !text.isEmpty() ) {
393 #ifndef KDEPIM_MOBILE_UI
394  QLabel* textLabel = new QLabel( text, page );
395  textLabel->setWordWrap( true );
396 
397  // Setting the size policy is necessary as a workaround for https://issues.kolab.org/issue4429
398  // and http://bugreports.qt.nokia.com/browse/QTBUG-8740
399  textLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
400  connect( textLabel, SIGNAL(linkActivated(QString)), SLOT(slotStartCertificateManager(QString)) );
401  mTopLayout->addWidget( textLabel );
402 #endif
403  }
404 
405 #ifndef KDEPIM_MOBILE_UI
406  QPushButton * const searchExternalPB =
407  new QPushButton( i18n( "Search for &External Certificates" ), page );
408  mTopLayout->addWidget( searchExternalPB, 0, Qt::AlignLeft );
409  connect( searchExternalPB, SIGNAL(clicked()),
410  this, SLOT(slotStartSearchForExternalCertificates()) );
411  if ( initialQuery.isEmpty() ) {
412  searchExternalPB->hide();
413  }
414 #endif
415 
416  QHBoxLayout * hlay = new QHBoxLayout();
417  mTopLayout->addLayout( hlay );
418 
419  KLineEdit * le = new KLineEdit( page );
420  le->setClearButtonShown(true);
421  le->setText( initialQuery );
422 
423  QLabel* lbSearchFor = new QLabel( i18n("&Search for:"), page ) ;
424  lbSearchFor->setBuddy(le);
425 
426  hlay->addWidget(lbSearchFor);
427  hlay->addWidget( le, 1 );
428  le->setFocus();
429 
430  connect( le, SIGNAL(textChanged(QString)),
431  this, SLOT(slotSearch(QString)) );
432  connect( mStartSearchTimer, SIGNAL(timeout()), SLOT(slotFilter()) );
433 
434  mKeyListView = new KeyListView( new ColumnStrategy( mKeyUsage ), 0, page );
435  mKeyListView->setObjectName( QLatin1String("mKeyListView") );
436  mKeyListView->header()->stretchLastSection();
437  mKeyListView->setRootIsDecorated( true );
438  mKeyListView->setSortingEnabled( true );
439  mKeyListView->header()->setSortIndicatorShown( true );
440  mKeyListView->header()->setSortIndicator( 1, Qt::AscendingOrder ); // sort by User ID
441  if ( extendedSelection )
442  mKeyListView->setSelectionMode( QAbstractItemView::ExtendedSelection );
443  mTopLayout->addWidget( mKeyListView, 10 );
444 
445  if ( rememberChoice ) {
446 #ifndef KDEPIM_MOBILE_UI
447  mRememberCB = new QCheckBox( i18n("&Remember choice"), page );
448  mTopLayout->addWidget( mRememberCB );
449  mRememberCB->setWhatsThis(
450  i18n("<qt><p>If you check this box your choice will "
451  "be stored and you will not be asked again."
452  "</p></qt>") );
453 #endif
454  }
455 
456  connect( mCheckSelectionTimer, SIGNAL(timeout()),
457  SLOT(slotCheckSelection()) );
458  connectSignals();
459 
460  connect( mKeyListView,
461  SIGNAL(doubleClicked(Kleo::KeyListViewItem*,int)),
462  SLOT(slotTryOk()) );
463  connect( mKeyListView,
464  SIGNAL(contextMenu(Kleo::KeyListViewItem*,QPoint)),
465  SLOT(slotRMB(Kleo::KeyListViewItem*,QPoint)) );
466 
467  setButtonText( KDialog::User1, i18n("&Reread Keys") );
468  setButtonText( KDialog::User2, i18n("&Start Certificate Manager") );
469  connect( this, SIGNAL(user1Clicked()), this, SLOT(slotRereadKeys()) );
470  connect( this, SIGNAL(user2Clicked()), this, SLOT(slotStartCertificateManager()) );
471  connect( this, SIGNAL(okClicked()), this, SLOT(slotOk()));
472  connect( this, SIGNAL(cancelClicked()),this,SLOT(slotCancel()));
473  slotRereadKeys();
474  mTopLayout->activate();
475 
476  if ( qApp ) {
477  QSize dialogSize( sizeHint() );
478  int iconSize = IconSize(KIconLoader::Desktop);
479  int miniSize = IconSize(KIconLoader::Small);
480  KWindowSystem::setIcons( winId(), qApp->windowIcon().pixmap(iconSize, iconSize),
481  qApp->windowIcon().pixmap(miniSize, miniSize) );
482 
483  KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
484  dialogSize = dialogConfig.readEntry( "Dialog size", dialogSize );
485  resize( dialogSize );
486  }
487 }
488 
489 Kleo::KeySelectionDialog::~KeySelectionDialog() {
490  KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
491  dialogConfig.writeEntry( "Dialog size", size() );
492  dialogConfig.sync();
493 }
494 
495 
496 void Kleo::KeySelectionDialog::connectSignals() {
497  if ( mKeyListView->isMultiSelection() )
498  connect( mKeyListView, SIGNAL(itemSelectionChanged()),
499  SLOT(slotSelectionChanged()) );
500  else
501  connect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
502  SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
503 }
504 
505 void Kleo::KeySelectionDialog::disconnectSignals() {
506  if ( mKeyListView->isMultiSelection() )
507  disconnect( mKeyListView, SIGNAL(itemSelectionChanged()),
508  this, SLOT(slotSelectionChanged()) );
509  else
510  disconnect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
511  this, SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
512 }
513 
514 const GpgME::Key & Kleo::KeySelectionDialog::selectedKey() const {
515  static const GpgME::Key null = GpgME::Key::null;
516  if ( mKeyListView->isMultiSelection() || !mKeyListView->selectedItem() )
517  return null;
518  return mKeyListView->selectedItem()->key();
519 }
520 
521 QString Kleo::KeySelectionDialog::fingerprint() const {
522  return QLatin1String(selectedKey().primaryFingerprint());
523 }
524 
525 QStringList Kleo::KeySelectionDialog::fingerprints() const {
526  QStringList result;
527  for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
528  if ( const char * fpr = it->primaryFingerprint() )
529  result.push_back( QLatin1String(fpr) );
530  return result;
531 }
532 
533 QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const {
534  QStringList result;
535  for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
536  if ( it->protocol() == GpgME::OpenPGP )
537  if ( const char * fpr = it->primaryFingerprint() )
538  result.push_back( QLatin1String(fpr) );
539  return result;
540 }
541 
542 QStringList Kleo::KeySelectionDialog::smimeFingerprints() const {
543  QStringList result;
544  for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
545  if ( it->protocol() == GpgME::CMS )
546  if ( const char * fpr = it->primaryFingerprint() )
547  result.push_back( QLatin1String(fpr) );
548  return result;
549 }
550 
551 void Kleo::KeySelectionDialog::slotRereadKeys() {
552  mKeyListView->clear();
553  mListJobCount = 0;
554  mTruncated = 0;
555  mSavedOffsetY = mKeyListView->verticalScrollBar()->value();
556 
557  disconnectSignals();
558  mKeyListView->setEnabled( false );
559 
560  // FIXME: save current selection
561  if ( mOpenPGPBackend )
562  startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false /*non-validating*/ );
563  if ( mSMIMEBackend )
564  startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false /*non-validating*/ );
565 
566  if ( mListJobCount == 0 ) {
567  mKeyListView->setEnabled( true );
568  KMessageBox::information( this,
569  i18n("No backends found for listing keys. "
570  "Check your installation."),
571  i18n("Key Listing Failed") );
572  connectSignals();
573  }
574 }
575 
576 void Kleo::KeySelectionDialog::slotStartCertificateManager( const QString &query )
577 {
578  QStringList args;
579  // ### waits for bug 175980 to be fixed, ie. those command line args to be added again
580 #if 0
581  // ### port to libkleopatra
582  if ( !query.isEmpty() )
583  args << QLatin1String("--external") << QLatin1String("--query") << KUrl::decode_string( query );
584 #endif
585  Q_UNUSED( query );
586  if( !QProcess::startDetached( QLatin1String("kleopatra"), args ) )
587  KMessageBox::error( this,
588  i18n( "Could not start certificate manager; "
589  "please check your installation." ),
590  i18n( "Certificate Manager Error" ) );
591  else
592  kDebug(5150) <<"\nslotStartCertManager(): certificate manager started.";
593 }
594 
595 #ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
596 #define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
597 static void showKeyListError( QWidget * parent, const GpgME::Error & err ) {
598  assert( err );
599  const QString msg = i18n( "<qt><p>An error occurred while fetching "
600  "the keys from the backend:</p>"
601  "<p><b>%1</b></p></qt>" ,
602  QString::fromLocal8Bit( err.asString() ) );
603 
604  KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) );
605 }
606 #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
607 
608 namespace {
609  struct ExtractFingerprint {
610  QString operator()( const GpgME::Key & key ) {
611  return QLatin1String(key.primaryFingerprint());
612  }
613  };
614 }
615 
616 void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) {
617  assert( backend );
618  KeyListJob * job = backend->keyListJob( false, false, validate ); // local, w/o sigs, validation as givem
619  if ( !job )
620  return;
621 
622  connect( job, SIGNAL(result(GpgME::KeyListResult)),
623  SLOT(slotKeyListResult(GpgME::KeyListResult)) );
624  if ( validate )
625  connect( job, SIGNAL(nextKey(GpgME::Key)),
626  mKeyListView, SLOT(slotRefreshKey(GpgME::Key)) );
627  else
628  connect( job, SIGNAL(nextKey(GpgME::Key)),
629  mKeyListView, SLOT(slotAddKey(GpgME::Key)) );
630 
631  QStringList fprs;
632  std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() );
633  const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) );
634 
635  if ( err )
636  return showKeyListError( this, err );
637 
638 #ifndef LIBKLEO_NO_PROGRESSDIALOG
639  // FIXME: create a MultiProgressDialog:
640  (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this );
641 #endif
642  ++mListJobCount;
643 }
644 
645 static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) {
646  klv->clearSelection();
647  if ( selectedKeys.empty() )
648  return;
649  for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it )
650  if ( Kleo::KeyListViewItem * item = klv->itemByFingerprint( it->primaryFingerprint() ) )
651  item->setSelected( true );
652 }
653 
654 void Kleo::KeySelectionDialog::slotKeyListResult( const GpgME::KeyListResult & res ) {
655  if ( res.error() )
656  showKeyListError( this, res.error() );
657  else if ( res.isTruncated() )
658  ++mTruncated;
659 
660  if ( --mListJobCount > 0 )
661  return; // not yet finished...
662 
663  if ( mTruncated > 0 )
664  KMessageBox::information( this,
665  i18np("<qt>One backend returned truncated output.<p>"
666  "Not all available keys are shown</p></qt>",
667  "<qt>%1 backends returned truncated output.<p>"
668  "Not all available keys are shown</p></qt>",
669  mTruncated),
670  i18n("Key List Result") );
671 
672  mKeyListView->flushKeys();
673 
674  mKeyListView->setEnabled( true );
675  mListJobCount = mTruncated = 0;
676  mKeysToCheck.clear();
677 
678  selectKeys( mKeyListView, mSelectedKeys );
679 
680  slotFilter();
681 
682  connectSignals();
683 
684  slotSelectionChanged();
685 
686  // restore the saved position of the contents
687  mKeyListView->verticalScrollBar()->setValue( mSavedOffsetY ); mSavedOffsetY = 0;
688 }
689 
690 void Kleo::KeySelectionDialog::slotSelectionChanged() {
691  kDebug(5150) <<"KeySelectionDialog::slotSelectionChanged()";
692 
693  // (re)start the check selection timer. Checking the selection is delayed
694  // because else drag-selection doesn't work very good (checking key trust
695  // is slow).
696  mCheckSelectionTimer->start( sCheckSelectionDelay );
697 }
698 
699 namespace {
700  struct AlreadyChecked {
701  bool operator()( const GpgME::Key & key ) const {
702  return key.keyListMode() & GpgME::Validate ;
703  }
704  };
705 }
706 
707 void Kleo::KeySelectionDialog::slotCheckSelection( KeyListViewItem * item ) {
708  kDebug(5150) <<"KeySelectionDialog::slotCheckSelection()";
709 
710  mCheckSelectionTimer->stop();
711 
712  mSelectedKeys.clear();
713 
714  if ( !mKeyListView->isMultiSelection() ) {
715  if ( item )
716  mSelectedKeys.push_back( item->key() );
717  }
718 
719  for ( KeyListViewItem * it = mKeyListView->firstChild() ; it ; it = it->nextSibling() )
720  if ( it->isSelected() )
721  mSelectedKeys.push_back( it->key() );
722 
723  mKeysToCheck.clear();
724  std::remove_copy_if( mSelectedKeys.begin(), mSelectedKeys.end(),
725  std::back_inserter( mKeysToCheck ),
726  AlreadyChecked() );
727  if ( mKeysToCheck.empty() ) {
728  enableButton( Ok, !mSelectedKeys.empty() &&
729  checkKeyUsage( mSelectedKeys, mKeyUsage ) );
730  return;
731  }
732 
733  // performed all fast checks - now for validating key listing:
734  startValidatingKeyListing();
735 }
736 
737 void Kleo::KeySelectionDialog::startValidatingKeyListing() {
738  if ( mKeysToCheck.empty() )
739  return;
740 
741  mListJobCount = 0;
742  mTruncated = 0;
743  mSavedOffsetY = mKeyListView->verticalScrollBar()->value();
744 
745  disconnectSignals();
746  mKeyListView->setEnabled( false );
747 
748  std::vector<GpgME::Key> smime, openpgp;
749  for ( std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin() ; it != mKeysToCheck.end() ; ++it )
750  if ( it->protocol() == GpgME::OpenPGP )
751  openpgp.push_back( *it );
752  else
753  smime.push_back( *it );
754 
755  if ( !openpgp.empty() ) {
756  assert( mOpenPGPBackend );
757  startKeyListJobForBackend( mOpenPGPBackend, openpgp, true /*validate*/ );
758  }
759  if ( !smime.empty() ) {
760  assert( mSMIMEBackend );
761  startKeyListJobForBackend( mSMIMEBackend, smime, true /*validate*/ );
762  }
763 
764  assert( mListJobCount > 0 );
765 }
766 
767 bool Kleo::KeySelectionDialog::rememberSelection() const {
768  return mRememberCB && mRememberCB->isChecked() ;
769 }
770 
771 void Kleo::KeySelectionDialog::slotRMB( Kleo::KeyListViewItem * item, const QPoint & p ) {
772  if ( !item ) return;
773 
774  mCurrentContextMenuItem = item;
775 
776  KMenu menu;
777  menu.addAction( i18n( "Recheck Key" ), this, SLOT(slotRecheckKey()) );
778  menu.exec( p );
779 }
780 
781 void Kleo::KeySelectionDialog::slotRecheckKey() {
782  if ( !mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull() )
783  return;
784 
785  mKeysToCheck.clear();
786  mKeysToCheck.push_back( mCurrentContextMenuItem->key() );
787 }
788 
789 void Kleo::KeySelectionDialog::slotTryOk() {
790  if ( !mSelectedKeys.empty() && checkKeyUsage( mSelectedKeys, mKeyUsage ) )
791  slotOk();
792 }
793 
794 void Kleo::KeySelectionDialog::slotOk() {
795  if ( mCheckSelectionTimer->isActive() )
796  slotCheckSelection();
797 
798  // button could be disabled again after checking the selected key
799  if ( !mSelectedKeys.empty() && checkKeyUsage( mSelectedKeys, mKeyUsage ) )
800  return;
801 
802  mStartSearchTimer->stop();
803  accept();
804 }
805 
806 
807 void Kleo::KeySelectionDialog::slotCancel() {
808  mCheckSelectionTimer->stop();
809  mStartSearchTimer->stop();
810  reject();
811 }
812 
813 void Kleo::KeySelectionDialog::slotSearch( const QString & text ) {
814  mSearchText = text.trimmed().toUpper();
815  slotSearch();
816 }
817 
818 void Kleo::KeySelectionDialog::slotSearch() {
819  mStartSearchTimer->setSingleShot( true );
820  mStartSearchTimer->start( sCheckSelectionDelay );
821 }
822 
823 void Kleo::KeySelectionDialog::slotFilter() {
824  if ( mSearchText.isEmpty() ) {
825  showAllItems();
826  return;
827  }
828 
829  // OK, so we need to filter:
830  QRegExp keyIdRegExp( QLatin1String("(?:0x)?[A-F0-9]{1,8}"), Qt::CaseInsensitive );
831  if ( keyIdRegExp.exactMatch( mSearchText ) ) {
832  if ( mSearchText.startsWith( QLatin1String("0X") ) )
833  // search for keyID only:
834  filterByKeyID( mSearchText.mid( 2 ) );
835  else
836  // search for UID and keyID:
837  filterByKeyIDOrUID( mSearchText );
838  } else {
839  // search in UID:
840  filterByUID( mSearchText );
841  }
842 }
843 
844 void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) {
845  assert( keyID.length() <= 8 );
846  assert( !keyID.isEmpty() ); // regexp in slotFilter should prevent these
847  if ( keyID.isEmpty() )
848  showAllItems();
849  else
850  for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
851  item->setHidden( !item->text( 0 ).toUpper().startsWith( keyID ) );
852 }
853 
854 static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) {
855  if ( !item )
856  return false;
857 
858  const std::vector<GpgME::UserID> uids = item->key().userIDs();
859  for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
860  if ( it->id() && rx.indexIn( QString::fromUtf8( it->id() ) ) >= 0 )
861  return true;
862  return false;
863 }
864 
865 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const QString & str ) {
866  assert( !str.isEmpty() );
867 
868  // match beginnings of words:
869  QRegExp rx( QLatin1String("\\b") + QRegExp::escape( str ), Qt::CaseInsensitive );
870 
871  for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
872  item->setHidden( !item->text( 0 ).toUpper().startsWith( str ) && !anyUIDMatches( item, rx ) );
873 
874 }
875 
876 void Kleo::KeySelectionDialog::filterByUID( const QString & str ) {
877  assert( !str.isEmpty() );
878 
879  // match beginnings of words:
880  QRegExp rx( QLatin1String("\\b") + QRegExp::escape( str ), Qt::CaseInsensitive );
881 
882  for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
883  item->setHidden( !anyUIDMatches( item, rx ) );
884 }
885 
886 
887 void Kleo::KeySelectionDialog::showAllItems() {
888  for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
889  item->setHidden( false );
890 }
891 
892 #include "keyselectiondialog.moc"
time_t2string
static QString time_t2string(time_t t)
Definition: keyselectiondialog.cpp:166
Kleo::KeySelectionDialog::~KeySelectionDialog
~KeySelectionDialog()
Definition: keyselectiondialog.cpp:489
Kleo::KeySelectionDialog::smimeFingerprints
QStringList smimeFingerprints() const
Return the selected smime fingerprints.
Definition: keyselectiondialog.cpp:542
selectKeys
static void selectKeys(Kleo::KeyListView *klv, const std::vector< GpgME::Key > &selectedKeys)
Definition: keyselectiondialog.cpp:645
Kleo::KeyListView::ColumnStrategy::width
virtual int width(int column, const QFontMetrics &fm) const
Definition: keylistview.cpp:424
keylistview.h
Kleo::CryptoBackendFactory::smime
const CryptoBackend::Protocol * smime() const
Definition: cryptobackendfactory.cpp:117
Kleo::KeySelectionDialog::TrustedKeys
Definition: keyselectiondialog.h:79
QWidget
Kleo::KeySelectionDialog::SecretKeys
Definition: keyselectiondialog.h:75
keyselectiondialog.h
Kleo::KeySelectionDialog::fingerprint
QString fingerprint() const
Definition: keyselectiondialog.cpp:521
KDialog
Kleo::DN::prettyDN
QString prettyDN() const
Definition: dn.cpp:381
QString
Kleo::CryptoBackendFactory::instance
static CryptoBackendFactory * instance()
Definition: cryptobackendfactory.cpp:102
Kleo::KeySelectionDialog::EncryptionKeys
Definition: keyselectiondialog.h:76
dn.h
showKeyListError
static void showKeyListError(QWidget *parent, const GpgME::Error &err)
Definition: keyselectiondialog.cpp:597
Kleo::KeySelectionDialog::selectedKey
const GpgME::Key & selectedKey() const
Returns the key ID of the selected key in single selection mode.
Definition: keyselectiondialog.cpp:514
sCheckSelectionDelay
static const int sCheckSelectionDelay
Definition: keyselectiondialog.cpp:301
Kleo::KeyListViewItem::nextSibling
KeyListViewItem * nextSibling() const
Definition: keylistview.cpp:469
Kleo::KeySelectionDialog::rememberSelection
bool rememberSelection() const
Definition: keyselectiondialog.cpp:767
Kleo::KeySelectionDialog::fingerprints
QStringList fingerprints() const
Return all the selected fingerprints.
Definition: keyselectiondialog.cpp:525
Kleo::KeySelectionDialog::SigningKeys
Definition: keyselectiondialog.h:77
Kleo::KeySelectionDialog::ValidKeys
Definition: keyselectiondialog.h:78
cryptobackendfactory.h
Kleo::KeySelectionDialog::KeySelectionDialog
KeySelectionDialog(const QString &title, const QString &text, const std::vector< GpgME::Key > &selectedKeys=std::vector< GpgME::Key >(), unsigned int keyUsage=AllKeys, bool extendedSelection=false, bool rememberChoice=false, QWidget *parent=0, bool modal=true)
Definition: keyselectiondialog.cpp:303
kdtools::transform
O transform(const I &i, P p)
Definition: stl_util.h:374
Kleo::KeyListView::itemByFingerprint
KeyListViewItem * itemByFingerprint(const QByteArray &) const
Definition: keylistview.cpp:267
Kleo::KeySelectionDialog::PublicKeys
Definition: keyselectiondialog.h:74
Kleo::DN
DN parser and reorderer.
Definition: dn.h:77
Kleo::KeySelectionDialog::AuthenticationKeys
Definition: keyselectiondialog.h:81
Kleo::KeyListViewItem::key
const GpgME::Key & key() const
Definition: keylistview.h:78
Kleo::KeyListView
Definition: keylistview.h:101
keylistjob.h
Kleo::KeySelectionDialog::CertificationKeys
Definition: keyselectiondialog.h:80
Kleo::KeyListViewItem
Definition: keylistview.h:69
checkKeyUsage
static bool checkKeyUsage(const GpgME::Key &key, unsigned int keyUsage)
Definition: keyselectiondialog.cpp:90
progressdialog.h
QFrame
Kleo::KeyListView::ColumnStrategy
Definition: keylistview.h:106
Kleo::KeySelectionDialog::pgpKeyFingerprints
QStringList pgpKeyFingerprints() const
Return the selected openpgp fingerprints.
Definition: keyselectiondialog.cpp:533
anyUIDMatches
static bool anyUIDMatches(const Kleo::KeyListViewItem *item, QRegExp &rx)
Definition: keyselectiondialog.cpp:854
Kleo::CryptoBackendFactory::openpgp
const CryptoBackend::Protocol * openpgp() const
Definition: cryptobackendfactory.cpp:126
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:57:48 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

libkleo

Skip menu "libkleo"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal