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

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 <QTimer>
0024 #include "IdleLauncher.h"
0025 #include "Imap/Model/Model.h"
0026 #include "KeepMailboxOpenTask.h"
0027 
0028 namespace Imap
0029 {
0030 namespace Mailbox
0031 {
0032 
0033 IdleLauncher::IdleLauncher(KeepMailboxOpenTask *parent):
0034     QObject(parent), task(parent), m_idling(false), m_idleCommandRunning(false)
0035 {
0036     delayedEnter = new QTimer(this);
0037     delayedEnter->setObjectName(QStringLiteral("%1-IdleLauncher-delayedEnter").arg(task->objectName()));
0038     delayedEnter->setSingleShot(true);
0039     // It's a question about what timeout to set here -- if it's too long, we enter IDLE too soon, before the
0040     // user has a chance to click on a message, but if we set it too long, we needlessly wait too long between
0041     // we receive updates, and also between terminating one IDLE and starting another.
0042     // 6 seconds is a compromise here.
0043     bool ok;
0044     int timeout = parent->model->property("trojita-imap-idle-delayedEnter").toUInt(&ok);
0045     if (! ok)
0046         timeout = 6 * 1000;
0047     delayedEnter->setInterval(timeout);
0048     connect(delayedEnter, &QTimer::timeout, this, &IdleLauncher::slotEnterIdleNow);
0049     renewal = new QTimer(this);
0050     renewal->setObjectName(QStringLiteral("%1-IdleLauncher-renewal").arg(task->objectName()));
0051     renewal->setSingleShot(true);
0052     timeout = parent->model->property("trojita-imap-idle-renewal").toUInt(&ok);
0053     if (! ok)
0054         timeout = 1000 * 29 * 60; // 29 minutes -- that's the longest allowed time to IDLE
0055     renewal->setInterval(timeout);
0056     connect(renewal, &QTimer::timeout, this, &IdleLauncher::slotTerminateLongIdle);
0057 }
0058 
0059 void IdleLauncher::slotEnterIdleNow()
0060 {
0061     delayedEnter->stop();
0062     renewal->stop();
0063 
0064     if (m_idleCommandRunning) {
0065         enterIdleLater();
0066         return;
0067     }
0068 
0069     Q_ASSERT(task->parser);
0070     Q_ASSERT(! m_idling);
0071     Q_ASSERT(! m_idleCommandRunning);
0072     Q_ASSERT(task->tagIdle.isEmpty());
0073     task->tagIdle = task->parser->idle();
0074     renewal->start();
0075     m_idling = true;
0076     m_idleCommandRunning = true;
0077 }
0078 
0079 void IdleLauncher::finishIdle()
0080 {
0081     Q_ASSERT(task->parser);
0082     if (m_idling) {
0083         renewal->stop();
0084         task->parser->idleDone();
0085         m_idling = false;
0086     } else if (delayedEnter->isActive()) {
0087         delayedEnter->stop();
0088     }
0089 }
0090 
0091 void IdleLauncher::slotTerminateLongIdle()
0092 {
0093     if (m_idling)
0094         finishIdle();
0095 }
0096 
0097 void IdleLauncher::enterIdleLater()
0098 {
0099     if (m_idling)
0100         return;
0101 
0102     delayedEnter->start();
0103 }
0104 
0105 void IdleLauncher::die()
0106 {
0107     delayedEnter->stop();
0108     delayedEnter->disconnect();
0109     renewal->stop();
0110     renewal->disconnect();
0111 }
0112 
0113 bool IdleLauncher::idling() const
0114 {
0115     return m_idling;
0116 }
0117 
0118 bool IdleLauncher::waitingForIdleTaggedTermination() const
0119 {
0120     return m_idleCommandRunning;
0121 }
0122 
0123 void IdleLauncher::idleCommandCompleted()
0124 {
0125     // FIXME: these asseerts could be triggered by a rogue server...
0126     if (m_idling) {
0127         task->log(QStringLiteral("Warning: IDLE completed before we could ask for its termination..."), Common::LOG_MAILBOX_SYNC);
0128         m_idling = false;
0129         renewal->stop();
0130         task->parser->idleMagicallyTerminatedByServer();
0131     }
0132     Q_ASSERT(m_idleCommandRunning);
0133     m_idleCommandRunning = false;
0134 }
0135 
0136 void IdleLauncher::idleCommandFailed()
0137 {
0138     // FIXME: these asseerts could be triggered by a rogue server...
0139     Q_ASSERT(m_idling);
0140     Q_ASSERT(m_idleCommandRunning);
0141     renewal->stop();
0142     m_idleCommandRunning = false;
0143     task->parser->idleContinuationWontCome();
0144     die();
0145 }
0146 
0147 }
0148 }