kmail

keyresolver.cpp

00001 /*  -*- c++ -*-
00002     keyresolver.cpp
00003 
00004     This file is part of libkleopatra, the KDE keymanagement library
00005     Copyright (c) 2004 Klarälvdalens Datakonsult AB
00006 
00007     Based on kpgp.cpp
00008     Copyright (C) 2001,2002 the KPGP authors
00009     See file libkdenetwork/AUTHORS.kpgp for details
00010 
00011     Libkleopatra is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU General Public License as
00013     published by the Free Software Foundation; either version 2 of the
00014     License, or (at your option) any later version.
00015 
00016     Libkleopatra is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019     General Public License for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with this program; if not, write to the Free Software
00023     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00024 
00025     In addition, as a special exception, the copyright holders give
00026     permission to link the code of this program with any edition of
00027     the Qt library by Trolltech AS, Norway (or with modified versions
00028     of Qt that use the same license as Qt), and distribute linked
00029     combinations including the two.  You must obey the GNU General
00030     Public License in all respects for all of the code used other than
00031     Qt.  If you modify this file, you may extend this exception to
00032     your version of the file, but you are not obligated to do so.  If
00033     you do not wish to do so, delete this exception statement from
00034     your version.
00035 */
00036 
00037 #ifdef HAVE_CONFIG_H
00038 #include <config.h>
00039 #endif
00040 
00041 #include "keyresolver.h"
00042 
00043 #include "kcursorsaver.h"
00044 #include "kleo_util.h"
00045 #include "stl_util.h"
00046 
00047 #include <libemailfunctions/email.h>
00048 #include <ui/keyselectiondialog.h>
00049 #include <kleo/cryptobackendfactory.h>
00050 #include <kleo/keylistjob.h>
00051 #include <kleo/dn.h>
00052 
00053 #include <gpgmepp/key.h>
00054 #include <gpgmepp/keylistresult.h>
00055 
00056 #include <kabc/stdaddressbook.h>
00057 #include <klocale.h>
00058 #include <kdebug.h>
00059 #include <kinputdialog.h>
00060 #include <kmessagebox.h>
00061 
00062 #include <tqstringlist.h>
00063 #include <tqtl.h>
00064 
00065 #include <time.h>
00066 
00067 #include <algorithm>
00068 #include <memory>
00069 #include <iterator>
00070 #include <functional>
00071 #include <map>
00072 #include <set>
00073 #include <iostream>
00074 #include <cassert>
00075 
00076 
00077 //
00078 // some predicates to be used in STL algorithms:
00079 //
00080 
00081 static inline bool EmptyKeyList( const Kleo::KeyApprovalDialog::Item & item ) {
00082   return item.keys.empty();
00083 }
00084 
00085 static inline TQString ItemDotAddress( const Kleo::KeyResolver::Item & item ) {
00086   return item.address;
00087 }
00088 
00089 static inline bool ApprovalNeeded( const Kleo::KeyResolver::Item & item ) {
00090   return item.pref == Kleo::UnknownPreference || item.pref == Kleo::NeverEncrypt || item.keys.empty() ;
00091 }
00092 
00093 static inline Kleo::KeyResolver::Item
00094 CopyKeysAndEncryptionPreferences( const Kleo::KeyResolver::Item & oldItem,
00095                   const Kleo::KeyApprovalDialog::Item & newItem ) {
00096   return Kleo::KeyResolver::Item( oldItem.address, newItem.keys, newItem.pref, oldItem.signPref, oldItem.format );
00097 }
00098 
00099 static inline bool ByKeyID( const GpgME::Key & left, const GpgME::Key & right ) {
00100   return qstrcmp( left.keyID(), right.keyID() ) < 0 ;
00101 }
00102 
00103 static inline bool WithRespectToKeyID( const GpgME::Key & left, const GpgME::Key & right ) {
00104   return qstrcmp( left.keyID(), right.keyID() ) == 0 ;
00105 }
00106 
00107 static bool ValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
00108   if ( key.protocol() != GpgME::Context::OpenPGP ) {
00109     return false;
00110   }
00111 #if 0
00112   if ( key.isRevoked() )
00113     kdWarning() << " is revoked" << endl;
00114   if ( key.isExpired() )
00115     kdWarning() << " is expired" << endl;
00116   if ( key.isDisabled() )
00117     kdWarning() << " is disabled" << endl;
00118   if ( !key.canEncrypt() )
00119     kdWarning() << " can't encrypt" << endl;
00120 #endif
00121   if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
00122     return false;
00123   return true;
00124 }
00125 
00126 static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
00127     if ( !ValidOpenPGPEncryptionKey( key ) )
00128         return false;
00129   const std::vector<GpgME::UserID> uids = key.userIDs();
00130   for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
00131     if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal )
00132       return true;
00133 #if 0
00134     else
00135       if ( it->isRevoked() )
00136         kdWarning() << "a userid is revoked" << endl;
00137       else
00138         kdWarning() << "bad validity " << it->validity() << endl;
00139 #endif
00140   }
00141   return false;
00142 }
00143 
00144 static bool ValidSMIMEEncryptionKey( const GpgME::Key & key ) {
00145   if ( key.protocol() != GpgME::Context::CMS )
00146     return false;
00147   if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
00148     return false;
00149   return true;
00150 }
00151 
00152 static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
00153   if ( !ValidSMIMEEncryptionKey( key ) )
00154     return false;
00155   return true;
00156 }
00157 
00158 static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
00159   switch ( key.protocol() ) {
00160   case GpgME::Context::OpenPGP:
00161     return ValidTrustedOpenPGPEncryptionKey( key );
00162   case GpgME::Context::CMS:
00163     return ValidTrustedSMIMEEncryptionKey( key );
00164   default:
00165     return false;
00166   }
00167 }
00168 
00169 static inline bool ValidEncryptionKey( const GpgME::Key & key ) {
00170     switch ( key.protocol() ) {
00171     case GpgME::Context::OpenPGP:
00172         return ValidOpenPGPEncryptionKey( key );
00173     case GpgME::Context::CMS:
00174         return ValidSMIMEEncryptionKey( key );
00175     default:
00176         return false;
00177     }
00178 }
00179 
00180 static inline bool ValidSigningKey( const GpgME::Key & key ) {
00181   if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign() )
00182     return false;
00183   return key.hasSecret();
00184 }
00185 
00186 static inline bool ValidOpenPGPSigningKey( const GpgME::Key & key ) {
00187   return key.protocol() == GpgME::Context::OpenPGP && ValidSigningKey( key );
00188 }
00189 
00190 static inline bool ValidSMIMESigningKey( const GpgME::Key & key ) {
00191   return key.protocol() == GpgME::Context::CMS && ValidSigningKey( key );
00192 }
00193 
00194 static inline bool NotValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
00195   return !ValidTrustedOpenPGPEncryptionKey( key );
00196 }
00197 
00198 static inline bool NotValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
00199   return !ValidOpenPGPEncryptionKey( key );
00200 }
00201 
00202 static inline bool NotValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
00203   return !ValidTrustedSMIMEEncryptionKey( key );
00204 }
00205 
00206 static inline bool NotValidSMIMEEncryptionKey( const GpgME::Key & key ) {
00207   return !ValidSMIMEEncryptionKey( key );
00208 }
00209 
00210 static inline bool NotValidTrustedEncryptionKey( const GpgME::Key & key ) {
00211   return !ValidTrustedEncryptionKey( key );
00212 }
00213 
00214 static inline bool NotValidEncryptionKey( const GpgME::Key & key ) {
00215   return !ValidEncryptionKey( key );
00216 }
00217 
00218 static inline bool NotValidSigningKey( const GpgME::Key & key ) {
00219   return !ValidSigningKey( key );
00220 }
00221 
00222 static inline bool NotValidOpenPGPSigningKey( const GpgME::Key & key ) {
00223   return !ValidOpenPGPSigningKey( key );
00224 }
00225 
00226 static inline bool NotValidSMIMESigningKey( const GpgME::Key & key ) {
00227   return !ValidSMIMESigningKey( key );
00228 }
00229 
00230 namespace {
00231     struct ByTrustScore {
00232         static int score( const GpgME::UserID & uid ) {
00233             return uid.isRevoked() || uid.isInvalid() ? -1 : uid.validity() ;
00234         }
00235         bool operator()( const GpgME::UserID & lhs, const GpgME::UserID & rhs ) const {
00236             return score( lhs ) < score( rhs ) ;
00237         }
00238     };
00239 }
00240 
00241 static std::vector<GpgME::UserID> matchingUIDs( const std::vector<GpgME::UserID> & uids, const TQString & address ) {
00242     if ( address.isEmpty() )
00243         return std::vector<GpgME::UserID>();
00244 
00245     std::vector<GpgME::UserID> result;
00246     result.reserve( uids.size() );
00247     for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin(), end = uids.end() ; it != end ; ++it )
00248         // PENDING(marc) check DN for an EMAIL, too, in case of X.509 certs... :/
00249         if ( const char * email = it->email() )
00250             if ( *email && TQString::fromUtf8( email ).stripWhiteSpace().lower() == address )
00251                 result.push_back( *it );
00252     return result;
00253 }
00254 
00255 static GpgME::UserID findBestMatchUID( const GpgME::Key & key, const TQString & address ) {
00256     const std::vector<GpgME::UserID> all = key.userIDs();
00257     if ( all.empty() )
00258         return GpgME::UserID();
00259     const std::vector<GpgME::UserID> matching = matchingUIDs( all, address.lower() );
00260     const std::vector<GpgME::UserID> & v = matching.empty() ? all : matching ;
00261     return *std::max_element( v.begin(), v.end(), ByTrustScore() );
00262 }
00263 
00264 static TQStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) {
00265   TQStringList strings;
00266   for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) {
00267     assert( !(*it).userID(0).isNull() );
00268     TQString keyLabel = TQString::fromUtf8( (*it).userID(0).email() );
00269     if ( keyLabel.isEmpty() )
00270       keyLabel = TQString::fromUtf8( (*it).userID(0).name() );
00271     if ( keyLabel.isEmpty() )
00272       keyLabel = TQString::fromUtf8( (*it).userID(0).id() );
00273     strings.append( keyLabel );
00274   }
00275   return strings;
00276 }
00277 
00278 static std::vector<GpgME::Key> trustedOrConfirmed( const std::vector<GpgME::Key> & keys, const TQString & address, bool & canceled ) {
00279 
00280   // PENDING(marc) work on UserIDs here?
00281   std::vector<GpgME::Key> fishies;
00282   std::vector<GpgME::Key> ickies;
00283   std::vector<GpgME::Key> rewookies;
00284   std::vector<GpgME::Key>::const_iterator it = keys.begin();
00285   const std::vector<GpgME::Key>::const_iterator end = keys.end();
00286   for ( ; it != end ; it++ ) {
00287     const GpgME::Key & key = *it;
00288     assert( ValidEncryptionKey( key ) );
00289     const GpgME::UserID uid = findBestMatchUID( key, address );
00290     if ( uid.isRevoked() ) {
00291         rewookies.push_back( key );
00292     }
00293     if ( !uid.isRevoked()  && uid.validity() == GpgME::UserID::Marginal ) {
00294         fishies.push_back( key );
00295     }
00296     if ( !uid.isRevoked()  && uid.validity() < GpgME::UserID::Never ) {
00297         ickies.push_back( key );
00298     }
00299   }
00300 
00301   if ( fishies.empty() && ickies.empty() && rewookies.empty() )
00302     return keys;
00303 
00304   // if  some keys are not fully trusted, let the user confirm their use
00305   TQString msg = address.isEmpty()
00306       ? i18n("One or more of your configured OpenPGP encryption "
00307              "keys or S/MIME certificates is not fully trusted "
00308              "for encryption.")
00309       : i18n("One or more of the OpenPGP encryption keys or S/MIME "
00310              "certificates for recipient \"%1\" is not fully trusted "
00311              "for encryption.").arg(address) ;
00312 
00313   if ( !fishies.empty() ) {
00314     // certificates can't have marginal trust
00315     msg += i18n( "\nThe following keys are only marginally trusted: \n");
00316     msg += keysAsStrings( fishies ).join(",");
00317   }
00318   if ( !ickies.empty() ) {
00319     msg += i18n( "\nThe following keys or certificates have unknown trust level: \n");
00320     msg += keysAsStrings( ickies ).join(",");
00321   }
00322   if ( !rewookies.empty() ) {
00323     msg += i18n( "\nThe following keys or certificates are <b>revoked</b>: \n");
00324     msg += keysAsStrings( rewookies ).join(",");
00325   }
00326 
00327   if( KMessageBox::warningContinueCancel( 0, msg, i18n("Not Fully Trusted Encryption Keys"),
00328                                               KStdGuiItem::cont(),
00329                                               "not fully trusted encryption key warning" )
00330           == KMessageBox::Continue )
00331     return keys;
00332   else
00333     canceled = true;
00334   return std::vector<GpgME::Key>();
00335 }
00336 
00337 namespace {
00338   struct IsNotForFormat : public std::unary_function<GpgME::Key,bool> {
00339     IsNotForFormat( Kleo::CryptoMessageFormat f ) : format( f ) {}
00340 
00341     bool operator()( const GpgME::Key & key ) const {
00342       return
00343     ( isOpenPGP( format ) && key.protocol() != GpgME::Context::OpenPGP ) ||
00344     ( isSMIME( format )   && key.protocol() != GpgME::Context::CMS );
00345     }
00346 
00347     const Kleo::CryptoMessageFormat format;
00348   };
00349 
00350   struct IsForFormat : std::unary_function<GpgME::Key,bool> {
00351     explicit IsForFormat( Kleo::CryptoMessageFormat f )
00352       : protocol( isOpenPGP( f ) ? GpgME::Context::OpenPGP :
00353                   isSMIME( f )   ? GpgME::Context::CMS     :
00354                   /* else */       GpgME::Context::Unknown ) {}
00355 
00356     bool operator()( const GpgME::Key & key ) const {
00357       return key.protocol() == protocol ;
00358     }
00359 
00360     const GpgME::Context::Protocol protocol;
00361   };
00362 
00363 }
00364 
00365 
00366 
00367 class Kleo::KeyResolver::SigningPreferenceCounter : public std::unary_function<Kleo::KeyResolver::Item,void> {
00368 public:
00369   SigningPreferenceCounter()
00370     : mTotal( 0 ),
00371       mUnknownSigningPreference( 0 ),
00372       mNeverSign( 0 ),
00373       mAlwaysSign( 0 ),
00374       mAlwaysSignIfPossible( 0 ),
00375       mAlwaysAskForSigning( 0 ),
00376       mAskSigningWheneverPossible( 0 )
00377   {
00378 
00379   }
00380   void operator()( const Kleo::KeyResolver::Item & item );
00381 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
00382   make_int_accessor(UnknownSigningPreference)
00383   make_int_accessor(NeverSign)
00384   make_int_accessor(AlwaysSign)
00385   make_int_accessor(AlwaysSignIfPossible)
00386   make_int_accessor(AlwaysAskForSigning)
00387   make_int_accessor(AskSigningWheneverPossible)
00388   make_int_accessor(Total)
00389 #undef make_int_accessor
00390 private:
00391   unsigned int mTotal;
00392   unsigned int mUnknownSigningPreference, mNeverSign, mAlwaysSign,
00393     mAlwaysSignIfPossible, mAlwaysAskForSigning, mAskSigningWheneverPossible;
00394 };
00395 
00396 void Kleo::KeyResolver::SigningPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
00397   switch ( item.signPref ) {
00398 #define CASE(x) case x: ++m##x; break
00399     CASE(UnknownSigningPreference);
00400     CASE(NeverSign);
00401     CASE(AlwaysSign);
00402     CASE(AlwaysSignIfPossible);
00403     CASE(AlwaysAskForSigning);
00404     CASE(AskSigningWheneverPossible);
00405 #undef CASE
00406   }
00407   ++mTotal;
00408 }
00409 
00410 
00411 
00412 class Kleo::KeyResolver::EncryptionPreferenceCounter : public std::unary_function<Item,void> {
00413   const Kleo::KeyResolver * _this;
00414 public:
00415   EncryptionPreferenceCounter( const Kleo::KeyResolver * kr, EncryptionPreference defaultPreference )
00416     : _this( kr ),
00417       mDefaultPreference( defaultPreference ),
00418       mTotal( 0 ),
00419       mNoKey( 0 ),
00420       mNeverEncrypt( 0 ),
00421       mUnknownPreference( 0 ),
00422       mAlwaysEncrypt( 0 ),
00423       mAlwaysEncryptIfPossible( 0 ),
00424       mAlwaysAskForEncryption( 0 ),
00425       mAskWheneverPossible( 0 )
00426   {
00427 
00428   }
00429   void operator()( Item & item );
00430 
00431   template <typename Container>
00432   void process( Container & c ) {
00433     *this = std::for_each( c.begin(), c.end(), *this );
00434   }
00435 
00436 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
00437   make_int_accessor(NoKey)
00438   make_int_accessor(NeverEncrypt)
00439   make_int_accessor(UnknownPreference)
00440   make_int_accessor(AlwaysEncrypt)
00441   make_int_accessor(AlwaysEncryptIfPossible)
00442   make_int_accessor(AlwaysAskForEncryption)
00443   make_int_accessor(AskWheneverPossible)
00444   make_int_accessor(Total)
00445 #undef make_int_accessor
00446 private:
00447   EncryptionPreference mDefaultPreference;
00448   bool mNoOps;
00449   unsigned int mTotal;
00450   unsigned int mNoKey;
00451   unsigned int mNeverEncrypt, mUnknownPreference, mAlwaysEncrypt,
00452     mAlwaysEncryptIfPossible, mAlwaysAskForEncryption, mAskWheneverPossible;
00453 };
00454 
00455 void Kleo::KeyResolver::EncryptionPreferenceCounter::operator()( Item & item ) {
00456   if ( _this ) {
00457   if ( item.needKeys )
00458     item.keys = _this->getEncryptionKeys( item.address, true );
00459   if ( item.keys.empty() ) {
00460     ++mNoKey;
00461     return;
00462   }
00463   }
00464   switch ( !item.pref ? mDefaultPreference : item.pref ) {
00465 #define CASE(x) case Kleo::x: ++m##x; break
00466     CASE(NeverEncrypt);
00467     CASE(UnknownPreference);
00468     CASE(AlwaysEncrypt);
00469     CASE(AlwaysEncryptIfPossible);
00470     CASE(AlwaysAskForEncryption);
00471     CASE(AskWheneverPossible);
00472 #undef CASE
00473   }
00474   ++mTotal;
00475 }
00476 
00477 namespace {
00478 
00479   class FormatPreferenceCounterBase : public std::unary_function<Kleo::KeyResolver::Item,void> {
00480   public:
00481     FormatPreferenceCounterBase()
00482       : mTotal( 0 ),
00483     mInlineOpenPGP( 0 ),
00484     mOpenPGPMIME( 0 ),
00485     mSMIME( 0 ),
00486     mSMIMEOpaque( 0 )
00487     {
00488 
00489     }
00490 
00491 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
00492     make_int_accessor(Total)
00493     make_int_accessor(InlineOpenPGP)
00494     make_int_accessor(OpenPGPMIME)
00495     make_int_accessor(SMIME)
00496     make_int_accessor(SMIMEOpaque)
00497 #undef make_int_accessor
00498 
00499     unsigned int numOf( Kleo::CryptoMessageFormat f ) const {
00500       switch ( f ) {
00501 #define CASE(x) case Kleo::x##Format: return m##x
00502     CASE(InlineOpenPGP);
00503     CASE(OpenPGPMIME);
00504     CASE(SMIME);
00505     CASE(SMIMEOpaque);
00506 #undef CASE
00507       default: return 0;
00508       }
00509     }
00510 
00511   protected:
00512     unsigned int mTotal;
00513     unsigned int mInlineOpenPGP, mOpenPGPMIME, mSMIME, mSMIMEOpaque;
00514   };
00515 
00516   class EncryptionFormatPreferenceCounter : public FormatPreferenceCounterBase {
00517   public:
00518     EncryptionFormatPreferenceCounter() : FormatPreferenceCounterBase() {}
00519     void operator()( const Kleo::KeyResolver::Item & item );
00520   };
00521 
00522   class SigningFormatPreferenceCounter : public FormatPreferenceCounterBase {
00523   public:
00524     SigningFormatPreferenceCounter() : FormatPreferenceCounterBase() {}
00525     void operator()( const Kleo::KeyResolver::Item & item );
00526   };
00527 
00528 #define CASE(x) if ( item.format & Kleo::x##Format ) ++m##x;
00529   void EncryptionFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
00530     if ( item.format & (Kleo::InlineOpenPGPFormat|Kleo::OpenPGPMIMEFormat) &&
00531      std::find_if( item.keys.begin(), item.keys.end(),
00532                ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) {  // -= trusted?
00533       CASE(OpenPGPMIME);
00534       CASE(InlineOpenPGP);
00535     }
00536     if ( item.format & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) &&
00537      std::find_if( item.keys.begin(), item.keys.end(),
00538                ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) {    // -= trusted?
00539       CASE(SMIME);
00540       CASE(SMIMEOpaque);
00541     }
00542     ++mTotal;
00543   }
00544 
00545   void SigningFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
00546     CASE(InlineOpenPGP);
00547     CASE(OpenPGPMIME);
00548     CASE(SMIME);
00549     CASE(SMIMEOpaque);
00550     ++mTotal;
00551   }
00552 #undef CASE
00553 
00554 } // anon namespace
00555 
00556 static TQString canonicalAddress( const TQString & _address ) {
00557   const TQString address = KPIM::getEmailAddress( _address );
00558   if ( address.find('@') == -1 ) {
00559     // local address
00560     //char hostname[1024];
00561     //gethostname(hostname,1024);
00562     //return address + '@' + hostname;
00563     return address + "@localdomain";
00564   }
00565   else
00566     return address;
00567 }
00568 
00569 
00570 struct FormatInfo {
00571   std::vector<Kleo::KeyResolver::SplitInfo> splitInfos;
00572   std::vector<GpgME::Key> signKeys;
00573 };
00574 
00575 struct Kleo::KeyResolver::Private {
00576   std::set<TQCString> alreadyWarnedFingerprints;
00577 
00578   std::vector<GpgME::Key> mOpenPGPSigningKeys; // signing
00579   std::vector<GpgME::Key> mSMIMESigningKeys; // signing
00580 
00581   std::vector<GpgME::Key> mOpenPGPEncryptToSelfKeys; // encryption to self
00582   std::vector<GpgME::Key> mSMIMEEncryptToSelfKeys; // encryption to self
00583 
00584   std::vector<Item> mPrimaryEncryptionKeys; // encryption to To/CC
00585   std::vector<Item> mSecondaryEncryptionKeys; // encryption to BCC
00586 
00587   std::map<CryptoMessageFormat,FormatInfo> mFormatInfoMap;
00588 
00589   // key=email address, value=crypto preferences for this contact (from kabc)
00590   typedef std::map<TQString, ContactPreferences> ContactPreferencesMap;
00591   ContactPreferencesMap mContactPreferencesMap;
00592 };
00593 
00594 
00595 Kleo::KeyResolver::KeyResolver( bool encToSelf, bool showApproval, bool oppEncryption,
00596                 unsigned int f,
00597                 int encrWarnThresholdKey, int signWarnThresholdKey,
00598                 int encrWarnThresholdRootCert, int signWarnThresholdRootCert,
00599                 int encrWarnThresholdChainCert, int signWarnThresholdChainCert )
00600   : mEncryptToSelf( encToSelf ),
00601     mShowApprovalDialog( showApproval ),
00602     mOpportunisticEncyption( oppEncryption ),
00603     mCryptoMessageFormats( f ),
00604     mEncryptKeyNearExpiryWarningThreshold( encrWarnThresholdKey ),
00605     mSigningKeyNearExpiryWarningThreshold( signWarnThresholdKey ),
00606     mEncryptRootCertNearExpiryWarningThreshold( encrWarnThresholdRootCert ),
00607     mSigningRootCertNearExpiryWarningThreshold( signWarnThresholdRootCert ),
00608     mEncryptChainCertNearExpiryWarningThreshold( encrWarnThresholdChainCert ),
00609     mSigningChainCertNearExpiryWarningThreshold( signWarnThresholdChainCert )
00610 {
00611   d = new Private();
00612 }
00613 
00614 Kleo::KeyResolver::~KeyResolver() {
00615   delete d; d = 0;
00616 }
00617 
00618 Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, const char * dontAskAgainName,
00619                             bool mine, bool sign, bool ca,
00620                             int recur_limit, const GpgME::Key & orig ) const {
00621   if ( recur_limit <= 0 ) {
00622     kdDebug() << "Kleo::KeyResolver::checkKeyNearExpiry(): key chain too long (>100 certs)" << endl;
00623     return Kpgp::Ok;
00624   }
00625   const GpgME::Subkey subkey = key.subkey(0);
00626   if ( d->alreadyWarnedFingerprints.count( subkey.fingerprint() ) )
00627     return Kpgp::Ok; // already warned about this one (and so about it's issuers)
00628 
00629   if ( subkey.neverExpires() )
00630     return Kpgp::Ok;
00631   static const double secsPerDay = 24 * 60 * 60;
00632   const double secsTillExpiry = ::difftime( subkey.expirationTime(), time(0) );
00633   if ( secsTillExpiry <= 0 ) {
00634       const int daysSinceExpiry = 1 + int( -secsTillExpiry / secsPerDay );
00635       kdDebug() << "Key 0x" << key.shortKeyID() << " expired less than "
00636                 << daysSinceExpiry << " days ago" << endl;
00637       const TQString msg =
00638           key.protocol() == GpgME::Context::OpenPGP
00639           ? ( mine ? sign
00640               ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00641                      "<p>expired less than a day ago.</p>",
00642                      "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00643                      "<p>expired %n days ago.</p>",
00644                      daysSinceExpiry )
00645               : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00646                      "<p>expired less than a day ago.</p>",
00647                      "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00648                      "<p>expired %n days ago.</p>",
00649                      daysSinceExpiry )
00650               : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00651                      "<p>expired less than a day ago.</p>",
00652                      "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00653                      "<p>expired %n days ago.</p>",
00654                      daysSinceExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ),
00655                      key.shortKeyID() )
00656           : ( ca
00657               ? ( key.isRoot()
00658                   ? ( mine ? sign
00659                       ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
00660                              "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00661                              "<p>expired less than a day ago.</p>",
00662                              "<p>The root certificate</p><p align=center><b>%3</b></p>"
00663                              "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00664                              "<p>expired %n days ago.</p>",
00665                              daysSinceExpiry )
00666                       : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
00667                              "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00668                              "<p>expired less than a day ago.</p>",
00669                              "<p>The root certificate</p><p align=center><b>%3</b></p>"
00670                              "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00671                              "<p>expired %n days ago.</p>",
00672                              daysSinceExpiry )
00673                       : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
00674                              "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00675                              "<p>expired less than a day ago.</p>",
00676                              "<p>The root certificate</p><p align=center><b>%3</b></p>"
00677                              "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00678                              "<p>expired %n days ago.</p>",
00679                              daysSinceExpiry ) )
00680                   : ( mine ? sign
00681                       ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00682                              "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00683                              "<p>expired less than a day ago.</p>",
00684                              "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00685                              "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00686                              "<p>expired %n days ago.</p>",
00687                              daysSinceExpiry )
00688                       : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00689                              "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00690                              "<p>expired less than a day ago.</p>",
00691                              "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00692                              "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00693                              "<p>expired %n days ago.</p>",
00694                              daysSinceExpiry )
00695                       : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00696                              "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00697                              "<p>expired less than a day ago.</p>",
00698                              "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00699                              "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00700                              "<p>expired %n days ago.</p>",
00701                              daysSinceExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(),
00702                                                        orig.issuerSerial(),
00703                                                        Kleo::DN( key.userID(0).id() ).prettyDN() )
00704               : ( mine ? sign
00705                   ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00706                          "<p>expired less than a day ago.</p>",
00707                          "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00708                          "<p>expired %n days ago.</p>",
00709                          daysSinceExpiry )
00710                   : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00711                          "<p>expired less than a day ago.</p>",
00712                          "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00713                          "<p>expired %n days ago.</p>",
00714                          daysSinceExpiry )
00715                   : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
00716                          "<p>expired less than a day ago.</p>",
00717                          "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
00718                          "<p>expired %n days ago.</p>",
00719                          daysSinceExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
00720                                                  key.issuerSerial() ) );
00721       d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
00722       if ( KMessageBox::warningContinueCancel( 0, msg,
00723                                                key.protocol() == GpgME::Context::OpenPGP
00724                                                ? i18n("OpenPGP Key Expired" )
00725                                                : i18n("S/MIME Certificate Expired" ),
00726                                                KStdGuiItem::cont(), dontAskAgainName ) == KMessageBox::Cancel )
00727           return Kpgp::Canceled;
00728   } else {
00729   const int daysTillExpiry = 1 + int( secsTillExpiry / secsPerDay );
00730   kdDebug() << "Key 0x" << key.shortKeyID() << " expires in less than "
00731         << daysTillExpiry << " days" << endl;
00732   const int threshold =
00733     ca
00734     ? ( key.isRoot()
00735     ? ( sign
00736         ? signingRootCertNearExpiryWarningThresholdInDays()
00737         : encryptRootCertNearExpiryWarningThresholdInDays() )
00738     : ( sign
00739         ? signingChainCertNearExpiryWarningThresholdInDays()
00740         : encryptChainCertNearExpiryWarningThresholdInDays() ) )
00741     : ( sign
00742     ? signingKeyNearExpiryWarningThresholdInDays()
00743     : encryptKeyNearExpiryWarningThresholdInDays() );
00744   if ( threshold > -1 && daysTillExpiry <= threshold ) {
00745     const TQString msg =
00746       key.protocol() == GpgME::Context::OpenPGP
00747       ? ( mine ? sign
00748       ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00749          "<p>expires in less than a day.</p>",
00750          "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00751          "<p>expires in less than %n days.</p>",
00752          daysTillExpiry )
00753       : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00754          "<p>expires in less than a day.</p>",
00755          "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00756          "<p>expires in less than %n days.</p>",
00757          daysTillExpiry )
00758       : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00759          "<p>expires in less than a day.</p>",
00760          "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
00761          "<p>expires in less than %n days.</p>",
00762          daysTillExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ),
00763                      key.shortKeyID() )
00764       : ( ca
00765       ? ( key.isRoot()
00766           ? ( mine ? sign
00767           ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
00768              "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00769              "<p>expires in less than a day.</p>",
00770              "<p>The root certificate</p><p align=center><b>%3</b></p>"
00771              "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00772              "<p>expires in less than %n days.</p>",
00773              daysTillExpiry )
00774           : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
00775              "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00776              "<p>expires in less than a day.</p>",
00777              "<p>The root certificate</p><p align=center><b>%3</b></p>"
00778              "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00779              "<p>expires in less than %n days.</p>",
00780              daysTillExpiry )
00781           : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
00782              "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00783              "<p>expires in less than a day.</p>",
00784              "<p>The root certificate</p><p align=center><b>%3</b></p>"
00785              "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00786              "<p>expires in less than %n days.</p>",
00787              daysTillExpiry ) )
00788           : ( mine ? sign
00789           ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00790              "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00791              "<p>expires in less than a day.</p>",
00792              "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00793              "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00794              "<p>expires in less than %n days.</p>",
00795              daysTillExpiry )
00796           : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00797              "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00798              "<p>expires in less than a day.</p>",
00799              "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00800              "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00801              "<p>expires in less than %n days.</p>",
00802              daysTillExpiry )
00803           : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00804              "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00805              "<p>expires in less than a day.</p>",
00806              "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
00807              "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00808              "<p>expires in less than %n days.</p>",
00809              daysTillExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(),
00810                            orig.issuerSerial(),
00811                            Kleo::DN( key.userID(0).id() ).prettyDN() )
00812       : ( mine ? sign
00813           ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00814              "<p>expires in less than a day.</p>",
00815              "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00816              "<p>expires in less than %n days.</p>",
00817              daysTillExpiry )
00818           : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00819              "<p>expires in less than a day.</p>",
00820              "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
00821              "<p>expires in less than %n days.</p>",
00822              daysTillExpiry )
00823           : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
00824              "<p>expires in less than a day.</p>",
00825              "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
00826              "<p>expires in less than %n days.</p>",
00827              daysTillExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
00828                          key.issuerSerial() ) );
00829     d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
00830     if ( KMessageBox::warningContinueCancel( 0, msg,
00831                          key.protocol() == GpgME::Context::OpenPGP
00832                          ? i18n("OpenPGP Key Expires Soon" )
00833                          : i18n("S/MIME Certificate Expires Soon" ),
00834                          KStdGuiItem::cont(), dontAskAgainName )
00835      == KMessageBox::Cancel )
00836       return Kpgp::Canceled;
00837   }
00838   }
00839   if ( key.isRoot() )
00840     return Kpgp::Ok;
00841   else if ( const char * chain_id = key.chainID() ) {
00842     const std::vector<GpgME::Key> issuer = lookup( chain_id, false );
00843     if ( issuer.empty() )
00844       return Kpgp::Ok;
00845     else
00846       return checkKeyNearExpiry( issuer.front(), dontAskAgainName, mine, sign,
00847                  true, recur_limit-1, ca ? orig : key );
00848   }
00849   return Kpgp::Ok;
00850 }
00851 
00852 Kpgp::Result Kleo::KeyResolver::setEncryptToSelfKeys( const TQStringList & fingerprints ) {
00853   if ( !encryptToSelf() )
00854     return Kpgp::Ok;
00855 
00856   std::vector<GpgME::Key> keys = lookup( fingerprints );
00857   std::remove_copy_if( keys.begin(), keys.end(),
00858                std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
00859                NotValidTrustedOpenPGPEncryptionKey ); // -= trusted?
00860   std::remove_copy_if( keys.begin(), keys.end(),
00861                std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
00862                NotValidTrustedSMIMEEncryptionKey );   // -= trusted?
00863 
00864   if ( d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size()
00865        < keys.size() ) {
00866     // too few keys remain...
00867     const TQString msg = i18n("One or more of your configured OpenPGP encryption "
00868                  "keys or S/MIME certificates is not usable for "
00869                  "encryption. Please reconfigure your encryption keys "
00870                  "and certificates for this identity in the identity "
00871                  "configuration dialog.\n"
00872                  "If you choose to continue, and the keys are needed "
00873                  "later on, you will be prompted to specify the keys "
00874                  "to use.");
00875     return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Encryption Keys"),
00876                            KStdGuiItem::cont(),
00877                            "unusable own encryption key warning" )
00878       == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ;
00879   }
00880 
00881   // check for near-expiry:
00882 
00883   for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPEncryptToSelfKeys.begin() ; it != d->mOpenPGPEncryptToSelfKeys.end() ; ++it ) {
00884     const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning",
00885                            true, false );
00886     if ( r != Kpgp::Ok )
00887       return r;
00888   }
00889 
00890   for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMEEncryptToSelfKeys.begin() ; it != d->mSMIMEEncryptToSelfKeys.end() ; ++it ) {
00891     const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning",
00892                            true, false );
00893     if ( r != Kpgp::Ok )
00894       return r;
00895   }
00896 
00897   return Kpgp::Ok;
00898 }
00899 
00900 Kpgp::Result Kleo::KeyResolver::setSigningKeys( const TQStringList & fingerprints ) {
00901   std::vector<GpgME::Key> keys = lookup( fingerprints, true ); // secret keys
00902   std::remove_copy_if( keys.begin(), keys.end(),
00903                std::back_inserter( d->mOpenPGPSigningKeys ),
00904                NotValidOpenPGPSigningKey );
00905   std::remove_copy_if( keys.begin(), keys.end(),
00906                std::back_inserter( d->mSMIMESigningKeys ),
00907                NotValidSMIMESigningKey );
00908 
00909   if ( d->mOpenPGPSigningKeys.size() + d->mSMIMESigningKeys.size() < keys.size() ) {
00910     // too few keys remain...
00911     const TQString msg = i18n("One or more of your configured OpenPGP signing keys "
00912                  "or S/MIME signing certificates is not usable for "
00913                  "signing. Please reconfigure your signing keys "
00914                  "and certificates for this identity in the identity "
00915                  "configuration dialog.\n"
00916                  "If you choose to continue, and the keys are needed "
00917                  "later on, you will be prompted to specify the keys "
00918                  "to use.");
00919     return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Signing Keys"),
00920                            KStdGuiItem::cont(),
00921                            "unusable signing key warning" )
00922       == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ;
00923   }
00924 
00925   // check for near expiry:
00926 
00927   for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPSigningKeys.begin() ; it != d->mOpenPGPSigningKeys.end() ; ++it ) {
00928     const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning",
00929                            true, true );
00930     if ( r != Kpgp::Ok )
00931       return r;
00932   }
00933 
00934   for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMESigningKeys.begin() ; it != d->mSMIMESigningKeys.end() ; ++it ) {
00935     const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning",
00936                            true, true );
00937     if ( r != Kpgp::Ok )
00938       return r;
00939   }
00940 
00941   return Kpgp::Ok;
00942 }
00943 
00944 void Kleo::KeyResolver::setPrimaryRecipients( const TQStringList & addresses ) {
00945   d->mPrimaryEncryptionKeys = getEncryptionItems( addresses );
00946 }
00947 
00948 void Kleo::KeyResolver::setSecondaryRecipients( const TQStringList & addresses ) {
00949   d->mSecondaryEncryptionKeys = getEncryptionItems( addresses );
00950 }
00951 
00952 std::vector<Kleo::KeyResolver::Item> Kleo::KeyResolver::getEncryptionItems( const TQStringList & addresses ) {
00953   std::vector<Item> items;
00954   items.reserve( addresses.size() );
00955   for ( TQStringList::const_iterator it = addresses.begin() ; it != addresses.end() ; ++it ) {
00956     TQString addr = canonicalAddress( *it ).lower();
00957     const ContactPreferences pref = lookupContactPreferences( addr );
00958 
00959     items.push_back( Item( *it, /*getEncryptionKeys( *it, true ),*/
00960                pref.encryptionPreference,
00961                pref.signingPreference,
00962                pref.cryptoMessageFormat ) );
00963   }
00964   return items;
00965 }
00966 
00967 static Kleo::Action action( bool doit, bool ask, bool dont, bool requested ) {
00968   if ( requested && !dont )
00969     return Kleo::DoIt;
00970   if ( doit && !ask && !dont )
00971     return Kleo::DoIt;
00972   if ( !doit && ask && !dont )
00973     return Kleo::Ask;
00974   if ( !doit && !ask && dont )
00975     return requested ? Kleo::Conflict : Kleo::DontDoIt ;
00976   if ( !doit && !ask && !dont )
00977     return Kleo::DontDoIt ;
00978   return Kleo::Conflict;
00979 }
00980 
00981 Kleo::Action Kleo::KeyResolver::checkSigningPreferences( bool signingRequested ) const {
00982 
00983   if ( signingRequested && d->mOpenPGPSigningKeys.empty() && d->mSMIMESigningKeys.empty() )
00984     return Impossible;
00985 
00986   SigningPreferenceCounter count;
00987   count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
00988              count );
00989   count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
00990              count );
00991 
00992   unsigned int sign = count.numAlwaysSign();
00993   unsigned int ask = count.numAlwaysAskForSigning();
00994   const unsigned int dontSign = count.numNeverSign();
00995   if ( signingPossible() ) {
00996     sign += count.numAlwaysSignIfPossible();
00997     ask += count.numAskSigningWheneverPossible();
00998   }
00999 
01000   return action( sign, ask, dontSign, signingRequested );
01001 }
01002 
01003 bool Kleo::KeyResolver::signingPossible() const {
01004   return !d->mOpenPGPSigningKeys.empty() || !d->mSMIMESigningKeys.empty() ;
01005 }
01006 
01007 Kleo::Action Kleo::KeyResolver::checkEncryptionPreferences( bool encryptionRequested ) const {
01008 
01009   if ( d->mPrimaryEncryptionKeys.empty() && d->mSecondaryEncryptionKeys.empty() )
01010     return DontDoIt;
01011 
01012   if ( encryptionRequested && encryptToSelf() &&
01013        d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty() )
01014     return Impossible;
01015 
01016   if ( !encryptionRequested && !mOpportunisticEncyption ) {
01017     // try to minimize crypto ops (including key lookups) by only
01018     // looking up keys when at least one the the encryption
01019     // preferences needs it:
01020     EncryptionPreferenceCounter count( 0, UnknownPreference );
01021     count.process( d->mPrimaryEncryptionKeys );
01022     count.process( d->mSecondaryEncryptionKeys );
01023     if ( !count.numAlwaysEncrypt() &&
01024          !count.numAlwaysAskForEncryption() && // this guy might not need a lookup, when declined, but it's too complex to implement that here
01025          !count.numAlwaysEncryptIfPossible() &&
01026          !count.numAskWheneverPossible() )
01027         return DontDoIt;
01028   }
01029 
01030   EncryptionPreferenceCounter count( this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference );
01031   count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01032              count );
01033   count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01034              count );
01035 
01036   unsigned int encrypt = count.numAlwaysEncrypt();
01037   unsigned int ask = count.numAlwaysAskForEncryption();
01038   const unsigned int dontEncrypt = count.numNeverEncrypt() + count.numNoKey();
01039   if ( encryptionPossible() ) {
01040     encrypt += count.numAlwaysEncryptIfPossible();
01041     ask += count.numAskWheneverPossible();
01042   }
01043 
01044   const Action act = action( encrypt, ask, dontEncrypt, encryptionRequested );
01045   if ( act != Ask ||
01046        std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01047        std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01048               EncryptionPreferenceCounter( this, UnknownPreference ) ) ).numAlwaysAskForEncryption() )
01049     return act;
01050   else
01051     return AskOpportunistic;
01052 }
01053 
01054 bool Kleo::KeyResolver::encryptionPossible() const {
01055   return std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01056                EmptyKeyList ) == d->mPrimaryEncryptionKeys.end()
01057     &&   std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01058                EmptyKeyList ) == d->mSecondaryEncryptionKeys.end() ;
01059 }
01060 
01061 Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& encryptionRequested ) {
01062   if ( !encryptionRequested && !signingRequested ) {
01063     // make a dummy entry with all recipients, but no signing or
01064     // encryption keys to avoid special-casing on the caller side:
01065     dump();
01066     d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) );
01067     dump();
01068     return Kpgp::Ok;
01069   }
01070   Kpgp::Result result = Kpgp::Ok;
01071   if ( encryptionRequested )
01072     result = resolveEncryptionKeys( signingRequested );
01073   if ( result != Kpgp::Ok )
01074     return result;
01075   if ( signingRequested ) {
01076     if ( encryptionRequested ) {
01077       result = resolveSigningKeysForEncryption();
01078     }
01079     else {
01080       result = resolveSigningKeysForSigningOnly();
01081       if ( result == Kpgp::Failure ) {
01082         signingRequested = false;
01083         return Kpgp::Ok;
01084       }
01085     }
01086   }
01087   return result;
01088 }
01089 
01090 Kpgp::Result Kleo::KeyResolver::resolveEncryptionKeys( bool signingRequested ) {
01091   //
01092   // 1. Get keys for all recipients:
01093   //
01094 
01095   for ( std::vector<Item>::iterator it = d->mPrimaryEncryptionKeys.begin() ; it != d->mPrimaryEncryptionKeys.end() ; ++it ) {
01096     if ( !it->needKeys )
01097       continue;
01098     it->keys = getEncryptionKeys( it->address, false );
01099     if ( it->keys.empty() )
01100       return Kpgp::Canceled;
01101     TQString addr = canonicalAddress( it->address ).lower();
01102     const ContactPreferences pref = lookupContactPreferences( addr );
01103     it->pref = pref.encryptionPreference;
01104     it->signPref = pref.signingPreference;
01105     it->format = pref.cryptoMessageFormat;
01106   }
01107 
01108   for ( std::vector<Item>::iterator it = d->mSecondaryEncryptionKeys.begin() ; it != d->mSecondaryEncryptionKeys.end() ; ++it ) {
01109     if ( !it->needKeys )
01110       continue;
01111     it->keys = getEncryptionKeys( it->address, false );
01112     if ( it->keys.empty() )
01113       return Kpgp::Canceled;
01114     TQString addr = canonicalAddress( it->address ).lower();
01115     const ContactPreferences pref = lookupContactPreferences( addr );
01116     it->pref = pref.encryptionPreference;
01117     it->signPref = pref.signingPreference;
01118     it->format = pref.cryptoMessageFormat;
01119   }
01120 
01121   // 1a: Present them to the user
01122 
01123   const Kpgp::Result res = showKeyApprovalDialog();
01124   if ( res != Kpgp::Ok )
01125     return res;
01126 
01127   //
01128   // 2. Check what the primary recipients need
01129   //
01130 
01131   // 2a. Try to find a common format for all primary recipients,
01132   //     else use as many formats as needed
01133 
01134   const EncryptionFormatPreferenceCounter primaryCount
01135     = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01136              EncryptionFormatPreferenceCounter() );
01137 
01138   CryptoMessageFormat commonFormat = AutoFormat;
01139   for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
01140     if ( !( concreteCryptoMessageFormats[i] & mCryptoMessageFormats ) )
01141       continue;
01142     if ( signingRequested && signingKeysFor( concreteCryptoMessageFormats[i] ).empty() )
01143       continue;
01144     if ( encryptToSelf() && encryptToSelfKeysFor( concreteCryptoMessageFormats[i] ).empty() )
01145       continue;
01146     if ( primaryCount.numOf( concreteCryptoMessageFormats[i] ) == primaryCount.numTotal() ) {
01147       commonFormat = concreteCryptoMessageFormats[i];
01148       break;
01149     }
01150   }
01151   if ( commonFormat != AutoFormat )
01152     addKeys( d->mPrimaryEncryptionKeys, commonFormat );
01153   else
01154     addKeys( d->mPrimaryEncryptionKeys );
01155 
01156   collapseAllSplitInfos(); // these can be encrypted together
01157 
01158   // 2b. Just try to find _something_ for each secondary recipient,
01159   //     with a preference to a common format (if that exists)
01160 
01161   const EncryptionFormatPreferenceCounter secondaryCount
01162     = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01163              EncryptionFormatPreferenceCounter() );
01164 
01165   if ( commonFormat != AutoFormat &&
01166        secondaryCount.numOf( commonFormat ) == secondaryCount.numTotal() )
01167     addKeys( d->mSecondaryEncryptionKeys, commonFormat );
01168   else
01169     addKeys( d->mSecondaryEncryptionKeys );
01170 
01171   // 3. Check for expiry:
01172 
01173   for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
01174     const std::vector<SplitInfo> si_list = encryptionItems( concreteCryptoMessageFormats[i] );
01175     for ( std::vector<SplitInfo>::const_iterator sit = si_list.begin() ; sit != si_list.end() ; ++sit )
01176       for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit ) {
01177     const Kpgp::Result r = checkKeyNearExpiry( *kit, "other encryption key near expiry warning",
01178                            false, false );
01179     if ( r != Kpgp::Ok )
01180       return r;
01181       }
01182   }
01183 
01184   // 4. Check that we have the right keys for encryptToSelf()
01185 
01186   if ( !encryptToSelf() )
01187     return Kpgp::Ok;
01188 
01189   // 4a. Check for OpenPGP keys
01190 
01191   if ( !encryptionItems( InlineOpenPGPFormat ).empty() ||
01192        !encryptionItems( OpenPGPMIMEFormat ).empty() ) {
01193     // need them
01194     if ( d->mOpenPGPEncryptToSelfKeys.empty() ) {
01195       const TQString msg = i18n("Examination of recipient's encryption preferences "
01196                    "yielded that the message should be encrypted using "
01197                    "OpenPGP, at least for some recipients;\n"
01198                    "however, you have not configured valid trusted "
01199                    "OpenPGP encryption keys for this identity.\n"
01200                    "You may continue without encrypting to yourself, "
01201                    "but be aware that you will not be able to read your "
01202                    "own messages if you do so.");
01203       if ( KMessageBox::warningContinueCancel( 0, msg,
01204                            i18n("Unusable Encryption Keys"),
01205                            KStdGuiItem::cont(),
01206                            "encrypt-to-self will fail warning" )
01207        == KMessageBox::Cancel )
01208     return Kpgp::Canceled;
01209       // FIXME: Allow selection
01210     }
01211     addToAllSplitInfos( d->mOpenPGPEncryptToSelfKeys,
01212             InlineOpenPGPFormat|OpenPGPMIMEFormat );
01213   }
01214 
01215   // 4b. Check for S/MIME certs:
01216 
01217   if ( !encryptionItems( SMIMEFormat ).empty() ||
01218        !encryptionItems( SMIMEOpaqueFormat ).empty() ) {
01219     // need them
01220     if ( d->mSMIMEEncryptToSelfKeys.empty() ) {
01221       // don't have one
01222       const TQString msg = i18n("Examination of recipient's encryption preferences "
01223                    "yielded that the message should be encrypted using "
01224                    "S/MIME, at least for some recipients;\n"
01225                    "however, you have not configured valid "
01226                    "S/MIME encryption certificates for this identity.\n"
01227                    "You may continue without encrypting to yourself, "
01228                    "but be aware that you will not be able to read your "
01229                    "own messages if you do so.");
01230       if ( KMessageBox::warningContinueCancel( 0, msg,
01231                            i18n("Unusable Encryption Keys"),
01232                            KStdGuiItem::cont(),
01233                            "encrypt-to-self will fail warning" )
01234        == KMessageBox::Cancel )
01235     return Kpgp::Canceled;
01236       // FIXME: Allow selection
01237     }
01238     addToAllSplitInfos( d->mSMIMEEncryptToSelfKeys,
01239             SMIMEFormat|SMIMEOpaqueFormat );
01240   }
01241 
01242   // FIXME: Present another message if _both_ OpenPGP and S/MIME keys
01243   // are missing.
01244 
01245   return Kpgp::Ok;
01246 }
01247 
01248 Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForEncryption() {
01249   if ( ( !encryptionItems( InlineOpenPGPFormat ).empty() ||
01250      !encryptionItems( OpenPGPMIMEFormat ).empty() )
01251        && d->mOpenPGPSigningKeys.empty() ) {
01252     const TQString msg = i18n("Examination of recipient's signing preferences "
01253                  "yielded that the message should be signed using "
01254                  "OpenPGP, at least for some recipients;\n"
01255                  "however, you have not configured valid "
01256                  "OpenPGP signing certificates for this identity.");
01257     if ( KMessageBox::warningContinueCancel( 0, msg,
01258                          i18n("Unusable Signing Keys"),
01259                          i18n("Do Not OpenPGP-Sign"),
01260                          "signing will fail warning" )
01261      == KMessageBox::Cancel )
01262       return Kpgp::Canceled;
01263     // FIXME: Allow selection
01264   }
01265   if ( ( !encryptionItems( SMIMEFormat ).empty() ||
01266      !encryptionItems( SMIMEOpaqueFormat ).empty() )
01267        && d->mSMIMESigningKeys.empty() ) {
01268     const TQString msg = i18n("Examination of recipient's signing preferences "
01269                  "yielded that the message should be signed using "
01270                  "S/MIME, at least for some recipients;\n"
01271                  "however, you have not configured valid "
01272                  "S/MIME signing certificates for this identity.");
01273     if ( KMessageBox::warningContinueCancel( 0, msg,
01274                          i18n("Unusable Signing Keys"),
01275                          i18n("Do Not S/MIME-Sign"),
01276                          "signing will fail warning" )
01277      == KMessageBox::Cancel )
01278       return Kpgp::Canceled;
01279     // FIXME: Allow selection
01280   }
01281 
01282   // FIXME: Present another message if _both_ OpenPGP and S/MIME keys
01283   // are missing.
01284 
01285   for ( std::map<CryptoMessageFormat,FormatInfo>::iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it )
01286     if ( !it->second.splitInfos.empty() ) {
01287       dump();
01288       it->second.signKeys = signingKeysFor( it->first );
01289       dump();
01290     }
01291 
01292   return Kpgp::Ok;
01293 }
01294 
01295 Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForSigningOnly() {
01296   //
01297   // we don't need to distinguish between primary and secondary
01298   // recipients here:
01299   //
01300   SigningFormatPreferenceCounter count;
01301   count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01302              count );
01303   count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01304              count );
01305 
01306   // try to find a common format that works for all (and that we have signing keys for):
01307 
01308   CryptoMessageFormat commonFormat = AutoFormat;
01309 
01310   for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
01311     if ( !(mCryptoMessageFormats & concreteCryptoMessageFormats[i]) )
01312       continue; // skip
01313     if ( signingKeysFor( concreteCryptoMessageFormats[i] ).empty() )
01314       continue; // skip
01315     if ( count.numOf( concreteCryptoMessageFormats[i] ) == count.numTotal() ) {
01316       commonFormat = concreteCryptoMessageFormats[i];
01317       break;
01318     }
01319   }
01320 
01321   if ( commonFormat != AutoFormat ) { // found
01322     dump();
01323     FormatInfo & fi = d->mFormatInfoMap[ commonFormat ];
01324     fi.signKeys = signingKeysFor( commonFormat );
01325     fi.splitInfos.resize( 1 );
01326     fi.splitInfos.front() = SplitInfo( allRecipients() );
01327     dump();
01328     return Kpgp::Ok;
01329   }
01330 
01331   const TQString msg = i18n("Examination of recipient's signing preferences "
01332                            "showed no common type of signature matching your "
01333                            "available signing keys.\n"
01334                            "Send message without signing?"  );
01335   if ( KMessageBox::warningContinueCancel( 0, msg, i18n("No signing possible"),
01336                                            KStdGuiItem::cont() )
01337        == KMessageBox::Continue ) {
01338     d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) );
01339     return Kpgp::Failure; // means "Ok, but without signing"
01340   }
01341   return Kpgp::Canceled;
01342 }
01343 
01344 std::vector<GpgME::Key> Kleo::KeyResolver::signingKeysFor( CryptoMessageFormat f ) const {
01345   if ( isOpenPGP( f ) )
01346     return d->mOpenPGPSigningKeys;
01347   if ( isSMIME( f ) )
01348     return d->mSMIMESigningKeys;
01349   return std::vector<GpgME::Key>();
01350 }
01351 
01352 std::vector<GpgME::Key> Kleo::KeyResolver::encryptToSelfKeysFor( CryptoMessageFormat f ) const {
01353   if ( isOpenPGP( f ) )
01354     return d->mOpenPGPEncryptToSelfKeys;
01355   if ( isSMIME( f ) )
01356     return d->mSMIMEEncryptToSelfKeys;
01357   return std::vector<GpgME::Key>();
01358 }
01359 
01360 TQStringList Kleo::KeyResolver::allRecipients() const {
01361   TQStringList result;
01362   std::transform( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01363           std::back_inserter( result ), ItemDotAddress );
01364   std::transform( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01365           std::back_inserter( result ), ItemDotAddress );
01366   return result;
01367 }
01368 
01369 void Kleo::KeyResolver::collapseAllSplitInfos() {
01370   dump();
01371   for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
01372     std::map<CryptoMessageFormat,FormatInfo>::iterator pos =
01373       d->mFormatInfoMap.find( concreteCryptoMessageFormats[i] );
01374     if ( pos == d->mFormatInfoMap.end() )
01375       continue;
01376     std::vector<SplitInfo> & v = pos->second.splitInfos;
01377     if ( v.size() < 2 )
01378       continue;
01379     SplitInfo & si = v.front();
01380     for ( std::vector<SplitInfo>::const_iterator it = v.begin() + 1; it != v.end() ; ++it ) {
01381       si.keys.insert( si.keys.end(), it->keys.begin(), it->keys.end() );
01382       qCopy( it->recipients.begin(), it->recipients.end(), std::back_inserter( si.recipients ) );
01383     }
01384     v.resize( 1 );
01385   }
01386   dump();
01387 }
01388 
01389 void Kleo::KeyResolver::addToAllSplitInfos( const std::vector<GpgME::Key> & keys, unsigned int f ) {
01390   dump();
01391   if ( !f || keys.empty() )
01392     return;
01393   for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
01394     if ( !( f & concreteCryptoMessageFormats[i] ) )
01395       continue;
01396     std::map<CryptoMessageFormat,FormatInfo>::iterator pos =
01397       d->mFormatInfoMap.find( concreteCryptoMessageFormats[i] );
01398     if ( pos == d->mFormatInfoMap.end() )
01399       continue;
01400     std::vector<SplitInfo> & v = pos->second.splitInfos;
01401     for ( std::vector<SplitInfo>::iterator it = v.begin() ; it != v.end() ; ++it )
01402       it->keys.insert( it->keys.end(), keys.begin(), keys.end() );
01403   }
01404   dump();
01405 }
01406 
01407 void Kleo::KeyResolver::dump() const {
01408 #ifndef NDEBUG
01409   if ( d->mFormatInfoMap.empty() )
01410     std::cerr << "Keyresolver: Format info empty" << std::endl;
01411   for ( std::map<CryptoMessageFormat,FormatInfo>::const_iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it ) {
01412     std::cerr << "Format info for " << Kleo::cryptoMessageFormatToString( it->first )
01413           << ":" << std::endl
01414           << "  Signing keys: ";
01415     for ( std::vector<GpgME::Key>::const_iterator sit = it->second.signKeys.begin() ; sit != it->second.signKeys.end() ; ++sit )
01416       std::cerr << sit->shortKeyID() << " ";
01417     std::cerr << std::endl;
01418     unsigned int i = 0;
01419     for ( std::vector<SplitInfo>::const_iterator sit = it->second.splitInfos.begin() ; sit != it->second.splitInfos.end() ; ++sit, ++i ) {
01420       std::cerr << "  SplitInfo #" << i << " encryption keys: ";
01421       for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit )
01422     std::cerr << kit->shortKeyID() << " ";
01423       std::cerr << std::endl
01424         << "  SplitInfo #" << i << " recipients: "
01425         << sit->recipients.join(", ").utf8() << std::endl;
01426     }
01427   }
01428 #endif
01429 }
01430 
01431 Kpgp::Result Kleo::KeyResolver::showKeyApprovalDialog() {
01432   const bool showKeysForApproval = showApprovalDialog()
01433     || std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01434              ApprovalNeeded ) != d->mPrimaryEncryptionKeys.end()
01435     || std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01436              ApprovalNeeded ) != d->mSecondaryEncryptionKeys.end() ;
01437 
01438   if ( !showKeysForApproval )
01439     return Kpgp::Ok;
01440 
01441   std::vector<Kleo::KeyApprovalDialog::Item> items;
01442   items.reserve( d->mPrimaryEncryptionKeys.size() +
01443              d->mSecondaryEncryptionKeys.size() );
01444   std::copy( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01445          std::back_inserter( items ) );
01446   std::copy( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01447          std::back_inserter( items ) );
01448 
01449   std::vector<GpgME::Key> senderKeys;
01450   senderKeys.reserve( d->mOpenPGPEncryptToSelfKeys.size() +
01451                   d->mSMIMEEncryptToSelfKeys.size() );
01452   std::copy( d->mOpenPGPEncryptToSelfKeys.begin(), d->mOpenPGPEncryptToSelfKeys.end(),
01453          std::back_inserter( senderKeys ) );
01454   std::copy( d->mSMIMEEncryptToSelfKeys.begin(), d->mSMIMEEncryptToSelfKeys.end(),
01455          std::back_inserter( senderKeys ) );
01456 
01457   const KCursorSaver idle( KBusyPtr::idle() );
01458 
01459   Kleo::KeyApprovalDialog dlg( items, senderKeys );
01460 
01461   if ( dlg.exec() == TQDialog::Rejected )
01462     return Kpgp::Canceled;
01463 
01464   items = dlg.items();
01465   senderKeys = dlg.senderKeys();
01466 
01467   if ( dlg.preferencesChanged() ) {
01468     for ( uint i = 0; i < items.size(); ++i ) {
01469       ContactPreferences pref = lookupContactPreferences( items[i].address );
01470       pref.encryptionPreference = items[i].pref;
01471       pref.pgpKeyFingerprints.clear();
01472       pref.smimeCertFingerprints.clear();
01473       const std::vector<GpgME::Key> & keys = items[i].keys;
01474       for ( std::vector<GpgME::Key>::const_iterator it = keys.begin(), end = keys.end() ; it != end ; ++it ) {
01475         if ( it->protocol() == GpgME::Context::OpenPGP ) {
01476           if ( const char * fpr = it->primaryFingerprint() )
01477             pref.pgpKeyFingerprints.push_back( fpr );
01478         } else if ( it->protocol() == GpgME::Context::CMS ) {
01479           if ( const char * fpr = it->primaryFingerprint() )
01480             pref.smimeCertFingerprints.push_back( fpr );
01481         }
01482       }
01483       saveContactPreference( items[i].address, pref );
01484     }
01485   }
01486 
01487   // show a warning if the user didn't select an encryption key for
01488   // herself:
01489   if ( encryptToSelf() && senderKeys.empty() ) {
01490     const TQString msg = i18n("You did not select an encryption key for yourself "
01491                  "(encrypt to self). You will not be able to decrypt "
01492                  "your own message if you encrypt it.");
01493     if ( KMessageBox::warningContinueCancel( 0, msg,
01494                          i18n("Missing Key Warning"),
01495                          i18n("&Encrypt") )
01496      == KMessageBox::Cancel )
01497       return Kpgp::Canceled;
01498     else
01499       mEncryptToSelf = false;
01500   }
01501 
01502   // count empty key ID lists
01503   const unsigned int emptyListCount =
01504     std::count_if( items.begin(), items.end(), EmptyKeyList );
01505 
01506   // show a warning if the user didn't select an encryption key for
01507   // some of the recipients
01508   if ( items.size() == emptyListCount  ) {
01509     const TQString msg = ( d->mPrimaryEncryptionKeys.size() +
01510               d->mSecondaryEncryptionKeys.size() == 1 )
01511                   ? i18n("You did not select an encryption key for the "
01512                          "recipient of this message; therefore, the message "
01513                          "will not be encrypted.")
01514                   : i18n("You did not select an encryption key for any of the "
01515                          "recipients of this message; therefore, the message "
01516                          "will not be encrypted.");
01517     if ( KMessageBox::warningContinueCancel( 0, msg,
01518                          i18n("Missing Key Warning"),
01519                          i18n("Send &Unencrypted") )
01520      == KMessageBox::Cancel )
01521       return Kpgp::Canceled;
01522   } else if ( emptyListCount > 0 ) {
01523     const TQString msg = ( emptyListCount == 1 )
01524                   ? i18n("You did not select an encryption key for one of "
01525                          "the recipients: this person will not be able to "
01526                          "decrypt the message if you encrypt it.")
01527                   : i18n("You did not select encryption keys for some of "
01528                          "the recipients: these persons will not be able to "
01529                          "decrypt the message if you encrypt it." );
01530     KCursorSaver idle( KBusyPtr::idle() );
01531     if ( KMessageBox::warningContinueCancel( 0, msg,
01532                          i18n("Missing Key Warning"),
01533                          i18n("&Encrypt") )
01534      == KMessageBox::Cancel )
01535       return Kpgp::Canceled;
01536   }
01537 
01538   std::transform( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01539           items.begin(),
01540           d->mPrimaryEncryptionKeys.begin(),
01541           CopyKeysAndEncryptionPreferences );
01542   std::transform( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01543           items.begin() + d->mPrimaryEncryptionKeys.size(),
01544           d->mSecondaryEncryptionKeys.begin(),
01545           CopyKeysAndEncryptionPreferences );
01546 
01547   d->mOpenPGPEncryptToSelfKeys.clear();
01548   d->mSMIMEEncryptToSelfKeys.clear();
01549 
01550   std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
01551                std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
01552                NotValidTrustedOpenPGPEncryptionKey ); // -= trusted (see above, too)?
01553   std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
01554                std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
01555                NotValidTrustedSMIMEEncryptionKey );   // -= trusted (see above, too)?
01556 
01557   return Kpgp::Ok;
01558 }
01559 
01560 std::vector<Kleo::KeyResolver::SplitInfo> Kleo::KeyResolver::encryptionItems( Kleo::CryptoMessageFormat f ) const {
01561   dump();
01562   std::map<CryptoMessageFormat,FormatInfo>::const_iterator it =
01563     d->mFormatInfoMap.find( f );
01564   return it != d->mFormatInfoMap.end() ? it->second.splitInfos : std::vector<SplitInfo>() ;
01565 }
01566 
01567 std::vector<GpgME::Key> Kleo::KeyResolver::signingKeys( CryptoMessageFormat f ) const {
01568   dump();
01569   std::map<CryptoMessageFormat,FormatInfo>::const_iterator it =
01570     d->mFormatInfoMap.find( f );
01571   return it != d->mFormatInfoMap.end() ? it->second.signKeys : std::vector<GpgME::Key>() ;
01572 }
01573 
01574 //
01575 //
01576 // Private helper methods below:
01577 //
01578 //
01579 
01580 
01581 std::vector<GpgME::Key> Kleo::KeyResolver::selectKeys( const TQString & person, const TQString & msg, const std::vector<GpgME::Key> & selectedKeys ) const {
01582   const bool opgp = containsOpenPGP( mCryptoMessageFormats );
01583   const bool x509 = containsSMIME( mCryptoMessageFormats );
01584 
01585   Kleo::KeySelectionDialog dlg( i18n("Encryption Key Selection"),
01586                 msg, KPIM::getEmailAddress(person), selectedKeys,
01587                                 Kleo::KeySelectionDialog::ValidEncryptionKeys
01588                                 & ~(opgp ? 0 : Kleo::KeySelectionDialog::OpenPGPKeys)
01589                                 & ~(x509 ? 0 : Kleo::KeySelectionDialog::SMIMEKeys),
01590                 true, true ); // multi-selection and "remember choice" box
01591 
01592   if ( dlg.exec() != TQDialog::Accepted )
01593     return std::vector<GpgME::Key>();
01594   std::vector<GpgME::Key> keys = dlg.selectedKeys();
01595   keys.erase( std::remove_if( keys.begin(), keys.end(),
01596                               NotValidTrustedEncryptionKey ), // -= trusted?
01597                               keys.end() );
01598   if ( !keys.empty() && dlg.rememberSelection() )
01599     setKeysForAddress( person, dlg.pgpKeyFingerprints(), dlg.smimeFingerprints() );
01600   return keys;
01601 }
01602 
01603 
01604 std::vector<GpgME::Key> Kleo::KeyResolver::getEncryptionKeys( const TQString & person, bool quiet ) const {
01605 
01606   const TQString address = canonicalAddress( person ).lower();
01607 
01608   // First look for this person's address in the address->key dictionary
01609   const TQStringList fingerprints = keysForAddress( address );
01610 
01611   if ( !fingerprints.empty() ) {
01612     kdDebug() << "Using encryption keys 0x"
01613           << fingerprints.join( ", 0x" )
01614           << " for " << person << endl;
01615     std::vector<GpgME::Key> keys = lookup( fingerprints );
01616     if ( !keys.empty() ) {
01617       // Check if all of the keys are trusted and valid encryption keys
01618       if ( std::find_if( keys.begin(), keys.end(),
01619                          NotValidTrustedEncryptionKey ) != keys.end() ) { // -= trusted?
01620 
01621         // not ok, let the user select: this is not conditional on !quiet,
01622         // since it's a bug in the configuration and the user should be
01623         // notified about it as early as possible:
01624         keys = selectKeys( person,
01625             i18n("if in your language something like "
01626               "'certificate(s)' isn't possible please "
01627               "use the plural in the translation",
01628               "There is a problem with the "
01629               "encryption certificate(s) for \"%1\".\n\n"
01630               "Please re-select the certificate(s) which should "
01631               "be used for this recipient.").arg(person),
01632             keys );
01633       }
01634       bool canceled = false;
01635       keys = trustedOrConfirmed( keys, address, canceled );
01636       if ( canceled )
01637           return std::vector<GpgME::Key>();
01638 
01639       if ( !keys.empty() )
01640         return keys;
01641       // keys.empty() is considered cancel by callers, so go on
01642     }
01643   }
01644 
01645   // Now search all public keys for matching keys
01646   std::vector<GpgME::Key> matchingKeys = lookup( person );
01647   matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
01648                       NotValidEncryptionKey ),
01649               matchingKeys.end() );
01650   // if no keys match the complete address look for keys which match
01651   // the canonical mail address
01652   if ( matchingKeys.empty() ) {
01653     matchingKeys = lookup( address );
01654     matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
01655                     NotValidEncryptionKey ),
01656             matchingKeys.end() );
01657   }
01658 
01659   // if called with quite == true (from EncryptionPreferenceCounter), we only want to
01660   // check if there are keys for this recipients, not (yet) their validity, so
01661   // don't show the untrusted encryption key warning in that case
01662   bool canceled = false;
01663   if ( !quiet )
01664       matchingKeys = trustedOrConfirmed( matchingKeys, address, canceled );
01665   if ( canceled )
01666       return std::vector<GpgME::Key>();
01667   if ( quiet || matchingKeys.size() == 1 )
01668     return matchingKeys;
01669 
01670   // no match until now, or more than one key matches; let the user
01671   // choose the key(s)
01672   // FIXME: let user get the key from keyserver
01673   return trustedOrConfirmed( selectKeys( person,
01674           matchingKeys.empty()
01675           ? i18n("if in your language something like "
01676               "'certificate(s)' isn't possible please "
01677               "use the plural in the translation",
01678               "<qt>No valid and trusted encryption certificate was "
01679               "found for \"%1\".<br/><br/>"
01680               "Select the certificate(s) which should "
01681               "be used for this recipient. If there is no suitable certificate in the list "
01682               "you can also search for external certificates by clicking the button: search for external certificates.</qt>")
01683              .arg( TQStyleSheet::escape(person) )
01684           : i18n("if in your language something like "
01685               "'certificate(s)' isn't possible please "
01686               "use the plural in the translation",
01687               "More than one certificate matches \"%1\".\n\n"
01688               "Select the certificate(s) which should "
01689               "be used for this recipient.").arg( TQStyleSheet::escape(person) ),
01690           matchingKeys ), address, canceled );
01691   // we can ignore 'canceled' here, since trustedOrConfirmed() returns
01692   // an empty vector when canceled == true, and we'd just do the same
01693 }
01694 
01695 
01696 std::vector<GpgME::Key> Kleo::KeyResolver::lookup( const TQStringList & patterns, bool secret ) const {
01697   if ( patterns.empty() )
01698     return std::vector<GpgME::Key>();
01699   kdDebug() << "Kleo::KeyResolver::lookup( \"" << patterns.join( "\", \"" )
01700         << "\", " << secret << " )" << endl;
01701   std::vector<GpgME::Key> result;
01702   if ( mCryptoMessageFormats & (InlineOpenPGPFormat|OpenPGPMIMEFormat) )
01703     if ( const Kleo::CryptoBackend::Protocol * p = Kleo::CryptoBackendFactory::instance()->openpgp() ) {
01704       std::auto_ptr<Kleo::KeyListJob> job( p->keyListJob( false, false, true ) ); // use validating keylisting
01705       if ( job.get() ) {
01706     std::vector<GpgME::Key> keys;
01707     job->exec( patterns, secret, keys );
01708     result.insert( result.end(), keys.begin(), keys.end() );
01709       }
01710     }
01711   if ( mCryptoMessageFormats & (SMIMEFormat|SMIMEOpaqueFormat) )
01712     if ( const Kleo::CryptoBackend::Protocol * p = Kleo::CryptoBackendFactory::instance()->smime() ) {
01713       std::auto_ptr<Kleo::KeyListJob> job( p->keyListJob( false, false, true ) ); // use validating keylisting
01714       if ( job.get() ) {
01715     std::vector<GpgME::Key> keys;
01716     job->exec( patterns, secret, keys );
01717     result.insert( result.end(), keys.begin(), keys.end() );
01718       }
01719     }
01720   kdDebug() << "  returned " << result.size() << " keys" << endl;
01721   return result;
01722 }
01723 
01724 void Kleo::KeyResolver::addKeys( const std::vector<Item> & items, CryptoMessageFormat f ) {
01725   dump();
01726   for ( std::vector<Item>::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
01727     SplitInfo si( it->address );
01728     std::remove_copy_if( it->keys.begin(), it->keys.end(),
01729              std::back_inserter( si.keys ), IsNotForFormat( f ) );
01730     dump();
01731     kdWarning( si.keys.empty() )
01732       << "Kleo::KeyResolver::addKeys(): Fix EncryptionFormatPreferenceCounter. "
01733       << "It detected a common format, but the list of such keys for recipient \""
01734       << it->address << "\" is empty!" << endl;
01735     d->mFormatInfoMap[ f ].splitInfos.push_back( si );
01736   }
01737   dump();
01738 }
01739 
01740 void Kleo::KeyResolver::addKeys( const std::vector<Item> & items ) {
01741   dump();
01742   for ( std::vector<Item>::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
01743     SplitInfo si( it->address );
01744     CryptoMessageFormat f = AutoFormat;
01745     for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
01746       const CryptoMessageFormat fmt = concreteCryptoMessageFormats[i];
01747       if ( ( fmt & it->format ) &&
01748            kdtools::any( it->keys.begin(), it->keys.end(), IsForFormat( fmt ) ) )
01749       {
01750         f = fmt;
01751         break;
01752       }
01753     }
01754     if ( f == AutoFormat )
01755       kdWarning() << "Kleo::KeyResolver::addKeys(): Something went wrong. Didn't find a format for \""
01756                   << it->address << "\"" << endl;
01757     else
01758       std::remove_copy_if( it->keys.begin(), it->keys.end(),
01759                            std::back_inserter( si.keys ), IsNotForFormat( f ) );
01760     d->mFormatInfoMap[ f ].splitInfos.push_back( si );
01761   }
01762   dump();
01763 }
01764 
01765 Kleo::KeyResolver::ContactPreferences Kleo::KeyResolver::lookupContactPreferences( const TQString& address ) const
01766 {
01767   const Private::ContactPreferencesMap::iterator it =
01768     d->mContactPreferencesMap.find( address );
01769   if ( it != d->mContactPreferencesMap.end() )
01770     return it->second;
01771 
01772   KABC::AddressBook *ab = KABC::StdAddressBook::self( true );
01773   const KABC::Addressee::List res = ab->findByEmail( address );
01774   ContactPreferences pref;
01775   if ( !res.isEmpty() ) {
01776     KABC::Addressee addr = res.first();
01777     TQString encryptPref = addr.custom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF" );
01778     pref.encryptionPreference = Kleo::stringToEncryptionPreference( encryptPref );
01779     TQString signPref = addr.custom( "KADDRESSBOOK", "CRYPTOSIGNPREF" );
01780     pref.signingPreference = Kleo::stringToSigningPreference( signPref );
01781     TQString cryptoFormats = addr.custom( "KADDRESSBOOK", "CRYPTOPROTOPREF" );
01782     pref.cryptoMessageFormat = Kleo::stringToCryptoMessageFormat( cryptoFormats );
01783     pref.pgpKeyFingerprints = TQStringList::split( ',', addr.custom( "KADDRESSBOOK", "OPENPGPFP" ) );
01784     pref.smimeCertFingerprints = TQStringList::split( ',', addr.custom( "KADDRESSBOOK", "SMIMEFP" ) );
01785   }
01786   // insert into map and grab resulting iterator
01787   d->mContactPreferencesMap.insert( std::make_pair( address, pref ) );
01788   return pref;
01789 }
01790 
01791 void Kleo::KeyResolver::saveContactPreference( const TQString& email, const ContactPreferences& pref ) const
01792 {
01793   d->mContactPreferencesMap.insert( std::make_pair( email, pref ) );
01794   KABC::AddressBook *ab = KABC::StdAddressBook::self( true );
01795   KABC::Addressee::List res = ab->findByEmail( email );
01796 
01797   KABC::Addressee addr;
01798   if ( res.isEmpty() ) {
01799      bool ok = true;
01800      TQString fullName = KInputDialog::getText( i18n( "Name Selection" ), i18n( "Which name shall the contact '%1' have in your addressbook?" ).arg( email ), TQString::null, &ok );
01801     if ( ok ) {
01802       addr.setNameFromString( fullName );
01803       addr.insertEmail( email, true );
01804     } else
01805       return;
01806   } else
01807     addr = res.first();
01808 
01809   addr.insertCustom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF", Kleo::encryptionPreferenceToString( pref.encryptionPreference ) );
01810   addr.insertCustom( "KADDRESSBOOK", "CRYPTOSIGNPREF", Kleo::signingPreferenceToString( pref.signingPreference ) );
01811   addr.insertCustom( "KADDRESSBOOK", "CRYPTOPROTOPREF", cryptoMessageFormatToString( pref.cryptoMessageFormat ) );
01812   addr.insertCustom( "KADDRESSBOOK", "OPENPGPFP", pref.pgpKeyFingerprints.join( "," ) );
01813   addr.insertCustom( "KADDRESSBOOK", "SMIMEFP", pref.smimeCertFingerprints.join( "," ) );
01814 
01815   ab->insertAddressee( addr );
01816   KABC::Ticket *ticket = ab->requestSaveTicket( addr.resource() );
01817   if ( ticket )
01818     ab->save( ticket );
01819 
01820   // Assumption: 'pref' comes from d->mContactPreferencesMap already, no need to update that
01821 }
01822 
01823 Kleo::KeyResolver::ContactPreferences::ContactPreferences()
01824   : encryptionPreference( UnknownPreference ),
01825     signingPreference( UnknownSigningPreference ),
01826     cryptoMessageFormat( AutoFormat )
01827 {
01828 }
01829 
01830 TQStringList Kleo::KeyResolver::keysForAddress( const TQString & address ) const {
01831   if( address.isEmpty() ) {
01832     return TQStringList();
01833   }
01834   TQString addr = canonicalAddress( address ).lower();
01835   const ContactPreferences pref = lookupContactPreferences( addr );
01836   return pref.pgpKeyFingerprints + pref.smimeCertFingerprints;
01837 }
01838 
01839 void Kleo::KeyResolver::setKeysForAddress( const TQString& address, const TQStringList& pgpKeyFingerprints, const TQStringList& smimeCertFingerprints ) const {
01840   if( address.isEmpty() ) {
01841     return;
01842   }
01843   TQString addr = canonicalAddress( address ).lower();
01844   ContactPreferences pref = lookupContactPreferences( addr );
01845   pref.pgpKeyFingerprints = pgpKeyFingerprints;
01846   pref.smimeCertFingerprints = smimeCertFingerprints;
01847   saveContactPreference( addr, pref );
01848 }