File indexing completed on 2024-11-24 04:50:44

0001 /*
0002   SPDX-FileCopyrightText: 1998 Barry D Benowitz <b.benowitz@telesciences.com>
0003   SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org>
0004   SPDX-FileCopyrightText: 2009 Allen Winter <winter@kde.org>
0005   SPDX-FileCopyrightText: 2023 Aakarsh MJ <mj.akarsh@gmail.com>
0006 
0007   SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "mailclient.h"
0011 #include "../config-merkuro.h"
0012 #include "mailheadermodel.h"
0013 #include "merkuro_mail_debug.h"
0014 
0015 #include <KEmailAddress>
0016 #include <KIdentityManagementCore/Identity>
0017 #include <KIdentityManagementCore/IdentityModel>
0018 
0019 #include <Akonadi/MessageQueueJob>
0020 #include <MailTransport/Transport>
0021 #include <MailTransport/TransportManager>
0022 
0023 #include <KMime/Headers>
0024 
0025 #include <MessageComposer/Composer>
0026 #include <MessageComposer/GlobalPart>
0027 #include <MessageComposer/InfoPart>
0028 #include <MessageComposer/ItipPart>
0029 #include <MessageComposer/TextPart>
0030 #include <MessageComposer/Util>
0031 
0032 #include <KJob>
0033 #include <KLocalizedString>
0034 
0035 using namespace Akonadi;
0036 
0037 MailClient::MailClient(QObject *parent)
0038     : QObject(parent)
0039 {
0040     m_charsets << "utf-8";
0041 }
0042 
0043 MailClient::~MailClient() = default;
0044 
0045 void MailClient::send(KIdentityManagementCore::IdentityModel *identityModel, MailHeaderModel *header, const QString &subject, const QString &body)
0046 {
0047     if (!header->rowCount()) {
0048         qCWarning(merkuro_MAIL_LOG) << "There are no attendees to e-mail";
0049         Q_EMIT finished(ResultNoAttendees, i18n("There are no attendees to e-mail"));
0050         return;
0051     }
0052 
0053     MessageData msg;
0054     msg.from = identityModel->data(identityModel->index(0, 0), KIdentityManagementCore::IdentityModel::EmailRole).toString();
0055     msg.subject = subject;
0056     msg.body = body;
0057 
0058     const int numberOfAttendees = header->rowCount();
0059     for (int attendee = 0; attendee < numberOfAttendees; attendee++) {
0060         const QString email = header->data(header->index(attendee, 0), MailHeaderModel::ValueRole).toString();
0061         const MailHeaderModel::Header headerAttendee = header->data(header->index(attendee, 0), MailHeaderModel::NameRole).value<MailHeaderModel::Header>();
0062         if (email.isEmpty()) {
0063             continue;
0064         } else if (headerAttendee == MailHeaderModel::To) {
0065             msg.to.push_back(email);
0066         } else if (headerAttendee == MailHeaderModel::CC) {
0067             msg.cc.push_back(email);
0068         } else if (headerAttendee == MailHeaderModel::BCC) {
0069             msg.bcc.push_back(email);
0070         }
0071     }
0072 
0073     if (msg.cc.isEmpty() && msg.to.isEmpty() && msg.bcc.isEmpty()) {
0074         qCWarning(merkuro_MAIL_LOG) << "There are really no attendees to e-mail";
0075         Q_EMIT finished(ResultReallyNoAttendees, i18n("There are no attendees to e-mail"));
0076         return;
0077     }
0078 
0079     const auto uoid = identityModel->data(identityModel->index(0, 0), KIdentityManagementCore::IdentityModel::UoidRole).toInt();
0080     const auto identity = KIdentityManagementCore::IdentityManager::self()->identityForUoid(uoid);
0081     const auto transportMgr = MailTransport::TransportManager::self();
0082     int transportId = -1;
0083     if (!identity.transport().isEmpty()) {
0084         transportId = identity.transport().toInt();
0085     } else {
0086         qWarning(merkuro_MAIL_LOG) << "Error while loading transport, using default tranport instead";
0087         transportId = transportMgr->defaultTransportId();
0088     }
0089 
0090     // No transport exits ask user to create one
0091     if (transportId == -1) {
0092         if (!transportMgr->showTransportCreationDialog(nullptr, MailTransport::TransportManager::IfNoTransportExists)) {
0093             qCritical() << "Error creating transport";
0094             Q_EMIT finished(ResultErrorCreatingTransport, i18n("Error creating transport"));
0095         }
0096         transportId = transportMgr->defaultTransportId();
0097     }
0098 
0099     auto composerPtr = populateComposer(msg, identityModel, &transportId);
0100     auto *composer = composerPtr.release();
0101     QObject::connect(composer, &MessageComposer::Composer::result, this, [this, transportId, composer, identity, msg]() {
0102         for (const auto &message : composer->resultMessages()) {
0103             queueMessage(transportId, composer, identity, message);
0104         }
0105         composer->deleteLater();
0106     });
0107     composer->start();
0108 }
0109 
0110 std::unique_ptr<MessageComposer::Composer>
0111 MailClient::populateComposer(const MessageData &msg, KIdentityManagementCore::IdentityModel *identityModel, int *transportId)
0112 {
0113     auto composer = std::make_unique<MessageComposer::Composer>();
0114     auto *globalPart = composer->globalPart();
0115     globalPart->setGuiEnabled(false);
0116     globalPart->setCharsets(m_charsets);
0117     globalPart->setMDNRequested(false);
0118     globalPart->setRequestDeleveryConfirmation(false);
0119 
0120     auto *infoPart = composer->infoPart();
0121     infoPart->setCc(msg.cc);
0122     infoPart->setTo(msg.to);
0123     infoPart->setFrom(msg.from);
0124     infoPart->setBcc(msg.bcc);
0125     infoPart->setSubject(msg.subject);
0126     infoPart->setTransportId(*transportId);
0127     infoPart->setUrgent(true);
0128     infoPart->setUserAgent(QStringLiteral("Merkuro-Mail"));
0129 
0130     // Setting Headers
0131     KMime::Headers::Base::List extras;
0132 
0133     auto *header = new KMime::Headers::Generic("X-Merkuro-Mail-Transport");
0134     header->fromUnicodeString(QString::number(*transportId), "utf-8");
0135     extras.push_back(header);
0136 
0137     header = new KMime::Headers::Generic("X-Merkuro-Mail-Transport-Name");
0138     auto transportName = identityModel->data(identityModel->index(0, 0), KIdentityManagementCore::IdentityModel::DisplayNameRole).toString();
0139     header->fromUnicodeString(transportName, "utf-8");
0140     infoPart->setExtraHeaders(extras);
0141 
0142     header = new KMime::Headers::Generic("X-Merkuro-Mail-Identity");
0143     auto identity = identityModel->data(identityModel->index(0, 0), KIdentityManagementCore::IdentityModel::UoidRole).toString();
0144     header->fromUnicodeString(identity, "utf-8");
0145     infoPart->setExtraHeaders(extras);
0146 
0147     header = new KMime::Headers::Generic("X-Merkuro-Mail-Identity-Name");
0148     auto identityName = identityModel->data(identityModel->index(0, 0), KIdentityManagementCore::IdentityModel::IdentityNameRole).toString();
0149     header->fromUnicodeString(identityName, "utf-8");
0150     infoPart->setExtraHeaders(extras);
0151 
0152     // Setting Message Body
0153     auto *textPart = composer->textPart();
0154     textPart->setCleanPlainText(msg.body);
0155     textPart->setWordWrappingEnabled(false);
0156 
0157     return composer;
0158 }
0159 
0160 void MailClient::queueMessage(const int transportId,
0161                               const MessageComposer::Composer *composer,
0162                               const KIdentityManagementCore::Identity &identity,
0163                               const KMime::Message::Ptr &message)
0164 {
0165     Akonadi::MessageQueueJob *qjob = new Akonadi::MessageQueueJob(this);
0166     message->assemble();
0167     qjob->setMessage(message);
0168 
0169     if (identity.disabledFcc()) {
0170         qjob->sentBehaviourAttribute().setSentBehaviour(Akonadi::SentBehaviourAttribute::Delete);
0171     } else {
0172         const Akonadi::Collection sentCollection(identity.fcc().toLongLong());
0173         if (sentCollection.isValid()) {
0174             qjob->sentBehaviourAttribute().setSentBehaviour(Akonadi::SentBehaviourAttribute::MoveToCollection);
0175             qjob->sentBehaviourAttribute().setMoveToCollection(sentCollection);
0176         } else {
0177             qjob->sentBehaviourAttribute().setSentBehaviour(Akonadi::SentBehaviourAttribute::MoveToDefaultSentCollection);
0178         }
0179     }
0180 
0181     qjob->transportAttribute().setTransportId(transportId);
0182     const auto transport = MailTransport::TransportManager::self()->transportById(transportId);
0183     if (transport && transport->specifySenderOverwriteAddress()) {
0184         qjob->addressAttribute().setFrom(
0185             KEmailAddress::extractEmailAddress(KEmailAddress::normalizeAddressesAndEncodeIdn(transport->senderOverwriteAddress())));
0186     } else if (!transport) {
0187         qCritical() << "Error loading transport";
0188         Q_EMIT finished(ResultErrorFetchingTransport, i18n("Error loading transport"));
0189     } else {
0190         qjob->addressAttribute().setFrom(KEmailAddress::extractEmailAddress(KEmailAddress::normalizeAddressesAndEncodeIdn(composer->infoPart()->from())));
0191     }
0192 
0193     qjob->addressAttribute().setTo(MessageComposer::Util::cleanUpEmailListAndEncoding(composer->infoPart()->to()));
0194     qjob->addressAttribute().setCc(MessageComposer::Util::cleanUpEmailListAndEncoding(composer->infoPart()->cc()));
0195     qjob->addressAttribute().setBcc(MessageComposer::Util::cleanUpEmailListAndEncoding(composer->infoPart()->bcc()));
0196 
0197     connect(qjob, &KJob::finished, this, &MailClient::handleQueueJobFinished);
0198     qjob->start();
0199 }
0200 
0201 void MailClient::handleQueueJobFinished(KJob *job)
0202 {
0203     if (job->error()) {
0204         qCritical() << "Error queueing message:" << job->errorText();
0205         Q_EMIT finished(ResultQueueJobError, i18n("Error queuing message in outbox: %1", job->errorText()));
0206     } else {
0207         Q_EMIT finished(ResultSuccess, QString());
0208     }
0209 }