File indexing completed on 2024-06-23 05:21:14

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 
0023 //#define TROJITA_DEBUG_TASK_TREE
0024 
0025 #ifndef IMAP_IMAPTASK_H
0026 #define IMAP_IMAPTASK_H
0027 
0028 #include <QObject>
0029 #include <QPointer>
0030 #include "Common/Logging.h"
0031 #include "../Parser/Parser.h"
0032 #include "../Model/FlagsOperation.h"
0033 
0034 namespace Imap
0035 {
0036 
0037 namespace Mailbox
0038 {
0039 
0040 class Model;
0041 
0042 /** @short Parent class for all IMAP-related jobs
0043 
0044 Each ImapTask serves a distinct purpose; some of them are for establishing a connection to the IMAP server, others are responsible
0045 for updating FLAGS of some messages, other tasks maintain a given mailbox synchronized with the server's responses and yet others
0046 deal with listing mailboxes, to name a few examples.
0047 
0048 Each task signals its successful completion by the completed() signal.  Should the activity fail, failed() is emitted.
0049 
0050 Some tasks perform activity which could be interrupted by the user without huge trouble, for example when downloading huge
0051 attachments.  Tasks which support this graceful abort shall do so when asked through the abort() method.
0052 
0053 Sometimes a task will have to deal with the fact that it is forbidden to use the network connection anymore.  That's what the
0054 die() command is for.
0055 */
0056 class ImapTask : public QObject
0057 {
0058     Q_OBJECT
0059 public:
0060     explicit ImapTask(Model *model);
0061     virtual ~ImapTask();
0062 
0063     /** @short Start performing the job of the task
0064 
0065     This method should be overrided by the task implementations.  It gets called when the dispatcher considers this task ready to
0066     run.
0067     */
0068     virtual void perform() = 0;
0069 
0070     /** @short Used for informing the task that it should cease from performing *any* activities immediately and that it will die soon
0071 
0072     This is crucial for any tasks which could perform some periodical activities involving Parser*, and should
0073     also be implemented for those that want to restore the rest of the world to a reasonable and consistent state
0074     before they get killed.
0075 
0076     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
0077     parser at all.
0078     */
0079     virtual void die(const QString &message);
0080 
0081     /** @short Abort the current activity of this task in a safe manner
0082 
0083     This function is executed in contexts where someone/something has decided that this task shall not really proceed any further.
0084     In case the activity is already in the middle of a critical section, it shall however proceed further and finish.
0085     */
0086     virtual void abort();
0087 
0088     /** @short Another task wants to depend on this one
0089 
0090     When this task finishes successfully, the dependent task gets called.  If this task fails, the child task will not get called.
0091     */
0092     virtual void addDependentTask(ImapTask *task);
0093     void updateParentTask(ImapTask *newParent);
0094 
0095     bool handleState(const Imap::Responses::State *const resp);
0096     virtual bool handleStateHelper(const Imap::Responses::State *const resp);
0097     virtual bool handleCapability(const Imap::Responses::Capability *const resp);
0098     virtual bool handleNumberResponse(const Imap::Responses::NumberResponse *const resp);
0099     virtual bool handleList(const Imap::Responses::List *const resp);
0100     virtual bool handleFlags(const Imap::Responses::Flags *const resp);
0101     virtual bool handleSearch(const Imap::Responses::Search *const resp);
0102     virtual bool handleESearch(const Imap::Responses::ESearch *const resp);
0103     virtual bool handleStatus(const Imap::Responses::Status *const resp);
0104     virtual bool handleFetch(const Imap::Responses::Fetch *const resp);
0105     virtual bool handleNamespace(const Imap::Responses::Namespace *const resp);
0106     virtual bool handleSort(const Imap::Responses::Sort *const resp);
0107     virtual bool handleThread(const Imap::Responses::Thread *const resp);
0108     virtual bool handleId(const Imap::Responses::Id *const resp);
0109     virtual bool handleEnabled(const Imap::Responses::Enabled *const resp);
0110     virtual bool handleVanished(const Imap::Responses::Vanished *const resp);
0111     virtual bool handleGenUrlAuth(const Imap::Responses::GenUrlAuth *const resp);
0112     virtual bool handleSocketEncryptedResponse(const Imap::Responses::SocketEncryptedResponse *const resp);
0113     virtual bool handleSocketDisconnectedResponse(const Imap::Responses::SocketDisconnectedResponse *const resp);
0114     virtual bool handleParseErrorResponse(const Imap::Responses::ParseErrorResponse *const resp);
0115 
0116     /** @short Return true if this task has already finished and can be safely deleted */
0117     bool isFinished() const { return _finished; }
0118 
0119     /** @short Return true if this task doesn't depend on anything can be run immediately */
0120     virtual bool isReadyToRun() const;
0121 
0122     /** @short Return true if this task needs properly maintained state of the mailbox
0123 
0124     Tasks which don't care about whether the connection has any mailbox opened (like listing mailboxes, performing STATUS etc)
0125     return true.
0126     */
0127     virtual bool needsMailbox() const = 0;
0128 
0129     /** @short Obtain some additional information for the purpose of this task for debugging purposes
0130 
0131     The meaning of this function is to be able to tell what any given Task is supposed to do. It's useful
0132     especially when the Model is compiled with DEBUG_TASK_ROUTING.
0133     */
0134     virtual QString debugIdentification() const;
0135 
0136     /** @short Implemente fetching of data for TaskPresentationModel */
0137     virtual QVariant taskData(const int role) const = 0;
0138 
0139 protected:
0140     void _completed();
0141 
0142     virtual void _failed(const QString &errorMessage);
0143 
0144     /** @short Kill all pending tasks that are waiting for this one to success */
0145     virtual void killAllPendingTasks(const QString &message);
0146 
0147     /** @short Get a debug logger associated with this task
0148 
0149     Use this function to obtain a logger which can be used for recording debug information associated with the current
0150     task. The events will be marked with an identification of the task which triggered them, and could be accessed from
0151     the GUI if logging is enabled.
0152     */
0153     void log(const QString &message, const Common::LogKind kind = Common::LOG_TASKS);
0154 
0155     /** @short Priority of the task activation that controls where it gets placed in the queue */
0156     typedef enum {
0157         TASK_APPEND, /**< @short Normal mode -- task goes at the end of the list */
0158         TASK_PREPEND /**< @short Special mode -- this task shall have higher priority for all event processing and hence goes to the top */
0159     } TaskActivatingPosition;
0160     void markAsActiveTask(const TaskActivatingPosition place=TASK_APPEND);
0161 
0162 private:
0163     void handleResponseCode(const Imap::Responses::State *const resp);
0164 
0165 signals:
0166     /** @short This signal is emitted if the job failed in some way */
0167     void failed(QString errorMessage);
0168     /** @short This signal is emitted upon successful completion of a job */
0169     void completed(Imap::Mailbox::ImapTask *task);
0170 
0171 public:
0172     Imap::Parser *parser;
0173     QPointer<ImapTask> parentTask;
0174 
0175 protected:
0176     QPointer<Model> model;
0177     QList<ImapTask *> dependentTasks;
0178     bool _finished;
0179     bool _dead;
0180     bool _aborted;
0181 
0182     friend class TaskPresentationModel; // needs access to the TaskPresentationModel
0183     friend class KeepMailboxOpenTask; // needs access to dependentTasks for removing stuff
0184 #ifdef TROJITA_DEBUG_TASK_TREE
0185     friend class Model; // needs access to dependentTasks for verification
0186 #endif
0187 };
0188 
0189 #define IMAP_TASK_CHECK_ABORT_DIE \
0190     if (_dead) {\
0191         _failed(ImapTask::tr("Asked to die"));\
0192         return;\
0193     } \
0194     if (_aborted) {\
0195         _failed(ImapTask::tr("Aborted"));\
0196         return;\
0197     }
0198 
0199 #ifdef TROJITA_DEBUG_TASK_TREE
0200 #define CHECK_TASK_TREE {model->checkTaskTreeConsistency();}
0201 #else
0202 #define CHECK_TASK_TREE {}
0203 #endif
0204 
0205 }
0206 }
0207 
0208 Q_DECLARE_METATYPE(Imap::Mailbox::ImapTask *)
0209 
0210 #endif // IMAP_IMAPTASK_H