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"