Messagelib

encryptjob.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, [email protected]
3  SPDX-FileCopyrightText: 2009 Leo Franchi <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "job/encryptjob.h"
9 
10 #include "contentjobbase_p.h"
11 #include "job/protectedheadersjob.h"
12 #include "utils/util_p.h"
13 
14 #include <QGpgME/EncryptJob>
15 #include <QGpgME/Protocol>
16 
17 #include "messagecomposer_debug.h"
18 
19 #include <gpgme++/encryptionresult.h>
20 #include <gpgme++/global.h>
21 #include <gpgme++/signingresult.h>
22 #include <sstream>
23 
24 using namespace MessageComposer;
25 
26 class MessageComposer::EncryptJobPrivate : public ContentJobBasePrivate
27 {
28 public:
29  EncryptJobPrivate(EncryptJob *qq)
30  : ContentJobBasePrivate(qq)
31  {
32  }
33 
34  QString gnupgHome;
35  QStringList recipients;
36  std::vector<GpgME::Key> keys;
37  Kleo::CryptoMessageFormat format;
38  KMime::Content *content = nullptr;
39  KMime::Message *skeletonMessage = nullptr;
40 
41  bool protectedHeaders = true;
42  bool protectedHeadersObvoscate = false;
43 
44  // copied from messagecomposer.cpp
45  bool binaryHint(Kleo::CryptoMessageFormat f)
46  {
47  switch (f) {
48  case Kleo::SMIMEFormat:
49  case Kleo::SMIMEOpaqueFormat:
50  return true;
51  default:
52  case Kleo::OpenPGPMIMEFormat:
53  case Kleo::InlineOpenPGPFormat:
54  return false;
55  }
56  }
57 
58  GpgME::SignatureMode signingMode(Kleo::CryptoMessageFormat f)
59  {
60  switch (f) {
61  case Kleo::SMIMEOpaqueFormat:
62  return GpgME::NormalSignatureMode;
63  case Kleo::InlineOpenPGPFormat:
64  return GpgME::Clearsigned;
65  default:
66  case Kleo::SMIMEFormat:
67  case Kleo::OpenPGPMIMEFormat:
68  return GpgME::Detached;
69  }
70  }
71 
72  Q_DECLARE_PUBLIC(EncryptJob)
73 };
74 
75 EncryptJob::EncryptJob(QObject *parent)
76  : ContentJobBase(*new EncryptJobPrivate(this), parent)
77 {
78 }
79 
80 EncryptJob::~EncryptJob() = default;
81 
82 void EncryptJob::setContent(KMime::Content *content)
83 {
84  Q_D(EncryptJob);
85 
86  d->content = content;
87  d->content->assemble();
88 }
89 
90 void EncryptJob::setCryptoMessageFormat(Kleo::CryptoMessageFormat format)
91 {
92  Q_D(EncryptJob);
93 
94  d->format = format;
95 }
96 
97 void EncryptJob::setEncryptionKeys(const std::vector<GpgME::Key> &keys)
98 {
99  Q_D(EncryptJob);
100 
101  d->keys = keys;
102 }
103 
104 void EncryptJob::setRecipients(const QStringList &recipients)
105 {
106  Q_D(EncryptJob);
107 
108  d->recipients = recipients;
109 }
110 
111 void EncryptJob::setSkeletonMessage(KMime::Message *skeletonMessage)
112 {
113  Q_D(EncryptJob);
114 
115  d->skeletonMessage = skeletonMessage;
116 }
117 
118 void EncryptJob::setProtectedHeaders(bool protectedHeaders)
119 {
120  Q_D(EncryptJob);
121 
122  d->protectedHeaders = protectedHeaders;
123 }
124 
125 void EncryptJob::setProtectedHeadersObvoscate(bool protectedHeadersObvoscate)
126 {
127  Q_D(EncryptJob);
128 
129  d->protectedHeadersObvoscate = protectedHeadersObvoscate;
130 }
131 
132 void EncryptJob::setGnupgHome(const QString &path)
133 {
134  Q_D(EncryptJob);
135 
136  d->gnupgHome = path;
137 }
138 
139 QStringList EncryptJob::recipients() const
140 {
141  Q_D(const EncryptJob);
142 
143  return d->recipients;
144 }
145 
146 std::vector<GpgME::Key> EncryptJob::encryptionKeys() const
147 {
148  Q_D(const EncryptJob);
149 
150  return d->keys;
151 }
152 
153 void EncryptJob::doStart()
154 {
155  Q_D(EncryptJob);
156  Q_ASSERT(d->resultContent == nullptr); // Not processed before.
157 
158  if (d->keys.size() == 0) { // should not happen---resolver should have dealt with it earlier
159  qCDebug(MESSAGECOMPOSER_LOG) << "HELP! Encrypt job but have no keys to encrypt with.";
160  return;
161  }
162 
163  // if setContent hasn't been called, we assume that a subjob was added
164  // and we want to use that
165  if (!d->content || !d->content->hasContent()) {
166  if (d->subjobContents.size() == 1) {
167  d->content = d->subjobContents.constFirst();
168  }
169  }
170 
171  if (d->protectedHeaders && d->skeletonMessage && d->format & Kleo::OpenPGPMIMEFormat) {
172  auto pJob = new ProtectedHeadersJob;
173  pJob->setContent(d->content);
174  pJob->setSkeletonMessage(d->skeletonMessage);
175  pJob->setObvoscate(d->protectedHeadersObvoscate);
176  QObject::connect(pJob, &ProtectedHeadersJob::finished, this, [d, pJob](KJob *job) {
177  if (job->error()) {
178  return;
179  }
180  d->content = pJob->content();
181  });
182  appendSubjob(pJob);
183  }
184 
186 }
187 
188 void EncryptJob::slotResult(KJob *job)
189 {
190  // Q_D(EncryptJob);
191  if (error() || job->error()) {
192  ContentJobBase::slotResult(job);
193  return;
194  }
195  if (subjobs().size() == 2) {
196  auto pjob = static_cast<ProtectedHeadersJob *>(subjobs().last());
197  if (pjob) {
198  auto cjob = qobject_cast<ContentJobBase *>(job);
199  Q_ASSERT(cjob);
200  pjob->setContent(cjob->content());
201  }
202  }
203 
204  ContentJobBase::slotResult(job);
205 }
206 
207 void EncryptJob::process()
208 {
209  Q_D(EncryptJob);
210 
211  // if setContent hasn't been called, we assume that a subjob was added
212  // and we want to use that
213  if (!d->content || !d->content->hasContent()) {
214  Q_ASSERT(d->subjobContents.size() == 1);
215  d->content = d->subjobContents.constFirst();
216  }
217 
218  const QGpgME::Protocol *proto = nullptr;
219  if (d->format & Kleo::AnyOpenPGP) {
220  proto = QGpgME::openpgp();
221  } else if (d->format & Kleo::AnySMIME) {
222  proto = QGpgME::smime();
223  } else {
224  qCDebug(MESSAGECOMPOSER_LOG) << "HELP! Encrypt job but have protocol to encrypt with.";
225  return;
226  }
227 
228  Q_ASSERT(proto);
229 
230  // for now just do the main recipients
232  d->content->assemble();
233  if (d->format & Kleo::InlineOpenPGPFormat) {
234  content = d->content->body();
235  } else {
237  }
238 
239  qCDebug(MESSAGECOMPOSER_LOG) << "got backend, starting job";
240  QGpgME::EncryptJob *eJob = proto->encryptJob(!d->binaryHint(d->format), d->format == Kleo::InlineOpenPGPFormat);
241 
242  if (!d->gnupgHome.isEmpty()) {
243  QGpgME::Job::context(eJob)->setEngineHomeDirectory(d->gnupgHome.toUtf8().constData());
244  }
245 
247  eJob,
248  &QGpgME::EncryptJob::result,
249  this,
250  [this, d](const GpgME::EncryptionResult &result, const QByteArray &cipherText, const QString &auditLogAsHtml, const GpgME::Error &auditLogError) {
251  Q_UNUSED(auditLogAsHtml)
252  Q_UNUSED(auditLogError)
253  if (result.error()) {
254  setError(result.error().code());
255  setErrorText(QString::fromLocal8Bit(result.error().asString()));
256  emitResult();
257  return;
258  }
259  d->resultContent = MessageComposer::Util::composeHeadersAndBody(d->content, cipherText, d->format, false);
260 
261  emitResult();
262  });
263 
264  const auto error = eJob->start(d->keys, content, true);
265  if (error.code()) {
266  eJob->deleteLater();
267  setError(error.code());
269  emitResult();
270  }
271 }
Content * content(const ContentIndex &index) const
QByteArray body() const
Simple interface that both EncryptJob and SignEncryptJob implement so the composer can extract some e...
void finished(KJob *job)
void setErrorText(const QString &errorText)
void result(KJob *job)
bool appendSubjob(ContentJobBase *job)
This is meant to be used instead of KCompositeJob::addSubjob(), making it possible to add subjobs fro...
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
const QList< KJob * > & subjobs() const
Encrypt the contents of a message .
Definition: encryptjob.h:33
QString fromLocal8Bit(const char *str, int size)
QByteArray encodedContent(bool useCrLf=false)
KMime::Content * content() const
Get the resulting KMime::Content that the ContentJobBase has generated.
virtual void doStart()
Reimplement to do additional stuff before processing children, such as adding more subjobs.
The ContentJobBase class.
void emitResult()
int error() const
void setError(int errorCode)
Copies headers from skeleton message to content.
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Tue May 17 2022 04:00:04 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.