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/jobbase_p.h"
17 #include "job/maintextjob.h"
18 #include "job/multipartjob.h"
19 #include "job/signencryptjob.h"
20 #include "job/signjob.h"
21 #include "job/skeletonmessagejob.h"
22 #include "job/transparentjob.h"
23 #include "part/globalpart.h"
24 #include "part/infopart.h"
25 #include "part/textpart.h"
26 #include "settings/messagecomposersettings.h"
28 #include "messagecomposer_debug.h"
29 #include <KLocalizedString>
34 class MessageComposer::ComposerPrivate :
public JobBasePrivate
37 explicit ComposerPrivate(
Composer *qq)
42 ~ComposerPrivate()
override
44 delete skeletonMessage;
52 void contentJobFinished(
KJob *job);
55 const AttachmentPart::List &parts,
56 const std::vector<GpgME::Key> &keys,
58 void attachmentsFinished(
KJob *job);
64 GpgME::Key senderEncryptionKey;
65 std::vector<GpgME::Key> signers;
66 AttachmentPart::List attachmentParts;
69 AttachmentPart::List lateAttachmentParts;
72 Kleo::CryptoMessageFormat format;
83 bool finished =
false;
86 bool noCrypto =
false;
87 bool autoSaving =
false;
88 bool autocryptEnabled =
false;
92 void ComposerPrivate::init()
103 void ComposerPrivate::doStart()
110 void ComposerPrivate::composeStep1()
122 Q_ASSERT(skeletonMessage ==
nullptr);
123 skeletonMessage = skeletonJob->message();
124 Q_ASSERT(skeletonMessage);
125 skeletonMessage->assemble();
129 q->addSubjob(skeletonJob);
130 skeletonJob->start();
133 void ComposerPrivate::composeStep2()
140 if ((sign || encrypt) && format & Kleo::InlineOpenPGPFormat) {
141 qCDebug(MESSAGECOMPOSER_LOG) <<
"sending to sign/enc inline job!";
148 if (attachmentParts.isEmpty()) {
153 multipartJob->setMultipartSubtype(
"mixed");
154 multipartJob->appendSubjob(subJob);
155 for (
const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) {
158 mainJob = multipartJob;
162 q->addSubjob(mainJob);
166 subJob->setSigningKeys(signers);
167 subJob->setCryptoMessageFormat(format);
168 subJob->appendSubjob(mainTextJob);
170 if (attachmentParts.isEmpty()) {
175 multipartJob->setMultipartSubtype(
"mixed");
176 multipartJob->appendSubjob(subJob);
177 for (
const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) {
180 mainJob = multipartJob;
183 q->addSubjob(mainJob);
189 qCDebug(MESSAGECOMPOSER_LOG) <<
"main job is null";
194 if (attachmentParts.isEmpty()) {
196 mainJob = mainTextJob;
200 while (iter.hasNext()) {
201 AttachmentPart::Ptr part = iter.next();
202 qCDebug(MESSAGECOMPOSER_LOG) <<
"Checking attachment crypto policy... signed: " << part->isSigned() <<
" isEncrypted : " << part->isEncrypted();
203 if (!noCrypto && !autoSaving && (sign != part->isSigned() || encrypt != part->isEncrypted())) {
204 qCDebug(MESSAGECOMPOSER_LOG) <<
"got attachment with different crypto policy!";
205 lateAttachmentParts.append(part);
210 multipartJob->setMultipartSubtype(
"mixed");
211 multipartJob->appendSubjob(mainTextJob);
212 for (
const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) {
215 mainJob = multipartJob;
218 if (autocryptEnabled) {
219 auto autocryptJob =
new AutocryptHeadersJob();
220 autocryptJob->setSkeletonMessage(skeletonMessage);
221 autocryptJob->setGnupgHome(gnupgHome);
222 autocryptJob->appendSubjob(mainJob);
223 autocryptJob->setSenderKey(senderEncryptionKey);
224 if (encrypt && format & Kleo::OpenPGPMIMEFormat) {
225 qDebug() <<
"Add gossip: " << encData[0].first.size() << encData[0].second.size();
226 if (encData[0].first.size() > 1 && encData[0].second.size() > 2) {
227 autocryptJob->setGossipKeys(encData[0].second);
230 mainJob = autocryptJob;
235 sJob->setCryptoMessageFormat(format);
236 sJob->setSigningKeys(signers);
237 sJob->appendSubjob(mainJob);
238 sJob->setSkeletonMessage(skeletonMessage);
243 const auto lstJob = createEncryptJobs(mainJob,
false);
248 eJob->setProtectedHeaders(
false);
256 q->addSubjob(mainJob);
271 qCDebug(MESSAGECOMPOSER_LOG) <<
"starting enc jobs";
272 qCDebug(MESSAGECOMPOSER_LOG) <<
"format:" << format;
273 qCDebug(MESSAGECOMPOSER_LOG) <<
"enc data:" << encData.
size();
275 if (encData.isEmpty()) {
276 q->setErrorText(
i18n(
"No key data for recipients found."));
277 q->setError(Composer::IncompleteError);
282 const int encDataSize = encData.
size();
284 for (
int i = 0; i < encDataSize; ++i) {
286 qCDebug(MESSAGECOMPOSER_LOG) <<
"got first list of recipients:" << recipients.first;
291 seJob->setCryptoMessageFormat(format);
292 seJob->setSigningKeys(signers);
293 seJob->setEncryptionKeys(recipients.second);
294 seJob->setRecipients(recipients.first);
295 seJob->setSkeletonMessage(skeletonMessage);
300 eJob->setCryptoMessageFormat(format);
301 eJob->setEncryptionKeys(recipients.second);
302 eJob->setRecipients(recipients.first);
303 eJob->setSkeletonMessage(skeletonMessage);
304 eJob->setGnupgHome(gnupgHome);
307 qCDebug(MESSAGECOMPOSER_LOG) <<
"subJob" << subJob;
311 qCDebug(MESSAGECOMPOSER_LOG) << jobs.
size();
315 void ComposerPrivate::contentJobFinished(
KJob *job)
320 qCDebug(MESSAGECOMPOSER_LOG) <<
"composing final message";
324 std::vector<GpgME::Key> keys;
332 if (encData.size() > 1) {
333 Q_ASSERT(
dynamic_cast<MessageComposer::AbstractEncryptJob *
>(job));
334 auto eJob =
dynamic_cast<MessageComposer::AbstractEncryptJob *
>(job);
336 keys = eJob->encryptionKeys();
337 recipients = eJob->recipients();
339 resultContent = contentJob->
content();
341 headers->
setHeader(skeletonMessage->from());
342 headers->
setHeader(skeletonMessage->to());
343 headers->
setHeader(skeletonMessage->cc());
344 headers->
setHeader(skeletonMessage->subject());
345 headers->
setHeader(skeletonMessage->date());
346 headers->
setHeader(skeletonMessage->messageID());
349 realTo->fromUnicodeString(eJob->recipients().join(
QLatin1Char(
'%')),
"utf-8");
351 qCDebug(MESSAGECOMPOSER_LOG) <<
"got one of multiple messages sending to:" << realTo->asUnicodeString();
352 qCDebug(MESSAGECOMPOSER_LOG) <<
"sending to recipients:" << recipients;
356 if (!encData.isEmpty()) {
357 const auto firstElement = encData.at(0);
358 qCDebug(MESSAGECOMPOSER_LOG) <<
"setting enc data:" << firstElement.first <<
"with num keys:" << firstElement.second.size();
359 keys = firstElement.second;
360 recipients = firstElement.
first;
363 headers = skeletonMessage;
364 resultContent = contentJob->
content();
367 if (lateAttachmentParts.isEmpty()) {
368 composeFinalStep(headers, resultContent);
370 composeWithLateAttachments(headers, resultContent, lateAttachmentParts, keys, recipients);
374 void ComposerPrivate::composeWithLateAttachments(
KMime::Message *headers,
376 const AttachmentPart::List &parts,
377 const std::vector<GpgME::Key> &keys,
383 multiJob->setMultipartSubtype(
"mixed");
387 tJob->setContent(content);
388 multiJob->appendSubjob(tJob);
389 multiJob->setExtraContent(headers);
391 qCDebug(MESSAGECOMPOSER_LOG) <<
"attachment encr key size:" << keys.size() <<
" recipients: " << recipients;
394 for (
const AttachmentPart::Ptr &attachment : std::as_const(parts)) {
397 qCDebug(MESSAGECOMPOSER_LOG) <<
"got a late attachment";
398 if (attachment->isSigned() && format) {
399 qCDebug(MESSAGECOMPOSER_LOG) <<
"adding signjob for late attachment";
401 sJob->setContent(
nullptr);
402 sJob->setCryptoMessageFormat(format);
403 sJob->setSigningKeys(signers);
405 sJob->appendSubjob(attachJob);
406 if (attachment->isEncrypted()) {
407 qCDebug(MESSAGECOMPOSER_LOG) <<
"adding sign + encrypt job for late attachment";
409 eJob->setCryptoMessageFormat(format);
410 eJob->setEncryptionKeys(keys);
411 eJob->setRecipients(recipients);
413 eJob->appendSubjob(sJob);
415 multiJob->appendSubjob(eJob);
417 qCDebug(MESSAGECOMPOSER_LOG) <<
"Just signing late attachment";
418 multiJob->appendSubjob(sJob);
420 }
else if (attachment->isEncrypted() && format) {
421 qCDebug(MESSAGECOMPOSER_LOG) <<
"just encrypting late attachment";
423 eJob->setCryptoMessageFormat(format);
424 eJob->setEncryptionKeys(keys);
425 eJob->setRecipients(recipients);
427 eJob->appendSubjob(attachJob);
428 multiJob->appendSubjob(eJob);
430 qCDebug(MESSAGECOMPOSER_LOG) <<
"attaching plain non-crypto attachment";
432 multiJob->appendSubjob(attachSecondJob);
438 q->addSubjob(multiJob);
442 void ComposerPrivate::attachmentsFinished(
KJob *job)
447 qCDebug(MESSAGECOMPOSER_LOG) <<
"composing final message with late attachments";
455 composeFinalStep(headers, content);
467 resultMessage->setContent(allData);
468 resultMessage->parse();
469 resultMessages.append(resultMessage);
472 Composer::Composer(
QObject *parent)
473 :
JobBase(*new ComposerPrivate(this), parent)
479 Composer::~Composer() =
default;
484 Q_ASSERT(d->finished);
486 return d->resultMessages;
492 return d->globalPart;
495 InfoPart *Composer::infoPart()
const
501 TextPart *Composer::textPart()
const
507 AttachmentPart::List Composer::attachmentParts()
const
510 return d->attachmentParts;
513 void Composer::addAttachmentPart(AttachmentPart::Ptr part,
bool autoresizeImage)
516 Q_ASSERT(!d->started);
517 Q_ASSERT(!d->attachmentParts.contains(part));
518 if (autoresizeImage) {
519 MessageComposer::Utils resizeUtils;
520 if (resizeUtils.resizeImage(part)) {
522 autoResizeJob.setName(part->name());
523 autoResizeJob.setMimetype(part->mimeType());
527 part->setMimeType(autoResizeJob.
mimetype());
528 part->setName(autoResizeJob.generateNewName());
529 resizeUtils.changeFileName(part);
534 d->attachmentParts.append(part);
537 void Composer::addAttachmentParts(
const AttachmentPart::List &parts,
bool autoresizeImage)
539 for (
const AttachmentPart::Ptr &part : parts) {
540 addAttachmentPart(part, autoresizeImage);
544 void Composer::removeAttachmentPart(AttachmentPart::Ptr part)
547 Q_ASSERT(!d->started);
548 const int numberOfElements = d->attachmentParts.removeAll(part);
549 if (numberOfElements <= 0) {
550 qCCritical(MESSAGECOMPOSER_LOG) <<
"Unknown attachment part" << part.data();
556 void Composer::setSignAndEncrypt(
const bool doSign,
const bool doEncrypt)
560 d->encrypt = doEncrypt;
563 void Composer::setMessageCryptoFormat(Kleo::CryptoMessageFormat format)
570 void Composer::setSigningKeys(
const std::vector<GpgME::Key> &signers)
574 d->signers = signers;
581 d->encData = encData;
584 void Composer::setNoCrypto(
bool noCrypto)
588 d->noCrypto = noCrypto;
591 void Composer::setAutocryptEnabled(
bool autocryptEnabled)
595 d->autocryptEnabled = autocryptEnabled;
598 void Composer::setSenderEncryptionKey(
const GpgME::Key &senderKey)
602 d->senderEncryptionKey = senderKey;
605 void Composer::setGnupgHome(
const QString &path)
612 QString Composer::gnupgHome()
const
619 bool Composer::finished()
const
626 bool Composer::autoSave()
const
630 return d->autoSaving;
633 void Composer::setAutoSave(
bool isAutoSave)
637 d->autoSaving = isAutoSave;
646 void Composer::slotResult(
KJob *job)
649 JobBase::slotResult(job);
657 #include "moc_composer.cpp"