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 "msgCore.h"
7 #include "nsMsgImapCID.h"
8
9 #include "netCore.h"
10 #include "nsIImapHostSessionList.h"
11 #include "nsImapIncomingServer.h"
12 #include "nsIMsgAccountManager.h"
13 #include "nsIMsgIdentity.h"
14 #include "nsIImapUrl.h"
15 #include "nsIUrlListener.h"
16 #include "nsThreadUtils.h"
17 #include "nsImapProtocol.h"
18 #include "nsCOMPtr.h"
19 #include "nsIPrefBranch.h"
20 #include "nsIPrefService.h"
21 #include "nsMsgFolderFlags.h"
22 #include "prmem.h"
23 #include "plstr.h"
24 #include "nsIMsgFolder.h"
25 #include "nsIMsgWindow.h"
26 #include "nsImapMailFolder.h"
27 #include "nsIMsgMailNewsUrl.h"
28 #include "nsIImapService.h"
29 #include "nsMsgI18N.h"
30 #include "nsIImapMockChannel.h"
31 // for the memory cache...
32 #include "nsICacheEntry.h"
33 #include "nsImapUrl.h"
34 #include "nsIMsgProtocolInfo.h"
35 #include "nsIMsgMailSession.h"
36 #include "nsImapNamespace.h"
37 #include "nsArrayUtils.h"
38 #include "nsMsgUtils.h"
39 #include "nsServiceManagerUtils.h"
40 #include "nsComponentManagerUtils.h"
41 #include "nsCRTGlue.h"
42 #include "mozilla/Services.h"
43 #include "nsNetUtil.h"
44 #include "mozilla/Utf8.h"
45 #include "mozilla/LoadInfo.h"
46
47 using namespace mozilla;
48
49 // Despite its name, this contains a folder path, for example INBOX/Trash.
50 #define PREF_TRASH_FOLDER_PATH "trash_folder_name"
51 #define DEFAULT_TRASH_FOLDER_PATH "Trash" // XXX Is this a useful default?
52
53 static NS_DEFINE_CID(kSubscribableServerCID, NS_SUBSCRIBABLESERVER_CID);
54 static NS_DEFINE_CID(kCImapHostSessionListCID, NS_IIMAPHOSTSESSIONLIST_CID);
55
NS_IMPL_ADDREF_INHERITED(nsImapIncomingServer,nsMsgIncomingServer)56 NS_IMPL_ADDREF_INHERITED(nsImapIncomingServer, nsMsgIncomingServer)
57 NS_IMPL_RELEASE_INHERITED(nsImapIncomingServer, nsMsgIncomingServer)
58
59 NS_INTERFACE_MAP_BEGIN(nsImapIncomingServer)
60 NS_INTERFACE_MAP_ENTRY(nsIImapServerSink)
61 NS_INTERFACE_MAP_ENTRY(nsIImapIncomingServer)
62 NS_INTERFACE_MAP_ENTRY(nsISubscribableServer)
63 NS_INTERFACE_MAP_ENTRY(nsIUrlListener)
64 NS_INTERFACE_MAP_END_INHERITING(nsMsgIncomingServer)
65
66 nsImapIncomingServer::nsImapIncomingServer()
67 : mLock("nsImapIncomingServer.mLock") {
68 m_capability = kCapabilityUndefined;
69 mDoingSubscribeDialog = false;
70 mDoingLsub = false;
71 m_canHaveFilters = true;
72 m_userAuthenticated = false;
73 m_shuttingDown = false;
74 mUtf8AcceptEnabled = false;
75 }
76
~nsImapIncomingServer()77 nsImapIncomingServer::~nsImapIncomingServer() {
78 mozilla::DebugOnly<nsresult> rv = ClearInner();
79 NS_ASSERTION(NS_SUCCEEDED(rv), "ClearInner failed");
80 CloseCachedConnections();
81 }
82
SetKey(const nsACString & aKey)83 NS_IMETHODIMP nsImapIncomingServer::SetKey(
84 const nsACString& aKey) // override nsMsgIncomingServer's implementation...
85 {
86 nsMsgIncomingServer::SetKey(aKey);
87
88 // okay now that the key has been set, we need to add ourselves to the
89 // host session list...
90
91 // every time we create an imap incoming server, we need to add it to the
92 // host session list!!
93
94 nsresult rv;
95 nsCOMPtr<nsIImapHostSessionList> hostSession =
96 do_GetService(kCImapHostSessionListCID, &rv);
97 NS_ENSURE_SUCCESS(rv, rv);
98
99 nsCString key(aKey);
100 hostSession->AddHostToList(key.get(), this);
101 nsMsgImapDeleteModel deleteModel =
102 nsMsgImapDeleteModels::MoveToTrash; // default to trash
103 GetDeleteModel(&deleteModel);
104 hostSession->SetDeleteIsMoveToTrashForHost(
105 key.get(), deleteModel == nsMsgImapDeleteModels::MoveToTrash);
106 hostSession->SetShowDeletedMessagesForHost(
107 key.get(), deleteModel == nsMsgImapDeleteModels::IMAPDelete);
108
109 nsAutoCString onlineDir;
110 rv = GetServerDirectory(onlineDir);
111 NS_ENSURE_SUCCESS(rv, rv);
112 if (!onlineDir.IsEmpty())
113 hostSession->SetOnlineDirForHost(key.get(), onlineDir.get());
114
115 nsCString personalNamespace;
116 nsCString publicNamespace;
117 nsCString otherUsersNamespace;
118
119 rv = GetPersonalNamespace(personalNamespace);
120 NS_ENSURE_SUCCESS(rv, rv);
121 rv = GetPublicNamespace(publicNamespace);
122 NS_ENSURE_SUCCESS(rv, rv);
123 rv = GetOtherUsersNamespace(otherUsersNamespace);
124 NS_ENSURE_SUCCESS(rv, rv);
125
126 if (personalNamespace.IsEmpty() && publicNamespace.IsEmpty() &&
127 otherUsersNamespace.IsEmpty())
128 personalNamespace.AssignLiteral("\"\"");
129
130 hostSession->SetNamespaceFromPrefForHost(key.get(), personalNamespace.get(),
131 kPersonalNamespace);
132
133 if (!publicNamespace.IsEmpty())
134 hostSession->SetNamespaceFromPrefForHost(key.get(), publicNamespace.get(),
135 kPublicNamespace);
136
137 if (!otherUsersNamespace.IsEmpty())
138 hostSession->SetNamespaceFromPrefForHost(
139 key.get(), otherUsersNamespace.get(), kOtherUsersNamespace);
140 return rv;
141 }
142
143 // construct the pretty name to show to the user if they haven't
144 // specified one. This should be overridden for news and mail.
145 NS_IMETHODIMP
GetConstructedPrettyName(nsAString & retval)146 nsImapIncomingServer::GetConstructedPrettyName(nsAString& retval) {
147 nsAutoCString username;
148 nsAutoCString hostName;
149 nsresult rv;
150
151 nsCOMPtr<nsIMsgAccountManager> accountManager =
152 do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
153 NS_ENSURE_SUCCESS(rv, rv);
154
155 nsCOMPtr<nsIMsgIdentity> identity;
156 rv =
157 accountManager->GetFirstIdentityForServer(this, getter_AddRefs(identity));
158 NS_ENSURE_SUCCESS(rv, rv);
159
160 nsAutoString emailAddress;
161
162 if (NS_SUCCEEDED(rv) && identity) {
163 nsCString identityEmailAddress;
164 identity->GetEmail(identityEmailAddress);
165 CopyASCIItoUTF16(identityEmailAddress, emailAddress);
166 } else {
167 rv = GetRealUsername(username);
168 NS_ENSURE_SUCCESS(rv, rv);
169 rv = GetRealHostName(hostName);
170 NS_ENSURE_SUCCESS(rv, rv);
171 if (!username.IsEmpty() && !hostName.IsEmpty()) {
172 CopyASCIItoUTF16(username, emailAddress);
173 emailAddress.Append('@');
174 emailAddress.Append(NS_ConvertASCIItoUTF16(hostName));
175 }
176 }
177
178 return GetFormattedStringFromName(emailAddress, "imapDefaultAccountName",
179 retval);
180 }
181
GetLocalStoreType(nsACString & type)182 NS_IMETHODIMP nsImapIncomingServer::GetLocalStoreType(nsACString& type) {
183 type.AssignLiteral("imap");
184 return NS_OK;
185 }
186
GetLocalDatabaseType(nsACString & type)187 NS_IMETHODIMP nsImapIncomingServer::GetLocalDatabaseType(nsACString& type) {
188 type.AssignLiteral("imap");
189 return NS_OK;
190 }
191
192 NS_IMETHODIMP
GetServerDirectory(nsACString & serverDirectory)193 nsImapIncomingServer::GetServerDirectory(nsACString& serverDirectory) {
194 return GetCharValue("server_sub_directory", serverDirectory);
195 }
196
197 NS_IMETHODIMP
SetServerDirectory(const nsACString & serverDirectory)198 nsImapIncomingServer::SetServerDirectory(const nsACString& serverDirectory) {
199 nsCString serverKey;
200 nsresult rv = GetKey(serverKey);
201 if (NS_SUCCEEDED(rv)) {
202 nsCOMPtr<nsIImapHostSessionList> hostSession =
203 do_GetService(kCImapHostSessionListCID, &rv);
204 if (NS_SUCCEEDED(rv))
205 hostSession->SetOnlineDirForHost(
206 serverKey.get(), PromiseFlatCString(serverDirectory).get());
207 }
208 return SetCharValue("server_sub_directory", serverDirectory);
209 }
210
211 NS_IMETHODIMP
GetOverrideNamespaces(bool * bVal)212 nsImapIncomingServer::GetOverrideNamespaces(bool* bVal) {
213 return GetBoolValue("override_namespaces", bVal);
214 }
215
216 NS_IMETHODIMP
SetOverrideNamespaces(bool bVal)217 nsImapIncomingServer::SetOverrideNamespaces(bool bVal) {
218 nsCString serverKey;
219 GetKey(serverKey);
220 if (!serverKey.IsEmpty()) {
221 nsresult rv;
222 nsCOMPtr<nsIImapHostSessionList> hostSession =
223 do_GetService(kCImapHostSessionListCID, &rv);
224 if (NS_SUCCEEDED(rv))
225 hostSession->SetNamespacesOverridableForHost(serverKey.get(), bVal);
226 }
227 return SetBoolValue("override_namespaces", bVal);
228 }
229
230 NS_IMETHODIMP
GetUsingSubscription(bool * bVal)231 nsImapIncomingServer::GetUsingSubscription(bool* bVal) {
232 return GetBoolValue("using_subscription", bVal);
233 }
234
235 NS_IMETHODIMP
SetUsingSubscription(bool bVal)236 nsImapIncomingServer::SetUsingSubscription(bool bVal) {
237 nsCString serverKey;
238 GetKey(serverKey);
239 if (!serverKey.IsEmpty()) {
240 nsresult rv;
241 nsCOMPtr<nsIImapHostSessionList> hostSession =
242 do_GetService(kCImapHostSessionListCID, &rv);
243 if (NS_SUCCEEDED(rv))
244 hostSession->SetHostIsUsingSubscription(serverKey.get(), bVal);
245 }
246 return SetBoolValue("using_subscription", bVal);
247 }
248
249 NS_IMETHODIMP
GetMaximumConnectionsNumber(int32_t * aMaxConnections)250 nsImapIncomingServer::GetMaximumConnectionsNumber(int32_t* aMaxConnections) {
251 NS_ENSURE_ARG_POINTER(aMaxConnections);
252
253 nsresult rv = GetIntValue("max_cached_connections", aMaxConnections);
254 // Get our maximum connection count. We need at least 1. If the value is 0,
255 // we use the default of 5. If it's negative, we treat that as 1.
256 if (NS_SUCCEEDED(rv) && *aMaxConnections > 0) return NS_OK;
257
258 *aMaxConnections = (NS_FAILED(rv) || (*aMaxConnections == 0)) ? 5 : 1;
259 (void)SetMaximumConnectionsNumber(*aMaxConnections);
260
261 return NS_OK;
262 }
263
264 NS_IMETHODIMP
SetMaximumConnectionsNumber(int32_t aMaxConnections)265 nsImapIncomingServer::SetMaximumConnectionsNumber(int32_t aMaxConnections) {
266 return SetIntValue("max_cached_connections", aMaxConnections);
267 }
268
269 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, ForceSelect, "force_select")
270
271 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, DualUseFolders,
272 "dual_use_folders")
273
274 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, AdminUrl, "admin_url")
275
276 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, CleanupInboxOnExit,
277 "cleanup_inbox_on_exit")
278
279 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, OfflineDownload,
280 "offline_download")
281
282 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, DownloadBodiesOnGetNewMail,
283 "download_bodies_on_get_new_mail")
284
285 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, AutoSyncOfflineStores,
286 "autosync_offline_stores")
287
288 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, UseIdle, "use_idle")
289
290 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, CheckAllFoldersForNew,
291 "check_all_folders_for_new")
292
293 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, UseCondStore, "use_condstore")
294
295 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, IsGMailServer, "is_gmail")
296
297 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, UseCompressDeflate,
298 "use_compress_deflate")
299
300 NS_IMPL_SERVERPREF_INT(nsImapIncomingServer, AutoSyncMaxAgeDays,
301 "autosync_max_age_days")
302
303 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, AllowUTF8Accept,
304 "allow_utf8_accept")
305
306 NS_IMETHODIMP
GetShuttingDown(bool * retval)307 nsImapIncomingServer::GetShuttingDown(bool* retval) {
308 NS_ENSURE_ARG_POINTER(retval);
309 *retval = m_shuttingDown;
310 return NS_OK;
311 }
312
313 NS_IMETHODIMP
SetShuttingDown(bool val)314 nsImapIncomingServer::SetShuttingDown(bool val) {
315 m_shuttingDown = val;
316 return NS_OK;
317 }
318
319 NS_IMETHODIMP
GetDeleteModel(int32_t * retval)320 nsImapIncomingServer::GetDeleteModel(int32_t* retval) {
321 NS_ENSURE_ARG(retval);
322 return GetIntValue("delete_model", retval);
323 }
324
325 NS_IMETHODIMP
SetDeleteModel(int32_t ivalue)326 nsImapIncomingServer::SetDeleteModel(int32_t ivalue) {
327 nsresult rv = SetIntValue("delete_model", ivalue);
328 if (NS_SUCCEEDED(rv)) {
329 nsCOMPtr<nsIImapHostSessionList> hostSession =
330 do_GetService(kCImapHostSessionListCID, &rv);
331 NS_ENSURE_SUCCESS(rv, rv);
332 hostSession->SetDeleteIsMoveToTrashForHost(
333 m_serverKey.get(), ivalue == nsMsgImapDeleteModels::MoveToTrash);
334 hostSession->SetShowDeletedMessagesForHost(
335 m_serverKey.get(), ivalue == nsMsgImapDeleteModels::IMAPDelete);
336
337 // Despite its name, this returns the trash folder path, for example
338 // INBOX/Trash.
339 nsAutoString trashFolderName;
340 nsresult rv = GetTrashFolderName(trashFolderName);
341 if (NS_SUCCEEDED(rv)) {
342 nsAutoCString trashFolderNameUtf7or8;
343 bool useUTF8 = false;
344 GetUtf8AcceptEnabled(&useUTF8);
345 if (useUTF8) {
346 CopyUTF16toUTF8(trashFolderName, trashFolderNameUtf7or8);
347 } else {
348 CopyUTF16toMUTF7(trashFolderName, trashFolderNameUtf7or8);
349 }
350 nsCOMPtr<nsIMsgFolder> trashFolder;
351 // 'trashFolderName' being a path here works well since this is appended
352 // to the server's root folder in GetFolder().
353 rv = GetFolder(trashFolderNameUtf7or8, getter_AddRefs(trashFolder));
354 NS_ENSURE_SUCCESS(rv, rv);
355 nsCString trashURI;
356 trashFolder->GetURI(trashURI);
357 rv = GetMsgFolderFromURI(trashFolder, trashURI,
358 getter_AddRefs(trashFolder));
359 if (NS_SUCCEEDED(rv) && trashFolder) {
360 // If the trash folder is used, set the flag, otherwise clear it.
361 if (ivalue == nsMsgImapDeleteModels::MoveToTrash)
362 trashFolder->SetFlag(nsMsgFolderFlags::Trash);
363 else
364 trashFolder->ClearFlag(nsMsgFolderFlags::Trash);
365 }
366 }
367 }
368 return rv;
369 }
370
371 NS_IMPL_SERVERPREF_INT(nsImapIncomingServer, TimeOutLimits, "timeout")
372
373 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, ServerIDPref, "serverIDResponse")
374
375 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, PersonalNamespace,
376 "namespace.personal")
377
378 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, PublicNamespace,
379 "namespace.public")
380
381 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, OtherUsersNamespace,
382 "namespace.other_users")
383
384 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, FetchByChunks, "fetch_by_chunks")
385
386 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, MimePartsOnDemand,
387 "mime_parts_on_demand")
388
389 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, SendID, "send_client_info")
390
391 NS_IMETHODIMP
GetIsAOLServer(bool * aBool)392 nsImapIncomingServer::GetIsAOLServer(bool* aBool) {
393 NS_ENSURE_ARG_POINTER(aBool);
394 *aBool = ((m_capability & kAOLImapCapability) != 0);
395 return NS_OK;
396 }
397
398 NS_IMETHODIMP
SetIsAOLServer(bool aBool)399 nsImapIncomingServer::SetIsAOLServer(bool aBool) {
400 if (aBool)
401 m_capability |= kAOLImapCapability;
402 else
403 m_capability &= ~kAOLImapCapability;
404 return NS_OK;
405 }
406
407 NS_IMETHODIMP
UpdateTrySTARTTLSPref(bool aStartTLSSucceeded)408 nsImapIncomingServer::UpdateTrySTARTTLSPref(bool aStartTLSSucceeded) {
409 SetSocketType(aStartTLSSucceeded ? nsMsgSocketType::alwaysSTARTTLS
410 : nsMsgSocketType::plain);
411 return NS_OK;
412 }
413
414 NS_IMETHODIMP
GetImapConnectionAndLoadUrl(nsIImapUrl * aImapUrl,nsISupports * aConsumer)415 nsImapIncomingServer::GetImapConnectionAndLoadUrl(nsIImapUrl* aImapUrl,
416 nsISupports* aConsumer) {
417 nsCOMPtr<nsIImapProtocol> aProtocol;
418
419 nsresult rv = GetImapConnection(aImapUrl, getter_AddRefs(aProtocol));
420 NS_ENSURE_SUCCESS(rv, rv);
421
422 nsCOMPtr<nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(aImapUrl, &rv);
423 if (aProtocol) {
424 rv = aProtocol->LoadImapUrl(mailnewsurl, aConsumer);
425 // *** jt - in case of the time out situation or the connection gets
426 // terminated by some unforeseen problems let's give it a second chance
427 // to run the url
428 if (NS_FAILED(rv) && rv != NS_ERROR_ILLEGAL_VALUE) {
429 rv = aProtocol->LoadImapUrl(mailnewsurl, aConsumer);
430 }
431 } else { // unable to get an imap connection to run the url; add to the url
432 // queue
433 nsImapProtocol::LogImapUrl("queuing url", aImapUrl);
434 PR_CEnterMonitor(this);
435 m_urlQueue.AppendObject(aImapUrl);
436 m_urlConsumers.AppendElement(aConsumer);
437 NS_IF_ADDREF(aConsumer);
438 PR_CExitMonitor(this);
439 // let's try running it now - maybe the connection is free now.
440 bool urlRun;
441 rv = LoadNextQueuedUrl(nullptr, &urlRun);
442 }
443
444 return rv;
445 }
446
447 NS_IMETHODIMP
PrepareToRetryUrl(nsIImapUrl * aImapUrl,nsIImapMockChannel ** aChannel)448 nsImapIncomingServer::PrepareToRetryUrl(nsIImapUrl* aImapUrl,
449 nsIImapMockChannel** aChannel) {
450 NS_ENSURE_ARG_POINTER(aChannel);
451 NS_ENSURE_ARG_POINTER(aImapUrl);
452 // maybe there's more we could do here, but this is all we need now.
453 return aImapUrl->GetMockChannel(aChannel);
454 }
455
456 NS_IMETHODIMP
SuspendUrl(nsIImapUrl * aImapUrl)457 nsImapIncomingServer::SuspendUrl(nsIImapUrl* aImapUrl) {
458 NS_ENSURE_ARG_POINTER(aImapUrl);
459 nsImapProtocol::LogImapUrl("suspending url", aImapUrl);
460 PR_CEnterMonitor(this);
461 m_urlQueue.AppendObject(aImapUrl);
462 m_urlConsumers.AppendElement(nullptr);
463 PR_CExitMonitor(this);
464 return NS_OK;
465 }
466
467 NS_IMETHODIMP
RetryUrl(nsIImapUrl * aImapUrl,nsIImapMockChannel * aChannel)468 nsImapIncomingServer::RetryUrl(nsIImapUrl* aImapUrl,
469 nsIImapMockChannel* aChannel) {
470 nsresult rv;
471 // Get current thread envent queue
472 aImapUrl->SetMockChannel(aChannel);
473 nsCOMPtr<nsIImapProtocol> protocolInstance;
474 nsImapProtocol::LogImapUrl("creating protocol instance to retry queued url",
475 aImapUrl);
476 nsCOMPtr<nsIThread> thread(do_GetCurrentThread());
477 rv = GetImapConnection(aImapUrl, getter_AddRefs(protocolInstance));
478 if (NS_SUCCEEDED(rv) && protocolInstance) {
479 nsCOMPtr<nsIURI> url = do_QueryInterface(aImapUrl, &rv);
480 if (NS_SUCCEEDED(rv) && url) {
481 nsImapProtocol::LogImapUrl("retrying url", aImapUrl);
482 rv = protocolInstance->LoadImapUrl(
483 url, nullptr); // ### need to save the display consumer.
484 }
485 }
486 return rv;
487 }
488
489 // checks to see if there are any queued urls on this incoming server,
490 // and if so, tries to run the oldest one. Returns true if the url is run
491 // on the passed in protocol connection.
492 NS_IMETHODIMP
LoadNextQueuedUrl(nsIImapProtocol * aProtocol,bool * aResult)493 nsImapIncomingServer::LoadNextQueuedUrl(nsIImapProtocol* aProtocol,
494 bool* aResult) {
495 if (WeAreOffline()) return NS_MSG_ERROR_OFFLINE;
496
497 nsresult rv = NS_OK;
498 bool urlRun = false;
499 bool keepGoing = true;
500 nsCOMPtr<nsIImapProtocol> protocolInstance;
501
502 MutexAutoLock mon(mLock);
503 int32_t cnt = m_urlQueue.Count();
504
505 while (cnt > 0 && !urlRun && keepGoing) {
506 nsCOMPtr<nsIImapUrl> aImapUrl(m_urlQueue[0]);
507
508 bool removeUrlFromQueue = false;
509 if (aImapUrl) {
510 nsImapProtocol::LogImapUrl("considering playing queued url", aImapUrl);
511 rv = DoomUrlIfChannelHasError(aImapUrl, &removeUrlFromQueue);
512 NS_ENSURE_SUCCESS(rv, rv);
513 // if we didn't doom the url, lets run it.
514 if (!removeUrlFromQueue) {
515 nsISupports* aConsumer = m_urlConsumers.ElementAt(0);
516 NS_IF_ADDREF(aConsumer);
517
518 nsImapProtocol::LogImapUrl(
519 "creating protocol instance to play queued url", aImapUrl);
520 rv = GetImapConnection(aImapUrl, getter_AddRefs(protocolInstance));
521 if (NS_SUCCEEDED(rv) && protocolInstance) {
522 nsCOMPtr<nsIURI> url = do_QueryInterface(aImapUrl, &rv);
523 if (NS_SUCCEEDED(rv) && url) {
524 nsImapProtocol::LogImapUrl("playing queued url", aImapUrl);
525 rv = protocolInstance->LoadImapUrl(url, aConsumer);
526 if (NS_SUCCEEDED(rv)) {
527 bool isInbox;
528 protocolInstance->IsBusy(&urlRun, &isInbox);
529 if (!urlRun)
530 nsImapProtocol::LogImapUrl("didn't need to run", aImapUrl);
531 removeUrlFromQueue = true;
532 } else {
533 nsImapProtocol::LogImapUrl("playing queued url failed", aImapUrl);
534 }
535 }
536 } else {
537 nsImapProtocol::LogImapUrl(
538 "failed creating protocol instance to play queued url", aImapUrl);
539 keepGoing = false;
540 }
541 NS_IF_RELEASE(aConsumer);
542 }
543 if (removeUrlFromQueue) {
544 m_urlQueue.RemoveObjectAt(0);
545 m_urlConsumers.RemoveElementAt(0);
546 }
547 }
548 cnt = m_urlQueue.Count();
549 }
550 if (aResult) *aResult = urlRun && aProtocol && aProtocol == protocolInstance;
551
552 return rv;
553 }
554
555 NS_IMETHODIMP
AbortQueuedUrls()556 nsImapIncomingServer::AbortQueuedUrls() {
557 nsresult rv = NS_OK;
558
559 MutexAutoLock mon(mLock);
560 int32_t cnt = m_urlQueue.Count();
561
562 while (cnt > 0) {
563 nsCOMPtr<nsIImapUrl> aImapUrl(m_urlQueue[cnt - 1]);
564 bool removeUrlFromQueue = false;
565
566 if (aImapUrl) {
567 rv = DoomUrlIfChannelHasError(aImapUrl, &removeUrlFromQueue);
568 NS_ENSURE_SUCCESS(rv, rv);
569 if (removeUrlFromQueue) {
570 m_urlQueue.RemoveObjectAt(cnt - 1);
571 m_urlConsumers.RemoveElementAt(cnt - 1);
572 }
573 }
574 cnt--;
575 }
576
577 return rv;
578 }
579
580 // if this url has a channel with an error, doom it and its mem cache entries,
581 // and notify url listeners.
DoomUrlIfChannelHasError(nsIImapUrl * aImapUrl,bool * urlDoomed)582 nsresult nsImapIncomingServer::DoomUrlIfChannelHasError(nsIImapUrl* aImapUrl,
583 bool* urlDoomed) {
584 nsresult rv = NS_OK;
585
586 nsCOMPtr<nsIMsgMailNewsUrl> aMailNewsUrl(do_QueryInterface(aImapUrl, &rv));
587
588 if (aMailNewsUrl && aImapUrl) {
589 nsCOMPtr<nsIImapMockChannel> mockChannel;
590
591 if (NS_SUCCEEDED(aImapUrl->GetMockChannel(getter_AddRefs(mockChannel))) &&
592 mockChannel) {
593 nsresult requestStatus;
594 mockChannel->GetStatus(&requestStatus);
595 if (NS_FAILED(requestStatus)) {
596 nsresult res;
597 *urlDoomed = true;
598 nsImapProtocol::LogImapUrl("dooming url", aImapUrl);
599
600 mockChannel
601 ->Close(); // try closing it to get channel listener nulled out.
602
603 if (aMailNewsUrl) {
604 nsCOMPtr<nsICacheEntry> cacheEntry;
605 res = aMailNewsUrl->GetMemCacheEntry(getter_AddRefs(cacheEntry));
606 if (NS_SUCCEEDED(res) && cacheEntry) cacheEntry->AsyncDoom(nullptr);
607 // we're aborting this url - tell listeners
608 aMailNewsUrl->SetUrlState(false, NS_MSG_ERROR_URL_ABORTED);
609 }
610 }
611 }
612 }
613 return rv;
614 }
615
616 NS_IMETHODIMP
RemoveConnection(nsIImapProtocol * aImapConnection)617 nsImapIncomingServer::RemoveConnection(nsIImapProtocol* aImapConnection) {
618 PR_CEnterMonitor(this);
619 if (aImapConnection) m_connectionCache.RemoveObject(aImapConnection);
620
621 PR_CExitMonitor(this);
622 return NS_OK;
623 }
624
ConnectionTimeOut(nsIImapProtocol * aConnection)625 bool nsImapIncomingServer::ConnectionTimeOut(nsIImapProtocol* aConnection) {
626 bool retVal = false;
627 if (!aConnection) return retVal;
628 nsresult rv;
629
630 int32_t timeoutInMinutes = 0;
631 rv = GetTimeOutLimits(&timeoutInMinutes);
632 if (NS_FAILED(rv) || timeoutInMinutes <= 0 || timeoutInMinutes > 29) {
633 timeoutInMinutes = 29;
634 SetTimeOutLimits(timeoutInMinutes);
635 }
636
637 PRTime cacheTimeoutLimits = timeoutInMinutes * 60 * PR_USEC_PER_SEC;
638 PRTime lastActiveTimeStamp;
639 rv = aConnection->GetLastActiveTimeStamp(&lastActiveTimeStamp);
640
641 if (PR_Now() - lastActiveTimeStamp >= cacheTimeoutLimits) {
642 RemoveConnection(aConnection);
643 aConnection->TellThreadToDie(false);
644 retVal = true;
645 }
646 return retVal;
647 }
648
GetImapConnection(nsIImapUrl * aImapUrl,nsIImapProtocol ** aImapConnection)649 nsresult nsImapIncomingServer::GetImapConnection(
650 nsIImapUrl* aImapUrl, nsIImapProtocol** aImapConnection) {
651 NS_ENSURE_ARG_POINTER(aImapUrl);
652
653 nsresult rv = NS_OK;
654 bool canRunUrlImmediately = false;
655 bool canRunButBusy = false;
656 nsCOMPtr<nsIImapProtocol> connection;
657 nsCOMPtr<nsIImapProtocol> freeConnection;
658 bool isBusy = false;
659 bool isInboxConnection = false;
660
661 PR_CEnterMonitor(this);
662
663 int32_t maxConnections;
664 (void)GetMaximumConnectionsNumber(&maxConnections);
665
666 int32_t cnt = m_connectionCache.Count();
667
668 *aImapConnection = nullptr;
669 // iterate through the connection cache for a connection that can handle this
670 // url.
671 // loop until we find a connection that can run the url, or doesn't have to
672 // wait?
673 for (int32_t i = cnt - 1; i >= 0 && !canRunUrlImmediately && !canRunButBusy;
674 i--) {
675 connection = m_connectionCache[i];
676 if (connection) {
677 bool badConnection = ConnectionTimeOut(connection);
678 if (!badConnection) {
679 badConnection = NS_FAILED(connection->CanHandleUrl(
680 aImapUrl, &canRunUrlImmediately, &canRunButBusy));
681 #ifdef DEBUG_bienvenu
682 nsAutoCString curSelectedFolderName;
683 if (connection)
684 connection->GetSelectedMailboxName(
685 getter_Copies(curSelectedFolderName));
686 // check that no other connection is in the same selected state.
687 if (!curSelectedFolderName.IsEmpty()) {
688 for (uint32_t j = 0; j < cnt; j++) {
689 if (j != i) {
690 nsCOMPtr<nsIImapProtocol> otherConnection =
691 do_QueryElementAt(m_connectionCache, j);
692 if (otherConnection) {
693 nsAutoCString otherSelectedFolderName;
694 otherConnection->GetSelectedMailboxName(
695 getter_Copies(otherSelectedFolderName));
696 NS_ASSERTION(
697 !curSelectedFolderName.Equals(otherSelectedFolderName),
698 "two connections selected on same folder");
699 }
700 }
701 }
702 }
703 #endif // DEBUG_bienvenu
704 }
705 if (badConnection) {
706 connection = nullptr;
707 continue;
708 }
709 }
710
711 // if this connection is wrong, but it's not busy, check if we should
712 // designate it as the free connection.
713 if (!canRunUrlImmediately && !canRunButBusy && connection) {
714 rv = connection->IsBusy(&isBusy, &isInboxConnection);
715 if (NS_FAILED(rv)) continue;
716 // if max connections is <= 1, we have to re-use the inbox connection.
717 if (!isBusy && (!isInboxConnection || maxConnections <= 1)) {
718 if (!freeConnection)
719 freeConnection = connection;
720 else // check which is the better free connection to use.
721 { // We prefer one not in the selected state.
722 nsAutoCString selectedFolderName;
723 connection->GetSelectedMailboxName(getter_Copies(selectedFolderName));
724 if (selectedFolderName.IsEmpty()) freeConnection = connection;
725 }
726 }
727 }
728 // don't leave this loop with connection set if we can't use it!
729 if (!canRunButBusy && !canRunUrlImmediately) connection = nullptr;
730 }
731
732 nsImapState requiredState;
733 aImapUrl->GetRequiredImapState(&requiredState);
734 // refresh cnt in case we killed one or more dead connections. This
735 // will prevent us from not spinning up a new connection when all
736 // connections were dead.
737 cnt = m_connectionCache.Count();
738 // if we got here and we have a connection, then we should return it!
739 if (canRunUrlImmediately && connection) {
740 connection.forget(aImapConnection);
741 } else if (canRunButBusy) {
742 // do nothing; return NS_OK; for queuing
743 }
744 // CanHandleUrl will pretend that some types of urls require a selected state
745 // url (e.g., a folder delete or msg append) but we shouldn't create new
746 // connections for these types of urls if we have a free connection. So we
747 // check the actual required state here.
748 else if (cnt < maxConnections &&
749 (!freeConnection ||
750 requiredState == nsIImapUrl::nsImapSelectedState)) {
751 rv = CreateProtocolInstance(aImapConnection);
752 } else if (freeConnection) {
753 freeConnection.forget(aImapConnection);
754 } else {
755 if (cnt >= maxConnections)
756 nsImapProtocol::LogImapUrl("exceeded connection cache limit", aImapUrl);
757 // caller will queue the url
758 }
759
760 PR_CExitMonitor(this);
761 return rv;
762 }
763
CreateProtocolInstance(nsIImapProtocol ** aImapConnection)764 nsresult nsImapIncomingServer::CreateProtocolInstance(
765 nsIImapProtocol** aImapConnection) {
766 // create a new connection and add it to the connection cache
767 // we may need to flag the protocol connection as busy so we don't get
768 // a race condition where someone else goes through this code
769
770 int32_t authMethod;
771 GetAuthMethod(&authMethod);
772 nsresult rv;
773 // pre-flight that we have nss - on the ui thread - for MD5 etc.
774 switch (authMethod) {
775 case nsMsgAuthMethod::passwordEncrypted:
776 case nsMsgAuthMethod::secure:
777 case nsMsgAuthMethod::anything: {
778 nsCOMPtr<nsISupports> dummyUsedToEnsureNSSIsInitialized =
779 do_GetService("@mozilla.org/psm;1", &rv);
780 NS_ENSURE_SUCCESS(rv, rv);
781 } break;
782 default:
783 break;
784 }
785 nsCOMPtr<nsIImapHostSessionList> hostSession =
786 do_GetService(kCImapHostSessionListCID, &rv);
787 NS_ENSURE_SUCCESS(rv, rv);
788 RefPtr<nsImapProtocol> protocolInstance(new nsImapProtocol());
789 rv = protocolInstance->Initialize(hostSession, this);
790 NS_ENSURE_SUCCESS(rv, rv);
791 // It implements nsIChannel, and all channels require loadInfo.
792 protocolInstance->SetLoadInfo(new mozilla::net::LoadInfo(
793 nsContentUtils::GetSystemPrincipal(), nullptr, nullptr,
794 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
795 nsIContentPolicy::TYPE_OTHER));
796
797 // take the protocol instance and add it to the connectionCache
798 m_connectionCache.AppendObject(protocolInstance);
799 protocolInstance.forget(aImapConnection);
800 return rv;
801 }
802
CloseConnectionForFolder(nsIMsgFolder * aMsgFolder)803 NS_IMETHODIMP nsImapIncomingServer::CloseConnectionForFolder(
804 nsIMsgFolder* aMsgFolder) {
805 nsresult rv = NS_OK;
806 nsCOMPtr<nsIImapProtocol> connection;
807 bool isBusy = false, isInbox = false;
808 nsCString inFolderName;
809 nsCString connectionFolderName;
810 nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aMsgFolder);
811
812 if (!imapFolder) return NS_ERROR_NULL_POINTER;
813
814 int32_t cnt = m_connectionCache.Count();
815 NS_ENSURE_SUCCESS(rv, rv);
816
817 imapFolder->GetOnlineName(inFolderName);
818 PR_CEnterMonitor(this);
819
820 for (int32_t i = 0; i < cnt; ++i) {
821 connection = m_connectionCache[i];
822 if (connection) {
823 rv = connection->GetSelectedMailboxName(
824 getter_Copies(connectionFolderName));
825 if (connectionFolderName.Equals(inFolderName)) {
826 rv = connection->IsBusy(&isBusy, &isInbox);
827 if (!isBusy) rv = connection->TellThreadToDie(true);
828 break; // found it, end of the loop
829 }
830 }
831 }
832
833 PR_CExitMonitor(this);
834 return rv;
835 }
836
ResetConnection(const nsACString & folderName)837 NS_IMETHODIMP nsImapIncomingServer::ResetConnection(
838 const nsACString& folderName) {
839 nsresult rv = NS_OK;
840 nsCOMPtr<nsIImapProtocol> connection;
841 bool isBusy = false, isInbox = false;
842 nsCString curFolderName;
843
844 int32_t cnt = m_connectionCache.Count();
845
846 PR_CEnterMonitor(this);
847
848 for (int32_t i = 0; i < cnt; ++i) {
849 connection = m_connectionCache[i];
850 if (connection) {
851 rv = connection->GetSelectedMailboxName(getter_Copies(curFolderName));
852 if (curFolderName.Equals(folderName)) {
853 rv = connection->IsBusy(&isBusy, &isInbox);
854 if (!isBusy) rv = connection->ResetToAuthenticatedState();
855 break; // found it, end of the loop
856 }
857 }
858 }
859
860 PR_CExitMonitor(this);
861 return rv;
862 }
863
864 NS_IMETHODIMP
PerformExpand(nsIMsgWindow * aMsgWindow)865 nsImapIncomingServer::PerformExpand(nsIMsgWindow* aMsgWindow) {
866 nsString password;
867 nsresult rv;
868 rv = GetPassword(password);
869 NS_ENSURE_SUCCESS(rv, rv);
870
871 if (password.IsEmpty()) return NS_OK;
872
873 rv = ResetFoldersToUnverified(nullptr);
874
875 nsCOMPtr<nsIMsgFolder> rootMsgFolder;
876 rv = GetRootFolder(getter_AddRefs(rootMsgFolder));
877 NS_ENSURE_SUCCESS(rv, rv);
878
879 if (!rootMsgFolder) return NS_ERROR_FAILURE;
880
881 nsCOMPtr<nsIImapService> imapService =
882 do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
883 NS_ENSURE_SUCCESS(rv, rv);
884 nsCOMPtr<nsIThread> thread(do_GetCurrentThread());
885 rv =
886 imapService->DiscoverAllFolders(rootMsgFolder, this, aMsgWindow, nullptr);
887 NS_ENSURE_SUCCESS(rv, rv);
888 nsCOMPtr<nsIImapHostSessionList> hostSessionList =
889 do_GetService(kCImapHostSessionListCID, &rv);
890 if (NS_SUCCEEDED(rv)) {
891 nsAutoCString serverKey;
892 rv = GetKey(serverKey);
893 if (!serverKey.IsEmpty())
894 hostSessionList->SetDiscoveryForHostInProgress(serverKey.get(), true);
895 }
896 return rv;
897 }
898
899 NS_IMETHODIMP
VerifyLogon(nsIUrlListener * aUrlListener,nsIMsgWindow * aMsgWindow,nsIURI ** aURL)900 nsImapIncomingServer::VerifyLogon(nsIUrlListener* aUrlListener,
901 nsIMsgWindow* aMsgWindow, nsIURI** aURL) {
902 nsresult rv;
903
904 nsCOMPtr<nsIImapService> imapService =
905 do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
906 NS_ENSURE_SUCCESS(rv, rv);
907 nsCOMPtr<nsIMsgFolder> rootFolder;
908 // this will create the resource if it doesn't exist, but it shouldn't
909 // do anything on disk.
910 rv = GetRootFolder(getter_AddRefs(rootFolder));
911 NS_ENSURE_SUCCESS(rv, rv);
912 return imapService->VerifyLogon(rootFolder, aUrlListener, aMsgWindow, aURL);
913 }
914
PerformBiff(nsIMsgWindow * aMsgWindow)915 NS_IMETHODIMP nsImapIncomingServer::PerformBiff(nsIMsgWindow* aMsgWindow) {
916 nsCOMPtr<nsIMsgFolder> rootMsgFolder;
917 nsresult rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
918 if (NS_SUCCEEDED(rv)) {
919 SetPerformingBiff(true);
920 rv = rootMsgFolder->GetNewMessages(aMsgWindow, nullptr);
921 }
922 return rv;
923 }
924
925 NS_IMETHODIMP
CloseCachedConnections()926 nsImapIncomingServer::CloseCachedConnections() {
927 nsCOMPtr<nsIImapProtocol> connection;
928 PR_CEnterMonitor(this);
929
930 // iterate through the connection cache closing open connections.
931 int32_t cnt = m_connectionCache.Count();
932
933 for (int32_t i = cnt; i > 0; --i) {
934 connection = m_connectionCache[i - 1];
935 if (connection) connection->TellThreadToDie(true);
936 }
937
938 PR_CExitMonitor(this);
939 return NS_OK;
940 }
941
CreateRootFolderFromUri(const nsACString & serverUri,nsIMsgFolder ** rootFolder)942 nsresult nsImapIncomingServer::CreateRootFolderFromUri(
943 const nsACString& serverUri, nsIMsgFolder** rootFolder) {
944 nsImapMailFolder* newRootFolder = new nsImapMailFolder;
945 newRootFolder->Init(serverUri);
946 NS_ADDREF(*rootFolder = newRootFolder);
947 return NS_OK;
948 }
949
950 // nsIImapServerSink impl
951 // aNewFolder will not be set if we're listing for the subscribe UI, since
952 // that's the way 4.x worked.
PossibleImapMailbox(const nsACString & folderPath,char hierarchyDelimiter,int32_t boxFlags,bool * aNewFolder)953 NS_IMETHODIMP nsImapIncomingServer::PossibleImapMailbox(
954 const nsACString& folderPath, char hierarchyDelimiter, int32_t boxFlags,
955 bool* aNewFolder) {
956 NS_ENSURE_ARG_POINTER(aNewFolder);
957 NS_ENSURE_TRUE(!folderPath.IsEmpty(), NS_ERROR_FAILURE);
958
959 // folderPath is in canonical format, i.e., hierarchy separator has been
960 // replaced with '/'
961 nsresult rv;
962 bool found = false;
963 bool haveParent = false;
964 nsCOMPtr<nsIMsgImapMailFolder> hostFolder;
965 nsCOMPtr<nsIMsgFolder> aFolder;
966 bool explicitlyVerify = false;
967
968 *aNewFolder = false;
969 nsCOMPtr<nsIMsgFolder> rootFolder;
970 rv = GetRootFolder(getter_AddRefs(rootFolder));
971
972 if (NS_FAILED(rv)) return rv;
973
974 nsAutoCString dupFolderPath(folderPath);
975 if (dupFolderPath.Last() == '/') {
976 dupFolderPath.SetLength(dupFolderPath.Length() - 1);
977 if (dupFolderPath.IsEmpty()) return NS_ERROR_FAILURE;
978 // *** this is what we did in 4.x in order to list uw folder only
979 // mailbox in order to get the \NoSelect flag
980 explicitlyVerify = !(boxFlags & kNameSpace);
981 }
982 if (mDoingSubscribeDialog) {
983 // Make sure the imapmailfolder object has the right delimiter because the
984 // unsubscribed folders (those not in the 'lsub' list) have the delimiter
985 // set to the default ('^').
986 if (rootFolder && !dupFolderPath.IsEmpty()) {
987 nsCOMPtr<nsIMsgFolder> msgFolder;
988 bool isNamespace = false;
989 bool noSelect = false;
990
991 rv = rootFolder->FindSubFolder(dupFolderPath, getter_AddRefs(msgFolder));
992 NS_ENSURE_SUCCESS(rv, rv);
993 m_subscribeFolders.AppendObject(msgFolder);
994 noSelect = (boxFlags & kNoselect) != 0;
995 nsCOMPtr<nsIMsgImapMailFolder> imapFolder =
996 do_QueryInterface(msgFolder, &rv);
997 NS_ENSURE_SUCCESS(rv, rv);
998 imapFolder->SetHierarchyDelimiter(hierarchyDelimiter);
999 isNamespace = (boxFlags & kNameSpace) != 0;
1000 if (!isNamespace)
1001 rv = AddTo(dupFolderPath,
1002 mDoingLsub && !noSelect /* add as subscribed */, !noSelect,
1003 mDoingLsub /* change if exists */);
1004 NS_ENSURE_SUCCESS(rv, rv);
1005 return rv;
1006 }
1007 }
1008
1009 hostFolder = do_QueryInterface(rootFolder, &rv);
1010 if (NS_FAILED(rv)) return rv;
1011
1012 nsAutoCString tempFolderName(dupFolderPath);
1013 nsAutoCString tokenStr, remStr, changedStr;
1014 int32_t slashPos = tempFolderName.FindChar('/');
1015 if (slashPos > 0) {
1016 tokenStr = StringHead(tempFolderName, slashPos);
1017 remStr = Substring(tempFolderName, slashPos);
1018 } else
1019 tokenStr.Assign(tempFolderName);
1020
1021 if ((int32_t(PL_strcasecmp(tokenStr.get(), "INBOX")) == 0) &&
1022 (strcmp(tokenStr.get(), "INBOX") != 0))
1023 changedStr.AppendLiteral("INBOX");
1024 else
1025 changedStr.Append(tokenStr);
1026
1027 if (slashPos > 0) changedStr.Append(remStr);
1028
1029 dupFolderPath.Assign(changedStr);
1030 nsAutoCString folderName(dupFolderPath);
1031
1032 nsAutoCString uri;
1033 nsCString serverUri;
1034 GetServerURI(serverUri);
1035 uri.Assign(serverUri);
1036 int32_t leafPos = folderName.RFindChar('/');
1037 nsAutoCString parentName(folderName);
1038 nsAutoCString parentUri(uri);
1039
1040 if (leafPos > 0) {
1041 // If there is a hierarchy, there is a parent.
1042 // Don't strip off slash if it's the first character
1043 parentName.SetLength(leafPos);
1044 folderName.Cut(0, leafPos + 1); // get rid of the parent name
1045 haveParent = true;
1046 parentUri.Append('/');
1047 parentUri.Append(parentName);
1048 }
1049 if (folderPath.LowerCaseEqualsLiteral("inbox") &&
1050 hierarchyDelimiter == kOnlineHierarchySeparatorNil) {
1051 hierarchyDelimiter = '/'; // set to default in this case (as in 4.x)
1052 hostFolder->SetHierarchyDelimiter(hierarchyDelimiter);
1053 }
1054
1055 nsCOMPtr<nsIMsgFolder> child;
1056
1057 // nsCString possibleName(aSpec->allocatedPathName);
1058 uri.Append('/');
1059 uri.Append(dupFolderPath);
1060 bool caseInsensitive = dupFolderPath.LowerCaseEqualsLiteral("inbox");
1061 rootFolder->GetChildWithURI(uri, true, caseInsensitive,
1062 getter_AddRefs(child));
1063 // if we couldn't find this folder by URI, tell the imap code it's a new
1064 // folder to us
1065 *aNewFolder = !child;
1066 if (child) found = true;
1067 if (!found) {
1068 // trying to find/discover the parent
1069 if (haveParent) {
1070 nsCOMPtr<nsIMsgFolder> parent;
1071 bool parentIsNew;
1072 caseInsensitive = parentName.LowerCaseEqualsLiteral("inbox");
1073 rootFolder->GetChildWithURI(parentUri, true, caseInsensitive,
1074 getter_AddRefs(parent));
1075 if (!parent /* || parentFolder->GetFolderNeedsAdded()*/) {
1076 PossibleImapMailbox(
1077 parentName, hierarchyDelimiter,
1078 kNoselect | // be defensive
1079 ((boxFlags & // only inherit certain flags from the child
1080 (kPublicMailbox | kOtherUsersMailbox | kPersonalMailbox))),
1081 &parentIsNew);
1082 }
1083 }
1084 rv = hostFolder->CreateClientSubfolderInfo(
1085 dupFolderPath, hierarchyDelimiter, boxFlags, false);
1086 NS_ENSURE_SUCCESS(rv, rv);
1087 caseInsensitive = dupFolderPath.LowerCaseEqualsLiteral("inbox");
1088 rootFolder->GetChildWithURI(uri, true, caseInsensitive,
1089 getter_AddRefs(child));
1090 }
1091 if (child) {
1092 nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(child);
1093 if (imapFolder) {
1094 nsAutoCString onlineName;
1095 nsAutoString unicodeName;
1096 imapFolder->SetVerifiedAsOnlineFolder(true);
1097 imapFolder->SetHierarchyDelimiter(hierarchyDelimiter);
1098 if (boxFlags & kImapTrash) {
1099 int32_t deleteModel;
1100 GetDeleteModel(&deleteModel);
1101 if (deleteModel == nsMsgImapDeleteModels::MoveToTrash)
1102 child->SetFlag(nsMsgFolderFlags::Trash);
1103 }
1104
1105 imapFolder->SetBoxFlags(boxFlags);
1106 imapFolder->SetExplicitlyVerify(explicitlyVerify);
1107 imapFolder->GetOnlineName(onlineName);
1108
1109 // online name needs to use the correct hierarchy delimiter (I think...)
1110 // or the canonical path - one or the other, but be consistent.
1111 dupFolderPath.ReplaceChar('/', hierarchyDelimiter);
1112 if (hierarchyDelimiter != '/') {
1113 nsImapUrl::UnescapeSlashes(dupFolderPath);
1114 }
1115
1116 // GMail gives us a localized name for the inbox but doesn't let
1117 // us select that localized name.
1118 if (boxFlags & kImapInbox)
1119 imapFolder->SetOnlineName("INBOX"_ns);
1120 else if (onlineName.IsEmpty() || !onlineName.Equals(dupFolderPath))
1121 imapFolder->SetOnlineName(dupFolderPath);
1122
1123 if (hierarchyDelimiter != '/') {
1124 nsImapUrl::UnescapeSlashes(folderName);
1125 }
1126 if (NS_SUCCEEDED(CopyFolderNameToUTF16(folderName, unicodeName)))
1127 child->SetPrettyName(unicodeName);
1128 }
1129 }
1130 if (!found && child)
1131 child->SetMsgDatabase(nullptr); // close the db, so we don't hold open all
1132 // the .msf files for new folders
1133 return NS_OK;
1134 }
1135
AddFolderRights(const nsACString & mailboxName,const nsACString & userName,const nsACString & rights)1136 NS_IMETHODIMP nsImapIncomingServer::AddFolderRights(
1137 const nsACString& mailboxName, const nsACString& userName,
1138 const nsACString& rights) {
1139 nsCOMPtr<nsIMsgFolder> rootFolder;
1140 nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
1141 if (NS_SUCCEEDED(rv) && rootFolder) {
1142 nsCOMPtr<nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
1143 if (imapRoot) {
1144 nsCOMPtr<nsIMsgImapMailFolder> foundFolder;
1145 rv = imapRoot->FindOnlineSubFolder(mailboxName,
1146 getter_AddRefs(foundFolder));
1147 if (NS_SUCCEEDED(rv) && foundFolder)
1148 return foundFolder->AddFolderRights(userName, rights);
1149 }
1150 }
1151 return rv;
1152 }
1153
FolderNeedsACLInitialized(const nsACString & folderPath,bool * aNeedsACLInitialized)1154 NS_IMETHODIMP nsImapIncomingServer::FolderNeedsACLInitialized(
1155 const nsACString& folderPath, bool* aNeedsACLInitialized) {
1156 NS_ENSURE_ARG_POINTER(aNeedsACLInitialized);
1157 nsCOMPtr<nsIMsgFolder> rootFolder;
1158 nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
1159 if (NS_SUCCEEDED(rv) && rootFolder) {
1160 nsCOMPtr<nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
1161 if (imapRoot) {
1162 nsCOMPtr<nsIMsgImapMailFolder> foundFolder;
1163 rv = imapRoot->FindOnlineSubFolder(folderPath,
1164 getter_AddRefs(foundFolder));
1165 if (NS_SUCCEEDED(rv) && foundFolder) {
1166 nsCOMPtr<nsIImapMailFolderSink> folderSink =
1167 do_QueryInterface(foundFolder);
1168 if (folderSink)
1169 return folderSink->GetFolderNeedsACLListed(aNeedsACLInitialized);
1170 }
1171 }
1172 }
1173 *aNeedsACLInitialized = false; // maybe we want to say TRUE here...
1174 return NS_OK;
1175 }
1176
RefreshFolderRights(const nsACString & folderPath)1177 NS_IMETHODIMP nsImapIncomingServer::RefreshFolderRights(
1178 const nsACString& folderPath) {
1179 nsCOMPtr<nsIMsgFolder> rootFolder;
1180 nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
1181 if (NS_SUCCEEDED(rv) && rootFolder) {
1182 nsCOMPtr<nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
1183 if (imapRoot) {
1184 nsCOMPtr<nsIMsgImapMailFolder> foundFolder;
1185 rv = imapRoot->FindOnlineSubFolder(folderPath,
1186 getter_AddRefs(foundFolder));
1187 if (NS_SUCCEEDED(rv) && foundFolder)
1188 return foundFolder->RefreshFolderRights();
1189 }
1190 }
1191 return rv;
1192 }
1193
GetFolder(const nsACString & name,nsIMsgFolder ** pFolder)1194 nsresult nsImapIncomingServer::GetFolder(const nsACString& name,
1195 nsIMsgFolder** pFolder) {
1196 NS_ENSURE_ARG_POINTER(pFolder);
1197 NS_ENSURE_TRUE(!name.IsEmpty(), NS_ERROR_FAILURE);
1198 nsresult rv;
1199 *pFolder = nullptr;
1200
1201 nsCOMPtr<nsIMsgFolder> rootFolder;
1202 rv = GetRootFolder(getter_AddRefs(rootFolder));
1203 if (NS_SUCCEEDED(rv) && rootFolder) {
1204 nsCString uri;
1205 rv = rootFolder->GetURI(uri);
1206 if (NS_SUCCEEDED(rv) && !uri.IsEmpty()) {
1207 nsAutoCString uriString(uri);
1208 uriString.Append('/');
1209 uriString.Append(name);
1210 rv = GetOrCreateFolder(uriString, pFolder);
1211 }
1212 }
1213 return rv;
1214 }
1215
OnlineFolderDelete(const nsACString & aFolderName)1216 NS_IMETHODIMP nsImapIncomingServer::OnlineFolderDelete(
1217 const nsACString& aFolderName) {
1218 return NS_OK;
1219 }
1220
OnlineFolderCreateFailed(const nsACString & aFolderName)1221 NS_IMETHODIMP nsImapIncomingServer::OnlineFolderCreateFailed(
1222 const nsACString& aFolderName) {
1223 return NS_OK;
1224 }
1225
OnlineFolderRename(nsIMsgWindow * msgWindow,const nsACString & oldName,const nsACString & newName)1226 NS_IMETHODIMP nsImapIncomingServer::OnlineFolderRename(
1227 nsIMsgWindow* msgWindow, const nsACString& oldName,
1228 const nsACString& newName) {
1229 nsresult rv = NS_ERROR_FAILURE;
1230 if (!newName.IsEmpty()) {
1231 nsCOMPtr<nsIMsgFolder> me;
1232 rv = GetFolder(oldName, getter_AddRefs(me));
1233 if (NS_FAILED(rv)) return rv;
1234
1235 nsCOMPtr<nsIMsgFolder> parent;
1236 nsCString tmpNewName(newName);
1237 int32_t folderStart = tmpNewName.RFindChar('/');
1238 if (folderStart > 0) {
1239 rv = GetFolder(StringHead(tmpNewName, folderStart),
1240 getter_AddRefs(parent));
1241 } else // root is the parent
1242 rv = GetRootFolder(getter_AddRefs(parent));
1243 if (NS_SUCCEEDED(rv) && parent) {
1244 nsCOMPtr<nsIMsgImapMailFolder> folder;
1245 folder = do_QueryInterface(me, &rv);
1246 if (NS_SUCCEEDED(rv)) {
1247 folder->RenameLocal(tmpNewName, parent);
1248 nsCOMPtr<nsIMsgImapMailFolder> parentImapFolder =
1249 do_QueryInterface(parent);
1250
1251 if (parentImapFolder)
1252 parentImapFolder->RenameClient(msgWindow, me, oldName, tmpNewName);
1253
1254 nsCOMPtr<nsIMsgFolder> newFolder;
1255 nsString unicodeNewName;
1256 // `tmpNewName` is in MUTF-7 or UTF-8. It needs to be convert to UTF-8.
1257 CopyFolderNameToUTF16(tmpNewName, unicodeNewName);
1258 CopyUTF16toUTF8(unicodeNewName, tmpNewName);
1259 rv = GetFolder(tmpNewName, getter_AddRefs(newFolder));
1260 if (NS_SUCCEEDED(rv)) {
1261 newFolder->NotifyFolderEvent(kRenameCompleted);
1262 }
1263 }
1264 }
1265 }
1266 return rv;
1267 }
1268
FolderIsNoSelect(const nsACString & aFolderName,bool * result)1269 NS_IMETHODIMP nsImapIncomingServer::FolderIsNoSelect(
1270 const nsACString& aFolderName, bool* result) {
1271 NS_ENSURE_ARG_POINTER(result);
1272 nsCOMPtr<nsIMsgFolder> msgFolder;
1273 nsresult rv = GetFolder(aFolderName, getter_AddRefs(msgFolder));
1274 if (NS_SUCCEEDED(rv) && msgFolder) {
1275 uint32_t flags;
1276 msgFolder->GetFlags(&flags);
1277 *result = ((flags & nsMsgFolderFlags::ImapNoselect) != 0);
1278 } else
1279 *result = false;
1280 return NS_OK;
1281 }
1282
SetFolderAdminURL(const nsACString & aFolderName,const nsACString & aFolderAdminUrl)1283 NS_IMETHODIMP nsImapIncomingServer::SetFolderAdminURL(
1284 const nsACString& aFolderName, const nsACString& aFolderAdminUrl) {
1285 nsCOMPtr<nsIMsgFolder> rootFolder;
1286 nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
1287 if (NS_SUCCEEDED(rv) && rootFolder) {
1288 nsCOMPtr<nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
1289 if (imapRoot) {
1290 nsCOMPtr<nsIMsgImapMailFolder> foundFolder;
1291 rv = imapRoot->FindOnlineSubFolder(aFolderName,
1292 getter_AddRefs(foundFolder));
1293 if (NS_SUCCEEDED(rv) && foundFolder)
1294 return foundFolder->SetAdminUrl(aFolderAdminUrl);
1295 }
1296 }
1297 return rv;
1298 }
1299
FolderVerifiedOnline(const nsACString & folderName,bool * aResult)1300 NS_IMETHODIMP nsImapIncomingServer::FolderVerifiedOnline(
1301 const nsACString& folderName, bool* aResult) {
1302 NS_ENSURE_ARG_POINTER(aResult);
1303 *aResult = false;
1304 nsCOMPtr<nsIMsgFolder> rootFolder;
1305 nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
1306 if (NS_SUCCEEDED(rv) && rootFolder) {
1307 nsCOMPtr<nsIMsgFolder> folder;
1308 rv = rootFolder->FindSubFolder(folderName, getter_AddRefs(folder));
1309 if (NS_SUCCEEDED(rv) && folder) {
1310 nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(folder);
1311 if (imapFolder) imapFolder->GetVerifiedAsOnlineFolder(aResult);
1312 }
1313 }
1314 return rv;
1315 }
1316
DiscoveryDone()1317 NS_IMETHODIMP nsImapIncomingServer::DiscoveryDone() {
1318 if (mDoingSubscribeDialog) return NS_OK;
1319
1320 nsCOMPtr<nsIMsgFolder> rootMsgFolder;
1321 nsresult rv = GetRootFolder(getter_AddRefs(rootMsgFolder));
1322 if (NS_SUCCEEDED(rv) && rootMsgFolder) {
1323 // GetResource() may return a node which is not in the folder
1324 // tree hierarchy but in the rdf cache in case of the non-existing default
1325 // Sent, Drafts, and Templates folders. The resource will be eventually
1326 // released when the rdf service shuts down. When we create the default
1327 // folders later on in the imap server, the subsequent GetResource() of the
1328 // same uri will get us the cached rdf resource which should have the folder
1329 // flag set appropriately.
1330
1331 nsCOMPtr<nsIMsgAccountManager> accountMgr =
1332 do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
1333 NS_ENSURE_SUCCESS(rv, rv);
1334
1335 nsCOMPtr<nsIMsgIdentity> identity;
1336 rv = accountMgr->GetFirstIdentityForServer(this, getter_AddRefs(identity));
1337 if (NS_SUCCEEDED(rv) && identity) {
1338 nsCString folderUri;
1339 identity->GetFccFolder(folderUri);
1340 nsCString existingUri;
1341
1342 if (CheckSpecialFolder(folderUri, nsMsgFolderFlags::SentMail,
1343 existingUri)) {
1344 identity->SetFccFolder(existingUri);
1345 identity->SetFccFolderPickerMode("1"_ns);
1346 }
1347 identity->GetDraftFolder(folderUri);
1348 if (CheckSpecialFolder(folderUri, nsMsgFolderFlags::Drafts,
1349 existingUri)) {
1350 identity->SetDraftFolder(existingUri);
1351 identity->SetDraftsFolderPickerMode("1"_ns);
1352 }
1353 bool archiveEnabled;
1354 identity->GetArchiveEnabled(&archiveEnabled);
1355 if (archiveEnabled) {
1356 identity->GetArchiveFolder(folderUri);
1357 if (CheckSpecialFolder(folderUri, nsMsgFolderFlags::Archive,
1358 existingUri)) {
1359 identity->SetArchiveFolder(existingUri);
1360 identity->SetArchivesFolderPickerMode("1"_ns);
1361 }
1362 }
1363 identity->GetStationeryFolder(folderUri);
1364 if (!folderUri.IsEmpty()) {
1365 nsCOMPtr<nsIMsgFolder> folder;
1366 rv = GetOrCreateFolder(folderUri, getter_AddRefs(folder));
1367 if (NS_SUCCEEDED(rv)) rv = folder->SetFlag(nsMsgFolderFlags::Templates);
1368 }
1369 }
1370
1371 nsCOMPtr<nsISpamSettings> spamSettings;
1372 rv = GetSpamSettings(getter_AddRefs(spamSettings));
1373 if (NS_SUCCEEDED(rv) && spamSettings) {
1374 nsCString spamFolderUri, existingUri;
1375 spamSettings->GetSpamFolderURI(spamFolderUri);
1376 if (CheckSpecialFolder(spamFolderUri, nsMsgFolderFlags::Junk,
1377 existingUri)) {
1378 // This only sets the cached values in the spam settings object.
1379 spamSettings->SetActionTargetFolder(existingUri);
1380 spamSettings->SetMoveTargetMode(
1381 nsISpamSettings::MOVE_TARGET_MODE_FOLDER);
1382 // Set the preferences too so that the values persist.
1383 SetCharValue("spamActionTargetFolder", existingUri);
1384 SetIntValue("moveTargetMode", nsISpamSettings::MOVE_TARGET_MODE_FOLDER);
1385 }
1386 }
1387
1388 bool isGMailServer;
1389 GetIsGMailServer(&isGMailServer);
1390
1391 // Verify there is only one trash folder. Another might be present if
1392 // the trash name has been changed. Or we might be a gmail server and
1393 // want to switch to gmail's trash folder.
1394 nsTArray<RefPtr<nsIMsgFolder>> trashFolders;
1395 rv = rootMsgFolder->GetFoldersWithFlags(nsMsgFolderFlags::Trash,
1396 trashFolders);
1397
1398 if (NS_SUCCEEDED(rv)) {
1399 nsAutoString trashName;
1400 if (NS_SUCCEEDED(GetTrashFolderName(trashName))) {
1401 for (auto trashFolder : trashFolders) {
1402 // If we're a gmail server, we clear the trash flags from folder(s)
1403 // without the kImapXListTrash flag. For normal servers, we clear
1404 // the trash folder flag if the folder name doesn't match the
1405 // pref trash folder name.
1406 nsAutoString retval;
1407 rv = GetUnicharValue(PREF_TRASH_FOLDER_PATH, retval);
1408 if (isGMailServer && (NS_FAILED(rv) || retval.IsEmpty())) {
1409 nsCOMPtr<nsIMsgImapMailFolder> imapFolder(
1410 do_QueryInterface(trashFolder));
1411 int32_t boxFlags;
1412 imapFolder->GetBoxFlags(&boxFlags);
1413 if (boxFlags & kImapXListTrash) {
1414 continue;
1415 }
1416 } else {
1417 // Store the trash folder path. We maintain the full path in the
1418 // trash_folder_name preference since the full path is stored
1419 // there when selecting a trash folder in the Account Manager.
1420 nsAutoCString trashURL;
1421 trashFolder->GetFolderURL(trashURL);
1422 nsCOMPtr<nsIURI> uri;
1423 NS_NewURI(getter_AddRefs(uri), trashURL);
1424 nsAutoCString trashPath;
1425 uri->GetPathQueryRef(trashPath);
1426 nsAutoCString unescapedName;
1427 MsgUnescapeString(Substring(trashPath, 1), // Skip leading slash.
1428 nsINetUtil::ESCAPE_URL_PATH, unescapedName);
1429 nsAutoString nameUnicode;
1430 if (NS_FAILED(CopyFolderNameToUTF16(unescapedName, nameUnicode)) ||
1431 trashName.Equals(nameUnicode)) {
1432 continue;
1433 }
1434 if (trashFolders.Length() == 1) {
1435 // We got here because the preferred trash folder does not
1436 // exist, but a folder got discovered to be the trash folder.
1437 SetUnicharValue(PREF_TRASH_FOLDER_PATH, nameUnicode);
1438 continue;
1439 }
1440 }
1441 // We clear the trash folder flag if the trash folder path doesn't
1442 // match mail.server.serverX.trash_folder_name.
1443 trashFolder->ClearFlag(nsMsgFolderFlags::Trash);
1444 }
1445 }
1446 }
1447 }
1448
1449 bool usingSubscription = true;
1450 GetUsingSubscription(&usingSubscription);
1451
1452 nsCOMArray<nsIMsgImapMailFolder> unverifiedFolders;
1453 GetUnverifiedFolders(unverifiedFolders);
1454
1455 int32_t count = unverifiedFolders.Count();
1456 for (int32_t k = 0; k < count; ++k) {
1457 bool explicitlyVerify = false;
1458 bool hasSubFolders = false;
1459 uint32_t folderFlags;
1460 nsCOMPtr<nsIMsgImapMailFolder> currentImapFolder(unverifiedFolders[k]);
1461 nsCOMPtr<nsIMsgFolder> currentFolder(
1462 do_QueryInterface(currentImapFolder, &rv));
1463 if (NS_FAILED(rv)) continue;
1464
1465 currentFolder->GetFlags(&folderFlags);
1466 if (folderFlags &
1467 nsMsgFolderFlags::Virtual) // don't remove virtual folders
1468 continue;
1469
1470 if ((!usingSubscription ||
1471 (NS_SUCCEEDED(
1472 currentImapFolder->GetExplicitlyVerify(&explicitlyVerify)) &&
1473 explicitlyVerify)) ||
1474 ((NS_SUCCEEDED(currentFolder->GetHasSubFolders(&hasSubFolders)) &&
1475 hasSubFolders) &&
1476 !NoDescendentsAreVerified(currentFolder))) {
1477 bool isNamespace;
1478 currentImapFolder->GetIsNamespace(&isNamespace);
1479 if (!isNamespace) // don't list namespaces explicitly
1480 {
1481 // If there are no subfolders and this is unverified, we don't want to
1482 // run this url. That is, we want to undiscover the folder.
1483 // If there are subfolders and no descendants are verified, we want to
1484 // undiscover all of the folders.
1485 // Only if there are subfolders and at least one of them is verified
1486 // do we want to refresh that folder's flags, because it won't be going
1487 // away.
1488 currentImapFolder->SetExplicitlyVerify(false);
1489 currentImapFolder->List();
1490 }
1491 } else {
1492 nsCOMPtr<nsIMsgFolder> parent;
1493 currentFolder->GetParent(getter_AddRefs(parent));
1494 if (parent) {
1495 currentImapFolder->RemoveLocalSelf();
1496 }
1497 }
1498 }
1499
1500 return rv;
1501 }
1502
1503 // Check if the special folder corresponding to the uri exists. If not, check
1504 // if there already exists a folder with the special folder flag (the server may
1505 // have told us about a folder to use through XLIST). If so, return the uri of
1506 // the existing special folder. If not, set the special flag on the folder so
1507 // it will be there if and when the folder is created.
1508 // Return true if we found an existing special folder different than
1509 // the one specified in prefs, and the one specified by prefs doesn't exist.
CheckSpecialFolder(nsCString & folderUri,uint32_t folderFlag,nsCString & existingUri)1510 bool nsImapIncomingServer::CheckSpecialFolder(nsCString& folderUri,
1511 uint32_t folderFlag,
1512 nsCString& existingUri) {
1513 nsCOMPtr<nsIMsgFolder> folder;
1514 nsCOMPtr<nsIMsgFolder> rootMsgFolder;
1515 nsresult rv = GetRootFolder(getter_AddRefs(rootMsgFolder));
1516 NS_ENSURE_SUCCESS(rv, false);
1517 nsCOMPtr<nsIMsgFolder> existingFolder;
1518 rootMsgFolder->GetFolderWithFlags(folderFlag, getter_AddRefs(existingFolder));
1519
1520 if (!folderUri.IsEmpty() &&
1521 NS_SUCCEEDED(GetOrCreateFolder(folderUri, getter_AddRefs(folder)))) {
1522 nsCOMPtr<nsIMsgFolder> parent;
1523 folder->GetParent(getter_AddRefs(parent));
1524 if (parent) {
1525 existingFolder = nullptr;
1526 }
1527 if (!existingFolder) {
1528 folder->SetFlag(folderFlag);
1529 }
1530
1531 nsString folderName;
1532 folder->GetPrettyName(folderName);
1533 // this will set the localized name based on the folder flag.
1534 folder->SetPrettyName(folderName);
1535 }
1536
1537 if (existingFolder) {
1538 existingFolder->GetURI(existingUri);
1539 return true;
1540 }
1541
1542 return false;
1543 }
1544
NoDescendentsAreVerified(nsIMsgFolder * parentFolder)1545 bool nsImapIncomingServer::NoDescendentsAreVerified(
1546 nsIMsgFolder* parentFolder) {
1547 nsTArray<RefPtr<nsIMsgFolder>> subFolders;
1548 nsresult rv = parentFolder->GetSubFolders(subFolders);
1549 if (NS_SUCCEEDED(rv)) {
1550 for (nsIMsgFolder* child : subFolders) {
1551 nsCOMPtr<nsIMsgImapMailFolder> childImapFolder =
1552 do_QueryInterface(child, &rv);
1553 if (NS_SUCCEEDED(rv) && childImapFolder) {
1554 bool childVerified = false;
1555 rv = childImapFolder->GetVerifiedAsOnlineFolder(&childVerified);
1556 if (NS_SUCCEEDED(rv) && childVerified) {
1557 return false;
1558 }
1559 if (!NoDescendentsAreVerified(child)) {
1560 return false;
1561 }
1562 }
1563 }
1564 }
1565 // If we get this far we didn't find any verified.
1566 return true;
1567 }
1568
AllDescendentsAreNoSelect(nsIMsgFolder * parentFolder)1569 bool nsImapIncomingServer::AllDescendentsAreNoSelect(
1570 nsIMsgFolder* parentFolder) {
1571 nsTArray<RefPtr<nsIMsgFolder>> subFolders;
1572 nsresult rv = parentFolder->GetSubFolders(subFolders);
1573 if (NS_SUCCEEDED(rv)) {
1574 for (nsIMsgFolder* child : subFolders) {
1575 nsCOMPtr<nsIMsgImapMailFolder> childImapFolder =
1576 do_QueryInterface(child, &rv);
1577 if (NS_SUCCEEDED(rv) && childImapFolder) {
1578 uint32_t flags;
1579 rv = child->GetFlags(&flags);
1580 bool isNoSelect =
1581 NS_SUCCEEDED(rv) && (flags & nsMsgFolderFlags::ImapNoselect);
1582 if (!isNoSelect) {
1583 return false;
1584 }
1585 if (!AllDescendentsAreNoSelect(child)) {
1586 return false;
1587 }
1588 }
1589 }
1590 }
1591 // If we get this far we found none without the Noselect flag.
1592 return true;
1593 }
1594
1595 NS_IMETHODIMP
PromptLoginFailed(nsIMsgWindow * aMsgWindow,int32_t * aResult)1596 nsImapIncomingServer::PromptLoginFailed(nsIMsgWindow* aMsgWindow,
1597 int32_t* aResult) {
1598 nsAutoCString hostName;
1599 GetRealHostName(hostName);
1600
1601 nsAutoCString userName;
1602 GetRealUsername(userName);
1603
1604 nsAutoString accountName;
1605 GetPrettyName(accountName);
1606
1607 return MsgPromptLoginFailed(aMsgWindow, hostName, userName, accountName,
1608 aResult);
1609 }
1610
1611 NS_IMETHODIMP
FEAlert(const nsAString & aAlertString,nsIMsgMailNewsUrl * aUrl)1612 nsImapIncomingServer::FEAlert(const nsAString& aAlertString,
1613 nsIMsgMailNewsUrl* aUrl) {
1614 GetStringBundle();
1615
1616 if (m_stringBundle) {
1617 nsAutoString hostName;
1618 nsresult rv = GetPrettyName(hostName);
1619 if (NS_SUCCEEDED(rv)) {
1620 nsString message;
1621 nsString tempString(aAlertString);
1622 AutoTArray<nsString, 2> params = {hostName, tempString};
1623
1624 rv = m_stringBundle->FormatStringFromName("imapServerAlert", params,
1625 message);
1626 if (NS_SUCCEEDED(rv)) {
1627 aUrl->SetErrorCode("imap-server-alert"_ns);
1628 aUrl->SetErrorMessage(message);
1629
1630 return AlertUser(message, aUrl);
1631 }
1632 }
1633 }
1634 return AlertUser(aAlertString, aUrl);
1635 }
1636
AlertUser(const nsAString & aString,nsIMsgMailNewsUrl * aUrl)1637 nsresult nsImapIncomingServer::AlertUser(const nsAString& aString,
1638 nsIMsgMailNewsUrl* aUrl) {
1639 nsresult rv;
1640 nsCOMPtr<nsIMsgMailSession> mailSession =
1641 do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
1642 NS_ENSURE_SUCCESS(rv, rv);
1643
1644 return mailSession->AlertUser(aString, aUrl);
1645 }
1646
1647 NS_IMETHODIMP
FEAlertWithName(const char * aMsgName,nsIMsgMailNewsUrl * aUrl)1648 nsImapIncomingServer::FEAlertWithName(const char* aMsgName,
1649 nsIMsgMailNewsUrl* aUrl) {
1650 // don't bother the user if we're shutting down.
1651 if (m_shuttingDown) return NS_OK;
1652
1653 GetStringBundle();
1654
1655 nsString message;
1656
1657 if (m_stringBundle) {
1658 nsAutoCString hostName;
1659 nsresult rv = GetHostName(hostName);
1660 if (NS_SUCCEEDED(rv)) {
1661 AutoTArray<nsString, 1> params;
1662 CopyUTF8toUTF16(hostName, *params.AppendElement());
1663 rv = m_stringBundle->FormatStringFromName(aMsgName, params, message);
1664 if (NS_SUCCEEDED(rv)) {
1665 aUrl->SetErrorCode(nsDependentCString(aMsgName));
1666 aUrl->SetErrorMessage(message);
1667
1668 return AlertUser(message, aUrl);
1669 }
1670 }
1671 }
1672
1673 // Error condition
1674 message.AssignLiteral("String Name ");
1675 message.AppendASCII(aMsgName);
1676 FEAlert(message, aUrl);
1677 return NS_OK;
1678 }
1679
FEAlertFromServer(const nsACString & aServerString,nsIMsgMailNewsUrl * aUrl)1680 NS_IMETHODIMP nsImapIncomingServer::FEAlertFromServer(
1681 const nsACString& aServerString, nsIMsgMailNewsUrl* aUrl) {
1682 NS_ENSURE_TRUE(!aServerString.IsEmpty(), NS_OK);
1683
1684 nsCString message(aServerString);
1685 message.Trim(" \t\b\r\n");
1686 if (message.Last() != '.') message.Append('.');
1687
1688 // Skip over the first two words (the command tag and "NO").
1689 // Find the first word break.
1690 int32_t pos = message.FindChar(' ');
1691
1692 // Find the second word break.
1693 if (pos != -1) pos = message.FindChar(' ', pos + 1);
1694
1695 // Adjust the message.
1696 if (pos != -1) message = Substring(message, pos + 1);
1697
1698 nsString hostName;
1699 GetPrettyName(hostName);
1700
1701 AutoTArray<nsString, 3> formatStrings = {hostName};
1702
1703 const char* msgName;
1704 nsString fullMessage;
1705 nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(aUrl);
1706 NS_ENSURE_TRUE(imapUrl, NS_ERROR_INVALID_ARG);
1707
1708 nsImapState imapState;
1709 nsImapAction imapAction;
1710
1711 imapUrl->GetRequiredImapState(&imapState);
1712 imapUrl->GetImapAction(&imapAction);
1713 nsString folderName;
1714
1715 NS_ConvertUTF8toUTF16 unicodeMsg(message);
1716
1717 aUrl->SetErrorCode("imap-server-error"_ns);
1718 aUrl->SetErrorMessage(unicodeMsg);
1719
1720 nsCOMPtr<nsIMsgFolder> folder;
1721 if (imapState == nsIImapUrl::nsImapSelectedState ||
1722 imapAction == nsIImapUrl::nsImapFolderStatus) {
1723 aUrl->GetFolder(getter_AddRefs(folder));
1724 if (folder) folder->GetPrettyName(folderName);
1725 msgName = "imapFolderCommandFailed";
1726 formatStrings.AppendElement(folderName);
1727 } else {
1728 msgName = "imapServerCommandFailed";
1729 }
1730
1731 formatStrings.AppendElement(unicodeMsg);
1732
1733 nsresult rv = GetStringBundle();
1734 NS_ENSURE_SUCCESS(rv, rv);
1735 if (m_stringBundle) {
1736 rv = m_stringBundle->FormatStringFromName(msgName, formatStrings,
1737 fullMessage);
1738 NS_ENSURE_SUCCESS(rv, rv);
1739 }
1740
1741 return AlertUser(fullMessage, aUrl);
1742 }
1743
1744 #define IMAP_MSGS_URL "chrome://messenger/locale/imapMsgs.properties"
1745
GetStringBundle()1746 nsresult nsImapIncomingServer::GetStringBundle() {
1747 if (m_stringBundle) return NS_OK;
1748
1749 nsCOMPtr<nsIStringBundleService> sBundleService =
1750 mozilla::services::GetStringBundleService();
1751 NS_ENSURE_TRUE(sBundleService, NS_ERROR_UNEXPECTED);
1752 return sBundleService->CreateBundle(IMAP_MSGS_URL,
1753 getter_AddRefs(m_stringBundle));
1754 }
1755
1756 NS_IMETHODIMP
GetImapStringByName(const char * msgName,nsAString & aString)1757 nsImapIncomingServer::GetImapStringByName(const char* msgName,
1758 nsAString& aString) {
1759 nsresult rv = NS_OK;
1760 GetStringBundle();
1761 if (m_stringBundle) {
1762 nsString res_str;
1763 rv = m_stringBundle->GetStringFromName(msgName, res_str);
1764 aString.Assign(res_str);
1765 if (NS_SUCCEEDED(rv)) return rv;
1766 }
1767 aString.AssignLiteral("String Name ");
1768 // mscott: FIX ME
1769 aString.AppendASCII(msgName);
1770 return NS_OK;
1771 }
1772
ResetFoldersToUnverified(nsIMsgFolder * parentFolder)1773 nsresult nsImapIncomingServer::ResetFoldersToUnverified(
1774 nsIMsgFolder* parentFolder) {
1775 nsresult rv = NS_OK;
1776 if (!parentFolder) {
1777 nsCOMPtr<nsIMsgFolder> rootFolder;
1778 rv = GetRootFolder(getter_AddRefs(rootFolder));
1779 NS_ENSURE_SUCCESS(rv, rv);
1780 return ResetFoldersToUnverified(rootFolder);
1781 }
1782
1783 nsCOMPtr<nsIMsgImapMailFolder> imapFolder =
1784 do_QueryInterface(parentFolder, &rv);
1785 NS_ENSURE_SUCCESS(rv, rv);
1786 rv = imapFolder->SetVerifiedAsOnlineFolder(false);
1787 nsTArray<RefPtr<nsIMsgFolder>> subFolders;
1788 rv = parentFolder->GetSubFolders(subFolders);
1789 NS_ENSURE_SUCCESS(rv, rv);
1790
1791 for (nsIMsgFolder* child : subFolders) {
1792 rv = ResetFoldersToUnverified(child);
1793 NS_ENSURE_SUCCESS(rv, rv);
1794 }
1795
1796 return rv;
1797 }
1798
GetUnverifiedFolders(nsCOMArray<nsIMsgImapMailFolder> & aFoldersArray)1799 void nsImapIncomingServer::GetUnverifiedFolders(
1800 nsCOMArray<nsIMsgImapMailFolder>& aFoldersArray) {
1801 nsCOMPtr<nsIMsgFolder> rootFolder;
1802 if (NS_FAILED(GetRootFolder(getter_AddRefs(rootFolder))) || !rootFolder)
1803 return;
1804
1805 nsCOMPtr<nsIMsgImapMailFolder> imapRoot(do_QueryInterface(rootFolder));
1806 // don't need to verify the root.
1807 if (imapRoot) imapRoot->SetVerifiedAsOnlineFolder(true);
1808
1809 GetUnverifiedSubFolders(rootFolder, aFoldersArray);
1810 }
1811
GetUnverifiedSubFolders(nsIMsgFolder * parentFolder,nsCOMArray<nsIMsgImapMailFolder> & aFoldersArray)1812 void nsImapIncomingServer::GetUnverifiedSubFolders(
1813 nsIMsgFolder* parentFolder,
1814 nsCOMArray<nsIMsgImapMailFolder>& aFoldersArray) {
1815 nsCOMPtr<nsIMsgImapMailFolder> imapFolder(do_QueryInterface(parentFolder));
1816
1817 bool verified = false, explicitlyVerify = false;
1818 if (imapFolder) {
1819 nsresult rv = imapFolder->GetVerifiedAsOnlineFolder(&verified);
1820 if (NS_SUCCEEDED(rv))
1821 rv = imapFolder->GetExplicitlyVerify(&explicitlyVerify);
1822
1823 if (NS_SUCCEEDED(rv) && (!verified || explicitlyVerify))
1824 aFoldersArray.AppendObject(imapFolder);
1825 }
1826
1827 nsTArray<RefPtr<nsIMsgFolder>> subFolders;
1828 if (NS_SUCCEEDED(parentFolder->GetSubFolders(subFolders))) {
1829 for (nsIMsgFolder* child : subFolders) {
1830 GetUnverifiedSubFolders(child, aFoldersArray);
1831 }
1832 }
1833 }
1834
ForgetSessionPassword()1835 NS_IMETHODIMP nsImapIncomingServer::ForgetSessionPassword() {
1836 nsresult rv = nsMsgIncomingServer::ForgetSessionPassword();
1837 NS_ENSURE_SUCCESS(rv, rv);
1838
1839 // fix for bugscape bug #15485
1840 // if we use turbo, and we logout, we need to make sure
1841 // the server doesn't think it's authenticated.
1842 // the biff timer continues to fire when you use turbo
1843 // (see #143848). if we exited, we've set the password to null
1844 // but if we're authenticated, and the biff timer goes off
1845 // we'll still perform biff, because we use m_userAuthenticated
1846 // to determine if we require a password for biff.
1847 // (if authenticated, we don't require a password
1848 // see nsMsgBiffManager::PerformBiff())
1849 // performing biff without a password will pop up the prompt dialog
1850 // which is pretty wacky, when it happens after you quit the application
1851 m_userAuthenticated = false;
1852 return NS_OK;
1853 }
1854
GetServerRequiresPasswordForBiff(bool * aServerRequiresPasswordForBiff)1855 NS_IMETHODIMP nsImapIncomingServer::GetServerRequiresPasswordForBiff(
1856 bool* aServerRequiresPasswordForBiff) {
1857 NS_ENSURE_ARG_POINTER(aServerRequiresPasswordForBiff);
1858 // if the user has already been authenticated, we've got the password
1859 *aServerRequiresPasswordForBiff = !m_userAuthenticated;
1860 return NS_OK;
1861 }
1862
ForgetPassword()1863 NS_IMETHODIMP nsImapIncomingServer::ForgetPassword() {
1864 return nsMsgIncomingServer::ForgetPassword();
1865 }
1866
1867 NS_IMETHODIMP
AsyncGetPassword(nsIImapProtocol * aProtocol,bool aNewPasswordRequested,nsAString & aPassword)1868 nsImapIncomingServer::AsyncGetPassword(nsIImapProtocol* aProtocol,
1869 bool aNewPasswordRequested,
1870 nsAString& aPassword) {
1871 if (m_password.IsEmpty()) {
1872 // We're now going to need to do something that will end up with us either
1873 // poking login manager or prompting the user. We need to ensure we only
1874 // do one prompt at a time (and login manager could cause a master password
1875 // prompt), so we need to use the async prompter.
1876 nsresult rv;
1877 nsCOMPtr<nsIMsgAsyncPrompter> asyncPrompter =
1878 do_GetService(NS_MSGASYNCPROMPTER_CONTRACTID, &rv);
1879 NS_ENSURE_SUCCESS(rv, rv);
1880 nsCOMPtr<nsIMsgAsyncPromptListener> promptListener(
1881 do_QueryInterface(aProtocol));
1882 rv = asyncPrompter->QueueAsyncAuthPrompt(m_serverKey, aNewPasswordRequested,
1883 promptListener);
1884 // Explicit NS_ENSURE_SUCCESS for debug purposes as errors tend to get
1885 // hidden.
1886 NS_ENSURE_SUCCESS(rv, rv);
1887 }
1888 if (!m_password.IsEmpty()) aPassword = m_password;
1889 return NS_OK;
1890 }
1891
1892 NS_IMETHODIMP
PromptPassword(nsIMsgWindow * aMsgWindow,nsAString & aPassword)1893 nsImapIncomingServer::PromptPassword(nsIMsgWindow* aMsgWindow,
1894 nsAString& aPassword) {
1895 nsAutoCString userName;
1896 GetRealUsername(userName);
1897
1898 nsAutoCString hostName;
1899 GetRealHostName(hostName);
1900
1901 nsresult rv = GetStringBundle();
1902 NS_ENSURE_SUCCESS(rv, rv);
1903
1904 AutoTArray<nsString, 1> formatStrings;
1905 CopyUTF8toUTF16(userName, *formatStrings.AppendElement());
1906
1907 nsString passwordTitle;
1908 rv = m_stringBundle->FormatStringFromName(
1909 "imapEnterPasswordPromptTitleWithUsername", formatStrings, passwordTitle);
1910 NS_ENSURE_SUCCESS(rv, rv);
1911
1912 AutoTArray<nsString, 2> formatStrings2;
1913 CopyUTF8toUTF16(userName, *formatStrings2.AppendElement());
1914 CopyUTF8toUTF16(hostName, *formatStrings2.AppendElement());
1915
1916 nsString passwordText;
1917 rv = m_stringBundle->FormatStringFromName("imapEnterServerPasswordPrompt",
1918 formatStrings2, passwordText);
1919 NS_ENSURE_SUCCESS(rv, rv);
1920
1921 rv = GetPasswordWithUI(passwordText, passwordTitle, aMsgWindow, aPassword);
1922 if (NS_SUCCEEDED(rv)) m_password = aPassword;
1923 return rv;
1924 }
1925
1926 // for the nsIImapServerSink interface
SetCapability(eIMAPCapabilityFlags capability)1927 NS_IMETHODIMP nsImapIncomingServer::SetCapability(
1928 eIMAPCapabilityFlags capability) {
1929 m_capability = capability;
1930 SetIsGMailServer((capability & kGmailImapCapability) != 0);
1931 return NS_OK;
1932 }
1933
1934 NS_IMETHODIMP
GetCapability(eIMAPCapabilityFlags * capability)1935 nsImapIncomingServer::GetCapability(eIMAPCapabilityFlags* capability) {
1936 NS_ENSURE_ARG_POINTER(capability);
1937 *capability = m_capability;
1938 return NS_OK;
1939 }
1940
SetServerID(const nsACString & aServerID)1941 NS_IMETHODIMP nsImapIncomingServer::SetServerID(const nsACString& aServerID) {
1942 return SetServerIDPref(aServerID);
1943 }
1944
CommitNamespaces()1945 NS_IMETHODIMP nsImapIncomingServer::CommitNamespaces() {
1946 nsresult rv;
1947 nsCOMPtr<nsIImapHostSessionList> hostSession =
1948 do_GetService(kCImapHostSessionListCID, &rv);
1949 NS_ENSURE_SUCCESS(rv, rv);
1950 return hostSession->CommitNamespacesForHost(this);
1951 }
1952
PseudoInterruptMsgLoad(nsIMsgFolder * aImapFolder,nsIMsgWindow * aMsgWindow,bool * interrupted)1953 NS_IMETHODIMP nsImapIncomingServer::PseudoInterruptMsgLoad(
1954 nsIMsgFolder* aImapFolder, nsIMsgWindow* aMsgWindow, bool* interrupted) {
1955 nsresult rv = NS_OK;
1956 nsCOMPtr<nsIImapProtocol> connection;
1957 PR_CEnterMonitor(this);
1958 // iterate through the connection cache for a connection that is loading
1959 // a message in this folder and should be pseudo-interrupted.
1960 int32_t cnt = m_connectionCache.Count();
1961
1962 for (int32_t i = 0; i < cnt; ++i) {
1963 connection = m_connectionCache[i];
1964 if (connection)
1965 rv = connection->PseudoInterruptMsgLoad(aImapFolder, aMsgWindow,
1966 interrupted);
1967 }
1968
1969 PR_CExitMonitor(this);
1970 return rv;
1971 }
1972
ResetNamespaceReferences()1973 NS_IMETHODIMP nsImapIncomingServer::ResetNamespaceReferences() {
1974 nsCOMPtr<nsIMsgFolder> rootFolder;
1975 nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
1976 if (NS_SUCCEEDED(rv) && rootFolder) {
1977 nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(rootFolder);
1978 if (imapFolder) rv = imapFolder->ResetNamespaceReferences();
1979 }
1980 return rv;
1981 }
1982
SetUserAuthenticated(bool aUserAuthenticated)1983 NS_IMETHODIMP nsImapIncomingServer::SetUserAuthenticated(
1984 bool aUserAuthenticated) {
1985 m_userAuthenticated = aUserAuthenticated;
1986 if (aUserAuthenticated) {
1987 nsresult rv;
1988 nsCOMPtr<nsIMsgAccountManager> accountManager =
1989 do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
1990 NS_ENSURE_SUCCESS(rv, rv);
1991
1992 accountManager->SetUserNeedsToAuthenticate(false);
1993 }
1994 return NS_OK;
1995 }
1996
GetUserAuthenticated(bool * aUserAuthenticated)1997 NS_IMETHODIMP nsImapIncomingServer::GetUserAuthenticated(
1998 bool* aUserAuthenticated) {
1999 NS_ENSURE_ARG_POINTER(aUserAuthenticated);
2000 *aUserAuthenticated = m_userAuthenticated;
2001 return NS_OK;
2002 }
2003
2004 /* void SetMailServerUrls (in string manageMailAccount, in string manageLists,
2005 * in string manageFilters); */
SetMailServerUrls(const nsACString & manageMailAccount,const nsACString & manageLists,const nsACString & manageFilters)2006 NS_IMETHODIMP nsImapIncomingServer::SetMailServerUrls(
2007 const nsACString& manageMailAccount, const nsACString& manageLists,
2008 const nsACString& manageFilters) {
2009 return SetManageMailAccountUrl(manageMailAccount);
2010 }
2011
SetManageMailAccountUrl(const nsACString & manageMailAccountUrl)2012 NS_IMETHODIMP nsImapIncomingServer::SetManageMailAccountUrl(
2013 const nsACString& manageMailAccountUrl) {
2014 m_manageMailAccountUrl = manageMailAccountUrl;
2015 return NS_OK;
2016 }
2017
GetManageMailAccountUrl(nsACString & manageMailAccountUrl)2018 NS_IMETHODIMP nsImapIncomingServer::GetManageMailAccountUrl(
2019 nsACString& manageMailAccountUrl) {
2020 manageMailAccountUrl = m_manageMailAccountUrl;
2021 return NS_OK;
2022 }
2023
2024 NS_IMETHODIMP
StartPopulatingWithUri(nsIMsgWindow * aMsgWindow,bool aForceToServer,const nsACString & uri)2025 nsImapIncomingServer::StartPopulatingWithUri(nsIMsgWindow* aMsgWindow,
2026 bool aForceToServer /*ignored*/,
2027 const nsACString& uri) {
2028 nsresult rv;
2029 mDoingSubscribeDialog = true;
2030
2031 rv = EnsureInner();
2032 NS_ENSURE_SUCCESS(rv, rv);
2033 rv = mInner->StartPopulatingWithUri(aMsgWindow, aForceToServer, uri);
2034 NS_ENSURE_SUCCESS(rv, rv);
2035
2036 // imap always uses the canonical delimiter form of paths for subscribe ui.
2037 rv = SetDelimiter('/');
2038 NS_ENSURE_SUCCESS(rv, rv);
2039
2040 rv = SetShowFullName(false);
2041 NS_ENSURE_SUCCESS(rv, rv);
2042
2043 nsCString serverUri;
2044 rv = GetServerURI(serverUri);
2045 NS_ENSURE_SUCCESS(rv, rv);
2046
2047 nsCOMPtr<nsIImapService> imapService =
2048 do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
2049 NS_ENSURE_SUCCESS(rv, rv);
2050
2051 /*
2052 if uri = imap://user@host/foo/bar, the serverUri is imap://user@host
2053 to get path from uri, skip over imap://user@host + 1 (for the /)
2054 */
2055 return imapService->GetListOfFoldersWithPath(
2056 this, aMsgWindow, Substring(uri, serverUri.Length() + 1));
2057 }
2058
2059 NS_IMETHODIMP
StartPopulating(nsIMsgWindow * aMsgWindow,bool aForceToServer,bool aGetOnlyNew)2060 nsImapIncomingServer::StartPopulating(nsIMsgWindow* aMsgWindow,
2061 bool aForceToServer /*ignored*/,
2062 bool aGetOnlyNew) {
2063 nsresult rv;
2064 mDoingSubscribeDialog = true;
2065
2066 rv = EnsureInner();
2067 NS_ENSURE_SUCCESS(rv, rv);
2068 rv = mInner->StartPopulating(aMsgWindow, aForceToServer, aGetOnlyNew);
2069 NS_ENSURE_SUCCESS(rv, rv);
2070
2071 // imap always uses the canonical delimiter form of paths for subscribe ui.
2072 rv = SetDelimiter('/');
2073 NS_ENSURE_SUCCESS(rv, rv);
2074
2075 rv = SetShowFullName(false);
2076 NS_ENSURE_SUCCESS(rv, rv);
2077
2078 nsCOMPtr<nsIImapService> imapService =
2079 do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
2080 NS_ENSURE_SUCCESS(rv, rv);
2081 return imapService->GetListOfFoldersOnServer(this, aMsgWindow);
2082 }
2083
2084 NS_IMETHODIMP
OnStartRunningUrl(nsIURI * url)2085 nsImapIncomingServer::OnStartRunningUrl(nsIURI* url) { return NS_OK; }
2086
2087 NS_IMETHODIMP
OnStopRunningUrl(nsIURI * url,nsresult exitCode)2088 nsImapIncomingServer::OnStopRunningUrl(nsIURI* url, nsresult exitCode) {
2089 nsresult rv = exitCode;
2090
2091 // xxx todo get msgWindow from url
2092 nsCOMPtr<nsIMsgWindow> msgWindow;
2093 nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(url);
2094 if (imapUrl) {
2095 nsImapAction imapAction = nsIImapUrl::nsImapTest;
2096 imapUrl->GetImapAction(&imapAction);
2097 switch (imapAction) {
2098 case nsIImapUrl::nsImapDiscoverAllAndSubscribedBoxesUrl:
2099 case nsIImapUrl::nsImapDiscoverChildrenUrl:
2100 rv = UpdateSubscribed();
2101 NS_ENSURE_SUCCESS(rv, rv);
2102 mDoingSubscribeDialog = false;
2103 rv = StopPopulating(msgWindow);
2104 NS_ENSURE_SUCCESS(rv, rv);
2105 break;
2106 case nsIImapUrl::nsImapDiscoverAllBoxesUrl:
2107 if (NS_SUCCEEDED(exitCode)) DiscoveryDone();
2108 break;
2109 case nsIImapUrl::nsImapFolderStatus: {
2110 nsCOMPtr<nsIMsgFolder> msgFolder;
2111 nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(imapUrl);
2112 mailUrl->GetFolder(getter_AddRefs(msgFolder));
2113 if (msgFolder) {
2114 nsresult rv;
2115 nsCOMPtr<nsIMsgMailSession> session =
2116 do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
2117 NS_ENSURE_SUCCESS(rv, rv);
2118 bool folderOpen;
2119 rv = session->IsFolderOpenInWindow(msgFolder, &folderOpen);
2120 if (NS_SUCCEEDED(rv) && !folderOpen && msgFolder)
2121 msgFolder->SetMsgDatabase(nullptr);
2122 nsCOMPtr<nsIMsgImapMailFolder> imapFolder =
2123 do_QueryInterface(msgFolder);
2124 m_foldersToStat.RemoveObject(imapFolder);
2125 }
2126 // if we get an error running the url, it's better
2127 // not to chain the next url.
2128 if (NS_FAILED(exitCode) && exitCode != NS_MSG_ERROR_IMAP_COMMAND_FAILED)
2129 m_foldersToStat.Clear();
2130 if (m_foldersToStat.Count() > 0)
2131 m_foldersToStat[0]->UpdateStatus(this, nullptr);
2132 break;
2133 }
2134 default:
2135 break;
2136 }
2137 }
2138 return NS_OK;
2139 }
2140
2141 NS_IMETHODIMP
SetIncomingServer(nsIMsgIncomingServer * aServer)2142 nsImapIncomingServer::SetIncomingServer(nsIMsgIncomingServer* aServer) {
2143 nsresult rv = EnsureInner();
2144 NS_ENSURE_SUCCESS(rv, rv);
2145 return mInner->SetIncomingServer(aServer);
2146 }
2147
2148 NS_IMETHODIMP
SetShowFullName(bool showFullName)2149 nsImapIncomingServer::SetShowFullName(bool showFullName) {
2150 nsresult rv = EnsureInner();
2151 NS_ENSURE_SUCCESS(rv, rv);
2152 return mInner->SetShowFullName(showFullName);
2153 }
2154
2155 NS_IMETHODIMP
GetDelimiter(char * aDelimiter)2156 nsImapIncomingServer::GetDelimiter(char* aDelimiter) {
2157 nsresult rv = EnsureInner();
2158 NS_ENSURE_SUCCESS(rv, rv);
2159 return mInner->GetDelimiter(aDelimiter);
2160 }
2161
2162 NS_IMETHODIMP
SetDelimiter(char aDelimiter)2163 nsImapIncomingServer::SetDelimiter(char aDelimiter) {
2164 nsresult rv = EnsureInner();
2165 NS_ENSURE_SUCCESS(rv, rv);
2166 return mInner->SetDelimiter(aDelimiter);
2167 }
2168
2169 NS_IMETHODIMP
SetAsSubscribed(const nsACString & path)2170 nsImapIncomingServer::SetAsSubscribed(const nsACString& path) {
2171 nsresult rv = EnsureInner();
2172 NS_ENSURE_SUCCESS(rv, rv);
2173 return mInner->SetAsSubscribed(path);
2174 }
2175
2176 NS_IMETHODIMP
UpdateSubscribed()2177 nsImapIncomingServer::UpdateSubscribed() { return NS_OK; }
2178
2179 NS_IMETHODIMP
AddTo(const nsACString & aName,bool addAsSubscribed,bool aSubscribable,bool changeIfExists)2180 nsImapIncomingServer::AddTo(const nsACString& aName, bool addAsSubscribed,
2181 bool aSubscribable, bool changeIfExists) {
2182 nsresult rv = EnsureInner();
2183 NS_ENSURE_SUCCESS(rv, rv);
2184
2185 // RFC 3501 allows UTF-8 in addition to MUTF-7.
2186 // If it's not UTF-8, it's not 7bit-ASCII and cannot be MUTF-7 either.
2187 // We just ignore it.
2188 if (!mozilla::IsUtf8(aName)) return NS_OK;
2189 // Now handle subscription folder names as UTF-8 so don't convert to MUTF-7.
2190 return mInner->AddTo(aName, addAsSubscribed, aSubscribable, changeIfExists);
2191 }
2192
2193 NS_IMETHODIMP
StopPopulating(nsIMsgWindow * aMsgWindow)2194 nsImapIncomingServer::StopPopulating(nsIMsgWindow* aMsgWindow) {
2195 nsresult rv = EnsureInner();
2196 NS_ENSURE_SUCCESS(rv, rv);
2197 return mInner->StopPopulating(aMsgWindow);
2198 }
2199
2200 NS_IMETHODIMP
SubscribeCleanup()2201 nsImapIncomingServer::SubscribeCleanup() {
2202 m_subscribeFolders.Clear();
2203 return ClearInner();
2204 }
2205
2206 NS_IMETHODIMP
SetSubscribeListener(nsISubscribeListener * aListener)2207 nsImapIncomingServer::SetSubscribeListener(nsISubscribeListener* aListener) {
2208 nsresult rv = EnsureInner();
2209 NS_ENSURE_SUCCESS(rv, rv);
2210 return mInner->SetSubscribeListener(aListener);
2211 }
2212
2213 NS_IMETHODIMP
GetSubscribeListener(nsISubscribeListener ** aListener)2214 nsImapIncomingServer::GetSubscribeListener(nsISubscribeListener** aListener) {
2215 nsresult rv = EnsureInner();
2216 NS_ENSURE_SUCCESS(rv, rv);
2217 return mInner->GetSubscribeListener(aListener);
2218 }
2219
2220 NS_IMETHODIMP
Subscribe(const char16_t * aName)2221 nsImapIncomingServer::Subscribe(const char16_t* aName) {
2222 NS_ENSURE_ARG_POINTER(aName);
2223 return SubscribeToFolder(nsDependentString(aName), true, nullptr);
2224 }
2225
2226 NS_IMETHODIMP
Unsubscribe(const char16_t * aName)2227 nsImapIncomingServer::Unsubscribe(const char16_t* aName) {
2228 NS_ENSURE_ARG_POINTER(aName);
2229
2230 return SubscribeToFolder(nsDependentString(aName), false, nullptr);
2231 }
2232
2233 NS_IMETHODIMP
SubscribeToFolder(const nsAString & aName,bool subscribe,nsIURI ** aUri)2234 nsImapIncomingServer::SubscribeToFolder(const nsAString& aName, bool subscribe,
2235 nsIURI** aUri) {
2236 nsresult rv;
2237 nsCOMPtr<nsIImapService> imapService =
2238 do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
2239 NS_ENSURE_SUCCESS(rv, rv);
2240
2241 nsCOMPtr<nsIMsgFolder> rootMsgFolder;
2242 rv = GetRootFolder(getter_AddRefs(rootMsgFolder));
2243 NS_ENSURE_SUCCESS(rv, rv);
2244
2245 // Locate the folder so that the correct hierarchical delimiter is used in the
2246 // folder pathnames, otherwise root's (ie, '^') is used and this is wrong.
2247
2248 // aName is not a genuine UTF-16 but just a zero-padded MUTF-7.
2249 NS_ConvertUTF16toUTF8 folderCName(aName);
2250 nsCOMPtr<nsIMsgFolder> msgFolder;
2251 if (rootMsgFolder && !aName.IsEmpty())
2252 rv = rootMsgFolder->FindSubFolder(folderCName, getter_AddRefs(msgFolder));
2253
2254 nsCOMPtr<nsIThread> thread(do_GetCurrentThread());
2255
2256 if (subscribe)
2257 rv = imapService->SubscribeFolder(msgFolder, aName, nullptr, aUri);
2258 else
2259 rv = imapService->UnsubscribeFolder(msgFolder, aName, nullptr, nullptr);
2260
2261 return rv;
2262 }
2263
2264 NS_IMETHODIMP
SetDoingLsub(bool doingLsub)2265 nsImapIncomingServer::SetDoingLsub(bool doingLsub) {
2266 mDoingLsub = doingLsub;
2267 return NS_OK;
2268 }
2269
2270 NS_IMETHODIMP
GetDoingLsub(bool * doingLsub)2271 nsImapIncomingServer::GetDoingLsub(bool* doingLsub) {
2272 NS_ENSURE_ARG_POINTER(doingLsub);
2273 *doingLsub = mDoingLsub;
2274 return NS_OK;
2275 }
2276
2277 NS_IMETHODIMP
SetUtf8AcceptEnabled(bool enabled)2278 nsImapIncomingServer::SetUtf8AcceptEnabled(bool enabled) {
2279 mUtf8AcceptEnabled = enabled;
2280 return NS_OK;
2281 }
2282
2283 NS_IMETHODIMP
GetUtf8AcceptEnabled(bool * enabled)2284 nsImapIncomingServer::GetUtf8AcceptEnabled(bool* enabled) {
2285 NS_ENSURE_ARG_POINTER(enabled);
2286 *enabled = mUtf8AcceptEnabled;
2287 return NS_OK;
2288 }
2289
2290 NS_IMETHODIMP
ReDiscoverAllFolders()2291 nsImapIncomingServer::ReDiscoverAllFolders() { return PerformExpand(nullptr); }
2292
2293 NS_IMETHODIMP
SetState(const nsACString & path,bool state,bool * stateChanged)2294 nsImapIncomingServer::SetState(const nsACString& path, bool state,
2295 bool* stateChanged) {
2296 nsresult rv = EnsureInner();
2297 NS_ENSURE_SUCCESS(rv, rv);
2298 return mInner->SetState(path, state, stateChanged);
2299 }
2300
2301 NS_IMETHODIMP
HasChildren(const nsACString & path,bool * aHasChildren)2302 nsImapIncomingServer::HasChildren(const nsACString& path, bool* aHasChildren) {
2303 nsresult rv = EnsureInner();
2304 NS_ENSURE_SUCCESS(rv, rv);
2305 return mInner->HasChildren(path, aHasChildren);
2306 }
2307
2308 NS_IMETHODIMP
IsSubscribed(const nsACString & path,bool * aIsSubscribed)2309 nsImapIncomingServer::IsSubscribed(const nsACString& path,
2310 bool* aIsSubscribed) {
2311 nsresult rv = EnsureInner();
2312 NS_ENSURE_SUCCESS(rv, rv);
2313 return mInner->IsSubscribed(path, aIsSubscribed);
2314 }
2315
2316 NS_IMETHODIMP
IsSubscribable(const nsACString & path,bool * aIsSubscribable)2317 nsImapIncomingServer::IsSubscribable(const nsACString& path,
2318 bool* aIsSubscribable) {
2319 nsresult rv = EnsureInner();
2320 NS_ENSURE_SUCCESS(rv, rv);
2321 return mInner->IsSubscribable(path, aIsSubscribable);
2322 }
2323
2324 NS_IMETHODIMP
GetLeafName(const nsACString & path,nsAString & aLeafName)2325 nsImapIncomingServer::GetLeafName(const nsACString& path,
2326 nsAString& aLeafName) {
2327 nsresult rv = EnsureInner();
2328 NS_ENSURE_SUCCESS(rv, rv);
2329 return mInner->GetLeafName(path, aLeafName);
2330 }
2331
2332 NS_IMETHODIMP
GetFirstChildURI(const nsACString & path,nsACString & aResult)2333 nsImapIncomingServer::GetFirstChildURI(const nsACString& path,
2334 nsACString& aResult) {
2335 nsresult rv = EnsureInner();
2336 NS_ENSURE_SUCCESS(rv, rv);
2337 return mInner->GetFirstChildURI(path, aResult);
2338 }
2339
2340 NS_IMETHODIMP
GetChildURIs(const nsACString & aPath,nsTArray<nsCString> & aResult)2341 nsImapIncomingServer::GetChildURIs(const nsACString& aPath,
2342 nsTArray<nsCString>& aResult) {
2343 nsresult rv = EnsureInner();
2344 NS_ENSURE_SUCCESS(rv, rv);
2345 return mInner->GetChildURIs(aPath, aResult);
2346 }
2347
EnsureInner()2348 nsresult nsImapIncomingServer::EnsureInner() {
2349 nsresult rv = NS_OK;
2350
2351 if (mInner) return NS_OK;
2352
2353 mInner = do_CreateInstance(kSubscribableServerCID, &rv);
2354 NS_ENSURE_SUCCESS(rv, rv);
2355 return SetIncomingServer(this);
2356 }
2357
ClearInner()2358 nsresult nsImapIncomingServer::ClearInner() {
2359 nsresult rv = NS_OK;
2360 if (mInner) {
2361 rv = mInner->SetSubscribeListener(nullptr);
2362 NS_ENSURE_SUCCESS(rv, rv);
2363 rv = mInner->SetIncomingServer(nullptr);
2364 NS_ENSURE_SUCCESS(rv, rv);
2365 mInner = nullptr;
2366 }
2367 return NS_OK;
2368 }
2369
2370 NS_IMETHODIMP
CommitSubscribeChanges()2371 nsImapIncomingServer::CommitSubscribeChanges() {
2372 return ReDiscoverAllFolders();
2373 }
2374
2375 NS_IMETHODIMP
GetCanBeDefaultServer(bool * canBeDefaultServer)2376 nsImapIncomingServer::GetCanBeDefaultServer(bool* canBeDefaultServer) {
2377 NS_ENSURE_ARG_POINTER(canBeDefaultServer);
2378 *canBeDefaultServer = true;
2379 return NS_OK;
2380 }
2381
2382 NS_IMETHODIMP
GetCanCompactFoldersOnServer(bool * canCompactFoldersOnServer)2383 nsImapIncomingServer::GetCanCompactFoldersOnServer(
2384 bool* canCompactFoldersOnServer) {
2385 NS_ENSURE_ARG_POINTER(canCompactFoldersOnServer);
2386 // Initialize canCompactFoldersOnServer true, a default value for IMAP
2387 *canCompactFoldersOnServer = true;
2388 GetPrefForServerAttribute("canCompactFoldersOnServer",
2389 canCompactFoldersOnServer);
2390 return NS_OK;
2391 }
2392
2393 NS_IMETHODIMP
GetCanUndoDeleteOnServer(bool * canUndoDeleteOnServer)2394 nsImapIncomingServer::GetCanUndoDeleteOnServer(bool* canUndoDeleteOnServer) {
2395 NS_ENSURE_ARG_POINTER(canUndoDeleteOnServer);
2396 // Initialize canUndoDeleteOnServer true, a default value for IMAP
2397 *canUndoDeleteOnServer = true;
2398 GetPrefForServerAttribute("canUndoDeleteOnServer", canUndoDeleteOnServer);
2399 return NS_OK;
2400 }
2401
2402 NS_IMETHODIMP
GetCanSearchMessages(bool * canSearchMessages)2403 nsImapIncomingServer::GetCanSearchMessages(bool* canSearchMessages) {
2404 NS_ENSURE_ARG_POINTER(canSearchMessages);
2405 // Initialize canSearchMessages true, a default value for IMAP
2406 *canSearchMessages = true;
2407 GetPrefForServerAttribute("canSearchMessages", canSearchMessages);
2408 return NS_OK;
2409 }
2410
2411 NS_IMETHODIMP
GetCanEmptyTrashOnExit(bool * canEmptyTrashOnExit)2412 nsImapIncomingServer::GetCanEmptyTrashOnExit(bool* canEmptyTrashOnExit) {
2413 NS_ENSURE_ARG_POINTER(canEmptyTrashOnExit);
2414 // Initialize canEmptyTrashOnExit true, a default value for IMAP
2415 *canEmptyTrashOnExit = true;
2416 GetPrefForServerAttribute("canEmptyTrashOnExit", canEmptyTrashOnExit);
2417 return NS_OK;
2418 }
2419
CreateHostSpecificPrefName(const char * prefPrefix,nsAutoCString & prefName)2420 nsresult nsImapIncomingServer::CreateHostSpecificPrefName(
2421 const char* prefPrefix, nsAutoCString& prefName) {
2422 NS_ENSURE_ARG_POINTER(prefPrefix);
2423
2424 nsCString hostName;
2425 nsresult rv = GetHostName(hostName);
2426 NS_ENSURE_SUCCESS(rv, rv);
2427
2428 prefName = prefPrefix;
2429 prefName.Append('.');
2430 prefName.Append(hostName);
2431 return NS_OK;
2432 }
2433
2434 NS_IMETHODIMP
GetSupportsDiskSpace(bool * aSupportsDiskSpace)2435 nsImapIncomingServer::GetSupportsDiskSpace(bool* aSupportsDiskSpace) {
2436 NS_ENSURE_ARG_POINTER(aSupportsDiskSpace);
2437 nsAutoCString prefName;
2438 nsresult rv =
2439 CreateHostSpecificPrefName("default_supports_diskspace", prefName);
2440 NS_ENSURE_SUCCESS(rv, rv);
2441
2442 nsCOMPtr<nsIPrefBranch> prefBranch =
2443 do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2444 if (NS_SUCCEEDED(rv))
2445 rv = prefBranch->GetBoolPref(prefName.get(), aSupportsDiskSpace);
2446
2447 // Couldn't get the default value with the hostname.
2448 // Fall back on IMAP default value
2449 if (NS_FAILED(rv)) // set default value
2450 *aSupportsDiskSpace = true;
2451 return NS_OK;
2452 }
2453
2454 // count number of non-busy connections in cache
2455 NS_IMETHODIMP
GetNumIdleConnections(int32_t * aNumIdleConnections)2456 nsImapIncomingServer::GetNumIdleConnections(int32_t* aNumIdleConnections) {
2457 NS_ENSURE_ARG_POINTER(aNumIdleConnections);
2458 *aNumIdleConnections = 0;
2459
2460 nsresult rv = NS_OK;
2461 nsCOMPtr<nsIImapProtocol> connection;
2462 bool isBusy = false;
2463 bool isInboxConnection;
2464 PR_CEnterMonitor(this);
2465
2466 int32_t cnt = m_connectionCache.Count();
2467
2468 // loop counting idle connections
2469 for (int32_t i = 0; i < cnt; ++i) {
2470 connection = m_connectionCache[i];
2471 if (connection) {
2472 rv = connection->IsBusy(&isBusy, &isInboxConnection);
2473 if (NS_FAILED(rv)) continue;
2474 if (!isBusy) (*aNumIdleConnections)++;
2475 }
2476 }
2477 PR_CExitMonitor(this);
2478 return rv;
2479 }
2480
2481 /**
2482 * Get the preference that tells us whether the imap server in question allows
2483 * us to create subfolders. Some ISPs might not want users to create any folders
2484 * besides the existing ones.
2485 * We do want to identify all those servers that don't allow creation of
2486 * subfolders and take them out of the account picker in the Copies and Folder
2487 * panel.
2488 */
2489 NS_IMETHODIMP
GetCanCreateFoldersOnServer(bool * aCanCreateFoldersOnServer)2490 nsImapIncomingServer::GetCanCreateFoldersOnServer(
2491 bool* aCanCreateFoldersOnServer) {
2492 NS_ENSURE_ARG_POINTER(aCanCreateFoldersOnServer);
2493 // Initialize aCanCreateFoldersOnServer true, a default value for IMAP
2494 *aCanCreateFoldersOnServer = true;
2495 GetPrefForServerAttribute("canCreateFolders", aCanCreateFoldersOnServer);
2496 return NS_OK;
2497 }
2498
2499 NS_IMETHODIMP
GetOfflineSupportLevel(int32_t * aSupportLevel)2500 nsImapIncomingServer::GetOfflineSupportLevel(int32_t* aSupportLevel) {
2501 NS_ENSURE_ARG_POINTER(aSupportLevel);
2502 nsresult rv = NS_OK;
2503
2504 rv = GetIntValue("offline_support_level", aSupportLevel);
2505 if (*aSupportLevel != OFFLINE_SUPPORT_LEVEL_UNDEFINED) return rv;
2506
2507 nsAutoCString prefName;
2508 rv = CreateHostSpecificPrefName("default_offline_support_level", prefName);
2509 NS_ENSURE_SUCCESS(rv, rv);
2510
2511 nsCOMPtr<nsIPrefBranch> prefBranch =
2512 do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2513 if (NS_SUCCEEDED(rv))
2514 rv = prefBranch->GetIntPref(prefName.get(), aSupportLevel);
2515
2516 // Couldn't get the pref value with the hostname.
2517 // Fall back on IMAP default value
2518 if (NS_FAILED(rv)) // set default value
2519 *aSupportLevel = OFFLINE_SUPPORT_LEVEL_REGULAR;
2520 return NS_OK;
2521 }
2522
2523 // Called only during the migration process. This routine enables the generation
2524 // of unique account name based on the username, hostname and the port. If the
2525 // port is valid and not a default one, it will be appended to the account name.
2526 NS_IMETHODIMP
GeneratePrettyNameForMigration(nsAString & aPrettyName)2527 nsImapIncomingServer::GeneratePrettyNameForMigration(nsAString& aPrettyName) {
2528 nsCString userName;
2529 nsCString hostName;
2530
2531 /**
2532 * Pretty name for migrated account is of format username@hostname:<port>,
2533 * provided the port is valid and not the default
2534 */
2535 // Get user name to construct pretty name
2536 nsresult rv = GetUsername(userName);
2537 NS_ENSURE_SUCCESS(rv, rv);
2538
2539 // Get host name to construct pretty name
2540 rv = GetHostName(hostName);
2541 NS_ENSURE_SUCCESS(rv, rv);
2542
2543 int32_t defaultServerPort;
2544 int32_t defaultSecureServerPort;
2545
2546 // Here, the final contract ID is already known, so use it directly for
2547 // efficiency.
2548 nsCOMPtr<nsIMsgProtocolInfo> protocolInfo =
2549 do_GetService(NS_IMAPPROTOCOLINFO_CONTRACTID, &rv);
2550 NS_ENSURE_SUCCESS(rv, rv);
2551
2552 // Get the default port
2553 rv = protocolInfo->GetDefaultServerPort(false, &defaultServerPort);
2554 NS_ENSURE_SUCCESS(rv, rv);
2555
2556 // Get the default secure port
2557 rv = protocolInfo->GetDefaultServerPort(true, &defaultSecureServerPort);
2558 NS_ENSURE_SUCCESS(rv, rv);
2559
2560 // Get the current server port
2561 int32_t serverPort = PORT_NOT_SET;
2562 rv = GetPort(&serverPort);
2563 NS_ENSURE_SUCCESS(rv, rv);
2564
2565 // Is the server secure ?
2566 int32_t socketType;
2567 rv = GetSocketType(&socketType);
2568 NS_ENSURE_SUCCESS(rv, rv);
2569 bool isSecure = (socketType == nsMsgSocketType::SSL);
2570
2571 // Is server port a default port ?
2572 bool isItDefaultPort = false;
2573 if (((serverPort == defaultServerPort) && !isSecure) ||
2574 ((serverPort == defaultSecureServerPort) && isSecure))
2575 isItDefaultPort = true;
2576
2577 // Construct pretty name from username and hostname
2578 nsAutoString constructedPrettyName;
2579 CopyASCIItoUTF16(userName, constructedPrettyName);
2580 constructedPrettyName.Append('@');
2581 constructedPrettyName.Append(NS_ConvertASCIItoUTF16(hostName));
2582
2583 // If the port is valid and not default, add port value to the pretty name
2584 if ((serverPort > 0) && (!isItDefaultPort)) {
2585 constructedPrettyName.Append(':');
2586 constructedPrettyName.AppendInt(serverPort);
2587 }
2588
2589 // Format the pretty name
2590 return GetFormattedStringFromName(constructedPrettyName,
2591 "imapDefaultAccountName", aPrettyName);
2592 }
2593
GetFormattedStringFromName(const nsAString & aValue,const char * aName,nsAString & aResult)2594 nsresult nsImapIncomingServer::GetFormattedStringFromName(
2595 const nsAString& aValue, const char* aName, nsAString& aResult) {
2596 nsresult rv = GetStringBundle();
2597 if (m_stringBundle) {
2598 nsString tmpVal(aValue);
2599 AutoTArray<nsString, 1> formatStrings = {tmpVal};
2600
2601 nsString result;
2602 rv = m_stringBundle->FormatStringFromName(aName, formatStrings, result);
2603 aResult.Assign(result);
2604 }
2605 return rv;
2606 }
2607
GetPrefForServerAttribute(const char * prefSuffix,bool * prefValue)2608 nsresult nsImapIncomingServer::GetPrefForServerAttribute(const char* prefSuffix,
2609 bool* prefValue) {
2610 // Any caller of this function must initialize prefValue with a default value
2611 // as this code will not set prefValue when the pref does not exist and return
2612 // NS_OK anyway
2613
2614 if (!mPrefBranch) return NS_ERROR_NOT_INITIALIZED;
2615
2616 NS_ENSURE_ARG_POINTER(prefValue);
2617
2618 if (NS_FAILED(mPrefBranch->GetBoolPref(prefSuffix, prefValue)))
2619 mDefPrefBranch->GetBoolPref(prefSuffix, prefValue);
2620
2621 return NS_OK;
2622 }
2623
2624 NS_IMETHODIMP
GetCanFileMessagesOnServer(bool * aCanFileMessagesOnServer)2625 nsImapIncomingServer::GetCanFileMessagesOnServer(
2626 bool* aCanFileMessagesOnServer) {
2627 NS_ENSURE_ARG_POINTER(aCanFileMessagesOnServer);
2628 // Initialize aCanFileMessagesOnServer true, a default value for IMAP
2629 *aCanFileMessagesOnServer = true;
2630 GetPrefForServerAttribute("canFileMessages", aCanFileMessagesOnServer);
2631 return NS_OK;
2632 }
2633
2634 NS_IMETHODIMP
SetSearchValue(const nsAString & searchValue)2635 nsImapIncomingServer::SetSearchValue(const nsAString& searchValue) {
2636 return NS_ERROR_NOT_IMPLEMENTED;
2637 }
2638
2639 NS_IMETHODIMP
GetSupportsSubscribeSearch(bool * retVal)2640 nsImapIncomingServer::GetSupportsSubscribeSearch(bool* retVal) {
2641 NS_ENSURE_ARG_POINTER(retVal);
2642 *retVal = false;
2643 return NS_OK;
2644 }
2645
2646 NS_IMETHODIMP
GetFolderView(nsITreeView ** aView)2647 nsImapIncomingServer::GetFolderView(nsITreeView** aView) {
2648 nsresult rv = EnsureInner();
2649 NS_ENSURE_SUCCESS(rv, rv);
2650 return mInner->GetFolderView(aView);
2651 }
2652
2653 NS_IMETHODIMP
GetFilterScope(nsMsgSearchScopeValue * filterScope)2654 nsImapIncomingServer::GetFilterScope(nsMsgSearchScopeValue* filterScope) {
2655 NS_ENSURE_ARG_POINTER(filterScope);
2656 // If the inbox is enabled for offline use, then use the offline filter
2657 // scope, else use the online filter scope.
2658 //
2659 // XXX We use the same scope for all folders with the same incoming server,
2660 // yet it is possible to set the offline flag separately for each folder.
2661 // Manual filters could perhaps check the offline status of each folder,
2662 // though it's hard to see how to make that work since we only store filters
2663 // per server.
2664 //
2665 nsCOMPtr<nsIMsgFolder> rootMsgFolder;
2666 nsresult rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
2667 NS_ENSURE_SUCCESS(rv, rv);
2668 nsCOMPtr<nsIMsgFolder> offlineInboxMsgFolder;
2669 rv = rootMsgFolder->GetFolderWithFlags(
2670 nsMsgFolderFlags::Inbox | nsMsgFolderFlags::Offline,
2671 getter_AddRefs(offlineInboxMsgFolder));
2672
2673 *filterScope = offlineInboxMsgFolder ? nsMsgSearchScope::offlineMailFilter
2674 : nsMsgSearchScope::onlineMailFilter;
2675 return NS_OK;
2676 }
2677
2678 NS_IMETHODIMP
GetSearchScope(nsMsgSearchScopeValue * searchScope)2679 nsImapIncomingServer::GetSearchScope(nsMsgSearchScopeValue* searchScope) {
2680 NS_ENSURE_ARG_POINTER(searchScope);
2681 *searchScope = WeAreOffline() ? nsMsgSearchScope::offlineMail
2682 : nsMsgSearchScope::onlineMail;
2683 return NS_OK;
2684 }
2685
2686 // This is a recursive function. It gets new messages for current folder
2687 // first if it is marked, then calls itself recursively for each subfolder.
2688 NS_IMETHODIMP
GetNewMessagesForNonInboxFolders(nsIMsgFolder * aFolder,nsIMsgWindow * aWindow,bool forceAllFolders,bool performingBiff)2689 nsImapIncomingServer::GetNewMessagesForNonInboxFolders(nsIMsgFolder* aFolder,
2690 nsIMsgWindow* aWindow,
2691 bool forceAllFolders,
2692 bool performingBiff) {
2693 NS_ENSURE_ARG_POINTER(aFolder);
2694 static bool gGotStatusPref = false;
2695 static bool gUseStatus = false;
2696
2697 bool isServer;
2698 (void)aFolder->GetIsServer(&isServer);
2699 // Check this folder for new messages if it is marked to be checked
2700 // or if we are forced to check all folders
2701 uint32_t flags = 0;
2702 aFolder->GetFlags(&flags);
2703 nsresult rv;
2704 nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aFolder, &rv);
2705 NS_ENSURE_SUCCESS(rv, rv);
2706 bool canOpen;
2707 imapFolder->GetCanOpenFolder(&canOpen);
2708 if (canOpen &&
2709 ((forceAllFolders &&
2710 !(flags & (nsMsgFolderFlags::Inbox | nsMsgFolderFlags::Trash |
2711 nsMsgFolderFlags::Junk | nsMsgFolderFlags::Virtual))) ||
2712 flags & nsMsgFolderFlags::CheckNew)) {
2713 // Get new messages for this folder.
2714 aFolder->SetGettingNewMessages(true);
2715 if (performingBiff) imapFolder->SetPerformingBiff(true);
2716 bool isOpen = false;
2717 nsCOMPtr<nsIMsgMailSession> mailSession =
2718 do_GetService(NS_MSGMAILSESSION_CONTRACTID);
2719 if (mailSession && aFolder)
2720 mailSession->IsFolderOpenInWindow(aFolder, &isOpen);
2721 // eventually, the gGotStatusPref should go away, once we work out the kinks
2722 // from using STATUS.
2723 if (!gGotStatusPref) {
2724 nsCOMPtr<nsIPrefBranch> prefBranch =
2725 do_GetService(NS_PREFSERVICE_CONTRACTID);
2726 if (prefBranch)
2727 prefBranch->GetBoolPref("mail.imap.use_status_for_biff", &gUseStatus);
2728 gGotStatusPref = true;
2729 }
2730 if (gUseStatus && !isOpen) {
2731 if (!isServer && m_foldersToStat.IndexOf(imapFolder) == -1)
2732 m_foldersToStat.AppendObject(imapFolder);
2733 } else
2734 aFolder->UpdateFolder(aWindow);
2735 }
2736
2737 // Loop through all subfolders to get new messages for them.
2738 nsTArray<RefPtr<nsIMsgFolder>> subFolders;
2739 rv = aFolder->GetSubFolders(subFolders);
2740 NS_ENSURE_SUCCESS(rv, rv);
2741 for (nsIMsgFolder* msgFolder : subFolders) {
2742 GetNewMessagesForNonInboxFolders(msgFolder, aWindow, forceAllFolders,
2743 performingBiff);
2744 }
2745 if (isServer && m_foldersToStat.Count() > 0)
2746 m_foldersToStat[0]->UpdateStatus(this, nullptr);
2747 return NS_OK;
2748 }
2749
2750 NS_IMETHODIMP
GetArbitraryHeaders(nsACString & aResult)2751 nsImapIncomingServer::GetArbitraryHeaders(nsACString& aResult) {
2752 nsCOMPtr<nsIMsgFilterList> filterList;
2753 nsresult rv = GetFilterList(nullptr, getter_AddRefs(filterList));
2754 NS_ENSURE_SUCCESS(rv, rv);
2755 return filterList->GetArbitraryHeaders(aResult);
2756 }
2757
2758 NS_IMETHODIMP
GetShowAttachmentsInline(bool * aResult)2759 nsImapIncomingServer::GetShowAttachmentsInline(bool* aResult) {
2760 NS_ENSURE_ARG_POINTER(aResult);
2761 *aResult = true; // true per default
2762 nsresult rv;
2763 nsCOMPtr<nsIPrefBranch> prefBranch =
2764 do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2765 NS_ENSURE_SUCCESS(rv, rv);
2766
2767 prefBranch->GetBoolPref("mail.inline_attachments", aResult);
2768 return NS_OK; // In case this pref is not set we need to return NS_OK.
2769 }
2770
SetSocketType(int32_t aSocketType)2771 NS_IMETHODIMP nsImapIncomingServer::SetSocketType(int32_t aSocketType) {
2772 int32_t oldSocketType;
2773 nsresult rv = GetSocketType(&oldSocketType);
2774 if (NS_SUCCEEDED(rv) && oldSocketType != aSocketType)
2775 CloseCachedConnections();
2776 return nsMsgIncomingServer::SetSocketType(aSocketType);
2777 }
2778
2779 NS_IMETHODIMP
OnUserOrHostNameChanged(const nsACString & oldName,const nsACString & newName,bool hostnameChanged)2780 nsImapIncomingServer::OnUserOrHostNameChanged(const nsACString& oldName,
2781 const nsACString& newName,
2782 bool hostnameChanged) {
2783 nsresult rv;
2784 // 1. Do common things in the base class.
2785 rv = nsMsgIncomingServer::OnUserOrHostNameChanged(oldName, newName,
2786 hostnameChanged);
2787 NS_ENSURE_SUCCESS(rv, rv);
2788
2789 // 2. Reset 'HaveWeEverDiscoveredFolders' flag so the new folder list can be
2790 // reloaded (ie, DiscoverMailboxList() will be invoked in nsImapProtocol).
2791 nsCOMPtr<nsIImapHostSessionList> hostSessionList =
2792 do_GetService(kCImapHostSessionListCID, &rv);
2793 NS_ENSURE_SUCCESS(rv, rv);
2794 nsAutoCString serverKey;
2795 rv = GetKey(serverKey);
2796 NS_ENSURE_SUCCESS(rv, rv);
2797 hostSessionList->SetHaveWeEverDiscoveredFoldersForHost(serverKey.get(),
2798 false);
2799 // 3. Make all the existing folders 'unverified' so that they can be
2800 // removed from the folder pane after users log into the new server.
2801 ResetFoldersToUnverified(nullptr);
2802 return NS_OK;
2803 }
2804
2805 // use canonical format in originalUri & convertedUri
2806 NS_IMETHODIMP
GetUriWithNamespacePrefixIfNecessary(int32_t namespaceType,const nsACString & originalUri,nsACString & convertedUri)2807 nsImapIncomingServer::GetUriWithNamespacePrefixIfNecessary(
2808 int32_t namespaceType, const nsACString& originalUri,
2809 nsACString& convertedUri) {
2810 nsresult rv = NS_OK;
2811 nsAutoCString serverKey;
2812 rv = GetKey(serverKey);
2813 NS_ENSURE_SUCCESS(rv, rv);
2814 nsCOMPtr<nsIImapHostSessionList> hostSessionList =
2815 do_GetService(kCImapHostSessionListCID, &rv);
2816 nsImapNamespace* ns = nullptr;
2817 rv = hostSessionList->GetDefaultNamespaceOfTypeForHost(
2818 serverKey.get(), (EIMAPNamespaceType)namespaceType, ns);
2819 if (ns) {
2820 nsAutoCString namespacePrefix(ns->GetPrefix());
2821 if (!namespacePrefix.IsEmpty()) {
2822 // check if namespacePrefix is the same as the online directory; if so,
2823 // ignore it.
2824 nsAutoCString onlineDir;
2825 rv = GetServerDirectory(onlineDir);
2826 NS_ENSURE_SUCCESS(rv, rv);
2827 if (!onlineDir.IsEmpty()) {
2828 char delimiter = ns->GetDelimiter();
2829 if (onlineDir.Last() != delimiter) onlineDir += delimiter;
2830 if (onlineDir.Equals(namespacePrefix)) return NS_OK;
2831 }
2832
2833 namespacePrefix.ReplaceChar(ns->GetDelimiter(),
2834 '/'); // use canonical format
2835 nsCString uri(originalUri);
2836 int32_t index = uri.Find("//"); // find scheme
2837 index = uri.FindChar('/', index + 2); // find '/' after scheme
2838 // it may be the case that this is the INBOX uri, in which case
2839 // we don't want to prepend the namespace. In that case, the uri ends with
2840 // "INBOX", but the namespace is "INBOX/", so they don't match.
2841 if (uri.Find(namespacePrefix, false, index + 1) != index + 1 &&
2842 !Substring(uri, index + 1).LowerCaseEqualsLiteral("inbox"))
2843 uri.Insert(namespacePrefix, index + 1); // insert namespace prefix
2844 convertedUri = uri;
2845 }
2846 }
2847 return rv;
2848 }
2849
GetTrashFolderName(nsAString & retval)2850 NS_IMETHODIMP nsImapIncomingServer::GetTrashFolderName(nsAString& retval) {
2851 // Despite its name, this returns a path, for example INBOX/Trash.
2852 nsresult rv = GetUnicharValue(PREF_TRASH_FOLDER_PATH, retval);
2853 if (NS_FAILED(rv)) return rv;
2854 if (retval.IsEmpty())
2855 retval = NS_LITERAL_STRING_FROM_CSTRING(DEFAULT_TRASH_FOLDER_PATH);
2856 return NS_OK;
2857 }
2858
SetTrashFolderName(const nsAString & chvalue)2859 NS_IMETHODIMP nsImapIncomingServer::SetTrashFolderName(
2860 const nsAString& chvalue) {
2861 // Clear trash flag from the old pref.
2862 // Despite its name, this returns the trash folder path, for example
2863 // INBOX/Trash.
2864 bool useUTF8 = false;
2865 GetUtf8AcceptEnabled(&useUTF8);
2866 nsAutoString oldTrashName;
2867 nsresult rv = GetTrashFolderName(oldTrashName);
2868 if (NS_SUCCEEDED(rv)) {
2869 nsAutoCString oldTrashNameUtf7or8;
2870 nsCOMPtr<nsIMsgFolder> oldFolder;
2871 // 'trashFolderName' being a path here works well since this is appended
2872 // to the server's root folder in GetFolder().
2873 if (useUTF8) {
2874 CopyUTF16toUTF8(oldTrashName, oldTrashNameUtf7or8);
2875 } else {
2876 CopyUTF16toMUTF7(oldTrashName, oldTrashNameUtf7or8);
2877 }
2878 rv = GetFolder(oldTrashNameUtf7or8, getter_AddRefs(oldFolder));
2879 if (NS_SUCCEEDED(rv) && oldFolder)
2880 oldFolder->ClearFlag(nsMsgFolderFlags::Trash);
2881 }
2882
2883 // If the user configured delete mode (model) is currently "move to trash",
2884 // mark the newly designated trash folder name as the active trash
2885 // destination folder.
2886 int32_t deleteModel;
2887 rv = GetDeleteModel(&deleteModel);
2888 if (NS_SUCCEEDED(rv) && (deleteModel == nsMsgImapDeleteModels::MoveToTrash)) {
2889 nsAutoCString newTrashNameUtf7or8;
2890 if (useUTF8) {
2891 CopyUTF16toUTF8(PromiseFlatString(chvalue), newTrashNameUtf7or8);
2892 } else {
2893 CopyUTF16toMUTF7(PromiseFlatString(chvalue), newTrashNameUtf7or8);
2894 }
2895 nsCOMPtr<nsIMsgFolder> newTrashFolder;
2896 rv = GetFolder(newTrashNameUtf7or8, getter_AddRefs(newTrashFolder));
2897 if (NS_SUCCEEDED(rv) && newTrashFolder)
2898 newTrashFolder->SetFlag(nsMsgFolderFlags::Trash);
2899 }
2900
2901 return SetUnicharValue(PREF_TRASH_FOLDER_PATH, chvalue);
2902 }
2903
2904 NS_IMETHODIMP
GetMsgFolderFromURI(nsIMsgFolder * aFolderResource,const nsACString & aURI,nsIMsgFolder ** aFolder)2905 nsImapIncomingServer::GetMsgFolderFromURI(nsIMsgFolder* aFolderResource,
2906 const nsACString& aURI,
2907 nsIMsgFolder** aFolder) {
2908 nsCOMPtr<nsIMsgFolder> msgFolder;
2909 bool namespacePrefixAdded = false;
2910 nsCString folderUriWithNamespace;
2911
2912 // clang-format off
2913 // Check if the folder exists as is...
2914 nsresult rv = GetExistingMsgFolder(aURI, folderUriWithNamespace,
2915 namespacePrefixAdded, false,
2916 getter_AddRefs(msgFolder));
2917
2918 // Or try again with a case-insensitive lookup
2919 if (NS_FAILED(rv) || !msgFolder)
2920 rv = GetExistingMsgFolder(aURI, folderUriWithNamespace,
2921 namespacePrefixAdded, true,
2922 getter_AddRefs(msgFolder));
2923 // clang-format on
2924
2925 if (NS_FAILED(rv) || !msgFolder) {
2926 // we didn't find the folder so we will have to create a new one.
2927 if (namespacePrefixAdded) {
2928 nsCOMPtr<nsIMsgFolder> folder;
2929 rv = GetOrCreateFolder(folderUriWithNamespace, getter_AddRefs(folder));
2930 NS_ENSURE_SUCCESS(rv, rv);
2931 msgFolder = folder;
2932 } else
2933 msgFolder = aFolderResource;
2934 }
2935
2936 msgFolder.forget(aFolder);
2937 return (aFolder ? NS_OK : NS_ERROR_FAILURE);
2938 }
2939
GetExistingMsgFolder(const nsACString & aURI,nsACString & aFolderUriWithNamespace,bool & aNamespacePrefixAdded,bool aCaseInsensitive,nsIMsgFolder ** aFolder)2940 nsresult nsImapIncomingServer::GetExistingMsgFolder(
2941 const nsACString& aURI, nsACString& aFolderUriWithNamespace,
2942 bool& aNamespacePrefixAdded, bool aCaseInsensitive,
2943 nsIMsgFolder** aFolder) {
2944 nsCOMPtr<nsIMsgFolder> rootMsgFolder;
2945 nsresult rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
2946 NS_ENSURE_SUCCESS(rv, rv);
2947
2948 aNamespacePrefixAdded = false;
2949 // Check if the folder exists as is...Even if we have a personal namespace,
2950 // it might be in another namespace (e.g., shared) and this will catch that.
2951 rv = rootMsgFolder->GetChildWithURI(aURI, true, aCaseInsensitive, aFolder);
2952
2953 // If we couldn't find the folder as is, check if we need to prepend the
2954 // personal namespace
2955 if (!*aFolder) {
2956 GetUriWithNamespacePrefixIfNecessary(kPersonalNamespace, aURI,
2957 aFolderUriWithNamespace);
2958 if (!aFolderUriWithNamespace.IsEmpty()) {
2959 aNamespacePrefixAdded = true;
2960 rv = rootMsgFolder->GetChildWithURI(aFolderUriWithNamespace, true,
2961 aCaseInsensitive, aFolder);
2962 }
2963 }
2964 return rv;
2965 }
2966
2967 NS_IMETHODIMP
CramMD5Hash(const char * decodedChallenge,const char * key,char ** result)2968 nsImapIncomingServer::CramMD5Hash(const char* decodedChallenge, const char* key,
2969 char** result) {
2970 NS_ENSURE_ARG_POINTER(decodedChallenge);
2971 NS_ENSURE_ARG_POINTER(key);
2972
2973 unsigned char resultDigest[DIGEST_LENGTH];
2974 nsresult rv = MSGCramMD5(decodedChallenge, strlen(decodedChallenge), key,
2975 strlen(key), resultDigest);
2976 NS_ENSURE_SUCCESS(rv, rv);
2977 *result = (char*)malloc(DIGEST_LENGTH);
2978 if (*result) memcpy(*result, resultDigest, DIGEST_LENGTH);
2979 return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
2980 }
2981
2982 NS_IMETHODIMP
GetLoginUsername(nsACString & aLoginUsername)2983 nsImapIncomingServer::GetLoginUsername(nsACString& aLoginUsername) {
2984 return GetRealUsername(aLoginUsername);
2985 }
2986
2987 NS_IMETHODIMP
GetOriginalUsername(nsACString & aUsername)2988 nsImapIncomingServer::GetOriginalUsername(nsACString& aUsername) {
2989 return GetUsername(aUsername);
2990 }
2991
2992 NS_IMETHODIMP
GetServerKey(nsACString & aServerKey)2993 nsImapIncomingServer::GetServerKey(nsACString& aServerKey) {
2994 return GetKey(aServerKey);
2995 }
2996
2997 NS_IMETHODIMP
GetServerPassword(nsAString & aPassword)2998 nsImapIncomingServer::GetServerPassword(nsAString& aPassword) {
2999 return GetPassword(aPassword);
3000 }
3001
3002 NS_IMETHODIMP
RemoveServerConnection(nsIImapProtocol * aProtocol)3003 nsImapIncomingServer::RemoveServerConnection(nsIImapProtocol* aProtocol) {
3004 return RemoveConnection(aProtocol);
3005 }
3006
3007 NS_IMETHODIMP
GetServerShuttingDown(bool * aShuttingDown)3008 nsImapIncomingServer::GetServerShuttingDown(bool* aShuttingDown) {
3009 return GetShuttingDown(aShuttingDown);
3010 }
3011
3012 NS_IMETHODIMP
ResetServerConnection(const nsACString & aFolderName)3013 nsImapIncomingServer::ResetServerConnection(const nsACString& aFolderName) {
3014 return ResetConnection(aFolderName);
3015 }
3016
3017 NS_IMETHODIMP
SetServerForceSelect(const nsACString & aForceSelect)3018 nsImapIncomingServer::SetServerForceSelect(const nsACString& aForceSelect) {
3019 return SetForceSelect(aForceSelect);
3020 }
3021
3022 NS_IMETHODIMP
SetServerDoingLsub(bool aDoingLsub)3023 nsImapIncomingServer::SetServerDoingLsub(bool aDoingLsub) {
3024 return SetDoingLsub(aDoingLsub);
3025 }
3026
3027 NS_IMETHODIMP
SetServerUtf8AcceptEnabled(bool enabled)3028 nsImapIncomingServer::SetServerUtf8AcceptEnabled(bool enabled) {
3029 return SetUtf8AcceptEnabled(enabled);
3030 }
3031