File system-proxies.patch of Package mozilla-xulrunner181

Index: netwerk/base/public/nsISystemProxySettings.idl
================================================================================
--- allmakefiles.sh
+++ allmakefiles.sh
@@ -984,6 +984,7 @@
 toolkit/components/downloads/src/Makefile
 toolkit/components/filepicker/Makefile
 toolkit/components/gnome/Makefile
+toolkit/components/unixproxy/Makefile
 toolkit/components/help/Makefile
 toolkit/components/history/Makefile
 toolkit/components/history/public/Makefile
--- netwerk/base/public/Makefile.in
+++ netwerk/base/public/Makefile.in
@@ -98,6 +98,7 @@
 		nsIStreamTransportService.idl \
 		nsIStreamLoader.idl \
 		nsISyncStreamListener.idl \
+		nsISystemProxySettings.idl \
 		nsIUnicharStreamLoader.idl \
 		nsIStandardURL.idl \
 		nsIURLParser.idl \
--- netwerk/base/public/nsISystemProxySettings.idl
+++ netwerk/base/public/nsISystemProxySettings.idl
@@ -0,0 +1,65 @@
+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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 Novell code.
+ *
+ * The Initial Developer of the Original Code is Novell.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * 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 MPL, 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 MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+#include "nsIURI.idl"
+
+%{C++
+#define NS_SYSTEMPROXYSETTINGS_CONTRACTID "@mozilla.org/system-proxy-settings;1"
+%}
+
+/** 
+ * This interface allows the proxy code to use platform-specific proxy
+ * settings when the proxy preference is set to "automatic discovery". If it can
+ * load a service with the above contract ID, it will use it to determine the
+ * PAC file name. If no PAC file is specified then the service itself will behave
+ * like a PAC file.
+ */
+[scriptable, uuid(a9f3ae38-b769-4e0b-9317-578388e326c9)]
+interface nsISystemProxySettings : nsISupports
+{
+    /**
+     * If non-empty, use this PAC file. If empty, call getProxyForURI instead.
+     */
+    readonly attribute AUTF8String PACURI;
+    
+    /**
+     * See nsIProxyAutoConfig::getProxyForURI; this function behaves exactly
+     * the same way.
+     */
+    ACString getProxyForURI(in nsIURI aURI);
+};
--- netwerk/base/src/nsPACMan.h
+++ netwerk/base/src/nsPACMan.h
@@ -128,6 +128,14 @@
    */
   PRBool IsLoading() { return mLoader != nsnull; }
 
+  /**
+   * Returns true if the given URI matches the URI of our PAC file.
+   */
+  PRBool IsPACURI(nsIURI *uri) {
+    PRBool result;
+    return mPACURI && NS_SUCCEEDED(mPACURI->Equals(uri, &result)) && result;
+  }
+
 private:
   NS_DECL_NSISTREAMLOADEROBSERVER
   NS_DECL_NSIINTERFACEREQUESTOR
@@ -163,14 +171,6 @@
   void OnLoadFailure();
 
   /**
-   * Returns true if the given URI matches the URI of our PAC file.
-   */
-  PRBool IsPACURI(nsIURI *uri) {
-    PRBool result;
-    return mPACURI && NS_SUCCEEDED(mPACURI->Equals(uri, &result)) && result;
-  }
-
-  /**
    * Event fu for calling StartLoading asynchronously.
    */
   PR_STATIC_CALLBACK(void *) LoadEvent_Handle(PLEvent *);
--- netwerk/base/src/nsProtocolProxyService.cpp
+++ netwerk/base/src/nsProtocolProxyService.cpp
@@ -411,6 +411,12 @@
             mProxyConfig = NS_STATIC_CAST(ProxyConfig, type);
             reloadPAC = PR_TRUE;
         }
+
+        if (mProxyConfig == eProxyConfig_System) {
+            mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID);
+        } else {
+            mSystemProxySettings = nsnull;
+        }
     }
 
     if (!pref || !strcmp(pref, "network.proxy.http"))
@@ -466,8 +472,10 @@
             LoadHostFilters(tempString.get());
     }
 
