14#include "composer/keyresolver.h"
16#include "contactpreference/savecontactpreferencejob.h"
18#include "utils/kleo_util.h"
19#include <KCursorSaver>
21#include <KEmailAddress>
23#include <Libkleo/Algorithm>
24#include <Libkleo/Compliance>
25#include <Libkleo/ExpiryChecker>
26#include <Libkleo/KeySelectionDialog>
28#include <QGpgME/KeyListJob>
29#include <QGpgME/Protocol>
31#include <gpgme++/key.h>
32#include <gpgme++/keylistresult.h>
34#include "messagecomposer_debug.h"
35#include <Akonadi/ContactSearchJob>
36#include <KLocalizedString>
39#include <MessageCore/AutocryptRecipient>
40#include <MessageCore/AutocryptStorage>
61static inline bool EmptyKeyList(
const KeyApprovalDialog::Item &item)
63 return item.keys.empty();
66static inline QString ItemDotAddress(
const KeyResolver::Item &item)
71static inline bool ApprovalNeeded(
const KeyResolver::Item &item)
73 bool approvalNeeded = item.pref == Kleo::NeverEncrypt || item.keys.empty();
74 if (!approvalNeeded && Kleo::DeVSCompliance::isCompliant()) {
75 approvalNeeded = !Kleo::all_of(item.keys, &Kleo::DeVSCompliance::keyIsCompliant);
77 return approvalNeeded;
80static inline KeyResolver::Item CopyKeysAndEncryptionPreferences(
const KeyResolver::Item &oldItem,
const KeyApprovalDialog::Item &newItem)
82 return KeyResolver::Item(oldItem.address, newItem.keys, newItem.pref, oldItem.signPref, oldItem.format);
85static bool ValidOpenPGPEncryptionKey(
const GpgME::Key &key)
87 if (key.protocol() != GpgME::OpenPGP) {
90 if (key.isRevoked()) {
91 qCWarning(MESSAGECOMPOSER_LOG) <<
"is revoked";
93 if (key.isExpired()) {
94 qCWarning(MESSAGECOMPOSER_LOG) <<
"is expired";
96 if (key.isDisabled()) {
97 qCWarning(MESSAGECOMPOSER_LOG) <<
"is disabled";
99 if (!key.canEncrypt()) {
100 qCWarning(MESSAGECOMPOSER_LOG) <<
"can't encrypt";
102 if (key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt()) {
108static bool ValidTrustedOpenPGPEncryptionKey(
const GpgME::Key &key)
110 if (!ValidOpenPGPEncryptionKey(key)) {
113 const std::vector<GpgME::UserID> uids = key.userIDs();
114 auto end(uids.end());
115 for (
auto it = uids.begin(); it != end; ++it) {
116 if (!it->isRevoked() && it->validity() >= GpgME::UserID::Marginal) {
118 }
else if (it->isRevoked()) {
119 qCWarning(MESSAGECOMPOSER_LOG) <<
"a userid is revoked";
121 qCWarning(MESSAGECOMPOSER_LOG) <<
"bad validity" << int(it->validity());
127static bool ValidSMIMEEncryptionKey(
const GpgME::Key &key)
129 if (key.protocol() != GpgME::CMS) {
132 if (key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt()) {
138static bool ValidTrustedSMIMEEncryptionKey(
const GpgME::Key &key)
140 if (!ValidSMIMEEncryptionKey(key)) {
146static inline bool ValidTrustedEncryptionKey(
const GpgME::Key &key)
148 switch (key.protocol()) {
150 return ValidTrustedOpenPGPEncryptionKey(key);
152 return ValidTrustedSMIMEEncryptionKey(key);
158static inline bool ValidEncryptionKey(
const GpgME::Key &key)
160 switch (key.protocol()) {
162 return ValidOpenPGPEncryptionKey(key);
164 return ValidSMIMEEncryptionKey(key);
170static inline bool ValidSigningKey(
const GpgME::Key &key)
172 if (key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign()) {
175 return key.hasSecret();
178static inline bool ValidOpenPGPSigningKey(
const GpgME::Key &key)
180 return key.protocol() == GpgME::OpenPGP && ValidSigningKey(key);
183static inline bool ValidSMIMESigningKey(
const GpgME::Key &key)
185 return key.protocol() == GpgME::CMS && ValidSigningKey(key);
188static inline bool NotValidTrustedOpenPGPEncryptionKey(
const GpgME::Key &key)
190 return !ValidTrustedOpenPGPEncryptionKey(key);
193static inline bool NotValidTrustedSMIMEEncryptionKey(
const GpgME::Key &key)
195 return !ValidTrustedSMIMEEncryptionKey(key);
198static inline bool NotValidTrustedEncryptionKey(
const GpgME::Key &key)
200 return !ValidTrustedEncryptionKey(key);
203static inline bool NotValidEncryptionKey(
const GpgME::Key &key)
205 return !ValidEncryptionKey(key);
208static inline bool NotValidOpenPGPSigningKey(
const GpgME::Key &key)
210 return !ValidOpenPGPSigningKey(key);
213static inline bool NotValidSMIMESigningKey(
const GpgME::Key &key)
215 return !ValidSMIMESigningKey(key);
221 static int score(
const GpgME::UserID &uid)
223 return uid.isRevoked() || uid.isInvalid() ? -1 : uid.validity();
226 bool operator()(
const GpgME::UserID &lhs,
const GpgME::UserID &rhs)
const
228 return score(lhs) < score(rhs);
233static std::vector<GpgME::UserID> matchingUIDs(
const std::vector<GpgME::UserID> &uids,
const QString &address)
239 std::vector<GpgME::UserID> result;
240 result.reserve(uids.size());
242 for (
auto it = uids.begin(), end = uids.end(); it != end; ++it) {
244 if (
const char *email = it->email()) {
246 result.push_back(*it);
253static GpgME::UserID findBestMatchUID(
const GpgME::Key &key,
const QString &address)
255 const std::vector<GpgME::UserID> all = key.userIDs();
259 const std::vector<GpgME::UserID> matching = matchingUIDs(all,
address.toLower());
260 const std::vector<GpgME::UserID> &v = matching.empty() ? all : matching;
261 return *std::max_element(v.begin(), v.end(), ByTrustScore());
264static QStringList keysAsStrings(
const std::vector<GpgME::Key> &keys)
268 for (
auto it = keys.begin(); it != keys.end(); ++it) {
269 assert(!(*it).userID(0).isNull());
270 const auto userID = (*it).userID(0);
283static std::vector<GpgME::Key> trustedOrConfirmed(
const std::vector<GpgME::Key> &keys,
const QString &address,
bool &canceled)
286 std::vector<GpgME::Key> fishies;
287 std::vector<GpgME::Key> ickies;
288 std::vector<GpgME::Key> rewookies;
289 auto it = keys.begin();
290 const auto end = keys.end();
291 for (; it !=
end; ++it) {
292 const GpgME::Key &key = *it;
293 assert(ValidEncryptionKey(key));
294 const GpgME::UserID uid = findBestMatchUID(key, address);
295 if (uid.isRevoked()) {
296 rewookies.push_back(key);
298 if (!uid.isRevoked()) {
299 if (uid.validity() == GpgME::UserID::Marginal) {
300 fishies.push_back(key);
302 if (uid.validity() < GpgME::UserID::Never) {
303 ickies.push_back(key);
308 if (fishies.empty() && ickies.empty() && rewookies.empty()) {
314 "One or more of your configured OpenPGP encryption "
315 "keys or S/MIME certificates is not fully trusted "
318 "One or more of the OpenPGP encryption keys or S/MIME "
319 "certificates for recipient \"%1\" is not fully trusted "
323 if (!fishies.empty()) {
325 msg += i18n(
"\nThe following keys are only marginally trusted: \n");
326 msg += keysAsStrings(fishies).join(QLatin1Char(
','));
328 if (!ickies.empty()) {
329 msg += i18n(
"\nThe following keys or certificates have unknown trust level: \n");
330 msg += keysAsStrings(ickies).join(QLatin1Char(
','));
332 if (!rewookies.empty()) {
333 msg += i18n(
"\nThe following keys or certificates are <b>revoked</b>: \n");
334 msg += keysAsStrings(rewookies).join(QLatin1Char(
','));
339 i18nc(
"@title:window",
"Not Fully Trusted Encryption Keys"),
342 QStringLiteral(
"not fully trusted encryption key warning"))
353struct IsNotForFormat :
public std::function<bool(GpgME::Key)> {
354 IsNotForFormat(Kleo::CryptoMessageFormat f)
359 bool operator()(
const GpgME::Key &key)
const
361 return (isOpenPGP(format) && key.protocol() != GpgME::OpenPGP) || (isSMIME(format) && key.protocol() != GpgME::CMS);
364 const Kleo::CryptoMessageFormat format;
367struct IsForFormat : std::function<bool(GpgME::Key)> {
368 explicit IsForFormat(Kleo::CryptoMessageFormat f)
369 : protocol(isOpenPGP(f) ? GpgME::OpenPGP
370 : isSMIME(f) ? GpgME::CMS
375 bool operator()(
const GpgME::Key &key)
const
377 return key.protocol() == protocol;
380 const GpgME::Protocol protocol;
384class KeyResolver::SigningPreferenceCounter :
public std::function<void(KeyResolver::Item)>
387 SigningPreferenceCounter() =
default;
389 void operator()(
const KeyResolver::Item &item);
390#define make_int_accessor(x) \
391 unsigned int num##x() const \
395 make_int_accessor(UnknownSigningPreference) make_int_accessor(NeverSign) make_int_accessor(AlwaysSign) make_int_accessor(AlwaysSignIfPossible)
396 make_int_accessor(AlwaysAskForSigning) make_int_accessor(AskSigningWheneverPossible) make_int_accessor(Total)
397#undef make_int_accessor
398 private :
unsigned int mTotal = 0;
399 unsigned int mUnknownSigningPreference = 0;
400 unsigned int mNeverSign = 0;
401 unsigned int mAlwaysSign = 0;
402 unsigned int mAlwaysSignIfPossible = 0;
403 unsigned int mAlwaysAskForSigning = 0;
404 unsigned int mAskSigningWheneverPossible = 0;
407void KeyResolver::SigningPreferenceCounter::operator()(
const KeyResolver::Item &item)
409 switch (item.signPref) {
414 CASE(UnknownSigningPreference);
417 CASE(AlwaysSignIfPossible);
418 CASE(AlwaysAskForSigning);
419 CASE(AskSigningWheneverPossible);
425class KeyResolver::EncryptionPreferenceCounter :
public std::function<void(Item)>
430 EncryptionPreferenceCounter(
const KeyResolver *kr, EncryptionPreference defaultPreference)
432 , mDefaultPreference(defaultPreference)
436 void operator()(
Item &item);
438 template<
typename Container>
439 void process(Container &c)
441 *
this = std::for_each(c.begin(), c.end(), *
this);
444#define make_int_accessor(x) \
445 unsigned int num##x() const \
449 make_int_accessor(NoKey) make_int_accessor(NeverEncrypt) make_int_accessor(UnknownPreference) make_int_accessor(AlwaysEncrypt)
450 make_int_accessor(AlwaysEncryptIfPossible) make_int_accessor(AlwaysAskForEncryption) make_int_accessor(AskWheneverPossible) make_int_accessor(Total)
451#undef make_int_accessor
452 private : EncryptionPreference mDefaultPreference;
453 unsigned int mTotal = 0;
454 unsigned int mNoKey = 0;
455 unsigned int mNeverEncrypt = 0;
456 unsigned int mUnknownPreference = 0;
457 unsigned int mAlwaysEncrypt = 0;
458 unsigned int mAlwaysEncryptIfPossible = 0;
459 unsigned int mAlwaysAskForEncryption = 0;
460 unsigned int mAskWheneverPossible = 0;
463void KeyResolver::EncryptionPreferenceCounter::operator()(
Item &item)
467 item.keys = _this->getEncryptionKeys(item.address,
true);
469 if (item.keys.empty()) {
474 switch (!item.pref ? mDefaultPreference : item.pref) {
480 CASE(UnknownPreference);
482 CASE(AlwaysEncryptIfPossible);
483 CASE(AlwaysAskForEncryption);
484 CASE(AskWheneverPossible);
492class FormatPreferenceCounterBase :
public std::function<void(KeyResolver::Item)>
495 FormatPreferenceCounterBase() =
default;
497#define make_int_accessor(x) \
498 unsigned int num##x() const \
502 make_int_accessor(Total) make_int_accessor(InlineOpenPGP) make_int_accessor(OpenPGPMIME) make_int_accessor(SMIME) make_int_accessor(SMIMEOpaque)
503#undef make_int_accessor
505 [[nodiscard]]
unsigned int numOf(Kleo::CryptoMessageFormat f)
const
509 case Kleo::x##Format: \
522 unsigned int mTotal = 0;
523 unsigned int mInlineOpenPGP = 0;
524 unsigned int mOpenPGPMIME = 0;
525 unsigned int mSMIME = 0;
526 unsigned int mSMIMEOpaque = 0;
529class EncryptionFormatPreferenceCounter :
public FormatPreferenceCounterBase
532 EncryptionFormatPreferenceCounter() =
default;
534 void operator()(
const KeyResolver::Item &item);
537class SigningFormatPreferenceCounter :
public FormatPreferenceCounterBase
540 SigningFormatPreferenceCounter() =
default;
542 void operator()(
const KeyResolver::Item &item);
546 if (item.format & Kleo::x##Format) { \
549void EncryptionFormatPreferenceCounter::operator()(
const KeyResolver::Item &item)
551 if (item.format & (Kleo::InlineOpenPGPFormat | Kleo::OpenPGPMIMEFormat)
552 && std::any_of(item.keys.begin(),
554 ValidTrustedOpenPGPEncryptionKey)) {
558 if (item.format & (Kleo::SMIMEFormat | Kleo::SMIMEOpaqueFormat)
559 && std::any_of(item.keys.begin(),
561 ValidTrustedSMIMEEncryptionKey)) {
568void SigningFormatPreferenceCounter::operator()(
const KeyResolver::Item &item)
593 std::vector<KeyResolver::SplitInfo> splitInfos;
594 std::vector<GpgME::Key> signKeys;
598 bool mAkonadiLookupEnabled =
true;
599 bool mAutocryptEnabled =
false;
600 std::set<QByteArray> alreadyWarnedFingerprints;
602 std::vector<GpgME::Key> mOpenPGPSigningKeys;
603 std::vector<GpgME::Key> mSMIMESigningKeys;
605 std::vector<GpgME::Key> mOpenPGPEncryptToSelfKeys;
606 std::vector<GpgME::Key> mSMIMEEncryptToSelfKeys;
608 std::vector<Item> mPrimaryEncryptionKeys;
609 std::vector<Item> mSecondaryEncryptionKeys;
611 std::map<CryptoMessageFormat, FormatInfo> mFormatInfoMap;
614 using ContactPreferencesMap = std::map<QString, MessageComposer::ContactPreference>;
615 ContactPreferencesMap mContactPreferencesMap;
616 std::map<QByteArray, QString> mAutocryptMap;
617 std::shared_ptr<Kleo::ExpiryChecker> expiryChecker;
620KeyResolver::KeyResolver(
bool encToSelf,
bool showApproval,
bool oppEncryption,
unsigned int f,
const std::shared_ptr<Kleo::ExpiryChecker> &expiryChecker)
621 : d(new KeyResolverPrivate)
622 , mEncryptToSelf(encToSelf)
623 , mShowApprovalDialog(showApproval)
624 , mOpportunisticEncyption(oppEncryption)
625 , mCryptoMessageFormats(f)
627 d->expiryChecker = expiryChecker;
630KeyResolver::~KeyResolver() =
default;
634 if (!encryptToSelf()) {
638 std::vector<GpgME::Key> keys = lookup(fingerprints);
639 std::remove_copy_if(keys.begin(), keys.end(), std::back_inserter(d->mOpenPGPEncryptToSelfKeys),
640 NotValidTrustedOpenPGPEncryptionKey);
641 std::remove_copy_if(keys.begin(), keys.end(), std::back_inserter(d->mSMIMEEncryptToSelfKeys),
642 NotValidTrustedSMIMEEncryptionKey);
644 if (d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size() < keys.size()) {
647 "One or more of your configured OpenPGP encryption "
648 "keys or S/MIME certificates is not usable for "
649 "encryption. Please reconfigure your encryption keys "
650 "and certificates for this identity in the identity "
651 "configuration dialog.\n"
652 "If you choose to continue, and the keys are needed "
653 "later on, you will be prompted to specify the keys "
657 i18nc(
"@title:window",
"Unusable Encryption Keys"),
660 QStringLiteral(
"unusable own encryption key warning"))
667 std::vector<GpgME::Key>::const_iterator end(d->mOpenPGPEncryptToSelfKeys.end());
669 for (
auto it = d->mOpenPGPEncryptToSelfKeys.begin(); it != end; ++it) {
670 d->expiryChecker->checkKey(*it, Kleo::ExpiryChecker::OwnEncryptionKey);
672 std::vector<GpgME::Key>::const_iterator end2(d->mSMIMEEncryptToSelfKeys.end());
673 for (
auto it = d->mSMIMEEncryptToSelfKeys.begin(); it != end2; ++it) {
674 d->expiryChecker->checkKey(*it, Kleo::ExpiryChecker::OwnEncryptionKey);
682 std::vector<GpgME::Key> keys = lookup(fingerprints,
true);
683 std::remove_copy_if(keys.begin(), keys.end(), std::back_inserter(d->mOpenPGPSigningKeys), NotValidOpenPGPSigningKey);
684 std::remove_copy_if(keys.begin(), keys.end(), std::back_inserter(d->mSMIMESigningKeys), NotValidSMIMESigningKey);
686 if (d->mOpenPGPSigningKeys.size() + d->mSMIMESigningKeys.size() < keys.size()) {
689 "One or more of your configured OpenPGP signing keys "
690 "or S/MIME signing certificates is not usable for "
691 "signing. Please reconfigure your signing keys "
692 "and certificates for this identity in the identity "
693 "configuration dialog.\n"
694 "If you choose to continue, and the keys are needed "
695 "later on, you will be prompted to specify the keys "
699 i18nc(
"@title:window",
"Unusable Signing Keys"),
702 QStringLiteral(
"unusable signing key warning"))
710 for (
auto it = d->mOpenPGPSigningKeys.begin(), total = d->mOpenPGPSigningKeys.end(); it != total; ++it) {
711 d->expiryChecker->checkKey(*it, Kleo::ExpiryChecker::OwnSigningKey);
714 for (
auto it = d->mSMIMESigningKeys.begin(), total = d->mSMIMESigningKeys.end(); it != total; ++it) {
715 d->expiryChecker->checkKey(*it, Kleo::ExpiryChecker::OwnSigningKey);
723 d->mPrimaryEncryptionKeys = getEncryptionItems(addresses);
728 d->mSecondaryEncryptionKeys = getEncryptionItems(addresses);
731std::vector<KeyResolver::Item> KeyResolver::getEncryptionItems(
const QStringList &addresses)
733 std::vector<Item> items;
734 items.reserve(addresses.
size());
738 const auto pref = lookupContactPreferences(addr);
740 items.emplace_back(*it,
741 pref.encryptionPreference,
742 pref.signingPreference,
743 pref.cryptoMessageFormat);
748static Kleo::Action action(
bool doit,
bool ask,
bool donot,
bool requested)
750 if (requested && !donot) {
753 if (doit && !ask && !donot) {
756 if (!doit && ask && !donot) {
759 if (!doit && !ask && donot) {
760 return requested ? Kleo::Conflict : Kleo::DontDoIt;
762 if (!doit && !ask && !donot) {
763 return Kleo::DontDoIt;
765 return Kleo::Conflict;
770 if (signingRequested && d->mOpenPGPSigningKeys.empty() && d->mSMIMESigningKeys.empty()) {
774 SigningPreferenceCounter count;
775 count = std::for_each(d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), count);
776 count = std::for_each(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), count);
778 unsigned int sign = count.numAlwaysSign();
779 unsigned int ask = count.numAlwaysAskForSigning();
780 const unsigned int dontSign = count.numNeverSign();
781 if (signingPossible()) {
782 sign += count.numAlwaysSignIfPossible();
783 ask += count.numAskSigningWheneverPossible();
786 return action(sign, ask, dontSign, signingRequested);
789bool KeyResolver::signingPossible()
const
791 return !d->mOpenPGPSigningKeys.empty() || !d->mSMIMESigningKeys.empty();
796 if (d->mPrimaryEncryptionKeys.empty() && d->mSecondaryEncryptionKeys.empty()) {
800 if (encryptionRequested && encryptToSelf() && d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty()) {
804 if (!encryptionRequested && !mOpportunisticEncyption) {
808 EncryptionPreferenceCounter count(
nullptr, UnknownPreference);
809 count.process(d->mPrimaryEncryptionKeys);
810 count.process(d->mSecondaryEncryptionKeys);
811 if (!count.numAlwaysEncrypt()
812 && !count.numAlwaysAskForEncryption()
813 && !count.numAlwaysEncryptIfPossible() && !count.numAskWheneverPossible()) {
818 EncryptionPreferenceCounter count(
this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference);
819 count = std::for_each(d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), count);
820 count = std::for_each(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), count);
822 unsigned int encrypt = count.numAlwaysEncrypt();
823 unsigned int ask = count.numAlwaysAskForEncryption();
824 const unsigned int dontEncrypt = count.numNeverEncrypt() + count.numNoKey();
825 if (encryptionPossible()) {
826 encrypt += count.numAlwaysEncryptIfPossible();
827 ask += count.numAskWheneverPossible();
830 const Action act = action(encrypt, ask, dontEncrypt, encryptionRequested);
833 d->mPrimaryEncryptionKeys.begin(),
834 d->mPrimaryEncryptionKeys.end(),
835 std::for_each(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), EncryptionPreferenceCounter(
this, UnknownPreference)))
836 .numAlwaysAskForEncryption()) {
839 return AskOpportunistic;
843bool KeyResolver::encryptionPossible()
const
845 return std::none_of(d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), EmptyKeyList)
846 && std::none_of(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), EmptyKeyList);
851 if (!encryptionRequested && !signingRequested) {
855 d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.emplace_back(allRecipients());
859 ResolverResult
result = Ok;
860 if (encryptionRequested) {
861 bool finalySendUnencrypted =
false;
862 result = resolveEncryptionKeys(signingRequested, finalySendUnencrypted);
863 if (finalySendUnencrypted) {
864 encryptionRequested =
false;
870 if (encryptionRequested) {
871 result = resolveSigningKeysForEncryption();
873 result = resolveSigningKeysForSigningOnly();
875 signingRequested =
false;
882ResolverResult KeyResolver::resolveEncryptionKeys(
bool signingRequested,
bool &finalySendUnencrypted)
887 qCDebug(MESSAGECOMPOSER_LOG) <<
"resolving enc keys" << d->mPrimaryEncryptionKeys.size();
888 for (
auto it = d->mPrimaryEncryptionKeys.begin(); it != d->mPrimaryEncryptionKeys.end(); ++it) {
889 qCDebug(MESSAGECOMPOSER_LOG) <<
"checking primary:" << it->address;
893 it->keys = getEncryptionKeys(it->address,
false);
894 qCDebug(MESSAGECOMPOSER_LOG) <<
"got # keys:" << it->keys.size();
895 if (it->keys.empty()) {
899 const auto pref = lookupContactPreferences(addr);
900 it->pref = pref.encryptionPreference;
901 it->signPref = pref.signingPreference;
902 it->format = pref.cryptoMessageFormat;
903 qCDebug(MESSAGECOMPOSER_LOG) <<
"set key data:" << int(it->pref) << int(it->signPref) << int(it->format);
906 for (
auto it = d->mSecondaryEncryptionKeys.begin(), total = d->mSecondaryEncryptionKeys.end(); it != total; ++it) {
910 it->keys = getEncryptionKeys(it->address,
false);
911 if (it->keys.empty()) {
915 const auto pref = lookupContactPreferences(addr);
916 it->pref = pref.encryptionPreference;
917 it->signPref = pref.signingPreference;
918 it->format = pref.cryptoMessageFormat;
923 const ResolverResult res = showKeyApprovalDialog(finalySendUnencrypted);
935 const EncryptionFormatPreferenceCounter primaryCount =
936 std::for_each(d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), EncryptionFormatPreferenceCounter());
938 CryptoMessageFormat commonFormat = AutoFormat;
939 for (
unsigned int i = 0; i < numConcreteCryptoMessageFormats; ++i) {
940 if (!(concreteCryptoMessageFormats[i] & mCryptoMessageFormats)) {
943 if (signingRequested && signingKeysFor(concreteCryptoMessageFormats[i]).empty()) {
946 if (encryptToSelf() && encryptToSelfKeysFor(concreteCryptoMessageFormats[i]).empty()) {
949 if (primaryCount.numOf(concreteCryptoMessageFormats[i]) == primaryCount.numTotal()) {
950 commonFormat = concreteCryptoMessageFormats[i];
954 qCDebug(MESSAGECOMPOSER_LOG) <<
"got commonFormat for primary recipients:" << int(commonFormat);
955 if (commonFormat != AutoFormat) {
956 addKeys(d->mPrimaryEncryptionKeys, commonFormat);
958 addKeys(d->mPrimaryEncryptionKeys);
961 collapseAllSplitInfos();
966 const EncryptionFormatPreferenceCounter secondaryCount =
967 std::for_each(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), EncryptionFormatPreferenceCounter());
969 if (commonFormat != AutoFormat && secondaryCount.numOf(commonFormat) == secondaryCount.numTotal()) {
970 addKeys(d->mSecondaryEncryptionKeys, commonFormat);
972 addKeys(d->mSecondaryEncryptionKeys);
977 for (
unsigned int i = 0; i < numConcreteCryptoMessageFormats; ++i) {
978 const std::vector<SplitInfo> si_list = encryptionItems(concreteCryptoMessageFormats[i]);
979 for (
auto sit = si_list.begin(), total = si_list.end(); sit != total; ++sit) {
980 for (
auto kit = sit->keys.begin(); kit != sit->keys.end(); ++kit) {
981 d->expiryChecker->checkKey(*kit, Kleo::ExpiryChecker::EncryptionKey);
988 if (!encryptToSelf()) {
994 qCDebug(MESSAGECOMPOSER_LOG) <<
"sizes of encryption items:" << encryptionItems(InlineOpenPGPFormat).size() << encryptionItems(OpenPGPMIMEFormat).size()
995 << encryptionItems(SMIMEFormat).size() << encryptionItems(SMIMEOpaqueFormat).size();
996 if (!encryptionItems(InlineOpenPGPFormat).empty() || !encryptionItems(OpenPGPMIMEFormat).empty()) {
998 if (d->mOpenPGPEncryptToSelfKeys.empty()) {
1000 "Examination of recipient's encryption preferences "
1001 "yielded that the message should be encrypted using "
1002 "OpenPGP, at least for some recipients;\n"
1003 "however, you have not configured valid trusted "
1004 "OpenPGP encryption keys for this identity.\n"
1005 "You may continue without encrypting to yourself, "
1006 "but be aware that you will not be able to read your "
1007 "own messages if you do so.");
1010 i18nc(
"@title:window",
"Unusable Encryption Keys"),
1013 QStringLiteral(
"encrypt-to-self will fail warning"))
1019 addToAllSplitInfos(d->mOpenPGPEncryptToSelfKeys, InlineOpenPGPFormat | OpenPGPMIMEFormat);
1024 if (!encryptionItems(SMIMEFormat).empty() || !encryptionItems(SMIMEOpaqueFormat).empty()) {
1026 if (d->mSMIMEEncryptToSelfKeys.empty()) {
1029 "Examination of recipient's encryption preferences "
1030 "yielded that the message should be encrypted using "
1031 "S/MIME, at least for some recipients;\n"
1032 "however, you have not configured valid "
1033 "S/MIME encryption certificates for this identity.\n"
1034 "You may continue without encrypting to yourself, "
1035 "but be aware that you will not be able to read your "
1036 "own messages if you do so.");
1039 i18nc(
"@title:window",
"Unusable Encryption Keys"),
1042 QStringLiteral(
"encrypt-to-self will fail warning"))
1048 addToAllSplitInfos(d->mSMIMEEncryptToSelfKeys, SMIMEFormat | SMIMEOpaqueFormat);
1057ResolverResult KeyResolver::resolveSigningKeysForEncryption()
1059 if ((!encryptionItems(InlineOpenPGPFormat).empty() || !encryptionItems(OpenPGPMIMEFormat).empty()) && d->mOpenPGPSigningKeys.empty()) {
1061 "Examination of recipient's signing preferences "
1062 "yielded that the message should be signed using "
1063 "OpenPGP, at least for some recipients;\n"
1064 "however, you have not configured valid "
1065 "OpenPGP signing certificates for this identity.");
1068 i18nc(
"@title:window",
"Unusable Signing Keys"),
1071 QStringLiteral(
"signing will fail warning"))
1077 if ((!encryptionItems(SMIMEFormat).empty() || !encryptionItems(SMIMEOpaqueFormat).empty()) && d->mSMIMESigningKeys.empty()) {
1079 "Examination of recipient's signing preferences "
1080 "yielded that the message should be signed using "
1081 "S/MIME, at least for some recipients;\n"
1082 "however, you have not configured valid "
1083 "S/MIME signing certificates for this identity.");
1086 i18nc(
"@title:window",
"Unusable Signing Keys"),
1089 QStringLiteral(
"signing will fail warning"))
1099 for (
auto it = d->mFormatInfoMap.begin(); it != d->mFormatInfoMap.end(); ++it) {
1100 if (!it->second.splitInfos.empty()) {
1102 it->second.signKeys = signingKeysFor(it->first);
1110ResolverResult KeyResolver::resolveSigningKeysForSigningOnly()
1116 SigningFormatPreferenceCounter count;
1117 count = std::for_each(d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), count);
1118 count = std::for_each(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), count);
1122 CryptoMessageFormat commonFormat = AutoFormat;
1124 for (
unsigned int i = 0; i < numConcreteCryptoMessageFormats; ++i) {
1125 const auto res = concreteCryptoMessageFormats[i];
1126 if (!(mCryptoMessageFormats & res)) {
1129 if (signingKeysFor(res).empty()) {
1132 if (count.numOf(res) == count.numTotal()) {
1138 if (commonFormat != AutoFormat) {
1140 FormatInfo &fi = d->mFormatInfoMap[commonFormat];
1141 fi.signKeys = signingKeysFor(commonFormat);
1142 fi.splitInfos.resize(1);
1143 fi.splitInfos.front() = SplitInfo(allRecipients());
1149 "Examination of recipient's signing preferences "
1150 "showed no common type of signature matching your "
1151 "available signing keys.\n"
1152 "Send message without signing?");
1154 d->mFormatInfoMap[OpenPGPMIMEFormat].splitInfos.emplace_back(allRecipients());
1160std::vector<GpgME::Key> KeyResolver::signingKeysFor(CryptoMessageFormat f)
const
1163 return d->mOpenPGPSigningKeys;
1166 return d->mSMIMESigningKeys;
1171std::vector<GpgME::Key> KeyResolver::encryptToSelfKeysFor(CryptoMessageFormat f)
const
1174 return d->mOpenPGPEncryptToSelfKeys;
1177 return d->mSMIMEEncryptToSelfKeys;
1185 std::transform(d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), std::back_inserter(
result), ItemDotAddress);
1186 std::transform(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), std::back_inserter(
result), ItemDotAddress);
1190void KeyResolver::collapseAllSplitInfos()
1193 for (
unsigned int i = 0; i < numConcreteCryptoMessageFormats; ++i) {
1194 auto pos = d->mFormatInfoMap.find(concreteCryptoMessageFormats[i]);
1195 if (pos == d->mFormatInfoMap.end()) {
1198 std::vector<SplitInfo> &v = pos->second.splitInfos;
1202 SplitInfo &si = v.front();
1203 for (
auto it = v.begin() + 1; it != v.end(); ++it) {
1204 si.keys.insert(si.keys.end(), it->keys.begin(), it->keys.end());
1205 std::copy(it->recipients.begin(), it->recipients.end(), std::back_inserter(si.recipients));
1212void KeyResolver::addToAllSplitInfos(
const std::vector<GpgME::Key> &keys,
unsigned int f)
1215 if (!f || keys.empty()) {
1218 for (
unsigned int i = 0; i < numConcreteCryptoMessageFormats; ++i) {
1219 if (!(f & concreteCryptoMessageFormats[i])) {
1222 auto pos = d->mFormatInfoMap.find(concreteCryptoMessageFormats[i]);
1223 if (pos == d->mFormatInfoMap.end()) {
1226 std::vector<SplitInfo> &v = pos->second.splitInfos;
1227 for (
auto it = v.begin(); it != v.end(); ++it) {
1228 it->keys.insert(it->keys.end(), keys.begin(), keys.end());
1234void KeyResolver::dump()
const
1237 if (d->mFormatInfoMap.empty()) {
1238 qCDebug(MESSAGECOMPOSER_LOG) <<
"Keyresolver: Format info empty";
1240 for (
auto it = d->mFormatInfoMap.begin(); it != d->mFormatInfoMap.end(); ++it) {
1241 qCDebug(MESSAGECOMPOSER_LOG) <<
"Format info for " << Kleo::cryptoMessageFormatToString(it->first) <<
": Signing keys: ";
1242 for (
auto sit = it->second.signKeys.begin(); sit != it->second.signKeys.end(); ++sit) {
1243 qCDebug(MESSAGECOMPOSER_LOG) <<
" " << sit->shortKeyID() <<
" ";
1246 for (
auto sit = it->second.splitInfos.begin(), sitEnd = it->second.splitInfos.end(); sit != sitEnd; ++sit, ++i) {
1247 qCDebug(MESSAGECOMPOSER_LOG) <<
" SplitInfo #" << i <<
" encryption keys: ";
1248 for (
auto kit = sit->keys.begin(), sitEnd = sit->keys.end(); kit != sitEnd; ++kit) {
1249 qCDebug(MESSAGECOMPOSER_LOG) <<
" " << kit->shortKeyID();
1251 qCDebug(MESSAGECOMPOSER_LOG) <<
" SplitInfo #" << i <<
" recipients: " << qPrintable(sit->recipients.join(
QLatin1StringView(
", ")));
1257ResolverResult KeyResolver::showKeyApprovalDialog(
bool &finalySendUnencrypted)
1259 const bool showKeysForApproval = showApprovalDialog() || std::any_of(d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), ApprovalNeeded)
1260 || std::any_of(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), ApprovalNeeded);
1262 if (!showKeysForApproval) {
1266 std::vector<Kleo::KeyApprovalDialog::Item> items;
1267 items.reserve(d->mPrimaryEncryptionKeys.size() + d->mSecondaryEncryptionKeys.size());
1268 std::copy(d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(), std::back_inserter(items));
1269 std::copy(d->mSecondaryEncryptionKeys.begin(), d->mSecondaryEncryptionKeys.end(), std::back_inserter(items));
1271 std::vector<GpgME::Key> senderKeys;
1272 senderKeys.reserve(d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size());
1273 std::copy(d->mOpenPGPEncryptToSelfKeys.begin(), d->mOpenPGPEncryptToSelfKeys.end(), std::back_inserter(senderKeys));
1274 std::copy(d->mSMIMEEncryptToSelfKeys.begin(), d->mSMIMEEncryptToSelfKeys.end(), std::back_inserter(senderKeys));
1285 items = dlg->items();
1286 senderKeys = dlg->senderKeys();
1287 const bool prefsChanged = dlg->preferencesChanged();
1291 for (uint i = 0, total = items.size(); i < total; ++i) {
1292 auto pref = lookupContactPreferences(items[i].address);
1293 pref.encryptionPreference = items[i].pref;
1294 pref.pgpKeyFingerprints.clear();
1295 pref.smimeCertFingerprints.clear();
1296 const std::vector<GpgME::Key> &keys = items[i].keys;
1297 for (
auto it = keys.begin(), end = keys.end(); it != end; ++it) {
1298 if (it->protocol() == GpgME::OpenPGP) {
1299 if (
const char *fpr = it->primaryFingerprint()) {
1302 }
else if (it->protocol() == GpgME::CMS) {
1303 if (
const char *fpr = it->primaryFingerprint()) {
1308 saveContactPreference(items[i].address, pref);
1314 if (encryptToSelf() && senderKeys.empty()) {
1316 "You did not select an encryption key for yourself "
1317 "(encrypt to self). You will not be able to decrypt "
1318 "your own message if you encrypt it.");
1323 mEncryptToSelf =
false;
1328 const unsigned int emptyListCount = std::count_if(items.begin(), items.end(), EmptyKeyList);
1332 if (items.size() == emptyListCount) {
1333 const QString msg = (d->mPrimaryEncryptionKeys.size() + d->mSecondaryEncryptionKeys.size() == 1)
1335 "You did not select an encryption key for the "
1336 "recipient of this message; therefore, the message "
1337 "will not be encrypted.")
1339 "You did not select an encryption key for any of the "
1340 "recipients of this message; therefore, the message "
1341 "will not be encrypted.");
1344 i18nc(
"@title:window",
"Missing Key Warning"),
1349 finalySendUnencrypted =
true;
1350 }
else if (emptyListCount > 0) {
1352 "You did not select an encryption key for one of "
1353 "the recipients: this person will not be able to "
1354 "decrypt the message if you encrypt it.")
1356 "You did not select encryption keys for some of "
1357 "the recipients: these persons will not be able to "
1358 "decrypt the message if you encrypt it.");
1366 std::transform(d->mPrimaryEncryptionKeys.begin(),
1367 d->mPrimaryEncryptionKeys.end(),
1369 d->mPrimaryEncryptionKeys.begin(),
1370 CopyKeysAndEncryptionPreferences);
1371 std::transform(d->mSecondaryEncryptionKeys.begin(),
1372 d->mSecondaryEncryptionKeys.end(),
1373 items.begin() + d->mPrimaryEncryptionKeys.size(),
1374 d->mSecondaryEncryptionKeys.begin(),
1375 CopyKeysAndEncryptionPreferences);
1377 d->mOpenPGPEncryptToSelfKeys.clear();
1378 d->mSMIMEEncryptToSelfKeys.clear();
1380 std::remove_copy_if(senderKeys.begin(),
1382 std::back_inserter(d->mOpenPGPEncryptToSelfKeys),
1383 NotValidTrustedOpenPGPEncryptionKey);
1384 std::remove_copy_if(senderKeys.begin(),
1386 std::back_inserter(d->mSMIMEEncryptToSelfKeys),
1387 NotValidTrustedSMIMEEncryptionKey);
1395 auto it = d->mFormatInfoMap.find(f);
1396 return it != d->mFormatInfoMap.end() ? it->second.splitInfos : std::vector<SplitInfo>();
1401 d->mAutocryptEnabled = autocryptEnabled;
1404std::map<QByteArray, QString> KeyResolver::useAutocrypt()
const
1406 return d->mAutocryptMap;
1411 d->mAkonadiLookupEnabled = akonadiLoopkupEnabled;
1417 auto it = d->mFormatInfoMap.find(f);
1418 return it != d->mFormatInfoMap.end() ? it->second.signKeys : std::vector<GpgME::Key>();
1427std::vector<GpgME::Key> KeyResolver::selectKeys(
const QString &person,
const QString &msg,
const std::vector<GpgME::Key> &selectedKeys)
const
1429 const bool opgp = containsOpenPGP(mCryptoMessageFormats);
1430 const bool x509 = containsSMIME(mCryptoMessageFormats);
1433 i18n(
"Encryption Key Selection"),
1437 Kleo::KeySelectionDialog::ValidEncryptionKeys & ~(opgp ? 0 : Kleo::KeySelectionDialog::OpenPGPKeys) & ~(x509 ? 0 : Kleo::KeySelectionDialog::SMIMEKeys),
1446 std::vector<GpgME::Key> keys = dlg->selectedKeys();
1447 keys.erase(std::remove_if(keys.begin(), keys.end(), NotValidEncryptionKey), keys.end());
1448 if (!keys.empty() && dlg->rememberSelection()) {
1449 setKeysForAddress(person, dlg->pgpKeyFingerprints(), dlg->smimeFingerprints());
1456std::vector<GpgME::Key> KeyResolver::getEncryptionKeys(
const QString &person,
bool quiet)
const
1461 const QStringList fingerprints = keysForAddress(address);
1463 if (!fingerprints.
empty()) {
1464 qCDebug(MESSAGECOMPOSER_LOG) <<
"Using encryption keys 0x" << fingerprints.
join(
QLatin1StringView(
", 0x")) <<
"for" << person;
1465 std::vector<GpgME::Key> keys = lookup(fingerprints);
1466 if (!keys.empty()) {
1468 if (std::any_of(keys.begin(), keys.end(),
1469 NotValidTrustedEncryptionKey)) {
1473 keys = selectKeys(person,
1474 i18nc(
"if in your language something like "
1475 "'certificate(s)' is not possible please "
1476 "use the plural in the translation",
1477 "There is a problem with the "
1478 "encryption certificate(s) for \"%1\".\n\n"
1479 "Please re-select the certificate(s) which should "
1480 "be used for this recipient.",
1484 bool canceled =
false;
1485 keys = trustedOrConfirmed(keys, address, canceled);
1490 if (!keys.empty()) {
1498 std::vector<GpgME::Key> matchingKeys = lookup(
QStringList(address));
1499 matchingKeys.erase(std::remove_if(matchingKeys.begin(), matchingKeys.end(), NotValidEncryptionKey), matchingKeys.end());
1501 if (matchingKeys.empty() && d->mAutocryptEnabled) {
1502 qCDebug(MESSAGECOMPOSER_LOG) <<
"Search in Autocrypt storage a key for " <<
address;
1503 const auto storage = MessageCore::AutocryptStorage::self();
1504 const auto recipient = storage->getRecipient(
address.toUtf8());
1506 const auto key = recipient->gpgKey();
1507 if (!key.isNull() && ValidEncryptionKey(key)) {
1508 qCDebug(MESSAGECOMPOSER_LOG) <<
"Found an valid autocrypt key.";
1509 matchingKeys.push_back(key);
1511 const auto gossipKey = recipient->gossipKey();
1512 if (!gossipKey.isNull() && ValidEncryptionKey(gossipKey)) {
1513 qCDebug(MESSAGECOMPOSER_LOG) <<
"Found an valid autocrypt gossip key.";
1514 matchingKeys.push_back(gossipKey);
1519 if (matchingKeys.size() == 1) {
1520 if (recipient->prefer_encrypt()) {
1521 d->mContactPreferencesMap[
address].encryptionPreference = AlwaysEncryptIfPossible;
1523 d->mAutocryptMap[matchingKeys[0].primaryFingerprint()] =
address;
1524 return matchingKeys;
1531 bool canceled =
false;
1533 matchingKeys = trustedOrConfirmed(matchingKeys, address, canceled);
1538 if (quiet || matchingKeys.size() == 1) {
1539 return matchingKeys;
1545 return trustedOrConfirmed(selectKeys(person,
1546 matchingKeys.empty() ?
i18nc(
"if in your language something like "
1547 "'certificate(s)' is not possible please "
1548 "use the plural in the translation",
1549 "<qt>No valid and trusted encryption certificate was "
1550 "found for \"%1\".<br/><br/>"
1551 "Select the certificate(s) which should "
1552 "be used for this recipient. If there is no suitable certificate in the list "
1553 "you can also search for external certificates by clicking the button: "
1554 "search for external certificates.</qt>",
1556 :
i18nc(
"if in your language something like "
1557 "'certificate(s)' is not possible please "
1558 "use the plural in the translation",
1559 "More than one certificate matches \"%1\".\n\n"
1560 "Select the certificate(s) which should "
1561 "be used for this recipient.",
1570std::vector<GpgME::Key> KeyResolver::lookup(
const QStringList &patterns,
bool secret)
const
1572 if (patterns.
empty()) {
1575 qCDebug(MESSAGECOMPOSER_LOG) <<
"( \"" << patterns.
join(
QLatin1StringView(
"\", \"")) <<
"\"," << secret <<
")";
1576 std::vector<GpgME::Key>
result;
1577 if (mCryptoMessageFormats & (InlineOpenPGPFormat | OpenPGPMIMEFormat)) {
1578 if (
const QGpgME::Protocol *p = QGpgME::openpgp()) {
1579 std::unique_ptr<QGpgME::KeyListJob> job(p->keyListJob(
false,
false,
true));
1581 std::vector<GpgME::Key> keys;
1582 job->exec(patterns, secret, keys);
1587 if (mCryptoMessageFormats & (SMIMEFormat | SMIMEOpaqueFormat)) {
1588 if (
const QGpgME::Protocol *p = QGpgME::smime()) {
1589 std::unique_ptr<QGpgME::KeyListJob> job(p->keyListJob(
false,
false,
true));
1591 std::vector<GpgME::Key> keys;
1592 job->exec(patterns, secret, keys);
1597 qCDebug(MESSAGECOMPOSER_LOG) <<
" returned" <<
result.size() <<
"keys";
1601void KeyResolver::addKeys(
const std::vector<Item> &items, CryptoMessageFormat f)
1604 for (
auto it = items.begin(); it != items.end(); ++it) {
1606 std::remove_copy_if(it->keys.begin(), it->keys.end(), std::back_inserter(si.keys), IsNotForFormat(f));
1608 if (si.keys.empty()) {
1609 qCWarning(MESSAGECOMPOSER_LOG) <<
"Kleo::KeyResolver::addKeys(): Fix EncryptionFormatPreferenceCounter."
1610 <<
"It detected a common format, but the list of such keys for recipient \"" << it->address <<
"\" is empty!";
1612 d->mFormatInfoMap[f].splitInfos.push_back(si);
1617void KeyResolver::addKeys(
const std::vector<Item> &items)
1620 for (
auto it = items.begin(); it != items.end(); ++it) {
1622 CryptoMessageFormat f = AutoFormat;
1623 for (
unsigned int i = 0; i < numConcreteCryptoMessageFormats; ++i) {
1624 const CryptoMessageFormat fmt = concreteCryptoMessageFormats[i];
1625 if ((fmt & it->format) && std::any_of(it->keys.begin(), it->keys.end(), IsForFormat(fmt))) {
1630 if (f == AutoFormat) {
1631 qCWarning(MESSAGECOMPOSER_LOG) <<
"Something went wrong. Didn't find a format for \"" << it->address <<
"\"";
1633 std::remove_copy_if(it->keys.begin(), it->keys.end(), std::back_inserter(si.keys), IsNotForFormat(f));
1635 d->mFormatInfoMap[f].splitInfos.push_back(si);
1640MessageComposer::ContactPreference KeyResolver::lookupContactPreferences(
const QString &address)
const
1642 const auto it = d->mContactPreferencesMap.find(address);
1643 if (it != d->mContactPreferencesMap.end()) {
1647 MessageComposer::ContactPreference pref;
1649 if (!d->mAkonadiLookupEnabled) {
1659 if (!res.isEmpty()) {
1661 pref.fillFromAddressee(addr);
1664 const_cast<KeyResolver *
>(
this)->setContactPreferences(address, pref);
1671 d->mContactPreferencesMap.insert(std::make_pair(address, pref));
1674void KeyResolver::saveContactPreference(
const QString &email,
const MessageComposer::ContactPreference &pref)
const
1676 d->mContactPreferencesMap.insert(std::make_pair(email, pref));
1677 auto saveContactPreferencesJob =
new MessageComposer::SaveContactPreferenceJob(email, pref);
1678 saveContactPreferencesJob->start();
1687 const auto pref = lookupContactPreferences(addr);
1688 return pref.pgpKeyFingerprints + pref.smimeCertFingerprints;
1691void KeyResolver::setKeysForAddress(
const QString &address,
const QStringList &pgpKeyFingerprints,
const QStringList &smimeCertFingerprints)
const
1697 auto pref = lookupContactPreferences(addr);
1698 pref.pgpKeyFingerprints = pgpKeyFingerprints;
1699 pref.smimeCertFingerprints = smimeCertFingerprints;
1700 saveContactPreference(addr, pref);
1703bool KeyResolver::encryptToSelf()
const
1705 return mEncryptToSelf;
1708bool KeyResolver::showApprovalDialog()
const
1710 return mShowApprovalDialog;
KeyResolver(bool encrypt, bool sign, GpgME::Protocol protocol=GpgME::UnknownProtocol, bool allowMixed=true)
void setSigningKeys(const QStringList &fingerprints)
void setContactPreferences(const QString &address, const ContactPreference &preference)
Sets crypto preferences for given email address.
void setPrimaryRecipients(const QStringList &addresses)
Set the list of primary (To/CC) recipient addresses.
std::vector< GpgME::Key > signingKeys(Kleo::CryptoMessageFormat f) const
void setAkonadiLookupEnabled(bool akonadiLookupEnabled)
Disable ContactSearchJob in KeyResolver.
ResolverResult setEncryptToSelfKeys(const QStringList &fingerprints)
Set the fingerprints of keys to be used for encrypting to self.
ResolverResult resolveAllKeys(bool &signingRequested, bool &encryptionRequested)
Queries the user for missing keys and displays a key approval dialog if needed.
void setAutocryptEnabled(bool autocryptEnabled)
If Autocrypt keys are used to find valid PGP Keys.
void setSecondaryRecipients(const QStringList &addresses)
Set the list of secondary (BCC) recipient addresses.
Kleo::Action checkEncryptionPreferences(bool encryptionRequested) const
Determine whether to encrypt or not, depending on the per-recipient encryption preferences,...
std::vector< SplitInfo > encryptionItems(Kleo::CryptoMessageFormat f) const
Kleo::Action checkSigningPreferences(bool signingRequested) const
Determine whether to sign or not, depending on the per-recipient signing preferences,...
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
PostalAddress address(const QVariant &location)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
const QList< QKeySequence > & end()
Simple interface that both EncryptJob and SignEncryptJob implement so the composer can extract some e...
void append(QList< T > &&value)
const_iterator constBegin() const const
const_iterator constEnd() const const
void reserve(qsizetype size)
qsizetype size() const const
const QChar at(qsizetype position) const const
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QString toHtmlEscaped() const const
QString toLower() const const
QString join(QChar separator) const const