8#include "filteractionencrypt.h"
9#include "mailcommon_debug.h"
10#include "util/cryptoutils.h"
17#include <KLocalizedString>
19#include <KMime/Message>
21#include <QGpgME/EncryptJob>
22#include <QGpgME/KeyListJob>
23#include <QGpgME/ListAllKeysJob>
24#include <QGpgME/Protocol>
25#include <gpgme++/encryptionresult.h>
26#include <gpgme++/keylistresult.h>
28#include <Libkleo/DefaultKeyFilter>
29#include <Libkleo/KeySelectionCombo>
31#include <MessageComposer/EncryptJob>
33#include <Akonadi/MessageFlags>
35#include <KColorScheme>
39#define LISTING_FINISHED "listingFinished"
40#define IGNORE_KEY_CHANGE "ignoreKeyChange"
42FilterActionEncrypt::FilterActionEncrypt(
QObject *parent)
43 : FilterActionWithCrypto(QStringLiteral(
"encrypt"),
i18n(
"Encrypt"), parent)
44 , mKeyCache(
Kleo::KeyCache::instance())
48FilterActionEncrypt::~FilterActionEncrypt() =
default;
52 return new FilterActionEncrypt();
55QString FilterActionEncrypt::displayString()
const
60QString FilterActionEncrypt::argsAsString()
const
66 const auto proto = ((mKey.protocol() == GpgME::OpenPGP) ? QStringLiteral(
"PGP") : QStringLiteral(
"SMIME"));
70void FilterActionEncrypt::argsFromString(
const QString &argsStr)
74 const auto protoStr = strView.left(pos);
76 QGpgME::Protocol *proto = {};
78 proto = QGpgME::openpgp();
80 proto = QGpgME::smime();
82 qCWarning(MAILCOMMON_LOG) <<
"Unknown protocol specified:" << protoStr;
87 const auto fp = argsStr.
mid(pos + 3);
88 auto listJob = proto->keyListJob(
false,
true,
true);
90 std::vector<GpgME::Key> keys;
91 auto result = listJob->exec({fp},
true, keys);
92 listJob->deleteLater();
95 qCWarning(MAILCOMMON_LOG) <<
"Failed to retrieve keys:" << result.error().asString();
100 qCWarning(MAILCOMMON_LOG) <<
"Could not obtain configured key: key expired or removed?";
116 qCWarning(MAILCOMMON_LOG) <<
"FilterActionEncrypt::process called without filter having a key!";
120 auto &item = context.
item();
122 qCWarning(MAILCOMMON_LOG) <<
"Item" << item.id() <<
"does not contain KMime::Message payload!";
127 if (KMime::isEncrypted(msg.data())) {
132 const auto encryptionKeys = getEncryptionKeysFromContent(msg, mKey.protocol());
133 qCDebug(MAILCOMMON_LOG) <<
"Item" << item.id() <<
"encrypted by following keys: " << encryptionKeys;
134 if (!encryptionKeys.isEmpty()) {
135 if (mKey.protocol() == GpgME::OpenPGP) {
136 std::vector<std::string> ids;
137 ids.reserve(encryptionKeys.size());
138 for (
const auto &key : encryptionKeys) {
139 ids.push_back(key.toStdString());
141 for (
const auto &key : mKeyCache->findByKeyIDOrFingerprint(ids)) {
142 if (qstrcmp(key.primaryFingerprint(), mKey.primaryFingerprint()) == 0) {
145 qCDebug(MAILCOMMON_LOG) <<
"Item" << item.id() <<
"already encrypted with" << mKey.primaryFingerprint() <<
", not re-encrypting";
149 }
else if (mKey.protocol() == GpgME::CMS) {
151 for (
const auto &key : mKeyCache->secretKeys()) {
152 if (qstrcmp(key.issuerSerial(), mKey.issuerSerial()) == 0) {
155 qCDebug(MAILCOMMON_LOG) <<
"Item" << item.id() <<
"already encrypted with" << mKey.primaryFingerprint() <<
", not re-encrypting";
162 const auto decrypted = CryptoUtils::decryptMessage(msg, dummy);
176 encrypt.setContent(msg.data());
177 encrypt.setCryptoMessageFormat(mKey.protocol() == GpgME::OpenPGP ? Kleo::OpenPGPMIMEFormat : Kleo::SMIMEFormat);
178 encrypt.setEncryptionKeys({mKey});
180 if (encrypt.
error()) {
181 qCWarning(MAILCOMMON_LOG) <<
"Encryption error:" << encrypt.
errorString();
188 auto nec = CryptoUtils::assembleMessage(msg, result);
199bool FilterActionEncrypt::isEmpty()
const
201 return mKey.isNull();
204QString FilterActionEncrypt::informationAboutNotValidAction()
const
206 return i18n(
"No encryption key has been selected");
209QWidget *FilterActionEncrypt::createParamWidget(
QWidget *parent)
const
215 auto combo =
new Kleo::KeySelectionCombo(w);
219 filter->setIsOpenPGP(Kleo::DefaultKeyFilter::DoesNotMatter);
220 filter->setCanEncrypt(Kleo::DefaultKeyFilter::Set);
221 filter->setHasSecret(Kleo::DefaultKeyFilter::Set);
222 combo->setKeyFilter(filter);
224 combo->setProperty(LISTING_FINISHED,
false);
225 combo->setProperty(IGNORE_KEY_CHANGE,
false);
226 connect(combo, &Kleo::KeySelectionCombo::keyListingFinished, combo, [combo] {
227 combo->setProperty(LISTING_FINISHED,
true);
228 combo->setProperty(IGNORE_KEY_CHANGE,
true);
230 connect(combo, &Kleo::KeySelectionCombo::currentKeyChanged,
this, [
this, combo]() {
233 if (!combo->property(IGNORE_KEY_CHANGE).toBool()) {
236 combo->setProperty(IGNORE_KEY_CHANGE,
false);
242 chkBox->setText(
i18n(
"Re-encrypt encrypted emails with this key"));
243 chkBox->setChecked(mReencrypt);
245 l->addWidget(chkBox);
248 auto palette = lbl->palette();
250 lbl->setPalette(palette);
251 lbl->setWordWrap(
true);
252 lbl->setText(
i18n(
"<b>Warning:</b> Seckey necessary to read emails."));
254 i18n(
"<p>Once an email has been encrypted you will need a crypto setup with "
255 "your secret key to access the contents again.</p>"
256 "<p>If you keep emails stored on an email server and use several clients, "
257 "each of them must be configured to enable decryption.</p>"));
263void FilterActionEncrypt::setParamWidgetValue(
QWidget *paramWidget)
const
265 if (
auto combo = paramWidget->
findChild<Kleo::KeySelectionCombo *>()) {
270 chkBox->setChecked(mReencrypt);
274void FilterActionEncrypt::applyParamWidgetValue(
QWidget *paramWidget)
276 if (
auto combo = paramWidget->
findChild<Kleo::KeySelectionCombo *>()) {
281 if (!combo->property(LISTING_FINISHED).toBool()) {
286 mKey = combo->currentKey();
289 mReencrypt = chkBox->isChecked();
293GpgME::Key FilterActionEncrypt::key()
const
298bool FilterActionEncrypt::reencrypt()
const
303#include "moc_filteractionencrypt.cpp"
void setPayload(const T &p)
void setFlag(const QByteArray &name)
virtual QString errorString() const
Abstract base class for mail filter actions.
ReturnCode
Describes the possible return codes of filter processing:
@ ErrorNeedComplete
Could not process because a complete message is needed.
@ ErrorButGoOn
A non-critical error occurred.
@ GoOn
Go on with applying filter actions.
void filterActionModified()
Called to notify that the current FilterAction has had some value modification.
QString label() const
Returns i18n'd label, ie.
A helper class for the filtering process.
void setNeedsPayloadStore()
Marks that the item's payload has been changed and needs to be written back.
Akonadi::Item & item()
Returns the item of the context.
void setNeedsFlagStore()
Marks that the item's flags has been changed and needs to be written back.
RequiredPart
Possible required parts.
@ CompleteMessage
Whole message.
KMime::Content * content() const
QString i18n(const char *text, const TYPE &arg...)
AKONADI_MIME_EXPORT const char Encrypted[]
int exec(ProcessEventsFlags flags)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T findChild(const QString &name, Qt::FindChildOptions options) const const
QObject * parent() const const
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
QString mid(qsizetype position, qsizetype n) const const
QString number(double n, char format, int precision)
QStringView mid(qsizetype start, qsizetype length) const const
int toInt(bool *ok, int base) const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)