33 #include <config-kleopatra.h> 
   40 #include "smimevalidationpreferences.h" 
   45 #include <kleo/stl_util.h> 
   46 #include <kleo/cryptobackendfactory.h> 
   48 #include <kleo/keylistjob.h> 
   49 #include <kleo/listallkeysjob.h> 
   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> 
   57 #include <gpg-error.h> 
   59 #include <kmime/kmime_header_parsing.h> 
   61 #include <KLocalizedString> 
   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> 
   80 using namespace GpgME;
 
   81 using namespace boost;
 
   82 using namespace KMime::Types;
 
   84 static const unsigned int hours2ms = 1000 * 60 * 60;
 
   96     struct is_string_empty : std::unary_function<const char*,bool> {
 
   97         bool operator()( 
const char * s )
 const { 
return !s || !*s; }
 
  102 class KeyCache::Private {
 
  103     friend class ::Kleo::KeyCache;
 
  106     explicit Private( 
KeyCache * qq ) : 
q( qq ) {
 
  107         connect( &m_autoKeyListingTimer, SIGNAL(timeout()), 
q, SLOT(startKeyListing()) );
 
  108         updateAutoKeyListingTimer();
 
  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 ) )
 
  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 ) )
 
  131     std::vector<Key>::const_iterator find_fpr( 
const char * fpr )
 const {
 
  132         return find<_detail::ByFingerprint>( by.fpr, fpr );
 
  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>() );
 
  142     std::vector<Key> find_mailbox( 
const Mailbox & mb, 
bool sign ) 
const;
 
  144     std::vector<Subkey>::const_iterator find_subkeyid( 
const char * subkeyid )
 const {
 
  145         return find<_detail::ByKeyID>( by.subkeyid, subkeyid );
 
  148     std::vector<Key>::const_iterator find_keyid( 
const char * keyid )
 const {
 
  149         return find<_detail::ByKeyID>( by.keyid, keyid );
 
  152     std::vector<Key>::const_iterator find_shortkeyid( 
const char * shortkeyid )
 const {
 
  153         return find<_detail::ByShortKeyID>( by.shortkeyid, shortkeyid );
 
  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>() );
 
  164     void refreshJobDone( 
const KeyListResult & result );
 
  167     void updateAutoKeyListingTimer() {
 
  168         setAutoKeyListingInterval( 
hours2ms * SMimeValidationPreferences().refreshInterval() );
 
  170     void setAutoKeyListingInterval( 
int ms ) {
 
  171         m_autoKeyListingTimer.stop();
 
  172         m_autoKeyListingTimer.setInterval( ms );
 
  174             m_autoKeyListingTimer.start();
 
  179     std::vector<shared_ptr<FileSystemWatcher> > m_fsWatchers;
 
  180     QTimer m_autoKeyListingTimer;
 
  183         std::vector<Key> fpr, keyid, shortkeyid, chainid;
 
  184         std::vector< std::pair<std::string,Key> > 
email;
 
  185         std::vector<Subkey> subkeyid;
 
  191     return mutableInstance();
 
  195     static weak_ptr<KeyCache> 
self;
 
  198     } 
catch ( 
const bad_weak_ptr & ) {
 
  206     : 
QObject(), 
d( new Private( this ) )
 
  216         i->setEnabled( enable );
 
  221     if ( d->m_refreshJob )
 
  224     d->updateAutoKeyListingTimer();
 
  228     connect( d->m_refreshJob, SIGNAL(done(GpgME::KeyListResult)), 
this, SLOT(refreshJobDone(GpgME::KeyListResult)) );
 
  229     d->m_refreshJob->start();
 
  234     if ( !d->m_refreshJob )
 
  236     d->m_refreshJob->cancel();
 
  243     d->m_fsWatchers.push_back( watcher );
 
  249     watcher->setEnabled( d->m_refreshJob == 0 );
 
  252 void KeyCache::Private::refreshJobDone( 
const KeyListResult& result )
 
  254     emit 
q->keyListingDone( result );
 
  255     q->enableFileSystemWatcher( 
true );
 
  259     const std::vector<Key>::const_iterator it = d->find_fpr( fpr );
 
  260     if ( it == d->by.fpr.end() ) {
 
  261         static const Key null;
 
  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 ) ) );
 
  274     std::sort( sorted.begin(), sorted.end(), _detail::ByFingerprint<std::less>() );
 
  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>() );
 
  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 ) );
 
  302     const std::vector<Key>::const_iterator it = d->find_shortkeyid( 
id );
 
  303     if ( it != d->by.shortkeyid.end() )
 
  305     static const Key null;
 
  312         const std::vector<Key>::const_iterator it = d->find_fpr( 
id );
 
  313         if ( it != d->by.fpr.end() )
 
  317         const std::vector<Key>::const_iterator it = d->find_keyid( 
id );
 
  318         if ( it != d->by.keyid.end() )
 
  321     static const Key null;
 
  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 ) ) );
 
  332     std::sort( keyids.begin(), keyids.end(), _detail::ByFingerprint<std::less>() );
 
  334     std::vector<Key> result;
 
  335     result.reserve( keyids.size() ); 
 
  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() ) {
 
  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>() );
 
  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() );
 
  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 ) ) );
 
  366     std::sort( sorted.begin(), sorted.end(), _detail::ByKeyID<std::less>() );
 
  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>() );
 
  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 );
 
  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 ) );
 
  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() );
 
  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 );
 
  400     return d->find_mailbox( mb, 
true );
 
  404     return d->find_mailbox( mb, 
false );
 
  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 {
 
  422             return key.hasSecret() &&
 
  423                 key.canReallySign() && !key.isRevoked() && !key.isExpired() && !key.isDisabled() && !key.isInvalid() ;
 
  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 {
 
  441                 key.canEncrypt()    && !key.isRevoked() && !key.isExpired() && !key.isDisabled() && !key.isInvalid() ;
 
  450 std::vector<Key> KeyCache::Private::find_mailbox( 
const Mailbox & mb, 
bool sign )
 const {
 
  451     const QString email = mb.addrSpec().asString();
 
  453         return std::vector<Key>();
 
  456         std::vector< std::pair<std::string,Key> >::const_iterator,
 
  457         std::vector< std::pair<std::string,Key> >::const_iterator
 
  460     std::vector<Key> result;
 
  461     result.
reserve( std::distance( pair.first, pair.second ) );
 
  463         kdtools::copy_2nd_if( pair.first, pair.second,
 
  464                               std::back_inserter( result ),
 
  465                               ready_for_signing() );
 
  467         kdtools::copy_2nd_if( pair.first, pair.second,
 
  468                               std::back_inserter( result ),
 
  469                               ready_for_encryption() );
 
  474     return findSubjects( std::vector<Key>( 1, key ), options );
 
  478     return findSubjects( keys.begin(), keys.end(), options );
 
  481 std::vector<Key> 
KeyCache::findSubjects( std::vector<Key>::const_iterator first, std::vector<Key>::const_iterator last, Options options )
 const {
 
  484         return std::vector<Key>();
 
  486     std::vector<Key> result;
 
  487     while ( first != last ) {
 
  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 );
 
  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() );
 
  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 );
 
  519         return std::vector<Key>();
 
  521     std::vector<Key> result;
 
  523         result.push_back( key );
 
  530     if ( issuer.isNull() )
 
  533     result.push_back( issuer );
 
  535     if ( !( options & RecursiveSearch ) )
 
  538     while ( !result.back().isNull() && !result.back().isRoot() )
 
  541     if ( result.back().isNull() )
 
  548     return findIssuers( keys.begin(), keys.end(), options );
 
  551 std::vector<Key> 
KeyCache::findIssuers( std::vector<Key>::const_iterator first, std::vector<Key>::const_iterator last, Options options )
 const {
 
  554         return std::vector<Key>();
 
  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>() );
 
  565     const std::vector<const char*>::iterator lastUniqueChainID = std::unique( chainIDs.begin(), chainIDs.end(), _detail::ByFingerprint<std::less>() );
 
  567     std::vector<Key> result;
 
  568     result.reserve( lastUniqueChainID - chainIDs.begin() );
 
  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>() );
 
  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>() );
 
  582     if ( !( options & RecursiveSearch ) )
 
  585     const std::vector<Key> l2result = 
