summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/imap/src/nsImapProtocol.h
blob: 815ac103dc91c3ae463be20e0b364d86ba70c854 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsImapProtocol_h___
#define nsImapProtocol_h___

#include "mozilla/Attributes.h"
#include "nsIImapProtocol.h"
#include "nsIImapUrl.h"

#include "nsMsgProtocol.h"
#include "nsIStreamListener.h"
#include "nsIAsyncOutputStream.h"
#include "nsIAsyncInputStream.h"
#include "nsImapCore.h"
#include "nsString.h"
#include "nsIProgressEventSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsISocketTransport.h"

// UI Thread proxy helper
#include "nsIImapProtocolSink.h"

#include "../public/nsIImapHostSessionList.h"
#include "nsImapServerResponseParser.h"
#include "nsImapFlagAndUidState.h"
#include "nsImapNamespace.h"
#include "nsTArray.h"
#include "nsIWeakReferenceUtils.h"
#include "nsMsgLineBuffer.h"  // we need this to use the nsMsgLineStreamBuffer helper class...
#include "nsIInputStream.h"
#include "nsIMsgIncomingServer.h"
#include "nsCOMArray.h"
#include "nsIThread.h"
#include "nsIRunnable.h"
#include "nsIImapMockChannel.h"
#include "nsILoadGroup.h"
#include "nsCOMPtr.h"
#include "nsIMsgWindow.h"
#include "nsIImapHeaderXferInfo.h"
#include "nsMsgLineBuffer.h"
#include "nsIAsyncInputStream.h"
#include "nsIMsgFolder.h"
#include "nsIMsgAsyncPrompter.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsSyncRunnableHelpers.h"
#include "nsICacheEntryOpenCallback.h"
#include "nsIProtocolProxyCallback.h"
#include "nsIStringBundle.h"
#include "nsHashPropertyBag.h"
#include "nsMailChannel.h"

#include "mozilla/Monitor.h"

class nsIMAPMessagePartID;
class nsIPrefBranch;

#define kDownLoadCacheSize 16000u  // was 1536 - try making it bigger

typedef struct _msg_line_info {
  const char* adoptedMessageLine;
  uint32_t uidOfMessage;
} msg_line_info;

class nsMsgImapLineDownloadCache : public nsIImapHeaderInfo,
                                   public nsByteArray {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIIMAPHEADERINFO
  nsMsgImapLineDownloadCache();
  uint32_t CurrentUID();
  uint32_t SpaceAvailable();
  bool CacheEmpty();

  msg_line_info* GetCurrentLineInfo();

 private:
  virtual ~nsMsgImapLineDownloadCache();

  msg_line_info* fLineInfo;
  int32_t m_msgSize;
};

#define kNumHdrsToXfer 10

class nsMsgImapHdrXferInfo : public nsIImapHeaderXferInfo {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIIMAPHEADERXFERINFO
  nsMsgImapHdrXferInfo();
  void ResetAll();    // reset HeaderInfos for re-use
  void ReleaseAll();  // release HeaderInfos (frees up memory)
  // this will return null if we're full, in which case the client code
  // should transfer the headers and retry.
  nsIImapHeaderInfo* StartNewHdr();
  // call when we've finished adding lines to current hdr
  void FinishCurrentHdr();

 private:
  virtual ~nsMsgImapHdrXferInfo();
  nsCOMArray<nsIImapHeaderInfo> m_hdrInfos;
  int32_t m_nextFreeHdrInfo;
};

// This class contains the name of a mailbox and whether or not
// its children have been listed.
class nsIMAPMailboxInfo {
 public:
  nsIMAPMailboxInfo(const nsACString& aName, char aDelimiter);
  virtual ~nsIMAPMailboxInfo();

  void SetChildrenListed(bool childrenListed);
  bool GetChildrenListed();
  const nsACString& GetMailboxName();
  char GetDelimiter();

 protected:
  nsCString mMailboxName;
  bool mChildrenListed;
  char mDelimiter;
};

// State Flags (Note, I use the word state in terms of storing
// state information about the connection (authentication, have we sent
// commands, etc. I do not intend it to refer to protocol state)
// Use these flags in conjunction with SetFlag/TestFlag/ClearFlag instead
// of creating PRBools for everything....
// clang-format off
#define IMAP_RECEIVED_GREETING        0x00000001  // should we pause for the next read
#define  IMAP_CONNECTION_IS_OPEN      0x00000004  // is the connection currently open?
#define IMAP_WAITING_FOR_DATA         0x00000008
#define IMAP_CLEAN_UP_URL_STATE       0x00000010  // processing clean up url state
#define IMAP_ISSUED_LANGUAGE_REQUEST  0x00000020  // make sure we only issue the language
                                                  // request once per connection...
