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

kleopatra

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

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