findIssuers( result, options & ~IncludeSubject );
 
  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>() );
 
  598     if ( email[0] == 
'<' && email[email.size()-1] == 
'>' )
 
  599         return email.substr( 1, email.size() - 2 );
 
  604 static std::vector<std::string> 
emails( 
const Key & key ) {
 
  605     std::vector<std::string> 
emails;
 
  606     Q_FOREACH( 
const UserID & uid, key.userIDs() ) {
 
  609             emails.push_back( e );
 
  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() );
 
  620     const char * fpr = key.primaryFingerprint();
 
  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 );
 
  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 ) );
 
  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 ) );
 
  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 ) );
 
  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 ) );
 
  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 ) );
 
  682     Q_FOREACH( 
const Key & key, keys )
 
  686 const std::vector<GpgME::Key> & 
KeyCache::keys()
 const 
  693     std::vector<Key> keys = this->
keys();
 
  694     keys.erase( std::remove_if( keys.begin(), keys.end(), !boost::bind( &Key::hasSecret, _1 ) ), keys.end() );
 
  705     insert( std::vector<Key>( 1, key ) );
 
  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;
 
  716         template <
typename U, 
typename V>
 
  717         bool operator()( 
const U & lhs, 
const V & rhs )
 const {
 
  719                 T1<std::less>()( lhs, rhs ) ||
 
  720                 ( T1<std::equal_to>()( lhs, rhs ) &&
 
  721                 T2<std::less>()( lhs, rhs ) )
 
  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 ) ) );
 
  737     Q_FOREACH( 
const Key & key, sorted )
 
  741     std::sort( sorted.begin(), sorted.end(), _detail::ByFingerprint<std::less>() );
 
  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>() );
 
  752     std::vector< std::pair<std::
