- Add patches from Debian release 3.0.3-2-2
authorRoland Rosenfeld <roland@spinnaker.de>
Sat, 9 Sep 2006 13:49:59 +0000 (13:49 +0000)
committerRoland Rosenfeld <roland@spinnaker.de>
Sat, 9 Sep 2006 13:49:59 +0000 (13:49 +0000)
- Adapt Debian patches to the upcoming 3.0.4 release

19 files changed:
debian/changelog
debian/control
debian/patches/00list
debian/patches/01_local_usermanual.dpatch
debian/patches/02_linkcolor.dpatch
debian/patches/03_ipv6.dpatch [new file with mode: 0755]
debian/patches/04_nomultiproxy.dpatch
debian/patches/05_defaut_action.dpatch
debian/patches/06_8bit_manual.dpatch
debian/patches/07_typos.dpatch
debian/patches/09_no_identity.dpatch
debian/patches/14_config.dpatch
debian/patches/15_mansection8.dpatch
debian/patches/16_gzip.dpatch [new file with mode: 0755]
debian/patches/17_502_no_such_domain.dpatch [new file with mode: 0755]
debian/patches/18_dns_retry.dpatch [new file with mode: 0755]
debian/patches/19_manpage_fixup.dpatch [new file with mode: 0755]
debian/patches/20_makefile_fixup.dpatch [new file with mode: 0755]
debian/patches/21_version_3.0.4.dpatch [new file with mode: 0755]

