kmail

keyresolver.cpp
1 /*
2  keyresolver.cpp
3 
4  This file is part of libkleopatra, the KDE keymanagement library
5  Copyright (c) 2004 Klarälvdalens Datakonsult AB
6 
7  Based on kpgp.cpp
8  Copyright (C) 2001,2002 the KPGP authors
9  See file libtdenetwork/AUTHORS.kpgp for details
10 
11  Libkleopatra is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 2 of the
14  License, or (at your option) any later version.
15 
16  Libkleopatra is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 
25  In addition, as a special exception, the copyright holders give
26  permission to link the code of this program with any edition of
27  the TQt library by Trolltech AS, Norway (or with modified versions
28  of TQt that use the same license as TQt), and distribute linked
29  combinations including the two. You must obey the GNU General
30  Public License in all respects for all of the code used other than
31  TQt. If you modify this file, you may extend this exception to
32  your version of the file, but you are not obligated to do so. If
33  you do not wish to do so, delete this exception statement from
34  your version.
35 */
36 
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40 
41 #include "keyresolver.h"
42 
43 #include "kcursorsaver.h"
44 #include "kleo_util.h"
45 #include "stl_util.h"
46 
47 #include <libemailfunctions/email.h>
48 #include <ui/keyselectiondialog.h>
49 #include <kleo/cryptobackendfactory.h>
50 #include <kleo/keylistjob.h>
51 #include <kleo/dn.h>
52 
53 #include <gpgmepp/key.h>
54 #include <gpgmepp/keylistresult.h>
55 
56 #include <tdeabc/stdaddressbook.h>
57 #include <tdelocale.h>
58 #include <kdebug.h>
59 #include <kinputdialog.h>
60 #include <tdemessagebox.h>
61 
62 #include <tqstringlist.h>
63 #include <tqtl.h>
64 
65 #include <time.h>
66 
67 #include <algorithm>
68 #include <memory>
69 #include <iterator>
70 #include <functional>
71 #include <map>
72 #include <set>
73 #include <iostream>
74 #include <cassert>
75 
76 
77 //
78 // some predicates to be used in STL algorithms:
79 //
80 
81 static inline bool EmptyKeyList( const Kleo::KeyApprovalDialog::Item & item ) {
82  return item.keys.empty();
83 }
84 
85 static inline TQString ItemDotAddress( const Kleo::KeyResolver::Item & item ) {
86  return item.address;
87 }
88 
89 static inline bool ApprovalNeeded( const Kleo::KeyResolver::Item & item ) {
90  return item.pref == Kleo::UnknownPreference || item.pref == Kleo::NeverEncrypt || item.keys.empty() ;
91 }
92 
93 static inline Kleo::KeyResolver::Item
94 CopyKeysAndEncryptionPreferences( const Kleo::KeyResolver::Item & oldItem,
95  const Kleo::KeyApprovalDialog::Item & newItem ) {
96  return Kleo::KeyResolver::Item( oldItem.address, newItem.keys, newItem.pref, oldItem.signPref, oldItem.format );
97 }
98 
99 static inline bool ByKeyID( const GpgME::Key & left, const GpgME::Key & right ) {
100  return qstrcmp( left.keyID(), right.keyID() ) < 0 ;
101 }
102 
103 static inline bool WithRespectToKeyID( const GpgME::Key & left, const GpgME::Key & right ) {
104  return qstrcmp( left.keyID(), right.keyID() ) == 0 ;
105 }
106 
107 static bool ValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
108  if ( key.protocol() != GpgME::Context::OpenPGP ) {
109  return false;
110  }
111 #if 0
112  if ( key.isRevoked() )
113  kdWarning() << " is revoked" << endl;
114  if ( key.isExpired() )
115  kdWarning() << " is expired" << endl;
116  if ( key.isDisabled() )
117  kdWarning() << " is disabled" << endl;
118  if ( !key.canEncrypt() )
119  kdWarning() << " can't encrypt" << endl;
120 #endif
121  if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
122  return false;
123  return true;
124 }
125 
126 static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
127  if ( !ValidOpenPGPEncryptionKey( key ) )
128  return false;
129  const std::vector<GpgME::UserID> uids = key.userIDs();
130  for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
131  if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal )
132  return true;
133 #if 0
134  else
135  if ( it->isRevoked() )
136  kdWarning() << "a userid is revoked" << endl;
137  else
138  kdWarning() << "bad validity " << it->validity() << endl;
139 #endif
140  }
141  return false;
142 }
143 
144 static bool ValidSMIMEEncryptionKey( const GpgME::Key & key ) {
145  if ( key.protocol() != GpgME::Context::CMS )
146  return false;
147  if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
148  return false;
149  return true;
150 }
151 
152 static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
153  if ( !ValidSMIMEEncryptionKey( key ) )
154  return false;
155  return true;
156 }
157 
158 static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
159  switch ( key.protocol() ) {
160  case GpgME::Context::OpenPGP:
161  return ValidTrustedOpenPGPEncryptionKey( key );
162  case GpgME::Context::CMS:
163  return ValidTrustedSMIMEEncryptionKey( key );
164  default:
165  return false;
166  }
167 }
168 
169 static inline bool ValidEncryptionKey( const GpgME::Key & key ) {
170  switch ( key.protocol() ) {
171  case GpgME::Context::OpenPGP:
172  return ValidOpenPGPEncryptionKey( key );
173  case GpgME::Context::CMS:
174  return ValidSMIMEEncryptionKey( key );
175  default:
176  return false;
177  }
178 }
179 
180 static inline bool ValidSigningKey( const GpgME::Key & key ) {
181  if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign() )
182  return false;
183  return key.hasSecret();
184 }
185 
186 static inline bool ValidOpenPGPSigningKey( const GpgME::Key & key ) {
187  return key.protocol() == GpgME::Context::OpenPGP && ValidSigningKey( key );
188 }
189 
190 static inline bool ValidSMIMESigningKey( const GpgME::Key & key ) {
191  return key.protocol() == GpgME::Context::CMS && ValidSigningKey( key );
192 }
193 
194 static inline bool NotValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
195  return !ValidTrustedOpenPGPEncryptionKey( key );
196 }
197 
198 static inline bool NotValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
199  return !ValidOpenPGPEncryptionKey( key );
200 }
201 
202 static inline bool NotValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
203  return !ValidTrustedSMIMEEncryptionKey( key );
204 }
205 
206 static inline bool NotValidSMIMEEncryptionKey( const GpgME::Key & key ) {
207  return !ValidSMIMEEncryptionKey( key );
208 }
209 
210 static inline bool NotValidTrustedEncryptionKey( const GpgME::Key & key ) {
211  return !ValidTrustedEncryptionKey( key );
212 }
213 
214 static inline bool NotValidEncryptionKey( const GpgME::Key & key ) {
215  return !ValidEncryptionKey( key );
216 }
217 
218 static inline bool NotValidSigningKey( const GpgME::Key & key ) {
219  return !ValidSigningKey( key );
220 }
221 
222 static inline bool NotValidOpenPGPSigningKey( const GpgME::Key & key ) {
223  return !ValidOpenPGPSigningKey( key );
224 }
225 
226 static inline bool NotValidSMIMESigningKey( const GpgME::Key & key ) {
227  return !ValidSMIMESigningKey( key );
228 }
229 
230 namespace {
231  struct ByTrustScore {
232  static int score( const GpgME::UserID & uid ) {
233  return uid.isRevoked() || uid.isInvalid() ? -1 : uid.validity() ;
234  }
235  bool operator()( const GpgME::UserID & lhs, const GpgME::UserID & rhs ) const {
236  return score( lhs ) < score( rhs ) ;
237  }
238  };
239 }
240 
241 static std::vector<GpgME::UserID> matchingUIDs( const std::vector<GpgME::UserID> & uids, const TQString & address ) {
242  if ( address.isEmpty() )
243  return std::vector<GpgME::UserID>();
244 
245  std::vector<GpgME::UserID> result;
246  result.reserve( uids.size() );
247  for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin(), end = uids.end() ; it != end ; ++it )
248  // PENDING(marc) check DN for an EMAIL, too, in case of X.509 certs... :/
249  if ( const char * email = it->email() )
250  if ( *email && TQString::fromUtf8( email ).stripWhiteSpace().lower() == address )
251  result.push_back( *it );
252  return result;
253 }
254 
255 static GpgME::UserID findBestMatchUID( const GpgME::Key & key, const TQString & address ) {
256  const std::vector<GpgME::UserID> all = key.userIDs();
257  if ( all.empty() )
258  return GpgME::UserID();
259  const std::vector<GpgME::UserID> matching = matchingUIDs( all, address.lower() );
260  const std::vector<GpgME::UserID> & v = matching.empty() ? all : matching ;
261  return *std::max_element( v.begin(), v.end(), ByTrustScore() );
262 }
263 
264 static TQStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) {
265  TQStringList strings;
266  for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) {
267  assert( !(*it).userID(0).isNull() );
268  TQString keyLabel = TQString::fromUtf8( (*it).userID(0).email() );
269  if ( keyLabel.isEmpty() )
270  keyLabel = TQString::fromUtf8( (*it).userID(0).name() );
271  if ( keyLabel.isEmpty() )
272  keyLabel = TQString::fromUtf8( (*it).userID(0).id() );
273  strings.append( keyLabel );
274  }
275  return strings;
276 }
277 
278 static std::vector<GpgME::Key> trustedOrConfirmed( const std::vector<GpgME::Key> & keys, const TQString & address, bool & canceled ) {
279 
280  // PENDING(marc) work on UserIDs here?
281  std::vector<GpgME::Key> fishies;
282  std::vector<GpgME::Key> ickies;
283  std::vector<GpgME::Key> rewookies;
284  std::vector<GpgME::Key>::const_iterator it = keys.begin();
285  const std::vector<GpgME::Key>::const_iterator end = keys.end();
286  for ( ; it != end ; it++ ) {
287  const GpgME::Key & key = *it;
288  assert( ValidEncryptionKey( key ) );
289  const GpgME::UserID uid = findBestMatchUID( key, address );
290  if ( uid.isRevoked() ) {
291  rewookies.push_back( key );
292  }
293  if ( !uid.isRevoked() && uid.validity() == GpgME::UserID::Marginal ) {
294  fishies.push_back( key );
295  }
296  if ( !uid.isRevoked() && uid.validity() < GpgME::UserID::Never ) {
297  ickies.push_back( key );
298  }
299  }
300 
301  if ( fishies.empty() && ickies.empty() && rewookies.empty() )
302  return keys;
303 
304  // if some keys are not fully trusted, let the user confirm their use
305  TQString msg = address.isEmpty()
306  ? i18n("One or more of your configured OpenPGP encryption "
307  "keys or S/MIME certificates is not fully trusted "
308  "for encryption.")
309  : i18n("One or more of the OpenPGP encryption keys or S/MIME "
310  "certificates for recipient \"%1\" is not fully trusted "
311  "for encryption.").arg(address) ;
312 
313  if ( !fishies.empty() ) {
314  // certificates can't have marginal trust
315  msg += i18n( "\nThe following keys are only marginally trusted: \n");
316  msg += keysAsStrings( fishies ).join(",");
317  }
318  if ( !ickies.empty() ) {
319  msg += i18n( "\nThe following keys or certificates have unknown trust level: \n");
320  msg += keysAsStrings( ickies ).join(",");
321  }
322  if ( !rewookies.empty() ) {
323  msg += i18n( "\nThe following keys or certificates are <b>revoked</b>: \n");
324  msg += keysAsStrings( rewookies ).join(",");
325  }
326 
327  if( KMessageBox::warningContinueCancel( 0, msg, i18n("Not Fully Trusted Encryption Keys"),
328  KStdGuiItem::cont(),
329  "not fully trusted encryption key warning" )
330  == KMessageBox::Continue )
331  return keys;
332  else
333  canceled = true;
334  return std::vector<GpgME::Key>();
335 }
336 
337 namespace {
338  struct IsNotForFormat : public std::function<bool(GpgME::Key)> {
339  IsNotForFormat( Kleo::CryptoMessageFormat f ) : format( f ) {}
340 
341  bool operator()( const GpgME::Key & key ) const {
342  return
343  ( isOpenPGP( format ) && key.protocol() != GpgME::Context::OpenPGP ) ||
344  ( isSMIME( format ) && key.protocol() != GpgME::Context::CMS );
345  }
346 
347  const Kleo::CryptoMessageFormat format;
348  };
349 
350  struct IsForFormat : std::function<bool(GpgME::Key)> {
351  explicit IsForFormat( Kleo::CryptoMessageFormat f )
352  : protocol( isOpenPGP( f ) ? GpgME::Context::OpenPGP :
353  isSMIME( f ) ? GpgME::Context::CMS :
354  /* else */ GpgME::Context::Unknown ) {}
355 
356  bool operator()( const GpgME::Key & key ) const {
357  return key.protocol() == protocol ;
358  }
359 
360  const GpgME::Context::Protocol protocol;
361  };
362 
363 }
364 
365 
366 
367 class Kleo::KeyResolver::SigningPreferenceCounter : public std::function<void(Kleo::KeyResolver::Item)> {
368 public:
369  SigningPreferenceCounter()
370  : mTotal( 0 ),
371  mUnknownSigningPreference( 0 ),
372  mNeverSign( 0 ),
373  mAlwaysSign( 0 ),
374  mAlwaysSignIfPossible( 0 ),
375  mAlwaysAskForSigning( 0 ),
376  mAskSigningWheneverPossible( 0 )
377  {
378 
379  }
380  void operator()( const Kleo::KeyResolver::Item & item );
381 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
382  make_int_accessor(UnknownSigningPreference)
383  make_int_accessor(NeverSign)
384  make_int_accessor(AlwaysSign)
385  make_int_accessor(AlwaysSignIfPossible)
386  make_int_accessor(AlwaysAskForSigning)
387  make_int_accessor(AskSigningWheneverPossible)
388  make_int_accessor(Total)
389 #undef make_int_accessor
390 private:
391  unsigned int mTotal;
392  unsigned int mUnknownSigningPreference, mNeverSign, mAlwaysSign,
393  mAlwaysSignIfPossible, mAlwaysAskForSigning, mAskSigningWheneverPossible;
394 };
395 
396 void Kleo::KeyResolver::SigningPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
397  switch ( item.signPref ) {
398 #define CASE(x) case x: ++m##x; break
399  CASE(UnknownSigningPreference);
400  CASE(NeverSign);
401  CASE(AlwaysSign);
402  CASE(AlwaysSignIfPossible);
403  CASE(AlwaysAskForSigning);
404  CASE(AskSigningWheneverPossible);
405 #undef CASE
406  }
407  ++mTotal;
408 }
409 
410 
411 
412 class Kleo::KeyResolver::EncryptionPreferenceCounter : public std::function<void(Item)> {
413  const Kleo::KeyResolver * _this;
414 public:
415  EncryptionPreferenceCounter( const Kleo::KeyResolver * kr, EncryptionPreference defaultPreference )
416  : _this( kr ),
417  mDefaultPreference( defaultPreference ),
418  mTotal( 0 ),
419  mNoKey( 0 ),
420  mNeverEncrypt( 0 ),
421  mUnknownPreference( 0 ),
422  mAlwaysEncrypt( 0 ),
423  mAlwaysEncryptIfPossible( 0 ),
424  mAlwaysAskForEncryption( 0 ),
425  mAskWheneverPossible( 0 )
426  {
427 
428  }
429  void operator()( Item & item );
430 
431  template <typename Container>
432  void process( Container & c ) {
433  *this = std::for_each( c.begin(), c.end(), *this );
434  }
435 
436 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
437  make_int_accessor(NoKey)
438  make_int_accessor(NeverEncrypt)
439  make_int_accessor(UnknownPreference)
440  make_int_accessor(AlwaysEncrypt)
441  make_int_accessor(AlwaysEncryptIfPossible)
442  make_int_accessor(AlwaysAskForEncryption)
443  make_int_accessor(AskWheneverPossible)
444  make_int_accessor(Total)
445 #undef make_int_accessor
446 private:
447  EncryptionPreference mDefaultPreference;
448  bool mNoOps;
449  unsigned int mTotal;
450  unsigned int mNoKey;
451  unsigned int mNeverEncrypt, mUnknownPreference, mAlwaysEncrypt,
452  mAlwaysEncryptIfPossible, mAlwaysAskForEncryption, mAskWheneverPossible;
453 };
454 
455 void Kleo::KeyResolver::EncryptionPreferenceCounter::operator()( Item & item ) {
456  if ( _this ) {
457  if ( item.needKeys )
458  item.keys = _this->getEncryptionKeys( item.address, true );
459  if ( item.keys.empty() ) {
460  ++mNoKey;
461  return;
462  }
463  }
464  switch ( !item.pref ? mDefaultPreference : item.pref ) {
465 #define CASE(x) case Kleo::x: ++m##x; break
466  CASE(NeverEncrypt);
467  CASE(UnknownPreference);
468  CASE(AlwaysEncrypt);
469  CASE(AlwaysEncryptIfPossible);
470  CASE(AlwaysAskForEncryption);
471  CASE(AskWheneverPossible);
472 #undef CASE
473  }
474  ++mTotal;
475 }
476 
477 namespace {
478 
479  class FormatPreferenceCounterBase : public std::function<void(Kleo::KeyResolver::Item)> {
480  public:
481  FormatPreferenceCounterBase()
482  : mTotal( 0 ),
483  mInlineOpenPGP( 0 ),
484  mOpenPGPMIME( 0 ),
485  mSMIME( 0 ),
486  mSMIMEOpaque( 0 )
487  {
488 
489  }
490 
491 #define make_int_accessor(x) unsigned int num##x() const { return m##x; }
492  make_int_accessor(Total)
493  make_int_accessor(InlineOpenPGP)
494  make_int_accessor(OpenPGPMIME)
495  make_int_accessor(SMIME)
496  make_int_accessor(SMIMEOpaque)
497 #undef make_int_accessor
498 
499  unsigned int numOf( Kleo::CryptoMessageFormat f ) const {
500  switch ( f ) {
501 #define CASE(x) case Kleo::x##Format: return m##x
502  CASE(InlineOpenPGP);
503  CASE(OpenPGPMIME);
504  CASE(SMIME);
505  CASE(SMIMEOpaque);
506 #undef CASE
507  default: return 0;
508  }
509  }
510 
511  protected:
512  unsigned int mTotal;
513  unsigned int mInlineOpenPGP, mOpenPGPMIME, mSMIME, mSMIMEOpaque;
514  };
515 
516  class EncryptionFormatPreferenceCounter : public FormatPreferenceCounterBase {
517  public:
518  EncryptionFormatPreferenceCounter() : FormatPreferenceCounterBase() {}
519  void operator()( const Kleo::KeyResolver::Item & item );
520  };
521 
522  class SigningFormatPreferenceCounter : public FormatPreferenceCounterBase {
523  public:
524  SigningFormatPreferenceCounter() : FormatPreferenceCounterBase() {}
525  void operator()( const Kleo::KeyResolver::Item & item );
526  };
527 
528 #define CASE(x) if ( item.format & Kleo::x##Format ) ++m##x;
529  void EncryptionFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
530  if ( item.format & (Kleo::InlineOpenPGPFormat|Kleo::OpenPGPMIMEFormat) &&
531  std::find_if( item.keys.begin(), item.keys.end(),
532  ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) { // -= trusted?
533  CASE(OpenPGPMIME);
534  CASE(InlineOpenPGP);
535  }
536  if ( item.format & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) &&
537  std::find_if( item.keys.begin(), item.keys.end(),
538  ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) { // -= trusted?
539  CASE(SMIME);
540  CASE(SMIMEOpaque);
541  }
542  ++mTotal;
543  }
544 
545  void SigningFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
546  CASE(InlineOpenPGP);
547  CASE(OpenPGPMIME);
548  CASE(SMIME);
549  CASE(SMIMEOpaque);
550  ++mTotal;
551  }
552 #undef CASE
553 
554 } // anon namespace
555 
556 static TQString canonicalAddress( const TQString & _address ) {
557  const TQString address = KPIM::getEmailAddress( _address );
558  if ( address.find('@') == -1 ) {
559  // local address
560  //char hostname[1024];
561  //gethostname(hostname,1024);
562  //return address + '@' + hostname;
563  return address + "@localdomain";
564  }
565  else
566  return address;
567 }
568 
569 
570 struct FormatInfo {
571  std::vector<Kleo::KeyResolver::SplitInfo> splitInfos;
572  std::vector<GpgME::Key> signKeys;
573 };
574 
575 struct Kleo::KeyResolver::Private {
576  std::set<TQCString> alreadyWarnedFingerprints;
577 
578  std::vector<GpgME::Key> mOpenPGPSigningKeys; // signing
579  std::vector<GpgME::Key> mSMIMESigningKeys; // signing
580 
581  std::vector<GpgME::Key> mOpenPGPEncryptToSelfKeys; // encryption to self
582  std::vector<GpgME::Key> mSMIMEEncryptToSelfKeys; // encryption to self
583 
584  std::vector<Item> mPrimaryEncryptionKeys; // encryption to To/CC
585  std::vector<Item> mSecondaryEncryptionKeys; // encryption to BCC
586 
587  std::map<CryptoMessageFormat,FormatInfo> mFormatInfoMap;
588 
589  // key=email address, value=crypto preferences for this contact (from tdeabc)
590  typedef std::map<TQString, ContactPreferences> ContactPreferencesMap;
591  ContactPreferencesMap mContactPreferencesMap;
592 };
593 
594 
595 Kleo::KeyResolver::KeyResolver( bool encToSelf, bool showApproval, bool oppEncryption,
596  unsigned int f,
597  int encrWarnThresholdKey, int signWarnThresholdKey,
598  int encrWarnThresholdRootCert, int signWarnThresholdRootCert,
599  int encrWarnThresholdChainCert, int signWarnThresholdChainCert )
600  : mEncryptToSelf( encToSelf ),
601  mShowApprovalDialog( showApproval ),
602  mOpportunisticEncyption( oppEncryption ),
603  mCryptoMessageFormats( f ),
604  mEncryptKeyNearExpiryWarningThreshold( encrWarnThresholdKey ),
605  mSigningKeyNearExpiryWarningThreshold( signWarnThresholdKey ),
606  mEncryptRootCertNearExpiryWarningThreshold( encrWarnThresholdRootCert ),
607  mSigningRootCertNearExpiryWarningThreshold( signWarnThresholdRootCert ),
608  mEncryptChainCertNearExpiryWarningThreshold( encrWarnThresholdChainCert ),
609  mSigningChainCertNearExpiryWarningThreshold( signWarnThresholdChainCert )
610 {
611  d = new Private();
612 }
613 
614 Kleo::KeyResolver::~KeyResolver() {
615  delete d; d = 0;
616 }
617 
618 Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, const char * dontAskAgainName,
619  bool mine, bool sign, bool ca,
620  int recur_limit, const GpgME::Key & orig ) const {
621  if ( recur_limit <= 0 ) {
622  kdDebug() << "Kleo::KeyResolver::checkKeyNearExpiry(): key chain too long (>100 certs)" << endl;
623  return Kpgp::Ok;
624  }
625  const GpgME::Subkey subkey = key.subkey(0);
626  if ( d->alreadyWarnedFingerprints.count( subkey.fingerprint() ) )
627  return Kpgp::Ok; // already warned about this one (and so about it's issuers)
628 
629  if ( subkey.neverExpires() )
630  return Kpgp::Ok;
631  static const double secsPerDay = 24 * 60 * 60;
632  const double secsTillExpiry = ::difftime( subkey.expirationTime(), time(0) );
633  if ( secsTillExpiry <= 0 ) {
634  const int daysSinceExpiry = 1 + int( -secsTillExpiry / secsPerDay );
635  kdDebug() << "Key 0x" << key.shortKeyID() << " expired less than "
636  << daysSinceExpiry << " days ago" << endl;
637  const TQString msg =
638  key.protocol() == GpgME::Context::OpenPGP
639  ? ( mine ? sign
640  ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
641  "<p>expired less than a day ago.</p>",
642  "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
643  "<p>expired %n days ago.</p>",
644  daysSinceExpiry )
645  : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
646  "<p>expired less than a day ago.</p>",
647  "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
648  "<p>expired %n days ago.</p>",
649  daysSinceExpiry )
650  : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
651  "<p>expired less than a day ago.</p>",
652  "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
653  "<p>expired %n days ago.</p>",
654  daysSinceExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ),
655  key.shortKeyID() )
656  : ( ca
657  ? ( key.isRoot()
658  ? ( mine ? sign
659  ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
660  "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
661  "<p>expired less than a day ago.</p>",
662  "<p>The root certificate</p><p align=center><b>%3</b></p>"
663  "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
664  "<p>expired %n days ago.</p>",
665  daysSinceExpiry )
666  : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
667  "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
668  "<p>expired less than a day ago.</p>",
669  "<p>The root certificate</p><p align=center><b>%3</b></p>"
670  "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
671  "<p>expired %n days ago.</p>",
672  daysSinceExpiry )
673  : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
674  "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
675  "<p>expired less than a day ago.</p>",
676  "<p>The root certificate</p><p align=center><b>%3</b></p>"
677  "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
678  "<p>expired %n days ago.</p>",
679  daysSinceExpiry ) )
680  : ( mine ? sign
681  ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
682  "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
683  "<p>expired less than a day ago.</p>",
684  "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
685  "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
686  "<p>expired %n days ago.</p>",
687  daysSinceExpiry )
688  : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
689  "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
690  "<p>expired less than a day ago.</p>",
691  "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
692  "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
693  "<p>expired %n days ago.</p>",
694  daysSinceExpiry )
695  : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
696  "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
697  "<p>expired less than a day ago.</p>",
698  "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
699  "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
700  "<p>expired %n days ago.</p>",
701  daysSinceExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(),
702  orig.issuerSerial(),
703  Kleo::DN( key.userID(0).id() ).prettyDN() )
704  : ( mine ? sign
705  ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
706  "<p>expired less than a day ago.</p>",
707  "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
708  "<p>expired %n days ago.</p>",
709  daysSinceExpiry )
710  : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
711  "<p>expired less than a day ago.</p>",
712  "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
713  "<p>expired %n days ago.</p>",
714  daysSinceExpiry )
715  : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
716  "<p>expired less than a day ago.</p>",
717  "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
718  "<p>expired %n days ago.</p>",
719  daysSinceExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
720  key.issuerSerial() ) );
721  d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
722  if ( KMessageBox::warningContinueCancel( 0, msg,
723  key.protocol() == GpgME::Context::OpenPGP
724  ? i18n("OpenPGP Key Expired" )
725  : i18n("S/MIME Certificate Expired" ),
726  KStdGuiItem::cont(), dontAskAgainName ) == KMessageBox::Cancel )
727  return Kpgp::Canceled;
728  } else {
729  const int daysTillExpiry = 1 + int( secsTillExpiry / secsPerDay );
730  kdDebug() << "Key 0x" << key.shortKeyID() << " expires in less than "
731  << daysTillExpiry << " days" << endl;
732  const int threshold =
733  ca
734  ? ( key.isRoot()
735  ? ( sign
736  ? signingRootCertNearExpiryWarningThresholdInDays()
737  : encryptRootCertNearExpiryWarningThresholdInDays() )
738  : ( sign
739  ? signingChainCertNearExpiryWarningThresholdInDays()
740  : encryptChainCertNearExpiryWarningThresholdInDays() ) )
741  : ( sign
742  ? signingKeyNearExpiryWarningThresholdInDays()
743  : encryptKeyNearExpiryWarningThresholdInDays() );
744  if ( threshold > -1 && daysTillExpiry <= threshold ) {
745  const TQString msg =
746  key.protocol() == GpgME::Context::OpenPGP
747  ? ( mine ? sign
748  ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
749  "<p>expires in less than a day.</p>",
750  "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
751  "<p>expires in less than %n days.</p>",
752  daysTillExpiry )
753  : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
754  "<p>expires in less than a day.</p>",
755  "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
756  "<p>expires in less than %n days.</p>",
757  daysTillExpiry )
758  : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
759  "<p>expires in less than a day.</p>",
760  "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
761  "<p>expires in less than %n days.</p>",
762  daysTillExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ),
763  key.shortKeyID() )
764  : ( ca
765  ? ( key.isRoot()
766  ? ( mine ? sign
767  ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
768  "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
769  "<p>expires in less than a day.</p>",
770  "<p>The root certificate</p><p align=center><b>%3</b></p>"
771  "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
772  "<p>expires in less than %n days.</p>",
773  daysTillExpiry )
774  : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
775  "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
776  "<p>expires in less than a day.</p>",
777  "<p>The root certificate</p><p align=center><b>%3</b></p>"
778  "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
779  "<p>expires in less than %n days.</p>",
780  daysTillExpiry )
781  : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
782  "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
783  "<p>expires in less than a day.</p>",
784  "<p>The root certificate</p><p align=center><b>%3</b></p>"
785  "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
786  "<p>expires in less than %n days.</p>",
787  daysTillExpiry ) )
788  : ( mine ? sign
789  ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
790  "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
791  "<p>expires in less than a day.</p>",
792  "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
793  "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
794  "<p>expires in less than %n days.</p>",
795  daysTillExpiry )
796  : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
797  "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
798  "<p>expires in less than a day.</p>",
799  "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
800  "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
801  "<p>expires in less than %n days.</p>",
802  daysTillExpiry )
803  : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
804  "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
805  "<p>expires in less than a day.</p>",
806  "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
807  "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
808  "<p>expires in less than %n days.</p>",
809  daysTillExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(),
810  orig.issuerSerial(),
811  Kleo::DN( key.userID(0).id() ).prettyDN() )
812  : ( mine ? sign
813  ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
814  "<p>expires in less than a day.</p>",
815  "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
816  "<p>expires in less than %n days.</p>",
817  daysTillExpiry )
818  : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
819  "<p>expires in less than a day.</p>",
820  "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
821  "<p>expires in less than %n days.</p>",
822  daysTillExpiry )
823  : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
824  "<p>expires in less than a day.</p>",
825  "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
826  "<p>expires in less than %n days.</p>",
827  daysTillExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
828  key.issuerSerial() ) );
829  d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
830  if ( KMessageBox::warningContinueCancel( 0, msg,
831  key.protocol() == GpgME::Context::OpenPGP
832  ? i18n("OpenPGP Key Expires Soon" )
833  : i18n("S/MIME Certificate Expires Soon" ),
834  KStdGuiItem::cont(), dontAskAgainName )
835  == KMessageBox::Cancel )
836  return Kpgp::Canceled;
837  }
838  }
839  if ( key.isRoot() )
840  return Kpgp::Ok;
841  else if ( const char * chain_id = key.chainID() ) {
842  const std::vector<GpgME::Key> issuer = lookup( chain_id, false );
843  if ( issuer.empty() )
844  return Kpgp::Ok;
845  else
846  return checkKeyNearExpiry( issuer.front(), dontAskAgainName, mine, sign,
847  true, recur_limit-1, ca ? orig : key );
848  }
849  return Kpgp::Ok;
850 }
851 
852 Kpgp::Result Kleo::KeyResolver::setEncryptToSelfKeys( const TQStringList & fingerprints ) {
853  if ( !encryptToSelf() )
854  return Kpgp::Ok;
855 
856  std::vector<GpgME::Key> keys = lookup( fingerprints );
857  std::remove_copy_if( keys.begin(), keys.end(),
858  std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
859  NotValidTrustedOpenPGPEncryptionKey ); // -= trusted?
860  std::remove_copy_if( keys.begin(), keys.end(),
861  std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
862  NotValidTrustedSMIMEEncryptionKey ); // -= trusted?
863 
864  if ( d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size()
865  < keys.size() ) {
866  // too few keys remain...
867  const TQString msg = i18n("One or more of your configured OpenPGP encryption "
868  "keys or S/MIME certificates is not usable for "
869  "encryption. Please reconfigure your encryption keys "
870  "and certificates for this identity in the identity "
871  "configuration dialog.\n"
872  "If you choose to continue, and the keys are needed "
873  "later on, you will be prompted to specify the keys "
874  "to use.");
875  return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Encryption Keys"),
876  KStdGuiItem::cont(),
877  "unusable own encryption key warning" )
878  == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ;
879  }
880 
881  // check for near-expiry:
882 
883  for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPEncryptToSelfKeys.begin() ; it != d->mOpenPGPEncryptToSelfKeys.end() ; ++it ) {
884  const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning",
885  true, false );
886  if ( r != Kpgp::Ok )
887  return r;
888  }
889 
890  for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMEEncryptToSelfKeys.begin() ; it != d->mSMIMEEncryptToSelfKeys.end() ; ++it ) {
891  const Kpgp::Result r = checkKeyNearExpiry( *it, "own encryption key expires soon warning",
892  true, false );
893  if ( r != Kpgp::Ok )
894  return r;
895  }
896 
897  return Kpgp::Ok;
898 }
899 
900 Kpgp::Result Kleo::KeyResolver::setSigningKeys( const TQStringList & fingerprints ) {
901  std::vector<GpgME::Key> keys = lookup( fingerprints, true ); // secret keys
902  std::remove_copy_if( keys.begin(), keys.end(),
903  std::back_inserter( d->mOpenPGPSigningKeys ),
904  NotValidOpenPGPSigningKey );
905  std::remove_copy_if( keys.begin(), keys.end(),
906  std::back_inserter( d->mSMIMESigningKeys ),
907  NotValidSMIMESigningKey );
908 
909  if ( d->mOpenPGPSigningKeys.size() + d->mSMIMESigningKeys.size() < keys.size() ) {
910  // too few keys remain...
911  const TQString msg = i18n("One or more of your configured OpenPGP signing keys "
912  "or S/MIME signing certificates is not usable for "
913  "signing. Please reconfigure your signing keys "
914  "and certificates for this identity in the identity "
915  "configuration dialog.\n"
916  "If you choose to continue, and the keys are needed "
917  "later on, you will be prompted to specify the keys "
918  "to use.");
919  return KMessageBox::warningContinueCancel( 0, msg, i18n("Unusable Signing Keys"),
920  KStdGuiItem::cont(),
921  "unusable signing key warning" )
922  == KMessageBox::Continue ? Kpgp::Ok : Kpgp::Canceled ;
923  }
924 
925  // check for near expiry:
926 
927  for ( std::vector<GpgME::Key>::const_iterator it = d->mOpenPGPSigningKeys.begin() ; it != d->mOpenPGPSigningKeys.end() ; ++it ) {
928  const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning",
929  true, true );
930  if ( r != Kpgp::Ok )
931  return r;
932  }
933 
934  for ( std::vector<GpgME::Key>::const_iterator it = d->mSMIMESigningKeys.begin() ; it != d->mSMIMESigningKeys.end() ; ++it ) {
935  const Kpgp::Result r = checkKeyNearExpiry( *it, "signing key expires soon warning",
936  true, true );
937  if ( r != Kpgp::Ok )
938  return r;
939  }
940 
941  return Kpgp::Ok;
942 }
943 
944 void Kleo::KeyResolver::setPrimaryRecipients( const TQStringList & addresses ) {
945  d->mPrimaryEncryptionKeys = getEncryptionItems( addresses );
946 }
947 
948 void Kleo::KeyResolver::setSecondaryRecipients( const TQStringList & addresses ) {
949  d->mSecondaryEncryptionKeys = getEncryptionItems( addresses );
950 }
951 
952 std::vector<Kleo::KeyResolver::Item> Kleo::KeyResolver::getEncryptionItems( const TQStringList & addresses ) {
953  std::vector<Item> items;
954  items.reserve( addresses.size() );
955  for ( TQStringList::const_iterator it = addresses.begin() ; it != addresses.end() ; ++it ) {
956  TQString addr = canonicalAddress( *it ).lower();
957  const ContactPreferences pref = lookupContactPreferences( addr );
958 
959  items.push_back( Item( *it, /*getEncryptionKeys( *it, true ),*/
960  pref.encryptionPreference,
961  pref.signingPreference,
962  pref.cryptoMessageFormat ) );
963  }
964  return items;
965 }
966 
967 static Kleo::Action action( bool doit, bool ask, bool dont, bool requested ) {
968  if ( requested && !dont )
969  return Kleo::DoIt;
970  if ( doit && !ask && !dont )
971  return Kleo::DoIt;
972  if ( !doit && ask && !dont )
973  return Kleo::Ask;
974  if ( !doit && !ask && dont )
975  return requested ? Kleo::Conflict : Kleo::DontDoIt ;
976  if ( !doit && !ask && !dont )
977  return Kleo::DontDoIt ;
978  return Kleo::Conflict;
979 }
980 
981 Kleo::Action Kleo::KeyResolver::checkSigningPreferences( bool signingRequested ) const {
982 
983  if ( signingRequested && d->mOpenPGPSigningKeys.empty() && d->mSMIMESigningKeys.empty() )
984  return Impossible;
985 
986  SigningPreferenceCounter count;
987  count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
988  count );
989  count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
990  count );
991 
992  unsigned int sign = count.numAlwaysSign();
993  unsigned int ask = count.numAlwaysAskForSigning();
994  const unsigned int dontSign = count.numNeverSign();
995  if ( signingPossible() ) {
996  sign += count.numAlwaysSignIfPossible();
997  ask += count.numAskSigningWheneverPossible();
998  }
999 
1000  return action( sign, ask, dontSign, signingRequested );
1001 }
1002 
1003 bool Kleo::KeyResolver::signingPossible() const {
1004  return !d->mOpenPGPSigningKeys.empty() || !d->mSMIMESigningKeys.empty() ;
1005 }
1006 
1007 Kleo::Action Kleo::KeyResolver::checkEncryptionPreferences( bool encryptionRequested ) const {
1008 
1009  if ( d->mPrimaryEncryptionKeys.empty() && d->mSecondaryEncryptionKeys.empty() )
1010  return DontDoIt;
1011 
1012  if ( encryptionRequested && encryptToSelf() &&
1013  d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty() )
1014  return Impossible;
1015 
1016  if ( !encryptionRequested && !mOpportunisticEncyption ) {
1017  // try to minimize crypto ops (including key lookups) by only
1018  // looking up keys when at least one the the encryption
1019  // preferences needs it:
1020  EncryptionPreferenceCounter count( 0, UnknownPreference );
1021  count.process( d->mPrimaryEncryptionKeys );
1022  count.process( d->mSecondaryEncryptionKeys );
1023  if ( !count.numAlwaysEncrypt() &&
1024  !count.numAlwaysAskForEncryption() && // this guy might not need a lookup, when declined, but it's too complex to implement that here
1025  !count.numAlwaysEncryptIfPossible() &&
1026  !count.numAskWheneverPossible() )
1027  return DontDoIt;
1028  }
1029 
1030  EncryptionPreferenceCounter count( this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference );
1031  count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1032  count );
1033  count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1034  count );
1035 
1036  unsigned int encrypt = count.numAlwaysEncrypt();
1037  unsigned int ask = count.numAlwaysAskForEncryption();
1038  const unsigned int dontEncrypt = count.numNeverEncrypt() + count.numNoKey();
1039  if ( encryptionPossible() ) {
1040  encrypt += count.numAlwaysEncryptIfPossible();
1041  ask += count.numAskWheneverPossible();
1042  }
1043 
1044  const Action act = action( encrypt, ask, dontEncrypt, encryptionRequested );
1045  if ( act != Ask ||
1046  std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1047  std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1048  EncryptionPreferenceCounter( this, UnknownPreference ) ) ).numAlwaysAskForEncryption() )
1049  return act;
1050  else
1051  return AskOpportunistic;
1052 }
1053 
1054 bool Kleo::KeyResolver::encryptionPossible() const {
1055  return std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1056  EmptyKeyList ) == d->mPrimaryEncryptionKeys.end()
1057  && std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1058  EmptyKeyList ) == d->mSecondaryEncryptionKeys.end() ;
1059 }
1060 
1061 Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& encryptionRequested ) {
1062  if ( !encryptionRequested && !signingRequested ) {
1063  // make a dummy entry with all recipients, but no signing or
1064  // encryption keys to avoid special-casing on the caller side:
1065  dump();
1066  d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) );
1067  dump();
1068  return Kpgp::Ok;
1069  }
1070  Kpgp::Result result = Kpgp::Ok;
1071  if ( encryptionRequested )
1072  result = resolveEncryptionKeys( signingRequested );
1073  if ( result != Kpgp::Ok )
1074  return result;
1075  if ( signingRequested ) {
1076  if ( encryptionRequested ) {
1077  result = resolveSigningKeysForEncryption();
1078  }
1079  else {
1080  result = resolveSigningKeysForSigningOnly();
1081  if ( result == Kpgp::Failure ) {
1082  signingRequested = false;
1083  return Kpgp::Ok;
1084  }
1085  }
1086  }
1087  return result;
1088 }
1089 
1090 Kpgp::Result Kleo::KeyResolver::resolveEncryptionKeys( bool signingRequested ) {
1091  //
1092  // 1. Get keys for all recipients:
1093  //
1094 
1095  for ( std::vector<Item>::iterator it = d->mPrimaryEncryptionKeys.begin() ; it != d->mPrimaryEncryptionKeys.end() ; ++it ) {
1096  if ( !it->needKeys )
1097  continue;
1098  it->keys = getEncryptionKeys( it->address, false );
1099  if ( it->keys.empty() )
1100  return Kpgp::Canceled;
1101  TQString addr = canonicalAddress( it->address ).lower();
1102  const ContactPreferences pref = lookupContactPreferences( addr );
1103  it->pref = pref.encryptionPreference;
1104  it->signPref = pref.signingPreference;
1105  it->format = pref.cryptoMessageFormat;
1106  }
1107 
1108  for ( std::vector<Item>::iterator it = d->mSecondaryEncryptionKeys.begin() ; it != d->mSecondaryEncryptionKeys.end() ; ++it ) {
1109  if ( !it->needKeys )
1110  continue;
1111  it->keys = getEncryptionKeys( it->address, false );
1112  if ( it->keys.empty() )
1113  return Kpgp::Canceled;
1114  TQString addr = canonicalAddress( it->address ).lower();
1115  const ContactPreferences pref = lookupContactPreferences( addr );
1116  it->pref = pref.encryptionPreference;
1117  it->signPref = pref.signingPreference;
1118  it->format = pref.cryptoMessageFormat;
1119  }
1120 
1121  // 1a: Present them to the user
1122 
1123  const Kpgp::Result res = showKeyApprovalDialog();
1124  if ( res != Kpgp::Ok )
1125  return res;
1126 
1127  //
1128  // 2. Check what the primary recipients need
1129  //
1130 
1131  // 2a. Try to find a common format for all primary recipients,
1132  // else use as many formats as needed
1133 
1134  const EncryptionFormatPreferenceCounter primaryCount
1135  = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1136  EncryptionFormatPreferenceCounter() );
1137 
1138  CryptoMessageFormat commonFormat = AutoFormat;
1139  for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1140  if ( !( concreteCryptoMessageFormats[i] & mCryptoMessageFormats ) )
1141  continue;
1142  if ( signingRequested && signingKeysFor( concreteCryptoMessageFormats[i] ).empty() )
1143  continue;
1144  if ( encryptToSelf() && encryptToSelfKeysFor( concreteCryptoMessageFormats[i] ).empty() )
1145  continue;
1146  if ( primaryCount.numOf( concreteCryptoMessageFormats[i] ) == primaryCount.numTotal() ) {
1147  commonFormat = concreteCryptoMessageFormats[i];
1148  break;
1149  }
1150  }
1151  if ( commonFormat != AutoFormat )
1152  addKeys( d->mPrimaryEncryptionKeys, commonFormat );
1153  else
1154  addKeys( d->mPrimaryEncryptionKeys );
1155 
1156  collapseAllSplitInfos(); // these can be encrypted together
1157 
1158  // 2b. Just try to find _something_ for each secondary recipient,
1159  // with a preference to a common format (if that exists)
1160 
1161  const EncryptionFormatPreferenceCounter secondaryCount
1162  = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1163  EncryptionFormatPreferenceCounter() );
1164 
1165  if ( commonFormat != AutoFormat &&
1166  secondaryCount.numOf( commonFormat ) == secondaryCount.numTotal() )
1167  addKeys( d->mSecondaryEncryptionKeys, commonFormat );
1168  else
1169  addKeys( d->mSecondaryEncryptionKeys );
1170 
1171  // 3. Check for expiry:
1172 
1173  for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1174  const std::vector<SplitInfo> si_list = encryptionItems( concreteCryptoMessageFormats[i] );
1175  for ( std::vector<SplitInfo>::const_iterator sit = si_list.begin() ; sit != si_list.end() ; ++sit )
1176  for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit ) {
1177  const Kpgp::Result r = checkKeyNearExpiry( *kit, "other encryption key near expiry warning",
1178  false, false );
1179  if ( r != Kpgp::Ok )
1180  return r;
1181  }
1182  }
1183 
1184  // 4. Check that we have the right keys for encryptToSelf()
1185 
1186  if ( !encryptToSelf() )
1187  return Kpgp::Ok;
1188 
1189  // 4a. Check for OpenPGP keys
1190 
1191  if ( !encryptionItems( InlineOpenPGPFormat ).empty() ||
1192  !encryptionItems( OpenPGPMIMEFormat ).empty() ) {
1193  // need them
1194  if ( d->mOpenPGPEncryptToSelfKeys.empty() ) {
1195  const TQString msg = i18n("Examination of recipient's encryption preferences "
1196  "yielded that the message should be encrypted using "
1197  "OpenPGP, at least for some recipients;\n"
1198  "however, you have not configured valid trusted "
1199  "OpenPGP encryption keys for this identity.\n"
1200  "You may continue without encrypting to yourself, "
1201  "but be aware that you will not be able to read your "
1202  "own messages if you do so.");
1203  if ( KMessageBox::warningContinueCancel( 0, msg,
1204  i18n("Unusable Encryption Keys"),
1205  KStdGuiItem::cont(),
1206  "encrypt-to-self will fail warning" )
1207  == KMessageBox::Cancel )
1208  return Kpgp::Canceled;
1209  // FIXME: Allow selection
1210  }
1211  addToAllSplitInfos( d->mOpenPGPEncryptToSelfKeys,
1212  InlineOpenPGPFormat|OpenPGPMIMEFormat );
1213  }
1214 
1215  // 4b. Check for S/MIME certs:
1216 
1217  if ( !encryptionItems( SMIMEFormat ).empty() ||
1218  !encryptionItems( SMIMEOpaqueFormat ).empty() ) {
1219  // need them
1220  if ( d->mSMIMEEncryptToSelfKeys.empty() ) {
1221  // don't have one
1222  const TQString msg = i18n("Examination of recipient's encryption preferences "
1223  "yielded that the message should be encrypted using "
1224  "S/MIME, at least for some recipients;\n"
1225  "however, you have not configured valid "
1226  "S/MIME encryption certificates for this identity.\n"
1227  "You may continue without encrypting to yourself, "
1228  "but be aware that you will not be able to read your "
1229  "own messages if you do so.");
1230  if ( KMessageBox::warningContinueCancel( 0, msg,
1231  i18n("Unusable Encryption Keys"),
1232  KStdGuiItem::cont(),
1233  "encrypt-to-self will fail warning" )
1234  == KMessageBox::Cancel )
1235  return Kpgp::Canceled;
1236  // FIXME: Allow selection
1237  }
1238  addToAllSplitInfos( d->mSMIMEEncryptToSelfKeys,
1239  SMIMEFormat|SMIMEOpaqueFormat );
1240  }
1241 
1242  // FIXME: Present another message if _both_ OpenPGP and S/MIME keys
1243  // are missing.
1244 
1245  return Kpgp::Ok;
1246 }
1247 
1248 Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForEncryption() {
1249  if ( ( !encryptionItems( InlineOpenPGPFormat ).empty() ||
1250  !encryptionItems( OpenPGPMIMEFormat ).empty() )
1251  && d->mOpenPGPSigningKeys.empty() ) {
1252  const TQString msg = i18n("Examination of recipient's signing preferences "
1253  "yielded that the message should be signed using "
1254  "OpenPGP, at least for some recipients;\n"
1255  "however, you have not configured valid "
1256  "OpenPGP signing certificates for this identity.");
1257  if ( KMessageBox::warningContinueCancel( 0, msg,
1258  i18n("Unusable Signing Keys"),
1259  i18n("Do Not OpenPGP-Sign"),
1260  "signing will fail warning" )
1261  == KMessageBox::Cancel )
1262  return Kpgp::Canceled;
1263  // FIXME: Allow selection
1264  }
1265  if ( ( !encryptionItems( SMIMEFormat ).empty() ||
1266  !encryptionItems( SMIMEOpaqueFormat ).empty() )
1267  && d->mSMIMESigningKeys.empty() ) {
1268  const TQString msg = i18n("Examination of recipient's signing preferences "
1269  "yielded that the message should be signed using "
1270  "S/MIME, at least for some recipients;\n"
1271  "however, you have not configured valid "
1272  "S/MIME signing certificates for this identity.");
1273  if ( KMessageBox::warningContinueCancel( 0, msg,
1274  i18n("Unusable Signing Keys"),
1275  i18n("Do Not S/MIME-Sign"),
1276  "signing will fail warning" )
1277  == KMessageBox::Cancel )
1278  return Kpgp::Canceled;
1279  // FIXME: Allow selection
1280  }
1281 
1282  // FIXME: Present another message if _both_ OpenPGP and S/MIME keys
1283  // are missing.
1284 
1285  for ( std::map<CryptoMessageFormat,FormatInfo>::iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it )
1286  if ( !it->second.splitInfos.empty() ) {
1287  dump();
1288  it->second.signKeys = signingKeysFor( it->first );
1289  dump();
1290  }
1291 
1292  return Kpgp::Ok;
1293 }
1294 
1295 Kpgp::Result Kleo::KeyResolver::resolveSigningKeysForSigningOnly() {
1296  //
1297  // we don't need to distinguish between primary and secondary
1298  // recipients here:
1299  //
1300  SigningFormatPreferenceCounter count;
1301  count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1302  count );
1303  count = std::for_each( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1304  count );
1305 
1306  // try to find a common format that works for all (and that we have signing keys for):
1307 
1308  CryptoMessageFormat commonFormat = AutoFormat;
1309 
1310  for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1311  if ( !(mCryptoMessageFormats & concreteCryptoMessageFormats[i]) )
1312  continue; // skip
1313  if ( signingKeysFor( concreteCryptoMessageFormats[i] ).empty() )
1314  continue; // skip
1315  if ( count.numOf( concreteCryptoMessageFormats[i] ) == count.numTotal() ) {
1316  commonFormat = concreteCryptoMessageFormats[i];
1317  break;
1318  }
1319  }
1320 
1321  if ( commonFormat != AutoFormat ) { // found
1322  dump();
1323  FormatInfo & fi = d->mFormatInfoMap[ commonFormat ];
1324  fi.signKeys = signingKeysFor( commonFormat );
1325  fi.splitInfos.resize( 1 );
1326  fi.splitInfos.front() = SplitInfo( allRecipients() );
1327  dump();
1328  return Kpgp::Ok;
1329  }
1330 
1331  const TQString msg = i18n("Examination of recipient's signing preferences "
1332  "showed no common type of signature matching your "
1333  "available signing keys.\n"
1334  "Send message without signing?" );
1335  if ( KMessageBox::warningContinueCancel( 0, msg, i18n("No signing possible"),
1336  KStdGuiItem::cont() )
1337  == KMessageBox::Continue ) {
1338  d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.push_back( SplitInfo( allRecipients() ) );
1339  return Kpgp::Failure; // means "Ok, but without signing"
1340  }
1341  return Kpgp::Canceled;
1342 }
1343 
1344 std::vector<GpgME::Key> Kleo::KeyResolver::signingKeysFor( CryptoMessageFormat f ) const {
1345  if ( isOpenPGP( f ) )
1346  return d->mOpenPGPSigningKeys;
1347  if ( isSMIME( f ) )
1348  return d->mSMIMESigningKeys;
1349  return std::vector<GpgME::Key>();
1350 }
1351 
1352 std::vector<GpgME::Key> Kleo::KeyResolver::encryptToSelfKeysFor( CryptoMessageFormat f ) const {
1353  if ( isOpenPGP( f ) )
1354  return d->mOpenPGPEncryptToSelfKeys;
1355  if ( isSMIME( f ) )
1356  return d->mSMIMEEncryptToSelfKeys;
1357  return std::vector<GpgME::Key>();
1358 }
1359 
1360 TQStringList Kleo::KeyResolver::allRecipients() const {
1361  TQStringList result;
1362  std::transform( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1363  std::back_inserter( result ), ItemDotAddress );
1364  std::transform( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1365  std::back_inserter( result ), ItemDotAddress );
1366  return result;
1367 }
1368 
1369 void Kleo::KeyResolver::collapseAllSplitInfos() {
1370  dump();
1371  for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1372  std::map<CryptoMessageFormat,FormatInfo>::iterator pos =
1373  d->mFormatInfoMap.find( concreteCryptoMessageFormats[i] );
1374  if ( pos == d->mFormatInfoMap.end() )
1375  continue;
1376  std::vector<SplitInfo> & v = pos->second.splitInfos;
1377  if ( v.size() < 2 )
1378  continue;
1379  SplitInfo & si = v.front();
1380  for ( std::vector<SplitInfo>::const_iterator it = v.begin() + 1; it != v.end() ; ++it ) {
1381  si.keys.insert( si.keys.end(), it->keys.begin(), it->keys.end() );
1382  tqCopy( it->recipients.begin(), it->recipients.end(), std::back_inserter( si.recipients ) );
1383  }
1384  v.resize( 1 );
1385  }
1386  dump();
1387 }
1388 
1389 void Kleo::KeyResolver::addToAllSplitInfos( const std::vector<GpgME::Key> & keys, unsigned int f ) {
1390  dump();
1391  if ( !f || keys.empty() )
1392  return;
1393  for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1394  if ( !( f & concreteCryptoMessageFormats[i] ) )
1395  continue;
1396  std::map<CryptoMessageFormat,FormatInfo>::iterator pos =
1397  d->mFormatInfoMap.find( concreteCryptoMessageFormats[i] );
1398  if ( pos == d->mFormatInfoMap.end() )
1399  continue;
1400  std::vector<SplitInfo> & v = pos->second.splitInfos;
1401  for ( std::vector<SplitInfo>::iterator it = v.begin() ; it != v.end() ; ++it )
1402  it->keys.insert( it->keys.end(), keys.begin(), keys.end() );
1403  }
1404  dump();
1405 }
1406 
1407 void Kleo::KeyResolver::dump() const {
1408 #ifndef NDEBUG
1409  if ( d->mFormatInfoMap.empty() )
1410  std::cerr << "Keyresolver: Format info empty" << std::endl;
1411  for ( std::map<CryptoMessageFormat,FormatInfo>::const_iterator it = d->mFormatInfoMap.begin() ; it != d->mFormatInfoMap.end() ; ++it ) {
1412  std::cerr << "Format info for " << Kleo::cryptoMessageFormatToString( it->first )
1413  << ":" << std::endl
1414  << " Signing keys: ";
1415  for ( std::vector<GpgME::Key>::const_iterator sit = it->second.signKeys.begin() ; sit != it->second.signKeys.end() ; ++sit )
1416  std::cerr << sit->shortKeyID() << " ";
1417  std::cerr << std::endl;
1418  unsigned int i = 0;
1419  for ( std::vector<SplitInfo>::const_iterator sit = it->second.splitInfos.begin() ; sit != it->second.splitInfos.end() ; ++sit, ++i ) {
1420  std::cerr << " SplitInfo #" << i << " encryption keys: ";
1421  for ( std::vector<GpgME::Key>::const_iterator kit = sit->keys.begin() ; kit != sit->keys.end() ; ++kit )
1422  std::cerr << kit->shortKeyID() << " ";
1423  std::cerr << std::endl
1424  << " SplitInfo #" << i << " recipients: "
1425  << sit->recipients.join(", ").utf8().data() << std::endl;
1426  }
1427  }
1428 #endif
1429 }
1430 
1431 Kpgp::Result Kleo::KeyResolver::showKeyApprovalDialog() {
1432  const bool showKeysForApproval = showApprovalDialog()
1433  || std::find_if( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1434  ApprovalNeeded ) != d->mPrimaryEncryptionKeys.end()
1435  || std::find_if( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1436  ApprovalNeeded ) != d->mSecondaryEncryptionKeys.end() ;
1437 
1438  if ( !showKeysForApproval )
1439  return Kpgp::Ok;
1440 
1441  std::vector<Kleo::KeyApprovalDialog::Item> items;
1442  items.reserve( d->mPrimaryEncryptionKeys.size() +
1443  d->mSecondaryEncryptionKeys.size() );
1444  std::copy( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1445  std::back_inserter( items ) );
1446  std::copy( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1447  std::back_inserter( items ) );
1448 
1449  std::vector<GpgME::Key> senderKeys;
1450  senderKeys.reserve( d->mOpenPGPEncryptToSelfKeys.size() +
1451  d->mSMIMEEncryptToSelfKeys.size() );
1452  std::copy( d->mOpenPGPEncryptToSelfKeys.begin(), d->mOpenPGPEncryptToSelfKeys.end(),
1453  std::back_inserter( senderKeys ) );
1454  std::copy( d->mSMIMEEncryptToSelfKeys.begin(), d->mSMIMEEncryptToSelfKeys.end(),
1455  std::back_inserter( senderKeys ) );
1456 
1457  const KCursorSaver idle( KBusyPtr::idle() );
1458 
1459  Kleo::KeyApprovalDialog dlg( items, senderKeys );
1460 
1461  if ( dlg.exec() == TQDialog::Rejected )
1462  return Kpgp::Canceled;
1463 
1464  items = dlg.items();
1465  senderKeys = dlg.senderKeys();
1466 
1467  if ( dlg.preferencesChanged() ) {
1468  for ( uint i = 0; i < items.size(); ++i ) {
1469  ContactPreferences pref = lookupContactPreferences( items[i].address );
1470  pref.encryptionPreference = items[i].pref;
1471  pref.pgpKeyFingerprints.clear();
1472  pref.smimeCertFingerprints.clear();
1473  const std::vector<GpgME::Key> & keys = items[i].keys;
1474  for ( std::vector<GpgME::Key>::const_iterator it = keys.begin(), end = keys.end() ; it != end ; ++it ) {
1475  if ( it->protocol() == GpgME::Context::OpenPGP ) {
1476  if ( const char * fpr = it->primaryFingerprint() )
1477  pref.pgpKeyFingerprints.push_back( fpr );
1478  } else if ( it->protocol() == GpgME::Context::CMS ) {
1479  if ( const char * fpr = it->primaryFingerprint() )
1480  pref.smimeCertFingerprints.push_back( fpr );
1481  }
1482  }
1483  saveContactPreference( items[i].address, pref );
1484  }
1485  }
1486 
1487  // show a warning if the user didn't select an encryption key for
1488  // herself:
1489  if ( encryptToSelf() && senderKeys.empty() ) {
1490  const TQString msg = i18n("You did not select an encryption key for yourself "
1491  "(encrypt to self). You will not be able to decrypt "
1492  "your own message if you encrypt it.");
1493  if ( KMessageBox::warningContinueCancel( 0, msg,
1494  i18n("Missing Key Warning"),
1495  i18n("&Encrypt") )
1496  == KMessageBox::Cancel )
1497  return Kpgp::Canceled;
1498  else
1499  mEncryptToSelf = false;
1500  }
1501 
1502  // count empty key ID lists
1503  const unsigned int emptyListCount =
1504  std::count_if( items.begin(), items.end(), EmptyKeyList );
1505 
1506  // show a warning if the user didn't select an encryption key for
1507  // some of the recipients
1508  if ( items.size() == emptyListCount ) {
1509  const TQString msg = ( d->mPrimaryEncryptionKeys.size() +
1510  d->mSecondaryEncryptionKeys.size() == 1 )
1511  ? i18n("You did not select an encryption key for the "
1512  "recipient of this message; therefore, the message "
1513  "will not be encrypted.")
1514  : i18n("You did not select an encryption key for any of the "
1515  "recipients of this message; therefore, the message "
1516  "will not be encrypted.");
1517  if ( KMessageBox::warningContinueCancel( 0, msg,
1518  i18n("Missing Key Warning"),
1519  i18n("Send &Unencrypted") )
1520  == KMessageBox::Cancel )
1521  return Kpgp::Canceled;
1522  } else if ( emptyListCount > 0 ) {
1523  const TQString msg = ( emptyListCount == 1 )
1524  ? i18n("You did not select an encryption key for one of "
1525  "the recipients: this person will not be able to "
1526  "decrypt the message if you encrypt it.")
1527  : i18n("You did not select encryption keys for some of "
1528  "the recipients: these persons will not be able to "
1529  "decrypt the message if you encrypt it." );
1530  KCursorSaver idle( KBusyPtr::idle() );
1531  if ( KMessageBox::warningContinueCancel( 0, msg,
1532  i18n("Missing Key Warning"),
1533  i18n("&Encrypt") )
1534  == KMessageBox::Cancel )
1535  return Kpgp::Canceled;
1536  }
1537 
1538  std::transform( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
1539  items.begin(),
1540  d->mPrimaryEncryptionKeys.begin(),
1541  CopyKeysAndEncryptionPreferences );
1542  std::transform( d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(),
1543  items.begin() + d->mPrimaryEncryptionKeys.size(),
1544  d->mSecondaryEncryptionKeys.begin(),
1545  CopyKeysAndEncryptionPreferences );
1546 
1547  d->mOpenPGPEncryptToSelfKeys.clear();
1548  d->mSMIMEEncryptToSelfKeys.clear();
1549 
1550  std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
1551  std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
1552  NotValidTrustedOpenPGPEncryptionKey ); // -= trusted (see above, too)?
1553  std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
1554  std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
1555  NotValidTrustedSMIMEEncryptionKey ); // -= trusted (see above, too)?
1556 
1557  return Kpgp::Ok;
1558 }
1559 
1560 std::vector<Kleo::KeyResolver::SplitInfo> Kleo::KeyResolver::encryptionItems( Kleo::CryptoMessageFormat f ) const {
1561  dump();
1562  std::map<CryptoMessageFormat,FormatInfo>::const_iterator it =
1563  d->mFormatInfoMap.find( f );
1564  return it != d->mFormatInfoMap.end() ? it->second.splitInfos : std::vector<SplitInfo>() ;
1565 }
1566 
1567 std::vector<GpgME::Key> Kleo::KeyResolver::signingKeys( CryptoMessageFormat f ) const {
1568  dump();
1569  std::map<CryptoMessageFormat,FormatInfo>::const_iterator it =
1570  d->mFormatInfoMap.find( f );
1571  return it != d->mFormatInfoMap.end() ? it->second.signKeys : std::vector<GpgME::Key>() ;
1572 }
1573 
1574 //
1575 //
1576 // Private helper methods below:
1577 //
1578 //
1579 
1580 
1581 std::vector<GpgME::Key> Kleo::KeyResolver::selectKeys( const TQString & person, const TQString & msg, const std::vector<GpgME::Key> & selectedKeys ) const {
1582  const bool opgp = containsOpenPGP( mCryptoMessageFormats );
1583  const bool x509 = containsSMIME( mCryptoMessageFormats );
1584 
1585  Kleo::KeySelectionDialog dlg( i18n("Encryption Key Selection"),
1586  msg, KPIM::getEmailAddress(person), selectedKeys,
1587  Kleo::KeySelectionDialog::ValidEncryptionKeys
1588  & ~(opgp ? 0 : Kleo::KeySelectionDialog::OpenPGPKeys)
1589  & ~(x509 ? 0 : Kleo::KeySelectionDialog::SMIMEKeys),
1590  true, true ); // multi-selection and "remember choice" box
1591 
1592  if ( dlg.exec() != TQDialog::Accepted )
1593  return std::vector<GpgME::Key>();
1594  std::vector<GpgME::Key> keys = dlg.selectedKeys();
1595  keys.erase( std::remove_if( keys.begin(), keys.end(),
1596  NotValidTrustedEncryptionKey ), // -= trusted?
1597  keys.end() );
1598  if ( !keys.empty() && dlg.rememberSelection() )
1599  setKeysForAddress( person, dlg.pgpKeyFingerprints(), dlg.smimeFingerprints() );
1600  return keys;
1601 }
1602 
1603 
1604 std::vector<GpgME::Key> Kleo::KeyResolver::getEncryptionKeys( const TQString & person, bool quiet ) const {
1605 
1606  const TQString address = canonicalAddress( person ).lower();
1607 
1608  // First look for this person's address in the address->key dictionary
1609  const TQStringList fingerprints = keysForAddress( address );
1610 
1611  if ( !fingerprints.empty() ) {
1612  kdDebug() << "Using encryption keys 0x"
1613  << fingerprints.join( ", 0x" )
1614  << " for " << person << endl;
1615  std::vector<GpgME::Key> keys = lookup( fingerprints );
1616  if ( !keys.empty() ) {
1617  // Check if all of the keys are trusted and valid encryption keys
1618  if ( std::find_if( keys.begin(), keys.end(),
1619  NotValidTrustedEncryptionKey ) != keys.end() ) { // -= trusted?
1620 
1621  // not ok, let the user select: this is not conditional on !quiet,
1622  // since it's a bug in the configuration and the user should be
1623  // notified about it as early as possible:
1624  keys = selectKeys( person,
1625  i18n("if in your language something like "
1626  "'certificate(s)' isn't possible please "
1627  "use the plural in the translation",
1628  "There is a problem with the "
1629  "encryption certificate(s) for \"%1\".\n\n"
1630  "Please re-select the certificate(s) which should "
1631  "be used for this recipient.").arg(person),
1632  keys );
1633  }
1634  bool canceled = false;
1635  keys = trustedOrConfirmed( keys, address, canceled );
1636  if ( canceled )
1637  return std::vector<GpgME::Key>();
1638 
1639  if ( !keys.empty() )
1640  return keys;
1641  // keys.empty() is considered cancel by callers, so go on
1642  }
1643  }
1644 
1645  // Now search all public keys for matching keys
1646  std::vector<GpgME::Key> matchingKeys = lookup( person );
1647  matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
1648  NotValidEncryptionKey ),
1649  matchingKeys.end() );
1650  // if no keys match the complete address look for keys which match
1651  // the canonical mail address
1652  if ( matchingKeys.empty() ) {
1653  matchingKeys = lookup( address );
1654  matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
1655  NotValidEncryptionKey ),
1656  matchingKeys.end() );
1657  }
1658 
1659  // if called with quite == true (from EncryptionPreferenceCounter), we only want to
1660  // check if there are keys for this recipients, not (yet) their validity, so
1661  // don't show the untrusted encryption key warning in that case
1662  bool canceled = false;
1663  if ( !quiet )
1664  matchingKeys = trustedOrConfirmed( matchingKeys, address, canceled );
1665  if ( canceled )
1666  return std::vector<GpgME::Key>();
1667  if ( quiet || matchingKeys.size() == 1 )
1668  return matchingKeys;
1669 
1670  // no match until now, or more than one key matches; let the user
1671  // choose the key(s)
1672  // FIXME: let user get the key from keyserver
1673  return trustedOrConfirmed( selectKeys( person,
1674  matchingKeys.empty()
1675  ? i18n("if in your language something like "
1676  "'certificate(s)' isn't possible please "
1677  "use the plural in the translation",
1678  "<qt>No valid and trusted encryption certificate was "
1679  "found for \"%1\".<br/><br/>"
1680  "Select the certificate(s) which should "
1681  "be used for this recipient. If there is no suitable certificate in the list "
1682  "you can also search for external certificates by clicking the button: search for external certificates.</qt>")
1683  .arg( TQStyleSheet::escape(person) )
1684  : i18n("if in your language something like "
1685  "'certificate(s)' isn't possible please "
1686  "use the plural in the translation",
1687  "More than one certificate matches \"%1\".\n\n"
1688  "Select the certificate(s) which should "
1689  "be used for this recipient.").arg( TQStyleSheet::escape(person) ),
1690  matchingKeys ), address, canceled );
1691  // we can ignore 'canceled' here, since trustedOrConfirmed() returns
1692  // an empty vector when canceled == true, and we'd just do the same
1693 }
1694 
1695 
1696 std::vector<GpgME::Key> Kleo::KeyResolver::lookup( const TQStringList & patterns, bool secret ) const {
1697  if ( patterns.empty() )
1698  return std::vector<GpgME::Key>();
1699  kdDebug() << "Kleo::KeyResolver::lookup( \"" << patterns.join( "\", \"" )
1700  << "\", " << secret << " )" << endl;
1701  std::vector<GpgME::Key> result;
1702  if ( mCryptoMessageFormats & (InlineOpenPGPFormat|OpenPGPMIMEFormat) )
1703  if ( const Kleo::CryptoBackend::Protocol * p = Kleo::CryptoBackendFactory::instance()->openpgp() ) {
1704  std::unique_ptr<Kleo::KeyListJob> job( p->keyListJob( false, false, true ) ); // use validating keylisting
1705  if ( job ) {
1706  std::vector<GpgME::Key> keys;
1707  job->exec( patterns, secret, keys );
1708  result.insert( result.end(), keys.begin(), keys.end() );
1709  }
1710  }
1711  if ( mCryptoMessageFormats & (SMIMEFormat|SMIMEOpaqueFormat) )
1712  if ( const Kleo::CryptoBackend::Protocol * p = Kleo::CryptoBackendFactory::instance()->smime() ) {
1713  std::unique_ptr<Kleo::KeyListJob> job( p->keyListJob( false, false, true ) ); // use validating keylisting
1714  if ( job ) {
1715  std::vector<GpgME::Key> keys;
1716  job->exec( patterns, secret, keys );
1717  result.insert( result.end(), keys.begin(), keys.end() );
1718  }
1719  }
1720  kdDebug() << " returned " << result.size() << " keys" << endl;
1721  return result;
1722 }
1723 
1724 void Kleo::KeyResolver::addKeys( const std::vector<Item> & items, CryptoMessageFormat f ) {
1725  dump();
1726  for ( std::vector<Item>::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
1727  SplitInfo si( it->address );
1728  std::remove_copy_if( it->keys.begin(), it->keys.end(),
1729  std::back_inserter( si.keys ), IsNotForFormat( f ) );
1730  dump();
1731  kdWarning( si.keys.empty() )
1732  << "Kleo::KeyResolver::addKeys(): Fix EncryptionFormatPreferenceCounter. "
1733  << "It detected a common format, but the list of such keys for recipient \""
1734  << it->address << "\" is empty!" << endl;
1735  d->mFormatInfoMap[ f ].splitInfos.push_back( si );
1736  }
1737  dump();
1738 }
1739 
1740 void Kleo::KeyResolver::addKeys( const std::vector<Item> & items ) {
1741  dump();
1742  for ( std::vector<Item>::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
1743  SplitInfo si( it->address );
1744  CryptoMessageFormat f = AutoFormat;
1745  for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
1746  const CryptoMessageFormat fmt = concreteCryptoMessageFormats[i];
1747  if ( ( fmt & it->format ) &&
1748  kdtools::any( it->keys.begin(), it->keys.end(), IsForFormat( fmt ) ) )
1749  {
1750  f = fmt;
1751  break;
1752  }
1753  }
1754  if ( f == AutoFormat )
1755  kdWarning() << "Kleo::KeyResolver::addKeys(): Something went wrong. Didn't find a format for \""
1756  << it->address << "\"" << endl;
1757  else
1758  std::remove_copy_if( it->keys.begin(), it->keys.end(),
1759  std::back_inserter( si.keys ), IsNotForFormat( f ) );
1760  d->mFormatInfoMap[ f ].splitInfos.push_back( si );
1761  }
1762  dump();
1763 }
1764 
1765 Kleo::KeyResolver::ContactPreferences Kleo::KeyResolver::lookupContactPreferences( const TQString& address ) const
1766 {
1767  const Private::ContactPreferencesMap::iterator it =
1768  d->mContactPreferencesMap.find( address );
1769  if ( it != d->mContactPreferencesMap.end() )
1770  return it->second;
1771 
1772  TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self( true );
1773  const TDEABC::Addressee::List res = ab->findByEmail( address );
1774  ContactPreferences pref;
1775  if ( !res.isEmpty() ) {
1776  TDEABC::Addressee addr = res.first();
1777  TQString encryptPref = addr.custom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF" );
1778  pref.encryptionPreference = Kleo::stringToEncryptionPreference( encryptPref );
1779  TQString signPref = addr.custom( "KADDRESSBOOK", "CRYPTOSIGNPREF" );
1780  pref.signingPreference = Kleo::stringToSigningPreference( signPref );
1781  TQString cryptoFormats = addr.custom( "KADDRESSBOOK", "CRYPTOPROTOPREF" );
1782  pref.cryptoMessageFormat = Kleo::stringToCryptoMessageFormat( cryptoFormats );
1783  pref.pgpKeyFingerprints = TQStringList::split( ',', addr.custom( "KADDRESSBOOK", "OPENPGPFP" ) );
1784  pref.smimeCertFingerprints = TQStringList::split( ',', addr.custom( "KADDRESSBOOK", "SMIMEFP" ) );
1785  }
1786  // insert into map and grab resulting iterator
1787  d->mContactPreferencesMap.insert( std::make_pair( address, pref ) );
1788  return pref;
1789 }
1790 
1791 void Kleo::KeyResolver::saveContactPreference( const TQString& email, const ContactPreferences& pref ) const
1792 {
1793  d->mContactPreferencesMap.insert( std::make_pair( email, pref ) );
1794  TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self( true );
1795  TDEABC::Addressee::List res = ab->findByEmail( email );
1796 
1797  TDEABC::Addressee addr;
1798  if ( res.isEmpty() ) {
1799  bool ok = true;
1800  TQString fullName = KInputDialog::getText( i18n( "Name Selection" ), i18n( "Which name shall the contact '%1' have in your addressbook?" ).arg( email ), TQString(), &ok );
1801  if ( ok ) {
1802  addr.setNameFromString( fullName );
1803  addr.insertEmail( email, true );
1804  } else
1805  return;
1806  } else
1807  addr = res.first();
1808 
1809  addr.insertCustom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF", Kleo::encryptionPreferenceToString( pref.encryptionPreference ) );
1810  addr.insertCustom( "KADDRESSBOOK", "CRYPTOSIGNPREF", Kleo::signingPreferenceToString( pref.signingPreference ) );
1811  addr.insertCustom( "KADDRESSBOOK", "CRYPTOPROTOPREF", cryptoMessageFormatToString( pref.cryptoMessageFormat ) );
1812  addr.insertCustom( "KADDRESSBOOK", "OPENPGPFP", pref.pgpKeyFingerprints.join( "," ) );
1813  addr.insertCustom( "KADDRESSBOOK", "SMIMEFP", pref.smimeCertFingerprints.join( "," ) );
1814 
1815  ab->insertAddressee( addr );
1816  TDEABC::Ticket *ticket = ab->requestSaveTicket( addr.resource() );
1817  if ( ticket )
1818  ab->save( ticket );
1819 
1820  // Assumption: 'pref' comes from d->mContactPreferencesMap already, no need to update that
1821 }
1822 
1823 Kleo::KeyResolver::ContactPreferences::ContactPreferences()
1824  : encryptionPreference( UnknownPreference ),
1825  signingPreference( UnknownSigningPreference ),
1826  cryptoMessageFormat( AutoFormat )
1827 {
1828 }
1829 
1830 TQStringList Kleo::KeyResolver::keysForAddress( const TQString & address ) const {
1831  if( address.isEmpty() ) {
1832  return TQStringList();
1833  }
1834  TQString addr = canonicalAddress( address ).lower();
1835  const ContactPreferences pref = lookupContactPreferences( addr );
1836  return pref.pgpKeyFingerprints + pref.smimeCertFingerprints;
1837 }
1838 
1839 void Kleo::KeyResolver::setKeysForAddress( const TQString& address, const TQStringList& pgpKeyFingerprints, const TQStringList& smimeCertFingerprints ) const {
1840  if( address.isEmpty() ) {
1841  return;
1842  }
1843  TQString addr = canonicalAddress( address ).lower();
1844  ContactPreferences pref = lookupContactPreferences( addr );
1845  pref.pgpKeyFingerprints = pgpKeyFingerprints;
1846  pref.smimeCertFingerprints = smimeCertFingerprints;
1847  saveContactPreference( addr, pref );
1848 }
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
Definition: kcursorsaver.h:14
A class to resolve signing/encryption keys w.r.t.
Definition: keyresolver.h:127
std::vector< SplitInfo > encryptionItems(CryptoMessageFormat f) const
std::vector< GpgME::Key > signingKeys(CryptoMessageFormat f) const
void setSecondaryRecipients(const TQStringList &addresses)
Set the list of secondary (BCC) recipient addresses.
Action checkSigningPreferences(bool signingRequested) const
Determine whether to sign or not, depending on the per-recipient signing preferences,...
Kpgp::Result setEncryptToSelfKeys(const TQStringList &fingerprints)
Set the fingerprints of keys to be used for encrypting to self.
Action checkEncryptionPreferences(bool encryptionRequested) const
Determine whether to encrypt or not, depending on the per-recipient encryption preferences,...
Kpgp::Result setSigningKeys(const TQStringList &fingerprints)
Set the fingerprints of keys to be used for signing.
Kpgp::Result resolveAllKeys(bool &signingRequested, bool &encryptionRequested)
Queries the user for missing keys and displays a key approval dialog if needed.
void setPrimaryRecipients(const TQStringList &addresses)
Set the list of primary (To/CC) recipient addresses.