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