mozilla-gconf-backend.patch
changeset 24 ca988be0905b
child 59 604517bb16d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mozilla-gconf-backend.patch	Sat Dec 19 21:51:16 2009 +0100
@@ -0,0 +1,3516 @@
+From: various contributors
+Subject: replace gconf backend with more complete mapping for lockdown feature
+
+diff --git a/extensions/pref/Makefile.in b/extensions/pref/Makefile.in
+--- a/extensions/pref/Makefile.in
++++ b/extensions/pref/Makefile.in
+@@ -40,13 +40,13 @@ DEPTH            = ../..
+ topsrcdir        = @top_srcdir@
+ srcdir           = @srcdir@
+ VPATH            = @srcdir@
+ 
+ include $(DEPTH)/config/autoconf.mk
+ 
+ DIRS             = autoconfig
+ 
+-ifdef MOZ_ENABLE_GTK2
++ifdef MOZ_ENABLE_GCONF
+ DIRS		+= system-pref
+ endif
+ 
+ include $(topsrcdir)/config/rules.mk
+diff --git a/extensions/pref/system-pref/src/Makefile.in b/extensions/pref/system-pref/src/Makefile.in
+--- a/extensions/pref/system-pref/src/Makefile.in
++++ b/extensions/pref/system-pref/src/Makefile.in
+@@ -38,47 +38,41 @@
+ DEPTH = ../../../..
+ topsrcdir = @top_srcdir@
+ srcdir = @srcdir@
+ VPATH = @srcdir@
+ 
+ include $(DEPTH)/config/autoconf.mk
+ 
+ MODULE = system-pref
+-LIBRARY_NAME = system-pref_s
++LIBRARY_NAME = system-pref
+ ifneq ($(OS_ARCH),WINNT)
+ SHORT_LIBNAME = syspref
+ endif
+ 
+ # We want to force the creation of a static lib.
+-FORCE_STATIC_LIB = 1
+-LIBXUL_LIBRARY = 1
++#FORCE_STATIC_LIB = 1
++LIBXUL_LIBRARY   = 1
++MODULE_NAME      = nsSystemPrefModule
++IS_COMPONENT     = 1
++EXPORT_LIBRARY   = 1
+ 
+ REQUIRES        = xpcom \
+ 		  string \
+ 		  embedcomponents \
+ 		  pref \
+ 		  $(NULL)
+ 
+-ifdef MOZ_ENABLE_GTK2
+-DIRS		= gconf
+-endif
++CPPSRCS =   \
++  nsSystemPref.cpp	   \
++  nsSystemPrefFactory.cpp  \
++  $(NULL)
+ 
+ EXTRA_DSO_LDOPTS = \
+-		-L$(DIST)/bin \
+ 		$(MOZ_COMPONENT_LIBS) \
+ 		$(NULL)
+ 
+-CPPSRCS =   \
+-  nsSystemPref.cpp	   \
+-  $(NULL)
+-
+ EXPORTS		= \
+-		nsSystemPrefLog.h \
++		nsISystemPrefService.h \
+ 		$(NULL)
+ 
+ include $(topsrcdir)/config/rules.mk
+ 
+-ifdef MOZ_ENABLE_GTK2
+-INCLUDES	+= \
+-		-I$(srcdir)/gconf \
+-		$(NULL)
+-endif
+diff --git a/extensions/pref/system-pref/src/gconf/Makefile.in b/extensions/pref/system-pref/src/gconf/Makefile.in
+--- a/extensions/pref/system-pref/src/gconf/Makefile.in
++++ b/extensions/pref/system-pref/src/gconf/Makefile.in
+@@ -37,50 +37,37 @@
+ 
+ DEPTH = ../../../../..
+ topsrcdir = @top_srcdir@
+ srcdir = @srcdir@
+ VPATH = @srcdir@
+ 
+ include $(DEPTH)/config/autoconf.mk
+ 
+-MODULE = system-pref
+-LIBRARY_NAME = system-pref
+-LIBXUL_LIBRARY = 1
++MODULE = system-pref-gconf
++LIBRARY_NAME = system-pref-gconf
++IS_COMPONENT = 1
++MODULE_NAME = nsSystemPrefServiceModule
++FORCE_SHARED_LIB = 1
+ 
+ REQUIRES        = pref \
+ 		  string \
+ 		  xpcom \
+-		  embedcomponents \
++		  necko \
+ 		  $(NULL)
+ 
+ CPPSRCS =   \
+ 	nsSystemPrefService.cpp       \
+-	nsSystemPrefFactory.cpp \
+ 	$(NULL)
+ 
+-SHARED_LIBRARY_LIBS = ../libsystem-pref_s.a
++OS_INCLUDES += $(MOZ_GCONF_CFLAGS)
++
+ 
+ EXTRA_DSO_LDOPTS = \
+-		-L$(DIST)/bin \
+-		$(MOZ_COMPONENT_LIBS) \
+-		$(MOZ_GTK2_LIBS) \
++		$(XPCOM_GLUE_LDOPTS) \
++		$(MOZ_GCONF_LIBS)    \
++		$(NSPR_LIBS) \
+ 		$(NULL)
+ 
+-EXPORT_LIBRARY = 1
+-IS_COMPONENT = 1
+-MODULE_NAME	= nsSystemPrefModule
+-
+-EXPORTS		= \
+-		nsSystemPrefService.h \
+-		$(NULL)
+ 
+ include $(topsrcdir)/config/rules.mk
+ 
+-CFLAGS		+= $(MOZ_GTK2_CFLAGS)
+-CXXFLAGS	+= $(MOZ_GTK2_CFLAGS)
+-
+-LOCAL_INCLUDES = -I$(srcdir)/..
+-
+-export::
+-	$(INSTALL) $(srcdir)/../nsSystemPrefFactory.cpp .
+-
+ GARBAGE += nsSystemPrefFactory.cpp
+diff --git a/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp b/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
+--- a/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
++++ b/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
+@@ -18,17 +18,19 @@
+  * The Original Code is mozilla.org code.
+  *
+  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+  * Portions created by Sun Microsystems are Copyright (C) 2003 Sun
+  * Microsystems, Inc. All Rights Reserved.
+  *
+  * Original Author: Bolian Yin (bolian.yin@sun.com)
+  *
+- * Contributor(s):
++ * Contributor(s): Robert O'Callahan/Novell (rocallahan@novell.com)
++ *                 Hubert Figuiere (hfiguiere@novell.com)
++ *                 Wolfgang Rosenauer (wr@rosenauer.org)
+  *
+  * Alternatively, the contents of this file may be used under the terms of
+  * either the GNU General Public License Version 2 or later (the "GPL"), or
+  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+  * in which case the provisions of the GPL or the LGPL are applicable instead
+  * of those above. If you wish to allow use of your version of this file only
+  * under the terms of either the GPL or the LGPL, and not to allow others to
+  * use your version of this file under the terms of the NPL, indicate your
+@@ -36,299 +38,1300 @@
+  * and other provisions required by the GPL or the LGPL. If you do not delete
+  * the provisions above, a recipient may use your version of this file under
+  * the terms of any one of the NPL, the GPL or the LGPL.
+  *
+  * ***** END LICENSE BLOCK ***** */
+ 
+ #include <glib.h>
+ #include <glib-object.h>
++#include <gconf/gconf-client.h>
+ 
+ #include "plstr.h"
+ #include "nsCOMPtr.h"
+-#include "nsIPrefBranch.h"
+-#include "nsIPrefService.h"
++#include "nsIPref.h"
+ #include "nsIServiceManager.h"
+ #include "nsIObserver.h"
+ #include "nsWeakReference.h"
++#include "nsIPrefBranch2.h"
++#include "nsDataHashtable.h"
++#include "nsHashKeys.h"
++#include "nsICategoryManager.h"
++#include "nsIGenericFactory.h"
++#include "nsStringAPI.h"
++#include "nsIPermissionManager.h"
++#include "../nsSystemPref.h"
+ 
+-#include "nsString.h"
+-#include "nsSystemPrefLog.h"
+-#include "nsSystemPrefService.h"
++#define NS_SYSTEMPREF_SERVICE_CID                  \
++  { /* {3724e748-b088-4bf8-9298-aad426b66293} */       \
++    0x3724e748,                                        \
++    0xb088,                                            \
++    0x4bf8,                                            \
++        { 0x92, 0x98, 0xaa, 0xd4, 0x26, 0xb6, 0x62, 0x93 } \
++  }
+ 
+-/*************************************************************************
+- * The strange thing here is that we load the gconf library manually and 
+- * search the function pointers we need. If that process fails, no gconf
+- * support is available in mozilla. The aim is to make mozilla independent
+- * on gconf, in both compile time and run time.
+- ************************************************************************/
++#define NS_SYSTEMPREF_SERVICE_CLASSNAME "System Preferences Platform Service"
+ 
+-//gconf types
+-extern "C" {
++NS_DEFINE_STATIC_IID_ACCESSOR(nsISystemPrefService, NS_ISYSTEMPREFSERVICE_IID)
+ 
+-    typedef enum {
+-        GCONF_VALUE_INVALID,
+-        GCONF_VALUE_STRING,
+-        GCONF_VALUE_INT,
+-        GCONF_VALUE_FLOAT,
+-        GCONF_VALUE_BOOL,
+-        GCONF_VALUE_SCHEMA,
++/**
++ * We can link directly to the gconf library. If it's not available,
++ * this component just won't load and no system prefs will be offered.
++ */
+ 
+-        GCONF_VALUE_LIST,
+-        GCONF_VALUE_PAIR
++#define NUM_ELEM(a) (sizeof(a)/sizeof(a[0]))
+ 
+-    }GConfValueType;
++class nsSystemPrefService;
+ 
+-    typedef struct {
+-        GConfValueType type;
+-    }GConfValue;
++/**
++ * List the preferences that have a simple mapping between Moz and gconf.
++ * These preferences have the same meaning and their values are
++ * automatically converted.
++ */
++struct SimplePrefMapping {
++    const char *mozPrefName;
++    const char *gconfPrefName;
++    /**
++     * If this is PR_FALSE, then we never allow Mozilla to change
++     * this setting. The Mozilla pref will always be locked.
++     * If this is PR_TRUE then Mozilla will be allowed to change
++     * the setting --- but only if it is writable in gconf.
++     */
++    PRBool allowWritesFromMozilla;
++};
++typedef nsresult (* ComplexGConfPrefChanged)(nsSystemPrefService* aPrefService,
++                                             GConfClient* aClient);
++typedef nsresult (* ComplexMozPrefChanged)(nsSystemPrefService* aPrefService,
++                                           GConfClient* aClient);
++struct ComplexGConfPrefMapping {
++    const char* gconfPrefName;
++    ComplexGConfPrefChanged callback;
++};
+ 
+-    typedef void * (*GConfClientGetDefaultType) (void);
+-    typedef PRBool (*GConfClientGetBoolType) (void *client, const gchar *key,
+-                                              GError **err);
+-    typedef gchar* (*GConfClientGetStringType) (void *client, const gchar *key,
+-                                                GError **err);
+-    typedef PRInt32 (*GConfClientGetIntType) (void *client, const gchar *key,
+-                                              GError **err);
+-    typedef GSList* (*GConfClientGetListType) (void *client, const gchar *key,
+-                                               GConfValueType list_type,
+-                                               GError **err);
+-    typedef  void (*GConfClientNotifyFuncType) (void* client, guint cnxn_id,
+-                                                void *entry, 
+-                                                gpointer user_data);
+-    typedef guint (*GConfClientNotifyAddType) (void* client,
+-                                               const gchar* namespace_section,
+-                                               GConfClientNotifyFuncType func,
+-                                               gpointer user_data,
+-                                               GFreeFunc destroy_notify,
+-                                               GError** err);
+-    typedef void (*GConfClientNotifyRemoveType) (void *client,
+-                                                 guint cnxn);
+-    typedef void (*GConfClientAddDirType) (void *client,
+-                                           const gchar *dir,
+-                                           guint8 preload,
+-                                           GError **err);
+-    typedef void (*GConfClientRemoveDirType) (void *client,
+-                                              const gchar *dir,
+-                                              GError **err);
++struct ComplexMozPrefMapping {
++    const char* mozPrefName;
++    ComplexMozPrefChanged callback;
++};
+ 
+-    typedef const char* (*GConfEntryGetKeyType) (const void *entry);
+-    typedef GConfValue* (*GConfEntryGetValueType) (const void *entry);
++class nsSystemPrefService : public nsISystemPrefService, nsIPrefBranch
++ {
++ public:
++    NS_DECL_ISUPPORTS
++    NS_DECL_NSIPREFBRANCH
+ 
+-    typedef const char* (*GConfValueGetStringType) (const GConfValue *value);
+-    typedef PRInt32 (*GConfValueGetIntType) (const GConfValue *value);
+-    typedef PRBool (*GConfValueGetBoolType) (const GConfValue *value);
++    nsresult Init();
+ 
+-    
+-    static void gconf_key_listener (void* client, guint cnxn_id,
+-                                    void *entry, gpointer user_data);
+-}
++    virtual nsresult LoadSystemPreferences(nsISystemPref* aPrefs);
++    virtual nsresult NotifyMozillaPrefChanged(const char* aPrefName);
++    virtual nsresult NotifyUnloadSystemPreferences();
+ 
+-struct GConfCallbackData
+-{
+-    GConfProxy *proxy;
+-    void * userData;
+-    PRUint32 atom;
+-    PRUint32 notifyId;
+-};
+-//////////////////////////////////////////////////////////////////////
+-// GConPrxoy is a thin wrapper for easy use of gconf funcs. It loads the
+-// gconf library and initializes the func pointers for later use.
+-//////////////////////////////////////////////////////////////////////
+-class GConfProxy
+-{
+-public:
+-    GConfProxy(nsSystemPrefService* aSysPrefService);
+-    ~GConfProxy();
+-    PRBool Init();
++    nsSystemPrefService();
++    virtual ~nsSystemPrefService();
+ 
+-    nsresult GetBoolPref(const char *aMozKey, PRBool *retval);
+-    nsresult GetCharPref(const char *aMozKey, char **retval);
+-    nsresult GetIntPref(const char *aMozKey, PRInt32 *retval);
+-
+-    nsresult NotifyAdd (PRUint32 aAtom, void *aUserData);
+-    nsresult NotifyRemove (PRUint32 aAtom, const void *aUserData);
+-
+-    nsresult GetAtomForMozKey(const char *aMozKey, PRUint32 *aAtom) {
+-        return GetAtom(aMozKey, 0, aAtom); 
++    nsISystemPref* GetPrefs() { return mPref; }
++    SimplePrefMapping* GetSimpleCallbackData(PRUint32 aKey) {
++      SimplePrefMapping* result = nsnull;
++      mGConfSimpleCallbacks.Get(aKey, &result);
++      return result;
+     }
+-    const char *GetMozKey(PRUint32 aAtom) {
+-        return GetKey(aAtom, 0); 
+-    }
+-
+-    void OnNotify(void *aClient, void * aEntry, PRUint32 aNotifyId,
+-                  GConfCallbackData *aData);
++    ComplexGConfPrefMapping* GetComplexCallbackData(PRUint32 aKey) {
++      ComplexGConfPrefMapping* result = nsnull;
++      mGConfComplexCallbacks.Get(aKey, &result);
++      return result;
++     }
+ 
+ private:
+-    void *mGConfClient;
+-    PRLibrary *mGConfLib;
+-    PRBool mInitialized;
+-    nsSystemPrefService *mSysPrefService;
++    nsISystemPref* mPref;
++    nsDataHashtable<nsUint32HashKey, SimplePrefMapping*> mGConfSimpleCallbacks;
++    nsDataHashtable<nsUint32HashKey, ComplexGConfPrefMapping*> mGConfComplexCallbacks;
++    // This is set to PR_FALSE temporarily to stop listening to gconf
++    // change notifications (while we change gconf values)
++    PRPackedBool mListenToGConf;
+ 
+-    //listeners
+-    nsAutoVoidArray *mObservers;
+-
+-    void InitFuncPtrs();
+-    //gconf public func ptrs
+-
+-    //gconf client funcs
+-    GConfClientGetDefaultType GConfClientGetDefault;
+-    GConfClientGetBoolType GConfClientGetBool;
+-    GConfClientGetStringType GConfClientGetString;
+-    GConfClientGetIntType GConfClientGetInt;
+-    GConfClientGetListType GConfClientGetList;
+-    GConfClientNotifyAddType GConfClientNotifyAdd;
+-    GConfClientNotifyRemoveType GConfClientNotifyRemove;
+-    GConfClientAddDirType GConfClientAddDir;
+-    GConfClientRemoveDirType GConfClientRemoveDir;
+-
+-    //gconf entry funcs
+-    GConfEntryGetValueType GConfEntryGetValue;
+-    GConfEntryGetKeyType GConfEntryGetKey;
+-
+-    //gconf value funcs
+-    GConfValueGetBoolType GConfValueGetBool;
+-    GConfValueGetStringType GConfValueGetString;
+-    GConfValueGetIntType GConfValueGetInt;
+-
+-    //pref name translating stuff
+-    nsresult GetAtom(const char *aKey, PRUint8 aNameType, PRUint32 *aAtom);
+-    nsresult GetAtomForGConfKey(const char *aGConfKey, PRUint32 *aAtom) \
+-    {return GetAtom(aGConfKey, 1, aAtom);}
+-    const char *GetKey(PRUint32 aAtom, PRUint8 aNameType);
+-    const char *GetGConfKey(PRUint32 aAtom) \
+-    {return GetKey(aAtom, 1); }
+-    inline const char *MozKey2GConfKey(const char *aMozKey);
+-
+-    //const strings
+-    static const char sPrefGConfKey[];
+-    static const char sDefaultLibName1[];
+-    static const char sDefaultLibName2[];
++    GConfValue* GConfGet(const char *aPrefName);
+ };
+ 
+-struct SysPrefCallbackData {
+-    nsISupports *observer;
+-    PRBool bIsWeakRef;
+-    PRUint32 prefAtom;
+-};
+-
+-PRBool
+-sysPrefDeleteObserver(void *aElement, void *aData) {
+-    SysPrefCallbackData *pElement =
+-        static_cast<SysPrefCallbackData *>(aElement);
+-    NS_RELEASE(pElement->observer);
+-    nsMemory::Free(pElement);
+-    return PR_TRUE;
+-}
+-
+-NS_IMPL_ISUPPORTS2(nsSystemPrefService, nsIPrefBranch, nsIPrefBranch2)
+-
+-/* public */
+ nsSystemPrefService::nsSystemPrefService()
+-    :mInitialized(PR_FALSE),
+-     mGConf(nsnull),
+-     mObservers(nsnull)
++   : mPref(nsnull), mListenToGConf(PR_TRUE)
+ {
++   mGConfSimpleCallbacks.Init();
++   mGConfComplexCallbacks.Init();
+ }
+ 
+ nsSystemPrefService::~nsSystemPrefService()
+ {
+-    mInitialized = PR_FALSE;
+-
+-    if (mGConf)
+-        delete mGConf;
+-    if (mObservers) {
+-        (void)mObservers->EnumerateForwards(sysPrefDeleteObserver, nsnull);
+-        delete mObservers;
+-    }
++   NotifyUnloadSystemPreferences();
+ }
+ 
+ nsresult
+ nsSystemPrefService::Init()
+ {
+-    if (!gSysPrefLog) {
+-        gSysPrefLog = PR_NewLogModule("Syspref");
+-        if (!gSysPrefLog) return NS_ERROR_OUT_OF_MEMORY;
++    return NS_OK;
++}
++
++NS_IMPL_ISUPPORTS2(nsSystemPrefService, 
++                   nsISystemPrefService, 
++                   nsIPrefBranch)
++
++static GConfClient* GetGConf() {
++    return gconf_client_get_default();
++}
++
++static PRBool VerifyMatchingTypes(nsISystemPref* aPrefs,
++                                  const char* aMozPref, GConfValue* aVal)
++{
++    nsCOMPtr<nsIPrefBranch2> prefBranch = aPrefs->GetPrefUserBranch();
++    PRInt32 type;
++    nsresult rv = prefBranch->GetPrefType(aMozPref, &type);
++    if (NS_FAILED(rv)) {
++        // pref probably doesn't exist. Let gconf set it.
++        return PR_TRUE;
+     }
+ 
+-    SYSPREF_LOG(("Init SystemPref Service\n"));
+-    if (mInitialized)
++    PRBool ok;
++    switch (aVal->type) {
++    case GCONF_VALUE_STRING:
++        ok = type == nsIPrefBranch2::PREF_STRING;
++        break;
++    case GCONF_VALUE_INT:
++        ok = type == nsIPrefBranch2::PREF_INT;
++        break;
++    case GCONF_VALUE_BOOL:
++        ok = type == nsIPrefBranch2::PREF_BOOL;
++        break;
++    default:
++        NS_ERROR("Unhandled gconf preference type");
++        return PR_FALSE;
++    }
++
++    NS_ASSERTION(ok, "Mismatched gconf/Mozilla pref types");
++    return ok;
++}
++
++/**
++ * Map a gconf pref value into the corresponding Mozilla pref.
++ */
++static nsresult ApplySimpleMapping(SimplePrefMapping* aMap,
++                                   nsISystemPref* aPrefs,
++                                   GConfClient* aClient)
++{
++    GConfValue* val = gconf_client_get(aClient, aMap->gconfPrefName, nsnull);
++    if (!val) {
++        // No gconf key, so there's really nothing to do
++        return NS_OK;
++    }
++
++    VerifyMatchingTypes(aPrefs, aMap->mozPrefName, val);
++
++    PRBool locked = !aMap->allowWritesFromMozilla ||
++        !gconf_client_key_is_writable(aClient, aMap->gconfPrefName, nsnull);
++    nsresult rv;
++    switch (val->type) {
++    case GCONF_VALUE_STRING: {
++        const char* str = gconf_value_get_string(val);
++        rv = aPrefs->SetOverridingMozillaStringPref(aMap->mozPrefName, str, locked);
++        // XXX do we need to free 'str' here?
++        break;
++    }
++    case GCONF_VALUE_INT:
++        rv = aPrefs->SetOverridingMozillaIntPref(aMap->mozPrefName,
++                                                 gconf_value_get_int(val), locked);
++        break;
++    case GCONF_VALUE_BOOL:
++        rv = aPrefs->SetOverridingMozillaBoolPref(aMap->mozPrefName,
++                                                  gconf_value_get_bool(val), locked);
++        break;
++    default:
++        NS_ERROR("Unusable gconf value type");
++        rv = NS_ERROR_FAILURE;
++        break;
++    }
++
++    gconf_value_free(val);
++    return rv;
++}
++
++/**
++ * Map a Mozilla pref into the corresponding gconf pref, if
++ * that's allowed.
++ */
++static nsresult ReverseApplySimpleMapping(SimplePrefMapping* aMap,
++                                          nsISystemPref* aPrefs,
++                                          GConfClient* aClient)
++{
++    // Verify that the gconf key has the right type, if it exists
++    GConfValue* val = gconf_client_get(aClient, aMap->gconfPrefName, nsnull);
++    if (val) {
++        VerifyMatchingTypes(aPrefs, aMap->mozPrefName, val);
++        gconf_value_free(val);
++    }
++
++    PRBool writable = aMap->allowWritesFromMozilla &&
++        gconf_client_key_is_writable(aClient, aMap->gconfPrefName, nsnull);
++    if (!writable) {
++        NS_ERROR("Gconf key is not writable");
+         return NS_ERROR_FAILURE;
++    }
+ 
+-    if (!mGConf) {
+-        mGConf = new GConfProxy(this);
+-        if (!mGConf->Init()) {
+-            delete mGConf;
+-            mGConf = nsnull;
++    nsCOMPtr<nsIPrefBranch2> prefBranch = aPrefs->GetPrefUserBranch();
++    PRInt32 type;
++    nsresult rv = prefBranch->GetPrefType(aMap->mozPrefName, &type);
++    if (NS_FAILED(rv)) {
++        NS_ERROR("Writing back a pref that doesn't exist?");
++        return rv;
++    }
++
++    switch (type) {
++    case nsIPrefBranch2::PREF_STRING:
++        {
++            char* result;
++            rv = prefBranch->GetCharPref(aMap->mozPrefName, &result);
++            if (NS_FAILED(rv))
++                return rv;
++
++            gconf_client_set_string(aClient, aMap->gconfPrefName, result, nsnull);
++            nsMemory::Free(result);
++        }
++        break;
++    case nsIPrefBranch2::PREF_INT:
++        {
++            PRInt32 result;
++            rv = prefBranch->GetIntPref(aMap->mozPrefName, &result);
++            if (NS_FAILED(rv))
++                return rv;
++
++            gconf_client_set_int(aClient, aMap->gconfPrefName, result, nsnull);
++        }
++        break;
++    case nsIPrefBranch2::PREF_BOOL:
++        {
++            PRBool result;
++            rv = prefBranch->GetBoolPref(aMap->mozPrefName, &result);
++            if (NS_FAILED(rv))
++                return rv;
++
++            gconf_client_set_bool(aClient, aMap->gconfPrefName, result, nsnull);
++        }
++        break;
++    default:
++        NS_ERROR("Unhandled gconf preference type");
++        return NS_ERROR_FAILURE;
++    }
++
++    return NS_OK;
++}
++
++/* BEGIN preference mapping definition area
++ *
++ * There are a few rules that our preference maps have to obey:
++ *
++ * 1) Each mapping defines a relationship R between a set of GConf preferences and
++ * a set of Mozilla preferences that must *always* be true. Thus, when a Mozilla
++ * pref changes or a gconf pref changes, we may need to change something on the
++ * other side to preserve R. If a GConf preference is read-only, then we may
++ * need to lock one or more Mozilla preferences to avoid a situation where the
++ * Mozilla preference changes and we can't update the GConf preference to
++ * ensure R continues to hold.
++ *
++ * 2) If an unlocked Mozilla preference is changed, then we can only
++ * preserve R by changing GConf preferences; we are not allowed to
++ * change Mozilla preferences.
++ *
++ * 3) If a GConf preference is changed, then we can only preserve R by
++ * changing Moozilla preferences; we are nt allowed to change GConf
++ * preferences.
++ *
++ * For "simple" mappings, the relationship R is just of the form
++ * "GConf preference 'A' is equal to Mozilla preference 'B'". R is
++ * preserved by setting A to B when B changes, and by setting B to A
++ * when A changes. If A is read-only then we lock B (or we may just
++ * decide to lock B for other reasons). Thus rules 1-3 are satisfied.
++ *
++ * For "complex" mappings we have more complicated
++ * relationships. These are documented below.
++ */
++
++static SimplePrefMapping sSimplePrefMappings[] = {
++    // GNOME accessibility setting; never allow this to be set by Firefox
++    {"config.use_system_prefs.accessibility",
++     "/desktop/gnome/interface/accessibility", PR_FALSE},
++
++    // GConf Firefox preferences; allow these to be set through the Firefox UI
++    {"security.enable_java", "/apps/firefox/web/java_enabled", PR_TRUE},
++    {"javascript.enabled", "/apps/firefox/web/javascript_enabled", PR_TRUE},
++    {"browser.startup.homepage", "/apps/firefox/general/homepage_url", PR_TRUE},
++    {"browser.cache.disk.capacity", "/apps/firefox/web/cache_size", PR_TRUE},
++    {"network.cookie.lifetimePolicy", "/apps/firefox/web/cookie_accept", PR_TRUE},
++
++    // UI lockdown settings; never allow these to be set by Firefox. There is no
++    // Firefox UI for these but they could otherwise be set via about:config.
++    {"config.lockdown.printing", "/desktop/gnome/lockdown/disable_printing", PR_FALSE},
++    {"config.lockdown.printsetup", "/desktop/gnome/lockdown/disable_print_setup", PR_FALSE},
++    {"config.lockdown.savepage", "/desktop/gnome/lockdown/disable_save_to_disk", PR_FALSE},
++    {"config.lockdown.history", "/apps/firefox/lockdown/disable_history", PR_FALSE},
++    {"config.lockdown.toolbarediting", "/apps/firefox/lockdown/disable_toolbar_editing", PR_FALSE},
++    {"config.lockdown.urlbar", "/apps/firefox/lockdown/disable_url_bar", PR_FALSE},
++    {"config.lockdown.bookmark", "/apps/firefox/lockdown/disable_bookmark_editing", PR_FALSE},
++    {"config.lockdown.disable_themes", "/apps/firefox/lockdown/disable_themes", PR_FALSE},
++    {"config.lockdown.disable_extensions", "/apps/firefox/lockdown/disable_extensions", PR_FALSE},
++    {"config.lockdown.searchbar", "/apps/firefox/lockdown/disable_searchbar", PR_FALSE},
++    {"config.lockdown.hidebookmark", "/apps/firefox/lockdown/hide_bookmark", PR_FALSE},
++    {"config.lockdown.showsavedpasswords", "/apps/firefox/lockdown/disable_show_passwords", PR_FALSE},
++};
++
++static nsresult ApplyListPref(nsSystemPrefService* aPrefService,
++                             GConfClient* aClient,
++                             const char* aGConfKey, const char* aMozKey,
++                             char aSeparator)
++{
++    GSList* list = gconf_client_get_list(aClient, aGConfKey,
++                                         GCONF_VALUE_STRING, nsnull);
++    nsCAutoString str;
++    for (GSList* l = list; l; l = l->next) {
++        str.Append((const char*)l->data);
++        if (l->next) {
++            str.Append(aSeparator);
++        }
++    }
++    PRBool lock = !gconf_client_key_is_writable(aClient, aGConfKey, nsnull);
++    nsresult rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaStringPref(aMozKey, str.get(), lock);
++    // XXX does this free the strings? Should it?
++    g_slist_free(list);
++    return rv;
++}
++static nsresult ReverseApplyListPref(nsSystemPrefService* aPrefService,
++                                    GConfClient* aClient,
++                                    const char* aGConfKey, const char* aMozKey,
++                                    char aSeparator)
++{
++    char* data = nsnull;
++    nsCOMPtr<nsIPrefBranch2> prefs =
++        aPrefService->GetPrefs()->GetPrefUserBranch();
++    prefs->GetCharPref(aMozKey, &data);
++    if (!data)
++        return NS_ERROR_FAILURE;
++    nsresult rv = NS_OK;
++    GSList* list = nsnull;
++    PRInt32 i = 0;
++    while (data[i]) {
++        const char* nextComma = strchr(data+i, ',');
++        PRInt32 tokLen = nextComma ? nextComma - (data+i) : strlen(data+i);
++        char* tok = strndup(data+i, tokLen);
++        if (!tok)
++            break;
++        GSList* newList = g_slist_append(list, tok);
++        if (!newList) {
++            rv = NS_ERROR_OUT_OF_MEMORY;
++            break;
++        }
++        list = newList;
++        if (!nextComma)
++            break;
++        i = nextComma + 1 - data;
++    }
++    nsMemory::Free(data);
++    if (NS_SUCCEEDED(rv)) {
++        if (gconf_client_key_is_writable(aClient, aGConfKey, nsnull))
++            gconf_client_set_list(aClient, aGConfKey, GCONF_VALUE_STRING, list, nsnull);
++        else
++            NS_ERROR("Gconf key is not writable");
++    }
++    for (GSList* l = list; l; l = l->next) {
++        free(l->data);
++    }
++    g_slist_free(list);
++    return rv;
++}
++
++/**
++ * The relationship R is
++ * "network.negotiate-auth.trusted-uris" is the comma-separated concatenation
++ * of the elements of the list "/apps/firefox/general/trusted_URIs"
++ */
++static const char GConfKey_TrustedURIs[] = "/apps/firefox/general/trusted_URIs";
++static const char MozKey_TrustedURIs[] = "network.negotiate-auth.trusted-uris";
++static nsresult ApplyTrustedURIs(nsSystemPrefService* aPrefService,
++                                GConfClient* aClient)
++{
++    return ApplyListPref(aPrefService, aClient,
++                        GConfKey_TrustedURIs, MozKey_TrustedURIs, ',');
++}
++static nsresult ReverseApplyTrustedURIs(nsSystemPrefService* aPrefService,
++                                       GConfClient* aClient)
++{
++    return ReverseApplyListPref(aPrefService, aClient,
++                               GConfKey_TrustedURIs, MozKey_TrustedURIs, ',');
++}
++
++/**
++ * The relationship R is
++ * "network.negotiate-auth.delegation-uris" is the comma-separated concatenation
++ * of the elements of the list "/apps/firefox/general/delegation_URIs"
++ */
++static const char GConfKey_DelegationURIs[] = "/apps/firefox/general/delegation_URIs";
++static const char MozKey_DelegationURIs[] = "network.negotiate-auth.delegation-uris";
++static nsresult ApplyDelegationURIs(nsSystemPrefService* aPrefService,
++                                   GConfClient* aClient)
++{
++    return ApplyListPref(aPrefService, aClient,
++                        GConfKey_DelegationURIs, MozKey_DelegationURIs, ',');
++}
++static nsresult ReverseApplyDelegationURIs(nsSystemPrefService* aPrefService,
++                                          GConfClient* aClient)
++{
++    return ReverseApplyListPref(aPrefService, aClient,
++                               GConfKey_DelegationURIs, MozKey_DelegationURIs, ',');
++}
++
++
++/**
++ * The relationship R is
++ * If "/apps/firefox/web/download_defaultfolder" is the empty string, then
++ * "browser.download.useDownloadDir" is false;
++ * otherwise "browser.download.useDownloadDir" is true and "browser.download.folderList"
++ * is (0 if "/apps/firefox/web/download_defaultfolder" is "Desktop";
++ *     1 if "/apps/firefox/web/download_defaultfolder" is "My Downloads";
++ *     3 if "/apps/firefox/web/download_defaultfolder" is "Home";
++ *     otherwise 2 and "browser.download.dir" = "/apps/firefox/web/download_defaultfolder")
++ */
++static const char GConfKey_DownloadFolder[] = "/apps/firefox/web/download_defaultfolder";
++static const char MozKey_UseDownloadDir[] = "browser.download.useDownloadDir";
++static const char MozKey_DownloadDirType[] = "browser.download.folderList";
++static const char MozKey_DownloadDirExplicit[] = "browser.download.dir";
++static nsresult ApplyDownloadFolder(nsSystemPrefService* aPrefService,
++                                    GConfClient* aClient)
++{
++    char* str = gconf_client_get_string(aClient, GConfKey_DownloadFolder, nsnull);
++    if (!str)
++        return NS_ERROR_FAILURE;
++    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DownloadFolder, nsnull);
++    nsresult rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_UseDownloadDir, *str != 0, lock);
++    if (NS_FAILED(rv)) {
++        g_free(str);
++        return rv;
++    }
++    PRInt32 dirType = 0;
++    if (!strcmp(str, "Desktop")) {
++        dirType = 0;
++    } else if (!strcmp(str, "My Downloads")) {
++        dirType = 1;
++    } else if (!strcmp(str, "Home")) {
++        dirType = 3;
++    } else {
++        dirType = 2;
++    }
++    // Always set all three Mozilla preferences. This is simpler and avoids
++    // problems; e.g., if the gconf value changes from "/home/rocallahan" to "Desktop"
++    // we might leave MozKey_DownloadDirType accidentally locked.
++    rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaIntPref(MozKey_DownloadDirType, dirType, lock);
++    if (NS_SUCCEEDED(rv)) {
++        rv = aPrefService->GetPrefs()->
++            SetOverridingMozillaStringPref(MozKey_DownloadDirExplicit, str, lock);
++    }
++    g_free(str);
++    return rv;
++}
++
++static nsresult ReverseApplyDownloadFolder(nsSystemPrefService* aPrefService,
++                                           GConfClient* aClient)
++{
++    PRBool useDownloadDir = PR_FALSE;
++    const char* result;
++    char* explicitStr = nsnull;
++    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++    prefs->GetBoolPref(MozKey_UseDownloadDir, &useDownloadDir);
++    if (!useDownloadDir) {
++        result = "";
++    } else {
++        PRInt32 type = -1;
++        prefs->GetIntPref(MozKey_DownloadDirType, &type);
++        if (type < 0)
++            return NS_ERROR_FAILURE;
++        switch (type) {
++        case 0: result = "Desktop"; break;
++        case 1: result = "Downloads"; break;
++        case 2:
++            prefs->GetCharPref(MozKey_DownloadDirExplicit, &explicitStr);
++            result = explicitStr;
++            break;
++        case 3: result = "Home"; break;
++        default:
++            NS_ERROR("Unknown download dir type");
+             return NS_ERROR_FAILURE;
+         }
+     }
++    if (!result)
++        return NS_ERROR_FAILURE;
++    if (gconf_client_key_is_writable(aClient, GConfKey_DownloadFolder, nsnull))
++        gconf_client_set_string(aClient, GConfKey_DownloadFolder,
++                                result, nsnull);
++    else
++        NS_ERROR("Gconf key is not writable");
++    nsMemory::Free(explicitStr);
++    return NS_OK;
++}
+ 
+-    mInitialized = PR_TRUE;
++/**
++ * The relationship R is
++ * "/apps/firefox/web/disable_cookies" is true if and only if
++ * "network.cookie.cookieBehavior" is 2 ('dontUse')
++ */
++static const char GConfKey_DisableCookies[] = "/apps/firefox/web/disable_cookies";
++static const char MozKey_CookieBehavior[] = "network.cookie.cookieBehavior";
++static const char MozKey_CookieExceptions[] = "network.cookie.honorExceptions";
++static const char MozKey_CookieViewExceptions[] = "pref.privacy.disable_button.cookie_exceptions";
++static nsresult ApplyDisableCookies(nsSystemPrefService* aPrefService,
++                                    GConfClient* aClient)
++{
++    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableCookies, nsnull);
++    PRInt32 behavior = -1;
++    nsCOMPtr<nsIPrefBranch2> prefs =
++        aPrefService->GetPrefs()->GetPrefUserBranch();
++    prefs->GetIntPref(MozKey_CookieBehavior, &behavior);
++    if (behavior < 0)
++        return NS_ERROR_FAILURE;
++    if (disable) {
++        behavior = 2;
++    } else {
++        if (behavior == 2) {
++            behavior = 0;
++        }
++    }
++    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableCookies, nsnull);
++    nsresult rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_CookieExceptions, !lock, lock);
++    if (NS_FAILED(rv))
++      return rv;
++    rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_CookieViewExceptions, lock, lock);
++    if (NS_FAILED(rv))
++      return rv;
++    return aPrefService->GetPrefs()->
++        SetOverridingMozillaIntPref(MozKey_CookieBehavior, behavior, lock);
++}
++static nsresult ReverseApplyDisableCookies(nsSystemPrefService* aPrefService,
++                                           GConfClient* aClient)
++{
++    PRInt32 behavior = -1;
++    nsCOMPtr<nsIPrefBranch2> prefs =
++        aPrefService->GetPrefs()->GetPrefUserBranch();
++    prefs->GetIntPref(MozKey_CookieBehavior, &behavior);
++    if (behavior < 0)
++        return NS_ERROR_FAILURE;
++    if (gconf_client_key_is_writable(aClient, GConfKey_DisableCookies, nsnull))
++        gconf_client_set_bool(aClient, GConfKey_DisableCookies, behavior == 2, nsnull);
++    else
++        NS_ERROR("Gconf key is not writable");
+     return NS_OK;
+ }
+ 
++static char const* windowOpenFeatures[] = {
++    "dom.disable_window_open_feature.close",
++    "dom.disable_window_open_feature.directories",
++    "dom.disable_window_open_feature.location",
++    "dom.disable_window_open_feature.menubar",
++    "dom.disable_window_open_feature.minimizable",
++    "dom.disable_window_open_feature.personalbar",
++    "dom.disable_window_open_feature.resizable",
++    "dom.disable_window_open_feature.scrollbars",
++    "dom.disable_window_open_feature.status",
++    "dom.disable_window_open_feature.titlebar",
++    "dom.disable_window_open_feature.toolbar"
++};
++/**
++ * The relationship R is
++ * "/apps/firefox/lockdown/disable_javascript_chrome" is true if and only if
++ * all of windowOpenFeatures are true
++ */
++static const char GConfKey_DisableJSChrome[] =
++    "/apps/firefox/lockdown/disable_javascript_chrome";
++static nsresult ApplyWindowOpen(nsSystemPrefService* aPrefService,
++                                GConfClient* aClient)
++{
++    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableJSChrome, nsnull);
++    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableJSChrome, nsnull);
++    PRBool curValues[NUM_ELEM(windowOpenFeatures)];
++    PRUint32 i;
++    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++    PRBool allDisabled = PR_TRUE;
++    for (i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) {
++        nsresult rv = prefs->GetBoolPref(windowOpenFeatures[i], &curValues[i]);
++        if (NS_FAILED(rv))
++            return rv;
++        if (!curValues[i]) {
++            allDisabled = PR_FALSE;
++        }
++    }
++    for (i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) {
++        PRBool newVal = curValues[i];
++        if (disable) {
++            newVal = PR_TRUE;
++        } else if (allDisabled) {
++            // If all disable-window-open-feature prefs are currently
++            // PR_TRUE, then we need to set at least one of them to
++            // PR_FALSE. Set all of them to PR_FALSE.
++            newVal = PR_FALSE;
++        } // If at least one disable-window-open-feature pref is
++          // currently PR_FALSE, then we don't need to change anything
++          // when the gconf pref says don't disable
++        nsresult rv = aPrefService->GetPrefs()->
++            SetOverridingMozillaBoolPref(windowOpenFeatures[i], newVal, lock);
++        if (NS_FAILED(rv))
++            return rv;
++    }
++    return NS_OK;
++}
++
++static nsresult ReverseApplyWindowOpen(nsSystemPrefService* aPrefService,
++                                       GConfClient* aClient)
++{
++    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++    PRBool allDisabled = PR_TRUE;
++    PRBool curValues[NUM_ELEM(windowOpenFeatures)];
++    for (PRUint32 i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) {
++        nsresult rv = prefs->GetBoolPref(windowOpenFeatures[i], &curValues[i]);
++        if (NS_FAILED(rv))
++            return rv;
++        if (!curValues[i]) {
++            allDisabled = PR_FALSE;
++        }
++    }
++    if (gconf_client_key_is_writable(aClient, GConfKey_DisableJSChrome, nsnull))
++        gconf_client_set_bool(aClient, GConfKey_DisableJSChrome, allDisabled, nsnull);
++    else
++        NS_ERROR("Gconf key is not writable");
++    return NS_OK;
++}
++
++/**
++ * The relationship R is
++ * If "/apps/firefox/lockdown/disable_unsafe_protocol" is true then
++ * -- "network.protocol-handler.blocked-default" is true
++ * -- "network.protocol-handler.blocked.XYZ" is false if and only if
++ * XYZ is a builtin non-disablable protocol or in
++ * "/apps/firefox/lockdown/additional_safe_protocols"
++ * AND if "/apps/firefox/lockdown/disable_unsafe_protocol" is false then
++ * -- "network.protocol-handler.blocked-default" is false
++ * -- if "network.protocol-handler.blocked.XYZ" exists then it is false
++ */
++static const char GConfKey_DisableUnsafeProtocols[] =
++    "/apps/firefox/lockdown/disable_unsafe_protocol";
++static const char GConfKey_AdditionalSafeProtocols[] =
++    "/apps/firefox/lockdown/additional_safe_protocols";
++static const char MozKey_BlockedDefault[] =
++    "network.protocol-handler.blocked-default";
++static const char MozKey_BlockedPrefix[] =
++    "network.protocol-handler.blocked.";
++static const char* nonDisablableBuiltinProtocols[] =
++    { "about", "data", "jar", "keyword", "resource", "viewsource",
++      "chrome", "moz-icon", "javascript", "file" };
++static PRBool FindString(const char** aList, PRInt32 aCount,
++                         const char* aStr)
++{
++    for (PRInt32 i = 0; i < aCount; ++i) {
++        if (!strcmp(aStr, aList[i]))
++            return PR_TRUE;
++    }
++    return PR_FALSE;
++}
++typedef nsDataHashtable<nsCStringHashKey,int> StringSet;
++/** Collect the set of protocol names that we want to set preferences for */
++static nsresult AddAllProtocols(nsSystemPrefService* aPrefService,
++                                const char* aSafeProtocols,
++                                StringSet* aProtocolSet,
++                                StringSet* aSafeSet)
++{
++    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++    PRUint32 childCount;
++    char **childArray = nsnull;
++    nsresult rv = prefs->GetChildList(MozKey_BlockedPrefix, &childCount, &childArray);
++    if (NS_FAILED(rv))
++        return rv;
++    PRUint32 i;
++    for (i = 0; i < childCount; ++i) {
++        nsDependentCString tmp(childArray[i] + NUM_ELEM(MozKey_BlockedPrefix)-1);
++        aProtocolSet->Put(tmp, 1); // copies
++    }
++    for (i = 0; i < NUM_ELEM(nonDisablableBuiltinProtocols); ++i) {
++        nsDependentCString tmp(nonDisablableBuiltinProtocols[i]);
++        aProtocolSet->Put(tmp, 1);
++    }
++    i = 0;
++    while (aSafeProtocols[i]) {
++        const char* nextComma = strchr(aSafeProtocols+i, ',');
++        PRUint32 tokLen = nextComma ? nextComma - (aSafeProtocols+i)
++            : strlen(aSafeProtocols+i);
++        nsCAutoString tok(aSafeProtocols+i, tokLen);
++        aProtocolSet->Put(tok, 1);
++        aSafeSet->Put(tok, 1);
++        if (nextComma) {
++            i = nextComma - aSafeProtocols + 1;
++        } else {
++            break;
++        }
++    }
++    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray);
++    return NS_OK;
++}
++
++struct ProtocolPrefClosure {
++    StringSet safeProtocolSet;
++    nsIPrefBranch2* prefs;
++    nsISystemPref* prefSetter;
++    PRPackedBool disableUnsafe;
++    PRPackedBool lock;
++};
++
++static PLDHashOperator PR_CALLBACK SetProtocolPref(const nsACString& aKey,
++                                                   int aItem,
++                                                   void* aClosure)
++{
++    ProtocolPrefClosure* closure = static_cast<ProtocolPrefClosure*>(aClosure);
++    const nsCString& protocol = PromiseFlatCString(aKey);
++    PRBool blockProtocol = PR_FALSE;
++    if (closure->disableUnsafe &&
++        !FindString(nonDisablableBuiltinProtocols,
++                    NUM_ELEM(nonDisablableBuiltinProtocols), protocol.get()) &&
++        !closure->safeProtocolSet.Get(aKey, nsnull)) {
++        blockProtocol = PR_TRUE;
++    }
++
++    nsCAutoString prefName;
++    prefName.Append(MozKey_BlockedPrefix);
++    prefName.Append(protocol);
++    closure->prefSetter->SetOverridingMozillaBoolPref(prefName.get(), blockProtocol,
++                                                      closure->lock);
++    return PL_DHASH_NEXT;
++}
++static nsresult ApplyUnsafeProtocols(nsSystemPrefService* aPrefService,
++                                     GConfClient* aClient)
++{
++    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableUnsafeProtocols, nsnull)
++        || !gconf_client_key_is_writable(aClient, GConfKey_AdditionalSafeProtocols, nsnull);
++    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableUnsafeProtocols, nsnull);
++    char* protocols = gconf_client_get_string(aClient, GConfKey_AdditionalSafeProtocols, nsnull);
++    if (!protocols)
++        return NS_ERROR_FAILURE;
++    nsresult rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_BlockedDefault, disable, lock);
++    StringSet protocolSet;
++    ProtocolPrefClosure closure;
++    protocolSet.Init();
++    closure.safeProtocolSet.Init();
++    if (NS_SUCCEEDED(rv)) {
++        rv = AddAllProtocols(aPrefService, protocols, &protocolSet,
++                             &closure.safeProtocolSet);
++    }
++    if (NS_SUCCEEDED(rv)) {
++        closure.disableUnsafe = disable;
++        closure.lock = lock;
++        closure.prefSetter = aPrefService->GetPrefs();
++        nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++        closure.prefs = prefs;
++        protocolSet.EnumerateRead(SetProtocolPref, &closure);
++    }
++    g_free(protocols);
++    return rv;
++}
++
++static nsresult ReverseApplyUnsafeProtocols(nsSystemPrefService* aPrefService,
++                                            GConfClient* aClient)
++{
++    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++    PRBool blockedDefault;
++    nsresult rv = prefs->GetBoolPref(MozKey_BlockedDefault, &blockedDefault);
++    if (NS_FAILED(rv))
++        return rv;
++    nsCAutoString enabledProtocols;
++    PRUint32 childCount;
++    char **childArray = nsnull;
++    rv = prefs->GetChildList(MozKey_BlockedPrefix, &childCount, &childArray);
++    if (NS_FAILED(rv))
++        return rv;
++    for (PRUint32 i = 0; i < childCount; ++i) {
++        PRBool val = PR_FALSE;
++        prefs->GetBoolPref(childArray[i], &val);
++        if (val) {
++            if (enabledProtocols.Length() > 0) {
++                enabledProtocols.Append(',');
++            }
++            enabledProtocols.Append(childArray[i] + NUM_ELEM(MozKey_BlockedPrefix)-1);
++        }
++    }
++    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray);
++    if (gconf_client_key_is_writable(aClient, GConfKey_DisableUnsafeProtocols, nsnull) &&
++            gconf_client_key_is_writable(aClient, GConfKey_AdditionalSafeProtocols, nsnull)) {
++        gconf_client_set_bool(aClient, GConfKey_DisableUnsafeProtocols, blockedDefault, nsnull);
++        gconf_client_set_string(aClient, GConfKey_AdditionalSafeProtocols,
++                                enabledProtocols.get(), nsnull);
++    } else {
++        NS_ERROR("Gconf key is not writable");
++    }
++    return NS_OK;
++}
++
++/**
++ * Set config.lockdown.setwallpaper if and only if
++ * /desktop/gnome/background/picture_filename is write-only. Always
++ * lock it.
++ */
++static const char MozKey_LockdownWallpaper[] = "config.lockdown.setwallpaper";
++static const char GConfKey_WallpaperSetting[] =
++    "/desktop/gnome/background/picture_filename";
++static nsresult ApplyWallpaper(nsSystemPrefService* aPrefService,
++                               GConfClient* aClient)
++{
++    PRBool canSetWallpaper =
++        gconf_client_key_is_writable(aClient, GConfKey_WallpaperSetting, nsnull);
++    return aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_LockdownWallpaper,
++                                     !canSetWallpaper, PR_TRUE);
++}
++// No ReverseApplyWallpaper because this Mozilla pref can never be
++// modified
++
++/**
++ * The relationship R is
++ * "signon.rememberSignons" is true if and only if "/apps/firefox/web/disable_save_password"
++ * is false.
++ */
++static const char MozKey_RememberSignons[] = "signon.rememberSignons";
++static const char GConfKey_DisableSavePassword[] = "/apps/firefox/web/disable_save_password";
++static nsresult ApplyDisableSavePassword(nsSystemPrefService* aPrefService,
++                                         GConfClient* aClient)
++{
++    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableSavePassword, nsnull);
++    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableSavePassword, nsnull);
++    return aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_RememberSignons, !disable, lock);
++}
++
++static nsresult ReverseApplyDisableSavePassword(nsSystemPrefService* aPrefService,
++                                                GConfClient* aClient)
++{
++    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++    PRBool remember;
++    nsresult rv = prefs->GetBoolPref(MozKey_RememberSignons, &remember);
++    if (NS_FAILED(rv))
++        return rv;
++    gconf_client_set_bool(aClient, GConfKey_DisableSavePassword, !remember, nsnull);
++    return NS_OK;
++}
++
++/**
++ * The relationship R is
++ * "permissions.default.image" is 1 (nsIPermissionManager::ALLOW_ACTION) if and only if
++ * "/apps/firefox/web/images_load" is 0, AND
++ * "permissions.default.image" is 2 (nsIPermissionManager::DENY_ACTION) if and only if
++ * "/apps/firefox/web/images_load" is 2, AND
++ * "permissions.default.image" is 3 if and only if "/apps/firefox/web/images_load" is 1
++ *
++ * Also, we set pref.advanced.images.disable_button.view_image iff
++ * /apps/firefox/web/images_load is read-only
++ * And we set permissions.default.honorExceptions iff
++ * /apps/firefox/web/images_load is not read-only
++ */
++static const char MozKey_ImagePermissions[] = "permissions.default.image";
++static const char MozKey_ImageExceptions[] = "permissions.honorExceptions.image";
++static const char MozKey_ImageViewExceptions[] = "pref.advanced.images.disable_button.view_image";
++static const char GConfKey_LoadImages[] = "/apps/firefox/web/images_load";
++static nsresult ApplyLoadImages(nsSystemPrefService* aPrefService,
++                                 GConfClient* aClient)
++{
++    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_LoadImages, nsnull);
++    // 0 == accept, 1 == no-foreign, 2 == reject
++    gint setting = gconf_client_get_int(aClient, GConfKey_LoadImages, nsnull);
++    PRInt32 pref;
++    switch (setting) {
++      case 0: pref = nsIPermissionManager::ALLOW_ACTION; break;
++      case 2: pref = nsIPermissionManager::DENY_ACTION; break;
++      case 1: pref = 3; break;
++      default: return NS_ERROR_FAILURE;
++    }
++    nsresult rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_ImageExceptions, !lock, lock);
++    if (NS_FAILED(rv))
++      return rv;
++    rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_ImageViewExceptions, lock, lock);
++    if (NS_FAILED(rv))
++      return rv;
++    return aPrefService->GetPrefs()->
++        SetOverridingMozillaIntPref(MozKey_ImagePermissions, pref, lock);
++}
++
++static nsresult ReverseApplyLoadImages(nsSystemPrefService* aPrefService,
++                                        GConfClient* aClient)
++{
++    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++    PRInt32 pref;
++    nsresult rv = prefs->GetIntPref(MozKey_ImagePermissions, &pref);
++    if (NS_FAILED(rv))
++        return rv;
++    gint setting;
++    switch (pref) {
++      case nsIPermissionManager::ALLOW_ACTION: setting = 0; break;
++      case nsIPermissionManager::DENY_ACTION: setting = 2; break;
++      case 3: setting = 1; break;
++      default: return NS_ERROR_FAILURE;
++    }
++    if (gconf_client_key_is_writable(aClient, GConfKey_LoadImages, nsnull))
++        gconf_client_set_int(aClient, GConfKey_LoadImages, setting, nsnull);
++    else
++        NS_ERROR("Gconf key is not writable");
++    return NS_OK;
++}
++
++/**
++ * The relationship R is
++ * "/apps/firefox/web/disable_popups" is true if and only if
++ * "dom.disable_open_during_load" is true
++ * AND if "/apps/firefox/web/disable_popups" is true then
++ * "privacy.popups.showBrowserMessage" is false.
++ */
++static const char MozKey_DisablePopups[] = "dom.disable_open_during_load";
++static const char MozKey_DisableBrowserPopupMessage[] = "privacy.popups.showBrowserMessage";
++static const char GConfKey_DisablePopups[] = "/apps/firefox/web/disable_popups";
++static nsresult ApplyDisablePopups(nsSystemPrefService* aPrefService,
++                                   GConfClient* aClient)
++{
++    PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisablePopups, nsnull);
++    gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisablePopups, nsnull);
++    nsresult rv = aPrefService->GetPrefs()->
++        SetOverridingMozillaBoolPref(MozKey_DisablePopups, disable, lock);
++    if (NS_SUCCEEDED(rv)) {
++        if (disable) {
++            rv = aPrefService->GetPrefs()->
++                SetOverridingMozillaBoolPref(MozKey_DisableBrowserPopupMessage, PR_TRUE, lock);
++        } else {
++            rv = aPrefService->GetPrefs()->
++                StopOverridingMozillaPref(MozKey_DisableBrowserPopupMessage);
++        }
++    }
++    return rv;
++}
++
++static nsresult ReverseApplyDisablePopups(nsSystemPrefService* aPrefService,
++                                          GConfClient* aClient)
++{
++    nsCOMPtr<nsIPrefBranch2> prefs = aPrefService->GetPrefs()->GetPrefUserBranch();
++    PRBool disabled;
++    nsresult rv = prefs->GetBoolPref(MozKey_DisablePopups, &disabled);
++    if (NS_FAILED(rv))
++        return rv;
++    if (gconf_client_key_is_writable(aClient, GConfKey_DisablePopups, nsnull))
++        gconf_client_set_bool(aClient, GConfKey_DisablePopups, disabled, nsnull);
++    else
++        NS_ERROR("Gconf key is not writable");
++    return NS_OK;
++}
++
++static ComplexGConfPrefMapping sComplexGConfPrefMappings[] = {
++    {GConfKey_TrustedURIs, ApplyTrustedURIs},
++    {GConfKey_DelegationURIs, ApplyDelegationURIs},
++    {GConfKey_DownloadFolder, ApplyDownloadFolder},
++    {GConfKey_DisableCookies, ApplyDisableCookies},
++    {GConfKey_DisableJSChrome, ApplyWindowOpen},
++    {GConfKey_DisableUnsafeProtocols, ApplyUnsafeProtocols},
++    {GConfKey_AdditionalSafeProtocols, ApplyUnsafeProtocols},
++    {GConfKey_WallpaperSetting, ApplyWallpaper},
++    {GConfKey_DisableSavePassword, ApplyDisableSavePassword},
++    {GConfKey_LoadImages, ApplyLoadImages},
++    {GConfKey_DisablePopups, ApplyDisablePopups}
++};
++static ComplexMozPrefMapping sComplexMozPrefMappings[] = {
++    {MozKey_TrustedURIs, ReverseApplyTrustedURIs},
++    {MozKey_DelegationURIs, ReverseApplyDelegationURIs},
++    {MozKey_UseDownloadDir, ReverseApplyDownloadFolder},
++    {MozKey_DownloadDirType, ReverseApplyDownloadFolder},
++    {MozKey_DownloadDirExplicit, ReverseApplyDownloadFolder},
++    {MozKey_CookieBehavior, ReverseApplyDisableCookies},
++    {MozKey_RememberSignons, ReverseApplyDisableSavePassword},
++    {MozKey_ImagePermissions, ReverseApplyLoadImages},
++    {MozKey_DisablePopups, ReverseApplyDisablePopups}
++};
++// The unsafe protocol preferences are handled specially because
++// they affect an unknown number of Mozilla preferences
++// Window opener permissions are also handled specially so we don't have to
++// repeat the windowOpenFeatures list.
++
++/* END preference mapping definition area */
++
++static PR_CALLBACK void GConfSimpleNotification(GConfClient* client,
++                                                guint cnxn_id,
++                                                GConfEntry *entry,
++                                                gpointer user_data)
++{
++    nsSystemPrefService* service = static_cast<nsSystemPrefService*>(user_data);
++    SimplePrefMapping* map = static_cast<SimplePrefMapping*>(
++                                            service->GetSimpleCallbackData(cnxn_id));
++    NS_ASSERTION(map, "Can't find mapping for callback");
++    if (!map)
++        return;
++
++    ApplySimpleMapping(map, service->GetPrefs(), client);
++}
++
++static PR_CALLBACK void GConfComplexNotification(GConfClient* client,
++                                                 guint cnxn_id,
++                                                 GConfEntry *entry,
++                                                 gpointer user_data)
++{
++    nsSystemPrefService* service = static_cast<nsSystemPrefService*>(user_data);
++    ComplexGConfPrefMapping* map = static_cast<ComplexGConfPrefMapping*>(
++                                                  service->GetComplexCallbackData(cnxn_id));
++    NS_ASSERTION(map, "Can't find mapping for callback");
++    if (!map)
++        return;
++
++    map->callback(service, GetGConf());
++}
++
++nsresult nsSystemPrefService::LoadSystemPreferences(nsISystemPref* aPrefs)
++{
++    mPref = aPrefs;
++
++    GConfClient* client = GetGConf();
++    PRUint32 i;
++    // Register simple mappings and callbacks
++    for (i = 0; i < NUM_ELEM(sSimplePrefMappings); ++i) {
++        guint cx = gconf_client_notify_add(client,
++                                           sSimplePrefMappings[i].gconfPrefName,
++                                           GConfSimpleNotification, this,
++                                           nsnull, nsnull);
++        mGConfSimpleCallbacks.Put(cx, &sSimplePrefMappings[i]);
++        nsresult rv = ApplySimpleMapping(&sSimplePrefMappings[i], aPrefs, client);
++        if (NS_FAILED(rv))
++            return rv;
++    }
++
++    // Update Mozilla settings with any gconf settings that have
++    // changed from the default. Do it before we register our
++    // Mozilla notifications.
++    ComplexGConfPrefChanged lastCallback = nsnull;
++    for (i = 0; i < NUM_ELEM(sComplexGConfPrefMappings); ++i) {
++        guint cx = gconf_client_notify_add(client,
++                                           sComplexGConfPrefMappings[i].gconfPrefName,
++                                           GConfComplexNotification, this,
++                                           nsnull, nsnull);
++        mGConfComplexCallbacks.Put(cx, &sComplexGConfPrefMappings[i]);
++        ComplexGConfPrefChanged cb = sComplexGConfPrefMappings[i].callback;
++        if (cb != lastCallback) {
++            cb(this, client);
++            lastCallback = cb;
++        }
++    }
++
++    nsCOMPtr<nsIPrefBranch2> userPrefs = aPrefs->GetPrefUserBranch();
++
++    // Update gconf settings with any Mozilla settings that have
++    // changed from the default.
++    for (i = 0; i < NUM_ELEM(sSimplePrefMappings); ++i) {
++        gconf_client_add_dir(client, sSimplePrefMappings[i].gconfPrefName,
++                             GCONF_CLIENT_PRELOAD_NONE, nsnull);
++
++        PRBool hasUserPref = PR_FALSE;
++        nsresult rv =
++            userPrefs->PrefHasUserValue(sSimplePrefMappings[i].mozPrefName,
++                                        &hasUserPref);
++        if (NS_FAILED(rv))
++            return rv;
++        if (hasUserPref && sSimplePrefMappings[i].allowWritesFromMozilla) {
++            rv = ReverseApplySimpleMapping(&sSimplePrefMappings[i],
++                                           aPrefs, client);
++            if (NS_FAILED(rv))
++                return rv;
++        }
++    }
++    for (i = 0; i < NUM_ELEM(sComplexGConfPrefMappings); ++i) {
++        gconf_client_add_dir(client, sComplexGConfPrefMappings[i].gconfPrefName,
++                             GCONF_CLIENT_PRELOAD_NONE, nsnull);
++    }
++    ComplexMozPrefChanged lastMozCallback = nsnull;
++    for (i = 0; i < NUM_ELEM(sComplexMozPrefMappings); ++i) {
++        PRBool hasUserPref = PR_FALSE;
++        nsresult rv =
++            userPrefs->PrefHasUserValue(sComplexMozPrefMappings[i].mozPrefName,
++                                        &hasUserPref);
++        if (NS_FAILED(rv))
++            return rv;
++        if (hasUserPref) {
++            ComplexMozPrefChanged cb = sComplexMozPrefMappings[i].callback;
++            if (cb != lastMozCallback) {
++                cb(this, client);
++                lastMozCallback = cb;
++            }
++        }
++    }
++
++    ApplyUnsafeProtocols(this, client);
++
++    return NS_OK;
++}
++
++nsresult nsSystemPrefService::NotifyMozillaPrefChanged(const char* aPrefName)
++{
++    PRUint32 i;
++    GConfClient* client = GetGConf();
++
++    for (i = 0; i < NUM_ELEM(sSimplePrefMappings); ++i) {
++        if (!strcmp(aPrefName, sSimplePrefMappings[i].mozPrefName)) {
++            ReverseApplySimpleMapping(&sSimplePrefMappings[i],
++                                      mPref, client);
++        }
++    }
++
++    for (i = 0; i < NUM_ELEM(sComplexMozPrefMappings); ++i) {
++        if (!strcmp(aPrefName, sComplexMozPrefMappings[i].mozPrefName)) {
++            sComplexMozPrefMappings[i].callback(this, client);
++        }
++    }
++
++    for (i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) {
++        if (!strcmp(aPrefName, windowOpenFeatures[i])) {
++            ReverseApplyWindowOpen(this, client);
++        }
++    }
++
++    ReverseApplyUnsafeProtocols(this, client);
++
++    return NS_OK;
++}
++
++static PLDHashOperator PR_CALLBACK UnregisterSimple(const PRUint32& aKey,
++                                                    SimplePrefMapping* aData,
++                                                    void* aClosure)
++{
++    GConfClient* client = GetGConf();
++    gconf_client_notify_remove(client, aKey);
++    gconf_client_remove_dir(client, aData->gconfPrefName, nsnull);
++    return PL_DHASH_NEXT;
++}
++
++static PLDHashOperator PR_CALLBACK UnregisterComplex(const PRUint32& aKey,
++                                                     ComplexGConfPrefMapping* aData,
++                                                     void* aClosure)
++{
++    GConfClient* client = GetGConf();
++    gconf_client_notify_remove(client, aKey);
++    gconf_client_remove_dir(client, aData->gconfPrefName, nsnull);
++    return PL_DHASH_NEXT;
++}
++
++nsresult nsSystemPrefService::NotifyUnloadSystemPreferences()
++{
++    // Unregister callbacks
++    mGConfSimpleCallbacks.EnumerateRead(UnregisterSimple, this);
++    mGConfSimpleCallbacks.Clear();
++    mGConfComplexCallbacks.EnumerateRead(UnregisterComplex, this);
++    mGConfComplexCallbacks.Clear();
++
++    return NS_OK;
++}
++
++// PrefBranch interfaces
++
++GConfValue* nsSystemPrefService::GConfGet(const char *aPrefName)
++{
++    PRUint32 i;
++    PRBool found = PR_FALSE;
++    GConfValue *val = NULL;
++    GConfClient* client = GetGConf();
++    NS_ASSERTION(client, "Could not get default GConf client");
++    if (!client) {
++        return NULL;
++    }
++    for (i = 0; i < NUM_ELEM(sSimplePrefMappings); ++i) {
++        if (!strcmp(aPrefName, sSimplePrefMappings[i].mozPrefName)) {
++            found = PR_TRUE;
++            break;
++        }
++    }
++    if (found) {
++        val = gconf_client_get(client, 
++                               sSimplePrefMappings[i].gconfPrefName, 
++                               NULL);
++    }
++    return val;
++}
++
+ /* readonly attribute string root; */
+ NS_IMETHODIMP nsSystemPrefService::GetRoot(char * *aRoot)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+ /* long getPrefType (in string aPrefName); */
+ NS_IMETHODIMP nsSystemPrefService::GetPrefType(const char *aPrefName, PRInt32 *_retval)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+ /* boolean getBoolPref (in string aPrefName); */
+ NS_IMETHODIMP nsSystemPrefService::GetBoolPref(const char *aPrefName, PRBool *_retval)
+ {
+-    return mInitialized ?
+-        mGConf->GetBoolPref(aPrefName, _retval) : NS_ERROR_FAILURE;
++    GConfValue *val = GConfGet(aPrefName);
++    if (val) {
++        *_retval = (PRBool)(gconf_value_get_bool(val));
++        return NS_OK;
++    }
++    return NS_ERROR_FAILURE;
+ }
+ 
+ /* void setBoolPref (in string aPrefName, in long aValue); */
+ NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRInt32 aValue)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+ /* string getCharPref (in string aPrefName); */
+ NS_IMETHODIMP nsSystemPrefService::GetCharPref(const char *aPrefName, char **_retval)
+ {
+-    return mInitialized ?
+-        mGConf->GetCharPref(aPrefName, _retval) : NS_ERROR_FAILURE;
++    GConfValue *val = GConfGet(aPrefName);
++    if (val) {
++        *_retval = (char*)(gconf_value_get_string(val));
++        return *_retval ? NS_OK : NS_ERROR_FAILURE;
++    }
++    return NS_ERROR_FAILURE;
+ }
+ 
+ /* void setCharPref (in string aPrefName, in string aValue); */
+ NS_IMETHODIMP nsSystemPrefService::SetCharPref(const char *aPrefName, const char *aValue)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+ /* long getIntPref (in string aPrefName); */
+ NS_IMETHODIMP nsSystemPrefService::GetIntPref(const char *aPrefName, PRInt32 *_retval)
+ {
+-    return mInitialized ?
+-        mGConf->GetIntPref(aPrefName, _retval) : NS_ERROR_FAILURE;
++    GConfValue *val = GConfGet(aPrefName);
++    if (val) {
++        *_retval = (PRInt32)(gconf_value_get_int(val));
++        return NS_OK;
++    }
++    return NS_ERROR_FAILURE;
+ }
+ 
+ /* void setIntPref (in string aPrefName, in long aValue); */
+ NS_IMETHODIMP nsSystemPrefService::SetIntPref(const char *aPrefName, PRInt32 aValue)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+-/* void getComplexValue (in string aPrefName, in nsIIDRef aType, [iid_is (aType), retval] out nsQIResult aValue); */
++/* void getComplexValue (in string aPrefName, in nsIIDRef aType, [iid_is
++ * (aType), retval] out nsQIResult aValue); */
+ NS_IMETHODIMP nsSystemPrefService::GetComplexValue(const char *aPrefName, const nsIID & aType, void * *aValue)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+-
+-/* void setComplexValue (in string aPrefName, in nsIIDRef aType, in nsISupports aValue); */
++/* void setComplexValue (in string aPrefName, in nsIIDRef aType, in
++ * nsISupports aValue); */
+ NS_IMETHODIMP nsSystemPrefService::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+ /* void clearUserPref (in string aPrefName); */
+ NS_IMETHODIMP nsSystemPrefService::ClearUserPref(const char *aPrefName)
+ {
+@@ -360,557 +1363,36 @@ NS_IMETHODIMP nsSystemPrefService::Unloc
+ }
+ 
+ /* void deleteBranch (in string aStartingAt); */
+ NS_IMETHODIMP nsSystemPrefService::DeleteBranch(const char *aStartingAt)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+-/* void getChildList (in string aStartingAt, out unsigned long aCount, [array, size_is (aCount), retval] out string aChildArray); */
++/* void getChildList (in string aStartingAt, out unsigned long aCount, [array,
++ * size_is (aCount), retval] out string aChildArray); */
+ NS_IMETHODIMP nsSystemPrefService::GetChildList(const char *aStartingAt, PRUint32 *aCount, char ***aChildArray)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+ /* void resetBranch (in string aStartingAt); */
+ NS_IMETHODIMP nsSystemPrefService::ResetBranch(const char *aStartingAt)
+ {
+     return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
+-/* void addObserver (in string aDomain, in nsIObserver aObserver, in boolean aHoldWeak); */
+-NS_IMETHODIMP nsSystemPrefService::AddObserver(const char *aDomain, nsIObserver *aObserver, PRBool aHoldWeak)
+-{
+-    nsresult rv;
+ 
+-    NS_ENSURE_ARG_POINTER(aDomain);
+-    NS_ENSURE_ARG_POINTER(aObserver);
++// Factory stuff
+ 
+-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
++NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPrefService, Init)
+ 
+-    PRUint32 prefAtom;
+-    // make sure the pref name is supported
+-    rv = mGConf->GetAtomForMozKey(aDomain, &prefAtom);
+-    NS_ENSURE_SUCCESS(rv, rv);
+-
+-    if (!mObservers) {
+-        mObservers = new nsAutoVoidArray();
+-        if (mObservers == nsnull)
+-            return NS_ERROR_OUT_OF_MEMORY;
+-    }
+-
+-    SysPrefCallbackData *pCallbackData = (SysPrefCallbackData *)
+-        nsMemory::Alloc(sizeof(SysPrefCallbackData));
+-    if (pCallbackData == nsnull)
+-        return NS_ERROR_OUT_OF_MEMORY;
+-
+-    pCallbackData->bIsWeakRef = aHoldWeak;
+-    pCallbackData->prefAtom = prefAtom;
+-    // hold a weak reference to the observer if so requested
+-    nsCOMPtr<nsISupports> observerRef;
+-    if (aHoldWeak) {
+-        nsCOMPtr<nsISupportsWeakReference> weakRefFactory = 
+-            do_QueryInterface(aObserver);
+-        if (!weakRefFactory) {
+-            // the caller didn't give us a object that supports weak reference.
+-            // ... tell them
+-            nsMemory::Free(pCallbackData);
+-            return NS_ERROR_INVALID_ARG;
+-        }
+-        nsCOMPtr<nsIWeakReference> tmp = do_GetWeakReference(weakRefFactory);
+-        observerRef = tmp;
+-    } else {
+-        observerRef = aObserver;
+-    }
+-
+-    rv = mGConf->NotifyAdd(prefAtom, pCallbackData);
+-    if (NS_FAILED(rv)) {
+-        nsMemory::Free(pCallbackData);
+-        return rv;
+-    }
+-
+-    pCallbackData->observer = observerRef;
+-    NS_ADDREF(pCallbackData->observer);
+-
+-    mObservers->AppendElement(pCallbackData);
+-    return NS_OK;
+-}
+-
+-/* void removeObserver (in string aDomain, in nsIObserver aObserver); */
+-NS_IMETHODIMP nsSystemPrefService::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
+-{
+-    nsresult rv;
+-
+-    NS_ENSURE_ARG_POINTER(aDomain);
+-    NS_ENSURE_ARG_POINTER(aObserver);
+-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
+-
+-    if (!mObservers)
+-        return NS_OK;
+-    
+-    PRUint32 prefAtom;
+-    // make sure the pref name is supported
+-    rv = mGConf->GetAtomForMozKey(aDomain, &prefAtom);
+-    NS_ENSURE_SUCCESS(rv, rv);
+-
+-    // need to find the index of observer, so we can remove it
+-    PRIntn count = mObservers->Count();
+-    if (count <= 0)
+-        return NS_OK;
+-
+-    PRIntn i;
+-    SysPrefCallbackData *pCallbackData;
+-    for (i = 0; i < count; ++i) {
+-        pCallbackData = (SysPrefCallbackData *)mObservers->ElementAt(i);
+-        if (pCallbackData) {
+-            nsCOMPtr<nsISupports> observerRef;
+-            if (pCallbackData->bIsWeakRef) {
+-                nsCOMPtr<nsISupportsWeakReference> weakRefFactory =
+-                    do_QueryInterface(aObserver);
+-                if (weakRefFactory) {
+-                    nsCOMPtr<nsIWeakReference> tmp =
+-                        do_GetWeakReference(aObserver);
+-                    observerRef = tmp;
+-                }
+-            }
+-            if (!observerRef)
+-                observerRef = aObserver;
+-
+-            if (pCallbackData->observer == observerRef &&
+-                pCallbackData->prefAtom == prefAtom) {
+-                rv = mGConf->NotifyRemove(prefAtom, pCallbackData);
+-                if (NS_SUCCEEDED(rv)) {
+-                    mObservers->RemoveElementAt(i);
+-                    NS_RELEASE(pCallbackData->observer);
+-                    nsMemory::Free(pCallbackData);
+-                }
+-                return rv;
+-            }
+-        }
+-    }
+-    return NS_OK;
+-}
+-
+-void
+-nsSystemPrefService::OnPrefChange(PRUint32 aPrefAtom, void *aData)
+-{
+-    if (!mInitialized)
+-        return;
+-
+-    SysPrefCallbackData *pData = (SysPrefCallbackData *)aData;
+-    if (pData->prefAtom != aPrefAtom)
+-        return;
+-
+-    nsCOMPtr<nsIObserver> observer;
+-    if (pData->bIsWeakRef) {
+-        nsCOMPtr<nsIWeakReference> weakRef =
+-            do_QueryInterface(pData->observer);
+-        if(weakRef)
+-            observer = do_QueryReferent(weakRef);
+-        if (!observer) {
+-            // this weak referenced observer went away, remove it from the list
+-            nsresult rv = mGConf->NotifyRemove(aPrefAtom, pData);
+-            if (NS_SUCCEEDED(rv)) {
+-                mObservers->RemoveElement(pData);
+-                NS_RELEASE(pData->observer);
+-                nsMemory::Free(pData);
+-            }
+-            return;
+-        }
+-    }
+-    else
+-        observer = do_QueryInterface(pData->observer);
+-
+-    if (observer)
+-        observer->Observe(static_cast<nsIPrefBranch *>(this),
+-                          NS_SYSTEMPREF_PREFCHANGE_TOPIC_ID,
+-                          NS_ConvertUTF8toUTF16(mGConf->GetMozKey(aPrefAtom)).
+-                          get());
+-}
+-
+-/*************************************************************
+- *  GConfProxy
+- *
+- ************************************************************/
+-
+-struct GConfFuncListType {
+-    const char *FuncName;
+-    PRFuncPtr  FuncPtr;
++static const nsModuleComponentInfo components[] = {
++    { NS_SYSTEMPREF_SERVICE_CLASSNAME,
++      NS_SYSTEMPREF_SERVICE_CID,
++      NS_SYSTEMPREF_SERVICE_CONTRACTID,
++      nsSystemPrefServiceConstructor,
++    },
+ };
+ 
+-struct PrefNamePair {
+-    const char *mozPrefName;
+-    const char *gconfPrefName;
+-};
++NS_IMPL_NSGETMODULE(nsSystemPrefServiceModule, components)
+ 
+-const char
+-GConfProxy::sPrefGConfKey[] = "accessibility.unix.gconf2.shared-library";
+-const char GConfProxy::sDefaultLibName1[] = "libgconf-2.so.4";
+-const char GConfProxy::sDefaultLibName2[] = "libgconf-2.so";
+-
+-#define GCONF_FUNCS_POINTER_BEGIN \
+-    static GConfFuncListType sGConfFuncList[] = {
+-#define GCONF_FUNCS_POINTER_ADD(func_name) \
+-    {func_name, nsnull},
+-#define GCONF_FUNCS_POINTER_END \
+-    {nsnull, nsnull}, };
+-
+-GCONF_FUNCS_POINTER_BEGIN
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_default")        // 0
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_bool")       // 1
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_string")     //2
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_int")       //3
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_notify_add")   //4
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_notify_remove")   //5
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_add_dir")   //6
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_remove_dir")   //7
+-    GCONF_FUNCS_POINTER_ADD("gconf_entry_get_value")       //8
+-    GCONF_FUNCS_POINTER_ADD("gconf_entry_get_key")       //9
+-    GCONF_FUNCS_POINTER_ADD("gconf_value_get_bool")      //10
+-    GCONF_FUNCS_POINTER_ADD("gconf_value_get_string")     //11
+-    GCONF_FUNCS_POINTER_ADD("gconf_value_get_int")       //12
+-    GCONF_FUNCS_POINTER_ADD("gconf_client_get_list")       //13
+-GCONF_FUNCS_POINTER_END
+-
+-/////////////////////////////////////////////////////////////////////////////
+-// the list is the mapping table, between mozilla prefs and gconf prefs
+-// It is expected to include all the pref pairs that are related in mozilla
+-// and gconf. 
+-//
+-// Note: the prefs listed here are not neccessarily be read from gconf, they
+-//       are the prefs that could be read from gconf. Mozilla has another
+-//       list (see sSysPrefList in nsSystemPref.cpp) that decide which prefs
+-//       are really read.
+-//////////////////////////////////////////////////////////////////////////////
+-
+-static const PrefNamePair sPrefNameMapping[] = {
+-#include "gconf_pref_list.inc"
+-    {nsnull, nsnull},
+-};
+-
+-PRBool
+-gconfDeleteObserver(void *aElement, void *aData) {
+-    nsMemory::Free(aElement);
+-    return PR_TRUE;
+-}
+-
+-GConfProxy::GConfProxy(nsSystemPrefService *aSysPrefService):
+-    mGConfClient(nsnull),
+-    mGConfLib(nsnull),
+-    mInitialized(PR_FALSE),
+-    mSysPrefService(aSysPrefService),
+-    mObservers(nsnull)
+-{
+-}
+-
+-GConfProxy::~GConfProxy()
+-{
+-    if (mGConfClient)
+-        g_object_unref(G_OBJECT(mGConfClient));
+-
+-    if (mObservers) {
+-        (void)mObservers->EnumerateForwards(gconfDeleteObserver, nsnull);
+-        delete mObservers;
+-    }
+-
+-    // bug 379666: can't unload GConf-2 since it registers atexit handlers
+-    //PR_UnloadLibrary(mGConfLib);
+-}
+-
+-PRBool
+-GConfProxy::Init()
+-{
+-    SYSPREF_LOG(("GConfProxy:: Init GConfProxy\n"));
+-    if (!mSysPrefService)
+-        return PR_FALSE;
+-    if (mInitialized)
+-        return PR_TRUE;
+-
+-    nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID); 
+-
+-    if (!pref)
+-        return PR_FALSE;
+-
+-    nsXPIDLCString gconfLibName;
+-    nsresult rv;
+-
+-    //check if gconf-2 library is given in prefs
+-    rv = pref->GetCharPref(sPrefGConfKey, getter_Copies(gconfLibName));
+-    if (NS_SUCCEEDED(rv)) {
+-        //use the library name in the preference
+-        SYSPREF_LOG(("GConf library in prefs is %s\n", gconfLibName.get()));
+-        mGConfLib = PR_LoadLibrary(gconfLibName.get());
+-    }
+-    else {
+-        SYSPREF_LOG(("GConf library not specified in prefs, try the default: "
+-                     "%s and %s\n", sDefaultLibName1, sDefaultLibName2));
+-        mGConfLib = PR_LoadLibrary(sDefaultLibName1);
+-        if (!mGConfLib)
+-            mGConfLib = PR_LoadLibrary(sDefaultLibName2);
+-    }
+-
+-    if (!mGConfLib) {
+-        SYSPREF_LOG(("Fail to load GConf library\n"));
+-        return PR_FALSE;
+-    }
+-
+-    //check every func we need in the gconf library
+-    GConfFuncListType *funcList;
+-    PRFuncPtr func;
+-    for (funcList = sGConfFuncList; funcList->FuncName; ++funcList) {
+-        func = PR_FindFunctionSymbol(mGConfLib, funcList->FuncName);
+-        if (!func) {
+-            SYSPREF_LOG(("Check GConf Func Error: %s", funcList->FuncName));
+-            goto init_failed_unload;
+-        }
+-        funcList->FuncPtr = func;
+-    }
+-
+-    InitFuncPtrs();
+-
+-    mGConfClient = GConfClientGetDefault();
+-
+-    // Don't unload past this point, since GConf's initialization of ORBit
+-    // causes atexit handlers to be registered.
+-
+-    if (!mGConfClient) {
+-        SYSPREF_LOG(("Fail to Get default gconf client\n"));
+-        goto init_failed;
+-    }
+-    mInitialized = PR_TRUE;
+-    return PR_TRUE;
+-
+- init_failed_unload:
+-    PR_UnloadLibrary(mGConfLib);
+- init_failed:
+-    mGConfLib = nsnull;
+-    return PR_FALSE;
+-}
+-
+-nsresult
+-GConfProxy::GetBoolPref(const char *aMozKey, PRBool *retval)
+-{
+-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
+-    *retval = GConfClientGetBool(mGConfClient, MozKey2GConfKey(aMozKey), NULL);
+-    return NS_OK;
+-}
+-
+-nsresult
+-GConfProxy::GetCharPref(const char *aMozKey, char **retval)
+-{
+-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
+-
+-    const gchar *gconfkey = MozKey2GConfKey(aMozKey);
+-
+-    if (!strcmp (aMozKey, "network.proxy.no_proxies_on")) {
+-        GSList *s;
+-        nsCString noproxy;
+-        GSList *gslist = GConfClientGetList(mGConfClient, gconfkey,
+-                                            GCONF_VALUE_STRING, NULL);
+-
+-        for (s = gslist; s; s = g_slist_next(s)) {
+-            noproxy += (char *)s->data;
+-            noproxy += ", ";
+-            g_free ((char *)s->data);
+-        }
+-        g_slist_free (gslist);
+-
+-        *retval = PL_strdup(noproxy.get());
+-    } else {
+-        gchar *str = GConfClientGetString(mGConfClient, gconfkey, NULL);
+-        if (str) {
+-            *retval = PL_strdup(str);
+-            g_free (str);
+-        }
+-    }
+-
+-    return NS_OK;
+-}
+-
+-nsresult
+-GConfProxy::GetIntPref(const char *aMozKey, PRInt32 *retval)
+-{
+-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
+-    if (strcmp (aMozKey, "network.proxy.type") == 0) {
+-	gchar *str;
+-
+-	str = GConfClientGetString(mGConfClient,
+-	                           MozKey2GConfKey (aMozKey), NULL);
+-
+-	if (str) {
+-		if (strcmp (str, "manual") == 0)
+-			*retval = 1;
+-		else if (strcmp (str, "auto") == 0)
+-			*retval = 2;
+-		else
+-			*retval = 0;
+-
+-		g_free (str);
+-	} else
+-		*retval = 0;
+-    } else {
+-    	*retval = GConfClientGetInt(mGConfClient, 
+-	                            MozKey2GConfKey(aMozKey), NULL);
+-    }
+-
+-    return NS_OK;
+-}
+-
+-nsresult
+-GConfProxy::NotifyAdd (PRUint32 aAtom, void *aUserData)
+-{
+-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
+-
+-    const char *gconfKey = GetGConfKey(aAtom);
+-    if (!gconfKey)
+-        return NS_ERROR_FAILURE;
+-
+-    if (!mObservers) {
+-        mObservers = new nsAutoVoidArray();
+-        if (mObservers == nsnull)
+-            return NS_ERROR_OUT_OF_MEMORY;
+-    }
+- 
+-    GConfCallbackData *pData = (GConfCallbackData *)
+-        nsMemory::Alloc(sizeof(GConfCallbackData));
+-    NS_ENSURE_TRUE(pData, NS_ERROR_OUT_OF_MEMORY);
+-
+-    pData->proxy = this;
+-    pData->userData = aUserData;
+-    pData->atom = aAtom;
+-    mObservers->AppendElement(pData);
+-
+-    GConfClientAddDir(mGConfClient, gconfKey,
+-                      0, // GCONF_CLIENT_PRELOAD_NONE,  don't preload anything 
+-                      NULL);
+-
+-    pData->notifyId = GConfClientNotifyAdd(mGConfClient, gconfKey,
+-                                           gconf_key_listener, pData,
+-                                           NULL, NULL);
+-    return NS_OK;
+-}
+-
+-nsresult
+-GConfProxy::NotifyRemove (PRUint32 aAtom, const void *aUserData)
+-{
+-    NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
+-
+-    PRIntn count = mObservers->Count();
+-    if (count <= 0)
+-        return NS_OK;
+-
+-    PRIntn i;
+-    GConfCallbackData *pData;
+-    for (i = 0; i < count; ++i) {
+-        pData = (GConfCallbackData *)mObservers->ElementAt(i);
+-        if (pData && pData->atom == aAtom && pData->userData == aUserData) {
+-            GConfClientNotifyRemove(mGConfClient, pData->notifyId);
+-            GConfClientRemoveDir(mGConfClient,
+-                                 GetGConfKey(pData->atom), NULL);
+-            mObservers->RemoveElementAt(i);
+-            nsMemory::Free(pData);
+-            break;
+-        }
+-    }
+-    return NS_OK;
+-}
+-
+-void
+-GConfProxy::InitFuncPtrs()
+-{
+-    //gconf client funcs
+-    GConfClientGetDefault =
+-        (GConfClientGetDefaultType) sGConfFuncList[0].FuncPtr;
+-    GConfClientGetBool =
+-        (GConfClientGetBoolType) sGConfFuncList[1].FuncPtr;
+-    GConfClientGetString =
+-        (GConfClientGetStringType) sGConfFuncList[2].FuncPtr;
+-    GConfClientGetInt =
+-        (GConfClientGetIntType) sGConfFuncList[3].FuncPtr;
+-    GConfClientNotifyAdd =
+-        (GConfClientNotifyAddType) sGConfFuncList[4].FuncPtr;
+-    GConfClientNotifyRemove =
+-        (GConfClientNotifyRemoveType) sGConfFuncList[5].FuncPtr;
+-    GConfClientAddDir =
+-        (GConfClientAddDirType) sGConfFuncList[6].FuncPtr;
+-    GConfClientRemoveDir =
+-        (GConfClientRemoveDirType) sGConfFuncList[7].FuncPtr;
+-
+-    //gconf entry funcs
+-    GConfEntryGetValue = (GConfEntryGetValueType) sGConfFuncList[8].FuncPtr;
+-    GConfEntryGetKey = (GConfEntryGetKeyType) sGConfFuncList[9].FuncPtr;
+-
+-    //gconf value funcs
+-    GConfValueGetBool = (GConfValueGetBoolType) sGConfFuncList[10].FuncPtr;
+-    GConfValueGetString = (GConfValueGetStringType) sGConfFuncList[11].FuncPtr;
+-    GConfValueGetInt = (GConfValueGetIntType) sGConfFuncList[12].FuncPtr;
+-
+-    //gconf client list func
+-    GConfClientGetList =
+-        (GConfClientGetListType) sGConfFuncList[13].FuncPtr;
+-}
+-
+-void
+-GConfProxy::OnNotify(void *aClient, void * aEntry, PRUint32 aNotifyId,
+-                     GConfCallbackData *aData)
+-{
+-    if (!mInitialized || !aEntry || (mGConfClient != aClient) || !aData)
+-        return;
+-
+-    if (GConfEntryGetValue(aEntry) == NULL)
+-        return;
+-
+-    PRUint32 prefAtom;
+-    nsresult rv = GetAtomForGConfKey(GConfEntryGetKey(aEntry), &prefAtom);
+-    if (NS_FAILED(rv))
+-        return;
+-
+-    mSysPrefService->OnPrefChange(prefAtom, aData->userData);
+-}
+-
+-nsresult
+-GConfProxy::GetAtom(const char *aKey, PRUint8 aNameType, PRUint32 *aAtom)
+-{
+-    if (!aKey)
+-        return NS_ERROR_FAILURE;
+-    PRUint32 prefSize = sizeof(sPrefNameMapping) / sizeof(sPrefNameMapping[0]);
+-    for (PRUint32 index = 0; index < prefSize; ++index) {
+-        if (!strcmp((aNameType == 0) ? sPrefNameMapping[index].mozPrefName :
+-                    sPrefNameMapping[index].gconfPrefName, aKey)) {
+-            *aAtom = index;
+-            return NS_OK;
+-        }
+-    }
+-    return NS_ERROR_FAILURE;
+-}
+-
+-const char *
+-GConfProxy::GetKey(PRUint32 aAtom, PRUint8 aNameType)
+-{
+-    PRUint32 mapSize = sizeof(sPrefNameMapping) / sizeof(sPrefNameMapping[0]);
+-    if (aAtom >= 0 && aAtom < mapSize)
+-        return (aNameType == 0) ? sPrefNameMapping[aAtom].mozPrefName :
+-            sPrefNameMapping[aAtom].gconfPrefName;
+-    return NULL;
+-}
+-
+-inline const char *
+-GConfProxy::MozKey2GConfKey(const char *aMozKey)
+-{
+-    PRUint32 atom;
+-    nsresult rv = GetAtomForMozKey(aMozKey, &atom);
+-    if (NS_SUCCEEDED(rv))
+-        return GetGConfKey(atom);
+-    return NULL;
+-}
+-
+-/* static */
+-void gconf_key_listener (void* client, guint cnxn_id,
+-                         void *entry, gpointer user_data)
+-{
+-    SYSPREF_LOG(("...SYSPREF_LOG...key listener get called \n"));
+-    if (!user_data)
+-        return;
+-    GConfCallbackData *pData = reinterpret_cast<GConfCallbackData *>
+-                                               (user_data);
+-    pData->proxy->OnNotify(client, entry, cnxn_id, pData);
+-}
+diff --git a/extensions/pref/system-pref/src/nsISystemPrefService.h b/extensions/pref/system-pref/src/nsISystemPrefService.h
+new file mode 100644
+--- /dev/null
++++ b/extensions/pref/system-pref/src/nsISystemPrefService.h
+@@ -0,0 +1,107 @@
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* vim:expandtab:shiftwidth=4:tabstop=4:
++ */
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ *
++ * The contents of this file are subject to the Mozilla Public
++ * License Version 1.1 (the "License"); you may not use this file
++ * except in compliance with the License. You may obtain a copy of
++ * the License at http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS
++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ * implied. See the License for the specific language governing
++ * rights and limitations under the License.
++ *
++ * The Original Code is mozilla.org code.
++ *
++ * The Initial Developer of the Original Code is Novell
++ * Portions created by Novell are Copyright (C) 2005 Novell,
++ * All Rights Reserved.
++ *
++ * Original Author: Robert O'Callahan (rocallahan@novell.com)
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the NPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the NPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#ifndef nsISystemPrefService_h__
++#define nsISystemPrefService_h__
++
++#include "nsCOMPtr.h"
++#include "nsIPrefBranchInternal.h"
++
++#define NS_SYSTEMPREF_SERVICE_CONTRACTID "@mozilla.org/system-preference-service;1"
++
++#define NS_ISYSTEMPREFSERVICE_IID   \
++{ 0x006e1cfd, 0xd66a, 0x40b9, \
++    { 0x84, 0xa1, 0x84, 0xf3, 0xe6, 0xa2, 0xca, 0xbc } }
++
++class nsISystemPref {
++public:
++    /**
++     * Call one of these three methods to override a Mozilla
++     * preference with a system value. You can call it multiple
++     * times to change the value of a given preference to track
++     * the underlying system value.
++     *
++     * If aLocked is true then we set the default preference and
++     * lock it so the user value is ignored. If aLocked is false
++     * then we unlock the Mozilla preference and set the Mozilla
++     * user value.
++     */
++    virtual nsresult SetOverridingMozillaBoolPref(const char* aPrefName,
++                                                  PRBool aValue, PRBool aLocked,
++                                                  PRBool aPresent = PR_TRUE) = 0;
++    virtual nsresult SetOverridingMozillaIntPref(const char* aPrefName,
++                                                 PRInt32 aValue, PRBool aLocked,
++                                                 PRBool aPresent = PR_TRUE) = 0;
++    virtual nsresult SetOverridingMozillaStringPref(const char* aPrefName,
++                                                    const char* aValue, PRBool aLocked,
++                                                    PRBool aPresent = PR_TRUE) = 0;
++    virtual nsresult StopOverridingMozillaPref(const char* aPrefName) = 0;
++    virtual already_AddRefed<nsIPrefBranch2> GetPrefUserBranch() = 0;
++    virtual already_AddRefed<nsIPrefBranch> GetPrefDefaultBranch() = 0;
++};
++
++class nsISystemPrefService : public nsISupports {
++public:
++    NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISYSTEMPREFSERVICE_IID)
++
++    /**
++     * Load the system prefs from the store into their corresponding
++     * Mozilla prefs, calling SetOverridingMozillaPref on each
++     * such pref.
++     */
++    virtual nsresult LoadSystemPreferences(nsISystemPref* aPrefs) = 0;
++
++    /**
++     * Notify that a Mozilla user pref that is being overridden by the
++     * store has changed.  The new value of the Mozilla pref should be
++     * written back to the store.
++     */
++    virtual nsresult NotifyMozillaPrefChanged(const char* aPrefName) = 0;
++
++    /**
++     * Notify that we're about to stop using the system prefs.  After
++     * this, nsSystemPref will automatically stop overriding all
++     * Mozilla prefs that are being overridden.
++     */
++    virtual nsresult NotifyUnloadSystemPreferences() = 0;
++};
++
++#endif
+diff --git a/extensions/pref/system-pref/src/nsSystemPref.cpp b/extensions/pref/system-pref/src/nsSystemPref.cpp
+--- a/extensions/pref/system-pref/src/nsSystemPref.cpp
++++ b/extensions/pref/system-pref/src/nsSystemPref.cpp
+@@ -19,16 +19,17 @@
+  *
+  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+  * Portions created by Sun Microsystems are Copyright (C) 2003 Sun
+  * Microsystems, Inc. All Rights Reserved.
+  *
+  * Original Author: Bolian Yin (bolian.yin@sun.com)
+  *
+  * Contributor(s):
++ *   Robert O'Callahan (rocallahan@novell.com)
+  *
+  * Alternatively, the contents of this file may be used under the terms of
+  * either the GNU General Public License Version 2 or later (the "GPL"), or
+  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+  * in which case the provisions of the GPL or the LGPL are applicable instead
+  * of those above. If you wish to allow use of your version of this file only
+  * under the terms of either the GPL or the LGPL, and not to allow others to
+  * use your version of this file under the terms of the NPL, indicate your
+@@ -36,76 +37,72 @@
+  * and other provisions required by the GPL or the LGPL. If you do not delete
+  * the provisions above, a recipient may use your version of this file under
+  * the terms of any one of the NPL, the GPL or the LGPL.
+  *
+  * ***** END LICENSE BLOCK ***** */
+ 
+ #include "nsSystemPref.h"
+ #include "nsIObserverService.h"
++#include "nsIAppStartupNotifier.h"
++#include "nsIPrefService.h"
++#include "nsIPrefBranch.h"
++#include "nsICategoryManager.h"
++#include "nsIServiceManager.h"
+ 
+ #include "nsSystemPrefLog.h"
+-#include "nsSystemPrefService.h"
+ #include "nsString.h"
+ 
+-const char sSysPrefString[] = "config.use_system_prefs";
+-union MozPrefValue {
+-    char *      stringVal;
+-    PRInt32     intVal;
+-    PRBool      boolVal;
+-};
++#include <stdlib.h>
+ 
+ struct SysPrefItem {
+-    const char *prefName;       // mozilla pref string name
+-    MozPrefValue defaultValue;  // store the mozilla default value
+-    PRBool isLocked;  // store the mozilla lock status
++    // Saved values on both branches
++    PRInt32      savedUserValueScalar;
++    char*        savedUserValueString;
++    PRInt32      savedDefaultValueScalar;
++    char*        savedDefaultValueString;
++    // When this is true, then the value was locked originally
++    PRPackedBool savedLocked;
++    // When this is true, then there was a user value
++    PRPackedBool savedUserPresent;
++    PRPackedBool ignore;
++    
+     SysPrefItem() {
+-        prefName = nsnull;
+-        defaultValue.intVal = 0;
+-        defaultValue.stringVal = nsnull;
+-        defaultValue.boolVal = PR_FALSE;
+-        isLocked = PR_FALSE;
++        savedUserValueScalar = 0;
++        savedUserValueString = nsnull;
++        savedDefaultValueScalar = 0;
++        savedDefaultValueString = nsnull;
++        savedUserPresent = PR_FALSE;
++        savedLocked = PR_FALSE;
++        ignore = PR_FALSE;
+     }
+-    void SetPrefName(const char *aPrefName) {
+-        prefName = aPrefName;
++
++    virtual ~SysPrefItem() {
++        nsMemory::Free(savedUserValueString);
++        nsMemory::Free(savedDefaultValueString);
+     }
+ };
+ 
+-// all prefs that mozilla need to read from host system if they are available
+-static const char *sSysPrefList[] = {
+-    "network.proxy.http",
+-    "network.proxy.http_port",
+-    "network.proxy.ftp",
+-    "network.proxy.ftp_port",
+-    "network.proxy.ssl",
+-    "network.proxy.ssl_port",
+-    "network.proxy.socks",
+-    "network.proxy.socks_port",
+-    "network.proxy.no_proxies_on",
+-    "network.proxy.autoconfig_url",
+-    "network.proxy.type",
+-    "config.use_system_prefs.accessibility",
+-};
++NS_DEFINE_STATIC_IID_ACCESSOR(nsISystemPrefService, NS_ISYSTEMPREFSERVICE_IID)
++
++static const char sSysPrefString[] = "config.use_system_prefs";
+ 
+ PRLogModuleInfo *gSysPrefLog = NULL;
+ 
+ NS_IMPL_ISUPPORTS2(nsSystemPref, nsIObserver, nsISupportsWeakReference)
+ 
+-nsSystemPref::nsSystemPref():
+-    mSysPrefService(nsnull),
+-    mEnabled(PR_FALSE),
+-    mSysPrefs(nsnull)
++nsSystemPref::nsSystemPref() : mIgnorePrefSetting(PR_FALSE)
+ {
++   mSavedPrefs.Init();
++   mCachedUserPrefBranch = nsnull;
++   mCachedDefaultPrefBranch = nsnull;
+ }
+ 
+ nsSystemPref::~nsSystemPref()
+ {
+-    mSysPrefService = nsnull;
+-    mEnabled = PR_FALSE;
+-    delete [] mSysPrefs;
+ }
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ // nsSystemPref::Init
+ // Setup log and listen on NS_PREFSERVICE_READ_TOPIC_ID from pref service
+ ///////////////////////////////////////////////////////////////////////////////
+ nsresult
+ nsSystemPref::Init(void)
+@@ -126,349 +123,519 @@ nsSystemPref::Init(void)
+                                           PR_FALSE);
+         rv = observerService->AddObserver(this, "profile-before-change",
+                                           PR_FALSE);
+         SYSPREF_LOG(("Add Observer for %s\n", NS_PREFSERVICE_READ_TOPIC_ID));
+     }
+     return(rv);
+ }
+ 
++already_AddRefed<nsIPrefBranch2>
++nsSystemPref::GetPrefUserBranch()
++{
++    if (mCachedUserPrefBranch) {
++        NS_ADDREF(mCachedUserPrefBranch);
++        return mCachedUserPrefBranch;
++    }
++
++    nsresult rv;
++    nsCOMPtr<nsIPrefService> prefService = 
++        do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
++    if (NS_FAILED(rv))
++        return nsnull;
++    nsCOMPtr<nsIPrefBranch> prefBranch;
++    rv = prefService->GetBranch(nsnull, getter_AddRefs(prefBranch));
++    if (NS_FAILED(rv))
++        return nsnull;
++    nsCOMPtr<nsIPrefBranch2> pb2(do_QueryInterface(prefBranch));
++    if (!pb2)
++        return nsnull;
++    
++    nsIPrefBranch2* result = nsnull;
++    pb2.swap(result);
++    return result;
++}
++
++already_AddRefed<nsIPrefBranch>
++nsSystemPref::GetPrefDefaultBranch()
++{
++    if (mCachedDefaultPrefBranch) {
++        NS_ADDREF(mCachedDefaultPrefBranch);
++        return mCachedDefaultPrefBranch;
++    }
++
++    nsresult rv;
++    nsCOMPtr<nsIPrefService> prefService = 
++        do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
++    if (NS_FAILED(rv))
++        return nsnull;
++    nsCOMPtr<nsIPrefBranch> prefBranch;
++    rv = prefService->GetDefaultBranch(nsnull, getter_AddRefs(prefBranch));
++    if (NS_FAILED(rv))
++        return nsnull;
++    nsIPrefBranch* pb = nsnull;
++    prefBranch.swap(pb);
++    return pb;
++}
++
+ ///////////////////////////////////////////////////////////////////////////////
+ // nsSystemPref::Observe
+ // Observe notifications from mozilla pref system and system prefs (if enabled)
+ ///////////////////////////////////////////////////////////////////////////////
+ NS_IMETHODIMP
+ nsSystemPref::Observe(nsISupports *aSubject,
+                       const char *aTopic,
+                       const PRUnichar *aData)
+ {
+     nsresult rv = NS_OK;
+ 
+     if (!aTopic)
+         return NS_OK;
+ 
+-    // if we are notified by pref service
+-    // check the system pref settings
++    nsCOMPtr<nsIPrefBranch2> userBranch = GetPrefUserBranch();
++    nsCOMPtr<nsIPrefBranch> defaultBranch = GetPrefDefaultBranch();
++ 
++    // Check the default branch first. If system prefs are enabled
++    // by default, then don't check the user prefs; we don't want
++    // to allow users to change the default.
++    PRBool defaultEnabled;
++    rv = defaultBranch->GetBoolPref(sSysPrefString, &defaultEnabled);
++    if (NS_FAILED(rv)) {
++        SYSPREF_LOG(("...Failed to Get %s\n", sSysPrefString));
++        return rv;
++    }
++    PRBool enabled = defaultEnabled;
++    if (!enabled) {
++        rv = userBranch->GetBoolPref(sSysPrefString, &enabled);
++
++        if (NS_FAILED(rv)) {
++            SYSPREF_LOG(("...Failed to Get %s\n", sSysPrefString));
++            return rv;
++        }
++    }
+     if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) {
++        // The prefs have just loaded. This is the first thing that
++        // happens to us.
+         SYSPREF_LOG(("Observed: %s\n", aTopic));
++ 
+ 
+-        nsCOMPtr<nsIPrefBranch2> prefBranch =
+-            do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
++        // listen on changes to use_system_pref. It's OK to
++        // hold a strong reference because we don't keep a reference
++        // to the pref branch.
++        rv = userBranch->AddObserver(sSysPrefString, this, PR_TRUE);
++
++        if (NS_FAILED(rv)) {
++            SYSPREF_LOG(("...Failed to add observer for %s\n", sSysPrefString));
++            return rv;
++        }
++        NS_ASSERTION(!mSysPrefService, "Should not be already enabled");
++        if (!enabled) {
++            // Don't load the system pref service if the preference is
++            // not set.
++            return NS_OK;
++        }
++
++        SYSPREF_LOG(("%s is enabled\n", sSysPrefString));
++
++	rv = LoadSystemPrefs();
+         if (NS_FAILED(rv))
+             return rv;
+ 
+-        rv = prefBranch->GetBoolPref(sSysPrefString, &mEnabled);
+-        if (NS_FAILED(rv)) {
+-            SYSPREF_LOG(("...FAil to Get %s\n", sSysPrefString));
+-            return rv;
+-        }
+-
+-        // if there is no system pref service, assume nothing happen to us
+-        mSysPrefService = do_GetService(NS_SYSTEMPREF_SERVICE_CONTRACTID, &rv);
+-        if (NS_FAILED(rv) || !mSysPrefService) {
+-            SYSPREF_LOG(("...No System Pref Service\n"));
+-            return NS_OK;
+-        }
+-
+-        // listen on its changes
+-        rv = prefBranch->AddObserver(sSysPrefString, this, PR_TRUE);
+-        if (NS_FAILED(rv)) {
+-            SYSPREF_LOG(("...FAil to add observer for %s\n", sSysPrefString));
+-            return rv;
+-        }
+-
+-        if (!mEnabled) {
+-            SYSPREF_LOG(("%s is disabled\n", sSysPrefString));
+-            return NS_OK;
+-        }
+-        SYSPREF_LOG(("%s is enabled\n", sSysPrefString));
+-        rv = UseSystemPrefs();
+-
+-    }
+-    // sSysPrefString value was changed, update ...
+-    else if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) &&
+-             NS_ConvertUTF8toUTF16(sSysPrefString).Equals(aData)) {
+-        SYSPREF_LOG(("++++++ Notify: topic=%s data=%s\n",
+-                     aTopic, NS_ConvertUTF16toUTF8(aData).get()));
+-
+-        nsCOMPtr<nsIPrefBranch> prefBranch =
+-            do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+-        if (NS_FAILED(rv))
+-            return rv;
+-
+-        PRBool enabled = mEnabled;
+-        rv = prefBranch->GetBoolPref(sSysPrefString, &mEnabled);
+-        if (enabled != mEnabled) {
+-            if (mEnabled)
+-                //read prefs from system
+-                rv = UseSystemPrefs();
+-            else
+-                //roll back to mozilla prefs
+-                rv = UseMozillaPrefs();
++        // Lock config.use_system_prefs so the user can't undo
++        // it. But only do this if it was set by in the default prefs;
++        // if it was not set by default, then locking it would actually
++        // unset the value! And the user should be allowed to turn off
++        // something they set themselves.
++        if (NS_SUCCEEDED(rv) && defaultEnabled) {
++            userBranch->LockPref(sSysPrefString);
+         }
+     }
+ 
+-    // if the system pref notify us that some pref has been changed by user
+-    // outside mozilla. We need to read it again.
+-    else if (!nsCRT::strcmp(aTopic, NS_SYSTEMPREF_PREFCHANGE_TOPIC_ID) &&
+-             aData) {
+-        NS_ASSERTION(mEnabled == PR_TRUE, "Should not listen when disabled");
+-        SYSPREF_LOG(("====== System Pref Notify topic=%s data=%s\n",
+-                     aTopic, (char*)aData));
+-        rv = ReadSystemPref(NS_LossyConvertUTF16toASCII(aData).get());
++    if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) &&
++        nsDependentString(aData).EqualsASCII(sSysPrefString)) {
++        // sSysPrefString value was changed, update...
++        SYSPREF_LOG(("++++++ Notify: topic=%s data=%s\n",
++                     aTopic, NS_ConvertUTF16toUTF8(aData).get()));
++        if (mSysPrefService && !enabled)
++            return RestoreMozillaPrefs();
++        if (!mSysPrefService && enabled) {
++            // Don't lock it. If the user enabled use_system_prefs,
++            // they should be allowed to unlock it.
++            return LoadSystemPrefs();
++        }
++ 
++        // didn't change?
+         return NS_OK;
+-    } else if (!nsCRT::strcmp(aTopic,"profile-before-change")) {
+-      //roll back to mozilla prefs
+-      if (mEnabled)
+-        UseMozillaPrefs();
+-      mEnabled = PR_FALSE;
+-      mSysPrefService = nsnull;
+-      delete [] mSysPrefs;
+-      mSysPrefs = nsnull;
+-    } else
+-        SYSPREF_LOG(("Not needed topic Received %s\n", aTopic));
++    }
++
++    if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
++        // some other pref changed, tell the backend if there is one
++        if (mSysPrefService && !mIgnorePrefSetting) {
++            NS_LossyConvertUTF16toASCII tmp(aData);
++#ifdef DEBUG
++            PRBool isLocked;
++            userBranch->PrefIsLocked(tmp.get(), &isLocked);
++            NS_ASSERTION(!isLocked, "Locked pref is changing?");
++#endif
++            SysPrefItem* item;
++            if (!mSavedPrefs.Get(tmp, &item)) {
++                NS_ERROR("Notified about pref change that we didn't ask about?");
++            } else {
++                if (!item->ignore) {
++                    mSysPrefService->NotifyMozillaPrefChanged(tmp.get());
++                }
++            }
++        }
++        return NS_OK;
++    }
++
++    if (!nsCRT::strcmp(aTopic,"profile-before-change"))
++        return RestoreMozillaPrefs();
++
++    SYSPREF_LOG(("Not needed topic Received %s\n", aTopic));
++
+     return rv;
+ }
+ 
+-/* private */
++nsresult
++nsSystemPref::SetOverridingMozillaBoolPref(const char* aPrefName,
++                                           PRBool aValue, PRBool aLock, PRBool aPresent)
++{
++    return OverridePref(aPrefName, nsIPrefBranch::PREF_BOOL,
++                        (void*)aValue, aLock, aPresent);
++}
+ 
+-////////////////////////////////////////////////////////////////
+-// nsSystemPref::UseSystemPrefs
+-// Read all the prefs in the table from system, listen for their
+-// changes in system pref service.
+-////////////////////////////////////////////////////////////////
+ nsresult
+-nsSystemPref::UseSystemPrefs()
++nsSystemPref::SetOverridingMozillaIntPref(const char* aPrefName,
++                                          PRInt32 aValue, PRBool aLock, PRBool aPresent)
+ {
+-    SYSPREF_LOG(("\n====Now Use system prefs==\n"));
+-    nsresult rv = NS_OK;
+-    if (!mSysPrefService) {
++    return OverridePref(aPrefName, nsIPrefBranch::PREF_INT,
++                        (void*)aValue, aLock, aPresent);
++}
++
++
++nsresult
++nsSystemPref::SetOverridingMozillaStringPref(const char* aPrefName,
++                                             const char* aValue, PRBool aLock, PRBool aPresent)
++{
++    return OverridePref(aPrefName, nsIPrefBranch::PREF_STRING,
++                        (void*)aValue, aLock, aPresent);
++}
++
++static nsresult RestorePrefValue(PRInt32 aPrefType,
++                                 const char* aPrefName,
++                                 SysPrefItem* aItem,
++                                 nsIPrefBranch* aUser,
++                                 nsIPrefBranch* aDefault)
++{
++    switch (aPrefType) {
++
++    case nsIPrefBranch::PREF_STRING:
++        aDefault->SetCharPref(aPrefName,
++                              aItem->savedDefaultValueString);
++        if (aItem->savedUserPresent) {
++            aUser->SetCharPref(aPrefName, aItem->savedUserValueString);
++        }
++        break;
++    case nsIPrefBranch::PREF_INT:
++        aDefault->SetBoolPref(aPrefName, aItem->savedDefaultValueScalar);
++        if (aItem->savedUserPresent) {
++            aUser->SetBoolPref(aPrefName, aItem->savedUserValueScalar);
++        }
++        break;
++    case nsIPrefBranch::PREF_BOOL:
++        aDefault->SetBoolPref(aPrefName, aItem->savedDefaultValueScalar);
++        if (aItem->savedUserPresent) {
++            aUser->SetBoolPref(aPrefName, aItem->savedUserValueScalar);
++        }
++        break;
++    default:
++        NS_ERROR("Unknown preference type");
+         return NS_ERROR_FAILURE;
+     }
+ 
+-    PRIntn sysPrefCount= sizeof(sSysPrefList) / sizeof(sSysPrefList[0]);
+-
+-    if (!mSysPrefs) {
+-        mSysPrefs = new SysPrefItem[sysPrefCount];
+-        if (!mSysPrefs)
+-            return NS_ERROR_OUT_OF_MEMORY;
+-        for (PRIntn index = 0; index < sysPrefCount; ++index)
+-            mSysPrefs[index].SetPrefName(sSysPrefList[index]);
++    if (!aItem->savedUserPresent) {
++        aUser->DeleteBranch(aPrefName);
+     }
+ 
+-    for (PRIntn index = 0; index < sysPrefCount; ++index) {
+-        // save mozilla prefs
+-        SaveMozDefaultPref(mSysPrefs[index].prefName,
+-                           &mSysPrefs[index].defaultValue,
+-                           &mSysPrefs[index].isLocked);
++    return NS_OK;
++}
+ 
+-        // get the system prefs
+-        ReadSystemPref(mSysPrefs[index].prefName);
+-        SYSPREF_LOG(("Add Listener on %s\n", mSysPrefs[index].prefName));
+-        mSysPrefService->AddObserver(mSysPrefs[index].prefName,
+-                                     this, PR_TRUE);
++static PLDHashOperator PR_CALLBACK RestorePref(const nsACString& aKey,
++                                               SysPrefItem* aItem,
++                                               void* aClosure)
++{
++    nsSystemPref* prefs = static_cast<nsSystemPref*>(aClosure);
++    nsCOMPtr<nsIPrefBranch2> userBranch = prefs->GetPrefUserBranch();
++    const nsCString& prefName = PromiseFlatCString(aKey);
++    
++    PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
++    nsresult rv = userBranch->GetPrefType(prefName.get(), &prefType);
++    if (NS_FAILED(rv))
++        return PL_DHASH_NEXT;
++    PRBool isLocked;
++    userBranch->PrefIsLocked(prefName.get(), &isLocked);
++    if (NS_FAILED(rv))
++        return PL_DHASH_NEXT;
++
++
++    // Remove our observer before we change the value
++    userBranch->RemoveObserver(prefName.get(), prefs);
++    // Remember to ignore this item. Because some prefs start with "config.use_system_prefs",
++    // which we always observe, even after we remove the observer, changes to the pref will
++    // still be observed by us. We must ignore them.
++    aItem->ignore = PR_TRUE;
++
++
++    // Unlock the pref so we can set it
++    if (isLocked) {
++        userBranch->UnlockPref(prefName.get());
+     }
++
++    nsCOMPtr<nsIPrefBranch> defaultBranch = prefs->GetPrefDefaultBranch();
++
++    RestorePrefValue(prefType, prefName.get(), aItem,
++                     userBranch, defaultBranch);
++
++    if (aItem->savedLocked) {
++        userBranch->LockPref(prefName.get());
++    }
++
++    return PL_DHASH_NEXT;
++}
++
++nsresult
++nsSystemPref::StopOverridingMozillaPref(const char* aPrefName)
++{
++    SysPrefItem* item;
++    nsDependentCString prefNameStr(aPrefName);
++    if (!mSavedPrefs.Get(prefNameStr, &item))
++        return NS_OK;
++
++    RestorePref(prefNameStr, item, this);
++    mSavedPrefs.Remove(prefNameStr);
++    delete item;
++    return NS_OK;
++}
++
++/* private */
++ 
++nsresult
++nsSystemPref::OverridePref(const char* aPrefName, PRInt32 aType,
++                           void* aValue, PRBool aLock, PRBool aPresent)
++{
++    nsCOMPtr<nsIPrefBranch2> userBranch = GetPrefUserBranch();
++    nsCOMPtr<nsIPrefBranch> defaultBranch = GetPrefDefaultBranch();
++
++    PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
++    nsresult rv = userBranch->GetPrefType(aPrefName, &prefType);
++    PRBool isLocked;
++    rv = userBranch->PrefIsLocked(aPrefName, &isLocked);
++    if (NS_FAILED(rv))
++        return rv;
++    PRBool hasUserValue;
++    rv = userBranch->PrefHasUserValue(aPrefName, &hasUserValue);
++    if (NS_FAILED(rv))
++        return rv;
++    if (prefType == 0) {
++        // Preference does not exist. Allow the system prefs to
++        // set it.
++    } else {
++        NS_ASSERTION(aType == prefType,
++                     "System pref engine passed incorrect type for Mozilla pref");
++        if (aType != prefType)
++            return NS_ERROR_FAILURE;
++    }
++
++    if (prefType != 0) {
++        nsDependentCString prefNameStr(aPrefName);
++        SysPrefItem* item = nsnull;
++        if (!mSavedPrefs.Get(prefNameStr, &item)) {
++            // Need to save the existing value away
++            item = new SysPrefItem();
++            if (!item)
++                return NS_ERROR_OUT_OF_MEMORY;
++
++            item->savedLocked = isLocked;
++            item->savedUserPresent = hasUserValue;
++        
++            switch (prefType) {
++            case nsIPrefBranch::PREF_STRING:
++                if (hasUserValue) {
++                    userBranch->GetCharPref(aPrefName, &item->savedUserValueString);
++                }
++                defaultBranch->GetCharPref(aPrefName, &item->savedDefaultValueString);
++                break;
++            case nsIPrefBranch::PREF_INT:
++                if (hasUserValue) {
++                    userBranch->GetIntPref(aPrefName, &item->savedUserValueScalar);
++                }
++                defaultBranch->GetIntPref(aPrefName, &item->savedDefaultValueScalar);
++                break;
++            case nsIPrefBranch::PREF_BOOL:
++                if (hasUserValue) {
++                    userBranch->GetBoolPref(aPrefName, &item->savedUserValueScalar);
++                }
++                defaultBranch->GetBoolPref(aPrefName, &item->savedDefaultValueScalar);
++                break;
++            default:
++                NS_ERROR("Unknown preference type");
++                delete item;
++                return NS_ERROR_FAILURE;
++            }
++
++            mSavedPrefs.Put(prefNameStr, item);
++
++            // Watch the user value in case it changes on the Mozilla side
++            // If 'aLock' is true then it shouldn't change and we don't
++            // need the observer, but don't bother optimizing for that.
++            userBranch->AddObserver(aPrefName, this, PR_TRUE);
++        } else {
++            if (isLocked != aLock) {
++                // restore pref value on user and default branches
++                RestorePrefValue(prefType, aPrefName, item,
++                                 userBranch, defaultBranch);
++            }
++        }
++    }
++
++    // We need to ignore pref changes due to our own calls here
++    mIgnorePrefSetting = PR_TRUE;
++ 
++    // Unlock it if it's locked, so we can set it
++    if (isLocked) {
++        rv = userBranch->UnlockPref(aPrefName);
++        if (NS_FAILED(rv))
++            return rv;
++    }
++
++    // Set the pref on the default branch if we're locking it, because
++    // only the default branch gets used when the pref is locked.
++    // Set the pref on the user branch if we're not locking it, because
++    // that's where the user change will go.
++    nsIPrefBranch* settingBranch =
++        aLock ? defaultBranch.get() : static_cast<nsIPrefBranch*>(userBranch.get());
++
++    if (!aPresent) {
++        rv = settingBranch->DeleteBranch(aPrefName);
++    } else {
++        switch (aType) {
++        case nsIPrefBranch::PREF_STRING:
++            rv = settingBranch->SetCharPref(aPrefName, (const char*)aValue);
++            break;
++        case nsIPrefBranch::PREF_INT:
++            rv = settingBranch->SetIntPref(aPrefName, (PRInt32)(NS_PTR_TO_INT32(aValue)));
++            break;
++        case nsIPrefBranch::PREF_BOOL:
++            rv = settingBranch->SetBoolPref(aPrefName, (PRBool)(NS_PTR_TO_INT32(aValue)));
++            break;
++        default:
++            NS_ERROR("Unknown preference type");
++            mIgnorePrefSetting = PR_FALSE;
++            return NS_ERROR_FAILURE;
++        }
++    }
++
++    if (NS_FAILED(rv))
++        return rv;
++    if (aLock) {
++        rv = userBranch->LockPref(aPrefName);
++    }
++
++    mIgnorePrefSetting = PR_FALSE;
+     return rv;
+ }
+ 
+-//////////////////////////////////////////////////////////////////////
+-// nsSystemPref::ReadSystemPref
+-// Read a pref value from system pref service, and lock it in mozilla.
+-//////////////////////////////////////////////////////////////////////
++
+ nsresult
+-nsSystemPref::ReadSystemPref(const char *aPrefName)
++nsSystemPref::FixupLockdownPrefs()
+ {
+-    if (!mSysPrefService)
+-        return NS_ERROR_FAILURE;
+-    nsresult rv;
+-
+-    nsCOMPtr<nsIPrefBranch> prefBranch
+-        (do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
++    nsCOMPtr<nsIPrefBranch2> userPrefs = GetPrefUserBranch();
++    nsCOMPtr<nsIPrefBranch2> defaultPrefs = GetPrefUserBranch();
++    PRUint32 childCount;
++    char **childArray = nsnull;
++    nsresult rv = userPrefs->GetChildList("config.lockdown.",
++                                          &childCount, &childArray);
+     if (NS_FAILED(rv))
+         return rv;
+-
+-    SYSPREF_LOG(("about to read aPrefName %s\n", aPrefName));
+-
+-    prefBranch->UnlockPref(aPrefName);
+-
+-    PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
+-    nsXPIDLCString strValue;
+-    PRInt32 intValue = 0;
+-    PRBool boolValue = PR_FALSE;
+-
+-    rv = prefBranch->GetPrefType(aPrefName, &prefType);
+-    if (NS_FAILED(rv))
+-        return rv;
+-    switch (prefType) {
+-    case nsIPrefBranch::PREF_STRING:
+-        mSysPrefService->GetCharPref(aPrefName, getter_Copies(strValue));
+-        SYSPREF_LOG(("system value is %s\n", strValue.get()));
+-
+-        prefBranch->SetCharPref(aPrefName, strValue.get());
+-        break;
+-    case nsIPrefBranch::PREF_INT:
+-        mSysPrefService->GetIntPref(aPrefName, &intValue);
+-        SYSPREF_LOG(("system value is %d\n", intValue));
+-
+-        prefBranch->SetIntPref(aPrefName, intValue);
+-        break;
+-    case nsIPrefBranch::PREF_BOOL:
+-        mSysPrefService->GetBoolPref(aPrefName, &boolValue);
+-        SYSPREF_LOG(("system value is %s\n", boolValue ? "TRUE" : "FALSE"));
+-
+-        prefBranch->SetBoolPref(aPrefName, boolValue);
+-        break;
+-    default:
+-        SYSPREF_LOG(("Fail to system value for it\n"));
+-        return NS_ERROR_FAILURE;
++    for (PRUint32 i = 0; i < childCount; ++i) {
++        PRInt32 type;
++        rv = defaultPrefs->GetPrefType(childArray[i], &type);
++        if (NS_FAILED(rv))
++            return rv;
++        NS_ASSERTION(type == nsIPrefBranch2::PREF_BOOL,
++                     "All config.lockdown.* prefs should be boolean");
++        if (type == nsIPrefBranch2::PREF_BOOL) {
++            rv = defaultPrefs->SetBoolPref(childArray[i], PR_FALSE);
++            if (NS_FAILED(rv))
++                return rv;
++        }
+     }
+-    prefBranch->LockPref(aPrefName);
++    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray);
+     return NS_OK;
+ }
+ 
+-//////////////////////////////////////////////////////////////////////
+-// nsSystemPref::UseMozillaPrefs
+-// Restore mozilla default prefs, remove system pref listeners
+-/////////////////////////////////////////////////////////////////////
++
+ nsresult
+-nsSystemPref::UseMozillaPrefs()
++nsSystemPref::LoadSystemPrefs()
+ {
+-    nsresult rv = NS_OK;
+-    SYSPREF_LOG(("\n====Now rollback to Mozilla prefs==\n"));
++    SYSPREF_LOG(("\n====Now Use system prefs==\n"));
++    NS_ASSERTION(!mSysPrefService,
++                 "Shouldn't have the pref service here");
++    nsresult rv;
++    mSysPrefService = do_GetService(NS_SYSTEMPREF_SERVICE_CONTRACTID, &rv);
++    if (NS_FAILED(rv) || !mSysPrefService) {
++        FixupLockdownPrefs();
++        SYSPREF_LOG(("...No System Pref Service\n"));
++        return NS_OK;
++    }
+ 
+-    // if we did not use system prefs, do nothing
+-    if (!mSysPrefService)
+-        return NS_OK;
++    // Cache the pref-branch while we load up the system prefs.
++    NS_ASSERTION(!mCachedUserPrefBranch,
++                 "Shouldn't have a cache here");
++    nsCOMPtr<nsIPrefBranch2> userBranch = GetPrefUserBranch();
++    nsCOMPtr<nsIPrefBranch> defaultBranch = GetPrefDefaultBranch();
++    mCachedDefaultPrefBranch = defaultBranch;
++    mCachedUserPrefBranch = userBranch;
++    rv = mSysPrefService->LoadSystemPreferences(this);
++    mCachedDefaultPrefBranch = nsnull;
++    mCachedUserPrefBranch = nsnull;
+ 
+-    PRIntn sysPrefCount= sizeof(sSysPrefList) / sizeof(sSysPrefList[0]);
+-    for (PRIntn index = 0; index < sysPrefCount; ++index) {
+-        // restore mozilla default value and free string memory if needed
+-        RestoreMozDefaultPref(mSysPrefs[index].prefName,
+-                              &mSysPrefs[index].defaultValue,
+-                              mSysPrefs[index].isLocked);
+-        SYSPREF_LOG(("stop listening on %s\n", mSysPrefs[index].prefName));
+-        mSysPrefService->RemoveObserver(mSysPrefs[index].prefName,
+-                                        this);
++    if (NS_FAILED(rv)) {
++        // Restore all modified preferences to their original values
++        mSavedPrefs.EnumerateRead(RestorePref, this);
++        mSavedPrefs.Clear();
++        mSysPrefService = nsnull;
+     }
++        
+     return rv;
+ }
+ 
+-////////////////////////////////////////////////////////////////////////////
+-// nsSystemPref::RestoreMozDefaultPref
+-// Save the saved mozilla default value.
+-// It is also responsible for allocate the string memory when needed, because
+-// this method know what type of value is stored.
+-/////////////////////////////////////////////////////////////////////////////
++
+ nsresult
+-nsSystemPref::SaveMozDefaultPref(const char *aPrefName,
+-                                 MozPrefValue *aPrefValue,
+-                                 PRBool *aLocked)
++nsSystemPref::RestoreMozillaPrefs()
+ {
+-    NS_ENSURE_ARG_POINTER(aPrefName);
+-    NS_ENSURE_ARG_POINTER(aPrefValue);
+-    NS_ENSURE_ARG_POINTER(aLocked);
++    SYSPREF_LOG(("\n====Now rollback to Mozilla prefs==\n"));
+ 
+-    nsresult rv;
++    NS_ASSERTION(mSysPrefService,
++                 "Should have the pref service here");
++    if (!mSysPrefService)
++        return NS_ERROR_FAILURE;
+ 
+-    nsCOMPtr<nsIPrefBranch> prefBranch =
+-        do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+-    if (NS_FAILED(rv))
+-        return rv;
++    nsCOMPtr<nsIPrefBranch2> userBranch = GetPrefUserBranch();
++    nsCOMPtr<nsIPrefBranch> defaultBranch = GetPrefDefaultBranch();
++    mCachedDefaultPrefBranch = defaultBranch;
++    mCachedUserPrefBranch = userBranch;
+ 
+-    SYSPREF_LOG(("Save Mozilla value for %s\n", aPrefName));
++    mSysPrefService->NotifyUnloadSystemPreferences();
++    // Restore all modified preferences to their original values
++    mSavedPrefs.EnumerateRead(RestorePref, this);
++    mSavedPrefs.Clear();
+ 
+-    PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
+-    nsXPIDLCString strValue;
++    mCachedDefaultPrefBranch = nsnull;
++    mCachedUserPrefBranch = nsnull;
++    
++    mSysPrefService = nsnull;
+ 
+-    rv = prefBranch->GetPrefType(aPrefName, &prefType);
+-    if (NS_FAILED(rv))
+-        return rv;
+-    switch (prefType) {
+-    case nsIPrefBranch::PREF_STRING:
+-        prefBranch->GetCharPref(aPrefName,
+-                                getter_Copies(strValue));
+-        SYSPREF_LOG(("Mozilla value is %s", strValue.get()));
++    FixupLockdownPrefs();
+ 
+-        if (aPrefValue->stringVal)
+-            PL_strfree(aPrefValue->stringVal);
+-        aPrefValue->stringVal = PL_strdup(strValue.get());
+-        break;
+-    case nsIPrefBranch::PREF_INT:
+-        prefBranch->GetIntPref(aPrefName, &aPrefValue->intVal);
+-        SYSPREF_LOG(("Mozilla value is %d\n", aPrefValue->intVal));
+-
+-        break;
+-    case nsIPrefBranch::PREF_BOOL:
+-        prefBranch->GetBoolPref(aPrefName, &aPrefValue->boolVal);
+-        SYSPREF_LOG(("Mozilla value is %s\n",
+-                     aPrefValue->boolVal ? "TRUE" : "FALSE"));
+-
+-        break;
+-    default:
+-        SYSPREF_LOG(("Fail to Read Mozilla value for it\n"));
+-        return NS_ERROR_FAILURE;
+-    }
+-    rv = prefBranch->PrefIsLocked(aPrefName, aLocked);
+-    SYSPREF_LOG((" (%s).\n", aLocked ? "Locked" : "NOT Locked"));
+-    return rv;
+-}
+-
+-////////////////////////////////////////////////////////////////////////////
+-// nsSystemPref::RestoreMozDefaultPref
+-// Restore the saved mozilla default value to pref service.
+-// It is also responsible for free the string memory when needed, because
+-// this method know what type of value is stored.
+-/////////////////////////////////////////////////////////////////////////////
+-nsresult
+-nsSystemPref::RestoreMozDefaultPref(const char *aPrefName,
+-                                    MozPrefValue *aPrefValue,
+-                                    PRBool aLocked)
+-{
+-    NS_ENSURE_ARG_POINTER(aPrefName);
+-
+-    nsresult rv;
+-
+-    nsCOMPtr<nsIPrefBranch> prefBranch =
+-        do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+-    if (NS_FAILED(rv))
+-        return rv;
+-
+-    SYSPREF_LOG(("Restore Mozilla value for %s\n", aPrefName));
+-
+-    PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
+-    rv = prefBranch->GetPrefType(aPrefName, &prefType);
+-    if (NS_FAILED(rv))
+-        return rv;
+-
+-    // unlock, if it is locked
+-    prefBranch->UnlockPref(aPrefName);
+-
+-    switch (prefType) {
+-    case nsIPrefBranch::PREF_STRING:
+-        prefBranch->SetCharPref(aPrefName,
+-                                aPrefValue->stringVal);
+-        SYSPREF_LOG(("Mozilla value is %s\n", aPrefValue->stringVal));
+-
+-        PL_strfree(aPrefValue->stringVal);
+-        aPrefValue->stringVal = nsnull;
+-
+-        break;
+-    case nsIPrefBranch::PREF_INT:
+-        prefBranch->SetIntPref(aPrefName, aPrefValue->intVal);
+-        SYSPREF_LOG(("Mozilla value is %d\n", aPrefValue->intVal));
+-
+-        break;
+-    case nsIPrefBranch::PREF_BOOL:
+-        prefBranch->SetBoolPref(aPrefName, aPrefValue->boolVal);
+-        SYSPREF_LOG(("Mozilla value is %s\n",
+-                     aPrefValue->boolVal ? "TRUE" : "FALSE"));
+-
+-        break;
+-    default:
+-        SYSPREF_LOG(("Fail to Restore Mozilla value for it\n"));
+-        return NS_ERROR_FAILURE;
+-    }
+-
+-    // restore its old lock status
+-    if (aLocked)
+-        prefBranch->LockPref(aPrefName);
+     return NS_OK;
+ }
+diff --git a/extensions/pref/system-pref/src/nsSystemPref.h b/extensions/pref/system-pref/src/nsSystemPref.h
+--- a/extensions/pref/system-pref/src/nsSystemPref.h
++++ b/extensions/pref/system-pref/src/nsSystemPref.h
+@@ -18,17 +18,17 @@
+  * The Original Code is mozilla.org code.
+  *
+  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
+  * Portions created by Sun Microsystems are Copyright (C) 2003 Sun
+  * Microsystems, Inc. All Rights Reserved.
+  *
+  * Original Author: Bolian Yin (bolian.yin@sun.com)
+  *
+- * Contributor(s):
++ * Contributor(s): Robert O'Callahan/Novell (rocallahan@novell.com)
+  *
+  * Alternatively, the contents of this file may be used under the terms of
+  * either the GNU General Public License Version 2 or later (the "GPL"), or
+  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+  * in which case the provisions of the GPL or the LGPL are applicable instead
+  * of those above. If you wish to allow use of your version of this file only
+  * under the terms of either the GPL or the LGPL, and not to allow others to
+  * use your version of this file under the terms of the NPL, indicate your
+@@ -40,71 +40,101 @@
+  * ***** END LICENSE BLOCK ***** */
+ 
+ #ifndef __SYSTEM_PREF_H__
+ #define __SYSTEM_PREF_H__
+ 
+ #include "nsCOMPtr.h"
+ #include "nsXPCOM.h"
+ #include "nsCRT.h"
+-#include "nsIAppStartupNotifier.h"
+-#include "nsICategoryManager.h"
+-#include "nsIServiceManager.h"
+ #include "nsWeakReference.h"
+-#include "nsIPrefService.h"
+-#include "nsIPrefBranch2.h"
++#include "nsClassHashtable.h"
++#include "nsHashKeys.h"
++#include "nsMemory.h"
+ 
+-#include <nsIObserver.h>
++#include "nsISystemPrefService.h"
++#include "nsIObserver.h"
+ 
+-union MozPrefValue;
+ struct SysPrefItem;
+ 
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // nsSystemPref, as an extension of mozilla pref service, reads some mozilla
+ // prefs from host system when the feature is enabled ("config.system-pref").
+ //
+-// nsSystemPref listens on NS_PREFSERVICE_READ_TOPIC_ID. When notified,
+-// nsSystemPref will start the nsSystemPrefService (platform specific) to
+-// read all the interested prefs (listed in sSysPrefList table) from system
+-// and lock these prefs from user's modification. 
++// nsSystemPref listens on NS_PREFSERVICE_READ_TOPIC_ID. When
++// notified, nsSystemPref will start the nsSystemPrefService (platform
++// specific) and tell it to override Mozilla prefs with its own
++// settings.
+ //
+-// This feature will make mozilla integrated better into host platforms. If
+-// users want to change the prefs read from system, the system provided pref
+-// editor (i.e. gconf-editor in gnome) should be used.
++// When overriding a Mozilla preference the prefservice can request the
++// pref be locked or unlocked. If the pref is locked then we set the default
++// value and lock it in Mozilla so the user value is ignored and the user cannot
++// change the value. If the pref is unlocked then we set the user value
++// and unlock it in Mozilla so the user can change it. If the user changes it,
++// then the prefservice is notified so it can copy the value back to its
++// underlying store.
++//
++// We detect changes to Mozilla prefs by observing pref changes in the
++// user branch.
++//
++// For testing purposes, if the user toggles on
++// config.use_system_prefs then we save the current preferences before
++// overriding them from gconf, and if the user toggles off
++// config.use_system_prefs *in the same session* then we restore the
++// preferences. If the user exits without turning off use_system_prefs
++// then the saved values are lost and the new values are permanent.
++//
+ //////////////////////////////////////////////////////////////////////////
+ 
+ class nsSystemPref : public nsIObserver,
+-                     public nsSupportsWeakReference
++                     public nsSupportsWeakReference,
++                     public nsISystemPref
+ {
+ public:
+     NS_DECL_ISUPPORTS
+     NS_DECL_NSIOBSERVER
+ 
+     nsSystemPref();
+     virtual ~nsSystemPref();
+     nsresult Init(void);
+ 
++    // nsISystemPref
++    virtual nsresult SetOverridingMozillaBoolPref(const char* aPrefName,
++                                                  PRBool aValue, PRBool aLocked,
++                                                  PRBool aPresent = PR_TRUE);
++    virtual nsresult SetOverridingMozillaIntPref(const char* aPrefName,
++                                                 PRInt32 aValue, PRBool aLocked,
++                                                 PRBool aPresent = PR_TRUE);
++    virtual nsresult SetOverridingMozillaStringPref(const char* aPrefName,
++                                                    const char* aValue, PRBool aLocked,
++                                                    PRBool aPresent = PR_TRUE);
++    virtual nsresult StopOverridingMozillaPref(const char* aPrefName);
++    virtual already_AddRefed<nsIPrefBranch2> GetPrefUserBranch();
++    virtual already_AddRefed<nsIPrefBranch> GetPrefDefaultBranch();
++
+ private:
+-    // funcs used to load system prefs and save mozilla default prefs
+-    nsresult UseSystemPrefs();
+-    nsresult ReadSystemPref(const char *aPrefName);
+-    nsresult SaveMozDefaultPref(const char *aPrefName,
+-                                MozPrefValue *aPrefVal,
+-                                PRBool *aLocked);
++    // If we don't load the system prefs for any reason, then
++    // set all config.lockdown.* preferences to PR_FALSE so that
++    // residual lockdown settings are removed.
++    nsresult FixupLockdownPrefs();
+ 
+-    // funcs used to load mozilla default prefs
+-    nsresult UseMozillaPrefs();
+-    nsresult RestoreMozDefaultPref(const char *aPrefName,
+-                                   MozPrefValue *aPrefVal,
+-                                   PRBool aLocked);
++    nsresult LoadSystemPrefs();
+ 
+-    nsCOMPtr<nsIPrefBranch2>  mSysPrefService;
+-    PRBool mEnabled;  // system pref is enabled or not
+-    SysPrefItem *mSysPrefs;
++    nsresult RestoreMozillaPrefs();
++
++    nsresult OverridePref(const char* aPrefName, PRInt32 aType,
++                          void* aValue, PRBool aLock, PRBool aPresent);
++
++    nsCOMPtr<nsISystemPrefService>  mSysPrefService;
++    nsClassHashtable<nsCStringHashKey,SysPrefItem> mSavedPrefs;
++    // weak pointers to cached prefbranches
++    nsIPrefBranch2* mCachedUserPrefBranch;
++    nsIPrefBranch* mCachedDefaultPrefBranch;
++    PRPackedBool mIgnorePrefSetting;
+ };
+ 
+ #define NS_SYSTEMPREF_CID                  \
+   { /* {549abb24-7c9d-4aba-915e-7ce0b716b32f} */       \
+     0x549abb24,                                        \
+     0x7c9d,                                            \
+     0x4aba,                                            \
+     { 0x91, 0x5e, 0x7c, 0xe0, 0xb7, 0x16, 0xb3, 0x2f } \
+diff --git a/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp b/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp
+--- a/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp
++++ b/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp
+@@ -37,20 +37,20 @@
+  * the provisions above, a recipient may use your version of this file under
+  * the terms of any one of the NPL, the GPL or the LGPL.
+  *
+  * ***** END LICENSE BLOCK ***** */
+ 
+ #include "nsICategoryManager.h"
+ #include "nsIGenericFactory.h"
+ #include "nsSystemPref.h"
+-#include "nsSystemPrefService.h"
++#include "nsIServiceManager.h"
++#include "nsIAppStartupNotifier.h"
+ 
+ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPref, Init)
+-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPrefService, Init)
+ 
+ // Registering nsSystemPref module as part of the app-startup category to get 
+ // it instantiated.
+ 
+ static NS_METHOD
+ RegisterSystemPref(nsIComponentManager *aCompMgr,
+                    nsIFile *aPath,
+                    const char *registryLocation,
+@@ -91,16 +91,11 @@ UnRegisterSystemPref(nsIComponentManager
+ static const nsModuleComponentInfo components[] = {
+     { NS_SYSTEMPREF_CLASSNAME,
+       NS_SYSTEMPREF_CID,
+       NS_SYSTEMPREF_CONTRACTID,
+       nsSystemPrefConstructor,
+       RegisterSystemPref,
+       UnRegisterSystemPref,
+     },
+-    { NS_SYSTEMPREF_SERVICE_CLASSNAME,
+-      NS_SYSTEMPREF_SERVICE_CID,
+-      NS_SYSTEMPREF_SERVICE_CONTRACTID,
+-      nsSystemPrefServiceConstructor,
+-    },
+ };
+ 
+ NS_IMPL_NSGETMODULE(nsSystemPrefModule, components)
+diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in
+--- a/toolkit/library/Makefile.in
++++ b/toolkit/library/Makefile.in
+@@ -229,16 +229,20 @@ endif
+ ifdef NS_OSSO
+ EXTRA_DSO_LDOPTS += $(LIBOSSO_LIBS)
+ endif
+ 
+ ifdef MOZ_ENABLE_DBUS
+ EXTRA_DSO_LDOPTS += $(MOZ_DBUS_GLIB_LIBS)
+ endif
+ 
++ifdef MOZ_ENABLE_GCONF
++EXTRA_DSO_LDOPTS += $(MOZ_GCONF_LIBS)
++endif
++
+ ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
+ EXTRA_DSO_LDOPTS += $(XLDFLAGS) $(XLIBS) $(XEXT_LIBS) $(XCOMPOSITE_LIBS) $(MOZ_PANGO_LIBS) $(MOZ_GTK2_LIBS) $(XT_LIBS) -lgthread-2.0
+ EXTRA_DSO_LDOPTS += $(FT2_LIBS)
+ endif
+ 
+ ifeq (qt,$(MOZ_WIDGET_TOOLKIT))
+ EXTRA_DSO_LDOPTS += $(XLDFLAGS) $(XLIBS) $(XT_LIBS) $(MOZ_QT_LIBS) -lgthread-2.0
+ EXTRA_DSO_LDOPTS += $(FT2_LIBS)
+diff --git a/toolkit/toolkit-tiers.mk b/toolkit/toolkit-tiers.mk
+--- a/toolkit/toolkit-tiers.mk
++++ b/toolkit/toolkit-tiers.mk
+@@ -253,16 +253,23 @@ endif
+ ifdef MOZ_ENABLE_LIBXUL
+ tier_toolkit_dirs += xpcom/stub
+ endif
+ 
+ ifdef NS_TRACE_MALLOC
+ tier_toolkit_dirs += tools/trace-malloc
+ endif
+ 
++# gconf module is external
++ifdef MOZ_PREF_EXTENSIONS
++ifdef MOZ_ENABLE_GCONF
++tier_toolkit_dirs += extensions/pref/system-pref/src/gconf
++endif
++endif
++
+ ifdef MOZ_ENABLE_GNOME_COMPONENT
+ tier_toolkit_dirs    += toolkit/system/gnome
+ endif
+ 
+ ifndef MOZ_ENABLE_LIBCONIC
+ # if libconic is present, it will do its own network monitoring
+ ifdef MOZ_ENABLE_DBUS
+ tier_toolkit_dirs    += toolkit/system/dbus