1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsImapProtocol_h___
7 #define nsImapProtocol_h___
8 
9 #include "mozilla/Attributes.h"
10 #include "nsIImapProtocol.h"
11 #include "nsIImapUrl.h"
12 
13 #include "nsMsgProtocol.h"
14 #include "nsIStreamListener.h"
15 #include "nsIAsyncOutputStream.h"
16 #include "nsIAsyncInputStream.h"
17 #include "nsImapCore.h"
18 #include "nsString.h"
19 #include "nsIProgressEventSink.h"
20 #include "nsIInterfaceRequestor.h"
21 #include "nsISocketTransport.h"
22 
23 // UI Thread proxy helper
24 #include "nsIImapProtocolSink.h"
25 
26 #include "nsIImapHostSessionList.h"
27 #include "nsImapServerResponseParser.h"
28 #include "nsImapFlagAndUidState.h"
29 #include "nsImapNamespace.h"
30 #include "nsTArray.h"
31 #include "nsIWeakReferenceUtils.h"
32 #include "nsMsgLineBuffer.h"  // we need this to use the nsMsgLineStreamBuffer helper class...
33 #include "nsIInputStream.h"
34 #include "nsIMsgIncomingServer.h"
35 #include "nsCOMArray.h"
36 #include "nsIThread.h"
37 #include "nsIRunnable.h"
38 #include "nsIImapMockChannel.h"
39 #include "nsILoadGroup.h"
40 #include "nsCOMPtr.h"
41 #include "nsIMsgWindow.h"
42 #include "nsIImapHeaderXferInfo.h"
43 #include "nsMsgLineBuffer.h"
44 #include "nsIAsyncInputStream.h"
45 #include "nsIMsgFolder.h"
46 #include "nsIMsgAsyncPrompter.h"
47 #include "mozilla/ReentrantMonitor.h"
48 #include "nsSyncRunnableHelpers.h"
49 #include "nsICacheEntryOpenCallback.h"
50 #include "nsIProtocolProxyCallback.h"
51 #include "nsIStringBundle.h"
52 #include "nsHashPropertyBag.h"
53 
54 #include "mozilla/Monitor.h"
55 
56 class nsIMAPMessagePartID;
57 class nsIPrefBranch;
58 
59 #define kDownLoadCacheSize 16000u  // was 1536 - try making it bigger
60 
61 typedef struct _msg_line_info {
62   const char* adoptedMessageLine;
63   uint32_t uidOfMessage;
64 } msg_line_info;
65 
66 class nsMsgImapLineDownloadCache : public nsIImapHeaderInfo,
67                                    public nsByteArray {
68  public:
69   NS_DECL_THREADSAFE_ISUPPORTS
70   NS_DECL_NSIIMAPHEADERINFO
71   nsMsgImapLineDownloadCache();
72   uint32_t CurrentUID();
73   uint32_t SpaceAvailable();
74   bool CacheEmpty();
75 
76   msg_line_info* GetCurrentLineInfo();
77 
78  private:
79   virtual ~nsMsgImapLineDownloadCache();
80 
81   msg_line_info* fLineInfo;
82   int32_t m_msgSize;
83 };
84 
85 #define kNumHdrsToXfer 10
86 
87 class nsMsgImapHdrXferInfo : public nsIImapHeaderXferInfo {
88  public:
89   NS_DECL_THREADSAFE_ISUPPORTS
90   NS_DECL_NSIIMAPHEADERXFERINFO
91   nsMsgImapHdrXferInfo();
92   void ResetAll();    // reset HeaderInfos for re-use
93   void ReleaseAll();  // release HeaderInfos (frees up memory)
94   // this will return null if we're full, in which case the client code
95   // should transfer the headers and retry.
96   nsIImapHeaderInfo* StartNewHdr();
97   // call when we've finished adding lines to current hdr
98   void FinishCurrentHdr();
99 
100  private:
101   virtual ~nsMsgImapHdrXferInfo();
102   nsCOMArray<nsIImapHeaderInfo> m_hdrInfos;
103   int32_t m_nextFreeHdrInfo;
104 };
105 
106 // This class contains the name of a mailbox and whether or not
107 // its children have been listed.
108 class nsIMAPMailboxInfo {
109  public:
110   nsIMAPMailboxInfo(const nsACString& aName, char aDelimiter);
111   virtual ~nsIMAPMailboxInfo();
112 
113   void SetChildrenListed(bool childrenListed);
114   bool GetChildrenListed();
115   const nsACString& GetMailboxName();
116   char GetDelimiter();
117 
118  protected:
119   nsCString mMailboxName;
120   bool mChildrenListed;
121   char mDelimiter;
122 };
123 
124 // State Flags (Note, I use the word state in terms of storing
125 // state information about the connection (authentication, have we sent
126 // commands, etc. I do not intend it to refer to protocol state)
127 // Use these flags in conjunction with SetFlag/TestFlag/ClearFlag instead
128 // of creating PRBools for everything....
129 // clang-format off
130 #define IMAP_RECEIVED_GREETING        0x00000001  // should we pause for the next read
131 #define  IMAP_CONNECTION_IS_OPEN      0x00000004  // is the connection currently open?
132 #define IMAP_WAITING_FOR_DATA         0x00000008
133 #define IMAP_CLEAN_UP_URL_STATE       0x00000010  // processing clean up url state
134 #define IMAP_ISSUED_LANGUAGE_REQUEST  0x00000020  // make sure we only issue the language
135                                                   // request once per connection...
136 #define IMAP_ISSUED_COMPRESS_REQUEST  0x00000040  // make sure we only request compression once
137 
138 // There are 3 types of progress strings for items downloaded from IMAP servers.
139 // An index is needed to keep track of the current count of the number of each
140 // item type downloaded. The IMAP_EMPTY_STRING_INDEX means no string displayed.
141 #define IMAP_NUMBER_OF_PROGRESS_STRINGS 4
142 #define IMAP_HEADERS_STRING_INDEX       0
143 #define IMAP_FLAGS_STRING_INDEX         1
144 #define IMAP_MESSAGES_STRING_INDEX      2
145 #define IMAP_EMPTY_STRING_INDEX         3
146 // clang-format on
147 
148 /**
149  * nsImapProtocol is, among other things, the underlying nsIChannel
150  * implementation for the IMAP protocol. However, it's usually hidden away
151  * behind nsImapMockChannel objects. It also represents the 'real' connection
152  * to the IMAP server - it maintains the nsISocketTransport.
153  * Because there can be multiple IMAP requests queued up, NS_NewChannel()
154  * will return nsImapMockChannel objects instead, to keep the request in a
155  * holding pattern until the connection is free. At which time the mock
156  * channel will just forward calls onward to the nsImapProtocol.
157  *
158  * The url scheme we implement here encodes various IMAP commands as URLs.
159  * Some URLs are just traditional I/O based nsIChannel transactions, but
160  * many others have side effects. For example, an IMAP folder discovery
161  * command might cause the creation of the nsImapMailFolder hierarchy under
162  * the the nsImapIncomingServer.
163  * Such side effects are communicated via the various "Sink" interfaces. This
164  * helps decouple the IMAP code from the rest of the system:
165  *
166  * - nsIImapServerSink      (implemented by nsImapIncomingServer)
167  * - nsIImapMailFolderSink  (implemented by nsImapMailFolder)
168  * - nsIImapMessageSink     (implemented by nsImapMailFolder)
169  *
170  * Internal to nsImapProtocol, these sink classes all have corresponding proxy
171  * implementations (ImapServerSinkProxy, ImapMailFolderSinkProxy and
172  * ImapMessageSinkProxy). These allow us to safely call the sink objects, in
173  * a synchronous fashion, from I/O threads (threads other than the main one).
174  * When an IMAP routine calls a member function of one of these sink proxies,
175  * it dispatches a call to the real sink object on the main thread, then
176  * blocks until the call is completed.
177  */
178 class nsImapProtocol : public nsIImapProtocol,
179                        public nsIInputStreamCallback,
180                        public nsSupportsWeakReference,
181                        public nsMsgProtocol,
182                        public nsIImapProtocolSink,
183                        public nsIMsgAsyncPromptListener,
184                        public nsIProtocolProxyCallback {
185  public:
186   struct TCPKeepalive {
187     // For enabling and setting TCP keepalive (not related to IMAP IDLE).
188     std::atomic<bool> enabled;
189     std::atomic<int32_t> idleTimeS;
190     std::atomic<int32_t> retryIntervalS;
191   };
192 
193   NS_DECL_ISUPPORTS_INHERITED
194   NS_DECL_NSIINPUTSTREAMCALLBACK
195   NS_DECL_NSIPROTOCOLPROXYCALLBACK
196   nsImapProtocol();
197 
198   virtual nsresult ProcessProtocolState(nsIURI* url,
199                                         nsIInputStream* inputStream,
200                                         uint64_t sourceOffset,
201                                         uint32_t length) override;
202 
203   //////////////////////////////////////////////////////////////////////////////////
204   // we support the nsIImapProtocol interface
205   //////////////////////////////////////////////////////////////////////////////////
206   NS_DECL_NSIIMAPPROTOCOL
207 
208   //////////////////////////////////////////////////////////////////////////////////
209   // we support the nsIImapProtocolSink interface
210   //////////////////////////////////////////////////////////////////////////////////
211   NS_DECL_NSIIMAPPROTOCOLSINK
212 
213   NS_DECL_NSIMSGASYNCPROMPTLISTENER
214 
215   // message id string utilities.
216   uint32_t CountMessagesInIdString(const char* idString);
217   static bool HandlingMultipleMessages(const nsCString& messageIdString);
218   // escape slashes and double quotes in username/passwords for insecure login.
219   static void EscapeUserNamePasswordString(const char* strToEscape,
220                                            nsCString* resultStr);
221 
222   // used to start fetching a message.
223   void GetShouldDownloadAllHeaders(bool* aResult);
224   void GetArbitraryHeadersToDownload(nsCString& aResult);
225   virtual void AdjustChunkSize();
226   virtual void FetchMessage(const nsCString& messageIds,
227                             nsIMAPeFetchFields whatToFetch,
228                             const char* fetchModifier = nullptr,
229                             uint32_t startByte = 0, uint32_t numBytes = 0,
230                             char* part = 0);
231   void FetchTryChunking(const nsCString& messageIds,
232                         nsIMAPeFetchFields whatToFetch, bool idIsUid,
233                         char* part, uint32_t downloadSize, bool tryChunking);
234   virtual void PipelinedFetchMessageParts(
235       nsCString& uid, const nsTArray<nsIMAPMessagePartID>& parts);
236   void FallbackToFetchWholeMsg(const nsCString& messageId,
237                                uint32_t messageSize);
238   // used when streaming a message fetch
239   virtual nsresult BeginMessageDownLoad(
240       uint32_t totalSize,        // for user, headers and body
241       const char* contentType);  // some downloads are header only
242   virtual void HandleMessageDownLoadLine(const char* line, bool isPartialLine,
243                                          char* lineCopy = nullptr);
244   virtual void NormalMessageEndDownload();
245   virtual void AbortMessageDownLoad();
246   virtual void PostLineDownLoadEvent(const char* line, uint32_t uid);
247   void FlushDownloadCache();
248 
249   virtual void SetMailboxDiscoveryStatus(EMailboxDiscoverStatus status);
250   virtual EMailboxDiscoverStatus GetMailboxDiscoveryStatus();
251 
252   virtual void ProcessMailboxUpdate(bool handlePossibleUndo);
253   // Send log output...
254   void Log(const char* logSubName, const char* extraInfo, const char* logData);
255   static void LogImapUrl(const char* logMsg, nsIImapUrl* imapUrl);
256   // Comment from 4.5: We really need to break out the thread synchronizer from
257   // the connection class...Not sure what this means
258   bool GetPseudoInterrupted();
259   void PseudoInterrupt(bool the_interrupt);
260 
261   uint32_t GetMessageSize(const nsACString& messageId);
262   bool GetSubscribingNow();
263 
264   bool DeathSignalReceived();
265   void ResetProgressInfo();
266   void SetActive(bool active);
267   bool GetActive();
268 
269   bool GetShowAttachmentsInline();
270 
271   // Sets whether or not the content referenced by the current ActiveEntry has
272   // been modified. Used for MIME parts on demand.
273   void SetContentModified(IMAP_ContentModifiedType modified);
274   bool GetShouldFetchAllParts();
GetIgnoreExpunges()275   bool GetIgnoreExpunges() { return m_ignoreExpunges; }
276   // Generic accessors required by the imap parser
277   char* CreateNewLineFromSocket();
278   nsresult GetConnectionStatus();
279   void SetConnectionStatus(nsresult status);
280 
281   // Cleanup the connection and shutdown the thread.
282   void TellThreadToDie();
283 
284   const nsCString&
285   GetImapHostName();  // return the host name from the url for the
286   // current connection
287   const nsCString& GetImapUserName();  // return the user name from the identity
288   const char*
289   GetImapServerKey();  // return the user name from the incoming server;
290 
291   // state set by the imap parser...
292   void NotifyMessageFlags(imapMessageFlagsType flags,
293                           const nsACString& keywords, nsMsgKey key,
294                           uint64_t highestModSeq);
295   void NotifySearchHit(const char* hitLine);
296 
297   // Event handlers for the imap parser.
298   void DiscoverMailboxSpec(nsImapMailboxSpec* adoptedBoxSpec);
299   void AlertUserEventUsingName(const char* aMessageId);
300   void AlertUserEvent(const char* message);
301   void AlertUserEventFromServer(const char* aServerEvent,
302                                 bool aForIdle = false);
303 
304   void ProgressEventFunctionUsingName(const char* aMsgId);
305   void ProgressEventFunctionUsingNameWithString(const char* aMsgName,
306                                                 const char* aExtraInfo);
307   void PercentProgressUpdateEvent(nsACString const& fmtStringName,
308                                   nsAString const& mailbox,
309                                   int64_t currentProgress, int64_t maxProgress);
310   void ShowProgress();
311 
312   // utility function calls made by the server
313 
314   void Copy(const char* messageList, const char* destinationMailbox,
315             bool idsAreUid);
316   void Search(const char* searchCriteria, bool useUID, bool notifyHit = true);
317   // imap commands issued by the parser
318   void Store(const nsCString& aMessageList, const char* aMessageData,
319              bool aIdsAreUid);
320   void ProcessStoreFlags(const nsCString& messageIds, bool idsAreUids,
321                          imapMessageFlagsType flags, bool addFlags);
322   void IssueUserDefinedMsgCommand(const char* command, const char* messageList);
323   void FetchMsgAttribute(const nsCString& messageIds,
324                          const nsCString& attribute);
325   void Expunge();
326   void UidExpunge(const nsCString& messageSet);
327   void Close(bool shuttingDown = false, bool waitForResponse = true);
328   void Check();
329   void SelectMailbox(const char* mailboxName);
330   // more imap commands
331   void Logout(bool shuttingDown = false, bool waitForResponse = true);
332   void Noop();
333   void XServerInfo();
334   void Netscape();
335   void XMailboxInfo(const char* mailboxName);
336   void XAOL_Option(const char* option);
337   void MailboxData();
338   void GetMyRightsForFolder(const char* mailboxName);
339   void Bodystructure(const nsCString& messageId, bool idIsUid);
340   void PipelinedFetchMessageParts(const char* uid,
341                                   const nsTArray<nsIMAPMessagePartID>& parts);
342 
343   // this function does not ref count!!! be careful!!!
GetCurrentUrl()344   nsIImapUrl* GetCurrentUrl() { return m_runningUrl; }
345 
346   // acl and namespace stuff
347   // notifies libmsg that we have a new personal/default namespace that we're
348   // using
349   void CommitNamespacesForHostEvent();
350   // notifies libmsg that we have new capability data for the current host
351   void CommitCapability();
352 
353   // Adds a set of rights for a given user on a given mailbox on the current
354   // host. if userName is NULL, it means "me," or MYRIGHTS. rights is a single
355   // string of rights, as specified by RFC2086, the IMAP ACL extension.
356   void AddFolderRightsForUser(const char* mailboxName, const char* userName,
357                               const char* rights);
358   // Clears all rights for the current folder, for all users.
359   void ClearAllFolderRights();
360   void RefreshFolderACLView(const char* mailboxName,
361                             nsImapNamespace* nsForMailbox);
362 
363   nsresult SetFolderAdminUrl(const char* mailboxName);
364   void HandleMemoryFailure();
365   void HandleCurrentUrlError();
366 
367   // UIDPLUS extension
368   void SetCopyResponseUid(const char* msgIdString);
369 
370   // Quota support
371   void UpdateFolderQuotaData(nsImapQuotaAction aAction, nsCString& aQuotaRoot,
372                              uint64_t aUsed, uint64_t aMax);
373 
GetPreferPlainText()374   bool GetPreferPlainText() { return m_preferPlainText; }
375 
GetCurFetchSize()376   int32_t GetCurFetchSize() { return m_curFetchSize; }
377 
GetEmptyMimePartString()378   const nsString& GetEmptyMimePartString() { return m_emptyMimePartString; }
379   void SetCapabilityResponseOccurred();
380 
381   // Start event loop. This is called on IMAP thread
382   bool RunImapThreadMainLoop();
383 
384  private:
385   virtual ~nsImapProtocol();
386   // the following flag is used to determine when a url is currently being run.
387   // It is cleared when we finish processng a url and it is set whenever we call
388   // Load on a url
389   bool m_urlInProgress;
390 
391   /** The nsIImapURL that is currently running. */
392   nsCOMPtr<nsIImapUrl> m_runningUrl;
393   nsCOMPtr<nsIImapUrl> m_runningUrlLatest;
394   /** Current imap action associated with this connection. */
395   nsImapAction m_imapAction;
396 
397   nsCString m_hostName;
398   nsCString m_userName;
399   nsCString m_serverKey;
400   nsCString m_realHostName;
401   char* m_dataOutputBuf;
402   RefPtr<nsMsgLineStreamBuffer> m_inputStreamBuffer;
403   nsCString m_trashFolderPath;
404 
405   /** The socket connection to the IMAP server. */
406   nsCOMPtr<nsISocketTransport> m_transport;
407 
408   /** Stream to handle data coming in from the IMAP server. */
409   nsCOMPtr<nsIInputStream> m_inputStream;
410 
411   nsCOMPtr<nsIAsyncInputStream> m_channelInputStream;
412   nsCOMPtr<nsIAsyncOutputStream> m_channelOutputStream;
413 
414   /** The currently running request. */
415   nsCOMPtr<nsIImapMockChannel> m_mockChannel;
416 
417   uint32_t m_bytesToChannel;
418   bool m_fetchingWholeMessage;
419   // nsCOMPtr<nsIRequest> mAsyncReadRequest; // we're going to cancel this when
420   // we're done with the conn.
421 
422   // ******* Thread support *******
423   PRThread* m_thread;
424   mozilla::ReentrantMonitor
425       m_dataAvailableMonitor;  // used to notify the arrival of data from the
426                                // server
427   mozilla::ReentrantMonitor
428       m_urlReadyToRunMonitor;  // used to notify the arrival of a new url to be
429                                // processed
430   mozilla::ReentrantMonitor m_pseudoInterruptMonitor;
431   mozilla::ReentrantMonitor m_dataMemberMonitor;
432   mozilla::ReentrantMonitor m_threadDeathMonitor;
433   mozilla::ReentrantMonitor m_waitForBodyIdsMonitor;
434   mozilla::ReentrantMonitor m_fetchBodyListMonitor;
435   mozilla::ReentrantMonitor m_passwordReadyMonitor;
436   mozilla::Mutex mLock;
437   // If we get an async password prompt, this is where the UI thread
438   // stores the password, before notifying the imap thread of the password
439   // via the m_passwordReadyMonitor.
440   nsString m_password;
441   // Set to the result of nsImapServer::PromptPassword
442   nsresult m_passwordStatus;
443   bool m_passwordObtained;
444 
445   bool m_imapThreadIsRunning;
446   void ImapThreadMainLoop(void);
447   nsresult m_connectionStatus;
448   nsCString m_connectionType;
449 
450   bool m_nextUrlReadyToRun;
451   nsWeakPtr m_server;
452 
453   RefPtr<ImapMailFolderSinkProxy> m_imapMailFolderSink;
454   RefPtr<ImapMessageSinkProxy> m_imapMessageSink;
455   RefPtr<ImapServerSinkProxy> m_imapServerSink;
456   RefPtr<ImapServerSinkProxy> m_imapServerSinkLatest;
457   RefPtr<ImapProtocolSinkProxy> m_imapProtocolSink;
458 
459   // helper function to setup imap sink interface proxies
460   nsresult SetupSinkProxy();
461   // End thread support stuff
462   nsresult LoadImapUrlInternal();
463 
464   bool GetDeleteIsMoveToTrash();
465   bool GetShowDeletedMessages();
466   nsCString m_currentCommand;
467   nsImapServerResponseParser m_parser;
GetServerStateParser()468   nsImapServerResponseParser& GetServerStateParser() { return m_parser; }
469 
470   void HandleIdleResponses();
471   virtual bool ProcessCurrentURL();
472   void EstablishServerConnection();
473   virtual void ParseIMAPandCheckForNewMail(const char* commandString = nullptr,
474                                            bool ignoreBadNOResponses = false);
475   // biff
476   void PeriodicBiff();
477   void SendSetBiffIndicatorEvent(nsMsgBiffState newState);
478 
479   // folder opening and listing header functions
480   void FolderHeaderDump(uint32_t* msgUids, uint32_t msgCount);
481   void FolderMsgDump(uint32_t* msgUids, uint32_t msgCount,
482                      nsIMAPeFetchFields fields);
483   void FolderMsgDumpLoop(uint32_t* msgUids, uint32_t msgCount,
484                          nsIMAPeFetchFields fields);
485   void WaitForPotentialListOfBodysToFetch(nsTArray<nsMsgKey>& msgIdList);
486   void HeaderFetchCompleted();
487   void UploadMessageFromFile(nsIFile* file, const char* mailboxName,
488                              PRTime date, imapMessageFlagsType flags,
489                              nsCString& keywords);
490 
491   // mailbox name utilities.
492   void CreateEscapedMailboxName(const char* rawName, nsCString& escapedName);
493   void SetupMessageFlagsString(nsCString& flagString,
494                                imapMessageFlagsType flags, uint16_t userFlags);
495 
496   // body fetching listing data
497   bool m_fetchBodyListIsNew;
498   nsTArray<nsMsgKey> m_fetchBodyIdList;
499 
500   // initialization function given a new url and transport layer
501   nsresult SetupWithUrl(nsIURI* aURL, nsISupports* aConsumer);
502   nsresult SetupWithUrlCallback(nsIProxyInfo* proxyInfo);
503   void ReleaseUrlState(bool rerunningUrl);  // release any state that is stored
504                                             // on a per action basis.
505   /**
506    * Last ditch effort to run the url without using an imap connection.
507    * If it turns out that we don't need to run the url at all (e.g., we're
508    * trying to download a single message for offline use and it has already
509    * been downloaded, this function will send the appropriate notifications.
510    *
511    * @returns true if the url has been run locally, or doesn't need to be run.
512    */
513   bool TryToRunUrlLocally(nsIURI* aURL, nsISupports* aConsumer);
514 
515   ////////////////////////////////////////////////////////////////////////////////////////
516   // Communication methods --> Reading and writing protocol
517   ////////////////////////////////////////////////////////////////////////////////////////
518 
519   // SendData not only writes the NULL terminated data in dataBuffer to our
520   // output stream but it also informs the consumer that the data has been
521   // written to the stream. aSuppressLogging --> set to true if you wish to
522   // suppress logging for this particular command. this is useful for making
523   // sure we don't log authentication information like the user's password
524   // (which was encoded anyway), but still we shouldn't add that information to
525   // the log.
526   nsresult SendData(const char* dataBuffer,
527                     bool aSuppressLogging = false) override;
528 
529   // state ported over from 4.5
530   bool m_pseudoInterrupted;
531   bool m_active;
532   bool m_folderNeedsSubscribing;
533   bool m_folderNeedsACLRefreshed;
534 
535   bool m_threadShouldDie;
536 
537   // use to prevent re-entering TellThreadToDie.
538   bool m_inThreadShouldDie;
539   // if the UI thread has signalled the IMAP thread to die, and the
540   // connection has timed out, this will be set to FALSE.
541   bool m_safeToCloseConnection;
542 
543   RefPtr<nsImapFlagAndUidState> m_flagState;
544   nsMsgBiffState m_currentBiffState;
545   // manage the IMAP server command tags
546   // 11 = enough memory for the decimal representation of MAX_UINT + trailing
547   // nul
548   char m_currentServerCommandTag[11];
549   uint32_t m_currentServerCommandTagNumber;
550   void IncrementCommandTagNumber();
551   const char* GetServerCommandTag();
552 
553   void StartTLS();
554 
555   // login related methods.
556   nsresult GetPassword(nsString& password, bool aNewPasswordRequested);
557   void InitPrefAuthMethods(int32_t authMethodPrefValue,
558                            nsIMsgIncomingServer* aServer);
559   nsresult ChooseAuthMethod();
560   void MarkAuthMethodAsFailed(eIMAPCapabilityFlags failedAuthMethod);
561   void ResetAuthMethods();
562 
563   // All of these methods actually issue protocol
564   void Capability();  // query host for capabilities.
565   void ID();          // send RFC 2971 app info to server
566   void EnableUTF8Accept();
567   void EnableCondStore();
568   void StartCompressDeflate();
569   nsresult BeginCompressing();
570   void Language();  // set the language on the server if it supports it
571   void Namespace();
572   void InsecureLogin(const char* userName, const nsCString& password);
573   nsresult ClientID();
574   nsresult AuthLogin(const char* userName, const nsString& password,
575                      eIMAPCapabilityFlag flag);
576   nsresult SendDataParseIMAPandCheckForNewMail(const char* data,
577                                                const char* command);
578   void ProcessAuthenticatedStateURL();
579   void ProcessAfterAuthenticated();
580   void ProcessSelectedStateURL();
581   bool TryToLogon();
582 
583   // Process Authenticated State Url used to be one giant if statement. I've
584   // broken out a set of actions based on the imap action passed into the url.
585   // The following functions are imap protocol handlers for each action. They
586   // are called by ProcessAuthenticatedStateUrl.
587   void OnLSubFolders();
588   void OnAppendMsgFromFile();
589 
590   char* GetFolderPathString();  // OK to call from UI thread
591 
592   char* OnCreateServerSourceFolderPathString();
593   char* OnCreateServerDestinationFolderPathString();
594   nsresult CreateServerSourceFolderPathString(char** result);
595   void OnCreateFolder(const char* aSourceMailbox);
596   void OnEnsureExistsFolder(const char* aSourceMailbox);
597   void OnSubscribe(const char* aSourceMailbox);
598   void OnUnsubscribe(const char* aSourceMailbox);
599   void RefreshACLForFolderIfNecessary(const char* mailboxName);
600   void RefreshACLForFolder(const char* aSourceMailbox);
601   void GetACLForFolder(const char* aMailboxName);
602   void OnRefreshAllACLs();
603   void OnListFolder(const char* aSourceMailbox, bool aBool);
604   void OnStatusForFolder(const char* sourceMailbox);
605   void OnDeleteFolder(const char* aSourceMailbox);
606   void OnRenameFolder(const char* aSourceMailbox);
607   void OnMoveFolderHierarchy(const char* aSourceMailbox);
608   void DeleteFolderAndMsgs(const char* aSourceMailbox);
609   void RemoveMsgsAndExpunge();
610   void FindMailboxesIfNecessary();
611   void CreateMailbox(const char* mailboxName);
612   void DeleteMailbox(const char* mailboxName);
613   void RenameMailbox(const char* existingName, const char* newName);
614   void RemoveHierarchyDelimiter(nsCString& mailboxName);
615   bool CreateMailboxRespectingSubscriptions(const char* mailboxName);
616   bool DeleteMailboxRespectingSubscriptions(const char* mailboxName);
617   bool RenameMailboxRespectingSubscriptions(const char* existingName,
618                                             const char* newName,
619                                             bool reallyRename);
620   // notify the fe that a folder was deleted
621   void FolderDeleted(const char* mailboxName);
622   // notify the fe that a folder creation failed
623   void FolderNotCreated(const char* mailboxName);
624   // notify the fe that a folder was deleted
625   void FolderRenamed(const char* oldName, const char* newName);
626 
627   bool FolderIsSelected(const char* mailboxName);
628 
629   bool MailboxIsNoSelectMailbox(const char* mailboxName);
630   bool FolderNeedsACLInitialized(const char* folderName);
631   void DiscoverMailboxList();
632   void DiscoverAllAndSubscribedBoxes();
633   void MailboxDiscoveryFinished();
634   void NthLevelChildList(const char* onlineMailboxPrefix, int32_t depth);
635   // LIST SUBSCRIBED command (from RFC 5258) crashes some servers. so we need to
636   // identify those servers
637   bool GetListSubscribedIsBrokenOnServer();
638   bool IsExtraSelectNeeded();
639   void Lsub(const char* mailboxPattern, bool addDirectoryIfNecessary);
640   void List(const char* mailboxPattern, bool addDirectoryIfNecessary,
641             bool useXLIST = false);
642   void Subscribe(const char* mailboxName);
643   void Unsubscribe(const char* mailboxName);
644   void Idle();
645   void EndIdle(bool waitForResponse = true);
646   // Some imap servers include the mailboxName following the dir-separator in
647   // the list of subfolders of the mailboxName. In fact, they are the same. So
648   // we should decide if we should delete such subfolder and provide feedback if
649   // the delete operation succeed.
650   bool DeleteSubFolders(const char* aMailboxName, bool& aDeleteSelf);
651   bool RenameHierarchyByHand(const char* oldParentMailboxName,
652                              const char* newParentMailboxName);
653   bool RetryUrl();
654 
655   nsresult GlobalInitialization(nsIPrefBranch* aPrefBranch);
656   nsresult Configure(int32_t TooFastTime, int32_t IdealTime,
657                      int32_t ChunkAddSize, int32_t ChunkSize,
658                      int32_t ChunkThreshold, bool FetchByChunks);
659   nsresult GetMsgWindow(nsIMsgWindow** aMsgWindow);
660   // End Process AuthenticatedState Url helper methods
661 
GetType()662   virtual char const* GetType() override { return "imap"; }
663 
664   // Quota support
665   void GetQuotaDataIfSupported(const char* aBoxName);
666 
667   // CondStore support - true if server supports it, and the user hasn't
668   // disabled it.
669   bool UseCondStore();
670   // false if pref "mail.server.serverxxx.use_condstore" is false;
671   bool m_useCondStore;
672   // COMPRESS=DEFLATE support - true if server supports it, and the user hasn't
673   // disabled it.
674   bool UseCompressDeflate();
675   // false if pref "mail.server.serverxxx.use_compress_deflate" is false;
676   bool m_useCompressDeflate;
677   // these come from the nsIDBFolderInfo in the msgDatabase and
678   // are initialized in nsImapProtocol::SetupWithUrl.
679   uint64_t mFolderLastModSeq;
680   int32_t mFolderTotalMsgCount;
681   uint32_t mFolderHighestUID;
682   uint32_t mFolderNumDeleted;
683   bool m_allowUTF8Accept;
684 
685   bool m_isGmailServer;
686   nsTArray<nsCString> mCustomDBHeaders;
687   nsTArray<nsCString> mCustomHeaders;
688   bool m_trackingTime;
689   PRTime m_startTime;
690   PRTime m_endTime;
691   PRTime m_lastActiveTime;
692   int32_t m_tooFastTime;
693   int32_t m_idealTime;
694   int32_t m_chunkAddSize;
695   int32_t m_chunkStartSize;
696   bool m_fetchByChunks;
697   bool m_sendID;
698   int32_t m_curFetchSize;
699   bool m_ignoreExpunges;
700   eIMAPCapabilityFlags m_prefAuthMethods;    // set of capability flags (in
701                                              // nsImapCore.h) for auth methods
702   eIMAPCapabilityFlags m_failedAuthMethods;  // ditto
703   eIMAPCapabilityFlag m_currentAuthMethod;  // exactly one capability flag, or 0
704   int32_t m_socketType;
705   int32_t m_chunkSize;
706   int32_t m_chunkThreshold;
707   RefPtr<nsMsgImapLineDownloadCache> m_downloadLineCache;
708   RefPtr<nsMsgImapHdrXferInfo> m_hdrDownloadCache;
709   nsCOMPtr<nsIImapHeaderInfo> m_curHdrInfo;
710   // mapping between mailboxes and the corresponding folder flags
711   nsTHashMap<nsCStringHashKey, int32_t> m_standardListMailboxes;
712   // mapping between special xlist mailboxes and the corresponding folder flags
713   nsTHashMap<nsCStringHashKey, int32_t> m_specialXListMailboxes;
714 
715   nsCOMPtr<nsIImapHostSessionList> m_hostSessionList;
716 
717   bool m_fromHeaderSeen;
718 
719   nsString mAcceptLanguages;
720 
721   nsCString m_clientId;
722 
723   // progress stuff
724   void SetProgressString(uint32_t aStringIndex);
725 
726   nsCString m_progressStringName;
727   uint32_t m_stringIndex;
728   int32_t m_progressCurrentNumber[IMAP_NUMBER_OF_PROGRESS_STRINGS];
729   int32_t m_progressExpectedNumber;
730   nsCString m_lastProgressStringName;
731   int32_t m_lastPercent;
732   int64_t m_lastProgressTime;
733 
734   bool m_notifySearchHit;
735   bool m_needNoop;
736   bool m_idle;
737   bool m_useIdle;
738   int32_t m_noopCount;
739   bool m_autoSubscribe, m_autoUnsubscribe, m_autoSubscribeOnOpen;
740   bool m_closeNeededBeforeSelect;
741   bool m_retryUrlOnError;
742   bool m_preferPlainText;
743   nsCString m_forceSelectValue;
744   bool m_forceSelect;
745 
746   int32_t m_uidValidity;  // stored uid validity for the selected folder.
747 
748   enum EMailboxHierarchyNameState {
749     kNoOperationInProgress,
750     // kDiscoverBaseFolderInProgress, - Unused. Keeping for historical reasons.
751     kDiscoverTrashFolderInProgress,
752     kDeleteSubFoldersInProgress,
753     kListingForInfoOnly,
754     kListingForInfoAndDiscovery,
755     kDiscoveringNamespacesOnly,
756     kXListing,
757     kListingForFolderFlags,
758     kListingForCreate
759   };
760   EMailboxHierarchyNameState m_hierarchyNameState;
761   EMailboxDiscoverStatus m_discoveryStatus;
762   nsTArray<nsIMAPMailboxInfo*> m_listedMailboxList;
763   nsTArray<char*>* m_deletableChildren;
764   uint32_t m_flagChangeCount;
765   PRTime m_lastCheckTime;
766 
767   bool CheckNeeded();
768 
769   nsString m_emptyMimePartString;
770 
771   RefPtr<mozilla::mailnews::OAuth2ThreadHelper> mOAuth2Support;
772   bool m_capabilityResponseOccurred;
773 };
774 
775 // This small class is a "mock" channel because it is a mockery of the imap
776 // channel's implementation... it's a light weight channel that we can return to
777 // necko when they ask for a channel on a url before we actually have an imap
778 // protocol instance around which can run the url. Please see my comments in
779 // nsIImapMockChannel.idl for more details..
780 //
781 // Threading concern: This class lives entirely in the UI thread.
782 
783 class nsICacheEntry;
784 
785 class nsImapMockChannel : public nsIImapMockChannel,
786                           public nsICacheEntryOpenCallback,
787                           public nsITransportEventSink,
788                           public nsSupportsWeakReference,
789                           public nsHashPropertyBag {
790  public:
791   friend class nsImapProtocol;
792 
793   NS_DECL_ISUPPORTS_INHERITED
794   NS_DECL_NSIIMAPMOCKCHANNEL
795   NS_DECL_NSICHANNEL
796   NS_DECL_NSIREQUEST
797   NS_DECL_NSICACHEENTRYOPENCALLBACK
798   NS_DECL_NSITRANSPORTEVENTSINK
799 
800   nsImapMockChannel();
801   static nsresult Create(const nsIID& iid, void** result);
802   nsresult RunOnStopRequestFailure();
803 
804  protected:
805   virtual ~nsImapMockChannel();
806   nsCOMPtr<nsIURI> m_url;
807 
808   nsCOMPtr<nsIURI> m_originalUrl;
809   nsCOMPtr<nsILoadGroup> m_loadGroup;
810   nsCOMPtr<nsILoadInfo> m_loadInfo;
811   nsCOMPtr<nsIStreamListener> m_channelListener;
812   nsresult m_cancelStatus;
813   nsLoadFlags mLoadFlags;
814   nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
815   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
816   nsCOMPtr<nsISupports> mOwner;
817   nsCOMPtr<nsISupports> mSecurityInfo;
818   nsCOMPtr<nsIRequest>
819       mCacheRequest;  // the request associated with a read from the cache
820   nsCString mContentType;
821   nsCString mCharset;
822   nsWeakPtr mProtocol;
823 
824   bool mChannelClosed;
825   bool mReadingFromCache;
826   bool mTryingToReadPart;
827   int64_t mContentLength;
828 
829   mozilla::Monitor mSuspendedMonitor;
830   bool mSuspended;
831 
832   nsresult ResumeAndNotifyOne();
833 
834   // cache related helper methods
835   nsresult OpenCacheEntry();  // makes a request to the cache service for a
836                               // cache entry for a url
837   bool ReadFromLocalCache();  // attempts to read the url out of our local
838                               // (offline) cache....
839   nsresult
840   ReadFromImapConnection();  // creates a new imap connection to read the url
841   nsresult ReadFromMemCache(nsICacheEntry* entry);  // attempts to read the url
842                                                     // out of our memory cache
843   nsresult NotifyStartEndReadFromCache(bool start);
844 
845   // we end up daisy chaining multiple nsIStreamListeners into the load process.
846   nsresult SetupPartExtractorListener(nsIImapUrl* aUrl,
847                                       nsIStreamListener* aConsumer);
848 
849   uint32_t mContentDisposition;
850 };
851 
852 #endif  // nsImapProtocol_h___
853