1 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net>
2
3 This file is part of the Trojita Qt IMAP e-mail client,
4 http://trojita.flaska.net/
5
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.
13
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.
18
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/>.
21 */
22
23
24 #include "ListChildMailboxesTask.h"
25 #include "Imap/Model/ItemRoles.h"
26 #include "Imap/Model/MailboxTree.h"
27 #include "Imap/Model/Model.h"
28 #include "GetAnyConnectionTask.h"
29 #include "NumberOfMessagesTask.h"
30
31 namespace Imap
32 {
33 namespace Mailbox
34 {
35
36
ListChildMailboxesTask(Model * model,const QModelIndex & mailbox)37 ListChildMailboxesTask::ListChildMailboxesTask(Model *model, const QModelIndex &mailbox):
38 ImapTask(model), mailboxIndex(mailbox), mailboxIsRootMailbox(!mailbox.isValid())
39 {
40 Q_ASSERT(!mailbox.isValid() || dynamic_cast<TreeItemMailbox *>(static_cast<TreeItem *>(mailbox.internalPointer())));
41 conn = model->m_taskFactory->createGetAnyConnectionTask(model);
42 conn->addDependentTask(this);
43 }
44
~ListChildMailboxesTask()45 ListChildMailboxesTask::~ListChildMailboxesTask()
46 {
47 qDeleteAll(m_pendingStatusResponses);
48 }
49
perform()50 void ListChildMailboxesTask::perform()
51 {
52 parser = conn->parser;
53 markAsActiveTask();
54
55 IMAP_TASK_CHECK_ABORT_DIE;
56
57 if (!mailboxIsRootMailbox && !mailboxIndex.isValid()) {
58 // FIXME: add proper fix
59 _failed(tr("Mailbox vanished before we could ask for its children"));
60 return;
61 }
62 TreeItemMailbox *mailbox = dynamic_cast<TreeItemMailbox *>(static_cast<TreeItem *>(model->translatePtr(mailboxIndex)));
63 Q_ASSERT(mailbox);
64
65 QString mailboxName = mailbox->mailbox();
66 if (mailboxName.isNull())
67 mailboxName = QStringLiteral("%");
68 else
69 mailboxName += mailbox->separator() + QLatin1Char('%');
70
71 QStringList returnOptions;
72 if (model->accessParser(parser).capabilitiesFresh) {
73 if (model->accessParser(parser).capabilities.contains(QStringLiteral("LIST-EXTENDED"))) {
74 returnOptions << QStringLiteral("SUBSCRIBED") << QStringLiteral("CHILDREN");
75 }
76 if (model->accessParser(parser).capabilities.contains(QStringLiteral("LIST-STATUS"))) {
77 returnOptions << QStringLiteral("STATUS (%1)").arg(NumberOfMessagesTask::requestedStatusOptions().join(QStringLiteral(" ")));
78 }
79 }
80 // empty string, not a null string
81 tag = parser->list(QLatin1String(""), mailboxName, returnOptions);
82 }
83
handleStateHelper(const Imap::Responses::State * const resp)84 bool ListChildMailboxesTask::handleStateHelper(const Imap::Responses::State *const resp)
85 {
86 if (resp->tag.isEmpty())
87 return false;
88
89 if (resp->tag == tag) {
90
91 if (mailboxIndex.isValid() || mailboxIsRootMailbox) {
92 TreeItemMailbox *mailbox = dynamic_cast<TreeItemMailbox *>(static_cast<TreeItem *>(model->translatePtr(mailboxIndex)));
93 Q_ASSERT(mailbox);
94
95 if (resp->kind == Responses::OK) {
96 model->finalizeList(parser, mailbox);
97 applyCachedStatus();
98 _completed();
99 } else {
100 applyCachedStatus();
101 _failed(tr("LIST failed"));
102 }
103 } else {
104 applyCachedStatus();
105 _failed(tr("Mailbox no longer available -- weird timing?"));
106 }
107 return true;
108 } else {
109 return false;
110 }
111 }
112
113 /** @short Defer processing of the STATUS responses until after all of the LISTs are processed */
handleStatus(const Imap::Responses::Status * const resp)114 bool ListChildMailboxesTask::handleStatus(const Imap::Responses::Status *const resp)
115 {
116 if (!mailboxIndex.isValid() && !mailboxIsRootMailbox)
117 return false;
118
119 if (!resp->mailbox.startsWith(mailboxIndex.data(RoleMailboxName).toString())) {
120 // not our data
121 return false;
122 }
123
124 // Got to cache these responses until we can apply them
125 m_pendingStatusResponses << new Imap::Responses::Status(*resp);
126 return true;
127 }
128
129 /** @short Send the cached STATUS responses to the Model */
applyCachedStatus()130 void ListChildMailboxesTask::applyCachedStatus()
131 {
132 Q_FOREACH(Imap::Responses::Status *resp, m_pendingStatusResponses) {
133 resp->plug(parser, model);
134 delete resp;
135 }
136 m_pendingStatusResponses.clear();
137 }
138
debugIdentification() const139 QString ListChildMailboxesTask::debugIdentification() const
140 {
141 if (!mailboxIndex.isValid() && !mailboxIsRootMailbox)
142 return QStringLiteral("[invalid mailboxIndex]");
143
144 TreeItemMailbox *mailbox = dynamic_cast<TreeItemMailbox *>(static_cast<TreeItem *>(model->translatePtr(mailboxIndex)));
145 Q_ASSERT(mailbox);
146 return QStringLiteral("Listing stuff below mailbox %1").arg(mailbox->mailbox());
147 }
148
taskData(const int role) const149 QVariant ListChildMailboxesTask::taskData(const int role) const
150 {
151 return role == RoleTaskCompactName ? QVariant(tr("Listing mailboxes")) : QVariant();
152 }
153
_failed(const QString & errorMessage)154 void ListChildMailboxesTask::_failed(const QString &errorMessage)
155 {
156 if (mailboxIsRootMailbox || mailboxIndex.isValid()) {
157 TreeItemMailbox *mailbox = dynamic_cast<TreeItemMailbox *>(static_cast<TreeItem *>(model->translatePtr(mailboxIndex)));
158 mailbox->setFetchStatus(TreeItem::UNAVAILABLE);
159 QModelIndex index = mailbox->toIndex(model);
160 emit model->dataChanged(index, index);
161 }
162 ImapTask::_failed(errorMessage);
163 }
164
165
166 }
167 }
168