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 #include "ImapTask.h"
0024 #include "Common/InvokeMethod.h"
0025 #include "Imap/Model/Model.h"
0026 #include "Imap/Model/TaskPresentationModel.h"
0027 #include "KeepMailboxOpenTask.h"
0028 
0029 namespace Imap
0030 {
0031 namespace Mailbox
0032 {
0033 
0034 ImapTask::ImapTask(Model *model) :
0035     QObject(model), parser(0), parentTask(0), model(model), _finished(false), _dead(false), _aborted(false)
0036 {
0037     connect(this, &QObject::destroyed, model, &Model::slotTaskDying);
0038     CHECK_TASK_TREE;
0039 }
0040 
0041 ImapTask::~ImapTask()
0042 {
0043 }
0044 
0045 /** @short Schedule another task to get a go when this one completes
0046 
0047 This function informs the current task (this) that when it terminates successfully, the dependant task (@arg task) shall be started.
0048 Subclasses are free to reimplement this method (@see KeepMailboxOpenTask), but they must not forget to update the parentTask of
0049 the depending task.
0050 */
0051 void ImapTask::addDependentTask(ImapTask *task)
0052 {
0053     CHECK_TASK_TREE
0054     Q_ASSERT(task);
0055     dependentTasks.append(task);
0056     task->updateParentTask(this);
0057     CHECK_TASK_TREE
0058 }
0059 
0060 /** @short Set this task's parent to the specified value */
0061 void ImapTask::updateParentTask(ImapTask *newParent)
0062 {
0063     Q_ASSERT(!parentTask);
0064     Q_ASSERT(newParent);
0065     parentTask = newParent;
0066     CHECK_TASK_TREE
0067     model->m_taskModel->slotTaskGotReparented(this);
0068     if (parser) {
0069         Q_ASSERT(!model->accessParser(parser).activeTasks.contains(this));
0070         //log(tr("Reparented to %1").arg(newParent->debugIdentification()));
0071     }
0072     CHECK_TASK_TREE
0073 }
0074 
0075 /** @short Tells the Model that we're from now on an active task */
0076 void ImapTask::markAsActiveTask(const TaskActivatingPosition place)
0077 {
0078     CHECK_TASK_TREE
0079     Q_ASSERT(parser);
0080     switch (place) {
0081     case TASK_APPEND:
0082         model->accessParser(parser).activeTasks.append(this);
0083         break;
0084     case TASK_PREPEND:
0085         model->accessParser(parser).activeTasks.prepend(this);
0086         break;
0087     }
0088     if (parentTask) {
0089         parentTask->dependentTasks.removeAll(this);
0090     }
0091     // As we're an active task, we no longer have a parent task
0092     parentTask = 0;
0093     model->m_taskModel->slotTaskGotReparented(this);
0094 
0095     if (model->accessParser(parser).maintainingTask && model->accessParser(parser).maintainingTask != this) {
0096         // Got to inform the currently responsible maintaining task about our demise
0097         connect(this, &QObject::destroyed, model->accessParser(parser).maintainingTask.data(), &KeepMailboxOpenTask::slotTaskDeleted);
0098     }
0099 
0100     log(QStringLiteral("Activated"));
0101     CHECK_TASK_TREE
0102 }
0103 
0104 bool ImapTask::handleState(const Imap::Responses::State *const resp)
0105 {
0106     handleResponseCode(resp);
0107     return handleStateHelper(resp);
0108 }
0109 
0110 bool ImapTask::handleStateHelper(const Imap::Responses::State *const resp)
0111 {
0112     Q_UNUSED(resp);
0113     return false;
0114 }
0115 
0116 bool ImapTask::handleCapability(const Imap::Responses::Capability *const resp)
0117 {
0118     Q_UNUSED(resp);
0119     return false;
0120 }
0121 
0122 bool ImapTask::handleNumberResponse(const Imap::Responses::NumberResponse *const resp)
0123 {
0124     Q_UNUSED(resp);
0125     return false;
0126 }
0127 
0128 bool ImapTask::handleList(const Imap::Responses::List *const resp)
0129 {
0130     Q_UNUSED(resp);
0131     return false;
0132 }
0133 
0134 bool ImapTask::handleFlags(const Imap::Responses::Flags *const resp)
0135 {
0136     Q_UNUSED(resp);
0137     return false;
0138 }
0139 
0140 bool ImapTask::handleSearch(const Imap::Responses::Search *const resp)
0141 {
0142     Q_UNUSED(resp);
0143     return false;
0144 }
0145 
0146 bool ImapTask::handleESearch(const Imap::Responses::ESearch *const resp)
0147 {
0148     Q_UNUSED(resp);
0149     return false;
0150 }
0151 
0152 bool ImapTask::handleStatus(const Imap::Responses::Status *const resp)
0153 {
0154     Q_UNUSED(resp);
0155     return false;
0156 }
0157 
0158 bool ImapTask::handleFetch(const Imap::Responses::Fetch *const resp)
0159 {
0160     Q_UNUSED(resp);
0161     return false;
0162 }
0163 
0164 bool ImapTask::handleNamespace(const Imap::Responses::Namespace *const resp)
0165 {
0166     Q_UNUSED(resp);
0167     return false;
0168 }
0169 
0170 bool ImapTask::handleSort(const Imap::Responses::Sort *const resp)
0171 {
0172     Q_UNUSED(resp);
0173     return false;
0174 }
0175 
0176 bool ImapTask::handleThread(const Imap::Responses::Thread *const resp)
0177 {
0178     Q_UNUSED(resp);
0179     return false;
0180 }
0181 
0182 bool ImapTask::handleId(const Responses::Id *const resp)
0183 {
0184     Q_UNUSED(resp);
0185     return false;
0186 }
0187 
0188 bool ImapTask::handleEnabled(const Responses::Enabled *const resp)
0189 {
0190     Q_UNUSED(resp);
0191     return false;
0192 }
0193 
0194 bool ImapTask::handleVanished(const Responses::Vanished *const resp)
0195 {
0196     Q_UNUSED(resp);
0197     return false;
0198 }
0199 
0200 bool ImapTask::handleGenUrlAuth(const Responses::GenUrlAuth *const resp)
0201 {
0202     Q_UNUSED(resp);
0203     return false;
0204 }
0205 
0206 bool ImapTask::handleSocketEncryptedResponse(const Imap::Responses::SocketEncryptedResponse *const resp)
0207 {
0208     Q_UNUSED(resp);
0209     return false;
0210 }
0211 
0212 bool ImapTask::handleSocketDisconnectedResponse(const Imap::Responses::SocketDisconnectedResponse *const resp)
0213 {
0214     Q_UNUSED(resp);
0215     return false;
0216 }
0217 
0218 bool ImapTask::handleParseErrorResponse(const Imap::Responses::ParseErrorResponse *const resp)
0219 {
0220     Q_UNUSED(resp);
0221     return false;
0222 }
0223 
0224 void ImapTask::_completed()
0225 {
0226     _finished = true;
0227     log(QStringLiteral("Completed"));
0228     Q_FOREACH(ImapTask* task, dependentTasks) {
0229         if (!task->isFinished())
0230             task->perform();
0231     }
0232     emit completed(this);
0233 }
0234 
0235 void ImapTask::_failed(const QString &errorMessage)
0236 {
0237     _finished = true;
0238     killAllPendingTasks(errorMessage);
0239     log(QStringLiteral("Failed: %1").arg(errorMessage));
0240     emit failed(errorMessage);
0241 }
0242 
0243 void ImapTask::killAllPendingTasks(const QString &message)
0244 {
0245     Q_FOREACH(ImapTask *task, dependentTasks) {
0246         task->die(message);
0247     }
0248 }
0249 
0250 void ImapTask::handleResponseCode(const Imap::Responses::State *const resp)
0251 {
0252     using namespace Imap::Responses;
0253     // Check for common stuff like ALERT and CAPABILITIES update
0254     switch (resp->respCode) {
0255     case ALERT:
0256         EMIT_LATER(model, alertReceived, Q_ARG(QString, tr("The server sent the following ALERT:\n%1").arg(resp->message)));
0257         break;
0258     case CAPABILITIES:
0259     {
0260         const RespData<QStringList> *const caps = dynamic_cast<const RespData<QStringList>* const>(resp->respCodeData.data());
0261         if (caps) {
0262             model->updateCapabilities(parser, caps->data);
0263         }
0264     }
0265     break;
0266     case BADCHARSET:
0267     case PARSE:
0268         qDebug() << "The server was having troubles with parsing message data:" << resp->message;
0269         break;
0270     default:
0271         // do nothing here, it must be handled later
0272         break;
0273     }
0274 }
0275 
0276 bool ImapTask::isReadyToRun() const
0277 {
0278     return false;
0279 }
0280 
0281 void ImapTask::die(const QString &message)
0282 {
0283     _dead = true;
0284     if (!_finished)
0285         _failed(message);
0286 }
0287 
0288 void ImapTask::abort()
0289 {
0290     _aborted = true;
0291     Q_FOREACH(ImapTask* task, dependentTasks) {
0292         task->abort();
0293     }
0294 }
0295 
0296 QString ImapTask::debugIdentification() const
0297 {
0298     return QString();
0299 }
0300 
0301 void ImapTask::log(const QString &message, const Common::LogKind kind)
0302 {
0303     Q_ASSERT(model);
0304     QString dbg = debugIdentification();
0305     if (!dbg.isEmpty()) {
0306         dbg.prepend(QLatin1Char(' '));
0307     }
0308     model->logTrace(parser ? parser->parserId() : 0, kind, QString::fromUtf8(metaObject()->className()) + dbg, message);
0309     model->m_taskModel->slotTaskMighHaveChanged(this);
0310 }
0311 
0312 }
0313 
0314 }