#define IMAP_ISSUED_COMPRESS_REQUEST  0x00000040  // make sure we only request compression once

// There are 3 types of progress strings for items downloaded from IMAP servers.
// An index is needed to keep track of the current count of the number of each
// item type downloaded. The IMAP_EMPTY_STRING_INDEX means no string displayed.
#define IMAP_NUMBER_OF_PROGRESS_STRINGS 4
#define IMAP_HEADERS_STRING_INDEX       0
#define IMAP_FLAGS_STRING_INDEX         1
#define IMAP_MESSAGES_STRING_INDEX      2
#define IMAP_EMPTY_STRING_INDEX         3
// clang-format on

/**
 * nsImapProtocol is, among other things, the underlying nsIChannel
 * implementation for the IMAP protocol. However, it's usually hidden away
 * behind nsImapMockChannel objects. It also represents the 'real' connection
 * to the IMAP server - it maintains the nsISocketTransport.
 * Because there can be multiple IMAP requests queued up, NS_NewChannel()
 * will return nsImapMockChannel objects instead, to keep the request in a
 * holding pattern until the connection is free. At which time the mock
 * channel will just forward calls onward to the nsImapProtocol.
 *
 * The url scheme we implement here encodes various IMAP commands as URLs.
 * Some URLs are just traditional I/O based nsIChannel transactions, but
 * many others have side effects. For example, an IMAP folder discovery
 * command might cause the creation of the nsImapMailFolder hierarchy under
 * the the nsImapIncomingServer.
 * Such side effects are communicated via the various "Sink" interfaces. This
 * helps decouple the IMAP code from the rest of the system:
 *
 * - nsIImapServerSink      (implemented by nsImapIncomingServer)
 * - nsIImapMailFolderSink  (implemented by nsImapMailFolder)
 * - nsIImapMessageSink     (implemented by nsImapMailFolder)
 *
 * Internal to nsImapProtocol, these sink classes all have corresponding proxy
 * implementations (ImapServerSinkProxy, ImapMailFolderSinkProxy and
 * ImapMessageSinkProxy). These allow us to safely call the sink objects, in
 * a synchronous fashion, from I/O threads (threads other than the main one).
 * When an IMAP routine calls a member function of one of these sink proxies,
 * it dispatches a call to the real sink object on the main thread, then
 * blocks until the call is completed.
 */
