kmail Library API Documentation

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