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