class nsImapProtocol : public nsIImapProtocol,
                       public nsIInputStreamCallback,
                       public nsSupportsWeakReference,
                       public nsMsgProtocol,
                       public nsIImapProtocolSink,
                       public nsIMsgAsyncPromptListener,
                       public nsIProtocolProxyCallback {
 public:
  struct TCPKeepalive {
    // For enabling and setting TCP keepalive (not related to IMAP IDLE).
    std::atomic<bool> enabled;
    std::atomic<int32_t> idleTimeS;
    std::atomic<int32_t> retryIntervalS;
  };

  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_NSIINPUTSTREAMCALLBACK
  NS_DECL_NSIPROTOCOLPROXYCALLBACK
  nsImapProtocol();

  virtual nsresult ProcessProtocolState(nsIURI* url,
                                        nsIInputStream* inputStream,
                                        uint64_t sourceOffset,
                                        uint32_t length) override;

  //////////////////////////////////////////////////////////////////////////////////
  // we support the nsIImapProtocol interface
  //////////////////////////////////////////////////////////////////////////////////
  NS_DECL_NSIIMAPPROTOCOL

  //////////////////////////////////////////////////////////////////////////////////
  // we support the nsIImapProtocolSink interface
  //////////////////////////////////////////////////////////////////////////////////
  NS_DECL_NSIIMAPPROTOCOLSINK

  NS_DECL_NSIMSGASYNCPROMPTLISTENER

  // message id string utilities.
  uint32_t CountMessagesInIdString(const char* idString);
  static bool HandlingMultipleMessages(const nsCString& messageIdString);
  // escape slashes and double quotes in username/passwords for insecure login.
  static void EscapeUserNamePasswordString(const char* strToEscape,
                                           nsCString* resultStr);

  // used to start fetching a message.
  void GetShouldDownloadAllHeaders(bool* aResult);
  void GetArbitraryHeadersToDownload(nsCString& aResult);
  virtual void AdjustChunkSize();
  virtual void FetchMessage(const nsCString& messageIds,
                            nsIMAPeFetchFields whatToFetch,
                            const char* fetchModifier = nullptr,
                            uint32_t startByte = 0, uint32_t numBytes = 0,
                            char* part = 0);
  void FetchTryChunking(const nsCString& messageIds,
                        nsIMAPeFetchFields whatToFetch, bool idIsUid,
                        char* part, uint32_t downloadSize, bool tryChunking);
  void FallbackToFetchWholeMsg(const nsCString& messageId,
                               uint32_t messageSize);
  // used when streaming a message fetch
  virtual nsresult BeginMessageDownLoad(
      uint32_t totalSize,        // for user, headers and body
      const char* contentType);  // some downloads are header only
  virtual void HandleMessageDownLoadLine(const char* line, bool isPartialLine,
                                         char* lineCopy = nullptr);
  virtual void NormalMessageEndDownload();
  virtual void AbortMessageDownLoad();
  virtual void PostLineDownLoadEvent(const char* line, uint32_t uid);
  void FlushDownloadCache();

  virtual void SetMailboxDiscoveryStatus(EMailboxDiscoverStatus status);
  virtual EMailboxDiscoverStatus GetMailboxDiscoveryStatus();

  virtual void ProcessMailboxUpdate(bool handlePossibleUndo);
  // Send log output...
  void Log(const char* logSubName, const char* extraInfo, const char* logData);
  static void LogImapUrl(const char* logMsg, nsIImapUrl* imapUrl);
  // Comment from 4.5: We really need to break out the thread synchronizer from
  // the connection class...Not sure what this means
  bool GetPseudoInterrupted();

  uint32_t GetMessageSize(const nsACString& messageId);
  bool GetSubscribingNow();

  bool DeathSignalReceived();
  void ResetProgressInfo();
  void SetActive(bool active);
  bool GetActive();

  bool GetShowAttachmentsInline();

  // Sets whether or not the content referenced by the current ActiveEntry has
  // been modified. Used for MIME parts on demand.
  void SetContentModified(IMAP_ContentModifiedType modified);
  bool GetShouldFetchAllParts();
  bool GetIgnoreExpunges() { return m_ignoreExpunges; }
  // Generic accessors required by the imap parser
  char* CreateNewLineFromSocket();
  nsresult GetConnectionStatus();
  void SetConnectionStatus(nsresult status);

  // Cleanup the connection and shutdown the thread.
  void TellThreadToDie();

  const nsCString&
  GetImapHostName();  // return the host name from the url for the
  // current connection
  const nsCString& GetImapUserName();  // return the user name from the identity
  const char*
  GetImapServerKey();  // return the user name from the incoming server;

  // state set by the imap parser...
  void NotifyMessageFlags(imapMessageFlagsType flags,
                          const nsACString& keywords, nsMsgKey key,
                          uint64_t highestModSeq);
  void NotifySearchHit(const char* hitLine);

  // Event handlers for the imap parser.
  void DiscoverMailboxSpec(nsImapMailboxSpec* adoptedBoxSpec);
  void AlertUserEventUsingName(const char* aMessageId);
  void AlertUserEvent(const char* message);
  void AlertUserEventFromServer(const char* aServerEvent,
                                bool aForIdle = false);

  void ProgressEventFunctionUsingName(const char* aMsgId);
  void ProgressEventFunctionUsingNameWithString(const char* aMsgName,
                                                const char* aExtraInfo);
  void PercentProgressUpdateEvent(nsACString const& fmtStringName,
                                  nsAString const& mailbox,
                                  int64_t currentProgress, int64_t maxProgress);
  void ShowProgress();

  // utility function calls made by the server

  void Copy(const char* messageList, const char* destinationMailbox,
            bool idsAreUid);
  void Search(const char* searchCriteria, bool useUID, bool notifyHit = true);
  // imap commands issued by the parser
  void Store(const nsCString& aMessageList, const char* aMessageData,
             bool aIdsAreUid);
  void ProcessStoreFlags(const nsCString& messageIds, bool idsAreUids,
                         imapMessageFlagsType flags, bool addFlags);
  void IssueUserDefinedMsgCommand(const char* command, const char* messageList);
  void FetchMsgAttribute(const nsCString& messageIds,
                         const nsCString& attribute);
  void Expunge();
  void UidExpunge(const nsCString& messageSet);
  void ImapClose(bool shuttingDown = false, bool waitForResponse = true);
  void Check();
  void SelectMailbox(const char* mailboxName);
  // more imap commands
  void Logout(bool shuttingDown = false, bool waitForResponse = true);
  void Noop();
  void XServerInfo();
  void Netscape();
  void XMailboxInfo(const char* mailboxName);
  void XAOL_Option(const char* option);
  void MailboxData();
  void GetMyRightsForFolder(const char* mailboxName);
  void Bodystructure(const nsCString& messageId, bool idIsUid);

  // this function does not ref count!!! be careful!!!
  nsIImapUrl* GetCurrentUrl() { return m_runningUrl; }

  // acl and namespace stuff
  // notifies libmsg that we have a new personal/default namespace that we're
  // using
  void CommitNamespacesForHostEvent();
  // notifies libmsg that we have new capability data for the current host
  void CommitCapability();

  // Adds a set of rights for a given user on a given mailbox on the current
  // host. if userName is NULL, it means "me," or MYRIGHTS. rights is a single
  // string of rights, as specified by RFC2086, the IMAP ACL extension.
  void AddFolderRightsForUser(const char* mailboxName, const char* userName,
                              const char* rights);
  // Clears all rights for the current folder, for all users.
  void ClearAllFolderRights();
  void RefreshFolderACLView(const char* mailboxName,
                            nsImapNamespace* nsForMailbox);

  nsresult SetFolderAdminUrl(const char* mailboxName);
  void HandleMemoryFailure();
  void HandleCurrentUrlError();

  // UIDPLUS extension
  void SetCopyResponseUid(const char* msgIdString);

  // Quota support
  void UpdateFolderQuotaData(nsImapQuotaAction aAction, nsCString& aQuotaRoot,
                             uint64_t aUsed, uint64_t aMax);

  bool GetPreferPlainText() { return m_preferPlainText; }

  int32_t GetCurFetchSize() { return m_curFetchSize; }

  const nsString& GetEmptyMimePartString() { return m_emptyMimePartString; }
  void SetCapabilityResponseOccurred();

  // Start event loop. This is called on IMAP thread
  bool RunImapThreadMainLoop();

 private:
  virtual ~nsImapProtocol();
  // the following flag is used to determine when a url is currently being run.
  // It is cleared when we finish processng a url and it is set whenever we call
  // Load on a url
  bool m_urlInProgress;

  /** The nsIImapURL that is currently running. */
  nsCOMPtr<nsIImapUrl> m_runningUrl;
  nsCOMPtr<nsIImapUrl> m_runningUrlLatest;
  /** Current imap action associated with this connection. */
  nsImapAction m_imapAction;

  nsCString m_hostName;
  nsCString m_userName;
  nsCString m_serverKey;
  char* m_dataOutputBuf;
  RefPtr<nsMsgLineStreamBuffer> m_inputStreamBuffer;
  nsCString m_trashFolderPath;

  /** The socket connection to the IMAP server. */
  nsCOMPtr<nsISocketTransport> m_transport;
  nsCOMPtr<nsITransportSecurityInfo> m_securityInfo;

  /** Stream to handle data coming in from the IMAP server. */
  nsCOMPtr<nsIInputStream> m_inputStream;

  nsCOMPtr<nsIAsyncInputStream> m_channelInputStream;
  nsCOMPtr<nsIAsyncOutputStream> m_channelOutputStream;

  /** The currently running request. */
  nsCOMPtr<nsIImapMockChannel> m_mockChannel;

  uint32_t m_bytesToChannel;
  bool m_fetchingWholeMessage;
  // nsCOMPtr<nsIRequest> mAsyncReadRequest; // we're going to cancel this when
  // we're done with the conn.

  // ******* Thread support *******
  PRThread* m_thread;
  mozilla::ReentrantMonitor
      m_dataAvailableMonitor;  // used to notify the arrival of data from the
                               // server
  mozilla::ReentrantMonitor
      m_urlReadyToRunMonitor;  // used to notify the arrival of a new url to be
                               // processed
  mozilla::ReentrantMonitor m_pseudoInterruptMonitor;
  mozilla::ReentrantMonitor m_dataMemberMonitor;
  mozilla::ReentrantMonitor m_threadDeathMonitor;
  mozilla::ReentrantMonitor m_waitForBodyIdsMonitor;
  mozilla::ReentrantMonitor m_fetchBodyListMonitor;
  mozilla::ReentrantMonitor m_passwordReadyMonitor;
  mozilla::Mutex mLock;
  // If we get an async password prompt, this is where the UI thread
  // stores the password, before notifying the imap thread of the password
  // via the m_passwordReadyMonitor.
  nsString m_password;
  // Set to the result of nsImapServer::PromptPassword
  nsresult m_passwordStatus;
  bool m_passwordObtained;

  bool m_imapThreadIsRunning;
  void ImapThreadMainLoop(void);
  nsresult m_connectionStatus;
  nsCString m_connectionType;

  bool m_nextUrlReadyToRun;
  bool m_idleResponseReadyToHandle;
  nsWeakPtr m_server;

  RefPtr<ImapMailFolderSinkProxy> m_imapMailFolderSink;
  RefPtr<ImapMailFolderSinkProxy> m_imapMailFolderSinkSelected;
  RefPtr<ImapMessageSinkProxy> m_imapMessageSink;
  RefPtr<ImapServerSinkProxy> m_imapServerSink;
  RefPtr<ImapServerSinkProxy> m_imapServerSinkLatest;
  RefPtr<ImapProtocolSinkProxy> m_imapProtocolSink;

  // helper function to setup imap sink interface proxies
  nsresult SetupSinkProxy();
  // End thread support stuff
  nsresult LoadImapUrlInternal();

  bool GetDeleteIsMoveToTrash();
  bool GetShowDeletedMessages();
  nsCString m_currentCommand;
  nsImapServerResponseParser m_parser;
  nsImapServerResponseParser& GetServerStateParser() { return m_parser; }

  bool HandleIdleResponses();
  virtual bool ProcessCurrentURL();
  void EstablishServerConnection();
  virtual void ParseIMAPandCheckForNewMail(const char* commandString = nullptr,
                                           bool ignoreBadNOResponses = false);
  // biff
  void PeriodicBiff();
  void SendSetBiffIndicatorEvent(nsMsgBiffState newState);

  // folder opening and listing header functions
  void FolderHeaderDump(uint32_t* msgUids, uint32_t msgCount);
  void FolderMsgDump(uint32_t* msgUids, uint32_t msgCount,
                     nsIMAPeFetchFields fields);
  void FolderMsgDumpLoop(uint32_t* msgUids, uint32_t msgCount,
                         nsIMAPeFetchFields fields);
  void WaitForPotentialListOfBodysToFetch(nsTArray<nsMsgKey>& msgIdList);
  void HeaderFetchCompleted();
  void UploadMessageFromFile(nsIFile* file, const char* mailboxName,
                             PRTime date, imapMessageFlagsType flags,
                             nsCString& keywords);

  // mailbox name utilities.
  void CreateEscapedMailboxName(const char* rawName, nsCString& escapedName);
  void SetupMessageFlagsString(nsCString& flagString,
                               imapMessageFlagsType flags, uint16_t userFlags);

  // body fetching listing data
  bool m_fetchBodyListIsNew;
  nsTArray<nsMsgKey> m_fetchBodyIdList;

  // initialization function given a new url and transport layer
  nsresult SetupWithUrl(nsIURI* aURL, nsISupports* aConsumer);
  nsresult SetupWithUrlCallback(nsIProxyInfo* proxyInfo);
  void ReleaseUrlState(bool rerunningUrl);  // release any state that is stored
                                            // on a per action basis.
  /**
   * Last ditch effort to run the url without using an imap connection.
   * If it turns out that we don't need to run the url at all (e.g., we're
   * trying to download a single message for offline use and it has already
   * been downloaded, this function will send the appropriate notifications.
   *
   * @returns true if the url has been run locally, or doesn't need to be run.
   */
  bool TryToRunUrlLocally(nsIURI* aURL, nsISupports* aConsumer);

  ////////////////////////////////////////////////////////////////////////////////////////
  // Communication methods --> Reading and writing protocol
  ////////////////////////////////////////////////////////////////////////////////////////

  // SendData not only writes the NULL terminated data in dataBuffer to our
  // output stream but it also informs the consumer that the data has been
  // written to the stream. aSuppressLogging --> set to true if you wish to
  // suppress logging for this particular command. this is useful for making
  // sure we don't log authentication information like the user's password
  // (which was encoded anyway), but still we shouldn't add that information to
  // the log.
  nsresult SendData(const char* dataBuffer,
                    bool aSuppressLogging = false) override;

  // state ported over from 4.5
  bool m_pseudoInterrupted;
  bool m_active;
  bool m_folderNeedsSubscribing;
  bool m_folderNeedsACLRefreshed;

  bool m_threadShouldDie;

  // use to prevent re-entering TellThreadToDie.
  bool m_inThreadShouldDie;
  // If the UI thread has signalled the IMAP thread to die, and the
  // connection has timed out, this will be set to FALSE.
  bool m_safeToCloseConnection;

  RefPtr<nsImapFlagAndUidState> m_flagState;
  nsMsgBiffState m_currentBiffState;
  // manage the IMAP server command tags
  // 11 = enough memory for the decimal representation of MAX_UINT + trailing
  // nul
  char m_currentServerCommandTag[11];
  uint32_t m_currentServerCommandTagNumber;
  void IncrementCommandTagNumber();
  const char* GetServerCommandTag();

  void StartTLS();

  // login related methods.
  nsresult GetPassword(nsString& password, bool aNewPasswordRequested);
  void InitPrefAuthMethods(int32_t authMethodPrefValue,
                           nsIMsgIncomingServer* aServer);
  nsresult ChooseAuthMethod();
  void MarkAuthMethodAsFailed(eIMAPCapabilityFlags failedAuthMethod);
  void ResetAuthMethods();

  // All of these methods actually issue protocol
  void Capability();  // query host for capabilities.
  void ID();          // send RFC 2971 app info to server
  void EnableUTF8Accept();
  void EnableCondStore();
  void StartCompressDeflate();
  nsresult BeginCompressing();
  void Language();  // set the language on the server if it supports it
  void Namespace();
  void InsecureLogin(const char* userName, const nsCString& password);
  nsresult ClientID();
  nsresult AuthLogin(const char* userName, const nsString& password,
                     eIMAPCapabilityFlag flag);
  nsresult SendDataParseIMAPandCheckForNewMail(const char* data,
                                               const char* command);
  void ProcessAuthenticatedStateURL();
  void ProcessAfterAuthenticated();
  void ProcessSelectedStateURL();
  bool TryToLogon();

  // ProcessAuthenticatedStateURL() used to be one giant if statement. I've
  // broken out a set of actions based on the imap action passed into the url.
  // The following functions are imap protocol handlers for each action. They
  // are called by ProcessAuthenticatedStateUrl.
  void OnLSubFolders();
  void OnAppendMsgFromFile();

  char* GetFolderPathString();  // OK to call from UI thread

  char* OnCreateServerSourceFolderPathString();
  char* OnCreateServerDestinationFolderPathString();
  nsresult CreateServerSourceFolderPathString(char** result);
  void OnCreateFolder(const char* aSourceMailbox);
  void OnEnsureExistsFolder(const char* aSourceMailbox);
  void OnSubscribe(const char* aSourceMailbox);
  void OnUnsubscribe(const char* aSourceMailbox);
  void RefreshACLForFolderIfNecessary(const char* mailboxName);
  void RefreshACLForFolder(const char* aSourceMailbox);
  void GetACLForFolder(const char* aMailboxName);
  void OnRefreshAllACLs();
  void OnListFolder(const char* aSourceMailbox, bool aBool);
  void OnStatusForFolder(const char* sourceMailbox);
  void OnDeleteFolder(const char* aSourceMailbox);
  void OnRenameFolder(const char* aSourceMailbox);
  void OnMoveFolderHierarchy(const char* aSourceMailbox);
  void DeleteFolderAndMsgs(const char* aSourceMailbox);
  void RemoveMsgsAndExpunge();
  void FindMailboxesIfNecessary();
  void CreateMailbox(const char* mailboxName);
  void DeleteMailbox(const char* mailboxName);
  void RenameMailbox(const char* existingName, const char* newName);
  void RemoveHierarchyDelimiter(nsCString& mailboxName);
  bool CreateMailboxRespectingSubscriptions(const char* mailboxName);
  bool DeleteMailboxRespectingSubscriptions(const char* mailboxName);
  bool RenameMailboxRespectingSubscriptions(const char* existingName,
                                            const char* newName,
                                            bool reallyRename);
  // notify the fe that a folder was deleted
  void FolderDeleted(const char* mailboxName);
  // notify the fe that a folder creation failed
  void FolderNotCreated(const char* mailboxName);
  // notify the fe that a folder was deleted
  void FolderRenamed(const char* oldName, const char* newName);

  bool FolderIsSelected(const char* mailboxName);

  bool MailboxIsNoSelectMailbox(const char* mailboxName);
  bool FolderNeedsACLInitialized(const char* folderName);
  void DiscoverMailboxList();
  void DiscoverAllAndSubscribedBoxes();
  void MailboxDiscoveryFinished();
  void NthLevelChildList(const char* onlineMailboxPrefix, int32_t depth);
  // LIST SUBSCRIBED command (from RFC 5258) crashes some servers. so we need to
  // identify those servers
  bool GetListSubscribedIsBrokenOnServer();
  void Lsub(const char* mailboxPattern, bool addDirectoryIfNecessary);
  void List(const char* mailboxPattern, bool addDirectoryIfNecessary,
            bool useXLIST = false);
  void Subscribe(const char* mailboxName);
  void Unsubscribe(const char* mailboxName);
  void Idle();
  void EndIdle(bool waitForResponse = true);
  // Some imap servers include the mailboxName following the dir-separator in
  // the list of subfolders of the mailboxName. In fact, they are the same. So
  // we should decide if we should delete such subfolder and provide feedback if
  // the delete operation succeed.
  bool DeleteSubFolders(const char* aMailboxName, bool& aDeleteSelf);
  bool RenameHierarchyByHand(const char* oldParentMailboxName,
                             const char* newParentMailboxName);
  bool RetryUrl();

  nsresult GlobalInitialization(nsIPrefBranch* aPrefBranch);
  nsresult Configure(int32_t TooFastTime, int32_t IdealTime,
                     int32_t ChunkAddSize, int32_t ChunkSize,
                     int32_t ChunkThreshold, bool FetchByChunks);
  nsresult GetMsgWindow(nsIMsgWindow** aMsgWindow);
  // End Process AuthenticatedState Url helper methods

  virtual char const* GetType() override { return "imap"; }

  // Quota support
  void GetQuotaDataIfSupported(const char* aBoxName);

  // CondStore support - true if server supports it, and the user hasn't
  // disabled it.
  bool UseCondStore();
  // false if pref "mail.server.serverxxx.use_condstore" is false;
  bool m_useCondStore;
  // COMPRESS=DEFLATE support - true if server supports it, and the user hasn't
  // disabled it.
  bool UseCompressDeflate();
  // false if pref "mail.server.serverxxx.use_compress_deflate" is false;
  bool m_useCompressDeflate;
  // these come from the nsIDBFolderInfo in the msgDatabase and
  // are initialized in nsImapProtocol::SetupWithUrl.
  uint64_t mFolderLastModSeq;
  int32_t mFolderTotalMsgCount;
  uint32_t mFolderHighestUID;
  bool m_allowUTF8Accept;

  bool m_isGmailServer;
  nsTArray<nsCString> mCustomDBHeaders;
  nsTArray<nsCString> mCustomHeaders;
  bool m_trackingTime;
  PRTime m_startTime;
  PRTime m_endTime;
  PRTime m_lastActiveTime;
  int32_t m_tooFastTime;
  int32_t m_idealTime;
  int32_t m_chunkAddSize;
  int32_t m_chunkStartSize;
  bool m_fetchByChunks;
  bool m_sendID;
  int32_t m_curFetchSize;
  bool m_ignoreExpunges;
  eIMAPCapabilityFlags m_prefAuthMethods;    // set of capability flags (in
                                             // nsImapCore.h) for auth methods
  eIMAPCapabilityFlags m_failedAuthMethods;  // ditto
  eIMAPCapabilityFlag m_currentAuthMethod;  // exactly one capability flag, or 0
  int32_t m_socketType;
  int32_t m_chunkSize;
  int32_t m_chunkThreshold;
  RefPtr<nsMsgImapLineDownloadCache> m_downloadLineCache;
  RefPtr<nsMsgImapHdrXferInfo> m_hdrDownloadCache;
  nsCOMPtr<nsIImapHeaderInfo> m_curHdrInfo;
  // mapping between mailboxes and the corresponding folder flags
  nsTHashMap<nsCStringHashKey, int32_t> m_standardListMailboxes;
  // mapping between special xlist mailboxes and the corresponding folder flags
  nsTHashMap<nsCStringHashKey, int32_t> m_specialXListMailboxes;

  nsCOMPtr<nsIImapHostSessionList> m_hostSessionList;

  bool m_fromHeaderSeen;

  nsString mAcceptLanguages;

  nsCString m_clientId;

  // progress stuff
  void SetProgressString(uint32_t aStringIndex);

  nsCString m_progressStringName;
  uint32_t m_stringIndex;
  int32_t m_progressCurrentNumber[IMAP_NUMBER_OF_PROGRESS_STRINGS];
  int32_t m_progressExpectedNumber;
  nsCString m_lastProgressStringName;
  int32_t m_lastPercent;
  int64_t m_lastProgressTime;

  bool m_notifySearchHit;
  bool m_needNoop;
  bool m_idle;
  bool m_useIdle;
  int32_t m_noopCount;
  bool m_autoSubscribe, m_autoUnsubscribe, m_autoSubscribeOnOpen;
  bool m_closeNeededBeforeSelect;
  bool m_retryUrlOnError;
  bool m_preferPlainText;
  bool m_forceSelect;

  int32_t m_uidValidity;  // stored uid validity for the selected folder.

  enum EMailboxHierarchyNameState {
    kNoOperationInProgress,
    // kDiscoverBaseFolderInProgress, - Unused. Keeping for historical reasons.
    kDiscoverTrashFolderInProgress,
    kDeleteSubFoldersInProgress,
    kListingForInfoOnly,
    kListingForInfoAndDiscovery,
    kDiscoveringNamespacesOnly,
    kXListing,
    kListingForFolderFlags,
    kListingForCreate
  };
  EMailboxHierarchyNameState m_hierarchyNameState;
  EMailboxDiscoverStatus m_discoveryStatus;
  nsTArray<nsIMAPMailboxInfo*> m_listedMailboxList;
  nsTArray<nsCString>* m_deletableChildren;
  uint32_t m_flagChangeCount;
  PRTime m_lastCheckTime;

  bool CheckNeeded();

  nsString m_emptyMimePartString;

  RefPtr<mozilla::mailnews::OAuth2ThreadHelper> mOAuth2Support;
  bool m_capabilityResponseOccurred;

  nsresult IsTransportAlive(bool* alive);
  nsresult TransportStartTLS();
  void GetTransportSecurityInfo(nsITransportSecurityInfo** aSecurityInfo);
};

