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"