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 #include <QTimer>
24 #include "IdleLauncher.h"
25 #include "Imap/Model/Model.h"
26 #include "KeepMailboxOpenTask.h"
27
28 namespace Imap
29 {
30 namespace Mailbox
31 {
32
IdleLauncher(KeepMailboxOpenTask * parent)33 IdleLauncher::IdleLauncher(KeepMailboxOpenTask *parent):
34 QObject(parent), task(parent), m_idling(false), m_idleCommandRunning(false)
35 {
36 delayedEnter = new QTimer(this);
37 delayedEnter->setObjectName(QStringLiteral("%1-IdleLauncher-delayedEnter").arg(task->objectName()));
38 delayedEnter->setSingleShot(true);
39 // It's a question about what timeout to set here -- if it's too long, we enter IDLE too soon, before the
40 // user has a chance to click on a message, but if we set it too long, we needlessly wait too long between
41 // we receive updates, and also between terminating one IDLE and starting another.
42 // 6 seconds is a compromise here.
43 bool ok;
44 int timeout = parent->model->property("trojita-imap-idle-delayedEnter").toUInt(&ok);
45 if (! ok)
46 timeout = 6 * 1000;
47 delayedEnter->setInterval(timeout);
48 connect(delayedEnter, &QTimer::timeout, this, &IdleLauncher::slotEnterIdleNow);
49 renewal = new QTimer(this);
50 renewal->setObjectName(QStringLiteral("%1-IdleLauncher-renewal").arg(task->objectName()));
51 renewal->setSingleShot(true);
52 timeout = parent->model->property("trojita-imap-idle-renewal").toUInt(&ok);
53 if (! ok)
54 timeout = 1000 * 29 * 60; // 29 minutes -- that's the longest allowed time to IDLE
55 renewal->setInterval(timeout);
56 connect(renewal, &QTimer::timeout, this, &IdleLauncher::slotTerminateLongIdle);
57 }
58
slotEnterIdleNow()59 void IdleLauncher::slotEnterIdleNow()
60 {
61 delayedEnter->stop();
62 renewal->stop();
63
64 if (m_idleCommandRunning) {
65 enterIdleLater();
66 return;
67 }
68
69 Q_ASSERT(task->parser);
70 Q_ASSERT(! m_idling);
71 Q_ASSERT(! m_idleCommandRunning);
72 Q_ASSERT(task->tagIdle.isEmpty());
73 task->tagIdle = task->parser->idle();
74 renewal->start();
75 m_idling = true;
76 m_idleCommandRunning = true;
77 }
78
finishIdle()79 void IdleLauncher::finishIdle()
80 {
81 Q_ASSERT(task->parser);
82 if (m_idling) {
83 renewal->stop();
84 task->parser->idleDone();
85 m_idling = false;
86 } else if (delayedEnter->isActive()) {
87 delayedEnter->stop();
88 }
89 }
90
slotTerminateLongIdle()91 void IdleLauncher::slotTerminateLongIdle()
92 {
93 if (m_idling)
94 finishIdle();
95 }
96
enterIdleLater()97 void IdleLauncher::enterIdleLater()
98 {
99 if (m_idling)
100 return;
101
102 delayedEnter->start();
103 }
104
die()105 void IdleLauncher::die()
106 {
107 delayedEnter->stop();
108 delayedEnter->disconnect();
109 renewal->stop();
110 renewal->disconnect();
111 }
112
idling() const113 bool IdleLauncher::idling() const
114 {
115 return m_idling;
116 }
117
waitingForIdleTaggedTermination() const118 bool IdleLauncher::waitingForIdleTaggedTermination() const
119 {
120 return m_idleCommandRunning;
121 }
122
idleCommandCompleted()123 void IdleLauncher::idleCommandCompleted()
124 {
125 // FIXME: these asseerts could be triggered by a rogue server...
126 if (m_idling) {
127 task->log(QStringLiteral("Warning: IDLE completed before we could ask for its termination..."), Common::LOG_MAILBOX_SYNC);
128 m_idling = false;
129 renewal->stop();
130 task->parser->idleMagicallyTerminatedByServer();
131 }
132 Q_ASSERT(m_idleCommandRunning);
133 m_idleCommandRunning = false;
134 }
135
idleCommandFailed()136 void IdleLauncher::idleCommandFailed()
137 {
138 // FIXME: these asseerts could be triggered by a rogue server...
139 Q_ASSERT(m_idling);
140 Q_ASSERT(m_idleCommandRunning);
141 renewal->stop();
142 m_idleCommandRunning = false;
143 task->parser->idleContinuationWontCome();
144 die();
145 }
146
147 }
148 }
149