// This small class is a "mock" channel because it is a mockery of the imap
// channel's implementation... it's a light weight channel that we can return to
// necko when they ask for a channel on a url before we actually have an imap
// protocol instance around which can run the url. Please see my comments in
// nsIImapMockChannel.idl for more details..
//
// Threading concern: This class lives entirely in the UI thread.

class nsICacheEntry;

class nsImapMockChannel : public nsIImapMockChannel,
                          public nsICacheEntryOpenCallback,
                          public nsITransportEventSink,
                          public nsSupportsWeakReference,
                          public nsMailChannel,
                          public nsHashPropertyBag {
 public:
  friend class nsImapProtocol;

  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_NSIIMAPMOCKCHANNEL
  NS_DECL_NSICHANNEL
  NS_DECL_NSIREQUEST
  NS_DECL_NSICACHEENTRYOPENCALLBACK
  NS_DECL_NSITRANSPORTEVENTSINK

  nsImapMockChannel();
  static nsresult Create(const nsIID& iid, void** result);
  nsresult RunOnStopRequestFailure();

 protected:
  virtual ~nsImapMockChannel();
  nsCOMPtr<nsIURI> m_url;

  nsCOMPtr<nsIURI> m_originalUrl;
  nsCOMPtr<nsILoadGroup> m_loadGroup;
  nsCOMPtr<nsILoadInfo> m_loadInfo;
  nsCOMPtr<nsIStreamListener> m_channelListener;
  nsresult m_cancelStatus;
  nsLoadFlags mLoadFlags;
  nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
  nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
  nsCOMPtr<nsISupports> mOwner;
  nsCOMPtr<nsITransportSecurityInfo> mSecurityInfo;
  nsCString mContentType;
  nsCString mCharset;
  nsWeakPtr mProtocol;

  bool mChannelClosed;
  bool mReadingFromCache;
  int64_t mContentLength;
  bool mWritingToCache;

  mozilla::Monitor mSuspendedMonitor;
  bool mSuspended;

  nsresult ResumeAndNotifyOne();

  // cache related helper methods
  nsresult OpenCacheEntry();  // makes a request to the cache service for a
                              // cache entry for a url
  bool ReadFromLocalCache();  // attempts to read the url out of our local
                              // (offline) cache....
  nsresult ReadFromCache2(nsICacheEntry* entry);  // pipes message from cache2
                                                  // entry to channel listener
  nsresult NotifyStartEndReadFromCache(bool start);

  // we end up daisy chaining multiple nsIStreamListeners into the load process.
  nsresult SetupPartExtractorListener(nsIImapUrl* aUrl,
                                      nsIStreamListener* aConsumer);

  uint32_t mContentDisposition;
};

#endif  // nsImapProtocol_h___