summaryrefslogtreecommitdiffstats
path: root/kmail/keyresolver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmail/keyresolver.cpp')
-rw-r--r--kmail/keyresolver.cpp343
1 files changed, 288 insertions, 55 deletions
diff --git a/kmail/keyresolver.cpp b/kmail/keyresolver.cpp
index e35a7f5f9..3c1a952ca 100644
--- a/kmail/keyresolver.cpp
+++ b/kmail/keyresolver.cpp
@@ -42,6 +42,7 @@
#include "kcursorsaver.h"
#include "kleo_util.h"
+#include "stl_util.h"
#include <libemailfunctions/email.h>
#include <ui/keyselectiondialog.h>
@@ -103,7 +104,7 @@ static inline bool WithRespectToKeyID( const GpgME::Key & left, const GpgME::Key
return qstrcmp( left.keyID(), right.keyID() ) == 0 ;
}
-static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
+static bool ValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
if ( key.protocol() != GpgME::Context::OpenPGP ) {
return false;
}
@@ -119,9 +120,15 @@ static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
#endif
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
return false;
+ return true;
+}
+
+static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
+ if ( !ValidOpenPGPEncryptionKey( key ) )
+ return false;
const std::vector<GpgME::UserID> uids = key.userIDs();
for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
- if ( !it->isRevoked() && it->validity() != GpgME::UserID::Marginal )
+ if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal )
return true;
#if 0
else
@@ -134,7 +141,7 @@ static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
return false;
}
-static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
+static bool ValidSMIMEEncryptionKey( const GpgME::Key & key ) {
if ( key.protocol() != GpgME::Context::CMS )
return false;
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
@@ -142,6 +149,12 @@ static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
return true;
}
+static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
+ if ( !ValidSMIMEEncryptionKey( key ) )
+ return false;
+ return true;
+}
+
static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
switch ( key.protocol() ) {
case GpgME::Context::OpenPGP:
@@ -153,6 +166,17 @@ static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
}
}
+static inline bool ValidEncryptionKey( const GpgME::Key & key ) {
+ switch ( key.protocol() ) {
+ case GpgME::Context::OpenPGP:
+ return ValidOpenPGPEncryptionKey( key );
+ case GpgME::Context::CMS:
+ return ValidSMIMEEncryptionKey( key );
+ default:
+ return false;
+ }
+}
+
static inline bool ValidSigningKey( const GpgME::Key & key ) {
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign() )
return false;
@@ -171,14 +195,26 @@ static inline bool NotValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key )
return !ValidTrustedOpenPGPEncryptionKey( key );
}
+static inline bool NotValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
+ return !ValidOpenPGPEncryptionKey( key );
+}
+
static inline bool NotValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
return !ValidTrustedSMIMEEncryptionKey( key );
}
+static inline bool NotValidSMIMEEncryptionKey( const GpgME::Key & key ) {
+ return !ValidSMIMEEncryptionKey( key );
+}
+
static inline bool NotValidTrustedEncryptionKey( const GpgME::Key & key ) {
return !ValidTrustedEncryptionKey( key );
}
+static inline bool NotValidEncryptionKey( const GpgME::Key & key ) {
+ return !ValidEncryptionKey( key );
+}
+
static inline bool NotValidSigningKey( const GpgME::Key & key ) {
return !ValidSigningKey( key );
}
@@ -191,6 +227,40 @@ static inline bool NotValidSMIMESigningKey( const GpgME::Key & key ) {
return !ValidSMIMESigningKey( key );
}
+namespace {
+ struct ByTrustScore {
+ static int score( const GpgME::UserID & uid ) {
+ return uid.isRevoked() || uid.isInvalid() ? -1 : uid.validity() ;
+ }
+ bool operator()( const GpgME::UserID & lhs, const GpgME::UserID & rhs ) const {
+ return score( lhs ) < score( rhs ) ;
+ }
+ };
+}
+
+static std::vector<GpgME::UserID> matchingUIDs( const std::vector<GpgME::UserID> & uids, const TQString & address ) {
+ if ( address.isEmpty() )
+ return std::vector<GpgME::UserID>();
+
+ std::vector<GpgME::UserID> result;
+ result.reserve( uids.size() );
+ for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin(), end = uids.end() ; it != end ; ++it )
+ // PENDING(marc) check DN for an EMAIL, too, in case of X.509 certs... :/
+ if ( const char * email = it->email() )
+ if ( *email && TQString::fromUtf8( email ).stripWhiteSpace().lower() == address )
+ result.push_back( *it );
+ return result;
+}
+
+static GpgME::UserID findBestMatchUID( const GpgME::Key & key, const TQString & address ) {
+ const std::vector<GpgME::UserID> all = key.userIDs();
+ if ( all.empty() )
+ return GpgME::UserID();
+ const std::vector<GpgME::UserID> matching = matchingUIDs( all, address.lower() );
+ const std::vector<GpgME::UserID> & v = matching.empty() ? all : matching ;
+ return *std::max_element( v.begin(), v.end(), ByTrustScore() );
+}
+
static TQStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) {
TQStringList strings;
for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) {
@@ -205,35 +275,40 @@ static TQStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) {
return strings;
}
-static inline std::vector<GpgME::Key> TrustedOrConfirmed( const std::vector<GpgME::Key> & keys ) {
+static std::vector<GpgME::Key> trustedOrConfirmed( const std::vector<GpgME::Key> & keys, const TQString & address, bool & canceled ) {
+ // PENDING(marc) work on UserIDs here?
std::vector<GpgME::Key> fishies;
std::vector<GpgME::Key> ickies;
+ std::vector<GpgME::Key> rewookies;
std::vector<GpgME::Key>::const_iterator it = keys.begin();
const std::vector<GpgME::Key>::const_iterator end = keys.end();
for ( ; it != end ; it++ ) {
- const GpgME::Key key = *it;
- assert( ValidTrustedEncryptionKey( key ) );
- const std::vector<GpgME::UserID> uids = key.userIDs();
- for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
- if ( !it->isRevoked() && it->validity() == GpgME::UserID::Marginal ) {
+ const GpgME::Key & key = *it;
+ assert( ValidEncryptionKey( key ) );
+ const GpgME::UserID uid = findBestMatchUID( key, address );
+ if ( uid.isRevoked() ) {
+ rewookies.push_back( key );
+ }
+ if ( !uid.isRevoked() && uid.validity() == GpgME::UserID::Marginal ) {
fishies.push_back( key );
- break;
- }
- if ( !it->isRevoked() && it->validity() < GpgME::UserID::Never ) {
+ }
+ if ( !uid.isRevoked() && uid.validity() < GpgME::UserID::Never ) {
ickies.push_back( key );
- break;
- }
}
}
- if ( fishies.empty() && ickies.empty() )
+ if ( fishies.empty() && ickies.empty() && rewookies.empty() )
return keys;
// if some keys are not fully trusted, let the user confirm their use
- TQString msg = i18n("One or more of your configured OpenPGP encryption "
- "keys or S/MIME certificates is not fully trusted "
- "for encryption.");
+ TQString msg = address.isEmpty()
+ ? i18n("One or more of your configured OpenPGP encryption "
+ "keys or S/MIME certificates is not fully trusted "
+ "for encryption.")
+ : i18n("One or more of the OpenPGP encryption keys or S/MIME "
+ "certificates for recipient \"%1\" is not fully trusted "
+ "for encryption.").arg(address) ;
if ( !fishies.empty() ) {
// certificates can't have marginal trust
@@ -244,6 +319,10 @@ static inline std::vector<GpgME::Key> TrustedOrConfirmed( const std::vector<GpgM
msg += i18n( "\nThe following keys or certificates have unknown trust level: \n");
msg += keysAsStrings( ickies ).join(",");
}
+ if ( !rewookies.empty() ) {
+ msg += i18n( "\nThe following keys or certificates are <b>revoked</b>: \n");
+ msg += keysAsStrings( rewookies ).join(",");
+ }
if( KMessageBox::warningContinueCancel( 0, msg, i18n("Not Fully Trusted Encryption Keys"),
KStdGuiItem::cont(),
@@ -251,7 +330,8 @@ static inline std::vector<GpgME::Key> TrustedOrConfirmed( const std::vector<GpgM
== KMessageBox::Continue )
return keys;
else
- return std::vector<GpgME::Key>();
+ canceled = true;
+ return std::vector<GpgME::Key>();
}
namespace {
@@ -266,6 +346,20 @@ namespace {
const Kleo::CryptoMessageFormat format;
};
+
+ struct IsForFormat : std::unary_function<GpgME::Key,bool> {
+ explicit IsForFormat( Kleo::CryptoMessageFormat f )
+ : protocol( isOpenPGP( f ) ? GpgME::Context::OpenPGP :
+ isSMIME( f ) ? GpgME::Context::CMS :
+ /* else */ GpgME::Context::Unknown ) {}
+
+ bool operator()( const GpgME::Key & key ) const {
+ return key.protocol() == protocol ;
+ }
+
+ const GpgME::Context::Protocol protocol;
+ };
+
}
@@ -334,6 +428,11 @@ public:
}
void operator()( Item & item );
+ template <typename Container>
+ void process( Container & c ) {
+ *this = std::for_each( c.begin(), c.end(), *this );
+ }
+
#define make_int_accessor(x) unsigned int num##x() const { return m##x; }
make_int_accessor(NoKey)
make_int_accessor(NeverEncrypt)
@@ -346,6 +445,7 @@ public:
#undef make_int_accessor
private:
EncryptionPreference mDefaultPreference;
+ bool mNoOps;
unsigned int mTotal;
unsigned int mNoKey;
unsigned int mNeverEncrypt, mUnknownPreference, mAlwaysEncrypt,
@@ -353,12 +453,14 @@ private:
};
void Kleo::KeyResolver::EncryptionPreferenceCounter::operator()( Item & item ) {
+ if ( _this ) {
if ( item.needKeys )
item.keys = _this->getEncryptionKeys( item.address, true );
if ( item.keys.empty() ) {
++mNoKey;
return;
}
+ }
switch ( !item.pref ? mDefaultPreference : item.pref ) {
#define CASE(x) case Kleo::x: ++m##x; break
CASE(NeverEncrypt);
@@ -427,13 +529,13 @@ namespace {
void EncryptionFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
if ( item.format & (Kleo::InlineOpenPGPFormat|Kleo::OpenPGPMIMEFormat) &&
std::find_if( item.keys.begin(), item.keys.end(),
- ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) {
+ ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) { // -= trusted?
CASE(OpenPGPMIME);
CASE(InlineOpenPGP);
}
if ( item.format & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) &&
std::find_if( item.keys.begin(), item.keys.end(),
- ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) {
+ ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) { // -= trusted?
CASE(SMIME);
CASE(SMIMEOpaque);
}
@@ -523,13 +625,108 @@ Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, cons
const GpgME::Subkey subkey = key.subkey(0);
if ( d->alreadyWarnedFingerprints.count( subkey.fingerprint() ) )
return Kpgp::Ok; // already warned about this one (and so about it's issuers)
- d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
if ( subkey.neverExpires() )
return Kpgp::Ok;
static const double secsPerDay = 24 * 60 * 60;
- const int daysTillExpiry =
- 1 + int( ::difftime( subkey.expirationTime(), time(0) ) / secsPerDay );
+ const double secsTillExpiry = ::difftime( subkey.expirationTime(), time(0) );
+ if ( secsTillExpiry <= 0 ) {
+ const int daysSinceExpiry = 1 + int( -secsTillExpiry / secsPerDay );
+ kdDebug() << "Key 0x" << key.shortKeyID() << " expired less than "
+ << daysSinceExpiry << " days ago" << endl;
+ const TQString msg =
+ key.protocol() == GpgME::Context::OpenPGP
+ ? ( mine ? sign
+ ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ),
+ key.shortKeyID() )
+ : ( ca
+ ? ( key.isRoot()
+ ? ( mine ? sign
+ ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry ) )
+ : ( mine ? sign
+ ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(),
+ orig.issuerSerial(),
+ Kleo::DN( key.userID(0).id() ).prettyDN() )
+ : ( mine ? sign
+ ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
+ key.issuerSerial() ) );
+ d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
+ if ( KMessageBox::warningContinueCancel( 0, msg,
+ key.protocol() == GpgME::Context::OpenPGP
+ ? i18n("OpenPGP Key Expired" )
+ : i18n("S/MIME Certificate Expired" ),
+ KStdGuiItem::cont(), dontAskAgainName ) == KMessageBox::Cancel )
+ return Kpgp::Canceled;
+ } else {
+ const int daysTillExpiry = 1 + int( secsTillExpiry / secsPerDay );
kdDebug() << "Key 0x" << key.shortKeyID() << " expires in less than "
<< daysTillExpiry << " days" << endl;
const int threshold =
@@ -629,6 +826,7 @@ Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, cons
"<p>expires in less than %n days.</p>",
daysTillExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
key.issuerSerial() ) );
+ d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
if ( KMessageBox::warningContinueCancel( 0, msg,
key.protocol() == GpgME::Context::OpenPGP
? i18n("OpenPGP Key Expires Soon" )
@@ -637,6 +835,7 @@ Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, cons
== KMessageBox::Cancel )
return Kpgp::Canceled;
}
+ }
if ( key.isRoot() )
return Kpgp::Ok;
else if ( const char * chain_id = key.chainID() ) {
@@ -657,10 +856,10 @@ Kpgp::Result Kleo::KeyResolver::setEncryptToSelfKeys( const TQStringList & finge
std::vector<GpgME::Key> keys = lookup( fingerprints );
std::remove_copy_if( keys.begin(), keys.end(),
std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
- NotValidTrustedOpenPGPEncryptionKey );
+ NotValidTrustedOpenPGPEncryptionKey ); // -= trusted?
std::remove_copy_if( keys.begin(), keys.end(),
std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
- NotValidTrustedSMIMEEncryptionKey );
+ NotValidTrustedSMIMEEncryptionKey ); // -= trusted?
if ( d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size()
< keys.size() ) {
@@ -814,6 +1013,20 @@ Kleo::Action Kleo::KeyResolver::checkEncryptionPreferences( bool encryptionReque
d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty() )
return Impossible;
+ if ( !encryptionRequested && !mOpportunisticEncyption ) {
+ // try to minimize crypto ops (including key lookups) by only
+ // looking up keys when at least one the the encryption
+ // preferences needs it:
+ EncryptionPreferenceCounter count( 0, UnknownPreference );
+ count.process( d->mPrimaryEncryptionKeys );
+ count.process( d->mSecondaryEncryptionKeys );
+ if ( !count.numAlwaysEncrypt() &&
+ !count.numAlwaysAskForEncryption() && // this guy might not need a lookup, when declined, but it's too complex to implement that here
+ !count.numAlwaysEncryptIfPossible() &&
+ !count.numAskWheneverPossible() )
+ return DontDoIt;
+ }
+
EncryptionPreferenceCounter count( this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference );
count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
count );
@@ -859,9 +1072,10 @@ Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& en
result = resolveEncryptionKeys( signingRequested );
if ( result != Kpgp::Ok )
return result;
- if ( signingRequested )
- if ( encryptionRequested )
+ if ( signingRequested ) {
+ if ( encryptionRequested ) {
result = resolveSigningKeysForEncryption();
+ }
else {
result = resolveSigningKeysForSigningOnly();
if ( result == Kpgp::Failure ) {
@@ -869,6 +1083,7 @@ Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& en
return Kpgp::Ok;
}
}
+ }
return result;
}
@@ -1334,10 +1549,10 @@ Kpgp::Result Kleo::KeyResolver::showKeyApprovalDialog() {
std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
- NotValidTrustedOpenPGPEncryptionKey );
+ NotValidTrustedOpenPGPEncryptionKey ); // -= trusted (see above, too)?
std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
- NotValidTrustedSMIMEEncryptionKey );
+ NotValidTrustedSMIMEEncryptionKey ); // -= trusted (see above, too)?
return Kpgp::Ok;
}
@@ -1364,16 +1579,21 @@ std::vector<GpgME::Key> Kleo::KeyResolver::signingKeys( CryptoMessageFormat f )
std::vector<GpgME::Key> Kleo::KeyResolver::selectKeys( const TQString & person, const TQString & msg, const std::vector<GpgME::Key> & selectedKeys ) const {
+ const bool opgp = containsOpenPGP( mCryptoMessageFormats );
+ const bool x509 = containsSMIME( mCryptoMessageFormats );
+
Kleo::KeySelectionDialog dlg( i18n("Encryption Key Selection"),
- msg, selectedKeys,
- Kleo::KeySelectionDialog::ValidEncryptionKeys,
+ msg, KPIM::getEmailAddress(person), selectedKeys,
+ Kleo::KeySelectionDialog::ValidEncryptionKeys
+ & ~(opgp ? 0 : Kleo::KeySelectionDialog::OpenPGPKeys)
+ & ~(x509 ? 0 : Kleo::KeySelectionDialog::SMIMEKeys),
true, true ); // multi-selection and "remember choice" box
if ( dlg.exec() != TQDialog::Accepted )
return std::vector<GpgME::Key>();
std::vector<GpgME::Key> keys = dlg.selectedKeys();
keys.erase( std::remove_if( keys.begin(), keys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidTrustedEncryptionKey ), // -= trusted?
keys.end() );
if ( !keys.empty() && dlg.rememberSelection() )
setKeysForAddress( person, dlg.pgpKeyFingerprints(), dlg.smimeFingerprints() );
@@ -1396,70 +1616,80 @@ std::vector<GpgME::Key> Kleo::KeyResolver::getEncryptionKeys( const TQString & p
if ( !keys.empty() ) {
// Check if all of the keys are trusted and valid encryption keys
if ( std::find_if( keys.begin(), keys.end(),
- NotValidTrustedEncryptionKey ) != keys.end() ) {
+ NotValidTrustedEncryptionKey ) != keys.end() ) { // -= trusted?
// not ok, let the user select: this is not conditional on !quiet,
// since it's a bug in the configuration and the user should be
// notified about it as early as possible:
keys = selectKeys( person,
i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
"There is a problem with the "
- "encryption key(s) for \"%1\".\n\n"
- "Please re-select the key(s) which should "
+ "encryption certificate(s) for \"%1\".\n\n"
+ "Please re-select the certificate(s) which should "
"be used for this recipient.").arg(person),
keys );
}
- keys = TrustedOrConfirmed( keys );
+ bool canceled = false;
+ keys = trustedOrConfirmed( keys, address, canceled );
+ if ( canceled )
+ return std::vector<GpgME::Key>();
if ( !keys.empty() )
return keys;
- // hmmm, should we not return the keys in any case here?
+ // keys.empty() is considered cancel by callers, so go on
}
}
// Now search all public keys for matching keys
std::vector<GpgME::Key> matchingKeys = lookup( person );
matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidEncryptionKey ),
matchingKeys.end() );
// if no keys match the complete address look for keys which match
// the canonical mail address
if ( matchingKeys.empty() ) {
matchingKeys = lookup( address );
matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidEncryptionKey ),
matchingKeys.end() );
}
// if called with quite == true (from EncryptionPreferenceCounter), we only want to
// check if there are keys for this recipients, not (yet) their validity, so
// don't show the untrusted encryption key warning in that case
+ bool canceled = false;
if ( !quiet )
- matchingKeys = TrustedOrConfirmed( matchingKeys );
+ matchingKeys = trustedOrConfirmed( matchingKeys, address, canceled );
+ if ( canceled )
+ return std::vector<GpgME::Key>();
if ( quiet || matchingKeys.size() == 1 )
return matchingKeys;
// no match until now, or more than one key matches; let the user
// choose the key(s)
// FIXME: let user get the key from keyserver
- return TrustedOrConfirmed( selectKeys( person,
+ return trustedOrConfirmed( selectKeys( person,
matchingKeys.empty()
? i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
- "No valid and trusted encryption key was "
- "found for \"%1\".\n\n"
- "Select the key(s) which should "
- "be used for this recipient.").arg(person)
+ "<qt>No valid and trusted encryption certificate was "
+ "found for \"%1\".<br/><br/>"
+ "Select the certificate(s) which should "
+ "be used for this recipient. If there is no suitable certificate in the list "
+ "you can also search for external certificates by clicking the button: search for external certificates.</qt>")
+ .arg( TQStyleSheet::escape(person) )
: i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
- "More than one key matches \"%1\".\n\n"
- "Select the key(s) which should "
- "be used for this recipient.").arg(person),
- matchingKeys ) );
+ "More than one certificate matches \"%1\".\n\n"
+ "Select the certificate(s) which should "
+ "be used for this recipient.").arg( TQStyleSheet::escape(person) ),
+ matchingKeys ), address, canceled );
+ // we can ignore 'canceled' here, since trustedOrConfirmed() returns
+ // an empty vector when canceled == true, and we'd just do the same
}
@@ -1513,8 +1743,11 @@ void Kleo::KeyResolver::addKeys( const std::vector<Item> & items ) {
SplitInfo si( it->address );
CryptoMessageFormat f = AutoFormat;
for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
- if ( concreteCryptoMessageFormats[i] & it->format ) {
- f = concreteCryptoMessageFormats[i];
+ const CryptoMessageFormat fmt = concreteCryptoMessageFormats[i];
+ if ( ( fmt & it->format ) &&
+ kdtools::any( it->keys.begin(), it->keys.end(), IsForFormat( fmt ) ) )
+ {
+ f = fmt;
break;
}
}