# HG changeset patch # User Wolfgang Rosenauer # Date 1261255876 -3600 # Node ID ca988be0905ba12bcd1a3d2af7fe571de6ad6962 # Parent c62859a2fd22f53ef60f9dec399f8195ae328308 Update and integrate new lockdown patches. (currently disabled as they need to be tested still) diff -r c62859a2fd22 -r ca988be0905b gecko-lockdown.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gecko-lockdown.patch Sat Dec 19 21:51:16 2009 +0100 @@ -0,0 +1,422 @@ +From: various contributors +Subject: lockdown hooks for Gecko + +diff --git a/extensions/cookie/nsCookiePermission.cpp b/extensions/cookie/nsCookiePermission.cpp +--- a/extensions/cookie/nsCookiePermission.cpp ++++ b/extensions/cookie/nsCookiePermission.cpp +@@ -1,10 +1,10 @@ + /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim:ts=2:sw=2:et: */ ++/* vim: set ts=2 sw=2 et: */ + /* ***** 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/ + * +@@ -81,16 +81,17 @@ static const PRBool kDefaultPolicy = PR_ + static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy"; + static const char kCookiesLifetimeDays[] = "network.cookie.lifetime.days"; + static const char kCookiesAlwaysAcceptSession[] = "network.cookie.alwaysAcceptSessionCookies"; + + static const char kCookiesPrefsMigrated[] = "network.cookie.prefsMigrated"; + // obsolete pref names for migration + static const char kCookiesLifetimeEnabled[] = "network.cookie.lifetime.enabled"; + static const char kCookiesLifetimeBehavior[] = "network.cookie.lifetime.behavior"; ++static const char kCookiesHonorExceptions[] = "network.cookie.honorExceptions"; + static const char kCookiesAskPermission[] = "network.cookie.warnAboutCookies"; + + static const char kPermissionType[] = "cookie"; + + #ifdef MOZ_MAIL_NEWS + // returns PR_TRUE if URI appears to be the URI of a mailnews protocol + // XXXbz this should be a protocol flag, not a scheme list, dammit! + static PRBool +@@ -120,16 +121,17 @@ nsCookiePermission::Init() + + // failure to access the pref service is non-fatal... + nsCOMPtr prefBranch = + do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefBranch) { + prefBranch->AddObserver(kCookiesLifetimePolicy, this, PR_FALSE); + prefBranch->AddObserver(kCookiesLifetimeDays, this, PR_FALSE); + prefBranch->AddObserver(kCookiesAlwaysAcceptSession, this, PR_FALSE); ++ prefBranch->AddObserver(kCookiesHonorExceptions, this, PR_FALSE); + PrefChanged(prefBranch, nsnull); + + // migration code for original cookie prefs + PRBool migrated; + rv = prefBranch->GetBoolPref(kCookiesPrefsMigrated, &migrated); + if (NS_FAILED(rv) || !migrated) { + PRBool warnAboutCookies = PR_FALSE; + prefBranch->GetBoolPref(kCookiesAskPermission, &warnAboutCookies); +@@ -173,16 +175,20 @@ nsCookiePermission::PrefChanged(nsIPrefB + if (PREF_CHANGED(kCookiesLifetimeDays) && + NS_SUCCEEDED(aPrefBranch->GetIntPref(kCookiesLifetimeDays, &val))) + // save cookie lifetime in seconds instead of days + mCookiesLifetimeSec = val * 24 * 60 * 60; + + if (PREF_CHANGED(kCookiesAlwaysAcceptSession) && + NS_SUCCEEDED(aPrefBranch->GetBoolPref(kCookiesAlwaysAcceptSession, &val))) + mCookiesAlwaysAcceptSession = val; ++ ++ if (PREF_CHANGED(kCookiesHonorExceptions) && ++ NS_SUCCEEDED(aPrefBranch->GetBoolPref(kCookiesHonorExceptions, &val))) ++ mCookiesHonorExceptions = val; + } + + NS_IMETHODIMP + nsCookiePermission::SetAccess(nsIURI *aURI, + nsCookieAccess aAccess) + { + // + // NOTE: nsCookieAccess values conveniently match up with +@@ -202,16 +208,21 @@ nsCookiePermission::CanAccess(nsIURI + // it. + if (IsFromMailNews(aURI)) { + *aResult = ACCESS_DENY; + return NS_OK; + } + #endif // MOZ_MAIL_NEWS + + // finally, check with permission manager... ++ if (!mCookiesHonorExceptions) { ++ *aResult = ACCESS_DEFAULT; ++ return NS_OK; ++ } ++ + nsresult rv = mPermMgr->TestPermission(aURI, kPermissionType, (PRUint32 *) aResult); + if (NS_SUCCEEDED(rv)) { + switch (*aResult) { + // if we have one of the publicly-available values, just return it + case nsIPermissionManager::UNKNOWN_ACTION: // ACCESS_DEFAULT + case nsIPermissionManager::ALLOW_ACTION: // ACCESS_ALLOW + case nsIPermissionManager::DENY_ACTION: // ACCESS_DENY + break; +diff --git a/extensions/cookie/nsCookiePermission.h b/extensions/cookie/nsCookiePermission.h +--- a/extensions/cookie/nsCookiePermission.h ++++ b/extensions/cookie/nsCookiePermission.h +@@ -54,30 +54,32 @@ public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOOKIEPERMISSION + NS_DECL_NSIOBSERVER + + nsCookiePermission() + : mCookiesLifetimeSec(LL_MAXINT) + , mCookiesLifetimePolicy(0) // ACCEPT_NORMALLY + , mCookiesAlwaysAcceptSession(PR_FALSE) ++ , mCookiesHonorExceptions(PR_TRUE) + {} + virtual ~nsCookiePermission() {} + + nsresult Init(); + void PrefChanged(nsIPrefBranch *, const char *); + + private: + PRBool InPrivateBrowsing(); + + nsCOMPtr mPermMgr; + nsCOMPtr mPBService; + + PRInt64 mCookiesLifetimeSec; // lifetime limit specified in seconds + PRUint8 mCookiesLifetimePolicy; // pref for how long cookies are stored + PRPackedBool mCookiesAlwaysAcceptSession; // don't prompt for session cookies ++ PRPackedBool mCookiesHonorExceptions; + }; + + // {EF565D0A-AB9A-4A13-9160-0644CDFD859A} + #define NS_COOKIEPERMISSION_CID \ + {0xEF565D0A, 0xAB9A, 0x4A13, {0x91, 0x60, 0x06, 0x44, 0xcd, 0xfd, 0x85, 0x9a }} + + #endif +diff --git a/extensions/permissions/nsContentBlocker.cpp b/extensions/permissions/nsContentBlocker.cpp +--- a/extensions/permissions/nsContentBlocker.cpp ++++ b/extensions/permissions/nsContentBlocker.cpp +@@ -71,32 +71,38 @@ static const char *kTypeString[NUMBER_OF + NS_IMPL_ISUPPORTS3(nsContentBlocker, + nsIContentPolicy, + nsIObserver, + nsSupportsWeakReference) + + nsContentBlocker::nsContentBlocker() + { + memset(mBehaviorPref, BEHAVIOR_ACCEPT, NUMBER_OF_TYPES); ++ memset(mHonorExceptions, PR_TRUE, NUMBER_OF_TYPES); + } + + nsresult + nsContentBlocker::Init() + { + nsresult rv; + mPermissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr prefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr prefBranch; + rv = prefService->GetBranch("permissions.default.", getter_AddRefs(prefBranch)); + NS_ENSURE_SUCCESS(rv, rv); + ++ nsCOMPtr honorExceptionsPrefBranch; ++ rv = prefService->GetBranch("permissions.honorExceptions.", ++ getter_AddRefs(honorExceptionsPrefBranch)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ + // Migrate old image blocker pref + nsCOMPtr oldPrefBranch; + oldPrefBranch = do_QueryInterface(prefService); + PRInt32 oldPref; + rv = oldPrefBranch->GetIntPref("network.image.imageBehavior", &oldPref); + if (NS_SUCCEEDED(rv) && oldPref) { + PRInt32 newPref; + switch (oldPref) { +@@ -116,39 +122,49 @@ nsContentBlocker::Init() + + + // The branch is not a copy of the prefservice, but a new object, because + // it is a non-default branch. Adding obeservers to it will only work if + // we make sure that the object doesn't die. So, keep a reference to it. + mPrefBranchInternal = do_QueryInterface(prefBranch, &rv); + NS_ENSURE_SUCCESS(rv, rv); + ++ mHonorExceptionsPrefBranchInternal = ++ do_QueryInterface(honorExceptionsPrefBranch, &rv); ++ NS_ENSURE_SUCCESS(rv, rv); ++ + rv = mPrefBranchInternal->AddObserver("", this, PR_TRUE); +- PrefChanged(prefBranch, nsnull); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ rv = mHonorExceptionsPrefBranchInternal->AddObserver("", this, PR_TRUE); ++ PrefChanged(nsnull); + + return rv; + } + + #undef LIMIT + #define LIMIT(x, low, high, default) ((x) >= (low) && (x) <= (high) ? (x) : (default)) + + void +-nsContentBlocker::PrefChanged(nsIPrefBranch *aPrefBranch, +- const char *aPref) ++nsContentBlocker::PrefChanged(const char *aPref) + { +- PRInt32 val; +- +-#define PREF_CHANGED(_P) (!aPref || !strcmp(aPref, _P)) +- +- for(PRUint32 i = 0; i < NUMBER_OF_TYPES; ++i) { +- if (PREF_CHANGED(kTypeString[i]) && +- NS_SUCCEEDED(aPrefBranch->GetIntPref(kTypeString[i], &val))) +- mBehaviorPref[i] = LIMIT(val, 1, 3, 1); ++ for (PRUint32 i = 0; i < NUMBER_OF_TYPES; ++i) { ++ if (!aPref || !strcmp(kTypeString[i], aPref)) { ++ PRInt32 val; ++ PRBool b; ++ if (mPrefBranchInternal && ++ NS_SUCCEEDED(mPrefBranchInternal->GetIntPref(kTypeString[i], &val))) { ++ mBehaviorPref[i] = LIMIT(val, 1, 3, 1); ++ } ++ if (mHonorExceptionsPrefBranchInternal && ++ NS_SUCCEEDED(mHonorExceptionsPrefBranchInternal->GetBoolPref(kTypeString[i], &b))) { ++ mHonorExceptions[i] = b; ++ } ++ } + } +- + } + + // nsIContentPolicy Implementation + NS_IMETHODIMP + nsContentBlocker::ShouldLoad(PRUint32 aContentType, + nsIURI *aContentLocation, + nsIURI *aRequestingLocation, + nsISupports *aRequestingContext, +@@ -264,21 +280,23 @@ nsContentBlocker::TestPermission(nsIURI + // This default will also get used if there is an unknown value in the + // permission list, or if the permission manager returns unknown values. + *aPermission = PR_TRUE; + + // check the permission list first; if we find an entry, it overrides + // default prefs. + // Don't forget the aContentType ranges from 1..8, while the + // array is indexed 0..7 +- PRUint32 permission; +- nsresult rv = mPermissionManager->TestPermission(aCurrentURI, +- kTypeString[aContentType - 1], +- &permission); +- NS_ENSURE_SUCCESS(rv, rv); ++ PRUint32 permission = 0; ++ if (mHonorExceptions[aContentType - 1]) { ++ nsresult rv = mPermissionManager->TestPermission(aCurrentURI, ++ kTypeString[aContentType - 1], ++ &permission); ++ NS_ENSURE_SUCCESS(rv, rv); ++ } + + // If there is nothing on the list, use the default. + if (!permission) { + permission = mBehaviorPref[aContentType - 1]; + *aFromPrefs = PR_TRUE; + } + + // Use the fact that the nsIPermissionManager values map to +@@ -294,17 +312,17 @@ nsContentBlocker::TestPermission(nsIURI + case BEHAVIOR_NOFOREIGN: + // Third party checking + + // Need a requesting uri for third party checks to work. + if (!aFirstURI) + return NS_OK; + + PRBool trustedSource = PR_FALSE; +- rv = aFirstURI->SchemeIs("chrome", &trustedSource); ++ nsresult rv = aFirstURI->SchemeIs("chrome", &trustedSource); + NS_ENSURE_SUCCESS(rv,rv); + if (!trustedSource) { + rv = aFirstURI->SchemeIs("resource", &trustedSource); + NS_ENSURE_SUCCESS(rv,rv); + } + if (trustedSource) + return NS_OK; + +@@ -360,12 +378,11 @@ nsContentBlocker::TestPermission(nsIURI + NS_IMETHODIMP + nsContentBlocker::Observe(nsISupports *aSubject, + const char *aTopic, + const PRUnichar *aData) + { + NS_ASSERTION(!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic), + "unexpected topic - we only deal with pref changes!"); + +- if (mPrefBranchInternal) +- PrefChanged(mPrefBranchInternal, NS_LossyConvertUTF16toASCII(aData).get()); ++ PrefChanged(NS_LossyConvertUTF16toASCII(aData).get()); + return NS_OK; + } +diff --git a/extensions/permissions/nsContentBlocker.h b/extensions/permissions/nsContentBlocker.h +--- a/extensions/permissions/nsContentBlocker.h ++++ b/extensions/permissions/nsContentBlocker.h +@@ -61,26 +61,28 @@ public: + NS_DECL_NSIOBSERVER + + nsContentBlocker(); + nsresult Init(); + + private: + ~nsContentBlocker() {} + +- void PrefChanged(nsIPrefBranch *, const char *); ++ void PrefChanged(const char *); + nsresult TestPermission(nsIURI *aCurrentURI, + nsIURI *aFirstURI, + PRInt32 aContentType, + PRBool *aPermission, + PRBool *aFromPrefs); + + nsCOMPtr mPermissionManager; + nsCOMPtr mPrefBranchInternal; ++ nsCOMPtr mHonorExceptionsPrefBranchInternal; + PRUint8 mBehaviorPref[NUMBER_OF_TYPES]; ++ PRPackedBool mHonorExceptions[NUMBER_OF_TYPES]; + }; + + #define NS_CONTENTBLOCKER_CID \ + { 0x4ca6b67b, 0x5cc7, 0x4e71, \ + { 0xa9, 0x8a, 0x97, 0xaf, 0x1c, 0x13, 0x48, 0x62 } } + + #define NS_CONTENTBLOCKER_CONTRACTID "@mozilla.org/permissions/contentblocker;1" + +diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js +--- a/modules/libpref/src/init/all.js ++++ b/modules/libpref/src/init/all.js +@@ -842,16 +842,17 @@ pref("network.automatic-ntlm-auth.truste + // response to a NTLM challenge. By default, this is disabled since servers + // should almost never need the LM hash, and the LM hash is what makes NTLM + // authentication less secure. See bug 250691 for further details. + // NOTE: automatic-ntlm-auth which leverages the OS-provided NTLM + // implementation will not be affected by this preference. + pref("network.ntlm.send-lm-response", false); + + pref("permissions.default.image", 1); // 1-Accept, 2-Deny, 3-dontAcceptForeign ++pref("permissions.honorExceptions.image", true); + + #ifndef XP_MACOSX + #ifdef XP_UNIX + pref("network.proxy.type", 5); + #else + pref("network.proxy.type", 0); + #endif + #else +@@ -869,16 +870,17 @@ pref("network.proxy.ssl_port", + pref("network.proxy.socks", ""); + pref("network.proxy.socks_port", 0); + pref("network.proxy.socks_version", 5); + pref("network.proxy.socks_remote_dns", false); + pref("network.proxy.no_proxies_on", "localhost, 127.0.0.1"); + pref("network.proxy.failover_timeout", 1800); // 30 minutes + pref("network.online", true); //online/offline + pref("network.cookie.cookieBehavior", 0); // 0-Accept, 1-dontAcceptForeign, 2-dontUse ++pref("network.cookie.honorExceptions", true); + pref("network.cookie.lifetimePolicy", 0); // accept normally, 1-askBeforeAccepting, 2-acceptForSession,3-acceptForNDays + pref("network.cookie.alwaysAcceptSessionCookies", false); + pref("network.cookie.prefsMigrated", false); + pref("network.cookie.lifetime.days", 90); + + // The PAC file to load. Ignored unless network.proxy.type is 2. + pref("network.proxy.autoconfig_url", ""); + +diff --git a/xpinstall/src/nsXPInstallManager.cpp b/xpinstall/src/nsXPInstallManager.cpp +--- a/xpinstall/src/nsXPInstallManager.cpp ++++ b/xpinstall/src/nsXPInstallManager.cpp +@@ -300,36 +300,46 @@ nsXPInstallManager::InitManagerInternal( + packageList[j++] = item->GetSafeURLString(); + packageList[j++] = item->mIconURL.get(); + packageList[j++] = item->mCertName.get(); + } + + //----------------------------------------------------- + // Get permission to install + //----------------------------------------------------- ++ nsCOMPtr pref(do_GetService(NS_PREFSERVICE_CONTRACTID)); + + #ifdef ENABLE_SKIN_SIMPLE_INSTALLATION_UI + if ( mChromeType == CHROME_SKIN ) + { + // We may want to enable the simple installation UI once + // bug 343037 is fixed + + // skins get a simpler/friendlier dialog + // XXX currently not embeddable +- OKtoInstall = ConfirmChromeInstall( mParentWindow, packageList ); ++ PRBool themesDisabled = PR_FALSE; ++ if (pref) ++ pref->GetBoolPref("config.lockdown.disable_themes", &themesDisabled); ++ OKtoInstall = !themesDisabled && ++ ConfirmChromeInstall( mParentWindow, packageList ); + } + else + { + #endif ++ PRBool extensionsDisabled = PR_FALSE; ++ if (pref) ++ pref->GetBoolPref("config.lockdown.disable_extensions", &extensionsDisabled); ++ if (!extensionsDisabled) { + rv = dlgSvc->ConfirmInstall( mParentWindow, + packageList, + numStrings, + &OKtoInstall ); + if (NS_FAILED(rv)) + OKtoInstall = PR_FALSE; ++ } + #ifdef ENABLE_SKIN_SIMPLE_INSTALLATION_UI + } + #endif + + if (OKtoInstall) + { + //----------------------------------------------------- + // Open the progress dialog diff -r c62859a2fd22 -r ca988be0905b mozilla-gconf-backend.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mozilla-gconf-backend.patch Sat Dec 19 21:51:16 2009 +0100 @@ -0,0 +1,3516 @@ +From: various contributors +Subject: replace gconf backend with more complete mapping for lockdown feature + +diff --git a/extensions/pref/Makefile.in b/extensions/pref/Makefile.in +--- a/extensions/pref/Makefile.in ++++ b/extensions/pref/Makefile.in +@@ -40,13 +40,13 @@ DEPTH = ../.. + topsrcdir = @top_srcdir@ + srcdir = @srcdir@ + VPATH = @srcdir@ + + include $(DEPTH)/config/autoconf.mk + + DIRS = autoconfig + +-ifdef MOZ_ENABLE_GTK2 ++ifdef MOZ_ENABLE_GCONF + DIRS += system-pref + endif + + include $(topsrcdir)/config/rules.mk +diff --git a/extensions/pref/system-pref/src/Makefile.in b/extensions/pref/system-pref/src/Makefile.in +--- a/extensions/pref/system-pref/src/Makefile.in ++++ b/extensions/pref/system-pref/src/Makefile.in +@@ -38,47 +38,41 @@ + DEPTH = ../../../.. + topsrcdir = @top_srcdir@ + srcdir = @srcdir@ + VPATH = @srcdir@ + + include $(DEPTH)/config/autoconf.mk + + MODULE = system-pref +-LIBRARY_NAME = system-pref_s ++LIBRARY_NAME = system-pref + ifneq ($(OS_ARCH),WINNT) + SHORT_LIBNAME = syspref + endif + + # We want to force the creation of a static lib. +-FORCE_STATIC_LIB = 1 +-LIBXUL_LIBRARY = 1 ++#FORCE_STATIC_LIB = 1 ++LIBXUL_LIBRARY = 1 ++MODULE_NAME = nsSystemPrefModule ++IS_COMPONENT = 1 ++EXPORT_LIBRARY = 1 + + REQUIRES = xpcom \ + string \ + embedcomponents \ + pref \ + $(NULL) + +-ifdef MOZ_ENABLE_GTK2 +-DIRS = gconf +-endif ++CPPSRCS = \ ++ nsSystemPref.cpp \ ++ nsSystemPrefFactory.cpp \ ++ $(NULL) + + EXTRA_DSO_LDOPTS = \ +- -L$(DIST)/bin \ + $(MOZ_COMPONENT_LIBS) \ + $(NULL) + +-CPPSRCS = \ +- nsSystemPref.cpp \ +- $(NULL) +- + EXPORTS = \ +- nsSystemPrefLog.h \ ++ nsISystemPrefService.h \ + $(NULL) + + include $(topsrcdir)/config/rules.mk + +-ifdef MOZ_ENABLE_GTK2 +-INCLUDES += \ +- -I$(srcdir)/gconf \ +- $(NULL) +-endif +diff --git a/extensions/pref/system-pref/src/gconf/Makefile.in b/extensions/pref/system-pref/src/gconf/Makefile.in +--- a/extensions/pref/system-pref/src/gconf/Makefile.in ++++ b/extensions/pref/system-pref/src/gconf/Makefile.in +@@ -37,50 +37,37 @@ + + DEPTH = ../../../../.. + topsrcdir = @top_srcdir@ + srcdir = @srcdir@ + VPATH = @srcdir@ + + include $(DEPTH)/config/autoconf.mk + +-MODULE = system-pref +-LIBRARY_NAME = system-pref +-LIBXUL_LIBRARY = 1 ++MODULE = system-pref-gconf ++LIBRARY_NAME = system-pref-gconf ++IS_COMPONENT = 1 ++MODULE_NAME = nsSystemPrefServiceModule ++FORCE_SHARED_LIB = 1 + + REQUIRES = pref \ + string \ + xpcom \ +- embedcomponents \ ++ necko \ + $(NULL) + + CPPSRCS = \ + nsSystemPrefService.cpp \ +- nsSystemPrefFactory.cpp \ + $(NULL) + +-SHARED_LIBRARY_LIBS = ../libsystem-pref_s.a ++OS_INCLUDES += $(MOZ_GCONF_CFLAGS) ++ + + EXTRA_DSO_LDOPTS = \ +- -L$(DIST)/bin \ +- $(MOZ_COMPONENT_LIBS) \ +- $(MOZ_GTK2_LIBS) \ ++ $(XPCOM_GLUE_LDOPTS) \ ++ $(MOZ_GCONF_LIBS) \ ++ $(NSPR_LIBS) \ + $(NULL) + +-EXPORT_LIBRARY = 1 +-IS_COMPONENT = 1 +-MODULE_NAME = nsSystemPrefModule +- +-EXPORTS = \ +- nsSystemPrefService.h \ +- $(NULL) + + include $(topsrcdir)/config/rules.mk + +-CFLAGS += $(MOZ_GTK2_CFLAGS) +-CXXFLAGS += $(MOZ_GTK2_CFLAGS) +- +-LOCAL_INCLUDES = -I$(srcdir)/.. +- +-export:: +- $(INSTALL) $(srcdir)/../nsSystemPrefFactory.cpp . +- + GARBAGE += nsSystemPrefFactory.cpp +diff --git a/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp b/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp +--- a/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp ++++ b/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp +@@ -18,17 +18,19 @@ + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Sun Microsystems, Inc. + * Portions created by Sun Microsystems are Copyright (C) 2003 Sun + * Microsystems, Inc. All Rights Reserved. + * + * Original Author: Bolian Yin (bolian.yin@sun.com) + * +- * Contributor(s): ++ * Contributor(s): Robert O'Callahan/Novell (rocallahan@novell.com) ++ * Hubert Figuiere (hfiguiere@novell.com) ++ * Wolfgang Rosenauer (wr@rosenauer.org) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your +@@ -36,299 +38,1300 @@ + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + #include + #include ++#include + + #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 mGConfSimpleCallbacks; ++ nsDataHashtable 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(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 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 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 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 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 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 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 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 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 StringSet; ++/** Collect the set of protocol names that we want to set preferences for */ ++static nsresult AddAllProtocols(nsSystemPrefService* aPrefService, ++ const char* aSafeProtocols, ++ StringSet* aProtocolSet, ++ StringSet* aSafeSet) ++{ ++ nsCOMPtr prefs = aPrefService->GetPrefs()->GetPrefUserBranch(); ++ PRUint32 childCount; ++ char **childArray = nsnull; ++ nsresult rv = prefs->GetChildList(MozKey_BlockedPrefix, &childCount, &childArray); ++ if (NS_FAILED(rv)) ++ return rv; ++ PRUint32 i; ++ for (i = 0; i < childCount; ++i) { ++ nsDependentCString tmp(childArray[i] + NUM_ELEM(MozKey_BlockedPrefix)-1); ++ aProtocolSet->Put(tmp, 1); // copies ++ } ++ for (i = 0; i < NUM_ELEM(nonDisablableBuiltinProtocols); ++i) { ++ nsDependentCString tmp(nonDisablableBuiltinProtocols[i]); ++ aProtocolSet->Put(tmp, 1); ++ } ++ i = 0; ++ while (aSafeProtocols[i]) { ++ const char* nextComma = strchr(aSafeProtocols+i, ','); ++ PRUint32 tokLen = nextComma ? nextComma - (aSafeProtocols+i) ++ : strlen(aSafeProtocols+i); ++ nsCAutoString tok(aSafeProtocols+i, tokLen); ++ aProtocolSet->Put(tok, 1); ++ aSafeSet->Put(tok, 1); ++ if (nextComma) { ++ i = nextComma - aSafeProtocols + 1; ++ } else { ++ break; ++ } ++ } ++ NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray); ++ return NS_OK; ++} ++ ++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(aClosure); ++ const nsCString& protocol = PromiseFlatCString(aKey); ++ PRBool blockProtocol = PR_FALSE; ++ if (closure->disableUnsafe && ++ !FindString(nonDisablableBuiltinProtocols, ++ NUM_ELEM(nonDisablableBuiltinProtocols), protocol.get()) && ++ !closure->safeProtocolSet.Get(aKey, nsnull)) { ++ blockProtocol = PR_TRUE; ++ } ++ ++ nsCAutoString prefName; ++ prefName.Append(MozKey_BlockedPrefix); ++ prefName.Append(protocol); ++ closure->prefSetter->SetOverridingMozillaBoolPref(prefName.get(), blockProtocol, ++ closure->lock); ++ return PL_DHASH_NEXT; ++} ++static nsresult ApplyUnsafeProtocols(nsSystemPrefService* aPrefService, ++ GConfClient* aClient) ++{ ++ PRBool lock = !gconf_client_key_is_writable(aClient, GConfKey_DisableUnsafeProtocols, nsnull) ++ || !gconf_client_key_is_writable(aClient, GConfKey_AdditionalSafeProtocols, nsnull); ++ gboolean disable = gconf_client_get_bool(aClient, GConfKey_DisableUnsafeProtocols, nsnull); ++ char* protocols = gconf_client_get_string(aClient, GConfKey_AdditionalSafeProtocols, nsnull); ++ if (!protocols) ++ return NS_ERROR_FAILURE; ++ nsresult rv = aPrefService->GetPrefs()-> ++ SetOverridingMozillaBoolPref(MozKey_BlockedDefault, disable, lock); ++ StringSet protocolSet; ++ ProtocolPrefClosure closure; ++ protocolSet.Init(); ++ closure.safeProtocolSet.Init(); ++ if (NS_SUCCEEDED(rv)) { ++ rv = AddAllProtocols(aPrefService, protocols, &protocolSet, ++ &closure.safeProtocolSet); ++ } ++ if (NS_SUCCEEDED(rv)) { ++ closure.disableUnsafe = disable; ++ closure.lock = lock; ++ closure.prefSetter = aPrefService->GetPrefs(); ++ nsCOMPtr prefs = aPrefService->GetPrefs()->GetPrefUserBranch(); ++ closure.prefs = prefs; ++ protocolSet.EnumerateRead(SetProtocolPref, &closure); ++ } ++ g_free(protocols); ++ return rv; ++} ++ ++static nsresult ReverseApplyUnsafeProtocols(nsSystemPrefService* aPrefService, ++ GConfClient* aClient) ++{ ++ nsCOMPtr prefs = aPrefService->GetPrefs()->GetPrefUserBranch(); ++ PRBool blockedDefault; ++ nsresult rv = prefs->GetBoolPref(MozKey_BlockedDefault, &blockedDefault); ++ if (NS_FAILED(rv)) ++ return rv; ++ nsCAutoString enabledProtocols; ++ PRUint32 childCount; ++ char **childArray = nsnull; ++ rv = prefs->GetChildList(MozKey_BlockedPrefix, &childCount, &childArray); ++ if (NS_FAILED(rv)) ++ return rv; ++ for (PRUint32 i = 0; i < childCount; ++i) { ++ PRBool val = PR_FALSE; ++ prefs->GetBoolPref(childArray[i], &val); ++ if (val) { ++ if (enabledProtocols.Length() > 0) { ++ enabledProtocols.Append(','); ++ } ++ 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 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 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 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(user_data); ++ SimplePrefMapping* map = static_cast( ++ 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(user_data); ++ ComplexGConfPrefMapping* map = static_cast( ++ 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 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 observerRef; +- if (aHoldWeak) { +- nsCOMPtr weakRefFactory = +- do_QueryInterface(aObserver); +- if (!weakRefFactory) { +- // the caller didn't give us a object that supports weak reference. +- // ... tell them +- nsMemory::Free(pCallbackData); +- return NS_ERROR_INVALID_ARG; +- } +- nsCOMPtr tmp = do_GetWeakReference(weakRefFactory); +- observerRef = tmp; +- } 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 observerRef; +- if (pCallbackData->bIsWeakRef) { +- nsCOMPtr weakRefFactory = +- do_QueryInterface(aObserver); +- if (weakRefFactory) { +- nsCOMPtr tmp = +- do_GetWeakReference(aObserver); +- observerRef = tmp; +- } +- } +- if (!observerRef) +- observerRef = aObserver; +- +- if (pCallbackData->observer == observerRef && +- pCallbackData->prefAtom == prefAtom) { +- rv = mGConf->NotifyRemove(prefAtom, pCallbackData); +- if (NS_SUCCEEDED(rv)) { +- mObservers->RemoveElementAt(i); +- NS_RELEASE(pCallbackData->observer); +- nsMemory::Free(pCallbackData); +- } +- return rv; +- } +- } +- } +- return NS_OK; +-} +- +-void +-nsSystemPrefService::OnPrefChange(PRUint32 aPrefAtom, void *aData) +-{ +- if (!mInitialized) +- return; +- +- SysPrefCallbackData *pData = (SysPrefCallbackData *)aData; +- if (pData->prefAtom != aPrefAtom) +- return; +- +- nsCOMPtr observer; +- if (pData->bIsWeakRef) { +- nsCOMPtr weakRef = +- do_QueryInterface(pData->observer); +- if(weakRef) +- observer = do_QueryReferent(weakRef); +- if (!observer) { +- // this weak referenced observer went away, remove it from the list +- nsresult rv = mGConf->NotifyRemove(aPrefAtom, pData); +- if (NS_SUCCEEDED(rv)) { +- mObservers->RemoveElement(pData); +- NS_RELEASE(pData->observer); +- nsMemory::Free(pData); +- } +- return; +- } +- } +- else +- observer = do_QueryInterface(pData->observer); +- +- if (observer) +- observer->Observe(static_cast(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 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 +- (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 GetPrefUserBranch() = 0; ++ virtual already_AddRefed GetPrefDefaultBranch() = 0; ++}; ++ ++class nsISystemPrefService : public nsISupports { ++public: ++ NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISYSTEMPREFSERVICE_IID) ++ ++ /** ++ * Load the system prefs from the store into their corresponding ++ * Mozilla prefs, calling SetOverridingMozillaPref on each ++ * such pref. ++ */ ++ virtual nsresult LoadSystemPreferences(nsISystemPref* aPrefs) = 0; ++ ++ /** ++ * Notify that a Mozilla user pref that is being overridden by the ++ * store has changed. The new value of the Mozilla pref should be ++ * written back to the store. ++ */ ++ virtual nsresult NotifyMozillaPrefChanged(const char* aPrefName) = 0; ++ ++ /** ++ * Notify that we're about to stop using the system prefs. After ++ * this, nsSystemPref will automatically stop overriding all ++ * Mozilla prefs that are being overridden. ++ */ ++ virtual nsresult NotifyUnloadSystemPreferences() = 0; ++}; ++ ++#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 + + 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 ++nsSystemPref::GetPrefUserBranch() ++{ ++ if (mCachedUserPrefBranch) { ++ NS_ADDREF(mCachedUserPrefBranch); ++ return mCachedUserPrefBranch; ++ } ++ ++ nsresult rv; ++ nsCOMPtr prefService = ++ do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); ++ if (NS_FAILED(rv)) ++ return nsnull; ++ nsCOMPtr prefBranch; ++ rv = prefService->GetBranch(nsnull, getter_AddRefs(prefBranch)); ++ if (NS_FAILED(rv)) ++ return nsnull; ++ nsCOMPtr pb2(do_QueryInterface(prefBranch)); ++ if (!pb2) ++ return nsnull; ++ ++ nsIPrefBranch2* result = nsnull; ++ pb2.swap(result); ++ return result; ++} ++ ++already_AddRefed ++nsSystemPref::GetPrefDefaultBranch() ++{ ++ if (mCachedDefaultPrefBranch) { ++ NS_ADDREF(mCachedDefaultPrefBranch); ++ return mCachedDefaultPrefBranch; ++ } ++ ++ nsresult rv; ++ nsCOMPtr prefService = ++ do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); ++ if (NS_FAILED(rv)) ++ return nsnull; ++ nsCOMPtr prefBranch; ++ rv = prefService->GetDefaultBranch(nsnull, getter_AddRefs(prefBranch)); ++ if (NS_FAILED(rv)) ++ return nsnull; ++ nsIPrefBranch* pb = nsnull; ++ prefBranch.swap(pb); ++ return pb; ++} ++ + /////////////////////////////////////////////////////////////////////////////// + // nsSystemPref::Observe + // Observe notifications from mozilla pref system and system prefs (if enabled) + /////////////////////////////////////////////////////////////////////////////// + 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 userBranch = GetPrefUserBranch(); ++ nsCOMPtr 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 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 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(aClosure); ++ nsCOMPtr userBranch = prefs->GetPrefUserBranch(); ++ const nsCString& prefName = PromiseFlatCString(aKey); ++ ++ PRInt32 prefType = nsIPrefBranch::PREF_INVALID; ++ nsresult rv = userBranch->GetPrefType(prefName.get(), &prefType); ++ if (NS_FAILED(rv)) ++ return PL_DHASH_NEXT; ++ PRBool isLocked; ++ userBranch->PrefIsLocked(prefName.get(), &isLocked); ++ if (NS_FAILED(rv)) ++ return PL_DHASH_NEXT; ++ ++ ++ // 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 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 userBranch = GetPrefUserBranch(); ++ nsCOMPtr 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(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 prefBranch +- (do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); ++ nsCOMPtr userPrefs = GetPrefUserBranch(); ++ nsCOMPtr defaultPrefs = GetPrefUserBranch(); ++ PRUint32 childCount; ++ char **childArray = nsnull; ++ nsresult rv = userPrefs->GetChildList("config.lockdown.", ++ &childCount, &childArray); + if (NS_FAILED(rv)) + return rv; +- +- 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 userBranch = GetPrefUserBranch(); ++ nsCOMPtr 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 prefBranch = +- do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); +- if (NS_FAILED(rv)) +- return rv; ++ nsCOMPtr userBranch = GetPrefUserBranch(); ++ nsCOMPtr 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 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 ++#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 GetPrefUserBranch(); ++ virtual already_AddRefed GetPrefDefaultBranch(); ++ + private: +- // funcs used to load system prefs and save mozilla default prefs +- nsresult UseSystemPrefs(); +- nsresult ReadSystemPref(const char *aPrefName); +- nsresult SaveMozDefaultPref(const char *aPrefName, +- MozPrefValue *aPrefVal, +- PRBool *aLocked); ++ // 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 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 mSysPrefService; ++ nsClassHashtable mSavedPrefs; ++ // weak pointers to cached prefbranches ++ nsIPrefBranch2* mCachedUserPrefBranch; ++ nsIPrefBranch* mCachedDefaultPrefBranch; ++ PRPackedBool mIgnorePrefSetting; + }; + + #define NS_SYSTEMPREF_CID \ + { /* {549abb24-7c9d-4aba-915e-7ce0b716b32f} */ \ + 0x549abb24, \ + 0x7c9d, \ + 0x4aba, \ + { 0x91, 0x5e, 0x7c, 0xe0, 0xb7, 0x16, 0xb3, 0x2f } \ +diff --git a/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp b/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp +--- a/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp ++++ b/extensions/pref/system-pref/src/nsSystemPrefFactory.cpp +@@ -37,20 +37,20 @@ + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + #include "nsICategoryManager.h" + #include "nsIGenericFactory.h" + #include "nsSystemPref.h" +-#include "nsSystemPrefService.h" ++#include "nsIServiceManager.h" ++#include "nsIAppStartupNotifier.h" + + NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPref, Init) +-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemPrefService, Init) + + // Registering nsSystemPref module as part of the app-startup category to get + // it instantiated. + + static NS_METHOD + RegisterSystemPref(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, +@@ -91,16 +91,11 @@ UnRegisterSystemPref(nsIComponentManager + static const nsModuleComponentInfo components[] = { + { NS_SYSTEMPREF_CLASSNAME, + NS_SYSTEMPREF_CID, + NS_SYSTEMPREF_CONTRACTID, + nsSystemPrefConstructor, + RegisterSystemPref, + UnRegisterSystemPref, + }, +- { NS_SYSTEMPREF_SERVICE_CLASSNAME, +- NS_SYSTEMPREF_SERVICE_CID, +- NS_SYSTEMPREF_SERVICE_CONTRACTID, +- nsSystemPrefServiceConstructor, +- }, + }; + + NS_IMPL_NSGETMODULE(nsSystemPrefModule, components) +diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in +--- a/toolkit/library/Makefile.in ++++ b/toolkit/library/Makefile.in +@@ -229,16 +229,20 @@ endif + ifdef NS_OSSO + EXTRA_DSO_LDOPTS += $(LIBOSSO_LIBS) + endif + + ifdef MOZ_ENABLE_DBUS + EXTRA_DSO_LDOPTS += $(MOZ_DBUS_GLIB_LIBS) + endif + ++ifdef MOZ_ENABLE_GCONF ++EXTRA_DSO_LDOPTS += $(MOZ_GCONF_LIBS) ++endif ++ + ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT)) + EXTRA_DSO_LDOPTS += $(XLDFLAGS) $(XLIBS) $(XEXT_LIBS) $(XCOMPOSITE_LIBS) $(MOZ_PANGO_LIBS) $(MOZ_GTK2_LIBS) $(XT_LIBS) -lgthread-2.0 + EXTRA_DSO_LDOPTS += $(FT2_LIBS) + endif + + ifeq (qt,$(MOZ_WIDGET_TOOLKIT)) + EXTRA_DSO_LDOPTS += $(XLDFLAGS) $(XLIBS) $(XT_LIBS) $(MOZ_QT_LIBS) -lgthread-2.0 + EXTRA_DSO_LDOPTS += $(FT2_LIBS) +diff --git a/toolkit/toolkit-tiers.mk b/toolkit/toolkit-tiers.mk +--- a/toolkit/toolkit-tiers.mk ++++ b/toolkit/toolkit-tiers.mk +@@ -253,16 +253,23 @@ endif + ifdef MOZ_ENABLE_LIBXUL + tier_toolkit_dirs += xpcom/stub + endif + + ifdef NS_TRACE_MALLOC + tier_toolkit_dirs += tools/trace-malloc + endif + ++# gconf module is external ++ifdef MOZ_PREF_EXTENSIONS ++ifdef MOZ_ENABLE_GCONF ++tier_toolkit_dirs += extensions/pref/system-pref/src/gconf ++endif ++endif ++ + ifdef MOZ_ENABLE_GNOME_COMPONENT + tier_toolkit_dirs += toolkit/system/gnome + endif + + ifndef MOZ_ENABLE_LIBCONIC + # if libconic is present, it will do its own network monitoring + ifdef MOZ_ENABLE_DBUS + tier_toolkit_dirs += toolkit/system/dbus diff -r c62859a2fd22 -r ca988be0905b mozilla-xulrunner192/gconf-backend.patch.bz2 --- a/mozilla-xulrunner192/gconf-backend.patch.bz2 Wed Dec 16 07:34:53 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../old/gconf-backend.patch.bz2 \ No newline at end of file diff -r c62859a2fd22 -r ca988be0905b mozilla-xulrunner192/gecko-lockdown.patch --- a/mozilla-xulrunner192/gecko-lockdown.patch Wed Dec 16 07:34:53 2009 +0100 +++ b/mozilla-xulrunner192/gecko-lockdown.patch Sat Dec 19 21:51:16 2009 +0100 @@ -1,1 +1,1 @@ -../old/gecko-lockdown.patch \ No newline at end of file +../gecko-lockdown.patch \ No newline at end of file diff -r c62859a2fd22 -r ca988be0905b mozilla-xulrunner192/mozilla-gconf-backend.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mozilla-xulrunner192/mozilla-gconf-backend.patch Sat Dec 19 21:51:16 2009 +0100 @@ -0,0 +1,1 @@ +../mozilla-gconf-backend.patch \ No newline at end of file diff -r c62859a2fd22 -r ca988be0905b mozilla-xulrunner192/mozilla-xulrunner192.spec --- a/mozilla-xulrunner192/mozilla-xulrunner192.spec Wed Dec 16 07:34:53 2009 +0100 +++ b/mozilla-xulrunner192/mozilla-xulrunner192.spec Sat Dec 19 21:51:16 2009 +0100 @@ -76,11 +76,10 @@ Patch8: mozilla-shared-nss-db.patch Patch9: mozilla-startup-notification.patch Patch10: mozilla-kde.patch -# PATCH-FEATURE-SLED FATE#302023, FATE#302024 - hfiguiere@novell.com -# --- disabled for now -Patch16: gconf-backend.patch.bz2 -Patch17: gecko-lockdown.patch -Patch18: toolkit-ui-lockdown.patch +# PATCH-FEATURE-SLED FATE#302023, FATE#302024 +Patch11: mozilla-gconf-backend.patch +Patch12: gecko-lockdown.patch +Patch13: toolkit-ui-lockdown.patch # --- BuildRoot: %{_tmppath}/%{name}-%{version}-build PreReq: update-alternatives coreutils @@ -193,11 +192,9 @@ %if %suse_version >= 1110 %patch10 -p1 %endif -# BEGIN lockdown - currently broken (see bnc#508611) -#%patch16 -p1 -#%patch17 -#%patch18 -p1 -# END lockdown +#%patch11 -p1 +#%patch12 -p1 +#%patch13 -p1 %build %if %suse_version >= 1110 diff -r c62859a2fd22 -r ca988be0905b mozilla-xulrunner192/toolkit-ui-lockdown.patch --- a/mozilla-xulrunner192/toolkit-ui-lockdown.patch Wed Dec 16 07:34:53 2009 +0100 +++ b/mozilla-xulrunner192/toolkit-ui-lockdown.patch Sat Dec 19 21:51:16 2009 +0100 @@ -1,1 +1,1 @@ -../old/toolkit-ui-lockdown.patch \ No newline at end of file +../toolkit-ui-lockdown.patch \ No newline at end of file diff -r c62859a2fd22 -r ca988be0905b old/gconf-backend.patch.bz2 Binary file old/gconf-backend.patch.bz2 has changed diff -r c62859a2fd22 -r ca988be0905b old/gecko-lockdown.patch --- a/old/gecko-lockdown.patch Wed Dec 16 07:34:53 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,319 +0,0 @@ -From: Robert O'Callahan -Subject: Lockdown feature for Gecko -References: - - -Index: extensions/cookie/nsCookiePermission.cpp -=================================================================== ---- extensions/cookie/nsCookiePermission.cpp.orig -+++ extensions/cookie/nsCookiePermission.cpp -@@ -86,6 +86,7 @@ static const char kCookiesPrefsMigrated[ - // obsolete pref names for migration - static const char kCookiesLifetimeEnabled[] = "network.cookie.lifetime.enabled"; - static const char kCookiesLifetimeBehavior[] = "network.cookie.lifetime.behavior"; -+static const char kCookiesHonorExceptions[] = "network.cookie.honorExceptions"; - static const char kCookiesAskPermission[] = "network.cookie.warnAboutCookies"; - - static const char kPermissionType[] = "cookie"; -@@ -125,6 +126,7 @@ nsCookiePermission::Init() - prefBranch->AddObserver(kCookiesLifetimePolicy, this, PR_FALSE); - prefBranch->AddObserver(kCookiesLifetimeDays, this, PR_FALSE); - prefBranch->AddObserver(kCookiesAlwaysAcceptSession, this, PR_FALSE); -+ prefBranch->AddObserver(kCookiesHonorExceptions, this, PR_FALSE); - #ifdef MOZ_MAIL_NEWS - prefBranch->AddObserver(kCookiesDisabledForMailNews, this, PR_FALSE); - #endif -@@ -182,6 +184,10 @@ nsCookiePermission::PrefChanged(nsIPrefB - NS_SUCCEEDED(aPrefBranch->GetBoolPref(kCookiesAlwaysAcceptSession, &val))) - mCookiesAlwaysAcceptSession = val; - -+ if (PREF_CHANGED(kCookiesHonorExceptions) && -+ NS_SUCCEEDED(aPrefBranch->GetBoolPref(kCookiesHonorExceptions, &val))) -+ mCookiesHonorExceptions = val; -+ - #ifdef MOZ_MAIL_NEWS - if (PREF_CHANGED(kCookiesDisabledForMailNews) && - NS_SUCCEEDED(aPrefBranch->GetBoolPref(kCookiesDisabledForMailNews, &val))) -@@ -232,6 +238,11 @@ nsCookiePermission::CanAccess(nsIURI - #endif // MOZ_MAIL_NEWS - - // finally, check with permission manager... -+ if (!mCookiesHonorExceptions) { -+ *aResult = ACCESS_DEFAULT; -+ return NS_OK; -+ } -+ - nsresult rv = mPermMgr->TestPermission(aURI, kPermissionType, (PRUint32 *) aResult); - if (NS_SUCCEEDED(rv)) { - switch (*aResult) { -Index: extensions/cookie/nsCookiePermission.h -=================================================================== ---- extensions/cookie/nsCookiePermission.h.orig -+++ extensions/cookie/nsCookiePermission.h -@@ -61,6 +61,7 @@ public: - #ifdef MOZ_MAIL_NEWS - , mCookiesDisabledForMailNews(PR_TRUE) - #endif -+ , mCookiesHonorExceptions(PR_TRUE) - {} - virtual ~nsCookiePermission() {} - -@@ -76,7 +77,7 @@ private: - #ifdef MOZ_MAIL_NEWS - PRPackedBool mCookiesDisabledForMailNews; - #endif -- -+ PRPackedBool mCookiesHonorExceptions; - }; - - // {EF565D0A-AB9A-4A13-9160-0644CDFD859A} -Index: extensions/permissions/nsContentBlocker.cpp -=================================================================== ---- extensions/permissions/nsContentBlocker.cpp.orig -+++ extensions/permissions/nsContentBlocker.cpp -@@ -76,6 +76,7 @@ NS_IMPL_ISUPPORTS3(nsContentBlocker, - nsContentBlocker::nsContentBlocker() - { - memset(mBehaviorPref, BEHAVIOR_ACCEPT, NUMBER_OF_TYPES); -+ memset(mHonorExceptions, PR_TRUE, NUMBER_OF_TYPES); - } - - nsresult -@@ -92,6 +93,11 @@ nsContentBlocker::Init() - rv = prefService->GetBranch("permissions.default.", getter_AddRefs(prefBranch)); - NS_ENSURE_SUCCESS(rv, rv); - -+ nsCOMPtr honorExceptionsPrefBranch; -+ rv = prefService->GetBranch("permissions.honorExceptions.", -+ getter_AddRefs(honorExceptionsPrefBranch)); -+ NS_ENSURE_SUCCESS(rv, rv); -+ - // Migrate old image blocker pref - nsCOMPtr oldPrefBranch; - oldPrefBranch = do_QueryInterface(prefService); -@@ -121,8 +127,15 @@ nsContentBlocker::Init() - mPrefBranchInternal = do_QueryInterface(prefBranch, &rv); - NS_ENSURE_SUCCESS(rv, rv); - -+ mHonorExceptionsPrefBranchInternal = -+ do_QueryInterface(honorExceptionsPrefBranch, &rv); -+ NS_ENSURE_SUCCESS(rv, rv); -+ - rv = mPrefBranchInternal->AddObserver("", this, PR_TRUE); -- PrefChanged(prefBranch, nsnull); -+ NS_ENSURE_SUCCESS(rv, rv); -+ -+ rv = mHonorExceptionsPrefBranchInternal->AddObserver("", this, PR_TRUE); -+ PrefChanged(nsnull); - - return rv; - } -@@ -131,19 +144,22 @@ nsContentBlocker::Init() - #define LIMIT(x, low, high, default) ((x) >= (low) && (x) <= (high) ? (x) : (default)) - - void --nsContentBlocker::PrefChanged(nsIPrefBranch *aPrefBranch, -- const char *aPref) -+nsContentBlocker::PrefChanged(const char *aPref) - { -- PRInt32 val; -- --#define PREF_CHANGED(_P) (!aPref || !strcmp(aPref, _P)) -- -- for(PRUint32 i = 0; i < NUMBER_OF_TYPES; ++i) { -- if (PREF_CHANGED(kTypeString[i]) && -- NS_SUCCEEDED(aPrefBranch->GetIntPref(kTypeString[i], &val))) -- mBehaviorPref[i] = LIMIT(val, 1, 3, 1); -+ for (PRUint32 i = 0; i < NUMBER_OF_TYPES; ++i) { -+ if (!aPref || !strcmp(kTypeString[i], aPref)) { -+ PRInt32 val; -+ PRBool b; -+ if (mPrefBranchInternal && -+ NS_SUCCEEDED(mPrefBranchInternal->GetIntPref(kTypeString[i], &val))) { -+ mBehaviorPref[i] = LIMIT(val, 1, 3, 1); -+ } -+ if (mHonorExceptionsPrefBranchInternal && -+ NS_SUCCEEDED(mHonorExceptionsPrefBranchInternal->GetBoolPref(kTypeString[i], &b))) { -+ mHonorExceptions[i] = b; -+ } -+ } - } -- - } - - // nsIContentPolicy Implementation -@@ -268,11 +284,13 @@ nsContentBlocker::TestPermission(nsIURI - // default prefs. - // Don't forget the aContentType ranges from 1..8, while the - // array is indexed 0..7 -- PRUint32 permission; -- nsresult rv = mPermissionManager->TestPermission(aCurrentURI, -- kTypeString[aContentType - 1], -- &permission); -- NS_ENSURE_SUCCESS(rv, rv); -+ PRUint32 permission = 0; -+ if (mHonorExceptions[aContentType - 1]) { -+ nsresult rv = mPermissionManager->TestPermission(aCurrentURI, -+ kTypeString[aContentType - 1], -+ &permission); -+ NS_ENSURE_SUCCESS(rv, rv); -+ } - - // If there is nothing on the list, use the default. - if (!permission) { -@@ -298,7 +316,7 @@ nsContentBlocker::TestPermission(nsIURI - return NS_OK; - - PRBool trustedSource = PR_FALSE; -- rv = aFirstURI->SchemeIs("chrome", &trustedSource); -+ nsresult rv = aFirstURI->SchemeIs("chrome", &trustedSource); - NS_ENSURE_SUCCESS(rv,rv); - if (!trustedSource) { - rv = aFirstURI->SchemeIs("resource", &trustedSource); -@@ -363,8 +381,6 @@ nsContentBlocker::Observe(nsISupports - { - NS_ASSERTION(!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic), - "unexpected topic - we only deal with pref changes!"); -- -- if (mPrefBranchInternal) -- PrefChanged(mPrefBranchInternal, NS_LossyConvertUTF16toASCII(aData).get()); -+ PrefChanged(NS_LossyConvertUTF16toASCII(aData).get()); - return NS_OK; - } -Index: extensions/permissions/nsContentBlocker.h -=================================================================== ---- extensions/permissions/nsContentBlocker.h.orig -+++ extensions/permissions/nsContentBlocker.h -@@ -66,7 +66,7 @@ public: - private: - ~nsContentBlocker() {} - -- void PrefChanged(nsIPrefBranch *, const char *); -+ void PrefChanged(const char *); - nsresult TestPermission(nsIURI *aCurrentURI, - nsIURI *aFirstURI, - PRInt32 aContentType, -@@ -75,7 +75,9 @@ private: - - nsCOMPtr mPermissionManager; - nsCOMPtr mPrefBranchInternal; -+ nsCOMPtr mHonorExceptionsPrefBranchInternal; - PRUint8 mBehaviorPref[NUMBER_OF_TYPES]; -+ PRPackedBool mHonorExceptions[NUMBER_OF_TYPES]; - }; - - #define NS_CONTENTBLOCKER_CID \ -Index: modules/libpref/src/init/all.js -=================================================================== ---- modules/libpref/src/init/all.js.orig -+++ modules/libpref/src/init/all.js -@@ -798,6 +798,7 @@ pref("network.automatic-ntlm-auth.truste - pref("network.ntlm.send-lm-response", false); - - pref("permissions.default.image", 1); // 1-Accept, 2-Deny, 3-dontAcceptForeign -+pref("permissions.honorExceptions.image", true); - - #ifndef XP_MACOSX - #ifdef XP_UNIX -@@ -825,6 +826,7 @@ pref("network.proxy.no_proxies_on", - pref("network.proxy.failover_timeout", 1800); // 30 minutes - pref("network.online", true); //online/offline - pref("network.cookie.cookieBehavior", 0); // 0-Accept, 1-dontAcceptForeign, 2-dontUse -+pref("network.cookie.honorExceptions", true); - pref("network.cookie.disableCookieForMailNews", true); // disable all cookies for mail - pref("network.cookie.lifetimePolicy", 0); // accept normally, 1-askBeforeAccepting, 2-acceptForSession,3-acceptForNDays - pref("network.cookie.alwaysAcceptSessionCookies", false); -Index: widget/src/gtk2/nsWindow.cpp -=================================================================== ---- widget/src/gtk2/nsWindow.cpp.orig -+++ widget/src/gtk2/nsWindow.cpp -@@ -81,6 +81,7 @@ - #include "nsIServiceManager.h" - #include "nsIStringBundle.h" - #include "nsGfxCIID.h" -+#include "nsIPrefService.h" - - #ifdef ACCESSIBILITY - #include "nsIAccessibilityService.h" -@@ -91,7 +92,6 @@ - static PRBool sAccessibilityChecked = PR_FALSE; - /* static */ - PRBool nsWindow::sAccessibilityEnabled = PR_FALSE; --static const char sSysPrefService [] = "@mozilla.org/system-preference-service;1"; - static const char sAccEnv [] = "GNOME_ACCESSIBILITY"; - static const char sAccessibilityKey [] = "config.use_system_prefs.accessibility"; - #endif -@@ -3992,18 +3992,18 @@ nsWindow::NativeCreate(nsIWidget - sAccessibilityEnabled = atoi(envValue) != 0; - LOG(("Accessibility Env %s=%s\n", sAccEnv, envValue)); - } -- //check gconf-2 setting -+ //check preference setting - else { -- nsCOMPtr sysPrefService = -- do_GetService(sSysPrefService, &rv); -- if (NS_SUCCEEDED(rv) && sysPrefService) { -- -- // do the work to get gconf setting. -- // will be done soon later. -- sysPrefService->GetBoolPref(sAccessibilityKey, -+ nsCOMPtr prefService = -+ do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); -+ if (NS_SUCCEEDED(rv) && prefService) { -+ nsCOMPtr prefBranch; -+ rv = prefService->GetBranch(nsnull, getter_AddRefs(prefBranch)); -+ if (NS_SUCCEEDED(rv) && prefBranch) { -+ prefBranch->GetBoolPref(sAccessibilityKey, - &sAccessibilityEnabled); -+ } - } -- - } - } - if (sAccessibilityEnabled) { -Index: xpinstall/src/nsXPInstallManager.cpp -=================================================================== ---- xpinstall/src/nsXPInstallManager.cpp.orig -+++ xpinstall/src/nsXPInstallManager.cpp -@@ -290,6 +290,7 @@ nsXPInstallManager::InitManagerInternal( - //----------------------------------------------------- - // Get permission to install - //----------------------------------------------------- -+ nsCOMPtr pref(do_GetService(NS_PREFSERVICE_CONTRACTID)); - - #ifdef ENABLE_SKIN_SIMPLE_INSTALLATION_UI - if ( mChromeType == CHROME_SKIN ) -@@ -299,17 +300,26 @@ nsXPInstallManager::InitManagerInternal( - - // skins get a simpler/friendlier dialog - // XXX currently not embeddable -- OKtoInstall = ConfirmChromeInstall( mParentWindow, packageList ); -+ PRBool themesDisabled = PR_FALSE; -+ if (pref) -+ pref->GetBoolPref("config.lockdown.disable_themes", &themesDisabled); -+ OKtoInstall = !themesDisabled && -+ ConfirmChromeInstall( mParentWindow, packageList ); - } - else - { - #endif -- rv = dlgSvc->ConfirmInstall( mParentWindow, -- packageList, -- numStrings, -- &OKtoInstall ); -- if (NS_FAILED(rv)) -- OKtoInstall = PR_FALSE; -+ PRBool extensionsDisabled = PR_FALSE; -+ if (pref) -+ pref->GetBoolPref("config.lockdown.disable_extensions", &extensionsDisabled); -+ if (!extensionsDisabled) { -+ rv = dlgSvc->ConfirmInstall( mParentWindow, -+ packageList, -+ numStrings, -+ &OKtoInstall ); -+ if (NS_FAILED(rv)) -+ OKtoInstall = PR_FALSE; -+ } - #ifdef ENABLE_SKIN_SIMPLE_INSTALLATION_UI - } - #endif diff -r c62859a2fd22 -r ca988be0905b old/toolkit-ui-lockdown.patch --- a/old/toolkit-ui-lockdown.patch Wed Dec 16 07:34:53 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -From: Robert O'Callahan -Subject: Lockdown feature for Toolkit UI -References: - -diff --git a/toolkit/components/passwordmgr/content/passwordManager.js b/toolkit/components/passwordmgr/content/passwordManager.js ---- a/toolkit/components/passwordmgr/content/passwordManager.js -+++ b/toolkit/components/passwordmgr/content/passwordManager.js -@@ -120,8 +120,17 @@ function LoadSignons() { - // disable "remove all signons" button if there are no signons - var element = document.getElementById("removeAllSignons"); - var toggle = document.getElementById("togglePasswords"); -+ try { -+ var viewLocked = Components.classes["@mozilla.org/preferences-service;1"] -+ .getService(Components.interfaces.nsIPrefBranch) -+ .getBoolPref("config.lockdown.showsavedpasswords"); -+ } catch (e) { -+ var viewLocked = false; -+ } - if (signons.length == 0 || gSelectUserInUse) { - element.setAttribute("disabled","true"); -+ toggle.setAttribute("disabled","true"); -+ } else if (viewLocked) { - toggle.setAttribute("disabled","true"); - } else { - element.removeAttribute("disabled"); -@@ -167,6 +176,18 @@ function DeleteAllSignons() { - } - - function TogglePasswordVisible() { -+ try { -+ var viewLocked = Components.classes["@mozilla.org/preferences-service;1"] -+ .getService(Components.interfaces.nsIPrefBranch) -+ .getBoolPref("config.lockdown.showsavedpasswords"); -+ } catch (e) { -+ var viewLocked = false; -+ } -+ // at that point if viewLocked is true, we shouldn't reach this code, -+ // but better be safe than sorry. -+ if (viewLocked) { -+ return; -+ } - if (showingPasswords || ConfirmShowPasswords()) { - showingPasswords = !showingPasswords; - document.getElementById("togglePasswords").label = kSignonBundle.getString(showingPasswords ? "hidePasswords" : "showPasswords"); -diff --git a/toolkit/components/printing/content/printdialog.js b/toolkit/components/printing/content/printdialog.js ---- a/toolkit/components/printing/content/printdialog.js -+++ b/toolkit/components/printing/content/printdialog.js -@@ -50,6 +50,7 @@ var gWebBrowserPrint = null; - var gWebBrowserPrint = null; - var gPrintSetInterface = Components.interfaces.nsIPrintSettings; - var doDebug = false; -+var gPrefService = null; - - //--------------------------------------------------- - function initDialog() -@@ -87,11 +88,23 @@ function initDialog() - dialog.fpDialog = document.getElementById("fpDialog"); - - dialog.enabled = false; -+ -+ gPrefService = Components.classes["@mozilla.org/preferences-service;1"] -+ .getService(Components.interfaces.nsIPrefService).getBranch(null); -+ if (gPrefService.getBoolPref("config.lockdown.savepage")) { -+ dialog.fileCheck.setAttribute("disabled", "true"); -+ } -+ if (gPrefService.getBoolPref("config.lockdown.printing")) { -+ dialog.printButton.setAttribute("disabled", "true"); -+ } - } - - //--------------------------------------------------- - function checkInteger(element) - { -+ if (gPrefService.getBoolPref("config.lockdown.printing")) -+ return; -+ - var value = element.value; - if (value && value.length > 0) { - value = value.replace(/[^0-9]/g,""); diff -r c62859a2fd22 -r ca988be0905b series --- a/series Wed Dec 16 07:34:53 2009 +0100 +++ b/series Sat Dec 19 21:51:16 2009 +0100 @@ -9,6 +9,9 @@ mozilla-shared-nss-db.patch mozilla-startup-notification.patch mozilla-kde.patch +mozilla-gconf-backend.patch +gecko-lockdown.patch +toolkit-ui-lockdown.patch # Firefox patches firefox-libxul-sdk.patch diff -r c62859a2fd22 -r ca988be0905b toolkit-ui-lockdown.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolkit-ui-lockdown.patch Sat Dec 19 21:51:16 2009 +0100 @@ -0,0 +1,119 @@ +From: various contributors +Subject: toolkit ui lockdown hooks + +diff --git a/toolkit/components/passwordmgr/content/passwordManager.js b/toolkit/components/passwordmgr/content/passwordManager.js +--- a/toolkit/components/passwordmgr/content/passwordManager.js ++++ b/toolkit/components/passwordmgr/content/passwordManager.js +@@ -119,19 +119,28 @@ function LoadSignons() { + // SignonColumnSort) assumes we want to toggle the sort + // direction but here we don't so we have to trick it + lastSignonSortAscending = !lastSignonSortAscending; + SignonColumnSort(lastSignonSortColumn); + + // disable "remove all signons" button if there are no signons + var element = document.getElementById("removeAllSignons"); + var toggle = document.getElementById("togglePasswords"); ++ try { ++ var viewLocked = Components.classes["@mozilla.org/preferences-service;1"] ++ .getService(Components.interfaces.nsIPrefBranch) ++ .getBoolPref("config.lockdown.showsavedpasswords"); ++ } catch (e) { ++ var viewLocked = false; ++ } + if (signons.length == 0 || gSelectUserInUse) { + element.setAttribute("disabled","true"); + toggle.setAttribute("disabled","true"); ++ } else if (viewLocked) { ++ toggle.setAttribute("disabled","true"); + } else { + element.removeAttribute("disabled"); + toggle.removeAttribute("disabled"); + } + + return true; + } + +@@ -166,16 +175,28 @@ function DeleteAllSignons() { + var syncNeeded = (signonsTreeView._filterSet.length != 0); + DeleteAllFromTree(signonsTree, signonsTreeView, + signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons, + deletedSignons, "removeSignon", "removeAllSignons"); + FinalizeSignonDeletions(syncNeeded); + } + + function TogglePasswordVisible() { ++ try { ++ var viewLocked = Components.classes["@mozilla.org/preferences-service;1"] ++ .getService(Components.interfaces.nsIPrefBranch) ++ .getBoolPref("config.lockdown.showsavedpasswords"); ++ } catch (e) { ++ var viewLocked = false; ++ } ++ // at that point if viewLocked is true, we shouldn't reach this code, ++ // but better be safe than sorry. ++ if (viewLocked) { ++ return; ++ } + if (showingPasswords || ConfirmShowPasswords()) { + showingPasswords = !showingPasswords; + document.getElementById("togglePasswords").label = kSignonBundle.getString(showingPasswords ? "hidePasswords" : "showPasswords"); + document.getElementById("togglePasswords").accessKey = kSignonBundle.getString(showingPasswords ? "hidePasswordsAccessKey" : "showPasswordsAccessKey"); + document.getElementById("passwordCol").hidden = !showingPasswords; + _filterPasswords(); + } + +diff --git a/toolkit/components/printing/content/printdialog.js b/toolkit/components/printing/content/printdialog.js +--- a/toolkit/components/printing/content/printdialog.js ++++ b/toolkit/components/printing/content/printdialog.js +@@ -45,16 +45,17 @@ var printService = null; + var gOriginalNumCopies = 1; + + var paramBlock; + var gPrefs = null; + var gPrintSettings = null; + var gWebBrowserPrint = null; + var gPrintSetInterface = Components.interfaces.nsIPrintSettings; + var doDebug = false; ++var gPrefService = null; + + //--------------------------------------------------- + function initDialog() + { + dialog = new Object; + + dialog.propertiesButton = document.getElementById("properties"); + dialog.descText = document.getElementById("descText"); +@@ -82,21 +83,33 @@ function initDialog() + + dialog.printButton = document.documentElement.getButton("accept"); + + // elements + dialog.printName = document.getElementById("printButton"); + dialog.fpDialog = document.getElementById("fpDialog"); + + dialog.enabled = false; ++ ++ gPrefService = Components.classes["@mozilla.org/preferences-service;1"] ++ .getService(Components.interfaces.nsIPrefService).getBranch(null); ++ if (gPrefService.getBoolPref("config.lockdown.savepage")) { ++ dialog.fileCheck.setAttribute("disabled", "true"); ++ } ++ if (gPrefService.getBoolPref("config.lockdown.printing")) { ++ dialog.printButton.setAttribute("disabled", "true"); ++ } + } + + //--------------------------------------------------- + function checkInteger(element) + { ++ if (gPrefService.getBoolPref("config.lockdown.printing")) ++ return; ++ + var value = element.value; + if (value && value.length > 0) { + value = value.replace(/[^0-9]/g,""); + if (!value) value = ""; + element.value = value; + } + if (!value || value < 1 || value > 999) + dialog.printButton.setAttribute("disabled","true");