Back to index

lightning-sunbird  0.9+nobinonly
nsPrefService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Communicator client 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  *   Alec Flett <alecf@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsPrefService.h"
00040 #include "nsAppDirectoryServiceDefs.h"
00041 #include "nsDirectoryServiceDefs.h"
00042 #include "nsICategoryManager.h"
00043 #include "nsCategoryManagerUtils.h"
00044 #include "nsNetUtil.h"
00045 #include "nsIFile.h"
00046 #include "nsILocalFile.h"
00047 #include "nsIObserverService.h"
00048 #include "nsPrefBranch.h"
00049 #include "nsXPIDLString.h"
00050 #include "nsCRT.h"
00051 #include "nsCOMArray.h"
00052 #include "nsXPCOMCID.h"
00053 
00054 #include "nsQuickSort.h"
00055 #include "prmem.h"
00056 #include "pldhash.h"
00057 
00058 #include "prefapi.h"
00059 #include "prefread.h"
00060 #include "prefapi_private_data.h"
00061 
00062 #include "nsITimelineService.h"
00063 
00064 #ifdef MOZ_PROFILESHARING
00065 #include "nsIProfileSharingSetup.h"
00066 #include "nsSharedPrefHandler.h"
00067 #endif
00068 
00069 // Definitions
00070 #define INITIAL_PREF_FILES 10
00071 #define PREF_READ_BUFFER_SIZE 4096
00072 
00073 // Prototypes
00074 #ifdef MOZ_PROFILESHARING
00075 static PRBool isSharingEnabled();
00076 #endif
00077 
00078 static nsresult openPrefFile(nsIFile* aFile);
00079 static nsresult pref_InitInitialObjects(void);
00080 
00081 //-----------------------------------------------------------------------------
00082 
00083 /*
00084  * Constructor/Destructor
00085  */
00086 
00087 nsPrefService::nsPrefService()
00088 : mErrorOpeningUserPrefs(PR_FALSE)
00089 #if MOZ_PROFILESHARING
00090   , mErrorOpeningSharedUserPrefs(PR_FALSE)
00091 #endif
00092 {
00093 }
00094 
00095 nsPrefService::~nsPrefService()
00096 {
00097   PREF_Cleanup();
00098 
00099 #ifdef MOZ_PROFILESHARING
00100   NS_IF_RELEASE(gSharedPrefHandler);
00101 #endif
00102 }
00103 
00104 
00105 /*
00106  * nsISupports Implementation
00107  */
00108 
00109 NS_IMPL_THREADSAFE_ADDREF(nsPrefService)
00110 NS_IMPL_THREADSAFE_RELEASE(nsPrefService)
00111 
00112 NS_INTERFACE_MAP_BEGIN(nsPrefService)
00113     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
00114     NS_INTERFACE_MAP_ENTRY(nsIPrefService)
00115     NS_INTERFACE_MAP_ENTRY(nsIObserver)
00116     NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
00117     NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
00118     NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
00119     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00120 NS_INTERFACE_MAP_END
00121 
00122 
00123 /*
00124  * nsIPrefService Implementation
00125  */
00126 
00127 nsresult nsPrefService::Init()
00128 {
00129   nsPrefBranch *rootBranch = new nsPrefBranch("", PR_FALSE); 
00130   if (!rootBranch)
00131     return NS_ERROR_OUT_OF_MEMORY;
00132 
00133   mRootBranch = (nsIPrefBranch2 *)rootBranch;
00134   
00135   nsXPIDLCString lockFileName;
00136   nsresult rv;
00137 
00138   rv = PREF_Init();
00139   NS_ENSURE_SUCCESS(rv, rv);
00140 
00141   rv = pref_InitInitialObjects();
00142   NS_ENSURE_SUCCESS(rv, rv);
00143 
00144   /*
00145    * The following is a small hack which will allow us to only load the library
00146    * which supports the netscape.cfg file if the preference is defined. We
00147    * test for the existence of the pref, set in the all.js (mozilla) or
00148    * all-ns.js (netscape 6), and if it exists we startup the pref config
00149    * category which will do the rest.
00150    */
00151 
00152   rv = mRootBranch->GetCharPref("general.config.filename", getter_Copies(lockFileName));
00153   if (NS_SUCCEEDED(rv))
00154     NS_CreateServicesFromCategory("pref-config-startup",
00155                                   NS_STATIC_CAST(nsISupports *, NS_STATIC_CAST(void *, this)),
00156                                   "pref-config-startup");    
00157 
00158   nsCOMPtr<nsIObserverService> observerService = 
00159            do_GetService("@mozilla.org/observer-service;1", &rv);
00160   if (observerService) {
00161     rv = observerService->AddObserver(this, "profile-before-change", PR_TRUE);
00162     if (NS_SUCCEEDED(rv)) {
00163       rv = observerService->AddObserver(this, "profile-do-change", PR_TRUE);
00164     }
00165   }
00166 
00167 #ifdef MOZ_PROFILESHARING  
00168   rv = NS_CreateSharedPrefHandler(this);
00169 #endif
00170 
00171   return(rv);
00172 }
00173 
00174 NS_IMETHODIMP nsPrefService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00175 {
00176   nsresult rv = NS_OK;
00177 
00178   if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
00179     if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
00180       if (mCurrentFile) {
00181         mCurrentFile->Remove(PR_FALSE);
00182         mCurrentFile = nsnull;
00183       }
00184     } else {
00185       rv = SavePrefFile(nsnull);
00186 #ifdef MOZ_PROFILESHARING
00187       if (isSharingEnabled())
00188         rv = gSharedPrefHandler->OnSessionEnd();
00189 #endif
00190     }
00191   } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
00192   
00193 #ifdef MOZ_PROFILESHARING
00194     if (isSharingEnabled())
00195       rv = gSharedPrefHandler->OnSessionBegin();
00196     else
00197 #endif
00198     {
00199       ResetUserPrefs();
00200       rv = ReadUserPrefs(nsnull);
00201     }
00202   } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
00203     // Reload the default prefs from file.
00204     pref_InitInitialObjects();
00205   }
00206   return rv;
00207 }
00208 
00209 
00210 NS_IMETHODIMP nsPrefService::ReadUserPrefs(nsIFile *aFile)
00211 {
00212   nsresult rv;
00213 
00214   if (nsnull == aFile) {
00215     rv = UseDefaultPrefFile();
00216     UseUserPrefFile();
00217 
00218     NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
00219 
00220   } else {
00221     rv = ReadAndOwnUserPrefFile(aFile);
00222   }
00223   return rv;
00224 }
00225 
00226 NS_IMETHODIMP nsPrefService::ResetPrefs()
00227 {
00228   NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
00229   PREF_CleanupPrefs();
00230 
00231   nsresult rv = PREF_Init();
00232   NS_ENSURE_SUCCESS(rv, rv);
00233 
00234   return pref_InitInitialObjects();
00235 }
00236 
00237 NS_IMETHODIMP nsPrefService::ResetUserPrefs()
00238 {
00239   PREF_ClearAllUserPrefs();
00240   return NS_OK;    
00241 }
00242 
00243 NS_IMETHODIMP nsPrefService::SavePrefFile(nsIFile *aFile)
00244 {
00245 #ifdef MOZ_PROFILESHARING
00246   // sharing only applies to the default prefs file
00247   if (aFile == nsnull && isSharingEnabled())
00248     return gSharedPrefHandler->OnSavePrefs();
00249 #endif
00250   return SavePrefFileInternal(aFile);
00251 }
00252 
00253 NS_IMETHODIMP nsPrefService::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
00254 {
00255   nsresult rv;
00256 
00257   if ((nsnull != aPrefRoot) && (*aPrefRoot != '\0')) {
00258     // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
00259     nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, PR_FALSE);
00260     if (!prefBranch)
00261       return NS_ERROR_OUT_OF_MEMORY;
00262 
00263     rv = CallQueryInterface(prefBranch, _retval);
00264   } else {
00265     // special case caching the default root
00266     rv = CallQueryInterface(mRootBranch, _retval);
00267   }
00268   return rv;
00269 }
00270 
00271 NS_IMETHODIMP nsPrefService::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
00272 {
00273   nsresult rv;
00274 
00275   // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
00276   nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, PR_TRUE);
00277   if (!prefBranch)
00278     return NS_ERROR_OUT_OF_MEMORY;
00279 
00280   rv = CallQueryInterface(prefBranch, _retval);
00281   return rv;
00282 }
00283 
00284 
00285 nsresult nsPrefService::NotifyServiceObservers(const char *aTopic)
00286 {
00287   nsresult rv;
00288   nsCOMPtr<nsIObserverService> observerService = 
00289     do_GetService("@mozilla.org/observer-service;1", &rv);
00290   
00291   if (NS_FAILED(rv) || !observerService)
00292     return rv;
00293 
00294   nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
00295   observerService->NotifyObservers(subject, aTopic, nsnull);
00296   
00297   return NS_OK;
00298 }
00299 
00300 nsresult nsPrefService::UseDefaultPrefFile()
00301 {
00302   nsresult rv, rv2;
00303   nsCOMPtr<nsIFile> aFile;
00304 
00305 #ifdef MOZ_PROFILESHARING
00306   // First, read the shared file.
00307   if (isSharingEnabled()) {
00308     rv = NS_GetSpecialDirectory(NS_SHARED NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
00309     if (NS_SUCCEEDED(rv)) {
00310       rv = ReadAndOwnSharedUserPrefFile(aFile);
00311       // Most likely cause of failure here is that the file didn't
00312       // exist, so save a new one. mSharedUserPrefReadFailed will be
00313       // used to catch an error in actually reading the file.
00314       if (NS_FAILED(rv)) {
00315         rv2 = SavePrefFileInternal(aFile);
00316         NS_ASSERTION(NS_SUCCEEDED(rv2), "Failed to save new shared pref file");
00317       }
00318     }
00319   }
00320   // Continue on to read the nonshared file.
00321 #endif
00322 
00323   rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
00324   if (NS_SUCCEEDED(rv)) {
00325     rv = ReadAndOwnUserPrefFile(aFile);
00326     // Most likely cause of failure here is that the file didn't
00327     // exist, so save a new one. mUserPrefReadFailed will be
00328     // used to catch an error in actually reading the file.
00329     if (NS_FAILED(rv)) {
00330       rv2 = SavePrefFileInternal(aFile);
00331       NS_ASSERTION(NS_SUCCEEDED(rv2), "Failed to save new shared pref file");
00332     }
00333   }
00334   
00335   return rv;
00336 }
00337 
00338 nsresult nsPrefService::UseUserPrefFile()
00339 {
00340   nsresult rv = NS_OK;
00341   nsCOMPtr<nsIFile> aFile;
00342 
00343 #ifdef MOZ_PROFILESHARING
00344   nsCAutoString prefsDirProp(NS_APP_PREFS_50_DIR);
00345   if (isSharingEnabled())
00346     prefsDirProp.Insert(NS_SHARED, 0); // Prepend modifier so we get shared file
00347 #else
00348   nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR);
00349 #endif
00350 
00351   rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile));
00352   if (NS_SUCCEEDED(rv) && aFile) {
00353     rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
00354     if (NS_SUCCEEDED(rv)) {
00355       rv = openPrefFile(aFile);
00356     }
00357   }
00358   return rv;
00359 }
00360 
00361 nsresult nsPrefService::ReadAndOwnUserPrefFile(nsIFile *aFile)
00362 {
00363   NS_ENSURE_ARG(aFile);
00364   
00365   if (mCurrentFile == aFile)
00366     return NS_OK;
00367   mCurrentFile = aFile;
00368 
00369 #ifdef MOZ_PROFILESHARING
00370   // We don't want prefs set here to cause transactions
00371   gSharedPrefHandler->ReadingUserPrefs(PR_TRUE);
00372 #endif
00373 
00374   // We need to track errors in reading the shared and the
00375   // non-shared files independently. 
00376   // Set the appropriate member variable from it after reading.
00377   nsresult rv = openPrefFile(mCurrentFile);
00378   mErrorOpeningUserPrefs = NS_FAILED(rv);
00379 
00380 #ifdef MOZ_PROFILESHARING
00381   gSharedPrefHandler->ReadingUserPrefs(PR_FALSE);
00382 #endif
00383 
00384   return rv;
00385 }
00386 
00387 #ifdef MOZ_PROFILESHARING
00388 nsresult nsPrefService::ReadAndOwnSharedUserPrefFile(nsIFile *aFile)
00389 {
00390   NS_ENSURE_ARG(aFile);
00391 
00392   if (mCurrentSharedFile == aFile)
00393     return NS_OK;
00394   mCurrentSharedFile = aFile;
00395 
00396 #ifdef MOZ_PROFILESHARING
00397   // We don't want prefs set here to cause transactions
00398   gSharedPrefHandler->ReadingUserPrefs(PR_TRUE);
00399 #endif
00400 
00401   // We need to track errors in reading the shared and the
00402   // non-shared files independently. 
00403   // Set the appropriate member variable from it after reading.
00404   nsresult rv = openPrefFile(mCurrentSharedFile);
00405   mErrorOpeningSharedUserPrefs = NS_FAILED(rv);
00406 
00407 #ifdef MOZ_PROFILESHARING
00408   gSharedPrefHandler->ReadingUserPrefs(PR_FALSE);
00409 #endif
00410 
00411   return rv;
00412 }
00413 #endif
00414 
00415 nsresult nsPrefService::SavePrefFileInternal(nsIFile *aFile)
00416 {
00417   if (nsnull == aFile) {
00418     // the gDirty flag tells us if we should write to mCurrentFile
00419     // we only check this flag when the caller wants to write to the default
00420     if (!gDirty)
00421       return NS_OK;
00422     
00423     // It's possible that we never got a prefs file.
00424     nsresult rv = NS_OK;
00425     if (mCurrentFile)
00426       rv = WritePrefFile(mCurrentFile);
00427 
00428 #ifdef MOZ_PROFILESHARING
00429     if (mCurrentSharedFile) {
00430       nsresult rv2 = WritePrefFile(mCurrentSharedFile);
00431       if (NS_SUCCEEDED(rv))
00432         rv = rv2;
00433     }
00434 #endif
00435 
00436     return rv;
00437   } else {
00438     return WritePrefFile(aFile);
00439   }
00440 }
00441 
00442 nsresult nsPrefService::WritePrefFile(nsIFile* aFile)
00443 {
00444   const char                outHeader[] =
00445     "# Mozilla User Preferences"
00446     NS_LINEBREAK
00447     NS_LINEBREAK
00448     "/* Do not edit this file."
00449     NS_LINEBREAK
00450     " *"
00451     NS_LINEBREAK
00452     " * If you make changes to this file while the application is running,"
00453     NS_LINEBREAK
00454     " * the changes will be overwritten when the application exits."
00455     NS_LINEBREAK
00456     " *"
00457     NS_LINEBREAK
00458     " * To make a manual change to preferences, you can visit the URL about:config"
00459     NS_LINEBREAK
00460     " * For more information, see http://www.mozilla.org/unix/customizing.html#prefs"
00461     NS_LINEBREAK
00462     " */"
00463     NS_LINEBREAK
00464     NS_LINEBREAK;
00465 
00466   nsCOMPtr<nsIOutputStream> outStreamSink;
00467   nsCOMPtr<nsIOutputStream> outStream;
00468   PRUint32                  writeAmount;
00469   nsresult                  rv;
00470 
00471   if (!gHashTable.ops)
00472     return NS_ERROR_NOT_INITIALIZED;
00473 
00474   /* ?! Don't save (blank) user prefs if there was an error reading them */
00475   if (aFile == mCurrentFile && mErrorOpeningUserPrefs)
00476     return NS_OK;
00477 #if MOZ_PROFILESHARING
00478   if (aFile == mCurrentSharedFile && mErrorOpeningSharedUserPrefs)
00479     return NS_OK;
00480 #endif
00481 
00482   // execute a "safe" save by saving through a tempfile
00483   rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
00484                                        aFile,
00485                                        -1,
00486                                        0600);
00487   if (NS_FAILED(rv)) 
00488       return rv;
00489   rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
00490   if (NS_FAILED(rv)) 
00491       return rv;  
00492 
00493   char** valueArray = (char **)PR_Calloc(sizeof(char *), gHashTable.entryCount);
00494   if (!valueArray)
00495     return NS_ERROR_OUT_OF_MEMORY;
00496   
00497   pref_saveArgs saveArgs;
00498   saveArgs.prefArray = valueArray;
00499   saveArgs.saveTypes = SAVE_ALL;
00500   
00501 #if MOZ_PROFILESHARING
00502   if (isSharingEnabled()) {
00503     if (aFile == mCurrentSharedFile)
00504       saveArgs.saveTypes = SAVE_SHARED;
00505     else if (aFile == mCurrentFile)
00506       saveArgs.saveTypes = SAVE_NONSHARED;
00507   }
00508 #endif
00509   
00510   // get the lines that we're supposed to be writing to the file
00511   PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
00512     
00513   /* Sort the preferences to make a readable file on disk */
00514   NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char *), pref_CompareStrings, NULL);
00515   
00516   // write out the file header
00517   outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
00518 
00519   char** walker = valueArray;
00520   for (PRUint32 valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) {
00521     if (*walker) {
00522       outStream->Write(*walker, strlen(*walker), &writeAmount);
00523       outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
00524       PR_Free(*walker);
00525     }
00526   }
00527   PR_Free(valueArray);
00528 
00529   // tell the safe output stream to overwrite the real prefs file
00530   // (it'll abort if there were any errors during writing)
00531   nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
00532   NS_ASSERTION(safeStream, "expected a safe output stream!");
00533   if (safeStream) {
00534     rv = safeStream->Finish();
00535     if (NS_FAILED(rv)) {
00536       NS_WARNING("failed to save prefs file! possible dataloss");
00537       return rv;
00538     }
00539   }
00540 
00541   gDirty = PR_FALSE;
00542   return NS_OK;
00543 }
00544 
00545 #ifdef MOZ_PROFILESHARING
00546 static PRBool isSharingEnabled()
00547 {
00548   static PRBool gSharingEnabled = PR_FALSE;
00549   
00550   // If FALSE, query again. It may not have been set yet.
00551   if (!gSharingEnabled) {
00552     nsCOMPtr<nsIProfileSharingSetup> sharingSetup =
00553         do_GetService("@mozilla.org/embedcomp/profile-sharing-setup;1");
00554     if (sharingSetup)
00555       sharingSetup->GetIsSharingEnabled(&gSharingEnabled);
00556   }
00557   return gSharingEnabled;
00558 }
00559 #endif
00560 
00561 static nsresult openPrefFile(nsIFile* aFile)
00562 {
00563   nsCOMPtr<nsIInputStream> inStr;
00564   char      readBuf[PREF_READ_BUFFER_SIZE];
00565 
00566 #if MOZ_TIMELINE
00567   {
00568     nsCAutoString str;
00569     aFile->GetNativePath(str);
00570     NS_TIMELINE_MARK_FUNCTION1("load pref file", str.get());
00571   }
00572 #endif
00573 
00574   nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
00575   if (NS_FAILED(rv)) 
00576     return rv;        
00577 
00578   PrefParseState ps;
00579   PREF_InitParseState(&ps, PREF_ReaderCallback, NULL);
00580   for (;;) {
00581     PRUint32 amtRead = 0;
00582     rv = inStr->Read(readBuf, sizeof(readBuf), &amtRead);
00583     if (NS_FAILED(rv) || amtRead == 0)
00584       break;
00585 
00586     PREF_ParseBuf(&ps, readBuf, amtRead); 
00587   }
00588   PREF_FinalizeParseState(&ps);
00589   return rv;        
00590 }
00591 
00592 /*
00593  * some stuff that gets called from Pref_Init()
00594  */
00595 
00596 static int
00597 pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
00598 {
00599   nsCAutoString filename1, filename2;
00600   aFile1->GetNativeLeafName(filename1);
00601   aFile2->GetNativeLeafName(filename2);
00602 
00603   return Compare(filename2, filename1);
00604 }
00605 
00611 static nsresult
00612 pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, PRUint32 aSpecialFilesCount)
00613 {
00614   nsresult rv, rv2;
00615   PRBool hasMoreElements;
00616 
00617   nsCOMPtr<nsISimpleEnumerator> dirIterator;
00618 
00619   // this may fail in some normal cases, such as embedders who do not use a GRE
00620   rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
00621   if (NS_FAILED(rv)) {
00622     // If the directory doesn't exist, then we have no reason to complain.  We
00623     // loaded everything (and nothing) successfully.
00624     if (rv == NS_ERROR_FILE_NOT_FOUND)
00625       rv = NS_OK;
00626     return rv;
00627   }
00628 
00629   rv = dirIterator->HasMoreElements(&hasMoreElements);
00630   NS_ENSURE_SUCCESS(rv, rv);
00631 
00632   nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
00633   nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
00634   nsCOMPtr<nsIFile> prefFile;
00635 
00636   while (hasMoreElements && NS_SUCCEEDED(rv)) {
00637     nsCAutoString leafName;
00638 
00639     rv = dirIterator->GetNext(getter_AddRefs(prefFile));
00640     if (NS_FAILED(rv)) {
00641       break;
00642     }
00643 
00644     prefFile->GetNativeLeafName(leafName);
00645     NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
00646 
00647     // Skip non-js files
00648     if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
00649                        nsCaseInsensitiveCStringComparator())) {
00650       PRBool shouldParse = PR_TRUE;
00651       // separate out special files
00652       for (PRUint32 i = 0; i < aSpecialFilesCount; ++i) {
00653         if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
00654           shouldParse = PR_FALSE;
00655           // special files should be process in order; we put them into
00656           // the array by index; this can make the array sparse
00657           specialFiles.ReplaceObjectAt(prefFile, i);
00658         }
00659       }
00660 
00661       if (shouldParse) {
00662         prefFiles.AppendObject(prefFile);
00663       }
00664     }
00665 
00666     rv = dirIterator->HasMoreElements(&hasMoreElements);
00667   }
00668 
00669   if (prefFiles.Count() + specialFiles.Count() == 0) {
00670     NS_WARNING("No default pref files found.");
00671     if (NS_SUCCEEDED(rv)) {
00672       rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
00673     }
00674     return rv;
00675   }
00676 
00677   prefFiles.Sort(pref_CompareFileNames, nsnull);
00678   
00679   PRUint32 arrayCount = prefFiles.Count();
00680   PRUint32 i;
00681   for (i = 0; i < arrayCount; ++i) {
00682     rv2 = openPrefFile(prefFiles[i]);
00683     if (NS_FAILED(rv2)) {
00684       NS_ERROR("Default pref file not parsed successfully.");
00685       rv = rv2;
00686     }
00687   }
00688 
00689   arrayCount = specialFiles.Count();
00690   for (i = 0; i < arrayCount; ++i) {
00691     // this may be a sparse array; test before parsing
00692     nsIFile* file = specialFiles[i];
00693     if (file) {
00694       rv2 = openPrefFile(file);
00695       if (NS_FAILED(rv2)) {
00696         NS_ERROR("Special default pref file not parsed successfully.");
00697         rv = rv2;
00698       }
00699     }
00700   }
00701 
00702   return rv;
00703 }
00704 
00705 
00706 //----------------------------------------------------------------------------------------
00707 // Initialize default preference JavaScript buffers from
00708 // appropriate TEXT resources
00709 //----------------------------------------------------------------------------------------
00710 static nsresult pref_InitInitialObjects()
00711 {
00712   nsCOMPtr<nsIFile> aFile;
00713   nsCOMPtr<nsIFile> defaultPrefDir;
00714   nsresult          rv;
00715 
00716   // first we parse the GRE default prefs. This also works if we're not using a GRE, 
00717 
00718   rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(defaultPrefDir));
00719   NS_ENSURE_SUCCESS(rv, rv);
00720 
00721   rv = defaultPrefDir->AppendNative(NS_LITERAL_CSTRING("greprefs"));
00722   NS_ENSURE_SUCCESS(rv, rv);
00723 
00724   rv = pref_LoadPrefsInDir(defaultPrefDir, nsnull, 0);
00725   if (NS_FAILED(rv)) {
00726     NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
00727   }
00728 
00729   // now parse the "application" default preferences
00730   rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
00731   NS_ENSURE_SUCCESS(rv, rv);
00732 
00733   /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
00734   static const char* specialFiles[] = {
00735 #if defined(XP_MAC) || defined(XP_MACOSX)
00736       "macprefs.js"
00737 #elif defined(XP_WIN)
00738       "winpref.js"
00739 #elif defined(XP_UNIX)
00740       "unix.js"
00741 #if defined(VMS)
00742       , "openvms.js"
00743 #elif defined(_AIX)
00744       , "aix.js"
00745 #endif
00746 #if defined(MOZ_WIDGET_PHOTON)
00747          , "photon.js"
00748 #endif         
00749 #elif defined(XP_OS2)
00750       "os2pref.js"
00751 #elif defined(XP_BEOS)
00752       "beos.js"
00753 #endif
00754   };
00755 
00756   rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, NS_ARRAY_LENGTH(specialFiles));
00757   if (NS_FAILED(rv)) {
00758     NS_WARNING("Error parsing application default preferences.");
00759   }
00760 
00761   // xxxbsmedberg: TODO load default prefs from a category
00762   // but the architecture is not quite there yet
00763 
00764   nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
00765   if (NS_FAILED(rv)) return rv;
00766 
00767   nsCOMPtr<nsISimpleEnumerator> dirList;
00768   dirSvc->Get(NS_APP_PREFS_DEFAULTS_DIR_LIST,
00769               NS_GET_IID(nsISimpleEnumerator),
00770               getter_AddRefs(dirList));
00771   if (dirList) {
00772     PRBool hasMore;
00773     while (NS_SUCCEEDED(dirList->HasMoreElements(&hasMore)) && hasMore) {
00774       nsCOMPtr<nsISupports> elem;
00775       dirList->GetNext(getter_AddRefs(elem));
00776       if (elem) {
00777         nsCOMPtr<nsIFile> dir = do_QueryInterface(elem);
00778         if (dir) {
00779           // Do we care if a file provided by this process fails to load?
00780           pref_LoadPrefsInDir(dir, nsnull, 0); 
00781         }
00782       }
00783     }
00784   }
00785 
00786   return NS_OK;
00787 }
00788