2001-09-28 20:14:13 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
2001-03-22 23:34:41 +00:00
|
|
|
*
|
2001-09-28 20:14:13 +00:00
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/NPL/
|
2001-03-22 23:34:41 +00:00
|
|
|
*
|
2001-09-28 20:14:13 +00:00
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
2001-03-22 23:34:41 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
2001-09-28 20:14:13 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
2001-03-22 23:34:41 +00:00
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Alec Flett <alecf@netscape.com>
|
2001-09-28 20:14:13 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the NPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the NPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2001-03-22 23:34:41 +00:00
|
|
|
|
|
|
|
#include "nsPrefService.h"
|
|
|
|
#include "jsapi.h"
|
2001-10-08 19:52:17 +00:00
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
|
|
#include "nsDirectoryServiceDefs.h"
|
2001-12-21 22:29:31 +00:00
|
|
|
#include "nsICategoryManager.h"
|
2002-04-16 18:48:19 +00:00
|
|
|
#include "nsIFile.h"
|
2001-12-11 22:19:53 +00:00
|
|
|
#include "nsIFileStreams.h"
|
2002-04-27 05:33:09 +00:00
|
|
|
#include "nsILocalFile.h"
|
2001-03-22 23:34:41 +00:00
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsPrefBranch.h"
|
|
|
|
#include "nsXPIDLString.h"
|
|
|
|
|
|
|
|
#include "nsQuickSort.h"
|
2001-10-08 19:52:17 +00:00
|
|
|
#include "prmem.h"
|
2001-12-04 01:52:44 +00:00
|
|
|
#include "pldhash.h"
|
2001-10-08 19:52:17 +00:00
|
|
|
|
2001-03-22 23:34:41 +00:00
|
|
|
#include "prefapi.h"
|
|
|
|
#include "prefapi_private_data.h"
|
|
|
|
|
|
|
|
// supporting PREF_Init()
|
|
|
|
#include "nsIJSRuntimeService.h"
|
|
|
|
|
2001-11-27 01:39:09 +00:00
|
|
|
#include "nsITimelineService.h"
|
|
|
|
|
2001-03-22 23:34:41 +00:00
|
|
|
// Definitions
|
|
|
|
#define INITIAL_MAX_DEFAULT_PREF_FILES 10
|
|
|
|
|
2001-10-08 19:52:17 +00:00
|
|
|
|
2001-03-22 23:34:41 +00:00
|
|
|
// Prototypes
|
2001-12-21 22:29:31 +00:00
|
|
|
static nsresult openPrefFile(nsIFile* aFile, PRBool aIsErrorFatal,
|
|
|
|
PRBool aIsGlobalContext, PRBool aSkipFirstLine);
|
2001-03-22 23:34:41 +00:00
|
|
|
|
|
|
|
|
2001-08-03 02:35:32 +00:00
|
|
|
// needed so we can still get the JS Runtime Service during XPCOM shutdown
|
|
|
|
static nsIJSRuntimeService* gJSRuntimeService = nsnull; // owning reference
|
|
|
|
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-03-29 00:48:30 +00:00
|
|
|
/*
|
|
|
|
* Constructor/Destructor
|
|
|
|
*/
|
2001-03-22 23:34:41 +00:00
|
|
|
|
|
|
|
nsPrefService::nsPrefService()
|
2001-03-29 00:48:30 +00:00
|
|
|
: mCurrentFile(nsnull)
|
2001-03-22 23:34:41 +00:00
|
|
|
{
|
|
|
|
nsPrefBranch *rootBranch;
|
|
|
|
|
|
|
|
NS_INIT_REFCNT();
|
|
|
|
|
2001-04-24 20:32:16 +00:00
|
|
|
rootBranch = new nsPrefBranch("", PR_FALSE);
|
2001-03-22 23:34:41 +00:00
|
|
|
mRootBranch = (nsIPrefBranch *)rootBranch;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
nsPrefService::~nsPrefService()
|
|
|
|
{
|
|
|
|
PREF_Cleanup();
|
2001-04-18 05:18:47 +00:00
|
|
|
NS_IF_RELEASE(mCurrentFile);
|
2001-08-03 02:35:32 +00:00
|
|
|
NS_IF_RELEASE(gJSRuntimeService);
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
|
2001-03-29 00:48:30 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* nsISupports Implementation
|
|
|
|
*/
|
|
|
|
|
|
|
|
NS_IMPL_THREADSAFE_ADDREF(nsPrefService)
|
|
|
|
NS_IMPL_THREADSAFE_RELEASE(nsPrefService)
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsPrefService)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIPrefService)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
|
2001-04-03 20:11:54 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
|
2001-06-19 01:40:19 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
2001-03-29 00:48:30 +00:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nsIPrefService Implementation
|
|
|
|
*/
|
|
|
|
|
2001-04-03 20:11:54 +00:00
|
|
|
nsresult nsPrefService::Init()
|
2001-03-22 23:34:41 +00:00
|
|
|
{
|
2001-12-21 22:29:31 +00:00
|
|
|
nsXPIDLCString lockFileName;
|
2001-09-05 18:22:10 +00:00
|
|
|
nsresult rv;
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-09-05 18:22:10 +00:00
|
|
|
if (!PREF_Init(nsnull))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2001-12-21 22:29:31 +00:00
|
|
|
/*
|
|
|
|
* The following is a small hack which will allow us to only load the library
|
|
|
|
* which supports the netscape.cfg file if the preference is defined. We
|
|
|
|
* test for the existence of the pref, set in the all.js (mozilla) or
|
|
|
|
* all-ns.js (netscape 6), and if it exists we startup the pref config
|
|
|
|
* category which will do the rest.
|
|
|
|
*/
|
|
|
|
|
|
|
|
rv = mRootBranch->GetCharPref("general.config.filename", getter_Copies(lockFileName));
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
NS_CreateServicesFromCategory("pref-config-startup",
|
|
|
|
NS_STATIC_CAST(nsISupports *, NS_STATIC_CAST(void *, this)),
|
|
|
|
"pref-config-startup");
|
2001-09-05 18:22:10 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> observerService =
|
2001-10-22 22:01:27 +00:00
|
|
|
do_GetService("@mozilla.org/observer-service;1", &rv);
|
2001-09-05 18:22:10 +00:00
|
|
|
if (observerService) {
|
2001-10-19 20:52:59 +00:00
|
|
|
rv = observerService->AddObserver(this, "profile-before-change", PR_TRUE);
|
2001-09-05 18:22:10 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2001-10-19 20:52:59 +00:00
|
|
|
rv = observerService->AddObserver(this, "profile-do-change", PR_TRUE);
|
2002-04-23 00:50:24 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = observerService->AddObserver(this, "session-logout", PR_TRUE);
|
|
|
|
}
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return(rv);
|
|
|
|
}
|
|
|
|
|
2001-10-19 20:52:59 +00:00
|
|
|
NS_IMETHODIMP nsPrefService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
|
2001-03-22 23:34:41 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
2001-10-19 20:52:59 +00:00
|
|
|
if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
|
2001-10-23 22:07:29 +00:00
|
|
|
if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
|
2001-03-22 23:34:41 +00:00
|
|
|
if (mCurrentFile) {
|
2001-07-24 18:38:25 +00:00
|
|
|
mCurrentFile->Remove(PR_FALSE);
|
2001-03-22 23:34:41 +00:00
|
|
|
NS_RELEASE(mCurrentFile);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rv = SavePrefFile(nsnull);
|
|
|
|
}
|
2001-10-19 20:52:59 +00:00
|
|
|
} else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
|
2001-03-22 23:34:41 +00:00
|
|
|
ResetUserPrefs();
|
|
|
|
rv = ReadUserPrefs(nsnull);
|
2002-04-23 00:50:24 +00:00
|
|
|
} else if (!nsCRT::strcmp(aTopic, "session-logout")) {
|
|
|
|
rv = SavePrefFile(nsnull);
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsPrefService::ReadUserPrefs(nsIFile *aFile)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (nsnull == aFile) {
|
2002-04-16 18:48:19 +00:00
|
|
|
rv = UseDefaultPrefFile(); // really should return a value...
|
2001-03-22 23:34:41 +00:00
|
|
|
if (NS_SUCCEEDED(rv))
|
2002-04-16 18:48:19 +00:00
|
|
|
UseUserPrefFile();
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2002-04-16 18:48:19 +00:00
|
|
|
NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
|
2001-12-21 22:29:31 +00:00
|
|
|
|
|
|
|
JS_MaybeGC(gMochaContext);
|
2001-03-22 23:34:41 +00:00
|
|
|
} else {
|
|
|
|
if (mCurrentFile == aFile)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
NS_IF_RELEASE(mCurrentFile);
|
|
|
|
mCurrentFile = aFile;
|
|
|
|
NS_ADDREF(mCurrentFile);
|
|
|
|
|
|
|
|
gErrorOpeningUserPrefs = PR_FALSE;
|
|
|
|
|
2001-12-21 22:29:31 +00:00
|
|
|
rv = openPrefFile(mCurrentFile, PR_TRUE, PR_FALSE, PR_TRUE);
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsPrefService::ResetPrefs()
|
|
|
|
{
|
2002-04-16 18:48:19 +00:00
|
|
|
NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
|
2001-03-22 23:34:41 +00:00
|
|
|
PREF_CleanupPrefs();
|
2001-09-05 18:22:10 +00:00
|
|
|
|
|
|
|
if (!PREF_Init(nsnull))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2001-12-21 22:29:31 +00:00
|
|
|
return NS_OK;
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsPrefService::ResetUserPrefs()
|
|
|
|
{
|
|
|
|
PREF_ClearAllUserPrefs();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsPrefService::SavePrefFile(nsIFile *aFile)
|
|
|
|
{
|
|
|
|
if (nsnull == aFile) {
|
2001-06-20 06:49:22 +00:00
|
|
|
// It's possible that we never got a prefs file.
|
2002-04-16 18:48:19 +00:00
|
|
|
return mCurrentFile ? WritePrefFile(mCurrentFile) : NS_OK;
|
2001-03-22 23:34:41 +00:00
|
|
|
} else {
|
2002-04-16 18:48:19 +00:00
|
|
|
return WritePrefFile(aFile);
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsPrefService::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
2001-10-08 19:52:17 +00:00
|
|
|
if ((nsnull != aPrefRoot) && (*aPrefRoot != '\0')) {
|
2001-04-18 05:18:47 +00:00
|
|
|
// TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
|
|
|
|
nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, PR_FALSE);
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-04-18 05:18:47 +00:00
|
|
|
rv = prefBranch->QueryInterface(NS_GET_IID(nsIPrefBranch), (void **)_retval);
|
|
|
|
} else {
|
|
|
|
// special case caching the default root
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(mRootBranch, &rv);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
*_retval = prefBranch;
|
|
|
|
NS_ADDREF(*_retval);
|
|
|
|
}
|
|
|
|
}
|
2001-03-22 23:34:41 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsPrefService::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
|
|
|
|
nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, PR_TRUE);
|
|
|
|
|
|
|
|
rv = prefBranch->QueryInterface(NS_GET_IID(nsIPrefBranch), (void **)_retval);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-04-03 20:11:54 +00:00
|
|
|
// Forward these methods through the nsIPrefBranchInternal headers
|
|
|
|
|
2001-10-22 20:54:48 +00:00
|
|
|
NS_IMETHODIMP nsPrefService::AddObserver(const char *aDomain, nsIObserver *aObserver, PRBool aHoldWeak)
|
2001-04-03 20:11:54 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPrefBranchInternal> prefBranch = do_QueryInterface(mRootBranch, &rv);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
2001-10-22 20:54:48 +00:00
|
|
|
rv = prefBranch->AddObserver(aDomain, aObserver, aHoldWeak);
|
2001-04-03 20:11:54 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsPrefService::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPrefBranchInternal> prefBranch = do_QueryInterface(mRootBranch, &rv);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
rv = prefBranch->RemoveObserver(aDomain, aObserver);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-16 18:48:19 +00:00
|
|
|
nsresult nsPrefService::NotifyServiceObservers(const char *aTopic)
|
2001-09-05 18:22:10 +00:00
|
|
|
{
|
2001-12-21 22:29:31 +00:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
|
|
do_GetService("@mozilla.org/observer-service;1", &rv);
|
|
|
|
|
|
|
|
if (NS_FAILED(rv) || !observerService)
|
2001-09-05 18:22:10 +00:00
|
|
|
return rv;
|
|
|
|
|
2001-12-21 22:29:31 +00:00
|
|
|
nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
|
|
|
|
observerService->NotifyObservers(subject, aTopic, nsnull);
|
2001-09-05 18:22:10 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-04-16 18:48:19 +00:00
|
|
|
nsresult nsPrefService::UseDefaultPrefFile()
|
2001-03-29 00:48:30 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIFile> aFile;
|
|
|
|
|
|
|
|
// Anything which calls NS_InitXPCOM will have this
|
|
|
|
rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
|
|
|
|
|
|
|
|
if (!aFile) {
|
|
|
|
// We know we have XPCOM directory services, but we might not have a provider which
|
|
|
|
// knows about NS_APP_PREFS_50_FILE. Put the file in NS_XPCOM_CURRENT_PROCESS_DIR.
|
|
|
|
rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(aFile));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
2002-05-07 23:07:19 +00:00
|
|
|
rv = aFile->AppendNative(NS_LITERAL_CSTRING("default_prefs.js"));
|
2001-03-29 00:48:30 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = ReadUserPrefs(aFile);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// need to save the prefs now
|
2001-12-21 22:29:31 +00:00
|
|
|
SavePrefFile(aFile);
|
2001-03-29 00:48:30 +00:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2002-04-16 18:48:19 +00:00
|
|
|
nsresult nsPrefService::UseUserPrefFile()
|
2001-03-29 00:48:30 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
nsCOMPtr<nsIFile> aFile;
|
|
|
|
|
|
|
|
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(aFile));
|
|
|
|
if (NS_SUCCEEDED(rv) && aFile) {
|
2002-05-07 23:07:19 +00:00
|
|
|
rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
|
2001-03-29 00:48:30 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2001-12-21 22:29:31 +00:00
|
|
|
rv = openPrefFile(aFile, PR_FALSE, PR_FALSE, PR_FALSE);
|
2001-03-29 00:48:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2002-04-16 18:48:19 +00:00
|
|
|
nsresult nsPrefService::WritePrefFile(nsIFile* aFile)
|
|
|
|
{
|
|
|
|
const char outHeader[] = "# Mozilla User Preferences"
|
|
|
|
NS_LINEBREAK
|
|
|
|
"// This is a generated file!"
|
|
|
|
NS_LINEBREAK
|
|
|
|
NS_LINEBREAK;
|
|
|
|
nsCOMPtr<nsIOutputStream> outStream;
|
|
|
|
PRUint32 writeAmount;
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (!gHashTable.ops)
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
|
|
|
|
/* ?! Don't save (blank) user prefs if there was an error reading them */
|
|
|
|
if (gErrorOpeningUserPrefs)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
char** valueArray = (char**) PR_Calloc(sizeof(char*), gHashTable.entryCount);
|
|
|
|
if (!valueArray)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), aFile);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
// write out the file header
|
|
|
|
rv = outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
|
|
|
|
|
|
|
|
// get the lines that we're supposed to be writing to the file
|
|
|
|
PL_DHashTableEnumerate(&gHashTable, pref_savePref, valueArray);
|
|
|
|
|
|
|
|
/* Sort the preferences to make a readable file on disk */
|
|
|
|
NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char*), pref_CompareStrings, NULL);
|
|
|
|
char** walker = valueArray;
|
|
|
|
for (PRUint32 valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) {
|
|
|
|
if (*walker) {
|
|
|
|
// skip writing if an has error occurred
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = outStream->Write(*walker, strlen(*walker), &writeAmount);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
rv = outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
|
|
|
|
}
|
|
|
|
// always free though...
|
|
|
|
PR_Free(*walker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PR_Free(valueArray);
|
|
|
|
outStream->Close();
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2001-12-21 22:29:31 +00:00
|
|
|
static nsresult openPrefFile(nsIFile* aFile, PRBool aIsErrorFatal,
|
|
|
|
PRBool aIsGlobalContext, PRBool aSkipFirstLine)
|
2001-03-22 23:34:41 +00:00
|
|
|
{
|
2001-12-11 22:19:53 +00:00
|
|
|
nsCOMPtr<nsIInputStream> inStr;
|
|
|
|
char *readBuf;
|
|
|
|
PRInt64 llFileSize;
|
|
|
|
PRUint32 fileSize;
|
2001-03-22 23:34:41 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
2001-11-27 01:39:09 +00:00
|
|
|
#if MOZ_TIMELINE
|
2001-12-11 22:19:53 +00:00
|
|
|
{
|
2002-04-27 05:33:09 +00:00
|
|
|
nsCAutoString str;
|
|
|
|
aFile->GetNativePath(str);
|
2001-12-11 22:19:53 +00:00
|
|
|
NS_TIMELINE_MARK_FUNCTION1("load pref file", str.get());
|
|
|
|
}
|
2001-11-27 01:39:09 +00:00
|
|
|
#endif
|
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
rv = aFile->GetFileSize(&llFileSize);
|
2001-03-22 23:34:41 +00:00
|
|
|
if (NS_FAILED(rv))
|
2001-12-11 22:19:53 +00:00
|
|
|
return rv;
|
|
|
|
LL_L2UI(fileSize, llFileSize); // Converting 64 bit structure to unsigned int
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
readBuf = (char *)PR_Malloc(fileSize);
|
|
|
|
if (!readBuf)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
JS_BeginRequest(gMochaContext);
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
PRUint32 amtRead = 0;
|
|
|
|
rv = inStr->Read(readBuf, fileSize, &amtRead);
|
|
|
|
NS_ASSERTION((amtRead == fileSize), "failed to read the entire prefs file!!");
|
2001-03-22 23:34:41 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2001-12-11 22:19:53 +00:00
|
|
|
if (!PREF_EvaluateConfigScript(readBuf, amtRead, nsnull, aIsGlobalContext, PR_TRUE,
|
2001-03-22 23:34:41 +00:00
|
|
|
aSkipFirstLine))
|
|
|
|
{
|
|
|
|
rv = NS_ERROR_FAILURE;
|
2001-12-11 22:19:53 +00:00
|
|
|
if (aIsErrorFatal)
|
|
|
|
// If the user prefs file exists but generates an error,
|
|
|
|
// don't clobber the file when we try to save it
|
|
|
|
gErrorOpeningUserPrefs = PR_TRUE;
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
PR_Free(readBuf);
|
2001-12-11 22:19:53 +00:00
|
|
|
JS_EndRequest(gMochaContext);
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
return rv;
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* some stuff that gets called from Pref_Init()
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// Note: inplaceSortCallback is a small C callback stub for NS_QuickSort
|
|
|
|
static int PR_CALLBACK
|
|
|
|
inplaceSortCallback(const void *data1, const void *data2, void *privateData)
|
|
|
|
{
|
2002-04-27 05:33:09 +00:00
|
|
|
nsCAutoString name1;
|
|
|
|
nsCAutoString name2;
|
2001-12-11 22:19:53 +00:00
|
|
|
nsIFile *file1= *(nsIFile **)data1;
|
|
|
|
nsIFile *file2= *(nsIFile **)data2;
|
2001-03-22 23:34:41 +00:00
|
|
|
nsresult rv;
|
|
|
|
int sortResult = 0;
|
|
|
|
|
2002-04-27 05:33:09 +00:00
|
|
|
rv = file1->GetNativeLeafName(name1);
|
2001-03-22 23:34:41 +00:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get the leaf name");
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2002-04-27 05:33:09 +00:00
|
|
|
rv = file2->GetNativeLeafName(name2);
|
2001-03-22 23:34:41 +00:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get the leaf name");
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2002-04-27 05:33:09 +00:00
|
|
|
if (!name1.IsEmpty() && !name2.IsEmpty()) {
|
2001-03-22 23:34:41 +00:00
|
|
|
// we want it so foo.js will come before foo-<bar>.js
|
|
|
|
// "foo." is before "foo-", so we have to reverse the order to accomplish
|
2002-04-27 05:33:09 +00:00
|
|
|
sortResult = Compare(name2, name1); // XXX i18n
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sortResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
2001-12-11 22:41:19 +00:00
|
|
|
JSBool pref_InitInitialObjects()
|
2001-03-22 23:34:41 +00:00
|
|
|
// Initialize default preference JavaScript buffers from
|
|
|
|
// appropriate TEXT resources
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIFile> aFile;
|
2001-12-11 22:19:53 +00:00
|
|
|
nsCOMPtr<nsIFile> defaultPrefDir;
|
|
|
|
nsresult rv;
|
|
|
|
PRBool hasMoreElements;
|
2001-03-22 23:34:41 +00:00
|
|
|
|
|
|
|
static const char* specialFiles[] = {
|
|
|
|
#ifdef XP_MAC
|
2002-04-16 18:48:19 +00:00
|
|
|
"macprefs.js"
|
2002-03-16 02:01:38 +00:00
|
|
|
#if defined (TARGET_CARBON)
|
|
|
|
, "macxprefs.js"
|
|
|
|
#endif
|
2001-03-22 23:34:41 +00:00
|
|
|
#elif defined(XP_WIN)
|
2002-04-16 18:48:19 +00:00
|
|
|
"winpref.js"
|
2001-03-22 23:34:41 +00:00
|
|
|
#elif defined(XP_UNIX)
|
2002-04-16 18:48:19 +00:00
|
|
|
"unix.js"
|
2001-03-22 23:34:41 +00:00
|
|
|
#if defined(VMS)
|
|
|
|
, "openvms.js"
|
|
|
|
#endif
|
2001-10-18 13:46:18 +00:00
|
|
|
#if defined(MOZ_WIDGET_PHOTON)
|
|
|
|
, "photon.js"
|
|
|
|
#endif
|
2001-03-22 23:34:41 +00:00
|
|
|
#elif defined(XP_OS2)
|
2002-04-16 18:48:19 +00:00
|
|
|
"os2pref.js"
|
|
|
|
#elif defined(XP_BEOS)
|
|
|
|
"beos.js"
|
2001-03-22 23:34:41 +00:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
nsIFile **defaultPrefFiles = (nsIFile **)nsMemory::Alloc(INITIAL_MAX_DEFAULT_PREF_FILES * sizeof(nsIFile *));
|
2001-03-22 23:34:41 +00:00
|
|
|
int maxDefaultPrefFiles = INITIAL_MAX_DEFAULT_PREF_FILES;
|
|
|
|
int numFiles = 0;
|
|
|
|
|
|
|
|
// Parse all the random files that happen to be in the components directory.
|
2001-12-11 22:19:53 +00:00
|
|
|
nsCOMPtr<nsISimpleEnumerator> dirIterator;
|
|
|
|
rv = defaultPrefDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
|
|
|
|
if (!dirIterator) {
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "ERROR: Could not make a directory iterator.");
|
2001-03-22 23:34:41 +00:00
|
|
|
return JS_FALSE;
|
2001-12-11 22:19:53 +00:00
|
|
|
}
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
dirIterator->HasMoreElements(&hasMoreElements);
|
|
|
|
if (!hasMoreElements) {
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "ERROR: Prefs directory is empty.");
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
while (hasMoreElements) {
|
2001-03-22 23:34:41 +00:00
|
|
|
PRBool shouldParse = PR_TRUE;
|
2002-04-27 05:33:09 +00:00
|
|
|
nsCAutoString leafName;
|
2001-12-11 22:19:53 +00:00
|
|
|
|
|
|
|
dirIterator->GetNext(getter_AddRefs(aFile));
|
|
|
|
dirIterator->HasMoreElements(&hasMoreElements);
|
|
|
|
|
2002-04-27 05:33:09 +00:00
|
|
|
rv = aFile->GetNativeLeafName(leafName);
|
2001-12-11 22:19:53 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2001-03-22 23:34:41 +00:00
|
|
|
// Skip non-js files
|
2002-04-27 05:33:09 +00:00
|
|
|
if ((leafName.Length() < 3) || !Substring(leafName, leafName.Length() - 3, 3).Equals(NS_LITERAL_CSTRING(".js")))
|
2001-03-22 23:34:41 +00:00
|
|
|
shouldParse = PR_FALSE;
|
|
|
|
// Skip files in the special list.
|
2001-12-11 22:19:53 +00:00
|
|
|
if (shouldParse) {
|
|
|
|
for (int j = 0; j < (int) (sizeof(specialFiles) / sizeof(char *)); j++)
|
2002-04-27 05:33:09 +00:00
|
|
|
if (!strcmp(leafName.get(), specialFiles[j]))
|
2001-03-22 23:34:41 +00:00
|
|
|
shouldParse = PR_FALSE;
|
|
|
|
}
|
2001-12-11 22:19:53 +00:00
|
|
|
if (shouldParse) {
|
|
|
|
rv = aFile->Clone(&(defaultPrefFiles[numFiles]));
|
|
|
|
if NS_SUCCEEDED(rv) {
|
|
|
|
++numFiles;
|
2001-03-22 23:34:41 +00:00
|
|
|
if (numFiles == maxDefaultPrefFiles) {
|
|
|
|
// double the size of the array
|
|
|
|
maxDefaultPrefFiles *= 2;
|
2001-12-11 22:19:53 +00:00
|
|
|
defaultPrefFiles = (nsIFile **)nsMemory::Realloc(defaultPrefFiles, maxDefaultPrefFiles * sizeof(nsIFile *));
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-12-11 22:19:53 +00:00
|
|
|
};
|
2001-03-22 23:34:41 +00:00
|
|
|
|
2001-12-11 22:19:53 +00:00
|
|
|
NS_QuickSort((void *)defaultPrefFiles, numFiles, sizeof(nsIFile *), inplaceSortCallback, nsnull);
|
|
|
|
|
|
|
|
int k;
|
|
|
|
for (k = 0; k < numFiles; k++) {
|
2001-12-21 22:29:31 +00:00
|
|
|
rv = openPrefFile(defaultPrefFiles[k], PR_FALSE, PR_FALSE, PR_FALSE);
|
2001-12-11 22:19:53 +00:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Config file not parsed successfully");
|
|
|
|
NS_RELEASE(defaultPrefFiles[k]);
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
nsMemory::Free(defaultPrefFiles);
|
|
|
|
|
2001-04-24 20:32:16 +00:00
|
|
|
// Finally, parse any other special files (platform-specific ones).
|
2002-04-16 18:48:19 +00:00
|
|
|
for (k = 0; k < (int) (sizeof(specialFiles) / sizeof(char *)); k++) {
|
2001-04-24 20:32:16 +00:00
|
|
|
// we must get the directory every time so we can append the child
|
|
|
|
// because SetLeafName will not work here.
|
2001-12-11 22:19:53 +00:00
|
|
|
rv = defaultPrefDir->Clone(getter_AddRefs(aFile));
|
2001-04-24 20:32:16 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2002-05-07 23:07:19 +00:00
|
|
|
rv = aFile->AppendNative(nsDependentCString(specialFiles[k]));
|
2001-03-22 23:34:41 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2001-12-21 22:29:31 +00:00
|
|
|
rv = openPrefFile(aFile, PR_FALSE, PR_FALSE, PR_FALSE);
|
2001-12-11 22:19:53 +00:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "<platform>.js was not parsed successfully");
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_MaybeGC(gMochaContext);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-03 23:04:29 +00:00
|
|
|
JSRuntime* PREF_GetJSRuntime()
|
2001-03-22 23:34:41 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
2001-08-03 02:35:32 +00:00
|
|
|
if (!gJSRuntimeService) {
|
|
|
|
rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
|
|
|
|
&gJSRuntimeService);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("nsJSRuntimeService is missing");
|
|
|
|
gJSRuntimeService = nsnull;
|
|
|
|
return nsnull;
|
2001-03-22 23:34:41 +00:00
|
|
|
}
|
|
|
|
}
|
2001-08-03 02:35:32 +00:00
|
|
|
|
|
|
|
JSRuntime* rt;
|
|
|
|
rv = gJSRuntimeService->GetRuntime(&rt);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
return rt;
|
2001-03-22 23:34:41 +00:00
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|