• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kmail

keyresolver.cpp

Go to the documentation of this file.
00001 /*  -*- c++ -*-
00002     keyresolver.cpp
00003 
00004     This file is part of libkleopatra, the KDE keymanagement library
00005     Copyright (c) 2004 Klarälvdalens Datakonsult AB
00006 
00007     Based on kpgp.cpp
00008     Copyright (C) 2001,2002 the KPGP authors
00009     See file libkdenetwork/AUTHORS.kpgp for details
00010 
00011     Libkleopatra is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU General Public License as
00013     published by the Free Software Foundation; either version 2 of the
00014     License, or (at your option) any later version.
00015 
00016     Libkleopatra is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019     General Public License for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with this program; if not, write to the Free Software
00023     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00024 
00025     In addition, as a special exception, the copyright holders give
00026     permission to link the code of this program with any edition of
00027     the Qt library by Trolltech AS, Norway (or with modified versions
00028     of Qt that use the same license as Qt), and distribute linked
00029     combinations including the two.  You must obey the GNU General
00030     Public License in all respects for all of the code used other than
00031     Qt.  If you modify this file, you may extend this exception to
00032     your version of the file, but you are not obligated to do so.  If
00033     you do not wish to do so, delete this exception statement from
00034     your version.
00035 */
00036 
00037 #include "keyresolver.h"
00038 
00039 #include "kcursorsaver.h"
00040 #include "kleo_util.h"
00041 
00042 #include <kpimutils/email.h>
00043 #include "libkleo/ui/keyselectiondialog.h"
00044 #include "kleo/cryptobackendfactory.h"
00045 #include "kleo/keylistjob.h"
00046 #include "kleo/dn.h"
00047 
00048 #include <gpgme++/key.h>
00049 #include <gpgme++/keylistresult.h>
00050 
00051 #include <kabc/stdaddressbook.h>
00052 #include <klocale.h>
00053 #include <kdebug.h>
00054 #include <kinputdialog.h>
00055 #include <kmessagebox.h>
00056 
00057 #include <QStringList>
00058 #include <time.h>
00059 
00060 #include <algorithm>
00061 #include <memory>
00062 #include <iterator>
00063 #include <functional>
00064 #include <map>
00065 #include <set>
00066 #include <iostream>
00067 #include <cassert>
00068 
00069 
00070 //
00071 // some predicates to be used in STL algorithms:
00072 //
00073 
00074 static inline bool EmptyKeyList( const Kleo::KeyApprovalDialog::Item & item ) {
00075   return item.keys.empty();
00076 }
00077 
00078 static inline QString ItemDotAddress( const Kleo::KeyResolver::Item & item ) {
00079   return item.address;
00080 }
00081 
00082 static inline bool ApprovalNeeded( const Kleo::KeyResolver::Item & item ) {
00083   return item.pref == Kleo::UnknownPreference || item.pref == Kleo::NeverEncrypt || item.keys.empty() ;
00084 }
00085 
00086 static inline Kleo::KeyResolver::Item
00087 CopyKeysAndEncryptionPreferences( const Kleo::KeyResolver::Item & oldItem,
00088                   const Kleo::KeyApprovalDialog::Item & newItem ) {
00089   return Kleo::KeyResolver::Item( oldItem.address, newItem.keys, newItem.pref, oldItem.signPref, oldItem.format );
00090 }
00091 
00092 static inline bool ByKeyID( const GpgME::Key & left, const GpgME::Key & right ) {
00093   return qstrcmp( left.keyID(), right.keyID() ) < 0 ;
00094 }
00095 
00096 static inline bool WithRespectToKeyID( const GpgME::Key & left, const GpgME::Key & right ) {
00097   return qstrcmp( left.keyID(), right.keyID() ) == 0 ;
00098 }
00099 
00100 static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
00101   if ( key.protocol() != GpgME::OpenPGP ) {
00102     return false;
00103   }
00104 #if 0
00105   if ( key.isRevoked() )
00106     kWarning(5006) <<" is revoked";
00107   if ( key.isExpired() )
00108     kWarning(5006) <<" is expired";
00109   if ( key.isDisabled() )
00110     kWarning(5006) <<" is disabled";
00111   if ( !key.canEncrypt() )
00112     kWarning(5006) <<" can't encrypt";
00113 #endif
00114   if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
00115     return false;
00116   const std::vector<GpgME::UserID> uids = key.userIDs();
00117   for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
00118     if ( !it->isRevoked() && it->validity() != GpgME::UserID::Marginal )
00119       return true;
00120 #if 0
00121     else
00122       if ( it->isRevoked() )
00123         kWarning(5006) <<"a userid is revoked";
00124       else
00125         kWarning(5006) <<"bad validity" << it->validity();
00126 #endif
00127   }
00128   return false;
00129 }
00130 
00131 static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
00132   if ( key.protocol() != GpgME::CMS )
00133     return false;
00134   if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
00135     return false;
00136   return true;
00137 }
00138 
00139 static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
00140   switch ( key.protocol() ) {
00141   case GpgME::OpenPGP:
00142     return ValidTrustedOpenPGPEncryptionKey( key );
00143   case GpgME::CMS:
00144     return ValidTrustedSMIMEEncryptionKey( key );
00145   default:
00146     return false;
00147   }
00148 }
00149 
00150 static inline bool ValidSigningKey( const GpgME::Key & key ) {
00151   if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign() )
00152     return false;
00153   return key.hasSecret();
00154 }
00155 
00156 static inline bool ValidOpenPGPSigningKey( const GpgME::Key & key ) {
00157   return key.protocol() == GpgME::OpenPGP && ValidSigningKey( key );
00158 }
00159 
00160 static inline bool ValidSMIMESigningKey( const GpgME::Key & key ) {
00161   return key.protocol() == GpgME::CMS && ValidSigningKey( key );
00162 }
00163 
00164 static inline bool NotValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
00165   return !ValidTrustedOpenPGPEncryptionKey( key );
00166 }
00167 
00168 static inline bool NotValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
00169   return !ValidTrustedSMIMEEncryptionKey( key );
00170 }
00171 
00172 static inline bool NotValidTrustedEncryptionKey( const GpgME::Key & key ) {
00173   return !ValidTrustedEncryptionKey( key );
00174 }
00175 
00176 static inline bool NotValidSigningKey( const GpgME::Key & key ) {
00177   return !ValidSigningKey( key );
00178 }
00179 
00180 static inline bool NotValidOpenPGPSigningKey( const GpgME::Key & key ) {
00181   return !ValidOpenPGPSigningKey( key );
00182 }
00183 
00184 static inline bool NotValidSMIMESigningKey( const GpgME::Key & key ) {
00185   return !ValidSMIMESigningKey( key );
00186 }
00187 
00188 static QStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) {
00189   QStringList strings;
00190   for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) {
00191     assert( !(*it).userID(0).isNull() );
00192     QString keyLabel = QString::fromUtf8( (*it).userID(0).email() );
00193     if ( keyLabel.isEmpty() )
00194       keyLabel = QString::fromUtf8( (*it).userID(0).name() );
00195     if ( keyLabel.isEmpty() )
00196       keyLabel = QString::fromUtf8( (*it).userID(0).id() );
00197     strings.append( keyLabel );
00198   }
00199   return strings;
00200 }
00201 
00202 static inline std::vector<GpgME::Key> TrustedOrConfirmed( const std::vector<GpgME::Key> & keys ) {
00203 
00204   std::vector<GpgME::Key> fishies;
00205   std::vector<GpgME::Key> ickies;
00206   std::vector<GpgME::Key>::const_iterator it = keys.begin();
00207   const std::vector<GpgME::Key>::const_iterator end = keys.end();
00208   for ( ; it != end ; ++it ) {
00209     const GpgME::Key key = *it;
00210     assert( ValidTrustedEncryptionKey( key ) );
00211     const std::vector<GpgME::UserID> uids = key.userIDs();
00212     for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
00213       if ( !it->isRevoked()  && it->validity() == GpgME::UserID::Marginal ) {
00214         fishies.push_back( key );
00215         break;
00216       }
00217       if ( !it->isRevoked()  && it->validity() < GpgME::UserID::Never ) {
00218         ickies.push_back( key );
00219         break;
00220       }
00221     }
00222   }
00223 
00224   if ( fishies.empty() && ickies.empty() )
00225     return keys;
00226 
00227   // if  some keys are not fully trusted, let the user confirm their use
00228   QString msg = i18n("One or more of your configured OpenPGP encryption "
00229                       "keys or S/MIME certificates is not fully trusted "
00230                       "for encryption.");
00231 
00232   if ( !fishies.empty() ) {
00233     // certificates can't have marginal trust
00234     msg += i18n( "\nThe following keys are only marginally trusted: \n");
00235     msg += keysAsStrings( fishies ).join(",");
00236   }
00237   if ( !ickies.empty() ) {
00238     msg += i18n( "\nThe following keys or certificates have unknown trust level: \n");
00239     msg += keysAsStrings( ickies ).join(",");
00240   }
00241 
00242   if( KMessageBox::warningContinueCancel( 0, msg, i18n("Not Fully Trusted Encryption Keys"),
00243                                           KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
00244                                           "not fully trusted encryption key warning" )
00245           == KMessageBox::Continue )
00246     return keys;
00247   else
00248     return std::vector<GpgME::Key>();
00249 }
00250 
00251 namespace {
00252   struct IsNotForFormat : public std::unary_function<GpgME::Key,bool> {
00253     IsNotForFormat( Kleo::CryptoMessageFormat f ) : format( f ) {}
00254 
00255     bool operator()( const GpgME::Key & key ) const {
00256       return
00257     ( isOpenPGP( format ) && key.protocol() != GpgME::OpenPGP ) ||
00258     ( isSMIME( format )   && key.protocol() != GpgME::CMS );
00259     }
00260 
00261     const Kleo::CryptoMessageFormat format;
00262   };
00263 }
00264 
00265 
00266 
00267 class Kleo::KeyResolver::SigningPreferenceCounter : public std::unary_function<Kleo::KeyResolver::Item,void> {
00268 public:
00269   SigningPreferenceCounter()
00270     : mTotal( 0 ),
00271       mUnknownSigningPreference( 0 ),
00272       mNeverSign( 0 ),
00273       mAlwaysSign( 0 ),
00274       mAlwaysSignIfPossible( 0 ),
00275       mAlwaysAskForSigning( 0 ),
00276       mAskSigningWheneverPossible( 0 )
00277   {
00278 
00279   }
00280   void operator()( const Kleo::KeyResolver::Item & item );
00281 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
00282   make_int_accessor(UnknownSigningPreference)
00283   make_int_accessor(NeverSign)
00284   make_int_accessor(AlwaysSign)
00285   make_int_accessor(AlwaysSignIfPossible)
00286   make_int_accessor(AlwaysAskForSigning)
00287   make_int_accessor(AskSigningWheneverPossible)
00288   make_int_accessor(Total)
00289 #undef make_int_accessor
00290 private:
00291   unsigned int mTotal;
00292   unsigned int mUnknownSigningPreference, mNeverSign, mAlwaysSign,
00293     mAlwaysSignIfPossible, mAlwaysAskForSigning, mAskSigningWheneverPossible;
00294 };
00295 
00296 void Kleo::KeyResolver::SigningPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
00297   switch ( item.signPref ) {
00298 #define CASE(x) case x: ++m##x; break
00299     CASE(UnknownSigningPreference);
00300     CASE(NeverSign);
00301     CASE(AlwaysSign);
00302     CASE(AlwaysSignIfPossible);
00303     CASE(AlwaysAskForSigning);
00304     CASE(AskSigningWheneverPossible);
00305 #undef CASE
00306   }
00307   ++mTotal;
00308 }
00309 
00310 
00311 
00312 class Kleo::KeyResolver::EncryptionPreferenceCounter : public std::unary_function<Item,void> {
00313   const Kleo::KeyResolver * _this;
00314 public:
00315   EncryptionPreferenceCounter( const Kleo::KeyResolver * kr, EncryptionPreference defaultPreference )
00316     : _this( kr ),
00317       mDefaultPreference( defaultPreference ),
00318       mTotal( 0 ),
00319       mNoKey( 0 ),
00320       mNeverEncrypt( 0 ),
00321       mUnknownPreference( 0 ),
00322       mAlwaysEncrypt( 0 ),
00323       mAlwaysEncryptIfPossible( 0 ),
00324       mAlwaysAskForEncryption( 0 ),
00325       mAskWheneverPossible( 0 )
00326   {
00327 
00328   }
00329   void operator()( Item & item );
00330 
00331 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
00332   make_int_accessor(NoKey)
00333   make_int_accessor(NeverEncrypt)
00334   make_int_accessor(UnknownPreference)
00335   make_int_accessor(AlwaysEncrypt)
00336   make_int_accessor(AlwaysEncryptIfPossible)
00337   make_int_accessor(AlwaysAskForEncryption)
00338   make_int_accessor(AskWheneverPossible)
00339   make_int_accessor(Total)
00340 #undef make_int_accessor
00341 private:
00342   EncryptionPreference mDefaultPreference;
00343   unsigned int mTotal;
00344   unsigned int mNoKey;
00345   unsigned int mNeverEncrypt, mUnknownPreference, mAlwaysEncrypt,
00346     mAlwaysEncryptIfPossible, mAlwaysAskForEncryption, mAskWheneverPossible;
00347 };
00348 
00349 void Kleo::KeyResolver::EncryptionPreferenceCounter::operator()( Item & item ) {
00350   if ( item.needKeys )
00351     item.keys = _this->getEncryptionKeys( item.address, true );
00352   if ( item.keys.empty() ) {
00353     ++mNoKey;
00354     return;
00355   }
00356   switch ( !item.pref ? mDefaultPreference : item.pref ) {
00357 #define CASE(x) case Kleo::x: ++m##x; break
00358     CASE(NeverEncrypt);
00359     CASE(UnknownPreference);
00360     CASE(AlwaysEncrypt);
00361     CASE(AlwaysEncryptIfPossible);
00362     CASE(AlwaysAskForEncryption);
00363     CASE(AskWheneverPossible);
00364 #undef CASE
00365   }
00366   ++mTotal;
00367 }
00368 
00369 namespace {
00370 
00371   class FormatPreferenceCounterBase : public std::unary_function<Kleo::KeyResolver::Item,void> {
00372   public:
00373     FormatPreferenceCounterBase()
00374       : mTotal( 0 ),
00375     mInlineOpenPGP( 0 ),
00376     mOpenPGPMIME( 0 ),
00377     mSMIME( 0 ),
00378     mSMIMEOpaque( 0 )
00379     {
00380 
00381     }
00382 
00383 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
00384     make_int_accessor(Total)
00385     make_int_accessor(InlineOpenPGP)
00386     make_int_accessor(OpenPGPMIME)
00387     make_int_accessor(SMIME)
00388     make_int_accessor(SMIMEOpaque)
00389 #undef make_int_accessor
00390 
00391     unsigned int numOf( Kleo::CryptoMessageFormat f ) const {
00392       switch ( f ) {
00393 #define CASE(x) case Kleo::x##Format: return m##x
00394     CASE(InlineOpenPGP);
00395     CASE(OpenPGPMIME);
00396     CASE(SMIME);
00397     CASE(SMIMEOpaque);
00398 #undef CASE
00399       default: return 0;
00400       }
00401     }
00402 
00403   protected:
00404     unsigned int mTotal;
00405     unsigned int mInlineOpenPGP, mOpenPGPMIME, mSMIME, mSMIMEOpaque;
00406   };
00407 
00408   class EncryptionFormatPreferenceCounter : public FormatPreferenceCounterBase {
00409   public:
00410     EncryptionFormatPreferenceCounter() : FormatPreferenceCounterBase() {}
00411     void operator()( const Kleo::KeyResolver::Item & item );
00412   };
00413 
00414   class SigningFormatPreferenceCounter : public FormatPreferenceCounterBase {
00415   public:
00416     SigningFormatPreferenceCounter() : FormatPreferenceCounterBase() {}
00417     void operator()( const Kleo::KeyResolver::Item & item );
00418   };
00419 
00420 #define CASE(x) if ( item.format & Kleo::x##Format ) ++m##x;
00421   void EncryptionFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
00422     if ( item.format & (Kleo::InlineOpenPGPFormat|Kleo::OpenPGPMIMEFormat) &&
00423      std::find_if( item.keys.begin(), item.keys.end(),
00424                ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) {
00425       CASE(OpenPGPMIME);
00426       CASE(InlineOpenPGP);
00427     }
00428     if ( item.format & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) &&
00429      std::find_if( item.keys.begin(), item.keys.end(),
00430                ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) {
00431       CASE(SMIME);
00432       CASE(SMIMEOpaque);
00433     }
00434     ++mTotal;
00435   }
00436 
00437   void SigningFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
00438     CASE(InlineOpenPGP);
00439     CASE(OpenPGPMIME);
00440     CASE(SMIME);
00441     CASE(SMIMEOpaque);
00442     ++mTotal;
00443   }
00444 #undef CASE
00445 
00446 } // anon namespace
00447 
00448 static QString canonicalAddress( const QString & _address ) {
00449   const QString address = KPIMUtils::extractEmailAddress( _address );
00450   if ( !address.contains('@') ) {
00451     // local address
00452     //return address + '@' + KNetwork::KResolver::localHostName();
00453     return address + "@localdomain";
00454   }
00455   else
00456     return address;
00457 }
00458 
00459 
00460 struct FormatInfo {
00461   std::vector<Kleo::KeyResolver::SplitInfo> splitInfos;
00462   std::vector<GpgME::Key> signKeys;
00463 };
00464 
00465 struct Kleo::KeyResolver::Private {
00466   std::set<QByteArray> alreadyWarnedFingerprints;
00467 
00468   std::vector<GpgME::Key> mOpenPGPSigningKeys; // signing
00469   std::vector<GpgME::Key> mSMIMESigningKeys; // signing
00470 
00471   std::vector<GpgME::Key> mOpenPGPEncryptToSelfKeys; // encryption to self
00472   std::vector<GpgME::Key> mSMIMEEncryptToSelfKeys; // encryption to self
00473 
00474   std::vector<Item> mPrimaryEncryptionKeys; // encryption to To/CC
00475   std::vector<Item> mSecondaryEncryptionKeys; // encryption to BCC
00476 
00477   std::map<CryptoMessageFormat,FormatInfo> mFormatInfoMap;
00478 
00479   // key=email address, value=crypto preferences for this contact (from kabc)
00480   typedef std::map<QString, ContactPreferences> ContactPreferencesMap;
00481   ContactPreferencesMap mContactPreferencesMap;
00482 };
00483 
00484 
00485 Kleo::KeyResolver::KeyResolver( bool encToSelf, bool showApproval, bool oppEncryption,
00486                 unsigned int f,
00487                 int encrWarnThresholdKey, int signWarnThresholdKey,
00488                 int encrWarnThresholdRootCert, int signWarnThresholdRootCert,
00489                 int encrWarnThresholdChainCert, int signWarnThresholdChainCert )
00490   : mEncryptToSelf( encToSelf ),
00491     mShowApprovalDialog( showApproval ),
00492     mOpportunisticEncyption( oppEncryption ),
00493     mCryptoMessageFormats( f ),
00494     mEncryptKeyNearExpiryWarningThreshold( encrWarnThresholdKey ),
00495     mSigningKeyNearExpiryWarningThreshold( signWarnThresholdKey ),
00496     mEncryptRootCertNearExpiryWarningThreshold( encrWarnThresholdRootCert ),
00497     mSigningRootCertNearExpiryWarningThreshold( signWarnThresholdRootCert ),
00498     mEncryptChainCertNearExpiryWarningThreshold( encrWarnThresholdChainCert ),
00499     mSigningChainCertNearExpiryWarningThreshold( signWarnThresholdChainCert )
00500 {
00501   d = new Private();
00502 }
00503 
00504 Kleo::KeyResolver::~KeyResolver() {
00505   delete d; d = 0;
00506 }
00507 
00508 Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, const char * dontAskAgainName,
00509                                                     bool mine, bool sign, bool ca,
00510                                                     int recur_limit, const GpgME::Key & orig ) const
00511 {
00512   if ( recur_limit <= 0 ) {
00513     kDebug(5006) << "Key chain too long (>100 certs)";
00514     return Kpgp::Ok;
00515   }
00516   const GpgME::Subkey subkey = key.subkey(0);
00517   if ( d->alreadyWarnedFingerprints.count( subkey.fingerprint() ) )
00518     return Kpgp::Ok; // already warned about this one (and so about it's issuers)
00519   d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
00520 
00521   if ( subkey.neverExpires() )
00522     return Kpgp::Ok;
00523   static const double secsPerDay = 24 * 60 * 60;
00524   const int daysTillExpiry =
00525     1 + int( ::difftime( subkey.expirationTime(), time(0) ) / secsPerDay );
00526   kDebug(5006) <<"Key 0x" << key.shortKeyID() <<"expires in less than"
00527                << daysTillExpiry << "days";
00528   const int threshold =
00529     ca
00530     ? ( key.isRoot()
00531     ? ( sign
00532         ? signingRootCertNearExpiryWarningThresholdInDays()
00533         : encryptRootCertNearExpiryWarningThresholdInDays() )
00534     : ( sign
00535         ? signingChainCertNearExpiryWarningThresholdInDays()
00536         : encryptChainCertNearExpiryWarningThresholdInDays() ) )
00537     : ( sign
00538     ? signingKeyNearExpiryWarningThresholdInDays()
00539     : encryptKeyNearExpiryWarningThresholdInDays() );
00540   if ( threshold > -1 && daysTillExpiry <= threshold ) {
00541     const QString msg =
00542       key.protocol() == GpgME::OpenPGP
00543       ? ( mine ? sign
00544       ? ki18np("<p>Your OpenPGP signing key</p><p align=\"center\"><b>%2</b> (KeyID 0x%3)</p>"
00545            "<p>expires in less than a day.</p>",
00546            "<p>Your OpenPGP signing key</p><p align=\"center\"><b>%2</b> (KeyID 0x%3)</p>"
00547            "<p>expires in less than %1 days.</p>")
00548       : ki18np("<p>Your OpenPGP encryption key</p><p align=\"center\"><b>%2</b> (KeyID 0x%3)</p>"
00549            "<p>expires in less than a day.</p>",
00550            "<p>Your OpenPGP encryption key</p><p align=\"center\"><b>%2</b> (KeyID 0x%3)</p>"
00551            "<p>expires in less than %1 days.</p>")
00552       : ki18np("<p>The OpenPGP key for</p><p align=\"center\"><b>%2</b> (KeyID 0x%3)</p>"
00553            "<p>expires in less than a day.</p>",
00554            "<p>The OpenPGP key for</p><p align=\"center\"><b>%2</b> (KeyID 0x%3)</p>"
00555            "<p>expires in less than %1 days.</p>") )
00556           .subs( daysTillExpiry )
00557           .subs( QString::fromUtf8( key.userID(0).id() ) )
00558           .subs( key.shortKeyID() )
00559           .toString()
00560       : ( ca
00561       ? ( key.isRoot()
00562           ? ( mine ? sign
00563           ? ki18np("<p>The root certificate</p><p align=\"center\"><b>%4</b></p>"
00564                "<p>for your S/MIME signing certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00565                "<p>expires in less than a day.</p>",
00566                "<p>The root certificate</p><p align=\"center\"><b>%4</b></p>"
00567                "<p>for your S/MIME signing certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00568                "<p>expires in less than %1 days.</p>")
00569           : ki18np("<p>The root certificate</p><p align=\"center\"><b>%4</b></p>"
00570                "<p>for your S/MIME encryption certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00571                "<p>expires in less than a day.</p>",
00572                "<p>The root certificate</p><p align=\"center\"><b>%4</b></p>"
00573                "<p>for your S/MIME encryption certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00574                "<p>expires in less than %1 days.</p>")
00575           : ki18np("<p>The root certificate</p><p align=\"center\"><b>%4</b></p>"
00576                "<p>for S/MIME certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00577                "<p>expires in less than a day.</p>",
00578                "<p>The root certificate</p><p align=\"center\"><b>%4</b></p>"
00579                "<p>for S/MIME certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00580                "<p>expires in less than %1 days.</p>") )
00581           : ( mine ? sign
00582           ? ki18np("<p>The intermediate CA certificate</p><p align=\"center\"><b>%4</b></p>"
00583                "<p>for your S/MIME signing certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00584                "<p>expires in less than a day.</p>",
00585                "<p>The intermediate CA certificate</p><p align=\"center\"><b>%4</b></p>"
00586                "<p>for your S/MIME signing certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00587                "<p>expires in less than %1 days.</p>")
00588           : ki18np("<p>The intermediate CA certificate</p><p align=\"center\"><b>%4</b></p>"
00589                "<p>for your S/MIME encryption certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00590                "<p>expires in less than a day.</p>",
00591                "<p>The intermediate CA certificate</p><p align=\"center\"><b>%4</b></p>"
00592                "<p>for your S/MIME encryption certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00593                "<p>expires in less than %1 days.</p>")
00594           : ki18np("<p>The intermediate CA certificate</p><p align=\"center\"><b>%4</b></p>"
00595                "<p>for S/MIME certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00596                "<p>expires in less than a day.</p>",
00597                "<p>The intermediate CA certificate</p><p align=\"center\"><b>%4</b></p>"
00598                "<p>for S/MIME certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00599                "<p>expires in less than %1 days.</p>") ) )
00600                .subs( daysTillExpiry )
00601                .subs( Kleo::DN( orig.userID(0).id() ).prettyDN() )
00602                .subs( orig.issuerSerial() )
00603                .subs( Kleo::DN( key.userID(0).id() ).prettyDN() )
00604                .toString()
00605       : ( mine ? sign
00606           ? ki18np("<p>Your S/MIME signing certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00607                "<p>expires in less than a day.</p>",
00608                "<p>Your S/MIME signing certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00609                "<p>expires in less than %1 days.</p>")
00610           : ki18np("<p>Your S/MIME encryption certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00611                "<p>expires in less than a day.</p>",
00612                "<p>Your S/MIME encryption certificate</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00613                "<p>expires in less than %1 days.</p>")
00614           : ki18np("<p>The S/MIME certificate for</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00615                "<p>expires in less than a day.</p>",
00616                "<p>The S/MIME certificate for</p><p align=\"center\"><b>%2</b> (serial number %3)</p>"
00617                "<p>expires in less than %1 days.</p>" ) )
00618                .subs( daysTillExpiry )
00619                .subs( Kleo::DN( key.userID(0).id() ).prettyDN() )
00620                .subs( key.issuerSerial() )
00621                .toString() );
00622     if ( KMessageBox::warningContinueCancel( 0, msg,
00623                          key.protocol() == GpgME::OpenPGP
00624                          ? i18n("OpenPGP Key Expires Soon" )
00625                          : i18n("S/MIME Certificate Expires Soon" ),
00626                          KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
00627                          dontAskAgainName )
00628      == KMessageBox::Cancel )
00629       return Kpgp::Canceled;
00630   }
00631   if ( key.isRoot() )
00632     return Kpgp::Ok;
00633   else if ( const char * chain_id = key.chainID() ) {
00634     const std::vector<GpgME::Key> issuer = lookup( QStringList( chain_id ), false );
00635     if ( issuer.empty() )
00636       return Kpgp::Ok;
00637     else
00638       return checkKeyNearExpiry( issuer.front(), dontAskAgainName, mine, sign,
00639                  true, recur_limit-1, ca ? orig : key );
00640   }
00641   return Kpgp::Ok;
00642 }
00643 
00644 Kpgp::Result Kleo::KeyResolver::setEncryptToSelfKeys( const QStringList & fingerprints ) {
00645   if ( !encryptToSelf() )
00646     return Kpgp::Ok;
00647 
00648   std::vector<GpgME::Key> keys = lookup( fingerprints );
00649   std::remove_copy_if( keys.begin(), keys.end(),
00650                std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
00651                NotValidTrustedOpenPGPEncryptionKey );
00652   std::remove_copy_if( keys.begin(), keys.end(),
00653                std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
00654                NotValidTrustedSMIMEEncryptionKey );
00655 
00656   if ( d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size()
00657        < keys.size() ) {
00658     // too few keys remain...
00659     const QString msg = i18n("One or more of your configured OpenPGP encryption "
00660                  "keys or S/MIME certificates is not usable for "
00661                  "encryption. Please reconfigure your encryption keys "
00662                  "and certificates for this identity in the identity "
00663                  "configuration dialog.\n"
00664                  "If you choose to continue, and the keys are needed "
00665                  "later on, you will be prompted to specify the keys "
00666                  "to use.");
00667     return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Encryption Keys"),
00668                            KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
00669                            "unusable own encryption key warning" )
00670       == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ;
00671   }
00672 
00673   // check for near-expiry:
00674 
00675   for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPEncryptToSelfKeys.begin() ; it != d->mOpenPGPEncryptToSelfKeys.end() ; ++it ) {
00676     const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning",
00677                            true, false );
00678     if ( r != Kpgp::Ok )
00679       return r;
00680   }
00681 
00682   for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMEEncryptToSelfKeys.begin() ; it != d->mSMIMEEncryptToSelfKeys.end() ; ++it ) {
00683     const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning",
00684                            true, false );
00685     if ( r != Kpgp::Ok )
00686       return r;
00687   }
00688 
00689   return Kpgp::Ok;
00690 }
00691 
00692 Kpgp::Result Kleo::KeyResolver::setSigningKeys( const QStringList & fingerprints ) {
00693   std::vector<GpgME::Key> keys = lookup( fingerprints, true ); // secret keys
00694   std::remove_copy_if( keys.begin(), keys.end(),
00695                std::back_inserter( d->mOpenPGPSigningKeys ),
00696                NotValidOpenPGPSigningKey );
00697   std::remove_copy_if( keys.begin(), keys.end(),
00698                std::back_inserter( d->mSMIMESigningKeys ),
00699                NotValidSMIMESigningKey );
00700 
00701   if ( d->mOpenPGPSigningKeys.size() + d->mSMIMESigningKeys.size() < keys.size() ) {
00702     // too few keys remain...
00703     const QString msg = i18n("One or more of your configured OpenPGP signing keys "
00704                  "or S/MIME signing certificates is not usable for "
00705                  "signing. Please reconfigure your signing keys "
00706                  "and certificates for this identity in the identity "
00707                  "configuration dialog.\n"
00708                  "If you choose to continue, and the keys are needed "
00709                  "later on, you will be prompted to specify the keys "
00710                  "to use.");
00711     return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Signing Keys"),
00712                            KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
00713                            "unusable signing key warning" )
00714       == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ;
00715   }
00716 
00717   // check for near expiry:
00718 
00719   for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPSigningKeys.begin() ; it != d->mOpenPGPSigningKeys.end() ; ++it ) {
00720     const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning",
00721                            true, true );
00722     if ( r != Kpgp::Ok )
00723       return r;
00724   }
00725 
00726   for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMESigningKeys.begin() ; it != d->mSMIMESigningKeys.end() ; ++it ) {
00727     const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning",
00728                            true, true );
00729     if ( r != Kpgp::Ok )
00730       return r;
00731   }
00732 
00733   return Kpgp::Ok;
00734 }
00735 
00736 void Kleo::KeyResolver::setPrimaryRecipients( const QStringList & addresses ) {
00737   d->mPrimaryEncryptionKeys = getEncryptionItems( addresses );
00738 }
00739 
00740 void Kleo::KeyResolver::setSecondaryRecipients( const QStringList & addresses ) {
00741   d->mSecondaryEncryptionKeys = getEncryptionItems( addresses );
00742 }
00743 
00744 std::vector<Kleo::KeyResolver::Item> Kleo::KeyResolver::getEncryptionItems( const QStringList & addresses ) {
00745   std::vector<Item> items;
00746   items.reserve( addresses.size() );
00747   for ( QStringList::const_iterator it = addresses.begin() ; it != addresses.end() ; ++it ) {
00748     QString addr = canonicalAddress( *it ).toLower();
00749     const ContactPreferences pref = lookupContactPreferences( addr );
00750 
00751     items.push_back( Item( *it, /*getEncryptionKeys( *it, true ),*/
00752                pref.encryptionPreference,
00753                pref.signingPreference,
00754                pref.cryptoMessageFormat ) );
00755   }
00756   return items;
00757 }
00758 
00759 static Kleo::Action action( bool doit, bool ask, bool donot, bool requested ) {
00760   if ( requested && !donot )
00761     return Kleo::DoIt;
00762   if ( doit && !ask && !donot )
00763     return Kleo::DoIt;
00764   if ( !doit && ask && !donot )
00765     return Kleo::Ask;
00766   if ( !doit && !ask && donot )
00767     return requested ? Kleo::Conflict : Kleo::DontDoIt ;
00768   if ( !doit && !ask && !donot )
00769     return Kleo::DontDoIt ;
00770   return Kleo::Conflict;
00771 }
00772 
00773 Kleo::Action Kleo::KeyResolver::checkSigningPreferences( bool signingRequested ) const {
00774 
00775   if ( signingRequested && d->mOpenPGPSigningKeys.empty() && d->mSMIMESigningKeys.empty() )
00776     return Impossible;
00777 
00778   SigningPreferenceCounter count;
00779   count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
00780              count );
00781   count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
00782              count );
00783 
00784   unsigned int sign = count.numAlwaysSign();
00785   unsigned int ask = count.numAlwaysAskForSigning();
00786   const unsigned int dontSign = count.numNeverSign();
00787   if ( signingPossible() ) {
00788     sign += count.numAlwaysSignIfPossible();
00789     ask += count.numAskSigningWheneverPossible();
00790   }
00791 
00792   return action( sign, ask, dontSign, signingRequested );
00793 }
00794 
00795 bool Kleo::KeyResolver::signingPossible() const {
00796   return !d->mOpenPGPSigningKeys.empty() || !d->mSMIMESigningKeys.empty() ;
00797 }
00798 
00799 Kleo::Action Kleo::KeyResolver::checkEncryptionPreferences( bool encryptionRequested ) const {
00800 
00801   if ( d->mPrimaryEncryptionKeys.empty() && d->mSecondaryEncryptionKeys.empty() )
00802     return DontDoIt;
00803 
00804   if ( encryptionRequested && encryptToSelf() &&
00805        d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty() )
00806     return Impossible;
00807 
00808   EncryptionPreferenceCounter count( this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference );
00809   count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
00810              count );
00811   count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
00812              count );
00813 
00814   unsigned int encrypt = count.numAlwaysEncrypt();
00815   unsigned int ask = count.numAlwaysAskForEncryption();
00816   const unsigned int dontEncrypt = count.numNeverEncrypt() + count.numNoKey();
00817   if ( encryptionPossible() ) {
00818     encrypt += count.numAlwaysEncryptIfPossible();
00819     ask += count.numAskWheneverPossible();
00820   }
00821 
00822   const Action act = action( encrypt, ask, dontEncrypt, encryptionRequested );
00823   if ( act != Ask ||
00824        std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
00825        std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
00826               EncryptionPreferenceCounter( this, UnknownPreference ) ) ).numAlwaysAskForEncryption() )
00827     return act;
00828   else
00829     return AskOpportunistic;
00830 }
00831 
00832 bool Kleo::KeyResolver::encryptionPossible() const {
00833   return std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
00834                EmptyKeyList ) == d->mPrimaryEncryptionKeys.end()
00835     &&   std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
00836                EmptyKeyList ) == d->mSecondaryEncryptionKeys.end() ;
00837 }
00838 
00839 Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& encryptionRequested ) {
00840   if ( !encryptionRequested && !signingRequested ) {
00841     // make a dummy entry with all recipients, but no signing or
00842     // encryption keys to avoid special-casing on the caller side:
00843     dump();
00844     d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) );
00845     dump();
00846     return Kpgp::Ok;
00847   }
00848   Kpgp::Result result = Kpgp::Ok;
00849   if ( encryptionRequested )
00850     result = resolveEncryptionKeys( signingRequested );
00851   if ( result != Kpgp::Ok )
00852     return result;
00853   if ( signingRequested )
00854     if ( encryptionRequested )
00855       result = resolveSigningKeysForEncryption();
00856     else {
00857       result = resolveSigningKeysForSigningOnly();
00858       if ( result == Kpgp::Failure ) {
00859         signingRequested = false;
00860         return Kpgp::Ok;
00861       }
00862     }
00863   return result;
00864 }
00865 
00866 Kpgp::Result Kleo::KeyResolver::resolveEncryptionKeys( bool signingRequested ) {
00867   //
00868   // 1. Get keys for all recipients:
00869   //
00870 
00871   for ( std::vector<Item>::iterator it = d->mPrimaryEncryptionKeys.begin() ; it != d->mPrimaryEncryptionKeys.end() ; ++it ) {
00872     if ( !it->needKeys )
00873       continue;
00874     it->keys = getEncryptionKeys( it->address, false );
00875     if ( it->keys.empty() )
00876       return Kpgp::Canceled;
00877     QString addr = canonicalAddress( it->address ).toLower();
00878     const ContactPreferences pref = lookupContactPreferences( addr );
00879     it->pref = pref.encryptionPreference;
00880     it->signPref = pref.signingPreference;
00881     it->format = pref.cryptoMessageFormat;
00882   }
00883 
00884   for ( std::vector<Item>::iterator it = d->mSecondaryEncryptionKeys.begin() ; it != d->mSecondaryEncryptionKeys.end() ; ++it ) {
00885     if ( !it->needKeys )
00886       continue;
00887     it->keys = getEncryptionKeys( it->address, false );
00888     if ( it->keys.empty() )
00889       return Kpgp::Canceled;
00890     QString addr = canonicalAddress( it->address ).toLower();
00891     const ContactPreferences pref = lookupContactPreferences( addr );
00892     it->pref = pref.encryptionPreference;
00893     it->signPref = pref.signingPreference;
00894     it->format = pref.cryptoMessageFormat;
00895   }
00896 
00897   // 1a: Present them to the user
00898 
00899   const Kpgp::Result res = showKeyApprovalDialog();
00900   if ( res != Kpgp::Ok )
00901     return res;
00902 
00903   //
00904   // 2. Check what the primary recipients need
00905   //
00906 
00907   // 2a. Try to find a common format for all primary recipients,
00908   //     else use as many formats as needed
00909 
00910   const EncryptionFormatPreferenceCounter primaryCount
00911     = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
00912              EncryptionFormatPreferenceCounter() );
00913 
00914   CryptoMessageFormat commonFormat = AutoFormat;
00915   for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
00916     if ( !( concreteCryptoMessageFormats[i] & mCryptoMessageFormats ) )
00917       continue;
00918     if ( signingRequested && signingKeysFor( concreteCryptoMessageFormats[i] ).empty() )
00919       continue;
00920     if ( encryptToSelf() && encryptToSelfKeysFor( concreteCryptoMessageFormats[i] ).empty() )
00921       continue;
00922     if ( primaryCount.numOf( concreteCryptoMessageFormats[i] ) == primaryCount.numTotal() ) {
00923       commonFormat = concreteCryptoMessageFormats[i];
00924       break;
00925     }
00926   }
00927   if ( commonFormat != AutoFormat )
00928     addKeys( d->mPrimaryEncryptionKeys, commonFormat );
00929   else
00930     addKeys( d->mPrimaryEncryptionKeys );
00931 
00932   collapseAllSplitInfos(); // these can be encrypted together
00933 
00934   // 2b. Just try to find _something_ for each secondary recipient,
00935   //     with a preference to a common format (if that exists)
00936 
00937   const EncryptionFormatPreferenceCounter secondaryCount
00938     = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
00939              EncryptionFormatPreferenceCounter() );
00940 
00941   if ( commonFormat != AutoFormat &&
00942        secondaryCount.numOf( commonFormat ) == secondaryCount.numTotal() )
00943     addKeys( d->mSecondaryEncryptionKeys, commonFormat );
00944   else
00945     addKeys( d->mSecondaryEncryptionKeys );
00946 
00947   // 3. Check for expiry:
00948 
00949   for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
00950     const std::vector<SplitInfo> si_list = encryptionItems( concreteCryptoMessageFormats[i] );
00951     for ( std::vector<SplitInfo>::const_iterator sit = si_list.begin() ; sit != si_list.end() ; ++sit )
00952       for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit ) {
00953     const Kpgp::Result r = checkKeyNearExpiry( *kit, "other encryption key near expiry warning",
00954                            false, false );
00955     if ( r != Kpgp::Ok )
00956       return r;
00957       }
00958   }
00959 
00960   // 4. Check that we have the right keys for encryptToSelf()
00961 
00962   if ( !encryptToSelf() )
00963     return Kpgp::Ok;
00964 
00965   // 4a. Check for OpenPGP keys
00966 
00967   if ( !encryptionItems( InlineOpenPGPFormat ).empty() ||
00968        !encryptionItems( OpenPGPMIMEFormat ).empty() ) {
00969     // need them
00970     if ( d->mOpenPGPEncryptToSelfKeys.empty() ) {
00971       const QString msg = i18n("Examination of recipient's encryption preferences "
00972                    "yielded that the message should be encrypted using "
00973                    "OpenPGP, at least for some recipients;\n"
00974                    "however, you have not configured valid trusted "
00975                    "OpenPGP encryption keys for this identity.\n"
00976                    "You may continue without encrypting to yourself, "
00977                    "but be aware that you will not be able to read your "
00978                    "own messages if you do so.");
00979       if ( KMessageBox::warningContinueCancel( 0, msg,
00980                            i18n("Unusable Encryption Keys"),
00981                            KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
00982                            "encrypt-to-self will fail warning" )
00983        == KMessageBox::Cancel )
00984     return Kpgp::Canceled;
00985       // FIXME: Allow selection
00986     }
00987     addToAllSplitInfos( d->mOpenPGPEncryptToSelfKeys,
00988             InlineOpenPGPFormat|OpenPGPMIMEFormat );
00989   }
00990 
00991   // 4b. Check for S/MIME certs:
00992 
00993   if ( !encryptionItems( SMIMEFormat ).empty() ||
00994        !encryptionItems( SMIMEOpaqueFormat ).empty() ) {
00995     // need them
00996     if ( d->mSMIMEEncryptToSelfKeys.empty() ) {
00997       // don't have one
00998       const QString msg = i18n("Examination of recipient's encryption preferences "
00999                    "yielded that the message should be encrypted using "
01000                    "S/MIME, at least for some recipients;\n"
01001                    "however, you have not configured valid "
01002                    "S/MIME encryption certificates for this identity.\n"
01003                    "You may continue without encrypting to yourself, "
01004                    "but be aware that you will not be able to read your "
01005                    "own messages if you do so.");
01006       if ( KMessageBox::warningContinueCancel( 0, msg,
01007                            i18n("Unusable Encryption Keys"),
01008                            KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
01009                            "encrypt-to-self will fail warning" )
01010        == KMessageBox::Cancel )
01011     return Kpgp::Canceled;
01012       // FIXME: Allow selection
01013     }
01014     addToAllSplitInfos( d->mSMIMEEncryptToSelfKeys,
01015             SMIMEFormat|SMIMEOpaqueFormat );
01016   }
01017 
01018   // FIXME: Present another message if _both_ OpenPGP and S/MIME keys
01019   // are missing.
01020 
01021   return Kpgp::Ok;
01022 }
01023 
01024 Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForEncryption() {
01025   if ( ( !encryptionItems( InlineOpenPGPFormat ).empty() ||
01026      !encryptionItems( OpenPGPMIMEFormat ).empty() )
01027        && d->mOpenPGPSigningKeys.empty() ) {
01028     const QString msg = i18n("Examination of recipient's signing preferences "
01029                  "yielded that the message should be signed using "
01030                  "OpenPGP, at least for some recipients;\n"
01031                  "however, you have not configured valid "
01032                  "OpenPGP signing certificates for this identity.");
01033     if ( KMessageBox::warningContinueCancel( 0, msg,
01034                          i18n("Unusable Signing Keys"),
01035                          KGuiItem(i18n("Do Not OpenPGP-Sign")),
01036                          KStandardGuiItem::cancel(),
01037                          "signing will fail warning" )
01038      == KMessageBox::Cancel )
01039       return Kpgp::Canceled;
01040     // FIXME: Allow selection
01041   }
01042   if ( ( !encryptionItems( SMIMEFormat ).empty() ||
01043      !encryptionItems( SMIMEOpaqueFormat ).empty() )
01044        && d->mSMIMESigningKeys.empty() ) {
01045     const QString msg = i18n("Examination of recipient's signing preferences "
01046                  "yielded that the message should be signed using "
01047                  "S/MIME, at least for some recipients;\n"
01048                  "however, you have not configured valid "
01049                  "S/MIME signing certificates for this identity.");
01050     if ( KMessageBox::warningContinueCancel( 0, msg,
01051                          i18n("Unusable Signing Keys"),
01052                          KGuiItem(i18n("Do Not S/MIME-Sign")),
01053                          KStandardGuiItem::cancel(),
01054                          "signing will fail warning" )
01055      == KMessageBox::Cancel )
01056       return Kpgp::Canceled;
01057     // FIXME: Allow selection
01058   }
01059 
01060   // FIXME: Present another message if _both_ OpenPGP and S/MIME keys
01061   // are missing.
01062 
01063   for ( std::map<CryptoMessageFormat,FormatInfo>::iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it )
01064     if ( !it->second.splitInfos.empty() ) {
01065       dump();
01066       it->second.signKeys = signingKeysFor( it->first );
01067       dump();
01068     }
01069 
01070   return Kpgp::Ok;
01071 }
01072 
01073 Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForSigningOnly() {
01074   //
01075   // we don't need to distinguish between primary and secondary
01076   // recipients here:
01077   //
01078   SigningFormatPreferenceCounter count;
01079   count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
01080              count );
01081   count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
01082              count );
01083 
01084   // try to find a common format that works for all (and that we have signing keys for):
01085 
01086   CryptoMessageFormat commonFormat = AutoFormat;
01087 
01088   for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
01089     if ( !(mCryptoMessageFormats & concreteCryptoMessageFormats[i]) )
01090       continue; // skip
01091     if ( signingKeysFor( concreteCryptoMessageFormats[i] ).empty() )
01092       continue; // skip
01093     if ( count.numOf( concreteCryptoMessageFormats[i] ) == count.numTotal() ) {
01094       commonFormat = concreteCryptoMessageFormats[i];
01095       break;
01096     }
01097   }
01098 
01099   if ( commonFormat != AutoFormat ) { // found
01100     dump();
01101     FormatInfo & fi = d->mFormatInfoMap[ commonFormat ];
01102     fi.signKeys = signingKeysFor( commonFormat );
01103     fi.splitInfos.resize( 1 );
01104     fi.splitInfos.front() = SplitInfo( allRecipients() );
01105     dump();
01106     return Kpgp::Ok;
01107   }
01108 
01109   const QString msg = i18n("Examination of recipient's signing preferences "
01110                            "showed no common type of signature matching your "
01111                            "available signing keys.\n"
01112                            "Send message without signing?"  );
01113   if ( KMessageBox::warningContinueCancel( 0, msg, i18n("No signing possible"),
01114                                            KStandardGuiItem::cont() )
01115        == KMessageBox::Continue ) {
01116     d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) );
01117     return Kpgp::Failure; // means "Ok, but without signing"
01118   }
01119   return Kpgp::Canceled;
01120 }
01121 
01122 std::vector<GpgME::Key> Kleo::KeyResolver::signingKeysFor( CryptoMessageFormat f ) const {
01123   if ( isOpenPGP( f ) )
01124     return d->mOpenPGPSigningKeys;
01125   if ( isSMIME( f ) )
01126     return d->mSMIMESigningKeys;
01127   return std::vector<GpgME::Key>();
01128 }
01129 
01130 std::vector<GpgME::Key> Kleo::KeyResolver::encryptToSelfKeysFor( CryptoMessageFormat f ) const {
01131   if ( isOpenPGP( f ) )
01132     return d->mOpenPGPEncryptToSelfKeys;
01133   if ( isSMIME( f ) )
01134     return d->mSMIMEEncryptToSelfKeys;
01135