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

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 
0024 #include "UnSelectTask.h"
0025 #include <QUuid>
0026 #include "Imap/Model/Model.h"
0027 #include "Imap/Model/MailboxTree.h"
0028 #include "KeepMailboxOpenTask.h"
0029 
0030 namespace Imap
0031 {
0032 namespace Mailbox
0033 {
0034 
0035 UnSelectTask::UnSelectTask(Model *model, ImapTask *parentTask) :
0036     ImapTask(model)
0037 {
0038     conn = parentTask;
0039     parser = conn->parser;
0040     Q_ASSERT(parser);
0041     connect(this, &ImapTask::completed, this, &UnSelectTask::resetConnectionState);
0042 }
0043 
0044 void UnSelectTask::perform()
0045 {
0046     markAsActiveTask(TASK_PREPEND);
0047 
0048     if (_dead) {
0049         _failed(tr("Asked to die"));
0050         return;
0051     }
0052     // We really should ignore abort() -- we're a very important task
0053 
0054     if (model->accessParser(parser).maintainingTask) {
0055         model->accessParser(parser).maintainingTask->breakOrCancelPossibleIdle();
0056     }
0057     if (model->accessParser(parser).capabilities.contains(QStringLiteral("UNSELECT"))) {
0058         unSelectTag = parser->unSelect();
0059     } else {
0060         doFakeSelect();
0061     }
0062 }
0063 
0064 void UnSelectTask::doFakeSelect()
0065 {
0066     if (_dead) {
0067         _failed(tr("Asked to die"));
0068         return;
0069     }
0070     // Again, ignoring abort()
0071 
0072     if (model->accessParser(parser).maintainingTask) {
0073         model->accessParser(parser).maintainingTask->breakOrCancelPossibleIdle();
0074     }
0075     // The server does not support UNSELECT. Let's construct an unlikely-to-exist mailbox, then.
0076     selectMissingTag = parser->examine(QLatin1String("trojita non existing ") + QUuid::createUuid().toString());
0077 }
0078 
0079 bool UnSelectTask::handleStateHelper(const Imap::Responses::State *const resp)
0080 {
0081     if (resp->tag.isEmpty()) {
0082         switch (resp->respCode) {
0083         case Responses::UNSEEN:
0084         case Responses::PERMANENTFLAGS:
0085         case Responses::UIDNEXT:
0086         case Responses::UIDVALIDITY:
0087         case Responses::NOMODSEQ:
0088         case Responses::HIGHESTMODSEQ:
0089         case Responses::CLOSED:
0090             return true;
0091         default:
0092             break;
0093         }
0094     }
0095     if (!resp->tag.isEmpty()) {
0096         if (resp->tag == unSelectTag) {
0097             if (resp->kind == Responses::OK) {
0098                 // nothing should be needed here
0099                 _completed();
0100             } else {
0101                 // This is really bad.
0102                 throw MailboxException("Attempted to unselect current mailbox, but the server denied our request. "
0103                                        "Can't continue, to avoid possible data corruption.", *resp);
0104             }
0105             return true;
0106         } else if (resp->tag == selectMissingTag) {
0107             if (resp->kind == Responses::OK) {
0108                 QTimer::singleShot(0, this, SLOT(doFakeSelect()));
0109                 log(QStringLiteral("The emergency EXAMINE command has unexpectedly succeeded, trying to get out of here..."), Common::LOG_MAILBOX_SYNC);
0110             } else {
0111                 // This is very good :)
0112                 _completed();
0113             }
0114             return true;
0115         }
0116     }
0117     return false;
0118 }
0119 
0120 bool UnSelectTask::handleNumberResponse(const Imap::Responses::NumberResponse *const resp)
0121 {
0122     Q_UNUSED(resp);
0123     log(QStringLiteral("UnSelectTask: ignoring numeric response"), Common::LOG_MAILBOX_SYNC);
0124     return true;
0125 }
0126 
0127 bool UnSelectTask::handleFlags(const Imap::Responses::Flags *const resp)
0128 {
0129     Q_UNUSED(resp);
0130     log(QStringLiteral("UnSelectTask: ignoring FLAGS response"), Common::LOG_MAILBOX_SYNC);
0131     return true;
0132 }
0133 
0134 bool UnSelectTask::handleSearch(const Imap::Responses::Search *const resp)
0135 {
0136     Q_UNUSED(resp);
0137     log(QStringLiteral("UnSelectTask: ignoring SEARCH response"), Common::LOG_MAILBOX_SYNC);
0138     return true;
0139 }
0140 
0141 bool UnSelectTask::handleFetch(const Imap::Responses::Fetch *const resp)
0142 {
0143     Q_UNUSED(resp);
0144     log(QStringLiteral("UnSelectTask: ignoring FETCH response"), Common::LOG_MAILBOX_SYNC);
0145     return true;
0146 }
0147 
0148 /** @short Internal task */
0149 QVariant UnSelectTask::taskData(const int role) const
0150 {
0151     Q_UNUSED(role);
0152     return QVariant();
0153 }
0154 
0155 /** @short Reset the "waiting for [CLOSED]" state */
0156 void UnSelectTask::resetConnectionState()
0157 {
0158     auto const state = model->accessParser(parser).connState;
0159     if (state > CONN_STATE_AUTHENTICATED && state < CONN_STATE_LOGOUT) {
0160         model->changeConnectionState(parser, CONN_STATE_AUTHENTICATED);
0161     }
0162 }
0163 
0164 }
0165 }