string,Key> > pairs;
 
  753     pairs.reserve( sorted.size() );
 
  754     Q_FOREACH( const Key & key, sorted ) {
 
  757             pairs.push_back( std::make_pair( e, key ) );
 
  759     std::sort( pairs.begin(), pairs.end(), ByEMail<std::less>() );
 
  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>() );
 
  770     std::stable_sort( sorted.begin(), sorted.end(), _detail::ByChainID<std::less>() );
 
  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>() );
 
  782     std::sort( sorted.begin(), sorted.end(), _detail::ByKeyID<std::less>() );
 
  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>() );
 
  793     std::sort( sorted.begin(), sorted.end(), _detail::ByShortKeyID<std::less>() );
 
  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>() );
 
  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 );
 
  811     std::sort( subkeys.begin(), subkeys.end(), _detail::ByKeyID<std::less>() );
 
  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>() );
 
  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 );
 
  829     Q_FOREACH( const Key & key, sorted )
 
  836     d->by = Private::By();
 
  847     RefreshKeysJob * 
const q;
 
  849     Private( 
KeyCache * cache, RefreshKeysJob * qq );
 
  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() )
 
  858             std::merge( m_keys.begin(), m_keys.end(),
 
  859                         nextKeys.begin(), nextKeys.end(),
 
  860                         std::back_inserter( keys ),
 
  861                         _detail::ByFingerprint<std::less>() );
 
  865     void emitDone( 
const KeyListResult & result );
 
  866     void updateKeyCache();
 
  870     std::vector<Key> m_keys;
 
  871     KeyListResult m_mergedResult;
 
  874     void jobDone( 
const KeyListResult & res );
 
  877 KeyCache::RefreshKeysJob::Private::Private( 
KeyCache * cache, RefreshKeysJob * qq ) : 
q( qq ), m_cache( cache ), m_jobsPending( 0 )
 
  882 void KeyCache::RefreshKeysJob::Private::jobDone( 
const KeyListResult & result )
 
  884     QObject* 
