summaryrefslogtreecommitdiffstats
path: root/extensions/pref
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/pref')
-rw-r--r--extensions/pref/autoconfig/moz.build9
-rw-r--r--extensions/pref/autoconfig/public/moz.build13
-rw-r--r--extensions/pref/autoconfig/public/nsIAutoConfig.idl26
-rw-r--r--extensions/pref/autoconfig/public/nsIReadConfig.idl24
-rw-r--r--extensions/pref/autoconfig/src/moz.build18
-rw-r--r--extensions/pref/autoconfig/src/nsAutoConfig.cpp532
-rw-r--r--extensions/pref/autoconfig/src/nsAutoConfig.h54
-rw-r--r--extensions/pref/autoconfig/src/nsConfigFactory.cpp41
-rw-r--r--extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp138
-rw-r--r--extensions/pref/autoconfig/src/nsReadConfig.cpp300
-rw-r--r--extensions/pref/autoconfig/src/nsReadConfig.h41
-rw-r--r--extensions/pref/autoconfig/src/prefcalls.js230
-rw-r--r--extensions/pref/autoconfig/test/unit/autoconfig-latin1.cfg6
-rw-r--r--extensions/pref/autoconfig/test/unit/autoconfig-utf8.cfg6
-rw-r--r--extensions/pref/autoconfig/test/unit/autoconfig.js4
-rw-r--r--extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js97
-rw-r--r--extensions/pref/autoconfig/test/unit/xpcshell.ini10
-rw-r--r--extensions/pref/moz.build8
18 files changed, 1557 insertions, 0 deletions
diff --git a/extensions/pref/autoconfig/moz.build b/extensions/pref/autoconfig/moz.build
new file mode 100644
index 000000000..632913a1c
--- /dev/null
+++ b/extensions/pref/autoconfig/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += ['public', 'src']
+
+XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
diff --git a/extensions/pref/autoconfig/public/moz.build b/extensions/pref/autoconfig/public/moz.build
new file mode 100644
index 000000000..467f0c475
--- /dev/null
+++ b/extensions/pref/autoconfig/public/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPIDL_SOURCES += [
+ 'nsIAutoConfig.idl',
+ 'nsIReadConfig.idl',
+]
+
+XPIDL_MODULE = 'autoconfig'
+
diff --git a/extensions/pref/autoconfig/public/nsIAutoConfig.idl b/extensions/pref/autoconfig/public/nsIAutoConfig.idl
new file mode 100644
index 000000000..e76dc0614
--- /dev/null
+++ b/extensions/pref/autoconfig/public/nsIAutoConfig.idl
@@ -0,0 +1,26 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+
+%{C++
+
+#define NS_AUTOCONFIG_CID\
+ { 0xe036c738,\
+ 0x1dd1,\
+ 0x11b2,\
+ { 0x93, 0x92, 0x9d, 0x94, 0xaa, 0x74, 0xb0, 0xc5 }\
+ }
+
+#define NS_AUTOCONFIG_CONTRACTID \
+ "@mozilla.org/autoconfiguration;1"
+
+%}
+
+[uuid (80DB54AE-13F2-11d5-BE44-00108335A220)]
+interface nsIAutoConfig : nsISupports {
+ attribute string configURL;
+};
diff --git a/extensions/pref/autoconfig/public/nsIReadConfig.idl b/extensions/pref/autoconfig/public/nsIReadConfig.idl
new file mode 100644
index 000000000..e00c06e52
--- /dev/null
+++ b/extensions/pref/autoconfig/public/nsIReadConfig.idl
@@ -0,0 +1,24 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+%{C++
+
+#define NS_READCONFIG_CID\
+ { 0xba5bc4c6,\
+ 0x1dd1, \
+ 0x11b2, \
+ { 0xbb, 0x89, 0xb8, 0x44, 0xc6, 0xec, 0x03, 0x39 }\
+ }
+
+#define NS_READCONFIG_CONTRACTID \
+ "@mozilla.org/readconfig;1"
+
+%}
+
+[uuid (ba5bc4c6-1dd1-11b2-bb89-b844c6ec0339)]
+interface nsIReadConfig : nsISupports {
+};
diff --git a/extensions/pref/autoconfig/src/moz.build b/extensions/pref/autoconfig/src/moz.build
new file mode 100644
index 000000000..3417269f0
--- /dev/null
+++ b/extensions/pref/autoconfig/src/moz.build
@@ -0,0 +1,18 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+ 'nsAutoConfig.cpp',
+ 'nsConfigFactory.cpp',
+ 'nsJSConfigTriggers.cpp',
+ 'nsReadConfig.cpp',
+]
+
+FINAL_LIBRARY = 'xul'
+
+FINAL_TARGET_FILES.defaults.autoconfig += [
+ 'prefcalls.js',
+]
diff --git a/extensions/pref/autoconfig/src/nsAutoConfig.cpp b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
new file mode 100644
index 000000000..08f406093
--- /dev/null
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
@@ -0,0 +1,532 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsAutoConfig.h"
+#include "nsIURI.h"
+#include "nsIHttpChannel.h"
+#include "nsIFileStreams.h"
+#include "nsThreadUtils.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "prmem.h"
+#include "nsIObserverService.h"
+#include "nsLiteralString.h"
+#include "nsIPromptService.h"
+#include "nsIServiceManager.h"
+#include "nsIStringBundle.h"
+#include "nsContentUtils.h"
+#include "nsCRT.h"
+#include "nsNetCID.h"
+#include "nsNetUtil.h"
+#include "nspr.h"
+#include <algorithm>
+
+#include "mozilla/Logging.h"
+
+using mozilla::LogLevel;
+
+mozilla::LazyLogModule MCD("MCD");
+
+extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
+ const char *filename,
+ bool bGlobalContext,
+ bool bCallbacks,
+ bool skipFirstLine);
+
+// nsISupports Implementation
+
+NS_IMPL_ISUPPORTS(nsAutoConfig, nsIAutoConfig, nsITimerCallback, nsIStreamListener, nsIObserver, nsIRequestObserver, nsISupportsWeakReference)
+
+nsAutoConfig::nsAutoConfig()
+{
+}
+
+nsresult nsAutoConfig::Init()
+{
+ // member initializers and constructor code
+
+ nsresult rv;
+ mLoaded = false;
+
+ // Registering the object as an observer to the profile-after-change topic
+ nsCOMPtr<nsIObserverService> observerService =
+ do_GetService("@mozilla.org/observer-service;1", &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = observerService->AddObserver(this,"profile-after-change", true);
+
+ return rv;
+}
+
+nsAutoConfig::~nsAutoConfig()
+{
+}
+
+// attribute string configURL
+NS_IMETHODIMP nsAutoConfig::GetConfigURL(char **aConfigURL)
+{
+ if (!aConfigURL)
+ return NS_ERROR_NULL_POINTER;
+
+ if (mConfigURL.IsEmpty()) {
+ *aConfigURL = nullptr;
+ return NS_OK;
+ }
+
+ *aConfigURL = ToNewCString(mConfigURL);
+ if (!*aConfigURL)
+ return NS_ERROR_OUT_OF_MEMORY;
+ return NS_OK;
+}
+NS_IMETHODIMP nsAutoConfig::SetConfigURL(const char *aConfigURL)
+{
+ if (!aConfigURL)
+ return NS_ERROR_NULL_POINTER;
+ mConfigURL.Assign(aConfigURL);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAutoConfig::OnStartRequest(nsIRequest *request, nsISupports *context)
+{
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsAutoConfig::OnDataAvailable(nsIRequest *request,
+ nsISupports *context,
+ nsIInputStream *aIStream,
+ uint64_t aSourceOffset,
+ uint32_t aLength)
+{
+ uint32_t amt, size;
+ nsresult rv;
+ char buf[1024];
+
+ while (aLength) {
+ size = std::min<size_t>(aLength, sizeof(buf));
+ rv = aIStream->Read(buf, size, &amt);
+ if (NS_FAILED(rv))
+ return rv;
+ mBuf.Append(buf, amt);
+ aLength -= amt;
+ }
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsAutoConfig::OnStopRequest(nsIRequest *request, nsISupports *context,
+ nsresult aStatus)
+{
+ nsresult rv;
+
+ // If the request is failed, go read the failover.jsc file
+ if (NS_FAILED(aStatus)) {
+ MOZ_LOG(MCD, LogLevel::Debug, ("mcd request failed with status %x\n", aStatus));
+ return readOfflineFile();
+ }
+
+ // Checking for the http response, if failure go read the failover file.
+ nsCOMPtr<nsIHttpChannel> pHTTPCon(do_QueryInterface(request));
+ if (pHTTPCon) {
+ uint32_t httpStatus;
+ pHTTPCon->GetResponseStatus(&httpStatus);
+ if (httpStatus != 200)
+ {
+ MOZ_LOG(MCD, LogLevel::Debug, ("mcd http request failed with status %x\n", httpStatus));
+ return readOfflineFile();
+ }
+ }
+
+ // Send the autoconfig.jsc to javascript engine.
+
+ rv = EvaluateAdminConfigScript(mBuf.get(), mBuf.Length(),
+ nullptr, false,true, false);
+ if (NS_SUCCEEDED(rv)) {
+
+ // Write the autoconfig.jsc to failover.jsc (cached copy)
+ rv = writeFailoverFile();
+
+ if (NS_FAILED(rv))
+ NS_WARNING("Error writing failover.jsc file");
+
+ // Releasing the lock to allow the main thread to start execution
+ mLoaded = true;
+
+ return NS_OK;
+ }
+ // there is an error in parsing of the autoconfig file.
+ NS_WARNING("Error reading autoconfig.jsc from the network, reading the offline version");
+ return readOfflineFile();
+}
+
+// Notify method as a TimerCallBack function
+NS_IMETHODIMP nsAutoConfig::Notify(nsITimer *timer)
+{
+ downloadAutoConfig();
+ return NS_OK;
+}
+
+/* Observe() is called twice: once at the instantiation time and other
+ after the profile is set. It doesn't do anything but return NS_OK during the
+ creation time. Second time it calls downloadAutoConfig().
+*/
+
+NS_IMETHODIMP nsAutoConfig::Observe(nsISupports *aSubject,
+ const char *aTopic,
+ const char16_t *someData)
+{
+ nsresult rv = NS_OK;
+ if (!nsCRT::strcmp(aTopic, "profile-after-change")) {
+
+ // We will be calling downloadAutoConfig even if there is no profile
+ // name. Nothing will be passed as a parameter to the URL and the
+ // default case will be picked up by the script.
+
+ rv = downloadAutoConfig();
+
+ }
+
+ return rv;
+}
+
+nsresult nsAutoConfig::downloadAutoConfig()
+{
+ nsresult rv;
+ nsAutoCString emailAddr;
+ nsXPIDLCString urlName;
+ static bool firstTime = true;
+
+ if (mConfigURL.IsEmpty()) {
+ MOZ_LOG(MCD, LogLevel::Debug, ("global config url is empty - did you set autoadmin.global_config_url?\n"));
+ NS_WARNING("AutoConfig called without global_config_url");
+ return NS_OK;
+ }
+
+ // If there is an email address appended as an argument to the ConfigURL
+ // in the previous read, we need to remove it when timer kicks in and
+ // downloads the autoconfig file again.
+ // If necessary, the email address will be added again as an argument.
+ int32_t index = mConfigURL.RFindChar((char16_t)'?');
+ if (index != -1)
+ mConfigURL.Truncate(index);
+
+ // Clean up the previous read, the new read is going to use the same buffer
+ if (!mBuf.IsEmpty())
+ mBuf.Truncate(0);
+
+ // Get the preferences branch and save it to the member variable
+ if (!mPrefBranch) {
+ nsCOMPtr<nsIPrefService> prefs =
+ do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = prefs->GetBranch(nullptr,getter_AddRefs(mPrefBranch));
+ if (NS_FAILED(rv))
+ return rv;
+ }
+
+ // Check to see if the network is online/offline
+ nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ bool offline;
+ rv = ios->GetOffline(&offline);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (offline) {
+ bool offlineFailover;
+ rv = mPrefBranch->GetBoolPref("autoadmin.offline_failover",
+ &offlineFailover);
+ // Read the failover.jsc if the network is offline and the pref says so
+ if (NS_SUCCEEDED(rv) && offlineFailover)
+ return readOfflineFile();
+ }
+
+ /* Append user's identity at the end of the URL if the pref says so.
+ First we are checking for the user's email address but if it is not
+ available in the case where the client is used without messenger, user's
+ profile name will be used as an unique identifier
+ */
+ bool appendMail;
+ rv = mPrefBranch->GetBoolPref("autoadmin.append_emailaddr", &appendMail);
+ if (NS_SUCCEEDED(rv) && appendMail) {
+ rv = getEmailAddr(emailAddr);
+ if (NS_SUCCEEDED(rv) && emailAddr.get()) {
+ /* Adding the unique identifier at the end of autoconfig URL.
+ In this case the autoconfig URL is a script and
+ emailAddr as passed as an argument
+ */
+ mConfigURL.Append('?');
+ mConfigURL.Append(emailAddr);
+ }
+ }
+
+ // create a new url
+ nsCOMPtr<nsIURI> url;
+ nsCOMPtr<nsIChannel> channel;
+
+ rv = NS_NewURI(getter_AddRefs(url), mConfigURL.get(), nullptr, nullptr);
+ if (NS_FAILED(rv))
+ {
+ MOZ_LOG(MCD, LogLevel::Debug, ("failed to create URL - is autoadmin.global_config_url valid? - %s\n", mConfigURL.get()));
+ return rv;
+ }
+
+ MOZ_LOG(MCD, LogLevel::Debug, ("running MCD url %s\n", mConfigURL.get()));
+ // open a channel for the url
+ rv = NS_NewChannel(getter_AddRefs(channel),
+ url,
+ nsContentUtils::GetSystemPrincipal(),
+ nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
+ nsIContentPolicy::TYPE_OTHER,
+ nullptr, // loadGroup
+ nullptr, // aCallbacks
+ nsIRequest::INHIBIT_PERSISTENT_CACHING |
+ nsIRequest::LOAD_BYPASS_CACHE);
+
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = channel->AsyncOpen2(this);
+ if (NS_FAILED(rv)) {
+ readOfflineFile();
+ return rv;
+ }
+
+ // Set a repeating timer if the pref is set.
+ // This is to be done only once.
+ // Also We are having the event queue processing only for the startup
+ // It is not needed with the repeating timer.
+ if (firstTime) {
+ firstTime = false;
+
+ // Getting the current thread. If we start an AsyncOpen, the thread
+ // needs to wait before the reading of autoconfig is done
+
+ nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
+ NS_ENSURE_STATE(thread);
+
+ /* process events until we're finished. AutoConfig.jsc reading needs
+ to be finished before the browser starts loading up
+ We are waiting for the mLoaded which will be set through
+ onStopRequest or readOfflineFile methods
+ There is a possibility of deadlock so we need to make sure
+ that mLoaded will be set to true in any case (success/failure)
+ */
+
+ while (!mLoaded)
+ NS_ENSURE_STATE(NS_ProcessNextEvent(thread));
+
+ int32_t minutes;
+ rv = mPrefBranch->GetIntPref("autoadmin.refresh_interval",
+ &minutes);
+ if (NS_SUCCEEDED(rv) && minutes > 0) {
+ // Create a new timer and pass this nsAutoConfig
+ // object as a timer callback.
+ mTimer = do_CreateInstance("@mozilla.org/timer;1",&rv);
+ if (NS_FAILED(rv))
+ return rv;
+ rv = mTimer->InitWithCallback(this, minutes * 60 * 1000,
+ nsITimer::TYPE_REPEATING_SLACK);
+ if (NS_FAILED(rv))
+ return rv;
+ }
+ } //first_time
+
+ return NS_OK;
+} // nsPref::downloadAutoConfig()
+
+
+
+nsresult nsAutoConfig::readOfflineFile()
+{
+ nsresult rv;
+
+ /* Releasing the lock to allow main thread to start
+ execution. At this point we do not need to stall
+ the thread since all network activities are done.
+ */
+ mLoaded = true;
+
+ bool failCache;
+ rv = mPrefBranch->GetBoolPref("autoadmin.failover_to_cached", &failCache);
+ if (NS_SUCCEEDED(rv) && !failCache) {
+ // disable network connections and return.
+
+ nsCOMPtr<nsIIOService> ios =
+ do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ bool offline;
+ rv = ios->GetOffline(&offline);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (!offline) {
+ rv = ios->SetOffline(true);
+ if (NS_FAILED(rv))
+ return rv;
+ }
+
+ // lock the "network.online" prference so user cannot toggle back to
+ // online mode.
+ rv = mPrefBranch->SetBoolPref("network.online", false);
+ if (NS_FAILED(rv))
+ return rv;
+
+ mPrefBranch->LockPref("network.online");
+ return NS_OK;
+ }
+
+ /* faiover_to_cached is set to true so
+ Open the file and read the content.
+ execute the javascript file
+ */
+
+ nsCOMPtr<nsIFile> failoverFile;
+ rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+ getter_AddRefs(failoverFile));
+ if (NS_FAILED(rv))
+ return rv;
+
+ failoverFile->AppendNative(NS_LITERAL_CSTRING("failover.jsc"));
+ rv = evaluateLocalFile(failoverFile);
+ if (NS_FAILED(rv))
+ NS_WARNING("Couldn't open failover.jsc, going back to default prefs");
+ return NS_OK;
+}
+
+nsresult nsAutoConfig::evaluateLocalFile(nsIFile *file)
+{
+ nsresult rv;
+ nsCOMPtr<nsIInputStream> inStr;
+
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), file);
+ if (NS_FAILED(rv))
+ return rv;
+
+ int64_t fileSize;
+ file->GetFileSize(&fileSize);
+ uint32_t fs = fileSize; // Converting 64 bit structure to unsigned int
+ char *buf = (char *)PR_Malloc(fs * sizeof(char));
+ if (!buf)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ uint32_t amt = 0;
+ rv = inStr->Read(buf, fs, &amt);
+ if (NS_SUCCEEDED(rv)) {
+ EvaluateAdminConfigScript(buf, fs, nullptr, false,
+ true, false);
+ }
+ inStr->Close();
+ PR_Free(buf);
+ return rv;
+}
+
+nsresult nsAutoConfig::writeFailoverFile()
+{
+ nsresult rv;
+ nsCOMPtr<nsIFile> failoverFile;
+ nsCOMPtr<nsIOutputStream> outStr;
+ uint32_t amt;
+
+ rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+ getter_AddRefs(failoverFile));
+ if (NS_FAILED(rv))
+ return rv;
+
+ failoverFile->AppendNative(NS_LITERAL_CSTRING("failover.jsc"));
+
+ rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStr), failoverFile);
+ if (NS_FAILED(rv))
+ return rv;
+ rv = outStr->Write(mBuf.get(),mBuf.Length(),&amt);
+ outStr->Close();
+ return rv;
+}
+
+nsresult nsAutoConfig::getEmailAddr(nsACString & emailAddr)
+{
+
+ nsresult rv;
+ nsXPIDLCString prefValue;
+
+ /* Getting an email address through set of three preferences:
+ First getting a default account with
+ "mail.accountmanager.defaultaccount"
+ second getting an associated id with the default account
+ Third getting an email address with id
+ */
+
+ rv = mPrefBranch->GetCharPref("mail.accountmanager.defaultaccount",
+ getter_Copies(prefValue));
+ if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty()) {
+ emailAddr = NS_LITERAL_CSTRING("mail.account.") +
+ prefValue + NS_LITERAL_CSTRING(".identities");
+ rv = mPrefBranch->GetCharPref(PromiseFlatCString(emailAddr).get(),
+ getter_Copies(prefValue));
+ if (NS_FAILED(rv) || prefValue.IsEmpty())
+ return PromptForEMailAddress(emailAddr);
+ int32_t commandIndex = prefValue.FindChar(',');
+ if (commandIndex != kNotFound)
+ prefValue.Truncate(commandIndex);
+ emailAddr = NS_LITERAL_CSTRING("mail.identity.") +
+ prefValue + NS_LITERAL_CSTRING(".useremail");
+ rv = mPrefBranch->GetCharPref(PromiseFlatCString(emailAddr).get(),
+ getter_Copies(prefValue));
+ if (NS_FAILED(rv) || prefValue.IsEmpty())
+ return PromptForEMailAddress(emailAddr);
+ emailAddr = prefValue;
+ }
+ else {
+ // look for 4.x pref in case we just migrated.
+ rv = mPrefBranch->GetCharPref("mail.identity.useremail",
+ getter_Copies(prefValue));
+ if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty())
+ emailAddr = prefValue;
+ else
+ PromptForEMailAddress(emailAddr);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsAutoConfig::PromptForEMailAddress(nsACString &emailAddress)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPromptService> promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIStringBundle> bundle;
+ rv = bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties",
+ getter_AddRefs(bundle));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsXPIDLString title;
+ rv = bundle->GetStringFromName(u"emailPromptTitle", getter_Copies(title));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsXPIDLString err;
+ rv = bundle->GetStringFromName(u"emailPromptMsg", getter_Copies(err));
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool check = false;
+ nsXPIDLString emailResult;
+ bool success;
+ rv = promptService->Prompt(nullptr, title.get(), err.get(), getter_Copies(emailResult), nullptr, &check, &success);
+ if (!success)
+ return NS_ERROR_FAILURE;
+ NS_ENSURE_SUCCESS(rv, rv);
+ LossyCopyUTF16toASCII(emailResult, emailAddress);
+ return NS_OK;
+}
diff --git a/extensions/pref/autoconfig/src/nsAutoConfig.h b/extensions/pref/autoconfig/src/nsAutoConfig.h
new file mode 100644
index 000000000..d805ad184
--- /dev/null
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsAutoConfig_h
+#define nsAutoConfig_h
+
+#include "nsIAutoConfig.h"
+#include "nsITimer.h"
+#include "nsIFile.h"
+#include "nsIObserver.h"
+#include "nsIStreamListener.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsWeakReference.h"
+#include "nsString.h"
+
+class nsAutoConfig : public nsIAutoConfig,
+ public nsITimerCallback,
+ public nsIStreamListener,
+ public nsIObserver,
+ public nsSupportsWeakReference
+
+{
+ public:
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIAUTOCONFIG
+ NS_DECL_NSIREQUESTOBSERVER
+ NS_DECL_NSISTREAMLISTENER
+ NS_DECL_NSIOBSERVER
+ NS_DECL_NSITIMERCALLBACK
+
+ nsAutoConfig();
+ nsresult Init();
+
+ protected:
+
+ virtual ~nsAutoConfig();
+ nsresult downloadAutoConfig();
+ nsresult readOfflineFile();
+ nsresult evaluateLocalFile(nsIFile *file);
+ nsresult writeFailoverFile();
+ nsresult getEmailAddr(nsACString & emailAddr);
+ nsresult PromptForEMailAddress(nsACString &emailAddress);
+ nsCString mBuf;
+ nsCOMPtr<nsIPrefBranch> mPrefBranch;
+ bool mLoaded;
+ nsCOMPtr<nsITimer> mTimer;
+ nsCString mConfigURL;
+};
+
+#endif
diff --git a/extensions/pref/autoconfig/src/nsConfigFactory.cpp b/extensions/pref/autoconfig/src/nsConfigFactory.cpp
new file mode 100644
index 000000000..89f886b2a
--- /dev/null
+++ b/extensions/pref/autoconfig/src/nsConfigFactory.cpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ModuleUtils.h"
+#include "nsAutoConfig.h"
+#include "nsReadConfig.h"
+#include "nsIAppStartupNotifier.h"
+
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAutoConfig, Init)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsReadConfig, Init)
+
+NS_DEFINE_NAMED_CID(NS_AUTOCONFIG_CID);
+NS_DEFINE_NAMED_CID(NS_READCONFIG_CID);
+
+static const mozilla::Module::CIDEntry kAutoConfigCIDs[] = {
+ { &kNS_AUTOCONFIG_CID, false, nullptr, nsAutoConfigConstructor },
+ { &kNS_READCONFIG_CID, false, nullptr, nsReadConfigConstructor },
+ { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kAutoConfigContracts[] = {
+ { NS_AUTOCONFIG_CONTRACTID, &kNS_AUTOCONFIG_CID },
+ { NS_READCONFIG_CONTRACTID, &kNS_READCONFIG_CID },
+ { nullptr }
+};
+
+static const mozilla::Module::CategoryEntry kAutoConfigCategories[] = {
+ { "pref-config-startup", "ReadConfig Module", NS_READCONFIG_CONTRACTID },
+ { nullptr }
+};
+
+static const mozilla::Module kAutoConfigModule = {
+ mozilla::Module::kVersion,
+ kAutoConfigCIDs,
+ kAutoConfigContracts,
+ kAutoConfigCategories
+};
+
+NSMODULE_DEFN(nsAutoConfigModule) = &kAutoConfigModule;
diff --git a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
new file mode 100644
index 000000000..87f2bef20
--- /dev/null
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jsapi.h"
+#include "nsIXPConnect.h"
+#include "nsCOMPtr.h"
+#include "nsIServiceManager.h"
+#include "nsIComponentManager.h"
+#include "nsString.h"
+#include "nsIPrefService.h"
+#include "nspr.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
+#include "nsContentUtils.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsJSPrincipals.h"
+#include "nsIScriptError.h"
+#include "jswrapper.h"
+
+extern mozilla::LazyLogModule MCD;
+using mozilla::AutoSafeJSContext;
+using mozilla::dom::AutoJSAPI;
+
+//*****************************************************************************
+
+static JS::PersistentRooted<JSObject *> autoconfigSb;
+
+nsresult CentralizedAdminPrefManagerInit()
+{
+ nsresult rv;
+
+ // If the sandbox is already created, no need to create it again.
+ if (autoconfigSb.initialized())
+ return NS_OK;
+
+ // Grab XPConnect.
+ nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // Grab the system principal.
+ nsCOMPtr<nsIPrincipal> principal;
+ nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(principal));
+
+
+ // Create a sandbox.
+ AutoSafeJSContext cx;
+ JS::Rooted<JSObject*> sandbox(cx);
+ rv = xpc->CreateSandbox(cx, principal, sandbox.address());
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Unwrap, store and root the sandbox.
+ NS_ENSURE_STATE(sandbox);
+ autoconfigSb.init(cx, js::UncheckedUnwrap(sandbox));
+
+ return NS_OK;
+}
+
+nsresult CentralizedAdminPrefManagerFinish()
+{
+ if (autoconfigSb.initialized()) {
+ AutoSafeJSContext cx;
+ autoconfigSb.reset();
+ JS_MaybeGC(cx);
+ }
+ return NS_OK;
+}
+
+nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
+ const char *filename, bool bGlobalContext,
+ bool bCallbacks, bool skipFirstLine)
+{
+ nsresult rv = NS_OK;
+
+ if (skipFirstLine) {
+ /* In order to protect the privacy of the JavaScript preferences file
+ * from loading by the browser, we make the first line unparseable
+ * by JavaScript. We must skip that line here before executing
+ * the JavaScript code.
+ */
+ unsigned int i = 0;
+ while (i < length) {
+ char c = js_buffer[i++];
+ if (c == '\r') {
+ if (js_buffer[i] == '\n')
+ i++;
+ break;
+ }
+ if (c == '\n')
+ break;
+ }
+
+ length -= i;
+ js_buffer += i;
+ }
+
+ // Grab XPConnect.
+ nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ AutoJSAPI jsapi;
+ if (!jsapi.Init(autoconfigSb)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ JSContext* cx = jsapi.cx();
+
+ nsAutoCString script(js_buffer, length);
+ JS::RootedValue v(cx);
+
+ nsString convertedScript;
+ bool isUTF8 = IsUTF8(script);
+ if (isUTF8) {
+ convertedScript = NS_ConvertUTF8toUTF16(script);
+ } else {
+ nsContentUtils::ReportToConsoleNonLocalized(
+ NS_LITERAL_STRING("Your AutoConfig file is ASCII. Please convert it to UTF-8."),
+ nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("autoconfig"),
+ nullptr);
+ /* If the length is 0, the conversion failed. Fallback to ASCII */
+ convertedScript = NS_ConvertASCIItoUTF16(script);
+ }
+ JS::Rooted<JS::Value> value(cx, JS::BooleanValue(isUTF8));
+ if (!JS_DefineProperty(cx, autoconfigSb, "gIsUTF8", value, JSPROP_ENUMERATE)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ rv = xpc->EvalInSandboxObject(convertedScript, filename, cx,
+ autoconfigSb, JSVERSION_LATEST, &v);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
diff --git a/extensions/pref/autoconfig/src/nsReadConfig.cpp b/extensions/pref/autoconfig/src/nsReadConfig.cpp
new file mode 100644
index 000000000..6f17deaf1
--- /dev/null
+++ b/extensions/pref/autoconfig/src/nsReadConfig.cpp
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsReadConfig.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIAppStartup.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsIAutoConfig.h"
+#include "nsIComponentManager.h"
+#include "nsIFile.h"
+#include "nsIObserverService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefService.h"
+#include "nsIPromptService.h"
+#include "nsIServiceManager.h"
+#include "nsIStringBundle.h"
+#include "nsToolkitCompsCID.h"
+#include "nsXPIDLString.h"
+#include "nsNetUtil.h"
+#include "prmem.h"
+#include "nsString.h"
+#include "nsCRT.h"
+#include "nspr.h"
+#include "nsXULAppAPI.h"
+#include "nsContentUtils.h"
+
+extern mozilla::LazyLogModule MCD;
+
+extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
+ const char *filename,
+ bool bGlobalContext,
+ bool bCallbacks,
+ bool skipFirstLine);
+extern nsresult CentralizedAdminPrefManagerInit();
+extern nsresult CentralizedAdminPrefManagerFinish();
+
+
+static void DisplayError(void)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIPromptService> promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1");
+ if (!promptService)
+ return;
+
+ nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
+ if (!bundleService)
+ return;
+
+ nsCOMPtr<nsIStringBundle> bundle;
+ bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties",
+ getter_AddRefs(bundle));
+ if (!bundle)
+ return;
+
+ nsXPIDLString title;
+ rv = bundle->GetStringFromName(u"readConfigTitle", getter_Copies(title));
+ if (NS_FAILED(rv))
+ return;
+
+ nsXPIDLString err;
+ rv = bundle->GetStringFromName(u"readConfigMsg", getter_Copies(err));
+ if (NS_FAILED(rv))
+ return;
+
+ promptService->Alert(nullptr, title.get(), err.get());
+}
+
+// nsISupports Implementation
+
+NS_IMPL_ISUPPORTS(nsReadConfig, nsIReadConfig, nsIObserver)
+
+nsReadConfig::nsReadConfig() :
+ mRead(false)
+{
+}
+
+nsresult nsReadConfig::Init()
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIObserverService> observerService =
+ do_GetService("@mozilla.org/observer-service;1", &rv);
+
+ if (observerService) {
+ rv = observerService->AddObserver(this, NS_PREFSERVICE_READ_TOPIC_ID, false);
+ }
+ return(rv);
+}
+
+nsReadConfig::~nsReadConfig()
+{
+ CentralizedAdminPrefManagerFinish();
+}
+
+NS_IMETHODIMP nsReadConfig::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
+{
+ nsresult rv = NS_OK;
+
+ if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) {
+ rv = readConfigFile();
+ if (NS_FAILED(rv)) {
+ DisplayError();
+
+ nsCOMPtr<nsIAppStartup> appStartup =
+ do_GetService(NS_APPSTARTUP_CONTRACTID);
+ if (appStartup)
+ appStartup->Quit(nsIAppStartup::eAttemptQuit);
+ }
+ }
+ return rv;
+}
+
+
+nsresult nsReadConfig::readConfigFile()
+{
+ nsresult rv = NS_OK;
+ nsXPIDLCString lockFileName;
+ nsXPIDLCString lockVendor;
+ uint32_t fileNameLen = 0;
+
+ nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = prefService->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
+ if (NS_FAILED(rv))
+ return rv;
+
+ // This preference is set in the all.js or all-ns.js (depending whether
+ // running mozilla or netscp6)
+
+ rv = defaultPrefBranch->GetCharPref("general.config.filename",
+ getter_Copies(lockFileName));
+
+
+ MOZ_LOG(MCD, LogLevel::Debug, ("general.config.filename = %s\n", lockFileName.get()));
+ if (NS_FAILED(rv))
+ return rv;
+
+ // This needs to be read only once.
+ //
+ if (!mRead) {
+ // Initiate the new JS Context for Preference management
+
+ rv = CentralizedAdminPrefManagerInit();
+ if (NS_FAILED(rv))
+ return rv;
+
+ // Open and evaluate function calls to set/lock/unlock prefs
+ rv = openAndEvaluateJSFile("prefcalls.js", 0, false, false);
+ if (NS_FAILED(rv))
+ return rv;
+
+ mRead = true;
+ }
+ // If the lockFileName is nullptr return ok, because no lockFile will be used
+
+
+ // Once the config file is read, we should check that the vendor name
+ // is consistent By checking for the vendor name after reading the config
+ // file we allow for the preference to be set (and locked) by the creator
+ // of the cfg file meaning the file can not be renamed (successfully).
+
+ nsCOMPtr<nsIPrefBranch> prefBranch;
+ rv = prefService->GetBranch(nullptr, getter_AddRefs(prefBranch));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ int32_t obscureValue = 0;
+ (void) defaultPrefBranch->GetIntPref("general.config.obscure_value", &obscureValue);
+ MOZ_LOG(MCD, LogLevel::Debug, ("evaluating .cfg file %s with obscureValue %d\n", lockFileName.get(), obscureValue));
+ rv = openAndEvaluateJSFile(lockFileName.get(), obscureValue, true, true);
+ if (NS_FAILED(rv))
+ {
+ MOZ_LOG(MCD, LogLevel::Debug, ("error evaluating .cfg file %s %x\n", lockFileName.get(), rv));
+ return rv;
+ }
+
+ rv = prefBranch->GetCharPref("general.config.filename",
+ getter_Copies(lockFileName));
+ if (NS_FAILED(rv))
+ // There is NO REASON we should ever get here. This is POST reading
+ // of the config file.
+ return NS_ERROR_FAILURE;
+
+
+ rv = prefBranch->GetCharPref("general.config.vendor",
+ getter_Copies(lockVendor));
+ // If vendor is not nullptr, do this check
+ if (NS_SUCCEEDED(rv)) {
+
+ fileNameLen = strlen(lockFileName);
+
+ // lockVendor and lockFileName should be the same with the addtion of
+ // .cfg to the filename by checking this post reading of the cfg file
+ // this value can be set within the cfg file adding a level of security.
+
+ if (PL_strncmp(lockFileName, lockVendor, fileNameLen - 4) != 0)
+ return NS_ERROR_FAILURE;
+ }
+
+ // get the value of the autoconfig url
+ nsXPIDLCString urlName;
+ rv = prefBranch->GetCharPref("autoadmin.global_config_url",
+ getter_Copies(urlName));
+ if (NS_SUCCEEDED(rv) && !urlName.IsEmpty()) {
+
+ // Instantiating nsAutoConfig object if the pref is present
+ mAutoConfig = do_CreateInstance(NS_AUTOCONFIG_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ rv = mAutoConfig->SetConfigURL(urlName);
+ if (NS_FAILED(rv))
+ return NS_ERROR_FAILURE;
+
+ }
+
+ return NS_OK;
+} // ReadConfigFile
+
+
+nsresult nsReadConfig::openAndEvaluateJSFile(const char *aFileName, int32_t obscureValue,
+ bool isEncoded,
+ bool isBinDir)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIInputStream> inStr;
+ if (isBinDir) {
+ nsCOMPtr<nsIFile> jsFile;
+ rv = NS_GetSpecialDirectory(NS_GRE_DIR,
+ getter_AddRefs(jsFile));
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = jsFile->AppendNative(nsDependentCString(aFileName));
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile);
+ if (NS_FAILED(rv))
+ return rv;
+
+ } else {
+ nsAutoCString location("resource://gre/defaults/autoconfig/");
+ location += aFileName;
+
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI(getter_AddRefs(uri), location);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIChannel> channel;
+ rv = NS_NewChannel(getter_AddRefs(channel),
+ uri,
+ nsContentUtils::GetSystemPrincipal(),
+ nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
+ nsIContentPolicy::TYPE_OTHER);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = channel->Open2(getter_AddRefs(inStr));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ uint64_t fs64;
+ uint32_t amt = 0;
+ rv = inStr->Available(&fs64);
+ if (NS_FAILED(rv))
+ return rv;
+ // PR_Malloc dones't support over 4GB
+ if (fs64 > UINT32_MAX)
+ return NS_ERROR_FILE_TOO_BIG;
+ uint32_t fs = (uint32_t)fs64;
+
+ char *buf = (char *)PR_Malloc(fs * sizeof(char));
+ if (!buf)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ rv = inStr->Read(buf, (uint32_t)fs, &amt);
+ NS_ASSERTION((amt == fs), "failed to read the entire configuration file!!");
+ if (NS_SUCCEEDED(rv)) {
+ if (obscureValue > 0) {
+
+ // Unobscure file by subtracting some value from every char.
+ for (uint32_t i = 0; i < amt; i++)
+ buf[i] -= obscureValue;
+ }
+ rv = EvaluateAdminConfigScript(buf, amt, aFileName,
+ false, true,
+ isEncoded ? true:false);
+ }
+ inStr->Close();
+ PR_Free(buf);
+
+ return rv;
+}
diff --git a/extensions/pref/autoconfig/src/nsReadConfig.h b/extensions/pref/autoconfig/src/nsReadConfig.h
new file mode 100644
index 000000000..66aa9e5f0
--- /dev/null
+++ b/extensions/pref/autoconfig/src/nsReadConfig.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsReadConfig_h
+#define nsReadConfig_h
+
+#include "nsCOMPtr.h"
+#include "nsIReadConfig.h"
+#include "nsIAutoConfig.h"
+#include "nsIObserver.h"
+
+
+class nsReadConfig : public nsIReadConfig,
+ public nsIObserver
+{
+
+ public:
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIREADCONFIG
+ NS_DECL_NSIOBSERVER
+
+ nsReadConfig();
+
+ nsresult Init();
+
+ protected:
+
+ virtual ~nsReadConfig();
+
+ nsresult readConfigFile();
+ nsresult openAndEvaluateJSFile(const char *aFileName, int32_t obscureValue,
+ bool isEncoded, bool isBinDir);
+ bool mRead;
+private:
+ nsCOMPtr<nsIAutoConfig> mAutoConfig;
+};
+
+#endif
diff --git a/extensions/pref/autoconfig/src/prefcalls.js b/extensions/pref/autoconfig/src/prefcalls.js
new file mode 100644
index 000000000..d0bbd538e
--- /dev/null
+++ b/extensions/pref/autoconfig/src/prefcalls.js
@@ -0,0 +1,230 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; js-indent-level: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const nsILDAPURL = Components.interfaces.nsILDAPURL;
+const LDAPURLContractID = "@mozilla.org/network/ldap-url;1";
+const nsILDAPSyncQuery = Components.interfaces.nsILDAPSyncQuery;
+const LDAPSyncQueryContractID = "@mozilla.org/ldapsyncquery;1";
+const nsIPrefService = Components.interfaces.nsIPrefService;
+const PrefServiceContractID = "@mozilla.org/preferences-service;1";
+
+var gVersion;
+var gIsUTF8;
+
+function getPrefBranch() {
+
+ var prefService = Components.classes[PrefServiceContractID]
+ .getService(nsIPrefService);
+ return prefService.getBranch(null);
+}
+
+function pref(prefName, value) {
+
+ try {
+ var prefBranch = getPrefBranch();
+
+ if (typeof value == "string") {
+ if (gIsUTF8) {
+ const nsISupportsString = Components.interfaces.nsISupportsString;
+ let string = Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(nsISupportsString);
+ string.data = value;
+ prefBranch.setComplexValue(prefName, nsISupportsString, string);
+ return;
+ }
+ prefBranch.setCharPref(prefName, value);
+ }
+ else if (typeof value == "number") {
+ prefBranch.setIntPref(prefName, value);
+ }
+ else if (typeof value == "boolean") {
+ prefBranch.setBoolPref(prefName, value);
+ }
+ }
+ catch(e) {
+ displayError("pref", e);
+ }
+}
+
+function defaultPref(prefName, value) {
+
+ try {
+ var prefService = Components.classes[PrefServiceContractID]
+ .getService(nsIPrefService);
+ var prefBranch = prefService.getDefaultBranch(null);
+ if (typeof value == "string") {
+ if (gIsUTF8) {
+ const nsISupportsString = Components.interfaces.nsISupportsString;
+ let string = Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(nsISupportsString);
+ string.data = value;
+ prefBranch.setComplexValue(prefName, nsISupportsString, string);
+ return;
+ }
+ prefBranch.setCharPref(prefName, value);
+ }
+ else if (typeof value == "number") {
+ prefBranch.setIntPref(prefName, value);
+ }
+ else if (typeof value == "boolean") {
+ prefBranch.setBoolPref(prefName, value);
+ }
+ }
+ catch(e) {
+ displayError("defaultPref", e);
+ }
+}
+
+function lockPref(prefName, value) {
+
+ try {
+ var prefBranch = getPrefBranch();
+
+ if (prefBranch.prefIsLocked(prefName))
+ prefBranch.unlockPref(prefName);
+
+ defaultPref(prefName, value);
+
+ prefBranch.lockPref(prefName);
+ }
+ catch(e) {
+ displayError("lockPref", e);
+ }
+}
+
+function unlockPref(prefName) {
+
+ try {
+
+ var prefBranch = getPrefBranch();
+ prefBranch.unlockPref(prefName);
+ }
+ catch(e) {
+ displayError("unlockPref", e);
+ }
+}
+
+function getPref(prefName) {
+
+ try {
+ var prefBranch = getPrefBranch();
+
+ switch (prefBranch.getPrefType(prefName)) {
+
+ case prefBranch.PREF_STRING:
+ if (gIsUTF8) {
+ const nsISupportsString = Components.interfaces.nsISupportsString;
+ let string = Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(nsISupportsString);
+ return prefBranch.getComplexValue(prefName, nsISupportsString).data;
+ }
+ return prefBranch.getCharPref(prefName);
+
+ case prefBranch.PREF_INT:
+ return prefBranch.getIntPref(prefName);
+
+ case prefBranch.PREF_BOOL:
+ return prefBranch.getBoolPref(prefName);
+ default:
+ return null;
+ }
+ }
+ catch(e) {
+ displayError("getPref", e);
+ }
+}
+
+function clearPref(prefName) {
+
+ try {
+ var prefBranch = getPrefBranch();
+ prefBranch.clearUserPref(prefName);
+ }
+ catch(e) {
+ }
+
+}
+
+function setLDAPVersion(version) {
+ gVersion = version;
+}
+
+
+function getLDAPAttributes(host, base, filter, attribs, isSecure) {
+
+ try {
+ var urlSpec = "ldap" + (isSecure ? "s" : "") + "://" + host + (isSecure ? ":636" : "") + "/" + base + "?" + attribs + "?sub?" +
+ filter;
+
+ var url = Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.nsIIOService)
+ .newURI(urlSpec, null, null)
+ .QueryInterface(Components.interfaces.nsILDAPURL);
+
+ var ldapquery = Components.classes[LDAPSyncQueryContractID]
+ .createInstance(nsILDAPSyncQuery);
+ // default to LDAP v3
+ if (!gVersion)
+ gVersion = Components.interfaces.nsILDAPConnection.VERSION3
+ // user supplied method
+ processLDAPValues(ldapquery.getQueryResults(url, gVersion));
+ }
+ catch(e) {
+ displayError("getLDAPAttibutes", e);
+ }
+}
+
+function getLDAPValue(str, key) {
+
+ try {
+ if (str == null || key == null)
+ return null;
+
+ var search_key = "\n" + key + "=";
+
+ var start_pos = str.indexOf(search_key);
+ if (start_pos == -1)
+ return null;
+
+ start_pos += search_key.length;
+
+ var end_pos = str.indexOf("\n", start_pos);
+ if (end_pos == -1)
+ end_pos = str.length;
+
+ return str.substring(start_pos, end_pos);
+ }
+ catch(e) {
+ displayError("getLDAPValue", e);
+ }
+}
+
+function displayError(funcname, message) {
+
+ try {
+ var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+ .getService(Components.interfaces.nsIPromptService);
+ var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
+ .getService(Components.interfaces.nsIStringBundleService)
+ .createBundle("chrome://autoconfig/locale/autoconfig.properties");
+
+ var title = bundle.GetStringFromName("autoConfigTitle");
+ var msg = bundle.formatStringFromName("autoConfigMsg", [funcname], 1);
+ promptService.alert(null, title, msg + " " + message);
+ }
+ catch(e) { }
+}
+
+function getenv(name) {
+ try {
+ var environment = Components.classes["@mozilla.org/process/environment;1"].
+ getService(Components.interfaces.nsIEnvironment);
+ return environment.get(name);
+ }
+ catch(e) {
+ displayError("getEnvironment", e);
+ }
+}
+
diff --git a/extensions/pref/autoconfig/test/unit/autoconfig-latin1.cfg b/extensions/pref/autoconfig/test/unit/autoconfig-latin1.cfg
new file mode 100644
index 000000000..6b96c65fd
--- /dev/null
+++ b/extensions/pref/autoconfig/test/unit/autoconfig-latin1.cfg
@@ -0,0 +1,6 @@
+// # don't remove this comment! (the first line is ignored by Mozilla)
+// ©
+lockPref("_test.string.ASCII", "ASCII");
+lockPref("_test.string.non-ASCII", "日本語");
+lockPref("_test.string.getPref", getPref("_test.string.non-ASCII"));
+lockPref("_test.string.gIsUTF8", String(this.gIsUTF8));
diff --git a/extensions/pref/autoconfig/test/unit/autoconfig-utf8.cfg b/extensions/pref/autoconfig/test/unit/autoconfig-utf8.cfg
new file mode 100644
index 000000000..eec789942
--- /dev/null
+++ b/extensions/pref/autoconfig/test/unit/autoconfig-utf8.cfg
@@ -0,0 +1,6 @@
+// # don't remove this comment! (the first line is ignored by Mozilla)
+
+lockPref("_test.string.ASCII", "UTF-8");
+lockPref("_test.string.non-ASCII", "日本語");
+lockPref("_test.string.getPref", getPref("_test.string.non-ASCII"));
+lockPref("_test.string.gIsUTF8", String(this.gIsUTF8));
diff --git a/extensions/pref/autoconfig/test/unit/autoconfig.js b/extensions/pref/autoconfig/test/unit/autoconfig.js
new file mode 100644
index 000000000..f831d95b6
--- /dev/null
+++ b/extensions/pref/autoconfig/test/unit/autoconfig.js
@@ -0,0 +1,4 @@
+pref("general.config.filename", "autoconfig.cfg");
+pref("general.config.vendor", "autoconfig");
+pref("general.config.obscure_value", 0);
+
diff --git a/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js b/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js
new file mode 100644
index 000000000..a42bc1219
--- /dev/null
+++ b/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js
@@ -0,0 +1,97 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var {classes: Cc, interfaces: Ci, results: Cr} = Components;
+
+function run_test() {
+ let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
+ getService(Ci.nsIProperties);
+ let obsvc = Cc['@mozilla.org/observer-service;1'].
+ getService(Ci.nsIObserverService);
+ let ps = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService);
+ let defaultPrefs = ps.getDefaultBranch(null);
+ let prefs = ps.getBranch(null);
+
+ let greD = dirSvc.get("GreD", Ci.nsIFile);
+ let defaultPrefD = dirSvc.get("PrfDef", Ci.nsIFile);
+ let testDir = do_get_cwd();
+
+ try {
+ let autoConfigJS = testDir.clone();
+ autoConfigJS.append("autoconfig.js");
+ autoConfigJS.copyTo(defaultPrefD, "autoconfig.js");
+
+ // Make sure nsReadConfig is initialized.
+ Cc["@mozilla.org/readconfig;1"].getService(Ci.nsISupports);
+ ps.resetPrefs();
+
+ var tests = [{
+ filename: "autoconfig-utf8.cfg",
+ prefs: {
+ "_test.string.ASCII": "UTF-8",
+ "_test.string.non-ASCII": "日本語",
+ "_test.string.getPref": "日本語",
+ "_test.string.gIsUTF8": "true"
+ }
+ }, {
+ filename: "autoconfig-latin1.cfg",
+ prefs: {
+ "_test.string.ASCII": "ASCII",
+ "_test.string.non-ASCII": "日本語",
+ "_test.string.getPref": "日本語",
+ "_test.string.gIsUTF8": "false",
+ }
+ }];
+
+ function testAutoConfig(test) {
+ // Make sure pref values are unset.
+ for (let prefName in test.prefs) {
+ do_check_eq(Ci.nsIPrefBranch.PREF_INVALID, prefs.getPrefType(prefName));
+ }
+
+ let autoConfigCfg = testDir.clone();
+ autoConfigCfg.append(test.filename);
+ autoConfigCfg.copyTo(greD, "autoconfig.cfg");
+
+ obsvc.notifyObservers(ps, "prefservice:before-read-userprefs", null);
+
+ for (let prefName in test.prefs) {
+ do_check_eq(test.prefs[prefName],
+ prefs.getComplexValue(prefName, Ci.nsISupportsString).data);
+ }
+
+ ps.resetPrefs();
+ // Make sure pref values are reset.
+ for (let prefName in test.prefs) {
+ do_check_eq(Ci.nsIPrefBranch.PREF_INVALID, prefs.getPrefType(prefName));
+ }
+ }
+
+ tests.forEach(testAutoConfig);
+
+ } finally {
+ try {
+ let autoConfigJS = defaultPrefD.clone();
+ autoConfigJS.append("autoconfig.js");
+ autoConfigJS.remove(false);
+ } catch (e) {
+ if (e.result != Cr.NS_ERROR_FILE_NOT_FOUND) {
+ throw e;
+ }
+ }
+
+ try {
+ let autoConfigCfg = greD.clone();
+ autoConfigCfg.append("autoconfig.cfg");
+ autoConfigCfg.remove(false);
+ } catch (e) {
+ if (e.result != Cr.NS_ERROR_FILE_NOT_FOUND) {
+ throw e;
+ }
+ }
+
+ ps.resetPrefs();
+ }
+}
+
diff --git a/extensions/pref/autoconfig/test/unit/xpcshell.ini b/extensions/pref/autoconfig/test/unit/xpcshell.ini
new file mode 100644
index 000000000..4806363e5
--- /dev/null
+++ b/extensions/pref/autoconfig/test/unit/xpcshell.ini
@@ -0,0 +1,10 @@
+[DEFAULT]
+head =
+tail =
+skip-if = toolkit == 'android'
+support-files =
+ autoconfig-latin1.cfg
+ autoconfig-utf8.cfg
+ autoconfig.js
+
+[test_autoconfig_nonascii.js]
diff --git a/extensions/pref/moz.build b/extensions/pref/moz.build
new file mode 100644
index 000000000..ed5958b04
--- /dev/null
+++ b/extensions/pref/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+DIRS += ['autoconfig']