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 }