prefs.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:27k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  * 
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  * 
  13.  * The Original Code is the Netscape security libraries.
  14.  * 
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are 
  17.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  18.  * Rights Reserved.
  19.  * 
  20.  * Contributor(s):
  21.  * 
  22.  * Alternatively, the contents of this file may be used under the
  23.  * terms of the GNU General Public License Version 2 or later (the
  24.  * "GPL"), in which case the provisions of the GPL are applicable 
  25.  * instead of those above.  If you wish to allow use of your 
  26.  * version of this file only under the terms of the GPL and not to
  27.  * allow others to use your version of this file under the MPL,
  28.  * indicate your decision by deleting the provisions above and
  29.  * replace them with the notice and other provisions required by
  30.  * the GPL.  If you do not delete the provisions above, a recipient
  31.  * may use your version of this file under either the MPL or the
  32.  * GPL.
  33.  */
  34. #if 0
  35. #include "prtypes.h"
  36. #include "prlock.h"
  37. #include "prmem.h"
  38. #include "prio.h"
  39. #include "prlog.h"
  40. #include "prerror.h"
  41. #include "prclist.h"
  42. #include "plstr.h"
  43. #include "prefs.h"
  44. /* Number of hash buckets.  As we add prefs, we should raise this. */
  45. #define NUM_BUCKETS 64
  46. static struct {
  47.     PRLock *lock;
  48.     PRCList list;
  49. } pref_file_list = { NULL };
  50. struct PrefFileStr {
  51.     PRCList link;
  52.     PRLock *lock;
  53.     int ref_cnt;
  54.     PrefFile *next;
  55.     char *filename;
  56.     PRBool modified;
  57.     PLHashTable *hash;
  58. };
  59. typedef struct DefaultPrefs {
  60.     char *key;
  61.     char *value;
  62. } DefaultPrefs;
  63. DefaultPrefs pref_defaults[] = {
  64.     { "enable_ssl2", "true" },
  65.     { "enable_ssl3", "true" },
  66.     { NULL, NULL }
  67. };
  68. static PLHashNumber
  69. pref_HashString(const void *key)
  70. {
  71.     PLHashNumber result;
  72.     char *string;
  73.     result = 0;
  74.     string = (char *)key;
  75.     while(*string != '') {
  76. result = (result << 4) + (result >> 28);
  77. result += *string;
  78. string++;
  79.     }
  80.     return result;
  81. }
  82. static PRIntn
  83. pref_HashCompareKey(const void *v1, const void *v2)
  84. {
  85.     if (strcmp(v1, v2) == 0)
  86. return 1;
  87.     else
  88. return 0;
  89. }
  90. static PRIntn
  91. pref_HashCompareValue(const void *v1, const void *v2)
  92. {
  93.     if (v1 == v2)
  94. return 1;
  95.     else
  96. return 0;
  97. }
  98. static void *
  99. pref_allocTable(void *pool, PRSize size)
  100. {
  101.     return PR_Malloc(size);
  102. }
  103. static void
  104. pref_freeTable(void *pool, void *item)
  105. {
  106.     PR_Free(item);
  107. }
  108. static PLHashEntry *
  109. pref_allocEntry(void *pool, const void *key)
  110. {
  111.     return PR_NEW(PLHashEntry);
  112. }
  113. static void
  114. pref_freeEntry(void *pool, PLHashEntry *he, PRUintn flag)
  115. {
  116.     PR_Free(he->value);
  117.     if (flag == HT_FREE_ENTRY)
  118.         PR_DELETE(he);
  119. }
  120. static PLHashAllocOps pref_HashAllocOps = {
  121.     pref_allocTable, pref_freeTable, pref_allocEntry, pref_freeEntry
  122. };
  123. struct StringBufStr {
  124.     char *str;
  125.     int len;
  126.     int space;
  127. };
  128. typedef struct StringBufStr StringBuf;
  129. static StringBuf *
  130. str_create(int space)
  131. {
  132.     StringBuf *buf;
  133.     buf = PR_NEW(StringBuf);
  134.     if (buf == NULL)
  135. goto loser;
  136.     buf->str = PR_Malloc(space + 1);
  137.     if (buf->str == NULL)
  138. goto loser;
  139.     buf->str[0] = '';
  140.     buf->len = 0;
  141.     buf->space = space;
  142.     return buf;
  143. loser:
  144.     if (buf != NULL) {
  145. if (buf->str != NULL)
  146.     PR_Free(buf->str);
  147. PR_DELETE(buf);
  148.     }
  149.     return NULL;
  150. }
  151. static SSMStatus
  152. str_addchar(StringBuf *buf, char c)
  153. {
  154.     int len, space;
  155.     PR_ASSERT(buf->len <= buf->space);
  156.     /* If we had a previous allocation failure, fail immediately. */
  157.     if (buf->space == 0)
  158. goto loser;
  159.     if (buf->len == buf->space) {
  160. buf->space *= 2;
  161. buf->str = PR_Realloc(buf->str, buf->space + 1);
  162. if (buf->str == NULL)
  163.     goto loser;
  164.     }
  165.     buf->str[len] = c;
  166.     len++;
  167.     buf->str[len] = '';
  168.     return PR_SUCCESS;
  169. loser:
  170.     buf->space = 0;
  171.     buf->len = 0;
  172.     return PR_FAILURE;
  173. }
  174. static void
  175. str_clear(StringBuf *buf)
  176. {
  177.     buf->len = 0;
  178.     buf->str[0] = '';
  179. }
  180. static char *
  181. str_dup(StringBuf *buf)
  182. {
  183.     return PL_strdup(buf->str);
  184. }
  185. static void
  186. str_destroy(StringBuf *buf)
  187. {
  188.     if (buf != NULL) {
  189. if (buf->str != NULL)
  190.     PR_Free(buf->str);
  191. PR_DELETE(buf);
  192.     }
  193. }
  194. typedef enum ParseState { parse_key, parse_value } ParseState;
  195. static SSMStatus
  196. pref_ReadPrefs(PrefFile *prefs)
  197. {
  198.     PRFileDesc *fd;
  199.     StringBuf *keybuf, *valbuf;
  200.     char *readbuf;
  201.     int i, readlen;
  202.     SSMStatus rv;
  203.     char c;
  204.     ParseState parse_state;
  205.     fd = PR_Open(prefs->filename, PR_RDONLY, 0);
  206.     if (fd == NULL) {
  207. /* No prefs file is okay.  Just don't do anything. */
  208. if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR)
  209.     return PR_SUCCESS;
  210. else
  211.     return PR_FAILURE;
  212.     }
  213.     keybuf = str_create(128);
  214.     if (keybuf == NULL)
  215. goto loser;
  216.     valbuf = str_create(128);
  217.     if (valbuf == NULL)
  218. goto loser;
  219.     readbuf = PR_Malloc(1024);
  220.     if (readbuf == NULL)
  221. goto loser;
  222.     readlen = PR_Read(fd, readbuf, 1024);
  223.     i = 0;
  224.     while(readlen != 0) {
  225. c = readbuf[i];
  226. switch(parse_state) {
  227.   case parse_key:
  228.     if (c == ':') {
  229. parse_state = parse_value;
  230.     } else { 
  231. str_addchar(keybuf, c);
  232.     }
  233.     break;
  234.   case parse_value:
  235.     if (c == 'n') {
  236. PLHashEntry *entry;
  237. char *key, *val;
  238. key = str_dup(keybuf);
  239. val = str_dup(valbuf);
  240. entry = PL_HashTableAdd(prefs->hash, key, val);
  241. if (entry == NULL) {
  242.     PR_Free(key);
  243.     PR_Free(val);
  244. }
  245. parse_state = parse_key;
  246.     } else {
  247. str_addchar(valbuf, c);
  248.     }
  249.     break;
  250. }
  251. i++;
  252. if (i == readlen) {
  253.     readlen = PR_Read(fd, readbuf, 1024);
  254.     i = 0;
  255. }
  256.     }
  257.     rv = PR_SUCCESS;
  258. done:
  259.     if (fd != NULL)
  260. PR_Close(fd);
  261.     if (keybuf != NULL)
  262. str_destroy(keybuf);
  263.     if (valbuf != NULL)
  264. str_destroy(valbuf);
  265.     if (readbuf != NULL)
  266. PR_Free(readbuf);
  267.     return rv;
  268. loser:
  269.     rv = PR_FAILURE;
  270.     goto done;
  271. }
  272. static PrefFile *
  273. pref_OpenNewPrefFile(char *filename)
  274. {
  275.     PrefFile *prefs;
  276.     PRFileDesc *fd;
  277.     SSMStatus status;
  278.     prefs = PR_NEW(PrefFile);
  279.     if (prefs == NULL)
  280. goto loser;
  281.     prefs->lock = PR_NewLock();
  282.     if (prefs->lock == NULL)
  283. goto loser;
  284.     prefs->filename = PL_strdup(filename);
  285.     if (prefs->filename == NULL)
  286. goto loser;
  287.     prefs->hash = PL_NewHashTable(NUM_BUCKETS, pref_HashString,
  288.   pref_HashCompareKey, pref_HashCompareValue,
  289.   NULL, NULL);
  290.     if (prefs->hash == NULL)
  291. goto loser;
  292.     status = pref_ReadPrefs(prefs);
  293.     if (status != PR_SUCCESS)
  294. goto loser;
  295.     prefs->ref_cnt = 1;
  296.     return prefs;
  297. loser:
  298.     if (prefs != NULL) {
  299. if (prefs->lock != NULL)
  300.     PR_DestroyLock(prefs->lock);
  301. if (prefs->filename != NULL)
  302.     PR_Free(prefs->filename);
  303. if (prefs->hash != NULL) {
  304.     PL_HashTableDestroy(prefs->hash);
  305. }
  306. PR_DELETE(prefs);
  307.     }
  308.     return NULL;
  309. }
  310. PrefFile *
  311. PREF_OpenPrefs(char *filename)
  312. {
  313.     PrefFile *prefs;
  314.     PRCList *link, *list;
  315.     /* Init the global file list if this is the first time. */
  316.     if (pref_file_list.lock == NULL) {
  317. pref_file_list.lock = PR_NewLock();
  318. if (pref_file_list.lock == NULL)
  319.     return NULL;
  320. PR_INIT_CLIST(&pref_file_list.list);
  321.     }
  322.     /* First, check to see if we've already got this file open. */
  323.     PR_Lock(pref_file_list.lock);
  324.     list = &pref_file_list.list;
  325.     for (link = PR_LIST_HEAD(list); link != list; link = PR_NEXT_LINK(link)) {
  326. prefs = (PrefFile *)link;
  327. if (PL_strcmp(filename, prefs->filename) == 0) {
  328.     PR_Lock(prefs->lock);
  329.     prefs->ref_cnt++;
  330.     PR_Unlock(prefs->lock);
  331.     PR_Unlock(pref_file_list.lock);
  332.     return prefs;
  333. }
  334.     }
  335.     /* We don't already have this prefs file open, so open it. */
  336.     prefs = pref_OpenNewPrefFile(filename);
  337.     if (prefs == NULL)
  338. goto loser;
  339.     PR_INSERT_BEFORE(&prefs->link, list);
  340.     PR_Unlock(pref_file_list.lock);
  341.     return prefs;
  342. loser:
  343.     PR_Unlock(pref_file_list.lock);
  344.     return NULL;
  345. }
  346. static PRIntn
  347. pref_writeEnumerator(PLHashEntry *he, PRIntn i, void *arg)
  348. {
  349.     PRFileDesc *fd = (PRFileDesc *)arg;
  350.     PR_Write(fd, he->key, PL_strlen(he->key));
  351.     PR_Write(fd, ":", 1);
  352.     PR_Write(fd, he->value, PL_strlen(he->value));
  353.     PR_Write(fd, "n", 1);
  354.     return HT_ENUMERATE_NEXT;
  355. }
  356. SSMStatus
  357. PREF_WritePrefs(PrefFile *prefs)
  358. {
  359.     PRFileDesc *fd;
  360.     SSMStatus status = PR_SUCCESS;
  361.     PR_Lock(prefs->lock);
  362.     if (prefs->modified == PR_FALSE)
  363. goto done;
  364.     fd = PR_Open(prefs->filename, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0600);
  365.     if (fd == NULL) {
  366. status = PR_FAILURE;
  367. goto done;
  368.     }
  369.     PL_HashTableEnumerateEntries(prefs->hash, pref_writeEnumerator, fd);
  370. done:
  371.     PR_Unlock(prefs->lock);
  372.     PR_Close(fd);
  373.     return status;
  374. }
  375. SSMStatus
  376. PREF_ClosePrefs(PrefFile *prefs)
  377. {
  378.     SSMStatus status;
  379.     PR_Lock(pref_file_list.lock);
  380.     PR_Lock(prefs->lock);
  381.     PR_ASSERT(prefs->ref_cnt >= 1);
  382.     prefs->ref_cnt--;
  383.     if (prefs->ref_cnt > 0) {
  384. PR_Unlock(prefs->lock);
  385. PR_Unlock(pref_file_list.lock);
  386. return PR_SUCCESS;
  387.     }
  388.     PR_REMOVE_LINK(&prefs->link);
  389.     PR_Unlock(pref_file_list.lock);
  390.     status = PREF_WritePrefs(prefs);
  391.     PR_DestroyLock(prefs->lock);
  392.     PR_Free(prefs->filename);
  393.     PL_HashTableDestroy(prefs->hash);
  394.     PR_Free(prefs);
  395.     return status;
  396. }
  397. static SSMStatus
  398. pref_SetStringPref_unlocked(PrefFile *prefs, char *name, char *value)
  399. {
  400.     PLHashEntry *entry;
  401.     char *key, *val;
  402.     key = PL_strdup(key);
  403.     if (key == NULL)
  404. goto loser;
  405.     val = PL_strdup(value);
  406.     if (val == NULL)
  407. goto loser;
  408.     entry = PL_HashTableAdd(prefs->hash, key, val);
  409.     if (entry == NULL)
  410. goto loser;
  411.     return PR_SUCCESS;
  412. loser:
  413.     if (key != NULL)
  414. PR_Free(key);
  415.     if (val != NULL)
  416. PR_Free(val);
  417.     return PR_FAILURE;
  418. }
  419. SSMStatus
  420. PREF_SetStringPref(PrefFile *prefs, char *name, char *value)
  421. {
  422.     SSMStatus status;
  423.     PR_Lock(prefs->lock);
  424.     status = pref_SetStringPref_unlocked(prefs, name, value);
  425.     prefs->modified = PR_TRUE;
  426.     PR_Unlock(prefs->lock);
  427.     return status;
  428. }
  429. char *
  430. PREF_GetStringPref(PrefFile *prefs, char *name)
  431. {
  432.     char *val;
  433.     PR_Lock(prefs->lock);
  434.     val = PL_HashTableLookup(prefs->hash, name);
  435.     if (val != NULL)
  436. val = PL_strdup(val);
  437.     PR_Unlock(prefs->lock);
  438.     return val;
  439. }
  440. static SSMStatus
  441. pref_SetDefaultPrefs(PrefFile *prefs)
  442. {
  443.     DefaultPrefs *dp;
  444.     SSMStatus status = PR_SUCCESS;
  445.     PR_Lock(prefs->lock);
  446.     dp = pref_defaults;
  447.     while(dp->key != NULL) {
  448. status = pref_SetStringPref_unlocked(prefs, dp->key, dp->value);
  449. if (status != PR_SUCCESS)
  450.     goto loser;
  451. dp++;
  452.     }
  453. loser:
  454.     PR_Unlock(prefs->lock);
  455.     return status;
  456. }
  457. #else    /* PREFS LITE (tm) */
  458. /*------------------------------------------------------*/
  459. #include "nspr.h"
  460. #include "prtypes.h"
  461. #include "prclist.h"
  462. #include "prlock.h"
  463. #include "prmem.h"
  464. #include "prlog.h"
  465. #include "plstr.h"
  466. #include "prefs.h"
  467. struct PrefSetStr {
  468.     PRCList list;
  469.     PRLock* lock;
  470.     PRBool modified;
  471. };
  472. typedef struct PrefItemStr {
  473.     char* key;
  474.     char* value;
  475. } PrefItem;
  476. typedef struct PrefItemNodeStr {
  477.     PRCList link;
  478.     PrefItem* item;
  479. } PrefItemNode;
  480. /* Default values with which a PrefSet is initialized
  481.  */ 
  482. PrefItem pref_defaults[] = {
  483.     {"security.enable_ssl2", "true"},
  484.     {"security.enable_ssl3", "true"},
  485.     {"security.default_personal_cert", "Ask Every Time"},
  486.     {"security.default_mail_cert", NULL},
  487.     {"security.ask_for_password", "0"},
  488.     {"security.password_lifetime", "30"},
  489.     {"security.OCSP.enabled", "false"},
  490.     {"security.warn_entering_secure", "true"},
  491.     {"security.warn_leaving_secure", "true"},
  492.     {"security.warn_viewing_mixed", "true"},
  493.     {"security.warn_submit_insecure", "true"},
  494.     {"mail.encrypt_outgoing_mail", "false"},
  495.     {"mail.crypto_sign_outgoing_mail", "false"},
  496.     {"mail.crypto_sign_outgoing_news", "false"},
  497.     {NULL, NULL}
  498. };
  499. char* STRING_TRUE = "true";
  500. char* STRING_FALSE = "false";
  501. static void pref_free_pref_item(PrefItem* pref)
  502. {
  503.     if (pref != NULL) {
  504.         if (pref->key != NULL) {
  505.             PR_Free(pref->key);
  506.         }
  507.         if (pref->value != NULL) {
  508.             PR_Free(pref->value);
  509.         }
  510.         PR_Free(pref);
  511.     }
  512. }
  513. static PrefItem* pref_new_pref_item(char* key, char* value)
  514. {
  515.     PrefItem* tmp = NULL;
  516.     PR_ASSERT(key != NULL);
  517.     tmp = (PrefItem*)PR_NEWZAP(PrefItem);
  518.     if (tmp == NULL) {
  519.         return tmp;
  520.     }
  521.     
  522.     tmp->key = PL_strdup(key);
  523.     if (tmp->key == NULL) {
  524.         goto loser;
  525.     }
  526.     if (value != NULL) {
  527.         tmp->value = PL_strdup(value);
  528.         if (tmp->value == NULL) {
  529.             goto loser;
  530.         }
  531.     }
  532.     else {
  533.         tmp->value = NULL;
  534.     }
  535.     return tmp;
  536. loser:
  537.     pref_free_pref_item(tmp);
  538.     return NULL;
  539. }
  540. static PrefItemNode* pref_new_pref_item_node(PrefItem* item)
  541. {
  542.     PrefItemNode* node = NULL;
  543.     PR_ASSERT(item != NULL);
  544.     node = (PrefItemNode*)PR_NEWZAP(PrefItemNode);
  545.     if (node == NULL) {
  546.         /* failed: bail out */
  547.         return node;
  548.     }
  549.     /* initialize elements to the right values */
  550.     PR_INIT_CLIST(&node->link);
  551.     node->item = item;
  552.     return node;
  553. }
  554. /* Append a PrefItem to the list */
  555. static SSMStatus pref_append_item_unlocked(PrefItem* pref, PRCList* list)
  556. {
  557.     PrefItemNode* node = NULL;
  558.     PR_ASSERT((pref != NULL) && (list != NULL));
  559.     node = pref_new_pref_item_node(pref);
  560.     if (node == NULL) {
  561.         return PR_FAILURE;
  562.     }
  563.     /* append the link */
  564.     PR_APPEND_LINK(&node->link, list);
  565.     return PR_SUCCESS;
  566. }
  567. /* Append a PrefItem made from (key, value) into the list */
  568. static SSMStatus pref_append_pref_unlocked(PrefSet* prefs, char* key, 
  569.                                           char* value)
  570. {
  571.     PrefItem* pref = NULL;
  572.     pref = pref_new_pref_item(key, value);
  573.     if (pref == NULL) {
  574.         return PR_FAILURE;
  575.     }
  576.     return pref_append_item_unlocked(pref, &prefs->list);
  577. }
  578. /* Modify (old) by comparing with (new)
  579.  * - returns PR_SUCCESS if everything went right; PR_FAILURE if PL_strdup()
  580.  *   failed
  581.  */
  582. static SSMStatus pref_reset_value(char** oldStr, char* newStr)
  583. {
  584.     PR_ASSERT(oldStr != NULL);
  585.     if (newStr == NULL) {
  586.         if (*oldStr != NULL) {
  587.             PR_Free(*oldStr);
  588.             *oldStr = newStr;
  589.         }
  590.         return PR_SUCCESS;
  591.     }
  592.     if (*oldStr != NULL) {
  593.         if (PL_strcmp(*oldStr, newStr) != 0) {
  594.             /* different: reset it */
  595.             PR_Free(*oldStr);
  596.             *oldStr = PL_strdup(newStr);
  597.             if (*oldStr == NULL) {
  598.                 return PR_FAILURE;
  599.             }
  600.         }
  601.     }
  602.     else {
  603.         *oldStr = PL_strdup(newStr);
  604.         if (*oldStr == NULL) {
  605.             return PR_FAILURE;
  606.         }
  607.     }
  608.     return PR_SUCCESS;
  609. }
  610. /* Retrieve (value) that belongs to (key) in (prefs)
  611.  * - return PR_SUCCESS if key exists; PR_FAILURE otherwise
  612.  * - (value) may be NULL
  613.  * - returned (value) is a pointer to an existing string, not a new string
  614.  */
  615. static SSMStatus pref_get_pref_unlocked(PrefSet* prefs, char* key, char** value)
  616. {
  617.     PRCList* link = NULL;
  618.     PR_ASSERT((prefs != NULL) && (key != NULL) && (value != NULL));
  619.     /* in case of failure */
  620.     *value = NULL;
  621.     /* first make sure the list is not empty */
  622.     if (PR_CLIST_IS_EMPTY(&prefs->list)) {
  623.         return PR_FAILURE;
  624.     }
  625.     /* walk the list to find the key */
  626.     for (link = PR_LIST_HEAD(&prefs->list); link != &prefs->list;
  627.          link = PR_NEXT_LINK(link)) {
  628.         PrefItemNode* node = (PrefItemNode*)link;
  629.         if (PL_strcmp(node->item->key, key) == 0) {
  630.             /* found the key: return the value whatever it is */
  631.             *value = node->item->value;
  632.             return PR_SUCCESS;
  633.         }
  634.     }
  635.     /* we couldn't find the key: return NULL */
  636.     return PR_FAILURE;
  637. }
  638. /* Set (value) for (key) in (prefs)
  639.  * - if (key) exists, reset (value) (if necessary)
  640.  * - if (key) does not exist, insert this item into (prefs)
  641.  * - we do not care if (value) is NULL
  642.  * - when new elements are created, they are allocated on the heap
  643.  */
  644. static SSMStatus pref_set_pref_unlocked(PrefSet* prefs, char* key, char* value)
  645. {
  646.     PRCList* link = NULL;
  647.     PR_ASSERT((prefs != NULL) && (key != NULL));
  648.     if (!PR_CLIST_IS_EMPTY(&prefs->list)) {
  649.         for (link = PR_LIST_HEAD(&prefs->list); link != &prefs->list;
  650.              link = PR_NEXT_LINK(link)) {
  651.             PrefItemNode* node = (PrefItemNode*)link;
  652.             if (PL_strcmp(node->item->key, key) == 0) {
  653.                 /* found the key */
  654.                 return pref_reset_value(&node->item->value, value);
  655.             }
  656.         }
  657.     }
  658.     /* either the list was empty or the key was not found */
  659.     return pref_append_pref_unlocked(prefs, key, value);
  660. }
  661. /* Compare (value) with the stored value under (key)
  662.  * - returns PR_TRUE if the key does not exist or the values do not match
  663.  * - returns PR_FALSE only if the key exists and the values match
  664.  */
  665. static PRBool pref_pref_changed_unlocked(PrefSet* prefs, char* key, 
  666.                                          char* value)
  667. {
  668.     PRCList* link = NULL;
  669.     PRBool rv = PR_TRUE;
  670.     PR_ASSERT((prefs != NULL) && (key != NULL));
  671.     if (!PR_CLIST_IS_EMPTY(&prefs->list)) {
  672.         for (link = PR_LIST_HEAD(&prefs->list); link != &prefs->list;
  673.              link = PR_NEXT_LINK(link)) {
  674.             PrefItemNode* node = (PrefItemNode*)link;
  675.             if (PL_strcmp(node->item->key, key) == 0) {
  676.                 /* found the key */
  677.                 if (((value == NULL) && (node->item->value == NULL)) ||
  678.                     (value != NULL) && (node->item->value != NULL) &&
  679.                     (PL_strcmp(node->item->value, value) == 0)) {
  680.                     rv = PR_FALSE;
  681.                 }
  682.                 goto done;
  683.             }
  684.         }
  685.         /* exhausted the list but could not find the key */
  686.     }
  687. done:
  688.     return rv;
  689. }
  690. static void pref_clean_out_list(PRCList* list)
  691. {
  692.     PRCList* link = NULL;
  693.     PR_ASSERT(list != NULL);
  694.     if (PR_CLIST_IS_EMPTY(list)) {
  695.         /* we're already done */
  696.         return;
  697.     }
  698.     link = PR_LIST_HEAD(list); 
  699.     while (link != list) {
  700.         PrefItemNode* node = (PrefItemNode*)link;
  701.         pref_free_pref_item(node->item);
  702.         link = PR_NEXT_LINK(link);
  703.         if (node != NULL) {
  704.             PR_Free(node);
  705.         }
  706.     }
  707.     return;
  708. }
  709. PrefSet* PREF_NewPrefs(void)
  710. {
  711.     SSMStatus status;
  712.     PrefSet* prefs = NULL;
  713.     int i;
  714.     /* initialize the structure */
  715.     prefs = (PrefSet*)PR_NEWZAP(PrefSet);
  716.     if (prefs == NULL) {
  717.         goto loser;
  718.     }
  719.     prefs->lock = PR_NewLock();
  720.     if (prefs->lock == NULL) {
  721.         goto loser;
  722.     }
  723.     PR_INIT_CLIST(&prefs->list);
  724.     /* fill the list with default data */
  725.     for (i = 0; pref_defaults[i].key != NULL; i++) {
  726.         PR_Lock(prefs->lock);
  727.         status = pref_append_pref_unlocked(prefs, pref_defaults[i].key,
  728.                                            pref_defaults[i].value);
  729.         PR_Unlock(prefs->lock);
  730.         if (status != PR_SUCCESS) {
  731.             goto loser;
  732.         }
  733.     }
  734.     return prefs;
  735. loser:
  736.     if (prefs != NULL) {
  737.         if (prefs->lock != NULL) {
  738.             PR_DestroyLock(prefs->lock);
  739.         }
  740.         PR_Free(prefs);
  741.     }
  742.     return NULL;
  743. }
  744. SSMStatus PREF_ClosePrefs(PrefSet* prefs)
  745. {
  746.     if (prefs == NULL) {
  747.         goto loser;
  748.     }
  749.     if (prefs->lock == NULL) {
  750.         goto loser;
  751.     }
  752.     /* clean out the list */
  753.     PR_Lock(prefs->lock);
  754.     pref_clean_out_list(&prefs->list);
  755.     PR_Unlock(prefs->lock);
  756.     PR_DestroyLock(prefs->lock);
  757.     PR_Free(prefs);
  758.     return PR_SUCCESS;
  759. loser:
  760.     return PR_FAILURE;
  761. }
  762. SSMStatus PREF_GetStringPref(PrefSet* prefs, char* key, char** value)
  763. {
  764.     SSMStatus rv;
  765.     /* in case of failure */
  766.     *value = NULL;
  767.     if ((prefs == NULL) || (key == NULL) || (value == NULL)) {
  768.         return PR_FAILURE;
  769.     }
  770.     PR_Lock(prefs->lock);
  771.     rv = pref_get_pref_unlocked(prefs, key, value);
  772.     PR_Unlock(prefs->lock);
  773.     return rv;
  774. }
  775. SSMStatus PREF_CopyStringPref(PrefSet* prefs, char* key, char** value)
  776. {
  777.     SSMStatus rv;
  778.     char* tmp = NULL;
  779.     *value = NULL;
  780.     rv = PREF_GetStringPref(prefs, key, &tmp);
  781.     if (tmp != NULL) {
  782.         *value = PL_strdup(tmp);
  783.         if (*value == NULL && rv == PR_SUCCESS) {
  784.             rv = PR_FAILURE;
  785.         }
  786.     }
  787.     return rv;
  788. }
  789. SSMStatus PREF_SetStringPref(PrefSet* prefs, char* key, char* value)
  790. {
  791.     SSMStatus rv;
  792.     if ((prefs == NULL) || (key == NULL)) {
  793.         return PR_FAILURE;
  794.     }
  795.     PR_Lock(prefs->lock);
  796.     rv = pref_set_pref_unlocked(prefs, key, value);
  797.     PR_Unlock(prefs->lock);
  798.     return rv;
  799. }
  800. PRBool PREF_StringPrefChanged(PrefSet* prefs, char* key, char* value)
  801. {
  802.     PRBool rv;
  803.     PR_ASSERT((prefs != NULL) && (key != NULL));
  804.     if ((prefs == NULL) || (key == NULL)) {
  805.         return PR_TRUE; /* this really is an error */
  806.     }
  807.     PR_Lock(prefs->lock);
  808.     rv = pref_pref_changed_unlocked(prefs, key, value);
  809.     PR_Unlock(prefs->lock);
  810.     return rv;
  811. }
  812. SSMStatus PREF_GetBoolPref(PrefSet* prefs, char* key, PRBool* value)
  813. {
  814.     SSMStatus rv;
  815.     char* tmp = NULL;
  816.     if ((prefs == NULL) || (key == NULL) || (value == NULL)) {
  817.         return PR_FAILURE;
  818.     }
  819.     PR_Lock(prefs->lock);
  820.     rv = pref_get_pref_unlocked(prefs, key, &tmp);
  821.     PR_Unlock(prefs->lock);
  822.     if (rv != PR_SUCCESS) {
  823.         /* pref item was not found */
  824.         return rv;
  825.     }
  826.     if (PL_strcmp(tmp, STRING_TRUE) == 0) {
  827.         *value = PR_TRUE;
  828.     }
  829.     else if (PL_strcmp(tmp, STRING_FALSE) == 0) {
  830.         *value = PR_FALSE;
  831.     }
  832.     else {
  833.         return PR_FAILURE;
  834.     }
  835.     return PR_SUCCESS;
  836. }
  837. SSMStatus PREF_SetBoolPref(PrefSet* prefs, char* key, PRBool value)
  838. {
  839.     SSMStatus rv;
  840.     char* tmp = NULL;
  841.     if ((prefs == NULL) || (key == NULL)) {
  842.         return PR_FAILURE;
  843.     }
  844.     if (value == PR_FALSE) {
  845.         tmp = STRING_FALSE;
  846.     }
  847.     else if (value == PR_TRUE) {
  848.         tmp = STRING_TRUE;
  849.     }
  850.     else {
  851.         PR_ASSERT(0);
  852.     }
  853.     PR_Lock(prefs->lock);
  854.     rv = pref_set_pref_unlocked(prefs, key, tmp);
  855.     PR_Unlock(prefs->lock);
  856.     return rv;
  857. }
  858. PRBool PREF_BoolPrefChanged(PrefSet* prefs, char* key, PRBool value)
  859. {
  860.     PRBool rv;
  861.     char* tmp = NULL;
  862.     PR_ASSERT((prefs != NULL) && (key != NULL));
  863.     if ((prefs == NULL) || (key == NULL)) {
  864.         return PR_TRUE; /* this really is an error */
  865.     }
  866.     if (value == PR_FALSE) {
  867.         tmp = STRING_FALSE;
  868.     }
  869.     else if (value == PR_TRUE) {
  870.         tmp = STRING_TRUE;
  871.     }
  872.     else {
  873.         PR_ASSERT(0);
  874.     }
  875.     PR_Lock(prefs->lock);
  876.     rv = pref_pref_changed_unlocked(prefs, key, tmp);
  877.     PR_Unlock(prefs->lock);
  878.     return rv;
  879. }
  880. SSMStatus PREF_GetIntPref(PrefSet* prefs, char* key, PRIntn* value)
  881. {
  882.     SSMStatus rv;
  883.     char* tmp = NULL;
  884.     if ((prefs == NULL) || (key == NULL) || (value == NULL)) {
  885.         return PR_FAILURE;
  886.     }
  887.     PR_Lock(prefs->lock);
  888.     rv = pref_get_pref_unlocked(prefs, key, &tmp);
  889.     PR_Unlock(prefs->lock);
  890.     if (rv != PR_SUCCESS) {
  891.         /* pref item was not found */
  892.         return rv;
  893.     }
  894.     /* convert char* into integer */
  895.     *value = atoi(tmp);
  896.     return PR_SUCCESS;
  897. }
  898. SSMStatus PREF_SetIntPref(PrefSet* prefs, char* key, PRIntn value)
  899. {
  900.     SSMStatus rv;
  901.     char* tmp = NULL;
  902.     if ((prefs == NULL) || (key == NULL)) {
  903.         return PR_FAILURE;
  904.     }
  905.     tmp = PR_smprintf("%d", value);
  906.     if (tmp == NULL) {
  907.         return PR_FAILURE;
  908.     }
  909.     PR_Lock(prefs->lock);
  910.     rv = pref_set_pref_unlocked(prefs, key, tmp);
  911.     PR_Unlock(prefs->lock);
  912.     PR_Free(tmp);
  913.     return rv;
  914. }
  915. PRBool PREF_IntPrefChanged(PrefSet* prefs, char* key, PRIntn value)
  916. {
  917.     PRBool rv;
  918.     char* tmp = NULL;
  919.     PR_ASSERT((prefs != NULL) && (key != NULL));
  920.     if ((prefs == NULL) || (key == NULL)) {
  921.         return PR_TRUE; /* this really is an error */
  922.     }
  923.     tmp = PR_smprintf("%d", value);
  924.     if (tmp == NULL) {
  925.         /* ouch... */
  926.         return PR_TRUE;
  927.     }
  928.     PR_Lock(prefs->lock);
  929.     rv = pref_pref_changed_unlocked(prefs, key, tmp);
  930.     PR_Unlock(prefs->lock);
  931.     PR_Free(tmp);
  932.     return rv;
  933. }
  934. /******************
  935.  * These functions allow to handle multiple options specified in 
  936.  * prefs. 
  937.  ******************/
  938. #include "connect.h" /* don't know what to include to use PR_Zalloc */
  939. SSMStatus pref_append_value(char *** list, char * value)
  940. {
  941.     SSMStatus rv = SSM_SUCCESS;
  942.     static int size, cursize;
  943.     if (!list || !value)
  944.         return SSM_FAILURE;
  945.     
  946.     /* Quick and dirty check if we already have that value in the list - 
  947.      * only check the value directly before. Preferences keys seem to go 
  948.      * in clusters so that might actually work untill there is a better way
  949.      */
  950.     if (*list && **list && !PL_strcmp(value, (*list)[cursize-1]))
  951.         return rv;
  952.     
  953.     if (!*list) {
  954.         size = 12;
  955.         cursize = 0;
  956.         *list = (char **)PORT_ZAlloc(sizeof(char *)* size);
  957.         if (!*list) {
  958.             rv = SSM_ERR_OUT_OF_MEMORY;
  959.             goto done;
  960.         }
  961.     }
  962.     else if (cursize == size-2) { 
  963.         size = size + 12;
  964.         *list = (char **)PR_Realloc(*list, sizeof(char *)*size);
  965.         if (!*list) {
  966.             rv = SSM_ERR_OUT_OF_MEMORY;
  967.             goto done;
  968.         }
  969.         /* clear the memory */
  970.         memset(*list+cursize, 0, sizeof(char*)*(size-cursize));
  971.     }
  972.     (*list)[cursize] = PL_strdup(value);
  973.     cursize++;
  974.     
  975.  done: 
  976.     return rv;
  977. }
  978. /****** retrieve all the values for a parent key:
  979.  * SSMStatus 
  980.  * PREF_CreateChildList(PrefSet * prefs, 
  981.  *                      const char* parent_key, 
  982.  *                      char **child_list);
  983.  * 
  984.  * For parent key x.y retrieves key names directly below x.y :
  985.  * x.y.a, x.y.b, x.y.c, etc.
  986.  *
  987.  * For parent_key == NULL returns all the preferences values. 
  988.  * (Why would anyone want to do that? )
  989.  *
  990.  * Allocates and returns char * array with all the requested values. 
  991.  * Caller is responsible for freeing memory.
  992.  *
  993.  * Used for LDAP server look-up for UI.
  994.  *****/
  995. SSMStatus PREF_CreateChildList(PrefSet * prefs, const char* parent_key, 
  996.                                char ***child_list)
  997. {
  998.     SSMStatus rv = SSM_FAILURE;
  999.     PRCList * link = NULL;
  1000.     char * child, * tmp;
  1001.     int parent_key_len = parent_key?strlen(parent_key):0;
  1002.     
  1003.     if (!prefs || !child_list) 
  1004.         goto loser;
  1005.     *child_list = NULL;
  1006.     
  1007.     /* walk the list untill find interesting key */
  1008.     if (!PR_CLIST_IS_EMPTY(&prefs->list)) {
  1009.         for (link = PR_LIST_HEAD(&prefs->list); link != &prefs->list;
  1010.              link = PR_NEXT_LINK(link)) {
  1011.             PrefItemNode* node = (PrefItemNode*)link;
  1012.             if (!parent_key || ((tmp = strstr(node->item->key, parent_key)) 
  1013.                                 && tmp[parent_key_len] == '.')) {
  1014.                 /* found the key */
  1015.                 /* append "child" string: "child" in parent.child.more */
  1016.                 child = PL_strdup(node->item->key + parent_key_len + 1);
  1017.                 tmp = strtok(child, ".");
  1018.                 rv = pref_append_value(child_list, tmp);
  1019.                 PR_Free(child);
  1020.                 if (rv != SSM_SUCCESS) 
  1021.                     goto loser;
  1022.             }
  1023.         }
  1024.     }
  1025.     rv = SSM_SUCCESS;
  1026.  loser:
  1027.     return rv;
  1028. }
  1029. #endif    /* PREFS LITE (tm) */