Back to index

lightning-sunbird  0.9+nobinonly
nsMsgIncomingServer.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  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *   David Bienvenu <bienvenu@nventure.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsMsgIncomingServer.h"
00041 #include "nscore.h"
00042 #include "plstr.h"
00043 #include "prmem.h"
00044 #include "prprf.h"
00045 
00046 #include "nsIServiceManager.h"
00047 #include "nsCOMPtr.h"
00048 #include "nsXPIDLString.h"
00049 #include "nsReadableUtils.h"
00050 #include "nsEscape.h"
00051 #include "nsISupportsObsolete.h"
00052 #include "nsISupportsPrimitives.h"
00053 
00054 #include "nsMsgBaseCID.h"
00055 #include "nsMsgDBCID.h"
00056 #include "nsIMsgFolder.h"
00057 #include "nsIMsgFolderCache.h"
00058 #include "nsIMsgFolderCacheElement.h"
00059 #include "nsIMsgWindow.h"
00060 #include "nsIMsgFilterService.h"
00061 #include "nsIMsgProtocolInfo.h"
00062 #include "nsIMsgMailSession.h"
00063 #include "nsIPrefService.h"
00064 #include "nsIDocShell.h"
00065 #include "nsIAuthPrompt.h"
00066 #include "nsIObserverService.h"
00067 #include "nsNetUtil.h"
00068 #include "nsIWindowWatcher.h"
00069 #include "nsIStringBundle.h"
00070 #include "nsIMsgHdr.h"
00071 #include "nsIRDFService.h"
00072 #include "nsRDFCID.h"
00073 #include "nsIInterfaceRequestor.h"
00074 #include "nsIInterfaceRequestorUtils.h"
00075 
00076 #include "nsIMsgAccountManager.h"
00077 #include "nsCPasswordManager.h"
00078 #include "nsIMsgMdnGenerator.h"
00079 #include "nsMsgFolderFlags.h"
00080 #include "nsMsgUtils.h"
00081 #include "nsAppDirectoryServiceDefs.h"
00082 
00083 #define PORT_NOT_SET -1
00084 
00085 #define REL_FILE_PREF_SUFFIX NS_LITERAL_CSTRING("-rel")
00086 
00087 MOZ_DECL_CTOR_COUNTER(nsMsgIncomingServer)
00088 
00089 nsMsgIncomingServer::nsMsgIncomingServer():
00090     m_rootFolder(0),
00091     m_prefBranch(0),
00092     m_biffState(nsIMsgFolder::nsMsgBiffState_NoMail),
00093     m_serverBusy(PR_FALSE),
00094     m_numMsgsDownloaded(0),
00095     m_canHaveFilters(PR_TRUE),
00096     m_displayStartupPage(PR_TRUE),
00097     mPerformingBiff(PR_FALSE)
00098 {
00099 }
00100 
00101 nsMsgIncomingServer::~nsMsgIncomingServer()
00102 {
00103     NS_IF_RELEASE(m_prefBranch);
00104 }
00105 
00106 NS_IMPL_THREADSAFE_ADDREF(nsMsgIncomingServer)
00107 NS_IMPL_THREADSAFE_RELEASE(nsMsgIncomingServer)
00108 NS_INTERFACE_MAP_BEGIN(nsMsgIncomingServer)
00109     NS_INTERFACE_MAP_ENTRY(nsIMsgIncomingServer)
00110     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00111     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMsgIncomingServer)
00112 NS_INTERFACE_MAP_END_THREADSAFE
00113 
00114 NS_IMPL_GETSET(nsMsgIncomingServer, ServerBusy, PRBool, m_serverBusy)
00115 NS_IMPL_GETTER_STR(nsMsgIncomingServer::GetKey, m_serverKey.get())
00116 
00117 NS_IMETHODIMP
00118 nsMsgIncomingServer::SetKey(const char * serverKey)
00119 {
00120     m_serverKey.Assign(serverKey);
00121 
00122     // in order to actually make use of the key, we need the prefs
00123     if (m_prefBranch)
00124         return NS_OK;
00125 
00126     return CallGetService(NS_PREFSERVICE_CONTRACTID, &m_prefBranch);
00127 }
00128     
00129 NS_IMETHODIMP
00130 nsMsgIncomingServer::SetRootFolder(nsIMsgFolder * aRootFolder)
00131 {
00132   m_rootFolder = aRootFolder;
00133   return NS_OK;
00134 }
00135 
00136 // this will return the root folder of this account,
00137 // even if this server is deferred.
00138 NS_IMETHODIMP
00139 nsMsgIncomingServer::GetRootFolder(nsIMsgFolder * *aRootFolder)
00140 {
00141   NS_ENSURE_ARG_POINTER(aRootFolder);
00142   if (m_rootFolder)
00143   {
00144     *aRootFolder = m_rootFolder;
00145     NS_ADDREF(*aRootFolder);
00146   } 
00147   else 
00148   {
00149     nsresult rv = CreateRootFolder();
00150     NS_ENSURE_SUCCESS(rv, rv);
00151     NS_IF_ADDREF(*aRootFolder = m_rootFolder);
00152   }
00153   return NS_OK;
00154 }
00155 
00156 // this will return the root folder of the deferred to account,
00157 // if this server is deferred.
00158 NS_IMETHODIMP
00159 nsMsgIncomingServer::GetRootMsgFolder(nsIMsgFolder **aRootMsgFolder)
00160 {
00161   NS_ENSURE_ARG_POINTER(aRootMsgFolder);
00162 
00163   if (!m_rootFolder)
00164   {
00165     nsresult rv = CreateRootFolder();
00166     if (NS_FAILED(rv))
00167       return rv;
00168   }
00169 
00170   NS_IF_ADDREF(*aRootMsgFolder = m_rootFolder);
00171   return NS_OK;
00172 }
00173 
00174 NS_IMETHODIMP
00175 nsMsgIncomingServer::PerformExpand(nsIMsgWindow *aMsgWindow)
00176 {
00177 #ifdef DEBUG_sspitzer
00178   printf("PerformExpand()\n");
00179 #endif
00180   return NS_OK;
00181 }
00182 
00183   
00184 NS_IMETHODIMP
00185 nsMsgIncomingServer::PerformBiff(nsIMsgWindow* aMsgWindow)
00186 {
00187   //This has to be implemented in the derived class, but in case someone doesn't implement it
00188   //just return not implemented.
00189   return NS_ERROR_NOT_IMPLEMENTED; 
00190 }
00191 
00192 NS_IMETHODIMP
00193 nsMsgIncomingServer::GetNewMessages(nsIMsgFolder *aFolder, nsIMsgWindow *aMsgWindow, 
00194                       nsIUrlListener *aUrlListener)
00195 {
00196   return aFolder->GetNewMessages(aMsgWindow, aUrlListener);
00197 }
00198 
00199 NS_IMETHODIMP nsMsgIncomingServer::GetPerformingBiff(PRBool *aPerformingBiff)
00200 {
00201   NS_ENSURE_ARG_POINTER(aPerformingBiff);
00202   *aPerformingBiff = mPerformingBiff;
00203   return NS_OK;
00204 }
00205 
00206 NS_IMETHODIMP nsMsgIncomingServer::SetPerformingBiff(PRBool aPerformingBiff)
00207 {
00208   mPerformingBiff = aPerformingBiff;
00209   return NS_OK;
00210 }
00211 
00212 NS_IMPL_GETSET(nsMsgIncomingServer, BiffState, PRUint32, m_biffState)
00213 
00214 NS_IMETHODIMP nsMsgIncomingServer::WriteToFolderCache(nsIMsgFolderCache *folderCache)
00215 {
00216   nsresult rv = NS_OK;
00217   if (m_rootFolder)
00218   {
00219     nsCOMPtr <nsIMsgFolder> msgFolder = do_QueryInterface(m_rootFolder, &rv);
00220     if (NS_SUCCEEDED(rv) && msgFolder)
00221       rv = msgFolder->WriteToFolderCache(folderCache, PR_TRUE /* deep */);
00222   }
00223   return rv;
00224 }
00225 
00226 NS_IMETHODIMP
00227 nsMsgIncomingServer::Shutdown()
00228 {
00229   nsresult rv = CloseCachedConnections();
00230   mFilterPlugin = nsnull;
00231   NS_ENSURE_SUCCESS(rv,rv);
00232 
00233   if (mFilterList) 
00234   {
00235     // close the filter log stream
00236     rv = mFilterList->SetLogStream(nsnull);
00237     NS_ENSURE_SUCCESS(rv,rv);
00238     mFilterList = nsnull;
00239   }
00240 
00241   if (mSpamSettings) 
00242   {
00243     // close the spam log stream
00244     rv = mSpamSettings->SetLogStream(nsnull);
00245     NS_ENSURE_SUCCESS(rv,rv);
00246     mSpamSettings = nsnull;
00247   }
00248   return rv;
00249 }
00250 
00251 NS_IMETHODIMP
00252 nsMsgIncomingServer::CloseCachedConnections()
00253 {
00254   // derived class should override if they cache connections.
00255   return NS_OK;
00256 }
00257 
00258 NS_IMETHODIMP
00259 nsMsgIncomingServer::GetDownloadMessagesAtStartup(PRBool *getMessagesAtStartup)
00260 {
00261     // derived class should override if they need to do this.
00262     *getMessagesAtStartup = PR_FALSE;
00263     return NS_OK;
00264 }
00265 
00266 NS_IMETHODIMP
00267 nsMsgIncomingServer::GetCanHaveFilters(PRBool *canHaveFilters)
00268 {
00269     // derived class should override if they need to do this.
00270     *canHaveFilters = m_canHaveFilters;
00271     return NS_OK;
00272 }
00273 
00274 NS_IMETHODIMP
00275 nsMsgIncomingServer::GetCanBeDefaultServer(PRBool *canBeDefaultServer)
00276 {
00277     // derived class should override if they need to do this.
00278     *canBeDefaultServer = PR_FALSE;
00279     return NS_OK;
00280 }
00281 
00282 NS_IMETHODIMP
00283 nsMsgIncomingServer::GetCanSearchMessages(PRBool *canSearchMessages)
00284 {
00285     // derived class should override if they need to do this.
00286     NS_ENSURE_ARG_POINTER(canSearchMessages);
00287     *canSearchMessages = PR_FALSE;
00288     return NS_OK;
00289 }
00290 
00291 NS_IMETHODIMP
00292 nsMsgIncomingServer::GetCanCompactFoldersOnServer(PRBool *canCompactFoldersOnServer)
00293 {
00294     // derived class should override if they need to do this.
00295     NS_ENSURE_ARG_POINTER(canCompactFoldersOnServer);
00296     *canCompactFoldersOnServer = PR_TRUE;
00297     return NS_OK;
00298 }
00299 
00300 NS_IMETHODIMP
00301 nsMsgIncomingServer::GetCanUndoDeleteOnServer(PRBool *canUndoDeleteOnServer)
00302 {
00303     // derived class should override if they need to do this.
00304     NS_ENSURE_ARG_POINTER(canUndoDeleteOnServer);
00305     *canUndoDeleteOnServer = PR_TRUE;
00306     return NS_OK;
00307 }
00308 
00309 NS_IMETHODIMP
00310 nsMsgIncomingServer::GetCanEmptyTrashOnExit(PRBool *canEmptyTrashOnExit)
00311 {
00312     // derived class should override if they need to do this.
00313     NS_ENSURE_ARG_POINTER(canEmptyTrashOnExit);
00314     *canEmptyTrashOnExit = PR_TRUE;
00315     return NS_OK;
00316 }
00317 
00318 NS_IMETHODIMP
00319 nsMsgIncomingServer::GetIsSecureServer(PRBool *isSecureServer)
00320 {
00321     // derived class should override if they need to do this.
00322     NS_ENSURE_ARG_POINTER(isSecureServer);
00323     *isSecureServer = PR_TRUE;
00324     return NS_OK;
00325 }
00326 
00327 // construct <localStoreType>://[<username>@]<hostname
00328 NS_IMETHODIMP
00329 nsMsgIncomingServer::GetServerURI(char* *aResult)
00330 {
00331     NS_ENSURE_ARG_POINTER(aResult);
00332     nsresult rv;
00333     nsCAutoString uri;
00334 
00335     nsXPIDLCString localStoreType;
00336     rv = GetLocalStoreType(getter_Copies(localStoreType));
00337     if (NS_FAILED(rv)) return rv;
00338 
00339     uri.Append(localStoreType);
00340     uri += "://";
00341 
00342     nsXPIDLCString username;
00343     rv = GetUsername(getter_Copies(username));
00344 
00345     if (NS_SUCCEEDED(rv) && ((const char*)username) && username[0]) {
00346         nsXPIDLCString escapedUsername;
00347         *((char **)getter_Copies(escapedUsername)) =
00348             nsEscape(username, url_XAlphas);
00349 //            nsEscape(username, url_Path);
00350         // not all servers have a username 
00351         uri.Append(escapedUsername);
00352         uri += '@';
00353     }
00354 
00355     nsXPIDLCString hostname;
00356     rv = GetHostName(getter_Copies(hostname));
00357 
00358     if (NS_SUCCEEDED(rv) && ((const char*)hostname) && hostname[0]) {
00359         nsXPIDLCString escapedHostname;
00360         *((char **)getter_Copies(escapedHostname)) =
00361             nsEscape(hostname, url_Path);
00362         // not all servers have a hostname
00363         uri.Append(escapedHostname);
00364     }
00365 
00366     *aResult = ToNewCString(uri);
00367     return NS_OK;
00368 }
00369 
00370 // helper routine to create local folder on disk, if it doesn't exist.
00371 // Path must already have a LeafName for this to work...
00372 nsresult
00373 nsMsgIncomingServer::CreateLocalFolder(nsIFileSpec *path, const char *folderName)
00374 {
00375   (void) path->SetLeafName(folderName); // never fails
00376   PRBool exists;
00377   nsresult rv = path->Exists(&exists);
00378   NS_ENSURE_SUCCESS(rv, rv);
00379   if (!exists) 
00380     rv = path->Touch();
00381   return rv;
00382 }
00383 
00384 
00385 nsresult
00386 nsMsgIncomingServer::CreateRootFolder()
00387 {
00388   nsresult rv;
00389                        // get the URI from the incoming server
00390   nsXPIDLCString serverUri;
00391   rv = GetServerURI(getter_Copies(serverUri));
00392   if (NS_FAILED(rv)) return rv;
00393 
00394   nsCOMPtr<nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
00395   NS_ENSURE_SUCCESS(rv, rv);
00396 
00397   // get the corresponding RDF resource
00398   // RDF will create the server resource if it doesn't already exist
00399   nsCOMPtr<nsIRDFResource> serverResource;
00400   rv = rdf->GetResource(serverUri, getter_AddRefs(serverResource));
00401   if (NS_FAILED(rv)) return rv;
00402 
00403   // make incoming server know about its root server folder so we 
00404   // can find sub-folders given an incoming server.
00405   m_rootFolder = do_QueryInterface(serverResource, &rv);
00406   return rv;
00407 }
00408 
00409 void
00410 nsMsgIncomingServer::getPrefName(const char *serverKey,
00411                                  const char *prefName,
00412                                  nsCString& fullPrefName)
00413 {
00414     // mail.server.<key>.<pref>
00415     fullPrefName = "mail.server.";
00416     fullPrefName.Append(serverKey);
00417     fullPrefName.Append('.');
00418     fullPrefName.Append(prefName);
00419 }
00420 
00421 // this will be slightly faster than the above, and allows
00422 // the "default" server preference root to be set in one place
00423 void
00424 nsMsgIncomingServer::getDefaultPrefName(const char *prefName,
00425                                         nsCString& fullPrefName)
00426 {
00427     // mail.server.default.<pref>
00428     fullPrefName = "mail.server.default.";
00429     fullPrefName.Append(prefName);
00430 }
00431 
00432 
00433 nsresult
00434 nsMsgIncomingServer::GetBoolValue(const char *prefname,
00435                                  PRBool *val)
00436 {
00437   nsCAutoString fullPrefName;
00438   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00439   nsresult rv = m_prefBranch->GetBoolPref(fullPrefName.get(), val);
00440   
00441   if (NS_FAILED(rv))
00442     rv = getDefaultBoolPref(prefname, val);
00443   
00444   return rv;
00445 }
00446 
00447 
00448 nsresult
00449 nsMsgIncomingServer::getDefaultBoolPref(const char *prefname,
00450                                         PRBool *val) {
00451   
00452   nsCAutoString fullPrefName;
00453   getDefaultPrefName(prefname, fullPrefName);
00454   nsresult rv = m_prefBranch->GetBoolPref(fullPrefName.get(), val);
00455 
00456   if (NS_FAILED(rv)) {
00457     *val = PR_FALSE;
00458     rv = NS_OK;
00459   }
00460   return rv;
00461 }
00462 
00463 
00464 nsresult
00465 nsMsgIncomingServer::SetBoolValue(const char *prefname,
00466                                  PRBool val)
00467 {
00468   nsresult rv;
00469   nsCAutoString fullPrefName;
00470   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00471 
00472   PRBool defaultValue;
00473   rv = getDefaultBoolPref(prefname, &defaultValue);
00474 
00475   if (NS_SUCCEEDED(rv) && val == defaultValue)
00476     m_prefBranch->ClearUserPref(fullPrefName.get());
00477   else
00478     rv = m_prefBranch->SetBoolPref(fullPrefName.get(), val);
00479   
00480   return rv;
00481 }
00482 
00483 nsresult
00484 nsMsgIncomingServer::GetIntValue(const char *prefname,
00485                                 PRInt32 *val)
00486 {
00487   nsCAutoString fullPrefName;
00488   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00489   nsresult rv = m_prefBranch->GetIntPref(fullPrefName.get(), val);
00490 
00491   if (NS_FAILED(rv))
00492     rv = getDefaultIntPref(prefname, val);
00493   
00494   return rv;
00495 }
00496 
00497 nsresult
00498 nsMsgIncomingServer::GetFileValue(const char* prefname,
00499                                   nsIFileSpec **spec)
00500 {
00501   nsCAutoString fullPrefName;
00502   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00503   
00504   nsCAutoString fullRelPrefName(fullPrefName);
00505   fullRelPrefName.Append(REL_FILE_PREF_SUFFIX);
00506   nsCOMPtr<nsILocalFile> prefLocal;
00507   
00508   PRBool gotRelPref;
00509   nsresult rv = NS_GetPersistentFile(fullRelPrefName.get(), fullPrefName.get(),
00510                                      nsnull, gotRelPref, getter_AddRefs(prefLocal));
00511   if (NS_FAILED(rv)) return rv;
00512 
00513   if (NS_SUCCEEDED(rv) && !gotRelPref) 
00514   {
00515     rv = NS_SetPersistentFile(fullRelPrefName.get(), fullPrefName.get(), prefLocal);
00516     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to update file pref.");
00517   }
00518   
00519   if (NS_FAILED(rv)) return rv;
00520 
00521   nsCOMPtr<nsIFileSpec> outSpec;
00522   rv = NS_NewFileSpecFromIFile(prefLocal, getter_AddRefs(outSpec));
00523   if (NS_FAILED(rv)) return rv;
00524   
00525   *spec = outSpec;
00526   NS_ADDREF(*spec);
00527 
00528   return NS_OK;
00529 }
00530 
00531 nsresult
00532 nsMsgIncomingServer::SetFileValue(const char* prefname,
00533                                     nsIFileSpec *spec)
00534 {
00535   nsCAutoString fullPrefName;
00536   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00537   nsCAutoString fullRelPrefName(fullPrefName);
00538   fullRelPrefName.Append(REL_FILE_PREF_SUFFIX);
00539   
00540   nsresult rv;
00541   nsFileSpec tempSpec;
00542   rv = spec->GetFileSpec(&tempSpec);
00543   if (NS_FAILED(rv)) return rv;
00544 
00545   nsCOMPtr<nsILocalFile> localFile;
00546   NS_FileSpecToIFile(&tempSpec, getter_AddRefs(localFile));
00547   if (!localFile) 
00548     return NS_ERROR_FAILURE;
00549   return NS_SetPersistentFile(fullRelPrefName.get(), fullPrefName.get(), localFile);
00550 }
00551 
00552 nsresult
00553 nsMsgIncomingServer::getDefaultIntPref(const char *prefname,
00554                                         PRInt32 *val) {
00555   
00556   nsCAutoString fullPrefName;
00557   getDefaultPrefName(prefname, fullPrefName);
00558   nsresult rv = m_prefBranch->GetIntPref(fullPrefName.get(), val);
00559 
00560   if (NS_FAILED(rv)) {
00561     *val = 0;
00562     rv = NS_OK;
00563   }
00564   
00565   return rv;
00566 }
00567 
00568 nsresult
00569 nsMsgIncomingServer::SetIntValue(const char *prefname,
00570                                  PRInt32 val)
00571 {
00572   nsresult rv;
00573   nsCAutoString fullPrefName;
00574   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00575   
00576   PRInt32 defaultVal;
00577   rv = getDefaultIntPref(prefname, &defaultVal);
00578   
00579   if (NS_SUCCEEDED(rv) && defaultVal == val)
00580     m_prefBranch->ClearUserPref(fullPrefName.get());
00581   else
00582     rv = m_prefBranch->SetIntPref(fullPrefName.get(), val);
00583   
00584   return rv;
00585 }
00586 
00587 nsresult
00588 nsMsgIncomingServer::GetCharValue(const char *prefname,
00589                                  char  **val)
00590 {
00591   nsCAutoString fullPrefName;
00592   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00593   nsresult rv = m_prefBranch->GetCharPref(fullPrefName.get(), val);
00594   
00595   if (NS_FAILED(rv))
00596     rv = getDefaultCharPref(prefname, val);
00597   
00598   return rv;
00599 }
00600 
00601 nsresult
00602 nsMsgIncomingServer::GetUnicharValue(const char *prefname,
00603                                      PRUnichar **val)
00604 {
00605   nsCAutoString fullPrefName;
00606   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00607   nsCOMPtr<nsISupportsString> supportsString;
00608   nsresult rv = m_prefBranch->GetComplexValue(fullPrefName.get(),
00609                                               NS_GET_IID(nsISupportsString),
00610                                               getter_AddRefs(supportsString));
00611   
00612   if (NS_FAILED(rv))
00613     return getDefaultUnicharPref(prefname, val);
00614 
00615   if (supportsString)
00616     rv = supportsString->ToString(val);
00617 
00618   return rv;
00619 }
00620 
00621 nsresult
00622 nsMsgIncomingServer::getDefaultCharPref(const char *prefname,
00623                                         char **val)
00624 {
00625   nsCAutoString fullPrefName;
00626   getDefaultPrefName(prefname, fullPrefName);
00627   nsresult rv = m_prefBranch->GetCharPref(fullPrefName.get(), val);
00628 
00629   if (NS_FAILED(rv)) {
00630     *val = nsnull;              // null is ok to return here
00631     rv = NS_OK;
00632   }
00633   return rv;
00634 }
00635 
00636 nsresult
00637 nsMsgIncomingServer::getDefaultUnicharPref(const char *prefname,
00638                                            PRUnichar **val) {
00639   
00640   nsCAutoString fullPrefName;
00641   getDefaultPrefName(prefname, fullPrefName);
00642   nsCOMPtr<nsISupportsString> supportsString;
00643   nsresult rv = m_prefBranch->GetComplexValue(fullPrefName.get(),
00644                                               NS_GET_IID(nsISupportsString),
00645                                               getter_AddRefs(supportsString));
00646   if (NS_FAILED(rv) || !supportsString) {
00647     *val = nsnull;              // null is ok to return here
00648     return NS_OK;
00649   }
00650 
00651   return supportsString->ToString(val);
00652 }
00653 
00654 nsresult
00655 nsMsgIncomingServer::SetCharValue(const char *prefname,
00656                                  const char * val)
00657 {
00658   nsresult rv;
00659   nsCAutoString fullPrefName;
00660   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00661 
00662   if (!val) {
00663     m_prefBranch->ClearUserPref(fullPrefName.get());
00664     return NS_OK;
00665   }
00666   
00667   nsXPIDLCString defaultVal;
00668   rv = getDefaultCharPref(prefname, getter_Copies(defaultVal));
00669   
00670   if (NS_SUCCEEDED(rv) && defaultVal.Equals(val))
00671     m_prefBranch->ClearUserPref(fullPrefName.get());
00672   else
00673     rv = m_prefBranch->SetCharPref(fullPrefName.get(), val);
00674   
00675   return rv;
00676 }
00677 
00678 nsresult
00679 nsMsgIncomingServer::SetUnicharValue(const char *prefname,
00680                                   const PRUnichar * val)
00681 {
00682   nsresult rv;
00683   nsCAutoString fullPrefName;
00684   getPrefName(m_serverKey.get(), prefname, fullPrefName);
00685 
00686   if (!val) {
00687     m_prefBranch->ClearUserPref(fullPrefName.get());
00688     return NS_OK;
00689   }
00690 
00691   PRUnichar *defaultVal=nsnull;
00692   rv = getDefaultUnicharPref(prefname, &defaultVal);
00693   if (defaultVal && NS_SUCCEEDED(rv) &&
00694       nsCRT::strcmp(defaultVal, val) == 0)
00695     m_prefBranch->ClearUserPref(fullPrefName.get());
00696   else {
00697     nsCOMPtr<nsISupportsString> supportsString =
00698       do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
00699     if (supportsString) {
00700       supportsString->SetData(nsDependentString(val));
00701       rv = m_prefBranch->SetComplexValue(fullPrefName.get(),
00702                                          NS_GET_IID(nsISupportsString),
00703                                          supportsString);
00704     }
00705   }
00706 
00707   PR_FREEIF(defaultVal);
00708   
00709   return rv;
00710 }
00711 
00712 // pretty name is the display name to show to the user
00713 NS_IMETHODIMP
00714 nsMsgIncomingServer::GetPrettyName(PRUnichar **retval) {
00715 
00716   nsXPIDLString val;
00717   nsresult rv = GetUnicharValue("name", getter_Copies(val));
00718   if (NS_FAILED(rv)) return rv;
00719 
00720   // if there's no name, then just return the hostname
00721   if (val.IsEmpty()) 
00722     return GetConstructedPrettyName(retval);
00723 
00724   *retval = nsCRT::strdup(val);
00725   return NS_OK;
00726 }
00727 
00728 NS_IMETHODIMP
00729 nsMsgIncomingServer::SetPrettyName(const PRUnichar *value)
00730 {
00731     SetUnicharValue("name", value);
00732     
00733     nsCOMPtr<nsIMsgFolder> rootFolder;
00734     GetRootFolder(getter_AddRefs(rootFolder));
00735 
00736     if (rootFolder)
00737         rootFolder->SetPrettyName(value);
00738 
00739     return NS_OK;
00740 }
00741 
00742 
00743 // construct the pretty name to show to the user if they haven't
00744 // specified one. This should be overridden for news and mail.
00745 NS_IMETHODIMP
00746 nsMsgIncomingServer::GetConstructedPrettyName(PRUnichar **retval) 
00747 {
00748     
00749   nsXPIDLCString username;
00750   nsAutoString prettyName;
00751   nsresult rv = GetUsername(getter_Copies(username));
00752   if (NS_FAILED(rv)) return rv;
00753   if ((const char*)username &&
00754       PL_strcmp((const char*)username, "")!=0) {
00755     prettyName.AssignWithConversion(username);
00756     prettyName.AppendLiteral(" on ");
00757   }
00758   
00759   nsXPIDLCString hostname;
00760   rv = GetHostName(getter_Copies(hostname));
00761   if (NS_FAILED(rv)) return rv;
00762 
00763 
00764   prettyName.AppendWithConversion(hostname);
00765 
00766   *retval = ToNewUnicode(prettyName);
00767   
00768   return NS_OK;
00769 }
00770 
00771 NS_IMETHODIMP
00772 nsMsgIncomingServer::ToString(PRUnichar** aResult) {
00773   *aResult = ToNewUnicode(NS_LITERAL_STRING("[nsIMsgIncomingServer: ") +
00774                           NS_ConvertASCIItoUCS2(m_serverKey) +
00775                           NS_LITERAL_STRING("]"));
00776   NS_ASSERTION(*aResult, "no server name!");
00777   return NS_OK;
00778 }
00779   
00780 
00781 NS_IMETHODIMP nsMsgIncomingServer::SetPassword(const char * aPassword)
00782 {
00783   m_password = aPassword;
00784   
00785   nsresult rv;
00786   PRBool rememberPassword = PR_FALSE;
00787   
00788   rv = GetRememberPassword(&rememberPassword);
00789   if (NS_FAILED(rv)) return rv;
00790   
00791   if (rememberPassword) 
00792   {
00793     rv = StorePassword();
00794     if (NS_FAILED(rv)) return rv;
00795   }
00796   
00797   return NS_OK;
00798 }
00799 
00800 NS_IMETHODIMP nsMsgIncomingServer::GetPassword(char ** aPassword)
00801 {
00802   NS_ENSURE_ARG_POINTER(aPassword);
00803   *aPassword = ToNewCString(m_password);
00804   return NS_OK;
00805 }
00806 
00807 NS_IMETHODIMP nsMsgIncomingServer::GetServerRequiresPasswordForBiff(PRBool *aServerRequiresPasswordForBiff)
00808 {
00809   NS_ENSURE_ARG_POINTER(aServerRequiresPasswordForBiff);
00810   *aServerRequiresPasswordForBiff = PR_TRUE;
00811   return NS_OK;
00812 }
00813 
00814 NS_IMETHODIMP
00815 nsMsgIncomingServer::GetPasswordWithUI(const PRUnichar * aPromptMessage, const
00816                                        PRUnichar *aPromptTitle, 
00817                                        nsIMsgWindow* aMsgWindow,
00818                                        PRBool *okayValue,
00819                                        char **aPassword) 
00820 {
00821   nsresult rv = NS_OK;
00822   
00823   NS_ENSURE_ARG_POINTER(aPassword);
00824   NS_ENSURE_ARG_POINTER(okayValue);
00825   
00826   if (m_password.IsEmpty()) 
00827   {
00828     // let's see if we have the password in the password manager and  
00829     // can avoid this prompting thing. This makes it easier to get embedders
00830     // to get up and running w/o a password prompting UI. We already depend on
00831     // nsIPasswordManagerInternal so this doesn't introduce a new dependency.
00832     nsCOMPtr <nsIPasswordManagerInternal> passwordMgrInt = do_GetService(NS_PASSWORDMANAGER_CONTRACTID, &rv);
00833     if(passwordMgrInt) 
00834     {
00835 
00836       // Get the current server URI
00837       nsXPIDLCString currServerUri;
00838       rv = GetServerURI(getter_Copies(currServerUri));
00839       NS_ENSURE_SUCCESS(rv, rv);
00840 
00841       nsCAutoString hostFound;
00842       nsAutoString userNameFound;
00843       nsAutoString passwordFound;
00844 
00845       const nsAFlatString& empty = EmptyString();
00846 
00847       // Get password entry corresponding to the host URI we are passing in.
00848       if (NS_SUCCEEDED(passwordMgrInt->FindPasswordEntry(currServerUri, empty, empty,
00849                                              hostFound, userNameFound, passwordFound)))
00850       {
00851         m_password.AssignWithConversion(passwordFound);
00852         *okayValue = PR_TRUE;
00853       }
00854     }
00855   }
00856   if (m_password.IsEmpty())
00857   {
00858     nsCOMPtr<nsIAuthPrompt> dialog;
00859 
00860     // aMsgWindow is required if we need to prompt
00861     if (aMsgWindow)
00862     {
00863       // prompt the user for the password
00864       nsCOMPtr<nsIDocShell> docShell;
00865       rv = aMsgWindow->GetRootDocShell(getter_AddRefs(docShell));
00866       if (NS_FAILED(rv)) return rv;
00867       
00868       dialog = do_GetInterface(docShell, &rv);
00869       if (NS_FAILED(rv)) return rv;
00870     }
00871     else
00872     {
00873       nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00874       if (wwatch)
00875         wwatch->GetNewAuthPrompter(0, getter_AddRefs(dialog));
00876       if (!dialog) return NS_ERROR_FAILURE;
00877     }
00878     if (dialog)
00879     {
00880       nsXPIDLCString serverUri;
00881       rv = GetServerURI(getter_Copies(serverUri));
00882       if (NS_FAILED(rv)) return rv;
00883       PRBool passwordProtectLocalCache = PR_FALSE;
00884 
00885       (void) m_prefBranch->GetBoolPref( "mail.password_protect_local_cache", &passwordProtectLocalCache);
00886       PRUnichar *uniPassword = nsnull;
00887       if (*aPassword)
00888         uniPassword = ToNewUnicode(NS_ConvertASCIItoUTF16(*aPassword));
00889 
00890       PRUint32 savePasswordType = (passwordProtectLocalCache) ? nsIAuthPrompt::SAVE_PASSWORD_FOR_SESSION : nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY;
00891       rv = dialog->PromptPassword(aPromptTitle, aPromptMessage, 
00892                                   NS_ConvertASCIItoUTF16(serverUri).get(), savePasswordType,
00893                                   &uniPassword, okayValue);
00894       nsAutoString uniPasswordAdopted;
00895       uniPasswordAdopted.Adopt(uniPassword);
00896       if (NS_FAILED(rv)) return rv;
00897       
00898       if (!*okayValue) // if the user pressed cancel, just return NULL;
00899       {
00900         *aPassword = nsnull;
00901         return NS_MSG_PASSWORD_PROMPT_CANCELLED;
00902       }
00903       
00904       // we got a password back...so remember it
00905       nsCString aCStr; 
00906       aCStr.AssignWithConversion(uniPasswordAdopted); 
00907       rv = SetPassword(aCStr.get());
00908       if (NS_FAILED(rv)) return rv;
00909     } // if we got a prompt dialog
00910   } // if the password is empty
00911   
00912   return GetPassword(aPassword);
00913 }
00914 
00915 NS_IMETHODIMP
00916 nsMsgIncomingServer::StorePassword()
00917 {
00918     nsresult rv;
00919 
00920     // we only need to store this if we're password protecting the local cache.
00921     // Otherwise, the password manager handles storing the password if the user 
00922     // checks the "remember password" box.
00923     if (!PasswordProtectLocalCache())
00924       return NS_OK;
00925 
00926     nsXPIDLCString pwd;
00927     rv = GetPassword(getter_Copies(pwd));
00928     if (NS_FAILED(rv)) return rv;
00929 
00930     nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
00931     NS_ENSURE_SUCCESS(rv,rv);
00932 
00933     nsXPIDLCString serverSpec;
00934     rv = GetServerURI(getter_Copies(serverSpec));
00935     if (NS_FAILED(rv)) return rv;
00936 
00937     // We're password protecting the local cache, we're going to munge the uri in the password mgr to 
00938     // start with 'x', so that we can remember the password in order to challenge the user, w/o having the
00939     // password mgr automatically use the password.
00940     serverSpec.Insert('x', 0);
00941     nsCOMPtr<nsIURI> uri;
00942     NS_NewURI(getter_AddRefs(uri), serverSpec);
00943 
00944     //this is need to make sure wallet service has been created
00945     rv = CreateServicesForPasswordManager();
00946     NS_ENSURE_SUCCESS(rv, rv);
00947 
00948     rv = observerService->NotifyObservers(uri, "login-succeeded", NS_ConvertUTF8toUCS2(pwd).get());
00949     NS_ENSURE_SUCCESS(rv,rv);
00950     nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
00951     if (accountManager)
00952       accountManager->SetUserNeedsToAuthenticate(PR_FALSE);
00953     return rv;
00954 }
00955 
00956 NS_IMETHODIMP
00957 nsMsgIncomingServer::ForgetPassword()
00958 {
00959     nsXPIDLCString serverSpec;
00960     nsresult rv = GetServerURI(getter_Copies(serverSpec));
00961     if (NS_FAILED(rv)) return rv;
00962 
00963     //this is need to make sure wallet service has been created
00964     rv = CreateServicesForPasswordManager();
00965     NS_ENSURE_SUCCESS(rv, rv);
00966     nsCOMPtr <nsIPasswordManager> passwordMgr = do_GetService(NS_PASSWORDMANAGER_CONTRACTID, &rv);
00967     if (NS_SUCCEEDED(rv) && passwordMgr)
00968     {
00969       // Get the current server URI
00970       nsXPIDLCString currServerUri;
00971       rv = GetServerURI(getter_Copies(currServerUri));
00972       NS_ENSURE_SUCCESS(rv, rv);
00973 
00974       passwordMgr->RemoveUser(currServerUri, EmptyString());
00975     }
00976     return SetPassword("");
00977 }
00978 
00979 NS_IMETHODIMP
00980 nsMsgIncomingServer::ForgetSessionPassword()
00981 {
00982     m_password.Truncate(0);
00983     return NS_OK;
00984 }
00985 
00986 NS_IMETHODIMP
00987 nsMsgIncomingServer::SetDefaultLocalPath(nsIFileSpec *aDefaultLocalPath)
00988 {
00989     nsresult rv;
00990     nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
00991     rv = getProtocolInfo(getter_AddRefs(protocolInfo));
00992     if (NS_FAILED(rv)) return rv;
00993 
00994     rv = protocolInfo->SetDefaultLocalPath(aDefaultLocalPath);
00995     return rv;
00996 }
00997 
00998 NS_IMETHODIMP
00999 nsMsgIncomingServer::GetLocalPath(nsIFileSpec **aLocalPath)
01000 {
01001     nsresult rv;
01002 
01003     // if the local path has already been set, use it
01004     rv = GetFileValue("directory", aLocalPath);
01005     if (NS_SUCCEEDED(rv) && *aLocalPath) return rv;
01006     
01007     // otherwise, create the path using the protocol info.
01008     // note we are using the
01009     // hostname, unless that directory exists.
01010        // this should prevent all collisions.
01011     nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
01012     rv = getProtocolInfo(getter_AddRefs(protocolInfo));
01013     if (NS_FAILED(rv)) return rv;
01014     
01015     nsCOMPtr<nsIFileSpec> path;
01016     rv = protocolInfo->GetDefaultLocalPath(getter_AddRefs(path));
01017     if (NS_FAILED(rv)) return rv;
01018     
01019     path->CreateDir();
01020     
01021        // set the leaf name to "dummy", and then call MakeUnique with a suggested leaf name
01022     rv = path->AppendRelativeUnixPath("dummy");
01023     if (NS_FAILED(rv)) return rv;
01024     nsXPIDLCString hostname;
01025     rv = GetHostName(getter_Copies(hostname));
01026     if (NS_FAILED(rv)) return rv;
01027     rv = path->MakeUniqueDirWithSuggestedName((const char *)hostname);
01028     if (NS_FAILED(rv)) return rv;
01029 
01030     rv = SetLocalPath(path);
01031     if (NS_FAILED(rv)) return rv;
01032 
01033     *aLocalPath = path;
01034     NS_ADDREF(*aLocalPath);
01035 
01036     return NS_OK;
01037 }
01038 
01039 NS_IMETHODIMP
01040 nsMsgIncomingServer::SetLocalPath(nsIFileSpec *spec)
01041 {
01042   if (spec)
01043   {
01044     spec->CreateDir();
01045     return SetFileValue("directory", spec);
01046   }
01047   else 
01048   {
01049     return NS_ERROR_NULL_POINTER;
01050   }
01051 }
01052 
01053 NS_IMETHODIMP
01054 nsMsgIncomingServer::SetRememberPassword(PRBool value)
01055 {
01056     if (!value)
01057         ForgetPassword();
01058     else 
01059         StorePassword();
01060     return SetBoolValue("remember_password", value);
01061 }
01062 
01063 PRBool nsMsgIncomingServer::PasswordProtectLocalCache()
01064 {
01065     PRBool passwordProtectLocalCache;
01066 
01067     nsresult rv = m_prefBranch->GetBoolPref( "mail.password_protect_local_cache", &passwordProtectLocalCache);
01068     NS_ENSURE_SUCCESS(rv, PR_FALSE);
01069     return passwordProtectLocalCache;
01070 }
01071 
01072 NS_IMETHODIMP
01073 nsMsgIncomingServer::GetRememberPassword(PRBool* aValue)
01074 {
01075     NS_ENSURE_ARG_POINTER(aValue);
01076     return GetBoolValue("remember_password", aValue);
01077 }
01078 
01079 NS_IMETHODIMP
01080 nsMsgIncomingServer::GetLocalStoreType(char **aResult)
01081 {
01082     NS_NOTYETIMPLEMENTED("nsMsgIncomingServer superclass not implementing GetLocalStoreType!");
01083     return NS_ERROR_UNEXPECTED;
01084 }
01085 
01086 NS_IMETHODIMP
01087 nsMsgIncomingServer::GetAccountManagerChrome(nsAString& aResult)
01088 {
01089     aResult.AssignLiteral("am-main.xul");
01090     return NS_OK;
01091 }
01092 
01093 NS_IMETHODIMP
01094 nsMsgIncomingServer::Equals(nsIMsgIncomingServer *server, PRBool *_retval)
01095 {
01096     nsresult rv;
01097 
01098     NS_ENSURE_ARG_POINTER(server);
01099     NS_ENSURE_ARG_POINTER(_retval);
01100 
01101     nsXPIDLCString key1;
01102     nsXPIDLCString key2;
01103 
01104     rv = GetKey(getter_Copies(key1));
01105     if (NS_FAILED(rv)) return rv;
01106 
01107     rv = server->GetKey(getter_Copies(key2));
01108     if (NS_FAILED(rv)) return rv;
01109 
01110     // compare the server keys
01111     if (PL_strcmp((const char *)key1,(const char *)key2)) {
01112 #ifdef DEBUG_MSGINCOMING_SERVER
01113         printf("%s and %s are different, servers are not the same\n",(const char *)key1,(const char *)key2);
01114 #endif /* DEBUG_MSGINCOMING_SERVER */
01115         *_retval = PR_FALSE;
01116     }
01117     else {
01118 #ifdef DEBUG_MSGINCOMING_SERVER
01119         printf("%s and %s are equal, servers are the same\n",(const char *)key1,(const char *)key2);
01120 #endif /* DEBUG_MSGINCOMING_SERVER */
01121         *_retval = PR_TRUE;
01122     }
01123     return rv;
01124 }
01125 
01126 NS_IMETHODIMP
01127 nsMsgIncomingServer::ClearAllValues()
01128 {
01129     nsCAutoString rootPref("mail.server.");
01130     rootPref += m_serverKey;
01131     rootPref += '.';
01132 
01133     PRUint32 childCount;
01134     char**   childArray;
01135     nsresult rv = m_prefBranch->GetChildList(rootPref.get(), &childCount, &childArray);
01136     NS_ENSURE_SUCCESS(rv, rv);
01137 
01138     for (PRUint32 i = 0; i < childCount; ++i) 
01139         m_prefBranch->ClearUserPref(childArray[i]);
01140 
01141     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray);
01142 
01143     return NS_OK;
01144 }
01145 
01146 NS_IMETHODIMP
01147 nsMsgIncomingServer::RemoveFiles()
01148 {
01149         // IMPORTANT, see bug #77652
01150         // don't turn this code on yet.  we don't inform the user that
01151        // we are going to be deleting the directory, and they might have
01152        // tweaked their localPath pref for this server to point to 
01153        // somewhere they didn't want deleted.
01154         // until we tell them, we shouldn't do the delete.
01155 #if 0
01156        nsresult rv = NS_OK;
01157        nsCOMPtr <nsIFileSpec> localPath;
01158        rv = GetLocalPath(getter_AddRefs(localPath));
01159        if (NS_FAILED(rv)) return rv;
01160        
01161        if (!localPath) return NS_ERROR_FAILURE;
01162        
01163        PRBool exists = PR_FALSE;
01164        rv = localPath->Exists(&exists);
01165        if (NS_FAILED(rv)) return rv;
01166 
01167        // if it doesn't exist, that's ok.
01168        if (!exists) return NS_OK;
01169 
01170        rv = localPath->Delete(PR_TRUE /* recursive */);
01171        if (NS_FAILED(rv)) return rv;
01172 
01173        // now check if it really gone
01174        rv = localPath->Exists(&exists);
01175        if (NS_FAILED(rv)) return rv;
01176 
01177        // if it still exists, something failed.
01178        if (exists) return NS_ERROR_FAILURE;
01179 #endif /* 0 */
01180        return NS_OK;
01181 }
01182 
01183 NS_IMETHODIMP
01184 nsMsgIncomingServer::SetFilterList(nsIMsgFilterList *aFilterList)
01185 {
01186   mFilterList = aFilterList;
01187   return NS_OK;
01188 }
01189 
01190 NS_IMETHODIMP
01191 nsMsgIncomingServer::GetFilterList(nsIMsgWindow *aMsgWindow, nsIMsgFilterList **aResult)
01192 {
01193   if (!mFilterList) 
01194   {
01195       nsCOMPtr<nsIMsgFolder> msgFolder;
01196       // use GetRootFolder so for deferred pop3 accounts, we'll get the filters
01197       // file from the deferred account, not the deferred to account,
01198       // so that filters will still be per-server.
01199       nsresult rv = GetRootFolder(getter_AddRefs(msgFolder));
01200       NS_ENSURE_SUCCESS(rv, rv);
01201       
01202       nsCOMPtr<nsIFileSpec> thisFolder;
01203       rv = msgFolder->GetPath(getter_AddRefs(thisFolder));
01204       NS_ENSURE_SUCCESS(rv, rv);
01205 
01206       mFilterFile = do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv);
01207       NS_ENSURE_SUCCESS(rv, rv);
01208 
01209       rv = mFilterFile->FromFileSpec(thisFolder);
01210       NS_ENSURE_SUCCESS(rv, rv);
01211 
01212       mFilterFile->AppendRelativeUnixPath("msgFilterRules.dat");
01213       
01214       PRBool fileExists;
01215       mFilterFile->Exists(&fileExists);
01216       if (!fileExists)
01217       {
01218         nsCOMPtr<nsIFileSpec> oldFilterFile = do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv);
01219         NS_ENSURE_SUCCESS(rv, rv);
01220 
01221         rv = oldFilterFile->FromFileSpec(thisFolder);
01222         NS_ENSURE_SUCCESS(rv, rv);
01223         oldFilterFile->AppendRelativeUnixPath("rules.dat");
01224         
01225         oldFilterFile->Exists(&fileExists);
01226         if (fileExists)  //copy rules.dat --> msgFilterRules.dat
01227         {
01228           nsFileSpec rootFolderSpec;
01229           thisFolder->GetFileSpec(&rootFolderSpec);
01230 
01231           nsCOMPtr<nsILocalFile> rootFolderDir;
01232           rv = NS_FileSpecToIFile(&rootFolderSpec, getter_AddRefs(rootFolderDir));
01233           NS_ENSURE_SUCCESS(rv, rv);
01234 
01235           nsFileSpec oldFilterSpec;
01236           oldFilterFile->GetFileSpec(&oldFilterSpec);
01237 
01238           nsCOMPtr<nsILocalFile> localFilterFile;
01239           rv = NS_FileSpecToIFile(&oldFilterSpec, getter_AddRefs(localFilterFile));
01240           NS_ENSURE_SUCCESS(rv, rv);
01241 
01242           rv = localFilterFile->CopyToNative(rootFolderDir, NS_LITERAL_CSTRING("msgFilterRules.dat"));
01243           NS_ENSURE_SUCCESS(rv, rv);
01244         }
01245       }
01246       nsCOMPtr<nsIMsgFilterService> filterService =
01247           do_GetService(NS_MSGFILTERSERVICE_CONTRACTID, &rv);
01248       NS_ENSURE_SUCCESS(rv, rv);
01249       
01250       rv = filterService->OpenFilterList(mFilterFile, msgFolder, aMsgWindow, getter_AddRefs(mFilterList));
01251       NS_ENSURE_SUCCESS(rv, rv);
01252   }
01253 
01254   NS_IF_ADDREF(*aResult = mFilterList);
01255   return NS_OK;
01256     
01257 }
01258          
01259 // If the hostname contains ':' (like hostname:1431)
01260 // then parse and set the port number.
01261 nsresult
01262 nsMsgIncomingServer::InternalSetHostName(const char *aHostname, const char *prefName)
01263 {
01264   nsresult rv;
01265   if (PL_strchr(aHostname, ':'))
01266   {
01267     nsCAutoString newHostname(aHostname);
01268     PRInt32 colonPos = newHostname.FindChar(':');
01269     
01270     nsCAutoString portString;
01271     newHostname.Right(portString, newHostname.Length() - colonPos);
01272     
01273     newHostname.Truncate(colonPos);
01274     
01275     PRInt32 err;
01276     PRInt32 port = portString.ToInteger(&err);
01277     if (!err) SetPort(port);
01278     
01279     rv = SetCharValue(prefName, newHostname.get());
01280   }
01281   else
01282     rv = SetCharValue(prefName, aHostname);
01283   return rv;
01284 }
01285 
01286 NS_IMETHODIMP
01287 nsMsgIncomingServer::OnUserOrHostNameChanged(const char *oldName, const char *newName)
01288 {
01289   nsresult rv;
01290 
01291   // 1. Reset password so that users are prompted for new password for the new user/host.
01292   ForgetPassword();
01293 
01294   // 2. Let the derived class close all cached connection to the old host.
01295   CloseCachedConnections();
01296 
01297   // 3. Notify any listeners for account server changes.
01298   nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
01299   NS_ENSURE_SUCCESS(rv, rv);
01300 
01301   rv = accountManager->NotifyServerChanged(this);
01302   NS_ENSURE_SUCCESS(rv, rv);
01303 
01304   // 4. Lastly, replace all occurrences of old name in the acct name with the new one.
01305   nsXPIDLString acctName;
01306   rv = GetPrettyName(getter_Copies(acctName));
01307   if (NS_SUCCEEDED(rv) && acctName)
01308   {
01309     nsAutoString newAcctName, oldVal, newVal;
01310     oldVal.AssignWithConversion(oldName);
01311     newVal.AssignWithConversion(newName);
01312     newAcctName.Assign(acctName);
01313     newAcctName.ReplaceSubstring(oldVal, newVal);
01314     SetPrettyName(newAcctName.get());
01315   }
01316 
01317   return rv;
01318 }
01319 
01320 nsresult
01321 nsMsgIncomingServer::SetHostName(const char *aHostname)
01322 {
01323   return (InternalSetHostName(aHostname, "hostname"));
01324 }
01325 
01326 // SetRealHostName() is called only when the server name is changed from the
01327 // UI (Account Settings page).  No one should call it in any circumstances.
01328 NS_IMETHODIMP
01329 nsMsgIncomingServer::SetRealHostName(const char *aHostname)
01330 {
01331   nsXPIDLCString oldName;
01332   nsresult rv = GetRealHostName(getter_Copies(oldName));
01333   NS_ENSURE_SUCCESS(rv, rv);
01334   rv = InternalSetHostName(aHostname, "realhostname");
01335 
01336   // A few things to take care of if we're changing the hostname.
01337   if (nsCRT::strcasecmp(aHostname, oldName.get()))
01338     rv = OnUserOrHostNameChanged(oldName.get(), aHostname);
01339 
01340   return rv;
01341 }
01342 
01343 nsresult
01344 nsMsgIncomingServer::GetHostName(char **aResult)
01345 {
01346     nsresult rv;
01347     rv = GetCharValue("hostname", aResult);
01348     if (PL_strchr(*aResult, ':')) 
01349     {
01350        // gack, we need to reformat the hostname - SetHostName will do that
01351         SetHostName(*aResult);
01352         rv = GetCharValue("hostname", aResult);
01353     }
01354     return rv;
01355 }
01356 
01357 NS_IMETHODIMP
01358 nsMsgIncomingServer::GetRealHostName(char **aResult)
01359 {
01360   // If 'realhostname' is set (was changed) then use it, otherwise use 'hostname'
01361   nsresult rv;
01362   rv = GetCharValue("realhostname", aResult);
01363   NS_ENSURE_SUCCESS(rv, rv);
01364   if (!*aResult || !**aResult)
01365     return(GetHostName(aResult));
01366 
01367   if (PL_strchr(*aResult, ':'))
01368   {
01369     SetRealHostName(*aResult);
01370     rv = GetCharValue("realhostname", aResult);
01371   }
01372   return rv;
01373 }
01374 
01375 NS_IMETHODIMP
01376 nsMsgIncomingServer::GetRealUsername(char **aResult)
01377 {
01378   // If 'realuserName' is set (was changed) then use it, otherwise use 'userName'
01379   nsresult rv;
01380   rv = GetCharValue("realuserName", aResult);
01381   NS_ENSURE_SUCCESS(rv, rv);
01382   if (!*aResult || !**aResult)
01383     return(GetUsername(aResult));
01384 
01385   return rv;
01386 }
01387 
01388 NS_IMETHODIMP
01389 nsMsgIncomingServer::SetRealUsername(const char *aUsername)
01390 {
01391   // Need to take care of few things if we're changing the username.
01392   nsXPIDLCString oldName;
01393   nsresult rv = GetRealUsername(getter_Copies(oldName));
01394   NS_ENSURE_SUCCESS(rv, rv);
01395   rv = SetCharValue("realuserName", aUsername);
01396   if (!oldName.Equals(aUsername))
01397     rv = OnUserOrHostNameChanged(oldName.get(), aUsername);
01398 
01399   return rv;
01400 }
01401 
01402 #define BIFF_PREF_NAME "check_new_mail"
01403 
01404 NS_IMETHODIMP
01405 nsMsgIncomingServer::GetDoBiff(PRBool *aDoBiff)
01406 {
01407     NS_ENSURE_ARG_POINTER(aDoBiff);
01408     nsresult rv;
01409    
01410     nsCAutoString fullPrefName;
01411     getPrefName(m_serverKey.get(), BIFF_PREF_NAME, fullPrefName);
01412     rv = m_prefBranch->GetBoolPref(fullPrefName.get(), aDoBiff);
01413     if (NS_SUCCEEDED(rv)) return rv;
01414 
01415     // if the pref isn't set, use the default
01416     // value based on the protocol
01417     nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
01418 
01419     rv = getProtocolInfo(getter_AddRefs(protocolInfo));
01420     NS_ENSURE_SUCCESS(rv, rv);
01421 
01422     rv = protocolInfo->GetDefaultDoBiff(aDoBiff);
01423     // note, don't call SetDoBiff()
01424     // since we keep changing our minds on
01425     // if biff should be on or off, let's keep the ability
01426     // to change the default in future builds.
01427     // if we call SetDoBiff() here, it will be in the users prefs.
01428     // and we can't do anything after that.
01429     return rv;
01430 }
01431 
01432 NS_IMETHODIMP
01433 nsMsgIncomingServer::SetDoBiff(PRBool aDoBiff)
01434 {
01435     nsresult rv;
01436     nsCAutoString fullPrefName;
01437     getPrefName(m_serverKey.get(), BIFF_PREF_NAME, fullPrefName);
01438 
01439     rv = m_prefBranch->SetBoolPref(fullPrefName.get(), aDoBiff);
01440     NS_ENSURE_SUCCESS(rv,rv);
01441     return NS_OK;
01442 }
01443 
01444 
01445 NS_IMETHODIMP
01446 nsMsgIncomingServer::GetPort(PRInt32 *aPort)
01447 {
01448     NS_ENSURE_ARG_POINTER(aPort);
01449     nsresult rv;
01450     
01451     rv = GetIntValue("port", aPort);
01452     if (*aPort != PORT_NOT_SET) return rv;
01453     
01454     // if the port isn't set, use the default
01455     // port based on the protocol
01456     nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
01457 
01458     rv = getProtocolInfo(getter_AddRefs(protocolInfo));
01459     NS_ENSURE_SUCCESS(rv, rv);
01460 
01461     PRBool isSecure = PR_FALSE;
01462     // Try this, and if it fails, fall back to the non-secure port
01463     GetIsSecure(&isSecure);
01464     return protocolInfo->GetDefaultServerPort(isSecure, aPort);
01465 }
01466 
01467 NS_IMETHODIMP
01468 nsMsgIncomingServer::SetPort(PRInt32 aPort)
01469 {
01470     nsresult rv;
01471  
01472     nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
01473     rv = getProtocolInfo(getter_AddRefs(protocolInfo));
01474     NS_ENSURE_SUCCESS(rv, rv);
01475 
01476     PRInt32 defaultPort;
01477     PRBool isSecure = PR_FALSE;
01478     // Try this, and if it fails, fall back to the non-secure port
01479     GetIsSecure(&isSecure);
01480     rv = protocolInfo->GetDefaultServerPort(isSecure, &defaultPort);
01481     if (NS_SUCCEEDED(rv) && aPort == defaultPort)
01482         // clear it out by setting it to the default
01483         rv = SetIntValue("port", PORT_NOT_SET);
01484     else
01485         rv = SetIntValue("port", aPort);
01486 
01487     return NS_OK;
01488 }
01489 
01490 nsresult
01491 nsMsgIncomingServer::getProtocolInfo(nsIMsgProtocolInfo **aResult)
01492 {
01493     NS_ENSURE_ARG_POINTER(aResult);
01494     nsresult rv;
01495 
01496     nsXPIDLCString type;
01497     rv = GetType(getter_Copies(type));
01498     NS_ENSURE_SUCCESS(rv, rv);
01499 
01500     nsCAutoString contractid(NS_MSGPROTOCOLINFO_CONTRACTID_PREFIX);
01501     contractid.Append(type);
01502 
01503     nsCOMPtr<nsIMsgProtocolInfo> protocolInfo =
01504         do_GetService(contractid.get(), &rv);
01505     NS_ENSURE_SUCCESS(rv, rv);
01506 
01507     *aResult = protocolInfo;
01508     NS_ADDREF(*aResult);
01509     return NS_OK;
01510 }
01511 
01512 NS_IMETHODIMP nsMsgIncomingServer::GetRetentionSettings(nsIMsgRetentionSettings **settings)
01513 {
01514   NS_ENSURE_ARG_POINTER(settings);
01515   nsMsgRetainByPreference retainByPreference;
01516   PRInt32 daysToKeepHdrs = 0;
01517   PRInt32 numHeadersToKeep = 0;
01518   PRBool keepUnreadMessagesOnly = PR_FALSE;
01519   PRInt32 daysToKeepBodies = 0;
01520   PRBool cleanupBodiesByDays = PR_FALSE;
01521   nsresult rv = NS_OK;
01522   if (!m_retentionSettings)
01523   {
01524     m_retentionSettings = do_CreateInstance(NS_MSG_RETENTIONSETTINGS_CONTRACTID);
01525     if (m_retentionSettings)
01526     {
01527       rv = GetBoolValue("keepUnreadOnly", &keepUnreadMessagesOnly);
01528       rv = GetIntValue("retainBy", (PRInt32*) &retainByPreference);
01529       rv = GetIntValue("numHdrsToKeep", &numHeadersToKeep);
01530       rv = GetIntValue("daysToKeepHdrs", &daysToKeepHdrs);
01531       rv = GetIntValue("daysToKeepBodies", &daysToKeepBodies);
01532       rv = GetBoolValue("cleanupBodies", &cleanupBodiesByDays);
01533       m_retentionSettings->SetRetainByPreference(retainByPreference);
01534       m_retentionSettings->SetNumHeadersToKeep((PRUint32) numHeadersToKeep);
01535       m_retentionSettings->SetKeepUnreadMessagesOnly(keepUnreadMessagesOnly);
01536       m_retentionSettings->SetDaysToKeepBodies(daysToKeepBodies);
01537       m_retentionSettings->SetDaysToKeepHdrs(daysToKeepHdrs);
01538       m_retentionSettings->SetCleanupBodiesByDays(cleanupBodiesByDays);
01539     }
01540     else
01541       rv = NS_ERROR_OUT_OF_MEMORY;
01542     // Create an empty retention settings object, 
01543     // get the settings from the server prefs, and init the object from the prefs.
01544   }
01545   *settings = m_retentionSettings;
01546   NS_IF_ADDREF(*settings);  return rv;
01547 }
01548 
01549 NS_IMETHODIMP nsMsgIncomingServer::SetRetentionSettings(nsIMsgRetentionSettings *settings)
01550 {
01551   nsMsgRetainByPreference retainByPreference;
01552   PRUint32 daysToKeepHdrs = 0;
01553   PRUint32 numHeadersToKeep = 0;
01554   PRBool keepUnreadMessagesOnly = PR_FALSE;
01555   PRUint32 daysToKeepBodies = 0;
01556   PRBool cleanupBodiesByDays = PR_FALSE;
01557   m_retentionSettings = settings;
01558   m_retentionSettings->GetRetainByPreference(&retainByPreference);
01559   m_retentionSettings->GetNumHeadersToKeep(&numHeadersToKeep);
01560   m_retentionSettings->GetKeepUnreadMessagesOnly(&keepUnreadMessagesOnly);
01561   m_retentionSettings->GetDaysToKeepBodies(&daysToKeepBodies);
01562   m_retentionSettings->GetDaysToKeepHdrs(&daysToKeepHdrs);
01563   m_retentionSettings->GetCleanupBodiesByDays(&cleanupBodiesByDays);
01564   nsresult rv = SetBoolValue("keepUnreadOnly", keepUnreadMessagesOnly);
01565   rv = SetIntValue("retainBy", retainByPreference);
01566   rv = SetIntValue("numHdrsToKeep", numHeadersToKeep);
01567   rv = SetIntValue("daysToKeepHdrs", daysToKeepHdrs);
01568   rv = SetIntValue("daysToKeepBodies", daysToKeepBodies);
01569   rv = SetBoolValue("cleanupBodies", cleanupBodiesByDays);
01570   return rv;
01571 }
01572  
01573 NS_IMETHODIMP
01574 nsMsgIncomingServer::GetDisplayStartupPage(PRBool *displayStartupPage)
01575 {
01576     NS_ENSURE_ARG_POINTER(displayStartupPage);
01577     *displayStartupPage = m_displayStartupPage;
01578     return NS_OK;
01579 }
01580 
01581 NS_IMETHODIMP
01582 nsMsgIncomingServer::SetDisplayStartupPage(PRBool displayStartupPage)
01583 {
01584     m_displayStartupPage = displayStartupPage;
01585     return NS_OK;
01586 }
01587 
01588 
01589 NS_IMETHODIMP nsMsgIncomingServer::GetDownloadSettings(nsIMsgDownloadSettings **settings)
01590 {
01591   NS_ENSURE_ARG_POINTER(settings);
01592   PRBool downloadUnreadOnly = PR_FALSE;
01593   PRBool downloadByDate = PR_FALSE;
01594   PRUint32 ageLimitOfMsgsToDownload = 0;
01595   nsresult rv = NS_OK;
01596   if (!m_downloadSettings)
01597   {
01598     m_downloadSettings = do_CreateInstance(NS_MSG_DOWNLOADSETTINGS_CONTRACTID);
01599     if (m_downloadSettings)
01600     {
01601       rv = GetBoolValue("downloadUnreadOnly", &downloadUnreadOnly);
01602       rv = GetBoolValue("downloadByDate", &downloadByDate);
01603       rv = GetIntValue("ageLimit", (PRInt32 *) &ageLimitOfMsgsToDownload);
01604       m_downloadSettings->SetDownloadUnreadOnly(downloadUnreadOnly);
01605       m_downloadSettings->SetDownloadByDate(downloadByDate);
01606       m_downloadSettings->SetAgeLimitOfMsgsToDownload(ageLimitOfMsgsToDownload);
01607     }
01608     else
01609       rv = NS_ERROR_OUT_OF_MEMORY;
01610     // Create an empty download settings object, 
01611     // get the settings from the server prefs, and init the object from the prefs.
01612   }
01613   *settings = m_downloadSettings;
01614   NS_IF_ADDREF(*settings);  return rv;
01615 }
01616 
01617 NS_IMETHODIMP nsMsgIncomingServer::SetDownloadSettings(nsIMsgDownloadSettings *settings)
01618 {
01619   m_downloadSettings = settings;
01620   PRBool downloadUnreadOnly = PR_FALSE;
01621   PRBool downloadByDate = PR_FALSE;
01622   PRUint32 ageLimitOfMsgsToDownload = 0;
01623   m_downloadSettings->GetDownloadUnreadOnly(&downloadUnreadOnly);
01624   m_downloadSettings->GetDownloadByDate(&downloadByDate);
01625   m_downloadSettings->GetAgeLimitOfMsgsToDownload(&ageLimitOfMsgsToDownload);
01626   nsresult rv = SetBoolValue("downloadUnreadOnly", downloadUnreadOnly);
01627   rv = SetBoolValue("downloadByDate", downloadByDate);
01628   rv = SetIntValue("ageLimit", ageLimitOfMsgsToDownload);
01629 
01630   return rv;
01631 }
01632 
01633 NS_IMETHODIMP
01634 nsMsgIncomingServer::GetSupportsDiskSpace(PRBool *aSupportsDiskSpace)
01635 {
01636     NS_ENSURE_ARG_POINTER(aSupportsDiskSpace);
01637     *aSupportsDiskSpace = PR_TRUE;
01638     return NS_OK;
01639 }
01640 
01641 NS_IMETHODIMP
01642 nsMsgIncomingServer::GetOfflineSupportLevel(PRInt32 *aSupportLevel)
01643 {
01644     NS_ENSURE_ARG_POINTER(aSupportLevel);
01645     nsresult rv;
01646     
01647     rv = GetIntValue("offline_support_level", aSupportLevel);
01648     if (*aSupportLevel != OFFLINE_SUPPORT_LEVEL_UNDEFINED) return rv;
01649     
01650     // set default value
01651     *aSupportLevel = OFFLINE_SUPPORT_LEVEL_NONE;
01652     return NS_OK;
01653 }
01654 
01655 NS_IMETHODIMP
01656 nsMsgIncomingServer::SetOfflineSupportLevel(PRInt32 aSupportLevel)
01657 {
01658     SetIntValue("offline_support_level", aSupportLevel);
01659     return NS_OK;
01660 }
01661 #define BASE_MSGS_URL       "chrome://messenger/locale/messenger.properties"
01662 
01663 NS_IMETHODIMP nsMsgIncomingServer::DisplayOfflineMsg(nsIMsgWindow *aMsgWindow)
01664 {
01665   nsresult rv;
01666   nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
01667   NS_ENSURE_SUCCESS(rv, rv);
01668 
01669   nsCOMPtr<nsIStringBundle> bundle;
01670   rv = bundleService->CreateBundle(BASE_MSGS_URL, getter_AddRefs(bundle));
01671   NS_ENSURE_SUCCESS(rv, rv);
01672   if (bundle)
01673   {
01674     nsXPIDLString errorMsgTitle;
01675     nsXPIDLString errorMsgBody;
01676 
01677     bundle->GetStringFromName(NS_LITERAL_STRING("nocachedbodybody").get(), getter_Copies(errorMsgBody));
01678     bundle->GetStringFromName(NS_LITERAL_STRING("nocachedbodytitle").get(),  getter_Copies(errorMsgTitle));
01679     if (aMsgWindow)
01680       return aMsgWindow->DisplayHTMLInMessagePane(errorMsgTitle, errorMsgBody, PR_TRUE);
01681     else
01682       return NS_ERROR_FAILURE;
01683 
01684   }
01685   return rv;
01686 }
01687 
01688 // Called only during the migration process. A unique name is generated for the
01689 // migrated account.
01690 NS_IMETHODIMP
01691 nsMsgIncomingServer::GeneratePrettyNameForMigration(PRUnichar **aPrettyName)
01692 {
01699     return NS_ERROR_NOT_IMPLEMENTED;
01700 }
01701 
01702 NS_IMETHODIMP
01703 nsMsgIncomingServer::GetFilterScope(nsMsgSearchScopeValue *filterScope)
01704 {
01705    NS_ENSURE_ARG_POINTER(filterScope);
01706 
01707    *filterScope = nsMsgSearchScope::offlineMailFilter;
01708    return NS_OK;
01709 }
01710 
01711 NS_IMETHODIMP
01712 nsMsgIncomingServer::GetSearchScope(nsMsgSearchScopeValue *searchScope)
01713 {
01714    NS_ENSURE_ARG_POINTER(searchScope);
01715 
01716    *searchScope = nsMsgSearchScope::offlineMail;
01717    return NS_OK;
01718 }
01719 
01720 // use the convenience macros to implement the accessors
01721 NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, Username, "userName")
01722 NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, PrefPassword, "password")
01723 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, IsSecure, "isSecure")
01724 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, UseSecAuth, "useSecAuth")
01725 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, LogonFallback, "logon_fallback")
01726 NS_IMPL_SERVERPREF_INT(nsMsgIncomingServer, BiffMinutes, "check_time")
01727 NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, Type, "type")
01728 // in 4.x, this was "mail.pop3_gets_new_mail" for pop and 
01729 // "mail.imap.new_mail_get_headers" for imap (it was global)
01730 // in 5.0, this will be per server, and it will be "download_on_biff"
01731 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, DownloadOnBiff, "download_on_biff")
01732 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, Valid, "valid")
01733 NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, RedirectorType,  "redirector_type")
01734 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, EmptyTrashOnExit,
01735                         "empty_trash_on_exit")
01736 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, CanDelete, "canDelete")
01737 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, LoginAtStartUp, "login_at_startup")
01738 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, 
01739                         DefaultCopiesAndFoldersPrefsToServer, 
01740                         "allows_specialfolders_usage")
01741 
01742 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, 
01743                         CanCreateFoldersOnServer, 
01744                         "canCreateFolders")
01745 
01746 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, 
01747                         CanFileMessagesOnServer, 
01748                         "canFileMessages")
01749 
01750 NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer,
01751       LimitOfflineMessageSize,
01752       "limit_offline_message_size")
01753 
01754 NS_IMPL_SERVERPREF_INT(nsMsgIncomingServer, MaxMessageSize, "max_size")
01755 
01756 NS_IMPL_SERVERPREF_INT(nsMsgIncomingServer, IncomingDuplicateAction, "dup_action")
01757 
01758 NS_IMETHODIMP nsMsgIncomingServer::SetUnicharAttribute(const char *aName, const PRUnichar *val)
01759 {
01760   return SetUnicharValue(aName, val);
01761 }
01762 
01763 NS_IMETHODIMP nsMsgIncomingServer::GetUnicharAttribute(const char *aName, PRUnichar **val)
01764 {
01765   return GetUnicharValue(aName, val);
01766 }
01767 
01768 NS_IMETHODIMP nsMsgIncomingServer::SetCharAttribute(const char *aName, const char *val)
01769 {
01770   return SetCharValue(aName, val);
01771 }
01772 
01773 NS_IMETHODIMP nsMsgIncomingServer::GetCharAttribute(const char *aName, char **val)
01774 {
01775   return GetCharValue(aName, val);
01776 }
01777 
01778 NS_IMETHODIMP nsMsgIncomingServer::SetBoolAttribute(const char *aName, PRBool val)
01779 {
01780   return SetBoolValue(aName, val);
01781 }
01782 
01783 NS_IMETHODIMP nsMsgIncomingServer::GetBoolAttribute(const char *aName, PRBool *val)
01784 {
01785   return GetBoolValue(aName, val);
01786 }
01787 
01788 NS_IMETHODIMP nsMsgIncomingServer::SetIntAttribute(const char *aName, PRInt32 val)
01789 {
01790   return SetIntValue(aName, val);
01791 }
01792 
01793 NS_IMETHODIMP nsMsgIncomingServer::GetIntAttribute(const char *aName, PRInt32 *val)
01794 {
01795   return GetIntValue(aName, val);
01796 }
01797 
01798 
01799 NS_IMETHODIMP nsMsgIncomingServer::GetSocketType(PRInt32 *aSocketType)
01800 {
01801   nsCAutoString fullPrefName;
01802   getPrefName(m_serverKey.get(), "socketType", fullPrefName);
01803   nsresult rv = m_prefBranch->GetIntPref(fullPrefName.get(), aSocketType);
01804 
01805   // socketType is set to default value. Look at isSecure setting
01806   if (NS_FAILED(rv))
01807   {
01808     PRBool isSecure;
01809     rv = GetBoolValue("isSecure", &isSecure);
01810     if (NS_SUCCEEDED(rv) && isSecure)
01811     {
01812        *aSocketType = nsIMsgIncomingServer::useSSL;
01813       // don't call virtual method in case overrides call GetSocketType
01814       nsMsgIncomingServer::SetSocketType(*aSocketType);
01815     }
01816     else
01817     {
01818        getDefaultIntPref("socketType", aSocketType);
01819     }
01820   }
01821   return rv;
01822   
01823 }
01824 
01825 NS_IMETHODIMP nsMsgIncomingServer::SetSocketType(PRInt32 aSocketType)
01826 {
01827   nsCAutoString fullPrefName;
01828   getPrefName(m_serverKey.get(), "socketType", fullPrefName);
01829   nsresult rv = m_prefBranch->SetIntPref(fullPrefName.get(), aSocketType);
01830 
01831   return rv;
01832 }
01833 
01834 // Check if the password is available and return a boolean indicating whether 
01835 // it is being authenticated or not.
01836 NS_IMETHODIMP 
01837 nsMsgIncomingServer::GetPasswordPromptRequired(PRBool *aPasswordIsRequired)
01838 {
01839   nsresult rv = NS_OK;
01840   NS_ENSURE_ARG_POINTER(aPasswordIsRequired);
01841 
01842   *aPasswordIsRequired = PR_TRUE;
01843   // If the password is empty, check to see if it is stored and to be retrieved
01844   if (m_password.IsEmpty()) {
01845     nsCOMPtr <nsIPasswordManagerInternal> passwordMgrInt = do_GetService(NS_PASSWORDMANAGER_CONTRACTID, &rv);
01846     if(NS_SUCCEEDED(rv) && passwordMgrInt) {
01847 
01848       // Get the current server URI
01849       nsXPIDLCString currServerUri;
01850       rv = GetServerURI(getter_Copies(currServerUri));
01851       NS_ENSURE_SUCCESS(rv, rv);
01852 
01853       // Obtain the server URI which is in the format <protocol>://<userid>@<hostname>.
01854       // Password manager uses the same format when it stores the password on user's request.
01855 
01856       nsCAutoString hostFound;
01857       nsAutoString userNameFound;
01858       nsAutoString passwordFound;
01859 
01860       // Get password entry corresponding to the host URI we are passing in.
01861       rv = passwordMgrInt->FindPasswordEntry(currServerUri, EmptyString(), EmptyString(),
01862                                              hostFound, userNameFound, passwordFound);
01863       if (NS_FAILED(rv)) 
01864       {
01865         *aPasswordIsRequired = PR_TRUE;
01866         return NS_OK;
01867       }
01868 
01869       // If a match is found, password element is filled in. Convert the
01870       // obtained password and store it for the session.
01871       if (!passwordFound.IsEmpty()) 
01872       {
01873         if (PasswordProtectLocalCache()) // hmm, shouldn't be in here, so remove it.
01874         {
01875           ForgetPassword();
01876         }
01877         else
01878         {
01879           nsCAutoString cStrPassword;
01880           cStrPassword.AssignWithConversion(passwordFound);
01881           rv = SetPassword(cStrPassword.get());
01882           NS_ENSURE_SUCCESS(rv, rv);
01883         }
01884       }
01885     }
01886   }
01887   *aPasswordIsRequired = m_password.IsEmpty();
01888   return rv;
01889 }
01890 
01891 NS_IMETHODIMP nsMsgIncomingServer::ConfigureTemporaryFilters(nsIMsgFilterList *aFilterList)
01892 {
01893   nsresult rv = ConfigureTemporaryReturnReceiptsFilter(aFilterList);
01894   if (NS_FAILED(rv)) // shut up warnings...
01895     return rv;
01896   return ConfigureTemporaryServerSpamFilters(aFilterList);
01897 }
01898 
01899 nsresult
01900 nsMsgIncomingServer::ConfigureTemporaryServerSpamFilters(nsIMsgFilterList *filterList)
01901 {
01902   nsCOMPtr<nsISpamSettings> spamSettings;
01903   nsresult rv = GetSpamSettings(getter_AddRefs(spamSettings));
01904   NS_ENSURE_SUCCESS(rv, rv);
01905 
01906   PRBool useServerFilter;
01907   rv = spamSettings->GetUseServerFilter(&useServerFilter);
01908   NS_ENSURE_SUCCESS(rv, rv);
01909   
01910   // if we aren't configured to use server filters, then return early.
01911   if (!useServerFilter)
01912     return NS_OK;
01913   
01914   // For performance reasons, we'll handle clearing of filters if the user turns
01915   // off the server-side filters from the junk mail controls, in the junk mail controls.
01916   nsCAutoString serverFilterName;
01917   spamSettings->GetServerFilterName(serverFilterName);
01918   if (serverFilterName.IsEmpty())
01919     return NS_OK;
01920   PRInt32 serverFilterTrustFlags = 0;
01921   (void) spamSettings->GetServerFilterTrustFlags(&serverFilterTrustFlags);
01922   if (!serverFilterTrustFlags)
01923     return NS_OK;
01924   // check if filters have been setup already.
01925   nsAutoString yesFilterName, noFilterName;
01926   yesFilterName.AppendWithConversion(serverFilterName);
01927   yesFilterName.AppendLiteral("Yes");
01928 
01929   noFilterName.AppendWithConversion(serverFilterName);
01930   noFilterName.AppendLiteral("No");
01931 
01932   nsCOMPtr<nsIMsgFilter> newFilter;
01933   (void) filterList->GetFilterNamed(yesFilterName.get(),
01934                                   getter_AddRefs(newFilter));
01935 
01936   if (!newFilter)
01937     (void) filterList->GetFilterNamed(noFilterName.get(),
01938                                   getter_AddRefs(newFilter));
01939   if (newFilter)
01940     return NS_OK;
01941 
01942   nsCOMPtr<nsIFile> file;
01943   spamSettings->GetServerFilterFile(getter_AddRefs(file));
01944 
01945   // it's possible that we can no longer find the sfd file (i.e. the user disabled an extnsion that
01946   // was supplying the .sfd file.
01947   if (!file)
01948     return NS_OK;
01949 
01950   nsCOMPtr<nsIFileSpec> serverFilterSpec;
01951   rv = NS_NewFileSpecFromIFile(file, getter_AddRefs(serverFilterSpec));
01952   if (NS_FAILED(rv)) return rv;
01953 
01954   nsCOMPtr<nsIMsgFilterService> filterService = do_GetService(NS_MSGFILTERSERVICE_CONTRACTID, &rv);
01955   nsCOMPtr<nsIMsgFilterList> serverFilterList;
01956     
01957   rv = filterService->OpenFilterList(serverFilterSpec, NULL, NULL, getter_AddRefs(serverFilterList));
01958   NS_ENSURE_SUCCESS(rv, rv);
01959 
01960   rv = serverFilterList->GetFilterNamed(yesFilterName.get(),
01961                                   getter_AddRefs(newFilter));
01962   if (newFilter && serverFilterTrustFlags & nsISpamSettings::TRUST_POSITIVES)
01963   {
01964     newFilter->SetTemporary(PR_TRUE);
01965     // check if we're supposed to move junk mail to junk folder; if so,
01966     // add filter action to do so.
01967     PRBool moveOnSpam, markAsReadOnSpam;
01968     spamSettings->GetMoveOnSpam(&moveOnSpam);
01969     if (moveOnSpam)
01970     {
01971       nsXPIDLCString spamFolderURI;
01972       rv = spamSettings->GetSpamFolderURI(getter_Copies(spamFolderURI));
01973       if (NS_SUCCEEDED(rv) && (!spamFolderURI.IsEmpty()))
01974       {
01975         nsCOMPtr <nsIMsgRuleAction> moveAction;
01976         rv = newFilter->CreateAction(getter_AddRefs(moveAction));
01977         if (NS_SUCCEEDED(rv))
01978         {
01979           moveAction->SetType(nsMsgFilterAction::MoveToFolder);
01980           moveAction->SetTargetFolderUri(spamFolderURI);
01981           newFilter->AppendAction(moveAction);
01982         }
01983       }
01984     }
01985     spamSettings->GetMarkAsReadOnSpam(&markAsReadOnSpam);
01986     if (markAsReadOnSpam)
01987     {
01988       nsCOMPtr <nsIMsgRuleAction> markAsReadAction;
01989       rv = newFilter->CreateAction(getter_AddRefs(markAsReadAction));
01990       if (NS_SUCCEEDED(rv))
01991       {
01992         markAsReadAction->SetType(nsMsgFilterAction::MarkRead);
01993         newFilter->AppendAction(markAsReadAction);
01994       }
01995     }
01996     filterList->InsertFilterAt(0, newFilter);
01997   }
01998 
01999   rv = serverFilterList->GetFilterNamed(noFilterName.get(),
02000                                   getter_AddRefs(newFilter));
02001   if (newFilter && serverFilterTrustFlags & nsISpamSettings::TRUST_NEGATIVES)
02002   {
02003     newFilter->SetTemporary(PR_TRUE);
02004     filterList->InsertFilterAt(0, newFilter);
02005   }
02006 
02007   return rv;
02008 }
02009 
02010 nsresult
02011 nsMsgIncomingServer::ConfigureTemporaryReturnReceiptsFilter(nsIMsgFilterList *filterList)
02012 {
02013   nsresult rv;
02014 
02015   nsCOMPtr<nsIMsgAccountManager> accountMgr = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
02016   NS_ENSURE_SUCCESS(rv, rv);
02017 
02018   nsCOMPtr<nsIMsgIdentity> identity;
02019   rv = accountMgr->GetFirstIdentityForServer(this, getter_AddRefs(identity));
02020   NS_ENSURE_SUCCESS(rv, rv);
02021   // this can return success and a null identity...
02022   
02023   PRBool useCustomPrefs = PR_FALSE;
02024   PRInt32 incorp = nsIMsgMdnGenerator::eIncorporateInbox;
02025 
02026   if (!identity)
02027     return NS_ERROR_NULL_POINTER;
02028 
02029   identity->GetBoolAttribute("use_custom_prefs", &useCustomPrefs);
02030   if (useCustomPrefs)
02031     rv = GetIntValue("incorporate_return_receipt", &incorp);
02032   else
02033   {
02034     rv = m_prefBranch->GetIntPref("mail.incorporate.return_receipt", &incorp);
02035   }
02036 
02037   PRBool enable = (incorp == nsIMsgMdnGenerator::eIncorporateSent);
02038 
02039   // this is a temporary, internal mozilla filter
02040   // it will not show up in the UI, it will not be written to disk
02041   NS_NAMED_LITERAL_STRING(internalReturnReceiptFilterName, "mozilla-temporary-internal-MDN-receipt-filter");
02042 
02043   nsCOMPtr<nsIMsgFilter> newFilter;
02044   rv = filterList->GetFilterNamed(internalReturnReceiptFilterName.get(),
02045                                   getter_AddRefs(newFilter));
02046   if (newFilter)
02047       newFilter->SetEnabled(enable);
02048   else if (enable)
02049   {
02050     nsXPIDLCString actionTargetFolderUri;
02051     rv = identity->GetFccFolder(getter_Copies(actionTargetFolderUri));
02052     if (!actionTargetFolderUri.IsEmpty())
02053     {
02054       filterList->CreateFilter(internalReturnReceiptFilterName.get(),
02055                                getter_AddRefs(newFilter));
02056       if (newFilter)
02057       {
02058         newFilter->SetEnabled(PR_TRUE);
02059         // this internal filter is temporary
02060         // and should not show up in the UI or be written to disk
02061         newFilter->SetTemporary(PR_TRUE);  
02062        
02063         nsCOMPtr<nsIMsgSearchTerm> term;
02064         nsCOMPtr<nsIMsgSearchValue> value;
02065         
02066         rv = newFilter->CreateTerm(getter_AddRefs(term));
02067         if (NS_SUCCEEDED(rv))
02068         {
02069           rv = term->GetValue(getter_AddRefs(value));
02070           if (NS_SUCCEEDED(rv))
02071           {
02072             // we need to use OtherHeader + 1 so nsMsgFilter::GetTerm will
02073             // return our custom header.
02074             value->SetAttrib(nsMsgSearchAttrib::OtherHeader + 1);
02075             value->SetStr(NS_LITERAL_STRING("multipart/report").get());
02076             term->SetAttrib(nsMsgSearchAttrib::OtherHeader + 1);  
02077             term->SetOp(nsMsgSearchOp::Contains);
02078             term->SetBooleanAnd(PR_TRUE);
02079             term->SetArbitraryHeader("Content-Type");
02080             term->SetValue(value);
02081             newFilter->AppendTerm(term);
02082           }
02083         }
02084         rv = newFilter->CreateTerm(getter_AddRefs(term));
02085         if (NS_SUCCEEDED(rv))
02086         {
02087           rv = term->GetValue(getter_AddRefs(value));
02088           if (NS_SUCCEEDED(rv))
02089           {
02090             // XXX todo
02091             // determine if ::OtherHeader is the best way to do this.
02092             // see nsMsgSearchOfflineMail::MatchTerms()
02093             value->SetAttrib(nsMsgSearchAttrib::OtherHeader + 1);
02094             value->SetStr(NS_LITERAL_STRING("disposition-notification").get());
02095             term->SetAttrib(nsMsgSearchAttrib::OtherHeader + 1);
02096             term->SetOp(nsMsgSearchOp::Contains);
02097             term->SetBooleanAnd(PR_TRUE);
02098             term->SetArbitraryHeader("Content-Type");
02099             term->SetValue(value);
02100             newFilter->AppendTerm(term);
02101           }
02102         }
02103         nsCOMPtr<nsIMsgRuleAction> filterAction;
02104         newFilter->CreateAction(getter_AddRefs(filterAction));
02105         filterAction->SetType(nsMsgFilterAction::MoveToFolder);
02106           filterAction->SetTargetFolderUri(actionTargetFolderUri);
02107           newFilter->AppendAction(filterAction);
02108           filterList->InsertFilterAt(0, newFilter);
02109         }
02110       }
02111     }
02112   return rv;
02113 }
02114 
02115 NS_IMETHODIMP
02116 nsMsgIncomingServer::ClearTemporaryReturnReceiptsFilter()
02117 {
02118   if (mFilterList)
02119   {
02120    nsCOMPtr<nsIMsgFilter> mdnFilter;
02121    nsresult rv = mFilterList->GetFilterNamed(
02122      NS_LITERAL_STRING("mozilla-temporary-internal-MDN-receipt-filter").get(),
02123      getter_AddRefs(mdnFilter));
02124    if (NS_SUCCEEDED(rv) && mdnFilter)
02125      return mFilterList->RemoveFilter(mdnFilter);
02126   }
02127   return NS_OK;
02128 }
02129 
02130 NS_IMETHODIMP
02131 nsMsgIncomingServer::GetMsgFolderFromURI(nsIMsgFolder *aFolderResource, const char *aURI, nsIMsgFolder **aFolder)
02132 {
02133   nsCOMPtr<nsIMsgFolder> rootMsgFolder;
02134   nsresult rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
02135   NS_ENSURE_SUCCESS(rv, rv);
02136   if (!rootMsgFolder)
02137     return NS_ERROR_UNEXPECTED;
02138 
02139   nsCOMPtr <nsIMsgFolder> msgFolder;
02140   rv = rootMsgFolder->GetChildWithURI(aURI, PR_TRUE, PR_TRUE /*caseInsensitive*/, getter_AddRefs(msgFolder));
02141   if (NS_FAILED(rv) || !msgFolder) 
02142     msgFolder = aFolderResource;
02143   
02144   NS_IF_ADDREF(*aFolder = msgFolder);
02145   return NS_OK;
02146 }
02147 
02148 NS_IMETHODIMP
02149 nsMsgIncomingServer::GetSpamSettings(nsISpamSettings **aSpamSettings)
02150 {
02151   NS_ENSURE_ARG_POINTER(aSpamSettings);
02152 
02153   if (!mSpamSettings) {
02154     nsresult rv;
02155 
02156     mSpamSettings = do_CreateInstance(NS_SPAMSETTINGS_CONTRACTID, &rv);
02157     NS_ENSURE_SUCCESS(rv,rv);
02158     mSpamSettings->Initialize(this);
02159     NS_ENSURE_SUCCESS(rv,rv);
02160   }
02161 
02162   NS_ADDREF(*aSpamSettings = mSpamSettings);
02163   return NS_OK;
02164 }
02165 
02166 NS_IMETHODIMP
02167 nsMsgIncomingServer::GetSpamFilterPlugin(nsIMsgFilterPlugin **aFilterPlugin)
02168 {
02169   NS_ENSURE_ARG_POINTER(aFilterPlugin);
02170   if (!mFilterPlugin)
02171   {
02172     nsresult rv;
02173 
02174     // get the plugin service
02175     mFilterPlugin = do_GetService("@mozilla.org/messenger/filter-plugin;1?name=bayesianfilter", &rv);
02176 
02177     if (NS_FAILED(rv)) 
02178         return rv;
02179   }
02180 
02181   NS_IF_ADDREF(*aFilterPlugin = mFilterPlugin);
02182   return NS_OK;
02183 }
02184 
02185 
02186 // get all the servers that defer to the account for the passed in server. Note that
02187 // destServer may not be "this"
02188 nsresult nsMsgIncomingServer::GetDeferredServers(nsIMsgIncomingServer *destServer, nsISupportsArray **_retval)
02189 {
02190   nsresult rv;
02191   nsCOMPtr<nsIMsgAccountManager> accountManager 
02192     = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
02193   NS_ENSURE_SUCCESS(rv, rv);
02194   nsCOMPtr<nsISupportsArray> servers;
02195   rv = NS_NewISupportsArray(getter_AddRefs(servers));
02196   if (NS_FAILED(rv)) return rv;
02197 
02198   nsCOMPtr <nsIMsgAccount> thisAccount;
02199   accountManager->FindAccountForServer(destServer, getter_AddRefs(thisAccount));
02200   if (thisAccount)
02201   {
02202     nsCOMPtr <nsISupportsArray> allServers;
02203     nsXPIDLCString accountKey;
02204     thisAccount->GetKey(getter_Copies(accountKey));
02205     accountManager->GetAllServers(getter_AddRefs(allServers));
02206     if (allServers)
02207     {
02208       PRUint32 serverCount;
02209       allServers->Count(&serverCount);
02210       for (PRUint32 i = 0; i < serverCount; i++)
02211       {
02212         nsCOMPtr <nsIMsgIncomingServer> server (do_QueryElementAt(allServers, i));
02213         if (server)
02214         {
02215           nsXPIDLCString deferredToAccount;
02216           server->GetCharValue("deferred_to_account", getter_Copies(deferredToAccount));
02217           if (deferredToAccount.Equals(accountKey))
02218             servers->AppendElement(server);
02219         }
02220       }
02221     }
02222   }
02223   *_retval = servers;
02224   NS_ADDREF(*_retval);
02225   return rv;
02226 }
02227 
02228 NS_IMETHODIMP nsMsgIncomingServer::GetIsDeferredTo(PRBool *aIsDeferredTo)
02229 {
02230   NS_ENSURE_ARG_POINTER(aIsDeferredTo);
02231   nsCOMPtr<nsIMsgAccountManager> accountManager 
02232     = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
02233   if (accountManager)
02234   {
02235     nsCOMPtr <nsIMsgAccount> thisAccount;
02236     accountManager->FindAccountForServer(this, getter_AddRefs(thisAccount));
02237     if (thisAccount)
02238     {
02239       nsCOMPtr <nsISupportsArray> allServers;
02240       nsXPIDLCString accountKey;
02241       thisAccount->GetKey(getter_Copies(accountKey));
02242       accountManager->GetAllServers(getter_AddRefs(allServers));
02243       if (allServers)
02244       {
02245         PRUint32 serverCount;
02246         allServers->Count(&serverCount);
02247         for (PRUint32 i = 0; i < serverCount; i++)
02248         {
02249           nsCOMPtr <nsIMsgIncomingServer> server (do_QueryElementAt(allServers, i));
02250           if (server)
02251           {
02252             nsXPIDLCString deferredToAccount;
02253             server->GetCharValue("deferred_to_account", getter_Copies(deferredToAccount));
02254             if (deferredToAccount.Equals(accountKey))
02255             {
02256               *aIsDeferredTo = PR_TRUE;
02257               return NS_OK;
02258             }
02259           }
02260         }
02261       }
02262     }
02263   }
02264   *aIsDeferredTo = PR_FALSE;
02265   return NS_OK;
02266 }
02267 
02268 const long kMaxDownloadTableSize = 500;
02269 
02270 // aData is the server, from that we get the cutoff point, below which we evict
02271 // element is the arrival index of the msg.
02272 /* static */PRBool nsMsgIncomingServer::evictOldEntries(nsHashKey *aKey, void *element, void *aData)
02273 {
02274   nsMsgIncomingServer *server = (nsMsgIncomingServer *)aData;
02275   if (NS_PTR_TO_INT32(element) < server->m_numMsgsDownloaded - kMaxDownloadTableSize/2)
02276     return kHashEnumerateRemove;
02277   return server->m_downloadedHdrs.Count() > kMaxDownloadTableSize/2;
02278 }
02279 
02280 // hash the concatenation of the message-id and subject as the hash table key, 
02281 // and store the arrival index as the value. To limit the size of the hash table,
02282 // we just throw out ones with a lower ordinal value than the cut-off point.
02283 NS_IMETHODIMP nsMsgIncomingServer::IsNewHdrDuplicate(nsIMsgDBHdr *aNewHdr, PRBool *aResult)
02284 {
02285   NS_ENSURE_ARG_POINTER(aResult);
02286   *aResult = PR_FALSE;
02287   nsCAutoString strHashKey;
02288   nsXPIDLCString messageId, subject;
02289   aNewHdr->GetMessageId(getter_Copies(messageId));
02290   strHashKey.Append(messageId);
02291   aNewHdr->GetSubject(getter_Copies(subject));
02292   strHashKey.Append(subject);
02293   nsCStringKey hashKey(strHashKey);
02294   PRInt32 hashValue = NS_PTR_TO_INT32(m_downloadedHdrs.Get(&hashKey));
02295   if (hashValue)
02296   {
02297     *aResult = PR_TRUE;
02298   }
02299   else
02300   {
02301     // we store the current size of the hash table as the hash
02302     // value - this allows us to delete older entries.
02303     m_downloadedHdrs.Put(&hashKey, NS_INT32_TO_PTR(++m_numMsgsDownloaded));
02304     // Check if hash table is larger than some reasonable size
02305     // and if is it, iterate over hash table deleting messages
02306     // with an arrival index < number of msgs downloaded - half the reasonable size.
02307     if (m_downloadedHdrs.Count() >= kMaxDownloadTableSize)
02308       m_downloadedHdrs.Enumerate(evictOldEntries, this);
02309   }
02310   return NS_OK;
02311 }
02312