Logoj0ke.net Open Build Service > Projects > mozilla > MozillaFirefox > gconf-backend.patch
Sign Up | Log In

File gconf-backend.patch of Package MozillaFirefox (Revision cc8a583026d31644cd2a5e0ac710ddd6)

Currently displaying revision cc8a583026d31644cd2a5e0ac710ddd6, show latest

x
 
1
Index: extensions/pref/system-pref/src/nsSystemPref.h
2
================================================================================
3
--- browser/installer/unix/packages-static
4
+++ browser/installer/unix/packages-static
5
@@ -210,6 +210,7 @@
6
 bin/components/nsUpdateService.js
7
 bin/components/extensions.xpt
8
 bin/components/update.xpt
9
+bin/components/libsystem-pref-gconf.so
10
 bin/components/nsBookmarkTransactionManager.js
11
 bin/components/nsSessionStartup.js
12
 bin/components/nsSessionStore.js
13
--- config/autoconf.mk.in
14
+++ config/autoconf.mk.in
15
@@ -226,6 +226,7 @@
16
 MOZ_GNOMEVFS_CFLAGS = @MOZ_GNOMEVFS_CFLAGS@
17
 MOZ_GNOMEVFS_LIBS = @MOZ_GNOMEVFS_LIBS@
18
 
19
+MOZ_ENABLE_GCONF = @MOZ_ENABLE_GCONF@
20
 MOZ_GCONF_CFLAGS = @MOZ_GCONF_CFLAGS@
21
 MOZ_GCONF_LIBS = @MOZ_GCONF_LIBS@
22
 
23
--- configure.in
24
+++ configure.in
25
@@ -4709,6 +4709,7 @@
26
         ])
27
     fi
28
 
29
+    AC_SUBST(MOZ_ENABLE_GCONF)
30
     AC_SUBST(MOZ_GCONF_CFLAGS)
31
     AC_SUBST(MOZ_GCONF_LIBS)
32
 
33
--- extensions/pref/system-pref/src/Makefile.in
34
+++ extensions/pref/system-pref/src/Makefile.in
35
@@ -47,14 +47,13 @@
36
 include $(DEPTH)/config/autoconf.mk
37
 
38
 MODULE = system-pref
39
-LIBRARY_NAME = system-pref_s
40
+LIBRARY_NAME = system-pref
41
 ifneq ($(OS_ARCH),WINNT)
42
 SHORT_LIBNAME = syspref
43
 endif
44
 
45
-# We want to force the creation of a static lib.
46
-FORCE_STATIC_LIB = 1
47
 MOZILLA_INTERNAL_API = 1
48
+GRE_MODULE = 1
49
 
50
 REQUIRES        = xpcom \
51
          string \
52
@@ -62,27 +61,25 @@
53
          pref \
54
          $(NULL)
55
 
56
-ifdef MOZ_ENABLE_GTK2
57
+ifdef MOZ_ENABLE_GCONF
58
 DIRS       = gconf
59
 endif
60
 
61
-EXTRA_DSO_LDOPTS = \
62
-       -L$(DIST)/bin \
63
-       $(MOZ_COMPONENT_LIBS) \
64
-       $(NULL)
65
-
66
 CPPSRCS =   \
67
   nsSystemPref.cpp    \
68
+  nsSystemPrefFactory.cpp  \
69
   $(NULL)
70
 
71
+EXTRA_DSO_LDOPTS = \
72
+       $(MOZ_COMPONENT_LIBS) \
73
+       $(NULL)
74
+
75
 EXPORTS        = \
76
-       nsSystemPrefLog.h \
77
+       nsISystemPrefService.h \
78
        $(NULL)
79
 
80
-include $(topsrcdir)/config/rules.mk
81
+EXPORT_LIBRARY = 1
82
+IS_COMPONENT = 1
83
+MODULE_NAME     = nsSystemPrefModule
84
 
85
-ifdef MOZ_ENABLE_GTK2
86
-INCLUDES   += \
87
-       -I$(srcdir)/gconf \
88
-       $(NULL)
89
-endif
90
+include $(topsrcdir)/config/rules.mk
91
--- extensions/pref/system-pref/src/gconf/Makefile.in
92
+++ extensions/pref/system-pref/src/gconf/Makefile.in
93
@@ -46,44 +46,36 @@
94
 
95
 include $(DEPTH)/config/autoconf.mk
96
 
97
-MODULE = system-pref
98
-LIBRARY_NAME = system-pref
99
+MODULE = system-pref-gconf
100
+LIBRARY_NAME = system-pref-gconf
101
 GRE_MODULE = 1
102
 MOZILLA_INTERNAL_API = 1
103
 
104
+PACKAGE_FILE = gconf.pkg
105
+
106
 REQUIRES        = pref \
107
+         system-pref \
108
          string \
109
          xpcom \
110
          embedcomponents \
111
+         necko \
112
          $(NULL)
113
 
114
 CPPSRCS =   \
115
    nsSystemPrefService.cpp       \
116
-   nsSystemPrefFactory.cpp \
117
    $(NULL)
118
 
119
-SHARED_LIBRARY_LIBS = $(DIST)/lib/libsystem-pref_s.a
120
-
121
 EXTRA_DSO_LDOPTS = \
122
-       -L$(DIST)/bin \
123
        $(MOZ_COMPONENT_LIBS) \
124
-       $(MOZ_GTK2_LIBS) \
125
+       $(MOZ_GTK2_LIBS)      \
126
+       $(MOZ_GCONF_LIBS)     \
127
        $(NULL)
128
 
129
-EXPORT_LIBRARY = 1
130
+#EXPORT_LIBRARY = 1
131
 IS_COMPONENT = 1
132
-MODULE_NAME    = nsSystemPrefModule
133
-
134
-EXPORTS        = \
135
-       nsSystemPrefService.h \
136
-       $(NULL)
137
+FORCE_SHARED_LIB = 1
138
 
139
 include $(topsrcdir)/config/rules.mk
140
 
141
-CFLAGS     += $(MOZ_GTK2_CFLAGS)
142
-CXXFLAGS   += $(MOZ_GTK2_CFLAGS)
143
-
144
-LOCAL_INCLUDES = -I$(srcdir)/..
145
-
146
-export::
147
-   $(INSTALL) $(srcdir)/../nsSystemPrefFactory.cpp .
148
+CFLAGS          += $(MOZ_GTK2_CFLAGS) $(MOZ_GCONF_CFLAGS)
149
+CXXFLAGS        += $(MOZ_GTK2_CFLAGS) $(MOZ_GCONF_CFLAGS)
150
--- extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
151
+++ extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
152
@@ -23,7 +23,7 @@
153
  *
154
  * Original Author: Bolian Yin (bolian.yin@sun.com)
155
  *
156
- * Contributor(s):
157
+ * Contributor(s): Robert O'Callahan/Novell (rocallahan@novell.com)
158
  *
159
  * Alternatively, the contents of this file may be used under the terms of
160
  * either the GNU General Public License Version 2 or later (the "GPL"), or
161
@@ -41,6 +41,7 @@
162
 
163
 #include <glib.h>
164
 #include <glib-object.h>
165
+#include <gconf/gconf-client.h>
166
 
167
 #include "plstr.h"
168
 #include "nsCOMPtr.h"
169
@@ -48,837 +49,1259 @@
170
 #include "nsIServiceManager.h"
171
 #include "nsIObserver.h"
172
 #include "nsWeakReference.h"
173
-
174
+#include "nsIPrefBranch2.h"
175
+#include "nsISystemPrefService.h"
176
+#include "nsDataHashtable.h"
177
+#include "nsHashKeys.h"
178
+#include "nsICategoryManager.h"
179
+#include "nsIGenericFactory.h"
180
 #include "nsString.h"
181
-#include "nsSystemPrefLog.h"
182
-#include "nsSystemPrefService.h"
183
-
184
-/*************************************************************************
185
- * The strange thing here is that we load the gconf library manually and 
186
- * search the function pointers we need. If that process fails, no gconf
187
- * support is available in mozilla. The aim is to make mozilla independent
188
- * on gconf, in both compile time and run time.
189
- ************************************************************************/
190
-
191
-//gconf types
192
-extern "C" {
193
-
194
-    typedef enum {
195
-        GCONF_VALUE_INVALID,
196
-        GCONF_VALUE_STRING,
197
-        GCONF_VALUE_INT,
198
-        GCONF_VALUE_FLOAT,
199
-        GCONF_VALUE_BOOL,
200
-        GCONF_VALUE_SCHEMA,
201
-
202
-        GCONF_VALUE_LIST,
203
-        GCONF_VALUE_PAIR
204
-
205
-    }GConfValueType;
206
-
207
-    typedef struct {
208
-        GConfValueType type;
209
-    }GConfValue;
210
-
211
-    typedef void * (*GConfClientGetDefaultType) (void);
212
-    typedef PRBool (*GConfClientGetBoolType) (void *client, const gchar *key,
213
-                                              GError **err);
214
-    typedef gchar* (*GConfClientGetStringType) (void *client, const gchar *key,
215
-                                                GError **err);
216
-    typedef PRInt32 (*GConfClientGetIntType) (void *client, const gchar *key,
217
-                                              GError **err);
218
-    typedef  void (*GConfClientNotifyFuncType) (void* client, guint cnxn_id,
219
-                                                void *entry, 
220
-                                                gpointer user_data);
221
-    typedef guint (*GConfClientNotifyAddType) (void* client,
222
-                                               const gchar* namespace_section,
223
-                                               GConfClientNotifyFuncType func,
224
-                                               gpointer user_data,
225
-                                               GFreeFunc destroy_notify,
226
-                                               GError** err);
227
-    typedef void (*GConfClientNotifyRemoveType) (void *client,
228
-                                                 guint cnxn);
229
-    typedef void (*GConfClientAddDirType) (void *client,
230
-                                           const gchar *dir,
231
-                                           guint8 preload,
232
-                                           GError **err);
233
-    typedef void (*GConfClientRemoveDirType) (void *client,
234
-                                              const gchar *dir,
235
-                                              GError **err);
236
-
237
-    typedef const char* (*GConfEntryGetKeyType) (const void *entry);
238
-    typedef GConfValue* (*GConfEntryGetValueType) (const void *entry);
239
-
240
-    typedef const char* (*GConfValueGetStringType) (const GConfValue *value);
241
-    typedef PRInt32 (*GConfValueGetIntType) (const GConfValue *value);
242
-    typedef PRBool (*GConfValueGetBoolType) (const GConfValue *value);
243
+#include "nsIPermissionManager.h"
244
 
245
-    
246
-    static void gconf_key_listener (void* client, guint cnxn_id,
247
-                                    void *entry, gpointer user_data);
248
-}
249
+#define NS_SYSTEMPREF_SERVICE_CID                  \
250
+  { /* {3724e748-b088-4bf8-9298-aad426b66293} */       \
251
+    0x3724e748,                                        \
252
+    0xb088,                                            \
253
+    0x4bf8,                                            \
254
+        { 0x92, 0x98, 0xaa, 0xd4, 0x26, 0xb6, 0x62, 0x93 } \
255
+  }
256
+
257
+#define NS_SYSTEMPREF_SERVICE_CLASSNAME "System Preferences Platform Service"
258
+
259
+/**
260
+ * We can link directly to the gconf library. If it's not available,
261
+ * this component just won't load and no system prefs will be offered.
262
+ */
263
+
264
+#define NUM_ELEM(a) (sizeof(a)/sizeof(a[0]))
265
+
266
+class nsSystemPrefService;
267
+
268
+/**
269
+ * List the preferences that have a simple mapping between Moz and gconf.
270
+ * These preferences have the same meaning and their values are
271
+ * automatically converted.
272
+ */
273
+struct SimplePrefMapping {
274
+    const char *mozPrefName;
275
+    const char *gconfPrefName;
276
+    /**
277
+     * If this is PR_FALSE, then we never allow Mozilla to change
278
+     * this setting. The Mozilla pref will always be locked.
279
+     * If this is PR_TRUE then Mozilla will be allowed to change
280
+     * the setting --- but only if it is writable in gconf.
281
+     */
282
+    PRBool allowWritesFromMozilla;
283
+};
284
+typedef nsresult (* ComplexGConfPrefChanged)(nsSystemPrefService* aPrefService,
285
+                                             GConfClient* aClient);
286
+typedef nsresult (* ComplexMozPrefChanged)(nsSystemPrefService* aPrefService,
287
+                                           GConfClient* aClient);
288
+struct ComplexGConfPrefMapping {
289
+    const char* gconfPrefName;
290
+    ComplexGConfPrefChanged callback;
291
+};
292
 
