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