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 nsPop3Protocol_h__
7 #define nsPop3Protocol_h__
8 
9 #include "mozilla/Attributes.h"
10 #include "nsIInputStream.h"
11 #include "nsIPop3Sink.h"
12 #include "nsMsgLineBuffer.h"
13 #include "nsMsgProtocol.h"
14 #include "nsIPop3Protocol.h"
15 #include "MailNewsTypes.h"
16 #include "nsIStringBundle.h"
17 #include "nsIMsgFolder.h"  // TO include biffState enum. Change to bool later...
18 #include "nsIMsgAsyncPrompter.h"
19 #include "nsIProtocolProxyCallback.h"
20 #include "msgIOAuth2Module.h"
21 
22 #include "prerror.h"
23 #include "plhash.h"
24 #include "nsCOMPtr.h"
25 
26 /* A more guaranteed way of making sure that we never get duplicate messages
27    is to always get each message's UIDL (if the server supports it)
28    and use these for storing up deletes which were not committed on the
29    server.  Based on our experience, it looks like we do NOT need to
30    do this (it has performance tradeoffs, etc.).  To turn it on, three
31    things need to happen: #define POP_ALWAYS_USE_UIDL_FOR_DUPLICATES, verify
32    that the uidl's are correctly getting added when the delete response is
33    received, and change the POP3_QUIT_RESPONSE state to flush the newly
34    committed deletes.
35  */
36 
37 /*
38  * Cannot have the following line uncommented. It is defined.
39  * #ifdef POP_ALWAYS_USE_UIDL_FOR_DUPLICATES will always be evaluated
40  * as true.
41  *
42 #define POP_ALWAYS_USE_UIDL_FOR_DUPLICATES 0
43  *
44  */
45 
46 #define MK_OUT_OF_MEMORY -207
47 #define MK_POP3_PASSWORD_UNDEFINED -313
48 #define XP_NO_ANSWER 14401
49 #define XP_THE_PREVIOUSLY_ENTERED_PASSWORD_IS_INVALID_ETC 14405
50 #define XP_PASSWORD_FOR_POP3_USER 14590
51 
52 #define OUTPUT_BUFFER_SIZE 8192  // maximum size of command string
53 
54 enum Pop3CapabilityEnum {
55   POP3_CAPABILITY_UNDEFINED = 0x00000000,
56   POP3_HAS_XSENDER = 0x00000001,
57   POP3_GURL_UNDEFINED = 0x00000002,
58   POP3_HAS_GURL = 0x00000004,
59   POP3_UIDL_UNDEFINED = 0x00000008,
60   POP3_HAS_UIDL = 0x00000010,
61   POP3_XTND_XLST_UNDEFINED = 0x00000020,
62   POP3_HAS_XTND_XLST = 0x00000040,
63   POP3_TOP_UNDEFINED = 0x00000080,
64   POP3_HAS_TOP = 0x00000100,
65   POP3_AUTH_MECH_UNDEFINED = 0x00000200,
66   POP3_HAS_AUTH_USER = 0x00000400,
67   POP3_HAS_AUTH_LOGIN = 0x00000800,
68   POP3_HAS_AUTH_PLAIN = 0x00001000,
69   POP3_HAS_AUTH_CRAM_MD5 = 0x00002000,
70   POP3_HAS_AUTH_APOP = 0x00004000,
71   POP3_HAS_AUTH_NTLM = 0x00008000,
72   POP3_HAS_AUTH_MSN = 0x00010000,
73   POP3_HAS_RESP_CODES = 0x00020000,
74   POP3_HAS_AUTH_RESP_CODE = 0x00040000,
75   POP3_HAS_STLS = 0x00080000,
76   POP3_HAS_AUTH_GSSAPI = 0x00100000,
77   POP3_HAS_AUTH_XOAUTH2 = 0x00200000
78 };
79 
80 // TODO use value > 0?
81 #define POP3_HAS_AUTH_NONE 0
82 #define POP3_HAS_AUTH_ANY 0x00001C00
83 #define POP3_HAS_AUTH_ANY_SEC 0x0011E000
84 
85 /**
86  * Structure to hold data pertaining to the active state of a transfer in
87  * progress.
88  */
89 enum Pop3StatesEnum {
90   POP3_READ_PASSWORD,                          // 0
91   POP3_START_CONNECT,                          // 1
92   POP3_FINISH_CONNECT,                         // 2
93   POP3_WAIT_FOR_RESPONSE,                      // 3
94   POP3_WAIT_FOR_START_OF_CONNECTION_RESPONSE,  // 4
95   POP3_SEND_USERNAME,                          // 5
96   POP3_SEND_PASSWORD,                          // 6
97   POP3_SEND_STAT,                              // 7
98   POP3_GET_STAT,                               // 8
99   POP3_SEND_LIST,                              // 9
100   POP3_GET_LIST,                               // 10
101   POP3_SEND_UIDL_LIST,                         // 11
102   POP3_GET_UIDL_LIST,                          // 12
103   POP3_SEND_XTND_XLST_MSGID,                   // 13
104   POP3_GET_XTND_XLST_MSGID,                    // 14
105   POP3_GET_MSG,                                // 15
106   POP3_SEND_TOP,                               // 16
107   POP3_TOP_RESPONSE,                           // 17
108   POP3_SEND_RETR,                              // 18
109   POP3_RETR_RESPONSE,                          // 19
110   POP3_SEND_DELE,                              // 20
111   POP3_DELE_RESPONSE,                          // 21
112   POP3_SEND_QUIT,                              // 22
113   POP3_DONE,                                   // 23
114   POP3_ERROR_DONE,                             // 24
115   POP3_FREE,                                   // 25
116   POP3_SEND_AUTH,                              // 26
117   POP3_AUTH_RESPONSE,                          // 27
118   POP3_SEND_CAPA,                              // 28
119   POP3_CAPA_RESPONSE,                          // 29
120   POP3_PROCESS_AUTH,                           // 30
121   POP3_NEXT_AUTH_STEP,                         // 31
122   POP3_AUTH_LOGIN,                             // 32
123   POP3_AUTH_LOGIN_RESPONSE,                    // 33
124   POP3_AUTH_NTLM,                              // 34
125   POP3_AUTH_NTLM_RESPONSE,                     // 35
126   POP3_SEND_XSENDER,                           // 36
127   POP3_XSENDER_RESPONSE,                       // 37
128   POP3_SEND_GURL,                              // 38
129   POP3_GURL_RESPONSE,                          // 39
130   POP3_QUIT_RESPONSE,                          // 40
131   POP3_TLS_RESPONSE,                           // 41
132   POP3_AUTH_GSSAPI,                            // 42
133   POP3_AUTH_GSSAPI_FIRST,                      // 43
134   POP3_AUTH_GSSAPI_STEP,                       // 44
135 
136   /**
137    * Async wait to obtain the password and deal with the result.
138    * The *PREOBTAIN* states are used for where we try and get the password
139    * before we've initiated a connection to the server.
140    */
141   POP3_OBTAIN_PASSWORD_EARLY,                   // 45
142   POP3_FINISH_OBTAIN_PASSWORD_EARLY,            // 46
143   POP3_OBTAIN_PASSWORD_BEFORE_USERNAME,         // 47
144   POP3_FINISH_OBTAIN_PASSWORD_BEFORE_USERNAME,  // 48
145   POP3_OBTAIN_PASSWORD_BEFORE_PASSWORD,         // 49
146   POP3_FINISH_OBTAIN_PASSWORD_BEFORE_PASSWORD,  // 50
147 
148   POP3_AUTH_OAUTH2_RESPONSE,   // 51
149   POP3_AUTH_OAUTH2_AUTH_STEP,  // 52
150 };
151 
152 #define KEEP 'k'        /* If we want to keep this item on server. */
153 #define DELETE_CHAR 'd' /* If we want to delete this item. */
154 #define TOO_BIG 'b'     /* item left on server because it was too big */
155 #define FETCH_BODY 'f'  /* Fetch full body of a partial msg */
156 
157 typedef struct Pop3UidlEntry { /* information about this message */
158   char* uidl;
159   char status;            // KEEP=='k', DELETE='d' TOO_BIG='b' FETCH_BODY='f'
160   uint32_t dateReceived;  // time message received, used for aging
161 } Pop3UidlEntry;
162 
163 typedef struct Pop3UidlHost {
164   char* host;
165   char* user;
166   PLHashTable* hash;
167   Pop3UidlEntry* uidlEntries;
168   struct Pop3UidlHost* next;
169 } Pop3UidlHost;
170 
171 typedef struct Pop3MsgInfo {
172   int32_t msgnum;
173   int32_t size;
174   char* uidl;
175 } Pop3MsgInfo;
176 
177 typedef struct _Pop3ConData {
178   bool leave_on_server;      /* Whether we're supposed to leave messages
179                                 on server. */
180   bool headers_only;         /* Whether to just fetch headers on initial
181                                 downloads. */
182   int32_t size_limit;        /* Leave messages bigger than this on the
183                                 server and only download a partial
184                                 message. */
185   uint32_t capability_flags; /* What capability this server has? */
186 
187   Pop3StatesEnum next_state; /* the next state or action to be taken */
188 
189   /* When in the generic POP3_WAIT_FOR_RESPONSE state, this indicates which
190    * state we want to go to when a successful response arrives. */
191   Pop3StatesEnum next_state_after_response;
192 
193   bool pause_for_read; /* Pause now for next read? */
194 
195   bool command_succeeded; /* did the last command succeed? */
196   bool command_temp_fail; /* The command respond was -ERR [SYS/TEMP] */
197   bool list_done;         /* did we get the complete list of msgIDs? */
198   int32_t first_msg;
199 
200   uint32_t obuffer_size;
201   uint32_t obuffer_fp;
202 
203   int32_t really_new_messages;
204   int32_t real_new_counter;
205   int32_t number_of_messages;
206   Pop3MsgInfo* msg_info; /* Message sizes and uidls (used only if we
207                             are playing games that involve leaving
208                             messages on the server). */
209   int32_t last_accessed_msg;
210   int32_t cur_msg_size;
211   bool truncating_cur_msg; /* are we using top and uidl? */
212   bool msg_del_started;    /* True if MSG_BeginMailDel...
213                             * called */
214   bool only_check_for_new_mail;
215   nsMsgBiffState biffstate; /* If just checking for, what the answer is. */
216 
217   bool verify_logon; /* true if we're just seeing if we can logon */
218 
219   void* msg_closure;
220 
221   bool graph_progress_bytes_p; /* whether we should display info about
222                                   the bytes transferred (usually we
223                                   display info about the number of
224                                   messages instead.) */
225 
226   Pop3UidlHost* uidlinfo;
227   PLHashTable* newuidl;
228   char* only_uidl; /* If non-NULL, then load only this UIDL. */
229 
230   bool get_url;
231   bool seenFromHeader;
232   int32_t parsed_bytes;
233   int32_t pop3_size;
234   bool dot_fix;
235   bool assumed_end;
236   nsresult urlStatus;
237 } Pop3ConData;
238 
239 // State Flags (Note, I use the word state in terms of storing
240 // state information about the connection (authentication, have we sent
241 // commands, etc. I do not intend it to refer to protocol state)
242 #define POP3_PAUSE_FOR_READ 0x00000001 /* should we pause for the next read */
243 #define POP3_PASSWORD_FAILED 0x00000002
244 #define POP3_STOPLOGIN 0x00000004 /* error logging in, so stop here */
245 #define POP3_AUTH_FAILURE \
246   0x00000008 /* extended code said authentication failed */
247 
248 class nsPop3Protocol : public nsMsgProtocol,
249                        public nsIPop3Protocol,
250                        public nsIMsgAsyncPromptListener,
251                        public msgIOAuth2ModuleListener,
252                        public nsIProtocolProxyCallback {
253  public:
254   explicit nsPop3Protocol(nsIURI* aURL);
255 
256   NS_DECL_ISUPPORTS_INHERITED
257   NS_DECL_MSGIOAUTH2MODULELISTENER
258   NS_DECL_NSIPOP3PROTOCOL
259   NS_DECL_NSIMSGASYNCPROMPTLISTENER
260   NS_DECL_NSIPROTOCOLPROXYCALLBACK
261 
262   nsresult Initialize(nsIURI* aURL);
263   nsresult InitializeInternal(nsIProxyInfo* proxyInfo);
264   virtual nsresult LoadUrl(nsIURI* aURL,
265                            nsISupports* aConsumer = nullptr) override;
266   nsresult LoadUrlInternal(nsIURI* aURL);
267   void Cleanup();
268 
GetUsername()269   const char* GetUsername() { return m_username.get(); }
270   void SetUsername(const char* name);
271 
272   nsresult StartGetAsyncPassword(Pop3StatesEnum aNextState);
273 
274   NS_IMETHOD OnTransportStatus(nsITransport* transport, nsresult status,
275                                int64_t progress, int64_t progressMax) override;
276   NS_IMETHOD OnStopRequest(nsIRequest* request, nsresult aStatus) override;
277   NS_IMETHOD Cancel(nsresult status) override;
278 
279   static void MarkMsgInHashTable(PLHashTable* hashTable,
280                                  const Pop3UidlEntry* uidl, bool* changed);
281 
282   static nsresult MarkMsgForHost(const char* hostName, const char* userName,
283                                  nsIFile* mailDirectory,
284                                  nsTArray<Pop3UidlEntry*>& UIDLArray);
285 
286  private:
287   virtual ~nsPop3Protocol();
288   nsCString m_ApopTimestamp;
289   nsCOMPtr<nsIStringBundle> mLocalBundle;
290 
291   nsCString m_username;
292   nsCString m_senderInfo;
293   nsCString m_commandResponse;
294   nsCString m_GSSAPICache;
295   /**
296    * For keeping track of the OAuth2 string to send, if it's long and can't be
297    * sent with the command directly.
298    */
299   nsCString m_OAuth2String;
300 
301   // Used for asynchronous password prompts to store the password temporarily.
302   nsString m_passwordResult;
303 
304   // progress state information
305   void UpdateProgressPercent(int64_t totalDone, int64_t total);
306   void UpdateStatus(const char* aStatusName);
307   void UpdateStatusWithString(const char16_t* aString);
308   nsresult FormatCounterString(const nsString& stringName, uint32_t count1,
309                                uint32_t count2, nsString& resultString);
310 
311   int32_t m_bytesInMsgReceived;
312   int64_t m_totalFolderSize;
313   int64_t m_totalDownloadSize;   /* Number of bytes we're going to
314                                     download.  Might be much less
315                                     than the total_folder_size. */
316   int64_t m_totalBytesReceived;  // total # bytes received for the connection
317 
318   virtual nsresult ProcessProtocolState(nsIURI* url,
319                                         nsIInputStream* inputStream,
320                                         uint64_t sourceOffset,
321                                         uint32_t length) override;
322   virtual int32_t Pop3SendData(const char* dataBuffer,
323                                bool aSuppressLogging = false);
324 
GetType()325   virtual const char* GetType() override { return "pop3"; }
326 
327   nsCOMPtr<nsIURI> m_url;
328   nsCOMPtr<nsIPop3Sink> m_nsIPop3Sink;
329   nsCOMPtr<nsIPop3IncomingServer> m_pop3Server;
330 
331   RefPtr<nsMsgLineStreamBuffer>
332       m_lineStreamBuffer;  // used to efficiently extract lines from the
333                            // incoming data stream
334   Pop3ConData* m_pop3ConData;
335   void FreeMsgInfo();
336   void Abort();
337 
338   bool m_tlsEnabled;
339   int32_t m_socketType;
340   bool m_password_already_sent;
341   bool m_needToRerunUrl;
342 
343   void SetCapFlag(uint32_t flag);
344   void ClearCapFlag(uint32_t flag);
345   bool TestCapFlag(uint32_t flag);
346   uint32_t GetCapFlags();
347 
348   void InitPrefAuthMethods(int32_t authMethodPrefValue);
349   nsresult ChooseAuthMethod();
350   void MarkAuthMethodAsFailed(int32_t failedAuthMethod);
351   void ResetAuthMethods();
352   int32_t m_prefAuthMethods;    // set of capability flags for auth methods
353   int32_t m_failedAuthMethods;  // ditto
354   int32_t m_currentAuthMethod;  // exactly one capability flag, or 0
355 
356   int32_t m_listpos;
357 
358   nsresult HandleLine(char* line, uint32_t line_length);
359 
360   nsresult GetApopTimestamp();
361 
362   //////////////////////////////////////////////////////////////////////////////////////////
363   // Begin Pop3 protocol state handlers
364   //////////////////////////////////////////////////////////////////////////////////////////
365   int32_t WaitForStartOfConnectionResponse(nsIInputStream* inputStream,
366                                            uint32_t length);
367   int32_t WaitForResponse(nsIInputStream* inputStream, uint32_t length);
368   int32_t Error(const char* err_code, const char16_t* param = nullptr);
369   int32_t SendAuth();
370   int32_t AuthResponse(nsIInputStream* inputStream, uint32_t length);
371   int32_t SendCapa();
372   int32_t CapaResponse(nsIInputStream* inputStream, uint32_t length);
373   int32_t SendTLSResponse();
374   int32_t ProcessAuth();
375   int32_t NextAuthStep();
376   int32_t AuthLogin();
377   int32_t AuthLoginResponse();
378   int32_t AuthOAuth2Response();
379   int32_t AuthNtlm();
380   int32_t AuthNtlmResponse();
381   int32_t AuthGSSAPI();
382   int32_t AuthGSSAPIResponse(bool first);
383   int32_t SendUsername();
384   int32_t SendPassword();
385   int32_t SendStatOrGurl(bool sendStat);
386   int32_t SendStat();
387   int32_t GetStat();
388   int32_t SendGurl();
389   int32_t GurlResponse();
390   int32_t SendList();
391   int32_t GetList(nsIInputStream* inputStream, uint32_t length);
392   int32_t HandleNoUidListAvailable();
393   int32_t SendXtndXlstMsgid();
394   int32_t GetXtndXlstMsgid(nsIInputStream* inputStream, uint32_t length);
395   int32_t SendUidlList();
396   int32_t GetUidlList(nsIInputStream* inputStream, uint32_t length);
397   int32_t GetMsg();
398   int32_t SendTop();
399   int32_t SendXsender();
400   int32_t XsenderResponse();
401   int32_t SendRetr();
402   int32_t OAuth2AuthStep();
403 
404   int32_t RetrResponse(nsIInputStream* inputStream, uint32_t length);
405   int32_t TopResponse(nsIInputStream* inputStream, uint32_t length);
406   int32_t SendDele();
407   int32_t DeleResponse();
408   int32_t CommitState(bool remove_last_entry);
409 
410   Pop3StatesEnum GetNextPasswordObtainState();
411   nsresult RerunUrl();
412 
413   // The support module for OAuth2 logon, only present if OAuth2 is enabled
414   // and working.
415   nsCOMPtr<msgIOAuth2Module> mOAuth2Support;
416 };
417 
418 #endif /* nsPop3Protocol_h__ */
419