summaryrefslogtreecommitdiffstats
path: root/mailnews/imap/src/nsImapProtocol.h
blob: 5c4f43abdfb8fd77fc6de8bdbb1d2fb3641f8374 (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
/* -*- 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 "nsStringGlue.h"
#include "nsIProgressEventSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsISocketTransport.h"
#include "nsIInputStreamPump.h"

// imap event sinks
#include "nsIImapMailFolderSink.h"
#include "nsIImapServerSink.h"
#include "nsIImapMessageSink.h"

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

#include "nsImapServerResponseParser.h"
#include "nsImapFlagAndUidState.h"
#include "nsIMAPNamespace.h"
#include "nsTArray.h"
#include "nsWeakPtr.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 "nsIImapIncomingServer.h"
#include "nsIMsgWindow.h"
#include "nsIImapHeaderXferInfo.h"
#include "nsMsgLineBuffer.h"
#include "nsIAsyncInputStream.h"
#include "nsITimer.h"
#include "nsAutoPtr.h"
#include "nsIMsgFolder.h"
#include "nsIMsgAsyncPrompter.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsSyncRunnableHelpers.h"
#include "nsICacheEntryOpenCallback.h"

class nsIMAPMessagePartIDArray;
class nsIMsgIncomingServer;
class nsIPrefBranch;
class nsIMAPMailboxInfo;

#define kDownLoadCacheSize 16000 // 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;
};

// 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....

#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

class nsImapProtocol : public nsIImapProtocol,
                       public nsIRunnable,
                       public nsIInputStreamCallback,
                       public nsSupportsWeakReference,
                       public nsMsgProtocol,
                       public nsIImapProtocolSink,
                       public nsIMsgAsyncPromptListener
{
public:

  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_NSIINPUTSTREAMCALLBACK
  nsImapProtocol();

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

  // nsIRunnable method
  NS_IMETHOD Run() 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);
  virtual void PipelinedFetchMessageParts(nsCString &uid, nsIMAPMessagePartIDArray *parts);
  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();
  void  PseudoInterrupt(bool the_interrupt);

  uint32_t GetMessageSize(const char * messageId, bool idsAreUids);
  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);

  void ProgressEventFunctionUsingName(const char* aMsgId);
  void ProgressEventFunctionUsingNameWithString(const char* aMsgName, const char *
    aExtraInfo);
  void PercentProgressUpdateEvent(char16_t *message, 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 Close(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);
  void PipelinedFetchMessageParts(const char *uid, nsIMAPMessagePartIDArray *parts);


  // 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(nsCString& aQuotaRoot, uint32_t aUsed, uint32_t aMax);

  bool GetPreferPlainText() { return m_preferPlainText; }

  int32_t GetCurFetchSize() { return m_curFetchSize; }

  const nsString &GetEmptyMimePartString() { return m_emptyMimePartString; }
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;
  nsCOMPtr<nsIImapUrl> m_runningUrl; // the nsIImapURL that is currently running
  nsImapAction m_imapAction;  // current imap action associated with this connnection...

  nsCString             m_hostName;
  nsCString             m_userName;
  nsCString             m_serverKey;
  nsCString             m_realHostName;
  char                  *m_dataOutputBuf;
  nsMsgLineStreamBuffer * m_inputStreamBuffer;
  uint32_t              m_allocatedSize; // allocated size
  uint32_t        m_totalDataSize; // total data size
  uint32_t        m_curReadIndex;  // current read index
  nsCString       m_trashFolderName;

  // Ouput stream for writing commands to the socket
  nsCOMPtr<nsISocketTransport>  m_transport;

  nsCOMPtr<nsIAsyncInputStream>   m_channelInputStream;
  nsCOMPtr<nsIAsyncOutputStream>  m_channelOutputStream;
  nsCOMPtr<nsIImapMockChannel>    m_mockChannel;   // this is the channel we should forward to people
  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 *******
  nsCOMPtr<nsIThread>      m_iThread;
  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.
  nsCString m_password;
  // Set to the result of nsImapServer::PromptPassword
  nsresult    m_passwordStatus;

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

  bool        m_nextUrlReadyToRun;
  nsWeakPtr   m_server;

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

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

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

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

  // 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(uint32_t **msgIdList, uint32_t &msgCount);
  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;
  uint32_t  m_fetchBodyCount;
  uint32_t  *m_fetchBodyIdList;

  // initialization function given a new url and transport layer
  nsresult  SetupWithUrl(nsIURI * aURL, nsISupports* aConsumer);
  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 authenication 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;

  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(nsCString &password, bool aNewPasswordRequested);
#ifdef MOZ_MAILNEWS_OAUTH2
  void InitPrefAuthMethods(int32_t authMethodPrefValue, nsIMsgIncomingServer *aServer);
#else
  void InitPrefAuthMethods(int32_t authMethodPrefValue);
#endif
  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 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 AuthLogin(const char *userName, const nsCString &password, eIMAPCapabilityFlag flag);
  void ProcessAuthenticatedStateURL();
  void ProcessAfterAuthenticated();
  void ProcessSelectedStateURL();
  bool TryToLogon();

  // Process Authenticated State Url 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);
  nsCString CreatePossibleTrashName(const char *prefix);
  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();
  bool IsExtraSelectNeeded();
  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;
  uint32_t mFolderNumDeleted;

  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
  nsDataHashtable<nsCStringHashKey, int32_t> m_standardListMailboxes;
  // mapping between special xlist mailboxes and the corresponding folder flags
  nsDataHashtable<nsCStringHashKey, int32_t> m_specialXListMailboxes;


  nsIImapHostSessionList * m_hostSessionList;

  bool m_fromHeaderSeen;

  // these settings allow clients to override various pieces of the connection info from the url
  bool m_overRideUrlConnectionInfo;

  nsCString m_logonHost;
  nsCString m_logonCookie;
  int16_t m_logonPort;
  
  nsString mAcceptLanguages;
  
  // progress stuff
  void SetProgressString(const char* stringName);
  
  nsString m_progressString;
  nsCString     m_progressStringName;
  int32_t       m_progressIndex;
  int32_t       m_progressCount;
  nsCString     m_lastProgressStringName;
  int32_t       m_lastPercent;
  int64_t       m_lastProgressTime;

  bool m_notifySearchHit;
  bool m_checkForNewMailDownloadsHeaders;
  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;
  nsCString m_forceSelectValue;
  bool m_forceSelect;

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

  enum EMailboxHierarchyNameState {
    kNoOperationInProgress,
      kDiscoverBaseFolderInProgress,
      kDiscoverTrashFolderInProgress,
      kDeleteSubFoldersInProgress,
      kListingForInfoOnly,
      kListingForInfoAndDiscovery,
      kDiscoveringNamespacesOnly,
      kXListing,
      kListingForFolderFlags,
      kListingForCreate
  };
  EMailboxHierarchyNameState  m_hierarchyNameState;
  EMailboxDiscoverStatus      m_discoveryStatus;
  nsTArray<nsIMAPMailboxInfo*> m_listedMailboxList;
  nsTArray<char*> *            m_deletableChildren;
  uint32_t                    m_flagChangeCount;
  PRTime                      m_lastCheckTime;

  bool CheckNeeded();

  nsString m_emptyMimePartString;

#ifdef MOZ_MAILNEWS_OAUTH2
  RefPtr<mozilla::mailnews::OAuth2ThreadHelper> mOAuth2Support;
#endif
};

// 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:
  friend class nsImapProtocol;

  NS_DECL_THREADSAFE_ISUPPORTS
  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;
  nsISupports * m_channelContext; 
  nsresult m_cancelStatus;
  nsLoadFlags mLoadFlags;
  nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
  nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
  nsCOMPtr<nsISupports> mOwner;
  nsCOMPtr<nsISupports> mSecurityInfo;
  nsCOMPtr<nsIRequest> mCacheRequest; // the request associated with a read from the cache
  nsCString mContentType;
  nsCString mCharset;
  nsWeakPtr mProtocol;

  bool mChannelClosed;
  bool mReadingFromCache;
  bool mTryingToReadPart;
  int64_t mContentLength;

  // 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 ReadFromImapConnection(); // creates a new imap connection to read the url
  nsresult ReadFromMemCache(nsICacheEntry *entry); // attempts to read the url out of our memory cache
  nsresult NotifyStartEndReadFromCache(bool start);

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

// 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;
};

#endif  // nsImapProtocol_h___