7#include "job/autocryptheadersjob.h"
9#include "contentjobbase_p.h"
11#include "job/singlepartjob.h"
12#include "utils/util_p.h"
14#include <QGpgME/ExportJob>
15#include <QGpgME/Protocol>
16#include <gpgme++/context.h>
19#include <KLocalizedString>
20#include <KMime/Content>
21#include <KMime/Headers>
22#include <Libkleo/Formatting>
30class MessageComposer::AutocryptHeadersJobPrivate :
public ContentJobBasePrivate
33 AutocryptHeadersJobPrivate(AutocryptHeadersJob *qq)
34 : ContentJobBasePrivate(qq)
38 ~AutocryptHeadersJobPrivate()
override
41 for (
const auto &[key, header] : gossipHeaders) {
44 gossipHeaders.clear();
47 void emitGpgError(
const GpgME::Error &error);
50 void finishOnLastSubJob();
55 std::map<QByteArray, KMime::Headers::Generic *> gossipHeaders;
57 bool preferEncrypted =
false;
61 GpgME::Key recipientKey;
62 std::vector<GpgME::Key> gossipKeys;
64 Q_DECLARE_PUBLIC(AutocryptHeadersJob)
67void AutocryptHeadersJobPrivate::finishOnLastSubJob()
69 Q_Q(AutocryptHeadersJob);
75 for (
const auto &[key, header] : gossipHeaders) {
78 gossipHeaders.clear();
79 resultContent = content;
84void AutocryptHeadersJobPrivate::emitGpgError(
const GpgME::Error &error)
86 Q_Q(AutocryptHeadersJob);
90 "<p>An error occurred while trying to export "
91 "the key from the backend:</p>"
93 Kleo::Formatting::errorAsString(error));
94 q->setError(KJob::UserDefinedError);
99void AutocryptHeadersJobPrivate::emitNotFoundError(
const QByteArray &addr,
const QByteArray &fingerprint)
101 Q_Q(AutocryptHeadersJob);
103 "<p>An error occurred while trying to export "
104 "the key from the backend:</p>"
105 "<p><b>No valid key found for user %1 (%2)</b></p>",
108 q->setError(KJob::UserDefinedError);
109 q->setErrorText(msg);
115 QByteArray parameters =
"addr=" + addr +
"; ";
116 if (preferEncrypted) {
117 parameters +=
"prefer-encrypt=mutual; ";
119 parameters +=
"keydata=\n ";
121 const auto length = encoded.
size();
122 const auto lineLength = 76;
125 while (
start < length) {
126 const auto midLength = std::min<int>(length -
start, lineLength - column);
127 parameters += encoded.
mid(
start, midLength);
130 if (column >= lineLength) {
138AutocryptHeadersJob::AutocryptHeadersJob(
QObject *parent)
143AutocryptHeadersJob::~AutocryptHeadersJob() =
default;
147 Q_D(AutocryptHeadersJob);
151 d->content->assemble();
155void AutocryptHeadersJob::setSkeletonMessage(
KMime::Message *skeletonMessage)
157 Q_D(AutocryptHeadersJob);
159 d->skeletonMessage = skeletonMessage;
162void AutocryptHeadersJob::setGnupgHome(
const QString &path)
164 Q_D(AutocryptHeadersJob);
169void AutocryptHeadersJob::setSenderKey(
const GpgME::Key &key)
171 Q_D(AutocryptHeadersJob);
173 d->recipientKey = key;
176void AutocryptHeadersJob::setPreferEncrypted(
bool preferEncrypted)
178 Q_D(AutocryptHeadersJob);
180 d->preferEncrypted = preferEncrypted;
183void AutocryptHeadersJob::setGossipKeys(
const std::vector<GpgME::Key> &gossipKeys)
185 Q_D(AutocryptHeadersJob);
187 d->gossipKeys = gossipKeys;
190void AutocryptHeadersJob::process()
192 Q_D(AutocryptHeadersJob);
193 Q_ASSERT(d->resultContent ==
nullptr);
198 Q_ASSERT(d->subjobContents.size() == 1);
199 d->content = d->subjobContents.constFirst();
202 auto job = QGpgME::openpgp()->publicKeyExportJob(
false);
205 if (!d->gnupgHome.isEmpty()) {
206 QGpgME::Job::context(job)->setEngineHomeDirectory(d->gnupgHome.toUtf8().constData());
208 if (!d->recipientKey.isNull() && !d->recipientKey.isInvalid()) {
209 connect(job, &QGpgME::ExportJob::result,
this, [
this, d](
const GpgME::Error &
error,
const QByteArray &keydata) {
216 d->emitGpgError(
error);
220 d->emitNotFoundError(d->skeletonMessage->from()->addresses()[0], d->recipientKey.primaryFingerprint());
225 d->fillHeaderData(autocrypt, d->skeletonMessage->from()->addresses()[0], d->preferEncrypted, keydata);
227 d->skeletonMessage->setHeader(autocrypt);
228 d->skeletonMessage->assemble();
230 d->finishOnLastSubJob();
234 job->setExportFlags(GpgME::Context::ExportMinimal);
237 const auto keys = d->gossipKeys;
238 for (
const auto &key : keys) {
243 auto gossipJob = QGpgME::openpgp()->publicKeyExportJob(
false);
246 if (!d->gnupgHome.isEmpty()) {
247 QGpgME::Job::context(gossipJob)->setEngineHomeDirectory(d->gnupgHome.toUtf8().constData());
250 connect(gossipJob, &QGpgME::ExportJob::result,
this, [
this, d, key](
const GpgME::Error &
error,
const QByteArray &keydata) {
257 d->emitGpgError(
error);
261 d->emitNotFoundError(key.userID(0).email(), key.primaryFingerprint());
266 d->fillHeaderData(header, key.userID(0).email(),
false, keydata);
268 d->gossipHeaders.insert({
QByteArray(key.primaryFingerprint()), header});
270 d->finishOnLastSubJob();
275 gossipJob->setExportFlags(GpgME::Context::ExportMinimal);
277 if (d->subJobs == 0) {
278 d->resultContent = d->content;
283#include "moc_autocryptheadersjob.cpp"
void appendHeader(Headers::Base *h)
The ContentJobBase class.
KMime::Content * content() const
Get the resulting KMime::Content that the ContentJobBase has generated.
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18n(const char *text, const TYPE &arg...)
KCODECS_EXPORT QByteArray base64Encode(QByteArrayView in)
QString path(const QString &relativePath)
Simple interface that both EncryptJob and SignEncryptJob implement so the composer can extract some e...
bool isEmpty() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
QByteArray & replace(QByteArrayView before, QByteArrayView after)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString fromLatin1(QByteArrayView str)