11#include "imagescaling/imagescaling.h"
12#include "imagescaling/imagescalingutils.h"
13#include "job/attachmentjob.h"
14#include "job/autocryptheadersjob.h"
15#include "job/encryptjob.h"
16#include "job/itipjob.h"
17#include "job/jobbase_p.h"
18#include "job/maintextjob.h"
19#include "job/multipartjob.h"
20#include "job/signencryptjob.h"
21#include "job/signjob.h"
22#include "job/skeletonmessagejob.h"
23#include "job/transparentjob.h"
24#include "part/globalpart.h"
25#include "part/infopart.h"
26#include "part/itippart.h"
27#include "part/textpart.h"
29#include "messagecomposer_debug.h"
30#include <KLocalizedString>
35class MessageComposer::ComposerPrivate :
public JobBasePrivate
38 explicit ComposerPrivate(
Composer *qq)
43 ~ComposerPrivate()
override
45 delete skeletonMessage;
53 void contentJobFinished(
KJob *job);
56 const AttachmentPart::List &parts,
57 const std::vector<GpgME::Key> &keys,
59 void attachmentsFinished(
KJob *job);
65 GpgME::Key senderEncryptionKey;
66 std::vector<GpgME::Key> signers;
67 AttachmentPart::List attachmentParts;
70 AttachmentPart::List lateAttachmentParts;
73 Kleo::CryptoMessageFormat format;
85 bool finished =
false;
88 bool noCrypto =
false;
89 bool autoSaving =
false;
90 bool autocryptEnabled =
false;
94void ComposerPrivate::init()
106void ComposerPrivate::doStart()
113void ComposerPrivate::composeStep1()
125 Q_ASSERT(skeletonMessage ==
nullptr);
126 skeletonMessage = skeletonJob->message();
127 Q_ASSERT(skeletonMessage);
132 q->addSubjob(skeletonJob);
133 skeletonJob->start();
136void ComposerPrivate::composeStep2()
142 Q_ASSERT(textPart || itipPart);
143 if (textPart && !itipPart) {
145 }
else if (!textPart && itipPart) {
146 mainContentJob =
new ItipJob(itipPart, q);
149 Q_ASSERT(!textPart || !itipPart);
152 if ((sign || encrypt) && format & Kleo::InlineOpenPGPFormat) {
153 qCDebug(MESSAGECOMPOSER_LOG) <<
"sending to sign/enc inline job!";
160 if (attachmentParts.isEmpty()) {
165 multipartJob->setMultipartSubtype(
"mixed");
166 multipartJob->appendSubjob(subJob);
167 for (
const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) {
170 mainJob = multipartJob;
174 q->addSubjob(mainJob);
178 subJob->setSigningKeys(signers);
179 subJob->setCryptoMessageFormat(format);
180 subJob->appendSubjob(mainContentJob);
182 if (attachmentParts.isEmpty()) {
187 multipartJob->setMultipartSubtype(
"mixed");
188 multipartJob->appendSubjob(subJob);
189 for (
const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) {
192 mainJob = multipartJob;
195 q->addSubjob(mainJob);
201 qCDebug(MESSAGECOMPOSER_LOG) <<
"main job is null";
206 if (attachmentParts.isEmpty()) {
208 mainJob = mainContentJob;
212 while (iter.hasNext()) {
213 AttachmentPart::Ptr part = iter.next();
214 qCDebug(MESSAGECOMPOSER_LOG) <<
"Checking attachment crypto policy... signed: " << part->isSigned() <<
" isEncrypted : " << part->isEncrypted();
215 if (!noCrypto && !autoSaving && (sign != part->isSigned() || encrypt != part->isEncrypted())) {
216 qCDebug(MESSAGECOMPOSER_LOG) <<
"got attachment with different crypto policy!";
217 lateAttachmentParts.append(part);
222 multipartJob->setMultipartSubtype(
"mixed");
223 multipartJob->appendSubjob(mainContentJob);
224 for (
const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) {
227 mainJob = multipartJob;
230 if (autocryptEnabled) {
231 auto autocryptJob =
new AutocryptHeadersJob();
232 autocryptJob->setSkeletonMessage(skeletonMessage);
233 autocryptJob->setGnupgHome(gnupgHome);
234 autocryptJob->appendSubjob(mainJob);
235 autocryptJob->setSenderKey(senderEncryptionKey);
236 if (encrypt && format & Kleo::OpenPGPMIMEFormat) {
237 qDebug() <<
"Add gossip: " << encData[0].
first.size() << encData[0].second.
size();
238 if (encData[0].first.size() > 1 && encData[0].second.size() > 2) {
239 autocryptJob->setGossipKeys(encData[0].second);
242 mainJob = autocryptJob;
247 sJob->setCryptoMessageFormat(format);
248 sJob->setSigningKeys(signers);
249 sJob->appendSubjob(mainJob);
250 sJob->setSkeletonMessage(skeletonMessage);
255 const auto lstJob = createEncryptJobs(mainJob,
false);
260 eJob->setProtectedHeaders(
false);
268 q->addSubjob(mainJob);
283 qCDebug(MESSAGECOMPOSER_LOG) <<
"starting enc jobs";
284 qCDebug(MESSAGECOMPOSER_LOG) <<
"format:" << format;
285 qCDebug(MESSAGECOMPOSER_LOG) <<
"enc data:" << encData.
size();
288 q->setErrorText(
i18n(
"No key data for recipients found."));
289 q->setError(Composer::IncompleteError);
294 const int encDataSize = encData.
size();
296 for (
int i = 0; i < encDataSize; ++i) {
297 QPair<QStringList, std::vector<GpgME::Key>> recipients = encData[i];
298 qCDebug(MESSAGECOMPOSER_LOG) <<
"got first list of recipients:" << recipients.
first;
303 seJob->setCryptoMessageFormat(format);
304 seJob->setSigningKeys(signers);
305 seJob->setEncryptionKeys(recipients.second);
306 seJob->setRecipients(recipients.first);
307 seJob->setSkeletonMessage(skeletonMessage);
312 eJob->setCryptoMessageFormat(format);
313 eJob->setEncryptionKeys(recipients.second);
314 eJob->setRecipients(recipients.first);
315 eJob->setSkeletonMessage(skeletonMessage);
316 eJob->setGnupgHome(gnupgHome);
319 qCDebug(MESSAGECOMPOSER_LOG) <<
"subJob" << subJob;
323 qCDebug(MESSAGECOMPOSER_LOG) << jobs.
size();
327void ComposerPrivate::contentJobFinished(
KJob *job)
332 qCDebug(MESSAGECOMPOSER_LOG) <<
"composing final message";
336 std::vector<GpgME::Key> keys;
344 if (encData.
size() > 1) {
345 Q_ASSERT(
dynamic_cast<MessageComposer::AbstractEncryptJob *
>(job));
346 auto eJob =
dynamic_cast<MessageComposer::AbstractEncryptJob *
>(job);
348 keys = eJob->encryptionKeys();
349 recipients = eJob->recipients();
351 resultContent = contentJob->
content();
361 realTo->fromUnicodeString(eJob->recipients().join(
QLatin1Char(
'%')));
363 qCDebug(MESSAGECOMPOSER_LOG) <<
"got one of multiple messages sending to:" << realTo->asUnicodeString();
364 qCDebug(MESSAGECOMPOSER_LOG) <<
"sending to recipients:" << recipients;
369 const auto firstElement = encData.
at(0);
370 qCDebug(MESSAGECOMPOSER_LOG) <<
"setting enc data:" << firstElement.first <<
"with num keys:" << firstElement.second.size();
371 keys = firstElement.second;
372 recipients = firstElement.
first;
375 headers = skeletonMessage;
376 resultContent = contentJob->
content();
379 if (lateAttachmentParts.isEmpty()) {
380 composeFinalStep(headers, resultContent);
382 composeWithLateAttachments(headers, resultContent, lateAttachmentParts, keys, recipients);
386void ComposerPrivate::composeWithLateAttachments(
KMime::Message *headers,
388 const AttachmentPart::List &parts,
389 const std::vector<GpgME::Key> &keys,
395 multiJob->setMultipartSubtype(
"mixed");
399 tJob->setContent(content);
400 multiJob->appendSubjob(tJob);
401 multiJob->setExtraContent(headers);
403 qCDebug(MESSAGECOMPOSER_LOG) <<
"attachment encr key size:" << keys.size() <<
" recipients: " << recipients;
406 for (
const AttachmentPart::Ptr &attachment : std::as_const(parts)) {
409 qCDebug(MESSAGECOMPOSER_LOG) <<
"got a late attachment";
410 if (attachment->isSigned() && format) {
411 qCDebug(MESSAGECOMPOSER_LOG) <<
"adding signjob for late attachment";
413 sJob->setContent(
nullptr);
414 sJob->setCryptoMessageFormat(format);
415 sJob->setSigningKeys(signers);
417 sJob->appendSubjob(attachJob);
418 if (attachment->isEncrypted()) {
419 qCDebug(MESSAGECOMPOSER_LOG) <<
"adding sign + encrypt job for late attachment";
421 eJob->setCryptoMessageFormat(format);
422 eJob->setEncryptionKeys(keys);
423 eJob->setRecipients(recipients);
425 eJob->appendSubjob(sJob);
427 multiJob->appendSubjob(eJob);
429 qCDebug(MESSAGECOMPOSER_LOG) <<
"Just signing late attachment";
430 multiJob->appendSubjob(sJob);
432 }
else if (attachment->isEncrypted() && format) {
433 qCDebug(MESSAGECOMPOSER_LOG) <<
"just encrypting late attachment";
435 eJob->setCryptoMessageFormat(format);
436 eJob->setEncryptionKeys(keys);
437 eJob->setRecipients(recipients);
439 eJob->appendSubjob(attachJob);
440 multiJob->appendSubjob(eJob);
442 qCDebug(MESSAGECOMPOSER_LOG) <<
"attaching plain non-crypto attachment";
444 multiJob->appendSubjob(attachSecondJob);
450 q->addSubjob(multiJob);
454void ComposerPrivate::attachmentsFinished(
KJob *job)
459 qCDebug(MESSAGECOMPOSER_LOG) <<
"composing final message with late attachments";
467 composeFinalStep(headers, content);
479 resultMessage->setContent(allData);
480 resultMessage->parse();
481 resultMessages.append(resultMessage);
484Composer::Composer(
QObject *parent)
485 :
JobBase(*new ComposerPrivate(this), parent)
491Composer::~Composer() =
default;
496 Q_ASSERT(d->finished);
498 return d->resultMessages;
504 return d->globalPart;
517 auto *self =
const_cast<Composer *
>(
this);
518 self->d_func()->textPart =
new TextPart(self);
523void Composer::clearTextPart()
527 d->textPart =
nullptr;
534 auto *self =
const_cast<Composer *
>(
this);
535 self->d_func()->itipPart =
new ItipPart(self);
540void Composer::clearItipPart()
544 d->itipPart =
nullptr;
547AttachmentPart::List Composer::attachmentParts()
const
550 return d->attachmentParts;
553void Composer::addAttachmentPart(AttachmentPart::Ptr part,
bool autoresizeImage)
556 Q_ASSERT(!d->started);
557 Q_ASSERT(!d->attachmentParts.contains(part));
558 if (autoresizeImage) {
559 MessageComposer::Utils resizeUtils;
560 if (resizeUtils.resizeImage(part)) {
562 autoResizeJob.setName(part->name());
563 autoResizeJob.setMimetype(part->mimeType());
567 part->setMimeType(autoResizeJob.
mimetype());
568 part->setName(autoResizeJob.generateNewName());
569 resizeUtils.changeFileName(part);
574 d->attachmentParts.append(part);
577void Composer::addAttachmentParts(
const AttachmentPart::List &parts,
bool autoresizeImage)
579 for (
const AttachmentPart::Ptr &part : parts) {
580 addAttachmentPart(part, autoresizeImage);
584void Composer::removeAttachmentPart(AttachmentPart::Ptr part)
587 Q_ASSERT(!d->started);
588 const int numberOfElements = d->attachmentParts.removeAll(part);
589 if (numberOfElements <= 0) {
590 qCCritical(MESSAGECOMPOSER_LOG) <<
"Unknown attachment part" << part.data();
596void Composer::setSignAndEncrypt(
const bool doSign,
const bool doEncrypt)
600 d->encrypt = doEncrypt;
603void Composer::setCryptoMessageFormat(Kleo::CryptoMessageFormat format)
610void Composer::setSigningKeys(
const std::vector<GpgME::Key> &signers)
614 d->signers = signers;
617void Composer::setEncryptionKeys(
const QList<QPair<
QStringList, std::vector<GpgME::Key>>> &encData)
621 d->encData = encData;
624void Composer::setNoCrypto(
bool noCrypto)
628 d->noCrypto = noCrypto;
631void Composer::setAutocryptEnabled(
bool autocryptEnabled)
635 d->autocryptEnabled = autocryptEnabled;
638void Composer::setSenderEncryptionKey(
const GpgME::Key &senderKey)
642 d->senderEncryptionKey = senderKey;
645void Composer::setGnupgHome(
const QString &path)
652QString Composer::gnupgHome()
const
659bool Composer::finished()
const
666bool Composer::autoSave()
const
670 return d->autoSaving;
677 d->autoSaving = isAutoSave;
680void Composer::start()
686void Composer::slotResult(
KJob *job)
697#include "moc_composer.cpp"
virtual void slotResult(KJob *job)
void setHeader(Headers::Base *h)
QByteArray encodedContent(bool useCrLf=false) const
const KMime::Headers::Date * date() const
const KMime::Headers::From * from() const
const KMime::Headers::To * to() const
const KMime::Headers::Cc * cc() const
const KMime::Headers::MessageID * messageID() const
const KMime::Headers::Subject * subject() const
void setAutoSave(bool isAutoSave)
Sets if this message being composed is an auto-saved message if so, might need different handling,...
The ContentJobBase class.
void start() override
Starts processing this ContentJobBase asynchronously.
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.
KMime::Content * extraContent() const
Get extra content that was previously added.
Encrypt the contents of a message .
bool resizeImage()
resizeImage
QByteArray imageArray() const
imageArray
QByteArray mimetype() const
mimetype
bool loadImageFromData(const QByteArray &data)
loadImageFromData
The InfoPart class contains the message header.
A dummy abstract class defining some errors pertaining to the Composer.
Signs and encrypt the contents of a message.
Signs the contents of a message.
A message containing only the headers...
A job that just wraps some KMime::Content into a job object for use as a subjob in another job.
A class that encapsulates an attachment.
QString i18n(const char *text, const TYPE &arg...)
QString path(const QString &relativePath)
Simple interface that both EncryptJob and SignEncryptJob implement so the composer can extract some e...
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)