-    // We're done if not using PAC or WPAD
-    if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD)
+    // We're done if not using something that could give us a PAC URL
+    // (PAC, WPAD or System)
+    if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD &&
+        mProxyConfig != eProxyConfig_System)
         return;
 
     // OK, we need to reload the PAC file if:
@@ -482,17 +490,21 @@
         if (mProxyConfig == eProxyConfig_PAC) {
             prefBranch->GetCharPref("network.proxy.autoconfig_url",
                                     getter_Copies(tempString));
-        }
-        else if (mProxyConfig == eProxyConfig_WPAD) {
+        } else {
             // We diverge from the WPAD spec here in that we don't walk the
             // hosts's FQDN, stripping components until we hit a TLD.  Doing so
             // is dangerous in the face of an incomplete list of TLDs, and TLDs
             // get added over time.  We could consider doing only a single
             // substitution of the first component, if that proves to help
             // compatibility.
-            tempString.AssignLiteral("http://wpad/wpad.dat");
+            if (mSystemProxySettings)
+                mSystemProxySettings->GetPACURI(tempString);
+            else
+                tempString.AssignLiteral("http://wpad/wpad.dat");
+        }
+        if (!tempString.IsEmpty()) {
+            ConfigureFromPAC(tempString);
         }
-        ConfigureFromPAC(tempString);
     }
 }
 
@@ -901,13 +913,16 @@
             return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    mFailedProxies.Clear();
-
     nsCOMPtr<nsIURI> pacURI;
     nsresult rv = NS_NewURI(getter_AddRefs(pacURI), spec);
     if (NS_FAILED(rv))
         return rv;
 
+    if (mPACMan->IsPACURI(pacURI))
+        return NS_OK;
+
+    mFailedProxies.Clear();
+
     return mPACMan->LoadPACFromURI(pacURI);
 }
 
@@ -917,8 +932,10 @@
                                             nsresult       aStatus,
                                             nsIProxyInfo **aResult)
 {
-    // We only support failover when a PAC file is configured.
-    if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD)
+    // We only support failover when a PAC file is configured, either
+    // directly or via system settings
+    if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD &&
+        mProxyConfig != eProxyConfig_System)
         return NS_ERROR_NOT_AVAILABLE;
 
     // Verify that |aProxy| is one of our nsProxyInfo objects.
@@ -1214,15 +1231,37 @@
     if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY))
         return NS_OK;  // Can't proxy this (filters may not override)
 
+    if (mSystemProxySettings) {
+        nsCAutoString PACURI;
+        if (NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) &&
+            !PACURI.IsEmpty()) {
+            // Switch to new PAC file if that setting has changed. If the setting
+            // hasn't changed, ConfigureFromPAC will exit early.
+            nsresult rv = ConfigureFromPAC(PACURI);
+            if (NS_FAILED(rv))
+                return rv;
+        } else {
+            nsCAutoString proxy;
+            nsresult rv = mSystemProxySettings->GetProxyForURI(uri, proxy);
+            if (NS_SUCCEEDED(rv)) {
+                ProcessPACString(proxy, result);
+                return NS_OK;
+            }
+            // no proxy, stop search
+            return NS_OK;
+        }
+    }
+
     // if proxies are enabled and this host:port combo is supposed to use a
     // proxy, check for a proxy.
     if (mProxyConfig == eProxyConfig_Direct ||
             (mProxyConfig == eProxyConfig_Manual &&
              !CanUseProxy(uri, info.defaultPort)))
         return NS_OK;
-    
+
     // Proxy auto config magic...
