kmail

keyresolver.cpp

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