const sender = 
q->sender();
 
  887     assert( m_jobsPending > 0 );
 
  889     m_mergedResult.mergeWith( result );
 
  890     if ( m_jobsPending > 0 )
 
  893     emitDone( m_mergedResult );
 
  896 void KeyCache::RefreshKeysJob::Private::emitDone( 
const KeyListResult & res )
 
  919 void KeyCache::RefreshKeysJob::Private::doStart()
 
  921     assert( m_jobsPending == 0 );
 
  922     m_mergedResult.mergeWith( KeyListResult( 
startKeyListing( 
"openpgp" ) ) );
 
  923     m_mergedResult.mergeWith( KeyListResult( 
startKeyListing( 
"smime" ) ) );
 
  925     if ( m_jobsPending != 0 )
 
  928     const bool hasError = m_mergedResult.error() || m_mergedResult.error().isCanceled();
 
  929     emitDone( hasError ? m_mergedResult : KeyListResult( Error( GPG_ERR_UNSUPPORTED_OPERATION ) ) );
 
  932 void KeyCache::RefreshKeysJob::Private::updateKeyCache()
 
  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 );
 
  945 Error KeyCache::RefreshKeysJob::Private::startKeyListing( 
const char* backend )
 
  947     const Kleo::CryptoBackend::Protocol * 
const protocol = Kleo::CryptoBackendFactory::instance()->protocol( backend );
 
  950     Kleo::ListAllKeysJob * 
const job = protocol->listAllKeysJob( 
false, 
true );
 
  953     connect( job, SIGNAL(result(GpgME::KeyListResult,std::vector<GpgME::Key>)),
 
  954              q, SLOT(listAllKeysJobDone(GpgME::KeyListResult,std::vector<GpgME::Key>)) );
 
  956     const QString label = protocol == Kleo::CryptoBackendFactory::instance()->smime()
 
  957         ? i18n(
"Listing X.509 certificates")
 
  958         : i18n(
"Listing OpenPGP certificates") ;
 
  962              job, SLOT(slotCancel()) );
 
  964     const Error error = job->start( 
true );
 
  966     if ( !error && !error.isCanceled() )
 
  971 #include "moc_keycache_p.cpp" 
  972 #include "moc_keycache.cpp" 
std::vector< GpgME::Key > findSigners(const GpgME::VerificationResult &result) const 
static const unsigned int hours2ms
static const unsigned int LIKELY_CHAIN_DEPTH
void insert(const GpgME::Key &key)
void addFileSystemWatcher(const boost::shared_ptr< FileSystemWatcher > &watcher)
static std::string email(const UserID &uid)
const GpgME::Key & findByKeyIDOrFingerprint(const char *id) const 
void added(const GpgME::Key &key)
std::vector< GpgME::Key > findIssuers(const GpgME::Key &key, Options options=RecursiveSearch) const 
#define make_comparator_str(Name, expr)
void refresh(const std::vector< GpgME::Key > &keys)
static std::vector< std::string > emails(const Key &key)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
std::vector< GpgME::Key > findSubjects(const GpgME::Key &key, Options option=RecursiveSearch) const 
void startKeyListing(GpgME::Protocol proto=GpgME::UnknownProtocol)
const char * constData() const
std::vector< GpgME::Key > findSigningKeysByMailbox(const KMime::Types::Mailbox &mb) const 
std::vector< GpgME::Key > findRecipients(const GpgME::DecryptionResult &result) const 
std::vector< GpgME::Key > secretKeys() const 
RefreshKeysJob(KeyCache *cache, QObject *parent=0)
std::vector< GpgME::Key > findByEMailAddress(const char *email) const 
const GpgME::Key & findByFingerprint(const char *fpr) const 
const GpgME::Key & findByShortKeyID(const char *id) const 
void remove(const GpgME::Key &key)
void aboutToRemove(const GpgME::Key &key)
static ReaderStatus * self
void enableFileSystemWatcher(bool enable)
void reload(GpgME::Protocol proto=GpgME::UnknownProtocol)
static boost::shared_ptr< const KeyCache > instance()
void keysMayHaveChanged()
std::vector< GpgME::Key > findEncryptionKeysByMailbox(const KMime::Types::Mailbox &mb) const 
const std::vector< GpgME::Key > & keys() const 
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KPIM::ProgressItem * createForJob(Kleo::Job *job, const QString &label)
std::vector< GpgME::Subkey > findSubkeysByKeyID(const std::vector< std::string > &ids) const 
static boost::shared_ptr< KeyCache > mutableInstance()
QByteArray toUtf8() const