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 #include "nsMsgIncomingServer.h"
7 #include "nscore.h"
8 #include "plstr.h"
9 #include "prmem.h"
10 #include "prprf.h"
11 
12 #include "nsIServiceManager.h"
13 #include "nsCOMPtr.h"
14 #include "nsString.h"
15 #include "nsMemory.h"
16 #include "nsISupportsPrimitives.h"
17 
18 #include "nsIMsgBiffManager.h"
19 #include "nsMsgBaseCID.h"
20 #include "nsMsgDBCID.h"
21 #include "nsIMsgFolder.h"
22 #include "nsMsgDBFolder.h"
23 #include "nsIMsgFolderCache.h"
24 #include "nsIMsgPluggableStore.h"
25 #include "nsIMsgFolderCacheElement.h"
26 #include "nsIMsgWindow.h"
27 #include "nsIMsgFilterService.h"
28 #include "nsIMsgProtocolInfo.h"
29 #include "nsIPrefService.h"
30 #include "nsIRelativeFilePref.h"
31 #include "mozilla/nsRelativeFilePref.h"
32 #include "nsIDocShell.h"
33 #include "nsIAuthPrompt.h"
34 #include "nsNetUtil.h"
35 #include "nsIWindowWatcher.h"
36 #include "nsIStringBundle.h"
37 #include "nsIMsgHdr.h"
38 #include "nsIInterfaceRequestor.h"
39 #include "nsIInterfaceRequestorUtils.h"
40 #include "nsILoginInfo.h"
41 #include "nsILoginManager.h"
42 #include "nsIMsgAccountManager.h"
43 #include "nsIMsgMdnGenerator.h"
44 #include "nsMsgUtils.h"
45 #include "nsMsgMessageFlags.h"
46 #include "nsIMsgSearchTerm.h"
47 #include "nsAppDirectoryServiceDefs.h"
48 #include "mozilla/Services.h"
49 #include "Services.h"
50 #include "nsIMsgFilter.h"
51 #include "nsIObserverService.h"
52 #include "mozilla/Unused.h"
53 
54 #define PORT_NOT_SET -1
55 
nsMsgIncomingServer()56 nsMsgIncomingServer::nsMsgIncomingServer()
57     : m_rootFolder(nullptr),
58       m_downloadedHdrs(50),
59       m_numMsgsDownloaded(0),
60       m_biffState(nsIMsgFolder::nsMsgBiffState_Unknown),
61       m_serverBusy(false),
62       m_canHaveFilters(true),
63       m_displayStartupPage(true),
64       mPerformingBiff(false) {}
65 
Init()66 nsresult nsMsgIncomingServer::Init() {
67   // We need to know when the password manager changes.
68   nsCOMPtr<nsIObserverService> observerService =
69       mozilla::services::GetObserverService();
70   NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
71 
72   observerService->AddObserver(this, "passwordmgr-storage-changed", false);
73   observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
74   return NS_OK;
75 }
76 
~nsMsgIncomingServer()77 nsMsgIncomingServer::~nsMsgIncomingServer() {}
78 
NS_IMPL_ISUPPORTS(nsMsgIncomingServer,nsIMsgIncomingServer,nsISupportsWeakReference,nsIObserver)79 NS_IMPL_ISUPPORTS(nsMsgIncomingServer, nsIMsgIncomingServer,
80                   nsISupportsWeakReference, nsIObserver)
81 
82 NS_IMETHODIMP
83 nsMsgIncomingServer::Observe(nsISupports* aSubject, const char* aTopic,
84                              const char16_t* aData) {
85   nsresult rv;
86 
87   // When the state of the password manager changes we need to clear the
88   // password from the cache in case the user just removed it.
89   if (strcmp(aTopic, "passwordmgr-storage-changed") == 0) {
90     // Check that the notification is for this server.
91     nsCOMPtr<nsILoginInfo> loginInfo = do_QueryInterface(aSubject);
92     if (loginInfo) {
93       nsAutoString hostnameInfo;
94       loginInfo->GetHostname(hostnameInfo);
95       nsAutoCString hostname;
96       GetHostName(hostname);
97       nsAutoCString fullName;
98       GetType(fullName);
99       if (fullName.EqualsLiteral("pop3")) {
100         fullName = "mailbox://"_ns + hostname;
101       } else {
102         fullName += "://"_ns + hostname;
103       }
104       if (!fullName.Equals(NS_ConvertUTF16toUTF8(hostnameInfo))) return NS_OK;
105     }
106     rv = ForgetSessionPassword();
107     NS_ENSURE_SUCCESS(rv, rv);
108   } else if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
109     // Now remove ourselves from the observer service as well.
110     nsCOMPtr<nsIObserverService> observerService =
111         mozilla::services::GetObserverService();
112     NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
113 
114     observerService->RemoveObserver(this, "passwordmgr-storage-changed");
115     observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
116   }
117 
118   return NS_OK;
119 }
120 
121 NS_IMETHODIMP
SetServerBusy(bool aServerBusy)122 nsMsgIncomingServer::SetServerBusy(bool aServerBusy) {
123   m_serverBusy = aServerBusy;
124   return NS_OK;
125 }
126 
127 NS_IMETHODIMP
GetServerBusy(bool * aServerBusy)128 nsMsgIncomingServer::GetServerBusy(bool* aServerBusy) {
129   NS_ENSURE_ARG_POINTER(aServerBusy);
130   *aServerBusy = m_serverBusy;
131   return NS_OK;
132 }
133 
134 NS_IMETHODIMP
GetKey(nsACString & serverKey)135 nsMsgIncomingServer::GetKey(nsACString& serverKey) {
136   serverKey = m_serverKey;
137   return NS_OK;
138 }
139 
140 NS_IMETHODIMP
SetKey(const nsACString & serverKey)141 nsMsgIncomingServer::SetKey(const nsACString& serverKey) {
142   m_serverKey.Assign(serverKey);
143 
144   // in order to actually make use of the key, we need the prefs
145   nsresult rv;
146   nsCOMPtr<nsIPrefService> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
147   NS_ENSURE_SUCCESS(rv, rv);
148 
149   nsAutoCString branchName;
150   branchName.AssignLiteral("mail.server.");
151   branchName.Append(m_serverKey);
152   branchName.Append('.');
153   rv = prefs->GetBranch(branchName.get(), getter_AddRefs(mPrefBranch));
154   NS_ENSURE_SUCCESS(rv, rv);
155 
156   return prefs->GetBranch("mail.server.default.",
157                           getter_AddRefs(mDefPrefBranch));
158 }
159 
160 NS_IMETHODIMP
SetRootFolder(nsIMsgFolder * aRootFolder)161 nsMsgIncomingServer::SetRootFolder(nsIMsgFolder* aRootFolder) {
162   m_rootFolder = aRootFolder;
163   return NS_OK;
164 }
165 
166 // this will return the root folder of this account,
167 // even if this server is deferred.
168 NS_IMETHODIMP
GetRootFolder(nsIMsgFolder ** aRootFolder)169 nsMsgIncomingServer::GetRootFolder(nsIMsgFolder** aRootFolder) {
170   NS_ENSURE_ARG_POINTER(aRootFolder);
171   if (!m_rootFolder) {
172     nsresult rv = CreateRootFolder();
173     NS_ENSURE_SUCCESS(rv, rv);
174   }
175 
176   NS_IF_ADDREF(*aRootFolder = m_rootFolder);
177   return NS_OK;
178 }
179 
180 // this will return the root folder of the deferred to account,
181 // if this server is deferred.
182 NS_IMETHODIMP
GetRootMsgFolder(nsIMsgFolder ** aRootMsgFolder)183 nsMsgIncomingServer::GetRootMsgFolder(nsIMsgFolder** aRootMsgFolder) {
184   return GetRootFolder(aRootMsgFolder);
185 }
186 
187 NS_IMETHODIMP
PerformExpand(nsIMsgWindow * aMsgWindow)188 nsMsgIncomingServer::PerformExpand(nsIMsgWindow* aMsgWindow) { return NS_OK; }
189 
190 NS_IMETHODIMP
VerifyLogon(nsIUrlListener * aUrlListener,nsIMsgWindow * aMsgWindow,nsIURI ** aURL)191 nsMsgIncomingServer::VerifyLogon(nsIUrlListener* aUrlListener,
192                                  nsIMsgWindow* aMsgWindow, nsIURI** aURL) {
193   return NS_ERROR_NOT_IMPLEMENTED;
194 }
195 
196 NS_IMETHODIMP
PerformBiff(nsIMsgWindow * aMsgWindow)197 nsMsgIncomingServer::PerformBiff(nsIMsgWindow* aMsgWindow) {
198   // This has to be implemented in the derived class, but in case someone
199   // doesn't implement it just return not implemented.
200   return NS_ERROR_NOT_IMPLEMENTED;
201 }
202 
203 NS_IMETHODIMP
GetNewMessages(nsIMsgFolder * aFolder,nsIMsgWindow * aMsgWindow,nsIUrlListener * aUrlListener)204 nsMsgIncomingServer::GetNewMessages(nsIMsgFolder* aFolder,
205                                     nsIMsgWindow* aMsgWindow,
206                                     nsIUrlListener* aUrlListener) {
207   NS_ENSURE_ARG_POINTER(aFolder);
208   return aFolder->GetNewMessages(aMsgWindow, aUrlListener);
209 }
210 
GetPerformingBiff(bool * aPerformingBiff)211 NS_IMETHODIMP nsMsgIncomingServer::GetPerformingBiff(bool* aPerformingBiff) {
212   NS_ENSURE_ARG_POINTER(aPerformingBiff);
213   *aPerformingBiff = mPerformingBiff;
214   return NS_OK;
215 }
216 
SetPerformingBiff(bool aPerformingBiff)217 NS_IMETHODIMP nsMsgIncomingServer::SetPerformingBiff(bool aPerformingBiff) {
218   mPerformingBiff = aPerformingBiff;
219   return NS_OK;
220 }
221 
NS_IMPL_GETSET(nsMsgIncomingServer,BiffState,uint32_t,m_biffState)222 NS_IMPL_GETSET(nsMsgIncomingServer, BiffState, uint32_t, m_biffState)
223 
224 NS_IMETHODIMP nsMsgIncomingServer::WriteToFolderCache(
225     nsIMsgFolderCache* folderCache) {
226   nsresult rv = NS_OK;
227   if (m_rootFolder) {
228     rv = m_rootFolder->WriteToFolderCache(folderCache, true /* deep */);
229   }
230   return rv;
231 }
232 
233 NS_IMETHODIMP
Shutdown()234 nsMsgIncomingServer::Shutdown() {
235   nsresult rv = CloseCachedConnections();
236   mFilterPlugin = nullptr;
237   NS_ENSURE_SUCCESS(rv, rv);
238 
239   if (mFilterList) {
240     // close the filter log stream
241     rv = mFilterList->SetLogStream(nullptr);
242     NS_ENSURE_SUCCESS(rv, rv);
243     mFilterList = nullptr;
244   }
245 
246   if (mSpamSettings) {
247     // close the spam log stream
248     rv = mSpamSettings->SetLogStream(nullptr);
249     NS_ENSURE_SUCCESS(rv, rv);
250     mSpamSettings = nullptr;
251   }
252   return rv;
253 }
254 
255 NS_IMETHODIMP
CloseCachedConnections()256 nsMsgIncomingServer::CloseCachedConnections() {
257   // derived class should override if they cache connections.
258   return NS_OK;
259 }
260 
261 NS_IMETHODIMP
GetDownloadMessagesAtStartup(bool * getMessagesAtStartup)262 nsMsgIncomingServer::GetDownloadMessagesAtStartup(bool* getMessagesAtStartup) {
263   // derived class should override if they need to do this.
264   *getMessagesAtStartup = false;
265   return NS_OK;
266 }
267 
268 NS_IMETHODIMP
GetCanHaveFilters(bool * canHaveFilters)269 nsMsgIncomingServer::GetCanHaveFilters(bool* canHaveFilters) {
270   NS_ENSURE_ARG_POINTER(canHaveFilters);
271   *canHaveFilters = m_canHaveFilters;
272   return NS_OK;
273 }
274 
275 NS_IMETHODIMP
SetCanHaveFilters(bool aCanHaveFilters)276 nsMsgIncomingServer::SetCanHaveFilters(bool aCanHaveFilters) {
277   m_canHaveFilters = aCanHaveFilters;
278   return NS_OK;
279 }
280 
281 NS_IMETHODIMP
GetCanBeDefaultServer(bool * canBeDefaultServer)282 nsMsgIncomingServer::GetCanBeDefaultServer(bool* canBeDefaultServer) {
283   // derived class should override if they need to do this.
284   *canBeDefaultServer = false;
285   return NS_OK;
286 }
287 
288 NS_IMETHODIMP
GetCanSearchMessages(bool * canSearchMessages)289 nsMsgIncomingServer::GetCanSearchMessages(bool* canSearchMessages) {
290   // derived class should override if they need to do this.
291   NS_ENSURE_ARG_POINTER(canSearchMessages);
292   *canSearchMessages = false;
293   return NS_OK;
294 }
295 
296 NS_IMETHODIMP
GetCanCompactFoldersOnServer(bool * canCompactFoldersOnServer)297 nsMsgIncomingServer::GetCanCompactFoldersOnServer(
298     bool* canCompactFoldersOnServer) {
299   // derived class should override if they need to do this.
300   NS_ENSURE_ARG_POINTER(canCompactFoldersOnServer);
301   *canCompactFoldersOnServer = true;
302   return NS_OK;
303 }
304 
305 NS_IMETHODIMP
GetCanUndoDeleteOnServer(bool * canUndoDeleteOnServer)306 nsMsgIncomingServer::GetCanUndoDeleteOnServer(bool* canUndoDeleteOnServer) {
307   // derived class should override if they need to do this.
308   NS_ENSURE_ARG_POINTER(canUndoDeleteOnServer);
309   *canUndoDeleteOnServer = true;
310   return NS_OK;
311 }
312 
313 NS_IMETHODIMP
GetCanEmptyTrashOnExit(bool * canEmptyTrashOnExit)314 nsMsgIncomingServer::GetCanEmptyTrashOnExit(bool* canEmptyTrashOnExit) {
315   // derived class should override if they need to do this.
316   NS_ENSURE_ARG_POINTER(canEmptyTrashOnExit);
317   *canEmptyTrashOnExit = true;
318   return NS_OK;
319 }
320 
321 // construct <localStoreType>://[<username>@]<hostname
322 NS_IMETHODIMP
GetServerURI(nsACString & aResult)323 nsMsgIncomingServer::GetServerURI(nsACString& aResult) {
324   nsresult rv;
325   rv = GetLocalStoreType(aResult);
326   NS_ENSURE_SUCCESS(rv, rv);
327   aResult.AppendLiteral("://");
328 
329   nsCString username;
330   rv = GetUsername(username);
331   if (NS_SUCCEEDED(rv) && !username.IsEmpty()) {
332     nsCString escapedUsername;
333     MsgEscapeString(username, nsINetUtil::ESCAPE_XALPHAS, escapedUsername);
334     // not all servers have a username
335     aResult.Append(escapedUsername);
336     aResult.Append('@');
337   }
338 
339   nsCString hostname;
340   rv = GetHostName(hostname);
341   if (NS_SUCCEEDED(rv) && !hostname.IsEmpty()) {
342     nsCString escapedHostname;
343     MsgEscapeString(hostname, nsINetUtil::ESCAPE_URL_PATH, escapedHostname);
344     // not all servers have a hostname
345     aResult.Append(escapedHostname);
346   }
347   return NS_OK;
348 }
349 
350 // helper routine to create local folder on disk, if it doesn't exist.
CreateLocalFolder(const nsAString & folderName)351 nsresult nsMsgIncomingServer::CreateLocalFolder(const nsAString& folderName) {
352   nsCOMPtr<nsIMsgFolder> rootFolder;
353   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
354   NS_ENSURE_SUCCESS(rv, rv);
355   nsCOMPtr<nsIMsgFolder> child;
356   rv = rootFolder->GetChildNamed(folderName, getter_AddRefs(child));
357   if (child) return NS_OK;
358   nsCOMPtr<nsIMsgPluggableStore> msgStore;
359   rv = GetMsgStore(getter_AddRefs(msgStore));
360   NS_ENSURE_SUCCESS(rv, rv);
361   return msgStore->CreateFolder(rootFolder, folderName, getter_AddRefs(child));
362 }
363 
CreateRootFolder()364 nsresult nsMsgIncomingServer::CreateRootFolder() {
365   nsresult rv;
366   // get the URI from the incoming server
367   nsCString serverUri;
368   rv = GetServerURI(serverUri);
369   NS_ENSURE_SUCCESS(rv, rv);
370   rv = GetOrCreateFolder(serverUri, getter_AddRefs(m_rootFolder));
371   NS_ENSURE_SUCCESS(rv, rv);
372   return NS_OK;
373 }
374 
375 NS_IMETHODIMP
GetBoolValue(const char * prefname,bool * val)376 nsMsgIncomingServer::GetBoolValue(const char* prefname, bool* val) {
377   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
378 
379   NS_ENSURE_ARG_POINTER(val);
380   *val = false;
381 
382   if (NS_FAILED(mPrefBranch->GetBoolPref(prefname, val)))
383     mDefPrefBranch->GetBoolPref(prefname, val);
384 
385   return NS_OK;
386 }
387 
388 NS_IMETHODIMP
SetBoolValue(const char * prefname,bool val)389 nsMsgIncomingServer::SetBoolValue(const char* prefname, bool val) {
390   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
391 
392   bool defaultValue;
393   nsresult rv = mDefPrefBranch->GetBoolPref(prefname, &defaultValue);
394 
395   if (NS_SUCCEEDED(rv) && val == defaultValue)
396     mPrefBranch->ClearUserPref(prefname);
397   else
398     rv = mPrefBranch->SetBoolPref(prefname, val);
399 
400   return rv;
401 }
402 
403 NS_IMETHODIMP
GetIntValue(const char * prefname,int32_t * val)404 nsMsgIncomingServer::GetIntValue(const char* prefname, int32_t* val) {
405   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
406 
407   NS_ENSURE_ARG_POINTER(val);
408   *val = 0;
409 
410   if (NS_FAILED(mPrefBranch->GetIntPref(prefname, val)))
411     mDefPrefBranch->GetIntPref(prefname, val);
412 
413   return NS_OK;
414 }
415 
416 NS_IMETHODIMP
GetFileValue(const char * aRelPrefName,const char * aAbsPrefName,nsIFile ** aLocalFile)417 nsMsgIncomingServer::GetFileValue(const char* aRelPrefName,
418                                   const char* aAbsPrefName,
419                                   nsIFile** aLocalFile) {
420   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
421 
422   // Get the relative first
423   nsCOMPtr<nsIRelativeFilePref> relFilePref;
424   nsresult rv = mPrefBranch->GetComplexValue(aRelPrefName,
425                                              NS_GET_IID(nsIRelativeFilePref),
426                                              getter_AddRefs(relFilePref));
427   if (relFilePref) {
428     rv = relFilePref->GetFile(aLocalFile);
429     NS_ASSERTION(*aLocalFile, "An nsIRelativeFilePref has no file.");
430     if (NS_SUCCEEDED(rv)) (*aLocalFile)->Normalize();
431   } else {
432     rv = mPrefBranch->GetComplexValue(aAbsPrefName, NS_GET_IID(nsIFile),
433                                       reinterpret_cast<void**>(aLocalFile));
434     if (NS_FAILED(rv)) return rv;
435 
436     nsCOMPtr<nsIRelativeFilePref> relFilePref =
437         new mozilla::nsRelativeFilePref();
438     mozilla::Unused << relFilePref->SetFile(*aLocalFile);
439     mozilla::Unused << relFilePref->SetRelativeToKey(
440         nsLiteralCString(NS_APP_USER_PROFILE_50_DIR));
441 
442     rv = mPrefBranch->SetComplexValue(
443         aRelPrefName, NS_GET_IID(nsIRelativeFilePref), relFilePref);
444   }
445 
446   return rv;
447 }
448 
449 NS_IMETHODIMP
SetFileValue(const char * aRelPrefName,const char * aAbsPrefName,nsIFile * aLocalFile)450 nsMsgIncomingServer::SetFileValue(const char* aRelPrefName,
451                                   const char* aAbsPrefName,
452                                   nsIFile* aLocalFile) {
453   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
454 
455   // Write the relative path.
456   nsCOMPtr<nsIRelativeFilePref> relFilePref = new mozilla::nsRelativeFilePref();
457   mozilla::Unused << relFilePref->SetFile(aLocalFile);
458   mozilla::Unused << relFilePref->SetRelativeToKey(
459       nsLiteralCString(NS_APP_USER_PROFILE_50_DIR));
460 
461   nsresult rv = mPrefBranch->SetComplexValue(
462       aRelPrefName, NS_GET_IID(nsIRelativeFilePref), relFilePref);
463   if (NS_FAILED(rv)) return rv;
464 
465   return mPrefBranch->SetComplexValue(aAbsPrefName, NS_GET_IID(nsIFile),
466                                       aLocalFile);
467 }
468 
469 NS_IMETHODIMP
SetIntValue(const char * prefname,int32_t val)470 nsMsgIncomingServer::SetIntValue(const char* prefname, int32_t val) {
471   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
472 
473   int32_t defaultVal;
474   nsresult rv = mDefPrefBranch->GetIntPref(prefname, &defaultVal);
475 
476   if (NS_SUCCEEDED(rv) && defaultVal == val)
477     mPrefBranch->ClearUserPref(prefname);
478   else
479     rv = mPrefBranch->SetIntPref(prefname, val);
480 
481   return rv;
482 }
483 
484 NS_IMETHODIMP
GetCharValue(const char * prefname,nsACString & val)485 nsMsgIncomingServer::GetCharValue(const char* prefname, nsACString& val) {
486   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
487 
488   nsCString tmpVal;
489   if (NS_FAILED(mPrefBranch->GetCharPref(prefname, tmpVal)))
490     mDefPrefBranch->GetCharPref(prefname, tmpVal);
491   val = tmpVal;
492   return NS_OK;
493 }
494 
495 NS_IMETHODIMP
GetUnicharValue(const char * prefname,nsAString & val)496 nsMsgIncomingServer::GetUnicharValue(const char* prefname, nsAString& val) {
497   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
498 
499   nsCString valueUtf8;
500   if (NS_FAILED(
501           mPrefBranch->GetStringPref(prefname, EmptyCString(), 0, valueUtf8)))
502     mDefPrefBranch->GetStringPref(prefname, EmptyCString(), 0, valueUtf8);
503   CopyUTF8toUTF16(valueUtf8, val);
504   return NS_OK;
505 }
506 
507 NS_IMETHODIMP
SetCharValue(const char * prefname,const nsACString & val)508 nsMsgIncomingServer::SetCharValue(const char* prefname, const nsACString& val) {
509   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
510 
511   if (val.IsEmpty()) {
512     mPrefBranch->ClearUserPref(prefname);
513     return NS_OK;
514   }
515 
516   nsCString defaultVal;
517   nsresult rv = mDefPrefBranch->GetCharPref(prefname, defaultVal);
518 
519   if (NS_SUCCEEDED(rv) && defaultVal.Equals(val))
520     mPrefBranch->ClearUserPref(prefname);
521   else
522     rv = mPrefBranch->SetCharPref(prefname, val);
523 
524   return rv;
525 }
526 
527 NS_IMETHODIMP
SetUnicharValue(const char * prefname,const nsAString & val)528 nsMsgIncomingServer::SetUnicharValue(const char* prefname,
529                                      const nsAString& val) {
530   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
531 
532   if (val.IsEmpty()) {
533     mPrefBranch->ClearUserPref(prefname);
534     return NS_OK;
535   }
536 
537   nsCString defaultVal;
538   nsresult rv =
539       mDefPrefBranch->GetStringPref(prefname, EmptyCString(), 0, defaultVal);
540 
541   if (NS_SUCCEEDED(rv) && defaultVal.Equals(NS_ConvertUTF16toUTF8(val)))
542     mPrefBranch->ClearUserPref(prefname);
543   else
544     rv = mPrefBranch->SetStringPref(prefname, NS_ConvertUTF16toUTF8(val));
545 
546   return rv;
547 }
548 
549 // pretty name is the display name to show to the user
550 NS_IMETHODIMP
GetPrettyName(nsAString & retval)551 nsMsgIncomingServer::GetPrettyName(nsAString& retval) {
552   nsresult rv = GetUnicharValue("name", retval);
553   NS_ENSURE_SUCCESS(rv, rv);
554 
555   // if there's no name, then just return the hostname
556   return retval.IsEmpty() ? GetConstructedPrettyName(retval) : rv;
557 }
558 
559 NS_IMETHODIMP
SetPrettyName(const nsAString & value)560 nsMsgIncomingServer::SetPrettyName(const nsAString& value) {
561   SetUnicharValue("name", value);
562   nsCOMPtr<nsIMsgFolder> rootFolder;
563   GetRootFolder(getter_AddRefs(rootFolder));
564   if (rootFolder) rootFolder->SetPrettyName(value);
565   return NS_OK;
566 }
567 
568 // construct the pretty name to show to the user if they haven't
569 // specified one. This should be overridden for news and mail.
570 NS_IMETHODIMP
GetConstructedPrettyName(nsAString & retval)571 nsMsgIncomingServer::GetConstructedPrettyName(nsAString& retval) {
572   nsCString username;
573   nsresult rv = GetUsername(username);
574   NS_ENSURE_SUCCESS(rv, rv);
575   if (!username.IsEmpty()) {
576     CopyASCIItoUTF16(username, retval);
577     retval.AppendLiteral(" on ");
578   }
579 
580   nsCString hostname;
581   rv = GetHostName(hostname);
582   NS_ENSURE_SUCCESS(rv, rv);
583 
584   retval.Append(NS_ConvertASCIItoUTF16(hostname));
585   return NS_OK;
586 }
587 
588 NS_IMETHODIMP
ToString(nsAString & aResult)589 nsMsgIncomingServer::ToString(nsAString& aResult) {
590   aResult.AssignLiteral("[nsIMsgIncomingServer: ");
591   aResult.Append(NS_ConvertASCIItoUTF16(m_serverKey));
592   aResult.Append(']');
593   return NS_OK;
594 }
595 
SetPassword(const nsAString & aPassword)596 NS_IMETHODIMP nsMsgIncomingServer::SetPassword(const nsAString& aPassword) {
597   m_password = aPassword;
598   return NS_OK;
599 }
600 
GetPassword(nsAString & aPassword)601 NS_IMETHODIMP nsMsgIncomingServer::GetPassword(nsAString& aPassword) {
602   aPassword = m_password;
603   return NS_OK;
604 }
605 
GetServerRequiresPasswordForBiff(bool * aServerRequiresPasswordForBiff)606 NS_IMETHODIMP nsMsgIncomingServer::GetServerRequiresPasswordForBiff(
607     bool* aServerRequiresPasswordForBiff) {
608   NS_ENSURE_ARG_POINTER(aServerRequiresPasswordForBiff);
609   *aServerRequiresPasswordForBiff = true;
610   return NS_OK;
611 }
612 
613 // This sets m_password if we find a password in the pw mgr.
GetPasswordWithoutUI()614 nsresult nsMsgIncomingServer::GetPasswordWithoutUI() {
615   nsresult rv;
616   nsCOMPtr<nsILoginManager> loginMgr(
617       do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv));
618   NS_ENSURE_SUCCESS(rv, rv);
619 
620   // Get the current server URI
621   nsCString currServerUri;
622   rv = GetLocalStoreType(currServerUri);
623   NS_ENSURE_SUCCESS(rv, rv);
624 
625   currServerUri.AppendLiteral("://");
626 
627   nsCString temp;
628   rv = GetHostName(temp);
629   NS_ENSURE_SUCCESS(rv, rv);
630 
631   currServerUri.Append(temp);
632 
633   NS_ConvertUTF8toUTF16 currServer(currServerUri);
634 
635   nsTArray<RefPtr<nsILoginInfo>> logins;
636   rv = loginMgr->FindLogins(currServer, EmptyString(), currServer, logins);
637 
638   // Login manager can produce valid fails, e.g. NS_ERROR_ABORT when a user
639   // cancels the master password dialog. Therefore handle that here, but don't
640   // warn about it.
641   if (NS_FAILED(rv)) return rv;
642   uint32_t numLogins = logins.Length();
643 
644   // Don't abort here, if we didn't find any or failed, then we'll just have
645   // to prompt.
646   if (numLogins > 0) {
647     nsCString serverCUsername;
648     rv = GetUsername(serverCUsername);
649     NS_ENSURE_SUCCESS(rv, rv);
650 
651     NS_ConvertUTF8toUTF16 serverUsername(serverCUsername);
652 
653     nsString username;
654     for (uint32_t i = 0; i < numLogins; ++i) {
655       rv = logins[i]->GetUsername(username);
656       NS_ENSURE_SUCCESS(rv, rv);
657 
658       if (username.Equals(serverUsername)) {
659         nsString password;
660         rv = logins[i]->GetPassword(password);
661         NS_ENSURE_SUCCESS(rv, rv);
662 
663         m_password = password;
664         break;
665       }
666     }
667   }
668   return NS_OK;
669 }
670 
671 NS_IMETHODIMP
GetPasswordWithUI(const nsAString & aPromptMessage,const nsAString & aPromptTitle,nsIMsgWindow * aMsgWindow,nsAString & aPassword)672 nsMsgIncomingServer::GetPasswordWithUI(const nsAString& aPromptMessage,
673                                        const nsAString& aPromptTitle,
674                                        nsIMsgWindow* aMsgWindow,
675                                        nsAString& aPassword) {
676   nsresult rv = NS_OK;
677 
678   if (m_password.IsEmpty()) {
679     // let's see if we have the password in the password manager and
680     // can avoid this prompting thing. This makes it easier to get embedders
681     // to get up and running w/o a password prompting UI.
682     rv = GetPasswordWithoutUI();
683     // If GetPasswordWithoutUI returns NS_ERROR_ABORT, the most likely case
684     // is the user canceled getting the master password, so just return
685     // straight away, as they won't want to get prompted again.
686     if (rv == NS_ERROR_ABORT) return NS_MSG_PASSWORD_PROMPT_CANCELLED;
687   }
688   if (m_password.IsEmpty()) {
689     nsCOMPtr<nsIAuthPrompt> dialog;
690     // aMsgWindow is required if we need to prompt
691     if (aMsgWindow) {
692       rv = aMsgWindow->GetAuthPrompt(getter_AddRefs(dialog));
693       NS_ENSURE_SUCCESS(rv, rv);
694     }
695     if (dialog) {
696       // prompt the user for the password
697       nsCString serverUri;
698       rv = GetLocalStoreType(serverUri);
699       NS_ENSURE_SUCCESS(rv, rv);
700 
701       serverUri.AppendLiteral("://");
702       nsCString temp;
703       rv = GetUsername(temp);
704       NS_ENSURE_SUCCESS(rv, rv);
705 
706       if (!temp.IsEmpty()) {
707         nsCString escapedUsername;
708         MsgEscapeString(temp, nsINetUtil::ESCAPE_XALPHAS, escapedUsername);
709         serverUri.Append(escapedUsername);
710         serverUri.Append('@');
711       }
712 
713       rv = GetHostName(temp);
714       NS_ENSURE_SUCCESS(rv, rv);
715 
716       serverUri.Append(temp);
717 
718       // we pass in the previously used password, if any, into PromptPassword
719       // so that it will appear as ******. This means we can't use an nsString
720       // and getter_Copies.
721       char16_t* uniPassword = nullptr;
722       if (!aPassword.IsEmpty()) uniPassword = ToNewUnicode(aPassword);
723 
724       bool okayValue = true;
725       rv = dialog->PromptPassword(PromiseFlatString(aPromptTitle).get(),
726                                   PromiseFlatString(aPromptMessage).get(),
727                                   NS_ConvertASCIItoUTF16(serverUri).get(),
728                                   nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
729                                   &uniPassword, &okayValue);
730       NS_ENSURE_SUCCESS(rv, rv);
731 
732       if (!okayValue)  // if the user pressed cancel, just return an empty
733                        // string;
734       {
735         aPassword.Truncate();
736         return NS_MSG_PASSWORD_PROMPT_CANCELLED;
737       }
738 
739       // we got a password back...so remember it
740       rv = SetPassword(nsDependentString(uniPassword));
741       NS_ENSURE_SUCCESS(rv, rv);
742 
743       PR_FREEIF(uniPassword);
744     }  // if we got a prompt dialog
745     else
746       return NS_ERROR_FAILURE;
747   }  // if the password is empty
748   return GetPassword(aPassword);
749 }
750 
751 NS_IMETHODIMP
ForgetPassword()752 nsMsgIncomingServer::ForgetPassword() {
753   nsresult rv;
754   nsCOMPtr<nsILoginManager> loginMgr =
755       do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv);
756   NS_ENSURE_SUCCESS(rv, rv);
757 
758   // Get the current server URI
759   nsCString currServerUri;
760   rv = GetLocalStoreType(currServerUri);
761   NS_ENSURE_SUCCESS(rv, rv);
762 
763   currServerUri.AppendLiteral("://");
764 
765   nsCString temp;
766   rv = GetHostName(temp);
767   NS_ENSURE_SUCCESS(rv, rv);
768 
769   currServerUri.Append(temp);
770 
771   NS_ConvertUTF8toUTF16 currServer(currServerUri);
772 
773   nsCString serverCUsername;
774   rv = GetUsername(serverCUsername);
775   NS_ENSURE_SUCCESS(rv, rv);
776 
777   NS_ConvertUTF8toUTF16 serverUsername(serverCUsername);
778 
779   nsTArray<RefPtr<nsILoginInfo>> logins;
780   rv = loginMgr->FindLogins(currServer, EmptyString(), currServer, logins);
781   NS_ENSURE_SUCCESS(rv, rv);
782 
783   // There should only be one-login stored for this url, however just in case
784   // there isn't.
785   nsString username;
786   for (uint32_t i = 0; i < logins.Length(); ++i) {
787     if (NS_SUCCEEDED(logins[i]->GetUsername(username)) &&
788         username.Equals(serverUsername)) {
789       // If this fails, just continue, we'll still want to remove the password
790       // from our local cache.
791       loginMgr->RemoveLogin(logins[i]);
792     }
793   }
794 
795   return SetPassword(EmptyString());
796 }
797 
798 NS_IMETHODIMP
ForgetSessionPassword()799 nsMsgIncomingServer::ForgetSessionPassword() {
800   m_password.Truncate();
801   return NS_OK;
802 }
803 
804 NS_IMETHODIMP
SetDefaultLocalPath(nsIFile * aDefaultLocalPath)805 nsMsgIncomingServer::SetDefaultLocalPath(nsIFile* aDefaultLocalPath) {
806   nsresult rv;
807   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
808   rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
809   NS_ENSURE_SUCCESS(rv, rv);
810   return protocolInfo->SetDefaultLocalPath(aDefaultLocalPath);
811 }
812 
813 NS_IMETHODIMP
GetLocalPath(nsIFile ** aLocalPath)814 nsMsgIncomingServer::GetLocalPath(nsIFile** aLocalPath) {
815   nsresult rv;
816 
817   // if the local path has already been set, use it
818   rv = GetFileValue("directory-rel", "directory", aLocalPath);
819   if (NS_SUCCEEDED(rv) && *aLocalPath) return rv;
820 
821   // otherwise, create the path using the protocol info.
822   // note we are using the
823   // hostname, unless that directory exists.
824   // this should prevent all collisions.
825   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
826   rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
827   NS_ENSURE_SUCCESS(rv, rv);
828 
829   nsCOMPtr<nsIFile> localPath;
830   rv = protocolInfo->GetDefaultLocalPath(getter_AddRefs(localPath));
831   NS_ENSURE_SUCCESS(rv, rv);
832   rv = localPath->Create(nsIFile::DIRECTORY_TYPE, 0755);
833   if (rv == NS_ERROR_FILE_ALREADY_EXISTS) rv = NS_OK;
834   NS_ENSURE_SUCCESS(rv, rv);
835 
836   nsCString hostname;
837   rv = GetHostName(hostname);
838   NS_ENSURE_SUCCESS(rv, rv);
839 
840   // set the leaf name to "dummy", and then call MakeUnique with a suggested
841   // leaf name
842   rv = localPath->AppendNative(hostname);
843   NS_ENSURE_SUCCESS(rv, rv);
844   rv = localPath->CreateUnique(nsIFile::DIRECTORY_TYPE, 0755);
845   NS_ENSURE_SUCCESS(rv, rv);
846 
847   rv = SetLocalPath(localPath);
848   NS_ENSURE_SUCCESS(rv, rv);
849 
850   localPath.forget(aLocalPath);
851   return NS_OK;
852 }
853 
854 NS_IMETHODIMP
GetMsgStore(nsIMsgPluggableStore ** aMsgStore)855 nsMsgIncomingServer::GetMsgStore(nsIMsgPluggableStore** aMsgStore) {
856   NS_ENSURE_ARG_POINTER(aMsgStore);
857   if (!m_msgStore) {
858     nsCString storeContractID;
859     nsresult rv;
860     // We don't want there to be a default pref, I think, since
861     // we can't change the default. We may want no pref to mean
862     // berkeley store, and then set the store pref off of some sort
863     // of default when creating a server. But we need to make sure
864     // that we do always write a store pref.
865     GetCharValue("storeContractID", storeContractID);
866     if (storeContractID.IsEmpty()) {
867       storeContractID.AssignLiteral("@mozilla.org/msgstore/berkeleystore;1");
868       SetCharValue("storeContractID", storeContractID);
869     }
870 
871     // After someone starts using the pluggable store, we can no longer
872     // change the value.
873     SetBoolValue("canChangeStoreType", false);
874 
875     // Right now, we just have one pluggable store per server. If we want
876     // to support multiple, this pref could be a list of pluggable store
877     // contract id's.
878     m_msgStore = do_CreateInstance(storeContractID.get(), &rv);
879     NS_ENSURE_SUCCESS(rv, rv);
880   }
881   NS_IF_ADDREF(*aMsgStore = m_msgStore);
882   return NS_OK;
883 }
884 
885 NS_IMETHODIMP
SetLocalPath(nsIFile * aLocalPath)886 nsMsgIncomingServer::SetLocalPath(nsIFile* aLocalPath) {
887   NS_ENSURE_ARG_POINTER(aLocalPath);
888   nsresult rv = aLocalPath->Create(nsIFile::DIRECTORY_TYPE, 0755);
889   if (rv == NS_ERROR_FILE_ALREADY_EXISTS) rv = NS_OK;
890   NS_ENSURE_SUCCESS(rv, rv);
891   return SetFileValue("directory-rel", "directory", aLocalPath);
892 }
893 
894 NS_IMETHODIMP
GetLocalStoreType(nsACString & aResult)895 nsMsgIncomingServer::GetLocalStoreType(nsACString& aResult) {
896   MOZ_ASSERT_UNREACHABLE(
897       "nsMsgIncomingServer superclass not implementing GetLocalStoreType!");
898   return NS_ERROR_UNEXPECTED;
899 }
900 
901 NS_IMETHODIMP
GetLocalDatabaseType(nsACString & aResult)902 nsMsgIncomingServer::GetLocalDatabaseType(nsACString& aResult) {
903   MOZ_ASSERT_UNREACHABLE(
904       "nsMsgIncomingServer superclass not implementing GetLocalDatabaseType!");
905   return NS_ERROR_UNEXPECTED;
906 }
907 
908 NS_IMETHODIMP
GetAccountManagerChrome(nsAString & aResult)909 nsMsgIncomingServer::GetAccountManagerChrome(nsAString& aResult) {
910   aResult.AssignLiteral("am-main.xhtml");
911   return NS_OK;
912 }
913 
914 NS_IMETHODIMP
Equals(nsIMsgIncomingServer * server,bool * _retval)915 nsMsgIncomingServer::Equals(nsIMsgIncomingServer* server, bool* _retval) {
916   nsresult rv;
917 
918   NS_ENSURE_ARG_POINTER(server);
919   NS_ENSURE_ARG_POINTER(_retval);
920 
921   nsCString key1;
922   nsCString key2;
923 
924   rv = GetKey(key1);
925   NS_ENSURE_SUCCESS(rv, rv);
926 
927   rv = server->GetKey(key2);
928   NS_ENSURE_SUCCESS(rv, rv);
929 
930   // compare the server keys
931   *_retval = key1.Equals(key2, nsCaseInsensitiveCStringComparator);
932 
933   return rv;
934 }
935 
936 NS_IMETHODIMP
ClearAllValues()937 nsMsgIncomingServer::ClearAllValues() {
938   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
939 
940   nsTArray<nsCString> prefNames;
941   nsresult rv = mPrefBranch->GetChildList("", prefNames);
942   NS_ENSURE_SUCCESS(rv, rv);
943 
944   for (auto& prefName : prefNames) {
945     mPrefBranch->ClearUserPref(prefName.get());
946   }
947 
948   return NS_OK;
949 }
950 
951 NS_IMETHODIMP
RemoveFiles()952 nsMsgIncomingServer::RemoveFiles() {
953   // IMPORTANT, see bug #77652
954   // TODO: Decide what to do for deferred accounts.
955   nsCString deferredToAccount;
956   GetCharValue("deferred_to_account", deferredToAccount);
957   bool isDeferredTo = true;
958   GetIsDeferredTo(&isDeferredTo);
959   if (!deferredToAccount.IsEmpty() || isDeferredTo) {
960     NS_ASSERTION(false, "shouldn't remove files for a deferred account");
961     return NS_ERROR_FAILURE;
962   }
963   nsCOMPtr<nsIFile> localPath;
964   nsresult rv = GetLocalPath(getter_AddRefs(localPath));
965   NS_ENSURE_SUCCESS(rv, rv);
966   return localPath->Remove(true);
967 }
968 
969 NS_IMETHODIMP
SetFilterList(nsIMsgFilterList * aFilterList)970 nsMsgIncomingServer::SetFilterList(nsIMsgFilterList* aFilterList) {
971   mFilterList = aFilterList;
972   return NS_OK;
973 }
974 
975 NS_IMETHODIMP
GetFilterList(nsIMsgWindow * aMsgWindow,nsIMsgFilterList ** aResult)976 nsMsgIncomingServer::GetFilterList(nsIMsgWindow* aMsgWindow,
977                                    nsIMsgFilterList** aResult) {
978   NS_ENSURE_ARG_POINTER(aResult);
979   if (!mFilterList) {
980     nsCOMPtr<nsIMsgFolder> msgFolder;
981     // use GetRootFolder so for deferred pop3 accounts, we'll get the filters
982     // file from the deferred account, not the deferred to account,
983     // so that filters will still be per-server.
984     nsresult rv = GetRootFolder(getter_AddRefs(msgFolder));
985     NS_ENSURE_SUCCESS(rv, rv);
986 
987     nsCString filterType;
988     rv = GetCharValue("filter.type", filterType);
989     NS_ENSURE_SUCCESS(rv, rv);
990 
991     if (!filterType.IsEmpty() && !filterType.EqualsLiteral("default")) {
992       nsAutoCString contractID("@mozilla.org/filterlist;1?type=");
993       contractID += filterType;
994       ToLowerCase(contractID);
995       mFilterList = do_CreateInstance(contractID.get(), &rv);
996       NS_ENSURE_SUCCESS(rv, rv);
997 
998       rv = mFilterList->SetFolder(msgFolder);
999       NS_ENSURE_SUCCESS(rv, rv);
1000 
1001       NS_ADDREF(*aResult = mFilterList);
1002       return NS_OK;
1003     }
1004 
1005     // The default case, a local folder, is a bit special. It requires
1006     // more initialization.
1007 
1008     nsCOMPtr<nsIFile> thisFolder;
1009     rv = msgFolder->GetFilePath(getter_AddRefs(thisFolder));
1010     NS_ENSURE_SUCCESS(rv, rv);
1011 
1012     mFilterFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
1013     NS_ENSURE_SUCCESS(rv, rv);
1014     rv = mFilterFile->InitWithFile(thisFolder);
1015     NS_ENSURE_SUCCESS(rv, rv);
1016 
1017     mFilterFile->AppendNative("msgFilterRules.dat"_ns);
1018 
1019     bool fileExists;
1020     mFilterFile->Exists(&fileExists);
1021     if (!fileExists) {
1022       nsCOMPtr<nsIFile> oldFilterFile =
1023           do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
1024       NS_ENSURE_SUCCESS(rv, rv);
1025       rv = oldFilterFile->InitWithFile(thisFolder);
1026       NS_ENSURE_SUCCESS(rv, rv);
1027       oldFilterFile->AppendNative("rules.dat"_ns);
1028 
1029       oldFilterFile->Exists(&fileExists);
1030       if (fileExists)  // copy rules.dat --> msgFilterRules.dat
1031       {
1032         rv = oldFilterFile->CopyToNative(thisFolder, "msgFilterRules.dat"_ns);
1033         NS_ENSURE_SUCCESS(rv, rv);
1034       }
1035     }
1036     nsCOMPtr<nsIMsgFilterService> filterService =
1037         do_GetService(NS_MSGFILTERSERVICE_CONTRACTID, &rv);
1038     NS_ENSURE_SUCCESS(rv, rv);
1039 
1040     rv = filterService->OpenFilterList(mFilterFile, msgFolder, aMsgWindow,
1041                                        getter_AddRefs(mFilterList));
1042     NS_ENSURE_SUCCESS(rv, rv);
1043   }
1044 
1045   NS_IF_ADDREF(*aResult = mFilterList);
1046   return NS_OK;
1047 }
1048 
1049 NS_IMETHODIMP
SetEditableFilterList(nsIMsgFilterList * aEditableFilterList)1050 nsMsgIncomingServer::SetEditableFilterList(
1051     nsIMsgFilterList* aEditableFilterList) {
1052   mEditableFilterList = aEditableFilterList;
1053   return NS_OK;
1054 }
1055 
1056 NS_IMETHODIMP
GetEditableFilterList(nsIMsgWindow * aMsgWindow,nsIMsgFilterList ** aResult)1057 nsMsgIncomingServer::GetEditableFilterList(nsIMsgWindow* aMsgWindow,
1058                                            nsIMsgFilterList** aResult) {
1059   NS_ENSURE_ARG_POINTER(aResult);
1060   if (!mEditableFilterList) {
1061     bool editSeparate;
1062     nsresult rv = GetBoolValue("filter.editable.separate", &editSeparate);
1063     if (NS_FAILED(rv) || !editSeparate)
1064       return GetFilterList(aMsgWindow, aResult);
1065 
1066     nsCString filterType;
1067     rv = GetCharValue("filter.editable.type", filterType);
1068     NS_ENSURE_SUCCESS(rv, rv);
1069 
1070     nsAutoCString contractID("@mozilla.org/filterlist;1?type=");
1071     contractID += filterType;
1072     ToLowerCase(contractID);
1073     mEditableFilterList = do_CreateInstance(contractID.get(), &rv);
1074     NS_ENSURE_SUCCESS(rv, rv);
1075 
1076     nsCOMPtr<nsIMsgFolder> msgFolder;
1077     // use GetRootFolder so for deferred pop3 accounts, we'll get the filters
1078     // file from the deferred account, not the deferred to account,
1079     // so that filters will still be per-server.
1080     rv = GetRootFolder(getter_AddRefs(msgFolder));
1081     NS_ENSURE_SUCCESS(rv, rv);
1082 
1083     rv = mEditableFilterList->SetFolder(msgFolder);
1084     NS_ENSURE_SUCCESS(rv, rv);
1085 
1086     NS_ADDREF(*aResult = mEditableFilterList);
1087     return NS_OK;
1088   }
1089 
1090   NS_IF_ADDREF(*aResult = mEditableFilterList);
1091   return NS_OK;
1092 }
1093 
1094 // If the hostname contains ':' (like hostname:1431)
1095 // then parse and set the port number.
InternalSetHostName(const nsACString & aHostname,const char * prefName)1096 nsresult nsMsgIncomingServer::InternalSetHostName(const nsACString& aHostname,
1097                                                   const char* prefName) {
1098   nsCString hostname;
1099   hostname = aHostname;
1100   if (hostname.CountChar(':') == 1) {
1101     int32_t colonPos = hostname.FindChar(':');
1102     nsAutoCString portString(Substring(hostname, colonPos));
1103     hostname.SetLength(colonPos);
1104     nsresult err;
1105     int32_t port = portString.ToInteger(&err);
1106     if (NS_SUCCEEDED(err)) SetPort(port);
1107   }
1108   return SetCharValue(prefName, hostname);
1109 }
1110 
1111 NS_IMETHODIMP
OnUserOrHostNameChanged(const nsACString & oldName,const nsACString & newName,bool hostnameChanged)1112 nsMsgIncomingServer::OnUserOrHostNameChanged(const nsACString& oldName,
1113                                              const nsACString& newName,
1114                                              bool hostnameChanged) {
1115   nsresult rv;
1116 
1117   // 1. Reset password so that users are prompted for new password for the new
1118   // user/host.
1119   int32_t atPos = newName.FindChar('@');
1120   // If only username changed and the new name just added a domain
1121   // we can keep the password.
1122   if (hostnameChanged || (atPos == kNotFound) ||
1123       !StringHead(NS_ConvertASCIItoUTF16(newName), atPos)
1124            .Equals(NS_ConvertASCIItoUTF16(oldName))) {
1125     ForgetPassword();
1126   }
1127 
1128   // 2. Let the derived class close all cached connection to the old host.
1129   CloseCachedConnections();
1130 
1131   // 3. Notify any listeners for account server changes.
1132   nsCOMPtr<nsIMsgAccountManager> accountManager(
1133       mozilla::services::GetAccountManager());
1134 
1135   rv = accountManager->NotifyServerChanged(this);
1136   NS_ENSURE_SUCCESS(rv, rv);
1137 
1138   // 4. Replace all occurrences of old name in the acct name with the new one.
1139   nsString acctName;
1140   rv = GetPrettyName(acctName);
1141   NS_ENSURE_SUCCESS(rv, rv);
1142 
1143   // 5. Clear the clientid because the user or host have changed.
1144   SetClientid(EmptyCString());
1145 
1146   // If new username contains @ then better do not update the account name.
1147   if (acctName.IsEmpty() || (!hostnameChanged && (atPos != kNotFound)))
1148     return NS_OK;
1149 
1150   atPos = acctName.FindChar('@');
1151 
1152   // get previous username and hostname
1153   nsCString userName, hostName;
1154   if (hostnameChanged) {
1155     rv = GetRealUsername(userName);
1156     NS_ENSURE_SUCCESS(rv, rv);
1157     hostName.Assign(oldName);
1158   } else {
1159     userName.Assign(oldName);
1160     rv = GetRealHostName(hostName);
1161     NS_ENSURE_SUCCESS(rv, rv);
1162   }
1163 
1164   // switch corresponding part of the account name to the new name...
1165   if (!hostnameChanged && (atPos != kNotFound)) {
1166     // ...if username changed and the previous username was equal to the part
1167     // of the account name before @
1168     if (StringHead(acctName, atPos).Equals(NS_ConvertASCIItoUTF16(userName)))
1169       acctName.Replace(0, userName.Length(), NS_ConvertASCIItoUTF16(newName));
1170   }
1171   if (hostnameChanged) {
1172     // ...if hostname changed and the previous hostname was equal to the part
1173     // of the account name after @, or to the whole account name
1174     if (atPos == kNotFound)
1175       atPos = 0;
1176     else
1177       atPos += 1;
1178     if (Substring(acctName, atPos).Equals(NS_ConvertASCIItoUTF16(hostName))) {
1179       acctName.Replace(atPos, acctName.Length() - atPos,
1180                        NS_ConvertASCIItoUTF16(newName));
1181     }
1182   }
1183 
1184   return SetPrettyName(acctName);
1185 }
1186 
1187 NS_IMETHODIMP
SetHostName(const nsACString & aHostname)1188 nsMsgIncomingServer::SetHostName(const nsACString& aHostname) {
1189   return (InternalSetHostName(aHostname, "hostname"));
1190 }
1191 
1192 // SetRealHostName() is called only when the server name is changed from the
1193 // UI (Account Settings page).  No one should call it in any circumstances.
1194 NS_IMETHODIMP
SetRealHostName(const nsACString & aHostname)1195 nsMsgIncomingServer::SetRealHostName(const nsACString& aHostname) {
1196   nsCString oldName;
1197   nsresult rv = GetRealHostName(oldName);
1198   NS_ENSURE_SUCCESS(rv, rv);
1199   rv = InternalSetHostName(aHostname, "realhostname");
1200 
1201   // A few things to take care of if we're changing the hostname.
1202   if (!aHostname.Equals(oldName, nsCaseInsensitiveCStringComparator))
1203     rv = OnUserOrHostNameChanged(oldName, aHostname, true);
1204   return rv;
1205 }
1206 
1207 NS_IMETHODIMP
GetHostName(nsACString & aResult)1208 nsMsgIncomingServer::GetHostName(nsACString& aResult) {
1209   nsresult rv;
1210   rv = GetCharValue("hostname", aResult);
1211   if (aResult.CountChar(':') == 1) {
1212     // gack, we need to reformat the hostname - SetHostName will do that
1213     SetHostName(aResult);
1214     rv = GetCharValue("hostname", aResult);
1215   }
1216   return rv;
1217 }
1218 
1219 NS_IMETHODIMP
GetRealHostName(nsACString & aResult)1220 nsMsgIncomingServer::GetRealHostName(nsACString& aResult) {
1221   // If 'realhostname' is set (was changed) then use it, otherwise use
1222   // 'hostname'
1223   nsresult rv;
1224   rv = GetCharValue("realhostname", aResult);
1225   NS_ENSURE_SUCCESS(rv, rv);
1226 
1227   if (aResult.IsEmpty()) return GetHostName(aResult);
1228 
1229   if (aResult.CountChar(':') == 1) {
1230     SetRealHostName(aResult);
1231     rv = GetCharValue("realhostname", aResult);
1232   }
1233 
1234   return rv;
1235 }
1236 
1237 NS_IMETHODIMP
GetRealUsername(nsACString & aResult)1238 nsMsgIncomingServer::GetRealUsername(nsACString& aResult) {
1239   // If 'realuserName' is set (was changed) then use it, otherwise use
1240   // 'userName'
1241   nsresult rv;
1242   rv = GetCharValue("realuserName", aResult);
1243   NS_ENSURE_SUCCESS(rv, rv);
1244   return aResult.IsEmpty() ? GetUsername(aResult) : rv;
1245 }
1246 
1247 NS_IMETHODIMP
SetRealUsername(const nsACString & aUsername)1248 nsMsgIncomingServer::SetRealUsername(const nsACString& aUsername) {
1249   // Need to take care of few things if we're changing the username.
1250   nsCString oldName;
1251   nsresult rv = GetRealUsername(oldName);
1252   NS_ENSURE_SUCCESS(rv, rv);
1253   rv = SetCharValue("realuserName", aUsername);
1254   if (!oldName.Equals(aUsername))
1255     rv = OnUserOrHostNameChanged(oldName, aUsername, false);
1256   return rv;
1257 }
1258 
1259 #define BIFF_PREF_NAME "check_new_mail"
1260 
1261 NS_IMETHODIMP
GetDoBiff(bool * aDoBiff)1262 nsMsgIncomingServer::GetDoBiff(bool* aDoBiff) {
1263   NS_ENSURE_ARG_POINTER(aDoBiff);
1264 
1265   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
1266 
1267   nsresult rv;
1268 
1269   rv = mPrefBranch->GetBoolPref(BIFF_PREF_NAME, aDoBiff);
1270   if (NS_SUCCEEDED(rv)) return rv;
1271 
1272   // if the pref isn't set, use the default
1273   // value based on the protocol
1274   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
1275   rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
1276   NS_ENSURE_SUCCESS(rv, rv);
1277 
1278   rv = protocolInfo->GetDefaultDoBiff(aDoBiff);
1279   // note, don't call SetDoBiff()
1280   // since we keep changing our minds on
1281   // if biff should be on or off, let's keep the ability
1282   // to change the default in future builds.
1283   // if we call SetDoBiff() here, it will be in the users prefs.
1284   // and we can't do anything after that.
1285   return rv;
1286 }
1287 
1288 NS_IMETHODIMP
SetDoBiff(bool aDoBiff)1289 nsMsgIncomingServer::SetDoBiff(bool aDoBiff) {
1290   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
1291 
1292   // Update biffManager immediately, no restart required. Adding/removing
1293   // existing/non-existing server is handled without error checking.
1294   nsresult rv;
1295   nsCOMPtr<nsIMsgBiffManager> biffService =
1296       do_GetService(NS_MSGBIFFMANAGER_CONTRACTID, &rv);
1297   if (NS_SUCCEEDED(rv) && biffService) {
1298     if (aDoBiff)
1299       (void)biffService->AddServerBiff(this);
1300     else
1301       (void)biffService->RemoveServerBiff(this);
1302   }
1303 
1304   return mPrefBranch->SetBoolPref(BIFF_PREF_NAME, aDoBiff);
1305 }
1306 
1307 NS_IMETHODIMP
GetPort(int32_t * aPort)1308 nsMsgIncomingServer::GetPort(int32_t* aPort) {
1309   NS_ENSURE_ARG_POINTER(aPort);
1310 
1311   nsresult rv;
1312   rv = GetIntValue("port", aPort);
1313   // We can't use a port of 0, because the URI parsing code fails.
1314   if (*aPort != PORT_NOT_SET && *aPort) return rv;
1315 
1316   // if the port isn't set, use the default
1317   // port based on the protocol
1318   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
1319   rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
1320   NS_ENSURE_SUCCESS(rv, rv);
1321 
1322   int32_t socketType;
1323   rv = GetSocketType(&socketType);
1324   NS_ENSURE_SUCCESS(rv, rv);
1325   bool useSSLPort = (socketType == nsMsgSocketType::SSL);
1326   return protocolInfo->GetDefaultServerPort(useSSLPort, aPort);
1327 }
1328 
1329 NS_IMETHODIMP
SetPort(int32_t aPort)1330 nsMsgIncomingServer::SetPort(int32_t aPort) {
1331   nsresult rv;
1332 
1333   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
1334   rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
1335   NS_ENSURE_SUCCESS(rv, rv);
1336 
1337   int32_t socketType;
1338   rv = GetSocketType(&socketType);
1339   NS_ENSURE_SUCCESS(rv, rv);
1340   bool useSSLPort = (socketType == nsMsgSocketType::SSL);
1341 
1342   int32_t defaultPort;
1343   protocolInfo->GetDefaultServerPort(useSSLPort, &defaultPort);
1344   return SetIntValue("port", aPort == defaultPort ? PORT_NOT_SET : aPort);
1345 }
1346 
1347 NS_IMETHODIMP
GetProtocolInfo(nsIMsgProtocolInfo ** aResult)1348 nsMsgIncomingServer::GetProtocolInfo(nsIMsgProtocolInfo** aResult) {
1349   NS_ENSURE_ARG_POINTER(aResult);
1350 
1351   nsCString type;
1352   nsresult rv = GetType(type);
1353   NS_ENSURE_SUCCESS(rv, rv);
1354 
1355   nsAutoCString contractid(NS_MSGPROTOCOLINFO_CONTRACTID_PREFIX);
1356   contractid.Append(type);
1357 
1358   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo =
1359       do_GetService(contractid.get(), &rv);
1360   NS_ENSURE_SUCCESS(rv, rv);
1361 
1362   protocolInfo.forget(aResult);
1363   return NS_OK;
1364 }
1365 
GetRetentionSettings(nsIMsgRetentionSettings ** settings)1366 NS_IMETHODIMP nsMsgIncomingServer::GetRetentionSettings(
1367     nsIMsgRetentionSettings** settings) {
1368   NS_ENSURE_ARG_POINTER(settings);
1369   nsMsgRetainByPreference retainByPreference;
1370   int32_t daysToKeepHdrs = 0;
1371   int32_t numHeadersToKeep = 0;
1372   int32_t daysToKeepBodies = 0;
1373   bool cleanupBodiesByDays = false;
1374   bool applyToFlaggedMessages = false;
1375   nsresult rv = NS_OK;
1376   // Create an empty retention settings object,
1377   // get the settings from the server prefs, and init the object from the prefs.
1378   nsCOMPtr<nsIMsgRetentionSettings> retentionSettings =
1379       do_CreateInstance(NS_MSG_RETENTIONSETTINGS_CONTRACTID);
1380   if (retentionSettings) {
1381     rv = GetIntValue("retainBy", (int32_t*)&retainByPreference);
1382     NS_ENSURE_SUCCESS(rv, rv);
1383     rv = GetIntValue("numHdrsToKeep", &numHeadersToKeep);
1384     NS_ENSURE_SUCCESS(rv, rv);
1385     rv = GetIntValue("daysToKeepHdrs", &daysToKeepHdrs);
1386     NS_ENSURE_SUCCESS(rv, rv);
1387     rv = GetIntValue("daysToKeepBodies", &daysToKeepBodies);
1388     NS_ENSURE_SUCCESS(rv, rv);
1389     rv = GetBoolValue("cleanupBodies", &cleanupBodiesByDays);
1390     NS_ENSURE_SUCCESS(rv, rv);
1391     rv = GetBoolValue("applyToFlaggedMessages", &applyToFlaggedMessages);
1392     NS_ENSURE_SUCCESS(rv, rv);
1393     retentionSettings->SetRetainByPreference(retainByPreference);
1394     retentionSettings->SetNumHeadersToKeep((uint32_t)numHeadersToKeep);
1395     retentionSettings->SetDaysToKeepBodies(daysToKeepBodies);
1396     retentionSettings->SetDaysToKeepHdrs(daysToKeepHdrs);
1397     retentionSettings->SetCleanupBodiesByDays(cleanupBodiesByDays);
1398     retentionSettings->SetApplyToFlaggedMessages(applyToFlaggedMessages);
1399   } else
1400     rv = NS_ERROR_OUT_OF_MEMORY;
1401   NS_IF_ADDREF(*settings = retentionSettings);
1402   return rv;
1403 }
1404 
SetRetentionSettings(nsIMsgRetentionSettings * settings)1405 NS_IMETHODIMP nsMsgIncomingServer::SetRetentionSettings(
1406     nsIMsgRetentionSettings* settings) {
1407   nsMsgRetainByPreference retainByPreference;
1408   uint32_t daysToKeepHdrs = 0;
1409   uint32_t numHeadersToKeep = 0;
1410   uint32_t daysToKeepBodies = 0;
1411   bool cleanupBodiesByDays = false;
1412   bool applyToFlaggedMessages = false;
1413   settings->GetRetainByPreference(&retainByPreference);
1414   settings->GetNumHeadersToKeep(&numHeadersToKeep);
1415   settings->GetDaysToKeepBodies(&daysToKeepBodies);
1416   settings->GetDaysToKeepHdrs(&daysToKeepHdrs);
1417   settings->GetCleanupBodiesByDays(&cleanupBodiesByDays);
1418   settings->GetApplyToFlaggedMessages(&applyToFlaggedMessages);
1419   nsresult rv = SetIntValue("retainBy", retainByPreference);
1420   NS_ENSURE_SUCCESS(rv, rv);
1421   rv = SetIntValue("numHdrsToKeep", numHeadersToKeep);
1422   NS_ENSURE_SUCCESS(rv, rv);
1423   rv = SetIntValue("daysToKeepHdrs", daysToKeepHdrs);
1424   NS_ENSURE_SUCCESS(rv, rv);
1425   rv = SetIntValue("daysToKeepBodies", daysToKeepBodies);
1426   NS_ENSURE_SUCCESS(rv, rv);
1427   rv = SetBoolValue("cleanupBodies", cleanupBodiesByDays);
1428   NS_ENSURE_SUCCESS(rv, rv);
1429   rv = SetBoolValue("applyToFlaggedMessages", applyToFlaggedMessages);
1430   NS_ENSURE_SUCCESS(rv, rv);
1431   return NS_OK;
1432 }
1433 
1434 NS_IMETHODIMP
GetDisplayStartupPage(bool * displayStartupPage)1435 nsMsgIncomingServer::GetDisplayStartupPage(bool* displayStartupPage) {
1436   NS_ENSURE_ARG_POINTER(displayStartupPage);
1437   *displayStartupPage = m_displayStartupPage;
1438   return NS_OK;
1439 }
1440 
1441 NS_IMETHODIMP
SetDisplayStartupPage(bool displayStartupPage)1442 nsMsgIncomingServer::SetDisplayStartupPage(bool displayStartupPage) {
1443   m_displayStartupPage = displayStartupPage;
1444   return NS_OK;
1445 }
1446 
GetDownloadSettings(nsIMsgDownloadSettings ** settings)1447 NS_IMETHODIMP nsMsgIncomingServer::GetDownloadSettings(
1448     nsIMsgDownloadSettings** settings) {
1449   NS_ENSURE_ARG_POINTER(settings);
1450   bool downloadUnreadOnly = false;
1451   bool downloadByDate = false;
1452   uint32_t ageLimitOfMsgsToDownload = 0;
1453   nsresult rv = NS_OK;
1454   if (!m_downloadSettings) {
1455     m_downloadSettings = do_CreateInstance(NS_MSG_DOWNLOADSETTINGS_CONTRACTID);
1456     if (m_downloadSettings) {
1457       rv = GetBoolValue("downloadUnreadOnly", &downloadUnreadOnly);
1458       rv = GetBoolValue("downloadByDate", &downloadByDate);
1459       rv = GetIntValue("ageLimit", (int32_t*)&ageLimitOfMsgsToDownload);
1460       m_downloadSettings->SetDownloadUnreadOnly(downloadUnreadOnly);
1461       m_downloadSettings->SetDownloadByDate(downloadByDate);
1462       m_downloadSettings->SetAgeLimitOfMsgsToDownload(ageLimitOfMsgsToDownload);
1463     } else
1464       rv = NS_ERROR_OUT_OF_MEMORY;
1465     // Create an empty download settings object,
1466     // get the settings from the server prefs, and init the object from the
1467     // prefs.
1468   }
1469   NS_IF_ADDREF(*settings = m_downloadSettings);
1470   return rv;
1471 }
1472 
SetDownloadSettings(nsIMsgDownloadSettings * settings)1473 NS_IMETHODIMP nsMsgIncomingServer::SetDownloadSettings(
1474     nsIMsgDownloadSettings* settings) {
1475   m_downloadSettings = settings;
1476   bool downloadUnreadOnly = false;
1477   bool downloadByDate = false;
1478   uint32_t ageLimitOfMsgsToDownload = 0;
1479   m_downloadSettings->GetDownloadUnreadOnly(&downloadUnreadOnly);
1480   m_downloadSettings->GetDownloadByDate(&downloadByDate);
1481   m_downloadSettings->GetAgeLimitOfMsgsToDownload(&ageLimitOfMsgsToDownload);
1482   nsresult rv = SetBoolValue("downloadUnreadOnly", downloadUnreadOnly);
1483   NS_ENSURE_SUCCESS(rv, rv);
1484   SetBoolValue("downloadByDate", downloadByDate);
1485   return SetIntValue("ageLimit", ageLimitOfMsgsToDownload);
1486 }
1487 
1488 NS_IMETHODIMP
GetSupportsDiskSpace(bool * aSupportsDiskSpace)1489 nsMsgIncomingServer::GetSupportsDiskSpace(bool* aSupportsDiskSpace) {
1490   NS_ENSURE_ARG_POINTER(aSupportsDiskSpace);
1491   *aSupportsDiskSpace = true;
1492   return NS_OK;
1493 }
1494 
1495 NS_IMETHODIMP
GetOfflineSupportLevel(int32_t * aSupportLevel)1496 nsMsgIncomingServer::GetOfflineSupportLevel(int32_t* aSupportLevel) {
1497   NS_ENSURE_ARG_POINTER(aSupportLevel);
1498 
1499   nsresult rv = GetIntValue("offline_support_level", aSupportLevel);
1500   NS_ENSURE_SUCCESS(rv, rv);
1501 
1502   if (*aSupportLevel == OFFLINE_SUPPORT_LEVEL_UNDEFINED)
1503     *aSupportLevel = OFFLINE_SUPPORT_LEVEL_NONE;
1504   return NS_OK;
1505 }
1506 
1507 NS_IMETHODIMP
SetOfflineSupportLevel(int32_t aSupportLevel)1508 nsMsgIncomingServer::SetOfflineSupportLevel(int32_t aSupportLevel) {
1509   SetIntValue("offline_support_level", aSupportLevel);
1510   return NS_OK;
1511 }
1512 #define BASE_MSGS_URL "chrome://messenger/locale/messenger.properties"
1513 
DisplayOfflineMsg(nsIMsgWindow * aMsgWindow)1514 NS_IMETHODIMP nsMsgIncomingServer::DisplayOfflineMsg(nsIMsgWindow* aMsgWindow) {
1515   NS_ENSURE_ARG_POINTER(aMsgWindow);
1516 
1517   nsCOMPtr<nsIStringBundleService> bundleService =
1518       mozilla::services::GetStringBundleService();
1519   NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
1520 
1521   nsCOMPtr<nsIStringBundle> bundle;
1522   nsresult rv =
1523       bundleService->CreateBundle(BASE_MSGS_URL, getter_AddRefs(bundle));
1524   NS_ENSURE_SUCCESS(rv, rv);
1525   if (bundle) {
1526     nsString errorMsgTitle;
1527     nsString errorMsgBody;
1528     bundle->GetStringFromName("nocachedbodybody2", errorMsgBody);
1529     bundle->GetStringFromName("nocachedbodytitle", errorMsgTitle);
1530     aMsgWindow->DisplayHTMLInMessagePane(errorMsgTitle, errorMsgBody, true);
1531   }
1532 
1533   return NS_OK;
1534 }
1535 
1536 // Called only during the migration process. A unique name is generated for the
1537 // migrated account.
1538 NS_IMETHODIMP
GeneratePrettyNameForMigration(nsAString & aPrettyName)1539 nsMsgIncomingServer::GeneratePrettyNameForMigration(nsAString& aPrettyName) {
1540   /**
1541    * 4.x had provisions for multiple imap servers to be maintained under
1542    * single identity. So, when migrated each of those server accounts need
1543    * to be represented by unique account name. nsImapIncomingServer will
1544    * override the implementation for this to do the right thing.
1545    */
1546   return NS_ERROR_NOT_IMPLEMENTED;
1547 }
1548 
1549 NS_IMETHODIMP
GetFilterScope(nsMsgSearchScopeValue * filterScope)1550 nsMsgIncomingServer::GetFilterScope(nsMsgSearchScopeValue* filterScope) {
1551   NS_ENSURE_ARG_POINTER(filterScope);
1552   *filterScope = nsMsgSearchScope::offlineMailFilter;
1553   return NS_OK;
1554 }
1555 
1556 NS_IMETHODIMP
GetSearchScope(nsMsgSearchScopeValue * searchScope)1557 nsMsgIncomingServer::GetSearchScope(nsMsgSearchScopeValue* searchScope) {
1558   NS_ENSURE_ARG_POINTER(searchScope);
1559   *searchScope = nsMsgSearchScope::offlineMail;
1560   return NS_OK;
1561 }
1562 
1563 NS_IMETHODIMP
GetIsSecure(bool * aIsSecure)1564 nsMsgIncomingServer::GetIsSecure(bool* aIsSecure) {
1565   NS_ENSURE_ARG_POINTER(aIsSecure);
1566   int32_t socketType;
1567   nsresult rv = GetSocketType(&socketType);
1568   NS_ENSURE_SUCCESS(rv, rv);
1569   *aIsSecure = (socketType == nsMsgSocketType::alwaysSTARTTLS ||
1570                 socketType == nsMsgSocketType::SSL);
1571   return NS_OK;
1572 }
1573 
1574 // use the convenience macros to implement the accessors
1575 NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, Username, "userName")
1576 NS_IMPL_SERVERPREF_INT(nsMsgIncomingServer, AuthMethod, "authMethod")
1577 NS_IMPL_SERVERPREF_INT(nsMsgIncomingServer, BiffMinutes, "check_time")
1578 NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, Type, "type")
1579 NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, Clientid, "clientid")
1580 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, ClientidEnabled, "clientidEnabled")
1581 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, DownloadOnBiff, "download_on_biff")
1582 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, Valid, "valid")
1583 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, EmptyTrashOnExit,
1584                         "empty_trash_on_exit")
1585 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, CanDelete, "canDelete")
1586 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, LoginAtStartUp, "login_at_startup")
1587 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer,
1588                         DefaultCopiesAndFoldersPrefsToServer,
1589                         "allows_specialfolders_usage")
1590 
1591 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, CanCreateFoldersOnServer,
1592                         "canCreateFolders")
1593 
1594 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, CanFileMessagesOnServer,
1595                         "canFileMessages")
1596 
1597 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, LimitOfflineMessageSize,
1598                         "limit_offline_message_size")
1599 
1600 NS_IMPL_SERVERPREF_INT(nsMsgIncomingServer, MaxMessageSize, "max_size")
1601 
1602 NS_IMPL_SERVERPREF_INT(nsMsgIncomingServer, IncomingDuplicateAction,
1603                        "dup_action")
1604 
1605 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, Hidden, "hidden")
1606 
GetSocketType(int32_t * aSocketType)1607 NS_IMETHODIMP nsMsgIncomingServer::GetSocketType(int32_t* aSocketType) {
1608   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
1609 
1610   nsresult rv = mPrefBranch->GetIntPref("socketType", aSocketType);
1611 
1612   // socketType is set to default value. Look at isSecure setting
1613   if (NS_FAILED(rv)) {
1614     bool isSecure;
1615     rv = mPrefBranch->GetBoolPref("isSecure", &isSecure);
1616     if (NS_SUCCEEDED(rv) && isSecure) {
1617       *aSocketType = nsMsgSocketType::SSL;
1618       // don't call virtual method in case overrides call GetSocketType
1619       nsMsgIncomingServer::SetSocketType(*aSocketType);
1620     } else {
1621       if (!mDefPrefBranch) return NS_ERROR_NOT_INITIALIZED;
1622       rv = mDefPrefBranch->GetIntPref("socketType", aSocketType);
1623       if (NS_FAILED(rv)) *aSocketType = nsMsgSocketType::plain;
1624     }
1625   }
1626   return rv;
1627 }
1628 
SetSocketType(int32_t aSocketType)1629 NS_IMETHODIMP nsMsgIncomingServer::SetSocketType(int32_t aSocketType) {
1630   if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
1631 
1632   int32_t socketType = nsMsgSocketType::plain;
1633   mPrefBranch->GetIntPref("socketType", &socketType);
1634 
1635   nsresult rv = mPrefBranch->SetIntPref("socketType", aSocketType);
1636   NS_ENSURE_SUCCESS(rv, rv);
1637 
1638   bool isSecureOld = (socketType == nsMsgSocketType::alwaysSTARTTLS ||
1639                       socketType == nsMsgSocketType::SSL);
1640   bool isSecureNew = (aSocketType == nsMsgSocketType::alwaysSTARTTLS ||
1641                       aSocketType == nsMsgSocketType::SSL);
1642   if ((isSecureOld != isSecureNew) && m_rootFolder) {
1643     m_rootFolder->NotifyBoolPropertyChanged(kIsSecure, isSecureOld,
1644                                             isSecureNew);
1645   }
1646   return NS_OK;
1647 }
1648 
1649 // Check if the password is available and return a boolean indicating whether
1650 // it is being authenticated or not.
1651 NS_IMETHODIMP
GetPasswordPromptRequired(bool * aPasswordIsRequired)1652 nsMsgIncomingServer::GetPasswordPromptRequired(bool* aPasswordIsRequired) {
1653   NS_ENSURE_ARG_POINTER(aPasswordIsRequired);
1654   *aPasswordIsRequired = true;
1655 
1656   // If the password is not even required for biff we don't need to check any
1657   // further
1658   nsresult rv = GetServerRequiresPasswordForBiff(aPasswordIsRequired);
1659   NS_ENSURE_SUCCESS(rv, rv);
1660   if (!*aPasswordIsRequired) return NS_OK;
1661 
1662   // If the password is empty, check to see if it is stored and to be retrieved
1663   if (m_password.IsEmpty()) (void)GetPasswordWithoutUI();
1664 
1665   *aPasswordIsRequired = m_password.IsEmpty();
1666   if (*aPasswordIsRequired) {
1667     // Set *aPasswordIsRequired false if authMethod is oauth2.
1668     int32_t authMethod = 0;
1669     rv = GetAuthMethod(&authMethod);
1670     if (NS_SUCCEEDED(rv) && authMethod == nsMsgAuthMethod::OAuth2) {
1671       *aPasswordIsRequired = false;
1672     }
1673   }
1674   return rv;
1675 }
1676 
ConfigureTemporaryFilters(nsIMsgFilterList * aFilterList)1677 NS_IMETHODIMP nsMsgIncomingServer::ConfigureTemporaryFilters(
1678     nsIMsgFilterList* aFilterList) {
1679   nsresult rv = ConfigureTemporaryReturnReceiptsFilter(aFilterList);
1680   if (NS_FAILED(rv))  // shut up warnings...
1681     return rv;
1682   return ConfigureTemporaryServerSpamFilters(aFilterList);
1683 }
1684 
ConfigureTemporaryServerSpamFilters(nsIMsgFilterList * filterList)1685 nsresult nsMsgIncomingServer::ConfigureTemporaryServerSpamFilters(
1686     nsIMsgFilterList* filterList) {
1687   nsCOMPtr<nsISpamSettings> spamSettings;
1688   nsresult rv = GetSpamSettings(getter_AddRefs(spamSettings));
1689   NS_ENSURE_SUCCESS(rv, rv);
1690 
1691   bool useServerFilter;
1692   rv = spamSettings->GetUseServerFilter(&useServerFilter);
1693   NS_ENSURE_SUCCESS(rv, rv);
1694 
1695   // if we aren't configured to use server filters, then return early.
1696   if (!useServerFilter) return NS_OK;
1697 
1698   // For performance reasons, we'll handle clearing of filters if the user turns
1699   // off the server-side filters from the junk mail controls, in the junk mail
1700   // controls.
1701   nsAutoCString serverFilterName;
1702   spamSettings->GetServerFilterName(serverFilterName);
1703   if (serverFilterName.IsEmpty()) return NS_OK;
1704   int32_t serverFilterTrustFlags = 0;
1705   (void)spamSettings->GetServerFilterTrustFlags(&serverFilterTrustFlags);
1706   if (!serverFilterTrustFlags) return NS_OK;
1707   // check if filters have been setup already.
1708   nsAutoString yesFilterName, noFilterName;
1709   CopyASCIItoUTF16(serverFilterName, yesFilterName);
1710   yesFilterName.AppendLiteral("Yes");
1711 
1712   CopyASCIItoUTF16(serverFilterName, noFilterName);
1713   noFilterName.AppendLiteral("No");
1714 
1715   nsCOMPtr<nsIMsgFilter> newFilter;
1716   (void)filterList->GetFilterNamed(yesFilterName, getter_AddRefs(newFilter));
1717 
1718   if (!newFilter)
1719     (void)filterList->GetFilterNamed(noFilterName, getter_AddRefs(newFilter));
1720   if (newFilter) return NS_OK;
1721 
1722   nsCOMPtr<nsIFile> file;
1723   spamSettings->GetServerFilterFile(getter_AddRefs(file));
1724 
1725   // it's possible that we can no longer find the sfd file (i.e. the user
1726   // disabled an extnsion that was supplying the .sfd file.
1727   if (!file) return NS_OK;
1728 
1729   nsCOMPtr<nsIMsgFilterService> filterService =
1730       do_GetService(NS_MSGFILTERSERVICE_CONTRACTID, &rv);
1731   nsCOMPtr<nsIMsgFilterList> serverFilterList;
1732 
1733   rv = filterService->OpenFilterList(file, NULL, NULL,
1734                                      getter_AddRefs(serverFilterList));
1735   NS_ENSURE_SUCCESS(rv, rv);
1736 
1737   rv = serverFilterList->GetFilterNamed(yesFilterName,
1738                                         getter_AddRefs(newFilter));
1739   if (newFilter && serverFilterTrustFlags & nsISpamSettings::TRUST_POSITIVES) {
1740     newFilter->SetTemporary(true);
1741     // check if we're supposed to move junk mail to junk folder; if so,
1742     // add filter action to do so.
1743 
1744     /*
1745      * We don't want this filter to activate on messages that have
1746      *  been marked by the user as not spam. This occurs when messages that
1747      *  were marked as good are moved back into the inbox. But to
1748      *  do this with a filter, we have to add a boolean term. That requires
1749      *  that we rewrite the existing filter search terms to group them.
1750      */
1751 
1752     // get the list of search terms from the filter
1753     nsTArray<RefPtr<nsIMsgSearchTerm>> searchTerms;
1754     rv = newFilter->GetSearchTerms(searchTerms);
1755     NS_ENSURE_SUCCESS(rv, rv);
1756     uint32_t count = searchTerms.Length();
1757     if (count > 1)  // don't need to group a single term
1758     {
1759       // beginGrouping the first term, and endGrouping the last term
1760       searchTerms[0]->SetBeginsGrouping(true);
1761       searchTerms[count - 1]->SetEndsGrouping(true);
1762     }
1763 
1764     // Create a new term, checking if the user set junk status. The term will
1765     // search for junkscoreorigin != "user"
1766     nsCOMPtr<nsIMsgSearchTerm> searchTerm;
1767     rv = newFilter->CreateTerm(getter_AddRefs(searchTerm));
1768     NS_ENSURE_SUCCESS(rv, rv);
1769 
1770     searchTerm->SetAttrib(nsMsgSearchAttrib::JunkScoreOrigin);
1771     searchTerm->SetOp(nsMsgSearchOp::Isnt);
1772     searchTerm->SetBooleanAnd(true);
1773 
1774     nsCOMPtr<nsIMsgSearchValue> searchValue;
1775     searchTerm->GetValue(getter_AddRefs(searchValue));
1776     NS_ENSURE_SUCCESS(rv, rv);
1777     searchValue->SetAttrib(nsMsgSearchAttrib::JunkScoreOrigin);
1778     searchValue->SetStr(u"user"_ns);
1779     searchTerm->SetValue(searchValue);
1780 
1781     newFilter->AppendTerm(searchTerm);
1782 
1783     bool moveOnSpam, markAsReadOnSpam;
1784     spamSettings->GetMoveOnSpam(&moveOnSpam);
1785     if (moveOnSpam) {
1786       nsCString spamFolderURI;
1787       rv = spamSettings->GetSpamFolderURI(spamFolderURI);
1788       if (NS_SUCCEEDED(rv) && (!spamFolderURI.IsEmpty())) {
1789         nsCOMPtr<nsIMsgRuleAction> moveAction;
1790         rv = newFilter->CreateAction(getter_AddRefs(moveAction));
1791         if (NS_SUCCEEDED(rv)) {
1792           moveAction->SetType(nsMsgFilterAction::MoveToFolder);
1793           moveAction->SetTargetFolderUri(spamFolderURI);
1794           newFilter->AppendAction(moveAction);
1795         }
1796       }
1797     }
1798     spamSettings->GetMarkAsReadOnSpam(&markAsReadOnSpam);
1799     if (markAsReadOnSpam) {
1800       nsCOMPtr<nsIMsgRuleAction> markAsReadAction;
1801       rv = newFilter->CreateAction(getter_AddRefs(markAsReadAction));
1802       if (NS_SUCCEEDED(rv)) {
1803         markAsReadAction->SetType(nsMsgFilterAction::MarkRead);
1804         newFilter->AppendAction(markAsReadAction);
1805       }
1806     }
1807     filterList->InsertFilterAt(0, newFilter);
1808   }
1809 
1810   rv =
1811       serverFilterList->GetFilterNamed(noFilterName, getter_AddRefs(newFilter));
1812   if (newFilter && serverFilterTrustFlags & nsISpamSettings::TRUST_NEGATIVES) {
1813     newFilter->SetTemporary(true);
1814     filterList->InsertFilterAt(0, newFilter);
1815   }
1816 
1817   return rv;
1818 }
1819 
ConfigureTemporaryReturnReceiptsFilter(nsIMsgFilterList * filterList)1820 nsresult nsMsgIncomingServer::ConfigureTemporaryReturnReceiptsFilter(
1821     nsIMsgFilterList* filterList) {
1822   nsresult rv;
1823 
1824   nsCOMPtr<nsIMsgAccountManager> accountMgr =
1825       do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
1826   NS_ENSURE_SUCCESS(rv, rv);
1827 
1828   nsCOMPtr<nsIMsgIdentity> identity;
1829   rv = accountMgr->GetFirstIdentityForServer(this, getter_AddRefs(identity));
1830   NS_ENSURE_SUCCESS(rv, rv);
1831   // this can return success and a null identity...
1832 
1833   bool useCustomPrefs = false;
1834   int32_t incorp = nsIMsgMdnGenerator::eIncorporateInbox;
1835   NS_ENSURE_TRUE(identity, NS_ERROR_NULL_POINTER);
1836 
1837   identity->GetBoolAttribute("use_custom_prefs", &useCustomPrefs);
1838   if (useCustomPrefs)
1839     rv = GetIntValue("incorporate_return_receipt", &incorp);
1840   else {
1841     nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
1842     if (prefs) prefs->GetIntPref("mail.incorporate.return_receipt", &incorp);
1843   }
1844 
1845   bool enable = (incorp == nsIMsgMdnGenerator::eIncorporateSent);
1846 
1847   // this is a temporary, internal mozilla filter
1848   // it will not show up in the UI, it will not be written to disk
1849   constexpr auto internalReturnReceiptFilterName =
1850       u"mozilla-temporary-internal-MDN-receipt-filter"_ns;
1851 
1852   nsCOMPtr<nsIMsgFilter> newFilter;
1853   rv = filterList->GetFilterNamed(internalReturnReceiptFilterName,
1854                                   getter_AddRefs(newFilter));
1855   if (newFilter)
1856     newFilter->SetEnabled(enable);
1857   else if (enable) {
1858     nsCString actionTargetFolderUri;
1859     rv = identity->GetFccFolder(actionTargetFolderUri);
1860     if (!actionTargetFolderUri.IsEmpty()) {
1861       filterList->CreateFilter(internalReturnReceiptFilterName,
1862                                getter_AddRefs(newFilter));
1863       if (newFilter) {
1864         newFilter->SetEnabled(true);
1865         // this internal filter is temporary
1866         // and should not show up in the UI or be written to disk
1867         newFilter->SetTemporary(true);
1868 
1869         nsCOMPtr<nsIMsgSearchTerm> term;
1870         nsCOMPtr<nsIMsgSearchValue> value;
1871 
1872         rv = newFilter->CreateTerm(getter_AddRefs(term));
1873         if (NS_SUCCEEDED(rv)) {
1874           rv = term->GetValue(getter_AddRefs(value));
1875           if (NS_SUCCEEDED(rv)) {
1876             // we need to use OtherHeader + 1 so nsMsgFilter::GetTerm will
1877             // return our custom header.
1878             value->SetAttrib(nsMsgSearchAttrib::OtherHeader + 1);
1879             value->SetStr(u"multipart/report"_ns);
1880             term->SetAttrib(nsMsgSearchAttrib::OtherHeader + 1);
1881             term->SetOp(nsMsgSearchOp::Contains);
1882             term->SetBooleanAnd(true);
1883             term->SetArbitraryHeader("Content-Type"_ns);
1884             term->SetValue(value);
1885             newFilter->AppendTerm(term);
1886           }
1887         }
1888         rv = newFilter->CreateTerm(getter_AddRefs(term));
1889         if (NS_SUCCEEDED(rv)) {
1890           rv = term->GetValue(getter_AddRefs(value));
1891           if (NS_SUCCEEDED(rv)) {
1892             // XXX todo
1893             // determine if ::OtherHeader is the best way to do this.
1894             // see nsMsgSearchOfflineMail::MatchTerms()
1895             value->SetAttrib(nsMsgSearchAttrib::OtherHeader + 1);
1896             value->SetStr(u"disposition-notification"_ns);
1897             term->SetAttrib(nsMsgSearchAttrib::OtherHeader + 1);
1898             term->SetOp(nsMsgSearchOp::Contains);
1899             term->SetBooleanAnd(true);
1900             term->SetArbitraryHeader("Content-Type"_ns);
1901             term->SetValue(value);
1902             newFilter->AppendTerm(term);
1903           }
1904         }
1905         nsCOMPtr<nsIMsgRuleAction> filterAction;
1906         rv = newFilter->CreateAction(getter_AddRefs(filterAction));
1907         if (NS_SUCCEEDED(rv)) {
1908           filterAction->SetType(nsMsgFilterAction::MoveToFolder);
1909           filterAction->SetTargetFolderUri(actionTargetFolderUri);
1910           newFilter->AppendAction(filterAction);
1911           filterList->InsertFilterAt(0, newFilter);
1912         }
1913       }
1914     }
1915   }
1916   return rv;
1917 }
1918 
1919 NS_IMETHODIMP
ClearTemporaryReturnReceiptsFilter()1920 nsMsgIncomingServer::ClearTemporaryReturnReceiptsFilter() {
1921   if (mFilterList) {
1922     nsCOMPtr<nsIMsgFilter> mdnFilter;
1923     nsresult rv = mFilterList->GetFilterNamed(
1924         u"mozilla-temporary-internal-MDN-receipt-filter"_ns,
1925         getter_AddRefs(mdnFilter));
1926     if (NS_SUCCEEDED(rv) && mdnFilter)
1927       return mFilterList->RemoveFilter(mdnFilter);
1928   }
1929   return NS_OK;
1930 }
1931 
1932 NS_IMETHODIMP
GetMsgFolderFromURI(nsIMsgFolder * aFolderResource,const nsACString & aURI,nsIMsgFolder ** aFolder)1933 nsMsgIncomingServer::GetMsgFolderFromURI(nsIMsgFolder* aFolderResource,
1934                                          const nsACString& aURI,
1935                                          nsIMsgFolder** aFolder) {
1936   nsCOMPtr<nsIMsgFolder> rootMsgFolder;
1937   nsresult rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
1938   NS_ENSURE_TRUE(rootMsgFolder, NS_ERROR_UNEXPECTED);
1939 
1940   nsCOMPtr<nsIMsgFolder> msgFolder;
1941   rv = rootMsgFolder->GetChildWithURI(aURI, true, true /*caseInsensitive*/,
1942                                       getter_AddRefs(msgFolder));
1943   if (NS_FAILED(rv) || !msgFolder) msgFolder = aFolderResource;
1944   NS_IF_ADDREF(*aFolder = msgFolder);
1945   return NS_OK;
1946 }
1947 
1948 NS_IMETHODIMP
GetSpamSettings(nsISpamSettings ** aSpamSettings)1949 nsMsgIncomingServer::GetSpamSettings(nsISpamSettings** aSpamSettings) {
1950   NS_ENSURE_ARG_POINTER(aSpamSettings);
1951 
1952   nsAutoCString spamActionTargetAccount;
1953   GetCharValue("spamActionTargetAccount", spamActionTargetAccount);
1954   if (spamActionTargetAccount.IsEmpty()) {
1955     GetServerURI(spamActionTargetAccount);
1956     SetCharValue("spamActionTargetAccount", spamActionTargetAccount);
1957   }
1958 
1959   if (!mSpamSettings) {
1960     nsresult rv;
1961     mSpamSettings = do_CreateInstance(NS_SPAMSETTINGS_CONTRACTID, &rv);
1962     NS_ENSURE_SUCCESS(rv, rv);
1963     mSpamSettings->Initialize(this);
1964     NS_ENSURE_SUCCESS(rv, rv);
1965   }
1966 
1967   NS_ADDREF(*aSpamSettings = mSpamSettings);
1968   return NS_OK;
1969 }
1970 
1971 NS_IMETHODIMP
GetSpamFilterPlugin(nsIMsgFilterPlugin ** aFilterPlugin)1972 nsMsgIncomingServer::GetSpamFilterPlugin(nsIMsgFilterPlugin** aFilterPlugin) {
1973   NS_ENSURE_ARG_POINTER(aFilterPlugin);
1974   if (!mFilterPlugin) {
1975     nsresult rv;
1976     mFilterPlugin = do_GetService(
1977         "@mozilla.org/messenger/filter-plugin;1?name=bayesianfilter", &rv);
1978     NS_ENSURE_SUCCESS(rv, rv);
1979   }
1980 
1981   NS_IF_ADDREF(*aFilterPlugin = mFilterPlugin);
1982   return NS_OK;
1983 }
1984 
1985 // get all the servers that defer to the account for the passed in server. Note
1986 // that destServer may not be "this"
GetDeferredServers(nsIMsgIncomingServer * destServer,nsTArray<RefPtr<nsIPop3IncomingServer>> & aServers)1987 nsresult nsMsgIncomingServer::GetDeferredServers(
1988     nsIMsgIncomingServer* destServer,
1989     nsTArray<RefPtr<nsIPop3IncomingServer>>& aServers) {
1990   nsresult rv;
1991   nsCOMPtr<nsIMsgAccountManager> accountManager =
1992       do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
1993   NS_ENSURE_SUCCESS(rv, rv);
1994 
1995   nsCOMPtr<nsIMsgAccount> thisAccount;
1996   accountManager->FindAccountForServer(destServer, getter_AddRefs(thisAccount));
1997   if (thisAccount) {
1998     nsCString accountKey;
1999     thisAccount->GetKey(accountKey);
2000     nsTArray<RefPtr<nsIMsgIncomingServer>> allServers;
2001     accountManager->GetAllServers(allServers);
2002     for (auto server : allServers) {
2003       nsCOMPtr<nsIPop3IncomingServer> popServer(do_QueryInterface(server));
2004       if (popServer) {
2005         nsCString deferredToAccount;
2006         popServer->GetDeferredToAccount(deferredToAccount);
2007         if (deferredToAccount.Equals(accountKey))
2008           aServers.AppendElement(popServer);
2009       }
2010     }
2011   }
2012   return rv;
2013 }
2014 
GetIsDeferredTo(bool * aIsDeferredTo)2015 NS_IMETHODIMP nsMsgIncomingServer::GetIsDeferredTo(bool* aIsDeferredTo) {
2016   NS_ENSURE_ARG_POINTER(aIsDeferredTo);
2017   nsCOMPtr<nsIMsgAccountManager> accountManager =
2018       do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
2019   if (accountManager) {
2020     nsCOMPtr<nsIMsgAccount> thisAccount;
2021     accountManager->FindAccountForServer(this, getter_AddRefs(thisAccount));
2022     if (thisAccount) {
2023       nsCString accountKey;
2024       thisAccount->GetKey(accountKey);
2025       nsTArray<RefPtr<nsIMsgIncomingServer>> allServers;
2026       accountManager->GetAllServers(allServers);
2027       for (auto server : allServers) {
2028         if (server) {
2029           nsCString deferredToAccount;
2030           server->GetCharValue("deferred_to_account", deferredToAccount);
2031           if (deferredToAccount.Equals(accountKey)) {
2032             *aIsDeferredTo = true;
2033             return NS_OK;
2034           }
2035         }
2036       }
2037     }
2038   }
2039   *aIsDeferredTo = false;
2040   return NS_OK;
2041 }
2042 
2043 const long kMaxDownloadTableSize = 500;
2044 
2045 // hash the concatenation of the message-id and subject as the hash table key,
2046 // and store the arrival index as the value. To limit the size of the hash
2047 // table, we just throw out ones with a lower ordinal value than the cut-off
2048 // point.
IsNewHdrDuplicate(nsIMsgDBHdr * aNewHdr,bool * aResult)2049 NS_IMETHODIMP nsMsgIncomingServer::IsNewHdrDuplicate(nsIMsgDBHdr* aNewHdr,
2050                                                      bool* aResult) {
2051   NS_ENSURE_ARG_POINTER(aResult);
2052   NS_ENSURE_ARG_POINTER(aNewHdr);
2053   *aResult = false;
2054 
2055   // If the message has been partially downloaded, the message should not
2056   // be considered a duplicated message. See bug 714090.
2057   uint32_t flags;
2058   aNewHdr->GetFlags(&flags);
2059   if (flags & nsMsgMessageFlags::Partial) return NS_OK;
2060 
2061   nsAutoCString strHashKey;
2062   nsCString messageId, subject;
2063   aNewHdr->GetMessageId(getter_Copies(messageId));
2064   strHashKey.Append(messageId);
2065   aNewHdr->GetSubject(getter_Copies(subject));
2066   // err on the side of caution and ignore messages w/o subject or messageid.
2067   if (subject.IsEmpty() || messageId.IsEmpty()) return NS_OK;
2068   strHashKey.Append(subject);
2069   int32_t hashValue = m_downloadedHdrs.Get(strHashKey);
2070   if (hashValue)
2071     *aResult = true;
2072   else {
2073     // we store the current size of the hash table as the hash
2074     // value - this allows us to delete older entries.
2075     m_downloadedHdrs.InsertOrUpdate(strHashKey, ++m_numMsgsDownloaded);
2076     // Check if hash table is larger than some reasonable size
2077     // and if is it, iterate over hash table deleting messages
2078     // with an arrival index < number of msgs downloaded - half the reasonable
2079     // size.
2080     if (m_downloadedHdrs.Count() >= kMaxDownloadTableSize) {
2081       for (auto iter = m_downloadedHdrs.Iter(); !iter.Done(); iter.Next()) {
2082         if (iter.Data() < m_numMsgsDownloaded - kMaxDownloadTableSize / 2) {
2083           iter.Remove();
2084         } else if (m_downloadedHdrs.Count() <= kMaxDownloadTableSize / 2) {
2085           break;
2086         }
2087       }
2088     }
2089   }
2090   return NS_OK;
2091 }
2092 
2093 NS_IMETHODIMP
GetForcePropertyEmpty(const char * aPropertyName,bool * _retval)2094 nsMsgIncomingServer::GetForcePropertyEmpty(const char* aPropertyName,
2095                                            bool* _retval) {
2096   NS_ENSURE_ARG_POINTER(_retval);
2097   nsAutoCString nameEmpty(aPropertyName);
2098   nameEmpty.AppendLiteral(".empty");
2099   nsCString value;
2100   GetCharValue(nameEmpty.get(), value);
2101   *_retval = value.EqualsLiteral("true");
2102   return NS_OK;
2103 }
2104 
2105 NS_IMETHODIMP
SetForcePropertyEmpty(const char * aPropertyName,bool aValue)2106 nsMsgIncomingServer::SetForcePropertyEmpty(const char* aPropertyName,
2107                                            bool aValue) {
2108   nsAutoCString nameEmpty(aPropertyName);
2109   nameEmpty.AppendLiteral(".empty");
2110   return SetCharValue(nameEmpty.get(), aValue ? "true"_ns : ""_ns);
2111 }
2112 
2113 NS_IMETHODIMP
GetSortOrder(int32_t * aSortOrder)2114 nsMsgIncomingServer::GetSortOrder(int32_t* aSortOrder) {
2115   NS_ENSURE_ARG_POINTER(aSortOrder);
2116   *aSortOrder = 100000000;
2117   return NS_OK;
2118 }
2119