diff -Naur mozilla.orig/config/autoconf.mk.in mozilla/config/autoconf.mk.in --- mozilla.orig/config/autoconf.mk.in 2008-03-18 10:37:00.000000000 -0700 +++ mozilla/config/autoconf.mk.in 2008-04-10 11:33:28.000000000 -0700 @@ -246,6 +246,7 @@ MOZ_GNOMEVFS_CFLAGS = @MOZ_GNOMEVFS_CFLAGS@ MOZ_GNOMEVFS_LIBS = @MOZ_GNOMEVFS_LIBS@ +MOZ_ENABLE_GCONF = @MOZ_ENABLE_GCONF@ MOZ_GCONF_CFLAGS = @MOZ_GCONF_CFLAGS@ MOZ_GCONF_LIBS = @MOZ_GCONF_LIBS@ diff -Naur mozilla.orig/configure.in mozilla/configure.in --- mozilla.orig/configure.in 2008-03-20 12:17:09.000000000 -0700 +++ mozilla/configure.in 2008-04-10 11:39:22.000000000 -0700 @@ -4957,6 +4957,7 @@ ]) fi + AC_SUBST(MOZ_ENABLE_GCONF) AC_SUBST(MOZ_GCONF_CFLAGS) AC_SUBST(MOZ_GCONF_LIBS) diff -Naur mozilla.orig/extensions/pref/system-pref/src/gconf/Makefile.in mozilla/extensions/pref/system-pref/src/gconf/Makefile.in --- mozilla.orig/extensions/pref/system-pref/src/gconf/Makefile.in 2006-04-28 07:54:52.000000000 -0700 +++ mozilla/extensions/pref/system-pref/src/gconf/Makefile.in 2008-04-01 16:50:49.000000000 -0700 @@ -42,45 +42,37 @@ include $(DEPTH)/config/autoconf.mk -MODULE = system-pref -LIBRARY_NAME = system-pref +MODULE = syspref-gconf +MODULE_NAME = nsSystemPrefServiceModule +LIBRARY_NAME = syspref-gconf +ifneq ($(OS_ARCH),WINNT) +SHORT_LIBNAME = spgconf +endif + +EXPORT_LIBRARY = 1 +IS_COMPONENT = 1 +FORCE_STATIC_LIB = 1 LIBXUL_LIBRARY = 1 REQUIRES = pref \ + system-pref \ string \ xpcom \ embedcomponents \ + necko \ $(NULL) CPPSRCS = \ nsSystemPrefService.cpp \ - nsSystemPrefFactory.cpp \ $(NULL) -SHARED_LIBRARY_LIBS = ../libsystem-pref_s.a - EXTRA_DSO_LDOPTS = \ - -L$(DIST)/bin \ $(MOZ_COMPONENT_LIBS) \ - $(MOZ_GTK2_LIBS) \ - $(NULL) - -EXPORT_LIBRARY = 1 -IS_COMPONENT = 1 -MODULE_NAME = nsSystemPrefModule - -EXPORTS = \ - nsSystemPrefService.h \ + $(MOZ_GTK2_LIBS) \ + $(MOZ_GCONF_LIBS) \ $(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 +CFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_GCONF_CFLAGS) +CXXFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_GCONF_CFLAGS) diff -Naur mozilla.orig/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp mozilla/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp --- mozilla.orig/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp 2007-07-08 00:08:21.000000000 -0700 +++ mozilla/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp 2008-04-01 16:50:49.000000000 -0700 @@ -23,7 +23,7 @@ * * 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 @@ -41,6 +41,7 @@ #include #include +#include #include "plstr.h" #include "nsCOMPtr.h" @@ -48,867 +49,1270 @@ #include "nsIServiceManager.h" #include "nsIObserver.h" #include "nsWeakReference.h" - +#include "nsIPrefBranch2.h" +#include "nsISystemPrefService.h" +#include "nsDataHashtable.h" +#include "nsHashKeys.h" +#include "nsICategoryManager.h" +#include "nsIGenericFactory.h" #include "nsString.h" -#include "nsSystemPrefLog.h" -#include "nsSystemPrefService.h" - -/************************************************************************* - * 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. - ************************************************************************/ - -//gconf types -extern "C" { - - typedef enum { - GCONF_VALUE_INVALID, - GCONF_VALUE_STRING, - GCONF_VALUE_INT, - GCONF_VALUE_FLOAT, - GCONF_VALUE_BOOL, - GCONF_VALUE_SCHEMA, - - GCONF_VALUE_LIST, - GCONF_VALUE_PAIR - - }GConfValueType; - - typedef struct { - GConfValueType type; - }GConfValue; - - 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); - - typedef const char* (*GConfEntryGetKeyType) (const void *entry); - typedef GConfValue* (*GConfEntryGetValueType) (const void *entry); - - typedef const char* (*GConfValueGetStringType) (const GConfValue *value); - typedef PRInt32 (*GConfValueGetIntType) (const GConfValue *value); - typedef PRBool (*GConfValueGetBoolType) (const GConfValue *value); +#include "nsIPermissionManager.h" - - static void gconf_key_listener (void* client, guint cnxn_id, - void *entry, gpointer user_data); -} +#define NS_SYSTEMPREF_SERVICE_CID \ + { /* {3724e748-b088-4bf8-9298-aad426b66293} */ \ + 0x3724e748, \ + 0xb088, \ + 0x4bf8, \ + { 0x92, 0x98, 0xaa, 0xd4, 0x26, 0xb6, 0x62, 0x93 } \ + } + +#define NS_SYSTEMPREF_SERVICE_CLASSNAME "System Preferences Platform Service" + +/** + * 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. + */ + +#define NUM_ELEM(a) (sizeof(a)/sizeof(a[0])) + +class nsSystemPrefService; + +/** + * 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; +}; -struct GConfCallbackData -{ - GConfProxy *proxy; - void * userData; - PRUint32 atom; - PRUint32 notifyId; +struct ComplexMozPrefMapping { + const char* mozPrefName; + ComplexMozPrefChanged callback; }; -////////////////////////////////////////////////////////////////////// -// 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 + +class nsSystemPrefService : public nsISystemPrefService { public: - GConfProxy(nsSystemPrefService* aSysPrefService); - ~GConfProxy(); - PRBool Init(); - - nsresult GetBoolPref(const char *aMozKey, PRBool *retval); - nsresult GetCharPref(const char *aMozKey, char **retval); - nsresult GetIntPref(const char *aMozKey, PRInt32 *retval); + NS_DECL_ISUPPORTS - nsresult NotifyAdd (PRUint32 aAtom, void *aUserData); - nsresult NotifyRemove (PRUint32 aAtom, const void *aUserData); + nsresult Init(); - nsresult GetAtomForMozKey(const char *aMozKey, PRUint32 *aAtom) { - return GetAtom(aMozKey, 0, aAtom); - } - const char *GetMozKey(PRUint32 aAtom) { - return GetKey(aAtom, 0); + virtual nsresult LoadSystemPreferences(nsISystemPref* aPrefs); + virtual nsresult NotifyMozillaPrefChanged(const char* aPrefName); + virtual nsresult NotifyUnloadSystemPreferences(); + + nsSystemPrefService(); + virtual ~nsSystemPrefService(); + + nsISystemPref* GetPrefs() { return mPref; } + SimplePrefMapping* GetSimpleCallbackData(PRUint32 aKey) { + SimplePrefMapping* result = nsnull; + mGConfSimpleCallbacks.Get(aKey, &result); + return result; + } + ComplexGConfPrefMapping* GetComplexCallbackData(PRUint32 aKey) { + ComplexGConfPrefMapping* result = nsnull; + mGConfComplexCallbacks.Get(aKey, &result); + return result; } - void OnNotify(void *aClient, void * aEntry, PRUint32 aNotifyId, - GConfCallbackData *aData); - private: - void *mGConfClient; - PRLibrary *mGConfLib; - PRBool mInitialized; - nsSystemPrefService *mSysPrefService; - - //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[]; + nsISystemPref* mPref; + nsDataHashtable mGConfSimpleCallbacks; + nsDataHashtable mGConfComplexCallbacks; + // This is set to PR_FALSE temporarily to stop listening to gconf + // change notifications (while we change gconf values) + PRPackedBool mListenToGConf; }; -struct SysPrefCallbackData { - nsISupports *observer; - PRBool bIsWeakRef; - PRUint32 prefAtom; -}; - -PRBool PR_CALLBACK -sysPrefDeleteObserver(void *aElement, void *aData) { - SysPrefCallbackData *pElement = - static_cast(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; - } - - SYSPREF_LOG(("Init SystemPref Service\n")); - if (mInitialized) - return NS_ERROR_FAILURE; - - if (!mGConf) { - mGConf = new GConfProxy(this); - if (!mGConf->Init()) { - delete mGConf; - mGConf = nsnull; - return NS_ERROR_FAILURE; - } - } - - mInitialized = PR_TRUE; return NS_OK; } -/* readonly attribute string root; */ -NS_IMETHODIMP nsSystemPrefService::GetRoot(char * *aRoot) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} +NS_IMPL_ISUPPORTS1(nsSystemPrefService, nsISystemPrefService) -/* long getPrefType (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::GetPrefType(const char *aPrefName, PRInt32 *_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; +static GConfClient* GetGConf() { + return gconf_client_get_default(); } -/* boolean getBoolPref (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::GetBoolPref(const char *aPrefName, PRBool *_retval) +static PRBool VerifyMatchingTypes(nsISystemPref* aPrefs, + const char* aMozPref, GConfValue* aVal) { - return mInitialized ? - mGConf->GetBoolPref(aPrefName, _retval) : NS_ERROR_FAILURE; -} + nsCOMPtr 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; + } -/* void setBoolPref (in string aPrefName, in long aValue); */ -NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRInt32 aValue) -{ - return NS_ERROR_NOT_IMPLEMENTED; + 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; } -/* string getCharPref (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::GetCharPref(const char *aPrefName, char **_retval) -{ - return mInitialized ? - mGConf->GetCharPref(aPrefName, _retval) : NS_ERROR_FAILURE; -} +/** + * 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; + } -/* void setCharPref (in string aPrefName, in string aValue); */ -NS_IMETHODIMP nsSystemPrefService::SetCharPref(const char *aPrefName, const char *aValue) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} + VerifyMatchingTypes(aPrefs, aMap->mozPrefName, val); -/* long getIntPref (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::GetIntPref(const char *aPrefName, PRInt32 *_retval) -{ - return mInitialized ? - mGConf->GetIntPref(aPrefName, _retval) : NS_ERROR_FAILURE; -} + 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; + } -/* void setIntPref (in string aPrefName, in long aValue); */ -NS_IMETHODIMP nsSystemPrefService::SetIntPref(const char *aPrefName, PRInt32 aValue) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} + nsCOMPtr 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; + } -/* 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; -} + switch (type) { + case nsIPrefBranch2::PREF_STRING: + { + char* result; + rv = prefBranch->GetCharPref(aMap->mozPrefName, &result); + if (NS_FAILED(rv)) + return rv; -/* 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; -} + 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; -/* void clearUserPref (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::ClearUserPref(const char *aPrefName) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} + 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; -/* void lockPref (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::LockPref(const char *aPrefName) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} + gconf_client_set_bool(aClient, aMap->gconfPrefName, result, nsnull); + } + break; + default: + NS_ERROR("Unhandled gconf preference type"); + return NS_ERROR_FAILURE; + } -/* boolean prefHasUserValue (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::PrefHasUserValue(const char *aPrefName, PRBool *_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; + return NS_OK; } -/* boolean prefIsLocked (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::PrefIsLocked(const char *aPrefName, PRBool *_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} +/* 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 proxy settings; allow these to be set through the Firefox UI + {"network.proxy.http", "/system/http_proxy/host", PR_TRUE}, + {"network.proxy.http_port", "/system/http_proxy/port", PR_TRUE}, + {"network.proxy.ftp", "/system/proxy/ftp_host", PR_TRUE}, + {"network.proxy.ftp_port", "/system/proxy/ftp_port", PR_TRUE}, + {"network.proxy.ssl", "/system/proxy/secure_host", PR_TRUE}, + {"network.proxy.ssl_port", "/system/proxy/secure_port", PR_TRUE}, + {"network.proxy.socks", "/system/proxy/socks_host", PR_TRUE}, + {"network.proxy.socks_port", "/system/proxy/socks_port", PR_TRUE}, + {"network.proxy.autoconfig_url", "/system/proxy/autoconfig_url", PR_TRUE}, + + // 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}, +}; -/* void unlockPref (in string aPrefName); */ -NS_IMETHODIMP nsSystemPrefService::UnlockPref(const char *aPrefName) -{ - return NS_ERROR_NOT_IMPLEMENTED; +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 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)) { + gconf_client_set_list(aClient, aGConfKey, GCONF_VALUE_STRING, list, nsnull); + } + for (GSList* l = list; l; l = l->next) { + free(l->data); + } + g_slist_free(list); + return rv; } -/* void deleteBranch (in string aStartingAt); */ -NS_IMETHODIMP nsSystemPrefService::DeleteBranch(const char *aStartingAt) +/** + * 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 + * "network.proxy.no_proxies_on" is the comma-separated concatenation + * of the elements of the list "/system/http_proxy/ignore_hosts" + */ +static const char GConfKey_IgnoreHosts[] = "/system/http_proxy/ignore_hosts"; +static const char MozKey_IgnoreHosts[] = "network.proxy.no_proxies_on"; +static nsresult ApplyIgnoreHosts(nsSystemPrefService* aPrefService, + GConfClient* aClient) +{ + return ApplyListPref(aPrefService, aClient, + GConfKey_IgnoreHosts, MozKey_IgnoreHosts, ','); +} +static nsresult ReverseApplyIgnoreHosts(nsSystemPrefService* aPrefService, + GConfClient* aClient) +{ + return ReverseApplyListPref(aPrefService, aClient, + GConfKey_IgnoreHosts, MozKey_IgnoreHosts, ','); +} + +/** + * The relationship R is + * ("/system/proxy/mode" is 'manual' if and only if "network.proxy.type" is eProxyConfig_Manual (1)) + * AND ("/system/proxy/mode" is 'auto' if and only if "network.proxy.type" is eProxyConfig_PAC (2)) + * + * [This means 'none' matches any value of "network.proxy.type" other than 1 or 2.] + */ +static const char GConfKey_ProxyMode[] = "/system/proxy/mode"; +static const char MozKey_ProxyMode[] = "network.proxy.type"; +static nsresult ApplyProxyMode(nsSystemPrefService* aPrefService, + GConfClient* aClient) { - return NS_ERROR_NOT_IMPLEMENTED; + char* str = gconf_client_get_string(aClient, GConfKey_ProxyMode, nsnull); + if (!str) + return NS_ERROR_FAILURE; + PRInt32 val = -1; + nsCOMPtr prefs = + aPrefService->GetPrefs()->GetPrefUserBranch(); + prefs->GetIntPref(MozKey_ProxyMode, &val); + if (val < 0) + return NS_ERROR_FAILURE; + if (!strcmp(str, "manual")) { + val = 1; + } else if (!strcmp(str, "auto")) { + val = 2; + } else if (strcmp(str, "none")) { + // invalid value for this gconf pref; do nothing + g_free(str); + return NS_OK; + } else { + if (val == 1 || val == 2) { + // We need to make it something that 'none' maps to + val = 0; + } + } + g_free(str); + PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_ProxyMode, nsnull); + nsresult rv = aPrefService->GetPrefs()-> + SetOverridingMozillaIntPref(MozKey_ProxyMode, val, lock); + return rv; +} +static nsresult ReverseApplyProxyMode(nsSystemPrefService* aPrefService, + GConfClient* aClient) +{ + PRInt32 val = -1; + nsCOMPtr prefs = + aPrefService->GetPrefs()->GetPrefUserBranch(); + prefs->GetIntPref(MozKey_ProxyMode, &val); + if (val < 0) + return NS_ERROR_FAILURE; + const char* str; + switch (val) { + case 1: str = "manual"; break; + case 2: str = "auto"; break; + default: str = "none"; break; + } + gconf_client_set_string(aClient, GConfKey_ProxyMode, str, nsnull); + return NS_OK; } -/* 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) +/** + * 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) { - return NS_ERROR_NOT_IMPLEMENTED; + 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; } -/* void resetBranch (in string aStartingAt); */ -NS_IMETHODIMP nsSystemPrefService::ResetBranch(const char *aStartingAt) -{ - return NS_ERROR_NOT_IMPLEMENTED; +static nsresult ReverseApplyDownloadFolder(nsSystemPrefService* aPrefService, + GConfClient* aClient) +{ + PRBool useDownloadDir = PR_FALSE; + const char* result; + char* explicitStr = nsnull; + nsCOMPtr 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 = "My 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; + gconf_client_set_string(aClient, GConfKey_DownloadFolder, + result, nsnull); + nsMemory::Free(explicitStr); + return NS_OK; } -/* 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); - - NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE); - - 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 observerRef; - if (aHoldWeak) { - nsCOMPtr 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 tmp = do_GetWeakReference(weakRefFactory); - observerRef = tmp; +/** + * 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 prefs = + aPrefService->GetPrefs()->GetPrefUserBranch(); + prefs->GetIntPref(MozKey_CookieBehavior, &behavior); + if (behavior < 0) + return NS_ERROR_FAILURE; + if (disable) { + behavior = 2; } else { - observerRef = aObserver; + 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 prefs = + aPrefService->GetPrefs()->GetPrefUserBranch(); + prefs->GetIntPref(MozKey_CookieBehavior, &behavior); + if (behavior < 0) + return NS_ERROR_FAILURE; + gconf_client_set_bool(aClient, GConfKey_DisableCookies, behavior == 2, nsnull); + return NS_OK; +} - rv = mGConf->NotifyAdd(prefAtom, pCallbackData); - if (NS_FAILED(rv)) { - nsMemory::Free(pCallbackData); - return rv; +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 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; } - - 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) +static nsresult ReverseApplyWindowOpen(nsSystemPrefService* aPrefService, + GConfClient* aClient) { - 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 observerRef; - if (pCallbackData->bIsWeakRef) { - nsCOMPtr weakRefFactory = - do_QueryInterface(aObserver); - if (weakRefFactory) { - nsCOMPtr 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; - } + nsCOMPtr 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; } } + gconf_client_set_bool(aClient, GConfKey_DisableJSChrome, allDisabled, nsnull); return NS_OK; } -void -nsSystemPrefService::OnPrefChange(PRUint32 aPrefAtom, void *aData) -{ - if (!mInitialized) - return; +/** + * 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 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 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; +} - SysPrefCallbackData *pData = (SysPrefCallbackData *)aData; - if (pData->prefAtom != aPrefAtom) - return; +struct ProtocolPrefClosure { + StringSet safeProtocolSet; + nsIPrefBranch2* prefs; + nsISystemPref* prefSetter; + PRPackedBool disableUnsafe; + PRPackedBool lock; +}; - nsCOMPtr observer; - if (pData->bIsWeakRef) { - nsCOMPtr 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); +static PLDHashOperator PR_CALLBACK SetProtocolPref(const nsACString& aKey, + int aItem, + void* aClosure) +{ + ProtocolPrefClosure* closure = static_cast(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 prefs = aPrefService->GetPrefs()->GetPrefUserBranch(); + closure.prefs = prefs; + protocolSet.EnumerateRead(SetProtocolPref, &closure); + } + g_free(protocols); + return rv; +} + +static nsresult ReverseApplyUnsafeProtocols(nsSystemPrefService* aPrefService, + GConfClient* aClient) +{ + nsCOMPtr 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(','); } - return; + enabledProtocols.Append(childArray[i] + NUM_ELEM(MozKey_BlockedPrefix)-1); } } - else - observer = do_QueryInterface(pData->observer); + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray); + gconf_client_set_bool(aClient, GConfKey_DisableUnsafeProtocols, blockedDefault, nsnull); + gconf_client_set_string(aClient, GConfKey_AdditionalSafeProtocols, + enabledProtocols.get(), nsnull); + return NS_OK; +} - if (observer) - observer->Observe(static_cast(this), - NS_SYSTEMPREF_PREFCHANGE_TOPIC_ID, - NS_ConvertUTF8toUTF16(mGConf->GetMozKey(aPrefAtom)). - get()); +/** + * 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 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; } -/************************************************************* - * GConfProxy +/** + * 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 * - ************************************************************/ - -struct GConfFuncListType { - const char *FuncName; - PRFuncPtr FuncPtr; -}; - -struct PrefNamePair { - const char *mozPrefName; - const char *gconfPrefName; -}; - -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 PR_CALLBACK -gconfDeleteObserver(void *aElement, void *aData) { - nsMemory::Free(aElement); - return PR_TRUE; + * 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); } -GConfProxy::GConfProxy(nsSystemPrefService *aSysPrefService): - mGConfClient(nsnull), - mGConfLib(nsnull), - mInitialized(PR_FALSE), - mSysPrefService(aSysPrefService), - mObservers(nsnull) +static nsresult ReverseApplyLoadImages(nsSystemPrefService* aPrefService, + GConfClient* aClient) { + nsCOMPtr 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; + } + gconf_client_set_int(aClient, GConfKey_LoadImages, setting, nsnull); + return NS_OK; } -GConfProxy::~GConfProxy() +/** + * 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) { - if (mGConfClient) - g_object_unref(G_OBJECT(mGConfClient)); + nsCOMPtr prefs = aPrefService->GetPrefs()->GetPrefUserBranch(); + PRBool disabled; + nsresult rv = prefs->GetBoolPref(MozKey_DisablePopups, &disabled); + if (NS_FAILED(rv)) + return rv; + gconf_client_set_bool(aClient, GConfKey_DisablePopups, disabled, nsnull); + return NS_OK; +} - if (mObservers) { - (void)mObservers->EnumerateForwards(gconfDeleteObserver, nsnull); - delete mObservers; - } +static ComplexGConfPrefMapping sComplexGConfPrefMappings[] = { + {GConfKey_TrustedURIs, ApplyTrustedURIs}, + {GConfKey_DelegationURIs, ApplyDelegationURIs}, + {GConfKey_IgnoreHosts, ApplyIgnoreHosts}, + {GConfKey_ProxyMode, ApplyProxyMode}, + {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_IgnoreHosts, ReverseApplyIgnoreHosts}, + {MozKey_ProxyMode, ReverseApplyProxyMode}, + {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. + +static PR_CALLBACK void GConfSimpleNotification(GConfClient* client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + nsSystemPrefService* service = static_cast(user_data); + SimplePrefMapping* map = static_cast( + service->GetSimpleCallbackData(cnxn_id)); + NS_ASSERTION(map, "Can't find mapping for callback"); + if (!map) + return; - // bug 379666: can't unload GConf-2 since it registers atexit handlers - //PR_UnloadLibrary(mGConfLib); + ApplySimpleMapping(map, service->GetPrefs(), client); } -PRBool -GConfProxy::Init() -{ - SYSPREF_LOG(("GConfProxy:: Init GConfProxy\n")); - if (!mSysPrefService) - return PR_FALSE; - if (mInitialized) - return PR_TRUE; +static PR_CALLBACK void GConfComplexNotification(GConfClient* client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + nsSystemPrefService* service = static_cast(user_data); + ComplexGConfPrefMapping* map = static_cast( + service->GetComplexCallbackData(cnxn_id)); + NS_ASSERTION(map, "Can't find mapping for callback"); + if (!map) + return; - nsCOMPtr pref = do_GetService(NS_PREF_CONTRACTID); - if (!pref) - return PR_FALSE; + map->callback(service, GetGConf()); +} - nsXPIDLCString gconfLibName; - nsresult rv; +static const char GConfKey_Homepage_Url[] = + "/apps/firefox/general/homepage_url"; - //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); +nsresult nsSystemPrefService::LoadSystemPreferences(nsISystemPref* aPrefs) +{ + mPref = aPrefs; + + GConfClient* client = GetGConf(); + PRUint32 i; + nsCOMPtr userPrefs = aPrefs->GetPrefUserBranch(); + + // Update gconf settings with any Mozilla settings that have + // changed from the default. Do it before we register our + // gconf notifications. + 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 && + gconf_client_key_is_writable(client, + sSimplePrefMappings[i].gconfPrefName, + nsnull)) { + rv = ReverseApplySimpleMapping(&sSimplePrefMappings[i], + aPrefs, client); + if (NS_FAILED(rv)) + return rv; + } } - - if (!mGConfLib) { - SYSPREF_LOG(("Fail to load GConf library\n")); - return PR_FALSE; + 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; + } + } } - - //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; + + // 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; + } + + 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; } - 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 (!gconf_client_get(client, GConfKey_DisablePopups, nsnull)) + { + gconf_client_set_bool(client, GConfKey_DisablePopups, true, nsnull); + } - if (!mGConfClient) { - SYSPREF_LOG(("Fail to Get default gconf client\n")); - goto init_failed; + if (!gconf_client_get(client, GConfKey_Homepage_Url, nsnull)) + { + gconf_client_set_string(client, GConfKey_Homepage_Url, "", nsnull); } - mInitialized = PR_TRUE; - return PR_TRUE; - init_failed_unload: - PR_UnloadLibrary(mGConfLib); - init_failed: - mGConfLib = nsnull; - return PR_FALSE; -} + ApplyUnsafeProtocols(this, client); -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) +nsresult nsSystemPrefService::NotifyMozillaPrefChanged(const char* aPrefName) { - 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); + PRUint32 i; + GConfClient* client = GetGConf(); - for (s = gslist; s; s = g_slist_next(s)) { - noproxy += (char *)s->data; - noproxy += ", "; - g_free ((char *)s->data); + for (i = 0; i < NUM_ELEM(sSimplePrefMappings); ++i) { + if (!strcmp(aPrefName, sSimplePrefMappings[i].mozPrefName)) { + ReverseApplySimpleMapping(&sSimplePrefMappings[i], + mPref, client); } - 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); + for (i = 0; i < NUM_ELEM(sComplexMozPrefMappings); ++i) { + if (!strcmp(aPrefName, sComplexMozPrefMappings[i].mozPrefName)) { + sComplexMozPrefMappings[i].callback(this, client); } } - 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); + for (i = 0; i < NUM_ELEM(windowOpenFeatures); ++i) { + if (!strcmp(aPrefName, windowOpenFeatures[i])) { + ReverseApplyWindowOpen(this, client); + } } + ReverseApplyUnsafeProtocols(this, client); + return NS_OK; } -nsresult -GConfProxy::NotifyAdd (PRUint32 aAtom, void *aUserData) +static PLDHashOperator PR_CALLBACK UnregisterSimple(const PRUint32& aKey, + SimplePrefMapping* aData, + void* aClosure) { - 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; + GConfClient* client = GetGConf(); + gconf_client_notify_remove(client, aKey); + gconf_client_remove_dir(client, aData->gconfPrefName, nsnull); + return PL_DHASH_NEXT; } -nsresult -GConfProxy::NotifyRemove (PRUint32 aAtom, const void *aUserData) +static PLDHashOperator PR_CALLBACK UnregisterComplex(const PRUint32& aKey, + ComplexGConfPrefMapping* aData, + void* aClosure) { - 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; + GConfClient* client = GetGConf(); + gconf_client_notify_remove(client, aKey); + gconf_client_remove_dir(client, aData->gconfPrefName, nsnull); + return PL_DHASH_NEXT; } -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) +nsresult nsSystemPrefService::NotifyUnloadSystemPreferences() { - if (!mInitialized || !aEntry || (mGConfClient != aClient) || !aData) - return; - - if (GConfEntryGetValue(aEntry) == NULL) - return; + // Unregister callbacks + mGConfSimpleCallbacks.EnumerateRead(UnregisterSimple, this); + mGConfSimpleCallbacks.Clear(); + mGConfComplexCallbacks.EnumerateRead(UnregisterComplex, this); + mGConfComplexCallbacks.Clear(); - PRUint32 prefAtom; - nsresult rv = GetAtomForGConfKey(GConfEntryGetKey(aEntry), &prefAtom); - if (NS_FAILED(rv)) - return; - - mSysPrefService->OnPrefChange(prefAtom, aData->userData); + return NS_OK; } -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; -} +// Factory stuff -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; -} +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPrefService, Init) -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 const nsModuleComponentInfo components[] = { + { NS_SYSTEMPREF_SERVICE_CLASSNAME, + NS_SYSTEMPREF_SERVICE_CID, + NS_SYSTEMPREF_SERVICE_CONTRACTID, + nsSystemPrefServiceConstructor, + }, +}; -/* 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 - (user_data); - pData->proxy->OnNotify(client, entry, cnxn_id, pData); -} +NS_IMPL_NSGETMODULE(nsSystemPrefServiceModule, components) diff -Naur mozilla.orig/extensions/pref/system-pref/src/gconf/nsSystemPrefService.h mozilla/extensions/pref/system-pref/src/gconf/nsSystemPrefService.h --- mozilla.orig/extensions/pref/system-pref/src/gconf/nsSystemPrefService.h 2005-02-23 08:15:37.000000000 -0800 +++ mozilla/extensions/pref/system-pref/src/gconf/nsSystemPrefService.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,93 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:expandtab:shiftwidth=4:tabstop=4: - */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 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 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): - * - * 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 __SYSTEM_PREF_SERVICE_H__ -#define __SYSTEM_PREF_SERVICE_H__ - -#include "prlink.h" -#include "nsVoidArray.h" -#include "nsWeakPtr.h" -#include "nsIPrefBranch.h" -#include "nsIPrefBranch2.h" - -class GConfProxy; - -//////////////////////////////////////////////////////////////////////////// -// nsSystemPrefService provide a interface for read system prefs. It is -// platform related. This directory (system-pref/gconf) impls it for gconf -// on the gconf platform. -//////////////////////////////////////////////////////////////////////////// - -class nsSystemPrefService : public nsIPrefBranch2 -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIPREFBRANCH - NS_DECL_NSIPREFBRANCH2 - - nsSystemPrefService(); - virtual ~nsSystemPrefService(); - nsresult Init(); - - void OnPrefChange(PRUint32 aPrefAtom, void *aData); - -private: - PRBool mInitialized; - GConfProxy *mGConf; - - //listeners - nsAutoVoidArray *mObservers; -}; - -#define NS_SYSTEMPREF_SERVICE_CID \ - { /* {94f1de09-d0e5-4ca8-94c2-98b049316b7f} */ \ - 0x94f1de09, \ - 0xd0e5, \ - 0x4ca8, \ - { 0x94, 0xc2, 0x98, 0xb0, 0x49, 0x31, 0x6b, 0x7f } \ - } - -#define NS_SYSTEMPREF_SERVICE_CONTRACTID "@mozilla.org/system-preference-service;1" -#define NS_SYSTEMPREF_SERVICE_CLASSNAME "System Preferences Service" - -#define NS_SYSTEMPREF_PREFCHANGE_TOPIC_ID "nsSystemPrefService:pref-changed" - -#endif /* __SYSTEM_PREF_SERVICE_H__ */ diff -Naur mozilla.orig/extensions/pref/system-pref/src/Makefile.in mozilla/extensions/pref/system-pref/src/Makefile.in --- mozilla.orig/extensions/pref/system-pref/src/Makefile.in 2005-12-31 04:14:42.000000000 -0800 +++ mozilla/extensions/pref/system-pref/src/Makefile.in 2008-04-01 16:50:49.000000000 -0700 @@ -43,12 +43,14 @@ include $(DEPTH)/config/autoconf.mk MODULE = system-pref -LIBRARY_NAME = system-pref_s +MODULE_NAME = nsSystemPrefModule +LIBRARY_NAME = system-pref ifneq ($(OS_ARCH),WINNT) SHORT_LIBNAME = syspref endif -# We want to force the creation of a static lib. +IS_COMPONENT = 1 +EXPORT_LIBRARY = 1 FORCE_STATIC_LIB = 1 LIBXUL_LIBRARY = 1 @@ -58,27 +60,22 @@ pref \ $(NULL) -ifdef MOZ_ENABLE_GTK2 +ifdef MOZ_ENABLE_GCONF DIRS = gconf endif -EXTRA_DSO_LDOPTS = \ - -L$(DIST)/bin \ - $(MOZ_COMPONENT_LIBS) \ - $(NULL) - CPPSRCS = \ nsSystemPref.cpp \ + nsSystemPrefFactory.cpp \ $(NULL) +EXTRA_DSO_LDOPTS = \ + $(MOZ_COMPONENT_LIBS) \ + $(NULL) + EXPORTS = \ - nsSystemPrefLog.h \ + nsISystemPrefService.h \ $(NULL) -include $(topsrcdir)/config/rules.mk -ifdef MOZ_ENABLE_GTK2 -INCLUDES += \ - -I$(srcdir)/gconf \ - $(NULL) -endif +include $(topsrcdir)/config/rules.mk diff -Naur mozilla.orig/extensions/pref/system-pref/src/nsISystemPrefService.h mozilla/extensions/pref/system-pref/src/nsISystemPrefService.h --- mozilla.orig/extensions/pref/system-pref/src/nsISystemPrefService.h 1969-12-31 16:00:00.000000000 -0800 +++ mozilla/extensions/pref/system-pref/src/nsISystemPrefService.h 2008-04-01 16:50:49.000000000 -0700 @@ -0,0 +1,109 @@ +/* -*- 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-preferences-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 GetPrefUserBranch() = 0; + virtual already_AddRefed 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; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsISystemPrefService, NS_ISYSTEMPREFSERVICE_IID) + +#endif diff -Naur mozilla.orig/extensions/pref/system-pref/src/nsSystemPref.cpp mozilla/extensions/pref/system-pref/src/nsSystemPref.cpp --- mozilla.orig/extensions/pref/system-pref/src/nsSystemPref.cpp 2006-04-17 15:03:46.000000000 -0700 +++ mozilla/extensions/pref/system-pref/src/nsSystemPref.cpp 2008-04-01 16:50:49.000000000 -0700 @@ -24,6 +24,7 @@ * 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 @@ -41,66 +42,60 @@ #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 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", -}; +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; } /////////////////////////////////////////////////////////////////////////////// @@ -131,6 +126,54 @@ return(rv); } +already_AddRefed +nsSystemPref::GetPrefUserBranch() +{ + if (mCachedUserPrefBranch) { + NS_ADDREF(mCachedUserPrefBranch); + return mCachedUserPrefBranch; + } + + nsresult rv; + nsCOMPtr prefService = + do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return nsnull; + nsCOMPtr prefBranch; + rv = prefService->GetBranch(nsnull, getter_AddRefs(prefBranch)); + if (NS_FAILED(rv)) + return nsnull; + nsCOMPtr pb2(do_QueryInterface(prefBranch)); + if (!pb2) + return nsnull; + + nsIPrefBranch2* result = nsnull; + pb2.swap(result); + return result; +} + +already_AddRefed +nsSystemPref::GetPrefDefaultBranch() +{ + if (mCachedDefaultPrefBranch) { + NS_ADDREF(mCachedDefaultPrefBranch); + return mCachedDefaultPrefBranch; + } + + nsresult rv; + nsCOMPtr prefService = + do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return nsnull; + nsCOMPtr 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) @@ -145,330 +188,438 @@ if (!aTopic) return NS_OK; - // if we are notified by pref service - // check the system pref settings + nsCOMPtr userBranch = GetPrefUserBranch(); + PRBool 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 prefBranch = - do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return rv; - - rv = prefBranch->GetBoolPref(sSysPrefString, &mEnabled); + // 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(("...FAil to Get %s\n", sSysPrefString)); + SYSPREF_LOG(("...Failed to add observer for %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")); + 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; } - // 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 prefBranch = - do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + rv = LoadSystemPrefs(); 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. Really this should already be locked because if it's + // not locked at a lower level the user can set it to false in + // their in prefs.js. But only do this if the value was not + // specially set by the user; if it was set by the user, then + // locking it would actually unset the value! And the user + // should be allowed to turn off something they set + // themselves. + PRBool hasUserValue; + rv = userBranch->PrefHasUserValue(sSysPrefString, &hasUserValue); + if (NS_SUCCEEDED(rv) && !hasUserValue) { + 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()); - 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)); - return rv; -} + 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(); + } -/* private */ + // didn't change? + return NS_OK; + } -//////////////////////////////////////////////////////////////// -// nsSystemPref::UseSystemPrefs -// Read all the prefs in the table from system, listen for their -// changes in system pref service. -//////////////////////////////////////////////////////////////// -nsresult -nsSystemPref::UseSystemPrefs() -{ - SYSPREF_LOG(("\n====Now Use system prefs==\n")); - nsresult rv = NS_OK; - if (!mSysPrefService) { - return NS_ERROR_FAILURE; + 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; } - PRIntn sysPrefCount= sizeof(sSysPrefList) / sizeof(sSysPrefList[0]); + if (!nsCRT::strcmp(aTopic,"profile-before-change")) + return RestoreMozillaPrefs(); - 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]); - } + SYSPREF_LOG(("Not needed topic Received %s\n", aTopic)); - for (PRIntn index = 0; index < sysPrefCount; ++index) { - // save mozilla prefs - SaveMozDefaultPref(mSysPrefs[index].prefName, - &mSysPrefs[index].defaultValue, - &mSysPrefs[index].isLocked); - - // 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); - } return rv; } -////////////////////////////////////////////////////////////////////// -// nsSystemPref::ReadSystemPref -// Read a pref value from system pref service, and lock it in mozilla. -////////////////////////////////////////////////////////////////////// nsresult -nsSystemPref::ReadSystemPref(const char *aPrefName) +nsSystemPref::SetOverridingMozillaBoolPref(const char* aPrefName, + PRBool aValue, PRBool aLock, PRBool aPresent) { - if (!mSysPrefService) - return NS_ERROR_FAILURE; - nsresult rv; - - nsCOMPtr prefBranch - (do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); - if (NS_FAILED(rv)) - return rv; - - SYSPREF_LOG(("about to read aPrefName %s\n", aPrefName)); + return OverridePref(aPrefName, nsIPrefBranch::PREF_BOOL, + (void*)aValue, aLock, aPresent); +} - prefBranch->UnlockPref(aPrefName); +nsresult +nsSystemPref::SetOverridingMozillaIntPref(const char* aPrefName, + PRInt32 aValue, PRBool aLock, PRBool aPresent) +{ + return OverridePref(aPrefName, nsIPrefBranch::PREF_INT, + (void*)aValue, aLock, aPresent); +} - PRInt32 prefType = nsIPrefBranch::PREF_INVALID; - nsXPIDLCString strValue; - PRInt32 intValue = 0; - PRBool boolValue = PR_FALSE; +nsresult +nsSystemPref::SetOverridingMozillaStringPref(const char* aPrefName, + const char* aValue, PRBool aLock, PRBool aPresent) +{ + return OverridePref(aPrefName, nsIPrefBranch::PREF_STRING, + (void*)aValue, aLock, aPresent); +} - rv = prefBranch->GetPrefType(aPrefName, &prefType); - if (NS_FAILED(rv)) - return rv; - switch (prefType) { +static nsresult RestorePrefValue(PRInt32 aPrefType, + const char* aPrefName, + SysPrefItem* aItem, + nsIPrefBranch* aUser, + nsIPrefBranch* aDefault) +{ + switch (aPrefType) { case nsIPrefBranch::PREF_STRING: - mSysPrefService->GetCharPref(aPrefName, getter_Copies(strValue)); - SYSPREF_LOG(("system value is %s\n", strValue.get())); - - prefBranch->SetCharPref(aPrefName, strValue.get()); + aDefault->SetCharPref(aPrefName, + aItem->savedDefaultValueString); + if (aItem->savedUserPresent) { + aUser->SetCharPref(aPrefName, aItem->savedUserValueString); + } break; case nsIPrefBranch::PREF_INT: - mSysPrefService->GetIntPref(aPrefName, &intValue); - SYSPREF_LOG(("system value is %d\n", intValue)); - - prefBranch->SetIntPref(aPrefName, intValue); + aDefault->SetIntPref(aPrefName, aItem->savedDefaultValueScalar); + if (aItem->savedUserPresent) { + aUser->SetIntPref(aPrefName, aItem->savedUserValueScalar); + } break; case nsIPrefBranch::PREF_BOOL: - mSysPrefService->GetBoolPref(aPrefName, &boolValue); - SYSPREF_LOG(("system value is %s\n", boolValue ? "TRUE" : "FALSE")); - - prefBranch->SetBoolPref(aPrefName, boolValue); + aDefault->SetBoolPref(aPrefName, aItem->savedDefaultValueScalar); + if (aItem->savedUserPresent) { + aUser->SetBoolPref(aPrefName, aItem->savedUserValueScalar); + } break; default: - SYSPREF_LOG(("Fail to system value for it\n")); + NS_ERROR("Unknown preference type"); return NS_ERROR_FAILURE; } - prefBranch->LockPref(aPrefName); + + if (!aItem->savedUserPresent) { + aUser->DeleteBranch(aPrefName); + } + return NS_OK; } -////////////////////////////////////////////////////////////////////// -// nsSystemPref::UseMozillaPrefs -// Restore mozilla default prefs, remove system pref listeners -///////////////////////////////////////////////////////////////////// -nsresult -nsSystemPref::UseMozillaPrefs() +static PLDHashOperator PR_CALLBACK RestorePref(const nsACString& aKey, + SysPrefItem* aItem, + void* aClosure) { - nsresult rv = NS_OK; - SYSPREF_LOG(("\n====Now rollback to Mozilla prefs==\n")); + nsSystemPref* prefs = static_cast(aClosure); + nsCOMPtr 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; - // if we did not use system prefs, do nothing - if (!mSysPrefService) - return NS_OK; + // 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; - 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); + // Unlock the pref so we can set it + if (isLocked) { + userBranch->UnlockPref(prefName.get()); } - return rv; + + nsCOMPtr defaultBranch = prefs->GetPrefDefaultBranch(); + + RestorePrefValue(prefType, prefName.get(), aItem, + userBranch, defaultBranch); + + if (aItem->savedLocked) { + userBranch->LockPref(prefName.get()); + } + + return PL_DHASH_NEXT; } -//////////////////////////////////////////////////////////////////////////// -// 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) -{ - NS_ENSURE_ARG_POINTER(aPrefName); - NS_ENSURE_ARG_POINTER(aPrefValue); - NS_ENSURE_ARG_POINTER(aLocked); - - nsresult rv; +nsSystemPref::StopOverridingMozillaPref(const char* aPrefName) +{ + SysPrefItem* item; + nsDependentCString prefNameStr(aPrefName); + if (!mSavedPrefs.Get(prefNameStr, &item)) + return NS_OK; - nsCOMPtr prefBranch = - do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return rv; + RestorePref(prefNameStr, item, this); + mSavedPrefs.Remove(prefNameStr); + //delete item; + return NS_OK; +} - SYSPREF_LOG(("Save Mozilla value for %s\n", aPrefName)); +/* private */ +nsresult +nsSystemPref::OverridePref(const char* aPrefName, PRInt32 aType, + void* aValue, PRBool aLock, PRBool aPresent) +{ + nsCOMPtr userBranch = GetPrefUserBranch(); + nsCOMPtr defaultBranch = GetPrefDefaultBranch(); PRInt32 prefType = nsIPrefBranch::PREF_INVALID; - nsXPIDLCString strValue; - - rv = prefBranch->GetPrefType(aPrefName, &prefType); + nsresult rv = userBranch->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())); - - 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")); + 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; - break; - default: - SYSPREF_LOG(("Fail to Read Mozilla value for it\n")); - return NS_ERROR_FAILURE; + 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); + } + } } - 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); + // We need to ignore pref changes due to our own calls here + mIgnorePrefSetting = PR_TRUE; - nsresult rv; + // Unlock it if it's locked, so we can set it + if (isLocked) { + rv = userBranch->UnlockPref(aPrefName); + if (NS_FAILED(rv)) + return rv; + } - nsCOMPtr prefBranch = - do_GetService(NS_PREFSERVICE_CONTRACTID, &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(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); + } - SYSPREF_LOG(("Restore Mozilla value for %s\n", aPrefName)); + mIgnorePrefSetting = PR_FALSE; + return rv; +} - PRInt32 prefType = nsIPrefBranch::PREF_INVALID; - rv = prefBranch->GetPrefType(aPrefName, &prefType); +nsresult +nsSystemPref::FixupLockdownPrefs() +{ + nsCOMPtr userPrefs = GetPrefUserBranch(); + nsCOMPtr defaultPrefs = GetPrefUserBranch(); + PRUint32 childCount; + char **childArray = nsnull; + nsresult rv = userPrefs->GetChildList("config.lockdown.", + &childCount, &childArray); if (NS_FAILED(rv)) return rv; + 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; + } + } + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray); + return NS_OK; +} - // unlock, if it is locked - prefBranch->UnlockPref(aPrefName); +nsresult +nsSystemPref::LoadSystemPrefs() +{ + 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; + } - switch (prefType) { - case nsIPrefBranch::PREF_STRING: - prefBranch->SetCharPref(aPrefName, - aPrefValue->stringVal); - SYSPREF_LOG(("Mozilla value is %s\n", aPrefValue->stringVal)); + // Cache the pref-branch while we load up the system prefs. + NS_ASSERTION(!mCachedUserPrefBranch, + "Shouldn't have a cache here"); + nsCOMPtr userBranch = GetPrefUserBranch(); + nsCOMPtr defaultBranch = GetPrefDefaultBranch(); + mCachedDefaultPrefBranch = defaultBranch; + mCachedUserPrefBranch = userBranch; + rv = mSysPrefService->LoadSystemPreferences(this); + mCachedDefaultPrefBranch = nsnull; + mCachedUserPrefBranch = nsnull; + + if (NS_FAILED(rv)) { + // Restore all modified preferences to their original values + mSavedPrefs.EnumerateRead(RestorePref, this); + mSavedPrefs.Clear(); + mSysPrefService = nsnull; + } + + return rv; +} - PL_strfree(aPrefValue->stringVal); - aPrefValue->stringVal = nsnull; +nsresult +nsSystemPref::RestoreMozillaPrefs() +{ + SYSPREF_LOG(("\n====Now rollback to Mozilla prefs==\n")); - break; - case nsIPrefBranch::PREF_INT: - prefBranch->SetIntPref(aPrefName, aPrefValue->intVal); - SYSPREF_LOG(("Mozilla value is %d\n", aPrefValue->intVal)); + NS_ASSERTION(mSysPrefService, + "Should have the pref service here"); + if (!mSysPrefService) + return NS_ERROR_FAILURE; - break; - case nsIPrefBranch::PREF_BOOL: - prefBranch->SetBoolPref(aPrefName, aPrefValue->boolVal); - SYSPREF_LOG(("Mozilla value is %s\n", - aPrefValue->boolVal ? "TRUE" : "FALSE")); + nsCOMPtr userBranch = GetPrefUserBranch(); + nsCOMPtr defaultBranch = GetPrefDefaultBranch(); + mCachedDefaultPrefBranch = defaultBranch; + mCachedUserPrefBranch = userBranch; + + mSysPrefService->NotifyUnloadSystemPreferences(); + // Restore all modified preferences to their original values + mSavedPrefs.EnumerateRead(RestorePref, this); + mSavedPrefs.Clear(); + + mCachedDefaultPrefBranch = nsnull; + mCachedUserPrefBranch = nsnull; + + mSysPrefService = nsnull; - break; - default: - SYSPREF_LOG(("Fail to Restore Mozilla value for it\n")); - return NS_ERROR_FAILURE; - } + FixupLockdownPrefs(); - // restore its old lock status - if (aLocked) - prefBranch->LockPref(aPrefName); return NS_OK; } diff -Naur mozilla.orig/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp mozilla/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp --- mozilla.orig/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp 2003-04-14 19:28:25.000000000 -0700 +++ mozilla/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp 2008-04-01 16:50:49.000000000 -0700 @@ -42,10 +42,10 @@ #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. @@ -96,11 +96,6 @@ RegisterSystemPref, UnRegisterSystemPref, }, - { NS_SYSTEMPREF_SERVICE_CLASSNAME, - NS_SYSTEMPREF_SERVICE_CID, - NS_SYSTEMPREF_SERVICE_CONTRACTID, - nsSystemPrefServiceConstructor, - }, }; NS_IMPL_NSGETMODULE(nsSystemPrefModule, components) diff -Naur mozilla.orig/extensions/pref/system-pref/src/nsSystemPref.h mozilla/extensions/pref/system-pref/src/nsSystemPref.h --- mozilla.orig/extensions/pref/system-pref/src/nsSystemPref.h 2005-02-23 08:15:37.000000000 -0800 +++ mozilla/extensions/pref/system-pref/src/nsSystemPref.h 2008-04-01 16:50:49.000000000 -0700 @@ -23,7 +23,7 @@ * * 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 @@ -45,16 +45,14 @@ #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 +#include "nsISystemPrefService.h" +#include "nsIObserver.h" -union MozPrefValue; struct SysPrefItem; ////////////////////////////////////////////////////////////////////////// @@ -62,18 +60,34 @@ // 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. -// -// 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. +// 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. +// +// 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 @@ -83,23 +97,39 @@ 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 GetPrefUserBranch(); + virtual already_AddRefed 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); - - // funcs used to load mozilla default prefs - nsresult UseMozillaPrefs(); - nsresult RestoreMozDefaultPref(const char *aPrefName, - MozPrefValue *aPrefVal, - PRBool aLocked); - - nsCOMPtr mSysPrefService; - PRBool mEnabled; // system pref is enabled or not - SysPrefItem *mSysPrefs; + // 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(); + + nsresult LoadSystemPrefs(); + + nsresult RestoreMozillaPrefs(); + + nsresult OverridePref(const char* aPrefName, PRInt32 aType, + void* aValue, PRBool aLock, PRBool aPresent); + + nsCOMPtr mSysPrefService; + nsClassHashtable mSavedPrefs; + // weak pointers to cached prefbranches + nsIPrefBranch2* mCachedUserPrefBranch; + nsIPrefBranch* mCachedDefaultPrefBranch; + PRPackedBool mIgnorePrefSetting; }; #define NS_SYSTEMPREF_CID \ diff -Naur mozilla.orig/modules/libpref/src/init/all.js mozilla/modules/libpref/src/init/all.js --- mozilla.orig/modules/libpref/src/init/all.js 2008-03-24 08:12:18.000000000 -0700 +++ mozilla/modules/libpref/src/init/all.js 2008-04-10 11:37:04.000000000 -0700 @@ -1064,7 +1064,7 @@ pref("roaming.showInitialWarning", true); // whether use prefs from system -pref("config.use_system_prefs", false); +pref("config.use_system_prefs", true); // if the system has enabled accessibility pref("config.use_system_prefs.accessibility", false); diff -Naur mozilla.orig/toolkit/library/libxul-config.mk mozilla/toolkit/library/libxul-config.mk --- mozilla.orig/toolkit/library/libxul-config.mk 2008-02-25 17:28:51.000000000 -0800 +++ mozilla/toolkit/library/libxul-config.mk 2008-04-10 11:38:00.000000000 -0700 @@ -266,6 +266,7 @@ ifdef MOZ_ENABLE_GTK2 COMPONENT_LIBS += widget_gtk2 ifdef MOZ_PREF_EXTENSIONS +COMPONENT_LIBS += syspref-gconf COMPONENT_LIBS += system-pref endif endif diff -Naur mozilla.orig/toolkit/library/libxul-rules.mk mozilla/toolkit/library/libxul-rules.mk --- mozilla.orig/toolkit/library/libxul-rules.mk 2008-03-08 01:43:03.000000000 -0800 +++ mozilla/toolkit/library/libxul-rules.mk 2008-04-10 11:38:07.000000000 -0700 @@ -89,6 +89,12 @@ EXTRA_DSO_LDOPTS += $(MOZ_PANGO_LIBS) endif +ifdef MOZ_ENABLE_GTK2 +ifdef MOZ_PREF_EXTENSIONS +EXTRA_DSO_LDOPTS += $(MOZ_GCONF_LIBS) +endif +endif + EXTRA_DSO_LDOPTS += $(MOZ_CAIRO_LIBS) export:: dlldeps.cpp diff -Naur mozilla.orig/toolkit/library/nsStaticXULComponents.cpp mozilla/toolkit/library/nsStaticXULComponents.cpp --- mozilla.orig/toolkit/library/nsStaticXULComponents.cpp 2008-02-25 17:28:51.000000000 -0800 +++ mozilla/toolkit/library/nsStaticXULComponents.cpp 2008-04-10 11:38:14.000000000 -0700 @@ -136,7 +136,8 @@ #ifdef MOZ_ENABLE_GTK2 #ifdef MOZ_PREF_EXTENSIONS #define SYSTEMPREF_MODULES MODULE(nsSystemPrefModule) \ - MODULE(nsAutoConfigModule) + MODULE(nsAutoConfigModule) \ + MODULE(nsSystemPrefServiceModule) #else #define SYSTEMPREF_MODULES #endif