b=450088 backing out (new reftest failed)
[wine-gecko.git] / modules / libpref / src / nsPrefService.cpp
blob5bd6ebf4696bf74324071515ad8588da984851da
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Alec Flett <alecf@netscape.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsPrefService.h"
40 #include "nsAppDirectoryServiceDefs.h"
41 #include "nsDirectoryServiceDefs.h"
42 #include "nsICategoryManager.h"
43 #include "nsCategoryManagerUtils.h"
44 #include "nsNetUtil.h"
45 #include "nsIFile.h"
46 #include "nsILocalFile.h"
47 #include "nsIObserverService.h"
48 #include "nsPrefBranch.h"
49 #include "nsXPIDLString.h"
50 #include "nsCRT.h"
51 #include "nsCOMArray.h"
52 #include "nsXPCOMCID.h"
53 #include "nsAutoPtr.h"
55 #include "nsQuickSort.h"
56 #include "prmem.h"
57 #include "pldhash.h"
59 #include "prefapi.h"
60 #include "prefread.h"
61 #include "prefapi_private_data.h"
63 #include "nsITimelineService.h"
65 // Definitions
66 #define INITIAL_PREF_FILES 10
68 // Prototypes
69 static nsresult openPrefFile(nsIFile* aFile);
70 static nsresult pref_InitInitialObjects(void);
72 //-----------------------------------------------------------------------------
75 * Constructor/Destructor
78 nsPrefService::nsPrefService()
79 : mDontWriteUserPrefs(PR_FALSE)
83 nsPrefService::~nsPrefService()
85 PREF_Cleanup();
90 * nsISupports Implementation
93 NS_IMPL_THREADSAFE_ADDREF(nsPrefService)
94 NS_IMPL_THREADSAFE_RELEASE(nsPrefService)
96 NS_INTERFACE_MAP_BEGIN(nsPrefService)
97 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
98 NS_INTERFACE_MAP_ENTRY(nsIPrefService)
99 NS_INTERFACE_MAP_ENTRY(nsIObserver)
100 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
101 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
102 NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
103 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
104 NS_INTERFACE_MAP_END
108 * nsIPrefService Implementation
111 nsresult nsPrefService::Init()
113 nsPrefBranch *rootBranch = new nsPrefBranch("", PR_FALSE);
114 if (!rootBranch)
115 return NS_ERROR_OUT_OF_MEMORY;
117 mRootBranch = (nsIPrefBranch2 *)rootBranch;
119 nsXPIDLCString lockFileName;
120 nsresult rv;
122 rv = PREF_Init();
123 NS_ENSURE_SUCCESS(rv, rv);
125 rv = pref_InitInitialObjects();
126 NS_ENSURE_SUCCESS(rv, rv);
129 * The following is a small hack which will allow us to only load the library
130 * which supports the netscape.cfg file if the preference is defined. We
131 * test for the existence of the pref, set in the all.js (mozilla) or
132 * all-ns.js (netscape 6), and if it exists we startup the pref config
133 * category which will do the rest.
136 rv = mRootBranch->GetCharPref("general.config.filename", getter_Copies(lockFileName));
137 if (NS_SUCCEEDED(rv))
138 NS_CreateServicesFromCategory("pref-config-startup",
139 static_cast<nsISupports *>(static_cast<void *>(this)),
140 "pref-config-startup");
142 nsCOMPtr<nsIObserverService> observerService =
143 do_GetService("@mozilla.org/observer-service;1", &rv);
144 if (observerService) {
145 rv = observerService->AddObserver(this, "profile-before-change", PR_TRUE);
146 if (NS_SUCCEEDED(rv)) {
147 rv = observerService->AddObserver(this, "profile-do-change", PR_TRUE);
151 return(rv);
154 NS_IMETHODIMP nsPrefService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
156 nsresult rv = NS_OK;
158 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
159 if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
160 if (mCurrentFile) {
161 mCurrentFile->Remove(PR_FALSE);
162 mCurrentFile = nsnull;
164 } else {
165 rv = SavePrefFile(nsnull);
167 } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
168 ResetUserPrefs();
169 rv = ReadUserPrefs(nsnull);
170 } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
171 // Reload the default prefs from file.
172 pref_InitInitialObjects();
174 return rv;
178 NS_IMETHODIMP nsPrefService::ReadUserPrefs(nsIFile *aFile)
180 nsresult rv;
182 if (nsnull == aFile) {
183 rv = UseDefaultPrefFile();
184 UseUserPrefFile();
186 NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
188 } else {
189 rv = ReadAndOwnUserPrefFile(aFile);
191 return rv;
194 NS_IMETHODIMP nsPrefService::ResetPrefs()
196 NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
197 PREF_CleanupPrefs();
199 nsresult rv = PREF_Init();
200 NS_ENSURE_SUCCESS(rv, rv);
202 return pref_InitInitialObjects();
205 NS_IMETHODIMP nsPrefService::ResetUserPrefs()
207 PREF_ClearAllUserPrefs();
208 return NS_OK;
211 NS_IMETHODIMP nsPrefService::SavePrefFile(nsIFile *aFile)
213 return SavePrefFileInternal(aFile);
216 NS_IMETHODIMP nsPrefService::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
218 nsresult rv;
220 if ((nsnull != aPrefRoot) && (*aPrefRoot != '\0')) {
221 // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
222 nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, PR_FALSE);
223 if (!prefBranch)
224 return NS_ERROR_OUT_OF_MEMORY;
226 rv = CallQueryInterface(prefBranch, _retval);
227 } else {
228 // special case caching the default root
229 rv = CallQueryInterface(mRootBranch, _retval);
231 return rv;
234 NS_IMETHODIMP nsPrefService::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
236 nsresult rv;
238 // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
239 nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, PR_TRUE);
240 if (!prefBranch)
241 return NS_ERROR_OUT_OF_MEMORY;
243 rv = CallQueryInterface(prefBranch, _retval);
244 return rv;
248 nsresult nsPrefService::NotifyServiceObservers(const char *aTopic)
250 nsresult rv;
251 nsCOMPtr<nsIObserverService> observerService =
252 do_GetService("@mozilla.org/observer-service;1", &rv);
254 if (NS_FAILED(rv) || !observerService)
255 return rv;
257 nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
258 observerService->NotifyObservers(subject, aTopic, nsnull);
260 return NS_OK;
263 nsresult nsPrefService::UseDefaultPrefFile()
265 nsresult rv, rv2;
266 nsCOMPtr<nsIFile> aFile;
268 rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
269 if (NS_SUCCEEDED(rv)) {
270 rv = ReadAndOwnUserPrefFile(aFile);
271 // Most likely cause of failure here is that the file didn't
272 // exist, so save a new one. mUserPrefReadFailed will be
273 // used to catch an error in actually reading the file.
274 if (NS_FAILED(rv)) {
275 rv2 = SavePrefFileInternal(aFile);
276 NS_ASSERTION(NS_SUCCEEDED(rv2), "Failed to save new shared pref file");
280 return rv;
283 nsresult nsPrefService::UseUserPrefFile()
285 nsresult rv = NS_OK;
286 nsCOMPtr<nsIFile> aFile;
287 nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR);
289 rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile));
290 if (NS_SUCCEEDED(rv) && aFile) {
291 rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
292 if (NS_SUCCEEDED(rv)) {
293 PRBool exists = PR_FALSE;
294 aFile->Exists(&exists);
295 if (exists) {
296 rv = openPrefFile(aFile);
297 } else {
298 rv = NS_ERROR_FILE_NOT_FOUND;
302 return rv;
305 nsresult nsPrefService::MakeBackupPrefFile(nsIFile *aFile)
307 // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
308 nsAutoString newFilename;
309 nsresult rv = aFile->GetLeafName(newFilename);
310 NS_ENSURE_SUCCESS(rv, rv);
311 newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0);
312 rv = aFile->CopyTo(nsnull, newFilename);
313 NS_ENSURE_SUCCESS(rv, rv);
314 return rv;
317 nsresult nsPrefService::ReadAndOwnUserPrefFile(nsIFile *aFile)
319 NS_ENSURE_ARG(aFile);
321 if (mCurrentFile == aFile)
322 return NS_OK;
323 mCurrentFile = aFile;
325 nsresult rv = NS_OK;
326 PRBool exists = PR_FALSE;
327 mCurrentFile->Exists(&exists);
328 if (exists) {
329 rv = openPrefFile(mCurrentFile);
330 if (NS_FAILED(rv)) {
331 mDontWriteUserPrefs = NS_FAILED(MakeBackupPrefFile(mCurrentFile));
333 } else {
334 rv = NS_ERROR_FILE_NOT_FOUND;
337 return rv;
340 nsresult nsPrefService::SavePrefFileInternal(nsIFile *aFile)
342 if (nsnull == aFile) {
343 // the gDirty flag tells us if we should write to mCurrentFile
344 // we only check this flag when the caller wants to write to the default
345 if (!gDirty)
346 return NS_OK;
348 // It's possible that we never got a prefs file.
349 nsresult rv = NS_OK;
350 if (mCurrentFile)
351 rv = WritePrefFile(mCurrentFile);
353 return rv;
354 } else {
355 return WritePrefFile(aFile);
359 nsresult nsPrefService::WritePrefFile(nsIFile* aFile)
361 const char outHeader[] =
362 "# Mozilla User Preferences"
363 NS_LINEBREAK
364 NS_LINEBREAK
365 "/* Do not edit this file."
366 NS_LINEBREAK
367 " *"
368 NS_LINEBREAK
369 " * If you make changes to this file while the application is running,"
370 NS_LINEBREAK
371 " * the changes will be overwritten when the application exits."
372 NS_LINEBREAK
373 " *"
374 NS_LINEBREAK
375 " * To make a manual change to preferences, you can visit the URL about:config"
376 NS_LINEBREAK
377 " * For more information, see http://www.mozilla.org/unix/customizing.html#prefs"
378 NS_LINEBREAK
379 " */"
380 NS_LINEBREAK
381 NS_LINEBREAK;
383 nsCOMPtr<nsIOutputStream> outStreamSink;
384 nsCOMPtr<nsIOutputStream> outStream;
385 PRUint32 writeAmount;
386 nsresult rv;
388 if (!gHashTable.ops)
389 return NS_ERROR_NOT_INITIALIZED;
391 // Don't save user prefs if there was an error reading them and we failed
392 // to make a backup copy, since all prefs from the error line to the end of
393 // the file would be lost (bug 361102).
394 if (mDontWriteUserPrefs && aFile == mCurrentFile)
395 return NS_OK;
397 // execute a "safe" save by saving through a tempfile
398 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
399 aFile,
401 0600);
402 if (NS_FAILED(rv))
403 return rv;
404 rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
405 if (NS_FAILED(rv))
406 return rv;
408 char** valueArray = (char **)PR_Calloc(sizeof(char *), gHashTable.entryCount);
409 if (!valueArray)
410 return NS_ERROR_OUT_OF_MEMORY;
412 pref_saveArgs saveArgs;
413 saveArgs.prefArray = valueArray;
414 saveArgs.saveTypes = SAVE_ALL;
416 // get the lines that we're supposed to be writing to the file
417 PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
419 /* Sort the preferences to make a readable file on disk */
420 NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char *), pref_CompareStrings, NULL);
422 // write out the file header
423 outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
425 char** walker = valueArray;
426 for (PRUint32 valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) {
427 if (*walker) {
428 outStream->Write(*walker, strlen(*walker), &writeAmount);
429 outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
430 PR_Free(*walker);
433 PR_Free(valueArray);
435 // tell the safe output stream to overwrite the real prefs file
436 // (it'll abort if there were any errors during writing)
437 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
438 NS_ASSERTION(safeStream, "expected a safe output stream!");
439 if (safeStream) {
440 rv = safeStream->Finish();
441 if (NS_FAILED(rv)) {
442 NS_WARNING("failed to save prefs file! possible dataloss");
443 return rv;
447 gDirty = PR_FALSE;
448 return NS_OK;
451 static nsresult openPrefFile(nsIFile* aFile)
453 nsCOMPtr<nsIInputStream> inStr;
455 #if MOZ_TIMELINE
457 nsCAutoString str;
458 aFile->GetNativePath(str);
459 NS_TIMELINE_MARK_FUNCTION1("load pref file", str.get());
461 #endif
463 nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
464 if (NS_FAILED(rv))
465 return rv;
467 PRInt64 fileSize;
468 rv = aFile->GetFileSize(&fileSize);
469 if (NS_FAILED(rv))
470 return rv;
472 nsAutoArrayPtr<char> fileBuffer(new char[fileSize]);
473 if (fileBuffer == nsnull)
474 return NS_ERROR_OUT_OF_MEMORY;
476 PrefParseState ps;
477 PREF_InitParseState(&ps, PREF_ReaderCallback, NULL);
479 // Read is not guaranteed to return a buf the size of fileSize,
480 // but usually will.
481 nsresult rv2 = NS_OK;
482 for (;;) {
483 PRUint32 amtRead = 0;
484 rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead);
485 if (NS_FAILED(rv) || amtRead == 0)
486 break;
487 if (!PREF_ParseBuf(&ps, fileBuffer, amtRead))
488 rv2 = NS_ERROR_FILE_CORRUPTED;
491 PREF_FinalizeParseState(&ps);
493 return NS_FAILED(rv) ? rv : rv2;
497 * some stuff that gets called from Pref_Init()
500 static int
501 pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
503 nsCAutoString filename1, filename2;
504 aFile1->GetNativeLeafName(filename1);
505 aFile2->GetNativeLeafName(filename2);
507 return Compare(filename2, filename1);
511 * Load default pref files from a directory. The files in the
512 * directory are sorted reverse-alphabetically; a set of "special file
513 * names" may be specified which are loaded after all the others.
515 static nsresult
516 pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, PRUint32 aSpecialFilesCount)
518 nsresult rv, rv2;
519 PRBool hasMoreElements;
521 nsCOMPtr<nsISimpleEnumerator> dirIterator;
523 // this may fail in some normal cases, such as embedders who do not use a GRE
524 rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
525 if (NS_FAILED(rv)) {
526 // If the directory doesn't exist, then we have no reason to complain. We
527 // loaded everything (and nothing) successfully.
528 if (rv == NS_ERROR_FILE_NOT_FOUND)
529 rv = NS_OK;
530 return rv;
533 rv = dirIterator->HasMoreElements(&hasMoreElements);
534 NS_ENSURE_SUCCESS(rv, rv);
536 nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
537 nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
538 nsCOMPtr<nsIFile> prefFile;
540 while (hasMoreElements && NS_SUCCEEDED(rv)) {
541 nsCAutoString leafName;
543 rv = dirIterator->GetNext(getter_AddRefs(prefFile));
544 if (NS_FAILED(rv)) {
545 break;
548 prefFile->GetNativeLeafName(leafName);
549 NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
551 // Skip non-js files
552 if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
553 nsCaseInsensitiveCStringComparator())) {
554 PRBool shouldParse = PR_TRUE;
555 // separate out special files
556 for (PRUint32 i = 0; i < aSpecialFilesCount; ++i) {
557 if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
558 shouldParse = PR_FALSE;
559 // special files should be process in order; we put them into
560 // the array by index; this can make the array sparse
561 specialFiles.ReplaceObjectAt(prefFile, i);
565 if (shouldParse) {
566 prefFiles.AppendObject(prefFile);
570 rv = dirIterator->HasMoreElements(&hasMoreElements);
573 if (prefFiles.Count() + specialFiles.Count() == 0) {
574 NS_WARNING("No default pref files found.");
575 if (NS_SUCCEEDED(rv)) {
576 rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
578 return rv;
581 prefFiles.Sort(pref_CompareFileNames, nsnull);
583 PRUint32 arrayCount = prefFiles.Count();
584 PRUint32 i;
585 for (i = 0; i < arrayCount; ++i) {
586 rv2 = openPrefFile(prefFiles[i]);
587 if (NS_FAILED(rv2)) {
588 NS_ERROR("Default pref file not parsed successfully.");
589 rv = rv2;
593 arrayCount = specialFiles.Count();
594 for (i = 0; i < arrayCount; ++i) {
595 // this may be a sparse array; test before parsing
596 nsIFile* file = specialFiles[i];
597 if (file) {
598 rv2 = openPrefFile(file);
599 if (NS_FAILED(rv2)) {
600 NS_ERROR("Special default pref file not parsed successfully.");
601 rv = rv2;
606 return rv;
609 static nsresult pref_LoadPrefsInDirList(const char *listId)
611 nsresult rv;
612 nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
613 if (NS_FAILED(rv)) return rv;
615 nsCOMPtr<nsISimpleEnumerator> dirList;
616 dirSvc->Get(listId,
617 NS_GET_IID(nsISimpleEnumerator),
618 getter_AddRefs(dirList));
619 if (dirList) {
620 PRBool hasMore;
621 while (NS_SUCCEEDED(dirList->HasMoreElements(&hasMore)) && hasMore) {
622 nsCOMPtr<nsISupports> elem;
623 dirList->GetNext(getter_AddRefs(elem));
624 if (elem) {
625 nsCOMPtr<nsIFile> dir = do_QueryInterface(elem);
626 if (dir) {
627 // Do we care if a file provided by this process fails to load?
628 pref_LoadPrefsInDir(dir, nsnull, 0);
633 return NS_OK;
636 //----------------------------------------------------------------------------------------
637 // Initialize default preference JavaScript buffers from
638 // appropriate TEXT resources
639 //----------------------------------------------------------------------------------------
640 static nsresult pref_InitInitialObjects()
642 nsCOMPtr<nsIFile> aFile;
643 nsCOMPtr<nsIFile> defaultPrefDir;
644 nsresult rv;
646 // first we parse the GRE default prefs. This also works if we're not using a GRE,
648 rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(defaultPrefDir));
649 NS_ENSURE_SUCCESS(rv, rv);
651 rv = defaultPrefDir->AppendNative(NS_LITERAL_CSTRING("greprefs"));
652 NS_ENSURE_SUCCESS(rv, rv);
654 rv = pref_LoadPrefsInDir(defaultPrefDir, nsnull, 0);
655 if (NS_FAILED(rv)) {
656 NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
659 // now parse the "application" default preferences
660 rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
661 NS_ENSURE_SUCCESS(rv, rv);
663 /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
664 static const char* specialFiles[] = {
665 #if defined(XP_MAC) || defined(XP_MACOSX)
666 "macprefs.js"
667 #elif defined(XP_WIN)
668 "winpref.js"
669 #elif defined(XP_UNIX)
670 "unix.js"
671 #if defined(VMS)
672 , "openvms.js"
673 #elif defined(_AIX)
674 , "aix.js"
675 #endif
676 #if defined(MOZ_WIDGET_PHOTON)
677 , "photon.js"
678 #endif
679 #elif defined(XP_OS2)
680 "os2pref.js"
681 #elif defined(XP_BEOS)
682 "beos.js"
683 #endif
686 rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, NS_ARRAY_LENGTH(specialFiles));
687 if (NS_FAILED(rv)) {
688 NS_WARNING("Error parsing application default preferences.");
691 rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
692 NS_ENSURE_SUCCESS(rv, rv);
694 NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
695 nsnull, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
697 nsCOMPtr<nsIObserverService> observerService =
698 do_GetService("@mozilla.org/observer-service;1", &rv);
700 if (NS_FAILED(rv) || !observerService)
701 return rv;
703 observerService->NotifyObservers(nsnull, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nsnull);
705 return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);