File indexing completed on 2024-11-24 04:53:15
0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net> 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 #include "FileDownloadManager.h" 0023 #include "Imap/Model/FullMessageCombiner.h" 0024 #include "Imap/Model/ItemRoles.h" 0025 #include "Imap/Model/MailboxTree.h" 0026 0027 #include <QDir> 0028 0029 namespace Imap 0030 { 0031 0032 namespace Network 0033 { 0034 0035 FileDownloadManager::FileDownloadManager(QObject *parent, Imap::Network::MsgPartNetAccessManager *manager, const QModelIndex &partIndex): 0036 QObject(parent), manager(manager), partIndex(partIndex), reply(0), saved(false) 0037 { 0038 } 0039 0040 FileDownloadManager::FileDownloadManager(QObject *parent, Imap::Network::MsgPartNetAccessManager *manager, const QUrl &url, const QModelIndex &relativeRoot): 0041 QObject(parent), manager(manager), partIndex(QModelIndex()), reply(0), saved(false) 0042 { 0043 if (url.scheme().toLower() == QLatin1String("cid")) { 0044 if (!relativeRoot.isValid()) { 0045 m_errorMessage = tr("Cannot translate CID URL: message is gone"); 0046 return; 0047 } 0048 auto cid = url.path().toUtf8(); 0049 if (!cid.startsWith('<')) { 0050 cid = '<' + cid; 0051 } 0052 if (!cid.endsWith('>')) { 0053 cid += '>'; 0054 } 0055 partIndex = manager->cidToPart(relativeRoot, cid); 0056 if (!partIndex.isValid()) { 0057 m_errorMessage = tr("CID not found (%1)").arg(url.toString()); 0058 } 0059 } else { 0060 m_errorMessage = tr("Unsupported URL (%1)").arg(url.toString()); 0061 } 0062 } 0063 0064 QString FileDownloadManager::toRealFileName(const QModelIndex &index) 0065 { 0066 QString fileName = index.data(Imap::Mailbox::RolePartFileName).toString(); 0067 if (!fileName.isEmpty()) 0068 return fileName; 0069 0070 QString uid = index.data(Imap::Mailbox::RoleMessageUid).toString(); 0071 QString partId = index.data(Imap::Mailbox::RolePartId).toString(); 0072 if (partId.isEmpty()) { 0073 // we're saving the complete message 0074 return tr("msg_%1.eml").arg(uid); 0075 } else { 0076 // it's a message part 0077 return tr("msg_%1_%2").arg(uid, partId); 0078 } 0079 } 0080 0081 void FileDownloadManager::downloadPart() 0082 { 0083 if (!m_errorMessage.isNull()) { 0084 emit transferError(m_errorMessage); 0085 return; 0086 } 0087 0088 if (!partIndex.isValid()) { 0089 emit transferError(tr("FileDownloadManager::downloadPart(): part has disappeared")); 0090 return; 0091 } 0092 QString saveFileName = toRealFileName(partIndex); 0093 emit fileNameRequested(&saveFileName); 0094 if (saveFileName.isEmpty()) { 0095 emit cancelled(); 0096 return; 0097 } 0098 0099 saving.setFileName(saveFileName); 0100 saved = false; 0101 0102 QNetworkRequest request; 0103 QUrl url; 0104 url.setScheme(QStringLiteral("trojita-imap")); 0105 url.setHost(QStringLiteral("msg")); 0106 url.setPath(partIndex.data(Imap::Mailbox::RolePartPathToPart).toString()); 0107 request.setUrl(url); 0108 reply = manager->get(request); 0109 connect(reply, &QNetworkReply::finished, this, &FileDownloadManager::onPartDataTransfered); 0110 connect(reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::errorOccurred), 0111 this, &FileDownloadManager::onReplyTransferError); 0112 connect(manager, &QNetworkAccessManager::finished, this, &FileDownloadManager::deleteReply); 0113 } 0114 0115 void FileDownloadManager::downloadMessage() 0116 { 0117 if (!partIndex.isValid()) { 0118 emit transferError(tr("FileDownloadManager::downloadMessage(): message has disappeared")); 0119 return; 0120 } 0121 QString saveFileName = toRealFileName(partIndex); 0122 Q_ASSERT(!m_combiner); 0123 m_combiner = new Imap::Mailbox::FullMessageCombiner(partIndex, this); 0124 0125 emit fileNameRequested(&saveFileName); 0126 if (saveFileName.isEmpty()) { 0127 emit cancelled(); 0128 return; 0129 } 0130 0131 saving.setFileName(saveFileName); 0132 saved = false; 0133 connect(m_combiner.data(), &Mailbox::FullMessageCombiner::completed, this, &FileDownloadManager::onMessageDataTransferred); 0134 connect(m_combiner.data(), &Mailbox::FullMessageCombiner::failed, this, &FileDownloadManager::onCombinerTransferError); 0135 connect(m_combiner.data(), &Mailbox::FullMessageCombiner::completed, m_combiner.data(), &QObject::deleteLater, Qt::QueuedConnection); 0136 connect(m_combiner.data(), &Mailbox::FullMessageCombiner::failed, m_combiner.data(), &QObject::deleteLater, Qt::QueuedConnection); 0137 m_combiner->load(); 0138 } 0139 0140 void FileDownloadManager::onPartDataTransfered() 0141 { 0142 if (!reply) { 0143 return; 0144 } 0145 if (reply->error() == QNetworkReply::NoError) { 0146 if (!saving.open(QIODevice::WriteOnly)) { 0147 emit transferError(saving.errorString()); 0148 return; 0149 } 0150 if (saving.write(reply->readAll()) == -1) { 0151 emit transferError(saving.errorString()); 0152 return; 0153 } 0154 if (!saving.flush()) { 0155 emit transferError(saving.errorString()); 0156 return; 0157 } 0158 saving.close(); 0159 saved = true; 0160 emit succeeded(); 0161 } 0162 } 0163 0164 void FileDownloadManager::onMessageDataTransferred() 0165 { 0166 Q_ASSERT(m_combiner); 0167 if (!saving.open(QIODevice::WriteOnly)) { 0168 emit transferError(saving.errorString()); 0169 return; 0170 } 0171 if (saving.write(m_combiner->data().data()) == -1) { 0172 emit transferError(saving.errorString()); 0173 return; 0174 } 0175 if (!saving.flush()) { 0176 emit transferError(saving.errorString()); 0177 return; 0178 } 0179 saving.close(); 0180 saved = true; 0181 emit succeeded(); 0182 } 0183 0184 void FileDownloadManager::onReplyTransferError() 0185 { 0186 Q_ASSERT(reply); 0187 emit transferError(reply->errorString()); 0188 } 0189 0190 void FileDownloadManager::onCombinerTransferError(const QString &message) 0191 { 0192 emit transferError(message); 0193 } 0194 0195 void FileDownloadManager::deleteReply(QNetworkReply *reply) 0196 { 0197 if (reply && reply == this->reply) { 0198 if (!saved) 0199 onPartDataTransfered(); 0200 reply->deleteLater(); 0201 this->reply = nullptr; 0202 } 0203 } 0204 0205 } 0206 }