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