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/skeletonmessagejob.h" 0008 #include "settings/messagecomposersettings.h" 0009 0010 #include "job/jobbase_p.h" 0011 #include "part/globalpart.h" 0012 #include "part/infopart.h" 0013 0014 #include <QHostInfo> 0015 #include <QUrl> 0016 0017 #include "messagecomposer_debug.h" 0018 0019 #include <KEmailAddress> 0020 #include <KMime/KMimeMessage> 0021 0022 using namespace MessageComposer; 0023 0024 class MessageComposer::SkeletonMessageJobPrivate : public JobBasePrivate 0025 { 0026 public: 0027 SkeletonMessageJobPrivate(SkeletonMessageJob *qq) 0028 : JobBasePrivate(qq) 0029 { 0030 } 0031 0032 void doStart(); // slot 0033 0034 InfoPart *infoPart = nullptr; 0035 GlobalPart *globalPart = nullptr; 0036 KMime::Message *message = nullptr; 0037 0038 Q_DECLARE_PUBLIC(SkeletonMessageJob) 0039 }; 0040 0041 void SkeletonMessageJobPrivate::doStart() 0042 { 0043 Q_Q(SkeletonMessageJob); 0044 0045 Q_ASSERT(infoPart); 0046 Q_ASSERT(message == nullptr); 0047 message = new KMime::Message; 0048 0049 // From: 0050 { 0051 auto from = new KMime::Headers::From; 0052 KMime::Types::Mailbox address; 0053 address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(infoPart->from())); 0054 from->fromUnicodeString(QString::fromLatin1(address.as7BitString("utf-8")), "utf-8"); 0055 message->setHeader(from); 0056 } 0057 0058 // To: 0059 { 0060 auto to = new KMime::Headers::To; 0061 QByteArray sTo; 0062 const QStringList lstTo = infoPart->to(); 0063 for (const QString &a : lstTo) { 0064 KMime::Types::Mailbox address; 0065 address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(a)); 0066 if (!sTo.isEmpty()) { 0067 sTo.append(","); 0068 } 0069 sTo.append(address.as7BitString("utf-8")); 0070 } 0071 to->fromUnicodeString(QString::fromLatin1(sTo), "utf-8"); 0072 message->setHeader(to); 0073 } 0074 0075 // Reply To: 0076 if (!infoPart->replyTo().isEmpty()) { 0077 auto replyTo = new KMime::Headers::ReplyTo; 0078 const QStringList lstReplyTo = infoPart->replyTo(); 0079 QByteArray sReplyTo; 0080 for (const QString &a : lstReplyTo) { 0081 KMime::Types::Mailbox address; 0082 address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(a)); 0083 if (!sReplyTo.isEmpty()) { 0084 sReplyTo.append(","); 0085 } 0086 sReplyTo.append(address.as7BitString("utf-8")); 0087 } 0088 replyTo->fromUnicodeString(QString::fromLatin1(sReplyTo), "utf-8"); 0089 message->setHeader(replyTo); 0090 } 0091 0092 // Cc: 0093 { 0094 auto cc = new KMime::Headers::Cc; 0095 QByteArray sCc; 0096 const QStringList lstCc = infoPart->cc(); 0097 for (const QString &a : lstCc) { 0098 KMime::Types::Mailbox address; 0099 address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(a)); 0100 if (!sCc.isEmpty()) { 0101 sCc.append(","); 0102 } 0103 sCc.append(address.as7BitString("utf-8")); 0104 } 0105 cc->fromUnicodeString(QString::fromLatin1(sCc), "utf-8"); 0106 message->setHeader(cc); 0107 } 0108 0109 // Bcc: 0110 { 0111 auto bcc = new KMime::Headers::Bcc; 0112 QByteArray sBcc; 0113 const QStringList lstBcc = infoPart->bcc(); 0114 for (const QString &a : lstBcc) { 0115 KMime::Types::Mailbox address; 0116 address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(a)); 0117 if (!sBcc.isEmpty()) { 0118 sBcc.append(","); 0119 } 0120 sBcc.append(address.as7BitString("utf-8")); 0121 } 0122 bcc->fromUnicodeString(QString::fromLatin1(sBcc), "utf-8"); 0123 message->setHeader(bcc); 0124 } 0125 0126 // Subject: 0127 { 0128 auto subject = new KMime::Headers::Subject; 0129 subject->fromUnicodeString(infoPart->subject(), "utf-8"); 0130 // TODO should we be more specific about the charset? 0131 message->setHeader(subject); 0132 } 0133 0134 // Date: 0135 { 0136 auto date = new KMime::Headers::Date; 0137 date->setDateTime(QDateTime::currentDateTime()); 0138 message->setHeader(date); 0139 } 0140 0141 // Fcc: 0142 if (!infoPart->fcc().isEmpty()) { 0143 auto header = new KMime::Headers::Generic("X-KMail-Fcc"); 0144 header->fromUnicodeString(infoPart->fcc(), "utf-8"); 0145 message->setHeader(header); 0146 } 0147 0148 // Transport: 0149 if (infoPart->transportId() > -1) { 0150 auto header = new KMime::Headers::Generic("X-KMail-Transport"); 0151 header->fromUnicodeString(QString::number(infoPart->transportId()), "utf-8"); 0152 message->setHeader(header); 0153 } 0154 0155 // Message-ID 0156 { 0157 auto messageId = new KMime::Headers::MessageID(); 0158 QByteArray fqdn; 0159 if (MessageComposer::MessageComposerSettings::self()->useCustomMessageIdSuffix()) { 0160 fqdn = QUrl::toAce(MessageComposer::MessageComposerSettings::self()->customMsgIDSuffix()); 0161 } 0162 if (fqdn.isEmpty()) { 0163 fqdn = QUrl::toAce(QHostInfo::localHostName()); 0164 } 0165 if (fqdn.isEmpty()) { 0166 qCWarning(MESSAGECOMPOSER_LOG) << "Unable to generate a Message-ID, falling back to 'localhost.localdomain'."; 0167 fqdn = "local.domain"; 0168 } 0169 messageId->generate(fqdn); 0170 message->setHeader(messageId); 0171 } 0172 // Extras 0173 0174 const KMime::Headers::Base::List extraHeaders = infoPart->extraHeaders(); 0175 for (KMime::Headers::Base *extra : extraHeaders) { 0176 const QByteArray headerType(extra->type()); 0177 auto copyHeader = KMime::Headers::createHeader(headerType); 0178 if (!copyHeader) { 0179 copyHeader = new KMime::Headers::Generic(headerType.constData(), headerType.size()); 0180 } 0181 copyHeader->from7BitString(extra->as7BitString(false)); 0182 message->setHeader(copyHeader); 0183 } 0184 0185 // Request Delivery Confirmation 0186 { 0187 if (globalPart->requestDeleveryConfirmation()) { 0188 // TODO fix me multi address 0189 const QString addr = infoPart->replyTo().isEmpty() ? infoPart->from() : infoPart->replyTo().at(0); 0190 auto requestDeleveryConfirmation = new KMime::Headers::Generic("Return-Receipt-To"); 0191 requestDeleveryConfirmation->fromUnicodeString(addr, "utf-8"); 0192 message->setHeader(requestDeleveryConfirmation); 0193 } 0194 } 0195 0196 // MDN 0197 { 0198 if (globalPart->MDNRequested()) { 0199 // TODO fix me multi address 0200 const QString addr = infoPart->replyTo().isEmpty() ? infoPart->from() : infoPart->replyTo().at(0); 0201 auto mdn = new KMime::Headers::Generic("Disposition-Notification-To"); 0202 mdn->fromUnicodeString(addr, "utf-8"); 0203 message->setHeader(mdn); 0204 } 0205 } 0206 0207 // Urgent header 0208 if (infoPart->urgent()) { 0209 auto urg1 = new KMime::Headers::Generic("X-PRIORITY"); 0210 urg1->fromUnicodeString(QStringLiteral("2 (High)"), "utf-8"); 0211 auto urg2 = new KMime::Headers::Generic("Priority"); 0212 urg2->fromUnicodeString(QStringLiteral("urgent"), "utf-8"); 0213 message->setHeader(urg1); 0214 message->setHeader(urg2); 0215 } 0216 0217 // In-Reply-To 0218 if (!infoPart->inReplyTo().isEmpty()) { 0219 auto header = new KMime::Headers::InReplyTo; 0220 header->fromUnicodeString(infoPart->inReplyTo(), "utf-8"); 0221 message->setHeader(header); 0222 } 0223 0224 // References 0225 if (!infoPart->references().isEmpty()) { 0226 auto header = new KMime::Headers::References; 0227 header->fromUnicodeString(infoPart->references(), "utf-8"); 0228 message->setHeader(header); 0229 } 0230 0231 q->emitResult(); // Success. 0232 } 0233 0234 SkeletonMessageJob::SkeletonMessageJob(InfoPart *infoPart, GlobalPart *globalPart, QObject *parent) 0235 : JobBase(*new SkeletonMessageJobPrivate(this), parent) 0236 { 0237 Q_D(SkeletonMessageJob); 0238 d->infoPart = infoPart; 0239 d->globalPart = globalPart; 0240 } 0241 0242 SkeletonMessageJob::~SkeletonMessageJob() = default; 0243 0244 InfoPart *SkeletonMessageJob::infoPart() const 0245 { 0246 Q_D(const SkeletonMessageJob); 0247 return d->infoPart; 0248 } 0249 0250 void SkeletonMessageJob::setInfoPart(InfoPart *part) 0251 { 0252 Q_D(SkeletonMessageJob); 0253 d->infoPart = part; 0254 } 0255 0256 GlobalPart *SkeletonMessageJob::globalPart() const 0257 { 0258 Q_D(const SkeletonMessageJob); 0259 return d->globalPart; 0260 } 0261 0262 void SkeletonMessageJob::setGlobalPart(GlobalPart *part) 0263 { 0264 Q_D(SkeletonMessageJob); 0265 d->globalPart = part; 0266 } 0267 0268 KMime::Message *SkeletonMessageJob::message() const 0269 { 0270 Q_D(const SkeletonMessageJob); 0271 return d->message; 0272 } 0273 0274 void SkeletonMessageJob::start() 0275 { 0276 Q_D(SkeletonMessageJob); 0277 d->doStart(); 0278 } 0279 0280 #include "moc_skeletonmessagejob.cpp"