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 //#define TROJITA_DEBUG_TASK_TREE
24 
25 #ifndef IMAP_IMAPTASK_H
26 #define IMAP_IMAPTASK_H
27 
28 #include <QObject>
29 #include <QPointer>
30 #include "Common/Logging.h"
31 #include "../Parser/Parser.h"
32 #include "../Model/FlagsOperation.h"
33 
34 namespace Imap
35 {
36 
37 namespace Mailbox
38 {
39 
40 class Model;
41 
42 /** @short Parent class for all IMAP-related jobs
43 
44 Each ImapTask serves a distinct purpose; some of them are for establishing a connection to the IMAP server, others are responsible
45 for updating FLAGS of some messages, other tasks maintain a given mailbox synchronized with the server's responses and yet others
46 deal with listing mailboxes, to name a few examples.
47 
48 Each task signals its successful completion by the completed() signal.  Should the activity fail, failed() is emitted.
49 
50 Some tasks perform activity which could be interrupted by the user without huge trouble, for example when downloading huge
51 attachments.  Tasks which support this graceful abort shall do so when asked through the abort() method.
52 
53 Sometimes a task will have to deal with the fact that it is forbidden to use the network connection anymore.  That's what the
54 die() command is for.
55 */
56 class ImapTask : public QObject
57 {
58     Q_OBJECT
59 public:
60     explicit ImapTask(Model *model);
61     virtual ~ImapTask();
62 
63     /** @short Start performing the job of the task
64 
65     This method should be overrided by the task implementations.  It gets called when the dispatcher considers this task ready to
66     run.
67     */
68     virtual void perform() = 0;
69 
70     /** @short Used for informing the task that it should cease from performing *any* activities immediately and that it will die soon
71 
72     This is crucial for any tasks which could perform some periodical activities involving Parser*, and should
73     also be implemented for those that want to restore the rest of the world to a reasonable and consistent state
74     before they get killed.
75 
76     This function is really a hard requirement -- as soon as this function got called, it's an error for this task to talk to the
77     parser at all.
78     */
79     virtual void die(const QString &message);
80 
81     /** @short Abort the current activity of this task in a safe manner
82 
83     This function is executed in contexts where someone/something has decided that this task shall not really proceed any further.
84     In case the activity is already in the middle of a critical section, it shall however proceed further and finish.
85     */
86     virtual void abort();
87 
88     /** @short Another task wants to depend on this one
89 
90     When this task finishes successfully, the dependent task gets called.  If this task fails, the child task will not get called.
91     */
92     virtual void addDependentTask(ImapTask *task);
93     void updateParentTask(ImapTask *newParent);
94 
95     bool handleState(const Imap::Responses::State *const resp);
96     virtual bool handleStateHelper(const Imap::Responses::State *const resp);
97     virtual bool handleCapability(const Imap::Responses::Capability *const resp);
98     virtual bool handleNumberResponse(const Imap::Responses::NumberResponse *const resp);
99     virtual bool handleList(const Imap::Responses::List *const resp);
100     virtual bool handleFlags(const Imap::Responses::Flags *const resp);
101     virtual bool handleSearch(const Imap::Responses::Search *const resp);
102     virtual bool handleESearch(const Imap::Responses::ESearch *const resp);
103     virtual bool handleStatus(const Imap::Responses::Status *const resp);
104     virtual bool handleFetch(const Imap::Responses::Fetch *const resp);
105     virtual bool handleNamespace(const Imap::Responses::Namespace *const resp);
106     virtual bool handleSort(const Imap::Responses::Sort *const resp);
107     virtual bool handleThread(const Imap::Responses::Thread *const resp);
108     virtual bool handleId(const Imap::Responses::Id *const resp);
109     virtual bool handleEnabled(const Imap::Responses::Enabled *const resp);
110     virtual bool handleVanished(const Imap::Responses::Vanished *const resp);
111     virtual bool handleGenUrlAuth(const Imap::Responses::GenUrlAuth *const resp);
112     virtual bool handleSocketEncryptedResponse(const Imap::Responses::SocketEncryptedResponse *const resp);
113     virtual bool handleSocketDisconnectedResponse(const Imap::Responses::SocketDisconnectedResponse *const resp);
114     virtual bool handleParseErrorResponse(const Imap::Responses::ParseErrorResponse *const resp);
115 
116     /** @short Return true if this task has already finished and can be safely deleted */
isFinished()117     bool isFinished() const { return _finished; }
118 
119     /** @short Return true if this task doesn't depend on anything can be run immediately */
120     virtual bool isReadyToRun() const;
121 
122     /** @short Return true if this task needs properly maintained state of the mailbox
123 
124     Tasks which don't care about whether the connection has any mailbox opened (like listing mailboxes, performing STATUS etc)
125     return true.
126     */
127     virtual bool needsMailbox() const = 0;
128 
129     /** @short Obtain some additional information for the purpose of this task for debugging purposes
130 
131     The meaning of this function is to be able to tell what any given Task is supposed to do. It's useful
132     especially when the Model is compiled with DEBUG_TASK_ROUTING.
133     */
134     virtual QString debugIdentification() const;
135 
136     /** @short Implemente fetching of data for TaskPresentationModel */
137     virtual QVariant taskData(const int role) const = 0;
138 
139 protected:
140     void _completed();
141 
142     virtual void _failed(const QString &errorMessage);
143 
144     /** @short Kill all pending tasks that are waiting for this one to success */
145     virtual void killAllPendingTasks(const QString &message);
146 
147     /** @short Get a debug logger associated with this task
148 
149     Use this function to obtain a logger which can be used for recording debug information associated with the current
150     task. The events will be marked with an identification of the task which triggered them, and could be accessed from
151     the GUI if logging is enabled.
152     */
153     void log(const QString &message, const Common::LogKind kind = Common::LOG_TASKS);
154 
155     /** @short Priority of the task activation that controls where it gets placed in the queue */
156     typedef enum {
157         TASK_APPEND, /**< @short Normal mode -- task goes at the end of the list */
158         TASK_PREPEND /**< @short Special mode -- this task shall have higher priority for all event processing and hence goes to the top */
159     } TaskActivatingPosition;
160     void markAsActiveTask(const TaskActivatingPosition place=TASK_APPEND);
161 
162 private:
163     void handleResponseCode(const Imap::Responses::State *const resp);
164 
165 signals:
166     /** @short This signal is emitted if the job failed in some way */
167     void failed(QString errorMessage);
168     /** @short This signal is emitted upon successful completion of a job */
169     void completed(Imap::Mailbox::ImapTask *task);
170 
171 public:
172     Imap::Parser *parser;
173     QPointer<ImapTask> parentTask;
174 
175 protected:
176     QPointer<Model> model;
177     QList<ImapTask *> dependentTasks;
178     bool _finished;
179     bool _dead;
180     bool _aborted;
181 
182     friend class TaskPresentationModel; // needs access to the TaskPresentationModel
183     friend class KeepMailboxOpenTask; // needs access to dependentTasks for removing stuff
184 #ifdef TROJITA_DEBUG_TASK_TREE
185     friend class Model; // needs access to dependentTasks for verification
186 #endif
187 };
188 
189 #define IMAP_TASK_CHECK_ABORT_DIE \
190     if (_dead) {\
191         _failed(ImapTask::tr("Asked to die"));\
192         return;\
193     } \
194     if (_aborted) {\
195         _failed(ImapTask::tr("Aborted"));\
196         return;\
197     }
198 
199 #ifdef TROJITA_DEBUG_TASK_TREE
200 #define CHECK_TASK_TREE {model->checkTaskTreeConsistency();}
201 #else
202 #define CHECK_TASK_TREE {}
203 #endif
204 
205 }
206 }
207 
208 Q_DECLARE_METATYPE(Imap::Mailbox::ImapTask *)
209 
210 #endif // IMAP_IMAPTASK_H
211