--- /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