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 "ImapAccess.h"
24 #include <QDir>
25 #include <QFileInfo>
26 #include <QSslKey>
27 #include <QSettings>
28 #include "Common/MetaTypes.h"
29 #include "Common/Paths.h"
30 #include "Common/PortNumbers.h"
31 #include "Common/SettingsNames.h"
32 #include "Imap/Model/CombinedCache.h"
33 #include "Imap/Model/DummyNetworkWatcher.h"
34 #include "Imap/Model/MailboxModel.h"
35 #include "Imap/Model/MemoryCache.h"
36 #include "Imap/Model/Model.h"
37 #include "Imap/Model/MsgListModel.h"
38 #include "Imap/Model/NetworkWatcher.h"
39 #include "Imap/Model/OneMessageModel.h"
40 #include "Imap/Model/SubtreeModel.h"
41 #include "Imap/Model/SystemNetworkWatcher.h"
42 #include "Imap/Model/ThreadingMsgListModel.h"
43 #include "Imap/Model/Utils.h"
44 #include "Imap/Model/VisibleTasksModel.h"
45 #include "Imap/Network/MsgPartNetAccessManager.h"
46 #include "Streams/SocketFactory.h"
47 #include "UiUtils/PasswordWatcher.h"
48 
49 namespace Imap {
50 
ImapAccess(QObject * parent,QSettings * settings,Plugins::PluginManager * pluginManager,const QString & accountName)51 ImapAccess::ImapAccess(QObject *parent, QSettings *settings, Plugins::PluginManager *pluginManager, const QString &accountName) :
52     QObject(parent), m_settings(settings), m_imapModel(0), m_mailboxModel(0), m_mailboxSubtreeModel(0), m_msgListModel(0),
53     m_threadingMsgListModel(0), m_visibleTasksModel(0), m_oneMessageModel(0), m_netWatcher(0), m_msgQNAM(0),
54     m_pluginManager(pluginManager), m_passwordWatcher(0), m_port(0),
55     m_connectionMethod(Common::ConnectionMethod::Invalid),
56     m_sslInfoIcon(UiUtils::Formatting::IconType::NoIcon),
57     m_accountName(accountName)
58 {
59     Imap::migrateSettings(m_settings);
60     reloadConfiguration();
61     m_cacheDir = Common::writablePath(Common::LOCATION_CACHE) + m_accountName + QLatin1Char('/');;
62     m_passwordWatcher = new UiUtils::PasswordWatcher(this, m_pluginManager,
63                                                      // FIXME: this can be removed when support for multiple accounts is implemented
64                                                      accountName.isEmpty() ? QStringLiteral("account-0") : accountName,
65                                                      QStringLiteral("imap"));
66 }
67 
reloadConfiguration()68 void ImapAccess::reloadConfiguration()
69 {
70     m_server = m_settings->value(Common::SettingsNames::imapHostKey).toString();
71     m_username = m_settings->value(Common::SettingsNames::imapUserKey).toString();
72     if (m_settings->value(Common::SettingsNames::imapMethodKey).toString() == Common::SettingsNames::methodSSL) {
73         m_connectionMethod = Common::ConnectionMethod::NetDedicatedTls;
74     } else if (m_settings->value(Common::SettingsNames::imapMethodKey).toString() == Common::SettingsNames::methodTCP) {
75         m_connectionMethod = m_settings->value(Common::SettingsNames::imapStartTlsKey).toBool() ?
76                     Common::ConnectionMethod::NetStartTls : Common::ConnectionMethod::NetCleartext;
77     } else if (m_settings->value(Common::SettingsNames::imapMethodKey).toString() == Common::SettingsNames::methodProcess) {
78         m_connectionMethod = Common::ConnectionMethod::Process;
79     }
80     m_port = m_settings->value(Common::SettingsNames::imapPortKey, QVariant(0)).toInt();
81     if (!m_port) {
82         switch (m_connectionMethod) {
83         case Common::ConnectionMethod::NetCleartext:
84         case Common::ConnectionMethod::NetStartTls:
85             m_port = Common::PORT_IMAP;
86             break;
87         case Common::ConnectionMethod::NetDedicatedTls:
88             m_port = Common::PORT_IMAPS;
89             break;
90         case Common::ConnectionMethod::Process:
91         case Common::ConnectionMethod::Invalid:
92             // do nothing
93             break;
94         }
95     }
96 }
97 
alertReceived(const QString & message)98 void ImapAccess::alertReceived(const QString &message)
99 {
100     qDebug() << "alertReceived" << message;
101 }
102 
imapError(const QString & message)103 void ImapAccess::imapError(const QString &message)
104 {
105     qDebug() << "imapError" << message;
106 }
107 
networkError(const QString & message)108 void ImapAccess::networkError(const QString &message)
109 {
110     qDebug() << "networkError" << message;
111 }
112 
slotLogged(uint parserId,const Common::LogMessage & message)113 void ImapAccess::slotLogged(uint parserId, const Common::LogMessage &message)
114 {
115     if (message.kind != Common::LOG_IO_READ) {
116         qDebug() << "LOG" << parserId << message.timestamp << message.kind << message.source << message.message;
117     }
118 }
119 
server() const120 QString ImapAccess::server() const
121 {
122     return m_server;
123 }
124 
setServer(const QString & server)125 void ImapAccess::setServer(const QString &server)
126 {
127     m_server = server;
128     m_settings->setValue(Common::SettingsNames::imapHostKey, m_server);
129     emit serverChanged();
130 }
131 
username() const132 QString ImapAccess::username() const
133 {
134     return m_username;
135 }
136 
setUsername(const QString & username)137 void ImapAccess::setUsername(const QString &username)
138 {
139     m_username = username;
140     m_settings->setValue(Common::SettingsNames::imapUserKey, m_username);
141     emit usernameChanged();;
142 }
143 
password() const144 QString ImapAccess::password() const
145 {
146     return m_password;
147 }
148 
setPassword(const QString & password)149 void ImapAccess::setPassword(const QString &password)
150 {
151     m_password = password;
152 }
153 
port() const154 int ImapAccess::port() const
155 {
156     return m_port;
157 }
158 
setPort(const int port)159 void ImapAccess::setPort(const int port)
160 {
161     m_port = port;
162     m_settings->setValue(Common::SettingsNames::imapPortKey, m_port);
163     emit portChanged();
164 }
165 
sslMode() const166 QString ImapAccess::sslMode() const
167 {
168     switch (m_connectionMethod) {
169     case Common::ConnectionMethod::NetCleartext:
170         return QStringLiteral("No");
171     case Common::ConnectionMethod::NetStartTls:
172         return QStringLiteral("StartTLS");
173     case Common::ConnectionMethod::NetDedicatedTls:
174         return QStringLiteral("SSL");
175     case Common::ConnectionMethod::Invalid:
176     case Common::ConnectionMethod::Process:
177         return QString();
178     }
179 
180     Q_ASSERT(false);
181     return QString();
182 }
183 
setSslMode(const QString & sslMode)184 void ImapAccess::setSslMode(const QString &sslMode)
185 {
186     if (sslMode == QLatin1String("No")) {
187         setConnectionMethod(Common::ConnectionMethod::NetCleartext);
188     } else if (sslMode == QLatin1String("SSL")) {
189         setConnectionMethod(Common::ConnectionMethod::NetDedicatedTls);
190     } else if (sslMode == QLatin1String("StartTLS")) {
191         setConnectionMethod(Common::ConnectionMethod::NetStartTls);
192     } else {
193         Q_ASSERT(false);
194     }
195 }
196 
connectionMethod() const197 Common::ConnectionMethod ImapAccess::connectionMethod() const
198 {
199     return m_connectionMethod;
200 }
201 
setConnectionMethod(const Common::ConnectionMethod mode)202 void ImapAccess::setConnectionMethod(const Common::ConnectionMethod mode)
203 {
204     m_connectionMethod = mode;
205     switch (m_connectionMethod) {
206     case Common::ConnectionMethod::Invalid:
207         break;
208     case Common::ConnectionMethod::NetCleartext:
209     case Common::ConnectionMethod::NetStartTls:
210         m_settings->setValue(Common::SettingsNames::imapMethodKey, Common::SettingsNames::methodTCP);
211         m_settings->setValue(Common::SettingsNames::imapStartTlsKey, m_connectionMethod == Common::ConnectionMethod::NetStartTls);
212         break;
213     case Common::ConnectionMethod::NetDedicatedTls:
214         m_settings->setValue(Common::SettingsNames::imapMethodKey, Common::SettingsNames::methodSSL);
215         // Trying to communicate the fact that this is going to be an encrypted connection, even though
216         // that settings bit is not actually used
217         m_settings->setValue(Common::SettingsNames::imapStartTlsKey, true);
218         break;
219     case Common::ConnectionMethod::Process:
220         m_settings->setValue(Common::SettingsNames::imapMethodKey, Common::SettingsNames::methodProcess);
221         break;
222     }
223     emit connMethodChanged();
224 }
225 
preferredNetworkPolicy() const226 Imap::Mailbox::NetworkPolicy ImapAccess::preferredNetworkPolicy() const
227 {
228     auto val = m_settings->value(Common::SettingsNames::imapStartMode).toString();
229     if (val == Common::SettingsNames::netOffline) {
230         return Imap::Mailbox::NETWORK_OFFLINE;
231     } else if (val == Common::SettingsNames::netExpensive) {
232         return Imap::Mailbox::NETWORK_EXPENSIVE;
233     } else {
234         return Imap::Mailbox::NETWORK_ONLINE;
235     }
236 }
237 
doConnect()238 void ImapAccess::doConnect()
239 {
240     if (m_netWatcher) {
241         // We're temporarily "disabling" this connection. Otherwise this "offline preference"
242         // would get saved into the config file, which would be bad.
243         disconnect(m_netWatcher, &Mailbox::NetworkWatcher::desiredNetworkPolicyChanged, this, &ImapAccess::desiredNetworkPolicyChanged);
244     }
245 
246     if (m_imapModel) {
247         // Disconnect from network, nuke the models
248         Q_ASSERT(m_netWatcher);
249         m_netWatcher->setNetworkOffline();
250         delete m_threadingMsgListModel;
251         m_threadingMsgListModel = 0;
252         delete m_msgQNAM;
253         m_msgQNAM = 0;
254         delete m_oneMessageModel;
255         m_oneMessageModel = 0;
256         delete m_visibleTasksModel;
257         m_visibleTasksModel = 0;
258         delete m_msgListModel;
259         m_msgListModel = 0;
260         delete m_mailboxSubtreeModel;
261         m_mailboxSubtreeModel = 0;
262         delete m_mailboxModel;
263         m_mailboxModel = 0;
264         delete m_netWatcher;
265         m_netWatcher = 0;
266         delete m_imapModel;
267         m_imapModel = 0;
268     }
269 
270     Q_ASSERT(!m_imapModel);
271 
272     Imap::Mailbox::SocketFactoryPtr factory;
273     Imap::Mailbox::TaskFactoryPtr taskFactory(new Imap::Mailbox::TaskFactory());
274 
275     Streams::ProxySettings proxySettings = m_settings->value(Common::SettingsNames::imapUseSystemProxy, true).toBool() ?
276                 Streams::ProxySettings::RespectSystemProxy : Streams::ProxySettings::DirectConnect;
277 
278     switch (m_connectionMethod) {
279     case Common::ConnectionMethod::Invalid:
280         factory.reset(new Streams::FakeSocketFactory(Imap::CONN_STATE_LOGOUT));
281         break;
282     case Common::ConnectionMethod::NetCleartext:
283     case Common::ConnectionMethod::NetStartTls:
284         factory.reset(new Streams::TlsAbleSocketFactory(server(), port()));
285         factory->setStartTlsRequired(m_connectionMethod == Common::ConnectionMethod::NetStartTls);
286         factory->setProxySettings(proxySettings, QStringLiteral("imap"));
287         break;
288     case Common::ConnectionMethod::NetDedicatedTls:
289         factory.reset(new Streams::SslSocketFactory(server(), port()));
290         factory->setProxySettings(proxySettings, QStringLiteral("imap"));
291         break;
292     case Common::ConnectionMethod::Process:
293         QStringList args = m_settings->value(Common::SettingsNames::imapProcessKey).toString().split(QLatin1Char(' '));
294         if (args.isEmpty()) {
295             // it's going to fail anyway
296             args << QLatin1String("");
297         }
298         QString appName = args.takeFirst();
299         factory.reset(new Streams::ProcessSocketFactory(appName, args));
300         break;
301     }
302 
303     bool shouldUsePersistentCache =
304             m_settings->value(Common::SettingsNames::cacheOfflineKey).toString() != Common::SettingsNames::cacheOfflineNone;
305 
306     if (shouldUsePersistentCache && !QDir().mkpath(m_cacheDir)) {
307         onCacheError(tr("Failed to create directory %1").arg(m_cacheDir));
308         shouldUsePersistentCache = false;
309     }
310 
311     if (shouldUsePersistentCache) {
312         QFile::Permissions expectedPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
313         if (QFileInfo(m_cacheDir).permissions() != expectedPerms) {
314             if (!QFile::setPermissions(m_cacheDir, expectedPerms)) {
315 #ifndef Q_OS_WIN32
316                 onCacheError(tr("Failed to set safe permissions on cache directory %1").arg(m_cacheDir));
317                 shouldUsePersistentCache = false;
318 #endif
319             }
320         }
321     }
322 
323     Imap::Mailbox::AbstractCache *cache = 0;
324 
325     if (!shouldUsePersistentCache) {
326         cache = new Imap::Mailbox::MemoryCache(this);
327     } else {
328         cache = new Imap::Mailbox::CombinedCache(this, QStringLiteral("trojita-imap-cache"), m_cacheDir);
329         connect(cache, &Mailbox::AbstractCache::error, this, &ImapAccess::onCacheError);
330         if (! static_cast<Imap::Mailbox::CombinedCache *>(cache)->open()) {
331             // Error message was already shown by the cacheError() slot
332             cache->deleteLater();
333             cache = new Imap::Mailbox::MemoryCache(this);
334         } else {
335             if (m_settings->value(Common::SettingsNames::cacheOfflineKey).toString() == Common::SettingsNames::cacheOfflineAll) {
336                 cache->setRenewalThreshold(0);
337             } else {
338                 const int defaultCacheLifetime = 30;
339                 bool ok;
340                 int num = m_settings->value(Common::SettingsNames::cacheOfflineNumberDaysKey, defaultCacheLifetime).toInt(&ok);
341                 if (!ok)
342                     num = defaultCacheLifetime;
343                 cache->setRenewalThreshold(num);
344             }
345         }
346     }
347 
348     m_imapModel = new Imap::Mailbox::Model(this, cache, std::move(factory), std::move(taskFactory));
349     m_imapModel->setObjectName(QStringLiteral("imapModel-%1").arg(m_accountName));
350     m_imapModel->setCapabilitiesBlacklist(m_settings->value(Common::SettingsNames::imapBlacklistedCapabilities).toStringList());
351     m_imapModel->setProperty("trojita-imap-id-no-versions", !m_settings->value(Common::SettingsNames::interopRevealVersions, true).toBool());
352     m_imapModel->setProperty("trojita-imap-idle-renewal", m_settings->value(Common::SettingsNames::imapIdleRenewal).toUInt() * 60 * 1000);
353     m_imapModel->setNumberRefreshInterval(numberRefreshInterval());
354     connect(m_imapModel, &Mailbox::Model::alertReceived, this, &ImapAccess::alertReceived);
355     connect(m_imapModel, &Mailbox::Model::imapError, this, &ImapAccess::imapError);
356     connect(m_imapModel, &Mailbox::Model::networkError, this, &ImapAccess::networkError);
357     //connect(m_imapModel, &Mailbox::Model::logged, this, &ImapAccess::slotLogged);
358     connect(m_imapModel, &Mailbox::Model::needsSslDecision, this, &ImapAccess::slotSslErrors);
359     connect(m_imapModel, &Mailbox::Model::requireStartTlsInFuture, this, &ImapAccess::onRequireStartTlsInFuture);
360 
361     if (m_settings->value(Common::SettingsNames::imapNeedsNetwork, true).toBool()) {
362         m_netWatcher = new Imap::Mailbox::SystemNetworkWatcher(this, m_imapModel);
363     } else {
364         m_netWatcher = new Imap::Mailbox::DummyNetworkWatcher(this, m_imapModel);
365     }
366     connect(m_netWatcher, &Mailbox::NetworkWatcher::desiredNetworkPolicyChanged, this, &ImapAccess::desiredNetworkPolicyChanged);
367     switch (preferredNetworkPolicy()) {
368     case Imap::Mailbox::NETWORK_OFFLINE:
369         QMetaObject::invokeMethod(m_netWatcher, "setNetworkOffline", Qt::QueuedConnection);
370         break;
371     case Imap::Mailbox::NETWORK_EXPENSIVE:
372         QMetaObject::invokeMethod(m_netWatcher, "setNetworkExpensive", Qt::QueuedConnection);
373         break;
374     case Imap::Mailbox::NETWORK_ONLINE:
375         QMetaObject::invokeMethod(m_netWatcher, "setNetworkOnline", Qt::QueuedConnection);
376         break;
377     }
378 
379     m_imapModel->setImapUser(username());
380     if (!m_password.isNull()) {
381         // Really; the idea is to wait before it has been set for the first time
382         m_imapModel->setImapPassword(password());
383     }
384 
385     m_mailboxModel = new Imap::Mailbox::MailboxModel(this, m_imapModel);
386     m_mailboxModel->setObjectName(QStringLiteral("mailboxModel-%1").arg(m_accountName));
387     m_mailboxSubtreeModel = new Imap::Mailbox::SubtreeModelOfMailboxModel(this);
388     m_mailboxSubtreeModel->setObjectName(QStringLiteral("mailboxSubtreeModel-%1").arg(m_accountName));
389     m_mailboxSubtreeModel->setSourceModel(m_mailboxModel);
390     m_mailboxSubtreeModel->setOriginalRoot();
391     m_msgListModel = new Imap::Mailbox::MsgListModel(this, m_imapModel);
392     m_msgListModel->setObjectName(QStringLiteral("msgListModel-%1").arg(m_accountName));
393     m_visibleTasksModel = new Imap::Mailbox::VisibleTasksModel(this, m_imapModel->taskModel());
394     m_visibleTasksModel->setObjectName(QStringLiteral("visibleTasksModel-%1").arg(m_accountName));
395     m_oneMessageModel = new Imap::Mailbox::OneMessageModel(m_imapModel);
396     m_oneMessageModel->setObjectName(QStringLiteral("oneMessageModel-%1").arg(m_accountName));
397     m_msgQNAM = new Imap::Network::MsgPartNetAccessManager(this);
398     m_msgQNAM->setObjectName(QStringLiteral("m_msgQNAM-%1").arg(m_accountName));
399     m_threadingMsgListModel = new Imap::Mailbox::ThreadingMsgListModel(this);
400     m_threadingMsgListModel->setObjectName(QStringLiteral("threadingMsgListModel-%1").arg(m_accountName));
401     m_threadingMsgListModel->setSourceModel(m_msgListModel);
402     emit modelsChanged();
403 }
404 
onCacheError(const QString & message)405 void ImapAccess::onCacheError(const QString &message)
406 {
407     if (m_imapModel) {
408         m_imapModel->setCache(new Imap::Mailbox::MemoryCache(m_imapModel));
409     }
410     emit cacheError(message);
411 }
412 
imapModel() const413 QAbstractItemModel *ImapAccess::imapModel() const
414 {
415     return m_imapModel;
416 }
417 
mailboxModel() const418 QAbstractItemModel *ImapAccess::mailboxModel() const
419 {
420     return m_mailboxSubtreeModel;
421 }
422 
msgListModel() const423 QAbstractItemModel *ImapAccess::msgListModel() const
424 {
425     return m_msgListModel;
426 }
427 
visibleTasksModel() const428 QAbstractItemModel *ImapAccess::visibleTasksModel() const
429 {
430     return m_visibleTasksModel;
431 }
432 
oneMessageModel() const433 QObject *ImapAccess::oneMessageModel() const
434 {
435     return m_oneMessageModel;
436 }
437 
networkWatcher() const438 QObject *ImapAccess::networkWatcher() const
439 {
440     return m_netWatcher;
441 }
442 
msgQNAM() const443 QObject *ImapAccess::msgQNAM() const
444 {
445     return m_msgQNAM;
446 }
447 
threadingMsgListModel() const448 QAbstractItemModel *ImapAccess::threadingMsgListModel() const
449 {
450     return m_threadingMsgListModel;
451 }
452 
passwordWatcher() const453 UiUtils::PasswordWatcher *ImapAccess::passwordWatcher() const
454 {
455     return m_passwordWatcher;
456 }
457 
openMessage(const QString & mailboxName,const uint uid)458 void ImapAccess::openMessage(const QString &mailboxName, const uint uid)
459 {
460     QModelIndex msgIndex = m_imapModel->messageIndexByUid(mailboxName, uid);
461     m_oneMessageModel->setMessage(msgIndex);
462     static_cast<Imap::Network::MsgPartNetAccessManager*>(m_msgQNAM)->setModelMessage(msgIndex);
463 }
464 
slotSslErrors(const QList<QSslCertificate> & sslCertificateChain,const QList<QSslError> & sslErrors)465 void ImapAccess::slotSslErrors(const QList<QSslCertificate> &sslCertificateChain, const QList<QSslError> &sslErrors)
466 {
467     m_sslChain = sslCertificateChain;
468     m_sslErrors = sslErrors;
469 
470     QByteArray lastKnownPubKey = m_settings->value(Common::SettingsNames::imapSslPemPubKey).toByteArray();
471     if (!m_sslChain.isEmpty() && !lastKnownPubKey.isEmpty() && lastKnownPubKey == m_sslChain[0].publicKey().toPem()) {
472         // This certificate chain contains the same public keys as the last time; we should accept that
473         m_imapModel->setSslPolicy(m_sslChain, m_sslErrors, true);
474     } else {
475         UiUtils::Formatting::formatSslState(
476                     m_sslChain, lastKnownPubKey, m_sslErrors, &m_sslInfoTitle, &m_sslInfoMessage, &m_sslInfoIcon);
477         emit checkSslPolicy();
478     }
479 }
480 
481 /** @short Remember to use STARTTLS during the next connection
482 
483 Once a first STARTTLS attempt succeeds, change the preferences to require STARTTLS in future. This is needed
484 to prevent a possible SSL stripping attack by a malicious proxy during subsequent connections.
485 */
onRequireStartTlsInFuture()486 void ImapAccess::onRequireStartTlsInFuture()
487 {
488     // It's possible that we're called after the user has already changed their preferences.
489     // In order to not change stuff which was not supposed to be changed, let's make sure that we won't undo their changes.
490     if (connectionMethod() == Common::ConnectionMethod::NetCleartext) {
491         setConnectionMethod(Common::ConnectionMethod::NetStartTls);
492     }
493 }
494 
desiredNetworkPolicyChanged(const Mailbox::NetworkPolicy policy)495 void ImapAccess::desiredNetworkPolicyChanged(const Mailbox::NetworkPolicy policy)
496 {
497     switch (policy) {
498     case Mailbox::NETWORK_OFFLINE:
499         m_settings->setValue(Common::SettingsNames::imapStartMode, Common::SettingsNames::netOffline);
500         break;
501     case Mailbox::NETWORK_EXPENSIVE:
502         m_settings->setValue(Common::SettingsNames::imapStartMode, Common::SettingsNames::netExpensive);
503         break;
504     case Mailbox::NETWORK_ONLINE:
505         m_settings->setValue(Common::SettingsNames::imapStartMode, Common::SettingsNames::netOnline);
506         break;
507     }
508 }
509 
setSslPolicy(bool accept)510 void ImapAccess::setSslPolicy(bool accept)
511 {
512     if (accept && !m_sslChain.isEmpty()) {
513         m_settings->setValue(Common::SettingsNames::imapSslPemPubKey, m_sslChain[0].publicKey().toPem());
514     }
515     m_imapModel->setSslPolicy(m_sslChain, m_sslErrors, accept);
516 }
517 
forgetSslCertificate()518 void ImapAccess::forgetSslCertificate()
519 {
520     m_settings->remove(Common::SettingsNames::imapSslPemPubKey);
521 }
522 
sslInfoTitle() const523 QString ImapAccess::sslInfoTitle() const
524 {
525     return m_sslInfoTitle;
526 }
527 
sslInfoMessage() const528 QString ImapAccess::sslInfoMessage() const
529 {
530     return m_sslInfoMessage;
531 }
532 
sslInfoIcon() const533 UiUtils::Formatting::IconType ImapAccess::sslInfoIcon() const
534 {
535     return m_sslInfoIcon;
536 }
537 
mailboxListMailboxName() const538 QString ImapAccess::mailboxListMailboxName() const
539 {
540     return m_mailboxSubtreeModel->rootIndex().data(Imap::Mailbox::RoleMailboxName).toString();
541 }
542 
mailboxListShortMailboxName() const543 QString ImapAccess::mailboxListShortMailboxName() const
544 {
545     return m_mailboxSubtreeModel->rootIndex().data(Imap::Mailbox::RoleShortMailboxName).toString();
546 }
547 
548 /** @short Persistently remove the local cache of IMAP data
549 
550 This method should be called by the UI when the user changes its connection details, i.e. when there's a big chance that we are
551 connecting to a completely different server since the last time.
552 */
nukeCache()553 void ImapAccess::nukeCache()
554 {
555     Imap::removeRecursively(m_cacheDir);
556 }
557 
deproxifiedIndex(const QModelIndex index)558 QModelIndex ImapAccess::deproxifiedIndex(const QModelIndex index)
559 {
560     return Imap::deproxifiedIndex(index);
561 }
562 
markMessageDeleted(const QModelIndex & message,bool marked)563 void ImapAccess::markMessageDeleted(const QModelIndex &message, bool marked)
564 {
565     Q_ASSERT(message.isValid());
566     m_imapModel->markMessagesDeleted(QModelIndexList() << message, marked ? Imap::Mailbox::FLAG_ADD : Imap::Mailbox::FLAG_REMOVE);
567 }
568 
numberRefreshInterval() const569 int ImapAccess::numberRefreshInterval() const
570 {
571     int interval = m_settings->value(Common::SettingsNames::imapNumberRefreshInterval, QVariant(300)).toInt();
572     if (interval < 30)
573         interval = 30;
574     else if (interval > 29*60)
575         interval = 29*60;
576     return interval;
577 }
578 
setNumberRefreshInterval(const int interval)579 void ImapAccess::setNumberRefreshInterval(const int interval)
580 {
581     m_settings->setValue(Common::SettingsNames::imapNumberRefreshInterval, interval);
582     if (m_imapModel)
583         m_imapModel->setNumberRefreshInterval(interval);
584 }
585 
accountName() const586 QString ImapAccess::accountName() const
587 {
588     return m_accountName;
589 }
590 
isConfigured() const591 bool ImapAccess::isConfigured() const
592 {
593     return m_settings->contains(Common::SettingsNames::imapMethodKey);
594 }
595 
596 }
597