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

kleopatra

  • sources
  • kde-4.14
  • kdepim
  • kleopatra
  • models
keycache.cpp
Go to the documentation of this file.
1 /* -*- mode: c++; c-basic-offset:4 -*-
2  models/keycache.cpp
3 
4  This file is part of Kleopatra, the KDE keymanager
5  Copyright (c) 2007,2008 Klarälvdalens Datakonsult AB
6 
7  Kleopatra is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  Kleopatra is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21  In addition, as a special exception, the copyright holders give
22  permission to link the code of this program with any edition of
23  the Qt library by Trolltech AS, Norway (or with modified versions
24  of Qt that use the same license as Qt), and distribute linked
25  combinations including the two. You must obey the GNU General
26  Public License in all respects for all of the code used other than
27  Qt. If you modify this file, you may extend this exception to
28  your version of the file, but you are not obligated to do so. If
29  you do not wish to do so, delete this exception statement from
30  your version.
31 */
32 
33 #include <config-kleopatra.h>
34 
35 #include "keycache.h"
36 #include "keycache_p.h"
37 
38 #include "predicates.h"
39 
40 #include "smimevalidationpreferences.h"
41 
42 #include <utils/filesystemwatcher.h>
43 #include <utils/progressmanager.h>
44 
45 #include <kleo/stl_util.h>
46 #include <kleo/cryptobackendfactory.h>
47 #include <kleo/dn.h>
48 #include <kleo/keylistjob.h>
49 #include <kleo/listallkeysjob.h>
50 
51 #include <gpgme++/error.h>
52 #include <gpgme++/key.h>
53 #include <gpgme++/decryptionresult.h>
54 #include <gpgme++/verificationresult.h>
55 #include <gpgme++/keylistresult.h>
56 
57 #include <gpg-error.h>
58 
59 #include <kmime/kmime_header_parsing.h>
60 
61 #include <KLocalizedString>
62 
63 #include <QPointer>
64 #include <QTimer>
65 
66 #ifndef Q_MOC_RUN
67 #include <boost/bind.hpp>
68 #include <boost/mem_fn.hpp>
69 #include <boost/range.hpp>
70 #include <boost/weak_ptr.hpp>
71 #include <boost/iterator/filter_iterator.hpp>
72 #endif
73 
74 #include <utility>
75 #include <algorithm>
76 #include <functional>
77 #include <iterator>
78 
79 using namespace Kleo;
80 using namespace GpgME;
81 using namespace boost;
82 using namespace KMime::Types;
83 
84 static const unsigned int hours2ms = 1000 * 60 * 60;
85 
86 //
87 //
88 // KeyCache
89 //
90 //
91 
92 namespace {
93 
94  make_comparator_str( ByEMail, .first.c_str() );
95 
96  struct is_string_empty : std::unary_function<const char*,bool> {
97  bool operator()( const char * s ) const { return !s || !*s; }
98  };
99 
100 }
101 
102 class KeyCache::Private {
103  friend class ::Kleo::KeyCache;
104  KeyCache * const q;
105 public:
106  explicit Private( KeyCache * qq ) : q( qq ) {
107  connect( &m_autoKeyListingTimer, SIGNAL(timeout()), q, SLOT(startKeyListing()) );
108  updateAutoKeyListingTimer();
109  }
110 
111  template < template <template <typename U> class Op> class Comp>
112  std::vector<Key>::const_iterator find( const std::vector<Key> & keys, const char * key ) const {
113  const std::vector<Key>::const_iterator it =
114  std::lower_bound( keys.begin(), keys.end(), key, Comp<std::less>() );
115  if ( it == keys.end() || Comp<std::equal_to>()( *it, key ) )
116  return it;
117  else
118  return keys.end();
119  }
120 
121  template < template <template <typename U> class Op> class Comp>
122  std::vector<Subkey>::const_iterator find( const std::vector<Subkey> & keys, const char * key ) const {
123  const std::vector<Subkey>::const_iterator it =
124  std::lower_bound( keys.begin(), keys.end(), key, Comp<std::less>() );
125  if ( it == keys.end() || Comp<std::equal_to>()( *it, key ) )
126  return it;
127  else
128  return keys.end();
129  }
130 
131  std::vector<Key>::const_iterator find_fpr( const char * fpr ) const {
132  return find<_detail::ByFingerprint>( by.fpr, fpr );
133  }
134 
135  std::pair< std::vector< std::pair<std::string,Key> >::const_iterator,
136  std::vector< std::pair<std::string,Key> >::const_iterator >
137  find_email( const char * email ) const {
138  return std::equal_range( by.email.begin(), by.email.end(),
139  email, ByEMail<std::less>() );
140  }
141 
142  std::vector<Key> find_mailbox( const Mailbox & mb, bool sign ) const;
143 
144  std::vector<Subkey>::const_iterator find_subkeyid( const char * subkeyid ) const {
145  return find<_detail::ByKeyID>( by.subkeyid, subkeyid );
146  }
147 
148  std::vector<Key>::const_iterator find_keyid( const char * keyid ) const {
149  return find<_detail::ByKeyID>( by.keyid, keyid );
150  }
151 
152  std::vector<Key>::const_iterator find_shortkeyid( const char * shortkeyid ) const {
153  return find<_detail::ByShortKeyID>( by.shortkeyid, shortkeyid );
154  }
155 
156  std::pair<
157  std::vector<Key>::const_iterator,
158  std::vector<Key>::const_iterator
159  > find_subjects( const char * chain_id ) const {
160  return std::equal_range( by.chainid.begin(), by.chainid.end(),
161  chain_id, _detail::ByChainID<std::less>() );
162  }
163 
164  void refreshJobDone( const KeyListResult & result );
165 
166 
167  void updateAutoKeyListingTimer() {
168  setAutoKeyListingInterval( hours2ms * SMimeValidationPreferences().refreshInterval() );
169  }
170  void setAutoKeyListingInterval( int ms ) {
171  m_autoKeyListingTimer.stop();
172  m_autoKeyListingTimer.setInterval( ms );
173  if ( ms != 0 )
174  m_autoKeyListingTimer.start();
175  }
176 
177 private:
178  QPointer<RefreshKeysJob> m_refreshJob;
179  std::vector<shared_ptr<FileSystemWatcher> > m_fsWatchers;
180  QTimer m_autoKeyListingTimer;
181 
182  struct By {
183  std::vector<Key> fpr, keyid, shortkeyid, chainid;
184  std::vector< std::pair<std::string,Key> > email;
185  std::vector<Subkey> subkeyid;
186  } by;
187 };
188 
189 
190 shared_ptr<const KeyCache> KeyCache::instance() {
191  return mutableInstance();
192 }
193 
194 shared_ptr<KeyCache> KeyCache::mutableInstance() {
195  static weak_ptr<KeyCache> self;
196  try {
197  return shared_ptr<KeyCache>( self );
198  } catch ( const bad_weak_ptr & ) {
199  const shared_ptr<KeyCache> s( new KeyCache );
200  self = s;
201  return s;
202  }
203 }
204 
205 KeyCache::KeyCache()
206  : QObject(), d( new Private( this ) )
207 {
208 
209 }
210 
211 KeyCache::~KeyCache() {}
212 
213 void KeyCache::enableFileSystemWatcher( bool enable )
214 {
215  Q_FOREACH( const shared_ptr<FileSystemWatcher> & i, d->m_fsWatchers )
216  i->setEnabled( enable );
217 }
218 
219 void KeyCache::reload( GpgME::Protocol /*proto*/ )
220 {
221  if ( d->m_refreshJob )
222  return;
223 
224  d->updateAutoKeyListingTimer();
225 
226  enableFileSystemWatcher( false );
227  d->m_refreshJob = new RefreshKeysJob( this );
228  connect( d->m_refreshJob, SIGNAL(done(GpgME::KeyListResult)), this, SLOT(refreshJobDone(GpgME::KeyListResult)) );
229  d->m_refreshJob->start();
230 }
231 
232 void KeyCache::cancelKeyListing()
233 {
234  if ( !d->m_refreshJob )
235  return;
236  d->m_refreshJob->cancel();
237 }
238 
239 void KeyCache::addFileSystemWatcher( const shared_ptr<FileSystemWatcher>& watcher )
240 {
241  if ( !watcher )
242  return;
243  d->m_fsWatchers.push_back( watcher );
244  connect( watcher.get(), SIGNAL(directoryChanged(QString)),
245  this, SLOT(startKeyListing()) );
246  connect( watcher.get(), SIGNAL(fileChanged(QString)),
247  this, SLOT(startKeyListing()) );
248 
249  watcher->setEnabled( d->m_refreshJob == 0 );
250 }
251 
252 void KeyCache::Private::refreshJobDone( const KeyListResult& result )
253 {
254  emit q->keyListingDone( result );
255  q->enableFileSystemWatcher( true );
256 }
257 
258 const Key & KeyCache::findByFingerprint( const char * fpr ) const {
259  const std::vector<Key>::const_iterator it = d->find_fpr( fpr );
260  if ( it == d->by.fpr.end() ) {
261  static const Key null;
262  return null;
263  } else {
264  return *it;
265  }
266 }
267 
268 std::vector<Key> KeyCache::findByFingerprint( const std::vector<std::string> & fprs ) const {
269  std::vector<std::string> sorted;
270  sorted.reserve( fprs.size() );
271  std::remove_copy_if( fprs.begin(), fprs.end(), std::back_inserter( sorted ),
272  boost::bind( is_string_empty(), boost::bind( &std::string::c_str, _1 ) ) );
273 
274  std::sort( sorted.begin(), sorted.end(), _detail::ByFingerprint<std::less>() );
275 
276  std::vector<Key> result;
277  kdtools::set_intersection( d->by.fpr.begin(), d->by.fpr.end(),
278  sorted.begin(), sorted.end(),
279  std::back_inserter( result ),
280  _detail::ByFingerprint<std::less>() );
281  return result;
282 }
283 
284 std::vector<Key> KeyCache::findByEMailAddress( const char * email ) const {
285  const std::pair<
286  std::vector< std::pair<std::string,Key> >::const_iterator,
287  std::vector< std::pair<std::string,Key> >::const_iterator
288  > pair = d->find_email( email );
289  std::vector<Key> result;
290  result.reserve( std::distance( pair.first, pair.second ) );
291  std::transform( pair.first, pair.second,
292  std::back_inserter( result ),
293  boost::bind( &std::pair<std::string,Key>::second, _1 ) );
294  return result;
295 }
296 
297 std::vector<Key> KeyCache::findByEMailAddress( const std::string & email ) const {
298  return findByEMailAddress( email.c_str() );
299 }
300 
301 const Key & KeyCache::findByShortKeyID( const char * id ) const {
302  const std::vector<Key>::const_iterator it = d->find_shortkeyid( id );
303  if ( it != d->by.shortkeyid.end() )
304  return *it;
305  static const Key null;
306  return null;
307 }
308 
309 const Key & KeyCache::findByKeyIDOrFingerprint( const char * id ) const {
310  {
311  // try by.fpr first:
312  const std::vector<Key>::const_iterator it = d->find_fpr( id );
313  if ( it != d->by.fpr.end() )
314  return *it;
315  }{
316  // try by.keyid next:
317  const std::vector<Key>::const_iterator it = d->find_keyid( id );
318  if ( it != d->by.keyid.end() )
319  return *it;
320  }
321  static const Key null;
322  return null;
323 }
324 
325 std::vector<Key> KeyCache::findByKeyIDOrFingerprint( const std::vector<std::string> & ids ) const {
326 
327  std::vector<std::string> keyids;
328  std::remove_copy_if( ids.begin(), ids.end(), std::back_inserter( keyids ),
329  boost::bind( is_string_empty(), boost::bind( &std::string::c_str, _1 ) ) );
330 
331  // this is just case-insensitive string search:
332  std::sort( keyids.begin(), keyids.end(), _detail::ByFingerprint<std::less>() );
333 
334  std::vector<Key> result;
335  result.reserve( keyids.size() ); // dups shouldn't happen
336 
337  kdtools::set_intersection( d->by.fpr.begin(), d->by.fpr.end(),
338  keyids.begin(), keyids.end(),
339  std::back_inserter( result ),
340  _detail::ByFingerprint<std::less>() );
341  if ( result.size() < keyids.size() ) {
342  // note that By{Fingerprint,KeyID,ShortKeyID} define the same
343  // order for _strings_
344  kdtools::set_intersection( d->by.keyid.begin(), d->by.keyid.end(),
345  keyids.begin(), keyids.end(),
346  std::back_inserter( result ),
347  _detail::ByKeyID<std::less>() );
348  }
349  // duplicates shouldn't happen, but make sure nonetheless:
350  std::sort( result.begin(), result.end(), _detail::ByFingerprint<std::less>() );
351  result.erase( std::unique( result.begin(), result.end(), _detail::ByFingerprint<std::equal_to>() ), result.end() );
352 
353  // we skip looking into short key ids here, as it's highly
354  // unlikely they're used for this purpose. We might need to revise
355  // this decision, but only after testing.
356  return result;
357 }
358 
359 
360 std::vector<Subkey> KeyCache::findSubkeysByKeyID( const std::vector<std::string> & ids ) const {
361  std::vector<std::string> sorted;
362  sorted.reserve( ids.size() );
363  std::remove_copy_if( ids.begin(), ids.end(), std::back_inserter( sorted ),
364  boost::bind( is_string_empty(), boost::bind( &std::string::c_str, _1 ) ) );
365 
366  std::sort( sorted.begin(), sorted.end(), _detail::ByKeyID<std::less>() );
367 
368  std::vector<Subkey> result;
369  kdtools::set_intersection( d->by.subkeyid.begin(), d->by.subkeyid.end(),
370  sorted.begin(), sorted.end(),
371  std::back_inserter( result ),
372  _detail::ByKeyID<std::less>() );
373  return result;
374 }
375 
376 std::vector<Key> KeyCache::findRecipients( const DecryptionResult & res ) const {
377  std::vector<std::string> keyids;
378  Q_FOREACH( const DecryptionResult::Recipient & r, res.recipients() )
379  if ( const char * kid = r.keyID() )
380  keyids.push_back( kid );
381  const std::vector<Subkey> subkeys = findSubkeysByKeyID( keyids );
382  std::vector<Key> result;
383  result.reserve( subkeys.size() );
384  std::transform( subkeys.begin(), subkeys.end(), std::back_inserter( result ), boost::bind( &Subkey::parent, _1 ) );
385 
386  std::sort( result.begin(), result.end(), _detail::ByFingerprint<std::less>() );
387  result.erase( std::unique( result.begin(), result.end(), _detail::ByFingerprint<std::equal_to>() ), result.end() );
388  return result;
389 }
390 
391 std::vector<Key> KeyCache::findSigners( const VerificationResult & res ) const {
392  std::vector<std::string> fprs;
393  Q_FOREACH( const Signature & s, res.signatures() )
394  if ( const char * fpr = s.fingerprint() )
395  fprs.push_back( fpr );
396  return findByKeyIDOrFingerprint( fprs );
397 }
398 
399 std::vector<Key> KeyCache::findSigningKeysByMailbox( const Mailbox & mb ) const {
400  return d->find_mailbox( mb, true );
401 }
402 
403 std::vector<Key> KeyCache::findEncryptionKeysByMailbox( const Mailbox & mb ) const {
404  return d->find_mailbox( mb, false );
405 }
406 
407 namespace {
408 #define DO( op, meth, meth2 ) if ( op key.meth() ) {} else { qDebug( "rejecting for signing: %s: %s", #meth2, key.primaryFingerprint() ); return false; }
409 #define ACCEPT( meth ) DO( !!, meth, !meth )
410 #define REJECT( meth ) DO( !, meth, meth )
411  struct ready_for_signing : std::unary_function<Key,bool> {
412  bool operator()( const Key & key ) const {
413 #if 1
414  ACCEPT( hasSecret );
415  ACCEPT( canReallySign );
416  REJECT( isRevoked );
417  REJECT( isExpired );
418  REJECT( isDisabled );
419  REJECT( isInvalid );
420  return true;
421 #else
422  return key.hasSecret() &&
423  key.canReallySign() && !key.isRevoked() && !key.isExpired() && !key.isDisabled() && !key.isInvalid() ;
424 #endif
425 #undef DO
426  }
427  };
428 
429  struct ready_for_encryption : std::unary_function<Key,bool> {
430 #define DO( op, meth, meth2 ) if ( op key.meth() ) {} else { qDebug( "rejecting for encrypting: %s: %s", #meth2, key.primaryFingerprint() ); return false; }
431  bool operator()( const Key & key ) const {
432 #if 1
433  ACCEPT( canEncrypt );
434  REJECT( isRevoked );
435  REJECT( isExpired );
436  REJECT( isDisabled );
437  REJECT( isInvalid );
438  return true;
439 #else
440  return
441  key.canEncrypt() && !key.isRevoked() && !key.isExpired() && !key.isDisabled() && !key.isInvalid() ;
442 #endif
443  }
444 #undef DO
445 #undef ACCEPT
446 #undef REJECT
447  };
448 }
449 
450 std::vector<Key> KeyCache::Private::find_mailbox( const Mailbox & mb, bool sign ) const {
451  const QString email = mb.addrSpec().asString();
452  if ( email.isEmpty() )
453  return std::vector<Key>();
454 
455  const std::pair<
456  std::vector< std::pair<std::string,Key> >::const_iterator,
457  std::vector< std::pair<std::string,Key> >::const_iterator
458  > pair = find_email( email.toUtf8().constData() );
459 
460  std::vector<Key> result;
461  result.reserve( std::distance( pair.first, pair.second ) );
462  if ( sign )
463  kdtools::copy_2nd_if( pair.first, pair.second,
464  std::back_inserter( result ),
465  ready_for_signing() );
466  else
467  kdtools::copy_2nd_if( pair.first, pair.second,
468  std::back_inserter( result ),
469  ready_for_encryption() );
470  return result;
471 }
472 
473 std::vector<Key> KeyCache::findSubjects( const GpgME::Key & key, Options options ) const {
474  return findSubjects( std::vector<Key>( 1, key ), options );
475 }
476 
477 std::vector<Key> KeyCache::findSubjects( const std::vector<Key> & keys, Options options ) const {
478  return findSubjects( keys.begin(), keys.end(), options );
479 }
480 
481 std::vector<Key> KeyCache::findSubjects( std::vector<Key>::const_iterator first, std::vector<Key>::const_iterator last, Options options ) const {
482 
483  if ( first == last )
484  return std::vector<Key>();
485 
486  std::vector<Key> result;
487  while ( first != last ) {
488  const std::pair<
489  std::vector<Key>::const_iterator,
490  std::vector<Key>::const_iterator
491  > pair = d->find_subjects( first->primaryFingerprint() );
492  result.insert( result.end(), pair.first, pair.second );
493  ++first;
494  }
495 
496  std::sort( result.begin(), result.end(), _detail::ByFingerprint<std::less>() );
497  result.erase( std::unique( result.begin(), result.end(), _detail::ByFingerprint<std::equal_to>() ), result.end() );
498 
499  if ( options & RecursiveSearch ) {
500  const std::vector<Key> furtherSubjects = findSubjects( result, options );
501  std::vector<Key> combined;
502  combined.reserve( result.size() + furtherSubjects.size() );
503  std::merge( result.begin(), result.end(),
504  furtherSubjects.begin(), furtherSubjects.end(),
505  std::back_inserter( combined ),
506  _detail::ByFingerprint<std::less>() );
507  combined.erase( std::unique( combined.begin(), combined.end(), _detail::ByFingerprint<std::equal_to>() ), combined.end() );
508  result.swap( combined );
509  }
510 
511  return result;
512 }
513 
514 static const unsigned int LIKELY_CHAIN_DEPTH = 3;
515 
516 std::vector<Key> KeyCache::findIssuers( const Key & key, Options options ) const {
517 
518  if ( key.isNull() )
519  return std::vector<Key>();
520 
521  std::vector<Key> result;
522  if ( options & IncludeSubject )
523  result.push_back( key );
524 
525  if ( key.isRoot() )
526  return result;
527 
528  const Key & issuer = findByFingerprint( key.chainID() );
529 
530  if ( issuer.isNull() )
531  return result;
532 
533  result.push_back( issuer );
534 
535  if ( !( options & RecursiveSearch ) )
536  return result;
537 
538  while ( !result.back().isNull() && !result.back().isRoot() )
539  result.push_back( findByFingerprint( result.back().chainID() ) );
540 
541  if ( result.back().isNull() )
542  result.pop_back();
543 
544  return result;
545 }
546 
547 std::vector<Key> KeyCache::findIssuers( const std::vector<Key> & keys, Options options ) const {
548  return findIssuers( keys.begin(), keys.end(), options );
549 }
550 
551 std::vector<Key> KeyCache::findIssuers( std::vector<Key>::const_iterator first, std::vector<Key>::const_iterator last, Options options ) const {
552 
553  if ( first == last )
554  return std::vector<Key>();
555 
556  // extract chain-ids, identifying issuers:
557  std::vector<const char *> chainIDs;
558  chainIDs.reserve( last - first );
559  std::transform( boost::make_filter_iterator( !boost::bind( &Key::isRoot, _1 ), first, last ),
560  boost::make_filter_iterator( !boost::bind( &Key::isRoot, _1 ), last, last ),
561  std::back_inserter( chainIDs ),
562  boost::bind( &Key::chainID, _1 ) );
563  std::sort( chainIDs.begin(), chainIDs.end(), _detail::ByFingerprint<std::less>() );
564 
565  const std::vector<const char*>::iterator lastUniqueChainID = std::unique( chainIDs.begin(), chainIDs.end(), _detail::ByFingerprint<std::less>() );
566 
567  std::vector<Key> result;
568  result.reserve( lastUniqueChainID - chainIDs.begin() );
569 
570  kdtools::set_intersection( d->by.fpr.begin(), d->by.fpr.end(),
571  chainIDs.begin(), lastUniqueChainID,
572  std::back_inserter( result ),
573  _detail::ByFingerprint<std::less>() );
574 
575  if ( options & IncludeSubject ) {
576  const unsigned int rs = result.size();
577  result.insert( result.end(), first, last );
578  std::inplace_merge( result.begin(), result.begin() + rs, result.end(),
579  _detail::ByFingerprint<std::less>() );
580  }
581 
582  if ( !( options & RecursiveSearch ) )
583  return result;
584 
585  const std::vector<Key> l2result = findIssuers( result, options & ~IncludeSubject );
586 
587  const unsigned long result_size = result.size();
588  result.insert( result.end(), l2result.begin(), l2result.end() );
589  std::inplace_merge( result.begin(), result.begin() + result_size, result.end(),
590  _detail::ByFingerprint<std::less>() );
591  return result;
592 }
593 
594 static std::string email( const UserID & uid ) {
595  const std::string email = uid.email();
596  if ( email.empty() )
597  return DN( uid.id() )[QLatin1String("EMAIL")].trimmed().toUtf8().constData();
598  if ( email[0] == '<' && email[email.size()-1] == '>' )
599  return email.substr( 1, email.size() - 2 );
600  else
601  return email;
602 }
603 
604 static std::vector<std::string> emails( const Key & key ) {
605  std::vector<std::string> emails;
606  Q_FOREACH( const UserID & uid, key.userIDs() ) {
607  const std::string e = email( uid );
608  if ( !e.empty() )
609  emails.push_back( e );
610  }
611  std::sort( emails.begin(), emails.end(), ByEMail<std::less>() );
612  emails.erase( std::unique( emails.begin(), emails.end(), ByEMail<std::equal_to>() ), emails.end() );
613  return emails;
614 }
615 
616 void KeyCache::remove( const Key & key ) {
617  if ( key.isNull() )
618  return;
619 
620  const char * fpr = key.primaryFingerprint();
621  if ( !fpr )
622  return;
623 
624  emit aboutToRemove( key );
625 
626  {
627  const std::pair<std::vector<Key>::iterator,std::vector<Key>::iterator> range
628  = std::equal_range( d->by.fpr.begin(), d->by.fpr.end(), fpr,
629  _detail::ByFingerprint<std::less>() );
630  d->by.fpr.erase( range.first, range.second );
631  }
632 
633  if ( const char * keyid = key.keyID() ) {
634  const std::pair<std::vector<Key>::iterator,std::vector<Key>::iterator> range
635  = std::equal_range( d->by.keyid.begin(), d->by.keyid.end(), keyid,
636  _detail::ByKeyID<std::less>() );
637  const std::vector<Key>::iterator it
638  = std::remove_if( begin( range ), end( range ), boost::bind( _detail::ByFingerprint<std::equal_to>(), fpr, _1 ) );
639  d->by.keyid.erase( it, end( range ) );
640  }
641 
642  if ( const char * shortkeyid = key.shortKeyID() ) {
643  const std::pair<std::vector<Key>::iterator,std::vector<Key>::iterator> range
644  = std::equal_range( d->by.shortkeyid.begin(), d->by.shortkeyid.end(), shortkeyid,
645  _detail::ByShortKeyID<std::less>() );
646  const std::vector<Key>::iterator it
647  = std::remove_if( begin( range ), end( range ), boost::bind( _detail::ByFingerprint<std::equal_to>(), fpr, _1 ) );
648  d->by.shortkeyid.erase( it, end( range ) );
649  }
650 
651  if ( const char * chainid = key.chainID() ) {
652  const std::pair<std::vector<Key>::iterator,std::vector<Key>::iterator> range
653  = std::equal_range( d->by.chainid.begin(), d->by.chainid.end(), chainid,
654  _detail::ByChainID<std::less>() );
655  const std::pair< std::vector<Key>::iterator, std::vector<Key>::iterator > range2
656  = std::equal_range( begin( range ), end( range ), fpr, _detail::ByFingerprint<std::less>() );
657  d->by.chainid.erase( begin( range2 ), end( range2 ) );
658  }
659 
660 
661  Q_FOREACH( const std::string & email, emails( key ) ) {
662  const std::pair<std::vector<std::pair<std::string,Key> >::iterator,std::vector<std::pair<std::string,Key> >::iterator> range
663  = std::equal_range( d->by.email.begin(), d->by.email.end(), email, ByEMail<std::less>() );
664  const std::vector< std::pair<std::string,Key> >::iterator it
665  = std::remove_if( begin( range ), end( range ), boost::bind( qstricmp, fpr, boost::bind( &Key::primaryFingerprint, boost::bind( &std::pair<std::string,Key>::second,_1 ) ) ) == 0 );
666  d->by.email.erase( it, end( range ) );
667  }
668 
669  Q_FOREACH( const Subkey & subkey, key.subkeys() ) {
670  if ( const char * keyid = subkey.keyID() ) {
671  const std::pair<std::vector<Subkey>::iterator,std::vector<Subkey>::iterator> range
672  = std::equal_range( d->by.subkeyid.begin(), d->by.subkeyid.end(), keyid,
673  _detail::ByKeyID<std::less>() );
674  const std::pair< std::vector<Subkey>::iterator, std::vector<Subkey>::iterator > range2
675  = std::equal_range( begin( range ), end( range ), fpr, _detail::ByKeyID<std::less>() );
676  d->by.subkeyid.erase( begin( range2 ), end( range2 ) );
677  }
678  }
679 }
680 
681 void KeyCache::remove( const std::vector<Key> & keys ) {
682  Q_FOREACH( const Key & key, keys )
683  remove( key );
684 }
685 
686 const std::vector<GpgME::Key> & KeyCache::keys() const
687 {
688  return d->by.fpr;
689 }
690 
691 std::vector<Key> KeyCache::secretKeys() const
692 {
693  std::vector<Key> keys = this->keys();
694  keys.erase( std::remove_if( keys.begin(), keys.end(), !boost::bind( &Key::hasSecret, _1 ) ), keys.end() );
695  return keys;
696 }
697 
698 void KeyCache::refresh( const std::vector<Key> & keys ) {
699  // make this better...
700  clear();
701  insert( keys );
702 }
703 
704 void KeyCache::insert( const Key & key ) {
705  insert( std::vector<Key>( 1, key ) );
706 }
707 
708 namespace {
709 
710  template <
711  template <template <typename T> class Op> class T1,
712  template <template <typename T> class Op> class T2
713  > struct lexicographically {
714  typedef bool result_type;
715 
716  template <typename U, typename V>
717  bool operator()( const U & lhs, const V & rhs ) const {
718  return
719  T1<std::less>()( lhs, rhs ) ||
720  ( T1<std::equal_to>()( lhs, rhs ) &&
721  T2<std::less>()( lhs, rhs ) )
722  ;
723  }
724  };
725 
726 }
727 
728 void KeyCache::insert( const std::vector<Key> & keys ) {
729 
730  // 1. remove those with empty fingerprints:
731  std::vector<Key> sorted;
732  sorted.reserve( keys.size() );
733  std::remove_copy_if( keys.begin(), keys.end(),
734  std::back_inserter( sorted ),
735  boost::bind( is_string_empty(), boost::bind( &Key::primaryFingerprint, _1 ) ) );
736 
737  Q_FOREACH( const Key & key, sorted )
738  remove( key ); // this is sub-optimal, but makes implementation from here on much easier
739 
740  // 2. sort by fingerprint:
741  std::sort( sorted.begin(), sorted.end(), _detail::ByFingerprint<std::less>() );
742 
743  // 2a. insert into fpr index:
744  std::vector<Key> by_fpr;
745  by_fpr.reserve( sorted.size() + d->by.fpr.size() );
746  std::merge( sorted.begin(), sorted.end(),
747  d->by.fpr.begin(), d->by.fpr.end(),
748  std::back_inserter( by_fpr ),
749  _detail::ByFingerprint<std::less>() );
750 
751  // 3. build email index:
752  std::vector< std::pair<std::string,Key> > pairs;
753  pairs.reserve( sorted.size() );
754  Q_FOREACH( const Key & key, sorted ) {
755  const std::vector<std::string> emails = ::emails( key );
756  Q_FOREACH( const std::string & e, emails )
757  pairs.push_back( std::make_pair( e, key ) );
758  }
759  std::sort( pairs.begin(), pairs.end(), ByEMail<std::less>() );
760 
761  // 3a. insert into email index:
762  std::vector< std::pair<std::string,Key> > by_email;
763  by_email.reserve( pairs.size() + d->by.email.size() );
764  std::merge( pairs.begin(), pairs.end(),
765  d->by.email.begin(), d->by.email.end(),
766  std::back_inserter( by_email ),
767  ByEMail<std::less>() );
768 
769  // 3.5: stable-sort by chain-id (effectively lexicographically<ByChainID,ByFingerprint>)
770  std::stable_sort( sorted.begin(), sorted.end(), _detail::ByChainID<std::less>() );
771 
772  // 3.5a: insert into chain-id index:
773  std::vector<Key> by_chainid;
774  by_chainid.reserve( sorted.size() + d->by.chainid.size() );
775  std::merge( boost::make_filter_iterator( !boost::bind( &Key::isRoot, _1 ), sorted.begin(), sorted.end() ),
776  boost::make_filter_iterator( !boost::bind( &Key::isRoot, _1 ), sorted.end(), sorted.end() ),
777  d->by.chainid.begin(), d->by.chainid.end(),
778  std::back_inserter( by_chainid ),
779  lexicographically<_detail::ByChainID,_detail::ByFingerprint>() );
780 
781  // 4. sort by key id:
782  std::sort( sorted.begin(), sorted.end(), _detail::ByKeyID<std::less>() );
783 
784  // 4a. insert into keyid index:
785  std::vector<Key> by_keyid;
786  by_keyid.reserve( sorted.size() + d->by.keyid.size() );
787  std::merge( sorted.begin(), sorted.end(),
788  d->by.keyid.begin(), d->by.keyid.end(),
789  std::back_inserter( by_keyid ),
790  _detail::ByKeyID<std::less>() );
791 
792  // 5. sort by short key id:
793  std::sort( sorted.begin(), sorted.end(), _detail::ByShortKeyID<std::less>() );
794 
795  // 5a. insert into short keyid index:
796  std::vector<Key> by_shortkeyid;
797  by_shortkeyid.reserve( sorted.size() + d->by.shortkeyid.size() );
798  std::merge( sorted.begin(), sorted.end(),
799  d->by.shortkeyid.begin(), d->by.shortkeyid.end(),
800  std::back_inserter( by_shortkeyid ),
801  _detail::ByShortKeyID<std::less>() );
802 
803  // 6. build subkey ID index:
804  std::vector<Subkey> subkeys;
805  subkeys.reserve( sorted.size() );
806  Q_FOREACH( const Key & key, sorted )
807  Q_FOREACH( const Subkey & subkey, key.subkeys() )
808  subkeys.push_back( subkey );
809 
810  // 6a sort by key id:
811  std::sort( subkeys.begin(), subkeys.end(), _detail::ByKeyID<std::less>() );
812 
813  // 6b. insert into subkey ID index:
814  std::vector<Subkey> by_subkeyid;
815  by_email.reserve( subkeys.size() + d->by.subkeyid.size() );
816  std::merge( subkeys.begin(), subkeys.end(),
817  d->by.subkeyid.begin(), d->by.subkeyid.end(),
818  std::back_inserter( by_subkeyid ),
819  _detail::ByKeyID<std::less>() );
820 
821  // now commit (well, we already removed keys...)
822  by_fpr.swap( d->by.fpr );
823  by_keyid.swap( d->by.keyid );
824  by_shortkeyid.swap( d->by.shortkeyid );
825  by_email.swap( d->by.email );
826  by_subkeyid.swap( d->by.subkeyid );
827  by_chainid.swap( d->by.chainid );
828 
829  Q_FOREACH( const Key & key, sorted )
830  emit added( key );
831 
832  emit keysMayHaveChanged();
833 }
834 
835 void KeyCache::clear() {
836  d->by = Private::By();
837 }
838 
839 //
840 //
841 // RefreshKeysJob
842 //
843 //
844 
845 class KeyCache::RefreshKeysJob::Private
846 {
847  RefreshKeysJob * const q;
848 public:
849  Private( KeyCache * cache, RefreshKeysJob * qq );
850  void doStart();
851  Error startKeyListing( const char* protocol );
852  void listAllKeysJobDone( const KeyListResult & res, const std::vector<Key> & nextKeys ) {
853  std::vector<Key> keys;
854  keys.reserve( m_keys.size() + nextKeys.size() );
855  if ( m_keys.empty() )
856  keys = nextKeys;
857  else
858  std::merge( m_keys.begin(), m_keys.end(),
859  nextKeys.begin(), nextKeys.end(),
860  std::back_inserter( keys ),
861  _detail::ByFingerprint<std::less>() );
862  m_keys.swap( keys );
863  jobDone( res );
864  }
865  void emitDone( const KeyListResult & result );
866  void updateKeyCache();
867 
868  KeyCache * m_cache;
869  uint m_jobsPending;
870  std::vector<Key> m_keys;
871  KeyListResult m_mergedResult;
872 
873 private:
874  void jobDone( const KeyListResult & res );
875 };
876 
877 KeyCache::RefreshKeysJob::Private::Private( KeyCache * cache, RefreshKeysJob * qq ) : q( qq ), m_cache( cache ), m_jobsPending( 0 )
878 {
879  assert( m_cache );
880 }
881 
882 void KeyCache::RefreshKeysJob::Private::jobDone( const KeyListResult & result )
883 {
884  QObject* const sender = q->sender();
885  if ( sender )
886  sender->disconnect( q );
887  assert( m_jobsPending > 0 );
888  --m_jobsPending;
889  m_mergedResult.mergeWith( result );
890  if ( m_jobsPending > 0 )
891  return;
892  updateKeyCache();
893  emitDone( m_mergedResult );
894 }
895 
896 void KeyCache::RefreshKeysJob::Private::emitDone( const KeyListResult & res )
897 {
898  q->deleteLater();
899  emit q->done( res );
900 }
901 
902 KeyCache::RefreshKeysJob::RefreshKeysJob( KeyCache * cache, QObject * parent ) : QObject( parent ), d( new Private( cache, this ) )
903 {
904 }
905 
906 KeyCache::RefreshKeysJob::~RefreshKeysJob() {}
907 
908 
909 void KeyCache::RefreshKeysJob::start()
910 {
911  QTimer::singleShot( 0, this, SLOT(doStart()) );
912 }
913 
914 void KeyCache::RefreshKeysJob::cancel()
915 {
916  emit canceled();
917 }
918 
919 void KeyCache::RefreshKeysJob::Private::doStart()
920 {
921  assert( m_jobsPending == 0 );
922  m_mergedResult.mergeWith( KeyListResult( startKeyListing( "openpgp" ) ) );
923  m_mergedResult.mergeWith( KeyListResult( startKeyListing( "smime" ) ) );
924 
925  if ( m_jobsPending != 0 )
926  return;
927 
928  const bool hasError = m_mergedResult.error() || m_mergedResult.error().isCanceled();
929  emitDone( hasError ? m_mergedResult : KeyListResult( Error( GPG_ERR_UNSUPPORTED_OPERATION ) ) );
930 }
931 
932 void KeyCache::RefreshKeysJob::Private::updateKeyCache()
933 {
934  std::vector<Key> cachedKeys = m_cache->keys();
935  std::sort( cachedKeys.begin(), cachedKeys.end(), _detail::ByFingerprint<std::less>() );
936  std::vector<Key> keysToRemove;
937  std::set_difference( cachedKeys.begin(), cachedKeys.end(),
938  m_keys.begin(), m_keys.end(),
939  std::back_inserter( keysToRemove ),
940  _detail::ByFingerprint<std::less>() );
941  m_cache->remove( keysToRemove );
942  m_cache->refresh( m_keys );
943 }
944 
945 Error KeyCache::RefreshKeysJob::Private::startKeyListing( const char* backend )
946 {
947  const Kleo::CryptoBackend::Protocol * const protocol = Kleo::CryptoBackendFactory::instance()->protocol( backend );
948  if ( !protocol )
949  return Error();
950  Kleo::ListAllKeysJob * const job = protocol->listAllKeysJob( /*includeSigs*/false, /*validate*/true );
951  if ( !job )
952  return Error();
953  connect( job, SIGNAL(result(GpgME::KeyListResult,std::vector<GpgME::Key>)),
954  q, SLOT(listAllKeysJobDone(GpgME::KeyListResult,std::vector<GpgME::Key>)) );
955 
956  const QString label = protocol == Kleo::CryptoBackendFactory::instance()->smime()
957  ? i18n("Listing X.509 certificates")
958  : i18n("Listing OpenPGP certificates") ;
959  (void)ProgressManager::createForJob( job, label );
960 
961  connect( q, SIGNAL(canceled()),
962  job, SLOT(slotCancel()) );
963 
964  const Error error = job->start( true );
965 
966  if ( !error && !error.isCanceled() )
967  ++m_jobsPending;
968  return error;
969 }
970 
971 #include "moc_keycache_p.cpp"
972 #include "moc_keycache.cpp"
973 
Kleo::KeyCache::findSigners
std::vector< GpgME::Key > findSigners(const GpgME::VerificationResult &result) const
Definition: keycache.cpp:391
hours2ms
static const unsigned int hours2ms
Definition: keycache.cpp:84
LIKELY_CHAIN_DEPTH
static const unsigned int LIKELY_CHAIN_DEPTH
Definition: keycache.cpp:514
Kleo::KeyCache
Definition: keycache.h:67
Kleo::KeyCache::insert
void insert(const GpgME::Key &key)
Kleo::KeyCache::addFileSystemWatcher
void addFileSystemWatcher(const boost::shared_ptr< FileSystemWatcher > &watcher)
Definition: keycache.cpp:239
email
static std::string email(const UserID &uid)
Definition: keycache.cpp:594
Kleo::KeyCache::RefreshKeysJob::start
void start()
Definition: keycache.cpp:909
Kleo::KeyCache::findByKeyIDOrFingerprint
const GpgME::Key & findByKeyIDOrFingerprint(const char *id) const
Definition: keycache.cpp:309
Kleo::KeyCache::RefreshKeysJob::Private
friend class Private
Definition: keycache_p.h:60
Kleo::KeyCache::added
void added(const GpgME::Key &key)
QPointer
Kleo::KeyCache::findIssuers
std::vector< GpgME::Key > findIssuers(const GpgME::Key &key, Options options=RecursiveSearch) const
make_comparator_str
#define make_comparator_str(Name, expr)
Definition: predicates.h:101
Kleo::KeyCache::cancelKeyListing
void cancelKeyListing()
Definition: keycache.cpp:232
Kleo::KeyCache::refresh
void refresh(const std::vector< GpgME::Key > &keys)
Definition: keycache.cpp:698
emails
static std::vector< std::string > emails(const Key &key)
Definition: keycache.cpp:604
QObject::disconnect
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
Kleo::KeyCache::findSubjects
std::vector< GpgME::Key > findSubjects(const GpgME::Key &key, Options option=RecursiveSearch) const
Definition: keycache.cpp:473
Kleo::KeyCache::RecursiveSearch
Definition: keycache.h:123
Kleo::KeyCache::startKeyListing
void startKeyListing(GpgME::Protocol proto=GpgME::UnknownProtocol)
Definition: keycache.h:138
Kleo::KeyCache::RefreshKeysJob::cancel
void cancel()
Definition: keycache.cpp:914
boost::shared_ptr
Definition: encryptemailcontroller.h:51
Kleo::KeyCache::RefreshKeysJob
Definition: keycache_p.h:45
REJECT
#define REJECT(meth)
Definition: keycache.cpp:410
d
#define d
Definition: adduseridcommand.cpp:89
keycache_p.h
QTimer
Kleo::KeyCache::KeyCache
KeyCache()
Definition: keycache.cpp:205
QObject
QString::isEmpty
bool isEmpty() const
progressmanager.h
QString::trimmed
QString trimmed() const
QByteArray::constData
const char * constData() const
Kleo::KeyCache::findSigningKeysByMailbox
std::vector< GpgME::Key > findSigningKeysByMailbox(const KMime::Types::Mailbox &mb) const
Definition: keycache.cpp:399
Kleo::KeyCache::findRecipients
std::vector< GpgME::Key > findRecipients(const GpgME::DecryptionResult &result) const
Definition: keycache.cpp:376
Kleo::KeyCache::secretKeys
std::vector< GpgME::Key > secretKeys() const
Definition: keycache.cpp:691
Kleo::KeyCache::RefreshKeysJob::RefreshKeysJob
RefreshKeysJob(KeyCache *cache, QObject *parent=0)
Definition: keycache.cpp:902
QString
Kleo::KeyCache::findByEMailAddress
std::vector< GpgME::Key > findByEMailAddress(const char *email) const
Definition: keycache.cpp:284
Kleo::KeyCache::findByFingerprint
const GpgME::Key & findByFingerprint(const char *fpr) const
Definition: keycache.cpp:258
Kleo::KeyCache::IncludeSubject
Definition: keycache.h:124
Kleo::KeyCache::findByShortKeyID
const GpgME::Key & findByShortKeyID(const char *id) const
Definition: keycache.cpp:301
Kleo::KeyCache::clear
void clear()
Definition: keycache.cpp:835
string
const char * string
Definition: verifychecksumscontroller.cpp:510
Kleo::KeyCache::~KeyCache
~KeyCache()
Definition: keycache.cpp:211
Kleo::KeyCache::RefreshKeysJob::~RefreshKeysJob
~RefreshKeysJob()
Definition: keycache.cpp:906
Kleo::KeyCache::remove
void remove(const GpgME::Key &key)
filesystemwatcher.h
QLatin1String
Kleo::KeyCache::aboutToRemove
void aboutToRemove(const GpgME::Key &key)
predicates.h
self
static ReaderStatus * self
Definition: readerstatus.cpp:86
q
#define q
Definition: adduseridcommand.cpp:90
Kleo::KeyCache::enableFileSystemWatcher
void enableFileSystemWatcher(bool enable)
Definition: keycache.cpp:213
Kleo::KeyCache::reload
void reload(GpgME::Protocol proto=GpgME::UnknownProtocol)
Definition: keycache.cpp:219
Kleo::KeyCache::instance
static boost::shared_ptr< const KeyCache > instance()
Definition: keycache.cpp:190
QString::reserve
void reserve(int size)
Kleo::KeyCache::keysMayHaveChanged
void keysMayHaveChanged()
Kleo::KeyCache::findEncryptionKeysByMailbox
std::vector< GpgME::Key > findEncryptionKeysByMailbox(const KMime::Types::Mailbox &mb) const
Definition: keycache.cpp:403
Kleo::KeyCache::keys
const std::vector< GpgME::Key > & keys() const
Definition: keycache.cpp:686
keycache.h
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
ACCEPT
#define ACCEPT(meth)
Definition: keycache.cpp:409
Kleo::ProgressManager::createForJob
KPIM::ProgressItem * createForJob(Kleo::Job *job, const QString &label)
Kleo::KeyCache::findSubkeysByKeyID
std::vector< GpgME::Subkey > findSubkeysByKeyID(const std::vector< std::string > &ids) const
Definition: keycache.cpp:360
Kleo::KeyCache::mutableInstance
static boost::shared_ptr< KeyCache > mutableInstance()
Definition: keycache.cpp:194
QTimer::singleShot
singleShot
QString::toUtf8
QByteArray toUtf8() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:33:11 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kleopatra

Skip menu "kleopatra"
  • 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