---------------------
PatchSet 5199 
Date: 2002/10/03 01:04:29
Author: rbcollins
Branch: rbcollins_cxxtest
Tag: (none) 
Log:
current state

Members: 
	.cvsignore:1.1->1.1.84.1 
	acinclude.m4:1.4->1.4.14.1 
	configure.in:1.70->1.70.2.1 
	include/Array.h:1.6->1.6.44.1 
	include/MemPool.h:1.2->1.2.32.1 
	include/Stack.h:1.5->1.5.44.1 
	include/config.h:1.5->1.5.52.1 
	include/hash.h:1.4->1.4.44.1 
	include/rfc2617.h:1.4->1.4.44.1 
	include/util.h:1.11->1.11.20.1 
	lib/Array.c:1.5->1.5.92.1 
	src/HttpRequest.c:1.7->1.7.64.1(DEAD) 
	src/HttpRequest.cc:1.1->1.1.2.1 
	src/IPInterception.c:1.4->1.4.6.1(DEAD) 
	src/IPInterception.cc:1.1->1.1.2.1 
	src/IPInterception.h:1.3->1.3.6.1 
	src/Makefile.am:1.29->1.29.2.1 
	src/access_log.c:1.19->1.19.2.1(DEAD) 
	src/access_log.cc:1.1->1.1.2.1 
	src/acl.c:1.60->1.60.2.1 
	src/auth_modules.sh:1.2->1.2.108.1 
	src/authenticate.c:1.27->1.27.2.1(DEAD) 
	src/authenticate.cc:1.1->1.1.2.1 
	src/authenticate.h:1.1->1.1.2.1 
	src/cache_cf.c:1.50->1.50.2.1(DEAD) 
	src/cache_cf.cc:1.1->1.1.2.1 
	src/cf.data.pre:1.83->1.83.2.1 
	src/client_side.c:1.76->1.76.2.1 
	src/client_side_reply.c:1.9->1.9.4.1 
	src/client_side_request.c:1.5->1.5.8.1 
	src/defines.h:1.25->1.25.6.1 
	src/enums.h:1.40->1.40.2.1 
	src/errorpage.c:1.23->1.23.6.1(DEAD) 
	src/errorpage.cc:1.1->1.1.2.1 
	src/external_acl.c:1.11->1.11.4.1 
	src/http.c:1.25->1.25.2.1(DEAD) 
	src/http.cc:1.1->1.1.2.1 
	src/logfile.c:1.7->1.7.14.1(DEAD) 
	src/logfile.cc:1.1->1.1.2.1 
	src/main.c:1.37->1.37.2.1(DEAD) 
	src/main.cc:1.1->1.1.2.1 
	src/mem.c:1.21->1.21.6.1 
	src/protos.h:1.63->1.63.2.1 
	src/redirect.c:1.10->1.10.14.1(DEAD) 
	src/redirect.cc:1.1->1.1.2.1 
	src/structs.h:1.70->1.70.2.1 
	src/typedefs.h:1.29->1.29.2.1 
	src/auth/Makefile.am:1.2->1.2.72.1 
	src/auth/basic/auth_basic.c:1.20->1.20.10.1(DEAD) 
	src/auth/basic/auth_basic.cc:1.1->1.1.2.1 
	src/auth/basic/auth_basic.h:1.4->1.4.44.1 
	src/auth/digest/auth_digest.c:1.16->1.16.14.1(DEAD) 
	src/auth/digest/auth_digest.cc:1.1->1.1.2.1 
	src/auth/digest/auth_digest.h:1.7->1.7.28.1 
	src/auth/ntlm/auth_ntlm.c:1.22->1.22.10.1(DEAD) 
	src/auth/ntlm/auth_ntlm.cc:1.1->1.1.2.1 
	src/auth/ntlm/auth_ntlm.h:1.8->1.8.40.1 

Index: squid/.cvsignore
===================================================================
RCS file: /cvsroot/squid-sf//squid/.cvsignore,v
retrieving revision 1.1
retrieving revision 1.1.84.1
diff -u -r1.1 -r1.1.84.1
--- squid/.cvsignore	10 Oct 2001 22:19:49 -0000	1.1
+++ squid/.cvsignore	3 Oct 2002 01:04:29 -0000	1.1.84.1
@@ -5,3 +5,4 @@
 aclocal.m4
 configure
 merge.log
+autom4te.cache
Index: squid/acinclude.m4
===================================================================
RCS file: /cvsroot/squid-sf//squid/acinclude.m4,v
retrieving revision 1.4
retrieving revision 1.4.14.1
diff -u -r1.4 -r1.4.14.1
--- squid/acinclude.m4	17 Jun 2002 21:02:55 -0000	1.4
+++ squid/acinclude.m4	3 Oct 2002 01:04:29 -0000	1.4.14.1
@@ -1,64 +1,14 @@
-dnl AC_CHECK_SIZEOF_SYSTYPE is as the standard AC_CHECK_SIZEOF macro
-dnl but also capable of checking the size of system defined types, not
-dnl only compiler defined types.
-dnl
-dnl AC_CHECK_SYSTYPE is the same thing but replacing AC_CHECK_TYPE
-dnl However AC_CHECK_TYPE is not by far as limited as AC_CHECK_SIZEOF
-dnl (it at least makes use of <sys/types.h>, <stddef.h> and <stdlib.h>)
-
-dnl AC_CHECK_SIZEOF_SYSTYPE(TYPE [, CROSS-SIZE])
-AC_DEFUN(AC_CHECK_SIZEOF_SYSTYPE,
-[changequote(<<, >>)dnl
-dnl The name to #define.
-define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
-dnl The cache variable name.
-define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl
-changequote([, ])dnl
-AC_MSG_CHECKING(size of $1)
-AC_CACHE_VAL(AC_CV_NAME,
-[AC_TRY_RUN([
-#include <stdio.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-#if HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#if HAVE_SYS_BITYPES_H
-#include <sys/bitypes.h>
-#endif
-int main()
-{
-  FILE *f=fopen("conftestval", "w");
-  if (!f) return(1);
-  fprintf(f, "%d\n", sizeof($1));
-  return(0);
-}
-], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$2], , , AC_CV_NAME=$2))])dnl
-AC_MSG_RESULT($AC_CV_NAME)
-AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME)
-undefine([AC_TYPE_NAME])dnl
-undefine([AC_CV_NAME])dnl
-])
-
-dnl AC_CHECK_SYSTYPE(TYPE, DEFAULT)
-AC_DEFUN(AC_CHECK_SYSTYPE,
-[AC_REQUIRE([AC_HEADER_STDC])dnl
-AC_MSG_CHECKING(for $1)
-AC_CACHE_VAL(ac_cv_type_$1,
-[AC_EGREP_CPP(dnl
-changequote(<<,>>)dnl
-<<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl
-changequote([,]), [
+dnl This encapsulates the nasty mess of headers we need to check when 
+dnl checking types.
+AC_DEFUN(SQUID_DEFAULT_INCLUDES,[[
 /* What a mess.. many systems have added the (now standard) bit types
  * in their own ways, so we need to scan a wide variety of headers to
  * find them..
+ * IMPORTANT: Keep include/squid_types.h syncronised with this list
  */
+#if HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif  
 #if STDC_HEADERS
 #include <stdlib.h>
 #include <stddef.h>
@@ -66,16 +16,13 @@
 #if HAVE_INTTYPES_H
 #include <inttypes.h>
 #endif
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
 #if HAVE_SYS_BITYPES_H
 #include <sys/bitypes.h>
 #endif
-], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl
-AC_MSG_RESULT($ac_cv_type_$1)
-if test $ac_cv_type_$1 = no; then
-  AC_DEFINE($1, $2)
-fi
-])
+]])     
 
+dnl and this is for AC_CHECK_SIZEOF
+AC_DEFUN(SQUID_DEFAULT_SIZEOF_INCLUDES,[
+#include <stdio.h>
+SQUID_DEFAULT_INCLUDES
+])
Index: squid/configure.in
===================================================================
RCS file: /cvsroot/squid-sf//squid/configure.in,v
retrieving revision 1.70
retrieving revision 1.70.2.1
diff -u -r1.70 -r1.70.2.1
--- squid/configure.in	2 Oct 2002 11:11:24 -0000	1.70
+++ squid/configure.in	3 Oct 2002 01:04:30 -0000	1.70.2.1
@@ -3,15 +3,17 @@
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.70 2002/10/02 11:11:24 squidadm Exp $
+dnl  $Id: configure.in,v 1.70.2.1 2002/10/03 01:04:30 rbcollins Exp $
 dnl
 dnl
 dnl
-AC_INIT(src/main.c)
+AC_INIT
+AC_PREREQ(2.53)
+AC_CONFIG_SRCDIR([src/main.c])
 AC_CONFIG_AUX_DIR(cfgaux)
-AM_INIT_AUTOMAKE(squid, 2.6-DEVEL)
+AM_INIT_AUTOMAKE(squid, 2.6-DEVEL-autoconf25)
 AM_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.70 $)dnl
+AC_REVISION($Revision: 1.70.2.1 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AM_MAINTAINER_MODE
 
@@ -22,6 +24,8 @@
 
 PRESET_CFLAGS="$CFLAGS"
 
+
+
 dnl Check for GNU cc
 AC_PROG_CC
 AC_LANG_C
@@ -65,12 +69,14 @@
 fi
 
 dnl Subsitutions
-AC_DEFINE_UNQUOTED(CACHE_HTTP_PORT, $CACHE_HTTP_PORT)
-AC_DEFINE_UNQUOTED(CACHE_ICP_PORT, $CACHE_ICP_PORT)
+AC_DEFINE_UNQUOTED(CACHE_HTTP_PORT, $CACHE_HTTP_PORT,
+[What default TCP port to use for HTTP listening?])
+AC_DEFINE_UNQUOTED(CACHE_ICP_PORT, $CACHE_ICP_PORT,
+[What default UDP port to use for ICP listening?])
 
-AC_DEFINE_UNQUOTED(CONFIG_HOST_TYPE, "$host")
+AC_DEFINE_UNQUOTED(CONFIG_HOST_TYPE, "$host",[Host type from configure])
 
-AC_DEFINE_UNQUOTED(SQUID_CONFIGURE_OPTIONS, "$ac_configure_args")
+AC_DEFINE_UNQUOTED(SQUID_CONFIGURE_OPTIONS, "$ac_configure_args", [configure command line used to configure Squid])
 
 dnl Check for GNU cc
 AC_PROG_CC
@@ -212,7 +218,7 @@
     ac_cv_header_gnumalloc_h="no"
     ac_cv_lib_malloc="no"
     ac_cv_enabled_dlmalloc="yes"
-    AC_DEFINE(USE_DLMALLOC, 1)
+    AC_DEFINE(USE_DLMALLOC, 1, [Compile & use the malloc package by Doug Lea])
 fi
 
 AC_SUBST(LIBDLMALLOC)
@@ -226,7 +232,7 @@
 [  --enable-debug-cbdata   Provide some debug information in cbdata],
 [ if test "$enableval" = "yes" ; then
     echo "cbdata debugging enabled"
-    AC_DEFINE(CBDATA_DEBUG)
+    AC_DEFINE(CBDATA_DEBUG,1,[Enable for cbdata debug information])
   fi
 ])
 
@@ -236,7 +242,7 @@
 dnl [  --enable-xmalloc-debug  Do some simple malloc debugging],
 dnl [ if test "$enableval" = "yes" ; then
 dnl     echo "Malloc debugging enabled"
-dnl     AC_DEFINE(XMALLOC_DEBUG)
+dnl     AC_DEFINE(XMALLOC_DEBUG,1,[Define to do simple malloc debugging])
 dnl   fi
 dnl ])
 
@@ -247,8 +253,8 @@
 dnl                           Detailed trace of memory allocations],
 dnl [ if test "$enableval" = "yes" ; then
 dnl     echo "Malloc debug trace enabled"
-dnl     AC_DEFINE(XMALLOC_TRACE)
-dnl     AC_DEFINE(XMALLOC_DEBUG)
+dnl     AC_DEFINE(XMALLOC_TRACE,1,[Define to have a detailed trace of memory allocations])
+dnl     AC_DEFINE(XMALLOC_DEBUG,1)
 dnl   fi
 dnl ])
 
@@ -257,7 +263,7 @@
                           Show malloc statistics in status page],
 [ if test "$enableval" = "yes" ; then
     echo "Malloc statistics enabled"
-    AC_DEFINE(XMALLOC_STATISTICS)
+    AC_DEFINE(XMALLOC_STATISTICS,1,[Define to have malloc statistics])
   fi
 ])
 
@@ -265,7 +271,7 @@
 [  --disable-carp           Disable CARP support],
 [ if test "$enableval" = "no" ; then
     echo "CARP disabled"
-    AC_DEFINE(USE_CARP, 0)
+    AC_DEFINE(USE_CARP, 0, [Cache Array Routing Protocol])
   else
     AC_DEFINE(USE_CARP, 1)
   fi
@@ -297,7 +303,8 @@
 [ aufs_io_threads=$withval ])
 if test "$aufs_io_threads"; then
     echo "With $aufs_io_threads aufs threads"
-    AC_DEFINE_UNQUOTED(AUFS_IO_THREADS,$aufs_io_threads)
+    AC_DEFINE_UNQUOTED(AUFS_IO_THREADS,$aufs_io_threads,
+    [Defines how many threads aufs uses for I/O])
 fi
 
 AC_ARG_WITH(pthreads,
@@ -441,7 +448,7 @@
 [  --enable-icmp           Enable ICMP pinging],
 [ if test "$enableval" = "yes" ; then
     echo "ICMP enabled"
-    AC_DEFINE(USE_ICMP)
+    AC_DEFINE(USE_ICMP,1)
     AM_CONDITIONAL(ENABLE_PINGER, true)
   fi
 ])
@@ -451,8 +458,8 @@
 [  --enable-delay-pools    Enable delay pools to limit bandwidth usage],
 [ if test "$enableval" = "yes" ; then
     echo "Delay pools enabled"
-    AC_DEFINE(DELAY_POOLS)
-    AM_CONDITIONAL(USE_DELAY_POOLS, true)
+    AC_DEFINE([DELAY_POOLS],1,[Traffic management via "delay pools".])
+    AM_CONDITIONAL(USE_DELAY_POOLS, true,)
   fi
 ])
 
@@ -462,7 +469,7 @@
 dnl [  --enable-mem-gen-trace  Do trace of memory stuff],
 dnl [ if test "$enableval" = "yes" ; then
 dnl     echo "Memory trace (to file) enabled"
-dnl     AC_DEFINE(MEM_GEN_TRACE)
+dnl     AC_DEFINE(MEM_GEN_TRACE,1,[Define for log file trace of mem alloc/free])
 dnl   fi    
 dnl ])     
 
@@ -470,7 +477,9 @@
 [  --enable-useragent-log  Enable logging of User-Agent header],
 [ if test "$enableval" = "yes" ; then
     echo "User-Agent logging enabled"
-    AC_DEFINE(USE_USERAGENT_LOG)
+    AC_DEFINE(USE_USERAGENT_LOG,1,[If you want to log User-Agent request header values, define this.
+    By default, they are written to useragent.log in the Squid log
+    directory.])
   fi
 ])
 
@@ -478,7 +487,9 @@
 [  --enable-referer-log    Enable logging of Referer header],
 [ if test "$enableval" = "yes" ; then
     echo "Referer logging enabled"
-    AC_DEFINE(USE_REFERER_LOG)
+    AC_DEFINE(USE_REFERER_LOG,1,[If you want to log Referer request header values, define this.
+    By default, they are written to referer.log in the Squid log
+    directory.])
   fi
 ])
 
@@ -486,7 +497,7 @@
 [  --disable-wccp          Disable Web Cache Coordination Protocol],
 [ if test "$enableval" = "no" ; then
     echo "Web Cache Coordination Protocol disabled"
-    AC_DEFINE(USE_WCCP, 0)
+    AC_DEFINE(USE_WCCP, 0,[Define to enable WCCP])
   else
     AC_DEFINE(USE_WCCP, 1)
   fi
@@ -497,7 +508,9 @@
                           Kill parent on shutdown],
 [ if test "$enableval" = "yes" ; then
     echo "Kill parent on shutdown"
-    AC_DEFINE(KILL_PARENT_OPT)
+    AC_DEFINE(KILL_PARENT_OPT,1,[A dangerous feature which causes Squid to kill its parent process
+    (presumably the RunCache script) upon receipt of SIGTERM or SIGINT.
+    Use with caution.])
   fi
 ])
 
@@ -506,7 +519,7 @@
 [  --enable-snmp           Enable SNMP monitoring],
 [ if test "$enableval" = "yes" ; then
     echo "SNMP monitoring enabled"
-    AC_DEFINE(SQUID_SNMP)
+    AC_DEFINE(SQUID_SNMP,1,[Define to enable SNMP monitoring of Squid])
     SNMPLIB='-L../snmplib -lsnmp'
     AM_CONDITIONAL(USE_SNMP, true)
     SNMP_MAKEFILE=./snmplib/Makefile
@@ -521,7 +534,8 @@
                           Make cachemgr.cgi default to this host],
 [  case $enableval in
    yes)
-       AC_DEFINE(CACHEMGR_HOSTNAME,[getfullhostname()])
+       AC_DEFINE(CACHEMGR_HOSTNAME,[getfullhostname()],
+       [If you are upset that the cachemgr.cgi form comes up with the hostname field blank, then define this to getfullhostname()])
        echo "Cachemgr default hostname == host where cachemgr runs"
        ;;
    no)
@@ -548,7 +562,7 @@
 	    sleep 10
 	    ;;
      esac
-     AC_DEFINE(USE_ARP_ACL)
+     AC_DEFINE(USE_ARP_ACL,1,[Define this to include code which lets you specify access control elements based on ethernet hardware addresses.  This code uses functions found in 4.4 BSD derviations (e.g. FreeBSD, ?).])
    fi
 ])
 
@@ -557,7 +571,7 @@
 [  --enable-htcp           Enable HTCP protocol],
 [ if test "$enableval" = "yes" ; then
     echo "HTCP enabled"
-    AC_DEFINE(USE_HTCP)
+    AC_DEFINE(USE_HTCP,1, [Define this to include code for the Hypertext Cache Protocol (HTCP)])
     AM_CONDITIONAL(ENABLE_HTCP, true)
   fi
 ])
@@ -568,7 +582,7 @@
 [  --enable-ssl            Enable ssl gatewaying support using OpenSSL],
 [ if test "$enableval" != "no"; then
     echo "SSL gatewaying using OpenSSL enabled"
-    AC_DEFINE(USE_SSL)
+    AC_DEFINE(USE_SSL,1,[Define this to include code for SSL encryption.])
     AM_CONDITIONAL(ENABLE_SSL, true)
     SSLLIB='-lssl -lcrypto'
     USE_OPENSSL=1
@@ -600,7 +614,7 @@
 
 if test -n "$USE_OPENSSL"; then
   echo "Using OpenSSL MD5 implementation"
-  AC_DEFINE(USE_OPENSSL)
+  AC_DEFINE(USE_OPENSSL,1,[Define this to make use of the OpenSSL libraries for MD5 calculation rather than Squid's own MD5 implementation or if building with SSL encryption (USE_SSL)])
   AM_CONDITIONAL(NEED_OWN_MD5, false)
   if test -z "$SSLLIB"; then
     SSLLIB="-lcrypto" # for MD5 routines
@@ -615,7 +629,7 @@
 [  --enable-forw-via-db    Enable Forw/Via database],
 [ if test "$enableval" = "yes" ; then
     echo "FORW-VIA enabled"
-    AC_DEFINE(FORW_VIA_DB)
+    AC_DEFINE(FORW_VIA_DB,1,[Enable Forw/Via database])
   fi
 ])
 
@@ -624,7 +638,7 @@
                           see http://www.squid-cache.org/FAQ/FAQ-16.html],
 [ if test "$enableval" = "yes" ; then
     echo "USE_CACHE_DIGESTS enabled"
-    AC_DEFINE(USE_CACHE_DIGESTS)
+    AC_DEFINE(USE_CACHE_DIGESTS,1,[Use Cache Digests for locating objects in neighbor caches.  This code is still semi-experimental.])
   fi
 ])
 
@@ -671,7 +685,7 @@
 [  --with-coss-membuf-size COSS membuf size (default 1048576 bytes) ],
 [  if test "$with_coss_membuf_size"; then
       echo "Setting COSS membuf size to $with_coss_membuf_size bytes"
-      AC_DEFINE_UNQUOTED(COSS_MEMBUF_SZ, $with_coss_membuf_size)
+      AC_DEFINE_UNQUOTED(COSS_MEMBUF_SZ, $with_coss_membuf_size,[Define if you want to set the COSS membuf size])
    fi
 ])
 
@@ -737,7 +751,7 @@
                           violate the HTTP protocol specification.],
 [ if test "$enableval" = "no" ; then
     echo "Disabling HTTP Violations"
-    AC_DEFINE(HTTP_VIOLATIONS, 0)
+    AC_DEFINE(HTTP_VIOLATIONS, 0,[By default (for now anyway) Squid includes options which allows the cache administrator to violate the HTTP protocol specification in terms of cache behaviour.  Setting this to '0' will disable such code.])
   else
     AC_DEFINE(HTTP_VIOLATIONS, 1)
   fi
@@ -750,7 +764,7 @@
                           using IP-Filter network address redirection.],
 [ if test "$enableval" = "yes" ; then
 	echo "IP-Filter Transparent Proxy enabled"
-	AC_DEFINE(IPF_TRANSPARENT)
+	AC_DEFINE(IPF_TRANSPARENT,1,[Enable support for Transparent Proxy on systems using IP-Filter address redirection. This provides "masquerading" support for non Linux system.])
 	IPF_TRANSPARENT="yes"
   fi
 ])
@@ -762,7 +776,7 @@
                           using PF network address redirection.],
 [ if test "$enableval" = "yes" ; then
 	echo "PF Transparent Proxy enabled"
-	AC_DEFINE(PF_TRANSPARENT)
+	AC_DEFINE(PF_TRANSPARENT,1,[Enable support for Transparent Proxy on systems using PF address redirection. This provides "masquerading" support for OpenBSD.])
 	PF_TRANSPARENT="yes"
   fi
 ])
@@ -773,7 +787,7 @@
                           Enable Transparent Proxy support for Linux 2.4.],
 [ if test "$enableval" = "yes" ; then
 	echo "Linux-Netfilter Transparent Proxy enabled"
-	AC_DEFINE(LINUX_NETFILTER)
+	AC_DEFINE(LINUX_NETFILTER,1,[Enable support for Transparent Proxy on Linux 2.4 systems])
 	LINUX_NETFILTER="yes"
   fi
 ])
@@ -798,7 +812,7 @@
 			  Useful for hackers only.],
 [ if test "$enableval" = "yes" ; then
 	echo "Leak-Finding enabled"
-	AC_DEFINE(USE_LEAKFINDER)
+	AC_DEFINE(USE_LEAKFINDER,1,[Enable code for assisting in finding memory leaks.  Hacker stuff only.])
 	USE_LEAKFINDER="yes"
 	AM_CONDITIONAL(MAKE_LEAKFINDER, true)
   fi
@@ -810,7 +824,7 @@
                           Ident (RFC 931) lookups.],
 [ if test "$enableval" = "no" ; then
     echo "Disabling Ident Lookups"
-    AC_DEFINE(USE_IDENT, 0)
+    AC_DEFINE(USE_IDENT, 0,[Compile in support for Ident (RFC 931) lookups?  Enabled by default.])
   else
     AC_DEFINE(USE_IDENT, 1)
   fi
@@ -840,7 +854,7 @@
                           filesystem inodes than unlink..],
 [ if test "$enableval" = "yes" ; then
     echo "Enabling truncate instead of unlink"
-    AC_DEFINE(USE_TRUNCATE)
+    AC_DEFINE(USE_TRUNCATE,1,[Do we want to use truncate(2) or unlink(2)?])
   fi
 ])
 
@@ -854,30 +868,10 @@
                           does not reject _ in hostnames...],
 [ if test "$enableval" = "yes" ; then
     echo "Enabling the use of underscores in host names"
-    AC_DEFINE(ALLOW_HOSTNAME_UNDERSCORES, 1)
+    AC_DEFINE(ALLOW_HOSTNAME_UNDERSCORES, 1,[Allow underscores in host names])
   fi
 ])
 
-dnl Select Default hosts file location
-AC_ARG_ENABLE(default-hostsfile,
-[  --enable-default-hostsfile=path
-                          Select default location for hosts file.
-                          See hosts_file directive in squid.conf for details],
-[
-    if test "$enableval" != "none" ; then
-    	if test -f $enableval; then
-	    OPT_DEFAULT_HOSTS=$enableval
-    	else
-	    echo "Warning Unable to find $enableval"
-	    sleep 5
-	fi
-    else
-	OPT_DEFAULT_HOSTS="none"    
-    fi
-    echo "Default hosts file set to: $enableval"
-],[OPT_DEFAULT_HOSTS="/etc/hosts"])
-AC_SUBST(OPT_DEFAULT_HOSTS)
-
 
 dnl Select auth schemes modules to build
 AC_ARG_ENABLE(auth,
@@ -1046,7 +1040,7 @@
                           Authentication steps can allow squid to still authenticate
                           the user.],
 [ if test "$enableval" = "yes" ; then
-    AC_DEFINE(NTLM_FAIL_OPEN)
+    AC_DEFINE(NTLM_FAIL_OPEN,1,[Define if NTLM is allowed to fail gracefully when a helper has problems. WARNING: This has security implications. DO NOT enable unless you KNOW you need it.])
   fi
 ])
 
@@ -1090,7 +1084,7 @@
 [  --disable-mempools      Disable memPools],
 [ if test "$enableval" = "no" ; then
     echo "memPools disabled"
-    AC_DEFINE(DISABLE_POOLS, 1)
+    AC_DEFINE(DISABLE_POOLS, 1, [Define if you have problems with memPools and want to disable Pools])
   else
     AC_DEFINE(DISABLE_POOLS, 0)
   fi
@@ -1111,7 +1105,7 @@
 ])
 if test "$use_unlinkd" = "yes"; then
     echo "unlinkd enabled"
-    AC_DEFINE(USE_UNLINKD)
+    AC_DEFINE(USE_UNLINKD,1,[Define this if unlinkd is required (strongly recommended for ufs storage type)])
     AM_CONDITIONAL(ENABLE_UNLINKD, true)
 else
     echo "unlinkd disabled"
@@ -1123,7 +1117,7 @@
 [  --enable-stacktraces    Enable automatic call backtrace on fatal errors],
 [ if test "$enableval" = "yes" ; then
     echo "Enabling automatic stack backtraces on fatal errors"
-    AC_DEFINE(PRINT_STACK_TRACE, 1)
+    AC_DEFINE(PRINT_STACK_TRACE, 1,[Print stacktraces on fatal errors])
   fi
 ])
 
@@ -1158,7 +1152,7 @@
                           that adds custom HTTP headers to the requests.],
 [ if test "$enableval" = "yes" ; then
     echo "Enabling support for X-Accelerator-Vary"
-    AC_DEFINE(X_ACCELERATOR_VARY, 1)
+    AC_DEFINE(X_ACCELERATOR_VARY, 1, [Enable support for the X-Accelerator-Vary HTTP header])
   fi
 ])
 
@@ -1318,72 +1312,48 @@
     ac_cv_have_ansi_prototypes="no")
 ])
 if test $ac_cv_have_ansi_prototypes = "yes" ; then
-  AC_DEFINE(HAVE_ANSI_PROTOTYPES)
+  AC_DEFINE(HAVE_ANSI_PROTOTYPES,1,[Define if your compiler supports prototyping])
 fi
 
-AC_CACHE_CHECK(for tm->tm_gmtoff,ac_cv_have_tm_gmoff, [
-  AC_TRY_COMPILE([#include <time.h>
-#include <sys/time.h>],
-    [struct tm foo;
-      foo.tm_gmtoff = 0;],
-    ac_cv_have_tm_gmoff="yes",
-    ac_cv_have_tm_gmoff="no")
+AC_STRUCT_TM
+AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[
+#if TM_IN_SYS_TIME
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#elif HAVE_TIME_H
+#include <time.h>
+#endif
 ])
-if test $ac_cv_have_tm_gmoff = "yes" ; then
-  AC_DEFINE(HAVE_TM_GMTOFF)
-fi
 
-AC_CACHE_CHECK(for struct mallinfo,ac_cv_have_struct_mallinfo, [
-  AC_TRY_COMPILE([#include <sys/types.h>
+AC_CHECK_TYPE(struct mallinfo,AC_DEFINE(HAVE_STRUCT_MALLINFO,1,[The system provides struct mallinfo]),,[
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 #if HAVE_MALLOC_H
 #include <malloc.h>
-#endif],
-    [struct mallinfo foo;
-    foo.arena = 0;
-    foo.ordblks = 0;
-    foo.smblks = 0;
-    foo.hblks = 0;
-    foo.hblkhd = 0;
-    foo.uordblks = 0;
-    foo.fordblks = 0;
-    foo.keepcost = 0;],
-    ac_cv_have_struct_mallinfo="yes",
-    ac_cv_have_struct_mallinfo="no")
-])
-if test $ac_cv_have_struct_mallinfo = "yes" ; then
-  AC_DEFINE(HAVE_STRUCT_MALLINFO)
-fi
-
-AC_CACHE_CHECK(for extended mallinfo,ac_cv_have_ext_mallinfo, [
-  AC_TRY_COMPILE([#include <sys/types.h>
-#include <malloc.h>],
-    [struct mallinfo foo;
-      foo.mxfast = 0;],
-    ac_cv_have_ext_mallinfo="yes",
-    ac_cv_have_ext_mallinfo="no")
-])
-if test $ac_cv_have_ext_mallinfo = "yes" ; then
-  AC_DEFINE(HAVE_EXT_MALLINFO)
-fi
+#endif])
 
-AC_CACHE_CHECK(for struct rusage,ac_cv_have_struct_rusage, [
-  AC_TRY_COMPILE([
+AC_CHECK_MEMBERS([struct mallinfo.mxfast],,,[
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif])
+
+AC_CHECK_TYPE(struct rusage,AC_DEFINE(HAVE_STRUCT_RUSAGE,1,[The system provides struct rusage]),,[
 #if HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
 #if HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
-#endif],
-    [struct rusage R;],
-    ac_cv_have_struct_rusage="yes",
-    ac_cv_have_struct_rusage="no")
-])
-if test $ac_cv_have_struct_rusage = "yes" ; then
-  AC_DEFINE(HAVE_STRUCT_RUSAGE)
-fi
+#endif])
 
-AC_CACHE_CHECK(for ip->ip_hl, ac_cv_have_ip_hl, [
-  AC_TRY_COMPILE([#include <sys/types.h>
+AC_CHECK_MEMBERS([struct iphdr.ip_hl],,,[
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -1394,120 +1364,118 @@
 #ifndef __CYGWIN__
 #define iphdr ip
 #endif
-#endif],
-    [struct iphdr ip;
-      ip.ip_hl= 0;],
-    ac_cv_have_ip_hl="yes",
-    ac_cv_have_ip_hl="no")
-])
-if test $ac_cv_have_ip_hl = "yes" ; then
-  AC_DEFINE(HAVE_IP_HL)
-fi
+#endif])
 
 dnl Check for typedefs
 AC_CHECK_SIZEOF(void *)
-AC_CHECK_SIZEOF(short)
-AC_CHECK_SIZEOF(int)
-AC_CHECK_SIZEOF(long)
-AC_CHECK_SIZEOF(long long)
-AC_CHECK_SIZEOF_SYSTYPE(__int64)
-AC_CHECK_SIZEOF_SYSTYPE(int16_t)
-AC_CHECK_SIZEOF_SYSTYPE(uint16_t)
-AC_CHECK_SIZEOF_SYSTYPE(u_int16_t)
-AC_CHECK_SIZEOF_SYSTYPE(int32_t)
-AC_CHECK_SIZEOF_SYSTYPE(uint32_t)
-AC_CHECK_SIZEOF_SYSTYPE(u_int32_t)
-AC_CHECK_SIZEOF_SYSTYPE(int64_t)
-AC_CHECK_SIZEOF_SYSTYPE(uint64_t)
-AC_CHECK_SIZEOF_SYSTYPE(u_int64_t)
-
-dnl int16_t
-if test "x$ac_cv_sizeof_short" = "x2"; then
-	AC_CHECK_SYSTYPE(int16_t,short)
-elif test "x$ac_cv_sizeof_int" = "x2"; then
-	AC_CHECK_SYSTYPE(int16_t,int)
-fi
-dnl u_int16t_t
-if test "x$ac_cv_sizeof_uint16_t" = "x2"; then
-	AC_CHECK_SYSTYPE(u_int16_t,uint16_t)
-elif test "x$ac_cv_sizeof_short" = "x2"; then
-	AC_CHECK_SYSTYPE(u_int16_t,unsigned short)
-elif test "x$ac_cv_sizeof_int" = "x2"; then
-	AC_CHECK_SYSTYPE(u_int16_t,unsigned int)
-fi
-dnl int32_t
-if test "x$ac_cv_sizeof_int" = "x4"; then
-	AC_CHECK_SYSTYPE(int32_t,int)
-elif "x$ac_cv_sizeof_long" = "x4"; then
-	AC_CHECK_SYSTYPE(int32_t,long)
-fi
-dnl u_int32_t
-if test "x$ac_cv_sizeof_uint32_t" = "x4"; then
-	AC_CHECK_SYSTYPE(u_int32_t,uint32_t)
-elif test "x$ac_cv_sizeof_int" = "x4"; then
-	AC_CHECK_SYSTYPE(u_int32_t,unsigned int)
-elif test "x$ac_cv_sizeof_long" = "x4"; then
-	AC_CHECK_SYSTYPE(u_int32_t,unsigned long)
-fi
-dnl int64_t
-if test "x$ac_cv_sizeof_long" = "x8"; then
-	AC_CHECK_SYSTYPE(int64_t,long)
-elif test "x$ac_cv_sizeof_long_long" = "x8"; then
-	AC_CHECK_SYSTYPE(int64_t,long long)
-elif test "x$ac_cv_sizeof___int64" = "x8"; then
-	AC_CHECK_SYSTYPE(int64_t,__int64)
-fi
-dnl u_int64_t
-if test "x$ac_cv_sizeof_uint64_t" = "x8"; then
-	AC_CHECK_SYSTYPE(u_int64_t,uint64_t)
-elif test "x$ac_cv_sizeof_long" = "x8"; then
-	AC_CHECK_SYSTYPE(u_int64_t,unsigned long)
-elif test "x$ac_cv_sizeof_long_long" = "x8"; then
-	AC_CHECK_SYSTYPE(u_int64_t,unsigned long long)
-elif test "x$ac_cv_sizeof___int64" = "x8"; then
-	AC_CHECK_SYSTYPE(int64_t,unsigned __int64)
-fi
-
-AC_CHECK_TYPE(pid_t, int)
-AC_CHECK_TYPE(size_t, unsigned int)
-AC_CHECK_TYPE(ssize_t, int)
-AC_CHECK_TYPE(off_t, int)
-AC_CHECK_TYPE(mode_t, u_short)
-AC_CHECK_TYPE(fd_mask, int)
 
-AC_CHECK_SIZEOF_SYSTYPE(off_t, 4)
-AC_CHECK_SIZEOF_SYSTYPE(size_t, 4)
+dnl 16 bit integers - int16_t and u_int16_t
+dnl if this is defined we trust it to be 16 bits
+AC_CHECK_TYPE(int16_t,
+  AC_DEFINE(HAVE_INT16_T,1,[int16_t is defined in system headers]),
+  ,SQUID_DEFAULT_INCLUDES)
+
+dnl fallback #1
+AC_CHECK_TYPE(short,[
+  AC_CHECK_SIZEOF(short,,SQUID_DEFAULT_INCLUDES)
+  AC_DEFINE(HAVE_SHORT,1,[short is defined in system headers])
+  ],,SQUID_DEFAULT_INCLUDES)
+
+dnl fallback #2
+AC_CHECK_TYPE(int,[
+  AC_CHECK_SIZEOF(int,,SQUID_DEFAULT_INCLUDES)
+  AC_DEFINE(HAVE_INT,1,[int is defined in system headers])
+  ],,SQUID_DEFAULT_INCLUDES)
+
+dnl unsigned 16 bit ints - u_int16_t
+dnl if this is defined we trust it to be 16 bits
+AC_CHECK_TYPE(u_int16_t,
+  AC_DEFINE(HAVE_U_INT16_T,1,[u_int16_t is defined in system headers]), 
+  ,SQUID_DEFAULT_INCLUDES)
+
+dnl fallback #1
+dnl if this is defined we trust it to be 16 bits
+AC_CHECK_TYPE(uint16_t,
+  AC_DEFINE(HAVE_UINT16_T,1,[uint16_t is defined in system headers]),     
+  ,SQUID_DEFAULT_INCLUDES)
+
+dnl 32 bit signed int - int32_t
+dnl if this is defined we trust it to be 32 bits
+AC_CHECK_TYPE(int32_t,
+  AC_DEFINE(HAVE_INT32_T,1,[int32_t is defined in system headers]),
+  ,SQUID_DEFAULT_INCLUDES)
+
+dnl fallback #1
+AC_CHECK_TYPE(long,[
+  AC_CHECK_SIZEOF(long,,SQUID_DEFAULT_INCLUDES)
+  AC_DEFINE(HAVE_LONG,1,[long is defined in system headers])
+  ],,SQUID_DEFAULT_INCLUDES)
+
+dnl 32 bit unsigned int - u_int32_t
+dnl if this is defined we trust it to be 32 bits
+AC_CHECK_TYPE(u_int32_t,
+  AC_DEFINE(HAVE_U_INT32_T,1,[u_int32_t is defined in system headers]),
+  ,SQUID_DEFAULT_INCLUDES)
+
+dnl fallback #1
+dnl if this is defined we trust it to be 32 bits
+AC_CHECK_TYPE(uint32_t,
+  AC_DEFINE(HAVE_UINT32_T,1,[uint32_t is defined in system headers]),
+    ,SQUID_DEFAULT_INCLUDES)
+
+dnl 64 bit signed - int64_t
+dnl if this is defind we trust it to be 64 bits
+AC_CHECK_TYPE(int64_t,
+  AC_DEFINE(HAVE_INT64_T,1,[int64_t is defined in system headers]),
+  ,SQUID_DEFAULT_INCLUDES)
+
+dnl fallback #1
+dnl if this is defind we trust it to be 64 bits
+AC_CHECK_TYPE(__int64,
+  AC_DEFINE(HAVE___INT64,1,[__int64 is defined in system headers]),
+  ,SQUID_DEFAULT_INCLUDES)
+
+dnl fallback #2
+AC_CHECK_TYPE(long long,[
+  AC_CHECK_SIZEOF(long long,,SQUID_DEFAULT_INCLUDES)
+  AC_DEFINE(HAVE_LONG_LONG,1,[long long is defined in system headers])
+  ],,SQUID_DEFAULT_INCLUDES)
+
+dnl 64 bit unsigned - u_int64_t
+dnl if this is defind we trust it to be 64 bits
+AC_CHECK_TYPE(u_int64_t,
+  AC_DEFINE(HAVE_U_INT64_T,1,[u_int64_t is defined in system headers]),
+  ,SQUID_DEFAULT_INCLUDES)
+
+dnl fallback #1
+dnl if this is defind we trust it to be 64 bits
+AC_CHECK_TYPE(uint64_t,
+  AC_DEFINE(HAVE_UINT64_T,1,[uint64_t is defined in system headers]),
+  ,SQUID_DEFAULT_INCLUDES)
+
+AC_CHECK_TYPE(pid_t, AC_DEFINE(HAVE_PID_T,1,[pid_t is defined by the system headers]),,SQUID_DEFAULT_INCLUDES)
+AC_CHECK_TYPE(size_t, [AC_CHECK_SIZEOF(size_t,,SQUID_DEFAULT_INCLUDES)
+  AC_DEFINE(HAVE_SIZE_T,1,[size_t is defined by the system headers])],,SQUID_DEFAULT_INCLUDES)
+AC_CHECK_TYPE(ssize_t, AC_DEFINE(HAVE_SSIZE_T,1,[ssize_t is defined by the system headers]),,SQUID_DEFAULT_INCLUDES)
+AC_CHECK_TYPE(off_t,[ AC_CHECK_SIZEOF(off_t,,SQUID_DEFAULT_INCLUDES)
+  AC_DEFINE(HAVE_OFF_T,1,[off_t is defined by the system headers])],,SQUID_DEFAULT_INCLUDES)
+AC_CHECK_TYPE(mode_t, AC_DEFINE(HAVE_MODE_T,1,[mode_t is defined by the system headers]),,SQUID_DEFAULT_INCLUDES)
+AC_CHECK_TYPE(fd_mask,  AC_DEFINE(HAVE_FD_MASK,1,[fd_mask is defined by the system headers]),,SQUID_DEFAULT_INCLUDES)
 
 dnl Check for special functions
 AC_FUNC_ALLOCA
 
-
-dnl Check for type in sys/socket.h
-AC_CACHE_CHECK(for socklen_t, ac_cv_type_socklen_t, [
-  AC_EGREP_CPP([socklen_t[^a-zA-Z_0-9]], [#include <sys/types.h>
+AC_CHECK_TYPE(socklen_t,AC_DEFINE(HAVE_SOCKLEN_T,1,[socklen_t is defined by the system headers]),,[
+#include <sys/types.h>
 #include <sys/socket.h>
 #if STDC_HEADERS
 #include <stdlib.h>
 #include <stddef.h>
-#endif],
-    ac_cv_type_socklen_t=yes,
-    ac_cv_type_socklen_t=no)
-])
-if test $ac_cv_type_socklen_t = no; then
-  AC_DEFINE(socklen_t, int)
-fi
+#endif])
 
-dnl Check for mtyp_t in some headers
-AC_CACHE_CHECK(for mtyp_t, ac_cv_type_mtyp_t, [
-  AC_EGREP_CPP([mtyp_t[^a-zA-Z_0-9]], [#include <sys/types.h>
+AC_CHECK_TYPE(mtyp_t,AC_DEFINE(HAVE_MTYP_T,1,[mtyp_t is defined by the system headers]),,[#include <sys/types.h>
 #include <sys/ipc.h>
-#include <sys/msg.h>],
-    ac_cv_type_mtyp_t=yes,
-    ac_cv_type_mtyp_t=no)
-])
-if test $ac_cv_type_mtyp_t = no; then
-  AC_DEFINE(mtyp_t, long)
- fi
+#include <sys/msg.h>])
 
 dnl Check for needed libraries
 AC_CHECK_LIB(nsl, main)
@@ -1527,7 +1495,7 @@
 ],
         squid_cv_unixsocket=yes,squid_cv_unixsocket=no)])
 if test x"$squid_cv_unixsocket" = x"yes"; then
-   AC_DEFINE(HAVE_UNIXSOCKET)
+   AC_DEFINE(HAVE_UNIXSOCKET,1,[Do we have unix sockets? (required for the winbind ntlm helper])
 fi
 dnl end rip
 
@@ -1638,13 +1606,13 @@
 		;;
 	*m88k*)
 		CFLAGS="$CFLAGS -D_SQUID_MOTOROLA_"
-		AC_DEFINE(GETTIMEOFDAY_NO_TZP)
+		AC_DEFINE(GETTIMEOFDAY_NO_TZP,1,[If gettimeofday is known to take only one argument])
 		;;
 	[*-*-solaris2.[0-4]])
-		AC_DEFINE(GETTIMEOFDAY_NO_TZP)
+		AC_DEFINE(GETTIMEOFDAY_NO_TZP,1)
 		;;
 	[*-sony-newsos[56]*])
-		AC_DEFINE(GETTIMEOFDAY_NO_TZP)
+		AC_DEFINE(GETTIMEOFDAY_NO_TZP,1)
 		;;
 esac
 
@@ -1771,18 +1739,18 @@
 
 if test "$ac_cv_func_poll" = "yes" ; then
         SELECT_TYPE="poll"
-        AC_DEFINE(USE_POLL)
+        AC_DEFINE(USE_POLL,1,[Use poll() for the IO loop])
 elif test "$ac_cv_func_select" = "yes" ; then
         SELECT_TYPE="select"
-        AC_DEFINE(USE_SELECT)
+        AC_DEFINE(USE_SELECT,1,[Use select() for the IO loop])
 elif test "$ac_cv_func_kqueue" = "yes" ; then
 	SELECT_TYPE="kqueue"
-	AC_DEFINE(USE_KQUEUE)
+	AC_DEFINE(USE_KQUEUE,1,[Use kqueue() for the IO loop])
 else
         echo "Eep!  Can't find poll, kqueue or select!"
         echo "I'll try select and hope for the best."
         SELECT_TYPE="select"
-        AC_DEFINE(USE_SELECT)
+        AC_DEFINE(USE_SELECT,1)
 fi
 echo "Using ${SELECT_TYPE} for select loop."
 
@@ -1804,7 +1772,7 @@
   ],ac_cv_func_setresuid="yes",ac_cv_func_setresuid="no")
 )
 if test "$ac_cv_func_setresuid" = "yes" ; then
-  AC_DEFINE(HAVE_SETRESUID)
+  AC_DEFINE(HAVE_SETRESUID,1,[Yay! Another Linux brokenness.  Its not good enough to know that setresuid() exists, because RedHat 5.0 declare setresuid() but doesn't implement it.])
 fi
 
 AM_CONDITIONAL(NEED_OWN_SNPRINTF, false)
@@ -1909,7 +1877,7 @@
 if test "$USE_GNUREGEX" = "yes"; then
 	REGEXLIB="-lregex"
 	LIBREGEX="libregex.a"
-	AC_DEFINE(USE_GNUREGEX)
+	AC_DEFINE(USE_GNUREGEX,1,[Define if we should use GNU regex])
 fi
 AC_SUBST(REGEXLIB)
 AC_SUBST(LIBREGEX)
@@ -1948,7 +1916,7 @@
 DEFAULT_FD_SETSIZE=256,
 DEFAULT_FD_SETSIZE=256)
 AC_MSG_RESULT($DEFAULT_FD_SETSIZE)
-AC_DEFINE_UNQUOTED(DEFAULT_FD_SETSIZE, $DEFAULT_FD_SETSIZE)
+AC_DEFINE_UNQUOTED(DEFAULT_FD_SETSIZE, $DEFAULT_FD_SETSIZE, [Default FD_SETSIZE value])
 
 
 dnl Not cached since people are likely to tune this
@@ -2057,11 +2025,11 @@
 	exit(0);
 }
 ],
-SQUID_UDP_SO_SNDBUF=`cat conftestval`,
-SQUID_UDP_SO_SNDBUF=16384,
-SQUID_UDP_SO_SNDBUF=16384)
-AC_MSG_RESULT($SQUID_UDP_SO_SNDBUF)
-AC_DEFINE_UNQUOTED(SQUID_UDP_SO_SNDBUF, $SQUID_UDP_SO_SNDBUF)
+SQUID_DETECT_UDP_SO_SNDBUF=`cat conftestval`,
+SQUID_DETECT_UDP_SO_SNDBUF=16384,
+SQUID_DETECT_UDP_SO_SNDBUF=16384)
+AC_MSG_RESULT($SQUID_DETECT_UDP_SO_SNDBUF)
+AC_DEFINE_UNQUOTED(SQUID_DETECT_UDP_SO_SNDBUF, $SQUID_DETECT_UDP_SO_SNDBUF,[UDP send buffer size])
 
 dnl Not cached since people are likely to tune this
 AC_MSG_CHECKING(Default UDP receive buffer size)
@@ -2083,11 +2051,11 @@
 	exit(0);
 }
 ],
-SQUID_UDP_SO_RCVBUF=`cat conftestval`,
-SQUID_UDP_SO_RCVBUF=16384,
-SQUID_UDP_SO_RCVBUF=16384)
-AC_MSG_RESULT($SQUID_UDP_SO_RCVBUF)
-AC_DEFINE_UNQUOTED(SQUID_UDP_SO_RCVBUF, $SQUID_UDP_SO_RCVBUF)
+SQUID_DETECT_UDP_SO_RCVBUF=`cat conftestval`,
+SQUID_DETECT_UDP_SO_RCVBUF=16384,
+SQUID_DETECT_UDP_SO_RCVBUF=16384)
+AC_MSG_RESULT($SQUID_DETECT_UDP_SO_RCVBUF)
+AC_DEFINE_UNQUOTED(SQUID_DETECT_UDP_SO_RCVBUF, $SQUID_DETECT_UDP_SO_RCVBUF,[UDP receive buffer size])
 
 dnl Not cached since people are likely to tune this
 AC_MSG_CHECKING(Default TCP send buffer size)
@@ -2113,7 +2081,7 @@
 SQUID_TCP_SO_SNDBUF=16384,
 SQUID_TCP_SO_SNDBUF=16384)
 AC_MSG_RESULT($SQUID_TCP_SO_SNDBUF)
-AC_DEFINE_UNQUOTED(SQUID_TCP_SO_SNDBUF, $SQUID_TCP_SO_SNDBUF)
+AC_DEFINE_UNQUOTED(SQUID_TCP_SO_SNDBUF, $SQUID_TCP_SO_SNDBUF,[TCP send buffer size])
 
 dnl Not cached since people are likely to tune this
 AC_MSG_CHECKING(Default TCP receive buffer size)
@@ -2139,7 +2107,7 @@
 SQUID_TCP_SO_RCVBUF=16384,
 SQUID_TCP_SO_RCVBUF=16384)
 AC_MSG_RESULT($SQUID_TCP_SO_RCVBUF)
-AC_DEFINE_UNQUOTED(SQUID_TCP_SO_RCVBUF, $SQUID_TCP_SO_RCVBUF)
+AC_DEFINE_UNQUOTED(SQUID_TCP_SO_RCVBUF, $SQUID_TCP_SO_RCVBUF,[TCP receive buffer size])
 
 AC_CACHE_CHECK(if sys_errlist is already defined, ac_cv_needs_sys_errlist,
   AC_TRY_COMPILE([#include <stdio.h>],[char *s = sys_errlist;],
@@ -2147,14 +2115,14 @@
     ac_cv_needs_sys_errlist="yes")
 )
 if test "$ac_cv_needs_sys_errlist" = "yes" ; then
-  AC_DEFINE(NEED_SYS_ERRLIST)
+  AC_DEFINE(NEED_SYS_ERRLIST,1,[If we need to declare sys_errlist[] as external])
 fi
 
 dnl Not cached since people are likely to change this
 AC_MSG_CHECKING(for libresolv _dns_ttl_ hack)
 AC_TRY_LINK(extern int _dns_ttl_;,return _dns_ttl_;,
 [AC_MSG_RESULT(yes)
-AC_DEFINE(LIBRESOLV_DNS_TTL_HACK)],
+AC_DEFINE(LIBRESOLV_DNS_TTL_HACK,1,[If libresolv.a has been hacked to export _dns_ttl_])],
 AC_MSG_RESULT(no))
 
 AC_MSG_CHECKING(if inet_ntoa() actually works)
@@ -2182,7 +2150,7 @@
 else
 	AC_MSG_RESULT("no")
 	echo "Will use our own inet_ntoa()."
-	LIBOBJS="$LIBOBJS inet_ntoa.o"
+	AC_LIBOBJ(inet_ntoa)
 #	echo "WARNING: This looks bad, and probably prevents Squid from working."
 #	echo "         If you're on IRIX and using GCC 2.8, you probably need"
 #	echo "         to use the IRIX C compiler instead."
@@ -2207,7 +2175,7 @@
   ac_cv_func_statvfs=no)
 AC_MSG_RESULT($ac_cv_func_statvfs)
 if test "$ac_cv_func_statvfs" = "yes" ; then
-  AC_DEFINE(HAVE_STATVFS)
+  AC_DEFINE(HAVE_STATVFS,1,[If your system has statvfs(), and if it actually works!])
 fi
 fi
 
@@ -2233,7 +2201,7 @@
 ac_cv_have_res_nsaddr_list="yes",
 ac_cv_have_res_nsaddr_list="no"))
 if test $ac_cv_have_res_nsaddr_list = "yes" ; then
-  AC_DEFINE(HAVE_RES_NSADDR_LIST)
+  AC_DEFINE(HAVE_RES_NSADDR_LIST,1,[If _res structure has nsaddr_list member])
 fi
 
 if test $ac_cv_have_res_nsaddr_list = "no" ; then
@@ -2259,7 +2227,7 @@
 ac_cv_have_res_ns_list="yes",
 ac_cv_have_res_ns_list="no"))
 if test $ac_cv_have_res_ns_list = "yes" ; then
-  AC_DEFINE(HAVE_RES_NS_LIST)
+  AC_DEFINE(HAVE_RES_NS_LIST,1,[If _res structure has ns_list member])
 fi
 fi
 
@@ -2318,7 +2286,7 @@
 dnl     src/fs/ufs/Makefile \
 dnl     src/repl/heap/Makefile \
 dnl     src/repl/lru/Makefile \
-AC_OUTPUT([\
+AC_CONFIG_FILES([\
 	Makefile \
 	lib/Makefile \
 	scripts/Makefile \
@@ -2370,3 +2338,4 @@
 	helpers/external_acl/wbinfo_group/Makefile \
 	helpers/external_acl/winbind_group/Makefile \
 ])
+AC_OUTPUT
Index: squid/include/Array.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/Array.h,v
retrieving revision 1.6
retrieving revision 1.6.44.1
diff -u -r1.6 -r1.6.44.1
--- squid/include/Array.h	9 Oct 2001 21:17:59 -0000	1.6
+++ squid/include/Array.h	3 Oct 2002 01:04:32 -0000	1.6.44.1
@@ -1,5 +1,5 @@
 /*
- * $Id: Array.h,v 1.6 2001/10/09 21:17:59 squidadm Exp $
+ * $Id: Array.h,v 1.6.44.1 2002/10/03 01:04:32 rbcollins Exp $
  *
  * AUTHOR: Alex Rousskov
  *
@@ -47,7 +47,7 @@
 extern void arrayInit(Array * s);
 extern void arrayClean(Array * s);
 extern void arrayDestroy(Array * s);
-extern void arrayAppend(Array * s, void *obj);
+SQUIDCEXTERN void arrayAppend(Array * s, void *obj);
 extern void arrayPreAppend(Array * s, int app_count);
 
 
Index: squid/include/MemPool.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/Attic/MemPool.h,v
retrieving revision 1.2
retrieving revision 1.2.32.1
diff -u -r1.2 -r1.2.32.1
--- squid/include/MemPool.h	6 Apr 2002 11:34:49 -0000	1.2
+++ squid/include/MemPool.h	3 Oct 2002 01:04:32 -0000	1.2.32.1
@@ -141,29 +141,29 @@
 /* memPools */
 
 /* Allocator API */
-extern MemPool *memPoolCreate(const char *label, size_t obj_size);
-extern void *memPoolAlloc(MemPool * pool);
-extern void memPoolFree(MemPool * pool, void *obj);
-extern void memPoolDestroy(MemPool ** pool);
-
-extern MemPoolIterator * memPoolIterate(void);
-extern MemPool * memPoolIterateNext(MemPoolIterator * iter);
-extern void memPoolIterateDone(MemPoolIterator ** iter);
+SQUIDCEXTERN MemPool *memPoolCreate(const char *label, size_t obj_size);
+SQUIDCEXTERN void *memPoolAlloc(MemPool * pool);
+SQUIDCEXTERN void memPoolFree(MemPool * pool, void *obj);
+SQUIDCEXTERN void memPoolDestroy(MemPool ** pool);
+
+SQUIDCEXTERN MemPoolIterator * memPoolIterate(void);
+SQUIDCEXTERN MemPool * memPoolIterateNext(MemPoolIterator * iter);
+SQUIDCEXTERN void memPoolIterateDone(MemPoolIterator ** iter);
 
 /* Tune API */
-extern void memPoolSetChunkSize(MemPool * pool, size_t chunksize);
-extern void memPoolSetIdleLimit(size_t new_idle_limit);
+SQUIDCEXTERN void memPoolSetChunkSize(MemPool * pool, size_t chunksize);
+SQUIDCEXTERN void memPoolSetIdleLimit(size_t new_idle_limit);
 
 /* Stats API */
-extern int memPoolGetStats(MemPoolStats * stats, MemPool * pool);
-extern int memPoolGetGlobalStats(MemPoolGlobalStats * stats);
+SQUIDCEXTERN int memPoolGetStats(MemPoolStats * stats, MemPool * pool);
+SQUIDCEXTERN int memPoolGetGlobalStats(MemPoolGlobalStats * stats);
 
 /* Module housekeeping API */
-extern void memPoolClean(time_t maxage);
+SQUIDCEXTERN void memPoolClean(time_t maxage);
 
 #if UNUSED
 /* Stats history API */
-extern void memPoolCheckRates(); /* stats history checkpoints */
+SQUIDCEXTERN void memPoolCheckRates(); /* stats history checkpoints */
 #endif
 
 #endif /* _MEM_POOLS_H_ */
Index: squid/include/Stack.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/Stack.h,v
retrieving revision 1.5
retrieving revision 1.5.44.1
diff -u -r1.5 -r1.5.44.1
--- squid/include/Stack.h	9 Oct 2001 21:17:59 -0000	1.5
+++ squid/include/Stack.h	3 Oct 2002 01:04:32 -0000	1.5.44.1
@@ -1,5 +1,5 @@
 /*
- * $Id: Stack.h,v 1.5 2001/10/09 21:17:59 squidadm Exp $
+ * $Id: Stack.h,v 1.5.44.1 2002/10/03 01:04:32 rbcollins Exp $
  *
  * AUTHOR: Alex Rousskov
  *
@@ -42,9 +42,9 @@
 #define stackInit arrayInit
 #define stackClean arrayClean
 #define stackDestroy arrayDestroy
-extern void *stackPop(Stack * s);
+SQUIDCEXTERN void *stackPop(Stack * s);
 #define stackPush arrayAppend
 #define stackPrePush arrayPreAppend
-extern void *stackTop(Stack * s);
+SQUIDCEXTERN void *stackTop(Stack * s);
 
 #endif /* SQUID_STACK_H */
Index: squid/include/config.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/config.h,v
retrieving revision 1.5
retrieving revision 1.5.52.1
diff -u -r1.5 -r1.5.52.1
--- squid/include/config.h	13 Nov 2001 22:19:32 -0000	1.5
+++ squid/include/config.h	3 Oct 2002 01:04:32 -0000	1.5.52.1
@@ -37,6 +37,13 @@
 #include "autoconf.h"		/* For GNU autoconf variables */
 #include "version.h"
 
+/* To keep API definitions clear */
+#ifdef __cplusplus
+#define SQUIDCEXTERN extern "C"
+#else
+#define SQUIDCEXTERN extern
+#endif
+
 /****************************************************************************
  *--------------------------------------------------------------------------*
  * DO *NOT* MAKE ANY CHANGES below here unless you know what you're doing...*
@@ -120,26 +127,121 @@
  *  the return codes of programs in if statements.  These options
  *  need to be overridden.
  */
-#ifndef socklen_t
-#define socklen_t int
 #endif
-#ifndef fd_mask
-#define fd_mask unsigned long
+
+/* Typedefs for missing entries on a system */
+
+#include "squid_types.h"
+
+/* int16_t */
+#ifndef HAVE_INT16_T
+#if HAVE_SHORT && SIZEOF_SHORT == 2
+typedef short int16_t;
+#elif HAVE_INT && SIZEOF_INT == 2
+typedef int int16_t;
+#else
+#error NO 16 bit signed type available
+#endif
+#endif
+
+/* u_int16_t */
+#ifndef HAVE_U_INT16_T
+#if HAVE_UINT16_T
+typedef uint16_t u_int16_t;
+#else
+typedef unsigned int16_t u_int16_t;
+#endif
+#endif
+
+/* int32_t */
+#ifndef HAVE_INT32_T
+#if HAVE_INT && SIZEOF_INT == 4
+typedef int int32_t;
+#elif HAVE_LONG && SIZEOF_LONG == 4
+typedef long int32_t;
+#else
+#error NO 32 bit signed type available
+#endif
+#endif
+
+/* u_int32_t */
+#ifndef HAVE_U_INT32_T
+#if HAVE_UINT32_T
+typedef uint32_t u_int32_t;
+#else
+typedef unsigned int32_t u_int32_t;
+#endif
+#endif
+
+/* int64_t */
+#ifndef HAVE_INT64_T
+#if HAVE___INT64
+typedef __int64 int64_t;
+#elif HAVE_LONG && SIZEOF_LONG == 8
+typedef long int64_t;
+#elif HAVE_LONG_LONG && SIZEOF_LONG_LONG == 8
+typedef long long int64_t;
+#else
+#error NO 64 bit signed type available
+#endif
+#endif
+
+/* u_int64_t */
+#ifndef HAVE_U_INT64_T
+#if HAVE_UINT64_T
+typedef uint64_t u_int64_t;
+#else
+typedef unsigned int64_t u_int64_t;
+#endif
+#endif
+
+
+#ifndef HAVE_PID_T
+typedef int pid_t;
+#endif
+
+#ifndef HAVE_SIZE_T
+typedef unsigned int size_t;
 #endif
+
+#ifndef HAVE_SSIZE_T
+typedef int ssize_t;
+#endif
+
+#ifndef HAVE_OFF_T
+typedef int off_t;
+#endif
+
+#ifndef HAVE_MODE_T
+typedef unsigned short mode_t;
+#endif
+
+#ifndef HAVE_FD_MASK
+typedef unsigned long fd_mask;
+#endif
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#ifndef HAVE_MTYP_T
+typedef long mtyp_t;
 #endif
 
 #if !defined(CACHEMGR_HOSTNAME)
 #define CACHEMGR_HOSTNAME ""
 #endif
 
-#if SQUID_UDP_SO_SNDBUF > 16384
-#undef SQUID_UDP_SO_SNDBUF
+#if SQUID_DETECT_UDP_SO_SNDBUF > 16384
 #define SQUID_UDP_SO_SNDBUF 16384
+#else
+#define SQUID_UDP_SO_SNDBUF SQUID_DETECT_UDP_SO_SNDBUF
 #endif
 
-#if SQUID_UDP_SO_RCVBUF > 16384
-#undef SQUID_UDP_SO_RCVBUF
+#if SQUID_DETECT_UDP_SO_RCVBUF > 16384
 #define SQUID_UDP_SO_RCVBUF 16384
+#else
+#define SQUID_UDP_SO_RCVBUF SQUID_DETECT_UDP_SO_RCVBUF
 #endif
 
 #ifdef HAVE_MEMCPY
Index: squid/include/hash.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/hash.h,v
retrieving revision 1.4
retrieving revision 1.4.44.1
diff -u -r1.4 -r1.4.44.1
--- squid/include/hash.h	9 Oct 2001 21:17:59 -0000	1.4
+++ squid/include/hash.h	3 Oct 2002 01:04:32 -0000	1.4.44.1
@@ -1,5 +1,5 @@
 /*
- * $Id: hash.h,v 1.4 2001/10/09 21:17:59 squidadm Exp $
+ * $Id: hash.h,v 1.4.44.1 2002/10/03 01:04:32 rbcollins Exp $
  */
 
 #ifndef SQUID_HASH_H
@@ -26,18 +26,18 @@
     int count;
 };
 
-extern hash_table *hash_create(HASHCMP *, int, HASHHASH *);
-extern void hash_join(hash_table *, hash_link *);
-extern void hash_remove_link(hash_table *, hash_link *);
+SQUIDCEXTERN hash_table *hash_create(HASHCMP *, int, HASHHASH *);
+SQUIDCEXTERN void hash_join(hash_table *, hash_link *);
+SQUIDCEXTERN void hash_remove_link(hash_table *, hash_link *);
 extern int hashPrime(int n);
-extern void *hash_lookup(hash_table *, const void *);
-extern void hash_first(hash_table *);
-extern void *hash_next(hash_table *);
+SQUIDCEXTERN void *hash_lookup(hash_table *, const void *);
+SQUIDCEXTERN void hash_first(hash_table *);
+SQUIDCEXTERN void *hash_next(hash_table *);
 extern void hash_last(hash_table *);
 extern hash_link *hash_get_bucket(hash_table *, unsigned int);
 extern void hashFreeMemory(hash_table *);
-extern void hashFreeItems(hash_table *, HASHFREE *);
-extern HASHHASH hash_string;
+SQUIDCEXTERN void hashFreeItems(hash_table *, HASHFREE *);
+SQUIDCEXTERN HASHHASH hash_string;
 extern HASHHASH hash4;
 extern const char *hashKeyStr(hash_link *);
 
Index: squid/include/rfc2617.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/rfc2617.h,v
retrieving revision 1.4
retrieving revision 1.4.44.1
diff -u -r1.4 -r1.4.44.1
--- squid/include/rfc2617.h	9 Oct 2001 21:17:59 -0000	1.4
+++ squid/include/rfc2617.h	3 Oct 2002 01:04:32 -0000	1.4.44.1
@@ -56,7 +56,7 @@
 typedef char HASHHEX[HASHHEXLEN + 1];
 
 /* calculate H(A1) as per HTTP Digest spec */
-void DigestCalcHA1(
+SQUIDCEXTERN void DigestCalcHA1(
     const char *pszAlg,
     const char *pszUserName,
     const char *pszRealm,
@@ -68,7 +68,7 @@
 );
 
 /* calculate request-digest/response-digest as per HTTP Digest spec */
-void DigestCalcResponse(
+SQUIDCEXTERN void DigestCalcResponse(
     const HASHHEX HA1,		/* H(A1) */
     const char *pszNonce,	/* nonce from server */
     const char *pszNonceCount,	/* 8 hex digits */
@@ -80,8 +80,8 @@
     HASHHEX Response		/* request-digest or response-digest */
 );
 
-void CvtHex(const HASH Bin, HASHHEX Hex);
+SQUIDCEXTERN void CvtHex(const HASH Bin, HASHHEX Hex);
 
-void CvtBin(const HASHHEX Hex, HASH Bin);
+SQUIDCEXTERN void CvtBin(const HASHHEX Hex, HASH Bin);
 
 #endif /* SQUID_RFC2617_H */
Index: squid/include/util.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/util.h,v
retrieving revision 1.11
retrieving revision 1.11.20.1
diff -u -r1.11 -r1.11.20.1
--- squid/include/util.h	6 Apr 2002 11:34:49 -0000	1.11
+++ squid/include/util.h	3 Oct 2002 01:04:32 -0000	1.11.20.1
@@ -1,5 +1,5 @@
 /*
- * $Id: util.h,v 1.11 2002/04/06 11:34:49 squidadm Exp $
+ * $Id: util.h,v 1.11.20.1 2002/10/03 01:04:32 rbcollins Exp $
  *
  * AUTHOR: Harvest Derived
  *
@@ -62,34 +62,34 @@
 #endif
 
 extern const char *getfullhostname(void);
-extern const char *mkhttpdlogtime(const time_t *);
-extern const char *mkrfc1123(time_t);
-extern char *uudecode(const char *);
-extern char *xstrdup(const char *);
-extern char *xstrndup(const char *, size_t);
-extern const char *xstrerror(void);
+SQUIDCEXTERN const char *mkhttpdlogtime(const time_t *);
+SQUIDCEXTERN const char *mkrfc1123(time_t);
+SQUIDCEXTERN char *uudecode(const char *);
+SQUIDCEXTERN char *xstrdup(const char *);
+SQUIDCEXTERN char *xstrndup(const char *, size_t);
+SQUIDCEXTERN const char *xstrerror(void);
 extern const char *xbstrerror(int);
 extern int tvSubMsec(struct timeval, struct timeval);
 extern int tvSubUsec(struct timeval, struct timeval);
 extern double tvSubDsec(struct timeval, struct timeval);
-extern char *xstrncpy(char *, const char *, size_t);
+SQUIDCEXTERN char *xstrncpy(char *, const char *, size_t);
 extern size_t xcountws(const char *str);
 extern time_t parse_rfc1123(const char *str);
-extern void *xcalloc(size_t, size_t);
-extern void *xmalloc(size_t);
-extern void *xrealloc(void *, size_t);
-extern void Tolower(char *);
-extern void xfree(void *);
-extern void xxfree(const void *);
+SQUIDCEXTERN void *xcalloc(size_t, size_t);
+SQUIDCEXTERN void *xmalloc(size_t);
+SQUIDCEXTERN void *xrealloc(void *, size_t);
+SQUIDCEXTERN void Tolower(char *);
+SQUIDCEXTERN void xfree(void *);
+SQUIDCEXTERN void xxfree(const void *);
 
 /* rfc1738.c */
-extern char *rfc1738_escape(const char *);
+SQUIDCEXTERN char *rfc1738_escape(const char *);
 extern char *rfc1738_escape_unescaped(const char *);
-extern char *rfc1738_escape_part(const char *);
-extern void rfc1738_unescape(char *);
+SQUIDCEXTERN char *rfc1738_escape_part(const char *);
+SQUIDCEXTERN void rfc1738_unescape(char *);
 
 /* html.c */
-extern char *html_quote(const char *);
+SQUIDCEXTERN char *html_quote(const char *);
 
 #if XMALLOC_STATISTICS
 extern void malloc_statistics(void (*)(int, int, int, void *), void *);
@@ -111,11 +111,11 @@
 #endif
 
 typedef struct in_addr SIA;
-extern int safe_inet_addr(const char *, SIA *);
+SQUIDCEXTERN int safe_inet_addr(const char *, SIA *);
 extern time_t parse_iso3307_time(const char *buf);
 extern char *base64_decode(const char *coded);
-extern const char *base64_encode(const char *decoded);
-extern const char *base64_encode_bin(const char *data, int len);
+SQUIDCEXTERN const char *base64_encode(const char *decoded);
+SQUIDCEXTERN const char *base64_encode_bin(const char *data, int len);
 
 extern double xpercent(double part, double whole);
 extern int xpercentInt(double part, double whole);
Index: squid/lib/Array.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/lib/Array.c,v
retrieving revision 1.5
retrieving revision 1.5.92.1
diff -u -r1.5 -r1.5.92.1
--- squid/lib/Array.c	7 Feb 2001 19:11:47 -0000	1.5
+++ squid/lib/Array.c	3 Oct 2002 01:04:32 -0000	1.5.92.1
@@ -1,5 +1,5 @@
 /*
- * $Id: Array.c,v 1.5 2001/02/07 19:11:47 hno Exp $
+ * $Id: Array.c,v 1.5.92.1 2002/10/03 01:04:32 rbcollins Exp $
  *
  * AUTHOR: Alex Rousskov
  *
@@ -119,7 +119,7 @@
     /* actual grow */
     assert(delta > 0);
     a->capacity += delta;
-    a->items = a->items ?
+    a->items = a->items ? 
 	xrealloc(a->items, a->capacity * sizeof(void *)) :
          xmalloc(a->capacity * sizeof(void *));
     /* reset, just in case */
--- squid/src/HttpRequest.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,160 +0,0 @@
-
-/*
- * $Id: HttpRequest.c,v 1.7 2001/04/14 00:31:01 squidadm Exp $
- *
- * DEBUG: section 73    HTTP Request
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-
-request_t *
-requestCreate(method_t method, protocol_t protocol, const char *urlpath)
-{
-    request_t *req = memAllocate(MEM_REQUEST_T);
-    req->method = method;
-    req->protocol = protocol;
-    if (urlpath)
-	stringReset(&req->urlpath, urlpath);
-    req->max_forwards = -1;
-    req->lastmod = -1;
-    req->client_addr = no_addr;
-    req->my_addr = no_addr;
-    httpHeaderInit(&req->header, hoRequest);
-    return req;
-}
-
-void
-requestDestroy(request_t * req)
-{
-    assert(req);
-    if (req->body_connection)
-	clientAbortBody(req);
-    if (req->auth_user_request)
-	authenticateAuthUserRequestUnlock(req->auth_user_request);
-    safe_free(req->canonical);
-    safe_free(req->vary_headers);
-    stringClean(&req->urlpath);
-    httpHeaderClean(&req->header);
-    if (req->cache_control)
-	httpHdrCcDestroy(req->cache_control);
-    if (req->range)
-	httpHdrRangeDestroy(req->range);
-    memFree(req, MEM_REQUEST_T);
-}
-
-request_t *
-requestLink(request_t * request)
-{
-    assert(request);
-    request->link_count++;
-    return request;
-}
-
-void
-requestUnlink(request_t * request)
-{
-    if (!request)
-	return;
-    assert(request->link_count > 0);
-    if (--request->link_count > 0)
-	return;
-    requestDestroy(request);
-}
-
-int
-httpRequestParseHeader(request_t * req, const char *parse_start)
-{
-    const char *blk_start, *blk_end;
-    if (!httpMsgIsolateHeaders(&parse_start, &blk_start, &blk_end))
-	return 0;
-    return httpHeaderParse(&req->header, blk_start, blk_end);
-}
-
-/* swaps out request using httpRequestPack */
-void
-httpRequestSwapOut(const request_t * req, StoreEntry * e)
-{
-    Packer p;
-    assert(req && e);
-    packerToStoreInit(&p, e);
-    httpRequestPack(req, &p);
-    packerClean(&p);
-}
-
-/* packs request-line and headers, appends <crlf> terminator */
-void
-httpRequestPack(const request_t * req, Packer * p)
-{
-    assert(req && p);
-    /* pack request-line */
-    packerPrintf(p, "%s %s HTTP/1.0\r\n",
-	RequestMethodStr[req->method], strBuf(req->urlpath));
-    /* headers */
-    httpHeaderPackInto(&req->header, p);
-    /* trailer */
-    packerAppend(p, "\r\n", 2);
-}
-
-#if UNUSED_CODE
-void
-httpRequestSetHeaders(request_t * req, method_t method, const char *uri, const char *header_str)
-{
-    assert(req && uri && header_str);
-    assert(!req->header.len);
-    httpHeaderParse(&req->header, header_str, header_str + strlen(header_str));
-}
-
-#endif
-
-/* returns the length of request line + headers + crlf */
-int
-httpRequestPrefixLen(const request_t * req)
-{
-    assert(req);
-    return strlen(RequestMethodStr[req->method]) + 1 +
-	strLen(req->urlpath) + 1 +
-	4 + 1 + 3 + 2 +
-	req->header.len + 2;
-}
-
-/*
- * Returns true if HTTP allows us to pass this header on.  Does not
- * check anonymizer (aka header_access) configuration.
- */
-int
-httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConn)
-{
-    assert(e);
-    /* check connection header */
-    if (strConn && strListIsMember(strConn, strBuf(e->name), ','))
-	return 0;
-    return 1;
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/HttpRequest.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,161 @@
+
+/*
+ * $Id: HttpRequest.cc,v 1.1.2.1 2002/10/03 01:04:33 rbcollins Exp $
+ *
+ * DEBUG: section 73    HTTP Request
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "authenticate.h"
+
+request_t *
+requestCreate(method_t method, protocol_t protocol, const char *urlpath)
+{
+    request_t *req = static_cast<request_t *>(memAllocate(MEM_REQUEST_T));
+    req->method = method;
+    req->protocol = protocol;
+    if (urlpath)
+	stringReset(&req->urlpath, urlpath);
+    req->max_forwards = -1;
+    req->lastmod = -1;
+    req->client_addr = no_addr;
+    req->my_addr = no_addr;
+    httpHeaderInit(&req->header, hoRequest);
+    return req;
+}
+
+void
+requestDestroy(request_t * req)
+{
+    assert(req);
+    if (req->body_connection)
+	clientAbortBody(req);
+    if (req->auth_user_request)
+	authenticateAuthUserRequestUnlock(req->auth_user_request);
+    safe_free(req->canonical);
+    safe_free(req->vary_headers);
+    stringClean(&req->urlpath);
+    httpHeaderClean(&req->header);
+    if (req->cache_control)
+	httpHdrCcDestroy(req->cache_control);
+    if (req->range)
+	httpHdrRangeDestroy(req->range);
+    memFree(req, MEM_REQUEST_T);
+}
+
+request_t *
+requestLink(request_t * request)
+{
+    assert(request);
+    request->link_count++;
+    return request;
+}
+
+void
+requestUnlink(request_t * request)
+{
+    if (!request)
+	return;
+    assert(request->link_count > 0);
+    if (--request->link_count > 0)
+	return;
+    requestDestroy(request);
+}
+
+int
+httpRequestParseHeader(request_t * req, const char *parse_start)
+{
+    const char *blk_start, *blk_end;
+    if (!httpMsgIsolateHeaders(&parse_start, &blk_start, &blk_end))
+	return 0;
+    return httpHeaderParse(&req->header, blk_start, blk_end);
+}
+
+/* swaps out request using httpRequestPack */
+void
+httpRequestSwapOut(const request_t * req, StoreEntry * e)
+{
+    Packer p;
+    assert(req && e);
+    packerToStoreInit(&p, e);
+    httpRequestPack(req, &p);
+    packerClean(&p);
+}
+
+/* packs request-line and headers, appends <crlf> terminator */
+void
+httpRequestPack(const request_t * req, Packer * p)
+{
+    assert(req && p);
+    /* pack request-line */
+    packerPrintf(p, "%s %s HTTP/1.0\r\n",
+	RequestMethodStr[req->method], strBuf(req->urlpath));
+    /* headers */
+    httpHeaderPackInto(&req->header, p);
+    /* trailer */
+    packerAppend(p, "\r\n", 2);
+}
+
+#if UNUSED_CODE
+void
+httpRequestSetHeaders(request_t * req, method_t method, const char *uri, const char *header_str)
+{
+    assert(req && uri && header_str);
+    assert(!req->header.len);
+    httpHeaderParse(&req->header, header_str, header_str + strlen(header_str));
+}
+
+#endif
+
+/* returns the length of request line + headers + crlf */
+int
+httpRequestPrefixLen(const request_t * req)
+{
+    assert(req);
+    return strlen(RequestMethodStr[req->method]) + 1 +
+	strLen(req->urlpath) + 1 +
+	4 + 1 + 3 + 2 +
+	req->header.len + 2;
+}
+
+/*
+ * Returns true if HTTP allows us to pass this header on.  Does not
+ * check anonymizer (aka header_access) configuration.
+ */
+int
+httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConn)
+{
+    assert(e);
+    /* check connection header */
+    if (strConn && strListIsMember(strConn, strBuf(e->name), ','))
+	return 0;
+    return 1;
+}
--- squid/src/IPInterception.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,194 +0,0 @@
-
-/*
- * $Id: IPInterception.c,v 1.4 2002/09/27 21:45:34 squidadm Exp $
- *
- * DEBUG: section 89    NAT / IP Interception 
- * AUTHOR: Robert Collins
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "clientStream.h"
-#include "IPInterception.h"
-
-#if IPF_TRANSPARENT
-#if HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#include <netinet/tcp.h>
-#include <net/if.h>
-#if HAVE_IP_FIL_COMPAT_H
-#include <ip_fil_compat.h>
-#elif HAVE_NETINET_IP_FIL_COMPAT_H
-#include <netinet/ip_fil_compat.h>
-#elif HAVE_IP_COMPAT_H
-#include <ip_compat.h>
-#elif HAVE_NETINET_IP_COMPAT_H
-#include <netinet/ip_compat.h>
-#endif
-#if HAVE_IP_FIL_H
-#include <ip_fil.h>
-#elif HAVE_NETINET_IP_FIL_H
-#include <netinet/ip_fil.h>
-#endif
-#if HAVE_IP_NAT_H
-#include <ip_nat.h>
-#elif HAVE_NETINET_IP_NAT_H
-#include <netinet/ip_nat.h>
-#endif
-#endif
-
-#if PF_TRANSPARENT
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/fcntl.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <net/pfvar.h>
-#endif
-
-#if LINUX_NETFILTER
-#include <linux/netfilter_ipv4.h>
-#endif
-
-void
-rewriteURIwithInterceptedDetails(char const *originalURL, char *uriBuffer, size_t bufferLength, int fd, struct sockaddr_in me, struct sockaddr_in peer, int vport)
-{
-#if IPF_TRANSPARENT
-    struct natlookup natLookup;
-    static int natfd = -1;
-    static int siocgnatl_cmd = SIOCGNATL & 0xff;
-    int x;
-#endif
-#if PF_TRANSPARENT
-    struct pfioc_natlook nl;
-    static int pffd = -1;
-#endif
-#if LINUX_NETFILTER
-    size_t sock_sz = sizeof(me);
-#endif
-#if IPF_TRANSPARENT
-    natLookup.nl_inport = me.sin_port;
-    natLookup.nl_outport = peer.sin_port;
-    natLookup.nl_inip = me.sin_addr;
-    natLookup.nl_outip = peer.sin_addr;
-    natLookup.nl_flags = IPN_TCP;
-    if (natfd < 0) {
-	int save_errno;
-	enter_suid();
-	natfd = open(IPL_NAT, O_RDONLY, 0);
-	save_errno = errno;
-	leave_suid();
-	errno = save_errno;
-    }
-    if (natfd < 0) {
-	debug(89, 1) ("rewriteURIwithInterceptedDetails: NAT open failed: %s\n",
-	    xstrerror());
-	cbdataFree(context);
-	xfree(inbuf);
-	return rewriteURIwithInterceptedDetailsAbort(conn, "error:nat-open-failed");
-    }
-    /* 
-     * IP-Filter changed the type for SIOCGNATL between
-     * 3.3 and 3.4.  It also changed the cmd value for
-     * SIOCGNATL, so at least we can detect it.  We could
-     * put something in configure and use ifdefs here, but
-     * this seems simpler.
-     */
-    if (63 == siocgnatl_cmd) {
-	struct natlookup *nlp = &natLookup;
-	x = ioctl(natfd, SIOCGNATL, &nlp);
-    } else {
-	x = ioctl(natfd, SIOCGNATL, &natLookup);
-    }
-    if (x < 0) {
-	if (errno != ESRCH) {
-	    debug(89, 1) ("rewriteURIwithInterceptedDetails: NAT lookup failed: ioctl(SIOCGNATL)\n");
-	    close(natfd);
-	    natfd = -1;
-	    cbdataFree(context);
-	    xfree(inbuf);
-	    return rewriteURIwithInterceptedDetailsAbort(conn,
-		"error:nat-lookup-failed");
-	} else
-	    snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
-		inet_ntoa(me.sin_addr), vport, originalURL);
-    } else {
-	if (vport_mode)
-	    vport = ntohs(natLookup.nl_realport);
-	snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
-	    inet_ntoa(natLookup.nl_realip), vport, originalURL);
-    }
-#elif PF_TRANSPARENT
-    if (pffd < 0)
-	pffd = open("/dev/pf", O_RDWR);
-    if (pffd < 0) {
-	debug(89, 1) ("rewriteURIwithInterceptedDetails: PF open failed: %s\n",
-	    xstrerror());
-	cbdataFree(context);
-	xfree(inbuf);
-	return rewriteURIwithInterceptedDetailsAbort(conn, "error:pf-open-failed");
-    }
-    memset(&nl, 0, sizeof(struct pfioc_natlook));
-    nl.saddr.v4.s_addr = peer.sin_addr.s_addr;
-    nl.sport = peer.sin_port;
-    nl.daddr.v4.s_addr = me.sin_addr.s_addr;
-    nl.dport = me.sin_port;
-    nl.af = AF_INET;
-    nl.proto = IPPROTO_TCP;
-    nl.direction = PF_OUT;
-    if (ioctl(pffd, DIOCNATLOOK, &nl)) {
-	if (errno != ENOENT) {
-	    debug(89, 1) ("rewriteURIwithInterceptedDetails: PF lookup failed: ioctl(DIOCNATLOOK)\n");
-	    close(pffd);
-	    pffd = -1;
-	    cbdataFree(context);
-	    xfree(inbuf);
-	    return rewriteURIwithInterceptedDetailsAbort(conn,
-		"error:pf-lookup-failed");
-	} else
-	    snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
-		inet_ntoa(me.sin_addr), vport, originalURL);
-    } else
-	snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
-	    inet_ntoa(nl.rdaddr.v4), ntohs(nl.rdport), originalURL);
-#else
-#if LINUX_NETFILTER
-    /* If the call fails the address structure will be unchanged */
-    getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, &me, &sock_sz);
-    debug(89, 5) ("rewriteURIwithInterceptedDetails: addr = %s",
-	inet_ntoa(me.sin_addr));
-    if (vport_mode)
-	vport = (int) ntohs(me.sin_port);
-#endif
-    snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
-	inet_ntoa(me.sin_addr), vport, originalURL);
-#endif
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/IPInterception.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,194 @@
+
+/*
+ * $Id: IPInterception.cc,v 1.1.2.1 2002/10/03 01:04:33 rbcollins Exp $
+ *
+ * DEBUG: section 89    NAT / IP Interception 
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "clientStream.h"
+#include "IPInterception.h"
+
+#if IPF_TRANSPARENT
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <netinet/tcp.h>
+#include <net/if.h>
+#if HAVE_IP_FIL_COMPAT_H
+#include <ip_fil_compat.h>
+#elif HAVE_NETINET_IP_FIL_COMPAT_H
+#include <netinet/ip_fil_compat.h>
+#elif HAVE_IP_COMPAT_H
+#include <ip_compat.h>
+#elif HAVE_NETINET_IP_COMPAT_H
+#include <netinet/ip_compat.h>
+#endif
+#if HAVE_IP_FIL_H
+#include <ip_fil.h>
+#elif HAVE_NETINET_IP_FIL_H
+#include <netinet/ip_fil.h>
+#endif
+#if HAVE_IP_NAT_H
+#include <ip_nat.h>
+#elif HAVE_NETINET_IP_NAT_H
+#include <netinet/ip_nat.h>
+#endif
+#endif
+
+#if PF_TRANSPARENT
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#endif
+
+#if LINUX_NETFILTER
+#include <linux/netfilter_ipv4.h>
+#endif
+
+void
+rewriteURIwithInterceptedDetails(char const *originalURL, char *uriBuffer, size_t bufferLength, int fd, struct sockaddr_in me, struct sockaddr_in peer, int vport)
+{
+#if IPF_TRANSPARENT
+    struct natlookup natLookup;
+    static int natfd = -1;
+    static int siocgnatl_cmd = SIOCGNATL & 0xff;
+    int x;
+#endif
+#if PF_TRANSPARENT
+    struct pfioc_natlook nl;
+    static int pffd = -1;
+#endif
+#if LINUX_NETFILTER
+    size_t sock_sz = sizeof(me);
+#endif
+#if IPF_TRANSPARENT
+    natLookup.nl_inport = me.sin_port;
+    natLookup.nl_outport = peer.sin_port;
+    natLookup.nl_inip = me.sin_addr;
+    natLookup.nl_outip = peer.sin_addr;
+    natLookup.nl_flags = IPN_TCP;
+    if (natfd < 0) {
+	int save_errno;
+	enter_suid();
+	natfd = open(IPL_NAT, O_RDONLY, 0);
+	save_errno = errno;
+	leave_suid();
+	errno = save_errno;
+    }
+    if (natfd < 0) {
+	debug(89, 1) ("rewriteURIwithInterceptedDetails: NAT open failed: %s\n",
+	    xstrerror());
+	cbdataFree(context);
+	xfree(inbuf);
+	return rewriteURIwithInterceptedDetailsAbort(conn, "error:nat-open-failed");
+    }
+    /* 
+     * IP-Filter changed the type for SIOCGNATL between
+     * 3.3 and 3.4.  It also changed the cmd value for
+     * SIOCGNATL, so at least we can detect it.  We could
+     * put something in configure and use ifdefs here, but
+     * this seems simpler.
+     */
+    if (63 == siocgnatl_cmd) {
+	struct natlookup *nlp = &natLookup;
+	x = ioctl(natfd, SIOCGNATL, &nlp);
+    } else {
+	x = ioctl(natfd, SIOCGNATL, &natLookup);
+    }
+    if (x < 0) {
+	if (errno != ESRCH) {
+	    debug(89, 1) ("rewriteURIwithInterceptedDetails: NAT lookup failed: ioctl(SIOCGNATL)\n");
+	    close(natfd);
+	    natfd = -1;
+	    cbdataFree(context);
+	    xfree(inbuf);
+	    return rewriteURIwithInterceptedDetailsAbort(conn,
+		"error:nat-lookup-failed");
+	} else
+	    snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
+		inet_ntoa(me.sin_addr), vport, originalURL);
+    } else {
+	if (vport_mode)
+	    vport = ntohs(natLookup.nl_realport);
+	snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
+	    inet_ntoa(natLookup.nl_realip), vport, originalURL);
+    }
+#elif PF_TRANSPARENT
+    if (pffd < 0)
+	pffd = open("/dev/pf", O_RDWR);
+    if (pffd < 0) {
+	debug(89, 1) ("rewriteURIwithInterceptedDetails: PF open failed: %s\n",
+	    xstrerror());
+	cbdataFree(context);
+	xfree(inbuf);
+	return rewriteURIwithInterceptedDetailsAbort(conn, "error:pf-open-failed");
+    }
+    memset(&nl, 0, sizeof(struct pfioc_natlook));
+    nl.saddr.v4.s_addr = peer.sin_addr.s_addr;
+    nl.sport = peer.sin_port;
+    nl.daddr.v4.s_addr = me.sin_addr.s_addr;
+    nl.dport = me.sin_port;
+    nl.af = AF_INET;
+    nl.proto = IPPROTO_TCP;
+    nl.direction = PF_OUT;
+    if (ioctl(pffd, DIOCNATLOOK, &nl)) {
+	if (errno != ENOENT) {
+	    debug(89, 1) ("rewriteURIwithInterceptedDetails: PF lookup failed: ioctl(DIOCNATLOOK)\n");
+	    close(pffd);
+	    pffd = -1;
+	    cbdataFree(context);
+	    xfree(inbuf);
+	    return rewriteURIwithInterceptedDetailsAbort(conn,
+		"error:pf-lookup-failed");
+	} else
+	    snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
+		inet_ntoa(me.sin_addr), vport, originalURL);
+    } else
+	snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
+	    inet_ntoa(nl.rdaddr.v4), ntohs(nl.rdport), originalURL);
+#else
+#if LINUX_NETFILTER
+    /* If the call fails the address structure will be unchanged */
+    getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, &me, &sock_sz);
+    debug(89, 5) ("rewriteURIwithInterceptedDetails: addr = %s",
+	inet_ntoa(me.sin_addr));
+    if (vport_mode)
+	vport = (int) ntohs(me.sin_port);
+#endif
+    snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
+	inet_ntoa(me.sin_addr), vport, originalURL);
+#endif
+}
Index: squid/src/IPInterception.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Attic/IPInterception.h,v
retrieving revision 1.3
retrieving revision 1.3.6.1
diff -u -r1.3 -r1.3.6.1
--- squid/src/IPInterception.h	27 Sep 2002 21:45:34 -0000	1.3
+++ squid/src/IPInterception.h	3 Oct 2002 01:04:33 -0000	1.3.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: IPInterception.h,v 1.3 2002/09/27 21:45:34 squidadm Exp $
+ * $Id: IPInterception.h,v 1.3.6.1 2002/10/03 01:04:33 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -34,7 +34,7 @@
 #ifndef SQUID_IPINTERCEPTION_H
 #define SQUID_IPINTERCEPTION_H
 
-void
+SQUIDCEXTERN void
      rewriteURIwithInterceptedDetails(char const *originalURL, char *uriBuffer, size_t bufferLength, int fd, struct sockaddr_in me, struct sockaddr_in peer, int vport);
 
 #endif /* SQUID_IPINTERCEPTION_H */
Index: squid/src/Makefile.am
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Makefile.am,v
retrieving revision 1.29
retrieving revision 1.29.2.1
diff -u -r1.29 -r1.29.2.1
--- squid/src/Makefile.am	2 Oct 2002 11:10:44 -0000	1.29
+++ squid/src/Makefile.am	3 Oct 2002 01:04:33 -0000	1.29.2.1
@@ -115,11 +115,11 @@
 	win32.c
 
 squid_SOURCES = \
-	access_log.c \
+	access_log.cc \
 	acl.c \
 	asn.c \
-	authenticate.c \
-	cache_cf.c \
+	authenticate.cc \
+	cache_cf.cc \
 	CacheDigest.c \
 	cache_manager.c \
 	carp.c \
@@ -141,7 +141,7 @@
 	disk.c \
 	$(DNSSOURCE) \
 	enums.h \
-	errorpage.c \
+	errorpage.cc \
 	ETag.c \
 	event.c \
 	external_acl.c \
@@ -154,7 +154,7 @@
 	gopher.c \
 	helper.c \
 	$(HTCPSOURCE) \
-	http.c \
+	http.cc \
 	HttpStatusLine.c \
 	HttpHdrCc.c \
 	HttpHdrRange.c \
@@ -164,7 +164,7 @@
 	HttpBody.c \
 	HttpMsg.c \
 	HttpReply.c \
-	HttpRequest.c \
+	HttpRequest.cc \
 	icmp.c \
 	icp_v2.c \
 	icp_v3.c \
@@ -172,11 +172,11 @@
 	internal.c \
 	ipc.c \
 	ipcache.c \
-	IPInterception.c \
+	IPInterception.cc \
 	IPInterception.h \
 	$(LEAKFINDERSOURCE) \
-	logfile.c \
-	main.c \
+	logfile.cc \
+	main.cc \
 	mem.c \
 	MemBuf.c \
 	mime.c \
@@ -189,7 +189,7 @@
 	peer_digest.c \
 	peer_select.c \
 	protos.h \
-	redirect.c \
+	redirect.cc \
 	referer.c \
 	refresh.c \
 	send-announce.c \
@@ -228,7 +228,7 @@
 
 nodist_squid_SOURCES = \
 	repl_modules.c \
-	auth_modules.c \
+	auth_modules.cc \
 	store_modules.c \
 	cf_parser.h \
 	globals.c \
@@ -267,7 +267,7 @@
 	globals.c \
 	string_arrays.c \
 	repl_modules.c \
-	auth_modules.c \
+	auth_modules.cc \
 	store_modules.c
 
 sysconf_DATA = \
@@ -366,8 +366,8 @@
 repl_modules.c: repl_modules.sh Makefile
 	$(SHELL) $(srcdir)/repl_modules.sh $(REPL_POLICIES) > repl_modules.c
 
-auth_modules.c: auth_modules.sh Makefile
-	@$(SHELL) $(srcdir)/auth_modules.sh $(AUTH_MODULES) >auth_modules.c
+auth_modules.cc: auth_modules.sh Makefile
+	@$(SHELL) $(srcdir)/auth_modules.sh $(AUTH_MODULES) >auth_modules.cc
 
 install-data-local: install-sysconfDATA install-dataDATA
 	@if test -f $(DESTDIR)$(DEFAULT_MIME_TABLE) ; then \
@@ -395,7 +395,7 @@
 	fi
 
 DISTCLEANFILES = cf_gen_defines.h cf.data cf_parser.h squid.conf.default \
-	globals.c string_arrays.c repl_modules.c auth_modules.c store_modules.c
+	globals.c string_arrays.c repl_modules.c auth_modules.cc store_modules.c
 
 ##install-pinger:
 ##	@f=$(PINGER_EXE); \
--- squid/src/access_log.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,636 +0,0 @@
-
-/*
- * $Id: access_log.c,v 1.19 2002/09/24 10:59:13 rbcollins Exp $
- *
- * DEBUG: section 46    Access Log
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-
-#include "squid.h"
-
-static void accessLogSquid(AccessLogEntry * al);
-static void accessLogCommon(AccessLogEntry * al);
-static Logfile *logfile = NULL;
-#if HEADERS_LOG
-static Logfile *headerslog = NULL;
-#endif
-
-#if MULTICAST_MISS_STREAM
-static int mcast_miss_fd = -1;
-static struct sockaddr_in mcast_miss_to;
-static void mcast_encode(unsigned int *, size_t, const unsigned int *);
-#endif
-
-const char *log_tags[] =
-{
-    "NONE",
-    "TCP_HIT",
-    "TCP_MISS",
-    "TCP_REFRESH_HIT",
-    "TCP_REF_FAIL_HIT",
-    "TCP_REFRESH_MISS",
-    "TCP_CLIENT_REFRESH_MISS",
-    "TCP_IMS_HIT",
-    "TCP_SWAPFAIL_MISS",
-    "TCP_NEGATIVE_HIT",
-    "TCP_MEM_HIT",
-    "TCP_DENIED",
-    "TCP_OFFLINE_HIT",
-#if LOG_TCP_REDIRECTS
-    "TCP_REDIRECT",
-#endif
-    "UDP_HIT",
-    "UDP_MISS",
-    "UDP_DENIED",
-    "UDP_INVALID",
-    "UDP_MISS_NOFETCH",
-    "ICP_QUERY",
-    "LOG_TYPE_MAX"
-};
-
-#if FORW_VIA_DB
-typedef struct {
-    hash_link hash;
-    int n;
-} fvdb_entry;
-static hash_table *via_table = NULL;
-static hash_table *forw_table = NULL;
-static void fvdbInit(void);
-static void fvdbDumpTable(StoreEntry * e, hash_table * hash);
-static void fvdbCount(hash_table * hash, const char *key);
-static OBJH fvdbDumpVia;
-static OBJH fvdbDumpForw;
-static FREE fvdbFreeEntry;
-static void fvdbClear(void);
-#endif
-
-static int LogfileStatus = LOG_DISABLE;
-#define LOG_BUF_SZ (MAX_URL<<2)
-
-static const char c2x[] =
-"000102030405060708090a0b0c0d0e0f"
-"101112131415161718191a1b1c1d1e1f"
-"202122232425262728292a2b2c2d2e2f"
-"303132333435363738393a3b3c3d3e3f"
-"404142434445464748494a4b4c4d4e4f"
-"505152535455565758595a5b5c5d5e5f"
-"606162636465666768696a6b6c6d6e6f"
-"707172737475767778797a7b7c7d7e7f"
-"808182838485868788898a8b8c8d8e8f"
-"909192939495969798999a9b9c9d9e9f"
-"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
-"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
-"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
-"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
-"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
-"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
-
-/* log_quote -- URL-style encoding on MIME headers. */
-
-char *
-log_quote(const char *header)
-{
-    int c;
-    int i;
-    char *buf;
-    char *buf_cursor;
-    if (header == NULL) {
-	buf = xcalloc(1, 1);
-	*buf = '\0';
-	return buf;
-    }
-    buf = xcalloc(1, (strlen(header) * 3) + 1);
-    buf_cursor = buf;
-    /*
-     * We escape: \x00-\x1F"#%;<>?{}|\\\\^~`\[\]\x7F-\xFF 
-     * which is the default escape list for the CPAN Perl5 URI module
-     * modulo the inclusion of space (x40) to make the raw logs a bit
-     * more readable.
-     */
-    while ((c = *(const unsigned char *) header++) != '\0') {
-#if !OLD_LOG_MIME
-	if (c == '\r') {
-	    *buf_cursor++ = '\\';
-	    *buf_cursor++ = 'r';
-	} else if (c == '\n') {
-	    *buf_cursor++ = '\\';
-	    *buf_cursor++ = 'n';
-	} else
-#endif
-	    if (c <= 0x1F
-		|| c >= 0x7F
-#if OLD_LOG_MIME
-		|| c == '"'
-		|| c == '#'
-		|| c == '%'
-		|| c == ';'
-		|| c == '<'
-		|| c == '>'
-		|| c == '?'
-		|| c == '{'
-		|| c == '}'
-		|| c == '|'
-		|| c == '\\'
-		|| c == '^'
-		|| c == '~'
-		|| c == '`'
-#endif
-		|| c == '['
-	    || c == ']') {
-	    *buf_cursor++ = '%';
-	    i = c * 2;
-	    *buf_cursor++ = c2x[i];
-	    *buf_cursor++ = c2x[i + 1];
-#if !OLD_LOG_MIME
-	} else if (c == '\\') {
-	    *buf_cursor++ = '\\';
-	    *buf_cursor++ = '\\';
-#endif
-	} else {
-	    *buf_cursor++ = (char) c;
-	}
-    }
-    *buf_cursor = '\0';
-    return buf;
-}
-
-static char *
-username_quote(const char *header)
-/* copy of log_quote. Bugs there will be found here */
-{
-    int c;
-    int i;
-    char *buf;
-    char *buf_cursor;
-    if (header == NULL) {
-	buf = xcalloc(1, 1);
-	*buf = '\0';
-	return buf;
-    }
-    buf = xcalloc(1, (strlen(header) * 3) + 1);
-    buf_cursor = buf;
-    /*
-     * We escape: space \x00-\x1F and space (0x40) and \x7F-\xFF
-     * to prevent garbage in the logs. CR and LF are also there just in case. 
-     */
-    while ((c = *(const unsigned char *) header++) != '\0') {
-	if (c == '\r') {
-	    *buf_cursor++ = '\\';
-	    *buf_cursor++ = 'r';
-	} else if (c == '\n') {
-	    *buf_cursor++ = '\\';
-	    *buf_cursor++ = 'n';
-	} else if (c <= 0x1F
-		|| c >= 0x7F
-	    || c == ' ') {
-	    *buf_cursor++ = '%';
-	    i = c * 2;
-	    *buf_cursor++ = c2x[i];
-	    *buf_cursor++ = c2x[i + 1];
-	} else {
-	    *buf_cursor++ = (char) c;
-	}
-    }
-    *buf_cursor = '\0';
-    return buf;
-}
-
-static char *
-accessLogFormatName(const char *name)
-{
-    if (NULL == name)
-	return NULL;
-    return username_quote(name);
-}
-
-static void
-accessLogSquid(AccessLogEntry * al)
-{
-    const char *client = NULL;
-    char *user = NULL;
-    if (Config.onoff.log_fqdn)
-	client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
-    if (client == NULL)
-	client = inet_ntoa(al->cache.caddr);
-    user = accessLogFormatName(al->cache.authuser ?
-	al->cache.authuser : al->cache.rfc931);
-    logfilePrintf(logfile, "%9d.%03d %6d %s %s/%03d %ld %s %s %s %s%s/%s %s",
-	(int) current_time.tv_sec,
-	(int) current_time.tv_usec / 1000,
-	al->cache.msec,
-	client,
-	log_tags[al->cache.code],
-	al->http.code,
-	(long int) al->cache.size,
-	al->_private.method_str,
-	al->url,
-	user && *user ? user : dash_str,
-	al->hier.ping.timedout ? "TIMEOUT_" : "",
-	hier_strings[al->hier.code],
-	al->hier.host,
-	al->http.content_type);
-    safe_free(user);
-}
-
-static void
-accessLogCommon(AccessLogEntry * al)
-{
-    const char *client = NULL;
-    char *user1 = NULL, *user2 = NULL;
-    if (Config.onoff.log_fqdn)
-	client = fqdncache_gethostbyaddr(al->cache.caddr, 0);
-    if (client == NULL)
-	client = inet_ntoa(al->cache.caddr);
-    user1 = accessLogFormatName(al->cache.authuser);
-    user2 = accessLogFormatName(al->cache.rfc931);
-    logfilePrintf(logfile, "%s %s %s [%s] \"%s %s HTTP/%d.%d\" %d %ld %s:%s",
-	client,
-	user2 ? user2 : dash_str,
-	user1 ? user1 : dash_str,
-	mkhttpdlogtime(&squid_curtime),
-	al->_private.method_str,
-	al->url,
-	al->http.version.major, al->http.version.minor,
-	al->http.code,
-	(long int) al->cache.size,
-	log_tags[al->cache.code],
-	hier_strings[al->hier.code]);
-    safe_free(user1);
-    safe_free(user2);
-}
-
-void
-accessLogLog(AccessLogEntry * al)
-{
-    if (LogfileStatus != LOG_ENABLE)
-	return;
-    if (al->url == NULL)
-	al->url = dash_str;
-    if (!al->http.content_type || *al->http.content_type == '\0')
-	al->http.content_type = dash_str;
-    if (al->icp.opcode)
-	al->_private.method_str = icp_opcode_str[al->icp.opcode];
-    else
-	al->_private.method_str = RequestMethodStr[al->http.method];
-    if (al->hier.host[0] == '\0')
-	xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
-
-    if (Config.onoff.common_log)
-	accessLogCommon(al);
-    else
-	accessLogSquid(al);
-    if (Config.onoff.log_mime_hdrs) {
-	char *ereq = log_quote(al->headers.request);
-	char *erep = log_quote(al->headers.reply);
-	logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
-	safe_free(ereq);
-	safe_free(erep);
-    } else {
-	logfilePrintf(logfile, "\n");
-    }
-    logfileFlush(logfile);
-#if MULTICAST_MISS_STREAM
-    if (al->cache.code != LOG_TCP_MISS)
-	(void) 0;
-    else if (al->http.method != METHOD_GET)
-	(void) 0;
-    else if (mcast_miss_fd < 0)
-	(void) 0;
-    else {
-	unsigned int ibuf[365];
-	size_t isize;
-	xstrncpy((char *) ibuf, al->url, 364 * sizeof(int));
-	isize = ((strlen(al->url) + 8) / 8) * 2;
-	if (isize > 364)
-	    isize = 364;
-	mcast_encode((unsigned int *) ibuf, isize,
-	    (const unsigned int *) Config.mcast_miss.encode_key);
-	comm_udp_sendto(mcast_miss_fd,
-	    &mcast_miss_to, sizeof(mcast_miss_to),
-	    ibuf, isize * sizeof(int));
-    }
-#endif
-}
-
-void
-accessLogRotate(void)
-{
-#if FORW_VIA_DB
-    fvdbClear();
-#endif
-    if (NULL == logfile)
-	return;
-    logfileRotate(logfile);
-#if HEADERS_LOG
-    logfileRotate(headerslog);
-#endif
-}
-
-void
-accessLogClose(void)
-{
-    if (NULL == logfile)
-	return;
-    logfileClose(logfile);
-    logfile = NULL;
-#if HEADERS_LOG
-    logfileClose(headerslog);
-    headerslog = NULL;
-#endif
-}
-
-void
-hierarchyNote(HierarchyLogEntry * hl,
-    hier_code code,
-    const char *cache_peer)
-{
-    assert(hl != NULL);
-    hl->code = code;
-    xstrncpy(hl->host, cache_peer, SQUIDHOSTNAMELEN);
-}
-
-void
-accessLogInit(void)
-{
-    assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *));
-    if (strcasecmp(Config.Log.access, "none") == 0)
-	return;
-    logfile = logfileOpen(Config.Log.access, MAX_URL << 1, 1);
-    LogfileStatus = LOG_ENABLE;
-#if HEADERS_LOG
-    headerslog = logfileOpen("/usr/local/squid/logs/headers.log", 512);
-    assert(NULL != headerslog);
-#endif
-#if FORW_VIA_DB
-    fvdbInit();
-#endif
-#if MULTICAST_MISS_STREAM
-    if (Config.mcast_miss.addr.s_addr != no_addr.s_addr) {
-	memset(&mcast_miss_to, '\0', sizeof(mcast_miss_to));
-	mcast_miss_to.sin_family = AF_INET;
-	mcast_miss_to.sin_port = htons(Config.mcast_miss.port);
-	mcast_miss_to.sin_addr.s_addr = Config.mcast_miss.addr.s_addr;
-	mcast_miss_fd = comm_open(SOCK_DGRAM,
-	    0,
-	    Config.Addrs.udp_incoming,
-	    Config.mcast_miss.port,
-	    COMM_NONBLOCKING,
-	    "Multicast Miss Stream");
-	if (mcast_miss_fd < 0)
-	    fatal("Cannot open Multicast Miss Stream Socket");
-	debug(46, 1) ("Multicast Miss Stream Socket opened on FD %d\n",
-	    mcast_miss_fd);
-	mcastSetTtl(mcast_miss_fd, Config.mcast_miss.ttl);
-	if (strlen(Config.mcast_miss.encode_key) < 16)
-	    fatal("mcast_encode_key is too short, must be 16 characters");
-    }
-#endif
-}
-
-const char *
-accessLogTime(time_t t)
-{
-    struct tm *tm;
-    static char buf[128];
-    static time_t last_t = 0;
-    if (t != last_t) {
-	tm = localtime(&t);
-	strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
-	last_t = t;
-    }
-    return buf;
-}
-
-
-#if FORW_VIA_DB
-
-static void
-fvdbInit(void)
-{
-    via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
-    forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
-    cachemgrRegister("via_headers", "Via Request Headers", fvdbDumpVia, 0, 1);
-    cachemgrRegister("forw_headers", "X-Forwarded-For Request Headers",
-	fvdbDumpForw, 0, 1);
-}
-
-static void
-fvdbCount(hash_table * hash, const char *key)
-{
-    fvdb_entry *fv;
-    if (NULL == hash)
-	return;
-    fv = hash_lookup(hash, key);
-    if (NULL == fv) {
-	fv = xcalloc(1, sizeof(fvdb_entry));
-	fv->hash.key = xstrdup(key);
-	hash_join(hash, &fv->hash);
-    }
-    fv->n++;
-}
-
-void
-fvdbCountVia(const char *key)
-{
-    fvdbCount(via_table, key);
-}
-
-void
-fvdbCountForw(const char *key)
-{
-    fvdbCount(forw_table, key);
-}
-
-static void
-fvdbDumpTable(StoreEntry * e, hash_table * hash)
-{
-    hash_link *h;
-    fvdb_entry *fv;
-    if (hash == NULL)
-	return;
-    hash_first(hash);
-    while ((h = hash_next(hash))) {
-	fv = (fvdb_entry *) h;
-	storeAppendPrintf(e, "%9d %s\n", fv->n, hashKeyStr(&fv->hash));
-    }
-}
-
-static void
-fvdbDumpVia(StoreEntry * e)
-{
-    fvdbDumpTable(e, via_table);
-}
-
-static void
-fvdbDumpForw(StoreEntry * e)
-{
-    fvdbDumpTable(e, forw_table);
-}
-
-static
-void
-fvdbFreeEntry(void *data)
-{
-    fvdb_entry *fv = data;
-    xfree(fv->hash.key);
-    xfree(fv);
-}
-
-static void
-fvdbClear(void)
-{
-    hashFreeItems(via_table, fvdbFreeEntry);
-    hashFreeMemory(via_table);
-    via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
-    hashFreeItems(forw_table, fvdbFreeEntry);
-    hashFreeMemory(forw_table);
-    forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
-}
-
-#endif
-
-#if MULTICAST_MISS_STREAM
-/*
- * From http://www.io.com/~paulhart/game/algorithms/tea.html
- *
- * size of 'ibuf' must be a multiple of 2.
- * size of 'key' must be 4.
- * 'ibuf' is modified in place, encrypted data is written in
- * network byte order.
- */
-static void
-mcast_encode(unsigned int *ibuf, size_t isize, const unsigned int *key)
-{
-    unsigned int y;
-    unsigned int z;
-    unsigned int sum;
-    const unsigned int delta = 0x9e3779b9;
-    unsigned int n = 32;
-    const unsigned int k0 = htonl(key[0]);
-    const unsigned int k1 = htonl(key[1]);
-    const unsigned int k2 = htonl(key[2]);
-    const unsigned int k3 = htonl(key[3]);
-    int i;
-    for (i = 0; i < isize; i += 2) {
-	y = htonl(ibuf[i]);
-	z = htonl(ibuf[i + 1]);
-	sum = 0;
-	for (n = 32; n; n--) {
-	    sum += delta;
-	    y += (z << 4) + (k0 ^ z) + (sum ^ (z >> 5)) + k1;
-	    z += (y << 4) + (k2 ^ y) + (sum ^ (y >> 5)) + k3;
-	}
-	ibuf[i] = htonl(y);
-	ibuf[i + 1] = htonl(z);
-    }
-}
-
-#endif
-
-#if HEADERS_LOG
-void
-headersLog(int cs, int pq, method_t m, void *data)
-{
-    HttpReply *rep;
-    request_t *req;
-    unsigned short magic = 0;
-    unsigned char M = (unsigned char) m;
-    unsigned short S;
-    char *hmask;
-    int ccmask = 0;
-    if (0 == pq) {
-	/* reply */
-	rep = data;
-	req = NULL;
-	magic = 0x0050;
-	hmask = rep->header.mask;
-	if (rep->cache_control)
-	    ccmask = rep->cache_control->mask;
-    } else {
-	/* request */
-	req = data;
-	rep = NULL;
-	magic = 0x0051;
-	hmask = req->header.mask;
-	if (req->cache_control)
-	    ccmask = req->cache_control->mask;
-    }
-    if (0 == cs) {
-	/* client */
-	magic |= 0x4300;
-    } else {
-	/* server */
-	magic |= 0x5300;
-    }
-    magic = htons(magic);
-    ccmask = htonl(ccmask);
-    if (0 == pq)
-	S = (unsigned short) rep->sline.status;
-    else
-	S = (unsigned short) HTTP_STATUS_NONE;
-    logfileWrite(headerslog, &magic, sizeof(magic));
-    logfileWrite(headerslog, &M, sizeof(M));
-    logfileWrite(headerslog, &S, sizeof(S));
-    logfileWrite(headerslog, hmask, sizeof(HttpHeaderMask));
-    logfileWrite(headerslog, &ccmask, sizeof(int));
-    logfileFlush(headerslog);
-}
-
-#endif
-
-void
-accessLogFreeMemory(AccessLogEntry * aLogEntry)
-{
-    safe_free(aLogEntry->headers.request);
-    safe_free(aLogEntry->headers.reply);
-    safe_free(aLogEntry->cache.authuser);
-}
-
-int
-logTypeIsATcpHit(log_type code)
-{
-    /* this should be a bitmap for better optimization */
-    if (code == LOG_TCP_HIT)
-	return 1;
-    if (code == LOG_TCP_IMS_HIT)
-	return 1;
-    if (code == LOG_TCP_REFRESH_FAIL_HIT)
-	return 1;
-    if (code == LOG_TCP_REFRESH_HIT)
-	return 1;
-    if (code == LOG_TCP_NEGATIVE_HIT)
-	return 1;
-    if (code == LOG_TCP_MEM_HIT)
-	return 1;
-    if (code == LOG_TCP_OFFLINE_HIT)
-	return 1;
-    return 0;
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/access_log.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,637 @@
+
+/*
+ * $Id: access_log.cc,v 1.1.2.1 2002/10/03 01:04:33 rbcollins Exp $
+ *
+ * DEBUG: section 46    Access Log
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+
+#include "squid.h"
+
+static void accessLogSquid(AccessLogEntry * al);
+static void accessLogCommon(AccessLogEntry * al);
+static Logfile *logfile = NULL;
+#if HEADERS_LOG
+static Logfile *headerslog = NULL;
+#endif
+
+#if MULTICAST_MISS_STREAM
+static int mcast_miss_fd = -1;
+static struct sockaddr_in mcast_miss_to;
+static void mcast_encode(unsigned int *, size_t, const unsigned int *);
+#endif
+
+const char *log_tags[] =
+{
+    "NONE",
+    "TCP_HIT",
+    "TCP_MISS",
+    "TCP_REFRESH_HIT",
+    "TCP_REF_FAIL_HIT",
+    "TCP_REFRESH_MISS",
+    "TCP_CLIENT_REFRESH_MISS",
+    "TCP_IMS_HIT",
+    "TCP_SWAPFAIL_MISS",
+    "TCP_NEGATIVE_HIT",
+    "TCP_MEM_HIT",
+    "TCP_DENIED",
+    "TCP_OFFLINE_HIT",
+#if LOG_TCP_REDIRECTS
+    "TCP_REDIRECT",
+#endif
+    "UDP_HIT",
+    "UDP_MISS",
+    "UDP_DENIED",
+    "UDP_INVALID",
+    "UDP_MISS_NOFETCH",
+    "ICP_QUERY",
+    "LOG_TYPE_MAX"
+};
+
+#if FORW_VIA_DB
+typedef struct {
+    hash_link hash;
+    int n;
+} fvdb_entry;
+static hash_table *via_table = NULL;
+static hash_table *forw_table = NULL;
+static void fvdbInit(void);
+static void fvdbDumpTable(StoreEntry * e, hash_table * hash);
+static void fvdbCount(hash_table * hash, const char *key);
+static OBJH fvdbDumpVia;
+static OBJH fvdbDumpForw;
+static FREE fvdbFreeEntry;
+static void fvdbClear(void);
+#endif
+
+static int LogfileStatus = LOG_DISABLE;
+#define LOG_BUF_SZ (MAX_URL<<2)
+
+static const char c2x[] =
+"000102030405060708090a0b0c0d0e0f"
+"101112131415161718191a1b1c1d1e1f"
+"202122232425262728292a2b2c2d2e2f"
+"303132333435363738393a3b3c3d3e3f"
+"404142434445464748494a4b4c4d4e4f"
+"505152535455565758595a5b5c5d5e5f"
+"606162636465666768696a6b6c6d6e6f"
+"707172737475767778797a7b7c7d7e7f"
+"808182838485868788898a8b8c8d8e8f"
+"909192939495969798999a9b9c9d9e9f"
+"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+
+/* log_quote -- URL-style encoding on MIME headers. */
+
+char *
+log_quote(const char *header)
+{
+    int c;
+    int i;
+    char *buf;
+    char *buf_cursor;
+    if (header == NULL) {
+	buf = static_cast<char *>(xcalloc(1, 1));
+	*buf = '\0';
+	return buf;
+    }
+    buf = static_cast<char *>(xcalloc(1, (strlen(header) * 3) + 1));
+    buf_cursor = buf;
+    /*
+     * We escape: \x00-\x1F"#%;<>?{}|\\\\^~`\[\]\x7F-\xFF 
+     * which is the default escape list for the CPAN Perl5 URI module
+     * modulo the inclusion of space (x40) to make the raw logs a bit
+     * more readable.
+     */
+    while ((c = *(const unsigned char *) header++) != '\0') {
+#if !OLD_LOG_MIME
+	if (c == '\r') {
+	    *buf_cursor++ = '\\';
+	    *buf_cursor++ = 'r';
+	} else if (c == '\n') {
+	    *buf_cursor++ = '\\';
+	    *buf_cursor++ = 'n';
+	} else
+#endif
+	    if (c <= 0x1F
+		|| c >= 0x7F
+#if OLD_LOG_MIME
+		|| c == '"'
+		|| c == '#'
+		|| c == '%'
+		|| c == ';'
+		|| c == '<'
+		|| c == '>'
+		|| c == '?'
+		|| c == '{'
+		|| c == '}'
+		|| c == '|'
+		|| c == '\\'
+		|| c == '^'
+		|| c == '~'
+		|| c == '`'
+#endif
+		|| c == '['
+	    || c == ']') {
+	    *buf_cursor++ = '%';
+	    i = c * 2;
+	    *buf_cursor++ = c2x[i];
+	    *buf_cursor++ = c2x[i + 1];
+#if !OLD_LOG_MIME
+	} else if (c == '\\') {
+	    *buf_cursor++ = '\\';
+	    *buf_cursor++ = '\\';
+#endif
+	} else {
+	    *buf_cursor++ = (char) c;
+	}
+    }
+    *buf_cursor = '\0';
+    return buf;
+}
+
+static char *
+username_quote(const char *header)
+/* copy of log_quote. Bugs there will be found here */
+{
+    int c;
+    int i;
+    char *buf;
+    char *buf_cursor;
+    if (header == NULL) {
+	buf = static_cast<char *>(xcalloc(1, 1));
+	*buf = '\0';
+	return buf;
+    }
+    buf = static_cast<char *>(xcalloc(1, (strlen(header) * 3) + 1));
+    buf_cursor = buf;
+    /*
+     * We escape: space \x00-\x1F and space (0x40) and \x7F-\xFF
+     * to prevent garbage in the logs. CR and LF are also there just in case. 
+     */
+    while ((c = *(const unsigned char *) header++) != '\0') {
+	if (c == '\r') {
+	    *buf_cursor++ = '\\';
+	    *buf_cursor++ = 'r';
+	} else if (c == '\n') {
+	    *buf_cursor++ = '\\';
+	    *buf_cursor++ = 'n';
+	} else if (c <= 0x1F
+		|| c >= 0x7F
+	    || c == ' ') {
+	    *buf_cursor++ = '%';
+	    i = c * 2;
+	    *buf_cursor++ = c2x[i];
+	    *buf_cursor++ = c2x[i + 1];
+	} else {
+	    *buf_cursor++ = (char) c;
+	}
+    }
+    *buf_cursor = '\0';
+    return buf;
+}
+
+static char *
+accessLogFormatName(const char *name)
+{
+    if (NULL == name)
+	return NULL;
+    return username_quote(name);
+}
+
+static void
+accessLogSquid(AccessLogEntry * al)
+{
+    const char *client = NULL;
+    char *user = NULL;
+    if (Config.onoff.log_fqdn)
+	client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
+    if (client == NULL)
+	client = inet_ntoa(al->cache.caddr);
+    user = accessLogFormatName(al->cache.authuser ?
+	al->cache.authuser : al->cache.rfc931);
+    logfilePrintf(logfile, "%9d.%03d %6d %s %s/%03d %ld %s %s %s %s%s/%s %s",
+	(int) current_time.tv_sec,
+	(int) current_time.tv_usec / 1000,
+	al->cache.msec,
+	client,
+	log_tags[al->cache.code],
+	al->http.code,
+	(long int) al->cache.size,
+	al->_private.method_str,
+	al->url,
+	user && *user ? user : dash_str,
+	al->hier.ping.timedout ? "TIMEOUT_" : "",
+	hier_strings[al->hier.code],
+	al->hier.host,
+	al->http.content_type);
+    safe_free(user);
+}
+
+static void
+accessLogCommon(AccessLogEntry * al)
+{
+    const char *client = NULL;
+    char *user1 = NULL, *user2 = NULL;
+    if (Config.onoff.log_fqdn)
+	client = fqdncache_gethostbyaddr(al->cache.caddr, 0);
+    if (client == NULL)
+	client = inet_ntoa(al->cache.caddr);
+    user1 = accessLogFormatName(al->cache.authuser);
+    user2 = accessLogFormatName(al->cache.rfc931);
+    logfilePrintf(logfile, "%s %s %s [%s] \"%s %s HTTP/%d.%d\" %d %ld %s:%s",
+	client,
+	user2 ? user2 : dash_str,
+	user1 ? user1 : dash_str,
+	mkhttpdlogtime(&squid_curtime),
+	al->_private.method_str,
+	al->url,
+	al->http.version.major, al->http.version.minor,
+	al->http.code,
+	(long int) al->cache.size,
+	log_tags[al->cache.code],
+	hier_strings[al->hier.code]);
+    safe_free(user1);
+    safe_free(user2);
+}
+
+void
+accessLogLog(AccessLogEntry * al)
+{
+    if (LogfileStatus != LOG_ENABLE)
+	return;
+    if (al->url == NULL)
+	al->url = dash_str;
+    if (!al->http.content_type || *al->http.content_type == '\0')
+	al->http.content_type = dash_str;
+    if (al->icp.opcode)
+	al->_private.method_str = icp_opcode_str[al->icp.opcode];
+    else
+	al->_private.method_str = RequestMethodStr[al->http.method];
+    if (al->hier.host[0] == '\0')
+	xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
+
+    if (Config.onoff.common_log)
+	accessLogCommon(al);
+    else
+	accessLogSquid(al);
+    if (Config.onoff.log_mime_hdrs) {
+	char *ereq = log_quote(al->headers.request);
+	char *erep = log_quote(al->headers.reply);
+	logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
+	safe_free(ereq);
+	safe_free(erep);
+    } else {
+	logfilePrintf(logfile, "\n");
+    }
+    logfileFlush(logfile);
+#if MULTICAST_MISS_STREAM
+    if (al->cache.code != LOG_TCP_MISS)
+	(void) 0;
+    else if (al->http.method != METHOD_GET)
+	(void) 0;
+    else if (mcast_miss_fd < 0)
+	(void) 0;
+    else {
+	unsigned int ibuf[365];
+	size_t isize;
+	xstrncpy((char *) ibuf, al->url, 364 * sizeof(int));
+	isize = ((strlen(al->url) + 8) / 8) * 2;
+	if (isize > 364)
+	    isize = 364;
+	mcast_encode((unsigned int *) ibuf, isize,
+	    (const unsigned int *) Config.mcast_miss.encode_key);
+	comm_udp_sendto(mcast_miss_fd,
+	    &mcast_miss_to, sizeof(mcast_miss_to),
+	    ibuf, isize * sizeof(int));
+    }
+#endif
+}
+
+void
+accessLogRotate(void)
+{
+#if FORW_VIA_DB
+    fvdbClear();
+#endif
+    if (NULL == logfile)
+	return;
+    logfileRotate(logfile);
+#if HEADERS_LOG
+    logfileRotate(headerslog);
+#endif
+}
+
+void
+accessLogClose(void)
+{
+    if (NULL == logfile)
+	return;
+    logfileClose(logfile);
+    logfile = NULL;
+#if HEADERS_LOG
+    logfileClose(headerslog);
+    headerslog = NULL;
+#endif
+}
+
+void
+hierarchyNote(HierarchyLogEntry * hl,
+    hier_code code,
+    const char *cache_peer)
+{
+    assert(hl != NULL);
+    hl->code = code;
+    xstrncpy(hl->host, cache_peer, SQUIDHOSTNAMELEN);
+}
+
+void
+accessLogInit(void)
+{
+    assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *));
+    if (strcasecmp(Config.Log.access, "none") == 0)
+	return;
+    logfile = logfileOpen(Config.Log.access, MAX_URL << 1, 1);
+    LogfileStatus = LOG_ENABLE;
+#if HEADERS_LOG
+    headerslog = logfileOpen("/usr/local/squid/logs/headers.log", 512);
+    assert(NULL != headerslog);
+#endif
+#if FORW_VIA_DB
+    fvdbInit();
+#endif
+#if MULTICAST_MISS_STREAM
+    if (Config.mcast_miss.addr.s_addr != no_addr.s_addr) {
+	memset(&mcast_miss_to, '\0', sizeof(mcast_miss_to));
+	mcast_miss_to.sin_family = AF_INET;
+	mcast_miss_to.sin_port = htons(Config.mcast_miss.port);
+	mcast_miss_to.sin_addr.s_addr = Config.mcast_miss.addr.s_addr;
+	mcast_miss_fd = comm_open(SOCK_DGRAM,
+	    0,
+	    Config.Addrs.udp_incoming,
+	    Config.mcast_miss.port,
+	    COMM_NONBLOCKING,
+	    "Multicast Miss Stream");
+	if (mcast_miss_fd < 0)
+	    fatal("Cannot open Multicast Miss Stream Socket");
+	debug(46, 1) ("Multicast Miss Stream Socket opened on FD %d\n",
+	    mcast_miss_fd);
+	mcastSetTtl(mcast_miss_fd, Config.mcast_miss.ttl);
+	if (strlen(Config.mcast_miss.encode_key) < 16)
+	    fatal("mcast_encode_key is too short, must be 16 characters");
+    }
+#endif
+}
+
+const char *
+accessLogTime(time_t t)
+{
+    struct tm *tm;
+    static char buf[128];
+    static time_t last_t = 0;
+    if (t != last_t) {
+	tm = localtime(&t);
+	strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
+	last_t = t;
+    }
+    return buf;
+}
+
+
+#if FORW_VIA_DB
+
+static void
+fvdbInit(void)
+{
+    via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
+    forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
+    cachemgrRegister("via_headers", "Via Request Headers", fvdbDumpVia, 0, 1);
+    cachemgrRegister("forw_headers", "X-Forwarded-For Request Headers",
+	fvdbDumpForw, 0, 1);
+}
+
+static void
+fvdbCount(hash_table * hash, const char *key)
+{
+    fvdb_entry *fv;
+    if (NULL == hash)
+	return;
+    fv = hash_lookup(hash, key);
+    if (NULL == fv) {
+	fv = static_cast <fvdb_entry *>(xcalloc(1, sizeof(fvdb_entry)));
+	fv->hash.key = xstrdup(key);
+	hash_join(hash, &fv->hash);
+    }
+    fv->n++;
+}
+
+void
+fvdbCountVia(const char *key)
+{
+    fvdbCount(via_table, key);
+}
+
+void
+fvdbCountForw(const char *key)
+{
+    fvdbCount(forw_table, key);
+}
+
+static void
+fvdbDumpTable(StoreEntry * e, hash_table * hash)
+{
+    hash_link *h;
+    fvdb_entry *fv;
+    if (hash == NULL)
+	return;
+    hash_first(hash);
+    while ((h = hash_next(hash))) {
+	fv = (fvdb_entry *) h;
+	storeAppendPrintf(e, "%9d %s\n", fv->n, hashKeyStr(&fv->hash));
+    }
+}
+
+static void
+fvdbDumpVia(StoreEntry * e)
+{
+    fvdbDumpTable(e, via_table);
+}
+
+static void
+fvdbDumpForw(StoreEntry * e)
+{
+    fvdbDumpTable(e, forw_table);
+}
+
+static
+void
+fvdbFreeEntry(void *data)
+{
+    fvdb_entry *fv = data;
+    xfree(fv->hash.key);
+    xfree(fv);
+}
+
+static void
+fvdbClear(void)
+{
+    hashFreeItems(via_table, fvdbFreeEntry);
+    hashFreeMemory(via_table);
+    via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
+    hashFreeItems(forw_table, fvdbFreeEntry);
+    hashFreeMemory(forw_table);
+    forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
+}
+
+#endif
+
+#if MULTICAST_MISS_STREAM
+/*
+ * From http://www.io.com/~paulhart/game/algorithms/tea.html
+ *
+ * size of 'ibuf' must be a multiple of 2.
+ * size of 'key' must be 4.
+ * 'ibuf' is modified in place, encrypted data is written in
+ * network byte order.
+ */
+static void
+mcast_encode(unsigned int *ibuf, size_t isize, const unsigned int *key)
+{
+    unsigned int y;
+    unsigned int z;
+    unsigned int sum;
+    const unsigned int delta = 0x9e3779b9;
+    unsigned int n = 32;
+    const unsigned int k0 = htonl(key[0]);
+    const unsigned int k1 = htonl(key[1]);
+    const unsigned int k2 = htonl(key[2]);
+    const unsigned int k3 = htonl(key[3]);
+    int i;
+    for (i = 0; i < isize; i += 2) {
+	y = htonl(ibuf[i]);
+	z = htonl(ibuf[i + 1]);
+	sum = 0;
+	for (n = 32; n; n--) {
+	    sum += delta;
+	    y += (z << 4) + (k0 ^ z) + (sum ^ (z >> 5)) + k1;
+	    z += (y << 4) + (k2 ^ y) + (sum ^ (y >> 5)) + k3;
+	}
+	ibuf[i] = htonl(y);
+	ibuf[i + 1] = htonl(z);
+    }
+}
+
+#endif
+
+#if HEADERS_LOG
+void
+headersLog(int cs, int pq, method_t m, void *data)
+{
+    HttpReply *rep;
+    request_t *req;
+    unsigned short magic = 0;
+    unsigned char M = (unsigned char) m;
+    unsigned short S;
+    char *hmask;
+    int ccmask = 0;
+    if (0 == pq) {
+	/* reply */
+	rep = data;
+	req = NULL;
+	magic = 0x0050;
+	hmask = rep->header.mask;
+	if (rep->cache_control)
+	    ccmask = rep->cache_control->mask;
+    } else {
+	/* request */
+	req = data;
+	rep = NULL;
+	magic = 0x0051;
+	hmask = req->header.mask;
+	if (req->cache_control)
+	    ccmask = req->cache_control->mask;
+    }
+    if (0 == cs) {
+	/* client */
+	magic |= 0x4300;
+    } else {
+	/* server */
+	magic |= 0x5300;
+    }
+    magic = htons(magic);
+    ccmask = htonl(ccmask);
+    if (0 == pq)
+	S = (unsigned short) rep->sline.status;
+    else
+	S = (unsigned short) HTTP_STATUS_NONE;
+    logfileWrite(headerslog, &magic, sizeof(magic));
+    logfileWrite(headerslog, &M, sizeof(M));
+    logfileWrite(headerslog, &S, sizeof(S));
+    logfileWrite(headerslog, hmask, sizeof(HttpHeaderMask));
+    logfileWrite(headerslog, &ccmask, sizeof(int));
+    logfileFlush(headerslog);
+}
+
+#endif
+
+void
+accessLogFreeMemory(AccessLogEntry * aLogEntry)
+{
+    safe_free(aLogEntry->headers.request);
+    safe_free(aLogEntry->headers.reply);
+    safe_free(aLogEntry->cache.authuser);
+}
+
+int
+logTypeIsATcpHit(log_type code)
+{
+    /* this should be a bitmap for better optimization */
+    if (code == LOG_TCP_HIT)
+	return 1;
+    if (code == LOG_TCP_IMS_HIT)
+	return 1;
+    if (code == LOG_TCP_REFRESH_FAIL_HIT)
+	return 1;
+    if (code == LOG_TCP_REFRESH_HIT)
+	return 1;
+    if (code == LOG_TCP_NEGATIVE_HIT)
+	return 1;
+    if (code == LOG_TCP_MEM_HIT)
+	return 1;
+    if (code == LOG_TCP_OFFLINE_HIT)
+	return 1;
+    return 0;
+}
+
Index: squid/src/acl.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/acl.c,v
retrieving revision 1.60
retrieving revision 1.60.2.1
diff -u -r1.60 -r1.60.2.1
--- squid/src/acl.c	2 Oct 2002 11:10:45 -0000	1.60
+++ squid/src/acl.c	3 Oct 2002 01:04:33 -0000	1.60.2.1
@@ -1,6 +1,5 @@
-
 /*
- * $Id: acl.c,v 1.60 2002/10/02 11:10:45 squidadm Exp $
+ * $Id: acl.c,v 1.60.2.1 2002/10/03 01:04:33 rbcollins Exp $
  *
  * DEBUG: section 28    Access Control
  * AUTHOR: Duane Wessels
@@ -35,6 +34,7 @@
 
 #include "squid.h"
 #include "splay.h"
+#include "authenticate.h"
 
 static void aclParseDomainList(void *curlist);
 static void aclParseUserList(void **current);
@@ -54,7 +54,7 @@
 static struct _acl *aclFindByName(const char *name);
 static int aclMatchAcl(struct _acl *, aclCheck_t *);
 static int aclMatchTime(acl_time_data * data, time_t when);
-static int aclMatchUser(void *proxyauth_acl, char *user);
+static int aclMatchUser(void *proxyauth_acl, char const *user);
 static int aclMatchIp(void *dataptr, struct in_addr c);
 static int aclMatchDomainList(void *dataptr, const char *);
 static int aclMatchIntegerRange(intrange * data, int i);
@@ -101,7 +101,7 @@
 static SPLAYCMP aclArpCompare;
 static SPLAYWALKEE aclDumpArpListWalkee;
 #endif
-static int aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, char *MatchParam);
+static int aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, char const *MatchParam);
 
 static squid_acl
 aclStrToType(const char *s)
@@ -1070,7 +1070,7 @@
 }
 
 static int
-aclMatchUser(void *proxyauth_acl, char *user)
+aclMatchUser(void *proxyauth_acl, char const *user)
 {
     acl_user_data *data = (acl_user_data *) proxyauth_acl;
     splayNode *Top = data->names;
@@ -1116,7 +1116,7 @@
  */
 static int
 aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data,
-    char *MatchParam)
+    char const *MatchParam)
 {
     int matchrv;
     acl_proxy_auth_match_cache *auth_match;
Index: squid/src/auth_modules.sh
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/auth_modules.sh,v
retrieving revision 1.2
retrieving revision 1.2.108.1
diff -u -r1.2 -r1.2.108.1
--- squid/src/auth_modules.sh	8 Jan 2001 00:02:37 -0000	1.2
+++ squid/src/auth_modules.sh	3 Oct 2002 01:04:33 -0000	1.2.108.1
@@ -3,6 +3,7 @@
 echo " * do not edit"
 echo " */"
 echo "#include \"squid.h\""
+echo "#include \"authenticate.h\""
 echo ""
 for module in "$@"; do
    echo "extern AUTHSSETUP authSchemeSetup_${module};"
--- squid/src/authenticate.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,999 +0,0 @@
-
-/*
- * $Id: authenticate.c,v 1.27 2002/09/26 21:46:04 squidadm Exp $
- *
- * DEBUG: section 29    Authenticator
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-/* The functions in this file handle authentication.
- * They DO NOT perform access control or auditing.
- * See acl.c for access control and client_side.c for auditing */
-
-
-#include "squid.h"
-
-CBDATA_TYPE(auth_user_ip_t);
-
-static void
-     authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request);
-static auth_acl_t authenticateAuthenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr);
-
-/*
- *
- * Private Data
- *
- */
-
-MemPool *auth_user_request_pool = NULL;
-
-/* Generic Functions */
-
-
-static int
-authenticateAuthSchemeConfigured(const char *proxy_auth)
-{
-    authScheme *scheme;
-    int i;
-    for (i = 0; i < Config.authConfig.n_configured; i++) {
-	scheme = Config.authConfig.schemes + i;
-	if ((strncasecmp(proxy_auth, scheme->typestr, strlen(scheme->typestr)) == 0) &&
-	    (authscheme_list[scheme->Id].Active()))
-	    return 1;
-    }
-    return 0;
-}
-
-int
-authenticateAuthSchemeId(const char *typestr)
-{
-    int i = 0;
-    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
-	if (strncasecmp(typestr, authscheme_list[i].typestr, strlen(authscheme_list[i].typestr)) == 0) {
-	    return i;
-	}
-    }
-    return -1;
-}
-
-void
-authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request)
-{
-    int i = 0;
-    assert(proxy_auth != NULL);
-    assert(auth_user_request != NULL);	/* we need this created for us. */
-    debug(29, 9) ("authenticateDecodeAuth: header = '%s'\n", proxy_auth);
-    if (authenticateAuthSchemeConfigured(proxy_auth)) {
-	/* we're configured to use this scheme - but is it active ? */
-	if ((i = authenticateAuthSchemeId(proxy_auth)) != -1) {
-	    authscheme_list[i].decodeauth(auth_user_request, proxy_auth);
-	    auth_user_request->auth_user->auth_module = i + 1;
-	    return;
-	}
-    }
-    debug(29, 1)
-	("authenticateDecodeAuth: Unsupported or unconfigured proxy-auth scheme, '%s'\n",
-	proxy_auth);
-    return;
-}
-
-/* clear any connection related authentication details */
-void
-authenticateOnCloseConnection(ConnStateData * conn)
-{
-    auth_user_request_t *auth_user_request;
-    assert(conn != NULL);
-    if (conn->auth_user_request != NULL) {
-	auth_user_request = conn->auth_user_request;
-	/* if the auth type gets reset, the connection shouldn't 
-	 * remain linked to it - the next type might not be conn based
-	 */
-	assert(auth_user_request->auth_user->auth_module);
-	if (authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection) {
-	    authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection(conn);
-	}
-    }
-}
-
-/**** PUBLIC FUNCTIONS (ALL GENERIC!)  ****/
-
-/* send the initial data to an authenticator module */
-void
-authenticateStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
-{
-    assert(auth_user_request);
-    assert(handler);
-    debug(29, 9) ("authenticateStart: auth_user_request '%p'\n", auth_user_request);
-    if (auth_user_request->auth_user->auth_module > 0)
-	authscheme_list[auth_user_request->auth_user->auth_module - 1].authStart(auth_user_request, handler, data);
-    else
-	handler(data, NULL);
-}
-
-/*
- * Check a auth_user pointer for validity. Does not check passwords, just data
- * sensability. Broken or Unknown auth_types are not valid for use...
- */
-
-int
-authenticateValidateUser(auth_user_request_t * auth_user_request)
-{
-    debug(29, 9) ("authenticateValidateUser: Validating Auth_user request '%p'.\n", auth_user_request);
-    if (auth_user_request == NULL) {
-	debug(29, 4) ("authenticateValidateUser: Auth_user_request was NULL!\n");
-	return 0;
-    }
-    if (auth_user_request->auth_user == NULL) {
-	debug(29, 4) ("authenticateValidateUser: No associated auth_user structure\n");
-	return 0;
-    }
-    if (auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) {
-	debug(29, 4) ("authenticateValidateUser: Auth_user '%p' uses unknown scheme.\n", auth_user_request->auth_user);
-	return 0;
-    }
-    if (auth_user_request->auth_user->auth_type == AUTH_BROKEN) {
-	debug(29, 4) ("authenticateValidateUser: Auth_user '%p' is broken for it's scheme.\n", auth_user_request->auth_user);
-	return 0;
-    }
-    if (!auth_user_request->auth_user->scheme_data) {
-	debug(29, 4) ("authenticateValidateUser: auth_user '%p' has no scheme data\n", auth_user_request->auth_user);
-	return 0;
-    }
-    /* any other sanity checks that we need in the future */
-
-    /* Thus should a module call to something like authValidate */
-
-    /* finally return ok */
-    debug(29, 5) ("authenticateValidateUser: Validated Auth_user request '%p'.\n", auth_user_request);
-    return 1;
-
-}
-
-auth_user_t *
-authenticateAuthUserNew(const char *scheme)
-{
-    auth_user_t *temp_auth;
-    temp_auth = memAllocate(MEM_AUTH_USER_T);
-    assert(temp_auth != NULL);
-    memset(temp_auth, '\0', sizeof(auth_user_t));
-    temp_auth->auth_type = AUTH_UNKNOWN;
-    temp_auth->references = 0;
-    temp_auth->auth_module = authenticateAuthSchemeId(scheme) + 1;
-    temp_auth->usernamehash = NULL;
-    return temp_auth;
-}
-
-static auth_user_request_t *
-authenticateAuthUserRequestNew(void)
-{
-    auth_user_request_t *temp_request;
-    if (!auth_user_request_pool)
-	auth_user_request_pool = memPoolCreate("Authenticate Request Data", sizeof(auth_user_request_t));
-    temp_request = memPoolAlloc(auth_user_request_pool);
-    assert(temp_request != NULL);
-    memset(temp_request, '\0', sizeof(auth_user_request_t));
-    return temp_request;
-}
-
-static void
-authenticateAuthUserRequestFree(auth_user_request_t * auth_user_request)
-{
-    dlink_node *link;
-    debug(29, 5) ("authenticateAuthUserRequestFree: freeing request %p\n", auth_user_request);
-    if (!auth_user_request)
-	return;
-    assert(auth_user_request->references == 0);
-    if (auth_user_request->auth_user) {
-	if (auth_user_request->scheme_data != NULL) {
-	    /* we MUST know the module */
-	    assert((auth_user_request->auth_user->auth_module > 0));
-	    /* and the module MUST support requestFree if it has created scheme data */
-	    assert(authscheme_list[auth_user_request->auth_user->auth_module - 1].requestFree != NULL);
-	    authscheme_list[auth_user_request->auth_user->auth_module - 1].requestFree(auth_user_request);
-	}
-	/* unlink from the auth_user struct */
-	link = auth_user_request->auth_user->requests.head;
-	while (link && (link->data != auth_user_request))
-	    link = link->next;
-	assert(link != NULL);
-	dlinkDelete(link, &auth_user_request->auth_user->requests);
-	dlinkNodeDelete(link);
-
-	/* unlock the request structure's lock */
-	authenticateAuthUserUnlock(auth_user_request->auth_user);
-	auth_user_request->auth_user = NULL;
-    } else
-	assert(auth_user_request->scheme_data == NULL);
-    if (auth_user_request->message)
-	xfree(auth_user_request->message);
-    memPoolFree(auth_user_request_pool, auth_user_request);
-}
-
-char *
-authenticateAuthUserRequestMessage(auth_user_request_t * auth_user_request)
-{
-    if (auth_user_request)
-	return auth_user_request->message;
-    return NULL;
-}
-
-void
-authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr)
-{
-    auth_user_ip_t *ipdata, *tempnode;
-    auth_user_t *auth_user;
-    char *ip1;
-    int found = 0;
-    CBDATA_INIT_TYPE(auth_user_ip_t);
-    if (!auth_user_request->auth_user)
-	return;
-    auth_user = auth_user_request->auth_user;
-    ipdata = (auth_user_ip_t *) auth_user->ip_list.head;
-    /*
-     * we walk the entire list to prevent the first item in the list
-     * preventing old entries being flushed and locking a user out after
-     * a timeout+reconfigure
-     */
-    while (ipdata) {
-	tempnode = (auth_user_ip_t *) ipdata->node.next;
-	/* walk the ip list */
-	if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
-	    /* This ip has alreadu been seen. */
-	    found = 1;
-	    /* update IP ttl */
-	    ipdata->ip_expiretime = squid_curtime;
-	} else if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) {
-	    /* This IP has expired - remove from the seen list */
-	    dlinkDelete(&ipdata->node, &auth_user->ip_list);
-	    cbdataFree(ipdata);
-	    /* catch incipient underflow */
-	    assert(auth_user->ipcount);
-	    auth_user->ipcount--;
-	}
-	ipdata = tempnode;
-    }
-
-    if (found)
-	return;
-
-    /* This ip is not in the seen list */
-    ipdata = cbdataAlloc(auth_user_ip_t);
-    ipdata->ip_expiretime = squid_curtime;
-    ipdata->ipaddr = ipaddr;
-    dlinkAddTail(ipdata, &ipdata->node, &auth_user->ip_list);
-    auth_user->ipcount++;
-
-    ip1 = xstrdup(inet_ntoa(ipaddr));
-    debug(29, 2) ("authenticateAuthUserRequestSetIp: user '%s' has been seen at a new IP address (%s)\n ", authenticateUserUsername(auth_user), ip1);
-    safe_free(ip1);
-}
-
-void
-authenticateAuthUserRequestRemoveIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr)
-{
-    auth_user_ip_t *ipdata;
-    auth_user_t *auth_user;
-    if (!auth_user_request->auth_user)
-	return;
-    auth_user = auth_user_request->auth_user;
-    ipdata = (auth_user_ip_t *) auth_user->ip_list.head;
-    while (ipdata) {
-	/* walk the ip list */
-	if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
-	    /* remove the node */
-	    dlinkDelete(&ipdata->node, &auth_user->ip_list);
-	    cbdataFree(ipdata);
-	    /* catch incipient underflow */
-	    assert(auth_user->ipcount);
-	    auth_user->ipcount--;
-	    return;
-	}
-	ipdata = (auth_user_ip_t *) ipdata->node.next;
-    }
-
-}
-
-static void
-authenticateAuthUserClearIp(auth_user_t * auth_user)
-{
-    auth_user_ip_t *ipdata, *tempnode;
-    if (!auth_user)
-	return;
-    ipdata = (auth_user_ip_t *) auth_user->ip_list.head;
-    while (ipdata) {
-	tempnode = (auth_user_ip_t *) ipdata->node.next;
-	/* walk the ip list */
-	dlinkDelete(&ipdata->node, &auth_user->ip_list);
-	cbdataFree(ipdata);
-	/* catch incipient underflow */
-	assert(auth_user->ipcount);
-	auth_user->ipcount--;
-	ipdata = tempnode;
-    }
-    /* integrity check */
-    assert(auth_user->ipcount == 0);
-}
-
-
-void
-authenticateAuthUserRequestClearIp(auth_user_request_t * auth_user_request)
-{
-    if (auth_user_request)
-	authenticateAuthUserClearIp(auth_user_request->auth_user);
-}
-
-size_t
-authenticateAuthUserRequestIPCount(auth_user_request_t * auth_user_request)
-{
-    assert(auth_user_request);
-    assert(auth_user_request->auth_user);
-    return auth_user_request->auth_user->ipcount;
-}
-
-
-/* Get Auth User: Return a filled out auth_user structure for the given
- * Proxy Auth (or Auth) header. It may be a cached Auth User or a new
- * Unauthenticated structure. The structure is given an inital lock here.
- */
-static auth_user_request_t *
-authenticateGetAuthUser(const char *proxy_auth)
-{
-    auth_user_request_t *auth_user_request = authenticateAuthUserRequestNew();
-    /* and lock for the callers instance */
-    authenticateAuthUserRequestLock(auth_user_request);
-    /* The scheme is allowed to provide a cached auth_user or a new one */
-    authenticateDecodeAuth(proxy_auth, auth_user_request);
-    return auth_user_request;
-}
-
-/*
- * authenticateUserAuthenticated: is this auth_user structure logged in ?
- */
-int
-authenticateUserAuthenticated(auth_user_request_t * auth_user_request)
-{
-    if (!authenticateValidateUser(auth_user_request))
-	return 0;
-    if (auth_user_request->auth_user->auth_module > 0)
-	return authscheme_list[auth_user_request->auth_user->auth_module - 1].authenticated(auth_user_request);
-    else
-	return 0;
-}
-
-/*
- * authenticateAuthenticateUser: call the module specific code to 
- * log this user request in.
- * Cache hits may change the auth_user pointer in the structure if needed.
- * This is basically a handle approach.
- */
-static void
-authenticateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
-{
-    assert(auth_user_request != NULL);
-    if (auth_user_request->auth_user->auth_module > 0)
-	authscheme_list[auth_user_request->auth_user->auth_module - 1].authAuthenticate(auth_user_request, request, conn, type);
-}
-
-/* returns one of
- * AUTH_ACL_CHALLENGE,
- * AUTH_ACL_HELPER,
- * AUTH_ACL_CANNOT_AUTHENTICATE,
- * AUTH_AUTHENTICATED
- *
- * How to use: In your proxy-auth dependent acl code, use the following 
- * construct:
- * int rv;
- * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED)
- *   return rv;
- * 
- * when this code is reached, the request/connection is authenticated.
- *
- * if you have non-acl code, but want to force authentication, you need a 
- * callback mechanism like the acl testing routines that will send a 40[1|7] to
- * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with 
- * the authenticateStart routine for rv==AUTH_ACL_HELPER
- */
-auth_acl_t
-authenticateAuthenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr)
-{
-    const char *proxy_auth;
-    assert(headertype != 0);
-
-    proxy_auth = httpHeaderGetStr(&request->header, headertype);
-
-    if (conn == NULL) {
-	debug(28, 1) ("authenticateAuthenticate: no connection data, cannot process authentication\n");
-	/*
-	 * deny access: clientreadrequest requires conn data, and it is always
-	 * compiled in so we should have it too.
-	 */
-	return AUTH_ACL_CANNOT_AUTHENTICATE;
-    }
-    /*
-     * a note on proxy_auth logix here:
-     * proxy_auth==NULL -> unauthenticated request || already authenticated connection
-     * so we test for an authenticated connection when we recieve no authentication
-     * header.
-     */
-    if (((proxy_auth == NULL) && (!authenticateUserAuthenticated(*auth_user_request ? *auth_user_request : conn->auth_user_request)))
-	|| (conn->auth_type == AUTH_BROKEN)) {
-	/* no header or authentication failed/got corrupted - restart */
-	conn->auth_type = AUTH_UNKNOWN;
-	debug(28, 4) ("authenticateAuthenticate: broken auth or no proxy_auth header. Requesting auth header.\n");
-	/* something wrong with the AUTH credentials. Force a new attempt */
-	if (conn->auth_user_request) {
-	    authenticateAuthUserRequestUnlock(conn->auth_user_request);
-	    conn->auth_user_request = NULL;
-	}
-	if (*auth_user_request) {
-	    /* unlock the ACL lock */
-	    authenticateAuthUserRequestUnlock(*auth_user_request);
-	    auth_user_request = NULL;
-	}
-	return AUTH_ACL_CHALLENGE;
-    }
-    /* 
-     * Is this an already authenticated connection with a new auth header?
-     * No check for function required in the if: its compulsory for conn based 
-     * auth modules
-     */
-    if (proxy_auth && conn->auth_user_request &&
-	authenticateUserAuthenticated(conn->auth_user_request) &&
-	strcmp(proxy_auth, authscheme_list[conn->auth_user_request->auth_user->auth_module - 1].authConnLastHeader(conn->auth_user_request))) {
-	debug(28, 2) ("authenticateAuthenticate: DUPLICATE AUTH - authentication header on already authenticated connection!. AU %p, Current user '%s' proxy_auth %s\n", conn->auth_user_request, authenticateUserRequestUsername(conn->auth_user_request), proxy_auth);
-	/* remove this request struct - the link is already authed and it can't be to 
-	 * reauth.
-	 */
-
-	/* This should _only_ ever occur on the first pass through 
-	 * authenticateAuthenticate 
-	 */
-	assert(*auth_user_request == NULL);
-	/* unlock the conn lock on the auth_user_request */
-	authenticateAuthUserRequestUnlock(conn->auth_user_request);
-	/* mark the conn as non-authed. */
-	conn->auth_user_request = NULL;
-	/* Set the connection auth type */
-	conn->auth_type = AUTH_UNKNOWN;
-    }
-    /* we have a proxy auth header and as far as we know this connection has
-     * not had bungled connection oriented authentication happen on it. */
-    debug(28, 9) ("authenticateAuthenticate: header %s.\n", proxy_auth);
-    if (*auth_user_request == NULL) {
-	debug(28, 9) ("authenticateAuthenticate: This is a new checklist test on FD:%d\n",
-	    conn->fd);
-	if ((!request->auth_user_request)
-	    && (conn->auth_type == AUTH_UNKNOWN)) {
-	    /* beginning of a new request check */
-	    debug(28, 4) ("authenticateAuthenticate: no connection authentication type\n");
-	    if (!authenticateValidateUser(*auth_user_request =
-		    authenticateGetAuthUser(proxy_auth))) {
-		/* the decode might have left a username for logging, or a message to
-		 * the user */
-		if (authenticateUserRequestUsername(*auth_user_request)) {
-		    /* lock the user for the request structure link */
-		    authenticateAuthUserRequestLock(*auth_user_request);
-		    request->auth_user_request = *auth_user_request;
-		}
-		/* unlock the ACL reference granted by ...GetAuthUser. */
-		authenticateAuthUserRequestUnlock(*auth_user_request);
-		*auth_user_request = NULL;
-		return AUTH_ACL_CHALLENGE;
-	    }
-	    /* the user_request comes prelocked for the caller to GetAuthUser (us) */
-	} else if (request->auth_user_request) {
-	    *auth_user_request = request->auth_user_request;
-	    /* lock the user request for this ACL processing */
-	    authenticateAuthUserRequestLock(*auth_user_request);
-	} else {
-	    if (conn->auth_user_request != NULL) {
-		*auth_user_request = conn->auth_user_request;
-		/* lock the user request for this ACL processing */
-		authenticateAuthUserRequestLock(*auth_user_request);
-	    } else {
-		/* failed connection based authentication */
-		debug(28, 4) ("authenticateAuthenticate: Auth user request %p conn-auth user request %p conn type %d authentication failed.\n",
-		    *auth_user_request, conn->auth_user_request, conn->auth_type);
-		authenticateAuthUserRequestUnlock(*auth_user_request);
-		*auth_user_request = NULL;
-		return AUTH_ACL_CHALLENGE;
-	    }
-	}
-    }
-    if (!authenticateUserAuthenticated(*auth_user_request)) {
-	/* User not logged in. Log them in */
-	authenticateAuthenticateUser(*auth_user_request, request,
-	    conn, headertype);
-	switch (authenticateDirection(*auth_user_request)) {
-	case 1:
-	case -2:
-	    /* this ACL check is finished. Unlock. */
-	    authenticateAuthUserRequestUnlock(*auth_user_request);
-	    *auth_user_request = NULL;
-	    return AUTH_ACL_CHALLENGE;
-	case -1:
-	    /* we are partway through authentication within squid,
-	     * the *auth_user_request variables stores the auth_user_request
-	     * for the callback to here - Do not Unlock */
-	    return AUTH_ACL_HELPER;
-	}
-	/* on 0 the authentication is finished - fallthrough */
-	/* See if user authentication failed for some reason */
-	if (!authenticateUserAuthenticated(*auth_user_request)) {
-	    if ((authenticateUserRequestUsername(*auth_user_request))) {
-		if (!request->auth_user_request) {
-		    /* lock the user for the request structure link */
-		    authenticateAuthUserRequestLock(*auth_user_request);
-		    request->auth_user_request = *auth_user_request;
-		}
-	    }
-	    /* this ACL check is finished. Unlock. */
-	    authenticateAuthUserRequestUnlock(*auth_user_request);
-	    *auth_user_request = NULL;
-	    return AUTH_ACL_CHALLENGE;
-	}
-    }
-    /* copy username to request for logging on client-side */
-    /* the credentials are correct at this point */
-    if (!request->auth_user_request) {
-	/* lock the user for the request structure link */
-	authenticateAuthUserRequestLock(*auth_user_request);
-	request->auth_user_request = *auth_user_request;
-	authenticateAuthUserRequestSetIp(*auth_user_request, src_addr);
-    }
-    /* Unlock the request - we've authenticated it */
-    authenticateAuthUserRequestUnlock(*auth_user_request);
-    return AUTH_AUTHENTICATED;
-}
-
-auth_acl_t
-authenticateTryToAuthenticateAndSetAuthUser(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr)
-{
-    /* If we have already been called, return the cached value */
-    auth_user_request_t *t = *auth_user_request ? *auth_user_request : conn->auth_user_request;
-    auth_acl_t result;
-    if (t && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE
-	&& t->lastReply != AUTH_ACL_HELPER) {
-	if (!*auth_user_request)
-	    *auth_user_request = t;
-	return t->lastReply;
-    }
-    /* ok, call the actual authenticator routine. */
-    result = authenticateAuthenticate(auth_user_request, headertype, request, conn, src_addr);
-    t = *auth_user_request ? *auth_user_request : conn->auth_user_request;
-    if (t && result != AUTH_ACL_CANNOT_AUTHENTICATE &&
-	result != AUTH_ACL_HELPER)
-	t->lastReply = result;
-    return result;
-}
-
-
-/* authenticateUserUsername: return a pointer to the username in the */
-char *
-authenticateUserUsername(auth_user_t * auth_user)
-{
-    if (!auth_user)
-	return NULL;
-    if (auth_user->auth_module > 0)
-	return authscheme_list[auth_user->auth_module - 1].authUserUsername(auth_user);
-    return NULL;
-}
-
-/* authenticateUserRequestUsername: return a pointer to the username in the */
-char *
-authenticateUserRequestUsername(auth_user_request_t * auth_user_request)
-{
-    assert(auth_user_request != NULL);
-    if (auth_user_request->auth_user)
-	return authenticateUserUsername(auth_user_request->auth_user);
-    else
-	return NULL;
-}
-
-/* returns
- * 0: no output needed
- * 1: send to client
- * -1: send to helper
- * -2: authenticate broken in some fashion
- */
-int
-authenticateDirection(auth_user_request_t * auth_user_request)
-{
-    if (!auth_user_request)
-	return -2;
-    if (authenticateUserAuthenticated(auth_user_request))
-	return 0;
-    if (auth_user_request->auth_user->auth_module > 0)
-	return authscheme_list[auth_user_request->auth_user->auth_module - 1].getdirection(auth_user_request);
-    return -2;
-}
-
-int
-authenticateActiveSchemeCount(void)
-{
-    int i = 0, rv = 0;
-    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
-	if (authscheme_list[i].configured())
-	    rv++;
-    debug(29, 9) ("authenticateActiveSchemeCount: %d active.\n", rv);
-    return rv;
-}
-
-int
-authenticateSchemeCount(void)
-{
-    int i = 0, rv = 0;
-    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
-	rv++;
-    debug(29, 9) ("authenticateSchemeCount: %d active.\n", rv);
-    return rv;
-}
-
-void
-authenticateSchemeInit(void)
-{
-    authSchemeSetup();
-}
-
-void
-authenticateInit(authConfig * config)
-{
-    int i;
-    authScheme *scheme;
-    for (i = 0; i < config->n_configured; i++) {
-	scheme = config->schemes + i;
-	if (authscheme_list[scheme->Id].init && authscheme_list[scheme->Id].configured()) {
-	    authscheme_list[scheme->Id].init(scheme);
-	}
-    }
-    if (!proxy_auth_username_cache)
-	authenticateInitUserCache();
-}
-
-static void
-authenticateProxyUserCacheFree(void *usernamehash_p)
-{
-    auth_user_hash_pointer *usernamehash = usernamehash_p;
-    auth_user_t *auth_user;
-    char *username = NULL;
-    auth_user = usernamehash->auth_user;
-    username = authenticateUserUsername(auth_user);
-    if ((authenticateAuthUserInuse(auth_user) - 1))
-	debug(29, 1) ("authenticateProxyUserCacheFree: entry in use\n");
-    authenticateAuthUserUnlock(auth_user);
-}
-
-void
-authenticateShutdown(void)
-{
-    int i;
-    debug(29, 2) ("authenticateShutdown: shutting down auth schemes\n");
-    /* free the cache if we are shutting down */
-    if (shutting_down)
-	hashFreeItems(proxy_auth_username_cache, authenticateProxyUserCacheFree);
-
-    /* find the currently known authscheme types */
-    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
-	if (authscheme_list[i].donefunc != NULL)
-	    authscheme_list[i].donefunc();
-	else
-	    debug(29, 2) ("authenticateShutdown: scheme %s has not registered a shutdown function.\n", authscheme_list[i].typestr);
-	if (shutting_down)
-	    authscheme_list[i].typestr = NULL;
-    }
-}
-
-void
-authenticateFixHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated, int internal)
-/* send the auth types we are configured to support (and have compiled in!) */
-{
-    int type = 0;
-    switch (rep->sline.status) {
-    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
-	/* Proxy authorisation needed */
-	type = HDR_PROXY_AUTHENTICATE;
-	break;
-    case HTTP_UNAUTHORIZED:
-	/* WWW Authorisation needed */
-	type = HDR_WWW_AUTHENTICATE;
-	break;
-    default:
-	/* Keep GCC happy */
-	/* some other HTTP status */
-	break;
-    }
-    debug(29, 9) ("authenticateFixHeader: headertype:%d authuser:%p\n", type, auth_user_request);
-    if (((rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
-	    || (rep->sline.status == HTTP_UNAUTHORIZED)) && internal)
-	/* this is a authenticate-needed response */
-    {
-	if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0) & !authenticateUserAuthenticated(auth_user_request))
-	    authscheme_list[auth_user_request->auth_user->auth_module - 1].authFixHeader(auth_user_request, rep, type, request);
-	else {
-	    int i;
-	    authScheme *scheme;
-	    /* call each configured & running authscheme */
-	    for (i = 0; i < Config.authConfig.n_configured; i++) {
-		scheme = Config.authConfig.schemes + i;
-		if (authscheme_list[scheme->Id].Active())
-		    authscheme_list[scheme->Id].authFixHeader(NULL, rep, type,
-			request);
-		else
-		    debug(29, 4) ("authenticateFixHeader: Configured scheme %s not Active\n", scheme->typestr);
-	    }
-	}
-    }
-    /* allow protocol specific headers to be _added_ to the existing response - ie
-     * digest auth
-     */
-    if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
-	&& (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader))
-	authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader(auth_user_request, rep, accelerated);
-    if (auth_user_request != NULL)
-	auth_user_request->lastReply = AUTH_ACL_CANNOT_AUTHENTICATE;
-}
-
-/* call the active auth module and allow it to add a trailer to the request */
-void
-authenticateAddTrailer(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated)
-{
-    if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
-	&& (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer))
-	authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer(auth_user_request, rep, accelerated);
-}
-
-void
-authenticateAuthUserLock(auth_user_t * auth_user)
-{
-    debug(29, 9) ("authenticateAuthUserLock auth_user '%p'.\n", auth_user);
-    assert(auth_user != NULL);
-    auth_user->references++;
-    debug(29, 9) ("authenticateAuthUserLock auth_user '%p' now at '%ld'.\n", auth_user, (long int) auth_user->references);
-}
-
-void
-authenticateAuthUserUnlock(auth_user_t * auth_user)
-{
-    debug(29, 9) ("authenticateAuthUserUnlock auth_user '%p'.\n", auth_user);
-    assert(auth_user != NULL);
-    if (auth_user->references > 0) {
-	auth_user->references--;
-    } else {
-	debug(29, 1) ("Attempt to lower Auth User %p refcount below 0!\n", auth_user);
-    }
-    debug(29, 9) ("authenticateAuthUserUnlock auth_user '%p' now at '%ld'.\n", auth_user, (long int) auth_user->references);
-    if (auth_user->references == 0)
-	authenticateFreeProxyAuthUser(auth_user);
-}
-
-void
-authenticateAuthUserRequestLock(auth_user_request_t * auth_user_request)
-{
-    debug(29, 9) ("authenticateAuthUserRequestLock auth_user request '%p'.\n", auth_user_request);
-    assert(auth_user_request != NULL);
-    auth_user_request->references++;
-    debug(29, 9) ("authenticateAuthUserRequestLock auth_user request '%p' now at '%ld'.\n", auth_user_request, (long int) auth_user_request->references);
-}
-
-void
-authenticateAuthUserRequestUnlock(auth_user_request_t * auth_user_request)
-{
-    debug(29, 9) ("authenticateAuthUserRequestUnlock auth_user request '%p'.\n", auth_user_request);
-    assert(auth_user_request != NULL);
-    if (auth_user_request->references > 0) {
-	auth_user_request->references--;
-    } else {
-	debug(29, 1) ("Attempt to lower Auth User request %p refcount below 0!\n", auth_user_request);
-    }
-    debug(29, 9) ("authenticateAuthUserRequestUnlock auth_user_request '%p' now at '%ld'.\n", auth_user_request, (long int) auth_user_request->references);
-    if (auth_user_request->references == 0) {
-	/* not locked anymore */
-	authenticateAuthUserRequestFree(auth_user_request);
-    }
-}
-
-int
-authenticateAuthUserInuse(auth_user_t * auth_user)
-/* returns 0 for not in use */
-{
-    assert(auth_user != NULL);
-    return auth_user->references;
-}
-
-/* Combine two user structs. ONLY to be called from within a scheme module.
- * The scheme module is responsible for ensuring that the two users _can_ be merged 
- * without invalidating all the request scheme data. 
- * the scheme is also responsible for merging any user related scheme data itself. */
-void
-authenticateAuthUserMerge(auth_user_t * from, auth_user_t * to)
-{
-    dlink_node *link, *tmplink;
-    auth_user_request_t *auth_user_request;
-/* XXX combine two authuser structs. Incomplete: it should merge in hash references 
- * too and ask the module to merge in scheme data */
-    debug(29, 5) ("authenticateAuthUserMerge auth_user '%p' into auth_user '%p'.\n", from, to);
-    link = from->requests.head;
-    while (link) {
-	auth_user_request = link->data;
-	tmplink = link;
-	link = link->next;
-	dlinkDelete(tmplink, &from->requests);
-	dlinkAddTail(auth_user_request, tmplink, &to->requests);
-	auth_user_request->auth_user = to;
-    }
-    to->references += from->references;
-    from->references = 0;
-    authenticateFreeProxyAuthUser(from);
-}
-
-void
-authenticateFreeProxyAuthUser(void *data)
-{
-    auth_user_t *u = data;
-    auth_user_request_t *auth_user_request;
-    dlink_node *link, *tmplink;
-    assert(data != NULL);
-    debug(29, 5) ("authenticateFreeProxyAuthUser: Freeing auth_user '%p' with refcount '%ld'.\n", u, (long int) u->references);
-    assert(u->references == 0);
-    /* were they linked in by username ? */
-    if (u->usernamehash) {
-	assert(u->usernamehash->auth_user == u);
-	debug(29, 5) ("authenticateFreeProxyAuthUser: removing usernamehash entry '%p'\n", u->usernamehash);
-	hash_remove_link(proxy_auth_username_cache,
-	    (hash_link *) u->usernamehash);
-	/* don't free the key as we use the same user string as the auth_user 
-	 * structure */
-	memFree(u->usernamehash, MEM_AUTH_USER_HASH);
-    }
-    /* remove any outstanding requests */
-    link = u->requests.head;
-    while (link) {
-	debug(29, 5) ("authenticateFreeProxyAuthUser: removing request entry '%p'\n", link->data);
-	auth_user_request = link->data;
-	tmplink = link;
-	link = link->next;
-	dlinkDelete(tmplink, &u->requests);
-	dlinkNodeDelete(tmplink);
-	authenticateAuthUserRequestFree(auth_user_request);
-    }
-    /* free cached acl results */
-    aclCacheMatchFlush(&u->proxy_match_cache);
-    /* free seen ip address's */
-    authenticateAuthUserClearIp(u);
-    if (u->scheme_data && u->auth_module > 0)
-	authscheme_list[u->auth_module - 1].FreeUser(u);
-    /* prevent accidental reuse */
-    u->auth_type = AUTH_UNKNOWN;
-    memFree(u, MEM_AUTH_USER_T);
-}
-
-void
-authenticateInitUserCache(void)
-{
-    if (!proxy_auth_username_cache) {
-	/* First time around, 7921 should be big enough */
-	proxy_auth_username_cache =
-	    hash_create((HASHCMP *) strcmp, 7921, hash_string);
-	assert(proxy_auth_username_cache);
-	eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
-    }
-}
-
-void
-authenticateProxyUserCacheCleanup(void *datanotused)
-{
-    /*
-     * We walk the hash by username as that is the unique key we use.
-     * For big hashs we could consider stepping through the cache, 100/200
-     * entries at a time. Lets see how it flys first.
-     */
-    auth_user_hash_pointer *usernamehash;
-    auth_user_t *auth_user;
-    char *username = NULL;
-    debug(29, 3) ("authenticateProxyUserCacheCleanup: Cleaning the user cache now\n");
-    debug(29, 3) ("authenticateProxyUserCacheCleanup: Current time: %ld\n", (long int) current_time.tv_sec);
-    hash_first(proxy_auth_username_cache);
-    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
-	auth_user = usernamehash->auth_user;
-	username = authenticateUserUsername(auth_user);
-
-	/* if we need to have inpedendent expiry clauses, insert a module call
-	 * here */
-	debug(29, 4) ("authenticateProxyUserCacheCleanup: Cache entry:\n\tType: %d\n\tUsername: %s\n\texpires: %ld\n\treferences: %ld\n", auth_user->auth_type, username, (long int) (auth_user->expiretime + Config.authenticateTTL), (long int) auth_user->references);
-	if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
-	    debug(29, 5) ("authenticateProxyUserCacheCleanup: Removing user %s from cache due to timeout.\n", username);
-	    /* the minus 1 accounts for the cache lock */
-	    if ((authenticateAuthUserInuse(auth_user) - 1))
-		debug(29, 4) ("authenticateProxyUserCacheCleanup: this cache entry has expired AND has a non-zero ref count.\n");
-	    else
-		authenticateAuthUserUnlock(auth_user);
-	}
-    }
-    debug(29, 3) ("authenticateProxyUserCacheCleanup: Finished cleaning the user cache.\n");
-    eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
-}
-
-/*
- * authenticateUserCacheRestart() cleans all config-dependent data from the 
- * auth_user cache. It DOES NOT Flush the user cache.
- */
-
-void
-authenticateUserCacheRestart(void)
-{
-    auth_user_hash_pointer *usernamehash;
-    auth_user_t *auth_user;
-    char *username = NULL;
-    debug(29, 3) ("authenticateUserCacheRestart: Clearing config dependent cache data.\n");
-    hash_first(proxy_auth_username_cache);
-    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
-	auth_user = usernamehash->auth_user;
-	username = authenticateUserUsername(auth_user);
-	debug(29, 5) ("authenticateUserCacheRestat: Clearing cache ACL results for user: %s\n", username);
-	aclCacheMatchFlush(&auth_user->proxy_match_cache);
-    }
-
-}
-
-/*
- * called to add another auth scheme module
- */
-void
-authSchemeAdd(const char *type, AUTHSSETUP * setup)
-{
-    int i;
-    debug(29, 4) ("authSchemeAdd: adding %s\n", type);
-    /* find the number of currently known authscheme types */
-    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
-	assert(strcmp(authscheme_list[i].typestr, type) != 0);
-    }
-    /* add the new type */
-    authscheme_list = xrealloc(authscheme_list, (i + 2) * sizeof(authscheme_entry_t));
-    memset(&authscheme_list[i + 1], 0, sizeof(authscheme_entry_t));
-    authscheme_list[i].typestr = type;
-    /* Call the scheme module to set up capabilities and initialize any global data */
-    setup(&authscheme_list[i]);
-}
-
-
-
-/* UserNameCacheAdd: add a auth_user structure to the username cache */
-void
-authenticateUserNameCacheAdd(auth_user_t * auth_user)
-{
-    auth_user_hash_pointer *usernamehash;
-    usernamehash = memAllocate(MEM_AUTH_USER_HASH);
-    usernamehash->key = authenticateUserUsername(auth_user);
-    usernamehash->auth_user = auth_user;
-    hash_join(proxy_auth_username_cache, (hash_link *) usernamehash);
-    auth_user->usernamehash = usernamehash;
-    /* lock for presence in the cache */
-    authenticateAuthUserLock(auth_user);
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/authenticate.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,1111 @@
+
+/*
+ * $Id: authenticate.cc,v 1.1.2.1 2002/10/03 01:04:33 rbcollins Exp $
+ *
+ * DEBUG: section 29    Authenticator
+ * AUTHOR:  Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/* The functions in this file handle authentication.
+ * They DO NOT perform access control or auditing.
+ * See acl.c for access control and client_side.c for auditing */
+
+#include "squid.h"
+#include "authenticate.h"
+
+CBDATA_TYPE(auth_user_ip_t);
+
+/*
+ *
+ * Private Data
+ *
+ */
+
+MemPool *AuthUserRequest::pool = NULL;
+MemPool *AuthUserHashPointer::pool = NULL;
+MemPool *AuthUser::pool = NULL;
+/*
+ *     memDataInit(MEM_AUTH_USER_T, "auth_user_t",
+ *             sizeof(auth_user_t), 0);
+ */
+
+/* Generic Functions */
+
+
+static int
+authenticateAuthSchemeConfigured(const char *proxy_auth)
+{
+    authScheme *scheme;
+    int i;
+    for (i = 0; i < Config.authConfiguration.n_configured; i++) {
+	scheme = Config.authConfiguration.schemes + i;
+	if ((strncasecmp(proxy_auth, scheme->typestr, strlen(scheme->typestr)) == 0) &&
+	    (authscheme_list[scheme->Id].Active()))
+	    return 1;
+    }
+    return 0;
+}
+
+int
+authenticateAuthSchemeId(const char *typestr)
+{
+    int i = 0;
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
+	if (strncasecmp(typestr, authscheme_list[i].typestr, strlen(authscheme_list[i].typestr)) == 0) {
+	    return i;
+	}
+    }
+    return -1;
+}
+
+void
+AuthUserRequest::decodeAuth(const char *proxy_auth)
+{
+    int i = 0;
+    assert(proxy_auth != NULL);
+    debug(29, 9) ("authenticateDecodeAuth: header = '%s'\n", proxy_auth);
+    if (!authenticateAuthSchemeConfigured(proxy_auth) || 
+	(i = authenticateAuthSchemeId(proxy_auth)) == -1) {
+	debug(29, 1) ("AuthUserRequest::decodeAuth: Unsupported or unconfigured proxy-auth scheme, '%s'\n", proxy_auth);
+	return;
+    }
+    assert (i >= 0);
+    authscheme_list[i].decodeauth(this, proxy_auth);
+    auth_user->auth_module = i + 1;
+}
+
+size_t
+AuthUserRequest::refCount () const
+{
+    return references;
+}
+
+char const *
+AuthUserRequest::username() const
+{
+    if (auth_user)
+	return auth_user->username();
+    else
+	return NULL;
+}
+
+size_t
+authenticateRequestRefCount (auth_user_request_t *aRequest)
+{
+    return aRequest->refCount();
+}
+
+/* clear any connection related authentication details */
+void
+authenticateOnCloseConnection(ConnStateData * conn)
+{
+    auth_user_request_t *auth_user_request;
+    assert(conn != NULL);
+    if (conn->auth_user_request != NULL) {
+	auth_user_request = conn->auth_user_request;
+	/* if the auth type gets reset, the connection shouldn't 
+	 * remain linked to it - the next type might not be conn based
+	 */
+	assert(auth_user_request->auth_user->auth_module);
+	if (authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection) {
+	    authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection(conn);
+	}
+    }
+}
+
+/**** PUBLIC FUNCTIONS (ALL GENERIC!)  ****/
+
+/* send the initial data to an authenticator module */
+void
+AuthUserRequest::start(RH * handler, void *data)
+{
+    assert(handler);
+    debug(29, 9) ("authenticateStart: auth_user_request '%p'\n", this);
+    if (auth_user->auth_module > 0)
+	authscheme_list[auth_user->auth_module - 1].authStart(this, handler, data);
+    else
+	handler(data, NULL);
+}
+
+void
+authenticateStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
+{
+    assert(auth_user_request);
+    auth_user_request->start (handler, data);
+}
+
+/*
+ * Check a auth_user pointer for validity. Does not check passwords, just data
+ * sensability. Broken or Unknown auth_types are not valid for use...
+ */
+
+int
+authenticateValidateUser(auth_user_request_t * auth_user_request)
+{
+    debug(29, 9) ("authenticateValidateUser: Validating Auth_user request '%p'.\n", auth_user_request);
+    if (auth_user_request == NULL) {
+	debug(29, 4) ("authenticateValidateUser: Auth_user_request was NULL!\n");
+	return 0;
+    }
+    if (auth_user_request->auth_user == NULL) {
+	debug(29, 4) ("authenticateValidateUser: No associated auth_user structure\n");
+	return 0;
+    }
+    if (auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) {
+	debug(29, 4) ("authenticateValidateUser: Auth_user '%p' uses unknown scheme.\n", auth_user_request->auth_user);
+	return 0;
+    }
+    if (auth_user_request->auth_user->auth_type == AUTH_BROKEN) {
+	debug(29, 4) ("authenticateValidateUser: Auth_user '%p' is broken for it's scheme.\n", auth_user_request->auth_user);
+	return 0;
+    }
+    if (!auth_user_request->auth_user->scheme_data) {
+	debug(29, 4) ("authenticateValidateUser: auth_user '%p' has no scheme data\n", auth_user_request->auth_user);
+	return 0;
+    }
+    /* any other sanity checks that we need in the future */
+
+    /* Thus should a module call to something like authValidate */
+
+    /* finally return ok */
+    debug(29, 5) ("authenticateValidateUser: Validated Auth_user request '%p'.\n", auth_user_request);
+    return 1;
+
+}
+
+void *
+AuthUser::operator new (unsigned int byteCount)
+{
+    /* derived classes with different sizes must implement their own new */
+    assert (byteCount == sizeof (AuthUser));
+    if (!pool)
+	pool = memPoolCreate("Authenticate User Data", sizeof (auth_user_t));
+    return static_cast<auth_user_t *> (memPoolAlloc(pool));
+}
+
+AuthUser::AuthUser (const char *scheme) :
+auth_type (AUTH_UNKNOWN), auth_module (authenticateAuthSchemeId(scheme) + 1),
+usernamehash (NULL), ipcount (0), expiretime (0), references (0), scheme_data (NULL)
+{
+    proxy_auth_list.head = proxy_auth_list.tail = NULL;
+    proxy_match_cache.head = proxy_match_cache.tail = NULL;
+    ip_list.head = ip_list.tail = NULL;
+    requests.head = requests.tail = NULL;
+}
+
+char const *
+AuthUser::username () const
+{
+    if (auth_module <= 0)
+	return NULL;
+    return authscheme_list[auth_module - 1].authUserUsername(this);
+}
+
+auth_user_t *
+authenticateAuthUserNew(const char *scheme)
+{
+    return new AuthUser (scheme);
+}
+
+void *
+AuthUserRequest::operator new (unsigned int byteCount)
+{
+    /* derived classes with different sizes must implement their own new */
+    assert (byteCount == sizeof (AuthUserRequest));
+    if (!pool)
+	pool = memPoolCreate("Authenticate Request Data", sizeof(auth_user_request_t));
+    return static_cast<auth_user_request_t *>(memPoolAlloc(pool));
+}
+
+void
+AuthUserRequest::operator delete (void *address)
+{
+    memPoolFree(pool, address);
+}
+
+AuthUserRequest::AuthUserRequest():auth_user(NULL), message(NULL), scheme_data (NULL),
+  references (0), lastReply (AUTH_ACL_CANNOT_AUTHENTICATE)
+{
+}
+ 
+AuthUserRequest::~AuthUserRequest()
+{
+    dlink_node *link;
+    debug(29, 5) ("AuthUserRequest::~AuthUserRequest: freeing request %p\n", this);
+    assert(references == 0);
+    if (auth_user) {
+	if (scheme_data != NULL) {
+	    /* we MUST know the module */
+	    assert(auth_user->auth_module > 0);
+	    /* and the module MUST support requestFree if it has created scheme data */
+	    assert(authscheme_list[auth_user->auth_module - 1].requestFree != NULL);
+	    authscheme_list[auth_user->auth_module - 1].requestFree(this);
+	}
+	/* unlink from the auth_user struct */
+	link = auth_user->requests.head;
+	while (link && (link->data != this))
+	    link = link->next;
+	assert(link != NULL);
+	dlinkDelete(link, &auth_user->requests);
+	dlinkNodeDelete(link);
+
+	/* unlock the request structure's lock */
+	authenticateAuthUserUnlock(auth_user);
+	auth_user = NULL;
+    } else
+	assert(scheme_data == NULL);
+    safe_free (message);
+}
+
+void
+AuthUserRequest::setDenyMessage (char const *aString)
+{
+    safe_free (message);
+    message = xstrdup (aString);
+}
+
+char const *
+AuthUserRequest::getDenyMessage ()
+{
+    return message;
+}
+
+char const *
+authenticateAuthUserRequestMessage(auth_user_request_t * auth_user_request)
+{
+    if (auth_user_request)
+	return auth_user_request->getDenyMessage();
+    return NULL;
+}
+
+void
+authenticateSetDenyMessage (auth_user_request_t * auth_user_request, char const *message)
+{
+    auth_user_request->setDenyMessage (message);
+}
+
+void
+authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr)
+{
+    auth_user_ip_t *ipdata, *tempnode;
+    auth_user_t *auth_user;
+    char *ip1;
+    int found = 0;
+    CBDATA_INIT_TYPE(auth_user_ip_t);
+    if (!auth_user_request->auth_user)
+	return;
+    auth_user = auth_user_request->auth_user;
+    ipdata = (auth_user_ip_t *) auth_user->ip_list.head;
+    /*
+     * we walk the entire list to prevent the first item in the list
+     * preventing old entries being flushed and locking a user out after
+     * a timeout+reconfigure
+     */
+    while (ipdata) {
+	tempnode = (auth_user_ip_t *) ipdata->node.next;
+	/* walk the ip list */
+	if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
+	    /* This ip has alreadu been seen. */
+	    found = 1;
+	    /* update IP ttl */
+	    ipdata->ip_expiretime = squid_curtime;
+	} else if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) {
+	    /* This IP has expired - remove from the seen list */
+	    dlinkDelete(&ipdata->node, &auth_user->ip_list);
+	    cbdataFree(ipdata);
+	    /* catch incipient underflow */
+	    assert(auth_user->ipcount);
+	    auth_user->ipcount--;
+	}
+	ipdata = tempnode;
+    }
+
+    if (found)
+	return;
+
+    /* This ip is not in the seen list */
+    ipdata = cbdataAlloc(auth_user_ip_t);
+    ipdata->ip_expiretime = squid_curtime;
+    ipdata->ipaddr = ipaddr;
+    dlinkAddTail(ipdata, &ipdata->node, &auth_user->ip_list);
+    auth_user->ipcount++;
+
+    ip1 = xstrdup(inet_ntoa(ipaddr));
+    debug(29, 2) ("authenticateAuthUserRequestSetIp: user '%s' has been seen at a new IP address (%s)\n ", auth_user->username(), ip1);
+    safe_free(ip1);
+}
+
+void
+authenticateAuthUserRequestRemoveIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr)
+{
+    auth_user_ip_t *ipdata;
+    auth_user_t *auth_user;
+    if (!auth_user_request->auth_user)
+	return;
+    auth_user = auth_user_request->auth_user;
+    ipdata = (auth_user_ip_t *) auth_user->ip_list.head;
+    while (ipdata) {
+	/* walk the ip list */
+	if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
+	    /* remove the node */
+	    dlinkDelete(&ipdata->node, &auth_user->ip_list);
+	    cbdataFree(ipdata);
+	    /* catch incipient underflow */
+	    assert(auth_user->ipcount);
+	    auth_user->ipcount--;
+	    return;
+	}
+	ipdata = (auth_user_ip_t *) ipdata->node.next;
+    }
+
+}
+
+static void
+authenticateAuthUserClearIp(auth_user_t * auth_user)
+{
+    auth_user_ip_t *ipdata, *tempnode;
+    if (!auth_user)
+	return;
+    ipdata = (auth_user_ip_t *) auth_user->ip_list.head;
+    while (ipdata) {
+	tempnode = (auth_user_ip_t *) ipdata->node.next;
+	/* walk the ip list */
+	dlinkDelete(&ipdata->node, &auth_user->ip_list);
+	cbdataFree(ipdata);
+	/* catch incipient underflow */
+	assert(auth_user->ipcount);
+	auth_user->ipcount--;
+	ipdata = tempnode;
+    }
+    /* integrity check */
+    assert(auth_user->ipcount == 0);
+}
+
+
+void
+authenticateAuthUserRequestClearIp(auth_user_request_t * auth_user_request)
+{
+    if (auth_user_request)
+	authenticateAuthUserClearIp(auth_user_request->auth_user);
+}
+
+size_t
+authenticateAuthUserRequestIPCount(auth_user_request_t * auth_user_request)
+{
+    assert(auth_user_request);
+    assert(auth_user_request->auth_user);
+    return auth_user_request->auth_user->ipcount;
+}
+
+
+/* Get Auth User: Return a filled out auth_user structure for the given
+ * Proxy Auth (or Auth) header. It may be a cached Auth User or a new
+ * Unauthenticated structure. The structure is given an inital lock here.
+ */
+auth_user_request_t *
+AuthUserRequest::createAuthUser(const char *proxy_auth)
+{
+    auth_user_request_t *result = new auth_user_request_t;
+    /* and lock for the callers instance */
+    result->lock();
+    /* The scheme is allowed to provide a cached auth_user or a new one */
+    result->decodeAuth(proxy_auth);
+    return result;
+}
+
+/*
+ * authenticateUserAuthenticated: is this auth_user structure logged in ?
+ */
+int
+authenticateUserAuthenticated(auth_user_request_t * auth_user_request)
+{
+    if (!authenticateValidateUser(auth_user_request))
+	return 0;
+    if (auth_user_request->auth_user->auth_module > 0)
+	return authscheme_list[auth_user_request->auth_user->auth_module - 1].authenticated(auth_user_request);
+    else
+	return 0;
+}
+
+/*
+ * authenticateAuthenticateUser: call the module specific code to 
+ * log this user request in.
+ * Cache hits may change the auth_user pointer in the structure if needed.
+ * This is basically a handle approach.
+ */
+static void
+authenticateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
+{
+    assert(auth_user_request != NULL);
+    if (auth_user_request->auth_user->auth_module > 0)
+	authscheme_list[auth_user_request->auth_user->auth_module - 1].authAuthenticate(auth_user_request, request, conn, type);
+}
+
+/* returns one of
+ * AUTH_ACL_CHALLENGE,
+ * AUTH_ACL_HELPER,
+ * AUTH_ACL_CANNOT_AUTHENTICATE,
+ * AUTH_AUTHENTICATED
+ *
+ * How to use: In your proxy-auth dependent acl code, use the following 
+ * construct:
+ * int rv;
+ * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED)
+ *   return rv;
+ * 
+ * when this code is reached, the request/connection is authenticated.
+ *
+ * if you have non-acl code, but want to force authentication, you need a 
+ * callback mechanism like the acl testing routines that will send a 40[1|7] to
+ * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with 
+ * the authenticateStart routine for rv==AUTH_ACL_HELPER
+ */
+auth_acl_t
+AuthUserRequest::authenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr)
+{
+    const char *proxy_auth;
+    assert(headertype != 0);
+
+    proxy_auth = httpHeaderGetStr(&request->header, headertype);
+
+    if (conn == NULL) {
+	debug(28, 1) ("authenticateAuthenticate: no connection data, cannot process authentication\n");
+	/*
+	 * deny access: clientreadrequest requires conn data, and it is always
+	 * compiled in so we should have it too.
+	 */
+	return AUTH_ACL_CANNOT_AUTHENTICATE;
+    }
+    /*
+     * a note on proxy_auth logix here:
+     * proxy_auth==NULL -> unauthenticated request || already authenticated connection
+     * so we test for an authenticated connection when we recieve no authentication
+     * header.
+     */
+    if (((proxy_auth == NULL) && (!authenticateUserAuthenticated(*auth_user_request ? *auth_user_request : conn->auth_user_request)))
+	|| (conn->auth_type == AUTH_BROKEN)) {
+	/* no header or authentication failed/got corrupted - restart */
+	conn->auth_type = AUTH_UNKNOWN;
+	debug(28, 4) ("authenticateAuthenticate: broken auth or no proxy_auth header. Requesting auth header.\n");
+	/* something wrong with the AUTH credentials. Force a new attempt */
+	if (conn->auth_user_request) {
+	    conn->auth_user_request->unlock();
+	    conn->auth_user_request = NULL;
+	}
+	if (*auth_user_request) {
+	    /* unlock the ACL lock */
+	    (*auth_user_request)->unlock();
+	    auth_user_request = NULL;
+	}
+	return AUTH_ACL_CHALLENGE;
+    }
+    /* 
+     * Is this an already authenticated connection with a new auth header?
+     * No check for function required in the if: its compulsory for conn based 
+     * auth modules
+     */
+    if (proxy_auth && conn->auth_user_request &&
+	authenticateUserAuthenticated(conn->auth_user_request) &&
+	strcmp(proxy_auth, authscheme_list[conn->auth_user_request->auth_user->auth_module - 1].authConnLastHeader(conn->auth_user_request))) {
+	debug(28, 2) ("authenticateAuthenticate: DUPLICATE AUTH - authentication header on already authenticated connection!. AU %p, Current user '%s' proxy_auth %s\n", conn->auth_user_request, conn->auth_user_request->username(), proxy_auth);
+	/* remove this request struct - the link is already authed and it can't be to 
+	 * reauth.
+	 */
+
+	/* This should _only_ ever occur on the first pass through 
+	 * authenticateAuthenticate 
+	 */
+	assert(*auth_user_request == NULL);
+	/* unlock the conn lock on the auth_user_request */
+	conn->auth_user_request->unlock();
+	/* mark the conn as non-authed. */
+	conn->auth_user_request = NULL;
+	/* Set the connection auth type */
+	conn->auth_type = AUTH_UNKNOWN;
+    }
+    /* we have a proxy auth header and as far as we know this connection has
+     * not had bungled connection oriented authentication happen on it. */
+    debug(28, 9) ("authenticateAuthenticate: header %s.\n", proxy_auth);
+    if (*auth_user_request == NULL) {
+	debug(28, 9) ("authenticateAuthenticate: This is a new checklist test on FD:%d\n",
+	    conn->fd);
+	if ((!request->auth_user_request)
+	    && (conn->auth_type == AUTH_UNKNOWN)) {
+	    /* beginning of a new request check */
+	    debug(28, 4) ("authenticateAuthenticate: no connection authentication type\n");
+	    if (!authenticateValidateUser(*auth_user_request =
+		    createAuthUser(proxy_auth))) {
+		/* the decode might have left a username for logging, or a message to
+		 * the user */
+		if ((*auth_user_request)->username()) {
+		    /* lock the user for the request structure link */
+		    (*auth_user_request)->lock();
+		    request->auth_user_request = *auth_user_request;
+		}
+		/* unlock the ACL reference granted by ...createAuthUser. */
+		(*auth_user_request)->unlock();
+		*auth_user_request = NULL;
+		return AUTH_ACL_CHALLENGE;
+	    }
+	    /* the user_request comes prelocked for the caller to createAuthUser (us) */
+	} else if (request->auth_user_request) {
+	    *auth_user_request = request->auth_user_request;
+	    /* lock the user request for this ACL processing */
+	    (*auth_user_request)->lock();
+	} else {
+	    if (conn->auth_user_request != NULL) {
+		*auth_user_request = conn->auth_user_request;
+		/* lock the user request for this ACL processing */
+		(*auth_user_request)->lock();
+	    } else {
+		/* failed connection based authentication */
+		debug(28, 4) ("authenticateAuthenticate: Auth user request %p conn-auth user request %p conn type %d authentication failed.\n",
+		    *auth_user_request, conn->auth_user_request, conn->auth_type);
+		(*auth_user_request)->unlock();
+		*auth_user_request = NULL;
+		return AUTH_ACL_CHALLENGE;
+	    }
+	}
+    }
+    if (!authenticateUserAuthenticated(*auth_user_request)) {
+	/* User not logged in. Log them in */
+	authenticateAuthenticateUser(*auth_user_request, request,
+	    conn, headertype);
+	switch (authenticateDirection(*auth_user_request)) {
+	case 1:
+	case -2:
+	    /* this ACL check is finished. Unlock. */
+	    (*auth_user_request)->unlock();
+	    *auth_user_request = NULL;
+	    return AUTH_ACL_CHALLENGE;
+	case -1:
+	    /* we are partway through authentication within squid,
+	     * the *auth_user_request variables stores the auth_user_request
+	     * for the callback to here - Do not Unlock */
+	    return AUTH_ACL_HELPER;
+	}
+	/* on 0 the authentication is finished - fallthrough */
+	/* See if user authentication failed for some reason */
+	if (!authenticateUserAuthenticated(*auth_user_request)) {
+	    if ((*auth_user_request)->username()) {
+		if (!request->auth_user_request) {
+		    /* lock the user for the request structure link */
+		    (*auth_user_request)->lock();
+		    request->auth_user_request = *auth_user_request;
+		}
+	    }
+	    /* this ACL check is finished. Unlock. */
+	    (*auth_user_request)->unlock();
+	    *auth_user_request = NULL;
+	    return AUTH_ACL_CHALLENGE;
+	}
+    }
+    /* copy username to request for logging on client-side */
+    /* the credentials are correct at this point */
+    if (!request->auth_user_request) {
+	/* lock the user for the request structure link */
+	(*auth_user_request)->lock();
+	request->auth_user_request = *auth_user_request;
+	authenticateAuthUserRequestSetIp(*auth_user_request, src_addr);
+    }
+    /* Unlock the request - we've authenticated it */
+    (*auth_user_request)->unlock();
+    return AUTH_AUTHENTICATED;
+}
+
+auth_acl_t
+AuthUserRequest::tryToAuthenticateAndSetAuthUser(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr)
+{
+    /* If we have already been called, return the cached value */
+    auth_user_request_t *t = *auth_user_request ? *auth_user_request : conn->auth_user_request;
+    auth_acl_t result;
+    if (t && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE
+	&& t->lastReply != AUTH_ACL_HELPER) {
+	if (!*auth_user_request)
+	    *auth_user_request = t;
+	return t->lastReply;
+    }
+    /* ok, call the actual authenticator routine. */
+    result = authenticate(auth_user_request, headertype, request, conn, src_addr);
+    t = *auth_user_request ? *auth_user_request : conn->auth_user_request;
+    if (t && result != AUTH_ACL_CANNOT_AUTHENTICATE &&
+	result != AUTH_ACL_HELPER)
+	t->lastReply = result;
+    return result;
+}
+
+auth_acl_t
+authenticateTryToAuthenticateAndSetAuthUser(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr)
+{
+    return AuthUserRequest::tryToAuthenticateAndSetAuthUser (auth_user_request, headertype,request, conn, src_addr);
+}
+
+/* authenticateUserRequestUsername: return a pointer to the username in the */
+char const *
+authenticateUserRequestUsername(auth_user_request_t * auth_user_request)
+{
+    assert(auth_user_request != NULL);
+    return auth_user_request->username();
+}
+
+/* returns
+ * 0: no output needed
+ * 1: send to client
+ * -1: send to helper
+ * -2: authenticate broken in some fashion
+ */
+int
+authenticateDirection(auth_user_request_t * auth_user_request)
+{
+    if (!auth_user_request)
+	return -2;
+    if (authenticateUserAuthenticated(auth_user_request))
+	return 0;
+    if (auth_user_request->auth_user->auth_module > 0)
+	return authscheme_list[auth_user_request->auth_user->auth_module - 1].getdirection(auth_user_request);
+    return -2;
+}
+
+int
+authenticateActiveSchemeCount(void)
+{
+    int i = 0, rv = 0;
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
+	if (authscheme_list[i].configured())
+	    rv++;
+    debug(29, 9) ("authenticateActiveSchemeCount: %d active.\n", rv);
+    return rv;
+}
+
+int
+authenticateSchemeCount(void)
+{
+    int i = 0, rv = 0;
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
+	rv++;
+    debug(29, 9) ("authenticateSchemeCount: %d active.\n", rv);
+    return rv;
+}
+
+void
+authenticateSchemeInit(void)
+{
+    authSchemeSetup();
+}
+
+void
+authenticateInit(authConfig * config)
+{
+    int i;
+    authScheme *scheme;
+    for (i = 0; i < config->n_configured; i++) {
+	scheme = config->schemes + i;
+	if (authscheme_list[scheme->Id].init && authscheme_list[scheme->Id].configured()) {
+	    authscheme_list[scheme->Id].init(scheme);
+	}
+    }
+    if (!proxy_auth_username_cache)
+	AuthUser::cacheInit();
+}
+
+void
+authenticateShutdown(void)
+{
+    int i;
+    debug(29, 2) ("authenticateShutdown: shutting down auth schemes\n");
+    /* free the cache if we are shutting down */
+    if (shutting_down)
+	hashFreeItems(proxy_auth_username_cache, AuthUserHashPointer::removeFromCache);
+
+    /* find the currently known authscheme types */
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
+	if (authscheme_list[i].donefunc != NULL)
+	    authscheme_list[i].donefunc();
+	else
+	    debug(29, 2) ("authenticateShutdown: scheme %s has not registered a shutdown function.\n", authscheme_list[i].typestr);
+	if (shutting_down)
+	    authscheme_list[i].typestr = NULL;
+    }
+}
+
+void
+AuthUserRequest::addReplyAuthHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated, int internal)
+/* send the auth types we are configured to support (and have compiled in!) */
+{
+    http_hdr_type type;
+    switch (rep->sline.status) {
+    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
+	/* Proxy authorisation needed */
+	type = HDR_PROXY_AUTHENTICATE;
+	break;
+    case HTTP_UNAUTHORIZED:
+	/* WWW Authorisation needed */
+	type = HDR_WWW_AUTHENTICATE;
+	break;
+    default:
+	/* Keep GCC happy */
+	/* some other HTTP status */
+	type = HDR_ENUM_END;
+	break;
+    }
+    debug(29, 9) ("authenticateFixHeader: headertype:%d authuser:%p\n", type, auth_user_request);
+    if (((rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
+	    || (rep->sline.status == HTTP_UNAUTHORIZED)) && internal)
+	/* this is a authenticate-needed response */
+    {
+	if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0) & !authenticateUserAuthenticated(auth_user_request))
+	    authscheme_list[auth_user_request->auth_user->auth_module - 1].authFixHeader(auth_user_request, rep, type, request);
+	else {
+	    int i;
+	    authScheme *scheme;
+	    /* call each configured & running authscheme */
+	    for (i = 0; i < Config.authConfiguration.n_configured; i++) {
+		scheme = Config.authConfiguration.schemes + i;
+		if (authscheme_list[scheme->Id].Active())
+		    authscheme_list[scheme->Id].authFixHeader(NULL, rep, type,
+			request);
+		else
+		    debug(29, 4) ("authenticateFixHeader: Configured scheme %s not Active\n", scheme->typestr);
+	    }
+	}
+    }
+    /* allow protocol specific headers to be _added_ to the existing response - ie
+     * digest auth
+     */
+    if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
+	&& (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader))
+	authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader(auth_user_request, rep, accelerated);
+    if (auth_user_request != NULL)
+	auth_user_request->lastReply = AUTH_ACL_CANNOT_AUTHENTICATE;
+}
+
+void
+authenticateFixHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated, int internal)
+{
+    AuthUserRequest::addReplyAuthHeader(rep, auth_user_request, request, accelerated, internal);
+}
+  
+
+/* call the active auth module and allow it to add a trailer to the request */
+void
+authenticateAddTrailer(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated)
+{
+    if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
+	&& (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer))
+	authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer(auth_user_request, rep, accelerated);
+}
+
+void
+authenticateAuthUserLock(auth_user_t * auth_user)
+{
+    debug(29, 9) ("authenticateAuthUserLock auth_user '%p'.\n", auth_user);
+    assert(auth_user != NULL);
+    auth_user->references++;
+    debug(29, 9) ("authenticateAuthUserLock auth_user '%p' now at '%ld'.\n", auth_user, (long int) auth_user->references);
+}
+
+void
+authenticateAuthUserUnlock(auth_user_t * auth_user)
+{
+    debug(29, 9) ("authenticateAuthUserUnlock auth_user '%p'.\n", auth_user);
+    assert(auth_user != NULL);
+    if (auth_user->references > 0) {
+	auth_user->references--;
+    } else {
+	debug(29, 1) ("Attempt to lower Auth User %p refcount below 0!\n", auth_user);
+    }
+    debug(29, 9) ("authenticateAuthUserUnlock auth_user '%p' now at '%ld'.\n", auth_user, (long int) auth_user->references);
+    if (auth_user->references == 0)
+	delete auth_user;
+}
+
+void
+AuthUserRequest::lock()
+{
+    debug(29, 9) ("AuthUserRequest::lock: auth_user request '%p'.\n", this);
+    assert(this != NULL);
+    ++references;
+    debug(29, 9) ("AuthUserRequest::lock: auth_user request '%p' now at '%ld'.\n", this, (long int) references);
+}
+
+void
+AuthUserRequest::unlock()
+{
+    debug(29, 9) ("AuthUserRequest::unlock: auth_user request '%p'.\n", this);
+    assert(this != NULL);
+    if (references > 0) {
+	--references;
+    } else {
+	debug(29, 1) ("Attempt to lower Auth User request %p refcount below 0!\n", this);
+    }
+    debug(29, 9) ("AuthUserRequest::unlock: auth_user_request '%p' now at '%ld'.\n", this, (long int) references);
+    if (references == 0)
+	/* not locked anymore */
+	delete this;
+}
+
+void
+authenticateAuthUserRequestLock(auth_user_request_t * auth_user_request)
+{
+    auth_user_request->lock();
+}
+
+void
+authenticateAuthUserRequestUnlock(auth_user_request_t * auth_user_request)
+{
+    auth_user_request->unlock();
+}
+  
+
+int
+authenticateAuthUserInuse(auth_user_t * auth_user)
+/* returns 0 for not in use */
+{
+    assert(auth_user != NULL);
+    return auth_user->references;
+}
+
+/* Combine two user structs. ONLY to be called from within a scheme module.
+ * The scheme module is responsible for ensuring that the two users _can_ be merged 
+ * without invalidating all the request scheme data. 
+ * the scheme is also responsible for merging any user related scheme data itself. */
+void
+AuthUser::absorb (AuthUser *from)
+{
+    auth_user_request_t *auth_user_request;
+/* XXX combine two authuser structs. Incomplete: it should merge in hash references 
+ * too and ask the module to merge in scheme data */
+    debug(29, 5) ("authenticateAuthUserMerge auth_user '%p' into auth_user '%p'.\n", from, this);
+    dlink_node *link = from->requests.head;
+    while (link) {
+	auth_user_request = static_cast<auth_user_request_t *>(link->data);
+	dlink_node *tmplink = link;
+	link = link->next;
+	dlinkDelete(tmplink, &from->requests);
+	dlinkAddTail(auth_user_request, tmplink, &requests);
+	auth_user_request->auth_user = this;
+    }
+    references += from->references;
+    from->references = 0;
+    delete from;
+}
+
+void
+authenticateAuthUserMerge(auth_user_t * from, auth_user_t * to)
+{   
+    to->absorb (from);
+}
+
+void
+AuthUser::operator delete (void *address)
+{
+    memPoolFree(pool, address);
+}
+
+AuthUser::~AuthUser()
+{
+    auth_user_request_t *auth_user_request;
+    dlink_node *link, *tmplink;
+    debug(29, 5) ("AuthUser::~AuthUser: Freeing auth_user '%p' with refcount '%ld'.\n", this, (long int) references);
+    assert(references == 0);
+    /* were they linked in by username ? */
+    if (usernamehash) {
+	assert(usernamehash->user() == this);
+	debug(29, 5) ("AuthUser::~AuthUser: removing usernamehash entry '%p'\n", usernamehash);
+	hash_remove_link(proxy_auth_username_cache,
+	    (hash_link *) usernamehash);
+	/* don't free the key as we use the same user string as the auth_user 
+	 * structure */
+	delete usernamehash;
+    }
+    /* remove any outstanding requests */
+    link = requests.head;
+    while (link) {
+	debug(29, 5) ("AuthUser::~AuthUser: removing request entry '%p'\n", link->data);
+	auth_user_request = static_cast<auth_user_request_t *>(link->data);
+	tmplink = link;
+	link = link->next;
+	dlinkDelete(tmplink, &requests);
+	dlinkNodeDelete(tmplink);
+	delete auth_user_request;
+    }
+    /* free cached acl results */
+    aclCacheMatchFlush(&proxy_match_cache);
+    /* free seen ip address's */
+    authenticateAuthUserClearIp(this);
+    if (scheme_data && auth_module > 0)
+	authscheme_list[auth_module - 1].FreeUser(this);
+    /* prevent accidental reuse */
+    auth_type = AUTH_UNKNOWN;
+}
+
+void
+AuthUser::cacheInit(void)
+{
+    if (!proxy_auth_username_cache) {
+	/* First time around, 7921 should be big enough */
+	proxy_auth_username_cache =
+	    hash_create((HASHCMP *) strcmp, 7921, hash_string);
+	assert(proxy_auth_username_cache);
+	eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
+    }
+}
+
+void
+AuthUser::cacheCleanup(void *datanotused)
+{
+    /*
+     * We walk the hash by username as that is the unique key we use.
+     * For big hashs we could consider stepping through the cache, 100/200
+     * entries at a time. Lets see how it flys first.
+     */
+    AuthUserHashPointer *usernamehash;
+    auth_user_t *auth_user;
+    char const *username = NULL;
+    debug(29, 3) ("AuthUser::cacheCleanup: Cleaning the user cache now\n");
+    debug(29, 3) ("AuthUser::cacheCleanup: Current time: %ld\n", (long int) current_time.tv_sec);
+    hash_first(proxy_auth_username_cache);
+    while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
+	auth_user = usernamehash->user();
+	username = auth_user->username();
+
+	/* if we need to have inpedendent expiry clauses, insert a module call
+	 * here */
+	debug(29, 4) ("AuthUser::cacheCleanup: Cache entry:\n\tType: %d\n\tUsername: %s\n\texpires: %ld\n\treferences: %ld\n", auth_user->auth_type, username, (long int) (auth_user->expiretime + Config.authenticateTTL), (long int) auth_user->references);
+	if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
+	    debug(29, 5) ("AuthUser::cacheCleanup: Removing user %s from cache due to timeout.\n", username);
+	    /* the minus 1 accounts for the cache lock */
+	    if ((authenticateAuthUserInuse(auth_user) - 1))
+		debug(29, 4) ("AuthUser::cacheCleanup: this cache entry has expired AND has a non-zero ref count.\n");
+	    else
+		authenticateAuthUserUnlock(auth_user);
+	}
+    }
+    debug(29, 3) ("AuthUser::cacheCleanup: Finished cleaning the user cache.\n");
+    eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
+}
+
+/*
+ * authenticateUserCacheRestart() cleans all config-dependent data from the 
+ * auth_user cache. It DOES NOT Flush the user cache.
+ */
+
+void
+authenticateUserCacheRestart(void)
+{
+    AuthUserHashPointer *usernamehash;
+    auth_user_t *auth_user;
+    debug(29, 3) ("authenticateUserCacheRestart: Clearing config dependent cache data.\n");
+    hash_first(proxy_auth_username_cache);
+    while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
+	auth_user = usernamehash->user();
+	debug(29, 5) ("authenticateUserCacheRestat: Clearing cache ACL results for user: %s\n", auth_user->username());
+    }
+
+}
+
+/*
+ * called to add another auth scheme module
+ */
+void
+authSchemeAdd(const char *type, AUTHSSETUP * setup)
+{
+    int i;
+    debug(29, 4) ("authSchemeAdd: adding %s\n", type);
+    /* find the number of currently known authscheme types */
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
+	assert(strcmp(authscheme_list[i].typestr, type) != 0);
+    }
+    /* add the new type */
+    authscheme_list = static_cast<authscheme_entry_t *>(xrealloc(authscheme_list, (i + 2) * sizeof(authscheme_entry_t)));
+    memset(&authscheme_list[i + 1], 0, sizeof(authscheme_entry_t));
+    authscheme_list[i].typestr = type;
+    /* Call the scheme module to set up capabilities and initialize any global data */
+    setup(&authscheme_list[i]);
+}
+
+/* _auth_user_hash_pointe */
+
+void
+AuthUserHashPointer::removeFromCache(void *usernamehash_p)
+{
+    AuthUserHashPointer *usernamehash = static_cast<AuthUserHashPointer *>(usernamehash_p);
+    auth_user_t *auth_user = usernamehash->auth_user;
+    if ((authenticateAuthUserInuse(auth_user) - 1))
+	debug(29, 1) ("AuthUserHashPointer::removeFromCache: entry in use - not freeing\n");
+    authenticateAuthUserUnlock(auth_user);
+    /* TODO: change behaviour - we remove from the auth user list here, and then unlock, and the
+     * delete ourselves.
+     */
+}
+
+void *
+AuthUserHashPointer::operator new (unsigned int byteCount)
+{
+    assert (byteCount == sizeof (AuthUserHashPointer));
+    if (!pool)
+	pool = memPoolCreate("Auth user hash link", sizeof(AuthUserHashPointer));
+    return static_cast<AuthUserHashPointer *>(memPoolAlloc(pool));
+}
+
+void
+AuthUserHashPointer::operator delete (void *address)
+{
+    memPoolFree(pool, address);
+}
+
+AuthUserHashPointer::AuthUserHashPointer (auth_user_t * anAuth_user):
+key (anAuth_user->username()), next (NULL), auth_user (anAuth_user)
+{
+    hash_join(proxy_auth_username_cache, (hash_link *) this);
+    /* lock for presence in the cache */
+    authenticateAuthUserLock(auth_user);
+}
+
+AuthUser *
+AuthUserHashPointer::user() const
+{
+    return auth_user;
+}
+
+/* C bindings */
+/* UserNameCacheAdd: add a auth_user structure to the username cache */
+void
+authenticateUserNameCacheAdd(auth_user_t * auth_user)
+{
+    auth_user->usernamehash = new AuthUserHashPointer (auth_user);
+}
+
+auth_user_t*
+authUserHashPointerUser (auth_user_hash_pointer *aHashEntry)
+{
+    return aHashEntry->user();
+}
+
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/authenticate.h	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,275 @@
+
+/*
+ * $Id: authenticate.h,v 1.1.2.1 2002/10/03 01:05:18 rbcollins Exp $
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_AUTHENTICATE_H
+#define SQUID_AUTHENTICATE_H
+
+/* A note on the C bindings:
+ * Direct use of the structs is prohibited - only (structfoo *) may be
+ * used from C code.
+ */
+
+#ifdef __cplusplus
+class AuthUser;
+#endif
+
+struct AuthUserHashPointer {
+    /* first two items must be same as hash_link */
+    char const *key;
+    auth_user_hash_pointer *next;
+#ifdef __cplusplus
+public:
+    static void removeFromCache (void *anAuthUserHashPointer);
+    
+    AuthUserHashPointer (AuthUser *);
+    
+    void *operator new (unsigned int byteCount);
+    void operator delete (void *address);
+    AuthUser *user() const;
+private:
+    static MemPool *pool;
+
+    AuthUser *auth_user;
+#endif
+};
+
+struct AuthUserIP {
+    dlink_node node;
+    /* IP addr this user authenticated from */
+    struct in_addr ipaddr;
+    time_t ip_expiretime;
+};
+
+struct AuthUser {
+    /* extra fields for proxy_auth */
+    /* this determines what scheme owns the user data. */
+    auth_type_t auth_type;
+    /* the index +1 in the authscheme_list to the authscheme entry */
+    int auth_module;
+    /* we only have one username associated with a given auth_user struct */
+    auth_user_hash_pointer *usernamehash;
+    /* we may have many proxy-authenticate strings that decode to the same user */
+    dlink_list proxy_auth_list;
+    dlink_list proxy_match_cache;
+    /* what ip addresses has this user been seen at?, plus a list length cache */
+    dlink_list ip_list;
+    size_t ipcount;
+    long expiretime;
+    /* how many references are outstanding to this instance */
+    size_t references;
+    /* the auth scheme has it's own private data area */
+    void *scheme_data;
+    /* the auth_user_request structures that link to this. Yes it could be a splaytree
+     * but how many requests will a single username have in parallel? */
+    dlink_list requests;
+#ifdef __cplusplus
+public:
+    static void cacheInit ();
+    
+    void absorb(auth_user_t *from);
+    AuthUser (const char *);
+    ~AuthUser ();
+    void *operator new (unsigned int byteCount);
+    void operator delete (void *address);
+    char const *username() const;
+private:
+    static void cacheCleanup (void *unused);
+    static MemPool *pool;
+#endif
+};
+
+struct AuthUserRequest {
+    /* this is the object passed around by client_side and acl functions */
+    /* it has request specific data, and links to user specific data */
+    /* the user */
+    auth_user_t *auth_user;
+    /* any scheme specific request related data */
+    void *scheme_data;
+#ifdef __cplusplus
+public:
+    static auth_acl_t tryToAuthenticateAndSetAuthUser(auth_user_request_t **, http_hdr_type, request_t *, ConnStateData *, struct in_addr);
+    static void addReplyAuthHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated, int internal);
+
+    ~AuthUserRequest();
+    void *operator new (unsigned int byteCount);
+    void operator delete (void *address);
+    void start ( RH * handler, void *data);
+    void setDenyMessage (char const *);
+    char const * getDenyMessage ();
+    size_t refCount() const;
+    void lock ();
+    void unlock ();
+    char const *username() const;
+private:
+    static auth_acl_t authenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr);
+    static auth_user_request_t *createAuthUser (const char *proxy_auth);
+    static MemPool *pool;
+
+    AuthUserRequest();
+    void decodeAuth (const char *proxy_auth);
+
+    /* return a message on the 407 error pages */
+    char *message;
+
+    /* how many 'processes' are working on this data */
+    size_t references;
+    
+    /* We only attempt authentication once per http request. This 
+     * is to allow multiple auth acl references from different _access areas
+     * when using connection based authentication
+     */
+    auth_acl_t lastReply;
+#endif
+};
+
+/* authenticate.c authenticate scheme routines typedefs */
+typedef int AUTHSACTIVE(void);
+typedef int AUTHSAUTHED(auth_user_request_t *);
+typedef void AUTHSAUTHUSER(auth_user_request_t *, request_t *, ConnStateData *, http_hdr_type);
+typedef int AUTHSCONFIGURED(void);
+typedef void AUTHSDECODE(auth_user_request_t *, const char *);
+typedef int AUTHSDIRECTION(auth_user_request_t *);
+typedef void AUTHSDUMP(StoreEntry *, const char *, authScheme *);
+typedef void AUTHSFIXERR(auth_user_request_t *, HttpReply *, http_hdr_type, request_t *);
+typedef void AUTHSADDHEADER(auth_user_request_t *, HttpReply *, int);
+typedef void AUTHSADDTRAILER(auth_user_request_t *, HttpReply *, int);
+typedef void AUTHSFREE(auth_user_t *);
+typedef void AUTHSFREECONFIG(authScheme *);
+typedef char const *AUTHSUSERNAME(auth_user_t const *);
+typedef void AUTHSONCLOSEC(ConnStateData *);
+typedef void AUTHSPARSE(authScheme *, int, char *);
+typedef void AUTHSINIT(authScheme *);
+typedef void AUTHSREQFREE(auth_user_request_t *);
+typedef void AUTHSSETUP(authscheme_entry_t *);
+typedef void AUTHSSHUTDOWN(void);
+typedef void AUTHSSTART(auth_user_request_t *, RH *, void *);
+typedef void AUTHSSTATS(StoreEntry *);
+typedef const char *AUTHSCONNLASTHEADER(auth_user_request_t *);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* subsumed by the C++ interface */
+extern void authenticateAuthUserMerge(auth_user_t *, auth_user_t *);
+extern auth_user_t *authenticateAuthUserNew(const char *);
+
+/* AuthUserRequest */
+extern void authenticateStart(auth_user_request_t *, RH *, void *);
+extern auth_acl_t authenticateTryToAuthenticateAndSetAuthUser(auth_user_request_t **, http_hdr_type, request_t *, ConnStateData *, struct in_addr);
+extern void authenticateSetDenyMessage (auth_user_request_t *, char const *);
+extern size_t authenticateRequestRefCount (auth_user_request_t *);
+extern char const *authenticateAuthUserRequestMessage(auth_user_request_t *);
+
+extern int authenticateAuthSchemeId(const char *typestr);
+extern void authenticateSchemeInit(void);
+extern void authenticateInit(authConfig *); 
+extern void authenticateShutdown(void);
+extern void authenticateFixHeader(HttpReply *, auth_user_request_t *, request_t *, int, int);
+extern void authenticateAddTrailer(HttpReply *, auth_user_request_t *, request_t *, int);
+extern void authenticateAuthUserUnlock(auth_user_t * auth_user);
+extern void authenticateAuthUserLock(auth_user_t * auth_user);
+extern void authenticateAuthUserRequestUnlock(auth_user_request_t *);
+extern void authenticateAuthUserRequestLock(auth_user_request_t *);
+extern int authenticateAuthUserInuse(auth_user_t * auth_user);
+extern void authenticateAuthUserRequestSetIp(auth_user_request_t *, struct in_addr);
+extern void authenticateAuthUserRequestRemoveIp(auth_user_request_t *, struct in_addr);
+extern void authenticateAuthUserRequestClearIp(auth_user_request_t *);
+extern size_t authenticateAuthUserRequestIPCount(auth_user_request_t *);
+extern int authenticateDirection(auth_user_request_t *);
+extern void authenticateFreeProxyAuthUserACLResults(void *data);
+extern int authenticateActiveSchemeCount(void);
+extern int authenticateSchemeCount(void);
+extern void authenticateUserNameCacheAdd(auth_user_t * auth_user);
+extern int authenticateCheckAuthUserIP(struct in_addr request_src_addr, auth_user_request_t * auth_user);
+extern int authenticateUserAuthenticated(auth_user_request_t *);
+extern void authenticateUserCacheRestart(void);
+extern char const *authenticateUserRequestUsername(auth_user_request_t *);
+extern int authenticateValidateUser(auth_user_request_t *);
+extern void authenticateOnCloseConnection(ConnStateData * conn);
+extern void authSchemeAdd(const char *type, AUTHSSETUP * setup);
+
+/* AuthUserHashPointer */
+extern auth_user_t* authUserHashPointerUser(auth_user_hash_pointer *);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* auth_modules.c */
+SQUIDCEXTERN void authSchemeSetup(void);
+
+/*
+ * This defines an auth scheme module
+ */
+
+struct _authscheme_entry {
+    const char *typestr;
+    AUTHSACTIVE *Active;
+    AUTHSADDHEADER *AddHeader;
+    AUTHSADDTRAILER *AddTrailer;
+    AUTHSAUTHED *authenticated;
+    AUTHSAUTHUSER *authAuthenticate;
+    AUTHSCONFIGURED *configured;
+    AUTHSDUMP *dump;
+    AUTHSFIXERR *authFixHeader;
+    AUTHSFREE *FreeUser;
+    AUTHSFREECONFIG *freeconfig;
+    AUTHSUSERNAME *authUserUsername;
+    AUTHSONCLOSEC *oncloseconnection;   /*optional */
+    AUTHSCONNLASTHEADER *authConnLastHeader;
+    AUTHSDECODE *decodeauth;
+    AUTHSDIRECTION *getdirection;
+    AUTHSPARSE *parse;
+    AUTHSINIT *init;
+    AUTHSREQFREE *requestFree;
+    AUTHSSHUTDOWN *donefunc;
+    AUTHSSTART *authStart;
+    AUTHSSTATS *authStats;
+};
+    
+/*  
+ * This is a configured auth scheme
+ */
+    
+/* private data types */
+struct _authScheme {
+    /* pointer to the authscheme_list's string entry */
+    const char *typestr;
+    /* the scheme id in the authscheme_list */
+    int Id;
+    /* the scheme's configuration details. */
+    void *scheme_data;
+};
+
+
+#endif /* SQUID_AUTHENTICATE_H */
--- squid/src/cache_cf.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,2525 +0,0 @@
-
-/*
- * $Id: cache_cf.c,v 1.50 2002/09/29 19:33:24 squidadm Exp $
- *
- * DEBUG: section 3     Configuration File Parsing
- * AUTHOR: Harvest Derived
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-
-#if SQUID_SNMP
-#include "snmp.h"
-#endif
-
-static const char *const T_SECOND_STR = "second";
-static const char *const T_MINUTE_STR = "minute";
-static const char *const T_HOUR_STR = "hour";
-static const char *const T_DAY_STR = "day";
-static const char *const T_WEEK_STR = "week";
-static const char *const T_FORTNIGHT_STR = "fortnight";
-static const char *const T_MONTH_STR = "month";
-static const char *const T_YEAR_STR = "year";
-static const char *const T_DECADE_STR = "decade";
-
-static const char *const B_BYTES_STR = "bytes";
-static const char *const B_KBYTES_STR = "KB";
-static const char *const B_MBYTES_STR = "MB";
-static const char *const B_GBYTES_STR = "GB";
-
-static const char *const list_sep = ", \t\n\r";
-
-static void parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring);
-static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd);
-static void parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring);
-static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd);
-static struct cache_dir_option common_cachedir_options[] =
-{
-    {"read-only", parse_cachedir_option_readonly, dump_cachedir_option_readonly},
-    {"max-size", parse_cachedir_option_maxsize, dump_cachedir_option_maxsize},
-    {NULL, NULL}
-};
-
-
-static void update_maxobjsize(void);
-static void configDoConfigure(void);
-static void parse_refreshpattern(refresh_t **);
-static int parseTimeUnits(const char *unit);
-static void parseTimeLine(time_t * tptr, const char *units);
-static void parse_ushort(u_short * var);
-static void parse_string(char **);
-static void default_all(void);
-static void defaults_if_none(void);
-static int parse_line(char *);
-static void parseBytesLine(size_t * bptr, const char *units);
-static size_t parseBytesUnits(const char *unit);
-static void free_all(void);
-void requirePathnameExists(const char *name, const char *path);
-static OBJH dump_config;
-#if HTTP_VIOLATIONS
-static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
-static void parse_http_header_access(header_mangler header[]);
-static void free_http_header_access(header_mangler header[]);
-static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
-static void parse_http_header_replace(header_mangler * header);
-static void free_http_header_replace(header_mangler * header);
-#endif
-static void parse_denyinfo(acl_deny_info_list ** var);
-static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
-static void free_denyinfo(acl_deny_info_list ** var);
-static void parse_sockaddr_in_list(sockaddr_in_list **);
-static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
-static void free_sockaddr_in_list(sockaddr_in_list **);
-#if 0
-static int check_null_sockaddr_in_list(const sockaddr_in_list *);
-#endif
-#if USE_SSL
-static void parse_https_port_list(https_port_list **);
-static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
-static void free_https_port_list(https_port_list **);
-#if 0
-static int check_null_https_port_list(const https_port_list *);
-#endif
-#endif /* USE_SSL */
-
-void
-self_destruct(void)
-{
-    fatalf("Bungled %s line %d: %s",
-	cfg_filename, config_lineno, config_input_line);
-}
-
-void
-wordlistDestroy(wordlist ** list)
-{
-    wordlist *w = NULL;
-    while ((w = *list) != NULL) {
-	*list = w->next;
-	safe_free(w->key);
-	memFree(w, MEM_WORDLIST);
-    }
-    *list = NULL;
-}
-
-const char *
-wordlistAdd(wordlist ** list, const char *key)
-{
-    while (*list)
-	list = &(*list)->next;
-    *list = memAllocate(MEM_WORDLIST);
-    (*list)->key = xstrdup(key);
-    (*list)->next = NULL;
-    return (*list)->key;
-}
-
-void
-wordlistJoin(wordlist ** list, wordlist ** wl)
-{
-    while (*list)
-	list = &(*list)->next;
-    *list = *wl;
-    *wl = NULL;
-}
-
-void
-wordlistAddWl(wordlist ** list, wordlist * wl)
-{
-    while (*list)
-	list = &(*list)->next;
-    for (; wl; wl = wl->next, list = &(*list)->next) {
-	*list = memAllocate(MEM_WORDLIST);
-	(*list)->key = xstrdup(wl->key);
-	(*list)->next = NULL;
-    }
-}
-
-void
-wordlistCat(const wordlist * w, MemBuf * mb)
-{
-    while (NULL != w) {
-	memBufPrintf(mb, "%s\n", w->key);
-	w = w->next;
-    }
-}
-
-wordlist *
-wordlistDup(const wordlist * w)
-{
-    wordlist *D = NULL;
-    while (NULL != w) {
-	wordlistAdd(&D, w->key);
-	w = w->next;
-    }
-    return D;
-}
-
-void
-intlistDestroy(intlist ** list)
-{
-    intlist *w = NULL;
-    intlist *n = NULL;
-    for (w = *list; w; w = n) {
-	n = w->next;
-	memFree(w, MEM_INTLIST);
-    }
-    *list = NULL;
-}
-
-int
-intlistFind(intlist * list, int i)
-{
-    intlist *w = NULL;
-    for (w = list; w; w = w->next)
-	if (w->i == i)
-	    return 1;
-    return 0;
-}
-
-/*
- * These functions is the same as atoi/l/f, except that they check for errors
- */
-
-static long
-xatol(const char *token)
-{
-    char *end;
-    long ret = strtol(token, &end, 10);
-    if (ret == 0 && end == token)
-	self_destruct();
-    return ret;
-}
-
-static int
-xatoi(const char *token)
-{
-    return xatol(token);
-}
-
-static double
-xatof(const char *token)
-{
-    char *end;
-    double ret = strtod(token, &end);
-    if (ret == 0 && end == token)
-	self_destruct();
-    return ret;
-}
-
-int
-GetInteger(void)
-{
-    char *token = strtok(NULL, w_space);
-    int i;
-    if (token == NULL)
-	self_destruct();
-    if (sscanf(token, "%d", &i) != 1)
-	self_destruct();
-    return i;
-}
-
-static void
-update_maxobjsize(void)
-{
-    int i;
-    ssize_t ms = -1;
-
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-	if (Config.cacheSwap.swapDirs[i].max_objsize > ms)
-	    ms = Config.cacheSwap.swapDirs[i].max_objsize;
-    }
-    store_maxobjsize = ms;
-}
-
-int
-parseConfigFile(const char *file_name)
-{
-    FILE *fp = NULL;
-    char *token = NULL;
-    char *tmp_line;
-    int err_count = 0;
-    int is_pipe = 0;
-    configFreeMemory();
-    default_all();
-    if (file_name[0] == '!' || file_name[0] == '|') {
-	fp = popen(file_name + 1, "r");
-	is_pipe = 1;
-    } else {
-	fp = fopen(file_name, "r");
-    }
-    if (fp == NULL)
-	fatalf("Unable to open configuration file: %s: %s",
-	    file_name, xstrerror());
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-    setmode(fileno(fp), O_TEXT);
-#endif
-    cfg_filename = file_name;
-    if (is_pipe)
-	cfg_filename = file_name + 1;
-    else if ((token = strrchr(cfg_filename, '/')))
-	cfg_filename = token + 1;
-    memset(config_input_line, '\0', BUFSIZ);
-    config_lineno = 0;
-    while (fgets(config_input_line, BUFSIZ, fp)) {
-	config_lineno++;
-	if ((token = strchr(config_input_line, '\n')))
-	    *token = '\0';
-	if (strncmp(config_input_line, "#line ", 6) == 0) {
-	    static char new_file_name[1024];
-	    static char *file;
-	    static char new_lineno;
-	    token = config_input_line + 6;
-	    new_lineno = strtol(token, &file, 0) - 1;
-	    if (file == token)
-		continue;	/* Not a valid #line directive, may be a comment */
-	    while (*file && isspace((unsigned char) *file))
-		file++;
-	    if (*file) {
-		if (*file != '"')
-		    continue;	/* Not a valid #line directive, may be a comment */
-		xstrncpy(new_file_name, file + 1, sizeof(new_file_name));
-		if ((token = strchr(new_file_name, '"')))
-		    *token = '\0';
-		cfg_filename = new_file_name;
-#if PROBABLY_NOT_WANTED_HERE
-		if ((token = strrchr(cfg_filename, '/')))
-		    cfg_filename = token + 1;
-#endif
-	    }
-	    config_lineno = new_lineno;
-	}
-	if (config_input_line[0] == '#')
-	    continue;
-	if (config_input_line[0] == '\0')
-	    continue;
-	debug(3, 5) ("Processing: '%s'\n", config_input_line);
-	tmp_line = xstrdup(config_input_line);
-	if (!parse_line(tmp_line)) {
-	    debug(3, 0) ("parseConfigFile: '%s' line %d unrecognized: '%s'\n",
-		cfg_filename,
-		config_lineno,
-		config_input_line);
-	    err_count++;
-	}
-	safe_free(tmp_line);
-    }
-    if (is_pipe) {
-	int ret = pclose(fp);
-	if (ret != 0)
-	    fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
-    } else {
-	fclose(fp);
-    }
-    defaults_if_none();
-    configDoConfigure();
-    cachemgrRegister("config",
-	"Current Squid Configuration",
-	dump_config,
-	1, 1);
-    return err_count;
-}
-
-static void
-configDoConfigure(void)
-{
-    LOCAL_ARRAY(char, buf, BUFSIZ);
-    memset(&Config2, '\0', sizeof(SquidConfig2));
-    /* init memory as early as possible */
-    memConfigure();
-    /* Sanity checks */
-    if (Config.cacheSwap.swapDirs == NULL)
-	fatal("No cache_dir's specified in config file");
-    /* calculate Config.Swap.maxSize */
-    storeDirConfigure();
-    if (0 == Config.Swap.maxSize)
-	/* people might want a zero-sized cache on purpose */
-	(void) 0;
-    else if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
-	debug(3, 0) ("WARNING cache_mem is larger than total disk cache space!\n");
-    if (Config.Announce.period > 0) {
-	Config.onoff.announce = 1;
-    } else if (Config.Announce.period < 1) {
-	Config.Announce.period = 86400 * 365;	/* one year */
-	Config.onoff.announce = 0;
-    }
-#if USE_DNSSERVERS
-    if (Config.dnsChildren < 1)
-	fatal("No dnsservers allocated");
-#endif
-    if (Config.Program.redirect) {
-	if (Config.redirectChildren < 1) {
-	    Config.redirectChildren = 0;
-	    wordlistDestroy(&Config.Program.redirect);
-	}
-    }
-    if (Config.Accel.host) {
-	snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
-	Config2.Accel.prefix = xstrdup(buf);
-	Config2.Accel.on = 1;
-    }
-    if (Config.appendDomain)
-	if (*Config.appendDomain != '.')
-	    fatal("append_domain must begin with a '.'");
-    if (Config.errHtmlText == NULL)
-	Config.errHtmlText = xstrdup(null_string);
-    storeConfigure();
-    if (Config2.Accel.on && !strcmp(Config.Accel.host, "virtual")) {
-	vhost_mode = 1;
-	if (Config.Accel.port == 0)
-	    vport_mode = 1;
-    }
-    snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
-	uniqueHostname(),
-	full_appname_string);
-    /*
-     * the extra space is for loop detection in client_side.c -- we search
-     * for substrings in the Via header.
-     */
-    snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
-	uniqueHostname(),
-	full_appname_string);
-    if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
-	Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
-    if (Config.appendDomain)
-	Config.appendDomainLen = strlen(Config.appendDomain);
-    else
-	Config.appendDomainLen = 0;
-    safe_free(debug_options)
-	debug_options = xstrdup(Config.debugOptions);
-    if (Config.retry.timeout < 5)
-	fatal("minimum_retry_timeout must be at least 5 seconds");
-    if (Config.retry.maxtries > 10)
-	fatal("maximum_single_addr_tries cannot be larger than 10");
-    if (Config.retry.maxtries < 1) {
-	debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
-	Config.retry.maxtries = 1;
-    }
-    requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
-#if USE_DNSSERVERS
-    requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
-#endif
-#if USE_UNLINKD
-    requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
-#endif
-    if (Config.Program.redirect)
-	requirePathnameExists("redirect_program", Config.Program.redirect->key);
-    requirePathnameExists("Icon Directory", Config.icons.directory);
-    requirePathnameExists("Error Directory", Config.errorDirectory);
-#if HTTP_VIOLATIONS
-    {
-	const refresh_t *R;
-	for (R = Config.Refresh; R; R = R->next) {
-	    if (!R->flags.override_expire)
-		continue;
-	    debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
-	    break;
-	}
-	for (R = Config.Refresh; R; R = R->next) {
-	    if (!R->flags.override_lastmod)
-		continue;
-	    debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
-	    break;
-	}
-    }
-#endif
-#if !HTTP_VIOLATIONS
-    Config.onoff.via = 1;
-#else
-    if (!Config.onoff.via)
-	debug(22, 1) ("WARNING: HTTP requires the use of Via\n");
-#endif
-    if (Config.Wais.relayHost) {
-	if (Config.Wais._peer)
-	    cbdataFree(Config.Wais._peer);
-	Config.Wais._peer = cbdataAlloc(peer);
-	Config.Wais._peer->host = xstrdup(Config.Wais.relayHost);
-	Config.Wais._peer->http_port = Config.Wais.relayPort;
-    }
-    if (aclPurgeMethodInUse(Config.accessList.http))
-	Config2.onoff.enable_purge = 1;
-    if (geteuid() == 0) {
-	if (NULL != Config.effectiveUser) {
-	    struct passwd *pwd = getpwnam(Config.effectiveUser);
-	    if (NULL == pwd)
-		/*
-		 * Andres Kroonmaa <andre@online.ee>:
-		 * Some getpwnam() implementations (Solaris?) require
-		 * an available FD < 256 for opening a FILE* to the
-		 * passwd file.
-		 * DW:
-		 * This should be safe at startup, but might still fail
-		 * during reconfigure.
-		 */
-		fatalf("getpwnam failed to find userid for effective user '%s'",
-		    Config.effectiveUser);
-	    Config2.effectiveUserID = pwd->pw_uid;
-	    Config2.effectiveGroupID = pwd->pw_gid;
-	}
-    } else {
-	Config2.effectiveUserID = geteuid();
-	Config2.effectiveGroupID = getegid();
-    }
-    if (NULL != Config.effectiveGroup) {
-	struct group *grp = getgrnam(Config.effectiveGroup);
-	if (NULL == grp)
-	    fatalf("getgrnam failed to find groupid for effective group '%s'",
-		Config.effectiveGroup);
-	Config2.effectiveGroupID = grp->gr_gid;
-    }
-    urlExtMethodConfigure();
-    if (0 == Config.onoff.client_db) {
-	acl *a;
-	for (a = Config.aclList; a; a = a->next) {
-	    if (ACL_MAXCONN != a->type)
-		continue;
-	    debug(22, 0) ("WARNING: 'maxconn' ACL (%s) won't work with client_db disabled\n", a->name);
-	}
-    }
-}
-
-/* Parse a time specification from the config file.  Store the
- * result in 'tptr', after converting it to 'units' */
-static void
-parseTimeLine(time_t * tptr, const char *units)
-{
-    char *token;
-    double d;
-    time_t m;
-    time_t u;
-    if ((u = parseTimeUnits(units)) == 0)
-	self_destruct();
-    if ((token = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-    d = xatof(token);
-    m = u;			/* default to 'units' if none specified */
-    if (0 == d)
-	(void) 0;
-    else if ((token = strtok(NULL, w_space)) == NULL)
-	debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
-	    config_input_line, d, units);
-    else if ((m = parseTimeUnits(token)) == 0)
-	self_destruct();
-    *tptr = m * d / u;
-}
-
-static int
-parseTimeUnits(const char *unit)
-{
-    if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
-	return 1;
-    if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
-	return 60;
-    if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
-	return 3600;
-    if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
-	return 86400;
-    if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
-	return 86400 * 7;
-    if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
-	return 86400 * 14;
-    if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
-	return 86400 * 30;
-    if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
-	return 86400 * 365.2522;
-    if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
-	return 86400 * 365.2522 * 10;
-    debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit);
-    return 0;
-}
-
-static void
-parseBytesLine(size_t * bptr, const char *units)
-{
-    char *token;
-    double d;
-    size_t m;
-    size_t u;
-    if ((u = parseBytesUnits(units)) == 0)
-	self_destruct();
-    if ((token = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-    d = xatof(token);
-    m = u;			/* default to 'units' if none specified */
-    if (0.0 == d)
-	(void) 0;
-    else if ((token = strtok(NULL, w_space)) == NULL)
-	debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
-	    config_input_line, d, units);
-    else if ((m = parseBytesUnits(token)) == 0)
-	self_destruct();
-    *bptr = m * d / u;
-}
-
-static size_t
-parseBytesUnits(const char *unit)
-{
-    if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
-	return 1;
-    if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
-	return 1 << 10;
-    if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
-	return 1 << 20;
-    if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
-	return 1 << 30;
-    debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
-    return 0;
-}
-
-/*****************************************************************************
- * Max
- *****************************************************************************/
-
-static void
-dump_acl(StoreEntry * entry, const char *name, acl * ae)
-{
-    wordlist *w;
-    wordlist *v;
-    while (ae != NULL) {
-	debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
-	v = w = aclDumpGeneric(ae);
-	while (v != NULL) {
-	    debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
-	    storeAppendPrintf(entry, "%s %s %s %s\n",
-		name,
-		ae->name,
-		aclTypeToStr(ae->type),
-		v->key);
-	    v = v->next;
-	}
-	wordlistDestroy(&w);
-	ae = ae->next;
-    }
-}
-
-static void
-parse_acl(acl ** ae)
-{
-    aclParseAclLine(ae);
-}
-
-static void
-free_acl(acl ** ae)
-{
-    aclDestroyAcls(ae);
-}
-
-static void
-dump_acl_list(StoreEntry * entry, acl_list * head)
-{
-    acl_list *l;
-    for (l = head; l; l = l->next) {
-	storeAppendPrintf(entry, " %s%s",
-	    l->op ? null_string : "!",
-	    l->_acl->name);
-    }
-}
-
-static void
-dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
-{
-    acl_access *l;
-    for (l = head; l; l = l->next) {
-	storeAppendPrintf(entry, "%s %s",
-	    name,
-	    l->allow ? "Allow" : "Deny");
-	dump_acl_list(entry, l->aclList);
-	storeAppendPrintf(entry, "\n");
-    }
-}
-
-static void
-parse_acl_access(acl_access ** head)
-{
-    aclParseAccessLine(head);
-}
-
-static void
-free_acl_access(acl_access ** head)
-{
-    aclDestroyAccessList(head);
-}
-
-static void
-dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
-{
-    storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
-}
-
-static void
-parse_address(struct in_addr *addr)
-{
-    const struct hostent *hp;
-    char *token = strtok(NULL, w_space);
-
-    if (token == NULL)
-	self_destruct();
-    if (safe_inet_addr(token, addr) == 1)
-	(void) 0;
-    else if ((hp = gethostbyname(token)))	/* dont use ipcache */
-	*addr = inaddrFromHostent(hp);
-    else
-	self_destruct();
-}
-
-static void
-free_address(struct in_addr *addr)
-{
-    memset(addr, '\0', sizeof(struct in_addr));
-}
-
-CBDATA_TYPE(acl_address);
-
-static void
-dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
-{
-    acl_address *l;
-    for (l = head; l; l = l->next) {
-	if (l->addr.s_addr != INADDR_ANY)
-	    storeAppendPrintf(entry, "%s %s", name, inet_ntoa(l->addr));
-	else
-	    storeAppendPrintf(entry, "%s autoselect", name);
-	dump_acl_list(entry, l->aclList);
-	storeAppendPrintf(entry, "\n");
-    }
-}
-
-static void
-freed_acl_address(void *data)
-{
-    acl_address *l = data;
-    aclDestroyAclList(&l->aclList);
-}
-
-static void
-parse_acl_address(acl_address ** head)
-{
-    acl_address *l;
-    acl_address **tail = head;	/* sane name below */
-    CBDATA_INIT_TYPE_FREECB(acl_address, freed_acl_address);
-    l = cbdataAlloc(acl_address);
-    parse_address(&l->addr);
-    aclParseAclList(&l->aclList);
-    while (*tail)
-	tail = &(*tail)->next;
-    *tail = l;
-}
-
-static void
-free_acl_address(acl_address ** head)
-{
-    while (*head) {
-	acl_address *l = *head;
-	*head = l->next;
-	cbdataFree(l);
-    }
-}
-
-CBDATA_TYPE(acl_tos);
-
-static void
-dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
-{
-    acl_tos *l;
-    for (l = head; l; l = l->next) {
-	if (l->tos > 0)
-	    storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
-	else
-	    storeAppendPrintf(entry, "%s none", name);
-	dump_acl_list(entry, l->aclList);
-	storeAppendPrintf(entry, "\n");
-    }
-}
-
-static void
-freed_acl_tos(void *data)
-{
-    acl_tos *l = data;
-    aclDestroyAclList(&l->aclList);
-}
-
-static void
-parse_acl_tos(acl_tos ** head)
-{
-    acl_tos *l;
-    acl_tos **tail = head;	/* sane name below */
-    int tos;
-    char junk;
-    char *token = strtok(NULL, w_space);
-    if (!token)
-	self_destruct();
-    if (sscanf(token, "0x%x%c", &tos, &junk) != 1)
-	self_destruct();
-    if (tos < 0 || tos > 255)
-	self_destruct();
-    CBDATA_INIT_TYPE_FREECB(acl_tos, freed_acl_tos);
-    l = cbdataAlloc(acl_tos);
-    l->tos = tos;
-    aclParseAclList(&l->aclList);
-    while (*tail)
-	tail = &(*tail)->next;
-    *tail = l;
-}
-
-static void
-free_acl_tos(acl_tos ** head)
-{
-    while (*head) {
-	acl_tos *l = *head;
-	*head = l->next;
-	l->next = NULL;
-	cbdataFree(l);
-    }
-}
-
-#if DELAY_POOLS
-
-/* do nothing - free_delay_pool_count is the magic free function.
- * this is why delay_pool_count isn't just marked TYPE: ushort
- */
-#define free_delay_pool_class(X)
-#define free_delay_pool_access(X)
-#define free_delay_pool_rates(X)
-#define dump_delay_pool_class(X, Y, Z)
-#define dump_delay_pool_access(X, Y, Z)
-#define dump_delay_pool_rates(X, Y, Z)
-
-static void
-free_delay_pool_count(delayConfig * cfg)
-{
-    int i;
-
-    if (!cfg->pools)
-	return;
-    for (i = 0; i < cfg->pools; i++) {
-	if (cfg->class[i]) {
-	    delayFreeDelayPool(i);
-	    safe_free(cfg->rates[i]);
-	}
-	aclDestroyAccessList(&cfg->access[i]);
-    }
-    delayFreeDelayData(cfg->pools);
-    xfree(cfg->class);
-    xfree(cfg->rates);
-    xfree(cfg->access);
-    memset(cfg, 0, sizeof(*cfg));
-}
-
-static void
-dump_delay_pool_count(StoreEntry * entry, const char *name, delayConfig cfg)
-{
-    int i;
-    LOCAL_ARRAY(char, nom, 32);
-
-    if (!cfg.pools) {
-	storeAppendPrintf(entry, "%s 0\n", name);
-	return;
-    }
-    storeAppendPrintf(entry, "%s %d\n", name, cfg.pools);
-    for (i = 0; i < cfg.pools; i++) {
-	storeAppendPrintf(entry, "delay_class %d %d\n", i + 1, cfg.class[i]);
-	snprintf(nom, 32, "delay_access %d", i + 1);
-	dump_acl_access(entry, nom, cfg.access[i]);
-	if (cfg.class[i] >= 1)
-	    storeAppendPrintf(entry, "delay_parameters %d %d/%d", i + 1,
-		cfg.rates[i]->aggregate.restore_bps,
-		cfg.rates[i]->aggregate.max_bytes);
-	if (cfg.class[i] >= 3)
-	    storeAppendPrintf(entry, " %d/%d",
-		cfg.rates[i]->network.restore_bps,
-		cfg.rates[i]->network.max_bytes);
-	if (cfg.class[i] >= 2)
-	    storeAppendPrintf(entry, " %d/%d",
-		cfg.rates[i]->individual.restore_bps,
-		cfg.rates[i]->individual.max_bytes);
-	if (cfg.class[i] >= 1)
-	    storeAppendPrintf(entry, "\n");
-    }
-}
-
-static void
-parse_delay_pool_count(delayConfig * cfg)
-{
-    if (cfg->pools) {
-	debug(3, 0) ("parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config\n");
-	free_delay_pool_count(cfg);
-    }
-    parse_ushort(&cfg->pools);
-    if (cfg->pools) {
-	delayInitDelayData(cfg->pools);
-	cfg->class = xcalloc(cfg->pools, sizeof(u_char));
-	cfg->rates = xcalloc(cfg->pools, sizeof(delaySpecSet *));
-	cfg->access = xcalloc(cfg->pools, sizeof(acl_access *));
-    }
-}
-
-static void
-parse_delay_pool_class(delayConfig * cfg)
-{
-    ushort pool, class;
-
-    parse_ushort(&pool);
-    if (pool < 1 || pool > cfg->pools) {
-	debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
-	return;
-    }
-    parse_ushort(&class);
-    if (class < 1 || class > 3) {
-	debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d class %d not in 1 .. 3\n", pool, class);
-	return;
-    }
-    pool--;
-    if (cfg->class[pool]) {
-	delayFreeDelayPool(pool);
-	safe_free(cfg->rates[pool]);
-    }
-    cfg->rates[pool] = xmalloc(class * sizeof(delaySpec));
-    cfg->class[pool] = class;
-    cfg->rates[pool]->aggregate.restore_bps = cfg->rates[pool]->aggregate.max_bytes = -1;
-    if (cfg->class[pool] >= 3)
-	cfg->rates[pool]->network.restore_bps = cfg->rates[pool]->network.max_bytes = -1;
-    if (cfg->class[pool] >= 2)
-	cfg->rates[pool]->individual.restore_bps = cfg->rates[pool]->individual.max_bytes = -1;
-    delayCreateDelayPool(pool, class);
-}
-
-static void
-parse_delay_pool_rates(delayConfig * cfg)
-{
-    ushort pool, class;
-    int i;
-    delaySpec *ptr;
-    char *token;
-
-    parse_ushort(&pool);
-    if (pool < 1 || pool > cfg->pools) {
-	debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
-	return;
-    }
-    pool--;
-    class = cfg->class[pool];
-    if (class == 0) {
-	debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d attempt to set rates with class not set\n", pool + 1);
-	return;
-    }
-    ptr = (delaySpec *) cfg->rates[pool];
-    /* read in "class" sets of restore,max pairs */
-    while (class--) {
-	token = strtok(NULL, "/");
-	if (token == NULL)
-	    self_destruct();
-	if (sscanf(token, "%d", &i) != 1)
-	    self_destruct();
-	ptr->restore_bps = i;
-	i = GetInteger();
-	ptr->max_bytes = i;
-	ptr++;
-    }
-    class = cfg->class[pool];
-    /* if class is 3, swap around network and individual */
-    if (class == 3) {
-	delaySpec tmp;
-
-	tmp = cfg->rates[pool]->individual;
-	cfg->rates[pool]->individual = cfg->rates[pool]->network;
-	cfg->rates[pool]->network = tmp;
-    }
-    /* initialize the delay pools */
-    delayInitDelayPool(pool, class, cfg->rates[pool]);
-}
-
-static void
-parse_delay_pool_access(delayConfig * cfg)
-{
-    ushort pool;
-
-    parse_ushort(&pool);
-    if (pool < 1 || pool > cfg->pools) {
-	debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
-	return;
-    }
-    aclParseAccessLine(&cfg->access[pool - 1]);
-}
-#endif
-
-#if HTTP_VIOLATIONS
-static void
-dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
-{
-    int i;
-    for (i = 0; i < HDR_ENUM_END; i++) {
-	if (header[i].access_list != NULL) {
-	    storeAppendPrintf(entry, "%s ", name);
-	    dump_acl_access(entry, httpHeaderNameById(i),
-		header[i].access_list);
-	}
-    }
-}
-
-static void
-parse_http_header_access(header_mangler header[])
-{
-    int id, i;
-    char *t = NULL;
-    if ((t = strtok(NULL, w_space)) == NULL) {
-	debug(3, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(3, 0) ("parse_http_header_access: missing header name.\n");
-	return;
-    }
-    /* Now lookup index of header. */
-    id = httpHeaderIdByNameDef(t, strlen(t));
-    if (strcmp(t, "All") == 0)
-	id = HDR_ENUM_END;
-    else if (strcmp(t, "Other") == 0)
-	id = HDR_OTHER;
-    else if (id == -1) {
-	debug(3, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(3, 0) ("parse_http_header_access: unknown header name %s.\n", t);
-	return;
-    }
-    if (id != HDR_ENUM_END) {
-	parse_acl_access(&header[id].access_list);
-    } else {
-	char *next_string = t + strlen(t) - 1;
-	*next_string = 'A';
-	*(next_string + 1) = ' ';
-	for (i = 0; i < HDR_ENUM_END; i++) {
-	    char *new_string = xstrdup(next_string);
-	    strtok(new_string, w_space);
-	    parse_acl_access(&header[i].access_list);
-	    safe_free(new_string);
-	}
-    }
-}
-
-static void
-free_http_header_access(header_mangler header[])
-{
-    int i;
-    for (i = 0; i < HDR_ENUM_END; i++) {
-	free_acl_access(&header[i].access_list);
-    }
-}
-
-static void
-dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
-    header[])
-{
-    int i;
-    for (i = 0; i < HDR_ENUM_END; i++) {
-	if (NULL == header[i].replacement)
-	    continue;
-	storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
-	    header[i].replacement);
-    }
-}
-
-static void
-parse_http_header_replace(header_mangler header[])
-{
-    int id, i;
-    char *t = NULL;
-    if ((t = strtok(NULL, w_space)) == NULL) {
-	debug(3, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(3, 0) ("parse_http_header_replace: missing header name.\n");
-	return;
-    }
-    /* Now lookup index of header. */
-    id = httpHeaderIdByNameDef(t, strlen(t));
-    if (strcmp(t, "All") == 0)
-	id = HDR_ENUM_END;
-    else if (strcmp(t, "Other") == 0)
-	id = HDR_OTHER;
-    else if (id == -1) {
-	debug(3, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(3, 0) ("parse_http_header_replace: unknown header name %s.\n",
-	    t);
-	return;
-    }
-    if (id != HDR_ENUM_END) {
-	if (header[id].replacement != NULL)
-	    safe_free(header[id].replacement);
-	header[id].replacement = xstrdup(t + strlen(t) + 1);
-    } else {
-	for (i = 0; i < HDR_ENUM_END; i++) {
-	    if (header[i].replacement != NULL)
-		safe_free(header[i].replacement);
-	    header[i].replacement = xstrdup(t + strlen(t) + 1);
-	}
-    }
-}
-
-static void
-free_http_header_replace(header_mangler header[])
-{
-    int i;
-    for (i = 0; i < HDR_ENUM_END; i++) {
-	if (header[i].replacement != NULL)
-	    safe_free(header[i].replacement);
-    }
-}
-#endif
-
-void
-dump_cachedir_options(StoreEntry * entry, struct cache_dir_option *options, SwapDir * sd)
-{
-    struct cache_dir_option *option;
-    if (!options)
-	return;
-    for (option = options; option->name; option++)
-	option->dump(entry, option->name, sd);
-}
-
-static void
-dump_cachedir(StoreEntry * entry, const char *name, cacheSwap swap)
-{
-    SwapDir *s;
-    int i;
-    for (i = 0; i < swap.n_configured; i++) {
-	s = swap.swapDirs + i;
-	storeAppendPrintf(entry, "%s %s %s", name, s->type, s->path);
-	if (s->dump)
-	    s->dump(entry, s);
-	dump_cachedir_options(entry, common_cachedir_options, s);
-	storeAppendPrintf(entry, "\n");
-    }
-}
-
-static int
-check_null_cachedir(cacheSwap swap)
-{
-    return swap.swapDirs == NULL;
-}
-
-static int
-check_null_string(char *s)
-{
-    return s == NULL;
-}
-
-static void
-allocate_new_authScheme(authConfig * cfg)
-{
-    if (cfg->schemes == NULL) {
-	cfg->n_allocated = 4;
-	cfg->schemes = xcalloc(cfg->n_allocated, sizeof(authScheme));
-    }
-    if (cfg->n_allocated == cfg->n_configured) {
-	authScheme *tmp;
-	cfg->n_allocated <<= 1;
-	tmp = xcalloc(cfg->n_allocated, sizeof(authScheme));
-	xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme));
-	xfree(cfg->schemes);
-	cfg->schemes = tmp;
-    }
-}
-
-static void
-parse_authparam(authConfig * config)
-{
-    char *type_str;
-    char *param_str;
-    authScheme *scheme = NULL;
-    int type, i;
-
-    if ((type_str = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-
-    if ((param_str = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-
-    if ((type = authenticateAuthSchemeId(type_str)) == -1) {
-	debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
-	return;
-    }
-    for (i = 0; i < config->n_configured; i++) {
-	if (config->schemes[i].Id == type) {
-	    scheme = config->schemes + i;
-	}
-    }
-
-    if (scheme == NULL) {
-	allocate_new_authScheme(config);
-	scheme = config->schemes + config->n_configured;
-	config->n_configured++;
-	scheme->Id = type;
-	scheme->typestr = authscheme_list[type].typestr;
-    }
-    authscheme_list[type].parse(scheme, config->n_configured, param_str);
-}
-
-static void
-free_authparam(authConfig * cfg)
-{
-    authScheme *scheme;
-    int i;
-    /* DON'T FREE THESE FOR RECONFIGURE */
-    if (reconfiguring)
-	return;
-    for (i = 0; i < cfg->n_configured; i++) {
-	scheme = cfg->schemes + i;
-	authscheme_list[scheme->Id].freeconfig(scheme);
-    }
-    safe_free(cfg->schemes);
-    cfg->schemes = NULL;
-    cfg->n_allocated = 0;
-    cfg->n_configured = 0;
-}
-
-static void
-dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
-{
-    authScheme *scheme;
-    int i;
-    for (i = 0; i < cfg.n_configured; i++) {
-	scheme = cfg.schemes + i;
-	authscheme_list[scheme->Id].dump(entry, name, scheme);
-    }
-}
-
-void
-allocate_new_swapdir(cacheSwap * swap)
-{
-    if (swap->swapDirs == NULL) {
-	swap->n_allocated = 4;
-	swap->swapDirs = xcalloc(swap->n_allocated, sizeof(SwapDir));
-    }
-    if (swap->n_allocated == swap->n_configured) {
-	SwapDir *tmp;
-	swap->n_allocated <<= 1;
-	tmp = xcalloc(swap->n_allocated, sizeof(SwapDir));
-	xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir));
-	xfree(swap->swapDirs);
-	swap->swapDirs = tmp;
-    }
-}
-
-static int
-find_fstype(char *type)
-{
-    int i;
-    for (i = 0; storefs_list[i].typestr != NULL; i++) {
-	if (strcasecmp(type, storefs_list[i].typestr) == 0) {
-	    return i;
-	}
-    }
-    return (-1);
-}
-
-static void
-parse_cachedir(cacheSwap * swap)
-{
-    char *type_str;
-    char *path_str;
-    SwapDir *sd;
-    int i;
-    int fs;
-
-    if ((type_str = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-
-    if ((path_str = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-
-    /*
-     * This bit of code is a little strange.
-     * See, if we find a path and type match for a given line, then
-     * as long as we're reconfiguring, we can just call its reconfigure
-     * function. No harm there.
-     *
-     * Trouble is, if we find a path match, but not a type match, we have
-     * a dilemma - we could gracefully shut down the fs, kill it, and
-     * create a new one of a new type in its place, BUT at this stage the
-     * fs is meant to be the *NEW* one, and so things go very strange. :-)
-     *
-     * So, we'll assume the person isn't going to change the fs type for now,
-     * and XXX later on we will make sure that its picked up.
-     *
-     * (moving around cache_dir lines will be looked at later in a little
-     * more sane detail..)
-     */
-
-    for (i = 0; i < swap->n_configured; i++) {
-	if (0 == strcasecmp(path_str, swap->swapDirs[i].path)) {
-	    /* This is a little weird, you'll appreciate it later */
-	    fs = find_fstype(type_str);
-	    if (fs < 0) {
-		fatalf("Unknown cache_dir type '%s'\n", type_str);
-	    }
-	    sd = swap->swapDirs + i;
-	    storefs_list[fs].reconfigurefunc(sd, i, path_str);
-	    update_maxobjsize();
-	    return;
-	}
-    }
-
-    assert(swap->n_configured < 63);	/* 7 bits, signed */
-
-    fs = find_fstype(type_str);
-    if (fs < 0) {
-	/* If we get here, we didn't find a matching cache_dir type */
-	fatalf("Unknown cache_dir type '%s'\n", type_str);
-    }
-    allocate_new_swapdir(swap);
-    sd = swap->swapDirs + swap->n_configured;
-    sd->type = storefs_list[fs].typestr;
-    /* defaults in case fs implementation fails to set these */
-    sd->max_objsize = -1;
-    sd->fs.blksize = 1024;
-    /* parse the FS parameters and options */
-    storefs_list[fs].parsefunc(sd, swap->n_configured, path_str);
-    swap->n_configured++;
-    /* Update the max object size */
-    update_maxobjsize();
-}
-
-static void
-parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring)
-{
-    int read_only = 0;
-    if (value)
-	read_only = xatoi(value);
-    else
-	read_only = 1;
-    sd->flags.read_only = read_only;
-}
-
-static void
-dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd)
-{
-    if (sd->flags.read_only)
-	storeAppendPrintf(e, " %s", option);
-}
-
-static void
-parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring)
-{
-    ssize_t size;
-
-    if (!value)
-	self_destruct();
-
-    size = xatoi(value);
-
-    if (reconfiguring && sd->max_objsize != size)
-	debug(3, 1) ("Cache dir '%s' max object size now %ld\n", sd->path, (long int) size);
-
-    sd->max_objsize = size;
-}
-
-static void
-dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd)
-{
-    if (sd->max_objsize != -1)
-	storeAppendPrintf(e, " %s=%ld", option, (long int) sd->max_objsize);
-}
-
-void
-parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring)
-{
-    int old_read_only = sd->flags.read_only;
-    char *name, *value;
-    struct cache_dir_option *option, *op;
-
-    while ((name = strtok(NULL, w_space)) != NULL) {
-	value = strchr(name, '=');
-	if (value)
-	    *value++ = '\0';	/* cut on = */
-	option = NULL;
-	if (options) {
-	    for (op = options; !option && op->name; op++) {
-		if (strcmp(op->name, name) == 0) {
-		    option = op;
-		    break;
-		}
-	    }
-	}
-	for (op = common_cachedir_options; !option && op->name; op++) {
-	    if (strcmp(op->name, name) == 0) {
-		option = op;
-		break;
-	    }
-	}
-	if (!option || !option->parse)
-	    self_destruct();
-	option->parse(sd, name, value, reconfiguring);
-    }
-    /*
-     * Handle notifications about reconfigured single-options with no value
-     * where the removal of the option cannot be easily detected in the
-     * parsing...
-     */
-    if (reconfiguring) {
-	if (old_read_only != sd->flags.read_only) {
-	    debug(3, 1) ("Cache dir '%s' now %s\n",
-		sd->path, sd->flags.read_only ? "Read-Only" : "Read-Write");
-	}
-    }
-}
-
-static void
-free_cachedir(cacheSwap * swap)
-{
-    SwapDir *s;
-    int i;
-    /* DON'T FREE THESE FOR RECONFIGURE */
-    if (reconfiguring)
-	return;
-    for (i = 0; i < swap->n_configured; i++) {
-	s = swap->swapDirs + i;
-	s->freefs(s);
-	xfree(s->path);
-    }
-    safe_free(swap->swapDirs);
-    swap->swapDirs = NULL;
-    swap->n_allocated = 0;
-    swap->n_configured = 0;
-}
-
-static const char *
-peer_type_str(const peer_t type)
-{
-    switch (type) {
-    case PEER_PARENT:
-	return "parent";
-	break;
-    case PEER_SIBLING:
-	return "sibling";
-	break;
-    case PEER_MULTICAST:
-	return "multicast";
-	break;
-    default:
-	return "unknown";
-	break;
-    }
-}
-
-static void
-dump_peer(StoreEntry * entry, const char *name, peer * p)
-{
-    domain_ping *d;
-    domain_type *t;
-    LOCAL_ARRAY(char, xname, 128);
-    while (p != NULL) {
-	storeAppendPrintf(entry, "%s %s %s %d %d",
-	    name,
-	    p->host,
-	    neighborTypeStr(p),
-	    p->http_port,
-	    p->icp.port);
-	dump_peer_options(entry, p);
-	for (d = p->peer_domain; d; d = d->next) {
-	    storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
-		p->host,
-		d->do_ping ? null_string : "!",
-		d->domain);
-	}
-	if (p->access) {
-	    snprintf(xname, 128, "cache_peer_access %s", p->host);
-	    dump_acl_access(entry, xname, p->access);
-	}
-	for (t = p->typelist; t; t = t->next) {
-	    storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
-		p->host,
-		peer_type_str(t->type),
-		t->domain);
-	}
-	p = p->next;
-    }
-}
-
-static void
-parse_peer(peer ** head)
-{
-    char *token = NULL;
-    peer *p;
-    int i;
-    p = cbdataAlloc(peer);
-    p->http_port = CACHE_HTTP_PORT;
-    p->icp.port = CACHE_ICP_PORT;
-    p->weight = 1;
-    p->basetime = 0;
-    p->stats.logged_state = PEER_ALIVE;
-    if ((token = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-    p->host = xstrdup(token);
-    if ((token = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-    p->type = parseNeighborType(token);
-    i = GetInteger();
-    p->http_port = (u_short) i;
-    i = GetInteger();
-    p->icp.port = (u_short) i;
-    while ((token = strtok(NULL, w_space))) {
-	if (!strcasecmp(token, "proxy-only")) {
-	    p->options.proxy_only = 1;
-	} else if (!strcasecmp(token, "no-query")) {
-	    p->options.no_query = 1;
-	} else if (!strcasecmp(token, "background-ping")) {
-	    p->options.background_ping = 1;
-	} else if (!strcasecmp(token, "no-digest")) {
-	    p->options.no_digest = 1;
-	} else if (!strcasecmp(token, "multicast-responder")) {
-	    p->options.mcast_responder = 1;
-	} else if (!strncasecmp(token, "weight=", 7)) {
-	    p->weight = xatoi(token + 7);
-	} else if (!strncasecmp(token, "basetime=", 9)) {
-	    p->basetime = xatoi(token + 9);
-	} else if (!strcasecmp(token, "closest-only")) {
-	    p->options.closest_only = 1;
-	} else if (!strncasecmp(token, "ttl=", 4)) {
-	    p->mcast.ttl = xatoi(token + 4);
-	    if (p->mcast.ttl < 0)
-		p->mcast.ttl = 0;
-	    if (p->mcast.ttl > 128)
-		p->mcast.ttl = 128;
-	} else if (!strcasecmp(token, "default")) {
-	    p->options.default_parent = 1;
-	} else if (!strcasecmp(token, "round-robin")) {
-	    p->options.roundrobin = 1;
-	} else if (!strcasecmp(token, "weighted-round-robin")) {
-	    p->options.weighted_roundrobin = 1;
-#if USE_HTCP
-	} else if (!strcasecmp(token, "htcp")) {
-	    p->options.htcp = 1;
-#endif
-	} else if (!strcasecmp(token, "no-netdb-exchange")) {
-	    p->options.no_netdb_exchange = 1;
-#if USE_CARP
-	} else if (!strcasecmp(token, "carp")) {
-	    if (p->type != PEER_PARENT)
-		fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
-	    p->options.carp = 1;
-#endif
-#if DELAY_POOLS
-	} else if (!strcasecmp(token, "no-delay")) {
-	    p->options.no_delay = 1;
-#endif
-	} else if (!strncasecmp(token, "login=", 6)) {
-	    p->login = xstrdup(token + 6);
-	    rfc1738_unescape(p->login);
-	} else if (!strncasecmp(token, "connect-timeout=", 16)) {
-	    p->connect_timeout = xatoi(token + 16);
-#if USE_CACHE_DIGESTS
-	} else if (!strncasecmp(token, "digest-url=", 11)) {
-	    p->digest_url = xstrdup(token + 11);
-#endif
-	} else if (!strcasecmp(token, "allow-miss")) {
-	    p->options.allow_miss = 1;
-	} else if (!strncasecmp(token, "max-conn=", 9)) {
-	    p->max_conn = xatoi(token + 9);
-	} else {
-	    debug(3, 0) ("parse_peer: token='%s'\n", token);
-	    self_destruct();
-	}
-    }
-    if (p->weight < 1)
-	p->weight = 1;
-    p->icp.version = ICP_VERSION_CURRENT;
-    p->tcp_up = PEER_TCP_MAGIC_COUNT;
-    p->test_fd = -1;
-#if USE_CACHE_DIGESTS
-    if (!p->options.no_digest) {
-	/* XXX This looks odd.. who has the original pointer
-	 * then?
-	 */
-	PeerDigest *pd = peerDigestCreate(p);
-	p->digest = cbdataReference(pd);
-    }
-#endif
-    while (*head != NULL)
-	head = &(*head)->next;
-    *head = p;
-    Config.npeers++;
-    peerClearRR(p);
-}
-
-static void
-free_peer(peer ** P)
-{
-    peer *p;
-    while ((p = *P) != NULL) {
-	*P = p->next;
-#if USE_CACHE_DIGESTS
-	cbdataReferenceDone(p->digest);
-#endif
-	cbdataFree(p);
-    }
-    Config.npeers = 0;
-}
-
-static void
-dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
-{
-    wordlist *w;
-    while (list != NULL) {
-	if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
-	    storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
-	else
-	    storeAppendPrintf(entry, "%s %s", name, list->passwd);
-	for (w = list->actions; w != NULL; w = w->next) {
-	    storeAppendPrintf(entry, " %s", w->key);
-	}
-	storeAppendPrintf(entry, "\n");
-	list = list->next;
-    }
-}
-
-static void
-parse_cachemgrpasswd(cachemgr_passwd ** head)
-{
-    char *passwd = NULL;
-    wordlist *actions = NULL;
-    cachemgr_passwd *p;
-    cachemgr_passwd **P;
-    parse_string(&passwd);
-    parse_wordlist(&actions);
-    p = xcalloc(1, sizeof(cachemgr_passwd));
-    p->passwd = passwd;
-    p->actions = actions;
-    for (P = head; *P; P = &(*P)->next);
-    *P = p;
-}
-
-static void
-free_cachemgrpasswd(cachemgr_passwd ** head)
-{
-    cachemgr_passwd *p;
-    while ((p = *head) != NULL) {
-	*head = p->next;
-	xfree(p->passwd);
-	wordlistDestroy(&p->actions);
-	xfree(p);
-    }
-}
-
-static void
-dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
-{
-    acl_name_list *a;
-    while (var != NULL) {
-	storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
-	for (a = var->acl_list; a != NULL; a = a->next)
-	    storeAppendPrintf(entry, " %s", a->name);
-	storeAppendPrintf(entry, "\n");
-	var = var->next;
-    }
-}
-
-static void
-parse_denyinfo(acl_deny_info_list ** var)
-{
-    aclParseDenyInfoLine(var);
-}
-
-void
-free_denyinfo(acl_deny_info_list ** list)
-{
-    acl_deny_info_list *a = NULL;
-    acl_deny_info_list *a_next = NULL;
-    acl_name_list *l = NULL;
-    acl_name_list *l_next = NULL;
-    for (a = *list; a; a = a_next) {
-	for (l = a->acl_list; l; l = l_next) {
-	    l_next = l->next;
-	    memFree(l, MEM_ACL_NAME_LIST);
-	    l = NULL;
-	}
-	a_next = a->next;
-	memFree(a, MEM_ACL_DENY_INFO_LIST);
-	a = NULL;
-    }
-    *list = NULL;
-}
-
-static void
-parse_peer_access(void)
-{
-    char *host = NULL;
-    peer *p;
-    if (!(host = strtok(NULL, w_space)))
-	self_destruct();
-    if ((p = peerFindByName(host)) == NULL) {
-	debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
-	    cfg_filename, config_lineno, host);
-	return;
-    }
-    aclParseAccessLine(&p->access);
-}
-
-static void
-parse_hostdomain(void)
-{
-    char *host = NULL;
-    char *domain = NULL;
-    if (!(host = strtok(NULL, w_space)))
-	self_destruct();
-    while ((domain = strtok(NULL, list_sep))) {
-	domain_ping *l = NULL;
-	domain_ping **L = NULL;
-	peer *p;
-	if ((p = peerFindByName(host)) == NULL) {
-	    debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
-		cfg_filename, config_lineno, host);
-	    continue;
-	}
-	l = xcalloc(1, sizeof(domain_ping));
-	l->do_ping = 1;
-	if (*domain == '!') {	/* check for !.edu */
-	    l->do_ping = 0;
-	    domain++;
-	}
-	l->domain = xstrdup(domain);
-	for (L = &(p->peer_domain); *L; L = &((*L)->next));
-	*L = l;
-    }
-}
-
-static void
-parse_hostdomaintype(void)
-{
-    char *host = NULL;
-    char *type = NULL;
-    char *domain = NULL;
-    if (!(host = strtok(NULL, w_space)))
-	self_destruct();
-    if (!(type = strtok(NULL, w_space)))
-	self_destruct();
-    while ((domain = strtok(NULL, list_sep))) {
-	domain_type *l = NULL;
-	domain_type **L = NULL;
-	peer *p;
-	if ((p = peerFindByName(host)) == NULL) {
-	    debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
-		cfg_filename, config_lineno, host);
-	    return;
-	}
-	l = xcalloc(1, sizeof(domain_type));
-	l->type = parseNeighborType(type);
-	l->domain = xstrdup(domain);
-	for (L = &(p->typelist); *L; L = &((*L)->next));
-	*L = l;
-    }
-}
-
-#if UNUSED_CODE
-static void
-dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
-{
-    while (u) {
-	storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
-	u = u->next;
-    }
-}
-
-static int
-check_null_ushortlist(ushortlist * u)
-{
-    return u == NULL;
-}
-
-static void
-parse_ushortlist(ushortlist ** P)
-{
-    char *token;
-    int i;
-    ushortlist *u;
-    ushortlist **U;
-    while ((token = strtok(NULL, w_space))) {
-	if (sscanf(token, "%d", &i) != 1)
-	    self_destruct();
-	if (i < 0)
-	    i = 0;
-	u = xcalloc(1, sizeof(ushortlist));
-	u->i = (u_short) i;
-	for (U = P; *U; U = &(*U)->next);
-	*U = u;
-    }
-}
-
-static void
-free_ushortlist(ushortlist ** P)
-{
-    ushortlist *u;
-    while ((u = *P) != NULL) {
-	*P = u->next;
-	xfree(u);
-    }
-}
-#endif
-
-static void
-dump_int(StoreEntry * entry, const char *name, int var)
-{
-    storeAppendPrintf(entry, "%s %d\n", name, var);
-}
-
-void
-parse_int(int *var)
-{
-    int i;
-    i = GetInteger();
-    *var = i;
-}
-
-static void
-free_int(int *var)
-{
-    *var = 0;
-}
-
-static void
-dump_onoff(StoreEntry * entry, const char *name, int var)
-{
-    storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
-}
-
-void
-parse_onoff(int *var)
-{
-    char *token = strtok(NULL, w_space);
-
-    if (token == NULL)
-	self_destruct();
-    if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
-	*var = 1;
-    else
-	*var = 0;
-}
-
-#define free_onoff free_int
-#define dump_eol dump_string
-#define free_eol free_string
-
-static void
-dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
-{
-    while (head != NULL) {
-	storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
-	    name,
-	    head->flags.icase ? " -i" : null_string,
-	    head->pattern,
-	    (int) head->min / 60,
-	    (int) (100.0 * head->pct + 0.5),
-	    (int) head->max / 60);
-#if HTTP_VIOLATIONS
-	if (head->flags.override_expire)
-	    storeAppendPrintf(entry, " override-expire");
-	if (head->flags.override_lastmod)
-	    storeAppendPrintf(entry, " override-lastmod");
-	if (head->flags.reload_into_ims)
-	    storeAppendPrintf(entry, " reload-into-ims");
-	if (head->flags.ignore_reload)
-	    storeAppendPrintf(entry, " ignore-reload");
-#endif
-	storeAppendPrintf(entry, "\n");
-	head = head->next;
-    }
-}
-
-static void
-parse_refreshpattern(refresh_t ** head)
-{
-    char *token;
-    char *pattern;
-    time_t min = 0;
-    double pct = 0.0;
-    time_t max = 0;
-#if HTTP_VIOLATIONS
-    int override_expire = 0;
-    int override_lastmod = 0;
-    int reload_into_ims = 0;
-    int ignore_reload = 0;
-#endif
-    int i;
-    refresh_t *t;
-    regex_t comp;
-    int errcode;
-    int flags = REG_EXTENDED | REG_NOSUB;
-    if ((token = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-    if (strcmp(token, "-i") == 0) {
-	flags |= REG_ICASE;
-	token = strtok(NULL, w_space);
-    } else if (strcmp(token, "+i") == 0) {
-	flags &= ~REG_ICASE;
-	token = strtok(NULL, w_space);
-    }
-    if (token == NULL)
-	self_destruct();
-    pattern = xstrdup(token);
-    i = GetInteger();		/* token: min */
-    min = (time_t) (i * 60);	/* convert minutes to seconds */
-    i = GetInteger();		/* token: pct */
-    pct = (double) i / 100.0;
-    i = GetInteger();		/* token: max */
-    max = (time_t) (i * 60);	/* convert minutes to seconds */
-    /* Options */
-    while ((token = strtok(NULL, w_space)) != NULL) {
-#if HTTP_VIOLATIONS
-	if (!strcmp(token, "override-expire"))
-	    override_expire = 1;
-	else if (!strcmp(token, "override-lastmod"))
-	    override_lastmod = 1;
-	else if (!strcmp(token, "reload-into-ims")) {
-	    reload_into_ims = 1;
-	    refresh_nocache_hack = 1;
-	    /* tell client_side.c that this is used */
-	} else if (!strcmp(token, "ignore-reload")) {
-	    ignore_reload = 1;
-	    refresh_nocache_hack = 1;
-	    /* tell client_side.c that this is used */
-	} else
-#endif
-	    debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
-		pattern, token);
-    }
-    if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
-	char errbuf[256];
-	regerror(errcode, &comp, errbuf, sizeof errbuf);
-	debug(22, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %s\n",
-	    pattern, errbuf);
-	return;
-    }
-    pct = pct < 0.0 ? 0.0 : pct;
-    max = max < 0 ? 0 : max;
-    t = xcalloc(1, sizeof(refresh_t));
-    t->pattern = (char *) xstrdup(pattern);
-    t->compiled_pattern = comp;
-    t->min = min;
-    t->pct = pct;
-    t->max = max;
-    if (flags & REG_ICASE)
-	t->flags.icase = 1;
-#if HTTP_VIOLATIONS
-    if (override_expire)
-	t->flags.override_expire = 1;
-    if (override_lastmod)
-	t->flags.override_lastmod = 1;
-    if (reload_into_ims)
-	t->flags.reload_into_ims = 1;
-    if (ignore_reload)
-	t->flags.ignore_reload = 1;
-#endif
-    t->next = NULL;
-    while (*head)
-	head = &(*head)->next;
-    *head = t;
-    safe_free(pattern);
-}
-
-#if UNUSED_CODE
-static int
-check_null_refreshpattern(refresh_t * data)
-{
-    return data == NULL;
-}
-#endif
-
-static void
-free_refreshpattern(refresh_t ** head)
-{
-    refresh_t *t;
-    while ((t = *head) != NULL) {
-	*head = t->next;
-	safe_free(t->pattern);
-	regfree(&t->compiled_pattern);
-	safe_free(t);
-    }
-}
-
-static void
-dump_string(StoreEntry * entry, const char *name, char *var)
-{
-    if (var != NULL)
-	storeAppendPrintf(entry, "%s %s\n", name, var);
-}
-
-static void
-parse_string(char **var)
-{
-    char *token = strtok(NULL, w_space);
-    safe_free(*var);
-    if (token == NULL)
-	self_destruct();
-    *var = xstrdup(token);
-}
-
-static void
-free_string(char **var)
-{
-    safe_free(*var);
-}
-
-void
-parse_eol(char *volatile *var)
-{
-    unsigned char *token = (unsigned char *) strtok(NULL, null_string);
-    safe_free(*var);
-    if (token == NULL)
-	self_destruct();
-    while (*token && isspace(*token))
-	token++;
-    if (!*token)
-	self_destruct();
-    *var = xstrdup((char *) token);
-}
-
-static void
-dump_time_t(StoreEntry * entry, const char *name, time_t var)
-{
-    storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
-}
-
-void
-parse_time_t(time_t * var)
-{
-    parseTimeLine(var, T_SECOND_STR);
-}
-
-static void
-free_time_t(time_t * var)
-{
-    *var = 0;
-}
-
-static void
-dump_size_t(StoreEntry * entry, const char *name, size_t var)
-{
-    storeAppendPrintf(entry, "%s %d\n", name, (int) var);
-}
-
-static void
-dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
-{
-    storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
-}
-
-static void
-dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
-{
-    storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
-}
-
-static void
-parse_size_t(size_t * var)
-{
-    int i;
-    i = GetInteger();
-    *var = (size_t) i;
-}
-
-static void
-parse_b_size_t(size_t * var)
-{
-    parseBytesLine(var, B_BYTES_STR);
-}
-
-CBDATA_TYPE(body_size);
-
-static void
-parse_body_size_t(dlink_list * bodylist)
-{
-    body_size *bs;
-    CBDATA_INIT_TYPE(body_size);
-    bs = cbdataAlloc(body_size);
-    parse_size_t(&bs->maxsize);
-    aclParseAccessLine(&bs->access_list);
-
-    dlinkAddTail(bs, &bs->node, bodylist);
-}
-
-static void
-dump_body_size_t(StoreEntry * entry, const char *name, dlink_list bodylist)
-{
-    body_size *bs;
-    bs = (body_size *) bodylist.head;
-    while (bs) {
-	acl_list *l;
-	acl_access *head = bs->access_list;
-	while (head != NULL) {
-	    storeAppendPrintf(entry, "%s %ld %s", name, (long int) bs->maxsize,
-		head->allow ? "Allow" : "Deny");
-	    for (l = head->aclList; l != NULL; l = l->next) {
-		storeAppendPrintf(entry, " %s%s",
-		    l->op ? null_string : "!",
-		    l->_acl->name);
-	    }
-	    storeAppendPrintf(entry, "\n");
-	    head = head->next;
-	}
-	bs = (body_size *) bs->node.next;
-    }
-}
-
-static void
-free_body_size_t(dlink_list * bodylist)
-{
-    body_size *bs, *tempnode;
-    bs = (body_size *) bodylist->head;
-    while (bs) {
-	bs->maxsize = 0;
-	aclDestroyAccessList(&bs->access_list);
-	tempnode = (body_size *) bs->node.next;
-	dlinkDelete(&bs->node, bodylist);
-	cbdataFree(bs);
-	bs = tempnode;
-    }
-}
-
-static int
-check_null_body_size_t(dlink_list bodylist)
-{
-    return bodylist.head == NULL;
-}
-
-
-static void
-parse_kb_size_t(size_t * var)
-{
-    parseBytesLine(var, B_KBYTES_STR);
-}
-
-static void
-free_size_t(size_t * var)
-{
-    *var = 0;
-}
-
-#define free_b_size_t free_size_t
-#define free_kb_size_t free_size_t
-#define free_mb_size_t free_size_t
-#define free_gb_size_t free_size_t
-
-static void
-dump_ushort(StoreEntry * entry, const char *name, u_short var)
-{
-    storeAppendPrintf(entry, "%s %d\n", name, var);
-}
-
-static void
-free_ushort(u_short * u)
-{
-    *u = 0;
-}
-
-static void
-parse_ushort(u_short * var)
-{
-    int i;
-
-    i = GetInteger();
-    if (i < 0)
-	i = 0;
-    *var = (u_short) i;
-}
-
-static void
-dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
-{
-    while (list != NULL) {
-	storeAppendPrintf(entry, "%s %s\n", name, list->key);
-	list = list->next;
-    }
-}
-
-void
-parse_wordlist(wordlist ** list)
-{
-    char *token;
-    char *t = strtok(NULL, "");
-    while ((token = strwordtok(NULL, &t)))
-	wordlistAdd(list, token);
-}
-
-static int
-check_null_wordlist(wordlist * w)
-{
-    return w == NULL;
-}
-
-static int
-check_null_acl_access(acl_access * a)
-{
-    return a == NULL;
-}
-
-#define free_wordlist wordlistDestroy
-
-#define free_uri_whitespace free_int
-
-static void
-parse_uri_whitespace(int *var)
-{
-    char *token = strtok(NULL, w_space);
-    if (token == NULL)
-	self_destruct();
-    if (!strcasecmp(token, "strip"))
-	*var = URI_WHITESPACE_STRIP;
-    else if (!strcasecmp(token, "deny"))
-	*var = URI_WHITESPACE_DENY;
-    else if (!strcasecmp(token, "allow"))
-	*var = URI_WHITESPACE_ALLOW;
-    else if (!strcasecmp(token, "encode"))
-	*var = URI_WHITESPACE_ENCODE;
-    else if (!strcasecmp(token, "chop"))
-	*var = URI_WHITESPACE_CHOP;
-    else
-	self_destruct();
-}
-
-
-static void
-dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
-{
-    const char *s;
-    if (var == URI_WHITESPACE_ALLOW)
-	s = "allow";
-    else if (var == URI_WHITESPACE_ENCODE)
-	s = "encode";
-    else if (var == URI_WHITESPACE_CHOP)
-	s = "chop";
-    else if (var == URI_WHITESPACE_DENY)
-	s = "deny";
-    else
-	s = "strip";
-    storeAppendPrintf(entry, "%s %s\n", name, s);
-}
-
-static void
-free_removalpolicy(RemovalPolicySettings ** settings)
-{
-    if (!*settings)
-	return;
-    free_string(&(*settings)->type);
-    free_wordlist(&(*settings)->args);
-    xfree(*settings);
-    *settings = NULL;
-}
-
-static void
-parse_removalpolicy(RemovalPolicySettings ** settings)
-{
-    if (*settings)
-	free_removalpolicy(settings);
-    *settings = xcalloc(1, sizeof(**settings));
-    parse_string(&(*settings)->type);
-    parse_wordlist(&(*settings)->args);
-}
-
-static void
-dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
-{
-    wordlist *args;
-    storeAppendPrintf(entry, "%s %s", name, settings->type);
-    args = settings->args;
-    while (args) {
-	storeAppendPrintf(entry, " %s", args->key);
-	args = args->next;
-    }
-    storeAppendPrintf(entry, "\n");
-}
-
-
-#include "cf_parser.h"
-
-peer_t
-parseNeighborType(const char *s)
-{
-    if (!strcasecmp(s, "parent"))
-	return PEER_PARENT;
-    if (!strcasecmp(s, "neighbor"))
-	return PEER_SIBLING;
-    if (!strcasecmp(s, "neighbour"))
-	return PEER_SIBLING;
-    if (!strcasecmp(s, "sibling"))
-	return PEER_SIBLING;
-    if (!strcasecmp(s, "multicast"))
-	return PEER_MULTICAST;
-    debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s);
-    return PEER_SIBLING;
-}
-
-void
-parse_sockaddr_in_list_token(sockaddr_in_list ** head, char *token)
-{
-    char *t;
-    char *host;
-    const struct hostent *hp;
-    unsigned short port;
-    sockaddr_in_list *s;
-
-    host = NULL;
-    port = 0;
-    if ((t = strchr(token, ':'))) {
-	/* host:port */
-	host = token;
-	*t = '\0';
-	port = (unsigned short) xatoi(t + 1);
-	if (0 == port)
-	    self_destruct();
-    } else if ((port = xatoi(token)) > 0) {
-	/* port */
-    } else {
-	self_destruct();
-    }
-    s = xcalloc(1, sizeof(*s));
-    s->s.sin_port = htons(port);
-    if (NULL == host)
-	s->s.sin_addr = any_addr;
-    else if (1 == safe_inet_addr(host, &s->s.sin_addr))
-	(void) 0;
-    else if ((hp = gethostbyname(host)))	/* dont use ipcache */
-	s->s.sin_addr = inaddrFromHostent(hp);
-    else
-	self_destruct();
-    while (*head)
-	head = &(*head)->next;
-    *head = s;
-}
-
-static void
-parse_sockaddr_in_list(sockaddr_in_list ** head)
-{
-    char *token;
-    while ((token = strtok(NULL, w_space))) {
-	parse_sockaddr_in_list_token(head, token);
-    }
-}
-
-static void
-dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
-{
-    while (s) {
-	storeAppendPrintf(e, "%s %s:%d\n",
-	    n,
-	    inet_ntoa(s->s.sin_addr),
-	    ntohs(s->s.sin_port));
-	s = s->next;
-    }
-}
-
-static void
-free_sockaddr_in_list(sockaddr_in_list ** head)
-{
-    sockaddr_in_list *s;
-    while ((s = *head) != NULL) {
-	*head = s->next;
-	xfree(s);
-    }
-}
-
-#if 0
-static int
-check_null_sockaddr_in_list(const sockaddr_in_list * s)
-{
-    return NULL == s;
-}
-#endif
-
-#if USE_SSL
-static void
-parse_https_port_list(https_port_list ** head)
-{
-    char *token;
-    char *t;
-    char *host;
-    const struct hostent *hp;
-    unsigned short port;
-    https_port_list *s;
-    token = strtok(NULL, w_space);
-    if (!token)
-	self_destruct();
-    host = NULL;
-    port = 0;
-    if ((t = strchr(token, ':'))) {
-	/* host:port */
-	host = token;
-	*t = '\0';
-	port = (unsigned short) xatoi(t + 1);
-	if (0 == port)
-	    self_destruct();
-    } else if ((port = xatoi(token)) > 0) {
-	/* port */
-    } else {
-	self_destruct();
-    }
-    s = xcalloc(1, sizeof(*s));
-    s->s.sin_port = htons(port);
-    if (NULL == host)
-	s->s.sin_addr = any_addr;
-    else if (1 == safe_inet_addr(host, &s->s.sin_addr))
-	(void) 0;
-    else if ((hp = gethostbyname(host)))	/* dont use ipcache */
-	s->s.sin_addr = inaddrFromHostent(hp);
-    else
-	self_destruct();
-    /* parse options ... */
-    while ((token = strtok(NULL, w_space))) {
-	if (strncmp(token, "cert=", 5) == 0) {
-	    safe_free(s->cert);
-	    s->cert = xstrdup(token + 5);
-	} else if (strncmp(token, "key=", 4) == 0) {
-	    safe_free(s->key);
-	    s->key = xstrdup(token + 4);
-	} else if (strncmp(token, "version=", 8) == 0) {
-	    s->version = xatoi(token + 8);
-	} else if (strncmp(token, "options=", 8) == 0) {
-	    safe_free(s->options);
-	    s->options = xstrdup(token + 8);
-	} else if (strncmp(token, "cipher=", 7) == 0) {
-	    safe_free(s->cipher);
-	    s->cipher = xstrdup(token + 7);
-	} else {
-	    self_destruct();
-	}
-    }
-    while (*head)
-	head = &(*head)->next;
-    *head = s;
-}
-
-static void
-dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
-{
-    while (s) {
-	storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"",
-	    n,
-	    inet_ntoa(s->s.sin_addr),
-	    ntohs(s->s.sin_port),
-	    s->cert,
-	    s->key);
-	if (s->version)
-	    storeAppendPrintf(e, " version=%d", s->version);
-	if (s->options)
-	    storeAppendPrintf(e, " options=%s", s->options);
-	if (s->cipher)
-	    storeAppendPrintf(e, " cipher=%s", s->cipher);
-	storeAppendPrintf(e, "\n");
-	s = s->next;
-    }
-}
-
-static void
-free_https_port_list(https_port_list ** head)
-{
-    https_port_list *s;
-    while ((s = *head) != NULL) {
-	*head = s->next;
-	safe_free(s->cert);
-	safe_free(s->key);
-	safe_free(s);
-    }
-}
-
-#if 0
-static int
-check_null_https_port_list(const https_port_list * s)
-{
-    return NULL == s;
-}
-#endif
-
-#endif /* USE_SSL */
-
-void
-configFreeMemory(void)
-{
-    safe_free(Config2.Accel.prefix);
-    free_all();
-}
-
-void
-requirePathnameExists(const char *name, const char *path)
-{
-    struct stat sb;
-    assert(path != NULL);
-    if (stat(path, &sb) < 0)
-	fatalf("%s: %s", path, xstrerror());
-}
-
-char *
-strtokFile(void)
-{
-    static int fromFile = 0;
-    static FILE *wordFile = NULL;
-
-    char *t, *fn;
-    LOCAL_ARRAY(char, buf, 256);
-
-  strtok_again:
-    if (!fromFile) {
-	t = (strtok(NULL, w_space));
-	if (!t || *t == '#') {
-	    return NULL;
-	} else if (*t == '\"' || *t == '\'') {
-	    /* quote found, start reading from file */
-	    fn = ++t;
-	    while (*t && *t != '\"' && *t != '\'')
-		t++;
-	    *t = '\0';
-	    if ((wordFile = fopen(fn, "r")) == NULL) {
-		debug(28, 0) ("strtokFile: %s not found\n", fn);
-		return (NULL);
-	    }
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-	    setmode(fileno(wordFile), O_TEXT);
-#endif
-	    fromFile = 1;
-	} else {
-	    return t;
-	}
-    }
-    /* fromFile */
-    if (fgets(buf, 256, wordFile) == NULL) {
-	/* stop reading from file */
-	fclose(wordFile);
-	wordFile = NULL;
-	fromFile = 0;
-	goto strtok_again;
-    } else {
-	t = buf;
-	/* skip leading and trailing white space */
-	t += strspn(buf, w_space);
-	t[strcspn(t, w_space)] = '\0';
-	/* skip comments */
-	if (*t == '#')
-	    goto strtok_again;
-	/* skip blank lines */
-	if (!*t)
-	    goto strtok_again;
-	return t;
-    }
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/cache_cf.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,2522 @@
+
+/*
+ * $Id: cache_cf.cc,v 1.1.2.1 2002/10/03 01:04:33 rbcollins Exp $
+ *
+ * DEBUG: section 3     Configuration File Parsing
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "authenticate.h"
+
+#if SQUID_SNMP
+#include "snmp.h"
+#endif
+
+static const char *const T_SECOND_STR = "second";
+static const char *const T_MINUTE_STR = "minute";
+static const char *const T_HOUR_STR = "hour";
+static const char *const T_DAY_STR = "day";
+static const char *const T_WEEK_STR = "week";
+static const char *const T_FORTNIGHT_STR = "fortnight";
+static const char *const T_MONTH_STR = "month";
+static const char *const T_YEAR_STR = "year";
+static const char *const T_DECADE_STR = "decade";
+
+static const char *const B_BYTES_STR = "bytes";
+static const char *const B_KBYTES_STR = "KB";
+static const char *const B_MBYTES_STR = "MB";
+static const char *const B_GBYTES_STR = "GB";
+
+static const char *const list_sep = ", \t\n\r";
+
+static void parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring);
+static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd);
+static void parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring);
+static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd);
+static struct cache_dir_option common_cachedir_options[] =
+{
+    {"read-only", parse_cachedir_option_readonly, dump_cachedir_option_readonly},
+    {"max-size", parse_cachedir_option_maxsize, dump_cachedir_option_maxsize},
+    {NULL, NULL}
+};
+
+
+static void update_maxobjsize(void);
+static void configDoConfigure(void);
+static void parse_refreshpattern(refresh_t **);
+static int parseTimeUnits(const char *unit);
+static void parseTimeLine(time_t * tptr, const char *units);
+static void parse_ushort(u_short * var);
+static void parse_string(char **);
+static void default_all(void);
+static void defaults_if_none(void);
+static int parse_line(char *);
+static void parseBytesLine(size_t * bptr, const char *units);
+static size_t parseBytesUnits(const char *unit);
+static void free_all(void);
+void requirePathnameExists(const char *name, const char *path);
+static OBJH dump_config;
+static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
+static void parse_http_header_access(header_mangler header[]);
+static void free_http_header_access(header_mangler header[]);
+static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
+static void parse_http_header_replace(header_mangler * header);
+static void free_http_header_replace(header_mangler * header);
+static void parse_denyinfo(acl_deny_info_list ** var);
+static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
+static void free_denyinfo(acl_deny_info_list ** var);
+static void parse_sockaddr_in_list(sockaddr_in_list **);
+static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
+static void free_sockaddr_in_list(sockaddr_in_list **);
+#if 0
+static int check_null_sockaddr_in_list(const sockaddr_in_list *);
+#endif
+#if USE_SSL
+static void parse_https_port_list(https_port_list **);
+static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
+static void free_https_port_list(https_port_list **);
+#if 0
+static int check_null_https_port_list(const https_port_list *);
+#endif
+#endif /* USE_SSL */
+
+void
+self_destruct(void)
+{
+    fatalf("Bungled %s line %d: %s",
+	cfg_filename, config_lineno, config_input_line);
+}
+
+void
+wordlistDestroy(wordlist ** list)
+{
+    wordlist *w = NULL;
+    while ((w = *list) != NULL) {
+	*list = w->next;
+	safe_free(w->key);
+	memFree(w, MEM_WORDLIST);
+    }
+    *list = NULL;
+}
+
+const char *
+wordlistAdd(wordlist ** list, const char *key)
+{
+    while (*list)
+	list = &(*list)->next;
+    *list = static_cast<wordlist *>(memAllocate(MEM_WORDLIST));
+    (*list)->key = xstrdup(key);
+    (*list)->next = NULL;
+    return (*list)->key;
+}
+
+void
+wordlistJoin(wordlist ** list, wordlist ** wl)
+{
+    while (*list)
+	list = &(*list)->next;
+    *list = *wl;
+    *wl = NULL;
+}
+
+void
+wordlistAddWl(wordlist ** list, wordlist * wl)
+{
+    while (*list)
+	list = &(*list)->next;
+    for (; wl; wl = wl->next, list = &(*list)->next) {
+	*list = static_cast<wordlist *>(memAllocate(MEM_WORDLIST));
+	(*list)->key = xstrdup(wl->key);
+	(*list)->next = NULL;
+    }
+}
+
+void
+wordlistCat(const wordlist * w, MemBuf * mb)
+{
+    while (NULL != w) {
+	memBufPrintf(mb, "%s\n", w->key);
+	w = w->next;
+    }
+}
+
+wordlist *
+wordlistDup(const wordlist * w)
+{
+    wordlist *D = NULL;
+    while (NULL != w) {
+	wordlistAdd(&D, w->key);
+	w = w->next;
+    }
+    return D;
+}
+
+void
+intlistDestroy(intlist ** list)
+{
+    intlist *w = NULL;
+    intlist *n = NULL;
+    for (w = *list; w; w = n) {
+	n = w->next;
+	memFree(w, MEM_INTLIST);
+    }
+    *list = NULL;
+}
+
+int
+intlistFind(intlist * list, int i)
+{
+    intlist *w = NULL;
+    for (w = list; w; w = w->next)
+	if (w->i == i)
+	    return 1;
+    return 0;
+}
+
+/*
+ * These functions is the same as atoi/l/f, except that they check for errors
+ */
+
+static long
+xatol(const char *token)
+{
+    char *end;
+    long ret = strtol(token, &end, 10);
+    if (ret == 0 && end == token)
+	self_destruct();
+    return ret;
+}
+
+static int
+xatoi(const char *token)
+{
+    return xatol(token);
+}
+
+static double
+xatof(const char *token)
+{
+    char *end;
+    double ret = strtod(token, &end);
+    if (ret == 0 && end == token)
+	self_destruct();
+    return ret;
+}
+
+int
+GetInteger(void)
+{
+    char *token = strtok(NULL, w_space);
+    int i;
+    if (token == NULL)
+	self_destruct();
+    if (sscanf(token, "%d", &i) != 1)
+	self_destruct();
+    return i;
+}
+
+static void
+update_maxobjsize(void)
+{
+    int i;
+    ssize_t ms = -1;
+
+    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+	if (Config.cacheSwap.swapDirs[i].max_objsize > ms)
+	    ms = Config.cacheSwap.swapDirs[i].max_objsize;
+    }
+    store_maxobjsize = ms;
+}
+
+int
+parseConfigFile(const char *file_name)
+{
+    FILE *fp = NULL;
+    char *token = NULL;
+    char *tmp_line;
+    int err_count = 0;
+    int is_pipe = 0;
+    configFreeMemory();
+    default_all();
+    if (file_name[0] == '!' || file_name[0] == '|') {
+	fp = popen(file_name + 1, "r");
+	is_pipe = 1;
+    } else {
+	fp = fopen(file_name, "r");
+    }
+    if (fp == NULL)
+	fatalf("Unable to open configuration file: %s: %s",
+	    file_name, xstrerror());
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+    setmode(fileno(fp), O_TEXT);
+#endif
+    cfg_filename = file_name;
+    if (is_pipe)
+	cfg_filename = file_name + 1;
+    else if ((token = strrchr(cfg_filename, '/')))
+	cfg_filename = token + 1;
+    memset(config_input_line, '\0', BUFSIZ);
+    config_lineno = 0;
+    while (fgets(config_input_line, BUFSIZ, fp)) {
+	config_lineno++;
+	if ((token = strchr(config_input_line, '\n')))
+	    *token = '\0';
+	if (strncmp(config_input_line, "#line ", 6) == 0) {
+	    static char new_file_name[1024];
+	    static char *file;
+	    static char new_lineno;
+	    token = config_input_line + 6;
+	    new_lineno = strtol(token, &file, 0) - 1;
+	    if (file == token)
+		continue;	/* Not a valid #line directive, may be a comment */
+	    while (*file && isspace((unsigned char) *file))
+		file++;
+	    if (*file) {
+		if (*file != '"')
+		    continue;	/* Not a valid #line directive, may be a comment */
+		xstrncpy(new_file_name, file + 1, sizeof(new_file_name));
+		if ((token = strchr(new_file_name, '"')))
+		    *token = '\0';
+		cfg_filename = new_file_name;
+#if PROBABLY_NOT_WANTED_HERE
+		if ((token = strrchr(cfg_filename, '/')))
+		    cfg_filename = token + 1;
+#endif
+	    }
+	    config_lineno = new_lineno;
+	}
+	if (config_input_line[0] == '#')
+	    continue;
+	if (config_input_line[0] == '\0')
+	    continue;
+	debug(3, 5) ("Processing: '%s'\n", config_input_line);
+	tmp_line = xstrdup(config_input_line);
+	if (!parse_line(tmp_line)) {
+	    debug(3, 0) ("parseConfigFile: '%s' line %d unrecognized: '%s'\n",
+		cfg_filename,
+		config_lineno,
+		config_input_line);
+	    err_count++;
+	}
+	safe_free(tmp_line);
+    }
+    if (is_pipe) {
+	int ret = pclose(fp);
+	if (ret != 0)
+	    fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
+    } else {
+	fclose(fp);
+    }
+    defaults_if_none();
+    configDoConfigure();
+    cachemgrRegister("config",
+	"Current Squid Configuration",
+	dump_config,
+	1, 1);
+    return err_count;
+}
+
+static void
+configDoConfigure(void)
+{
+    LOCAL_ARRAY(char, buf, BUFSIZ);
+    memset(&Config2, '\0', sizeof(SquidConfig2));
+    /* init memory as early as possible */
+    memConfigure();
+    /* Sanity checks */
+    if (Config.cacheSwap.swapDirs == NULL)
+	fatal("No cache_dir's specified in config file");
+    /* calculate Config.Swap.maxSize */
+    storeDirConfigure();
+    if (0 == Config.Swap.maxSize)
+	/* people might want a zero-sized cache on purpose */
+	(void) 0;
+    else if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
+	debug(3, 0) ("WARNING cache_mem is larger than total disk cache space!\n");
+    if (Config.Announce.period > 0) {
+	Config.onoff.announce = 1;
+    } else if (Config.Announce.period < 1) {
+	Config.Announce.period = 86400 * 365;	/* one year */
+	Config.onoff.announce = 0;
+    }
+#if USE_DNSSERVERS
+    if (Config.dnsChildren < 1)
+	fatal("No dnsservers allocated");
+#endif
+    if (Config.Program.redirect) {
+	if (Config.redirectChildren < 1) {
+	    Config.redirectChildren = 0;
+	    wordlistDestroy(&Config.Program.redirect);
+	}
+    }
+    if (Config.Accel.host) {
+	snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
+	Config2.Accel.prefix = xstrdup(buf);
+	Config2.Accel.on = 1;
+    }
+    if (Config.appendDomain)
+	if (*Config.appendDomain != '.')
+	    fatal("append_domain must begin with a '.'");
+    if (Config.errHtmlText == NULL)
+	Config.errHtmlText = xstrdup(null_string);
+    storeConfigure();
+    if (Config2.Accel.on && !strcmp(Config.Accel.host, "virtual")) {
+	vhost_mode = 1;
+	if (Config.Accel.port == 0)
+	    vport_mode = 1;
+    }
+    snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
+	uniqueHostname(),
+	full_appname_string);
+    /*
+     * the extra space is for loop detection in client_side.c -- we search
+     * for substrings in the Via header.
+     */
+    snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
+	uniqueHostname(),
+	full_appname_string);
+    if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
+	Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
+    if (Config.appendDomain)
+	Config.appendDomainLen = strlen(Config.appendDomain);
+    else
+	Config.appendDomainLen = 0;
+    safe_free(debug_options)
+	debug_options = xstrdup(Config.debugOptions);
+    if (Config.retry.timeout < 5)
+	fatal("minimum_retry_timeout must be at least 5 seconds");
+    if (Config.retry.maxtries > 10)
+	fatal("maximum_single_addr_tries cannot be larger than 10");
+    if (Config.retry.maxtries < 1) {
+	debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
+	Config.retry.maxtries = 1;
+    }
+    requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
+#if USE_DNSSERVERS
+    requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
+#endif
+#if USE_UNLINKD
+    requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
+#endif
+    if (Config.Program.redirect)
+	requirePathnameExists("redirect_program", Config.Program.redirect->key);
+    requirePathnameExists("Icon Directory", Config.icons.directory);
+    requirePathnameExists("Error Directory", Config.errorDirectory);
+#if HTTP_VIOLATIONS
+    {
+	const refresh_t *R;
+	for (R = Config.Refresh; R; R = R->next) {
+	    if (!R->flags.override_expire)
+		continue;
+	    debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
+	    break;
+	}
+	for (R = Config.Refresh; R; R = R->next) {
+	    if (!R->flags.override_lastmod)
+		continue;
+	    debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
+	    break;
+	}
+    }
+#endif
+#if !HTTP_VIOLATIONS
+    Config.onoff.via = 1;
+#else
+    if (!Config.onoff.via)
+	debug(22, 1) ("WARNING: HTTP requires the use of Via\n");
+#endif
+    if (Config.Wais.relayHost) {
+	if (Config.Wais._peer)
+	    cbdataFree(Config.Wais._peer);
+	Config.Wais._peer = cbdataAlloc(peer);
+	Config.Wais._peer->host = xstrdup(Config.Wais.relayHost);
+	Config.Wais._peer->http_port = Config.Wais.relayPort;
+    }
+    if (aclPurgeMethodInUse(Config.accessList.http))
+	Config2.onoff.enable_purge = 1;
+    if (geteuid() == 0) {
+	if (NULL != Config.effectiveUser) {
+	    struct passwd *pwd = getpwnam(Config.effectiveUser);
+	    if (NULL == pwd)
+		/*
+		 * Andres Kroonmaa <andre@online.ee>:
+		 * Some getpwnam() implementations (Solaris?) require
+		 * an available FD < 256 for opening a FILE* to the
+		 * passwd file.
+		 * DW:
+		 * This should be safe at startup, but might still fail
+		 * during reconfigure.
+		 */
+		fatalf("getpwnam failed to find userid for effective user '%s'",
+		    Config.effectiveUser);
+	    Config2.effectiveUserID = pwd->pw_uid;
+	    Config2.effectiveGroupID = pwd->pw_gid;
+	}
+    } else {
+	Config2.effectiveUserID = geteuid();
+	Config2.effectiveGroupID = getegid();
+    }
+    if (NULL != Config.effectiveGroup) {
+	struct group *grp = getgrnam(Config.effectiveGroup);
+	if (NULL == grp)
+	    fatalf("getgrnam failed to find groupid for effective group '%s'",
+		Config.effectiveGroup);
+	Config2.effectiveGroupID = grp->gr_gid;
+    }
+    urlExtMethodConfigure();
+    if (0 == Config.onoff.client_db) {
+	acl *a;
+	for (a = Config.aclList; a; a = a->next) {
+	    if (ACL_MAXCONN != a->type)
+		continue;
+	    debug(22, 0) ("WARNING: 'maxconn' ACL (%s) won't work with client_db disabled\n", a->name);
+	}
+    }
+}
+
+/* Parse a time specification from the config file.  Store the
+ * result in 'tptr', after converting it to 'units' */
+static void
+parseTimeLine(time_t * tptr, const char *units)
+{
+    char *token;
+    double d;
+    time_t m;
+    time_t u;
+    if ((u = parseTimeUnits(units)) == 0)
+	self_destruct();
+    if ((token = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+    d = xatof(token);
+    m = u;			/* default to 'units' if none specified */
+    if (0 == d)
+	(void) 0;
+    else if ((token = strtok(NULL, w_space)) == NULL)
+	debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
+	    config_input_line, d, units);
+    else if ((m = parseTimeUnits(token)) == 0)
+	self_destruct();
+    *tptr = static_cast<time_t> (m * d / u);
+}
+
+static int
+parseTimeUnits(const char *unit)
+{
+    if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
+	return 1;
+    if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
+	return 60;
+    if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
+	return 3600;
+    if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
+	return 86400;
+    if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
+	return 86400 * 7;
+    if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
+	return 86400 * 14;
+    if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
+	return 86400 * 30;
+    if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
+	return static_cast<int>(86400 * 365.2522);
+    if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
+	return static_cast<int>(86400 * 365.2522 * 10);
+    debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit);
+    return 0;
+}
+
+static void
+parseBytesLine(size_t * bptr, const char *units)
+{
+    char *token;
+    double d;
+    size_t m;
+    size_t u;
+    if ((u = parseBytesUnits(units)) == 0)
+	self_destruct();
+    if ((token = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+    d = xatof(token);
+    m = u;			/* default to 'units' if none specified */
+    if (0.0 == d)
+	(void) 0;
+    else if ((token = strtok(NULL, w_space)) == NULL)
+	debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
+	    config_input_line, d, units);
+    else if ((m = parseBytesUnits(token)) == 0)
+	self_destruct();
+    *bptr = static_cast<size_t>(m * d / u);
+}
+
+static size_t
+parseBytesUnits(const char *unit)
+{
+    if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
+	return 1;
+    if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
+	return 1 << 10;
+    if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
+	return 1 << 20;
+    if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
+	return 1 << 30;
+    debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
+    return 0;
+}
+
+/*****************************************************************************
+ * Max
+ *****************************************************************************/
+
+static void
+dump_acl(StoreEntry * entry, const char *name, acl * ae)
+{
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+	debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
+	v = w = aclDumpGeneric(ae);
+	while (v != NULL) {
+	    debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
+	    storeAppendPrintf(entry, "%s %s %s %s\n",
+		name,
+		ae->name,
+		aclTypeToStr(ae->type),
+		v->key);
+	    v = v->next;
+	}
+	wordlistDestroy(&w);
+	ae = ae->next;
+    }
+}
+
+static void
+parse_acl(acl ** ae)
+{
+    aclParseAclLine(ae);
+}
+
+static void
+free_acl(acl ** ae)
+{
+    aclDestroyAcls(ae);
+}
+
+static void
+dump_acl_list(StoreEntry * entry, acl_list * head)
+{
+    acl_list *l;
+    for (l = head; l; l = l->next) {
+	storeAppendPrintf(entry, " %s%s",
+	    l->op ? null_string : "!",
+	    l->_acl->name);
+    }
+}
+
+static void
+dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
+{
+    acl_access *l;
+    for (l = head; l; l = l->next) {
+	storeAppendPrintf(entry, "%s %s",
+	    name,
+	    l->allow ? "Allow" : "Deny");
+	dump_acl_list(entry, l->aclList);
+	storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void
+parse_acl_access(acl_access ** head)
+{
+    aclParseAccessLine(head);
+}
+
+static void
+free_acl_access(acl_access ** head)
+{
+    aclDestroyAccessList(head);
+}
+
+static void
+dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
+{
+    storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
+}
+
+static void
+parse_address(struct in_addr *addr)
+{
+    const struct hostent *hp;
+    char *token = strtok(NULL, w_space);
+
+    if (token == NULL)
+	self_destruct();
+    if (safe_inet_addr(token, addr) == 1)
+	(void) 0;
+    else if ((hp = gethostbyname(token)))	/* dont use ipcache */
+	*addr = inaddrFromHostent(hp);
+    else
+	self_destruct();
+}
+
+static void
+free_address(struct in_addr *addr)
+{
+    memset(addr, '\0', sizeof(struct in_addr));
+}
+
+CBDATA_TYPE(acl_address);
+
+static void
+dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
+{
+    acl_address *l;
+    for (l = head; l; l = l->next) {
+	if (l->addr.s_addr != INADDR_ANY)
+	    storeAppendPrintf(entry, "%s %s", name, inet_ntoa(l->addr));
+	else
+	    storeAppendPrintf(entry, "%s autoselect", name);
+	dump_acl_list(entry, l->aclList);
+	storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void
+freed_acl_address(void *data)
+{
+    acl_address *l = static_cast<acl_address *>(data);
+    aclDestroyAclList(&l->aclList);
+}
+
+static void
+parse_acl_address(acl_address ** head)
+{
+    acl_address *l;
+    acl_address **tail = head;	/* sane name below */
+    CBDATA_INIT_TYPE_FREECB(acl_address, freed_acl_address);
+    l = cbdataAlloc(acl_address);
+    parse_address(&l->addr);
+    aclParseAclList(&l->aclList);
+    while (*tail)
+	tail = &(*tail)->next;
+    *tail = l;
+}
+
+static void
+free_acl_address(acl_address ** head)
+{
+    while (*head) {
+	acl_address *l = *head;
+	*head = l->next;
+	cbdataFree(l);
+    }
+}
+
+CBDATA_TYPE(acl_tos);
+
+static void
+dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
+{
+    acl_tos *l;
+    for (l = head; l; l = l->next) {
+	if (l->tos > 0)
+	    storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
+	else
+	    storeAppendPrintf(entry, "%s none", name);
+	dump_acl_list(entry, l->aclList);
+	storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void
+freed_acl_tos(void *data)
+{
+    acl_tos *l = static_cast<acl_tos *>(data);
+    aclDestroyAclList(&l->aclList);
+}
+
+static void
+parse_acl_tos(acl_tos ** head)
+{
+    acl_tos *l;
+    acl_tos **tail = head;	/* sane name below */
+    int tos;
+    char junk;
+    char *token = strtok(NULL, w_space);
+    if (!token)
+	self_destruct();
+    if (sscanf(token, "0x%x%c", &tos, &junk) != 1)
+	self_destruct();
+    if (tos < 0 || tos > 255)
+	self_destruct();
+    CBDATA_INIT_TYPE_FREECB(acl_tos, freed_acl_tos);
+    l = cbdataAlloc(acl_tos);
+    l->tos = tos;
+    aclParseAclList(&l->aclList);
+    while (*tail)
+	tail = &(*tail)->next;
+    *tail = l;
+}
+
+static void
+free_acl_tos(acl_tos ** head)
+{
+    while (*head) {
+	acl_tos *l = *head;
+	*head = l->next;
+	l->next = NULL;
+	cbdataFree(l);
+    }
+}
+
+#if DELAY_POOLS
+
+/* do nothing - free_delay_pool_count is the magic free function.
+ * this is why delay_pool_count isn't just marked TYPE: ushort
+ */
+#define free_delay_pool_class(X)
+#define free_delay_pool_access(X)
+#define free_delay_pool_rates(X)
+#define dump_delay_pool_class(X, Y, Z)
+#define dump_delay_pool_access(X, Y, Z)
+#define dump_delay_pool_rates(X, Y, Z)
+
+static void
+free_delay_pool_count(delayConfig * cfg)
+{
+    int i;
+
+    if (!cfg->pools)
+	return;
+    for (i = 0; i < cfg->pools; i++) {
+	if (cfg->class[i]) {
+	    delayFreeDelayPool(i);
+	    safe_free(cfg->rates[i]);
+	}
+	aclDestroyAccessList(&cfg->access[i]);
+    }
+    delayFreeDelayData(cfg->pools);
+    xfree(cfg->class);
+    xfree(cfg->rates);
+    xfree(cfg->access);
+    memset(cfg, 0, sizeof(*cfg));
+}
+
+static void
+dump_delay_pool_count(StoreEntry * entry, const char *name, delayConfig cfg)
+{
+    int i;
+    LOCAL_ARRAY(char, nom, 32);
+
+    if (!cfg.pools) {
+	storeAppendPrintf(entry, "%s 0\n", name);
+	return;
+    }
+    storeAppendPrintf(entry, "%s %d\n", name, cfg.pools);
+    for (i = 0; i < cfg.pools; i++) {
+	storeAppendPrintf(entry, "delay_class %d %d\n", i + 1, cfg.class[i]);
+	snprintf(nom, 32, "delay_access %d", i + 1);
+	dump_acl_access(entry, nom, cfg.access[i]);
+	if (cfg.class[i] >= 1)
+	    storeAppendPrintf(entry, "delay_parameters %d %d/%d", i + 1,
+		cfg.rates[i]->aggregate.restore_bps,
+		cfg.rates[i]->aggregate.max_bytes);
+	if (cfg.class[i] >= 3)
+	    storeAppendPrintf(entry, " %d/%d",
+		cfg.rates[i]->network.restore_bps,
+		cfg.rates[i]->network.max_bytes);
+	if (cfg.class[i] >= 2)
+	    storeAppendPrintf(entry, " %d/%d",
+		cfg.rates[i]->individual.restore_bps,
+		cfg.rates[i]->individual.max_bytes);
+	if (cfg.class[i] >= 1)
+	    storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void
+parse_delay_pool_count(delayConfig * cfg)
+{
+    if (cfg->pools) {
+	debug(3, 0) ("parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config\n");
+	free_delay_pool_count(cfg);
+    }
+    parse_ushort(&cfg->pools);
+    if (cfg->pools) {
+	delayInitDelayData(cfg->pools);
+	cfg->class = xcalloc(cfg->pools, sizeof(u_char));
+	cfg->rates = xcalloc(cfg->pools, sizeof(delaySpecSet *));
+	cfg->access = xcalloc(cfg->pools, sizeof(acl_access *));
+    }
+}
+
+static void
+parse_delay_pool_class(delayConfig * cfg)
+{
+    ushort pool, class;
+
+    parse_ushort(&pool);
+    if (pool < 1 || pool > cfg->pools) {
+	debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
+	return;
+    }
+    parse_ushort(&class);
+    if (class < 1 || class > 3) {
+	debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d class %d not in 1 .. 3\n", pool, class);
+	return;
+    }
+    pool--;
+    if (cfg->class[pool]) {
+	delayFreeDelayPool(pool);
+	safe_free(cfg->rates[pool]);
+    }
+    cfg->rates[pool] = xmalloc(class * sizeof(delaySpec));
+    cfg->class[pool] = class;
+    cfg->rates[pool]->aggregate.restore_bps = cfg->rates[pool]->aggregate.max_bytes = -1;
+    if (cfg->class[pool] >= 3)
+	cfg->rates[pool]->network.restore_bps = cfg->rates[pool]->network.max_bytes = -1;
+    if (cfg->class[pool] >= 2)
+	cfg->rates[pool]->individual.restore_bps = cfg->rates[pool]->individual.max_bytes = -1;
+    delayCreateDelayPool(pool, class);
+}
+
+static void
+parse_delay_pool_rates(delayConfig * cfg)
+{
+    ushort pool, class;
+    int i;
+    delaySpec *ptr;
+    char *token;
+
+    parse_ushort(&pool);
+    if (pool < 1 || pool > cfg->pools) {
+	debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
+	return;
+    }
+    pool--;
+    class = cfg->class[pool];
+    if (class == 0) {
+	debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d attempt to set rates with class not set\n", pool + 1);
+	return;
+    }
+    ptr = (delaySpec *) cfg->rates[pool];
+    /* read in "class" sets of restore,max pairs */
+    while (class--) {
+	token = strtok(NULL, "/");
+	if (token == NULL)
+	    self_destruct();
+	if (sscanf(token, "%d", &i) != 1)
+	    self_destruct();
+	ptr->restore_bps = i;
+	i = GetInteger();
+	ptr->max_bytes = i;
+	ptr++;
+    }
+    class = cfg->class[pool];
+    /* if class is 3, swap around network and individual */
+    if (class == 3) {
+	delaySpec tmp;
+
+	tmp = cfg->rates[pool]->individual;
+	cfg->rates[pool]->individual = cfg->rates[pool]->network;
+	cfg->rates[pool]->network = tmp;
+    }
+    /* initialize the delay pools */
+    delayInitDelayPool(pool, class, cfg->rates[pool]);
+}
+
+static void
+parse_delay_pool_access(delayConfig * cfg)
+{
+    ushort pool;
+
+    parse_ushort(&pool);
+    if (pool < 1 || pool > cfg->pools) {
+	debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
+	return;
+    }
+    aclParseAccessLine(&cfg->access[pool - 1]);
+}
+#endif
+
+static void
+dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
+{
+    int i;
+    for (i = 0; i < HDR_ENUM_END; i++) {
+	if (header[i].access_list != NULL) {
+	    storeAppendPrintf(entry, "%s ", name);
+	    dump_acl_access(entry, httpHeaderNameById(i),
+		header[i].access_list);
+	}
+    }
+}
+
+static void
+parse_http_header_access(header_mangler header[])
+{
+    int id, i;
+    char *t = NULL;
+    if ((t = strtok(NULL, w_space)) == NULL) {
+	debug(3, 0) ("%s line %d: %s\n",
+	    cfg_filename, config_lineno, config_input_line);
+	debug(3, 0) ("parse_http_header_access: missing header name.\n");
+	return;
+    }
+    /* Now lookup index of header. */
+    id = httpHeaderIdByNameDef(t, strlen(t));
+    if (strcmp(t, "All") == 0)
+	id = HDR_ENUM_END;
+    else if (strcmp(t, "Other") == 0)
+	id = HDR_OTHER;
+    else if (id == -1) {
+	debug(3, 0) ("%s line %d: %s\n",
+	    cfg_filename, config_lineno, config_input_line);
+	debug(3, 0) ("parse_http_header_access: unknown header name %s.\n", t);
+	return;
+    }
+    if (id != HDR_ENUM_END) {
+	parse_acl_access(&header[id].access_list);
+    } else {
+	char *next_string = t + strlen(t) - 1;
+	*next_string = 'A';
+	*(next_string + 1) = ' ';
+	for (i = 0; i < HDR_ENUM_END; i++) {
+	    char *new_string = xstrdup(next_string);
+	    strtok(new_string, w_space);
+	    parse_acl_access(&header[i].access_list);
+	    safe_free(new_string);
+	}
+    }
+}
+
+static void
+free_http_header_access(header_mangler header[])
+{
+    int i;
+    for (i = 0; i < HDR_ENUM_END; i++) {
+	free_acl_access(&header[i].access_list);
+    }
+}
+
+static void
+dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
+    header[])
+{
+    int i;
+    for (i = 0; i < HDR_ENUM_END; i++) {
+	if (NULL == header[i].replacement)
+	    continue;
+	storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
+	    header[i].replacement);
+    }
+}
+
+static void
+parse_http_header_replace(header_mangler header[])
+{
+    int id, i;
+    char *t = NULL;
+    if ((t = strtok(NULL, w_space)) == NULL) {
+	debug(3, 0) ("%s line %d: %s\n",
+	    cfg_filename, config_lineno, config_input_line);
+	debug(3, 0) ("parse_http_header_replace: missing header name.\n");
+	return;
+    }
+    /* Now lookup index of header. */
+    id = httpHeaderIdByNameDef(t, strlen(t));
+    if (strcmp(t, "All") == 0)
+	id = HDR_ENUM_END;
+    else if (strcmp(t, "Other") == 0)
+	id = HDR_OTHER;
+    else if (id == -1) {
+	debug(3, 0) ("%s line %d: %s\n",
+	    cfg_filename, config_lineno, config_input_line);
+	debug(3, 0) ("parse_http_header_replace: unknown header name %s.\n",
+	    t);
+	return;
+    }
+    if (id != HDR_ENUM_END) {
+	if (header[id].replacement != NULL)
+	    safe_free(header[id].replacement);
+	header[id].replacement = xstrdup(t + strlen(t) + 1);
+    } else {
+	for (i = 0; i < HDR_ENUM_END; i++) {
+	    if (header[i].replacement != NULL)
+		safe_free(header[i].replacement);
+	    header[i].replacement = xstrdup(t + strlen(t) + 1);
+	}
+    }
+}
+
+static void
+free_http_header_replace(header_mangler header[])
+{
+    int i;
+    for (i = 0; i < HDR_ENUM_END; i++) {
+	if (header[i].replacement != NULL)
+	    safe_free(header[i].replacement);
+    }
+}
+
+void
+dump_cachedir_options(StoreEntry * entry, struct cache_dir_option *options, SwapDir * sd)
+{
+    struct cache_dir_option *option;
+    if (!options)
+	return;
+    for (option = options; option->name; option++)
+	option->dump(entry, option->name, sd);
+}
+
+static void
+dump_cachedir(StoreEntry * entry, const char *name, _SquidConfig::_cacheSwap swap)
+{
+    SwapDir *s;
+    int i;
+    for (i = 0; i < swap.n_configured; i++) {
+	s = swap.swapDirs + i;
+	storeAppendPrintf(entry, "%s %s %s", name, s->type, s->path);
+	if (s->dump)
+	    s->dump(entry, s);
+	dump_cachedir_options(entry, common_cachedir_options, s);
+	storeAppendPrintf(entry, "\n");
+    }
+}
+
+static int
+check_null_cachedir(_SquidConfig::_cacheSwap swap)
+{
+    return swap.swapDirs == NULL;
+}
+
+static int
+check_null_string(char *s)
+{
+    return s == NULL;
+}
+
+static void
+allocate_new_authScheme(authConfig * cfg)
+{
+    if (cfg->schemes == NULL) {
+	cfg->n_allocated = 4;
+	cfg->schemes = static_cast<authScheme *>(xcalloc(cfg->n_allocated, sizeof(authScheme)));
+    }
+    if (cfg->n_allocated == cfg->n_configured) {
+	authScheme *tmp;
+	cfg->n_allocated <<= 1;
+	tmp = static_cast<authScheme *>(xcalloc(cfg->n_allocated, sizeof(authScheme)));
+	xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme));
+	xfree(cfg->schemes);
+	cfg->schemes = tmp;
+    }
+}
+
+static void
+parse_authparam(authConfig * config)
+{
+    char *type_str;
+    char *param_str;
+    authScheme *scheme = NULL;
+    int type, i;
+
+    if ((type_str = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+
+    if ((param_str = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+
+    if ((type = authenticateAuthSchemeId(type_str)) == -1) {
+	debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
+	return;
+    }
+    for (i = 0; i < config->n_configured; i++) {
+	if (config->schemes[i].Id == type) {
+	    scheme = config->schemes + i;
+	}
+    }
+
+    if (scheme == NULL) {
+	allocate_new_authScheme(config);
+	scheme = config->schemes + config->n_configured;
+	config->n_configured++;
+	scheme->Id = type;
+	scheme->typestr = authscheme_list[type].typestr;
+    }
+    authscheme_list[type].parse(scheme, config->n_configured, param_str);
+}
+
+static void
+free_authparam(authConfig * cfg)
+{
+    authScheme *scheme;
+    int i;
+    /* DON'T FREE THESE FOR RECONFIGURE */
+    if (reconfiguring)
+	return;
+    for (i = 0; i < cfg->n_configured; i++) {
+	scheme = cfg->schemes + i;
+	authscheme_list[scheme->Id].freeconfig(scheme);
+    }
+    safe_free(cfg->schemes);
+    cfg->schemes = NULL;
+    cfg->n_allocated = 0;
+    cfg->n_configured = 0;
+}
+
+static void
+dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
+{
+    authScheme *scheme;
+    int i;
+    for (i = 0; i < cfg.n_configured; i++) {
+	scheme = cfg.schemes + i;
+	authscheme_list[scheme->Id].dump(entry, name, scheme);
+    }
+}
+
+void
+allocate_new_swapdir(_SquidConfig::_cacheSwap * swap)
+{
+    if (swap->swapDirs == NULL) {
+	swap->n_allocated = 4;
+	swap->swapDirs = static_cast<SwapDir *>(xcalloc(swap->n_allocated, sizeof(SwapDir)));
+    }
+    if (swap->n_allocated == swap->n_configured) {
+	SwapDir *tmp;
+	swap->n_allocated <<= 1;
+	tmp = static_cast<SwapDir *>(xcalloc(swap->n_allocated, sizeof(SwapDir)));
+	xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir));
+	xfree(swap->swapDirs);
+	swap->swapDirs = tmp;
+    }
+}
+
+static int
+find_fstype(char *type)
+{
+    int i;
+    for (i = 0; storefs_list[i].typestr != NULL; i++) {
+	if (strcasecmp(type, storefs_list[i].typestr) == 0) {
+	    return i;
+	}
+    }
+    return (-1);
+}
+
+static void
+parse_cachedir(_SquidConfig::_cacheSwap * swap)
+{
+    char *type_str;
+    char *path_str;
+    SwapDir *sd;
+    int i;
+    int fs;
+
+    if ((type_str = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+
+    if ((path_str = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+
+    /*
+     * This bit of code is a little strange.
+     * See, if we find a path and type match for a given line, then
+     * as long as we're reconfiguring, we can just call its reconfigure
+     * function. No harm there.
+     *
+     * Trouble is, if we find a path match, but not a type match, we have
+     * a dilemma - we could gracefully shut down the fs, kill it, and
+     * create a new one of a new type in its place, BUT at this stage the
+     * fs is meant to be the *NEW* one, and so things go very strange. :-)
+     *
+     * So, we'll assume the person isn't going to change the fs type for now,
+     * and XXX later on we will make sure that its picked up.
+     *
+     * (moving around cache_dir lines will be looked at later in a little
+     * more sane detail..)
+     */
+
+    for (i = 0; i < swap->n_configured; i++) {
+	if (0 == strcasecmp(path_str, swap->swapDirs[i].path)) {
+	    /* This is a little weird, you'll appreciate it later */
+	    fs = find_fstype(type_str);
+	    if (fs < 0) {
+		fatalf("Unknown cache_dir type '%s'\n", type_str);
+	    }
+	    sd = swap->swapDirs + i;
+	    storefs_list[fs].reconfigurefunc(sd, i, path_str);
+	    update_maxobjsize();
+	    return;
+	}
+    }
+
+    assert(swap->n_configured < 63);	/* 7 bits, signed */
+
+    fs = find_fstype(type_str);
+    if (fs < 0) {
+	/* If we get here, we didn't find a matching cache_dir type */
+	fatalf("Unknown cache_dir type '%s'\n", type_str);
+    }
+    allocate_new_swapdir(swap);
+    sd = swap->swapDirs + swap->n_configured;
+    sd->type = storefs_list[fs].typestr;
+    /* defaults in case fs implementation fails to set these */
+    sd->max_objsize = -1;
+    sd->fs.blksize = 1024;
+    /* parse the FS parameters and options */
+    storefs_list[fs].parsefunc(sd, swap->n_configured, path_str);
+    swap->n_configured++;
+    /* Update the max object size */
+    update_maxobjsize();
+}
+
+static void
+parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring)
+{
+    int read_only = 0;
+    if (value)
+	read_only = xatoi(value);
+    else
+	read_only = 1;
+    sd->flags.read_only = read_only;
+}
+
+static void
+dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd)
+{
+    if (sd->flags.read_only)
+	storeAppendPrintf(e, " %s", option);
+}
+
+static void
+parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring)
+{
+    ssize_t size;
+
+    if (!value)
+	self_destruct();
+
+    size = xatoi(value);
+
+    if (reconfiguring && sd->max_objsize != size)
+	debug(3, 1) ("Cache dir '%s' max object size now %ld\n", sd->path, (long int) size);
+
+    sd->max_objsize = size;
+}
+
+static void
+dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd)
+{
+    if (sd->max_objsize != -1)
+	storeAppendPrintf(e, " %s=%ld", option, (long int) sd->max_objsize);
+}
+
+void
+parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring)
+{
+    int old_read_only = sd->flags.read_only;
+    char *name, *value;
+    struct cache_dir_option *option, *op;
+
+    while ((name = strtok(NULL, w_space)) != NULL) {
+	value = strchr(name, '=');
+	if (value)
+	    *value++ = '\0';	/* cut on = */
+	option = NULL;
+	if (options) {
+	    for (op = options; !option && op->name; op++) {
+		if (strcmp(op->name, name) == 0) {
+		    option = op;
+		    break;
+		}
+	    }
+	}
+	for (op = common_cachedir_options; !option && op->name; op++) {
+	    if (strcmp(op->name, name) == 0) {
+		option = op;
+		break;
+	    }
+	}
+	if (!option || !option->parse)
+	    self_destruct();
+	option->parse(sd, name, value, reconfiguring);
+    }
+    /*
+     * Handle notifications about reconfigured single-options with no value
+     * where the removal of the option cannot be easily detected in the
+     * parsing...
+     */
+    if (reconfiguring) {
+	if (old_read_only != sd->flags.read_only) {
+	    debug(3, 1) ("Cache dir '%s' now %s\n",
+		sd->path, sd->flags.read_only ? "Read-Only" : "Read-Write");
+	}
+    }
+}
+
+static void
+free_cachedir(_SquidConfig::_cacheSwap * swap)
+{
+    SwapDir *s;
+    int i;
+    /* DON'T FREE THESE FOR RECONFIGURE */
+    if (reconfiguring)
+	return;
+    for (i = 0; i < swap->n_configured; i++) {
+	s = swap->swapDirs + i;
+	s->freefs(s);
+	xfree(s->path);
+    }
+    safe_free(swap->swapDirs);
+    swap->swapDirs = NULL;
+    swap->n_allocated = 0;
+    swap->n_configured = 0;
+}
+
+static const char *
+peer_type_str(const peer_t type)
+{
+    switch (type) {
+    case PEER_PARENT:
+	return "parent";
+	break;
+    case PEER_SIBLING:
+	return "sibling";
+	break;
+    case PEER_MULTICAST:
+	return "multicast";
+	break;
+    default:
+	return "unknown";
+	break;
+    }
+}
+
+static void
+dump_peer(StoreEntry * entry, const char *name, peer * p)
+{
+    domain_ping *d;
+    domain_type *t;
+    LOCAL_ARRAY(char, xname, 128);
+    while (p != NULL) {
+	storeAppendPrintf(entry, "%s %s %s %d %d",
+	    name,
+	    p->host,
+	    neighborTypeStr(p),
+	    p->http_port,
+	    p->icp.port);
+	dump_peer_options(entry, p);
+	for (d = p->peer_domain; d; d = d->next) {
+	    storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
+		p->host,
+		d->do_ping ? null_string : "!",
+		d->domain);
+	}
+	if (p->access) {
+	    snprintf(xname, 128, "cache_peer_access %s", p->host);
+	    dump_acl_access(entry, xname, p->access);
+	}
+	for (t = p->typelist; t; t = t->next) {
+	    storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
+		p->host,
+		peer_type_str(t->type),
+		t->domain);
+	}
+	p = p->next;
+    }
+}
+
+static void
+parse_peer(peer ** head)
+{
+    char *token = NULL;
+    peer *p;
+    int i;
+    p = cbdataAlloc(peer);
+    p->http_port = CACHE_HTTP_PORT;
+    p->icp.port = CACHE_ICP_PORT;
+    p->weight = 1;
+    p->basetime = 0;
+    p->stats.logged_state = PEER_ALIVE;
+    if ((token = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+    p->host = xstrdup(token);
+    if ((token = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+    p->type = parseNeighborType(token);
+    i = GetInteger();
+    p->http_port = (u_short) i;
+    i = GetInteger();
+    p->icp.port = (u_short) i;
+    while ((token = strtok(NULL, w_space))) {
+	if (!strcasecmp(token, "proxy-only")) {
+	    p->options.proxy_only = 1;
+	} else if (!strcasecmp(token, "no-query")) {
+	    p->options.no_query = 1;
+	} else if (!strcasecmp(token, "background-ping")) {
+	    p->options.background_ping = 1;
+	} else if (!strcasecmp(token, "no-digest")) {
+	    p->options.no_digest = 1;
+	} else if (!strcasecmp(token, "multicast-responder")) {
+	    p->options.mcast_responder = 1;
+	} else if (!strncasecmp(token, "weight=", 7)) {
+	    p->weight = xatoi(token + 7);
+	} else if (!strncasecmp(token, "basetime=", 9)) {
+	    p->basetime = xatoi(token + 9);
+	} else if (!strcasecmp(token, "closest-only")) {
+	    p->options.closest_only = 1;
+	} else if (!strncasecmp(token, "ttl=", 4)) {
+	    p->mcast.ttl = xatoi(token + 4);
+	    if (p->mcast.ttl < 0)
+		p->mcast.ttl = 0;
+	    if (p->mcast.ttl > 128)
+		p->mcast.ttl = 128;
+	} else if (!strcasecmp(token, "default")) {
+	    p->options.default_parent = 1;
+	} else if (!strcasecmp(token, "round-robin")) {
+	    p->options.roundrobin = 1;
+	} else if (!strcasecmp(token, "weighted-round-robin")) {
+	    p->options.weighted_roundrobin = 1;
+#if USE_HTCP
+	} else if (!strcasecmp(token, "htcp")) {
+	    p->options.htcp = 1;
+#endif
+	} else if (!strcasecmp(token, "no-netdb-exchange")) {
+	    p->options.no_netdb_exchange = 1;
+#if USE_CARP
+	} else if (!strcasecmp(token, "carp")) {
+	    if (p->type != PEER_PARENT)
+		fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
+	    p->options.carp = 1;
+#endif
+#if DELAY_POOLS
+	} else if (!strcasecmp(token, "no-delay")) {
+	    p->options.no_delay = 1;
+#endif
+	} else if (!strncasecmp(token, "login=", 6)) {
+	    p->login = xstrdup(token + 6);
+	    rfc1738_unescape(p->login);
+	} else if (!strncasecmp(token, "connect-timeout=", 16)) {
+	    p->connect_timeout = xatoi(token + 16);
+#if USE_CACHE_DIGESTS
+	} else if (!strncasecmp(token, "digest-url=", 11)) {
+	    p->digest_url = xstrdup(token + 11);
+#endif
+	} else if (!strcasecmp(token, "allow-miss")) {
+	    p->options.allow_miss = 1;
+	} else if (!strncasecmp(token, "max-conn=", 9)) {
+	    p->max_conn = xatoi(token + 9);
+	} else {
+	    debug(3, 0) ("parse_peer: token='%s'\n", token);
+	    self_destruct();
+	}
+    }
+    if (p->weight < 1)
+	p->weight = 1;
+    p->icp.version = ICP_VERSION_CURRENT;
+    p->tcp_up = PEER_TCP_MAGIC_COUNT;
+    p->test_fd = -1;
+#if USE_CACHE_DIGESTS
+    if (!p->options.no_digest) {
+	/* XXX This looks odd.. who has the original pointer
+	 * then?
+	 */
+	PeerDigest *pd = peerDigestCreate(p);
+	p->digest = cbdataReference(pd);
+    }
+#endif
+    while (*head != NULL)
+	head = &(*head)->next;
+    *head = p;
+    Config.npeers++;
+    peerClearRR(p);
+}
+
+static void
+free_peer(peer ** P)
+{
+    peer *p;
+    while ((p = *P) != NULL) {
+	*P = p->next;
+#if USE_CACHE_DIGESTS
+	cbdataReferenceDone(p->digest);
+#endif
+	cbdataFree(p);
+    }
+    Config.npeers = 0;
+}
+
+static void
+dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
+{
+    wordlist *w;
+    while (list != NULL) {
+	if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
+	    storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
+	else
+	    storeAppendPrintf(entry, "%s %s", name, list->passwd);
+	for (w = list->actions; w != NULL; w = w->next) {
+	    storeAppendPrintf(entry, " %s", w->key);
+	}
+	storeAppendPrintf(entry, "\n");
+	list = list->next;
+    }
+}
+
+static void
+parse_cachemgrpasswd(cachemgr_passwd ** head)
+{
+    char *passwd = NULL;
+    wordlist *actions = NULL;
+    cachemgr_passwd *p;
+    cachemgr_passwd **P;
+    parse_string(&passwd);
+    parse_wordlist(&actions);
+    p = static_cast<cachemgr_passwd *>(xcalloc(1, sizeof(cachemgr_passwd)));
+    p->passwd = passwd;
+    p->actions = actions;
+    for (P = head; *P; P = &(*P)->next);
+    *P = p;
+}
+
+static void
+free_cachemgrpasswd(cachemgr_passwd ** head)
+{
+    cachemgr_passwd *p;
+    while ((p = *head) != NULL) {
+	*head = p->next;
+	xfree(p->passwd);
+	wordlistDestroy(&p->actions);
+	xfree(p);
+    }
+}
+
+static void
+dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
+{
+    acl_name_list *a;
+    while (var != NULL) {
+	storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
+	for (a = var->acl_list; a != NULL; a = a->next)
+	    storeAppendPrintf(entry, " %s", a->name);
+	storeAppendPrintf(entry, "\n");
+	var = var->next;
+    }
+}
+
+static void
+parse_denyinfo(acl_deny_info_list ** var)
+{
+    aclParseDenyInfoLine(var);
+}
+
+void
+free_denyinfo(acl_deny_info_list ** list)
+{
+    acl_deny_info_list *a = NULL;
+    acl_deny_info_list *a_next = NULL;
+    acl_name_list *l = NULL;
+    acl_name_list *l_next = NULL;
+    for (a = *list; a; a = a_next) {
+	for (l = a->acl_list; l; l = l_next) {
+	    l_next = l->next;
+	    memFree(l, MEM_ACL_NAME_LIST);
+	    l = NULL;
+	}
+	a_next = a->next;
+	memFree(a, MEM_ACL_DENY_INFO_LIST);
+	a = NULL;
+    }
+    *list = NULL;
+}
+
+static void
+parse_peer_access(void)
+{
+    char *host = NULL;
+    peer *p;
+    if (!(host = strtok(NULL, w_space)))
+	self_destruct();
+    if ((p = peerFindByName(host)) == NULL) {
+	debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
+	    cfg_filename, config_lineno, host);
+	return;
+    }
+    aclParseAccessLine(&p->access);
+}
+
+static void
+parse_hostdomain(void)
+{
+    char *host = NULL;
+    char *domain = NULL;
+    if (!(host = strtok(NULL, w_space)))
+	self_destruct();
+    while ((domain = strtok(NULL, list_sep))) {
+	domain_ping *l = NULL;
+	domain_ping **L = NULL;
+	peer *p;
+	if ((p = peerFindByName(host)) == NULL) {
+	    debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
+		cfg_filename, config_lineno, host);
+	    continue;
+	}
+	l = static_cast<domain_ping *>(xcalloc(1, sizeof(domain_ping)));
+	l->do_ping = 1;
+	if (*domain == '!') {	/* check for !.edu */
+	    l->do_ping = 0;
+	    domain++;
+	}
+	l->domain = xstrdup(domain);
+	for (L = &(p->peer_domain); *L; L = &((*L)->next));
+	*L = l;
+    }
+}
+
+static void
+parse_hostdomaintype(void)
+{
+    char *host = NULL;
+    char *type = NULL;
+    char *domain = NULL;
+    if (!(host = strtok(NULL, w_space)))
+	self_destruct();
+    if (!(type = strtok(NULL, w_space)))
+	self_destruct();
+    while ((domain = strtok(NULL, list_sep))) {
+	domain_type *l = NULL;
+	domain_type **L = NULL;
+	peer *p;
+	if ((p = peerFindByName(host)) == NULL) {
+	    debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
+		cfg_filename, config_lineno, host);
+	    return;
+	}
+	l = static_cast<domain_type *>(xcalloc(1, sizeof(domain_type)));
+	l->type = parseNeighborType(type);
+	l->domain = xstrdup(domain);
+	for (L = &(p->typelist); *L; L = &((*L)->next));
+	*L = l;
+    }
+}
+
+#if UNUSED_CODE
+static void
+dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
+{
+    while (u) {
+	storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
+	u = u->next;
+    }
+}
+
+static int
+check_null_ushortlist(ushortlist * u)
+{
+    return u == NULL;
+}
+
+static void
+parse_ushortlist(ushortlist ** P)
+{
+    char *token;
+    int i;
+    ushortlist *u;
+    ushortlist **U;
+    while ((token = strtok(NULL, w_space))) {
+	if (sscanf(token, "%d", &i) != 1)
+	    self_destruct();
+	if (i < 0)
+	    i = 0;
+	u = xcalloc(1, sizeof(ushortlist));
+	u->i = (u_short) i;
+	for (U = P; *U; U = &(*U)->next);
+	*U = u;
+    }
+}
+
+static void
+free_ushortlist(ushortlist ** P)
+{
+    ushortlist *u;
+    while ((u = *P) != NULL) {
+	*P = u->next;
+	xfree(u);
+    }
+}
+#endif
+
+static void
+dump_int(StoreEntry * entry, const char *name, int var)
+{
+    storeAppendPrintf(entry, "%s %d\n", name, var);
+}
+
+void
+parse_int(int *var)
+{
+    int i;
+    i = GetInteger();
+    *var = i;
+}
+
+static void
+free_int(int *var)
+{
+    *var = 0;
+}
+
+static void
+dump_onoff(StoreEntry * entry, const char *name, int var)
+{
+    storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
+}
+
+void
+parse_onoff(int *var)
+{
+    char *token = strtok(NULL, w_space);
+
+    if (token == NULL)
+	self_destruct();
+    if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
+	*var = 1;
+    else
+	*var = 0;
+}
+
+#define free_onoff free_int
+#define dump_eol dump_string
+#define free_eol free_string
+
+static void
+dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
+{
+    while (head != NULL) {
+	storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
+	    name,
+	    head->flags.icase ? " -i" : null_string,
+	    head->pattern,
+	    (int) head->min / 60,
+	    (int) (100.0 * head->pct + 0.5),
+	    (int) head->max / 60);
+#if HTTP_VIOLATIONS
+	if (head->flags.override_expire)
+	    storeAppendPrintf(entry, " override-expire");
+	if (head->flags.override_lastmod)
+	    storeAppendPrintf(entry, " override-lastmod");
+	if (head->flags.reload_into_ims)
+	    storeAppendPrintf(entry, " reload-into-ims");
+	if (head->flags.ignore_reload)
+	    storeAppendPrintf(entry, " ignore-reload");
+#endif
+	storeAppendPrintf(entry, "\n");
+	head = head->next;
+    }
+}
+
+static void
+parse_refreshpattern(refresh_t ** head)
+{
+    char *token;
+    char *pattern;
+    time_t min = 0;
+    double pct = 0.0;
+    time_t max = 0;
+#if HTTP_VIOLATIONS
+    int override_expire = 0;
+    int override_lastmod = 0;
+    int reload_into_ims = 0;
+    int ignore_reload = 0;
+#endif
+    int i;
+    refresh_t *t;
+    regex_t comp;
+    int errcode;
+    int flags = REG_EXTENDED | REG_NOSUB;
+    if ((token = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+    if (strcmp(token, "-i") == 0) {
+	flags |= REG_ICASE;
+	token = strtok(NULL, w_space);
+    } else if (strcmp(token, "+i") == 0) {
+	flags &= ~REG_ICASE;
+	token = strtok(NULL, w_space);
+    }
+    if (token == NULL)
+	self_destruct();
+    pattern = xstrdup(token);
+    i = GetInteger();		/* token: min */
+    min = (time_t) (i * 60);	/* convert minutes to seconds */
+    i = GetInteger();		/* token: pct */
+    pct = (double) i / 100.0;
+    i = GetInteger();		/* token: max */
+    max = (time_t) (i * 60);	/* convert minutes to seconds */
+    /* Options */
+    while ((token = strtok(NULL, w_space)) != NULL) {
+#if HTTP_VIOLATIONS
+	if (!strcmp(token, "override-expire"))
+	    override_expire = 1;
+	else if (!strcmp(token, "override-lastmod"))
+	    override_lastmod = 1;
+	else if (!strcmp(token, "reload-into-ims")) {
+	    reload_into_ims = 1;
+	    refresh_nocache_hack = 1;
+	    /* tell client_side.c that this is used */
+	} else if (!strcmp(token, "ignore-reload")) {
+	    ignore_reload = 1;
+	    refresh_nocache_hack = 1;
+	    /* tell client_side.c that this is used */
+	} else
+#endif
+	    debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
+		pattern, token);
+    }
+    if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
+	char errbuf[256];
+	regerror(errcode, &comp, errbuf, sizeof errbuf);
+	debug(22, 0) ("%s line %d: %s\n",
+	    cfg_filename, config_lineno, config_input_line);
+	debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %s\n",
+	    pattern, errbuf);
+	return;
+    }
+    pct = pct < 0.0 ? 0.0 : pct;
+    max = max < 0 ? 0 : max;
+    t = static_cast<refresh_t *>(xcalloc(1, sizeof(refresh_t)));
+    t->pattern = (char *) xstrdup(pattern);
+    t->compiled_pattern = comp;
+    t->min = min;
+    t->pct = pct;
+    t->max = max;
+    if (flags & REG_ICASE)
+	t->flags.icase = 1;
+#if HTTP_VIOLATIONS
+    if (override_expire)
+	t->flags.override_expire = 1;
+    if (override_lastmod)
+	t->flags.override_lastmod = 1;
+    if (reload_into_ims)
+	t->flags.reload_into_ims = 1;
+    if (ignore_reload)
+	t->flags.ignore_reload = 1;
+#endif
+    t->next = NULL;
+    while (*head)
+	head = &(*head)->next;
+    *head = t;
+    safe_free(pattern);
+}
+
+#if UNUSED_CODE
+static int
+check_null_refreshpattern(refresh_t * data)
+{
+    return data == NULL;
+}
+#endif
+
+static void
+free_refreshpattern(refresh_t ** head)
+{
+    refresh_t *t;
+    while ((t = *head) != NULL) {
+	*head = t->next;
+	safe_free(t->pattern);
+	regfree(&t->compiled_pattern);
+	safe_free(t);
+    }
+}
+
+static void
+dump_string(StoreEntry * entry, const char *name, char *var)
+{
+    if (var != NULL)
+	storeAppendPrintf(entry, "%s %s\n", name, var);
+}
+
+static void
+parse_string(char **var)
+{
+    char *token = strtok(NULL, w_space);
+    safe_free(*var);
+    if (token == NULL)
+	self_destruct();
+    *var = xstrdup(token);
+}
+
+static void
+free_string(char **var)
+{
+    safe_free(*var);
+}
+
+void
+parse_eol(char *volatile *var)
+{
+    unsigned char *token = (unsigned char *) strtok(NULL, null_string);
+    safe_free(*var);
+    if (token == NULL)
+	self_destruct();
+    while (*token && isspace(*token))
+	token++;
+    if (!*token)
+	self_destruct();
+    *var = xstrdup((char *) token);
+}
+
+static void
+dump_time_t(StoreEntry * entry, const char *name, time_t var)
+{
+    storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
+}
+
+void
+parse_time_t(time_t * var)
+{
+    parseTimeLine(var, T_SECOND_STR);
+}
+
+static void
+free_time_t(time_t * var)
+{
+    *var = 0;
+}
+
+static void
+dump_size_t(StoreEntry * entry, const char *name, size_t var)
+{
+    storeAppendPrintf(entry, "%s %d\n", name, (int) var);
+}
+
+static void
+dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
+{
+    storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
+}
+
+static void
+dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
+{
+    storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
+}
+
+static void
+parse_size_t(size_t * var)
+{
+    int i;
+    i = GetInteger();
+    *var = (size_t) i;
+}
+
+static void
+parse_b_size_t(size_t * var)
+{
+    parseBytesLine(var, B_BYTES_STR);
+}
+
+CBDATA_TYPE(body_size);
+
+static void
+parse_body_size_t(dlink_list * bodylist)
+{
+    body_size *bs;
+    CBDATA_INIT_TYPE(body_size);
+    bs = cbdataAlloc(body_size);
+    parse_size_t(&bs->maxsize);
+    aclParseAccessLine(&bs->access_list);
+
+    dlinkAddTail(bs, &bs->node, bodylist);
+}
+
+static void
+dump_body_size_t(StoreEntry * entry, const char *name, dlink_list bodylist)
+{
+    body_size *bs;
+    bs = (body_size *) bodylist.head;
+    while (bs) {
+	acl_list *l;
+	acl_access *head = bs->access_list;
+	while (head != NULL) {
+	    storeAppendPrintf(entry, "%s %ld %s", name, (long int) bs->maxsize,
+		head->allow ? "Allow" : "Deny");
+	    for (l = head->aclList; l != NULL; l = l->next) {
+		storeAppendPrintf(entry, " %s%s",
+		    l->op ? null_string : "!",
+		    l->_acl->name);
+	    }
+	    storeAppendPrintf(entry, "\n");
+	    head = head->next;
+	}
+	bs = (body_size *) bs->node.next;
+    }
+}
+
+static void
+free_body_size_t(dlink_list * bodylist)
+{
+    body_size *bs, *tempnode;
+    bs = (body_size *) bodylist->head;
+    while (bs) {
+	bs->maxsize = 0;
+	aclDestroyAccessList(&bs->access_list);
+	tempnode = (body_size *) bs->node.next;
+	dlinkDelete(&bs->node, bodylist);
+	cbdataFree(bs);
+	bs = tempnode;
+    }
+}
+
+static int
+check_null_body_size_t(dlink_list bodylist)
+{
+    return bodylist.head == NULL;
+}
+
+
+static void
+parse_kb_size_t(size_t * var)
+{
+    parseBytesLine(var, B_KBYTES_STR);
+}
+
+static void
+free_size_t(size_t * var)
+{
+    *var = 0;
+}
+
+#define free_b_size_t free_size_t
+#define free_kb_size_t free_size_t
+#define free_mb_size_t free_size_t
+#define free_gb_size_t free_size_t
+
+static void
+dump_ushort(StoreEntry * entry, const char *name, u_short var)
+{
+    storeAppendPrintf(entry, "%s %d\n", name, var);
+}
+
+static void
+free_ushort(u_short * u)
+{
+    *u = 0;
+}
+
+static void
+parse_ushort(u_short * var)
+{
+    int i;
+
+    i = GetInteger();
+    if (i < 0)
+	i = 0;
+    *var = (u_short) i;
+}
+
+static void
+dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
+{
+    while (list != NULL) {
+	storeAppendPrintf(entry, "%s %s\n", name, list->key);
+	list = list->next;
+    }
+}
+
+void
+parse_wordlist(wordlist ** list)
+{
+    char *token;
+    char *t = strtok(NULL, "");
+    while ((token = strwordtok(NULL, &t)))
+	wordlistAdd(list, token);
+}
+
+static int
+check_null_wordlist(wordlist * w)
+{
+    return w == NULL;
+}
+
+static int
+check_null_acl_access(acl_access * a)
+{
+    return a == NULL;
+}
+
+#define free_wordlist wordlistDestroy
+
+#define free_uri_whitespace free_int
+
+static void
+parse_uri_whitespace(int *var)
+{
+    char *token = strtok(NULL, w_space);
+    if (token == NULL)
+	self_destruct();
+    if (!strcasecmp(token, "strip"))
+	*var = URI_WHITESPACE_STRIP;
+    else if (!strcasecmp(token, "deny"))
+	*var = URI_WHITESPACE_DENY;
+    else if (!strcasecmp(token, "allow"))
+	*var = URI_WHITESPACE_ALLOW;
+    else if (!strcasecmp(token, "encode"))
+	*var = URI_WHITESPACE_ENCODE;
+    else if (!strcasecmp(token, "chop"))
+	*var = URI_WHITESPACE_CHOP;
+    else
+	self_destruct();
+}
+
+
+static void
+dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
+{
+    const char *s;
+    if (var == URI_WHITESPACE_ALLOW)
+	s = "allow";
+    else if (var == URI_WHITESPACE_ENCODE)
+	s = "encode";
+    else if (var == URI_WHITESPACE_CHOP)
+	s = "chop";
+    else if (var == URI_WHITESPACE_DENY)
+	s = "deny";
+    else
+	s = "strip";
+    storeAppendPrintf(entry, "%s %s\n", name, s);
+}
+
+static void
+free_removalpolicy(RemovalPolicySettings ** settings)
+{
+    if (!*settings)
+	return;
+    free_string(&(*settings)->type);
+    free_wordlist(&(*settings)->args);
+    xfree(*settings);
+    *settings = NULL;
+}
+
+static void
+parse_removalpolicy(RemovalPolicySettings ** settings)
+{
+    if (*settings)
+	free_removalpolicy(settings);
+    *settings = static_cast<RemovalPolicySettings *>(xcalloc(1, sizeof(**settings)));
+    parse_string(&(*settings)->type);
+    parse_wordlist(&(*settings)->args);
+}
+
+static void
+dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
+{
+    wordlist *args;
+    storeAppendPrintf(entry, "%s %s", name, settings->type);
+    args = settings->args;
+    while (args) {
+	storeAppendPrintf(entry, " %s", args->key);
+	args = args->next;
+    }
+    storeAppendPrintf(entry, "\n");
+}
+
+
+#include "cf_parser.h"
+
+peer_t
+parseNeighborType(const char *s)
+{
+    if (!strcasecmp(s, "parent"))
+	return PEER_PARENT;
+    if (!strcasecmp(s, "neighbor"))
+	return PEER_SIBLING;
+    if (!strcasecmp(s, "neighbour"))
+	return PEER_SIBLING;
+    if (!strcasecmp(s, "sibling"))
+	return PEER_SIBLING;
+    if (!strcasecmp(s, "multicast"))
+	return PEER_MULTICAST;
+    debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s);
+    return PEER_SIBLING;
+}
+
+void
+parse_sockaddr_in_list_token(sockaddr_in_list ** head, char *token)
+{
+    char *t;
+    char *host;
+    const struct hostent *hp;
+    unsigned short port;
+    sockaddr_in_list *s;
+
+    host = NULL;
+    port = 0;
+    if ((t = strchr(token, ':'))) {
+	/* host:port */
+	host = token;
+	*t = '\0';
+	port = (unsigned short) xatoi(t + 1);
+	if (0 == port)
+	    self_destruct();
+    } else if ((port = xatoi(token)) > 0) {
+	/* port */
+    } else {
+	self_destruct();
+    }
+    s = static_cast<sockaddr_in_list *>(xcalloc(1, sizeof(*s)));
+    s->s.sin_port = htons(port);
+    if (NULL == host)
+	s->s.sin_addr = any_addr;
+    else if (1 == safe_inet_addr(host, &s->s.sin_addr))
+	(void) 0;
+    else if ((hp = gethostbyname(host)))	/* dont use ipcache */
+	s->s.sin_addr = inaddrFromHostent(hp);
+    else
+	self_destruct();
+    while (*head)
+	head = &(*head)->next;
+    *head = s;
+}
+
+static void
+parse_sockaddr_in_list(sockaddr_in_list ** head)
+{
+    char *token;
+    while ((token = strtok(NULL, w_space))) {
+	parse_sockaddr_in_list_token(head, token);
+    }
+}
+
+static void
+dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
+{
+    while (s) {
+	storeAppendPrintf(e, "%s %s:%d\n",
+	    n,
+	    inet_ntoa(s->s.sin_addr),
+	    ntohs(s->s.sin_port));
+	s = s->next;
+    }
+}
+
+static void
+free_sockaddr_in_list(sockaddr_in_list ** head)
+{
+    sockaddr_in_list *s;
+    while ((s = *head) != NULL) {
+	*head = s->next;
+	xfree(s);
+    }
+}
+
+#if 0
+static int
+check_null_sockaddr_in_list(const sockaddr_in_list * s)
+{
+    return NULL == s;
+}
+#endif
+
+#if USE_SSL
+static void
+parse_https_port_list(https_port_list ** head)
+{
+    char *token;
+    char *t;
+    char *host;
+    const struct hostent *hp;
+    unsigned short port;
+    https_port_list *s;
+    token = strtok(NULL, w_space);
+    if (!token)
+	self_destruct();
+    host = NULL;
+    port = 0;
+    if ((t = strchr(token, ':'))) {
+	/* host:port */
+	host = token;
+	*t = '\0';
+	port = (unsigned short) xatoi(t + 1);
+	if (0 == port)
+	    self_destruct();
+    } else if ((port = xatoi(token)) > 0) {
+	/* port */
+    } else {
+	self_destruct();
+    }
+    s = xcalloc(1, sizeof(*s));
+    s->s.sin_port = htons(port);
+    if (NULL == host)
+	s->s.sin_addr = any_addr;
+    else if (1 == safe_inet_addr(host, &s->s.sin_addr))
+	(void) 0;
+    else if ((hp = gethostbyname(host)))	/* dont use ipcache */
+	s->s.sin_addr = inaddrFromHostent(hp);
+    else
+	self_destruct();
+    /* parse options ... */
+    while ((token = strtok(NULL, w_space))) {
+	if (strncmp(token, "cert=", 5) == 0) {
+	    safe_free(s->cert);
+	    s->cert = xstrdup(token + 5);
+	} else if (strncmp(token, "key=", 4) == 0) {
+	    safe_free(s->key);
+	    s->key = xstrdup(token + 4);
+	} else if (strncmp(token, "version=", 8) == 0) {
+	    s->version = xatoi(token + 8);
+	} else if (strncmp(token, "options=", 8) == 0) {
+	    safe_free(s->options);
+	    s->options = xstrdup(token + 8);
+	} else if (strncmp(token, "cipher=", 7) == 0) {
+	    safe_free(s->cipher);
+	    s->cipher = xstrdup(token + 7);
+	} else {
+	    self_destruct();
+	}
+    }
+    while (*head)
+	head = &(*head)->next;
+    *head = s;
+}
+
+static void
+dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
+{
+    while (s) {
+	storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"",
+	    n,
+	    inet_ntoa(s->s.sin_addr),
+	    ntohs(s->s.sin_port),
+	    s->cert,
+	    s->key);
+	if (s->version)
+	    storeAppendPrintf(e, " version=%d", s->version);
+	if (s->options)
+	    storeAppendPrintf(e, " options=%s", s->options);
+	if (s->cipher)
+	    storeAppendPrintf(e, " cipher=%s", s->cipher);
+	storeAppendPrintf(e, "\n");
+	s = s->next;
+    }
+}
+
+static void
+free_https_port_list(https_port_list ** head)
+{
+    https_port_list *s;
+    while ((s = *head) != NULL) {
+	*head = s->next;
+	safe_free(s->cert);
+	safe_free(s->key);
+	safe_free(s);
+    }
+}
+
+#if 0
+static int
+check_null_https_port_list(const https_port_list * s)
+{
+    return NULL == s;
+}
+#endif
+
+#endif /* USE_SSL */
+
+void
+configFreeMemory(void)
+{
+    safe_free(Config2.Accel.prefix);
+    free_all();
+}
+
+void
+requirePathnameExists(const char *name, const char *path)
+{
+    struct stat sb;
+    assert(path != NULL);
+    if (stat(path, &sb) < 0)
+	fatalf("%s: %s", path, xstrerror());
+}
+
+char *
+strtokFile(void)
+{
+    static int fromFile = 0;
+    static FILE *wordFile = NULL;
+
+    char *t, *fn;
+    LOCAL_ARRAY(char, buf, 256);
+
+  strtok_again:
+    if (!fromFile) {
+	t = (strtok(NULL, w_space));
+	if (!t || *t == '#') {
+	    return NULL;
+	} else if (*t == '\"' || *t == '\'') {
+	    /* quote found, start reading from file */
+	    fn = ++t;
+	    while (*t && *t != '\"' && *t != '\'')
+		t++;
+	    *t = '\0';
+	    if ((wordFile = fopen(fn, "r")) == NULL) {
+		debug(28, 0) ("strtokFile: %s not found\n", fn);
+		return (NULL);
+	    }
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+	    setmode(fileno(wordFile), O_TEXT);
+#endif
+	    fromFile = 1;
+	} else {
+	    return t;
+	}
+    }
+    /* fromFile */
+    if (fgets(buf, 256, wordFile) == NULL) {
+	/* stop reading from file */
+	fclose(wordFile);
+	wordFile = NULL;
+	fromFile = 0;
+	goto strtok_again;
+    } else {
+	t = buf;
+	/* skip leading and trailing white space */
+	t += strspn(buf, w_space);
+	t[strcspn(t, w_space)] = '\0';
+	/* skip comments */
+	if (*t == '#')
+	    goto strtok_again;
+	/* skip blank lines */
+	if (!*t)
+	    goto strtok_again;
+	return t;
+    }
+}
Index: squid/src/cf.data.pre
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/cf.data.pre,v
retrieving revision 1.83
retrieving revision 1.83.2.1
diff -u -r1.83 -r1.83.2.1
--- squid/src/cf.data.pre	29 Sep 2002 19:33:24 -0000	1.83
+++ squid/src/cf.data.pre	3 Oct 2002 01:04:33 -0000	1.83.2.1
@@ -1,6 +1,6 @@
 
 #
-# $Id: cf.data.pre,v 1.83 2002/09/29 19:33:24 squidadm Exp $
+# $Id: cf.data.pre,v 1.83.2.1 2002/10/03 01:04:33 rbcollins Exp $
 #
 #
 # SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -1283,7 +1283,7 @@
 
 NAME: auth_param
 TYPE: authparam
-LOC: Config.authConfig
+LOC: Config.authConfiguration
 DEFAULT: none
 DOC_START
 	This is used to pass parameters to the various authentication
Index: squid/src/client_side.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v
retrieving revision 1.76
retrieving revision 1.76.2.1
diff -u -r1.76 -r1.76.2.1
--- squid/src/client_side.c	27 Sep 2002 21:45:34 -0000	1.76
+++ squid/src/client_side.c	3 Oct 2002 01:04:34 -0000	1.76.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side.c,v 1.76 2002/09/27 21:45:34 squidadm Exp $
+ * $Id: client_side.c,v 1.76.2.1 2002/10/03 01:04:34 rbcollins Exp $
  *
  * DEBUG: section 33    Client-side Routines
  * AUTHOR: Duane Wessels
@@ -58,6 +58,7 @@
 #include "squid.h"
 #include "clientStream.h"
 #include "IPInterception.h"
+#include "authenticate.h"
 
 #if LINGERING_CLOSE
 #define comm_close comm_lingering_close
Index: squid/src/client_side_reply.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Attic/client_side_reply.c,v
retrieving revision 1.9
retrieving revision 1.9.4.1
diff -u -r1.9 -r1.9.4.1
--- squid/src/client_side_reply.c	29 Sep 2002 12:39:30 -0000	1.9
+++ squid/src/client_side_reply.c	3 Oct 2002 01:04:34 -0000	1.9.4.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side_reply.c,v 1.9 2002/09/29 12:39:30 rbcollins Exp $
+ * $Id: client_side_reply.c,v 1.9.4.1 2002/10/03 01:04:34 rbcollins Exp $
  *
  * DEBUG: section 88    Client-side Reply Routines
  * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c)
@@ -36,6 +36,7 @@
 #include "squid.h"
 #include "StoreClient.h"
 #include "clientStream.h"
+#include "authenticate.h"
 
 typedef struct _clientReplyContext {
     clientHttpRequest *http;
Index: squid/src/client_side_request.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Attic/client_side_request.c,v
retrieving revision 1.5
retrieving revision 1.5.8.1
diff -u -r1.5 -r1.5.8.1
--- squid/src/client_side_request.c	24 Sep 2002 10:59:15 -0000	1.5
+++ squid/src/client_side_request.c	3 Oct 2002 01:04:35 -0000	1.5.8.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side_request.c,v 1.5 2002/09/24 10:59:15 rbcollins Exp $
+ * $Id: client_side_request.c,v 1.5.8.1 2002/10/03 01:04:35 rbcollins Exp $
  * 
  * DEBUG: section 85    Client-side Request Routines AUTHOR: Robert Collins
  * (Originally Duane Wessels in client_side.c)
@@ -44,6 +44,7 @@
 #include "squid.h"
 #include "clientStream.h"
 #include "client_side_request.h"
+#include "authenticate.h"
 
 #if LINGERING_CLOSE
 #define comm_close comm_lingering_close
@@ -245,7 +246,7 @@
     clientHttpRequest *http = context->http;
     err_type page_id;
     http_status status;
-    char *proxy_auth_msg = NULL;
+    char const *proxy_auth_msg = NULL;
     debug(85, 2) ("The request %s %s is %s, because it matched '%s'\n",
 	RequestMethodStr[http->request->method], http->uri,
 	answer == ACCESS_ALLOWED ? "ALLOWED" : "DENIED",
Index: squid/src/defines.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/defines.h,v
retrieving revision 1.25
retrieving revision 1.25.6.1
diff -u -r1.25 -r1.25.6.1
--- squid/src/defines.h	15 Sep 2002 11:06:31 -0000	1.25
+++ squid/src/defines.h	3 Oct 2002 01:04:35 -0000	1.25.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: defines.h,v 1.25 2002/09/15 11:06:31 rbcollins Exp $
+ * $Id: defines.h,v 1.25.6.1 2002/10/03 01:04:35 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -291,10 +291,10 @@
 #endif
 #define cbdataReference(var)	(cbdataInternalLock(var), var)
 #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0)
-#define CBDATA_TYPE(type)	static cbdata_type CBDATA_##type = 0
+#define CBDATA_TYPE(type)	static cbdata_type CBDATA_##type = CBDATA_UNKNOWN
 #define CBDATA_GLOBAL_TYPE(type)	cbdata_type CBDATA_##type
-#define CBDATA_INIT_TYPE(type)	(CBDATA_##type ? 0 : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL)))
-#define CBDATA_INIT_TYPE_FREECB(type, free_func)	(CBDATA_##type ? 0 : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func)))
+#define CBDATA_INIT_TYPE(type)	(CBDATA_##type ?  CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL)))
+#define CBDATA_INIT_TYPE_FREECB(type, free_func)	(CBDATA_##type ?  CBDATA_UNKNOWN : (CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func)))
 
 #ifndef O_TEXT
 #define O_TEXT 0
Index: squid/src/enums.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/enums.h,v
retrieving revision 1.40
retrieving revision 1.40.2.1
diff -u -r1.40 -r1.40.2.1
--- squid/src/enums.h	24 Sep 2002 10:59:15 -0000	1.40
+++ squid/src/enums.h	3 Oct 2002 01:04:35 -0000	1.40.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: enums.h,v 1.40 2002/09/24 10:59:15 rbcollins Exp $
+ * $Id: enums.h,v 1.40.2.1 2002/10/03 01:04:35 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -589,8 +589,6 @@
     MEM_ACL_IP_DATA,
     MEM_ACL_LIST,
     MEM_ACL_NAME_LIST,
-    MEM_AUTH_USER_T,
-    MEM_AUTH_USER_HASH,
     MEM_ACL_PROXY_AUTH_MATCH,
     MEM_ACL_USER_DATA,
     MEM_ACL_TIME_DATA,
--- squid/src/errorpage.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,726 +0,0 @@
-
-/*
- * $Id: errorpage.c,v 1.23 2002/09/15 11:06:32 rbcollins Exp $
- *
- * DEBUG: section 4     Error Generation
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-/*
- * Abstract:  These routines are used to generate error messages to be
- *              sent to clients.  The error type is used to select between
- *              the various message formats. (formats are stored in the
- *              Config.errorDirectory)
- */
-
-#include "squid.h"
-
-
-/* local types */
-
-typedef struct {
-    int id;
-    char *page_name;
-} ErrorDynamicPageInfo;
-
-/* local constant and vars */
-
-/*
- * note: hard coded error messages are not appended with %S automagically
- * to give you more control on the format
- */
-static const struct {
-    int type;			/* and page_id */
-    const char *text;
-} error_hard_text[] = {
-
-    {
-	ERR_SQUID_SIGNATURE,
-	    "\n<BR clear=\"all\">\n"
-	    "<HR noshade size=\"1px\">\n"
-	    "<ADDRESS>\n"
-	    "Generated %T by %h (%s)\n"
-	    "</ADDRESS>\n"
-	    "</BODY></HTML>\n"
-    },
-    {
-	TCP_RESET,
-	    "reset"
-    }
-};
-
-static Stack ErrorDynamicPages;
-
-/* local prototypes */
-
-static const int error_hard_text_count = sizeof(error_hard_text) / sizeof(*error_hard_text);
-static char **error_text = NULL;
-static int error_page_count = 0;
-
-static char *errorTryLoadText(const char *page_name, const char *dir);
-static char *errorLoadText(const char *page_name);
-static const char *errorFindHardText(err_type type);
-static ErrorDynamicPageInfo *errorDynamicPageInfoCreate(int id, const char *page_name);
-static void errorDynamicPageInfoDestroy(ErrorDynamicPageInfo * info);
-static MemBuf errorBuildContent(ErrorState * err);
-static int errorDump(ErrorState * err, MemBuf * mb);
-static const char *errorConvert(char token, ErrorState * err);
-static CWCB errorSendComplete;
-
-/*
- * Function:  errorInitialize
- *
- * Abstract:  This function finds the error messages formats, and stores
- *            them in error_text[];
- *
- * Global effects:
- *            error_text[] - is modified
- */
-void
-errorInitialize(void)
-{
-    err_type i;
-    const char *text;
-    error_page_count = ERR_MAX + ErrorDynamicPages.count;
-    error_text = xcalloc(error_page_count, sizeof(char *));
-    for (i = ERR_NONE, i++; i < error_page_count; i++) {
-	safe_free(error_text[i]);
-	/* hard-coded ? */
-	if ((text = errorFindHardText(i)))
-	    error_text[i] = xstrdup(text);
-	else if (i < ERR_MAX) {
-	    /* precompiled ? */
-	    error_text[i] = errorLoadText(err_type_str[i]);
-	} else {
-	    /* dynamic */
-	    ErrorDynamicPageInfo *info = ErrorDynamicPages.items[i - ERR_MAX];
-	    assert(info && info->id == i && info->page_name);
-	    if (strchr(info->page_name, ':') == NULL) {
-		/* Not on redirected errors... */
-		error_text[i] = errorLoadText(info->page_name);
-	    }
-	}
-    }
-}
-
-void
-errorClean(void)
-{
-    if (error_text) {
-	int i;
-	for (i = ERR_NONE + 1; i < error_page_count; i++)
-	    safe_free(error_text[i]);
-	safe_free(error_text);
-    }
-    while (ErrorDynamicPages.count)
-	errorDynamicPageInfoDestroy(stackPop(&ErrorDynamicPages));
-    error_page_count = 0;
-}
-
-static const char *
-errorFindHardText(err_type type)
-{
-    int i;
-    for (i = 0; i < error_hard_text_count; i++)
-	if (error_hard_text[i].type == type)
-	    return error_hard_text[i].text;
-    return NULL;
-}
-
-
-static char *
-errorLoadText(const char *page_name)
-{
-    /* test configured location */
-    char *text = errorTryLoadText(page_name, Config.errorDirectory);
-    /* test default location if failed */
-    if (!text && strcmp(Config.errorDirectory, DEFAULT_SQUID_ERROR_DIR))
-	text = errorTryLoadText(page_name, DEFAULT_SQUID_ERROR_DIR);
-    /* giving up if failed */
-    if (!text)
-	fatal("failed to find or read error text file.");
-    return text;
-}
-
-static char *
-errorTryLoadText(const char *page_name, const char *dir)
-{
-    int fd;
-    char path[MAXPATHLEN];
-    struct stat sb;
-    char *text;
-
-    snprintf(path, sizeof(path), "%s/%s", dir, page_name);
-    fd = file_open(path, O_RDONLY | O_TEXT);
-    if (fd < 0 || fstat(fd, &sb) < 0) {
-	debug(4, 0) ("errorTryLoadText: '%s': %s\n", path, xstrerror());
-	if (fd >= 0)
-	    file_close(fd);
-	return NULL;
-    }
-    text = xcalloc(sb.st_size + 2 + 1, 1);	/* 2 == space for %S */
-    if (FD_READ_METHOD(fd, text, sb.st_size) != sb.st_size) {
-	debug(4, 0) ("errorTryLoadText: failed to fully read: '%s': %s\n",
-	    path, xstrerror());
-	xfree(text);
-	text = NULL;
-    }
-    file_close(fd);
-    if (strstr(text, "%s") == NULL)
-	strcat(text, "%S");	/* add signature */
-    return text;
-}
-
-static ErrorDynamicPageInfo *
-errorDynamicPageInfoCreate(int id, const char *page_name)
-{
-    ErrorDynamicPageInfo *info = xcalloc(1, sizeof(ErrorDynamicPageInfo));
-    info->id = id;
-    info->page_name = xstrdup(page_name);
-    return info;
-}
-
-static void
-errorDynamicPageInfoDestroy(ErrorDynamicPageInfo * info)
-{
-    assert(info);
-    xfree(info->page_name);
-    xfree(info);
-}
-
-static int
-errorPageId(const char *page_name)
-{
-    int i;
-    for (i = 0; i < ERR_MAX; i++) {
-	if (strcmp(err_type_str[i], page_name) == 0)
-	    return i;
-    }
-    for (i = 0; i < ErrorDynamicPages.count; i++) {
-	if (strcmp(((ErrorDynamicPageInfo *) ErrorDynamicPages.items[i])->page_name, page_name) == 0)
-	    return i + ERR_MAX;
-    }
-    return ERR_NONE;
-}
-
-int
-errorReservePageId(const char *page_name)
-{
-    ErrorDynamicPageInfo *info;
-    int id = errorPageId(page_name);
-    if (id == ERR_NONE) {
-	info = errorDynamicPageInfoCreate(ERR_MAX + ErrorDynamicPages.count, page_name);
-	stackPush(&ErrorDynamicPages, info);
-	id = info->id;
-    }
-    return id;
-}
-
-static const char *
-errorPageName(int pageId)
-{
-    if (pageId >= ERR_NONE && pageId < ERR_MAX)		/* common case */
-	return err_type_str[pageId];
-    if (pageId >= ERR_MAX && pageId - ERR_MAX < ErrorDynamicPages.count)
-	return ((ErrorDynamicPageInfo *) ErrorDynamicPages.
-	    items[pageId - ERR_MAX])->page_name;
-    return "ERR_UNKNOWN";	/* should not happen */
-}
-
-/*
- * Function:  errorCon
- *
- * Abstract:  This function creates a ErrorState object.
- */
-ErrorState *
-errorCon(err_type type, http_status status)
-{
-    ErrorState *err;
-    err = cbdataAlloc(ErrorState);
-    err->page_id = type;	/* has to be reset manually if needed */
-    err->type = type;
-    err->httpStatus = status;
-    return err;
-}
-
-/*
- * Function:  errorAppendEntry
- *
- * Arguments: err - This object is destroyed after use in this function.
- *
- * Abstract:  This function generates a error page from the info contained
- *            by 'err' and then stores the text in the specified store
- *            entry.  This function should only be called by ``server
- *            side routines'' which need to communicate errors to the
- *            client side.  It should also be called from client_side.c
- *            because we now support persistent connections, and
- *            cannot assume that we can immediately write to the socket
- *            for an error.
- */
-void
-errorAppendEntry(StoreEntry * entry, ErrorState * err)
-{
-    HttpReply *rep;
-    MemObject *mem = entry->mem_obj;
-    assert(mem != NULL);
-    assert(mem->inmem_hi == 0);
-    if (entry->store_status != STORE_PENDING) {
-	/*
-	 * If the entry is not STORE_PENDING, then no clients
-	 * care about it, and we don't need to generate an
-	 * error message
-	 */
-	assert(EBIT_TEST(entry->flags, ENTRY_ABORTED));
-	assert(mem->nclients == 0);
-	errorStateFree(err);
-	return;
-    }
-    if (err->page_id == TCP_RESET) {
-	if (err->request) {
-	    debug(4, 2) ("RSTing this reply\n");
-	    err->request->flags.reset_tcp = 1;
-	}
-    }
-    storeLockObject(entry);
-    storeBuffer(entry);
-    rep = errorBuildReply(err);
-    /* Add authentication header */
-    /* TODO: alter errorstate to be accel on|off aware. The 0 on the next line
-     * depends on authenticate behaviour: all schemes to date send no extra data
-     * on 407/401 responses, and do not check the accel state on 401/407 responses 
-     */
-    authenticateFixHeader(rep, err->auth_user_request, err->request, 0, 1);
-    httpReplySwapOut(rep, entry);
-    httpReplyAbsorb(mem->reply, rep);
-    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
-    storeBufferFlush(entry);
-    storeComplete(entry);
-    storeNegativeCache(entry);
-    storeReleaseRequest(entry);
-    storeUnlockObject(entry);
-    errorStateFree(err);
-}
-
-/*
- * Function:  errorSend
- *
- * Arguments: err - This object is destroyed after use in this function.
- *
- * Abstract:  This function generates a error page from the info contained
- *            by 'err' and then sends it to the client.
- *            The callback function errorSendComplete() is called after
- *            the page has been written to the client socket (fd).
- *            errorSendComplete() deallocates 'err'.  We need to add
- *            'err' to the cbdata because comm_write() requires it
- *            for all callback data pointers.
- *
- *            Note, normally errorSend() should only be called from
- *            routines in ssl.c and pass.c, where we don't have any
- *            StoreEntry's.  In client_side.c we must allocate a StoreEntry
- *            for errors and use errorAppendEntry() to account for
- *            persistent/pipeline connections.
- */
-void
-errorSend(int fd, ErrorState * err)
-{
-    HttpReply *rep;
-    debug(4, 3) ("errorSend: FD %d, err=%p\n", fd, err);
-    assert(fd >= 0);
-    /*
-     * ugh, this is how we make sure error codes get back to
-     * the client side for logging and error tracking.
-     */
-    if (err->request)
-	err->request->errType = err->type;
-    /* moved in front of errorBuildBuf @?@ */
-    err->flags.flag_cbdata = 1;
-    rep = errorBuildReply(err);
-    comm_write_mbuf(fd, httpReplyPack(rep), errorSendComplete, err);
-    httpReplyDestroy(rep);
-}
-
-/*
- * Function:  errorSendComplete
- *
- * Abstract:  Called by commHandleWrite() after data has been written
- *            to the client socket.
- *
- * Note:      If there is a callback, the callback is responsible for
- *            closeing the FD, otherwise we do it ourseves.
- */
-static void
-errorSendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
-{
-    ErrorState *err = data;
-    debug(4, 3) ("errorSendComplete: FD %d, size=%ld\n", fd, (long int) size);
-    if (errflag != COMM_ERR_CLOSING) {
-	if (err->callback) {
-	    debug(4, 3) ("errorSendComplete: callback\n");
-	    err->callback(fd, err->callback_data, size);
-	} else {
-	    comm_close(fd);
-	    debug(4, 3) ("errorSendComplete: comm_close\n");
-	}
-    }
-    errorStateFree(err);
-}
-
-void
-errorStateFree(ErrorState * err)
-{
-    requestUnlink(err->request);
-    safe_free(err->redirect_url);
-    safe_free(err->url);
-    safe_free(err->host);
-    safe_free(err->dnsserver_msg);
-    safe_free(err->request_hdrs);
-    wordlistDestroy(&err->ftp.server_msg);
-    safe_free(err->ftp.request);
-    safe_free(err->ftp.reply);
-    if (err->auth_user_request)
-	authenticateAuthUserRequestUnlock(err->auth_user_request);
-    err->auth_user_request = NULL;
-    cbdataFree(err);
-}
-
-static int
-errorDump(ErrorState * err, MemBuf * mb)
-{
-    request_t *r = err->request;
-    MemBuf str = MemBufNULL;
-    const char *p = NULL;	/* takes priority over mb if set */
-    memBufReset(&str);
-    /* email subject line */
-    memBufPrintf(&str, "CacheErrorInfo - %s", errorPageName(err->type));
-    memBufPrintf(mb, "?subject=%s", rfc1738_escape_part(str.buf));
-    memBufReset(&str);
-    /* email body */
-    memBufPrintf(&str, "CacheHost: %s\r\n", getMyHostname());
-    /* - Err Msgs */
-    memBufPrintf(&str, "ErrPage: %s\r\n", errorPageName(err->type));
-    if (err->xerrno) {
-	memBufPrintf(&str, "Err: (%d) %s\r\n", err->xerrno, strerror(err->xerrno));
-    } else {
-	memBufPrintf(&str, "Err: [none]\r\n");
-    }
-    if (authenticateAuthUserRequestMessage(err->auth_user_request)) {
-	memBufPrintf(&str, "extAuth ErrMsg: %s\r\n", authenticateAuthUserRequestMessage(err->auth_user_request));
-    }
-    if (err->dnsserver_msg) {
-	memBufPrintf(&str, "DNS Server ErrMsg: %s\r\n", err->dnsserver_msg);
-    }
-    /* - TimeStamp */
-    memBufPrintf(&str, "TimeStamp: %s\r\n\r\n", mkrfc1123(squid_curtime));
-    /* - IP stuff */
-    memBufPrintf(&str, "ClientIP: %s\r\n", inet_ntoa(err->src_addr));
-    if (err->host) {
-	memBufPrintf(&str, "ServerIP: %s\r\n", err->host);
-    }
-    memBufPrintf(&str, "\r\n");
-    /* - HTTP stuff */
-    memBufPrintf(&str, "HTTP Request:\r\n");
-    if (NULL != r) {
-	Packer p;
-	memBufPrintf(&str, "%s %s HTTP/%d.%d\n",
-	    RequestMethodStr[r->method],
-	    strLen(r->urlpath) ? strBuf(r->urlpath) : "/",
-	    r->http_ver.major, r->http_ver.minor);
-	packerToMemInit(&p, &str);
-	httpHeaderPackInto(&r->header, &p);
-	packerClean(&p);
-    } else if (err->request_hdrs) {
-	p = err->request_hdrs;
-    } else {
-	p = "[none]";
-    }
-    memBufPrintf(&str, "\r\n");
-    /* - FTP stuff */
-    if (err->ftp.request) {
-	memBufPrintf(&str, "FTP Request: %s\r\n", err->ftp.request);
-	memBufPrintf(&str, "FTP Reply: %s\r\n", err->ftp.reply);
-	memBufPrintf(&str, "FTP Msg: ");
-	wordlistCat(err->ftp.server_msg, &str);
-	memBufPrintf(&str, "\r\n");
-    }
-    memBufPrintf(&str, "\r\n");
-    memBufPrintf(mb, "&body=%s", rfc1738_escape_part(str.buf));
-    memBufClean(&str);
-    return 0;
-}
-
-#define CVT_BUF_SZ 512
-
-/*
- * B - URL with FTP %2f hack                    x
- * c - Squid error code                         x
- * d - seconds elapsed since request received   x
- * e - errno                                    x
- * E - strerror()                               x
- * f - FTP request line                         x
- * F - FTP reply line                           x
- * g - FTP server message                       x
- * h - cache hostname                           x
- * H - server host name                         x
- * i - client IP address                        x
- * I - server IP address                        x
- * L - HREF link for more info/contact          x
- * M - Request Method                           x
- * m - Error message returned by external Auth. x 
- * p - URL port #                               x
- * P - Protocol                                 x
- * R - Full HTTP Request                        x
- * S - squid signature from ERR_SIGNATURE       x
- * s - caching proxy software with version      x
- * t - local time                               x
- * T - UTC                                      x
- * U - URL without password                     x
- * u - URL with password                        x
- * w - cachemgr email address                   x
- * W - error data (to be included in the mailto links)
- * z - dns server error message                 x
- */
-
-static const char *
-errorConvert(char token, ErrorState * err)
-{
-    request_t *r = err->request;
-    static MemBuf mb = MemBufNULL;
-    const char *p = NULL;	/* takes priority over mb if set */
-    int do_quote = 1;
-
-    memBufReset(&mb);
-    switch (token) {
-    case 'B':
-	p = r ? ftpUrlWith2f(r) : "[no URL]";
-	break;
-    case 'c':
-	p = errorPageName(err->type);
-	break;
-    case 'e':
-	memBufPrintf(&mb, "%d", err->xerrno);
-	break;
-    case 'E':
-	if (err->xerrno)
-	    memBufPrintf(&mb, "(%d) %s", err->xerrno, strerror(err->xerrno));
-	else
-	    memBufPrintf(&mb, "[No Error]");
-	break;
-    case 'f':
-	/* FTP REQUEST LINE */
-	if (err->ftp.request)
-	    p = err->ftp.request;
-	else
-	    p = "nothing";
-	break;
-    case 'F':
-	/* FTP REPLY LINE */
-	if (err->ftp.request)
-	    p = err->ftp.reply;
-	else
-	    p = "nothing";
-	break;
-    case 'g':
-	/* FTP SERVER MESSAGE */
-	wordlistCat(err->ftp.server_msg, &mb);
-	break;
-    case 'h':
-	memBufPrintf(&mb, "%s", getMyHostname());
-	break;
-    case 'H':
-	p = r ? r->host : "[unknown host]";
-	break;
-    case 'i':
-	memBufPrintf(&mb, "%s", inet_ntoa(err->src_addr));
-	break;
-    case 'I':
-	if (err->host) {
-	    memBufPrintf(&mb, "%s", err->host);
-	} else
-	    p = "[unknown]";
-	break;
-    case 'L':
-	if (Config.errHtmlText) {
-	    memBufPrintf(&mb, "%s", Config.errHtmlText);
-	    do_quote = 0;
-	} else
-	    p = "[not available]";
-	break;
-    case 'm':
-	p = authenticateAuthUserRequestMessage(err->auth_user_request) ? authenticateAuthUserRequestMessage(err->auth_user_request) : "[not available]";
-	break;
-    case 'M':
-	p = r ? RequestMethodStr[r->method] : "[unkown method]";
-	break;
-    case 'p':
-	if (r) {
-	    memBufPrintf(&mb, "%d", (int) r->port);
-	} else {
-	    p = "[unknown port]";
-	}
-	break;
-    case 'P':
-	p = r ? ProtocolStr[r->protocol] : "[unkown protocol]";
-	break;
-    case 'R':
-	if (NULL != r) {
-	    Packer p;
-	    memBufPrintf(&mb, "%s %s HTTP/%d.%d\n",
-		RequestMethodStr[r->method],
-		strLen(r->urlpath) ? strBuf(r->urlpath) : "/",
-		r->http_ver.major, r->http_ver.minor);
-	    packerToMemInit(&p, &mb);
-	    httpHeaderPackInto(&r->header, &p);
-	    packerClean(&p);
-	} else if (err->request_hdrs) {
-	    p = err->request_hdrs;
-	} else {
-	    p = "[no request]";
-	}
-	break;
-    case 's':
-	p = full_appname_string;
-	break;
-    case 'S':
-	/* signature may contain %-escapes, recursion */
-	if (err->page_id != ERR_SQUID_SIGNATURE) {
-	    const int saved_id = err->page_id;
-	    MemBuf sign_mb;
-	    err->page_id = ERR_SQUID_SIGNATURE;
-	    sign_mb = errorBuildContent(err);
-	    memBufPrintf(&mb, "%s", sign_mb.buf);
-	    memBufClean(&sign_mb);
-	    err->page_id = saved_id;
-	    do_quote = 0;
-	} else {
-	    /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
-	    p = "[%S]";
-	}
-	break;
-    case 't':
-	memBufPrintf(&mb, "%s", mkhttpdlogtime(&squid_curtime));
-	break;
-    case 'T':
-	memBufPrintf(&mb, "%s", mkrfc1123(squid_curtime));
-	break;
-    case 'U':
-	p = r ? urlCanonicalClean(r) : err->url ? err->url : "[no URL]";
-	break;
-    case 'u':
-	p = r ? urlCanonical(r) : err->url ? err->url : "[no URL]";
-	break;
-    case 'w':
-	if (Config.adminEmail)
-	    memBufPrintf(&mb, "%s", Config.adminEmail);
-	else
-	    p = "[unknown]";
-	break;
-    case 'W':
-	if (Config.adminEmail && Config.onoff.emailErrData)
-	    errorDump(err, &mb);
-	break;
-    case 'z':
-	if (err->dnsserver_msg)
-	    p = err->dnsserver_msg;
-	else
-	    p = "[unknown]";
-	break;
-    case '%':
-	p = "%";
-	break;
-    default:
-	memBufPrintf(&mb, "%%%c", token);
-	break;
-    }
-    if (!p)
-	p = mb.buf;		/* do not use mb after this assignment! */
-    assert(p);
-    debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p);
-    if (do_quote)
-	p = html_quote(p);
-    return p;
-}
-
-/* allocates and initializes an error response */
-HttpReply *
-errorBuildReply(ErrorState * err)
-{
-    HttpReply *rep = httpReplyCreate();
-    const char *name = errorPageName(err->page_id);
-    http_version_t version;
-    /* no LMT for error pages; error pages expire immediately */
-    httpBuildVersion(&version, 1, 0);
-    if (strchr(name, ':')) {
-	/* Redirection */
-	char *quoted_url = rfc1738_escape_part(errorConvert('u', err));
-	httpReplySetHeaders(rep, version, HTTP_MOVED_TEMPORARILY, NULL, "text/html", 0, 0, squid_curtime);
-	httpHeaderPutStrf(&rep->header, HDR_LOCATION, name, quoted_url);
-	httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%d %s\n", err->httpStatus, "Access Denied");
-    } else {
-	MemBuf content = errorBuildContent(err);
-	httpReplySetHeaders(rep, version, err->httpStatus, NULL, "text/html", content.size, 0, squid_curtime);
-	/*
-	 * include some information for downstream caches. Implicit
-	 * replaceable content. This isn't quite sufficient. xerrno is not
-	 * necessarily meaningful to another system, so we really should
-	 * expand it. Additionally, we should identify ourselves. Someone
-	 * might want to know. Someone _will_ want to know OTOH, the first
-	 * X-CACHE-MISS entry should tell us who.
-	 */
-	httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%s %d",
-	    name, err->xerrno);
-	httpBodySet(&rep->body, &content);
-	/* do not memBufClean() the content, it was absorbed by httpBody */
-    }
-    return rep;
-}
-
-static MemBuf
-errorBuildContent(ErrorState * err)
-{
-    MemBuf content;
-    const char *m;
-    const char *p;
-    const char *t;
-    assert(err != NULL);
-    assert(err->page_id > ERR_NONE && err->page_id < error_page_count);
-    memBufDefInit(&content);
-    m = error_text[err->page_id];
-    assert(m);
-    while ((p = strchr(m, '%'))) {
-	memBufAppend(&content, m, p - m);	/* copy */
-	t = errorConvert(*++p, err);	/* convert */
-	memBufPrintf(&content, "%s", t);	/* copy */
-	m = p + 1;		/* advance */
-    }
-    if (*m)
-	memBufPrintf(&content, "%s", m);	/* copy tail */
-    assert(content.size == strlen(content.buf));
-    return content;
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/errorpage.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,731 @@
+
+/*
+ * $Id: errorpage.cc,v 1.1.2.1 2002/10/03 01:04:35 rbcollins Exp $
+ *
+ * DEBUG: section 4     Error Generation
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/*
+ * Abstract:  These routines are used to generate error messages to be
+ *              sent to clients.  The error type is used to select between
+ *              the various message formats. (formats are stored in the
+ *              Config.errorDirectory)
+ */
+
+#include "squid.h"
+#include "authenticate.h"
+
+/* local types */
+
+typedef struct {
+    int id;
+    char *page_name;
+} ErrorDynamicPageInfo;
+
+/* local constant and vars */
+
+/*
+ * note: hard coded error messages are not appended with %S automagically
+ * to give you more control on the format
+ */
+static const struct {
+    int type;			/* and page_id */
+    const char *text;
+} error_hard_text[] = {
+
+    {
+	ERR_SQUID_SIGNATURE,
+	    "\n<BR clear=\"all\">\n"
+	    "<HR noshade size=\"1px\">\n"
+	    "<ADDRESS>\n"
+	    "Generated %T by %h (%s)\n"
+	    "</ADDRESS>\n"
+	    "</BODY></HTML>\n"
+    },
+    {
+	TCP_RESET,
+	    "reset"
+    }
+};
+
+static Stack ErrorDynamicPages;
+
+/* local prototypes */
+
+static const int error_hard_text_count = sizeof(error_hard_text) / sizeof(*error_hard_text);
+static char **error_text = NULL;
+static int error_page_count = 0;
+
+static char *errorTryLoadText(const char *page_name, const char *dir);
+static char *errorLoadText(const char *page_name);
+static const char *errorFindHardText(err_type type);
+static ErrorDynamicPageInfo *errorDynamicPageInfoCreate(int id, const char *page_name);
+static void errorDynamicPageInfoDestroy(ErrorDynamicPageInfo * info);
+static MemBuf errorBuildContent(ErrorState * err);
+static int errorDump(ErrorState * err, MemBuf * mb);
+static const char *errorConvert(char token, ErrorState * err);
+static CWCB errorSendComplete;
+
+
+err_type &operator++ (err_type &anErr)
+{
+    anErr = (err_type)(++(int)anErr);
+}
+/*
+ * Function:  errorInitialize
+ *
+ * Abstract:  This function finds the error messages formats, and stores
+ *            them in error_text[];
+ *
+ * Global effects:
+ *            error_text[] - is modified
+ */
+void
+errorInitialize(void)
+{
+    err_type i;
+    const char *text;
+    error_page_count = ERR_MAX + ErrorDynamicPages.count;
+    error_text = static_cast<char **>(xcalloc(error_page_count, sizeof(char *)));
+    for (i = ERR_NONE, ++i; i < error_page_count; ++i) {
+	safe_free(error_text[i]);
+	/* hard-coded ? */
+	if ((text = errorFindHardText(i)))
+	    error_text[i] = xstrdup(text);
+	else if (i < ERR_MAX) {
+	    /* precompiled ? */
+	    error_text[i] = errorLoadText(err_type_str[i]);
+	} else {
+	    /* dynamic */
+	    ErrorDynamicPageInfo *info = static_cast<ErrorDynamicPageInfo *>(ErrorDynamicPages.items[i - ERR_MAX]);
+	    assert(info && info->id == i && info->page_name);
+	    if (strchr(info->page_name, ':') == NULL) {
+		/* Not on redirected errors... */
+		error_text[i] = errorLoadText(info->page_name);
+	    }
+	}
+    }
+}
+
+void
+errorClean(void)
+{
+    if (error_text) {
+	int i;
+	for (i = ERR_NONE + 1; i < error_page_count; i++)
+	    safe_free(error_text[i]);
+	safe_free(error_text);
+    }
+    while (ErrorDynamicPages.count)
+	errorDynamicPageInfoDestroy(static_cast<ErrorDynamicPageInfo *>(stackPop(&ErrorDynamicPages)));
+    error_page_count = 0;
+}
+
+static const char *
+errorFindHardText(err_type type)
+{
+    int i;
+    for (i = 0; i < error_hard_text_count; i++)
+	if (error_hard_text[i].type == type)
+	    return error_hard_text[i].text;
+    return NULL;
+}
+
+
+static char *
+errorLoadText(const char *page_name)
+{
+    /* test configured location */
+    char *text = errorTryLoadText(page_name, Config.errorDirectory);
+    /* test default location if failed */
+    if (!text && strcmp(Config.errorDirectory, DEFAULT_SQUID_ERROR_DIR))
+	text = errorTryLoadText(page_name, DEFAULT_SQUID_ERROR_DIR);
+    /* giving up if failed */
+    if (!text)
+	fatal("failed to find or read error text file.");
+    return text;
+}
+
+static char *
+errorTryLoadText(const char *page_name, const char *dir)
+{
+    int fd;
+    char path[MAXPATHLEN];
+    struct stat sb;
+    char *text;
+
+    snprintf(path, sizeof(path), "%s/%s", dir, page_name);
+    fd = file_open(path, O_RDONLY | O_TEXT);
+    if (fd < 0 || fstat(fd, &sb) < 0) {
+	debug(4, 0) ("errorTryLoadText: '%s': %s\n", path, xstrerror());
+	if (fd >= 0)
+	    file_close(fd);
+	return NULL;
+    }
+    text = (char *)xcalloc(sb.st_size + 2 + 1, 1);	/* 2 == space for %S */
+    if (FD_READ_METHOD(fd, text, sb.st_size) != sb.st_size) {
+	debug(4, 0) ("errorTryLoadText: failed to fully read: '%s': %s\n",
+	    path, xstrerror());
+	xfree(text);
+	text = NULL;
+    }
+    file_close(fd);
+    if (strstr(text, "%s") == NULL)
+	strcat(text, "%S");	/* add signature */
+    return text;
+}
+
+static ErrorDynamicPageInfo *
+errorDynamicPageInfoCreate(int id, const char *page_name)
+{
+    ErrorDynamicPageInfo *info = static_cast<ErrorDynamicPageInfo *>(xcalloc(1, sizeof(ErrorDynamicPageInfo)));
+    info->id = id;
+    info->page_name = xstrdup(page_name);
+    return info;
+}
+
+static void
+errorDynamicPageInfoDestroy(ErrorDynamicPageInfo * info)
+{
+    assert(info);
+    xfree(info->page_name);
+    xfree(info);
+}
+
+static int
+errorPageId(const char *page_name)
+{
+    int i;
+    for (i = 0; i < ERR_MAX; i++) {
+	if (strcmp(err_type_str[i], page_name) == 0)
+	    return i;
+    }
+    for (i = 0; i < ErrorDynamicPages.count; i++) {
+	if (strcmp(((ErrorDynamicPageInfo *) ErrorDynamicPages.items[i])->page_name, page_name) == 0)
+	    return i + ERR_MAX;
+    }
+    return ERR_NONE;
+}
+
+int
+errorReservePageId(const char *page_name)
+{
+    ErrorDynamicPageInfo *info;
+    int id = errorPageId(page_name);
+    if (id == ERR_NONE) {
+	info = errorDynamicPageInfoCreate(ERR_MAX + ErrorDynamicPages.count, page_name);
+	stackPush(&ErrorDynamicPages, info);
+	id = info->id;
+    }
+    return id;
+}
+
+static const char *
+errorPageName(int pageId)
+{
+    if (pageId >= ERR_NONE && pageId < ERR_MAX)		/* common case */
+	return err_type_str[pageId];
+    if (pageId >= ERR_MAX && pageId - ERR_MAX < ErrorDynamicPages.count)
+	return ((ErrorDynamicPageInfo *) ErrorDynamicPages.
+	    items[pageId - ERR_MAX])->page_name;
+    return "ERR_UNKNOWN";	/* should not happen */
+}
+
+/*
+ * Function:  errorCon
+ *
+ * Abstract:  This function creates a ErrorState object.
+ */
+ErrorState *
+errorCon(err_type type, http_status status)
+{
+    ErrorState *err;
+    err = cbdataAlloc(ErrorState);
+    err->page_id = type;	/* has to be reset manually if needed */
+    err->type = type;
+    err->httpStatus = status;
+    return err;
+}
+
+/*
+ * Function:  errorAppendEntry
+ *
+ * Arguments: err - This object is destroyed after use in this function.
+ *
+ * Abstract:  This function generates a error page from the info contained
+ *            by 'err' and then stores the text in the specified store
+ *            entry.  This function should only be called by ``server
+ *            side routines'' which need to communicate errors to the
+ *            client side.  It should also be called from client_side.c
+ *            because we now support persistent connections, and
+ *            cannot assume that we can immediately write to the socket
+ *            for an error.
+ */
+void
+errorAppendEntry(StoreEntry * entry, ErrorState * err)
+{
+    HttpReply *rep;
+    MemObject *mem = entry->mem_obj;
+    assert(mem != NULL);
+    assert(mem->inmem_hi == 0);
+    if (entry->store_status != STORE_PENDING) {
+	/*
+	 * If the entry is not STORE_PENDING, then no clients
+	 * care about it, and we don't need to generate an
+	 * error message
+	 */
+	assert(EBIT_TEST(entry->flags, ENTRY_ABORTED));
+	assert(mem->nclients == 0);
+	errorStateFree(err);
+	return;
+    }
+    if (err->page_id == TCP_RESET) {
+	if (err->request) {
+	    debug(4, 2) ("RSTing this reply\n");
+	    err->request->flags.reset_tcp = 1;
+	}
+    }
+    storeLockObject(entry);
+    storeBuffer(entry);
+    rep = errorBuildReply(err);
+    /* Add authentication header */
+    /* TODO: alter errorstate to be accel on|off aware. The 0 on the next line
+     * depends on authenticate behaviour: all schemes to date send no extra data
+     * on 407/401 responses, and do not check the accel state on 401/407 responses 
+     */
+    authenticateFixHeader(rep, err->auth_user_request, err->request, 0, 1);
+    httpReplySwapOut(rep, entry);
+    httpReplyAbsorb(mem->reply, rep);
+    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+    storeBufferFlush(entry);
+    storeComplete(entry);
+    storeNegativeCache(entry);
+    storeReleaseRequest(entry);
+    storeUnlockObject(entry);
+    errorStateFree(err);
+}
+
+/*
+ * Function:  errorSend
+ *
+ * Arguments: err - This object is destroyed after use in this function.
+ *
+ * Abstract:  This function generates a error page from the info contained
+ *            by 'err' and then sends it to the client.
+ *            The callback function errorSendComplete() is called after
+ *            the page has been written to the client socket (fd).
+ *            errorSendComplete() deallocates 'err'.  We need to add
+ *            'err' to the cbdata because comm_write() requires it
+ *            for all callback data pointers.
+ *
+ *            Note, normally errorSend() should only be called from
+ *            routines in ssl.c and pass.c, where we don't have any
+ *            StoreEntry's.  In client_side.c we must allocate a StoreEntry
+ *            for errors and use errorAppendEntry() to account for
+ *            persistent/pipeline connections.
+ */
+void
+errorSend(int fd, ErrorState * err)
+{
+    HttpReply *rep;
+    debug(4, 3) ("errorSend: FD %d, err=%p\n", fd, err);
+    assert(fd >= 0);
+    /*
+     * ugh, this is how we make sure error codes get back to
+     * the client side for logging and error tracking.
+     */
+    if (err->request)
+	err->request->errType = err->type;
+    /* moved in front of errorBuildBuf @?@ */
+    err->flags.flag_cbdata = 1;
+    rep = errorBuildReply(err);
+    comm_write_mbuf(fd, httpReplyPack(rep), errorSendComplete, err);
+    httpReplyDestroy(rep);
+}
+
+/*
+ * Function:  errorSendComplete
+ *
+ * Abstract:  Called by commHandleWrite() after data has been written
+ *            to the client socket.
+ *
+ * Note:      If there is a callback, the callback is responsible for
+ *            closeing the FD, otherwise we do it ourseves.
+ */
+static void
+errorSendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
+{
+    ErrorState *err = static_cast<ErrorState *>(data);
+    debug(4, 3) ("errorSendComplete: FD %d, size=%ld\n", fd, (long int) size);
+    if (errflag != COMM_ERR_CLOSING) {
+	if (err->callback) {
+	    debug(4, 3) ("errorSendComplete: callback\n");
+	    err->callback(fd, err->callback_data, size);
+	} else {
+	    comm_close(fd);
+	    debug(4, 3) ("errorSendComplete: comm_close\n");
+	}
+    }
+    errorStateFree(err);
+}
+
+void
+errorStateFree(ErrorState * err)
+{
+    requestUnlink(err->request);
+    safe_free(err->redirect_url);
+    safe_free(err->url);
+    safe_free(err->host);
+    safe_free(err->dnsserver_msg);
+    safe_free(err->request_hdrs);
+    wordlistDestroy(&err->ftp.server_msg);
+    safe_free(err->ftp.request);
+    safe_free(err->ftp.reply);
+    if (err->auth_user_request)
+	authenticateAuthUserRequestUnlock(err->auth_user_request);
+    err->auth_user_request = NULL;
+    cbdataFree(err);
+}
+
+static int
+errorDump(ErrorState * err, MemBuf * mb)
+{
+    request_t *r = err->request;
+    MemBuf str = MemBufNULL;
+    const char *p = NULL;	/* takes priority over mb if set */
+    memBufReset(&str);
+    /* email subject line */
+    memBufPrintf(&str, "CacheErrorInfo - %s", errorPageName(err->type));
+    memBufPrintf(mb, "?subject=%s", rfc1738_escape_part(str.buf));
+    memBufReset(&str);
+    /* email body */
+    memBufPrintf(&str, "CacheHost: %s\r\n", getMyHostname());
+    /* - Err Msgs */
+    memBufPrintf(&str, "ErrPage: %s\r\n", errorPageName(err->type));
+    if (err->xerrno) {
+	memBufPrintf(&str, "Err: (%d) %s\r\n", err->xerrno, strerror(err->xerrno));
+    } else {
+	memBufPrintf(&str, "Err: [none]\r\n");
+    }
+    if (authenticateAuthUserRequestMessage(err->auth_user_request)) {
+	memBufPrintf(&str, "extAuth ErrMsg: %s\r\n", authenticateAuthUserRequestMessage(err->auth_user_request));
+    }
+    if (err->dnsserver_msg) {
+	memBufPrintf(&str, "DNS Server ErrMsg: %s\r\n", err->dnsserver_msg);
+    }
+    /* - TimeStamp */
+    memBufPrintf(&str, "TimeStamp: %s\r\n\r\n", mkrfc1123(squid_curtime));
+    /* - IP stuff */
+    memBufPrintf(&str, "ClientIP: %s\r\n", inet_ntoa(err->src_addr));
+    if (err->host) {
+	memBufPrintf(&str, "ServerIP: %s\r\n", err->host);
+    }
+    memBufPrintf(&str, "\r\n");
+    /* - HTTP stuff */
+    memBufPrintf(&str, "HTTP Request:\r\n");
+    if (NULL != r) {
+	Packer p;
+	memBufPrintf(&str, "%s %s HTTP/%d.%d\n",
+	    RequestMethodStr[r->method],
+	    strLen(r->urlpath) ? strBuf(r->urlpath) : "/",
+	    r->http_ver.major, r->http_ver.minor);
+	packerToMemInit(&p, &str);
+	httpHeaderPackInto(&r->header, &p);
+	packerClean(&p);
+    } else if (err->request_hdrs) {
+	p = err->request_hdrs;
+    } else {
+	p = "[none]";
+    }
+    memBufPrintf(&str, "\r\n");
+    /* - FTP stuff */
+    if (err->ftp.request) {
+	memBufPrintf(&str, "FTP Request: %s\r\n", err->ftp.request);
+	memBufPrintf(&str, "FTP Reply: %s\r\n", err->ftp.reply);
+	memBufPrintf(&str, "FTP Msg: ");
+	wordlistCat(err->ftp.server_msg, &str);
+	memBufPrintf(&str, "\r\n");
+    }
+    memBufPrintf(&str, "\r\n");
+    memBufPrintf(mb, "&body=%s", rfc1738_escape_part(str.buf));
+    memBufClean(&str);
+    return 0;
+}
+
+#define CVT_BUF_SZ 512
+
+/*
+ * B - URL with FTP %2f hack                    x
+ * c - Squid error code                         x
+ * d - seconds elapsed since request received   x
+ * e - errno                                    x
+ * E - strerror()                               x
+ * f - FTP request line                         x
+ * F - FTP reply line                           x
+ * g - FTP server message                       x
+ * h - cache hostname                           x
+ * H - server host name                         x
+ * i - client IP address                        x
+ * I - server IP address                        x
+ * L - HREF link for more info/contact          x
+ * M - Request Method                           x
+ * m - Error message returned by external Auth. x 
+ * p - URL port #                               x
+ * P - Protocol                                 x
+ * R - Full HTTP Request                        x
+ * S - squid signature from ERR_SIGNATURE       x
+ * s - caching proxy software with version      x
+ * t - local time                               x
+ * T - UTC                                      x
+ * U - URL without password                     x
+ * u - URL with password                        x
+ * w - cachemgr email address                   x
+ * W - error data (to be included in the mailto links)
+ * z - dns server error message                 x
+ */
+
+static const char *
+errorConvert(char token, ErrorState * err)
+{
+    request_t *r = err->request;
+    static MemBuf mb = MemBufNULL;
+    const char *p = NULL;	/* takes priority over mb if set */
+    int do_quote = 1;
+
+    memBufReset(&mb);
+    switch (token) {
+    case 'B':
+	p = r ? ftpUrlWith2f(r) : "[no URL]";
+	break;
+    case 'c':
+	p = errorPageName(err->type);
+	break;
+    case 'e':
+	memBufPrintf(&mb, "%d", err->xerrno);
+	break;
+    case 'E':
+	if (err->xerrno)
+	    memBufPrintf(&mb, "(%d) %s", err->xerrno, strerror(err->xerrno));
+	else
+	    memBufPrintf(&mb, "[No Error]");
+	break;
+    case 'f':
+	/* FTP REQUEST LINE */
+	if (err->ftp.request)
+	    p = err->ftp.request;
+	else
+	    p = "nothing";
+	break;
+    case 'F':
+	/* FTP REPLY LINE */
+	if (err->ftp.request)
+	    p = err->ftp.reply;
+	else
+	    p = "nothing";
+	break;
+    case 'g':
+	/* FTP SERVER MESSAGE */
+	wordlistCat(err->ftp.server_msg, &mb);
+	break;
+    case 'h':
+	memBufPrintf(&mb, "%s", getMyHostname());
+	break;
+    case 'H':
+	p = r ? r->host : "[unknown host]";
+	break;
+    case 'i':
+	memBufPrintf(&mb, "%s", inet_ntoa(err->src_addr));
+	break;
+    case 'I':
+	if (err->host) {
+	    memBufPrintf(&mb, "%s", err->host);
+	} else
+	    p = "[unknown]";
+	break;
+    case 'L':
+	if (Config.errHtmlText) {
+	    memBufPrintf(&mb, "%s", Config.errHtmlText);
+	    do_quote = 0;
+	} else
+	    p = "[not available]";
+	break;
+    case 'm':
+	p = authenticateAuthUserRequestMessage(err->auth_user_request) ? authenticateAuthUserRequestMessage(err->auth_user_request) : "[not available]";
+	break;
+    case 'M':
+	p = r ? RequestMethodStr[r->method] : "[unkown method]";
+	break;
+    case 'p':
+	if (r) {
+	    memBufPrintf(&mb, "%d", (int) r->port);
+	} else {
+	    p = "[unknown port]";
+	}
+	break;
+    case 'P':
+	p = r ? ProtocolStr[r->protocol] : "[unkown protocol]";
+	break;
+    case 'R':
+	if (NULL != r) {
+	    Packer p;
+	    memBufPrintf(&mb, "%s %s HTTP/%d.%d\n",
+		RequestMethodStr[r->method],
+		strLen(r->urlpath) ? strBuf(r->urlpath) : "/",
+		r->http_ver.major, r->http_ver.minor);
+	    packerToMemInit(&p, &mb);
+	    httpHeaderPackInto(&r->header, &p);
+	    packerClean(&p);
+	} else if (err->request_hdrs) {
+	    p = err->request_hdrs;
+	} else {
+	    p = "[no request]";
+	}
+	break;
+    case 's':
+	p = full_appname_string;
+	break;
+    case 'S':
+	/* signature may contain %-escapes, recursion */
+	if (err->page_id != ERR_SQUID_SIGNATURE) {
+	    const int saved_id = err->page_id;
+	    MemBuf sign_mb;
+	    err->page_id = ERR_SQUID_SIGNATURE;
+	    sign_mb = errorBuildContent(err);
+	    memBufPrintf(&mb, "%s", sign_mb.buf);
+	    memBufClean(&sign_mb);
+	    err->page_id = saved_id;
+	    do_quote = 0;
+	} else {
+	    /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
+	    p = "[%S]";
+	}
+	break;
+    case 't':
+	memBufPrintf(&mb, "%s", mkhttpdlogtime(&squid_curtime));
+	break;
+    case 'T':
+	memBufPrintf(&mb, "%s", mkrfc1123(squid_curtime));
+	break;
+    case 'U':
+	p = r ? urlCanonicalClean(r) : err->url ? err->url : "[no URL]";
+	break;
+    case 'u':
+	p = r ? urlCanonical(r) : err->url ? err->url : "[no URL]";
+	break;
+    case 'w':
+	if (Config.adminEmail)
+	    memBufPrintf(&mb, "%s", Config.adminEmail);
+	else
+	    p = "[unknown]";
+	break;
+    case 'W':
+	if (Config.adminEmail && Config.onoff.emailErrData)
+	    errorDump(err, &mb);
+	break;
+    case 'z':
+	if (err->dnsserver_msg)
+	    p = err->dnsserver_msg;
+	else
+	    p = "[unknown]";
+	break;
+    case '%':
+	p = "%";
+	break;
+    default:
+	memBufPrintf(&mb, "%%%c", token);
+	break;
+    }
+    if (!p)
+	p = mb.buf;		/* do not use mb after this assignment! */
+    assert(p);
+    debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p);
+    if (do_quote)
+	p = html_quote(p);
+    return p;
+}
+
+/* allocates and initializes an error response */
+HttpReply *
+errorBuildReply(ErrorState * err)
+{
+    HttpReply *rep = httpReplyCreate();
+    const char *name = errorPageName(err->page_id);
+    http_version_t version;
+    /* no LMT for error pages; error pages expire immediately */
+    httpBuildVersion(&version, 1, 0);
+    if (strchr(name, ':')) {
+	/* Redirection */
+	char *quoted_url = rfc1738_escape_part(errorConvert('u', err));
+	httpReplySetHeaders(rep, version, HTTP_MOVED_TEMPORARILY, NULL, "text/html", 0, 0, squid_curtime);
+	httpHeaderPutStrf(&rep->header, HDR_LOCATION, name, quoted_url);
+	httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%d %s\n", err->httpStatus, "Access Denied");
+    } else {
+	MemBuf content = errorBuildContent(err);
+	httpReplySetHeaders(rep, version, err->httpStatus, NULL, "text/html", content.size, 0, squid_curtime);
+	/*
+	 * include some information for downstream caches. Implicit
+	 * replaceable content. This isn't quite sufficient. xerrno is not
+	 * necessarily meaningful to another system, so we really should
+	 * expand it. Additionally, we should identify ourselves. Someone
+	 * might want to know. Someone _will_ want to know OTOH, the first
+	 * X-CACHE-MISS entry should tell us who.
+	 */
+	httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%s %d",
+	    name, err->xerrno);
+	httpBodySet(&rep->body, &content);
+	/* do not memBufClean() the content, it was absorbed by httpBody */
+    }
+    return rep;
+}
+
+static MemBuf
+errorBuildContent(ErrorState * err)
+{
+    MemBuf content;
+    const char *m;
+    const char *p;
+    const char *t;
+    assert(err != NULL);
+    assert(err->page_id > ERR_NONE && err->page_id < error_page_count);
+    memBufDefInit(&content);
+    m = error_text[err->page_id];
+    assert(m);
+    while ((p = strchr(m, '%'))) {
+	memBufAppend(&content, m, p - m);	/* copy */
+	t = errorConvert(*++p, err);	/* convert */
+	memBufPrintf(&content, "%s", t);	/* copy */
+	m = p + 1;		/* advance */
+    }
+    if (*m)
+	memBufPrintf(&content, "%s", m);	/* copy tail */
+    assert(content.size == strlen(content.buf));
+    return content;
+}
Index: squid/src/external_acl.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/external_acl.c,v
retrieving revision 1.11
retrieving revision 1.11.4.1
diff -u -r1.11 -r1.11.4.1
--- squid/src/external_acl.c	29 Sep 2002 19:33:25 -0000	1.11
+++ squid/src/external_acl.c	3 Oct 2002 01:04:35 -0000	1.11.4.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: external_acl.c,v 1.11 2002/09/29 19:33:25 squidadm Exp $
+ * $Id: external_acl.c,v 1.11.4.1 2002/10/03 01:04:35 rbcollins Exp $
  *
  * DEBUG: section 82    External ACL
  * AUTHOR: Henrik Nordstrom, MARA Systems AB
@@ -41,6 +41,7 @@
  */
 
 #include "squid.h"
+#include "authenticate.h"
 
 #ifndef DEFAULT_EXTERNAL_ACL_TTL
 #define DEFAULT_EXTERNAL_ACL_TTL 1 * 60 * 60
@@ -569,7 +570,7 @@
     else
 	return 0;
 }
-
+ 
 static void
 free_external_acl_entry(void *data)
 {
--- squid/src/http.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,1113 +0,0 @@
-
-/*
- * $Id: http.c,v 1.25 2002/09/24 10:59:15 rbcollins Exp $
- *
- * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
- * AUTHOR: Harvest Derived
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-/*
- * Anonymizing patch by lutz@as-node.jena.thur.de
- * have a look into http-anon.c to get more informations.
- */
-
-#include "squid.h"
-
-static const char *const crlf = "\r\n";
-
-static CWCB httpSendComplete;
-static CWCB httpSendRequestEntity;
-
-static PF httpReadReply;
-static void httpSendRequest(HttpStateData *);
-static PF httpStateFree;
-static PF httpTimeout;
-static void httpCacheNegatively(StoreEntry *);
-static void httpMakePrivate(StoreEntry *);
-static void httpMakePublic(StoreEntry *);
-static int httpCachableReply(HttpStateData *);
-static void httpMaybeRemovePublic(StoreEntry *, http_status);
-
-static void
-httpStateFree(int fd, void *data)
-{
-    HttpStateData *httpState = data;
-#if DELAY_POOLS
-    delayClearNoDelay(fd);
-#endif
-    if (httpState == NULL)
-	return;
-    storeUnlockObject(httpState->entry);
-    if (httpState->reply_hdr) {
-	memFree(httpState->reply_hdr, MEM_8K_BUF);
-	httpState->reply_hdr = NULL;
-    }
-    requestUnlink(httpState->request);
-    requestUnlink(httpState->orig_request);
-    httpState->request = NULL;
-    httpState->orig_request = NULL;
-    cbdataFree(httpState);
-}
-
-int
-httpCachable(method_t method)
-{
-    /* GET and HEAD are cachable. Others are not. */
-    if (method != METHOD_GET && method != METHOD_HEAD)
-	return 0;
-    /* else cachable */
-    return 1;
-}
-
-static void
-httpTimeout(int fd, void *data)
-{
-    HttpStateData *httpState = data;
-    StoreEntry *entry = httpState->entry;
-    debug(11, 4) ("httpTimeout: FD %d: '%s'\n", fd, storeUrl(entry));
-    if (entry->store_status == STORE_PENDING) {
-	if (entry->mem_obj->inmem_hi == 0) {
-	    fwdFail(httpState->fwd,
-		errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT));
-	}
-    }
-    comm_close(fd);
-}
-
-/* This object can be cached for a long time */
-static void
-httpMakePublic(StoreEntry * entry)
-{
-    if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
-	storeSetPublicKey(entry);
-}
-
-/* This object should never be cached at all */
-static void
-httpMakePrivate(StoreEntry * entry)
-{
-    storeExpireNow(entry);
-    storeReleaseRequest(entry);	/* delete object when not used */
-    /* storeReleaseRequest clears ENTRY_CACHABLE flag */
-}
-
-/* This object may be negatively cached */
-static void
-httpCacheNegatively(StoreEntry * entry)
-{
-    storeNegativeCache(entry);
-    if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
-	storeSetPublicKey(entry);
-}
-
-static void
-httpMaybeRemovePublic(StoreEntry * e, http_status status)
-{
-    int remove = 0;
-    int forbidden = 0;
-    StoreEntry *pe;
-    if (!EBIT_TEST(e->flags, KEY_PRIVATE))
-	return;
-    switch (status) {
-    case HTTP_OK:
-    case HTTP_NON_AUTHORITATIVE_INFORMATION:
-    case HTTP_MULTIPLE_CHOICES:
-    case HTTP_MOVED_PERMANENTLY:
-    case HTTP_MOVED_TEMPORARILY:
-    case HTTP_GONE:
-    case HTTP_NOT_FOUND:
-	remove = 1;
-	break;
-    case HTTP_FORBIDDEN:
-    case HTTP_METHOD_NOT_ALLOWED:
-	forbidden = 1;
-	break;
-#if WORK_IN_PROGRESS
-    case HTTP_UNAUTHORIZED:
-	forbidden = 1;
-	break;
-#endif
-    default:
-#if QUESTIONABLE
-	/*
-	 * Any 2xx response should eject previously cached entities...
-	 */
-	if (status >= 200 && status < 300)
-	    remove = 1;
-#endif
-	break;
-    }
-    if (!remove && !forbidden)
-	return;
-    assert(e->mem_obj);
-    if (e->mem_obj->request)
-	pe = storeGetPublicByRequest(e->mem_obj->request);
-    else
-	pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method);
-    if (pe != NULL) {
-	assert(e != pe);
-	storeRelease(pe);
-    }
-    /*
-     * Also remove any cached HEAD response in case the object has
-     * changed.
-     */
-    if (e->mem_obj->request)
-	pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD);
-    else
-	pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD);
-    if (pe != NULL) {
-	assert(e != pe);
-	storeRelease(pe);
-    }
-    if (forbidden)
-	return;
-    switch (e->mem_obj->method) {
-    case METHOD_PUT:
-    case METHOD_DELETE:
-    case METHOD_PROPPATCH:
-    case METHOD_MKCOL:
-    case METHOD_MOVE:
-    case METHOD_BMOVE:
-    case METHOD_BDELETE:
-	/*
-	 * Remove any cached GET object if it is beleived that the
-	 * object may have changed as a result of other methods
-	 */
-	if (e->mem_obj->request)
-	    pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_GET);
-	else
-	    pe = storeGetPublic(e->mem_obj->url, METHOD_GET);
-	if (pe != NULL) {
-	    assert(e != pe);
-	    storeRelease(pe);
-	}
-	break;
-    default:
-	/* Keep GCC happy. The methods above are all mutating HTTP methods 
-	 */
-	break;
-    }
-}
-
-static int
-httpCachableReply(HttpStateData * httpState)
-{
-    HttpReply *rep = httpState->entry->mem_obj->reply;
-    HttpHeader *hdr = &rep->header;
-    const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
-    const char *v;
-    if (EBIT_TEST(cc_mask, CC_PRIVATE))
-	return 0;
-    if (EBIT_TEST(cc_mask, CC_NO_CACHE))
-	return 0;
-    if (EBIT_TEST(cc_mask, CC_NO_STORE))
-	return 0;
-    if (httpState->request->flags.auth) {
-	/*
-	 * Responses to requests with authorization may be cached
-	 * only if a Cache-Control: public reply header is present.
-	 * RFC 2068, sec 14.9.4
-	 */
-	if (!EBIT_TEST(cc_mask, CC_PUBLIC))
-	    return 0;
-    }
-    /* Pragma: no-cache in _replies_ is not documented in HTTP,
-     * but servers like "Active Imaging Webcast/2.0" sure do use it */
-    if (httpHeaderHas(hdr, HDR_PRAGMA)) {
-	String s = httpHeaderGetList(hdr, HDR_PRAGMA);
-	const int no_cache = strListIsMember(&s, "no-cache", ',');
-	stringClean(&s);
-	if (no_cache)
-	    return 0;
-    }
-    /*
-     * The "multipart/x-mixed-replace" content type is used for
-     * continuous push replies.  These are generally dynamic and
-     * probably should not be cachable
-     */
-    if ((v = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE)))
-	if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
-	    return 0;
-    switch (httpState->entry->mem_obj->reply->sline.status) {
-	/* Responses that are cacheable */
-    case HTTP_OK:
-    case HTTP_NON_AUTHORITATIVE_INFORMATION:
-    case HTTP_MULTIPLE_CHOICES:
-    case HTTP_MOVED_PERMANENTLY:
-    case HTTP_GONE:
-	/*
-	 * Don't cache objects that need to be refreshed on next request,
-	 * unless we know how to refresh it.
-	 */
-	if (!refreshIsCachable(httpState->entry))
-	    return 0;
-	/* don't cache objects from peers w/o LMT, Date, or Expires */
-	/* check that is it enough to check headers @?@ */
-	if (rep->date > -1)
-	    return 1;
-	else if (rep->last_modified > -1)
-	    return 1;
-	else if (!httpState->_peer)
-	    return 1;
-	/* @?@ (here and 302): invalid expires header compiles to squid_curtime */
-	else if (rep->expires > -1)
-	    return 1;
-	else
-	    return 0;
-	/* NOTREACHED */
-	break;
-	/* Responses that only are cacheable if the server says so */
-    case HTTP_MOVED_TEMPORARILY:
-	if (rep->expires > -1)
-	    return 1;
-	else
-	    return 0;
-	/* NOTREACHED */
-	break;
-	/* Errors can be negatively cached */
-    case HTTP_NO_CONTENT:
-    case HTTP_USE_PROXY:
-    case HTTP_BAD_REQUEST:
-    case HTTP_FORBIDDEN:
-    case HTTP_NOT_FOUND:
-    case HTTP_METHOD_NOT_ALLOWED:
-    case HTTP_REQUEST_URI_TOO_LARGE:
-    case HTTP_INTERNAL_SERVER_ERROR:
-    case HTTP_NOT_IMPLEMENTED:
-    case HTTP_BAD_GATEWAY:
-    case HTTP_SERVICE_UNAVAILABLE:
-    case HTTP_GATEWAY_TIMEOUT:
-	return -1;
-	/* NOTREACHED */
-	break;
-	/* Some responses can never be cached */
-    case HTTP_PARTIAL_CONTENT:	/* Not yet supported */
-    case HTTP_SEE_OTHER:
-    case HTTP_NOT_MODIFIED:
-    case HTTP_UNAUTHORIZED:
-    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
-    case HTTP_INVALID_HEADER:	/* Squid header parsing error */
-    default:			/* Unknown status code */
-	return 0;
-	/* NOTREACHED */
-	break;
-    }
-    /* NOTREACHED */
-}
-
-/*
- * For Vary, store the relevant request headers as 
- * virtual headers in the reply
- * Returns false if the variance cannot be stored
- */
-const char *
-httpMakeVaryMark(request_t * request, HttpReply * reply)
-{
-    String vary, hdr;
-    const char *pos = NULL;
-    const char *item;
-    const char *value;
-    int ilen;
-    static String vstr =
-    {0, 0, NULL};
-
-    stringClean(&vstr);
-    vary = httpHeaderGetList(&reply->header, HDR_VARY);
-    while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
-	char *name = xmalloc(ilen + 1);
-	xstrncpy(name, item, ilen + 1);
-	Tolower(name);
-	strListAdd(&vstr, name, ',');
-	hdr = httpHeaderGetByName(&request->header, name);
-	safe_free(name);
-	value = strBuf(hdr);
-	if (value) {
-	    value = rfc1738_escape_part(value);
-	    stringAppend(&vstr, "=\"", 2);
-	    stringAppend(&vstr, value, strlen(value));
-	    stringAppend(&vstr, "\"", 1);
-	}
-	stringClean(&hdr);
-    }
-    stringClean(&vary);
-#if X_ACCELERATOR_VARY
-    vary = httpHeaderGetList(&reply->header, HDR_X_ACCELERATOR_VARY);
-    while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
-	char *name = xmalloc(ilen + 1);
-	xstrncpy(name, item, ilen + 1);
-	Tolower(name);
-	strListAdd(&vstr, name, ',');
-	hdr = httpHeaderGetByName(&request->header, name);
-	safe_free(name);
-	value = strBuf(hdr);
-	if (value) {
-	    value = rfc1738_escape_part(value);
-	    stringAppend(&vstr, "=\"", 2);
-	    stringAppend(&vstr, value, strlen(value));
-	    stringAppend(&vstr, "\"", 1);
-	}
-	stringClean(&hdr);
-    }
-    stringClean(&vary);
-#endif
-    debug(11, 3) ("httpMakeVaryMark: %s\n", strBuf(vstr));
-    return strBuf(vstr);
-}
-
-/* rewrite this later using new interfaces @?@ */
-void
-httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
-{
-    char *t = NULL;
-    StoreEntry *entry = httpState->entry;
-    int room;
-    size_t hdr_len;
-    HttpReply *reply = entry->mem_obj->reply;
-    Ctx ctx;
-    debug(11, 3) ("httpProcessReplyHeader: key '%s'\n",
-	storeKeyText(entry->hash.key));
-    if (httpState->reply_hdr == NULL)
-	httpState->reply_hdr = memAllocate(MEM_8K_BUF);
-    assert(httpState->reply_hdr_state == 0);
-    hdr_len = httpState->reply_hdr_size;
-    room = 8191 - hdr_len;
-    xmemcpy(httpState->reply_hdr + hdr_len, buf, room < size ? room : size);
-    hdr_len += room < size ? room : size;
-    httpState->reply_hdr[hdr_len] = '\0';
-    httpState->reply_hdr_size = hdr_len;
-    if (hdr_len > 4 && strncmp(httpState->reply_hdr, "HTTP/", 5)) {
-	debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr);
-	httpState->reply_hdr_state += 2;
-	reply->sline.status = HTTP_INVALID_HEADER;
-	return;
-    }
-    t = httpState->reply_hdr + hdr_len;
-    /* headers can be incomplete only if object still arriving */
-    if (!httpState->eof) {
-	size_t k = headersEnd(httpState->reply_hdr, 8192);
-	if (0 == k)
-	    return;		/* headers not complete */
-	t = httpState->reply_hdr + k;
-    }
-    *t = '\0';
-    httpState->reply_hdr_state++;
-    assert(httpState->reply_hdr_state == 1);
-    ctx = ctx_enter(entry->mem_obj->url);
-    httpState->reply_hdr_state++;
-    debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
-	httpState->reply_hdr);
-    /* Parse headers into reply structure */
-    /* what happens if we fail to parse here? */
-    httpReplyParse(reply, httpState->reply_hdr, hdr_len);
-    storeTimestampsSet(entry);
-    /* Check if object is cacheable or not based on reply code */
-    debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status);
-    if (neighbors_do_private_keys)
-	httpMaybeRemovePublic(entry, reply->sline.status);
-    switch (httpCachableReply(httpState)) {
-    case 1:
-	if (httpHeaderHas(&reply->header, HDR_VARY)
-#if X_ACCELERATOR_VARY
-	    || httpHeaderHas(&reply->header, HDR_X_ACCELERATOR_VARY)
-#endif
-	    ) {
-	    const char *vary = httpMakeVaryMark(httpState->orig_request, reply);
-	    if (vary) {
-		entry->mem_obj->vary_headers = xstrdup(vary);
-		/* Kill the old base object if a change in variance is detected */
-		httpMakePublic(entry);
-	    } else {
-		httpMakePrivate(entry);
-	    }
-	} else {
-	    httpMakePublic(entry);
-	}
-	break;
-    case 0:
-	httpMakePrivate(entry);
-	break;
-    case -1:
-	httpCacheNegatively(entry);
-	break;
-    default:
-	assert(0);
-	break;
-    }
-    if (reply->cache_control) {
-	if (EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE))
-	    EBIT_SET(entry->flags, ENTRY_REVALIDATE);
-	else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE))
-	    EBIT_SET(entry->flags, ENTRY_REVALIDATE);
-    }
-    if (httpState->flags.keepalive)
-	if (httpState->_peer)
-	    httpState->_peer->stats.n_keepalives_sent++;
-    if (reply->keep_alive)
-	if (httpState->_peer)
-	    httpState->_peer->stats.n_keepalives_recv++;
-    if (reply->date > -1 && !httpState->_peer) {
-	int skew = abs(reply->date - squid_curtime);
-	if (skew > 86400)
-	    debug(11, 3) ("%s's clock is skewed by %d seconds!\n",
-		httpState->request->host, skew);
-    }
-    ctx_exit(ctx);
-#if HEADERS_LOG
-    headersLog(1, 0, httpState->request->method, reply);
-#endif
-}
-
-static int
-httpPconnTransferDone(HttpStateData * httpState)
-{
-    /* return 1 if we got the last of the data on a persistent connection */
-    MemObject *mem = httpState->entry->mem_obj;
-    HttpReply *reply = mem->reply;
-    int clen;
-    debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
-    /*
-     * If we didn't send a keep-alive request header, then this
-     * can not be a persistent connection.
-     */
-    if (!httpState->flags.keepalive)
-	return 0;
-    /*
-     * What does the reply have to say about keep-alive?
-     */
-    /*
-     * XXX BUG?
-     * If the origin server (HTTP/1.0) does not send a keep-alive
-     * header, but keeps the connection open anyway, what happens?
-     * We'll return here and http.c waits for an EOF before changing
-     * store_status to STORE_OK.   Combine this with ENTRY_FWD_HDR_WAIT
-     * and an error status code, and we might have to wait until
-     * the server times out the socket.
-     */
-    if (!reply->keep_alive)
-	return 0;
-    debug(11, 5) ("httpPconnTransferDone: content_length=%d\n",
-	reply->content_length);
-    /* If we haven't seen the end of reply headers, we are not done */
-    if (httpState->reply_hdr_state < 2)
-	return 0;
-    clen = httpReplyBodySize(httpState->request->method, reply);
-    /* If there is no message body, we can be persistent */
-    if (0 == clen)
-	return 1;
-    /* If the body size is unknown we must wait for EOF */
-    if (clen < 0)
-	return 0;
-    /* If the body size is known, we must wait until we've gotten all of it.  */
-    if (mem->inmem_hi < reply->content_length + reply->hdr_sz)
-	return 0;
-    /* We got it all */
-    return 1;
-}
-
-/* This will be called when data is ready to be read from fd.  Read until
- * error or connection closed. */
-/* XXX this function is too long! */
-static void
-httpReadReply(int fd, void *data)
-{
-    HttpStateData *httpState = data;
-    LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF);
-    StoreEntry *entry = httpState->entry;
-    const request_t *request = httpState->request;
-    int len;
-    int bin;
-    int clen;
-    size_t read_sz;
-#if DELAY_POOLS
-    delay_id delay_id;
-
-    /* special "if" only for http (for nodelay proxy conns) */
-    if (delayIsNoDelay(fd))
-	delay_id = 0;
-    else
-	delay_id = delayMostBytesAllowed(entry->mem_obj);
-#endif
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-	comm_close(fd);
-	return;
-    }
-    /* check if we want to defer reading */
-    errno = 0;
-    read_sz = SQUID_TCP_SO_RCVBUF;
-#if DELAY_POOLS
-    read_sz = delayBytesWanted(delay_id, 1, read_sz);
-#endif
-    statCounter.syscalls.sock.reads++;
-    len = FD_READ_METHOD(fd, buf, read_sz);
-    debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, len);
-    if (len > 0) {
-	fd_bytes(fd, len, FD_READ);
-#if DELAY_POOLS
-	delayBytesIn(delay_id, len);
-#endif
-	kb_incr(&statCounter.server.all.kbytes_in, len);
-	kb_incr(&statCounter.server.http.kbytes_in, len);
-	commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
-	IOStats.Http.reads++;
-	for (clen = len - 1, bin = 0; clen; bin++)
-	    clen >>= 1;
-	IOStats.Http.read_hist[bin]++;
-    }
-    if (!httpState->reply_hdr && len > 0) {
-	/* Skip whitespace */
-	while (len > 0 && xisspace(*buf))
-	    xmemmove(buf, buf + 1, len--);
-	if (len == 0) {
-	    /* Continue to read... */
-	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
-	    return;
-	}
-    }
-    if (len < 0) {
-	debug(50, 2) ("httpReadReply: FD %d: read failure: %s.\n",
-	    fd, xstrerror());
-	if (ignoreErrno(errno)) {
-	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
-	} else if (entry->mem_obj->inmem_hi == 0) {
-	    ErrorState *err;
-	    err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR);
-	    err->request = requestLink((request_t *) request);
-	    err->xerrno = errno;
-	    fwdFail(httpState->fwd, err);
-	    comm_close(fd);
-	} else {
-	    comm_close(fd);
-	}
-    } else if (len == 0 && entry->mem_obj->inmem_hi == 0) {
-	ErrorState *err;
-	err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
-	err->xerrno = errno;
-	err->request = requestLink((request_t *) request);
-	fwdFail(httpState->fwd, err);
-	httpState->eof = 1;
-	comm_close(fd);
-    } else if (len == 0) {
-	/* Connection closed; retrieval done. */
-	httpState->eof = 1;
-	if (httpState->reply_hdr_state < 2)
-	    /*
-	     * Yes Henrik, there is a point to doing this.  When we
-	     * called httpProcessReplyHeader() before, we didn't find
-	     * the end of headers, but now we are definately at EOF, so
-	     * we want to process the reply headers.
-	     */
-	    httpProcessReplyHeader(httpState, buf, len);
-	fwdComplete(httpState->fwd);
-	comm_close(fd);
-    } else {
-	if (httpState->reply_hdr_state < 2) {
-	    httpProcessReplyHeader(httpState, buf, len);
-	    if (httpState->reply_hdr_state == 2) {
-		http_status s = entry->mem_obj->reply->sline.status;
-#if WIP_FWD_LOG
-		fwdStatus(httpState->fwd, s);
-#endif
-		/*
-		 * If its not a reply that we will re-forward, then
-		 * allow the client to get it.
-		 */
-		if (!fwdReforwardableStatus(s))
-		    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
-	    }
-	}
-	storeAppend(entry, buf, len);
-	if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-	    /*
-	     * the above storeAppend() call could ABORT this entry,
-	     * in that case, the server FD should already be closed.
-	     * there's nothing for us to do.
-	     */
-	    (void) 0;
-	} else if (httpPconnTransferDone(httpState)) {
-	    /* yes we have to clear all these! */
-	    commSetDefer(fd, NULL, NULL);
-	    commSetTimeout(fd, -1, NULL, NULL);
-	    commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
-#if DELAY_POOLS
-	    delayClearNoDelay(fd);
-#endif
-	    comm_remove_close_handler(fd, httpStateFree, httpState);
-	    fwdUnregister(fd, httpState->fwd);
-	    pconnPush(fd, request->host, request->port);
-	    fwdComplete(httpState->fwd);
-	    httpState->fd = -1;
-	    httpStateFree(fd, httpState);
-	} else {
-	    /* Wait for EOF condition */
-	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
-	}
-    }
-}
-
-/* This will be called when request write is complete. Schedule read of
- * reply. */
-static void
-httpSendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
-{
-    HttpStateData *httpState = data;
-    StoreEntry *entry = httpState->entry;
-    ErrorState *err;
-    debug(11, 5) ("httpSendComplete: FD %d: size %d: errflag %d.\n",
-	fd, (int) size, errflag);
-#if URL_CHECKSUM_DEBUG
-    assert(entry->mem_obj->chksum == url_checksum(entry->mem_obj->url));
-#endif
-    if (size > 0) {
-	fd_bytes(fd, size, FD_WRITE);
-	kb_incr(&statCounter.server.all.kbytes_out, size);
-	kb_incr(&statCounter.server.http.kbytes_out, size);
-    }
-    if (errflag == COMM_ERR_CLOSING)
-	return;
-    if (errflag) {
-	err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
-	err->xerrno = errno;
-	err->request = requestLink(httpState->orig_request);
-	errorAppendEntry(entry, err);
-	comm_close(fd);
-	return;
-    } else {
-	/* Schedule read reply. */
-	commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
-	/*
-	 * Set the read timeout here because it hasn't been set yet.
-	 * We only set the read timeout after the request has been
-	 * fully written to the server-side.  If we start the timeout
-	 * after connection establishment, then we are likely to hit
-	 * the timeout for POST/PUT requests that have very large
-	 * request bodies.
-	 */
-	commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
-	commSetDefer(fd, fwdCheckDeferRead, entry);
-    }
-}
-
-/*
- * build request headers and append them to a given MemBuf 
- * used by httpBuildRequestPrefix()
- * note: calls httpHeaderInit(), the caller is responsible for Clean()-ing
- */
-void
-httpBuildRequestHeader(request_t * request,
-    request_t * orig_request,
-    StoreEntry * entry,
-    HttpHeader * hdr_out,
-    int cfd,
-    http_state_flags flags)
-{
-    /* building buffer for complex strings */
-#define BBUF_SZ (MAX_URL+32)
-    LOCAL_ARRAY(char, bbuf, BBUF_SZ);
-    String strConnection = StringNull;
-    const HttpHeader *hdr_in = &orig_request->header;
-    const HttpHeaderEntry *e;
-    String strFwd;
-    HttpHeaderPos pos = HttpHeaderInitPos;
-    httpHeaderInit(hdr_out, hoRequest);
-    /* append our IMS header */
-    if (request->lastmod > -1 && request->method == METHOD_GET)
-	httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, request->lastmod);
-
-    strConnection = httpHeaderGetList(hdr_in, HDR_CONNECTION);
-    while ((e = httpHeaderGetEntry(hdr_in, &pos))) {
-	debug(11, 5) ("httpBuildRequestHeader: %s: %s\n",
-	    strBuf(e->name), strBuf(e->value));
-	if (!httpRequestHdrAllowed(e, &strConnection)) {
-	    debug(11, 2) ("'%s' header denied by anonymize_headers configuration\n",
-		strBuf(e->name));
-	    continue;
-	}
-	switch (e->id) {
-	case HDR_PROXY_AUTHORIZATION:
-	    /* Only pass on proxy authentication to peers for which
-	     * authentication forwarding is explicitly enabled
-	     */
-	    if (request->flags.proxying && orig_request->peer_login &&
-		strcmp(orig_request->peer_login, "PASS") == 0) {
-		httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
-	    }
-	    break;
-	case HDR_AUTHORIZATION:
-	    /* Pass on WWW authentication even if used locally. If this is
-	     * not wanted in an accelerator then the header can be removed
-	     * using the anonymization functions
-	     */
-	    httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
-	    /* XXX Some accelerators might want to strip the header
-	     * and regard the reply as cacheable, but authentication
-	     * is not normally enabled for accelerators without reading
-	     * the code, so there is not much use in adding logics here
-	     * without first defining the concept of having authentication
-	     * in the accelerator...
-	     */
-	    break;
-	case HDR_HOST:
-	    /*
-	     * Normally Squid does not copy the Host: header from
-	     * a client request into the forwarded request headers.
-	     * However, there is one case when we do: If the URL
-	     * went through our redirector and the admin configured
-	     * 'redir_rewrites_host' to be off.
-	     */
-	    if (request->flags.redirected)
-		if (!Config.onoff.redir_rewrites_host)
-		    httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
-	    break;
-	case HDR_IF_MODIFIED_SINCE:
-	    /* append unless we added our own;
-	     * note: at most one client's ims header can pass through */
-	    if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE))
-		httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
-	    break;
-	case HDR_MAX_FORWARDS:
-	    if (orig_request->method == METHOD_TRACE) {
-		/* sacrificing efficiency over clarity, etc. */
-		const int hops = httpHeaderGetInt(hdr_in, HDR_MAX_FORWARDS);
-		if (hops > 0)
-		    httpHeaderPutInt(hdr_out, HDR_MAX_FORWARDS, hops - 1);
-	    }
-	    break;
-	case HDR_VIA:
-	    /* If Via is disabled then forward any received header as-is */
-	    if (!Config.onoff.via)
-		httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
-	    break;
-	case HDR_PROXY_CONNECTION:
-	case HDR_CONNECTION:
-	case HDR_X_FORWARDED_FOR:
-	case HDR_CACHE_CONTROL:
-	    /* append these after the loop if needed */
-	    break;
-	default:
-	    /* pass on all other header fields */
-	    httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
-	}
-    }
-
-    /* append Via */
-    if (Config.onoff.via) {
-	String strVia = httpHeaderGetList(hdr_in, HDR_VIA);
-	snprintf(bbuf, BBUF_SZ, "%d.%d %s",
-	    orig_request->http_ver.major,
-	    orig_request->http_ver.minor, ThisCache);
-	strListAdd(&strVia, bbuf, ',');
-	httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia));
-	stringClean(&strVia);
-    }
-    /* append X-Forwarded-For */
-    strFwd = httpHeaderGetList(hdr_in, HDR_X_FORWARDED_FOR);
-    strListAdd(&strFwd, (cfd < 0 ? "unknown" : fd_table[cfd].ipaddr), ',');
-    httpHeaderPutStr(hdr_out, HDR_X_FORWARDED_FOR, strBuf(strFwd));
-    stringClean(&strFwd);
-
-    /* append Host if not there already */
-    if (!httpHeaderHas(hdr_out, HDR_HOST)) {
-	/* use port# only if not default */
-	if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
-	    httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
-	} else {
-	    httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
-		orig_request->host, (int) orig_request->port);
-	}
-    }
-    /* append Authorization if known in URL, not in header and going direct */
-    if (!httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) {
-	if (!request->flags.proxying && *request->login) {
-	    httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
-		base64_encode(request->login));
-	}
-    }
-    /* append Proxy-Authorization if configured for peer, and proxying */
-    if (request->flags.proxying && orig_request->peer_login &&
-	!httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION) &&
-	strcmp(orig_request->peer_login, "PASS") != 0) {
-	if (*orig_request->peer_login == '*') {
-	    /* Special mode, to pass the username to the upstream cache */
-	    char loginbuf[256];
-	    const char *username = "-";
-	    if (orig_request->auth_user_request)
-		username = authenticateUserRequestUsername(orig_request->auth_user_request);
-	    snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
-	    httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
-		base64_encode(loginbuf));
-	} else {
-	    httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
-		base64_encode(orig_request->peer_login));
-	}
-    }
-    /* append Cache-Control, add max-age if not there already */
-    {
-	HttpHdrCc *cc = httpHeaderGetCc(hdr_in);
-	if (!cc)
-	    cc = httpHdrCcCreate();
-	if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
-	    const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request);
-	    httpHdrCcSetMaxAge(cc, getMaxAge(url));
-	    if (strLen(request->urlpath))
-		assert(strstr(url, strBuf(request->urlpath)));
-	}
-	if (flags.only_if_cached)
-	    EBIT_SET(cc->mask, CC_ONLY_IF_CACHED);
-	httpHeaderPutCc(hdr_out, cc);
-	httpHdrCcDestroy(cc);
-    }
-    /* maybe append Connection: keep-alive */
-    if (flags.keepalive) {
-	if (flags.proxying) {
-	    httpHeaderPutStr(hdr_out, HDR_PROXY_CONNECTION, "keep-alive");
-	} else {
-	    httpHeaderPutStr(hdr_out, HDR_CONNECTION, "keep-alive");
-	}
-    }
-    /* Now mangle the headers. */
-    httpHdrMangleList(hdr_out, request);
-    stringClean(&strConnection);
-}
-
-/* build request prefix and append it to a given MemBuf; 
- * return the length of the prefix */
-mb_size_t
-httpBuildRequestPrefix(request_t * request,
-    request_t * orig_request,
-    StoreEntry * entry,
-    MemBuf * mb,
-    int cfd,
-    http_state_flags flags)
-{
-    const int offset = mb->size;
-    memBufPrintf(mb, "%s %s HTTP/1.0\r\n",
-	RequestMethodStr[request->method],
-	strLen(request->urlpath) ? strBuf(request->urlpath) : "/");
-    /* build and pack headers */
-    {
-	HttpHeader hdr;
-	Packer p;
-	httpBuildRequestHeader(request, orig_request, entry, &hdr, cfd, flags);
-	packerToMemInit(&p, mb);
-	httpHeaderPackInto(&hdr, &p);
-	httpHeaderClean(&hdr);
-	packerClean(&p);
-    }
-    /* append header terminator */
-    memBufAppend(mb, crlf, 2);
-    return mb->size - offset;
-}
-/* This will be called when connect completes. Write request. */
-static void
-httpSendRequest(HttpStateData * httpState)
-{
-    MemBuf mb;
-    request_t *req = httpState->request;
-    StoreEntry *entry = httpState->entry;
-    int cfd;
-    peer *p = httpState->_peer;
-    CWCB *sendHeaderDone;
-
-    debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", httpState->fd, httpState);
-
-    if (httpState->orig_request->body_connection)
-	sendHeaderDone = httpSendRequestEntity;
-    else
-	sendHeaderDone = httpSendComplete;
-
-    if (!opt_forwarded_for)
-	cfd = -1;
-    else if (entry->mem_obj == NULL)
-	cfd = -1;
-    else
-	cfd = entry->mem_obj->fd;
-    assert(-1 == cfd || FD_SOCKET == fd_table[cfd].type);
-    if (p != NULL)
-	httpState->flags.proxying = 1;
-    else
-	httpState->flags.proxying = 0;
-    /*
-     * Is keep-alive okay for all request methods?
-     */
-    if (!Config.onoff.server_pconns)
-	httpState->flags.keepalive = 0;
-    else if (p == NULL)
-	httpState->flags.keepalive = 1;
-    else if (p->stats.n_keepalives_sent < 10)
-	httpState->flags.keepalive = 1;
-    else if ((double) p->stats.n_keepalives_recv / (double) p->stats.n_keepalives_sent > 0.50)
-	httpState->flags.keepalive = 1;
-    if (httpState->_peer)
-	if (neighborType(httpState->_peer, httpState->request) == PEER_SIBLING &&
-	    !httpState->_peer->options.allow_miss)
-	    httpState->flags.only_if_cached = 1;
-    memBufDefInit(&mb);
-    httpBuildRequestPrefix(req,
-	httpState->orig_request,
-	entry,
-	&mb,
-	cfd,
-	httpState->flags);
-    debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", httpState->fd, mb.buf);
-    comm_write_mbuf(httpState->fd, mb, sendHeaderDone, httpState);
-}
-
-void
-httpStart(FwdState * fwd)
-{
-    int fd = fwd->server_fd;
-    HttpStateData *httpState;
-    request_t *proxy_req;
-    request_t *orig_req = fwd->request;
-    debug(11, 3) ("httpStart: \"%s %s\"\n",
-	RequestMethodStr[orig_req->method],
-	storeUrl(fwd->entry));
-    httpState = cbdataAlloc(HttpStateData);
-    storeLockObject(fwd->entry);
-    httpState->fwd = fwd;
-    httpState->entry = fwd->entry;
-    httpState->fd = fd;
-    if (fwd->servers)
-	httpState->_peer = fwd->servers->_peer;		/* might be NULL */
-    if (httpState->_peer) {
-	proxy_req = requestCreate(orig_req->method,
-	    PROTO_NONE, storeUrl(httpState->entry));
-	xstrncpy(proxy_req->host, httpState->_peer->host, SQUIDHOSTNAMELEN);
-	proxy_req->port = httpState->_peer->http_port;
-	proxy_req->flags = orig_req->flags;
-	proxy_req->lastmod = orig_req->lastmod;
-	httpState->request = requestLink(proxy_req);
-	httpState->orig_request = requestLink(orig_req);
-	proxy_req->flags.proxying = 1;
-	/*
-	 * This NEIGHBOR_PROXY_ONLY check probably shouldn't be here.
-	 * We might end up getting the object from somewhere else if,
-	 * for example, the request to this neighbor fails.
-	 */
-	if (httpState->_peer->options.proxy_only)
-	    storeReleaseRequest(httpState->entry);
-#if DELAY_POOLS
-	assert(delayIsNoDelay(fd) == 0);
-	if (httpState->_peer->options.no_delay)
-	    delaySetNoDelay(fd);
-#endif
-    } else {
-	httpState->request = requestLink(orig_req);
-	httpState->orig_request = requestLink(orig_req);
-    }
-    /*
-     * register the handler to free HTTP state data when the FD closes
-     */
-    comm_add_close_handler(fd, httpStateFree, httpState);
-    statCounter.server.all.requests++;
-    statCounter.server.http.requests++;
-    httpSendRequest(httpState);
-    /*
-     * We used to set the read timeout here, but not any more.
-     * Now its set in httpSendComplete() after the full request,
-     * including request body, has been written to the server.
-     */
-}
-
-static void
-httpSendRequestEntityDone(int fd, void *data)
-{
-    HttpStateData *httpState = data;
-    aclCheck_t ch;
-    debug(11, 5) ("httpSendRequestEntityDone: FD %d\n",
-	fd);
-    memset(&ch, '\0', sizeof(ch));
-    ch.request = httpState->request;
-    if (!Config.accessList.brokenPosts) {
-	debug(11, 5) ("httpSendRequestEntityDone: No brokenPosts list\n");
-	httpSendComplete(fd, NULL, 0, 0, data);
-    } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) {
-	debug(11, 5) ("httpSendRequestEntityDone: didn't match brokenPosts\n");
-	httpSendComplete(fd, NULL, 0, 0, data);
-    } else {
-	debug(11, 2) ("httpSendRequestEntityDone: matched brokenPosts\n");
-	comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL);
-    }
-}
-
-static void
-httpRequestBodyHandler(char *buf, size_t size, void *data)
-{
-    HttpStateData *httpState = (HttpStateData *) data;
-    if (size > 0) {
-	comm_write(httpState->fd, buf, size, httpSendRequestEntity, data, memFree8K);
-    } else if (size == 0) {
-	/* End of body */
-	memFree8K(buf);
-	httpSendRequestEntityDone(httpState->fd, data);
-    } else {
-	/* Failed to get whole body, probably aborted */
-	memFree8K(buf);
-	httpSendComplete(httpState->fd, NULL, 0, COMM_ERR_CLOSING, data);
-    }
-}
-
-static void
-httpSendRequestEntity(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
-{
-    HttpStateData *httpState = data;
-    StoreEntry *entry = httpState->entry;
-    ErrorState *err;
-    debug(11, 5) ("httpSendRequestEntity: FD %d: size %d: errflag %d.\n",
-	fd, (int) size, errflag);
-    if (size > 0) {
-	fd_bytes(fd, size, FD_WRITE);
-	kb_incr(&statCounter.server.all.kbytes_out, size);
-	kb_incr(&statCounter.server.http.kbytes_out, size);
-    }
-    if (errflag == COMM_ERR_CLOSING)
-	return;
-    if (errflag) {
-	err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
-	err->xerrno = errno;
-	err->request = requestLink(httpState->orig_request);
-	errorAppendEntry(entry, err);
-	comm_close(fd);
-	return;
-    }
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-	comm_close(fd);
-	return;
-    }
-    clientReadBody(httpState->orig_request, memAllocate(MEM_8K_BUF), 8192, httpRequestBodyHandler, httpState);
-}
-
-void
-httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor)
-{
-    version->major = major;
-    version->minor = minor;
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/http.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,1114 @@
+
+/*
+ * $Id: http.cc,v 1.1.2.1 2002/10/03 01:04:35 rbcollins Exp $
+ *
+ * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/*
+ * Anonymizing patch by lutz@as-node.jena.thur.de
+ * have a look into http-anon.c to get more informations.
+ */
+
+#include "squid.h"
+#include "authenticate.h"
+
+static const char *const crlf = "\r\n";
+
+static CWCB httpSendComplete;
+static CWCB httpSendRequestEntity;
+
+static PF httpReadReply;
+static void httpSendRequest(HttpStateData *);
+static PF httpStateFree;
+static PF httpTimeout;
+static void httpCacheNegatively(StoreEntry *);
+static void httpMakePrivate(StoreEntry *);
+static void httpMakePublic(StoreEntry *);
+static int httpCachableReply(HttpStateData *);
+static void httpMaybeRemovePublic(StoreEntry *, http_status);
+
+static void
+httpStateFree(int fd, void *data)
+{
+    HttpStateData *httpState = static_cast<HttpStateData *>(data);
+#if DELAY_POOLS
+    delayClearNoDelay(fd);
+#endif
+    if (httpState == NULL)
+	return;
+    storeUnlockObject(httpState->entry);
+    if (httpState->reply_hdr) {
+	memFree(httpState->reply_hdr, MEM_8K_BUF);
+	httpState->reply_hdr = NULL;
+    }
+    requestUnlink(httpState->request);
+    requestUnlink(httpState->orig_request);
+    httpState->request = NULL;
+    httpState->orig_request = NULL;
+    cbdataFree(httpState);
+}
+
+int
+httpCachable(method_t method)
+{
+    /* GET and HEAD are cachable. Others are not. */
+    if (method != METHOD_GET && method != METHOD_HEAD)
+	return 0;
+    /* else cachable */
+    return 1;
+}
+
+static void
+httpTimeout(int fd, void *data)
+{
+    HttpStateData *httpState = static_cast<HttpStateData *>(data);
+    StoreEntry *entry = httpState->entry;
+    debug(11, 4) ("httpTimeout: FD %d: '%s'\n", fd, storeUrl(entry));
+    if (entry->store_status == STORE_PENDING) {
+	if (entry->mem_obj->inmem_hi == 0) {
+	    fwdFail(httpState->fwd,
+		errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT));
+	}
+    }
+    comm_close(fd);
+}
+
+/* This object can be cached for a long time */
+static void
+httpMakePublic(StoreEntry * entry)
+{
+    if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
+	storeSetPublicKey(entry);
+}
+
+/* This object should never be cached at all */
+static void
+httpMakePrivate(StoreEntry * entry)
+{
+    storeExpireNow(entry);
+    storeReleaseRequest(entry);	/* delete object when not used */
+    /* storeReleaseRequest clears ENTRY_CACHABLE flag */
+}
+
+/* This object may be negatively cached */
+static void
+httpCacheNegatively(StoreEntry * entry)
+{
+    storeNegativeCache(entry);
+    if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
+	storeSetPublicKey(entry);
+}
+
+static void
+httpMaybeRemovePublic(StoreEntry * e, http_status status)
+{
+    int remove = 0;
+    int forbidden = 0;
+    StoreEntry *pe;
+    if (!EBIT_TEST(e->flags, KEY_PRIVATE))
+	return;
+    switch (status) {
+    case HTTP_OK:
+    case HTTP_NON_AUTHORITATIVE_INFORMATION:
+    case HTTP_MULTIPLE_CHOICES:
+    case HTTP_MOVED_PERMANENTLY:
+    case HTTP_MOVED_TEMPORARILY:
+    case HTTP_GONE:
+    case HTTP_NOT_FOUND:
+	remove = 1;
+	break;
+    case HTTP_FORBIDDEN:
+    case HTTP_METHOD_NOT_ALLOWED:
+	forbidden = 1;
+	break;
+#if WORK_IN_PROGRESS
+    case HTTP_UNAUTHORIZED:
+	forbidden = 1;
+	break;
+#endif
+    default:
+#if QUESTIONABLE
+	/*
+	 * Any 2xx response should eject previously cached entities...
+	 */
+	if (status >= 200 && status < 300)
+	    remove = 1;
+#endif
+	break;
+    }
+    if (!remove && !forbidden)
+	return;
+    assert(e->mem_obj);
+    if (e->mem_obj->request)
+	pe = storeGetPublicByRequest(e->mem_obj->request);
+    else
+	pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method);
+    if (pe != NULL) {
+	assert(e != pe);
+	storeRelease(pe);
+    }
+    /*
+     * Also remove any cached HEAD response in case the object has
+     * changed.
+     */
+    if (e->mem_obj->request)
+	pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD);
+    else
+	pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD);
+    if (pe != NULL) {
+	assert(e != pe);
+	storeRelease(pe);
+    }
+    if (forbidden)
+	return;
+    switch (e->mem_obj->method) {
+    case METHOD_PUT:
+    case METHOD_DELETE:
+    case METHOD_PROPPATCH:
+    case METHOD_MKCOL:
+    case METHOD_MOVE:
+    case METHOD_BMOVE:
+    case METHOD_BDELETE:
+	/*
+	 * Remove any cached GET object if it is beleived that the
+	 * object may have changed as a result of other methods
+	 */
+	if (e->mem_obj->request)
+	    pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_GET);
+	else
+	    pe = storeGetPublic(e->mem_obj->url, METHOD_GET);
+	if (pe != NULL) {
+	    assert(e != pe);
+	    storeRelease(pe);
+	}
+	break;
+    default:
+	/* Keep GCC happy. The methods above are all mutating HTTP methods 
+	 */
+	break;
+    }
+}
+
+static int
+httpCachableReply(HttpStateData * httpState)
+{
+    HttpReply *rep = httpState->entry->mem_obj->reply;
+    HttpHeader *hdr = &rep->header;
+    const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
+    const char *v;
+    if (EBIT_TEST(cc_mask, CC_PRIVATE))
+	return 0;
+    if (EBIT_TEST(cc_mask, CC_NO_CACHE))
+	return 0;
+    if (EBIT_TEST(cc_mask, CC_NO_STORE))
+	return 0;
+    if (httpState->request->flags.auth) {
+	/*
+	 * Responses to requests with authorization may be cached
+	 * only if a Cache-Control: public reply header is present.
+	 * RFC 2068, sec 14.9.4
+	 */
+	if (!EBIT_TEST(cc_mask, CC_PUBLIC))
+	    return 0;
+    }
+    /* Pragma: no-cache in _replies_ is not documented in HTTP,
+     * but servers like "Active Imaging Webcast/2.0" sure do use it */
+    if (httpHeaderHas(hdr, HDR_PRAGMA)) {
+	String s = httpHeaderGetList(hdr, HDR_PRAGMA);
+	const int no_cache = strListIsMember(&s, "no-cache", ',');
+	stringClean(&s);
+	if (no_cache)
+	    return 0;
+    }
+    /*
+     * The "multipart/x-mixed-replace" content type is used for
+     * continuous push replies.  These are generally dynamic and
+     * probably should not be cachable
+     */
+    if ((v = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE)))
+	if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
+	    return 0;
+    switch (httpState->entry->mem_obj->reply->sline.status) {
+	/* Responses that are cacheable */
+    case HTTP_OK:
+    case HTTP_NON_AUTHORITATIVE_INFORMATION:
+    case HTTP_MULTIPLE_CHOICES:
+    case HTTP_MOVED_PERMANENTLY:
+    case HTTP_GONE:
+	/*
+	 * Don't cache objects that need to be refreshed on next request,
+	 * unless we know how to refresh it.
+	 */
+	if (!refreshIsCachable(httpState->entry))
+	    return 0;
+	/* don't cache objects from peers w/o LMT, Date, or Expires */
+	/* check that is it enough to check headers @?@ */
+	if (rep->date > -1)
+	    return 1;
+	else if (rep->last_modified > -1)
+	    return 1;
+	else if (!httpState->_peer)
+	    return 1;
+	/* @?@ (here and 302): invalid expires header compiles to squid_curtime */
+	else if (rep->expires > -1)
+	    return 1;
+	else
+	    return 0;
+	/* NOTREACHED */
+	break;
+	/* Responses that only are cacheable if the server says so */
+    case HTTP_MOVED_TEMPORARILY:
+	if (rep->expires > -1)
+	    return 1;
+	else
+	    return 0;
+	/* NOTREACHED */
+	break;
+	/* Errors can be negatively cached */
+    case HTTP_NO_CONTENT:
+    case HTTP_USE_PROXY:
+    case HTTP_BAD_REQUEST:
+    case HTTP_FORBIDDEN:
+    case HTTP_NOT_FOUND:
+    case HTTP_METHOD_NOT_ALLOWED:
+    case HTTP_REQUEST_URI_TOO_LARGE:
+    case HTTP_INTERNAL_SERVER_ERROR:
+    case HTTP_NOT_IMPLEMENTED:
+    case HTTP_BAD_GATEWAY:
+    case HTTP_SERVICE_UNAVAILABLE:
+    case HTTP_GATEWAY_TIMEOUT:
+	return -1;
+	/* NOTREACHED */
+	break;
+	/* Some responses can never be cached */
+    case HTTP_PARTIAL_CONTENT:	/* Not yet supported */
+    case HTTP_SEE_OTHER:
+    case HTTP_NOT_MODIFIED:
+    case HTTP_UNAUTHORIZED:
+    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
+    case HTTP_INVALID_HEADER:	/* Squid header parsing error */
+    default:			/* Unknown status code */
+	return 0;
+	/* NOTREACHED */
+	break;
+    }
+    /* NOTREACHED */
+}
+
+/*
+ * For Vary, store the relevant request headers as 
+ * virtual headers in the reply
+ * Returns false if the variance cannot be stored
+ */
+const char *
+httpMakeVaryMark(request_t * request, HttpReply * reply)
+{
+    String vary, hdr;
+    const char *pos = NULL;
+    const char *item;
+    const char *value;
+    int ilen;
+    static String vstr =
+    {0, 0, NULL};
+
+    stringClean(&vstr);
+    vary = httpHeaderGetList(&reply->header, HDR_VARY);
+    while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
+	char *name = (char *)xmalloc(ilen + 1);
+	xstrncpy(name, item, ilen + 1);
+	Tolower(name);
+	strListAdd(&vstr, name, ',');
+	hdr = httpHeaderGetByName(&request->header, name);
+	safe_free(name);
+	value = strBuf(hdr);
+	if (value) {
+	    value = rfc1738_escape_part(value);
+	    stringAppend(&vstr, "=\"", 2);
+	    stringAppend(&vstr, value, strlen(value));
+	    stringAppend(&vstr, "\"", 1);
+	}
+	stringClean(&hdr);
+    }
+    stringClean(&vary);
+#if X_ACCELERATOR_VARY
+    vary = httpHeaderGetList(&reply->header, HDR_X_ACCELERATOR_VARY);
+    while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
+	char *name = xmalloc(ilen + 1);
+	xstrncpy(name, item, ilen + 1);
+	Tolower(name);
+	strListAdd(&vstr, name, ',');
+	hdr = httpHeaderGetByName(&request->header, name);
+	safe_free(name);
+	value = strBuf(hdr);
+	if (value) {
+	    value = rfc1738_escape_part(value);
+	    stringAppend(&vstr, "=\"", 2);
+	    stringAppend(&vstr, value, strlen(value));
+	    stringAppend(&vstr, "\"", 1);
+	}
+	stringClean(&hdr);
+    }
+    stringClean(&vary);
+#endif
+    debug(11, 3) ("httpMakeVaryMark: %s\n", strBuf(vstr));
+    return strBuf(vstr);
+}
+
+/* rewrite this later using new interfaces @?@ */
+void
+httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
+{
+    char *t = NULL;
+    StoreEntry *entry = httpState->entry;
+    int room;
+    size_t hdr_len;
+    HttpReply *reply = entry->mem_obj->reply;
+    Ctx ctx;
+    debug(11, 3) ("httpProcessReplyHeader: key '%s'\n",
+	storeKeyText((const cache_key *)(entry->hash.key)));
+    if (httpState->reply_hdr == NULL)
+	httpState->reply_hdr = (char *)memAllocate(MEM_8K_BUF);
+    assert(httpState->reply_hdr_state == 0);
+    hdr_len = httpState->reply_hdr_size;
+    room = 8191 - hdr_len;
+    xmemcpy(httpState->reply_hdr + hdr_len, buf, room < size ? room : size);
+    hdr_len += room < size ? room : size;
+    httpState->reply_hdr[hdr_len] = '\0';
+    httpState->reply_hdr_size = hdr_len;
+    if (hdr_len > 4 && strncmp(httpState->reply_hdr, "HTTP/", 5)) {
+	debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr);
+	httpState->reply_hdr_state += 2;
+	reply->sline.status = HTTP_INVALID_HEADER;
+	return;
+    }
+    t = httpState->reply_hdr + hdr_len;
+    /* headers can be incomplete only if object still arriving */
+    if (!httpState->eof) {
+	size_t k = headersEnd(httpState->reply_hdr, 8192);
+	if (0 == k)
+	    return;		/* headers not complete */
+	t = httpState->reply_hdr + k;
+    }
+    *t = '\0';
+    httpState->reply_hdr_state++;
+    assert(httpState->reply_hdr_state == 1);
+    ctx = ctx_enter(entry->mem_obj->url);
+    httpState->reply_hdr_state++;
+    debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
+	httpState->reply_hdr);
+    /* Parse headers into reply structure */
+    /* what happens if we fail to parse here? */
+    httpReplyParse(reply, httpState->reply_hdr, hdr_len);
+    storeTimestampsSet(entry);
+    /* Check if object is cacheable or not based on reply code */
+    debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status);
+    if (neighbors_do_private_keys)
+	httpMaybeRemovePublic(entry, reply->sline.status);
+    switch (httpCachableReply(httpState)) {
+    case 1:
+	if (httpHeaderHas(&reply->header, HDR_VARY)
+#if X_ACCELERATOR_VARY
+	    || httpHeaderHas(&reply->header, HDR_X_ACCELERATOR_VARY)
+#endif
+	    ) {
+	    const char *vary = httpMakeVaryMark(httpState->orig_request, reply);
+	    if (vary) {
+		entry->mem_obj->vary_headers = xstrdup(vary);
+		/* Kill the old base object if a change in variance is detected */
+		httpMakePublic(entry);
+	    } else {
+		httpMakePrivate(entry);
+	    }
+	} else {
+	    httpMakePublic(entry);
+	}
+	break;
+    case 0:
+	httpMakePrivate(entry);
+	break;
+    case -1:
+	httpCacheNegatively(entry);
+	break;
+    default:
+	assert(0);
+	break;
+    }
+    if (reply->cache_control) {
+	if (EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE))
+	    EBIT_SET(entry->flags, ENTRY_REVALIDATE);
+	else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE))
+	    EBIT_SET(entry->flags, ENTRY_REVALIDATE);
+    }
+    if (httpState->flags.keepalive)
+	if (httpState->_peer)
+	    httpState->_peer->stats.n_keepalives_sent++;
+    if (reply->keep_alive)
+	if (httpState->_peer)
+	    httpState->_peer->stats.n_keepalives_recv++;
+    if (reply->date > -1 && !httpState->_peer) {
+	int skew = abs(reply->date - squid_curtime);
+	if (skew > 86400)
+	    debug(11, 3) ("%s's clock is skewed by %d seconds!\n",
+		httpState->request->host, skew);
+    }
+    ctx_exit(ctx);
+#if HEADERS_LOG
+    headersLog(1, 0, httpState->request->method, reply);
+#endif
+}
+
+static int
+httpPconnTransferDone(HttpStateData * httpState)
+{
+    /* return 1 if we got the last of the data on a persistent connection */
+    MemObject *mem = httpState->entry->mem_obj;
+    HttpReply *reply = mem->reply;
+    int clen;
+    debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
+    /*
+     * If we didn't send a keep-alive request header, then this
+     * can not be a persistent connection.
+     */
+    if (!httpState->flags.keepalive)
+	return 0;
+    /*
+     * What does the reply have to say about keep-alive?
+     */
+    /*
+     * XXX BUG?
+     * If the origin server (HTTP/1.0) does not send a keep-alive
+     * header, but keeps the connection open anyway, what happens?
+     * We'll return here and http.c waits for an EOF before changing
+     * store_status to STORE_OK.   Combine this with ENTRY_FWD_HDR_WAIT
+     * and an error status code, and we might have to wait until
+     * the server times out the socket.
+     */
+    if (!reply->keep_alive)
+	return 0;
+    debug(11, 5) ("httpPconnTransferDone: content_length=%d\n",
+	reply->content_length);
+    /* If we haven't seen the end of reply headers, we are not done */
+    if (httpState->reply_hdr_state < 2)
+	return 0;
+    clen = httpReplyBodySize(httpState->request->method, reply);
+    /* If there is no message body, we can be persistent */
+    if (0 == clen)
+	return 1;
+    /* If the body size is unknown we must wait for EOF */
+    if (clen < 0)
+	return 0;
+    /* If the body size is known, we must wait until we've gotten all of it.  */
+    if (mem->inmem_hi < reply->content_length + reply->hdr_sz)
+	return 0;
+    /* We got it all */
+    return 1;
+}
+
+/* This will be called when data is ready to be read from fd.  Read until
+ * error or connection closed. */
+/* XXX this function is too long! */
+static void
+httpReadReply(int fd, void *data)
+{
+    HttpStateData *httpState = static_cast<HttpStateData *>(data);
+    LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF);
+    StoreEntry *entry = httpState->entry;
+    const request_t *request = httpState->request;
+    int len;
+    int bin;
+    int clen;
+    size_t read_sz;
+#if DELAY_POOLS
+    delay_id delay_id;
+
+    /* special "if" only for http (for nodelay proxy conns) */
+    if (delayIsNoDelay(fd))
+	delay_id = 0;
+    else
+	delay_id = delayMostBytesAllowed(entry->mem_obj);
+#endif
+    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+	comm_close(fd);
+	return;
+    }
+    /* check if we want to defer reading */
+    errno = 0;
+    read_sz = SQUID_TCP_SO_RCVBUF;
+#if DELAY_POOLS
+    read_sz = delayBytesWanted(delay_id, 1, read_sz);
+#endif
+    statCounter.syscalls.sock.reads++;
+    len = FD_READ_METHOD(fd, buf, read_sz);
+    debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, len);
+    if (len > 0) {
+	fd_bytes(fd, len, FD_READ);
+#if DELAY_POOLS
+	delayBytesIn(delay_id, len);
+#endif
+	kb_incr(&statCounter.server.all.kbytes_in, len);
+	kb_incr(&statCounter.server.http.kbytes_in, len);
+	commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
+	IOStats.Http.reads++;
+	for (clen = len - 1, bin = 0; clen; bin++)
+	    clen >>= 1;
+	IOStats.Http.read_hist[bin]++;
+    }
+    if (!httpState->reply_hdr && len > 0) {
+	/* Skip whitespace */
+	while (len > 0 && xisspace(*buf))
+	    xmemmove(buf, buf + 1, len--);
+	if (len == 0) {
+	    /* Continue to read... */
+	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+	    return;
+	}
+    }
+    if (len < 0) {
+	debug(50, 2) ("httpReadReply: FD %d: read failure: %s.\n",
+	    fd, xstrerror());
+	if (ignoreErrno(errno)) {
+	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+	} else if (entry->mem_obj->inmem_hi == 0) {
+	    ErrorState *err;
+	    err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR);
+	    err->request = requestLink((request_t *) request);
+	    err->xerrno = errno;
+	    fwdFail(httpState->fwd, err);
+	    comm_close(fd);
+	} else {
+	    comm_close(fd);
+	}
+    } else if (len == 0 && entry->mem_obj->inmem_hi == 0) {
+	ErrorState *err;
+	err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
+	err->xerrno = errno;
+	err->request = requestLink((request_t *) request);
+	fwdFail(httpState->fwd, err);
+	httpState->eof = 1;
+	comm_close(fd);
+    } else if (len == 0) {
+	/* Connection closed; retrieval done. */
+	httpState->eof = 1;
+	if (httpState->reply_hdr_state < 2)
+	    /*
+	     * Yes Henrik, there is a point to doing this.  When we
+	     * called httpProcessReplyHeader() before, we didn't find
+	     * the end of headers, but now we are definately at EOF, so
+	     * we want to process the reply headers.
+	     */
+	    httpProcessReplyHeader(httpState, buf, len);
+	fwdComplete(httpState->fwd);
+	comm_close(fd);
+    } else {
+	if (httpState->reply_hdr_state < 2) {
+	    httpProcessReplyHeader(httpState, buf, len);
+	    if (httpState->reply_hdr_state == 2) {
+		http_status s = entry->mem_obj->reply->sline.status;
+#if WIP_FWD_LOG
+		fwdStatus(httpState->fwd, s);
+#endif
+		/*
+		 * If its not a reply that we will re-forward, then
+		 * allow the client to get it.
+		 */
+		if (!fwdReforwardableStatus(s))
+		    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+	    }
+	}
+	storeAppend(entry, buf, len);
+	if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+	    /*
+	     * the above storeAppend() call could ABORT this entry,
+	     * in that case, the server FD should already be closed.
+	     * there's nothing for us to do.
+	     */
+	    (void) 0;
+	} else if (httpPconnTransferDone(httpState)) {
+	    /* yes we have to clear all these! */
+	    commSetDefer(fd, NULL, NULL);
+	    commSetTimeout(fd, -1, NULL, NULL);
+	    commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
+#if DELAY_POOLS
+	    delayClearNoDelay(fd);
+#endif
+	    comm_remove_close_handler(fd, httpStateFree, httpState);
+	    fwdUnregister(fd, httpState->fwd);
+	    pconnPush(fd, request->host, request->port);
+	    fwdComplete(httpState->fwd);
+	    httpState->fd = -1;
+	    httpStateFree(fd, httpState);
+	} else {
+	    /* Wait for EOF condition */
+	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+	}
+    }
+}
+
+/* This will be called when request write is complete. Schedule read of
+ * reply. */
+static void
+httpSendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
+{
+    HttpStateData *httpState = static_cast<HttpStateData *>(data);
+    StoreEntry *entry = httpState->entry;
+    ErrorState *err;
+    debug(11, 5) ("httpSendComplete: FD %d: size %d: errflag %d.\n",
+	fd, (int) size, errflag);
+#if URL_CHECKSUM_DEBUG
+    assert(entry->mem_obj->chksum == url_checksum(entry->mem_obj->url));
+#endif
+    if (size > 0) {
+	fd_bytes(fd, size, FD_WRITE);
+	kb_incr(&statCounter.server.all.kbytes_out, size);
+	kb_incr(&statCounter.server.http.kbytes_out, size);
+    }
+    if (errflag == COMM_ERR_CLOSING)
+	return;
+    if (errflag) {
+	err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
+	err->xerrno = errno;
+	err->request = requestLink(httpState->orig_request);
+	errorAppendEntry(entry, err);
+	comm_close(fd);
+	return;
+    } else {
+	/* Schedule read reply. */
+	commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+	/*
+	 * Set the read timeout here because it hasn't been set yet.
+	 * We only set the read timeout after the request has been
+	 * fully written to the server-side.  If we start the timeout
+	 * after connection establishment, then we are likely to hit
+	 * the timeout for POST/PUT requests that have very large
+	 * request bodies.
+	 */
+	commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
+	commSetDefer(fd, fwdCheckDeferRead, entry);
+    }
+}
+
+/*
+ * build request headers and append them to a given MemBuf 
+ * used by httpBuildRequestPrefix()
+ * note: calls httpHeaderInit(), the caller is responsible for Clean()-ing
+ */
+void
+httpBuildRequestHeader(request_t * request,
+    request_t * orig_request,
+    StoreEntry * entry,
+    HttpHeader * hdr_out,
+    int cfd,
+    http_state_flags flags)
+{
+    /* building buffer for complex strings */
+#define BBUF_SZ (MAX_URL+32)
+    LOCAL_ARRAY(char, bbuf, BBUF_SZ);
+    String strConnection = StringNull;
+    const HttpHeader *hdr_in = &orig_request->header;
+    const HttpHeaderEntry *e;
+    String strFwd;
+    HttpHeaderPos pos = HttpHeaderInitPos;
+    httpHeaderInit(hdr_out, hoRequest);
+    /* append our IMS header */
+    if (request->lastmod > -1 && request->method == METHOD_GET)
+	httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, request->lastmod);
+
+    strConnection = httpHeaderGetList(hdr_in, HDR_CONNECTION);
+    while ((e = httpHeaderGetEntry(hdr_in, &pos))) {
+	debug(11, 5) ("httpBuildRequestHeader: %s: %s\n",
+	    strBuf(e->name), strBuf(e->value));
+	if (!httpRequestHdrAllowed(e, &strConnection)) {
+	    debug(11, 2) ("'%s' header denied by anonymize_headers configuration\n",
+		strBuf(e->name));
+	    continue;
+	}
+	switch (e->id) {
+	case HDR_PROXY_AUTHORIZATION:
+	    /* Only pass on proxy authentication to peers for which
+	     * authentication forwarding is explicitly enabled
+	     */
+	    if (request->flags.proxying && orig_request->peer_login &&
+		strcmp(orig_request->peer_login, "PASS") == 0) {
+		httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+	    }
+	    break;
+	case HDR_AUTHORIZATION:
+	    /* Pass on WWW authentication even if used locally. If this is
+	     * not wanted in an accelerator then the header can be removed
+	     * using the anonymization functions
+	     */
+	    httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+	    /* XXX Some accelerators might want to strip the header
+	     * and regard the reply as cacheable, but authentication
+	     * is not normally enabled for accelerators without reading
+	     * the code, so there is not much use in adding logics here
+	     * without first defining the concept of having authentication
+	     * in the accelerator...
+	     */
+	    break;
+	case HDR_HOST:
+	    /*
+	     * Normally Squid does not copy the Host: header from
+	     * a client request into the forwarded request headers.
+	     * However, there is one case when we do: If the URL
+	     * went through our redirector and the admin configured
+	     * 'redir_rewrites_host' to be off.
+	     */
+	    if (request->flags.redirected)
+		if (!Config.onoff.redir_rewrites_host)
+		    httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+	    break;
+	case HDR_IF_MODIFIED_SINCE:
+	    /* append unless we added our own;
+	     * note: at most one client's ims header can pass through */
+	    if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE))
+		httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+	    break;
+	case HDR_MAX_FORWARDS:
+	    if (orig_request->method == METHOD_TRACE) {
+		/* sacrificing efficiency over clarity, etc. */
+		const int hops = httpHeaderGetInt(hdr_in, HDR_MAX_FORWARDS);
+		if (hops > 0)
+		    httpHeaderPutInt(hdr_out, HDR_MAX_FORWARDS, hops - 1);
+	    }
+	    break;
+	case HDR_VIA:
+	    /* If Via is disabled then forward any received header as-is */
+	    if (!Config.onoff.via)
+		httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+	    break;
+	case HDR_PROXY_CONNECTION:
+	case HDR_CONNECTION:
+	case HDR_X_FORWARDED_FOR:
+	case HDR_CACHE_CONTROL:
+	    /* append these after the loop if needed */
+	    break;
+	default:
+	    /* pass on all other header fields */
+	    httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+	}
+    }
+
+    /* append Via */
+    if (Config.onoff.via) {
+	String strVia = httpHeaderGetList(hdr_in, HDR_VIA);
+	snprintf(bbuf, BBUF_SZ, "%d.%d %s",
+	    orig_request->http_ver.major,
+	    orig_request->http_ver.minor, ThisCache);
+	strListAdd(&strVia, bbuf, ',');
+	httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia));
+	stringClean(&strVia);
+    }
+    /* append X-Forwarded-For */
+    strFwd = httpHeaderGetList(hdr_in, HDR_X_FORWARDED_FOR);
+    strListAdd(&strFwd, (cfd < 0 ? "unknown" : fd_table[cfd].ipaddr), ',');
+    httpHeaderPutStr(hdr_out, HDR_X_FORWARDED_FOR, strBuf(strFwd));
+    stringClean(&strFwd);
+
+    /* append Host if not there already */
+    if (!httpHeaderHas(hdr_out, HDR_HOST)) {
+	/* use port# only if not default */
+	if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
+	    httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
+	} else {
+	    httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
+		orig_request->host, (int) orig_request->port);
+	}
+    }
+    /* append Authorization if known in URL, not in header and going direct */
+    if (!httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) {
+	if (!request->flags.proxying && *request->login) {
+	    httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
+		base64_encode(request->login));
+	}
+    }
+    /* append Proxy-Authorization if configured for peer, and proxying */
+    if (request->flags.proxying && orig_request->peer_login &&
+	!httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION) &&
+	strcmp(orig_request->peer_login, "PASS") != 0) {
+	if (*orig_request->peer_login == '*') {
+	    /* Special mode, to pass the username to the upstream cache */
+	    char loginbuf[256];
+	    const char *username = "-";
+	    if (orig_request->auth_user_request)
+		username = orig_request->auth_user_request->username();
+	    snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
+	    httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
+		base64_encode(loginbuf));
+	} else {
+	    httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
+		base64_encode(orig_request->peer_login));
+	}
+    }
+    /* append Cache-Control, add max-age if not there already */
+    {
+	HttpHdrCc *cc = httpHeaderGetCc(hdr_in);
+	if (!cc)
+	    cc = httpHdrCcCreate();
+	if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
+	    const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request);
+	    httpHdrCcSetMaxAge(cc, getMaxAge(url));
+	    if (strLen(request->urlpath))
+		assert(strstr(url, strBuf(request->urlpath)));
+	}
+	if (flags.only_if_cached)
+	    EBIT_SET(cc->mask, CC_ONLY_IF_CACHED);
+	httpHeaderPutCc(hdr_out, cc);
+	httpHdrCcDestroy(cc);
+    }
+    /* maybe append Connection: keep-alive */
+    if (flags.keepalive) {
+	if (flags.proxying) {
+	    httpHeaderPutStr(hdr_out, HDR_PROXY_CONNECTION, "keep-alive");
+	} else {
+	    httpHeaderPutStr(hdr_out, HDR_CONNECTION, "keep-alive");
+	}
+    }
+    /* Now mangle the headers. */
+    httpHdrMangleList(hdr_out, request);
+    stringClean(&strConnection);
+}
+
+/* build request prefix and append it to a given MemBuf; 
+ * return the length of the prefix */
+mb_size_t
+httpBuildRequestPrefix(request_t * request,
+    request_t * orig_request,
+    StoreEntry * entry,
+    MemBuf * mb,
+    int cfd,
+    http_state_flags flags)
+{
+    const int offset = mb->size;
+    memBufPrintf(mb, "%s %s HTTP/1.0\r\n",
+	RequestMethodStr[request->method],
+	strLen(request->urlpath) ? strBuf(request->urlpath) : "/");
+    /* build and pack headers */
+    {
+	HttpHeader hdr;
+	Packer p;
+	httpBuildRequestHeader(request, orig_request, entry, &hdr, cfd, flags);
+	packerToMemInit(&p, mb);
+	httpHeaderPackInto(&hdr, &p);
+	httpHeaderClean(&hdr);
+	packerClean(&p);
+    }
+    /* append header terminator */
+    memBufAppend(mb, crlf, 2);
+    return mb->size - offset;
+}
+/* This will be called when connect completes. Write request. */
+static void
+httpSendRequest(HttpStateData * httpState)
+{
+    MemBuf mb;
+    request_t *req = httpState->request;
+    StoreEntry *entry = httpState->entry;
+    int cfd;
+    peer *p = httpState->_peer;
+    CWCB *sendHeaderDone;
+
+    debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", httpState->fd, httpState);
+
+    if (httpState->orig_request->body_connection)
+	sendHeaderDone = httpSendRequestEntity;
+    else
+	sendHeaderDone = httpSendComplete;
+
+    if (!opt_forwarded_for)
+	cfd = -1;
+    else if (entry->mem_obj == NULL)
+	cfd = -1;
+    else
+	cfd = entry->mem_obj->fd;
+    assert(-1 == cfd || FD_SOCKET == fd_table[cfd].type);
+    if (p != NULL)
+	httpState->flags.proxying = 1;
+    else
+	httpState->flags.proxying = 0;
+    /*
+     * Is keep-alive okay for all request methods?
+     */
+    if (!Config.onoff.server_pconns)
+	httpState->flags.keepalive = 0;
+    else if (p == NULL)
+	httpState->flags.keepalive = 1;
+    else if (p->stats.n_keepalives_sent < 10)
+	httpState->flags.keepalive = 1;
+    else if ((double) p->stats.n_keepalives_recv / (double) p->stats.n_keepalives_sent > 0.50)
+	httpState->flags.keepalive = 1;
+    if (httpState->_peer)
+	if (neighborType(httpState->_peer, httpState->request) == PEER_SIBLING &&
+	    !httpState->_peer->options.allow_miss)
+	    httpState->flags.only_if_cached = 1;
+    memBufDefInit(&mb);
+    httpBuildRequestPrefix(req,
+	httpState->orig_request,
+	entry,
+	&mb,
+	cfd,
+	httpState->flags);
+    debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", httpState->fd, mb.buf);
+    comm_write_mbuf(httpState->fd, mb, sendHeaderDone, httpState);
+}
+
+void
+httpStart(FwdState * fwd)
+{
+    int fd = fwd->server_fd;
+    HttpStateData *httpState;
+    request_t *proxy_req;
+    request_t *orig_req = fwd->request;
+    debug(11, 3) ("httpStart: \"%s %s\"\n",
+	RequestMethodStr[orig_req->method],
+	storeUrl(fwd->entry));
+    httpState = cbdataAlloc(HttpStateData);
+    storeLockObject(fwd->entry);
+    httpState->fwd = fwd;
+    httpState->entry = fwd->entry;
+    httpState->fd = fd;
+    if (fwd->servers)
+	httpState->_peer = fwd->servers->_peer;		/* might be NULL */
+    if (httpState->_peer) {
+	proxy_req = requestCreate(orig_req->method,
+	    PROTO_NONE, storeUrl(httpState->entry));
+	xstrncpy(proxy_req->host, httpState->_peer->host, SQUIDHOSTNAMELEN);
+	proxy_req->port = httpState->_peer->http_port;
+	proxy_req->flags = orig_req->flags;
+	proxy_req->lastmod = orig_req->lastmod;
+	httpState->request = requestLink(proxy_req);
+	httpState->orig_request = requestLink(orig_req);
+	proxy_req->flags.proxying = 1;
+	/*
+	 * This NEIGHBOR_PROXY_ONLY check probably shouldn't be here.
+	 * We might end up getting the object from somewhere else if,
+	 * for example, the request to this neighbor fails.
+	 */
+	if (httpState->_peer->options.proxy_only)
+	    storeReleaseRequest(httpState->entry);
+#if DELAY_POOLS
+	assert(delayIsNoDelay(fd) == 0);
+	if (httpState->_peer->options.no_delay)
+	    delaySetNoDelay(fd);
+#endif
+    } else {
+	httpState->request = requestLink(orig_req);
+	httpState->orig_request = requestLink(orig_req);
+    }
+    /*
+     * register the handler to free HTTP state data when the FD closes
+     */
+    comm_add_close_handler(fd, httpStateFree, httpState);
+    statCounter.server.all.requests++;
+    statCounter.server.http.requests++;
+    httpSendRequest(httpState);
+    /*
+     * We used to set the read timeout here, but not any more.
+     * Now its set in httpSendComplete() after the full request,
+     * including request body, has been written to the server.
+     */
+}
+
+static void
+httpSendRequestEntityDone(int fd, void *data)
+{
+    HttpStateData *httpState = static_cast<HttpStateData *>(data);
+    aclCheck_t ch;
+    debug(11, 5) ("httpSendRequestEntityDone: FD %d\n",
+	fd);
+    memset(&ch, '\0', sizeof(ch));
+    ch.request = httpState->request;
+    if (!Config.accessList.brokenPosts) {
+	debug(11, 5) ("httpSendRequestEntityDone: No brokenPosts list\n");
+	httpSendComplete(fd, NULL, 0, COMM_OK, data);
+    } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) {
+	debug(11, 5) ("httpSendRequestEntityDone: didn't match brokenPosts\n");
+	httpSendComplete(fd, NULL, 0, COMM_OK, data);
+    } else {
+	debug(11, 2) ("httpSendRequestEntityDone: matched brokenPosts\n");
+	comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL);
+    }
+}
+
+static void
+httpRequestBodyHandler(char *buf, size_t size, void *data)
+{
+    HttpStateData *httpState = (HttpStateData *) data;
+    if (size > 0) {
+	comm_write(httpState->fd, buf, size, httpSendRequestEntity, data, memFree8K);
+    } else if (size == 0) {
+	/* End of body */
+	memFree8K(buf);
+	httpSendRequestEntityDone(httpState->fd, data);
+    } else {
+	/* Failed to get whole body, probably aborted */
+	memFree8K(buf);
+	httpSendComplete(httpState->fd, NULL, 0, COMM_ERR_CLOSING, data);
+    }
+}
+
+static void
+httpSendRequestEntity(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
+{
+    HttpStateData *httpState = static_cast<HttpStateData *>(data);
+    StoreEntry *entry = httpState->entry;
+    ErrorState *err;
+    debug(11, 5) ("httpSendRequestEntity: FD %d: size %d: errflag %d.\n",
+	fd, (int) size, errflag);
+    if (size > 0) {
+	fd_bytes(fd, size, FD_WRITE);
+	kb_incr(&statCounter.server.all.kbytes_out, size);
+	kb_incr(&statCounter.server.http.kbytes_out, size);
+    }
+    if (errflag == COMM_ERR_CLOSING)
+	return;
+    if (errflag) {
+	err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
+	err->xerrno = errno;
+	err->request = requestLink(httpState->orig_request);
+	errorAppendEntry(entry, err);
+	comm_close(fd);
+	return;
+    }
+    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+	comm_close(fd);
+	return;
+    }
+    clientReadBody(httpState->orig_request, (char *)memAllocate(MEM_8K_BUF), 8192, httpRequestBodyHandler, httpState);
+}
+
+void
+httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor)
+{
+    version->major = major;
+    version->minor = minor;
+}
--- squid/src/logfile.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,190 +0,0 @@
-/*
- * $Id$
- *
- * DEBUG: section 50    Log file handling
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-
-static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len);
-
-Logfile *
-logfileOpen(const char *path, size_t bufsz, int fatal_flag)
-{
-    int fd;
-    Logfile *lf;
-    fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
-    if (DISK_ERROR == fd) {
-	if (ENOENT == errno && fatal_flag) {
-	    fatalf("Cannot open '%s' because\n"
-		"\tthe parent directory does not exist.\n"
-		"\tPlease create the directory.\n", path);
-	} else if (EACCES == errno && fatal_flag) {
-	    fatalf("Cannot open '%s' for writing.\n"
-		"\tThe parent directory must be writeable by the\n"
-		"\tuser '%s', which is the cache_effective_user\n"
-		"\tset in squid.conf.", path, Config.effectiveUser);
-	} else {
-	    debug(50, 1) ("logfileOpen: %s: %s\n", path, xstrerror());
-	    return NULL;
-	}
-    }
-    lf = xcalloc(1, sizeof(*lf));
-    lf->fd = fd;
-    if (fatal_flag)
-	lf->flags.fatal = 1;
-    xstrncpy(lf->path, path, MAXPATHLEN);
-    if (bufsz > 0) {
-	lf->buf = xmalloc(bufsz);
-	lf->bufsz = bufsz;
-    }
-    return lf;
-}
-
-void
-logfileClose(Logfile * lf)
-{
-    logfileFlush(lf);
-    file_close(lf->fd);
-    if (lf->buf)
-	xfree(lf->buf);
-    xfree(lf);
-}
-
-void
-logfileRotate(Logfile * lf)
-{
-#ifdef S_ISREG
-    struct stat sb;
-#endif
-    int i;
-    char from[MAXPATHLEN];
-    char to[MAXPATHLEN];
-    assert(lf->path);
-#ifdef S_ISREG
-    if (stat(lf->path, &sb) == 0)
-	if (S_ISREG(sb.st_mode) == 0)
-	    return;
-#endif
-    debug(0, 1) ("logfileRotate: %s\n", lf->path);
-    /* Rotate numbers 0 through N up one */
-    for (i = Config.Log.rotateNumber; i > 1;) {
-	i--;
-	snprintf(from, MAXPATHLEN, "%s.%d", lf->path, i - 1);
-	snprintf(to, MAXPATHLEN, "%s.%d", lf->path, i);
-	xrename(from, to);
-    }
-    /* Rotate the current log to .0 */
-    logfileFlush(lf);
-    file_close(lf->fd);		/* always close */
-    if (Config.Log.rotateNumber > 0) {
-	snprintf(to, MAXPATHLEN, "%s.%d", lf->path, 0);
-	xrename(lf->path, to);
-    }
-    /* Reopen the log.  It may have been renamed "manually" */
-    lf->fd = file_open(lf->path, O_WRONLY | O_CREAT | O_TEXT);
-    if (DISK_ERROR == lf->fd && lf->flags.fatal) {
-	debug(50, 1) ("logfileRotate: %s: %s\n", lf->path, xstrerror());
-	fatalf("Cannot open %s: %s", lf->path, xstrerror());
-    }
-}
-
-void
-logfileWrite(Logfile * lf, void *buf, size_t len)
-{
-    if (0 == lf->bufsz) {
-	/* buffering disabled */
-	logfileWriteWrapper(lf, buf, len);
-	return;
-    }
-    if (lf->offset > 0 && lf->offset + len > lf->bufsz)
-	logfileFlush(lf);
-    if (len > lf->bufsz) {
-	/* too big to fit in buffer */
-	logfileWriteWrapper(lf, buf, len);
-	return;
-    }
-    /* buffer it */
-    xmemcpy(lf->buf + lf->offset, buf, len);
-    lf->offset += len;
-    assert(lf->offset <= lf->bufsz);
-}
-
-void
-#if STDC_HEADERS
-logfilePrintf(Logfile * lf, const char *fmt,...)
-#else
-logfilePrintf(va_alist)
-     va_dcl
-#endif
-{
-    va_list args;
-    char buf[8192];
-    int s;
-#if STDC_HEADERS
-    va_start(args, fmt);
-#else
-    Logfile *lf;
-    const char *fmt;
-    va_start(args);
-    lf = va_arg(args, Logfile *);
-    fmt = va_arg(args, char *);
-#endif
-    s = vsnprintf(buf, 8192, fmt, args);
-    logfileWrite(lf, buf, (size_t) s);
-    va_end(args);
-}
-
-void
-logfileFlush(Logfile * lf)
-{
-    if (0 == lf->offset)
-	return;
-    logfileWriteWrapper(lf, lf->buf, (size_t) lf->offset);
-    lf->offset = 0;
-}
-
-/*
- * Aborts with fatal message if write() returns something other
- * than its length argument.
- */
-static void
-logfileWriteWrapper(Logfile * lf, const void *buf, size_t len)
-{
-    int s;
-    s = FD_WRITE_METHOD(lf->fd, buf, len);
-    fd_bytes(lf->fd, s, FD_WRITE);
-    if (s == len)
-	return;
-    if (!lf->flags.fatal)
-	return;
-    fatalf("logfileWrite: %s: %s\n", lf->path, xstrerror());
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/logfile.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,191 @@
+/*
+ * $Id: logfile.cc,v 1.1.2.1 2002/10/03 01:04:35 rbcollins Exp $
+ *
+ * DEBUG: section 50    Log file handling
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "authenticate.h"
+
+static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len);
+
+Logfile *
+logfileOpen(const char *path, size_t bufsz, int fatal_flag)
+{
+    int fd;
+    Logfile *lf;
+    fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
+    if (DISK_ERROR == fd) {
+	if (ENOENT == errno && fatal_flag) {
+	    fatalf("Cannot open '%s' because\n"
+		"\tthe parent directory does not exist.\n"
+		"\tPlease create the directory.\n", path);
+	} else if (EACCES == errno && fatal_flag) {
+	    fatalf("Cannot open '%s' for writing.\n"
+		"\tThe parent directory must be writeable by the\n"
+		"\tuser '%s', which is the cache_effective_user\n"
+		"\tset in squid.conf.", path, Config.effectiveUser);
+	} else {
+	    debug(50, 1) ("logfileOpen: %s: %s\n", path, xstrerror());
+	    return NULL;
+	}
+    }
+    lf = static_cast<Logfile *>(xcalloc(1, sizeof(*lf)));
+    lf->fd = fd;
+    if (fatal_flag)
+	lf->flags.fatal = 1;
+    xstrncpy(lf->path, path, MAXPATHLEN);
+    if (bufsz > 0) {
+	lf->buf = (char *) xmalloc(bufsz);
+	lf->bufsz = bufsz;
+    }
+    return lf;
+}
+
+void
+logfileClose(Logfile * lf)
+{
+    logfileFlush(lf);
+    file_close(lf->fd);
+    if (lf->buf)
+	xfree(lf->buf);
+    xfree(lf);
+}
+
+void
+logfileRotate(Logfile * lf)
+{
+#ifdef S_ISREG
+    struct stat sb;
+#endif
+    int i;
+    char from[MAXPATHLEN];
+    char to[MAXPATHLEN];
+    assert(lf->path);
+#ifdef S_ISREG
+    if (stat(lf->path, &sb) == 0)
+	if (S_ISREG(sb.st_mode) == 0)
+	    return;
+#endif
+    debug(0, 1) ("logfileRotate: %s\n", lf->path);
+    /* Rotate numbers 0 through N up one */
+    for (i = Config.Log.rotateNumber; i > 1;) {
+	i--;
+	snprintf(from, MAXPATHLEN, "%s.%d", lf->path, i - 1);
+	snprintf(to, MAXPATHLEN, "%s.%d", lf->path, i);
+	xrename(from, to);
+    }
+    /* Rotate the current log to .0 */
+    logfileFlush(lf);
+    file_close(lf->fd);		/* always close */
+    if (Config.Log.rotateNumber > 0) {
+	snprintf(to, MAXPATHLEN, "%s.%d", lf->path, 0);
+	xrename(lf->path, to);
+    }
+    /* Reopen the log.  It may have been renamed "manually" */
+    lf->fd = file_open(lf->path, O_WRONLY | O_CREAT | O_TEXT);
+    if (DISK_ERROR == lf->fd && lf->flags.fatal) {
+	debug(50, 1) ("logfileRotate: %s: %s\n", lf->path, xstrerror());
+	fatalf("Cannot open %s: %s", lf->path, xstrerror());
+    }
+}
+
+void
+logfileWrite(Logfile * lf, void *buf, size_t len)
+{
+    if (0 == lf->bufsz) {
+	/* buffering disabled */
+	logfileWriteWrapper(lf, buf, len);
+	return;
+    }
+    if (lf->offset > 0 && lf->offset + len > lf->bufsz)
+	logfileFlush(lf);
+    if (len > lf->bufsz) {
+	/* too big to fit in buffer */
+	logfileWriteWrapper(lf, buf, len);
+	return;
+    }
+    /* buffer it */
+    xmemcpy(lf->buf + lf->offset, buf, len);
+    lf->offset += len;
+    assert(lf->offset <= lf->bufsz);
+}
+
+void
+#if STDC_HEADERS
+logfilePrintf(Logfile * lf, const char *fmt,...)
+#else
+logfilePrintf(va_alist)
+     va_dcl
+#endif
+{
+    va_list args;
+    char buf[8192];
+    int s;
+#if STDC_HEADERS
+    va_start(args, fmt);
+#else
+    Logfile *lf;
+    const char *fmt;
+    va_start(args);
+    lf = va_arg(args, Logfile *);
+    fmt = va_arg(args, char *);
+#endif
+    s = vsnprintf(buf, 8192, fmt, args);
+    logfileWrite(lf, buf, (size_t) s);
+    va_end(args);
+}
+
+void
+logfileFlush(Logfile * lf)
+{
+    if (0 == lf->offset)
+	return;
+    logfileWriteWrapper(lf, lf->buf, (size_t) lf->offset);
+    lf->offset = 0;
+}
+
+/*
+ * Aborts with fatal message if write() returns something other
+ * than its length argument.
+ */
+static void
+logfileWriteWrapper(Logfile * lf, const void *buf, size_t len)
+{
+    int s;
+    s = FD_WRITE_METHOD(lf->fd, (char const *)buf, len);
+    fd_bytes(lf->fd, s, FD_WRITE);
+    if (s == len)
+	return;
+    if (!lf->flags.fatal)
+	return;
+    fatalf("logfileWrite: %s: %s\n", lf->path, xstrerror());
+}
--- squid/src/main.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,996 +0,0 @@
-
-/*
- * $Id: main.c,v 1.37 2002/10/02 11:10:47 squidadm Exp $
- *
- * DEBUG: section 1     Startup and Main Loop
- * AUTHOR: Harvest Derived
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-
-/* for error reporting from xmalloc and friends */
-extern void (*failure_notify) (const char *);
-
-static int opt_send_signal = -1;
-static int opt_no_daemon = 0;
-static int opt_parse_cfg_only = 0;
-static int icpPortNumOverride = 1;	/* Want to detect "-u 0" */
-static int configured_once = 0;
-#if MALLOC_DBG
-static int malloc_debug_level = 0;
-#endif
-static volatile int do_reconfigure = 0;
-static volatile int do_rotate = 0;
-static volatile int do_shutdown = 0;
-
-static void mainRotate(void);
-static void mainReconfigure(void);
-static SIGHDLR rotate_logs;
-static SIGHDLR reconfigure;
-static void mainInitialize(void);
-static void usage(void);
-static void mainParseOptions(int, char **);
-static void sendSignal(void);
-static void serverConnectionsOpen(void);
-static void watch_child(char **);
-static void setEffectiveUser(void);
-#if MEM_GEN_TRACE
-extern void log_trace_done();
-extern void log_trace_init(char *);
-#endif
-static EVH SquidShutdown;
-static void mainSetCwd(void);
-static int checkRunningPid(void);
-
-static const char *squid_start_script = "squid_start";
-
-#if TEST_ACCESS
-#include "test_access.c"
-#endif
-
-static void
-usage(void)
-{
-    fprintf(stderr,
-	"Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n"
-	"       -a port   Specify HTTP port number (default: %d).\n"
-	"       -d level  Write debugging to stderr also.\n"
-	"       -f file   Use given config-file instead of\n"
-	"                 %s\n"
-	"       -h        Print help message.\n"
-	"       -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
-	"                 Parse configuration file, then send signal to \n"
-	"                 running copy (except -k parse) and exit.\n"
-	"       -s        Enable logging to syslog.\n"
-	"       -u port   Specify ICP port number (default: %d), disable with 0.\n"
-	"       -v        Print version.\n"
-	"       -z        Create swap directories\n"
-	"       -C        Do not catch fatal signals.\n"
-	"       -D        Disable initial DNS tests.\n"
-	"       -F        Don't serve any requests until store is rebuilt.\n"
-	"       -N        No daemon mode.\n"
-	"       -R        Do not set REUSEADDR on port.\n"
-	"       -S        Double-check swap during rebuild.\n"
-	"       -V        Virtual host httpd-accelerator.\n"
-	"       -X        Force full debugging.\n"
-	"       -Y        Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
-	appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
-    exit(1);
-}
-
-static void
-mainParseOptions(int argc, char *argv[])
-{
-    extern char *optarg;
-    int c;
-
-    while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) {
-	switch (c) {
-	case 'C':
-	    opt_catch_signals = 0;
-	    break;
-	case 'D':
-	    opt_dns_tests = 0;
-	    break;
-	case 'F':
-	    opt_foreground_rebuild = 1;
-	    break;
-	case 'N':
-	    opt_no_daemon = 1;
-	    break;
-	case 'R':
-	    opt_reuseaddr = 0;
-	    break;
-	case 'S':
-	    opt_store_doublecheck = 1;
-	    break;
-	case 'V':
-	    vhost_mode = 1;
-	    break;
-	case 'X':
-	    /* force full debugging */
-	    sigusr2_handle(SIGUSR2);
-	    break;
-	case 'Y':
-	    opt_reload_hit_only = 1;
-	    break;
-	case 'a':
-	    parse_sockaddr_in_list_token(&Config.Sockaddr.http, optarg);
-	    break;
-	case 'd':
-	    opt_debug_stderr = atoi(optarg);
-	    break;
-	case 'f':
-	    xfree(ConfigFile);
-	    ConfigFile = xstrdup(optarg);
-	    break;
-	case 'h':
-	    usage();
-	    break;
-	case 'k':
-	    if ((int) strlen(optarg) < 1)
-		usage();
-	    if (!strncmp(optarg, "reconfigure", strlen(optarg)))
-		opt_send_signal = SIGHUP;
-	    else if (!strncmp(optarg, "rotate", strlen(optarg)))
-#ifdef _SQUID_LINUX_THREADS_
-		opt_send_signal = SIGQUIT;
-#else
-		opt_send_signal = SIGUSR1;
-#endif
-	    else if (!strncmp(optarg, "debug", strlen(optarg)))
-#ifdef _SQUID_LINUX_THREADS_
-		opt_send_signal = SIGTRAP;
-#else
-		opt_send_signal = SIGUSR2;
-#endif
-	    else if (!strncmp(optarg, "shutdown", strlen(optarg)))
-		opt_send_signal = SIGTERM;
-	    else if (!strncmp(optarg, "interrupt", strlen(optarg)))
-		opt_send_signal = SIGINT;
-	    else if (!strncmp(optarg, "kill", strlen(optarg)))
-		opt_send_signal = SIGKILL;
-	    else if (!strncmp(optarg, "check", strlen(optarg)))
-		opt_send_signal = 0;	/* SIGNULL */
-	    else if (!strncmp(optarg, "parse", strlen(optarg)))
-		opt_parse_cfg_only = 1;		/* parse cfg file only */
-	    else
-		usage();
-	    break;
-	case 'm':
-	    if (optarg) {
-#if MALLOC_DBG
-		malloc_debug_level = atoi(optarg);
-		/* NOTREACHED */
-		break;
-#else
-		fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
-		/* NOTREACHED */
-#endif
-	    } else {
-#if XMALLOC_TRACE
-		xmalloc_trace = !xmalloc_trace;
-#else
-		fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
-#endif
-	    }
-	case 's':
-#if HAVE_SYSLOG
-	    opt_syslog_enable = 1;
-	    break;
-#else
-	    fatal("Logging to syslog not available on this platform");
-	    /* NOTREACHED */
-#endif
-	case 'u':
-	    icpPortNumOverride = atoi(optarg);
-	    if (icpPortNumOverride < 0)
-		icpPortNumOverride = 0;
-	    break;
-	case 'v':
-	    printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
-	    exit(0);
-	    /* NOTREACHED */
-	case 'z':
-	    opt_create_swap_dirs = 1;
-	    break;
-	case '?':
-	default:
-	    usage();
-	    break;
-	}
-    }
-}
-
-/* ARGSUSED */
-static void
-rotate_logs(int sig)
-{
-    do_rotate = 1;
-#if !HAVE_SIGACTION
-    signal(sig, rotate_logs);
-#endif
-}
-
-/* ARGSUSED */
-static void
-reconfigure(int sig)
-{
-    do_reconfigure = 1;
-#if !HAVE_SIGACTION
-    signal(sig, reconfigure);
-#endif
-}
-
-void
-shut_down(int sig)
-{
-    do_shutdown = sig == SIGINT ? -1 : 1;
-#ifdef KILL_PARENT_OPT
-    if (getppid() > 1) {
-	debug(1, 1) ("Killing RunCache, pid %d\n", getppid());
-	if (kill(getppid(), sig) < 0)
-	    debug(1, 1) ("kill %d: %s\n", getppid(), xstrerror());
-    }
-#endif
-#if SA_RESETHAND == 0
-    signal(SIGTERM, SIG_DFL);
-    signal(SIGINT, SIG_DFL);
-#endif
-}
-
-static void
-serverConnectionsOpen(void)
-{
-    clientOpenListenSockets();
-    icpConnectionsOpen();
-#if USE_HTCP
-    htcpInit();
-#endif
-#ifdef SQUID_SNMP
-    snmpConnectionOpen();
-#endif
-#if USE_WCCP
-    wccpConnectionOpen();
-#endif
-    clientdbInit();
-    icmpOpen();
-    netdbInit();
-    asnInit();
-    peerSelectInit();
-#if USE_CARP
-    carpInit();
-#endif
-}
-
-void
-serverConnectionsClose(void)
-{
-    assert(shutting_down || reconfiguring);
-    clientHttpConnectionsClose();
-    icpConnectionShutdown();
-#if USE_HTCP
-    htcpSocketShutdown();
-#endif
-    icmpClose();
-#ifdef SQUID_SNMP
-    snmpConnectionShutdown();
-#endif
-#if USE_WCCP
-    wccpConnectionShutdown();
-#endif
-    asnFreeMemory();
-}
-
-static void
-mainReconfigure(void)
-{
-    debug(1, 1) ("Restarting Squid Cache (version %s)...\n", version_string);
-    reconfiguring = 1;
-    /* Already called serverConnectionsClose and ipcacheShutdownServers() */
-    serverConnectionsClose();
-    icpConnectionClose();
-#if USE_HTCP
-    htcpSocketClose();
-#endif
-#ifdef SQUID_SNMP
-    snmpConnectionClose();
-#endif
-#if USE_WCCP
-    wccpConnectionClose();
-#endif
-#if USE_DNSSERVERS
-    dnsShutdown();
-#else
-    idnsShutdown();
-#endif
-    redirectShutdown();
-    authenticateShutdown();
-    externalAclShutdown();
-    storeDirCloseSwapLogs();
-    errorClean();
-    enter_suid();		/* root to read config file */
-    parseConfigFile(ConfigFile);
-    setEffectiveUser();
-    _db_init(Config.Log.log, Config.debugOptions);
-    ipcache_restart();		/* clear stuck entries */
-    authenticateUserCacheRestart();	/* clear stuck ACL entries */
-    fqdncache_restart();	/* sigh, fqdncache too */
-    parseEtcHosts();
-    errorInitialize();		/* reload error pages */
-#if USE_DNSSERVERS
-    dnsInit();
-#else
-    idnsInit();
-#endif
-    redirectInit();
-    authenticateInit(&Config.authConfig);
-    externalAclInit();
-#if USE_WCCP
-    wccpInit();
-#endif
-    serverConnectionsOpen();
-    if (theOutIcpConnection >= 0) {
-	if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
-	    neighbors_open(theOutIcpConnection);
-	else
-	    debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
-    }
-    storeDirOpenSwapLogs();
-    mimeInit(Config.mimeTablePathname);
-    writePidFile();		/* write PID file */
-    debug(1, 1) ("Ready to serve requests.\n");
-    reconfiguring = 0;
-}
-
-static void
-mainRotate(void)
-{
-    icmpClose();
-#if USE_DNSSERVERS
-    dnsShutdown();
-#endif
-    redirectShutdown();
-    authenticateShutdown();
-    externalAclShutdown();
-    _db_rotate_log();		/* cache.log */
-    storeDirWriteCleanLogs(1);
-    storeLogRotate();		/* store.log */
-    accessLogRotate();		/* access.log */
-    useragentRotateLog();	/* useragent.log */
-    refererRotateLog();		/* referer.log */
-#if WIP_FWD_LOG
-    fwdLogRotate();
-#endif
-    icmpOpen();
-#if USE_DNSSERVERS
-    dnsInit();
-#endif
-    redirectInit();
-    authenticateInit(&Config.authConfig);
-    externalAclInit();
-}
-
-static void
-setEffectiveUser(void)
-{
-    leave_suid();		/* Run as non privilegied user */
-#ifdef _SQUID_OS2_
-    return;
-#endif
-    if (geteuid() == 0) {
-	debug(0, 0) ("Squid is not safe to run as root!  If you must\n");
-	debug(0, 0) ("start Squid as root, then you must configure\n");
-	debug(0, 0) ("it to run as a non-priveledged user with the\n");
-	debug(0, 0) ("'cache_effective_user' option in the config file.\n");
-	fatal("Don't run Squid as root, set 'cache_effective_user'!");
-    }
-}
-
-static void
-mainSetCwd(void)
-{
-    char pathbuf[MAXPATHLEN];
-    if (Config.coredump_dir) {
-	if (0 == strcmp("none", Config.coredump_dir)) {
-	    (void) 0;
-	} else if (chdir(Config.coredump_dir) == 0) {
-	    debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
-	    return;
-	} else {
-	    debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
-	}
-    }
-    /* If we don't have coredump_dir or couldn't cd there, report current dir */
-    if (getcwd(pathbuf, MAXPATHLEN)) {
-	debug(0, 1) ("Current Directory is %s\n", pathbuf);
-    } else {
-	debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
-    }
-}
-
-static void
-mainInitialize(void)
-{
-    /* chroot if configured to run inside chroot */
-    if (Config.chroot_dir && chroot(Config.chroot_dir)) {
-	fatal("failed to chroot");
-    }
-    if (opt_catch_signals) {
-	squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
-	squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
-    }
-    squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
-    squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
-
-    setEffectiveUser();
-    if (icpPortNumOverride != 1)
-	Config.Port.icp = (u_short) icpPortNumOverride;
-
-    _db_init(Config.Log.log, Config.debugOptions);
-    fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
-#if MEM_GEN_TRACE
-    log_trace_init("/tmp/squid.alloc");
-#endif
-    debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
-	version_string,
-	CONFIG_HOST_TYPE);
-    debug(1, 1) ("Process ID %d\n", (int) getpid());
-    debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
-
-    if (!configured_once)
-	disk_init();		/* disk_init must go before ipcache_init() */
-    ipcache_init();
-    fqdncache_init();
-    parseEtcHosts();
-#if USE_DNSSERVERS
-    dnsInit();
-#else
-    idnsInit();
-#endif
-    redirectInit();
-    authenticateInit(&Config.authConfig);
-    externalAclInit();
-    useragentOpenLog();
-    refererOpenLog();
-    httpHeaderInitModule();	/* must go before any header processing (e.g. the one in errorInitialize) */
-    httpReplyInitModule();	/* must go before accepting replies */
-    errorInitialize();
-    accessLogInit();
-#if USE_IDENT
-    identInit();
-#endif
-#ifdef SQUID_SNMP
-    snmpInit();
-#endif
-#if MALLOC_DBG
-    malloc_debug(0, malloc_debug_level);
-#endif
-
-    if (!configured_once) {
-#if USE_UNLINKD
-	unlinkdInit();
-#endif
-	urlInitialize();
-	cachemgrInit();
-	statInit();
-	storeInit();
-	mainSetCwd();
-	/* after this point we want to see the mallinfo() output */
-	do_mallinfo = 1;
-	mimeInit(Config.mimeTablePathname);
-	pconnInit();
-	refreshInit();
-#if DELAY_POOLS
-	delayPoolsInit();
-#endif
-	fwdInit();
-    }
-#if USE_WCCP
-    wccpInit();
-#endif
-    serverConnectionsOpen();
-    if (theOutIcpConnection >= 0) {
-	if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
-	    neighbors_open(theOutIcpConnection);
-	else
-	    debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
-    }
-    if (Config.chroot_dir)
-	no_suid();
-    if (!configured_once)
-	writePidFile();		/* write PID file */
-
-#ifdef _SQUID_LINUX_THREADS_
-    squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
-    squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
-#else
-    squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
-    squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
-#endif
-    squid_signal(SIGHUP, reconfigure, SA_RESTART);
-    squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
-    squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
-    memCheckInit();
-    debug(1, 1) ("Ready to serve requests.\n");
-    if (!configured_once) {
-	eventAdd("storeMaintain", storeMaintainSwapSpace, NULL, 1.0, 1);
-	if (Config.onoff.announce)
-	    eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
-	eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
-	eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
-#if USE_XPROF_STATS
-	eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
-#endif
-	eventAdd("memPoolCleanIdlePools", memPoolCleanIdlePools, NULL, 15.0, 1);
-    }
-    configured_once = 1;
-}
-
-int
-main(int argc, char **argv)
-{
-    int errcount = 0;
-    int n;			/* # of GC'd objects */
-    time_t loop_delay;
-    mode_t oldmask;
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-    int WIN32_init_err;
-#endif
-
-    debug_log = stderr;
-    if (FD_SETSIZE < Squid_MaxFD)
-	Squid_MaxFD = FD_SETSIZE;
-
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-    if ((WIN32_init_err = WIN32_Subsystem_Init()))
-	return WIN32_init_err;
-#endif
-
-    /* call mallopt() before anything else */
-#if HAVE_MALLOPT
-#ifdef M_GRAIN
-    /* Round up all sizes to a multiple of this */
-    mallopt(M_GRAIN, 16);
-#endif
-#ifdef M_MXFAST
-    /* biggest size that is considered a small block */
-    mallopt(M_MXFAST, 256);
-#endif
-#ifdef M_NBLKS
-    /* allocate this many small blocks at once */
-    mallopt(M_NLBLKS, 32);
-#endif
-#endif /* HAVE_MALLOPT */
-
-    /*
-     * The plan here is to set the umask to 007 (deny others for
-     * read,write,execute), but only if the umask is not already
-     * set.  Unfortunately, there is no way to get the current
-     * umask value without setting it.
-     */
-    oldmask = umask(S_IRWXO);
-    if (oldmask)
-	umask(oldmask);
-
-    memset(&local_addr, '\0', sizeof(struct in_addr));
-    safe_inet_addr(localhost, &local_addr);
-    memset(&any_addr, '\0', sizeof(struct in_addr));
-    safe_inet_addr("0.0.0.0", &any_addr);
-    memset(&no_addr, '\0', sizeof(struct in_addr));
-    safe_inet_addr("255.255.255.255", &no_addr);
-    squid_srandom(time(NULL));
-
-    getCurrentTime();
-    squid_start = current_time;
-    failure_notify = fatal_dump;
-
-    mainParseOptions(argc, argv);
-
-    /* parse configuration file
-     * note: in "normal" case this used to be called from mainInitialize() */
-    {
-	int parse_err;
-	if (!ConfigFile)
-	    ConfigFile = xstrdup(DefaultConfigFile);
-	assert(!configured_once);
-#if USE_LEAKFINDER
-	leakInit();
-#endif
-	memInit();
-	cbdataInit();
-	eventInit();		/* eventInit() is required for config parsing */
-	storeFsInit();		/* required for config parsing */
-	authenticateSchemeInit();	/* required for config parsign */
-	parse_err = parseConfigFile(ConfigFile);
-
-	if (opt_parse_cfg_only)
-	    return parse_err;
-    }
-    if (-1 == opt_send_signal)
-	if (checkRunningPid())
-	    exit(1);
-
-#if TEST_ACCESS
-    comm_init();
-    comm_select_init();
-    mainInitialize();
-    test_access();
-    return 0;
-#endif
-
-    /* send signal to running copy and exit */
-    if (opt_send_signal != -1) {
-	/* chroot if configured to run inside chroot */
-	if (Config.chroot_dir && chroot(Config.chroot_dir)) {
-	    fatal("failed to chroot");
-	}
-	sendSignal();
-	/* NOTREACHED */
-    }
-    if (opt_create_swap_dirs) {
-	/* chroot if configured to run inside chroot */
-	if (Config.chroot_dir && chroot(Config.chroot_dir)) {
-	    fatal("failed to chroot");
-	}
-	setEffectiveUser();
-	debug(0, 0) ("Creating Swap Directories\n");
-	storeCreateSwapDirectories();
-	return 0;
-    }
-    if (!opt_no_daemon)
-	watch_child(argv);
-    setMaxFD();
-
-    if (opt_catch_signals)
-	for (n = Squid_MaxFD; n > 2; n--)
-	    close(n);
-
-    /* init comm module */
-    comm_init();
-    comm_select_init();
-
-    if (opt_no_daemon) {
-	/* we have to init fdstat here. */
-	fd_open(0, FD_LOG, "stdin");
-	fd_open(1, FD_LOG, "stdout");
-	fd_open(2, FD_LOG, "stderr");
-    }
-    mainInitialize();
-
-    /* main loop */
-    for (;;) {
-	if (do_reconfigure) {
-	    mainReconfigure();
-	    do_reconfigure = 0;
-	} else if (do_rotate) {
-	    mainRotate();
-	    do_rotate = 0;
-	} else if (do_shutdown) {
-	    time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
-	    debug(1, 1) ("Preparing for shutdown after %d requests\n",
-		statCounter.client_http.requests);
-	    debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
-		(int) wait);
-	    do_shutdown = 0;
-	    shutting_down = 1;
-	    serverConnectionsClose();
-#if USE_DNSSERVERS
-	    dnsShutdown();
-#else
-	    idnsShutdown();
-#endif
-	    redirectShutdown();
-	    externalAclShutdown();
-	    eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
-	}
-	eventRun();
-	if ((loop_delay = eventNextTime()) < 0)
-	    loop_delay = 0;
-	switch (comm_select(loop_delay)) {
-	case COMM_OK:
-	    errcount = 0;	/* reset if successful */
-	    break;
-	case COMM_ERROR:
-	    errcount++;
-	    debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
-	    if (errcount == 10)
-		fatal_dump("Select Loop failed!");
-	    break;
-	case COMM_TIMEOUT:
-	    break;
-	case COMM_SHUTDOWN:
-	    SquidShutdown(NULL);
-	    break;
-	default:
-	    fatal_dump("MAIN: Internal error -- this should never happen.");
-	    break;
-	}
-    }
-    /* NOTREACHED */
-    return 0;
-}
-
-static void
-sendSignal(void)
-{
-    pid_t pid;
-    debug_log = stderr;
-    pid = readPidFile();
-    if (pid > 1) {
-	if (kill(pid, opt_send_signal) &&
-	/* ignore permissions if just running check */
-	    !(opt_send_signal == 0 && errno == EPERM)) {
-	    fprintf(stderr, "%s: ERROR: Could not send ", appname);
-	    fprintf(stderr, "signal %d to process %d: %s\n",
-		opt_send_signal, (int) pid, xstrerror());
-	    exit(1);
-	}
-    } else {
-	fprintf(stderr, "%s: ERROR: No running copy\n", appname);
-	exit(1);
-    }
-    /* signal successfully sent */
-    exit(0);
-}
-
-/*
- * This function is run when Squid is in daemon mode, just
- * before the parent forks and starts up the child process.
- * It can be used for admin-specific tasks, such as notifying
- * someone that Squid is (re)started.
- */
-static void
-mainStartScript(const char *prog)
-{
-    char script[SQUID_MAXPATHLEN];
-    char *t;
-    size_t sl = 0;
-    pid_t cpid;
-    pid_t rpid;
-    xstrncpy(script, prog, MAXPATHLEN);
-    if ((t = strrchr(script, '/'))) {
-	*(++t) = '\0';
-	sl = strlen(script);
-    }
-    xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
-    if ((cpid = fork()) == 0) {
-	/* child */
-	execl(script, squid_start_script, 0);
-	_exit(0);
-    } else {
-	do {
-#ifdef _SQUID_NEXT_
-	    union wait status;
-	    rpid = wait3(&status, 0, NULL);
-#else
-	    int status;
-	    rpid = waitpid(-1, &status, 0);
-#endif
-	} while (rpid != cpid);
-    }
-}
-
-static int
-checkRunningPid(void)
-{
-    pid_t pid;
-    debug_log = stderr;
-    pid = readPidFile();
-    if (pid < 2)
-	return 0;
-    if (kill(pid, 0) < 0)
-	return 0;
-    debug(0, 0) ("Squid is already running!  Process ID %d\n", pid);
-    return 1;
-}
-
-static void
-watch_child(char *argv[])
-{
-    char *prog;
-    int failcount = 0;
-    time_t start;
-    time_t stop;
-#ifdef _SQUID_NEXT_
-    union wait status;
-#else
-    int status;
-#endif
-    pid_t pid;
-    int i;
-    int nullfd;
-    if (*(argv[0]) == '(')
-	return;
-    openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
-    if ((pid = fork()) < 0)
-	syslog(LOG_ALERT, "fork failed: %s", xstrerror());
-    else if (pid > 0)
-	exit(0);
-    if (setsid() < 0)
-	syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
-    closelog();
-#ifdef TIOCNOTTY
-    if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
-	ioctl(i, TIOCNOTTY, NULL);
-	close(i);
-    }
-#endif
-
-
-    /*
-     * RBCOLLINS - if cygwin stackdumps when squid is run without
-     * -N, check the cygwin1.dll version, it needs to be AT LEAST
-     * 1.1.3.  execvp had a bit overflow error in a loop..
-     */
-    /* Connect stdio to /dev/null in daemon mode */
-    nullfd = open("/dev/null", O_RDWR | O_TEXT);
-    dup2(nullfd, 0);
-    if (opt_debug_stderr < 0) {
-	dup2(nullfd, 1);
-	dup2(nullfd, 2);
-    }
-    /* Close all else */
-    for (i = 3; i < Squid_MaxFD; i++)
-	close(i);
-    for (;;) {
-	mainStartScript(argv[0]);
-	if ((pid = fork()) == 0) {
-	    /* child */
-	    openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
-	    prog = xstrdup(argv[0]);
-	    argv[0] = xstrdup("(squid)");
-	    execvp(prog, argv);
-	    syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
-	}
-	/* parent */
-	openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
-	syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
-	time(&start);
-	squid_signal(SIGINT, SIG_IGN, SA_RESTART);
-#ifdef _SQUID_NEXT_
-	pid = wait3(&status, 0, NULL);
-#else
-	pid = waitpid(-1, &status, 0);
-#endif
-	time(&stop);
-	if (WIFEXITED(status)) {
-	    syslog(LOG_NOTICE,
-		"Squid Parent: child process %d exited with status %d",
-		pid, WEXITSTATUS(status));
-	} else if (WIFSIGNALED(status)) {
-	    syslog(LOG_NOTICE,
-		"Squid Parent: child process %d exited due to signal %d",
-		pid, WTERMSIG(status));
-	} else {
-	    syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
-	}
-	if (stop - start < 10)
-	    failcount++;
-	else
-	    failcount = 0;
-	if (failcount == 5) {
-	    syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
-	    exit(1);
-	}
-	if (WIFEXITED(status))
-	    if (WEXITSTATUS(status) == 0)
-		exit(0);
-	if (WIFSIGNALED(status)) {
-	    switch (WTERMSIG(status)) {
-	    case SIGKILL:
-		exit(0);
-		break;
-	    default:
-		break;
-	    }
-	}
-	squid_signal(SIGINT, SIG_DFL, SA_RESTART);
-	sleep(3);
-    }
-    /* NOTREACHED */
-}
-
-static void
-SquidShutdown(void *unused)
-{
-    debug(1, 1) ("Shutting down...\n");
-    if (Config.pidFilename && strcmp(Config.pidFilename, "none")) {
-	enter_suid();
-	safeunlink(Config.pidFilename, 0);
-	leave_suid();
-    }
-    icpConnectionClose();
-#if USE_HTCP
-    htcpSocketClose();
-#endif
-#ifdef SQUID_SNMP
-    snmpConnectionClose();
-#endif
-#if USE_WCCP
-    wccpConnectionClose();
-#endif
-    releaseServerSockets();
-    commCloseAllSockets();
-    authenticateShutdown();
-#if USE_UNLINKD
-    unlinkdClose();
-#endif
-    storeDirSync();		/* Flush pending object writes/unlinks */
-    storeDirWriteCleanLogs(0);
-    PrintRusage();
-    dumpMallocStats();
-    storeDirSync();		/* Flush log writes */
-    storeLogClose();
-    accessLogClose();
-    useragentLogClose();
-#if WIP_FWD_LOG
-    fwdUninit();
-#endif
-    storeDirSync();		/* Flush log close */
-#if PURIFY || XMALLOC_TRACE
-    storeFsDone();
-    configFreeMemory();
-    storeFreeMemory();
-    /*stmemFreeMemory(); */
-    netdbFreeMemory();
-    ipcacheFreeMemory();
-    fqdncacheFreeMemory();
-    asnFreeMemory();
-    clientdbFreeMemory();
-    httpHeaderCleanModule();
-    statFreeMemory();
-    eventFreeMemory();
-    mimeFreeMemory();
-    errorClean();
-#endif
-#if !XMALLOC_TRACE
-    if (opt_no_daemon) {
-	file_close(0);
-	file_close(1);
-	file_close(2);
-    }
-#endif
-    fdDumpOpen();
-    fdFreeMemory();
-    memClean();
-#if XMALLOC_TRACE
-    xmalloc_find_leaks();
-    debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
-#endif
-#if MEM_GEN_TRACE
-    log_trace_done();
-#endif
-    debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
-	version_string);
-    if (debug_log)
-	fclose(debug_log);
-    exit(0);
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/main.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,998 @@
+
+/*
+ * $Id: main.cc,v 1.1.2.1 2002/10/03 01:04:35 rbcollins Exp $
+ *
+ * DEBUG: section 1     Startup and Main Loop
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "authenticate.h"
+
+/* for error reporting from xmalloc and friends */
+extern void (*failure_notify) (const char *);
+
+static int opt_send_signal = -1;
+static int opt_no_daemon = 0;
+static int opt_parse_cfg_only = 0;
+static int icpPortNumOverride = 1;	/* Want to detect "-u 0" */
+static int configured_once = 0;
+#if MALLOC_DBG
+static int malloc_debug_level = 0;
+#endif
+static volatile int do_reconfigure = 0;
+static volatile int do_rotate = 0;
+static volatile int do_shutdown = 0;
+
+static void mainRotate(void);
+static void mainReconfigure(void);
+static SIGHDLR rotate_logs;
+static SIGHDLR reconfigure;
+static void mainInitialize(void);
+static void usage(void);
+static void mainParseOptions(int, char **);
+static void sendSignal(void);
+static void serverConnectionsOpen(void);
+static void watch_child(char **);
+static void setEffectiveUser(void);
+#if MEM_GEN_TRACE
+extern void log_trace_done();
+extern void log_trace_init(char *);
+#endif
+static EVH SquidShutdown;
+static void mainSetCwd(void);
+static int checkRunningPid(void);
+
+static const char *squid_start_script = "squid_start";
+
+#if TEST_ACCESS
+#include "test_access.c"
+#endif
+
+static void
+usage(void)
+{
+    fprintf(stderr,
+	"Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n"
+	"       -a port   Specify HTTP port number (default: %d).\n"
+	"       -d level  Write debugging to stderr also.\n"
+	"       -f file   Use given config-file instead of\n"
+	"                 %s\n"
+	"       -h        Print help message.\n"
+	"       -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
+	"                 Parse configuration file, then send signal to \n"
+	"                 running copy (except -k parse) and exit.\n"
+	"       -s        Enable logging to syslog.\n"
+	"       -u port   Specify ICP port number (default: %d), disable with 0.\n"
+	"       -v        Print version.\n"
+	"       -z        Create swap directories\n"
+	"       -C        Do not catch fatal signals.\n"
+	"       -D        Disable initial DNS tests.\n"
+	"       -F        Don't serve any requests until store is rebuilt.\n"
+	"       -N        No daemon mode.\n"
+	"       -R        Do not set REUSEADDR on port.\n"
+	"       -S        Double-check swap during rebuild.\n"
+	"       -V        Virtual host httpd-accelerator.\n"
+	"       -X        Force full debugging.\n"
+	"       -Y        Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
+	appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
+    exit(1);
+}
+
+static void
+mainParseOptions(int argc, char *argv[])
+{
+    extern char *optarg;
+    int c;
+
+    while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) {
+	switch (c) {
+	case 'C':
+	    opt_catch_signals = 0;
+	    break;
+	case 'D':
+	    opt_dns_tests = 0;
+	    break;
+	case 'F':
+	    opt_foreground_rebuild = 1;
+	    break;
+	case 'N':
+	    opt_no_daemon = 1;
+	    break;
+	case 'R':
+	    opt_reuseaddr = 0;
+	    break;
+	case 'S':
+	    opt_store_doublecheck = 1;
+	    break;
+	case 'V':
+	    vhost_mode = 1;
+	    break;
+	case 'X':
+	    /* force full debugging */
+	    sigusr2_handle(SIGUSR2);
+	    break;
+	case 'Y':
+	    opt_reload_hit_only = 1;
+	    break;
+	case 'a':
+	    parse_sockaddr_in_list_token(&Config.Sockaddr.http, optarg);
+	    break;
+	case 'd':
+	    opt_debug_stderr = atoi(optarg);
+	    break;
+	case 'f':
+	    xfree(ConfigFile);
+	    ConfigFile = xstrdup(optarg);
+	    break;
+	case 'h':
+	    usage();
+	    break;
+	case 'k':
+	    if ((int) strlen(optarg) < 1)
+		usage();
+	    if (!strncmp(optarg, "reconfigure", strlen(optarg)))
+		opt_send_signal = SIGHUP;
+	    else if (!strncmp(optarg, "rotate", strlen(optarg)))
+#ifdef _SQUID_LINUX_THREADS_
+		opt_send_signal = SIGQUIT;
+#else
+		opt_send_signal = SIGUSR1;
+#endif
+	    else if (!strncmp(optarg, "debug", strlen(optarg)))
+#ifdef _SQUID_LINUX_THREADS_
+		opt_send_signal = SIGTRAP;
+#else
+		opt_send_signal = SIGUSR2;
+#endif
+	    else if (!strncmp(optarg, "shutdown", strlen(optarg)))
+		opt_send_signal = SIGTERM;
+	    else if (!strncmp(optarg, "interrupt", strlen(optarg)))
+		opt_send_signal = SIGINT;
+	    else if (!strncmp(optarg, "kill", strlen(optarg)))
+		opt_send_signal = SIGKILL;
+	    else if (!strncmp(optarg, "check", strlen(optarg)))
+		opt_send_signal = 0;	/* SIGNULL */
+	    else if (!strncmp(optarg, "parse", strlen(optarg)))
+		opt_parse_cfg_only = 1;		/* parse cfg file only */
+	    else
+		usage();
+	    break;
+	case 'm':
+	    if (optarg) {
+#if MALLOC_DBG
+		malloc_debug_level = atoi(optarg);
+		/* NOTREACHED */
+		break;
+#else
+		fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
+		/* NOTREACHED */
+#endif
+	    } else {
+#if XMALLOC_TRACE
+		xmalloc_trace = !xmalloc_trace;
+#else
+		fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
+#endif
+	    }
+	case 's':
+#if HAVE_SYSLOG
+	    opt_syslog_enable = 1;
+	    break;
+#else
+	    fatal("Logging to syslog not available on this platform");
+	    /* NOTREACHED */
+#endif
+	case 'u':
+	    icpPortNumOverride = atoi(optarg);
+	    if (icpPortNumOverride < 0)
+		icpPortNumOverride = 0;
+	    break;
+	case 'v':
+	    printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
+	    exit(0);
+	    /* NOTREACHED */
+	case 'z':
+	    opt_create_swap_dirs = 1;
+	    break;
+	case '?':
+	default:
+	    usage();
+	    break;
+	}
+    }
+}
+
+/* ARGSUSED */
+static void
+rotate_logs(int sig)
+{
+    do_rotate = 1;
+#if !HAVE_SIGACTION
+    signal(sig, rotate_logs);
+#endif
+}
+
+/* ARGSUSED */
+static void
+reconfigure(int sig)
+{
+    do_reconfigure = 1;
+#if !HAVE_SIGACTION
+    signal(sig, reconfigure);
+#endif
+}
+
+void
+shut_down(int sig)
+{
+    do_shutdown = sig == SIGINT ? -1 : 1;
+#ifdef KILL_PARENT_OPT
+    if (getppid() > 1) {
+	debug(1, 1) ("Killing RunCache, pid %d\n", getppid());
+	if (kill(getppid(), sig) < 0)
+	    debug(1, 1) ("kill %d: %s\n", getppid(), xstrerror());
+    }
+#endif
+#if SA_RESETHAND == 0
+    signal(SIGTERM, SIG_DFL);
+    signal(SIGINT, SIG_DFL);
+#endif
+}
+
+static void
+serverConnectionsOpen(void)
+{
+    clientOpenListenSockets();
+    icpConnectionsOpen();
+#if USE_HTCP
+    htcpInit();
+#endif
+#ifdef SQUID_SNMP
+    snmpConnectionOpen();
+#endif
+#if USE_WCCP
+    wccpConnectionOpen();
+#endif
+    clientdbInit();
+    icmpOpen();
+    netdbInit();
+    asnInit();
+    peerSelectInit();
+#if USE_CARP
+    carpInit();
+#endif
+}
+
+void
+serverConnectionsClose(void)
+{
+    assert(shutting_down || reconfiguring);
+    clientHttpConnectionsClose();
+    icpConnectionShutdown();
+#if USE_HTCP
+    htcpSocketShutdown();
+#endif
+    icmpClose();
+#ifdef SQUID_SNMP
+    snmpConnectionShutdown();
+#endif
+#if USE_WCCP
+    wccpConnectionShutdown();
+#endif
+    asnFreeMemory();
+}
+
+static void
+mainReconfigure(void)
+{
+    debug(1, 1) ("Restarting Squid Cache (version %s)...\n", version_string);
+    reconfiguring = 1;
+    /* Already called serverConnectionsClose and ipcacheShutdownServers() */
+    serverConnectionsClose();
+    icpConnectionClose();
+#if USE_HTCP
+    htcpSocketClose();
+#endif
+#ifdef SQUID_SNMP
+    snmpConnectionClose();
+#endif
+#if USE_WCCP
+    wccpConnectionClose();
+#endif
+#if USE_DNSSERVERS
+    dnsShutdown();
+#else
+    idnsShutdown();
+#endif
+    redirectShutdown();
+    authenticateShutdown();
+    externalAclShutdown();
+    storeDirCloseSwapLogs();
+    errorClean();
+    enter_suid();		/* root to read config file */
+    parseConfigFile(ConfigFile);
+    setEffectiveUser();
+    _db_init(Config.Log.log, Config.debugOptions);
+    ipcache_restart();		/* clear stuck entries */
+    authenticateUserCacheRestart();	/* clear stuck ACL entries */
+    fqdncache_restart();	/* sigh, fqdncache too */
+    parseEtcHosts();
+    errorInitialize();		/* reload error pages */
+#if USE_DNSSERVERS
+    dnsInit();
+#else
+    idnsInit();
+#endif
+    redirectInit();
+    authenticateInit(&Config.authConfiguration);
+    externalAclInit();
+#if USE_WCCP
+    wccpInit();
+#endif
+    serverConnectionsOpen();
+    if (theOutIcpConnection >= 0) {
+	if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
+	    neighbors_open(theOutIcpConnection);
+	else
+	    debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
+    }
+    storeDirOpenSwapLogs();
+    mimeInit(Config.mimeTablePathname);
+    writePidFile();		/* write PID file */
+    debug(1, 1) ("Ready to serve requests.\n");
+    reconfiguring = 0;
+}
+
+static void
+mainRotate(void)
+{
+    icmpClose();
+#if USE_DNSSERVERS
+    dnsShutdown();
+#endif
+    redirectShutdown();
+    authenticateShutdown();
+    externalAclShutdown();
+    _db_rotate_log();		/* cache.log */
+    storeDirWriteCleanLogs(1);
+    storeLogRotate();		/* store.log */
+    accessLogRotate();		/* access.log */
+    useragentRotateLog();	/* useragent.log */
+    refererRotateLog();		/* referer.log */
+#if WIP_FWD_LOG
+    fwdLogRotate();
+#endif
+    icmpOpen();
+#if USE_DNSSERVERS
+    dnsInit();
+#endif
+    redirectInit();
+    authenticateInit(&Config.authConfiguration);
+    externalAclInit();
+}
+
+static void
+setEffectiveUser(void)
+{
+    leave_suid();		/* Run as non privilegied user */
+#ifdef _SQUID_OS2_
+    return;
+#endif
+    if (geteuid() == 0) {
+	debug(0, 0) ("Squid is not safe to run as root!  If you must\n");
+	debug(0, 0) ("start Squid as root, then you must configure\n");
+	debug(0, 0) ("it to run as a non-priveledged user with the\n");
+	debug(0, 0) ("'cache_effective_user' option in the config file.\n");
+	fatal("Don't run Squid as root, set 'cache_effective_user'!");
+    }
+}
+
+static void
+mainSetCwd(void)
+{
+    char pathbuf[MAXPATHLEN];
+    if (Config.coredump_dir) {
+	if (0 == strcmp("none", Config.coredump_dir)) {
+	    (void) 0;
+	} else if (chdir(Config.coredump_dir) == 0) {
+	    debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
+	    return;
+	} else {
+	    debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
+	}
+    }
+    /* If we don't have coredump_dir or couldn't cd there, report current dir */
+    if (getcwd(pathbuf, MAXPATHLEN)) {
+	debug(0, 1) ("Current Directory is %s\n", pathbuf);
+    } else {
+	debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
+    }
+}
+
+static void
+mainInitialize(void)
+{
+    /* chroot if configured to run inside chroot */
+    if (Config.chroot_dir && chroot(Config.chroot_dir)) {
+	fatal("failed to chroot");
+    }
+    if (opt_catch_signals) {
+	squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
+	squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
+    }
+    squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
+    squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
+
+    setEffectiveUser();
+    if (icpPortNumOverride != 1)
+	Config.Port.icp = (u_short) icpPortNumOverride;
+
+    _db_init(Config.Log.log, Config.debugOptions);
+    fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
+#if MEM_GEN_TRACE
+    log_trace_init("/tmp/squid.alloc");
+#endif
+    debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
+	version_string,
+	CONFIG_HOST_TYPE);
+    debug(1, 1) ("Process ID %d\n", (int) getpid());
+    debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
+
+    if (!configured_once)
+	disk_init();		/* disk_init must go before ipcache_init() */
+    ipcache_init();
+    fqdncache_init();
+    parseEtcHosts();
+#if USE_DNSSERVERS
+    dnsInit();
+#else
+    idnsInit();
+#endif
+    redirectInit();
+    authenticateInit(&Config.authConfiguration);
+    externalAclInit();
+    useragentOpenLog();
+    refererOpenLog();
+    httpHeaderInitModule();	/* must go before any header processing (e.g. the one in errorInitialize) */
+    httpReplyInitModule();	/* must go before accepting replies */
+    errorInitialize();
+    accessLogInit();
+#if USE_IDENT
+    identInit();
+#endif
+#ifdef SQUID_SNMP
+    snmpInit();
+#endif
+#if MALLOC_DBG
+    malloc_debug(0, malloc_debug_level);
+#endif
+
+    if (!configured_once) {
+#if USE_UNLINKD
+	unlinkdInit();
+#endif
+	urlInitialize();
+	cachemgrInit();
+	statInit();
+	storeInit();
+	mainSetCwd();
+	/* after this point we want to see the mallinfo() output */
+	do_mallinfo = 1;
+	mimeInit(Config.mimeTablePathname);
+	pconnInit();
+	refreshInit();
+#if DELAY_POOLS
+	delayPoolsInit();
+#endif
+	fwdInit();
+    }
+#if USE_WCCP
+    wccpInit();
+#endif
+    serverConnectionsOpen();
+    if (theOutIcpConnection >= 0) {
+	if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
+	    neighbors_open(theOutIcpConnection);
+	else
+	    debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
+    }
+    if (Config.chroot_dir)
+	no_suid();
+    if (!configured_once)
+	writePidFile();		/* write PID file */
+
+#ifdef _SQUID_LINUX_THREADS_
+    squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
+    squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
+#else
+    squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
+    squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
+#endif
+    squid_signal(SIGHUP, reconfigure, SA_RESTART);
+    squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+    squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+    memCheckInit();
+    debug(1, 1) ("Ready to serve requests.\n");
+    if (!configured_once) {
+	eventAdd("storeMaintain", storeMaintainSwapSpace, NULL, 1.0, 1);
+	if (Config.onoff.announce)
+	    eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
+	eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
+	eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
+#if USE_XPROF_STATS
+	eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
+#endif
+	  
+	eventAdd("memPoolCleanIdlePools", memPoolCleanIdlePools, NULL, 15.0, 1);
+    }
+    configured_once = 1;
+}
+
+int
+main(int argc, char **argv)
+{
+    int errcount = 0;
+    int n;			/* # of GC'd objects */
+    time_t loop_delay;
+    mode_t oldmask;
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+    int WIN32_init_err;
+#endif
+
+    debug_log = stderr;
+    if (FD_SETSIZE < Squid_MaxFD)
+	Squid_MaxFD = FD_SETSIZE;
+
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+    if ((WIN32_init_err = WIN32_Subsystem_Init()))
+	return WIN32_init_err;
+#endif
+
+    /* call mallopt() before anything else */
+#if HAVE_MALLOPT
+#ifdef M_GRAIN
+    /* Round up all sizes to a multiple of this */
+    mallopt(M_GRAIN, 16);
+#endif
+#ifdef M_MXFAST
+    /* biggest size that is considered a small block */
+    mallopt(M_MXFAST, 256);
+#endif
+#ifdef M_NBLKS
+    /* allocate this many small blocks at once */
+    mallopt(M_NLBLKS, 32);
+#endif
+#endif /* HAVE_MALLOPT */
+
+    /*
+     * The plan here is to set the umask to 007 (deny others for
+     * read,write,execute), but only if the umask is not already
+     * set.  Unfortunately, there is no way to get the current
+     * umask value without setting it.
+     */
+    oldmask = umask(S_IRWXO);
+    if (oldmask)
+	umask(oldmask);
+
+    memset(&local_addr, '\0', sizeof(struct in_addr));
+    safe_inet_addr(localhost, &local_addr);
+    memset(&any_addr, '\0', sizeof(struct in_addr));
+    safe_inet_addr("0.0.0.0", &any_addr);
+    memset(&no_addr, '\0', sizeof(struct in_addr));
+    safe_inet_addr("255.255.255.255", &no_addr);
+    squid_srandom(time(NULL));
+
+    getCurrentTime();
+    squid_start = current_time;
+    failure_notify = fatal_dump;
+
+    mainParseOptions(argc, argv);
+
+    /* parse configuration file
+     * note: in "normal" case this used to be called from mainInitialize() */
+    {
+	int parse_err;
+	if (!ConfigFile)
+	    ConfigFile = xstrdup(DefaultConfigFile);
+	assert(!configured_once);
+#if USE_LEAKFINDER
+	leakInit();
+#endif
+	memInit();
+	cbdataInit();
+	eventInit();		/* eventInit() is required for config parsing */
+	storeFsInit();		/* required for config parsing */
+	authenticateSchemeInit();	/* required for config parsign */
+	parse_err = parseConfigFile(ConfigFile);
+
+	if (opt_parse_cfg_only)
+	    return parse_err;
+    }
+    if (-1 == opt_send_signal)
+	if (checkRunningPid())
+	    exit(1);
+
+#if TEST_ACCESS
+    comm_init();
+    comm_select_init();
+    mainInitialize();
+    test_access();
+    return 0;
+#endif
+
+    /* send signal to running copy and exit */
+    if (opt_send_signal != -1) {
+	/* chroot if configured to run inside chroot */
+	if (Config.chroot_dir && chroot(Config.chroot_dir)) {
+	    fatal("failed to chroot");
+	}
+	sendSignal();
+	/* NOTREACHED */
+    }
+    if (opt_create_swap_dirs) {
+	/* chroot if configured to run inside chroot */
+	if (Config.chroot_dir && chroot(Config.chroot_dir)) {
+	    fatal("failed to chroot");
+	}
+	setEffectiveUser();
+	debug(0, 0) ("Creating Swap Directories\n");
+	storeCreateSwapDirectories();
+	return 0;
+    }
+    if (!opt_no_daemon)
+	watch_child(argv);
+    setMaxFD();
+
+    if (opt_catch_signals)
+	for (n = Squid_MaxFD; n > 2; n--)
+	    close(n);
+
+    /* init comm module */
+    comm_init();
+    comm_select_init();
+
+    if (opt_no_daemon) {
+	/* we have to init fdstat here. */
+	fd_open(0, FD_LOG, "stdin");
+	fd_open(1, FD_LOG, "stdout");
+	fd_open(2, FD_LOG, "stderr");
+    }
+    mainInitialize();
+
+    /* main loop */
+    for (;;) {
+	if (do_reconfigure) {
+	    mainReconfigure();
+	    do_reconfigure = 0;
+	} else if (do_rotate) {
+	    mainRotate();
+	    do_rotate = 0;
+	} else if (do_shutdown) {
+	    time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
+	    debug(1, 1) ("Preparing for shutdown after %d requests\n",
+		statCounter.client_http.requests);
+	    debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
+		(int) wait);
+	    do_shutdown = 0;
+	    shutting_down = 1;
+	    serverConnectionsClose();
+#if USE_DNSSERVERS
+	    dnsShutdown();
+#else
+	    idnsShutdown();
+#endif
+	    redirectShutdown();
+	    externalAclShutdown();
+	    eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
+	}
+	eventRun();
+	if ((loop_delay = eventNextTime()) < 0)
+	    loop_delay = 0;
+	switch (comm_select(loop_delay)) {
+	case COMM_OK:
+	    errcount = 0;	/* reset if successful */
+	    break;
+	case COMM_ERROR:
+	    errcount++;
+	    debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
+	    if (errcount == 10)
+		fatal_dump("Select Loop failed!");
+	    break;
+	case COMM_TIMEOUT:
+	    break;
+	case COMM_SHUTDOWN:
+	    SquidShutdown(NULL);
+	    break;
+	default:
+	    fatal_dump("MAIN: Internal error -- this should never happen.");
+	    break;
+	}
+    }
+    /* NOTREACHED */
+    return 0;
+}
+
+static void
+sendSignal(void)
+{
+    pid_t pid;
+    debug_log = stderr;
+    pid = readPidFile();
+    if (pid > 1) {
+	if (kill(pid, opt_send_signal) &&
+	/* ignore permissions if just running check */
+	    !(opt_send_signal == 0 && errno == EPERM)) {
+	    fprintf(stderr, "%s: ERROR: Could not send ", appname);
+	    fprintf(stderr, "signal %d to process %d: %s\n",
+		opt_send_signal, (int) pid, xstrerror());
+	    exit(1);
+	}
+    } else {
+	fprintf(stderr, "%s: ERROR: No running copy\n", appname);
+	exit(1);
+    }
+    /* signal successfully sent */
+    exit(0);
+}
+
+/*
+ * This function is run when Squid is in daemon mode, just
+ * before the parent forks and starts up the child process.
+ * It can be used for admin-specific tasks, such as notifying
+ * someone that Squid is (re)started.
+ */
+static void
+mainStartScript(const char *prog)
+{
+    char script[SQUID_MAXPATHLEN];
+    char *t;
+    size_t sl = 0;
+    pid_t cpid;
+    pid_t rpid;
+    xstrncpy(script, prog, MAXPATHLEN);
+    if ((t = strrchr(script, '/'))) {
+	*(++t) = '\0';
+	sl = strlen(script);
+    }
+    xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
+    if ((cpid = fork()) == 0) {
+	/* child */
+	execl(script, squid_start_script, 0);
+	_exit(0);
+    } else {
+	do {
+#ifdef _SQUID_NEXT_
+	    union wait status;
+	    rpid = wait3(&status, 0, NULL);
+#else
+	    int status;
+	    rpid = waitpid(-1, &status, 0);
+#endif
+	} while (rpid != cpid);
+    }
+}
+
+static int
+checkRunningPid(void)
+{
+    pid_t pid;
+    debug_log = stderr;
+    pid = readPidFile();
+    if (pid < 2)
+	return 0;
+    if (kill(pid, 0) < 0)
+	return 0;
+    debug(0, 0) ("Squid is already running!  Process ID %d\n", pid);
+    return 1;
+}
+
+static void
+watch_child(char *argv[])
+{
+    char *prog;
+    int failcount = 0;
+    time_t start;
+    time_t stop;
+#ifdef _SQUID_NEXT_
+    union wait status;
+#else
+    int status;
+#endif
+    pid_t pid;
+    int i;
+    int nullfd;
+    if (*(argv[0]) == '(')
+	return;
+    openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+    if ((pid = fork()) < 0)
+	syslog(LOG_ALERT, "fork failed: %s", xstrerror());
+    else if (pid > 0)
+	exit(0);
+    if (setsid() < 0)
+	syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
+    closelog();
+#ifdef TIOCNOTTY
+    if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
+	ioctl(i, TIOCNOTTY, NULL);
+	close(i);
+    }
+#endif
+
+
+    /*
+     * RBCOLLINS - if cygwin stackdumps when squid is run without
+     * -N, check the cygwin1.dll version, it needs to be AT LEAST
+     * 1.1.3.  execvp had a bit overflow error in a loop..
+     */
+    /* Connect stdio to /dev/null in daemon mode */
+    nullfd = open("/dev/null", O_RDWR | O_TEXT);
+    dup2(nullfd, 0);
+    if (opt_debug_stderr < 0) {
+	dup2(nullfd, 1);
+	dup2(nullfd, 2);
+    }
+    /* Close all else */
+    for (i = 3; i < Squid_MaxFD; i++)
+	close(i);
+    for (;;) {
+	mainStartScript(argv[0]);
+	if ((pid = fork()) == 0) {
+	    /* child */
+	    openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+	    prog = xstrdup(argv[0]);
+	    argv[0] = xstrdup("(squid)");
+	    execvp(prog, argv);
+	    syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
+	}
+	/* parent */
+	openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+	syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
+	time(&start);
+	squid_signal(SIGINT, SIG_IGN, SA_RESTART);
+#ifdef _SQUID_NEXT_
+	pid = wait3(&status, 0, NULL);
+#else
+	pid = waitpid(-1, &status, 0);
+#endif
+	time(&stop);
+	if (WIFEXITED(status)) {
+	    syslog(LOG_NOTICE,
+		"Squid Parent: child process %d exited with status %d",
+		pid, WEXITSTATUS(status));
+	} else if (WIFSIGNALED(status)) {
+	    syslog(LOG_NOTICE,
+		"Squid Parent: child process %d exited due to signal %d",
+		pid, WTERMSIG(status));
+	} else {
+	    syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
+	}
+	if (stop - start < 10)
+	    failcount++;
+	else
+	    failcount = 0;
+	if (failcount == 5) {
+	    syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
+	    exit(1);
+	}
+	if (WIFEXITED(status))
+	    if (WEXITSTATUS(status) == 0)
+		exit(0);
+	if (WIFSIGNALED(status)) {
+	    switch (WTERMSIG(status)) {
+	    case SIGKILL:
+		exit(0);
+		break;
+	    default:
+		break;
+	    }
+	}
+	squid_signal(SIGINT, SIG_DFL, SA_RESTART);
+	sleep(3);
+    }
+    /* NOTREACHED */
+}
+
+static void
+SquidShutdown(void *unused)
+{
+    debug(1, 1) ("Shutting down...\n");
+    if (Config.pidFilename && strcmp(Config.pidFilename, "none")) {
+	enter_suid();
+	safeunlink(Config.pidFilename, 0);
+	leave_suid();
+    }
+    icpConnectionClose();
+#if USE_HTCP
+    htcpSocketClose();
+#endif
+#ifdef SQUID_SNMP
+    snmpConnectionClose();
+#endif
+#if USE_WCCP
+    wccpConnectionClose();
+#endif
+    releaseServerSockets();
+    commCloseAllSockets();
+    authenticateShutdown();
+#if USE_UNLINKD
+    unlinkdClose();
+#endif
+    storeDirSync();		/* Flush pending object writes/unlinks */
+    storeDirWriteCleanLogs(0);
+    PrintRusage();
+    dumpMallocStats();
+    storeDirSync();		/* Flush log writes */
+    storeLogClose();
+    accessLogClose();
+    useragentLogClose();
+#if WIP_FWD_LOG
+    fwdUninit();
+#endif
+    storeDirSync();		/* Flush log close */
+#if PURIFY || XMALLOC_TRACE
+    storeFsDone();
+    configFreeMemory();
+    storeFreeMemory();
+    /*stmemFreeMemory(); */
+    netdbFreeMemory();
+    ipcacheFreeMemory();
+    fqdncacheFreeMemory();
+    asnFreeMemory();
+    clientdbFreeMemory();
+    httpHeaderCleanModule();
+    statFreeMemory();
+    eventFreeMemory();
+    mimeFreeMemory();
+    errorClean();
+#endif
+#if !XMALLOC_TRACE
+    if (opt_no_daemon) {
+	file_close(0);
+	file_close(1);
+	file_close(2);
+    }
+#endif
+    fdDumpOpen();
+    fdFreeMemory();
+    memClean();
+#if XMALLOC_TRACE
+    xmalloc_find_leaks();
+    debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
+#endif
+#if MEM_GEN_TRACE
+    log_trace_done();
+#endif
+    debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
+	version_string);
+    if (debug_log)
+	fclose(debug_log);
+    exit(0);
+}
Index: squid/src/mem.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/mem.c,v
retrieving revision 1.21
retrieving revision 1.21.6.1
diff -u -r1.21 -r1.21.6.1
--- squid/src/mem.c	15 Sep 2002 11:06:33 -0000	1.21
+++ squid/src/mem.c	3 Oct 2002 01:04:35 -0000	1.21.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: mem.c,v 1.21 2002/09/15 11:06:33 rbcollins Exp $
+ * $Id: mem.c,v 1.21.6.1 2002/10/03 01:04:35 rbcollins Exp $
  *
  * DEBUG: section 13    High Level Memory Pool Management
  * AUTHOR: Harvest Derived
@@ -349,10 +349,6 @@
     memDataInit(MEM_ACL_LIST, "acl_list", sizeof(acl_list), 0);
     memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0);
     memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0);
-    memDataInit(MEM_AUTH_USER_T, "auth_user_t",
-	sizeof(auth_user_t), 0);
-    memDataInit(MEM_AUTH_USER_HASH, "auth_user_hash_pointer",
-	sizeof(auth_user_hash_pointer), 0);
     memDataInit(MEM_ACL_PROXY_AUTH_MATCH, "acl_proxy_auth_match_cache",
 	sizeof(acl_proxy_auth_match_cache), 0);
     memDataInit(MEM_ACL_USER_DATA, "acl_user_data",
Index: squid/src/protos.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/protos.h,v
retrieving revision 1.63
retrieving revision 1.63.2.1
diff -u -r1.63 -r1.63.2.1
--- squid/src/protos.h	26 Sep 2002 21:46:06 -0000	1.63
+++ squid/src/protos.h	3 Oct 2002 01:04:35 -0000	1.63.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.63 2002/09/26 21:46:06 squidadm Exp $
+ * $Id: protos.h,v 1.63.2.1 2002/10/03 01:04:35 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -34,1144 +34,1102 @@
 #ifndef SQUID_PROTOS_H
 #define SQUID_PROTOS_H
 
-extern void accessLogLog(AccessLogEntry *);
-extern void accessLogRotate(void);
-extern void accessLogClose(void);
-extern void accessLogInit(void);
-extern void accessLogFreeMemory(AccessLogEntry * aLogEntry);
-extern const char *accessLogTime(time_t);
-extern void hierarchyNote(HierarchyLogEntry *, hier_code, const char *);
+SQUIDCEXTERN void accessLogLog(AccessLogEntry *);
+SQUIDCEXTERN void accessLogRotate(void);
+SQUIDCEXTERN void accessLogClose(void);
+SQUIDCEXTERN void accessLogInit(void);
+SQUIDCEXTERN void accessLogFreeMemory(AccessLogEntry * aLogEntry);
+SQUIDCEXTERN const char *accessLogTime(time_t);
+SQUIDCEXTERN void hierarchyNote(HierarchyLogEntry *, hier_code, const char *);
 #if FORW_VIA_DB
-extern void fvdbCountVia(const char *key);
-extern void fvdbCountForw(const char *key);
+SQUIDCEXTERN void fvdbCountVia(const char *key);
+SQUIDCEXTERN void fvdbCountForw(const char *key);
 #endif
 #if HEADERS_LOG
-extern void headersLog(int cs, int pq, method_t m, void *data);
+SQUIDCEXTERN void headersLog(int cs, int pq, method_t m, void *data);
 #endif
 char *log_quote(const char *header);
-extern int logTypeIsATcpHit(log_type);
+SQUIDCEXTERN int logTypeIsATcpHit(log_type);
 
 /* acl.c */
-extern aclCheck_t *aclChecklistCreate(const struct _acl_access *,
+SQUIDCEXTERN aclCheck_t *aclChecklistCreate(const struct _acl_access *,
     request_t *,
     const char *ident);
-extern void aclNBCheck(aclCheck_t *, PF *, void *);
-extern int aclCheckFast(const struct _acl_access *A, aclCheck_t *);
-extern void aclChecklistFree(aclCheck_t *);
-extern int aclMatchAclList(const acl_list * list, aclCheck_t * checklist);
-extern void aclDestroyAccessList(struct _acl_access **list);
-extern void aclDestroyAcls(acl **);
-extern void aclDestroyAclList(acl_list **);
-extern void aclParseAccessLine(struct _acl_access **);
-extern void aclParseAclList(acl_list **);
-extern void aclParseAclLine(acl **);
-extern int aclIsProxyAuth(const char *name);
-extern err_type aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name);
-extern void aclParseDenyInfoLine(struct _acl_deny_info_list **);
-extern void aclDestroyDenyInfoList(struct _acl_deny_info_list **);
-extern void aclDestroyRegexList(struct _relist *data);
-extern int aclMatchRegex(relist * data, const char *word);
-extern void aclParseRegexList(void *curlist);
-extern const char *aclTypeToStr(squid_acl);
-extern wordlist *aclDumpGeneric(const acl *);
-extern int aclPurgeMethodInUse(acl_access *);
-extern void aclCacheMatchFlush(dlink_list * cache);
-extern int aclAuthenticated(aclCheck_t * checklist);
+SQUIDCEXTERN void aclNBCheck(aclCheck_t *, PF *, void *);
+SQUIDCEXTERN int aclCheckFast(const struct _acl_access *A, aclCheck_t *);
+SQUIDCEXTERN void aclChecklistFree(aclCheck_t *);
+SQUIDCEXTERN int aclMatchAclList(const acl_list * list, aclCheck_t * checklist);
+SQUIDCEXTERN void aclDestroyAccessList(struct _acl_access **list);
+SQUIDCEXTERN void aclDestroyAcls(acl **);
+SQUIDCEXTERN void aclDestroyAclList(acl_list **);
+SQUIDCEXTERN void aclParseAccessLine(struct _acl_access **);
+SQUIDCEXTERN void aclParseAclList(acl_list **);
+SQUIDCEXTERN void aclParseAclLine(acl **);
+SQUIDCEXTERN int aclIsProxyAuth(const char *name);
+SQUIDCEXTERN err_type aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name);
+SQUIDCEXTERN void aclParseDenyInfoLine(struct _acl_deny_info_list **);
+SQUIDCEXTERN void aclDestroyDenyInfoList(struct _acl_deny_info_list **);
+SQUIDCEXTERN void aclDestroyRegexList(struct _relist *data);
+SQUIDCEXTERN int aclMatchRegex(relist * data, const char *word);
+SQUIDCEXTERN void aclParseRegexList(void *curlist);
+SQUIDCEXTERN const char *aclTypeToStr(squid_acl);
+SQUIDCEXTERN wordlist *aclDumpGeneric(const acl *);
+SQUIDCEXTERN int aclPurgeMethodInUse(acl_access *);
+SQUIDCEXTERN void aclCacheMatchFlush(dlink_list * cache);
+SQUIDCEXTERN int aclAuthenticated(aclCheck_t * checklist);
 
 /*
  * cache_cf.c
  */
-extern int parseConfigFile(const char *file_name);
-extern void intlistDestroy(intlist **);
-extern int intlistFind(intlist * list, int i);
-extern const char *wordlistAdd(wordlist **, const char *);
-extern void wordlistAddWl(wordlist **, wordlist *);
-extern void wordlistJoin(wordlist **, wordlist **);
-extern wordlist *wordlistDup(const wordlist *);
-extern void wordlistDestroy(wordlist **);
-extern void configFreeMemory(void);
-extern void wordlistCat(const wordlist *, MemBuf * mb);
-extern void allocate_new_swapdir(cacheSwap *);
-extern void self_destruct(void);
-extern int GetInteger(void);
+SQUIDCEXTERN int parseConfigFile(const char *file_name);
+SQUIDCEXTERN void intlistDestroy(intlist **);
+SQUIDCEXTERN int intlistFind(intlist * list, int i);
+SQUIDCEXTERN const char *wordlistAdd(wordlist **, const char *);
+SQUIDCEXTERN void wordlistAddWl(wordlist **, wordlist *);
+SQUIDCEXTERN void wordlistJoin(wordlist **, wordlist **);
+SQUIDCEXTERN wordlist *wordlistDup(const wordlist *);
+SQUIDCEXTERN void wordlistDestroy(wordlist **);
+SQUIDCEXTERN void configFreeMemory(void);
+SQUIDCEXTERN void wordlistCat(const wordlist *, MemBuf * mb);
+SQUIDCEXTERN void allocate_new_swapdir(cacheSwap *);
+SQUIDCEXTERN void self_destruct(void);
+SQUIDCEXTERN int GetInteger(void);
 
 /* extra functions from cache_cf.c useful for lib modules */
-extern void parse_int(int *var);
-extern void parse_onoff(int *var);
-extern void parse_eol(char *volatile *var);
-extern void parse_wordlist(wordlist ** list);
-extern void requirePathnameExists(const char *name, const char *path);
-extern void parse_time_t(time_t * var);
-extern void parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring);
-extern void dump_cachedir_options(StoreEntry * e, struct cache_dir_option *options, SwapDir * sd);
-extern void parse_sockaddr_in_list_token(sockaddr_in_list **, char *);
+SQUIDCEXTERN void parse_int(int *var);
+SQUIDCEXTERN void parse_onoff(int *var);
+SQUIDCEXTERN void parse_eol(char *volatile *var);
+SQUIDCEXTERN void parse_wordlist(wordlist ** list);
+SQUIDCEXTERN void requirePathnameExists(const char *name, const char *path);
+SQUIDCEXTERN void parse_time_t(time_t * var);
+SQUIDCEXTERN void parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring);
+SQUIDCEXTERN void dump_cachedir_options(StoreEntry * e, struct cache_dir_option *options, SwapDir * sd);
+SQUIDCEXTERN void parse_sockaddr_in_list_token(sockaddr_in_list **, char *);
 
 
 /*
  * cbdata.c
  */
-extern void cbdataInit(void);
+SQUIDCEXTERN void cbdataInit(void);
 #if CBDATA_DEBUG
-extern void *cbdataInternalAllocDbg(cbdata_type type, const char *, int);
-extern void *cbdataInternalFreeDbg(void *p, const char *, int);
-extern void cbdataInternalLockDbg(const void *p, const char *, int);
-extern void cbdataInternalUnlockDbg(const void *p, const char *, int);
-extern int cbdataInternalReferenceDoneValidDbg(void **p, void **tp, const char *, int);
+SQUIDCEXTERN void *cbdataInternalAllocDbg(cbdata_type type, const char *, int);
+SQUIDCEXTERN void *cbdataInternalFreeDbg(void *p, const char *, int);
+SQUIDCEXTERN void cbdataInternalLockDbg(const void *p, const char *, int);
+SQUIDCEXTERN void cbdataInternalUnlockDbg(const void *p, const char *, int);
+SQUIDCEXTERN int cbdataInternalReferenceDoneValidDbg(void **p, void **tp, const char *, int);
 #else
-extern void *cbdataInternalAlloc(cbdata_type type);
-extern void *cbdataInternalFree(void *p);
-extern void cbdataInternalLock(const void *p);
-extern void cbdataInternalUnlock(const void *p);
-extern int cbdataInternalReferenceDoneValid(void **p, void **tp);
+SQUIDCEXTERN void *cbdataInternalAlloc(cbdata_type type);
+SQUIDCEXTERN void *cbdataInternalFree(void *p);
+SQUIDCEXTERN void cbdataInternalLock(const void *p);
+SQUIDCEXTERN void cbdataInternalUnlock(const void *p);
+SQUIDCEXTERN int cbdataInternalReferenceDoneValid(void **p, void **tp);
 #endif
-extern int cbdataReferenceValid(const void *p);
-extern cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func);
+SQUIDCEXTERN int cbdataReferenceValid(const void *p);
+SQUIDCEXTERN cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func);
 
 /* client_side.c - FD related client side routines */
 
-extern void clientdbInit(void);
-extern void clientdbUpdate(struct in_addr, log_type, protocol_t, size_t);
-extern int clientdbCutoffDenied(struct in_addr);
-extern void clientdbDump(StoreEntry *);
-extern void clientdbFreeMemory(void);
-extern int clientdbEstablished(struct in_addr, int);
-
-extern void clientAccessCheck(void *);
-extern char *clientConstructTraceEcho(clientHttpRequest *);
-extern void clientOpenListenSockets(void);
-extern void clientHttpConnectionsClose(void);
-extern void clientReadBody(request_t * req, char *buf, size_t size, CBCB * callback, void *data);
-extern int clientAbortBody(request_t * req);
-extern void httpRequestFree(void *);
+SQUIDCEXTERN void clientdbInit(void);
+SQUIDCEXTERN void clientdbUpdate(struct in_addr, log_type, protocol_t, size_t);
+SQUIDCEXTERN int clientdbCutoffDenied(struct in_addr);
+SQUIDCEXTERN void clientdbDump(StoreEntry *);
+SQUIDCEXTERN void clientdbFreeMemory(void);
+SQUIDCEXTERN int clientdbEstablished(struct in_addr, int);
+
+SQUIDCEXTERN void clientAccessCheck(void *);
+SQUIDCEXTERN char *clientConstructTraceEcho(clientHttpRequest *);
+SQUIDCEXTERN void clientOpenListenSockets(void);
+SQUIDCEXTERN void clientHttpConnectionsClose(void);
+SQUIDCEXTERN void clientReadBody(request_t * req, char *buf, size_t size, CBCB * callback, void *data);
+SQUIDCEXTERN int clientAbortBody(request_t * req);
+SQUIDCEXTERN void httpRequestFree(void *);
 
 /* client_side_reply.c - client side reply related routines (pure logic, no comms) */
-extern void *clientReplyNewContext(clientHttpRequest *);
-extern int clientHttpRequestStatus(int fd, clientHttpRequest const *http);
-extern void clientSetReplyToError(void *, err_type, http_status, method_t, char const *, struct in_addr *, request_t *, char *, auth_user_request_t * auth_user_request);
-
-extern int commSetNonBlocking(int fd);
-extern int commUnsetNonBlocking(int fd);
-extern void commSetCloseOnExec(int fd);
-extern int comm_accept(int fd, struct sockaddr_in *, struct sockaddr_in *);
-extern void comm_close(int fd);
-extern void comm_reset_close(int fd);
+SQUIDCEXTERN void *clientReplyNewContext(clientHttpRequest *);
+SQUIDCEXTERN int clientHttpRequestStatus(int fd, clientHttpRequest const *http);
+SQUIDCEXTERN void clientSetReplyToError(void *, err_type, http_status, method_t, char const *, struct in_addr *, request_t *, char *, auth_user_request_t * auth_user_request);
+
+SQUIDCEXTERN int commSetNonBlocking(int fd);
+SQUIDCEXTERN int commUnsetNonBlocking(int fd);
+SQUIDCEXTERN void commSetCloseOnExec(int fd);
+SQUIDCEXTERN int comm_accept(int fd, struct sockaddr_in *, struct sockaddr_in *);
+SQUIDCEXTERN void comm_close(int fd);
+SQUIDCEXTERN void comm_reset_close(int fd);
 #if LINGERING_CLOSE
-extern void comm_lingering_close(int fd);
+SQUIDCEXTERN void comm_lingering_close(int fd);
 #endif
-extern void commConnectStart(int fd, const char *, u_short, CNCB *, void *);
-extern int comm_connect_addr(int sock, const struct sockaddr_in *);
-extern void comm_init(void);
-extern int comm_listen(int sock);
-extern int comm_open(int, int, struct in_addr, u_short port, int, const char *note);
-extern int comm_openex(int, int, struct in_addr, u_short, int, unsigned char TOS, const char *);
-extern u_short comm_local_port(int fd);
-
-extern void commSetSelect(int, unsigned int, PF *, void *, time_t);
-extern void comm_add_close_handler(int fd, PF *, void *);
-extern void comm_remove_close_handler(int fd, PF *, void *);
-extern int comm_udp_sendto(int, const struct sockaddr_in *, int, const void *, int);
-extern void comm_write(int fd,
+SQUIDCEXTERN void commConnectStart(int fd, const char *, u_short, CNCB *, void *);
+SQUIDCEXTERN int comm_connect_addr(int sock, const struct sockaddr_in *);
+SQUIDCEXTERN void comm_init(void);
+SQUIDCEXTERN int comm_listen(int sock);
+SQUIDCEXTERN int comm_open(int, int, struct in_addr, u_short port, int, const char *note);
+SQUIDCEXTERN int comm_openex(int, int, struct in_addr, u_short, int, unsigned char TOS, const char *);
+SQUIDCEXTERN u_short comm_local_port(int fd);
+
+SQUIDCEXTERN void commSetSelect(int, unsigned int, PF *, void *, time_t);
+SQUIDCEXTERN void comm_add_close_handler(int fd, PF *, void *);
+SQUIDCEXTERN void comm_remove_close_handler(int fd, PF *, void *);
+SQUIDCEXTERN int comm_udp_sendto(int, const struct sockaddr_in *, int, const void *, int);
+SQUIDCEXTERN void comm_write(int fd,
     const char *buf,
     int size,
     CWCB * handler,
     void *handler_data,
     FREE *);
-extern void comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data);
-extern void commCallCloseHandlers(int fd);
-extern int commSetTimeout(int fd, int, PF *, void *);
-extern void commSetDefer(int fd, DEFER * func, void *);
-extern int ignoreErrno(int);
-extern void commCloseAllSockets(void);
-extern void checkTimeouts(void);
-extern int commDeferRead(int fd);
+SQUIDCEXTERN void comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data);
+SQUIDCEXTERN void commCallCloseHandlers(int fd);
+SQUIDCEXTERN int commSetTimeout(int fd, int, PF *, void *);
+SQUIDCEXTERN void commSetDefer(int fd, DEFER * func, void *);
+SQUIDCEXTERN int ignoreErrno(int);
+SQUIDCEXTERN void commCloseAllSockets(void);
+SQUIDCEXTERN void checkTimeouts(void);
+SQUIDCEXTERN int commDeferRead(int fd);
 
 
 /*
  * comm_select.c
  */
-extern void comm_select_init(void);
-extern comm_err_t comm_select(int);
-extern void comm_quick_poll_required(void);
-
-extern void packerToStoreInit(Packer * p, StoreEntry * e);
-extern void packerToMemInit(Packer * p, MemBuf * mb);
-extern void packerClean(Packer * p);
-extern void packerAppend(Packer * p, const char *buf, int size);
+SQUIDCEXTERN void comm_select_init(void);
+SQUIDCEXTERN comm_err_t comm_select(int);
+SQUIDCEXTERN void comm_quick_poll_required(void);
+
+SQUIDCEXTERN void packerToStoreInit(Packer * p, StoreEntry * e);
+SQUIDCEXTERN void packerToMemInit(Packer * p, MemBuf * mb);
+SQUIDCEXTERN void packerClean(Packer * p);
+SQUIDCEXTERN void packerAppend(Packer * p, const char *buf, int size);
 #if STDC_HEADERS
-extern void
+SQUIDCEXTERN void
 packerPrintf(Packer * p, const char *fmt,...) PRINTF_FORMAT_ARG2;
 #else
-extern void packerPrintf();
+SQUIDCEXTERN void packerPrintf();
 #endif
 
 
 /* see debug.c for info on context-based debugging */
-extern Ctx ctx_enter(const char *descr);
-extern void ctx_exit(Ctx ctx);
+SQUIDCEXTERN Ctx ctx_enter(const char *descr);
+SQUIDCEXTERN void ctx_exit(Ctx ctx);
 
-extern void _db_init(const char *logfile, const char *options);
-extern void _db_rotate_log(void);
+SQUIDCEXTERN void _db_init(const char *logfile, const char *options);
+SQUIDCEXTERN void _db_rotate_log(void);
 
 #if STDC_HEADERS
-extern void
-_db_print(const char *,...) PRINTF_FORMAT_ARG1;
+SQUIDCEXTERN void _db_print(const char *,...) PRINTF_FORMAT_ARG1;
 #else
-extern void _db_print();
+SQUIDCEXTERN void _db_print();
 #endif
-extern void xassert(const char *, const char *, int);
+SQUIDCEXTERN void xassert(const char *, const char *, int);
 
 /* packs, then prints an object using debug() */
-extern void debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm);
+SQUIDCEXTERN void debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm);
 
 /* disk.c */
-extern int file_open(const char *path, int mode);
-extern void file_close(int fd);
-extern void file_write(int, off_t, void *, int len, DWCB *, void *, FREE *);
-extern void file_write_mbuf(int fd, off_t, MemBuf mb, DWCB * handler, void *handler_data);
-extern void file_read(int, char *, int, off_t, DRCB *, void *);
-extern void disk_init(void);
+SQUIDCEXTERN int file_open(const char *path, int mode);
+SQUIDCEXTERN void file_close(int fd);
+SQUIDCEXTERN void file_write(int, off_t, void *, int len, DWCB *, void *, FREE *);
+SQUIDCEXTERN void file_write_mbuf(int fd, off_t, MemBuf mb, DWCB * handler, void *handler_data);
+SQUIDCEXTERN void file_read(int, char *, int, off_t, DRCB *, void *);
+SQUIDCEXTERN void disk_init(void);
 
 /* diskd.c */
-extern diskd_queue *afile_create_queue(void);
-extern void afile_destroy_queue(diskd_queue *);
-extern void afile_sync_queue(diskd_queue *);
-extern void afile_sync(void);
-extern void afile_open(const char *path, int mode, DOCB *, void *);
-extern void afile_close(int fd, DCCB * callback, void *data);
-extern void afile_write(int, off_t, void *, int len, DWCB *, void *, FREE *);
-extern void afile_write_mbuf(int fd, off_t, MemBuf, DWCB *, void *);
-extern void afile_read(int, char *, int, off_t, DRCB *, void *);
-extern void afile_unlink(const char *path, DUCB *, void *);
-extern void afile_truncate(const char *path, DTCB *, void *);
-
-extern void dnsShutdown(void);
-extern void dnsInit(void);
-extern void dnsSubmit(const char *lookup, HLPCB * callback, void *data);
+SQUIDCEXTERN diskd_queue *afile_create_queue(void);
+SQUIDCEXTERN void afile_destroy_queue(diskd_queue *);
+SQUIDCEXTERN void afile_sync_queue(diskd_queue *);
+SQUIDCEXTERN void afile_sync(void);
+SQUIDCEXTERN void afile_open(const char *path, int mode, DOCB *, void *);
+SQUIDCEXTERN void afile_close(int fd, DCCB * callback, void *data);
+SQUIDCEXTERN void afile_write(int, off_t, void *, int len, DWCB *, void *, FREE *);
+SQUIDCEXTERN void afile_write_mbuf(int fd, off_t, MemBuf, DWCB *, void *);
+SQUIDCEXTERN void afile_read(int, char *, int, off_t, DRCB *, void *);
+SQUIDCEXTERN void afile_unlink(const char *path, DUCB *, void *);
+SQUIDCEXTERN void afile_truncate(const char *path, DTCB *, void *);
+
+SQUIDCEXTERN void dnsShutdown(void);
+SQUIDCEXTERN void dnsInit(void);
+SQUIDCEXTERN void dnsSubmit(const char *lookup, HLPCB * callback, void *data);
 
 /* dns_internal.c */
-extern void idnsInit(void);
-extern void idnsShutdown(void);
-extern void idnsALookup(const char *, IDNSCB *, void *);
-extern void idnsPTRLookup(const struct in_addr, IDNSCB *, void *);
-
-extern void eventAdd(const char *name, EVH * func, void *arg, double when, int);
-extern void eventAddIsh(const char *name, EVH * func, void *arg, double delta_ish, int);
-extern void eventRun(void);
-extern time_t eventNextTime(void);
-extern void eventDelete(EVH * func, void *arg);
-extern void eventInit(void);
-extern void eventFreeMemory(void);
-extern int eventFind(EVH *, void *);
-
-extern void fd_close(int fd);
-extern void fd_open(int fd, unsigned int type, const char *);
-extern void fd_note(int fd, const char *);
-extern void fd_bytes(int fd, int len, unsigned int type);
-extern void fdFreeMemory(void);
-extern void fdDumpOpen(void);
-extern int fdNFree(void);
-extern void fdAdjustReserved(void);
-
-extern fileMap *file_map_create(void);
-extern int file_map_allocate(fileMap *, int);
-extern int file_map_bit_set(fileMap *, int);
-extern int file_map_bit_test(fileMap *, int);
-extern void file_map_bit_reset(fileMap *, int);
-extern void filemapFreeMemory(fileMap *);
-
-
-extern void fqdncache_nbgethostbyaddr(struct in_addr, FQDNH *, void *);
-extern const char *fqdncache_gethostbyaddr(struct in_addr, int flags);
-extern void fqdncache_init(void);
-extern void fqdnStats(StoreEntry *);
-extern void fqdncacheReleaseInvalid(const char *);
-extern const char *fqdnFromAddr(struct in_addr);
-extern int fqdncacheQueueDrain(void);
-extern void fqdncacheFreeMemory(void);
-extern void fqdncache_restart(void);
-extern EVH fqdncache_purgelru;
-extern void fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames);
+SQUIDCEXTERN void idnsInit(void);
+SQUIDCEXTERN void idnsShutdown(void);
+SQUIDCEXTERN void idnsALookup(const char *, IDNSCB *, void *);
+SQUIDCEXTERN void idnsPTRLookup(const struct in_addr, IDNSCB *, void *);
+
+SQUIDCEXTERN void eventAdd(const char *name, EVH * func, void *arg, double when, int);
+SQUIDCEXTERN void eventAddIsh(const char *name, EVH * func, void *arg, double delta_ish, int);
+SQUIDCEXTERN void eventRun(void);
+SQUIDCEXTERN time_t eventNextTime(void);
+SQUIDCEXTERN void eventDelete(EVH * func, void *arg);
+SQUIDCEXTERN void eventInit(void);
+SQUIDCEXTERN void eventFreeMemory(void);
+SQUIDCEXTERN int eventFind(EVH *, void *);
+
+SQUIDCEXTERN void fd_close(int fd);
+SQUIDCEXTERN void fd_open(int fd, unsigned int type, const char *);
+SQUIDCEXTERN void fd_note(int fd, const char *);
+SQUIDCEXTERN void fd_bytes(int fd, int len, unsigned int type);
+SQUIDCEXTERN void fdFreeMemory(void);
+SQUIDCEXTERN void fdDumpOpen(void);
+SQUIDCEXTERN int fdNFree(void);
+SQUIDCEXTERN void fdAdjustReserved(void);
+
+SQUIDCEXTERN fileMap *file_map_create(void);
+SQUIDCEXTERN int file_map_allocate(fileMap *, int);
+SQUIDCEXTERN int file_map_bit_set(fileMap *, int);
+SQUIDCEXTERN int file_map_bit_test(fileMap *, int);
+SQUIDCEXTERN void file_map_bit_reset(fileMap *, int);
+SQUIDCEXTERN void filemapFreeMemory(fileMap *);
+
+
+SQUIDCEXTERN void fqdncache_nbgethostbyaddr(struct in_addr, FQDNH *, void *);
+SQUIDCEXTERN const char *fqdncache_gethostbyaddr(struct in_addr, int flags);
+SQUIDCEXTERN void fqdncache_init(void);
+SQUIDCEXTERN void fqdnStats(StoreEntry *);
+SQUIDCEXTERN void fqdncacheReleaseInvalid(const char *);
+SQUIDCEXTERN const char *fqdnFromAddr(struct in_addr);
+SQUIDCEXTERN int fqdncacheQueueDrain(void);
+SQUIDCEXTERN void fqdncacheFreeMemory(void);
+SQUIDCEXTERN void fqdncache_restart(void);
+SQUIDCEXTERN EVH fqdncache_purgelru;
+SQUIDCEXTERN void fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames);
 
-extern void ftpStart(FwdState *);
-extern char *ftpUrlWith2f(const request_t *);
+SQUIDCEXTERN void ftpStart(FwdState *);
+SQUIDCEXTERN char *ftpUrlWith2f(const request_t *);
 
-extern void gopherStart(FwdState *);
-extern int gopherCachable(const request_t *);
+SQUIDCEXTERN void gopherStart(FwdState *);
+SQUIDCEXTERN int gopherCachable(const request_t *);
 
 
-extern void whoisStart(FwdState *);
+SQUIDCEXTERN void whoisStart(FwdState *);
 
 /* http.c */
-extern int httpCachable(method_t);
-extern void httpStart(FwdState *);
-extern void httpParseReplyHeaders(const char *, http_reply *);
-extern void httpProcessReplyHeader(HttpStateData *, const char *, int);
-extern mb_size_t httpBuildRequestPrefix(request_t * request,
+SQUIDCEXTERN int httpCachable(method_t);
+SQUIDCEXTERN void httpStart(FwdState *);
+SQUIDCEXTERN void httpParseReplyHeaders(const char *, http_reply *);
+SQUIDCEXTERN void httpProcessReplyHeader(HttpStateData *, const char *, int);
+SQUIDCEXTERN mb_size_t httpBuildRequestPrefix(request_t * request,
     request_t * orig_request,
     StoreEntry * entry,
     MemBuf * mb,
     int cfd,
     http_state_flags);
-extern void httpAnonInitModule(void);
-extern int httpAnonHdrAllowed(http_hdr_type hdr_id);
-extern int httpAnonHdrDenied(http_hdr_type hdr_id);
-extern void httpBuildRequestHeader(request_t *, request_t *, StoreEntry *, HttpHeader *, int, http_state_flags);
-extern void httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor);
-extern const char *httpMakeVaryMark(request_t * request, HttpReply * reply);
+SQUIDCEXTERN void httpAnonInitModule(void);
+SQUIDCEXTERN int httpAnonHdrAllowed(http_hdr_type hdr_id);
+SQUIDCEXTERN int httpAnonHdrDenied(http_hdr_type hdr_id);
+SQUIDCEXTERN void httpBuildRequestHeader(request_t *, request_t *, StoreEntry *, HttpHeader *, int, http_state_flags);
+SQUIDCEXTERN void httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor);
+SQUIDCEXTERN const char *httpMakeVaryMark(request_t * request, HttpReply * reply);
 
 /* ETag */
-extern int etagParseInit(ETag * etag, const char *str);
-extern int etagIsEqual(const ETag * tag1, const ETag * tag2);
+SQUIDCEXTERN int etagParseInit(ETag * etag, const char *str);
+SQUIDCEXTERN int etagIsEqual(const ETag * tag1, const ETag * tag2);
 
 /* Http Status Line */
 /* init/clean */
-extern void httpStatusLineInit(HttpStatusLine * sline);
-extern void httpStatusLineClean(HttpStatusLine * sline);
+SQUIDCEXTERN void httpStatusLineInit(HttpStatusLine * sline);
+SQUIDCEXTERN void httpStatusLineClean(HttpStatusLine * sline);
 /* set/get values */
-extern void httpStatusLineSet(HttpStatusLine * sline, http_version_t version,
+SQUIDCEXTERN void httpStatusLineSet(HttpStatusLine * sline, http_version_t version,
     http_status status, const char *reason);
-extern const char *httpStatusLineReason(const HttpStatusLine * sline);
+SQUIDCEXTERN const char *httpStatusLineReason(const HttpStatusLine * sline);
 /* parse/pack */
 /* parse a 0-terminating buffer and fill internal structires; returns true on success */
-extern int httpStatusLineParse(HttpStatusLine * sline, const char *start,
+SQUIDCEXTERN int httpStatusLineParse(HttpStatusLine * sline, const char *start,
     const char *end);
 /* pack fields using Packer */
-extern void httpStatusLinePackInto(const HttpStatusLine * sline, Packer * p);
-extern const char *httpStatusString(http_status status);
+SQUIDCEXTERN void httpStatusLinePackInto(const HttpStatusLine * sline, Packer * p);
+SQUIDCEXTERN const char *httpStatusString(http_status status);
 
 /* Http Body */
 /* init/clean */
-extern void httpBodyInit(HttpBody * body);
-extern void httpBodyClean(HttpBody * body);
+SQUIDCEXTERN void httpBodyInit(HttpBody * body);
+SQUIDCEXTERN void httpBodyClean(HttpBody * body);
 /* get body ptr (always use this) */
-extern const char *httpBodyPtr(const HttpBody * body);
+SQUIDCEXTERN const char *httpBodyPtr(const HttpBody * body);
 /* set body, does not clone mb so you should not reuse it */
-extern void httpBodySet(HttpBody * body, MemBuf * mb);
+SQUIDCEXTERN void httpBodySet(HttpBody * body, MemBuf * mb);
 
 /* pack */
-extern void httpBodyPackInto(const HttpBody * body, Packer * p);
+SQUIDCEXTERN void httpBodyPackInto(const HttpBody * body, Packer * p);
 
 /* Http Cache Control Header Field */
-extern void httpHdrCcInitModule(void);
-extern void httpHdrCcCleanModule(void);
-extern HttpHdrCc *httpHdrCcCreate(void);
-extern HttpHdrCc *httpHdrCcParseCreate(const String * str);
-extern void httpHdrCcDestroy(HttpHdrCc * cc);
-extern HttpHdrCc *httpHdrCcDup(const HttpHdrCc * cc);
-extern void httpHdrCcPackInto(const HttpHdrCc * cc, Packer * p);
-extern void httpHdrCcJoinWith(HttpHdrCc * cc, const HttpHdrCc * new_cc);
-extern void httpHdrCcSetMaxAge(HttpHdrCc * cc, int max_age);
-extern void httpHdrCcSetSMaxAge(HttpHdrCc * cc, int s_maxage);
-extern void httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist);
-extern void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count);
+SQUIDCEXTERN void httpHdrCcInitModule(void);
+SQUIDCEXTERN void httpHdrCcCleanModule(void);
+SQUIDCEXTERN HttpHdrCc *httpHdrCcCreate(void);
+SQUIDCEXTERN HttpHdrCc *httpHdrCcParseCreate(const String * str);
+SQUIDCEXTERN void httpHdrCcDestroy(HttpHdrCc * cc);
+SQUIDCEXTERN HttpHdrCc *httpHdrCcDup(const HttpHdrCc * cc);
+SQUIDCEXTERN void httpHdrCcPackInto(const HttpHdrCc * cc, Packer * p);
+SQUIDCEXTERN void httpHdrCcJoinWith(HttpHdrCc * cc, const HttpHdrCc * new_cc);
+SQUIDCEXTERN void httpHdrCcSetMaxAge(HttpHdrCc * cc, int max_age);
+SQUIDCEXTERN void httpHdrCcSetSMaxAge(HttpHdrCc * cc, int s_maxage);
+SQUIDCEXTERN void httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist);
+SQUIDCEXTERN void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count);
 
 /* Http Range Header Field */
-extern HttpHdrRange *httpHdrRangeParseCreate(const String * range_spec);
+SQUIDCEXTERN HttpHdrRange *httpHdrRangeParseCreate(const String * range_spec);
 /* returns true if ranges are valid; inits HttpHdrRange */
-extern int httpHdrRangeParseInit(HttpHdrRange * range, const String * range_spec);
-extern void httpHdrRangeDestroy(HttpHdrRange * range);
-extern HttpHdrRange *httpHdrRangeDup(const HttpHdrRange * range);
-extern void httpHdrRangePackInto(const HttpHdrRange * range, Packer * p);
+SQUIDCEXTERN int httpHdrRangeParseInit(HttpHdrRange * range, const String * range_spec);
+SQUIDCEXTERN void httpHdrRangeDestroy(HttpHdrRange * range);
+SQUIDCEXTERN HttpHdrRange *httpHdrRangeDup(const HttpHdrRange * range);
+SQUIDCEXTERN void httpHdrRangePackInto(const HttpHdrRange * range, Packer * p);
 /* iterate through specs */
-extern HttpHdrRangeSpec *httpHdrRangeGetSpec(const HttpHdrRange * range, HttpHdrRangePos * pos);
+SQUIDCEXTERN HttpHdrRangeSpec *httpHdrRangeGetSpec(const HttpHdrRange * range, HttpHdrRangePos * pos);
 /* adjust specs after the length is known */
-extern int httpHdrRangeCanonize(HttpHdrRange *, ssize_t);
+SQUIDCEXTERN int httpHdrRangeCanonize(HttpHdrRange *, ssize_t);
 /* other */
-extern String httpHdrRangeBoundaryStr(clientHttpRequest * http);
-extern int httpHdrRangeIsComplex(const HttpHdrRange * range);
-extern int httpHdrRangeWillBeComplex(const HttpHdrRange * range);
-extern ssize_t httpHdrRangeFirstOffset(const HttpHdrRange * range);
-extern ssize_t httpHdrRangeLowestOffset(const HttpHdrRange * range, ssize_t);
-extern int httpHdrRangeOffsetLimit(HttpHdrRange *);
+SQUIDCEXTERN String httpHdrRangeBoundaryStr(clientHttpRequest * http);
+SQUIDCEXTERN int httpHdrRangeIsComplex(const HttpHdrRange * range);
+SQUIDCEXTERN int httpHdrRangeWillBeComplex(const HttpHdrRange * range);
+SQUIDCEXTERN ssize_t httpHdrRangeFirstOffset(const HttpHdrRange * range);
+SQUIDCEXTERN ssize_t httpHdrRangeLowestOffset(const HttpHdrRange * range, ssize_t);
+SQUIDCEXTERN int httpHdrRangeOffsetLimit(HttpHdrRange *);
 
 
 /* Http Content Range Header Field */
-extern HttpHdrContRange *httpHdrContRangeCreate(void);
-extern HttpHdrContRange *httpHdrContRangeParseCreate(const char *crange_spec);
+SQUIDCEXTERN HttpHdrContRange *httpHdrContRangeCreate(void);
+SQUIDCEXTERN HttpHdrContRange *httpHdrContRangeParseCreate(const char *crange_spec);
 /* returns true if range is valid; inits HttpHdrContRange */
-extern int httpHdrContRangeParseInit(HttpHdrContRange * crange, const char *crange_spec);
-extern void httpHdrContRangeDestroy(HttpHdrContRange * crange);
-extern HttpHdrContRange *httpHdrContRangeDup(const HttpHdrContRange * crange);
-extern void httpHdrContRangePackInto(const HttpHdrContRange * crange, Packer * p);
+SQUIDCEXTERN int httpHdrContRangeParseInit(HttpHdrContRange * crange, const char *crange_spec);
+SQUIDCEXTERN void httpHdrContRangeDestroy(HttpHdrContRange * crange);
+SQUIDCEXTERN HttpHdrContRange *httpHdrContRangeDup(const HttpHdrContRange * crange);
+SQUIDCEXTERN void httpHdrContRangePackInto(const HttpHdrContRange * crange, Packer * p);
 /* inits with given spec */
-extern void httpHdrContRangeSet(HttpHdrContRange *, HttpHdrRangeSpec, ssize_t);
+SQUIDCEXTERN void httpHdrContRangeSet(HttpHdrContRange *, HttpHdrRangeSpec, ssize_t);
 
 /* Http Header Tools */
-extern HttpHeaderFieldInfo *httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count);
-extern void httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * info, int count);
-extern int httpHeaderIdByName(const char *name, int name_len, const HttpHeaderFieldInfo * attrs, int end);
-extern int httpHeaderIdByNameDef(const char *name, int name_len);
-extern const char *httpHeaderNameById(int id);
-extern void httpHeaderMaskInit(HttpHeaderMask * mask, int value);
-extern void httpHeaderCalcMask(HttpHeaderMask * mask, const int *enums, int count);
-extern int httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive);
-extern void httpHeaderAddContRange(HttpHeader *, HttpHdrRangeSpec, ssize_t);
-extern void strListAdd(String * str, const char *item, char del);
-extern int strListIsMember(const String * str, const char *item, char del);
-extern int strListIsSubstr(const String * list, const char *s, char del);
-extern int strListGetItem(const String * str, char del, const char **item, int *ilen, const char **pos);
-extern const char *getStringPrefix(const char *str, const char *end);
-extern int httpHeaderParseInt(const char *start, int *val);
-extern int httpHeaderParseSize(const char *start, ssize_t * sz);
-extern int httpHeaderReset(HttpHeader * hdr);
+SQUIDCEXTERN HttpHeaderFieldInfo *httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count);
+SQUIDCEXTERN void httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * info, int count);
+SQUIDCEXTERN int httpHeaderIdByName(const char *name, int name_len, const HttpHeaderFieldInfo * attrs, int end);
+SQUIDCEXTERN int httpHeaderIdByNameDef(const char *name, int name_len);
+SQUIDCEXTERN const char *httpHeaderNameById(int id);
+SQUIDCEXTERN void httpHeaderMaskInit(HttpHeaderMask * mask, int value);
+SQUIDCEXTERN void httpHeaderCalcMask(HttpHeaderMask * mask, const int *enums, int count);
+SQUIDCEXTERN int httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive);
+SQUIDCEXTERN void httpHeaderAddContRange(HttpHeader *, HttpHdrRangeSpec, ssize_t);
+SQUIDCEXTERN void strListAdd(String * str, const char *item, char del);
+SQUIDCEXTERN int strListIsMember(const String * str, const char *item, char del);
+SQUIDCEXTERN int strListIsSubstr(const String * list, const char *s, char del);
+SQUIDCEXTERN int strListGetItem(const String * str, char del, const char **item, int *ilen, const char **pos);
+SQUIDCEXTERN const char *getStringPrefix(const char *str, const char *end);
+SQUIDCEXTERN int httpHeaderParseInt(const char *start, int *val);
+SQUIDCEXTERN int httpHeaderParseSize(const char *start, ssize_t * sz);
+SQUIDCEXTERN int httpHeaderReset(HttpHeader * hdr);
 #if STDC_HEADERS
-extern void
+SQUIDCEXTERN void
 httpHeaderPutStrf(HttpHeader * hdr, http_hdr_type id, const char *fmt,...) PRINTF_FORMAT_ARG3;
 #else
-extern void httpHeaderPutStrf();
+SQUIDCEXTERN void httpHeaderPutStrf();
 #endif
 
 
 /* Http Header */
-extern void httpHeaderInitModule(void);
-extern void httpHeaderCleanModule(void);
+SQUIDCEXTERN void httpHeaderInitModule(void);
+SQUIDCEXTERN void httpHeaderCleanModule(void);
 /* init/clean */
-extern void httpHeaderInit(HttpHeader * hdr, http_hdr_owner_type owner);
-extern void httpHeaderClean(HttpHeader * hdr);
+SQUIDCEXTERN void httpHeaderInit(HttpHeader * hdr, http_hdr_owner_type owner);
+SQUIDCEXTERN void httpHeaderClean(HttpHeader * hdr);
 /* append/update */
-extern void httpHeaderAppend(HttpHeader * dest, const HttpHeader * src);
-extern void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask);
+SQUIDCEXTERN void httpHeaderAppend(HttpHeader * dest, const HttpHeader * src);
+SQUIDCEXTERN void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask);
 /* parse/pack */
-extern int httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end);
-extern void httpHeaderPackInto(const HttpHeader * hdr, Packer * p);
+SQUIDCEXTERN int httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end);
+SQUIDCEXTERN void httpHeaderPackInto(const HttpHeader * hdr, Packer * p);
 /* field manipulation */
-extern int httpHeaderHas(const HttpHeader * hdr, http_hdr_type type);
-extern void httpHeaderPutInt(HttpHeader * hdr, http_hdr_type type, int number);
-extern void httpHeaderPutTime(HttpHeader * hdr, http_hdr_type type, time_t htime);
-extern void httpHeaderPutStr(HttpHeader * hdr, http_hdr_type type, const char *str);
-extern void httpHeaderPutAuth(HttpHeader * hdr, const char *auth_scheme, const char *realm);
-extern void httpHeaderPutCc(HttpHeader * hdr, const HttpHdrCc * cc);
-extern void httpHeaderPutContRange(HttpHeader * hdr, const HttpHdrContRange * cr);
-extern void httpHeaderPutRange(HttpHeader * hdr, const HttpHdrRange * range);
-extern void httpHeaderPutExt(HttpHeader * hdr, const char *name, const char *value);
-extern int httpHeaderGetInt(const HttpHeader * hdr, http_hdr_type id);
-extern time_t httpHeaderGetTime(const HttpHeader * hdr, http_hdr_type id);
-extern TimeOrTag httpHeaderGetTimeOrTag(const HttpHeader * hdr, http_hdr_type id);
-extern HttpHdrCc *httpHeaderGetCc(const HttpHeader * hdr);
-extern ETag httpHeaderGetETag(const HttpHeader * hdr, http_hdr_type id);
-extern HttpHdrRange *httpHeaderGetRange(const HttpHeader * hdr);
-extern HttpHdrContRange *httpHeaderGetContRange(const HttpHeader * hdr);
-extern const char *httpHeaderGetStr(const HttpHeader * hdr, http_hdr_type id);
-extern const char *httpHeaderGetLastStr(const HttpHeader * hdr, http_hdr_type id);
-extern const char *httpHeaderGetAuth(const HttpHeader * hdr, http_hdr_type id, const char *auth_scheme);
-extern String httpHeaderGetList(const HttpHeader * hdr, http_hdr_type id);
-extern String httpHeaderGetStrOrList(const HttpHeader * hdr, http_hdr_type id);
-extern String httpHeaderGetByName(const HttpHeader * hdr, const char *name);
-extern String httpHeaderGetListMember(const HttpHeader * hdr, http_hdr_type id, const char *member, const char separator);
-extern String httpHeaderGetByNameListMember(const HttpHeader * hdr, const char *name, const char *member, const char separator);
-extern int httpHeaderDelByName(HttpHeader * hdr, const char *name);
-extern int httpHeaderDelById(HttpHeader * hdr, http_hdr_type id);
-extern void httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos);
+SQUIDCEXTERN int httpHeaderHas(const HttpHeader * hdr, http_hdr_type type);
+SQUIDCEXTERN void httpHeaderPutInt(HttpHeader * hdr, http_hdr_type type, int number);
+SQUIDCEXTERN void httpHeaderPutTime(HttpHeader * hdr, http_hdr_type type, time_t htime);
+SQUIDCEXTERN void httpHeaderPutStr(HttpHeader * hdr, http_hdr_type type, const char *str);
+SQUIDCEXTERN void httpHeaderPutAuth(HttpHeader * hdr, const char *auth_scheme, const char *realm);
+SQUIDCEXTERN void httpHeaderPutCc(HttpHeader * hdr, const HttpHdrCc * cc);
+SQUIDCEXTERN void httpHeaderPutContRange(HttpHeader * hdr, const HttpHdrContRange * cr);
+SQUIDCEXTERN void httpHeaderPutRange(HttpHeader * hdr, const HttpHdrRange * range);
+SQUIDCEXTERN void httpHeaderPutExt(HttpHeader * hdr, const char *name, const char *value);
+SQUIDCEXTERN int httpHeaderGetInt(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN time_t httpHeaderGetTime(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN TimeOrTag httpHeaderGetTimeOrTag(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN HttpHdrCc *httpHeaderGetCc(const HttpHeader * hdr);
+SQUIDCEXTERN ETag httpHeaderGetETag(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN HttpHdrRange *httpHeaderGetRange(const HttpHeader * hdr);
+SQUIDCEXTERN HttpHdrContRange *httpHeaderGetContRange(const HttpHeader * hdr);
+SQUIDCEXTERN const char *httpHeaderGetStr(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN const char *httpHeaderGetLastStr(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN const char *httpHeaderGetAuth(const HttpHeader * hdr, http_hdr_type id, const char *auth_scheme);
+SQUIDCEXTERN String httpHeaderGetList(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN String httpHeaderGetStrOrList(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN String httpHeaderGetByName(const HttpHeader * hdr, const char *name);
+SQUIDCEXTERN String httpHeaderGetListMember(const HttpHeader * hdr, http_hdr_type id, const char *member, const char separator);
+SQUIDCEXTERN String httpHeaderGetByNameListMember(const HttpHeader * hdr, const char *name, const char *member, const char separator);
+SQUIDCEXTERN int httpHeaderDelByName(HttpHeader * hdr, const char *name);
+SQUIDCEXTERN int httpHeaderDelById(HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN void httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos);
 /* avoid using these low level routines */
-extern HttpHeaderEntry *httpHeaderGetEntry(const HttpHeader * hdr, HttpHeaderPos * pos);
-extern HttpHeaderEntry *httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id);
-extern void httpHeaderAddEntry(HttpHeader * hdr, HttpHeaderEntry * e);
-extern HttpHeaderEntry *httpHeaderEntryClone(const HttpHeaderEntry * e);
-extern void httpHeaderEntryPackInto(const HttpHeaderEntry * e, Packer * p);
+SQUIDCEXTERN HttpHeaderEntry *httpHeaderGetEntry(const HttpHeader * hdr, HttpHeaderPos * pos);
+SQUIDCEXTERN HttpHeaderEntry *httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id);
+SQUIDCEXTERN void httpHeaderAddEntry(HttpHeader * hdr, HttpHeaderEntry * e);
+SQUIDCEXTERN HttpHeaderEntry *httpHeaderEntryClone(const HttpHeaderEntry * e);
+SQUIDCEXTERN void httpHeaderEntryPackInto(const HttpHeaderEntry * e, Packer * p);
 /* store report about current header usage and other stats */
-extern void httpHeaderStoreReport(StoreEntry * e);
-extern void httpHdrMangleList(HttpHeader *, request_t *);
+SQUIDCEXTERN void httpHeaderStoreReport(StoreEntry * e);
+SQUIDCEXTERN void httpHdrMangleList(HttpHeader *, request_t *);
 
 /* Http Msg (currently in HttpReply.c @?@ ) */
-extern int httpMsgIsPersistent(http_version_t http_ver, const HttpHeader * hdr);
-extern int httpMsgIsolateHeaders(const char **parse_start, const char **blk_start, const char **blk_end);
+SQUIDCEXTERN int httpMsgIsPersistent(http_version_t http_ver, const HttpHeader * hdr);
+SQUIDCEXTERN int httpMsgIsolateHeaders(const char **parse_start, const char **blk_start, const char **blk_end);
 
 /* Http Reply */
-extern void httpReplyInitModule(void);
+SQUIDCEXTERN void httpReplyInitModule(void);
 /* create/destroy */
-extern HttpReply *httpReplyCreate(void);
-extern void httpReplyDestroy(HttpReply * rep);
+SQUIDCEXTERN HttpReply *httpReplyCreate(void);
+SQUIDCEXTERN void httpReplyDestroy(HttpReply * rep);
 /* reset: clean, then init */
-extern void httpReplyReset(HttpReply * rep);
+SQUIDCEXTERN void httpReplyReset(HttpReply * rep);
 /* absorb: copy the contents of a new reply to the old one, destroy new one */
-extern void httpReplyAbsorb(HttpReply * rep, HttpReply * new_rep);
+SQUIDCEXTERN void httpReplyAbsorb(HttpReply * rep, HttpReply * new_rep);
 /* parse returns -1,0,+1 on error,need-more-data,success */
-extern int httpReplyParse(HttpReply * rep, const char *buf, ssize_t);
-extern void httpReplyPackInto(const HttpReply * rep, Packer * p);
+SQUIDCEXTERN int httpReplyParse(HttpReply * rep, const char *buf, ssize_t);
+SQUIDCEXTERN void httpReplyPackInto(const HttpReply * rep, Packer * p);
 /* ez-routines */
 /* mem-pack: returns a ready to use mem buffer with a packed reply */
-extern MemBuf httpReplyPack(const HttpReply * rep);
+SQUIDCEXTERN MemBuf httpReplyPack(const HttpReply * rep);
 /* swap: create swap-based packer, pack, destroy packer */
-extern void httpReplySwapOut(const HttpReply * rep, StoreEntry * e);
+SQUIDCEXTERN void httpReplySwapOut(const HttpReply * rep, StoreEntry * e);
 /* set commonly used info with one call */
-extern void httpReplySetHeaders(HttpReply * rep, http_version_t ver, http_status status,
+SQUIDCEXTERN void httpReplySetHeaders(HttpReply * rep, http_version_t ver, http_status status,
     const char *reason, const char *ctype, int clen, time_t lmt, time_t expires);
 /* do everything in one call: init, set, pack, clean, return MemBuf */
-extern MemBuf httpPackedReply(http_version_t ver, http_status status, const char *ctype,
+SQUIDCEXTERN MemBuf httpPackedReply(http_version_t ver, http_status status, const char *ctype,
     int clen, time_t lmt, time_t expires);
 /* construct 304 reply and pack it into MemBuf, return MemBuf */
-extern MemBuf httpPacked304Reply(const HttpReply * rep);
+SQUIDCEXTERN MemBuf httpPacked304Reply(const HttpReply * rep);
 /* update when 304 reply is received for a cached object */
-extern void httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep);
+SQUIDCEXTERN void httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep);
 /* header manipulation */
-extern int httpReplyContentLen(const HttpReply * rep);
-extern const char *httpReplyContentType(const HttpReply * rep);
-extern time_t httpReplyExpires(const HttpReply * rep);
-extern int httpReplyHasCc(const HttpReply * rep, http_hdr_cc_type type);
-extern void httpRedirectReply(HttpReply *, http_status, const char *);
-extern int httpReplyBodySize(method_t, HttpReply *);
-extern void httpReplyBodyBuildSize(request_t *, HttpReply *, dlink_list *);
+SQUIDCEXTERN int httpReplyContentLen(const HttpReply * rep);
+SQUIDCEXTERN const char *httpReplyContentType(const HttpReply * rep);
+SQUIDCEXTERN time_t httpReplyExpires(const HttpReply * rep);
+SQUIDCEXTERN int httpReplyHasCc(const HttpReply * rep, http_hdr_cc_type type);
+SQUIDCEXTERN void httpRedirectReply(HttpReply *, http_status, const char *);
+SQUIDCEXTERN int httpReplyBodySize(method_t, HttpReply *);
+SQUIDCEXTERN void httpReplyBodyBuildSize(request_t *, HttpReply *, dlink_list *);
 
 /* Http Request */
-extern request_t *requestCreate(method_t, protocol_t, const char *urlpath);
-extern void requestDestroy(request_t *);
-extern request_t *requestLink(request_t *);
-extern void requestUnlink(request_t *);
-extern int httpRequestParseHeader(request_t * req, const char *parse_start);
-extern void httpRequestSwapOut(const request_t * req, StoreEntry * e);
-extern void httpRequestPack(const request_t * req, Packer * p);
-extern int httpRequestPrefixLen(const request_t * req);
-extern int httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConnection);
-extern int httpRequestHdrAllowedByName(http_hdr_type id);
-
-extern void icmpOpen(void);
-extern void icmpClose(void);
-extern void icmpPing(struct in_addr to);
-extern void icmpSourcePing(struct in_addr to, const icp_common_t *, const char *url);
-extern void icmpDomainPing(struct in_addr to, const char *domain);
+SQUIDCEXTERN request_t *requestCreate(method_t, protocol_t, const char *urlpath);
+SQUIDCEXTERN void requestDestroy(request_t *);
+SQUIDCEXTERN request_t *requestLink(request_t *);
+SQUIDCEXTERN void requestUnlink(request_t *);
+SQUIDCEXTERN int httpRequestParseHeader(request_t * req, const char *parse_start);
+SQUIDCEXTERN void httpRequestSwapOut(const request_t * req, StoreEntry * e);
+SQUIDCEXTERN void httpRequestPack(const request_t * req, Packer * p);
+SQUIDCEXTERN int httpRequestPrefixLen(const request_t * req);
+SQUIDCEXTERN int httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConnection);
+SQUIDCEXTERN int httpRequestHdrAllowedByName(http_hdr_type id);
+
+SQUIDCEXTERN void icmpOpen(void);
+SQUIDCEXTERN void icmpClose(void);
+SQUIDCEXTERN void icmpPing(struct in_addr to);
+SQUIDCEXTERN void icmpSourcePing(struct in_addr to, const icp_common_t *, const char *url);
+SQUIDCEXTERN void icmpDomainPing(struct in_addr to, const char *domain);
 
-extern void *icpCreateMessage(icp_opcode opcode,
+SQUIDCEXTERN void *icpCreateMessage(icp_opcode opcode,
     int flags,
     const char *url,
     int reqnum,
     int pad);
-extern int icpUdpSend(int, const struct sockaddr_in *, icp_common_t *, log_type, int);
-extern PF icpHandleUdp;
-extern PF icpUdpSendQueue;
-extern PF httpAccept;
+SQUIDCEXTERN int icpUdpSend(int, const struct sockaddr_in *, icp_common_t *, log_type, int);
+SQUIDCEXTERN PF icpHandleUdp;
+SQUIDCEXTERN PF icpUdpSendQueue;
+SQUIDCEXTERN PF httpAccept;
 
 #ifdef SQUID_SNMP
-extern PF snmpHandleUdp;
-extern void snmpInit(void);
-extern void snmpConnectionOpen(void);
-extern void snmpConnectionShutdown(void);
-extern void snmpConnectionClose(void);
-extern void snmpDebugOid(int lvl, oid * Name, snint Len);
-extern void addr2oid(struct in_addr addr, oid * Dest);
-extern struct in_addr *oid2addr(oid * id);
-extern struct in_addr *client_entry(struct in_addr *current);
-extern variable_list *snmp_basicFn(variable_list *, snint *);
-extern variable_list *snmp_confFn(variable_list *, snint *);
-extern variable_list *snmp_sysFn(variable_list *, snint *);
-extern variable_list *snmp_prfSysFn(variable_list *, snint *);
-extern variable_list *snmp_prfProtoFn(variable_list *, snint *);
-extern variable_list *snmp_prfPeerFn(variable_list *, snint *);
-extern variable_list *snmp_netIpFn(variable_list *, snint *);
-extern variable_list *snmp_netFqdnFn(variable_list *, snint *);
+SQUIDCEXTERN PF snmpHandleUdp;
+SQUIDCEXTERN void snmpInit(void);
+SQUIDCEXTERN void snmpConnectionOpen(void);
+SQUIDCEXTERN void snmpConnectionShutdown(void);
+SQUIDCEXTERN void snmpConnectionClose(void);
+SQUIDCEXTERN void snmpDebugOid(int lvl, oid * Name, snint Len);
+SQUIDCEXTERN void addr2oid(struct in_addr addr, oid * Dest);
+SQUIDCEXTERN struct in_addr *oid2addr(oid * id);
+SQUIDCEXTERN struct in_addr *client_entry(struct in_addr *current);
+SQUIDCEXTERN variable_list *snmp_basicFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_confFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_sysFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_prfSysFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_prfProtoFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_prfPeerFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_netIpFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_netFqdnFn(variable_list *, snint *);
 #if USE_DNSSERVERS
-extern variable_list *snmp_netDnsFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_netDnsFn(variable_list *, snint *);
 #else
-extern variable_list *snmp_netIdnsFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_netIdnsFn(variable_list *, snint *);
 #endif
-extern variable_list *snmp_meshPtblFn(variable_list *, snint *);
-extern variable_list *snmp_meshCtblFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_meshPtblFn(variable_list *, snint *);
+SQUIDCEXTERN variable_list *snmp_meshCtblFn(variable_list *, snint *);
 #endif /* SQUID_SNMP */
 
 #if USE_WCCP
-extern void wccpInit(void);
-extern void wccpConnectionOpen(void);
-extern void wccpConnectionShutdown(void);
-extern void wccpConnectionClose(void);
+SQUIDCEXTERN void wccpInit(void);
+SQUIDCEXTERN void wccpConnectionOpen(void);
+SQUIDCEXTERN void wccpConnectionShutdown(void);
+SQUIDCEXTERN void wccpConnectionClose(void);
 #endif /* USE_WCCP */
 
-extern void icpHandleIcpV3(int, struct sockaddr_in, char *, int);
-extern int icpCheckUdpHit(StoreEntry *, request_t * request);
-extern void icpConnectionsOpen(void);
-extern void icpConnectionShutdown(void);
-extern void icpConnectionClose(void);
-extern int icpSetCacheKey(const cache_key * key);
-extern const cache_key *icpGetCacheKey(const char *url, int reqnum);
+SQUIDCEXTERN void icpHandleIcpV3(int, struct sockaddr_in, char *, int);
+SQUIDCEXTERN int icpCheckUdpHit(StoreEntry *, request_t * request);
+SQUIDCEXTERN void icpConnectionsOpen(void);
+SQUIDCEXTERN void icpConnectionShutdown(void);
+SQUIDCEXTERN void icpConnectionClose(void);
+SQUIDCEXTERN int icpSetCacheKey(const cache_key * key);
+SQUIDCEXTERN const cache_key *icpGetCacheKey(const char *url, int reqnum);
 
-extern void ipcache_nbgethostbyname(const char *name,
+SQUIDCEXTERN void ipcache_nbgethostbyname(const char *name,
     IPH * handler,
     void *handlerData);
-extern EVH ipcache_purgelru;
-extern const ipcache_addrs *ipcache_gethostbyname(const char *, int flags);
-extern void ipcacheInvalidate(const char *);
-extern void ipcacheReleaseInvalid(const char *);
-extern void ipcache_init(void);
-extern void stat_ipcache_get(StoreEntry *);
-extern int ipcacheQueueDrain(void);
-extern void ipcacheCycleAddr(const char *name, ipcache_addrs *);
-extern void ipcacheMarkBadAddr(const char *name, struct in_addr);
-extern void ipcacheMarkGoodAddr(const char *name, struct in_addr);
-extern void ipcacheFreeMemory(void);
-extern ipcache_addrs *ipcacheCheckNumeric(const char *name);
-extern void ipcache_restart(void);
-extern int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr);
+SQUIDCEXTERN EVH ipcache_purgelru;
+SQUIDCEXTERN const ipcache_addrs *ipcache_gethostbyname(const char *, int flags);
+SQUIDCEXTERN void ipcacheInvalidate(const char *);
+SQUIDCEXTERN void ipcacheReleaseInvalid(const char *);
+SQUIDCEXTERN void ipcache_init(void);
+SQUIDCEXTERN void stat_ipcache_get(StoreEntry *);
+SQUIDCEXTERN int ipcacheQueueDrain(void);
+SQUIDCEXTERN void ipcacheCycleAddr(const char *name, ipcache_addrs *);
+SQUIDCEXTERN void ipcacheMarkBadAddr(const char *name, struct in_addr);
+SQUIDCEXTERN void ipcacheMarkGoodAddr(const char *name, struct in_addr);
+SQUIDCEXTERN void ipcacheFreeMemory(void);
+SQUIDCEXTERN ipcache_addrs *ipcacheCheckNumeric(const char *name);
+SQUIDCEXTERN void ipcache_restart(void);
+SQUIDCEXTERN int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr);
 
 /* MemBuf */
 /* init with specific sizes */
-extern void memBufInit(MemBuf * mb, mb_size_t szInit, mb_size_t szMax);
+SQUIDCEXTERN void memBufInit(MemBuf * mb, mb_size_t szInit, mb_size_t szMax);
 /* init with defaults */
-extern void memBufDefInit(MemBuf * mb);
+SQUIDCEXTERN void memBufDefInit(MemBuf * mb);
 /* cleans mb; last function to call if you do not give .buf away */
-extern void memBufClean(MemBuf * mb);
+SQUIDCEXTERN void memBufClean(MemBuf * mb);
 /* resets mb preserving (or initializing if needed) memory buffer */
-extern void memBufReset(MemBuf * mb);
+SQUIDCEXTERN void memBufReset(MemBuf * mb);
 /* unfirtunate hack to test if the buffer has been Init()ialized */
-extern int memBufIsNull(MemBuf * mb);
+SQUIDCEXTERN int memBufIsNull(MemBuf * mb);
 /* calls memcpy, appends exactly size bytes, extends buffer if needed */
-extern void memBufAppend(MemBuf * mb, const char *buf, mb_size_t size);
+SQUIDCEXTERN void memBufAppend(MemBuf * mb, const char *buf, mb_size_t size);
 /* calls snprintf, extends buffer if needed */
 #if STDC_HEADERS
-extern void
+SQUIDCEXTERN void
 memBufPrintf(MemBuf * mb, const char *fmt,...) PRINTF_FORMAT_ARG2;
 #else
-extern void memBufPrintf();
+SQUIDCEXTERN void memBufPrintf();
 #endif
 /* vprintf for other printf()'s to use */
-extern void memBufVPrintf(MemBuf * mb, const char *fmt, va_list ap);
+SQUIDCEXTERN void memBufVPrintf(MemBuf * mb, const char *fmt, va_list ap);
 /* returns free() function to be used, _freezes_ the object! */
-extern FREE *memBufFreeFunc(MemBuf * mb);
+SQUIDCEXTERN FREE *memBufFreeFunc(MemBuf * mb);
 /* puts report on MemBuf _module_ usage into mb */
-extern void memBufReport(MemBuf * mb);
+SQUIDCEXTERN void memBufReport(MemBuf * mb);
 
-extern char *mime_get_header(const char *mime, const char *header);
-extern char *mime_get_header_field(const char *mime, const char *name, const char *prefix);
-extern size_t headersEnd(const char *, size_t);
-extern const char *mime_get_auth(const char *hdr, const char *auth_scheme, const char **auth_field);
-
-extern void mimeInit(char *filename);
-extern void mimeFreeMemory(void);
-extern char *mimeGetContentEncoding(const char *fn);
-extern char *mimeGetContentType(const char *fn);
-extern char *mimeGetIcon(const char *fn);
-extern const char *mimeGetIconURL(const char *fn);
-extern char mimeGetTransferMode(const char *fn);
-extern int mimeGetDownloadOption(const char *fn);
-extern int mimeGetViewOption(const char *fn);
+SQUIDCEXTERN char *mime_get_header(const char *mime, const char *header);
+SQUIDCEXTERN char *mime_get_header_field(const char *mime, const char *name, const char *prefix);
+SQUIDCEXTERN size_t headersEnd(const char *, size_t);
+SQUIDCEXTERN const char *mime_get_auth(const char *hdr, const char *auth_scheme, const char **auth_field);
+
+SQUIDCEXTERN void mimeInit(char *filename);
+SQUIDCEXTERN void mimeFreeMemory(void);
+SQUIDCEXTERN char *mimeGetContentEncoding(const char *fn);
+SQUIDCEXTERN char *mimeGetContentType(const char *fn);
+SQUIDCEXTERN char *mimeGetIcon(const char *fn);
+SQUIDCEXTERN const char *mimeGetIconURL(const char *fn);
+SQUIDCEXTERN char mimeGetTransferMode(const char *fn);
+SQUIDCEXTERN int mimeGetDownloadOption(const char *fn);
+SQUIDCEXTERN int mimeGetViewOption(const char *fn);
 
-extern int mcastSetTtl(int, int);
-extern IPH mcastJoinGroups;
+SQUIDCEXTERN int mcastSetTtl(int, int);
+SQUIDCEXTERN IPH mcastJoinGroups;
 
 /* Labels for hierachical log file */
 /* put them all here for easier reference when writing a logfile analyzer */
 
 
-extern peer *getFirstPeer(void);
-extern peer *getFirstUpParent(request_t *);
-extern peer *getNextPeer(peer *);
-extern peer *getSingleParent(request_t *);
-extern int neighborsCount(request_t *);
-extern int neighborsUdpPing(request_t *,
+SQUIDCEXTERN peer *getFirstPeer(void);
+SQUIDCEXTERN peer *getFirstUpParent(request_t *);
+SQUIDCEXTERN peer *getNextPeer(peer *);
+SQUIDCEXTERN peer *getSingleParent(request_t *);
+SQUIDCEXTERN int neighborsCount(request_t *);
+SQUIDCEXTERN int neighborsUdpPing(request_t *,
     StoreEntry *,
     IRCB * callback,
     void *data,
     int *exprep,
     int *timeout);
-extern void neighborAddAcl(const char *, const char *);
-extern void neighborsUdpAck(const cache_key *, icp_common_t *, const struct sockaddr_in *);
-extern void neighborAdd(const char *, const char *, int, int, int, int, int);
-extern void neighbors_open(int);
-extern peer *peerFindByName(const char *);
-extern peer *peerFindByNameAndPort(const char *, unsigned short);
-extern peer *getDefaultParent(request_t * request);
-extern peer *getRoundRobinParent(request_t * request);
-extern peer *getWeightedRoundRobinParent(request_t * request);
-EVH peerClearRR;
-extern peer *getAnyParent(request_t * request);
-extern lookup_t peerDigestLookup(peer * p, request_t * request);
-extern peer *neighborsDigestSelect(request_t * request);
-extern void peerNoteDigestLookup(request_t * request, peer * p, lookup_t lookup);
-extern void peerNoteDigestGone(peer * p);
-extern int neighborUp(const peer * e);
-extern CBDUNL peerDestroy;
-extern const char *neighborTypeStr(const peer * e);
-extern peer_t neighborType(const peer *, const request_t *);
-extern void peerConnectFailed(peer *);
-extern void peerConnectSucceded(peer *);
-extern void dump_peer_options(StoreEntry *, peer *);
-extern int peerHTTPOkay(const peer *, request_t *);
-extern peer *whichPeer(const struct sockaddr_in *from);
+SQUIDCEXTERN void neighborAddAcl(const char *, const char *);
+SQUIDCEXTERN void neighborsUdpAck(const cache_key *, icp_common_t *, const struct sockaddr_in *);
+SQUIDCEXTERN void neighborAdd(const char *, const char *, int, int, int, int, int);
+SQUIDCEXTERN void neighbors_open(int);
+SQUIDCEXTERN peer *peerFindByName(const char *);
+SQUIDCEXTERN peer *peerFindByNameAndPort(const char *, unsigned short);
+SQUIDCEXTERN peer *getDefaultParent(request_t * request);
+SQUIDCEXTERN peer *getRoundRobinParent(request_t * request);
+SQUIDCEXTERN peer *getWeightedRoundRobinParent(request_t * request);
+SQUIDCEXTERN EVH peerClearRR;
+SQUIDCEXTERN peer *getAnyParent(request_t * request);
+SQUIDCEXTERN lookup_t peerDigestLookup(peer * p, request_t * request);
+SQUIDCEXTERN peer *neighborsDigestSelect(request_t * request);
+SQUIDCEXTERN void peerNoteDigestLookup(request_t * request, peer * p, lookup_t lookup);
+SQUIDCEXTERN void peerNoteDigestGone(peer * p);
+SQUIDCEXTERN int neighborUp(const peer * e);
+SQUIDCEXTERN CBDUNL peerDestroy;
+SQUIDCEXTERN const char *neighborTypeStr(const peer * e);
+SQUIDCEXTERN peer_t neighborType(const peer *, const request_t *);
+SQUIDCEXTERN void peerConnectFailed(peer *);
+SQUIDCEXTERN void peerConnectSucceded(peer *);
+SQUIDCEXTERN void dump_peer_options(StoreEntry *, peer *);
+SQUIDCEXTERN int peerHTTPOkay(const peer *, request_t *);
+SQUIDCEXTERN peer *whichPeer(const struct sockaddr_in *from);
 #if USE_HTCP
-extern void neighborsHtcpReply(const cache_key *, htcpReplyData *, const struct sockaddr_in *);
+SQUIDCEXTERN void neighborsHtcpReply(const cache_key *, htcpReplyData *, const struct sockaddr_in *);
 #endif
 
-extern void netdbInit(void);
-extern void netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt);
-extern void netdbPingSite(const char *hostname);
-extern void netdbDump(StoreEntry *);
-extern int netdbHops(struct in_addr);
-extern void netdbFreeMemory(void);
-extern int netdbHostHops(const char *host);
-extern int netdbHostRtt(const char *host);
-extern int netdbHostPeerRtt(const char *host, peer * p);
-extern void netdbUpdatePeer(request_t *, peer * e, int rtt, int hops);
-extern void netdbDeleteAddrNetwork(struct in_addr addr);
-extern void netdbBinaryExchange(StoreEntry *);
-extern EVH netdbExchangeStart;
-extern void netdbExchangeUpdatePeer(struct in_addr, peer *, double, double);
-extern peer *netdbClosestParent(request_t *);
-extern void netdbHostData(const char *host, int *samp, int *rtt, int *hops);
-
-extern void cachemgrStart(int fd, request_t * request, StoreEntry * entry);
-extern void cachemgrRegister(const char *, const char *, OBJH *, int, int);
-extern void cachemgrInit(void);
+SQUIDCEXTERN void netdbInit(void);
+SQUIDCEXTERN void netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt);
+SQUIDCEXTERN void netdbPingSite(const char *hostname);
+SQUIDCEXTERN void netdbDump(StoreEntry *);
+SQUIDCEXTERN int netdbHops(struct in_addr);
+SQUIDCEXTERN void netdbFreeMemory(void);
+SQUIDCEXTERN int netdbHostHops(const char *host);
+SQUIDCEXTERN int netdbHostRtt(const char *host);
+SQUIDCEXTERN int netdbHostPeerRtt(const char *host, peer * p);
+SQUIDCEXTERN void netdbUpdatePeer(request_t *, peer * e, int rtt, int hops);
+SQUIDCEXTERN void netdbDeleteAddrNetwork(struct in_addr addr);
+SQUIDCEXTERN void netdbBinaryExchange(StoreEntry *);
+SQUIDCEXTERN EVH netdbExchangeStart;
+SQUIDCEXTERN void netdbExchangeUpdatePeer(struct in_addr, peer *, double, double);
+SQUIDCEXTERN peer *netdbClosestParent(request_t *);
+SQUIDCEXTERN void netdbHostData(const char *host, int *samp, int *rtt, int *hops);
+
+SQUIDCEXTERN void cachemgrStart(int fd, request_t * request, StoreEntry * entry);
+SQUIDCEXTERN void cachemgrRegister(const char *, const char *, OBJH *, int, int);
+SQUIDCEXTERN void cachemgrInit(void);
 
-extern void peerSelect(request_t *, StoreEntry *, PSC *, void *data);
-extern void peerSelectInit(void);
+SQUIDCEXTERN void peerSelect(request_t *, StoreEntry *, PSC *, void *data);
+SQUIDCEXTERN void peerSelectInit(void);
 
 /* peer_digest.c */
-extern PeerDigest *peerDigestCreate(peer * p);
-extern void peerDigestNeeded(PeerDigest * pd);
-extern void peerDigestNotePeerGone(PeerDigest * pd);
-extern void peerDigestStatsReport(const PeerDigest * pd, StoreEntry * e);
+SQUIDCEXTERN PeerDigest *peerDigestCreate(peer * p);
+SQUIDCEXTERN void peerDigestNeeded(PeerDigest * pd);
+SQUIDCEXTERN void peerDigestNotePeerGone(PeerDigest * pd);
+SQUIDCEXTERN void peerDigestStatsReport(const PeerDigest * pd, StoreEntry * e);
 
 /* forward.c */
-extern void fwdStart(int, StoreEntry *, request_t *);
-extern DEFER fwdCheckDeferRead;
-extern void fwdFail(FwdState *, ErrorState *);
-extern void fwdUnregister(int fd, FwdState *);
-extern void fwdComplete(FwdState * fwdState);
-extern void fwdInit(void);
-extern int fwdReforwardableStatus(http_status s);
-extern void fwdServersFree(FwdServer ** FS);
+SQUIDCEXTERN void fwdStart(int, StoreEntry *, request_t *);
+SQUIDCEXTERN DEFER fwdCheckDeferRead;
+SQUIDCEXTERN void fwdFail(FwdState *, ErrorState *);
+SQUIDCEXTERN void fwdUnregister(int fd, FwdState *);
+SQUIDCEXTERN void fwdComplete(FwdState * fwdState);
+SQUIDCEXTERN void fwdInit(void);
+SQUIDCEXTERN int fwdReforwardableStatus(http_status s);
+SQUIDCEXTERN void fwdServersFree(FwdServer ** FS);
 #if WIP_FWD_LOG
-extern void fwdUninit(void);
-extern void fwdLogRotate(void);
-extern void fwdStatus(FwdState *, http_status);
+SQUIDCEXTERN void fwdUninit(void);
+SQUIDCEXTERN void fwdLogRotate(void);
+SQUIDCEXTERN void fwdStatus(FwdState *, http_status);
 #endif
 struct in_addr getOutgoingAddr(request_t * request);
 unsigned long getOutgoingTOS(request_t * request);
 
-extern void urnStart(request_t *, StoreEntry *);
+SQUIDCEXTERN void urnStart(request_t *, StoreEntry *);
 
-extern void redirectStart(clientHttpRequest *, RH *, void *);
-extern void redirectInit(void);
-extern void redirectShutdown(void);
-
-/* auth_modules.c */
-extern void authSchemeSetup(void);
-
-/* authenticate.c */
-extern void authenticateAuthUserMerge(auth_user_t *, auth_user_t *);
-extern auth_user_t *authenticateAuthUserNew(const char *);
-extern int authenticateAuthSchemeId(const char *typestr);
-extern void authenticateStart(auth_user_request_t *, RH *, void *);
-extern void authenticateSchemeInit(void);
-extern void authenticateInit(authConfig *);
-extern void authenticateShutdown(void);
-extern void authenticateFixHeader(HttpReply *, auth_user_request_t *, request_t *, int, int);
-extern void authenticateAddTrailer(HttpReply *, auth_user_request_t *, request_t *, int);
-extern auth_acl_t authenticateTryToAuthenticateAndSetAuthUser(auth_user_request_t **, http_hdr_type, request_t *, ConnStateData *, struct in_addr);
-extern void authenticateAuthUserUnlock(auth_user_t * auth_user);
-extern void authenticateAuthUserLock(auth_user_t * auth_user);
-extern void authenticateAuthUserRequestUnlock(auth_user_request_t *);
-extern void authenticateAuthUserRequestLock(auth_user_request_t *);
-extern char *authenticateAuthUserRequestMessage(auth_user_request_t *);
-extern int authenticateAuthUserInuse(auth_user_t * auth_user);
-extern void authenticateAuthUserRequestSetIp(auth_user_request_t *, struct in_addr);
-extern void authenticateAuthUserRequestRemoveIp(auth_user_request_t *, struct in_addr);
-extern void authenticateAuthUserRequestClearIp(auth_user_request_t *);
-extern size_t authenticateAuthUserRequestIPCount(auth_user_request_t *);
-extern int authenticateDirection(auth_user_request_t *);
-extern FREE authenticateFreeProxyAuthUser;
-extern void authenticateFreeProxyAuthUserACLResults(void *data);
-extern void authenticateProxyUserCacheCleanup(void *);
-extern void authenticateInitUserCache(void);
-extern int authenticateActiveSchemeCount(void);
-extern int authenticateSchemeCount(void);
-extern void authenticateUserNameCacheAdd(auth_user_t * auth_user);
-extern int authenticateCheckAuthUserIP(struct in_addr request_src_addr, auth_user_request_t * auth_user);
-extern int authenticateUserAuthenticated(auth_user_request_t *);
-extern void authenticateUserCacheRestart(void);
-extern char *authenticateUserUsername(auth_user_t *);
-extern char *authenticateUserRequestUsername(auth_user_request_t *);
-extern int authenticateValidateUser(auth_user_request_t *);
-extern void authenticateOnCloseConnection(ConnStateData * conn);
-extern void authSchemeAdd(const char *type, AUTHSSETUP * setup);
-
-extern void refreshAddToList(const char *, int, time_t, int, time_t);
-extern int refreshIsCachable(const StoreEntry *);
-extern int refreshCheckHTTP(const StoreEntry *, request_t *);
-extern int refreshCheckICP(const StoreEntry *, request_t *);
-extern int refreshCheckHTCP(const StoreEntry *, request_t *);
-extern int refreshCheckDigest(const StoreEntry *, time_t delta);
-extern time_t getMaxAge(const char *url);
-extern void refreshInit(void);
-
-extern void serverConnectionsClose(void);
-extern void shut_down(int);
-
-
-extern void start_announce(void *unused);
-extern void sslStart(clientHttpRequest *, size_t *, int *);
-extern void waisStart(FwdState *);
+SQUIDCEXTERN void redirectStart(clientHttpRequest *, RH *, void *);
+SQUIDCEXTERN void redirectInit(void);
+SQUIDCEXTERN void redirectShutdown(void);
+
+SQUIDCEXTERN void refreshAddToList(const char *, int, time_t, int, time_t);
+SQUIDCEXTERN int refreshIsCachable(const StoreEntry *);
+SQUIDCEXTERN int refreshCheckHTTP(const StoreEntry *, request_t *);
+SQUIDCEXTERN int refreshCheckICP(const StoreEntry *, request_t *);
+SQUIDCEXTERN int refreshCheckHTCP(const StoreEntry *, request_t *);
+SQUIDCEXTERN int refreshCheckDigest(const StoreEntry *, time_t delta);
+SQUIDCEXTERN time_t getMaxAge(const char *url);
+SQUIDCEXTERN void refreshInit(void);
+
+SQUIDCEXTERN void serverConnectionsClose(void);
+SQUIDCEXTERN void shut_down(int);
+
+
+SQUIDCEXTERN void start_announce(void *unused);
+SQUIDCEXTERN void sslStart(clientHttpRequest *, size_t *, int *);
+SQUIDCEXTERN void waisStart(FwdState *);
 
 /* ident.c */
 #if USE_IDENT
-extern void identStart(struct sockaddr_in *me, struct sockaddr_in *my_peer,
+SQUIDCEXTERN void identStart(struct sockaddr_in *me, struct sockaddr_in *my_peer,
     IDCB * callback, void *cbdata);
-extern void identInit(void);
+SQUIDCEXTERN void identInit(void);
 #endif
 
-extern void statInit(void);
-extern void statFreeMemory(void);
-extern double median_svc_get(int, int);
-extern void pconnHistCount(int, int);
-extern int stat5minClientRequests(void);
-extern double stat5minCPUUsage(void);
-extern const char *storeEntryFlags(const StoreEntry *);
-extern double statRequestHitRatio(int minutes);
-extern double statRequestHitMemoryRatio(int minutes);
-extern double statRequestHitDiskRatio(int minutes);
-extern double statByteHitRatio(int minutes);
-extern int storeEntryLocked(const StoreEntry *);
+SQUIDCEXTERN void statInit(void);
+SQUIDCEXTERN void statFreeMemory(void);
+SQUIDCEXTERN double median_svc_get(int, int);
+SQUIDCEXTERN void pconnHistCount(int, int);
+SQUIDCEXTERN int stat5minClientRequests(void);
+SQUIDCEXTERN double stat5minCPUUsage(void);
+SQUIDCEXTERN const char *storeEntryFlags(const StoreEntry *);
+SQUIDCEXTERN double statRequestHitRatio(int minutes);
+SQUIDCEXTERN double statRequestHitMemoryRatio(int minutes);
+SQUIDCEXTERN double statRequestHitDiskRatio(int minutes);
+SQUIDCEXTERN double statByteHitRatio(int minutes);
+SQUIDCEXTERN int storeEntryLocked(const StoreEntry *);
 
 
 /* StatHist */
-extern void statHistClean(StatHist * H);
-extern void statHistCount(StatHist * H, double val);
-extern void statHistCopy(StatHist * Dest, const StatHist * Orig);
-extern void statHistSafeCopy(StatHist * Dest, const StatHist * Orig);
-extern double statHistDeltaMedian(const StatHist * A, const StatHist * B);
-extern void statHistDump(const StatHist * H, StoreEntry * sentry, StatHistBinDumper * bd);
-extern void statHistLogInit(StatHist * H, int capacity, double min, double max);
-extern void statHistEnumInit(StatHist * H, int last_enum);
-extern void statHistIntInit(StatHist * H, int n);
-extern StatHistBinDumper statHistEnumDumper;
-extern StatHistBinDumper statHistIntDumper;
+SQUIDCEXTERN void statHistClean(StatHist * H);
+SQUIDCEXTERN void statHistCount(StatHist * H, double val);
+SQUIDCEXTERN void statHistCopy(StatHist * Dest, const StatHist * Orig);
+SQUIDCEXTERN void statHistSafeCopy(StatHist * Dest, const StatHist * Orig);
+SQUIDCEXTERN double statHistDeltaMedian(const StatHist * A, const StatHist * B);
+SQUIDCEXTERN void statHistDump(const StatHist * H, StoreEntry * sentry, StatHistBinDumper * bd);
+SQUIDCEXTERN void statHistLogInit(StatHist * H, int capacity, double min, double max);
+SQUIDCEXTERN void statHistEnumInit(StatHist * H, int last_enum);
+SQUIDCEXTERN void statHistIntInit(StatHist * H, int n);
+SQUIDCEXTERN StatHistBinDumper statHistEnumDumper;
+SQUIDCEXTERN StatHistBinDumper statHistIntDumper;
 
 
 /* mem */
-extern void memInit(void);
-extern void memClean(void);
-extern void memInitModule(void);
-extern void memCleanModule(void);
-extern void memConfigure(void);
-extern void *memAllocate(mem_type);
-extern void *memAllocString(size_t net_size, size_t * gross_size);
-extern void *memAllocBuf(size_t net_size, size_t * gross_size);
-extern void *memReallocBuf(void *buf, size_t net_size, size_t * gross_size);
-extern void memFree(void *, int type);
-extern void memFree4K(void *);
-extern void memFree8K(void *);
-extern void memFreeString(size_t size, void *);
-extern void memFreeBuf(size_t size, void *);
-extern FREE *memFreeBufFunc(size_t size);
-extern int memInUse(mem_type);
-extern void memDataInit(mem_type, const char *, size_t, int);
-extern void memCheckInit(void);
+SQUIDCEXTERN void memInit(void);
+SQUIDCEXTERN void memClean(void);
+SQUIDCEXTERN void memInitModule(void);
+SQUIDCEXTERN void memCleanModule(void);
+SQUIDCEXTERN void memConfigure(void);
+SQUIDCEXTERN void *memAllocate(mem_type);
+SQUIDCEXTERN void *memAllocString(size_t net_size, size_t * gross_size);
+SQUIDCEXTERN void *memAllocBuf(size_t net_size, size_t * gross_size);
+SQUIDCEXTERN void *memReallocBuf(void *buf, size_t net_size, size_t * gross_size);
+SQUIDCEXTERN void memFree(void *, int type);
+SQUIDCEXTERN void memFree4K(void *);
+SQUIDCEXTERN void memFree8K(void *);
+SQUIDCEXTERN void memFreeString(size_t size, void *);
+SQUIDCEXTERN void memFreeBuf(size_t size, void *);
+SQUIDCEXTERN FREE *memFreeBufFunc(size_t size);
+SQUIDCEXTERN int memInUse(mem_type);
+SQUIDCEXTERN void memDataInit(mem_type, const char *, size_t, int);
+SQUIDCEXTERN void memCheckInit(void);
 
 /* MemPool */
-extern MemPool *memPoolCreate(const char *label, size_t obj_size);
-extern void *memPoolAlloc(MemPool * pool);
-extern void memPoolFree(MemPool * pool, void *obj);
-extern void memPoolDestroy(MemPool ** pool);
-extern MemPoolIterator *memPoolGetFirst(void);
-extern MemPool *memPoolGetNext(MemPoolIterator ** iter);
-extern void memPoolSetChunkSize(MemPool * pool, size_t chunksize);
-extern void memPoolSetIdleLimit(size_t new_idle_limit);
-extern int memPoolGetStats(MemPoolStats * stats, MemPool * pool);
-extern int memPoolGetGlobalStats(MemPoolGlobalStats * stats);
-extern void memPoolClean(time_t maxage);
+SQUIDCEXTERN MemPool *memPoolCreate(const char *label, size_t obj_size);
+SQUIDCEXTERN void *memPoolAlloc(MemPool * pool);
+SQUIDCEXTERN void memPoolFree(MemPool * pool, void *obj);
+SQUIDCEXTERN void memPoolDestroy(MemPool ** pool);
+SQUIDCEXTERN MemPoolIterator *memPoolGetFirst(void);
+SQUIDCEXTERN MemPool *memPoolGetNext(MemPoolIterator ** iter);
+SQUIDCEXTERN void memPoolSetChunkSize(MemPool * pool, size_t chunksize);
+SQUIDCEXTERN void memPoolSetIdleLimit(size_t new_idle_limit);
+SQUIDCEXTERN int memPoolGetStats(MemPoolStats * stats, MemPool * pool);
+SQUIDCEXTERN int memPoolGetGlobalStats(MemPoolGlobalStats * stats);
+SQUIDCEXTERN void memPoolClean(time_t maxage);
 
 /* Mem */
-extern void memReport(StoreEntry * e);
-extern void memConfigure(void);
-extern void memPoolCleanIdlePools(void *unused);
-extern int memPoolInUseCount(MemPool * pool);
-extern int memPoolsTotalAllocated(void);
-
-extern int stmemFreeDataUpto(mem_hdr *, int);
-extern void stmemAppend(mem_hdr *, const char *, int);
-extern ssize_t stmemCopy(const mem_hdr *, off_t, char *, size_t);
-extern void stmemFree(mem_hdr *);
-extern void stmemFreeData(mem_hdr *);
+SQUIDCEXTERN void memReport(StoreEntry * e);
+SQUIDCEXTERN void memConfigure(void);
+SQUIDCEXTERN void memPoolCleanIdlePools(void *unused);
+SQUIDCEXTERN int memPoolInUseCount(MemPool * pool);
+SQUIDCEXTERN int memPoolsTotalAllocated(void);
+
+SQUIDCEXTERN int stmemFreeDataUpto(mem_hdr *, int);
+SQUIDCEXTERN void stmemAppend(mem_hdr *, const char *, int);
+SQUIDCEXTERN ssize_t stmemCopy(const mem_hdr *, off_t, char *, size_t);
+SQUIDCEXTERN void stmemFree(mem_hdr *);
+SQUIDCEXTERN void stmemFreeData(mem_hdr *);
 
 /* ----------------------------------------------------------------- */
 
 /*
  * store.c
  */
-extern StoreEntry *new_StoreEntry(int, const char *, const char *);
-extern StoreEntry *storeGet(const cache_key *);
-extern StoreEntry *storeGetPublic(const char *uri, const method_t method);
-extern StoreEntry *storeGetPublicByRequest(request_t * request);
-extern StoreEntry *storeGetPublicByRequestMethod(request_t * request, const method_t method);
-extern StoreEntry *storeCreateEntry(const char *, const char *, request_flags, method_t);
-extern void storeSetPublicKey(StoreEntry *);
-extern void storeComplete(StoreEntry *);
-extern void storeInit(void);
-extern void storeAbort(StoreEntry *);
-extern void storeAppend(StoreEntry *, const char *, int);
-extern void storeLockObject(StoreEntry *);
-extern void storeRelease(StoreEntry *);
-extern int storeUnlockObject(StoreEntry *);
-extern EVH storeMaintainSwapSpace;
-extern void storeExpireNow(StoreEntry *);
-extern void storeReleaseRequest(StoreEntry *);
-extern void storeConfigure(void);
-extern int storeCheckNegativeHit(StoreEntry *);
-extern void storeNegativeCache(StoreEntry *);
-extern void storeFreeMemory(void);
-extern int expiresMoreThan(time_t, time_t);
-extern int storeEntryValidToSend(StoreEntry *);
-extern void storeTimestampsSet(StoreEntry *);
-extern void storeRegisterAbort(StoreEntry * e, STABH * cb, void *);
-extern void storeUnregisterAbort(StoreEntry * e);
-extern void storeMemObjectDump(MemObject * mem);
-extern void storeEntryDump(const StoreEntry * e, int debug_lvl);
-extern const char *storeUrl(const StoreEntry *);
-extern void storeCreateMemObject(StoreEntry *, const char *, const char *);
-extern void storeCopyNotModifiedReplyHeaders(MemObject * O, MemObject * N);
-extern void storeBuffer(StoreEntry *);
-extern void storeBufferFlush(StoreEntry *);
-extern void storeHashInsert(StoreEntry * e, const cache_key *);
-extern void storeSetMemStatus(StoreEntry * e, int);
+SQUIDCEXTERN StoreEntry *new_StoreEntry(int, const char *, const char *);
+SQUIDCEXTERN StoreEntry *storeGet(const cache_key *);
+SQUIDCEXTERN StoreEntry *storeGetPublic(const char *uri, const method_t method);
+SQUIDCEXTERN StoreEntry *storeGetPublicByRequest(request_t * request);
+SQUIDCEXTERN StoreEntry *storeGetPublicByRequestMethod(request_t * request, const method_t method);
+SQUIDCEXTERN StoreEntry *storeCreateEntry(const char *, const char *, request_flags, method_t);
+SQUIDCEXTERN void storeSetPublicKey(StoreEntry *);
+SQUIDCEXTERN void storeComplete(StoreEntry *);
+SQUIDCEXTERN void storeInit(void);
+SQUIDCEXTERN void storeAbort(StoreEntry *);
+SQUIDCEXTERN void storeAppend(StoreEntry *, const char *, int);
+SQUIDCEXTERN void storeLockObject(StoreEntry *);
+SQUIDCEXTERN void storeRelease(StoreEntry *);
+SQUIDCEXTERN int storeUnlockObject(StoreEntry *);
+SQUIDCEXTERN EVH storeMaintainSwapSpace;
+SQUIDCEXTERN void storeExpireNow(StoreEntry *);
+SQUIDCEXTERN void storeReleaseRequest(StoreEntry *);
+SQUIDCEXTERN void storeConfigure(void);
+SQUIDCEXTERN int storeCheckNegativeHit(StoreEntry *);
+SQUIDCEXTERN void storeNegativeCache(StoreEntry *);
+SQUIDCEXTERN void storeFreeMemory(void);
+SQUIDCEXTERN int expiresMoreThan(time_t, time_t);
+SQUIDCEXTERN int storeEntryValidToSend(StoreEntry *);
+SQUIDCEXTERN void storeTimestampsSet(StoreEntry *);
+SQUIDCEXTERN void storeRegisterAbort(StoreEntry * e, STABH * cb, void *);
+SQUIDCEXTERN void storeUnregisterAbort(StoreEntry * e);
+SQUIDCEXTERN void storeMemObjectDump(MemObject * mem);
+SQUIDCEXTERN void storeEntryDump(const StoreEntry * e, int debug_lvl);
+SQUIDCEXTERN const char *storeUrl(const StoreEntry *);
+SQUIDCEXTERN void storeCreateMemObject(StoreEntry *, const char *, const char *);
+SQUIDCEXTERN void storeCopyNotModifiedReplyHeaders(MemObject * O, MemObject * N);
+SQUIDCEXTERN void storeBuffer(StoreEntry *);
+SQUIDCEXTERN void storeBufferFlush(StoreEntry *);
+SQUIDCEXTERN void storeHashInsert(StoreEntry * e, const cache_key *);
+SQUIDCEXTERN void storeSetMemStatus(StoreEntry * e, int);
 #if STDC_HEADERS
-extern void
+SQUIDCEXTERN void
 storeAppendPrintf(StoreEntry *, const char *,...) PRINTF_FORMAT_ARG2;
 #else
-extern void storeAppendPrintf();
+SQUIDCEXTERN void storeAppendPrintf();
 #endif
-extern void storeAppendVPrintf(StoreEntry *, const char *, va_list ap);
-extern int storeCheckCachable(StoreEntry * e);
-extern void storeSetPrivateKey(StoreEntry *);
-extern int objectLen(const StoreEntry * e);
-extern int contentLen(const StoreEntry * e);
-extern HttpReply *storeEntryReply(StoreEntry *);
-extern int storeTooManyDiskFilesOpen(void);
-extern void storeEntryReset(StoreEntry *);
-extern void storeHeapPositionUpdate(StoreEntry *, SwapDir *);
-extern void storeSwapFileNumberSet(StoreEntry * e, sfileno filn);
-extern void storeFsInit(void);
-extern void storeFsDone(void);
-extern void storeFsAdd(const char *, STSETUP *);
-extern void storeReplAdd(const char *, REMOVALPOLICYCREATE *);
+SQUIDCEXTERN void storeAppendVPrintf(StoreEntry *, const char *, va_list ap);
+SQUIDCEXTERN int storeCheckCachable(StoreEntry * e);
+SQUIDCEXTERN void storeSetPrivateKey(StoreEntry *);
+SQUIDCEXTERN int objectLen(const StoreEntry * e);
+SQUIDCEXTERN int contentLen(const StoreEntry * e);
+SQUIDCEXTERN HttpReply *storeEntryReply(StoreEntry *);
+SQUIDCEXTERN int storeTooManyDiskFilesOpen(void);
+SQUIDCEXTERN void storeEntryReset(StoreEntry *);
+SQUIDCEXTERN void storeHeapPositionUpdate(StoreEntry *, SwapDir *);
+SQUIDCEXTERN void storeSwapFileNumberSet(StoreEntry * e, sfileno filn);
+SQUIDCEXTERN void storeFsInit(void);
+SQUIDCEXTERN void storeFsDone(void);
+SQUIDCEXTERN void storeFsAdd(const char *, STSETUP *);
+SQUIDCEXTERN void storeReplAdd(const char *, REMOVALPOLICYCREATE *);
 
 /* store_modules.c */
-extern void storeFsSetup(void);
+SQUIDCEXTERN void storeFsSetup(void);
 
 /* repl_modules.c */
-extern void storeReplSetup(void);
+SQUIDCEXTERN void storeReplSetup(void);
 
 /* store_io.c */
-extern storeIOState *storeCreate(StoreEntry *, STFNCB *, STIOCB *, void *);
-extern storeIOState *storeOpen(StoreEntry *, STFNCB *, STIOCB *, void *);
-extern void storeClose(storeIOState *);
-extern void storeRead(storeIOState *, char *, size_t, off_t, STRCB *, void *);
-extern void storeWrite(storeIOState *, char *, size_t, off_t, FREE *);
-extern void storeUnlink(StoreEntry *);
-extern off_t storeOffset(storeIOState *);
+SQUIDCEXTERN storeIOState *storeCreate(StoreEntry *, STFNCB *, STIOCB *, void *);
+SQUIDCEXTERN storeIOState *storeOpen(StoreEntry *, STFNCB *, STIOCB *, void *);
+SQUIDCEXTERN void storeClose(storeIOState *);
+SQUIDCEXTERN void storeRead(storeIOState *, char *, size_t, off_t, STRCB *, void *);
+SQUIDCEXTERN void storeWrite(storeIOState *, char *, size_t, off_t, FREE *);
+SQUIDCEXTERN void storeUnlink(StoreEntry *);
+SQUIDCEXTERN off_t storeOffset(storeIOState *);
 
 /*
  * store_log.c
  */
-extern void storeLog(int tag, const StoreEntry * e);
-extern void storeLogRotate(void);
-extern void storeLogClose(void);
-extern void storeLogOpen(void);
+SQUIDCEXTERN void storeLog(int tag, const StoreEntry * e);
+SQUIDCEXTERN void storeLogRotate(void);
+SQUIDCEXTERN void storeLogClose(void);
+SQUIDCEXTERN void storeLogOpen(void);
 
 
 /*
  * store_key_*.c
  */
-extern cache_key *storeKeyDup(const cache_key *);
-extern cache_key *storeKeyCopy(cache_key *, const cache_key *);
-extern void storeKeyFree(const cache_key *);
-extern const cache_key *storeKeyScan(const char *);
-extern const char *storeKeyText(const cache_key *);
-extern const cache_key *storeKeyPublic(const char *, const method_t);
-extern const cache_key *storeKeyPublicByRequest(request_t *);
-extern const cache_key *storeKeyPublicByRequestMethod(request_t *, const method_t);
-extern const cache_key *storeKeyPrivate(const char *, method_t, int);
-extern int storeKeyHashBuckets(int);
-extern int storeKeyNull(const cache_key *);
-extern void storeKeyInit(void);
-extern HASHHASH storeKeyHashHash;
-extern HASHCMP storeKeyHashCmp;
+SQUIDCEXTERN cache_key *storeKeyDup(const cache_key *);
+SQUIDCEXTERN cache_key *storeKeyCopy(cache_key *, const cache_key *);
+SQUIDCEXTERN void storeKeyFree(const cache_key *);
+SQUIDCEXTERN const cache_key *storeKeyScan(const char *);
+SQUIDCEXTERN const char *storeKeyText(const cache_key *);
+SQUIDCEXTERN const cache_key *storeKeyPublic(const char *, const method_t);
+SQUIDCEXTERN const cache_key *storeKeyPublicByRequest(request_t *);
+SQUIDCEXTERN const cache_key *storeKeyPublicByRequestMethod(request_t *, const method_t);
+SQUIDCEXTERN const cache_key *storeKeyPrivate(const char *, method_t, int);
+SQUIDCEXTERN int storeKeyHashBuckets(int);
+SQUIDCEXTERN int storeKeyNull(const cache_key *);
+SQUIDCEXTERN void storeKeyInit(void);
+SQUIDCEXTERN HASHHASH storeKeyHashHash;
+SQUIDCEXTERN HASHCMP storeKeyHashCmp;
 
 /*
  * store_digest.c
  */
-extern void storeDigestInit(void);
-extern void storeDigestNoteStoreReady(void);
-extern void storeDigestScheduleRebuild(void);
-extern void storeDigestDel(const StoreEntry * entry);
-extern void storeDigestReport(StoreEntry *);
+SQUIDCEXTERN void storeDigestInit(void);
+SQUIDCEXTERN void storeDigestNoteStoreReady(void);
+SQUIDCEXTERN void storeDigestScheduleRebuild(void);
+SQUIDCEXTERN void storeDigestDel(const StoreEntry * entry);
+SQUIDCEXTERN void storeDigestReport(StoreEntry *);
 
 /*
  * store_dir.c
  */
-extern OBJH storeDirStats;
-extern char *storeDirSwapLogFile(int, const char *);
-extern char *storeSwapDir(int);
-extern char *storeSwapFullPath(int, char *);
-extern char *storeSwapSubSubDir(int, char *);
-extern const char *storeSwapPath(int);
-extern int storeDirWriteCleanLogs(int reopen);
-extern STDIRSELECT *storeDirSelectSwapDir;
-extern int storeVerifySwapDirs(void);
-extern void storeCreateSwapDirectories(void);
-extern void storeDirCloseSwapLogs(void);
-extern void storeDirCloseTmpSwapLog(int dirn);
-extern void storeDirConfigure(void);
-extern void storeDirDiskFull(sdirno);
-extern void storeDirInit(void);
-extern void storeDirOpenSwapLogs(void);
-extern void storeDirSwapLog(const StoreEntry *, int op);
-extern void storeDirUpdateSwapSize(SwapDir *, size_t size, int sign);
-extern void storeDirSync(void);
-extern void storeDirCallback(void);
-extern void storeDirLRUDelete(StoreEntry *);
-extern void storeDirLRUAdd(StoreEntry *);
-extern int storeDirGetBlkSize(const char *path, int *blksize);
-extern int storeDirGetUFSStats(const char *, int *, int *, int *, int *);
+SQUIDCEXTERN OBJH storeDirStats;
+SQUIDCEXTERN char *storeDirSwapLogFile(int, const char *);
+SQUIDCEXTERN char *storeSwapDir(int);
+SQUIDCEXTERN char *storeSwapFullPath(int, char *);
+SQUIDCEXTERN char *storeSwapSubSubDir(int, char *);
+SQUIDCEXTERN const char *storeSwapPath(int);
+SQUIDCEXTERN int storeDirWriteCleanLogs(int reopen);
+SQUIDCEXTERN STDIRSELECT *storeDirSelectSwapDir;
+SQUIDCEXTERN int storeVerifySwapDirs(void);
+SQUIDCEXTERN void storeCreateSwapDirectories(void);
+SQUIDCEXTERN void storeDirCloseSwapLogs(void);
+SQUIDCEXTERN void storeDirCloseTmpSwapLog(int dirn);
+SQUIDCEXTERN void storeDirConfigure(void);
+SQUIDCEXTERN void storeDirDiskFull(sdirno);
+SQUIDCEXTERN void storeDirInit(void);
+SQUIDCEXTERN void storeDirOpenSwapLogs(void);
+SQUIDCEXTERN void storeDirSwapLog(const StoreEntry *, int op);
+SQUIDCEXTERN void storeDirUpdateSwapSize(SwapDir *, size_t size, int sign);
+SQUIDCEXTERN void storeDirSync(void);
+SQUIDCEXTERN void storeDirCallback(void);
+SQUIDCEXTERN void storeDirLRUDelete(StoreEntry *);
+SQUIDCEXTERN void storeDirLRUAdd(StoreEntry *);
+SQUIDCEXTERN int storeDirGetBlkSize(const char *path, int *blksize);
+SQUIDCEXTERN int storeDirGetUFSStats(const char *, int *, int *, int *, int *);
 
 /*
  * store_swapmeta.c
  */
-extern char *storeSwapMetaPack(tlv * tlv_list, int *length);
-extern tlv *storeSwapMetaBuild(StoreEntry * e);
-extern tlv *storeSwapMetaUnpack(const char *buf, int *hdrlen);
-extern void storeSwapTLVFree(tlv * n);
+SQUIDCEXTERN char *storeSwapMetaPack(tlv * tlv_list, int *length);
+SQUIDCEXTERN tlv *storeSwapMetaBuild(StoreEntry * e);
+SQUIDCEXTERN tlv *storeSwapMetaUnpack(const char *buf, int *hdrlen);
+SQUIDCEXTERN void storeSwapTLVFree(tlv * n);
 
 /*
  * store_rebuild.c
  */
-extern void storeRebuildStart(void);
-extern void storeRebuildComplete(struct _store_rebuild_data *);
-extern void storeRebuildProgress(int sd_index, int total, int sofar);
+SQUIDCEXTERN void storeRebuildStart(void);
+SQUIDCEXTERN void storeRebuildComplete(struct _store_rebuild_data *);
+SQUIDCEXTERN void storeRebuildProgress(int sd_index, int total, int sofar);
 
 /*
  * store_swapin.c
  */
-extern void storeSwapInStart(store_client *);
+SQUIDCEXTERN void storeSwapInStart(store_client *);
 
 /*
  * store_swapout.c
  */
-extern void storeSwapOut(StoreEntry * e);
-extern void storeSwapOutFileClose(StoreEntry * e);
-extern int storeSwapOutAble(const StoreEntry * e);
+SQUIDCEXTERN void storeSwapOut(StoreEntry * e);
+SQUIDCEXTERN void storeSwapOutFileClose(StoreEntry * e);
+SQUIDCEXTERN int storeSwapOutAble(const StoreEntry * e);
 
 /*
  * store_client.c
  */
-extern store_client *storeClientListAdd(StoreEntry * e, void *data);
-extern int storeClientCopyPending(store_client *, StoreEntry * e, void *data);
-extern int storeUnregister(store_client * sc, StoreEntry * e, void *data);
-extern off_t storeLowestMemReaderOffset(const StoreEntry * entry);
-extern void InvokeHandlers(StoreEntry * e);
-extern int storePendingNClients(const StoreEntry * e);
-extern int storeClientIsThisAClient(store_client * sc, void *someClient);
+SQUIDCEXTERN store_client *storeClientListAdd(StoreEntry * e, void *data);
+SQUIDCEXTERN int storeClientCopyPending(store_client *, StoreEntry * e, void *data);
+SQUIDCEXTERN int storeUnregister(store_client * sc, StoreEntry * e, void *data);
+SQUIDCEXTERN off_t storeLowestMemReaderOffset(const StoreEntry * entry);
+SQUIDCEXTERN void InvokeHandlers(StoreEntry * e);
+SQUIDCEXTERN int storePendingNClients(const StoreEntry * e);
+SQUIDCEXTERN int storeClientIsThisAClient(store_client * sc, void *someClient);
 
 
-extern const char *getMyHostname(void);
-extern const char *uniqueHostname(void);
-extern void safeunlink(const char *path, int quiet);
-extern void death(int sig);
-extern void fatal(const char *message);
+SQUIDCEXTERN const char *getMyHostname(void);
+SQUIDCEXTERN const char *uniqueHostname(void);
+SQUIDCEXTERN void safeunlink(const char *path, int quiet);
+SQUIDCEXTERN void death(int sig);
+SQUIDCEXTERN void fatal(const char *message);
 #if STDC_HEADERS
-extern void
+SQUIDCEXTERN void
 fatalf(const char *fmt,...) PRINTF_FORMAT_ARG1;
 #else
-extern void fatalf();
+SQUIDCEXTERN void fatalf();
 #endif
-extern void fatal_dump(const char *message);
-extern void sigusr2_handle(int sig);
-extern void sig_child(int sig);
-extern void leave_suid(void);
-extern void enter_suid(void);
-extern void no_suid(void);
-extern void writePidFile(void);
-extern void setSocketShutdownLifetimes(int);
-extern void setMaxFD(void);
-extern time_t getCurrentTime(void);
-extern int percent(int, int);
-extern double dpercent(double, double);
-extern void squid_signal(int sig, SIGHDLR *, int flags);
-extern pid_t readPidFile(void);
-extern struct in_addr inaddrFromHostent(const struct hostent *hp);
-extern int intAverage(int, int, int, int);
-extern double doubleAverage(double, double, int, int);
-extern void debug_trap(const char *);
-extern void logsFlush(void);
-extern const char *checkNullString(const char *p);
-extern void squid_getrusage(struct rusage *r);
-extern double rusage_cputime(struct rusage *r);
-extern int rusage_maxrss(struct rusage *r);
-extern int rusage_pagefaults(struct rusage *r);
-extern void releaseServerSockets(void);
-extern void PrintRusage(void);
-extern void dumpMallocStats(void);
+SQUIDCEXTERN void fatal_dump(const char *message);
+SQUIDCEXTERN void sigusr2_handle(int sig);
+SQUIDCEXTERN void sig_child(int sig);
+SQUIDCEXTERN void leave_suid(void);
+SQUIDCEXTERN void enter_suid(void);
+SQUIDCEXTERN void no_suid(void);
+SQUIDCEXTERN void writePidFile(void);
+SQUIDCEXTERN void setSocketShutdownLifetimes(int);
+SQUIDCEXTERN void setMaxFD(void);
+SQUIDCEXTERN time_t getCurrentTime(void);
+SQUIDCEXTERN int percent(int, int);
+SQUIDCEXTERN double dpercent(double, double);
+SQUIDCEXTERN void squid_signal(int sig, SIGHDLR *, int flags);
+SQUIDCEXTERN pid_t readPidFile(void);
+SQUIDCEXTERN struct in_addr inaddrFromHostent(const struct hostent *hp);
+SQUIDCEXTERN int intAverage(int, int, int, int);
+SQUIDCEXTERN double doubleAverage(double, double, int, int);
+SQUIDCEXTERN void debug_trap(const char *);
+SQUIDCEXTERN void logsFlush(void);
+SQUIDCEXTERN const char *checkNullString(const char *p);
+SQUIDCEXTERN void squid_getrusage(struct rusage *r);
+SQUIDCEXTERN double rusage_cputime(struct rusage *r);
+SQUIDCEXTERN int rusage_maxrss(struct rusage *r);
+SQUIDCEXTERN int rusage_pagefaults(struct rusage *r);
+SQUIDCEXTERN void releaseServerSockets(void);
+SQUIDCEXTERN void PrintRusage(void);
+SQUIDCEXTERN void dumpMallocStats(void);
 
 #if USE_UNLINKD
-extern void unlinkdInit(void);
-extern void unlinkdClose(void);
-extern void unlinkdUnlink(const char *);
-#endif
-
-extern char *url_convert_hex(char *org_url, int allocate);
-extern char *url_escape(const char *url);
-extern protocol_t urlParseProtocol(const char *);
-extern method_t urlParseMethod(const char *);
-extern void urlInitialize(void);
-extern request_t *urlParse(method_t, char *);
-extern const char *urlCanonical(request_t *);
-extern char *urlRInternal(const char *host, u_short port, const char *dir, const char *name);
-extern char *urlInternal(const char *dir, const char *name);
-extern int matchDomainName(const char *host, const char *domain);
-extern int urlCheckRequest(const request_t *);
-extern int urlDefaultPort(protocol_t p);
-extern char *urlCanonicalClean(const request_t *);
-extern char *urlHostname(const char *url);
-extern void urlExtMethodConfigure(void);
-
-extern void useragentOpenLog(void);
-extern void useragentRotateLog(void);
-extern void logUserAgent(const char *, const char *);
-extern void useragentLogClose(void);
-extern void refererOpenLog(void);
-extern void refererRotateLog(void);
-extern void logReferer(const char *, const char *, const char *);
-extern peer_t parseNeighborType(const char *s);
-
-extern void errorInitialize(void);
-extern void errorClean(void);
-extern HttpReply *errorBuildReply(ErrorState * err);
-extern void errorSend(int fd, ErrorState *);
-extern void errorAppendEntry(StoreEntry *, ErrorState *);
-extern void errorStateFree(ErrorState * err);
-extern int errorReservePageId(const char *page_name);
-extern ErrorState *errorCon(err_type type, http_status);
-
-extern void pconnPush(int, const char *host, u_short port);
-extern int pconnPop(const char *host, u_short port);
-extern void pconnInit(void);
-
-extern int asnMatchIp(void *, struct in_addr);
-extern void asnInit(void);
-extern void asnFreeMemory(void);
+SQUIDCEXTERN void unlinkdInit(void);
+SQUIDCEXTERN void unlinkdClose(void);
+SQUIDCEXTERN void unlinkdUnlink(const char *);
+#endif
+
+SQUIDCEXTERN char *url_convert_hex(char *org_url, int allocate);
+SQUIDCEXTERN char *url_escape(const char *url);
+SQUIDCEXTERN protocol_t urlParseProtocol(const char *);
+SQUIDCEXTERN method_t urlParseMethod(const char *);
+SQUIDCEXTERN void urlInitialize(void);
+SQUIDCEXTERN request_t *urlParse(method_t, char *);
+SQUIDCEXTERN const char *urlCanonical(request_t *);
+SQUIDCEXTERN char *urlRInternal(const char *host, u_short port, const char *dir, const char *name);
+SQUIDCEXTERN char *urlInternal(const char *dir, const char *name);
+SQUIDCEXTERN int matchDomainName(const char *host, const char *domain);
+SQUIDCEXTERN int urlCheckRequest(const request_t *);
+SQUIDCEXTERN int urlDefaultPort(protocol_t p);
+SQUIDCEXTERN char *urlCanonicalClean(const request_t *);
+SQUIDCEXTERN char *urlHostname(const char *url);
+SQUIDCEXTERN void urlExtMethodConfigure(void);
+
+SQUIDCEXTERN void useragentOpenLog(void);
+SQUIDCEXTERN void useragentRotateLog(void);
+SQUIDCEXTERN void logUserAgent(const char *, const char *);
+SQUIDCEXTERN void useragentLogClose(void);
+SQUIDCEXTERN void refererOpenLog(void);
+SQUIDCEXTERN void refererRotateLog(void);
+SQUIDCEXTERN void logReferer(const char *, const char *, const char *);
+SQUIDCEXTERN peer_t parseNeighborType(const char *s);
+
+SQUIDCEXTERN void errorInitialize(void);
+SQUIDCEXTERN void errorClean(void);
+SQUIDCEXTERN HttpReply *errorBuildReply(ErrorState * err);
+SQUIDCEXTERN void errorSend(int fd, ErrorState *);
+SQUIDCEXTERN void errorAppendEntry(StoreEntry *, ErrorState *);
+SQUIDCEXTERN void errorStateFree(ErrorState * err);
+SQUIDCEXTERN int errorReservePageId(const char *page_name);
+SQUIDCEXTERN ErrorState *errorCon(err_type type, http_status);
+
+SQUIDCEXTERN void pconnPush(int, const char *host, u_short port);
+SQUIDCEXTERN int pconnPop(const char *host, u_short port);
+SQUIDCEXTERN void pconnInit(void);
+
+SQUIDCEXTERN int asnMatchIp(void *, struct in_addr);
+SQUIDCEXTERN void asnInit(void);
+SQUIDCEXTERN void asnFreeMemory(void);
 
 /* tools.c */
-extern void dlinkAdd(void *data, dlink_node *, dlink_list *);
-extern void dlinkAddAfter(void *, dlink_node *, dlink_node *, dlink_list *);
-extern void dlinkAddTail(void *data, dlink_node *, dlink_list *);
-extern void dlinkDelete(dlink_node * m, dlink_list * list);
-extern void dlinkNodeDelete(dlink_node * m);
-extern dlink_node *dlinkNodeNew(void);
-
-extern void kb_incr(kb_t *, size_t);
-extern int stringHasWhitespace(const char *);
-extern int stringHasCntl(const char *);
-extern void linklistPush(link_list **, void *);
-extern void *linklistShift(link_list **);
-extern int xrename(const char *from, const char *to);
-extern int isPowTen(int);
-extern void parseEtcHosts(void);
-extern int getMyPort(void);
+SQUIDCEXTERN void dlinkAdd(void *data, dlink_node *, dlink_list *);
+SQUIDCEXTERN void dlinkAddAfter(void *, dlink_node *, dlink_node *, dlink_list *);
+SQUIDCEXTERN void dlinkAddTail(void *data, dlink_node *, dlink_list *);
+SQUIDCEXTERN void dlinkDelete(dlink_node * m, dlink_list * list);
+SQUIDCEXTERN void dlinkNodeDelete(dlink_node * m);
+SQUIDCEXTERN dlink_node *dlinkNodeNew(void);
+
+SQUIDCEXTERN void kb_incr(kb_t *, size_t);
+SQUIDCEXTERN int stringHasWhitespace(const char *);
+SQUIDCEXTERN int stringHasCntl(const char *);
+SQUIDCEXTERN void linklistPush(link_list **, void *);
+SQUIDCEXTERN void *linklistShift(link_list **);
+SQUIDCEXTERN int xrename(const char *from, const char *to);
+SQUIDCEXTERN int isPowTen(int);
+SQUIDCEXTERN void parseEtcHosts(void);
+SQUIDCEXTERN int getMyPort(void);
 
-char *strwordtok(char *buf, char **t);
+SQUIDCEXTERN char *strwordtok(char *buf, char **t);
 void strwordquote(MemBuf * mb, const char *str);
 
 #if USE_HTCP
-extern void htcpInit(void);
-extern void htcpQuery(StoreEntry * e, request_t * req, peer * p);
-extern void htcpSocketShutdown(void);
-extern void htcpSocketClose(void);
+SQUIDCEXTERN void htcpInit(void);
+SQUIDCEXTERN void htcpQuery(StoreEntry * e, request_t * req, peer * p);
+SQUIDCEXTERN void htcpSocketShutdown(void);
+SQUIDCEXTERN void htcpSocketClose(void);
 #endif
 
 /* String */
@@ -1188,18 +1146,18 @@
 #define strCut(s,pos) (((s).len = pos) , ((s).buf[pos] = '\0'))
 #define strCutPtr(s,ptr) (((s).len = (ptr)-(s).buf) , ((s).buf[(s).len] = '\0'))
 #define strCat(s,str)  stringAppend(&(s), (str), strlen(str))
-extern void stringInit(String * s, const char *str);
-extern void stringLimitInit(String * s, const char *str, int len);
-extern String stringDup(const String * s);
-extern void stringClean(String * s);
-extern void stringReset(String * s, const char *str);
-extern void stringAppend(String * s, const char *buf, int len);
-/* extern void stringAppendf(String *s, const char *fmt, ...) PRINTF_FORMAT_ARG2; */
+SQUIDCEXTERN void stringInit(String * s, const char *str);
+SQUIDCEXTERN void stringLimitInit(String * s, const char *str, int len);
+SQUIDCEXTERN String stringDup(const String * s);
+SQUIDCEXTERN void stringClean(String * s);
+SQUIDCEXTERN void stringReset(String * s, const char *str);
+SQUIDCEXTERN void stringAppend(String * s, const char *buf, int len);
+/* SQUIDCEXTERN void stringAppendf(String *s, const char *fmt, ...) PRINTF_FORMAT_ARG2; */
 
 /*
  * ipc.c
  */
-extern int ipcCreate(int type,
+SQUIDCEXTERN int ipcCreate(int type,
     const char *prog,
     const char *const args[],
     const char *name,
@@ -1207,118 +1165,118 @@
     int *wfd);
 
 /* CacheDigest */
-extern CacheDigest *cacheDigestCreate(int capacity, int bpe);
-extern void cacheDigestDestroy(CacheDigest * cd);
-extern CacheDigest *cacheDigestClone(const CacheDigest * cd);
-extern void cacheDigestClear(CacheDigest * cd);
-extern void cacheDigestChangeCap(CacheDigest * cd, int new_cap);
-extern int cacheDigestTest(const CacheDigest * cd, const cache_key * key);
-extern void cacheDigestAdd(CacheDigest * cd, const cache_key * key);
-extern void cacheDigestDel(CacheDigest * cd, const cache_key * key);
-extern size_t cacheDigestCalcMaskSize(int cap, int bpe);
-extern int cacheDigestBitUtil(const CacheDigest * cd);
-extern void cacheDigestGuessStatsUpdate(cd_guess_stats * stats, int real_hit, int guess_hit);
-extern void cacheDigestGuessStatsReport(const cd_guess_stats * stats, StoreEntry * sentry, const char *label);
-extern void cacheDigestReport(CacheDigest * cd, const char *label, StoreEntry * e);
-
-extern void internalStart(request_t *, StoreEntry *);
-extern int internalCheck(const char *urlpath);
-extern int internalStaticCheck(const char *urlpath);
-extern char *internalLocalUri(const char *dir, const char *name);
-extern char *internalRemoteUri(const char *, u_short, const char *, const char *);
-extern const char *internalHostname(void);
-extern int internalHostnameIs(const char *);
+SQUIDCEXTERN CacheDigest *cacheDigestCreate(int capacity, int bpe);
+SQUIDCEXTERN void cacheDigestDestroy(CacheDigest * cd);
+SQUIDCEXTERN CacheDigest *cacheDigestClone(const CacheDigest * cd);
+SQUIDCEXTERN void cacheDigestClear(CacheDigest * cd);
+SQUIDCEXTERN void cacheDigestChangeCap(CacheDigest * cd, int new_cap);
+SQUIDCEXTERN int cacheDigestTest(const CacheDigest * cd, const cache_key * key);
+SQUIDCEXTERN void cacheDigestAdd(CacheDigest * cd, const cache_key * key);
+SQUIDCEXTERN void cacheDigestDel(CacheDigest * cd, const cache_key * key);
+SQUIDCEXTERN size_t cacheDigestCalcMaskSize(int cap, int bpe);
+SQUIDCEXTERN int cacheDigestBitUtil(const CacheDigest * cd);
+SQUIDCEXTERN void cacheDigestGuessStatsUpdate(cd_guess_stats * stats, int real_hit, int guess_hit);
+SQUIDCEXTERN void cacheDigestGuessStatsReport(const cd_guess_stats * stats, StoreEntry * sentry, const char *label);
+SQUIDCEXTERN void cacheDigestReport(CacheDigest * cd, const char *label, StoreEntry * e);
+
+SQUIDCEXTERN void internalStart(request_t *, StoreEntry *);
+SQUIDCEXTERN int internalCheck(const char *urlpath);
+SQUIDCEXTERN int internalStaticCheck(const char *urlpath);
+SQUIDCEXTERN char *internalLocalUri(const char *dir, const char *name);
+SQUIDCEXTERN char *internalRemoteUri(const char *, u_short, const char *, const char *);
+SQUIDCEXTERN const char *internalHostname(void);
+SQUIDCEXTERN int internalHostnameIs(const char *);
 
 #if USE_CARP
-extern void carpInit(void);
-extern peer *carpSelectParent(request_t *);
+SQUIDCEXTERN void carpInit(void);
+SQUIDCEXTERN peer *carpSelectParent(request_t *);
 #endif
 
 #if DELAY_POOLS
-extern void delayPoolsInit(void);
-extern void delayInitDelayData(unsigned short pools);
-extern void delayFreeDelayData(unsigned short pools);
-extern void delayCreateDelayPool(unsigned short pool, u_char class);
-extern void delayInitDelayPool(unsigned short pool, u_char class, delaySpecSet * rates);
-extern void delayFreeDelayPool(unsigned short pool);
-extern void delayPoolsReconfigure(void);
-extern void delaySetNoDelay(int fd);
-extern void delayClearNoDelay(int fd);
-extern int delayIsNoDelay(int fd);
-extern delay_id delayClient(clientHttpRequest *);
-extern EVH delayPoolsUpdate;
-extern int delayBytesWanted(delay_id d, int min, int max);
-extern void delayBytesIn(delay_id, int qty);
-extern int delayMostBytesWanted(const MemObject * mem, int max);
-extern delay_id delayMostBytesAllowed(const MemObject * mem);
-extern void delaySetStoreClient(store_client * sc, delay_id delay_id);
-extern void delayRegisterDelayIdPtr(delay_id * loc);
-extern void delayUnregisterDelayIdPtr(delay_id * loc);
+SQUIDCEXTERN void delayPoolsInit(void);
+SQUIDCEXTERN void delayInitDelayData(unsigned short pools);
+SQUIDCEXTERN void delayFreeDelayData(unsigned short pools);
+SQUIDCEXTERN void delayCreateDelayPool(unsigned short pool, u_char class);
+SQUIDCEXTERN void delayInitDelayPool(unsigned short pool, u_char class, delaySpecSet * rates);
+SQUIDCEXTERN void delayFreeDelayPool(unsigned short pool);
+SQUIDCEXTERN void delayPoolsReconfigure(void);
+SQUIDCEXTERN void delaySetNoDelay(int fd);
+SQUIDCEXTERN void delayClearNoDelay(int fd);
+SQUIDCEXTERN int delayIsNoDelay(int fd);
+SQUIDCEXTERN delay_id delayClient(clientHttpRequest *);
+SQUIDCEXTERN EVH delayPoolsUpdate;
+SQUIDCEXTERN int delayBytesWanted(delay_id d, int min, int max);
+SQUIDCEXTERN void delayBytesIn(delay_id, int qty);
+SQUIDCEXTERN int delayMostBytesWanted(const MemObject * mem, int max);
+SQUIDCEXTERN delay_id delayMostBytesAllowed(const MemObject * mem);
+SQUIDCEXTERN void delaySetStoreClient(store_client * sc, delay_id delay_id);
+SQUIDCEXTERN void delayRegisterDelayIdPtr(delay_id * loc);
+SQUIDCEXTERN void delayUnregisterDelayIdPtr(delay_id * loc);
 #endif
 
 /* helper.c */
-extern void helperOpenServers(helper * hlp);
-extern void helperStatefulOpenServers(statefulhelper * hlp);
-extern void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data);
-extern void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPSCB * callback, void *data, helper_stateful_server * lastserver);
-extern void helperStats(StoreEntry * sentry, helper * hlp);
-extern void helperStatefulStats(StoreEntry * sentry, statefulhelper * hlp);
-extern void helperShutdown(helper * hlp);
-extern void helperStatefulShutdown(statefulhelper * hlp);
-extern helper *helperCreate(const char *);
-extern statefulhelper *helperStatefulCreate(const char *);
-extern void helperFree(helper *);
-extern void helperStatefulFree(statefulhelper *);
-extern void helperStatefulReset(helper_stateful_server * srv);
-extern void helperStatefulReleaseServer(helper_stateful_server * srv);
-extern void *helperStatefulServerGetData(helper_stateful_server * srv);
-extern helper_stateful_server *helperStatefulDefer(statefulhelper *);
+SQUIDCEXTERN void helperOpenServers(helper * hlp);
+SQUIDCEXTERN void helperStatefulOpenServers(statefulhelper * hlp);
+SQUIDCEXTERN void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data);
+SQUIDCEXTERN void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPSCB * callback, void *data, helper_stateful_server * lastserver);
+SQUIDCEXTERN void helperStats(StoreEntry * sentry, helper * hlp);
+SQUIDCEXTERN void helperStatefulStats(StoreEntry * sentry, statefulhelper * hlp);
+SQUIDCEXTERN void helperShutdown(helper * hlp);
+SQUIDCEXTERN void helperStatefulShutdown(statefulhelper * hlp);
+SQUIDCEXTERN helper *helperCreate(const char *);
+SQUIDCEXTERN statefulhelper *helperStatefulCreate(const char *);
+SQUIDCEXTERN void helperFree(helper *);
+SQUIDCEXTERN void helperStatefulFree(statefulhelper *);
+SQUIDCEXTERN void helperStatefulReset(helper_stateful_server * srv);
+SQUIDCEXTERN void helperStatefulReleaseServer(helper_stateful_server * srv);
+SQUIDCEXTERN void *helperStatefulServerGetData(helper_stateful_server * srv);
+SQUIDCEXTERN helper_stateful_server *helperStatefulDefer(statefulhelper *);
 
 
 
 #if USE_LEAKFINDER
-extern void leakInit(void);
-extern void *leakAddFL(void *, const char *, int);
-extern void *leakTouchFL(void *, const char *, int);
-extern void *leakFreeFL(void *, const char *, int);
+SQUIDCEXTERN void leakInit(void);
+SQUIDCEXTERN void *leakAddFL(void *, const char *, int);
+SQUIDCEXTERN void *leakTouchFL(void *, const char *, int);
+SQUIDCEXTERN void *leakFreeFL(void *, const char *, int);
 #endif
 
 /* logfile.c */
-extern Logfile *logfileOpen(const char *path, size_t bufsz, int);
-extern void logfileClose(Logfile * lf);
-extern void logfileRotate(Logfile * lf);
-extern void logfileWrite(Logfile * lf, void *buf, size_t len);
-extern void logfileFlush(Logfile * lf);
+SQUIDCEXTERN Logfile *logfileOpen(const char *path, size_t bufsz, int);
+SQUIDCEXTERN void logfileClose(Logfile * lf);
+SQUIDCEXTERN void logfileRotate(Logfile * lf);
+SQUIDCEXTERN void logfileWrite(Logfile * lf, void *buf, size_t len);
+SQUIDCEXTERN void logfileFlush(Logfile * lf);
 #if STDC_HEADERS
-extern void
+SQUIDCEXTERN void
 logfilePrintf(Logfile * lf, const char *fmt,...) PRINTF_FORMAT_ARG2;
 #else
-extern void logfilePrintf(va_alist);
+SQUIDCEXTERN void logfilePrintf(va_alist);
 #endif
 
 /*
  * Removal Policies
  */
-extern RemovalPolicy *createRemovalPolicy(RemovalPolicySettings * settings);
+SQUIDCEXTERN RemovalPolicy *createRemovalPolicy(RemovalPolicySettings * settings);
 
 /*
  * prototypes for system functions missing from system includes
  */
 
 #ifdef _SQUID_SOLARIS_
-extern int getrusage(int, struct rusage *);
-extern int getpagesize(void);
-extern int gethostname(char *, int);
+SQUIDCEXTERN int getrusage(int, struct rusage *);
+SQUIDCEXTERN int getpagesize(void);
+SQUIDCEXTERN int gethostname(char *, int);
 #endif
 
 #if URL_CHECKSUM_DEBUG
-extern unsigned int url_checksum(const char *url);
+SQUIDCEXTERN unsigned int url_checksum(const char *url);
 #endif
 
 /*
  * hack to allow snmp access to the statistics counters
  */
-extern StatCounters *snmpStatGet(int);
+SQUIDCEXTERN StatCounters *snmpStatGet(int);
 
 /* Vary support functions */
 int varyEvaluateMatch(StoreEntry * entry, request_t * req);
@@ -1326,22 +1284,22 @@
 /* CygWin & Windows NT Port */
 /* win32.c */
 #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-extern int WIN32_Subsystem_Init(void);
-extern void WIN32_Exit(void);
+SQUIDCEXTERN int WIN32_Subsystem_Init(void);
+SQUIDCEXTERN void WIN32_Exit(void);
 #endif
 
 /* external_acl.c */
-extern void parse_externalAclHelper(external_acl **);
-extern void dump_externalAclHelper(StoreEntry * sentry, const char *name, const external_acl *);
-extern void free_externalAclHelper(external_acl **);
-extern void aclParseExternal(void *curlist);
-extern void aclDestroyExternal(void **curlust);
-extern int aclMatchExternal(void *dataptr, aclCheck_t * ch);
-extern wordlist *aclDumpExternal(void *dataptr);
+SQUIDCEXTERN void parse_externalAclHelper(external_acl **);
+SQUIDCEXTERN void dump_externalAclHelper(StoreEntry * sentry, const char *name, const external_acl *);
+SQUIDCEXTERN void free_externalAclHelper(external_acl **);
+SQUIDCEXTERN void aclParseExternal(void *curlist);
+SQUIDCEXTERN void aclDestroyExternal(void **curlust);
+SQUIDCEXTERN int aclMatchExternal(void *dataptr, aclCheck_t * ch);
+SQUIDCEXTERN wordlist *aclDumpExternal(void *dataptr);
 typedef void EAH(void *data, void *result);
-extern void externalAclLookup(aclCheck_t * ch, void *acl_data, EAH * handler, void *data);
-extern void externalAclInit(void);
-extern void externalAclShutdown(void);
-extern char *strtokFile(void);
+SQUIDCEXTERN void externalAclLookup(aclCheck_t * ch, void *acl_data, EAH * handler, void *data);
+SQUIDCEXTERN void externalAclInit(void);
+SQUIDCEXTERN void externalAclShutdown(void);
+SQUIDCEXTERN char *strtokFile(void);
 
 #endif /* SQUID_PROTOS_H */
--- squid/src/redirect.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,179 +0,0 @@
-
-/*
- * $Id: redirect.c,v 1.10 2002/07/21 01:06:07 squidadm Exp $
- *
- * DEBUG: section 61    Redirector
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-
-typedef struct {
-    void *data;
-    char *orig_url;
-    struct in_addr client_addr;
-    const char *client_ident;
-    const char *method_s;
-    RH *handler;
-} redirectStateData;
-
-static HLPCB redirectHandleReply;
-static void redirectStateFree(redirectStateData * r);
-static helper *redirectors = NULL;
-static OBJH redirectStats;
-static int n_bypassed = 0;
-CBDATA_TYPE(redirectStateData);
-
-static void
-redirectHandleReply(void *data, char *reply)
-{
-    redirectStateData *r = data;
-    char *t;
-    void *cbdata;
-    debug(61, 5) ("redirectHandleRead: {%s}\n", reply ? reply : "<NULL>");
-    if (reply) {
-	if ((t = strchr(reply, ' ')))
-	    *t = '\0';
-	if (*reply == '\0')
-	    reply = NULL;
-    }
-    if (cbdataReferenceValidDone(r->data, &cbdata))
-	r->handler(cbdata, reply);
-    redirectStateFree(r);
-}
-
-static void
-redirectStateFree(redirectStateData * r)
-{
-    safe_free(r->orig_url);
-    cbdataFree(r);
-}
-
-static void
-redirectStats(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "Redirector Statistics:\n");
-    helperStats(sentry, redirectors);
-    if (Config.onoff.redirector_bypass)
-	storeAppendPrintf(sentry, "\nNumber of requests bypassed "
-	    "because all redirectors were busy: %d\n", n_bypassed);
-}
-
-/**** PUBLIC FUNCTIONS ****/
-
-void
-redirectStart(clientHttpRequest * http, RH * handler, void *data)
-{
-    ConnStateData *conn = http->conn;
-    redirectStateData *r = NULL;
-    const char *fqdn;
-    char buf[8192];
-    assert(http);
-    assert(handler);
-    debug(61, 5) ("redirectStart: '%s'\n", http->uri);
-    if (Config.Program.redirect == NULL) {
-	handler(data, NULL);
-	return;
-    }
-    if (Config.accessList.redirector) {
-	aclCheck_t ch;
-	memset(&ch, '\0', sizeof(ch));
-	ch.src_addr = http->conn->peer.sin_addr;
-	ch.my_addr = http->conn->me.sin_addr;
-	ch.my_port = ntohs(http->conn->me.sin_port);
-	ch.request = http->request;
-	if (!aclCheckFast(Config.accessList.redirector, &ch)) {
-	    /* denied -- bypass redirector */
-	    handler(data, NULL);
-	    return;
-	}
-    }
-    if (Config.onoff.redirector_bypass && redirectors->stats.queue_size) {
-	/* Skip redirector if there is one request queued */
-	n_bypassed++;
-	handler(data, NULL);
-	return;
-    }
-    r = cbdataAlloc(redirectStateData);
-    r->orig_url = xstrdup(http->uri);
-    r->client_addr = conn->log_addr;
-    if (http->request->auth_user_request)
-	r->client_ident = authenticateUserRequestUsername(http->request->auth_user_request);
-    else if (conn->rfc931[0]) {
-	r->client_ident = conn->rfc931;
-    } else {
-	r->client_ident = dash_str;
-    }
-    r->method_s = RequestMethodStr[http->request->method];
-    r->handler = handler;
-    r->data = cbdataReference(data);
-    if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
-	fqdn = dash_str;
-    snprintf(buf, 8192, "%s %s/%s %s %s\n",
-	r->orig_url,
-	inet_ntoa(r->client_addr),
-	fqdn,
-	r->client_ident,
-	r->method_s);
-    helperSubmit(redirectors, buf, redirectHandleReply, r);
-}
-
-void
-redirectInit(void)
-{
-    static int init = 0;
-    if (!Config.Program.redirect)
-	return;
-    if (redirectors == NULL)
-	redirectors = helperCreate("redirector");
-    redirectors->cmdline = Config.Program.redirect;
-    redirectors->n_to_start = Config.redirectChildren;
-    redirectors->ipc_type = IPC_STREAM;
-    helperOpenServers(redirectors);
-    if (!init) {
-	cachemgrRegister("redirector",
-	    "URL Redirector Stats",
-	    redirectStats, 0, 1);
-	init = 1;
-	CBDATA_INIT_TYPE(redirectStateData);
-    }
-}
-
-void
-redirectShutdown(void)
-{
-    if (!redirectors)
-	return;
-    helperShutdown(redirectors);
-    if (!shutting_down)
-	return;
-    helperFree(redirectors);
-    redirectors = NULL;
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/redirect.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,180 @@
+
+/*
+ * $Id: redirect.cc,v 1.1.2.1 2002/10/03 01:04:36 rbcollins Exp $
+ *
+ * DEBUG: section 61    Redirector
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "authenticate.h"
+
+typedef struct {
+    void *data;
+    char *orig_url;
+    struct in_addr client_addr;
+    const char *client_ident;
+    const char *method_s;
+    RH *handler;
+} redirectStateData;
+
+static HLPCB redirectHandleReply;
+static void redirectStateFree(redirectStateData * r);
+static helper *redirectors = NULL;
+static OBJH redirectStats;
+static int n_bypassed = 0;
+CBDATA_TYPE(redirectStateData);
+
+static void
+redirectHandleReply(void *data, char *reply)
+{
+    redirectStateData *r = static_cast<redirectStateData *>(data);
+    char *t;
+    void *cbdata;
+    debug(61, 5) ("redirectHandleRead: {%s}\n", reply ? reply : "<NULL>");
+    if (reply) {
+	if ((t = strchr(reply, ' ')))
+	    *t = '\0';
+	if (*reply == '\0')
+	    reply = NULL;
+    }
+    if (cbdataReferenceValidDone(r->data, &cbdata))
+	r->handler(cbdata, reply);
+    redirectStateFree(r);
+}
+
+static void
+redirectStateFree(redirectStateData * r)
+{
+    safe_free(r->orig_url);
+    cbdataFree(r);
+}
+
+static void
+redirectStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "Redirector Statistics:\n");
+    helperStats(sentry, redirectors);
+    if (Config.onoff.redirector_bypass)
+	storeAppendPrintf(sentry, "\nNumber of requests bypassed "
+	    "because all redirectors were busy: %d\n", n_bypassed);
+}
+
+/**** PUBLIC FUNCTIONS ****/
+
+void
+redirectStart(clientHttpRequest * http, RH * handler, void *data)
+{
+    ConnStateData *conn = http->conn;
+    redirectStateData *r = NULL;
+    const char *fqdn;
+    char buf[8192];
+    assert(http);
+    assert(handler);
+    debug(61, 5) ("redirectStart: '%s'\n", http->uri);
+    if (Config.Program.redirect == NULL) {
+	handler(data, NULL);
+	return;
+    }
+    if (Config.accessList.redirector) {
+	aclCheck_t ch;
+	memset(&ch, '\0', sizeof(ch));
+	ch.src_addr = http->conn->peer.sin_addr;
+	ch.my_addr = http->conn->me.sin_addr;
+	ch.my_port = ntohs(http->conn->me.sin_port);
+	ch.request = http->request;
+	if (!aclCheckFast(Config.accessList.redirector, &ch)) {
+	    /* denied -- bypass redirector */
+	    handler(data, NULL);
+	    return;
+	}
+    }
+    if (Config.onoff.redirector_bypass && redirectors->stats.queue_size) {
+	/* Skip redirector if there is one request queued */
+	n_bypassed++;
+	handler(data, NULL);
+	return;
+    }
+    r = cbdataAlloc(redirectStateData);
+    r->orig_url = xstrdup(http->uri);
+    r->client_addr = conn->log_addr;
+    if (http->request->auth_user_request)
+	r->client_ident = authenticateUserRequestUsername(http->request->auth_user_request);
+    else if (conn->rfc931[0]) {
+	r->client_ident = conn->rfc931;
+    } else {
+	r->client_ident = dash_str;
+    }
+    r->method_s = RequestMethodStr[http->request->method];
+    r->handler = handler;
+    r->data = cbdataReference(data);
+    if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
+	fqdn = dash_str;
+    snprintf(buf, 8192, "%s %s/%s %s %s\n",
+	r->orig_url,
+	inet_ntoa(r->client_addr),
+	fqdn,
+	r->client_ident,
+	r->method_s);
+    helperSubmit(redirectors, buf, redirectHandleReply, r);
+}
+
+void
+redirectInit(void)
+{
+    static int init = 0;
+    if (!Config.Program.redirect)
+	return;
+    if (redirectors == NULL)
+	redirectors = helperCreate("redirector");
+    redirectors->cmdline = Config.Program.redirect;
+    redirectors->n_to_start = Config.redirectChildren;
+    redirectors->ipc_type = IPC_STREAM;
+    helperOpenServers(redirectors);
+    if (!init) {
+	cachemgrRegister("redirector",
+	    "URL Redirector Stats",
+	    redirectStats, 0, 1);
+	init = 1;
+	CBDATA_INIT_TYPE(redirectStateData);
+    }
+}
+
+void
+redirectShutdown(void)
+{
+    if (!redirectors)
+	return;
+    helperShutdown(redirectors);
+    if (!shutting_down)
+	return;
+    helperFree(redirectors);
+    redirectors = NULL;
+}
Index: squid/src/structs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/structs.h,v
retrieving revision 1.70
retrieving revision 1.70.2.1
diff -u -r1.70 -r1.70.2.1
--- squid/src/structs.h	26 Sep 2002 21:46:06 -0000	1.70
+++ squid/src/structs.h	3 Oct 2002 01:04:36 -0000	1.70.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.70 2002/09/26 21:46:06 squidadm Exp $
+ * $Id: structs.h,v 1.70.2.1 2002/10/03 01:04:36 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -88,107 +88,6 @@
     void *acl_data;
 };
 
-struct _auth_user_hash_pointer {
-    /* first two items must be same as hash_link */
-    char *key;
-    auth_user_hash_pointer *next;
-    auth_user_t *auth_user;
-    dlink_node link;		/* other hash entries that point to the same auth_user */
-};
-
-struct _auth_user_ip_t {
-    dlink_node node;
-    /* IP addr this user authenticated from */
-    struct in_addr ipaddr;
-    time_t ip_expiretime;
-};
-
-struct _auth_user_t {
-    /* extra fields for proxy_auth */
-    /* this determines what scheme owns the user data. */
-    auth_type_t auth_type;
-    /* the index +1 in the authscheme_list to the authscheme entry */
-    int auth_module;
-    /* we only have one username associated with a given auth_user struct */
-    auth_user_hash_pointer *usernamehash;
-    /* we may have many proxy-authenticate strings that decode to the same user */
-    dlink_list proxy_auth_list;
-    dlink_list proxy_match_cache;
-    /* what ip addresses has this user been seen at?, plus a list length cache */
-    dlink_list ip_list;
-    size_t ipcount;
-    long expiretime;
-    /* how many references are outstanding to this instance */
-    size_t references;
-    /* the auth scheme has it's own private data area */
-    void *scheme_data;
-    /* the auth_user_request structures that link to this. Yes it could be a splaytree
-     * but how many requests will a single username have in parallel? */
-    dlink_list requests;
-};
-
-struct _auth_user_request_t {
-    /* this is the object passed around by client_side and acl functions */
-    /* it has request specific data, and links to user specific data */
-    /* the user */
-    auth_user_t *auth_user;
-    /* return a message on the 407 error pages */
-    char *message;
-    /* any scheme specific request related data */
-    void *scheme_data;
-    /* how many 'processes' are working on this data */
-    size_t references;
-    /* We only attempt authentication once per http request. This 
-     * is to allow multiple auth acl references from different _access areas
-     * when using connection based authentication
-     */
-    auth_acl_t lastReply;
-};
-
-
-/*
- * This defines an auth scheme module
- */
-
-struct _authscheme_entry {
-    const char *typestr;
-    AUTHSACTIVE *Active;
-    AUTHSADDHEADER *AddHeader;
-    AUTHSADDTRAILER *AddTrailer;
-    AUTHSAUTHED *authenticated;
-    AUTHSAUTHUSER *authAuthenticate;
-    AUTHSCONFIGURED *configured;
-    AUTHSDUMP *dump;
-    AUTHSFIXERR *authFixHeader;
-    AUTHSFREE *FreeUser;
-    AUTHSFREECONFIG *freeconfig;
-    AUTHSUSERNAME *authUserUsername;
-    AUTHSONCLOSEC *oncloseconnection;	/*optional */
-    AUTHSCONNLASTHEADER *authConnLastHeader;
-    AUTHSDECODE *decodeauth;
-    AUTHSDIRECTION *getdirection;
-    AUTHSPARSE *parse;
-    AUTHSINIT *init;
-    AUTHSREQFREE *requestFree;
-    AUTHSSHUTDOWN *donefunc;
-    AUTHSSTART *authStart;
-    AUTHSSTATS *authStats;
-};
-
-/*
- * This is a configured auth scheme
- */
-
-/* private data types */
-struct _authScheme {
-    /* pointer to the authscheme_list's string entry */
-    const char *typestr;
-    /* the scheme id in the authscheme_list */
-    int Id;
-    /* the scheme's configuration details. */
-    void *scheme_data;
-};
-
 struct _acl_deny_info_list {
     int err_page_id;
     char *err_page_name;
@@ -368,6 +267,12 @@
 
 #endif
 
+struct _authConfig {
+    authScheme *schemes;
+    int n_allocated;
+    int n_configured;
+};
+
 struct _RemovalPolicySettings {
     char *type;
     wordlist *args;
@@ -619,11 +524,7 @@
 	acl_tos *outgoing_tos;
     } accessList;
     acl_deny_info_list *denyInfoList;
-    struct _authConfig {
-	authScheme *schemes;
-	int n_allocated;
-	int n_configured;
-    } authConfig;
+    authConfig authConfiguration;
     struct {
 	size_t list_width;
 	int list_wrap;
Index: squid/src/typedefs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v
retrieving revision 1.29
retrieving revision 1.29.2.1
diff -u -r1.29 -r1.29.2.1
--- squid/src/typedefs.h	24 Sep 2002 10:59:17 -0000	1.29
+++ squid/src/typedefs.h	3 Oct 2002 01:04:36 -0000	1.29.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: typedefs.h,v 1.29 2002/09/24 10:59:17 rbcollins Exp $
+ * $Id: typedefs.h,v 1.29.2.1 2002/10/03 01:04:36 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -55,10 +55,10 @@
 typedef struct _acl_time_data acl_time_data;
 typedef struct _acl_name_list acl_name_list;
 typedef struct _acl_deny_info_list acl_deny_info_list;
-typedef struct _auth_user_t auth_user_t;
-typedef struct _auth_user_request_t auth_user_request_t;
-typedef struct _auth_user_hash_pointer auth_user_hash_pointer;
-typedef struct _auth_user_ip_t auth_user_ip_t;
+typedef struct AuthUser auth_user_t;
+typedef struct AuthUserRequest auth_user_request_t;
+typedef struct AuthUserHashPointer auth_user_hash_pointer;
+typedef struct AuthUserIP auth_user_ip_t;
 typedef struct _acl_proxy_auth_match_cache acl_proxy_auth_match_cache;
 typedef struct _authscheme_entry authscheme_entry_t;
 typedef struct _authScheme authScheme;
@@ -286,30 +286,6 @@
 typedef double hbase_f(double);
 typedef void StatHistBinDumper(StoreEntry *, int idx, double val, double size, int count);
 
-/* authenticate.c authenticate scheme routines typedefs */
-typedef int AUTHSACTIVE(void);
-typedef int AUTHSAUTHED(auth_user_request_t *);
-typedef void AUTHSAUTHUSER(auth_user_request_t *, request_t *, ConnStateData *, http_hdr_type);
-typedef int AUTHSCONFIGURED(void);
-typedef void AUTHSDECODE(auth_user_request_t *, const char *);
-typedef int AUTHSDIRECTION(auth_user_request_t *);
-typedef void AUTHSDUMP(StoreEntry *, const char *, authScheme *);
-typedef void AUTHSFIXERR(auth_user_request_t *, HttpReply *, http_hdr_type, request_t *);
-typedef void AUTHSADDHEADER(auth_user_request_t *, HttpReply *, int);
-typedef void AUTHSADDTRAILER(auth_user_request_t *, HttpReply *, int);
-typedef void AUTHSFREE(auth_user_t *);
-typedef void AUTHSFREECONFIG(authScheme *);
-typedef char *AUTHSUSERNAME(auth_user_t *);
-typedef void AUTHSONCLOSEC(ConnStateData *);
-typedef void AUTHSPARSE(authScheme *, int, char *);
-typedef void AUTHSINIT(authScheme *);
-typedef void AUTHSREQFREE(auth_user_request_t *);
-typedef void AUTHSSETUP(authscheme_entry_t *);
-typedef void AUTHSSHUTDOWN(void);
-typedef void AUTHSSTART(auth_user_request_t *, RH *, void *);
-typedef void AUTHSSTATS(StoreEntry *);
-typedef const char *AUTHSCONNLASTHEADER(auth_user_request_t *);
-
 /* append/vprintf's for Packer */
 typedef void (*append_f) (void *, const char *buf, int size);
 #if STDC_HEADERS
Index: squid/src/auth/Makefile.am
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/auth/Makefile.am,v
retrieving revision 1.2
retrieving revision 1.2.72.1
diff -u -r1.2 -r1.2.72.1
--- squid/src/auth/Makefile.am	1 Sep 2001 11:46:49 -0000	1.2
+++ squid/src/auth/Makefile.am	3 Oct 2002 01:04:36 -0000	1.2.72.1
@@ -4,15 +4,15 @@
 #
 AUTOMAKE_OPTIONS = subdir-objects
 
-DIST_SUBDIRS	= basic digest ntlm
-SUBDIRS		= @AUTH_MODULES@
+##DIST_SUBDIRS	= basic digest ntlm
+##SUBDIRS		= @AUTH_MODULES@
 
 EXTRA_LIBRARIES	= libbasic.a libdigest.a libntlm.a
 noinst_LIBRARIES	= @AUTH_LIBS@
 
-libbasic_a_SOURCES	= basic/auth_basic.c basic/auth_basic.h
-libdigest_a_SOURCES	= digest/auth_digest.c digest/auth_digest.h
-libntlm_a_SOURCES	= ntlm/auth_ntlm.c ntlm/auth_ntlm.h
+libbasic_a_SOURCES	= basic/auth_basic.cc basic/auth_basic.h
+libdigest_a_SOURCES	= digest/auth_digest.cc digest/auth_digest.h
+libntlm_a_SOURCES	= ntlm/auth_ntlm.cc ntlm/auth_ntlm.h
 
 INCLUDES      = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
 	-I$(top_srcdir)/src/
--- squid/src/auth/basic/auth_basic.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,599 +0,0 @@
-/*
- * $Id$
- *
- * DEBUG: section 29    Authenticator
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-/* The functions in this file handle authentication.
- * They DO NOT perform access control or auditing.
- * See acl.c for access control and client_side.c for auditing */
-
-
-#include "squid.h"
-#include "auth_basic.h"
-
-static void
-authenticateStateFree(authenticateStateData * r)
-{
-    cbdataFree(r);
-}
-
-/* Basic Scheme */
-
-static HLPCB authenticateBasicHandleReply;
-static AUTHSACTIVE authenticateBasicActive;
-static AUTHSAUTHED authenticateBasicAuthenticated;
-static AUTHSAUTHUSER authenticateBasicAuthenticateUser;
-static AUTHSCONFIGURED authBasicConfigured;
-static AUTHSDIRECTION authenticateBasicDirection;
-static AUTHSDECODE authenticateBasicDecodeAuth;
-static AUTHSDUMP authBasicCfgDump;
-static AUTHSFIXERR authenticateBasicFixErrorHeader;
-static AUTHSFREE authenticateBasicFreeUser;
-static AUTHSFREECONFIG authBasicFreeConfig;
-static AUTHSPARSE authBasicParse;
-static AUTHSINIT authBasicInit;
-static AUTHSSTART authenticateBasicStart;
-static AUTHSSTATS authenticateBasicStats;
-static AUTHSUSERNAME authenticateBasicUsername;
-static AUTHSSHUTDOWN authBasicDone;
-
-static helper *basicauthenticators = NULL;
-
-static auth_basic_config *basicConfig = NULL;
-
-static int authbasic_initialised = 0;
-MemPool *basic_data_pool = NULL;
-
-
-/*
- *
- * Public Functions
- *
- */
-
-AUTHSSETUP authSchemeSetup_basic;
-
-void
-authSchemeSetup_basic(authscheme_entry_t * authscheme)
-{
-    assert(!authbasic_initialised);
-    authscheme->Active = authenticateBasicActive;
-    authscheme->parse = authBasicParse;
-    authscheme->dump = authBasicCfgDump;
-    authscheme->init = authBasicInit;
-    authscheme->authAuthenticate = authenticateBasicAuthenticateUser;
-    authscheme->authenticated = authenticateBasicAuthenticated;
-    authscheme->configured = authBasicConfigured;
-    authscheme->authFixHeader = authenticateBasicFixErrorHeader;
-    authscheme->FreeUser = authenticateBasicFreeUser;
-    authscheme->freeconfig = authBasicFreeConfig;
-    authscheme->authStart = authenticateBasicStart;
-    authscheme->authStats = authenticateBasicStats;
-    authscheme->authUserUsername = authenticateBasicUsername;
-    authscheme->getdirection = authenticateBasicDirection;
-    authscheme->oncloseconnection = NULL;
-    authscheme->decodeauth = authenticateBasicDecodeAuth;
-    authscheme->donefunc = authBasicDone;
-    authscheme->authConnLastHeader = NULL;
-}
-
-/* internal functions */
-
-static void
-authBasicDone(void)
-{
-    if (basicauthenticators)
-	helperShutdown(basicauthenticators);
-    authbasic_initialised = 0;
-    if (!shutting_down)
-	return;
-    if (basicauthenticators)
-	helperFree(basicauthenticators);
-    basicauthenticators = NULL;
-    if (basic_data_pool) {
-	memPoolDestroy(&basic_data_pool);
-	basic_data_pool = NULL;
-    }
-    debug(29, 2) ("authBasicDone: Basic authentication Shutdown.\n");
-}
-
-static int
-authenticateBasicActive()
-{
-    return (authbasic_initialised == 1) ? 1 : 0;
-}
-
-static int
-authBasicConfigured()
-{
-    if ((basicConfig != NULL) && (basicConfig->authenticate != NULL) &&
-	(basicConfig->authenticateChildren != 0) &&
-	(basicConfig->basicAuthRealm != NULL)) {
-	debug(29, 9) ("authBasicConfigured: returning configured\n");
-	return 1;
-    }
-    debug(29, 9) ("authBasicConfigured: returning unconfigured\n");
-    return 0;
-}
-
-static int
-authenticateBasicAuthenticated(auth_user_request_t * auth_user_request)
-{
-    basic_data *basic_auth = auth_user_request->auth_user->scheme_data;
-    if ((basic_auth->flags.credentials_ok == 1) && (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL > squid_curtime))
-	return 1;
-    debug(29, 4) ("User not authenticated or credentials need rechecking.\n");
-    return 0;
-}
-
-#if UNUSED_CODE
-static int
-authenticateBasiccmpUsername(basic_data * u1, basic_data * u2)
-{
-    return strcmp(u1->username, u2->username);
-}
-#endif
-
-/* log a basic user in
- */
-static void
-authenticateBasicAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
-{
-    auth_user_t *auth_user;
-    basic_data *basic_auth;
-
-    assert(auth_user_request->auth_user != NULL);
-    auth_user = auth_user_request->auth_user;
-
-    assert(auth_user->scheme_data != NULL);
-    basic_auth = auth_user->scheme_data;
-
-    /* if the password is not ok, do an identity */
-    if (basic_auth->flags.credentials_ok != 1)
-	return;
-
-    /* are we about to recheck the credentials externally? */
-    if ((basic_auth->credentials_checkedtime + basicConfig->credentialsTTL) <= squid_curtime) {
-	debug(29, 4) ("authBasicAuthenticate: credentials expired - rechecking\n");
-	return;
-    }
-    /* we have been through the external helper, and the credentials haven't expired */
-    debug(29, 9) ("authenticateBasicAuthenticateuser: user '%s' authenticated\n",
-	basic_auth->username);
-
-    /* Decode now takes care of finding the auth_user struct in the cache */
-    /* after external auth occurs anyway */
-    auth_user->expiretime = current_time.tv_sec;
-    return;
-}
-
-int
-authenticateBasicDirection(auth_user_request_t * auth_user_request)
-{
-/* null auth_user is checked for by authenticateDirection */
-    auth_user_t *auth_user = auth_user_request->auth_user;
-    basic_data *basic_auth = auth_user->scheme_data;
-    switch (basic_auth->flags.credentials_ok) {
-    case 0:			/* not checked */
-	return -1;
-    case 1:			/* checked & ok */
-	if (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL <= squid_curtime)
-	    return -1;
-	return 0;
-    case 2:			/* paused while waiting for a username:password check on another request */
-	return -1;
-    case 3:			/* authentication process failed. */
-	return -2;
-    }
-    return -2;
-}
-
-void
-authenticateBasicFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
-{
-    if (basicConfig->authenticate) {
-	debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicConfig->basicAuthRealm);
-	httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicConfig->basicAuthRealm);
-    }
-}
-
-/* free any allocated configuration details */
-void
-authBasicFreeConfig(authScheme * scheme)
-{
-    if (basicConfig == NULL)
-	return;
-    assert(basicConfig == scheme->scheme_data);
-    if (basicConfig->authenticate)
-	wordlistDestroy(&basicConfig->authenticate);
-    if (basicConfig->basicAuthRealm)
-	safe_free(basicConfig->basicAuthRealm);
-    xfree(basicConfig);
-    basicConfig = NULL;
-}
-
-void
-authenticateBasicFreeUser(auth_user_t * auth_user)
-{
-    basic_data *basic_auth = auth_user->scheme_data;
-    debug(29, 5) ("authenticateBasicFreeUser: Clearing Basic scheme data\n");
-    if (basic_auth->username)
-	xfree(basic_auth->username);
-    if (basic_auth->passwd)
-	xfree(basic_auth->passwd);
-    memPoolFree(basic_data_pool, auth_user->scheme_data);
-    auth_user->scheme_data = NULL;
-}
-
-static void
-authenticateBasicHandleReply(void *data, char *reply)
-{
-    authenticateStateData *r = data;
-    auth_user_t *auth_user;
-    basic_data *basic_auth;
-    auth_basic_queue_node *tmpnode;
-    char *t = NULL;
-    void *cbdata;
-    debug(29, 9) ("authenticateBasicHandleReply: {%s}\n", reply ? reply : "<NULL>");
-    if (reply) {
-	if ((t = strchr(reply, ' ')))
-	    *t = '\0';
-	if (*reply == '\0')
-	    reply = NULL;
-    }
-    assert(r->auth_user_request != NULL);
-    assert(r->auth_user_request->auth_user->auth_type == AUTH_BASIC);
-    auth_user = r->auth_user_request->auth_user;
-    basic_auth = auth_user->scheme_data;
-    if (reply && (strncasecmp(reply, "OK", 2) == 0))
-	basic_auth->flags.credentials_ok = 1;
-    else
-	basic_auth->flags.credentials_ok = 3;
-    basic_auth->credentials_checkedtime = squid_curtime;
-    if (cbdataReferenceValidDone(r->data, &cbdata))
-	r->handler(cbdata, NULL);
-    cbdataReferenceDone(r->data);
-    while (basic_auth->auth_queue) {
-	tmpnode = basic_auth->auth_queue->next;
-	if (cbdataReferenceValidDone(basic_auth->auth_queue->data, &cbdata))
-	    basic_auth->auth_queue->handler(cbdata, NULL);
-	xfree(basic_auth->auth_queue);
-	basic_auth->auth_queue = tmpnode;
-    }
-    authenticateStateFree(r);
-}
-
-static void
-authBasicCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
-{
-    auth_basic_config *config = scheme->scheme_data;
-    wordlist *list = config->authenticate;
-    storeAppendPrintf(entry, "%s %s", name, "basic");
-    while (list != NULL) {
-	storeAppendPrintf(entry, " %s", list->key);
-	list = list->next;
-    }
-    storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s credentialsttl %d seconds\n",
-	name, "basic", config->basicAuthRealm,
-	name, "basic", config->authenticateChildren,
-	name, "basic", (int)config->credentialsTTL);
-
-}
-
-static void
-authBasicParse(authScheme * scheme, int n_configured, char *param_str)
-{
-    if (scheme->scheme_data == NULL) {
-	assert(basicConfig == NULL);
-	/* this is the first param to be found */
-	scheme->scheme_data = xmalloc(sizeof(auth_basic_config));
-	memset(scheme->scheme_data, 0, sizeof(auth_basic_config));
-	basicConfig = scheme->scheme_data;
-	basicConfig->authenticateChildren = 5;
-	basicConfig->credentialsTTL = 2 * 60 * 60;	/* two hours */
-    }
-    basicConfig = scheme->scheme_data;
-    if (strcasecmp(param_str, "program") == 0) {
-	if (basicConfig->authenticate)
-	    wordlistDestroy(&basicConfig->authenticate);
-	parse_wordlist(&basicConfig->authenticate);
-	requirePathnameExists("authparam basic program", basicConfig->authenticate->key);
-    } else if (strcasecmp(param_str, "children") == 0) {
-	parse_int(&basicConfig->authenticateChildren);
-    } else if (strcasecmp(param_str, "realm") == 0) {
-	parse_eol(&basicConfig->basicAuthRealm);
-    } else if (strcasecmp(param_str, "credentialsttl") == 0) {
-	parse_time_t(&basicConfig->credentialsTTL);
-    } else {
-	debug(28, 0) ("unrecognised basic auth scheme parameter '%s'\n", param_str);
-    }
-}
-
-static void
-authenticateBasicStats(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "Basic Authenticator Statistics:\n");
-    helperStats(sentry, basicauthenticators);
-}
-
-CBDATA_TYPE(authenticateStateData);
-
-/* authenticateBasicUsername: return a pointer to the username in the */
-char *
-authenticateBasicUsername(auth_user_t * auth_user)
-{
-    basic_data *basic_auth = auth_user->scheme_data;
-    if (basic_auth)
-	return basic_auth->username;
-    return NULL;
-}
-
-static basic_data *
-authBasicDataNew(void)
-{
-    basic_data *temp;
-    temp = memPoolAlloc(basic_data_pool);
-    assert(temp != NULL);
-    temp->username = NULL;
-    temp->passwd = NULL;
-    temp->auth_queue = NULL;
-    return temp;
-}
-
-#if UNUSED_CODE
-static void
-authBasicDataFree(basic_data * basic_auth)
-{
-}
-
-#endif
-
-static auth_user_t *
-authBasicAuthUserFindUsername(const char *username)
-{
-    auth_user_hash_pointer *usernamehash;
-    debug(29, 9) ("authBasicAuthUserFindUsername: Looking for user '%s'\n", username);
-    if (username && (usernamehash = hash_lookup(proxy_auth_username_cache, username))) {
-	while (usernamehash) {
-	    if ((usernamehash->auth_user->auth_type == AUTH_BASIC) &&
-		!strcmp(username, usernamehash->key))
-		return usernamehash->auth_user;
-	    usernamehash = usernamehash->next;
-	}
-    }
-    return NULL;
-}
-
-
-
-/*
- * Decode a Basic [Proxy-]Auth string, linking the passed auth_user_request structure 
- * to any existing user structure or creating one if needed. Note that just returning
- * will be treated as "cannot decode credentials". Use the message field to return a 
- * descriptive message to the user.
- */
-
-static void
-authenticateBasicDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
-{
-    char *sent_auth;
-    char *cleartext;
-    basic_data *basic_auth, local_basic;
-    auth_user_t *auth_user;
-    dlink_node *node;
-
-    /* decode the username */
-    /* trim BASIC from string */
-    while (!xisspace(*proxy_auth))
-	proxy_auth++;
-
-    local_basic.passwd = NULL;
-
-    /* Trim leading whitespace before decoding */
-    while (xisspace(*proxy_auth))
-	proxy_auth++;
-    /* username and password */
-    sent_auth = xstrdup(proxy_auth);
-    /* Trim trailing \n before decoding */
-    strtok(sent_auth, "\n");
-    cleartext = uudecode(sent_auth);
-    xfree(sent_auth);
-    /*
-     * Don't allow NL or CR in the credentials.
-     * Oezguer Kesim <oec@codeblau.de>
-     */
-    strtok(cleartext, "\r\n");
-    debug(29, 9) ("authenticateBasicDecodeAuth: cleartext = '%s'\n", cleartext);
-    local_basic.username = xstrndup(cleartext, USER_IDENT_SZ);
-    xfree(cleartext);
-    if ((cleartext = strchr(local_basic.username, ':')) != NULL)
-	*(cleartext)++ = '\0';
-    local_basic.passwd = cleartext;
-    if (cleartext == NULL) {
-	debug(29, 4) ("authenticateBasicDecodeAuth: no password in proxy authorization header '%s'\n",
-	    proxy_auth);
-	local_basic.passwd = NULL;
-	auth_user_request->message = xstrdup("no password was present in the HTTP [proxy-]authorization header. This is most likely a browser bug");
-    } else if (*cleartext == '\0') {
-	debug(29, 4) ("authenticateBasicDecodeAuth: Disallowing empty password,"
-	    "user is '%s'\n", local_basic.username);
-	local_basic.passwd = NULL;
-	auth_user_request->message = xstrdup("Request denied because you provided an empty password. Users MUST have a password.");
-    }
-    /* special case: we have to free the strings for user and password
-     * if we are not returning a filled out structure 
-     */
-    if (local_basic.passwd == NULL) {
-	if (local_basic.username) {
-	    /* log the username */
-	    debug(29, 9) ("authBasicDecodeAuth: Creating new user for logging '%s'\n", local_basic.username);
-	    /* new auth_user */
-	    auth_user = authenticateAuthUserNew("basic");
-	    /* new scheme data */
-	    basic_auth = authBasicDataNew();
-	    /* save the credentials */
-	    basic_auth->username = local_basic.username;
-	    /* link the scheme data in */
-	    auth_user->scheme_data = basic_auth;
-	    /* set the auth_user type */
-	    auth_user->auth_type = AUTH_BROKEN;
-	    /* link the request to the user */
-	    auth_user_request->auth_user = auth_user;
-	    /* lock for the auth_user_request link */
-	    authenticateAuthUserLock(auth_user);
-	    node = dlinkNodeNew();
-	    dlinkAdd(auth_user_request, node, &auth_user->requests);
-	}
-	return;
-    } else {
-	local_basic.passwd = xstrndup(cleartext, USER_IDENT_SZ);
-    }
-
-    /* now lookup and see if we have a matching auth_user structure in memory. */
-
-    if ((auth_user = authBasicAuthUserFindUsername(local_basic.username)) == NULL) {
-	/* the user doesn't exist in the username cache yet */
-	debug(29, 9) ("authBasicDecodeAuth: Creating new user '%s'\n", local_basic.username);
-	/* new auth_user */
-	auth_user = authenticateAuthUserNew("basic");
-	/* new scheme data */
-	basic_auth = authBasicDataNew();
-	/* save the credentials */
-	basic_auth->username = local_basic.username;
-	basic_auth->passwd = local_basic.passwd;
-	/* link the scheme data in */
-	auth_user->scheme_data = basic_auth;
-	/* set the auth_user type */
-	auth_user->auth_type = AUTH_BASIC;
-	/* current time for timeouts */
-	auth_user->expiretime = current_time.tv_sec;
-
-	/* this auth_user struct is the 'lucky one' to get added to the username cache */
-	/* the requests after this link to the auth_user */
-	/* store user in hash */
-	authenticateUserNameCacheAdd(auth_user);
-    } else {
-	debug(29, 9) ("authBasicDecodeAuth: Found user '%s' in the user cache as '%p'\n", local_basic.username, auth_user);
-	xfree(local_basic.username);
-	basic_auth = auth_user->scheme_data;
-	if (strcmp(local_basic.passwd, basic_auth->passwd)) {
-	    debug(29, 4) ("authBasicDecodeAuth: new password found. Updating in user master record and resetting auth state to unchecked\n");
-	    basic_auth->flags.credentials_ok = 0;
-	    xfree(basic_auth->passwd);
-	    basic_auth->passwd = local_basic.passwd;
-	} else
-	    xfree(local_basic.passwd);
-	if (basic_auth->flags.credentials_ok == 3) {
-	    debug(29, 4) ("authBasicDecodeAuth: last attempt to authenticate this user failed, resetting auth state to unchecked\n");
-	    basic_auth->flags.credentials_ok = 0;
-	}
-    }
-    /* link the request to the user */
-    auth_user_request->auth_user = auth_user;
-    /* lock for the auth_user_request link */
-    authenticateAuthUserLock(auth_user);
-    node = dlinkNodeNew();
-    dlinkAdd(auth_user_request, node, &auth_user->requests);
-    return;
-}
-
-/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
- * config file */
-static void
-authBasicInit(authScheme * scheme)
-{
-    static int init = 0;
-    if (basicConfig->authenticate) {
-	if (!basic_data_pool)
-	    basic_data_pool = memPoolCreate("Basic Scheme User Data", sizeof(basic_data));
-	authbasic_initialised = 1;
-	if (basicauthenticators == NULL)
-	    basicauthenticators = helperCreate("basicauthenticator");
-	basicauthenticators->cmdline = basicConfig->authenticate;
-	basicauthenticators->n_to_start = basicConfig->authenticateChildren;
-	basicauthenticators->ipc_type = IPC_STREAM;
-	helperOpenServers(basicauthenticators);
-	if (!init) {
-	    cachemgrRegister("basicauthenticator",
-		"User Authenticator Stats",
-		authenticateBasicStats, 0, 1);
-	    init++;
-	}
-	CBDATA_INIT_TYPE(authenticateStateData);
-    }
-}
-
-/* send the initial data to a basic authenticator module */
-static void
-authenticateBasicStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
-{
-    authenticateStateData *r = NULL;
-    char buf[8192];
-    char user[1024], pass[1024];
-    basic_data *basic_auth;
-    assert(auth_user_request);
-    assert(handler);
-    assert(auth_user_request->auth_user->auth_type == AUTH_BASIC);
-    assert(auth_user_request->auth_user->scheme_data != NULL);
-    basic_auth = auth_user_request->auth_user->scheme_data;
-    debug(29, 9) ("authenticateStart: '%s:%s'\n", basic_auth->username,
-	basic_auth->passwd);
-    if (basicConfig->authenticate == NULL) {
-	handler(data, NULL);
-	return;
-    }
-    /* check to see if the auth_user already has a request outstanding */
-    if (basic_auth->flags.credentials_ok == 2) {
-	/* there is a request with the same credentials already being verified */
-	auth_basic_queue_node *node;
-	node = xmalloc(sizeof(auth_basic_queue_node));
-	assert(node);
-	/* save the details */
-	node->next = basic_auth->auth_queue;
-	basic_auth->auth_queue = node;
-	node->auth_user_request = auth_user_request;
-	node->handler = handler;
-	node->data = cbdataReference(data);
-	return;
-    } else {
-	r = cbdataAlloc(authenticateStateData);
-	r->handler = handler;
-	r->data = cbdataReference(data);
-	r->auth_user_request = auth_user_request;
-	/* mark the user as haveing verification in progress */
-	basic_auth->flags.credentials_ok = 2;
-	xstrncpy(user, rfc1738_escape(basic_auth->username), sizeof(user));
-	xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass));
-	snprintf(buf, sizeof(buf), "%s %s\n", user, pass);
-	helperSubmit(basicauthenticators, buf, authenticateBasicHandleReply, r);
-    }
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/auth/basic/auth_basic.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,600 @@
+/*
+ * $Id: auth_basic.cc,v 1.1.2.1 2002/10/03 01:04:37 rbcollins Exp $
+ *
+ * DEBUG: section 29    Authenticator
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/* The functions in this file handle authentication.
+ * They DO NOT perform access control or auditing.
+ * See acl.c for access control and client_side.c for auditing */
+
+
+#include "squid.h"
+#include "auth_basic.h"
+#include "authenticate.h"
+
+static void
+authenticateStateFree(AuthenticateStateData * r)
+{
+    cbdataFree(r);
+}
+
+/* Basic Scheme */
+
+static HLPCB authenticateBasicHandleReply;
+static AUTHSACTIVE authenticateBasicActive;
+static AUTHSAUTHED authenticateBasicAuthenticated;
+static AUTHSAUTHUSER authenticateBasicAuthenticateUser;
+static AUTHSCONFIGURED authBasicConfigured;
+static AUTHSDIRECTION authenticateBasicDirection;
+static AUTHSDECODE authenticateBasicDecodeAuth;
+static AUTHSDUMP authBasicCfgDump;
+static AUTHSFIXERR authenticateBasicFixErrorHeader;
+static AUTHSFREE authenticateBasicFreeUser;
+static AUTHSFREECONFIG authBasicFreeConfig;
+static AUTHSPARSE authBasicParse;
+static AUTHSINIT authBasicInit;
+static AUTHSSTART authenticateBasicStart;
+static AUTHSSTATS authenticateBasicStats;
+static AUTHSUSERNAME authenticateBasicUsername;
+static AUTHSSHUTDOWN authBasicDone;
+
+static helper *basicauthenticators = NULL;
+
+static auth_basic_config *basicConfig = NULL;
+
+static int authbasic_initialised = 0;
+MemPool *basic_data_pool = NULL;
+
+
+/*
+ *
+ * Public Functions
+ *
+ */
+
+AUTHSSETUP authSchemeSetup_basic;
+
+void
+authSchemeSetup_basic(authscheme_entry_t * authscheme)
+{
+    assert(!authbasic_initialised);
+    authscheme->Active = authenticateBasicActive;
+    authscheme->parse = authBasicParse;
+    authscheme->dump = authBasicCfgDump;
+    authscheme->init = authBasicInit;
+    authscheme->authAuthenticate = authenticateBasicAuthenticateUser;
+    authscheme->authenticated = authenticateBasicAuthenticated;
+    authscheme->configured = authBasicConfigured;
+    authscheme->authFixHeader = authenticateBasicFixErrorHeader;
+    authscheme->FreeUser = authenticateBasicFreeUser;
+    authscheme->freeconfig = authBasicFreeConfig;
+    authscheme->authStart = authenticateBasicStart;
+    authscheme->authStats = authenticateBasicStats;
+    authscheme->authUserUsername = authenticateBasicUsername;
+    authscheme->getdirection = authenticateBasicDirection;
+    authscheme->oncloseconnection = NULL;
+    authscheme->decodeauth = authenticateBasicDecodeAuth;
+    authscheme->donefunc = authBasicDone;
+    authscheme->authConnLastHeader = NULL;
+}
+
+/* internal functions */
+
+static void
+authBasicDone(void)
+{
+    if (basicauthenticators)
+	helperShutdown(basicauthenticators);
+    authbasic_initialised = 0;
+    if (!shutting_down)
+	return;
+    if (basicauthenticators)
+	helperFree(basicauthenticators);
+    basicauthenticators = NULL;
+    if (basic_data_pool) {
+	memPoolDestroy(&basic_data_pool);
+	basic_data_pool = NULL;
+    }
+    debug(29, 2) ("authBasicDone: Basic authentication Shutdown.\n");
+}
+
+static int
+authenticateBasicActive()
+{
+    return (authbasic_initialised == 1) ? 1 : 0;
+}
+
+static int
+authBasicConfigured()
+{
+    if ((basicConfig != NULL) && (basicConfig->authenticate != NULL) &&
+	(basicConfig->authenticateChildren != 0) &&
+	(basicConfig->basicAuthRealm != NULL)) {
+	debug(29, 9) ("authBasicConfigured: returning configured\n");
+	return 1;
+    }
+    debug(29, 9) ("authBasicConfigured: returning unconfigured\n");
+    return 0;
+}
+
+static int
+authenticateBasicAuthenticated(auth_user_request_t * auth_user_request)
+{
+    basic_data *basic_auth = static_cast<basic_data *>(auth_user_request->auth_user->scheme_data);
+    if ((basic_auth->flags.credentials_ok == 1) && (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL > squid_curtime))
+	return 1;
+    debug(29, 4) ("User not authenticated or credentials need rechecking.\n");
+    return 0;
+}
+
+#if UNUSED_CODE
+static int
+authenticateBasiccmpUsername(basic_data * u1, basic_data * u2)
+{
+    return strcmp(u1->username, u2->username);
+}
+#endif
+
+/* log a basic user in
+ */
+static void
+authenticateBasicAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
+{
+    auth_user_t *auth_user;
+    basic_data *basic_auth;
+
+    assert(auth_user_request->auth_user != NULL);
+    auth_user = auth_user_request->auth_user;
+
+    assert(auth_user->scheme_data != NULL);
+    basic_auth = static_cast<basic_data *>(auth_user->scheme_data);
+
+    /* if the password is not ok, do an identity */
+    if (basic_auth->flags.credentials_ok != 1)
+	return;
+
+    /* are we about to recheck the credentials externally? */
+    if ((basic_auth->credentials_checkedtime + basicConfig->credentialsTTL) <= squid_curtime) {
+	debug(29, 4) ("authBasicAuthenticate: credentials expired - rechecking\n");
+	return;
+    }
+    /* we have been through the external helper, and the credentials haven't expired */
+    debug(29, 9) ("authenticateBasicAuthenticateuser: user '%s' authenticated\n",
+	basic_auth->username);
+
+    /* Decode now takes care of finding the auth_user struct in the cache */
+    /* after external auth occurs anyway */
+    auth_user->expiretime = current_time.tv_sec;
+    return;
+}
+
+int
+authenticateBasicDirection(auth_user_request_t * auth_user_request)
+{
+/* null auth_user is checked for by authenticateDirection */
+    auth_user_t *auth_user = auth_user_request->auth_user;
+    basic_data *basic_auth = static_cast<basic_data *>(auth_user->scheme_data);
+    switch (basic_auth->flags.credentials_ok) {
+    case 0:			/* not checked */
+	return -1;
+    case 1:			/* checked & ok */
+	if (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL <= squid_curtime)
+	    return -1;
+	return 0;
+    case 2:			/* paused while waiting for a username:password check on another request */
+	return -1;
+    case 3:			/* authentication process failed. */
+	return -2;
+    }
+    return -2;
+}
+
+void
+authenticateBasicFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
+{
+    if (basicConfig->authenticate) {
+	debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicConfig->basicAuthRealm);
+	httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicConfig->basicAuthRealm);
+    }
+}
+
+/* free any allocated configuration details */
+void
+authBasicFreeConfig(authScheme * scheme)
+{
+    if (basicConfig == NULL)
+	return;
+    assert(basicConfig == scheme->scheme_data);
+    if (basicConfig->authenticate)
+	wordlistDestroy(&basicConfig->authenticate);
+    if (basicConfig->basicAuthRealm)
+	safe_free(basicConfig->basicAuthRealm);
+    xfree(basicConfig);
+    basicConfig = NULL;
+}
+
+void
+authenticateBasicFreeUser(auth_user_t * auth_user)
+{
+    basic_data *basic_auth = static_cast<basic_data *>(auth_user->scheme_data);
+    debug(29, 5) ("authenticateBasicFreeUser: Clearing Basic scheme data\n");
+    if (basic_auth->username)
+	xfree(basic_auth->username);
+    if (basic_auth->passwd)
+	xfree(basic_auth->passwd);
+    memPoolFree(basic_data_pool, auth_user->scheme_data);
+    auth_user->scheme_data = NULL;
+}
+
+static void
+authenticateBasicHandleReply(void *data, char *reply)
+{
+    AuthenticateStateData *r = static_cast<AuthenticateStateData *>(data);
+    auth_user_t *auth_user;
+    basic_data *basic_auth;
+    BasicAuthQueueNode *tmpnode;
+    char *t = NULL;
+    void *cbdata;
+    debug(29, 9) ("authenticateBasicHandleReply: {%s}\n", reply ? reply : "<NULL>");
+    if (reply) {
+	if ((t = strchr(reply, ' ')))
+	    *t = '\0';
+	if (*reply == '\0')
+	    reply = NULL;
+    }
+    assert(r->auth_user_request != NULL);
+    assert(r->auth_user_request->auth_user->auth_type == AUTH_BASIC);
+    auth_user = r->auth_user_request->auth_user;
+    basic_auth = static_cast<basic_data *>(auth_user->scheme_data);
+    if (reply && (strncasecmp(reply, "OK", 2) == 0))
+	basic_auth->flags.credentials_ok = 1;
+    else
+	basic_auth->flags.credentials_ok = 3;
+    basic_auth->credentials_checkedtime = squid_curtime;
+    if (cbdataReferenceValidDone(r->data, &cbdata))
+	r->handler(cbdata, NULL);
+    cbdataReferenceDone(r->data);
+    while (basic_auth->auth_queue) {
+	tmpnode = basic_auth->auth_queue->next;
+	if (cbdataReferenceValidDone(basic_auth->auth_queue->data, &cbdata))
+	    basic_auth->auth_queue->handler(cbdata, NULL);
+	xfree(basic_auth->auth_queue);
+	basic_auth->auth_queue = tmpnode;
+    }
+    authenticateStateFree(r);
+}
+
+static void
+authBasicCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
+{
+    auth_basic_config *config = static_cast<auth_basic_config *>(scheme->scheme_data);
+    wordlist *list = config->authenticate;
+    storeAppendPrintf(entry, "%s %s", name, "basic");
+    while (list != NULL) {
+	storeAppendPrintf(entry, " %s", list->key);
+	list = list->next;
+    }
+    storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s credentialsttl %d seconds\n",
+	name, "basic", config->basicAuthRealm,
+	name, "basic", config->authenticateChildren,
+	name, "basic", (int)config->credentialsTTL);
+
+}
+
+static void
+authBasicParse(authScheme * scheme, int n_configured, char *param_str)
+{
+    if (scheme->scheme_data == NULL) {
+	assert(basicConfig == NULL);
+	/* this is the first param to be found */
+	scheme->scheme_data = xmalloc(sizeof(auth_basic_config));
+	memset(scheme->scheme_data, 0, sizeof(auth_basic_config));
+	basicConfig = static_cast<auth_basic_config *>(scheme->scheme_data);
+	basicConfig->authenticateChildren = 5;
+	basicConfig->credentialsTTL = 2 * 60 * 60;	/* two hours */
+    }
+    basicConfig =  static_cast<auth_basic_config *>(scheme->scheme_data);
+    if (strcasecmp(param_str, "program") == 0) {
+	if (basicConfig->authenticate)
+	    wordlistDestroy(&basicConfig->authenticate);
+	parse_wordlist(&basicConfig->authenticate);
+	requirePathnameExists("authparam basic program", basicConfig->authenticate->key);
+    } else if (strcasecmp(param_str, "children") == 0) {
+	parse_int(&basicConfig->authenticateChildren);
+    } else if (strcasecmp(param_str, "realm") == 0) {
+	parse_eol(&basicConfig->basicAuthRealm);
+    } else if (strcasecmp(param_str, "credentialsttl") == 0) {
+	parse_time_t(&basicConfig->credentialsTTL);
+    } else {
+	debug(28, 0) ("unrecognised basic auth scheme parameter '%s'\n", param_str);
+    }
+}
+
+static void
+authenticateBasicStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "Basic Authenticator Statistics:\n");
+    helperStats(sentry, basicauthenticators);
+}
+
+CBDATA_TYPE(AuthenticateStateData);
+
+/* authenticateBasicUsername: return a pointer to the username in the */
+char const *
+authenticateBasicUsername(auth_user_t const * auth_user)
+{
+    basic_data *basic_auth =  static_cast<basic_data *>(auth_user->scheme_data);
+    if (basic_auth)
+	return basic_auth->username;
+    return NULL;
+}
+
+static basic_data *
+authBasicDataNew(void)
+{
+    basic_data *temp;
+    temp =  static_cast<basic_data *>(memPoolAlloc(basic_data_pool));
+    assert(temp != NULL);
+    temp->username = NULL;
+    temp->passwd = NULL;
+    temp->auth_queue = NULL;
+    return temp;
+}
+
+#if UNUSED_CODE
+static void
+authBasicDataFree(basic_data * basic_auth)
+{
+}
+
+#endif
+
+static auth_user_t *
+authBasicAuthUserFindUsername(const char *username)
+{
+    AuthUserHashPointer *usernamehash;
+    debug(29, 9) ("authBasicAuthUserFindUsername: Looking for user '%s'\n", username);
+    if (username && (usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, username)))) {
+	while (usernamehash) {
+	    if ((authUserHashPointerUser(usernamehash)->auth_type == AUTH_BASIC) &&
+		!strcmp(username, usernamehash->key))
+		return authUserHashPointerUser(usernamehash);
+	    usernamehash = usernamehash->next;
+	}
+    }
+    return NULL;
+}
+
+
+
+/*
+ * Decode a Basic [Proxy-]Auth string, linking the passed auth_user_request structure 
+ * to any existing user structure or creating one if needed. Note that just returning
+ * will be treated as "cannot decode credentials". Use the message field to return a 
+ * descriptive message to the user.
+ */
+
+static void
+authenticateBasicDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
+{
+    char *sent_auth;
+    char *cleartext;
+    basic_data *basic_auth, local_basic;
+    auth_user_t *auth_user;
+    dlink_node *node;
+
+    /* decode the username */
+    /* trim BASIC from string */
+    while (!xisspace(*proxy_auth))
+	proxy_auth++;
+
+    local_basic.passwd = NULL;
+
+    /* Trim leading whitespace before decoding */
+    while (xisspace(*proxy_auth))
+	proxy_auth++;
+    /* username and password */
+    sent_auth = xstrdup(proxy_auth);
+    /* Trim trailing \n before decoding */
+    strtok(sent_auth, "\n");
+    cleartext = uudecode(sent_auth);
+    xfree(sent_auth);
+    /*
+     * Don't allow NL or CR in the credentials.
+     * Oezguer Kesim <oec@codeblau.de>
+     */
+    strtok(cleartext, "\r\n");
+    debug(29, 9) ("authenticateBasicDecodeAuth: cleartext = '%s'\n", cleartext);
+    local_basic.username = xstrndup(cleartext, USER_IDENT_SZ);
+    xfree(cleartext);
+    if ((cleartext = strchr(local_basic.username, ':')) != NULL)
+	*(cleartext)++ = '\0';
+    local_basic.passwd = cleartext;
+    if (cleartext == NULL) {
+	debug(29, 4) ("authenticateBasicDecodeAuth: no password in proxy authorization header '%s'\n",
+	    proxy_auth);
+	local_basic.passwd = NULL;
+	authenticateSetDenyMessage (auth_user_request, "no password was present in the HTTP [proxy-]authorization header. This is most likely a browser bug");
+    } else if (*cleartext == '\0') {
+	debug(29, 4) ("authenticateBasicDecodeAuth: Disallowing empty password,"
+	    "user is '%s'\n", local_basic.username);
+	local_basic.passwd = NULL;
+	authenticateSetDenyMessage (auth_user_request, "Request denied because you provided an empty password. Users MUST have a password.");
+    }
+    /* special case: we have to free the strings for user and password
+     * if we are not returning a filled out structure 
+     */
+    if (local_basic.passwd == NULL) {
+	if (local_basic.username) {
+	    /* log the username */
+	    debug(29, 9) ("authBasicDecodeAuth: Creating new user for logging '%s'\n", local_basic.username);
+	    /* new auth_user */
+	    auth_user = authenticateAuthUserNew("basic");
+	    /* new scheme data */
+	    basic_auth = authBasicDataNew();
+	    /* save the credentials */
+	    basic_auth->username = local_basic.username;
+	    /* link the scheme data in */
+	    auth_user->scheme_data = basic_auth;
+	    /* set the auth_user type */
+	    auth_user->auth_type = AUTH_BROKEN;
+	    /* link the request to the user */
+	    auth_user_request->auth_user = auth_user;
+	    /* lock for the auth_user_request link */
+	    authenticateAuthUserLock(auth_user);
+	    node = dlinkNodeNew();
+	    dlinkAdd(auth_user_request, node, &auth_user->requests);
+	}
+	return;
+    } else {
+	local_basic.passwd = xstrndup(cleartext, USER_IDENT_SZ);
+    }
+
+    /* now lookup and see if we have a matching auth_user structure in memory. */
+
+    if ((auth_user = authBasicAuthUserFindUsername(local_basic.username)) == NULL) {
+	/* the user doesn't exist in the username cache yet */
+	debug(29, 9) ("authBasicDecodeAuth: Creating new user '%s'\n", local_basic.username);
+	/* new auth_user */
+	auth_user = authenticateAuthUserNew("basic");
+	/* new scheme data */
+	basic_auth = authBasicDataNew();
+	/* save the credentials */
+	basic_auth->username = local_basic.username;
+	basic_auth->passwd = local_basic.passwd;
+	/* link the scheme data in */
+	auth_user->scheme_data = basic_auth;
+	/* set the auth_user type */
+	auth_user->auth_type = AUTH_BASIC;
+	/* current time for timeouts */
+	auth_user->expiretime = current_time.tv_sec;
+
+	/* this auth_user struct is the 'lucky one' to get added to the username cache */
+	/* the requests after this link to the auth_user */
+	/* store user in hash */
+	authenticateUserNameCacheAdd(auth_user);
+    } else {
+	debug(29, 9) ("authBasicDecodeAuth: Found user '%s' in the user cache as '%p'\n", local_basic.username, auth_user);
+	xfree(local_basic.username);
+	basic_auth =  static_cast<basic_data *>(auth_user->scheme_data);
+	if (strcmp(local_basic.passwd, basic_auth->passwd)) {
+	    debug(29, 4) ("authBasicDecodeAuth: new password found. Updating in user master record and resetting auth state to unchecked\n");
+	    basic_auth->flags.credentials_ok = 0;
+	    xfree(basic_auth->passwd);
+	    basic_auth->passwd = local_basic.passwd;
+	} else
+	    xfree(local_basic.passwd);
+	if (basic_auth->flags.credentials_ok == 3) {
+	    debug(29, 4) ("authBasicDecodeAuth: last attempt to authenticate this user failed, resetting auth state to unchecked\n");
+	    basic_auth->flags.credentials_ok = 0;
+	}
+    }
+    /* link the request to the user */
+    auth_user_request->auth_user = auth_user;
+    /* lock for the auth_user_request link */
+    authenticateAuthUserLock(auth_user);
+    node = dlinkNodeNew();
+    dlinkAdd(auth_user_request, node, &auth_user->requests);
+    return;
+}
+
+/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
+ * config file */
+static void
+authBasicInit(authScheme * scheme)
+{
+    static int init = 0;
+    if (basicConfig->authenticate) {
+	if (!basic_data_pool)
+	    basic_data_pool = memPoolCreate("Basic Scheme User Data", sizeof(basic_data));
+	authbasic_initialised = 1;
+	if (basicauthenticators == NULL)
+	    basicauthenticators = helperCreate("basicauthenticator");
+	basicauthenticators->cmdline = basicConfig->authenticate;
+	basicauthenticators->n_to_start = basicConfig->authenticateChildren;
+	basicauthenticators->ipc_type = IPC_STREAM;
+	helperOpenServers(basicauthenticators);
+	if (!init) {
+	    cachemgrRegister("basicauthenticator",
+		"User Authenticator Stats",
+		authenticateBasicStats, 0, 1);
+	    init++;
+	}
+	CBDATA_INIT_TYPE(AuthenticateStateData);
+    }
+}
+
+/* send the initial data to a basic authenticator module */
+static void
+authenticateBasicStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
+{
+    AuthenticateStateData *r = NULL;
+    char buf[8192];
+    char user[1024], pass[1024];
+    basic_data *basic_auth;
+    assert(auth_user_request);
+    assert(handler);
+    assert(auth_user_request->auth_user->auth_type == AUTH_BASIC);
+    assert(auth_user_request->auth_user->scheme_data != NULL);
+    basic_auth = static_cast<basic_data *>(auth_user_request->auth_user->scheme_data);
+    debug(29, 9) ("authenticateStart: '%s:%s'\n", basic_auth->username,
+	basic_auth->passwd);
+    if (basicConfig->authenticate == NULL) {
+	handler(data, NULL);
+	return;
+    }
+    /* check to see if the auth_user already has a request outstanding */
+    if (basic_auth->flags.credentials_ok == 2) {
+	/* there is a request with the same credentials already being verified */
+	BasicAuthQueueNode *node;
+	node = static_cast<BasicAuthQueueNode *>(xmalloc(sizeof(BasicAuthQueueNode)));
+	assert(node);
+	/* save the details */
+	node->next = basic_auth->auth_queue;
+	basic_auth->auth_queue = node;
+	node->auth_user_request = auth_user_request;
+	node->handler = handler;
+	node->data = cbdataReference(data);
+	return;
+    } else {
+	r = cbdataAlloc(AuthenticateStateData);
+	r->handler = handler;
+	r->data = cbdataReference(data);
+	r->auth_user_request = auth_user_request;
+	/* mark the user as haveing verification in progress */
+	basic_auth->flags.credentials_ok = 2;
+	xstrncpy(user, rfc1738_escape(basic_auth->username), sizeof(user));
+	xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass));
+	snprintf(buf, sizeof(buf), "%s %s\n", user, pass);
+	helperSubmit(basicauthenticators, buf, authenticateBasicHandleReply, r);
+    }
+}
Index: squid/src/auth/basic/auth_basic.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/auth/basic/auth_basic.h,v
retrieving revision 1.4
retrieving revision 1.4.44.1
diff -u -r1.4 -r1.4.44.1
--- squid/src/auth/basic/auth_basic.h	17 Oct 2001 12:42:59 -0000	1.4
+++ squid/src/auth/basic/auth_basic.h	3 Oct 2002 01:04:37 -0000	1.4.44.1
@@ -6,47 +6,43 @@
 #ifndef __AUTH_BASIC_H__
 #define __AUTH_BASIC_H__
 
-
 #define DefaultAuthenticateChildrenMax  32	/* 32 processes */
 
 /* Generic */
-typedef struct {
+class AuthenticateStateData {
+public:
     void *data;
     auth_user_request_t *auth_user_request;
     RH *handler;
-} authenticateStateData;
-
-typedef struct _auth_basic_queue_node auth_basic_queue_node;
+};
 
 /* queue of auth requests waiting for verification to occur */
-struct _auth_basic_queue_node {
-    auth_basic_queue_node *next;
-    auth_user_request_t *auth_user_request;
+class BasicAuthQueueNode {
+public:
+    BasicAuthQueueNode *next;
+    AuthUserRequest *auth_user_request;
     RH *handler;
     void *data;
 };
 
-struct _basic_data {
+class basic_data {
+public:
     char *username;
     char *passwd;
     time_t credentials_checkedtime;
     struct {
 	unsigned int credentials_ok:2;	/*0=unchecked,1=ok,2=failed */
     } flags;
-    auth_basic_queue_node *auth_queue;
+    BasicAuthQueueNode *auth_queue;
 };
 
 /* configuration runtime data */
-struct _auth_basic_config {
+class auth_basic_config {
+public:
     int authenticateChildren;
     char *basicAuthRealm;
     wordlist *authenticate;
     time_t credentialsTTL;
 };
 
-typedef struct _auth_basic_config auth_basic_config;
-
-typedef struct _basic_data basic_data;
-
-
 #endif
--- squid/src/auth/digest/auth_digest.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,1353 +0,0 @@
-
-/*
- * $Id$
- *
- * DEBUG: section 29    Authenticator
- * AUTHOR: Robert Collins
- *
- * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from the
- *  Internet community.  Development is led by Duane Wessels of the
- *  National Laboratory for Applied Network Research and funded by the
- *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
- *  the Regents of the University of California.  Please see the
- *  COPYRIGHT file for full details.  Squid incorporates software
- *  developed and/or copyrighted by other sources.  Please see the
- *  CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-/* The functions in this file handle authentication.
- * They DO NOT perform access control or auditing.
- * See acl.c for access control and client_side.c for auditing */
-
-
-#include "squid.h"
-#include "rfc2617.h"
-#include "auth_digest.h"
-
-extern AUTHSSETUP authSchemeSetup_digest;
-
-static void
-authenticateStateFree(authenticateStateData * r)
-{
-    cbdataFree(r);
-}
-
-/* Digest Scheme */
-
-static HLPCB authenticateDigestHandleReply;
-static AUTHSACTIVE authenticateDigestActive;
-static AUTHSADDHEADER authDigestAddHeader;
-#if WAITING_FOR_TE
-static AUTHSADDTRAILER authDigestAddTrailer;
-#endif
-static AUTHSAUTHED authDigestAuthenticated;
-static AUTHSAUTHUSER authenticateDigestAuthenticateUser;
-static AUTHSCONFIGURED authDigestConfigured;
-static AUTHSDIRECTION authenticateDigestDirection;
-static AUTHSDECODE authenticateDigestDecodeAuth;
-static AUTHSDUMP authDigestCfgDump;
-static AUTHSFIXERR authenticateDigestFixHeader;
-static AUTHSFREE authenticateDigestUserFree;
-static AUTHSFREECONFIG authDigestFreeConfig;
-static AUTHSINIT authDigestInit;
-static AUTHSPARSE authDigestParse;
-static AUTHSREQFREE authDigestAURequestFree;
-static AUTHSSTART authenticateDigestStart;
-static AUTHSSTATS authenticateDigestStats;
-static AUTHSUSERNAME authenticateDigestUsername;
-static AUTHSSHUTDOWN authDigestDone;
-
-static helper *digestauthenticators = NULL;
-
-static hash_table *digest_nonce_cache;
-
-static auth_digest_config *digestConfig = NULL;
-
-static int authdigest_initialised = 0;
-static MemPool *digest_user_pool = NULL;
-static MemPool *digest_request_pool = NULL;
-static MemPool *digest_nonce_pool = NULL;
-
-CBDATA_TYPE(authenticateStateData);
-
-/*
- *
- * Nonce Functions
- *
- */
-
-static void authenticateDigestNonceCacheCleanup(void *data);
-static digest_nonce_h *authenticateDigestNonceFindNonce(const char *nonceb64);
-static digest_nonce_h *authenticateDigestNonceNew(void);
-static void authenticateDigestNonceDelete(digest_nonce_h * nonce);
-static void authenticateDigestNonceSetup(void);
-static void authenticateDigestNonceShutdown(void);
-static void authenticateDigestNonceReconfigure(void);
-static const char *authenticateDigestNonceNonceb64(digest_nonce_h * nonce);
-static int authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9]);
-static int authDigestNonceIsStale(digest_nonce_h * nonce);
-static void authDigestNonceEncode(digest_nonce_h * nonce);
-static int authDigestNonceLastRequest(digest_nonce_h * nonce);
-static void authDigestNonceLink(digest_nonce_h * nonce);
-static void authDigestNonceUnlink(digest_nonce_h * nonce);
-#if NOT_USED
-static int authDigestNonceLinks(digest_nonce_h * nonce);
-#endif
-static void authDigestNonceUserUnlink(digest_nonce_h * nonce);
-static void authDigestNoncePurge(digest_nonce_h * nonce);
-
-static void
-authDigestNonceEncode(digest_nonce_h * nonce)
-{
-    if (!nonce)
-	return;
-    if (nonce->hash.key)
-	xfree(nonce->hash.key);
-    nonce->hash.key = xstrdup(base64_encode_bin((char *) &(nonce->noncedata), sizeof(digest_nonce_data)));
-}
-
-static digest_nonce_h *
-authenticateDigestNonceNew(void)
-{
-    digest_nonce_h *newnonce = memPoolAlloc(digest_nonce_pool);
-    digest_nonce_h *temp;
-
-/* NONCE CREATION - NOTES AND REASONING. RBC 20010108
- * === EXCERPT FROM RFC 2617 ===
- * The contents of the nonce are implementation dependent. The quality
- * of the implementation depends on a good choice. A nonce might, for
- * example, be constructed as the base 64 encoding of
- * 
- * time-stamp H(time-stamp ":" ETag ":" private-key)
- * 
- * where time-stamp is a server-generated time or other non-repeating
- * value, ETag is the value of the HTTP ETag header associated with
- * the requested entity, and private-key is data known only to the
- * server.  With a nonce of this form a server would recalculate the
- * hash portion after receiving the client authentication header and
- * reject the request if it did not match the nonce from that header
- * or if the time-stamp value is not recent enough. In this way the
- * server can limit the time of the nonce's validity. The inclusion of
- * the ETag prevents a replay request for an updated version of the
- * resource.  (Note: including the IP address of the client in the
- * nonce would appear to offer the server the ability to limit the
- * reuse of the nonce to the same client that originally got it.
- * However, that would break proxy farms, where requests from a single
- * user often go through different proxies in the farm. Also, IP
- * address spoofing is not that hard.)
- * ====
- * 
- * Now for my reasoning:
- * We will not accept a unrecognised nonce->we have all recognisable
- * nonces stored If we send out unique base64 encodings we guarantee
- * that a given nonce applies to only one user (barring attacks or
- * really bad timing with expiry and creation).  Using a random
- * component in the nonce allows us to loop to find a unique nonce.
- * We use H(nonce_data) so the nonce is meaningless to the reciever.
- * So our nonce looks like base64(H(timestamp,pointertohash,randomdata))
- * And even if our randomness is not very random (probably due to
- * bad coding on my part) we don't really care - the timestamp and
- * memory pointer should provide enough protection for the users
- * authentication.
- */
-
-    /* create a new nonce */
-    newnonce->nc = 0;
-    newnonce->flags.valid = 1;
-    newnonce->noncedata.self = newnonce;
-    newnonce->noncedata.creationtime = current_time.tv_sec;
-    newnonce->noncedata.randomdata = squid_random();
-
-    authDigestNonceEncode(newnonce);
-    /*
-     * loop until we get a unique nonce. The nonce creation must
-     * have a random factor
-     */
-    while ((temp = authenticateDigestNonceFindNonce(newnonce->hash.key))) {
-	/* create a new nonce */
-	newnonce->noncedata.randomdata = squid_random();
-	authDigestNonceEncode(newnonce);
-    }
-    hash_join(digest_nonce_cache, &newnonce->hash);
-    /* the cache's link */
-    authDigestNonceLink(newnonce);
-    newnonce->flags.incache = 1;
-    debug(29, 5) ("authenticateDigestNonceNew: created nonce %p at %ld\n", newnonce, (long int)newnonce->noncedata.creationtime);
-    return newnonce;
-}
-
-static void
-authenticateDigestNonceDelete(digest_nonce_h * nonce)
-{
-    if (nonce) {
-	assert(nonce->references == 0);
-#if UNREACHABLECODE
-	if (nonce->flags.incache)
-	    hash_remove_link(digest_nonce_cache, &nonce->hash);
-#endif
-	assert(nonce->flags.incache == 0);
-	safe_free(nonce->hash.key);
-	memPoolFree(digest_nonce_pool, nonce);
-    }
-}
-
-static void
-authenticateDigestNonceSetup(void)
-{
-    if (!digest_nonce_pool)
-	digest_nonce_pool = memPoolCreate("Digest Scheme nonce's", sizeof(digest_nonce_h));
-    if (!digest_nonce_cache) {
-	digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
-	assert(digest_nonce_cache);
-	eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1);
-    }
-}
-
-static void
-authenticateDigestNonceShutdown(void)
-{
-    /* 
-     * We empty the cache of any nonces left in there.
-     */
-    digest_nonce_h *nonce;
-    if (digest_nonce_cache) {
-	debug(29, 2) ("authenticateDigestNonceShutdown: Shutting down nonce cache \n");
-	hash_first(digest_nonce_cache);
-	while ((nonce = ((digest_nonce_h *) hash_next(digest_nonce_cache)))) {
-	    assert(nonce->flags.incache);
-	    authDigestNoncePurge(nonce);
-	}
-    }
-    if (digest_nonce_pool) {
-	assert(memPoolInUseCount(digest_nonce_pool) == 0);
-	memPoolDestroy(&digest_nonce_pool);
-    }
-    debug(29, 2) ("authenticateDigestNonceShutdown: Nonce cache shutdown\n");
-}
-
-static void
-authenticateDigestNonceReconfigure(void)
-{
-}
-
-static void
-authenticateDigestNonceCacheCleanup(void *data)
-{
-    /*
-     * We walk the hash by nonceb64 as that is the unique key we
-     * use.  For big hash tables we could consider stepping through
-     * the cache, 100/200 entries at a time. Lets see how it flies
-     * first.
-     */
-    digest_nonce_h *nonce;
-    debug(29, 3) ("authenticateDigestNonceCacheCleanup: Cleaning the nonce cache now\n");
-    debug(29, 3) ("authenticateDigestNonceCacheCleanup: Current time: %ld\n",
-	(long int)current_time.tv_sec);
-    hash_first(digest_nonce_cache);
-    while ((nonce = ((digest_nonce_h *) hash_next(digest_nonce_cache)))) {
-	debug(29, 3) ("authenticateDigestNonceCacheCleanup: nonce entry  : %p '%s'\n", nonce, (char *)nonce->hash.key);
-	debug(29, 4) ("authenticateDigestNonceCacheCleanup: Creation time: %ld\n", (long int)nonce->noncedata.creationtime);
-	if (authDigestNonceIsStale(nonce)) {
-	    debug(29, 4) ("authenticateDigestNonceCacheCleanup: Removing nonce %s from cache due to timeout.\n", (char *)nonce->hash.key);
-	    assert(nonce->flags.incache);
-	    /* invalidate nonce so future requests fail */
-	    nonce->flags.valid = 0;
-	    /* if it is tied to a auth_user, remove the tie */
-	    authDigestNonceUserUnlink(nonce);
-	    authDigestNoncePurge(nonce);
-	}
-    }
-    debug(29, 3) ("authenticateDigestNonceCacheCleanup: Finished cleaning the nonce cache.\n");
-    if (authenticateDigestActive())
-	eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1);
-}
-
-static void
-authDigestNonceLink(digest_nonce_h * nonce)
-{
-    assert(nonce != NULL);
-    nonce->references++;
-    debug(29, 9) ("authDigestNonceLink: nonce '%p' now at '%d'.\n", nonce, nonce->references);
-}
-
-#if NOT_USED
-static int
-authDigestNonceLinks(digest_nonce_h * nonce)
-{
-    if (!nonce)
-	return -1;
-    return nonce->references;
-}
-#endif
-
-static void
-authDigestNonceUnlink(digest_nonce_h * nonce)
-{
-    assert(nonce != NULL);
-    if (nonce->references > 0) {
-	nonce->references--;
-    } else {
-	debug(29, 1) ("authDigestNonceUnlink; Attempt to lower nonce %p refcount below 0!\n", nonce);
-    }
-    debug(29, 9) ("authDigestNonceUnlink: nonce '%p' now at '%d'.\n", nonce, nonce->references);
-    if (nonce->references == 0)
-	authenticateDigestNonceDelete(nonce);
-}
-
-static const char *
-authenticateDigestNonceNonceb64(digest_nonce_h * nonce)
-{
-    if (!nonce)
-	return NULL;
-    return nonce->hash.key;
-}
-
-static digest_nonce_h *
-authenticateDigestNonceFindNonce(const char *nonceb64)
-{
-    digest_nonce_h *nonce = NULL;
-    if (nonceb64 == NULL)
-	return NULL;
-    debug(29, 9) ("authDigestNonceFindNonce:looking for nonceb64 '%s' in the nonce cache.\n", nonceb64);
-    nonce = hash_lookup(digest_nonce_cache, nonceb64);
-    if ((nonce == NULL) || (strcmp(nonce->hash.key, nonceb64)))
-	return NULL;
-    debug(29, 9) ("authDigestNonceFindNonce: Found nonce '%p'\n", nonce);
-    return nonce;
-}
-
-static int
-authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9])
-{
-    unsigned long intnc;
-    /* do we have a nonce ? */
-    if (!nonce)
-	return 0;
-    intnc = strtol(nc, NULL, 16);
-    if ((digestConfig->NonceStrictness && intnc != nonce->nc + 1) ||
-	intnc < nonce->nc + 1) {
-	debug(29, 4) ("authDigestNonceIsValid: Nonce count doesn't match\n");
-	nonce->flags.valid = 0;
-	return 0;
-    }
-    /* has it already been invalidated ? */
-    if (!nonce->flags.valid) {
-	debug(29, 4) ("authDigestNonceIsValid: Nonce already invalidated\n");
-	return 0;
-    }
-    /* seems ok */
-    /* increment the nonce count - we've already checked that intnc is a
-     *  valid representation for us, so we don't need the test here.
-     */
-    nonce->nc = intnc;
-    return -1;
-}
-
-static int
-authDigestNonceIsStale(digest_nonce_h * nonce)
-{
-    /* do we have a nonce ? */
-    if (!nonce)
-	return -1;
-    /* has it's max duration expired? */
-    if (nonce->noncedata.creationtime + digestConfig->noncemaxduration < current_time.tv_sec) {
-	debug(29, 4) ("authDigestNonceIsStale: Nonce is too old. %ld %d %ld\n", (long int)nonce->noncedata.creationtime, (int)digestConfig->noncemaxduration, (long int)current_time.tv_sec);
-	nonce->flags.valid = 0;
-	return -1;
-    }
-    if (nonce->nc > 99999998) {
-	debug(29, 4) ("authDigestNonceIsStale: Nonce count overflow\n");
-	nonce->flags.valid = 0;
-	return -1;
-    }
-    if (nonce->nc > digestConfig->noncemaxuses) {
-	debug(29, 4) ("authDigestNoncelastRequest: Nonce count over user limit\n");
-	nonce->flags.valid = 0;
-	return -1;
-    }
-    /* seems ok */
-    return 0;
-}
-
-/* return -1 if the digest will be stale on the next request */
-static int
-authDigestNonceLastRequest(digest_nonce_h * nonce)
-{
-    if (!nonce)
-	return -1;
-    if (nonce->nc == 99999997) {
-	debug(29, 4) ("authDigestNoncelastRequest: Nonce count about to overflow\n");
-	return -1;
-    }
-    if (nonce->nc >= digestConfig->noncemaxuses - 1) {
-	debug(29, 4) ("authDigestNoncelastRequest: Nonce count about to hit user limit\n");
-	return -1;
-    }
-    /* and other tests are possible. */
-    return 0;
-}
-
-static void
-authDigestNoncePurge(digest_nonce_h * nonce)
-{
-    if (!nonce)
-	return;
-    if (!nonce->flags.incache)
-	return;
-    hash_remove_link(digest_nonce_cache, &nonce->hash);
-    nonce->flags.incache = 0;
-    /* the cache's link */
-    authDigestNonceUnlink(nonce);
-}
-
-/* USER related functions */
-
-
-#if NOT_USED
-static int
-authDigestUsercmpname(digest_user_h * u1, digest_user_h * u2)
-{
-    return strcmp(u1->username, u2->username);
-}
-#endif
-
-static auth_user_t *
-authDigestUserFindUsername(const char *username)
-{
-    auth_user_hash_pointer *usernamehash;
-    auth_user_t *auth_user;
-    debug(29, 9) ("authDigestUserFindUsername: Looking for user '%s'\n", username);
-    if (username && (usernamehash = hash_lookup(proxy_auth_username_cache, username))) {
-	while ((usernamehash->auth_user->auth_type != AUTH_DIGEST) &&
-	    (usernamehash->next))
-	    usernamehash = usernamehash->next;
-	auth_user = NULL;
-	if (usernamehash->auth_user->auth_type == AUTH_DIGEST) {
-	    auth_user = usernamehash->auth_user;
-	}
-	return auth_user;
-    }
-    return NULL;
-}
-
-static digest_user_h *
-authDigestUserNew(void)
-{
-    return memPoolAlloc(digest_user_pool);
-}
-
-static void
-authDigestUserSetup(void)
-{
-    if (!digest_user_pool)
-	digest_user_pool = memPoolCreate("Digest Scheme User Data", sizeof(digest_user_h));
-}
-
-static void
-authDigestUserShutdown(void)
-{
-    /*
-     * Future work: the auth framework could flush it's cache 
-     */
-    auth_user_hash_pointer *usernamehash;
-    auth_user_t *auth_user;
-    hash_first(proxy_auth_username_cache);
-    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
-	auth_user = usernamehash->auth_user;
-	if (authscheme_list[auth_user->auth_module - 1].typestr &&
-	    strcmp(authscheme_list[auth_user->auth_module - 1].typestr, "digest") == 0)
-	    /* it's digest */
-	    authenticateAuthUserUnlock(auth_user);
-    }
-    if (digest_user_pool) {
-	assert(memPoolInUseCount(digest_user_pool) == 0);
-	memPoolDestroy(&digest_user_pool);
-    }
-}
-
-
-/* request related functions */
-
-/* delete the digest reuqest structure. Does NOT delete related structures */
-static void
-authDigestRequestDelete(digest_request_h * digest_request)
-{
-    if (digest_request->nonceb64)
-	xfree(digest_request->nonceb64);
-    if (digest_request->cnonce)
-	xfree(digest_request->cnonce);
-    if (digest_request->realm)
-	xfree(digest_request->realm);
-    if (digest_request->pszPass)
-	xfree(digest_request->pszPass);
-    if (digest_request->algorithm)
-	xfree(digest_request->algorithm);
-    if (digest_request->pszMethod)
-	xfree(digest_request->pszMethod);
-    if (digest_request->qop)
-	xfree(digest_request->qop);
-    if (digest_request->uri)
-	xfree(digest_request->uri);
-    if (digest_request->response)
-	xfree(digest_request->response);
-    if (digest_request->nonce)
-	authDigestNonceUnlink(digest_request->nonce);
-    memPoolFree(digest_request_pool, digest_request);
-}
-
-static void
-authDigestAURequestFree(auth_user_request_t * auth_user_request)
-{
-    if (auth_user_request->scheme_data != NULL)
-	authDigestRequestDelete((digest_request_h *) auth_user_request->scheme_data);
-}
-
-static digest_request_h *
-authDigestRequestNew(void)
-{
-    digest_request_h *tmp;
-    tmp = memPoolAlloc(digest_request_pool);
-    assert(tmp != NULL);
-    return tmp;
-}
-
-static void
-authDigestRequestSetup(void)
-{
-    if (!digest_request_pool)
-	digest_request_pool = memPoolCreate("Digest Scheme Request Data", sizeof(digest_request_h));
-}
-
-static void
-authDigestRequestShutdown(void)
-{
-    /* No requests should be in progress when we get here */
-    if (digest_request_pool) {
-	assert(memPoolInUseCount(digest_request_pool) == 0);
-	memPoolDestroy(&digest_request_pool);
-    }
-}
-
-
-static void
-authDigestDone(void)
-{
-    if (digestauthenticators)
-	helperShutdown(digestauthenticators);
-    authdigest_initialised = 0;
-    if (!shutting_down) {
-	authenticateDigestNonceReconfigure();
-	return;
-    }
-    if (digestauthenticators) {
-	helperFree(digestauthenticators);
-	digestauthenticators = NULL;
-    }
-    authDigestRequestShutdown();
-    authDigestUserShutdown();
-    authenticateDigestNonceShutdown();
-    debug(29, 2) ("authenticateDigestDone: Digest authentication shut down.\n");
-}
-
-static void
-authDigestCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
-{
-    auth_digest_config *config = scheme->scheme_data;
-    wordlist *list = config->authenticate;
-    debug(29, 9) ("authDigestCfgDump: Dumping configuration\n");
-    storeAppendPrintf(entry, "%s %s", name, "digest");
-    while (list != NULL) {
-	storeAppendPrintf(entry, " %s", list->key);
-	list = list->next;
-    }
-    storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s nonce_max_count %d\n%s %s nonce_max_duration %d seconds\n%s %s nonce_garbage_interval %d seconds\n",
-	name, "digest", config->digestAuthRealm,
-	name, "digest", config->authenticateChildren,
-	name, "digest", config->noncemaxuses,
-	name, "digest", (int)config->noncemaxduration,
-	name, "digest", (int)config->nonceGCInterval);
-}
-
-void
-authSchemeSetup_digest(authscheme_entry_t * authscheme)
-{
-    assert(!authdigest_initialised);
-    authscheme->Active = authenticateDigestActive;
-    authscheme->configured = authDigestConfigured;
-    authscheme->parse = authDigestParse;
-    authscheme->freeconfig = authDigestFreeConfig;
-    authscheme->dump = authDigestCfgDump;
-    authscheme->init = authDigestInit;
-    authscheme->authAuthenticate = authenticateDigestAuthenticateUser;
-    authscheme->authenticated = authDigestAuthenticated;
-    authscheme->authFixHeader = authenticateDigestFixHeader;
-    authscheme->FreeUser = authenticateDigestUserFree;
-    authscheme->AddHeader = authDigestAddHeader;
-#if WAITING_FOR_TE
-    authscheme->AddTrailer = authDigestAddTrailer;
-#endif
-    authscheme->authStart = authenticateDigestStart;
-    authscheme->authStats = authenticateDigestStats;
-    authscheme->authUserUsername = authenticateDigestUsername;
-    authscheme->getdirection = authenticateDigestDirection;
-    authscheme->oncloseconnection = NULL;
-    authscheme->decodeauth = authenticateDigestDecodeAuth;
-    authscheme->donefunc = authDigestDone;
-    authscheme->requestFree = authDigestAURequestFree;
-    authscheme->authConnLastHeader = NULL;
-}
-
-static int
-authenticateDigestActive(void)
-{
-    return (authdigest_initialised == 1) ? 1 : 0;
-}
-static int
-authDigestConfigured(void)
-{
-    if ((digestConfig != NULL) && (digestConfig->authenticate != NULL) &&
-	(digestConfig->authenticateChildren != 0) &&
-	(digestConfig->digestAuthRealm != NULL) && (digestConfig->noncemaxduration > -1))
-	return 1;
-    return 0;
-}
-
-static int
-authDigestAuthenticated(auth_user_request_t * auth_user_request)
-{
-    digest_user_h *digest_user = auth_user_request->auth_user->scheme_data;
-    if (digest_user->flags.credentials_ok == 1)
-	return 1;
-    else
-	return 0;
-}
-
-/* log a digest user in
- */
-static void
-authenticateDigestAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
-{
-    auth_user_t *auth_user;
-    digest_request_h *digest_request;
-    digest_user_h *digest_user;
-
-    HASHHEX SESSIONKEY;
-    HASHHEX HA2 = "";
-    HASHHEX Response;
-
-    assert(auth_user_request->auth_user != NULL);
-    auth_user = auth_user_request->auth_user;
-
-    assert(auth_user->scheme_data != NULL);
-    digest_user = auth_user->scheme_data;
-
-    /* if the check has corrupted the user, just return */
-    if (digest_user->flags.credentials_ok == 3) {
-	return;
-    }
-    assert(auth_user_request->scheme_data != NULL);
-    digest_request = auth_user_request->scheme_data;
-
-    /* do we have the HA1 */
-    if (!digest_user->HA1created) {
-	digest_user->flags.credentials_ok = 2;
-	return;
-    }
-    if (digest_request->nonce == NULL) {
-	/* this isn't a nonce we issued */
-	/* TODO: record breaks in authentication at the request level 
-	 * This is probably best done with support changes at the
-	 * auth_rewrite level -RBC
-	 * and can wait for auth_rewrite V2.
-	 * RBC 20010902 further note: flags.credentials ok is now
-	 * a local scheme flag, so we can move this to the request
-	 * level at any time.
-	 */
-	digest_user->flags.credentials_ok = 3;
-	return;
-    }
-    DigestCalcHA1(digest_request->algorithm, NULL, NULL, NULL,
-	authenticateDigestNonceNonceb64(digest_request->nonce),
-	digest_request->cnonce,
-	digest_user->HA1, SESSIONKEY);
-    DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
-	digest_request->nc, digest_request->cnonce, digest_request->qop,
-	RequestMethodStr[request->method], digest_request->uri, HA2, Response);
-
-    debug(29, 9) ("\nResponse = '%s'\n"
-	"squid is = '%s'\n", digest_request->response, Response);
-
-    if (strcasecmp(digest_request->response, Response)) {
-	digest_user->flags.credentials_ok = 3;
-	return;
-    }
-    digest_user->flags.credentials_ok = 1;
-    /* password was checked and did match */
-    debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n",
-	digest_user->username);
-
-    /* auth_user is now linked, we reset these values
-     * after external auth occurs anyway */
-    auth_user->expiretime = current_time.tv_sec;
-    return;
-}
-
-static int
-authenticateDigestDirection(auth_user_request_t * auth_user_request)
-{
-    digest_request_h *digest_request;
-    digest_user_h *digest_user = auth_user_request->auth_user->scheme_data;
-    /* null auth_user is checked for by authenticateDirection */
-    switch (digest_user->flags.credentials_ok) {
-    case 0:			/* not checked */
-	return -1;
-    case 1:			/* checked & ok */
-	digest_request = auth_user_request->scheme_data;
-	if (authDigestNonceIsStale(digest_request->nonce))
-	    /* send stale response to the client agent */
-	    return -2;
-	return 0;
-    case 2:			/* partway through checking. */
-	return -1;
-    case 3:			/* authentication process failed. */
-	return -2;
-    }
-    return -2;
-}
-
-/* add the [proxy]authorisation header */
-static void
-authDigestAddHeader(auth_user_request_t * auth_user_request, HttpReply * rep, int accel)
-{
-    int type;
-    digest_request_h *digest_request;
-    if (!auth_user_request)
-	return;
-    digest_request = auth_user_request->scheme_data;
-    /* don't add to authentication error pages */
-    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
-	|| (accel && rep->sline.status == HTTP_UNAUTHORIZED))
-	return;
-    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
-
-#if WAITING_FOR_TE
-    /* test for http/1.1 transfer chunked encoding */
-    if (chunkedtest)
-	return;
-#endif
-
-    if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) {
-	digest_request->flags.authinfo_sent = 1;
-	debug(29, 9) ("authDigestAddHead: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce));
-	httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce));
-    }
-}
-
-#if WAITING_FOR_TE
-/* add the [proxy]authorisation header */
-static void
-authDigestAddTrailer(auth_user_request_t * auth_user_request, HttpReply * rep, int accel)
-{
-    int type;
-    digest_request_h *digest_request;
-    if (!auth_user_request)
-	return;
-    digest_request = auth_user_request->scheme_data;
-    /* has the header already been send? */
-    if (digest_request->flags.authinfo_sent)
-	return;
-    /* don't add to authentication error pages */
-    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
-	|| (accel && rep->sline.status == HTTP_UNAUTHORIZED))
-	return;
-    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
-
-    if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) {
-	debug(29, 9) ("authDigestAddTrailer: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce));
-	httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce));
-    }
-}
-#endif
-
-/* add the [www-|Proxy-]authenticate header on a 407 or 401 reply */
-void
-authenticateDigestFixHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
-{
-    digest_request_h *digest_request;
-    int stale = 0;
-    digest_nonce_h *nonce = authenticateDigestNonceNew();
-    if (auth_user_request && authDigestAuthenticated(auth_user_request) && auth_user_request->scheme_data) {
-	digest_request = auth_user_request->scheme_data;
-	stale = authDigestNonceIsStale(digest_request->nonce);
-    }
-    if (digestConfig->authenticate) {
-	debug(29, 9) ("authenticateFixHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s\n", type, digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false");
-	/* in the future, for WWW auth we may want to support the domain entry */
-	httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s", digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false");
-    }
-}
-
-static void
-authenticateDigestUserFree(auth_user_t * auth_user)
-{
-    digest_user_h *digest_user = auth_user->scheme_data;
-    dlink_node *link, *tmplink;
-    debug(29, 9) ("authenticateDigestFreeUser: Clearing Digest scheme data\n");
-    if (!digest_user)
-	return;
-    safe_free(digest_user->username);
-
-    link = digest_user->nonces.head;
-    while (link) {
-	tmplink = link;
-	link = link->next;
-	dlinkDelete(tmplink, &digest_user->nonces);
-	authDigestNoncePurge(tmplink->data);
-	authDigestNonceUnlink(tmplink->data);
-	dlinkNodeDelete(tmplink);
-    }
-
-    memPoolFree(digest_user_pool, auth_user->scheme_data);
-    auth_user->scheme_data = NULL;
-}
-
-static void
-authenticateDigestHandleReply(void *data, char *reply)
-{
-    authenticateStateData *r = data;
-    auth_user_request_t *auth_user_request;
-    digest_request_h *digest_request;
-    digest_user_h *digest_user;
-    char *t = NULL;
-    void *cbdata;
-    debug(29, 9) ("authenticateDigestHandleReply: {%s}\n", reply ? reply : "<NULL>");
-    if (reply) {
-	if ((t = strchr(reply, ' ')))
-	    *t = '\0';
-	if (*reply == '\0')
-	    reply = NULL;
-    }
-    assert(r->auth_user_request != NULL);
-    auth_user_request = r->auth_user_request;
-    assert(auth_user_request->scheme_data != NULL);
-    digest_request = auth_user_request->scheme_data;
-    digest_user = auth_user_request->auth_user->scheme_data;
-    if (reply && (strncasecmp(reply, "ERR", 3) == 0))
-	digest_user->flags.credentials_ok = 3;
-    else {
-	CvtBin(reply, digest_user->HA1);
-	digest_user->HA1created = 1;
-    }
-    if (cbdataReferenceValidDone(r->data, &cbdata))
-	r->handler(cbdata, NULL);
-    authenticateStateFree(r);
-}
-
-/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
- * config file */
-static void
-authDigestInit(authScheme * scheme)
-{
-    static int init = 0;
-    if (digestConfig->authenticate) {
-	authDigestUserSetup();
-	authDigestRequestSetup();
-	authenticateDigestNonceSetup();
-	authdigest_initialised = 1;
-	if (digestauthenticators == NULL)
-	    digestauthenticators = helperCreate("digestauthenticator");
-	digestauthenticators->cmdline = digestConfig->authenticate;
-	digestauthenticators->n_to_start = digestConfig->authenticateChildren;
-	digestauthenticators->ipc_type = IPC_STREAM;
-	helperOpenServers(digestauthenticators);
-	if (!init) {
-	    cachemgrRegister("digestauthenticator", "User Authenticator Stats",
-		authenticateDigestStats, 0, 1);
-	    init++;
-	}
-	CBDATA_INIT_TYPE(authenticateStateData);
-    }
-}
-
-
-/* free any allocated configuration details */
-void
-authDigestFreeConfig(authScheme * scheme)
-{
-    if (digestConfig == NULL)
-	return;
-    assert(digestConfig == scheme->scheme_data);
-    if (digestConfig->authenticate)
-	wordlistDestroy(&digestConfig->authenticate);
-    if (digestConfig->digestAuthRealm)
-	safe_free(digestConfig->digestAuthRealm);
-    xfree(digestConfig);
-    digestConfig = NULL;
-}
-
-static void
-authDigestParse(authScheme * scheme, int n_configured, char *param_str)
-{
-    if (scheme->scheme_data == NULL) {
-	assert(digestConfig == NULL);
-	/* this is the first param to be found */
-	scheme->scheme_data = xmalloc(sizeof(auth_digest_config));
-	memset(scheme->scheme_data, 0, sizeof(auth_digest_config));
-	digestConfig = scheme->scheme_data;
-	digestConfig->authenticateChildren = 5;
-	/* 5 minutes */
-	digestConfig->nonceGCInterval = 5 * 60;
-	/* 30 minutes */
-	digestConfig->noncemaxduration = 30 * 60;
-	/* 50 requests */
-	digestConfig->noncemaxuses = 50;
-	/* strict nonce count behaviour */
-	digestConfig->NonceStrictness = 1;
-    }
-    digestConfig = scheme->scheme_data;
-    if (strcasecmp(param_str, "program") == 0) {
-	if (digestConfig->authenticate)
-	    wordlistDestroy(&digestConfig->authenticate);
-	parse_wordlist(&digestConfig->authenticate);
-	requirePathnameExists("authparam digest program", digestConfig->authenticate->key);
-    } else if (strcasecmp(param_str, "children") == 0) {
-	parse_int(&digestConfig->authenticateChildren);
-    } else if (strcasecmp(param_str, "realm") == 0) {
-	parse_eol(&digestConfig->digestAuthRealm);
-    } else if (strcasecmp(param_str, "nonce_garbage_interval") == 0) {
-	parse_time_t(&digestConfig->nonceGCInterval);
-    } else if (strcasecmp(param_str, "nonce_max_duration") == 0) {
-	parse_time_t(&digestConfig->noncemaxduration);
-    } else if (strcasecmp(param_str, "nonce_max_count") == 0) {
-	parse_int(&digestConfig->noncemaxuses);
-    } else if (strcasecmp(param_str, "nonce_strictness") == 0) {
-        parse_onoff(&digestConfig->NonceStrictness);
-    } else {
-	debug(28, 0) ("unrecognised digest auth scheme parameter '%s'\n", param_str);
-    }
-}
-
-
-static void
-authenticateDigestStats(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "Digest Authenticator Statistics:\n");
-    helperStats(sentry, digestauthenticators);
-}
-
-/* NonceUserUnlink: remove the reference to auth_user and unlink the node from the list */
-
-static void
-authDigestNonceUserUnlink(digest_nonce_h * nonce)
-{
-    digest_user_h *digest_user;
-    dlink_node *link, *tmplink;
-    if (!nonce)
-	return;
-    if (!nonce->auth_user)
-	return;
-    digest_user = nonce->auth_user->scheme_data;
-    /* unlink from the user list. Yes we're crossing structures but this is the only 
-     * time this code is needed
-     */
-    link = digest_user->nonces.head;
-    while (link) {
-	tmplink = link;
-	link = link->next;
-	if (tmplink->data == nonce) {
-	    dlinkDelete(tmplink, &digest_user->nonces);
-	    authDigestNonceUnlink(tmplink->data);
-	    dlinkNodeDelete(tmplink);
-	    link = NULL;
-	}
-    }
-    /* this reference to auth_user was not locked because freeeing the auth_user frees
-     * the nonce too. 
-     */
-    nonce->auth_user = NULL;
-}
-
-/* authDigestUserLinkNonce: add a nonce to a given user's struct */
-
-static void
-authDigestUserLinkNonce(auth_user_t * auth_user, digest_nonce_h * nonce)
-{
-    dlink_node *node;
-    digest_user_h *digest_user;
-    if (!auth_user || !nonce)
-	return;
-    if (!auth_user->scheme_data)
-	return;
-    digest_user = auth_user->scheme_data;
-    node = digest_user->nonces.head;
-    while (node && (node->data != nonce))
-	node = node->next;
-    if (node)
-	return;
-    node = dlinkNodeNew();
-    dlinkAddTail(nonce, node, &digest_user->nonces);
-    authDigestNonceLink(nonce);
-    /* ping this nonce to this auth user */
-    assert((nonce->auth_user == NULL) || (nonce->auth_user = auth_user));
-    /* we don't lock this reference because removing the auth_user removes the 
-     * hash too. Of course if that changes we're stuffed so read the code huh?
-     */
-    nonce->auth_user = auth_user;
-}
-
-/* authenticateDigestUsername: return a pointer to the username in the */
-static char *
-authenticateDigestUsername(auth_user_t * auth_user)
-{
-    digest_user_h *digest_user = auth_user->scheme_data;
-    if (digest_user)
-	return digest_user->username;
-    return NULL;
-}
-
-/* setup the necessary info to log the username */
-static void
-authDigestLogUsername(auth_user_request_t * auth_user_request, char *username)
-{
-    auth_user_t *auth_user;
-    digest_user_h *digest_user;
-    dlink_node *node;
-
-    /* log the username */
-    debug(29, 9) ("authBasicDecodeAuth: Creating new user for logging '%s'\n", username);
-    /* new auth_user */
-    auth_user = authenticateAuthUserNew("digest");
-    /* new scheme data */
-    digest_user = authDigestUserNew();
-    /* save the credentials */
-    digest_user->username = username;
-    /* link the scheme data in */
-    auth_user->scheme_data = digest_user;
-    /* set the auth_user type */
-    auth_user->auth_type = AUTH_BROKEN;
-    /* link the request to the user */
-    auth_user_request->auth_user = auth_user;
-    /* lock for the auth_user_request link */
-    authenticateAuthUserLock(auth_user);
-    node = dlinkNodeNew();
-    dlinkAdd(auth_user_request, node, &auth_user->requests);
-}
-
-/*
- * Decode a Digest [Proxy-]Auth string, placing the results in the passed
- * Auth_user structure.
- */
-
-static void
-authenticateDigestDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
-{
-    String temp;
-    const char *item;
-    const char *p;
-    const char *pos = NULL;
-    char *username = NULL;
-    digest_nonce_h *nonce;
-    int ilen;
-    digest_request_h *digest_request;
-    digest_user_h *digest_user;
-    auth_user_t *auth_user;
-    dlink_node *node;
-
-    debug(29, 9) ("authenticateDigestDecodeAuth: beginning\n");
-    assert(auth_user_request != NULL);
-
-    digest_request = authDigestRequestNew();
-
-    /* trim DIGEST from string */
-    while (!xisspace(*proxy_auth))
-	proxy_auth++;
-
-    /* Trim leading whitespace before decoding */
-    while (xisspace(*proxy_auth))
-	proxy_auth++;
-
-    stringInit(&temp, proxy_auth);
-    while (strListGetItem(&temp, ',', &item, &ilen, &pos)) {
-	if ((p = strchr(item, '=')) && (p - item < ilen))
-	    ilen = p++ - item;
-	if (!strncmp(item, "username", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    /* quote mark */
-	    p++;
-	    username = xstrndup(p, strchr(p, '"') + 1 - p);
-	    debug(29, 9) ("authDigestDecodeAuth: Found Username '%s'\n", username);
-	} else if (!strncmp(item, "realm", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    /* quote mark */
-	    p++;
-	    digest_request->realm = xstrndup(p, strchr(p, '"') + 1 - p);
-	    debug(29, 9) ("authDigestDecodeAuth: Found realm '%s'\n", digest_request->realm);
-	} else if (!strncmp(item, "qop", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    if (*p == '\"')
-	        /* quote mark */
-	        p++;
-	    digest_request->qop = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}") + 1);
-	    debug(29, 9) ("authDigestDecodeAuth: Found qop '%s'\n", digest_request->qop);
-	} else if (!strncmp(item, "algorithm", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    if (*p == '\"')
-	        /* quote mark */
-	        p++;
-	    digest_request->algorithm = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}")+1);
-	    debug(29, 9) ("authDigestDecodeAuth: Found algorithm '%s'\n", digest_request->algorithm);
-	} else if (!strncmp(item, "uri", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    /* quote mark */
-	    p++;
-	    digest_request->uri = xstrndup(p, strchr(p, '"') + 1 - p);
-	    debug(29, 9) ("authDigestDecodeAuth: Found uri '%s'\n", digest_request->uri);
-	} else if (!strncmp(item, "nonce", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    /* quote mark */
-	    p++;
-	    digest_request->nonceb64 = xstrndup(p, strchr(p, '"') + 1 - p);
-	    debug(29, 9) ("authDigestDecodeAuth: Found nonce '%s'\n", digest_request->nonceb64);
-	} else if (!strncmp(item, "nc", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    xstrncpy(digest_request->nc, p, 9);
-	    debug(29, 9) ("authDigestDecodeAuth: Found noncecount '%s'\n", digest_request->nc);
-	} else if (!strncmp(item, "cnonce", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    /* quote mark */
-	    p++;
-	    digest_request->cnonce = xstrndup(p, strchr(p, '"') + 1 - p);
-	    debug(29, 9) ("authDigestDecodeAuth: Found cnonce '%s'\n", digest_request->cnonce);
-	} else if (!strncmp(item, "response", ilen)) {
-	    /* white space */
-	    while (xisspace(*p))
-		p++;
-	    /* quote mark */
-	    p++;
-	    digest_request->response = xstrndup(p, strchr(p, '"') + 1 - p);
-	    debug(29, 9) ("authDigestDecodeAuth: Found response '%s'\n", digest_request->response);
-	}
-    }
-    stringClean(&temp);
-
-
-    /* now we validate the data given to us */
-
-    /*
-     * TODO: on invalid parameters we should return 400, not 407.
-     * Find some clean way of doing this. perhaps return a valid
-     * struct, and set the direction to clientwards combined with
-     * a change to the clientwards handling code (ie let the
-     * clientwards call set the error type (but limited to known
-     * correct values - 400/401/407
-     */
-
-    /* first the NONCE count */
-    if (digest_request->cnonce && strlen(digest_request->nc) != 8) {
-	debug(29, 4) ("authenticateDigestDecode: nonce count length invalid\n");
-	authDigestLogUsername(auth_user_request, username);
-
-	/* we don't need the scheme specific data anymore */
-	authDigestRequestDelete(digest_request);
-	auth_user_request->scheme_data = NULL;
-	return;
-    }
-    /* now the nonce */
-    nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64);
-    if ((nonce == NULL) || !(authDigestNonceIsValid(nonce, digest_request->nc))) {
-	/* we couldn't find a matching nonce! */
-	debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce recieved\n");
-	authDigestLogUsername(auth_user_request, username);
-
-	/* we don't need the scheme specific data anymore */
-	authDigestRequestDelete(digest_request);
-	auth_user_request->scheme_data = NULL;
-	return;
-    }
-    digest_request->nonce = nonce;
-    authDigestNonceLink(nonce);
-
-    /* check the qop is what we expected. Note that for compatability with 
-     * RFC 2069 we should support a missing qop. Tough. */
-    if (!digest_request->qop || strcmp(digest_request->qop, QOP_AUTH)) {
-	/* we recieved a qop option we didn't send */
-	debug(29, 4) ("authenticateDigestDecode: Invalid qop option recieved\n");
-	authDigestLogUsername(auth_user_request, username);
-
-	/* we don't need the scheme specific data anymore */
-	authDigestRequestDelete(digest_request);
-	auth_user_request->scheme_data = NULL;
-	return;
-    }
-    /* we can't check the URI just yet. We'll check it in the
-     * authenticate phase */
-
-    /* is the response the correct length? */
-
-    if (!digest_request->response || strlen(digest_request->response) != 32) {
-	debug(29, 4) ("authenticateDigestDecode: Response length invalid\n");
-	authDigestLogUsername(auth_user_request, username);
-
-	/* we don't need the scheme specific data anymore */
-	authDigestRequestDelete(digest_request);
-	auth_user_request->scheme_data = NULL;
-	return;
-    }
-    /* do we have a username ? */
-    if (!username || username[0] == '\0') {
-	debug(29, 4) ("authenticateDigestDecode: Empty or not present username\n");
-	authDigestLogUsername(auth_user_request, username);
-
-	/* we don't need the scheme specific data anymore */
-	authDigestRequestDelete(digest_request);
-	auth_user_request->scheme_data = NULL;
-	return;
-    }
-    /* check that we're not being hacked / the username hasn't changed */
-    if (nonce->auth_user && strcmp(username, authenticateUserUsername(nonce->auth_user))) {
-	debug(29, 4) ("authenticateDigestDecode: Username for the nonce does not equal the username for the request\n");
-	authDigestLogUsername(auth_user_request, username);
-
-	/* we don't need the scheme specific data anymore */
-	authDigestRequestDelete(digest_request);
-	auth_user_request->scheme_data = NULL;
-	return;
-    }
-    /* if we got a qop, did we get a cnonce or did we get a cnonce wihtout a qop? */
-    if ((digest_request->qop && !digest_request->cnonce)
-	|| (!digest_request->qop && digest_request->cnonce)) {
-	debug(29, 4) ("authenticateDigestDecode: qop without cnonce, or vice versa!\n");
-	authDigestLogUsername(auth_user_request, username);
-
-	/* we don't need the scheme specific data anymore */
-	authDigestRequestDelete(digest_request);
-	auth_user_request->scheme_data = NULL;
-	return;
-    }
-    /* check the algorithm is present and supported */
-    if (!digest_request->algorithm)
-        digest_request->algorithm = xstrndup ("MD5", 4);
-    else if (strcmp(digest_request->algorithm, "MD5")
-	&& strcmp(digest_request->algorithm, "MD5-sess")) {
-	debug(29, 4) ("authenticateDigestDecode: invalid algorithm specified!\n");
-	authDigestLogUsername(auth_user_request, username);
-
-	/* we don't need the scheme specific data anymore */
-	authDigestRequestDelete(digest_request);
-	auth_user_request->scheme_data = NULL;
-	return;
-    }
-    /* the method we'll check at the authenticate step as well */
-
-
-    /* we don't send or parse opaques. Ok so we're flexable ... */
-
-    /* find the user */
-
-    if ((auth_user = authDigestUserFindUsername(username)) == NULL) {
-	/* the user doesn't exist in the username cache yet */
-	debug(29, 9) ("authDigestDecodeAuth: Creating new digest user '%s'\n", username);
-	/* new auth_user */
-	auth_user = authenticateAuthUserNew("digest");
-	/* new scheme user data */
-	digest_user = authDigestUserNew();
-	/* save the username */
-	digest_user->username = username;
-	/* link the primary struct in */
-	auth_user->scheme_data = digest_user;
-	/* set the user type */
-	auth_user->auth_type = AUTH_DIGEST;
-	/* this auth_user struct is the one to get added to the
-	 * username cache */
-	/* store user in hash's */
-	authenticateUserNameCacheAdd(auth_user);
-	/* 
-	 * Add the digest to the user so we can tell if a hacking
-	 * or spoofing attack is taking place. We do this by assuming
-	 * the user agent won't change user name without warning.
-	 */
-	authDigestUserLinkNonce(auth_user, nonce);
-    } else {
-	debug(29, 9) ("authDigestDecodeAuth: Found user '%s' in the user cache as '%p'\n", username, auth_user);
-	digest_user = auth_user->scheme_data;
-	xfree(username);
-    }
-    /*link the request and the user */
-    auth_user_request->auth_user = auth_user;
-    auth_user_request->scheme_data = digest_request;
-    /* lock for the request link */
-    authenticateAuthUserLock(auth_user);
-    node = dlinkNodeNew();
-    dlinkAdd(auth_user_request, node, &auth_user->requests);
-
-    debug(29, 9) ("username = '%s'\nrealm = '%s'\nqop = '%s'\nalgorithm = '%s'\nuri = '%s'\nnonce = '%s'\nnc = '%s'\ncnonce = '%s'\nresponse = '%s'\ndigestnonce = '%p'\n",
-	digest_user->username, digest_request->realm,
-	digest_request->qop, digest_request->algorithm,
-	digest_request->uri, digest_request->nonceb64,
-	digest_request->nc, digest_request->cnonce, digest_request->response, nonce);
-
-    return;
-}
-
-/* send the initial data to a digest authenticator module */
-static void
-authenticateDigestStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
-{
-    authenticateStateData *r = NULL;
-    char buf[8192];
-    digest_request_h *digest_request;
-    digest_user_h *digest_user;
-    assert(auth_user_request);
-    assert(handler);
-    assert(auth_user_request->auth_user->auth_type == AUTH_DIGEST);
-    assert(auth_user_request->auth_user->scheme_data != NULL);
-    assert(auth_user_request->scheme_data != NULL);
-    digest_request = auth_user_request->scheme_data;
-    digest_user = auth_user_request->auth_user->scheme_data;
-    debug(29, 9) ("authenticateStart: '\"%s\":\"%s\"'\n", digest_user->username,
-	digest_request->realm);
-    if (digestConfig->authenticate == NULL) {
-	handler(data, NULL);
-	return;
-    }
-    r = cbdataAlloc(authenticateStateData);
-    r->handler = handler;
-    r->data = cbdataReference(data);
-    r->auth_user_request = auth_user_request;
-    snprintf(buf, 8192, "\"%s\":\"%s\"\n", digest_user->username, digest_request->realm);
-    helperSubmit(digestauthenticators, buf, authenticateDigestHandleReply, r);
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/auth/digest/auth_digest.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,1353 @@
+
+/*
+ * $Id: auth_digest.cc,v 1.1.2.1 2002/10/03 01:04:37 rbcollins Exp $
+ *
+ * DEBUG: section 29    Authenticator
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/* The functions in this file handle authentication.
+ * They DO NOT perform access control or auditing.
+ * See acl.c for access control and client_side.c for auditing */
+
+
+#include "squid.h"
+#include "rfc2617.h"
+#include "auth_digest.h"
+#include "authenticate.h"
+
+extern AUTHSSETUP authSchemeSetup_digest;
+
+static void
+authenticateStateFree(DigestAuthenticateStateData * r)
+{
+    cbdataFree(r);
+}
+
+/* Digest Scheme */
+
+static HLPCB authenticateDigestHandleReply;
+static AUTHSACTIVE authenticateDigestActive;
+static AUTHSADDHEADER authDigestAddHeader;
+#if WAITING_FOR_TE
+static AUTHSADDTRAILER authDigestAddTrailer;
+#endif
+static AUTHSAUTHED authDigestAuthenticated;
+static AUTHSAUTHUSER authenticateDigestAuthenticateUser;
+static AUTHSCONFIGURED authDigestConfigured;
+static AUTHSDIRECTION authenticateDigestDirection;
+static AUTHSDECODE authenticateDigestDecodeAuth;
+static AUTHSDUMP authDigestCfgDump;
+static AUTHSFIXERR authenticateDigestFixHeader;
+static AUTHSFREE authenticateDigestUserFree;
+static AUTHSFREECONFIG authDigestFreeConfig;
+static AUTHSINIT authDigestInit;
+static AUTHSPARSE authDigestParse;
+static AUTHSREQFREE authDigestAURequestFree;
+static AUTHSSTART authenticateDigestStart;
+static AUTHSSTATS authenticateDigestStats;
+static AUTHSUSERNAME authenticateDigestUsername;
+static AUTHSSHUTDOWN authDigestDone;
+
+static helper *digestauthenticators = NULL;
+
+static hash_table *digest_nonce_cache;
+
+static auth_digest_config *digestConfig = NULL;
+
+static int authdigest_initialised = 0;
+static MemPool *digest_user_pool = NULL;
+static MemPool *digest_request_pool = NULL;
+static MemPool *digest_nonce_pool = NULL;
+
+CBDATA_TYPE(DigestAuthenticateStateData);
+
+/*
+ *
+ * Nonce Functions
+ *
+ */
+
+static void authenticateDigestNonceCacheCleanup(void *data);
+static digest_nonce_h *authenticateDigestNonceFindNonce(const char *nonceb64);
+static digest_nonce_h *authenticateDigestNonceNew(void);
+static void authenticateDigestNonceDelete(digest_nonce_h * nonce);
+static void authenticateDigestNonceSetup(void);
+static void authenticateDigestNonceShutdown(void);
+static void authenticateDigestNonceReconfigure(void);
+static const char *authenticateDigestNonceNonceb64(digest_nonce_h * nonce);
+static int authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9]);
+static int authDigestNonceIsStale(digest_nonce_h * nonce);
+static void authDigestNonceEncode(digest_nonce_h * nonce);
+static int authDigestNonceLastRequest(digest_nonce_h * nonce);
+static void authDigestNonceLink(digest_nonce_h * nonce);
+static void authDigestNonceUnlink(digest_nonce_h * nonce);
+#if NOT_USED
+static int authDigestNonceLinks(digest_nonce_h * nonce);
+#endif
+static void authDigestNonceUserUnlink(digest_nonce_h * nonce);
+static void authDigestNoncePurge(digest_nonce_h * nonce);
+
+static void
+authDigestNonceEncode(digest_nonce_h * nonce)
+{
+    if (!nonce)
+	return;
+    if (nonce->hash.key)
+	xfree(nonce->hash.key);
+    nonce->hash.key = xstrdup(base64_encode_bin((char *) &(nonce->noncedata), sizeof(digest_nonce_data)));
+}
+
+static digest_nonce_h *
+authenticateDigestNonceNew(void)
+{
+    digest_nonce_h *newnonce = static_cast<digest_nonce_h *>(memPoolAlloc(digest_nonce_pool));
+    digest_nonce_h *temp;
+
+/* NONCE CREATION - NOTES AND REASONING. RBC 20010108
+ * === EXCERPT FROM RFC 2617 ===
+ * The contents of the nonce are implementation dependent. The quality
+ * of the implementation depends on a good choice. A nonce might, for
+ * example, be constructed as the base 64 encoding of
+ * 
+ * time-stamp H(time-stamp ":" ETag ":" private-key)
+ * 
+ * where time-stamp is a server-generated time or other non-repeating
+ * value, ETag is the value of the HTTP ETag header associated with
+ * the requested entity, and private-key is data known only to the
+ * server.  With a nonce of this form a server would recalculate the
+ * hash portion after receiving the client authentication header and
+ * reject the request if it did not match the nonce from that header
+ * or if the time-stamp value is not recent enough. In this way the
+ * server can limit the time of the nonce's validity. The inclusion of
+ * the ETag prevents a replay request for an updated version of the
+ * resource.  (Note: including the IP address of the client in the
+ * nonce would appear to offer the server the ability to limit the
+ * reuse of the nonce to the same client that originally got it.
+ * However, that would break proxy farms, where requests from a single
+ * user often go through different proxies in the farm. Also, IP
+ * address spoofing is not that hard.)
+ * ====
+ * 
+ * Now for my reasoning:
+ * We will not accept a unrecognised nonce->we have all recognisable
+ * nonces stored If we send out unique base64 encodings we guarantee
+ * that a given nonce applies to only one user (barring attacks or
+ * really bad timing with expiry and creation).  Using a random
+ * component in the nonce allows us to loop to find a unique nonce.
+ * We use H(nonce_data) so the nonce is meaningless to the reciever.
+ * So our nonce looks like base64(H(timestamp,pointertohash,randomdata))
+ * And even if our randomness is not very random (probably due to
+ * bad coding on my part) we don't really care - the timestamp and
+ * memory pointer should provide enough protection for the users
+ * authentication.
+ */
+
+    /* create a new nonce */
+    newnonce->nc = 0;
+    newnonce->flags.valid = 1;
+    newnonce->noncedata.self = newnonce;
+    newnonce->noncedata.creationtime = current_time.tv_sec;
+    newnonce->noncedata.randomdata = squid_random();
+
+    authDigestNonceEncode(newnonce);
+    /*
+     * loop until we get a unique nonce. The nonce creation must
+     * have a random factor
+     */
+    while ((temp = authenticateDigestNonceFindNonce((char const *)(newnonce->hash.key)))) {
+	/* create a new nonce */
+	newnonce->noncedata.randomdata = squid_random();
+	authDigestNonceEncode(newnonce);
+    }
+    hash_join(digest_nonce_cache, &newnonce->hash);
+    /* the cache's link */
+    authDigestNonceLink(newnonce);
+    newnonce->flags.incache = 1;
+    debug(29, 5) ("authenticateDigestNonceNew: created nonce %p at %ld\n", newnonce, (long int)newnonce->noncedata.creationtime);
+    return newnonce;
+}
+
+static void
+authenticateDigestNonceDelete(digest_nonce_h * nonce)
+{
+    if (nonce) {
+	assert(nonce->references == 0);
+#if UNREACHABLECODE
+	if (nonce->flags.incache)
+	    hash_remove_link(digest_nonce_cache, &nonce->hash);
+#endif
+	assert(nonce->flags.incache == 0);
+	safe_free(nonce->hash.key);
+	memPoolFree(digest_nonce_pool, nonce);
+    }
+}
+
+static void
+authenticateDigestNonceSetup(void)
+{
+    if (!digest_nonce_pool)
+	digest_nonce_pool = memPoolCreate("Digest Scheme nonce's", sizeof(digest_nonce_h));
+    if (!digest_nonce_cache) {
+	digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
+	assert(digest_nonce_cache);
+	eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1);
+    }
+}
+
+static void
+authenticateDigestNonceShutdown(void)
+{
+    /* 
+     * We empty the cache of any nonces left in there.
+     */
+    digest_nonce_h *nonce;
+    if (digest_nonce_cache) {
+	debug(29, 2) ("authenticateDigestNonceShutdown: Shutting down nonce cache \n");
+	hash_first(digest_nonce_cache);
+	while ((nonce = ((digest_nonce_h *) hash_next(digest_nonce_cache)))) {
+	    assert(nonce->flags.incache);
+	    authDigestNoncePurge(nonce);
+	}
+    }
+    if (digest_nonce_pool) {
+	assert(memPoolInUseCount(digest_nonce_pool) == 0);
+	memPoolDestroy(&digest_nonce_pool);
+    }
+    debug(29, 2) ("authenticateDigestNonceShutdown: Nonce cache shutdown\n");
+}
+
+static void
+authenticateDigestNonceReconfigure(void)
+{
+}
+
+static void
+authenticateDigestNonceCacheCleanup(void *data)
+{
+    /*
+     * We walk the hash by nonceb64 as that is the unique key we
+     * use.  For big hash tables we could consider stepping through
+     * the cache, 100/200 entries at a time. Lets see how it flies
+     * first.
+     */
+    digest_nonce_h *nonce;
+    debug(29, 3) ("authenticateDigestNonceCacheCleanup: Cleaning the nonce cache now\n");
+    debug(29, 3) ("authenticateDigestNonceCacheCleanup: Current time: %ld\n",
+	(long int)current_time.tv_sec);
+    hash_first(digest_nonce_cache);
+    while ((nonce = ((digest_nonce_h *) hash_next(digest_nonce_cache)))) {
+	debug(29, 3) ("authenticateDigestNonceCacheCleanup: nonce entry  : %p '%s'\n", nonce, (char *)nonce->hash.key);
+	debug(29, 4) ("authenticateDigestNonceCacheCleanup: Creation time: %ld\n", (long int)nonce->noncedata.creationtime);
+	if (authDigestNonceIsStale(nonce)) {
+	    debug(29, 4) ("authenticateDigestNonceCacheCleanup: Removing nonce %s from cache due to timeout.\n", (char *)nonce->hash.key);
+	    assert(nonce->flags.incache);
+	    /* invalidate nonce so future requests fail */
+	    nonce->flags.valid = 0;
+	    /* if it is tied to a auth_user, remove the tie */
+	    authDigestNonceUserUnlink(nonce);
+	    authDigestNoncePurge(nonce);
+	}
+    }
+    debug(29, 3) ("authenticateDigestNonceCacheCleanup: Finished cleaning the nonce cache.\n");
+    if (authenticateDigestActive())
+	eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1);
+}
+
+static void
+authDigestNonceLink(digest_nonce_h * nonce)
+{
+    assert(nonce != NULL);
+    nonce->references++;
+    debug(29, 9) ("authDigestNonceLink: nonce '%p' now at '%d'.\n", nonce, nonce->references);
+}
+
+#if NOT_USED
+static int
+authDigestNonceLinks(digest_nonce_h * nonce)
+{
+    if (!nonce)
+	return -1;
+    return nonce->references;
+}
+#endif
+
+static void
+authDigestNonceUnlink(digest_nonce_h * nonce)
+{
+    assert(nonce != NULL);
+    if (nonce->references > 0) {
+	nonce->references--;
+    } else {
+	debug(29, 1) ("authDigestNonceUnlink; Attempt to lower nonce %p refcount below 0!\n", nonce);
+    }
+    debug(29, 9) ("authDigestNonceUnlink: nonce '%p' now at '%d'.\n", nonce, nonce->references);
+    if (nonce->references == 0)
+	authenticateDigestNonceDelete(nonce);
+}
+
+static const char *
+authenticateDigestNonceNonceb64(digest_nonce_h * nonce)
+{
+    if (!nonce)
+	return NULL;
+    return (char const *)nonce->hash.key;
+}
+
+static digest_nonce_h *
+authenticateDigestNonceFindNonce(const char *nonceb64)
+{
+    digest_nonce_h *nonce = NULL;
+    if (nonceb64 == NULL)
+	return NULL;
+    debug(29, 9) ("authDigestNonceFindNonce:looking for nonceb64 '%s' in the nonce cache.\n", nonceb64);
+    nonce = static_cast<digest_nonce_h *>(hash_lookup(digest_nonce_cache, nonceb64));
+    if ((nonce == NULL) || (strcmp(authenticateDigestNonceNonceb64(nonce), nonceb64)))
+	return NULL;
+    debug(29, 9) ("authDigestNonceFindNonce: Found nonce '%p'\n", nonce);
+    return nonce;
+}
+
+static int
+authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9])
+{
+    unsigned long intnc;
+    /* do we have a nonce ? */
+    if (!nonce)
+	return 0;
+    intnc = strtol(nc, NULL, 16);
+    if ((digestConfig->NonceStrictness && intnc != nonce->nc + 1) ||
+	intnc < nonce->nc + 1) {
+	debug(29, 4) ("authDigestNonceIsValid: Nonce count doesn't match\n");
+	nonce->flags.valid = 0;
+	return 0;
+    }
+    /* has it already been invalidated ? */
+    if (!nonce->flags.valid) {
+	debug(29, 4) ("authDigestNonceIsValid: Nonce already invalidated\n");
+	return 0;
+    }
+    /* seems ok */
+    /* increment the nonce count - we've already checked that intnc is a
+     *  valid representation for us, so we don't need the test here.
+     */
+    nonce->nc = intnc;
+    return -1;
+}
+
+static int
+authDigestNonceIsStale(digest_nonce_h * nonce)
+{
+    /* do we have a nonce ? */
+    if (!nonce)
+	return -1;
+    /* has it's max duration expired? */
+    if (nonce->noncedata.creationtime + digestConfig->noncemaxduration < current_time.tv_sec) {
+	debug(29, 4) ("authDigestNonceIsStale: Nonce is too old. %ld %d %ld\n", (long int)nonce->noncedata.creationtime, (int)digestConfig->noncemaxduration, (long int)current_time.tv_sec);
+	nonce->flags.valid = 0;
+	return -1;
+    }
+    if (nonce->nc > 99999998) {
+	debug(29, 4) ("authDigestNonceIsStale: Nonce count overflow\n");
+	nonce->flags.valid = 0;
+	return -1;
+    }
+    if (nonce->nc > digestConfig->noncemaxuses) {
+	debug(29, 4) ("authDigestNoncelastRequest: Nonce count over user limit\n");
+	nonce->flags.valid = 0;
+	return -1;
+    }
+    /* seems ok */
+    return 0;
+}
+
+/* return -1 if the digest will be stale on the next request */
+static int
+authDigestNonceLastRequest(digest_nonce_h * nonce)
+{
+    if (!nonce)
+	return -1;
+    if (nonce->nc == 99999997) {
+	debug(29, 4) ("authDigestNoncelastRequest: Nonce count about to overflow\n");
+	return -1;
+    }
+    if (nonce->nc >= digestConfig->noncemaxuses - 1) {
+	debug(29, 4) ("authDigestNoncelastRequest: Nonce count about to hit user limit\n");
+	return -1;
+    }
+    /* and other tests are possible. */
+    return 0;
+}
+
+static void
+authDigestNoncePurge(digest_nonce_h * nonce)
+{
+    if (!nonce)
+	return;
+    if (!nonce->flags.incache)
+	return;
+    hash_remove_link(digest_nonce_cache, &nonce->hash);
+    nonce->flags.incache = 0;
+    /* the cache's link */
+    authDigestNonceUnlink(nonce);
+}
+
+/* USER related functions */
+
+
+#if NOT_USED
+static int
+authDigestUsercmpname(digest_user_h * u1, digest_user_h * u2)
+{
+    return strcmp(u1->username, u2->username);
+}
+#endif
+
+static auth_user_t *
+authDigestUserFindUsername(const char *username)
+{
+    auth_user_hash_pointer *usernamehash;
+    auth_user_t *auth_user;
+    debug(29, 9) ("authDigestUserFindUsername: Looking for user '%s'\n", username);
+    if (username && (usernamehash = static_cast<auth_user_hash_pointer *>(hash_lookup(proxy_auth_username_cache, username)))) {
+	while ((authUserHashPointerUser(usernamehash)->auth_type != AUTH_DIGEST) &&
+	    (usernamehash->next))
+	    usernamehash = usernamehash->next;
+	auth_user = NULL;
+	if (authUserHashPointerUser(usernamehash)->auth_type == AUTH_DIGEST) {
+	    auth_user = authUserHashPointerUser(usernamehash);
+	}
+	return auth_user;
+    }
+    return NULL;
+}
+
+static digest_user_h *
+authDigestUserNew(void)
+{
+    return static_cast<digest_user_h *>(memPoolAlloc(digest_user_pool));
+}
+
+static void
+authDigestUserSetup(void)
+{
+    if (!digest_user_pool)
+	digest_user_pool = memPoolCreate("Digest Scheme User Data", sizeof(digest_user_h));
+}
+
+static void
+authDigestUserShutdown(void)
+{
+    /*
+     * Future work: the auth framework could flush it's cache 
+     */
+    auth_user_hash_pointer *usernamehash;
+    auth_user_t *auth_user;
+    hash_first(proxy_auth_username_cache);
+    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
+	auth_user = authUserHashPointerUser(usernamehash);
+	if (authscheme_list[auth_user->auth_module - 1].typestr &&
+	    strcmp(authscheme_list[auth_user->auth_module - 1].typestr, "digest") == 0)
+	    /* it's digest */
+	    authenticateAuthUserUnlock(auth_user);
+    }
+    if (digest_user_pool) {
+	assert(memPoolInUseCount(digest_user_pool) == 0);
+	memPoolDestroy(&digest_user_pool);
+    }
+}
+
+
+/* request related functions */
+
+/* delete the digest reuqest structure. Does NOT delete related structures */
+static void
+authDigestRequestDelete(digest_request_h * digest_request)
+{
+    if (digest_request->nonceb64)
+	xfree(digest_request->nonceb64);
+    if (digest_request->cnonce)
+	xfree(digest_request->cnonce);
+    if (digest_request->realm)
+	xfree(digest_request->realm);
+    if (digest_request->pszPass)
+	xfree(digest_request->pszPass);
+    if (digest_request->algorithm)
+	xfree(digest_request->algorithm);
+    if (digest_request->pszMethod)
+	xfree(digest_request->pszMethod);
+    if (digest_request->qop)
+	xfree(digest_request->qop);
+    if (digest_request->uri)
+	xfree(digest_request->uri);
+    if (digest_request->response)
+	xfree(digest_request->response);
+    if (digest_request->nonce)
+	authDigestNonceUnlink(digest_request->nonce);
+    memPoolFree(digest_request_pool, digest_request);
+}
+
+static void
+authDigestAURequestFree(auth_user_request_t * auth_user_request)
+{
+    if (auth_user_request->scheme_data != NULL)
+	authDigestRequestDelete(static_cast<digest_request_h *>( auth_user_request->scheme_data));
+}
+
+static digest_request_h *
+authDigestRequestNew(void)
+{
+    digest_request_h *tmp;
+    tmp = static_cast<digest_request_h *>(memPoolAlloc(digest_request_pool));
+    assert(tmp != NULL);
+    return tmp;
+}
+
+static void
+authDigestRequestSetup(void)
+{
+    if (!digest_request_pool)
+	digest_request_pool = memPoolCreate("Digest Scheme Request Data", sizeof(digest_request_h));
+}
+
+static void
+authDigestRequestShutdown(void)
+{
+    /* No requests should be in progress when we get here */
+    if (digest_request_pool) {
+	assert(memPoolInUseCount(digest_request_pool) == 0);
+	memPoolDestroy(&digest_request_pool);
+    }
+}
+
+
+static void
+authDigestDone(void)
+{
+    if (digestauthenticators)
+	helperShutdown(digestauthenticators);
+    authdigest_initialised = 0;
+    if (!shutting_down) {
+	authenticateDigestNonceReconfigure();
+	return;
+    }
+    if (digestauthenticators) {
+	helperFree(digestauthenticators);
+	digestauthenticators = NULL;
+    }
+    authDigestRequestShutdown();
+    authDigestUserShutdown();
+    authenticateDigestNonceShutdown();
+    debug(29, 2) ("authenticateDigestDone: Digest authentication shut down.\n");
+}
+
+static void
+authDigestCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
+{
+    auth_digest_config *config = static_cast<auth_digest_config *>(scheme->scheme_data);
+    wordlist *list = config->authenticate;
+    debug(29, 9) ("authDigestCfgDump: Dumping configuration\n");
+    storeAppendPrintf(entry, "%s %s", name, "digest");
+    while (list != NULL) {
+	storeAppendPrintf(entry, " %s", list->key);
+	list = list->next;
+    }
+    storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s nonce_max_count %d\n%s %s nonce_max_duration %d seconds\n%s %s nonce_garbage_interval %d seconds\n",
+	name, "digest", config->digestAuthRealm,
+	name, "digest", config->authenticateChildren,
+	name, "digest", config->noncemaxuses,
+	name, "digest", (int)config->noncemaxduration,
+	name, "digest", (int)config->nonceGCInterval);
+}
+
+void
+authSchemeSetup_digest(authscheme_entry_t * authscheme)
+{
+    assert(!authdigest_initialised);
+    authscheme->Active = authenticateDigestActive;
+    authscheme->configured = authDigestConfigured;
+    authscheme->parse = authDigestParse;
+    authscheme->freeconfig = authDigestFreeConfig;
+    authscheme->dump = authDigestCfgDump;
+    authscheme->init = authDigestInit;
+    authscheme->authAuthenticate = authenticateDigestAuthenticateUser;
+    authscheme->authenticated = authDigestAuthenticated;
+    authscheme->authFixHeader = authenticateDigestFixHeader;
+    authscheme->FreeUser = authenticateDigestUserFree;
+    authscheme->AddHeader = authDigestAddHeader;
+#if WAITING_FOR_TE
+    authscheme->AddTrailer = authDigestAddTrailer;
+#endif
+    authscheme->authStart = authenticateDigestStart;
+    authscheme->authStats = authenticateDigestStats;
+    authscheme->authUserUsername = authenticateDigestUsername;
+    authscheme->getdirection = authenticateDigestDirection;
+    authscheme->oncloseconnection = NULL;
+    authscheme->decodeauth = authenticateDigestDecodeAuth;
+    authscheme->donefunc = authDigestDone;
+    authscheme->requestFree = authDigestAURequestFree;
+    authscheme->authConnLastHeader = NULL;
+}
+
+static int
+authenticateDigestActive(void)
+{
+    return (authdigest_initialised == 1) ? 1 : 0;
+}
+static int
+authDigestConfigured(void)
+{
+    if ((digestConfig != NULL) && (digestConfig->authenticate != NULL) &&
+	(digestConfig->authenticateChildren != 0) &&
+	(digestConfig->digestAuthRealm != NULL) && (digestConfig->noncemaxduration > -1))
+	return 1;
+    return 0;
+}
+
+static int
+authDigestAuthenticated(auth_user_request_t * auth_user_request)
+{
+    digest_user_h *digest_user = static_cast<digest_user_h *>(auth_user_request->auth_user->scheme_data);
+    if (digest_user->flags.credentials_ok == 1)
+	return 1;
+    else
+	return 0;
+}
+
+/* log a digest user in
+ */
+static void
+authenticateDigestAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
+{
+    auth_user_t *auth_user;
+    digest_request_h *digest_request;
+    digest_user_h *digest_user;
+
+    HASHHEX SESSIONKEY;
+    HASHHEX HA2 = "";
+    HASHHEX Response;
+
+    assert(auth_user_request->auth_user != NULL);
+    auth_user = auth_user_request->auth_user;
+
+    assert(auth_user->scheme_data != NULL);
+    digest_user = static_cast<digest_user_h *>(auth_user->scheme_data);
+
+    /* if the check has corrupted the user, just return */
+    if (digest_user->flags.credentials_ok == 3) {
+	return;
+    }
+    assert(auth_user_request->scheme_data != NULL);
+    digest_request = static_cast<digest_request_h *>(auth_user_request->scheme_data);
+
+    /* do we have the HA1 */
+    if (!digest_user->HA1created) {
+	digest_user->flags.credentials_ok = 2;
+	return;
+    }
+    if (digest_request->nonce == NULL) {
+	/* this isn't a nonce we issued */
+	/* TODO: record breaks in authentication at the request level 
+	 * This is probably best done with support changes at the
+	 * auth_rewrite level -RBC
+	 * and can wait for auth_rewrite V2.
+	 * RBC 20010902 further note: flags.credentials ok is now
+	 * a local scheme flag, so we can move this to the request
+	 * level at any time.
+	 */
+	digest_user->flags.credentials_ok = 3;
+	return;
+    }
+    DigestCalcHA1(digest_request->algorithm, NULL, NULL, NULL,
+	authenticateDigestNonceNonceb64(digest_request->nonce),
+	digest_request->cnonce,
+	digest_user->HA1, SESSIONKEY);
+    DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
+	digest_request->nc, digest_request->cnonce, digest_request->qop,
+	RequestMethodStr[request->method], digest_request->uri, HA2, Response);
+
+    debug(29, 9) ("\nResponse = '%s'\n"
+	"squid is = '%s'\n", digest_request->response, Response);
+
+    if (strcasecmp(digest_request->response, Response)) {
+	digest_user->flags.credentials_ok = 3;
+	return;
+    }
+    digest_user->flags.credentials_ok = 1;
+    /* password was checked and did match */
+    debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n",
+	digest_user->username);
+
+    /* auth_user is now linked, we reset these values
+     * after external auth occurs anyway */
+    auth_user->expiretime = current_time.tv_sec;
+    return;
+}
+
+static int
+authenticateDigestDirection(auth_user_request_t * auth_user_request)
+{
+    digest_request_h *digest_request;
+    digest_user_h *digest_user = static_cast<digest_user_h *>(auth_user_request->auth_user->scheme_data);
+    /* null auth_user is checked for by authenticateDirection */
+    switch (digest_user->flags.credentials_ok) {
+    case 0:			/* not checked */
+	return -1;
+    case 1:			/* checked & ok */
+	digest_request = static_cast<digest_request_h *>(auth_user_request->scheme_data);
+	if (authDigestNonceIsStale(digest_request->nonce))
+	    /* send stale response to the client agent */
+	    return -2;
+	return 0;
+    case 2:			/* partway through checking. */
+	return -1;
+    case 3:			/* authentication process failed. */
+	return -2;
+    }
+    return -2;
+}
+
+/* add the [proxy]authorisation header */
+static void
+authDigestAddHeader(auth_user_request_t * auth_user_request, HttpReply * rep, int accel)
+{
+    enum http_hdr_type type;
+    digest_request_h *digest_request;
+    if (!auth_user_request)
+	return;
+    digest_request = static_cast<digest_request_h *>(auth_user_request->scheme_data);
+    /* don't add to authentication error pages */
+    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
+	|| (accel && rep->sline.status == HTTP_UNAUTHORIZED))
+	return;
+    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
+
+#if WAITING_FOR_TE
+    /* test for http/1.1 transfer chunked encoding */
+    if (chunkedtest)
+	return;
+#endif
+
+    if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) {
+	digest_request->flags.authinfo_sent = 1;
+	debug(29, 9) ("authDigestAddHead: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce));
+	httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce));
+    }
+}
+
+#if WAITING_FOR_TE
+/* add the [proxy]authorisation header */
+static void
+authDigestAddTrailer(auth_user_request_t * auth_user_request, HttpReply * rep, int accel)
+{
+    int type;
+    digest_request_h *digest_request;
+    if (!auth_user_request)
+	return;
+    digest_request = static_cast<digest_request_h *>(auth_user_request->scheme_data);
+    /* has the header already been send? */
+    if (digest_request->flags.authinfo_sent)
+	return;
+    /* don't add to authentication error pages */
+    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
+	|| (accel && rep->sline.status == HTTP_UNAUTHORIZED))
+	return;
+    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
+
+    if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) {
+	debug(29, 9) ("authDigestAddTrailer: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce));
+	httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce));
+    }
+}
+#endif
+
+/* add the [www-|Proxy-]authenticate header on a 407 or 401 reply */
+void
+authenticateDigestFixHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
+{
+    digest_request_h *digest_request;
+    int stale = 0;
+    digest_nonce_h *nonce = authenticateDigestNonceNew();
+    if (auth_user_request && authDigestAuthenticated(auth_user_request) && auth_user_request->scheme_data) {
+	digest_request = static_cast<digest_request_h *>(auth_user_request->scheme_data);
+	stale = authDigestNonceIsStale(digest_request->nonce);
+    }
+    if (digestConfig->authenticate) {
+	debug(29, 9) ("authenticateFixHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s\n", type, digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false");
+	/* in the future, for WWW auth we may want to support the domain entry */
+	httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s", digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false");
+    }
+}
+
+static void
+authenticateDigestUserFree(auth_user_t * auth_user)
+{
+    digest_user_h *digest_user = static_cast<digest_user_h *>(auth_user->scheme_data);
+    dlink_node *link, *tmplink;
+    debug(29, 9) ("authenticateDigestFreeUser: Clearing Digest scheme data\n");
+    if (!digest_user)
+	return;
+    safe_free(digest_user->username);
+
+    link = digest_user->nonces.head;
+    while (link) {
+	tmplink = link;
+	link = link->next;
+	dlinkDelete(tmplink, &digest_user->nonces);
+	authDigestNoncePurge(static_cast<digest_nonce_h *>(tmplink->data));
+	authDigestNonceUnlink(static_cast<digest_nonce_h *>(tmplink->data));
+	dlinkNodeDelete(tmplink);
+    }
+
+    memPoolFree(digest_user_pool, auth_user->scheme_data);
+    auth_user->scheme_data = NULL;
+}
+
+static void
+authenticateDigestHandleReply(void *data, char *reply)
+{
+    DigestAuthenticateStateData *r = static_cast<DigestAuthenticateStateData *>(data);
+    auth_user_request_t *auth_user_request;
+    digest_request_h *digest_request;
+    digest_user_h *digest_user;
+    char *t = NULL;
+    void *cbdata;
+    debug(29, 9) ("authenticateDigestHandleReply: {%s}\n", reply ? reply : "<NULL>");
+    if (reply) {
+	if ((t = strchr(reply, ' ')))
+	    *t = '\0';
+	if (*reply == '\0')
+	    reply = NULL;
+    }
+    assert(r->auth_user_request != NULL);
+    auth_user_request = r->auth_user_request;
+    assert(auth_user_request->scheme_data != NULL);
+    digest_request = static_cast<digest_request_h *>(auth_user_request->scheme_data);
+    digest_user = static_cast<digest_user_h *>(auth_user_request->auth_user->scheme_data);
+    if (reply && (strncasecmp(reply, "ERR", 3) == 0))
+	digest_user->flags.credentials_ok = 3;
+    else {
+	CvtBin(reply, digest_user->HA1);
+	digest_user->HA1created = 1;
+    }
+    if (cbdataReferenceValidDone(r->data, &cbdata))
+	r->handler(cbdata, NULL);
+    authenticateStateFree(r);
+}
+
+/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
+ * config file */
+static void
+authDigestInit(authScheme * scheme)
+{
+    static int init = 0;
+    if (digestConfig->authenticate) {
+	authDigestUserSetup();
+	authDigestRequestSetup();
+	authenticateDigestNonceSetup();
+	authdigest_initialised = 1;
+	if (digestauthenticators == NULL)
+	    digestauthenticators = helperCreate("digestauthenticator");
+	digestauthenticators->cmdline = digestConfig->authenticate;
+	digestauthenticators->n_to_start = digestConfig->authenticateChildren;
+	digestauthenticators->ipc_type = IPC_STREAM;
+	helperOpenServers(digestauthenticators);
+	if (!init) {
+	    cachemgrRegister("digestauthenticator", "User Authenticator Stats",
+		authenticateDigestStats, 0, 1);
+	    init++;
+	}
+	CBDATA_INIT_TYPE(DigestAuthenticateStateData);
+    }
+}
+
+
+/* free any allocated configuration details */
+void
+authDigestFreeConfig(authScheme * scheme)
+{
+    if (digestConfig == NULL)
+	return;
+    assert(digestConfig == scheme->scheme_data);
+    if (digestConfig->authenticate)
+	wordlistDestroy(&digestConfig->authenticate);
+    safe_free(digestConfig->digestAuthRealm);
+    xfree(digestConfig);
+    digestConfig = NULL;
+}
+
+static void
+authDigestParse(authScheme * scheme, int n_configured, char *param_str)
+{
+    if (scheme->scheme_data == NULL) {
+	assert(digestConfig == NULL);
+	/* this is the first param to be found */
+	scheme->scheme_data = xmalloc(sizeof(auth_digest_config));
+	memset(scheme->scheme_data, 0, sizeof(auth_digest_config));
+	digestConfig = static_cast<auth_digest_config *>(scheme->scheme_data);
+	digestConfig->authenticateChildren = 5;
+	/* 5 minutes */
+	digestConfig->nonceGCInterval = 5 * 60;
+	/* 30 minutes */
+	digestConfig->noncemaxduration = 30 * 60;
+	/* 50 requests */
+	digestConfig->noncemaxuses = 50;
+	/* strict nonce count behaviour */
+	digestConfig->NonceStrictness = 1;
+    }
+    digestConfig = static_cast<auth_digest_config *>(scheme->scheme_data);
+    if (strcasecmp(param_str, "program") == 0) {
+	if (digestConfig->authenticate)
+	    wordlistDestroy(&digestConfig->authenticate);
+	parse_wordlist(&digestConfig->authenticate);
+	requirePathnameExists("authparam digest program", digestConfig->authenticate->key);
+    } else if (strcasecmp(param_str, "children") == 0) {
+	parse_int(&digestConfig->authenticateChildren);
+    } else if (strcasecmp(param_str, "realm") == 0) {
+	parse_eol(&digestConfig->digestAuthRealm);
+    } else if (strcasecmp(param_str, "nonce_garbage_interval") == 0) {
+	parse_time_t(&digestConfig->nonceGCInterval);
+    } else if (strcasecmp(param_str, "nonce_max_duration") == 0) {
+	parse_time_t(&digestConfig->noncemaxduration);
+    } else if (strcasecmp(param_str, "nonce_max_count") == 0) {
+	parse_int(&digestConfig->noncemaxuses);
+    } else if (strcasecmp(param_str, "nonce_strictness") == 0) {
+        parse_onoff(&digestConfig->NonceStrictness);
+    } else {
+	debug(28, 0) ("unrecognised digest auth scheme parameter '%s'\n", param_str);
+    }
+}
+
+
+static void
+authenticateDigestStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "Digest Authenticator Statistics:\n");
+    helperStats(sentry, digestauthenticators);
+}
+
+/* NonceUserUnlink: remove the reference to auth_user and unlink the node from the list */
+
+static void
+authDigestNonceUserUnlink(digest_nonce_h * nonce)
+{
+    digest_user_h *digest_user;
+    dlink_node *link, *tmplink;
+    if (!nonce)
+	return;
+    if (!nonce->auth_user)
+	return;
+    digest_user = static_cast<digest_user_h *>(nonce->auth_user->scheme_data);
+    /* unlink from the user list. Yes we're crossing structures but this is the only 
+     * time this code is needed
+     */
+    link = digest_user->nonces.head;
+    while (link) {
+	tmplink = link;
+	link = link->next;
+	if (tmplink->data == nonce) {
+	    dlinkDelete(tmplink, &digest_user->nonces);
+	    authDigestNonceUnlink(static_cast<digest_nonce_h *>(tmplink->data));
+	    dlinkNodeDelete(tmplink);
+	    link = NULL;
+	}
+    }
+    /* this reference to auth_user was not locked because freeeing the auth_user frees
+     * the nonce too. 
+     */
+    nonce->auth_user = NULL;
+}
+
+/* authDigestUserLinkNonce: add a nonce to a given user's struct */
+
+static void
+authDigestUserLinkNonce(auth_user_t * auth_user, digest_nonce_h * nonce)
+{
+    dlink_node *node;
+    digest_user_h *digest_user;
+    if (!auth_user || !nonce)
+	return;
+    if (!auth_user->scheme_data)
+	return;
+    digest_user = static_cast<digest_user_h *>(auth_user->scheme_data);
+    node = digest_user->nonces.head;
+    while (node && (node->data != nonce))
+	node = node->next;
+    if (node)
+	return;
+    node = dlinkNodeNew();
+    dlinkAddTail(nonce, node, &digest_user->nonces);
+    authDigestNonceLink(nonce);
+    /* ping this nonce to this auth user */
+    assert((nonce->auth_user == NULL) || (nonce->auth_user = auth_user));
+    /* we don't lock this reference because removing the auth_user removes the 
+     * hash too. Of course if that changes we're stuffed so read the code huh?
+     */
+    nonce->auth_user = auth_user;
+}
+
+/* authenticateDigestUsername: return a pointer to the username in the */
+static char const *
+authenticateDigestUsername(auth_user_t const * auth_user)
+{
+    digest_user_h *digest_user = static_cast<digest_user_h *>(auth_user->scheme_data);
+    if (digest_user)
+	return digest_user->username;
+    return NULL;
+}
+
+/* setup the necessary info to log the username */
+static void
+authDigestLogUsername(auth_user_request_t * auth_user_request, char *username)
+{
+    auth_user_t *auth_user;
+    digest_user_h *digest_user;
+    dlink_node *node;
+
+    /* log the username */
+    debug(29, 9) ("authBasicDecodeAuth: Creating new user for logging '%s'\n", username);
+    /* new auth_user */
+    auth_user = authenticateAuthUserNew("digest");
+    /* new scheme data */
+    digest_user = authDigestUserNew();
+    /* save the credentials */
+    digest_user->username = username;
+    /* link the scheme data in */
+    auth_user->scheme_data = digest_user;
+    /* set the auth_user type */
+    auth_user->auth_type = AUTH_BROKEN;
+    /* link the request to the user */
+    auth_user_request->auth_user = auth_user;
+    /* lock for the auth_user_request link */
+    authenticateAuthUserLock(auth_user);
+    node = dlinkNodeNew();
+    dlinkAdd(auth_user_request, node, &auth_user->requests);
+}
+
+/*
+ * Decode a Digest [Proxy-]Auth string, placing the results in the passed
+ * Auth_user structure.
+ */
+
+static void
+authenticateDigestDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
+{
+    String temp;
+    const char *item;
+    const char *p;
+    const char *pos = NULL;
+    char *username = NULL;
+    digest_nonce_h *nonce;
+    int ilen;
+    digest_request_h *digest_request;
+    digest_user_h *digest_user;
+    auth_user_t *auth_user;
+    dlink_node *node;
+
+    debug(29, 9) ("authenticateDigestDecodeAuth: beginning\n");
+    assert(auth_user_request != NULL);
+
+    digest_request = authDigestRequestNew();
+
+    /* trim DIGEST from string */
+    while (!xisspace(*proxy_auth))
+	proxy_auth++;
+
+    /* Trim leading whitespace before decoding */
+    while (xisspace(*proxy_auth))
+	proxy_auth++;
+
+    stringInit(&temp, proxy_auth);
+    while (strListGetItem(&temp, ',', &item, &ilen, &pos)) {
+	if ((p = strchr(item, '=')) && (p - item < ilen))
+	    ilen = p++ - item;
+	if (!strncmp(item, "username", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    /* quote mark */
+	    p++;
+	    username = xstrndup(p, strchr(p, '"') + 1 - p);
+	    debug(29, 9) ("authDigestDecodeAuth: Found Username '%s'\n", username);
+	} else if (!strncmp(item, "realm", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    /* quote mark */
+	    p++;
+	    digest_request->realm = xstrndup(p, strchr(p, '"') + 1 - p);
+	    debug(29, 9) ("authDigestDecodeAuth: Found realm '%s'\n", digest_request->realm);
+	} else if (!strncmp(item, "qop", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    if (*p == '\"')
+	        /* quote mark */
+	        p++;
+	    digest_request->qop = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}") + 1);
+	    debug(29, 9) ("authDigestDecodeAuth: Found qop '%s'\n", digest_request->qop);
+	} else if (!strncmp(item, "algorithm", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    if (*p == '\"')
+	        /* quote mark */
+	        p++;
+	    digest_request->algorithm = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}")+1);
+	    debug(29, 9) ("authDigestDecodeAuth: Found algorithm '%s'\n", digest_request->algorithm);
+	} else if (!strncmp(item, "uri", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    /* quote mark */
+	    p++;
+	    digest_request->uri = xstrndup(p, strchr(p, '"') + 1 - p);
+	    debug(29, 9) ("authDigestDecodeAuth: Found uri '%s'\n", digest_request->uri);
+	} else if (!strncmp(item, "nonce", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    /* quote mark */
+	    p++;
+	    digest_request->nonceb64 = xstrndup(p, strchr(p, '"') + 1 - p);
+	    debug(29, 9) ("authDigestDecodeAuth: Found nonce '%s'\n", digest_request->nonceb64);
+	} else if (!strncmp(item, "nc", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    xstrncpy(digest_request->nc, p, 9);
+	    debug(29, 9) ("authDigestDecodeAuth: Found noncecount '%s'\n", digest_request->nc);
+	} else if (!strncmp(item, "cnonce", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    /* quote mark */
+	    p++;
+	    digest_request->cnonce = xstrndup(p, strchr(p, '"') + 1 - p);
+	    debug(29, 9) ("authDigestDecodeAuth: Found cnonce '%s'\n", digest_request->cnonce);
+	} else if (!strncmp(item, "response", ilen)) {
+	    /* white space */
+	    while (xisspace(*p))
+		p++;
+	    /* quote mark */
+	    p++;
+	    digest_request->response = xstrndup(p, strchr(p, '"') + 1 - p);
+	    debug(29, 9) ("authDigestDecodeAuth: Found response '%s'\n", digest_request->response);
+	}
+    }
+    stringClean(&temp);
+
+
+    /* now we validate the data given to us */
+
+    /*
+     * TODO: on invalid parameters we should return 400, not 407.
+     * Find some clean way of doing this. perhaps return a valid
+     * struct, and set the direction to clientwards combined with
+     * a change to the clientwards handling code (ie let the
+     * clientwards call set the error type (but limited to known
+     * correct values - 400/401/407
+     */
+
+    /* first the NONCE count */
+    if (digest_request->cnonce && strlen(digest_request->nc) != 8) {
+	debug(29, 4) ("authenticateDigestDecode: nonce count length invalid\n");
+	authDigestLogUsername(auth_user_request, username);
+
+	/* we don't need the scheme specific data anymore */
+	authDigestRequestDelete(digest_request);
+	auth_user_request->scheme_data = NULL;
+	return;
+    }
+    /* now the nonce */
+    nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64);
+    if ((nonce == NULL) || !(authDigestNonceIsValid(nonce, digest_request->nc))) {
+	/* we couldn't find a matching nonce! */
+	debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce recieved\n");
+	authDigestLogUsername(auth_user_request, username);
+
+	/* we don't need the scheme specific data anymore */
+	authDigestRequestDelete(digest_request);
+	auth_user_request->scheme_data = NULL;
+	return;
+    }
+    digest_request->nonce = nonce;
+    authDigestNonceLink(nonce);
+
+    /* check the qop is what we expected. Note that for compatability with 
+     * RFC 2069 we should support a missing qop. Tough. */
+    if (!digest_request->qop || strcmp(digest_request->qop, QOP_AUTH)) {
+	/* we recieved a qop option we didn't send */
+	debug(29, 4) ("authenticateDigestDecode: Invalid qop option recieved\n");
+	authDigestLogUsername(auth_user_request, username);
+
+	/* we don't need the scheme specific data anymore */
+	authDigestRequestDelete(digest_request);
+	auth_user_request->scheme_data = NULL;
+	return;
+    }
+    /* we can't check the URI just yet. We'll check it in the
+     * authenticate phase */
+
+    /* is the response the correct length? */
+
+    if (!digest_request->response || strlen(digest_request->response) != 32) {
+	debug(29, 4) ("authenticateDigestDecode: Response length invalid\n");
+	authDigestLogUsername(auth_user_request, username);
+
+	/* we don't need the scheme specific data anymore */
+	authDigestRequestDelete(digest_request);
+	auth_user_request->scheme_data = NULL;
+	return;
+    }
+    /* do we have a username ? */
+    if (!username || username[0] == '\0') {
+	debug(29, 4) ("authenticateDigestDecode: Empty or not present username\n");
+	authDigestLogUsername(auth_user_request, username);
+
+	/* we don't need the scheme specific data anymore */
+	authDigestRequestDelete(digest_request);
+	auth_user_request->scheme_data = NULL;
+	return;
+    }
+    /* check that we're not being hacked / the username hasn't changed */
+    if (nonce->auth_user && strcmp(username, nonce->auth_user->username())) {
+	debug(29, 4) ("authenticateDigestDecode: Username for the nonce does not equal the username for the request\n");
+	authDigestLogUsername(auth_user_request, username);
+
+	/* we don't need the scheme specific data anymore */
+	authDigestRequestDelete(digest_request);
+	auth_user_request->scheme_data = NULL;
+	return;
+    }
+    /* if we got a qop, did we get a cnonce or did we get a cnonce wihtout a qop? */
+    if ((digest_request->qop && !digest_request->cnonce)
+	|| (!digest_request->qop && digest_request->cnonce)) {
+	debug(29, 4) ("authenticateDigestDecode: qop without cnonce, or vice versa!\n");
+	authDigestLogUsername(auth_user_request, username);
+
+	/* we don't need the scheme specific data anymore */
+	authDigestRequestDelete(digest_request);
+	auth_user_request->scheme_data = NULL;
+	return;
+    }
+    /* check the algorithm is present and supported */
+    if (!digest_request->algorithm)
+        digest_request->algorithm = xstrndup ("MD5", 4);
+    else if (strcmp(digest_request->algorithm, "MD5")
+	&& strcmp(digest_request->algorithm, "MD5-sess")) {
+	debug(29, 4) ("authenticateDigestDecode: invalid algorithm specified!\n");
+	authDigestLogUsername(auth_user_request, username);
+
+	/* we don't need the scheme specific data anymore */
+	authDigestRequestDelete(digest_request);
+	auth_user_request->scheme_data = NULL;
+	return;
+    }
+    /* the method we'll check at the authenticate step as well */
+
+
+    /* we don't send or parse opaques. Ok so we're flexable ... */
+
+    /* find the user */
+
+    if ((auth_user = authDigestUserFindUsername(username)) == NULL) {
+	/* the user doesn't exist in the username cache yet */
+	debug(29, 9) ("authDigestDecodeAuth: Creating new digest user '%s'\n", username);
+	/* new auth_user */
+	auth_user = authenticateAuthUserNew("digest");
+	/* new scheme user data */
+	digest_user = authDigestUserNew();
+	/* save the username */
+	digest_user->username = username;
+	/* link the primary struct in */
+	auth_user->scheme_data = digest_user;
+	/* set the user type */
+	auth_user->auth_type = AUTH_DIGEST;
+	/* this auth_user struct is the one to get added to the
+	 * username cache */
+	/* store user in hash's */
+	authenticateUserNameCacheAdd(auth_user);
+	/* 
+	 * Add the digest to the user so we can tell if a hacking
+	 * or spoofing attack is taking place. We do this by assuming
+	 * the user agent won't change user name without warning.
+	 */
+	authDigestUserLinkNonce(auth_user, nonce);
+    } else {
+	debug(29, 9) ("authDigestDecodeAuth: Found user '%s' in the user cache as '%p'\n", username, auth_user);
+	digest_user = static_cast<digest_user_h *>(auth_user->scheme_data);
+	xfree(username);
+    }
+    /*link the request and the user */
+    auth_user_request->auth_user = auth_user;
+    auth_user_request->scheme_data = digest_request;
+    /* lock for the request link */
+    authenticateAuthUserLock(auth_user);
+    node = dlinkNodeNew();
+    dlinkAdd(auth_user_request, node, &auth_user->requests);
+
+    debug(29, 9) ("username = '%s'\nrealm = '%s'\nqop = '%s'\nalgorithm = '%s'\nuri = '%s'\nnonce = '%s'\nnc = '%s'\ncnonce = '%s'\nresponse = '%s'\ndigestnonce = '%p'\n",
+	digest_user->username, digest_request->realm,
+	digest_request->qop, digest_request->algorithm,
+	digest_request->uri, digest_request->nonceb64,
+	digest_request->nc, digest_request->cnonce, digest_request->response, nonce);
+
+    return;
+}
+
+/* send the initial data to a digest authenticator module */
+static void
+authenticateDigestStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
+{
+    DigestAuthenticateStateData *r = NULL;
+    char buf[8192];
+    digest_request_h *digest_request;
+    digest_user_h *digest_user;
+    assert(auth_user_request);
+    assert(handler);
+    assert(auth_user_request->auth_user->auth_type == AUTH_DIGEST);
+    assert(auth_user_request->auth_user->scheme_data != NULL);
+    assert(auth_user_request->scheme_data != NULL);
+    digest_request = static_cast<digest_request_h *>(auth_user_request->scheme_data);
+    digest_user = static_cast<digest_user_h *>(auth_user_request->auth_user->scheme_data);
+    debug(29, 9) ("authenticateStart: '\"%s\":\"%s\"'\n", digest_user->username,
+	digest_request->realm);
+    if (digestConfig->authenticate == NULL) {
+	handler(data, NULL);
+	return;
+    }
+    r = cbdataAlloc(DigestAuthenticateStateData);
+    r->handler = handler;
+    r->data = cbdataReference(data);
+    r->auth_user_request = auth_user_request;
+    snprintf(buf, 8192, "\"%s\":\"%s\"\n", digest_user->username, digest_request->realm);
+    helperSubmit(digestauthenticators, buf, authenticateDigestHandleReply, r);
+}
Index: squid/src/auth/digest/auth_digest.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/auth/digest/auth_digest.h,v
retrieving revision 1.7
retrieving revision 1.7.28.1
diff -u -r1.7 -r1.7.28.1
--- squid/src/auth/digest/auth_digest.h	13 Jan 2002 03:21:39 -0000	1.7
+++ squid/src/auth/digest/auth_digest.h	3 Oct 2002 01:04:37 -0000	1.7.28.1
@@ -8,11 +8,12 @@
 #include "rfc2617.h"
 
 /* Generic */
-typedef struct {
+class DigestAuthenticateStateData {
+public:
     void *data;
     auth_user_request_t *auth_user_request;
     RH *handler;
-} authenticateStateData;
+};
 
 typedef struct _digest_request_h digest_request_h;
 typedef struct _digest_user_h digest_user_h;
--- squid/src/auth/ntlm/auth_ntlm.c	Wed Feb 14 01:07:15 2007
+++ /dev/null	Wed Feb 14 01:05:20 2007
@@ -1,1066 +0,0 @@
-
-/*
- * $Id$
- *
- * DEBUG: section 29    NTLM Authenticator
- * AUTHOR: Robert Collins
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-/* The functions in this file handle authentication.
- * They DO NOT perform access control or auditing.
- * See acl.c for access control and client_side.c for auditing */
-
-
-#include "squid.h"
-#include "auth_ntlm.h"
-
-extern AUTHSSETUP authSchemeSetup_ntlm;
-
-static void
-authenticateStateFree(authenticateStateData * r)
-{
-    cbdataFree(r);
-}
-
-/* NTLM Scheme */
-static HLPSCB authenticateNTLMHandleReply;
-static HLPSCB authenticateNTLMHandleplaceholder;
-static AUTHSACTIVE authenticateNTLMActive;
-static AUTHSAUTHED authNTLMAuthenticated;
-static AUTHSAUTHUSER authenticateNTLMAuthenticateUser;
-static AUTHSCONFIGURED authNTLMConfigured;
-static AUTHSFIXERR authenticateNTLMFixErrorHeader;
-static AUTHSFREE authenticateNTLMFreeUser;
-static AUTHSDIRECTION authenticateNTLMDirection;
-static AUTHSDECODE authenticateDecodeNTLMAuth;
-static AUTHSDUMP authNTLMCfgDump;
-static AUTHSFREECONFIG authNTLMFreeConfig;
-static AUTHSINIT authNTLMInit;
-static AUTHSONCLOSEC authenticateNTLMOnCloseConnection;
-static AUTHSCONNLASTHEADER NTLMLastHeader;
-static AUTHSUSERNAME authenticateNTLMUsername;
-static AUTHSREQFREE authNTLMAURequestFree;
-static AUTHSPARSE authNTLMParse;
-static AUTHSSTART authenticateNTLMStart;
-static AUTHSSTATS authenticateNTLMStats;
-static AUTHSSHUTDOWN authNTLMDone;
-
-/* helper callbacks to handle per server state data */
-static HLPSAVAIL authenticateNTLMHelperServerAvailable;
-static HLPSONEQ authenticateNTLMHelperServerOnEmpty;
-
-static statefulhelper *ntlmauthenticators = NULL;
-
-CBDATA_TYPE(authenticateStateData);
-
-static int authntlm_initialised = 0;
-
-static MemPool *ntlm_helper_state_pool = NULL;
-static MemPool *ntlm_user_pool = NULL;
-static MemPool *ntlm_request_pool = NULL;
-static auth_ntlm_config *ntlmConfig = NULL;
-
-static hash_table *proxy_auth_cache = NULL;
-
-/*
- *
- * Private Functions
- *
- */
-
-static void
-authNTLMDone(void)
-{
-    debug(29, 2) ("authNTLMDone: shutting down NTLM authentication.\n");
-    if (ntlmauthenticators)
-	helperStatefulShutdown(ntlmauthenticators);
-    authntlm_initialised = 0;
-    if (!shutting_down)
-	return;
-    if (ntlmauthenticators)
-	helperStatefulFree(ntlmauthenticators);
-    ntlmauthenticators = NULL;
-    if (ntlm_helper_state_pool) {
-	assert(memPoolInUseCount(ntlm_helper_state_pool) == 0);
-	memPoolDestroy(&ntlm_helper_state_pool);
-    }
-    if (ntlm_request_pool) {
-	assert(memPoolInUseCount(ntlm_request_pool) == 0);
-	memPoolDestroy(&ntlm_request_pool);
-    }
-    if (ntlm_user_pool) {
-	assert(memPoolInUseCount(ntlm_user_pool) == 0);
-	memPoolDestroy(&ntlm_user_pool);
-    }
-    debug(29, 2) ("authNTLMDone: NTLM authentication Shutdown.\n");
-}
-
-/* free any allocated configuration details */
-static void
-authNTLMFreeConfig(authScheme * scheme)
-{
-    if (ntlmConfig == NULL)
-	return;
-    assert(ntlmConfig == scheme->scheme_data);
-    if (ntlmConfig->authenticate)
-	wordlistDestroy(&ntlmConfig->authenticate);
-    xfree(ntlmConfig);
-    ntlmConfig = NULL;
-}
-
-static void
-authNTLMCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
-{
-    auth_ntlm_config *config = scheme->scheme_data;
-    wordlist *list = config->authenticate;
-    storeAppendPrintf(entry, "%s %s", name, "ntlm");
-    while (list != NULL) {
-	storeAppendPrintf(entry, " %s", list->key);
-	list = list->next;
-    }
-    storeAppendPrintf(entry, "\n%s %s children %d\n%s %s max_challenge_reuses %d\n%s %s max_challenge_lifetime %d seconds\n",
-	name, "ntlm", config->authenticateChildren,
-	name, "ntlm", config->challengeuses,
-	name, "ntlm", (int)config->challengelifetime);
-
-}
-
-static void
-authNTLMParse(authScheme * scheme, int n_configured, char *param_str)
-{
-    if (scheme->scheme_data == NULL) {
-	assert(ntlmConfig == NULL);
-	/* this is the first param to be found */
-	scheme->scheme_data = xmalloc(sizeof(auth_ntlm_config));
-	memset(scheme->scheme_data, 0, sizeof(auth_ntlm_config));
-	ntlmConfig = scheme->scheme_data;
-	ntlmConfig->authenticateChildren = 5;
-	ntlmConfig->challengeuses = 0;
-	ntlmConfig->challengelifetime = 60;
-    }
-    ntlmConfig = scheme->scheme_data;
-    if (strcasecmp(param_str, "program") == 0) {
-	if (ntlmConfig->authenticate)
-	    wordlistDestroy(&ntlmConfig->authenticate);
-	parse_wordlist(&ntlmConfig->authenticate);
-	requirePathnameExists("authparam ntlm program", ntlmConfig->authenticate->key);
-    } else if (strcasecmp(param_str, "children") == 0) {
-	parse_int(&ntlmConfig->authenticateChildren);
-    } else if (strcasecmp(param_str, "max_challenge_reuses") == 0) {
-	parse_int(&ntlmConfig->challengeuses);
-    } else if (strcasecmp(param_str, "max_challenge_lifetime") == 0) {
-	parse_time_t(&ntlmConfig->challengelifetime);
-    } else {
-	debug(28, 0) ("unrecognised ntlm auth scheme parameter '%s'\n", param_str);
-    }
-    /*
-     * disable client side request pipelining. There is a race with
-     * NTLM when the client sends a second request on an NTLM
-     * connection before the authenticate challenge is sent. With
-     * this patch, the client may fail to authenticate, but squid's
-     * state will be preserved.  Caveats: this should be a post-parse
-     * test, but that can wait for the modular parser to be integrated.
-     */
-    if (ntlmConfig->authenticate)
-	Config.onoff.pipeline_prefetch = 0;
-}
-
-
-void
-authSchemeSetup_ntlm(authscheme_entry_t * authscheme)
-{
-    assert(!authntlm_initialised);
-    authscheme->Active = authenticateNTLMActive;
-    authscheme->configured = authNTLMConfigured;
-    authscheme->parse = authNTLMParse;
-    authscheme->dump = authNTLMCfgDump;
-    authscheme->requestFree = authNTLMAURequestFree;
-    authscheme->freeconfig = authNTLMFreeConfig;
-    authscheme->init = authNTLMInit;
-    authscheme->authAuthenticate = authenticateNTLMAuthenticateUser;
-    authscheme->authenticated = authNTLMAuthenticated;
-    authscheme->authFixHeader = authenticateNTLMFixErrorHeader;
-    authscheme->FreeUser = authenticateNTLMFreeUser;
-    authscheme->authStart = authenticateNTLMStart;
-    authscheme->authStats = authenticateNTLMStats;
-    authscheme->authUserUsername = authenticateNTLMUsername;
-    authscheme->getdirection = authenticateNTLMDirection;
-    authscheme->decodeauth = authenticateDecodeNTLMAuth;
-    authscheme->donefunc = authNTLMDone;
-    authscheme->oncloseconnection = authenticateNTLMOnCloseConnection;
-    authscheme->authConnLastHeader = NTLMLastHeader;
-}
-
-/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
- * config file */
-static void
-authNTLMInit(authScheme * scheme)
-{
-    static int ntlminit = 0;
-    if (ntlmConfig->authenticate) {
-	if (!ntlm_helper_state_pool)
-	    ntlm_helper_state_pool = memPoolCreate("NTLM Helper State data", sizeof(ntlm_helper_state_t));
-	if (!ntlm_user_pool)
-	    ntlm_user_pool = memPoolCreate("NTLM Scheme User Data", sizeof(ntlm_user_t));
-	if (!ntlm_request_pool)
-	    ntlm_request_pool = memPoolCreate("NTLM Scheme Request Data", sizeof(ntlm_request_t));
-	authntlm_initialised = 1;
-	if (ntlmauthenticators == NULL)
-	    ntlmauthenticators = helperStatefulCreate("ntlmauthenticator");
-	if (!proxy_auth_cache)
-	    proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
-	assert(proxy_auth_cache);
-	ntlmauthenticators->cmdline = ntlmConfig->authenticate;
-	ntlmauthenticators->n_to_start = ntlmConfig->authenticateChildren;
-	ntlmauthenticators->ipc_type = IPC_STREAM;
-	ntlmauthenticators->datapool = ntlm_helper_state_pool;
-	ntlmauthenticators->IsAvailable = authenticateNTLMHelperServerAvailable;
-	ntlmauthenticators->OnEmptyQueue = authenticateNTLMHelperServerOnEmpty;
-	helperStatefulOpenServers(ntlmauthenticators);
-	/* TODO: In here send the initial YR to preinitialise the challenge cache */
-	/* Think about this... currently we ask when the challenge is needed. Better? */
-	if (!ntlminit) {
-	    cachemgrRegister("ntlmauthenticator", "User NTLM Authenticator Stats", authenticateNTLMStats, 0, 1);
-	    ntlminit++;
-	}
-	CBDATA_INIT_TYPE(authenticateStateData);
-    }
-}
-
-static int
-authenticateNTLMActive()
-{
-    return (authntlm_initialised == 1) ? 1 : 0;
-}
-
-
-static int
-authNTLMConfigured()
-{
-    if ((ntlmConfig != NULL) && (ntlmConfig->authenticate != NULL) && (ntlmConfig->authenticateChildren != 0) && (ntlmConfig->challengeuses > -1) && (ntlmConfig->challengelifetime > -1)) {
-	debug(29, 9) ("authNTLMConfigured: returning configured\n");
-	return 1;
-    }
-    debug(29, 9) ("authNTLMConfigured: returning unconfigured\n");
-    return 0;
-}
-
-/* NTLM Scheme */
-
-static int
-authenticateNTLMDirection(auth_user_request_t * auth_user_request)
-{
-    ntlm_request_t *ntlm_request = auth_user_request->scheme_data;
-    /* null auth_user is checked for by authenticateDirection */
-    switch (ntlm_request->auth_state) {
-    case AUTHENTICATE_STATE_NONE:	/* no progress at all. */
-	debug(29, 1) ("authenticateNTLMDirection: called before NTLM Authenticate!. Report a bug to squid-dev. au %p\n", auth_user_request);
-	/* fall thru */
-    case AUTHENTICATE_STATE_FAILED:
-	return -2;
-    case AUTHENTICATE_STATE_NEGOTIATE:		/* send to helper */
-    case AUTHENTICATE_STATE_RESPONSE:	/*send to helper */
-	return -1;
-    case AUTHENTICATE_STATE_CHALLENGE:		/* send to client */
-	return 1;
-    case AUTHENTICATE_STATE_DONE:	/* do nothing.. */
-	return 0;
-    }
-    return -2;
-}
-
-/*
- * Send the authenticate error header(s). Note: IE has a bug and the NTLM header
- * must be first. To ensure that, the configure use --enable-auth=ntlm, anything
- * else.
- */
-static void
-authenticateNTLMFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
-{
-    ntlm_request_t *ntlm_request;
-    if (ntlmConfig->authenticate) {
-	/* New request, no user details */
-	if (auth_user_request == NULL) {
-	    debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type);
-	    httpHeaderPutStrf(&rep->header, type, "NTLM");
-	    /* drop the connection */
-	    httpHeaderDelByName(&rep->header, "keep-alive");
-	    /* NTLM has problems if the initial connection is not dropped
-	     * I haven't checked the RFC compliance of this hack - RBCollins */
-	    request->flags.proxy_keepalive = 0;
-	} else {
-	    ntlm_request = auth_user_request->scheme_data;
-	    switch (ntlm_request->auth_state) {
-	    case AUTHENTICATE_STATE_NONE:
-	    case AUTHENTICATE_STATE_FAILED:
-		debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type);
-		httpHeaderPutStrf(&rep->header, type, "NTLM");
-		/* drop the connection */
-		httpHeaderDelByName(&rep->header, "keep-alive");
-		/* NTLM has problems if the initial connection is not dropped
-		 * I haven't checked the RFC compliance of this hack - RBCollins */
-		request->flags.proxy_keepalive = 0;
-		break;
-	    case AUTHENTICATE_STATE_CHALLENGE:
-		/* we are 'waiting' for a response */
-		/* pass the challenge to the client */
-		debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM %s'\n", type, ntlm_request->authchallenge);
-		httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->authchallenge);
-		break;
-	    default:
-		debug(29, 0) ("authenticateNTLMFixErrorHeader: state %d.\n", ntlm_request->auth_state);
-		fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n");
-	    }
-	}
-    }
-}
-
-static void
-authNTLMRequestFree(ntlm_request_t * ntlm_request)
-{
-    if (!ntlm_request)
-	return;
-    if (ntlm_request->ntlmnegotiate)
-	xfree(ntlm_request->ntlmnegotiate);
-    if (ntlm_request->authchallenge)
-	xfree(ntlm_request->authchallenge);
-    if (ntlm_request->ntlmauthenticate)
-	xfree(ntlm_request->ntlmauthenticate);
-    if (ntlm_request->authserver != NULL && ntlm_request->authserver_deferred) {
-	debug(29, 9) ("authenticateNTLMRequestFree: releasing server '%p'\n", ntlm_request->authserver);
-	helperStatefulReleaseServer(ntlm_request->authserver);
-	ntlm_request->authserver = NULL;
-    }
-    memPoolFree(ntlm_request_pool, ntlm_request);
-}
-
-static void
-authNTLMAURequestFree(auth_user_request_t * auth_user_request)
-{
-    if (auth_user_request->scheme_data)
-	authNTLMRequestFree((ntlm_request_t *) auth_user_request->scheme_data);
-    auth_user_request->scheme_data = NULL;
-}
-
-static void
-authenticateNTLMFreeUser(auth_user_t * auth_user)
-{
-    dlink_node *link, *tmplink;
-    ntlm_user_t *ntlm_user = auth_user->scheme_data;
-    auth_user_hash_pointer *proxy_auth_hash;
-
-    debug(29, 5) ("authenticateNTLMFreeUser: Clearing NTLM scheme data\n");
-    if (ntlm_user->username)
-	xfree(ntlm_user->username);
-    /* were they linked in by one or more proxy-authenticate headers */
-    link = ntlm_user->proxy_auth_list.head;
-    while (link) {
-	debug(29, 9) ("authenticateFreeProxyAuthUser: removing proxy_auth hash entry '%p'\n", link->data);
-	proxy_auth_hash = link->data;
-	tmplink = link;
-	link = link->next;
-	dlinkDelete(tmplink, &ntlm_user->proxy_auth_list);
-	hash_remove_link(proxy_auth_cache, (hash_link *) proxy_auth_hash);
-	/* free the key (usually the proxy_auth header) */
-	xfree(proxy_auth_hash->key);
-	memFree(proxy_auth_hash, MEM_AUTH_USER_HASH);
-    }
-    memPoolFree(ntlm_user_pool, ntlm_user);
-    auth_user->scheme_data = NULL;
-}
-
-static stateful_helper_callback_t
-authenticateNTLMHandleplaceholder(void *data, void *lastserver, char *reply)
-{
-    authenticateStateData *r = data;
-    stateful_helper_callback_t result = S_HELPER_UNKNOWN;
-    /* we should only be called for placeholder requests - which have no reply string */
-    assert(reply == NULL);
-    assert(r->auth_user_request);
-    /* standard callback stuff */
-    if (!cbdataReferenceValid(r->data)) {
-	debug(29, 1) ("AuthenticateNTLMHandlePlacheholder: invalid callback data.\n");
-	return result;
-    }
-    /* call authenticateNTLMStart to retry this request */
-    debug(29, 9) ("authenticateNTLMHandleplaceholder: calling authenticateNTLMStart\n");
-    authenticateNTLMStart(r->auth_user_request, r->handler, r->data);
-    cbdataReferenceDone(r->data);
-    authenticateStateFree(r);
-    return result;
-}
-
-static stateful_helper_callback_t
-authenticateNTLMHandleReply(void *data, void *lastserver, char *reply)
-{
-    authenticateStateData *r = data;
-    ntlm_helper_state_t *helperstate;
-    stateful_helper_callback_t result = S_HELPER_UNKNOWN;
-    char *t = NULL;
-    auth_user_request_t *auth_user_request;
-    auth_user_t *auth_user;
-    ntlm_user_t *ntlm_user;
-    ntlm_request_t *ntlm_request;
-    debug(29, 9) ("authenticateNTLMHandleReply: Helper: '%p' {%s}\n", lastserver, reply ? reply : "<NULL>");
-    if (!cbdataReferenceValid(r->data)) {
-	debug(29, 1) ("AuthenticateNTLMHandleReply: invalid callback data. Releasing helper '%p'.\n", lastserver);
-	cbdataReferenceDone(r->data);
-	authenticateStateFree(r);
-	debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", S_HELPER_RELEASE);
-	return S_HELPER_RELEASE;
-    }
-    if (!reply) {
-        /* TODO: this occurs when a helper crashes. We should clean up that helpers resources
-	 * and queued requests.
-	 */
-	fatal("authenticateNTLMHandleReply: called with no result string\n");
-    }
-    /* seperate out the useful data */
-    if (strncasecmp(reply, "TT ", 3) == 0) {
-	reply += 3;
-	/* we have been given a Challenge */
-	/* we should check we weren't given an empty challenge */
-	/* copy the challenge to the state data */
-	helperstate = helperStatefulServerGetData(lastserver);
-	if (helperstate == NULL)
-	    fatal("lost NTLM helper state! quitting\n");
-	helperstate->challenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
-	helperstate->challengeuses = 0;
-	helperstate->renewed = squid_curtime;
-	/* and we satisfy the request that happended on the refresh boundary */
-	/* note this code is now in two places FIXME */
-	assert(r->auth_user_request != NULL);
-	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
-	auth_user_request = r->auth_user_request;
-	ntlm_request = auth_user_request->scheme_data;
-	assert(ntlm_request != NULL);
-	result = S_HELPER_DEFER;
-	/* reserve the server for future authentication */
-	ntlm_request->authserver_deferred = 1;
-	debug(29, 9) ("authenticateNTLMHandleReply: helper '%p'\n", lastserver);
-	assert(ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE);
-	ntlm_request->authserver = lastserver;
-	ntlm_request->authchallenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
-    } else if (strncasecmp(reply, "AF ", 3) == 0) {
-	/* we're finished, release the helper */
-	reply += 3;
-	assert(r->auth_user_request != NULL);
-	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
-	auth_user_request = r->auth_user_request;
-	assert(auth_user_request->scheme_data != NULL);
-	ntlm_request = auth_user_request->scheme_data;
-	auth_user = auth_user_request->auth_user;
-	ntlm_user = auth_user_request->auth_user->scheme_data;
-	assert(ntlm_user != NULL);
-	result = S_HELPER_RELEASE;
-	/* we only expect OK when finishing the handshake */
-	assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
-	ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
-	ntlm_request->authserver = NULL;
-#ifdef NTLM_FAIL_OPEN
-    } else if (strncasecmp(reply, "LD ", 3) == 0) {
-	/* This is a variant of BH, which rather than deny access
-	 * allows the user through. The helper is starved and then refreshed
-	 * via YR, all pending authentications are likely to fail also.
-	 * It is meant for those helpers which occasionally fail for
-	 * no reason at all (casus belli, NTLMSSP helper on NT domain,
-	 * failing about 1 auth out of 1k.
-	 * The code is a merge from the BH case with snippets of the AF
-	 * case */
-	/* AF code: mark user as authenticated */
-	reply += 3;
-	assert(r->auth_user_request != NULL);
-	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
-	auth_user_request = r->auth_user_request;
-	assert(auth_user_request->scheme_data != NULL);
-	ntlm_request = auth_user_request->scheme_data;
-	auth_user = auth_user_request->auth_user;
-	ntlm_user = auth_user_request->auth_user->scheme_data;
-	assert(ntlm_user != NULL);
-	result = S_HELPER_RELEASE;
-	/* we only expect LD when finishing the handshake */
-	assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
-	ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
-	helperstate = helperStatefulServerGetData(ntlm_request->authserver);
-	ntlm_request->authserver = NULL;
-	/* BH code: mark helper as broken */
-	/* mark it for starving */
-	helperstate->starve = 1;
-#endif
-    } else if (strncasecmp(reply, "NA ", 3) == 0) {
-	/* TODO: only work with auth_user here if it exists */
-	assert(r->auth_user_request != NULL);
-	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
-	auth_user_request = r->auth_user_request;
-	auth_user = auth_user_request->auth_user;
-	assert(auth_user != NULL);
-	ntlm_user = auth_user->scheme_data;
-	ntlm_request = auth_user_request->scheme_data;
-	assert((ntlm_user != NULL) && (ntlm_request != NULL));
-	/* todo: action of Negotiate state on error */
-	result = S_HELPER_RELEASE;	/*some error has occured. no more requests */
-	ntlm_request->authserver = NULL;
-	debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
-	ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
-	if ((t = strchr(reply, ' ')))	/* strip after a space */
-	    *t = '\0';
-    } else if (strncasecmp(reply, "NA", 2) == 0) {
-	/* NTLM Helper protocol violation! */
-	fatal("NTLM Helper returned invalid response \"NA\" - a error message MUST be attached\n");
-    } else if (strncasecmp(reply, "BH ", 3) == 0) {
-	/* TODO kick off a refresh process. This can occur after a YR or after
-	 * a KK. If after a YR release the helper and resubmit the request via 
-	 * Authenticate NTLM start. 
-	 * If after a KK deny the user's request w/ 407 and mark the helper as 
-	 * Needing YR. */
-	assert(r->auth_user_request != NULL);
-	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
-	auth_user_request = r->auth_user_request;
-	auth_user = auth_user_request->auth_user;
-	assert(auth_user != NULL);
-	ntlm_user = auth_user->scheme_data;
-	ntlm_request = auth_user_request->scheme_data;
-	assert((ntlm_user != NULL) && (ntlm_request != NULL));
-	result = S_HELPER_RELEASE;	/*some error has occured. no more requests for 
-					 * this helper */
-	assert(ntlm_request->authserver ? ntlm_request->authserver == lastserver : 1);
-	helperstate = helperStatefulServerGetData(ntlm_request->authserver);
-	ntlm_request->authserver = NULL;
-	if (ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE) {
-	    /* The helper broke on YR. It automatically
-	     * resets */
-	    debug(29, 1) ("authenticateNTLMHandleReply: Error obtaining challenge from helper: %p. Error returned '%s'\n", lastserver, reply);
-	    /* mark it for starving */
-	    helperstate->starve = 1;
-	    /* resubmit the request. This helper is currently busy, so we will get
-	     * a different one. Our auth state stays the same */
-	    authenticateNTLMStart(auth_user_request, r->handler, r->data);
-	    /* don't call the callback */
-	    cbdataReferenceDone(r->data);
-	    authenticateStateFree(r);
-	    debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", result);
-	    return result;
-	} 
-	/* the helper broke on a KK */
-	/* first the standard KK stuff */
-	debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
-	if ((t = strchr(reply, ' ')))	/* strip after a space */
-	    *t = '\0';
-	/* now we mark the helper for resetting. */
-	helperstate->starve = 1;
-	ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
-    } else {
-	/* TODO: only work with auth_user here if it exists */
-        /* TODO: take the request state into consideration */
-	assert(r->auth_user_request != NULL);
-	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
-	auth_user_request = r->auth_user_request;
-	auth_user = auth_user_request->auth_user;
-	assert(auth_user != NULL);
-	ntlm_user = auth_user->scheme_data;
-	ntlm_request = auth_user_request->scheme_data;
-	assert((ntlm_user != NULL) && (ntlm_request != NULL));
-	debug(29, 1) ("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
-	/* **** NOTE THIS CODE IS EFFECTIVELY UNTESTED **** */
-	/* restart the authentication process */
-	ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
-	assert (ntlm_request->authserver ? ntlm_request->authserver == lastserver : 1);
-	ntlm_request->authserver = NULL;
-    }
-    r->handler(r->data, NULL);
-    cbdataReferenceDone(r->data);
-    authenticateStateFree(r);
-    debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", result);
-    return result;
-}
-
-static void
-authenticateNTLMStats(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "NTLM Authenticator Statistics:\n");
-    helperStatefulStats(sentry, ntlmauthenticators);
-}
-
-/* is a particular challenge still valid ? */
-static int
-authenticateNTLMValidChallenge(ntlm_helper_state_t * helperstate)
-{
-    debug(29, 9) ("authenticateNTLMValidChallenge: Challenge is %s\n", helperstate->challenge ? "Valid" : "Invalid");
-    if (helperstate->challenge == NULL)
-	return 0;
-    return 1;
-}
-
-/* does our policy call for changing the challenge now? */
-static int
-authenticateNTLMChangeChallenge_p(ntlm_helper_state_t * helperstate)
-{
-    /* don't check for invalid challenges just for expiry choices */
-    /* this is needed because we have to starve the helper until all old
-     * requests have been satisfied */
-    if (!helperstate->renewed) {
-	/* first use, no challenge has been set. Without this check, it will
-	 * loop forever */
-	debug(29, 5) ("authenticateNTLMChangeChallenge_p: first use\n");
-	return 0;
-    }
-    if (helperstate->challengeuses > ntlmConfig->challengeuses) {
-	debug(29, 4) ("authenticateNTLMChangeChallenge_p: Challenge uses (%d) exceeded max uses (%d)\n", helperstate->challengeuses, ntlmConfig->challengeuses);
-	return 1;
-    }
-    if (helperstate->renewed + ntlmConfig->challengelifetime < squid_curtime) {
-	debug(29, 4) ("authenticateNTLMChangeChallenge_p: Challenge exceeded max lifetime by %d seconds\n", (int) (squid_curtime - (helperstate->renewed + ntlmConfig->challengelifetime)));
-	return 1;
-    }
-    debug(29, 9) ("Challenge is to be reused\n");
-    return 0;
-}
-
-/* send the initial data to a stateful ntlm authenticator module */
-static void
-authenticateNTLMStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
-{
-    authenticateStateData *r = NULL;
-    helper_stateful_server *server;
-    ntlm_helper_state_t *helperstate;
-    char buf[8192];
-    char *sent_string = NULL;
-    ntlm_user_t *ntlm_user;
-    ntlm_request_t *ntlm_request;
-    auth_user_t *auth_user;
-
-    assert(auth_user_request);
-    auth_user = auth_user_request->auth_user;
-    ntlm_user = auth_user->scheme_data;
-    ntlm_request = auth_user_request->scheme_data;
-    assert(ntlm_user);
-    assert(ntlm_request);
-    assert(handler);
-    assert(data);
-    assert(auth_user->auth_type = AUTH_NTLM);
-    debug(29, 9) ("authenticateNTLMStart: auth state '%d'\n", ntlm_request->auth_state);
-    switch (ntlm_request->auth_state) {
-    case AUTHENTICATE_STATE_NEGOTIATE:
-	sent_string = ntlm_request->ntlmnegotiate;
-	break;
-    case AUTHENTICATE_STATE_RESPONSE:
-	sent_string = ntlm_request->ntlmauthenticate;
-	assert(ntlm_request->authserver);
-	debug(29, 9) ("authenticateNTLMStart: Asking NTLMauthenticator '%p'.\n", ntlm_request->authserver);
-	break;
-    default:
-	fatal("Invalid authenticate state for NTLMStart");
-    }
-
-    while (!xisspace(*sent_string))	/*trim NTLM */
-	sent_string++;
-
-    while (xisspace(*sent_string))	/*trim leading spaces */
-	sent_string++;
-
-    debug(29, 9) ("authenticateNTLMStart: state '%d'\n", ntlm_request->auth_state);
-    debug(29, 9) ("authenticateNTLMStart: '%s'\n", sent_string);
-    if (ntlmConfig->authenticate == NULL) {
-	debug(29, 0) ("authenticateNTLMStart: no NTLM program specified:'%s'\n", sent_string);
-	handler(data, NULL);
-	return;
-    }
-    /* this is ugly TODO: move the challenge generation routines to their own function and
-     * tidy the logic up to make use of the efficiency we now have */
-    switch (ntlm_request->auth_state) {
-    case AUTHENTICATE_STATE_NEGOTIATE:
-	/*  
-	 * 1: get a helper server
-	 * 2: does it have a challenge?
-	 * 3: tell it to get a challenge, or give ntlmauthdone the challenge
-	 */
-	server = helperStatefulDefer(ntlmauthenticators);
-	helperstate = server ? helperStatefulServerGetData(server) : NULL;
-	while ((server != NULL) && authenticateNTLMChangeChallenge_p(helperstate)) {
-	    /* flag this helper for challenge changing */
-	    helperstate->starve = 1;
-	    /* and release the deferred request */
-	    helperStatefulReleaseServer(server);
-	    /* Get another deferrable server */
-	    server = helperStatefulDefer(ntlmauthenticators);
-	    helperstate = server ? helperStatefulServerGetData(server) : NULL;
-	}
-	if (server == NULL)
-	    debug(29, 9) ("unable to get a deferred ntlm helper... all helpers are refreshing challenges. Queuing as a placeholder request.\n");
-
-	ntlm_request->authserver = server;
-	/* tell the log what helper we have been given */
-	debug(29, 9) ("authenticateNTLMStart: helper '%p' assigned\n", server);
-	/* server and valid challenge? */
-	if ((server == NULL) || !authenticateNTLMValidChallenge(helperstate)) {
-	    /* No server, or server with invalid challenge */
-	    r = cbdataAlloc(authenticateStateData);
-	    r->handler = handler;
-	    r->data = cbdataReference(data);
-	    r->auth_user_request = auth_user_request;
-	    if (server == NULL) {
-		helperStatefulSubmit(ntlmauthenticators, NULL, authenticateNTLMHandleplaceholder, r, NULL);
-	    } else {
-		/* Server with invalid challenge */
-		snprintf(buf, 8192, "YR\n");
-		helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver);
-	    }
-	} else {
-	    /* (server != NULL and we have a valid challenge) */
-	    /* TODO: turn the below into a function and call from here and handlereply */
-	    /* increment the challenge uses */
-	    helperstate->challengeuses++;
-	    /* assign the challenge */
-	    ntlm_request->authchallenge = xstrndup(helperstate->challenge, NTLM_CHALLENGE_SZ + 5);
-	    /* we're not actually submitting a request, so we need to release the helper 
-	     * should the connection close unexpectedly
-	     */
-	    ntlm_request->authserver_deferred = 1;
-	    handler(data, NULL);
-	}
-
-	break;
-    case AUTHENTICATE_STATE_RESPONSE:
-	r = cbdataAlloc(authenticateStateData);
-	r->handler = handler;
-	r->data = cbdataReference(data);
-	r->auth_user_request = auth_user_request;
-	snprintf(buf, 8192, "KK %s\n", sent_string);
-	/* getting rid of deferred request status */
-	ntlm_request->authserver_deferred = 0;
-	helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver);
-	debug(29, 9) ("authenticateNTLMstart: finished\n");
-	break;
-    default:
-	fatal("Invalid authenticate state for NTLMStart");
-    }
-}
-
-/* callback used by stateful helper routines */
-static int
-authenticateNTLMHelperServerAvailable(void *data)
-{
-    ntlm_helper_state_t *statedata = data;
-    if (statedata != NULL) {
-	if (statedata->starve) {
-	    debug(29, 4) ("authenticateNTLMHelperServerAvailable: starving - returning 0\n");
-	    return 0;
-	} else {
-	    debug(29, 4) ("authenticateNTLMHelperServerAvailable: not starving - returning 1\n");
-	    return 1;
-	}
-    }
-    debug(29, 4) ("authenticateNTLMHelperServerAvailable: no state data - returning 0\n");
-    return 0;
-}
-
-static void
-authenticateNTLMHelperServerOnEmpty(void *data)
-{
-    ntlm_helper_state_t *statedata = data;
-    if (statedata == NULL)
-	return;
-    if (statedata->starve) {
-	/* we have been starving the helper */
-	debug(29, 9) ("authenticateNTLMHelperServerOnEmpty: resetting challenge details\n");
-	statedata->starve = 0;
-	statedata->challengeuses = 0;
-	statedata->renewed = 0;
-	xfree(statedata->challenge);
-	statedata->challenge = NULL;
-    }
-}
-
-
-/* clear the NTLM helper of being reserved for future requests */
-static void
-authenticateNTLMReleaseServer(auth_user_request_t * auth_user_request)
-{
-    ntlm_request_t *ntlm_request;
-    assert(auth_user_request->auth_user->auth_type == AUTH_NTLM);
-    assert(auth_user_request->scheme_data != NULL);
-    ntlm_request = auth_user_request->scheme_data;
-    debug(29, 9) ("authenticateNTLMReleaseServer: releasing server '%p'\n", ntlm_request->authserver);
-    helperStatefulReleaseServer(ntlm_request->authserver);
-    ntlm_request->authserver = NULL;
-}
-
-/* clear any connection related authentication details */
-static void
-authenticateNTLMOnCloseConnection(ConnStateData * conn)
-{
-    ntlm_request_t *ntlm_request;
-    assert(conn != NULL);
-    if (conn->auth_user_request != NULL) {
-	assert(conn->auth_user_request->scheme_data != NULL);
-	ntlm_request = conn->auth_user_request->scheme_data;
-	assert(ntlm_request->conn == conn);
-	if (ntlm_request->authserver != NULL && ntlm_request->authserver_deferred)
-	    authenticateNTLMReleaseServer(conn->auth_user_request);
-	/* unlock the connection based lock */
-	debug(29, 9) ("authenticateNTLMOnCloseConnection: Unlocking auth_user from the connection.\n");
-	/* minor abstraction break here: FIXME */
-	/* Ensure that the auth user request will be getting closed */
-	/* IFF we start persisting the struct after the conn closes - say for logging
-	 * then this test may become invalid
-	 */
-	assert(conn->auth_user_request->references == 1);
-	authenticateAuthUserRequestUnlock(conn->auth_user_request);
-	conn->auth_user_request = NULL;
-    }
-}
-
-/* authenticateUserUsername: return a pointer to the username in the */
-static char *
-authenticateNTLMUsername(auth_user_t * auth_user)
-{
-    ntlm_user_t *ntlm_user = auth_user->scheme_data;
-    if (ntlm_user)
-	return ntlm_user->username;
-    return NULL;
-}
-
-/* NTLMLastHeader: return a pointer to the last header used in authenticating
- * the request/conneciton
- */
-static const char *
-NTLMLastHeader(auth_user_request_t * auth_user_request)
-{
-    ntlm_request_t *ntlm_request;
-    assert(auth_user_request != NULL);
-    assert(auth_user_request->scheme_data != NULL);
-    ntlm_request = auth_user_request->scheme_data;
-    return ntlm_request->ntlmauthenticate;
-}
-
-/*
- * Decode an NTLM [Proxy-]Auth string, placing the results in the passed
- * Auth_user structure.
- */
-
-static void
-authenticateDecodeNTLMAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
-{
-    dlink_node *node;
-    assert(auth_user_request->auth_user == NULL);
-    auth_user_request->auth_user = authenticateAuthUserNew("ntlm");
-    auth_user_request->auth_user->auth_type = AUTH_NTLM;
-    auth_user_request->auth_user->scheme_data = memPoolAlloc(ntlm_user_pool);
-    auth_user_request->scheme_data = memPoolAlloc(ntlm_request_pool);
-    memset(auth_user_request->scheme_data, '\0', sizeof(ntlm_request_t));
-    /* lock for the auth_user_request link */
-    authenticateAuthUserLock(auth_user_request->auth_user);
-    node = dlinkNodeNew();
-    dlinkAdd(auth_user_request, node, &auth_user_request->auth_user->requests);
-
-    /* all we have to do is identify that it's NTLM - the helper does the rest */
-    debug(29, 9) ("authenticateDecodeNTLMAuth: NTLM authentication\n");
-    return;
-}
-
-static int
-authenticateNTLMcmpUsername(ntlm_user_t * u1, ntlm_user_t * u2)
-{
-    return strcmp(u1->username, u2->username);
-}
-
-
-/* there is a known race where a single client recieves the same challenge
- * and sends the same response to squid on a single select cycle.
- * Check for this and if found ignore the new link 
- */
-static void
-authenticateProxyAuthCacheAddLink(const char *key, auth_user_t * auth_user)
-{
-    auth_user_hash_pointer *proxy_auth_hash;
-    dlink_node *node;
-    ntlm_user_t *ntlm_user;
-    ntlm_user = auth_user->scheme_data;
-    node = ntlm_user->proxy_auth_list.head;
-    /* prevent duplicates */
-    while (node) {
-	if (!strcmp(key, ((auth_user_hash_pointer *) node->data)->key))
-	    return;
-	node = node->next;
-    }
-    proxy_auth_hash = memAllocate(MEM_AUTH_USER_HASH);
-    proxy_auth_hash->key = xstrdup(key);
-    proxy_auth_hash->auth_user = auth_user;
-    dlinkAddTail(proxy_auth_hash, &proxy_auth_hash->link, &ntlm_user->proxy_auth_list);
-    hash_join(proxy_auth_cache, (hash_link *) proxy_auth_hash);
-}
-
-
-static int
-authNTLMAuthenticated(auth_user_request_t * auth_user_request)
-{
-    ntlm_request_t *ntlm_request = auth_user_request->scheme_data;
-    if (ntlm_request->auth_state == AUTHENTICATE_STATE_DONE)
-	return 1;
-    debug(29, 9) ("User not fully authenticated.\n");
-    return 0;
-}
-
-static void
-authenticateNTLMAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
-{
-    const char *proxy_auth;
-    auth_user_hash_pointer *usernamehash, *proxy_auth_hash = NULL;
-    auth_user_t *auth_user;
-    ntlm_request_t *ntlm_request;
-    ntlm_user_t *ntlm_user;
-    LOCAL_ARRAY(char, ntlmhash, NTLM_CHALLENGE_SZ * 2);
-    /* get header */
-    proxy_auth = httpHeaderGetStr(&request->header, type);
-
-    auth_user = auth_user_request->auth_user;
-    assert(auth_user);
-    assert(auth_user->auth_type == AUTH_NTLM);
-    assert(auth_user->scheme_data != NULL);
-    assert(auth_user_request->scheme_data != NULL);
-    ntlm_user = auth_user->scheme_data;
-    ntlm_request = auth_user_request->scheme_data;
-    switch (ntlm_request->auth_state) {
-    case AUTHENTICATE_STATE_NONE:
-	/* we've recieved a negotiate request. pass to a helper */
-	debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state ntlm none. %s\n", proxy_auth);
-	ntlm_request->auth_state = AUTHENTICATE_STATE_NEGOTIATE;
-	ntlm_request->ntlmnegotiate = xstrndup(proxy_auth, NTLM_CHALLENGE_SZ + 5);
-	conn->auth_type = AUTH_NTLM;
-	conn->auth_user_request = auth_user_request;
-	ntlm_request->conn = conn;
-	/* and lock for the connection duration */
-	debug(29, 9) ("authenticateNTLMAuthenticateUser: Locking auth_user from the connection.\n");
-	authenticateAuthUserRequestLock(auth_user_request);
-	return;
-	break;
-    case AUTHENTICATE_STATE_NEGOTIATE:
-	ntlm_request->auth_state = AUTHENTICATE_STATE_CHALLENGE;
-	/* We _MUST_ have the auth challenge by now */
-	assert(ntlm_request->authchallenge);
-	return;
-	break;
-    case AUTHENTICATE_STATE_CHALLENGE:
-	/* we should have recieved a NTLM challenge. pass it to the same 
-	 * helper process */
-	debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state challenge with header %s.\n", proxy_auth);
-	/* do a cache lookup here. If it matches it's a successful ntlm 
-	 * challenge - release the helper and use the existing auth_user 
-	 * details. */
-	if (strncmp("NTLM ", proxy_auth, 5) == 0) {
-	    ntlm_request->ntlmauthenticate = xstrdup(proxy_auth);
-	} else {
-	    fatal("Incorrect scheme in auth header\n");
-	    /* TODO: more fault tolerance.. reset the auth scheme here */
-	}
-	/* cache entries have authenticateauthheaderchallengestring */
-	snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s",
-	    ntlm_request->ntlmauthenticate,
-	    ntlm_request->authchallenge);
-	/* see if we already know this user's authenticate */
-	debug(29, 9) ("aclMatchProxyAuth: cache lookup with key '%s'\n", ntlmhash);
-	assert(proxy_auth_cache != NULL);
-	proxy_auth_hash = hash_lookup(proxy_auth_cache, ntlmhash);
-	if (!proxy_auth_hash) {	/* not in the hash table */
-	    debug(29, 4) ("authenticateNTLMAuthenticateUser: proxy-auth cache miss.\n");
-	    ntlm_request->auth_state = AUTHENTICATE_STATE_RESPONSE;
-	    /* verify with the ntlm helper */
-	} else {
-	    debug(29, 4) ("authenticateNTLMAuthenticateUser: ntlm proxy-auth cache hit\n");
-	    /* throw away the temporary entry */
-	    ntlm_request->authserver_deferred = 0;
-	    authenticateNTLMReleaseServer(auth_user_request);
-	    authenticateAuthUserMerge(auth_user, proxy_auth_hash->auth_user);
-	    auth_user = proxy_auth_hash->auth_user;
-	    auth_user_request->auth_user = auth_user;
-	    ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
-	    /* we found one */
-	    debug(29, 9) ("found matching cache entry\n");
-	    assert(auth_user->auth_type == AUTH_NTLM);
-	    /* get the existing entries details */
-	    ntlm_user = auth_user->scheme_data;
-	    debug(29, 9) ("Username to be used is %s\n", ntlm_user->username);
-	    /* on ntlm auth we do not unlock the auth_user until the
-	     * connection is dropped. Thank MS for this quirk */
-	    auth_user->expiretime = current_time.tv_sec;
-	}
-	return;
-	break;
-    case AUTHENTICATE_STATE_RESPONSE:
-	/* auth-challenge pair cache miss. We've just got the response from the helper */
-	/*add to cache and let them through */
-	ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
-	/* this connection is authenticated */
-	debug(29, 4) ("authenticated\nch    %s\nauth     %s\nauthuser %s\n",
-	    ntlm_request->authchallenge,
-	    ntlm_request->ntlmauthenticate,
-	    ntlm_user->username);
-	/* cache entries have authenticateauthheaderchallengestring */
-	snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s",
-	    ntlm_request->ntlmauthenticate,
-	    ntlm_request->authchallenge);
-	/* see if this is an existing user with a different proxy_auth 
-	 * string */
-	if ((usernamehash = hash_lookup(proxy_auth_username_cache, ntlm_user->username))) {
-	    while ((usernamehash->auth_user->auth_type != auth_user->auth_type) && (usernamehash->next) && !authenticateNTLMcmpUsername(usernamehash->auth_user->scheme_data, ntlm_user))
-		usernamehash = usernamehash->next;
-	    if (usernamehash->auth_user->auth_type == auth_user->auth_type) {
-		/*
-		 * add another link from the new proxy_auth to the
-		 * auth_user structure and update the information */
-		assert(proxy_auth_hash == NULL);
-		authenticateProxyAuthCacheAddLink(ntlmhash, usernamehash->auth_user);
-		/* we can't seamlessly recheck the username due to the 
-		 * challenge nature of the protocol. Just free the 
-		 * temporary auth_user */
-		authenticateAuthUserMerge(auth_user, usernamehash->auth_user);
-		auth_user = usernamehash->auth_user;
-		auth_user_request->auth_user = auth_user;
-	    }
-	} else {
-	    /* store user in hash's */
-	    authenticateUserNameCacheAdd(auth_user);
-	    authenticateProxyAuthCacheAddLink(ntlmhash, auth_user);
-	}
-	/* set these to now because this is either a new login from an 
-	 * existing user or a new user */
-	auth_user->expiretime = current_time.tv_sec;
-	return;
-	break;
-    case AUTHENTICATE_STATE_DONE:
-	fatal("authenticateNTLMAuthenticateUser: unexpect auth state DONE! Report a bug to the squid developers.\n");
-	break;
-    case AUTHENTICATE_STATE_FAILED:
-	/* we've failed somewhere in authentication */
-	debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state ntlm failed. %s\n", proxy_auth);
-	return;
-    }
-    return;
-}
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/auth/ntlm/auth_ntlm.cc	Wed Feb 14 01:07:15 2007
@@ -0,0 +1,1072 @@
+
+/*
+ * $Id: auth_ntlm.cc,v 1.1.2.1 2002/10/03 01:04:38 rbcollins Exp $
+ *
+ * DEBUG: section 29    NTLM Authenticator
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  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.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/* The functions in this file handle authentication.
+ * They DO NOT perform access control or auditing.
+ * See acl.c for access control and client_side.c for auditing */
+
+
+#include "squid.h"
+#include "auth_ntlm.h"
+#include "authenticate.h"
+
+extern AUTHSSETUP authSchemeSetup_ntlm;
+
+static void
+authenticateStateFree(authenticateStateData * r)
+{
+    cbdataFree(r);
+}
+
+/* NTLM Scheme */
+static HLPSCB authenticateNTLMHandleReply;
+static HLPSCB authenticateNTLMHandleplaceholder;
+static AUTHSACTIVE authenticateNTLMActive;
+static AUTHSAUTHED authNTLMAuthenticated;
+static AUTHSAUTHUSER authenticateNTLMAuthenticateUser;
+static AUTHSCONFIGURED authNTLMConfigured;
+static AUTHSFIXERR authenticateNTLMFixErrorHeader;
+static AUTHSFREE authenticateNTLMFreeUser;
+static AUTHSDIRECTION authenticateNTLMDirection;
+static AUTHSDECODE authenticateDecodeNTLMAuth;
+static AUTHSDUMP authNTLMCfgDump;
+static AUTHSFREECONFIG authNTLMFreeConfig;
+static AUTHSINIT authNTLMInit;
+static AUTHSONCLOSEC authenticateNTLMOnCloseConnection;
+static AUTHSCONNLASTHEADER NTLMLastHeader;
+static AUTHSUSERNAME authenticateNTLMUsername;
+static AUTHSREQFREE authNTLMAURequestFree;
+static AUTHSPARSE authNTLMParse;
+static AUTHSSTART authenticateNTLMStart;
+static AUTHSSTATS authenticateNTLMStats;
+static AUTHSSHUTDOWN authNTLMDone;
+
+/* helper callbacks to handle per server state data */
+static HLPSAVAIL authenticateNTLMHelperServerAvailable;
+static HLPSONEQ authenticateNTLMHelperServerOnEmpty;
+
+static statefulhelper *ntlmauthenticators = NULL;
+
+CBDATA_TYPE(authenticateStateData);
+
+static int authntlm_initialised = 0;
+
+static MemPool *ntlm_helper_state_pool = NULL;
+static MemPool *ntlm_user_pool = NULL;
+static MemPool *ntlm_request_pool = NULL;
+static MemPool *ntlm_user_hash_pool = NULL;
+
+static auth_ntlm_config *ntlmConfig = NULL;
+
+static hash_table *proxy_auth_cache = NULL;
+
+/*
+ *
+ * Private Functions
+ *
+ */
+
+static void
+authNTLMDone(void)
+{
+    debug(29, 2) ("authNTLMDone: shutting down NTLM authentication.\n");
+    if (ntlmauthenticators)
+	helperStatefulShutdown(ntlmauthenticators);
+    authntlm_initialised = 0;
+    if (!shutting_down)
+	return;
+    if (ntlmauthenticators)
+	helperStatefulFree(ntlmauthenticators);
+    ntlmauthenticators = NULL;
+    if (ntlm_helper_state_pool) {
+	assert(memPoolInUseCount(ntlm_helper_state_pool) == 0);
+	memPoolDestroy(&ntlm_helper_state_pool);
+    }
+    if (ntlm_request_pool) {
+	assert(memPoolInUseCount(ntlm_request_pool) == 0);
+	memPoolDestroy(&ntlm_request_pool);
+    }
+    if (ntlm_user_pool) {
+	assert(memPoolInUseCount(ntlm_user_pool) == 0);
+	memPoolDestroy(&ntlm_user_pool);
+    }
+    debug(29, 2) ("authNTLMDone: NTLM authentication Shutdown.\n");
+}
+
+/* free any allocated configuration details */
+static void
+authNTLMFreeConfig(authScheme * scheme)
+{
+    if (ntlmConfig == NULL)
+	return;
+    assert(ntlmConfig == scheme->scheme_data);
+    if (ntlmConfig->authenticate)
+	wordlistDestroy(&ntlmConfig->authenticate);
+    xfree(ntlmConfig);
+    ntlmConfig = NULL;
+}
+
+static void
+authNTLMCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
+{
+    auth_ntlm_config *config = static_cast<auth_ntlm_config *>(scheme->scheme_data);
+    wordlist *list = config->authenticate;
+    storeAppendPrintf(entry, "%s %s", name, "ntlm");
+    while (list != NULL) {
+	storeAppendPrintf(entry, " %s", list->key);
+	list = list->next;
+    }
+    storeAppendPrintf(entry, "\n%s %s children %d\n%s %s max_challenge_reuses %d\n%s %s max_challenge_lifetime %d seconds\n",
+	name, "ntlm", config->authenticateChildren,
+	name, "ntlm", config->challengeuses,
+	name, "ntlm", (int)config->challengelifetime);
+
+}
+
+static void
+authNTLMParse(authScheme * scheme, int n_configured, char *param_str)
+{
+    if (scheme->scheme_data == NULL) {
+	assert(ntlmConfig == NULL);
+	/* this is the first param to be found */
+	scheme->scheme_data = xmalloc(sizeof(auth_ntlm_config));
+	memset(scheme->scheme_data, 0, sizeof(auth_ntlm_config));
+	ntlmConfig = static_cast<auth_ntlm_config *>(scheme->scheme_data);
+	ntlmConfig->authenticateChildren = 5;
+	ntlmConfig->challengeuses = 0;
+	ntlmConfig->challengelifetime = 60;
+    }
+    ntlmConfig = static_cast<auth_ntlm_config *>(scheme->scheme_data);
+    if (strcasecmp(param_str, "program") == 0) {
+	if (ntlmConfig->authenticate)
+	    wordlistDestroy(&ntlmConfig->authenticate);
+	parse_wordlist(&ntlmConfig->authenticate);
+	requirePathnameExists("authparam ntlm program", ntlmConfig->authenticate->key);
+    } else if (strcasecmp(param_str, "children") == 0) {
+	parse_int(&ntlmConfig->authenticateChildren);
+    } else if (strcasecmp(param_str, "max_challenge_reuses") == 0) {
+	parse_int(&ntlmConfig->challengeuses);
+    } else if (strcasecmp(param_str, "max_challenge_lifetime") == 0) {
+	parse_time_t(&ntlmConfig->challengelifetime);
+    } else {
+	debug(28, 0) ("unrecognised ntlm auth scheme parameter '%s'\n", param_str);
+    }
+    /*
+     * disable client side request pipelining. There is a race with
+     * NTLM when the client sends a second request on an NTLM
+     * connection before the authenticate challenge is sent. With
+     * this patch, the client may fail to authenticate, but squid's
+     * state will be preserved.  Caveats: this should be a post-parse
+     * test, but that can wait for the modular parser to be integrated.
+     */
+    if (ntlmConfig->authenticate)
+	Config.onoff.pipeline_prefetch = 0;
+}
+
+
+void
+authSchemeSetup_ntlm(authscheme_entry_t * authscheme)
+{
+    assert(!authntlm_initialised);
+    authscheme->Active = authenticateNTLMActive;
+    authscheme->configured = authNTLMConfigured;
+    authscheme->parse = authNTLMParse;
+    authscheme->dump = authNTLMCfgDump;
+    authscheme->requestFree = authNTLMAURequestFree;
+    authscheme->freeconfig = authNTLMFreeConfig;
+    authscheme->init = authNTLMInit;
+    authscheme->authAuthenticate = authenticateNTLMAuthenticateUser;
+    authscheme->authenticated = authNTLMAuthenticated;
+    authscheme->authFixHeader = authenticateNTLMFixErrorHeader;
+    authscheme->FreeUser = authenticateNTLMFreeUser;
+    authscheme->authStart = authenticateNTLMStart;
+    authscheme->authStats = authenticateNTLMStats;
+    authscheme->authUserUsername = authenticateNTLMUsername;
+    authscheme->getdirection = authenticateNTLMDirection;
+    authscheme->decodeauth = authenticateDecodeNTLMAuth;
+    authscheme->donefunc = authNTLMDone;
+    authscheme->oncloseconnection = authenticateNTLMOnCloseConnection;
+    authscheme->authConnLastHeader = NTLMLastHeader;
+}
+
+/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
+ * config file */
+static void
+authNTLMInit(authScheme * scheme)
+{
+    static int ntlminit = 0;
+    if (ntlmConfig->authenticate) {
+	if (!ntlm_helper_state_pool)
+	    ntlm_helper_state_pool = memPoolCreate("NTLM Helper State data", sizeof(ntlm_helper_state_t));
+	if (!ntlm_user_pool)
+	    ntlm_user_pool = memPoolCreate("NTLM Scheme User Data", sizeof(ntlm_user_t));
+	if (!ntlm_request_pool)
+	    ntlm_request_pool = memPoolCreate("NTLM Scheme Request Data", sizeof(ntlm_request_t));
+	if (!ntlm_user_hash_pool)
+	    ntlm_user_hash_pool = memPoolCreate("NTLM Header Hash Data", sizeof(struct ProxyAuthCachePointer));
+	authntlm_initialised = 1;
+	if (ntlmauthenticators == NULL)
+	    ntlmauthenticators = helperStatefulCreate("ntlmauthenticator");
+	if (!proxy_auth_cache)
+	    proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
+	assert(proxy_auth_cache);
+	ntlmauthenticators->cmdline = ntlmConfig->authenticate;
+	ntlmauthenticators->n_to_start = ntlmConfig->authenticateChildren;
+	ntlmauthenticators->ipc_type = IPC_STREAM;
+	ntlmauthenticators->datapool = ntlm_helper_state_pool;
+	ntlmauthenticators->IsAvailable = authenticateNTLMHelperServerAvailable;
+	ntlmauthenticators->OnEmptyQueue = authenticateNTLMHelperServerOnEmpty;
+	helperStatefulOpenServers(ntlmauthenticators);
+	/* TODO: In here send the initial YR to preinitialise the challenge cache */
+	/* Think about this... currently we ask when the challenge is needed. Better? */
+	if (!ntlminit) {
+	    cachemgrRegister("ntlmauthenticator", "User NTLM Authenticator Stats", authenticateNTLMStats, 0, 1);
+	    ntlminit++;
+	}
+	CBDATA_INIT_TYPE(authenticateStateData);
+    }
+}
+
+static int
+authenticateNTLMActive()
+{
+    return (authntlm_initialised == 1) ? 1 : 0;
+}
+
+
+static int
+authNTLMConfigured()
+{
+    if ((ntlmConfig != NULL) && (ntlmConfig->authenticate != NULL) && (ntlmConfig->authenticateChildren != 0) && (ntlmConfig->challengeuses > -1) && (ntlmConfig->challengelifetime > -1)) {
+	debug(29, 9) ("authNTLMConfigured: returning configured\n");
+	return 1;
+    }
+    debug(29, 9) ("authNTLMConfigured: returning unconfigured\n");
+    return 0;
+}
+
+/* NTLM Scheme */
+
+static int
+authenticateNTLMDirection(auth_user_request_t * auth_user_request)
+{
+    ntlm_request_t *ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+    /* null auth_user is checked for by authenticateDirection */
+    switch (ntlm_request->auth_state) {
+    case AUTHENTICATE_STATE_NONE:	/* no progress at all. */
+	debug(29, 1) ("authenticateNTLMDirection: called before NTLM Authenticate!. Report a bug to squid-dev. au %p\n", auth_user_request);
+	/* fall thru */
+    case AUTHENTICATE_STATE_FAILED:
+	return -2;
+    case AUTHENTICATE_STATE_NEGOTIATE:		/* send to helper */
+    case AUTHENTICATE_STATE_RESPONSE:	/*send to helper */
+	return -1;
+    case AUTHENTICATE_STATE_CHALLENGE:		/* send to client */
+	return 1;
+    case AUTHENTICATE_STATE_DONE:	/* do nothing.. */
+	return 0;
+    }
+    return -2;
+}
+
+/*
+ * Send the authenticate error header(s). Note: IE has a bug and the NTLM header
+ * must be first. To ensure that, the configure use --enable-auth=ntlm, anything
+ * else.
+ */
+static void
+authenticateNTLMFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
+{
+    ntlm_request_t *ntlm_request;
+    if (ntlmConfig->authenticate) {
+	/* New request, no user details */
+	if (auth_user_request == NULL) {
+	    debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type);
+	    httpHeaderPutStrf(&rep->header, type, "NTLM");
+	    /* drop the connection */
+	    httpHeaderDelByName(&rep->header, "keep-alive");
+	    /* NTLM has problems if the initial connection is not dropped
+	     * I haven't checked the RFC compliance of this hack - RBCollins */
+	    request->flags.proxy_keepalive = 0;
+	} else {
+	    ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+	    switch (ntlm_request->auth_state) {
+	    case AUTHENTICATE_STATE_NONE:
+	    case AUTHENTICATE_STATE_FAILED:
+		debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type);
+		httpHeaderPutStrf(&rep->header, type, "NTLM");
+		/* drop the connection */
+		httpHeaderDelByName(&rep->header, "keep-alive");
+		/* NTLM has problems if the initial connection is not dropped
+		 * I haven't checked the RFC compliance of this hack - RBCollins */
+		request->flags.proxy_keepalive = 0;
+		break;
+	    case AUTHENTICATE_STATE_CHALLENGE:
+		/* we are 'waiting' for a response */
+		/* pass the challenge to the client */
+		debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM %s'\n", type, ntlm_request->authchallenge);
+		httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->authchallenge);
+		break;
+	    default:
+		debug(29, 0) ("authenticateNTLMFixErrorHeader: state %d.\n", ntlm_request->auth_state);
+		fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n");
+	    }
+	}
+    }
+}
+
+static void
+authNTLMRequestFree(ntlm_request_t * ntlm_request)
+{
+    if (!ntlm_request)
+	return;
+    if (ntlm_request->ntlmnegotiate)
+	xfree(ntlm_request->ntlmnegotiate);
+    if (ntlm_request->authchallenge)
+	xfree(ntlm_request->authchallenge);
+    if (ntlm_request->ntlmauthenticate)
+	xfree(ntlm_request->ntlmauthenticate);
+    if (ntlm_request->authserver != NULL && ntlm_request->authserver_deferred) {
+	debug(29, 9) ("authenticateNTLMRequestFree: releasing server '%p'\n", ntlm_request->authserver);
+	helperStatefulReleaseServer(ntlm_request->authserver);
+	ntlm_request->authserver = NULL;
+    }
+    memPoolFree(ntlm_request_pool, ntlm_request);
+}
+
+static void
+authNTLMAURequestFree(auth_user_request_t * auth_user_request)
+{
+    if (auth_user_request->scheme_data)
+	authNTLMRequestFree(static_cast< ntlm_request_t *>(auth_user_request->scheme_data));
+    auth_user_request->scheme_data = NULL;
+}
+
+static void
+authenticateNTLMFreeUser(auth_user_t * auth_user)
+{
+    dlink_node *link, *tmplink;
+    ntlm_user_t *ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+    ProxyAuthCachePointer *proxy_auth_hash;
+
+    debug(29, 5) ("authenticateNTLMFreeUser: Clearing NTLM scheme data\n");
+    if (ntlm_user->username)
+	xfree(ntlm_user->username);
+    /* were they linked in by one or more proxy-authenticate headers */
+    link = ntlm_user->proxy_auth_list.head;
+    while (link) {
+	debug(29, 9) ("authenticateFreeProxyAuthUser: removing proxy_auth hash entry '%p'\n", link->data);
+	proxy_auth_hash = static_cast<ProxyAuthCachePointer *>(link->data);
+	tmplink = link;
+	link = link->next;
+	dlinkDelete(tmplink, &ntlm_user->proxy_auth_list);
+	hash_remove_link(proxy_auth_cache, (hash_link *) proxy_auth_hash);
+	/* free the key (usually the proxy_auth header) */
+	xfree(proxy_auth_hash->key);
+	memPoolFree(ntlm_user_hash_pool, proxy_auth_hash);
+    }
+    memPoolFree(ntlm_user_pool, ntlm_user);
+    auth_user->scheme_data = NULL;
+}
+
+static stateful_helper_callback_t
+authenticateNTLMHandleplaceholder(void *data, void *lastserver, char *reply)
+{
+    authenticateStateData *r = static_cast<authenticateStateData *>(data);
+    stateful_helper_callback_t result = S_HELPER_UNKNOWN;
+    /* we should only be called for placeholder requests - which have no reply string */
+    assert(reply == NULL);
+    assert(r->auth_user_request);
+    /* standard callback stuff */
+    if (!cbdataReferenceValid(r->data)) {
+	debug(29, 1) ("AuthenticateNTLMHandlePlacheholder: invalid callback data.\n");
+	return result;
+    }
+    /* call authenticateNTLMStart to retry this request */
+    debug(29, 9) ("authenticateNTLMHandleplaceholder: calling authenticateNTLMStart\n");
+    authenticateNTLMStart(r->auth_user_request, r->handler, r->data);
+    cbdataReferenceDone(r->data);
+    authenticateStateFree(r);
+    return result;
+}
+
+static stateful_helper_callback_t
+authenticateNTLMHandleReply(void *data, void *lastserver, char *reply)
+{
+    authenticateStateData *r = static_cast<authenticateStateData *>(data);
+    ntlm_helper_state_t *helperstate;
+    stateful_helper_callback_t result = S_HELPER_UNKNOWN;
+    char *t = NULL;
+    auth_user_request_t *auth_user_request;
+    auth_user_t *auth_user;
+    ntlm_user_t *ntlm_user;
+    ntlm_request_t *ntlm_request;
+    debug(29, 9) ("authenticateNTLMHandleReply: Helper: '%p' {%s}\n", lastserver, reply ? reply : "<NULL>");
+    if (!cbdataReferenceValid(r->data)) {
+	debug(29, 1) ("AuthenticateNTLMHandleReply: invalid callback data. Releasing helper '%p'.\n", lastserver);
+	cbdataReferenceDone(r->data);
+	authenticateStateFree(r);
+	debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", S_HELPER_RELEASE);
+	return S_HELPER_RELEASE;
+    }
+    if (!reply) {
+        /* TODO: this occurs when a helper crashes. We should clean up that helpers resources
+	 * and queued requests.
+	 */
+	fatal("authenticateNTLMHandleReply: called with no result string\n");
+    }
+    /* seperate out the useful data */
+    if (strncasecmp(reply, "TT ", 3) == 0) {
+	reply += 3;
+	/* we have been given a Challenge */
+	/* we should check we weren't given an empty challenge */
+	/* copy the challenge to the state data */
+	helperstate = static_cast<ntlm_helper_state_t *>(helperStatefulServerGetData(static_cast<helper_stateful_server *>(lastserver)));
+	if (helperstate == NULL)
+	    fatal("lost NTLM helper state! quitting\n");
+	helperstate->challenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
+	helperstate->challengeuses = 0;
+	helperstate->renewed = squid_curtime;
+	/* and we satisfy the request that happended on the refresh boundary */
+	/* note this code is now in two places FIXME */
+	assert(r->auth_user_request != NULL);
+	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+	auth_user_request = r->auth_user_request;
+	ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+	assert(ntlm_request != NULL);
+	result = S_HELPER_DEFER;
+	/* reserve the server for future authentication */
+	ntlm_request->authserver_deferred = 1;
+	debug(29, 9) ("authenticateNTLMHandleReply: helper '%p'\n", lastserver);
+	assert(ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE);
+	ntlm_request->authserver = static_cast<helper_stateful_server *>(lastserver);
+	ntlm_request->authchallenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
+    } else if (strncasecmp(reply, "AF ", 3) == 0) {
+	/* we're finished, release the helper */
+	reply += 3;
+	assert(r->auth_user_request != NULL);
+	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+	auth_user_request = r->auth_user_request;
+	assert(auth_user_request->scheme_data != NULL);
+	ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+	auth_user = auth_user_request->auth_user;
+	ntlm_user = static_cast<ntlm_user_t *>(auth_user_request->auth_user->scheme_data);
+	assert(ntlm_user != NULL);
+	result = S_HELPER_RELEASE;
+	/* we only expect OK when finishing the handshake */
+	assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
+	ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
+	ntlm_request->authserver = NULL;
+#ifdef NTLM_FAIL_OPEN
+    } else if (strncasecmp(reply, "LD ", 3) == 0) {
+	/* This is a variant of BH, which rather than deny access
+	 * allows the user through. The helper is starved and then refreshed
+	 * via YR, all pending authentications are likely to fail also.
+	 * It is meant for those helpers which occasionally fail for
+	 * no reason at all (casus belli, NTLMSSP helper on NT domain,
+	 * failing about 1 auth out of 1k.
+	 * The code is a merge from the BH case with snippets of the AF
+	 * case */
+	/* AF code: mark user as authenticated */
+	reply += 3;
+	assert(r->auth_user_request != NULL);
+	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+	auth_user_request = r->auth_user_request;
+	assert(auth_user_request->scheme_data != NULL);
+	ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+	auth_user = auth_user_request->auth_user;
+	ntlm_user = static_cast<ntlm_user_t *>(auth_user_request->auth_user->scheme_data);
+	assert(ntlm_user != NULL);
+	result = S_HELPER_RELEASE;
+	/* we only expect LD when finishing the handshake */
+	assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
+	ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
+	helperstate = helperStatefulServerGetData(ntlm_request->authserver);
+	ntlm_request->authserver = NULL;
+	/* BH code: mark helper as broken */
+	/* mark it for starving */
+	helperstate->starve = 1;
+#endif
+    } else if (strncasecmp(reply, "NA ", 3) == 0) {
+	/* TODO: only work with auth_user here if it exists */
+	assert(r->auth_user_request != NULL);
+	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+	auth_user_request = r->auth_user_request;
+	auth_user = auth_user_request->auth_user;
+	assert(auth_user != NULL);
+	ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+	ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+	assert((ntlm_user != NULL) && (ntlm_request != NULL));
+	/* todo: action of Negotiate state on error */
+	result = S_HELPER_RELEASE;	/*some error has occured. no more requests */
+	ntlm_request->authserver = NULL;
+	debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
+	ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
+	if ((t = strchr(reply, ' ')))	/* strip after a space */
+	    *t = '\0';
+    } else if (strncasecmp(reply, "NA", 2) == 0) {
+	/* NTLM Helper protocol violation! */
+	fatal("NTLM Helper returned invalid response \"NA\" - a error message MUST be attached\n");
+    } else if (strncasecmp(reply, "BH ", 3) == 0) {
+	/* TODO kick off a refresh process. This can occur after a YR or after
+	 * a KK. If after a YR release the helper and resubmit the request via 
+	 * Authenticate NTLM start. 
+	 * If after a KK deny the user's request w/ 407 and mark the helper as 
+	 * Needing YR. */
+	assert(r->auth_user_request != NULL);
+	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+	auth_user_request = r->auth_user_request;
+	auth_user = auth_user_request->auth_user;
+	assert(auth_user != NULL);
+	ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+	ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+	assert((ntlm_user != NULL) && (ntlm_request != NULL));
+	result = S_HELPER_RELEASE;	/*some error has occured. no more requests for 
+					 * this helper */
+	assert(ntlm_request->authserver ? ntlm_request->authserver == lastserver : 1);
+	helperstate = static_cast<ntlm_helper_state_t *>(helperStatefulServerGetData(ntlm_request->authserver));
+	ntlm_request->authserver = NULL;
+	if (ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE) {
+	    /* The helper broke on YR. It automatically
+	     * resets */
+	    debug(29, 1) ("authenticateNTLMHandleReply: Error obtaining challenge from helper: %p. Error returned '%s'\n", lastserver, reply);
+	    /* mark it for starving */
+	    helperstate->starve = 1;
+	    /* resubmit the request. This helper is currently busy, so we will get
+	     * a different one. Our auth state stays the same */
+	    authenticateNTLMStart(auth_user_request, r->handler, r->data);
+	    /* don't call the callback */
+	    cbdataReferenceDone(r->data);
+	    authenticateStateFree(r);
+	    debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", result);
+	    return result;
+	} 
+	/* the helper broke on a KK */
+	/* first the standard KK stuff */
+	debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
+	if ((t = strchr(reply, ' ')))	/* strip after a space */
+	    *t = '\0';
+	/* now we mark the helper for resetting. */
+	helperstate->starve = 1;
+	ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
+    } else {
+	/* TODO: only work with auth_user here if it exists */
+        /* TODO: take the request state into consideration */
+	assert(r->auth_user_request != NULL);
+	assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+	auth_user_request = r->auth_user_request;
+	auth_user = auth_user_request->auth_user;
+	assert(auth_user != NULL);
+	ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+	ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+	assert((ntlm_user != NULL) && (ntlm_request != NULL));
+	debug(29, 1) ("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
+	/* **** NOTE THIS CODE IS EFFECTIVELY UNTESTED **** */
+	/* restart the authentication process */
+	ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
+	assert (ntlm_request->authserver ? ntlm_request->authserver == lastserver : 1);
+	ntlm_request->authserver = NULL;
+    }
+    r->handler(r->data, NULL);
+    cbdataReferenceDone(r->data);
+    authenticateStateFree(r);
+    debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", result);
+    return result;
+}
+
+static void
+authenticateNTLMStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "NTLM Authenticator Statistics:\n");
+    helperStatefulStats(sentry, ntlmauthenticators);
+}
+
+/* is a particular challenge still valid ? */
+static int
+authenticateNTLMValidChallenge(ntlm_helper_state_t * helperstate)
+{
+    debug(29, 9) ("authenticateNTLMValidChallenge: Challenge is %s\n", helperstate->challenge ? "Valid" : "Invalid");
+    if (helperstate->challenge == NULL)
+	return 0;
+    return 1;
+}
+
+/* does our policy call for changing the challenge now? */
+static int
+authenticateNTLMChangeChallenge_p(ntlm_helper_state_t * helperstate)
+{
+    /* don't check for invalid challenges just for expiry choices */
+    /* this is needed because we have to starve the helper until all old
+     * requests have been satisfied */
+    if (!helperstate->renewed) {
+	/* first use, no challenge has been set. Without this check, it will
+	 * loop forever */
+	debug(29, 5) ("authenticateNTLMChangeChallenge_p: first use\n");
+	return 0;
+    }
+    if (helperstate->challengeuses > ntlmConfig->challengeuses) {
+	debug(29, 4) ("authenticateNTLMChangeChallenge_p: Challenge uses (%d) exceeded max uses (%d)\n", helperstate->challengeuses, ntlmConfig->challengeuses);
+	return 1;
+    }
+    if (helperstate->renewed + ntlmConfig->challengelifetime < squid_curtime) {
+	debug(29, 4) ("authenticateNTLMChangeChallenge_p: Challenge exceeded max lifetime by %d seconds\n", (int) (squid_curtime - (helperstate->renewed + ntlmConfig->challengelifetime)));
+	return 1;
+    }
+    debug(29, 9) ("Challenge is to be reused\n");
+    return 0;
+}
+
+/* send the initial data to a stateful ntlm authenticator module */
+static void
+authenticateNTLMStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
+{
+    authenticateStateData *r = NULL;
+    helper_stateful_server *server;
+    ntlm_helper_state_t *helperstate;
+    char buf[8192];
+    char *sent_string = NULL;
+    ntlm_user_t *ntlm_user;
+    ntlm_request_t *ntlm_request;
+    auth_user_t *auth_user;
+
+    assert(auth_user_request);
+    auth_user = auth_user_request->auth_user;
+    ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+    ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+    assert(ntlm_user);
+    assert(ntlm_request);
+    assert(handler);
+    assert(data);
+    assert(auth_user->auth_type = AUTH_NTLM);
+    debug(29, 9) ("authenticateNTLMStart: auth state '%d'\n", ntlm_request->auth_state);
+    switch (ntlm_request->auth_state) {
+    case AUTHENTICATE_STATE_NEGOTIATE:
+	sent_string = ntlm_request->ntlmnegotiate;
+	break;
+    case AUTHENTICATE_STATE_RESPONSE:
+	sent_string = ntlm_request->ntlmauthenticate;
+	assert(ntlm_request->authserver);
+	debug(29, 9) ("authenticateNTLMStart: Asking NTLMauthenticator '%p'.\n", ntlm_request->authserver);
+	break;
+    default:
+	fatal("Invalid authenticate state for NTLMStart");
+    }
+
+    while (!xisspace(*sent_string))	/*trim NTLM */
+	sent_string++;
+
+    while (xisspace(*sent_string))	/*trim leading spaces */
+	sent_string++;
+
+    debug(29, 9) ("authenticateNTLMStart: state '%d'\n", ntlm_request->auth_state);
+    debug(29, 9) ("authenticateNTLMStart: '%s'\n", sent_string);
+    if (ntlmConfig->authenticate == NULL) {
+	debug(29, 0) ("authenticateNTLMStart: no NTLM program specified:'%s'\n", sent_string);
+	handler(data, NULL);
+	return;
+    }
+    /* this is ugly TODO: move the challenge generation routines to their own function and
+     * tidy the logic up to make use of the efficiency we now have */
+    switch (ntlm_request->auth_state) {
+    case AUTHENTICATE_STATE_NEGOTIATE:
+	/*  
+	 * 1: get a helper server
+	 * 2: does it have a challenge?
+	 * 3: tell it to get a challenge, or give ntlmauthdone the challenge
+	 */
+	server = helperStatefulDefer(ntlmauthenticators);
+	helperstate = server ? static_cast<ntlm_helper_state_t *>(helperStatefulServerGetData(server)) : NULL;
+	while ((server != NULL) && authenticateNTLMChangeChallenge_p(helperstate)) {
+	    /* flag this helper for challenge changing */
+	    helperstate->starve = 1;
+	    /* and release the deferred request */
+	    helperStatefulReleaseServer(server);
+	    /* Get another deferrable server */
+	    server = helperStatefulDefer(ntlmauthenticators);
+	    helperstate = server ? static_cast<ntlm_helper_state_t *>(helperStatefulServerGetData(server)) : NULL;
+	}
+	if (server == NULL)
+	    debug(29, 9) ("unable to get a deferred ntlm helper... all helpers are refreshing challenges. Queuing as a placeholder request.\n");
+
+	ntlm_request->authserver = server;
+	/* tell the log what helper we have been given */
+	debug(29, 9) ("authenticateNTLMStart: helper '%p' assigned\n", server);
+	/* server and valid challenge? */
+	if ((server == NULL) || !authenticateNTLMValidChallenge(helperstate)) {
+	    /* No server, or server with invalid challenge */
+	    r = cbdataAlloc(authenticateStateData);
+	    r->handler = handler;
+	    r->data = cbdataReference(data);
+	    r->auth_user_request = auth_user_request;
+	    if (server == NULL) {
+		helperStatefulSubmit(ntlmauthenticators, NULL, authenticateNTLMHandleplaceholder, r, NULL);
+	    } else {
+		/* Server with invalid challenge */
+		snprintf(buf, 8192, "YR\n");
+		helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver);
+	    }
+	} else {
+	    /* (server != NULL and we have a valid challenge) */
+	    /* TODO: turn the below into a function and call from here and handlereply */
+	    /* increment the challenge uses */
+	    helperstate->challengeuses++;
+	    /* assign the challenge */
+	    ntlm_request->authchallenge = xstrndup(helperstate->challenge, NTLM_CHALLENGE_SZ + 5);
+	    /* we're not actually submitting a request, so we need to release the helper 
+	     * should the connection close unexpectedly
+	     */
+	    ntlm_request->authserver_deferred = 1;
+	    handler(data, NULL);
+	}
+
+	break;
+    case AUTHENTICATE_STATE_RESPONSE:
+	r = cbdataAlloc(authenticateStateData);
+	r->handler = handler;
+	r->data = cbdataReference(data);
+	r->auth_user_request = auth_user_request;
+	snprintf(buf, 8192, "KK %s\n", sent_string);
+	/* getting rid of deferred request status */
+	ntlm_request->authserver_deferred = 0;
+	helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver);
+	debug(29, 9) ("authenticateNTLMstart: finished\n");
+	break;
+    default:
+	fatal("Invalid authenticate state for NTLMStart");
+    }
+}
+
+/* callback used by stateful helper routines */
+static int
+authenticateNTLMHelperServerAvailable(void *data)
+{
+    ntlm_helper_state_t *statedata = static_cast<ntlm_helper_state_t *>(data);
+    if (statedata != NULL) {
+	if (statedata->starve) {
+	    debug(29, 4) ("authenticateNTLMHelperServerAvailable: starving - returning 0\n");
+	    return 0;
+	} else {
+	    debug(29, 4) ("authenticateNTLMHelperServerAvailable: not starving - returning 1\n");
+	    return 1;
+	}
+    }
+    debug(29, 4) ("authenticateNTLMHelperServerAvailable: no state data - returning 0\n");
+    return 0;
+}
+
+static void
+authenticateNTLMHelperServerOnEmpty(void *data)
+{
+    ntlm_helper_state_t *statedata = static_cast<ntlm_helper_state_t *>(data);
+    if (statedata == NULL)
+	return;
+    if (statedata->starve) {
+	/* we have been starving the helper */
+	debug(29, 9) ("authenticateNTLMHelperServerOnEmpty: resetting challenge details\n");
+	statedata->starve = 0;
+	statedata->challengeuses = 0;
+	statedata->renewed = 0;
+	xfree(statedata->challenge);
+	statedata->challenge = NULL;
+    }
+}
+
+
+/* clear the NTLM helper of being reserved for future requests */
+static void
+authenticateNTLMReleaseServer(auth_user_request_t * auth_user_request)
+{
+    ntlm_request_t *ntlm_request;
+    assert(auth_user_request->auth_user->auth_type == AUTH_NTLM);
+    assert(auth_user_request->scheme_data != NULL);
+    ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+    debug(29, 9) ("authenticateNTLMReleaseServer: releasing server '%p'\n", ntlm_request->authserver);
+    helperStatefulReleaseServer(ntlm_request->authserver);
+    ntlm_request->authserver = NULL;
+}
+
+/* clear any connection related authentication details */
+static void
+authenticateNTLMOnCloseConnection(ConnStateData * conn)
+{
+    ntlm_request_t *ntlm_request;
+    assert(conn != NULL);
+    if (conn->auth_user_request != NULL) {
+	assert(conn->auth_user_request->scheme_data != NULL);
+	ntlm_request = static_cast< ntlm_request_t *>(conn->auth_user_request->scheme_data);
+	assert(ntlm_request->conn == conn);
+	if (ntlm_request->authserver != NULL && ntlm_request->authserver_deferred)
+	    authenticateNTLMReleaseServer(conn->auth_user_request);
+	/* unlock the connection based lock */
+	debug(29, 9) ("authenticateNTLMOnCloseConnection: Unlocking auth_user from the connection.\n");
+	/* This still breaks the abstraction, but is at least read only now */
+	/* Ensure that the auth user request will be getting closed */
+	/* IFF we start persisting the struct after the conn closes - say for logging
+	 * then this test may become invalid
+	 */
+	assert(authenticateRequestRefCount(conn->auth_user_request) == 1);
+	authenticateAuthUserRequestUnlock(conn->auth_user_request);
+	conn->auth_user_request = NULL;
+    }
+}
+
+/* authenticateUserUsername: return a pointer to the username in the */
+static const char *
+authenticateNTLMUsername(auth_user_t const * auth_user)
+{
+    ntlm_user_t *ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+    if (ntlm_user)
+	return ntlm_user->username;
+    return NULL;
+}
+
+/* NTLMLastHeader: return a pointer to the last header used in authenticating
+ * the request/conneciton
+ */
+static const char *
+NTLMLastHeader(auth_user_request_t * auth_user_request)
+{
+    ntlm_request_t *ntlm_request;
+    assert(auth_user_request != NULL);
+    assert(auth_user_request->scheme_data != NULL);
+    ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+    return ntlm_request->ntlmauthenticate;
+}
+
+/*
+ * Decode an NTLM [Proxy-]Auth string, placing the results in the passed
+ * Auth_user structure.
+ */
+
+static void
+authenticateDecodeNTLMAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
+{
+    dlink_node *node;
+    assert(auth_user_request->auth_user == NULL);
+    auth_user_request->auth_user = authenticateAuthUserNew("ntlm");
+    auth_user_request->auth_user->auth_type = AUTH_NTLM;
+    auth_user_request->auth_user->scheme_data = memPoolAlloc(ntlm_user_pool);
+    auth_user_request->scheme_data = memPoolAlloc(ntlm_request_pool);
+    memset(auth_user_request->scheme_data, '\0', sizeof(ntlm_request_t));
+    /* lock for the auth_user_request link */
+    authenticateAuthUserLock(auth_user_request->auth_user);
+    node = dlinkNodeNew();
+    dlinkAdd(auth_user_request, node, &auth_user_request->auth_user->requests);
+
+    /* all we have to do is identify that it's NTLM - the helper does the rest */
+    debug(29, 9) ("authenticateDecodeNTLMAuth: NTLM authentication\n");
+    return;
+}
+
+static int
+authenticateNTLMcmpUsername(ntlm_user_t * u1, ntlm_user_t * u2)
+{
+    return strcmp(u1->username, u2->username);
+}
+
+
+/* there is a known race where a single client recieves the same challenge
+ * and sends the same response to squid on a single select cycle.
+ * Check for this and if found ignore the new link 
+ */
+static void
+authenticateProxyAuthCacheAddLink(const char *key, auth_user_t * auth_user)
+{
+    struct ProxyAuthCachePointer *proxy_auth_hash;
+    dlink_node *node;
+    ntlm_user_t *ntlm_user;
+    ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+    node = ntlm_user->proxy_auth_list.head;
+    /* prevent duplicates */
+    while (node) {
+	if (!strcmp(key, ((struct ProxyAuthCachePointer *) node->data)->key))
+	    return;
+	node = node->next;
+    }
+    proxy_auth_hash = static_cast<ProxyAuthCachePointer *>(memPoolAlloc(ntlm_user_hash_pool));
+    proxy_auth_hash->key = xstrdup(key);
+    proxy_auth_hash->auth_user = auth_user;
+    dlinkAddTail(proxy_auth_hash, &proxy_auth_hash->link, &ntlm_user->proxy_auth_list);
+    hash_join(proxy_auth_cache, (hash_link *) proxy_auth_hash);
+}
+
+
+static int
+authNTLMAuthenticated(auth_user_request_t * auth_user_request)
+{
+    ntlm_request_t *ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+    if (ntlm_request->auth_state == AUTHENTICATE_STATE_DONE)
+	return 1;
+    debug(29, 9) ("User not fully authenticated.\n");
+    return 0;
+}
+
+static void
+authenticateNTLMAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
+{
+    const char *proxy_auth;
+    struct ProxyAuthCachePointer *proxy_auth_hash = NULL;
+    auth_user_hash_pointer *usernamehash;
+    auth_user_t *auth_user;
+    ntlm_request_t *ntlm_request;
+    ntlm_user_t *ntlm_user;
+    LOCAL_ARRAY(char, ntlmhash, NTLM_CHALLENGE_SZ * 2);
+    /* get header */
+    proxy_auth = httpHeaderGetStr(&request->header, type);
+
+    auth_user = auth_user_request->auth_user;
+    assert(auth_user);
+    assert(auth_user->auth_type == AUTH_NTLM);
+    assert(auth_user->scheme_data != NULL);
+    assert(auth_user_request->scheme_data != NULL);
+    ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+    ntlm_request = static_cast< ntlm_request_t *>(auth_user_request->scheme_data);
+    switch (ntlm_request->auth_state) {
+    case AUTHENTICATE_STATE_NONE:
+	/* we've recieved a negotiate request. pass to a helper */
+	debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state ntlm none. %s\n", proxy_auth);
+	ntlm_request->auth_state = AUTHENTICATE_STATE_NEGOTIATE;
+	ntlm_request->ntlmnegotiate = xstrndup(proxy_auth, NTLM_CHALLENGE_SZ + 5);
+	conn->auth_type = AUTH_NTLM;
+	conn->auth_user_request = auth_user_request;
+	ntlm_request->conn = conn;
+	/* and lock for the connection duration */
+	debug(29, 9) ("authenticateNTLMAuthenticateUser: Locking auth_user from the connection.\n");
+	authenticateAuthUserRequestLock(auth_user_request);
+	return;
+	break;
+    case AUTHENTICATE_STATE_NEGOTIATE:
+	ntlm_request->auth_state = AUTHENTICATE_STATE_CHALLENGE;
+	/* We _MUST_ have the auth challenge by now */
+	assert(ntlm_request->authchallenge);
+	return;
+	break;
+    case AUTHENTICATE_STATE_CHALLENGE:
+	/* we should have recieved a NTLM challenge. pass it to the same 
+	 * helper process */
+	debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state challenge with header %s.\n", proxy_auth);
+	/* do a cache lookup here. If it matches it's a successful ntlm 
+	 * challenge - release the helper and use the existing auth_user 
+	 * details. */
+	if (strncmp("NTLM ", proxy_auth, 5) == 0) {
+	    ntlm_request->ntlmauthenticate = xstrdup(proxy_auth);
+	} else {
+	    fatal("Incorrect scheme in auth header\n");
+	    /* TODO: more fault tolerance.. reset the auth scheme here */
+	}
+	/* cache entries have authenticateauthheaderchallengestring */
+	snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s",
+	    ntlm_request->ntlmauthenticate,
+	    ntlm_request->authchallenge);
+	/* see if we already know this user's authenticate */
+	debug(29, 9) ("aclMatchProxyAuth: cache lookup with key '%s'\n", ntlmhash);
+	assert(proxy_auth_cache != NULL);
+	proxy_auth_hash = static_cast<ProxyAuthCachePointer *>(hash_lookup(proxy_auth_cache, ntlmhash));
+	if (!proxy_auth_hash) {	/* not in the hash table */
+	    debug(29, 4) ("authenticateNTLMAuthenticateUser: proxy-auth cache miss.\n");
+	    ntlm_request->auth_state = AUTHENTICATE_STATE_RESPONSE;
+	    /* verify with the ntlm helper */
+	} else {
+	    debug(29, 4) ("authenticateNTLMAuthenticateUser: ntlm proxy-auth cache hit\n");
+	    /* throw away the temporary entry */
+	    ntlm_request->authserver_deferred = 0;
+	    authenticateNTLMReleaseServer(auth_user_request);
+	    authenticateAuthUserMerge(auth_user, proxy_auth_hash->auth_user);
+	    auth_user = proxy_auth_hash->auth_user;
+	    auth_user_request->auth_user = auth_user;
+	    ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
+	    /* we found one */
+	    debug(29, 9) ("found matching cache entry\n");
+	    assert(auth_user->auth_type == AUTH_NTLM);
+	    /* get the existing entries details */
+	    ntlm_user = static_cast<ntlm_user_t *>(auth_user->scheme_data);
+	    debug(29, 9) ("Username to be used is %s\n", ntlm_user->username);
+	    /* on ntlm auth we do not unlock the auth_user until the
+	     * connection is dropped. Thank MS for this quirk */
+	    auth_user->expiretime = current_time.tv_sec;
+	}
+	return;
+	break;
+    case AUTHENTICATE_STATE_RESPONSE:
+	/* auth-challenge pair cache miss. We've just got the response from the helper */
+	/*add to cache and let them through */
+	ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
+	/* this connection is authenticated */
+	debug(29, 4) ("authenticated\nch    %s\nauth     %s\nauthuser %s\n",
+	    ntlm_request->authchallenge,
+	    ntlm_request->ntlmauthenticate,
+	    ntlm_user->username);
+	/* cache entries have authenticateauthheaderchallengestring */
+	snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s",
+	    ntlm_request->ntlmauthenticate,
+	    ntlm_request->authchallenge);
+	/* see if this is an existing user with a different proxy_auth 
+	 * string */
+	if ((usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, ntlm_user->username)))) {
+	    while ((authUserHashPointerUser(usernamehash)->auth_type != auth_user->auth_type) && (usernamehash->next) && !authenticateNTLMcmpUsername(static_cast<ntlm_user_t *>(authUserHashPointerUser(usernamehash)->scheme_data), ntlm_user))
+		usernamehash = usernamehash->next;
+	    if (authUserHashPointerUser(usernamehash)->auth_type == auth_user->auth_type) {
+		/*
+		 * add another link from the new proxy_auth to the
+		 * auth_user structure and update the information */
+		assert(proxy_auth_hash == NULL);
+		authenticateProxyAuthCacheAddLink(ntlmhash, authUserHashPointerUser(usernamehash));
+		/* we can't seamlessly recheck the username due to the 
+		 * challenge nature of the protocol. Just free the 
+		 * temporary auth_user */
+		authenticateAuthUserMerge(auth_user, authUserHashPointerUser(usernamehash));
+		auth_user = authUserHashPointerUser(usernamehash);
+		auth_user_request->auth_user = auth_user;
+	    }
+	} else {
+	    /* store user in hash's */
+	    authenticateUserNameCacheAdd(auth_user);
+	    authenticateProxyAuthCacheAddLink(ntlmhash, auth_user);
+	}
+	/* set these to now because this is either a new login from an 
+	 * existing user or a new user */
+	auth_user->expiretime = current_time.tv_sec;
+	return;
+	break;
+    case AUTHENTICATE_STATE_DONE:
+	fatal("authenticateNTLMAuthenticateUser: unexpect auth state DONE! Report a bug to the squid developers.\n");
+	break;
+    case AUTHENTICATE_STATE_FAILED:
+	/* we've failed somewhere in authentication */
+	debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state ntlm failed. %s\n", proxy_auth);
+	return;
+    }
+    return;
+}
Index: squid/src/auth/ntlm/auth_ntlm.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/auth/ntlm/auth_ntlm.h,v
retrieving revision 1.8
retrieving revision 1.8.40.1
diff -u -r1.8 -r1.8.40.1
--- squid/src/auth/ntlm/auth_ntlm.h	28 Nov 2001 23:29:52 -0000	1.8
+++ squid/src/auth/ntlm/auth_ntlm.h	3 Oct 2002 01:04:38 -0000	1.8.40.1
@@ -62,13 +62,17 @@
     time_t challengelifetime;
 };
 
+struct ProxyAuthCachePointer {
+    /* first two items must be same as hash_link */
+    char *key;
+    auth_user_hash_pointer *next;dlink_node link;
+    /* other hash entries that point to the same auth_user */
+    auth_user_t *auth_user;
+};
+
 typedef struct _ntlm_user ntlm_user_t;
 typedef struct _ntlm_request ntlm_request_t;
 typedef struct _ntlm_helper_state_t ntlm_helper_state_t;
 typedef struct _auth_ntlm_config auth_ntlm_config;
 
-extern MemPool *ntlm_helper_state_pool;
-extern MemPool *ntlm_user_pool;
-extern MemPool *ntlm_request_pool;
-
 #endif
