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 }