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