ltabb 8ed5afe62c Free the lizard
git-svn-id: svn://10.0.0.236/trunk@10 18797224-902f-48f8-a5cc-f745e15eee43
1998-03-28 02:44:41 +00:00

2221 lines
56 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "jsapi.h"
#include "xp_core.h"
#include "xp_mcom.h"
#include "xp_qsort.h"
#include <errno.h>
#include "prefldap.h"
#include "prefapi.h"
#if defined(XP_MAC) || defined(XP_UNIX)
#include "fe_proto.h"
#endif
#if defined(XP_WIN) || defined(XP_OS2)
#include "npapi.h"
#include "assert.h"
#define NOT_NULL(X) X
#define XP_ASSERT(X) assert(X)
#define LINEBREAK "\n"
#endif
#include "sechash.h"
#ifndef NSPR20
#include "prhash.h"
#else
#include "plhash.h"
#endif
#if defined(XP_MAC) && defined (__MWERKS__)
/* Can't get the xp people to fix warnings... */
#pragma require_prototypes off
#endif
JSTaskState * m_mochaTaskState = NULL;
JSContext * m_mochaContext = NULL;
JSObject * m_mochaPrefObject = NULL;
JSObject * m_GlobalConfigObject = NULL;
static char * m_filename = NULL;
static char * m_lifilename = NULL;
static struct CallbackNode* m_Callbacks = NULL;
static XP_Bool m_ErrorOpeningUserPrefs = FALSE;
static XP_Bool m_CallbacksEnabled = FALSE;
static XP_Bool m_IsAnyPrefLocked = FALSE;
static PRHashTable* m_HashTable = NULL;
/* LI_STUFF - PREF_LILOCAL here to flag prefs as transferable or not */
typedef enum { PREF_LOCKED = 1, PREF_USERSET = 2, PREF_CONFIG = 4,
PREF_STRING = 8, PREF_INT = 16, PREF_BOOL = 32,
PREF_LILOCAL = 64 } PrefType;
/* LI_STUFF PREF_SETLI here to flag prefs as transferable or not */
typedef enum { PREF_SETDEFAULT, PREF_SETUSER,
PREF_LOCK, PREF_SETCONFIG, PREF_SETLI } PrefAction;
#define PREF_IS_LOCKED(pref) ((pref)->flags & PREF_LOCKED)
#define PREF_IS_CONFIG(pref) ((pref)->flags & PREF_CONFIG)
#define PREF_HAS_USER_VALUE(pref) ((pref)->flags & PREF_USERSET)
#define PREF_HAS_LI_VALUE(pref) ((pref)->flags & PREF_LILOCAL) /* LI_STUFF */
typedef union
{
char* stringVal;
int32 intVal;
XP_Bool boolVal;
} PrefValue;
typedef struct
{
PrefValue defaultPref;
PrefValue userPref;
uint8 flags;
} PrefNode;
static JSBool pref_HashJSPref(unsigned int argc, jsval *argv, PrefAction action);
/* Hash table allocation */
PR_IMPLEMENT(void *)
pref_AllocTable(void *pool, size_t size)
{
return malloc(size);
}
PR_IMPLEMENT(void)
pref_FreeTable(void *pool, void *item)
{
free(item); /* free items? */
}
PR_IMPLEMENT(PRHashEntry *)
pref_AllocEntry(void *pool, const void *key)
{
return malloc(sizeof(PRHashEntry));
}
PR_IMPLEMENT(void)
pref_FreeEntry(void *pool, PRHashEntry *he, uint flag)
{
PrefNode *pref = (PrefNode *) he->value;
if (pref) {
if (pref->flags & PREF_STRING) {
XP_FREEIF(pref->defaultPref.stringVal);
XP_FREEIF(pref->userPref.stringVal);
}
XP_FREE(he->value);
}
if (flag == HT_FREE_ENTRY) {
XP_FREEIF((void *)he->key);
XP_FREE(he);
}
}
static PRHashAllocOps pref_HashAllocOps = {
pref_AllocTable, pref_FreeTable,
pref_AllocEntry, pref_FreeEntry
};
#include "prlink.h"
extern PRLibrary *pref_LoadAutoAdminLib(void);
PRLibrary *m_AutoAdminLib = NULL;
/* -- Privates */
struct CallbackNode {
char* domain;
PrefChangedFunc func;
void* data;
struct CallbackNode* next;
};
/* -- Prototypes */
int pref_DoCallback(const char* changed_pref);
int pref_OpenFile(const char* filename, XP_Bool is_error_fatal, XP_Bool verifyHash, XP_Bool bGlobalContext);
XP_Bool pref_VerifyLockFile(char* buf, long buflen);
int pref_GetCharPref(const char *pref_name, char * return_buffer, int * length, XP_Bool get_default);
int pref_CopyCharPref(const char *pref_name, char ** return_buffer, XP_Bool get_default);
int pref_GetIntPref(const char *pref_name,int32 * return_int, XP_Bool get_default);
int pref_GetBoolPref(const char *pref_name, XP_Bool * return_value, XP_Bool get_default);
JSBool PR_CALLBACK pref_BranchCallback(JSContext *cx, JSScript *script);
void pref_ErrorReporter(JSContext *cx, const char *message,JSErrorReport *report);
void pref_Alert(char* msg);
int pref_HashPref(const char *key, PrefValue value, PrefType type, PrefAction action);
/* -- Platform specific function extern */
#if !defined(XP_OS2)
extern JSBool pref_InitInitialObjects(void);
#endif
PRIVATE JSClass global_class = {
"global", 0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
};
JSBool PR_CALLBACK pref_NativeDefaultPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
JSBool PR_CALLBACK pref_NativeUserPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
JSBool PR_CALLBACK pref_NativeLockPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
JSBool PR_CALLBACK pref_NativeUnlockPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
JSBool PR_CALLBACK pref_NativeSetConfig(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
JSBool PR_CALLBACK pref_NativeGetPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
JSBool PR_CALLBACK pref_NativeGetLDAPAttr(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
/* LI_STUFF add nativelilocalpref */
JSBool PR_CALLBACK pref_NativeLILocalPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
/* LI_STUFF add NativeLIUserPref - does both lilocal and user at once */
JSBool PR_CALLBACK pref_NativeLIUserPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
JSBool PR_CALLBACK pref_NativeLIDefPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
/* LI_STUFF added localPref pref_NativeLILocalPref, 1 */
PRIVATE JSFunctionSpec autoconf_methods[] = {
{ "pref", pref_NativeDefaultPref, 2 },
{ "defaultPref", pref_NativeDefaultPref, 2 },
{ "user_pref", pref_NativeUserPref, 2 },
{ "lockPref", pref_NativeLockPref, 2 },
{ "unlockPref", pref_NativeUnlockPref, 1 },
{ "config", pref_NativeSetConfig, 2 },
{ "getPref", pref_NativeGetPref, 1 },
{ "getLDAPAttributes", pref_NativeGetLDAPAttr, 4 },
{ "localPref", pref_NativeLILocalPref, 1 },
{ "localUserPref", pref_NativeLIUserPref, 2 },
{ "localDefPref", pref_NativeLIDefPref, 2 },
{ NULL, NULL, 0 }
};
PRIVATE JSPropertySpec autoconf_props[] = {
{0}
};
PRIVATE JSClass autoconf_class = {
"PrefConfig", 0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
};
int pref_OpenFile(const char* filename, XP_Bool is_error_fatal, XP_Bool verifyHash, XP_Bool bGlobalContext)
{
int ok = PREF_ERROR;
XP_File fp;
XP_StatStruct stats;
long fileLength;
stats.st_size = 0;
if ( stat(filename, &stats) == -1 )
return PREF_ERROR;
fileLength = stats.st_size;
if (fileLength <= 1)
return PREF_ERROR;
fp = fopen(filename, "r");
if (fp) {
char* readBuf = (char *) malloc(fileLength * sizeof(char));
if (readBuf) {
fileLength = XP_FileRead(readBuf, fileLength, fp);
if ( verifyHash && pref_VerifyLockFile(readBuf, fileLength) == FALSE )
{
ok = PREF_BAD_LOCKFILE;
}
else if ( PREF_EvaluateConfigScript(readBuf, fileLength,
filename, bGlobalContext, FALSE ) == JS_TRUE )
{
ok = PREF_NOERROR;
}
free(readBuf);
}
XP_FileClose(fp);
/* If the user prefs file exists but generates an error,
don't clobber the file when we try to save it. */
if ((!readBuf || ok != PREF_NOERROR) && is_error_fatal)
m_ErrorOpeningUserPrefs = TRUE;
#ifdef XP_WIN
if (m_ErrorOpeningUserPrefs && is_error_fatal)
MessageBox(NULL,"Error in preference file (prefs.js). Default preferences will be used.","Netscape - Warning", MB_OK);
#endif
}
JS_GC(m_mochaContext);
return (ok);
}
/* Computes the MD5 hash of the given buffer (not including the first line)
and verifies the first line of the buffer expresses the correct hash in the form:
// xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
where each 'xx' is a hex value. */
XP_Bool pref_VerifyLockFile(char* buf, long buflen)
{
XP_Bool success = FALSE;
const int obscure_value = 7;
const long hash_length = 51; /* len = 48 chars of MD5 + // + EOL */
unsigned char digest[16];
char szHash[64];
/* Unobscure file by subtracting some value from every char. */
unsigned int i;
for (i = 0; i < buflen; i++) {
buf[i] -= obscure_value;
}
if (buflen >= hash_length) {
const unsigned char magic_key[] = "VonGloda5652TX75235ISBN";
unsigned char *pStart = (unsigned char*) buf + hash_length;
unsigned int len;
MD5Context * md5_cxt = MD5_NewContext();
MD5_Begin(md5_cxt);
/* start with the magic key */
MD5_Update(md5_cxt, magic_key, sizeof(magic_key));
MD5_Update(md5_cxt, pStart, buflen - hash_length);
MD5_End(md5_cxt, digest, &len, 16);
MD5_DestroyContext(md5_cxt, PR_TRUE);
XP_SPRINTF(szHash, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
(int)digest[0],(int)digest[1],(int)digest[2],(int)digest[3],
(int)digest[4],(int)digest[5],(int)digest[6],(int)digest[7],
(int)digest[8],(int)digest[9],(int)digest[10],(int)digest[11],
(int)digest[12],(int)digest[13],(int)digest[14],(int)digest[15]);
success = ( strncmp((const char*) buf + 3, szHash, hash_length - 4) == 0 );
}
/*
* Should return 'success', but since the MD5 code is stubbed out,
* just return 'TRUE' until we have a replacement.
*/
return TRUE;
}
PR_IMPLEMENT(int)
PREF_ReadLIJSFile(char *filename)
{
int ok;
if (filename) m_lifilename = strdup(filename);
ok = pref_OpenFile(filename, FALSE, FALSE, FALSE);
return ok;
}
PR_IMPLEMENT(int)
PREF_ReadUserJSFile(char *filename)
{
int ok = pref_OpenFile(filename, FALSE, FALSE, TRUE);
return ok;
}
PR_IMPLEMENT(int)
PREF_Init(char *filename)
{
JSBool ok = JS_TRUE;
/* --ML hash test */
if (!m_HashTable)
m_HashTable = PR_NewHashTable(2048, PR_HashString, PR_CompareStrings,
PR_CompareValues, &pref_HashAllocOps, NULL);
if (!m_HashTable)
return 0;
if (filename) m_filename = strdup(filename);
if (!m_mochaTaskState)
m_mochaTaskState = JS_Init((uint32) 0xffffffffL);
if (!m_mochaContext) {
m_mochaContext = JS_NewContext(m_mochaTaskState, 8192); /* ???? What size? */
if (!m_mochaContext) {
return 0;
}
JS_SetVersion(m_mochaContext, JSVERSION_1_2);
m_GlobalConfigObject = JS_NewObject(m_mochaContext, &global_class, NULL, NULL);
if (!m_GlobalConfigObject)
return 0;
if (!JS_InitStandardClasses(m_mochaContext, m_GlobalConfigObject))
return 0;
JS_SetBranchCallback(m_mochaContext, pref_BranchCallback);
JS_SetErrorReporter(m_mochaContext, NULL);
m_mochaPrefObject = JS_DefineObject(m_mochaContext, m_GlobalConfigObject,
"PrefConfig",
&autoconf_class,
NULL,
JSPROP_ENUMERATE|JSPROP_READONLY);
if (m_mochaPrefObject) {
if (!JS_DefineProperties(m_mochaContext,
m_mochaPrefObject,
autoconf_props)) {
return 0;
}
if (!JS_DefineFunctions(m_mochaContext,
m_mochaPrefObject,
autoconf_methods)) {
return 0;
}
}
#if !defined(XP_WIN) && !defined(XP_OS2)
ok = pref_InitInitialObjects();
#endif
}
if (ok && filename) {
ok = (JSBool) (pref_OpenFile(filename, TRUE, FALSE, FALSE) == PREF_NOERROR);
}
else if (!ok) {
m_ErrorOpeningUserPrefs = TRUE;
}
return ok;
}
PR_IMPLEMENT(int)
PREF_GetConfigContext(JSContext **js_context)
{
if (!js_context) return FALSE;
*js_context = NULL;
if (m_mochaContext)
*js_context = m_mochaContext;
return TRUE;
}
PR_IMPLEMENT(int)
PREF_GetGlobalConfigObject(JSObject **js_object)
{
if (!js_object) return FALSE;
*js_object = NULL;
if (m_GlobalConfigObject)
*js_object = m_GlobalConfigObject;
return TRUE;
}
PR_IMPLEMENT(int)
PREF_GetPrefConfigObject(JSObject **js_object)
{
if (!js_object) return FALSE;
*js_object = NULL;
if (m_mochaPrefObject)
*js_object = m_mochaPrefObject;
return TRUE;
}
/* Frees the callback list. */
PR_IMPLEMENT(void)
PREF_Cleanup()
{
struct CallbackNode* node = m_Callbacks;
struct CallbackNode* next_node;
while (node) {
next_node = node->next;
XP_FREE(node->domain);
XP_FREE(node);
node = next_node;
}
if (m_mochaContext) JS_DestroyContext(m_mochaContext);
if (m_mochaTaskState) JS_Finish(m_mochaTaskState);
m_mochaContext = NULL;
m_mochaTaskState = NULL;
if (m_HashTable)
PR_HashTableDestroy(m_HashTable);
}
PR_IMPLEMENT(int)
PREF_ReadLockFile(const char *filename)
{
/*
return pref_OpenFile(filename, FALSE, FALSE, TRUE);
Lock files are obscured, and the security code to read them has
been removed from the free source. So don't even try to read one.
This is benign: no one listens closely to this error return,
and no one mourns the missing lock file.
*/
return PREF_ERROR;
}
/* This is more recent than the below 3 routines which should be obsoleted */
PR_IMPLEMENT(JSBool)
PREF_EvaluateConfigScript(const char * js_buffer, size_t length,
const char* filename, XP_Bool bGlobalContext, XP_Bool bCallbacks)
{
JSBool ok;
jsval result;
JSObject* scope;
JSErrorReporter errReporter;
if (bGlobalContext)
scope = m_GlobalConfigObject;
else
scope = m_mochaPrefObject;
if (!m_mochaContext || !scope)
return JS_FALSE;
errReporter = JS_SetErrorReporter(m_mochaContext, pref_ErrorReporter);
m_CallbacksEnabled = bCallbacks;
ok = JS_EvaluateScript(m_mochaContext, scope,
js_buffer, length, filename, 0, &result);
m_CallbacksEnabled = TRUE; /* ?? want to enable after reading user/lock file */
JS_SetErrorReporter(m_mochaContext, errReporter);
return ok;
}
PR_IMPLEMENT(int)
PREF_EvaluateJSBuffer(const char * js_buffer, size_t length)
{
/* old routine that no longer triggers callbacks */
int ret;
ret = PREF_QuietEvaluateJSBuffer(js_buffer, length);
return ret;
}
PR_IMPLEMENT(int)
PREF_QuietEvaluateJSBuffer(const char * js_buffer, size_t length)
{
JSBool ok;
jsval result;
if (!m_mochaContext || !m_mochaPrefObject)
return PREF_NOT_INITIALIZED;
ok = JS_EvaluateScript(m_mochaContext, m_mochaPrefObject,
js_buffer, length, NULL, 0, &result);
/* Hey, this really returns a JSBool */
return ok;
}
PR_IMPLEMENT(int)
PREF_QuietEvaluateJSBufferWithGlobalScope(const char * js_buffer, size_t length)
{
JSBool ok;
jsval result;
if (!m_mochaContext || !m_GlobalConfigObject)
return PREF_NOT_INITIALIZED;
ok = JS_EvaluateScript(m_mochaContext, m_GlobalConfigObject,
js_buffer, length, NULL, 0, &result);
/* Hey, this really returns a JSBool */
return ok;
}
static char * str_escape(const char * original) {
const char *p;
char * ret_str, *q;
if (original == NULL)
return NULL;
ret_str = malloc(2*strlen(original) + 1); /* Paranoid worse case all slashes will free quickly */
for(p = original, q=ret_str ; *p; p++, q++)
switch(*p) {
case '\\':
q[0] = '\\';
q[1] = '\\';
q++;
break;
case '\"':
q[0] = '\\';
q[1] = '\"';
q++;
break;
default:
*q = *p;
break;
}
*q = 0;
return ret_str;
}
/*
// External calls
*/
PR_IMPLEMENT(int)
PREF_SetCharPref(const char *pref_name, const char *value)
{
PrefValue pref;
pref.stringVal = (char*) value;
return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
}
PR_IMPLEMENT(int)
PREF_SetIntPref(const char *pref_name, int32 value)
{
PrefValue pref;
pref.intVal = value;
return pref_HashPref(pref_name, pref, PREF_INT, PREF_SETUSER);
}
PR_IMPLEMENT(int)
PREF_SetBoolPref(const char *pref_name, XP_Bool value)
{
PrefValue pref;
pref.boolVal = value;
return pref_HashPref(pref_name, pref, PREF_BOOL, PREF_SETUSER);
}
#if !defined(XP_WIN) && !defined(XP_OS2)
extern char *EncodeBase64Buffer(char *subject, long size);
extern char *DecodeBase64Buffer(char *subject);
#else
/* temporary to make windows into a DLL...add a assert if used */
char *EncodeBase64Buffer(char *subject, long size)
{
assert(0);
}
char *DecodeBase64Buffer(char *subject)
{
assert(0);
}
#endif
PR_IMPLEMENT(int)
PREF_SetBinaryPref(const char *pref_name, void * value, long size)
{
char* buf = EncodeBase64Buffer(value, size);
if (buf) {
PrefValue pref;
pref.stringVal = buf;
return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
}
else
return PREF_ERROR;
}
PR_IMPLEMENT(int)
PREF_SetColorPref(const char *pref_name, uint8 red, uint8 green, uint8 blue)
{
char colstr[63];
PrefValue pref;
XP_SPRINTF( colstr, "#%02X%02X%02X", red, green, blue);
pref.stringVal = colstr;
return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
}
#define MYGetboolVal(rgb) ((uint8) ((rgb) >> 16))
#define MYGetGValue(rgb) ((uint8) (((uint16) (rgb)) >> 8))
#define MYGetRValue(rgb) ((uint8) (rgb))
PR_IMPLEMENT(int)
PREF_SetColorPrefDWord(const char *pref_name, uint32 colorref)
{
int red,green,blue;
char colstr[63];
PrefValue pref;
red = MYGetRValue(colorref);
green = MYGetGValue(colorref);
blue = MYGetboolVal(colorref);
XP_SPRINTF( colstr, "#%02X%02X%02X", red, green, blue);
pref.stringVal = colstr;
return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
}
PR_IMPLEMENT(int)
PREF_SetRectPref(const char *pref_name, int16 left, int16 top, int16 right, int16 bottom)
{
char rectstr[63];
PrefValue pref;
XP_SPRINTF( rectstr, "%d,%d,%d,%d", left, top, right, bottom);
pref.stringVal = rectstr;
return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
}
/*
// DEFAULT VERSIONS: Call internal with (set_default == TRUE)
*/
PR_IMPLEMENT(int)
PREF_SetDefaultCharPref(const char *pref_name,const char *value)
{
PrefValue pref;
pref.stringVal = (char*) value;
return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETDEFAULT);
}
PR_IMPLEMENT(int)
PREF_SetDefaultIntPref(const char *pref_name,int32 value)
{
PrefValue pref;
pref.intVal = value;
return pref_HashPref(pref_name, pref, PREF_INT, PREF_SETDEFAULT);
}
PR_IMPLEMENT(int)
PREF_SetDefaultBoolPref(const char *pref_name,XP_Bool value)
{
PrefValue pref;
pref.boolVal = value;
return pref_HashPref(pref_name, pref, PREF_BOOL, PREF_SETDEFAULT);
}
PR_IMPLEMENT(int)
PREF_SetDefaultBinaryPref(const char *pref_name,void * value,long size)
{
char* buf = EncodeBase64Buffer(value, size);
if (buf) {
PrefValue pref;
pref.stringVal = buf;
return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETDEFAULT);
}
else
return PREF_ERROR;
}
PR_IMPLEMENT(int)
PREF_SetDefaultColorPref(const char *pref_name, uint8 red, uint8 green, uint8 blue)
{
char colstr[63];
XP_SPRINTF( colstr, "#%02X%02X%02X", red, green, blue);
return PREF_SetDefaultCharPref(pref_name, colstr);
}
PR_IMPLEMENT(int)
PREF_SetDefaultRectPref(const char *pref_name, int16 left, int16 top, int16 right, int16 bottom)
{
char rectstr[63];
XP_SPRINTF( rectstr, "%d,%d,%d,%d", left, top, right, bottom);
return PREF_SetDefaultCharPref(pref_name, rectstr);
}
/* LI_STUFF this does the same as savePref except it omits the lilocal prefs from the file. */
PR_IMPLEMENT(int)
pref_saveLIPref(PRHashEntry *he, int i, void *arg)
{
char **prefArray = (char**) arg;
PrefNode *pref = (PrefNode *) he->value;
if (pref && PREF_HAS_USER_VALUE(pref) && !PREF_HAS_LI_VALUE(pref)) {
char buf[2048];
if (pref->flags & PREF_STRING) {
char *tmp_str = str_escape(pref->userPref.stringVal);
if (tmp_str) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", \"%s\");" LINEBREAK,
(char*) he->key, tmp_str);
XP_FREE(tmp_str);
}
}
else if (pref->flags & PREF_INT) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", %ld);" LINEBREAK,
(char*) he->key, (long) pref->userPref.intVal);
}
else if (pref->flags & PREF_BOOL) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", %s);" LINEBREAK, (char*) he->key,
(pref->userPref.boolVal) ? "true" : "false");
}
prefArray[i] = XP_STRDUP(buf);
} else if (pref && PREF_IS_LOCKED(pref) && !PREF_HAS_LI_VALUE(pref)) {
char buf[2048];
if (pref->flags & PREF_STRING) {
char *tmp_str = str_escape(pref->defaultPref.stringVal);
if (tmp_str) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", \"%s\");" LINEBREAK,
(char*) he->key, tmp_str);
XP_FREE(tmp_str);
}
}
else if (pref->flags & PREF_INT) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", %ld);" LINEBREAK,
(char*) he->key, (long) pref->defaultPref.intVal);
}
else if (pref->flags & PREF_BOOL) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", %s);" LINEBREAK, (char*) he->key,
(pref->defaultPref.boolVal) ? "true" : "false");
}
prefArray[i] = XP_STRDUP(buf);
}
return 0;
}
PR_IMPLEMENT(int)
pref_savePref(PRHashEntry *he, int i, void *arg)
{
char **prefArray = (char**) arg;
PrefNode *pref = (PrefNode *) he->value;
if (pref && PREF_HAS_USER_VALUE(pref)) {
char buf[2048];
if (pref->flags & PREF_STRING) {
char *tmp_str = str_escape(pref->userPref.stringVal);
if (tmp_str) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", \"%s\");" LINEBREAK,
(char*) he->key, tmp_str);
XP_FREE(tmp_str);
}
}
else if (pref->flags & PREF_INT) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", %ld);" LINEBREAK,
(char*) he->key, (long) pref->userPref.intVal);
}
else if (pref->flags & PREF_BOOL) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", %s);" LINEBREAK, (char*) he->key,
(pref->userPref.boolVal) ? "true" : "false");
}
prefArray[i] = XP_STRDUP(buf);
} else if (pref && PREF_IS_LOCKED(pref)) {
char buf[2048];
if (pref->flags & PREF_STRING) {
char *tmp_str = str_escape(pref->defaultPref.stringVal);
if (tmp_str) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", \"%s\");" LINEBREAK,
(char*) he->key, tmp_str);
XP_FREE(tmp_str);
}
}
else if (pref->flags & PREF_INT) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", %ld);" LINEBREAK,
(char*) he->key, (long) pref->defaultPref.intVal);
}
else if (pref->flags & PREF_BOOL) {
PR_snprintf(buf, 2048, "user_pref(\"%s\", %s);" LINEBREAK, (char*) he->key,
(pref->defaultPref.boolVal) ? "true" : "false");
}
prefArray[i] = XP_STRDUP(buf);
}
/* LI_STUFF?? may need to write out the lilocal stuff here if it applies - probably won't support in
the prefs.js file. We won't need to worry about the user.js since it is read only.
*/
return 0;
}
PR_IMPLEMENT(int)
pref_CompareStrings (const void *v1, const void *v2)
{
char *s1 = *(char**) v1;
char *s2 = *(char**) v2;
if (!s1)
{
if (!s2)
return 0;
else
return -1;
}
else if (!s2)
return 1;
else
return strcmp(s1, s2);
}
/* LI_STUFF
this is new. clients should use the old PREF_SavePrefFile or new PREF_SaveLIPrefFile.
This is called by them and does the right thing.
?? make this private to this file.
*/
PR_IMPLEMENT(int)
PREF_SavePrefFileWith(const char *filename, PRHashEnumerator heSaveProc) {
int success = PREF_ERROR;
FILE * fp;
char **valueArray = NULL;
int valueIdx;
if (!m_HashTable)
return PREF_NOT_INITIALIZED;
/* ?! Don't save (blank) user prefs if there was an error reading them */
#if defined(XP_WIN) || defined(XP_OS2)
if (!filename)
#else
if (!filename || m_ErrorOpeningUserPrefs)
#endif
return PREF_NOERROR;
valueArray = (char**) XP_CALLOC(sizeof(char*), m_HashTable->nentries);
if (!valueArray)
return PREF_OUT_OF_MEMORY;
fp = fopen(filename, "w");
if (fp) {
XP_FileWrite("// Netscape User Preferences" LINEBREAK
"// This is a generated file! Do not edit." LINEBREAK LINEBREAK,
-1, fp);
/* LI_STUFF here we pass in the heSaveProc proc used so that li can do its own thing */
PR_HashTableEnumerateEntries(m_HashTable, heSaveProc, valueArray);
/* Sort the preferences to make a readable file on disk */
XP_QSORT (valueArray, m_HashTable->nentries, sizeof(char*), pref_CompareStrings);
for (valueIdx = 0; valueIdx < m_HashTable->nentries; valueIdx++)
{
if (valueArray[valueIdx])
{
XP_FileWrite(valueArray[valueIdx], -1, fp);
XP_FREE(valueArray[valueIdx]);
}
}
XP_FileClose(fp);
success = PREF_NOERROR;
}
else
success = errno;
XP_FREE(valueArray);
return success;
}
PR_IMPLEMENT(int)
PREF_SavePrefFile()
{
if (!m_HashTable)
return PREF_NOT_INITIALIZED;
return (PREF_SavePrefFileWith(m_filename, pref_savePref));
}
/* LI_STUFF Create a saveprefFile for LI for outsiders to call */
PR_IMPLEMENT(int)
PREF_SaveLIPrefFile(const char *filename)
{
if (!m_HashTable)
return PREF_NOT_INITIALIZED;
return (PREF_SavePrefFileWith(((filename) ? filename : m_lifilename), pref_saveLIPref));
}
/* LI_STUFF pass in the pref_savePref proc used instead of assuming it so that li can share that code too */
PR_IMPLEMENT(int)
PREF_SavePrefFileAs(const char *filename) {
return PREF_SavePrefFileWith(filename, pref_savePref);
}
int pref_GetCharPref(const char *pref_name, char * return_buffer, int * length, XP_Bool get_default)
{
int result = PREF_ERROR;
char* stringVal;
PrefNode* pref;
if (!m_HashTable)
return PREF_NOT_INITIALIZED;
pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
if (pref) {
if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
stringVal = pref->defaultPref.stringVal;
else
stringVal = pref->userPref.stringVal;
if (stringVal) {
if (*length == 0) {
*length = strlen(stringVal) + 1;
}
else {
strncpy(return_buffer, stringVal, PR_MIN(*length - 1, strlen(stringVal) + 1));
return_buffer[*length - 1] = '\0';
}
result = PREF_OK;
}
}
return result;
}
int pref_CopyCharPref(const char *pref_name, char ** return_buffer, XP_Bool get_default)
{
int result = PREF_ERROR;
char* stringVal;
PrefNode* pref;
if (!m_HashTable)
return PREF_NOT_INITIALIZED;
pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
if (pref && pref->flags & PREF_STRING) {
if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
stringVal = pref->defaultPref.stringVal;
else
stringVal = pref->userPref.stringVal;
if (stringVal) {
*return_buffer = XP_STRDUP(stringVal);
result = PREF_OK;
}
}
return result;
}
int pref_GetIntPref(const char *pref_name,int32 * return_int, XP_Bool get_default)
{
int result = PREF_ERROR;
PrefNode* pref;
if (!m_HashTable)
return PREF_NOT_INITIALIZED;
pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
if (pref && pref->flags & PREF_INT) {
if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
*return_int = pref->defaultPref.intVal;
else
*return_int = pref->userPref.intVal;
result = PREF_OK;
}
return result;
}
int pref_GetBoolPref(const char *pref_name, XP_Bool * return_value, XP_Bool get_default)
{
int result = PREF_ERROR;
PrefNode* pref;
if (!m_HashTable)
return PREF_NOT_INITIALIZED;
pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
if (pref && pref->flags & PREF_BOOL) {
if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
*return_value = pref->defaultPref.boolVal;
else
*return_value = pref->userPref.boolVal;
result = PREF_OK;
}
return result;
}
PR_IMPLEMENT(int)
PREF_GetCharPref(const char *pref_name, char * return_buffer, int * length)
{
return pref_GetCharPref(pref_name, return_buffer, length, FALSE);
}
PR_IMPLEMENT(int)
PREF_CopyCharPref(const char *pref_name, char ** return_buffer)
{
return pref_CopyCharPref(pref_name, return_buffer, FALSE);
}
PR_IMPLEMENT(int)
PREF_GetIntPref(const char *pref_name,int32 * return_int)
{
return pref_GetIntPref(pref_name, return_int, FALSE);
}
PR_IMPLEMENT(int)
PREF_GetBoolPref(const char *pref_name, XP_Bool * return_value)
{
return pref_GetBoolPref(pref_name, return_value, FALSE);
}
PR_IMPLEMENT(int)
PREF_GetColorPref(const char *pref_name, uint8 *red, uint8 *green, uint8 *blue)
{
char colstr[8];
int iSize = 8;
int result = PREF_GetCharPref(pref_name, colstr, &iSize);
if (result == PREF_NOERROR) {
int r, g, b;
sscanf(colstr, "#%02X%02X%02X", &r, &g, &b);
*red = r;
*green = g;
*blue = b;
}
return result;
}
#define MYRGB(r, g ,b) ((uint32) (((uint8) (r) | ((uint16) (g) << 8)) | (((uint32) (uint8) (b)) << 16)))
PR_IMPLEMENT(int)
PREF_GetColorPrefDWord(const char *pref_name, uint32 *colorref)
{
char colstr[8];
int iSize = 8;
uint8 red, green, blue;
int result = PREF_GetCharPref(pref_name, colstr, &iSize);
if (result == 0) {
int r, g, b;
sscanf(colstr, "#%02X%02X%02X", &r, &g, &b);
red = r;
green = g;
blue = b;
}
*colorref = MYRGB(red,green,blue);
return result;
}
PR_IMPLEMENT(int)
PREF_GetRectPref(const char *pref_name, int16 *left, int16 *top, int16 *right, int16 *bottom)
{
char rectstr[64];
int iSize=64;
int result = PREF_GetCharPref(pref_name, rectstr, &iSize);
if (result == PREF_NOERROR) {
int l, t, r, b;
sscanf(rectstr, "%i,%i,%i,%i", &l, &t, &r, &b);
*left = l; *top = t;
*right = r; *bottom = b;
}
return result;
}
PR_IMPLEMENT(int)
PREF_GetBinaryPref(const char *pref_name, void * return_value, int *size)
{
char* buf;
int result;
if (!m_mochaPrefObject || !return_value) return -1;
result = PREF_CopyCharPref(pref_name, &buf);
if (result == PREF_NOERROR) {
char* debuf;
if (strlen(buf) == 0) { /* don't decode empty string ? */
XP_FREE(buf);
return -1;
}
debuf = DecodeBase64Buffer(buf);
XP_MEMCPY(return_value, debuf, *size);
XP_FREE(buf);
XP_FREE(debuf);
}
return result;
}
typedef int (*CharPrefReadFunc)(const char*, char**);
static int
ReadCharPrefUsing(const char *pref_name, void** return_value, int *size, CharPrefReadFunc inFunc)
{
char* buf;
int result;
if (!m_mochaPrefObject || !return_value)
return -1;
*return_value = NULL;
result = inFunc(pref_name, &buf);
if (result == PREF_NOERROR) {
if (strlen(buf) == 0) { /* do not decode empty string? */
XP_FREE(buf);
return -1;
}
*return_value = DecodeBase64Buffer(buf);
*size = strlen(buf);
XP_FREE(buf);
}
return result;
}
PR_IMPLEMENT(int)
PREF_CopyBinaryPref(const char *pref_name, void ** return_value, int *size)
{
return ReadCharPrefUsing(pref_name, return_value, size, PREF_CopyCharPref);
}
PR_IMPLEMENT(int)
PREF_CopyDefaultBinaryPref(const char *pref_name, void ** return_value, int *size)
{
return ReadCharPrefUsing(pref_name, return_value, size, PREF_CopyDefaultCharPref);
}
#ifndef XP_MAC
PR_IMPLEMENT(int)
PREF_CopyPathPref(const char *pref_name, char ** return_buffer)
{
return PREF_CopyCharPref(pref_name, return_buffer);
}
PR_IMPLEMENT(int)
PREF_SetPathPref(const char *pref_name, const char *path, XP_Bool set_default)
{
PrefAction action = set_default ? PREF_SETDEFAULT : PREF_SETUSER;
PrefValue pref;
pref.stringVal = (char*) path;
return pref_HashPref(pref_name, pref, PREF_STRING, action);
}
#endif /* XP_MAC */
PR_IMPLEMENT(int)
PREF_GetDefaultCharPref(const char *pref_name, char * return_buffer, int * length)
{
return pref_GetCharPref(pref_name, return_buffer, length, TRUE);
}
PR_IMPLEMENT(int)
PREF_CopyDefaultCharPref(const char *pref_name, char ** return_buffer)
{
return pref_CopyCharPref(pref_name, return_buffer, TRUE);
}
PR_IMPLEMENT(int)
PREF_GetDefaultIntPref(const char *pref_name, int32 * return_int)
{
return pref_GetIntPref(pref_name, return_int, TRUE);
}
PR_IMPLEMENT(int)
PREF_GetDefaultBoolPref(const char *pref_name, XP_Bool * return_value)
{
return pref_GetBoolPref(pref_name, return_value, TRUE);
}
PR_IMPLEMENT(int)
PREF_GetDefaultBinaryPref(const char *pref_name, void * return_value, int * length)
{
#ifdef XP_WIN
assert( FALSE );
#else
XP_ASSERT( FALSE );
#endif
return TRUE;
}
PR_IMPLEMENT(int)
PREF_GetDefaultColorPref(const char *pref_name, uint8 *red, uint8 *green, uint8 *blue)
{
char colstr[8];
int iSize = 8;
int result = PREF_GetDefaultCharPref(pref_name, colstr, &iSize);
if (result == PREF_NOERROR) {
int r, g, b;
sscanf(colstr, "#%02X%02X%02X", &r, &g, &b);
*red = r;
*green = g;
*blue = b;
}
return result;
}
PR_IMPLEMENT(int)
PREF_GetDefaultColorPrefDWord(const char *pref_name, uint32 * colorref)
{
char colstr[8];
int iSize = 8;
uint8 red, green, blue;
int result = PREF_GetDefaultCharPref(pref_name, colstr, &iSize);
if (result == PREF_NOERROR) {
int r, g, b;
sscanf(colstr, "#%02X%02X%02X", &r, &g, &b);
red = r;
green = g;
blue = b;
}
*colorref = MYRGB(red,green,blue);
return result;
}
PR_IMPLEMENT(int)
PREF_GetDefaultRectPref(const char *pref_name, int16 *left, int16 *top, int16 *right, int16 *bottom)
{
char rectstr[256];
int iLen = 256;
int result = PREF_GetDefaultCharPref(pref_name, (char *)&rectstr, &iLen);
if (result == PREF_NOERROR) {
sscanf(rectstr, "%d,%d,%d,%d", left, top, right, bottom);
}
return result;
}
/* Delete a branch. Used for deleting mime types */
PR_IMPLEMENT(int)
pref_DeleteItem(PRHashEntry *he, int i, void *arg)
{
const char *to_delete = (const char *) arg;
int len = strlen(to_delete);
/* note if we're deleting "ldap" then we want to delete "ldap.xxx"
and "ldap" (if such a leaf node exists) but not "ldap_1.xxx" */
if (to_delete && (XP_STRNCMP(he->key, to_delete, len) == 0 ||
(len-1 == strlen(he->key) && XP_STRNCMP(he->key, to_delete, len-1) == 0)))
return HT_ENUMERATE_REMOVE;
else
return HT_ENUMERATE_NEXT;
}
PR_IMPLEMENT(int)
PREF_DeleteBranch(const char *branch_name)
{
char* branch_dot = PR_smprintf("%s.", branch_name);
if (!branch_dot)
return PREF_OUT_OF_MEMORY;
PR_HashTableEnumerateEntries(m_HashTable, pref_DeleteItem, (void*) branch_dot);
XP_FREE(branch_dot);
return 0;
}
/* LI_STUFF add a function to clear the li pref
does anyone use this??
*/
PR_IMPLEMENT(int)
PREF_ClearLIPref(const char *pref_name)
{
int success = PREF_ERROR;
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
if (pref && PREF_HAS_LI_VALUE(pref)) {
pref->flags &= ~PREF_LILOCAL;
if (m_CallbacksEnabled)
pref_DoCallback(pref_name);
success = PREF_OK;
}
return success;
}
PR_IMPLEMENT(int)
PREF_ClearUserPref(const char *pref_name)
{
int success = PREF_ERROR;
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
if (pref && PREF_HAS_USER_VALUE(pref)) {
pref->flags &= ~PREF_USERSET;
if (m_CallbacksEnabled)
pref_DoCallback(pref_name);
success = PREF_OK;
}
return success;
}
/* Prototype Admin Kit support */
PR_IMPLEMENT(int)
PREF_GetConfigString(const char *obj_name, char * return_buffer, int size,
int index, const char *field)
{
#ifdef XP_WIN
assert( FALSE );
#else
XP_ASSERT( FALSE );
#endif
return -1;
}
/*
* Administration Kit support
*/
PR_IMPLEMENT(int)
PREF_CopyConfigString(const char *obj_name, char **return_buffer)
{
int success = PREF_ERROR;
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, obj_name);
if (pref && pref->flags & PREF_STRING) {
if (return_buffer)
*return_buffer = XP_STRDUP(pref->defaultPref.stringVal);
success = PREF_NOERROR;
}
return success;
}
PR_IMPLEMENT(int)
PREF_CopyIndexConfigString(const char *obj_name,
int index, const char *field, char **return_buffer)
{
int success = PREF_ERROR;
PrefNode* pref;
char* setup_buf = PR_smprintf("%s_%d.%s", obj_name, index, field);
pref = (PrefNode*) PR_HashTableLookup(m_HashTable, setup_buf);
if (pref && pref->flags & PREF_STRING) {
if (return_buffer)
*return_buffer = XP_STRDUP(pref->defaultPref.stringVal);
success = PREF_NOERROR;
}
XP_FREEIF(setup_buf);
return success;
}
PR_IMPLEMENT(int)
PREF_GetConfigInt(const char *obj_name, int32 *return_int)
{
int success = PREF_ERROR;
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, obj_name);
if (pref && pref->flags & PREF_INT) {
*return_int = pref->defaultPref.intVal;
success = PREF_NOERROR;
}
return success;
}
PR_IMPLEMENT(int)
PREF_GetConfigBool(const char *obj_name, XP_Bool *return_bool)
{
int success = PREF_ERROR;
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, obj_name);
if (pref && pref->flags & PREF_BOOL) {
*return_bool = pref->defaultPref.boolVal;
success = PREF_NOERROR;
}
return success;
}
/*
* Hash table functions
*/
static XP_Bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type)
{
XP_Bool changed = TRUE;
switch (type) {
case PREF_STRING:
if (oldValue.stringVal && newValue.stringVal)
changed = (strcmp(oldValue.stringVal, newValue.stringVal) != 0);
break;
case PREF_INT:
changed = oldValue.intVal != newValue.intVal;
break;
case PREF_BOOL:
changed = oldValue.boolVal != newValue.boolVal;
break;
}
return changed;
}
static void pref_SetValue(PrefValue* oldValue, PrefValue newValue, PrefType type)
{
switch (type) {
case PREF_STRING:
XP_ASSERT(newValue.stringVal);
XP_FREEIF(oldValue->stringVal);
oldValue->stringVal = newValue.stringVal ? XP_STRDUP(newValue.stringVal) : NULL;
break;
default:
*oldValue = newValue;
}
}
int pref_HashPref(const char *key, PrefValue value, PrefType type, PrefAction action)
{
PrefNode* pref;
int result = PREF_OK;
if (!m_HashTable)
return PREF_NOT_INITIALIZED;
pref = (PrefNode*) PR_HashTableLookup(m_HashTable, key);
if (!pref) {
pref = (PrefNode*) calloc(sizeof(PrefNode), 1);
if (!pref)
return PREF_OUT_OF_MEMORY;
pref->flags = type;
if (pref->flags & PREF_BOOL)
pref->defaultPref.boolVal = (XP_Bool) -2;
/* ugly hack -- define it to a default that no pref will ever default to
this should really get fixed right by some out of band data */
if (pref->flags & PREF_INT)
pref->defaultPref.intVal = (int32) -5632;
PR_HashTableAdd(m_HashTable, XP_STRDUP(key), pref);
}
else if (!(pref->flags & type)) {
XP_ASSERT(0); /* this shouldn't happen */
return PREF_TYPE_CHANGE_ERR;
}
switch (action) {
case PREF_SETDEFAULT:
case PREF_SETCONFIG:
if (!PREF_IS_LOCKED(pref)) { /* ?? change of semantics? */
if (pref_ValueChanged(pref->defaultPref, value, type)) {
pref_SetValue(&pref->defaultPref, value, type);
if (!PREF_HAS_USER_VALUE(pref))
result = PREF_VALUECHANGED;
}
}
if (action == PREF_SETCONFIG)
pref->flags |= PREF_CONFIG;
break;
/* LI_STUFF turn the li stuff on */
case PREF_SETLI:
if ( !PREF_HAS_LI_VALUE(pref) ||
pref_ValueChanged(pref->userPref, value, type) ) {
pref_SetValue(&pref->userPref, value, type);
pref->flags |= PREF_LILOCAL;
if (!PREF_IS_LOCKED(pref))
result = PREF_VALUECHANGED;
}
break;
case PREF_SETUSER:
/* If setting to the default value, then un-set the user value.
Otherwise, set the user value only if it has changed */
if ( !pref_ValueChanged(pref->defaultPref, value, type) ) {
if (PREF_HAS_USER_VALUE(pref)) {
pref->flags &= ~PREF_USERSET;
if (!PREF_IS_LOCKED(pref))
result = PREF_VALUECHANGED;
}
}
else if ( !PREF_HAS_USER_VALUE(pref) ||
pref_ValueChanged(pref->userPref, value, type) ) {
pref_SetValue(&pref->userPref, value, type);
pref->flags |= PREF_USERSET;
if (!PREF_IS_LOCKED(pref))
result = PREF_VALUECHANGED;
}
break;
case PREF_LOCK:
if (pref_ValueChanged(pref->defaultPref, value, type)) {
pref_SetValue(&pref->defaultPref, value, type);
result = PREF_VALUECHANGED;
}
else if (!PREF_IS_LOCKED(pref)) {
result = PREF_VALUECHANGED;
}
pref->flags |= PREF_LOCKED;
m_IsAnyPrefLocked = TRUE;
break;
}
if (result == PREF_VALUECHANGED && m_CallbacksEnabled) {
int result2 = pref_DoCallback(key);
if (result2 < 0)
result = result2;
}
return result;
}
PR_IMPLEMENT(int)
PREF_GetPrefType(const char *pref_name)
{
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
if (pref) {
if (pref->flags & PREF_STRING)
return PREF_STRING;
else if (pref->flags & PREF_INT)
return PREF_INT;
else if (pref->flags & PREF_BOOL)
return PREF_BOOL;
}
return PREF_ERROR;
}
JSBool PR_CALLBACK pref_NativeDefaultPref
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
return pref_HashJSPref(argc, argv, PREF_SETDEFAULT);
}
/* LI_STUFF here is the hookup with js prefs calls */
JSBool PR_CALLBACK pref_NativeLILocalPref
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
if (argc >= 1 && JSVAL_IS_STRING(argv[0])) {
const char *key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, key);
if (pref && !PREF_HAS_LI_VALUE(pref)) {
pref->flags |= PREF_LILOCAL;
if (m_CallbacksEnabled) {
pref_DoCallback(key);
}
}
}
return JS_TRUE;
}
/* combo li and user pref - save some time */
JSBool PR_CALLBACK pref_NativeLIUserPref
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
return (JSBool)(pref_HashJSPref(argc, argv, PREF_SETUSER) && pref_HashJSPref(argc, argv, PREF_SETLI));
}
/* combo li and user pref - save some time */
JSBool PR_CALLBACK pref_NativeLIDefPref
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
return (JSBool)(pref_HashJSPref(argc, argv, PREF_SETDEFAULT) && pref_HashJSPref(argc, argv, PREF_SETLI));
}
JSBool PR_CALLBACK pref_NativeUserPref
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
return pref_HashJSPref(argc, argv, PREF_SETUSER);
}
JSBool PR_CALLBACK pref_NativeLockPref
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
return pref_HashJSPref(argc, argv, PREF_LOCK);
}
JSBool PR_CALLBACK pref_NativeUnlockPref
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
if (argc >= 1 && JSVAL_IS_STRING(argv[0])) {
const char *key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, key);
if (pref && PREF_IS_LOCKED(pref)) {
pref->flags &= ~PREF_LOCKED;
if (m_CallbacksEnabled) {
pref_DoCallback(key);
}
}
}
return JS_TRUE;
}
JSBool PR_CALLBACK pref_NativeSetConfig
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
return pref_HashJSPref(argc, argv, PREF_SETCONFIG);
}
JSBool PR_CALLBACK pref_NativeGetPref
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
void* value = NULL;
PrefNode* pref;
XP_Bool prefExists = TRUE;
if (argc >= 1 && JSVAL_IS_STRING(argv[0]))
{
const char *key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
pref = (PrefNode*) PR_HashTableLookup(m_HashTable, key);
if (pref) {
XP_Bool use_default = (PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref));
if (pref->flags & PREF_STRING) {
char* str = use_default ? pref->defaultPref.stringVal : pref->userPref.stringVal;
JSString* jsstr = JS_NewStringCopyZ(cx, str);
*rval = STRING_TO_JSVAL(jsstr);
}
else if (pref->flags & PREF_INT) {
*rval = INT_TO_JSVAL(use_default ? pref->defaultPref.intVal : pref->userPref.intVal);
}
else if (pref->flags & PREF_BOOL) {
*rval = BOOLEAN_TO_JSVAL(use_default ? pref->defaultPref.boolVal : pref->userPref.boolVal);
}
}
}
return JS_TRUE;
}
/* -- */
PR_IMPLEMENT(XP_Bool)
PREF_PrefIsLocked(const char *pref_name)
{
XP_Bool result = FALSE;
if (m_IsAnyPrefLocked) {
PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
if (pref && PREF_IS_LOCKED(pref))
result = TRUE;
}
return result;
}
/*
* Creates an iterator over the children of a node.
*/
typedef struct
{
char* childList;
char* parent;
int bufsize;
} PrefChildIter;
/* if entry begins with the given string, i.e. if string is
"a"
and entry is
"a.b.c" or "a.b"
then add "a.b" to the list. */
PR_IMPLEMENT(int)
pref_addChild(PRHashEntry *he, int i, void *arg)
{
PrefChildIter* pcs = (PrefChildIter*) arg;
if ( XP_STRNCMP(he->key, pcs->parent, strlen(pcs->parent)) == 0 ) {
char buf[512];
char* nextdelim;
int parentlen = strlen(pcs->parent);
char* substring;
XP_Bool substringBordersSeparator = FALSE;
strncpy(buf, he->key, PR_MIN(512, strlen(he->key) + 1));
nextdelim = buf + parentlen;
if (parentlen < strlen(buf)) {
/* Find the next delimiter if any and truncate the string there */
nextdelim = strstr(nextdelim, ".");
if (nextdelim) {
*nextdelim = '\0';
}
}
substring = strstr(pcs->childList, buf);
if (substring)
{
int buflen = strlen(buf);
XP_ASSERT(substring[buflen] > 0);
substringBordersSeparator = (substring[buflen] == '\0' || substring[buflen] == ';');
}
if (!substring || !substringBordersSeparator) {
int newsize = strlen(pcs->childList) + strlen(buf) + 2;
#ifdef XP_WIN16
return HT_ENUMERATE_STOP;
#else
if (newsize > pcs->bufsize) {
pcs->bufsize *= 3;
pcs->childList = (char*) realloc(pcs->childList, sizeof(char) * pcs->bufsize);
if (!pcs->childList)
return HT_ENUMERATE_STOP;
}
#endif
XP_STRCAT(pcs->childList, buf);
XP_STRCAT(pcs->childList, ";");
}
}
return 0;
}
PR_IMPLEMENT(int)
PREF_CreateChildList(const char* parent_node, char **child_list)
{
PrefChildIter pcs;
#ifdef XP_WIN16
pcs.bufsize = 20480;
#else
pcs.bufsize = 2048;
#endif
pcs.childList = (char*) malloc(sizeof(char) * pcs.bufsize);
pcs.parent = PR_smprintf("%s.", parent_node);
if (!pcs.parent || !pcs.childList)
return PREF_OUT_OF_MEMORY;
pcs.childList[0] = '\0';
PR_HashTableEnumerateEntries(m_HashTable, pref_addChild, &pcs);
*child_list = pcs.childList;
XP_FREE(pcs.parent);
return (pcs.childList == NULL) ? PREF_OUT_OF_MEMORY : PREF_OK;
}
PR_IMPLEMENT(char*)
PREF_NextChild(char *child_list, int *index)
{
char* child = strtok(&child_list[*index], ";");
if (child)
*index += strlen(child) + 1;
return child;
}
/* Adds a node to the beginning of the callback list. */
PR_IMPLEMENT(void)
PREF_RegisterCallback(const char *pref_node,
PrefChangedFunc callback,
void * instance_data)
{
struct CallbackNode* node = (struct CallbackNode*) malloc(sizeof(struct CallbackNode));
if (node) {
node->domain = XP_STRDUP(pref_node);
node->func = callback;
node->data = instance_data;
node->next = m_Callbacks;
m_Callbacks = node;
}
return;
}
/* Deletes a node from the callback list. */
PR_IMPLEMENT(int)
PREF_UnregisterCallback(const char *pref_node,
PrefChangedFunc callback,
void * instance_data)
{
int result = PREF_ERROR;
struct CallbackNode* node = m_Callbacks;
struct CallbackNode* prev_node = NULL;
while (node != NULL)
{
if ( strcmp(node->domain, pref_node) == 0 &&
node->func == callback &&
node->data == instance_data )
{
struct CallbackNode* next_node = node->next;
if (prev_node)
prev_node->next = next_node;
else
m_Callbacks = next_node;
XP_FREE(node->domain);
XP_FREE(node);
node = next_node;
result = PREF_NOERROR;
}
else {
prev_node = node;
node = node->next;
}
}
return result;
}
int pref_DoCallback(const char* changed_pref)
{
int result = PREF_OK;
struct CallbackNode* node;
for (node = m_Callbacks; node != NULL; node = node->next)
{
if ( XP_STRNCMP(changed_pref, node->domain, strlen(node->domain)) == 0 ) {
int result2 = (*node->func) (changed_pref, node->data);
if (result2 != PREF_OK)
result = result2;
}
}
return result;
}
/* !! Front ends need to implement */
#ifndef XP_MAC
PR_IMPLEMENT(XP_Bool)
PREF_IsAutoAdminEnabled()
{
if (m_AutoAdminLib == NULL)
m_AutoAdminLib = pref_LoadAutoAdminLib();
return (m_AutoAdminLib != NULL);
}
#endif
/* Called from JavaScript */
typedef char* (*ldap_func)(char*, char*, char*, char*, char**);
JSBool PR_CALLBACK pref_NativeGetLDAPAttr
(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
#ifdef MOZ_ADMIN_LIB
ldap_func get_ldap_attributes = NULL;
#if (defined (XP_MAC) && defined(powerc)) || defined (XP_WIN) || defined(XP_UNIX)
if (m_AutoAdminLib == NULL) {
m_AutoAdminLib = pref_LoadAutoAdminLib();
}
if (m_AutoAdminLib) {
get_ldap_attributes = (ldap_func)
#ifndef NSPR20
PR_FindSymbol(
#ifndef XP_WIN16
"pref_get_ldap_attributes"
#else
MAKEINTRESOURCE(1)
#endif
, m_AutoAdminLib);
#else /* NSPR20 */
PR_FindSymbol(
m_AutoAdminLib,
#ifndef XP_WIN16
"pref_get_ldap_attributes"
#else
MAKEINTRESOURCE(1)
#endif
);
#endif /* NSPR20 */
}
if (get_ldap_attributes == NULL) {
/* This indicates the AutoAdmin dll was not found. */
*rval = JSVAL_NULL;
return JS_TRUE;
}
#else
get_ldap_attributes = pref_get_ldap_attributes;
#endif /* MOZ_ADMIN_LIB */
if (argc >= 4 && JSVAL_IS_STRING(argv[0])
&& JSVAL_IS_STRING(argv[1])
&& JSVAL_IS_STRING(argv[2])
&& JSVAL_IS_STRING(argv[3])) {
char *return_error = NULL;
char *value = get_ldap_attributes(
JS_GetStringBytes(JSVAL_TO_STRING(argv[0])),
JS_GetStringBytes(JSVAL_TO_STRING(argv[1])),
JS_GetStringBytes(JSVAL_TO_STRING(argv[2])),
JS_GetStringBytes(JSVAL_TO_STRING(argv[3])),
&return_error );
if (value) {
JSString* str = JS_NewStringCopyZ(cx, value);
XP_FREE(value);
if (str) {
*rval = STRING_TO_JSVAL(str);
return JS_TRUE;
}
}
if (return_error) {
pref_Alert(return_error);
}
}
#endif
*rval = JSVAL_NULL;
return JS_TRUE;
}
/* LI_STUFF ?? add some debugging stuff here. */
/* Dump debugging info in response to about:config.
*/
PR_IMPLEMENT(int)
pref_printDebugInfo(PRHashEntry *he, int i, void *arg)
{
char *buf1, *buf2;
PrefValue val;
PrefChildIter* pcs = (PrefChildIter*) arg;
PrefNode *pref = (PrefNode *) he->value;
if (PREF_HAS_USER_VALUE(pref) && !PREF_IS_LOCKED(pref)) {
buf1 = PR_smprintf("<font color=\"blue\">%s = ", (char*) he->key);
val = pref->userPref;
}
else {
buf1 = PR_smprintf("<font color=\"%s\">%s = ",
PREF_IS_LOCKED(pref) ? "red" : (PREF_IS_CONFIG(pref) ? "black" : "green"),
(char*) he->key);
val = pref->defaultPref;
}
if (pref->flags & PREF_STRING) {
buf2 = PR_smprintf("%s %s</font><br>", buf1, val.stringVal);
}
else if (pref->flags & PREF_INT) {
buf2 = PR_smprintf("%s %d</font><br>", buf1, val.intVal);
}
else if (pref->flags & PREF_BOOL) {
buf2 = PR_smprintf("%s %s</font><br>", buf1, val.boolVal ? "true" : "false");
}
if ((strlen(buf2) + strlen(pcs->childList) + 1) > pcs->bufsize) {
pcs->bufsize *= 3;
pcs->childList = (char*) realloc(pcs->childList, sizeof(char) * pcs->bufsize);
if (!pcs->childList)
return HT_ENUMERATE_STOP;
}
XP_STRCAT(pcs->childList, buf2);
XP_FREE(buf1);
XP_FREE(buf2);
return 0;
}
PR_IMPLEMENT(char *)
PREF_AboutConfig()
{
PrefChildIter pcs;
pcs.bufsize = 8192;
pcs.childList = (char*) malloc(sizeof(char) * pcs.bufsize);
pcs.childList[0] = '\0';
XP_STRCAT(pcs.childList, "<HTML>");
PR_HashTableEnumerateEntries(m_HashTable, pref_printDebugInfo, &pcs);
return pcs.childList;
}
#define MAYBE_GC_BRANCH_COUNT_MASK 4095
JSBool PR_CALLBACK
pref_BranchCallback(JSContext *cx, JSScript *script)
{
static uint32 count = 0;
/*
* If we've been running for a long time, then try a GC to
* free up some memory.
*/
if ( (++count & MAYBE_GC_BRANCH_COUNT_MASK) == 0 )
JS_MaybeGC(cx);
#ifdef LATER
JSDecoder *decoder;
char *message;
JSBool ok = JS_TRUE;
decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
if (decoder->window_context && ++decoder->branch_count == 1000000) {
decoder->branch_count = 0;
message = PR_smprintf("Lengthy %s still running. Continue?",
lm_language_name);
if (message) {
ok = FE_Confirm(decoder->window_context, message);
XP_FREE(message);
}
}
#endif
return JS_TRUE;
}
/* copied from libmocha */
void
pref_ErrorReporter(JSContext *cx, const char *message,
JSErrorReport *report)
{
char *last;
int i, j, k, n;
const char *s, *t;
last = PR_sprintf_append(0, "An error occurred reading the startup configuration file. "
"Please contact your administrator.");
last = PR_sprintf_append(last, LINEBREAK LINEBREAK);
if (!report) {
last = PR_sprintf_append(last, "%s\n", message);
} else {
if (report->filename)
last = PR_sprintf_append(last, "%s, ",
report->filename, report->filename);
if (report->lineno)
last = PR_sprintf_append(last, "line %u: ", report->lineno);
last = PR_sprintf_append(last, "%s. ", message);
if (report->linebuf) {
for (s = t = report->linebuf; *s != '\0'; s = t) {
for (; t != report->tokenptr && *t != '<' && *t != '\0'; t++)
;
last = PR_sprintf_append(last, "%.*s", t - s, s);
if (*t == '\0')
break;
last = PR_sprintf_append(last, (*t == '<') ? "" : "%c", *t);
t++;
}
}
}
if (last) {
pref_Alert(last);
XP_FREE(last);
}
}
/* Platform specific alert messages */
void pref_Alert(char* msg)
{
#if defined(XP_MAC) || defined(XP_UNIX) || defined(XP_OS2)
#if defined(XP_UNIX)
if ( getenv("NO_PREF_SPAM") == NULL )
#endif
FE_Alert(NULL, msg);
#endif
#if defined (XP_WIN)
MessageBox (NULL, msg, "Netscape -- JS Preference Warning", MB_OK);
#endif
}
#ifdef XP_WIN16
#define ADMNLIBNAME "adm1640.dll"
#elif defined XP_WIN32 || defined XP_OS2
#define ADMNLIBNAME "adm3240.dll"
#elif defined XP_UNIX
#define ADMNLIBNAME "libAutoAdmin.so"
extern void fe_GetProgramDirectory(char *path, int len);
#else
#define ADMNLIBNAME "AutoAdmin" /* internal fragment name */
#endif
/* Try to load AutoAdminLib */
PRLibrary *
pref_LoadAutoAdminLib()
{
PRLibrary *lib = NULL;
#ifdef XP_MAC
const char *oldpath = PR_GetLibraryPath();
PR_SetLibraryPath( "/usr/local/netscape/" );
#endif
#ifdef XP_UNIX
{
char aalib[MAXPATHLEN];
if (getenv("NS_ADMIN_LIB"))
{
lib = PR_LoadLibrary(getenv("NS_ADMIN_LIB"));
}
else
{
if (getenv("MOZILLA_HOME"))
{
strcpy(aalib, getenv("MOZILLA_HOME"));
lib = PR_LoadLibrary(strcat(aalib, ADMNLIBNAME));
}
if (lib == NULL)
{
fe_GetProgramDirectory(aalib, sizeof(aalib)-1);
lib = PR_LoadLibrary(strcat(aalib, ADMNLIBNAME));
}
if (lib == NULL)
{
(void) strcpy(aalib, "/usr/local/netscape/");
lib = PR_LoadLibrary(strcat(aalib, ADMNLIBNAME));
}
}
}
/* Make sure it's really libAutoAdmin.so */
#ifndef NSPR20
if ( lib && PR_FindSymbol("_POLARIS_SplashPro", lib) == NULL ) return NULL;
#else
if ( lib && PR_FindSymbol(lib, "_POLARIS_SplashPro") == NULL ) return NULL;
#endif
#else
lib = PR_LoadLibrary( ADMNLIBNAME );
#endif
#ifdef XP_MAC
PR_SetLibraryPath(oldpath);
#endif
return lib;
}
/*
* Native implementations of JavaScript functions
pref -> pref_NativeDefaultPref
defaultPref -> "
userPref -> pref_NativeUserPref
lockPref -> pref_NativeLockPref
unlockPref -> pref_NativeUnlockPref
getPref -> pref_NativeGetPref
config -> pref_NativeSetConfig
*/
static JSBool pref_HashJSPref(unsigned int argc, jsval *argv, PrefAction action)
{
#ifdef NOPE1987
/* this is somehow fixing an internal compiler error for win16 */
PrefValue value;
const char *key;
XP_Bool bIsBool, bIsInt, bIsString;
;
if (argc < 2)
return JS_FALSE;
if (!JSVAL_IS_STRING(argv[0]))
return JS_FALSE;
bIsBool = JSVAL_IS_BOOLEAN(argv[1]);
bIsInt = JSVAL_IS_INT(argv[1]);
bIsString = JSVAL_IS_STRING(argv[1]);
key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
if (bIsString) {
value.stringVal = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
pref_HashPref(key, value, PREF_STRING, action);
}
#else
if (argc >= 2 && JSVAL_IS_STRING(argv[0])) {
PrefValue value;
const char *key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
if (JSVAL_IS_STRING(argv[1])) {
value.stringVal = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
pref_HashPref(key, value, PREF_STRING, action);
}
else if (JSVAL_IS_INT(argv[1])) {
value.intVal = JSVAL_TO_INT(argv[1]);
pref_HashPref(key, value, PREF_INT, action);
}
else if (JSVAL_IS_BOOLEAN(argv[1])) {
value.boolVal = JSVAL_TO_BOOLEAN(argv[1]);
pref_HashPref(key, value, PREF_BOOL, action);
}
}
#endif
return JS_TRUE;
}