293
-struct GConfCallbackData
294
-{
295
-    GConfProxy *proxy;
296
-    void * userData;
297
-    PRUint32 atom;
298
-    PRUint32 notifyId;
299
+struct ComplexMozPrefMapping {
300
+    const char* mozPrefName;
301
+    ComplexMozPrefChanged callback;
302
 };
303
-//////////////////////////////////////////////////////////////////////
304
-// GConPrxoy is a thin wrapper for easy use of gconf funcs. It loads the
305
-// gconf library and initializes the func pointers for later use.
306
-//////////////////////////////////////////////////////////////////////
307
-class GConfProxy
308
+
309
+class nsSystemPrefService : public nsISystemPrefService
310
 {
311
 public:
312
-    GConfProxy(nsSystemPrefService* aSysPrefService);
313
-    ~GConfProxy();
314
-    PRBool Init();
315
-
316
-    nsresult GetBoolPref(const char *aMozKey, PRBool *retval);
317
-    nsresult GetCharPref(const char *aMozKey, char **retval);
318
-    nsresult GetIntPref(const char *aMozKey, PRInt32 *retval);
319
+    NS_DECL_ISUPPORTS
320
 
321
-    nsresult NotifyAdd (PRUint32 aAtom, void *aUserData);
322
-    nsresult NotifyRemove (PRUint32 aAtom, const void *aUserData);
323
+    nsresult Init();
324
 
325
-    nsresult GetAtomForMozKey(const char *aMozKey, PRUint32 *aAtom) {
326
-        return GetAtom(aMozKey, 0, aAtom); 
327
-    }
328
-    const char *GetMozKey(PRUint32 aAtom) {
329
-        return GetKey(aAtom, 0); 
330
+    virtual nsresult LoadSystemPreferences(nsISystemPref* aPrefs);
331
+    virtual nsresult NotifyMozillaPrefChanged(const char* aPrefName);
332
+    virtual nsresult NotifyUnloadSystemPreferences();
333
+
334
+    nsSystemPrefService();
335
+    virtual ~nsSystemPrefService();
336
+
337
+    nsISystemPref* GetPrefs() { return mPref; }
338
+    SimplePrefMapping* GetSimpleCallbackData(PRUint32 aKey) {
339
+      SimplePrefMapping* result = nsnull;
340
+      mGConfSimpleCallbacks.Get(aKey, &result);
341
+      return result;
342
+    }
343
+    ComplexGConfPrefMapping* GetComplexCallbackData(PRUint32 aKey) {
344
+      ComplexGConfPrefMapping* result = nsnull;
345
+      mGConfComplexCallbacks.Get(aKey, &result);
346
+      return result;
347
     }
348
 
349
-    void OnNotify(void *aClient, void * aEntry, PRUint32 aNotifyId,
350
-                  GConfCallbackData *aData);
351
-
352
 private:
353
-    void *mGConfClient;
354
-    PRLibrary *mGConfLib;
355
-    PRBool mInitialized;
356
-    nsSystemPrefService *mSysPrefService;
357
-
358
-    //listeners
359
-    nsAutoVoidArray *mObservers;
360
-
361
-    void InitFuncPtrs();
362
-    //gconf public func ptrs
363
-
364
-    //gconf client funcs
365
-    GConfClientGetDefaultType GConfClientGetDefault;
366
-    GConfClientGetBoolType GConfClientGetBool;
367
-    GConfClientGetStringType GConfClientGetString;
368
-    GConfClientGetIntType GConfClientGetInt;
369
-    GConfClientNotifyAddType GConfClientNotifyAdd;
370
-    GConfClientNotifyRemoveType GConfClientNotifyRemove;
371
-    GConfClientAddDirType GConfClientAddDir;
372
-    GConfClientRemoveDirType GConfClientRemoveDir;
373
-
374
-    //gconf entry funcs
375
-    GConfEntryGetValueType GConfEntryGetValue;
376
-    GConfEntryGetKeyType GConfEntryGetKey;
377
-
378
-    //gconf value funcs
379
-    GConfValueGetBoolType GConfValueGetBool;
380
-    GConfValueGetStringType GConfValueGetString;
381
-    GConfValueGetIntType GConfValueGetInt;
382
-
383
-    //pref name translating stuff
384
-    nsresult GetAtom(const char *aKey, PRUint8 aNameType, PRUint32 *aAtom);
385
-    nsresult GetAtomForGConfKey(const char *aGConfKey, PRUint32 *aAtom) \
386
-    {return GetAtom(aGConfKey, 1, aAtom);}
387
-    const char *GetKey(PRUint32 aAtom, PRUint8 aNameType);
388
-    const char *GetGConfKey(PRUint32 aAtom) \
389
-    {return GetKey(aAtom, 1); }
390
-    inline const char *MozKey2GConfKey(const char *aMozKey);
391
-
392
-    //const strings
393
-    static const char sPrefGConfKey[];
394
-    static const char sDefaultLibName1[];
395
-    static const char sDefaultLibName2[];
396
+    nsISystemPref* mPref;
397
+    nsDataHashtable<nsUint32HashKey, SimplePrefMapping*> mGConfSimpleCallbacks;
398
+    nsDataHashtable<nsUint32HashKey, ComplexGConfPrefMapping*> mGConfComplexCallbacks;
399
+    // This is set to PR_FALSE temporarily to stop listening to gconf
400
+    // change notifications (while we change gconf values)
401
+    PRPackedBool mListenToGConf;
402
 };
403
 
404
-struct SysPrefCallbackData {
405
-    nsISupports *observer;
406
-    PRBool bIsWeakRef;
407
-    PRUint32 prefAtom;
408
-};
409
-
410
-PRBool PR_CALLBACK
411
-sysPrefDeleteObserver(void *aElement, void *aData) {
412
-    SysPrefCallbackData *pElement =
413
-        NS_STATIC_CAST(SysPrefCallbackData *, aElement);
414
-    NS_RELEASE(pElement->observer);
415
-    nsMemory::Free(pElement);
416
-    return PR_TRUE;
417
-}
418
-
419
-NS_IMPL_ISUPPORTS2(nsSystemPrefService, nsIPrefBranch, nsIPrefBranch2)
420
-
421
-/* public */
422
 nsSystemPrefService::nsSystemPrefService()
423
-    :mInitialized(PR_FALSE),
424
-     mGConf(nsnull),
425
-     mObservers(nsnull)
426
+    : mPref(nsnull), mListenToGConf(PR_TRUE)
427
 {
428
+    mGConfSimpleCallbacks.Init();
429
+    mGConfComplexCallbacks.Init();
430
 }
431
 
432
 nsSystemPrefService::~nsSystemPrefService()
433
 {
434
-    mInitialized = PR_FALSE;
435
-
436
-    if (mGConf)
437
-        delete mGConf;
438
-    if (mObservers) {
439
-        (void)mObservers->EnumerateForwards(sysPrefDeleteObserver, nsnull);
440
-        delete mObservers;
441
-    }
442
+    NotifyUnloadSystemPreferences();
443
 }
444
 
445
 nsresult
446
 nsSystemPrefService::Init()
447
 {
448
-    if (!gSysPrefLog) {
449
-        gSysPrefLog = PR_NewLogModule("Syspref");
450
-        if (!gSysPrefLog) return NS_ERROR_OUT_OF_MEMORY;
451
-    }
452
-
453
-    SYSPREF_LOG(("Init SystemPref Service\n"));
454
-    if (mInitialized)
455
-        return NS_ERROR_FAILURE;
456
-
457
-    if (!mGConf) {
458
-        mGConf = new GConfProxy(this);
459
-        if (!mGConf->Init()) {
460
-            delete mGConf;
461
-            mGConf = nsnull;
462
-            return NS_ERROR_FAILURE;
463
-        }
464
-    }
465
-
466
-    mInitialized = PR_TRUE;
467
     return NS_OK;
468
 }
469
 
470
-/* readonly attribute string root; */
471
-NS_IMETHODIMP nsSystemPrefService::GetRoot(char * *aRoot)
472
-{
473
-    return NS_ERROR_NOT_IMPLEMENTED;
474
-}
475
+NS_IMPL_ISUPPORTS1(nsSystemPrefService, nsISystemPrefService)
476
 
477
-/* long getPrefType (in string aPrefName); */
478
-NS_IMETHODIMP nsSystemPrefService::GetPrefType(const char *aPrefName, PRInt32 *_retval)
479
-{
480
-    return NS_ERROR_NOT_IMPLEMENTED;
481
+static GConfClient* GetGConf() {
482
+    return gconf_client_get_default();
483
 }
484
 
485
-/* boolean getBoolPref (in string aPrefName); */
486
-NS_IMETHODIMP nsSystemPrefService::GetBoolPref(const char *aPrefName, PRBool *_retval)
487
+static PRBool VerifyMatchingTypes(nsISystemPref* aPrefs,
488
+                                  const char* aMozPref, GConfValue* aVal)
489
 {
490
-    return mInitialized ?
491
-        mGConf->GetBoolPref(aPrefName, _retval) : NS_ERROR_FAILURE;
492
-}
493
+    nsCOMPtr<nsIPrefBranch2> prefBranch = aPrefs->GetPrefUserBranch();
494
+    PRInt32 type;
495
+    nsresult rv = prefBranch->GetPrefType(aMozPref, &type);
496
+    if (NS_FAILED(rv)) {
497
+        // pref probably doesn't exist. Let gconf set it.
498
+        return PR_TRUE;
499
+    }
500
 
501
-/* void setBoolPref (in string aPrefName, in long aValue); */
502
-NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRInt32 aValue)
503
-{
504
-    return NS_ERROR_NOT_IMPLEMENTED;
505
+    PRBool ok;
506
+    switch (aVal->type) {
507
+    case GCONF_VALUE_STRING:
508
+        ok = type == nsIPrefBranch2::PREF_STRING;
509
+        break;
510
+    case GCONF_VALUE_INT:
511
+        ok = type == nsIPrefBranch2::PREF_INT;
512
+        break;
513
+    case GCONF_VALUE_BOOL:
514
+        ok = type == nsIPrefBranch2::PREF_BOOL;
515
+        break;
516
+    default:
517
+        NS_ERROR("Unhandled gconf preference type");
518
+        return PR_FALSE;
519
+    }
520
+    
521
+    NS_ASSERTION(ok, "Mismatched gconf/Mozilla pref types");
522
+    return ok;
523
 }
524
 
525
-/* string getCharPref (in string aPrefName); */
526
-NS_IMETHODIMP nsSystemPrefService::GetCharPref(const char *aPrefName, char **_retval)
527
-{
528
-    return mInitialized ?
529
-        mGConf->GetCharPref(aPrefName, _retval) : NS_ERROR_FAILURE;
530
-}
531
+/**
532
+ * Map a gconf pref value into the corresponding Mozilla pref.
533
+ */
534
+static nsresult ApplySimpleMapping(SimplePrefMapping* aMap,
535
+                                   nsISystemPref* aPrefs,
536
+                                   GConfClient* aClient)
537
+{
538
+    GConfValue* val = gconf_client_get(aClient, aMap->gconfPrefName, nsnull);
539
+    if (!val) {
540
+        // No gconf key, so there's really nothing to do
541
+        return NS_OK;
542
+    }
543
 
544
-/* void setCharPref (in string aPrefName, in string aValue); */
545
-NS_IMETHODIMP nsSystemPrefService::SetCharPref(const char *aPrefName, const char *aValue)
546
-{
547
-    return NS_ERROR_NOT_IMPLEMENTED;
548
-}
549
+    VerifyMatchingTypes(aPrefs, aMap->mozPrefName, val);
550
 
551
-/* long getIntPref (in string aPrefName); */
552
-NS_IMETHODIMP nsSystemPrefService::GetIntPref(const char *aPrefName, PRInt32 *_retval)
553
-{
554
-    return mInitialized ?
555
-        mGConf->GetIntPref(aPrefName, _retval) : NS_ERROR_FAILURE;
556
-}
557
+    PRBool locked = !aMap->allowWritesFromMozilla ||
558
+        !gconf_client_key_is_writable(aClient, aMap->gconfPrefName, nsnull);
559
+    nsresult rv;
560
+    switch (val->type) {
561
+    case GCONF_VALUE_STRING: {
562
+        const char* str = gconf_value_get_string(val);
563
+        rv = aPrefs->SetOverridingMozillaStringPref(aMap->mozPrefName, str, locked);
564
+        // XXX do we need to free 'str' here?
565
+        break;
566
+    }
567
+    case GCONF_VALUE_INT:
568
+        rv = aPrefs->SetOverridingMozillaIntPref(aMap->mozPrefName,
569
+                                                 gconf_value_get_int(val), locked);
570
+        break;
571
+    case GCONF_VALUE_BOOL:
572
+        rv = aPrefs->SetOverridingMozillaBoolPref(aMap->mozPrefName,
573
+                                                  gconf_value_get_bool(val), locked);
574
+        break;
575
+    default:
576
+        NS_ERROR("Unusable gconf value type");
577
+        rv = NS_ERROR_FAILURE;
578
+        break;
579
+    }
580
+        
581
+    gconf_value_free(val);
582
+    return rv;
583
+}
584
+
585
+/**
586
+ * Map a Mozilla pref into the corresponding gconf pref, if
587
+ * that's allowed.
588
+ */
589
+static nsresult ReverseApplySimpleMapping(SimplePrefMapping* aMap,
590
+                                          nsISystemPref* aPrefs,
591
+                                          GConfClient* aClient)
592
+{
593
+    // Verify that the gconf key has the right type, if it exists
594
+    GConfValue* val = gconf_client_get(aClient, aMap->gconfPrefName, nsnull);
595
+    if (val) {
596
+        VerifyMatchingTypes(aPrefs, aMap->mozPrefName, val);
597
+        gconf_value_free(val);
598
+    }
599
+
600
+    PRBool writable = aMap->allowWritesFromMozilla &&
601
+        gconf_client_key_is_writable(aClient, aMap->gconfPrefName, nsnull);
602
+    if (!writable) {
603
+        NS_ERROR("Gconf key is not writable");
604
+        return NS_ERROR_FAILURE;
605
+    }
606
 
607
-/* void setIntPref (in string aPrefName, in long aValue); */
608
-NS_IMETHODIMP nsSystemPrefService::SetIntPref(const char *aPrefName, PRInt32 aValue)
609
-{
610
-    return NS_ERROR_NOT_IMPLEMENTED;
611
-}
612
+    nsCOMPtr<nsIPrefBranch2> prefBranch = aPrefs->GetPrefUserBranch();
613
+    PRInt32 type;
614
+    nsresult rv = prefBranch->GetPrefType(aMap->mozPrefName, &type);
615
+    if (NS_FAILED(rv)) {
616
+        NS_ERROR("Writing back a pref that doesn't exist?");
617
+        return rv;
618
+    }
619
 
620
-/* void getComplexValue (in string aPrefName, in nsIIDRef aType, [iid_is (aType), retval] out nsQIResult aValue); */
621
-NS_IMETHODIMP nsSystemPrefService::GetComplexValue(const char *aPrefName, const nsIID & aType, void * *aValue)
622
-{
623
-    return NS_ERROR_NOT_IMPLEMENTED;
624
-}
625
+    switch (type) {
626
+    case nsIPrefBranch2::PREF_STRING:
627
+        {
628
+            char* result;
629
+            rv = prefBranch->GetCharPref(aMap->mozPrefName, &result);
630
+            if (NS_FAILED(rv))
631
+                return rv;
632
 
633
-/* void setComplexValue (in string aPrefName, in nsIIDRef aType, in nsISupports aValue); */
634
-NS_IMETHODIMP nsSystemPrefService::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
635
-{
636
-    return NS_ERROR_NOT_IMPLEMENTED;
637
-}
638
+            gconf_client_set_string(aClient, aMap->gconfPrefName, result, nsnull);
639
+            nsMemory::Free(result);
640
+        }
641
+        break;
642
+    case nsIPrefBranch2::PREF_INT:
643
+        {
644
+            PRInt32 result;
645
+            rv = prefBranch->GetIntPref(aMap->mozPrefName, &result);
646
+            if (NS_FAILED(rv))
647
+                return rv;
648
 
649
-/* void clearUserPref (in string aPrefName); */
650
-NS_IMETHODIMP nsSystemPrefService::ClearUserPref(const char *aPrefName)
651
-{
652
-    return NS_ERROR_NOT_IMPLEMENTED;
653
-}
654
+            gconf_client_set_int(aClient, aMap->gconfPrefName, result, nsnull);
655
+        }
656
+        break;
657
+    case nsIPrefBranch2::PREF_BOOL:
658
+        {
659
+            PRBool result;
660
+            rv = prefBranch->GetBoolPref(aMap->mozPrefName, &result);
661
+            if (NS_FAILED(rv))
662
+                return rv;
663
 
664
-/* void lockPref (in string aPrefName); */
665
-NS_IMETHODIMP nsSystemPrefService::LockPref(const char *aPrefName)
666
-{
667
-    return NS_ERROR_NOT_IMPLEMENTED;
668
-}
669
+            gconf_client_set_bool(aClient, aMap->gconfPrefName, result, nsnull);
670
+        }
671
+        break;
672
+    default:
673
+        NS_ERROR("Unhandled gconf preference type");
674
+        return NS_ERROR_FAILURE;
675
+    }
676
 
677
-/* boolean prefHasUserValue (in string aPrefName); */
678
-NS_IMETHODIMP nsSystemPrefService::PrefHasUserValue(const char *aPrefName, PRBool *_retval)
679
-{
680
-    return NS_ERROR_NOT_IMPLEMENTED;
681
+    return NS_OK;
682
 }
683
 
684
-/* boolean prefIsLocked (in string aPrefName); */
685
-NS_IMETHODIMP nsSystemPrefService::PrefIsLocked(const char *aPrefName, PRBool *_retval)
686
-{
687
-    return NS_ERROR_NOT_IMPLEMENTED;
688
-}
689
+/* BEGIN preference mapping definition area
690
+ *
691
+ * There are a few rules that our preference maps have to obey:
692
+ *
693
+ * 1) Each mapping defines a relationship R between a set of GConf preferences and
694
+ * a set of Mozilla preferences that must *always* be true. Thus, when a Mozilla
695
+ * pref changes or a gconf pref changes, we may need to change something on the
696
+ * other side to preserve R. If a GConf preference is read-only, then we may
697
+ * need to lock one or more Mozilla preferences to avoid a situation where the
698
+ * Mozilla preference changes and we can't update the GConf preference to
699
+ * ensure R continues to hold.
700
+ *
701
+ * 2) If an unlocked Mozilla preference is changed, then we can only
702
+ * preserve R by changing GConf preferences; we are not allowed to
703
+ * change Mozilla preferences.
704
+ *
705
+ * 3) If a GConf preference is changed, then we can only preserve R by
706
+ * changing Moozilla preferences; we are nt allowed to change GConf
707
+ * preferences.
708
+ *
709
+ * For "simple" mappings, the relationship R is just of the form
710
+ * "GConf preference 'A' is equal to Mozilla preference 'B'". R is
711
+ * preserved by setting A to B when B changes, and by setting B to A
712
+ * when A changes. If A is read-only then we lock B (or we may just
713
+ * decide to lock B for other reasons). Thus rules 1-3 are satisfied.
714
+ *
715
+ * For "complex" mappings we have more complicated
716
+ * relationships. These are documented below.
717
+ */
718
+
719
+static SimplePrefMapping sSimplePrefMappings[] = {
720
+    // GNOME proxy settings; allow these to be set through the Firefox UI
721
+    {"network.proxy.http", "/system/http_proxy/host", PR_TRUE},
722
+    {"network.proxy.http_port", "/system/http_proxy/port", PR_TRUE},
723
+    {"network.proxy.ftp", "/system/proxy/ftp_host", PR_TRUE},
724
+    {"network.proxy.ftp_port", "/system/proxy/ftp_port", PR_TRUE},
725
+    {"network.proxy.ssl", "/system/proxy/secure_host", PR_TRUE},
726
+    {"network.proxy.ssl_port", "/system/proxy/secure_port", PR_TRUE},
727
+    {"network.proxy.socks", "/system/proxy/socks_host", PR_TRUE},
728
+    {"network.proxy.socks_port", "/system/proxy/socks_port", PR_TRUE},
729
+    {"network.proxy.autoconfig_url", "/system/proxy/autoconfig_url", PR_TRUE},
730
+    
731
+    // GNOME accessibility setting; never allow this to be set by Firefox
732
+    {"config.use_system_prefs.accessibility",
733
+     "/desktop/gnome/interface/accessibility", PR_FALSE},
734
+
735
+    // GConf Firefox preferences; allow these to be set through the Firefox UI
736
+    {"security.enable_java", "/apps/firefox/web/java_enabled", PR_TRUE},
737
+    {"javascript.enabled", "/apps/firefox/web/javascript_enabled", PR_TRUE},
738
+    {"browser.startup.homepage", "/apps/firefox/general/homepage_url", PR_TRUE},
739
+    {"browser.cache.disk.capacity", "/apps/firefox/web/cache_size", PR_TRUE},
740
+    {"network.cookie.lifetimePolicy", "/apps/firefox/web/cookie_accept", PR_TRUE},
741
+
742
+    // UI lockdown settings; never allow these to be set by Firefox. There is no
743
+    // Firefox UI for these but they could otherwise be set via about:config.
744
+    {"config.lockdown.printing", "/desktop/gnome/lockdown/disable_printing", PR_FALSE},
745
+    {"config.lockdown.printsetup", "/desktop/gnome/lockdown/disable_print_setup", PR_FALSE},
746
+    {"config.lockdown.savepage", "/desktop/gnome/lockdown/disable_save_to_disk", PR_FALSE},
747
+    {"config.lockdown.history", "/apps/firefox/lockdown/disable_history", PR_FALSE},
748
+    {"config.lockdown.toolbarediting", "/apps/firefox/lockdown/disable_toolbar_editing", PR_FALSE},
749
+    {"config.lockdown.urlbar", "/apps/firefox/lockdown/disable_url_bar", PR_FALSE},
750
+    {"config.lockdown.bookmark", "/apps/firefox/lockdown/disable_bookmark_editing", PR_FALSE},
751
+    {"config.lockdown.disable_themes", "/apps/firefox/lockdown/disable_themes", PR_FALSE},
752
+    {"config.lockdown.disable_extensions", "/apps/firefox/lockdown/disable_extensions", PR_FALSE},
753
+    {"config.lockdown.searchbar", "/apps/firefox/lockdown/disable_searchbar", PR_FALSE},
754
+    {"config.lockdown.hidebookmark", "/apps/firefox/lockdown/hide_bookmark", PR_FALSE},
755
+};
756
 
757
-/* void unlockPref (in string aPrefName); */
758
-NS_IMETHODIMP nsSystemPrefService::UnlockPref(const char *aPrefName)
759
-{
760
-    return NS_ERROR_NOT_IMPLEMENTED;
761
+static nsresult ApplyListPref(nsSystemPrefService* aPrefService,
762
+                             GConfClient* aClient,
763
+                             const char* aGConfKey, const char* aMozKey,
764
+                             char aSeparator)
765
+{
766
+    GSList* list = gconf_client_get_list(aClient, aGConfKey,
767
+                                         GCONF_VALUE_STRING, nsnull);
768
+    nsCAutoString str;
769
+    for (GSList* l = list; l; l = l->next) {
770
+        str.Append((const char*)l->data);
771
+        if (l->next) {
772
+            str.Append(aSeparator);
773
+        }
774
+    }
775
+    PRBool lock = !gconf_client_key_is_writable(aClient, aGConfKey, nsnull);
776
+    nsresult rv = aPrefService->GetPrefs()->
777
+        SetOverridingMozillaStringPref(aMozKey, str.get(), lock);
778
+    // XXX does this free the strings? Should it?
779
+    g_slist_free(list);
780
+    return rv;
781
+}
782
+static nsresult ReverseApplyListPref(nsSystemPrefService* aPrefService,
783
+                                    GConfClient* aClient,
784
+                                    const char* aGConfKey, const char* aMozKey,
785
+                                    char aSeparator)
786
+{
787
+    char* data = nsnull;
788
+    nsCOMPtr<nsIPrefBranch2> prefs =
789
+        aPrefService->GetPrefs()->GetPrefUserBranch();
790
+    prefs->GetCharPref(aMozKey, &data);
791
+    if (!data)
792
+        return NS_ERROR_FAILURE;
793
+    nsresult rv = NS_OK;
794
+    GSList* list = nsnull;
795
+    PRInt32 i = 0;
796
+    while (data[i]) {
797
+        const char* nextComma = strchr(data+i, ',');
798
+        PRInt32 tokLen = nextComma ? nextComma - (data+i) : strlen(data+i);
799
+        char* tok = strndup(data+i, tokLen);
800
+        if (!tok)
801
+            break;
802
+        GSList* newList = g_slist_append(list, tok);
803
+        if (!newList) {
804
+            rv = NS_ERROR_OUT_OF_MEMORY;
805
+            break;
806
+        }
807
+        list = newList;
808
+        if (!nextComma)
809
+            break;
810
+        i = nextComma + 1 - data;
811
+    }
812
+    nsMemory::Free(data);
813
+    if (NS_SUCCEEDED(rv)) {
814
+        gconf_client_set_list(aClient, aGConfKey, GCONF_VALUE_STRING, list, nsnull);
815
+    }
816
+    for (GSList* l = list; l; l = l->next) {
817
+        free(l->data);
818
+    }
819
+    g_slist_free(list);
820
+    return rv;
821
 }
822
 
823
-/* void deleteBranch (in string aStartingAt); */
824
-NS_IMETHODIMP nsSystemPrefService::DeleteBranch(const char *aStartingAt)
825
+/**
826
+ * The relationship R is
827
+ * "network.negotiate-auth.trusted-uris" is the comma-separated concatenation
828
+ * of the elements of the list "/apps/firefox/general/trusted_URIs"
829
+ */
830
+static const char GConfKey_TrustedURIs[] = "/apps/firefox/general/trusted_URIs";
831
+static const char MozKey_TrustedURIs[] = "network.negotiate-auth.trusted-uris";
832
+static nsresult ApplyTrustedURIs(nsSystemPrefService* aPrefService,
833
+                                GConfClient* aClient)
834
+{
835
+    return ApplyListPref(aPrefService, aClient, 
836
+                        GConfKey_TrustedURIs, MozKey_TrustedURIs, ',');
837
+}
838
+static nsresult ReverseApplyTrustedURIs(nsSystemPrefService* aPrefService,
839
+                                       GConfClient* aClient)
840
+{
841
+    return ReverseApplyListPref(aPrefService, aClient, 
842
+                               GConfKey_TrustedURIs, MozKey_TrustedURIs, ',');
843
+}
844
+
845
+/**
846
+ * The relationship R is
847
+ * "network.negotiate-auth.delegation-uris" is the comma-separated concatenation
848
+ * of the elements of the list "/apps/firefox/general/delegation_URIs"
849
+ */
850
+static const char GConfKey_DelegationURIs[] = "/apps/firefox/general/delegation_URIs";
851
+static const char MozKey_DelegationURIs[] = "network.negotiate-auth.delegation-uris";
852
+static nsresult ApplyDelegationURIs(nsSystemPrefService* aPrefService,
853
+                                   GConfClient* aClient)
854
+{
855
+    return ApplyListPref(aPrefService, aClient, 
856
+                        GConfKey_DelegationURIs, MozKey_DelegationURIs, ',');
857
+}
858
+static nsresult ReverseApplyDelegationURIs(nsSystemPrefService* aPrefService,
859
+                                          GConfClient* aClient)
860
+{
861
+    return ReverseApplyListPref(aPrefService, aClient, 
862
+                               GConfKey_DelegationURIs, MozKey_DelegationURIs, ',');
863
+}
864
+
865
+/**
866
+ * The relationship R is
867
+ * "network.proxy.no_proxies_on" is the comma-separated concatenation
868
+ * of the elements of the list "/system/http_proxy/ignore_hosts"
869
+ */
870
+static const char GConfKey_IgnoreHosts[] = "/system/http_proxy/ignore_hosts";
871
+static const char MozKey_IgnoreHosts[] = "network.proxy.no_proxies_on";
872
+static nsresult ApplyIgnoreHosts(nsSystemPrefService* aPrefService,
873
+                                 GConfClient* aClient)
874
+{
875
+    return ApplyListPref(aPrefService, aClient, 
876
+                        GConfKey_IgnoreHosts, MozKey_IgnoreHosts, ',');
877
+}
878
+static nsresult ReverseApplyIgnoreHosts(nsSystemPrefService* aPrefService,
879
+                                        GConfClient* aClient)
880
+{
881
+    return ReverseApplyListPref(aPrefService, aClient, 
882
+                               GConfKey_IgnoreHosts, MozKey_IgnoreHosts, ',');
883
+}
884
+
885
+/**
886
+ * The relationship R is
887
+ * ("/system/proxy/mode" is 'manual' if and only if "network.proxy.type" is eProxyConfig_Manual (1))
888
+ * AND ("/system/proxy/mode" is 'auto' if and only if "network.proxy.type" is eProxyConfig_PAC (2))
889
+ * 
890
+ * [This means 'none' matches any value of "network.proxy.type" other than 1 or 2.]
891
+ */
892
+static const char GConfKey_ProxyMode[] = "/system/proxy/mode";
893
+static const char MozKey_ProxyMode[] = "network.proxy.type";
894
+static nsresult ApplyProxyMode(nsSystemPrefService* aPrefService,
895
+                               GConfClient* aClient)
896
 {
897
-    return NS_ERROR_NOT_IMPLEMENTED;
898
+    char* str = gconf_client_get_string(aClient, GConfKey_ProxyMode, nsnull);
899
+    if (!str)
900
+        return NS_ERROR_FAILURE;
901
+    PRInt32 val = -1;
902
+    nsCOMPtr<nsIPrefBranch2> prefs =
903
+        aPrefService->GetPrefs()->GetPrefUserBranch();
904
+    prefs->GetIntPref(MozKey_ProxyMode, &val);
905
+    if (val < 0)
906
+        return NS_ERROR_FAILURE;
907
+    if (!strcmp(str, "manual")) {
908
+        val = 1;
909
+    } else if (!strcmp(str, "auto")) {
910
+        val = 2;
911
+    } else if (strcmp(str, "none")) {
912
+        // invalid value for this gconf pref; do nothing
913
+        g_free(str);
914
+        return NS_OK;
915
+    } else {
916
+        if (val == 1 || val == 2) {
917
+            // We need to make it something that 'none' maps to
918
+            val = 0;
919
+        }
920
+    }
921
+    g_free(str);
922
+    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_ProxyMode, nsnull);
923
+    nsresult rv = aPrefService->GetPrefs()->
924
+        SetOverridingMozillaIntPref(MozKey_ProxyMode, val, lock);
925
+    return rv;
926
+}
927
+static nsresult ReverseApplyProxyMode(nsSystemPrefService* aPrefService,
928
+                                      GConfClient* aClient)
929
+{
930
+    PRInt32 val = -1;
931
+    nsCOMPtr<nsIPrefBranch2> prefs =
932
+        aPrefService->GetPrefs()->GetPrefUserBranch();
933
+    prefs->GetIntPref(MozKey_ProxyMode, &val);
934
+    if (val < 0)
935
+        return NS_ERROR_FAILURE;
936
+    const char* str;
937
+    switch (val) {
938
+    case 1: str = "manual"; break;
939
+    case 2: str = "auto"; break;
940
+    default: str = "none"; break;
941
+    }
942
+    gconf_client_set_string(aClient, GConfKey_ProxyMode, str, nsnull);
943
+    return NS_OK;
944
 }
945
 
946
-/* void getChildList (in string aStartingAt, out unsigned long aCount, [array, size_is (aCount), retval] out string aChildArray); */
947
-NS_IMETHODIMP nsSystemPrefService::GetChildList(const char *aStartingAt, PRUint32 *aCount, char ***aChildArray)
948
+/**
949
+ * The relationship R is
950
+ * If "/apps/firefox/web/download_defaultfolder" is the empty string, then
951
+ * "browser.download.useDownloadDir" is false;
952
+ * otherwise "browser.download.useDownloadDir" is true and "browser.download.folderList"
953
+ * is (0 if "/apps/firefox/web/download_defaultfolder" is "Desktop";
954
+ *     1 if "/apps/firefox/web/download_defaultfolder" is "My Downloads";
955
+ *     3 if "/apps/firefox/web/download_defaultfolder" is "Home";
956
+ *     otherwise 2 and "browser.download.dir" = "/apps/firefox/web/download_defaultfolder")
957
+ */
958
+static const char GConfKey_DownloadFolder[] = "/apps/firefox/web/download_defaultfolder";
959
+static const char MozKey_UseDownloadDir[] = "browser.download.useDownloadDir";
960
+static const char MozKey_DownloadDirType[] = "browser.download.folderList";
961
+static const char MozKey_DownloadDirExplicit[] = "browser.download.dir";
962
+static nsresult ApplyDownloadFolder(nsSystemPrefService* aPrefService,
963
+                                    GConfClient* aClient)
964
 {
965
-    return NS_ERROR_NOT_IMPLEMENTED;
966
+    char* str = gconf_client_get_string(aClient, GConfKey_DownloadFolder, nsnull);
967
+    if (!str)
968
+        return NS_ERROR_FAILURE;
969
+    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DownloadFolder, nsnull);
970
+    nsresult rv = aPrefService->GetPrefs()->
971
+        SetOverridingMozillaBoolPref(MozKey_UseDownloadDir, *str != 0, lock);
972
+    if (NS_FAILED(rv)) {
973
+        g_free(str);
974
+        return rv;
975
+    }
976
+    PRInt32 dirType = 0;
977
+    if (!strcmp(str, "Desktop")) {
978
+        dirType = 0;
979
+    } else if (!strcmp(str, "My Downloads")) {
980
+        dirType = 1;
981
+    } else if (!strcmp(str, "Home")) {
982
+        dirType = 3;
983
+    } else {
984
+        dirType = 2;
985
+    }
986
+    // Always set all three Mozilla preferences. This is simpler and avoids
987
+    // problems; e.g., if the gconf value changes from "/home/rocallahan" to "Desktop"
988
+    // we might leave MozKey_DownloadDirType accidentally locked.
989
+    rv = aPrefService->GetPrefs()->
990
+        SetOverridingMozillaIntPref(MozKey_DownloadDirType, dirType, lock);
991
+    if (NS_SUCCEEDED(rv)) {
992
+        rv = aPrefService->GetPrefs()->
993
+            SetOverridingMozillaStringPref(MozKey_DownloadDirExplicit, str, lock);
994
+    }
995
+    g_free(str);
996
+    return rv;
997
 }
998
 
999
-/* void resetBranch (in string aStartingAt); */
1000
-NS_IMETHODIMP nsSystemPrefService::ResetBranch(const char *aStartingAt)
1001
-{
1002
-    return NS_ERROR_NOT_IMPLEMENTED;
1003
+static nsresult ReverseApplyDownloadFolder(nsSystemPrefService* aPrefService,
1004
+                                           GConfClient* aClient)
1005
+{
1006
+    PRBool useDownloadDir = PR_FALSE;
1007
+    const char* result;
1008
+    char* explicitStr = nsnull;
1009
+    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1010
+    prefs->GetBoolPref(MozKey_UseDownloadDir, &useDownloadDir);
1011
+    if (!useDownloadDir) {
1012
+        result = "";
1013
+    } else {
1014
+        PRInt32 type = -1;
1015
+        prefs->GetIntPref(MozKey_DownloadDirType, &type);
1016
+        if (type < 0)
1017
+            return NS_ERROR_FAILURE;
1018
+        switch (type) {
1019
+        case 0: result = "Desktop"; break;
1020
+        case 1: result = "My Downloads"; break;
1021
+        case 2:
1022
+            prefs->GetCharPref(MozKey_DownloadDirExplicit, &explicitStr);
1023
+            result = explicitStr;
1024
+            break;
1025
+        case 3: result = "Home"; break;
1026
+        default:
1027
+            NS_ERROR("Unknown download dir type");
1028
+            return NS_ERROR_FAILURE;
1029
+        }
1030
+    }
1031
+    if (!result)
1032
+        return NS_ERROR_FAILURE;
1033
+    gconf_client_set_string(aClient, GConfKey_DownloadFolder,
1034
+                            result, nsnull);
1035
+    nsMemory::Free(explicitStr);
1036
+    return NS_OK;
1037
 }
1038
 
1039
-/* void addObserver (in string aDomain, in nsIObserver aObserver, in boolean aHoldWeak); */
1040
-NS_IMETHODIMP nsSystemPrefService::AddObserver(const char *aDomain, nsIObserver *aObserver, PRBool aHoldWeak)
1041
-{
1042
-    nsresult rv;
1043
-
1044
-    NS_ENSURE_ARG_POINTER(aDomain);
1045
-    NS_ENSURE_ARG_POINTER(aObserver);
1046
-
1047
-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
1048
-
1049
-    PRUint32 prefAtom;
1050
-    // make sure the pref name is supported
1051
-    rv = mGConf->GetAtomForMozKey(aDomain, &prefAtom);
1052
-    NS_ENSURE_SUCCESS(rv, rv);
1053
-
1054
-    if (!mObservers) {
1055
-        mObservers = new nsAutoVoidArray();
1056
-        if (mObservers == nsnull)
1057
-            return NS_ERROR_OUT_OF_MEMORY;
1058
-    }
1059
-
1060
-    SysPrefCallbackData *pCallbackData = (SysPrefCallbackData *)
1061
-        nsMemory::Alloc(sizeof(SysPrefCallbackData));
1062
-    if (pCallbackData == nsnull)
1063
-        return NS_ERROR_OUT_OF_MEMORY;
1064
-
1065
-    pCallbackData->bIsWeakRef = aHoldWeak;
1066
-    pCallbackData->prefAtom = prefAtom;
1067
-    // hold a weak reference to the observer if so requested
1068
-    nsCOMPtr<nsISupports> observerRef;
1069
-    if (aHoldWeak) {
1070
-        nsCOMPtr<nsISupportsWeakReference> weakRefFactory = 
1071
-            do_QueryInterface(aObserver);
1072
-        if (!weakRefFactory) {
1073
-            // the caller didn't give us a object that supports weak reference.
1074
-            // ... tell them
1075
-            nsMemory::Free(pCallbackData);
1076
-            return NS_ERROR_INVALID_ARG;
1077
-        }
1078
-        nsCOMPtr<nsIWeakReference> tmp = do_GetWeakReference(weakRefFactory);
1079
-        observerRef = tmp;
1080
+/**
1081
+ * The relationship R is
1082
+ * "/apps/firefox/web/disable_cookies" is true if and only if
1083
+ * "network.cookie.cookieBehavior" is 2 ('dontUse')
1084
+ */
1085
+static const char GConfKey_DisableCookies[] = "/apps/firefox/web/disable_cookies";
1086
+static const char MozKey_CookieBehavior[] = "network.cookie.cookieBehavior";
1087
+static const char MozKey_CookieExceptions[] = "network.cookie.honorExceptions";
1088
+static const char MozKey_CookieViewExceptions[] = "pref.privacy.disable_button.cookie_exceptions";
1089
+static nsresult ApplyDisableCookies(nsSystemPrefService* aPrefService,
1090
+                                    GConfClient* aClient)
1091
+{
1092
+    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableCookies, nsnull);
1093
+    PRInt32 behavior = -1;
1094
+    nsCOMPtr<nsIPrefBranch2> prefs =
1095
+        aPrefService->GetPrefs()->GetPrefUserBranch();
1096
+    prefs->GetIntPref(MozKey_CookieBehavior, &behavior);
1097
+    if (behavior < 0)
1098
+        return NS_ERROR_FAILURE;
1099
+    if (disable) {
1100
+        behavior = 2;
1101
     } else {
1102
-        observerRef = aObserver;
1103
+        if (behavior == 2) {
1104
+            behavior = 0;
1105
+        }
1106
     }
1107
+    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableCookies, nsnull);
1108
+    nsresult rv = aPrefService->GetPrefs()->
1109
+        SetOverridingMozillaBoolPref(MozKey_CookieExceptions, !lock, lock);
1110
+    if (NS_FAILED(rv))
1111
+      return rv;
1112
+    rv = aPrefService->GetPrefs()->
1113
+        SetOverridingMozillaBoolPref(MozKey_CookieViewExceptions, lock, lock);
1114
+    if (NS_FAILED(rv))
1115
+      return rv;
1116
+    return aPrefService->GetPrefs()->
1117
+        SetOverridingMozillaIntPref(MozKey_CookieBehavior, behavior, lock);
1118
+}
1119
+static nsresult ReverseApplyDisableCookies(nsSystemPrefService* aPrefService,
1120
+                                           GConfClient* aClient)
1121
+{
1122
+    PRInt32 behavior = -1;
1123
+    nsCOMPtr<nsIPrefBranch2> prefs =
1124
+        aPrefService->GetPrefs()->GetPrefUserBranch();
1125
+    prefs->GetIntPref(MozKey_CookieBehavior, &behavior);
1126
+    if (behavior < 0)
1127
+        return NS_ERROR_FAILURE;
1128
+    gconf_client_set_bool(aClient, GConfKey_DisableCookies, behavior == 2, nsnull);
1129
+    return NS_OK;
1130
+}
1131
 
1132
-    rv = mGConf->NotifyAdd(prefAtom, pCallbackData);
1133
-    if (NS_FAILED(rv)) {
1134
-        nsMemory::Free(pCallbackData);
1135
-        return rv;
1136
+static char const* windowOpenFeatures[] = {
1137
+    "dom.disable_window_open_feature.close",
1138
+    "dom.disable_window_open_feature.directories",
1139
+    "dom.disable_window_open_feature.location",
1140
+    "dom.disable_window_open_feature.menubar",
1141
+    "dom.disable_window_open_feature.minimizable",
1142
+    "dom.disable_window_open_feature.personalbar",
1143
+    "dom.disable_window_open_feature.resizable",
1144
+    "dom.disable_window_open_feature.scrollbars",
1145
+    "dom.disable_window_open_feature.status",
1146
+    "dom.disable_window_open_feature.titlebar",
1147
+    "dom.disable_window_open_feature.toolbar"
1148
+};
1149
+/**
1150
+ * The relationship R is
1151
+ * "/apps/firefox/lockdown/disable_javascript_chrome" is true if and only if
1152
+ * all of windowOpenFeatures are true
1153
+ */
1154
+static const char GConfKey_DisableJSChrome[] =
1155
+    "/apps/firefox/lockdown/disable_javascript_chrome";
1156
+static nsresult ApplyWindowOpen(nsSystemPrefService* aPrefService,
1157
+                                GConfClient* aClient)
1158
+{
1159
+    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableJSChrome, nsnull);
1160
+    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableJSChrome, nsnull);
1161
+    PRBool curValues[NUM_ELEM(windowOpenFeatures)];
1162
+    PRUint32 i;
1163
+    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1164
+    PRBool allDisabled = PR_TRUE;
1165
+    for (i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) {
1166
+        nsresult rv = prefs->GetBoolPref(windowOpenFeatures[i], &curValues[i]);
1167
+        if (NS_FAILED(rv))
1168
+            return rv;
1169
+        if (!curValues[i]) {
1170
+            allDisabled = PR_FALSE;
1171
+        }
1172
+    }
1173
+    for (i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) {
1174
+        PRBool newVal = curValues[i];
1175
+        if (disable) {
1176
+            newVal = PR_TRUE;
1177
+        } else if (allDisabled) {
1178
+            // If all disable-window-open-feature prefs are currently
1179
+            // PR_TRUE, then we need to set at least one of them to
1180
+            // PR_FALSE. Set all of them to PR_FALSE.
1181
+            newVal = PR_FALSE;
1182
+        } // If at least one disable-window-open-feature pref is
1183
+          // currently PR_FALSE, then we don't need to change anything
1184
+          // when the gconf pref says don't disable
1185
+        nsresult rv = aPrefService->GetPrefs()->
1186
+            SetOverridingMozillaBoolPref(windowOpenFeatures[i], newVal, lock);
1187
+        if (NS_FAILED(rv))
1188
+            return rv;
1189
     }
1190
-
1191
-    pCallbackData->observer = observerRef;
1192
-    NS_ADDREF(pCallbackData->observer);
1193
-
1194
-    mObservers->AppendElement(pCallbackData);
1195
     return NS_OK;
1196
 }
1197
 
1198
-/* void removeObserver (in string aDomain, in nsIObserver aObserver); */
1199
-NS_IMETHODIMP nsSystemPrefService::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
1200
+static nsresult ReverseApplyWindowOpen(nsSystemPrefService* aPrefService,
1201
+                                       GConfClient* aClient)
1202
 {
1203
-    nsresult rv;
1204
-
1205
-    NS_ENSURE_ARG_POINTER(aDomain);
1206
-    NS_ENSURE_ARG_POINTER(aObserver);
1207
-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
1208
-
1209
-    if (!mObservers)
1210
-        return NS_OK;
1211
-    
1212
-    PRUint32 prefAtom;
1213
-    // make sure the pref name is supported
1214
-    rv = mGConf->GetAtomForMozKey(aDomain, &prefAtom);
1215
-    NS_ENSURE_SUCCESS(rv, rv);
1216
-
1217
-    // need to find the index of observer, so we can remove it
1218
-    PRIntn count = mObservers->Count();
1219
-    if (count <= 0)
1220
-        return NS_OK;
1221
-
1222
-    PRIntn i;
1223
-    SysPrefCallbackData *pCallbackData;
1224
-    for (i = 0; i < count; ++i) {
1225
-        pCallbackData = (SysPrefCallbackData *)mObservers->ElementAt(i);
1226
-        if (pCallbackData) {
1227
-            nsCOMPtr<nsISupports> observerRef;
1228
-            if (pCallbackData->bIsWeakRef) {
1229
-                nsCOMPtr<nsISupportsWeakReference> weakRefFactory =
1230
-                    do_QueryInterface(aObserver);
1231
-                if (weakRefFactory) {
1232
-                    nsCOMPtr<nsIWeakReference> tmp =
1233
-                        do_GetWeakReference(aObserver);
1234
-                    observerRef = tmp;
1235
-                }
1236
-            }
1237
-            if (!observerRef)
1238
-                observerRef = aObserver;
1239
-
1240
-            if (pCallbackData->observer == observerRef &&
1241
-                pCallbackData->prefAtom == prefAtom) {
1242
-                rv = mGConf->NotifyRemove(prefAtom, pCallbackData);
1243
-                if (NS_SUCCEEDED(rv)) {
1244
-                    mObservers->RemoveElementAt(i);
1245
-                    NS_RELEASE(pCallbackData->observer);
1246
-                    nsMemory::Free(pCallbackData);
1247
-                }
1248
-                return rv;
1249
-            }
1250
+    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1251
+    PRBool allDisabled = PR_TRUE;
1252
+    PRBool curValues[NUM_ELEM(windowOpenFeatures)];
1253
+    for (PRUint32 i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) {
1254
+        nsresult rv = prefs->GetBoolPref(windowOpenFeatures[i], &curValues[i]);
1255
+        if (NS_FAILED(rv))
1256
+            return rv;
1257
+        if (!curValues[i]) {
1258
+            allDisabled = PR_FALSE;
1259
         }
1260
     }
1261
+    gconf_client_set_bool(aClient, GConfKey_DisableJSChrome, allDisabled, nsnull);
1262
     return NS_OK;
1263
 }
1264
 
1265
-void
1266
-nsSystemPrefService::OnPrefChange(PRUint32 aPrefAtom, void *aData)
1267
-{
1268
-    if (!mInitialized)
1269
-        return;
1270
-
1271
-    SysPrefCallbackData *pData = (SysPrefCallbackData *)aData;
1272
-    if (pData->prefAtom != aPrefAtom)
1273
-        return;
1274
-
1275
-    nsCOMPtr<nsIObserver> observer;
1276
-    if (pData->bIsWeakRef) {
1277
-        nsCOMPtr<nsIWeakReference> weakRef =
1278
-            do_QueryInterface(pData->observer);
1279
-        if(weakRef)
1280
-            observer = do_QueryReferent(weakRef);
1281
-        if (!observer) {
1282
-            // this weak referenced observer went away, remove it from the list
1283
-            nsresult rv = mGConf->NotifyRemove(aPrefAtom, pData);
1284
-            if (NS_SUCCEEDED(rv)) {
1285
-                mObservers->RemoveElement(pData);
1286
-                NS_RELEASE(pData->observer);
1287
-                nsMemory::Free(pData);
1288
-            }
1289
-            return;
1290
+/**
1291
+ * The relationship R is
1292
+ * If "/apps/firefox/lockdown/disable_unsafe_protocol" is true then
1293
+ * -- "network.protocol-handler.blocked-default" is true
1294
+ * -- "network.protocol-handler.blocked.XYZ" is false if and only if
1295
+ * XYZ is a builtin non-disablable protocol or in
1296
+ * "/apps/firefox/lockdown/additional_safe_protocols"
1297
+ * AND if "/apps/firefox/lockdown/disable_unsafe_protocol" is false then
1298
+ * -- "network.protocol-handler.blocked-default" is false
1299
+ * -- if "network.protocol-handler.blocked.XYZ" exists then it is false
1300
+ */
1301
+static const char GConfKey_DisableUnsafeProtocols[] =
1302
+    "/apps/firefox/lockdown/disable_unsafe_protocol";
1303
+static const char GConfKey_AdditionalSafeProtocols[] =
1304
+    "/apps/firefox/lockdown/additional_safe_protocols";
1305
+static const char MozKey_BlockedDefault[] =
1306
+    "network.protocol-handler.blocked-default";
1307
+static const char MozKey_BlockedPrefix[] =
1308
+    "network.protocol-handler.blocked.";
1309
+static const char* nonDisablableBuiltinProtocols[] =
1310
+    { "about", "data", "jar", "keyword", "resource", "viewsource",
1311
+      "chrome", "moz-icon", "javascript", "file" };
1312
+static PRBool FindString(const char** aList, PRInt32 aCount,
1313
+                         const char* aStr)
1314
+{
1315
+    for (PRInt32 i = 0; i < aCount; ++i) {
1316
+        if (!strcmp(aStr, aList[i]))
1317
+            return PR_TRUE;
1318
+    }
1319
+    return PR_FALSE;
1320
+}
1321
+typedef nsDataHashtable<nsCStringHashKey,int> StringSet;
1322
+/** Collect the set of protocol names that we want to set preferences for */
1323
+static nsresult AddAllProtocols(nsSystemPrefService* aPrefService,
1324
+                                const char* aSafeProtocols,
1325
+                                StringSet* aProtocolSet,
1326
+                                StringSet* aSafeSet)
1327
+{
1328
+    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1329
+    PRUint32 childCount;
1330
+    char **childArray = nsnull;
1331
+    nsresult rv = prefs->GetChildList(MozKey_BlockedPrefix, &childCount, &childArray);
1332
+    if (NS_FAILED(rv))
1333
+        return rv;
1334
+    PRUint32 i;
1335
+    for (i = 0; i < childCount; ++i) {
1336
+        nsDependentCString tmp(childArray[i] + NUM_ELEM(MozKey_BlockedPrefix)-1);
1337
+        aProtocolSet->Put(tmp, 1); // copies
1338
+    }
1339
+    for (i = 0; i < NUM_ELEM(nonDisablableBuiltinProtocols); ++i) {
1340
+        nsDependentCString tmp(nonDisablableBuiltinProtocols[i]);
1341
+        aProtocolSet->Put(tmp, 1);
1342
+    }
1343
+    i = 0;
1344
+    while (aSafeProtocols[i]) {
1345
+        const char* nextComma = strchr(aSafeProtocols+i, ',');
1346
+        PRUint32 tokLen = nextComma ? nextComma - (aSafeProtocols+i)
1347
+            : strlen(aSafeProtocols+i);
1348
+        nsCAutoString tok(aSafeProtocols+i, tokLen);
1349
+        aProtocolSet->Put(tok, 1);
1350
+        aSafeSet->Put(tok, 1);
1351
+        if (nextComma) {
1352
+            i = nextComma - aSafeProtocols + 1;
1353
+        } else {
1354
+            break;
1355
         }
1356
     }
1357
-    else
1358
-        observer = do_QueryInterface(pData->observer);
1359
-
1360
-    if (observer)
1361
-        observer->Observe(NS_STATIC_CAST(nsIPrefBranch *, this),
1362
-                          NS_SYSTEMPREF_PREFCHANGE_TOPIC_ID,
1363
-                          NS_ConvertUTF8toUCS2(mGConf->GetMozKey(aPrefAtom)).
1364
-                          get());
1365
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray);
1366
+    return NS_OK;
1367
 }
1368
 
1369
-/*************************************************************
1370
- *  GConfProxy
1371
- *
1372
- ************************************************************/
1373
-
1374
-struct GConfFuncListType {
1375
-    const char *FuncName;
1376
-    PRFuncPtr  FuncPtr;
1377
-};
1378
-
1379
-struct PrefNamePair {
1380
-    const char *mozPrefName;
1381
-    const char *gconfPrefName;
1382
-};
1383
-
1384
-const char
1385
-GConfProxy::sPrefGConfKey[] = "accessibility.unix.gconf2.shared-library";
1386
-const char GConfProxy::sDefaultLibName1[] = "libgconf-2.so.4";
1387
-const char GConfProxy::sDefaultLibName2[] = "libgconf-2.so";
1388
-
1389
-#define GCONF_FUNCS_POINTER_BEGIN \
1390
-    static GConfFuncListType sGConfFuncList[] = {
1391
-#define GCONF_FUNCS_POINTER_ADD(func_name) \
1392
-    {func_name, nsnull},
1393
-#define GCONF_FUNCS_POINTER_END \
1394
-    {nsnull, nsnull}, };
1395
-
1396
-GCONF_FUNCS_POINTER_BEGIN
1397
-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_default")        // 0
1398
-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_bool")       // 1
1399
-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_string")     //2
1400
-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_int")       //3
1401
-    GCONF_FUNCS_POINTER_ADD("gconf_client_notify_add")   //4
1402
-    GCONF_FUNCS_POINTER_ADD("gconf_client_notify_remove")   //5
1403
-    GCONF_FUNCS_POINTER_ADD("gconf_client_add_dir")   //6
1404
-    GCONF_FUNCS_POINTER_ADD("gconf_client_remove_dir")   //7
1405
-    GCONF_FUNCS_POINTER_ADD("gconf_entry_get_value")       //8
1406
-    GCONF_FUNCS_POINTER_ADD("gconf_entry_get_key")       //9
1407
-    GCONF_FUNCS_POINTER_ADD("gconf_value_get_bool")      //10
1408
-    GCONF_FUNCS_POINTER_ADD("gconf_value_get_string")     //11
1409
-    GCONF_FUNCS_POINTER_ADD("gconf_value_get_int")       //12
1410
-GCONF_FUNCS_POINTER_END
1411
-
1412
-/////////////////////////////////////////////////////////////////////////////
1413
-// the list is the mapping table, between mozilla prefs and gconf prefs
1414
-// It is expected to include all the pref pairs that are related in mozilla
1415
-// and gconf. 
1416
-//
1417
-// Note: the prefs listed here are not neccessarily be read from gconf, they
1418
-//       are the prefs that could be read from gconf. Mozilla has another
1419
-//       list (see sSysPrefList in nsSystemPref.cpp) that decide which prefs
1420
-//       are really read.
1421
-//////////////////////////////////////////////////////////////////////////////
1422
-
1423
-static const PrefNamePair sPrefNameMapping[] = {
1424
-#include "gconf_pref_list.inc"
1425
-    {nsnull, nsnull},
1426
+struct ProtocolPrefClosure {
1427
+    StringSet safeProtocolSet;
1428
+    nsIPrefBranch2* prefs;
1429
+    nsISystemPref* prefSetter;
1430
+    PRPackedBool disableUnsafe;
1431
+    PRPackedBool lock;
1432
 };
1433
 
1434
-PRBool PR_CALLBACK
1435
-gconfDeleteObserver(void *aElement, void *aData) {
1436
-    nsMemory::Free(aElement);
1437
-    return PR_TRUE;
1438
+static PLDHashOperator PR_CALLBACK SetProtocolPref(const nsACString& aKey,
1439
+                                                   int aItem,
1440
+                                                   void* aClosure)
1441
+{
1442
+    ProtocolPrefClosure* closure = NS_STATIC_CAST(ProtocolPrefClosure*, aClosure);
1443
+    const nsCString& protocol = PromiseFlatCString(aKey);
1444
+    PRBool blockProtocol = PR_FALSE;
1445
+    if (closure->disableUnsafe &&
1446
+        !FindString(nonDisablableBuiltinProtocols,
1447
+                    NUM_ELEM(nonDisablableBuiltinProtocols), protocol.get()) &&
1448
+        !closure->safeProtocolSet.Get(aKey, nsnull)) {
1449
+        blockProtocol = PR_TRUE;
1450
+    }
1451
+
1452
+    nsCAutoString prefName;
1453
+    prefName.Append(MozKey_BlockedPrefix);
1454
+    prefName.Append(protocol);
1455
+    closure->prefSetter->SetOverridingMozillaBoolPref(prefName.get(), blockProtocol,
1456
+                                                      closure->lock);
1457
+    return PL_DHASH_NEXT;
1458
+}
1459
+static nsresult ApplyUnsafeProtocols(nsSystemPrefService* aPrefService,
1460
+                                     GConfClient* aClient)
1461
+{
1462
+    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableUnsafeProtocols, nsnull)
1463
+        || !gconf_client_key_is_writable(aClient, GConfKey_AdditionalSafeProtocols, nsnull);
1464
+    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableUnsafeProtocols, nsnull);
1465
+    char* protocols = gconf_client_get_string(aClient, GConfKey_AdditionalSafeProtocols, nsnull);
1466
+    if (!protocols)
1467
+        return NS_ERROR_FAILURE;
1468
+    nsresult rv = aPrefService->GetPrefs()->
1469
+        SetOverridingMozillaBoolPref(MozKey_BlockedDefault, disable, lock);
1470
+    StringSet protocolSet;
1471
+    ProtocolPrefClosure closure;
1472
+    protocolSet.Init();
1473
+    closure.safeProtocolSet.Init();
1474
+    if (NS_SUCCEEDED(rv)) {
1475
+        rv = AddAllProtocols(aPrefService, protocols, &protocolSet,
1476
+                             &closure.safeProtocolSet);
1477
+    }
1478
+    if (NS_SUCCEEDED(rv)) {
1479
+        closure.disableUnsafe = disable;
1480
+        closure.lock = lock;
1481
+        closure.prefSetter = aPrefService->GetPrefs();
1482
+        nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1483
+        closure.prefs = prefs;
1484
+        protocolSet.EnumerateRead(SetProtocolPref, &closure);
1485
+    }
1486
+    g_free(protocols);
1487
+    return rv;
1488
+}
1489
+
1490
+static nsresult ReverseApplyUnsafeProtocols(nsSystemPrefService* aPrefService,
1491
+                                            GConfClient* aClient)
1492
+{
1493
+    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1494
+    PRBool blockedDefault;
1495
+    nsresult rv = prefs->GetBoolPref(MozKey_BlockedDefault, &blockedDefault);
1496
+    if (NS_FAILED(rv))
1497
+        return rv;
1498
+    nsCAutoString enabledProtocols;
1499
+    PRUint32 childCount;
1500
+    char **childArray = nsnull;
1501
+    rv = prefs->GetChildList(MozKey_BlockedPrefix, &childCount, &childArray);
1502
+    if (NS_FAILED(rv))
1503
+        return rv;
1504
+    for (PRUint32 i = 0; i < childCount; ++i) {
1505
+        PRBool val = PR_FALSE;
1506
+        prefs->GetBoolPref(childArray[i], &val);
1507
+        if (val) {
1508
+            if (enabledProtocols.Length() > 0) {
1509
+                enabledProtocols.Append(',');
1510
+            }
1511
+            enabledProtocols.Append(childArray[i] + NUM_ELEM(MozKey_BlockedPrefix)-1);
1512
+        }
1513
+    }
1514
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray);
1515
+    gconf_client_set_bool(aClient, GConfKey_DisableUnsafeProtocols, blockedDefault, nsnull);
1516
+    gconf_client_set_string(aClient, GConfKey_AdditionalSafeProtocols,
1517
+                            enabledProtocols.get(), nsnull);
1518
+    return NS_OK;
1519
 }
1520
 
1521
-GConfProxy::GConfProxy(nsSystemPrefService *aSysPrefService):
1522
-    mGConfClient(nsnull),
1523
-    mGConfLib(nsnull),
1524
-    mInitialized(PR_FALSE),
1525
-    mSysPrefService(aSysPrefService),
1526
-    mObservers(nsnull)
1527
-{
1528
+/**
1529
+ * Set config.lockdown.setwallpaper if and only if
1530
+ * /desktop/gnome/background/picture_filename is write-only. Always
1531
+ * lock it.
1532
+ */
1533
+static const char MozKey_LockdownWallpaper[] = "config.lockdown.setwallpaper";
1534
+static const char GConfKey_WallpaperSetting[] =
1535
+    "/desktop/gnome/background/picture_filename";
1536
+static nsresult ApplyWallpaper(nsSystemPrefService* aPrefService,
1537
+                               GConfClient* aClient)
1538
+{
1539
+    PRBool canSetWallpaper =
1540
+        gconf_client_key_is_writable(aClient, GConfKey_WallpaperSetting, nsnull);
1541
+    return aPrefService->GetPrefs()->
1542
+        SetOverridingMozillaBoolPref(MozKey_LockdownWallpaper,
1543
+                                     !canSetWallpaper, PR_TRUE);
1544
+}
1545
+// No ReverseApplyWallpaper because this Mozilla pref can never be
1546
+// modified
1547
+
1548
+/**
1549
+ * The relationship R is 
1550
+ * "signon.rememberSignons" is true if and only if "/apps/firefox/web/disable_save_password"
1551
+ * is false.
1552
+ */
1553
+static const char MozKey_RememberSignons[] = "signon.rememberSignons";
1554
+static const char GConfKey_DisableSavePassword[] = "/apps/firefox/web/disable_save_password";
1555
+static nsresult ApplyDisableSavePassword(nsSystemPrefService* aPrefService,
1556
+                                         GConfClient* aClient)
1557
+{
1558
+    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableSavePassword, nsnull);
1559
+    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableSavePassword, nsnull);
1560
+    return aPrefService->GetPrefs()->
1561
+        SetOverridingMozillaBoolPref(MozKey_RememberSignons, !disable, lock);
1562
+}
1563
+
1564
+static nsresult ReverseApplyDisableSavePassword(nsSystemPrefService* aPrefService,
1565
+                                                GConfClient* aClient)
1566
+{
1567
+    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1568
+    PRBool remember;
1569
+    nsresult rv = prefs->GetBoolPref(MozKey_RememberSignons, &remember);
1570
+    if (NS_FAILED(rv))
1571
+        return rv;
1572
+    gconf_client_set_bool(aClient, GConfKey_DisableSavePassword, !remember, nsnull);
1573
+    return NS_OK;
1574
 }
1575
 
1576
-GConfProxy::~GConfProxy()
1577
-{
1578
-    if (mGConfClient)
1579
-        g_object_unref(G_OBJECT(mGConfClient));
1580
-
1581
-    if (mObservers) {
1582
-        (void)mObservers->EnumerateForwards(gconfDeleteObserver, nsnull);
1583
-        delete mObservers;
1584
+/**
1585
+ * The relationship R is
1586
+ * "permissions.default.image" is 1 (nsIPermissionManager::ALLOW_ACTION) if and only if
1587
+ * "/apps/firefox/web/images_load" is 0, AND
1588
+ * "permissions.default.image" is 2 (nsIPermissionManager::DENY_ACTION) if and only if
1589
+ * "/apps/firefox/web/images_load" is 2, AND
1590
+ * "permissions.default.image" is 3 if and only if "/apps/firefox/web/images_load" is 1
1591
+ *
1592
+ * Also, we set pref.advanced.images.disable_button.view_image iff
1593
+ * /apps/firefox/web/images_load is read-only
1594
+ * And we set permissions.default.honorExceptions iff
1595
+ * /apps/firefox/web/images_load is not read-only
1596
+ */
1597
+static const char MozKey_ImagePermissions[] = "permissions.default.image";
1598
+static const char MozKey_ImageExceptions[] = "permissions.honorExceptions.image";
1599
+static const char MozKey_ImageViewExceptions[] = "pref.advanced.images.disable_button.view_image";
1600
+static const char GConfKey_LoadImages[] = "/apps/firefox/web/images_load";
1601
+static nsresult ApplyLoadImages(nsSystemPrefService* aPrefService,
1602
+                                 GConfClient* aClient)
1603
+{
1604
+    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_LoadImages, nsnull);
1605
+    // 0 == accept, 1 == no-foreign, 2 == reject
1606
+    gint setting = gconf_client_get_int(aClient, GConfKey_LoadImages, nsnull);
1607
+    PRInt32 pref;
1608
+    switch (setting) {
1609
+      case 0: pref = nsIPermissionManager::ALLOW_ACTION; break;
1610
+      case 2: pref = nsIPermissionManager::DENY_ACTION; break;
1611
+      case 1: pref = 3; break;
1612
+      default: return NS_ERROR_FAILURE;
1613
     }
1614
+    nsresult rv = aPrefService->GetPrefs()->
1615
+        SetOverridingMozillaBoolPref(MozKey_ImageExceptions, !lock, lock);
1616
+    if (NS_FAILED(rv))
1617
+      return rv;
1618
+    rv = aPrefService->GetPrefs()->
1619
+        SetOverridingMozillaBoolPref(MozKey_ImageViewExceptions, lock, lock);
1620
+    if (NS_FAILED(rv))
1621
+      return rv;
1622
+    return aPrefService->GetPrefs()->
1623
+        SetOverridingMozillaIntPref(MozKey_ImagePermissions, pref, lock);
1624
 }
1625
 
1626
-PRBool
1627
-GConfProxy::Init()
1628
+static nsresult ReverseApplyLoadImages(nsSystemPrefService* aPrefService,
1629
+                                        GConfClient* aClient)
1630
 {
1631
-    SYSPREF_LOG(("GConfProxy:: Init GConfProxy\n"));
1632
-    if (!mSysPrefService)
1633
-        return PR_FALSE;
1634
-    if (mInitialized)
1635
-        return PR_TRUE;
1636
-
1637
-    nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID);
1638
-    if (!pref)
1639
-        return PR_FALSE;
1640
-
1641
-    nsXPIDLCString gconfLibName;
1642
-    nsresult rv;
1643
-
1644
-    //check if gconf-2 library is given in prefs
1645
-    rv = pref->GetCharPref(sPrefGConfKey, getter_Copies(gconfLibName));
1646
-    if (NS_SUCCEEDED(rv)) {
1647
-        //use the library name in the preference
1648
-        SYSPREF_LOG(("GConf library in prefs is %s\n", gconfLibName.get()));
1649
-        mGConfLib = PR_LoadLibrary(gconfLibName.get());
1650
-    }
1651
-    else {
1652
-        SYSPREF_LOG(("GConf library not specified in prefs, try the default: "
1653
-                     "%s and %s\n", sDefaultLibName1, sDefaultLibName2));
1654
-        mGConfLib = PR_LoadLibrary(sDefaultLibName1);
1655
-        if (!mGConfLib)
1656
-            mGConfLib = PR_LoadLibrary(sDefaultLibName2);
1657
-    }
1658
-
1659
-    if (!mGConfLib) {
1660
-        SYSPREF_LOG(("Fail to load GConf library\n"));
1661
-        return PR_FALSE;
1662
+    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1663
+    PRInt32 pref;
1664
+    nsresult rv = prefs->GetIntPref(MozKey_ImagePermissions, &pref);
1665
+    if (NS_FAILED(rv))
1666
+        return rv;
1667
+    gint setting;
1668
+    switch (pref) {
1669
+      case nsIPermissionManager::ALLOW_ACTION: setting = 0; break;
1670
+      case nsIPermissionManager::DENY_ACTION: setting = 2; break;
1671
+      case 3: setting = 1; break;
1672
+      default: return NS_ERROR_FAILURE;
1673
     }
1674
+    gconf_client_set_int(aClient, GConfKey_LoadImages, setting, nsnull);
1675
+    return NS_OK;
1676
+}
1677
 
1678
-    //check every func we need in the gconf library
1679
-    GConfFuncListType *funcList;
1680
-    PRFuncPtr func;
1681
-    for (funcList = sGConfFuncList; funcList->FuncName; ++funcList) {
1682
-        func = PR_FindFunctionSymbol(mGConfLib, funcList->FuncName);
1683
-        if (!func) {
1684
-            SYSPREF_LOG(("Check GConf Func Error: %s", funcList->FuncName));
1685
-            goto init_failed_unload;
1686
+/**
1687
+ * The relationship R is 
1688
+ * "/apps/firefox/web/disable_popups" is true if and only if
1689
+ * "dom.disable_open_during_load" is true
1690
+ * AND if "/apps/firefox/web/disable_popups" is true then
1691
+ * "privacy.popups.showBrowserMessage" is false.
1692
+ */
1693
+static const char MozKey_DisablePopups[] = "dom.disable_open_during_load";
1694
+static const char MozKey_DisableBrowserPopupMessage[] = "privacy.popups.showBrowserMessage";
1695
+static const char GConfKey_DisablePopups[] = "/apps/firefox/web/disable_popups";
1696
+static nsresult ApplyDisablePopups(nsSystemPrefService* aPrefService,
1697
+                                   GConfClient* aClient)
1698
+{
1699
+    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisablePopups, nsnull);
1700
+    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisablePopups, nsnull);
1701
+    nsresult rv = aPrefService->GetPrefs()->
1702
+        SetOverridingMozillaBoolPref(MozKey_DisablePopups, disable, lock);
1703
+    if (NS_SUCCEEDED(rv)) {
1704
+        if (disable) {
1705
+            rv = aPrefService->GetPrefs()->
1706
+                SetOverridingMozillaBoolPref(MozKey_DisableBrowserPopupMessage, PR_TRUE, lock);
1707
+        } else {
1708
+            rv = aPrefService->GetPrefs()->
1709
+                StopOverridingMozillaPref(MozKey_DisableBrowserPopupMessage);
1710
         }
1711
-        funcList->FuncPtr = func;
1712
     }
1713
-
1714
-    InitFuncPtrs();
1715
-
1716
-    mGConfClient = GConfClientGetDefault();
1717
-
1718
-    // Don't unload past this point, since GConf's initialization of ORBit
1719
-    // causes atexit handlers to be registered.
1720
-
1721
-    if (!mGConfClient) {
1722
-        SYSPREF_LOG(("Fail to Get default gconf client\n"));
1723
-        goto init_failed;
1724
-    }
1725
-    mInitialized = PR_TRUE;
1726
-    return PR_TRUE;
1727
-
1728
- init_failed_unload:
1729
-    PR_UnloadLibrary(mGConfLib);
1730
- init_failed:
1731
-    mGConfLib = nsnull;
1732
-    return PR_FALSE;
1733
+    return rv;
1734
 }
1735
 
1736
-nsresult
1737
-GConfProxy::GetBoolPref(const char *aMozKey, PRBool *retval)
1738
+static nsresult ReverseApplyDisablePopups(nsSystemPrefService* aPrefService,
1739
+                                          GConfClient* aClient)
1740
 {
1741
-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
1742
-    *retval = GConfClientGetBool(mGConfClient, MozKey2GConfKey(aMozKey), NULL);
1743
+    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
1744
+    PRBool disabled;
1745
+    nsresult rv = prefs->GetBoolPref(MozKey_DisablePopups, &disabled);
1746
+    if (NS_FAILED(rv))
1747
+        return rv;
1748
+    gconf_client_set_bool(aClient, GConfKey_DisablePopups, disabled, nsnull);
1749
     return NS_OK;
1750
 }
1751
 
1752
-nsresult
1753
-GConfProxy::GetCharPref(const char *aMozKey, char **retval)
1754
-{
1755
-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
1756
+static ComplexGConfPrefMapping sComplexGConfPrefMappings[] = {
1757
+    {GConfKey_TrustedURIs, ApplyTrustedURIs},
1758
+    {GConfKey_DelegationURIs, ApplyDelegationURIs},
1759
+    {GConfKey_IgnoreHosts, ApplyIgnoreHosts},
1760
+    {GConfKey_ProxyMode, ApplyProxyMode},
1761
+    {GConfKey_DownloadFolder, ApplyDownloadFolder},
1762
+    {GConfKey_DisableCookies, ApplyDisableCookies},
1763
+    {GConfKey_DisableJSChrome, ApplyWindowOpen},
1764
+    {GConfKey_DisableUnsafeProtocols, ApplyUnsafeProtocols},
1765
+    {GConfKey_AdditionalSafeProtocols, ApplyUnsafeProtocols},
1766
+    {GConfKey_WallpaperSetting, ApplyWallpaper},
1767
+    {GConfKey_DisableSavePassword, ApplyDisableSavePassword},
1768
+    {GConfKey_LoadImages, ApplyLoadImages},
1769
+    {GConfKey_DisablePopups, ApplyDisablePopups}
1770
+};
1771
+static ComplexMozPrefMapping sComplexMozPrefMappings[] = {
1772
+    {MozKey_TrustedURIs, ReverseApplyTrustedURIs},
1773
+    {MozKey_DelegationURIs, ReverseApplyDelegationURIs},
1774
+    {MozKey_IgnoreHosts, ReverseApplyIgnoreHosts},
1775
+    {MozKey_ProxyMode, ReverseApplyProxyMode},
1776
+    {MozKey_UseDownloadDir, ReverseApplyDownloadFolder},
1777
+    {MozKey_DownloadDirType, ReverseApplyDownloadFolder},
1778
+    {MozKey_DownloadDirExplicit, ReverseApplyDownloadFolder},
1779
+    {MozKey_CookieBehavior, ReverseApplyDisableCookies},
1780
+    {MozKey_RememberSignons, ReverseApplyDisableSavePassword},
1781
+    {MozKey_ImagePermissions, ReverseApplyLoadImages},
1782
+    {MozKey_DisablePopups, ReverseApplyDisablePopups}
1783
+};
1784
+// The unsafe protocol preferences are handled specially because
1785
+// they affect an unknown number of Mozilla preferences
1786
+// Window opener permissions are also handled specially so we don't have to
1787
+// repeat the windowOpenFeatures list.
1788
+
1789
+/* END preference mapping definition area */
1790
+
1791
+static PR_CALLBACK void GConfSimpleNotification(GConfClient* client,
1792
+                                                guint cnxn_id,
1793
+                                                GConfEntry *entry,
1794
+                                                gpointer user_data)
1795
+{
1796
+    nsSystemPrefService* service = NS_STATIC_CAST(nsSystemPrefService*, user_data);
1797
+    SimplePrefMapping* map = NS_STATIC_CAST(SimplePrefMapping*,
1798
+                                            service->GetSimpleCallbackData(cnxn_id));
1799
+    NS_ASSERTION(map, "Can't find mapping for callback");
1800
+    if (!map)
1801
+        return;
1802
 
1803
-    gchar *str = GConfClientGetString(mGConfClient,
1804
-                                      MozKey2GConfKey(aMozKey), NULL);
1805
-    if (str) {
1806
-        *retval = PL_strdup(str);
1807
-        g_free(str);
1808
-    }
1809
-    return NS_OK;
1810
+    ApplySimpleMapping(map, service->GetPrefs(), client);
1811
 }
1812
 
1813
-nsresult
1814
-GConfProxy::GetIntPref(const char *aMozKey, PRInt32 *retval)
1815
-{
1816
-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
1817
-    if (strcmp (aMozKey, "network.proxy.type") == 0) {
1818
-   gchar *str;
1819
-
1820
-   str = GConfClientGetString(mGConfClient,
1821
-                              MozKey2GConfKey (aMozKey), NULL);
1822
-
1823
-   if (str) {
1824
-       if (strcmp (str, "manual") == 0)
1825
-           *retval = 1;
1826
-       else if (strcmp (str, "auto") == 0)
1827
-           *retval = 2;
1828
-       else
1829
-           *retval = 0;
1830
-
1831
-       g_free (str);
1832
-   } else
1833
-       *retval = 0;
1834
-    } else {
1835
-       *retval = GConfClientGetInt(mGConfClient, 
1836
-                               MozKey2GConfKey(aMozKey), NULL);
1837
-    }
1838
+static PR_CALLBACK void GConfComplexNotification(GConfClient* client,
1839
+                                                 guint cnxn_id,
1840
+                                                 GConfEntry *entry,
1841
+                                                 gpointer user_data)
1842
+{
1843
+    nsSystemPrefService* service = NS_STATIC_CAST(nsSystemPrefService*, user_data);
1844
+    ComplexGConfPrefMapping* map = NS_STATIC_CAST(ComplexGConfPrefMapping*,
1845
+                                                  service->GetComplexCallbackData(cnxn_id));
1846
+    NS_ASSERTION(map, "Can't find mapping for callback");
1847
+    if (!map)
1848
+        return;
1849
 
1850
-    return NS_OK;
1851
+    map->callback(service, GetGConf());
1852
 }
1853
 
1854
-nsresult
1855
-GConfProxy::NotifyAdd (PRUint32 aAtom, void *aUserData)
1856
+nsresult nsSystemPrefService::LoadSystemPreferences(nsISystemPref* aPrefs)
1857
 {
1858
-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
1859
-
1860
-    const char *gconfKey = GetGConfKey(aAtom);
1861
-    if (!gconfKey)
1862
-        return NS_ERROR_FAILURE;
1863
+    mPref = aPrefs;
1864
 
1865
-    if (!mObservers) {
1866
-        mObservers = new nsAutoVoidArray();
1867
-        if (mObservers == nsnull)
1868
-            return NS_ERROR_OUT_OF_MEMORY;
1869
+    GConfClient* client = GetGConf();
1870
+    PRUint32 i;
1871
+    nsCOMPtr<nsIPrefBranch2> userPrefs = aPrefs->GetPrefUserBranch();
1872
+
1873
+    // Update gconf settings with any Mozilla settings that have
1874
+    // changed from the default. Do it before we register our
1875
+    // gconf notifications.
1876
+    for (i = 0; i < NUM_ELEM(sSimplePrefMappings); ++i) {
1877
+        gconf_client_add_dir(client, sSimplePrefMappings[i].gconfPrefName,
1878
+                             GCONF_CLIENT_PRELOAD_NONE, nsnull);
1879
+
1880
+        PRBool hasUserPref = PR_FALSE;
1881
+        nsresult rv =
1882
+            userPrefs->PrefHasUserValue(sSimplePrefMappings[i].mozPrefName,
1883
+                                        &hasUserPref);
1884
+        if (NS_FAILED(rv))
1885
+            return rv;
1886
+        if (hasUserPref && sSimplePrefMappings[i].allowWritesFromMozilla &&
1887
+            gconf_client_key_is_writable(client,
1888
+                                         sSimplePrefMappings[i].gconfPrefName,
1889
+                                         nsnull)) {
1890
+            rv = ReverseApplySimpleMapping(&sSimplePrefMappings[i],
1891
+                                           aPrefs, client);
1892
+            if (NS_FAILED(rv))
1893
+                return rv;
1894
+        }
1895
+    }
1896
+    for (i = 0; i < NUM_ELEM(sComplexGConfPrefMappings); ++i) {
1897
+        gconf_client_add_dir(client, sComplexGConfPrefMappings[i].gconfPrefName,
1898
+                             GCONF_CLIENT_PRELOAD_NONE, nsnull);
1899
+    }
1900
+    ComplexMozPrefChanged lastMozCallback = nsnull;
1901
+    for (i = 0; i < NUM_ELEM(sComplexMozPrefMappings); ++i) {
1902
+        PRBool hasUserPref = PR_FALSE;
1903
+        nsresult rv =
1904
+            userPrefs->PrefHasUserValue(sComplexMozPrefMappings[i].mozPrefName,
1905
+                                        &hasUserPref);
1906
+        if (NS_FAILED(rv))
1907
+            return rv;
1908
+        if (hasUserPref) {
1909
+            ComplexMozPrefChanged cb = sComplexMozPrefMappings[i].callback;
1910
+            if (cb != lastMozCallback) {
1911
+                cb(this, client);
1912
+                lastMozCallback = cb;
1913
+            }
1914
+        }
1915
     }
1916
  
1917
-    GConfCallbackData *pData = (GConfCallbackData *)
1918
-        nsMemory::Alloc(sizeof(GConfCallbackData));
1919
-    NS_ENSURE_TRUE(pData, NS_ERROR_OUT_OF_MEMORY);
1920
-
1921
-    pData->proxy = this;
1922
-    pData->userData = aUserData;
1923
-    pData->atom = aAtom;
1924
-    mObservers->AppendElement(pData);
1925
-
1926
-    GConfClientAddDir(mGConfClient, gconfKey,
1927
-                      0, // GCONF_CLIENT_PRELOAD_NONE,  don't preload anything 
1928
-                      NULL);
1929
-
1930
-    pData->notifyId = GConfClientNotifyAdd(mGConfClient, gconfKey,
1931
-                                           gconf_key_listener, pData,
1932
-                                           NULL, NULL);
1933
+    // Register simple mappings and callbacks
1934
+    for (i = 0; i < NUM_ELEM(sSimplePrefMappings); ++i) {
1935
+        guint cx = gconf_client_notify_add(client,
1936
+                                           sSimplePrefMappings[i].gconfPrefName,
1937
+                                           GConfSimpleNotification, this,
1938
+                                           nsnull, nsnull);
1939
+        mGConfSimpleCallbacks.Put(cx, &sSimplePrefMappings[i]);
1940
+        nsresult rv = ApplySimpleMapping(&sSimplePrefMappings[i], aPrefs, client);
1941
+        if (NS_FAILED(rv))
1942
+            return rv;
1943
+    }
1944
+
1945
+    ComplexGConfPrefChanged lastCallback = nsnull;
1946
+    for (i = 0; i < NUM_ELEM(sComplexGConfPrefMappings); ++i) {
1947
+        guint cx = gconf_client_notify_add(client,
1948
+                                           sComplexGConfPrefMappings[i].gconfPrefName,
1949
+                                           GConfComplexNotification, this,
1950
+                                           nsnull, nsnull);
1951
+        mGConfComplexCallbacks.Put(cx, &sComplexGConfPrefMappings[i]);
1952
+        ComplexGConfPrefChanged cb = sComplexGConfPrefMappings[i].callback;
1953
+        if (cb != lastCallback) {
1954
+            cb(this, client);
1955
+            lastCallback = cb;
1956
+        }
1957
+    }
1958
+
1959
+    ApplyUnsafeProtocols(this, client);
1960
+
1961
     return NS_OK;
1962
 }
1963
 
1964
-nsresult
1965
-GConfProxy::NotifyRemove (PRUint32 aAtom, const void *aUserData)
1966
+nsresult nsSystemPrefService::NotifyMozillaPrefChanged(const char* aPrefName)
1967
 {
1968
-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
1969
+    PRUint32 i;
1970
+    GConfClient* client = GetGConf();
1971
 
1972
-    PRIntn count = mObservers->Count();
1973
-    if (count <= 0)
1974
-        return NS_OK;
1975
-
1976
-    PRIntn i;
1977
-    GConfCallbackData *pData;
1978
-    for (i = 0; i < count; ++i) {
1979
-        pData = (GConfCallbackData *)mObservers->ElementAt(i);
1980
-        if (pData && pData->atom == aAtom && pData->userData == aUserData) {
1981
-            GConfClientNotifyRemove(mGConfClient, pData->notifyId);
1982
-            GConfClientRemoveDir(mGConfClient,
1983
-                                 GetGConfKey(pData->atom), NULL);
1984
-            mObservers->RemoveElementAt(i);
1985
-            nsMemory::Free(pData);
1986
-            break;
1987
+    for (i = 0; i < NUM_ELEM(sSimplePrefMappings); ++i) {
1988
+        if (!strcmp(aPrefName, sSimplePrefMappings[i].mozPrefName)) {
1989
+            ReverseApplySimpleMapping(&sSimplePrefMappings[i],
1990
+                                      mPref, client);
1991
         }
1992
     }
1993
-    return NS_OK;
1994
-}
1995
 
1996
-void
1997
-GConfProxy::InitFuncPtrs()
1998
-{
1999
-    //gconf client funcs
2000
-    GConfClientGetDefault =
2001
-        (GConfClientGetDefaultType) sGConfFuncList[0].FuncPtr;
2002
-    GConfClientGetBool =
2003
-        (GConfClientGetBoolType) sGConfFuncList[1].FuncPtr;
2004
-    GConfClientGetString =
2005
-        (GConfClientGetStringType) sGConfFuncList[2].FuncPtr;
2006
-    GConfClientGetInt =
2007
-        (GConfClientGetIntType) sGConfFuncList[3].FuncPtr;
2008
-    GConfClientNotifyAdd =
2009
-        (GConfClientNotifyAddType) sGConfFuncList[4].FuncPtr;
2010
-    GConfClientNotifyRemove =
2011
-        (GConfClientNotifyRemoveType) sGConfFuncList[5].FuncPtr;
2012
-    GConfClientAddDir =
2013
-        (GConfClientAddDirType) sGConfFuncList[6].FuncPtr;
2014
-    GConfClientRemoveDir =
2015
-        (GConfClientRemoveDirType) sGConfFuncList[7].FuncPtr;
2016
-
2017
-    //gconf entry funcs
2018
-    GConfEntryGetValue = (GConfEntryGetValueType) sGConfFuncList[8].FuncPtr;
2019
-    GConfEntryGetKey = (GConfEntryGetKeyType) sGConfFuncList[9].FuncPtr;
2020
-
2021
-    //gconf value funcs
2022
-    GConfValueGetBool = (GConfValueGetBoolType) sGConfFuncList[10].FuncPtr;
2023
-    GConfValueGetString = (GConfValueGetStringType) sGConfFuncList[11].FuncPtr;
2024
-    GConfValueGetInt = (GConfValueGetIntType) sGConfFuncList[12].FuncPtr;
2025
-}
2026
-
2027
-void
2028
-GConfProxy::OnNotify(void *aClient, void * aEntry, PRUint32 aNotifyId,
2029
-                     GConfCallbackData *aData)
2030
-{
2031
-    if (!mInitialized || !aEntry || (mGConfClient != aClient) || !aData)
2032
-        return;
2033
+    for (i = 0; i < NUM_ELEM(sComplexMozPrefMappings); ++i) {
2034
+        if (!strcmp(aPrefName, sComplexMozPrefMappings[i].mozPrefName)) {
2035
+            sComplexMozPrefMappings[i].callback(this, client);
2036
+        }
2037
+    }
2038
 
2039
-    if (GConfEntryGetValue(aEntry) == NULL)
2040
-        return;
2041
+    for (i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) {
2042
+        if (!strcmp(aPrefName, windowOpenFeatures[i])) {
2043
+            ReverseApplyWindowOpen(this, client);
2044
+        }
2045
+    }
2046
 
2047
-    PRUint32 prefAtom;
2048
-    nsresult rv = GetAtomForGConfKey(GConfEntryGetKey(aEntry), &prefAtom);
2049
-    if (NS_FAILED(rv))
2050
-        return;
2051
+    ReverseApplyUnsafeProtocols(this, client);
2052
 
2053
-    mSysPrefService->OnPrefChange(prefAtom, aData->userData);
2054
+    return NS_OK;
2055
 }
2056
 
2057
-nsresult
2058
-GConfProxy::GetAtom(const char *aKey, PRUint8 aNameType, PRUint32 *aAtom)
2059
+static PLDHashOperator PR_CALLBACK UnregisterSimple(const PRUint32& aKey,
2060
+                                                    SimplePrefMapping* aData,
2061
+                                                    void* aClosure)
2062
 {
2063
-    if (!aKey)
2064
-        return NS_ERROR_FAILURE;
2065
-    PRUint32 prefSize = sizeof(sPrefNameMapping) / sizeof(sPrefNameMapping[0]);
2066
-    for (PRUint32 index = 0; index < prefSize; ++index) {
2067
-        if (!strcmp((aNameType == 0) ? sPrefNameMapping[index].mozPrefName :
2068
-                    sPrefNameMapping[index].gconfPrefName, aKey)) {
2069
-            *aAtom = index;
2070
-            return NS_OK;
2071
-        }
2072
-    }
2073
-    return NS_ERROR_FAILURE;
2074
+    GConfClient* client = GetGConf();
2075
+    gconf_client_notify_remove(client, aKey);
2076
+    gconf_client_remove_dir(client, aData->gconfPrefName, nsnull);
2077
+    return PL_DHASH_NEXT;
2078
 }
2079
 
2080
-const char *
2081
-GConfProxy::GetKey(PRUint32 aAtom, PRUint8 aNameType)
2082
+static PLDHashOperator PR_CALLBACK UnregisterComplex(const PRUint32& aKey,
2083
+                                                     ComplexGConfPrefMapping* aData,
2084
+                                                     void* aClosure)
2085
 {
2086
-    PRUint32 mapSize = sizeof(sPrefNameMapping) / sizeof(sPrefNameMapping[0]);
2087
-    if (aAtom >= 0 && aAtom < mapSize)
2088
-        return (aNameType == 0) ? sPrefNameMapping[aAtom].mozPrefName :
2089
-            sPrefNameMapping[aAtom].gconfPrefName;
2090
-    return NULL;
2091
+    GConfClient* client = GetGConf();
2092
+    gconf_client_notify_remove(client, aKey);
2093
+    gconf_client_remove_dir(client, aData->gconfPrefName, nsnull);
2094
+    return PL_DHASH_NEXT;
2095
 }
2096
 
2097
-inline const char *
2098
-GConfProxy::MozKey2GConfKey(const char *aMozKey)
2099
+nsresult nsSystemPrefService::NotifyUnloadSystemPreferences()
2100
 {
2101
-    PRUint32 atom;
2102
-    nsresult rv = GetAtomForMozKey(aMozKey, &atom);
2103
-    if (NS_SUCCEEDED(rv))
2104
-        return GetGConfKey(atom);
2105
-    return NULL;
2106
-}
2107
+    // Unregister callbacks
2108
+    mGConfSimpleCallbacks.EnumerateRead(UnregisterSimple, this);
2109
+    mGConfSimpleCallbacks.Clear();
2110
+    mGConfComplexCallbacks.EnumerateRead(UnregisterComplex, this);
2111
+    mGConfComplexCallbacks.Clear();
2112
 
2113
-/* static */
2114
-void gconf_key_listener (void* client, guint cnxn_id,
2115
-                         void *entry, gpointer user_data)
2116
-{
2117
-    SYSPREF_LOG(("...SYSPREF_LOG...key listener get called \n"));
2118
-    if (!user_data)
2119
-        return;
2120
-    GConfCallbackData *pData = NS_REINTERPRET_CAST(GConfCallbackData *,
2121
-                                                   user_data);
2122
-    pData->proxy->OnNotify(client, entry, cnxn_id, pData);
2123
+    return NS_OK;
2124
 }
2125
+
2126
+// Factory stuff
2127
+
2128
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPrefService, Init)
2129
+
2130
+static const nsModuleComponentInfo components[] = {
2131
+    { NS_SYSTEMPREF_SERVICE_CLASSNAME,
2132
+      NS_SYSTEMPREF_SERVICE_CID,
2133
+      NS_SYSTEMPREF_SERVICE_CONTRACTID,
2134
+      nsSystemPrefServiceConstructor,
2135
+    },
2136
+};
2137
+
2138
+NS_IMPL_NSGETMODULE(nsSystemPrefServiceModule, components)
2139
--- extensions/pref/system-pref/src/nsISystemPrefService.h
2140
+++ extensions/pref/system-pref/src/nsISystemPrefService.h
2141
@@ -0,0 +1,107 @@
2142
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2143
+/* vim:expandtab:shiftwidth=4:tabstop=4:
2144
+ */
2145
+/* ***** BEGIN LICENSE BLOCK *****
2146
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
2147
+ *
2148
+ *
2149
+ * The contents of this file are subject to the Mozilla Public
2150
+ * License Version 1.1 (the "License"); you may not use this file
2151
+ * except in compliance with the License. You may obtain a copy of
2152
+ * the License at http://www.mozilla.org/MPL/
2153
+ *
2154
+ * Software distributed under the License is distributed on an "AS
2155
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
2156
+ * implied. See the License for the specific language governing
2157
+ * rights and limitations under the License.
2158
+ *
2159
+ * The Original Code is mozilla.org code.
2160
+ *
2161
+ * The Initial Developer of the Original Code is Novell
2162
+ * Portions created by Novell are Copyright (C) 2005 Novell,
2163
+ * All Rights Reserved.
2164
+ *
2165
+ * Original Author: Robert O'Callahan (rocallahan@novell.com)
2166
+ *
2167
+ * Contributor(s):
2168
+ *
2169
+ * Alternatively, the contents of this file may be used under the terms of
2170
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
2171
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
2172
+ * in which case the provisions of the GPL or the LGPL are applicable instead
2173
+ * of those above. If you wish to allow use of your version of this file only
2174
+ * under the terms of either the GPL or the LGPL, and not to allow others to
2175
+ * use your version of this file under the terms of the NPL, indicate your
2176
+ * decision by deleting the provisions above and replace them with the notice
2177
+ * and other provisions required by the GPL or the LGPL. If you do not delete
2178
+ * the provisions above, a recipient may use your version of this file under
2179
+ * the terms of any one of the NPL, the GPL or the LGPL.
2180
+ *
2181
+ * ***** END LICENSE BLOCK ***** */
2182
+
2183
+#ifndef nsISystemPrefService_h__
2184
+#define nsISystemPrefService_h__
2185
+
2186
+#include "nsCOMPtr.h"
2187
+#include "nsIPrefBranchInternal.h"
2188
+
2189
+#define NS_SYSTEMPREF_SERVICE_CONTRACTID "@mozilla.org/system-preferences-service;1"
2190
+
2191
+#define NS_ISYSTEMPREFSERVICE_IID   \
2192
+{ 0x006e1cfd, 0xd66a, 0x40b9, \
2193
+    { 0x84, 0xa1, 0x84, 0xf3, 0xe6, 0xa2, 0xca, 0xbc } }
2194
+
2195
+class nsISystemPref {
2196
+public:
2197
+    /**
2198
+     * Call one of these three methods to override a Mozilla
2199
+     * preference with a system value. You can call it multiple
2200
+     * times to change the value of a given preference to track
2201
+     * the underlying system value.
2202
+     *
2203
+     * If aLocked is true then we set the default preference and
2204
+     * lock it so the user value is ignored. If aLocked is false
2205
+     * then we unlock the Mozilla preference and set the Mozilla
2206
+     * user value.
2207
+     */
2208
+    virtual nsresult SetOverridingMozillaBoolPref(const char* aPrefName,
2209
+                                                  PRBool aValue, PRBool aLocked,
2210
+                                                  PRBool aPresent = PR_TRUE) = 0;
2211
+    virtual nsresult SetOverridingMozillaIntPref(const char* aPrefName,
2212
+                                                 PRInt32 aValue, PRBool aLocked,
2213
+                                                 PRBool aPresent = PR_TRUE) = 0;
2214
+    virtual nsresult SetOverridingMozillaStringPref(const char* aPrefName,
2215
+                                                    const char* aValue, PRBool aLocked,
2216
+                                                    PRBool aPresent = PR_TRUE) = 0;
2217
+    virtual nsresult StopOverridingMozillaPref(const char* aPrefName) = 0;
2218
+    virtual already_AddRefed<nsIPrefBranch2> GetPrefUserBranch() = 0;
2219
+    virtual already_AddRefed<nsIPrefBranch> GetPrefDefaultBranch() = 0;
2220
+};
2221
+
2222
+class nsISystemPrefService : public nsISupports {
2223
+public:
2224
+    NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISYSTEMPREFSERVICE_IID)
2225
+
2226
+    /**
2227
+     * Load the system prefs from the store into their corresponding
2228
+     * Mozilla prefs, calling SetOverridingMozillaPref on each
2229
+     * such pref.
2230
+     */
2231
+    virtual nsresult LoadSystemPreferences(nsISystemPref* aPrefs) = 0;
2232
+
2233
+    /**
2234
+     * Notify that a Mozilla user pref that is being overridden by the
2235
+     * store has changed.  The new value of the Mozilla pref should be
2236
+     * written back to the store.
2237
+     */
2238
+    virtual nsresult NotifyMozillaPrefChanged(const char* aPrefName) = 0;
2239
+
2240
+    /**
2241
+     * Notify that we're about to stop using the system prefs.  After
2242
+     * this, nsSystemPref will automatically stop overriding all
2243
+     * Mozilla prefs that are being overridden.
2244
+     */
2245
+    virtual nsresult NotifyUnloadSystemPreferences() = 0;
2246
+};
2247
+
2248
+#endif
2249
--- extensions/pref/system-pref/src/nsSystemPref.cpp
2250
+++ extensions/pref/system-pref/src/nsSystemPref.cpp
2251
@@ -24,6 +24,7 @@
2252
  * Original Author: Bolian Yin (bolian.yin@sun.com)
2253
  *
2254
  * Contributor(s):
2255
+ *   Robert O'Callahan (rocallahan@novell.com)
2256
  *
2257
  * Alternatively, the contents of this file may be used under the terms of
2258
  * either the GNU General Public License Version 2 or later (the "GPL"), or
2259
@@ -41,66 +42,60 @@
2260
 
2261
 #include "nsSystemPref.h"
2262
 #include "nsIObserverService.h"
2263
+#include "nsIAppStartupNotifier.h"
2264
+#include "nsIPrefService.h"
2265
+#include "nsIPrefBranch.h"
2266
+#include "nsICategoryManager.h"
2267
+#include "nsIServiceManager.h"
2268
 
2269
 #include "nsSystemPrefLog.h"
2270
-#include "nsSystemPrefService.h"
2271
 #include "nsString.h"
2272
 
2273
-const char sSysPrefString[] = "config.use_system_prefs";
2274
-union MozPrefValue {
2275
-    char *      stringVal;
2276
-    PRInt32     intVal;
2277
-    PRBool      boolVal;
2278
-};
2279
+#include <stdlib.h>
2280
 
2281
 struct SysPrefItem {
2282
-    const char *prefName;       // mozilla pref string name
2283
-    MozPrefValue defaultValue;  // store the mozilla default value
2284
-    PRBool isLocked;  // store the mozilla lock status
2285
+    // Saved values on both branches
2286
+    PRInt32      savedUserValueScalar;
2287
+    char*        savedUserValueString;
2288
+    PRInt32      savedDefaultValueScalar;
2289
+    char*        savedDefaultValueString;
2290
+    // When this is true, then the value was locked originally
2291
+    PRPackedBool savedLocked;
2292
+    // When this is true, then there was a user value
2293
+    PRPackedBool savedUserPresent;
2294
+    PRPackedBool ignore;
2295
+    
2296
     SysPrefItem() {
2297
-        prefName = nsnull;
2298
-        defaultValue.intVal = 0;
2299
-        defaultValue.stringVal = nsnull;
2300
-        defaultValue.boolVal = PR_FALSE;
2301
-        isLocked = PR_FALSE;
2302
+        savedUserValueScalar = 0;
2303
+        savedUserValueString = nsnull;
2304
+        savedDefaultValueScalar = 0;
2305
+        savedDefaultValueString = nsnull;
2306
+        savedUserPresent = PR_FALSE;
2307
+        savedLocked = PR_FALSE;
2308
+        ignore = PR_FALSE;
2309
     }
2310
-    void SetPrefName(const char *aPrefName) {
2311
-        prefName = aPrefName;
2312
+
2313
+    virtual ~SysPrefItem() {
2314
+        nsMemory::Free(savedUserValueString);
2315
+        nsMemory::Free(savedDefaultValueString);
2316
     }
2317
 };
2318
 
2319
-// all prefs that mozilla need to read from host system if they are available
2320
-static const char *sSysPrefList[] = {
2321
-    "network.proxy.http",
2322
-    "network.proxy.http_port",
2323
-    "network.proxy.ftp",
2324
-    "network.proxy.ftp_port",
2325
-    "network.proxy.ssl",
2326
-    "network.proxy.ssl_port",
2327
-    "network.proxy.socks",
2328
-    "network.proxy.socks_port",
2329
-    "network.proxy.no_proxies_on",
2330
-    "network.proxy.autoconfig_url",
2331
-    "network.proxy.type",
2332
-    "config.use_system_prefs.accessibility",
2333
-};
2334
+static const char sSysPrefString[] = "config.use_system_prefs";
2335
 
2336
 PRLogModuleInfo *gSysPrefLog = NULL;
2337
 
2338
 NS_IMPL_ISUPPORTS2(nsSystemPref, nsIObserver, nsISupportsWeakReference)
2339
 
2340
-nsSystemPref::nsSystemPref():
2341
-    mSysPrefService(nsnull),
2342
-    mEnabled(PR_FALSE),
2343
-    mSysPrefs(nsnull)
2344
+nsSystemPref::nsSystemPref() : mIgnorePrefSetting(PR_FALSE)
2345
 {
2346
+   mSavedPrefs.Init();
2347
+   mCachedUserPrefBranch = nsnull;
2348
+   mCachedDefaultPrefBranch = nsnull;
2349
 }
2350
 
2351
 nsSystemPref::~nsSystemPref()
2352
 {
2353
-    mSysPrefService = nsnull;
2354
-    mEnabled = PR_FALSE;
2355
-    delete [] mSysPrefs;
2356
 }
2357
 
2358
 ///////////////////////////////////////////////////////////////////////////////
2359
@@ -131,6 +126,54 @@
2360
     return(rv);
2361
 }
2362
 
2363
+already_AddRefed<nsIPrefBranch2>
2364
+nsSystemPref::GetPrefUserBranch()
2365
+{
2366
+    if (mCachedUserPrefBranch) {
2367
+        NS_ADDREF(mCachedUserPrefBranch);
2368
+        return mCachedUserPrefBranch;
2369
+    }
2370
+
2371
+    nsresult rv;
2372
+    nsCOMPtr<nsIPrefService> prefService = 
2373
+        do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2374
+    if (NS_FAILED(rv))
2375
+        return nsnull;
2376
+    nsCOMPtr<nsIPrefBranch> prefBranch;
2377
+    rv = prefService->GetBranch(nsnull, getter_AddRefs(prefBranch));
2378
+    if (NS_FAILED(rv))
2379
+        return nsnull;
2380
+    nsCOMPtr<nsIPrefBranch2> pb2(do_QueryInterface(prefBranch));
2381
+    if (!pb2)
2382
+        return nsnull;
2383
+    
2384
+    nsIPrefBranch2* result = nsnull;
2385
+    pb2.swap(result);
2386
+    return result;
2387
+}
2388
+
2389
+already_AddRefed<nsIPrefBranch>
2390
+nsSystemPref::GetPrefDefaultBranch()
2391
+{
2392
+    if (mCachedDefaultPrefBranch) {
2393
+        NS_ADDREF(mCachedDefaultPrefBranch);
2394
+        return mCachedDefaultPrefBranch;
2395
+    }
2396
+
2397
+    nsresult rv;
2398
+    nsCOMPtr<nsIPrefService> prefService = 
2399
+        do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2400
+    if (NS_FAILED(rv))
2401
+        return nsnull;
2402
+    nsCOMPtr<nsIPrefBranch> prefBranch;
2403
+    rv = prefService->GetDefaultBranch(nsnull, getter_AddRefs(prefBranch));
2404
+    if (NS_FAILED(rv))
2405
+        return nsnull;
2406
+    nsIPrefBranch* pb = nsnull;
2407
+    prefBranch.swap(pb);
2408
+    return pb;
2409
+}
2410
+
2411
 ///////////////////////////////////////////////////////////////////////////////
2412
 // nsSystemPref::Observe
2413
 // Observe notifications from mozilla pref system and system prefs (if enabled)
2414
@@ -145,330 +188,446 @@
2415
     if (!aTopic)
2416
         return NS_OK;
2417
 
2418
-    // if we are notified by pref service
2419
-    // check the system pref settings
2420
-    if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) {
2421
-        SYSPREF_LOG(("Observed: %s\n", aTopic));
2422
-
2423
-        nsCOMPtr<nsIPrefBranch2> prefBranch =
2424
-            do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2425
-        if (NS_FAILED(rv))
2426
-            return rv;
2427
+    nsCOMPtr<nsIPrefBranch2> userBranch = GetPrefUserBranch();
2428
+    nsCOMPtr<nsIPrefBranch> defaultBranch = GetPrefDefaultBranch();
2429
 
2430
-        rv = prefBranch->GetBoolPref(sSysPrefString, &mEnabled);
2431
+    // Check the default branch first. If system prefs are enabled
2432
+    // by default, then don't check the user prefs; we don't want
2433
+    // to allow users to change the default.
2434
+    PRBool defaultEnabled;
2435
+    rv = defaultBranch->GetBoolPref(sSysPrefString, &defaultEnabled);
2436
+    if (NS_FAILED(rv)) {
2437
+        SYSPREF_LOG(("...Failed to Get %s\n", sSysPrefString));
2438
+        return rv;
2439
+    }
2440
+    PRBool enabled = defaultEnabled;
2441
+    if (!enabled) {
2442
+        rv = userBranch->GetBoolPref(sSysPrefString, &enabled);
2443
         if (NS_FAILED(rv)) {
2444
-            SYSPREF_LOG(("...FAil to Get %s\n", sSysPrefString));
2445
+            SYSPREF_LOG(("...Failed to Get %s\n", sSysPrefString));
2446
             return rv;
2447
         }
2448
+    }
2449
 
2450
-        // if there is no system pref service, assume nothing happen to us
2451
-        mSysPrefService = do_GetService(NS_SYSTEMPREF_SERVICE_CONTRACTID, &rv);
2452
-        if (NS_FAILED(rv) || !mSysPrefService) {
2453
-            SYSPREF_LOG(("...No System Pref Service\n"));
2454
-            return NS_OK;
2455
-        }
2456
+    if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) {
2457
+        // The prefs have just loaded. This is the first thing that
2458
+        // happens to us.
2459
+        SYSPREF_LOG(("Observed: %s\n", aTopic));
2460
 
2461
-        // listen on its changes
2462
-        rv = prefBranch->AddObserver(sSysPrefString, this, PR_TRUE);
2463
+        // listen on changes to use_system_pref. It's OK to
2464
+        // hold a strong reference because we don't keep a reference
2465
+        // to the pref branch.
2466
+        rv = userBranch->AddObserver(sSysPrefString, this, PR_TRUE);
2467
         if (NS_FAILED(rv)) {
2468
-            SYSPREF_LOG(("...FAil to add observer for %s\n", sSysPrefString));
2469
+            SYSPREF_LOG(("...Failed to add observer for %s\n", sSysPrefString));
2470
             return rv;
2471
         }
2472
 
2473
-        if (!mEnabled) {
2474
-            SYSPREF_LOG(("%s is disabled\n", sSysPrefString));
2475
+        NS_ASSERTION(!mSysPrefService, "Should not be already enabled");
2476
+        if (!enabled) {
2477
+            // Don't load the system pref service if the preference is
2478
+            // not set.
2479
             return NS_OK;
2480
         }
2481
-        SYSPREF_LOG(("%s is enabled\n", sSysPrefString));
2482
-        rv = UseSystemPrefs();
2483
 
2484
-    }
2485
-    // sSysPrefString value was changed, update ...
2486
-    else if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) &&
2487
-             NS_ConvertUTF8toUCS2(sSysPrefString).Equals(aData)) {
2488
-        SYSPREF_LOG(("++++++ Notify: topic=%s data=%s\n",
2489
-                     aTopic, NS_ConvertUCS2toUTF8(aData).get()));
2490
+        SYSPREF_LOG(("%s is enabled\n", sSysPrefString));
2491
 
2492
-        nsCOMPtr<nsIPrefBranch> prefBranch =
2493
-            do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2494
+        rv = LoadSystemPrefs();
2495
         if (NS_FAILED(rv))
2496
             return rv;
2497
 
2498
-        PRBool enabled = mEnabled;
2499
-        rv = prefBranch->GetBoolPref(sSysPrefString, &mEnabled);
2500
-        if (enabled != mEnabled) {
2501
-            if (mEnabled)
2502
-                //read prefs from system
2503
-                rv = UseSystemPrefs();
2504
-            else
2505
-                //roll back to mozilla prefs
2506
-                rv = UseMozillaPrefs();
2507
+        // Lock config.use_system_prefs so the user can't undo
2508
+        // it. But only do this if it was set by in the default prefs;
2509
+        // if it was not set by default, then locking it would actually
2510
+        // unset the value! And the user should be allowed to turn off
2511
+        // something they set themselves.
2512
+        if (NS_SUCCEEDED(rv) && defaultEnabled) {
2513
+            userBranch->LockPref(sSysPrefString);
2514
         }
2515
     }
2516
 
2517
-    // if the system pref notify us that some pref has been changed by user
2518
-    // outside mozilla. We need to read it again.
2519
-    else if (!nsCRT::strcmp(aTopic, NS_SYSTEMPREF_PREFCHANGE_TOPIC_ID) &&
2520
-             aData) {
2521
-        NS_ASSERTION(mEnabled == PR_TRUE, "Should not listen when disabled");
2522
-        SYSPREF_LOG(("====== System Pref Notify topic=%s data=%s\n",
2523
-                     aTopic, (char*)aData));
2524
-        rv = ReadSystemPref(NS_LossyConvertUCS2toASCII(aData).get());
2525
-        return NS_OK;
2526
-    } else if (!nsCRT::strcmp(aTopic,"profile-before-change")) {
2527
-      //roll back to mozilla prefs
2528
-      if (mEnabled)
2529
-        UseMozillaPrefs();
2530
-      mEnabled = PR_FALSE;
2531
-      mSysPrefService = nsnull;
2532
-      delete [] mSysPrefs;
2533
-      mSysPrefs = nsnull;
2534
-    } else
2535
-        SYSPREF_LOG(("Not needed topic Received %s\n", aTopic));
2536
-    return rv;
2537
-}
2538
+    if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) &&
2539
+        nsDependentString(aData).EqualsASCII(sSysPrefString)) {
2540
+        // sSysPrefString value was changed, update...
2541
+        SYSPREF_LOG(("++++++ Notify: topic=%s data=%s\n",
2542
+                     aTopic, NS_ConvertUCS2toUTF8(aData).get()));
2543
+        if (mSysPrefService && !enabled)
2544
+            return RestoreMozillaPrefs();
2545
+        if (!mSysPrefService && enabled) {
2546
+            // Don't lock it. If the user enabled use_system_prefs,
2547
+            // they should be allowed to unlock it.
2548
+            return LoadSystemPrefs();
2549
+        }
2550
 
2551
-/* private */
2552
+        // didn't change?
2553
+        return NS_OK;
2554
+    }
2555
 
2556
-////////////////////////////////////////////////////////////////
2557
-// nsSystemPref::UseSystemPrefs
2558
-// Read all the prefs in the table from system, listen for their
2559
-// changes in system pref service.
2560
-////////////////////////////////////////////////////////////////
2561
-nsresult
2562
-nsSystemPref::UseSystemPrefs()
2563
-{
2564
-    SYSPREF_LOG(("\n====Now Use system prefs==\n"));
2565
-    nsresult rv = NS_OK;
2566
-    if (!mSysPrefService) {
2567
-        return NS_ERROR_FAILURE;
2568
+    if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
2569
+        // some other pref changed, tell the backend if there is one
2570
+        if (mSysPrefService && !mIgnorePrefSetting) {
2571
+            NS_LossyConvertUTF16toASCII tmp(aData);
2572
+#ifdef DEBUG
2573
+            PRBool isLocked;
2574
+            userBranch->PrefIsLocked(tmp.get(), &isLocked);
2575
+            NS_ASSERTION(!isLocked, "Locked pref is changing?");
2576
+#endif
2577
+            SysPrefItem* item;
2578
+            if (!mSavedPrefs.Get(tmp, &item)) {
2579
+                NS_ERROR("Notified about pref change that we didn't ask about?");
2580
+            } else {
2581
+                if (!item->ignore) {
2582
+                    mSysPrefService->NotifyMozillaPrefChanged(tmp.get());
2583
+                }
2584
+            }
2585
+        }
2586
+        return NS_OK;
2587
     }
2588
 
2589
-    PRIntn sysPrefCount= sizeof(sSysPrefList) / sizeof(sSysPrefList[0]);
2590
+    if (!nsCRT::strcmp(aTopic,"profile-before-change"))
2591
+        return RestoreMozillaPrefs();
2592
 
2593
-    if (!mSysPrefs) {
2594
-        mSysPrefs = new SysPrefItem[sysPrefCount];
2595
-        if (!mSysPrefs)
2596
-            return NS_ERROR_OUT_OF_MEMORY;
2597
-        for (PRIntn index = 0; index < sysPrefCount; ++index)
2598
-            mSysPrefs[index].SetPrefName(sSysPrefList[index]);
2599
-    }
2600
+    SYSPREF_LOG(("Not needed topic Received %s\n", aTopic));
2601
 
2602
-    for (PRIntn index = 0; index < sysPrefCount; ++index) {
2603
-        // save mozilla prefs
2604
-        SaveMozDefaultPref(mSysPrefs[index].prefName,
2605
-                           &mSysPrefs[index].defaultValue,
2606
-                           &mSysPrefs[index].isLocked);
2607
-
2608
-        // get the system prefs
2609
-        ReadSystemPref(mSysPrefs[index].prefName);
2610
-        SYSPREF_LOG(("Add Listener on %s\n", mSysPrefs[index].prefName));
2611
-        mSysPrefService->AddObserver(mSysPrefs[index].prefName,
2612
-                                     this, PR_TRUE);
2613
-    }
2614
     return rv;
2615
 }
2616
 
2617
-//////////////////////////////////////////////////////////////////////
2618
-// nsSystemPref::ReadSystemPref
2619
-// Read a pref value from system pref service, and lock it in mozilla.
2620
-//////////////////////////////////////////////////////////////////////
2621
 nsresult
2622
-nsSystemPref::ReadSystemPref(const char *aPrefName)
2623
+nsSystemPref::SetOverridingMozillaBoolPref(const char* aPrefName,
2624
+                                           PRBool aValue, PRBool aLock, PRBool aPresent)
2625
 {
2626
-    if (!mSysPrefService)
2627
-        return NS_ERROR_FAILURE;
2628
-    nsresult rv;
2629
-
2630
-    nsCOMPtr<nsIPrefBranch> prefBranch
2631
-        (do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
2632
-    if (NS_FAILED(rv))
2633
-        return rv;
2634
-
2635
-    SYSPREF_LOG(("about to read aPrefName %s\n", aPrefName));
2636
+    return OverridePref(aPrefName, nsIPrefBranch::PREF_BOOL,
2637
+                        (void*)aValue, aLock, aPresent);
2638
+}
2639
 
2640
-    prefBranch->UnlockPref(aPrefName);
2641
+nsresult
2642
+nsSystemPref::SetOverridingMozillaIntPref(const char* aPrefName,
2643
+                                          PRInt32 aValue, PRBool aLock, PRBool aPresent)
2644
+{
2645
+    return OverridePref(aPrefName, nsIPrefBranch::PREF_INT,
2646
+                        (void*)aValue, aLock, aPresent);
2647
+}
2648
 
2649
-    PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
2650
-    nsXPIDLCString strValue;
2651
-    PRInt32 intValue = 0;
2652
-    PRBool boolValue = PR_FALSE;
2653
+nsresult
2654
+nsSystemPref::SetOverridingMozillaStringPref(const char* aPrefName,
2655
+                                             const char* aValue, PRBool aLock, PRBool aPresent)
2656
+{
2657
+    return OverridePref(aPrefName, nsIPrefBranch::PREF_STRING,
2658
+                        (void*)aValue, aLock, aPresent);
2659
+}
2660
 
2661
-    rv = prefBranch->GetPrefType(aPrefName, &prefType);
2662
-    if (NS_FAILED(rv))
2663
-        return rv;
2664
-    switch (prefType) {
2665
+static nsresult RestorePrefValue(PRInt32 aPrefType,
2666
+                                 const char* aPrefName,
2667
+                                 SysPrefItem* aItem,
2668
+                                 nsIPrefBranch* aUser,
2669
+                                 nsIPrefBranch* aDefault)
2670
+{
2671
+    switch (aPrefType) {
2672
     case nsIPrefBranch::PREF_STRING:
2673
-        mSysPrefService->GetCharPref(aPrefName, getter_Copies(strValue));
2674
-        SYSPREF_LOG(("system value is %s\n", strValue.get()));
2675
-
2676
-        prefBranch->SetCharPref(aPrefName, strValue.get());
2677
+        aDefault->SetCharPref(aPrefName,
2678
+                              aItem->savedDefaultValueString);
2679
+        if (aItem->savedUserPresent) {
2680
+            aUser->SetCharPref(aPrefName, aItem->savedUserValueString);
2681
+        }
2682
         break;
2683
     case nsIPrefBranch::PREF_INT:
2684
-        mSysPrefService->GetIntPref(aPrefName, &intValue);
2685
-        SYSPREF_LOG(("system value is %d\n", intValue));
2686
-
2687
-        prefBranch->SetIntPref(aPrefName, intValue);
2688
+        aDefault->SetIntPref(aPrefName, aItem->savedDefaultValueScalar);
2689
+        if (aItem->savedUserPresent) {
2690
+            aUser->SetIntPref(aPrefName, aItem->savedUserValueScalar);
2691
+        }
2692
         break;
2693
     case nsIPrefBranch::PREF_BOOL:
2694
-        mSysPrefService->GetBoolPref(aPrefName, &boolValue);
2695
-        SYSPREF_LOG(("system value is %s\n", boolValue ? "TRUE" : "FALSE"));
2696
-
2697
-        prefBranch->SetBoolPref(aPrefName, boolValue);
2698
+        aDefault->SetBoolPref(aPrefName, aItem->savedDefaultValueScalar);
2699
+        if (aItem->savedUserPresent) {
2700
+            aUser->SetBoolPref(aPrefName, aItem->savedUserValueScalar);
2701
+        }
2702
         break;
2703
     default:
2704
-        SYSPREF_LOG(("Fail to system value for it\n"));
2705
+        NS_ERROR("Unknown preference type");
2706
         return NS_ERROR_FAILURE;
2707
     }
2708
-    prefBranch->LockPref(aPrefName);
2709
+
2710
+    if (!aItem->savedUserPresent) {
2711
+        aUser->DeleteBranch(aPrefName);
2712
+    }
2713
+
2714
     return NS_OK;
2715
 }
2716
 
2717
-//////////////////////////////////////////////////////////////////////
2718
-// nsSystemPref::UseMozillaPrefs
2719
-// Restore mozilla default prefs, remove system pref listeners
2720
-/////////////////////////////////////////////////////////////////////
2721
-nsresult
2722
-nsSystemPref::UseMozillaPrefs()
2723
+static PLDHashOperator PR_CALLBACK RestorePref(const nsACString& aKey,
2724
+                                               SysPrefItem* aItem,
2725
+                                               void* aClosure)
2726
 {
2727
-    nsresult rv = NS_OK;
2728
-    SYSPREF_LOG(("\n====Now rollback to Mozilla prefs==\n"));
2729
+    nsSystemPref* prefs = NS_STATIC_CAST(nsSystemPref*, aClosure);
2730
+    nsCOMPtr<nsIPrefBranch2> userBranch = prefs->GetPrefUserBranch();
2731
+    const nsCString& prefName = PromiseFlatCString(aKey);
2732
+    
2733
+    PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
2734
+    nsresult rv = userBranch->GetPrefType(prefName.get(), &prefType);
2735
+    if (NS_FAILED(rv))
2736
+        return PL_DHASH_NEXT;
2737
+    PRBool isLocked;
2738
+    userBranch->PrefIsLocked(prefName.get(), &isLocked);
2739
+    if (NS_FAILED(rv))
2740
+        return PL_DHASH_NEXT;
2741
 
2742
-    // if we did not use system prefs, do nothing
2743
-    if (!mSysPrefService)
2744
-        return NS_OK;
2745
+    // Remove our observer before we change the value
2746
+    userBranch->RemoveObserver(prefName.get(), prefs);
2747
+    // Remember to ignore this item. Because some prefs start with "config.use_system_prefs",
2748
+    // which we always observe, even after we remove the observer, changes to the pref will
2749
+    // still be observed by us. We must ignore them.
2750
+    aItem->ignore = PR_TRUE;
2751
 
2752
-    PRIntn sysPrefCount= sizeof(sSysPrefList) / sizeof(sSysPrefList[0]);
2753
-    for (PRIntn index = 0; index < sysPrefCount; ++index) {
2754
-        // restore mozilla default value and free string memory if needed
2755
-        RestoreMozDefaultPref(mSysPrefs[index].prefName,
2756
-                              &mSysPrefs[index].defaultValue,
2757
-                              mSysPrefs[index].isLocked);
2758
-        SYSPREF_LOG(("stop listening on %s\n", mSysPrefs[index].prefName));
2759
-        mSysPrefService->RemoveObserver(mSysPrefs[index].prefName,
2760
-                                        this);
2761
+    // Unlock the pref so we can set it
2762
+    if (isLocked) {
2763
+        userBranch->UnlockPref(prefName.get());
2764
     }
2765
-    return rv;
2766
+
2767
+    nsCOMPtr<nsIPrefBranch> defaultBranch = prefs->GetPrefDefaultBranch();
2768
+
2769
+    RestorePrefValue(prefType, prefName.get(), aItem,
2770
+                     userBranch, defaultBranch);
2771
+
2772
+    if (aItem->savedLocked) {
2773
+        userBranch->LockPref(prefName.get());
2774
+    }
2775
+
2776
+    return PL_DHASH_NEXT;
2777
 }
2778
 
2779
-////////////////////////////////////////////////////////////////////////////
2780
-// nsSystemPref::RestoreMozDefaultPref
2781
-// Save the saved mozilla default value.
2782
-// It is also responsible for allocate the string memory when needed, because
2783
-// this method know what type of value is stored.
2784
-/////////////////////////////////////////////////////////////////////////////
2785
 nsresult
2786
-nsSystemPref::SaveMozDefaultPref(const char *aPrefName,
2787
-                                 MozPrefValue *aPrefValue,
2788
-                                 PRBool *aLocked)
2789
-{
2790
-    NS_ENSURE_ARG_POINTER(aPrefName);
2791
-    NS_ENSURE_ARG_POINTER(aPrefValue);
2792
-    NS_ENSURE_ARG_POINTER(aLocked);
2793
-
2794
-    nsresult rv;
2795
+nsSystemPref::StopOverridingMozillaPref(const char* aPrefName)
2796
+{
2797
+    SysPrefItem* item;
2798
+    nsDependentCString prefNameStr(aPrefName);
2799
+    if (!mSavedPrefs.Get(prefNameStr, &item))
2800
+        return NS_OK;
2801
 
2802
-    nsCOMPtr<nsIPrefBranch> prefBranch =
2803
-        do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2804
-    if (NS_FAILED(rv))
2805
-        return rv;
2806
+    RestorePref(prefNameStr, item, this);
2807
+    mSavedPrefs.Remove(prefNameStr);
2808
+    delete item;
2809
+    return NS_OK;
2810
+}
2811
 
2812
-    SYSPREF_LOG(("Save Mozilla value for %s\n", aPrefName));
2813
+/* private */
2814
 
2815
+nsresult
2816
+nsSystemPref::OverridePref(const char* aPrefName, PRInt32 aType,
2817
+                           void* aValue, PRBool aLock, PRBool aPresent)
2818
+{
2819
+    nsCOMPtr<nsIPrefBranch2> userBranch = GetPrefUserBranch();
2820
+    nsCOMPtr<nsIPrefBranch> defaultBranch = GetPrefDefaultBranch();
2821
     PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
2822
-    nsXPIDLCString strValue;
2823
-
2824
-    rv = prefBranch->GetPrefType(aPrefName, &prefType);
2825
+    nsresult rv = userBranch->GetPrefType(aPrefName, &prefType);
2826
     if (NS_FAILED(rv))
2827
         return rv;
2828
-    switch (prefType) {
2829
-    case nsIPrefBranch::PREF_STRING:
2830
-        prefBranch->GetCharPref(aPrefName,
2831
-                                getter_Copies(strValue));
2832
-        SYSPREF_LOG(("Mozilla value is %s", strValue.get()));
2833
-
2834
-        if (aPrefValue->stringVal)
2835
-            PL_strfree(aPrefValue->stringVal);
2836
-        aPrefValue->stringVal = PL_strdup(strValue.get());
2837
-        break;
2838
-    case nsIPrefBranch::PREF_INT:
2839
-        prefBranch->GetIntPref(aPrefName, &aPrefValue->intVal);
2840
-        SYSPREF_LOG(("Mozilla value is %d\n", aPrefValue->intVal));
2841
 
2842
-        break;
2843
-    case nsIPrefBranch::PREF_BOOL:
2844
-        prefBranch->GetBoolPref(aPrefName, &aPrefValue->boolVal);
2845
-        SYSPREF_LOG(("Mozilla value is %s\n",
2846
-                     aPrefValue->boolVal ? "TRUE" : "FALSE"));
2847
+    PRBool isLocked;
2848
+    rv = userBranch->PrefIsLocked(aPrefName, &isLocked);
2849
+    if (NS_FAILED(rv))
2850
+        return rv;
2851
+    PRBool hasUserValue;
2852
+    rv = userBranch->PrefHasUserValue(aPrefName, &hasUserValue);
2853
+    if (NS_FAILED(rv))
2854
+        return rv;
2855
 
2856
-        break;
2857
-    default:
2858
-        SYSPREF_LOG(("Fail to Read Mozilla value for it\n"));
2859
-        return NS_ERROR_FAILURE;
2860
+    if (prefType == 0) {
2861
+        // Preference does not exist. Allow the system prefs to
2862
+        // set it.
2863
+    } else {
2864
+        NS_ASSERTION(aType == prefType,
2865
+                     "System pref engine passed incorrect type for Mozilla pref");
2866
+        if (aType != prefType)
2867
+            return NS_ERROR_FAILURE;
2868
+    }
2869
+
2870
+    if (prefType != 0) {
2871
+        nsDependentCString prefNameStr(aPrefName);
2872
+        SysPrefItem* item = nsnull;
2873
+        if (!mSavedPrefs.Get(prefNameStr, &item)) {
2874
+            // Need to save the existing value away
2875
+            item = new SysPrefItem();
2876
+            if (!item)
2877
+                return NS_ERROR_OUT_OF_MEMORY;
2878
+
2879
+            item->savedLocked = isLocked;
2880
+            item->savedUserPresent = hasUserValue;
2881
+        
2882
+            switch (prefType) {
2883
+            case nsIPrefBranch::PREF_STRING:
2884
+                if (hasUserValue) {
2885
+                    userBranch->GetCharPref(aPrefName, &item->savedUserValueString);
2886
+                }
2887
+                defaultBranch->GetCharPref(aPrefName, &item->savedDefaultValueString);
2888
+                break;
2889
+            case nsIPrefBranch::PREF_INT:
2890
+                if (hasUserValue) {
2891
+                    userBranch->GetIntPref(aPrefName, &item->savedUserValueScalar);
2892
+                }
2893
+                defaultBranch->GetIntPref(aPrefName, &item->savedDefaultValueScalar);
2894
+                break;
2895
+            case nsIPrefBranch::PREF_BOOL:
2896
+                if (hasUserValue) {
2897
+                    userBranch->GetBoolPref(aPrefName, &item->savedUserValueScalar);
2898
+                }
2899
+                defaultBranch->GetBoolPref(aPrefName, &item->savedDefaultValueScalar);
2900
+                break;
2901
+            default:
2902
+                NS_ERROR("Unknown preference type");
2903
+                delete item;
2904
+                return NS_ERROR_FAILURE;
2905
+            }
2906
+
2907
+            mSavedPrefs.Put(prefNameStr, item);
2908
+
2909
+            // Watch the user value in case it changes on the Mozilla side
2910
+            // If 'aLock' is true then it shouldn't change and we don't
2911
+            // need the observer, but don't bother optimizing for that.
2912
+            userBranch->AddObserver(aPrefName, this, PR_TRUE);
2913
+        } else {
2914
+            if (isLocked != aLock) {
2915
+                // restore pref value on user and default branches
2916
+                RestorePrefValue(prefType, aPrefName, item,
2917
+                                 userBranch, defaultBranch);
2918
+            }
2919
+        }
2920
     }
2921
-    rv = prefBranch->PrefIsLocked(aPrefName, aLocked);
2922
-    SYSPREF_LOG((" (%s).\n", aLocked ? "Locked" : "NOT Locked"));
2923
-    return rv;
2924
-}
2925
 
2926
-////////////////////////////////////////////////////////////////////////////
2927
-// nsSystemPref::RestoreMozDefaultPref
2928
-// Restore the saved mozilla default value to pref service.
2929
-// It is also responsible for free the string memory when needed, because
2930
-// this method know what type of value is stored.
2931
-/////////////////////////////////////////////////////////////////////////////
2932
-nsresult
2933
-nsSystemPref::RestoreMozDefaultPref(const char *aPrefName,
2934
-                                    MozPrefValue *aPrefValue,
2935
-                                    PRBool aLocked)
2936
-{
2937
-    NS_ENSURE_ARG_POINTER(aPrefName);
2938
+    // We need to ignore pref changes due to our own calls here
2939
+    mIgnorePrefSetting = PR_TRUE;
2940
 
2941
-    nsresult rv;
2942
+    // Unlock it if it's locked, so we can set it
2943
+    if (isLocked) {
2944
+        rv = userBranch->UnlockPref(aPrefName);
2945
+        if (NS_FAILED(rv))
2946
+            return rv;
2947
+    }
2948
 
2949
-    nsCOMPtr<nsIPrefBranch> prefBranch =
2950
-        do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
2951
+    // Set the pref on the default branch if we're locking it, because
2952
+    // only the default branch gets used when the pref is locked.
2953
+    // Set the pref on the user branch if we're not locking it, because
2954
+    // that's where the user change will go.
2955
+    nsIPrefBranch* settingBranch =
2956
+        aLock ? defaultBranch.get() : NS_STATIC_CAST(nsIPrefBranch*, userBranch.get());
2957
+
2958
+    if (!aPresent) {
2959
+        rv = settingBranch->DeleteBranch(aPrefName);
2960
+    } else {
2961
+        switch (aType) {
2962
+        case nsIPrefBranch::PREF_STRING:
2963
+            rv = settingBranch->SetCharPref(aPrefName, (const char*)aValue);
2964
+            break;
2965
+        case nsIPrefBranch::PREF_INT:
2966
+            rv = settingBranch->SetIntPref(aPrefName, (PRInt32)(NS_PTR_TO_INT32(aValue)));
2967
+            break;
2968
+        case nsIPrefBranch::PREF_BOOL:
2969
+            rv = settingBranch->SetBoolPref(aPrefName, (PRBool)(NS_PTR_TO_INT32(aValue)));
2970
+            break;
2971
+        default:
2972
+            NS_ERROR("Unknown preference type");
2973
+            mIgnorePrefSetting = PR_FALSE;
2974
+            return NS_ERROR_FAILURE;
2975
+        }
2976
+    }
2977
     if (NS_FAILED(rv))
2978
         return rv;
2979
+    if (aLock) {
2980
+        rv = userBranch->LockPref(aPrefName);
2981
+    }
2982
 
2983
-    SYSPREF_LOG(("Restore Mozilla value for %s\n", aPrefName));
2984
+    mIgnorePrefSetting = PR_FALSE;
2985
+    return rv;
2986
+}
2987
 
2988
-    PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
2989
-    rv = prefBranch->GetPrefType(aPrefName, &prefType);
2990
+nsresult
2991
+nsSystemPref::FixupLockdownPrefs()
2992
+{
2993
+    nsCOMPtr<nsIPrefBranch2> userPrefs = GetPrefUserBranch();
2994
+    nsCOMPtr<nsIPrefBranch2> defaultPrefs = GetPrefUserBranch();
2995
+    PRUint32 childCount;
2996
+    char **childArray = nsnull;
2997
+    nsresult rv = userPrefs->GetChildList("config.lockdown.",
2998
+                                          &childCount, &childArray);
2999
     if (NS_FAILED(rv))
3000
         return rv;
3001
+    for (PRUint32 i = 0; i < childCount; ++i) {
3002
+        PRInt32 type;
3003
+        rv = defaultPrefs->GetPrefType(childArray[i], &type);
3004
+        if (NS_FAILED(rv))
3005
+            return rv;
3006
+        NS_ASSERTION(type == nsIPrefBranch2::PREF_BOOL,
3007
+                     "All config.lockdown.* prefs should be boolean");
3008
+        if (type == nsIPrefBranch2::PREF_BOOL) {
3009
+            rv = defaultPrefs->SetBoolPref(childArray[i], PR_FALSE);
3010
+            if (NS_FAILED(rv))
3011
+                return rv;
3012
+        }
3013
+    }
3014
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray);
3015
+    return NS_OK;
3016
+}
3017
 
3018
-    // unlock, if it is locked
3019
-    prefBranch->UnlockPref(aPrefName);
3020
+nsresult
3021
+nsSystemPref::LoadSystemPrefs()
3022
+{
3023
+    SYSPREF_LOG(("\n====Now Use system prefs==\n"));
3024
+    NS_ASSERTION(!mSysPrefService,
3025
+                 "Shouldn't have the pref service here");
3026
+    nsresult rv;
3027
+    mSysPrefService = do_GetService(NS_SYSTEMPREF_SERVICE_CONTRACTID, &rv);
3028
+    if (NS_FAILED(rv) || !mSysPrefService) {
3029
+        FixupLockdownPrefs();
3030
+        SYSPREF_LOG(("...No System Pref Service\n"));
3031
+        return NS_OK;
3032
+    }
3033
 
3034
-    switch (prefType) {
3035
-    case nsIPrefBranch::PREF_STRING:
3036
-        prefBranch->SetCharPref(aPrefName,
3037
-                                aPrefValue->stringVal);
3038
-        SYSPREF_LOG(("Mozilla value is %s\n", aPrefValue->stringVal));
3039
+    // Cache the pref-branch while we load up the system prefs.
3040
+    NS_ASSERTION(!mCachedUserPrefBranch,
3041
+                 "Shouldn't have a cache here");
3042
+    nsCOMPtr<nsIPrefBranch2> userBranch = GetPrefUserBranch();
3043
+    nsCOMPtr<nsIPrefBranch> defaultBranch = GetPrefDefaultBranch();
3044
+    mCachedDefaultPrefBranch = defaultBranch;
3045
+    mCachedUserPrefBranch = userBranch;
3046
+    rv = mSysPrefService->LoadSystemPreferences(this);
3047
+    mCachedDefaultPrefBranch = nsnull;
3048
+    mCachedUserPrefBranch = nsnull;
3049
+
3050
+    if (NS_FAILED(rv)) {
3051
+        // Restore all modified preferences to their original values
3052
+        mSavedPrefs.EnumerateRead(RestorePref, this);
3053
+        mSavedPrefs.Clear();
3054
+        mSysPrefService = nsnull;
3055
+    }
3056
+        
3057
+    return rv;
3058
+}
3059
 
3060
-        PL_strfree(aPrefValue->stringVal);
3061
-        aPrefValue->stringVal = nsnull;
3062
+nsresult
3063
+nsSystemPref::RestoreMozillaPrefs()
3064
+{
3065
+    SYSPREF_LOG(("\n====Now rollback to Mozilla prefs==\n"));
3066
 
3067
-        break;
3068
-    case nsIPrefBranch::PREF_INT:
3069
-        prefBranch->SetIntPref(aPrefName, aPrefValue->intVal);
3070
-        SYSPREF_LOG(("Mozilla value is %d\n", aPrefValue->intVal));
3071
+    NS_ASSERTION(mSysPrefService,
3072
+                 "Should have the pref service here");
3073
+    if (!mSysPrefService)
3074
+        return NS_ERROR_FAILURE;
3075
 
3076
-        break;
3077
-    case nsIPrefBranch::PREF_BOOL:
3078
-        prefBranch->SetBoolPref(aPrefName, aPrefValue->boolVal);
3079
-        SYSPREF_LOG(("Mozilla value is %s\n",
3080
-                     aPrefValue->boolVal ? "TRUE" : "FALSE"));
3081
+    nsCOMPtr<nsIPrefBranch2> userBranch = GetPrefUserBranch();
3082
+    nsCOMPtr<nsIPrefBranch> defaultBranch = GetPrefDefaultBranch();
3083
+    mCachedDefaultPrefBranch = defaultBranch;
3084
+    mCachedUserPrefBranch = userBranch;
3085
+
3086
+    mSysPrefService->NotifyUnloadSystemPreferences();
3087
+    // Restore all modified preferences to their original values
3088
+    mSavedPrefs.EnumerateRead(RestorePref, this);
3089
+    mSavedPrefs.Clear();
3090
+
3091
+    mCachedDefaultPrefBranch = nsnull;
3092
+    mCachedUserPrefBranch = nsnull;
3093
+    
3094
+    mSysPrefService = nsnull;
3095
 
3096
-        break;
3097
-    default:
3098
-        SYSPREF_LOG(("Fail to Restore Mozilla value for it\n"));
3099
-        return NS_ERROR_FAILURE;
3100
-    }
3101
+    FixupLockdownPrefs();
3102
 
3103
-    // restore its old lock status
3104
-    if (aLocked)
3105
-        prefBranch->LockPref(aPrefName);
3106
     return NS_OK;
3107
 }
3108
--- extensions/pref/system-pref/src/nsSystemPref.h
3109
+++ extensions/pref/system-pref/src/nsSystemPref.h
3110
@@ -23,7 +23,7 @@
3111
  *
3112
  * Original Author: Bolian Yin (bolian.yin@sun.com)
3113
  *
3114
- * Contributor(s):
3115
+ * Contributor(s): Robert O'Callahan/Novell (rocallahan@novell.com)
3116
  *
3117
  * Alternatively, the contents of this file may be used under the terms of
3118
  * either the GNU General Public License Version 2 or later (the "GPL"), or
3119
@@ -45,16 +45,14 @@
3120
 #include "nsCOMPtr.h"
3121
 #include "nsXPCOM.h"
3122
 #include "nsCRT.h"
3123
-#include "nsIAppStartupNotifier.h"
3124
-#include "nsICategoryManager.h"
3125
-#include "nsIServiceManager.h"
3126
 #include "nsWeakReference.h"
3127
-#include "nsIPrefService.h"
3128
-#include "nsIPrefBranch2.h"
3129
+#include "nsClassHashtable.h"
3130
+#include "nsHashKeys.h"
3131
+#include "nsMemory.h"
3132
 
3133
-#include <nsIObserver.h>
3134
+#include "nsISystemPrefService.h"
3135
+#include "nsIObserver.h"
3136
 
3137
-union MozPrefValue;
3138
 struct SysPrefItem;
3139
 
3140
 //////////////////////////////////////////////////////////////////////////
3141
@@ -62,18 +60,34 @@
3142
 // nsSystemPref, as an extension of mozilla pref service, reads some mozilla
3143
 // prefs from host system when the feature is enabled ("config.system-pref").
3144
 //
3145
-// nsSystemPref listens on NS_PREFSERVICE_READ_TOPIC_ID. When notified,
3146
-// nsSystemPref will start the nsSystemPrefService (platform specific) to
3147
-// read all the interested prefs (listed in sSysPrefList table) from system
3148
-// and lock these prefs from user's modification. 
3149
-//
3150
-// This feature will make mozilla integrated better into host platforms. If
3151
-// users want to change the prefs read from system, the system provided pref
3152
-// editor (i.e. gconf-editor in gnome) should be used.
3153
+// nsSystemPref listens on NS_PREFSERVICE_READ_TOPIC_ID. When
3154
+// notified, nsSystemPref will start the nsSystemPrefService (platform
3155
+// specific) and tell it to override Mozilla prefs with its own
3156
+// settings.
3157
+//
3158
+// When overriding a Mozilla preference the prefservice can request the
3159
+// pref be locked or unlocked. If the pref is locked then we set the default
3160
+// value and lock it in Mozilla so the user value is ignored and the user cannot
3161
+// change the value. If the pref is unlocked then we set the user value
3162
+// and unlock it in Mozilla so the user can change it. If the user changes it,
3163
+// then the prefservice is notified so it can copy the value back to its
3164
+// underlying store.
3165
+//
3166
+// We detect changes to Mozilla prefs by observing pref changes in the
3167
+// user branch.
3168
+//
3169
+// For testing purposes, if the user toggles on
3170
+// config.use_system_prefs then we save the current preferences before
3171
+// overriding them from gconf, and if the user toggles off
3172
+// config.use_system_prefs *in the same session* then we restore the
3173
+// preferences. If the user exits without turning off use_system_prefs
3174
+// then the saved values are lost and the new values are permanent.
3175
+//
3176
 //////////////////////////////////////////////////////////////////////////
3177
 
3178
 class nsSystemPref : public nsIObserver,
3179
-                     public nsSupportsWeakReference
3180
+                     public nsSupportsWeakReference,
3181
+                     public nsISystemPref
3182
 {
3183
 public:
3184
     NS_DECL_ISUPPORTS
3185
@@ -83,23 +97,39 @@
3186
     virtual ~nsSystemPref();
3187
     nsresult Init(void);
3188
 
3189
+    // nsISystemPref
3190
+    virtual nsresult SetOverridingMozillaBoolPref(const char* aPrefName,
3191
+                                                  PRBool aValue, PRBool aLocked,
3192
+                                                  PRBool aPresent = PR_TRUE);
3193
+    virtual nsresult SetOverridingMozillaIntPref(const char* aPrefName,
3194
+                                                 PRInt32 aValue, PRBool aLocked,
3195
+                                                 PRBool aPresent = PR_TRUE);
3196
+    virtual nsresult SetOverridingMozillaStringPref(const char* aPrefName,
3197
+                                                    const char* aValue, PRBool aLocked,
3198
+                                                    PRBool aPresent = PR_TRUE);
3199
+    virtual nsresult StopOverridingMozillaPref(const char* aPrefName);
3200
+    virtual already_AddRefed<nsIPrefBranch2> GetPrefUserBranch();
3201
+    virtual already_AddRefed<nsIPrefBranch> GetPrefDefaultBranch();
3202
+
3203
 private:
3204
-    // funcs used to load system prefs and save mozilla default prefs
3205
-    nsresult UseSystemPrefs();
3206
-    nsresult ReadSystemPref(const char *aPrefName);
3207
-    nsresult SaveMozDefaultPref(const char *aPrefName,
3208
-                                MozPrefValue *aPrefVal,
3209
-                                PRBool *aLocked);
3210
-
3211
-    // funcs used to load mozilla default prefs
3212
-    nsresult UseMozillaPrefs();
3213
-    nsresult RestoreMozDefaultPref(const char *aPrefName,
3214
-                                   MozPrefValue *aPrefVal,
3215
-                                   PRBool aLocked);
3216
-
3217
-    nsCOMPtr<nsIPrefBranch2>  mSysPrefService;
3218
-    PRBool mEnabled;  // system pref is enabled or not
3219
-    SysPrefItem *mSysPrefs;
3220
+    // If we don't load the system prefs for any reason, then
3221
+    // set all config.lockdown.* preferences to PR_FALSE so that
3222
+    // residual lockdown settings are removed.
3223
+    nsresult FixupLockdownPrefs();
3224
+
3225
+    nsresult LoadSystemPrefs();
3226
+
3227
+    nsresult RestoreMozillaPrefs();
3228
+
3229
+    nsresult OverridePref(const char* aPrefName, PRInt32 aType,
3230
+                          void* aValue, PRBool aLock, PRBool aPresent);
3231
+
3232
+    nsCOMPtr<nsISystemPrefService>  mSysPrefService;
3233
+    nsClassHashtable<nsCStringHashKey,SysPrefItem> mSavedPrefs;
3234
+    // weak pointers to cached prefbranches
3235
+    nsIPrefBranch2* mCachedUserPrefBranch;
3236
+    nsIPrefBranch* mCachedDefaultPrefBranch;
3237
+    PRPackedBool mIgnorePrefSetting;
3238
 };
3239
 
3240
 #define NS_SYSTEMPREF_CID                  \
3241
--- extensions/pref/system-pref/src/nsSystemPrefFactory.cpp
3242
+++ extensions/pref/system-pref/src/nsSystemPrefFactory.cpp
3243
@@ -42,10 +42,10 @@
3244
 #include "nsICategoryManager.h"
3245
 #include "nsIGenericFactory.h"
3246
 #include "nsSystemPref.h"
3247
-#include "nsSystemPrefService.h"
3248
+#include "nsIServiceManager.h"
3249
+#include "nsIAppStartupNotifier.h"
3250
 
3251
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPref, Init)
3252
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPrefService, Init)
3253
 
3254
 // Registering nsSystemPref module as part of the app-startup category to get 
3255
 // it instantiated.
3256
@@ -96,11 +96,6 @@
3257
       RegisterSystemPref,
3258
       UnRegisterSystemPref,
3259
     },
3260
-    { NS_SYSTEMPREF_SERVICE_CLASSNAME,
3261
-      NS_SYSTEMPREF_SERVICE_CID,
3262
-      NS_SYSTEMPREF_SERVICE_CONTRACTID,
3263
-      nsSystemPrefServiceConstructor,
3264
-    },
3265
 };
3266
 
3267
 NS_IMPL_NSGETMODULE(nsSystemPrefModule, components)
3268