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