File indexing completed on 2024-06-23 05:18:26
0001 /* 0002 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com> 0003 SPDX-FileCopyrightText: 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net 0004 SPDX-FileCopyrightText: 2009 Leo Franchi <lfranchi@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "composer.h" 0010 0011 #include "imagescaling/imagescaling.h" 0012 #include "imagescaling/imagescalingutils.h" 0013 #include "job/attachmentjob.h" 0014 #include "job/autocryptheadersjob.h" 0015 #include "job/encryptjob.h" 0016 #include "job/itipjob.h" 0017 #include "job/jobbase_p.h" 0018 #include "job/maintextjob.h" 0019 #include "job/multipartjob.h" 0020 #include "job/signencryptjob.h" 0021 #include "job/signjob.h" 0022 #include "job/skeletonmessagejob.h" 0023 #include "job/transparentjob.h" 0024 #include "part/globalpart.h" 0025 #include "part/infopart.h" 0026 #include "part/itippart.h" 0027 #include "part/textpart.h" 0028 0029 #include "messagecomposer_debug.h" 0030 #include <KLocalizedString> 0031 0032 using namespace MessageComposer; 0033 using MessageCore::AttachmentPart; 0034 0035 class MessageComposer::ComposerPrivate : public JobBasePrivate 0036 { 0037 public: 0038 explicit ComposerPrivate(Composer *qq) 0039 : JobBasePrivate(qq) 0040 { 0041 } 0042 0043 ~ComposerPrivate() override 0044 { 0045 delete skeletonMessage; 0046 } 0047 0048 void init(); 0049 void doStart(); // slot 0050 void composeStep1(); 0051 void composeStep2(); 0052 [[nodiscard]] QList<ContentJobBase *> createEncryptJobs(ContentJobBase *contentJob, bool sign); 0053 void contentJobFinished(KJob *job); // slot 0054 void composeWithLateAttachments(KMime::Message *headers, 0055 KMime::Content *content, 0056 const AttachmentPart::List &parts, 0057 const std::vector<GpgME::Key> &keys, 0058 const QStringList &recipients); 0059 void attachmentsFinished(KJob *job); // slot 0060 0061 void composeFinalStep(KMime::Content *headers, KMime::Content *content); 0062 0063 QString gnupgHome; 0064 QList<QPair<QStringList, std::vector<GpgME::Key>>> encData; 0065 GpgME::Key senderEncryptionKey; 0066 std::vector<GpgME::Key> signers; 0067 AttachmentPart::List attachmentParts; 0068 // attachments with different sign/encrypt settings from 0069 // main message body. added at the end of the process 0070 AttachmentPart::List lateAttachmentParts; 0071 QList<KMime::Message::Ptr> resultMessages; 0072 0073 Kleo::CryptoMessageFormat format; 0074 0075 // Stuff that the application plays with. 0076 GlobalPart *globalPart = nullptr; 0077 InfoPart *infoPart = nullptr; 0078 TextPart *textPart = nullptr; 0079 ItipPart *itipPart = nullptr; 0080 0081 // Stuff that we play with. 0082 KMime::Message *skeletonMessage = nullptr; 0083 0084 bool started = false; 0085 bool finished = false; 0086 bool sign = false; 0087 bool encrypt = false; 0088 bool noCrypto = false; 0089 bool autoSaving = false; 0090 bool autocryptEnabled = false; 0091 Q_DECLARE_PUBLIC(Composer) 0092 }; 0093 0094 void ComposerPrivate::init() 0095 { 0096 Q_Q(Composer); 0097 0098 // We cannot create these in ComposerPrivate's constructor, because 0099 // their parent q is not fully constructed at that time. 0100 globalPart = new GlobalPart(q); 0101 infoPart = new InfoPart(q); 0102 textPart = nullptr; 0103 itipPart = nullptr; 0104 } 0105 0106 void ComposerPrivate::doStart() 0107 { 0108 Q_ASSERT(!started); 0109 started = true; 0110 composeStep1(); 0111 } 0112 0113 void ComposerPrivate::composeStep1() 0114 { 0115 Q_Q(Composer); 0116 0117 // Create skeleton message (containing headers only; no content). 0118 auto skeletonJob = new SkeletonMessageJob(infoPart, globalPart, q); 0119 QObject::connect(skeletonJob, &SkeletonMessageJob::finished, q, [this, skeletonJob](KJob *job) { 0120 if (job->error()) { 0121 return; // KCompositeJob takes care of the error. 0122 } 0123 0124 // SkeletonMessageJob is a special job creating a Message instead of a Content. 0125 Q_ASSERT(skeletonMessage == nullptr); 0126 skeletonMessage = skeletonJob->message(); 0127 Q_ASSERT(skeletonMessage); 0128 skeletonMessage->assemble(); 0129 0130 composeStep2(); 0131 }); 0132 q->addSubjob(skeletonJob); 0133 skeletonJob->start(); 0134 } 0135 0136 void ComposerPrivate::composeStep2() 0137 { 0138 Q_Q(Composer); 0139 0140 ContentJobBase *mainJob = nullptr; 0141 ContentJobBase *mainContentJob = nullptr; 0142 Q_ASSERT(textPart || itipPart); // At least one must be present, otherwise it's a useless message 0143 if (textPart && !itipPart) { 0144 mainContentJob = new MainTextJob(textPart, q); 0145 } else if (!textPart && itipPart) { 0146 mainContentJob = new ItipJob(itipPart, q); 0147 } else { 0148 // Combination of both text and itip parts not supported right now 0149 Q_ASSERT(!textPart || !itipPart); 0150 } 0151 0152 if ((sign || encrypt) && format & Kleo::InlineOpenPGPFormat) { // needs custom handling --- one SignEncryptJob by itself 0153 qCDebug(MESSAGECOMPOSER_LOG) << "sending to sign/enc inline job!"; 0154 0155 if (encrypt) { 0156 // TODO: fix Inline PGP with encrypted attachments 0157 0158 const QList<ContentJobBase *> jobs = createEncryptJobs(mainContentJob, sign); 0159 for (ContentJobBase *subJob : jobs) { 0160 if (attachmentParts.isEmpty()) { 0161 // We have no attachments. Use the content given by the mainContentJob 0162 mainJob = subJob; 0163 } else { 0164 auto multipartJob = new MultipartJob(q); 0165 multipartJob->setMultipartSubtype("mixed"); 0166 multipartJob->appendSubjob(subJob); 0167 for (const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) { 0168 multipartJob->appendSubjob(new AttachmentJob(part)); 0169 } 0170 mainJob = multipartJob; 0171 } 0172 0173 QObject::connect(mainJob, SIGNAL(finished(KJob *)), q, SLOT(contentJobFinished(KJob *))); 0174 q->addSubjob(mainJob); 0175 } 0176 } else { 0177 auto subJob = new SignJob(q); 0178 subJob->setSigningKeys(signers); 0179 subJob->setCryptoMessageFormat(format); 0180 subJob->appendSubjob(mainContentJob); 0181 0182 if (attachmentParts.isEmpty()) { 0183 // We have no attachments. Use the content given by the mainContentJob. 0184 mainJob = subJob; 0185 } else { 0186 auto multipartJob = new MultipartJob(q); 0187 multipartJob->setMultipartSubtype("mixed"); 0188 multipartJob->appendSubjob(subJob); 0189 for (const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) { 0190 multipartJob->appendSubjob(new AttachmentJob(part)); 0191 } 0192 mainJob = multipartJob; 0193 } 0194 QObject::connect(mainJob, SIGNAL(finished(KJob *)), q, SLOT(contentJobFinished(KJob *))); 0195 q->addSubjob(mainJob); 0196 } 0197 0198 if (mainJob) { 0199 mainJob->start(); 0200 } else { 0201 qCDebug(MESSAGECOMPOSER_LOG) << "main job is null"; 0202 } 0203 return; 0204 } 0205 0206 if (attachmentParts.isEmpty()) { 0207 // We have no attachments. Use the content given by the mainContentJob 0208 mainJob = mainContentJob; 0209 } else { 0210 // We have attachments. Create a multipart/mixed content. 0211 QMutableListIterator<AttachmentPart::Ptr> iter(attachmentParts); 0212 while (iter.hasNext()) { 0213 AttachmentPart::Ptr part = iter.next(); 0214 qCDebug(MESSAGECOMPOSER_LOG) << "Checking attachment crypto policy... signed: " << part->isSigned() << " isEncrypted : " << part->isEncrypted(); 0215 if (!noCrypto && !autoSaving && (sign != part->isSigned() || encrypt != part->isEncrypted())) { // different policy 0216 qCDebug(MESSAGECOMPOSER_LOG) << "got attachment with different crypto policy!"; 0217 lateAttachmentParts.append(part); 0218 iter.remove(); 0219 } 0220 } 0221 auto multipartJob = new MultipartJob(q); 0222 multipartJob->setMultipartSubtype("mixed"); 0223 multipartJob->appendSubjob(mainContentJob); 0224 for (const AttachmentPart::Ptr &part : std::as_const(attachmentParts)) { 0225 multipartJob->appendSubjob(new AttachmentJob(part)); 0226 } 0227 mainJob = multipartJob; 0228 } 0229 0230 if (autocryptEnabled) { 0231 auto autocryptJob = new AutocryptHeadersJob(); 0232 autocryptJob->setSkeletonMessage(skeletonMessage); 0233 autocryptJob->setGnupgHome(gnupgHome); 0234 autocryptJob->appendSubjob(mainJob); 0235 autocryptJob->setSenderKey(senderEncryptionKey); 0236 if (encrypt && format & Kleo::OpenPGPMIMEFormat) { 0237 qDebug() << "Add gossip: " << encData[0].first.size() << encData[0].second.size(); 0238 if (encData[0].first.size() > 1 && encData[0].second.size() > 2) { 0239 autocryptJob->setGossipKeys(encData[0].second); 0240 } 0241 } 0242 mainJob = autocryptJob; 0243 } 0244 0245 if (sign) { 0246 auto sJob = new SignJob(q); 0247 sJob->setCryptoMessageFormat(format); 0248 sJob->setSigningKeys(signers); 0249 sJob->appendSubjob(mainJob); 0250 sJob->setSkeletonMessage(skeletonMessage); 0251 mainJob = sJob; 0252 } 0253 0254 if (encrypt) { 0255 const auto lstJob = createEncryptJobs(mainJob, false); 0256 for (ContentJobBase *job : lstJob) { 0257 auto eJob = dynamic_cast<EncryptJob *>(job); 0258 if (eJob && sign) { 0259 // When doing Encrypt and Sign move headers only in the signed part 0260 eJob->setProtectedHeaders(false); 0261 } 0262 QObject::connect(job, SIGNAL(finished(KJob *)), q, SLOT(contentJobFinished(KJob *))); 0263 q->addSubjob(job); 0264 mainJob = job; // start only last EncryptJob 0265 } 0266 } else { 0267 QObject::connect(mainJob, SIGNAL(finished(KJob *)), q, SLOT(contentJobFinished(KJob *))); 0268 q->addSubjob(mainJob); 0269 } 0270 0271 mainJob->start(); 0272 } 0273 0274 QList<ContentJobBase *> ComposerPrivate::createEncryptJobs(ContentJobBase *contentJob, bool sign) 0275 { 0276 Q_Q(Composer); 0277 0278 QList<ContentJobBase *> jobs; 0279 0280 // each SplitInfo holds a list of recipients/keys, if there is more than 0281 // one item in it then it means there are secondary recipients that need 0282 // different messages w/ clean headers 0283 qCDebug(MESSAGECOMPOSER_LOG) << "starting enc jobs"; 0284 qCDebug(MESSAGECOMPOSER_LOG) << "format:" << format; 0285 qCDebug(MESSAGECOMPOSER_LOG) << "enc data:" << encData.size(); 0286 0287 if (encData.isEmpty()) { // no key data! bail! 0288 q->setErrorText(i18n("No key data for recipients found.")); 0289 q->setError(Composer::IncompleteError); 0290 q->emitResult(); 0291 return jobs; 0292 } 0293 0294 const int encDataSize = encData.size(); 0295 jobs.reserve(encDataSize); 0296 for (int i = 0; i < encDataSize; ++i) { 0297 QPair<QStringList, std::vector<GpgME::Key>> recipients = encData[i]; 0298 qCDebug(MESSAGECOMPOSER_LOG) << "got first list of recipients:" << recipients.first; 0299 ContentJobBase *subJob = nullptr; 0300 if (sign) { 0301 auto seJob = new SignEncryptJob(q); 0302 0303 seJob->setCryptoMessageFormat(format); 0304 seJob->setSigningKeys(signers); 0305 seJob->setEncryptionKeys(recipients.second); 0306 seJob->setRecipients(recipients.first); 0307 seJob->setSkeletonMessage(skeletonMessage); 0308 0309 subJob = seJob; 0310 } else { 0311 auto eJob = new EncryptJob(q); 0312 eJob->setCryptoMessageFormat(format); 0313 eJob->setEncryptionKeys(recipients.second); 0314 eJob->setRecipients(recipients.first); 0315 eJob->setSkeletonMessage(skeletonMessage); 0316 eJob->setGnupgHome(gnupgHome); 0317 subJob = eJob; 0318 } 0319 qCDebug(MESSAGECOMPOSER_LOG) << "subJob" << subJob; 0320 subJob->appendSubjob(contentJob); 0321 jobs.append(subJob); 0322 } 0323 qCDebug(MESSAGECOMPOSER_LOG) << jobs.size(); 0324 return jobs; 0325 } 0326 0327 void ComposerPrivate::contentJobFinished(KJob *job) 0328 { 0329 if (job->error()) { 0330 return; // KCompositeJob takes care of the error. 0331 } 0332 qCDebug(MESSAGECOMPOSER_LOG) << "composing final message"; 0333 0334 KMime::Message *headers = nullptr; 0335 KMime::Content *resultContent = nullptr; 0336 std::vector<GpgME::Key> keys; 0337 QStringList recipients; 0338 0339 Q_ASSERT(dynamic_cast<ContentJobBase *>(job) == static_cast<ContentJobBase *>(job)); 0340 auto contentJob = static_cast<ContentJobBase *>(job); 0341 0342 // create the final headers and body, 0343 // taking into account secondary recipients for encryption 0344 if (encData.size() > 1) { // crypto job with secondary recipients.. 0345 Q_ASSERT(dynamic_cast<MessageComposer::AbstractEncryptJob *>(job)); // we need to get the recipients for this job 0346 auto eJob = dynamic_cast<MessageComposer::AbstractEncryptJob *>(job); 0347 0348 keys = eJob->encryptionKeys(); 0349 recipients = eJob->recipients(); 0350 0351 resultContent = contentJob->content(); // content() comes from superclass 0352 headers = new KMime::Message; 0353 headers->setHeader(skeletonMessage->from()); 0354 headers->setHeader(skeletonMessage->to()); 0355 headers->setHeader(skeletonMessage->cc()); 0356 headers->setHeader(skeletonMessage->subject()); 0357 headers->setHeader(skeletonMessage->date()); 0358 headers->setHeader(skeletonMessage->messageID()); 0359 0360 auto realTo = new KMime::Headers::Generic("X-KMail-EncBccRecipients"); 0361 realTo->fromUnicodeString(eJob->recipients().join(QLatin1Char('%')), "utf-8"); 0362 0363 qCDebug(MESSAGECOMPOSER_LOG) << "got one of multiple messages sending to:" << realTo->asUnicodeString(); 0364 qCDebug(MESSAGECOMPOSER_LOG) << "sending to recipients:" << recipients; 0365 headers->setHeader(realTo); 0366 headers->assemble(); 0367 } else { // just use the saved headers from before 0368 if (!encData.isEmpty()) { 0369 const auto firstElement = encData.at(0); 0370 qCDebug(MESSAGECOMPOSER_LOG) << "setting enc data:" << firstElement.first << "with num keys:" << firstElement.second.size(); 0371 keys = firstElement.second; 0372 recipients = firstElement.first; 0373 } 0374 0375 headers = skeletonMessage; 0376 resultContent = contentJob->content(); 0377 } 0378 0379 if (lateAttachmentParts.isEmpty()) { 0380 composeFinalStep(headers, resultContent); 0381 } else { 0382 composeWithLateAttachments(headers, resultContent, lateAttachmentParts, keys, recipients); 0383 } 0384 } 0385 0386 void ComposerPrivate::composeWithLateAttachments(KMime::Message *headers, 0387 KMime::Content *content, 0388 const AttachmentPart::List &parts, 0389 const std::vector<GpgME::Key> &keys, 0390 const QStringList &recipients) 0391 { 0392 Q_Q(Composer); 0393 0394 auto multiJob = new MultipartJob(q); 0395 multiJob->setMultipartSubtype("mixed"); 0396 0397 // wrap the content into a job for the multijob to handle it 0398 auto tJob = new MessageComposer::TransparentJob(q); 0399 tJob->setContent(content); 0400 multiJob->appendSubjob(tJob); 0401 multiJob->setExtraContent(headers); 0402 0403 qCDebug(MESSAGECOMPOSER_LOG) << "attachment encr key size:" << keys.size() << " recipients: " << recipients; 0404 0405 // operate correctly on each attachment that has a different crypto policy than body. 0406 for (const AttachmentPart::Ptr &attachment : std::as_const(parts)) { 0407 auto attachJob = new AttachmentJob(attachment, q); 0408 0409 qCDebug(MESSAGECOMPOSER_LOG) << "got a late attachment"; 0410 if (attachment->isSigned() && format) { 0411 qCDebug(MESSAGECOMPOSER_LOG) << "adding signjob for late attachment"; 0412 auto sJob = new SignJob(q); 0413 sJob->setContent(nullptr); 0414 sJob->setCryptoMessageFormat(format); 0415 sJob->setSigningKeys(signers); 0416 0417 sJob->appendSubjob(attachJob); 0418 if (attachment->isEncrypted()) { 0419 qCDebug(MESSAGECOMPOSER_LOG) << "adding sign + encrypt job for late attachment"; 0420 auto eJob = new EncryptJob(q); 0421 eJob->setCryptoMessageFormat(format); 0422 eJob->setEncryptionKeys(keys); 0423 eJob->setRecipients(recipients); 0424 0425 eJob->appendSubjob(sJob); 0426 0427 multiJob->appendSubjob(eJob); 0428 } else { 0429 qCDebug(MESSAGECOMPOSER_LOG) << "Just signing late attachment"; 0430 multiJob->appendSubjob(sJob); 0431 } 0432 } else if (attachment->isEncrypted() && format) { // only encryption 0433 qCDebug(MESSAGECOMPOSER_LOG) << "just encrypting late attachment"; 0434 auto eJob = new EncryptJob(q); 0435 eJob->setCryptoMessageFormat(format); 0436 eJob->setEncryptionKeys(keys); 0437 eJob->setRecipients(recipients); 0438 0439 eJob->appendSubjob(attachJob); 0440 multiJob->appendSubjob(eJob); 0441 } else { 0442 qCDebug(MESSAGECOMPOSER_LOG) << "attaching plain non-crypto attachment"; 0443 auto attachSecondJob = new AttachmentJob(attachment, q); 0444 multiJob->appendSubjob(attachSecondJob); 0445 } 0446 } 0447 0448 QObject::connect(multiJob, SIGNAL(finished(KJob *)), q, SLOT(attachmentsFinished(KJob *))); 0449 0450 q->addSubjob(multiJob); 0451 multiJob->start(); 0452 } 0453 0454 void ComposerPrivate::attachmentsFinished(KJob *job) 0455 { 0456 if (job->error()) { 0457 return; // KCompositeJob takes care of the error. 0458 } 0459 qCDebug(MESSAGECOMPOSER_LOG) << "composing final message with late attachments"; 0460 0461 Q_ASSERT(dynamic_cast<ContentJobBase *>(job)); 0462 auto contentJob = static_cast<ContentJobBase *>(job); 0463 0464 KMime::Content *content = contentJob->content(); 0465 KMime::Content *headers = contentJob->extraContent(); 0466 0467 composeFinalStep(headers, content); 0468 } 0469 0470 void ComposerPrivate::composeFinalStep(KMime::Content *headers, KMime::Content *content) 0471 { 0472 content->assemble(); 0473 0474 const QByteArray allData = headers->head() + content->encodedContent(); 0475 0476 delete content; 0477 0478 KMime::Message::Ptr resultMessage(new KMime::Message); 0479 resultMessage->setContent(allData); 0480 resultMessage->parse(); // Not strictly necessary. 0481 resultMessages.append(resultMessage); 0482 } 0483 0484 Composer::Composer(QObject *parent) 0485 : JobBase(*new ComposerPrivate(this), parent) 0486 { 0487 Q_D(Composer); 0488 d->init(); 0489 } 0490 0491 Composer::~Composer() = default; 0492 0493 QList<KMime::Message::Ptr> Composer::resultMessages() const 0494 { 0495 Q_D(const Composer); 0496 Q_ASSERT(d->finished); 0497 Q_ASSERT(!error()); 0498 return d->resultMessages; 0499 } 0500 0501 GlobalPart *Composer::globalPart() const 0502 { 0503 Q_D(const Composer); 0504 return d->globalPart; 0505 } 0506 0507 InfoPart *Composer::infoPart() const 0508 { 0509 Q_D(const Composer); 0510 return d->infoPart; 0511 } 0512 0513 TextPart *Composer::textPart() const 0514 { 0515 Q_D(const Composer); 0516 if (!d->textPart) { 0517 auto *self = const_cast<Composer *>(this); 0518 self->d_func()->textPart = new TextPart(self); 0519 } 0520 return d->textPart; 0521 } 0522 0523 void Composer::clearTextPart() 0524 { 0525 Q_D(Composer); 0526 delete d->textPart; 0527 d->textPart = nullptr; 0528 } 0529 0530 ItipPart *Composer::itipPart() const 0531 { 0532 Q_D(const Composer); 0533 if (!d->itipPart) { 0534 auto *self = const_cast<Composer *>(this); 0535 self->d_func()->itipPart = new ItipPart(self); 0536 } 0537 return d->itipPart; 0538 } 0539 0540 void Composer::clearItipPart() 0541 { 0542 Q_D(Composer); 0543 delete d->itipPart; 0544 d->itipPart = nullptr; 0545 } 0546 0547 AttachmentPart::List Composer::attachmentParts() const 0548 { 0549 Q_D(const Composer); 0550 return d->attachmentParts; 0551 } 0552 0553 void Composer::addAttachmentPart(AttachmentPart::Ptr part, bool autoresizeImage) 0554 { 0555 Q_D(Composer); 0556 Q_ASSERT(!d->started); 0557 Q_ASSERT(!d->attachmentParts.contains(part)); 0558 if (autoresizeImage) { 0559 MessageComposer::Utils resizeUtils; 0560 if (resizeUtils.resizeImage(part)) { 0561 MessageComposer::ImageScaling autoResizeJob; 0562 autoResizeJob.setName(part->name()); 0563 autoResizeJob.setMimetype(part->mimeType()); 0564 if (autoResizeJob.loadImageFromData(part->data())) { 0565 if (autoResizeJob.resizeImage()) { 0566 part->setData(autoResizeJob.imageArray()); 0567 part->setMimeType(autoResizeJob.mimetype()); 0568 part->setName(autoResizeJob.generateNewName()); 0569 resizeUtils.changeFileName(part); 0570 } 0571 } 0572 } 0573 } 0574 d->attachmentParts.append(part); 0575 } 0576 0577 void Composer::addAttachmentParts(const AttachmentPart::List &parts, bool autoresizeImage) 0578 { 0579 for (const AttachmentPart::Ptr &part : parts) { 0580 addAttachmentPart(part, autoresizeImage); 0581 } 0582 } 0583 0584 void Composer::removeAttachmentPart(AttachmentPart::Ptr part) 0585 { 0586 Q_D(Composer); 0587 Q_ASSERT(!d->started); 0588 const int numberOfElements = d->attachmentParts.removeAll(part); 0589 if (numberOfElements <= 0) { 0590 qCCritical(MESSAGECOMPOSER_LOG) << "Unknown attachment part" << part.data(); 0591 Q_ASSERT(false); 0592 return; 0593 } 0594 } 0595 0596 void Composer::setSignAndEncrypt(const bool doSign, const bool doEncrypt) 0597 { 0598 Q_D(Composer); 0599 d->sign = doSign; 0600 d->encrypt = doEncrypt; 0601 } 0602 0603 void Composer::setMessageCryptoFormat(Kleo::CryptoMessageFormat format) 0604 { 0605 Q_D(Composer); 0606 0607 d->format = format; 0608 } 0609 0610 void Composer::setSigningKeys(const std::vector<GpgME::Key> &signers) 0611 { 0612 Q_D(Composer); 0613 0614 d->signers = signers; 0615 } 0616 0617 void Composer::setEncryptionKeys(const QList<QPair<QStringList, std::vector<GpgME::Key>>> &encData) 0618 { 0619 Q_D(Composer); 0620 0621 d->encData = encData; 0622 } 0623 0624 void Composer::setNoCrypto(bool noCrypto) 0625 { 0626 Q_D(Composer); 0627 0628 d->noCrypto = noCrypto; 0629 } 0630 0631 void Composer::setAutocryptEnabled(bool autocryptEnabled) 0632 { 0633 Q_D(Composer); 0634 0635 d->autocryptEnabled = autocryptEnabled; 0636 } 0637 0638 void Composer::setSenderEncryptionKey(const GpgME::Key &senderKey) 0639 { 0640 Q_D(Composer); 0641 0642 d->senderEncryptionKey = senderKey; 0643 } 0644 0645 void Composer::setGnupgHome(const QString &path) 0646 { 0647 Q_D(Composer); 0648 0649 d->gnupgHome = path; 0650 } 0651 0652 QString Composer::gnupgHome() const 0653 { 0654 Q_D(const Composer); 0655 0656 return d->gnupgHome; 0657 } 0658 0659 bool Composer::finished() const 0660 { 0661 Q_D(const Composer); 0662 0663 return d->finished; 0664 } 0665 0666 bool Composer::autoSave() const 0667 { 0668 Q_D(const Composer); 0669 0670 return d->autoSaving; 0671 } 0672 0673 void Composer::setAutoSave(bool isAutoSave) 0674 { 0675 Q_D(Composer); 0676 0677 d->autoSaving = isAutoSave; 0678 } 0679 0680 void Composer::start() 0681 { 0682 Q_D(Composer); 0683 d->doStart(); 0684 } 0685 0686 void Composer::slotResult(KJob *job) 0687 { 0688 Q_D(Composer); 0689 JobBase::slotResult(job); 0690 0691 if (!hasSubjobs()) { 0692 d->finished = true; 0693 emitResult(); 0694 } 0695 } 0696 0697 #include "moc_composer.cpp"