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 //#define TROJITA_DEBUG_TASK_TREE
24 
25 #ifndef IMAP_MODEL_H
26 #define IMAP_MODEL_H
27 
28 #include <QAbstractItemModel>
29 #include <QPointer>
30 #include <QTimer>
31 #include "Cache.h"
32 #include "../ConnectionState.h"
33 #include "../Parser/Parser.h"
34 #include "CacheLoadingMode.h"
35 #include "CopyMoveOperation.h"
36 #include "FlagsOperation.h"
37 #include "NetworkPolicy.h"
38 #include "ParserState.h"
39 #include "TaskFactory.h"
40 
41 #include "Common/Logging.h"
42 
43 class QAuthenticator;
44 class QNetworkSession;
45 class QSslError;
46 
47 class FakeCapabilitiesInjector;
48 class ImapModelIdleTest;
49 class LibMailboxSync;
50 
51 namespace Composer {
52 class ImapMessageAttachmentItem;
53 class ImapPartAttachmentItem;
54 class MessageComposer;
55 }
56 
57 namespace Streams {
58 class SocketFactory;
59 }
60 
61 /** @short Namespace for IMAP interaction */
62 namespace Imap
63 {
64 
65 /** @short Classes for handling of mailboxes and connections */
66 namespace Mailbox
67 {
68 
69 class TreeItem;
70 class TreeItemMailbox;
71 class TreeItemMsgList;
72 class TreeItemMessage;
73 class TreeItemPart;
74 class MsgListModel;
75 class MailboxModel;
76 class DummyNetworkWatcher;
77 class SystemNetworkWatcher;
78 
79 class ImapTask;
80 class KeepMailboxOpenTask;
81 class TaskPresentationModel;
82 template <typename SourceModel> class SubtreeClassSpecificItem;
83 typedef std::unique_ptr<Streams::SocketFactory> SocketFactoryPtr;
84 
85 /** @short Progress of mailbox synchronization with the IMAP server */
86 typedef enum { STATE_WAIT_FOR_CONN, /**< Waiting for connection to become active */
87                STATE_SELECTING, /**< SELECT command in progress */
88                STATE_SYNCING_UIDS, /**< UID syncing in progress */
89                STATE_SYNCING_FLAGS, /**< Flag syncing in progress */
90                STATE_DONE /**< Mailbox is fully synchronized, both UIDs and flags are up to date */
91              } MailboxSyncingProgress;
92 
93 /** @short A model implementing view of the whole IMAP server */
94 class Model: public QAbstractItemModel
95 {
96     Q_OBJECT
97 
98     Q_PROPERTY(QString imapUser READ imapUser WRITE setImapUser)
99     Q_PROPERTY(QString imapPassword READ imapPassword WRITE setImapPassword RESET unsetImapPassword)
100     Q_PROPERTY(QString imapAuthError READ imapAuthError NOTIFY imapAuthErrorChanged)
101     Q_PROPERTY(bool isNetworkAvailable READ isNetworkAvailable NOTIFY networkPolicyChanged)
102     Q_PROPERTY(bool isNetworkOnline READ isNetworkOnline NOTIFY networkPolicyChanged)
103 
104     /** @short How to open a mailbox */
105     enum RWMode {
106         ReadOnly /**< @short Use EXAMINE or leave it in SELECTed mode*/,
107         ReadWrite /**< @short Invoke SELECT if necessarry */
108     };
109 
110     mutable AbstractCache *m_cache;
111     mutable SocketFactoryPtr m_socketFactory;
112     TaskFactoryPtr m_taskFactory;
113     mutable QMap<Parser *,ParserState> m_parsers;
114     int m_maxParsers;
115     mutable TreeItemMailbox *m_mailboxes;
116     mutable NetworkPolicy m_netPolicy;
117     bool m_startTls;
118 
119     mutable QList<Imap::Responses::NamespaceData> m_personalNamespace, m_otherUsersNamespace, m_sharedNamespace;
120 
121     QList<QPair<QPair<QList<QSslCertificate>, QList<QSslError> >, bool> > m_sslErrorPolicy;
122 
123 
124 public:
125     Model(QObject *parent, AbstractCache *cache, SocketFactoryPtr m_socketFactory, TaskFactoryPtr m_taskFactory);
126     ~Model();
127 
128     virtual QModelIndex index(int row, int column, const QModelIndex &parent) const;
129     virtual QModelIndex parent(const QModelIndex &index) const;
130     virtual int rowCount(const QModelIndex &index) const;
131     virtual int columnCount(const QModelIndex &index) const;
132     virtual QVariant data(const QModelIndex &index, int role) const;
133     virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
134 
135     void handleState(Imap::Parser *ptr, const Imap::Responses::State *const resp);
136     void handleCapability(Imap::Parser *ptr, const Imap::Responses::Capability *const resp);
137     void handleNumberResponse(Imap::Parser *ptr, const Imap::Responses::NumberResponse *const resp);
138     void handleList(Imap::Parser *ptr, const Imap::Responses::List *const resp);
139     void handleFlags(Imap::Parser *ptr, const Imap::Responses::Flags *const resp);
140     void handleSearch(Imap::Parser *ptr, const Imap::Responses::Search *const resp);
141     void handleESearch(Imap::Parser *ptr, const Imap::Responses::ESearch *const resp);
142     void handleStatus(Imap::Parser *ptr, const Imap::Responses::Status *const resp);
143     void handleFetch(Imap::Parser *ptr, const Imap::Responses::Fetch *const resp);
144     void handleNamespace(Imap::Parser *ptr, const Imap::Responses::Namespace *const resp);
145     void handleSort(Imap::Parser *ptr, const Imap::Responses::Sort *const resp);
146     void handleThread(Imap::Parser *ptr, const Imap::Responses::Thread *const resp);
147     void handleId(Imap::Parser *ptr, const Imap::Responses::Id *const resp);
148     void handleEnabled(Imap::Parser *ptr, const Imap::Responses::Enabled *const resp);
149     void handleVanished(Imap::Parser *ptr, const Imap::Responses::Vanished *const resp);
150     void handleGenUrlAuth(Imap::Parser *ptr, const Imap::Responses::GenUrlAuth *const resp);
151     void handleSocketEncryptedResponse(Imap::Parser *ptr, const Imap::Responses::SocketEncryptedResponse *const resp);
152     void handleSocketDisconnectedResponse(Imap::Parser *ptr, const Imap::Responses::SocketDisconnectedResponse *const resp);
153     void handleParseErrorResponse(Imap::Parser *ptr, const Imap::Responses::ParseErrorResponse *const resp);
154 
cache()155     AbstractCache *cache() const { return m_cache; }
156     /** Throw away current cache implementation, replace it with the new one
157 
158     The old cache is automatically deleted.
159     */
160     void setCache(AbstractCache *cache);
161 
162     /** @short Force a SELECT / EXAMINE of a mailbox
163 
164     This command sends a SELECT or EXAMINE command to the remote server, even if the
165     requested mailbox is currently selected. This has a side effect that we synchronize
166     the list of messages, which is why this function exists in the first place.
167     */
168     void resyncMailbox(const QModelIndex &mbox);
169 
170     /** @short Mark all messages in a given mailbox as read */
171     void markMailboxAsRead(const QModelIndex &mailbox);
172     /** @short Add/Remove a flag for the indicated message */
173     ImapTask *setMessageFlags(const QModelIndexList &messages, const QString flag, const FlagsOperation marked);
174     /** @short Ask the server to set/unset the \\Deleted flag for the indicated messages */
175     void markMessagesDeleted(const QModelIndexList &messages, const FlagsOperation marked);
176     /** @short Ask the server to set/unset the \\Seen flag for the indicated messages */
177     void markMessagesRead(const QModelIndexList &messages, const FlagsOperation marked);
178 
179     /** @short Run the EXPUNGE command in the specified mailbox */
180     void expungeMailbox(const QModelIndex &mailbox);
181 
182     /** @short Copy or move a sequence of messages between two mailboxes */
183     void copyMoveMessages(TreeItemMailbox *sourceMbox, const QString &destMboxName, Imap::Uids uids, const CopyMoveOperation op);
184 
185     /** @short Create a new mailbox */
186     void createMailbox(const QString &name, const AutoSubscription subscription = AutoSubscription::NO_EXPLICIT_SUBSCRIPTION);
187     /** @short Delete an existing mailbox */
188     void deleteMailbox(const QString &name);
189 
190     /** @short Subscribe a mailbox */
191     void subscribeMailbox(const QString &name);
192     /** @short Unsubscribe a mailbox */
193     void unsubscribeMailbox(const QString &name);
194 
195     /** @short Save a message into a mailbox */
196     AppendTask* appendIntoMailbox(const QString &mailbox, const QByteArray &rawMessageData, const QStringList &flags,
197                                   const QDateTime &timestamp);
198 
199     /** @short Save a message into a mailbox using the CATENATE extension */
200     AppendTask* appendIntoMailbox(const QString &mailbox, const QList<CatenatePair> &data, const QStringList &flags,
201                                   const QDateTime &timestamp);
202 
203     /** @short Issue the GENURLAUTH command for a specified part/section */
204     GenUrlAuthTask *generateUrlAuthForMessage(const QString &host, const QString &user, const QString &mailbox,
205                                               const uint uidValidity, const uint uid, const QString &part, const QString &access);
206 
207     /** @short Send a mail through the UID SEND mechanism */
208     UidSubmitTask *sendMailViaUidSubmit(const QString &mailbox, const uint uidValidity, const uint uid,
209                                         const UidSubmitOptionsList &options);
210 
211 
212     /** @short Returns true if we are allowed to access the network */
isNetworkAvailable()213     bool isNetworkAvailable() const { return m_netPolicy != NETWORK_OFFLINE; }
214     /** @short Returns true if the network access is cheap */
isNetworkOnline()215     bool isNetworkOnline() const { return m_netPolicy == NETWORK_ONLINE; }
216 
217     /** @short Return a TreeItem* for a specified index
218 
219     Certain proxy models implement their own indexes. These indexes typically won't
220     share the internalPointer() with the original model.  Because we use this pointer
221     quite often, a method is needed to automatically go through the list of all proxy
222     models and return the appropriate raw pointer.
223 
224     Upon success, a valid pointer is returned, *whichModel is set to point to the
225     corresponding Model instance and *translatedIndex contains the index in the real
226     underlying model. If any of these pointers is NULL, it won't get changed, of course.
227 
228     Upon failure, this function returns 0 and doesn't touch any of @arg whichModel
229     and @arg translatedIndex.
230     */
231     static TreeItem *realTreeItem(QModelIndex index, const Model **whichModel = 0, QModelIndex *translatedIndex = 0);
232 
233     /** @short Inform the model that data for this message won't likely be requested in near future
234 
235     Model will transform the corresponding TreeItemMessage into the state similar to how it would look
236     right after a fresh mailbox synchronization. All TreeItemParts will be freed, envelope and body
237     structure forgotten. This will substantially reduce Model's memory usage.
238 
239     The UID and flags are not affected by this operation. The cache and any data stored in there will
240     also be left intact (and would indeed be consulted instead of the network when future requests for
241     this message happen again.
242 
243     */
244     void releaseMessageData(const QModelIndex &message);
245 
246     /** @short Return a list of capabilities which are supported by the server */
247     QStringList capabilities() const;
248 
249     /** @short Log an IMAP-related message */
250     void logTrace(uint parserId, const Common::LogKind kind, const QString &source, const QString &message);
251     void logTrace(const QModelIndex &relevantIndex, const Common::LogKind kind, const QString &source, const QString &message);
252 
253     /** @short Return the server's response to the ID command
254 
255     When the server indicates that the ID command is available, Trojitá will always send the ID command.  The information sent to
256     the server is controlled by the trojita-imap-id-no-versions property.  By default, Trojitá will tell the truth and proudly
257     present herself under her own name and using detailed version information and OS info. If set, it will just send the Trojita
258     name, but no version info.
259 
260     The command is always sent upon each connection (ie. one protocol session, not the mailbox session).  The result of this
261     function will therefore not make much sense (like be empty) when the model has always been offline.  Each reconnection updates
262     the cached result.  See RFC 2971 for the semantics of the ID command.
263     */
264     QMap<QByteArray,QByteArray> serverId() const;
265 
266     QStringList normalizeFlags(const QStringList &source) const;
267 
268     QString imapUser() const;
269     void setImapUser(const QString &imapUser);
270     QString imapPassword() const;
271     void setImapPassword(const QString &imapPassword);
272     void unsetImapPassword();
273 
274     /** @short Return an index for the message specified by the mailbox name and the message UID */
275     QModelIndex messageIndexByUid(const QString &mailboxName, const uint uid);
276 
277     /** @short Provide a list of capabilities to not use
278 
279     All blacklisted capabilities must be provided in the upper case. Capabilities are filtered only as they are reported by the
280     IMAP server. Calling this function while the connection is already open and kicking might have terrible consequences.
281     */
282     void setCapabilitiesBlacklist(const QStringList &blacklist);
283 
284     bool isCatenateSupported() const;
285     bool isGenUrlAuthSupported() const;
286     bool isImapSubmissionSupported() const;
287 
288     void setNumberRefreshInterval(const int interval);
289 
290 public slots:
291     /** @short Ask for an updated list of mailboxes on the server */
292     void reloadMailboxList();
293 
294     /** @short Try to maintain a connection to the given mailbox
295 
296       This function informs the Model that the user is interested in receiving
297       updates about the mailbox state, such as about the arrival of new messages.
298       The usual response to such a hint is launching the IDLE command.
299     */
300     void switchToMailbox(const QModelIndex &mbox);
301 
302     /** @short Get a pointer to the model visualizing the state of the tasks
303 
304     The returned object still belongs to this Imap::Mailbox::Model, and its internal working is implementation-specific.  The only
305     valid method of access is through the usual Qt Interview framework.
306     */
307     QAbstractItemModel *taskModel() const;
308 
309     void setSslPolicy(const QList<QSslCertificate> &sslChain, const QList<QSslError> &sslErrors, bool proceed);
310 
311     void invalidateAllMessageCounts();
312 
313     QString imapAuthError() const;
314 
315 private slots:
316     /** @short Helper for low-level state change propagation */
317     void handleSocketStateChanged(Imap::Parser *parser, Imap::ConnectionState state);
318 
319     /** @short The parser has received a full line */
320     void slotParserLineReceived(Imap::Parser *parser, const QByteArray &line);
321 
322     /** @short The parser has sent a block of data */
323     void slotParserLineSent(Imap::Parser *parser, const QByteArray &line);
324 
325     /** @short There's been a change in the state of various tasks */
326     void slotTasksChanged();
327 
328     /** @short A maintaining task is about to die */
329     void slotTaskDying(QObject *obj);
330 
331     void setImapAuthError(const QString &error);
332 
333 signals:
334     /** @short This signal is emitted then the server sent us an ALERT response code */
335     void alertReceived(const QString &message);
336     /** @short The network went offline
337 
338       This signal is emitted if the network connection went offline for any reason.
339     Common reasons are an explicit user action or a network error.
340     */
341     void networkPolicyOffline();
342     /** @short The network access policy got changed to "expensive" */
343     void networkPolicyExpensive();
344     /** @short The network is available and cheap again */
345     void networkPolicyOnline();
346 
347     /** @short The network policy has changed
348 
349     This signal is emitted whenever the network policy (might) got changed to any state and for any reason. No filtering for false
350     positives is done, i.e. it might be emitted even when no change has actually taken place.
351     */
352     void networkPolicyChanged();
353 
354     /** @short Something bad happened to the network connectivity */
355     void networkError(const QString &message);
356 
357     /** @short An error at the application layer, e.g. an IMAP error, synchronization error, etc */
358     void imapError(const QString &message);
359 
360     /** @short The server requests the user to authenticate
361 
362     The user is expected to file username and password through setting the "imapUser" and "imapPassword" properties.  The imapUser
363     shall be set at first (if needed); a change to imapPassword will trigger the authentication process.
364     */
365     void authRequested();
366 
367     /** @short The authentication attempt has failed
368 
369     Slots attached to his signal should display an appropriate message to the user and (if applicable) also invalidate
370     the cached credentials.  The credentials be requested when the model decides to try logging in again via the usual
371     authRequested() function.
372     */
373     void authAttemptFailed(const QString &message);
374 
375     /** @short Signal the need for a decision about accepting a particular SSL state
376 
377     This signal is emitted in case a conneciton has hit a series of SSL errors which has not been encountered before.  The rest
378     of the code shall make a decision about whether the presented sequence of errors is safe to allow and call the setSslPolicy()
379     with the passed list of errors and an instruction whether to continue or not.
380     */
381     void needsSslDecision(const QList<QSslCertificate> &certificates, const QList<QSslError> &sslErrors);
382 
383     /** @short Inform the user that it is advised to enable STARTTLS in future connection attempts */
384     void requireStartTlsInFuture();
385 
386     /** @short The amount of messages in the indicated mailbox might have changed */
387     void messageCountPossiblyChanged(const QModelIndex &mailbox);
388 
389     /** @short We've succeeded to create the given mailbox */
390     void mailboxCreationSucceded(const QString &mailbox);
391     /** @short The mailbox creation failed for some reason */
392     void mailboxCreationFailed(const QString &mailbox, const QString &message);
393     /** @short We've succeeded to delete a mailbox */
394     void mailboxDeletionSucceded(const QString &mailbox);
395     /** @short Mailbox deletion failed */
396     void mailboxDeletionFailed(const QString &mailbox, const QString &message);
397     /** @short Got an error while syncing a mailbox */
398     void mailboxSyncFailed(const QString &mailbox, const QString &message);
399 
400     /** @short Inform the GUI about the progress of a connection */
401     void connectionStateChanged(uint parserId, Imap::ConnectionState state);   // got to use fully qualified namespace here
402 
403     /** @short The parser has encountered a fatal error */
404     void logParserFatalError(uint parser, const QString &exceptionClass, const QString &message, const QByteArray &line, int position);
405 
406     void mailboxSyncingProgress(const QModelIndex &mailbox, Imap::Mailbox::MailboxSyncingProgress state);
407 
408     void mailboxFirstUnseenMessage(const QModelIndex &maillbox, const QModelIndex &message);
409 
410     /** @short Threading has arrived */
411     void threadingAvailable(const QModelIndex &mailbox, const QByteArray &algorithm,
412                             const QStringList &searchCriteria, const QVector<Imap::Responses::ThreadingNode> &mapping);
413 
414     /** @short Failed to obtain threading information */
415     void threadingFailed(const QModelIndex &mailbox, const QByteArray &algorithm, const QStringList &searchCriteria);
416 
417     void capabilitiesUpdated(const QStringList &capabilities);
418 
419     void logged(uint parserId, const Common::LogMessage &message);
420 
421     void imapAuthErrorChanged(const QString &error);
422 
423 private:
424     Model &operator=(const Model &);  // don't implement
425     Model(const Model &);  // don't implement
426 
427 
428     friend class TreeItem;
429     friend class TreeItemMailbox;
430     friend class TreeItemMsgList;
431     friend class TreeItemMessage;
432     friend class TreeItemPart;
433     friend class TreeItemModifiedPart; // needs access to createIndex()
434     friend class MsgListModel; // needs access to createIndex()
435     friend class MailboxModel; // needs access to createIndex()
436     friend class ThreadingMsgListModel; // needs access to taskFactory
437     friend class SubtreeClassSpecificItem<Model>; // needs access to createIndex()
438 
439     friend class IdleLauncher;
440 
441     friend class ImapTask;
442     friend class FetchMsgPartTask;
443     friend class UpdateFlagsTask;
444     friend class UpdateFlagsOfAllMessagesTask;
445     friend class ListChildMailboxesTask;
446     friend class NumberOfMessagesTask;
447     friend class FetchMsgMetadataTask;
448     friend class ExpungeMailboxTask;
449     friend class ExpungeMessagesTask;
450     friend class CreateMailboxTask;
451     friend class DeleteMailboxTask;
452     friend class CopyMoveMessagesTask;
453     friend class ObtainSynchronizedMailboxTask;
454     friend class KeepMailboxOpenTask;
455     friend class OpenConnectionTask;
456     friend class GetAnyConnectionTask;
457     friend class IdTask;
458     friend class Fake_ListChildMailboxesTask;
459     friend class Fake_OpenConnectionTask;
460     friend class NoopTask;
461     friend class ThreadTask;
462     friend class UnSelectTask;
463     friend class OfflineConnectionTask;
464     friend class SortTask;
465     friend class AppendTask;
466     friend class SubscribeUnsubscribeTask;
467     friend class GenUrlAuthTask;
468     friend class UidSubmitTask;
469 
470     friend class TestingTaskFactory; // needs access to socketFactory
471     friend class DummyNetworkWatcher; // needs access to the network policy manipulation
472     friend class SystemNetworkWatcher; // needs access to the network policy manipulation
473     friend class NetworkWatcher; // needs access to the network policy manipulation
474 
475     friend class ::FakeCapabilitiesInjector; // for injecting fake capabilities
476     friend class ::ImapModelIdleTest; // needs access to findTaskResponsibleFor() for IDLE testing
477     friend class TaskPresentationModel; // needs access to the ParserState
478     friend class ::LibMailboxSync; // needs access to accessParser/ParserState
479 
480     friend class Composer::ImapMessageAttachmentItem; // needs access to findMailboxByName and findMessagesByUids
481     friend class Composer::ImapPartAttachmentItem; // dtto
482     friend class Composer::MessageComposer; // dtto
483 
484     void askForChildrenOfMailbox(TreeItemMailbox *item, bool forceReload);
485     void askForMessagesInMailbox(TreeItemMsgList *item);
486     void askForNumberOfMessages(TreeItemMsgList *item);
487 
488     typedef enum {PRELOAD_PER_POLICY, PRELOAD_DISABLED} PreloadingMode;
489 
490     void askForMsgMetadata(TreeItemMessage *item, PreloadingMode preloadMode);
491     void askForMsgPart(TreeItemPart *item, bool onlyFromCache=false);
492 
493     void finalizeList(Parser *parser, TreeItemMailbox *const mailboxPtr);
494     void finalizeIncrementalList(Parser *parser, const QString &parentMailboxName);
495     bool finalizeFetchPart(TreeItemMailbox *const mailbox, const uint sequenceNo, const QByteArray &partId);
496     void genericHandleFetch(TreeItemMailbox *mailbox, const Imap::Responses::Fetch *const resp);
497 
498     void replaceChildMailboxes(TreeItemMailbox *mailboxPtr, const TreeItemChildrenList &mailboxes);
499     void updateCapabilities(Parser *parser, const QStringList capabilities);
500 
501     TreeItem *translatePtr(const QModelIndex &index) const;
502 
503     void emitMessageCountChanged(TreeItemMailbox *const mailbox);
504 
505     TreeItemMailbox *findMailboxByName(const QString &name) const;
506     TreeItemMailbox *findMailboxByName(const QString &name, const TreeItemMailbox *const root) const;
507     TreeItemMailbox *findParentMailboxByName(const QString &name) const;
508     QList<TreeItemMessage *> findMessagesByUids(const TreeItemMailbox *const mailbox, const Imap::Uids &uids);
509     TreeItemChildrenList::iterator findMessageOrNextOneByUid(TreeItemMsgList *list, const uint uid);
510 
511     static TreeItemMailbox *mailboxForSomeItem(QModelIndex index);
512 
513     void saveUidMap(TreeItemMsgList *list);
514 
515     /** @short Return a corresponding KeepMailboxOpenTask for a given mailbox */
516     KeepMailboxOpenTask *findTaskResponsibleFor(const QModelIndex &mailbox);
517     KeepMailboxOpenTask *findTaskResponsibleFor(TreeItemMailbox *mailboxPtr);
518 
519     /** @short Find a mailbox which is expected to be common for all passed items
520 
521     The @arg items is expected to consists of message parts or messages themselves.
522     If they belong to different mailboxes, an exception is thrown.
523     */
524     QModelIndex findMailboxForItems(const QModelIndexList &items);
525 
networkPolicy()526     NetworkPolicy networkPolicy() const { return m_netPolicy; }
527     void setNetworkPolicy(const NetworkPolicy policy);
528 
529     /** @short Helper function for changing connection state */
530     void changeConnectionState(Parser *parser, ConnectionState state);
531 
532     void processSslErrors(OpenConnectionTask *task);
533 
534     /** @short Is the reason for killing the parser an expected one? */
535     typedef enum {
536         PARSER_KILL_EXPECTED, /**< @short Normal operation */
537         PARSER_KILL_HARD, /**< @short Sudden, unexpected death */
538         PARSER_JUST_DELETE_LATER /**< @short Just call deleteLater(), nothing else */
539     } ParserKillingMethod;
540 
541     /** @short Dispose of the parser in a C++-safe way */
542     void killParser(Parser *parser, ParserKillingMethod method=PARSER_KILL_HARD);
543 
544     ParserState &accessParser(Parser *parser);
545 
546     /** @short Helper for the slotParseError() */
547     void broadcastParseError(const uint parser, const QString &exceptionClass, const QString &errorMessage, const QByteArray &line, int position);
548 
549     void responseReceived(const QMap<Parser *,ParserState>::iterator it);
550 
551     /** @short Remove deleted Tasks from the activeTasks list */
552     void removeDeletedTasks(const QList<ImapTask *> &deletedTasks, QList<ImapTask *> &activeTasks);
553 
554     void informTasksAboutNewPassword();
555 
556     QStringList onlineMessageFetch;
557 
558     /** @short Model visualizing the state of the tasks */
559     TaskPresentationModel *m_taskModel;
560 
561     QMap<QByteArray,QByteArray> m_idResult;
562 
563     mutable QSet<QString> m_flagLiterals;
564 
565     /** @short Username for login */
566     QString m_imapUser;
567     /** @short Cached copy of the IMAP password */
568     QString m_imapPassword;
569     /** @short Is the IMAP password cached in the Model already? */
570     enum class PasswordAvailability {
571         NOT_REQUESTED,
572         ASKED_WAITING,
573         AVAILABLE,
574     };
575     PasswordAvailability m_hasImapPassword;
576     /** @short Contains IMAP error output while password prompt process*/
577     QString m_imapAuthError;
578 
579     QTimer *m_periodicMailboxNumbersRefresh;
580 
581     QStringList m_capabilitiesBlacklist;
582 
583 protected slots:
584     void responseReceived();
585     void responseReceived(Imap::Parser *parser);
586     void askForChildrenOfMailbox(const QModelIndex &index, const Imap::Mailbox::CacheLoadingMode cacheMode);
587     void askForMessagesInMailbox(const QModelIndex &index);
588 
589     void runReadyTasks();
590 
591 #ifdef TROJITA_DEBUG_TASK_TREE
592     void checkTaskTreeConsistency();
593     void checkDependentTasksConsistency(Parser *parser, ImapTask *task, ImapTask *expectedParentTask, int depth);
594 #endif
595 
596 };
597 
598 }
599 
600 }
601 
602 #endif /* IMAP_MODEL_H */
603