Messagelib

signencryptjob.cpp
1/*
2 SPDX-FileCopyrightText: 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
3 SPDX-FileCopyrightText: 2009 Leo Franchi <lfranchi@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "job/signencryptjob.h"
9
10#include "contentjobbase_p.h"
11#include "job/protectedheadersjob.h"
12#include "utils/util_p.h"
13
14#include <QGpgME/Protocol>
15#include <QGpgME/SignEncryptJob>
16
17#include "messagecomposer_debug.h"
18#include <KMime/Content>
19#include <KMime/Headers>
20#include <KMime/Message>
21#include <Libkleo/Formatting>
22
23#include <gpgme++/encryptionresult.h>
24#include <gpgme++/global.h>
25#include <gpgme++/signingresult.h>
26
27using namespace MessageComposer;
28
29class MessageComposer::SignEncryptJobPrivate : public ContentJobBasePrivate
30{
31public:
32 SignEncryptJobPrivate(SignEncryptJob *qq)
33 : ContentJobBasePrivate(qq)
34 {
35 }
36
37 std::vector<GpgME::Key> signers;
38
39 std::vector<GpgME::Key> encKeys;
40 QStringList recipients;
41 Kleo::CryptoMessageFormat format;
42 KMime::Content *content = nullptr;
43 KMime::Message *skeletonMessage = nullptr;
44
45 bool protectedHeaders = true;
46 bool protectedHeadersObvoscate = false;
47
48 // copied from messagecomposer.cpp
49 [[nodiscard]] bool binaryHint(Kleo::CryptoMessageFormat f)
50 {
51 switch (f) {
52 case Kleo::SMIMEFormat:
53 case Kleo::SMIMEOpaqueFormat:
54 return true;
55 default:
56 case Kleo::OpenPGPMIMEFormat:
57 case Kleo::InlineOpenPGPFormat:
58 return false;
59 }
60 }
61
62 Q_DECLARE_PUBLIC(SignEncryptJob)
63};
64
65SignEncryptJob::SignEncryptJob(QObject *parent)
66 : ContentJobBase(*new SignEncryptJobPrivate(this), parent)
67{
68}
69
70SignEncryptJob::~SignEncryptJob() = default;
71
72void SignEncryptJob::setContent(KMime::Content *content)
73{
75
76 Q_ASSERT(content);
77
78 d->content = content;
79}
80
81void SignEncryptJob::setCryptoMessageFormat(Kleo::CryptoMessageFormat format)
82{
84
85 // There *must* be a concrete format set at this point.
86 Q_ASSERT(format == Kleo::OpenPGPMIMEFormat || format == Kleo::InlineOpenPGPFormat || format == Kleo::SMIMEFormat || format == Kleo::SMIMEOpaqueFormat);
87 d->format = format;
88}
89
90void SignEncryptJob::setSigningKeys(const std::vector<GpgME::Key> &signers)
91{
93
94 d->signers = signers;
95}
96
97KMime::Content *SignEncryptJob::origContent()
98{
100
101 return d->content;
102}
103
104void SignEncryptJob::setEncryptionKeys(const std::vector<GpgME::Key> &keys)
105{
107
108 d->encKeys = keys;
109}
110
111void SignEncryptJob::setRecipients(const QStringList &recipients)
112{
114
115 d->recipients = recipients;
116}
117
118void SignEncryptJob::setSkeletonMessage(KMime::Message *skeletonMessage)
119{
121
122 d->skeletonMessage = skeletonMessage;
123}
124
125void SignEncryptJob::setProtectedHeaders(bool protectedHeaders)
126{
128
129 d->protectedHeaders = protectedHeaders;
130}
131
132void SignEncryptJob::setProtectedHeadersObvoscate(bool protectedHeadersObvoscate)
133{
135
136 d->protectedHeadersObvoscate = protectedHeadersObvoscate;
137}
138
139QStringList SignEncryptJob::recipients() const
140{
141 Q_D(const SignEncryptJob);
142
143 return d->recipients;
144}
145
146std::vector<GpgME::Key> SignEncryptJob::encryptionKeys() const
147{
148 Q_D(const SignEncryptJob);
149
150 return d->encKeys;
151}
152
153void SignEncryptJob::doStart()
154{
156 Q_ASSERT(d->resultContent == nullptr); // Not processed before.
157
158 if (d->protectedHeaders && d->skeletonMessage && d->format & Kleo::OpenPGPMIMEFormat) {
159 auto pJob = new ProtectedHeadersJob;
160 pJob->setContent(d->content);
161 pJob->setSkeletonMessage(d->skeletonMessage);
162 pJob->setObvoscate(d->protectedHeadersObvoscate);
163 QObject::connect(pJob, &ProtectedHeadersJob::finished, this, [d, pJob](KJob *job) {
164 if (job->error()) {
165 return;
166 }
167 d->content = pJob->content();
168 });
169 appendSubjob(pJob);
170 }
171
173}
174
175void SignEncryptJob::slotResult(KJob *job)
176{
177 // Q_D(SignEncryptJob);
178 if (error() || job->error()) {
179 ContentJobBase::slotResult(job);
180 return;
181 }
182 if (subjobs().size() == 2) {
183 auto pjob = static_cast<ProtectedHeadersJob *>(subjobs().last());
184 if (pjob) {
185 auto cjob = qobject_cast<ContentJobBase *>(job);
186 Q_ASSERT(cjob);
187 pjob->setContent(cjob->content());
188 }
189 }
190
191 ContentJobBase::slotResult(job);
192}
193
194void SignEncryptJob::process()
195{
197 Q_ASSERT(d->resultContent == nullptr); // Not processed before.
198
199 // if setContent hasn't been called, we assume that a subjob was added
200 // and we want to use that
201 if (!d->content || !d->content->hasContent()) {
202 Q_ASSERT(d->subjobContents.size() == 1);
203 d->content = d->subjobContents.constFirst();
204 }
205
206 const QGpgME::Protocol *proto = nullptr;
207 if (d->format & Kleo::AnyOpenPGP) {
208 proto = QGpgME::openpgp();
209 } else if (d->format & Kleo::AnySMIME) {
210 proto = QGpgME::smime();
211 } else {
212 return;
213 }
214 Q_ASSERT(proto);
215 // d->resultContent = new KMime::Content;
216
217 qCDebug(MESSAGECOMPOSER_LOG) << "creating signencrypt from:" << proto->name() << proto->displayName();
218
219 QByteArray encBody;
220 d->content->assemble();
221
222 // replace simple LFs by CRLFs for all MIME supporting CryptPlugs
223 // according to RfC 2633, 3.1.1 Canonicalization
225 if (d->format & Kleo::InlineOpenPGPFormat) {
226 content = d->content->body();
227 } else if (!(d->format & Kleo::SMIMEOpaqueFormat)) {
228 content = KMime::LFtoCRLF(d->content->encodedContent());
229 } else { // SMimeOpaque doesn't need LFtoCRLF, else it gets munged
231 }
232
233 QGpgME::SignEncryptJob *job(proto->signEncryptJob(!d->binaryHint(d->format), d->format == Kleo::InlineOpenPGPFormat));
235 &QGpgME::SignEncryptJob::result,
236 this,
237 [this, d](const GpgME::SigningResult &signingResult,
238 const GpgME::EncryptionResult &encryptionResult,
239 const QByteArray &cipherText,
240 const QString &auditLogAsHtml,
241 const GpgME::Error &auditLogError) {
242 Q_UNUSED(auditLogAsHtml)
243 Q_UNUSED(auditLogError)
244 if (signingResult.error()) {
245 qCDebug(MESSAGECOMPOSER_LOG) << "signing failed:" << Kleo::Formatting::errorAsString(signingResult.error());
246 setError(signingResult.error().code());
247 setErrorText(Kleo::Formatting::errorAsString(signingResult.error()));
248 emitResult();
249 return;
250 }
251 if (encryptionResult.error()) {
252 qCDebug(MESSAGECOMPOSER_LOG) << "encrypting failed:" << Kleo::Formatting::errorAsString(encryptionResult.error());
253 setError(encryptionResult.error().code());
254 setErrorText(Kleo::Formatting::errorAsString(encryptionResult.error()));
255 emitResult();
256 return;
257 }
258
259 QByteArray signatureHashAlgo = signingResult.createdSignature(0).hashAlgorithmAsString();
260 d->resultContent = MessageComposer::Util::composeHeadersAndBody(d->content, cipherText, d->format, false, signatureHashAlgo);
261
262 emitResult();
263 });
264
265 const auto error = job->start(d->signers, d->encKeys, content, false);
266 if (error.code()) {
267 job->deleteLater();
268 setError(error.code());
269 setErrorText(Kleo::Formatting::errorAsString(error));
270 emitResult();
271 }
272}
273
274#include "moc_signencryptjob.cpp"
const QList< KJob * > & subjobs() const
void setErrorText(const QString &errorText)
void emitResult()
int error() const
void finished(KJob *job)
void setError(int errorCode)
virtual Q_SCRIPTABLE void start()=0
Content * content(const ContentIndex &index) const
QByteArray body() const
QByteArray encodedContent(bool useCrLf=false) const
The ContentJobBase class.
virtual void doStart()
Reimplement to do additional stuff before processing children, such as adding more subjobs.
bool appendSubjob(ContentJobBase *job)
This is meant to be used instead of KCompositeJob::addSubjob(), making it possible to add subjobs fro...
KMime::Content * content() const
Get the resulting KMime::Content that the ContentJobBase has generated.
Copies headers from skeleton message to content.
Signs and encrypt the contents of a message.
Simple interface that both EncryptJob and SignEncryptJob implement so the composer can extract some e...
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
T qobject_cast(QObject *object)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:07:24 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.