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
231  QByteArray content;
232  d->content->assemble();
233  if (d->format & Kleo::InlineOpenPGPFormat) {
234  content = d->content->body();
235  } else {
236  content = d->content->encodedContent();
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());
268  setErrorText(QString::fromLocal8Bit(error.asString()));
269  emitResult();
270  }
271 }
void emitResult()
void setError(int errorCode)
virtual void doStart()
Reimplement to do additional stuff before processing children, such as adding more subjobs...
void setErrorText(const QString &errorText)
QString fromLocal8Bit(const char *str, int size)
void finished(KJob *job)
Copies headers from skeleton message to content.
Encrypt the contents of a message .
Definition: encryptjob.h:33
Simple interface that both EncryptJob and SignEncryptJob implement so the composer can extract some e...
void result(KJob *job)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
T qobject_cast(QObject *object)
int error() const
The ContentJobBase class.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Dec 6 2021 23:04:57 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.