kmail Library API Documentation

keyresolver.cpp

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