File indexing completed on 2025-02-23 05:01:27

0001 /* Copyright (C) 2006 - 2017 Jan Kundrát <jkt@kde.org>
0002 
0003    This file is part of the Trojita Qt IMAP e-mail client,
0004    http://trojita.flaska.net/
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public License as
0008    published by the Free Software Foundation; either version 2 of
0009    the License or (at your option) version 3 or any later version
0010    accepted by the membership of KDE e.V. (or its successor approved
0011    by the membership of KDE e.V.), which shall act as a proxy
0012    defined in Section 14 of version 3 of the license.
0013 
0014    This program is distributed in the hope that it will be useful,
0015    but WITHOUT ANY WARRANTY; without even the implied warranty of
0016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017    GNU General Public License for more details.
0018 
0019    You should have received a copy of the GNU General Public License
0020    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include <algorithm>
0024 #include <QBuffer>
0025 #include <QUrl>
0026 #include <QUuid>
0027 #include "Composer/ExistingMessageComposer.h"
0028 #include "Imap/Encoders.h"
0029 #include "Imap/Model/FullMessageCombiner.h"
0030 #include "Imap/Model/ItemRoles.h"
0031 #include "Imap/Model/Utils.h"
0032 
0033 namespace Composer {
0034 
0035 ExistingMessageComposer::ExistingMessageComposer(const QModelIndex& messageRoot)
0036     : m_root(messageRoot)
0037 {
0038     m_combiner.reset(new Imap::Mailbox::FullMessageCombiner(messageRoot, nullptr));
0039     QObject::connect(m_combiner.get(), &Imap::Mailbox::FullMessageCombiner::failed,
0040                      [this](const QString &message) { m_errorMessage = message; });
0041 }
0042 
0043 ExistingMessageComposer::~ExistingMessageComposer() = default;
0044 
0045 bool ExistingMessageComposer::isReadyForSerialization() const
0046 {
0047     return m_combiner->loaded();
0048 }
0049 
0050 void ExistingMessageComposer::setPreloadEnabled(const bool preload)
0051 {
0052     if (preload) {
0053         m_combiner->load();
0054     }
0055 }
0056 
0057 bool ExistingMessageComposer::asRawMessage(QIODevice *target, QString *errorMessage) const
0058 {
0059     m_combiner->load();
0060     if (!m_combiner->loaded()) {
0061         *errorMessage = m_errorMessage;
0062         return false;
0063     }
0064 
0065     target->write(resentChunk() + m_combiner->data());
0066     return true;
0067 }
0068 
0069 bool ExistingMessageComposer::asCatenateData(QList<Imap::Mailbox::CatenatePair> &target, QString *errorMessage) const
0070 {
0071     target.clear();
0072     QByteArray url = m_root.data(Imap::Mailbox::RoleIMAPRelativeUrl).toByteArray();
0073     if (!url.isEmpty()) {
0074         target.append(qMakePair(Imap::Mailbox::CATENATE_TEXT, resentChunk()));
0075         target.append(qMakePair(Imap::Mailbox::CATENATE_URL, url));
0076         return true;
0077     } else {
0078         *errorMessage = Imap::Mailbox::FullMessageCombiner::tr("Cannot obtain IMAP URL for CATENATE");
0079         return false;
0080     }
0081 }
0082 
0083 QDateTime ExistingMessageComposer::timestamp() const
0084 {
0085     return m_root.data(Imap::Mailbox::RoleMessageDate).toDateTime();
0086 }
0087 
0088 QByteArray ExistingMessageComposer::rawFromAddress() const
0089 {
0090     return m_resentFrom.asSMTPMailbox();
0091 }
0092 
0093 QList<QByteArray> ExistingMessageComposer::rawRecipientAddresses() const
0094 {
0095     QList<QByteArray> res;
0096     std::transform(m_recipients.cbegin(), m_recipients.cend(), std::back_inserter(res),
0097                    [](const QPair<Composer::RecipientKind, Imap::Message::MailAddress> &addr) {
0098         return addr.second.asSMTPMailbox();
0099     });
0100     return res;
0101 }
0102 
0103 void ExistingMessageComposer::setRecipients(const QList<QPair<Composer::RecipientKind, Imap::Message::MailAddress>> &recipients)
0104 {
0105     m_recipients = recipients;
0106 }
0107 
0108 void ExistingMessageComposer::setFrom(const Imap::Message::MailAddress &from)
0109 {
0110     m_resentFrom = from;
0111 }
0112 
0113 QByteArray ExistingMessageComposer::resentChunk() const
0114 {
0115     if (!m_resentDate.isValid()) {
0116         m_resentDate = QDateTime::currentDateTime();
0117     }
0118 
0119     if (m_messageId.isNull()) {
0120         m_messageId = generateMessageId(m_resentFrom);
0121     }
0122 
0123     QByteArray buf = "Resent-Date: " + Imap::dateTimeToRfc2822(m_resentDate).toUtf8() + "\r\n"
0124                      + "Resent-Message-ID: <" + m_messageId + ">\r\n";
0125     if (m_resentFrom != Imap::Message::MailAddress()) {
0126         buf += "Resent-From: " + m_resentFrom.asMailHeader() + "\r\n";
0127     }
0128 
0129     QList<QByteArray> rcptTo, rcptCc;
0130     for (auto it = m_recipients.begin(); it != m_recipients.end(); ++it) {
0131         switch(it->first) {
0132         case Composer::ADDRESS_RESENT_TO:
0133             rcptTo << it->second.asMailHeader();
0134             break;
0135         case Composer::ADDRESS_RESENT_CC:
0136             rcptCc << it->second.asMailHeader();
0137             break;
0138         case Composer::ADDRESS_RESENT_BCC:
0139             break;
0140         case Composer::ADDRESS_FROM:
0141         case Composer::ADDRESS_SENDER:
0142         case Composer::ADDRESS_REPLY_TO:
0143         case Composer::ADDRESS_RESENT_FROM:
0144         case Composer::ADDRESS_RESENT_SENDER:
0145         case Composer::ADDRESS_TO:
0146         case Composer::ADDRESS_CC:
0147         case Composer::ADDRESS_BCC:
0148             // These are not expected here
0149             Q_ASSERT(false);
0150             break;
0151         }
0152     }
0153     auto processRcptHeader = [&buf](const QByteArray &prefix, const QList<QByteArray> &recipients) {
0154         if (recipients.empty())
0155             return;
0156         buf += prefix + ": ";
0157         for (int i = 0; i < recipients.size() - 1; ++i)
0158             buf += recipients[i] + ",\r\n ";
0159         buf += recipients.last() + "\r\n";
0160     };
0161     processRcptHeader(QByteArrayLiteral("Resent-To"), rcptTo);
0162     processRcptHeader(QByteArrayLiteral("Resent-Cc"), rcptCc);
0163 
0164     return buf;
0165 }
0166 
0167 }