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 "nsImapHostSessionList.h"
8 #include "nsImapBodyShell.h"
9 #include "nsImapNamespace.h"
10 #include "nsIImapIncomingServer.h"
11 #include "nsCOMPtr.h"
12 #include "nsIMsgIncomingServer.h"
13 #include "nsIObserverService.h"
14 #include "nsServiceManagerUtils.h"
15 #include "nsMsgUtils.h"
16 #include "mozilla/Services.h"
17 
nsIMAPHostInfo(const char * serverKey,nsIImapIncomingServer * server)18 nsIMAPHostInfo::nsIMAPHostInfo(const char* serverKey,
19                                nsIImapIncomingServer* server) {
20   fServerKey = serverKey;
21   NS_ASSERTION(server, "*** Fatal null imap incoming server...");
22   server->GetServerDirectory(fOnlineDir);
23   fNextHost = NULL;
24   fCapabilityFlags = kCapabilityUndefined;
25   fHierarchyDelimiters = NULL;
26 #ifdef DEBUG_bienvenu1
27   fHaveWeEverDiscoveredFolders =
28       true;  // try this, see what bad happens - we'll need to
29              // figure out a way to make new accounts have it be false
30 #else
31   fHaveWeEverDiscoveredFolders = false;  // try this, see what bad happens
32 #endif
33   fDiscoveryForHostInProgress = false;
34   fCanonicalOnlineSubDir = NULL;
35   fNamespaceList = nsImapNamespaceList::CreatensImapNamespaceList();
36   fUsingSubscription = true;
37   server->GetUsingSubscription(&fUsingSubscription);
38   fOnlineTrashFolderExists = false;
39   fShouldAlwaysListInbox = true;
40   fShellCache = nsImapBodyShellCache::Create();
41   fPasswordVerifiedOnline = false;
42   fDeleteIsMoveToTrash = true;
43   fShowDeletedMessages = false;
44   fGotNamespaces = false;
45   fHaveAdminURL = false;
46   fNamespacesOverridable = true;
47   server->GetOverrideNamespaces(&fNamespacesOverridable);
48   fTempNamespaceList = nsImapNamespaceList::CreatensImapNamespaceList();
49 }
50 
~nsIMAPHostInfo()51 nsIMAPHostInfo::~nsIMAPHostInfo() {
52   PR_Free(fHierarchyDelimiters);
53   delete fNamespaceList;
54   delete fTempNamespaceList;
55   delete fShellCache;
56 }
57 
NS_IMPL_ISUPPORTS(nsImapHostSessionList,nsIImapHostSessionList,nsIObserver,nsISupportsWeakReference)58 NS_IMPL_ISUPPORTS(nsImapHostSessionList, nsIImapHostSessionList, nsIObserver,
59                   nsISupportsWeakReference)
60 
61 nsImapHostSessionList::nsImapHostSessionList() {
62   gCachedHostInfoMonitor = PR_NewMonitor(/* "accessing-hostlist-monitor"*/);
63   fHostInfoList = nullptr;
64 }
65 
~nsImapHostSessionList()66 nsImapHostSessionList::~nsImapHostSessionList() {
67   ResetAll();
68   PR_DestroyMonitor(gCachedHostInfoMonitor);
69 }
70 
Init()71 nsresult nsImapHostSessionList::Init() {
72   nsCOMPtr<nsIObserverService> observerService =
73       mozilla::services::GetObserverService();
74   NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
75   observerService->AddObserver(this, "profile-before-change", true);
76   observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
77   return NS_OK;
78 }
79 
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * someData)80 NS_IMETHODIMP nsImapHostSessionList::Observe(nsISupports* aSubject,
81                                              const char* aTopic,
82                                              const char16_t* someData) {
83   if (!strcmp(aTopic, "profile-before-change"))
84     ResetAll();
85   else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
86     nsCOMPtr<nsIObserverService> observerService =
87         mozilla::services::GetObserverService();
88     NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
89     observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
90     observerService->RemoveObserver(this, "profile-before-change");
91   }
92   return NS_OK;
93 }
94 
FindHost(const char * serverKey)95 nsIMAPHostInfo* nsImapHostSessionList::FindHost(const char* serverKey) {
96   nsIMAPHostInfo* host;
97 
98   // ### should also check userName here, if NON NULL
99   for (host = fHostInfoList; host; host = host->fNextHost) {
100     if (host->fServerKey.Equals(serverKey, nsCaseInsensitiveCStringComparator))
101       return host;
102   }
103   return host;
104 }
105 
106 // reset any cached connection info - delete the lot of 'em
ResetAll()107 NS_IMETHODIMP nsImapHostSessionList::ResetAll() {
108   PR_EnterMonitor(gCachedHostInfoMonitor);
109   nsIMAPHostInfo* nextHost = NULL;
110   for (nsIMAPHostInfo* host = fHostInfoList; host; host = nextHost) {
111     nextHost = host->fNextHost;
112     delete host;
113   }
114   fHostInfoList = NULL;
115   PR_ExitMonitor(gCachedHostInfoMonitor);
116   return NS_OK;
117 }
118 
119 NS_IMETHODIMP
AddHostToList(const char * serverKey,nsIImapIncomingServer * server)120 nsImapHostSessionList::AddHostToList(const char* serverKey,
121                                      nsIImapIncomingServer* server) {
122   nsIMAPHostInfo* newHost = NULL;
123   PR_EnterMonitor(gCachedHostInfoMonitor);
124   if (!FindHost(serverKey)) {
125     // stick it on the front
126     newHost = new nsIMAPHostInfo(serverKey, server);
127     if (newHost) {
128       newHost->fNextHost = fHostInfoList;
129       fHostInfoList = newHost;
130     }
131   }
132   PR_ExitMonitor(gCachedHostInfoMonitor);
133   return (newHost == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
134 }
135 
GetPasswordForHost(const char * serverKey,nsString & result)136 NS_IMETHODIMP nsImapHostSessionList::GetPasswordForHost(const char* serverKey,
137                                                         nsString& result) {
138   PR_EnterMonitor(gCachedHostInfoMonitor);
139   nsIMAPHostInfo* host = FindHost(serverKey);
140   if (host) result = host->fCachedPassword;
141   PR_ExitMonitor(gCachedHostInfoMonitor);
142   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
143 }
144 
SetPasswordForHost(const char * serverKey,const nsAString & password)145 NS_IMETHODIMP nsImapHostSessionList::SetPasswordForHost(
146     const char* serverKey, const nsAString& password) {
147   PR_EnterMonitor(gCachedHostInfoMonitor);
148   nsIMAPHostInfo* host = FindHost(serverKey);
149   if (host) host->fCachedPassword = password;
150   PR_ExitMonitor(gCachedHostInfoMonitor);
151   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
152 }
153 
SetPasswordVerifiedOnline(const char * serverKey)154 NS_IMETHODIMP nsImapHostSessionList::SetPasswordVerifiedOnline(
155     const char* serverKey) {
156   PR_EnterMonitor(gCachedHostInfoMonitor);
157   nsIMAPHostInfo* host = FindHost(serverKey);
158   if (host) host->fPasswordVerifiedOnline = true;
159   PR_ExitMonitor(gCachedHostInfoMonitor);
160   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
161 }
162 
GetPasswordVerifiedOnline(const char * serverKey,bool & result)163 NS_IMETHODIMP nsImapHostSessionList::GetPasswordVerifiedOnline(
164     const char* serverKey, bool& result) {
165   PR_EnterMonitor(gCachedHostInfoMonitor);
166   nsIMAPHostInfo* host = FindHost(serverKey);
167   if (host) result = host->fPasswordVerifiedOnline;
168   PR_ExitMonitor(gCachedHostInfoMonitor);
169   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
170 }
171 
GetOnlineDirForHost(const char * serverKey,nsString & result)172 NS_IMETHODIMP nsImapHostSessionList::GetOnlineDirForHost(const char* serverKey,
173                                                          nsString& result) {
174   PR_EnterMonitor(gCachedHostInfoMonitor);
175   nsIMAPHostInfo* host = FindHost(serverKey);
176   if (host) CopyASCIItoUTF16(host->fOnlineDir, result);
177   PR_ExitMonitor(gCachedHostInfoMonitor);
178   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
179 }
180 
SetOnlineDirForHost(const char * serverKey,const char * onlineDir)181 NS_IMETHODIMP nsImapHostSessionList::SetOnlineDirForHost(
182     const char* serverKey, const char* onlineDir) {
183   PR_EnterMonitor(gCachedHostInfoMonitor);
184   nsIMAPHostInfo* host = FindHost(serverKey);
185   if (host) {
186     if (onlineDir) host->fOnlineDir = onlineDir;
187   }
188   PR_ExitMonitor(gCachedHostInfoMonitor);
189   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
190 }
191 
GetDeleteIsMoveToTrashForHost(const char * serverKey,bool & result)192 NS_IMETHODIMP nsImapHostSessionList::GetDeleteIsMoveToTrashForHost(
193     const char* serverKey, bool& result) {
194   PR_EnterMonitor(gCachedHostInfoMonitor);
195   nsIMAPHostInfo* host = FindHost(serverKey);
196   if (host) result = host->fDeleteIsMoveToTrash;
197   PR_ExitMonitor(gCachedHostInfoMonitor);
198   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
199 }
200 
GetShowDeletedMessagesForHost(const char * serverKey,bool & result)201 NS_IMETHODIMP nsImapHostSessionList::GetShowDeletedMessagesForHost(
202     const char* serverKey, bool& result) {
203   PR_EnterMonitor(gCachedHostInfoMonitor);
204   nsIMAPHostInfo* host = FindHost(serverKey);
205   if (host) result = host->fShowDeletedMessages;
206   PR_ExitMonitor(gCachedHostInfoMonitor);
207   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
208 }
209 
SetDeleteIsMoveToTrashForHost(const char * serverKey,bool isMoveToTrash)210 NS_IMETHODIMP nsImapHostSessionList::SetDeleteIsMoveToTrashForHost(
211     const char* serverKey, bool isMoveToTrash) {
212   PR_EnterMonitor(gCachedHostInfoMonitor);
213   nsIMAPHostInfo* host = FindHost(serverKey);
214   if (host) host->fDeleteIsMoveToTrash = isMoveToTrash;
215   PR_ExitMonitor(gCachedHostInfoMonitor);
216   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
217 }
218 
SetShowDeletedMessagesForHost(const char * serverKey,bool showDeletedMessages)219 NS_IMETHODIMP nsImapHostSessionList::SetShowDeletedMessagesForHost(
220     const char* serverKey, bool showDeletedMessages) {
221   PR_EnterMonitor(gCachedHostInfoMonitor);
222   nsIMAPHostInfo* host = FindHost(serverKey);
223   if (host) host->fShowDeletedMessages = showDeletedMessages;
224   PR_ExitMonitor(gCachedHostInfoMonitor);
225   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
226 }
227 
GetGotNamespacesForHost(const char * serverKey,bool & result)228 NS_IMETHODIMP nsImapHostSessionList::GetGotNamespacesForHost(
229     const char* serverKey, bool& result) {
230   PR_EnterMonitor(gCachedHostInfoMonitor);
231   nsIMAPHostInfo* host = FindHost(serverKey);
232   if (host) result = host->fGotNamespaces;
233   PR_ExitMonitor(gCachedHostInfoMonitor);
234   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
235 }
236 
SetGotNamespacesForHost(const char * serverKey,bool gotNamespaces)237 NS_IMETHODIMP nsImapHostSessionList::SetGotNamespacesForHost(
238     const char* serverKey, bool gotNamespaces) {
239   PR_EnterMonitor(gCachedHostInfoMonitor);
240   nsIMAPHostInfo* host = FindHost(serverKey);
241   if (host) host->fGotNamespaces = gotNamespaces;
242   PR_ExitMonitor(gCachedHostInfoMonitor);
243   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
244 }
245 
GetHostIsUsingSubscription(const char * serverKey,bool & result)246 NS_IMETHODIMP nsImapHostSessionList::GetHostIsUsingSubscription(
247     const char* serverKey, bool& result) {
248   PR_EnterMonitor(gCachedHostInfoMonitor);
249   nsIMAPHostInfo* host = FindHost(serverKey);
250   if (host) result = host->fUsingSubscription;
251   PR_ExitMonitor(gCachedHostInfoMonitor);
252   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
253 }
254 
SetHostIsUsingSubscription(const char * serverKey,bool usingSubscription)255 NS_IMETHODIMP nsImapHostSessionList::SetHostIsUsingSubscription(
256     const char* serverKey, bool usingSubscription) {
257   PR_EnterMonitor(gCachedHostInfoMonitor);
258   nsIMAPHostInfo* host = FindHost(serverKey);
259   if (host) host->fUsingSubscription = usingSubscription;
260   PR_ExitMonitor(gCachedHostInfoMonitor);
261   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
262 }
263 
GetHostHasAdminURL(const char * serverKey,bool & result)264 NS_IMETHODIMP nsImapHostSessionList::GetHostHasAdminURL(const char* serverKey,
265                                                         bool& result) {
266   PR_EnterMonitor(gCachedHostInfoMonitor);
267   nsIMAPHostInfo* host = FindHost(serverKey);
268   if (host) result = host->fHaveAdminURL;
269   PR_ExitMonitor(gCachedHostInfoMonitor);
270   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
271 }
272 
SetHostHasAdminURL(const char * serverKey,bool haveAdminURL)273 NS_IMETHODIMP nsImapHostSessionList::SetHostHasAdminURL(const char* serverKey,
274                                                         bool haveAdminURL) {
275   PR_EnterMonitor(gCachedHostInfoMonitor);
276   nsIMAPHostInfo* host = FindHost(serverKey);
277   if (host) host->fHaveAdminURL = haveAdminURL;
278   PR_ExitMonitor(gCachedHostInfoMonitor);
279   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
280 }
281 
GetHaveWeEverDiscoveredFoldersForHost(const char * serverKey,bool & result)282 NS_IMETHODIMP nsImapHostSessionList::GetHaveWeEverDiscoveredFoldersForHost(
283     const char* serverKey, bool& result) {
284   PR_EnterMonitor(gCachedHostInfoMonitor);
285   nsIMAPHostInfo* host = FindHost(serverKey);
286   if (host) result = host->fHaveWeEverDiscoveredFolders;
287   PR_ExitMonitor(gCachedHostInfoMonitor);
288   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
289 }
290 
SetHaveWeEverDiscoveredFoldersForHost(const char * serverKey,bool discovered)291 NS_IMETHODIMP nsImapHostSessionList::SetHaveWeEverDiscoveredFoldersForHost(
292     const char* serverKey, bool discovered) {
293   PR_EnterMonitor(gCachedHostInfoMonitor);
294   nsIMAPHostInfo* host = FindHost(serverKey);
295   if (host) host->fHaveWeEverDiscoveredFolders = discovered;
296   PR_ExitMonitor(gCachedHostInfoMonitor);
297   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
298 }
299 
GetDiscoveryForHostInProgress(const char * serverKey,bool & result)300 NS_IMETHODIMP nsImapHostSessionList::GetDiscoveryForHostInProgress(
301     const char* serverKey, bool& result) {
302   PR_EnterMonitor(gCachedHostInfoMonitor);
303   nsIMAPHostInfo* host = FindHost(serverKey);
304   if (host)
305     result = host->fDiscoveryForHostInProgress;
306   else
307     result = false;
308   PR_ExitMonitor(gCachedHostInfoMonitor);
309   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
310 }
311 
SetDiscoveryForHostInProgress(const char * serverKey,bool inProgress)312 NS_IMETHODIMP nsImapHostSessionList::SetDiscoveryForHostInProgress(
313     const char* serverKey, bool inProgress) {
314   PR_EnterMonitor(gCachedHostInfoMonitor);
315   nsIMAPHostInfo* host = FindHost(serverKey);
316   if (host) host->fDiscoveryForHostInProgress = inProgress;
317   PR_ExitMonitor(gCachedHostInfoMonitor);
318   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
319 }
320 
SetOnlineTrashFolderExistsForHost(const char * serverKey,bool exists)321 NS_IMETHODIMP nsImapHostSessionList::SetOnlineTrashFolderExistsForHost(
322     const char* serverKey, bool exists) {
323   PR_EnterMonitor(gCachedHostInfoMonitor);
324   nsIMAPHostInfo* host = FindHost(serverKey);
325   if (host) host->fOnlineTrashFolderExists = exists;
326   PR_ExitMonitor(gCachedHostInfoMonitor);
327   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
328 }
329 
GetOnlineTrashFolderExistsForHost(const char * serverKey,bool & result)330 NS_IMETHODIMP nsImapHostSessionList::GetOnlineTrashFolderExistsForHost(
331     const char* serverKey, bool& result) {
332   PR_EnterMonitor(gCachedHostInfoMonitor);
333   nsIMAPHostInfo* host = FindHost(serverKey);
334   if (host) result = host->fOnlineTrashFolderExists;
335   PR_ExitMonitor(gCachedHostInfoMonitor);
336   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
337 }
338 
AddNewNamespaceForHost(const char * serverKey,nsImapNamespace * ns)339 NS_IMETHODIMP nsImapHostSessionList::AddNewNamespaceForHost(
340     const char* serverKey, nsImapNamespace* ns) {
341   PR_EnterMonitor(gCachedHostInfoMonitor);
342   nsIMAPHostInfo* host = FindHost(serverKey);
343   if (host) host->fNamespaceList->AddNewNamespace(ns);
344   PR_ExitMonitor(gCachedHostInfoMonitor);
345   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
346 }
347 
SetNamespaceFromPrefForHost(const char * serverKey,const char * namespacePref,EIMAPNamespaceType nstype)348 NS_IMETHODIMP nsImapHostSessionList::SetNamespaceFromPrefForHost(
349     const char* serverKey, const char* namespacePref,
350     EIMAPNamespaceType nstype) {
351   PR_EnterMonitor(gCachedHostInfoMonitor);
352   nsIMAPHostInfo* host = FindHost(serverKey);
353   if (host) {
354     if (namespacePref) {
355       int numNamespaces = host->fNamespaceList->UnserializeNamespaces(
356           namespacePref, nullptr, 0);
357       char** prefixes = (char**)PR_CALLOC(numNamespaces * sizeof(char*));
358       if (prefixes) {
359         int len = host->fNamespaceList->UnserializeNamespaces(
360             namespacePref, prefixes, numNamespaces);
361         for (int i = 0; i < len; i++) {
362           char* thisns = prefixes[i];
363           char delimiter = '/';  // a guess
364           if (PL_strlen(thisns) >= 1) delimiter = thisns[PL_strlen(thisns) - 1];
365           nsImapNamespace* ns =
366               new nsImapNamespace(nstype, thisns, delimiter, true);
367           if (ns) host->fNamespaceList->AddNewNamespace(ns);
368           PR_FREEIF(thisns);
369         }
370         PR_Free(prefixes);
371       }
372     }
373   }
374   PR_ExitMonitor(gCachedHostInfoMonitor);
375   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
376 }
377 
GetNamespaceForMailboxForHost(const char * serverKey,const char * mailbox_name,nsImapNamespace * & result)378 NS_IMETHODIMP nsImapHostSessionList::GetNamespaceForMailboxForHost(
379     const char* serverKey, const char* mailbox_name, nsImapNamespace*& result) {
380   PR_EnterMonitor(gCachedHostInfoMonitor);
381   nsIMAPHostInfo* host = FindHost(serverKey);
382   if (host) result = host->fNamespaceList->GetNamespaceForMailbox(mailbox_name);
383   PR_ExitMonitor(gCachedHostInfoMonitor);
384   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
385 }
386 
ClearPrefsNamespacesForHost(const char * serverKey)387 NS_IMETHODIMP nsImapHostSessionList::ClearPrefsNamespacesForHost(
388     const char* serverKey) {
389   PR_EnterMonitor(gCachedHostInfoMonitor);
390   nsIMAPHostInfo* host = FindHost(serverKey);
391   if (host) host->fNamespaceList->ClearNamespaces(true, false, true);
392   PR_ExitMonitor(gCachedHostInfoMonitor);
393   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
394 }
395 
ClearServerAdvertisedNamespacesForHost(const char * serverKey)396 NS_IMETHODIMP nsImapHostSessionList::ClearServerAdvertisedNamespacesForHost(
397     const char* serverKey) {
398   PR_EnterMonitor(gCachedHostInfoMonitor);
399   nsIMAPHostInfo* host = FindHost(serverKey);
400   if (host) host->fNamespaceList->ClearNamespaces(false, true, true);
401   PR_ExitMonitor(gCachedHostInfoMonitor);
402   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
403 }
404 
GetDefaultNamespaceOfTypeForHost(const char * serverKey,EIMAPNamespaceType type,nsImapNamespace * & result)405 NS_IMETHODIMP nsImapHostSessionList::GetDefaultNamespaceOfTypeForHost(
406     const char* serverKey, EIMAPNamespaceType type, nsImapNamespace*& result) {
407   PR_EnterMonitor(gCachedHostInfoMonitor);
408   nsIMAPHostInfo* host = FindHost(serverKey);
409   if (host) result = host->fNamespaceList->GetDefaultNamespaceOfType(type);
410   PR_ExitMonitor(gCachedHostInfoMonitor);
411   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
412 }
413 
GetNamespacesOverridableForHost(const char * serverKey,bool & result)414 NS_IMETHODIMP nsImapHostSessionList::GetNamespacesOverridableForHost(
415     const char* serverKey, bool& result) {
416   PR_EnterMonitor(gCachedHostInfoMonitor);
417   nsIMAPHostInfo* host = FindHost(serverKey);
418   if (host) result = host->fNamespacesOverridable;
419   PR_ExitMonitor(gCachedHostInfoMonitor);
420   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
421 }
422 
SetNamespacesOverridableForHost(const char * serverKey,bool overridable)423 NS_IMETHODIMP nsImapHostSessionList::SetNamespacesOverridableForHost(
424     const char* serverKey, bool overridable) {
425   PR_EnterMonitor(gCachedHostInfoMonitor);
426   nsIMAPHostInfo* host = FindHost(serverKey);
427   if (host) host->fNamespacesOverridable = overridable;
428   PR_ExitMonitor(gCachedHostInfoMonitor);
429   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
430 }
431 
GetNumberOfNamespacesForHost(const char * serverKey,uint32_t & result)432 NS_IMETHODIMP nsImapHostSessionList::GetNumberOfNamespacesForHost(
433     const char* serverKey, uint32_t& result) {
434   int32_t intResult = 0;
435 
436   PR_EnterMonitor(gCachedHostInfoMonitor);
437   nsIMAPHostInfo* host = FindHost(serverKey);
438   if (host) intResult = host->fNamespaceList->GetNumberOfNamespaces();
439   PR_ExitMonitor(gCachedHostInfoMonitor);
440   NS_ASSERTION(intResult >= 0, "negative number of namespaces");
441   result = (uint32_t)intResult;
442   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
443 }
444 
GetNamespaceNumberForHost(const char * serverKey,int32_t n,nsImapNamespace * & result)445 NS_IMETHODIMP nsImapHostSessionList::GetNamespaceNumberForHost(
446     const char* serverKey, int32_t n, nsImapNamespace*& result) {
447   PR_EnterMonitor(gCachedHostInfoMonitor);
448   nsIMAPHostInfo* host = FindHost(serverKey);
449   if (host) result = host->fNamespaceList->GetNamespaceNumber(n);
450   PR_ExitMonitor(gCachedHostInfoMonitor);
451   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
452 }
453 
SetNamespacesPrefForHost(nsIImapIncomingServer * aHost,EIMAPNamespaceType type,const char * pref)454 nsresult nsImapHostSessionList::SetNamespacesPrefForHost(
455     nsIImapIncomingServer* aHost, EIMAPNamespaceType type, const char* pref) {
456   if (type == kPersonalNamespace)
457     aHost->SetPersonalNamespace(nsDependentCString(pref));
458   else if (type == kPublicNamespace)
459     aHost->SetPublicNamespace(nsDependentCString(pref));
460   else if (type == kOtherUsersNamespace)
461     aHost->SetOtherUsersNamespace(nsDependentCString(pref));
462   else
463     NS_ASSERTION(false, "bogus namespace type");
464   return NS_OK;
465 }
466 // do we need this? What should we do about the master thing?
467 // Make sure this is running in the Mozilla thread when called
CommitNamespacesForHost(nsIImapIncomingServer * aHost)468 NS_IMETHODIMP nsImapHostSessionList::CommitNamespacesForHost(
469     nsIImapIncomingServer* aHost) {
470   NS_ENSURE_ARG_POINTER(aHost);
471   nsCString serverKey;
472   nsCOMPtr<nsIMsgIncomingServer> incomingServer = do_QueryInterface(aHost);
473   if (!incomingServer) return NS_ERROR_NULL_POINTER;
474 
475   nsresult rv = incomingServer->GetKey(serverKey);
476   NS_ENSURE_SUCCESS(rv, rv);
477 
478   PR_EnterMonitor(gCachedHostInfoMonitor);
479   nsIMAPHostInfo* host = FindHost(serverKey.get());
480   if (host) {
481     host->fGotNamespaces =
482         true;  // so we only issue NAMESPACE once per host per session.
483     EIMAPNamespaceType type = kPersonalNamespace;
484     for (int i = 1; i <= 3; i++) {
485       switch (i) {
486         case 1:
487           type = kPersonalNamespace;
488           break;
489         case 2:
490           type = kPublicNamespace;
491           break;
492         case 3:
493           type = kOtherUsersNamespace;
494           break;
495         default:
496           type = kPersonalNamespace;
497           break;
498       }
499 
500       int32_t numInNS = host->fNamespaceList->GetNumberOfNamespaces(type);
501       if (numInNS == 0)
502         SetNamespacesPrefForHost(aHost, type, "");
503       else if (numInNS >= 1) {
504         char* pref = PR_smprintf("");
505         for (int count = 1; count <= numInNS; count++) {
506           nsImapNamespace* ns =
507               host->fNamespaceList->GetNamespaceNumber(count, type);
508           if (ns) {
509             if (count > 1) {
510               // append the comma
511               char* tempPref = PR_smprintf("%s,", pref);
512               PR_FREEIF(pref);
513               pref = tempPref;
514             }
515             char* tempPref = PR_smprintf("%s\"%s\"", pref, ns->GetPrefix());
516             PR_FREEIF(pref);
517             pref = tempPref;
518           }
519         }
520         if (pref) {
521           SetNamespacesPrefForHost(aHost, type, pref);
522           PR_Free(pref);
523         }
524       }
525     }
526     // clear, but don't delete the entries in, the temp namespace list
527     host->fTempNamespaceList->ClearNamespaces(true, true, false);
528 
529     // Now reset all of libmsg's namespace references.
530     // Did I mention this needs to be running in the mozilla thread?
531     aHost->ResetNamespaceReferences();
532   }
533   PR_ExitMonitor(gCachedHostInfoMonitor);
534   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
535 }
536 
FlushUncommittedNamespacesForHost(const char * serverKey,bool & result)537 NS_IMETHODIMP nsImapHostSessionList::FlushUncommittedNamespacesForHost(
538     const char* serverKey, bool& result) {
539   PR_EnterMonitor(gCachedHostInfoMonitor);
540   nsIMAPHostInfo* host = FindHost(serverKey);
541   if (host) host->fTempNamespaceList->ClearNamespaces(true, true, true);
542   PR_ExitMonitor(gCachedHostInfoMonitor);
543   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
544 }
545 
546 // Returns NULL if there is no personal namespace on the given host
GetOnlineInboxPathForHost(const char * serverKey,nsString & result)547 NS_IMETHODIMP nsImapHostSessionList::GetOnlineInboxPathForHost(
548     const char* serverKey, nsString& result) {
549   PR_EnterMonitor(gCachedHostInfoMonitor);
550   nsIMAPHostInfo* host = FindHost(serverKey);
551   if (host) {
552     nsImapNamespace* ns = NULL;
553     ns = host->fNamespaceList->GetDefaultNamespaceOfType(kPersonalNamespace);
554     if (ns) {
555       CopyASCIItoUTF16(nsDependentCString(ns->GetPrefix()), result);
556       result.AppendLiteral("INBOX");
557     }
558   } else
559     result.Truncate();
560   PR_ExitMonitor(gCachedHostInfoMonitor);
561   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
562 }
563 
GetShouldAlwaysListInboxForHost(const char *,bool & result)564 NS_IMETHODIMP nsImapHostSessionList::GetShouldAlwaysListInboxForHost(
565     const char* /*serverKey*/, bool& result) {
566   result = true;
567 
568   /*
569   PR_EnterMonitor(gCachedHostInfoMonitor);
570   nsIMAPHostInfo *host = FindHost(serverKey);
571   if (host)
572     ret = host->fShouldAlwaysListInbox;
573   PR_ExitMonitor(gCachedHostInfoMonitor);
574   */
575   return NS_OK;
576 }
577 
SetShouldAlwaysListInboxForHost(const char * serverKey,bool shouldList)578 NS_IMETHODIMP nsImapHostSessionList::SetShouldAlwaysListInboxForHost(
579     const char* serverKey, bool shouldList) {
580   PR_EnterMonitor(gCachedHostInfoMonitor);
581   nsIMAPHostInfo* host = FindHost(serverKey);
582   if (host) host->fShouldAlwaysListInbox = shouldList;
583   PR_ExitMonitor(gCachedHostInfoMonitor);
584   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
585 }
586 
587 NS_IMETHODIMP
SetNamespaceHierarchyDelimiterFromMailboxForHost(const char * serverKey,const char * boxName,char delimiter)588 nsImapHostSessionList::SetNamespaceHierarchyDelimiterFromMailboxForHost(
589     const char* serverKey, const char* boxName, char delimiter) {
590   PR_EnterMonitor(gCachedHostInfoMonitor);
591   nsIMAPHostInfo* host = FindHost(serverKey);
592   if (host) {
593     nsImapNamespace* ns = host->fNamespaceList->GetNamespaceForMailbox(boxName);
594     if (ns && !ns->GetIsDelimiterFilledIn()) ns->SetDelimiter(delimiter, true);
595   }
596   PR_ExitMonitor(gCachedHostInfoMonitor);
597   return (host) ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
598 }
599 
AddShellToCacheForHost(const char * serverKey,nsImapBodyShell * shell)600 NS_IMETHODIMP nsImapHostSessionList::AddShellToCacheForHost(
601     const char* serverKey, nsImapBodyShell* shell) {
602   nsresult rv = NS_OK;
603   PR_EnterMonitor(gCachedHostInfoMonitor);
604   nsIMAPHostInfo* host = FindHost(serverKey);
605   if (host) {
606     if (host->fShellCache) {
607       if (!host->fShellCache->AddShellToCache(shell)) rv = NS_ERROR_UNEXPECTED;
608     }
609   } else
610     rv = NS_ERROR_ILLEGAL_VALUE;
611 
612   PR_ExitMonitor(gCachedHostInfoMonitor);
613   return rv;
614 }
615 
FindShellInCacheForHost(const char * serverKey,const char * mailboxName,const char * UID,IMAP_ContentModifiedType modType,nsImapBodyShell ** shell)616 NS_IMETHODIMP nsImapHostSessionList::FindShellInCacheForHost(
617     const char* serverKey, const char* mailboxName, const char* UID,
618     IMAP_ContentModifiedType modType, nsImapBodyShell** shell) {
619   nsCString uidString(UID);
620 
621   PR_EnterMonitor(gCachedHostInfoMonitor);
622   nsIMAPHostInfo* host = FindHost(serverKey);
623   if (host && host->fShellCache)
624     NS_IF_ADDREF(*shell = host->fShellCache->FindShellForUID(
625                      uidString, mailboxName, modType));
626   PR_ExitMonitor(gCachedHostInfoMonitor);
627   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
628 }
629 
630 NS_IMETHODIMP
ClearShellCacheForHost(const char * serverKey)631 nsImapHostSessionList::ClearShellCacheForHost(const char* serverKey) {
632   PR_EnterMonitor(gCachedHostInfoMonitor);
633   nsIMAPHostInfo* host = FindHost(serverKey);
634   if (host && host->fShellCache) host->fShellCache->Clear();
635   PR_ExitMonitor(gCachedHostInfoMonitor);
636   return (host == NULL) ? NS_ERROR_ILLEGAL_VALUE : NS_OK;
637 }
638