-    if (mProxyConfig == eProxyConfig_PAC || mProxyConfig == eProxyConfig_WPAD) {
+    if (mProxyConfig == eProxyConfig_PAC || mProxyConfig == eProxyConfig_WPAD ||
+        mProxyConfig == eProxyConfig_System) {
         // Do not query PAC now.
         *usePAC = PR_TRUE;
         return NS_OK;
--- netwerk/base/src/nsProtocolProxyService.h
+++ netwerk/base/src/nsProtocolProxyService.h
@@ -48,6 +48,7 @@
 #include "nsPIProtocolProxyService.h"
 #include "nsIProtocolProxyFilter.h"
 #include "nsIProxyAutoConfig.h"
+#include "nsISystemProxySettings.h"
 #include "nsIProxyInfo.h"
 #include "nsIObserver.h"
 #include "nsDataHashtable.h"
@@ -310,6 +311,7 @@
         eProxyConfig_PAC,
         eProxyConfig_Direct4x,
         eProxyConfig_WPAD,
+        eProxyConfig_System, // use system proxy settings if available, otherwise WPAD
         eProxyConfig_Last
     };
 
@@ -371,6 +373,7 @@
     PRBool                       mSOCKSProxyRemoteDNS;
 
     nsRefPtr<nsPACMan>           mPACMan;  // non-null if we are using PAC
+    nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
 
     PRTime                       mSessionStart;
     nsFailedProxyTable           mFailedProxies;
Index: Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/Makefile.in,v
retrieving revision 1.299.2.18
diff -u -p -6 -r1.299.2.18 Makefile.in
--- Makefile.in	14 Sep 2006 18:07:02 -0000	1.299.2.18
+++ Makefile.in	27 Nov 2006 19:04:14 -0000
@@ -282,12 +282,13 @@ tier_50_dirs	+= directory/xpcom
 endif
 
 ifndef MINIMO
 ifdef MOZ_XUL_APP
 ifdef MOZ_ENABLE_GTK2
 tier_50_dirs    += toolkit/components/gnome
+tier_50_dirs    += toolkit/components/unixproxy
 endif
 endif
 endif
 
 ifdef MOZ_LEAKY
 tier_50_dirs        += tools/leaky
--- toolkit/components/unixproxy/Makefile.in.orig	2006-11-27 21:25:50.000000000 +0100
+++ toolkit/components/unixproxy/Makefile.in	2006-11-27 21:26:18.000000000 +0100
@@ -0,0 +1,67 @@
+# ***** 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 the Mozilla GNOME integration code.
+#
+# The Initial Developer of the Original Code is
+# IBM Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2004
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Brian Ryner <bryner@brianryner.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 MPL, 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 MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH     = ../../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE          = unixproxy
+MOZILLA_INTERNAL_API = 1
+
+REQUIRES = \
+        xpcom \
+        string \
+        necko \
+        mozgnome \
+        $(NULL)
+
+CPPSRCS = \
+        nsUnixSystemProxySettings.cpp \
+        $(NULL)
+
+LIBRARY_NAME    = unixproxy
+IS_COMPONENT    = 1
+FORCE_SHARED_LIB = 1
+
+EXTRA_DSO_LDOPTS += \
+	$(MOZ_COMPONENT_LIBS) \
+	$(NULL)
+
+include $(topsrcdir)/config/rules.mk
Index: toolkit/components/gnome/nsGConfService.cpp
===================================================================
RCS file: /cvsroot/mozilla/toolkit/components/gnome/Attic/nsGConfService.cpp,v
retrieving revision 1.2
diff -u -p -6 -r1.2 nsGConfService.cpp
--- toolkit/components/gnome/nsGConfService.cpp	15 Jul 2004 22:51:19 -0000	1.2
+++ toolkit/components/gnome/nsGConfService.cpp	29 May 2007 05:42:27 -0000
@@ -121,12 +121,70 @@ nsGConfService::GetFloat(const nsACStrin
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
+class StringListEnumerator : public nsIUTF8StringEnumerator
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIUTF8STRINGENUMERATOR
+
+  StringListEnumerator(GSList* aList) : mList(aList), mNext(aList) {}
+  virtual ~StringListEnumerator() {
+    g_slist_free(mList);
+  }
+
+private:
+  GSList* mList;
+  GSList* mNext;
+};
+
+NS_IMPL_ISUPPORTS1(StringListEnumerator, nsIUTF8StringEnumerator)
+
+NS_IMETHODIMP
+StringListEnumerator::HasMore(PRBool* aResult)
+{
+  NS_PRECONDITION(aResult, "null ptr");
+  *aResult = mNext != nsnull;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+StringListEnumerator::GetNext(nsACString& aResult)
+{
+  if (!mNext)
+    return NS_ERROR_UNEXPECTED;
+  aResult.Assign(NS_STATIC_CAST(char*, mNext->data));
+  mNext = mNext->next;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGConfService::GetStringList(const nsACString &aKey,
+                              nsIUTF8StringEnumerator** aResult)
+{
+  GError* error = nsnull;
+  GSList* list = gconf_client_get_list(mClient, PromiseFlatCString(aKey).get(),
+                                       GCONF_VALUE_STRING, &error);
+  if (error) {
+    g_error_free(error);
+    return NS_ERROR_FAILURE;
+  }
+
+  StringListEnumerator* enumerator = new StringListEnumerator(list);
+  if (!enumerator) {
+    g_slist_free(list);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  NS_ADDREF(*aResult = enumerator);
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsGConfService::SetBool(const nsACString &aKey, PRBool aValue)
 {
   PRBool res = gconf_client_set_bool(mClient, PromiseFlatCString(aKey).get(),
                                      aValue, nsnull);
 
Index: toolkit/components/gnome/nsIGConfService.idl
===================================================================
RCS file: /cvsroot/mozilla/toolkit/components/gnome/Attic/nsIGConfService.idl,v
retrieving revision 1.2
diff -u -p -6 -r1.2 nsIGConfService.idl
--- toolkit/components/gnome/nsIGConfService.idl	15 Jul 2004 22:51:19 -0000	1.2
+++ toolkit/components/gnome/nsIGConfService.idl	29 May 2007 05:42:52 -0000
@@ -34,21 +34,23 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
+#include "nsIStringEnumerator.idl"
 
 [scriptable, uuid(01ac7b2e-c07c-465f-b35c-542eaef420a9)]
 interface nsIGConfService : nsISupports
 {
   /* Basic registry access */
   boolean       getBool(in AUTF8String key);
   AUTF8String   getString(in AUTF8String key);
   long          getInt(in AUTF8String key);
   float         getFloat(in AUTF8String key);
+  nsIUTF8StringEnumerator getStringList(in AUTF8String key);
 
   void setBool(in AUTF8String key, in boolean value);
   void setString(in AUTF8String key, in AUTF8String value);
   void setInt(in AUTF8String key, in long value);
   void setFloat(in AUTF8String key, in float value);
 
--- toolkit/components/unixproxy/nsUnixSystemProxySettings.cpp.orig	2007-05-29 07:45:58.000000000 +0200
+++ toolkit/components/unixproxy/nsUnixSystemProxySettings.cpp	2007-05-29 08:37:45.000000000 +0200
@@ -0,0 +1,422 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * 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 MPL, 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 MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISystemProxySettings.h"
+#include "nsIGenericFactory.h"
+#include "nsIServiceManager.h"
+#include "nsIGConfService.h"
+#include "nsIURI.h"
+#include "nsReadableUtils.h"
+#include "nsArray.h"
+#include "prnetdb.h"
+#include "prenv.h"
+#include "nsPrintfCString.h"
+#include "nsNetUtil.h"
+
+class nsUnixSystemProxySettings : public nsISystemProxySettings {
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISYSTEMPROXYSETTINGS
+
+  nsUnixSystemProxySettings() {}
+  nsresult Init();
+
+private:
+  ~nsUnixSystemProxySettings() {}
+  
+  nsCOMPtr<nsIGConfService> mGConf;
+};
+
+NS_IMPL_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings)
+
+nsresult
+nsUnixSystemProxySettings::Init()
+{
+  // If this is a GNOME session, load gconf and try to use its preferences.
+  // If gconf is not available (which would be stupid) we'll proceed as if this
+  // was not a GNOME session, using *_PROXY environment variables.
+  const char* sessionType = PR_GetEnv("DESKTOP_SESSION");
+  if (sessionType && !strcmp(sessionType, "gnome")) {
+    mGConf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
+  }
+  return NS_OK;
+}
+
+static PRBool
+IsProxyMode(nsIGConfService* aGConf, const char* aMode)
+{
+  nsCAutoString mode;
+  return NS_SUCCEEDED(aGConf->GetString(NS_LITERAL_CSTRING("/system/proxy/mode"), mode)) &&
+      mode.EqualsASCII(aMode);
+}
+
+nsresult
+nsUnixSystemProxySettings::GetPACURI(nsACString& aResult)
+{
+  if (!mGConf || !IsProxyMode(mGConf, "auto"))
+    return NS_ERROR_FAILURE;
+  return mGConf->GetString(NS_LITERAL_CSTRING("/system/proxy/autoconfig_url"),
+                           aResult);
+}
+
+static PRBool
+IsInNoProxyList(const nsACString& aHost, PRInt32 aPort, const char* noProxyVal)
+{
+  NS_ASSERTION(aPort >= 0, "Negative port?");
+  
+  nsCAutoString noProxy(noProxyVal);
+  if (noProxy.EqualsLiteral("*"))
+    return PR_TRUE;
+    
+  noProxy.StripWhitespace();
+  
+  nsReadingIterator<char> pos;
+  nsReadingIterator<char> end;
+  noProxy.BeginReading(pos);
+  noProxy.EndReading(end);
+  while (pos != end) {
+    nsReadingIterator<char> last = pos;
+    nsReadingIterator<char> nextPos;
+    if (FindCharInReadable(',', last, end)) {
+      nextPos = last;
+      ++nextPos;
+    } else {
+      last = end;
+      nextPos = end;
+    }
+    
+    nsReadingIterator<char> colon = pos;
+    PRInt32 port = -1;
+    if (FindCharInReadable(':', colon, last)) {
+      ++colon;
+      nsDependentCSubstring portStr(colon, last);
+      nsCAutoString portStr2(portStr);
+      PRInt32 err;
+      port = portStr2.ToInteger(&err);
+      if (err != 0) {
+        port = -2; // don't match any port, so we ignore this pattern
+      }
+      --colon;
+    } else {
+      colon = last;
+    }
+    
+    if (port == -1 || port == aPort) {
+      nsDependentCSubstring hostStr(pos, colon);
+      if (StringEndsWith(aHost, hostStr, nsCaseInsensitiveCStringComparator()))
+        return PR_TRUE;
+    }
+    
+    pos = nextPos;
+  }
+  
+  return PR_FALSE;
+}
+
+static void SetProxyResult(const char* aType, const nsACString& aHost,
+                               PRInt32 aPort, nsACString& aResult)
+{
+  aResult.AppendASCII(aType);
+  aResult.Append(' ');
+  aResult.Append(aHost);
+  aResult.Append(':');
+  aResult.Append(nsPrintfCString("%d", aPort));
+}
+
+static nsresult
+GetProxyForURIFromEnvironment(const nsACString& aScheme,
+                              const nsACString& aHost,
+                              PRInt32 aPort,
+                              nsACString& aResult)
+{
+  nsCAutoString envVar;
+  envVar.Append(aScheme);
+  envVar.AppendLiteral("_proxy");
+  const char* proxyVal = PR_GetEnv(envVar.get());
+  if (!proxyVal) {
+    proxyVal = PR_GetEnv("all_proxy");
+    if (!proxyVal) {
+      // Return failure so that the caller can detect the failure and
+      // fall back to other proxy detection (e.g., WPAD)
+      return NS_ERROR_FAILURE;
+    }
+  }
+  
+  const char* noProxyVal = PR_GetEnv("no_proxy");
+  if (noProxyVal && IsInNoProxyList(aHost, aPort, noProxyVal)) {
+    aResult.AppendLiteral("DIRECT");
+    return NS_OK;
+  }
+  
+  // Use our URI parser to crack the proxy URI
+  nsCOMPtr<nsIURI> proxyURI;
+  nsresult rv = NS_NewURI(getter_AddRefs(proxyURI), proxyVal);
+  if (NS_FAILED(rv))
+    return rv;
+
+  // Is there a way to specify "socks://" or something in these environment
+  // variables? I can't find any documentation.
+  PRBool isHTTP;
+  rv = proxyURI->SchemeIs("http", &isHTTP);
+  if (NS_FAILED(rv))
+    return rv;
+  if (!isHTTP)
+    return NS_ERROR_FAILURE;
+
+  nsCAutoString proxyHost;
+  rv = proxyURI->GetHost(proxyHost);
+  if (NS_FAILED(rv))
+    return rv;
+  PRInt32 proxyPort;
+  rv = proxyURI->GetPort(&proxyPort);
+  if (NS_FAILED(rv))
+    return rv;
+
+  SetProxyResult("PROXY", proxyHost, proxyPort, aResult);
+  return NS_OK;
+}
+
+static nsresult
+SetProxyResultFromGConf(nsIGConfService* aGConf, const char* aKeyBase,
+                        const char* aType, nsACString& aResult)
+{
+  nsCAutoString hostKey;
+  hostKey.AppendASCII(aKeyBase);
+  hostKey.AppendLiteral("host");
+  nsCAutoString host;
+  nsresult rv = aGConf->GetString(hostKey, host);
+  if (NS_FAILED(rv))
+    return rv;
+  if (host.IsEmpty())
+    return NS_ERROR_FAILURE;
+  
+  nsCAutoString portKey;
+  portKey.AppendASCII(aKeyBase);
+  portKey.AppendLiteral("port");
+  PRInt32 port;
+  rv = aGConf->GetInt(portKey, &port);
+  if (NS_FAILED(rv))
+    return rv;
+    
+  SetProxyResult(aType, host, port, aResult);
+  return NS_OK;
+}
+
+/* copied from nsProtocolProxyService.cpp --- we should share this! */
+static void
+proxy_MaskIPv6Addr(PRIPv6Addr &addr, PRUint16 mask_len)
+{
+    if (mask_len == 128)
+        return;
+
+    if (mask_len > 96) {
+        addr.pr_s6_addr32[3] = PR_htonl(
+                PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len)));
+    }
+    else if (mask_len > 64) {
+        addr.pr_s6_addr32[3] = 0;
+        addr.pr_s6_addr32[2] = PR_htonl(
+                PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len)));
+    }
+    else if (mask_len > 32) {
+        addr.pr_s6_addr32[3] = 0;
+        addr.pr_s6_addr32[2] = 0;
+        addr.pr_s6_addr32[1] = PR_htonl(
+                PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len)));
+    }
+    else {
+        addr.pr_s6_addr32[3] = 0;
+        addr.pr_s6_addr32[2] = 0;
+        addr.pr_s6_addr32[1] = 0;
+        addr.pr_s6_addr32[0] = PR_htonl(
+                PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len)));
+    }
+}
+
+static PRBool ConvertToIPV6Addr(const nsACString& aName,
+                                PRIPv6Addr* aAddr)
+{
+  PRNetAddr addr;
+  if (PR_StringToNetAddr(PromiseFlatCString(aName).get(), &addr) != PR_SUCCESS)
+    return PR_FALSE;
+
+  PRIPv6Addr ipv6;
+  // convert parsed address to IPv6
+  if (addr.raw.family == PR_AF_INET) {
+    // convert to IPv4-mapped address
+    PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &ipv6);
+  } else if (addr.raw.family == PR_AF_INET6) {
+    // copy the address
+    memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr));
+  } else {
+    return PR_FALSE;
+  }
+  
+  return PR_TRUE;
+}
+
+static PRBool GConfIgnoreHost(const nsACString& aIgnore,
+                              const nsACString& aHost)
+{
+  if (aIgnore.Equals(aHost, nsCaseInsensitiveCStringComparator()))
+    return PR_TRUE;
+
+  if (StringBeginsWith(aIgnore, NS_LITERAL_CSTRING("*")) &&
+      StringEndsWith(aHost, nsDependentCSubstring(aIgnore, 1),
+                     nsCaseInsensitiveCStringComparator()))
+    return PR_TRUE;
+
+  PRInt32 mask = 128;
+  nsReadingIterator<char> start;
+  nsReadingIterator<char> slash;
+  nsReadingIterator<char> end;
+  aIgnore.BeginReading(start);
+  aIgnore.BeginReading(slash);
+  aIgnore.EndReading(end);
+  if (FindCharInReadable('/', slash, end)) {
+    ++slash;
+    nsDependentCSubstring maskStr(slash, end);
+    nsCAutoString maskStr2(maskStr);
+    PRInt32 err;
+    mask = maskStr2.ToInteger(&err);
+    if (err != 0) {
+      mask = 128;
+    }
+    --slash;
+  } else {
+    slash = end;
+  }
+
+  PRIPv6Addr ignoreAddr, hostAddr;
+  if (!ConvertToIPV6Addr(aIgnore, &ignoreAddr) ||
+      !ConvertToIPV6Addr(aHost, &hostAddr))
+    return PR_FALSE;
+
+  proxy_MaskIPv6Addr(ignoreAddr, mask);
+  proxy_MaskIPv6Addr(hostAddr, mask);
+  
+  return memcmp(&ignoreAddr, &hostAddr, sizeof(PRIPv6Addr)) == 0;
+}
+
+static nsresult
+GetProxyForURIFromGConf(nsIGConfService* aGConf,
+                        const nsACString& aScheme,
+                        const nsACString& aHost,
+                        PRInt32 aPort,
+                        nsACString& aResult)
+{
+  if (!IsProxyMode(aGConf, "manual")) {
+    aResult.AppendLiteral("DIRECT");
+    return NS_OK;
+  }
+  
+  nsCOMPtr<nsIUTF8StringEnumerator> ignoreList;
+  if (NS_SUCCEEDED(aGConf->GetStringList(NS_LITERAL_CSTRING("/system/http_proxy/ignore_hosts"),
+                                         getter_AddRefs(ignoreList))) && ignoreList) {
+    while (PR_TRUE) {
+      PRBool hasMore;
+      if (NS_FAILED(ignoreList->HasMore(&hasMore)) || !hasMore)
+        break;
+      nsCAutoString s;
+      if (NS_SUCCEEDED(ignoreList->GetNext(s))) {
+        if (GConfIgnoreHost(s, aHost)) {
+          aResult.AppendLiteral("DIRECT");
+          return NS_OK;
+        }
+      }
+    }
+  }
+  
+  nsresult rv = SetProxyResultFromGConf(aGConf, "/system/proxy/socks_", "SOCKS", aResult);
+  if (NS_SUCCEEDED(rv))
+    return rv;
+  
+  if (aScheme.LowerCaseEqualsLiteral("http")) {
+    rv = SetProxyResultFromGConf(aGConf, "/system/http_proxy/", "PROXY", aResult);
+  } else if (aScheme.LowerCaseEqualsLiteral("https")) {
+    rv = SetProxyResultFromGConf(aGConf, "/system/proxy/secure_", "PROXY", aResult);
+  } else if (aScheme.LowerCaseEqualsLiteral("ftp")) {
+    rv = SetProxyResultFromGConf(aGConf, "/system/proxy/ftp_", "PROXY", aResult);
+  } else {
+    rv = NS_ERROR_FAILURE;
+  }
+  
+  if (NS_FAILED(rv)) {
+    aResult.AppendLiteral("DIRECT");
+  }
+  return NS_OK;
+}
+
+nsresult
+nsUnixSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
+{
+  nsCAutoString scheme;
+  nsresult rv = aURI->GetScheme(scheme);
+  if (NS_FAILED(rv))
+    return rv;
+
+  nsCAutoString host;
+  rv = aURI->GetHost(host);
+  if (NS_FAILED(rv))
+    return rv;
+
+  PRInt32 port;
+  rv = aURI->GetPort(&port);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (!mGConf)
+    return GetProxyForURIFromEnvironment(scheme, host, port, aResult);
+
+  return GetProxyForURIFromGConf(mGConf, scheme, host, port, aResult);
+}
+
+#define NS_UNIXSYSTEMPROXYSERVICE_CID  /* 0fa3158c-d5a7-43de-9181-a285e74cf1d4 */\
+     { 0x0fa3158c, 0xd5a7, 0x43de, \
+       {0x91, 0x81, 0xa2, 0x85, 0xe7, 0x4c, 0xf1, 0xd4 } }
+
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsUnixSystemProxySettings, Init)
+
+static const nsModuleComponentInfo components[] = {
+  { "Unix System Proxy Settings Service",
+    NS_UNIXSYSTEMPROXYSERVICE_CID,
+    NS_SYSTEMPROXYSETTINGS_CONTRACTID,
+    nsUnixSystemProxySettingsConstructor }
+};
+
+NS_IMPL_NSGETMODULE(unixproxy, components)
openSUSE Build Service is sponsored by