kmail

keyresolver.cpp

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