Messagelib

encryptjob.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 <config-messagelib.h>
9 
10 #include "job/encryptjob.h"
11 
12 #include "contentjobbase_p.h"
13 #include "job/protectedheadersjob.h"
14 #include "utils/util_p.h"
15 
16 #include <QGpgME/EncryptJob>
17 #include <QGpgME/Protocol>
18 
19 #include "messagecomposer_debug.h"
20 
21 #include <gpgme++/encryptionresult.h>
22 #include <gpgme++/global.h>
23 #include <gpgme++/signingresult.h>
24 #include <sstream>
25 
26 using namespace MessageComposer;
27 
28 class MessageComposer::EncryptJobPrivate : public ContentJobBasePrivate
29 {
30 public:
31  EncryptJobPrivate(EncryptJob *qq)
32  : ContentJobBasePrivate(qq)
33  {
34  }
35 
36  QString gnupgHome;
37  QStringList recipients;
38  std::vector<GpgME::Key> keys;
39  Kleo::CryptoMessageFormat format;
40  KMime::Content *content = nullptr;
41  KMime::Message *skeletonMessage = nullptr;
42 
43  bool protectedHeaders = true;
44  bool protectedHeadersObvoscate = false;
45 
46  // copied from messagecomposer.cpp
47  bool binaryHint(Kleo::CryptoMessageFormat f)
48  {
49  switch (f) {
50  case Kleo::SMIMEFormat:
51  case Kleo::SMIMEOpaqueFormat:
52  return true;
53  default:
54  case Kleo::OpenPGPMIMEFormat:
55  case Kleo::InlineOpenPGPFormat:
56  return false;
57  }
58  }
59 
60  GpgME::SignatureMode signingMode(Kleo::CryptoMessageFormat f)
61  {
62  switch (f) {
63  case Kleo::SMIMEOpaqueFormat:
64  return GpgME::NormalSignatureMode;
65  case Kleo::InlineOpenPGPFormat:
66  return GpgME::Clearsigned;
67  default:
68  case Kleo::SMIMEFormat:
69  case Kleo::OpenPGPMIMEFormat:
70  return GpgME::Detached;
71  }
72  }
73 
74  Q_DECLARE_PUBLIC(EncryptJob)
75 };
76 
77 EncryptJob::EncryptJob(QObject *parent)
78  : ContentJobBase(*new EncryptJobPrivate(this), parent)
79 {
80 }
81 
82 EncryptJob::~EncryptJob() = default;
83 
84 void EncryptJob::setContent(KMime::Content *content)
85 {
86  Q_D(EncryptJob);
87 
88  d->content = content;
89  d->content->assemble();
90 }
91 
92 void EncryptJob::setCryptoMessageFormat(Kleo::CryptoMessageFormat format)
93 {
94  Q_D(EncryptJob);
95 
96  d->format = format;
97 }
98 
99 void EncryptJob::setEncryptionKeys(const std::vector<GpgME::Key> &keys)
100 {
101  Q_D(EncryptJob);
102 
103  d->keys = keys;
104 }
105 
106 void EncryptJob::setRecipients(const QStringList &recipients)
107 {
108  Q_D(EncryptJob);
109 
110  d->recipients = recipients;
111 }
112 
113 void EncryptJob::setSkeletonMessage(KMime::Message *skeletonMessage)
114 {
115  Q_D(EncryptJob);
116 
117  d->skeletonMessage = skeletonMessage;
118 }
119 
120 void EncryptJob::setProtectedHeaders(bool protectedHeaders)
121 {
122  Q_D(EncryptJob);
123 
124  d->protectedHeaders = protectedHeaders;
125 }
126 
127 void EncryptJob::setProtectedHeadersObvoscate(bool protectedHeadersObvoscate)
128 {
129  Q_D(EncryptJob);
130 
131  d->protectedHeadersObvoscate = protectedHeadersObvoscate;
132 }
133 
134 void EncryptJob::setGnupgHome(const QString &path)
135 {
136  Q_D(EncryptJob);
137 
138  d->gnupgHome = path;
139 }
140 
141 QStringList EncryptJob::recipients() const
142 {
143  Q_D(const EncryptJob);
144 
145  return d->recipients;
146 }
147 
148 std::vector<GpgME::Key> EncryptJob::encryptionKeys() const
149 {
150  Q_D(const EncryptJob);
151 
152  return d->keys;
153 }
154 
155 void EncryptJob::doStart()
156 {
157  Q_D(EncryptJob);
158  Q_ASSERT(d->resultContent == nullptr); // Not processed before.
159 
160  if (d->keys.size() == 0) { // should not happen---resolver should have dealt with it earlier
161  qCDebug(MESSAGECOMPOSER_LOG) << "HELP! Encrypt job but have no keys to encrypt with.";
162  return;
163  }
164 
165  // if setContent hasn't been called, we assume that a subjob was added
166  // and we want to use that
167  if (!d->content || !d->content->hasContent()) {
168  if (d->subjobContents.size() == 1) {
169  d->content = d->subjobContents.constFirst();
170  }
171  }
172 
173  if (d->protectedHeaders && d->skeletonMessage && d->format & Kleo::OpenPGPMIMEFormat) {
174  auto pJob = new ProtectedHeadersJob;
175  pJob->setContent(d->content);
176  pJob->setSkeletonMessage(d->skeletonMessage);
177  pJob->setObvoscate(d->protectedHeadersObvoscate);
178  QObject::connect(pJob, &ProtectedHeadersJob::finished, this, [d, pJob](KJob *job) {
179  if (job->error()) {
180  return;
181  }
182  d->content = pJob->content();
183  });
184  appendSubjob(pJob);
185  }
186 
188 }
189 
190 void EncryptJob::slotResult(KJob *job)
191 {
192  // Q_D(EncryptJob);
193  if (error() || job->error()) {
194  ContentJobBase::slotResult(job);
195  return;
196  }
197  if (subjobs().size() == 2) {
198  auto pjob = static_cast<ProtectedHeadersJob *>(subjobs().last());
199  if (pjob) {
200  auto cjob = qobject_cast<ContentJobBase *>(job);
201  Q_ASSERT(cjob);
202  pjob->setContent(cjob->content());
203  }
204  }
205 
206  ContentJobBase::slotResult(job);
207 }
208 
209 void EncryptJob::process()
210 {
211  Q_D(EncryptJob);
212 
213  // if setContent hasn't been called, we assume that a subjob was added
214  // and we want to use that
215  if (!d->content || !d->content->hasContent()) {
216  Q_ASSERT(d->subjobContents.size() == 1);
217  d->content = d->subjobContents.constFirst();
218  }
219 
220  const QGpgME::Protocol *proto = nullptr;
221  if (d->format & Kleo::AnyOpenPGP) {
222  proto = QGpgME::openpgp();
223  } else if (d->format & Kleo::AnySMIME) {
224  proto = QGpgME::smime();
225  } else {
226  qCDebug(MESSAGECOMPOSER_LOG) << "HELP! Encrypt job but have protocol to encrypt with.";
227  return;
228  }
229 
230  Q_ASSERT(proto);
231 
232  // for now just do the main recipients
234  d->content->assemble();
235  if (d->format & Kleo::InlineOpenPGPFormat) {
236  content = d->content->body();
237  } else {
239  }
240 
241  qCDebug(MESSAGECOMPOSER_LOG) << "got backend, starting job";
242  QGpgME::EncryptJob *eJob = proto->encryptJob(!d->binaryHint(d->format), d->format == Kleo::InlineOpenPGPFormat);
243 #if QGPGME_SUPPORTS_ENCRYPTION_JOB_SET_INPUT_ENCODING
244  if (!(d->format & Kleo::InlineOpenPGPFormat)) {
245  eJob->setInputEncoding(GpgME::Data::MimeEncoding);
246  }
247 #endif
248 
249  if (!d->gnupgHome.isEmpty()) {
250  QGpgME::Job::context(eJob)->setEngineHomeDirectory(d->gnupgHome.toUtf8().constData());
251  }
252 
254  eJob,
255  &QGpgME::EncryptJob::result,
256  this,
257  [this, d](const GpgME::EncryptionResult &result, const QByteArray &cipherText, const QString &auditLogAsHtml, const GpgME::Error &auditLogError) {
258  Q_UNUSED(auditLogAsHtml)
259  Q_UNUSED(auditLogError)
260  if (result.error()) {
261  setError(result.error().code());
262  setErrorText(QString::fromLocal8Bit(result.error().asString()));
263  emitResult();
264  return;
265  }
266  d->resultContent = MessageComposer::Util::composeHeadersAndBody(d->content, cipherText, d->format, false);
267 
268  emitResult();
269  });
270 
271  const auto error = eJob->start(d->keys, content, true);
272  if (error.code()) {
273  eJob->deleteLater();
274  setError(error.code());
276  emitResult();
277  }
278 }
279 
280 #include "moc_encryptjob.cpp"
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.
QString path(const QString &relativePath)
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-2024 The KDE developers.
Generated on Thu Feb 15 2024 03:55:20 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.