home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / libpref / src / prefapi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  57.8 KB  |  2,221 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "jsapi.h"
  20. #include "xp_core.h"
  21. #include "xp_mcom.h"
  22. #include "xp_qsort.h"
  23. #include <errno.h>
  24.  
  25. #include "prefldap.h"
  26. #include "prefapi.h"
  27.  
  28. #if defined(XP_MAC) || defined(XP_UNIX)
  29. #include "fe_proto.h"
  30. #endif
  31. #if defined(XP_WIN) || defined(XP_OS2)
  32. #include "npapi.h"
  33. #include "assert.h"
  34. #define NOT_NULL(X)    X
  35. #define XP_ASSERT(X) assert(X)
  36. #define LINEBREAK "\n"
  37. #endif
  38. #include "sechash.h"
  39. #ifndef NSPR20
  40. #include "prhash.h"
  41. #else
  42. #include "plhash.h"
  43. #endif
  44.  
  45. #if defined(XP_MAC) && defined (__MWERKS__)
  46. /* Can't get the xp people to fix warnings... */
  47. #pragma require_prototypes off
  48. #endif
  49.  
  50. JSTaskState *            m_mochaTaskState = NULL;
  51. JSContext *                m_mochaContext = NULL;
  52. JSObject *                m_mochaPrefObject = NULL;
  53. JSObject *                m_GlobalConfigObject = NULL;
  54.  
  55. static char *                m_filename = NULL;
  56. static char *                m_lifilename = NULL;
  57. static struct CallbackNode*    m_Callbacks = NULL;
  58. static XP_Bool                m_ErrorOpeningUserPrefs = FALSE;
  59. static XP_Bool                m_CallbacksEnabled = FALSE;
  60. static XP_Bool                m_IsAnyPrefLocked = FALSE;
  61. static PRHashTable*            m_HashTable = NULL;
  62.  
  63. /* LI_STUFF - PREF_LILOCAL here to flag prefs as transferable or not */
  64. typedef enum { PREF_LOCKED = 1, PREF_USERSET = 2, PREF_CONFIG = 4,
  65.                PREF_STRING = 8, PREF_INT = 16, PREF_BOOL = 32, 
  66.                PREF_LILOCAL = 64 } PrefType;
  67. /* LI_STUFF  PREF_SETLI here to flag prefs as transferable or not */
  68. typedef enum { PREF_SETDEFAULT, PREF_SETUSER, 
  69.                PREF_LOCK, PREF_SETCONFIG, PREF_SETLI } PrefAction;
  70.  
  71. #define PREF_IS_LOCKED(pref)            ((pref)->flags & PREF_LOCKED)
  72. #define PREF_IS_CONFIG(pref)            ((pref)->flags & PREF_CONFIG)
  73. #define PREF_HAS_USER_VALUE(pref)        ((pref)->flags & PREF_USERSET)
  74. #define PREF_HAS_LI_VALUE(pref)            ((pref)->flags & PREF_LILOCAL) /* LI_STUFF */
  75.  
  76. typedef union
  77. {
  78.     char*        stringVal;
  79.     int32        intVal;
  80.     XP_Bool        boolVal;
  81. } PrefValue;
  82.  
  83. typedef struct 
  84. {
  85.     PrefValue    defaultPref;
  86.     PrefValue    userPref;
  87.     uint8        flags;
  88. } PrefNode;
  89.  
  90. static JSBool pref_HashJSPref(unsigned int argc, jsval *argv, PrefAction action);
  91.  
  92. /* Hash table allocation */
  93. PR_IMPLEMENT(void *)
  94. pref_AllocTable(void *pool, size_t size)
  95. {
  96.     return malloc(size);
  97. }
  98.  
  99. PR_IMPLEMENT(void) 
  100. pref_FreeTable(void *pool, void *item)
  101. {
  102.     free(item);        /* free items? */
  103. }
  104.  
  105. PR_IMPLEMENT(PRHashEntry *)
  106. pref_AllocEntry(void *pool, const void *key)
  107. {
  108.     return malloc(sizeof(PRHashEntry));
  109. }
  110.  
  111. PR_IMPLEMENT(void)
  112. pref_FreeEntry(void *pool, PRHashEntry *he, uint flag)
  113. {
  114.     PrefNode *pref = (PrefNode *) he->value;
  115.     if (pref) {
  116.         if (pref->flags & PREF_STRING) {
  117.             XP_FREEIF(pref->defaultPref.stringVal);
  118.             XP_FREEIF(pref->userPref.stringVal);
  119.         }
  120.         XP_FREE(he->value);
  121.     }
  122.  
  123.     if (flag == HT_FREE_ENTRY) {
  124.         XP_FREEIF((void *)he->key);
  125.         XP_FREE(he);
  126.     }
  127. }
  128.  
  129. static PRHashAllocOps pref_HashAllocOps = {
  130.     pref_AllocTable, pref_FreeTable,
  131.     pref_AllocEntry, pref_FreeEntry
  132. };
  133.  
  134. #include "prlink.h"
  135. extern PRLibrary *pref_LoadAutoAdminLib(void);
  136. PRLibrary *m_AutoAdminLib = NULL;
  137.  
  138. /* -- Privates */
  139. struct CallbackNode {
  140.     char*                    domain;
  141.     PrefChangedFunc            func;
  142.     void*                    data;
  143.     struct CallbackNode*    next;
  144. };
  145.  
  146. /* -- Prototypes */
  147. int pref_DoCallback(const char* changed_pref);
  148. int pref_OpenFile(const char* filename, XP_Bool is_error_fatal, XP_Bool verifyHash, XP_Bool bGlobalContext);
  149. XP_Bool pref_VerifyLockFile(char* buf, long buflen);
  150.  
  151. int pref_GetCharPref(const char *pref_name, char * return_buffer, int * length, XP_Bool get_default);
  152. int pref_CopyCharPref(const char *pref_name, char ** return_buffer, XP_Bool get_default);
  153. int pref_GetIntPref(const char *pref_name,int32 * return_int, XP_Bool get_default);
  154. int pref_GetBoolPref(const char *pref_name, XP_Bool * return_value, XP_Bool get_default);
  155.  
  156. JSBool PR_CALLBACK pref_BranchCallback(JSContext *cx, JSScript *script);
  157. void pref_ErrorReporter(JSContext *cx, const char *message,JSErrorReport *report);
  158. void pref_Alert(char* msg);
  159. int pref_HashPref(const char *key, PrefValue value, PrefType type, PrefAction action);
  160.  
  161. /* -- Platform specific function extern */
  162. #if !defined(XP_OS2)
  163. extern JSBool pref_InitInitialObjects(void);
  164. #endif
  165.  
  166. PRIVATE JSClass global_class = {
  167.     "global", 0,
  168.     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
  169.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
  170. };
  171.  
  172. JSBool PR_CALLBACK pref_NativeDefaultPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  173. JSBool PR_CALLBACK pref_NativeUserPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  174. JSBool PR_CALLBACK pref_NativeLockPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  175. JSBool PR_CALLBACK pref_NativeUnlockPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  176. JSBool PR_CALLBACK pref_NativeSetConfig(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  177. JSBool PR_CALLBACK pref_NativeGetPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  178. JSBool PR_CALLBACK pref_NativeGetLDAPAttr(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  179. /* LI_STUFF add nativelilocalpref */
  180. JSBool PR_CALLBACK pref_NativeLILocalPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  181. /* LI_STUFF add NativeLIUserPref - does both lilocal and user at once */
  182. JSBool PR_CALLBACK pref_NativeLIUserPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  183. JSBool PR_CALLBACK pref_NativeLIDefPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  184.  
  185.  
  186. /* LI_STUFF added localPref    pref_NativeLILocalPref,    1 */
  187. PRIVATE JSFunctionSpec autoconf_methods[] = {
  188.     { "pref",                pref_NativeDefaultPref,    2 },
  189.     { "defaultPref",        pref_NativeDefaultPref,    2 },
  190.     { "user_pref",            pref_NativeUserPref,    2 },
  191.     { "lockPref",            pref_NativeLockPref,    2 },
  192.     { "unlockPref",            pref_NativeUnlockPref,    1 },
  193.     { "config",                pref_NativeSetConfig,    2 },
  194.     { "getPref",            pref_NativeGetPref,        1 },
  195.     { "getLDAPAttributes",    pref_NativeGetLDAPAttr, 4 },
  196.     { "localPref",            pref_NativeLILocalPref,    1 },
  197.     { "localUserPref",        pref_NativeLIUserPref,    2 },
  198.     { "localDefPref",        pref_NativeLIDefPref,    2 },
  199.     { NULL,                 NULL,                   0 }
  200. };
  201.  
  202. PRIVATE JSPropertySpec autoconf_props[] = {
  203.     {0}
  204. };
  205.  
  206. PRIVATE JSClass autoconf_class = {
  207.     "PrefConfig", 0,
  208.     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
  209.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
  210. };
  211.  
  212. int pref_OpenFile(const char* filename, XP_Bool is_error_fatal, XP_Bool verifyHash, XP_Bool bGlobalContext)
  213. {
  214.     int ok = PREF_ERROR;
  215.     XP_File fp;
  216.     XP_StatStruct stats;
  217.     long fileLength;
  218.  
  219.     stats.st_size = 0;
  220.     if ( stat(filename, &stats) == -1 )
  221.         return PREF_ERROR;
  222.  
  223.     fileLength = stats.st_size;
  224.     if (fileLength <= 1)
  225.         return PREF_ERROR;
  226.     fp = fopen(filename, "r");
  227.  
  228.     if (fp) {    
  229.         char* readBuf = (char *) malloc(fileLength * sizeof(char));
  230.         if (readBuf) {
  231.             fileLength = XP_FileRead(readBuf, fileLength, fp);
  232.  
  233.             if ( verifyHash && pref_VerifyLockFile(readBuf, fileLength) == FALSE )
  234.             {
  235.                 ok = PREF_BAD_LOCKFILE;
  236.             }
  237.             else if ( PREF_EvaluateConfigScript(readBuf, fileLength,
  238.                         filename, bGlobalContext, FALSE ) == JS_TRUE )
  239.             {
  240.                 ok = PREF_NOERROR;
  241.             }
  242.             free(readBuf);
  243.         }
  244.         XP_FileClose(fp);
  245.         
  246.         /* If the user prefs file exists but generates an error,
  247.            don't clobber the file when we try to save it. */
  248.         if ((!readBuf || ok != PREF_NOERROR) && is_error_fatal)
  249.             m_ErrorOpeningUserPrefs = TRUE;
  250. #ifdef XP_WIN
  251.         if (m_ErrorOpeningUserPrefs && is_error_fatal)
  252.             MessageBox(NULL,"Error in preference file (prefs.js).  Default preferences will be used.","Netscape - Warning", MB_OK);
  253. #endif
  254.     }
  255.     JS_GC(m_mochaContext);
  256.     return (ok);
  257. }
  258.  
  259. /* Computes the MD5 hash of the given buffer (not including the first line)
  260.    and verifies the first line of the buffer expresses the correct hash in the form:
  261.    // xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
  262.    where each 'xx' is a hex value. */
  263. XP_Bool pref_VerifyLockFile(char* buf, long buflen)
  264. {
  265.     XP_Bool success = FALSE;
  266.     const int obscure_value = 7;
  267.     const long hash_length = 51;        /* len = 48 chars of MD5 + // + EOL */
  268.     unsigned char digest[16];
  269.     char szHash[64];
  270.  
  271.     /* Unobscure file by subtracting some value from every char. */
  272.     unsigned int i;
  273.     for (i = 0; i < buflen; i++) {
  274.         buf[i] -= obscure_value;
  275.     }
  276.  
  277.     if (buflen >= hash_length) {
  278.         const unsigned char magic_key[] = "VonGloda5652TX75235ISBN";
  279.         unsigned char *pStart = (unsigned char*) buf + hash_length;
  280.         unsigned int len;
  281.         
  282.         MD5Context * md5_cxt = MD5_NewContext();
  283.         MD5_Begin(md5_cxt);
  284.         
  285.         /* start with the magic key */
  286.         MD5_Update(md5_cxt, magic_key, sizeof(magic_key));
  287.  
  288.         MD5_Update(md5_cxt, pStart, buflen - hash_length);
  289.         
  290.         MD5_End(md5_cxt, digest, &len, 16);
  291.         
  292.         MD5_DestroyContext(md5_cxt, PR_TRUE);
  293.         
  294.         XP_SPRINTF(szHash, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
  295.             (int)digest[0],(int)digest[1],(int)digest[2],(int)digest[3],
  296.             (int)digest[4],(int)digest[5],(int)digest[6],(int)digest[7],
  297.             (int)digest[8],(int)digest[9],(int)digest[10],(int)digest[11],
  298.             (int)digest[12],(int)digest[13],(int)digest[14],(int)digest[15]);
  299.  
  300.         success = ( strncmp((const char*) buf + 3, szHash, hash_length - 4) == 0 );
  301.     }
  302.     
  303.     /*
  304.      * Should return 'success', but since the MD5 code is stubbed out,
  305.      * just return 'TRUE' until we have a replacement.
  306.      */
  307.     return TRUE;
  308. }
  309.  
  310. PR_IMPLEMENT(int)
  311. PREF_ReadLIJSFile(char *filename)
  312. {
  313.     int ok;
  314.  
  315.     if (filename) m_lifilename = strdup(filename);
  316.  
  317.     ok = pref_OpenFile(filename, FALSE, FALSE, FALSE);
  318.  
  319.     return ok;
  320. }
  321.  
  322. PR_IMPLEMENT(int)
  323. PREF_ReadUserJSFile(char *filename)
  324. {
  325.     int ok = pref_OpenFile(filename, FALSE, FALSE, TRUE);
  326.  
  327.     return ok;
  328. }
  329.  
  330. PR_IMPLEMENT(int)
  331. PREF_Init(char *filename)
  332. {
  333.     JSBool ok = JS_TRUE;
  334.  
  335.     /* --ML hash test */
  336.     if (!m_HashTable)
  337.     m_HashTable = PR_NewHashTable(2048, PR_HashString, PR_CompareStrings,
  338.         PR_CompareValues, &pref_HashAllocOps, NULL);
  339.     if (!m_HashTable)
  340.         return 0;
  341.  
  342.     if (filename) m_filename = strdup(filename);
  343.  
  344.     if (!m_mochaTaskState)
  345.         m_mochaTaskState = JS_Init((uint32) 0xffffffffL);
  346.  
  347.     if (!m_mochaContext) {
  348.         m_mochaContext = JS_NewContext(m_mochaTaskState, 8192);  /* ???? What size? */
  349.         if (!m_mochaContext) {
  350.             return 0;
  351.         }
  352.  
  353.         JS_SetVersion(m_mochaContext, JSVERSION_1_2);
  354.  
  355.         m_GlobalConfigObject = JS_NewObject(m_mochaContext, &global_class, NULL, NULL);
  356.         if (!m_GlobalConfigObject) 
  357.             return 0;
  358.  
  359.         if (!JS_InitStandardClasses(m_mochaContext, m_GlobalConfigObject))
  360.             return 0;
  361.  
  362.         JS_SetBranchCallback(m_mochaContext, pref_BranchCallback);
  363.         JS_SetErrorReporter(m_mochaContext, NULL);
  364.  
  365.         m_mochaPrefObject = JS_DefineObject(m_mochaContext, m_GlobalConfigObject, 
  366.                             "PrefConfig",
  367.                             &autoconf_class, 
  368.                             NULL, 
  369.                             JSPROP_ENUMERATE|JSPROP_READONLY);
  370.         
  371.         if (m_mochaPrefObject) {
  372.             if (!JS_DefineProperties(m_mochaContext,
  373.                          m_mochaPrefObject,
  374.                          autoconf_props)) {
  375.             return 0;
  376.             }
  377.  
  378.             if (!JS_DefineFunctions(m_mochaContext,
  379.                         m_mochaPrefObject,
  380.                         autoconf_methods)) {
  381.             return 0;
  382.             }
  383.  
  384.         }
  385.  
  386. #if !defined(XP_WIN) && !defined(XP_OS2)
  387.         ok = pref_InitInitialObjects();
  388. #endif
  389.     }
  390.  
  391.     if (ok && filename) {
  392.         ok = (JSBool) (pref_OpenFile(filename, TRUE, FALSE, FALSE) == PREF_NOERROR);
  393.     }
  394.     else if (!ok) {
  395.         m_ErrorOpeningUserPrefs = TRUE;
  396.     }
  397.     return ok;
  398. }
  399.  
  400. PR_IMPLEMENT(int)
  401. PREF_GetConfigContext(JSContext **js_context)
  402. {
  403.     if (!js_context) return FALSE;
  404.  
  405.     *js_context = NULL;
  406.     if (m_mochaContext)
  407.         *js_context = m_mochaContext;
  408.  
  409.     return TRUE;
  410. }
  411.  
  412. PR_IMPLEMENT(int)
  413. PREF_GetGlobalConfigObject(JSObject **js_object)
  414. {
  415.     if (!js_object) return FALSE;
  416.  
  417.     *js_object = NULL;
  418.     if (m_GlobalConfigObject)
  419.         *js_object = m_GlobalConfigObject;
  420.  
  421.     return TRUE;
  422. }
  423.  
  424. PR_IMPLEMENT(int)
  425. PREF_GetPrefConfigObject(JSObject **js_object)
  426. {
  427.     if (!js_object) return FALSE;
  428.  
  429.     *js_object = NULL;
  430.     if (m_mochaPrefObject)
  431.         *js_object = m_mochaPrefObject;
  432.  
  433.     return TRUE;
  434. }
  435.  
  436. /* Frees the callback list. */
  437. PR_IMPLEMENT(void)
  438. PREF_Cleanup()
  439. {
  440.     struct CallbackNode* node = m_Callbacks;
  441.     struct CallbackNode* next_node;
  442.     
  443.     while (node) {
  444.         next_node = node->next;
  445.         XP_FREE(node->domain);
  446.         XP_FREE(node);
  447.         node = next_node;
  448.     }
  449.     if (m_mochaContext) JS_DestroyContext(m_mochaContext);
  450.     if (m_mochaTaskState) JS_Finish(m_mochaTaskState);                      
  451.     m_mochaContext = NULL;
  452.     m_mochaTaskState = NULL;
  453.     
  454.     if (m_HashTable)
  455.         PR_HashTableDestroy(m_HashTable);
  456. }
  457.  
  458. PR_IMPLEMENT(int)
  459. PREF_ReadLockFile(const char *filename)
  460. {
  461. /*
  462.     return pref_OpenFile(filename, FALSE, FALSE, TRUE);
  463.  
  464.     Lock files are obscured, and the security code to read them has
  465.     been removed from the free source.  So don't even try to read one.
  466.     This is benign: no one listens closely to this error return,
  467.     and no one mourns the missing lock file.
  468. */
  469.     return PREF_ERROR;
  470. }
  471.  
  472. /* This is more recent than the below 3 routines which should be obsoleted */
  473. PR_IMPLEMENT(JSBool)
  474. PREF_EvaluateConfigScript(const char * js_buffer, size_t length,
  475.     const char* filename, XP_Bool bGlobalContext, XP_Bool bCallbacks)
  476. {
  477.     JSBool ok;
  478.     jsval result;
  479.     JSObject* scope;
  480.     JSErrorReporter errReporter;
  481.     
  482.     if (bGlobalContext)
  483.         scope = m_GlobalConfigObject;
  484.     else
  485.         scope = m_mochaPrefObject;
  486.         
  487.     if (!m_mochaContext || !scope)
  488.         return JS_FALSE;
  489.  
  490.     errReporter = JS_SetErrorReporter(m_mochaContext, pref_ErrorReporter);
  491.     m_CallbacksEnabled = bCallbacks;
  492.  
  493.     ok = JS_EvaluateScript(m_mochaContext, scope,
  494.             js_buffer, length, filename, 0, &result);
  495.     
  496.     m_CallbacksEnabled = TRUE;        /* ?? want to enable after reading user/lock file */
  497.     JS_SetErrorReporter(m_mochaContext, errReporter);
  498.     
  499.     return ok;
  500. }
  501.  
  502. PR_IMPLEMENT(int)
  503. PREF_EvaluateJSBuffer(const char * js_buffer, size_t length)
  504. {
  505. /* old routine that no longer triggers callbacks */
  506.     int ret;
  507.  
  508.     ret = PREF_QuietEvaluateJSBuffer(js_buffer, length);
  509.     
  510.     return ret;
  511. }
  512.  
  513. PR_IMPLEMENT(int)
  514. PREF_QuietEvaluateJSBuffer(const char * js_buffer, size_t length)
  515. {
  516.     JSBool ok;
  517.     jsval result;
  518.     
  519.     if (!m_mochaContext || !m_mochaPrefObject)
  520.         return PREF_NOT_INITIALIZED;
  521.  
  522.     ok = JS_EvaluateScript(m_mochaContext, m_mochaPrefObject,
  523.             js_buffer, length, NULL, 0, &result);
  524.     
  525.     /* Hey, this really returns a JSBool */
  526.     return ok;
  527. }
  528.  
  529. PR_IMPLEMENT(int)
  530. PREF_QuietEvaluateJSBufferWithGlobalScope(const char * js_buffer, size_t length)
  531. {
  532.     JSBool ok;
  533.     jsval result;
  534.     
  535.     if (!m_mochaContext || !m_GlobalConfigObject)
  536.         return PREF_NOT_INITIALIZED;
  537.     
  538.     ok = JS_EvaluateScript(m_mochaContext, m_GlobalConfigObject,
  539.             js_buffer, length, NULL, 0, &result);
  540.     
  541.     /* Hey, this really returns a JSBool */
  542.     return ok;
  543. }
  544.  
  545. static char * str_escape(const char * original) {
  546.     const char *p;
  547.     char * ret_str, *q;
  548.  
  549.     if (original == NULL)
  550.         return NULL;
  551.     
  552.     ret_str = malloc(2*strlen(original) + 1);  /* Paranoid worse case all slashes will free quickly */
  553.     for(p = original, q=ret_str ; *p; p++, q++)
  554.         switch(*p) {
  555.             case '\\':
  556.                 q[0] = '\\';
  557.                 q[1] = '\\';
  558.                 q++;
  559.                 break;
  560.             case '\"':
  561.                 q[0] = '\\';
  562.                 q[1] = '\"';
  563.                 q++;
  564.                 break;
  565.             default:
  566.                 *q = *p;
  567.                 break;
  568.         }
  569.     *q = 0;
  570.     return ret_str;
  571. }
  572.  
  573. /*
  574. // External calls
  575.  */
  576. PR_IMPLEMENT(int)
  577. PREF_SetCharPref(const char *pref_name, const char *value)
  578. {
  579.     PrefValue pref;
  580.     pref.stringVal = (char*) value;
  581.     
  582.     return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
  583. }
  584.  
  585. PR_IMPLEMENT(int)
  586. PREF_SetIntPref(const char *pref_name, int32 value)
  587. {
  588.     PrefValue pref;
  589.     pref.intVal = value;
  590.     
  591.     return pref_HashPref(pref_name, pref, PREF_INT, PREF_SETUSER);
  592. }
  593.  
  594. PR_IMPLEMENT(int)
  595. PREF_SetBoolPref(const char *pref_name, XP_Bool value)
  596. {
  597.     PrefValue pref;
  598.     pref.boolVal = value;
  599.     
  600.     return pref_HashPref(pref_name, pref, PREF_BOOL, PREF_SETUSER);
  601. }
  602.  
  603. #if !defined(XP_WIN) && !defined(XP_OS2)
  604. extern char *EncodeBase64Buffer(char *subject, long size);
  605. extern char *DecodeBase64Buffer(char *subject);
  606. #else
  607. /* temporary to make windows into a DLL...add a assert if used */
  608. char *EncodeBase64Buffer(char *subject, long size) 
  609. {
  610.     assert(0);
  611. }
  612.  
  613. char *DecodeBase64Buffer(char *subject)
  614. {
  615.     assert(0);
  616. }
  617. #endif
  618.  
  619. PR_IMPLEMENT(int)
  620. PREF_SetBinaryPref(const char *pref_name, void * value, long size)
  621. {
  622.     char* buf = EncodeBase64Buffer(value, size);
  623.  
  624.     if (buf) {
  625.         PrefValue pref;
  626.         pref.stringVal = buf;
  627.         return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
  628.     }
  629.     else
  630.         return PREF_ERROR;
  631. }
  632.  
  633. PR_IMPLEMENT(int)
  634. PREF_SetColorPref(const char *pref_name, uint8 red, uint8 green, uint8 blue)
  635. {
  636.     char colstr[63];
  637.     PrefValue pref;
  638.     XP_SPRINTF( colstr, "#%02X%02X%02X", red, green, blue);
  639.  
  640.     pref.stringVal = colstr;
  641.     return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
  642. }
  643.  
  644. #define MYGetboolVal(rgb)   ((uint8) ((rgb) >> 16))
  645. #define MYGetGValue(rgb)   ((uint8) (((uint16) (rgb)) >> 8)) 
  646. #define MYGetRValue(rgb)   ((uint8) (rgb)) 
  647.  
  648. PR_IMPLEMENT(int)
  649. PREF_SetColorPrefDWord(const char *pref_name, uint32 colorref)
  650. {
  651.     int red,green,blue;
  652.     char colstr[63];
  653.     PrefValue pref;
  654.  
  655.     red = MYGetRValue(colorref);
  656.     green = MYGetGValue(colorref);
  657.     blue = MYGetboolVal(colorref);
  658.     XP_SPRINTF( colstr, "#%02X%02X%02X", red, green, blue);
  659.  
  660.     pref.stringVal = colstr;
  661.     return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
  662. }
  663.  
  664. PR_IMPLEMENT(int)
  665. PREF_SetRectPref(const char *pref_name, int16 left, int16 top, int16 right, int16 bottom)
  666. {
  667.     char rectstr[63];
  668.     PrefValue pref;
  669.     XP_SPRINTF( rectstr, "%d,%d,%d,%d", left, top, right, bottom);
  670.  
  671.     pref.stringVal = rectstr;
  672.     return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETUSER);
  673. }
  674.  
  675. /*
  676. // DEFAULT VERSIONS:  Call internal with (set_default == TRUE)
  677.  */
  678. PR_IMPLEMENT(int)
  679. PREF_SetDefaultCharPref(const char *pref_name,const char *value)
  680. {
  681.     PrefValue pref;
  682.     pref.stringVal = (char*) value;
  683.     
  684.     return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETDEFAULT);
  685. }
  686.  
  687.  
  688. PR_IMPLEMENT(int)
  689. PREF_SetDefaultIntPref(const char *pref_name,int32 value)
  690. {
  691.     PrefValue pref;
  692.     pref.intVal = value;
  693.     
  694.     return pref_HashPref(pref_name, pref, PREF_INT, PREF_SETDEFAULT);
  695. }
  696.  
  697. PR_IMPLEMENT(int)
  698. PREF_SetDefaultBoolPref(const char *pref_name,XP_Bool value)
  699. {
  700.     PrefValue pref;
  701.     pref.boolVal = value;
  702.     
  703.     return pref_HashPref(pref_name, pref, PREF_BOOL, PREF_SETDEFAULT);
  704. }
  705.  
  706. PR_IMPLEMENT(int)
  707. PREF_SetDefaultBinaryPref(const char *pref_name,void * value,long size)
  708. {
  709.     char* buf = EncodeBase64Buffer(value, size);
  710.     if (buf) {
  711.         PrefValue pref;
  712.         pref.stringVal = buf;
  713.         return pref_HashPref(pref_name, pref, PREF_STRING, PREF_SETDEFAULT);
  714.     }
  715.     else
  716.         return PREF_ERROR;
  717. }
  718.  
  719. PR_IMPLEMENT(int)
  720. PREF_SetDefaultColorPref(const char *pref_name, uint8 red, uint8 green, uint8 blue)
  721. {
  722.     char colstr[63];
  723.     XP_SPRINTF( colstr, "#%02X%02X%02X", red, green, blue);
  724.  
  725.     return PREF_SetDefaultCharPref(pref_name, colstr);
  726. }
  727.  
  728. PR_IMPLEMENT(int)
  729. PREF_SetDefaultRectPref(const char *pref_name, int16 left, int16 top, int16 right, int16 bottom)
  730. {
  731.     char rectstr[63];
  732.     XP_SPRINTF( rectstr, "%d,%d,%d,%d", left, top, right, bottom);
  733.  
  734.     return PREF_SetDefaultCharPref(pref_name, rectstr);
  735. }
  736.  
  737.  
  738. /* LI_STUFF this does the same as savePref except it omits the lilocal prefs from the file. */
  739. PR_IMPLEMENT(int)
  740. pref_saveLIPref(PRHashEntry *he, int i, void *arg)
  741. {
  742.     char **prefArray = (char**) arg;
  743.     PrefNode *pref = (PrefNode *) he->value;
  744.     if (pref && PREF_HAS_USER_VALUE(pref) && !PREF_HAS_LI_VALUE(pref)) {
  745.         char buf[2048];
  746.  
  747.         if (pref->flags & PREF_STRING) {
  748.             char *tmp_str = str_escape(pref->userPref.stringVal);
  749.             if (tmp_str) {
  750.                 PR_snprintf(buf, 2048, "user_pref(\"%s\", \"%s\");" LINEBREAK,
  751.                     (char*) he->key, tmp_str);
  752.                 XP_FREE(tmp_str);
  753.             }
  754.         }
  755.         else if (pref->flags & PREF_INT) {
  756.             PR_snprintf(buf, 2048, "user_pref(\"%s\", %ld);" LINEBREAK,
  757.                 (char*) he->key, (long) pref->userPref.intVal);
  758.         }
  759.         else if (pref->flags & PREF_BOOL) {
  760.             PR_snprintf(buf, 2048, "user_pref(\"%s\", %s);" LINEBREAK, (char*) he->key,
  761.                 (pref->userPref.boolVal) ? "true" : "false");
  762.         }
  763.  
  764.         prefArray[i] = XP_STRDUP(buf);
  765.     } else if (pref && PREF_IS_LOCKED(pref) && !PREF_HAS_LI_VALUE(pref)) {
  766.         char buf[2048];
  767.  
  768.         if (pref->flags & PREF_STRING) {
  769.             char *tmp_str = str_escape(pref->defaultPref.stringVal);
  770.             if (tmp_str) {
  771.                 PR_snprintf(buf, 2048, "user_pref(\"%s\", \"%s\");" LINEBREAK,
  772.                     (char*) he->key, tmp_str);
  773.                 XP_FREE(tmp_str);
  774.             }
  775.         }
  776.         else if (pref->flags & PREF_INT) {
  777.             PR_snprintf(buf, 2048, "user_pref(\"%s\", %ld);" LINEBREAK,
  778.                 (char*) he->key, (long) pref->defaultPref.intVal);
  779.         }
  780.         else if (pref->flags & PREF_BOOL) {
  781.             PR_snprintf(buf, 2048, "user_pref(\"%s\", %s);" LINEBREAK, (char*) he->key,
  782.                 (pref->defaultPref.boolVal) ? "true" : "false");
  783.         }
  784.  
  785.         prefArray[i] = XP_STRDUP(buf);
  786.     }
  787.     return 0;
  788. }
  789.  
  790.  
  791. PR_IMPLEMENT(int)
  792. pref_savePref(PRHashEntry *he, int i, void *arg)
  793. {
  794.     char **prefArray = (char**) arg;
  795.     PrefNode *pref = (PrefNode *) he->value;
  796.  
  797.     if (pref && PREF_HAS_USER_VALUE(pref)) {
  798.         char buf[2048];
  799.  
  800.         if (pref->flags & PREF_STRING) {
  801.             char *tmp_str = str_escape(pref->userPref.stringVal);
  802.             if (tmp_str) {
  803.                 PR_snprintf(buf, 2048, "user_pref(\"%s\", \"%s\");" LINEBREAK,
  804.                     (char*) he->key, tmp_str);
  805.                 XP_FREE(tmp_str);
  806.             }
  807.         }
  808.         else if (pref->flags & PREF_INT) {
  809.             PR_snprintf(buf, 2048, "user_pref(\"%s\", %ld);" LINEBREAK,
  810.                 (char*) he->key, (long) pref->userPref.intVal);
  811.         }
  812.         else if (pref->flags & PREF_BOOL) {
  813.             PR_snprintf(buf, 2048, "user_pref(\"%s\", %s);" LINEBREAK, (char*) he->key,
  814.                 (pref->userPref.boolVal) ? "true" : "false");
  815.         }
  816.  
  817.         prefArray[i] = XP_STRDUP(buf);
  818.     } else if (pref && PREF_IS_LOCKED(pref)) {
  819.         char buf[2048];
  820.  
  821.         if (pref->flags & PREF_STRING) {
  822.             char *tmp_str = str_escape(pref->defaultPref.stringVal);
  823.             if (tmp_str) {
  824.                 PR_snprintf(buf, 2048, "user_pref(\"%s\", \"%s\");" LINEBREAK,
  825.                     (char*) he->key, tmp_str);
  826.                 XP_FREE(tmp_str);
  827.             }
  828.         }
  829.         else if (pref->flags & PREF_INT) {
  830.             PR_snprintf(buf, 2048, "user_pref(\"%s\", %ld);" LINEBREAK,
  831.                 (char*) he->key, (long) pref->defaultPref.intVal);
  832.         }
  833.         else if (pref->flags & PREF_BOOL) {
  834.             PR_snprintf(buf, 2048, "user_pref(\"%s\", %s);" LINEBREAK, (char*) he->key,
  835.                 (pref->defaultPref.boolVal) ? "true" : "false");
  836.         }
  837.  
  838.         prefArray[i] = XP_STRDUP(buf);
  839.     }
  840.     /* LI_STUFF?? may need to write out the lilocal stuff here if it applies - probably won't support in 
  841.         the prefs.js file. We won't need to worry about the user.js since it is read only.
  842.     */
  843.     return 0;
  844. }
  845.  
  846. PR_IMPLEMENT(int)
  847. pref_CompareStrings (const void *v1, const void *v2)
  848. {
  849.     char *s1 = *(char**) v1;
  850.     char *s2 = *(char**) v2;
  851.  
  852.     if (!s1)
  853.     {
  854.         if (!s2)
  855.             return 0;
  856.         else
  857.             return -1;
  858.     }
  859.     else if (!s2)
  860.         return 1;
  861.     else
  862.         return strcmp(s1, s2);
  863. }
  864.  
  865. /* LI_STUFF  
  866. this is new.  clients should use the old PREF_SavePrefFile or new PREF_SaveLIPrefFile.  
  867. This is called by them and does the right thing.  
  868. ?? make this private to this file.
  869. */
  870. PR_IMPLEMENT(int)
  871. PREF_SavePrefFileWith(const char *filename, PRHashEnumerator heSaveProc) {
  872.     int success = PREF_ERROR;
  873.     FILE * fp;
  874.     char **valueArray = NULL;
  875.     int valueIdx;
  876.  
  877.     if (!m_HashTable)
  878.         return PREF_NOT_INITIALIZED;
  879.  
  880.     /* ?! Don't save (blank) user prefs if there was an error reading them */
  881. #if defined(XP_WIN) || defined(XP_OS2)
  882.     if (!filename)
  883. #else
  884.     if (!filename || m_ErrorOpeningUserPrefs)
  885. #endif
  886.         return PREF_NOERROR;
  887.  
  888.     valueArray = (char**) XP_CALLOC(sizeof(char*), m_HashTable->nentries);
  889.     if (!valueArray)
  890.         return PREF_OUT_OF_MEMORY;
  891.  
  892.     fp = fopen(filename, "w");
  893.     if (fp) {
  894.         XP_FileWrite("// Netscape User Preferences" LINEBREAK
  895.              "// This is a generated file!  Do not edit." LINEBREAK LINEBREAK,
  896.              -1, fp);
  897.         
  898.         /* LI_STUFF here we pass in the heSaveProc proc used so that li can do its own thing */
  899.         PR_HashTableEnumerateEntries(m_HashTable, heSaveProc, valueArray);
  900.         
  901.         /* Sort the preferences to make a readable file on disk */
  902.         XP_QSORT (valueArray, m_HashTable->nentries, sizeof(char*), pref_CompareStrings);
  903.         for (valueIdx = 0; valueIdx < m_HashTable->nentries; valueIdx++)
  904.         {
  905.             if (valueArray[valueIdx])
  906.             {
  907.                 XP_FileWrite(valueArray[valueIdx], -1, fp);
  908.                 XP_FREE(valueArray[valueIdx]);
  909.             }
  910.         }
  911.  
  912.         XP_FileClose(fp);
  913.         success = PREF_NOERROR;
  914.     }
  915.     else 
  916.         success = errno;
  917.  
  918.     XP_FREE(valueArray);
  919.  
  920.     return success;
  921. }
  922.  
  923.  
  924. PR_IMPLEMENT(int)
  925. PREF_SavePrefFile()
  926. {
  927.     if (!m_HashTable)
  928.         return PREF_NOT_INITIALIZED;
  929.     return (PREF_SavePrefFileWith(m_filename, pref_savePref));
  930. }
  931.  
  932. /* LI_STUFF  Create a saveprefFile for LI for outsiders to call */
  933. PR_IMPLEMENT(int)
  934. PREF_SaveLIPrefFile(const char *filename)
  935. {
  936.  
  937.     if (!m_HashTable)
  938.         return PREF_NOT_INITIALIZED;
  939.     return (PREF_SavePrefFileWith(((filename) ? filename : m_lifilename), pref_saveLIPref));
  940. }
  941.  
  942. /* LI_STUFF  pass in the pref_savePref proc used instead of assuming it so that li can share that code too */
  943. PR_IMPLEMENT(int)
  944. PREF_SavePrefFileAs(const char *filename) {
  945.     return PREF_SavePrefFileWith(filename, pref_savePref);
  946. }
  947.  
  948. int pref_GetCharPref(const char *pref_name, char * return_buffer, int * length, XP_Bool get_default)
  949. {
  950.     int result = PREF_ERROR;
  951.     char* stringVal;
  952.     
  953.     PrefNode* pref;
  954.  
  955.     if (!m_HashTable)
  956.         return PREF_NOT_INITIALIZED;
  957.  
  958.     pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
  959.  
  960.     if (pref) {
  961.         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
  962.             stringVal = pref->defaultPref.stringVal;
  963.         else
  964.             stringVal = pref->userPref.stringVal;
  965.         
  966.         if (stringVal) {
  967.             if (*length == 0) {
  968.                 *length = strlen(stringVal) + 1;
  969.             }
  970.             else {
  971.                 strncpy(return_buffer, stringVal, PR_MIN(*length - 1, strlen(stringVal) + 1));
  972.                 return_buffer[*length - 1] = '\0';
  973.             }
  974.             result = PREF_OK;
  975.         }
  976.     }
  977.     return result;
  978. }
  979.  
  980. int pref_CopyCharPref(const char *pref_name, char ** return_buffer, XP_Bool get_default)
  981. {
  982.     int result = PREF_ERROR;
  983.     char* stringVal;    
  984.     PrefNode* pref;
  985.  
  986.     if (!m_HashTable)
  987.         return PREF_NOT_INITIALIZED;
  988.  
  989.     pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
  990.  
  991.     if (pref && pref->flags & PREF_STRING) {
  992.         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
  993.             stringVal = pref->defaultPref.stringVal;
  994.         else
  995.             stringVal = pref->userPref.stringVal;
  996.         
  997.         if (stringVal) {
  998.             *return_buffer = XP_STRDUP(stringVal);
  999.             result = PREF_OK;
  1000.         }
  1001.     }
  1002.     return result;
  1003. }
  1004.  
  1005. int pref_GetIntPref(const char *pref_name,int32 * return_int, XP_Bool get_default)
  1006. {
  1007.     int result = PREF_ERROR;    
  1008.     PrefNode* pref;
  1009.  
  1010.     if (!m_HashTable)
  1011.         return PREF_NOT_INITIALIZED;
  1012.  
  1013.     pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
  1014.     if (pref && pref->flags & PREF_INT) {
  1015.         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
  1016.             *return_int = pref->defaultPref.intVal;
  1017.         else
  1018.             *return_int = pref->userPref.intVal;
  1019.         result = PREF_OK;
  1020.     }
  1021.     return result;
  1022. }
  1023.  
  1024. int pref_GetBoolPref(const char *pref_name, XP_Bool * return_value, XP_Bool get_default)
  1025. {
  1026.     int result = PREF_ERROR;
  1027.     PrefNode* pref;
  1028.  
  1029.     if (!m_HashTable)
  1030.         return PREF_NOT_INITIALIZED;
  1031.  
  1032.     pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);    
  1033.     if (pref && pref->flags & PREF_BOOL) {
  1034.         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
  1035.             *return_value = pref->defaultPref.boolVal;
  1036.         else
  1037.             *return_value = pref->userPref.boolVal;
  1038.         result = PREF_OK;
  1039.     }
  1040.     return result;
  1041. }
  1042.  
  1043.  
  1044. PR_IMPLEMENT(int)
  1045. PREF_GetCharPref(const char *pref_name, char * return_buffer, int * length)
  1046. {
  1047.     return pref_GetCharPref(pref_name, return_buffer, length, FALSE);
  1048. }
  1049.  
  1050. PR_IMPLEMENT(int)
  1051. PREF_CopyCharPref(const char *pref_name, char ** return_buffer)
  1052. {
  1053.     return pref_CopyCharPref(pref_name, return_buffer, FALSE);
  1054. }
  1055.  
  1056. PR_IMPLEMENT(int)
  1057. PREF_GetIntPref(const char *pref_name,int32 * return_int)
  1058. {
  1059.     return pref_GetIntPref(pref_name, return_int, FALSE);
  1060. }
  1061.  
  1062. PR_IMPLEMENT(int)
  1063. PREF_GetBoolPref(const char *pref_name, XP_Bool * return_value)
  1064. {
  1065.     return pref_GetBoolPref(pref_name, return_value, FALSE);
  1066. }
  1067.  
  1068. PR_IMPLEMENT(int)
  1069. PREF_GetColorPref(const char *pref_name, uint8 *red, uint8 *green, uint8 *blue)
  1070. {
  1071.     char colstr[8];
  1072.     int iSize = 8;
  1073.  
  1074.     int result = PREF_GetCharPref(pref_name, colstr, &iSize);
  1075.     
  1076.     if (result == PREF_NOERROR) {
  1077.         int r, g, b;
  1078.         sscanf(colstr, "#%02X%02X%02X", &r, &g, &b);
  1079.         *red = r;
  1080.         *green = g;
  1081.         *blue = b;
  1082.     }
  1083.     
  1084.     return result;
  1085. }
  1086.  
  1087. #define MYRGB(r, g ,b)  ((uint32) (((uint8) (r) | ((uint16) (g) << 8)) | (((uint32) (uint8) (b)) << 16))) 
  1088.  
  1089. PR_IMPLEMENT(int)
  1090. PREF_GetColorPrefDWord(const char *pref_name, uint32 *colorref)
  1091. {
  1092.     char colstr[8];
  1093.     int iSize = 8;
  1094.     uint8 red, green, blue;
  1095.  
  1096.     int result = PREF_GetCharPref(pref_name, colstr, &iSize);
  1097.     
  1098.     if (result == 0) {
  1099.         int r, g, b;
  1100.         sscanf(colstr, "#%02X%02X%02X", &r, &g, &b);
  1101.         red = r;
  1102.         green = g;
  1103.         blue = b;
  1104.     }
  1105.     *colorref = MYRGB(red,green,blue);
  1106.     return result;
  1107. }
  1108.  
  1109. PR_IMPLEMENT(int)
  1110. PREF_GetRectPref(const char *pref_name, int16 *left, int16 *top, int16 *right, int16 *bottom)
  1111. {
  1112.     char rectstr[64];
  1113.     int iSize=64;
  1114.     int result = PREF_GetCharPref(pref_name, rectstr, &iSize);
  1115.     
  1116.     if (result == PREF_NOERROR) {
  1117.         int l, t, r, b;
  1118.         sscanf(rectstr, "%i,%i,%i,%i", &l, &t, &r, &b);
  1119.         *left = l;    *top = t;
  1120.         *right = r;    *bottom = b;
  1121.     }
  1122.     return result;
  1123. }
  1124.  
  1125. PR_IMPLEMENT(int)
  1126. PREF_GetBinaryPref(const char *pref_name, void * return_value, int *size)
  1127. {
  1128.     char* buf;
  1129.     int result;
  1130.  
  1131.     if (!m_mochaPrefObject || !return_value) return -1;
  1132.  
  1133.     result = PREF_CopyCharPref(pref_name, &buf);
  1134.  
  1135.     if (result == PREF_NOERROR) {
  1136.         char* debuf;
  1137.         if (strlen(buf) == 0) {        /* don't decode empty string ? */
  1138.             XP_FREE(buf);
  1139.             return -1;
  1140.         }
  1141.     
  1142.         debuf = DecodeBase64Buffer(buf);
  1143.         XP_MEMCPY(return_value, debuf, *size);
  1144.         
  1145.         XP_FREE(buf);
  1146.         XP_FREE(debuf);
  1147.     }
  1148.     return result;
  1149. }
  1150.  
  1151. typedef int (*CharPrefReadFunc)(const char*, char**);
  1152.  
  1153. static int
  1154. ReadCharPrefUsing(const char *pref_name, void** return_value, int *size, CharPrefReadFunc inFunc)
  1155. {
  1156.     char* buf;
  1157.     int result;
  1158.  
  1159.     if (!m_mochaPrefObject || !return_value)
  1160.         return -1;
  1161.     *return_value = NULL;
  1162.  
  1163.     result = inFunc(pref_name, &buf);
  1164.  
  1165.     if (result == PREF_NOERROR) {
  1166.         if (strlen(buf) == 0) {        /* do not decode empty string? */
  1167.             XP_FREE(buf);
  1168.             return -1;
  1169.         }
  1170.     
  1171.         *return_value = DecodeBase64Buffer(buf);
  1172.         *size = strlen(buf);
  1173.         
  1174.         XP_FREE(buf);
  1175.     }
  1176.     return result;
  1177. }
  1178.  
  1179. PR_IMPLEMENT(int)
  1180. PREF_CopyBinaryPref(const char *pref_name, void  ** return_value, int *size)
  1181. {
  1182.     return ReadCharPrefUsing(pref_name, return_value, size, PREF_CopyCharPref);
  1183. }
  1184.  
  1185. PR_IMPLEMENT(int)
  1186. PREF_CopyDefaultBinaryPref(const char *pref_name, void  ** return_value, int *size)
  1187. {
  1188.     return ReadCharPrefUsing(pref_name, return_value, size, PREF_CopyDefaultCharPref);
  1189. }
  1190.  
  1191. #ifndef XP_MAC
  1192. PR_IMPLEMENT(int)
  1193. PREF_CopyPathPref(const char *pref_name, char ** return_buffer)
  1194. {
  1195.     return PREF_CopyCharPref(pref_name, return_buffer);
  1196. }
  1197.  
  1198. PR_IMPLEMENT(int)
  1199. PREF_SetPathPref(const char *pref_name, const char *path, XP_Bool set_default)
  1200. {
  1201.     PrefAction action = set_default ? PREF_SETDEFAULT : PREF_SETUSER;
  1202.     PrefValue pref;
  1203.     pref.stringVal = (char*) path;
  1204.     
  1205.     return pref_HashPref(pref_name, pref, PREF_STRING, action);
  1206. }
  1207. #endif /* XP_MAC */
  1208.  
  1209.  
  1210. PR_IMPLEMENT(int)
  1211. PREF_GetDefaultCharPref(const char *pref_name, char * return_buffer, int * length)
  1212. {
  1213.     return pref_GetCharPref(pref_name, return_buffer, length, TRUE);
  1214. }
  1215.  
  1216. PR_IMPLEMENT(int)
  1217. PREF_CopyDefaultCharPref(const char *pref_name, char  ** return_buffer)
  1218. {
  1219.     return pref_CopyCharPref(pref_name, return_buffer, TRUE);
  1220. }
  1221.  
  1222. PR_IMPLEMENT(int)
  1223. PREF_GetDefaultIntPref(const char *pref_name, int32 * return_int)
  1224. {
  1225.     return pref_GetIntPref(pref_name, return_int, TRUE);
  1226. }
  1227.  
  1228. PR_IMPLEMENT(int)
  1229. PREF_GetDefaultBoolPref(const char *pref_name, XP_Bool * return_value)
  1230. {
  1231.     return pref_GetBoolPref(pref_name, return_value, TRUE);
  1232. }
  1233.  
  1234. PR_IMPLEMENT(int)
  1235. PREF_GetDefaultBinaryPref(const char *pref_name, void * return_value, int * length)
  1236. {
  1237. #ifdef XP_WIN
  1238.     assert( FALSE );
  1239. #else
  1240.     XP_ASSERT( FALSE );
  1241. #endif
  1242.     return TRUE;
  1243. }
  1244.  
  1245. PR_IMPLEMENT(int)
  1246. PREF_GetDefaultColorPref(const char *pref_name, uint8 *red, uint8 *green, uint8 *blue)
  1247. {
  1248.     char colstr[8];
  1249.     int iSize = 8;
  1250.  
  1251.     int result = PREF_GetDefaultCharPref(pref_name, colstr, &iSize);
  1252.     
  1253.     if (result == PREF_NOERROR) {
  1254.         int r, g, b;
  1255.         sscanf(colstr, "#%02X%02X%02X", &r, &g, &b);
  1256.         *red = r;
  1257.         *green = g;
  1258.         *blue = b;
  1259.     }
  1260.  
  1261.     return result;
  1262. }
  1263.  
  1264. PR_IMPLEMENT(int)
  1265. PREF_GetDefaultColorPrefDWord(const char *pref_name, uint32 * colorref)
  1266. {
  1267.     char colstr[8];
  1268.     int iSize = 8;
  1269.     uint8 red, green, blue;
  1270.  
  1271.     int result = PREF_GetDefaultCharPref(pref_name, colstr, &iSize);
  1272.     
  1273.     if (result == PREF_NOERROR) {
  1274.         int r, g, b;
  1275.         sscanf(colstr, "#%02X%02X%02X", &r, &g, &b);
  1276.         red = r;
  1277.         green = g;
  1278.         blue = b;
  1279.     }
  1280.     *colorref = MYRGB(red,green,blue);
  1281.     return result;
  1282. }
  1283.  
  1284. PR_IMPLEMENT(int)
  1285. PREF_GetDefaultRectPref(const char *pref_name, int16 *left, int16 *top, int16 *right, int16 *bottom)
  1286. {
  1287.     char rectstr[256];
  1288.     int iLen = 256;
  1289.     int result = PREF_GetDefaultCharPref(pref_name, (char *)&rectstr, &iLen);
  1290.     
  1291.     if (result == PREF_NOERROR) {
  1292.         sscanf(rectstr, "%d,%d,%d,%d", left, top, right, bottom);
  1293.     }
  1294.     return result;
  1295. }
  1296.  
  1297. /* Delete a branch. Used for deleting mime types */
  1298. PR_IMPLEMENT(int)
  1299. pref_DeleteItem(PRHashEntry *he, int i, void *arg)
  1300. {
  1301.     const char *to_delete = (const char *) arg;
  1302.     int len = strlen(to_delete);
  1303.     
  1304.     /* note if we're deleting "ldap" then we want to delete "ldap.xxx"
  1305.         and "ldap" (if such a leaf node exists) but not "ldap_1.xxx" */
  1306.     if (to_delete && (XP_STRNCMP(he->key, to_delete, len) == 0 ||
  1307.         (len-1 == strlen(he->key) && XP_STRNCMP(he->key, to_delete, len-1) == 0)))
  1308.         return HT_ENUMERATE_REMOVE;
  1309.     else
  1310.         return HT_ENUMERATE_NEXT;
  1311. }
  1312.  
  1313. PR_IMPLEMENT(int)
  1314. PREF_DeleteBranch(const char *branch_name)
  1315. {
  1316.     char* branch_dot = PR_smprintf("%s.", branch_name);
  1317.     if (!branch_dot)
  1318.         return PREF_OUT_OF_MEMORY;        
  1319.  
  1320.     PR_HashTableEnumerateEntries(m_HashTable, pref_DeleteItem, (void*) branch_dot);
  1321.     
  1322.     XP_FREE(branch_dot);
  1323.     return 0;
  1324. }
  1325.  
  1326. /* LI_STUFF  add a function to clear the li pref 
  1327.    does anyone use this??
  1328. */
  1329. PR_IMPLEMENT(int)
  1330. PREF_ClearLIPref(const char *pref_name)
  1331. {
  1332.     int success = PREF_ERROR;
  1333.     PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
  1334.     if (pref && PREF_HAS_LI_VALUE(pref)) {
  1335.         pref->flags &= ~PREF_LILOCAL;
  1336.         if (m_CallbacksEnabled)
  1337.             pref_DoCallback(pref_name);
  1338.         success = PREF_OK;
  1339.     }
  1340.     return success;
  1341. }
  1342.  
  1343.  
  1344.  
  1345. PR_IMPLEMENT(int)
  1346. PREF_ClearUserPref(const char *pref_name)
  1347. {
  1348.     int success = PREF_ERROR;
  1349.     PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
  1350.     if (pref && PREF_HAS_USER_VALUE(pref)) {
  1351.         pref->flags &= ~PREF_USERSET;
  1352.         if (m_CallbacksEnabled)
  1353.             pref_DoCallback(pref_name);
  1354.         success = PREF_OK;
  1355.     }
  1356.     return success;
  1357. }
  1358.  
  1359. /* Prototype Admin Kit support */
  1360. PR_IMPLEMENT(int)
  1361. PREF_GetConfigString(const char *obj_name, char * return_buffer, int size,
  1362.     int index, const char *field)
  1363. {
  1364. #ifdef XP_WIN
  1365.     assert( FALSE );
  1366. #else
  1367.     XP_ASSERT( FALSE );
  1368. #endif
  1369.     return -1;
  1370. }
  1371.  
  1372. /*
  1373.  * Administration Kit support 
  1374.  */
  1375. PR_IMPLEMENT(int)
  1376. PREF_CopyConfigString(const char *obj_name, char **return_buffer)
  1377. {
  1378.     int success = PREF_ERROR;
  1379.     PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, obj_name);
  1380.     
  1381.     if (pref && pref->flags & PREF_STRING) {
  1382.         if (return_buffer)
  1383.             *return_buffer = XP_STRDUP(pref->defaultPref.stringVal);
  1384.         success = PREF_NOERROR;
  1385.     }
  1386.     return success;
  1387. }
  1388.  
  1389. PR_IMPLEMENT(int)
  1390. PREF_CopyIndexConfigString(const char *obj_name,
  1391.     int index, const char *field, char **return_buffer)
  1392. {
  1393.     int success = PREF_ERROR;
  1394.     PrefNode* pref;
  1395.     char* setup_buf = PR_smprintf("%s_%d.%s", obj_name, index, field);
  1396.  
  1397.     pref = (PrefNode*) PR_HashTableLookup(m_HashTable, setup_buf);
  1398.     
  1399.     if (pref && pref->flags & PREF_STRING) {
  1400.         if (return_buffer)
  1401.             *return_buffer = XP_STRDUP(pref->defaultPref.stringVal);
  1402.         success = PREF_NOERROR;
  1403.     }
  1404.     XP_FREEIF(setup_buf);
  1405.     return success;
  1406. }
  1407.  
  1408. PR_IMPLEMENT(int)
  1409. PREF_GetConfigInt(const char *obj_name, int32 *return_int)
  1410. {
  1411.     int success = PREF_ERROR;
  1412.     
  1413.     PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, obj_name);
  1414.     
  1415.     if (pref && pref->flags & PREF_INT) {
  1416.         *return_int = pref->defaultPref.intVal;
  1417.         success = PREF_NOERROR;
  1418.     }
  1419.  
  1420.     return success;
  1421. }
  1422.  
  1423. PR_IMPLEMENT(int)
  1424. PREF_GetConfigBool(const char *obj_name, XP_Bool *return_bool)
  1425. {
  1426.     int success = PREF_ERROR;
  1427.     
  1428.     PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, obj_name);
  1429.     
  1430.     if (pref && pref->flags & PREF_BOOL) {
  1431.         *return_bool = pref->defaultPref.boolVal;
  1432.         success = PREF_NOERROR;
  1433.     }
  1434.  
  1435.     return success;
  1436. }
  1437.  
  1438. /*
  1439.  * Hash table functions
  1440.  */
  1441. static XP_Bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type)
  1442. {
  1443.     XP_Bool changed = TRUE;
  1444.     switch (type) {
  1445.         case PREF_STRING:
  1446.             if (oldValue.stringVal && newValue.stringVal)
  1447.                 changed = (strcmp(oldValue.stringVal, newValue.stringVal) != 0);
  1448.             break;
  1449.         
  1450.         case PREF_INT:
  1451.             changed = oldValue.intVal != newValue.intVal;
  1452.             break;
  1453.             
  1454.         case PREF_BOOL:
  1455.             changed = oldValue.boolVal != newValue.boolVal;
  1456.             break;
  1457.     }
  1458.     return changed;
  1459. }
  1460.  
  1461. static void pref_SetValue(PrefValue* oldValue, PrefValue newValue, PrefType type)
  1462. {
  1463.     switch (type) {
  1464.         case PREF_STRING:
  1465.             XP_ASSERT(newValue.stringVal);
  1466.             XP_FREEIF(oldValue->stringVal);
  1467.             oldValue->stringVal = newValue.stringVal ? XP_STRDUP(newValue.stringVal) : NULL;
  1468.             break;
  1469.         
  1470.         default:
  1471.             *oldValue = newValue;
  1472.     }
  1473. }
  1474.  
  1475. int pref_HashPref(const char *key, PrefValue value, PrefType type, PrefAction action)
  1476. {
  1477.     PrefNode* pref;
  1478.     int result = PREF_OK;
  1479.  
  1480.     if (!m_HashTable)
  1481.         return PREF_NOT_INITIALIZED;
  1482.  
  1483.     pref = (PrefNode*) PR_HashTableLookup(m_HashTable, key);
  1484.     if (!pref) {
  1485.         pref = (PrefNode*) calloc(sizeof(PrefNode), 1);
  1486.         if (!pref)    
  1487.             return PREF_OUT_OF_MEMORY;
  1488.         pref->flags = type;
  1489.         if (pref->flags & PREF_BOOL)
  1490.             pref->defaultPref.boolVal = (XP_Bool) -2;
  1491.         /* ugly hack -- define it to a default that no pref will ever default to
  1492.            this should really get fixed right by some out of band data */
  1493.         if (pref->flags & PREF_INT)
  1494.             pref->defaultPref.intVal = (int32) -5632;
  1495.         PR_HashTableAdd(m_HashTable, XP_STRDUP(key), pref);
  1496.     }
  1497.     else if (!(pref->flags & type)) {
  1498.         XP_ASSERT(0);            /* this shouldn't happen */
  1499.         return PREF_TYPE_CHANGE_ERR;
  1500.     }
  1501.     
  1502.     switch (action) {
  1503.         case PREF_SETDEFAULT:
  1504.         case PREF_SETCONFIG:
  1505.             if (!PREF_IS_LOCKED(pref)) {        /* ?? change of semantics? */
  1506.                 if (pref_ValueChanged(pref->defaultPref, value, type)) {
  1507.                     pref_SetValue(&pref->defaultPref, value, type);
  1508.                     if (!PREF_HAS_USER_VALUE(pref))
  1509.                         result = PREF_VALUECHANGED;
  1510.                 }
  1511.             }
  1512.             if (action == PREF_SETCONFIG)
  1513.                 pref->flags |= PREF_CONFIG;
  1514.             break;
  1515.  
  1516.         /* LI_STUFF  turn the li stuff on */
  1517.         case PREF_SETLI:
  1518.             if ( !PREF_HAS_LI_VALUE(pref) ||
  1519.                     pref_ValueChanged(pref->userPref, value, type) ) {        
  1520.                 pref_SetValue(&pref->userPref, value, type);
  1521.                 pref->flags |= PREF_LILOCAL;
  1522.                 if (!PREF_IS_LOCKED(pref))
  1523.                     result = PREF_VALUECHANGED;
  1524.             }
  1525.             break;
  1526.             
  1527.         case PREF_SETUSER:
  1528.             /* If setting to the default value, then un-set the user value.
  1529.                Otherwise, set the user value only if it has changed */
  1530.             if ( !pref_ValueChanged(pref->defaultPref, value, type) ) {
  1531.                 if (PREF_HAS_USER_VALUE(pref)) {
  1532.                     pref->flags &= ~PREF_USERSET;
  1533.                     if (!PREF_IS_LOCKED(pref))
  1534.                         result = PREF_VALUECHANGED;
  1535.                 }
  1536.             }
  1537.             else if ( !PREF_HAS_USER_VALUE(pref) ||
  1538.                        pref_ValueChanged(pref->userPref, value, type) ) {        
  1539.                 pref_SetValue(&pref->userPref, value, type);
  1540.                 pref->flags |= PREF_USERSET;
  1541.                 if (!PREF_IS_LOCKED(pref))
  1542.                     result = PREF_VALUECHANGED;
  1543.             }
  1544.             break;
  1545.             
  1546.         case PREF_LOCK:
  1547.             if (pref_ValueChanged(pref->defaultPref, value, type)) {
  1548.                 pref_SetValue(&pref->defaultPref, value, type);
  1549.                 result = PREF_VALUECHANGED;
  1550.             }
  1551.             else if (!PREF_IS_LOCKED(pref)) {
  1552.                 result = PREF_VALUECHANGED;
  1553.             }
  1554.             pref->flags |= PREF_LOCKED;
  1555.             m_IsAnyPrefLocked = TRUE;
  1556.             break;
  1557.     }
  1558.  
  1559.     if (result == PREF_VALUECHANGED && m_CallbacksEnabled) {
  1560.         int result2 = pref_DoCallback(key);
  1561.         if (result2 < 0)
  1562.             result = result2;
  1563.     }
  1564.     return result;
  1565. }
  1566.  
  1567. PR_IMPLEMENT(int)
  1568. PREF_GetPrefType(const char *pref_name)
  1569. {
  1570.     PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
  1571.     if (pref) {
  1572.         if (pref->flags & PREF_STRING)
  1573.             return PREF_STRING;
  1574.         else if (pref->flags & PREF_INT)
  1575.             return PREF_INT;
  1576.         else if (pref->flags & PREF_BOOL)
  1577.             return PREF_BOOL;
  1578.     }
  1579.     return PREF_ERROR;
  1580. }
  1581.  
  1582. JSBool PR_CALLBACK pref_NativeDefaultPref
  1583.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1584. {
  1585.     return pref_HashJSPref(argc, argv, PREF_SETDEFAULT);
  1586. }
  1587.  
  1588. /* LI_STUFF    here is the hookup with js prefs calls */
  1589. JSBool PR_CALLBACK pref_NativeLILocalPref
  1590.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1591. {
  1592.     if (argc >= 1 && JSVAL_IS_STRING(argv[0])) {
  1593.         const char *key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1594.         PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, key);
  1595.         
  1596.         if (pref && !PREF_HAS_LI_VALUE(pref)) {
  1597.             pref->flags |= PREF_LILOCAL;
  1598.             if (m_CallbacksEnabled) {
  1599.                 pref_DoCallback(key);
  1600.             }
  1601.         }
  1602.     }
  1603.     return JS_TRUE;
  1604. }
  1605.  
  1606. /* combo li and user pref - save some time */
  1607. JSBool PR_CALLBACK pref_NativeLIUserPref
  1608.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1609. {
  1610.     return (JSBool)(pref_HashJSPref(argc, argv, PREF_SETUSER) && pref_HashJSPref(argc, argv, PREF_SETLI));
  1611. }
  1612.  
  1613. /* combo li and user pref - save some time */
  1614. JSBool PR_CALLBACK pref_NativeLIDefPref
  1615.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1616. {
  1617.     return (JSBool)(pref_HashJSPref(argc, argv, PREF_SETDEFAULT) && pref_HashJSPref(argc, argv, PREF_SETLI));
  1618. }
  1619.  
  1620. JSBool PR_CALLBACK pref_NativeUserPref
  1621.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1622. {
  1623.     return pref_HashJSPref(argc, argv, PREF_SETUSER);
  1624. }
  1625.  
  1626. JSBool PR_CALLBACK pref_NativeLockPref
  1627.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1628. {
  1629.     return pref_HashJSPref(argc, argv, PREF_LOCK);
  1630. }
  1631.  
  1632. JSBool PR_CALLBACK pref_NativeUnlockPref
  1633.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1634. {
  1635.     if (argc >= 1 && JSVAL_IS_STRING(argv[0])) {
  1636.         const char *key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1637.         PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, key);
  1638.         
  1639.         if (pref && PREF_IS_LOCKED(pref)) {
  1640.             pref->flags &= ~PREF_LOCKED;
  1641.             if (m_CallbacksEnabled) {
  1642.                 pref_DoCallback(key);
  1643.             }
  1644.         }
  1645.     }
  1646.     return JS_TRUE;
  1647. }
  1648.  
  1649. JSBool PR_CALLBACK pref_NativeSetConfig
  1650.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1651. {
  1652.     return pref_HashJSPref(argc, argv, PREF_SETCONFIG);
  1653. }
  1654.  
  1655. JSBool PR_CALLBACK pref_NativeGetPref
  1656.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1657. {
  1658.     void* value = NULL;
  1659.     PrefNode* pref;
  1660.     XP_Bool prefExists = TRUE;
  1661.     
  1662.     if (argc >= 1 && JSVAL_IS_STRING(argv[0]))
  1663.     {
  1664.         const char *key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1665.         pref = (PrefNode*) PR_HashTableLookup(m_HashTable, key);
  1666.         
  1667.         if (pref) {
  1668.             XP_Bool use_default = (PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref));
  1669.                 
  1670.             if (pref->flags & PREF_STRING) {
  1671.                 char* str = use_default ? pref->defaultPref.stringVal : pref->userPref.stringVal;
  1672.                 JSString* jsstr = JS_NewStringCopyZ(cx, str);
  1673.                 *rval = STRING_TO_JSVAL(jsstr);
  1674.             }
  1675.             else if (pref->flags & PREF_INT) {
  1676.                 *rval = INT_TO_JSVAL(use_default ? pref->defaultPref.intVal : pref->userPref.intVal);
  1677.             }
  1678.             else if (pref->flags & PREF_BOOL) {
  1679.                 *rval = BOOLEAN_TO_JSVAL(use_default ? pref->defaultPref.boolVal : pref->userPref.boolVal);
  1680.             }
  1681.         }
  1682.     }
  1683.     return JS_TRUE;
  1684. }
  1685. /* -- */
  1686.  
  1687. PR_IMPLEMENT(XP_Bool)
  1688. PREF_PrefIsLocked(const char *pref_name)
  1689. {
  1690.     XP_Bool result = FALSE;
  1691.     if (m_IsAnyPrefLocked) {
  1692.         PrefNode* pref = (PrefNode*) PR_HashTableLookup(m_HashTable, pref_name);
  1693.         if (pref && PREF_IS_LOCKED(pref))
  1694.             result = TRUE;
  1695.     }
  1696.     
  1697.     return result;
  1698. }
  1699.  
  1700. /*
  1701.  * Creates an iterator over the children of a node.
  1702.  */
  1703. typedef struct 
  1704. {
  1705.     char*        childList;
  1706.     char*        parent;
  1707.     int            bufsize;
  1708. } PrefChildIter; 
  1709.  
  1710. /* if entry begins with the given string, i.e. if string is
  1711.   "a"
  1712.   and entry is
  1713.   "a.b.c" or "a.b"
  1714.   then add "a.b" to the list. */
  1715. PR_IMPLEMENT(int)
  1716. pref_addChild(PRHashEntry *he, int i, void *arg)
  1717. {
  1718.     PrefChildIter* pcs = (PrefChildIter*) arg;
  1719.     if ( XP_STRNCMP(he->key, pcs->parent, strlen(pcs->parent)) == 0 ) {
  1720.         char buf[512];
  1721.         char* nextdelim;
  1722.         int parentlen = strlen(pcs->parent);
  1723.         char* substring;
  1724.         XP_Bool substringBordersSeparator = FALSE;
  1725.  
  1726.         strncpy(buf, he->key, PR_MIN(512, strlen(he->key) + 1));
  1727.         nextdelim = buf + parentlen;
  1728.         if (parentlen < strlen(buf)) {
  1729.             /* Find the next delimiter if any and truncate the string there */
  1730.             nextdelim = strstr(nextdelim, ".");
  1731.             if (nextdelim) {
  1732.                 *nextdelim = '\0';
  1733.             }
  1734.         }
  1735.  
  1736.         substring = strstr(pcs->childList, buf);
  1737.         if (substring)
  1738.         {
  1739.             int buflen = strlen(buf);
  1740.             XP_ASSERT(substring[buflen] > 0);
  1741.             substringBordersSeparator = (substring[buflen] == '\0' || substring[buflen] == ';');
  1742.         }
  1743.  
  1744.         if (!substring || !substringBordersSeparator) {
  1745.             int newsize = strlen(pcs->childList) + strlen(buf) + 2;
  1746. #ifdef XP_WIN16
  1747.             return HT_ENUMERATE_STOP;
  1748. #else
  1749.             if (newsize > pcs->bufsize) {
  1750.                 pcs->bufsize *= 3;
  1751.                 pcs->childList = (char*) realloc(pcs->childList, sizeof(char) * pcs->bufsize);
  1752.                 if (!pcs->childList)
  1753.                     return HT_ENUMERATE_STOP;
  1754.             }
  1755. #endif
  1756.             XP_STRCAT(pcs->childList, buf);
  1757.             XP_STRCAT(pcs->childList, ";");
  1758.         }
  1759.     }
  1760.     return 0;
  1761. }
  1762.  
  1763. PR_IMPLEMENT(int)
  1764. PREF_CreateChildList(const char* parent_node, char **child_list)
  1765. {
  1766.     PrefChildIter pcs;
  1767.  
  1768. #ifdef XP_WIN16
  1769.     pcs.bufsize = 20480;
  1770. #else
  1771.     pcs.bufsize = 2048;
  1772. #endif
  1773.     pcs.childList = (char*) malloc(sizeof(char) * pcs.bufsize);
  1774.     pcs.parent = PR_smprintf("%s.", parent_node);
  1775.     if (!pcs.parent || !pcs.childList)
  1776.         return PREF_OUT_OF_MEMORY;
  1777.     pcs.childList[0] = '\0';
  1778.  
  1779.     PR_HashTableEnumerateEntries(m_HashTable, pref_addChild, &pcs);
  1780.  
  1781.     *child_list = pcs.childList;
  1782.     XP_FREE(pcs.parent);
  1783.     
  1784.     return (pcs.childList == NULL) ? PREF_OUT_OF_MEMORY : PREF_OK;
  1785. }
  1786.  
  1787. PR_IMPLEMENT(char*)
  1788. PREF_NextChild(char *child_list, int *index)
  1789. {
  1790.     char* child = strtok(&child_list[*index], ";");
  1791.     if (child)
  1792.         *index += strlen(child) + 1;
  1793.     return child;
  1794. }
  1795.  
  1796. /* Adds a node to the beginning of the callback list. */
  1797. PR_IMPLEMENT(void)
  1798. PREF_RegisterCallback(const char *pref_node,
  1799.                        PrefChangedFunc callback,
  1800.                        void * instance_data)
  1801. {
  1802.     struct CallbackNode* node = (struct CallbackNode*) malloc(sizeof(struct CallbackNode));
  1803.     if (node) {
  1804.         node->domain = XP_STRDUP(pref_node);
  1805.         node->func = callback;
  1806.         node->data = instance_data;
  1807.         node->next = m_Callbacks;
  1808.         m_Callbacks = node;
  1809.     }
  1810.     return;
  1811. }
  1812.  
  1813. /* Deletes a node from the callback list. */
  1814. PR_IMPLEMENT(int)
  1815. PREF_UnregisterCallback(const char *pref_node,
  1816.                          PrefChangedFunc callback,
  1817.                          void * instance_data)
  1818. {
  1819.     int result = PREF_ERROR;
  1820.     struct CallbackNode* node = m_Callbacks;
  1821.     struct CallbackNode* prev_node = NULL;
  1822.     
  1823.     while (node != NULL)
  1824.     {
  1825.         if ( strcmp(node->domain, pref_node) == 0 &&
  1826.              node->func == callback &&
  1827.              node->data == instance_data )
  1828.         {
  1829.             struct CallbackNode* next_node = node->next;
  1830.             if (prev_node)
  1831.                 prev_node->next = next_node;
  1832.             else
  1833.                 m_Callbacks = next_node;
  1834.             XP_FREE(node->domain);
  1835.             XP_FREE(node);
  1836.             node = next_node;
  1837.             result = PREF_NOERROR;
  1838.         }
  1839.         else {
  1840.             prev_node = node;
  1841.             node = node->next;
  1842.         }
  1843.     }
  1844.     return result;
  1845. }
  1846.  
  1847. int pref_DoCallback(const char* changed_pref)
  1848. {
  1849.     int result = PREF_OK;
  1850.     struct CallbackNode* node;
  1851.     for (node = m_Callbacks; node != NULL; node = node->next)
  1852.     {
  1853.         if ( XP_STRNCMP(changed_pref, node->domain, strlen(node->domain)) == 0 ) {
  1854.             int result2 = (*node->func) (changed_pref, node->data);
  1855.             if (result2 != PREF_OK)
  1856.                 result = result2;
  1857.         }
  1858.     }
  1859.     return result;
  1860. }
  1861.  
  1862. /* !! Front ends need to implement */
  1863. #ifndef XP_MAC
  1864. PR_IMPLEMENT(XP_Bool)
  1865. PREF_IsAutoAdminEnabled()
  1866. {
  1867.     if (m_AutoAdminLib == NULL)
  1868.         m_AutoAdminLib = pref_LoadAutoAdminLib();
  1869.     
  1870.     return (m_AutoAdminLib != NULL);
  1871. }
  1872. #endif
  1873.  
  1874. /* Called from JavaScript */
  1875. typedef char* (*ldap_func)(char*, char*, char*, char*, char**); 
  1876.  
  1877. JSBool PR_CALLBACK pref_NativeGetLDAPAttr
  1878.     (JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
  1879. {
  1880. #ifdef MOZ_ADMIN_LIB
  1881.     ldap_func get_ldap_attributes = NULL;
  1882. #if (defined (XP_MAC) && defined(powerc)) || defined (XP_WIN) || defined(XP_UNIX)
  1883.     if (m_AutoAdminLib == NULL) {
  1884.         m_AutoAdminLib = pref_LoadAutoAdminLib();
  1885.     }
  1886.         
  1887.     if (m_AutoAdminLib) {
  1888.         get_ldap_attributes = (ldap_func)
  1889. #ifndef NSPR20
  1890.             PR_FindSymbol(
  1891. #ifndef XP_WIN16
  1892.             "pref_get_ldap_attributes"
  1893. #else
  1894.             MAKEINTRESOURCE(1)
  1895. #endif
  1896.             , m_AutoAdminLib);
  1897. #else /* NSPR20 */
  1898.             PR_FindSymbol(
  1899.              m_AutoAdminLib,
  1900. #ifndef XP_WIN16
  1901.             "pref_get_ldap_attributes"
  1902. #else
  1903.             MAKEINTRESOURCE(1)
  1904. #endif
  1905.             );
  1906. #endif /* NSPR20 */
  1907.     }
  1908.     if (get_ldap_attributes == NULL) {
  1909.         /* This indicates the AutoAdmin dll was not found. */
  1910.         *rval = JSVAL_NULL;
  1911.         return JS_TRUE;
  1912.     }
  1913. #else
  1914.     get_ldap_attributes = pref_get_ldap_attributes;
  1915. #endif /* MOZ_ADMIN_LIB */
  1916.  
  1917.     if (argc >= 4 && JSVAL_IS_STRING(argv[0])
  1918.         && JSVAL_IS_STRING(argv[1])
  1919.         && JSVAL_IS_STRING(argv[2])
  1920.         && JSVAL_IS_STRING(argv[3])) {
  1921.         char *return_error = NULL;
  1922.         char *value = get_ldap_attributes(
  1923.             JS_GetStringBytes(JSVAL_TO_STRING(argv[0])),
  1924.             JS_GetStringBytes(JSVAL_TO_STRING(argv[1])),
  1925.             JS_GetStringBytes(JSVAL_TO_STRING(argv[2])),
  1926.             JS_GetStringBytes(JSVAL_TO_STRING(argv[3])),
  1927.             &return_error );
  1928.         
  1929.         if (value) {
  1930.             JSString* str = JS_NewStringCopyZ(cx, value);
  1931.             XP_FREE(value);
  1932.             if (str) {
  1933.                 *rval = STRING_TO_JSVAL(str);
  1934.                 return JS_TRUE;
  1935.             }
  1936.         }
  1937.         if (return_error) {
  1938.             pref_Alert(return_error);
  1939.         }
  1940.     }
  1941. #endif
  1942.     
  1943.     *rval = JSVAL_NULL;
  1944.     return JS_TRUE;
  1945. }
  1946.  
  1947. /* LI_STUFF ?? add some debugging stuff here. */
  1948. /* Dump debugging info in response to about:config.
  1949.  */
  1950. PR_IMPLEMENT(int)
  1951. pref_printDebugInfo(PRHashEntry *he, int i, void *arg)
  1952. {
  1953.     char *buf1, *buf2;
  1954.     PrefValue val;
  1955.     PrefChildIter* pcs = (PrefChildIter*) arg;
  1956.     PrefNode *pref = (PrefNode *) he->value;
  1957.     
  1958.     if (PREF_HAS_USER_VALUE(pref) && !PREF_IS_LOCKED(pref)) {
  1959.         buf1 = PR_smprintf("<font color=\"blue\">%s = ", (char*) he->key);
  1960.         val = pref->userPref;
  1961.     }
  1962.     else {
  1963.         buf1 = PR_smprintf("<font color=\"%s\">%s = ",
  1964.             PREF_IS_LOCKED(pref) ? "red" : (PREF_IS_CONFIG(pref) ? "black" : "green"),
  1965.             (char*) he->key);
  1966.         val = pref->defaultPref;
  1967.     }
  1968.     
  1969.     if (pref->flags & PREF_STRING) {
  1970.         buf2 = PR_smprintf("%s %s</font><br>", buf1, val.stringVal);
  1971.     }
  1972.     else if (pref->flags & PREF_INT) {
  1973.         buf2 = PR_smprintf("%s %d</font><br>", buf1, val.intVal);
  1974.     }
  1975.     else if (pref->flags & PREF_BOOL) {
  1976.         buf2 = PR_smprintf("%s %s</font><br>", buf1, val.boolVal ? "true" : "false");
  1977.     }
  1978.     
  1979.     if ((strlen(buf2) + strlen(pcs->childList) + 1) > pcs->bufsize) {
  1980.         pcs->bufsize *= 3;
  1981.         pcs->childList = (char*) realloc(pcs->childList, sizeof(char) * pcs->bufsize);
  1982.         if (!pcs->childList)
  1983.             return HT_ENUMERATE_STOP;
  1984.     }
  1985.     XP_STRCAT(pcs->childList, buf2);
  1986.     XP_FREE(buf1);
  1987.     XP_FREE(buf2);
  1988.     return 0;
  1989. }
  1990.  
  1991. PR_IMPLEMENT(char *)
  1992. PREF_AboutConfig()
  1993. {
  1994.     PrefChildIter pcs;
  1995.     pcs.bufsize = 8192;
  1996.     pcs.childList = (char*) malloc(sizeof(char) * pcs.bufsize);
  1997.     pcs.childList[0] = '\0';
  1998.     XP_STRCAT(pcs.childList, "<HTML>");    
  1999.  
  2000.     PR_HashTableEnumerateEntries(m_HashTable, pref_printDebugInfo, &pcs);
  2001.     
  2002.     return pcs.childList;
  2003. }
  2004.  
  2005. #define MAYBE_GC_BRANCH_COUNT_MASK    4095
  2006.  
  2007. JSBool PR_CALLBACK
  2008. pref_BranchCallback(JSContext *cx, JSScript *script)
  2009.     static uint32    count = 0;
  2010.     
  2011.     /*
  2012.      * If we've been running for a long time, then try a GC to 
  2013.      * free up some memory.
  2014.      */    
  2015.     if ( (++count & MAYBE_GC_BRANCH_COUNT_MASK) == 0 )
  2016.         JS_MaybeGC(cx); 
  2017.  
  2018. #ifdef LATER
  2019.     JSDecoder *decoder;
  2020.     char *message;
  2021.     JSBool ok = JS_TRUE;
  2022.  
  2023.     decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  2024.     if (decoder->window_context && ++decoder->branch_count == 1000000) {
  2025.     decoder->branch_count = 0;
  2026.     message = PR_smprintf("Lengthy %s still running.  Continue?",
  2027.                   lm_language_name);
  2028.     if (message) {
  2029.         ok = FE_Confirm(decoder->window_context, message);
  2030.         XP_FREE(message);
  2031.     }
  2032.     }
  2033. #endif
  2034.     return JS_TRUE;
  2035. }
  2036.  
  2037. /* copied from libmocha */
  2038. void
  2039. pref_ErrorReporter(JSContext *cx, const char *message,
  2040.                  JSErrorReport *report)
  2041. {
  2042.     char *last;
  2043.  
  2044.     int i, j, k, n;
  2045.     const char *s, *t;
  2046.  
  2047.     last = PR_sprintf_append(0, "An error occurred reading the startup configuration file.  "
  2048.         "Please contact your administrator.");
  2049.  
  2050.     last = PR_sprintf_append(last, LINEBREAK LINEBREAK);
  2051.     if (!report) {
  2052.         last = PR_sprintf_append(last, "%s\n", message);
  2053.     } else {
  2054.         if (report->filename)
  2055.             last = PR_sprintf_append(last, "%s, ",
  2056.                                      report->filename, report->filename);
  2057.         if (report->lineno)
  2058.             last = PR_sprintf_append(last, "line %u: ", report->lineno);
  2059.         last = PR_sprintf_append(last, "%s. ", message);
  2060.         if (report->linebuf) {
  2061.             for (s = t = report->linebuf; *s != '\0'; s = t) {
  2062.                 for (; t != report->tokenptr && *t != '<' && *t != '\0'; t++)
  2063.                     ;
  2064.                 last = PR_sprintf_append(last, "%.*s", t - s, s);
  2065.                 if (*t == '\0')
  2066.                     break;
  2067.                 last = PR_sprintf_append(last, (*t == '<') ? "" : "%c", *t);
  2068.                 t++;
  2069.             }
  2070.         }
  2071.     }
  2072.  
  2073.     if (last) {
  2074.         pref_Alert(last);
  2075.         XP_FREE(last);
  2076.     }
  2077. }
  2078.  
  2079. /* Platform specific alert messages */
  2080. void pref_Alert(char* msg)
  2081. {
  2082. #if defined(XP_MAC) || defined(XP_UNIX) || defined(XP_OS2)
  2083. #if defined(XP_UNIX)
  2084.     if ( getenv("NO_PREF_SPAM") == NULL )
  2085. #endif
  2086.     FE_Alert(NULL, msg);
  2087. #endif
  2088. #if defined (XP_WIN)
  2089.         MessageBox (NULL, msg, "Netscape -- JS Preference Warning", MB_OK);
  2090. #endif
  2091. }
  2092.  
  2093.  
  2094. #ifdef XP_WIN16
  2095. #define ADMNLIBNAME "adm1640.dll"
  2096. #elif defined XP_WIN32 || defined XP_OS2
  2097. #define ADMNLIBNAME "adm3240.dll"
  2098. #elif defined XP_UNIX
  2099. #define ADMNLIBNAME "libAutoAdmin.so"
  2100. extern void fe_GetProgramDirectory(char *path, int len);
  2101. #else
  2102. #define ADMNLIBNAME "AutoAdmin"    /* internal fragment name */
  2103. #endif
  2104.  
  2105. /* Try to load AutoAdminLib */
  2106. PRLibrary *
  2107. pref_LoadAutoAdminLib()
  2108. {
  2109.     PRLibrary *lib = NULL;
  2110.  
  2111. #ifdef XP_MAC
  2112.     const char *oldpath = PR_GetLibraryPath();
  2113.     PR_SetLibraryPath( "/usr/local/netscape/" );
  2114. #endif
  2115.  
  2116. #ifdef XP_UNIX
  2117.     {
  2118.         char aalib[MAXPATHLEN];
  2119.  
  2120.         if (getenv("NS_ADMIN_LIB"))
  2121.         {
  2122.             lib = PR_LoadLibrary(getenv("NS_ADMIN_LIB"));
  2123.         }
  2124.         else
  2125.         {
  2126.             if (getenv("MOZILLA_HOME"))
  2127.             {
  2128.                 strcpy(aalib, getenv("MOZILLA_HOME"));
  2129.                 lib = PR_LoadLibrary(strcat(aalib, ADMNLIBNAME));
  2130.             }
  2131.             if (lib == NULL)
  2132.             {
  2133.                 fe_GetProgramDirectory(aalib, sizeof(aalib)-1);
  2134.                 lib = PR_LoadLibrary(strcat(aalib, ADMNLIBNAME));
  2135.             }
  2136.             if (lib == NULL)
  2137.             {
  2138.                 (void) strcpy(aalib, "/usr/local/netscape/");
  2139.                 lib = PR_LoadLibrary(strcat(aalib, ADMNLIBNAME));
  2140.             }
  2141.         }
  2142.     }
  2143.     /* Make sure it's really libAutoAdmin.so */
  2144.     
  2145. #ifndef NSPR20
  2146.     if ( lib && PR_FindSymbol("_POLARIS_SplashPro", lib) == NULL ) return NULL;
  2147. #else 
  2148.     if ( lib && PR_FindSymbol(lib, "_POLARIS_SplashPro") == NULL ) return NULL;
  2149. #endif
  2150. #else
  2151.     lib = PR_LoadLibrary( ADMNLIBNAME );
  2152. #endif
  2153.  
  2154. #ifdef XP_MAC
  2155.     PR_SetLibraryPath(oldpath);
  2156. #endif
  2157.  
  2158.     return lib;
  2159. }
  2160.  
  2161. /*
  2162.  * Native implementations of JavaScript functions
  2163.     pref        -> pref_NativeDefaultPref
  2164.     defaultPref -> "
  2165.     userPref    -> pref_NativeUserPref
  2166.     lockPref    -> pref_NativeLockPref
  2167.     unlockPref    -> pref_NativeUnlockPref
  2168.     getPref        -> pref_NativeGetPref
  2169.     config        -> pref_NativeSetConfig
  2170.  */
  2171. static JSBool pref_HashJSPref(unsigned int argc, jsval *argv, PrefAction action)
  2172. {    
  2173. #ifdef NOPE1987
  2174.     /* this is somehow fixing an internal compiler error for win16 */
  2175.     PrefValue value;
  2176.     const char *key;
  2177.     XP_Bool bIsBool, bIsInt, bIsString;
  2178.  
  2179.     ;
  2180.     if (argc < 2)
  2181.         return JS_FALSE;
  2182.     if (!JSVAL_IS_STRING(argv[0]))
  2183.         return JS_FALSE;
  2184.  
  2185.     bIsBool = JSVAL_IS_BOOLEAN(argv[1]);
  2186.     bIsInt = JSVAL_IS_INT(argv[1]);
  2187.     bIsString = JSVAL_IS_STRING(argv[1]);
  2188.  
  2189.     key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  2190.  
  2191.     if (bIsString) {
  2192.         value.stringVal = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
  2193.         pref_HashPref(key, value, PREF_STRING, action);
  2194.     }
  2195.     
  2196. #else
  2197.     if (argc >= 2 && JSVAL_IS_STRING(argv[0])) {
  2198.         PrefValue value;
  2199.         const char *key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  2200.         
  2201.         if (JSVAL_IS_STRING(argv[1])) {
  2202.             value.stringVal = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
  2203.             pref_HashPref(key, value, PREF_STRING, action);
  2204.         }
  2205.         else if (JSVAL_IS_INT(argv[1])) {
  2206.             value.intVal = JSVAL_TO_INT(argv[1]);
  2207.             pref_HashPref(key, value, PREF_INT, action);
  2208.         }
  2209.         else if (JSVAL_IS_BOOLEAN(argv[1])) {
  2210.             value.boolVal = JSVAL_TO_BOOLEAN(argv[1]);
  2211.             pref_HashPref(key, value, PREF_BOOL, action);
  2212.         }
  2213.     }
  2214. #endif
  2215.  
  2216.     return JS_TRUE;
  2217. }
  2218.  
  2219.  
  2220.