2221 lines
56 KiB
C++
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;
|
|
}
|
|
|
|
|