index 804eefc..8e0fdb0 100644 (file)
@@ -1,8 +1,40 @@
+privoxy (3.0.4.cvs20060909-1) UNRELEASED; urgency=low
+
+  * New upstream CVS snapshot as of 2006-09-09.
+  * Adapted all patches to this version.
+  * The following patches are incorporated upstream now, so they are no
+    longer needed: 01_local_usermanual.dpatch, 08_log_pthread.dpatch,
+    09_no_identity.dpatch, 12_multiple-filters.dpatch, 13_memory.dpatch,
+    18_dns_retry.dpatch.
+  * 20_makefile_fixup.dpatch: Fix a syntax error in the GNUmakefile.in.
+
+ -- Roland Rosenfeld <roland@debian.org>  Sat,  9 Sep 2006 15:26:34 +0200
+
+privoxy (3.0.3-2-2) unstable; urgency=low
+
+  * Upgrade to Standards-Version 3.7.2 (no changes).
+  * 17_502_no_such_domain.dpatch: Changes the 404 HTTP status code of the
+    "No such Domain" template to 502 Bad Gateway, which seems to be more
+    correct according to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+    (Closes: #380389).
+  * Disable filter{js-annoyances} and filter{unsolicited-popups} for
+    .cnrs.fr and blogs.msdn.com, because these sites consume very much CPU
+    time otherwise (Closes: #377843).
+  * 18_dns_retry.dpatch by Fabian Keil <fk@fabiankeil.de>: 10 retries
+    before giving up DNS lookup. This hopefully Closes: #335660.
+  * 19_manpage_fixup.dpatch:
+    - Convert Latin-1 char á to groff eqivalent in man page.
+    - Quote minus signs to differenciate them from hyphens.
+  * Do not filter{banners-by-size} on .w3.org pages, because these often
+    contain validator icons (Closes: #319025).
+
+ -- Roland Rosenfeld <roland@debian.org>  Sat,  5 Aug 2006 15:15:17 +0200
+
 privoxy (3.0.3-2-1) unstable; urgency=low
 
   * New upstream version 3.0.3-2.
   * Add debian/watch file.
 privoxy (3.0.3-2-1) unstable; urgency=low
 
   * New upstream version 3.0.3-2.
   * Add debian/watch file.
-  * Remove parts of 13_memory.dpatch, which seem to be free too much
+  * Remove parts of 13_memory.dpatch, which seems to free too much
     memory (Closes: #353110, #354611).
 
  -- Roland Rosenfeld <roland@debian.org>  Mon, 27 Feb 2006 23:28:52 +0100
     memory (Closes: #353110, #354611).
 
  -- Roland Rosenfeld <roland@debian.org>  Mon, 27 Feb 2006 23:28:52 +0100
index cd43c6c..f33f074 100644 (file)
@@ -3,7 +3,7 @@ Section: web
 Priority: optional
 Maintainer: Roland Rosenfeld <roland@debian.org>
 Build-Depends: debhelper (>= 5.0.0), autoconf, autotools-dev, libpcre3-dev, jade, docbook-dsssl, w3m, sp, sgmlspl, groff, htmldoc (>= 1.8.25-1), man2html, dpatch
 Priority: optional
 Maintainer: Roland Rosenfeld <roland@debian.org>
 Build-Depends: debhelper (>= 5.0.0), autoconf, autotools-dev, libpcre3-dev, jade, docbook-dsssl, w3m, sp, sgmlspl, groff, htmldoc (>= 1.8.25-1), man2html, dpatch
-Standards-Version: 3.6.2
+Standards-Version: 3.7.2
 
 Package: privoxy
 Architecture: any
 
 Package: privoxy
 Architecture: any
index 6c2fb3f..c225495 100644 (file)
@@ -1,14 +1,21 @@
-01_local_usermanual.dpatch
+# 01_local_usermanual.dpatch # now upstream
 02_linkcolor.dpatch
 02_linkcolor.dpatch
+# 03_ipv6.dpatch # incompatible with 18_dns_retry.dpatch
 04_nomultiproxy.dpatch
 05_defaut_action.dpatch
 06_8bit_manual.dpatch
 07_typos.dpatch
 04_nomultiproxy.dpatch
 05_defaut_action.dpatch
 06_8bit_manual.dpatch
 07_typos.dpatch
-08_log_pthread.dpatch
-09_no_identity.dpatch
+# 08_log_pthread.dpatch # now upstream
+# 09_no_identity.dpatch # now upstream
 10_backup_doc.dpatch
 11_backup_autotools.dpatch
 10_backup_doc.dpatch
 11_backup_autotools.dpatch
-12_multiple-filters.dpatch
-13_memory.dpatch
+# 12_multiple-filters.dpatch # now upstream
+# 13_memory.dpatch # new upstream
 14_config.dpatch
 15_mansection8.dpatch
 14_config.dpatch
 15_mansection8.dpatch
+# 16_gzip.dpatch # still broken.
+17_502_no_such_domain.dpatch 
+# 18_dns_retry.dpatch # now upstream
+19_manpage_fixup.dpatch
+20_makefile_fixup.dpatch
+21_version_3.0.4.dpatch
index a5c51fa..faa5722 100644 (file)
@@ -7,9 +7,9 @@
 
 @DPATCH@
 diff -urNad privoxy~/cgi.c privoxy/cgi.c
 
 @DPATCH@
 diff -urNad privoxy~/cgi.c privoxy/cgi.c
---- privoxy~/cgi.c     2006-02-11 23:44:26.000000000 +0100
-+++ privoxy/cgi.c      2006-02-11 23:44:34.000000000 +0100
-@@ -609,6 +609,9 @@
+--- privoxy~/cgi.c
++++ privoxy/cgi.c
+@@ -616,6 +616,9 @@
     { "t",
           cgi_transparent_image, 
           NULL, TRUE /* Send a transparent image (short name) */ },
     { "t",
           cgi_transparent_image, 
           NULL, TRUE /* Send a transparent image (short name) */ },
@@ -19,7 +19,7 @@ diff -urNad privoxy~/cgi.c privoxy/cgi.c
     { NULL, /* NULL Indicates end of list and default page */
           cgi_error_404,
           NULL, TRUE /* Unknown CGI page */ }
     { NULL, /* NULL Indicates end of list and default page */
           cgi_error_404,
           NULL, TRUE /* Unknown CGI page */ }
-@@ -821,21 +824,28 @@
+@@ -828,21 +831,28 @@
     {
        return cgi_error_memory();
     }
     {
        return cgi_error_memory();
     }
@@ -57,7 +57,7 @@ diff -urNad privoxy~/cgi.c privoxy/cgi.c
     }
  
     /*
     }
  
     /*
-@@ -1597,7 +1607,13 @@
+@@ -1604,7 +1614,13 @@
     if (!item) return NULL;
  
     result = strdup("<a href=\"");
     if (!item) return NULL;
  
     result = strdup("<a href=\"");
@@ -72,7 +72,7 @@ diff -urNad privoxy~/cgi.c privoxy/cgi.c
     string_append(&result, ACTIONS_HELP_PREFIX);
     string_join  (&result, string_toupper(item));
     string_append(&result, "\">");
     string_append(&result, ACTIONS_HELP_PREFIX);
     string_join  (&result, string_toupper(item));
     string_append(&result, "\">");
-@@ -2171,7 +2187,11 @@
+@@ -2193,7 +2209,11 @@
     if (!err) err = map(exports, "default-cgi",   1, html_encode(CGI_PREFIX), 0);
     if (!err) err = map(exports, "menu",          1, make_menu(caller), 0);
     if (!err) err = map(exports, "code-status",   1, CODE_STATUS, 1);
     if (!err) err = map(exports, "default-cgi",   1, html_encode(CGI_PREFIX), 0);
     if (!err) err = map(exports, "menu",          1, make_menu(caller), 0);
     if (!err) err = map(exports, "code-status",   1, CODE_STATUS, 1);
@@ -86,9 +86,9 @@ diff -urNad privoxy~/cgi.c privoxy/cgi.c
  #ifdef FEATURE_TOGGLE
     if (!err) err = map_conditional(exports, "enabled-display", global_toggle_state);
 diff -urNad privoxy~/cgisimple.c privoxy/cgisimple.c
  #ifdef FEATURE_TOGGLE
     if (!err) err = map_conditional(exports, "enabled-display", global_toggle_state);
 diff -urNad privoxy~/cgisimple.c privoxy/cgisimple.c
---- privoxy~/cgisimple.c       2006-02-11 23:44:26.000000000 +0100
-+++ privoxy/cgisimple.c        2006-02-11 23:44:34.000000000 +0100
-@@ -642,6 +642,89 @@
+--- privoxy~/cgisimple.c
++++ privoxy/cgisimple.c
+@@ -660,6 +660,89 @@
     return JB_ERR_OK;
  
  }
     return JB_ERR_OK;
  
  }
@@ -179,9 +179,9 @@ diff -urNad privoxy~/cgisimple.c privoxy/cgisimple.c
  
  /*********************************************************************
 diff -urNad privoxy~/cgisimple.h privoxy/cgisimple.h
  
  /*********************************************************************
 diff -urNad privoxy~/cgisimple.h privoxy/cgisimple.h
---- privoxy~/cgisimple.h       2006-02-11 23:44:26.000000000 +0100
-+++ privoxy/cgisimple.h        2006-02-11 23:44:34.000000000 +0100
-@@ -128,6 +128,9 @@
+--- privoxy~/cgisimple.h
++++ privoxy/cgisimple.h
+@@ -132,6 +132,9 @@
  extern jb_err cgi_send_stylesheet(struct client_state *csp,
                                    struct http_response *rsp,
                                    const struct map *parameters);
  extern jb_err cgi_send_stylesheet(struct client_state *csp,
                                    struct http_response *rsp,
                                    const struct map *parameters);
@@ -192,9 +192,9 @@ diff -urNad privoxy~/cgisimple.h privoxy/cgisimple.h
  #ifdef FEATURE_GRACEFUL_TERMINATION
  extern jb_err cgi_die (struct client_state *csp,
 diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
  #ifdef FEATURE_GRACEFUL_TERMINATION
  extern jb_err cgi_die (struct client_state *csp,
 diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
---- privoxy~/loadcfg.c 2006-02-11 23:44:26.000000000 +0100
-+++ privoxy/loadcfg.c  2006-02-11 23:44:34.000000000 +0100
-@@ -1579,7 +1579,13 @@
+--- privoxy~/loadcfg.c
++++ privoxy/loadcfg.c
+@@ -1605,7 +1605,13 @@
      * link to it's section in the user-manual
      */
     buf = strdup("\n<br><a href=\"");
      * link to it's section in the user-manual
      */
     buf = strdup("\n<br><a href=\"");
index 160778d..966d576 100644 (file)
@@ -6,8 +6,8 @@
 
 @DPATCH@
 diff -urNad privoxy~/utils/ldp_print/ldp_print privoxy/utils/ldp_print/ldp_print
 
 @DPATCH@
 diff -urNad privoxy~/utils/ldp_print/ldp_print privoxy/utils/ldp_print/ldp_print
---- privoxy~/utils/ldp_print/ldp_print 2006-02-05 22:03:58.000000000 +0100
-+++ privoxy/utils/ldp_print/ldp_print  2006-02-05 22:12:43.000000000 +0100
+--- privoxy~/utils/ldp_print/ldp_print
++++ privoxy/utils/ldp_print/ldp_print
 @@ -54,7 +54,7 @@
  
  my($cmd) = "htmldoc --size universal --bodyfont helvetica --fontsize 8 " .
 @@ -54,7 +54,7 @@
  
  my($cmd) = "htmldoc --size universal --bodyfont helvetica --fontsize 8 " .
diff --git a/debian/patches/03_ipv6.dpatch b/debian/patches/03_ipv6.dpatch
new file mode 100755 (executable)
index 0000000..853c573
--- /dev/null
@@ -0,0 +1,3535 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 03_ipv6.dpatch by Lionel Elie Mamane <lionel@mamane.lu>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: privoxy_CVS_20030523_ipv6_5.patch.bz2 from
+## DP: ftp://ftp.deepspace6.net/pub/ds6/sources/privoxy/privoxy_CVS_20030523_ipv6_5.patch.bz2
+## DP: adapted to the 3.0 branch of privoxy by Roland Rosenfeld
+
+@DPATCH@
+diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
+--- privoxy~/GNUmakefile.in
++++ privoxy/GNUmakefile.in
+@@ -187,7 +187,7 @@
+ C_SRC  = actions.c cgi.c cgiedit.c cgisimple.c deanimate.c encode.c \
+          errlog.c filters.c gateway.c jbsockets.c jcc.c killpopup.c \
+          list.c loadcfg.c loaders.c miscutil.c parsers.c ssplit.c \
+-         urlmatch.c
++         urlmatch.c addrlist.c jb_socket_set.c
+ C_OBJS = $(C_SRC:.c=.@OBJEXT@)
+ C_HDRS = $(C_SRC:.c=.h) project.h actionlist.h
+@@ -241,7 +241,7 @@
+ SPECIAL_CFLAGS = @SPECIAL_CFLAGS@
+ # Add your flags here 
+-OTHER_CFLAGS =   
++OTHER_CFLAGS = -DINET6
+ CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \
+          @STATIC_PCRE_ONLY@ -Ipcre 
+diff -urNad privoxy~/addrlist.c privoxy/addrlist.c
+--- privoxy~/addrlist.c
++++ privoxy/addrlist.c
+@@ -0,0 +1,198 @@
++const char addrlist_rcs[] = "$Id: $";
++/*********************************************************************
++ *
++ * File        :  $Source: $
++ *
++ * Purpose     :  Declares functions to handle lists of network addresses.
++ *                Functions declared include:
++ *                   `destroy_addr_list', head_addr_list and `tail_addr_list'
++ *
++ * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
++ *                <lionel@mamane.lu>
++ *
++ *                This program is free software; you can redistribute it
++ *                and/or modify it under the terms of the GNU General
++ *                Public License as published by the Free Software
++ *                Foundation; either version 2 of the License, or (at
++ *                your option) any later version.
++ *
++ *                This program is distributed in the hope that it will
++ *                be useful, but WITHOUT ANY WARRANTY; without even the
++ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
++ *                PARTICULAR PURPOSE.  See the GNU General Public
++ *                License for more details.
++ *
++ *                The GNU General Public License should be included with
++ *                this file.  If not, you can view it at
++ *                http://www.gnu.org/copyleft/gpl.html
++ *                or write to the Free Software Foundation, Inc., 59
++ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ * Revisions   :
++ *    $Log: addrlist.c,v $
++ *
++ *********************************************************************/
++
++#include "addrlist.h"
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netdb.h>
++#include <string.h>
++
++/*********************************************************************
++ *
++ * Function    :  acceptable
++ *
++ * Description :  Test wheter an address is acceptable for our use
++ *                Currently, this means either an IPv4 or an IPv6 address
++ *
++ * Parameters  :
++ *          0  :  addr = the address to test
++ *
++ * Returns     :  0             = false / no
++ *                anything else = true / yes
++ *
++ *********************************************************************/
++static int acceptable (struct sockaddr_storage *addr)
++{
++   switch(addr->ss_family)
++   {
++   case AF_INET:
++#ifdef INET6
++   case AF_INET6:
++#endif
++      return !0;
++   default:
++      return 0;
++   }
++}
++
++/*********************************************************************
++ *
++ * Function    :  skim
++ *
++ * Description :  Get the first acceptable address in head position
++ *                Assumes there is one
++ *
++ * Parameters  :
++ *          0  :  l = the list to skim
++ *
++ * Returns     :  the skimmed list
++ *
++ *********************************************************************/
++static addr_list *skim (addr_list *l)
++{
++   if (acceptable((struct sockaddr_storage*)l->ai_addr))
++      return l;
++   return skim(l->ai_next);
++}
++
++/*********************************************************************
++ *
++ * Function    :  tail_addr_list
++ *
++ * Description :  Get the tail of an address list
++ *
++ * Parameters  :
++ *          0  :  l = the list to get the tail of
++ *
++ * Returns     :  the tail of the list
++ *                If the list has no tail (i.e. is nil), unspecified
++ *                behaviour
++ *
++ *********************************************************************/
++addr_list *tail_addr_list(addr_list *l)
++{
++   return skim(l)->ai_next;
++}
++
++/*********************************************************************
++ *
++ * Function    :  head_addr_list
++ *
++ * Description :  Get the head of an address list
++ *
++ * Parameters  :
++ *          0  :  l = the list to get the head of
++ *
++ * Returns     :  the head of the list
++ *                If the list has no head (i.e. is nil), unspecified
++ *                behaviour
++ *
++ *********************************************************************/
++struct sockaddr_storage *head_addr_list(addr_list *l)
++{
++   return (struct sockaddr_storage *)skim(l)->ai_addr;
++}
++
++/*********************************************************************
++ *
++ * Function    :  cpy_head_addr_list
++ *
++ * Description :  Copy the head of an address list to the given destination
++ *
++ * Parameters  :
++ *          0  :  l = the list to get the head of
++ *          1  :  r = where to put the result
++ *
++ * Returns     :  Nothing
++ *                If the list has no head (i.e. is nil), unspecified
++ *                behaviour
++ *
++ *********************************************************************/
++void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen)
++{
++   addr_list *sl = skim(l);
++   memcpy(r, sl->ai_addr, sl->ai_addrlen);
++   *addrlen = sl->ai_addrlen;
++}
++
++/*********************************************************************
++ *
++ * Function    :  destroy_addr_list
++ *
++ * Description :  Unallocate memory allocated to an address list
++ *
++ * Parameters  :
++ *          0  :  l = the list to unallocate
++ *
++ * Returns     :  nothing
++ *
++ *********************************************************************/
++void destroy_addr_list(addr_list *l)
++{
++   freeaddrinfo(l);
++}
++
++/*********************************************************************
++ *
++ * Function    :  is_nil_addr_list
++ *
++ * Description :  Test wheter a list is nil (empty)
++ *
++ * Parameters  :
++ *          0  :  l = the list to test
++ *
++ * Returns     :  0             = false if list has a head,
++ *                anything else = true if list is nil
++ *
++ *********************************************************************/
++int is_nil_addr_list(addr_list *l)
++{
++   /* We are searching for a witness of non-nilness (modulo acceptability)
++    * If none is found, the list is nil
++    */
++   if (l==NULL)
++      /* Empty list*/
++      return !0;
++   if (acceptable(head_addr_list(l)))
++      /* Witness found */
++      return 0;
++   return is_nil_addr_list(l->ai_next);
++}
++
++/*
++  Local Variables:
++  tab-width: 3
++  end:
++*/
+diff -urNad privoxy~/addrlist.h privoxy/addrlist.h
+--- privoxy~/addrlist.h
++++ privoxy/addrlist.h
+@@ -0,0 +1,56 @@
++#ifndef ADDR_LIST_H_INCLUDED
++#define ADDR_LIST_H_INCLUDED
++#define ADDR_LIST_H_VERSION "$Id: $"
++/*********************************************************************
++ *
++ * File        :  $Source: $
++ *
++ * Purpose     :  Declares functions to handle lists of network addresses.
++ *                Functions declared include:
++ *                   `destroy_addr_list', head_addr_list and `tail_addr_list'
++ *
++ * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
++ *                <lionel@mamane.lu>
++ *
++ *                This program is free software; you can redistribute it
++ *                and/or modify it under the terms of the GNU General
++ *                Public License as published by the Free Software
++ *                Foundation; either version 2 of the License, or (at
++ *                your option) any later version.
++ *
++ *                This program is distributed in the hope that it will
++ *                be useful, but WITHOUT ANY WARRANTY; without even the
++ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
++ *                PARTICULAR PURPOSE.  See the GNU General Public
++ *                License for more details.
++ *
++ *                The GNU General Public License should be included with
++ *                this file.  If not, you can view it at
++ *                http://www.gnu.org/copyleft/gpl.html
++ *                or write to the Free Software Foundation, Inc., 59
++ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ * Revisions   :
++ *    $Log: addrlist.h,v $
++ *
++ *********************************************************************/
++
++#include <sys/socket.h>
++
++typedef struct addrinfo addr_list;
++
++addr_list *tail_addr_list(addr_list *l);
++struct sockaddr_storage *head_addr_list(addr_list *l);
++void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen);
++void destroy_addr_list(addr_list *l);
++int is_nil_addr_list(addr_list *l);
++
++#define freez_addr_list(X)  { if(X) { destroy_addr_list(X); X = NULL ; } }
++
++#endif /* ndef LIST_H_INCLUDED */
++
++/*
++  Local Variables:
++  tab-width: 3
++  end:
++*/
+diff -urNad privoxy~/cgi.c privoxy/cgi.c
+--- privoxy~/cgi.c
++++ privoxy/cgi.c
+@@ -14,6 +14,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 8 December 2002, 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and 
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -2167,7 +2170,6 @@
+  *********************************************************************/
+ struct map *default_exports(const struct client_state *csp, const char *caller)
+ {
+-   char buf[20];
+    jb_err err;
+    struct map * exports;
+    int local_help_exists = 0;
+@@ -2199,8 +2201,7 @@
+    if (!err) err = map_block_killer(exports, "can-toggle");
+ #endif
+-   snprintf(buf, 20, "%d", csp->config->hport);
+-   if (!err) err = map(exports, "my-port", 1, buf, 1);
++      if (!err) err = map(exports, "my-port", 1, csp->my_port_str, 1);
+    if(!strcmp(CODE_STATUS, "stable"))
+    {
+diff -urNad privoxy~/errlog.c privoxy/errlog.c
+--- privoxy~/errlog.c
++++ privoxy/errlog.c
+@@ -679,6 +679,13 @@
+             break;
+          case 'E':
+             /* Non-standard: Print error code from errno */
++            /* TODO
++             * This is not only not standard, but clashes
++             * with the E modifier on the GNU (and possibly
++             * other systems): It means double (floating point)
++             * number in exponential notation, with capital E
++             * for mantiss / exponenent separator
++             */
+ #ifdef _WIN32
+             ival = WSAGetLastError();
+             sval = w32_socket_strerr(ival, tempbuf);
+diff -urNad privoxy~/filters.c privoxy/filters.c
+--- privoxy~/filters.c
++++ privoxy/filters.c
+@@ -14,6 +14,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 8 December 2002, 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -427,6 +430,9 @@
+ #include <ctype.h>
+ #include <string.h>
+ #include <assert.h>
++#ifdef INET6
++#include <netdb.h>
++#endif
+ #ifndef _WIN32
+ #ifndef __OS2__
+@@ -461,17 +467,119 @@
+ const char filters_h_rcs[] = FILTERS_H_VERSION;
+-/* Fix a problem with Solaris.  There should be no effect on other
+- * platforms.
+- * Solaris's isspace() is a macro which uses it's argument directly
+- * as an array index.  Therefore we need to make sure that high-bit
+- * characters generate +ve values, and ideally we also want to make
+- * the argument match the declared parameter type of "int".
+- */
+-#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
++#ifdef FEATURE_ACL
++/*********************************************************************
++ *
++ * Function    :  addr_equal_under_mask
++ *
++ * Description :  Are these addresses equal modulo this mask?
++ *                Assumes the second argument is already in
++ *                mask-normal form
++ *
++ * Parameters  :
++ *          0  :  addr1 = First address to compare
++ *          1  :  addr2 = Second address to compare
++ *                        MUST be in mask-normal form
++ *          2  :  mask = for IPv4 addresses, a bitmask
++ *                       for IPv6 addresses, a prefixlen in bits
++ *
++ * Returns     : 0 = FALSE (not equal) and non-zero = TRUE (equal)
++ *
++ *********************************************************************/
++static
++int
++addr_equal_under_mask(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, unsigned long  mask)
++{
++   if (!mask)
++       return 1;
++   /* only identical families can be compared */
++   /* TODO: Should we code the special case of "IPv4 addresses as IPv6 addresses"? */
++   if (addr1->ss_family != addr2-> ss_family)
++     {
++       /*fprintf(stderr, "equal_under_mask: diff sa_family: %d %d\n",
++         sa1->sa_family, sa2-> sa_family); */
++       return 0;
++     }
++  
++   switch (addr1->ss_family)
++      {
++      case AF_INET:
++         {
++            /* IPv4 - mask is a bitmask */
++            struct sockaddr_in *sin1 = (struct sockaddr_in *)addr1;
++            struct sockaddr_in *sin2 = (struct sockaddr_in *)addr2;
++            
++            /*fprintf(stderr, "AF_INET: %08x %08x %08x\n", 
++              sin1->sin_addr.s_addr,
++              sin2->sin_addr.s_addr,
++              mask); */
++            return (sin1->sin_addr.s_addr & mask) == sin2->sin_addr.s_addr;
++         }
++         break;
++#ifdef INET6
++      case AF_INET6:
++         {
++            /* IPv6 - mask is a prefixlength in bits. */
++            struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)addr1;
++            struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)addr2;
++            char bitmask;
++            char *a1, *a2;
++            const int maskbytes = mask / 8;
++            static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
++                                0xF0, 0xF8, 0xFC, 0xFE };
++/*             { */
++/*                int i; */
++/*                fprintf(stderr, "PF_INET6: "); */
++/*                for (i = 0; i < 16; i++) { */
++/*                   fprintf(stderr, "%02x ", sin1->sin6_addr.s6_addr[i]); */
++/*                } */
++/*                fprintf(stderr, "   "); */
++/*                for (i = 0; i < 16; i++) { */
++/*                   fprintf(stderr, "%02x ", sin2->sin6_addr.s6_addr[i]); */
++/*                } */
++/*                fprintf(stderr, "mask %d scopeids %x %x\n", mask, sin1->sin6_scope_id, sin2->sin6_scope_id); */
++/*             } */
++            /* should we compare scope ids and such too? */
++            /*
++             * LEM: I see no reason for this comparison
++             * Quite the contrary: A client coming to us with
++             * a small-scope address should be able to a bigger-scope
++             * address.
++             */
++/*             if (sin1->sin6_scope_id != sin2->sin6_scope_id) */
++/*                return 0; */
++
++            if (mask > 128ul)
++            {
++               log_error(LOG_LEVEL_ERROR, "%s%d", "Tried to compare IPv6 addresses with invalid prefixlen: ", mask);
++               return 0;
++            }
++
++            a1 = sin1->sin6_addr.s6_addr;
++            a2 = sin2->sin6_addr.s6_addr;
++
++            if (memcmp(a1, a2, maskbytes) != 0)
++               return 0;
++
++            mask %= 8;
++            /* This special case is necessary for when mask==128
++               else, we would go over the array size in a1/a2
++             */
++            if (mask==0)
++               return 1;
++
++            bitmask = m[mask];
++
++            return (a1[maskbytes] & bitmask) == a2[maskbytes];
++      }
++         break;
++#endif
++      default:
++         return 0;
++      }
++}
+-#ifdef FEATURE_ACL
+ /*********************************************************************
+  *
+  * Function    :  block_acl
+@@ -501,7 +609,7 @@
+    /* search the list */
+    while (acl != NULL)
+    {
+-      if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
++      if (addr_equal_under_mask(&csp->ip_addr_addr, &acl->src->addr, acl->src->mask))
+       {
+          if (dst == NULL)
+          {
+@@ -511,8 +619,8 @@
+                return(0);
+             }
+          }
+-         else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
+-           && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
++         else if ( addr_equal_under_mask(&dst->addr, &acl->dst->addr, acl->dst->mask)
++                   && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
+          {
+             if (acl->action == ACL_PERMIT)
+             {
+@@ -531,81 +639,249 @@
+ }
+-
+ /*********************************************************************
+  *
+- * Function    :  acl_addr
++ * Function    :  fill_acl_addr_mask
+  *
+- * Description :  Called from `load_config' to parse an ACL address.
++ * Description :  Fill in the mask-related members of a
++ *                struct access_control_addr
+  *
+  * Parameters  :
+- *          1  :  aspec = String specifying ACL address.
+- *          2  :  aca = struct access_control_addr to fill in.
++ *          0  :  aca = struct access_control_addr to fill in.
++ *          1  :  masklength = mask length.
+  *
+- * Returns     :  0 => Ok, everything else is an error.
++ * Returns     :  nothing
+  *
+  *********************************************************************/
+-int acl_addr(char *aspec, struct access_control_addr *aca)
++void fill_acl_addr_mask(struct access_control_addr *aca, int masklength)
+ {
+-   int i, masklength, port;
+-   char *p;
++   int pf;
+-   masklength = 32;
+-   port       =  0;
++   pf = aca->addr.ss_family;
+-   if ((p = strchr(aspec, '/')) != NULL)
++   switch (pf)
+    {
+-      *p++ = '\0';
+-
+-      if (ijb_isdigit(*p) == 0)
++   case PF_INET:
++      /* build the netmask */
++      if (masklength == -1)
++         masklength = 32;
++      aca->mask = 0;
++      for(pf=1; pf <= masklength ; ++pf)
+       {
+-         return(-1);
++         aca->mask |= (1 << (32 - pf));
+       }
+-      masklength = atoi(p);
+-   }
++      aca->mask = htonl(aca->mask);
++      
++      /* now mask off the host portion of the ip address
++       * (i.e. save on the network portion of the address).
++       */
++      ((struct sockaddr_in*) &aca->addr)->sin_addr.s_addr &= aca->mask;
++      aca->port = ((struct sockaddr_in*) &aca->addr)->sin_port;
++      break;
++#ifdef INET6
++   case PF_INET6:
++      {
++         static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
++                             0xF0, 0xF8, 0xFC, 0xFE };
++         int i;
++         struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)&aca->addr;
+-   if ((masklength < 0) || (masklength > 32))
+-   {
+-      return(-1);
++         aca->mask = (masklength == -1) ? masklength : 128 ;
++         /* now mask off the host portion of the ip address
++          * (i.e. save on the network portion of the address).
++          */
++         i = aca->mask / 8;
++         if (i < 16)
++         {
++            sa6->sin6_addr.s6_addr[i] &= m[aca->mask % 8];
++            /* The following loop is not strictly necessary,
++               because of the way addr_equal_under_mask is
++               written. Better safe than sorry, though:
++               New code might make the full mask-normal
++               form assumption.
++             */
++            for(++i; i < 16 ; ++i)
++               sa6->sin6_addr.s6_addr[i] = 0;
++         }
++         aca -> port = sa6->sin6_port;
++         break;
++      }
++#endif
++   default:
++      /* FATAL because access_control_addr's are created only with adresses
++         deemed 'acceptable' by the addr_list stuff, thus currently IPv4 and
++         IPv6.
++       */
++      log_error(LOG_LEVEL_FATAL,"%s%d","Unknown address family in ACL address: ",pf);
+    }
++}
+-   if ((p = strchr(aspec, ':')) != NULL)
+-   {
+-      *p++ = '\0';
++/*********************************************************************
++ *
++ * Function    :  acl_addrs
++ *
++ * Description :  Parse an ACL address (adress + mask prefix)
++ *                Resolve the parsed address
++ *                Describe errors in *proxy_args.
++ *
++ * Parameters  :
++ *          0  :  aspec = the string containing the ACL address/mask
++ *          1  :  masklength = pointer used to return the mask
++ *          2  :  proxy_args = Pointer to string to append description of errors to.
++ *          3  :  type = type of ACL adress (source / destination).
++ *                       Used for error reporting.
++ *
++ * Returns     :  the list of adresses the ACL address resolves to
++ *
++ *********************************************************************/
++static addr_list *acl_addrs(char *aspec, int *masklength, char**proxy_args, const char *type)
++{
++   char *host;
++   char *port;
++   int pf;
+-      if (ijb_isdigit(*p) == 0)
+-      {
+-         return(-1);
+-      }
+-      port = atoi(p);
++   pf = -1;
++   if (parse_pf_ip_netmask(aspec, &host, &port, &pf, masklength) != 0)
++   {
++      log_error(LOG_LEVEL_ERROR, "Invalid %s IP for (deny|permit)-access "
++                "directive in configuration file: \"%s\"", type, aspec);
++      string_append(proxy_args,"<br>\nWARNING: Invalid ");
++      string_append(proxy_args, type);
++      string_append(proxy_args," IP for (deny|permit)-access directive"
++                    " in configuration file: \"");
++      string_append(proxy_args, aspec);
++      string_append(proxy_args,"\"<br><br>\n");
++      return NULL;
+    }
+-   aca->port = port;
++   return resolve_hostname_to_ip(host, port, pf);
++}
+-   aca->addr = ntohl(resolve_hostname_to_ip(aspec));
++/*********************************************************************
++ *
++ * Function    :  add_one_to_acl_list
++ *
++ * Description :  Add one entry to an access_control_list.
++ *
++ * Parameters  :
++ *          0  :  l = the list to add to
++ *          1  :  action = ACL_DENY or ACL_PERMIT
++ *          2  :  src_addrs = the head of this list will be used as source
++ *                            in the ACL entry.
++ *          3  :  dst_addrs = the head of this list will be used as destination
++ *                            in the ACL entry.
++ *                            NULL for none
++ *          4  :  src_masklength = mask length for the source
++ *          5  :  src_masklength = mask length for the destination
++ *
++ * Returns     :  the new list
++ *
++ *********************************************************************/
++struct access_control_list *add_one_to_acl_list(struct access_control_list *l, short action,
++                                                addr_list *src_addrs, addr_list *dst_addrs,
++                                                int src_masklength, int dst_masklength)
++{
++   struct access_control_list *cur_acl;
++   /* allocate a new node */
++   cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
+-   if (aca->addr == INADDR_NONE)
++   if (cur_acl == NULL)
+    {
+-      return(-1);
++      log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
++      /* Never get here - LOG_LEVEL_FATAL causes program exit */
++      return l;
+    }
+-   /* build the netmask */
+-   aca->mask = 0;
+-   for (i=1; i <= masklength ; i++)
++   cur_acl->action = action;
++
++   cpy_head_addr_list(src_addrs, &cur_acl->src->addr, &cur_acl->src->addrlen);
++   fill_acl_addr_mask(cur_acl->src, src_masklength);
++   if (dst_addrs != NULL)
+    {
+-      aca->mask |= (1 << (32 - i));
++      cpy_head_addr_list(dst_addrs, &cur_acl->dst->addr, &cur_acl->dst->addrlen);
++      fill_acl_addr_mask(cur_acl->src, src_masklength);
+    }
+-   /* now mask off the host portion of the ip address
+-    * (i.e. save on the network portion of the address).
++   /*
++    * Add it to the list.  Note we reverse the list to get the
++    * behaviour the user expects.  With both the ACL and
++    * actions file, the last match wins.  However, the internal
++    * implementations are different:  The actions file is stored
++    * in the same order as the file, and scanned completely.
++    * With the ACL, we reverse the order as we load it, then
++    * when we scan it we stop as soon as we get a match.
+     */
+-   aca->addr = aca->addr & aca->mask;
++   cur_acl->next  = l;
+-   return(0);
++   return cur_acl;
++}
++
++/*********************************************************************
++ *
++ * Function    :  add_to_acl_list
++ *
++ * Description :  Add entries to an access_control_list.
++ *                Describe errors in *proxy_args.
++ *
++ * Parameters  :
++ *          0  :  l = the list to add to
++ *          1  :  action = ACL_DENY or ACL_PERMIT
++ *          2  :  src_spec = String giving the source of the acl entry
++ *          3  :  dst_spec = String giving the destination of the acl entry,
++ *                           or NULL
++ *          4  :  proxy_args = Pointer to string to append description of errors to.
++ *
++ * Returns     :  the new list
++ *
++ *********************************************************************/
++struct access_control_list *add_to_acl_list(struct access_control_list *l,
++                                            short action,
++                                            char *src_spec,
++                                            char *dst_spec,
++                                            char **proxy_args)
++{
++   int src_masklength, dst_masklength;
++   addr_list *src_addrs, *dst_addrs;
++   addr_list *src_addrs_remaining, *dst_addrs_remaining;
++
++   src_addrs = acl_addrs(src_spec, &src_masklength, proxy_args, "source");
++   if (is_nil_addr_list(src_addrs))
++   {
++      log_error(LOG_LEVEL_ERROR, "Source of ACL resolves to no address",dst_spec);
++      return l;
++   }
++   if (dst_spec != NULL)
++   {
++      dst_addrs = acl_addrs(dst_spec, &dst_masklength, proxy_args, "destination");
++      if (is_nil_addr_list(dst_addrs))
++      {
++         log_error(LOG_LEVEL_ERROR, "Destination of ACL resolves to no address",dst_spec);
++         destroy_addr_list(src_addrs);
++         return l;
++      }
++   }
++   else
++      dst_addrs = NULL;
++
++   for(src_addrs_remaining = src_addrs;
++       is_nil_addr_list(src_addrs);
++       src_addrs_remaining=tail_addr_list(src_addrs_remaining))
++   {
++      if (dst_addrs == NULL)
++         l = add_one_to_acl_list(l, action, src_addrs_remaining, NULL, src_masklength,0);
++      else for(dst_addrs_remaining = dst_addrs;
++               is_nil_addr_list(dst_addrs);
++               dst_addrs_remaining=tail_addr_list(dst_addrs_remaining))
++         l = add_one_to_acl_list(l, action, src_addrs_remaining, dst_addrs_remaining,
++                                 src_masklength, dst_masklength);
++   }
++   destroy_addr_list(src_addrs);
++   destroy_addr_list(dst_addrs);
++   return l;
+ }
+-#endif /* def FEATURE_ACL */
++#endif /* def FEATURE_ACL */
+ /*********************************************************************
+  *
+@@ -1048,7 +1324,7 @@
+  *********************************************************************/
+ struct http_response *redirect_url(struct client_state *csp)
+ {
+-   char *p, *q;
++   const char *p, *q;
+    struct http_response *rsp;
+    p = q = csp->http->path;
+diff -urNad privoxy~/filters.h privoxy/filters.h
+--- privoxy~/filters.h
++++ privoxy/filters.h
+@@ -15,6 +15,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 8 December 2002, 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and 
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -221,7 +224,11 @@
+  */
+ #ifdef FEATURE_ACL
+ extern int block_acl(struct access_control_addr *dst, struct client_state *csp);
+-extern int acl_addr(char *aspec, struct access_control_addr *aca);
++extern struct access_control_list *add_to_acl_list(struct access_control_list *l,
++                                                   short action,
++                                                   char *src_spec,
++                                                   char *dst_spec,
++                                                   char **proxy_args);
+ #endif /* def FEATURE_ACL */
+ extern int match_portlist(const char *portlist, int port);
+diff -urNad privoxy~/gateway.c privoxy/gateway.c
+--- privoxy~/gateway.c
++++ privoxy/gateway.c
+@@ -10,6 +10,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 8 December 2002, 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -199,12 +202,14 @@
+  * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket file descriptor.
+  *
+  *********************************************************************/
+-jb_socket forwarded_connect(const struct forward_spec * fwd,
++jb_socket forwarded_connect(const struct forward_spec *fwd,
+                             struct http_request *http,
+                             struct client_state *csp)
+ {
+    const char * dest_host;
+-   int dest_port;
++   const char * dest_port_str;
++   unsigned long dest_port;
++   int dest_pf;
+    /* Figure out if we need to connect to the web server or a HTTP proxy. */
+    if (fwd->forward_host)
+@@ -212,19 +217,23 @@
+       /* HTTP proxy */
+       dest_host = fwd->forward_host;
+       dest_port = fwd->forward_port;
++      dest_port_str = fwd->forward_port_str;
++      dest_pf = fwd->forward_family;
+    }
+    else
+    {
+       /* Web server */
+       dest_host = http->host;
+       dest_port = http->port;
++      dest_port_str = http->port_str;
++      dest_pf = PF_UNSPEC;
+    }
+    /* Connect, maybe using a SOCKS proxy */
+    switch (fwd->type)
+    {
+       case SOCKS_NONE:
+-         return (connect_to(dest_host, dest_port, csp));
++         return (connect_to(dest_host, dest_port_str, dest_port, dest_pf, csp));
+       case SOCKS_4:
+       case SOCKS_4A:
+@@ -258,74 +267,19 @@
+  * Returns     :  JB_INVALID_SOCKET => failure, else a socket file descriptor.
+  *
+  *********************************************************************/
+-static jb_socket socks4_connect(const struct forward_spec * fwd,
+-                                const char * target_host,
+-                                int target_port,
+-                                struct client_state *csp)
++static jb_socket socks4_connect_one_ip(const struct forward_spec * fwd,
++                                       unsigned long web_server_addr,
++                                       int target_port,
++                                       struct client_state *csp,
++                                       size_t csiz,
++                                       char *cbuf)
+ {
+-   int web_server_addr;
+-   char cbuf[BUFFER_SIZE];
+    char sbuf[BUFFER_SIZE];
+-   struct socks_op    *c = (struct socks_op    *)cbuf;
+    struct socks_reply *s = (struct socks_reply *)sbuf;
+-   size_t n;
+-   size_t csiz;
++   struct socks_reply *c = (struct socks_reply *)cbuf;
+    jb_socket sfd;
+-   int err = 0;
+    char *errstr;
+-   if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
+-   {
+-      log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
+-      err = 1;
+-   }
+-
+-   if (fwd->gateway_port <= 0)
+-   {
+-      log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
+-      err = 1;
+-   }
+-
+-   if (err)
+-   {
+-      errno = EINVAL;
+-      return(JB_INVALID_SOCKET);
+-   }
+-
+-   /* build a socks request for connection to the web server */
+-
+-   strcpy((char *)&(c->userid), socks_userid);
+-
+-   csiz = sizeof(*c) + sizeof(socks_userid) - 1;
+-
+-   switch (fwd->type)
+-   {
+-      case SOCKS_4:
+-         web_server_addr = htonl(resolve_hostname_to_ip(target_host));
+-         if (web_server_addr == INADDR_NONE)
+-         {
+-            log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
+-            return(JB_INVALID_SOCKET);
+-         }
+-         break;
+-      case SOCKS_4A:
+-         web_server_addr = 0x00000001;
+-         n = csiz + strlen(target_host) + 1;
+-         if (n > sizeof(cbuf))
+-         {
+-            errno = EINVAL;
+-            return(JB_INVALID_SOCKET);
+-         }
+-         strcpy(cbuf + csiz, target_host);
+-         csiz = n;
+-         break;
+-      default:
+-         /* Should never get here */
+-         log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
+-         errno = EINVAL;
+-         return(JB_INVALID_SOCKET);
+-   }
+-
+    c->vn          = 4;
+    c->cd          = 1;
+    c->dstport[0]  = (target_port       >> 8  ) & 0xff;
+@@ -336,7 +290,7 @@
+    c->dstip[3]    = (web_server_addr         ) & 0xff;
+    /* pass the request to the socks server */
+-   sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
++   sfd = connect_to(fwd->gateway_host, fwd->gateway_port_str, fwd->gateway_port, PF_INET ,csp);
+    if (sfd == JB_INVALID_SOCKET)
+    {
+@@ -391,6 +345,92 @@
+ }
++static jb_socket socks4_connect(const struct forward_spec * fwd,
++                                const char * target_host,
++                                int target_port,
++                                struct client_state *csp)
++{
++   char cbuf[BUFFER_SIZE];
++   struct socks_op    *c = (struct socks_op    *)cbuf;
++   size_t csiz;
++   int err = 0;
++
++   /**
++    * SOCKS4 is IPv4-specific. At least I think so.
++    */
++   if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
++   {
++      log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
++      err = 1;
++   }
++
++   if (fwd->gateway_port <= 0)
++   {
++      log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
++      err = 1;
++   }
++
++   if (err)
++   {
++      errno = EINVAL;
++      return(JB_INVALID_SOCKET);
++   }
++
++   /* build a socks request for connection to the web server */
++
++   strcpy((char *)&(c->userid), socks_userid);
++
++   csiz = sizeof(*c) + sizeof(socks_userid) - 1;
++
++   switch (fwd->type)
++   {
++      case SOCKS_4:
++      {
++         addr_list *web_server_addrs = resolve_hostname_to_ip(target_host,NULL,PF_INET);
++         jb_socket return_value = JB_INVALID_SOCKET;
++         if (is_nil_addr_list(web_server_addrs))
++         {
++            log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
++         }
++         else
++         {
++            addr_list *addrs_to_try;
++            
++            for(addrs_to_try = web_server_addrs;
++                !is_nil_addr_list(addrs_to_try);
++                addrs_to_try = tail_addr_list(addrs_to_try))
++            {
++               const unsigned long web_server_addr = ((struct sockaddr_in*) head_addr_list(addrs_to_try))->sin_addr.s_addr;
++               return_value=socks4_connect_one_ip(fwd, web_server_addr, target_port, csp, csiz, cbuf);
++               if(return_value != JB_INVALID_SOCKET)
++                  break;
++            }
++         }
++         destroy_addr_list(web_server_addrs);
++         return return_value;
++         break;
++      }
++      case SOCKS_4A:
++      {
++         size_t n;
++         n = csiz + strlen(target_host) + 1;
++         if (n > sizeof(cbuf))
++         {
++            errno = EINVAL;
++            return(JB_INVALID_SOCKET);
++         }
++         strcpy(cbuf + csiz, target_host);
++         csiz = n;
++         return socks4_connect_one_ip(fwd, 0x00000001, target_port, csp, csiz, cbuf);
++         break;
++      }
++      default:
++         /* Should never get here */
++         log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
++         errno = EINVAL;
++         return(JB_INVALID_SOCKET);
++   }
++}
+ /*
+   Local Variables:
+diff -urNad privoxy~/jb_socket_set.c privoxy/jb_socket_set.c
+--- privoxy~/jb_socket_set.c
++++ privoxy/jb_socket_set.c
+@@ -0,0 +1,174 @@
++const char jb_socket_set_rcs[] = "$Id: $";
++/*********************************************************************
++ *
++ * File        :  $Source: $
++ *
++ * Purpose     :  Declares functions to handle sets of sockets
++ *
++ * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
++ *                <lionel@mamane.lu>
++ *
++ *                This program is free software; you can redistribute it
++ *                and/or modify it under the terms of the GNU General
++ *                Public License as published by the Free Software
++ *                Foundation; either version 2 of the License, or (at
++ *                your option) any later version.
++ *
++ *                This program is distributed in the hope that it will
++ *                be useful, but WITHOUT ANY WARRANTY; without even the
++ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
++ *                PARTICULAR PURPOSE.  See the GNU General Public
++ *                License for more details.
++ *
++ *                The GNU General Public License should be included with
++ *                this file.  If not, you can view it at
++ *                http://www.gnu.org/copyleft/gpl.html
++ *                or write to the Free Software Foundation, Inc., 59
++ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ * Revisions   :
++ *    $Log: jb_socket_set.c,v $
++ *
++ *********************************************************************/
++
++#include "jb_socket_set.h"
++#include <sys/time.h>
++#include <sys/types.h>
++#include <unistd.h>
++#include "project.h"
++
++/*********************************************************************
++ *
++ * Function    :  jb_socket_set_add
++ *
++ * Description :  Add a socket to the set
++ *
++ * Parameters  :
++ *          0  :  l = the set to add to
++ *          1  :  the elemen to add to the set
++ *
++ * Returns     :  0 on success
++ *                non-0 on failure
++ *
++ *********************************************************************/
++
++int jb_socket_set_add(jb_socket_set *l, jb_socket e)
++{
++   if (l->data==NULL)
++   {
++      l->size=2;
++      l->data=malloc(l->size * sizeof(jb_socket));
++      if (l->data==NULL)
++      {
++         l->size = 0;
++         return -1;
++      }
++      l->occupied=0;
++   }
++   l->data[(l->occupied)++] = e;
++   if (l->occupied == l->size)
++   {
++      jb_socket *new_data;
++      l->size *= 2;
++      new_data = realloc(l->data,l->size * sizeof(jb_socket));
++      if (new_data == NULL)
++      {
++         /* Not enough memory to continue. Cancel changes. */
++         l->data[--(l->occupied)] = JB_INVALID_SOCKET;
++         l->size /= 2;
++         return -1;
++      }
++      l->data = new_data;
++   }
++   l->data[l->occupied] = JB_INVALID_SOCKET;
++   return 0;
++}
++
++/*********************************************************************
++ *
++ * Function    :  destroy_jb_socket_set
++ *
++ * Description :  Unallocate memory allocated to a socket set
++ *
++ * Parameters  :
++ *          0  :  l = the set to unallocate
++ *
++ * Returns     :  nothing
++ *
++ *********************************************************************/
++void destroy_jb_socket_set(jb_socket_set *l)
++{
++   free(l->data);
++   init_jb_socket_set(l);
++}
++/*********************************************************************
++ *
++ * Function    :  is_empty_jb_socket_set
++ *
++ * Description :  Test wheter a set is empty
++ *
++ * Parameters  :
++ *          0  :  l = the set to test
++ *
++ * Returns     :  0             = false if set has a head,
++ *                anything else = true if set is nil
++ *
++ *********************************************************************/
++int is_nil_jb_socket_set(jb_socket_set *l)
++{
++   return (l->occupied == 0);
++}
++
++/*********************************************************************
++ *
++ * Function    :  init_jb_socket_set
++ *
++ * Description :  Init a set to empty
++ *
++ * Parameters  :
++ *          0  :  l = the set to init
++ *
++ *********************************************************************/
++void init_jb_socket_set(jb_socket_set *l)
++{
++   l->data=NULL;
++   l->size=0;
++   l->occupied=0;
++}
++
++/*********************************************************************
++ *
++ * Function    :  jb_socket_set_iteration_begin
++ *
++ * Description :  Return an iterator on the set
++ *
++ * Parameters  :
++ *          0  :  l = the set
++ *
++ *********************************************************************/
++jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *l)
++{
++   return l->data;
++}
++
++/*********************************************************************
++ *
++ * Function    :  jb_socket_set_iteration_next
++ *
++ * Description :  Return value pointed to by iterator and step
++ *                iterator to next position
++ *
++ * Parameters  :
++ *          0  :  s = the iterator
++ *
++ *********************************************************************/
++jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*s)
++{
++   return(*((*s)++));
++}
++
++/*
++  Local Variables:
++  tab-width: 3
++  end:
++*/
+diff -urNad privoxy~/jb_socket_set.h privoxy/jb_socket_set.h
+--- privoxy~/jb_socket_set.h
++++ privoxy/jb_socket_set.h
+@@ -0,0 +1,71 @@
++#ifndef JB_SOCKET_SET_H_INCLUDED
++#define JB_SOCKET_SET_H_INCLUDED
++#define JB_SOCKET_SET_H_VERSION "$Id: $"
++/*********************************************************************
++ *
++ * File        :  $Source: $
++ *
++ * Purpose     :  Declares functions to handle sets of sockets
++ *
++ * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
++ *                <lionel@mamane.lu>
++ *
++ *                This program is free software; you can redistribute it
++ *                and/or modify it under the terms of the GNU General
++ *                Public License as published by the Free Software
++ *                Foundation; either version 2 of the License, or (at
++ *                your option) any later version.
++ *
++ *                This program is distributed in the hope that it will
++ *                be useful, but WITHOUT ANY WARRANTY; without even the
++ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
++ *                PARTICULAR PURPOSE.  See the GNU General Public
++ *                License for more details.
++ *
++ *                The GNU General Public License should be included with
++ *                this file.  If not, you can view it at
++ *                http://www.gnu.org/copyleft/gpl.html
++ *                or write to the Free Software Foundation, Inc., 59
++ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ * Revisions   :
++ *    $Log: jb_socket_set.h,v $
++ *
++ *********************************************************************/
++#include <sys/time.h>
++#include <sys/types.h>
++#include <unistd.h>
++#include "project.h"
++
++struct jb_socket_set_struct
++{
++   unsigned int size; /* size allocated*/
++   unsigned int occupied; /* size occupied - 1 == index of final JB_INVALID_SOCKET
++                             == number of sockets in the set */
++   jb_socket *data; /* Array containing the sockets, JB_INVALID_SOCKET-terminated */
++};
++
++typedef struct jb_socket_set_struct jb_socket_set;
++typedef const jb_socket* jb_socket_set_iterate_state;
++
++void init_jb_socket_set(jb_socket_set*);
++
++jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *);
++jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*);
++
++int jb_socket_set_add(jb_socket_set*, jb_socket);
++
++void destroy_jb_socket_set(jb_socket_set *l);
++int is_empty_jb_socket_set(jb_socket_set *l);
++
++#define freez_jb_socket_set(X)  { if(X) { destroy_jb_socket_set(X); X = NULL ; } }
++
++int jb_select(jb_socket_set *readfds, jb_socket_set *writefds, jb_socket_set *exceptfds, struct timeval *timeout);
++
++#endif /* ndef JB_SOCKET_SET_H_INCLUDED */
++
++/*
++  Local Variables:
++  tab-width: 3
++  end:
++*/
+diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c
+--- privoxy~/jbsockets.c
++++ privoxy/jbsockets.c
+@@ -11,6 +11,10 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 8-9 December 2002, 24 January 2003,
++ *                13 February 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and 
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -258,6 +262,7 @@
+ #include "jbsockets.h"
+ #include "filters.h"
+ #include "errlog.h"
++#include "addrlist.h"
+ const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
+@@ -270,141 +275,194 @@
+  *                that this is allowed according to ACL.
+  *
+  * Parameters  :
+- *          1  :  host = hostname to connect to
+- *          2  :  portnum = port to connent on
++ *          0  :  host = hostname to connect to
++ *          1  :  port = port to connect on, as string
++ *          2  :  portnum = port to connect on, as integer
+  *          3  :  csp = Current client state (buffers, headers, etc...)
+- *                      Not modified, only used for source IP and ACL.
+  *
+  * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket
+  *                file descriptor.
+  *
+  *********************************************************************/
+-jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
++jb_socket connect_to_one_ip(struct sockaddr_storage *addr, size_t addrlen, const char *host, unsigned long portnum, struct client_state *csp)
+ {
+-   struct sockaddr_in inaddr;
+-   jb_socket fd;
+-   int addr;
+-   fd_set wfds;
+-   struct timeval tv[1];
+-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
+-   int   flags;
+-#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
+-
+ #ifdef FEATURE_ACL
+-   struct access_control_addr dst[1];
+-#endif /* def FEATURE_ACL */
+-
+-   memset((char *)&inaddr, 0, sizeof inaddr);
+-
+-   if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
++   if (csp)
+    {
+-      csp->http->host_ip_addr_str = strdup("unknown");
+-      return(JB_INVALID_SOCKET);
+-   }
++      struct access_control_addr dst[1];
++      char hostname[NI_MAXHOST];
++      char port[NI_MAXSERV];
++      if (getnameinfo((struct sockaddr*)addr, addrlen, hostname, NI_MAXHOST,
++                      port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
++      {
++         log_error(LOG_LEVEL_ERROR, "connect: Could not get string address and port back from sockaddr because %E");
++         strncpy(hostname,"unknown",NI_MAXHOST);
++         strncpy(port,"unknown",NI_MAXSERV);
++      }
+-#ifdef FEATURE_ACL
+-   dst->addr = ntohl((unsigned long) addr);
+-   dst->port = portnum;
++      csp->http->host_ip_addr_str = strdup(hostname);
+-   if (block_acl(dst, csp))
+-   {
++      dst->addr = *addr;
++      dst->addrlen = addrlen;
++      dst->port = portnum;
++
++      if (block_acl(dst, csp))
++      {
+ #ifdef __OS2__
+-      errno = SOCEPERM;
++         errno = SOCEPERM;
+ #else
+-      errno = EPERM;
++         errno = EPERM;
+ #endif
+-      return(JB_INVALID_SOCKET);
+-   }
+-#endif /* def FEATURE_ACL */
++         return(JB_INVALID_SOCKET);
++      }
+-   inaddr.sin_addr.s_addr = addr;
+-   inaddr.sin_family      = AF_INET;
+-   csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
+-#ifndef _WIN32
+-   if (sizeof(inaddr.sin_port) == sizeof(short))
+-#endif /* ndef _WIN32 */
+-   {
+-      inaddr.sin_port = htons((unsigned short) portnum);
+    }
+-#ifndef _WIN32
+-   else
++#endif /* def FEATURE_ACL */
++
+    {
+-      inaddr.sin_port = htonl((unsigned long)portnum);
+-   }
+-#endif /* ndef _WIN32 */
++      jb_socket fd;
+ #ifdef _WIN32
+-   if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
++      if ((fd = socket(addr->ss_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
+ #else
+-   if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
++      if ((fd = socket(addr->ss_family, SOCK_STREAM, 6)) < 0)
+ #endif
+-   {
+-      return(JB_INVALID_SOCKET);
+-   }
++      {
++         return(JB_INVALID_SOCKET);
++      }
+ #ifdef TCP_NODELAY
+-   {  /* turn off TCP coalescence */
+-      int mi = 1;
+-      setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
+-   }
++      {  /* turn off TCP coalescence */
++         int mi = 1;
++         setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
++      }
+ #endif /* def TCP_NODELAY */
+ #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+-   if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
+-   {
+-      flags |= O_NDELAY;
+-      fcntl(fd, F_SETFL, flags);
+-   }
++      {
++         int flags;
++
++         if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
++         {
++            flags |= O_NDELAY;
++            fcntl(fd, F_SETFL, flags);
++         }
++      }
+ #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+-   while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
+-   {
++      while (connect(fd, (struct sockaddr *) addr, addrlen) == JB_INVALID_SOCKET)
++      {
+ #ifdef _WIN32
+-      if (errno == WSAEINPROGRESS)
++         if (errno == WSAEINPROGRESS)
+ #elif __OS2__ 
+-      if (sock_errno() == EINPROGRESS)
++         if (sock_errno() == EINPROGRESS)
+ #else /* ifndef _WIN32 */
+-      if (errno == EINPROGRESS)
++         if (errno == EINPROGRESS)
+ #endif /* ndef _WIN32 || __OS2__ */
+-      {
+-         break;
+-      }
++         {
++            break;
++         }
+ #ifdef __OS2__ 
+-      if (sock_errno() != EINTR)
++         if (sock_errno() != EINTR)
+ #else
+-      if (errno != EINTR)
++         if (errno != EINTR)
+ #endif /* __OS2__ */
++         {
++            close_socket(fd);
++            return(JB_INVALID_SOCKET);
++         }
++      }
++
++#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+       {
+-         close_socket(fd);
+-         return(JB_INVALID_SOCKET);
++         int flags;
++         if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
++         {
++            flags &= ~O_NDELAY;
++            fcntl(fd, F_SETFL, flags);
++         }
+       }
+-   }
++#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
++
++      {
++         fd_set wfds;
++         struct timeval tv[1];
++
++         /* wait for connection to complete */
++         FD_ZERO(&wfds);
++         FD_SET(fd, &wfds);
++         tv->tv_sec  = 30;
++         tv->tv_usec = 0;
++
++         /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
++         if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
++         {
++            close_socket(fd);
++            return(JB_INVALID_SOCKET);
++         }
+ #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+-   if (flags != -1)
+-   {
+-      flags &= ~O_NDELAY;
+-      fcntl(fd, F_SETFL, flags);
+-   }
++         else
++         {
++            int connect_result;
++            socklen_t connect_result_len = sizeof connect_result;
++
++            if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &connect_result, &connect_result_len) != 0)
++            {
++               log_error(LOG_LEVEL_ERROR, "Could not determine whether connection to %s port %d was successful because %E. Assuming failure.",
++                         csp->http->host_ip_addr_str, portnum);
++               close_socket(fd);
++               return(JB_INVALID_SOCKET);
++            }
++            else if( connect_result != 0 )
++            {
++               log_error(LOG_LEVEL_CONNECT, "Connection to %s port %d failed because %s.",
++                         csp->http->host_ip_addr_str, portnum, strerror(connect_result));
++               close_socket(fd);
++               return(JB_INVALID_SOCKET);
++            }
++         }
+ #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
++      }
++      return(fd);
++   }
++}
+-   /* wait for connection to complete */
+-   FD_ZERO(&wfds);
+-   FD_SET(fd, &wfds);
++jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp)
++{
++   jb_socket fd = JB_INVALID_SOCKET;
++   struct sockaddr_storage addr;
++   addr_list *addrs, *addrs_to_try;
+-   tv->tv_sec  = 30;
+-   tv->tv_usec = 0;
++   addrs = resolve_hostname_to_ip(host,port,pf);
+-   /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
+-   if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
++   if (is_nil_addr_list(addrs))
+    {
+-      close_socket(fd);
+-      return(JB_INVALID_SOCKET);
++      errno = EINVAL;
++      return fd;
+    }
+-   return(fd);
++   for(addrs_to_try=addrs;
++       !is_nil_addr_list(addrs_to_try);
++       addrs_to_try = tail_addr_list(addrs_to_try))
++   {
++      size_t addrlen;
++      memset((char *)&addr, 0, sizeof addr);
++      cpy_head_addr_list(addrs_to_try, &addr,&addrlen);
++      fd = connect_to_one_ip(&addr, addrlen, host, portnum, csp);
++      if (fd != JB_INVALID_SOCKET)
++         break;
++   }
++
++   if (fd == JB_INVALID_SOCKET)
++   {
++      csp->http->host_ip_addr_str = strdup("unknown");
++   }
++
++   destroy_addr_list(addrs);
++   return fd;
+ }
+@@ -544,55 +602,30 @@
+ /*********************************************************************
+  *
+- * Function    :  bind_port
++ * Function    :  bind_port_one_ip
+  *
+  * Description :  Call socket, set socket options, and listen.
+- *                Called by listen_loop to "boot up" our proxy address.
+  *
+  * Parameters  :
+- *          1  :  hostnam = TCP/IP address to bind/listen to
+- *          2  :  portnum = port to listen on
+- *          3  :  pfd = pointer used to return file descriptor.
++ *          0  :  addr = TCP/IP address and port to bind/listen to
++ *          1  :  fds = jb_socket_set where the new socket should go
+  *
+- * Returns     :  if success, returns 0 and sets *pfd.
++ * Returns     :  if success returns 0 and adds sockets to fds.
+  *                if failure, returns -3 if address is in use,
+- *                                    -2 if address unresolvable,
++ *                                    -2 if memory error
+  *                                    -1 otherwise
+  *********************************************************************/
+-int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
++int bind_port_one_ip(struct sockaddr *addr, const socklen_t addr_len, jb_socket_set *fds)
+ {
+-   struct sockaddr_in inaddr;
+    jb_socket fd;
++   int flags;
+ #ifndef _WIN32
+    int one = 1;
+ #endif /* ndef _WIN32 */
+-   *pfd = JB_INVALID_SOCKET;
+-
+-   memset((char *)&inaddr, '\0', sizeof inaddr);
+-
+-   inaddr.sin_family      = AF_INET;
+-   inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
+-
+-   if (inaddr.sin_addr.s_addr == INADDR_NONE)
+-   {
+-      return(-2);
+-   }
+-
+-#ifndef _WIN32
+-   if (sizeof(inaddr.sin_port) == sizeof(short))
+-#endif /* ndef _WIN32 */
+-   {
+-      inaddr.sin_port = htons((unsigned short) portnum);
+-   }
+-#ifndef _WIN32
+-   else
+-   {
+-      inaddr.sin_port = htonl((unsigned long) portnum);
+-   }
+-#endif /* ndef _WIN32 */
++   fd = JB_INVALID_SOCKET;
+-   fd = socket(AF_INET, SOCK_STREAM, 0);
++   fd = socket(addr->sa_family, SOCK_STREAM, 6);
+ #ifdef _WIN32
+    if (fd == JB_INVALID_SOCKET)
+@@ -618,8 +651,17 @@
+     */
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
+ #endif /* ndef _WIN32 */
+-
+-   if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
++   /* As we are now listening on more than one socket,
++    * this is important: The only way to be sure accept
++    * won't block!!
++    */
++   if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
++   {
++      flags |= O_NONBLOCK;
++      fcntl(fd, F_SETFL, flags);
++   }
++   
++   if (bind (fd, addr, addr_len) < 0)
+    {
+ #ifdef _WIN32
+       errno = WSAGetLastError();
+@@ -638,7 +680,7 @@
+       }
+    }
+-   while (listen(fd, 5) == -1)
++   while (listen(fd, 25) == -1)
+    {
+       if (errno != EINTR)
+       {
+@@ -646,7 +688,11 @@
+       }
+    }
+-   *pfd = fd;
++   if (jb_socket_set_add(fds,fd) != 0)
++   {
++      close_socket(fd);
++      return -2;
++   }
+    return 0;
+ }
+@@ -654,6 +700,91 @@
+ /*********************************************************************
+  *
++ * Function    :  bind_port
++ *
++ * Description :  Call bind_port_one_ip on all addresses host resolves to
++ *                Called by listen_loop to "boot up" our proxy address.
++ *
++ * Parameters  :
++ *          0  :  host = TCP/IP hostname to bind/listen to
++ *          1  :  port = port to listen to, as string
++ *          2  :  fds = socket set the sockets should be added to
++ *
++ * Returns     :  if success on at least one address resolving from hostnam,
++ *                 returns 0 and adds sockets to fds.
++ *                if failure, returns non-zero
++ *********************************************************************/
++int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds)
++{
++   int result;
++   int failure = 1;
++   struct sockaddr_storage addr;
++   struct sockaddr * const addr_addr = (struct sockaddr *)&addr;
++   addr_list *addrs, *addrs_to_try;
++
++   const char * const log_host = (host != NULL) ? host : "ADDR_ANY";
++
++   addrs = resolve_hostname_to_ip(host,port,pf);
++
++   if (is_nil_addr_list(addrs))
++      log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: " 
++                "Name resolution didn't give any address",
++                log_host, port);
++
++   log_error(LOG_LEVEL_INFO, "Binding to %s:%s...",  log_host, port);
++
++   for(addrs_to_try=addrs;
++       !is_nil_addr_list(addrs_to_try);
++       addrs_to_try = tail_addr_list(addrs_to_try))
++   {
++      char numeric_hostname[NI_MAXHOST];
++      char numeric_port[NI_MAXSERV];
++      size_t addrlen;
++      memset((char *)addr_addr, 0, sizeof addr);
++      cpy_head_addr_list(addrs_to_try, &addr, &addrlen);
++      result = getnameinfo(addr_addr, addrlen, numeric_hostname, NI_MAXHOST,
++                           numeric_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
++      if (result != 0)
++      {
++         log_error(LOG_LEVEL_ERROR, "bind: Could not get string address and port back from sockaddr because %E");
++         strncpy(numeric_hostname,"unknown",NI_MAXHOST);
++         strncpy(numeric_port,"unknown",NI_MAXSERV);
++      }
++      result = bind_port_one_ip(addr_addr, addrlen, fds);
++      if( result == 0 )
++      {
++         failure = 0;
++         log_error(LOG_LEVEL_INFO, "Successfully bound to %s:%s", numeric_hostname, numeric_port);
++      }
++      else
++      {
++         switch(result)
++         {
++         case -3 :
++            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
++                      "There may be another Privoxy or some other "
++                      "proxy running on port %s",
++                      log_host, port, numeric_hostname, numeric_port, numeric_port);
++                              break;
++         case -2 :
++            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
++                      "Out of memory",
++                      log_host, port, numeric_hostname, numeric_port);
++                              break;
++         default :
++            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
++                      log_host, numeric_port);
++         }
++      }
++   }
++
++   destroy_addr_list(addrs);
++   return failure;
++}
++
++
++/*********************************************************************
++ *
+  * Function    :  accept_connection
+  *
+  * Description :  Accepts a connection on a socket.  Socket must have
+@@ -670,8 +801,7 @@
+  *********************************************************************/
+ int accept_connection(struct client_state * csp, jb_socket fd)
+ {
+-   struct sockaddr_in client, server;
+-   struct hostent *host = NULL;
++   struct sockaddr_storage client, server;
+    jb_socket afd;
+ #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
+    /* Wierdness - fix a warning. */
+@@ -679,15 +809,7 @@
+ #else
+    socklen_t c_length, s_length;
+ #endif
+-#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) ||  defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
+-   struct hostent result;
+-#if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
+-   struct hostent_data hdata;
+-#else
+-   char hbuf[HOSTENT_BUFFER_SIZE];
+-   int thd_err;
+-#endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
+-#endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
++   int flags;
+    c_length = s_length = sizeof(client);
+@@ -707,6 +829,12 @@
+       return 0;
+    }
+ #endif
++   /* If we inherited O_NONBLOCK from the listening fd, unset it */
++   if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
++   {
++      flags &= ~O_NONBLOCK;
++      fcntl(fd, F_SETFL, flags);
++   }
+    /* 
+     * Determine the IP-Adress that the client used to reach us
+@@ -714,49 +842,50 @@
+     */
+    if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
+    {
+-      csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
+-#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
+-      gethostbyaddr_r((const char *)&server.sin_addr,
+-                      sizeof(server.sin_addr), AF_INET,
+-                      &result, hbuf, HOSTENT_BUFFER_SIZE,
+-                      &host, &thd_err);
+-#elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
+-      host = gethostbyaddr_r((const char *)&server.sin_addr,
+-                      sizeof(server.sin_addr), AF_INET,
+-                      &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
+-#elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
+-      if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
+-                               sizeof(server.sin_addr), AF_INET,
+-                               &result, &hdata))
++      char hostname[NI_MAXHOST];
++      char port[NI_MAXSERV];
++
++      if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST,
++                      port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+       {
+-         host = &result;
++         log_error(LOG_LEVEL_ERROR, "accept: Could not get string address and port back from server sockaddr because %E");
++         strncpy(hostname,"unknown IP",NI_MAXHOST);
++         strncpy(port,"unknown port",NI_MAXSERV);
+       }
+-      else
++      csp->my_ip_addr_str = strdup(hostname);
++      csp->my_port_str = strdup(port);
++
++      if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD) != 0)
+       {
+-         host = NULL;
++         log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
++         strncpy(hostname,"unknown host",NI_MAXHOST);
+       }
+-#elif defined(OSX_DARWIN)
+-      pthread_mutex_lock(&gethostbyaddr_mutex);
+-      host = gethostbyaddr((const char *)&server.sin_addr, 
+-                           sizeof(server.sin_addr), AF_INET);
+-      pthread_mutex_unlock(&gethostbyaddr_mutex);
+-#else
+-      host = gethostbyaddr((const char *)&server.sin_addr, 
+-                           sizeof(server.sin_addr), AF_INET);
+-#endif
+-      if (host == NULL)
++      csp->my_hostname = strdup(hostname);
++   }
++   else
++   {
++      log_error(LOG_LEVEL_ERROR, "accept: Could not get sockaddr from socket fd because %E");
++   }
++
++   csp->cfd    = afd;
++   {
++      char hostname[NI_MAXHOST];
++
++      if (getnameinfo((struct sockaddr *)&client, c_length, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
+       {
+-         log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
++         log_error(LOG_LEVEL_ERROR, "accept: Could not get client IP address string because %E");
++         strncpy(hostname,"unknown IP",NI_MAXHOST);
+       }
+-      else
++      csp->my_ip_addr_str = strdup(hostname);
++
++      if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, 0) != 0)
+       {
+-         csp->my_hostname = strdup(host->h_name);
++         log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
++         strncpy(hostname,"unknown host",NI_MAXHOST);
+       }
++      csp->ip_addr_str = strdup(hostname);
+    }
+-
+-   csp->cfd    = afd;
+-   csp->ip_addr_str  = strdup(inet_ntoa(client.sin_addr));
+-   csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
++   csp->ip_addr_addr = client;
+    return 1;
+@@ -767,90 +896,41 @@
+  *
+  * Function    :  resolve_hostname_to_ip
+  *
+- * Description :  Resolve a hostname to an internet tcp/ip address.
+- *                NULL or an empty string resolve to INADDR_ANY.
++ * Description :  Resolve a hostname to a list of internet tcp/ip addresses.
+  *
+  * Parameters  :
+- *          1  :  host = hostname to resolve
++ *          0  :  host = hostname to resolve
++ *          1  :  result = where to store the result
++ *          2  :  pf = preferred address family. PF_UNSPEC for no preference (recommended).
+  *
+- * Returns     :  INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful.
++ * Returns     :  A (possibly empty) list of adresses
+  *
+  *********************************************************************/
+-unsigned long resolve_hostname_to_ip(const char *host)
++addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf)
+ {
+-   struct sockaddr_in inaddr;
+-   struct hostent *hostp;
+-#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
+-   struct hostent result;
+-#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
+-   char hbuf[HOSTENT_BUFFER_SIZE];
+-   int thd_err;
+-#else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
+-   struct hostent_data hdata;
+-#endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
+-#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
+-
+-   if ((host == NULL) || (*host == '\0'))
+-   {
+-      return(INADDR_ANY);
+-   }
+-
+-   memset((char *) &inaddr, 0, sizeof inaddr);
++   /* TODO 
++    * Do all supported platforms have "getaddrinfo"?
++    */
++    
++   struct addrinfo hints, *res0;
++   int result;
++   memset(&hints, 0, sizeof(hints));
++   hints.ai_family = pf;
++   hints.ai_socktype = SOCK_STREAM;
+-   if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
++   result = getaddrinfo(host, port, &hints, &res0);
++   if ( result != 0 )
+    {
+-#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
+-      gethostbyname_r(host, &result, hbuf,
+-                      HOSTENT_BUFFER_SIZE, &hostp, &thd_err);
+-#elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
+-      hostp = gethostbyname_r(host, &result, hbuf,
+-                      HOSTENT_BUFFER_SIZE, &thd_err);
+-#elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
+-      if (0 == gethostbyname_r(host, &result, &hdata))
+-      {
+-         hostp = &result;
+-      }
+-      else
+-      {
+-         hostp = NULL;
+-      }
+-#elif OSX_DARWIN
+-      pthread_mutex_lock(&gethostbyname_mutex);
+-      hostp = gethostbyname(host);
+-      pthread_mutex_unlock(&gethostbyname_mutex);
+-#else
+-      hostp = gethostbyname(host);
+-#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
+-      /*
+-       * On Mac OSX, if a domain exists but doesn't have a type A
+-       * record associated with it, the h_addr member of the struct
+-       * hostent returned by gethostbyname is NULL, even if h_length
+-       * is 4. Therefore the second test below.
+-       */
+-      if (hostp == NULL || hostp->h_addr == NULL)
+-      {
+-         errno = EINVAL;
+-         log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
+-         return(INADDR_NONE);
+-      }
+-      if (hostp->h_addrtype != AF_INET)
+-      {
+-#ifdef _WIN32
+-         errno = WSAEPROTOTYPE;
+-#else
+-         errno = EPROTOTYPE;
+-#endif 
+-         log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
+-         return(INADDR_NONE);
+-      }
+-      memcpy(
+-         (char *) &inaddr.sin_addr,
+-         (char *) hostp->h_addr,
+-         sizeof(inaddr.sin_addr)
+-      );
++      log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s because %s", host,gai_strerror(result));
++      if (result == EAI_SYSTEM)
++         log_error(LOG_LEVEL_ERROR, "The system error is %E");
++      return NULL;
+    }
+-   return(inaddr.sin_addr.s_addr);
++   else
++      if (res0==0)
++         log_error(LOG_LEVEL_ERROR, "Problem in resolving hostname %s: succeeded, but no information returned", host);
++   return res0;
+ }
+diff -urNad privoxy~/jbsockets.h privoxy/jbsockets.h
+--- privoxy~/jbsockets.h
++++ privoxy/jbsockets.h
+@@ -13,6 +13,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 8 December 2002, 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and 
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -100,9 +103,11 @@
+ extern "C" {
+ #endif
++#include "addrlist.h"
++
+ struct client_state;
+-extern jb_socket connect_to(const char *host, int portnum, struct client_state *csp);
++extern jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp);
+ #ifdef AMIGA
+ extern int write_socket(jb_socket fd, const char *buf, ssize_t n);
+ #else
+@@ -111,10 +116,10 @@
+ extern int read_socket(jb_socket fd, char *buf, int n);
+ extern void close_socket(jb_socket fd);
+-extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd);
++extern int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds);
+ extern int accept_connection(struct client_state * csp, jb_socket fd);
+-extern unsigned long resolve_hostname_to_ip(const char *host);
++extern addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf);
+ /* Revision control strings from this header and associated .c file */
+ extern const char jbsockets_rcs[];
+diff -urNad privoxy~/jcc.c privoxy/jcc.c
+--- privoxy~/jcc.c
++++ privoxy/jcc.c
+@@ -676,6 +676,7 @@
+ #include "cgi.h"
+ #include "loadcfg.h"
+ #include "urlmatch.h"
++#include "jb_socket_set.h"
+ const char jcc_h_rcs[] = JCC_H_VERSION;
+ const char project_h_rcs[] = PROJECT_H_VERSION;
+@@ -2112,61 +2113,78 @@
+  * Returns     :  Port that was opened.
+  *
+  *********************************************************************/
+-static jb_socket bind_port_helper(struct configuration_spec * config)
++static void bind_port_helper(struct configuration_spec * config, jb_socket_set *bfds)
+ {
+    int result;
+-   jb_socket bfd;
++   struct bind_spec *bs;
++   unsigned int bs_index;
++   int never_bound;
+-   if ( (config->haddr != NULL)
+-     && (config->haddr[0] == '1')
+-     && (config->haddr[1] == '2')
+-     && (config->haddr[2] == '7')
+-     && (config->haddr[3] == '.') )
+-   {
+-      log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only",
+-                config->hport);
+-   }
+-   else if (config->haddr == NULL)
+-   {
+-      log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
+-                config->hport);
+-   }
+-   else
++   never_bound = 1;
++   for (bs_index = 0; bs_index < config->hspecs_occupied;++bs_index)
+    {
+-      log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s",
+-                config->hport, config->haddr);
+-   }
++      bs = &config->hspecs[bs_index];
++      
++      /* This check misses about a trillion zillion different manners to describe
++         the local interface in IPv6. Who cares? */
++      if ( (bs->haddr != NULL)
++           && (((bs->haddr[0] == '1')
++                && (bs->haddr[1] == '2')
++                && (bs->haddr[2] == '7')
++                && (bs->haddr[3] == '.'))
++               || ((bs->haddr[0] == ':')
++                   && (bs->haddr[1] == ':')
++                   && (bs->haddr[2] == '1'))))
++      {
++         log_error(LOG_LEVEL_INFO, "Listening on port %s for local connections only",
++                   bs->hport);
++      }
++      else if (bs->haddr == NULL || bs->haddr[0]=='\0')
++      {
++         log_error(LOG_LEVEL_INFO, "Listening on port %s on all IP addresses",
++                   bs->hport);
++      }
++      else
++      {
++         log_error(LOG_LEVEL_INFO, "Listening on port %s on IP address %s",
++                   bs->hport, bs->haddr);
++      }
+-   result = bind_port(config->haddr, config->hport, &bfd);
++      result = bind_port(bs->haddr, bs->hport, bs->pf, bfds);
+-   if (result < 0)
+-   {
+-      switch(result)
++      if (result != 0)
+       {
++         switch(result)
++         {
+          case -3 :
+-            log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
++            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
+                "There may be another Privoxy or some other "
+-               "proxy running on port %d",
+-               (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
+-                      config->hport, config->hport);
++               "proxy running on port %s",
++               (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY",
++                      bs->hport, bs->hport);
++                              break;
+          case -2 :
+-            log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: " 
++            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: " 
+                "The hostname is not resolvable",
+-               (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
++               (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
++                              break;
+          default :
+-            log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E",
+-               (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
++            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
++               (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
++         }
+       }
++      else
++         never_bound = 0;
++   }
++   if(never_bound)
++   {
++      log_error(LOG_LEVEL_FATAL, "Couldn't bind at all - bailing out");
+       /* shouldn't get here */
+-      return JB_INVALID_SOCKET;
+    }
+-
+    config->need_bind = 0;
+-
+-   return bfd;
+ }
+@@ -2184,12 +2202,18 @@
+ static void listen_loop(void)
+ {
+    struct client_state *csp = NULL;
+-   jb_socket bfd;
++   jb_socket_set bfds;
++   fd_set bfds_fs;
++   jb_socket_set_iterate_state bfds_iterate_state;
++   jb_socket bfd_current;
+    struct configuration_spec * config;
++   init_jb_socket_set(&bfds);
++
+    config = load_config();
+-   bfd = bind_port_helper(config);
++   bind_port_helper(config,&bfds);
++   bfd_current=JB_INVALID_SOCKET;
+ #ifdef FEATURE_GRACEFUL_TERMINATION
+    while (!g_terminate)
+@@ -2263,14 +2287,55 @@
+           * that this will hurt people's feelings.
+           */
+-         close_socket(bfd);
++         jb_socket_set_iterate_state s;
++         jb_socket bfd;
++         s=jb_socket_set_iteration_begin(&bfds);
++         for(bfd=jb_socket_set_iteration_next(&s);bfd!=JB_INVALID_SOCKET;bfd=jb_socket_set_iteration_next(&s))
++         {
++            close_socket(bfd);
++         }
++         destroy_jb_socket_set(&bfds);
++         bind_port_helper(config,&bfds);
++         /* We have a new set of fd's to accept. Restart iteration over bfds. */
++         bfd_current = JB_INVALID_SOCKET;
++      }
+-         bfd = bind_port_helper(config);
++      /* Here: select call on listening sockets: bfd=sockets */
++      if (bfd_current == JB_INVALID_SOCKET)
++      {
++         jb_socket max;
++         log_error(LOG_LEVEL_CONNECT, "select connections ... ");
++         bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
++         FD_ZERO(&bfds_fs);
++         max = 0;
++         for(bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
++             bfd_current!=JB_INVALID_SOCKET;
++             bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state))
++         {
++            FD_SET(bfd_current,&bfds_fs);
++            if (bfd_current >= max)
++               max = bfd_current + 1;
++         }
++         if(!select(max,&bfds_fs,NULL,NULL,NULL))
++         {
++            log_error(LOG_LEVEL_CONNECT, "select failed: %E");
++            bfd_current=JB_INVALID_SOCKET;
++            continue;
++         }
++         log_error(LOG_LEVEL_CONNECT, "OK");
++         bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
++         bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
++      }
++      if (!FD_ISSET(bfd_current,&bfds_fs))
++      {
++         bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
++         freez(csp);
++         continue;
+       }
+       log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
+-      if (!accept_connection(csp, bfd))
++      if (!accept_connection(csp, bfd_current))
+       {
+          log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
+@@ -2288,6 +2353,8 @@
+          log_error(LOG_LEVEL_CONNECT, "OK");
+       }
++      bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
++
+ #ifdef FEATURE_TOGGLE
+       if (global_toggle_state)
+       {
+diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
+--- privoxy~/loadcfg.c
++++ privoxy/loadcfg.c
+@@ -11,6 +11,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 8 December 2002, 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -372,6 +375,7 @@
+ #include "encode.h"
+ #include "urlmatch.h"
+ #include "cgi.h"
++#include "parsers.h"
+ const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
+@@ -489,8 +493,8 @@
+       struct forward_spec * next_fwd = cur_fwd->next;
+       free_url_spec(cur_fwd->url);
+-      freez(cur_fwd->gateway_host);
+-      freez(cur_fwd->forward_host);
++      freez(cur_fwd->gateway_malloc);
++      freez(cur_fwd->forward_malloc);
+       free(cur_fwd);
+       cur_fwd = next_fwd;
+    }
+@@ -507,7 +511,16 @@
+    freez(config->confdir);
+    freez(config->logdir);
+-   freez(config->haddr);
++   if(config -> hspecs != NULL)
++   {
++      int i;
++      for (i=0; i < config->hspecs_occupied; ++i)
++      {
++         freez(config->hspecs[i].haddr);
++         freez(config->hspecs[i].hport);
++      }
++   }
++   freez(config->hspecs);
+    freez(config->logfile);
+    for (i = 0; i < MAX_ACTION_FILES; i++)
+@@ -570,6 +583,28 @@
+  * Returns     :  The configuration_spec, or NULL on error.
+  *
+  *********************************************************************/
++static void fail_load_config_memory(struct file_list *fs, struct configuration_spec *config)
++{
++   freez(fs->filename);
++   freez(fs);
++   if (config != NULL)
++   {
++      if(config -> hspecs != NULL)
++      {
++         int i;
++         for (i=0; i < config->hspecs_occupied; ++i)
++         {
++            freez(config->hspecs[i].haddr);
++            freez(config->hspecs[i].hport);
++         }
++      }
++      freez(config -> hspecs);
++   }
++   freez(config);
++   log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
++   /* Never get here - LOG_LEVEL_FATAL causes program exit */
++}
++
+ struct configuration_spec * load_config(void)
+ {
+    char buf[BUFFER_SIZE];
+@@ -601,12 +636,7 @@
+    fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
+    if (config==NULL)
+-   {
+-      freez(fs->filename);
+-      freez(fs);
+-      log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
+-      /* Never get here - LOG_LEVEL_FATAL causes program exit */
+-   }
++      fail_load_config_memory(fs,config);
+    /*
+     * This is backwards from how it's usually done.
+@@ -623,7 +653,7 @@
+     * Set to defaults
+     */
+    config->multi_threaded    = 1;
+-   config->hport             = HADDR_PORT;
++   config->hspecs            = NULL;
+    config->buffer_limit      = 4096 * 1024;
+    config->usermanual        = strdup(USER_MANUAL_URL);
+    config->proxy_args        = strdup("");
+@@ -640,9 +670,6 @@
+       char cmd[BUFFER_SIZE];
+       char arg[BUFFER_SIZE];
+       char tmp[BUFFER_SIZE];
+-#ifdef FEATURE_ACL
+-      struct access_control_list *cur_acl;
+-#endif /* def FEATURE_ACL */
+       struct forward_spec *cur_fwd;
+       int vec_count;
+       char *vec[3];
+@@ -753,74 +780,23 @@
+  * *************************************************************************/
+ #ifdef FEATURE_ACL
+          case hash_deny_access:
+-            vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
+-
+-            if ((vec_count != 1) && (vec_count != 2))
+-            {
+-               log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
+-                     "deny-access directive in configuration file.");
+-               string_append(&config->proxy_args,
+-                  "<br>\nWARNING: Wrong number of parameters for "
+-                  "deny-access directive in configuration file.<br><br>\n");
+-               continue;
+-            }
+-
+-            /* allocate a new node */
+-            cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
+-
+-            if (cur_acl == NULL)
+-            {
+-               log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
+-               /* Never get here - LOG_LEVEL_FATAL causes program exit */
+-               continue;
+-            }
+-            cur_acl->action = ACL_DENY;
+-
+-            if (acl_addr(vec[0], cur_acl->src) < 0)
+-            {
+-               log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access "
+-                     "directive in configuration file: \"%s\"", vec[0]);
+-               string_append(&config->proxy_args,
+-                  "<br>\nWARNING: Invalid source IP for deny-access directive"
+-                  " in configuration file: \"");
+-               string_append(&config->proxy_args,
+-                  vec[0]);
+-               string_append(&config->proxy_args,
+-                  "\"<br><br>\n");
+-               freez(cur_acl);
+-               continue;
+-            }
+-            if (vec_count == 2)
++            switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
+             {
+-               if (acl_addr(vec[1], cur_acl->dst) < 0)
+-               {
+-                  log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access "
+-                        "directive in configuration file: \"%s\"", vec[0]);
+-                  string_append(&config->proxy_args,
+-                     "<br>\nWARNING: Invalid destination IP for deny-access directive"
+-                     " in configuration file: \"");
+-                  string_append(&config->proxy_args,
+-                     vec[0]);
++               case 1:
++                  config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], NULL, &config->proxy_args);
++                                              break;
++               case 2:
++                  config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], vec[1], &config->proxy_args);
++                                              break;
++               default:
++                  log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
++                            "deny-access directive in configuration file.");
+                   string_append(&config->proxy_args,
+-                     "\"<br><br>\n");
+-                  freez(cur_acl);
+-                  continue;
+-               }
++                                "<br>\nWARNING: Wrong number of parameters for "
++                                "deny-access directive in configuration file.<br><br>\n");
+             }
+-
+-            /*
+-             * Add it to the list.  Note we reverse the list to get the
+-             * behaviour the user expects.  With both the ACL and
+-             * actions file, the last match wins.  However, the internal
+-             * implementations are different:  The actions file is stored
+-             * in the same order as the file, and scanned completely.
+-             * With the ACL, we reverse the order as we load it, then
+-             * when we scan it we stop as soon as we get a match.
+-             */
+-            cur_acl->next  = config->acl;
+-            config->acl = cur_acl;
+-
+             continue;
++
+ #endif /* def FEATURE_ACL */
+ /* *************************************************************************
+@@ -914,16 +890,18 @@
+             if (strcmp(p, ".") != 0)
+             {
+-               cur_fwd->forward_host = strdup(p);
++               cur_fwd->forward_malloc = strdup(p);
++               cur_fwd->forward_family = -1;
+-               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
+-               {
+-                  *p++ = '\0';
+-                  cur_fwd->forward_port = atoi(p);
+-               }
++               parse_pf_ip(cur_fwd->forward_malloc,
++                           &cur_fwd->forward_host,
++                           &cur_fwd->forward_port_str,
++                           &cur_fwd->forward_family);
++               cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
+                if (cur_fwd->forward_port <= 0)
+                {
++                  cur_fwd->forward_port_str = "8000";
+                   cur_fwd->forward_port = 8000;
+                }
+             }
+@@ -977,15 +955,27 @@
+             if (strcmp(p, ".") != 0)
+             {
+-               cur_fwd->gateway_host = strdup(p);
++               /* SOCKS is IPv4-specific */
++               int pf = PF_INET;
+-               if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
++               cur_fwd->gateway_malloc = strdup(p);
++               if (parse_pf_ip(cur_fwd->gateway_malloc,
++                               &cur_fwd->gateway_host,
++                               &cur_fwd->gateway_port_str,
++                               &pf) != 0)
+                {
+-                  *p++ = '\0';
+-                  cur_fwd->gateway_port = atoi(p);
++                 log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4 host: %s",p);
++                 cur_fwd->gateway_host = NULL;
++                 cur_fwd->gateway_port_str = NULL;
++                 freez(cur_fwd->gateway_malloc);
++                 continue;
+                }
++
++               cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
++
+                if (cur_fwd->gateway_port <= 0)
+                {
++                  cur_fwd->gateway_port_str = "1080";
+                   cur_fwd->gateway_port = 1080;
+                }
+             }
+@@ -995,16 +985,26 @@
+             if (strcmp(p, ".") != 0)
+             {
+-               cur_fwd->forward_host = strdup(p);
++               cur_fwd->forward_malloc = strdup(p);
++               cur_fwd->forward_family = -1;
+-               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
++               parse_pf_ip(cur_fwd->forward_malloc,
++                           &cur_fwd->forward_host,
++                           &cur_fwd->forward_port_str,
++                           &cur_fwd->forward_family);
++               cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
++
++               if (cur_fwd->forward_port <= 0)
+                {
+-                  *p++ = '\0';
+-                  cur_fwd->forward_port = atoi(p);
++                  cur_fwd->forward_port_str = "8000";
++                  cur_fwd->forward_port = 8000;
+                }
++               cur_fwd->forward_port = atoi(p);
++
+                if (cur_fwd->forward_port <= 0)
+                {
++                  cur_fwd->forward_port_str = "8000";
+                   cur_fwd->forward_port = 8000;
+                }
+             }
+@@ -1056,16 +1056,30 @@
+             /* Parse the SOCKS proxy host[:port] */
+             p = vec[1];
+-            cur_fwd->gateway_host = strdup(p);
+-
+-            if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
+-            {
+-               *p++ = '\0';
+-               cur_fwd->gateway_port = atoi(p);
+-            }
+-            if (cur_fwd->gateway_port <= 0)
+             {
+-               cur_fwd->gateway_port = 1080;
++               /* SOCKS is IPv4-specific */
++               int pf = PF_INET;
++
++               cur_fwd->gateway_malloc = strdup(p);
++               if (parse_pf_ip(cur_fwd->gateway_malloc,
++                               &cur_fwd->gateway_host,
++                               &cur_fwd->gateway_port_str,
++                               &pf) != 0)
++               {
++                 log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4a host: %s",p);
++                 cur_fwd->gateway_host = NULL;
++                 cur_fwd->gateway_port_str = NULL;
++                 freez(cur_fwd->gateway_malloc);
++                 continue;
++               }
++
++               cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
++
++               if (cur_fwd->gateway_port <= 0)
++               {
++                  cur_fwd->gateway_port_str = "1080";
++                  cur_fwd->gateway_port = 1080;
++               }
+             }
+             /* Parse the parent HTTP proxy host[:port] */
+@@ -1073,16 +1087,26 @@
+             if (strcmp(p, ".") != 0)
+             {
+-               cur_fwd->forward_host = strdup(p);
++               cur_fwd->forward_malloc = strdup(p);
++               cur_fwd->forward_family = -1;
+-               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
++               parse_pf_ip(cur_fwd->forward_malloc,
++                           &cur_fwd->forward_host,
++                           &cur_fwd->forward_port_str,
++                           &cur_fwd->forward_family);
++               cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
++
++               if (cur_fwd->forward_port <= 0)
+                {
+-                  *p++ = '\0';
+-                  cur_fwd->forward_port = atoi(p);
++                  cur_fwd->forward_port_str = "8000";
++                  cur_fwd->forward_port = 8000;
+                }
++               cur_fwd->forward_port = atoi(p);
++
+                if (cur_fwd->forward_port <= 0)
+                {
++                  cur_fwd->forward_port_str = "8000";
+                   cur_fwd->forward_port = 8000;
+                }
+             }
+@@ -1108,10 +1132,49 @@
+  * listen-address [ip][:port]
+  * *************************************************************************/
+          case hash_listen_address :
+-            freez(config->haddr);
+-            config->haddr = strdup(arg);
++         {
++            struct bind_spec *bs;
++            char *arg_cpy;
++            if (config->hspecs == NULL)
++            {
++               /* This is the first we'll bind to */
++               config->hspecs = calloc(2,sizeof(struct bind_spec));
++               if (config->hspecs == NULL)
++                  fail_load_config_memory(fs,config);
++               config->hspecs_size = 2;
++               config->hspecs_occupied = 0;
++            }
++            
++            arg_cpy = strdup(arg);
++            if (arg_cpy == NULL)
++               fail_load_config_memory(fs,config);
++            if (config->hspecs_occupied == config->hspecs_size)
++              {
++                struct bind_spec *new_hspecs;
++                config->hspecs_size *= 2;
++                new_hspecs = realloc(config->hspecs,config->hspecs_size * sizeof(struct bind_spec));
++                if (new_hspecs == NULL)
++                  {
++                    /* Not enough memory to continue. Cancel changes. */
++                    config->hspecs_size /= 2;
++                    fail_load_config_memory(fs,config);
++                  }
++                config->hspecs = new_hspecs;
++              }
++            bs = &config->hspecs[(config->hspecs_occupied)++];
++            bs->pf = -1;
++            parse_pf_ip(arg,&bs->haddr,&bs->hport,&bs->pf);
++            if (*bs->haddr == '\0')
++            {
++               bs->haddr = NULL;
++            }
++            else
++            {
++               (bs->haddr = strdup(bs->haddr));
++            }
++            bs->hport = strdup(bs->hport);
+             continue;
+-
++         }
+ /* *************************************************************************
+  * logdir directory-name
+  * *************************************************************************/
+@@ -1134,75 +1197,21 @@
+  * *************************************************************************/
+ #ifdef FEATURE_ACL
+          case hash_permit_access:
+-            vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
+-
+-            if ((vec_count != 1) && (vec_count != 2))
+-            {
+-               log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
+-                     "permit-access directive in configuration file.");
+-               string_append(&config->proxy_args,
+-                  "<br>\nWARNING: Wrong number of parameters for "
+-                  "permit-access directive in configuration file.<br><br>\n");
+-
+-               continue;
+-            }
+-
+-            /* allocate a new node */
+-            cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
+-
+-            if (cur_acl == NULL)
+-            {
+-               log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
+-               /* Never get here - LOG_LEVEL_FATAL causes program exit */
+-               continue;
+-            }
+-            cur_acl->action = ACL_PERMIT;
+-
+-            if (acl_addr(vec[0], cur_acl->src) < 0)
+-            {
+-               log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access "
+-                     "directive in configuration file: \"%s\"", vec[0]);
+-               string_append(&config->proxy_args,
+-                  "<br>\nWARNING: Invalid source IP for permit-access directive"
+-                  " in configuration file: \"");
+-               string_append(&config->proxy_args,
+-                  vec[0]);
+-               string_append(&config->proxy_args,
+-                  "\"<br><br>\n");
+-               freez(cur_acl);
+-               continue;
+-            }
+-            if (vec_count == 2)
++            switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
+             {
+-               if (acl_addr(vec[1], cur_acl->dst) < 0)
+-               {
+-                  log_error(LOG_LEVEL_ERROR, "Invalid destination IP for "
+-                        "permit-access directive in configuration file: \"%s\"",
+-                        vec[0]);
+-                  string_append(&config->proxy_args,
+-                     "<br>\nWARNING: Invalid destination IP for permit-access directive"
+-                     " in configuration file: \"");
+-                  string_append(&config->proxy_args,
+-                     vec[0]);
++               case 1:
++                  config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], NULL, &config->proxy_args);
++                                              break;
++               case 2:
++                  config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], vec[1], &config->proxy_args);
++                                              break;
++               default:
++                  log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
++                            "permit-access directive in configuration file.");
+                   string_append(&config->proxy_args,
+-                     "\"<br><br>\n");
+-                  freez(cur_acl);
+-                  continue;
+-               }
++                                "<br>\nWARNING: Wrong number of parameters for "
++                                "permit-access directive in configuration file.<br><br>\n");
+             }
+-
+-            /*
+-             * Add it to the list.  Note we reverse the list to get the
+-             * behaviour the user expects.  With both the ACL and
+-             * actions file, the last match wins.  However, the internal
+-             * implementations are different:  The actions file is stored
+-             * in the same order as the file, and scanned completely.
+-             * With the ACL, we reverse the order as we load it, then
+-             * when we scan it we stop as soon as we get a match.
+-             */
+-            cur_acl->next  = config->acl;
+-            config->acl = cur_acl;
+-
+             continue;
+ #endif /* def FEATURE_ACL */
+@@ -1442,32 +1451,33 @@
+    }
+ #endif /* def FEATURE_COOKIE_JAR */
+-   if ( NULL == config->haddr )
+-   {
+-      config->haddr = strdup( HADDR_DEFAULT );
+-   }
+-
+-   if ( NULL != config->haddr )
++   if ( config->hspecs == NULL )
+    {
+-      if (NULL != (p = strchr(config->haddr, ':')))
+-      {
+-         *p++ = '\0';
+-         if (*p)
+-         {
+-            config->hport = atoi(p);
+-         }
+-      }
+-
+-      if (config->hport <= 0)
+-      {
+-         *--p = ':';
+-         log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
+-         /* Never get here - LOG_LEVEL_FATAL causes program exit */
+-      }
+-      if (*config->haddr == '\0')
+-      {
+-         config->haddr = NULL;
+-      }
++      /* No listen-address set. The default is localhost on port 8118, on IPv4
++         and (if INET6 is defined) IPv6.
++       */
++      struct bind_spec *bs;
++#ifdef INET6
++      config->hspecs = calloc(2,sizeof(struct bind_spec));
++      if (config->hspecs == NULL)
++         fail_load_config_memory(fs,config);
++      config->hspecs_size=2;
++      config->hspecs_occupied=1;
++      bs = &config->hspecs[0];
++      bs->haddr = strdup("::1");
++      bs->hport = strdup("8118");
++      bs->pf = PF_UNSPEC;
++#else
++      config->hspecs = calloc(1,sizeof(struct bind_spec));
++      if (config->hspecs == NULL)
++         fail_load_config_memory(fs,config);
++      config->hspecs_size=1;
++      config->hspecs_occupied=0;
++#endif
++      bs = &config->hspecs[config->hspecs_occupied++];
++      bs->haddr = strdup("127.0.0.1");
++      bs->hport = strdup("8118");
++      bs->pf = PF_UNSPEC;
+    }
+    /*
+@@ -1509,31 +1519,29 @@
+       struct configuration_spec * oldcfg = (struct configuration_spec *)
+                                            current_configfile->f;
+       /*
+-       * Check if config->haddr,hport == oldcfg->haddr,hport
+-       *
+-       * The following could be written more compactly as a single,
+-       * (unreadably long) if statement.
++       * Check if the listening addresses have changed
+        */
+       config->need_bind = 0;
+-      if (config->hport != oldcfg->hport)
+-      {
+-         config->need_bind = 1;
+-      }
+-      else if (config->haddr == NULL)
++      if (config -> hspecs_occupied == oldcfg -> hspecs_occupied)
+       {
+-         if (oldcfg->haddr != NULL)
++         int bs_index;
++         struct bind_spec *hspec;
++         struct bind_spec *oldhspec;
++         hspec = config -> hspecs;
++         oldhspec = oldcfg -> hspecs;
++         for(bs_index = 0; bs_index < oldcfg->hspecs_occupied; ++bs_index)
+          {
+-            config->need_bind = 1;
++           if (strcmp(hspec[bs_index].haddr,oldhspec[bs_index].haddr) != 0
++               || strcmp(hspec[bs_index].hport,oldhspec[bs_index].hport) != 0
++               || hspec[bs_index].pf != hspec[bs_index].pf)
++           {
++              config -> need_bind = 1;
++              break;
++           }
+          }
+       }
+-      else if (oldcfg->haddr == NULL)
+-      {
+-         config->need_bind = 1;
+-      }
+-      else if (0 != strcmp(config->haddr, oldcfg->haddr))
+-      {
+-         config->need_bind = 1;
+-      }
++      else
++         config-> need_bind = 1;
+       current_configfile->unloader = unload_configfile;
+    }
+diff -urNad privoxy~/loaders.c privoxy/loaders.c
+--- privoxy~/loaders.c
++++ privoxy/loaders.c
+@@ -11,6 +11,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 8 December 2002, 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -427,6 +430,7 @@
+          freez(csp->ip_addr_str);
+          freez(csp->my_ip_addr_str);
++         freez(csp->my_port_str);
+          freez(csp->my_hostname);
+          freez(csp->x_forwarded);
+          freez(csp->iob->buf);
+diff -urNad privoxy~/miscutil.h privoxy/miscutil.h
+--- privoxy~/miscutil.h
++++ privoxy/miscutil.h
+@@ -142,6 +142,15 @@
+ #include "project.h"
++/* Fix a problem with Solaris.  There should be no effect on other
++ * platforms.
++ * Solaris's isspace() is a macro which uses it's argument directly
++ * as an array index.  Therefore we need to make sure that high-bit
++ * characters generate +ve values, and ideally we also want to make
++ * the argument match the declared parameter type of "int".
++ */
++#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
++
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+diff -urNad privoxy~/parsers.c privoxy/parsers.c
+--- privoxy~/parsers.c
++++ privoxy/parsers.c
+@@ -16,6 +16,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -1953,6 +1956,167 @@
+ }
+ #endif /* def FEATURE_FORCE_LOAD */
++/*********************************************************************
++ *
++ * Function    :  parse_pf_ip_netmask
++ *
++ * Description :  Parse an IPv{4,6} litteral or hostname
++ *                with optional port and optional explicit family
++ *                and optional netmask
++ *
++ * Parameters  :
++ *          0  :  string = the string to parse
++ *          1  :  host = Is set to point to the hostname or IP literal
++ *                       part
++ *          2  :  port = Is set to point to the port part,
++ *                       or NULL if no port in string
++ *          3  :  pf = pointer used to return the address family
++ *                     pf is a value-result argument:
++ *                     If it is set to -1, then parse_pf_ip will set it
++ *                      to the address family of the pf_ip string
++ *                     else, it won't touch it, and fail if the two
++ *                      cannot match
++ *          4  :  pointer used to return the mask length
++ *                Set to -1 if no mask
++ *
++ * Returns     :  0 on success
++ *
++ *********************************************************************/
++int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength)
++{
++   int i;
++   char *p;
++
++   *masklength = -1;
++
++   if ((p = strchr(string, '/')) != NULL)
++   {
++      *p++ = '\0';
++
++      if (ijb_isdigit(*p) == 0)
++      {
++         return -1;
++      }
++      i = atoi(p);
++      if ( i < 0 )
++         return -1;
++      *masklength = i;
++   }
++
++   return parse_pf_ip(string, host, port, pf);
++}
++
++/*********************************************************************
++ *
++ * Function    :  parse_pf_ip
++ *
++ * Description :  Parse an IPv{4,6} litteral or hostname
++ *                with optional port and optional explicit family
++ *
++ * Parameters  :
++ *          0  :  string = the string to parse
++ *          1  :  host = Is set to point to the hostname or IP literal
++ *                       part
++ *          2  :  port = Is set to point to the port part,
++ *                       or NULL if no port in string
++ *          3  :  pf = pointer used to return the address family
++ *                     pf is a value-result argument:
++ *                     If it is set to -1, then parse_pf_ip will set it
++ *                      to the address family of the pf_ip string
++ *                     else, it won't touch it, and fail if the two
++ *                      cannot match
++ *
++ * Returns     :  0 on success
++ *
++ *********************************************************************/
++int parse_pf_ip(char *string, char **host, char **port, int *pf)
++{
++   if (pf != NULL && *pf == -1)
++      *pf = PF_UNSPEC;
++
++   /* See if we want to override the default protocol family */
++   if (strncmpic(string, "ipv4:", 5) == 0)
++   {
++      string += 5;
++      if (pf!=NULL)
++      {
++         if(*pf==PF_INET || *pf==PF_UNSPEC)
++            *pf = AF_INET;
++         else
++         {
++            log_error(LOG_LEVEL_ERROR,"%s","IPv4 address found where other awaited");
++            return -2;
++         }
++      }
++   }
++   else if (strncmpic(string, "ipv6:", 5) == 0)
++   {
++#ifdef INET6
++      string += 5;
++      if(*pf==PF_INET6 || *pf==PF_UNSPEC)
++         *pf = AF_INET6;
++      else
++      {
++        log_error(LOG_LEVEL_ERROR,"%s","IPv6 address found where other awaited");
++        return -2;
++      }
++#else
++      log_error(LOG_LEVEL_ERROR,"%s","This privoxy hasn't IPv6 support");
++      return -1;
++#endif
++   }
++   return parse_ip(string, host, port);
++}
++
++/*********************************************************************
++ *
++ * Function    :  parse_ip
++ *
++ * Description :  Parse an IPv{4,6} litteral or hostname
++ *                with optional port
++ *
++ * Parameters  :
++ *          0  :  string = the string to parse
++ *          1  :  host = Is set to point to the hostname or IP literal
++ *                       part
++ *          2  :  port = Is set to point to the port part,
++ *                       or NULL if no port in string
++ * Returns     :  0 on success
++ *
++ *********************************************************************/
++int parse_ip(char *string, char **host, char **port)
++{
++   char *p;
++   int skip;
++
++   /* allow IPv6 address literal: [numbers:with:colons]:port/mask */
++   if (string[0] == '[' && (p = strchr(string, ']')))
++   {
++      *p++ = '\0';
++      skip = 1;
++   }
++   else
++   {
++      p = string;
++      skip = 0;
++   }
++
++   if (host != NULL)
++      *host = string + skip;
++
++   for(;*p != '\0'; ++p)
++   {
++      if (*p == ':')
++      {
++         *p++ = '\0';
++         break;
++      }
++   }
++   if (port != NULL)
++      *port = p;
++   return 0;
++}
++
+ /*
+   Local Variables:
+diff -urNad privoxy~/parsers.h privoxy/parsers.h
+--- privoxy~/parsers.h
++++ privoxy/parsers.h
+@@ -19,6 +19,9 @@
+  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+  *                Privoxy team. http://www.privoxy.org/
+  *
++ *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
++ *                for IPv6 support on 24 January 2003.
++ *
+  *                Based on the Internet Junkbuster originally written
+  *                by and Copyright (C) 1997 Anonymous Coders and 
+  *                Junkbusters Corporation.  http://www.junkbusters.com
+@@ -227,6 +230,10 @@
+ extern jb_err server_transfer_coding (struct client_state *csp, char **header);
+ extern jb_err server_http            (struct client_state *csp, char **header);
++extern int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength);
++extern int parse_pf_ip(char *string, char ** host, char ** port, int *pf);
++extern int parse_ip(char *string, char ** host, char** port);
++
+ #ifdef FEATURE_FORCE_LOAD
+ extern int strclean(const char *string, const char *substring);
+ #endif /* def FEATURE_FORCE_LOAD */
+diff -urNad privoxy~/project.h privoxy/project.h
+--- privoxy~/project.h
++++ privoxy/project.h
+@@ -549,6 +549,20 @@
+ #endif /* ndef _WIN32 */
++#include "jb_socket_set.h"
++
++#ifdef INET6
++/**
++ * Get from the operating system structures big enough
++ * to put a network address in, namely sockaddr_storage
++ */
++#include <sys/socket.h> 
++/**
++ * If no IPv6 support, just use the old sockaddr
++ */
++#else
++#define sockaddr_storage   sockaddr
++#endif
+ /**
+  * A standard error code.  This should be JB_ERR_OK or one of the JB_ERR_xxx
+@@ -618,19 +632,6 @@
+  */
+ #define FOREVER 1
+-/**
+- * Default IP address to listen on, as a string.
+- * Set to "127.0.0.1".
+- */
+-#define HADDR_DEFAULT   "127.0.0.1"
+-
+-/**
+- * Default port to listen on, as a number.
+- * Set to 8118.
+- */
+-#define HADDR_PORT      8118
+-
+-
+ /* Forward def for struct client_state */
+ struct configuration_spec;
+@@ -709,13 +710,16 @@
+    char *ver;      /**< Protocol version */
+    int status;     /**< HTTP Status */
++   char *host_port_malloc;     /**< malloc used for place wher host and port_str are */
+    char *host;     /**< Host part of URL */
+    int   port;     /**< Port of URL or 80 (default) */
++   char *port_str; /**< Port of URL, as string */
+    char *path;     /**< Path of URL */
+    char *hostport; /**< host[:port] */
+    int   ssl;      /**< Flag if protocol is https */
+-   char *host_ip_addr_str; /**< String with dotted decimal representation
++   char *host_ip_addr_str; /**< String with dotted decimal representation (IPv4)
++                                or hexadecimal colon-separated (IPv6)
+                                 of host's IP. NULL before connect_to() */
+    char  *dbuffer; /**< Buffer with '\0'-delimited domain name.           */
+@@ -1039,13 +1043,16 @@
+        As a string. */
+    char *ip_addr_str;
+    /** Client PC's IP address, as reported by the accept() function.
+-       As a number. */
+-   long  ip_addr_long;
++       As an address. */
++   struct sockaddr_storage ip_addr_addr;
+    /** Our IP address. I.e. the IP address that the client used to reach us,
+        as a string. */
+    char *my_ip_addr_str;
++   /** Our  port. I.e. the port the client used to reach us */
++   char *my_port_str;
++
+    /** Our hostname. I.e. the reverse DNS of the IP address that the client
+        used to reach us, as a string. */
+    char *my_hostname;
+@@ -1214,18 +1221,33 @@
+    /** Connection type.  Must be SOCKS_NONE, SOCKS_4, or SOCKS_4A. */
+    int   type;
++   /** pointer returned by the malloc used for gateway_host and gateway_port_str */
++   char *gateway_malloc;
++
+    /** SOCKS server hostname.  Only valid if "type" is SOCKS_4 or SOCKS_4A. */
+    char *gateway_host;
+    /** SOCKS server port. */
+    int   gateway_port;
++   /** SOCKS server port, as string. */
++   char *gateway_port_str;
++
++   /** pointer returned by the malloc used for forward_host and forward_port_str */
++   char *forward_malloc;
++
++   /** Parent HTTP proxy address family. */
++   int forward_family;
++
+    /** Parent HTTP proxy hostname, or NULL for none. */
+    char *forward_host;
+    /** Parent HTTP proxy port. */
+    int   forward_port;
++   /** Parent HTTP proxy port as string. */
++   char *forward_port_str;
++
+    /** Next entry in the linked list. */
+    struct forward_spec *next;
+ };
+@@ -1234,7 +1256,7 @@
+ /**
+  * Initializer for a static struct forward_spec.
+  */
+-#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL }
++#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
+ /**
+@@ -1263,7 +1285,8 @@
+  */
+ struct access_control_addr
+ {
+-   unsigned long addr;  /**< The IP address as an integer. */
++   struct sockaddr_storage addr; /**< The IP address. */
++   size_t addrlen;
+    unsigned long mask;  /**< The network mask as an integer. */
+    unsigned long port;  /**< The port number. */
+ };
+@@ -1295,6 +1318,17 @@
+ /** configuration_spec::feature_flags: Web-based toggle. */
+ #define RUNTIME_FEATURE_CGI_TOGGLE        2
++struct bind_spec
++{
++   /** IP address to bind to. */
++   char *haddr;
++
++   /** Port to bind to. */
++   char *hport;
++
++   /** Address family */
++   int pf;
++};
+ /**
+  * Data loaded from the configuration file.
+@@ -1355,11 +1389,13 @@
+ #endif /* def FEATURE_COOKIE_JAR */
+-   /** IP address to bind to.  Defaults to HADDR_DEFAULT == 127.0.0.1. */
+-   const char *haddr;
+-
+-   /** Port to bind to.  Defaults to HADDR_PORT == 8118. */
+-   int         hport;
++   /* IP addresses and ports to bind to.
++       Defaults to HSPECS_DEFAULT == {ipv4:127.0.0.1:8118, ipv6:[::1]:8118}. */
++   struct bind_spec *hspecs;
++   /* size allocated */
++   unsigned int hspecs_size;
++   /* number of entries */
++   unsigned int hspecs_occupied;
+    /** Size limit for IOB */
+    size_t buffer_limit;
+diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c
+--- privoxy~/urlmatch.c
++++ privoxy/urlmatch.c
+@@ -133,6 +133,7 @@
+ #include "ssplit.h"
+ #include "miscutil.h"
+ #include "errlog.h"
++#include "parsers.h"
+ const char urlmatch_h_rcs[] = URLMATCH_H_VERSION;
+@@ -156,7 +157,7 @@
+    freez(http->cmd);
+    freez(http->ocmd);
+    freez(http->gpc);
+-   freez(http->host);
++   freez(http->host_port_malloc);
+    freez(http->url);
+    freez(http->hostport);
+    freez(http->path);
+@@ -298,8 +299,6 @@
+     */
+    {
+       char *buf;
+-      char *host;
+-      char *port;
+       buf = strdup(http->hostport);
+       if (buf == NULL)
+@@ -307,38 +306,34 @@
+          return JB_ERR_MEMORY;
+       }
++              http->host_port_malloc = buf;
++
+       /* check if url contains username and/or password */
+-      host = strchr(buf, '@');
+-      if (host != NULL)
++      buf = strchr(buf, '@');
++      if (buf != NULL)
+       {
+          /* Contains username/password, skip it and the @ sign. */
+-         host++;
++         buf++;
+       }
+       else
+       {
+          /* No username or password. */
+-         host = buf;
++         buf = http->host_port_malloc;
+       }
+-      /* check if url contains port */
+-      port = strchr(host, ':');
+-      if (port != NULL)
++      parse_ip(buf,&http->host,&http->port_str);
++
++      if (*http->port_str != '\0')
+       {
+-         /* Contains port */
+-         /* Terminate hostname and point to start of port string */
+-         *port++ = '\0';
+-         http->port = atoi(port);
++         http->port = atoi(http->port_str);
+       }
+       else
+       {
+          /* No port specified. */
+-         http->port = (http->ssl ? 443 : 80);
++         http->port_str = (http->ssl ? "143" : "80");
++                      http->port = (http->ssl ? 443 : 80);
+       }
+-      http->host = strdup(host);
+-
+-      free(buf);
+-
+       if (http->host == NULL)
+       {
+          return JB_ERR_MEMORY;
+@@ -662,9 +657,8 @@
+  *                               written to system log)
+  *
+  *********************************************************************/
+-jb_err create_url_spec(struct url_spec * url, const char * buf)
++jb_err create_url_spec(struct url_spec * url, char * buf)
+ {
+-   char *p;
+    assert(url);
+    assert(buf);
+@@ -681,22 +675,25 @@
+    {
+       return JB_ERR_MEMORY;
+    }
+-
+-   if ((p = strchr(buf, '/')) != NULL)
+    {
+-      if (NULL == (url->path = strdup(p)))
++      char *p;
++
++      if ((p = strchr(buf, '/')) != NULL)
+       {
+-         freez(url->spec);
+-         return JB_ERR_MEMORY;
++         if (NULL == (url->path = strdup(p)))
++         {
++            freez(url->spec);
++            return JB_ERR_MEMORY;
++         }
++         url->pathlen = strlen(url->path);
++         *p = '\0';
+       }
+-      url->pathlen = strlen(url->path);
+-      *p = '\0';
+-   }
+-   else
+-   {
+-      url->path    = NULL;
+-      url->pathlen = 0;
+-   }
++      else
++      {
++         url->path    = NULL;
++         url->pathlen = 0;
++      }
++      }
+    if (url->path)
+    {
+       int errcode;
+@@ -735,15 +732,12 @@
+          return JB_ERR_PARSE;
+       }
+    }
+-   if ((p = strchr(buf, ':')) == NULL)
+-   {
+-      url->port = 0;
+-   }
+-   else
++
+    {
+-      *p++ = '\0';
+-      url->port = atoi(p);
+-   }
++     char *p;
++     parse_ip(buf,&buf,&p);
++     url->port = atoi(p);
++      }
+    if (buf[0] != '\0')
+    {
+@@ -775,12 +769,13 @@
+          return JB_ERR_MEMORY;
+       }
+-      /* 
+-       * Map to lower case
+-       */
+-      for (p = url->dbuffer; *p ; p++)
+       {
+-         *p = tolower((int)(unsigned char)*p);
++         char* p;
++         /* map to lower case */
++         for (p = url->dbuffer; *p ; p++)
++         {
++            *p = tolower((int)(unsigned char)*p);
++         }
+       }
+       /* 
+diff -urNad privoxy~/urlmatch.h privoxy/urlmatch.h
+--- privoxy~/urlmatch.h
++++ privoxy/urlmatch.h
+@@ -79,7 +79,7 @@
+ extern int url_match(const struct url_spec *pattern,
+                      const struct http_request *url);
+-extern jb_err create_url_spec(struct url_spec * url, const char * buf);
++extern jb_err create_url_spec(struct url_spec * url, char * buf);
+ extern void free_url_spec(struct url_spec *url);
index 2a451a1..5f7fd28 100644 (file)
@@ -7,9 +7,9 @@
 
 @DPATCH@
 diff -urNad privoxy~/config privoxy/config
 
 @DPATCH@
 diff -urNad privoxy~/config privoxy/config
---- privoxy~/config    2006-02-05 16:23:12.000000000 +0100
-+++ privoxy/config     2006-02-05 16:25:45.000000000 +0100
-@@ -889,11 +889,10 @@
+--- privoxy~/config
++++ privoxy/config
+@@ -931,11 +931,10 @@
  #  This feature allows routing of HTTP requests through a chain
  #  of multiple proxies. It can be used to better protect privacy
  #  and confidentiality when accessing specific domains by routing
  #  This feature allows routing of HTTP requests through a chain
  #  of multiple proxies. It can be used to better protect privacy
  #  and confidentiality when accessing specific domains by routing
@@ -18,34 +18,17 @@ diff -urNad privoxy~/config privoxy/config
 -#  proxy to speed up browsing. Or chaining to a parent proxy may be
 -#  necessary because the machine that Privoxy runs on has no direct
 -#  Internet access.
 -#  proxy to speed up browsing. Or chaining to a parent proxy may be
 -#  necessary because the machine that Privoxy runs on has no direct
 -#  Internet access.
-+#  requests to those domains through an anonymous public proxy 
-+#  or to use a caching proxy to speed up browsing. Or chaining to
-+#  a parent proxy may be necessary because the machine that Privoxy
-+#  runs on has no direct Internet access.
- #  
++#  requests to those domains through an anonymous public proxy or 
++#  use a caching proxy to speed up browsing. Or chaining to a parent
++#  proxy may be necessary because the machine that Privoxy runs on has
++#  no direct Internet access.
+ #
  #  Also specified here are SOCKS proxies. Privoxy supports the SOCKS
  #  4 and SOCKS 4A protocols.
  #  Also specified here are SOCKS proxies. Privoxy supports the SOCKS
  #  4 and SOCKS 4A protocols.
-diff -urNad privoxy~/doc/source/faq.sgml privoxy/doc/source/faq.sgml
---- privoxy~/doc/source/faq.sgml       2006-02-05 16:23:12.000000000 +0100
-+++ privoxy/doc/source/faq.sgml        2006-02-05 16:25:45.000000000 +0100
-@@ -1255,13 +1255,6 @@
-  on (those suspicious) people with a more than average preference for privacy.
- </para>
- <para>
-- You can find a list of anonymous public proxies at <ulink
-- url="http://www.multiproxy.org/anon_list.htm">multiproxy.org</ulink> and many
-- more through Google. A particularly interesting project is the JAP service
-- offered by the Technical University of Dresden (<ulink
-- url="http://anon.inf.tu-dresden.de/index_en.html">http://anon.inf.tu-dresden.de/index_en.html</ulink>).
--</para>
--<para>
-  There is, however, even in the single-machine case the possibility to make the
-  server believe that your machine is in fact a shared proxy serving a whole big
-  LAN, and we are looking into that.
 diff -urNad privoxy~/doc/source/p-config.sgml privoxy/doc/source/p-config.sgml
 diff -urNad privoxy~/doc/source/p-config.sgml privoxy/doc/source/p-config.sgml
---- privoxy~/doc/source/p-config.sgml  2006-02-05 16:23:12.000000000 +0100
-+++ privoxy/doc/source/p-config.sgml   2006-02-05 16:25:45.000000000 +0100
-@@ -1519,9 +1519,8 @@
+--- privoxy~/doc/source/p-config.sgml
++++ privoxy/doc/source/p-config.sgml
+@@ -1606,9 +1606,8 @@
   multiple proxies.
   It can be used to better protect privacy and confidentiality when
   accessing specific domains by routing requests to those domains
   multiple proxies.
   It can be used to better protect privacy and confidentiality when
   accessing specific domains by routing requests to those domains
index cf779e0..716d81c 100644 (file)
@@ -6,32 +6,38 @@
 
 @DPATCH@
 diff -urNad privoxy~/default.action.master privoxy/default.action.master
 
 @DPATCH@
 diff -urNad privoxy~/default.action.master privoxy/default.action.master
---- privoxy~/default.action.master     2006-02-05 16:23:12.000000000 +0100
-+++ privoxy/default.action.master      2006-02-05 16:25:47.000000000 +0100
-@@ -1444,6 +1444,8 @@
- .microsoft.com
- #MASTER# PROBLEM-URL: http://javabog.dk/ijk/
- javabog.dk/ijk/
-+#MASTER# PROBLEM-URL: http://validator.w3.org/
-+/valid-
- #----------------------------------------------------------------------------
- # These don't work without the referrer information:
-@@ -1464,6 +1466,8 @@
- #MASTER# PROBLEM-URL: http://www.mandrakelinux.com/en/ftp.php3
- #MASTER# REMARKS: Link to download page breaks
+--- privoxy~/default.action.master
++++ privoxy/default.action.master
+@@ -1593,6 +1593,8 @@
  www.mandrakelinux.com/en/ftp.php3
  www.mandrakelinux.com/en/ftp.php3
+ #MASTER# REMARKS: Actions Tracker 1313157
+ validator.w3.org/check\?uri=referer
 +#MASTER# PROBLEM-URL: http://www.petitiononline.com/mod_perl/signed.cgi?eldred&2901
 +www.petitiononline.com/mod_perl/signed.cgi
  
  #----------------------------------------------------------------------------
  # These animated gifs are either useful or nice:
 +#MASTER# PROBLEM-URL: http://www.petitiononline.com/mod_perl/signed.cgi?eldred&2901
 +www.petitiononline.com/mod_perl/signed.cgi
  
  #----------------------------------------------------------------------------
  # These animated gifs are either useful or nice:
-@@ -1601,6 +1605,8 @@
+@@ -1714,6 +1716,10 @@
+ #MASTER# PROBLEM-URL: http://www.nasa.gov
+ #MASTER# REMARKS: No progress past main page without js-annoyances
+ .nasa.gov
++#MASTER# PROBLEM-URL: http://www2.cnrs.fr/presse/communique/900.htm
++.cnrs.fr
++#MASTER# PROBLEM-URL: http://blogs.msdn.com/wga/archive/2006/07/16/667063.aspx
++blogs.msdn.com
+ {-filter{unsolicited-popups}}
+ #MASTER# DONT-VERIFY
+@@ -1733,6 +1739,12 @@
  cf.nbc4.com/
  #MASTER# PROBLEM-URL: http://www.hh.schule.de/ak/nt/
  www.hh.schule.de/ak/nt/
 +#MASTER# PROBLEM-URL: http://www.perl.com/language/newdocs/pod/perlop.html#Regexp_Quote_Like_Operators
 +www.perl.com/language/newdocs/pod/
  cf.nbc4.com/
  #MASTER# PROBLEM-URL: http://www.hh.schule.de/ak/nt/
  www.hh.schule.de/ak/nt/
 +#MASTER# PROBLEM-URL: http://www.perl.com/language/newdocs/pod/perlop.html#Regexp_Quote_Like_Operators
 +www.perl.com/language/newdocs/pod/
++#MASTER# PROBLEM-URL: http://www2.cnrs.fr/presse/communique/900.htm
++.cnrs.fr
++#MASTER# PROBLEM-URL: http://blogs.msdn.com/wga/archive/2006/07/16/667063.aspx
++blogs.msdn.com
  
  
- {+fast-redirects -block}
+ {+fast-redirects{check-decoded-url} -block}
  #MASTER# PROBLEM-URL: http://isbn.nu/0596001088/price/2.html
  #MASTER# PROBLEM-URL: http://isbn.nu/0596001088/price/2.html
index 3ddc586..e3ac205 100644 (file)
@@ -5,32 +5,32 @@
 ## DP: Stop converting 8bit chars in the documentation (#203697)
 
 @DPATCH@
 ## DP: Stop converting 8bit chars in the documentation (#203697)
 
 @DPATCH@
-diff -urNad privoxy-dpatch~/doc/source/ldp.dsl.in privoxy-dpatch/doc/source/ldp.dsl.in
---- privoxy-dpatch~/doc/source/ldp.dsl.in      2006-02-05 16:17:43.000000000 +0100
-+++ privoxy-dpatch/doc/source/ldp.dsl.in       2006-02-05 16:17:46.000000000 +0100
+diff -urNad privoxy~/doc/source/ldp.dsl.in privoxy/doc/source/ldp.dsl.in
+--- privoxy~/doc/source/ldp.dsl.in
++++ privoxy/doc/source/ldp.dsl.in
 @@ -47,9 +47,9 @@
 @@ -47,9 +47,9 @@
- ;; this is necessary because right now jadetex does not understand
- ;; symbolic entities, whereas things work well with numeric entities.
--(declare-characteristic preserve-sdata?
--  "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"
--  #f)
-+;(declare-characteristic preserve-sdata?
-+;  "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"
-+;  #f)
- ;; put the legal notice in a separate file
- (define %generate-legalnotice-link%
\r
+ ;; this is necessary because right now jadetex does not understand\r
+ ;; symbolic entities, whereas things work well with numeric entities.\r
+-(declare-characteristic preserve-sdata?\r
+-  "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"\r
+-  #f)\r
++;(declare-characteristic preserve-sdata?\r
++;  "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"\r
++;  #f)\r
\r
+ ;; put the legal notice in a separate file\r
+ (define %generate-legalnotice-link%\r
 @@ -257,9 +257,9 @@
 @@ -257,9 +257,9 @@
- ;; this is necessary because right now jadetex does not understand
- ;; symbolic entities, whereas things work well with numeric entities.
--(declare-characteristic preserve-sdata?
--  "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"
--  #f)
-+;(declare-characteristic preserve-sdata?
-+;  "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"
-+;  #f)
- ;; put the legal notice in a separate file
- (define %generate-legalnotice-link%
\r
+ ;; this is necessary because right now jadetex does not understand\r
+ ;; symbolic entities, whereas things work well with numeric entities.\r
+-(declare-characteristic preserve-sdata?\r
+-  "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"\r
+-  #f)\r
++;(declare-characteristic preserve-sdata?\r
++;  "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"\r
++;  #f)\r
\r
+ ;; put the legal notice in a separate file\r
+ (define %generate-legalnotice-link%\r
index 32669d1..7b53410 100644 (file)
@@ -7,9 +7,9 @@
 
 @DPATCH@
 diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy-man-page.sgml
 
 @DPATCH@
 diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy-man-page.sgml
---- privoxy~/doc/source/privoxy-man-page.sgml  2006-02-05 22:03:58.000000000 +0100
-+++ privoxy/doc/source/privoxy-man-page.sgml   2006-02-11 18:32:40.000000000 +0100
-@@ -333,7 +333,7 @@
+--- privoxy~/doc/source/privoxy-man-page.sgml
++++ privoxy/doc/source/privoxy-man-page.sgml
+@@ -367,7 +367,7 @@
   
   # Set personal exceptions to the policies in default.action #######
  
   
   # Set personal exceptions to the policies in default.action #######
  
@@ -18,33 +18,3 @@ diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy
   {-crunch-cookies -session-cookies-only}
    .redhat.com
    .sun.com
   {-crunch-cookies -session-cookies-only}
    .redhat.com
    .sun.com
-diff -urNad privoxy~/doc/source/user-manual.sgml privoxy/doc/source/user-manual.sgml
---- privoxy~/doc/source/user-manual.sgml       2004-01-31 10:49:48.000000000 +0100
-+++ privoxy/doc/source/user-manual.sgml        2006-02-11 18:34:24.000000000 +0100
-@@ -368,7 +368,7 @@
- </para>
- <para>
-- In order not to loose your personal changes and adjustments when updating
-+ In order not to lose your personal changes and adjustments when updating
-  to the latest <literal>default.action</literal> file we <emphasis>strongly
-  recommend</emphasis> that you use <literal>user.action</literal> for your
-  customization of <application>Privoxy</application>. See the <link
-@@ -1720,7 +1720,7 @@
- <para>
-  To determine which actions apply to a request, the URL of the request is
-- compared to all patterns in each action file file. Every time it matches, the list of
-+ compared to all patterns in each <quote>action file</quote> file. Every time it matches, the list of
-  applicable actions for the URL is incrementally updated, using the heading
-  of the section in which the pattern is located. If multiple matches for
-  the same URL set the same action differently, the last match wins. If not, 
-@@ -5251,7 +5251,7 @@
-  blocks of HTML code disappear when a specific symbol is set. We use this
-  for many purposes, one of them being to include the beta warning in all
-  our user interface (CGI) pages when <application>Privoxy</application>
-- in in an alpha or beta development stage:
-+ is in an alpha or beta development stage:
- </para>
- <para>
index 95129c7..b3458fd 100644 (file)
@@ -7,9 +7,9 @@
 
 @DPATCH@
 diff -urNad privoxy~/parsers.c privoxy/parsers.c
 
 @DPATCH@
 diff -urNad privoxy~/parsers.c privoxy/parsers.c
---- privoxy~/parsers.c 2006-02-05 16:23:12.000000000 +0100
-+++ privoxy/parsers.c  2006-02-05 16:25:49.000000000 +0100
-@@ -871,8 +871,7 @@
+--- privoxy~/parsers.c
++++ privoxy/parsers.c
+@@ -1248,8 +1248,7 @@
   *
   * Description :  - Prohibit filtering (CT_TABOO) if transfer coding compresses
   *                - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked"
   *
   * Description :  - Prohibit filtering (CT_TABOO) if transfer coding compresses
   *                - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked"
@@ -19,7 +19,7 @@ diff -urNad privoxy~/parsers.c privoxy/parsers.c
   *
   * Parameters  :
   *          1  :  csp = Current client state (buffers, headers, etc...)
   *
   * Parameters  :
   *          1  :  csp = Current client state (buffers, headers, etc...)
-@@ -904,13 +903,13 @@
+@@ -1281,14 +1280,13 @@
  
        /*
         * If the body was modified, it has been
  
        /*
         * If the body was modified, it has been
@@ -32,6 +32,7 @@ diff -urNad privoxy~/parsers.c privoxy/parsers.c
        {
           freez(*header);
 -         *header = strdup("Transfer-Encoding: identity");
        {
           freez(*header);
 -         *header = strdup("Transfer-Encoding: identity");
+-         log_error(LOG_LEVEL_HEADER, "Set: %s", *header);
 -         return (header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
        }
     }
 -         return (header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
        }
     }
index b1b9695..8390de2 100644 (file)
@@ -6,67 +6,67 @@
 
 @DPATCH@
 diff -urNad privoxy~/config privoxy/config
 
 @DPATCH@
 diff -urNad privoxy~/config privoxy/config
---- privoxy~/config    2006-02-11 20:29:59.000000000 +0100
-+++ privoxy/config     2006-02-11 20:30:28.000000000 +0100
+--- privoxy~/config
++++ privoxy/config
 @@ -1,4 +1,4 @@
 @@ -1,4 +1,4 @@
--#        Sample Configuration File for Privoxy v3.0.x
+-#        Sample Configuration File for Privoxy v3.0.4
 +#        Sample Configuration File for Privoxy
 +#        Sample Configuration File for Privoxy
- #  
- #  Copyright (C) 2001-2004 Privoxy Developers http://privoxy.org
- #  
-@@ -104,7 +104,7 @@
- #      flat, except for confdir/templates, where the HTML templates
- #      for CGI output reside (e.g. Privoxy's 404 error page).
- #  
--confdir .
-+confdir /etc/privoxy
- #  
- #  1.2. logdir
-@@ -131,7 +131,7 @@
- #  
- #      No trailing "/", please
- #  
--logdir .
-+logdir /var/log/privoxy
- #  
- #  1.3. actionsfile
-@@ -406,7 +406,7 @@
+ #
+ #  $Id: config,v 1.53 2006/09/07 02:02:56 hal9 Exp $
+ #
+@@ -123,7 +123,7 @@
  #          If set, this option should be the first option in the config
  #          file, because it is used while the config file is being read.
  #          If set, this option should be the first option in the config
  #          file, because it is used while the config file is being read.
- #  
+ #
 -#user-manual http://www.privoxy.org/user-manual/
 +user-manual /usr/share/doc/privoxy/user-manual
  
 -#user-manual http://www.privoxy.org/user-manual/
 +user-manual /usr/share/doc/privoxy/user-manual
  
- #  
- #  2.2. trust-info-url
-@@ -442,8 +442,8 @@
+ #
+ #  1.2. trust-info-url
+@@ -159,8 +159,8 @@
  #      don't end up locked out from the information on why they were
  #      locked out in the first place!
  #      don't end up locked out from the information on why they were
  #      locked out in the first place!
- #  
+ #
 -trust-info-url  http://www.example.com/why_we_block.html
 -trust-info-url  http://www.example.com/what_we_allow.html
 +#trust-info-url  http://www.example.com/why_we_block.html
 +#trust-info-url  http://www.example.com/what_we_allow.html
  
 -trust-info-url  http://www.example.com/why_we_block.html
 -trust-info-url  http://www.example.com/what_we_allow.html
 +#trust-info-url  http://www.example.com/why_we_block.html
 +#trust-info-url  http://www.example.com/what_we_allow.html
  
- #  
- #  2.3. admin-address
-@@ -730,7 +730,7 @@
+ #
+ #  1.3. admin-address
+@@ -266,7 +266,7 @@
+ #      flat, except for confdir/templates, where the HTML templates
+ #      for CGI output reside (e.g. Privoxy's 404 error page).
+ #
+-confdir .
++confdir /etc/privoxy
+ #
+ #  2.2. logdir
+@@ -293,7 +293,7 @@
+ #
+ #      No trailing "/", please
+ #
+-logdir .
++logdir /var/log/privoxy
+ #
+ #  2.3. actionsfile
+@@ -735,7 +735,7 @@
  #      Note that you must have compiled Privoxy with support for this
  #      feature, otherwise this option has no effect.
  #      Note that you must have compiled Privoxy with support for this
  #      feature, otherwise this option has no effect.
- #  
+ #
 -enable-remote-toggle  1
 +enable-remote-toggle  0
  
 -enable-remote-toggle  1
 +enable-remote-toggle  0
  
- #  
- #  4.4. enable-edit-actions
-@@ -763,7 +763,7 @@
+ #
+ #  4.4. enable-remote-http-toggle
+@@ -803,7 +803,7 @@
  #      Note that you must have compiled Privoxy with support for this
  #      feature, otherwise this option has no effect.
  #      Note that you must have compiled Privoxy with support for this
  #      feature, otherwise this option has no effect.
- #  
+ #
 -enable-edit-actions 1
 +enable-edit-actions 0
  
 -enable-edit-actions 1
 +enable-edit-actions 0
  
- #  
- #  4.5. ACLs: permit-access and deny-access
+ #
+ #  4.6. ACLs: permit-access and deny-access
index 8311c66..79e0081 100644 (file)
@@ -5,21 +5,9 @@
 ## DP: Move man page from man section 1 to man section 8.
 
 @DPATCH@
 ## DP: Move man page from man section 1 to man section 8.
 
 @DPATCH@
-diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy-man-page.sgml
---- privoxy~/doc/source/privoxy-man-page.sgml  2006-02-11 23:44:40.000000000 +0100
-+++ privoxy/doc/source/privoxy-man-page.sgml   2006-02-11 23:44:40.000000000 +0100
-@@ -57,7 +57,7 @@
- </refentryinfo>
- <refmeta>
-  <refentrytitle>privoxy</refentrytitle> 
-- <manvolnum>1</manvolnum>
-+ <manvolnum>8</manvolnum>
-  <refmiscinfo>
-   Privoxy &p-version;<![%p-not-stable;[ &p-status;]]>
-  </refmiscinfo>
 diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
 diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
---- privoxy~/GNUmakefile.in    2006-02-11 23:44:25.000000000 +0100
-+++ privoxy/GNUmakefile.in     2006-02-11 23:44:40.000000000 +0100
+--- privoxy~/GNUmakefile.in
++++ privoxy/GNUmakefile.in
 @@ -177,7 +177,7 @@
                `find doc/text/ -type f | grep -v "CVS" | grep -v "\.\#" | grep -v ".*~" | grep -v ".cvsignore" | grep -v "TAGS"` \
                `find doc/webserver/ -name "*.html" | grep -v "\(webserver\|team\)\/index\.html"` \
 @@ -177,7 +177,7 @@
                `find doc/text/ -type f | grep -v "CVS" | grep -v "\.\#" | grep -v ".*~" | grep -v ".cvsignore" | grep -v "TAGS"` \
                `find doc/webserver/ -name "*.html" | grep -v "\(webserver\|team\)\/index\.html"` \
@@ -29,7 +17,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
                doc/pdf/*.pdf
  
  #############################################################################
                doc/pdf/*.pdf
  
  #############################################################################
-@@ -520,7 +520,7 @@
+@@ -521,7 +521,7 @@
        $(RM) /etc/init.d/privoxy
        $(RM) /usr/sbin/privoxy
        $(RM) /usr/sbin/rcprivoxy
        $(RM) /etc/init.d/privoxy
        $(RM) /usr/sbin/privoxy
        $(RM) /usr/sbin/rcprivoxy
@@ -38,7 +26,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
  
  #############################################################################
  # generic distribution
  
  #############################################################################
  # generic distribution
-@@ -692,7 +692,7 @@
+@@ -697,7 +697,7 @@
        $(RM) doc/man/* doc/webserver/man-page/*.html
  ifneq ($(MAN2HTML),false)
        $(ECHO) "<html><head><title>Privoxy Man page</title><link rel=\"stylesheet\" type=\"text/css\" href=\"../p_web.css\"></head><body><H2>NAME</H2>" > doc/webserver/man-page/privoxy-man-page.html
        $(RM) doc/man/* doc/webserver/man-page/*.html
  ifneq ($(MAN2HTML),false)
        $(ECHO) "<html><head><title>Privoxy Man page</title><link rel=\"stylesheet\" type=\"text/css\" href=\"../p_web.css\"></head><body><H2>NAME</H2>" > doc/webserver/man-page/privoxy-man-page.html
@@ -47,7 +35,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
        $(ECHO) "</body></html>" >> doc/webserver/man-page/privoxy-man-page.html
  else
        $(MAKE) groff2html
        $(ECHO) "</body></html>" >> doc/webserver/man-page/privoxy-man-page.html
  else
        $(MAKE) groff2html
-@@ -704,14 +704,14 @@
+@@ -709,14 +709,14 @@
  man: dok-release
        mkdir -p doc/source/temp && cd doc/source/temp && $(RM) * ;\
        nsgmls ../privoxy-man-page.sgml  | sgmlspl ../../../utils/docbook2man/docbook2man-spec.pl &&\
  man: dok-release
        mkdir -p doc/source/temp && cd doc/source/temp && $(RM) * ;\
        nsgmls ../privoxy-man-page.sgml  | sgmlspl ../../../utils/docbook2man/docbook2man-spec.pl &&\
@@ -65,7 +53,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
        $(PERL) -pi.bak -e 's/<A .*Contents<\/A>//; s/<A .*man2html<\/A>/man2html/' tmp.html
        $(PERL) -pi.bak -e 's/(<\/HEAD>)/<LINK REL=\"STYLESHEET\" TYPE=\"text\/css\" HREF=\"..\/p_doc.css\"><\/HEAD>/' tmp.html
  # Twice because my version of man2html is pulling in commas and periods in URLs.
        $(PERL) -pi.bak -e 's/<A .*Contents<\/A>//; s/<A .*man2html<\/A>/man2html/' tmp.html
        $(PERL) -pi.bak -e 's/(<\/HEAD>)/<LINK REL=\"STYLESHEET\" TYPE=\"text\/css\" HREF=\"..\/p_doc.css\"><\/HEAD>/' tmp.html
  # Twice because my version of man2html is pulling in commas and periods in URLs.
-@@ -726,7 +726,7 @@
+@@ -731,7 +731,7 @@
  
  # Otherwise we get plain groff conversion.
  groff2html:
  
  # Otherwise we get plain groff conversion.
  groff2html:
@@ -74,8 +62,8 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
  
  
  # readme page and INSTALL file
  
  
  # readme page and INSTALL file
-@@ -1122,8 +1122,8 @@
-               $(INSTALL) $(INSTALL_T) $(DOK_WEB)/p_doc.css $$DOC;\
+@@ -1129,8 +1129,8 @@
+               $(INSTALL) $(INSTALL_T) $(DOK_WEB)/p_doc.css $$DOC/user-manual;\
        fi
        @# Not all platforms support gzipped man pages.
 -      @$(ECHO) Installing man page to $(MAN_DEST)/privoxy.1
        fi
        @# Not all platforms support gzipped man pages.
 -      @$(ECHO) Installing man page to $(MAN_DEST)/privoxy.1
@@ -85,7 +73,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
  
        @# Change the config file default directories according to the configured ones
        @$(ECHO) Rewriting config for this installation
  
        @# Change the config file default directories according to the configured ones
        @$(ECHO) Rewriting config for this installation
-@@ -1273,7 +1273,7 @@
+@@ -1286,7 +1286,7 @@
  
        @# man page and docs
        @$(ECHO) Removing $(PROGRAM) docs
  
        @# man page and docs
        @$(ECHO) Removing $(PROGRAM) docs
@@ -94,3 +82,15 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
        -$(RM) -r $(DOC_DEST) || $(RM) -r $(prefix)/doc/privoxy
  
        @# Log and jarfile and pidfile
        -$(RM) -r $(DOC_DEST) || $(RM) -r $(prefix)/doc/privoxy
  
        @# Log and jarfile and pidfile
+diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy-man-page.sgml
+--- privoxy~/doc/source/privoxy-man-page.sgml
++++ privoxy/doc/source/privoxy-man-page.sgml
+@@ -57,7 +57,7 @@
+ </refentryinfo>
+ <refmeta>
+  <refentrytitle>privoxy</refentrytitle> 
+- <manvolnum>1</manvolnum>
++ <manvolnum>8</manvolnum>
+  <refmiscinfo>
+   Privoxy &p-version;<![%p-not-stable;[ &p-status;]]>
+  </refmiscinfo>
diff --git a/debian/patches/16_gzip.dpatch b/debian/patches/16_gzip.dpatch
new file mode 100755 (executable)
index 0000000..9d6cc72
--- /dev/null
@@ -0,0 +1,527 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 16_gzip.dpatch by Wil Mahan <wmahan@users.sourceforge.net>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Add deflate-filter support to privoxy, see sf bug id 895531
+## DP: Adapted from privoxy 3.1 to 3.0.x by Roland Rosenfeld.
+## DP: This requires --enable-zlib as configure option in debian/rules
+## DP: and a build dependeny on zlib1g-dev.
+
+@DPATCH@
+diff -urNad privoxy~/actionlist.h privoxy/actionlist.h
+--- privoxy~/actionlist.h
++++ privoxy/actionlist.h
+@@ -116,6 +116,7 @@
+ DEFINE_ACTION_STRING     ("deanimate-gifs",             ACTION_DEANIMATE,       ACTION_STRING_DEANIMATE)
+ DEFINE_CGI_PARAM_RADIO   ("deanimate-gifs",             ACTION_DEANIMATE,       ACTION_STRING_DEANIMATE,     "first", 0)
+ DEFINE_CGI_PARAM_RADIO   ("deanimate-gifs",             ACTION_DEANIMATE,       ACTION_STRING_DEANIMATE,     "last",  1)
++DEFINE_ACTION_BOOL       ("decompress-from-server",     ACTION_DECOMPRESS_IN)
+ DEFINE_ACTION_BOOL       ("downgrade-http-version",     ACTION_DOWNGRADE)
+ DEFINE_ACTION_BOOL       ("fast-redirects",             ACTION_FAST_REDIRECTS)
+ DEFINE_ACTION_MULTI      ("filter",                     ACTION_MULTI_FILTER)
+diff -urNad privoxy~/configure.in privoxy/configure.in
+--- privoxy~/configure.in
++++ privoxy/configure.in
+@@ -1234,6 +1234,20 @@
+                                 libpcrs is available],
+ [ if test $enableval = "no"; then have_pcrs=no; fi ])
++AC_ARG_ENABLE(zlib,
++[  --enable-zlib            Use the zlib library to allow compressing or
++                             decompressing data on the fly.],
++[enableval2=$enableval],
++[enableval2=no])
++if test $enableval2 = yes; then
++  AC_CHECK_LIB(z, zlibVersion, , [
++    AC_MSG_ERROR([Unable to find a copy of zlib.  The zlib library
++is necessary to enable compresion support. ])
++  ]) 
++  AC_DEFINE(FEATURE_ZLIB,1,
++    [ Define to 1 to use compression through the zlib library. ])
++fi
++
+ # If we have libpcre and either we also have pcreposix or
+ # we don't need pcreposix, then link pcre dynamically; else
+diff -urNad privoxy~/default.action.master privoxy/default.action.master
+--- privoxy~/default.action.master
++++ privoxy/default.action.master
+@@ -452,7 +452,7 @@
+ -hide-user-agent \
+ -kill-popups \
+ -limit-connect \
+-+prevent-compression \
++-prevent-compression \
+ -send-vanilla-wafer \
+ -send-wafer \
+ +session-cookies-only \
+diff -urNad privoxy~/filters.c privoxy/filters.c
+--- privoxy~/filters.c
++++ privoxy/filters.c
+@@ -1325,6 +1325,38 @@
+          return(NULL);
+    }
++#ifdef FEATURE_ZLIB
++   /* If the body has a compressed transfer-encoding, uncompress
++    * it first, adjusting size and iob->eod.  Note that
++    * decompression occurs after de-chunking.
++    */
++   if (csp->content_type & CT_GZIP || csp->content_type & CT_DEFLATE)
++   {
++      /* Notice that we at least tried to decompress. */
++      if (JB_ERR_OK != decompress_iob(csp))
++      {
++       /* We failed to decompress the data; there's no point
++        * in continuing since we can't filter.  This is
++        * slightly tricky because we need to remember not to
++        * modify the Content-Encoding header later; using
++        * CT_TABOO flag is a kludge for this purpose.
++        */
++         csp->content_type |= CT_TABOO;
++         return(NULL);
++      }
++      log_error(LOG_LEVEL_RE_FILTER, "Decompressing successful");
++
++      /* Decompression gives us a completely new iob, so we
++       * need to update.
++       */
++      size = csp->iob->eod - csp->iob->cur;
++      old  = csp->iob->cur;
++
++      csp->flags |= CSP_FLAG_MODIFIED;
++   }
++#endif
++
++
+    /*
+     * If the body has a "chunked" transfer-encoding,
+     * get rid of it first, adjusting size and iob->eod
+diff -urNad privoxy~/jcc.c privoxy/jcc.c
+--- privoxy~/jcc.c
++++ privoxy/jcc.c
+@@ -659,6 +659,10 @@
+ #  include <select.h>
+ # endif
++#ifdef FEATURE_ZLIB
++#include <zlib.h>
++#endif
++
+ #endif
+ #include "project.h"
+@@ -1609,6 +1613,8 @@
+             if ((csp->content_type & CT_TEXT) &&  /* It's a text / * MIME-Type */
+                 !http->ssl    &&                  /* We talk plaintext */
++                                       !(csp->content_type & CT_GZIP)    && 
++                                       !(csp->content_type & CT_DEFLATE) && 
+                 block_popups)                     /* Policy allows */
+             {
+                block_popups_now = 1;
+diff -urNad privoxy~/parsers.c privoxy/parsers.c
+--- privoxy~/parsers.c
++++ privoxy/parsers.c
+@@ -433,6 +433,10 @@
+ #include <assert.h>
+ #include <string.h>
++#ifdef FEATURE_ZLIB
++#include <zlib.h>
++#endif
++
+ #if !defined(_WIN32) && !defined(__OS2__)
+ #include <unistd.h>
+ #endif
+@@ -632,6 +636,281 @@
+ }
++#ifdef FEATURE_ZLIB
++/*********************************************************************
++ *
++ * Function    :  decompress_iob
++ *
++ * Description :  Decompress buffered page, expanding the
++ *                buffer as necessary.  csp->iob->cur
++ *                should point to the the beginning of the
++ *                compressed data block.
++ *
++ * Parameters  :
++ *          1  :  csp = Current client state (buffers, headers, etc...)
++ *
++ * Returns     :  JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory
++ *                limit reached, JB_ERR_COMPRESS if error decompressing
++ *                buffer.
++ *
++ *********************************************************************/
++jb_err decompress_iob(struct client_state *csp)
++{
++   char *buf;                    /* new, uncompressed buffer */
++   int bufsize = csp->iob->size; /* allocated size of the new buffer */
++                                 /* Number of bytes at the beginning
++                                * of the iob that we should NOT
++                                * decompress.
++                                */
++   int skip_size = csp->iob->cur - csp->iob->buf;
++   int status;                   /* return status of the inflate() call */
++   z_stream zstr;           /* used by calls to zlib */
++
++   /* This is to protect the parsing of gzipped data, but it should(?)
++    * be valid for deflated data also.
++    */
++   if (bufsize < 10)
++   {
++      log_error (LOG_LEVEL_ERROR, "Buffer too small decompressing iob");
++      return JB_ERR_COMPRESS;
++   }
++
++   if (csp->content_type & CT_GZIP)
++   {
++      /* Our task is slightly complicated by the facts that data
++       * compressed by gzip does not include a zlib header, and
++       * that there is no easily accessible interface in zlib to
++       * handle a gzip header.  We strip off the gzip header by
++       * hand, and later inform zlib not to expect a header.
++       */
++
++      /* Strip off the gzip header.  Please see RFC 1952 for more
++       * explanation of the appropriate fields.
++       */
++      if ((*csp->iob->cur++ != (char)0x1f)
++           || (*csp->iob->cur++ != (char)0x8b)
++         || (*csp->iob->cur++ != Z_DEFLATED))
++      {
++         log_error (LOG_LEVEL_ERROR,
++                   "Invalid gzip header when decompressing");
++         return JB_ERR_COMPRESS;
++      }
++      else {
++         int flags = *csp->iob->cur++;
++         if (flags & 0xe0)
++         {
++            /* The gzip header has reserved bits set; bail out. */
++            log_error (LOG_LEVEL_ERROR,
++                      "Invalid gzip header when decompressing");
++            return JB_ERR_COMPRESS;
++         }
++         csp->iob->cur += 6;
++
++         /* Skip extra fields if necessary. */
++         if (flags & 0x04)
++         {
++            /* Skip a given number of bytes, specified as a 16-bit
++           * little-endian value.
++           */
++            csp->iob->cur += *csp->iob->cur++ + (*csp->iob->cur++ << 8);
++         }
++
++         /* Skip the filename if necessary. */
++         if (flags & 0x08)
++         {
++            /* A null-terminated string follows. */
++            while (*csp->iob->cur++);
++         }
++
++         /* Skip the comment if necessary. */
++         if (flags & 0x10)
++         {
++            while (*csp->iob->cur++);
++         }
++
++         /* Skip the CRC if necessary. */
++         if (flags & 0x02)
++         {
++            csp->iob->cur += 2;
++         }
++      }
++   }
++   else if (csp->content_type & CT_DEFLATE)
++   {
++   log_error (LOG_LEVEL_INFO, "Decompressing deflated iob: %d", *csp->iob->cur);
++      /* In theory (that is, according to RFC 1950), deflate-compressed
++       * data should begin with a two-byte zlib header and have an
++       * adler32 checksum at the end.  It seems that in practice the
++       * only the raw compressed data is sent.  Note that this means that
++       * we are not RFC 1950-compliant here, but the advantage is that
++       * this actually works. :)
++       *
++       * We add a dummy null byte to tell zlib where the data ends,
++       * and later inform it not to expect a header.
++       *
++       * Fortunately, add_to_iob() has thoughtfully null-terminated
++       * the buffer; we can just increment the end pointer to include
++       * the dummy byte.  
++       */
++      csp->iob->eod++;
++   }
++   else
++   {
++      log_error (LOG_LEVEL_ERROR,
++                                        "Unable to determine compression format for decompression");
++      return JB_ERR_COMPRESS;
++   }
++
++   /* Set up the fields required by zlib. */
++   zstr.next_in  = csp->iob->cur;
++   zstr.avail_in = csp->iob->eod - csp->iob->cur;
++   zstr.zalloc   = Z_NULL;
++   zstr.zfree    = Z_NULL;
++   zstr.opaque   = Z_NULL;
++
++   /* Passing -MAX_WBITS to inflateInit2 tells the library
++    * that there is no zlib header.
++    */
++   if (inflateInit2 (&zstr, -MAX_WBITS) != Z_OK)
++   {
++      log_error (LOG_LEVEL_ERROR,
++                "Error initializing decompression");
++      return JB_ERR_COMPRESS;
++   }
++
++   /* Next, we allocate new storage for the inflated data.
++    * We don't modify the existing iob yet, so in case there
++    * is error in decompression we can recover gracefully.
++    */
++   buf = zalloc (bufsize);
++   if (NULL == buf)
++   {
++      log_error (LOG_LEVEL_ERROR,
++                "Out of memory decompressing iob");
++      return JB_ERR_MEMORY;
++   }
++
++   assert(bufsize >= skip_size);
++   memcpy(buf, csp->iob->buf, skip_size);
++   zstr.avail_out = bufsize - skip_size;
++   zstr.next_out  = buf + skip_size;
++
++   /* Try to decompress the whole stream in one shot. */
++   while (Z_BUF_ERROR == (status = inflate(&zstr, Z_FINISH)))
++   { 
++      /* We need to allocate more memory for the output buffer. */
++
++      char *tmpbuf;             /* used for realloc'ing the buffer */
++      int oldbufsize = bufsize; /* keep track of the old bufsize */
++
++      /* If zlib wants more data then there's a problem, because
++       * the complete compressed file should have been buffered.
++       */
++      if (0 == zstr.avail_in)
++      {
++         log_error(LOG_LEVEL_ERROR,
++                  "Unexpected end of compressed iob");
++         return JB_ERR_COMPRESS;
++      }
++
++      /* If we tried the limit and still didn't have enough
++       * memory, just give up.
++       */
++      if (bufsize == csp->config->buffer_limit)
++      {
++         log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
++         return JB_ERR_MEMORY;
++      }
++
++      /* Try doubling the buffer size each time. */
++      bufsize *= 2;
++
++      /* Don't exceed the buffer limit. */
++      if (bufsize > csp->config->buffer_limit)
++      {
++         bufsize = csp->config->buffer_limit;
++      }
++    
++      /* Try to allocate the new buffer. */
++      tmpbuf = realloc(buf, bufsize);
++      if (NULL == tmpbuf)
++      {
++         log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
++       freez(buf);
++         return JB_ERR_MEMORY;
++      }
++      else
++      {
++         char *oldnext_out = zstr.next_out;
++
++         /* Update the fields for inflate() to use the new
++        * buffer, which may be in a different location from
++        * the old one.
++        */
++         zstr.avail_out += bufsize - oldbufsize;
++       zstr.next_out = tmpbuf + bufsize - zstr.avail_out;
++
++         /* Compare with an uglier method of calculating these values
++        * that doesn't require the extra oldbufsize variable.
++        */
++         assert(zstr.avail_out ==
++                tmpbuf + bufsize - (char *)zstr.next_out);
++         assert((char *)zstr.next_out ==
++                tmpbuf + ((char *)oldnext_out - buf));
++         assert(zstr.avail_out > 0);
++
++         buf = tmpbuf;
++      }
++   }
++
++   inflateEnd(&zstr);
++   if (status != Z_STREAM_END)
++   {
++      /* We failed to decompress the stream. */
++      log_error(LOG_LEVEL_ERROR,
++               "Error in decompressing to the buffer (iob): %s",
++             zstr.msg);
++      return JB_ERR_COMPRESS;
++   }
++
++   /* Finally, we can actually update the iob, since the
++    * decompression was successful.  First, free the old
++    * buffer.
++    */
++   freez(csp->iob->buf);
++
++   /* Now, update the iob to use the new buffer. */
++   csp->iob->buf  = buf;
++   csp->iob->cur  = csp->iob->buf + skip_size;
++   csp->iob->eod  = zstr.next_out;
++   csp->iob->size = bufsize;
++  
++   /* Make sure the new uncompressed iob obeys some minimal
++    * consistency conditions.
++    */
++   if ((csp->iob->buf < csp->iob->cur)
++       && (csp->iob->cur <= csp->iob->eod)
++       && (csp->iob->eod <= csp->iob->buf + csp->iob->size))
++   {
++         char t = csp->iob->cur[100];
++         csp->iob->cur[100] = 0;
++      log_error(LOG_LEVEL_INFO,
++               "Sucessfully decompressed: %s", csp->iob->cur);
++         csp->iob->cur[100] = t;
++      return JB_ERR_OK;
++   }
++   else
++   {
++      /* It seems that zlib did something weird. */
++      log_error(LOG_LEVEL_ERROR,
++               "Unexpected error decompressing the buffer (iob): %d==%d, %d>%d, %d<%d", csp->iob->cur,  csp->iob->buf + skip_size, csp->iob->eod, csp->iob->buf, csp->iob->eod, csp->iob->buf + csp->iob->size);
++      return JB_ERR_COMPRESS;
++   }
++
++}
++#endif /* defined(FEATURE_ZLIB) */
++
++
+ /*********************************************************************
+  *
+  * Function    :  get_header
+@@ -936,13 +1215,59 @@
+  *********************************************************************/
+ jb_err server_content_encoding(struct client_state *csp, char **header)
+ {
++#ifdef FEATURE_ZLIB
++   if (strstr(*header, "gzip"))
++   {
++      /*
++       * If the body was modified, we have tried to
++       * decompress it, so adjust the header if necessary.
++       */
++      if ((csp->flags & CSP_FLAG_MODIFIED) /* we attempted to decompress   */
++      && !(csp->content_type & CT_TABOO))  /* decompression was successful */
++      {
++         freez(*header);
++         *header = strdup("Content-Encoding: identity");
++         return (header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
++      }
++      else
++      {
++        csp->content_type |= CT_GZIP;
++      }
++   }
++   else if (strstr(*header, "deflate"))
++   {
++      /*
++       * If the body was modified, we have tried to
++       * decompress it, so adjust the header if necessary.
++       */
++      if ((csp->flags & CSP_FLAG_MODIFIED) /* we attempted to decompress   */
++      && !(csp->content_type & CT_TABOO))  /* decompression was successful */
++      {
++         freez(*header);
++         *header = strdup("Content-Encoding: identity");
++         return (header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
++      }
++      else
++      {
++        csp->content_type |= CT_DEFLATE;
++      }
++   }
++   else if (strstr(*header, "compress"))
++   {
++      /* We can't decompress this; therefore we can't filter
++       * it either.
++       */
++      csp->content_type |= CT_TABOO;
++   }
++#else /* !defined(FEATURE_GZIP) */
+    /*
+     * Turn off pcrs and gif filtering if body compressed
+     */
+    if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate"))
+    {
+-      csp->content_type = CT_TABOO;
++      csp->content_type |= CT_TABOO;
+    }
++#endif /* !defined(FEATURE_GZIP) */
+    return JB_ERR_OK;
+diff -urNad privoxy~/parsers.h privoxy/parsers.h
+--- privoxy~/parsers.h
++++ privoxy/parsers.h
+@@ -194,6 +194,7 @@
+ extern int flush_socket(jb_socket fd, struct client_state *csp);
+ extern jb_err add_to_iob(struct client_state *csp, char *buf, int n);
++extern jb_err decompress_iob(struct client_state *csp);
+ extern char *get_header(struct client_state *csp);
+ extern char *get_header_value(const struct list *header_list, const char *header_name);
+ extern char *sed(const struct parsers pats[], const add_header_func_ptr more_headers[], struct client_state *csp);
+diff -urNad privoxy~/project.h privoxy/project.h
+--- privoxy~/project.h
++++ privoxy/project.h
+@@ -563,7 +563,7 @@
+ #define JB_ERR_PARSE      4 /**< Error parsing file                       */
+ #define JB_ERR_MODIFIED   5 /**< File has been modified outside of the  
+                                  CGI actions editor.                      */
+-
++#define JB_ERR_COMPRESS   6 /**< Error on decompression                   */
+ /**
+  * This macro is used to free a pointer that may be NULL.
+@@ -818,6 +818,15 @@
+ #define CT_TABOO  4 /**< csp->content_type bitmask:
+                          DO NOT filter, irrespective of other flags. */
++/* Although these are not, strictly speaking, content types
++ * (they are content encodings), it is simple to handle
++ * them as such.
++ */
++#define CT_GZIP     8 /**< csp->content_type bitmask:
++                         gzip-compressed data. */
++#define CT_DEFLATE 16 /**< csp->content_type bitmask:
++                         zlib-compressed data. */
++
+ /**
+  * The mask which includes all actions.
+  */
+@@ -862,6 +871,8 @@
+ #define ACTION_VANILLA_WAFER   0x00008000UL
+ /** Action bitmap: Limit CONNECT requests to safe ports. */
+ #define ACTION_LIMIT_CONNECT   0x00010000UL
++/** Action bitmap: Uncompress incoming text for filtering. */
++#define ACTION_DECOMPRESS_IN   0x00020000UL
+ /** Action string index: How to deanimate GIFs */
+ #define ACTION_STRING_DEANIMATE     0
diff --git a/debian/patches/17_502_no_such_domain.dpatch b/debian/patches/17_502_no_such_domain.dpatch
new file mode 100755 (executable)
index 0000000..6eafee7
--- /dev/null
@@ -0,0 +1,30 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 17_502_no_such_domain.dpatch by Roland Rosenfeld <roland@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Changes the 404 HTTP status code of the "No such Domain" template
+## DP: to 502 Bad Gateway, which seems to be more correct according to 
+## DP: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+
+@DPATCH@
+diff -urNad privoxy~/templates/no-such-domain privoxy/templates/no-such-domain
+--- privoxy~/templates/no-such-domain
++++ privoxy/templates/no-such-domain
+@@ -79,7 +79,7 @@
+ <html>
+ <head>
+-  <title>404 - No such Domain (Privoxy@@my-hostname@)</title>
++  <title>502 - Bad Gateway (Privoxy@@my-hostname@)</title>
+   <meta http-equiv="Content-Style-Type" content="text/css">
+   <meta http-equiv="Content-Script-Type" content="text/javascript">
+   <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+@@ -92,7 +92,7 @@
+   <table cellpadding="20" cellspacing="10" border="0" width="100%">
+     <tr>
+       <td class="status">
+-        404
++        502
+       </td>     
+       <td class="title" style="width: 100%">
diff --git a/debian/patches/18_dns_retry.dpatch b/debian/patches/18_dns_retry.dpatch
new file mode 100755 (executable)
index 0000000..cff2cbb
--- /dev/null
@@ -0,0 +1,58 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 18_dns_retry.dpatch by Fabian Keil <fk@fabiankeil.de>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Retries DNS queries 10 times before giving up.
+## DP: Extracted from http://www.fabiankeil.de/sourcecode/privoxy/
+
+@DPATCH@
+diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c
+--- privoxy~/jbsockets.c
++++ privoxy/jbsockets.c
+@@ -780,6 +780,7 @@
+ {
+    struct sockaddr_in inaddr;
+    struct hostent *hostp;
++   unsigned int dns_retries = 0;
+ #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
+    struct hostent result;
+ #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
+@@ -800,8 +801,13 @@
+    if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
+    {
+ #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
+-      gethostbyname_r(host, &result, hbuf,
+-                      HOSTENT_BUFFER_SIZE, &hostp, &thd_err);
++              while ( gethostbyname_r(host, &result, hbuf,
++                                                                              HOSTENT_BUFFER_SIZE, &hostp, &thd_err)
++                                && (thd_err == TRY_AGAIN) && (dns_retries++ < 10) )
++              {   
++                log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
++                                              dns_retries, host);
++      }
+ #elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
+       hostp = gethostbyname_r(host, &result, hbuf,
+                       HOSTENT_BUFFER_SIZE, &thd_err);
+@@ -816,10 +822,20 @@
+       }
+ #elif OSX_DARWIN
+       pthread_mutex_lock(&gethostbyname_mutex);
+-      hostp = gethostbyname(host);
++              while ( NULL == (hostp = gethostbyname(host))
++                                && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
++              {   
++                log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
++                                              dns_retries, host);
++      }
+       pthread_mutex_unlock(&gethostbyname_mutex);
+ #else
+-      hostp = gethostbyname(host);
++      while ( NULL == (hostp = gethostbyname(host))
++            && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
++      {
++         log_error(LOG_LEVEL_ERROR, "%u. timeout while trying to resolve %s. Trying again.",
++                                                dns_retries, host);
++      }
+ #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
+       /*
+        * On Mac OSX, if a domain exists but doesn't have a type A
diff --git a/debian/patches/19_manpage_fixup.dpatch b/debian/patches/19_manpage_fixup.dpatch
new file mode 100755 (executable)
index 0000000..bdb3c11
--- /dev/null
@@ -0,0 +1,30 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 19_manpage_fixup.dpatch by Roland Rosenfeld <roland@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Convert Latin-1 char á to groff eqivalent in man page.
+## DP: Quote minus signs to differenciate them from hyphens.
+
+@DPATCH@
+diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
+--- privoxy~/GNUmakefile.in
++++ privoxy/GNUmakefile.in
+@@ -710,6 +710,10 @@
+       mkdir -p doc/source/temp && cd doc/source/temp && $(RM) * ;\
+       nsgmls ../privoxy-man-page.sgml  | sgmlspl ../../../utils/docbook2man/docbook2man-spec.pl &&\
+       perl -pi.bak -e 's/ <URL:.*>//; s/\[ /\[/g' privoxy.8 ;\
++      perl -pi.bak -e "s/\[ /\[/g;s/á/\\\\['a]/g" privoxy.8; \
++      perl -pi.bak -e 's/([ {])-([a-z])/$$1\\-$$2/g' privoxy.8; \
++      perl -pi.bak -e 's/ --([a-z])/ \\-\\-$$1/g' privoxy.8; \
++      perl -pi.bak -e 's/\\fB--/\\fB\\-\\-/g' privoxy.8; \
+       $(DB) ../privoxy-man-page.sgml && $(MV) -f privoxy.8 ../../../privoxy.8
+ # For those with man2html ala RH7s.
+@@ -722,6 +726,7 @@
+ # Twice because my version of man2html is pulling in commas and periods in URLs.
+       $(PERL) -pi.bak -e 's/(<A.*),(">)/$$1$$2/g' tmp.html
+       $(PERL) -pi.bak -e 's,\.">,">,g' tmp.html
++      $(PERL) -pi.bak -e "s/\['a\]/\&aacute;/g" tmp.html
+ # Get rid of spurious \a from conversion. (How to do this with perl?)
+       $(SED) -e 's/\a//g' tmp.html > doc/webserver/man-page/privoxy-man-page.html && $(RM) tmp.*
+ else
diff --git a/debian/patches/20_makefile_fixup.dpatch b/debian/patches/20_makefile_fixup.dpatch
new file mode 100755 (executable)
index 0000000..2717bb9
--- /dev/null
@@ -0,0 +1,23 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 20_makefile_fixup.dpatch by Roland Rosenfeld <roland@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Fix syntax error in GNUmakefile.in
+
+@DPATCH@
+diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
+--- privoxy~/GNUmakefile.in
++++ privoxy/GNUmakefile.in
+@@ -678,9 +678,9 @@
+       $(RM) -r doc/source/user-manual/
+       mkdir -p doc/text doc/source/user-manual
+       cd doc/source/user-manual && $(DB) -iuser-man ../user-manual.sgml && cd .. && cp user-manual/*.html ../webserver/user-manual/
+-      @#FIXME: temp fix so same stylesheet gets in more than one place so it works \
+-      @# for all doc set-ups, including the 'user manual' config option in local \
+-      @#system where it MUST be in same directory as html.
++      #FIXME: temp fix so same stylesheet gets in more than one place so it works \
++      # for all doc set-ups, including the 'user manual' config option in local \
++      #system where it MUST be in same directory as html.
+       $(PERL) -pi.bak -e 's/<\/head/\n<LINK REL=\"STYLESHEET\" TYPE=\"text\/css\" HREF=\"p_doc.css\">\n<\/head/i' doc/webserver/user-manual/*html
+       cd doc/source && $(DB) -iuser-man -V nochunks user-manual.sgml > tmp.html && $(WDUMP) tmp.html > ../text/user-manual.txt && $(RM) -r tmp.html user-manual
diff --git a/debian/patches/21_version_3.0.4.dpatch b/debian/patches/21_version_3.0.4.dpatch
new file mode 100755 (executable)
index 0000000..821f5ef
--- /dev/null
@@ -0,0 +1,22 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 21_version_3.0.4.dpatch by Roland Rosenfeld <roland@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Bump version to 3.0.4 otherwise privoxy complains in the version check.
+
+@DPATCH@
+diff -urNad privoxy~/configure.in privoxy/configure.in
+--- privoxy~/configure.in
++++ privoxy/configure.in
+@@ -488,9 +488,9 @@
+ dnl Application version number
+ dnl =================================================================
+-VERSION_MAJOR=0
++VERSION_MAJOR=3
+ VERSION_MINOR=0
+-VERSION_POINT=0
++VERSION_POINT=4
+ CODE_STATUS="UNRELEASED"
+ dnl CODE_STATUS can be "alpha", "beta", or "stable", and will be