File indexing completed on 2024-06-23 05:18:33

0001 /*
0002   SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
0003 
0004   SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "job/singlepartjob.h"
0008 
0009 #include "contentjobbase_p.h"
0010 #include "part/globalpart.h"
0011 
0012 #include "messagecomposer_debug.h"
0013 #include <KLocalizedString>
0014 
0015 #include <KMime/Content>
0016 #include <KMime/Headers>
0017 
0018 using namespace MessageComposer;
0019 
0020 class MessageComposer::SinglepartJobPrivate : public ContentJobBasePrivate
0021 {
0022 public:
0023     SinglepartJobPrivate(SinglepartJob *qq)
0024         : ContentJobBasePrivate(qq)
0025     {
0026     }
0027 
0028     bool chooseCTE();
0029 
0030     QByteArray data;
0031     KMime::Headers::ContentDescription *contentDescription = nullptr;
0032     KMime::Headers::ContentDisposition *contentDisposition = nullptr;
0033     KMime::Headers::ContentID *contentID = nullptr;
0034     KMime::Headers::ContentTransferEncoding *contentTransferEncoding = nullptr;
0035     KMime::Headers::ContentType *contentType = nullptr;
0036 
0037     Q_DECLARE_PUBLIC(SinglepartJob)
0038 };
0039 
0040 bool SinglepartJobPrivate::chooseCTE()
0041 {
0042     Q_Q(SinglepartJob);
0043 
0044     auto allowed = KMime::encodingsForData(data);
0045 
0046     if (!q->globalPart()->is8BitAllowed()) {
0047         allowed.removeAll(KMime::Headers::CE8Bit);
0048     }
0049 
0050 #if 0 // TODO signing
0051       // In the following cases only QP and Base64 are allowed:
0052       // - the buffer will be OpenPGP/MIME signed and it contains trailing
0053       //   whitespace (cf. RFC 3156)
0054       // - a line starts with "From "
0055     if ((willBeSigned && cf.hasTrailingWhitespace())
0056         || cf.hasLeadingFrom()) {
0057         ret.removeAll(DwMime::kCte8bit);
0058         ret.removeAll(DwMime::kCte7bit);
0059     }
0060 #endif
0061 
0062     if (contentTransferEncoding) {
0063         // Specific CTE set.  Check that our data fits in it.
0064         if (!allowed.contains(contentTransferEncoding->encoding())) {
0065             q->setError(JobBase::BugError);
0066             q->setErrorText(
0067                 i18n("%1 Content-Transfer-Encoding cannot correctly encode this message.", KMime::nameForEncoding(contentTransferEncoding->encoding())));
0068             return false;
0069             // TODO improve error message in case 8bit is requested but not allowed.
0070         }
0071     } else {
0072         // No specific CTE set.  Choose the best one.
0073         Q_ASSERT(!allowed.isEmpty());
0074         contentTransferEncoding = new KMime::Headers::ContentTransferEncoding;
0075         contentTransferEncoding->setEncoding(allowed.first());
0076     }
0077     qCDebug(MESSAGECOMPOSER_LOG) << "Settled on encoding" << KMime::nameForEncoding(contentTransferEncoding->encoding());
0078     return true;
0079 }
0080 
0081 SinglepartJob::SinglepartJob(QObject *parent)
0082     : ContentJobBase(*new SinglepartJobPrivate(this), parent)
0083 {
0084 }
0085 
0086 SinglepartJob::~SinglepartJob() = default;
0087 
0088 QByteArray SinglepartJob::data() const
0089 {
0090     Q_D(const SinglepartJob);
0091     return d->data;
0092 }
0093 
0094 void SinglepartJob::setData(const QByteArray &data)
0095 {
0096     Q_D(SinglepartJob);
0097     d->data = data;
0098 }
0099 
0100 KMime::Headers::ContentDescription *SinglepartJob::contentDescription()
0101 {
0102     Q_D(SinglepartJob);
0103     if (!d->contentDescription) {
0104         d->contentDescription = new KMime::Headers::ContentDescription;
0105     }
0106     return d->contentDescription;
0107 }
0108 
0109 KMime::Headers::ContentDisposition *SinglepartJob::contentDisposition()
0110 {
0111     Q_D(SinglepartJob);
0112     if (!d->contentDisposition) {
0113         d->contentDisposition = new KMime::Headers::ContentDisposition;
0114     }
0115     return d->contentDisposition;
0116 }
0117 
0118 KMime::Headers::ContentID *SinglepartJob::contentID()
0119 {
0120     Q_D(SinglepartJob);
0121     if (!d->contentID) {
0122         d->contentID = new KMime::Headers::ContentID;
0123     }
0124     return d->contentID;
0125 }
0126 
0127 KMime::Headers::ContentTransferEncoding *SinglepartJob::contentTransferEncoding()
0128 {
0129     Q_D(SinglepartJob);
0130     if (!d->contentTransferEncoding) {
0131         d->contentTransferEncoding = new KMime::Headers::ContentTransferEncoding;
0132     }
0133     return d->contentTransferEncoding;
0134 }
0135 
0136 KMime::Headers::ContentType *SinglepartJob::contentType()
0137 {
0138     Q_D(SinglepartJob);
0139     if (!d->contentType) {
0140         d->contentType = new KMime::Headers::ContentType;
0141     }
0142     return d->contentType;
0143 }
0144 
0145 void SinglepartJob::process()
0146 {
0147     Q_D(SinglepartJob);
0148     Q_ASSERT(d->resultContent == nullptr); // Not processed before.
0149     d->resultContent = new KMime::Content;
0150 
0151     if (!d->chooseCTE()) {
0152         Q_ASSERT(error());
0153         emitResult();
0154         return;
0155     }
0156 
0157     // Set headers.
0158     if (d->contentDescription) {
0159         d->resultContent->setHeader(d->contentDescription);
0160     }
0161     if (d->contentDisposition) {
0162         d->resultContent->setHeader(d->contentDisposition);
0163     }
0164     if (d->contentID) {
0165         d->resultContent->setHeader(d->contentID);
0166     }
0167     Q_ASSERT(d->contentTransferEncoding); // chooseCTE() created it if it didn't exist.
0168     {
0169         d->resultContent->setHeader(d->contentTransferEncoding);
0170     }
0171     if (d->contentType) {
0172         d->resultContent->setHeader(d->contentType);
0173     }
0174 
0175     // Set data.
0176     d->resultContent->setBody(d->data);
0177 
0178     emitResult();
0179 }
0180 
0181 #include "moc_singlepartjob.cpp"