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

libkleo

  • sources
  • kde-4.14
  • 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  const QByteArray headerState = dialogConfig.readEntry( "header", QByteArray());
486  if (!headerState.isEmpty())
487  mKeyListView->header()->restoreState(headerState);
488  resize( dialogSize );
489  }
490 }
491 
492 Kleo::KeySelectionDialog::~KeySelectionDialog() {
493  KConfigGroup dialogConfig( KGlobal::config(), "Key Selection Dialog" );
494  dialogConfig.writeEntry( "Dialog size", size() );
495  dialogConfig.writeEntry( "header", mKeyListView->header()->saveState());
496  dialogConfig.sync();
497 }
498 
499 
500 void Kleo::KeySelectionDialog::connectSignals() {
501  if ( mKeyListView->isMultiSelection() )
502  connect( mKeyListView, SIGNAL(itemSelectionChanged()),
503  SLOT(slotSelectionChanged()) );
504  else
505  connect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
506  SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
507 }
508 
509 void Kleo::KeySelectionDialog::disconnectSignals() {
510  if ( mKeyListView->isMultiSelection() )
511  disconnect( mKeyListView, SIGNAL(itemSelectionChanged()),
512  this, SLOT(slotSelectionChanged()) );
513  else
514  disconnect( mKeyListView, SIGNAL(selectionChanged(Kleo::KeyListViewItem*)),
515  this, SLOT(slotCheckSelection(Kleo::KeyListViewItem*)) );
516 }
517 
518 const GpgME::Key & Kleo::KeySelectionDialog::selectedKey() const {
519  static const GpgME::Key null = GpgME::Key::null;
520  if ( mKeyListView->isMultiSelection() || !mKeyListView->selectedItem() )
521  return null;
522  return mKeyListView->selectedItem()->key();
523 }
524 
525 QString Kleo::KeySelectionDialog::fingerprint() const {
526  return QLatin1String(selectedKey().primaryFingerprint());
527 }
528 
529 QStringList Kleo::KeySelectionDialog::fingerprints() const {
530  QStringList result;
531  for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
532  if ( const char * fpr = it->primaryFingerprint() )
533  result.push_back( QLatin1String(fpr) );
534  return result;
535 }
536 
537 QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const {
538  QStringList result;
539  for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
540  if ( it->protocol() == GpgME::OpenPGP )
541  if ( const char * fpr = it->primaryFingerprint() )
542  result.push_back( QLatin1String(fpr) );
543  return result;
544 }
545 
546 QStringList Kleo::KeySelectionDialog::smimeFingerprints() const {
547  QStringList result;
548  for ( std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin() ; it != mSelectedKeys.end() ; ++it )
549  if ( it->protocol() == GpgME::CMS )
550  if ( const char * fpr = it->primaryFingerprint() )
551  result.push_back( QLatin1String(fpr) );
552  return result;
553 }
554 
555 void Kleo::KeySelectionDialog::slotRereadKeys() {
556  mKeyListView->clear();
557  mListJobCount = 0;
558  mTruncated = 0;
559  mSavedOffsetY = mKeyListView->verticalScrollBar()->value();
560 
561  disconnectSignals();
562  mKeyListView->setEnabled( false );
563 
564  // FIXME: save current selection
565  if ( mOpenPGPBackend )
566  startKeyListJobForBackend( mOpenPGPBackend, std::vector<GpgME::Key>(), false /*non-validating*/ );
567  if ( mSMIMEBackend )
568  startKeyListJobForBackend( mSMIMEBackend, std::vector<GpgME::Key>(), false /*non-validating*/ );
569 
570  if ( mListJobCount == 0 ) {
571  mKeyListView->setEnabled( true );
572  KMessageBox::information( this,
573  i18n("No backends found for listing keys. "
574  "Check your installation."),
575  i18n("Key Listing Failed") );
576  connectSignals();
577  }
578 }
579 
580 void Kleo::KeySelectionDialog::slotStartCertificateManager( const QString &query )
581 {
582  QStringList args;
583  // ### waits for bug 175980 to be fixed, ie. those command line args to be added again
584 #if 0
585  // ### port to libkleopatra
586  if ( !query.isEmpty() )
587  args << QLatin1String("--external") << QLatin1String("--query") << KUrl::decode_string( query );
588 #endif
589  Q_UNUSED( query );
590  if( !QProcess::startDetached( QLatin1String("kleopatra"), args ) )
591  KMessageBox::error( this,
592  i18n( "Could not start certificate manager; "
593  "please check your installation." ),
594  i18n( "Certificate Manager Error" ) );
595  else
596  kDebug(5150) <<"\nslotStartCertManager(): certificate manager started.";
597 }
598 
599 #ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
600 #define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
601 static void showKeyListError( QWidget * parent, const GpgME::Error & err ) {
602  assert( err );
603  const QString msg = i18n( "<qt><p>An error occurred while fetching "
604  "the keys from the backend:</p>"
605  "<p><b>%1</b></p></qt>" ,
606  QString::fromLocal8Bit( err.asString() ) );
607 
608  KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) );
609 }
610 #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
611 
612 namespace {
613  struct ExtractFingerprint {
614  QString operator()( const GpgME::Key & key ) {
615  return QLatin1String(key.primaryFingerprint());
616  }
617  };
618 }
619 
620 void Kleo::KeySelectionDialog::startKeyListJobForBackend( const CryptoBackend::Protocol * backend, const std::vector<GpgME::Key> & keys, bool validate ) {
621  assert( backend );
622  KeyListJob * job = backend->keyListJob( false, false, validate ); // local, w/o sigs, validation as givem
623  if ( !job )
624  return;
625 
626  connect( job, SIGNAL(result(GpgME::KeyListResult)),
627  SLOT(slotKeyListResult(GpgME::KeyListResult)) );
628  if ( validate )
629  connect( job, SIGNAL(nextKey(GpgME::Key)),
630  mKeyListView, SLOT(slotRefreshKey(GpgME::Key)) );
631  else
632  connect( job, SIGNAL(nextKey(GpgME::Key)),
633  mKeyListView, SLOT(slotAddKey(GpgME::Key)) );
634 
635  QStringList fprs;
636  std::transform( keys.begin(), keys.end(), std::back_inserter( fprs ), ExtractFingerprint() );
637  const GpgME::Error err = job->start( fprs, mKeyUsage & SecretKeys && !( mKeyUsage & PublicKeys ) );
638 
639  if ( err )
640  return showKeyListError( this, err );
641 
642 #ifndef LIBKLEO_NO_PROGRESSDIALOG
643  // FIXME: create a MultiProgressDialog:
644  (void)new ProgressDialog( job, validate ? i18n( "Checking selected keys..." ) : i18n( "Fetching keys..." ), this );
645 #endif
646  ++mListJobCount;
647 }
648 
649 static void selectKeys( Kleo::KeyListView * klv, const std::vector<GpgME::Key> & selectedKeys ) {
650  klv->clearSelection();
651  if ( selectedKeys.empty() )
652  return;
653  for ( std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin() ; it != selectedKeys.end() ; ++it )
654  if ( Kleo::KeyListViewItem * item = klv->itemByFingerprint( it->primaryFingerprint() ) )
655  item->setSelected( true );
656 }
657 
658 void Kleo::KeySelectionDialog::slotKeyListResult( const GpgME::KeyListResult & res ) {
659  if ( res.error() )
660  showKeyListError( this, res.error() );
661  else if ( res.isTruncated() )
662  ++mTruncated;
663 
664  if ( --mListJobCount > 0 )
665  return; // not yet finished...
666 
667  if ( mTruncated > 0 )
668  KMessageBox::information( this,
669  i18np("<qt>One backend returned truncated output.<p>"
670  "Not all available keys are shown</p></qt>",
671  "<qt>%1 backends returned truncated output.<p>"
672  "Not all available keys are shown</p></qt>",
673  mTruncated),
674  i18n("Key List Result") );
675 
676  mKeyListView->flushKeys();
677 
678  mKeyListView->setEnabled( true );
679  mListJobCount = mTruncated = 0;
680  mKeysToCheck.clear();
681 
682  selectKeys( mKeyListView, mSelectedKeys );
683 
684  slotFilter();
685 
686  connectSignals();
687 
688  slotSelectionChanged();
689 
690  // restore the saved position of the contents
691  mKeyListView->verticalScrollBar()->setValue( mSavedOffsetY ); mSavedOffsetY = 0;
692 }
693 
694 void Kleo::KeySelectionDialog::slotSelectionChanged() {
695  kDebug(5150) <<"KeySelectionDialog::slotSelectionChanged()";
696 
697  // (re)start the check selection timer. Checking the selection is delayed
698  // because else drag-selection doesn't work very good (checking key trust
699  // is slow).
700  mCheckSelectionTimer->start( sCheckSelectionDelay );
701 }
702 
703 namespace {
704  struct AlreadyChecked {
705  bool operator()( const GpgME::Key & key ) const {
706  return key.keyListMode() & GpgME::Validate ;
707  }
708  };
709 }
710 
711 void Kleo::KeySelectionDialog::slotCheckSelection( KeyListViewItem * item ) {
712  kDebug(5150) <<"KeySelectionDialog::slotCheckSelection()";
713 
714  mCheckSelectionTimer->stop();
715 
716  mSelectedKeys.clear();
717 
718  if ( !mKeyListView->isMultiSelection() ) {
719  if ( item )
720  mSelectedKeys.push_back( item->key() );
721  }
722 
723  for ( KeyListViewItem * it = mKeyListView->firstChild() ; it ; it = it->nextSibling() )
724  if ( it->isSelected() )
725  mSelectedKeys.push_back( it->key() );
726 
727  mKeysToCheck.clear();
728  std::remove_copy_if( mSelectedKeys.begin(), mSelectedKeys.end(),
729  std::back_inserter( mKeysToCheck ),
730  AlreadyChecked() );
731  if ( mKeysToCheck.empty() ) {
732  enableButton( Ok, !mSelectedKeys.empty() &&
733  checkKeyUsage( mSelectedKeys, mKeyUsage ) );
734  return;
735  }
736 
737  // performed all fast checks - now for validating key listing:
738  startValidatingKeyListing();
739 }
740 
741 void Kleo::KeySelectionDialog::startValidatingKeyListing() {
742  if ( mKeysToCheck.empty() )
743  return;
744 
745  mListJobCount = 0;
746  mTruncated = 0;
747  mSavedOffsetY = mKeyListView->verticalScrollBar()->value();
748 
749  disconnectSignals();
750  mKeyListView->setEnabled( false );
751 
752  std::vector<GpgME::Key> smime, openpgp;
753  for ( std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin() ; it != mKeysToCheck.end() ; ++it )
754  if ( it->protocol() == GpgME::OpenPGP )
755  openpgp.push_back( *it );
756  else
757  smime.push_back( *it );
758 
759  if ( !openpgp.empty() ) {
760  assert( mOpenPGPBackend );
761  startKeyListJobForBackend( mOpenPGPBackend, openpgp, true /*validate*/ );
762  }
763  if ( !smime.empty() ) {
764  assert( mSMIMEBackend );
765  startKeyListJobForBackend( mSMIMEBackend, smime, true /*validate*/ );
766  }
767 
768  assert( mListJobCount > 0 );
769 }
770 
771 bool Kleo::KeySelectionDialog::rememberSelection() const {
772  return mRememberCB && mRememberCB->isChecked() ;
773 }
774 
775 void Kleo::KeySelectionDialog::slotRMB( Kleo::KeyListViewItem * item, const QPoint & p ) {
776  if ( !item ) return;
777 
778  mCurrentContextMenuItem = item;
779 
780  KMenu menu;
781  menu.addAction( i18n( "Recheck Key" ), this, SLOT(slotRecheckKey()) );
782  menu.exec( p );
783 }
784 
785 void Kleo::KeySelectionDialog::slotRecheckKey() {
786  if ( !mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull() )
787  return;
788 
789  mKeysToCheck.clear();
790  mKeysToCheck.push_back( mCurrentContextMenuItem->key() );
791 }
792 
793 void Kleo::KeySelectionDialog::slotTryOk() {
794  if ( !mSelectedKeys.empty() && checkKeyUsage( mSelectedKeys, mKeyUsage ) )
795  slotOk();
796 }
797 
798 void Kleo::KeySelectionDialog::slotOk() {
799  if ( mCheckSelectionTimer->isActive() )
800  slotCheckSelection();
801 
802  // button could be disabled again after checking the selected key
803  if ( !mSelectedKeys.empty() && checkKeyUsage( mSelectedKeys, mKeyUsage ) )
804  return;
805 
806  mStartSearchTimer->stop();
807  accept();
808 }
809 
810 
811 void Kleo::KeySelectionDialog::slotCancel() {
812  mCheckSelectionTimer->stop();
813  mStartSearchTimer->stop();
814  reject();
815 }
816 
817 void Kleo::KeySelectionDialog::slotSearch( const QString & text ) {
818  mSearchText = text.trimmed().toUpper();
819  slotSearch();
820 }
821 
822 void Kleo::KeySelectionDialog::slotSearch() {
823  mStartSearchTimer->setSingleShot( true );
824  mStartSearchTimer->start( sCheckSelectionDelay );
825 }
826 
827 void Kleo::KeySelectionDialog::slotFilter() {
828  if ( mSearchText.isEmpty() ) {
829  showAllItems();
830  return;
831  }
832 
833  // OK, so we need to filter:
834  QRegExp keyIdRegExp( QLatin1String("(?:0x)?[A-F0-9]{1,8}"), Qt::CaseInsensitive );
835  if ( keyIdRegExp.exactMatch( mSearchText ) ) {
836  if ( mSearchText.startsWith( QLatin1String("0X") ) )
837  // search for keyID only:
838  filterByKeyID( mSearchText.mid( 2 ) );
839  else
840  // search for UID and keyID:
841  filterByKeyIDOrUID( mSearchText );
842  } else {
843  // search in UID:
844  filterByUID( mSearchText );
845  }
846 }
847 
848 void Kleo::KeySelectionDialog::filterByKeyID( const QString & keyID ) {
849  assert( keyID.length() <= 8 );
850  assert( !keyID.isEmpty() ); // regexp in slotFilter should prevent these
851  if ( keyID.isEmpty() )
852  showAllItems();
853  else
854  for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
855  item->setHidden( !item->text( 0 ).toUpper().startsWith( keyID ) );
856 }
857 
858 static bool anyUIDMatches( const Kleo::KeyListViewItem * item, QRegExp & rx ) {
859  if ( !item )
860  return false;
861 
862  const std::vector<GpgME::UserID> uids = item->key().userIDs();
863  for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it )
864  if ( it->id() && rx.indexIn( QString::fromUtf8( it->id() ) ) >= 0 )
865  return true;
866  return false;
867 }
868 
869 void Kleo::KeySelectionDialog::filterByKeyIDOrUID( const QString & str ) {
870  assert( !str.isEmpty() );
871 
872  // match beginnings of words:
873  QRegExp rx( QLatin1String("\\b") + QRegExp::escape( str ), Qt::CaseInsensitive );
874 
875  for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
876  item->setHidden( !item->text( 0 ).toUpper().startsWith( str ) && !anyUIDMatches( item, rx ) );
877 
878 }
879 
880 void Kleo::KeySelectionDialog::filterByUID( const QString & str ) {
881  assert( !str.isEmpty() );
882 
883  // match beginnings of words:
884  QRegExp rx( QLatin1String("\\b") + QRegExp::escape( str ), Qt::CaseInsensitive );
885 
886  for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
887  item->setHidden( !anyUIDMatches( item, rx ) );
888 }
889 
890 
891 void Kleo::KeySelectionDialog::showAllItems() {
892  for ( KeyListViewItem * item = mKeyListView->firstChild() ; item ; item = item->nextSibling() )
893  item->setHidden( false );
894 }
895 
time_t2string
static QString time_t2string(time_t t)
Definition: keyselectiondialog.cpp:166
QDateTime::toString
QString toString(Qt::DateFormat format) const
QWidget
Kleo::KeySelectionDialog::~KeySelectionDialog
~KeySelectionDialog()
Definition: keyselectiondialog.cpp:492
Kleo::KeySelectionDialog::smimeFingerprints
QStringList smimeFingerprints() const
Return the selected smime fingerprints.
Definition: keyselectiondialog.cpp:546
QString::toUpper
QString toUpper() const
selectKeys
static void selectKeys(Kleo::KeyListView *klv, const std::vector< GpgME::Key > &selectedKeys)
Definition: keyselectiondialog.cpp:649
Kleo::KeyListView::ColumnStrategy::width
virtual int width(int column, const QFontMetrics &fm) const
Definition: keylistview.cpp:424
keylistview.h
QList::push_back
void push_back(const T &value)
QByteArray
Kleo::CryptoBackendFactory::smime
const CryptoBackend::Protocol * smime() const
Definition: cryptobackendfactory.cpp:117
Kleo::KeySelectionDialog::TrustedKeys
Definition: keyselectiondialog.h:79
QRegExp::escape
QString escape(const QString &str)
QProcess::startDetached
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
Kleo::KeySelectionDialog::SecretKeys
Definition: keyselectiondialog.h:75
QByteArray::isEmpty
bool isEmpty() const
keyselectiondialog.h
QHBoxLayout
Kleo::KeySelectionDialog::fingerprint
QString fingerprint() const
Definition: keyselectiondialog.cpp:525
QPoint
KDialog
QFontMetrics
Kleo::DN::prettyDN
QString prettyDN() const
Definition: dn.cpp:381
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:601
QLabel::setBuddy
void setBuddy(QWidget *buddy)
Kleo::KeySelectionDialog::selectedKey
const GpgME::Key & selectedKey() const
Returns the key ID of the selected key in single selection mode.
Definition: keyselectiondialog.cpp:518
QRegExp::indexIn
int indexIn(const QString &str, int offset, CaretMode caretMode) const
sCheckSelectionDelay
static const int sCheckSelectionDelay
Definition: keyselectiondialog.cpp:301
QRegExp
Kleo::KeyListViewItem::nextSibling
KeyListViewItem * nextSibling() const
Definition: keylistview.cpp:469
QBoxLayout::addWidget
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
QString::fromLocal8Bit
QString fromLocal8Bit(const char *str, int size)
QString::fromUtf8
QString fromUtf8(const char *str, int size)
QTimer
Kleo::KeySelectionDialog::rememberSelection
bool rememberSelection() const
Definition: keyselectiondialog.cpp:771
QCheckBox
Kleo::KeySelectionDialog::fingerprints
QStringList fingerprints() const
Return all the selected fingerprints.
Definition: keyselectiondialog.cpp:529
Kleo::KeySelectionDialog::SigningKeys
Definition: keyselectiondialog.h:77
QString::isEmpty
bool isEmpty() const
QString::trimmed
QString trimmed() const
Kleo::KeySelectionDialog::ValidKeys
Definition: keyselectiondialog.h:78
cryptobackendfactory.h
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
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:376
QVBoxLayout
QString
QWidget::hide
void hide()
QWidget::setSizePolicy
void setSizePolicy(QSizePolicy)
Kleo::KeyListView::itemByFingerprint
KeyListViewItem * itemByFingerprint(const QByteArray &) const
Definition: keylistview.cpp:267
Kleo::KeySelectionDialog::PublicKeys
Definition: keyselectiondialog.h:74
QStringList
Kleo::DN
DN parser and reorderer.
Definition: dn.h:77
QTreeWidgetItem::setHidden
void setHidden(bool hide)
Kleo::KeySelectionDialog::AuthenticationKeys
Definition: keyselectiondialog.h:81
QSize
QLatin1Char
QFrame
QFontMetrics::width
int width(const QString &text, int len) const
Kleo::KeyListViewItem::key
const GpgME::Key & key() const
Definition: keylistview.h:78
Kleo::KeyListView
Definition: keylistview.h:101
QLatin1String
keylistjob.h
QString::length
int length() const
Kleo::KeySelectionDialog::CertificationKeys
Definition: keyselectiondialog.h:80
Kleo::KeyListViewItem
Definition: keylistview.h:69
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QPushButton
checkKeyUsage
static bool checkKeyUsage(const GpgME::Key &key, unsigned int keyUsage)
Definition: keyselectiondialog.cpp:90
progressdialog.h
QAbstractItemView::clearSelection
void clearSelection()
QLabel
Kleo::KeyListView::ColumnStrategy
Definition: keylistview.h:106
QTreeWidgetItem::text
QString text(int column) const
Kleo::KeySelectionDialog::pgpKeyFingerprints
QStringList pgpKeyFingerprints() const
Return the selected openpgp fingerprints.
Definition: keyselectiondialog.cpp:537
QLabel::setWordWrap
void setWordWrap(bool on)
anyUIDMatches
static bool anyUIDMatches(const Kleo::KeyListViewItem *item, QRegExp &rx)
Definition: keyselectiondialog.cpp:858
QDateTime
Kleo::CryptoBackendFactory::openpgp
const CryptoBackend::Protocol * openpgp() const
Definition: cryptobackendfactory.cpp:126
QDateTime::setTime_t
void setTime_t(uint seconds)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:33:38 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
  • pimprint

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