1 /* 2 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com> 3 4 SPDX-License-Identifier: LGPL-2.0-or-later 5 */ 6 7 #include "job/singlepartjob.h" 8 9 #include "composer/composer.h" 10 #include "contentjobbase_p.h" 11 #include "part/globalpart.h" 12 #include "utils/util.h" 13 14 #include "messagecomposer_debug.h" 15 #include <KLocalizedString> 16 17 #include <KMime/Content> 18 #include <KMime/Headers> 19 20 using namespace MessageComposer; 21 22 class MessageComposer::SinglepartJobPrivate : public ContentJobBasePrivate 23 { 24 public: SinglepartJobPrivate(SinglepartJob * qq)25 SinglepartJobPrivate(SinglepartJob *qq) 26 : ContentJobBasePrivate(qq) 27 { 28 } 29 30 bool chooseCTE(); 31 32 QByteArray data; 33 KMime::Headers::ContentDescription *contentDescription = nullptr; 34 KMime::Headers::ContentDisposition *contentDisposition = nullptr; 35 KMime::Headers::ContentID *contentID = nullptr; 36 KMime::Headers::ContentTransferEncoding *contentTransferEncoding = nullptr; 37 KMime::Headers::ContentType *contentType = nullptr; 38 39 Q_DECLARE_PUBLIC(SinglepartJob) 40 }; 41 chooseCTE()42bool SinglepartJobPrivate::chooseCTE() 43 { 44 Q_Q(SinglepartJob); 45 46 auto allowed = KMime::encodingsForData(data); 47 48 if (!q->globalPart()->is8BitAllowed()) { 49 allowed.removeAll(KMime::Headers::CE8Bit); 50 } 51 52 #if 0 // TODO signing 53 // In the following cases only QP and Base64 are allowed: 54 // - the buffer will be OpenPGP/MIME signed and it contains trailing 55 // whitespace (cf. RFC 3156) 56 // - a line starts with "From " 57 if ((willBeSigned && cf.hasTrailingWhitespace()) 58 || cf.hasLeadingFrom()) { 59 ret.removeAll(DwMime::kCte8bit); 60 ret.removeAll(DwMime::kCte7bit); 61 } 62 #endif 63 64 if (contentTransferEncoding) { 65 // Specific CTE set. Check that our data fits in it. 66 if (!allowed.contains(contentTransferEncoding->encoding())) { 67 q->setError(JobBase::BugError); 68 q->setErrorText( 69 i18n("%1 Content-Transfer-Encoding cannot correctly encode this message.", KMime::nameForEncoding(contentTransferEncoding->encoding()))); 70 return false; 71 // TODO improve error message in case 8bit is requested but not allowed. 72 } 73 } else { 74 // No specific CTE set. Choose the best one. 75 Q_ASSERT(!allowed.isEmpty()); 76 contentTransferEncoding = new KMime::Headers::ContentTransferEncoding; 77 contentTransferEncoding->setEncoding(allowed.first()); 78 } 79 qCDebug(MESSAGECOMPOSER_LOG) << "Settled on encoding" << KMime::nameForEncoding(contentTransferEncoding->encoding()); 80 return true; 81 } 82 SinglepartJob(QObject * parent)83SinglepartJob::SinglepartJob(QObject *parent) 84 : ContentJobBase(*new SinglepartJobPrivate(this), parent) 85 { 86 } 87 ~SinglepartJob()88SinglepartJob::~SinglepartJob() 89 { 90 } 91 data() const92QByteArray SinglepartJob::data() const 93 { 94 Q_D(const SinglepartJob); 95 return d->data; 96 } 97 setData(const QByteArray & data)98void SinglepartJob::setData(const QByteArray &data) 99 { 100 Q_D(SinglepartJob); 101 d->data = data; 102 } 103 contentDescription()104KMime::Headers::ContentDescription *SinglepartJob::contentDescription() 105 { 106 Q_D(SinglepartJob); 107 if (!d->contentDescription) { 108 d->contentDescription = new KMime::Headers::ContentDescription; 109 } 110 return d->contentDescription; 111 } 112 contentDisposition()113KMime::Headers::ContentDisposition *SinglepartJob::contentDisposition() 114 { 115 Q_D(SinglepartJob); 116 if (!d->contentDisposition) { 117 d->contentDisposition = new KMime::Headers::ContentDisposition; 118 } 119 return d->contentDisposition; 120 } 121 contentID()122KMime::Headers::ContentID *SinglepartJob::contentID() 123 { 124 Q_D(SinglepartJob); 125 if (!d->contentID) { 126 d->contentID = new KMime::Headers::ContentID; 127 } 128 return d->contentID; 129 } 130 contentTransferEncoding()131KMime::Headers::ContentTransferEncoding *SinglepartJob::contentTransferEncoding() 132 { 133 Q_D(SinglepartJob); 134 if (!d->contentTransferEncoding) { 135 d->contentTransferEncoding = new KMime::Headers::ContentTransferEncoding; 136 } 137 return d->contentTransferEncoding; 138 } 139 contentType()140KMime::Headers::ContentType *SinglepartJob::contentType() 141 { 142 Q_D(SinglepartJob); 143 if (!d->contentType) { 144 d->contentType = new KMime::Headers::ContentType; 145 } 146 return d->contentType; 147 } 148 process()149void SinglepartJob::process() 150 { 151 Q_D(SinglepartJob); 152 Q_ASSERT(d->resultContent == nullptr); // Not processed before. 153 d->resultContent = new KMime::Content; 154 155 if (!d->chooseCTE()) { 156 Q_ASSERT(error()); 157 emitResult(); 158 return; 159 } 160 161 // Set headers. 162 if (d->contentDescription) { 163 d->resultContent->setHeader(d->contentDescription); 164 } 165 if (d->contentDisposition) { 166 d->resultContent->setHeader(d->contentDisposition); 167 } 168 if (d->contentID) { 169 d->resultContent->setHeader(d->contentID); 170 } 171 Q_ASSERT(d->contentTransferEncoding); // chooseCTE() created it if it didn't exist. 172 { 173 d->resultContent->setHeader(d->contentTransferEncoding); 174 } 175 if (d->contentType) { 176 d->resultContent->setHeader(d->contentType); 177 } 178 179 // Set data. 180 d->resultContent->setBody(d->data); 181 182 emitResult(); 183 } 184