Back to index

lightning-sunbird  0.9+nobinonly
nsImapIncomingServer.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   David Bienvenu <bienvenu@nventure.com>
00024  *   Jeff Tsai <jefft@netscape.com>
00025  *   Scott MacGregor <mscott@netscape.com>
00026  *   Seth Spitzer <sspitzer@netscape.com>
00027  *   Alec Flett <alecf@netscape.com>
00028  *   Pierre Phaneuf <pp@ludusdesign.com>
00029  *
00030  * Alternatively, the contents of this file may be used under the terms of
00031  * either of the GNU General Public License Version 2 or later (the "GPL"),
00032  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00033  * in which case the provisions of the GPL or the LGPL are applicable instead
00034  * of those above. If you wish to allow use of your version of this file only
00035  * under the terms of either the GPL or the LGPL, and not to allow others to
00036  * use your version of this file under the terms of the MPL, indicate your
00037  * decision by deleting the provisions above and replace them with the notice
00038  * and other provisions required by the GPL or the LGPL. If you do not delete
00039  * the provisions above, a recipient may use your version of this file under
00040  * the terms of any one of the MPL, the GPL or the LGPL.
00041  *
00042  * ***** END LICENSE BLOCK ***** */
00043 
00044 #include "msgCore.h"
00045 #include "nsMsgImapCID.h"
00046 
00047 #include "netCore.h"
00048 
00049 #include "nsString.h"
00050 #include "nsReadableUtils.h"
00051 #include "nsISupportsObsolete.h"
00052 
00053 #include "nsIMAPHostSessionList.h"
00054 #include "nsImapIncomingServer.h"
00055 #include "nsIMsgAccountManager.h"
00056 #include "nsIMsgIdentity.h"
00057 #include "nsIImapUrl.h"
00058 #include "nsIUrlListener.h"
00059 #include "nsIEventQueue.h"
00060 #include "nsImapProtocol.h"
00061 #include "nsISupportsArray.h"
00062 #include "nsVoidArray.h"
00063 #include "nsCOMPtr.h"
00064 #include "nsImapStringBundle.h"
00065 #include "nsIPrefBranch.h"
00066 #include "nsIPrefService.h"
00067 #include "nsMsgFolderFlags.h"
00068 #include "prmem.h"
00069 #include "plstr.h"
00070 #include "nsXPIDLString.h"
00071 #include "nsIMsgFolder.h"
00072 #include "nsIMsgWindow.h"
00073 #include "nsIMsgImapMailFolder.h"
00074 #include "nsImapUtils.h"
00075 #include "nsIRDFService.h"
00076 #include "nsRDFCID.h"
00077 #include "nsEnumeratorUtils.h"
00078 #include "nsIEventQueueService.h"
00079 #include "nsIMsgMailNewsUrl.h"
00080 #include "nsIImapService.h"
00081 #include "nsMsgI18N.h"
00082 #include "nsAutoLock.h"
00083 #include "nsIImapMockChannel.h"
00084 #include "nsIPrompt.h"
00085 #include "nsIWindowWatcher.h"
00086 // for the memory cache...
00087 #include "nsICacheEntryDescriptor.h"
00088 #include "nsImapUrl.h"
00089 #include "nsFileStream.h"
00090 #include "nsIMsgProtocolInfo.h"
00091 #include "nsIMsgMailSession.h"
00092 #include "nsIMAPNamespace.h"
00093 #include "nsISignatureVerifier.h"
00094 
00095 #include "nsITimer.h"
00096 #include "nsMsgUtils.h"
00097 
00098 #define PREF_TRASH_FOLDER_NAME "trash_folder_name"
00099 #define DEFAULT_TRASH_FOLDER_NAME "Trash"
00100 
00101 static NS_DEFINE_CID(kImapProtocolCID, NS_IMAPPROTOCOL_CID);
00102 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00103 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00104 static NS_DEFINE_CID(kImapServiceCID, NS_IMAPSERVICE_CID);
00105 static NS_DEFINE_CID(kSubscribableServerCID, NS_SUBSCRIBABLESERVER_CID);
00106 static NS_DEFINE_CID(kCImapHostSessionListCID, NS_IIMAPHOSTSESSIONLIST_CID);
00107 
00108 NS_IMPL_ADDREF_INHERITED(nsImapIncomingServer, nsMsgIncomingServer)
00109 NS_IMPL_RELEASE_INHERITED(nsImapIncomingServer, nsMsgIncomingServer)
00110 
00111 NS_INTERFACE_MAP_BEGIN(nsImapIncomingServer)
00112        NS_INTERFACE_MAP_ENTRY(nsIImapServerSink)
00113        NS_INTERFACE_MAP_ENTRY(nsIImapIncomingServer)
00114        NS_INTERFACE_MAP_ENTRY(nsIMsgLogonRedirectionRequester)
00115        NS_INTERFACE_MAP_ENTRY(nsISubscribableServer)
00116        NS_INTERFACE_MAP_ENTRY(nsIUrlListener)
00117 NS_INTERFACE_MAP_END_INHERITING(nsMsgIncomingServer)
00118 
00119 nsImapIncomingServer::nsImapIncomingServer()
00120 {    
00121   nsresult rv;
00122   rv = NS_NewISupportsArray(getter_AddRefs(m_connectionCache));
00123   rv = NS_NewISupportsArray(getter_AddRefs(m_urlQueue));
00124   m_capability = kCapabilityUndefined;
00125   m_waitingForConnectionInfo = PR_FALSE;
00126   m_redirectedLogonRetries = 0;
00127   mDoingSubscribeDialog = PR_FALSE;
00128   mDoingLsub = PR_FALSE;
00129   m_canHaveFilters = PR_TRUE;
00130   m_userAuthenticated = PR_FALSE;
00131   m_readPFCName = PR_FALSE;
00132   m_readRedirectorType = PR_FALSE;
00133   m_shuttingDown = PR_FALSE;
00134 }
00135 
00136 nsImapIncomingServer::~nsImapIncomingServer()
00137 {
00138     nsresult rv = ClearInner();
00139     NS_ASSERTION(NS_SUCCEEDED(rv), "ClearInner failed");
00140 
00141     CloseCachedConnections();
00142 }
00143 
00144 NS_IMETHODIMP nsImapIncomingServer::SetKey(const char * aKey)  // override nsMsgIncomingServer's implementation...
00145 {
00146   nsMsgIncomingServer::SetKey(aKey);
00147 
00148   // okay now that the key has been set, we need to add ourselves to the
00149   // host session list...
00150 
00151   // every time we create an imap incoming server, we need to add it to the
00152   // host session list!! 
00153 
00154   nsresult rv;
00155   nsCOMPtr<nsIImapHostSessionList> hostSession = 
00156           do_GetService(kCImapHostSessionListCID, &rv);
00157   if (NS_FAILED(rv)) return rv;
00158 
00159   hostSession->AddHostToList(aKey, this);
00160   nsMsgImapDeleteModel deleteModel = nsMsgImapDeleteModels::MoveToTrash; // default to trash
00161   GetDeleteModel(&deleteModel);
00162   hostSession->SetDeleteIsMoveToTrashForHost(aKey, deleteModel == nsMsgImapDeleteModels::MoveToTrash); 
00163   hostSession->SetShowDeletedMessagesForHost(aKey, deleteModel == nsMsgImapDeleteModels::IMAPDelete);
00164 
00165   nsXPIDLCString onlineDir;
00166   rv = GetServerDirectory(getter_Copies(onlineDir));
00167   if (NS_FAILED(rv)) return rv;
00168   if (onlineDir)
00169       hostSession->SetOnlineDirForHost(aKey, (const char *) onlineDir);
00170 
00171   nsXPIDLCString personalNamespace;
00172   nsXPIDLCString publicNamespace;
00173   nsXPIDLCString otherUsersNamespace;
00174 
00175   rv = GetPersonalNamespace(getter_Copies(personalNamespace));
00176   if (NS_FAILED(rv)) return rv;
00177   rv = GetPublicNamespace(getter_Copies(publicNamespace));
00178   if (NS_FAILED(rv)) return rv;
00179   rv = GetOtherUsersNamespace(getter_Copies(otherUsersNamespace));
00180   if (NS_FAILED(rv)) return rv;
00181 
00182   if (!personalNamespace && !publicNamespace && !otherUsersNamespace)
00183       personalNamespace.Adopt(nsCRT::strdup("\"\""));
00184 
00185   hostSession->SetNamespaceFromPrefForHost(aKey, personalNamespace,
00186                                            kPersonalNamespace);
00187 
00188   if (publicNamespace && PL_strlen(publicNamespace))
00189       hostSession->SetNamespaceFromPrefForHost(aKey, publicNamespace,
00190                                                kPublicNamespace);
00191 
00192   if (otherUsersNamespace && PL_strlen(otherUsersNamespace))
00193       hostSession->SetNamespaceFromPrefForHost(aKey, otherUsersNamespace,
00194                                                kOtherUsersNamespace);
00195   PRInt32 capability;
00196   rv = GetCapabilityPref(&capability);
00197   NS_ENSURE_SUCCESS(rv, rv);
00198   hostSession->SetCapabilityForHost(aKey, capability);
00199   return rv;
00200 }
00201 
00202 // construct the pretty name to show to the user if they haven't
00203 // specified one. This should be overridden for news and mail.
00204 NS_IMETHODIMP
00205 nsImapIncomingServer::GetConstructedPrettyName(PRUnichar **retval) 
00206 {
00207     
00208   nsXPIDLCString username;
00209   nsXPIDLCString hostName;
00210   nsresult rv;
00211 
00212   nsCOMPtr<nsIMsgAccountManager> accountManager = 
00213            do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00214   NS_ENSURE_SUCCESS(rv,rv);
00215 
00216   nsCOMPtr<nsIMsgIdentity> identity;
00217   rv = accountManager->GetFirstIdentityForServer(this, getter_AddRefs(identity));
00218   NS_ENSURE_SUCCESS(rv,rv);
00219 
00220   nsAutoString emailAddress;
00221 
00222   if (NS_SUCCEEDED(rv) && identity)
00223   {
00224     nsXPIDLCString identityEmailAddress;
00225     identity->GetEmail(getter_Copies(identityEmailAddress));
00226     emailAddress.AssignWithConversion(identityEmailAddress);
00227   }
00228   else
00229   {
00230     rv = GetRealUsername(getter_Copies(username));
00231     if (NS_FAILED(rv)) return rv;
00232     rv = GetRealHostName(getter_Copies(hostName));
00233     if (NS_FAILED(rv)) return rv;
00234     if ((const char*)username && (const char *) hostName &&
00235         PL_strcmp((const char*)username, "")!=0) {
00236       emailAddress.AssignWithConversion(username);
00237       emailAddress.AppendLiteral("@");
00238       emailAddress.AppendWithConversion(hostName);
00239 
00240     }
00241   }
00242 
00243   rv = GetFormattedStringFromID(emailAddress.get(), IMAP_DEFAULT_ACCOUNT_NAME, retval);
00244   return rv;
00245 }
00246 
00247 
00248 NS_IMETHODIMP nsImapIncomingServer::GetLocalStoreType(char ** type)
00249 {
00250     NS_ENSURE_ARG_POINTER(type);
00251     *type = nsCRT::strdup("imap");
00252     return NS_OK;
00253 }
00254 
00255 NS_IMETHODIMP
00256 nsImapIncomingServer::GetServerDirectory(char **serverDirectory)
00257 {
00258     return GetCharValue("server_sub_directory", serverDirectory);
00259 }
00260 
00261 NS_IMETHODIMP
00262 nsImapIncomingServer::SetServerDirectory(const char *serverDirectory)
00263 {
00264     nsXPIDLCString serverKey;
00265     nsresult rv = GetKey(getter_Copies(serverKey));
00266     if (NS_SUCCEEDED(rv))
00267     {
00268         nsCOMPtr<nsIImapHostSessionList> hostSession = 
00269                  do_GetService(kCImapHostSessionListCID, &rv);
00270         if (NS_SUCCEEDED(rv))
00271             hostSession->SetOnlineDirForHost(serverKey, serverDirectory);
00272     }
00273     return SetCharValue("server_sub_directory", serverDirectory);
00274 }
00275 
00276 
00277 NS_IMETHODIMP
00278 nsImapIncomingServer::GetOverrideNamespaces(PRBool *bVal)
00279 {
00280     return GetBoolValue("override_namespaces", bVal);
00281 }
00282 
00283 NS_IMETHODIMP
00284 nsImapIncomingServer::SetOverrideNamespaces(PRBool bVal)
00285 {
00286     nsXPIDLCString serverKey;
00287     GetKey(getter_Copies(serverKey));
00288     if (serverKey)
00289     {
00290         nsresult rv;
00291         nsCOMPtr<nsIImapHostSessionList> hostSession = 
00292                  do_GetService(kCImapHostSessionListCID, &rv);
00293         if (NS_SUCCEEDED(rv))
00294             hostSession->SetNamespacesOverridableForHost(serverKey, bVal);
00295     }
00296     return SetBoolValue("override_namespaces", bVal);
00297 }
00298 
00299 NS_IMETHODIMP
00300 nsImapIncomingServer::GetUsingSubscription(PRBool *bVal)
00301 {
00302     return GetBoolValue("using_subscription", bVal);
00303 }
00304 
00305 NS_IMETHODIMP
00306 nsImapIncomingServer::SetUsingSubscription(PRBool bVal)
00307 {
00308     nsXPIDLCString serverKey;
00309     GetKey(getter_Copies(serverKey));
00310     if (serverKey)
00311     {
00312         nsresult rv;
00313         nsCOMPtr<nsIImapHostSessionList> hostSession = 
00314                  do_GetService(kCImapHostSessionListCID, &rv);
00315         if (NS_SUCCEEDED(rv))
00316             hostSession->SetHostIsUsingSubscription(serverKey, bVal);
00317     }
00318     return SetBoolValue("using_subscription", bVal);
00319 }
00320 
00321 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, DualUseFolders,
00322                         "dual_use_folders")
00323                      
00324                      
00325 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, AdminUrl,
00326                        "admin_url")
00327 
00328 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, CleanupInboxOnExit,
00329                         "cleanup_inbox_on_exit")
00330                      
00331 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, OfflineDownload,
00332                         "offline_download")
00333 
00334 NS_IMPL_SERVERPREF_INT(nsImapIncomingServer, MaximumConnectionsNumber,
00335                        "max_cached_connections")
00336 
00337 NS_IMPL_SERVERPREF_INT(nsImapIncomingServer, EmptyTrashThreshhold,
00338                        "empty_trash_threshhold")
00339 
00340 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, StoreReadMailInPFC,
00341                         "store_read_mail_in_pfc")
00342                      
00343 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, StoreSentMailInPFC,
00344                         "store_sent_mail_in_pfc")
00345 
00346 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, DownloadBodiesOnGetNewMail,
00347                         "download_bodies_on_get_new_mail")
00348 
00349 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, AutoSyncOfflineStores,
00350                         "autosync_offline_stores")
00351 
00352 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, UseIdle,
00353                         "use_idle")
00354 //NS_IMPL_SERVERPREF_INT(nsImapIncomingServer, DeleteModel,
00355 //                       "delete_model")
00356 
00357 
00358 NS_IMPL_GETSET(nsImapIncomingServer, ShuttingDown, PRBool, m_shuttingDown)
00359 
00360 NS_IMETHODIMP                                                         
00361 nsImapIncomingServer::GetDeleteModel(PRInt32 *retval)
00362 {                                         
00363   NS_ENSURE_ARG(retval);
00364 
00365   nsXPIDLCString redirectorType;
00366   GetRedirectorType(getter_Copies(redirectorType));
00367   if (redirectorType.Equals("aol"))
00368   {
00369     PRBool suppressPseudoView = PR_FALSE;
00370     GetBoolAttribute("suppresspseudoview", &suppressPseudoView);
00371     if (!suppressPseudoView)
00372       *retval = nsMsgImapDeleteModels::DeleteNoTrash;
00373     else
00374       *retval = nsMsgImapDeleteModels::IMAPDelete;
00375     return NS_OK;
00376   }
00377   nsresult ret = GetIntValue("delete_model", retval);
00378   return ret;
00379 }
00380 
00381 NS_IMETHODIMP                                                         \
00382 nsImapIncomingServer::SetDeleteModel(PRInt32 ivalue)
00383 {                                                                                   \
00384   nsresult rv = SetIntValue("delete_model", ivalue);                  
00385   if (NS_SUCCEEDED(rv))
00386   {
00387     nsCOMPtr<nsIImapHostSessionList> hostSession = 
00388         do_GetService(kCImapHostSessionListCID, &rv);
00389     NS_ENSURE_SUCCESS(rv,rv);
00390     hostSession->SetDeleteIsMoveToTrashForHost(m_serverKey.get(), ivalue == nsMsgImapDeleteModels::MoveToTrash); 
00391     hostSession->SetShowDeletedMessagesForHost(m_serverKey.get(), ivalue == nsMsgImapDeleteModels::IMAPDelete);
00392   }
00393   return rv;
00394 }
00395 
00396 NS_IMPL_SERVERPREF_INT(nsImapIncomingServer, TimeOutLimits,
00397                        "timeout")
00398 
00399 NS_IMPL_SERVERPREF_INT(nsImapIncomingServer, CapabilityPref,
00400                        "capability")
00401 
00402 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, PersonalNamespace,
00403                        "namespace.personal")
00404 
00405 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, PublicNamespace,
00406                        "namespace.public")
00407 
00408 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, OtherUsersNamespace,
00409                        "namespace.other_users")
00410 
00411 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, FetchByChunks,
00412                        "fetch_by_chunks")
00413 
00414 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, MimePartsOnDemand,
00415                        "mime_parts_on_demand")
00416 
00417 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, AOLMailboxView,
00418                        "aol_mailbox_view")
00419 
00420 NS_IMETHODIMP
00421 nsImapIncomingServer::GetIsAOLServer(PRBool *aBool)
00422 {
00423   if (!aBool)
00424     return NS_ERROR_NULL_POINTER;
00425   *aBool = ((m_capability & kAOLImapCapability) != 0);
00426   return NS_OK;
00427 }
00428 
00429 NS_IMETHODIMP
00430 nsImapIncomingServer::SetIsAOLServer(PRBool aBool)
00431 {
00432   if (aBool)
00433     m_capability |= kAOLImapCapability;
00434   else
00435     m_capability &= ~kAOLImapCapability;
00436   return NS_OK;
00437 }
00438 
00439 
00440 NS_IMETHODIMP
00441 nsImapIncomingServer::GetImapConnectionAndLoadUrl(nsIEventQueue * aClientEventQueue,
00442                                                   nsIImapUrl* aImapUrl,
00443                                                   nsISupports* aConsumer)
00444 {
00445   nsresult rv = NS_OK;
00446   nsCOMPtr <nsIImapProtocol> aProtocol;
00447   
00448   rv = GetImapConnection(aClientEventQueue, aImapUrl, getter_AddRefs(aProtocol));
00449   if (NS_FAILED(rv)) return rv;
00450 
00451   nsCOMPtr<nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(aImapUrl, &rv);
00452   if (aProtocol)
00453   {
00454     rv = aProtocol->LoadImapUrl(mailnewsurl, aConsumer);
00455     // *** jt - in case of the time out situation or the connection gets
00456     // terminated by some unforseen problems let's give it a second chance
00457     // to run the url
00458     if (NS_FAILED(rv))
00459     {
00460       NS_ASSERTION(PR_FALSE, "shouldn't get an error loading url");
00461       rv = aProtocol->LoadImapUrl(mailnewsurl, aConsumer);
00462     }
00463   }
00464   else
00465   {   // unable to get an imap connection to run the url; add to the url
00466     // queue
00467     nsImapProtocol::LogImapUrl("queuing url", aImapUrl);
00468     PR_CEnterMonitor(this);
00469     nsCOMPtr <nsISupports> supports(do_QueryInterface(aImapUrl));
00470     if (supports)
00471       m_urlQueue->AppendElement(supports);
00472     m_urlConsumers.AppendElement((void*)aConsumer);
00473     NS_IF_ADDREF(aConsumer);
00474     PR_CExitMonitor(this);
00475     // let's try running it now - maybe the connection is free now.
00476     PRBool urlRun;
00477     rv = LoadNextQueuedUrl(nsnull, &urlRun);
00478   }
00479 
00480   return rv;
00481 }
00482 
00483 NS_IMETHODIMP
00484 nsImapIncomingServer::RetryUrl(nsIImapUrl *aImapUrl)
00485 {
00486   nsresult rv;
00487   nsCOMPtr <nsIEventQueue> aEventQueue;
00488   // Get current thread envent queue
00489   nsCOMPtr<nsIEventQueueService> pEventQService = 
00490     do_GetService(kEventQueueServiceCID, &rv); 
00491   if (NS_SUCCEEDED(rv) && pEventQService)
00492     pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
00493     getter_AddRefs(aEventQueue));
00494   nsCOMPtr <nsIImapProtocol> protocolInstance;
00495   nsImapProtocol::LogImapUrl("creating protocol instance to retry queued url", aImapUrl);
00496   rv = GetImapConnection(aEventQueue, aImapUrl, getter_AddRefs(protocolInstance));
00497   if (NS_SUCCEEDED(rv) && protocolInstance)
00498   {
00499     nsCOMPtr<nsIURI> url = do_QueryInterface(aImapUrl, &rv);
00500     if (NS_SUCCEEDED(rv) && url)
00501     {
00502       nsImapProtocol::LogImapUrl("retrying  url", aImapUrl);
00503       rv = protocolInstance->LoadImapUrl(url, nsnull); // ### need to save the display consumer.
00504       NS_ASSERTION(NS_SUCCEEDED(rv), "failed running queued url");
00505     }
00506   }
00507   return rv;
00508 }
00509 
00510 // checks to see if there are any queued urls on this incoming server,
00511 // and if so, tries to run the oldest one. Returns true if the url is run
00512 // on the passed in protocol connection.
00513 NS_IMETHODIMP
00514 nsImapIncomingServer::LoadNextQueuedUrl(nsIImapProtocol *aProtocol, PRBool *aResult)
00515 {
00516   PRUint32 cnt = 0;
00517   nsresult rv = NS_OK;
00518   PRBool urlRun = PR_FALSE;
00519   PRBool keepGoing = PR_TRUE;
00520   nsCOMPtr <nsIImapProtocol>  protocolInstance ;
00521   
00522   nsAutoCMonitor mon(this);
00523   m_urlQueue->Count(&cnt);
00524 
00525   while (cnt > 0 && !urlRun && keepGoing)
00526   {
00527     nsCOMPtr<nsIImapUrl> aImapUrl(do_QueryElementAt(m_urlQueue, 0, &rv));
00528     nsCOMPtr<nsIMsgMailNewsUrl> aMailNewsUrl(do_QueryInterface(aImapUrl, &rv));
00529     
00530     PRBool removeUrlFromQueue = PR_FALSE;
00531     if (aImapUrl)
00532     {
00533       nsImapProtocol::LogImapUrl("considering playing queued url", aImapUrl);
00534       rv = DoomUrlIfChannelHasError(aImapUrl, &removeUrlFromQueue);
00535       NS_ENSURE_SUCCESS(rv, rv);
00536       // if we didn't doom the url, lets run it.
00537       if (!removeUrlFromQueue)
00538       {
00539         nsISupports *aConsumer = (nsISupports*)m_urlConsumers.ElementAt(0);
00540         NS_IF_ADDREF(aConsumer);
00541         
00542         nsImapProtocol::LogImapUrl("creating protocol instance to play queued url", aImapUrl);
00543         rv = GetImapConnection(nsnull, aImapUrl, getter_AddRefs(protocolInstance));
00544         if (NS_SUCCEEDED(rv) && protocolInstance)
00545         {
00546           nsCOMPtr<nsIURI> url = do_QueryInterface(aImapUrl, &rv);
00547           if (NS_SUCCEEDED(rv) && url)
00548           {
00549             nsImapProtocol::LogImapUrl("playing queued url", aImapUrl);
00550             rv = protocolInstance->LoadImapUrl(url, aConsumer);
00551             NS_ASSERTION(NS_SUCCEEDED(rv), "failed running queued url");
00552             urlRun = PR_TRUE;
00553             removeUrlFromQueue = PR_TRUE;
00554           }
00555         }
00556         else
00557         {
00558           nsImapProtocol::LogImapUrl("failed creating protocol instance to play queued url", aImapUrl);
00559           keepGoing = PR_FALSE;
00560         }
00561         NS_IF_RELEASE(aConsumer);
00562       }
00563       if (removeUrlFromQueue)
00564       {
00565         m_urlQueue->RemoveElementAt(0);
00566         m_urlConsumers.RemoveElementAt(0);
00567       }
00568     }
00569     m_urlQueue->Count(&cnt);
00570   }
00571   if (aResult)
00572     *aResult = urlRun && aProtocol && aProtocol == protocolInstance;
00573   
00574   return rv;
00575 }
00576 
00577 NS_IMETHODIMP
00578 nsImapIncomingServer::AbortQueuedUrls()
00579 {
00580   PRUint32 cnt = 0;
00581   nsresult rv = NS_OK;
00582   
00583   nsAutoCMonitor mon(this);
00584   m_urlQueue->Count(&cnt);
00585   
00586   while (cnt > 0)
00587   {
00588     nsCOMPtr<nsIImapUrl> aImapUrl(do_QueryElementAt(m_urlQueue, cnt - 1, &rv));
00589     PRBool removeUrlFromQueue = PR_FALSE;
00590     
00591     if (aImapUrl)
00592     {
00593       rv = DoomUrlIfChannelHasError(aImapUrl, &removeUrlFromQueue);
00594       NS_ENSURE_SUCCESS(rv, rv);
00595       if (removeUrlFromQueue)
00596       {
00597         m_urlQueue->RemoveElementAt(cnt - 1);
00598         m_urlConsumers.RemoveElementAt(cnt - 1);
00599       }
00600     }
00601     cnt--;
00602   }
00603   
00604   return rv;
00605 }
00606 
00607 // if this url has a channel with an error, doom it and its mem cache entries,
00608 // and notify url listeners.
00609 nsresult nsImapIncomingServer::DoomUrlIfChannelHasError(nsIImapUrl *aImapUrl, PRBool *urlDoomed)
00610 {
00611   nsresult rv = NS_OK;
00612 
00613   nsCOMPtr<nsIMsgMailNewsUrl> aMailNewsUrl(do_QueryInterface(aImapUrl, &rv));
00614   
00615   if (aMailNewsUrl && aImapUrl)
00616   {
00617     nsCOMPtr <nsIImapMockChannel> mockChannel;
00618     
00619     if (NS_SUCCEEDED(aImapUrl->GetMockChannel(getter_AddRefs(mockChannel))) && mockChannel)
00620     {
00621       nsresult requestStatus;
00622       nsCOMPtr<nsIRequest> request = do_QueryInterface(mockChannel);
00623       if (!request)
00624         return NS_ERROR_FAILURE;
00625       request->GetStatus(&requestStatus);
00626       if (NS_FAILED(requestStatus))
00627       {
00628         nsresult res;
00629         *urlDoomed = PR_TRUE;
00630         nsImapProtocol::LogImapUrl("dooming url", aImapUrl);
00631         
00632         mockChannel->Close(); // try closing it to get channel listener nulled out.
00633         
00634         if (aMailNewsUrl)
00635         {
00636           nsCOMPtr<nsICacheEntryDescriptor>  cacheEntry;
00637           res = aMailNewsUrl->GetMemCacheEntry(getter_AddRefs(cacheEntry));
00638           if (NS_SUCCEEDED(res) && cacheEntry)
00639             cacheEntry->Doom();
00640           // we're aborting this url - tell listeners
00641           aMailNewsUrl->SetUrlState(PR_FALSE, NS_MSG_ERROR_URL_ABORTED);
00642         }
00643       }
00644     }
00645   }
00646   return rv;
00647 }
00648 
00649 NS_IMETHODIMP
00650 nsImapIncomingServer::RemoveConnection(nsIImapProtocol* aImapConnection)
00651 {
00652     PR_CEnterMonitor(this);
00653 
00654     if (aImapConnection)
00655         m_connectionCache->RemoveElement(aImapConnection);
00656 
00657     PR_CExitMonitor(this);
00658     return NS_OK;
00659 }
00660 
00661 PRBool
00662 nsImapIncomingServer::ConnectionTimeOut(nsIImapProtocol* aConnection)
00663 {
00664     PRBool retVal = PR_FALSE;
00665     if (!aConnection) return retVal;
00666     nsresult rv;
00667 
00668     PR_CEnterMonitor(this);
00669     PRInt32 timeoutInMinutes = 0;
00670     rv = GetTimeOutLimits(&timeoutInMinutes);
00671     if (NS_FAILED(rv) || timeoutInMinutes <= 0 || timeoutInMinutes > 29)
00672     {
00673         timeoutInMinutes = 29;
00674         SetTimeOutLimits(timeoutInMinutes);
00675     }
00676 
00677     PRTime cacheTimeoutLimits;
00678 
00679     LL_I2L(cacheTimeoutLimits, timeoutInMinutes * 60 * 1000000); // in
00680                                                               // microseconds
00681     PRTime lastActiveTimeStamp;
00682     rv = aConnection->GetLastActiveTimeStamp(&lastActiveTimeStamp);
00683 
00684     PRTime elapsedTime;
00685     LL_SUB(elapsedTime, PR_Now(), lastActiveTimeStamp);
00686     PRTime t;
00687     LL_SUB(t, elapsedTime, cacheTimeoutLimits);
00688     if (LL_GE_ZERO(t))
00689     {
00690         nsCOMPtr<nsIImapProtocol> aProtocol(do_QueryInterface(aConnection,
00691                                                               &rv));
00692         if (NS_SUCCEEDED(rv) && aProtocol)
00693         {
00694             m_connectionCache->RemoveElement(aConnection);
00695             aProtocol->TellThreadToDie(PR_FALSE);
00696             retVal = PR_TRUE;
00697         }
00698     }
00699     PR_CExitMonitor(this);
00700     return retVal;
00701 }
00702 
00703 nsresult
00704 nsImapIncomingServer::GetImapConnection(nsIEventQueue *aEventQueue, 
00705                                            nsIImapUrl * aImapUrl, 
00706                                            nsIImapProtocol ** aImapConnection)
00707 {
00708   nsresult rv = NS_OK;
00709   PRBool canRunUrlImmediately = PR_FALSE;
00710   PRBool canRunButBusy = PR_FALSE;
00711   nsCOMPtr<nsIImapProtocol> connection;
00712   nsCOMPtr<nsIImapProtocol> freeConnection;
00713   PRBool isBusy = PR_FALSE;
00714   PRBool isInboxConnection = PR_FALSE;
00715   nsXPIDLCString redirectorType;
00716 
00717   PR_CEnterMonitor(this);
00718 
00719   GetRedirectorType(getter_Copies(redirectorType));
00720   PRBool redirectLogon = !redirectorType.IsEmpty();
00721 
00722   PRInt32 maxConnections = 5; // default to be five
00723   rv = GetMaximumConnectionsNumber(&maxConnections);
00724   if (NS_FAILED(rv) || maxConnections == 0)
00725   {
00726       maxConnections = 5;
00727       rv = SetMaximumConnectionsNumber(maxConnections);
00728   }
00729   else if (maxConnections < 1)
00730   {   // forced to use at least 1
00731       maxConnections = 1;
00732       rv = SetMaximumConnectionsNumber(maxConnections);
00733   }
00734 
00735   PRUint32 cnt;
00736   rv = m_connectionCache->Count(&cnt);
00737   if (NS_FAILED(rv)) return rv;
00738 
00739   *aImapConnection = nsnull;
00740        // iterate through the connection cache for a connection that can handle this url.
00741   PRBool userCancelled = PR_FALSE;
00742 
00743   // loop until we find a connection that can run the url, or doesn't have to wait?
00744   for (PRUint32 i = 0; i < cnt && !canRunUrlImmediately && !canRunButBusy; i++) 
00745   {
00746     connection = do_QueryElementAt(m_connectionCache, i);
00747     if (connection)
00748     {
00749       if (ConnectionTimeOut(connection))
00750       {
00751         connection = nsnull;
00752         i--; cnt--; // if the connection times out, we'll remove it from the array,
00753             // so we need to adjust the array index.
00754       }
00755       else
00756       {
00757         rv = connection->CanHandleUrl(aImapUrl, &canRunUrlImmediately, &canRunButBusy);
00758 #ifdef DEBUG_bienvenu
00759         nsXPIDLCString curSelectedFolderName;
00760         if (connection)    
00761           connection->GetSelectedMailboxName(getter_Copies(curSelectedFolderName));
00762         // check that no other connection is in the same selected state.
00763         if (!curSelectedFolderName.IsEmpty())
00764         {
00765           for (PRUint32 j = 0; j < cnt; j++)
00766           {
00767             if (j != i)
00768             {
00769               nsCOMPtr<nsIImapProtocol> otherConnection = do_QueryElementAt(m_connectionCache, j);
00770               if (otherConnection)
00771               {
00772                 nsXPIDLCString otherSelectedFolderName;
00773                 otherConnection->GetSelectedMailboxName(getter_Copies(otherSelectedFolderName));
00774                 NS_ASSERTION(!curSelectedFolderName.Equals(otherSelectedFolderName), "two connections selected on same folder");
00775               }
00776 
00777             }
00778           }
00779         }
00780 #endif // DEBUG_bienvenu
00781       }
00782     }
00783     if (NS_FAILED(rv)) 
00784     {
00785         connection = nsnull;
00786         rv = NS_OK; // don't want to return this error, just don't use the connection
00787         continue;
00788     }
00789 
00790     // if this connection is wrong, but it's not busy, check if we should designate
00791     // it as the free connection.
00792     if (!canRunUrlImmediately && !canRunButBusy && connection)
00793     {
00794         rv = connection->IsBusy(&isBusy, &isInboxConnection);
00795         if (NS_FAILED(rv)) 
00796           continue;
00797         // if max connections is <= 1, we have to re-use the inbox connection.
00798         if (!isBusy && (!isInboxConnection || maxConnections <= 1))
00799         {
00800           if (!freeConnection)
00801             freeConnection = connection;
00802           else  // check which is the better free connection to use.
00803           {     // We prefer one not in the selected state.
00804             nsXPIDLCString selectedFolderName;
00805             connection->GetSelectedMailboxName(getter_Copies(selectedFolderName));
00806             if (selectedFolderName.IsEmpty())
00807               freeConnection = connection;
00808           }
00809         }
00810     }
00811     // don't leave this loop with connection set if we can't use it!
00812     if (!canRunButBusy && !canRunUrlImmediately)
00813       connection = nsnull;
00814   }
00815   
00816   if (ConnectionTimeOut(connection))
00817       connection = nsnull;
00818   if (ConnectionTimeOut(freeConnection))
00819     freeConnection = nsnull;
00820   
00821   if (!canRunButBusy && redirectLogon && (!connection || !canRunUrlImmediately))
00822   {
00823     // here's where we'd start the asynchronous process of requesting a connection to the 
00824     // AOL Imap server and getting back an ip address, port #, and cookie.
00825     // if m_overRideUrlConnectionInfo is true, then we can go ahead and make a connection to this server.
00826     // We should set some sort of timer on this override info.
00827     if (!m_waitingForConnectionInfo)
00828     {
00829       m_waitingForConnectionInfo = PR_TRUE;
00830       nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(aImapUrl, &rv);
00831       nsCOMPtr<nsIMsgWindow> aMsgWindow;
00832       if (NS_SUCCEEDED(rv)) 
00833         rv = mailnewsUrl->GetMsgWindow(getter_AddRefs(aMsgWindow));
00834       
00835       rv = RequestOverrideInfo(aMsgWindow);
00836       if (m_waitingForConnectionInfo)
00837       canRunButBusy = PR_TRUE;
00838       else 
00839         userCancelled = PR_TRUE;
00840     }    
00841   }
00842   nsImapState requiredState;
00843   aImapUrl->GetRequiredImapState(&requiredState);
00844   // refresh cnt in case we killed one or more dead connections. This
00845   // will prevent us from not spinning up a new connection when all
00846   // connections were dead.
00847   (void) m_connectionCache->Count(&cnt);
00848   // if we got here and we have a connection, then we should return it!
00849   if (canRunUrlImmediately && connection)
00850   {
00851     *aImapConnection = connection;
00852     NS_IF_ADDREF(*aImapConnection);
00853   }
00854   else if (canRunButBusy)
00855   {
00856       // do nothing; return NS_OK; for queuing
00857   }
00858   else if (userCancelled)
00859   {
00860     rv = NS_BINDING_ABORTED;  // user cancelled
00861   }
00862   // CanHandleUrl will pretend that some types of urls require a selected state url
00863   // (e.g., a folder delete or msg append) but we shouldn't create new connections
00864   // for these types of urls if we have a free connection. So we check the actual
00865   // required state here.
00866   else if (cnt < ((PRUint32)maxConnections) && aEventQueue 
00867       && (!freeConnection || requiredState == nsIImapUrl::nsImapSelectedState))
00868   {    
00869     rv = CreateProtocolInstance(aEventQueue, aImapConnection);
00870   }
00871   else if (freeConnection)
00872   {
00873     *aImapConnection = freeConnection;
00874     NS_IF_ADDREF(*aImapConnection);
00875   }
00876   else // cannot get anyone to handle the url queue it
00877   {
00878     if (cnt >= (PRUint32) maxConnections)
00879       nsImapProtocol::LogImapUrl("exceeded connection cache limit", aImapUrl);
00880 
00881       // caller will queue the url
00882   }
00883 
00884   PR_CExitMonitor(this);
00885   return rv;
00886 }
00887 
00888 nsresult
00889 nsImapIncomingServer::CreateProtocolInstance(nsIEventQueue *aEventQueue, 
00890                                              nsIImapProtocol ** aImapConnection)
00891 {
00892   // create a new connection and add it to the connection cache
00893   // we may need to flag the protocol connection as busy so we don't get
00894   // a race condition where someone else goes through this code 
00895 
00896   PRBool useSecAuth;
00897   GetUseSecAuth(&useSecAuth);
00898   nsresult rv;
00899   // pre-flight that we have nss - on the ui thread
00900   if (useSecAuth)
00901   {
00902     nsCOMPtr<nsISignatureVerifier> verifier = do_GetService(SIGNATURE_VERIFIER_CONTRACTID, &rv);
00903     NS_ENSURE_SUCCESS(rv, rv);
00904   }
00905   nsIImapProtocol * protocolInstance;
00906   rv = CallCreateInstance(kImapProtocolCID, &protocolInstance);
00907   if (NS_SUCCEEDED(rv) && protocolInstance)
00908   {
00909     nsCOMPtr<nsIImapHostSessionList> hostSession = 
00910       do_GetService(kCImapHostSessionListCID, &rv);
00911     if (NS_SUCCEEDED(rv))
00912       rv = protocolInstance->Initialize(hostSession, this, aEventQueue);
00913   }
00914   
00915   // take the protocol instance and add it to the connectionCache
00916   if (protocolInstance)
00917     m_connectionCache->AppendElement(protocolInstance);
00918   *aImapConnection = protocolInstance; // this is already ref counted.
00919   return rv;
00920 }
00921 
00922 NS_IMETHODIMP nsImapIncomingServer::CloseConnectionForFolder(nsIMsgFolder *aMsgFolder)
00923 {
00924     nsresult rv = NS_OK;
00925     nsCOMPtr<nsIImapProtocol> connection;
00926     PRBool isBusy = PR_FALSE, isInbox = PR_FALSE;
00927     PRUint32 cnt = 0;
00928     nsXPIDLCString inFolderName;
00929     nsXPIDLCString connectionFolderName;
00930     nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aMsgFolder);
00931 
00932     if (!imapFolder)
00933       return NS_ERROR_NULL_POINTER;
00934 
00935     rv = m_connectionCache->Count(&cnt);
00936     if (NS_FAILED(rv)) return rv;
00937 
00938     imapFolder->GetOnlineName(getter_Copies(inFolderName));
00939     PR_CEnterMonitor(this);
00940     
00941     for (PRUint32 i=0; i < cnt; i++)
00942     {
00943         connection = do_QueryElementAt(m_connectionCache, i);
00944         if (connection)
00945         {
00946             rv = connection->GetSelectedMailboxName(getter_Copies(connectionFolderName));
00947             if (PL_strcmp(connectionFolderName,inFolderName) == 0)
00948             {
00949                 rv = connection->IsBusy(&isBusy, &isInbox);
00950                 if (!isBusy)
00951                     rv = connection->TellThreadToDie(PR_TRUE);
00952                 break; // found it, end of the loop
00953             }
00954         }
00955     }
00956 
00957     PR_CExitMonitor(this);
00958     return rv;
00959 }
00960 
00961 NS_IMETHODIMP nsImapIncomingServer::ResetConnection(const char* folderName)
00962 {
00963     nsresult rv = NS_OK;
00964     nsCOMPtr<nsIImapProtocol> connection;
00965     PRBool isBusy = PR_FALSE, isInbox = PR_FALSE;
00966     PRUint32 cnt = 0;
00967     nsXPIDLCString curFolderName;
00968 
00969     rv = m_connectionCache->Count(&cnt);
00970     if (NS_FAILED(rv)) return rv;
00971 
00972     PR_CEnterMonitor(this);
00973     
00974     for (PRUint32 i=0; i < cnt; i++)
00975     {
00976         connection = do_QueryElementAt(m_connectionCache, i);
00977         if (connection)
00978         {
00979             rv = connection->GetSelectedMailboxName(getter_Copies(curFolderName));
00980             if (PL_strcmp(curFolderName,folderName) == 0)
00981             {
00982                 rv = connection->IsBusy(&isBusy, &isInbox);
00983                 if (!isBusy)
00984                     rv = connection->ResetToAuthenticatedState();
00985                 break; // found it, end of the loop
00986             }
00987         }
00988     }
00989 
00990     PR_CExitMonitor(this);
00991     return rv;
00992 }
00993 
00994 NS_IMETHODIMP 
00995 nsImapIncomingServer::PerformExpand(nsIMsgWindow *aMsgWindow)
00996 {
00997     nsXPIDLCString password;
00998     nsresult rv;
00999 
01000     
01001     rv = GetPassword(getter_Copies(password));
01002     if (NS_FAILED(rv)) return rv;
01003     if (password.IsEmpty())
01004         return NS_OK;
01005 
01006     rv = ResetFoldersToUnverified(nsnull);
01007     
01008     nsCOMPtr<nsIMsgFolder> rootMsgFolder;
01009     rv = GetRootFolder(getter_AddRefs(rootMsgFolder));
01010        if (NS_FAILED(rv)) return rv;
01011        if (!rootMsgFolder) return NS_ERROR_FAILURE;
01012 
01013     nsCOMPtr<nsIImapService> imapService = do_GetService(kImapServiceCID, &rv);
01014     if (NS_FAILED(rv)) return rv;
01015     if (!imapService) return NS_ERROR_FAILURE;
01016     nsCOMPtr<nsIEventQueue> queue;
01017     // get the Event Queue for this thread...
01018     nsCOMPtr<nsIEventQueueService> pEventQService = 
01019              do_GetService(kEventQueueServiceCID, &rv);
01020     if (NS_FAILED(rv)) return rv;
01021        if (!pEventQService) return NS_ERROR_FAILURE;
01022  
01023     rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
01024     if (NS_FAILED(rv)) return rv;
01025     rv = imapService->DiscoverAllFolders(queue, rootMsgFolder, this, aMsgWindow, nsnull);
01026        return rv;    
01027 }
01028 
01029 NS_IMETHODIMP nsImapIncomingServer::PerformBiff(nsIMsgWindow* aMsgWindow)
01030 {
01031   
01032   nsCOMPtr<nsIMsgFolder> rootMsgFolder;
01033   nsresult rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
01034   if(NS_SUCCEEDED(rv))
01035   {
01036     SetPerformingBiff(PR_TRUE);
01037     rv = rootMsgFolder->GetNewMessages(aMsgWindow, nsnull);
01038   }
01039   return rv;
01040 }
01041 
01042 
01043 NS_IMETHODIMP
01044 nsImapIncomingServer::CloseCachedConnections()
01045 {
01046   nsCOMPtr<nsIImapProtocol> connection;
01047   PR_CEnterMonitor(this);
01048   
01049   // iterate through the connection cache closing open connections.
01050   PRUint32 cnt;
01051   
01052   nsresult rv = m_connectionCache->Count(&cnt);
01053   if (NS_FAILED(rv)) return rv;
01054   
01055   for (PRUint32 i = cnt; i>0; i--)
01056   {
01057     connection = do_QueryElementAt(m_connectionCache, i-1);
01058     if (connection)
01059       connection->TellThreadToDie(PR_TRUE);
01060   }
01061 
01062   PR_CExitMonitor(this);
01063   return rv;
01064 }
01065 
01066 const char *nsImapIncomingServer::GetPFCName()
01067 {
01068   if (!m_readPFCName)
01069   {
01070     if(NS_SUCCEEDED(GetStringBundle()))
01071     {
01072       nsXPIDLString pfcName;
01073       nsresult res = m_stringBundle->GetStringFromID(IMAP_PERSONAL_FILING_CABINET, getter_Copies(pfcName));
01074       if (NS_SUCCEEDED(res))
01075         CopyUTF16toUTF8(pfcName, m_pfcName);
01076     }
01077     m_readPFCName = PR_TRUE;
01078   }
01079   return m_pfcName.get();
01080 }
01081 
01082 NS_IMETHODIMP nsImapIncomingServer::GetIsPFC(const char *folderName, PRBool *result)
01083 {
01084   NS_ENSURE_ARG(result);
01085   NS_ENSURE_ARG(folderName);
01086   *result = !nsCRT::strcmp(GetPFCName(), folderName);
01087   return NS_OK;
01088 }
01089 
01090 NS_IMETHODIMP nsImapIncomingServer::GetPFC(PRBool createIfMissing, nsIMsgFolder **pfcFolder)
01091 {
01092   nsresult rv;
01093   nsCOMPtr<nsIMsgAccountManager> accountManager = 
01094            do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
01095   if (NS_SUCCEEDED(rv))
01096   {
01097     nsCOMPtr <nsIMsgIncomingServer> server; 
01098     rv = accountManager->GetLocalFoldersServer(getter_AddRefs(server)); 
01099     if (NS_SUCCEEDED(rv) && server)
01100     {
01101       return server->GetRootMsgFolder(pfcFolder);
01102     }
01103   }
01104   return rv;
01105 }
01106 
01107 nsresult nsImapIncomingServer::GetPFCForStringId(PRBool createIfMissing, PRInt32 stringId, nsIMsgFolder **aFolder)
01108 {
01109   NS_ENSURE_ARG_POINTER(aFolder);
01110   nsCOMPtr <nsIMsgFolder> pfcParent;
01111 
01112   nsresult rv = GetPFC(createIfMissing, getter_AddRefs(pfcParent));
01113   NS_ENSURE_SUCCESS(rv, rv);
01114   nsXPIDLCString pfcURI;
01115   pfcParent->GetURI(getter_Copies(pfcURI));
01116 
01117   rv = GetStringBundle();
01118   NS_ENSURE_SUCCESS(rv, rv);
01119        nsXPIDLString pfcName;
01120        rv = m_stringBundle->GetStringFromID(stringId, getter_Copies(pfcName));
01121   NS_ENSURE_SUCCESS(rv, rv);
01122   nsCAutoString pfcMailUri(pfcURI);
01123 //  pfcMailUri.Append(".sbd");
01124   pfcMailUri.Append('/');
01125   AppendUTF16toUTF8(pfcName, pfcMailUri);
01126   pfcParent->GetChildWithURI(pfcMailUri.get(), PR_FALSE, PR_FALSE /* caseInsensitive*/, aFolder);
01127   if (!*aFolder && createIfMissing)
01128   {
01129               // get the URI from the incoming server
01130          nsCOMPtr<nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
01131     NS_ENSURE_SUCCESS(rv,rv);
01132 
01133     nsCOMPtr<nsIRDFResource> res;
01134          rv = rdf->GetResource(pfcMailUri, getter_AddRefs(res));
01135          NS_ENSURE_SUCCESS(rv, rv);
01136 
01137     nsCOMPtr <nsIMsgFolder> parentToCreate = do_QueryInterface(res, &rv);
01138     NS_ENSURE_SUCCESS(rv, rv);
01139     
01140     parentToCreate->SetParent(pfcParent);
01141     parentToCreate->CreateStorageIfMissing(nsnull);
01142     NS_IF_ADDREF(*aFolder = parentToCreate);
01143   }
01144   return rv;
01145 }
01146 
01147 NS_IMETHODIMP nsImapIncomingServer::GetReadMailPFC(PRBool createIfMissing, nsIMsgFolder **aFolder)
01148 {
01149   NS_ENSURE_ARG_POINTER(aFolder);
01150   return GetPFCForStringId(createIfMissing, IMAP_PFC_READ_MAIL, aFolder);
01151 }
01152 
01153 NS_IMETHODIMP nsImapIncomingServer::GetSentMailPFC(PRBool createIfMissing, nsIMsgFolder **aFolder)
01154 {
01155   NS_ENSURE_ARG_POINTER(aFolder);
01156   return GetPFCForStringId(createIfMissing, IMAP_PFC_SENT_MAIL, aFolder);
01157 }
01158 
01159 // nsIImapServerSink impl
01160 // aNewFolder will not be set if we're listing for the subscribe UI, since that's the way 4.x worked.
01161 NS_IMETHODIMP nsImapIncomingServer::PossibleImapMailbox(const char *folderPath, PRUnichar hierarchyDelimiter, 
01162                                                         PRInt32 boxFlags, PRBool *aNewFolder)
01163 {
01164   // folderPath is in canonical format, i.e., hierarchy separator has been replaced with '/'
01165   nsresult rv;
01166   PRBool found = PR_FALSE;
01167   PRBool haveParent = PR_FALSE;
01168   nsCOMPtr<nsIMsgImapMailFolder> hostFolder;
01169   nsCOMPtr<nsIMsgFolder> aFolder;
01170   PRBool explicitlyVerify = PR_FALSE;
01171     
01172   if (!folderPath || !*folderPath || !aNewFolder) return NS_ERROR_NULL_POINTER;
01173 
01174   *aNewFolder = PR_FALSE;
01175   nsCOMPtr<nsIMsgFolder> a_nsIFolder;
01176   rv = GetRootFolder(getter_AddRefs(a_nsIFolder));
01177 
01178   if(NS_FAILED(rv))
01179     return rv;
01180 
01181   nsCAutoString dupFolderPath(folderPath);
01182   if (dupFolderPath.Last() == hierarchyDelimiter)
01183   {
01184       dupFolderPath.SetLength(dupFolderPath.Length()-1);
01185       // *** this is what we did in 4.x in order to list uw folder only
01186       // mailbox in order to get the \NoSelect flag
01187       explicitlyVerify = !(boxFlags & kNameSpace);
01188   }
01189   if (mDoingSubscribeDialog) 
01190   {
01191     // Make sure the imapmailfolder object has the right delimiter because the unsubscribed
01192     // folders (those not in the 'lsub' list) have the delimiter set to the default ('^').
01193     if (a_nsIFolder && !dupFolderPath.IsEmpty())
01194     {
01195       nsCOMPtr<nsIMsgFolder> msgFolder;
01196       PRBool isNamespace = PR_FALSE;
01197       PRBool noSelect = PR_FALSE;
01198 
01199       rv = a_nsIFolder->FindSubFolder(dupFolderPath, getter_AddRefs(msgFolder));
01200       NS_ENSURE_SUCCESS(rv,rv);
01201       m_subscribeFolders.AppendObject(msgFolder);
01202       noSelect = (boxFlags & kNoselect) != 0;
01203       nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(msgFolder, &rv);
01204       NS_ENSURE_SUCCESS(rv,rv);
01205       imapFolder->SetHierarchyDelimiter(hierarchyDelimiter);
01206       isNamespace = (boxFlags & kNameSpace) != 0;
01207       if (!isNamespace)
01208         rv = AddTo(dupFolderPath, mDoingLsub && !noSelect/* add as subscribed */,
01209                    !noSelect, mDoingLsub /* change if exists */);
01210       NS_ENSURE_SUCCESS(rv,rv);
01211       return rv;
01212     }
01213   }
01214 
01215   hostFolder = do_QueryInterface(a_nsIFolder, &rv);
01216   if (NS_FAILED(rv))
01217     return rv;
01218 
01219   nsCAutoString tempFolderName(dupFolderPath);
01220   nsCAutoString tokenStr, remStr, changedStr;
01221   PRInt32 slashPos = tempFolderName.FindChar('/');
01222   if (slashPos > 0)
01223   {
01224     tempFolderName.Left(tokenStr,slashPos);
01225     tempFolderName.Right(remStr, tempFolderName.Length()-slashPos);
01226   }
01227   else
01228     tokenStr.Assign(tempFolderName);
01229   
01230   if ((nsCRT::strcasecmp(tokenStr.get(), "INBOX")==0) && (nsCRT::strcmp(tokenStr.get(), "INBOX") != 0))
01231     changedStr.Append("INBOX");
01232   else
01233     changedStr.Append(tokenStr);
01234 
01235   if (slashPos > 0 ) 
01236     changedStr.Append(remStr);
01237 
01238   dupFolderPath.Assign(changedStr);
01239   nsCAutoString folderName(dupFolderPath);
01240         
01241   nsCAutoString uri;
01242   nsXPIDLCString serverUri;
01243 
01244   GetServerURI(getter_Copies(serverUri));
01245   
01246   uri.Assign(serverUri);
01247   
01248   PRInt32 leafPos = folderName.RFindChar('/');
01249   
01250   nsCAutoString parentName(folderName);
01251   nsCAutoString parentUri(uri);
01252   
01253   if (leafPos > 0)
01254   {
01255     // If there is a hierarchy, there is a parent.
01256     // Don't strip off slash if it's the first character
01257     parentName.Truncate(leafPos);
01258     folderName.Cut(0, leafPos + 1);       // get rid of the parent name
01259     haveParent = PR_TRUE;
01260     parentUri.Append('/');
01261     parentUri.Append(parentName);
01262   }
01263   if (nsCRT::strcasecmp("INBOX", folderPath) == 0 &&
01264     hierarchyDelimiter == kOnlineHierarchySeparatorNil)
01265   {
01266     hierarchyDelimiter = '/'; // set to default in this case (as in 4.x)
01267     hostFolder->SetHierarchyDelimiter(hierarchyDelimiter);
01268   }
01269   
01270   // Check to see if we need to ignore this folder (like AOL's 'RECYCLE_OUT').
01271   PRBool hideFolder;
01272   rv = HideFolderName(dupFolderPath.get(), &hideFolder);
01273   if (hideFolder)
01274     return NS_OK;
01275   
01276   nsCOMPtr <nsIMsgFolder> child;
01277   
01278   //   nsCString possibleName(aSpec->allocatedPathName);
01279   
01280   
01281   uri.Append('/');
01282   uri.Append(dupFolderPath);
01283   
01284   
01285   PRBool caseInsensitive = (nsCRT::strcasecmp("INBOX", dupFolderPath.get()) == 0);
01286   a_nsIFolder->GetChildWithURI(uri.get(), PR_TRUE, caseInsensitive, getter_AddRefs(child));
01287   // if we couldn't find this folder by URI, tell the imap code it's a new folder to us
01288   *aNewFolder = !child;
01289   if (child)
01290     found = PR_TRUE;
01291   if (!found)
01292   {
01293     // trying to find/discover the parent
01294     if (haveParent)
01295     {  
01296       nsCOMPtr <nsIMsgFolder> parent;
01297       PRBool parentIsNew;
01298       caseInsensitive = (nsCRT::strcasecmp("INBOX", parentName.get()) == 0);
01299       a_nsIFolder->GetChildWithURI(parentUri.get(), PR_TRUE, caseInsensitive, getter_AddRefs(parent));
01300       if (!parent /* || parentFolder->GetFolderNeedsAdded()*/)
01301       {
01302         PossibleImapMailbox(parentName.get(), hierarchyDelimiter, kNoselect |       // be defensive
01303           ((boxFlags  &     //only inherit certain flags from the child
01304           (kPublicMailbox | kOtherUsersMailbox | kPersonalMailbox))), &parentIsNew); 
01305       }
01306     }
01307     
01308     hostFolder->CreateClientSubfolderInfo(dupFolderPath.get(), hierarchyDelimiter,boxFlags, PR_FALSE);
01309     caseInsensitive = (nsCRT::strcasecmp("INBOX", dupFolderPath.get())== 0);
01310     a_nsIFolder->GetChildWithURI(uri.get(), PR_TRUE, caseInsensitive , getter_AddRefs(child));
01311   }
01312   if (child)
01313   {
01314     nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(child);
01315     if (imapFolder)
01316     {
01317       PRBool isAOLServer = PR_FALSE;
01318       
01319       GetIsAOLServer(&isAOLServer);
01320       
01321       nsXPIDLCString onlineName;
01322       nsXPIDLString unicodeName;
01323       imapFolder->SetVerifiedAsOnlineFolder(PR_TRUE);
01324       imapFolder->SetHierarchyDelimiter(hierarchyDelimiter);
01325       if (boxFlags & kImapTrash)
01326       {
01327         PRInt32 deleteModel;
01328         GetDeleteModel(&deleteModel);
01329         if (deleteModel == nsMsgImapDeleteModels::MoveToTrash)
01330           child->SetFlag(MSG_FOLDER_FLAG_TRASH);
01331       }
01332       imapFolder->SetBoxFlags(boxFlags);
01333       imapFolder->SetExplicitlyVerify(explicitlyVerify);
01334       imapFolder->GetOnlineName(getter_Copies(onlineName));
01335       if (boxFlags & kNewlyCreatedFolder)
01336       {
01337         PRBool setNewFoldersForOffline = PR_FALSE;
01338         GetOfflineDownload(&setNewFoldersForOffline);
01339         if (setNewFoldersForOffline)
01340           child->SetFlag(MSG_FOLDER_FLAG_OFFLINE);
01341       }
01342       // online name needs to use the correct hierarchy delimiter (I think...)
01343       // or the canonical path - one or the other, but be consistent.
01344       dupFolderPath.ReplaceChar('/', hierarchyDelimiter);
01345       if (hierarchyDelimiter != '/')
01346         nsImapUrl::UnescapeSlashes(dupFolderPath.BeginWriting());
01347       
01348       if (onlineName.IsEmpty()
01349         || nsCRT::strcmp(onlineName.get(), dupFolderPath.get()))
01350         imapFolder->SetOnlineName(dupFolderPath.get());
01351       if (hierarchyDelimiter != '/')
01352         nsImapUrl::UnescapeSlashes(folderName.BeginWriting());
01353       if (NS_SUCCEEDED(CopyMUTF7toUTF16(folderName, unicodeName)))
01354         child->SetPrettyName(unicodeName);
01355       // Call ConvertFolderName() and HideFolderName() to do special folder name
01356       // mapping and hiding, if configured to do so. For example, need to hide AOL's
01357       // 'RECYCLE_OUT' & convert a few AOL folder names. Regular imap accounts
01358       // will do no-op in the calls.
01359       nsXPIDLString convertedName;
01360       PRBool hideFolder;
01361       rv = HideFolderName(onlineName.get(), &hideFolder);
01362       if (hideFolder)
01363       {
01364         nsCOMPtr<nsISupports> support(do_QueryInterface(child, &rv));
01365         a_nsIFolder->PropagateDelete(child, PR_FALSE, nsnull);
01366       }
01367       else
01368       {
01369         rv = ConvertFolderName(onlineName.get(), getter_Copies(convertedName));
01370 
01371         //make sure rv value is not crunched, it is used to SetPrettyName
01372         nsXPIDLCString redirectorType;
01373         GetRedirectorType(getter_Copies(redirectorType)); //Sent mail folder as per aol/netscape webmail
01374         if ((redirectorType.EqualsLiteral("aol") && onlineName.EqualsLiteral("Sent Items"))
01375           || (redirectorType.EqualsLiteral("netscape") && onlineName.EqualsLiteral("Sent")))
01376           //we know that we don't allowConversion for netscape webmail so just use the onlineName
01377           child->SetFlag(MSG_FOLDER_FLAG_SENTMAIL);
01378 
01379         else if (redirectorType.EqualsLiteral("netscape") && onlineName.EqualsLiteral("Draft"))
01380           child->SetFlag(MSG_FOLDER_FLAG_DRAFTS);
01381 
01382         else if (redirectorType.EqualsLiteral("aol") && onlineName.EqualsLiteral("RECYCLE"))
01383           child->SetFlag(MSG_FOLDER_FLAG_TRASH);
01384 
01385         if (NS_SUCCEEDED(rv))
01386           child->SetPrettyName(convertedName);
01387       }
01388     }
01389   }
01390   if (!found && child)
01391     child->SetMsgDatabase(nsnull); // close the db, so we don't hold open all the .msf files for new folders
01392   return NS_OK;
01393 }
01394 
01395 NS_IMETHODIMP nsImapIncomingServer::AddFolderRights(const char *mailboxName, const char *userName, const char *rights)
01396 {
01397   nsCOMPtr <nsIMsgFolder> rootFolder;
01398   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
01399   if(NS_SUCCEEDED(rv) && rootFolder)
01400   {
01401     nsCOMPtr <nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
01402     if (imapRoot)
01403     {
01404       nsCOMPtr <nsIMsgImapMailFolder> foundFolder;
01405       rv = imapRoot->FindOnlineSubFolder(mailboxName, getter_AddRefs(foundFolder));
01406       if (NS_SUCCEEDED(rv) && foundFolder)
01407         return foundFolder->AddFolderRights(userName, rights);
01408     }
01409   }
01410   return rv;
01411 }
01412 
01413 NS_IMETHODIMP nsImapIncomingServer::FolderNeedsACLInitialized(const char *folderPath, PRBool *aNeedsACLInitialized)
01414 {
01415   NS_ENSURE_ARG_POINTER(aNeedsACLInitialized);
01416   nsCOMPtr <nsIMsgFolder> rootFolder;
01417   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
01418   if(NS_SUCCEEDED(rv) && rootFolder)
01419   {
01420     nsCOMPtr <nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
01421     if (imapRoot)
01422     {
01423       nsCOMPtr <nsIMsgImapMailFolder> foundFolder;
01424       rv = imapRoot->FindOnlineSubFolder(folderPath, getter_AddRefs(foundFolder));
01425       if (NS_SUCCEEDED(rv) && foundFolder)
01426       {
01427         nsCOMPtr <nsIImapMailFolderSink> folderSink = do_QueryInterface(foundFolder);
01428         if (folderSink)
01429           return folderSink->GetFolderNeedsACLListed(aNeedsACLInitialized);
01430       }
01431     }
01432   }
01433   *aNeedsACLInitialized = PR_FALSE; // maybe we want to say TRUE here...
01434   return NS_OK;
01435 }
01436 
01437 NS_IMETHODIMP nsImapIncomingServer::RefreshFolderRights(const char *folderPath)
01438 {
01439   nsCOMPtr <nsIMsgFolder> rootFolder;
01440   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
01441   if(NS_SUCCEEDED(rv) && rootFolder)
01442   {
01443     nsCOMPtr <nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
01444     if (imapRoot)
01445     {
01446       nsCOMPtr <nsIMsgImapMailFolder> foundFolder;
01447       rv = imapRoot->FindOnlineSubFolder(folderPath, getter_AddRefs(foundFolder));
01448       if (NS_SUCCEEDED(rv) && foundFolder)
01449         return foundFolder->RefreshFolderRights();
01450     }
01451   }
01452   return rv;
01453 }
01454 
01455 NS_IMETHODIMP nsImapIncomingServer::GetRedirectorType(char **redirectorType)
01456 {
01457   if (m_readRedirectorType)
01458   {
01459     *redirectorType = ToNewCString(m_redirectorType);
01460     return NS_OK;
01461   }
01462   nsresult rv;
01463   
01464   // Differentiate 'aol' and non-aol redirector type.
01465   rv = GetCharValue("redirector_type", redirectorType);
01466   m_redirectorType = *redirectorType;
01467   m_readRedirectorType = PR_TRUE;
01468 
01469   if (*redirectorType)  
01470   {
01471     // we used to use "aol" as the redirector type  
01472     // for both aol mail and webmail
01473     // this code migrates webmail accounts to use "netscape" as the
01474     // redirectory type
01475     if (!nsCRT::strcasecmp(*redirectorType, "aol"))  
01476     {
01477       nsXPIDLCString hostName;
01478       GetHostName(getter_Copies(hostName));
01479     
01480       if (hostName.get() && !nsCRT::strcasecmp(hostName, "imap.mail.netcenter.com"))
01481         SetRedirectorType("netscape");
01482     }
01483   }
01484   else 
01485   {
01486     // for people who have migrated from 4.x or outlook, or mistakenly
01487     // created redirected accounts as regular imap accounts, 
01488     // they won't have redirector type set properly
01489     // this fixes the redirector type for them automatically
01490     nsCAutoString prefName;
01491     rv = CreateHostSpecificPrefName("default_redirector_type", prefName);
01492     NS_ENSURE_SUCCESS(rv,rv);
01493 
01494     nsXPIDLCString defaultRedirectorType;
01495   
01496     nsCOMPtr <nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01497     NS_ENSURE_SUCCESS(rv,rv);
01498 
01499     nsCOMPtr<nsIPrefBranch> prefBranch; 
01500     rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch)); 
01501     NS_ENSURE_SUCCESS(rv,rv);
01502 
01503     rv = prefBranch->GetCharPref(prefName.get(), getter_Copies(defaultRedirectorType));
01504     if (NS_SUCCEEDED(rv) && !defaultRedirectorType.IsEmpty()) 
01505     {
01506       // only set redirectory type in memory
01507       // if we call SetRedirectorType() that sets it in prefs
01508       // which makes this automatic redirector type repair permanent
01509       m_redirectorType = defaultRedirectorType.get();
01510     }
01511   }
01512   return NS_OK;
01513 }
01514 
01515 NS_IMETHODIMP nsImapIncomingServer::SetRedirectorType(const char *redirectorType)
01516 {
01517   m_redirectorType = redirectorType;
01518   return (SetCharValue("redirector_type", redirectorType));
01519 }
01520 
01521 NS_IMETHODIMP nsImapIncomingServer::GetTrashFolderByRedirectorType(char **specialTrashName)
01522 {
01523   NS_ENSURE_ARG_POINTER(specialTrashName);
01524   *specialTrashName = nsnull;
01525   nsresult rv;
01526 
01527   // see if it has a predefined trash folder name. The pref setting is like:
01528   //    pref("imap.aol.trashFolder", "RECYCLE");  where the redirector type = 'aol'
01529   nsCAutoString prefName;
01530   rv = CreatePrefNameWithRedirectorType(".trashFolder", prefName);
01531   if (NS_FAILED(rv)) 
01532     return NS_OK; // return if no redirector type
01533 
01534   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01535   NS_ENSURE_SUCCESS(rv,rv);
01536 
01537   rv = prefBranch->GetCharPref(prefName.get(), specialTrashName);
01538   if (NS_SUCCEEDED(rv) && ((!*specialTrashName) || (!**specialTrashName)))
01539     return NS_ERROR_FAILURE;
01540 
01541   return rv;
01542 }
01543 
01544 NS_IMETHODIMP nsImapIncomingServer::AllowFolderConversion(PRBool *allowConversion)
01545 {
01546   NS_ENSURE_ARG_POINTER(allowConversion);
01547 
01548   nsresult rv;
01549   *allowConversion = PR_FALSE;
01550 
01551   // See if the redirector type allows folder name conversion. The pref setting is like:
01552   //    pref("imap.aol.convertFolders",true);     where the redirector type = 'aol'
01553   // Construct pref name (like "imap.aol.hideFolders.RECYCLE_OUT") and get the setting.
01554   nsCAutoString prefName;
01555   rv = CreatePrefNameWithRedirectorType(".convertFolders", prefName);
01556   if (NS_FAILED(rv)) 
01557     return NS_OK; // return if no redirector type
01558 
01559   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01560   NS_ENSURE_SUCCESS(rv,rv);
01561 
01562   // In case this pref is not set we need to return NS_OK.
01563   prefBranch->GetBoolPref(prefName.get(), allowConversion);
01564   return NS_OK;
01565 }
01566 
01567 NS_IMETHODIMP nsImapIncomingServer::ConvertFolderName(const char *originalName, PRUnichar **convertedName)
01568 {
01569   NS_ENSURE_ARG_POINTER(convertedName);
01570 
01571   nsresult rv = NS_OK;
01572   *convertedName = nsnull;
01573 
01574   // See if the redirector type allows folder name conversion.
01575   PRBool allowConversion;
01576   rv = AllowFolderConversion(&allowConversion);
01577   if (NS_SUCCEEDED(rv) && !allowConversion)
01578     return NS_ERROR_FAILURE;
01579 
01580   // Get string bundle based on redirector type and convert folder name.
01581   nsCOMPtr<nsIStringBundle> stringBundle;
01582   nsCAutoString propertyURL;
01583   nsXPIDLCString redirectorType;
01584   GetRedirectorType(getter_Copies(redirectorType));
01585   if (!redirectorType)
01586     return NS_ERROR_FAILURE; // return if no redirector type
01587 
01588   propertyURL = "chrome://messenger/locale/";
01589   propertyURL.Append(redirectorType);
01590   propertyURL.Append("-imap.properties");
01591 
01592   nsCOMPtr<nsIStringBundleService> sBundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
01593   if (NS_SUCCEEDED(rv) && (nsnull != sBundleService)) 
01594     rv = sBundleService->CreateBundle(propertyURL.get(), getter_AddRefs(stringBundle));
01595   if (NS_SUCCEEDED(rv))
01596     rv = stringBundle->GetStringFromName(NS_ConvertASCIItoUCS2(originalName).get(), convertedName);
01597 
01598   if (NS_SUCCEEDED(rv) && ((!*convertedName) || (!**convertedName)))
01599     return NS_ERROR_FAILURE;
01600   else
01601     return rv;
01602   }
01603 
01604 NS_IMETHODIMP nsImapIncomingServer::HideFolderName(const char *folderName, PRBool *hideFolder)
01605 {
01606   NS_ENSURE_ARG_POINTER(hideFolder);
01607 
01608   nsresult rv;
01609   *hideFolder = PR_FALSE;
01610 
01611   if (!folderName || !*folderName) return NS_OK;
01612 
01613   // See if the redirector type allows folder hiding. The pref setting is like:
01614   //    pref("imap.aol.hideFolders.RECYCLE_OUT",true);    where the redirector type = 'aol'
01615   nsCAutoString prefName;
01616   rv = CreatePrefNameWithRedirectorType(".hideFolder.", prefName);
01617   if (NS_FAILED(rv)) 
01618     return NS_OK; // return if no redirector type
01619 
01620   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01621   NS_ENSURE_SUCCESS(rv,rv);
01622 
01623   prefName.Append(folderName);
01624   // In case this pref is not set we need to return NS_OK.
01625   prefBranch->GetBoolPref(prefName.get(), hideFolder);
01626   return NS_OK;
01627 }
01628 
01629 nsresult nsImapIncomingServer::GetFolder(const char* name, nsIMsgFolder** pFolder)
01630 {
01631     nsresult rv = NS_ERROR_NULL_POINTER;
01632     if (!name || !*name || !pFolder) return rv;
01633     *pFolder = nsnull;
01634     nsCOMPtr<nsIMsgFolder> rootFolder;
01635     rv = GetRootFolder(getter_AddRefs(rootFolder));
01636     if (NS_SUCCEEDED(rv) && rootFolder)
01637     {
01638         nsXPIDLCString uri;
01639         rv = rootFolder->GetURI(getter_Copies(uri));
01640         if (NS_SUCCEEDED(rv) && uri)
01641         {
01642           nsCAutoString uriString(uri);
01643           uriString.Append('/');
01644           uriString.Append(name);
01645           nsCOMPtr<nsIRDFService> rdf(do_GetService(kRDFServiceCID, &rv));
01646           if (NS_FAILED(rv)) return rv;
01647           nsCOMPtr<nsIRDFResource> res;
01648           rv = rdf->GetResource(uriString, getter_AddRefs(res));
01649           if (NS_SUCCEEDED(rv))
01650           {
01651               nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(res, &rv));
01652               if (NS_SUCCEEDED(rv) && folder)
01653               {
01654                   *pFolder = folder;
01655                   NS_ADDREF(*pFolder);
01656               }
01657           }
01658         }
01659     }
01660     return rv;
01661 }
01662 
01663 NS_IMETHODIMP  nsImapIncomingServer::OnlineFolderDelete(const char *aFolderName) 
01664 {
01665   return NS_OK;
01666 }
01667 
01668 NS_IMETHODIMP  nsImapIncomingServer::OnlineFolderCreateFailed(const char *aFolderName) 
01669 {
01670   return NS_OK;
01671 }
01672 
01673 NS_IMETHODIMP nsImapIncomingServer::OnlineFolderRename(nsIMsgWindow *msgWindow, const char *oldName, const char *newName)
01674 {
01675   nsresult rv = NS_ERROR_FAILURE;
01676   if (newName && *newName)
01677   {
01678     nsCOMPtr<nsIMsgFolder> me;
01679     rv = GetFolder(oldName, getter_AddRefs(me));
01680     if (NS_FAILED(rv)) 
01681       return rv;
01682         
01683               nsCOMPtr<nsIMsgFolder> parent;
01684     nsCAutoString newNameString(newName);
01685     nsCAutoString parentName;
01686     PRInt32 folderStart = newNameString.RFindChar('/');
01687     if (folderStart > 0)
01688     {
01689       newNameString.Left(parentName, folderStart);
01690       rv = GetFolder(parentName.get(),getter_AddRefs(parent));
01691     }
01692     else  // root is the parent
01693     {
01694       rv = GetRootFolder(getter_AddRefs(parent));
01695     }
01696     if (NS_SUCCEEDED(rv) && parent) 
01697     {
01698       nsCOMPtr<nsIMsgImapMailFolder> folder;
01699       folder = do_QueryInterface(me, &rv);
01700       if (NS_SUCCEEDED(rv))
01701       {
01702         folder->RenameLocal(newName,parent);
01703         nsCOMPtr<nsIMsgImapMailFolder> parentImapFolder = do_QueryInterface(parent);
01704 
01705         if (parentImapFolder)
01706           parentImapFolder->RenameClient(msgWindow, me,oldName, newName);
01707         
01708         nsCOMPtr <nsIMsgFolder> newFolder;
01709         rv = GetFolder(newName, getter_AddRefs(newFolder));
01710         if (NS_SUCCEEDED(rv))
01711         {
01712           nsCOMPtr <nsIAtom> folderRenameAtom;
01713           folderRenameAtom = do_GetAtom("RenameCompleted");
01714           newFolder->NotifyFolderEvent(folderRenameAtom);
01715         }
01716       }
01717     }
01718   }
01719   return rv;
01720 }
01721 
01722 NS_IMETHODIMP  nsImapIncomingServer::FolderIsNoSelect(const char *aFolderName, PRBool *result) 
01723 {
01724    if (!result)
01725       return NS_ERROR_NULL_POINTER;   
01726    nsCOMPtr<nsIMsgFolder> msgFolder;
01727    nsresult rv = GetFolder(aFolderName, getter_AddRefs(msgFolder));
01728    if (NS_SUCCEEDED(rv) && msgFolder)
01729    {
01730      PRUint32 flags;
01731      msgFolder->GetFlags(&flags);
01732      *result = ((flags & MSG_FOLDER_FLAG_IMAP_NOSELECT) != 0);
01733    }
01734    else
01735      *result = PR_FALSE;
01736    return NS_OK;
01737 }
01738 
01739 NS_IMETHODIMP nsImapIncomingServer::SetFolderAdminURL(const char *aFolderName, const char *aFolderAdminUrl)
01740 {
01741   nsCOMPtr <nsIMsgFolder> rootFolder;
01742   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
01743   if(NS_SUCCEEDED(rv) && rootFolder)
01744   {
01745     nsCOMPtr <nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
01746     if (imapRoot)
01747     {
01748       nsCOMPtr <nsIMsgImapMailFolder> foundFolder;
01749       rv = imapRoot->FindOnlineSubFolder(aFolderName, getter_AddRefs(foundFolder));
01750       if (NS_SUCCEEDED(rv) && foundFolder)
01751         return foundFolder->SetAdminUrl(aFolderAdminUrl);
01752     }
01753   }
01754   return rv;
01755 }
01756 
01757 NS_IMETHODIMP  nsImapIncomingServer::FolderVerifiedOnline(const char *folderName, PRBool *aResult) 
01758 {
01759   NS_ENSURE_ARG_POINTER(aResult);
01760   *aResult = PR_FALSE;
01761   nsCOMPtr<nsIMsgFolder> rootFolder;
01762   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
01763   if (NS_SUCCEEDED(rv) && rootFolder)
01764   {
01765     nsCOMPtr<nsIMsgFolder> aFolder;
01766     rv = rootFolder->FindSubFolder(nsDependentCString(folderName), getter_AddRefs(aFolder));
01767     if (NS_SUCCEEDED(rv) && aFolder)
01768     {
01769       nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aFolder);
01770       if (imapFolder)
01771         imapFolder->GetVerifiedAsOnlineFolder(aResult);
01772     }
01773   }
01774   return rv;
01775 }
01776 
01777 NS_IMETHODIMP nsImapIncomingServer::DiscoveryDone()
01778 {
01779   nsresult rv = NS_ERROR_FAILURE;
01780   //   m_haveDiscoveredAllFolders = PR_TRUE;
01781   
01782   if (mDoingSubscribeDialog)
01783     return NS_OK;
01784   nsCOMPtr<nsIMsgFolder> rootMsgFolder;
01785   rv = GetRootFolder(getter_AddRefs(rootMsgFolder));
01786   if (NS_SUCCEEDED(rv) && rootMsgFolder)
01787   {
01788     rootMsgFolder->SetPrefFlag();
01789     
01790     // Verify there is only one trash folder. Another might be present if 
01791     // the trash name has been changed.
01792     PRUint32 numFolders;
01793     rv = rootMsgFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_TRASH, 0, &numFolders, NULL);
01794     
01795     if (NS_SUCCEEDED(rv) && numFolders > 1)
01796     {
01797       nsXPIDLString trashName;
01798       if (NS_SUCCEEDED(GetTrashFolderName(getter_Copies(trashName))))
01799       {
01800         nsIMsgFolder *trashFolders[2];
01801         if (NS_SUCCEEDED(rootMsgFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_TRASH, 2, 
01802           &numFolders, trashFolders)))
01803         {
01804           for (PRUint32 i = 0; i < numFolders; i++)
01805           {
01806             nsXPIDLString folderName;
01807             if (NS_SUCCEEDED(trashFolders[i]->GetName(getter_Copies(folderName))))
01808             {
01809               if (!folderName.Equals(trashName))
01810                 trashFolders[i]->ClearFlag(MSG_FOLDER_FLAG_TRASH);
01811             }
01812 
01813             NS_RELEASE(trashFolders[i]);
01814           }
01815         }
01816       }
01817     }
01818   }
01819   
01820   PRInt32 numUnverifiedFolders;
01821   nsCOMPtr<nsISupportsArray> unverifiedFolders;
01822   
01823   rv = NS_NewISupportsArray(getter_AddRefs(unverifiedFolders));
01824   if(NS_FAILED(rv))
01825     return rv;
01826   
01827   PRBool usingSubscription = PR_TRUE;
01828   GetUsingSubscription(&usingSubscription);
01829 
01830   rv = GetUnverifiedFolders(unverifiedFolders, &numUnverifiedFolders);
01831   if (numUnverifiedFolders > 0)
01832   {
01833     for (PRInt32 k = 0; k < numUnverifiedFolders; k++)
01834     {
01835       PRBool explicitlyVerify = PR_FALSE;
01836       PRBool hasSubFolders = PR_FALSE;
01837       PRUint32 folderFlags;
01838       nsCOMPtr<nsISupports> element;
01839       unverifiedFolders->GetElementAt(k, getter_AddRefs(element));
01840       
01841       nsCOMPtr<nsIMsgImapMailFolder> currentImapFolder = do_QueryInterface(element, &rv);
01842       nsCOMPtr<nsIMsgFolder> currentFolder = do_QueryInterface(element, &rv);
01843       if (NS_FAILED(rv))
01844         continue;
01845       currentFolder->GetFlags(&folderFlags);
01846       if (folderFlags & MSG_FOLDER_FLAG_VIRTUAL) // don't remove virtual folders
01847         continue;
01848       if ((!usingSubscription || (NS_SUCCEEDED(currentImapFolder->GetExplicitlyVerify(&explicitlyVerify)) && explicitlyVerify)) ||
01849         ((NS_SUCCEEDED(currentFolder->GetHasSubFolders(&hasSubFolders)) && hasSubFolders)
01850         && !NoDescendentsAreVerified(currentFolder)))
01851       {
01852         PRBool isNamespace;
01853         currentImapFolder->GetIsNamespace(&isNamespace);
01854         if (!isNamespace) // don't list namespaces explicitly
01855         {
01856           // If there are no subfolders and this is unverified, we don't want to run
01857           // this url.  That is, we want to undiscover the folder.
01858           // If there are subfolders and no descendants are verified, we want to 
01859           // undiscover all of the folders.
01860           // Only if there are subfolders and at least one of them is verified do we want
01861           // to refresh that folder's flags, because it won't be going away.
01862           currentImapFolder->SetExplicitlyVerify(PR_FALSE);
01863           currentImapFolder->List();
01864         }
01865       }
01866       else
01867       {
01868         DeleteNonVerifiedFolders(currentFolder);
01869       }
01870     }
01871   }
01872   
01873   return rv;
01874 }
01875 
01876 nsresult nsImapIncomingServer::DeleteNonVerifiedFolders(nsIMsgFolder *curFolder)
01877 {
01878   PRBool autoUnsubscribeFromNoSelectFolders = PR_TRUE;
01879   nsresult rv;
01880   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01881   if (NS_SUCCEEDED(rv))
01882     prefBranch->GetBoolPref("mail.imap.auto_unsubscribe_from_noselect_folders", &autoUnsubscribeFromNoSelectFolders);
01883   
01884   nsCOMPtr<nsIEnumerator> subFolders;
01885   
01886   rv = curFolder->GetSubFolders(getter_AddRefs(subFolders));
01887   if(NS_SUCCEEDED(rv))
01888   {
01889     nsAdapterEnumerator *simpleEnumerator = new nsAdapterEnumerator(subFolders);
01890     if (simpleEnumerator == nsnull)
01891       return NS_ERROR_OUT_OF_MEMORY;
01892     PRBool moreFolders;
01893     
01894     while (NS_SUCCEEDED(simpleEnumerator->HasMoreElements(&moreFolders)) && moreFolders)
01895     {
01896       nsCOMPtr<nsISupports> child;
01897       rv = simpleEnumerator->GetNext(getter_AddRefs(child));
01898       if (NS_SUCCEEDED(rv) && child) 
01899       {
01900         PRBool childVerified = PR_FALSE;
01901         nsCOMPtr <nsIMsgImapMailFolder> childImapFolder = do_QueryInterface(child, &rv);
01902         if (NS_SUCCEEDED(rv) && childImapFolder)
01903         {
01904           PRUint32 flags;
01905           
01906           nsCOMPtr <nsIMsgFolder> childFolder = do_QueryInterface(child, &rv);
01907           rv = childImapFolder->GetVerifiedAsOnlineFolder(&childVerified);
01908           
01909           rv = childFolder->GetFlags(&flags);
01910           PRBool folderIsNoSelectFolder = NS_SUCCEEDED(rv) && ((flags & MSG_FOLDER_FLAG_IMAP_NOSELECT) != 0);
01911           
01912           PRBool usingSubscription = PR_TRUE;
01913           GetUsingSubscription(&usingSubscription);
01914           if (usingSubscription)
01915           {
01916             PRBool folderIsNameSpace = PR_FALSE;
01917             PRBool noDescendentsAreVerified = NoDescendentsAreVerified(childFolder);
01918             PRBool shouldDieBecauseNoSelect = (folderIsNoSelectFolder ? 
01919               ((noDescendentsAreVerified || AllDescendentsAreNoSelect(childFolder)) && !folderIsNameSpace)
01920               : PR_FALSE);
01921             if (!childVerified && (noDescendentsAreVerified || shouldDieBecauseNoSelect))
01922             {
01923             }
01924             
01925           }
01926           else
01927           {
01928           }
01929         }
01930       }
01931     }
01932     delete simpleEnumerator;
01933   }
01934   
01935     
01936   nsCOMPtr<nsIMsgFolder> parent;
01937   rv = curFolder->GetParent(getter_AddRefs(parent));
01938   
01939   if (NS_SUCCEEDED(rv) && parent)
01940   {
01941     nsCOMPtr<nsIMsgImapMailFolder> imapParent = do_QueryInterface(parent);
01942     if (imapParent)
01943       imapParent->RemoveSubFolder(curFolder);
01944   }
01945   
01946   return rv;
01947 }
01948 
01949 
01950 PRBool nsImapIncomingServer::NoDescendentsAreVerified(nsIMsgFolder *parentFolder)
01951 {
01952   PRBool nobodyIsVerified = PR_TRUE;
01953   
01954   nsCOMPtr<nsIEnumerator> subFolders;
01955   
01956   nsresult rv = parentFolder->GetSubFolders(getter_AddRefs(subFolders));
01957   if(NS_SUCCEEDED(rv))
01958   {
01959     nsAdapterEnumerator *simpleEnumerator =      new nsAdapterEnumerator(subFolders);
01960     if (simpleEnumerator == nsnull)
01961       return NS_ERROR_OUT_OF_MEMORY;
01962     PRBool moreFolders;
01963     
01964     while (NS_SUCCEEDED(simpleEnumerator->HasMoreElements(&moreFolders)) && moreFolders && nobodyIsVerified)
01965     {
01966       nsCOMPtr<nsISupports> child;
01967       rv = simpleEnumerator->GetNext(getter_AddRefs(child));
01968       if (NS_SUCCEEDED(rv) && child) 
01969       {
01970         PRBool childVerified = PR_FALSE;
01971         nsCOMPtr <nsIMsgImapMailFolder> childImapFolder = do_QueryInterface(child, &rv);
01972         if (NS_SUCCEEDED(rv) && childImapFolder)
01973         {
01974           nsCOMPtr <nsIMsgFolder> childFolder = do_QueryInterface(child, &rv);
01975           rv = childImapFolder->GetVerifiedAsOnlineFolder(&childVerified);
01976           nobodyIsVerified = !childVerified && NoDescendentsAreVerified(childFolder);
01977         }
01978       }
01979     }
01980     delete simpleEnumerator;
01981   }
01982   
01983   return nobodyIsVerified;
01984 }
01985 
01986 
01987 PRBool nsImapIncomingServer::AllDescendentsAreNoSelect(nsIMsgFolder *parentFolder)
01988 {
01989   PRBool allDescendentsAreNoSelect = PR_TRUE;
01990   nsCOMPtr<nsIEnumerator> subFolders;
01991   
01992   nsresult rv = parentFolder->GetSubFolders(getter_AddRefs(subFolders));
01993   if(NS_SUCCEEDED(rv))
01994   {
01995     nsAdapterEnumerator *simpleEnumerator =      new nsAdapterEnumerator(subFolders);
01996     if (simpleEnumerator == nsnull)
01997       return NS_ERROR_OUT_OF_MEMORY;
01998     PRBool moreFolders;
01999     
02000     while (NS_SUCCEEDED(simpleEnumerator->HasMoreElements(&moreFolders)) && moreFolders && allDescendentsAreNoSelect)
02001     {
02002       nsCOMPtr<nsISupports> child;
02003       rv = simpleEnumerator->GetNext(getter_AddRefs(child));
02004       if (NS_SUCCEEDED(rv) && child) 
02005       {
02006         PRBool childIsNoSelect = PR_FALSE;
02007         nsCOMPtr <nsIMsgImapMailFolder> childImapFolder = do_QueryInterface(child, &rv);
02008         if (NS_SUCCEEDED(rv) && childImapFolder)
02009         {
02010           PRUint32 flags;
02011           
02012           nsCOMPtr <nsIMsgFolder> childFolder = do_QueryInterface(child, &rv);
02013           rv = childFolder->GetFlags(&flags);
02014           childIsNoSelect = NS_SUCCEEDED(rv) && (flags & MSG_FOLDER_FLAG_IMAP_NOSELECT);
02015           allDescendentsAreNoSelect = !childIsNoSelect && AllDescendentsAreNoSelect(childFolder);
02016         }
02017       }
02018     }
02019     delete simpleEnumerator;
02020   }
02021 #if 0
02022   int numberOfSubfolders = parentFolder->GetNumSubFolders();
02023   
02024   for (int childIndex=0; allDescendantsAreNoSelect && (childIndex < numberOfSubfolders); childIndex++)
02025   {
02026     MSG_IMAPFolderInfoMail *currentChild = (MSG_IMAPFolderInfoMail *) parentFolder->GetSubFolder(childIndex);
02027     allDescendentsAreNoSelect = (currentChild->GetFolderPrefFlags() & MSG_FOLDER_PREF_IMAPNOSELECT) &&
02028       AllDescendentsAreNoSelect(currentChild);
02029   }
02030 #endif // 0
02031   return allDescendentsAreNoSelect;
02032 }
02033 
02034 
02035 #if 0
02036 void nsImapIncomingServer::UnsubscribeFromAllDescendents(nsIMsgFolder *parentFolder)
02037 {
02038   int numberOfSubfolders = parentFolder->GetNumSubFolders();
02039   
02040   for (int childIndex=0; childIndex < numberOfSubfolders; childIndex++)
02041   {
02042     MSG_IMAPFolderInfoMail *currentChild = (MSG_IMAPFolderInfoMail *) parentFolder->GetSubFolder(childIndex);
02043     char *unsubscribeUrl = CreateIMAPUnsubscribeMailboxURL(currentChild->GetHostName(), currentChild->GetOnlineName(), currentChild->GetOnlineHierarchySeparator());    // unsubscribe from child
02044     if (unsubscribeUrl)
02045     {
02046       MSG_UrlQueue::AddUrlToPane(unsubscribeUrl, NULL, pane);
02047       XP_FREE(unsubscribeUrl);
02048     }
02049     UnsubscribeFromAllDescendants(currentChild); // unsubscribe from its children
02050   }
02051 }
02052 #endif // 0
02053 
02054 
02055 NS_IMETHODIMP
02056 nsImapIncomingServer::FEAlert(const PRUnichar* aString, nsIMsgWindow * aMsgWindow)
02057 {
02058        nsresult rv = NS_OK;
02059   nsCOMPtr<nsIPrompt> dialog;
02060   if (aMsgWindow)
02061     aMsgWindow->GetPromptDialog(getter_AddRefs(dialog));
02062 
02063   if (!dialog) // if we didn't get one, use the default....
02064   {
02065     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
02066     if (wwatch)
02067       wwatch->GetNewPrompter(0, getter_AddRefs(dialog));
02068   }
02069 
02070   if (dialog)
02071          rv = dialog->Alert(nsnull, aString);
02072   return rv;
02073 }
02074 
02075 NS_IMETHODIMP  nsImapIncomingServer::FEAlertFromServer(const char *aString, nsIMsgWindow * aMsgWindow)
02076 {
02077   nsresult rv = NS_OK;
02078   
02079   nsCOMPtr<nsIPrompt> dialog;
02080   if (aMsgWindow)
02081     aMsgWindow->GetPromptDialog(getter_AddRefs(dialog));
02082   
02083   if (dialog)
02084   {
02085     if (aString)
02086     {
02087       // skip over the first two words, I guess.
02088       char *whereRealMessage = PL_strchr(aString, ' ');
02089       if (whereRealMessage)
02090         whereRealMessage++;
02091       if (whereRealMessage)
02092         whereRealMessage = PL_strchr(whereRealMessage, ' ');
02093       if (whereRealMessage)
02094       {
02095         PRInt32 len = PL_strlen(whereRealMessage)-1;
02096         if (len > 0 && whereRealMessage[len] !=  '.')
02097           whereRealMessage[len] = '.';
02098       }
02099       
02100       PRUnichar *serverSaidPrefix = nsnull;
02101       GetImapStringByID(IMAP_SERVER_SAID, &serverSaidPrefix);
02102       if (serverSaidPrefix)
02103       {
02104         nsAutoString message(serverSaidPrefix);
02105         // the alert string from the server IS UTF-8!!! We must convert it to unicode
02106         // correctly before appending it to our error message string...
02107         AppendUTF8toUTF16(whereRealMessage ? whereRealMessage : aString, message);
02108         rv = dialog->Alert(nsnull, message.get());
02109         
02110         PR_Free(serverSaidPrefix);
02111       }
02112     }
02113   }
02114   
02115   return rv;
02116 }
02117 
02118 #define IMAP_MSGS_URL       "chrome://messenger/locale/imapMsgs.properties"
02119 
02120 nsresult nsImapIncomingServer::GetStringBundle()
02121 {
02122   nsresult res;
02123        if (!m_stringBundle)
02124        {
02125               static const char propertyURL[] = IMAP_MSGS_URL;
02126 
02127               nsCOMPtr<nsIStringBundleService> sBundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &res); 
02128               if (NS_SUCCEEDED(res) && (nsnull != sBundleService)) 
02129               {
02130                      res = sBundleService->CreateBundle(propertyURL, getter_AddRefs(m_stringBundle));
02131               }
02132        }
02133   return (m_stringBundle) ? NS_OK : res;
02134 }
02135 
02136 NS_IMETHODIMP  nsImapIncomingServer::GetImapStringByID(PRInt32 aMsgId, PRUnichar **aString)
02137 {
02138   nsresult res = NS_OK;
02139   
02140 
02141   GetStringBundle();
02142   if (m_stringBundle)
02143   {
02144     res = m_stringBundle->GetStringFromID(aMsgId, aString);
02145     if (NS_SUCCEEDED(res))
02146       return res;
02147   }
02148   nsAutoString       resultString(NS_LITERAL_STRING("String ID "));
02149   resultString.AppendInt(aMsgId);
02150   *aString = ToNewUnicode(resultString);
02151   return NS_OK;
02152 }
02153 
02154 NS_IMETHODIMP  nsImapIncomingServer::FormatStringWithHostNameByID(PRInt32 aMsgId, PRUnichar **aString)
02155 {
02156   nsresult res = NS_OK;
02157   
02158   GetStringBundle();
02159   if (m_stringBundle)
02160   {
02161     nsXPIDLCString hostName;
02162     res = GetRealHostName(getter_Copies(hostName));
02163     if (NS_SUCCEEDED(res))
02164     {
02165       nsAutoString hostStr;
02166       hostStr.AssignWithConversion(hostName.get());
02167       const PRUnichar *params[] = { hostStr.get() };
02168       res = m_stringBundle->FormatStringFromID(aMsgId, params, 1, aString);
02169       if (NS_SUCCEEDED(res))
02170         return res;
02171     }
02172   }
02173   nsAutoString       resultString(NS_LITERAL_STRING("String ID "));
02174   resultString.AppendInt(aMsgId);
02175   *aString = ToNewUnicode(resultString);
02176   return NS_OK;
02177 }
02178 
02179 nsresult nsImapIncomingServer::ResetFoldersToUnverified(nsIMsgFolder *parentFolder)
02180 {
02181   nsresult rv = NS_OK;
02182   if (!parentFolder) 
02183   {
02184     nsCOMPtr<nsIMsgFolder> rootFolder;
02185     rv = GetRootFolder(getter_AddRefs(rootFolder));
02186     if (NS_FAILED(rv)) return rv;
02187     return ResetFoldersToUnverified(rootFolder);
02188   }
02189   else 
02190   {
02191     nsCOMPtr<nsIEnumerator> subFolders;
02192     nsCOMPtr<nsIMsgImapMailFolder> imapFolder =
02193       do_QueryInterface(parentFolder, &rv);
02194     if (NS_FAILED(rv)) return rv;
02195     rv = imapFolder->SetVerifiedAsOnlineFolder(PR_FALSE);
02196     rv = parentFolder->GetSubFolders(getter_AddRefs(subFolders));
02197     if (NS_FAILED(rv)) return rv;
02198     nsAdapterEnumerator *simpleEnumerator = new
02199       nsAdapterEnumerator(subFolders);
02200     if (!simpleEnumerator) return NS_ERROR_OUT_OF_MEMORY;
02201     PRBool moreFolders = PR_FALSE;
02202     while (NS_SUCCEEDED(simpleEnumerator->HasMoreElements(&moreFolders))
02203       && moreFolders) 
02204     {
02205       nsCOMPtr<nsISupports> child;
02206       rv = simpleEnumerator->GetNext(getter_AddRefs(child));
02207       if (NS_SUCCEEDED(rv) && child) 
02208       {
02209         nsCOMPtr<nsIMsgFolder> childFolder = do_QueryInterface(child,
02210           &rv);
02211         if (NS_SUCCEEDED(rv) && childFolder) 
02212         {
02213           rv = ResetFoldersToUnverified(childFolder);
02214           if (NS_FAILED(rv)) break;
02215         }
02216       }
02217     }
02218     delete simpleEnumerator;
02219   }
02220   return rv;
02221 }
02222 
02223 nsresult nsImapIncomingServer::GetUnverifiedFolders(nsISupportsArray *aFoldersArray, PRInt32 *aNumUnverifiedFolders)
02224 {
02225   // can't have both be null, but one null is OK, since the caller
02226   // may just be trying to count the number of unverified folders.
02227   if (!aFoldersArray && !aNumUnverifiedFolders)
02228     return NS_ERROR_NULL_POINTER;
02229 
02230   if (aNumUnverifiedFolders)
02231     *aNumUnverifiedFolders = 0;
02232   nsCOMPtr<nsIMsgFolder> rootFolder;
02233   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
02234   if(NS_SUCCEEDED(rv) && rootFolder)
02235   {
02236     nsCOMPtr <nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
02237     if (imapRoot)
02238       imapRoot->SetVerifiedAsOnlineFolder(PR_TRUE); // don't need to verify the root.
02239     rv = GetUnverifiedSubFolders(rootFolder, aFoldersArray, aNumUnverifiedFolders);
02240   }
02241   return rv;
02242 }
02243 
02244 nsresult nsImapIncomingServer::GetUnverifiedSubFolders(nsIMsgFolder *parentFolder, nsISupportsArray *aFoldersArray, PRInt32 *aNumUnverifiedFolders)
02245 {
02246   nsresult rv = NS_OK;
02247   
02248   nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(parentFolder);
02249   PRBool verified = PR_FALSE, explicitlyVerify = PR_FALSE;
02250   if (imapFolder)
02251   {
02252     rv = imapFolder->GetVerifiedAsOnlineFolder(&verified);
02253     if (NS_SUCCEEDED(rv))
02254       rv = imapFolder->GetExplicitlyVerify(&explicitlyVerify);
02255     
02256     if (NS_SUCCEEDED(rv) && (!verified || explicitlyVerify))
02257     {
02258       if (aFoldersArray)
02259       {
02260         nsCOMPtr <nsISupports> supports = do_QueryInterface(imapFolder);
02261         aFoldersArray->AppendElement(supports);
02262       }
02263       if (aNumUnverifiedFolders)
02264         (*aNumUnverifiedFolders)++;
02265     }
02266   }
02267   nsCOMPtr<nsIEnumerator> subFolders;
02268   
02269   rv = parentFolder->GetSubFolders(getter_AddRefs(subFolders));
02270   if(NS_SUCCEEDED(rv))
02271   {
02272     nsAdapterEnumerator *simpleEnumerator = new nsAdapterEnumerator(subFolders);
02273     if (simpleEnumerator == nsnull)
02274       return NS_ERROR_OUT_OF_MEMORY;
02275     PRBool moreFolders;
02276     
02277     while (NS_SUCCEEDED(simpleEnumerator->HasMoreElements(&moreFolders)) && moreFolders)
02278     {
02279       nsCOMPtr<nsISupports> child;
02280       rv = simpleEnumerator->GetNext(getter_AddRefs(child));
02281       if (NS_SUCCEEDED(rv) && child) 
02282       {
02283         nsCOMPtr <nsIMsgFolder> childFolder = do_QueryInterface(child, &rv);
02284         if (NS_SUCCEEDED(rv) && childFolder)
02285         {
02286           rv = GetUnverifiedSubFolders(childFolder, aFoldersArray, aNumUnverifiedFolders);
02287           if (NS_FAILED(rv))
02288             break;
02289         }
02290       }
02291     }
02292     delete simpleEnumerator;
02293   }
02294   return rv;
02295 }
02296 
02297 NS_IMETHODIMP nsImapIncomingServer::ForgetSessionPassword()
02298 {
02299   nsresult rv = nsMsgIncomingServer::ForgetSessionPassword();
02300   NS_ENSURE_SUCCESS(rv,rv);
02301 
02302   // fix for bugscape bug #15485
02303   // if we use turbo, and we logout, we need to make sure
02304   // the server doesn't think it's authenticated.
02305   // the biff timer continues to fire when you use turbo
02306   // (see #143848).  if we exited, we've set the password to null
02307   // but if we're authenticated, and the biff timer goes off
02308   // we'll still perform biff, because we use m_userAuthenticated
02309   // to determine if we require a password for biff.
02310   // (if authenticated, we don't require a password
02311   // see nsMsgBiffManager::PerformBiff())
02312   // performing biff without a password will pop up the prompt dialog
02313   // which is pretty wacky, when it happens after you quit the application
02314   m_userAuthenticated = PR_FALSE;
02315   return NS_OK;
02316 }
02317 
02318 NS_IMETHODIMP nsImapIncomingServer::GetServerRequiresPasswordForBiff(PRBool *aServerRequiresPasswordForBiff)
02319 {
02320   NS_ENSURE_ARG_POINTER(aServerRequiresPasswordForBiff);
02321   // if the user has already been authenticated, we've got the password
02322   *aServerRequiresPasswordForBiff = !m_userAuthenticated;
02323   return NS_OK;
02324 }
02325 
02326 NS_IMETHODIMP nsImapIncomingServer::ForgetPassword()
02327 {
02328   return nsMsgIncomingServer::ForgetPassword();
02329 }
02330 
02331 
02332 NS_IMETHODIMP nsImapIncomingServer::PromptForPassword(char ** aPassword,
02333                                                       nsIMsgWindow * aMsgWindow)
02334 {
02335     nsXPIDLString passwordTitle; 
02336     IMAPGetStringByID(IMAP_ENTER_PASSWORD_PROMPT_TITLE, getter_Copies(passwordTitle));
02337     nsXPIDLCString userName;
02338     PRBool okayValue;
02339     GetRealUsername(getter_Copies(userName));
02340 
02341     nsCAutoString promptValue(userName);
02342 
02343     nsCAutoString prefName;
02344     nsresult rv = CreatePrefNameWithRedirectorType(".hide_hostname_for_password", prefName);
02345     NS_ENSURE_SUCCESS(rv,rv);
02346 
02347     nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
02348     NS_ENSURE_SUCCESS(rv,rv);
02349 
02350     PRBool hideHostnameForPassword = PR_FALSE;
02351     rv = prefBranch->GetBoolPref(prefName.get(), &hideHostnameForPassword);
02352     if (NS_SUCCEEDED(rv) && hideHostnameForPassword) 
02353     {
02354       // for certain redirector types, we don't want to show the
02355       // hostname to the user when prompting for password
02356     }
02357     else 
02358     {
02359       nsXPIDLCString hostName;
02360       GetRealHostName(getter_Copies(hostName));
02361       promptValue.Append("@");
02362       promptValue.Append(hostName);
02363     }
02364 
02365     nsXPIDLString passwordText;
02366     rv = GetFormattedStringFromID(NS_ConvertASCIItoUCS2(promptValue).get(), IMAP_ENTER_PASSWORD_PROMPT, getter_Copies(passwordText));
02367     NS_ENSURE_SUCCESS(rv,rv);
02368 
02369     rv =  GetPasswordWithUI(passwordText, passwordTitle, aMsgWindow,
02370                                      &okayValue, aPassword);
02371     return (okayValue) ? rv : NS_MSG_PASSWORD_PROMPT_CANCELLED;
02372 }
02373 
02374 // for the nsIImapServerSink interface
02375 NS_IMETHODIMP  nsImapIncomingServer::SetCapability(PRUint32 capability)
02376 {
02377     m_capability = capability;
02378     SetCapabilityPref(capability);
02379     return NS_OK;
02380 }
02381 
02382 NS_IMETHODIMP  nsImapIncomingServer::CommitNamespaces()
02383 {
02384   
02385   nsresult rv;
02386   nsCOMPtr<nsIImapHostSessionList> hostSession = 
02387     do_GetService(kCImapHostSessionListCID, &rv);
02388   if (NS_FAILED(rv)) 
02389     return rv;
02390   
02391   return hostSession->CommitNamespacesForHost(this);
02392   
02393 }
02394 
02395 NS_IMETHODIMP nsImapIncomingServer::PseudoInterruptMsgLoad(nsIMsgFolder *aImapFolder, nsIMsgWindow *aMsgWindow, PRBool *interrupted)
02396 {
02397   nsresult rv = NS_OK;
02398   nsCOMPtr<nsIImapProtocol> connection;
02399   
02400   PR_CEnterMonitor(this);
02401   
02402   // iterate through the connection cache for a connection that is loading
02403   // a message in this folder and should be pseudo-interrupted.
02404   PRUint32 cnt;
02405   
02406   rv = m_connectionCache->Count(&cnt);
02407   if (NS_FAILED(rv)) return rv;
02408   for (PRUint32 i = 0; i < cnt; i++) 
02409   {    
02410     connection = do_QueryElementAt(m_connectionCache, i);
02411     if (connection)
02412       rv = connection->PseudoInterruptMsgLoad(aImapFolder, aMsgWindow, interrupted);
02413   }
02414   
02415   PR_CExitMonitor(this);
02416   return rv;
02417 }
02418 
02419 NS_IMETHODIMP nsImapIncomingServer::ResetNamespaceReferences()
02420 {
02421 
02422   nsCOMPtr <nsIMsgFolder> rootFolder;
02423   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
02424   if (NS_SUCCEEDED(rv) && rootFolder)
02425   {
02426     nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(rootFolder);
02427     if (imapFolder)
02428       rv = imapFolder->ResetNamespaceReferences();
02429   }
02430   return rv;
02431 }
02432 
02433 NS_IMETHODIMP nsImapIncomingServer::SetUserAuthenticated(PRBool aUserAuthenticated)
02434 {
02435   m_userAuthenticated = aUserAuthenticated;
02436   if (aUserAuthenticated)
02437     StorePassword();
02438   return NS_OK;
02439 }
02440 
02441 NS_IMETHODIMP nsImapIncomingServer::GetUserAuthenticated(PRBool *aUserAuthenticated)
02442 {
02443   NS_ENSURE_ARG_POINTER(aUserAuthenticated);
02444   *aUserAuthenticated = m_userAuthenticated;
02445   return NS_OK;
02446 }
02447 
02448 /* void SetMailServerUrls (in string manageMailAccount, in string manageLists, in string manageFilters); */
02449 NS_IMETHODIMP  nsImapIncomingServer::SetMailServerUrls(const char *manageMailAccount, const char *manageLists, const char *manageFilters)
02450 {
02451   return SetManageMailAccountUrl((char *) manageMailAccount);
02452 }
02453 
02454 NS_IMETHODIMP nsImapIncomingServer::SetManageMailAccountUrl(const char *manageMailAccountUrl)
02455 {
02456   m_manageMailAccountUrl = manageMailAccountUrl;
02457   return NS_OK;
02458 }
02459 
02460 NS_IMETHODIMP nsImapIncomingServer::GetManageMailAccountUrl(char **manageMailAccountUrl)
02461 {
02462   if (!manageMailAccountUrl)
02463     return NS_ERROR_NULL_POINTER;
02464   
02465   *manageMailAccountUrl = ToNewCString(m_manageMailAccountUrl);
02466   return NS_OK;
02467 }
02468 
02469 NS_IMETHODIMP nsImapIncomingServer::RemoveChannelFromUrl(nsIMsgMailNewsUrl *aUrl, PRUint32 statusCode)
02470 {
02471   nsresult rv = NS_OK;
02472   if (aUrl)
02473   {
02474     nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(aUrl);
02475     if (imapUrl)
02476       rv = imapUrl->RemoveChannel(statusCode);
02477   }
02478 
02479   return rv;
02480 }
02481 
02482 nsresult nsImapIncomingServer::RequestOverrideInfo(nsIMsgWindow *aMsgWindow)
02483 {
02484   
02485   nsresult rv;
02486   nsCAutoString contractID(NS_MSGLOGONREDIRECTORSERVICE_CONTRACTID);
02487   nsXPIDLCString redirectorType;
02488   
02489   GetRedirectorType(getter_Copies(redirectorType));
02490   contractID.Append('/');
02491   contractID.Append(redirectorType);
02492   
02493   m_logonRedirector = do_GetService(contractID.get(), &rv);
02494   if (m_logonRedirector && NS_SUCCEEDED(rv))
02495   {
02496     nsCOMPtr <nsIMsgLogonRedirectionRequester> logonRedirectorRequester;
02497     rv = QueryInterface(NS_GET_IID(nsIMsgLogonRedirectionRequester), getter_AddRefs(logonRedirectorRequester));
02498     if (NS_SUCCEEDED(rv))
02499     {
02500       nsXPIDLCString password;
02501       nsXPIDLCString userName;
02502       PRBool requiresPassword = PR_TRUE;
02503       
02504       GetRealUsername(getter_Copies(userName));
02505       m_logonRedirector->RequiresPassword(userName, redirectorType.get(), &requiresPassword);
02506       
02507       if (requiresPassword)
02508       {
02509         GetPassword(getter_Copies(password));
02510         
02511         if (password.IsEmpty())
02512           PromptForPassword(getter_Copies(password), aMsgWindow);
02513         
02514         if (password.IsEmpty())  // if still empty then the user canceld out of the password dialog
02515         {
02516           // be sure to clear the waiting for connection info flag because we aren't waiting
02517           // anymore for a connection...
02518           m_waitingForConnectionInfo = PR_FALSE;
02519           return NS_OK;
02520         }
02521       }
02522       else
02523       {
02524         SetUserAuthenticated(PR_TRUE);  // we are already authenicated
02525       }
02526       
02527       nsCOMPtr<nsIPrompt> dialogPrompter;
02528       if (aMsgWindow)
02529         aMsgWindow->GetPromptDialog(getter_AddRefs(dialogPrompter));
02530       rv = m_logonRedirector->Logon(userName, password, redirectorType, dialogPrompter, logonRedirectorRequester, nsMsgLogonRedirectionServiceIDs::Imap);
02531       if (NS_FAILED(rv)) 
02532         return OnLogonRedirectionError(nsnull, PR_TRUE);
02533     }
02534   }
02535   
02536   return rv;
02537 }
02538 
02539 NS_IMETHODIMP nsImapIncomingServer::OnLogonRedirectionError(const PRUnichar *pErrMsg, PRBool badPassword)
02540 {
02541   nsresult rv = NS_OK;
02542   
02543   nsXPIDLString progressString;
02544   GetImapStringByID(IMAP_REDIRECT_LOGIN_FAILED, getter_Copies(progressString));
02545   
02546   nsCOMPtr<nsIMsgWindow> msgWindow;
02547   PRUint32 urlQueueCnt = 0;
02548   // pull the url out of the queue so we can get the msg window, and try to rerun it.
02549   m_urlQueue->Count(&urlQueueCnt);
02550   
02551   nsCOMPtr<nsISupports> aSupport;
02552   nsCOMPtr<nsIImapUrl> aImapUrl;
02553   nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl;
02554   if (urlQueueCnt > 0)
02555   {
02556     aSupport = getter_AddRefs(m_urlQueue->ElementAt(0));
02557     aImapUrl = do_QueryInterface(aSupport, &rv);
02558     mailnewsUrl = do_QueryInterface(aSupport, &rv);
02559   }
02560 
02561   if (mailnewsUrl)
02562     mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow));
02563   
02564   // don't put up alert if no msg window - it means we're biffing.
02565   if (msgWindow)
02566     FEAlert(progressString, msgWindow);
02567   
02568   
02569 
02570   // If password is bad then clean up all cached passwords.
02571   if (badPassword)
02572     ForgetPassword();
02573   
02574   PRBool resetUrlState = PR_FALSE;
02575   if (badPassword && ++m_redirectedLogonRetries <= 3)
02576   {
02577     // this will force a reprompt for the password.
02578     // ### DMB TODO display error message?
02579     if (urlQueueCnt > 0)
02580     {
02581       nsCOMPtr <nsIImapProtocol> imapProtocol;
02582       nsCOMPtr <nsIEventQueue> aEventQueue;
02583       // Get current thread envent queue
02584       nsCOMPtr<nsIEventQueueService> pEventQService = 
02585         do_GetService(kEventQueueServiceCID, &rv); 
02586       if (NS_SUCCEEDED(rv) && pEventQService)
02587         pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
02588         getter_AddRefs(aEventQueue));
02589       
02590       if (aImapUrl)
02591       {       
02592         nsCOMPtr <nsIImapProtocol>  protocolInstance ;
02593         m_waitingForConnectionInfo = PR_FALSE;
02594         rv = GetImapConnection(aEventQueue, aImapUrl, getter_AddRefs(protocolInstance));
02595         // If users cancel the login then we need to reset url state.
02596         if (rv == NS_BINDING_ABORTED)
02597           resetUrlState = PR_TRUE;
02598       }
02599     }
02600   }
02601   else
02602     resetUrlState = PR_TRUE;
02603 
02604   // Either user cancel (2nd, 3rd or 4th) login or all tries fail we'll
02605   // have to reset url state so that next login will work correctly.
02606   if  (resetUrlState)
02607   {
02608     m_redirectedLogonRetries = 0; // reset so next attempt will start at 0.
02609     m_waitingForConnectionInfo = PR_FALSE;
02610     if (urlQueueCnt > 0)
02611     {
02612       // Reset url state. 
02613       if (mailnewsUrl)
02614         mailnewsUrl->SetUrlState(PR_FALSE, NS_MSG_ERROR_URL_ABORTED);
02615 
02616       m_urlQueue->RemoveElementAt(0);
02617       m_urlConsumers.RemoveElementAt(0);
02618     }
02619   }
02620   
02621   return rv;
02622 }
02623   
02624   /* Logon Redirection Progress */
02625 NS_IMETHODIMP nsImapIncomingServer::OnLogonRedirectionProgress(nsMsgLogonRedirectionState pState)
02626 {
02627        return NS_OK;
02628 }
02629 
02630   /* reply with logon redirection data. */
02631 NS_IMETHODIMP nsImapIncomingServer::OnLogonRedirectionReply(const PRUnichar *pHost, unsigned short pPort, const char *pCookieData,  unsigned short pCookieSize)
02632 {
02633   PRBool urlRun = PR_FALSE;
02634   nsresult rv;
02635   nsCOMPtr <nsIImapProtocol> imapProtocol;
02636   nsCOMPtr <nsIEventQueue> aEventQueue;
02637   nsCAutoString cookie(pCookieData, pCookieSize);
02638   // Get current thread envent queue
02639   nsCOMPtr<nsIEventQueueService> pEventQService = 
02640     do_GetService(kEventQueueServiceCID, &rv); 
02641   if (NS_SUCCEEDED(rv) && pEventQService)
02642     pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
02643     getter_AddRefs(aEventQueue));
02644   // we used to logoff the external requestor...we no longer need to do
02645   // that.
02646   
02647   m_redirectedLogonRetries = 0; // we got through, so reset this counter.
02648   
02649   PRUint32 cnt = 0;
02650   
02651   m_urlQueue->Count(&cnt);
02652   if (cnt > 0)
02653   {
02654     nsCOMPtr<nsIImapUrl> aImapUrl(do_QueryElementAt(m_urlQueue, 0, &rv));
02655     
02656     if (aImapUrl)
02657     {
02658       nsCOMPtr<nsISupports> aConsumer = (nsISupports*)m_urlConsumers.ElementAt(0);
02659       
02660       nsCOMPtr <nsIImapProtocol>  protocolInstance ;
02661       rv = GetImapConnection(aEventQueue, aImapUrl, getter_AddRefs(protocolInstance));
02662       m_waitingForConnectionInfo = PR_FALSE;
02663       if (NS_SUCCEEDED(rv) && protocolInstance)
02664       {
02665         protocolInstance->OverrideConnectionInfo(pHost, pPort, cookie.get());
02666         nsCOMPtr<nsIURI> url = do_QueryInterface(aImapUrl, &rv);
02667         if (NS_SUCCEEDED(rv) && url)
02668         {
02669           rv = protocolInstance->LoadImapUrl(url, aConsumer);
02670           urlRun = PR_TRUE;
02671         }
02672         
02673         m_urlQueue->RemoveElementAt(0);
02674         m_urlConsumers.RemoveElementAt(0);
02675       }
02676     }    
02677   }
02678   else
02679   {
02680     m_waitingForConnectionInfo = PR_FALSE;
02681     NS_ASSERTION(PR_FALSE, "got redirection response with no queued urls");
02682   // Need to clear this even if we don't have any urls in the queue.
02683   // Otherwise, we'll never clear it and we'll never request override info.
02684   }
02685   return rv;
02686 }
02687 
02688 NS_IMETHODIMP
02689 nsImapIncomingServer::StartPopulatingWithUri(nsIMsgWindow *aMsgWindow, PRBool aForceToServer /*ignored*/, const char *uri)
02690 {
02691        nsresult rv;
02692 #ifdef DEBUG_sspitzer
02693        printf("in StartPopulatingWithUri(%s)\n",uri);
02694 #endif
02695        mDoingSubscribeDialog = PR_TRUE;   
02696 
02697     rv = EnsureInner();
02698     NS_ENSURE_SUCCESS(rv,rv);
02699     rv = mInner->StartPopulatingWithUri(aMsgWindow, aForceToServer, uri);
02700     NS_ENSURE_SUCCESS(rv,rv);
02701 
02702     // imap always uses the canonical delimiter form of paths for subscribe ui.
02703     rv = SetDelimiter('/');
02704     NS_ENSURE_SUCCESS(rv,rv);
02705 
02706     rv = SetShowFullName(PR_FALSE);
02707     NS_ENSURE_SUCCESS(rv,rv);
02708 
02709     nsXPIDLCString serverUri;
02710     rv = GetServerURI(getter_Copies(serverUri));
02711     NS_ENSURE_SUCCESS(rv,rv);
02712 
02713        nsCOMPtr<nsIImapService> imapService = do_GetService(kImapServiceCID, &rv);
02714     NS_ENSURE_SUCCESS(rv,rv);
02715        if (!imapService) return NS_ERROR_FAILURE;
02716 
02717     /* 
02718     if uri = imap://user@host/foo/bar, the serverUri is imap://user@host
02719     to get path from uri, skip over imap://user@host + 1 (for the /)
02720     */
02721     const char *path = uri + strlen((const char *)serverUri) + 1;
02722 
02723     rv = imapService->GetListOfFoldersWithPath(this, aMsgWindow, path);
02724     NS_ENSURE_SUCCESS(rv,rv);
02725 
02726     return NS_OK;
02727 }
02728 
02729 NS_IMETHODIMP
02730 nsImapIncomingServer::StartPopulating(nsIMsgWindow *aMsgWindow, PRBool aForceToServer /*ignored*/)
02731 {
02732        nsresult rv;
02733 #ifdef DEBUG_sspitzer
02734        printf("in StartPopulating()\n");
02735 #endif
02736        mDoingSubscribeDialog = PR_TRUE;   
02737 
02738     rv = EnsureInner();
02739     NS_ENSURE_SUCCESS(rv,rv);
02740     rv = mInner->StartPopulating(aMsgWindow, aForceToServer);
02741     NS_ENSURE_SUCCESS(rv,rv);
02742 
02743     // imap always uses the canonical delimiter form of paths for subscribe ui.
02744     rv = SetDelimiter('/'); 
02745     NS_ENSURE_SUCCESS(rv,rv);
02746 
02747     rv = SetShowFullName(PR_FALSE);
02748     NS_ENSURE_SUCCESS(rv,rv);
02749 
02750        nsCOMPtr<nsIImapService> imapService = do_GetService(kImapServiceCID, &rv);
02751     NS_ENSURE_SUCCESS(rv,rv);
02752        if (!imapService) return NS_ERROR_FAILURE;
02753 
02754     rv = imapService->GetListOfFoldersOnServer(this, aMsgWindow);
02755     NS_ENSURE_SUCCESS(rv,rv);
02756 
02757     return NS_OK;
02758 }
02759 
02760 NS_IMETHODIMP
02761 nsImapIncomingServer::OnStartRunningUrl(nsIURI *url)
02762 {
02763     return NS_OK;
02764 }
02765 
02766 NS_IMETHODIMP
02767 nsImapIncomingServer::OnStopRunningUrl(nsIURI *url, nsresult exitCode)
02768 {
02769     nsresult rv = exitCode;
02770 
02771     // xxx todo get msgWindow from url
02772     nsCOMPtr<nsIMsgWindow> msgWindow;
02773 
02774     nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(url);
02775     if (imapUrl) {
02776         nsImapAction imapAction = nsIImapUrl::nsImapTest;
02777         imapUrl->GetImapAction(&imapAction);
02778         switch (imapAction) {
02779         case nsIImapUrl::nsImapDiscoverAllAndSubscribedBoxesUrl:
02780         case nsIImapUrl::nsImapDiscoverChildrenUrl:
02781             rv = UpdateSubscribed();
02782             if (NS_FAILED(rv)) return rv;
02783             mDoingSubscribeDialog = PR_FALSE;
02784             rv = StopPopulating(msgWindow);
02785             if (NS_FAILED(rv)) return rv;
02786             break;
02787         case nsIImapUrl::nsImapDiscoverAllBoxesUrl:
02788             DiscoveryDone();
02789             break;
02790         case nsIImapUrl::nsImapFolderStatus:
02791           {
02792             PRInt32 folderCount = m_foldersToStat.Count();
02793             m_foldersToStat.RemoveObjectAt(folderCount - 1);
02794             if (folderCount > 1)
02795               m_foldersToStat[folderCount - 2]->UpdateStatus(this, nsnull);
02796           }
02797         default:
02798             break;
02799         }
02800     }
02801 
02802     return NS_OK;
02803 }
02804 
02805 NS_IMETHODIMP
02806 nsImapIncomingServer::SetIncomingServer(nsIMsgIncomingServer *aServer)
02807 {
02808     nsresult rv = EnsureInner();
02809     NS_ENSURE_SUCCESS(rv,rv);
02810        return mInner->SetIncomingServer(aServer);
02811 }
02812 
02813 NS_IMETHODIMP
02814 nsImapIncomingServer::SetShowFullName(PRBool showFullName)
02815 {
02816     nsresult rv = EnsureInner();
02817     NS_ENSURE_SUCCESS(rv,rv);
02818        return mInner->SetShowFullName(showFullName);
02819 }
02820 
02821 NS_IMETHODIMP
02822 nsImapIncomingServer::GetDelimiter(char *aDelimiter)
02823 {
02824     nsresult rv = EnsureInner();
02825     NS_ENSURE_SUCCESS(rv,rv);
02826     return mInner->GetDelimiter(aDelimiter);
02827 }
02828 
02829 NS_IMETHODIMP
02830 nsImapIncomingServer::SetDelimiter(char aDelimiter)
02831 {
02832   nsresult rv = EnsureInner();
02833   NS_ENSURE_SUCCESS(rv,rv);
02834   return mInner->SetDelimiter(aDelimiter);
02835 }
02836 
02837 NS_IMETHODIMP
02838 nsImapIncomingServer::SetAsSubscribed(const nsACString &path)
02839 {
02840   nsresult rv = EnsureInner();
02841   NS_ENSURE_SUCCESS(rv,rv);
02842   return mInner->SetAsSubscribed(path);
02843 }
02844 
02845 NS_IMETHODIMP
02846 nsImapIncomingServer::UpdateSubscribed()
02847 {
02848 #ifdef DEBUG_sspitzer
02849   printf("for imap, do this when we populate\n");
02850 #endif
02851   return NS_OK;
02852 }
02853 
02854 NS_IMETHODIMP
02855 nsImapIncomingServer::AddTo(const nsACString &aName, PRBool addAsSubscribed,
02856                             PRBool aSubscribable, PRBool changeIfExists)
02857 {
02858   nsresult rv = EnsureInner();
02859   NS_ENSURE_SUCCESS(rv,rv);
02860   
02861   // RFC 3501 allows UTF-8 in addition to modified UTF-7
02862   // If it's not UTF-8, it cannot be MUTF7, either. We just ignore it.
02863   // (otherwise we'll crash. see #63186)
02864   if (!IsUTF8(aName)) 
02865     return NS_OK; 
02866 
02867   if (!IsASCII(aName)) { 
02868       nsCAutoString name;
02869       CopyUTF16toMUTF7(NS_ConvertUTF8toUTF16(aName), name);
02870       return mInner->AddTo(name, addAsSubscribed, aSubscribable, changeIfExists);
02871   }
02872  
02873   return mInner->AddTo(aName, addAsSubscribed, aSubscribable, changeIfExists);
02874 }
02875 
02876 NS_IMETHODIMP
02877 nsImapIncomingServer::StopPopulating(nsIMsgWindow *aMsgWindow)
02878 {
02879        nsresult rv;
02880 
02881     nsCOMPtr<nsISubscribeListener> listener;
02882     rv = GetSubscribeListener(getter_AddRefs(listener));
02883     if (NS_FAILED(rv)) return rv;
02884     if (!listener) return NS_ERROR_FAILURE;
02885 
02886     rv = listener->OnDonePopulating();
02887     if (NS_FAILED(rv)) return rv;
02888        
02889     rv = EnsureInner();
02890     NS_ENSURE_SUCCESS(rv,rv);
02891        rv = mInner->StopPopulating(aMsgWindow);
02892     NS_ENSURE_SUCCESS(rv,rv);
02893 
02894     //xxx todo when do I set this to null?
02895     //rv = ClearInner();
02896     //NS_ENSURE_SUCCESS(rv,rv);
02897        return NS_OK;
02898 }
02899 
02900 
02901 NS_IMETHODIMP
02902 nsImapIncomingServer::SubscribeCleanup()
02903 {
02904        nsresult rv;
02905   m_subscribeFolders.Clear();
02906     rv = ClearInner();
02907     NS_ENSURE_SUCCESS(rv,rv);
02908        return NS_OK;
02909 }
02910 
02911 NS_IMETHODIMP
02912 nsImapIncomingServer::SetSubscribeListener(nsISubscribeListener *aListener)
02913 {
02914     nsresult rv = EnsureInner();
02915     NS_ENSURE_SUCCESS(rv,rv);
02916        return mInner->SetSubscribeListener(aListener);
02917 }
02918 
02919 NS_IMETHODIMP
02920 nsImapIncomingServer::GetSubscribeListener(nsISubscribeListener **aListener)
02921 {
02922     nsresult rv = EnsureInner();
02923     NS_ENSURE_SUCCESS(rv,rv);
02924        return mInner->GetSubscribeListener(aListener);
02925 }
02926 
02927 NS_IMETHODIMP
02928 nsImapIncomingServer::Subscribe(const PRUnichar *aName)
02929 {
02930   return SubscribeToFolder(aName, PR_TRUE, nsnull);
02931 }
02932 
02933 NS_IMETHODIMP
02934 nsImapIncomingServer::Unsubscribe(const PRUnichar *aName)
02935 {
02936   return SubscribeToFolder(aName, PR_FALSE, nsnull);
02937 }
02938 
02939 NS_IMETHODIMP
02940 nsImapIncomingServer::SubscribeToFolder(const PRUnichar *aName, PRBool subscribe, nsIURI **aUri)
02941 {
02942   nsresult rv;
02943   nsCOMPtr<nsIImapService> imapService = do_GetService(kImapServiceCID, &rv);
02944   if (NS_FAILED(rv)) return rv;
02945   if (!imapService) return NS_ERROR_FAILURE;
02946   
02947   nsCOMPtr<nsIMsgFolder> rootMsgFolder;
02948   rv = GetRootFolder(getter_AddRefs(rootMsgFolder));
02949   if (NS_FAILED(rv)) return rv;
02950   if (!rootMsgFolder) return NS_ERROR_FAILURE;
02951   
02952   // Locate the folder so that the correct hierarchical delimiter is used in the
02953   // folder pathnames, otherwise root's (ie, '^') is used and this is wrong.
02954   
02955   // aName is not a genuine UTF-16 but just a zero-padded modified UTF-7 
02956   NS_LossyConvertUTF16toASCII folderCName(aName);
02957   nsCOMPtr<nsIMsgFolder> msgFolder;
02958   if (rootMsgFolder && aName && (*aName))
02959   {
02960     rv = rootMsgFolder->FindSubFolder(folderCName, getter_AddRefs(msgFolder));
02961   }
02962   
02963   nsCOMPtr<nsIEventQueue> queue;
02964   // get the Event Queue for this thread...
02965   nsCOMPtr<nsIEventQueueService> pEventQService = 
02966     do_GetService(kEventQueueServiceCID, &rv);
02967   if (NS_FAILED(rv)) return rv;
02968   
02969   rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
02970   if (NS_FAILED(rv)) return rv;
02971 
02972   nsAutoString unicodeName;
02973   rv = CopyMUTF7toUTF16(folderCName, unicodeName);
02974   NS_ENSURE_SUCCESS(rv, rv);
02975 
02976   if (subscribe)
02977     rv = imapService->SubscribeFolder(queue, msgFolder, unicodeName.get(), nsnull, aUri);
02978   else 
02979     rv = imapService->UnsubscribeFolder(queue, msgFolder, unicodeName.get(), nsnull, nsnull);
02980   
02981   if (NS_FAILED(rv)) return rv;
02982   return NS_OK;
02983 }
02984 
02985 NS_IMETHODIMP
02986 nsImapIncomingServer::SetDoingLsub(PRBool doingLsub)
02987 {
02988   mDoingLsub = doingLsub;
02989   return NS_OK;
02990 }
02991 
02992 NS_IMETHODIMP
02993 nsImapIncomingServer::GetDoingLsub(PRBool *doingLsub)
02994 {
02995   if (!doingLsub) return NS_ERROR_NULL_POINTER;
02996   
02997   *doingLsub = mDoingLsub;
02998   return NS_OK;
02999 }
03000 
03001 NS_IMETHODIMP
03002 nsImapIncomingServer::ReDiscoverAllFolders()
03003 {
03004     nsresult rv = PerformExpand(nsnull);
03005     return rv;
03006 }
03007 
03008 NS_IMETHODIMP
03009 nsImapIncomingServer::SetState(const nsACString &path, PRBool state,
03010                                PRBool *stateChanged)
03011 {
03012     nsresult rv = EnsureInner();
03013     NS_ENSURE_SUCCESS(rv,rv);
03014     return mInner->SetState(path, state, stateChanged);
03015 }
03016 
03017 NS_IMETHODIMP
03018 nsImapIncomingServer::HasChildren(const nsACString &path, PRBool *aHasChildren)
03019 {
03020     nsresult rv = EnsureInner();
03021     NS_ENSURE_SUCCESS(rv,rv);
03022     return mInner->HasChildren(path, aHasChildren);
03023 }
03024 
03025 NS_IMETHODIMP
03026 nsImapIncomingServer::IsSubscribed(const nsACString &path,
03027                                    PRBool *aIsSubscribed)
03028 {
03029     nsresult rv = EnsureInner();
03030     NS_ENSURE_SUCCESS(rv,rv);
03031     return mInner->IsSubscribed(path, aIsSubscribed);
03032 }
03033 
03034 NS_IMETHODIMP
03035 nsImapIncomingServer::IsSubscribable(const nsACString &path, PRBool *aIsSubscribable)
03036 {
03037     nsresult rv = EnsureInner();
03038     NS_ENSURE_SUCCESS(rv,rv);
03039     return mInner->IsSubscribable(path, aIsSubscribable);
03040 }
03041 
03042 NS_IMETHODIMP
03043 nsImapIncomingServer::GetLeafName(const nsACString &path, nsAString &aLeafName)
03044 {
03045     nsresult rv = EnsureInner();
03046     NS_ENSURE_SUCCESS(rv,rv);
03047     return mInner->GetLeafName(path, aLeafName);
03048 }
03049 
03050 NS_IMETHODIMP
03051 nsImapIncomingServer::GetFirstChildURI(const nsACString &path, nsACString &aResult)
03052 {
03053     nsresult rv = EnsureInner();
03054     NS_ENSURE_SUCCESS(rv,rv);
03055     return mInner->GetFirstChildURI(path, aResult);
03056 }
03057 
03058 
03059 NS_IMETHODIMP
03060 nsImapIncomingServer::GetChildren(const nsACString &path, nsISupportsArray *array)
03061 {
03062     nsresult rv = EnsureInner();
03063     NS_ENSURE_SUCCESS(rv,rv);
03064     return mInner->GetChildren(path, array);
03065 }
03066 
03067 nsresult
03068 nsImapIncomingServer::EnsureInner()
03069 {
03070     nsresult rv = NS_OK;
03071 
03072     if (mInner) return NS_OK;
03073 
03074     mInner = do_CreateInstance(kSubscribableServerCID,&rv);
03075     NS_ENSURE_SUCCESS(rv,rv);
03076     if (!mInner) return NS_ERROR_FAILURE;
03077 
03078     rv = SetIncomingServer(this);
03079     NS_ENSURE_SUCCESS(rv,rv);
03080 
03081     return NS_OK;
03082 }
03083 
03084 nsresult
03085 nsImapIncomingServer::ClearInner()
03086 {
03087     nsresult rv = NS_OK;
03088 
03089     if (mInner) {
03090         rv = mInner->SetSubscribeListener(nsnull);
03091         NS_ENSURE_SUCCESS(rv,rv);
03092 
03093         rv = mInner->SetIncomingServer(nsnull);
03094         NS_ENSURE_SUCCESS(rv,rv);
03095 
03096         mInner = nsnull;
03097     }
03098     return NS_OK;
03099 }
03100 
03101 NS_IMETHODIMP
03102 nsImapIncomingServer::CommitSubscribeChanges()
03103 {
03104     return ReDiscoverAllFolders();
03105 }
03106 
03107 NS_IMETHODIMP
03108 nsImapIncomingServer::GetCanBeDefaultServer(PRBool *canBeDefaultServer)
03109 {
03110     *canBeDefaultServer = PR_TRUE;
03111     return NS_OK;
03112 }
03113 
03114 NS_IMETHODIMP
03115 nsImapIncomingServer::GetCanCompactFoldersOnServer(PRBool *canCompactFoldersOnServer)
03116 {
03117     NS_ENSURE_ARG_POINTER(canCompactFoldersOnServer);
03118 
03119     // Initialize canCompactFoldersOnServer true, a default value for IMAP
03120     *canCompactFoldersOnServer = PR_TRUE;
03121 
03122     GetPrefForServerAttribute("canCompactFoldersOnServer", canCompactFoldersOnServer);
03123 
03124     return NS_OK;
03125 }
03126 
03127 NS_IMETHODIMP
03128 nsImapIncomingServer::GetCanUndoDeleteOnServer(PRBool *canUndoDeleteOnServer)
03129 {
03130     NS_ENSURE_ARG_POINTER(canUndoDeleteOnServer);
03131 
03132     // Initialize canUndoDeleteOnServer true, a default value for IMAP
03133     *canUndoDeleteOnServer = PR_TRUE;
03134 
03135     GetPrefForServerAttribute("canUndoDeleteOnServer", canUndoDeleteOnServer);
03136 
03137     return NS_OK;
03138 }
03139 
03140 NS_IMETHODIMP
03141 nsImapIncomingServer::GetCanSearchMessages(PRBool *canSearchMessages)
03142 {
03143     NS_ENSURE_ARG_POINTER(canSearchMessages);
03144 
03145     // Initialize canSearchMessages true, a default value for IMAP
03146     *canSearchMessages = PR_TRUE;
03147 
03148     GetPrefForServerAttribute("canSearchMessages", canSearchMessages);
03149 
03150     return NS_OK;
03151 }
03152 
03153 NS_IMETHODIMP
03154 nsImapIncomingServer::GetCanEmptyTrashOnExit(PRBool *canEmptyTrashOnExit)
03155 {
03156     NS_ENSURE_ARG_POINTER(canEmptyTrashOnExit);
03157 
03158     // Initialize canEmptyTrashOnExit true, a default value for IMAP
03159     *canEmptyTrashOnExit = PR_TRUE;
03160 
03161     GetPrefForServerAttribute("canEmptyTrashOnExit", canEmptyTrashOnExit);
03162 
03163     return NS_OK;
03164 }
03165 
03166 NS_IMETHODIMP
03167 nsImapIncomingServer::GetIsSecureServer(PRBool *isSecureServer)
03168 {
03169     NS_ENSURE_ARG_POINTER(isSecureServer);
03170 
03171     // Initialize isSecureServer true, a default value for IMAP
03172     *isSecureServer = PR_TRUE;
03173 
03174     GetPrefForServerAttribute("isSecureServer", isSecureServer);
03175 
03176     return NS_OK;
03177 }
03178 
03179 nsresult
03180 nsImapIncomingServer::CreateHostSpecificPrefName(const char *prefPrefix, nsCAutoString &prefName)
03181 {
03182   NS_ENSURE_ARG_POINTER(prefPrefix);
03183 
03184   nsXPIDLCString hostName;
03185   nsresult rv = GetHostName(getter_Copies(hostName));
03186   NS_ENSURE_SUCCESS(rv,rv);
03187 
03188   prefName = prefPrefix;
03189   prefName.Append(".");
03190   prefName.Append(hostName.get());
03191 
03192   return NS_OK;
03193 }
03194 
03195 NS_IMETHODIMP
03196 nsImapIncomingServer::GetSupportsDiskSpace(PRBool *aSupportsDiskSpace)
03197 {
03198   NS_ENSURE_ARG_POINTER(aSupportsDiskSpace);
03199   nsCAutoString prefName;
03200   nsresult rv = CreateHostSpecificPrefName("default_supports_diskspace", prefName);
03201   NS_ENSURE_SUCCESS(rv,rv);
03202 
03203   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
03204   if (NS_SUCCEEDED(rv) && prefBranch) {
03205      rv = prefBranch->GetBoolPref(prefName.get(), aSupportsDiskSpace);
03206   }
03207 
03208   // Couldn't get the default value with the hostname.
03209   // Fall back on IMAP default value
03210   if (NS_FAILED(rv)) {
03211      // set default value
03212      *aSupportsDiskSpace = PR_TRUE;
03213   }
03214   return NS_OK;
03215 }
03216 
03217 // count number of non-busy connections in cache
03218 NS_IMETHODIMP
03219 nsImapIncomingServer::GetNumIdleConnections(PRInt32 *aNumIdleConnections)
03220 {
03221   NS_ENSURE_ARG_POINTER(aNumIdleConnections);
03222   *aNumIdleConnections = 0;
03223   
03224   nsresult rv = NS_OK;
03225   nsCOMPtr<nsIImapProtocol> connection;
03226   PRBool isBusy = PR_FALSE;
03227   PRBool isInboxConnection;
03228   PR_CEnterMonitor(this);
03229   
03230   PRUint32 cnt;
03231   
03232   rv = m_connectionCache->Count(&cnt);
03233   if (NS_FAILED(rv)) return rv;
03234   // loop counting idle connections
03235   for (PRUint32 i = 0; i < cnt; i++) 
03236   {
03237     connection = do_QueryElementAt(m_connectionCache, i);
03238     if (connection)
03239     {
03240       rv = connection->IsBusy(&isBusy, &isInboxConnection);
03241       if (NS_FAILED(rv)) 
03242         continue;
03243       if (!isBusy)
03244         (*aNumIdleConnections)++;
03245     }
03246   }
03247   PR_CExitMonitor(this);
03248   return rv;
03249 }
03250 
03251 
03261 NS_IMETHODIMP
03262 nsImapIncomingServer::GetCanCreateFoldersOnServer(PRBool *aCanCreateFoldersOnServer)
03263 {
03264     NS_ENSURE_ARG_POINTER(aCanCreateFoldersOnServer);
03265 
03266     // Initialize aCanCreateFoldersOnServer true, a default value for IMAP
03267     *aCanCreateFoldersOnServer = PR_TRUE;
03268 
03269     GetPrefForServerAttribute("canCreateFolders", aCanCreateFoldersOnServer);
03270 
03271     return NS_OK;
03272 }
03273 
03274 NS_IMETHODIMP
03275 nsImapIncomingServer::GetOfflineSupportLevel(PRInt32 *aSupportLevel)
03276 {
03277     NS_ENSURE_ARG_POINTER(aSupportLevel);
03278     nsresult rv = NS_OK;
03279     
03280     rv = GetIntValue("offline_support_level", aSupportLevel);
03281     if (*aSupportLevel != OFFLINE_SUPPORT_LEVEL_UNDEFINED) return rv;
03282     
03283     nsCAutoString prefName;
03284     rv = CreateHostSpecificPrefName("default_offline_support_level", prefName);
03285     NS_ENSURE_SUCCESS(rv,rv);
03286 
03287     nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
03288     if (NS_SUCCEEDED(rv) && prefBranch) {
03289       rv = prefBranch->GetIntPref(prefName.get(), aSupportLevel);
03290     } 
03291 
03292     // Couldn't get the pref value with the hostname. 
03293     // Fall back on IMAP default value
03294     if (NS_FAILED(rv)) {
03295       // set default value
03296       *aSupportLevel = OFFLINE_SUPPORT_LEVEL_REGULAR;
03297     }
03298     return NS_OK;
03299 }
03300 
03301 // Called only during the migration process. This routine enables the generation of 
03302 // unique account name based on the username, hostname and the port. If the port 
03303 // is valid and not a default one, it will be appended to the account name.
03304 NS_IMETHODIMP
03305 nsImapIncomingServer::GeneratePrettyNameForMigration(PRUnichar **aPrettyName)
03306 {
03307     NS_ENSURE_ARG_POINTER(aPrettyName);
03308     nsresult rv = NS_OK;
03309    
03310     nsXPIDLCString userName;
03311     nsXPIDLCString hostName;
03312 
03318     // Get user name to construct pretty name
03319     rv = GetUsername(getter_Copies(userName));
03320     NS_ENSURE_SUCCESS(rv, rv);
03321     
03322     // Get host name to construct pretty name
03323     rv = GetHostName(getter_Copies(hostName));
03324     NS_ENSURE_SUCCESS(rv, rv);
03325 
03326     PRInt32 defaultServerPort;
03327     PRInt32 defaultSecureServerPort;
03328 
03329     nsCOMPtr <nsIMsgProtocolInfo> protocolInfo = do_GetService("@mozilla.org/messenger/protocol/info;1?type=imap", &rv);
03330     NS_ENSURE_SUCCESS(rv,rv);
03331 
03332     // Get the default port
03333     rv = protocolInfo->GetDefaultServerPort(PR_FALSE, &defaultServerPort);
03334     NS_ENSURE_SUCCESS(rv,rv);
03335 
03336     // Get the default secure port
03337     rv = protocolInfo->GetDefaultServerPort(PR_TRUE, &defaultSecureServerPort);
03338     NS_ENSURE_SUCCESS(rv,rv);
03339 
03340     // Get the current server port
03341     PRInt32 serverPort = PORT_NOT_SET;
03342     rv = GetPort(&serverPort);
03343     NS_ENSURE_SUCCESS(rv,rv);
03344 
03345     // Is the server secure ?
03346     PRInt32 socketType;
03347     rv = GetSocketType(&socketType);
03348     NS_ENSURE_SUCCESS(rv,rv);
03349     PRBool isSecure = (socketType == nsIMsgIncomingServer::useSSL);
03350 
03351     // Is server port a default port ?
03352     PRBool isItDefaultPort = PR_FALSE;
03353     if (((serverPort == defaultServerPort) && !isSecure)|| 
03354         ((serverPort == defaultSecureServerPort) && isSecure)) {
03355         isItDefaultPort = PR_TRUE;
03356     }
03357 
03358     // Construct pretty name from username and hostname
03359     nsAutoString constructedPrettyName;
03360     constructedPrettyName.AssignWithConversion(userName);
03361     constructedPrettyName.AppendLiteral("@");
03362     constructedPrettyName.AppendWithConversion(hostName);
03363 
03364     // If the port is valid and not default, add port value to the pretty name
03365     if ((serverPort > 0) && (!isItDefaultPort)) {
03366         constructedPrettyName.AppendLiteral(":");
03367         constructedPrettyName.AppendInt(serverPort);
03368     }
03369 
03370     // Format the pretty name
03371     rv = GetFormattedStringFromID(constructedPrettyName.get(), IMAP_DEFAULT_ACCOUNT_NAME, aPrettyName);
03372     NS_ENSURE_SUCCESS(rv, rv);
03373 
03374     return rv;
03375 }
03376 
03377 nsresult
03378 nsImapIncomingServer::GetFormattedStringFromID(const PRUnichar *aValue, PRInt32 aID, PRUnichar **aResult)
03379 {
03380     NS_ENSURE_ARG_POINTER(aResult);
03381 
03382     nsresult rv;
03383     rv = GetStringBundle();
03384     if (m_stringBundle)
03385     {
03386         const PRUnichar *formatStrings[] =
03387         {
03388             aValue,
03389         };
03390         rv = m_stringBundle->FormatStringFromID(aID,
03391                                     formatStrings, 1,
03392                                     aResult);
03393         NS_ENSURE_SUCCESS(rv, rv);
03394     }
03395     return rv;
03396 }
03397 
03398 nsresult
03399 nsImapIncomingServer::CreatePrefNameWithRedirectorType(const char *prefSuffix, nsCAutoString &prefName)
03400 {
03401     NS_ENSURE_ARG_POINTER(prefSuffix);
03402 
03403     nsXPIDLCString redirectorType;
03404     nsresult rv = GetRedirectorType(getter_Copies(redirectorType));
03405     if (NS_FAILED(rv)) 
03406         return rv;
03407     if (!redirectorType)
03408         return NS_ERROR_FAILURE;
03409  
03410     prefName.Assign("imap.");
03411     prefName.Append(redirectorType);
03412     prefName.Append(prefSuffix);
03413 
03414     return NS_OK;
03415 }
03416 
03417 nsresult
03418 nsImapIncomingServer::GetPrefForServerAttribute(const char *prefSuffix, PRBool *prefValue)
03419 {
03420   NS_ENSURE_ARG_POINTER(prefSuffix);
03421   nsresult rv;
03422   nsCAutoString prefName;
03423   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
03424 
03425   nsXPIDLCString serverKey;
03426   rv = GetKey(getter_Copies(serverKey));
03427 
03428   // Time to check if this server has the pref 
03429   // (mail.server.<serverkey>.prefSuffix) already set
03430   nsMsgIncomingServer::getPrefName(serverKey, 
03431                                    prefSuffix, 
03432                                    prefName);
03433   rv = prefBranch->GetBoolPref(prefName.get(), prefValue);
03434 
03435   // If the server pref is not set in then look at the 
03436   // pref set with redirector type
03437   if (NS_FAILED(rv)) 
03438   {
03439     nsCAutoString redirectorType;
03440     redirectorType.Assign(".");
03441     redirectorType.Append(prefSuffix);
03442 
03443     rv = CreatePrefNameWithRedirectorType(redirectorType.get(), prefName);
03444 
03445     if (NS_SUCCEEDED(rv)) 
03446       rv = prefBranch->GetBoolPref(prefName.get(), prefValue);
03447   }
03448 
03449   return rv;
03450 }
03451 
03452 NS_IMETHODIMP
03453 nsImapIncomingServer::GetCanFileMessagesOnServer(PRBool *aCanFileMessagesOnServer)
03454 {
03455     NS_ENSURE_ARG_POINTER(aCanFileMessagesOnServer);
03456 
03457     // Initialize aCanFileMessagesOnServer true, a default value for IMAP
03458     *aCanFileMessagesOnServer = PR_TRUE;
03459 
03460     GetPrefForServerAttribute("canFileMessages", aCanFileMessagesOnServer);
03461 
03462     return NS_OK;
03463 }
03464 
03465 NS_IMETHODIMP
03466 nsImapIncomingServer::SetSearchValue(const nsAString &searchValue)
03467 {
03468     return NS_ERROR_NOT_IMPLEMENTED;
03469 }
03470 
03471 NS_IMETHODIMP
03472 nsImapIncomingServer::GetSupportsSubscribeSearch(PRBool *retVal)
03473 {
03474    *retVal = PR_FALSE;
03475    return NS_OK;
03476 }
03477 
03478 NS_IMETHODIMP
03479 nsImapIncomingServer::GetFilterScope(nsMsgSearchScopeValue *filterScope)
03480 {
03481    NS_ENSURE_ARG_POINTER(filterScope);
03482 
03483    *filterScope = nsMsgSearchScope::onlineMailFilter;
03484    return NS_OK;
03485 }
03486 
03487 NS_IMETHODIMP
03488 nsImapIncomingServer::GetSearchScope(nsMsgSearchScopeValue *searchScope)
03489 {
03490    NS_ENSURE_ARG_POINTER(searchScope);
03491    
03492    if (WeAreOffline()) {
03493      *searchScope = nsMsgSearchScope::offlineMail;
03494    }
03495    else {
03496      *searchScope = nsMsgSearchScope::onlineMail;
03497    }
03498    return NS_OK;
03499 }
03500 
03501 // This is a recursive function. It gets new messages for current folder
03502 // first if it is marked, then calls itself recursively for each subfolder.
03503 NS_IMETHODIMP 
03504 nsImapIncomingServer::GetNewMessagesForNonInboxFolders(nsIMsgFolder *aFolder,
03505                                                        nsIMsgWindow *aWindow,
03506                                                        PRBool forceAllFolders,
03507                                                        PRBool performingBiff)
03508 {
03509   nsresult retval = NS_OK;
03510   static PRBool gGotStatusPref = PR_FALSE;
03511   static PRBool gUseStatus = PR_FALSE;
03512   if (!aFolder)
03513     return retval;
03514 
03515   PRBool isServer;
03516   (void) aFolder->GetIsServer(&isServer);
03517   // Check this folder for new messages if it is marked to be checked
03518   // or if we are forced to check all folders
03519   PRUint32 flags = 0;
03520   aFolder->GetFlags(&flags);
03521   if ((forceAllFolders && 
03522     !(flags & (MSG_FOLDER_FLAG_INBOX | MSG_FOLDER_FLAG_TRASH | MSG_FOLDER_FLAG_JUNK | MSG_FOLDER_FLAG_IMAP_NOSELECT)))
03523     || (flags & MSG_FOLDER_FLAG_CHECK_NEW))
03524   {
03525     // Get new messages for this folder.
03526     aFolder->SetGettingNewMessages(PR_TRUE);
03527     if (performingBiff)
03528     {
03529       nsresult rv;
03530       nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aFolder, &rv);
03531       if (imapFolder)
03532         imapFolder->SetPerformingBiff(PR_TRUE);
03533     }
03534     PRBool isOpen = PR_FALSE;
03535     nsCOMPtr <nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID);
03536     if (mailSession && aFolder)
03537       mailSession->IsFolderOpenInWindow(aFolder, &isOpen);
03538     // eventually, the gGotStatusPref should go away, once we work out the kinks
03539     // from using STATUS.
03540     if (!gGotStatusPref)
03541     {
03542       nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
03543       if(prefBranch)  
03544         prefBranch->GetBoolPref("mail.imap.use_status_for_biff", &gUseStatus);
03545       gGotStatusPref = PR_TRUE;
03546     }
03547     if (gUseStatus && !isOpen)
03548     {
03549       nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aFolder);
03550       if (imapFolder && !isServer)
03551         m_foldersToStat.AppendObject(imapFolder);
03552         //imapFolder->UpdateStatus(this, nsnull /* aWindow - null window will prevent alerts */);
03553     }
03554     else
03555     {
03556       aFolder->UpdateFolder(aWindow);
03557     }
03558   }
03559 
03560   // Loop through all subfolders to get new messages for them.
03561   nsCOMPtr<nsIEnumerator> aEnumerator;
03562   retval = aFolder->GetSubFolders(getter_AddRefs(aEnumerator));
03563   NS_ASSERTION((NS_SUCCEEDED(retval) && aEnumerator), "GetSubFolders() failed to return enumerator.");
03564   if (NS_FAILED(retval)) 
03565     return retval;
03566 
03567   nsresult more = aEnumerator->First();
03568 
03569   while (NS_SUCCEEDED(more))
03570   {
03571     nsCOMPtr<nsISupports> aSupport;
03572     nsresult rv = aEnumerator->CurrentItem(getter_AddRefs(aSupport));
03573     NS_ASSERTION((NS_SUCCEEDED(rv) && aSupport), "CurrentItem() failed.");
03574                      
03575     nsCOMPtr<nsIMsgFolder> msgFolder = do_QueryInterface(aSupport, &rv);
03576     NS_ASSERTION((NS_SUCCEEDED(rv) && msgFolder), "nsIMsgFolder service not found.");
03577 
03578     retval = GetNewMessagesForNonInboxFolders(msgFolder, aWindow, forceAllFolders, performingBiff);
03579 
03580     more = aEnumerator->Next();
03581   }
03582 
03583   if (isServer)
03584   {
03585     PRInt32 folderCount = m_foldersToStat.Count();
03586     if (folderCount > 0)
03587       m_foldersToStat[folderCount - 1]->UpdateStatus(this, nsnull);
03588   }
03589   return retval;
03590 }
03591 
03592 NS_IMETHODIMP
03593 nsImapIncomingServer::GetArbitraryHeaders(char **aResult)
03594 {
03595   nsCOMPtr <nsIMsgFilterList> filterList;  
03596   nsresult rv = GetFilterList(nsnull, getter_AddRefs(filterList));
03597   NS_ENSURE_SUCCESS(rv,rv);
03598 
03599   rv = filterList->GetArbitraryHeaders(aResult);
03600   return rv;
03601 }
03602 
03603 NS_IMETHODIMP
03604 nsImapIncomingServer::GetShowAttachmentsInline(PRBool *aResult)
03605 {
03606   *aResult = PR_TRUE; // true per default
03607  
03608   nsresult rv; 
03609   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
03610   NS_ENSURE_SUCCESS(rv,rv);
03611   
03612   prefBranch->GetBoolPref("mail.inline_attachments", aResult);
03613   return NS_OK; // In case this pref is not set we need to return NS_OK.
03614 }
03615 
03616 NS_IMETHODIMP nsImapIncomingServer::SetSocketType(PRInt32 aSocketType)
03617 {
03618   PRInt32 oldSocketType;
03619   nsresult rv = GetSocketType(&oldSocketType);
03620   if (NS_SUCCEEDED(rv) && oldSocketType != aSocketType)
03621     CloseCachedConnections();
03622   nsCAutoString fullPrefName;
03623   getPrefName(m_serverKey.get(), "socketType", fullPrefName);
03624   return m_prefBranch->SetIntPref(fullPrefName.get(), aSocketType);
03625 }
03626 
03627 NS_IMETHODIMP
03628 nsImapIncomingServer::OnUserOrHostNameChanged(const char *oldName, const char *newName)
03629 {
03630   nsresult rv;
03631   // 1. Do common things in the base class.
03632   rv = nsMsgIncomingServer::OnUserOrHostNameChanged(oldName, newName);
03633   NS_ENSURE_SUCCESS(rv,rv);
03634 
03635   // 2. Reset 'HaveWeEverDiscoveredFolders' flag so the new folder list can be
03636   //    reloaded (ie, DiscoverMailboxList() will be invoked in nsImapProtocol).
03637   nsCOMPtr<nsIImapHostSessionList> hostSessionList = do_GetService(kCImapHostSessionListCID, &rv);
03638   NS_ENSURE_SUCCESS(rv, rv);
03639   nsXPIDLCString serverKey;
03640   rv = GetKey(getter_Copies(serverKey));
03641   NS_ENSURE_SUCCESS(rv, rv);
03642   hostSessionList->SetHaveWeEverDiscoveredFoldersForHost(serverKey.get(), PR_FALSE);
03643 
03644   // 3. Make all the existing folders 'unverified' so that they can be
03645   //    removed from the folder pane after users log into the new server.
03646   ResetFoldersToUnverified(nsnull);
03647   return NS_OK;
03648 }
03649 
03650 // use canonical format in originalUri & convertedUri
03651 NS_IMETHODIMP
03652 nsImapIncomingServer::GetUriWithNamespacePrefixIfNecessary(PRInt32 namespaceType,
03653                                                            const char *originalUri,
03654                                                            char **convertedUri)
03655 {
03656   NS_ENSURE_ARG_POINTER(convertedUri);
03657   *convertedUri = nsnull;
03658 
03659   nsresult rv = NS_OK;
03660   nsXPIDLCString serverKey;
03661   rv = GetKey(getter_Copies(serverKey));
03662   if (NS_FAILED(rv)) return rv;
03663   nsCOMPtr<nsIImapHostSessionList> hostSessionList = do_GetService(kCImapHostSessionListCID, &rv);
03664   nsIMAPNamespace *ns = nsnull;
03665   rv = hostSessionList->GetDefaultNamespaceOfTypeForHost(serverKey, (EIMAPNamespaceType)namespaceType, ns);
03666   if (ns)
03667   {
03668     nsCAutoString namespacePrefix(ns->GetPrefix());
03669     if (!namespacePrefix.IsEmpty())
03670     {
03671       // check if namespacePrefix is the same as the online directory; if so, ignore it.
03672 
03673       nsXPIDLCString onlineDir;
03674       rv = GetServerDirectory(getter_Copies(onlineDir));
03675       NS_ENSURE_SUCCESS(rv, rv);
03676       if (!onlineDir.IsEmpty())
03677       {
03678         char delimiter = ns->GetDelimiter();
03679           if ( onlineDir.Last() != delimiter )
03680             onlineDir += delimiter;
03681           if (onlineDir.Equals(namespacePrefix))
03682             return NS_OK;
03683       }
03684 
03685       namespacePrefix.ReplaceChar(ns->GetDelimiter(), '/'); // use canonical format
03686       nsCAutoString resultUri(originalUri);
03687       PRInt32 index = resultUri.Find("//");           // find scheme
03688       index = resultUri.Find("/", PR_FALSE, index+2); // find '/' after scheme
03689       // it may be the case that this is the INBOX uri, in which case
03690       // we don't want to prepend the namespace. In that case, the uri ends with "INBOX",
03691       // but the namespace is "INBOX/", so they don't match.
03692       if (resultUri.Find(namespacePrefix.get(), PR_FALSE, index+1) != index+1
03693         && !Substring(resultUri, index + 1, resultUri.Length() - index - 1).LowerCaseEqualsLiteral("inbox"))
03694         resultUri.Insert(namespacePrefix, index+1);   // insert namespace prefix
03695       *convertedUri = nsCRT::strdup(resultUri.get());
03696     }
03697   }
03698   return rv;
03699 }
03700 
03701 NS_IMETHODIMP nsImapIncomingServer::GetTrashFolderName(PRUnichar **retval)
03702 {
03703   nsresult rv = GetUnicharValue(PREF_TRASH_FOLDER_NAME, retval);
03704   if (NS_FAILED(rv))
03705     return rv;
03706 
03707   if (!*retval || !**retval)
03708   {
03709       // if GetUnicharValue() above returned allocated empty string, we must free it first
03710       // before allocating space and assigning the default value
03711       if (*retval)
03712           nsMemory::Free(*retval);
03713       *retval = ToNewUnicode(NS_LITERAL_STRING(DEFAULT_TRASH_FOLDER_NAME));
03714   }
03715   return NS_OK;
03716 }
03717 
03718 NS_IMETHODIMP nsImapIncomingServer::SetTrashFolderName(const PRUnichar *chvalue)
03719 {
03720   // clear trash flag from the old pref
03721   nsXPIDLString oldTrashName;
03722   nsresult rv = GetTrashFolderName(getter_Copies(oldTrashName));
03723   if (NS_SUCCEEDED(rv))
03724   {
03725     nsCAutoString oldTrashNameUtf7;
03726     rv = CopyUTF16toMUTF7(oldTrashName, oldTrashNameUtf7);
03727     if (NS_SUCCEEDED(rv))
03728     {
03729       nsCOMPtr<nsIMsgFolder> oldFolder;
03730       rv = GetFolder(oldTrashNameUtf7.get(), getter_AddRefs(oldFolder));
03731       if (NS_SUCCEEDED(rv) && oldFolder)
03732       {
03733         oldFolder->ClearFlag(MSG_FOLDER_FLAG_TRASH);
03734       }
03735     }
03736   }
03737   
03738   return SetUnicharValue(PREF_TRASH_FOLDER_NAME, chvalue);
03739 }
03740 
03741 NS_IMETHODIMP
03742 nsImapIncomingServer::GetMsgFolderFromURI(nsIMsgFolder *aFolderResource, const char *aURI, nsIMsgFolder **aFolder)
03743 {
03744   nsCOMPtr<nsIMsgFolder> rootMsgFolder;
03745   nsresult rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
03746   NS_ENSURE_SUCCESS(rv, rv);
03747   if (!rootMsgFolder)
03748     return NS_ERROR_UNEXPECTED;
03749 
03750   nsCOMPtr <nsIMsgFolder> msgFolder;
03751   PRBool namespacePrefixAdded = PR_FALSE;
03752   nsXPIDLCString folderUriWithNamespace;
03753 
03754   // Check if the folder exists as is...Even if we have a personal namespace,
03755   // it might be in another namespace (e.g., shared) and this will catch that.
03756   rv = rootMsgFolder->GetChildWithURI(aURI, PR_TRUE, PR_FALSE, getter_AddRefs(msgFolder));
03757 
03758   // If we couldn't find the folder as is, check if we need to prepend the
03759   // personal namespace
03760   if (!msgFolder)
03761   {
03762     GetUriWithNamespacePrefixIfNecessary(kPersonalNamespace, aURI, getter_Copies(folderUriWithNamespace));
03763     if (!folderUriWithNamespace.IsEmpty()) 
03764     {
03765       namespacePrefixAdded = PR_TRUE;
03766       rv = rootMsgFolder->GetChildWithURI(folderUriWithNamespace, PR_TRUE, PR_FALSE, getter_AddRefs(msgFolder));
03767     }
03768     else 
03769     {
03770       rv = rootMsgFolder->GetChildWithURI(aURI, PR_TRUE, PR_FALSE, getter_AddRefs(msgFolder));
03771     }
03772   }
03773 
03774   if (NS_FAILED(rv) || !msgFolder) {
03775     // we didn't find the folder so we will have to create new one.
03776     if (namespacePrefixAdded)
03777     {
03778       nsCOMPtr <nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
03779       NS_ENSURE_SUCCESS(rv,rv);
03780 
03781       nsCOMPtr<nsIRDFResource> resource;
03782       rv = rdf->GetResource(folderUriWithNamespace, getter_AddRefs(resource));
03783       NS_ENSURE_SUCCESS(rv,rv);
03784       
03785       nsCOMPtr <nsIMsgFolder> folderResource;
03786       folderResource = do_QueryInterface(resource, &rv);
03787       NS_ENSURE_SUCCESS(rv,rv);
03788       msgFolder = folderResource;
03789     }
03790     else
03791       msgFolder = aFolderResource;
03792   }
03793 
03794   NS_IF_ADDREF(*aFolder = msgFolder);
03795   return NS_OK;
03796 }
03797 
03798 NS_IMETHODIMP
03799 nsImapIncomingServer::CramMD5Hash(const char *decodedChallenge, const char *key, char **result)
03800 {
03801   unsigned char resultDigest[DIGEST_LENGTH];
03802   nsresult rv = MSGCramMD5(decodedChallenge, strlen(decodedChallenge), 
03803         key, strlen(key), resultDigest);
03804   NS_ENSURE_SUCCESS(rv, rv);
03805   *result = (char *) malloc(DIGEST_LENGTH);
03806   if (*result)
03807     memcpy(*result, resultDigest, DIGEST_LENGTH);
03808   return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
03809 }
03810