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