Refactoring: move FETCH finalization to a corresponding Task
[trojita.git] / src / Imap / Tasks / FetchMsgPartTask.cpp
blob40e7ec81b452827cd5d7bcb3d6001afe5509603d
1 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net>
3 This file is part of the Trojita Qt IMAP e-mail client,
4 http://trojita.flaska.net/
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of
9 the License or (at your option) version 3 or any later version
10 accepted by the membership of KDE e.V. (or its successor approved
11 by the membership of KDE e.V.), which shall act as a proxy
12 defined in Section 14 of version 3 of the license.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "FetchMsgPartTask.h"
25 #include "Imap/Model/ItemRoles.h"
26 #include "Imap/Model/Model.h"
27 #include "Imap/Model/MailboxTree.h"
28 #include "KeepMailboxOpenTask.h"
30 namespace Imap
32 namespace Mailbox
35 FetchMsgPartTask::FetchMsgPartTask(Model *model, const QModelIndex &mailbox, const Uids &uids, const QList<QByteArray> &parts):
36 ImapTask(model), uids(uids), parts(parts), mailboxIndex(mailbox)
38 Q_ASSERT(!uids.isEmpty());
39 conn = model->findTaskResponsibleFor(mailboxIndex);
40 conn->addDependentTask(this);
41 connect(this, &ImapTask::failed, this, &FetchMsgPartTask::markPendingItemsUnavailable);
44 void FetchMsgPartTask::perform()
46 parser = conn->parser;
47 markAsActiveTask();
49 IMAP_TASK_CHECK_ABORT_DIE;
51 Sequence seq = Sequence::fromVector(uids);
52 tag = parser->uidFetch(seq, parts);
55 bool FetchMsgPartTask::handleFetch(const Imap::Responses::Fetch *const resp)
57 if (!mailboxIndex.isValid()) {
58 _failed(tr("Mailbox disappeared"));
59 return false;
62 TreeItemMailbox *mailbox = dynamic_cast<TreeItemMailbox *>(static_cast<TreeItem *>(mailboxIndex.internalPointer()));
63 Q_ASSERT(mailbox);
64 model->genericHandleFetch(mailbox, resp);
65 return true;
68 bool FetchMsgPartTask::handleStateHelper(const Imap::Responses::State *const resp)
70 if (resp->tag.isEmpty())
71 return false;
73 if (!mailboxIndex.isValid()) {
74 _failed(tr("Mailbox disappeared"));
75 return false;
78 if (resp->tag == tag) {
79 markPendingItemsUnavailable();
80 if (resp->kind == Responses::OK) {
81 log(QStringLiteral("Fetched parts"), Common::LOG_MESSAGES);
82 model->changeConnectionState(parser, CONN_STATE_SELECTED);
83 _completed();
84 } else {
85 _failed(tr("Part fetch failed"));
87 return true;
88 } else {
89 return false;
93 QString FetchMsgPartTask::debugIdentification() const
95 if (!mailboxIndex.isValid())
96 return QStringLiteral("[invalid mailbox]");
98 Q_ASSERT(!uids.isEmpty());
99 QStringList buf;
100 Q_FOREACH(const QByteArray &item, parts) {
101 buf << QString::fromUtf8(item);
103 return QStringLiteral("%1: parts %2 for UIDs %3")
104 .arg(mailboxIndex.data(RoleMailboxName).toString(), buf.join(QStringLiteral(", ")),
105 QString::fromUtf8(Sequence::fromVector(uids).toByteArray()));
108 QVariant FetchMsgPartTask::taskData(const int role) const
110 return role == RoleTaskCompactName ? QVariant(tr("Downloading messages")) : QVariant();
113 /** @short We're dead, the data which hasn't arrived so far won't arrive in future unless a reset happens */
114 void FetchMsgPartTask::markPendingItemsUnavailable()
116 if (!mailboxIndex.isValid())
117 return;
119 TreeItemMailbox *mailbox = dynamic_cast<TreeItemMailbox *>(static_cast<TreeItem *>(mailboxIndex.internalPointer()));
120 Q_ASSERT(mailbox);
121 QList<TreeItemMessage *> messages = model->findMessagesByUids(mailbox, uids);
122 Q_FOREACH(TreeItemMessage *message, messages) {
123 Q_FOREACH(const QByteArray &partId, parts) {
124 if (finalizeFetchPart(mailbox, message->row() + 1, partId)) {
125 log(QLatin1String("Fetched part ") + QString::fromUtf8(partId), Common::LOG_MESSAGES);
126 } else {
127 log(QLatin1String("Received no data for part ") + QString::fromUtf8(partId), Common::LOG_MESSAGES);
133 /** @short Retrieval of a message part has completed */
134 bool FetchMsgPartTask::finalizeFetchPart(TreeItemMailbox *const mailbox, const uint sequenceNo, const QByteArray &partId)
136 Q_ASSERT(model);
137 // At first, verify that the message itself is marked as loaded.
138 // If it isn't, it's probably because of Model::releaseMessageData().
139 TreeItem *item = mailbox->m_children[0]; // TreeItemMsgList
140 item = item->child(sequenceNo - 1, model); // TreeItemMessage
141 Q_ASSERT(item); // FIXME: or rather throw an exception?
142 if (item->accessFetchStatus() == TreeItem::NONE) {
143 // ...and it indeed got released, so let's just return and don't try to check anything
144 return false;
147 TreeItemPart *part = mailbox->partIdToPtr(model, static_cast<TreeItemMessage *>(item), partId);
148 if (!part) {
149 log(QStringLiteral("Can't verify part fetching status: part is not here!"), Common::LOG_MESSAGES);
150 return false;
152 if (part->loading()) {
153 part->setFetchStatus(TreeItem::UNAVAILABLE);
154 QModelIndex idx = part->toIndex(model);
155 emit model->dataChanged(idx, idx);
156 return false;
157 } else {
158 return true;