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