This patch is generated from the push branch of HEAD in squid
Mon Jan 26 12:58:16 2004 GMT
See http://devel.squid-cache.org/

Index: squid/CONTRIBUTORS
diff -u squid/CONTRIBUTORS:1.22 squid/CONTRIBUTORS:1.17.6.2
--- squid/CONTRIBUTORS:1.22	Fri Jul  5 15:42:12 2002
+++ squid/CONTRIBUTORS	Tue Sep  3 10:39:07 2002
@@ -88,5 +88,6 @@
 	Ian Castle <ian.castle@coldcomfortfarm.net>
 	Brad Smitch <brad@comstyle.com>
 	Jerry Murdock <jmurdock@itraktech.com>
+	Jon Kay <jkay@pushcache.com>
 
 	Duane Wessels <wessels@squid-cache.org>
Index: squid/acconfig.h
diff -u squid/acconfig.h:1.20 squid/acconfig.h:1.12.2.4
--- squid/acconfig.h:1.20	Thu Aug  8 12:42:06 2002
+++ squid/acconfig.h	Tue Sep  3 10:39:08 2002
@@ -130,6 +130,21 @@
 #undef USE_ARP_ACL
 
 /*
+ * Define this to include code for Hint Caching.
+ */
+#undef USE_HINT_CACHE
+
+/*
+ * Define this to include code for the Plaxton dynamic cache hierarchy.
+ */
+#undef USE_DYNAMIC_HIERARCHY
+
+/*
+ * Define this to include code for sending data by ICP
+ */
+#undef USE_ICP_DATA
+
+/*
  * Define this to include code for the Hypertext Cache Protocol (HTCP)
  */
 #undef USE_HTCP
Index: squid/acinclude.m4
diff -u squid/acinclude.m4:1.4 squid/acinclude.m4:1.1.54.1
--- squid/acinclude.m4:1.4	Mon Jun 17 14:02:55 2002
+++ squid/acinclude.m4	Tue Sep  3 10:39:08 2002
@@ -16,8 +16,7 @@
 changequote([, ])dnl
 AC_MSG_CHECKING(size of $1)
 AC_CACHE_VAL(AC_CV_NAME,
-[AC_TRY_RUN([
-#include <stdio.h>
+[AC_TRY_RUN([#include <stdio.h>
 #if STDC_HEADERS
 #include <stdlib.h>
 #include <stddef.h>
@@ -28,17 +27,13 @@
 #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_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
@@ -53,12 +48,7 @@
 [AC_EGREP_CPP(dnl
 changequote(<<,>>)dnl
 <<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl
-changequote([,]), [
-/* 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..
- */
-#include <sys/types.h>
+changequote([,]), [#include <sys/types.h>
 #if STDC_HEADERS
 #include <stdlib.h>
 #include <stddef.h>
@@ -68,11 +58,7 @@
 #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
+#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)
Index: squid/configure.in
diff -u squid/configure.in:1.65 squid/configure.in:1.35.2.4
--- squid/configure.in:1.65	Sun Sep  1 09:30:40 2002
+++ squid/configure.in	Tue Sep  3 10:39:09 2002
@@ -27,20 +27,19 @@
 AM_PROG_CC_C_O
 AC_CANONICAL_HOST
 
-
 CRYPTLIB=''
-REGEXLIB=''	# -lregex
-LIBREGEX=''	# libregex.a
+REGEXLIB=''     # -lregex
+LIBREGEX=''     # libregex.a
 
 dnl find out the exe extension for this platform. If it's not empty, use it for CGI's as well.
 AC_EXEEXT
 AC_OBJEXT
 
 if test -z "$EXEEXT"; then
-	CGIEXT=".cgi"
+        CGIEXT=".cgi"
 else
-	# automake automatically adds .exe when installing binaries
-	CGIEXT=""
+        # automake automatically adds .exe when installing binaries
+        CGIEXT=""
 fi
 AC_SUBST(CGIEXT)
 
@@ -49,17 +48,17 @@
 case "$host_os" in
 cygwin|cygwin32)
         AM_CONDITIONAL(ENABLE_WIN32SPECIFIC, true)
-	;;
+        ;;
 *)
-	AM_CONDITIONAL(ENABLE_WIN32SPECIFIC, false)
-	;;
+        AM_CONDITIONAL(ENABLE_WIN32SPECIFIC, false)
+        ;;
 esac
 
 if test -z "$CACHE_HTTP_PORT"; then
-	CACHE_HTTP_PORT="3128"
+        CACHE_HTTP_PORT="3128"
 fi
 if test -z "$CACHE_ICP_PORT"; then
-	CACHE_ICP_PORT="3130"
+        CACHE_ICP_PORT="3130"
 fi
 
 dnl Subsitutions
@@ -76,43 +75,43 @@
 dnl Gerben Wierda <Gerben_Wierda@RnA.nl>
 case "$host" in
     mab-next-nextstep3)
-	CC="$CC -arch m68k -arch i486 -arch hppa -arch sparc"
-	;;
+        CC="$CC -arch m68k -arch i486 -arch hppa -arch sparc"
+        ;;
 esac
 
 dnl Set Default CFLAGS
 if test -z "$PRESET_CFLAGS"; then
     if test "$GCC" = "yes"; then
         case "$host" in
-	*-sun-sunos*)
-    	    # sunos has too many warnings for this to be useful
-	    # motorola too
-    	    ;;
-	*m88k*)
-	    # Motorola cc/ld does not like -02 but is ok on -O
-	    CFLAGS=`echo $CFLAGS | sed -e 's/-O[0-9]/-O/'`
-	    ;;
+        *-sun-sunos*)
+            # sunos has too many warnings for this to be useful
+            # motorola too
+            ;;
+        *m88k*)
+            # Motorola cc/ld does not like -02 but is ok on -O
+            CFLAGS=`echo $CFLAGS | sed -e 's/-O[0-9]/-O/'`
+            ;;
         *)
-    	    CFLAGS="$CFLAGS -Wall"
-    	    ;;
+            CFLAGS="$CFLAGS -Wall"
+            ;;
         esac
     else
-	case "$host" in
-	*mips-sgi-irix6.*)
-	    # suggested by Rafael Seidl <rafaels@cthulhu.engr.sgi.com>
-	    CFLAGS="$CFLAGS -n32 -mips3 -O3 -OPT:Olimit=0:space=OFF \
-		-woff 1009,1014,1110,1116,1185,1188,1204,1230,1233 \
-		-Wl,-woff,85,-woff,84,-woff,134 \
-		-nostdinc -I/usr/include -D_BSD_SIGNALS"
-	    ;;
-	alpha-dec-osf4.*)
-	    # Mogul says DEC compilers take both -g and -O2
-	    CFLAGS=`echo $CFLAGS | sed -e 's/-g/-g3/'`
-	    CFLAGS="$CFLAGS -O2"
-	    ;;
-	*)
-	    ;;
-	esac
+        case "$host" in
+        *mips-sgi-irix6.*)
+            # suggested by Rafael Seidl <rafaels@cthulhu.engr.sgi.com>
+            CFLAGS="$CFLAGS -n32 -mips3 -O3 -OPT:Olimit=0:space=OFF \
+                -woff 1009,1014,1110,1116,1185,1188,1204,1230,1233 \
+                -Wl,-woff,85,-woff,84,-woff,134 \
+                -nostdinc -I/usr/include -D_BSD_SIGNALS"
+            ;;
+        alpha-dec-osf4.*)
+            # Mogul says DEC compilers take both -g and -O2
+            CFLAGS=`echo $CFLAGS | sed -e 's/-g/-g3/'`
+            CFLAGS="$CFLAGS -O2"
+            ;;
+        *)
+            ;;
+        esac
     fi
 fi
 
@@ -121,16 +120,16 @@
     if test "$GCC" = "yes"; then
         case "$host" in
         *)
-    	    # nothing
-	    ;;
+            # nothing
+            ;;
         esac
     else
-	case "$host" in
-	*mips-sgi-irix6.*)
-	    # suggested by Rafael Seidl <rafaels@cthulhu.engr.sgi.com>
-	    LDFLAGS="-n32 -mips3 -nostdlib -L/usr/lib32"
-	    ;;
-	esac
+        case "$host" in
+        *mips-sgi-irix6.*)
+            # suggested by Rafael Seidl <rafaels@cthulhu.engr.sgi.com>
+            LDFLAGS="-n32 -mips3 -nostdlib -L/usr/lib32"
+            ;;
+        esac
     fi
 fi
 
@@ -156,18 +155,18 @@
 ])
 if test "${use_dlmalloc-unset}" = unset; then
     case "$host" in
-	i386-*-solaris2.*)
-		echo "Enabling dlmalloc for $host"
-		use_dlmalloc="yes"
-		LIBDLMALLOC="libdlmalloc.a"
-		LIB_MALLOC="-L../lib -ldlmalloc"
-		;;
-	*-sgi-irix*)
-		echo "Enabling dlmalloc for $host"
-		use_dlmalloc="yes"
-		LIBDLMALLOC="libdlmalloc.a"
-		LIB_MALLOC="-L../lib -ldlmalloc"
-		;;
+        i386-*-solaris2.*)
+                echo "Enabling dlmalloc for $host"
+                use_dlmalloc="yes"
+                LIBDLMALLOC="libdlmalloc.a"
+                LIB_MALLOC="-L../lib -ldlmalloc"
+                ;;
+        *-sgi-irix*)
+                echo "Enabling dlmalloc for $host"
+                use_dlmalloc="yes"
+                LIBDLMALLOC="libdlmalloc.a"
+                LIB_MALLOC="-L../lib -ldlmalloc"
+                ;;
     esac
 fi
 if test "x$ac_cv_enabled_dlmalloc" = "xyes"; then
@@ -267,7 +266,7 @@
   else
     AC_DEFINE(USE_CARP, 1)
   fi
-])      
+])
 
 AC_ARG_ENABLE(async-io,
 [  --enable-async-io[=N_THREADS]
@@ -277,13 +276,13 @@
                           --enable-storeio=ufs,aufs],
 [ case $enableval in
   yes)
-	STORE_MODULES="ufs aufs"
+        STORE_MODULES="ufs aufs"
     ;;
   no)
     ;;
   *)
-  	aufs_io_threads=$enableval
-	STORE_MODULES="ufs aufs"
+        aufs_io_threads=$enableval
+        STORE_MODULES="ufs aufs"
     ;;
   esac
 ])
@@ -313,9 +312,9 @@
     ;;
     *-solaris2.*)
         if test "$GCC" = "yes" ; then
-	    CFLAGS="$CFLAGS -pthreads"
-	else
-	    CFLAGS="$CFLAGS -mt"
+            CFLAGS="$CFLAGS -pthreads"
+        else
+            CFLAGS="$CFLAGS -mt"
         fi
     ;;
     esac
@@ -342,16 +341,16 @@
                           for details on how to build your custom store module],
 [ case $enableval in
   yes)
-	for module in $srcdir/src/fs/*; do
-	    if test -f $module/Makefile.in; then
-		STORE_MODULES="$STORE_MODULES `basename $module`"
-	    fi
-	done
-  	;;
+        for module in $srcdir/src/fs/*; do
+            if test -f $module/Makefile.in; then
+                STORE_MODULES="$STORE_MODULES `basename $module`"
+            fi
+        done
+        ;;
   no)
-  	;;
-  *)	STORE_MODULES="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
-	;;
+        ;;
+  *)    STORE_MODULES="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
+        ;;
   esac
 ],
 [ if test -z "$STORE_MODULES"; then
@@ -370,32 +369,31 @@
     case "$fs" in
     diskd)
         STORE_MODULE_SUBDIRS="$STORE_MODULE_SUBDIRS $fs"
-	OPT_DISKD_EXE='diskd$(EXEEXT)'
-	;;
+        OPT_DISKD_EXE='diskd$(EXEEXT)'
+        ;;
     aufs)
-	if test -z "$with_pthreads"; then
-	    echo "aufs store used, pthreads support automatically enabled"
-	    with_pthreads=yes
-	fi
-	;;
+        if test -z "$with_pthreads"; then
+            echo "aufs store used, pthreads support automatically enabled"
+            with_pthreads=yes
+        fi
+        ;;
     coss)
-	if test -z "$with_aio"; then
-	    echo "coss store used, aio support automatically enabled"
-	    with_aio=yes
-	fi
-	;;
+        if test -z "$with_aio"; then
+            echo "coss store used, aio support automatically enabled"
+            with_aio=yes
+        fi
+        ;;
     esac
 done
 AC_SUBST(STORE_MODULES)
 AC_SUBST(STORE_MODULE_SUBDIRS)
 AC_SUBST(OPT_DISKD_EXE)
 
-
 dnl --enable-heap-replacement compability option
 AC_ARG_ENABLE(heap-replacement,
 [  --enable-heap-replacement
                           Backwards compability option. Please use the
-			  new --enable-removal-policies directive instead.],
+                          new --enable-removal-policies directive instead.],
 [ if test "$enableval" = "yes" ; then
     echo "--enable-heap-replacement is obsolete. please use the new"
     echo "--enable-removal-policies directive instead"
@@ -410,19 +408,19 @@
                           The default is only to build the "lru" module.
                           See src/repl for a list of available modules, or
                           Programmers Guide section 9.9 for details on how
-			  to build your custom policy],
+                          to build your custom policy],
 [ case $enableval in
   yes)
-	for module in $srcdir/src/repl/*; do
-	    if test -f $module/Makefile.in; then
-		REPL_POLICIES="$REPL_POLICIES `basename $module`"
-	    fi
-	done
-  	;;
+        for module in $srcdir/src/repl/*; do
+            if test -f $module/Makefile.in; then
+                REPL_POLICIES="$REPL_POLICIES `basename $module`"
+            fi
+        done
+        ;;
   no)
-  	;;
-  *)	REPL_POLICIES="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
-	;;
+        ;;
+  *)    REPL_POLICIES="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
+        ;;
   esac
 ],
 [ if test -z "$REPL_POLICIES"; then
@@ -467,8 +465,8 @@
 dnl [ if test "$enableval" = "yes" ; then
 dnl     echo "Memory trace (to file) enabled"
 dnl     AC_DEFINE(MEM_GEN_TRACE)
-dnl   fi    
-dnl ])     
+dnl   fi
+dnl ])
 
 AC_ARG_ENABLE(useragent-log,
 [  --enable-useragent-log  Enable logging of User-Agent header],
@@ -486,7 +484,7 @@
   fi
 ])
 
-AC_ARG_ENABLE(wccp,  
+AC_ARG_ENABLE(wccp,
 [  --disable-wccp          Disable Web Cache Coordination Protocol],
 [ if test "$enableval" = "no" ; then
     echo "Web Cache Coordination Protocol disabled"
@@ -494,7 +492,7 @@
   else
     AC_DEFINE(USE_WCCP, 1)
   fi
-])      
+])
 
 AC_ARG_ENABLE(kill-parent-hack,
 [  --enable-kill-parent-hack
@@ -543,19 +541,50 @@
 [  if test "$enableval" = "yes" ; then
      echo "ARP ACL lists enabled (ether address)"
      case "$host" in
-	*-linux-*)
-	    ;;
-	*-solaris-*)
-	    ;;
-	*)
-	    echo "WARNING: ARP ACL support probably won't work on $host."
-	    sleep 10
-	    ;;
+        *-linux-*)
+            ;;
+        *-solaris-*)
+            ;;
+        *)
+            echo "WARNING: ARP ACL support probably won't work on $host."
+            sleep 10
+            ;;
      esac
      AC_DEFINE(USE_ARP_ACL)
    fi
 ])
 
+AM_CONDITIONAL(ENABLE_HINTS, false)
+AC_ARG_ENABLE(hints,
+[  --enable-hints           Enable Hint Cache protocol],
+[ if test "$enableval" = "yes" ; then
+    echo "Hint Cache enabled"
+    AC_DEFINE(USE_HINT_CACHE)
+    AM_CONDITIONAL(ENABLE_HINTS, true)
+  fi
+])
+
+AM_CONDITIONAL(ENABLE_PLAXTON, false)
+AC_ARG_ENABLE(plaxton,
+[  --enable-plaxton           Enable Plaxton dynamic hierarchy protocol],
+[ if test "$enableval" = "yes" ; then
+    echo "Plaxton dynamic hierarchy enabled"
+    AC_DEFINE(USE_DYNAMIC_HIERARCHY)
+    AM_CONDITIONAL(ENABLE_PLAXTON, true)
+  fi
+])
+
+AM_CONDITIONAL(ENABLE_ICP_DATA, false)
+AC_ARG_ENABLE(icpdata,
+[  --enable-icpdata           Enable sending data by ICP],
+[ if test "$enableval" = "yes" ; then
+    echo "Push over ICP/UDP enabled"
+    AC_DEFINE(USE_ICP_DATA)
+    AM_CONDITIONAL(ENABLE_ICP_DATA, true)
+  fi
+])
+
+  AM_CONDITIONAL(ENABLE_HTCP, false)
 AM_CONDITIONAL(ENABLE_HTCP, false)
 AC_ARG_ENABLE(htcp,
 [  --enable-htcp           Enable HTCP protocol],
@@ -584,10 +613,10 @@
 AC_ARG_WITH(openssl,
 [  --with-openssl[=prefix]
                           Compile with the OpenSSL libraries. The path to
-			  the OpenSSL development libraries and headers
-			  installation can be specified if outside of the
-			  system standard directories],
-[ 
+                          the OpenSSL development libraries and headers
+                          installation can be specified if outside of the
+                          system standard directories],
+[
   case "$with_openssl" in
   yes)
     USE_OPENSSL=1
@@ -639,10 +668,10 @@
                           errors directory) ],
 [
     if test -d $srcdir/errors/$enableval; then
-	ERR_DEFAULT_LANGUAGE=$enableval
+        ERR_DEFAULT_LANGUAGE=$enableval
     else
-	echo "ERROR! Unknown language $enableval, see errors/ directory"
-	exit 1
+        echo "ERROR! Unknown language $enableval, see errors/ directory"
+        exit 1
     fi
 ],[ERR_DEFAULT_LANGUAGE="English"])
 AC_SUBST(ERR_DEFAULT_LANGUAGE)
@@ -655,9 +684,9 @@
 [
     for l in $enableval; do
         if test -d $srcdir/errors/$l; then :; else
-	    echo "ERROR! Unknown language $$l, see errors/"
-	    exit 1
-	fi
+            echo "ERROR! Unknown language $$l, see errors/"
+            exit 1
+        fi
     done
     ERR_LANGUAGES=$enableval
 ],[
@@ -665,7 +694,7 @@
     for l in $srcdir/errors/*; do
         if test -f $l/ERR_ACCESS_DENIED; then
             ERR_LANGUAGES="$ERR_LANGUAGES `basename $l`"
-	fi
+        fi
     done
 ])
 AC_SUBST(ERR_LANGUAGES)
@@ -753,9 +782,9 @@
                           Enable Transparent Proxy support for systems
                           using IP-Filter network address redirection.],
 [ if test "$enableval" = "yes" ; then
-	echo "IP-Filter Transparent Proxy enabled"
-	AC_DEFINE(IPF_TRANSPARENT)
-	IPF_TRANSPARENT="yes"
+        echo "IP-Filter Transparent Proxy enabled"
+        AC_DEFINE(IPF_TRANSPARENT)
+        IPF_TRANSPARENT="yes"
   fi
 ])
 
@@ -765,9 +794,9 @@
                           Enable Transparent Proxy support for systems
                           using PF network address redirection.],
 [ if test "$enableval" = "yes" ; then
-	echo "PF Transparent Proxy enabled"
-	AC_DEFINE(PF_TRANSPARENT)
-	PF_TRANSPARENT="yes"
+        echo "PF Transparent Proxy enabled"
+        AC_DEFINE(PF_TRANSPARENT)
+        PF_TRANSPARENT="yes"
   fi
 ])
 
@@ -776,9 +805,9 @@
 [  --enable-linux-netfilter
                           Enable Transparent Proxy support for Linux 2.4.],
 [ if test "$enableval" = "yes" ; then
-	echo "Linux-Netfilter Transparent Proxy enabled"
-	AC_DEFINE(LINUX_NETFILTER)
-	LINUX_NETFILTER="yes"
+        echo "Linux-Netfilter Transparent Proxy enabled"
+        AC_DEFINE(LINUX_NETFILTER)
+        LINUX_NETFILTER="yes"
   fi
 ])
 
@@ -787,8 +816,8 @@
 [  --enable-large-files    Enable support for large files (>2GB). Still
                           experimental.],
 [ if test "$enableval" = "yes" ; then
-	echo "Large file support enabled"
-	CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64"
+        echo "Large file support enabled"
+        CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64"
   fi
 ])
 
@@ -798,13 +827,13 @@
 [  --enable-leakfinder
                           Enable Leak Finding code.  Enabling this alone
                           does nothing; you also have to modify the source
-			  code to use the leak finding functions.  Probably
-			  Useful for hackers only.],
+                          code to use the leak finding functions.  Probably
+                          Useful for hackers only.],
 [ if test "$enableval" = "yes" ; then
-	echo "Leak-Finding enabled"
-	AC_DEFINE(USE_LEAKFINDER)
-	USE_LEAKFINDER="yes"
-	AM_CONDITIONAL(MAKE_LEAKFINDER, true)
+        echo "Leak-Finding enabled"
+        AC_DEFINE(USE_LEAKFINDER)
+        USE_LEAKFINDER="yes"
+        AM_CONDITIONAL(MAKE_LEAKFINDER, true)
   fi
 ])
 
@@ -873,20 +902,19 @@
                           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
+        if test -f $enableval; then
+            OPT_DEFAULT_HOSTS=$enableval
+        else
+            echo "Warning Unable to find $enableval"
+            sleep 5
+        fi
     else
-	OPT_DEFAULT_HOSTS="none"    
+        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,
 [  --enable-auth=\"list of auth scheme modules\"
@@ -931,11 +959,11 @@
   echo "option --enable-basic-auth-helpers"
   sleep 5
   case "$enableval" in
-  yes) 
+  yes)
     for helper in $srcdir/helpers/basic_auth/*; do
-	if test -f $helper/Makefile.in; then
-	    BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS `basename $helper`"
-	fi
+        if test -f $helper/Makefile.in; then
+            BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS `basename $helper`"
+        fi
     done
     ;;
   no)
@@ -947,16 +975,16 @@
 AC_ARG_ENABLE(basic-auth-helpers,
 [  --enable-basic-auth-helpers=\"list of helpers\"
                           This option selects which basic scheme proxy_auth
-                          helpers to build and install as part of the normal 
+                          helpers to build and install as part of the normal
                           build process. For a list of available
                           helpers see the helpers/basic_auth directory.],
 [ case "$enableval" in
-  yes) 
+  yes)
     BASIC_AUTH_HELPERS=""
     for helper in $srcdir/helpers/basic_auth/*; do
-	if test -f $helper/Makefile.in; then
-	    BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS `basename $helper`"
-	fi
+        if test -f $helper/Makefile.in; then
+            BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS `basename $helper`"
+        fi
     done
     ;;
   no)
@@ -967,12 +995,12 @@
 ])
 if test -n "$BASIC_AUTH_HELPERS"; then
     for helper in $BASIC_AUTH_HELPERS; do
-	if test -f $srcdir/helpers/basic_auth/$helper/Makefile.in; then
-		:
-	else
-		echo "ERROR: Basic auth helper $helper does not exists"
-		exit 1
-	fi
+        if test -f $srcdir/helpers/basic_auth/$helper/Makefile.in; then
+                :
+        else
+                echo "ERROR: Basic auth helper $helper does not exists"
+                exit 1
+        fi
     done
     echo "Basic auth helpers built: $BASIC_AUTH_HELPERS"
 fi
@@ -983,15 +1011,15 @@
 AC_ARG_ENABLE(ntlm-auth-helpers,
 [  --enable-ntlm-auth-helpers=\"list of helpers\"
                           This option selects which proxy_auth ntlm helpers
-                          to build and install as part of the normal build 
+                          to build and install as part of the normal build
                           process. For a list of available helpers see
                           the helpers/ntlm_auth directory.],
 [ case "$enableval" in
-  yes) 
+  yes)
     for helper in $srcdir/helpers/ntlm_auth/*; do
-	if test -f $helper/Makefile.in; then
-	    NTLM_AUTH_HELPERS="$NTLM_AUTH_HELPERS `basename $helper`"
-	fi
+        if test -f $helper/Makefile.in; then
+            NTLM_AUTH_HELPERS="$NTLM_AUTH_HELPERS `basename $helper`"
+        fi
     done
     ;;
   no)
@@ -1002,12 +1030,12 @@
 ])
 if test -n "$NTLM_AUTH_HELPERS"; then
     for helper in $NTLM_AUTH_HELPERS; do
-	if test -f $srcdir/helpers/ntlm_auth/$helper/Makefile.in; then
-		:
-	else
-		echo "ERROR: NTLM auth helper $helper does not exists"
-		exit 1
-	fi
+        if test -f $srcdir/helpers/ntlm_auth/$helper/Makefile.in; then
+                :
+        else
+                echo "ERROR: NTLM auth helper $helper does not exists"
+                exit 1
+        fi
     done
     echo "NTLM auth helpers built: $NTLM_AUTH_HELPERS"
 fi
@@ -1037,12 +1065,12 @@
 ])
 if test -n "$DIGEST_AUTH_HELPERS"; then
     for helper in $DIGEST_AUTH_HELPERS; do
-	if test -f $srcdir/helpers/digest_auth/$helper/Makefile.in; then
-		:
-	else
-		echo "ERROR: digest auth helper $helper does not exists"
-		exit 1
-	fi
+        if test -f $srcdir/helpers/digest_auth/$helper/Makefile.in; then
+                :
+        else
+                echo "ERROR: digest auth helper $helper does not exists"
+                exit 1
+        fi
     done
     echo "Digest auth helpers built: $DIGEST_AUTH_HELPERS"
 fi
@@ -1082,12 +1110,12 @@
 ])
 if test -n "$EXTERNAL_ACL_HELPERS"; then
     for helper in $EXTERNAL_ACL_HELPERS; do
-	if test -f $srcdir/helpers/external_acl/$helper/Makefile.in; then
-		:
-	else
-		echo "ERROR: external acl helper $helper does not exists"
-		exit 1
-	fi
+        if test -f $srcdir/helpers/external_acl/$helper/Makefile.in; then
+                :
+        else
+                echo "ERROR: external acl helper $helper does not exists"
+                exit 1
+        fi
     done
     echo "External acl helpers built: $EXTERNAL_ACL_HELPERS"
 fi
@@ -1153,19 +1181,19 @@
 #
 case "$host" in
     alpha-dec-osf*)
-	if test "$ac_cv_prog_CC" = "cc" ; then
-		echo "adding '-std1' to cc args for $host"
-		CC="cc -std1";
-		ac_cv_prog_CC="$CC"
-	fi
-	;;
+        if test "$ac_cv_prog_CC" = "cc" ; then
+                echo "adding '-std1' to cc args for $host"
+                CC="cc -std1";
+                ac_cv_prog_CC="$CC"
+        fi
+        ;;
     *-hp-hpux*)
-	if test "$ac_cv_prog_CC" = "cc" ; then
-		echo "adding '-Ae' to cc args for $host"
-		CC="cc -Ae";
-		ac_cv_prog_CC="$CC"
-	fi
-	;;
+        if test "$ac_cv_prog_CC" = "cc" ; then
+                echo "adding '-Ae' to cc args for $host"
+                CC="cc -Ae";
+                ac_cv_prog_CC="$CC"
+        fi
+        ;;
 esac
 
 dnl Check for programs
@@ -1185,24 +1213,24 @@
 AC_PATH_PROG(AR, ar, $FALSE)
 
 if test "$ac_cv_path_PERL" = "none"; then
-	echo "Perl is required to compile Squid"
-	echo "Please install Perl and then re-run configure"
-	exit 1
+        echo "Perl is required to compile Squid"
+        echo "Please install Perl and then re-run configure"
+        exit 1
 fi
 
 case "$host" in
     *-hp-hpux*)
-	echo "Disabling 'ranlib' for HP-UX..."
-	RANLIB=":"
-	;;
+        echo "Disabling 'ranlib' for HP-UX..."
+        RANLIB=":"
+        ;;
 esac
 
 dnl set $(AR)
 AR_R="$AR r"
 case "$host" in
-	*-next-nextstep3)
-		AR="libtool -o"
-		;;
+        *-next-nextstep3)
+                AR="libtool -o"
+                ;;
 esac
 AC_SUBST(AR_R)
 
@@ -1211,84 +1239,84 @@
 AC_HEADER_STDC
 
 AC_CHECK_HEADERS( \
-	arpa/inet.h \
-	arpa/nameser.h \
-	assert.h \
-	bstring.h \
-	crypt.h \
-	ctype.h \
-	errno.h \
-	execinfo.h \
-	fcntl.h \
-	getopt.h \
-	gnumalloc.h \
-	grp.h \
-	ip_compat.h \
-	ip_fil_compat.h \
-	ip_fil.h \
-	ip_nat.h \
-	libc.h \
-	limits.h \
-	linux/netfilter_ipv4.h \
-	malloc.h \
-	math.h \
-	memory.h \
-	mount.h \
-	net/if.h \
-	net/pfvar.h \
-	netdb.h \
-	netinet/if_ether.h \
-	netinet/in.h \
-	netinet/tcp.h \
-	netinet/ip_compat.h \
-	netinet/ip_fil_compat.h \
-	netinet/ip_fil.h \
-	netinet/ip_nat.h \
-	openssl/err.h \
-	openssl/md5.h \
-	openssl/ssl.h \
-	poll.h \
-	pwd.h \
-	regex.h \
-	resolv.h \
-	sched.h \
-	signal.h \
-	stdarg.h \
-	stddef.h \
-	stdio.h \
-	stdlib.h \
-	string.h \
-	strings.h \
-	sys/bitypes.h \
-	sys/file.h \
-	sys/ioctl.h \
-	sys/mount.h \
-	sys/msg.h \
-	sys/param.h \
-	sys/resource.h \
-	sys/select.h\
-	sys/socket.h \
-	sys/stat.h \
-	sys/statvfs.h \
-	syscall.h \
-	sys/syscall.h \
-	sys/time.h \
-	sys/types.h \
-	sys/un.h \
-	sys/vfs.h \
-	sys/wait.h \
-	syslog.h \
-	time.h \
-	unistd.h \
-	utime.h \
-	varargs.h \
-	byteswap.h \
-	glib.h \
-	stdint.h \
-	inttypes.h \
-	grp.h \
-	nss_common.h \
-	nss.h
+        arpa/inet.h \
+        arpa/nameser.h \
+        assert.h \
+        bstring.h \
+        crypt.h \
+        ctype.h \
+        errno.h \
+        execinfo.h \
+        fcntl.h \
+        getopt.h \
+        gnumalloc.h \
+        grp.h \
+        ip_compat.h \
+        ip_fil_compat.h \
+        ip_fil.h \
+        ip_nat.h \
+        libc.h \
+        limits.h \
+        linux/netfilter_ipv4.h \
+        malloc.h \
+        math.h \
+        memory.h \
+        mount.h \
+        net/if.h \
+        net/pfvar.h \
+        netdb.h \
+        netinet/if_ether.h \
+        netinet/in.h \
+        netinet/tcp.h \
+        netinet/ip_compat.h \
+        netinet/ip_fil_compat.h \
+        netinet/ip_fil.h \
+        netinet/ip_nat.h \
+        openssl/err.h \
+        openssl/md5.h \
+        openssl/ssl.h \
+        poll.h \
+        pwd.h \
+        regex.h \
+        resolv.h \
+        sched.h \
+        signal.h \
+        stdarg.h \
+        stddef.h \
+        stdio.h \
+        stdlib.h \
+        string.h \
+        strings.h \
+        sys/bitypes.h \
+        sys/file.h \
+        sys/ioctl.h \
+        sys/mount.h \
+        sys/msg.h \
+        sys/param.h \
+        sys/resource.h \
+        sys/select.h\
+        sys/socket.h \
+        sys/stat.h \
+        sys/statvfs.h \
+        syscall.h \
+        sys/syscall.h \
+        sys/time.h \
+        sys/types.h \
+        sys/un.h \
+        sys/vfs.h \
+        sys/wait.h \
+        syslog.h \
+        time.h \
+        unistd.h \
+        utime.h \
+        varargs.h \
+        byteswap.h \
+        glib.h \
+        stdint.h \
+        inttypes.h \
+        grp.h \
+        nss_common.h \
+        nss.h
 )
 
 AC_C_CONST
@@ -1406,49 +1434,49 @@
 
 dnl int16_t
 if test "x$ac_cv_sizeof_short" = "x2"; then
-	AC_CHECK_SYSTYPE(int16_t,short)
+        AC_CHECK_SYSTYPE(int16_t,short)
 elif test "x$ac_cv_sizeof_int" = "x2"; then
-	AC_CHECK_SYSTYPE(int16_t,int)
+        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)
+        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)
+        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)
+        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)
+        AC_CHECK_SYSTYPE(int32_t,int)
 elif "x$ac_cv_sizeof_long" = "x4"; then
-	AC_CHECK_SYSTYPE(int32_t,long)
+        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)
+        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)
+        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)
+        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)
+        AC_CHECK_SYSTYPE(int64_t,long)
 elif test "x$ac_cv_sizeof_long_long" = "x8"; then
-	AC_CHECK_SYSTYPE(int64_t,long long)
+        AC_CHECK_SYSTYPE(int64_t,long long)
 elif test "x$ac_cv_sizeof___int64" = "x8"; then
-	AC_CHECK_SYSTYPE(int64_t,__int64)
+        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)
+        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)
+        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)
+        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)
+        AC_CHECK_SYSTYPE(int64_t,unsigned __int64)
 fi
 
 AC_CHECK_TYPE(pid_t, int)
@@ -1464,7 +1492,6 @@
 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>
@@ -1505,7 +1532,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>],
 [
-  struct sockaddr_un sunaddr; 
+  struct sockaddr_un sunaddr;
   sunaddr.sun_family = AF_UNIX;
 ],
         squid_cv_unixsocket=yes,squid_cv_unixsocket=no)])
@@ -1519,23 +1546,23 @@
 else
   AC_CHECK_LIB(gnumalloc, main)
   if test "$ac_cv_lib_gnumalloc_main" = "yes"; then
-		echo "Disabling extended malloc functions when using gnumalloc"
-		ac_cv_func_mallinfo=no
-		ac_cv_func_mallocblksize=no
-		ac_cv_func_mallopt=no
+                echo "Disabling extended malloc functions when using gnumalloc"
+                ac_cv_func_mallinfo=no
+                ac_cv_func_mallocblksize=no
+                ac_cv_func_mallopt=no
   else
-		case "$host" in
-			*-sun-solaris*)
-			  echo "skipping libmalloc check for $host"
-				;;
-			i386-*-freebsd*)
-			  echo "skipping libmalloc check for $host"
-				;;
-			*)
-  
-				AC_CHECK_LIB(malloc, main)
-				;;
-		esac
+                case "$host" in
+                        *-sun-solaris*)
+                          echo "skipping libmalloc check for $host"
+                                ;;
+                        i386-*-freebsd*)
+                          echo "skipping libmalloc check for $host"
+                                ;;
+                        *)
+
+                                AC_CHECK_LIB(malloc, main)
+                                ;;
+                esac
   fi
 fi
 
@@ -1544,13 +1571,13 @@
 AC_CHECK_LIB(bind, gethostbyname)
 if test $ac_cv_lib_bind_gethostbyname = "no" ; then
     case "$host" in
-	i386-*-freebsd*)
-		echo "skipping libresolv checks for $host"
-		;;
-	*)
-		AC_CHECK_LIB(resolv, inet_aton, AC_CHECK_LIB(44bsd, inet_aton))
-		AC_CHECK_LIB(resolv, main)
-		;;
+        i386-*-freebsd*)
+                echo "skipping libresolv checks for $host"
+                ;;
+        *)
+                AC_CHECK_LIB(resolv, inet_aton, AC_CHECK_LIB(44bsd, inet_aton))
+                AC_CHECK_LIB(resolv, main)
+                ;;
     esac
 fi
 AC_CHECK_LIB(m, main)
@@ -1582,173 +1609,173 @@
 dnl Robert Side <rside@aiinc.bc.ca>
 dnl Mon, 18 Jan 1999 17:48:00 GMT
 case "$host" in
-	*-pc-sco3.2*)
-		AC_CHECK_LIB(intl, strftime)
-		;;
+        *-pc-sco3.2*)
+                AC_CHECK_LIB(intl, strftime)
+                ;;
 esac
 
 dnl System-specific library modifications
 dnl
 case "$host" in
-	i386-*-solaris2.*)
-    		if test "$GCC" = "yes"; then
-			echo "Removing -O for gcc on $host"
-			CFLAGS="`echo $CFLAGS | sed -e 's/-O[[0-9]]*//'`"
-		fi
-		;;
-	*-sgi-irix*)
-        	echo "Removing -lsocket for IRIX..."
-        	LIBS=`echo $LIBS | sed -e s/-lsocket//`
-        	echo "Removing -lnsl for IRIX..."
-        	LIBS=`echo $LIBS | sed -e s/-lnsl//`
-		ac_cv_lib_nsl_main=no
-		echo "Removing -lbsd for IRIX..."
-		LIBS=`echo $LIBS | sed -e s/-lbsd//`
-		;;
+        i386-*-solaris2.*)
+                if test "$GCC" = "yes"; then
+                        echo "Removing -O for gcc on $host"
+                        CFLAGS="`echo $CFLAGS | sed -e 's/-O[[0-9]]*//'`"
+                fi
+                ;;
+        *-sgi-irix*)
+                echo "Removing -lsocket for IRIX..."
+                LIBS=`echo $LIBS | sed -e s/-lsocket//`
+                echo "Removing -lnsl for IRIX..."
+                LIBS=`echo $LIBS | sed -e s/-lnsl//`
+                ac_cv_lib_nsl_main=no
+                echo "Removing -lbsd for IRIX..."
+                LIBS=`echo $LIBS | sed -e s/-lbsd//`
+                ;;
 dnl From: c0032033@ws.rz.tu-bs.de (Joerg Schumacher)
 dnl Date: Thu, 17 Oct 1996 04:09:30 +0200
 dnl Please change your configure script.  AIX doesn't need -lbsd.
-	*-ibm-aix*)
-		echo "Removing -lbsd for AIX..."
-		LIBS=`echo $LIBS | sed -e s/-lbsd//`
+        *-ibm-aix*)
+                echo "Removing -lbsd for AIX..."
+                LIBS=`echo $LIBS | sed -e s/-lbsd//`
 dnl From: mlaster@metavillage.com (Mike Laster)
 dnl AIX 4.1.4.x does not have header files for snprintf/vsnprintf
 dnl So using the internal versions generates a load of warnings
 dnl during compile.
-		echo "disabling snprintf/vsnprintf for $host"
-		ac_cv_func_snprintf=no
-		ac_cv_func_vsnprintf=no
-		;;
-	*m88k*)
-		CFLAGS="$CFLAGS -D_SQUID_MOTOROLA_"
-		AC_DEFINE(GETTIMEOFDAY_NO_TZP)
-		;;
-	[*-*-solaris2.[0-4]])
-		AC_DEFINE(GETTIMEOFDAY_NO_TZP)
-		;;
-	[*-sony-newsos[56]*])
-		AC_DEFINE(GETTIMEOFDAY_NO_TZP)
-		;;
+                echo "disabling snprintf/vsnprintf for $host"
+                ac_cv_func_snprintf=no
+                ac_cv_func_vsnprintf=no
+                ;;
+        *m88k*)
+                CFLAGS="$CFLAGS -D_SQUID_MOTOROLA_"
+                AC_DEFINE(GETTIMEOFDAY_NO_TZP)
+                ;;
+        [*-*-solaris2.[0-4]])
+                AC_DEFINE(GETTIMEOFDAY_NO_TZP)
+                ;;
+        [*-sony-newsos[56]*])
+                AC_DEFINE(GETTIMEOFDAY_NO_TZP)
+                ;;
 esac
 
 # Remove optimization for GCC 2.95.[123]
 # gcc -O[2] on *BSD and Linux (x86) causes pointers to magically become NULL
 if test "$GCC" = "yes"; then
-	GCCVER=`$CC -v 2>&1 | awk '$2 ==  "version" {print $3}'`
-	case "$GCCVER" in
-	[2.95.[123]])
-		echo "Removing -O for gcc on $host with GCC $GCCVER"
-		CFLAGS="`echo $CFLAGS | sed -e 's/-O[[0-9]]*//'`"
-		;;
-	esac
+        GCCVER=`$CC -v 2>&1 | awk '$2 ==  "version" {print $3}'`
+        case "$GCCVER" in
+        [2.95.[123]])
+                echo "Removing -O for gcc on $host with GCC $GCCVER"
+                CFLAGS="`echo $CFLAGS | sed -e 's/-O[[0-9]]*//'`"
+                ;;
+        esac
 fi
 
 # Recommended by Balint Nagy Endre <bne@CareNet.hu>
 case "$host" in
-	*-univel-sysv4.2MP)
-		if test `uname -v` = "2.03"; then
-			echo "disabling mallinfo for $host"
-			ac_cv_func_mallinfo=no
-		fi
-		;;
+        *-univel-sysv4.2MP)
+                if test `uname -v` = "2.03"; then
+                        echo "disabling mallinfo for $host"
+                        ac_cv_func_mallinfo=no
+                fi
+                ;;
 esac
 
 dnl This has to be before AC_CHECK_FUNCS
 # Disable poll() on certain platforms. Override by setting ac_cv_func_poll
 # when running configure.
 if test -z "$ac_cv_func_poll"; then
-	case "$host" in
-		[alpha-dec-osf3.*])
-			# John Kay (jkay@nlanr.net) 19970818
-			echo "disabling poll for $host..."
-			ac_cv_func_poll='no'
-			;;
-		[*-hp-hpux*.*])
-			# Duane Wessels
-			echo "disabling poll for $host..."
-			ac_cv_func_poll='no'
-			;;
-		[*-linux-*])
-			# Henrik Nordstrom (hno@squid-cache.org) 19980817
-			# poll is problematic on Linux.  We disable it
-			# by default until Linux gets it right.
-			rev=`uname -r | awk -F. '{printf "%03d%03d",$1,$2}'`
-			if test $rev -lt 002002; then
-			    echo "disabling poll for $host < 2.2..."
-			    ac_cv_func_poll='no'
-			fi
-			;;
-		[powerpc-ibm-aix4.1.*])
-			# Mike Laster (mlaster@metavillage.com) 19981021
-			echo "disabling poll for $host..."
-			ac_cv_func_poll='no'
-			;;
-		[*-pc-sco3.2*])
-			# Robert Side <rside@aiinc.bc.ca>
-			# Mon, 18 Jan 1999 17:48:00 GMT
-			echo "disabling poll for $host..."
-			ac_cv_func_poll='no'
-			;;
-	esac
+        case "$host" in
+                [alpha-dec-osf3.*])
+                        # John Kay (jkay@nlanr.net) 19970818
+                        echo "disabling poll for $host..."
+                        ac_cv_func_poll='no'
+                        ;;
+                [*-hp-hpux*.*])
+                        # Duane Wessels
+                        echo "disabling poll for $host..."
+                        ac_cv_func_poll='no'
+                        ;;
+                [*-linux-*])
+                        # Henrik Nordstrom (hno@squid-cache.org) 19980817
+                        # poll is problematic on Linux.  We disable it
+                        # by default until Linux gets it right.
+                        rev=`uname -r | awk -F. '{printf "%03d%03d",$1,$2}'`
+                        if test $rev -lt 002002; then
+                            echo "disabling poll for $host < 2.2..."
+                            ac_cv_func_poll='no'
+                        fi
+                        ;;
+                [powerpc-ibm-aix4.1.*])
+                        # Mike Laster (mlaster@metavillage.com) 19981021
+                        echo "disabling poll for $host..."
+                        ac_cv_func_poll='no'
+                        ;;
+                [*-pc-sco3.2*])
+                        # Robert Side <rside@aiinc.bc.ca>
+                        # Mon, 18 Jan 1999 17:48:00 GMT
+                        echo "disabling poll for $host..."
+                        ac_cv_func_poll='no'
+                        ;;
+        esac
 fi
 
 dnl Check for library functions
 AC_CHECK_FUNCS(\
-	backtrace_symbols_fd \
-	bcopy \
-	bswap_16 \
-	bswap_32 \
-	crypt \
-	fchmod \
-	getdtablesize \
-	getpagesize \
-	getpass \
-	getrlimit \
-	getrusage \
-	getspnam \
-	lrand48 \
-	mallinfo \
-	mallocblksize \
-	mallopt \
-	memcpy \
-	memmove \
-	memset \
-	mkstemp \
-	mktime \
-	mstats \
-	poll \
-	pthread_attr_setschedparam \
-	pthread_attr_setscope \
-	pthread_setschedparam \
-	pthread_sigmask \
-	putenv \
-	random \
-	regcomp \
-	regexec \
-	regfree \
-	res_init \
-	rint \
-	select \
-	seteuid \
-	setgroups \
-	setpgrp \
-	setrlimit \
-	setsid \
-	sigaction \
-	snprintf \
-	socketpair \
-	srand48 \
-	srandom \
-	statfs \
-	sysconf \
-	syslog \
-	timegm \
-	vsnprintf \
+        backtrace_symbols_fd \
+        bcopy \
+        bswap_16 \
+        bswap_32 \
+        crypt \
+        fchmod \
+        getdtablesize \
+        getpagesize \
+        getpass \
+        getrlimit \
+        getrusage \
+        getspnam \
+        lrand48 \
+        mallinfo \
+        mallocblksize \
+        mallopt \
+        memcpy \
+        memmove \
+        memset \
+        mkstemp \
+        mktime \
+        mstats \
+        poll \
+        pthread_attr_setschedparam \
+        pthread_attr_setscope \
+        pthread_setschedparam \
+        pthread_sigmask \
+        putenv \
+        random \
+        regcomp \
+        regexec \
+        regfree \
+        res_init \
+        rint \
+        select \
+        seteuid \
+        setgroups \
+        setpgrp \
+        setrlimit \
+        setsid \
+        sigaction \
+        snprintf \
+        socketpair \
+        srand48 \
+        srandom \
+        statfs \
+        sysconf \
+        syslog \
+        timegm \
+        vsnprintf \
 )
 
 dnl Magic which checks whether we are forcing a type of comm loop we
 dnl are actually going to (ab)use
- 
+
 dnl Actually do the define magic now
 dnl mostly ripped from squid-commloops, thanks to adrian and benno
 
@@ -1759,8 +1786,8 @@
         SELECT_TYPE="select"
         AC_DEFINE(USE_SELECT)
 elif test "$ac_cv_func_kqueue" = "yes" ; then
-	SELECT_TYPE="kqueue"
-	AC_DEFINE(USE_KQUEUE)
+        SELECT_TYPE="kqueue"
+        AC_DEFINE(USE_KQUEUE)
 else
         echo "Eep!  Can't find poll, kqueue or select!"
         echo "I'll try select and hope for the best."
@@ -1769,7 +1796,6 @@
 fi
 echo "Using ${SELECT_TYPE} for select loop."
 
-
 dnl Yay!  Another Linux brokenness.  Its not good enough
 dnl to know that setresuid() exists, because RedHat 5.0 declares
 dnl setresuid() but doesn't implement it.
@@ -1794,7 +1820,7 @@
 if test "$ac_cv_func_snprintf" = "no" || test "$ac_cv_func_vsnprintf" = "no" ; then
   AM_CONDITIONAL(NEED_OWN_SNPRINTF, true)
 fi
-  
+
 dnl IP-Filter support requires ipf header files. These aren't
 dnl installed by default, so we need to check for them
 if test "$IPF_TRANSPARENT" ; then
@@ -1821,7 +1847,7 @@
         AC_DEFINE(IPF_TRANSPARENT, 0)
     fi
     AC_MSG_RESULT($IPF_TRANSPARENT)
-fi 
+fi
 if test "$IPF_TRANSPARENT" = "no" ; then
     echo "WARNING: Cannot find necessary IP-Filter header files"
     echo "         Transparent Proxy support WILL NOT be enabled"
@@ -1860,7 +1886,7 @@
         AC_DEFINE(LINUX_NETFILTER, 0)
     fi
     AC_MSG_RESULT($LINUX_NETFILTER)
-fi 
+fi
 if test "$LINUX_NETFILTER" = "no" ; then
     echo "WARNING: Cannot find necessary Linux 2.4 kernel header files"
     echo "         Linux 2.4 Transparent Proxy support WILL NOT be enabled"
@@ -1870,37 +1896,37 @@
 if test -z "$USE_GNUREGEX" ; then
     case "$host" in
     *-sun-solaris2.[[0-4]])
-	  USE_GNUREGEX="yes"
-	  ;;
+          USE_GNUREGEX="yes"
+          ;;
     *-next-nextstep*)
-	  USE_GNUREGEX="yes"
-	  ;;
+          USE_GNUREGEX="yes"
+          ;;
     esac
 fi
 AC_MSG_CHECKING(if GNUregex needs to be compiled)
 if test -z "$USE_GNUREGEX"; then
 if test "$ac_cv_func_regcomp" = "no" || test "$USE_GNUREGEX" = "yes" ; then
-	USE_GNUREGEX="yes"
+        USE_GNUREGEX="yes"
 else
-	AC_TRY_COMPILE([#include <sys/types.h>
+        AC_TRY_COMPILE([#include <sys/types.h>
 #include <regex.h>],[regex_t t; regcomp(&t,"",0);],
-		USE_GNUREGEX="no",
-		USE_GNUREGEX="yes")
+                USE_GNUREGEX="no",
+                USE_GNUREGEX="yes")
 fi
 fi
 AC_MSG_RESULT($USE_GNUREGEX)
 if test "$USE_GNUREGEX" = "yes"; then
-	REGEXLIB="-lregex"
-	LIBREGEX="libregex.a"
-	AC_DEFINE(USE_GNUREGEX)
+        REGEXLIB="-lregex"
+        LIBREGEX="libregex.a"
+        AC_DEFINE(USE_GNUREGEX)
 fi
 AC_SUBST(REGEXLIB)
 AC_SUBST(LIBREGEX)
 
 AC_REPLACE_FUNCS(\
-	drand48 \
-	tempnam \
-	strerror \
+        drand48 \
+        tempnam \
+        strerror \
 )
 
 dnl Not cached since people are likely to tune this
@@ -1922,9 +1948,9 @@
 #include <sys/types.h>
 #endif
 main() {
-	FILE *fp = fopen("conftestval", "w");
-	fprintf (fp, "%d\n", FD_SETSIZE);
-	exit(0);
+        FILE *fp = fopen("conftestval", "w");
+        fprintf (fp, "%d\n", FD_SETSIZE);
+        exit(0);
 }
 ],
 DEFAULT_FD_SETSIZE=`cat conftestval`,
@@ -1940,18 +1966,18 @@
 case $host in
 i386-unknown-freebsd*)
     if echo "$LDFLAGS" | grep -q pthread; then
-	LDFLAGS=`echo $LDFLAGS | sed -e "s/-pthread//"`
+        LDFLAGS=`echo $LDFLAGS | sed -e "s/-pthread//"`
     fi
 esac
 AC_TRY_RUN([
 #include <stdio.h>
 #include <unistd.h>
-#include <sys/time.h>	/* needed on FreeBSD */
+#include <sys/time.h>   /* needed on FreeBSD */
 #include <sys/param.h>
 #include <sys/resource.h>
 main() {
-	FILE *fp;
-	int i,j;
+        FILE *fp;
+        int i,j;
 #if defined(__CYGWIN32__) || defined (__CYGWIN__)
     /* getrlimit and sysconf returns bogous values on cygwin32.
      * Number of fds is virtually unlimited in cygwin (sys/param.h)
@@ -1981,12 +2007,12 @@
     }
 #endif /* RLIMIT_NOFILE */
 #endif /* HAVE_SETRLIMIT */
-	/* by starting at 2^14, we will never get higher
-	than 2^15 for SQUID_MAXFD */
+        /* by starting at 2^14, we will never get higher
+        than 2^15 for SQUID_MAXFD */
         i = j = 1<<14;
         while (j) {
                 j >>= 1;
-                if (dup2(0, i) < 0) { 
+                if (dup2(0, i) < 0) {
                         i -= j;
                 } else {
                         close(i);
@@ -1995,9 +2021,9 @@
         }
         i++;
 #endif /* IF !DEF CYGWIN */
-	fp = fopen("conftestval", "w");
-	fprintf (fp, "%d\n", i);
-	exit(0);
+        fp = fopen("conftestval", "w");
+        fprintf (fp, "%d\n", i);
+        exit(0);
 }
 ],
 SQUID_MAXFD=`cat conftestval`,
@@ -2024,14 +2050,14 @@
 #include <netinet/in.h>
 main ()
 {
-	FILE *fp;
+        FILE *fp;
         int fd,val=0,len=sizeof(int);
-	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1);
+        if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1);
         if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) exit(1);
-	if (val<=0) exit(1);
+        if (val<=0) exit(1);
         fp = fopen("conftestval", "w");
         fprintf (fp, "%d\n", val);
-	exit(0);
+        exit(0);
 }
 ],
 SQUID_UDP_SO_SNDBUF=`cat conftestval`,
@@ -2050,14 +2076,14 @@
 #include <netinet/in.h>
 main ()
 {
-	FILE *fp;
+        FILE *fp;
         int fd,val=0,len=sizeof(int);
-	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1);
+        if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1);
         if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) < 0) exit(1);
-	if (val <= 0) exit(1);
-	fp = fopen("conftestval", "w"); 
-	fprintf (fp, "%d\n", val);
-	exit(0);
+        if (val <= 0) exit(1);
+        fp = fopen("conftestval", "w");
+        fprintf (fp, "%d\n", val);
+        exit(0);
 }
 ],
 SQUID_UDP_SO_RCVBUF=`cat conftestval`,
@@ -2076,14 +2102,14 @@
 #include <netinet/in.h>
 main ()
 {
-	FILE *fp;
+        FILE *fp;
         int fd,val=0,len=sizeof(int);
-	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1);
+        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1);
         if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) exit(1);
-	if (val <= 0) exit(1);
-	fp = fopen("conftestval", "w"); 
-	fprintf (fp, "%d\n", val);
-	exit(0);
+        if (val <= 0) exit(1);
+        fp = fopen("conftestval", "w");
+        fprintf (fp, "%d\n", val);
+        exit(0);
 }
 ],
 SQUID_TCP_SO_SNDBUF=`cat conftestval`,
@@ -2102,14 +2128,14 @@
 #include <netinet/in.h>
 main ()
 {
-	FILE *fp;
+        FILE *fp;
         int fd,val=0,len=sizeof(int);
-	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1);
+        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1);
         if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) < 0) exit(1);
-	if (val <= 0) exit(1);
-	fp = fopen("conftestval", "w"); 
-	fprintf (fp, "%d\n", val);
-	exit(0);
+        if (val <= 0) exit(1);
+        fp = fopen("conftestval", "w");
+        fprintf (fp, "%d\n", val);
+        exit(0);
 }
 ],
 SQUID_TCP_SO_RCVBUF=`cat conftestval`,
@@ -2143,27 +2169,27 @@
 #include <arpa/inet.h>
 main ()
 {
-	FILE *fp;
-	struct in_addr in;
-	in.s_addr = inet_addr("1.2.3.4");
-	fp = fopen("conftestval", "w"); 
-	fprintf (fp, "%s\n", inet_ntoa(in));
-	exit(0);
+        FILE *fp;
+        struct in_addr in;
+        in.s_addr = inet_addr("1.2.3.4");
+        fp = fopen("conftestval", "w");
+        fprintf (fp, "%s\n", inet_ntoa(in));
+        exit(0);
 }
 ],
 INET_NTOA_RESULT=`cat conftestval`,
 INET_NTOA_RESULT="broken",
 INET_NTOA_RESULT="broken")
 if test "$INET_NTOA_RESULT" = "1.2.3.4" ; then
-	AC_MSG_RESULT("yes")
+        AC_MSG_RESULT("yes")
 else
-	AC_MSG_RESULT("no")
-	echo "Will use our own inet_ntoa()."
-	LIBOBJS="$LIBOBJS inet_ntoa.o"
-#	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."
-#	sleep 10
+        AC_MSG_RESULT("no")
+        echo "Will use our own inet_ntoa()."
+        LIBOBJS="$LIBOBJS inet_ntoa.o"
+#       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."
+#       sleep 10
 fi
 
 if test "$ac_cv_header_sys_statvfs_h" = "yes" ; then
@@ -2176,7 +2202,7 @@
 ],
 [
 struct statvfs sfs;
-sfs.f_blocks = sfs.f_bfree = sfs.f_frsize = 
+sfs.f_blocks = sfs.f_bfree = sfs.f_frsize =
 sfs.f_files = sfs.f_ffree = 0;
 statvfs("/tmp", &sfs);
 ],
@@ -2243,51 +2269,50 @@
 dnl Need the debugging version of malloc if available
 XTRA_OBJS=''
 if test "$ac_cv_lib_malloc_main" = "yes" ; then
-	if test -r /usr/lib/debug/malloc.o ; then
-		XTRA_OBJS="$XTRA_OBJS /usr/lib/debug/malloc.o"
-	fi
-	if test -r /usr/lib/debug/mallocmap.o ; then
-		XTRA_OBJS="$XTRA_OBJS /usr/lib/debug/mallocmap.o"
-	fi
+        if test -r /usr/lib/debug/malloc.o ; then
+                XTRA_OBJS="$XTRA_OBJS /usr/lib/debug/malloc.o"
+        fi
+        if test -r /usr/lib/debug/mallocmap.o ; then
+                XTRA_OBJS="$XTRA_OBJS /usr/lib/debug/mallocmap.o"
+        fi
 fi
 
 AC_SUBST(XTRA_OBJS)
 
 if test -z "$XTRA_LIBS"; then
-	XTRA_LIBS="$LIBS"
-	dnl minor cleanup
-	XTRA_LIBS=`echo $XTRA_LIBS | sed -e "s/  */ /g"`
-	LIBS=''
+        XTRA_LIBS="$LIBS"
+        dnl minor cleanup
+        XTRA_LIBS=`echo $XTRA_LIBS | sed -e "s/  */ /g"`
+        LIBS=''
 fi
 AC_SUBST(XTRA_LIBS)
 
 dnl Clean up after OSF/1 core dump bug
-rm -f core 
+rm -f core
 
 dnl FS_MAKEFILES=""
 dnl for fs in $STORE_MODULES none; do
-dnl 	if test $fs != none; then
-dnl	    FS_MAKEFILES="$FS_MAKEFILES ./src/fs/$fs/Makefile"
-dnl 	fi
+dnl     if test $fs != none; then
+dnl         FS_MAKEFILES="$FS_MAKEFILES ./src/fs/$fs/Makefile"
+dnl     fi
 dnl done
 dnl REPL_MAKEFILES=""
 dnl for repl in $REPL_POLICIES none; do
-dnl 	if test $repl != none; then
-dnl 	    REPL_MAKEFILES="$REPL_MAKEFILES ./src/repl/$repl/Makefile"
-dnl 	fi
+dnl     if test $repl != none; then
+dnl         REPL_MAKEFILES="$REPL_MAKEFILES ./src/repl/$repl/Makefile"
+dnl     fi
 dnl done
 
 dnl This could actually be used to find all the Makefiles..
 dnl One of Automake's limitations is that it needs to know all the created makefiles.
 dnl AUTH_MAKEFILES=""
 dnl for auth in `find $srcdir/src/auth -type d -print`; do
-dnl 	if test -f $auth/Makefile.in; then
-dnl	    dir=`echo $auth | sed -e "s|^$srcdir/||"`
+dnl     if test -f $auth/Makefile.in; then
+dnl         dir=`echo $auth | sed -e "s|^$srcdir/||"`
 dnl            AUTH_MAKEFILES="$AUTH_MAKEFILES ./$dir/Makefile"
-dnl	fi
+dnl     fi
 dnl done
 
-
 dnl     src/fs/aufs/Makefile \
 dnl     src/fs/coss/Makefile \
 dnl     src/fs/diskd/Makefile \
@@ -2296,54 +2321,55 @@
 dnl     src/repl/heap/Makefile \
 dnl     src/repl/lru/Makefile \
 AC_OUTPUT([\
-	Makefile \
-	lib/Makefile \
-	scripts/Makefile \
-	scripts/RunCache \
-	scripts/RunAccel \
-	src/Makefile \
-	src/fs/Makefile \
-	src/repl/Makefile \
-	src/auth/Makefile \
-	src/auth/basic/Makefile \
-	src/auth/digest/Makefile \
-	src/auth/ntlm/Makefile \
-	contrib/Makefile \
-	snmplib/Makefile \
-	icons/Makefile \
-	errors/Makefile \
-	src/fs/aufs/Makefile \
-	src/fs/coss/Makefile \
-	src/fs/diskd/Makefile \
-	src/fs/null/Makefile \
-	src/fs/ufs/Makefile \
-	src/repl/heap/Makefile \
-	src/repl/lru/Makefile \
-	doc/Makefile \
-	helpers/Makefile \
-	helpers/basic_auth/Makefile \
-	helpers/basic_auth/LDAP/Makefile \
-	helpers/basic_auth/MSNT/Makefile \
-	helpers/basic_auth/NCSA/Makefile \
-	helpers/basic_auth/PAM/Makefile \
-	helpers/basic_auth/SMB/Makefile \
-	helpers/basic_auth/YP/Makefile \
-	helpers/basic_auth/getpwnam/Makefile \
-	helpers/basic_auth/multi-domain-NTLM/Makefile \
-	helpers/basic_auth/SASL/Makefile \
-	helpers/basic_auth/winbind/Makefile \
-	helpers/digest_auth/Makefile \
-	helpers/digest_auth/password/Makefile \
-	helpers/ntlm_auth/Makefile \
-	helpers/ntlm_auth/fakeauth/Makefile \
-	helpers/ntlm_auth/no_check/Makefile \
-	helpers/ntlm_auth/SMB/Makefile \
-	helpers/ntlm_auth/SMB/smbval/Makefile \
-	helpers/ntlm_auth/winbind/Makefile \
-	helpers/external_acl/Makefile \
-	helpers/external_acl/ip_user/Makefile \
-	helpers/external_acl/ldap_group/Makefile \
-	helpers/external_acl/unix_group/Makefile \
-	helpers/external_acl/wbinfo_group/Makefile \
-	helpers/external_acl/winbind_group/Makefile \
+        Makefile \
+        lib/Makefile \
+        scripts/Makefile \
+        scripts/RunCache \
+        scripts/RunAccel \
+        src/Makefile \
+        src/fs/Makefile \
+        src/repl/Makefile \
+        src/auth/Makefile \
+        src/auth/basic/Makefile \
+        src/auth/digest/Makefile \
+        src/auth/ntlm/Makefile \
+        contrib/Makefile \
+        snmplib/Makefile \
+        icons/Makefile \
+        errors/Makefile \
+        src/fs/aufs/Makefile \
+        src/fs/coss/Makefile \
+        src/fs/diskd/Makefile \
+        src/fs/null/Makefile \
+        src/fs/ufs/Makefile \
+        src/repl/heap/Makefile \
+        src/repl/lru/Makefile \
+        doc/Makefile \
+        helpers/Makefile \
+        helpers/basic_auth/Makefile \
+        helpers/basic_auth/LDAP/Makefile \
+        helpers/basic_auth/MSNT/Makefile \
+        helpers/basic_auth/NCSA/Makefile \
+        helpers/basic_auth/PAM/Makefile \
+        helpers/basic_auth/SMB/Makefile \
+        helpers/basic_auth/YP/Makefile \
+        helpers/basic_auth/getpwnam/Makefile \
+        helpers/basic_auth/multi-domain-NTLM/Makefile \
+        helpers/basic_auth/SASL/Makefile \
+        helpers/basic_auth/winbind/Makefile \
+        helpers/digest_auth/Makefile \
+        helpers/digest_auth/password/Makefile \
+        helpers/ntlm_auth/Makefile \
+        helpers/ntlm_auth/fakeauth/Makefile \
+        helpers/ntlm_auth/no_check/Makefile \
+        helpers/ntlm_auth/SMB/Makefile \
+        helpers/ntlm_auth/SMB/smbval/Makefile \
+        helpers/ntlm_auth/winbind/Makefile \
+        helpers/external_acl/Makefile \
+        helpers/external_acl/ip_user/Makefile \
+        helpers/external_acl/ldap_group/Makefile \
+        helpers/external_acl/unix_group/Makefile \
+        helpers/external_acl/wbinfo_group/Makefile \
+        helpers/external_acl/winbind_group/Makefile \
 ])
+
Index: squid/mkrelease.sh
diff -u squid/mkrelease.sh:1.6 squid/mkrelease.sh:1.2.12.2
--- squid/mkrelease.sh:1.6	Sun Sep  1 09:30:40 2002
+++ squid/mkrelease.sh	Tue Sep  3 10:39:10 2002
@@ -50,6 +50,15 @@
 make dist-all
 
 cd $startdir
+<<<<<<< mkrelease.sh
+cp -p $tmpdir/${name}.tar.gz	$dst
+cp -p $tmpdir/${name}.tar.bz2	$dst
+cp -p $tmpdir/CONTRIBUTORS	$dst/CONTRIBUTORS.txt
+cp -p $tmpdir/COPYING		$dst/COPYING.txt
+cp -p $tmpdir/COPYRIGHT		$dst/COPYRIGHT.txt
+cp -p $tmpdir/CREDITS		$dst/CREDITS.txt
+cp -p $tmpdir/ChangeLog		$dst/ChangeLog.txt
+=======
 cp -p $tmpdir/${name}.tar.gz	$dst
 cp -p $tmpdir/${name}.tar.bz2	$dst
 cp -p $tmpdir/CONTRIBUTORS	$dst/CONTRIBUTORS.txt
@@ -60,3 +69,4 @@
 if [ -f $tmpdir/doc/release-notes/release-$RELEASE.html ]; then
     cp -p $tmpdir/doc/release-notes/release-$RELEASE.html $dst/RELEASENOTES.html
 fi
+>>>>>>> 1.6
Index: squid/doc/push.txt
diff -u /dev/null squid/doc/push.txt:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/doc/push.txt	Mon May 20 19:46:41 2002
@@ -0,0 +1,133 @@
+		HOW TO USE PUSH
+
+		  Jon Kay
+	        pushcache.com
+
+
+This document is about how to make use of a pushcache.  There are
+basically two ways: you can either speak the protocol, which is a
+couple of simple addenda to standard HTTP, or, those of you whose
+lives extend beyond writing HTTP protocol code can use a shell script
+called 'webpush.'  Webpush is meant as a parallel command to 'client'
+(e.g., it's client, but for push rather than pull), so, just like
+client, it can be found in the bin subdirectory of installed Squid
+trees, and the src subdirectory in source distributions.
+
+Arguably, there is no need for 'webpush.'  You can do much the same
+thing by executing:
+   client -m PUT <url> <file>
+
+But most people find that just really tough to think about, so instead
+we have the more user-friendly
+
+    webpush <url> <file>
+
+constitute the shell and scripting interface to pushcaches.  Besides,
+webpush preserves Last-modified information (stat st_mtime) from the
+file.  That may not seem like much, but it's seriously handy in the
+push world, where that amounts to a version number, and it used to
+figure out which of different URL contents to keep as current.
+
+You can push any kind of content.  You can see the results by changing
+your browsers Preferences/Advanced/Proxies settings to point to Squid
+(default port is 3128), and then looking in on the file, or reloading
+if you already have fetched an old copy.
+
+PUT ACL
+
+Before you do anything, whether with webpush or programming, you have
+to set up your acls so that they permit PUT requests from everyone you
+want to be able to do push.  See the ACL section of your
+etc/squid.conf; for most people, the appropriate thing will be to
+simply allow all types of requests from whomever the Good Guys are.
+
+PUSHING HTTP
+
+The other way to do push is, as we said, to speak the protocol.
+A push application would, probably with the aid of an appropriate
+programming library such as pushcache.com's PushAp Kit push library,
+use these protocol elements to communicate with pushcaches.
+
+Pushcaches, in turn, use these protocols plus hint cache protocols
+(not defined in this document) to communicate.
+
+There are, in effect, two requests:  push and dist.  
+
+
+
+PUSH
+
+Push is accomplished by sending a standard HTTP PUT request to a local
+pushcache.  There is no protocol addendum, except in practical usage
+terms.  A pushcache receiving such a request is expected to
+effectively propagate the object sent on the given URL to every
+interested pushcache and application instance connected to the same
+pushcache cloud.
+
+An application or cache is defined to be interested if it has sent a 
+dist request to a local pushcache.
+
+
+DIST
+
+Dists are accomplished by sending a special nonstandard HTTP request
+to a local pushcache.  The format is a standard GET request, except
+that the URL is augmented to append the string 'dist' and a TCP port
+number to the URL method.  E.g., the first line of a dist request
+for http://server/file would be:
+
+      GET httpdist6543://server/file HTTP/1.0\r\n
+
+The pushcache returns the contents of http://server/file, then, later,
+when the contents of http://server/file change, it sends the new
+contents via HTTP PUT to the host that originated the 'dist' at the
+TCP port number specified in the dist request.  Third-party dists are
+not supported, for security.
+
+If there is an error, e.g., the server or the file does not exist, the
+pushcache will not remember the request should the URL later become
+valid.
+
+We chose not to define a new DIST request type to facilitate
+interoperation with non-pushy firewalls and proxies.
+
+
+PUSHCACHE OPERATION
+
+Pushcache clouds in effect create a distribution tree for each object
+as interest in that object spreads.  
+
+Most pushcaches forward GET requests to neighboring caches as dists
+instead, in effect implementing eager consistency.
+
+If a pushcache receives a dist request for an object it has a copy of 
+already, it distributes the object and changes to it, in effect
+implementing a distribution link, adding a link a node to whatever
+digraph the pushcache is already part of.
+
+When pushcaches send dist requests to other pushcaches, they
+act as though that pushcache sent them a dist request as well, for
+purposes of propagating later changes (they do not send an immediate
+current copy).  Thus, distribution links between pushcaches are
+automatically bidirectional (NOT true of distribution links to client
+applications).
+
+A pushcache receiving a dist request for an object it does not know
+about consults its magic hint cache.  Each pushcache knows the closest
+location of every object that any pushcache in the connected cloud
+knows about.  If it's in the hint cache, it knows about the object,
+otherwise not.	If it can find it, the pushcache sends a dist request
+to that closest pushcache that does have it, attaching this cache to
+the digraph for that object.
+
+
+SEMANTICS VS. SCALING
+
+Pushcaches implement "best effort" consistency.  That is, they make a
+good effort, will usually succeed, but there are no guarantees.  This
+design point was chosen to optimize for scalability.  We believe this
+will suffice for most potential applications, though certainly not all.
+
+Research is ongoing into improving consistency without losing
+scalability.
+
Index: squid/doc/Programming-Guide/prog-guide.sgml
diff -u squid/doc/Programming-Guide/prog-guide.sgml:1.21 squid/doc/Programming-Guide/prog-guide.sgml:1.16.8.1
--- squid/doc/Programming-Guide/prog-guide.sgml:1.21	Fri Aug  9 14:45:58 2002
+++ squid/doc/Programming-Guide/prog-guide.sgml	Tue Sep  3 10:39:11 2002
@@ -64,27 +64,6 @@
 	structures and their members will be written in an italicized
 	font, such as <em/StoreEntry/.
 
-<sect>Coding Conventions
-
-<sect1>Infrastructure
-
-	<P>
-	Most custom types and tools are documented in the code or the relevant
-	portions of this manual. Some key points apply globally however.
-
-<sect2>Fixed width types
-	<P>
-	If you need to use specific width types - such as
-	a 16 bit unsigned integer, use one of the following types. To access
-	them simply include "config.h".
-        <enum>
-	<item>int16_t   - 16 bit signed.
-	<item>u_int16_t - 16 bit unsigned.
-	<item>int32t    - 32 bit signed.
-	<item>u_int32_t - 32 bit unsigned.
-	<item>int64_t   - 64 bit signed.
-	<item>u_int64_t - 64 bit unsigned.
-	</enum>
 
 <sect>Overview of Squid Components
 
@@ -405,7 +384,7 @@
 <sect1>Refresh Rules
 
 	<P>
-	These routines decide whether a cached object is stale or fresh,
+	These routines decide wether a cached object is stale or fresh,
 	based on the <em/refresh_pattern/ configuration options.
 	If an object is fresh, it can be returned as a cache hit.
 	If it is stale, then it must be revalidated with an	
@@ -423,7 +402,7 @@
 	<P>
 	We are experimenting with URN support in Squid version 1.2.
 	Note, we're not talking full-blown generic URN's here. This
-	is primarily targeted toward using URN's as an smart way
+	is primarily targeted towards using URN's as an smart way
 	of handling lists of mirror sites.  For more details, please
 	see <url        url="http://squid.nlanr.net/Squid/urn-support.html"
 	name="URN support in Squid">.
@@ -2527,10 +2506,9 @@
 	<P>
 	Macro that defines a new cbdata datatype. Similar to a variable
 	or struct definition. Scope is always local to the file/block
-	where it is defined and all calls to cbdataAlloc for this type
-	must be within the same scope as the CBDATA_TYPE declaration.
-	Allocated entries may be referenced or freed anywhere with no
-	restrictions on scope.
+	where it is defined and all allocations must be within this scope.
+	Allocated entries referenced or freed anywhere with no restrictions
+	on scope.
 
 <sect2>CBDATA_GLOBAL_TYPE
 
@@ -2643,12 +2621,10 @@
 
 	<P>
 	Removes a reference created by cbdataReference() and checks
-	it for validity. A temporary pointer to the referenced data
-	(if valid) is returned in the &amp;pointer argument.
+	it for validity.
 	
 	<P>
-	Meant to be used on the last dereference, usually to make
-	a callback.
+	Meant to be used on the last dereference
 
 <verb>
 	void *cbdata;
@@ -2663,120 +2639,81 @@
 <sect1>Examples
 
 	<P>
-	Here you can find some examples on how to use cbdata, and why
-
-<sect2>Asynchronous operation without cbdata, showing why cbdata is needed
-
-	<P>
-	For a asyncronous operation with callback functions, the normal
-	sequence of events in programs NOT using cbdata is as follows:
+	For a blocking operation
+	with callback functions, the normal sequence of events is as
+	follows:
 <verb>
-	/* initialization */
-	type_of_data our_data;
-	...
-	our_data = malloc(...);
+	callback_data = malloc(...);
 	...
-	/* Initiate a asyncronous operation, with our_data as callback_data */
-	fooOperationStart(bar, callback_func, our_data);
+	fooOperationStart(bar, callback_func, callback_data);
 	...
-	/* The asyncronous operation completes and makes the callback */
+	fooOperationComplete(...);
 	callback_func(callback_data, ....);
-	/* Some time later we clean up our data */
-	free(our_data);
+	...
+	free(callback_data);
 </verb>
 	However, things become more interesting if we want or need
 	to free the callback_data, or otherwise cancel the callback,
-	before the operation completes. In constructs like this you
-	can quite easily end up with having the memory referenced
-	pointed to by callback_data freed before the callback is invoked
-	causing a program failure or memory corruption:
-<verb>
-	/* initialization */
-	type_of_data our_data;
-	...
-	our_data = malloc(...);
-	...
-	/* Initiate a asyncronous operation, with our_data as callback_data */
-	fooOperationStart(bar, callback_func, our_data);
-	...
-	/* ouch, something bad happened elsewhere.. try to cleanup
-	 * but the programmer forgot there is a callback pending from
-	 * fooOperationsStart() (an easy thing to forget when writing code
-	 * to deal with errors, especially if there may be many different
-	 * pending operation)
-	 */
-	free(our_data);
-	...
-	/* The asyncronous operation completes and makes the callback */
-	callback_func(callback_data, ....);
-	/* CRASH, the memory pointer to by callback_data is no longer valid
-	 * at the time of the callback
-	 */
-</verb>
-<sect2>Asyncronous operation with cbdata
+	before the operation completes.
 
 	<P>
 	The callback data allocator lets us do this in a uniform and
 	safe manner.  The callback data allocator is used to allocate,
 	track and free memory pool objects used during callback
-	operations.  Allocated memory is locked while the asyncronous
+	operations.  Allocated memory is locked while the blocking
 	operation executes elsewhere, and is freed when the operation
 	completes.  The normal sequence of events is:
 <verb>
 	/* initialization */
-	type_of_data our_data;
+	type_of_data callback_data;
 	...
-	our_data = cbdataAlloc(type_of_data);
+	callback_data = cbdataAlloc(type_of_data);
 	...
-	/* Initiate a asyncronous operation, with our_data as callback_data */
-	fooOperationStart(..., callback_func, our_data);
+	/* calling "foo" */
+	fooOperationStart(..., callback_func, callback_data);
 	...
-	/* foo */
-	void *local_pointer = cbdataReference(callback_data);
-	....
-	/* The asyncronous operation completes and makes the callback */
-	void *cbdata;
-	if (cbdataReferenceValidDone(local_pointer, &amp;cbdata))
-	    callback_func(...., cbdata);
-	...
-	cbdataFree(our_data);
+	/* being destroyed */
+	cbdataFree(callback_data);
 
+	/* foo */
+	void
+	fooOperationStart(..., callback_func, void *callback_data)
+	{
+	    void *local_pointer = cbdataReference(callback_data);
+	    ....
+	}
+	void
+	fooOperationComplete(...)
+	{
+	    void *cbdata;
+	    ...
+	    if (cbdataReferenceValidDone(local_pointer, &amp;cbdata))
+		callback_func(...., cbdata);
+	}
 </verb>
 
-<sect2>Asynchronous operation cancelled by cbdata
-
 	<P>
 	With this scheme, nothing bad happens if <tt/cbdataFree/ gets called
 	before fooOperantionComplete(...).
 <verb>
-	/* initialization */
-	type_of_data our_data;
-	...
-	our_data = cbdataAlloc(type_of_data);
+	callback_data = cbdataAlloc(...);
 	...
-	/* Initiate a asyncronous operation, with our_data as callback_data */
-	fooOperationStart(..., callback_func, our_data);
+	fooOperationStart(bar, callback_func, callback_data);
+	local_pointer = cbdataReference(callback_data);
 	...
-	/* foo */
-	void *local_pointer = cbdataReference(callback_data);
-	....
-	/* something bad happened elsewhere.. cleanup */
-	cbdataFree(our_data);
+	cbdataFree(callback_data);
 	...
-	/* The asyncronous operation completes and tries to make the callback */
+	fooOperationComplete(...);
 	void *cbdata;
-	if (cbdataReferenceValidDone(local_pointer, &amp;cbdata))
-	    /* won't be called, as the data is no longer valid */
-	    callback_func(...., cbdata);
-
+	if (cbdataReferenceValidDone(local_pointer, cbdata))
+	    callback_func(cbdata, ....);
 </verb>
 	In this case, when <tt/cbdataFree/ is called before
 	<tt/cbdataReferenceValidDone/, the callback_data gets marked as invalid.
-	When the callback_data is invalid before executing the callback
-	function, <tt/cbdataReferenceValidDone/ will return 0 and
-	callback_func is never executed.
-
-<sect2>Adding a new cbdata registered type
+	Before executing the callback function, <tt/cbdataReferenceValidDone/ will return 0
+	and callback_func is never executed.  When <tt/cbdataReferenceValidDone/ gets
+	called, it notices that the callback_data is invalid and will
+	then call <tt/cbdataFree/.
 
 	<P>
 	To add new module specific data types to the allocator one uses the
@@ -2795,24 +2732,16 @@
 	 * (can be called multiple times with only a minimal overhead)
 	 */
 	CBDATA_INIT_TYPE(type_of_data);
-	/* Or if a free function is associated with the data type. This
-	 * function is responsible for cleaning up any dependencies etc
-	 * referenced by the structure and is called on cbdataFree or
-	 * when the last reference is deleted by cbdataReferenceDone /
-	 * cbdataReferenceValidDone
-	 */
+	/* Or if a free function is associated with the data type */
 	CBDATA_INIT_TYPE_FREECB(type_of_data, free_function);
 </verb>
 
-<sect2>Adding a new cbdata registered data type globally
-
 	<P>
-	To add new global data types that can be allocated from anywhere
-	within the code one have to add them to the cbdata_type enum in
-	enums.h, and a corresponding CREATE_CBDATA call in
-	cbdata.c:cbdataInit(). Or alternatively add a CBDATA_GLOBAL_TYPE
-	definition to globals.h as shown below and use CBDATA_INIT_TYPE at
-	the appropriate location(s) as described above.
+	To add new global data types one have to add them to the
+	cbdata_type enum in enums.h, and a corresponding
+	CREATE_CBDATA call in cbdata.c:cbdataInit(). Or alternatively
+	add a CBDATA_GLOBAL_TYPE definition to globals.h and use
+	CBDATA_INIT_TYPE as described above.
 
 <verb>
 	extern CBDATA_GLOBAL_TYPE(type_of_data);	/* CBDATA_UNDEF */
Index: squid/errors/list
diff -u squid/errors/list:1.1.1.1 squid/errors/list:1.1.1.1.120.1
--- squid/errors/list:1.1.1.1	Tue Jan 25 19:21:47 2000
+++ squid/errors/list	Fri Dec  7 15:25:31 2001
@@ -3,6 +3,7 @@
 ERR_CACHE_MGR_ACCESS_DENIED
 ERR_CANNOT_FORWARD
 ERR_CLIENT_ABORT
+ERR_CONFLICT
 ERR_CONNECT_FAIL
 ERR_DNS_FAIL
 ERR_FORWARDING_DENIED
Index: squid/errors/Bulgarian/ERR_CONFLICT
diff -u /dev/null squid/errors/Bulgarian/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/Bulgarian/ERR_CONFLICT	Sat Dec 22 08:31:33 2001
@@ -0,0 +1,34 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+The system returned:
+<PRE><I>    %E</I></PRE>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Catalan/ERR_ACCESS_DENIED
diff -u squid/errors/Catalan/ERR_ACCESS_DENIED:1.4 squid/errors/Catalan/ERR_ACCESS_DENIED:1.4.6.1
--- squid/errors/Catalan/ERR_ACCESS_DENIED:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_ACCESS_DENIED	Tue Sep  3 10:39:18 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED
diff -u squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4 squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4.6.1
--- squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED	Tue Sep  3 10:39:18 2002
@@ -1,12 +1,10 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: Acc&eacute;s denegat a la cache</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD>
 <BODY>
 <H1>ERROR</H1>
 <H2>Acc&eacute;s denegat a la cache</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED
diff -u squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4 squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4.6.1
--- squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED	Tue Sep  3 10:39:19 2002
@@ -1,12 +1,10 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: Acc&eacute;s denegat a l'administraci&oacute; de la cache</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD>
 <BODY>
 <H1>ERROR</H1>
 <H2>ERROR: Acc&eacute;s denegat a l'administraci&oacute; de la cache</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_CANNOT_FORWARD
diff -u squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4 squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4.6.1
--- squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_CANNOT_FORWARD	Tue Sep  3 10:39:19 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_CONNECT_FAIL
diff -u squid/errors/Catalan/ERR_CONNECT_FAIL:1.4 squid/errors/Catalan/ERR_CONNECT_FAIL:1.4.6.1
--- squid/errors/Catalan/ERR_CONNECT_FAIL:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_CONNECT_FAIL	Tue Sep  3 10:39:20 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_DNS_FAIL
diff -u squid/errors/Catalan/ERR_DNS_FAIL:1.4 squid/errors/Catalan/ERR_DNS_FAIL:1.4.6.1
--- squid/errors/Catalan/ERR_DNS_FAIL:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_DNS_FAIL	Tue Sep  3 10:39:20 2002
@@ -1,10 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_FORWARDING_DENIED
diff -u squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4 squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4.6.1
--- squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FORWARDING_DENIED	Tue Sep  3 10:39:21 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_FTP_DISABLED
diff -u squid/errors/Catalan/ERR_FTP_DISABLED:1.4 squid/errors/Catalan/ERR_FTP_DISABLED:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_DISABLED:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_DISABLED	Tue Sep  3 10:39:21 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_FTP_FAILURE
diff -u squid/errors/Catalan/ERR_FTP_FAILURE:1.4 squid/errors/Catalan/ERR_FTP_FAILURE:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_FAILURE:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_FAILURE	Tue Sep  3 10:39:21 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 S'ha produ&iuml;t un error FTP mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_FTP_FORBIDDEN
diff -u squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4 squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_FORBIDDEN	Tue Sep  3 10:39:21 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 S'ha produ&iuml;t un error en l'autentificaci&oacute; FTP
 mentre s'intentava llegir la URL
Index: squid/errors/Catalan/ERR_FTP_NOT_FOUND
diff -u squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4 squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_NOT_FOUND	Tue Sep  3 10:39:21 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_FTP_PUT_CREATED
diff -u squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4 squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_PUT_CREATED	Tue Sep  3 10:39:21 2002
@@ -1,8 +1,6 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>Comanda FTP PUT executada amb &egrave;xit: Fitxer creat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>Operaci&oacute; completada</H1>
 <H2>Fitxer creat</H2>
-<HR noshade size="1px">
+<HR>
Index: squid/errors/Catalan/ERR_FTP_PUT_ERROR
diff -u squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4 squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_PUT_ERROR	Tue Sep  3 10:39:21 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: Ha fallat l'enviament del fitxer FTP</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>Ha fallat la comanda FTP d'enviament de fitxer</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava la comanda PUT a la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_FTP_PUT_MODIFIED
diff -u squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4 squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_PUT_MODIFIED	Tue Sep  3 10:39:21 2002
@@ -1,8 +1,6 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>Comanda FTP PUT completada amb &eacute;xit: Fitxer actualitzat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>Operaci&oacute; completada</H1>
 <H2>Fitxer actualitzat</H2>
-<HR noshade size="1px">
+<HR>
Index: squid/errors/Catalan/ERR_FTP_UNAVAILABLE
diff -u squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4 squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_UNAVAILABLE	Tue Sep  3 10:39:21 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 El servidor FTP estava massa ocupat quan intentava mostrar la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_INVALID_REQ
diff -u squid/errors/Catalan/ERR_INVALID_REQ:1.4 squid/errors/Catalan/ERR_INVALID_REQ:1.4.6.1
--- squid/errors/Catalan/ERR_INVALID_REQ:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_INVALID_REQ	Tue Sep  3 10:39:22 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <PRE>
Index: squid/errors/Catalan/ERR_INVALID_URL
diff -u squid/errors/Catalan/ERR_INVALID_URL:1.4 squid/errors/Catalan/ERR_INVALID_URL:1.4.6.1
--- squid/errors/Catalan/ERR_INVALID_URL:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_INVALID_URL	Tue Sep  3 10:39:22 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_LIFETIME_EXP
diff -u squid/errors/Catalan/ERR_LIFETIME_EXP:1.4 squid/errors/Catalan/ERR_LIFETIME_EXP:1.4.6.1
--- squid/errors/Catalan/ERR_LIFETIME_EXP:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_LIFETIME_EXP	Tue Sep  3 10:39:22 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_NO_RELAY
diff -u squid/errors/Catalan/ERR_NO_RELAY:1.4 squid/errors/Catalan/ERR_NO_RELAY:1.4.6.1
--- squid/errors/Catalan/ERR_NO_RELAY:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_NO_RELAY	Tue Sep  3 10:39:22 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS
diff -u squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4 squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4.6.1
--- squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS	Tue Sep  3 10:39:22 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_READ_ERROR
diff -u squid/errors/Catalan/ERR_READ_ERROR:1.4 squid/errors/Catalan/ERR_READ_ERROR:1.4.6.1
--- squid/errors/Catalan/ERR_READ_ERROR:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_READ_ERROR	Tue Sep  3 10:39:22 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_READ_TIMEOUT
diff -u squid/errors/Catalan/ERR_READ_TIMEOUT:1.4 squid/errors/Catalan/ERR_READ_TIMEOUT:1.4.6.1
--- squid/errors/Catalan/ERR_READ_TIMEOUT:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_READ_TIMEOUT	Tue Sep  3 10:39:23 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_SHUTTING_DOWN
diff -u squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4 squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4.6.1
--- squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_SHUTTING_DOWN	Tue Sep  3 10:39:23 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_SOCKET_FAILURE
diff -u squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4 squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4.6.1
--- squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_SOCKET_FAILURE	Tue Sep  3 10:39:23 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_TOO_BIG
diff -u squid/errors/Catalan/ERR_TOO_BIG:1.4 squid/errors/Catalan/ERR_TOO_BIG:1.4.6.1
--- squid/errors/Catalan/ERR_TOO_BIG:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_TOO_BIG	Tue Sep  3 10:39:23 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_UNSUP_REQ
diff -u squid/errors/Catalan/ERR_UNSUP_REQ:1.4 squid/errors/Catalan/ERR_UNSUP_REQ:1.4.6.1
--- squid/errors/Catalan/ERR_UNSUP_REQ:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_UNSUP_REQ	Tue Sep  3 10:39:23 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_URN_RESOLVE
diff -u squid/errors/Catalan/ERR_URN_RESOLVE:1.4 squid/errors/Catalan/ERR_URN_RESOLVE:1.4.6.1
--- squid/errors/Catalan/ERR_URN_RESOLVE:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_URN_RESOLVE	Tue Sep  3 10:39:23 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URN que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URN que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URN:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_WRITE_ERROR
diff -u squid/errors/Catalan/ERR_WRITE_ERROR:1.5 squid/errors/Catalan/ERR_WRITE_ERROR:1.5.6.1
--- squid/errors/Catalan/ERR_WRITE_ERROR:1.5	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_WRITE_ERROR	Tue Sep  3 10:39:23 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
-<TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
+<HTML><HEAD>
+TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT
diff -u squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4 squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4.6.1
--- squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT	Tue Sep  3 10:39:23 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL:
 <A HREF="%U">%U</A>
Index: squid/errors/Catalan/generic
diff -u squid/errors/Catalan/generic:1.2 squid/errors/Catalan/generic:1.2.10.1
--- squid/errors/Catalan/generic:1.2	Thu Jul 18 17:00:42 2002
+++ squid/errors/Catalan/generic	Tue Sep  3 10:39:24 2002
@@ -1,11 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff; font-family:verdana,sans-serif}--></STYLE>
 </HEAD><BODY>
 <H1>ERROR</H1>
 <H2>No es pot mostrar la URL que heu sol.licitat</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 Mentre s'intentava llegir la URL::
 <A HREF="%U">%U</A>
Index: squid/errors/Czech/ERR_CONFLICT
diff -u /dev/null squid/errors/Czech/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/Czech/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Danish/ERR_CONFLICT
diff -u /dev/null squid/errors/Danish/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/Danish/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Dutch/ERR_CONFLICT
diff -u /dev/null squid/errors/Dutch/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/Dutch/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/English/ERR_CONFLICT
diff -u /dev/null squid/errors/English/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/English/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Estonian/ERR_CONFLICT
diff -u /dev/null squid/errors/Estonian/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/Estonian/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Finnish/ERR_CONFLICT
diff -u /dev/null squid/errors/Finnish/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/Finnish/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/French/ERR_CONFLICT
diff -u /dev/null squid/errors/French/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/French/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/German/ERR_CONFLICT
diff -u /dev/null squid/errors/German/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/German/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Hebrew/ERR_ACCESS_DENIED
diff -u squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3.6.1
--- squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_ACCESS_DENIED	Tue Sep  3 10:39:55 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED
diff -u squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3.6.1
--- squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED	Tue Sep  3 10:39:55 2002
@@ -1,14 +1,12 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: âéùä ìùøú ðãçéú</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD>
 <BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>âéùä ìùøú ðãçéú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED
diff -u squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3.6.1
--- squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED	Tue Sep  3 10:39:56 2002
@@ -1,14 +1,12 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: âéùú îðäì ìùøú ðãçéú</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD>
 <BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>âéùú îðäì ìùøú ðãçéú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_CANNOT_FORWARD
diff -u squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3 squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3.6.1
--- squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_CANNOT_FORWARD	Tue Sep  3 10:39:56 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_CONNECT_FAIL
diff -u squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3 squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3.6.1
--- squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_CONNECT_FAIL	Tue Sep  3 10:39:56 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_DNS_FAIL
diff -u squid/errors/Hebrew/ERR_DNS_FAIL:1.4 squid/errors/Hebrew/ERR_DNS_FAIL:1.4.6.1
--- squid/errors/Hebrew/ERR_DNS_FAIL:1.4	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_DNS_FAIL	Tue Sep  3 10:39:57 2002
@@ -1,12 +1,10 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_FORWARDING_DENIED
diff -u squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3 squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3.6.1
--- squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FORWARDING_DENIED	Tue Sep  3 10:39:57 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_FTP_DISABLED
diff -u squid/errors/Hebrew/ERR_FTP_DISABLED:1.3 squid/errors/Hebrew/ERR_FTP_DISABLED:1.3.6.1
--- squid/errors/Hebrew/ERR_FTP_DISABLED:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FTP_DISABLED	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_FTP_FAILURE
diff -u squid/errors/Hebrew/ERR_FTP_FAILURE:1.3 squid/errors/Hebrew/ERR_FTP_FAILURE:1.3.6.1
--- squid/errors/Hebrew/ERR_FTP_FAILURE:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FTP_FAILURE	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ÷øúä ùâéàú ôøåèå÷åì FTP
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
Index: squid/errors/Hebrew/ERR_FTP_FORBIDDEN
diff -u squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3 squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3.6.1
--- squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FTP_FORBIDDEN	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ùâéàä áæéäåé îùúîù FTP
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
Index: squid/errors/Hebrew/ERR_FTP_NOT_FOUND
diff -u squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3 squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3.6.1
--- squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FTP_NOT_FOUND	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ìà ðéúï ìâùú àì äëúåáú äð"ì:
 <A HREF="%U">%U</A>
Index: squid/errors/Hebrew/ERR_FTP_PUT_CREATED
diff -u squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3 squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3.6.1
--- squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FTP_PUT_CREATED	Tue Sep  3 10:39:59 2002
@@ -1,10 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ôòåìú FTP PUT òáøä áäöìçä: ä÷åáõ ðåöø</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ôòåìä òáøä áäöìçä</H1>
 <H2>ä÷åáõ ðåöø</H2>
-<HR noshade size="1px">
+<HR>
Index: squid/errors/Hebrew/ERR_FTP_PUT_ERROR
diff -u squid/errors/Hebrew/ERR_FTP_PUT_ERROR:1.3 squid/errors/Hebrew/ERR_FTP_PUT_ERROR:1.3.6.1
--- squid/errors/Hebrew/ERR_FTP_PUT_ERROR:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FTP_PUT_ERROR	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äòìàú ÷åáõ ì-FTP ðëùìä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>äòìàú ÷åáõ ì-FTP ðëùìä</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ùâéàä ëàùø ðéñéúé ìùìåç àú:
 <A HREF="%U">%U</A>
Index: squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED
diff -u squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3 squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3.6.1
--- squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED	Tue Sep  3 10:39:59 2002
@@ -1,10 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ôòåìú FTP PUT òáøä áäöìçä: ä÷åáõ òåãëï</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ôòåìä òáøä áäöìçä</H1>
 <H2>ä÷åáõ òåãëï</H2>
-<HR noshade size="1px">
+<HR>
Index: squid/errors/Hebrew/ERR_FTP_UNAVAILABLE
diff -u squid/errors/Hebrew/ERR_FTP_UNAVAILABLE:1.3 squid/errors/Hebrew/ERR_FTP_UNAVAILABLE:1.3.6.1
--- squid/errors/Hebrew/ERR_FTP_UNAVAILABLE:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_FTP_UNAVAILABLE	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ùøú ä-FTP äéä òñå÷ îãé, ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_INVALID_REQ
diff -u squid/errors/Hebrew/ERR_INVALID_REQ:1.3 squid/errors/Hebrew/ERR_INVALID_REQ:1.3.6.1
--- squid/errors/Hebrew/ERR_INVALID_REQ:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_INVALID_REQ	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìòáã àú äá÷ùä:
 <PRE>
Index: squid/errors/Hebrew/ERR_INVALID_URL
diff -u squid/errors/Hebrew/ERR_INVALID_URL:1.3 squid/errors/Hebrew/ERR_INVALID_URL:1.3.6.1
--- squid/errors/Hebrew/ERR_INVALID_URL:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_INVALID_URL	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_LIFETIME_EXP
diff -u squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3 squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3.6.1
--- squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_LIFETIME_EXP	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_NO_RELAY
diff -u squid/errors/Hebrew/ERR_NO_RELAY:1.3 squid/errors/Hebrew/ERR_NO_RELAY:1.3.6.1
--- squid/errors/Hebrew/ERR_NO_RELAY:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_NO_RELAY	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS
diff -u squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3 squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3.6.1
--- squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_READ_ERROR
diff -u squid/errors/Hebrew/ERR_READ_ERROR:1.3 squid/errors/Hebrew/ERR_READ_ERROR:1.3.6.1
--- squid/errors/Hebrew/ERR_READ_ERROR:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_READ_ERROR	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_READ_TIMEOUT
diff -u squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3 squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3.6.1
--- squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_READ_TIMEOUT	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_SHUTTING_DOWN
diff -u squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3 squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3.6.1
--- squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_SHUTTING_DOWN	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_SOCKET_FAILURE
diff -u squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3 squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3.6.1
--- squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_SOCKET_FAILURE	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_TOO_BIG
diff -u squid/errors/Hebrew/ERR_TOO_BIG:1.3 squid/errors/Hebrew/ERR_TOO_BIG:1.3.6.1
--- squid/errors/Hebrew/ERR_TOO_BIG:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_TOO_BIG	Tue Sep  3 10:40:00 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_UNSUP_REQ
diff -u squid/errors/Hebrew/ERR_UNSUP_REQ:1.3 squid/errors/Hebrew/ERR_UNSUP_REQ:1.3.6.1
--- squid/errors/Hebrew/ERR_UNSUP_REQ:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_UNSUP_REQ	Tue Sep  3 10:40:00 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_URN_RESOLVE
diff -u squid/errors/Hebrew/ERR_URN_RESOLVE:1.3 squid/errors/Hebrew/ERR_URN_RESOLVE:1.3.6.1
--- squid/errors/Hebrew/ERR_URN_RESOLVE:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_URN_RESOLVE	Tue Sep  3 10:40:00 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ERROR: The requested URN not be retrieved</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>A URL for the requested URN could not be retrieved</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 While trying to retrieve the URN:
 <A HREF="%U">%U</A>
Index: squid/errors/Hebrew/ERR_WRITE_ERROR
diff -u squid/errors/Hebrew/ERR_WRITE_ERROR:1.3 squid/errors/Hebrew/ERR_WRITE_ERROR:1.3.6.1
--- squid/errors/Hebrew/ERR_WRITE_ERROR:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_WRITE_ERROR	Tue Sep  3 10:40:00 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT
diff -u squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3 squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3.6.1
--- squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT	Tue Sep  3 10:40:00 2002
@@ -1,13 +1,11 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <HTML><HEAD>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1255">
 <TITLE>ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä</TITLE>
-<STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE>
 </HEAD><BODY>
 <div dir="rtl" align="right">
 <H1>ùâéàä</H1>
 <H2>ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú</H2>
-<HR noshade size="1px">
+<HR>
 <P>
 ëàùø ðéñéúé ìâùú àì äëúåáú: <A HREF="%U">%U</A>
 <P>
Index: squid/errors/Hungarian/ERR_CONFLICT
diff -u /dev/null squid/errors/Hungarian/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/Hungarian/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Italian/ERR_CONFLICT
diff -u /dev/null squid/errors/Italian/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:35 2004
+++ squid/errors/Italian/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Japanese/ERR_CONFLICT
diff -u /dev/null squid/errors/Japanese/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Japanese/ERR_CONFLICT	Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Korean/ERR_CONFLICT
diff -u /dev/null squid/errors/Korean/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Korean/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Polish/ERR_CONFLICT
diff -u /dev/null squid/errors/Polish/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Polish/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Portuguese/ERR_CONFLICT
diff -u /dev/null squid/errors/Portuguese/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Portuguese/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Romanian/ERR_CONFLICT
diff -u /dev/null squid/errors/Romanian/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Romanian/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Russian-1251/ERR_CONFLICT
diff -u /dev/null squid/errors/Russian-1251/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Russian-1251/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Russian-koi8-r/ERR_CONFLICT
diff -u /dev/null squid/errors/Russian-koi8-r/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Russian-koi8-r/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Serbian/ERR_CONFLICT
diff -u /dev/null squid/errors/Serbian/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Serbian/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Simplify_Chinese/ERR_CONFLICT
diff -u /dev/null squid/errors/Simplify_Chinese/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Simplify_Chinese/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Slovak/ERR_CONFLICT
diff -u /dev/null squid/errors/Slovak/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Slovak/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Spanish/ERR_CONFLICT
diff -u /dev/null squid/errors/Spanish/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Spanish/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Swedish/ERR_CONFLICT
diff -u /dev/null squid/errors/Swedish/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Swedish/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Traditional_Chinese/ERR_CONFLICT
diff -u /dev/null squid/errors/Traditional_Chinese/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Traditional_Chinese/ERR_CONFLICT	Sat Dec 22 08:31:35 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/errors/Turkish/ERR_CONFLICT
diff -u /dev/null squid/errors/Turkish/ERR_CONFLICT:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:36 2004
+++ squid/errors/Turkish/ERR_CONFLICT	Sat Dec 22 08:31:36 2001
@@ -0,0 +1,30 @@
+<HTML><HEAD>
+<TITLE>ERROR: The requested URL could not be retrieved</TITLE>
+</HEAD><BODY>
+<H1>ERROR</H1>
+<H2>The requested URL could not be retrieved</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+You made a PUT request with a version that conflicts with 
+the version already present in the cache.
+</STRONG>
+</UL>
+
+<P>
+This means that:
+<PRE>
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+</PRE>
+</P>
+
Index: squid/lib/MemPool.c
diff -u squid/lib/MemPool.c:1.7 squid/lib/MemPool.c:1.1.46.1
--- squid/lib/MemPool.c:1.7	Fri Aug  9 14:46:00 2002
+++ squid/lib/MemPool.c	Tue Sep  3 10:41:24 2002
@@ -80,13 +80,12 @@
  *   Andres Kroonmaa.
  */
 
-#include "config.h"
-
 #define FLUSH_LIMIT 1000	/* Flush memPool counters to memMeters after flush limit calls */
 #define MEM_MAX_MMAP_CHUNKS 2048
 
 #include <assert.h>
 
+#include "config.h"
 #if HAVE_STRING_H
 #include <string.h>
 #endif
Index: squid/src/HintCache.c
diff -u /dev/null squid/src/HintCache.c:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:38 2004
+++ squid/src/HintCache.c	Mon May 20 19:46:41 2002
@@ -0,0 +1,460 @@
+/*
+ * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * AUTHOR: Mike Dahlin, UT Austin, 1998
+ * DEBUG: section 84    Hint cache to Squid interface.
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ *------------------------------------------------------------------
+ * LESS Group 
+ * Computer Sciences Department 
+ * University of Texas at Austin
+ *
+ * HintCache.c --- High-level interface to hint cache.
+ *------------------------------------------------------------------
+ */
+
+#include "squid.h"
+
+static EVH hintCacheTimer;	/* timeout to flush StoreEntries */
+
+#define HINT_CACHE_DEBUG 84
+
+/*
+ * Globals
+ */
+#if USE_DYNAMIC_HIERARCHY
+HintCacheNet *parentOutgoingA = NULL;
+HintCacheNet *childrenOutgoingA = NULL;
+HintCacheNet *neighborsOutgoing = NULL;
+#endif
+HintCacheDisk *hcDisk = NULL;
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheInit --
+ *
+ *          description.
+ *
+ * Results:
+ *      Return nonzero on error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+int
+hintCacheInit()
+{
+    peer *e;
+#if USE_DYNAMIC_HIERARCHY
+    int ii;
+#endif
+
+    hcDisk = (HintCacheDisk *) xmalloc(sizeof(HintCacheDisk));
+    assert(hcDisk);
+    hintCacheDiskInit(hcDisk, Config.Hints.cache_file);
+
+#if USE_DYNAMIC_HIERARCHY
+    /*
+     * Three sets of network buffers. Children and parents
+     * are the children and parents as determined by the
+     * dynamic hierarchy algorithm (HCHier.h). Neighbors
+     * are static squid neighbors (neighbors.h). The
+     * static neighbors are used to bootstrap the
+     * dynamic algorithm.
+     */
+    neighborsOutgoing = (HintCacheNet *) xmalloc(sizeof(HintCacheNet));
+    assert(neighborsOutgoing);
+    hintCacheNetInit(neighborsOutgoing);
+    hintCacheHierInit();
+
+    childrenOutgoingA =
+	(HintCacheNet *) xmalloc(sizeof(HintCacheNet) *
+	hintCacheHier_NChildrenQs());
+    assert(childrenOutgoingA);
+    for (ii = 0; ii < hintCacheHierNChildrenQs(); ii++) {
+	hintCacheNet_Init(&childrenOutgoingA[ii]);
+    }
+    parentOutgoingA =
+	(HintCacheNet *) xmalloc(sizeof(HintCacheNet) *
+	hintCacheHier_NParentQs());
+    assert(parentOutgoingA);
+    for (ii = 0; ii < hintCacheHierNParentQs(); ii++) {
+	hintCacheNetInit(&parentOutgoingA[ii]);
+    }
+#else
+    for (e = getFirstPeer(); e; e = getNextPeer(e))
+	hintCacheNetInit(&e->hcoutq);
+#endif
+
+    /* Start hint timer */
+    eventAdd("hint timer", hintCacheTimer, NULL,
+	(double) (squid_random() % Config.Hints.intvl), 1);
+
+    return 0;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheDestroy --
+ *
+ *          Shut down.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+void
+hintCacheDestroy()
+{
+#if USE_DYNAMIC_HIERARCHY
+    int ii;
+
+    for (ii = 0; ii < hintCacheHier_NChildrenQs(); ii++) {
+	hintCacheNetDestroy(&childrenOutgoingA[ii]);
+    }
+    xfree(childrenOutgoingA);
+    childrenOutgoingA = NULL;
+    for (ii = 0; ii < hintCacheHier_NParentQs(); ii++) {
+	hintCacheNetDestroy(&parentOutgoingA[ii]);
+    }
+    xfree(parentOutgoingA);
+    parentOutgoingA = NULL;
+    hintCacheNetDestroy(neighborsOutgoing);
+    xfree(neighborsOutgoing);
+    neighborsOutgoing = NULL;
+#endif
+
+    hintCacheHierDestroy();
+
+    hintCacheDiskClose(hcDisk);
+    xfree(hcDisk);
+    hcDisk = NULL;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheCreate --
+ *
+ *          Create a NEW disk cache (obliterating the one
+ *          already on disk, if any). Then do normal initialization.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+void
+hintCacheCreate(void)
+{
+    if (access(Config.Hints.cache_file, R_OK | W_OK) == -1)
+	hintCacheDiskCreateFile(Config.Hints.cache_file, Config.Hints.size,
+	    Config.Hints.assoc);
+
+    hintCacheInit();
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheinformLocalCopy --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+void
+hintCacheInformLocalCopy(StoreEntry * entry)
+{
+    char *url = entry->mem_obj->url;
+    struct sockaddr_in *me;
+    HintCacheEntry myentry;
+    URLKey *key;
+    HintCacheUpdate update;
+
+    debug(HINT_CACHE_DEBUG, 5) ("hintCacheinformLocalCopy: got %s\n",
+				url);
+
+    if (!HINT_CACHE_ACTIVE()) {
+	/* Hint cache is inoperative.  Nothing to do. */
+	return;
+    }
+
+    if (strstr(url, "//updates"))
+	/* Routes handle their own updates */
+	return;
+
+    me = &Config.Sockaddr.http->s;
+
+    /* Prepare data structures */
+    key = HINT_CACHE_KEY(entry);
+    hintCacheEntryInit(&myentry, *key, me, entry->lastmod);
+    hintCacheUpdateInit(&update, HC_InformToParent, &myentry, 0);
+
+    /*
+     * Update local and remote hint caches.
+     */
+    hintCachePropHandleInformToParent(&update, me, 1);
+    update.action = HC_InformToChild;
+    hintCachePropHandleInformToChild(&update, me, 1);
+}
+
+void
+hintCacheInvalLocalCopy(StoreEntry * entry)
+{
+    struct sockaddr_in *me;
+    HintCacheEntry myentry;
+    HintCacheUpdate update;
+
+    if (!HINT_CACHE_ACTIVE()) {
+	/* Hint cache is inoperative.  Nothing to do. */
+	return;
+    }
+
+    me = &Config.Sockaddr.http->s;
+
+    /* Prepare data structures */
+    hintCacheEntryInit(&myentry, *HINT_CACHE_KEY(entry),
+		       me, entry->lastmod);
+    hintCacheUpdateInit(&update, HC_InvalToParent, &myentry, 0);
+
+    /*
+     * Update local and remote hint caches.
+     */
+    hintCacheHandleInvalToParent(&update, me, 1);
+    update.action = HC_InvalToChild;
+    hintCachePropHandleInvalToChild(&update, me, 1);
+
+    debug(HINT_CACHE_DEBUG, 5) ("hintCacheinvalLocalCopy: lost 0x%qx\n",
+				((URLKey *) &entry->hchash.key)->key);
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCachefindNearest --
+ *
+ *          Find the nearest copy of the specified URL.
+ *          Return a copy of the location in *saddr.
+ *          Return the saddr pointer if we found a copy
+ *          or return NULL if no copy found.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------3.24.1998-----------
+ */
+struct sockaddr_in *
+hintCacheFindNearest(StoreEntry *entry, struct sockaddr_in *saddr)
+{
+    const struct sockaddr_in *me;
+    URLKey *urlKey;
+    HintCacheEntry nearest;
+    int found;
+
+    if (!HINT_CACHE_ACTIVE()) {
+	/* Hint cache is inoperative.  Nothing to do. */
+	return (NULL);
+    }
+
+    urlKey = HINT_CACHE_KEY(entry);
+    found = hintCacheDiskFindNearest(hcDisk, *urlKey, &nearest);
+    if (!found)
+	return NULL;
+
+    saddr->sin_family = AF_INET;
+    saddr->sin_port = nearest.port;
+    saddr->sin_addr = nearest.ipaddr;
+
+    /* Never return ourselves. */
+    me = &Config.Sockaddr.http->s;
+    if (saddr->sin_port == me->sin_port) {
+	if (saddr->sin_addr.s_addr == me->sin_addr.s_addr)
+	    return NULL;
+	if (saddr->sin_addr.s_addr == 0x7f000000)
+	    return NULL;
+    }
+#if 0				/* Fixed? */
+    /* XXX - shouldn't be needed, but is - noted in BUGS */
+    /* Swap bytes to host format. */
+    saddr->sin_addr.s_addr = ntohl(saddr->sin_addr.s_addr);
+    saddr->sin_port = ntohs(saddr->sin_port);
+#endif
+    debug(HINT_CACHE_DEBUG, 5) ("hintCachefindNearest: %s is at <%s,%d>\n",
+	entry->mem_obj->url, inet_ntoa(saddr->sin_addr), saddr->sin_port);
+    return (saddr);
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheTimer --
+ *
+ *          This gets called every so often. Its job is
+ *          to flush outgoing messages.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+static void
+hintCacheTimer(void *junk)
+{
+    struct sockaddr_in sin;
+#if USE_DYNAMIC_HIERARCHY
+    struct sockaddr_in *childSinA = NULL;
+    static int nextjoin = 0;
+    int nchildren, ichild;
+    int error;
+    int ii;
+#else
+    peer *e;
+#endif
+
+    /* Reload timer */
+    eventAdd("hint timer", hintCacheTimer, NULL,
+	(double) (squid_random() % Config.Hints.intvl), 1);
+
+#if USE_DYNAMIC_HIERARCHY
+    /* Process peers */
+    /* Send enqueued updates */
+    if (parentOutgoingA != NULL) {
+	for (ii = 0; ii < hintCacheHier_NParentQs(); ii++) {
+	    if (hintCacheNetBytesReady(&parentOutgoingA[ii]) >
+		sizeof(HintCacheNetHeader)) {
+		hintCacheNetComplete(&parentOutgoingA[ii]);
+		error = hintCacheHierGetParentAddr(ii, &sin);
+		debug(HINT_CACHE_DEBUG, 6)
+		    ("Sending %d bytes from parentOutgoing[%d] to %s %s\n",
+		    hintCacheNetbytesReady(&parentOutgoingA[ii]), ii,
+		    inet_ntoa(sin.sin_addr), error ? "ERROR" : "");
+		if (!error) {
+		    hintCacheNetSendTo(&parentOutgoingA[ii], &sin);
+		}
+		hintCacheNetDone(&parentOutgoingA[ii]);
+	    }
+	}
+    }
+    if (childrenOutgoingA != NULL) {
+	for (ii = 0; ii < hintCacheHierNChildrenQs(); ii++) {
+	    if (hintCacheNet_bytesReady(&childrenOutgoingA[ii]) >
+		sizeof(HintCacheNetHeader)) {
+		hintCacheNetComplete(&childrenOutgoingA[ii]);
+		nchildren = hintCacheHierGetChildAddrs(ii, &childSinA);
+		debug(HINT_CACHE_DEBUG, 6)
+		    ("Sending %d bytes to %d children from childrenOutgoing[%d]:",
+		    hintCacheNetBytesReady(&childrenOutgoingA[ii]), nchildren,
+		    ii);
+
+		for (ichild = 0; ichild < nchildren; ichild++) {
+		    debug(HINT_CACHE_DEBUG, 8) (" %s ",
+			inet_ntoa(childSinA[ichild].sin_addr));
+		    hintCacheNetSendTo(&childrenOutgoingA[ii],
+			&childSinA[ichild]);
+		}
+
+		hintCacheNetDone(&childrenOutgoingA[ii]);
+		xfree(childSinA);
+	    }
+	}
+    }
+#else
+    for (e = getFirstPeer(); e; e = getNextPeer(e)) {
+	if (hintCacheNetBytesReady(&e->hcoutq) > sizeof(HintCacheNetHeader)) {
+	    hintCacheNetComplete(&e->hcoutq);
+	    sin.sin_addr = e->in_addr.sin_addr;
+	    sin.sin_port = e->http_port;
+	    hintCacheNetSendTo(&e->hcoutq, &sin);
+	    hintCacheNetDone(&e->hcoutq);
+	}
+    }
+#endif /* USE_DYNAMIC_HIERARCHY */
+
+
+#if USE_DYNAMIC_HIERARCHY
+    /*
+     * Send out Joins once every few hours.
+     */
+    if (hintCacheNodelistMyStatus() == HC_Join) {
+	if (squid_curtime >= nextjoin) {
+	    hintCacheNodelistLocalJoin();
+	    nextjoin =
+		squid_curtime + (squid_random() % Config.Hints.join_intvl);
+	}
+    }
+#endif
+
+#ifdef DOTEST
+    if (0) {			/* XXX */
+	if (!hintCacheHierSelfTestDone) {
+	    hintCacheHierTestNetwork();
+	}
+    }
+#endif
+}
Index: squid/src/HintCacheDisk.c
diff -u /dev/null squid/src/HintCacheDisk.c:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:38 2004
+++ squid/src/HintCacheDisk.c	Mon May 20 19:46:41 2002
@@ -0,0 +1,817 @@
+/*
+ * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * AUTHOR: Mike Dahlin, UT Austin, 1998
+ * DEBUG: section 82    On-disk hint cache
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ *------------------------------------------------------------------
+ *
+ * LESS Group 
+ * Computer Sciences Department 
+ * University of Texas at Austin
+ *
+ * HintCacheDisk ---
+ *          The on-disk cache of hints. The key data structure
+ *          is an mmapped array which is treated as a <entriesPerBucket>-
+ *          associative cache.
+ *
+ *------------------------------------------------------------------
+ */
+#include "squid.h"
+
+#define HCDISK_DEBUG 82
+
+#define BIG_ENOUGH 1024
+
+static const char *suffix = ".hints";
+
+static int readLine(int fd, char *buffer, int max);
+static void initializeFile(int dataFD, int nbuckets, int associativity);
+static int findKey(HintCacheDisk * d, int b, URLKey key,
+    HintCacheDiskEntry * foundRet);
+static int deleteKey(HintCacheDisk * d, int b, HintCacheDiskEntry * oldEntry,
+    HintCacheDiskEntry * survivingEntry);
+static void insertKey(HintCacheDisk * d, int b, HintCacheDiskEntry * newEntry);
+#ifdef MADV_RANDOM
+static caddr_t pageAddr(caddr_t e);
+#endif
+static void sanityCheckMatch(HintCacheDisk * d, HintCacheDiskEntry * bucketp,
+    HintCacheDiskEntry * entry, int expectFullMatch, int expectKeyMatch);
+static int bucket(HintCacheDisk * d, URLKey key);
+static HintCacheDiskEntry *readBucket(HintCacheDisk * d, int b);
+static int writeBucket(HintCacheDisk * d, int b, HintCacheDiskEntry * bucketp);
+#ifdef DOTEST
+static void timeMadvise();
+#endif
+
+static long pageSize;
+
+/*
+ * Should we try to keep stuff we just read or wrote in the cache.
+ */
+/*
+ * You may not want to cache writes since they may or may not
+ * be about stuff you will later read. On the other hand, there
+ * may be temporal locality about stuff that gets updated --
+ * I may be likely to read or discard the object in the near
+ * future. Also, telling system to kick it out of cache costs
+ * about 1ms per call.
+ */
+static const int CACHE_RECENT_WRITES = 1;
+/*
+ * You may not want to cache reads since these are things
+ * that you will now have in your cache (so why would
+ * you look at the hints any time soon. On the other hand,
+ * telling system to kick out reads costs about 1ms per call
+ */
+static const int CACHE_RECENT_READS = 0;
+/* 
+ * You may not want to prefetch at all (we can only prefetch
+ * on network updates, and those are not on critical
+ * path anywhere. Maybe better to sacrifice latency for
+ * reduced overhead.
+ * 
+ * No point int trying to pipeline if there are not many
+ * updates to pipeline. Otherwise the overhead of the
+ * system calls outweighs the reduced latency for disk
+ * reads. In the best case, madvise (tight loop of madvise
+ * about same location), madvise appears to take about 1ms per call.
+ */
+static const int DO_PREFETCH = 0;
+
+/*  HintCacheDisk constructor */
+void
+hintCacheDiskInit(HintCacheDisk * d, char *diskPath)
+{
+    int header;
+    int dataF;
+    char buffer[BIG_ENOUGH], token[BIG_ENOUGH], dataFile[BIG_ENOUGH];
+    int version;
+    int size, buckets, associativity;
+    int gotVersion = 0, gotData = 0, gotAssoc = 0, gotSize = 0, gotBuckets = 0;
+
+    if ((pageSize = sysconf(_SC_PAGESIZE)) < 0) {
+	perror("Cannot determine page size\n");
+	exit(-1);
+    }
+
+    header = open(diskPath, O_RDONLY);
+    if (header < 0) {
+	debug(HCDISK_DEBUG, 1)
+	    ("warning: Can\'t open %s, hint caching disabled\n", diskPath);
+	HCDisk = NULL;
+	return;
+    }
+
+    while (readLine(header, buffer, BIG_ENOUGH)) {
+	if (buffer[0] != '#') {
+	    sscanf(buffer, "%s", token);
+	    if (!strcmp(token, "VERSION")) {
+		gotVersion = sscanf(buffer, "VERSION %d\n", &version);
+		assert(gotVersion == 1);
+		assert(version == HCD_VERSION);
+	    } else if (!strcmp(token, "DATA_FILE")) {
+		gotData = sscanf(buffer, "DATA_FILE %s\n", dataFile);
+		assert(gotData == 1);
+	    } else if (!strcmp(token, "SIZE_BYTES")) {
+		gotSize = sscanf(buffer, "SIZE_BYTES %d\n", &size);
+		assert(gotSize == 1);
+	    } else if (!strcmp(token, "BUCKETS")) {
+		gotBuckets = sscanf(buffer, "BUCKETS %d\n", &buckets);
+		assert(gotBuckets == 1);
+	    } else if (!strcmp(token, "ASSOCIATIVITY")) {
+		gotAssoc = sscanf(buffer, "ASSOCIATIVITY %d\n", &associativity);
+		assert(gotAssoc == 1);
+	    } else {
+		/* Ignore what we don't understand */
+	    }
+	}
+    }
+    close(header);
+    assert(gotVersion && gotData && gotAssoc && gotSize && gotBuckets);
+    assert(size == buckets * associativity * sizeof(HintCacheDiskEntry));
+    d->nbuckets = buckets;
+    d->entriesPerBucket = associativity;
+    dataF = open(dataFile, O_RDWR);
+    if (dataF < 0) {
+	debug(HCDISK_DEBUG, 1)
+	    ("warning: Can\'t open %s, hint caching disabled\n", dataFile);
+	HCDisk = NULL;
+	return;
+    }
+    if (Config.onoff.hint_cache_use_mmap) {
+	d->mmappedArray =
+	    (HintCacheDiskEntry *) mmap(0, size, PROT_READ | PROT_WRITE,
+	    MAP_SHARED, dataF, 0);
+	if (!d->mmappedArray) {
+	    debug(HCDISK_DEBUG, 1)
+		("warning: Can\'t mmap %s, hint caching disabled\n", dataFile);
+	    HCDisk = NULL;
+	    return;
+	}
+#ifdef MADV_RANDOM
+	if (madvise((char *) d->mmappedArray, size, MADV_RANDOM)) {
+	    debug(HCDISK_DEBUG, 1)
+		("warning: madvise on hint cache data failed");
+	}
+#endif
+	close(dataF);
+	d->fd = -1;
+    } else {
+	d->fd = dataF;
+    }
+}
+
+/*
+ *          Read one line of input from file. We really want
+ *          to use fgets(), but the fopen() etc. routines
+ *          don't work if you have large numbers of
+ *          files open (60 or 255 are the max for some implementations).
+ *          So, we use the basic open/read/close routines
+ *          instead, which let us open up to the max number
+ *          of allowed file descriptors.
+ *
+ *          Store a line of text ending with \n\0 in buffer
+ *          and return nonzero if we succeeded in getting
+ *          a well-formed line.
+ */
+static int
+readLine(int fd, char *buffer, int max)
+{
+    ssize_t got;
+    int count = 0;
+
+    assert(buffer);
+    assert(fd >= 0);
+    assert(fd <= 10000);
+    assert(max > 2);		/* need room for \n\0 */
+
+    while (count < max - 2) {
+	got = read(fd, &buffer[count], 1);
+	if (got != 1) {
+	    return 0;
+	}
+	if (buffer[count] == '\n') {
+	    buffer[count + 1] = '\0';
+	    return 1;
+	}
+	count++;
+    }
+    return 0;
+}
+
+/*
+ *          Does the hard work of setting up a new empty file.
+ *
+ *          Note: we use raw open() and write() rather than
+ *          fopen() and fwrite() because the f-routines
+ *          get unhappy in programs that open lots of files
+ *          (they often die if you have more than 60 or 255
+ *          files open, even if you are allowed to 
+ *          have more open file descriptors than that).
+ */
+void
+hintCacheDiskCreateFile(char *hcPath, int size, int associativity)
+{
+    char *dataPath;
+    int buckets;
+    int headerF, dataF;
+    char buffer[BIG_ENOUGH];
+    int len;
+
+    len = strlen(hcPath);
+    dataPath = (char *) xmalloc(len + strlen(suffix) + 1);
+    assert(dataPath);
+    snprintf(dataPath, len, "%s%s", hcPath, suffix);
+
+    buckets = (size / associativity) / sizeof(HintCacheDiskEntry);
+    assert(buckets * associativity * sizeof(HintCacheDiskEntry) <= size);
+    size = buckets * associativity * sizeof(HintCacheDiskEntry);
+
+    headerF = open(hcPath, O_WRONLY | O_CREAT | O_TRUNC, 0744);
+    if (headerF < 0) {
+	perror("Opening Hint Cache header");
+	exit(-1);
+    }
+
+    snprintf(buffer, BIG_ENOUGH,
+	"# *** Header for hint cache. Do not modify ***\n");
+    write(headerF, buffer, strlen(buffer));
+    snprintf(buffer, BIG_ENOUGH, "VERSION %d\n", HCD_VERSION);
+    write(headerF, buffer, strlen(buffer));
+    snprintf(buffer, BIG_ENOUGH, "DATA_FILE %s\n", dataPath);
+    write(headerF, buffer, strlen(buffer));
+    snprintf(buffer, BIG_ENOUGH, "SIZE_BYTES %d\n", size);
+    write(headerF, buffer, strlen(buffer));
+    snprintf(buffer, BIG_ENOUGH, "BUCKETS %d\n", buckets);
+    write(headerF, buffer, strlen(buffer));
+    snprintf(buffer, BIG_ENOUGH, "ASSOCIATIVITY %d\n", associativity);
+    write(headerF, buffer, strlen(buffer));
+
+    close(headerF);
+
+    /* Open data file */
+    dataF = open(dataPath, O_WRONLY | O_CREAT | O_TRUNC, 0744);
+    if (dataF < 0) {
+	perror("Opening Hint Cache data");
+	exit(-1);
+    }
+
+    /* Need to pre-extend file to 'size' */
+    lseek(dataF, size - 1, 0);
+    write(dataF, "\0", 1);
+    lseek(dataF, 0, 0);
+
+    initializeFile(dataF, buckets, associativity);
+    close(dataF);
+    xfree(dataPath);
+}
+
+/* Set a file to empty by invalidating all entries.  */
+static void
+initializeFile(int fd, int nbuckets, int associativity)
+{
+    HintCacheDiskEntry invalidEntry;
+    int ibucket, ientry;
+    int count;
+
+    HCE_INVALIDATE(&invalidEntry.entry);
+
+    for (ibucket = 0; ibucket < nbuckets; ibucket++) {
+	for (ientry = 0; ientry < associativity; ientry++) {
+	    count = write(fd, &invalidEntry, sizeof(HintCacheDiskEntry));
+	    if (count != sizeof(HintCacheDiskEntry)) {
+		perror("ERROR Creating HintCacheCache file");
+		exit(-1);
+	    }
+	}
+    }
+}
+
+/*  Unmap the file. */
+void
+hintCacheDiskClose(HintCacheDisk * d)
+{
+    munmap((char *) d->mmappedArray, d->nbuckets * d->entriesPerBucket);
+    d->mmappedArray = NULL;
+}
+
+/* Update data structures to reflect the fact a copy is cached locally. */
+void
+hintCacheDiskInformLocal(HintCacheDisk * d, URLKey key, unsigned mtime)
+{
+    int b;
+    HintCacheDiskEntry new, dummyRet, old;
+    int foundOld;
+
+    assert(d);
+
+    if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) {
+	return;
+    }
+
+    b = bucket(d, key);
+    foundOld = findKey(d, b, key, &old);
+    if (foundOld) {
+	/* Delete old instead of replace to support multiversioning */
+	deleteKey(d, b, &old, &dummyRet);
+    }
+    hintCacheEntryInit(&new.entry, key, &Config.Sockaddr.http->s, mtime);
+    new.rtime = squid_curtime;
+    insertKey(d, b, &new);
+#ifdef MADV_RANDOM
+    if (!CACHE_RECENT_WRITES) {
+	if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)),
+		pageSize, MADV_DONTNEED)) {
+	    debug(HCDISK_DEBUG, 1) ("madvise DONTNEED failed\n");
+	}
+    }
+#endif
+}
+
+
+
+/* Update local data structures to reflect the fact
+ * that we no longer have a copy locally.   */
+void
+hintCacheDiskInvalLocal(HintCacheDisk * d, URLKey key, unsigned mtime)
+{
+    HintCacheDiskEntry myent, dummyRet;
+    int b;
+
+    debug(HCDISK_DEBUG, 2) ("HintCacheDiskinvalLocalCopy: deleting %ll\n",
+	key.key);
+
+    if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) {
+	return;
+    }
+
+    hintCacheEntryInit(&myent.entry, key, &Config.Sockaddr.http->s, mtime);
+    myent.rtime = squid_curtime;
+    b = bucket(d, key);
+    deleteKey(d, b, &myent, &dummyRet);
+#ifdef MADV_RANDOM
+    if (Config.onoff.hint_cache_use_mmap) {
+	if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)),
+		pageSize, MADV_DONTNEED)) {
+	    debug(HCDISK_DEBUG, 1) ("Madvise DONTNEED failed\n");
+	}
+    }
+#endif
+}
+
+/* Warn vm system that certain pages will be needed.  These pages 
+ * hold or will hold object mentioned in this hint update. */
+void
+hintCacheDiskprefetch(HintCacheDisk * d, HintCacheUpdate * uArray, int nupdates)
+{
+#ifdef MADV_RANDOM
+    int b;
+    int ii;
+    if (DO_PREFETCH && Config.onoff.hint_cache_use_mmap) {
+	for (ii = 0; ii < nupdates; ii++) {
+	    if (uArray[ii].action == HC_InvalToParent ||
+		uArray[ii].action == HC_InvalToChild ||
+		uArray[ii].action == HC_InformToParent ||
+		uArray[ii].action == HC_InformToChild) {
+		b = bucket(d, uArray[ii].entry.key);
+		if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)),
+			pageSize, MADV_WILLNEED)) {
+		    debug(HCDISK_DEBUG, 1) ("madvise WILLNEED failed\n");
+		}
+	    }
+	}
+    }
+#endif
+}
+
+/*
+ *          The network told us that <key, invalNode> is
+ *          no longer a valid mapping. If we knew of a 
+ *          different copy than the one that was invalidated
+ *          then report that back by returning 1 and putting
+ *          a copy of the survivor in survivor.
+ *
+ *          The function takes HCEntrys as args rather than
+ *          HintCacheDiskEntrys because it is called exclusively
+ *          from outside HintCacheDisk.c.
+ */
+int
+hintCacheDisknetInvalRecord(HintCacheDisk * d,
+    HintCacheEntry * entry, HintCacheEntry * survivor)
+{
+    HintCacheDiskEntry dentry, dsurv;
+    int remainingCopy;
+    int b;
+
+    if (!HCE_VALID(entry)) {
+	survivor->key.key = 0;
+	return 0;
+    }
+
+    dentry.entry = *entry;
+    dentry.rtime = squid_curtime;
+
+    b = bucket(d, entry->key);
+    remainingCopy = deleteKey(d, b, &dentry, &dsurv);
+    *survivor = dsurv.entry;
+#ifdef MADV_RANDOM
+    if (Config.onoff.hint_cache_use_mmap)
+	if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)),
+		pageSize, MADV_DONTNEED)) {
+	    debug(HCDISK_DEBUG, 1) ("madvise DONTNEED failed\n");
+	}
+#endif
+
+    return remainingCopy;
+}
+
+/*
+ *          The network told us that <key, newnode> is a valid
+ *          mapping. Install it if it is better than the one
+ *          we have.
+ *
+ *          Takes HintCacheEntrys as args because it's exported.
+ */
+int
+hintCacheDiskUpdateIfCloser(HintCacheDisk * d, HintCacheEntry * new)
+{
+    HintCacheDiskEntry old, dummyRet, dnew, *todelete;
+    URLKey key = new->key;
+    int dochange = 0;
+    StoreEntry *e;
+    int ret = 0;
+    int foundOld;
+    int b;
+
+    if (!HCE_VALID(new)) {
+	return 0;
+    }
+
+    dnew.entry = *new;
+    dnew.rtime = squid_curtime;
+
+    b = bucket(d, key);
+    foundOld = findKey(d, b, key, &old);
+    if (!foundOld) {
+	insertKey(d, b, &dnew);
+	todelete = &dnew;
+	ret = 1;
+    } else
+	todelete = &old;
+
+    e = hintCacheStoreGet(key);
+    if (e && e->lastmod < new->mtime) {
+	/* This hint is about a new version. Invalidate the old version */
+	storeRelease(e);
+	dochange = 1;
+    } else if (foundOld && squid_curtime >= old.rtime + Config.Hints.holddown) {
+	/* Don't propagate hints about the same version more often
+	 * that once every fifteen minutes. */
+	dochange = 1;
+    } else if (hintCacheHierCompareDistance(new->ipaddr, old.entry.ipaddr) < 0) {
+	/* This hint is for cache closer than what we got */
+	dochange = 1;
+    }
+
+    if (dochange) {
+	deleteKey(d, b, todelete, &dummyRet);
+	insertKey(d, b, &dnew);
+	ret = 1;
+    }
+#ifdef MADV_RANDOM
+    if (!CACHE_RECENT_WRITES && Config.onoff.hint_cache_use_mmap) {
+	if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)),
+		pageSize, MADV_DONTNEED)) {
+	    perror("Madvise DONTNEED failed\n");
+	}
+    }
+#endif
+    return ret;
+}
+
+/*
+ *          Find the record for the key if one exists. Return 1
+ *          if matching record found and a copy in *match. 
+ *          Return 0 if no match found.
+ *
+ *          Note: we can't just return a pointer to match
+ *          because its location in the bucket can change
+ *          at any time.
+ *
+ *          Takes HintCacheEntry as arg because it is exported.
+ */
+int
+hintCacheDiskFindNearest(HintCacheDisk * d, URLKey key, HintCacheEntry * match)
+{
+    int b;
+    int found;
+    HintCacheDiskEntry dent;
+
+    assert(match != 0);
+    if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) {
+	return 0;
+    }
+
+    b = bucket(d, key);
+    found = findKey(d, b, key, &dent);
+    if (found)
+	*match = dent.entry;
+#ifdef MADV_RANDOM
+    if (!CACHE_RECENT_READS && Config.onoff.hint_cache_use_mmap) {
+	if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)),
+		pageSize, MADV_DONTNEED)) {
+	    perror("Madvise DONTNEED failed\n");
+	}
+    }
+#endif
+    return found;
+}
+
+
+/* Return pointer to first entry in bucket for key. */
+static int
+bucket(HintCacheDisk * d, URLKey key)
+{
+    int b;
+
+    b = key.key % d->nbuckets;
+    return b * d->entriesPerBucket;
+}
+
+#ifdef MADV_RANDOM
+/*
+ *          Return the address of the first byte of the
+ *          page that holds an address.
+ */
+static caddr_t
+pageAddr(caddr_t e)
+{
+    caddr_t ret;
+    ret = e - ((unsigned) e % pageSize);
+    return ret;
+}
+#endif /* MADV_RANDOM */
+
+/*
+ *          Delete the record associated with the specified <key, node>
+ *          pair.
+ *          
+ *          If there is a record for the key that survives the
+ *          delete (e.g. the node doesn't match) return it
+ *          in the HintCacheEntry *surviver field and return 1. If
+ *          no record for the key survives the delete, return 0.
+ *          
+ *          Note: we can't just return a pointer to survivor
+ *          because its location in the bucket can change
+ *          at any time.
+ */
+static int
+deleteKey(HintCacheDisk * d, int b, HintCacheDiskEntry * entry,
+    HintCacheDiskEntry * survivor)
+{
+    HintCacheDiskEntry *bucketp = d->mmappedArray + b;
+    int ii;
+
+    assert(survivor != NULL);
+    assert(entry != survivor);
+    assert(HintCacheE_VALID(&entry->entry));
+
+    bucketp = readBucket(d, b);
+    for (ii = 0; ii < d->entriesPerBucket; ii++) {
+	if (!URLKEY_COMPARE(bucketp[ii].entry.key, entry->entry.key)) {
+	    if (!HCEntry_Compare(&entry->entry, &bucketp[ii].entry)) {
+		HCE_INVALIDATE(&bucketp[ii].entry);
+		sanityCheckMatch(d, bucketp, entry, 0, 0);
+		break;
+	    } else {
+		/*
+		 * Matched key but not NodeId.
+		 */
+		*survivor = bucketp[ii];
+		sanityCheckMatch(d, bucketp, entry, 0, 1);
+		sanityCheckMatch(d, bucketp, survivor, 1, 1);
+		return 1;
+	    }
+	}
+    }
+    writeBucket(d, b, bucketp);
+    /*
+     * No match key
+     */
+    return 0;
+}
+
+
+/*
+ *          Insert an entry in a given bucket in hash table.
+ *          The table is n-way associative. The new entry
+ *          is always inserted into entry 0, and the remaining
+ *          entries are shifted up. If there is an empty
+ *          entry, we don't have to shift any higher entries.
+ *          If all entries are full, entry d->entriesPerBucket - 1 
+ *          (the last entry) is lost.
+ */
+static void
+insertKey(HintCacheDisk * d, int b, HintCacheDiskEntry * entry)
+{
+    HintCacheDiskEntry *bucketp;
+    int from, to;
+
+    /* Get bucket */
+    bucketp = readBucket(d, b);
+
+    /*
+     * Caller responsible for deleting old entry before inserting
+     * a new one.
+     */
+    sanityCheckMatch(d, bucketp, entry, 0, 0);
+
+    /*
+     * First, see if there are any empty entries. All entries
+     * below the first empty one get shifted up to make
+     * room in entry 0. The last entry by definition is
+     * emtpy if all earlier ones are empty (you are always
+     * allowed to shift over the last entry.)
+     */
+    for (to = 0; to < d->entriesPerBucket - 1; to++) {
+	if (!HCE_VALID(&bucketp[to].entry)) {
+	    break;
+	}
+    }
+    assert(to <= d->entriesPerBucket - 1);
+    assert(!HCE_VALID(&bucketp[to].entry) || (to == d->entriesPerBucket - 1));
+
+    /*
+     * Shift entry <from> up to entry <from+1> to make entry 0 empty.
+     * The last bucket we shift is entry (from==entriesPerBucket-2)
+     * which shifts into the last bucket (entriesPerBucket-1).
+     * Don't go any farther, or we clobber the next bucket.
+     */
+    for (; to > 0; to--) {
+	from = to - 1;
+	assert(from >= 0);
+	bucketp[to] = bucketp[from];
+    }
+    bucketp[0] = *entry;
+    sanityCheckMatch(d, bucketp, entry, 1, 1);
+    writeBucket(d, b, bucketp);
+}
+
+/*
+ *      Check to see that the expected number of entries in bucket
+ *      match specified key.
+ */
+static void
+sanityCheckMatch(HintCacheDisk * d, HintCacheDiskEntry * bucketp,
+    HintCacheDiskEntry * entry, int expectFullMatch, int expectKeyMatch)
+{
+    int ii;
+    int fullMatch = 0, keyMatch = 0;
+
+    for (ii = 0; ii < d->entriesPerBucket; ii++) {
+	if (!hintCacheEntryCompare(&bucketp[ii].entry, &entry->entry)) {
+	    fullMatch++;
+	}
+	if (!URLKEY_COMPARE(bucketp[ii].entry.key, entry->entry.key)) {
+	    keyMatch++;
+	}
+    }
+    assert(fullMatch == expectFullMatch);
+    assert(keyMatch == expectKeyMatch);
+}
+
+/*
+ *          Find an entry that matches the key. Return
+ *          true if found and put the result in foundRet.
+ *          Since this is a read, 
+ *          update the LRU list by removing key and
+ *          then re-inserting key.
+ *         
+ *          Note: we can't just return a pointer to copy
+ *          because its location in the bucket can change
+ *          at any time.
+ */
+static int
+findKey(HintCacheDisk * d, int b, URLKey key, HintCacheDiskEntry * copy)
+{
+    HintCacheDiskEntry *bucketp;
+    int ii;
+
+    bucketp = readBucket(d, b);
+    assert(copy != NULL);
+    assert(copy < bucketp || copy > &bucketp[d->entriesPerBucket - 1]);
+    assert(URLKEY_COMPARE(key, INVALID_URL_KEY));
+    for (ii = 0; ii < d->entriesPerBucket; ii++) {
+	if (!URLKEY_COMPARE(bucketp[ii].entry.key, key)) {
+	    *copy = bucketp[ii];
+	    assert(!URLKEY_COMPARE(copy->entry.key, key));
+	    if (ii != 0) {
+		/*
+		 * Move to front of LRU list by deleting entry and inserting
+		 */
+		HCE_INVALIDATE(&bucketp[ii].entry);
+		writeBucket(d, b, &bucketp[ii]);
+		insertKey(d, b, copy);
+	    }
+	    return 1;
+	}
+    }
+    HCE_INVALIDATE(&copy->entry);
+    return 0;
+}
+
+static HintCacheDiskEntry *
+readBucket(HintCacheDisk * d, int b)
+{
+    static HintCacheDiskEntry *bucketp = 0;
+    int bucketlen;
+
+    /* If using mmap, just return the pointer */
+    if (Config.onoff.hint_cache_use_mmap)
+	return (d->mmappedArray + b);
+
+    /* Get a static buffer to put stuff in */
+    bucketlen = sizeof(HintCacheDiskEntry) * d->entriesPerBucket;
+    if (bucketp == 0) {
+	bucketp = (HintCacheDiskEntry *) xmalloc(bucketlen);
+    }
+
+    /* Fetch hint from disk by Unix I/O */
+    if (lseek(d->fd, b * sizeof(HintCacheDiskEntry), 0) == -1) {
+	debug(HCDISK_DEBUG, 1) ("warning: can't seek to hint at offset %d\n",
+	    b * sizeof(HintCacheDiskEntry));
+	return 0;
+    }
+    if (read(d->fd, bucketp, bucketlen) == -1) {
+	debug(HCDISK_DEBUG, 1)
+	    ("warning: can't read hint at offset %d\n",
+	    b * sizeof(HintCacheDiskEntry));
+	return 0;
+    }
+
+    return bucketp;
+}
+
+
+static int
+writeBucket(HintCacheDisk * d, int b, HintCacheDiskEntry * bucketp)
+{
+    /* If using mmap, no action is necessary - model is that
+     * you modify stuff via direct pointer you got from read */
+    if (Config.onoff.hint_cache_use_mmap)
+	return 0;
+
+    /* Write bucket to disk by Unix I/O */
+    if (lseek(d->fd, b * sizeof(HintCacheDiskEntry), 0) == -1) {
+	debug(HCDISK_DEBUG, 1) ("warning: can't seek to hint at offset %d\n",
+	    b * sizeof(HintCacheDiskEntry));
+	return -1;
+    }
+    if (write(d->fd, bucketp,
+	    sizeof(HintCacheDiskEntry) * d->entriesPerBucket) == -1) {
+	debug(HCDISK_DEBUG, 1) ("warning: can't write hint at offset %d\n",
+	    b * sizeof(HintCacheDiskEntry));
+	return -1;
+    }
+
+    return 0;
+}
+
+void
+hcdiskDeleteHintCache()
+{
+    char hcname[256];
+
+    if (!Config.Hints.cache_file[0])
+	return;
+
+    unlink(Config.Hints.cache_file);
+    strcpy(hcname, Config.Hints.cache_file);
+    strcat(hcname, ".theCache");
+    unlink(hcname);
+}
Index: squid/src/HintCacheEndian.c
diff -u /dev/null squid/src/HintCacheEndian.c:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:38 2004
+++ squid/src/HintCacheEndian.c	Mon May 20 19:46:41 2002
@@ -0,0 +1,97 @@
+/*
+ * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * DEBUG: section 85    Hint Cache Endianness conversion routines
+ * AUTHOR: Mike Dahlin, UT Austin, 1998
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ *------------------------------------------------------------------
+ * LESS Group 
+ * Computer Sciences Department 
+ * University of Texas at Austin
+ *
+ * HCEndian.c ---
+ *          
+ * HCEndian has the really low-level stuff for transmorifying
+ * basic types -- long, long long. It is up to each class
+ * that wants to be able to go across the wire to call
+ * these primitives on its own fields. 
+ *------------------------------------------------------------------
+ */
+
+#include "squid.h"
+#include <assert.h>
+
+long long unsigned
+HCEndian_llNetToMachine(long long unsigned net)
+{
+    long unsigned *netLong = (long unsigned *) &net;
+    long long unsigned machine;
+    long unsigned *machineLong = (long unsigned *) &machine;
+
+    machineLong[0] = ntohl(netLong[0]);
+    machineLong[1] = ntohl(netLong[1]);
+    return machine;
+}
+
+
+long long unsigned
+HCEndian_llMachineToNet(long long unsigned machine)
+{
+    long unsigned *machineLong = (long unsigned *) &machine;
+    long long unsigned net;
+    long unsigned *netLong = (long unsigned *) &net;
+
+    netLong[0] = htonl(machineLong[0]);
+    netLong[1] = htonl(machineLong[1]);
+    return net;
+}
+
+
+#ifdef DOTEST
+void
+HCEndian_selfTest(void)
+{
+    static const int verbose = 0;
+    long long unsigned ll1 = (long long unsigned) 0x3BCDEF0213579876;
+    long long unsigned ll2;
+
+    printf("HCEndian_selfTest.");
+    if (verbose) {
+	printf("before: %llx\n", ll1);
+    }
+    ll2 = HCEndian_llMachineToNet(ll1);
+    if (verbose) {
+	printf("during: %llx\n", ll2);
+    }
+    ll2 = HCEndian_llNetToMachine(ll2);
+    if (verbose) {
+	printf("after: %llx\n", ll2);
+    }
+    assert(ll1 == ll2);
+    printf("..OK\n");
+}
+#endif
Index: squid/src/HintCacheHier.c
diff -u /dev/null squid/src/HintCacheHier.c:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:38 2004
+++ squid/src/HintCacheHier.c	Mon May 20 19:46:41 2002
@@ -0,0 +1,755 @@
+/*
+ * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * AUTHOR: Mike Dahlin, UT Austin, 1998
+ * DEBUG:  section 86,  Hint cache hierarchy.
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ *------------------------------------------------------------------
+ *
+ * LESS Group
+ * Computer Sciences Department 
+ * University of Texas at Austin
+ *
+ * HCDisk ---
+ *          The on-disk cache of hints. The key data structure
+ *          is an mmapped array which is treated as a <entriesPerBucket>-
+ *          associative cache.
+ * 
+ *------------------------------------------------------------------
+ */
+#include "squid.h"
+
+/*
+ * MDD 7.18.1998 
+ * We use a primitive hierarchy consisting of the edges 
+ * listed in the config file for bootstrapping the real 
+ * hierarchy. Each node floods Join/Leave events to
+ * neighbors on the peerlist. The peerlist initially comes from
+ * the config file cache_host entries. We add one thing:
+ * if node A lists B as a cache host to which it will
+ * propagate Join/Leave events, we also want B to have
+ * A on the peerlist. E.g., make all peerlist edges bidirectional
+ * even if the config file's don't make them bidirectional.
+ * The reason for this is that if a new node that no current
+ * nodes have ever heard of joins the system, we of course want to 
+ * propagate membership information to it. E.g, if node D
+ * adds node A to its config file, that effectively also
+ * adds node D to A's config file. Otherwise the old nodes
+ * learn about the new node, but the new node doesn't learn
+ * about anything.
+ *
+ * We also need to help figure out the hierarchy for Plaxton's
+ * algorithm. Plaxton's algorithm figures out who the parents
+ * are, but it doesn't know who the children are. We observe
+ * messages to keep in sync. 
+ * On recv message:
+ *	recv parent msg from parent: process parent message
+ *	recv child msg from child: process child message
+ *	recv parent msg from !parent: send "I am not child" to parent;
+ *			drop message
+ *	recv child msg from !child: add child to child list;
+ *				process child message
+ *	recv "I am not child" from child: remove child
+ */
+
+#define HCHIER_DEBUG 86
+
+#ifdef DOTEST
+static int doTestBarrier(int barrier);
+static void writeTestBarrier(int barrier);
+static int readTestBarrier(int barrier);
+static void clearTestBarrier();
+static void testFindPeer(peer * p);
+static void testPlax(void);
+static void testCreateStuff(char *tag);
+static void testFind(void);
+static void testFindStuff(char *tag, const struct sockaddr_in *expect);
+#endif /* DOTEST */
+
+/*
+ * These must be an set of values each one greater than the
+ * last to define the series of states for the network test.
+ */
+#define BARRIER_START 1000
+#define BARRIER_READY 1001
+#define BARRIER_JOIN 1002
+#define BARRIER_JOIN2 1003
+#define BARRIER_NODELIST 1004
+#define BARRIER_CREATE_STUFF 1005
+#define BARRIER_CREATE_STUFF2 1006
+#define BARRIER_CREATE_STUFF3 1007
+#define BARRIER_PLAX 1008
+#define BARRIER_FIND 1009
+#define BARRIER_LAST 1010
+#define BARRIER_DONE 9999
+
+int HintCacheHier_selfTestDone = 0;
+
+
+dlink_list HintCacheHier_Nodes;
+
+int scanIDs (dlink_list * l, char *b, int *count);
+int scanIDDistances (dlink_list * l, char *b, int *count);
+
+void
+hintCacheHier_Init(void)
+{
+    HintCacheNodeListIter iter;
+    struct sockaddr_in saddr;
+    /*
+     * This should be set in config file
+     */
+    static int bitsPerLevelXXX = 8;
+
+    HintCacheNodelist_Init();
+    HintCachePlax_Init(bitsPerLevelXXX);
+    HintCacheNodelist_LocalJoin();
+    for (HintCacheNodeList_IterStart(&iter);
+	hintCacheNodeList_IterCheck(iter); hintCacheNodeList_IterNext(&iter)) {
+	if (hintCacheNodeList_IterGetAddr(iter, &saddr)) {
+	    hintCachePlax_addNode(&saddr);
+	}
+    }
+}
+
+void
+hintCacheHier_Destroy(void)
+{
+    hintCacheNodelist_LocalLeave();
+    hintCacheNodelist_Destroy();
+    hintCachePlax_Destroy();
+}
+
+/*
+ *------------------------------------------------------------------
+ * MDD 7.18.1998
+ *
+ * HCHier_updateMembershipNeighbor --
+ *
+ *          Add the specified node to the peerlist. See HCHier.h
+ *          for explanation.
+ *
+ * Arguments:
+ *      None.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------7.18.1998---------
+ */
+void
+hintCacheHierUpdateMembershipNeighbor(struct sockaddr_in *neighbor,
+    NeighborAction action)
+{
+    /* Currently nothing */
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierCompareDistanceFromMe --
+ *
+ *          Return <0 if new node is closer than old node, 0 if same
+ *          distance, >0 if new node is closer than old  node.
+ *          If either node is missing, it must be far away. If both
+ *          are missing, say new one is closer (0) (needed to make
+ *          initial sight of new host work).
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+int
+hintCacheHierCompareDistanceFromMe(struct in_addr new, struct in_addr old)
+{
+    int nrtt, ortt;
+    int nhops, ohops;
+    char name[16];
+
+    /* Compare by rtt if both have measured rtts */
+    /* Must make copy of result of inet_ntoa before making
+     * function call because netdb also uses that function */
+    strcpy(name, inet_ntoa(new));
+    nrtt = netdbHostRtt(name);
+    strcpy(name, inet_ntoa(old));
+    ortt = netdbHostRtt(name);
+    if (nrtt && ortt)
+	return (nrtt - ortt);
+
+    /* Otherwise compare hopcount */
+    nhops = netdbHintHops(new);
+    ohops = netdbHintHops(old);
+
+    /* If either host is unknown, say new one is nearer */
+    if (nhops == 0 || ohops == 0)
+	return (-1);
+
+    return (nhops - ohops);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierNewNode --
+ *
+ *          This gets called when we hear about a new node in the system.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------4.1.1998-----------
+ */
+void
+hintCacheHierNewNode(struct sockaddr_in *sin, int hops, long long joinTimeNS)
+{
+    hintCacheNodelist_NetJoin(sin, hops, joinTimeNS);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierDelNode --
+ *
+ *          This gets called when we hear about a node leaving the system
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------4.1.1998-----------
+ */
+void
+hintCacheHierDelNode(struct sockaddr_in *sin, int hops, long long joinTimeNS)
+{
+    hintCacheNodelist_NetLeave(sin, hops, joinTimeNS);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierCheckIfParent --
+ *
+ *          See if the specified node is really my parent.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.10.1998---------
+ */
+int
+hintCacheHierCheckIfParent(URLKey key, struct sockaddr_in *candidate)
+{
+#if USE_DYNAMIC_HIERARCHY
+    return hintCachePlax_CheckIfParent(key, candidate);
+#else
+    /* 
+     * For static algorithm, anyone that wants to be my parent can 
+     * be.
+     */
+    return 1;
+#endif
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHier_CheckIfChild --
+ *
+ *          See if the specified node is really my child.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.10.1998---------
+ */
+int
+hintCacheHierCheckIfChild(struct sockaddr_in *candidate)
+{
+#if USE_DYNAMIC_HIERARCHY
+    return hintCachePlax_CheckIfChild(candidate);
+#else
+    /* 
+     * For static algorithm, anyone that wants to be my child can 
+     * be.
+     */
+    return 1;
+#endif
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierAddChild --
+ *
+ *          This node has claimed to by my child, so add it
+ *          to the dynamic hierarchy.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.10.1998--------
+ */
+void
+hintCacheHierAddChild(struct sockaddr_in *child)
+{
+#if USE_DYNAMIC_HIERARCHY
+    hintCachePlax_AddChild(child);
+#else
+    /*
+     * For static algorithm, I don't track children.
+     */
+    return;
+#endif
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierRemoveChild --
+ *
+ *          This node denies paternity. Disinherit it.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.10.1998----------
+ */
+void
+hintCacheHierRemoveChild(struct sockaddr_in *child)
+{
+#if USE_DYNAMIC_HIERARCHY
+    hintCachePlax_RemoveChild(child);
+#else
+    /*
+     * For static algorithm, I don't track children.
+     */
+    return;
+#endif
+}
+
+
+/*
+ * Network enqueue/send interface.
+ */
+
+/*  Each children queue holds messages that should go to a set of
+ * "equivalent" children  (eg. the children at some level of the
+ * hierarchy.)  There are hintCacheHier_NChildrenQs() such queues;
+ * Child queue q contains c = hintCacheHier_ChildrenPerQ(q) children.
+ * The addresses of the children can be found with the function
+ * hintCacheHier_GetChildAddr(q, c);
+ *
+ * Each parent queue holds messages that should go to one parent.
+ * In general, we may have different parents for different objects.
+ * So, enqueue messages for an object in the queue
+ * hintCacheHier_ParentQIndex(URLKey).
+ */
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierChildQIndex --
+ *
+ *          Return the index into the array of queues of 
+ *          children for children that are my children 
+ *          for this object. (See hintCachePlax for how
+ *          children are grouped into levels.)
+ *
+ *          Also, if I have no children for this object,
+ *          set amILeaf to true.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------4.10.1998-------------
+ */
+int
+hintCacheHierChildQIndex(URLKey * key, int iAmRoot, int *amILeaf)
+{
+    assert(amILeaf != NULL);
+#if USE_DYNAMIC_HIERARCHY
+    return hintCachePlax_ChildQIndex(key, iAmRoot, amILeaf);
+#else
+    /*
+     * For static algorithm, we have one set of children and
+     * thus one outgoing children buffer with index 0.
+     */
+    *amILeaf = 0;
+    return 0;
+#endif
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierNChildrenQs --
+ *
+ *          Return the number of outgoing message queues
+ *          to different classes of children. Each
+ *          "class" corresponds to children for which 
+ *          I am a parent. (See hintCachePlax for how
+ *          children are grouped into levels.)
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------4.10.1998------------
+ */
+int
+hintCacheHierNChildrenQs(void)
+{
+#if USE_DYNAMIC_HIERARCHY
+    return hintCachePlax_NChildrenQs();
+#else
+    /*
+     * For static algorithm, we have one set of children and
+     * thus one outgoing children buffer with index 0.
+     */
+    return 1;
+#endif
+}
+
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierGetChildAddrs --
+ *
+ *        Return the number of children for the specified message
+ *        queue, allocate a buffer for that many addresses,
+ *        and fill in that bufer with the children's addresses.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      See above.
+ *
+ * Side effects:
+ *      Allocates a vector for the addresses. Caller must free
+ *      this vector when done.
+ *
+ *      Note: the vector may be out of date by the time ther caller
+ *      uses it. This is inherent problem -- even if caller sent
+ *      all messages instantaneously, by the time they arrive
+ *      at destination, the child could have left the system
+ *      or a new child could have joined.
+ *
+ *------------------------------------------------4.16.1998------------
+ */
+int
+hintCacheHierGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP)
+{
+#ifndef USE_DYNAMIC_HIERARCHY
+    peer *p;
+    int count = 0, nchildren = 0;
+#endif
+
+    assert(retAddrAP);
+    assert(qIndex < hintCacheHierNChildrenQs());
+
+#if USE_DYNAMIC_HIERARCHY
+    return hintCachePlaxGetChildAddrs(qIndex, retAddrAP);
+#else
+    assert(qIndex == 0);
+    for (p = getFirstPeer(); p; p = getNextPeer(p)) {
+	nchildren++;
+    }
+    *retAddrAP = (struct sockaddr_in *) xmalloc(nchildren
+	* sizeof(struct sockaddr_in));
+    for (p = getFirstPeer(); p; p = getNextPeer(p)) {
+	(*retAddrAP)[count] = p->in_addr;
+	count++;
+    }
+    /*
+     * Squid promises that we run atomically
+     */
+    assert(count == nchildren);
+    return nchildren;
+#endif
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierNParentQs --
+ *
+ *          How many different message queues are they for different
+ *          parents?
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *--------------------------------------------------4.10.1998---------
+ */
+int
+hintCacheHierNParentQs(void)
+{
+#if USE_DYNAMIC_HIERARCHY
+    return hintCachePlaxNParentQs();
+#else
+    /*
+     * For static algorithm, we have one parent
+     * thus one outgoing parent buffer with index 0.
+     */
+    return 1;
+#endif
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierParentQIndex --
+ *
+ *          Return the index of the queue I should use to talk
+ *          to the parent for the specified object (set amIRoot
+ *          if I am the root for the object.)
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.10.1998---------
+ */
+int
+hintCacheHierParentQIndex(URLKey * key, int *amIRoot)
+{
+    assert(amIRoot != NULL);
+#if USE_DYNAMIC_HIERARCHY
+    return hintCachePlaxParentQIndex(key, amIRoot);
+#else
+    /*
+     * For static algorithm, we have one parent
+     * thus one outgoing parent buffer with index 0.
+     */
+    *amIRoot = 0;
+    return 0;
+#endif
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheHierGetParentAddr --
+ *
+ *          Return the address of the node that is curerntly
+ *          the parent for the specified message queue.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      Put answer in *retAddr and return nonzero on error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.10.1998-------
+ */
+int
+hintCacheHierGetParentAddr(int index, struct sockaddr_in *retAddr)
+{
+#if USE_DYNAMIC_HIERARCHY
+    return hintCachePlaxGetParentAddr(index, retAddr);
+#else
+    peer *p;
+
+    for (p = getFirstPeer(); p; p = getNextPeer(p)) {
+	if (p->type == PEER_PARENT) {
+	    *retAddr = p->in_addr;
+	    return 0;
+	}
+    }
+    p = getFirstPeer();
+    if (p) {
+	*retAddr = p->in_addr;
+	return 0;
+    }
+    return -1;
+#endif
+}
+
+
+int
+hintCacheHierSendToParent(struct sockaddr_in *src, HintCacheUpdate * update, int msgtype)
+{
+#if USE_DYNAMIC_HIERARCHY
+    int stillHave;
+    int pIndex, cIndex;
+    int iAmRoot, iAmLeaf;
+#else
+    peer *e;
+#endif
+
+#if USE_DYNAMIC_HIERARCHY
+    pIndex = hintCacheHierParentQIndex(&update->entry.key, &iAmRoot);
+#else
+    for (e = getFirstPeer(); e; e = getNextPeer(e)) {
+	if (e->type != PEER_PARENT)
+	    continue;
+	if (e->in_addr.sin_addr.s_addr == src->sin_addr.s_addr
+	    && e->http_port == src->sin_port) {
+	    if (e->type != PEER_PARENT) {
+		debug(HCHIER_DEBUG, 0,
+		    "warning: got parental msg from non-parent <%s,%d>.\n",
+		    inet_ntoa(src->sin_addr), src->sin_port);
+		debug(HCHIER_DEBUG, 0,
+		    "    Not propagating it.  Configuration mismatch?\n");
+		return (-1);
+	    }
+	    continue;
+	}
+	hintCacheNetEnqueue(&e->hcoutq, msgtype, &update->entry,
+	    update->hopcount + 1);
+    }
+    if (e == 0) {
+	/* Not found. */
+	return (-1);
+	/* Don't propagate */
+    }
+#endif
+
+#if USE_DYNAMIC_HIERARCHY
+    /* Send message */
+    if (!iAmRoot) {
+	assert(pIndex < hintCacheHier_NParentQs());
+	hintCacheNetEnqueue(&parentOutgoingA[pIndex], msgtype, &update->entry,
+	    update->hopcount + 1);
+    }
+#endif
+
+    return (0);
+}
+
+
+
+int
+hintCacheHierSendToSiblings(struct sockaddr_in *src, HintCacheUpdate * update,
+    int msgtype, int siblingtype)
+{
+#if USE_DYNAMIC_HIERARCHY
+    int stillHave;
+    int pIndex, cIndex;
+    int iAmRoot, iAmLeaf;
+#else
+    peer *e;
+#endif
+
+#if USE_DYNAMIC_HIERARCHY
+    pIndex = hintCacheHierParentQIndex(&update->entry.key, &iAmRoot);
+    cIndex = hintCacheHierChildQIndex(&update->entry.key, iAmRoot, &iAmLeaf);
+    if (!iAmLeaf) {
+	assert(cIndex < hintCacheHierNChildrenQs());
+	hintCacheNetEnqueue(&childrenOutgoingA[cIndex], msgtype,
+	    &update->entry, update->hopcount + 1);
+    }
+#else
+    for (e = getFirstPeer(); e; e = getNextPeer(e)) {
+	if (e->in_addr.sin_addr.s_addr != src->sin_addr.s_addr
+	    || e->http_port != src->sin_port) {
+	    if (siblingtype == PEER_NONE || e->type == siblingtype)
+		hintCacheNetEnqueue(&e->hcoutq, msgtype, &update->entry,
+		    update->hopcount + 1);
+	}
+    }
+#endif
+    return (0);
+}
+
+
Index: squid/src/HintCacheNet.c
diff -u /dev/null squid/src/HintCacheNet.c:1.1.2.3
--- /dev/null	Mon Jan 26 04:57:38 2004
+++ squid/src/HintCacheNet.c	Mon May 20 19:46:41 2002
@@ -0,0 +1,563 @@
+/*
+ * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * DEBUG: section 87    Hint cache networking.
+ * AUTHOR: Mike Dahlin, UT Austin, 1998
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ *------------------------------------------------------------------
+ * LESS Group 
+ * Computer Sciences Department 
+ * University of Texas at Austin
+ *
+ * hintCacheNet --- Simple send interface built on squid async send stuff.
+ *------------------------------------------------------------------
+ */
+
+#include "squid.h"
+#include <assert.h>
+
+#define HCNET_DEBUG 87
+
+#define RECV_DEBUG(type, u, hdr, src) \
+    debug (HCNET_DEBUG, 2) ("Got %s: 0x%x at <%s,%d> from <%s,%d>\n", \
+	  (type), *(int *) &(u)->entry.key.key, \
+	  inet_ntoa((u)->entry.ipaddr), (u)->entry.port, \
+	  inet_ntoa((src)->sin_addr), (hdr)->httpport)
+
+static void enqueueBytes(HintCacheNet * n, char *data, int nbytes);
+static int copyToLocal(HintCacheUpdate * updatesA, char *data, int len,
+    int oneUpdateSize);
+static void clear(HintCacheNet * n);
+static void updateHierarchy(HintCacheUpdate * updatesA, int nupdates,
+    struct sockaddr_in *source);
+static void suppress(HintCacheUpdate * updateA, int nupdates);
+static void scoldParent(struct sockaddr_in *parent);
+
+void
+hintCacheNetInit(HintCacheNet * n)
+{
+#ifdef DOTEST
+    n->testMode = 0;
+    n->testCount = 0;
+#endif
+    clear(n);
+}
+
+static void
+clear(HintCacheNet * n)
+{
+    HintCacheNetHeader hdr;
+    const char *url = "route://updates";
+    request_flags rflags;
+    StoreEntry *entry;
+
+    assert(n);
+
+    /* Set up entry with request */
+    *(unsigned int *) &rflags = 0;
+    rflags.cachable = 1;
+    entry = storeCreateEntry(url, url, rflags, METHOD_GET);
+    n->sendBuffer = entry;
+    EBIT_SET(entry->flags, ENTRY_SPECIAL);	/* formerly set KEEP_INMEM */
+/*   EBIT_SET(entry->flags, DONT_FREE_FOR); */
+    n->sendBuffer->mem_obj->request =
+	requestLink(urlParse(METHOD_GET, (char *) url));
+
+    n->sendLength = 0;
+
+    n->state = HC_filling;
+
+    /* Prepare header for next transmission */
+    hdr.httpport = htons(Config.Sockaddr.http->s.sin_port);
+    hdr.updlen = htons(sizeof(HintCacheUpdateNet));
+    enqueueBytes(n, (char *) &hdr, sizeof(hdr));
+}
+
+void
+hintCacheNetDestroy(HintCacheNet * n)
+{
+    storeRelease(n->sendBuffer);
+    n->state = HC_destroyed;
+}
+
+void
+hintCacheNetEnqueue(HintCacheNet * n, int action, HintCacheEntry * entry, int hopcount)
+{
+    HintCacheUpdate update;
+    HintCacheUpdateNet netUpdate;
+
+#ifdef DOTEST
+    if (n->testMode) {
+	n->testCount++;
+	return;
+    }
+#endif
+    debug(HCNET_DEBUG, 4)
+	("HCNet_Enqueue onto 0x%x (action %d) (entry.key %llx entry.ipaddr %s port %d)\n",
+	n, action, entry->key.key, inet_ntoa(entry->ipaddr), entry->port);
+
+    hintCacheUpdateInit(&update, action, entry, hopcount);
+    hintCacheUpdateNetInit(&netUpdate, &update);
+    enqueueBytes(n, (char *) &netUpdate, sizeof(HintCacheUpdateNet));
+}
+
+static void
+enqueueBytes(HintCacheNet * n, char *data, int nbytes)
+{
+    static enqreentrancy = 0;
+
+    assert(n->state == HC_filling);
+    assert(!enqreentrancy);
+    ++enqreentrancy;
+    n->sendLength += nbytes;
+    storeAppend(n->sendBuffer, data, nbytes);
+    --enqreentrancy;
+}
+
+int
+hintCacheNetBytesReady(HintCacheNet * n)
+{
+    return n->sendLength;
+}
+
+void
+hintCacheNetComplete(HintCacheNet * n)
+{
+
+    assert(n);
+    assert(n->state == HC_filling);
+    n->state = HC_full;
+    hintCacheFinishHeader(n->sendBuffer);
+    storeComplete(n->sendBuffer);
+}
+
+void
+hintCacheNetSendTo(HintCacheNet * n, struct sockaddr_in *dest)
+{
+    assert(n->state == HC_full);
+    assert(n->sendLength > sizeof(HintCacheNetHeader));
+    debug(HCNET_DEBUG, 2) ("HCNet_SendTo: sending routes on 0x%x to <%s,%d>\n",
+	n, inet_ntoa(dest->sin_addr), dest->sin_port);
+    putSend(n->sendBuffer, dest, NULL, NULL, 0);
+}
+
+void
+hintCacheNetDone(HintCacheNet * n)
+{
+    StoreEntry *entry = n->sendBuffer;
+
+    assert(n->state == HC_full);
+
+    EBIT_CLR(entry->flags, ENTRY_SPECIAL);     /* formerly KEEP_INMEM flag */
+
+    EBIT_SET(entry->flags, RELEASE_REQUEST);
+    storeUnlockObject(entry);
+
+    clear(n);
+}
+
+
+#ifdef DOTEST
+void
+hintCacheNetSetTestMode(HintCacheNet * n)
+{
+    n->testMode = 1;
+    n->testCount = 0;
+}
+
+int
+hintCacheNetGetTestCount(HintCacheNet * n)
+{
+    return n->testCount;
+}
+#endif /* DOTEST */
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNetDataArrives --
+ *
+ *          Action to take when messages arrive from network.
+ *
+ * Arguments:
+ *      char *data -- unaligned buffer of network-formatted hintCacheNetUpdates
+ *      int len -- number of bytes in that buffer
+ *      struct sockaddr *source -- who sent the buffer
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Many.
+ *
+ *------------------------------------------------4.2.1998------------
+ */
+void
+hintCacheNetDataArrives(char *data, int len, HintCacheNetHeader * hdr,
+    struct sockaddr_in *source)
+{
+    struct sockaddr_in sin;
+    HintCacheUpdate *updatesA;
+    int nupdates;
+    int iupdate;
+
+    if (!HC_ACTIVE()) {
+	/* Hint cache is inoperative.  Nothing to do. */
+	return;
+    }
+
+    assert(source->sin_family == AF_INET);
+    assert(hdr->updlen >= HCU_MINLEN);
+
+    debug(HCNET_DEBUG, 3)
+	("HintCacheDataArrives: got %d bytes of stuff (probably %d updates xtra=%d\n",
+	len, len / hdr->updlen, len % hdr->updlen);
+
+    /* Copy to alignment buffer and local format */
+    updatesA = (HintCacheUpdate *) xmalloc(len);
+    nupdates = copyToLocal(updatesA, data, len, hdr->updlen);
+
+    /* 
+     * Suppress loops. Better to do this on send-side, but
+     * this should be uncommon --> no performance impact
+     */
+    suppress(updatesA, nupdates);
+
+    /*
+     * Help hierarchy learn about who our children are.
+     */
+    source->sin_port = hdr->httpport;
+
+    updateHierarchy(updatesA, nupdates, source);
+
+    /* 
+     * Prefetch if we have a large number of requests.
+     * Idea is to tell OS to start bringing in the pages
+     * that we are about to touch.
+     */
+    if (nupdates >= HCD_PREFETCH_THRESH) {
+	hintCacheDisk_prefetch(hcDisk, updatesA, nupdates);
+    }
+
+    /*
+     * OK. Now we can start processing the messages.
+     */
+    for (iupdate = 0; iupdate < nupdates; iupdate++) {
+	switch (updatesA[iupdate].action) {
+	case HC_InvalToParent:
+	    RECV_DEBUG("hintCache_InvalToParent", &updatesA[iupdate], hdr, source);
+	    hcprop_handleInvalToParent(&updatesA[iupdate], source, 0);
+	    break;
+
+	case HC_InvalToChild:
+	    RECV_DEBUG("hintCache_InvalToChild", &updatesA[iupdate], hdr, source);
+	    hcprop_handleInvalToChild(&updatesA[iupdate], source, 0);
+	    break;
+
+	case HC_InformToParent:
+	    RECV_DEBUG("hintCache_InformToParent", &updatesA[iupdate], hdr, source);
+	    hcprop_handleInformToParent(&updatesA[iupdate], source, 0);
+	    break;
+
+	case HC_InformToChild:
+	    RECV_DEBUG("hintCache_InformToChild", &updatesA[iupdate], hdr, source);
+	    hcprop_handleInformToChild(&updatesA[iupdate], source, 0);
+	    break;
+
+	case HC_Join:
+	    /* New cache node!  Add to list. */
+	    RECV_DEBUG("hintCache_Join", &updatesA[iupdate], hdr, source);
+	    /*
+	     * MDD 7.18.1998 
+	     * When a node relays a join/leave to us, make sure
+	     * that we send future joins to that node by adding
+	     * that node to the peer list if it's not already there.
+	     */
+	    sin.sin_family = AF_INET;
+	    sin.sin_addr = source->sin_addr;
+	    sin.sin_port = hdr->httpport;
+	    hintCacheHier_updateMembershipNeighbor(&sin, NEIGHBOR_ADD);
+
+	    /*
+	     * Now update local state for join
+	     */
+	    sin.sin_family = AF_INET;
+	    sin.sin_addr = updatesA[iupdate].entry.ipaddr;
+	    sin.sin_port = updatesA[iupdate].entry.port;
+	    hintCacheHier_newNode(&sin, updatesA[iupdate].hopcount,
+		updatesA[iupdate].entry.key.key);
+	    break;
+
+	case HC_Leave:
+	    /* Cache node is either dead or has been detected dead. */
+	    RECV_DEBUG("hintCache_Leave", &updatesA[iupdate], hdr, source);
+	    sin.sin_family = AF_INET;
+	    sin.sin_addr = updatesA[iupdate].entry.ipaddr;
+	    sin.sin_port = updatesA[iupdate].entry.port;
+	    hintCacheHier_delNode(&sin, updatesA[iupdate].hopcount,
+		updatesA[iupdate].entry.key.key);
+
+	    /*
+	     * MDD 7.18.1998 
+	     * When we receive a join from a node, make sure
+	     * that we send future joins to that node by adding
+	     * that node to the peer list if it's not already there.
+	     */
+	    hintCacheHier_updateMembershipNeighbor(source, NEIGHBOR_ADD);
+	    /*
+	     * MDD 7.18.1998
+	     * And the node we just heard about is gone, so it must
+	     * no longer be a neighbor across which to propagate changes
+	     * in membership.
+	     */
+	    hintCacheHier_updateMembershipNeighbor(&sin, NEIGHBOR_REMOVE);
+
+	    break;
+
+	case HC_NotChild:
+	    /*
+	     * This message should have been handled and suppressed
+	     * (by making it "HC_Ignore") in the updateHierarchy() code.
+	     */
+	    RECV_DEBUG("HC_NotChild", &updatesA[iupdate], hdr, source);
+	    assert(0);
+	    break;
+
+	case HC_Ignore:
+	    /* This message was suppressed either because it is
+	     * part of a loop or because it came from a node that
+	     * thinks it is my parent but isnt.
+	     */
+	    break;
+
+	default:
+	    /* Ignore bad messages */
+	    debug(HCNET_DEBUG, 1)
+		("HCHintCache: unknown update action %d from net\n",
+		updatesA[iupdate].action);
+	    break;
+	}
+    }
+
+    xfree(updatesA);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * copyToLocal --
+ *
+ *          Copy unaligned network-format buffer to aligned, local format
+ *          array of updates
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      Nelements
+ *
+ * Side effects:
+ *      Copies data into udpatesA
+ *
+ *-----------------------------------------------3.31.1998-----------
+ */
+static int
+copyToLocal(HintCacheUpdate * updatesA, char *data, int len, int oneUpdateSize)
+{
+    char *alignbuf;
+    int uoff;
+    HintCacheUpdateNet *nupdatep;
+    int ii;
+
+    alignbuf = xmalloc(len);
+    memcpy(alignbuf, data, len);
+
+    for (uoff = 0, ii = 0; uoff < len; uoff += oneUpdateSize, ii++) {
+	nupdatep = (HintCacheUpdateNet *) (alignbuf + uoff);
+	hintCacheUpdateNetLocalFormat(nupdatep, &updatesA[ii]);
+    }
+    xfree(alignbuf);
+    return ii;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * suppress --
+ *
+ *          Decide if any of these hints have bounced around
+ *          network too much to be worth looking at (mainly
+ *          we want to suppress loops.) In prinicple,
+ *          the algorithm guarantees that loops cannot occur,
+ *          but best to be safe.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      May modify records in updateA to mark them as "ignore."
+ *
+ *-----------------------------------------------4.1.1998-------------
+ */
+static void
+suppress(HintCacheUpdate * updateA, int nupdates)
+{
+#ifdef NOTYET
+    /* Need to fill this in */
+    int iupdate;
+
+    for (iupdate = 0; iupdate < nupdates; iupdate++) {
+	if (stoppable update) {
+	    updateA[iupdate].action = HC_Ignore;
+	}
+    }
+#endif
+
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * updateHierarchy --
+ *
+ * We also need to help figure out the hierarchy for Plaxton's
+ * algorithm. Plaxton's algorithm figures out who the parents
+ * are, but it doesn't know who the children are. We observe
+ * messages to keep in sync. 
+ * On recv message:
+ *	recv parent msg from parent: process parent message
+ *	recv child msg from child: process child message
+ *	recv parent msg from !parent: send "I am not child" to parent;
+ *			drop message
+ *	recv child msg from !child: add child to child list;
+ *				process child message
+ *	recv "I am not child" from child: remove child
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      May modify records in update array to be "HC_Ignore."
+ *
+ *------------------------------------------------4.1.1998------------
+ */
+static void
+updateHierarchy(HintCacheUpdate * updatesA, int nupdates, struct sockaddr_in *source)
+{
+    int iupdate;
+    int parentScolded = 0;
+
+    for (iupdate = 0; iupdate < nupdates; iupdate++) {
+	switch (updatesA[iupdate].action) {
+	case HC_InformToChild:
+	case HC_InvalToChild:
+	    if (!HCHier_CheckIfParent(updatesA[iupdate].entry.key, source)) {
+		if (!parentScolded) {
+		    scoldParent(source);
+		    parentScolded = 1;
+		}
+		updatesA[iupdate].action = HC_Ignore;
+	    }
+	    break;
+
+	case HC_InformToParent:
+	case HC_InvalToParent:
+#if 1				/* XXX! - disabling parent&child lists */
+	    if (!hintCacheHier_CheckIfChild(source)) {
+		hintCacheHier_AddChild(source);
+	    }
+#endif
+	    break;
+
+	case HC_NotChild:
+	    hintCacheHier_RemoveChild(source);
+	    updatesA[iupdate].action = HC_Ignore;
+	    break;
+
+
+	default:
+	    /*
+	     * Other messages don't affect hierarchy. Ignore them here.
+	     */
+	    break;
+	}
+    }
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * scoldParent --
+ *
+ *          Tell parent "I am not child". Need to use
+ *          our own private HintCacheNet queue since all of the
+ *          other queues are associated with the hierarchy
+ *          and this message is to tell someone they
+ *          are *not* in the hierarchy.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------4.2.1998------------
+ */
+static void
+scoldParent(struct sockaddr_in *parent)
+{
+    static int initialized = 0;
+    static HintCacheNet netBuf;
+    static HintCacheEntry dummyEntry;
+    static URLKey dummyKey;
+
+    debug(HCNET_DEBUG, 7) ("In scoldParent %s\n", inet_ntoa(parent->sin_addr));
+
+    if (!initialized) {
+	hintCacheNetInit(&netBuf);
+	URLKey_Init(&dummyKey, NULL);
+	hintCacheEntry_Init(&dummyEntry, dummyKey,
+	    &Config.Sockaddr.http->s, squid_curtime);
+	initialized = 1;
+    }
+
+    hintCacheNetEnqueue(&netBuf, HC_NotChild, &dummyEntry, 1);
+    hintCacheNetComplete(&netBuf);
+    hintCacheNetSendTo(&netBuf, parent);
+    hintCacheNetDone(&netBuf);
+    return;
+}
Index: squid/src/HintCacheNodes.c
diff -u /dev/null squid/src/HintCacheNodes.c:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:38 2004
+++ squid/src/HintCacheNodes.c	Mon May 20 19:46:41 2002
@@ -0,0 +1,970 @@
+/*
+ * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * DEBUG: section 88    List of known caches.
+ * AUTHOR: Mike Dahlin, UT Austin, 1998
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ *------------------------------------------------------------------
+ * LESS Group 
+ * Computer Sciences Department 
+ * University of Texas at Austin
+ *
+ * HCNodelist ---
+ * The nodelist keeps a list of all nodes in the hierarchy whether they
+ * are alive or dead. It uses a flooding algorithm for this (see 
+ * ../notes.3.17.1998). As part of this flooding algorithm, it learns
+ * a hopcount to other nodes. We tell squid_db this hopcount as an
+ * initial *rough* estimate of distance between nodes.
+ *  
+ * The flooding algorithm needs as input a list of "neighbors". The lists
+ * of neighbors for all nodes MUST overlap. The lists of neighbors SHOULD
+ * include only nearby neighbors (so that the hopcounts are correct). 
+ * It uses the squid static hierarchy (see neighbors.c e.g. getFirstPeer()
+ * etc) for this initial list.
+ *------------------------------------------------------------------
+ */
+#include "squid.h"
+
+/*
+ * Mike Dahlin's interface comments from HCNodelist.h:
+ *
+ * Out-calls: These internal routines are where you should place
+ * outcalls for being notified of important events:
+ *
+ * static void HCNodelist_OutcallHops _PARAMS((struct sockaddr_in sin, 
+ *						int hops)); 
+ *
+ * e.g.  The nodelist promises to tell squid_db whenever it learns a new
+ *       distance to a node. ?? The nodelist promises to tell Plaxton
+ *       when the distance to a node changes??
+ *
+ * static void HCNodelist_OutcallJoin() _PARAMS((struct sockaddr_in sin));
+ * e.g.  The nodelist promises to tell Plaxton when a new node joins.
+ *
+ * static void hintCacheNodelist_OutcallLeave() _PARAMS((struct sockaddr_in sin));
+ *  The nodelist promises to tell Plaxton when a node leaves.
+ */
+
+#define HCNODES_DEBUG 88
+
+typedef struct HierNodeElem
+{
+    dlink_node links;
+    struct sockaddr_in sin;
+    int action;			/* HC_Join or HC_Leave */
+    long long timestamp_ns;	/* time of action */
+}
+HierNodeElem;
+
+static dlink_list nodes;
+static int myStatus = HC_Leave;
+
+static void HierNodeElem_Init _PARAMS((HierNodeElem *, struct sockaddr_in *,
+	int action, long long timestamp_ns));
+
+static HierNodeElem *nodeFind(struct sockaddr_in *sin);
+static long long currentTimeNS();
+static void floodEvent(int action, struct sockaddr_in *source,
+    long long timeNS, int hopcount);
+
+static void hintCacheNodelistOutcallHops(struct sockaddr_in *sin,
+    int hops, long long timeNS);
+static void hintCacheNodelistOutcallJoin(struct sockaddr_in *sin,
+    int hops, long long timeNS);
+static void hintCacheNodelistOutcallLeave(struct sockaddr_in *sin,
+    int hops, long long timeNS);
+
+static void printList();
+
+
+static void
+HierNodeElem_Init(HierNodeElem * e, struct sockaddr_in *sin, int action,
+    long long timestamp_ns)
+{
+    assert(action == HC_Join || action == HC_Leave);
+    List_InitElement(&e->links);
+    e->sin = *sin;
+    e->action = action;
+    e->timestamp_ns = timestamp_ns;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodeList_Init --
+ *
+ *          Constructor.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Initialize nodelist to empty list.
+ *
+ *----------------------------------------------3.31.1998-------------
+ */
+void
+hintCacheNodelistInit(void)
+{
+    nodes.head = nodes.tail = 0;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodeListDestroy --
+ *
+ *          Deallocate all elements in list
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *--------------------------------------------------3.31.1998-------
+ */
+void
+hintCacheNodelist_Destroy(void)
+{
+    dlink_node *item;
+    
+    while (nodes.head) {
+	item = nodes.head;
+	dlinkDelete(item, &nodes);
+	xfree(item);
+    }
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodeListLocalJoin --
+ *
+ *          Do a local join. This tells the algorithm
+ *          to flood "join" messages to the neighbors.
+ *
+ * Arguments:
+ *      struct sockaddr_in myId -- my ip address
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.1.1998----
+ */
+void
+hintCacheNodelistLocalJoin(void)
+{
+    struct sockaddr_in *myId;
+    int hopcount;
+    long long timeNS;
+#if 0
+    HintCacheEntry hcEntry;
+    HintCacheUpdate update;
+    URLKey key;
+    int nbpl;
+    int ii;
+#endif
+
+    myStatus = HC_Join;
+
+    myId = &Config.Sockaddr.http->s;
+    timeNS = currentTimeNS();
+    hopcount = 1;
+    floodEvent(HC_Join, myId, timeNS, hopcount);
+
+#if 0
+    /* "Priming" code */
+    if (parentOutgoingA) {
+	nbpl = (hintCachePlax_bucketsPerLevel > 0) ? hintCachePlax_bucketsPerLevel : 256;
+	for (ii = 0; ii < nbpl; ii++) {
+	    key.key = ii;
+	    hintCacheEntry_Init(&hcEntry, key, &Config.Sockaddr.http->s);
+	    hintCacheUpdate_Init(&update, HC_InvalToParent, &hcEntry, 1);
+	    hcprop_handleInvalToParent(&update, 1);
+	}
+    }
+#endif
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodeListLocalLeave --
+ *
+ *          Do a local leave. This tells the algorithm
+ *          to flood "leave" messages to the neighbors.
+ *
+ * Arguments:
+ *      struct sockaddr_in myId -- my ip address
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.1.1998----
+ */
+void
+hintCacheNodelistLocalLeave(void)
+{
+    struct sockaddr_in *myId;
+    int hopcount;
+    long long timeNS;
+
+    myStatus = HC_Leave;
+    myId = &Config.Sockaddr.http->s;
+    timeNS = currentTimeNS();
+    hopcount = 1;
+    floodEvent(HC_Leave, myId, timeNS, hopcount);
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodelistgetMyStatus --
+ *
+ *          Am I currently in or out?
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.1.1998--------
+ */
+int
+hintCacheNodelistmyStatus(void)
+{
+    return myStatus;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodelistNetJoin --
+ *
+ *          Process a "join" received from the network.
+ *          If this is a new node, a new action for a node,
+ *          or a current action with a shorter distance,
+ *          proceed with the join and propagate message
+ *          to neighbors.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Allocates and adds an element to the list; calls 
+ *      OutcallJoin().
+ *
+ *------------------------------------------------------7.19.1998----
+ */
+void
+hintCacheNodelistNetJoin(struct sockaddr_in *sin, int hops, long long joinTimeNS)
+{
+    HierNodeElem *h, *oldCopy;
+    int oldHops;
+    int foundOldJoin = 0;
+    int joinIsNewer;
+
+    assert(sin);
+    /* Ignore if it's already on list and either (1) a newer record
+     * or (2) a current record and at least as close as this
+     * update.  Also ignore if it is me!
+     * For simplicity, rather than update a record in place, remove
+     * it and add a new record to front of list. This should be better
+     * for performance, too, since we expect to get a burst of
+     * notifications from all neighbors, so put record at front of list. 
+     */
+    if (!SINCMP(sin, &Config.Sockaddr.http->s)) {
+	return;
+    }
+    oldCopy = nodeFind(sin);
+    if (oldCopy != NULL) {
+	if (oldCopy->timestamp_ns > joinTimeNS) {
+	    /* We got a stale message; ignore it */
+	    return;
+	} else if (oldCopy->action != HC_Join
+	    && oldCopy->timestamp_ns < joinTimeNS) {
+	    /* Join supercedes an old HC_Leave */
+	    dlinkDelete(&oldCopy->links, &nodes);
+	    xfree(oldCopy);
+	    /* Fall through and add this join to nodelist */
+	} else {
+	    assert(oldCopy->action == HC_Join);
+	    foundOldJoin = 1;
+	    assert(oldCopy->timestamp_ns <= joinTimeNS);
+	    joinIsNewer = (oldCopy->timestamp_ns < joinTimeNS);
+	    oldHops = netdbHintHops(sin->sin_addr);
+
+
+	    if (oldHops > hops) {
+	        dlinkDelete(&oldCopy->links, &nodes);
+		xfree(oldCopy);
+		/* Fall through and add this join to nodelist and flood */
+	    } else if (joinIsNewer) {
+		/*
+		 * Join is newer but not closer. Propagate to neighbors
+		 * but no need to do anything locally beyond updating
+		 * the timestamp.
+		 */
+		oldCopy->timestamp_ns = joinTimeNS;
+		floodEvent(HC_Join, sin, joinTimeNS, hops + 1);
+		return;
+	    }
+	}
+    }
+    /*
+     * Only get here if new join supercedes and old join removed or
+     * nonexistant. Do the join and flood it to neighbors.
+     */
+    assert(!nodeFind(sin));
+
+    h = (HierNodeElem *) xmalloc(sizeof(HierNodeElem));
+    HierNodeElem_Init(h, sin, HC_Join, joinTimeNS);
+    dlinkAdd(h, &h->links, &nodes);
+
+    /*
+     * Now tell everyone else (locally and network) about 
+     * the new addition or new distance
+     */
+    floodEvent(HC_Join, sin, joinTimeNS, hops + 1);
+    if (foundOldJoin) {
+	HintCacheNodelistOutcallHops(sin, hops, joinTimeNS);
+    } else {
+	hintCacheNodelistOutcallJoin(sin, hops, joinTimeNS);
+    }
+
+    if (!foundOldJoin) {
+	debug(HCNODES_DEBUG, 2)
+	    ("hintCacheNodelist::NetJoin() adds %d.%d.%d.%d; list is: \n",
+	    (unsigned char) ((sin->sin_addr.s_addr & 0xFF000000) >> 24),
+	    (unsigned char) ((sin->sin_addr.s_addr & 0x00FF0000) >> 16),
+	    (unsigned char) ((sin->sin_addr.s_addr & 0x0000FF00) >> 8),
+	    (unsigned char) ((sin->sin_addr.s_addr & 0x000000FF) >> 0));
+	printList();
+	debug(HCNODES_DEBUG, 2) ("\n");
+    }
+
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodelistNetLeave --
+ *
+ *          Process a notification that a node has left the system
+ *
+ *          We keep "departed" nodes on nodelist with a "leave" flag
+ *          set so we know when to stop propagating messages.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------7.19.1998--------------
+ */
+void
+hintCacheNodelistNetLeave(struct sockaddr_in *sin, int hops, long long leaveTimeNS)
+{
+    HierNodeElem *h, *oldCopy;
+    int foundOldLeave = 0;
+
+    assert(sin);
+
+    /* Ignore if it's already on list and a newer record.
+     * For simplicity, rather than update a record in place, remove
+     * it and add a new record to front of list. This should be better
+     * for performance, too, since we expect to get a burst of
+     * notifications from all neighbors, so put record at front of list. 
+     */
+    oldCopy = nodeFind(sin);
+    if (oldCopy) {
+	if (oldCopy->action == HC_Leave) {
+	    foundOldLeave = 1;
+	}
+	if (oldCopy->timestamp_ns < leaveTimeNS) {
+	    dlinkDelete(&oldCopy->links, &nodes);
+	    xfree(oldCopy);
+	} else {
+	    /* 
+	     * old copy is actually newer than this update. Ignore this
+	     * update.
+	     */
+	    return;
+	}
+    }
+    /*
+     * Only get here if new leave supercedes old record removed or
+     * nonexistant 
+     */
+    assert(!nodeFind(sin));
+
+    h = (HierNodeElem *) xmalloc(sizeof(HierNodeElem));
+    HierNodeElem_Init(h, sin, HC_Leave, leaveTimeNS);
+    dlinkAdd(h, &h->links, &nodes);
+
+    /*
+     * Now tell everyone else (locally and network) about 
+     * the new addition or new distance
+     */
+    floodEvent(HC_Leave, sin, leaveTimeNS, hops + 1);
+    if (!foundOldLeave) {
+	HCNodelist_OutcallLeave(sin, hops, leaveTimeNS);
+    }
+
+    if (!foundOldLeave) {
+	debug(HCNODES_DEBUG, 4)
+	    ("HCNodelist::NetLeave() removes %d.%d.%d.%d; list is: \n",
+	    (unsigned char) ((sin->sin_addr.s_addr & 0xFF000000) >> 24),
+	    (unsigned char) ((sin->sin_addr.s_addr & 0x00FF0000) >> 16),
+	    (unsigned char) ((sin->sin_addr.s_addr & 0x0000FF00) >> 8),
+	    (unsigned char) ((sin->sin_addr.s_addr & 0x000000FF) >> 0));
+	printList();
+	debug(HCNODES_DEBUG, 4) ("\n");
+    }
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodelist_OutcallHops --
+ *
+ *          This function gets called whenever the number of hops
+ *          to a node *changes* due to network updates. This
+ *          is a good place to put function calls to modules that
+ *          care to hear about such things.
+ *
+ *          1) netdb
+ *          2) plaxton dynamic hierarchy algorithm
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *--------------------------------------------------------7.19.1998-----
+ */
+static void
+hintCacheNodelistOutcallHops(struct sockaddr_in *sin, int hops, long long timeNS)
+{
+    char name[16];
+
+    /*
+     * Tell netdb
+     */
+    strcpy(name, inet_ntoa(sin->sin_addr));
+    if (!netdbHintHops(sin->sin_addr)) {
+	netdbAdd(sin->sin_addr, name);
+    }
+    netdbUpdateHintHops(sin->sin_addr, hops);
+
+    /* 
+     * Tell plaxton algorithm
+     */
+    hintCachePlax_changeDistance(sin);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodelistOutcallJoin --
+ *
+ *          This function gets called whenever a node joins the
+ *          sytsem.
+ *          This is a good place to put function calls to modules that
+ *          care to hear about such things.
+ *
+ *          Right now, 3 people care:
+ *          1) netdb
+ *          2) plaxton dynamic hierarchy algorithm
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------7.19.1998-----------
+ */
+static void
+hintCacheNodelistOutcallJoin(struct sockaddr_in *sin, int hops, long long timeNS)
+{
+    char name[16];
+
+    /*
+     * Tell netdb
+     */
+    strcpy(name, inet_ntoa(sin->sin_addr));
+    netdbAdd(sin->sin_addr, name);
+    netdbUpdateHintHops(sin->sin_addr, hops);
+
+    /* 
+     * Tell plaxton algorithm
+     */
+    hintCachePlax_addNode(sin);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodelistOutcallLeave --
+ *
+ *          This function gets called whenever a node leaves the
+ *          sytsem.
+ *          This is a good place to put function calls to modules that
+ *          care to hear about such things.
+ *
+ *          1) plaxton dynamic hierarchy algorithm
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------7.19.1998----------
+ */
+static void
+hintCacheNodelistOutcallLeave(struct sockaddr_in *sin, int hops, long long timeNS)
+{
+    /* 
+     * Tell plaxton algorithm
+     */
+    hintCachePlax_removeNode(sin);
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * nodeFind --
+ *
+ *          Find node with matching address.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+static HierNodeElem *
+nodeFind(struct sockaddr_in *sin)
+{
+    HierNodeElem *e;
+    dlink_node *item;
+
+    for (item = nodes.head; item; item = item->next) {
+	e = (HierNodeElem *) item;
+	if (!SINCMP(&e->sin, sin)) {
+	    return (e);
+	}
+    }
+    return (NULL);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * floodEvent --
+ *
+ *          Send the notification to our neighbors.
+ *
+ * Arguments:
+ *      int action HC_Join or HC_Leave
+ *      struct sockaddr_in *source -- the subject of the action
+ *      long long timeNS -- the time of the action (used for
+ *                          ordering events and removing duplicates)
+ *      int hopcount -- how many hops has this event seen?
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------3.31.1998--------
+ */
+static void
+floodEvent(int action, struct sockaddr_in *source, long long timeNS,
+    int hopcount)
+{
+#ifdef USE_DYNAMIC_HIERARCHY
+    HintCacheEntry entry;
+    peer *p;
+    URLKey hackURLKey;
+    struct sockaddr_in dest;
+
+    assert(action == HC_Join || action == HC_Leave);
+
+    if (neighborsOutgoing == NULL) {
+	return;
+    }
+
+    hackURLKey.key = timeNS;	/* XXX Update should be a union XXX */
+
+    hintCacheEntry_Init(&entry, hackURLKey, source);
+    hintCacheNet_Enqueue(neighborsOutgoing, action, &entry, hopcount);
+#if 1
+    hintCacheNet_Complete(neighborsOutgoing);
+
+    for (p = getFirstPeer(); p; p = getNextPeer(p)) {
+	if (p->in_addr.sin_addr.s_addr == 0) {
+	    debug(HCNODES_DEBUG, 4)
+		("hintCacheNodelist warning: peer %s addr not set\n", p->host);
+	    continue;
+	}
+	dest.sin_family = AF_INET;
+	dest.sin_addr = p->in_addr.sin_addr;
+	dest.sin_port = p->http_port;
+	hintCacheNet_SendTo(neighborsOutgoing, &dest);
+    }
+
+    hintCacheNet_Done(neighborsOutgoing);
+#endif
+#endif /* USE_DYNAMIC_HIERARCHY */
+}
+
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodeListIterXXX --
+ *
+ *          Used for iterating through all addresses on list.
+ *
+ *   for(hintCacheNodeListIterStart(&iter);
+ *       hintCacheNodeListIterCheck(&iter);
+ *       hintCacheNodeListIterNext(&iter)){
+ *     valid = hintCacheNOdeListIterGetAddr(&iter, &addr);
+ *   }
+ *  
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Note -- only itereates through "joined" elements;
+ *      Skip the shadow elements representing nodes that
+ *      have left.
+ *
+ *      Warning -- iterator is pointer into element on list.
+ *      If list changing during iteration, could get confused.
+ *
+ *------------------------------------------------------------------
+ */
+void
+hintCacheNodeListIterStart(HintCacheNodeListIter iter)
+{
+    iter = (HintCacheNodeListIter) nodes.head;
+}
+
+int
+hintCacheNodeList_IterCheck(HintCacheNodeListIter iter)
+{
+    dlink_node *links = iter;
+    return (links->next != 0);
+}
+
+void
+hintCacheNodeList_IterNext(HintCacheNodeListIter iter)
+{
+    HierNodeElem *elem;
+
+    if (iter->next == 0) {
+	return;
+    }
+
+    while (1) {
+	iter = iter->next;
+	/*
+	 * Skip non-HC_Join elements by keeping going in that case.
+	 */
+	if (iter->next == 0) {
+	    return;
+	}
+	elem = iter->data;
+	if (elem->action == HC_Join) {
+	    return;
+	}
+    }
+
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodelistIterGetAddr --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+int
+hintCacheNodelistIterGetAddr(HintCacheNodeListIter iter, struct sockaddr_in *ret)
+{
+    HierNodeElem *elem;
+    elem = iter->data;
+    *ret = elem->sin;
+    if (elem->action == HC_Join) {
+	return 1;
+    }
+    return 0;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * currentTimeNS --
+ *
+ *          Return the current time in nanoseconds since Jan 1, 1970.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+static long long
+currentTimeNS()
+{
+    static const long long NS_PER_SEC = 1000000000;
+    static const long long NS_PER_USEC = 1000;
+    int error;
+    struct timeval time;
+    long long ret;
+
+    error = gettimeofday(&time, NULL);
+    assert(error != -1);
+    ret = NS_PER_SEC * (long long) time.tv_sec
+	+ NS_PER_USEC * (long long) time.tv_usec;
+    return ret;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * printList --
+ *
+ *          Print the current list of nodes to stdout.
+ *
+ * Arguments:
+ *      None.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+
+ *------------------------------------------------------------------
+ */
+static void
+printList()
+{
+    HintCacheNodeListIter iter;
+    struct sockaddr_in nodeAddr;
+    int valid;
+
+    for (hintCacheNodeListIterStart(iter);
+	hintCacheNodeListIterCheck(iter); hintCacheNodeListIterNext(&iter)) {
+	valid = hintCacheNodeListIterGetAddr(iter, &nodeAddr);
+	if (valid) {
+	    debug(HCNODES_DEBUG, 2)
+		("\t%d.%d.%d.%d\n",
+		(unsigned char) ((nodeAddr.sin_addr.s_addr & 0xFF000000) >> 24),
+		(unsigned char) ((nodeAddr.sin_addr.s_addr & 0x00FF0000) >> 16),
+		(unsigned char) ((nodeAddr.sin_addr.s_addr & 0x0000FF00) >> 8),
+		(unsigned char) ((nodeAddr.sin_addr.s_addr & 0x000000FF) >> 0));
+	}
+    }
+}
+
+
+#ifdef DOTEST
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheNodelistSelfTest --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+void
+hintCacheNodelistSelfTest(void)
+{
+    struct sockaddr_in n0, n1, n2;
+    HintCacheNodeListIter iter;
+    struct sockaddr_in nodeAddr;
+    int nhops;
+    int valid;
+    int found = 0;
+
+    printf("HintCacheNodelistSelfTest...");
+    n0.sin_addr.s_addr = 0x90536F00;
+    n0.sin_port = 0;
+    n1.sin_addr.s_addr = 0x91536F01;
+    n1.sin_port = 1;
+    n2.sin_addr.s_addr = 0x92536F02;
+    n2.sin_port = 2;
+
+    hintCacheNodelistInit();
+    hintCachePlax_Init(8);
+
+    assert(neighborsOutgoing == NULL);
+    neighborsOutgoing = (HintCacheNet *) xmalloc(sizeof(HintCacheNet));
+    assert(neighborsOutgoing);
+    hintCacheNet_Init(neighborsOutgoing);
+    hintCacheNet_SetTestMode(neighborsOutgoing);
+
+
+    /*
+     * How to test if this really works? For now look at how many
+     * outgoing messages were enqueued.
+     */
+    hintCacheNodelistLocalJoin();
+    hintCacheNodelistLocalLeave();
+    assert(hintCacheNet_GetTestCount(neighborsOutgoing) == 2);
+
+    /*
+     * Expected final state:
+     * n0 JOIN dist = 12
+     * n1 LEAVE XXX
+     * n2 JOIN dist=20
+     */
+    hintCacheNodelistNetJoin(&n0, 10, 42);
+    hintCacheNodelistNetJoin(&n2, 20, 42);
+    hintCacheNodelistNetJoin(&n0, 13, 43);
+    hintCacheNodelistNetJoin(&n1, 20, 42);
+    hintCacheNodelistNetJoin(&n2, 20, 100);
+    hintCacheNodelistNetJoin(&n0, 9, 42);
+    hintCacheNodelistNetJoin(&n0, 12, 43);
+    hintCacheNodelistNetJoin(&n2, 20, 42);
+    hintCacheNodelistNetLeave(&n1, 999, 43);
+    hintCacheNodelistNetJoin(&n1, 19, 42);
+
+    for (hintCacheNodeListIterStart(&iter);
+	hintCacheNodeListIterCheck(iter); hintCacheNodeList_IterNext(&iter)) {
+	valid = hintCacheNodeListIterGetAddr(iter, &nodeAddr);
+	if (valid) {
+	    nhops = netdbHintHops(nodeAddr.sin_addr);
+	    if (nodeAddr.sin_addr.s_addr == n0.sin_addr.s_addr) {
+		found++;
+		assert(nhops == 12);
+	    }
+	    if (nodeAddr.sin_addr.s_addr == n2.sin_addr.s_addr) {
+		found++;
+		assert(nhops = 20);
+	    }
+	    if (nodeAddr.sin_addr.s_addr == n1.sin_addr.s_addr) {
+		assert(0);
+	    }
+	}
+    }
+    assert(found == 2);
+
+    hintCacheNodelistDestroy();
+    hintCachePlaxDestroy();
+
+    hintCacheNetDestroy(neighborsOutgoing);
+    free(neighborsOutgoing);
+    neighborsOutgoing = NULL;
+
+    printf("..OK\n");
+
+}
+
+#endif /* DOTEST */
Index: squid/src/HintCachePrim.c
diff -u /dev/null squid/src/HintCachePrim.c:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:38 2004
+++ squid/src/HintCachePrim.c	Mon May 20 19:46:42 2002
@@ -0,0 +1,404 @@
+/*
+ * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * DEBUG: section 89    List of known caches.
+ * AUTHOR: Mike Dahlin, UT Austin, 1998
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ *------------------------------------------------------------------
+ * LESS Group 
+ * Computer Sciences Department 
+ * University of Texas at Austin
+ *
+ * HCPrimitives.h --- Primitive types for hint cache.
+ *------------------------------------------------------------------
+ */
+#include "squid.h"
+#include <assert.h>
+
+
+const URLKey INVALID_URL_KEY = { 0 };
+
+static HintCacheKey calculateStupidKey(char *url);
+static void makeLowerCase(char *url);
+
+const static int useMD5 = 1;
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * URLKey --
+ *
+ *          The first 64 bits of the 128-bit Squid/Cache Digest URL key.
+ */
+
+
+
+/*
+ * Make lower case, but stop at third '/' (e.g., after the hostname).
+ */
+static void
+makeLowerCase(char *url)
+{
+    int len, ii;
+    int slashCount = 0;
+
+    assert(url);
+    len = strlen(url);
+    for (ii = 0; ii < len; ii++) {
+	/*
+	 * Alignment.
+	 */
+	if (url[ii] == '/') {
+	    slashCount++;
+	    if (slashCount == 3) {
+		return;
+	    }
+	}
+	url[ii] = tolower(url[ii]);
+    }
+}
+
+
+/* functional encapsulation of the ever-popular macro of the
+   same name.  Needed for hash table. */
+int 
+hintCacheURLKeyCompare(URLKey *u1, URLKey *u2)
+{
+    return(URLKEY_COMPARE(*u1, *u2));
+}
+
+/*
+ * Retrieve entry using hint_table.
+ * The hint_table keeps a pointer to the hchash part of th
+ * StoreEntry, so we apply the appropriate offset to
+ * retrieve the StoreEntry itself.
+ */
+StoreEntry *
+hintCacheStoreGet(URLKey urlkey)
+{
+    hash_link *hchash;
+    StoreEntry *entry;
+    int hchoff;
+    
+    hchash = (hash_link *) hash_lookup(store_table, &urlkey);
+    hchoff = (u_char *) &entry->hchash - (u_char *) entry;
+    entry = (StoreEntry *) ((u_char *) hchash - hchoff);
+    return(entry);
+}
+
+
+void
+hintCacheNetURLKeyNetInit(URLKeyNet * mungedKey, URLKey * key)
+{
+    mungedKey->mungedKey = hintCacheEndian_llMachineToNet(key->key);
+}
+
+void
+hintCacheNetURLKeyLocalFormat(URLKeyNet * mungedKey, URLKey * key)
+{
+    key->key = hintCacheEndian_llNetToMachine(mungedKey->mungedKey);
+}
+
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * NodeKey --
+ *
+ *          A <key, struct sockaddr_in> pair (plus stuff to
+ *          put it on a list.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.9.1998--------
+ */
+void
+hintCacheNodeKeyInit(NodeKey * k, const struct sockaddr_in *addrP)
+{
+    assert(k);
+    assert(addrP);
+
+    k->links.data = k;
+    k->links.next = k->links.prev = 0;
+    k->key = hintCacheNodeKeyKey(addrP);
+    k->addr = *addrP;
+}
+
+int
+hintCacheNodeKeyCompare(const NodeKey * k1, const NodeKey * k2)
+{
+    assert(k1);
+    assert(k2);
+    if (k1->key != k2->key) {
+	return 1;
+    }
+    return 0;
+}
+
+struct sockaddr_in
+hintCacheNodeKeyGetAddr(const NodeKey * k)
+{
+    assert(k);
+    return k->addr;
+}
+
+HintCacheKey
+hintCacheNodeKeyKey(const struct sockaddr_in * addrP)
+{
+    HintCacheKey k;
+    char *name;
+
+    name = inet_ntoa(addrP->sin_addr);
+    k = *(HintCacheKey *) storeKeyPublic(name, METHOD_PUT);
+    return k;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * hintCacheEntry --
+ *
+ *          A structure including a <URLKey, sockaddr_in> pair. Generally
+ *          points to the nearest copy of the specified url.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+void
+hintCacheEntryInit(HintCacheEntry * entry, URLKey key, struct sockaddr_in *saddr,
+    unsigned int mtime)
+{
+    entry->key = key;
+    entry->ipaddr = saddr->sin_addr;
+    entry->port = saddr->sin_port;
+    entry->pad = 0;
+    entry->mtime = mtime;
+}
+
+int
+hintCacheEntryCompare(HintCacheEntry * e1, HintCacheEntry * e2)
+{
+    /* 
+     * If you add a field, you must change this code.
+     */
+    if (URLKEY_COMPARE(e1->key, e2->key)) {
+	return 1;
+    }
+
+    if (e1->ipaddr.s_addr != e2->ipaddr.s_addr)
+	return 1;
+
+    if (e1->port != e2->port)
+	return 1;
+
+    if (e1->mtime != e2->mtime)
+	return 1;
+
+    return 0;
+}
+
+void
+hintCacheNetEntryInit(HintCacheEntryNet * mungedEntry, HintCacheEntry * entry)
+{
+    /* 
+     * If you add a field, you must change this code.
+     */
+    URLKeyNetInit(&mungedEntry->mungedKey, &entry->key);
+/*  mungedEntry->mungedIpaddr.s_addr  = htonl(entry->ipaddr.s_addr);*/
+    mungedEntry->mungedIpaddr.s_addr = entry->ipaddr.s_addr;
+    mungedEntry->mungedPort = htons(entry->port);
+    mungedEntry->mungedMtime = htonl(entry->mtime);
+}
+
+void
+hintCacheEntryLocalFormatNet(HintCacheEntryNet * mungedEntry, HintCacheEntry * entry)
+{
+    /* 
+     * If you add a field, you must change this code.
+     */
+    URLKeyLocalFormatNet(&mungedEntry->mungedKey, &entry->key);
+/*  entry->ipaddr.s_addr = ntohl(mungedEntry->mungedIpaddr.s_addr);*/
+    entry->ipaddr.s_addr = mungedEntry->mungedIpaddr.s_addr;
+    entry->port = ntohs(mungedEntry->mungedPort);
+    entry->mtime = htonl(mungedEntry->mungedMtime);
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * HCUpdate --
+ *
+ *          An update is a HintCacheEntry and an action.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+void
+hintCacheUpdateInit(HintCacheUpdate * u, int action, HintCacheEntry * entry, int hopcount)
+{
+    u->action = action;
+    u->hopcount = hopcount;
+    u->UNUSED = 0;		/* remove this field sometime */
+    u->entry = *entry;
+}
+
+void
+hintCacheUpdateSelfTest()
+{
+    HintCacheUpdate update;
+    HintCacheUpdateNet netupd;
+
+    /* HintCacheUpdate must be at least this min size */
+    assert(sizeof(HintCacheUpdate) >= HCU_MINLEN);
+
+    /* Test that some field in update has expected offset */
+    assert((char *) &update.entry - (char *) &update == 8);
+    assert((char *) &netupd.mungedEntry - (char *) &netupd == 8);
+
+    /* Make sure net version of struct stays in sync. */
+    assert(sizeof(HintCacheUpdate) == sizeof(HintCacheUpdateNet));
+}
+
+void
+hintCacheUpdateInitNet(HintCacheUpdateNet * mupdate, HintCacheUpdate * update)
+{
+    /* No need for htonl on action, hopcount, or len - they are single bytes. */
+    mupdate->mungedAction = update->action;
+    mupdate->mungedUNUSED = update->UNUSED;	/* remove this field sometime */
+    mupdate->mungedHopcount = update->hopcount;
+    mupdate->mungedPad1 = -1;
+    mupdate->mungedPad2 = -1;
+/*     mupdate->mungedCchange  = htonl(update->cchange); XXX - NOTYET */
+
+    hintCacheEntryInitNet(&mupdate->mungedEntry, &update->entry);
+}
+
+
+void
+hintCacheUpdateLocalFormatNet(HintCacheUpdateNet * mupdate, HintCacheUpdate * update)
+{
+    /* No need for htonl on action or len - they are single bytes. */
+    update->action = mupdate->mungedAction;
+    update->UNUSED = mupdate->mungedUNUSED;;
+    update->hopcount = mupdate->mungedHopcount;
+/*     update->cchange  = ntohl(mupdate->mungedCchange); XXX - NOTYET */
+
+    hintCacheEntryLocalFormatNet(&mupdate->mungedEntry, &update->entry);
+}
+
+int
+hintCacheUpdateCompare(HintCacheUpdate * u1, HintCacheUpdate * u2)
+{
+    if ((u1->action != u2->action)
+	|| (u1->hopcount != u2->hopcount)
+	|| (hintCacheEntry_Compare(&u1->entry, &u2->entry))) {
+	return 1;
+    }
+    return 0;
+}
+
+#ifdef DOTEST
+/*
+ *------------------------------------------------------------------
+ *
+ * primitivesSelfTest --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+void
+primitivesSelfTest()
+{
+
+    URLKey urlKey, urlKey2;
+    URLKeyNet netUrlKey;
+    char url[128];
+    HintCachEntry hcEntry, hcEntry2;
+    HintCacheEntry netHintCacheEntry;
+    HintCacheUpdate hcUpdate, hcUpdate2;
+    HintCacheUpdateNet netHintCacheUpdate;
+    struct sockaddr_in saddr = { AF_INET, 0, {{{0, 0, 0, 0}}} };
+
+    printf("primitivesSelfTest()..");
+
+    sprintf(url, "http://www.cs.Utexas.edu");
+    hintCacheURLKey_Init(&urlKey, url);
+    Net_URLKey_Init(&netUrlKey, &urlKey);
+    URLKeyLocalFormatNet(&netUrlKey, &urlKey2);
+    assert(!URLKEY_COMPARE(urlKey, urlKey2));
+
+    hintCacheEntryInit(&hcEntry, urlKey, &saddr);
+    hintCacheEntryInitNet(&netHintCacheEntry, &hcEntry);
+    hintCacheEntryLocalFormatNet(&netHintCacheEntry, &hcEntry2);
+    assert(!hintCacheEntryCompare(&hcEntry, &hcEntry2));
+
+    hintCacheUpdateInit(&hcUpdate, HC_InvalToChild, &hcEntry, 1);
+    hintCacheUpdate_selfTest();
+    hintCacheUpdateInitNet(&netHintCacheUpdate, &hcUpdate);
+    hintCacheUpdateLocalFormatNet(&netHintCacheUpdate, &hcUpdate2);
+    assert(!HintCacheUpdate_Compare(&hcUpdate, &hcUpdate2));
+
+    printf(".OK\n");
+}
+#endif /* DOTEST */
Index: squid/src/Makefile.am
diff -u squid/src/Makefile.am:1.24 squid/src/Makefile.am:1.8.2.5
--- squid/src/Makefile.am:1.24	Sun Sep  1 09:30:40 2002
+++ squid/src/Makefile.am	Tue Sep  3 10:41:32 2002
@@ -52,6 +52,32 @@
 SSLSOURCE = 
 endif
 
+if ENABLE_HINTS
+HINTSOURCE = \
+	HintCache.c \
+	HintCacheDisk.c \
+	HintCacheEndian.c \
+	HintCacheHier.c \
+	HintCacheNet.c \
+	HintCacheNodes.c \
+	HintCachePrim.c \
+	HintCacheProp.c
+else
+HINTSOURCE=
+endif
+
+if ENABLE_PLAXTON
+PLAXSOURCE = Plaxton.c
+else
+PLAXSOURCE =
+endif
+
+if ENABLE_ICP_DATA
+ICPDATASOURCE = icp_data.c
+else
+ICPDATASOURCE =
+endif
+
 if ENABLE_WIN32SPECIFIC
 WIN32SOURCE = win32.c
 else
@@ -74,6 +100,7 @@
 	squid
 
 bin_PROGRAMS = \
+	webpush \
 	squidclient
 
 libexec_PROGRAMS = \
@@ -122,6 +149,7 @@
 	defines.h \
 	$(DELAY_POOL_SOURCE) \
 	disk.c \
+        dist.c \
 	$(DNSSOURCE) \
 	enums.h \
 	errorpage.c \
@@ -136,6 +164,7 @@
 	globals.h \
 	gopher.c \
 	helper.c \
+	$(HINTSOURCE) \
 	$(HTCPSOURCE) \
 	http.c \
 	HttpStatusLine.c \
@@ -151,6 +180,7 @@
 	icmp.c \
 	icp_v2.c \
 	icp_v3.c \
+	$(ICPDATASOURCE) \
 	ident.c \
 	internal.c \
 	ipc.c \
@@ -168,7 +198,9 @@
 	pconn.c \
 	peer_digest.c \
 	peer_select.c \
+	$(PLAXSOURCE) \
 	protos.h \
+	put.c \
 	redirect.c \
 	referer.c \
 	refresh.c \
@@ -283,6 +315,7 @@
 DEFAULT_ICON_DIR	= $(datadir)/icons
 DEFAULT_ERROR_DIR	= $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@
 DEFAULT_MIB_PATH	= $(datadir)/mib.txt
+DEFAULT_HINT_FILE       = $(DEFAULT_SWAP_DIR)/hints
 DEFAULT_HOSTS		= @OPT_DEFAULT_HOSTS@
 
 DEFS = @DEFS@ -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
@@ -333,6 +366,7 @@
 	s%@DEFAULT_ICON_DIR@%$(DEFAULT_ICON_DIR)%g;\
 	s%@DEFAULT_MIB_PATH@%$(DEFAULT_MIB_PATH)%g;\
 	s%@DEFAULT_ERROR_DIR@%$(DEFAULT_ERROR_DIR)%g;\
+	s%@DEFAULT_HINT_FILE@%$(DEFAULT_HINT_FILE)%g;\
 	s%@DEFAULT_PREFIX@%$(DEFAULT_PREFIX)%g;\
 	s%@DEFAULT_HOSTS@%$(DEFAULT_HOSTS)%g;"\
 	< $(srcdir)/cf.data.pre >$@
Index: squid/src/Plaxton.c
diff -u /dev/null squid/src/Plaxton.c:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:38 2004
+++ squid/src/Plaxton.c	Mon May 20 19:46:42 2002
@@ -0,0 +1,2440 @@
+/*
+ * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * DEBUG: section 91    Greg Plaxton's per-object hierarchy.
+ * AUTHOR: Mike Dahlin, UT Austin, 1998
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ *------------------------------------------------------------------
+ * LESS Group 
+ * Computer Sciences Department 
+ * University of Texas at Austin
+ *
+ * Plaxton.c --- Dynamic algorithm via plaxton's algorithm.
+ *------------------------------------------------------------------
+ */
+
+/*
+ * Plaxton.c interface notes, from Mike Dahlin's comments in HCPlax.h:
+ *
+ * Each children queue holds messages that should go to a set of
+ * "equivalent" children  (eg. the children at some level of the
+ * hierarchy.)  There are HCHPlax_NChildrenQs() such queues;
+ * num = HCPlax_GetChildAddrs(q, arraypointer) allocates
+ * an array of addresses for a particular queue and returns
+ * the number of children.
+ * The rule is simple -- when I send a message to children about
+ * an object, I send it to all children who match that object's
+ * key in fewer bits than I do.
+ *
+ * Each parent queue holds messages that should go to one parent.
+ * In general, we may have different parents for different objects.
+ * So, enqueue messages for an object in the queue
+ * HCPlax_ParentQIndex(URLKey).
+ *
+ * We also need to help figure out the hierarchy for Plaxton's
+ * algorithm. Plaxton's algorithm figures out who the parents
+ * are, but it doesn't know who the children are. We observe
+ * messages to keep in sync. 
+ * On recv message:
+ *	recv parent msg from parent: process parent message
+ *	recv child msg from child: process child message
+ *	recv parent msg from !parent: send "I am not child" to parent;
+ *			drop message
+ *	recv child msg from !child: add child to child list;
+ *				process child message
+ *	recv "I am not child" from child: remove child
+ */
+
+#include "squid.h"
+
+
+#define HCPLAX_DEBUG 91
+
+/*
+ * Array [BITS_PER_BYTE * sizeof(HintCacheNodeKeyKey) + 1]  of dlink_nodes
+ */
+#define BITS_PER_BYTE 8
+#define BITS_PER_KEY (8 * sizeof(HintCacheKey))
+
+static HintCacheKey myNodeKey;
+
+static int initialized = 0;
+
+/*
+ * For keeping track of children
+ */
+static int nChildLists = -9999;
+static dlink_list *childrenListA;
+static int *childrenCountA = NULL;	/* Entry i is the number of children
+					 * that match in i bits.  */
+static int childrenCountTot = 0;
+
+/*
+ * For keeping track of parents
+ */
+int Plaxton_bucketsPerLevel = -999;
+static int nParentLevels = -999;
+static int bitsPerLevel = -999;
+static int maxParentBucket = -9999;
+/* 
+ * parentListA is an array [nParentLevels][Plaxton_bucketsPerLevel] 
+ * where entry k = l*bitsPerLevel + i (0 <= i < 2^bitsPerLevel)
+ * contains a list of all known nodes whose node key matches
+ * the local node key in the lowest l*bitsPerLevel bits
+ * and whose next bitsPerLevel bits have the same bit pattern
+ * as i
+ * For example, with bitsPerLevel = 2, if our local node key
+ * were 010110, a node with key 111010 would belong in level 1
+ * (since the bottom two bits match us but the next two bits dont
+ * in entry 10), so node 111010 would go into bucket 
+ * 1*Plaxton_bucketsPerLevel + 10 = 4 + 2 = 6.
+ * Maintain the invariant that the entries in each bucket are sorted
+ * by their distance from me with the closest node always
+ * at the head of its list.
+ */
+static dlink_list *parentListA = NULL;
+/*
+ * Special case of parent finding when I match in as many bits
+ * as anyone. In case of a tie for root, 
+ * we all need to agree on whom among us is the root. We need
+ * to do so in a way that avoids loops (and hopefully which
+ * gets everyone to agree on the same root.) Solution: if
+ * an object matches me in k bits and I know of no node
+ * that matches the object in more than k bits, choose as
+ * the root for that object, the node that matches the
+ * object (and me) in k bits and which has the highest
+ * known NodeKey.
+ *
+ * highestMatchA is an array [BITS_PER_KEY] where entry k
+ * contains a list of all nodes that match me in at least 
+ * the bottom k bits. The lists all include me. The lists
+ * are sorted by the integer value of the key with the
+ * largest value at the head of the list.
+ */
+static dlink_list *highestMatchA = NULL;
+
+static int normalParentIndex(int bucket);
+static int fullMatchIndex(HintCacheKey k);
+static int firstLevelBucketForMatch(int matchBits);
+static int highestMatchIndex(int matchBits);
+static void childAdd _PARAMS((HintCacheNodeKey * key));
+static HintCacheNodeKey *childFind _PARAMS((HintCacheNodeKey * key));
+static void freeList(dlink_list * list);
+static void addNodeParentList(struct sockaddr_in *addNode);
+static void removeNodeParentList(struct sockaddr_in *goneNode);
+static void changeDistanceParentList(struct sockaddr_in *changeDistNode);
+static int parentListIndex(HintCacheNodeKey * n);
+static void addNodeHighestMatch(struct sockaddr_in *addNode);
+static void matchInsert(dlink_list *l, struct sockaddr_in *a);
+static void removeNodeHighestMatch(struct sockaddr_in *goneNode);
+static void matchRemove(dlink_list *l, struct sockaddr_in *a);
+static int scanForParentMatch(int maxTry, int minTry, const URLKey * key,
+    int *parentIndexRet, int *amIRootRet);
+static HintCacheKey makeMatchKey(const URLKey * key, int matchBits,
+    int permuteVal);
+
+#ifdef DOTEST
+static void selfTestChildren();
+static int selfTestFindAddr(int addr, struct sockaddr_in *childrenA,
+    int childCount);
+static void selfTestParents();
+static void testParentsBinaryTree(void);
+static void testParentsMultiRootCase(void);
+static void stressTestParents(void);
+static void testParentsInternals(void);
+static void testParentsInternals2(void);
+static void testMakeMatchKey(void);
+#endif /* DOTEST */
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonInit --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------4.15.1998-----------
+ */
+void
+plaxtonInit(int bitsPerLevel_)
+{
+    int ii;
+    int nParentBuckets;
+    struct sockaddr_in *me = &Config.Sockaddr.http->s;
+    HintCacheNodeKey *key;
+
+    assert(nChildLists < 0);	/* We shouldn't be initialized yet */
+
+    assert(!initialized);
+    initialized = 1;
+
+    myNodeKey = NodeKK_Key(me);
+    /*
+     * List i contains all children that match me in i bits.
+     * Legal values for i are [0, BITS_PER_KEY]
+     */
+    nChildLists = BITS_PER_KEY + 1;
+    assert(childrenListA == NULL);
+    childrenListA = (dlink_list *) xcalloc(nChildLists, sizeof(dlink_list));
+    assert(childrenListA);
+    childrenCountA = (int *) xcalloc(nChildLists, sizeof(int));
+    childrenCountTot = 0;
+
+    /*
+     * Parents
+     */
+    bitsPerLevel = bitsPerLevel_;
+    nParentLevels = (BITS_PER_KEY) / bitsPerLevel;
+    if ((BITS_PER_KEY) % bitsPerLevel != 0) {
+	nParentLevels++;
+    }
+    Plaxton_bucketsPerLevel = 1;
+    for (ii = 0; ii < bitsPerLevel; ii++) {
+	Plaxton_bucketsPerLevel *= 2;
+    }
+    nParentBuckets = Plaxton_bucketsPerLevel * nParentLevels;
+    maxParentBucket = nParentBuckets - 1;
+    assert(parentListA == NULL);
+    parentListA = (dlink_list *) xcalloc(nParentBuckets, sizeof(dlink_list));
+    assert(parentListA);
+    assert(highestMatchA == NULL);
+    highestMatchA = (dlink_list *) xcalloc(BITS_PER_KEY, sizeof(dlink_list));
+    assert(highestMatchA);
+    for (ii = 0; ii < BITS_PER_KEY; ii++) {
+	key = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey));
+	hintCacheNodeKeyInit(key, &Config.Sockaddr.http->s);
+	dlinkAdd(key, &key->links, &highestMatchA[ii]);
+    }
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonDestroy --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.16.1998------
+ */
+void
+plaxtonDestroy(void)
+{
+    int ii;
+
+    assert(initialized);
+    initialized = 0;
+
+    assert(nChildLists > 0);	/* Are we initialized? */
+    for (ii = 0; ii < nChildLists; ii++) {
+	freeList(&childrenListA[ii]);
+    }
+    xfree(childrenListA);
+    childrenListA = NULL;
+    xfree(childrenCountA);
+    childrenCountA = NULL;
+    childrenCountTot = -999999;
+    nChildLists = -88888;
+
+    /*
+     * Parents
+     */
+    for (ii = 0; ii < nParentLevels * Plaxton_bucketsPerLevel; ii++) {
+	freeList(&parentListA[ii]);
+    }
+    xfree(parentListA);
+    parentListA = NULL;
+    nParentLevels = -8888;
+    bitsPerLevel = -8888;
+    Plaxton_bucketsPerLevel = -8888;
+    for (ii = 0; ii < BITS_PER_KEY; ii++) {
+	freeList(&highestMatchA[ii]);
+    }
+    xfree(highestMatchA);
+    highestMatchA = NULL;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * freeList --
+ *
+ *          Free all elements on a list of HintCacheNodeKeys
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.16.1998--------
+ */
+static void
+freeList(dlink_list *list)
+{
+    dlink_node *node;
+    HintCacheNodeKey *k;
+
+    assert(list);
+    for (node = list->head ; node; node = node->next) {
+	k = node->data;
+	dlinkDelete(node, list);
+	xfree(k);
+    }
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonAddChild --
+ *
+ *          Add the specified child to the list of children.
+ *          We keep a separate list of children for each
+ *          number of bits that can match the local addrss key.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.9.1998---------
+ */
+void
+plaxtonAddChild(struct sockaddr_in *child)
+{
+    HintCacheNodeKey *key;
+
+    assert(initialized);
+    assert(nChildLists > 0);	/* Are we initialized? */
+    key = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey));
+    hintCacheNodeKeyInit(key, child);
+    if (childFind(key)) {
+	xfree(key);
+	return;
+    }
+    childAdd(key);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonRemoveChild --
+ *
+ *          Remove the specified child from its list of children.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------4.9.1998-----
+ */
+void
+plaxtonRemoveChild(struct sockaddr_in *child)
+{
+    HintCacheNodeKey key, *found;
+    int match;
+
+    assert(initialized);
+    assert(nChildLists > 0);	/* Are we initialized? */
+    hintCacheNodeKeyInit(&key, child);
+    found = childFind(&key);
+    if (found) {
+	dlinkDelete(&found->links, 
+	List_Remove((dlink_node *) found);
+	xfree(found);
+	match = plaxtonMatchBits(key.key, myNodeKey);
+	childrenCountA[match]--;
+	childrenCountTot--;
+	assert(childrenCountA[match] >= 0);
+	assert(childrenCountTot >= 0);
+	return;
+    }
+    return;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonCheckIfChild --
+ *
+ *          Return nonzero if the specified node is listed
+ *          as a child.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.9.1998------
+ */
+int
+plaxtonCheckIfChild(struct sockaddr_in *child)
+{
+    HintCacheNodeKey key, *found;
+
+    assert(initialized);
+    assert(nChildLists > 0);	/* Are we initialized? */
+    hintCacheNodeKeyInit(&key, child);
+    found = childFind(&key);
+    if (found != NULL) {
+	return 1;
+    }
+    return 0;
+}
+
+
+
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonChildQIndex --
+ *
+ *          Return the queue for which messages about the specified
+ *          object should be stored.
+ *
+ *          The rule is simple -- when I send a message to children about
+ *          an object, I send it to all children who match that object's
+ *          key in fewer bits than I do. (Unless I am the root
+ *          for that object, in which case I send info to all 
+ *          nodes that think of me as a parent.)
+ *
+ *          So, store messages for an object that matches me in i bits
+ *          in queue i. Later, we will send it to all children
+ *          that match me in i or fewer bits. (Store messages
+ *          for objects for which I am root in queue nChildLists-1).
+ *
+ *          As an optimization, if I have no children that match
+ *          me in i or fewer bits, set *amILeaf to nozero. In that
+ *          case, the caller may choose not to enqueue any message.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------5.1.1998------
+ */
+int
+plaxtonChildQIndex(URLKey * key, int iAmRoot, int *amILeaf)
+{
+    int match;
+    int leafCheck;
+
+    assert(initialized);
+    assert(nChildLists > 0);	/* Are we initialized? */
+
+
+    if (iAmRoot) {
+	if ( /*childrenCountTot > 0 */ 1) {	/* XXX */
+	    *amILeaf = 0;
+	    return nChildLists - 1;
+	} else {
+	    *amILeaf = 1;
+	    return -999;
+	}
+    }
+
+    match = plaxtonMatchBits(key->key, myNodeKey);
+    /*
+     * Check to see if I am a leaf for this object by looking
+     * at all childlists for children that match me in fewer bits 
+     * than this object. If all such lists are empty, than I am 
+     * a leaf. This is less inefficient than it seems. The expected
+     * number of queues I have to check is less than (1 + .5 + .25 + ...)
+     * (since I match in 0 bits half the time, ... )
+     */
+    *amILeaf = 1;
+    for (leafCheck = match - 1; leafCheck >= 0; leafCheck--) {
+	if (!List_IsEmpty(&childrenListA[leafCheck])) {
+	    *amILeaf = 0;
+	    break;
+	}
+    }
+    return match;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonNChildrenQs --
+ *
+ *          Return the number of queues of messages for children
+ *          caller should allocate.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------------4.10.1998---
+ */
+int
+plaxtonNChildrenQs(void)
+{
+    assert(initialized);
+    assert(nChildLists > 0);	/* Are we initialized? */
+    return nChildLists;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonGetChildAddrs --
+ *
+ *        Return the number of children for the specified message
+ *        queue, allocate a buffer for that many addresses,
+ *        and fill in that buffer with the children's addresses.
+ *
+ *        Notice -- the question being asked is "to whom should
+ *        I send messages for objects that match me in k bits?"
+ *        The answer is all nodes that match in k *or fewer* bits.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Allocates a vector for the addresses. Caller must free
+ *      this vector when done.
+ *
+ *      Note: the vector may be out of date by the time ther caller
+ *      uses it. This is inherent problem -- even if caller sent
+ *      all messages instantaneously, by the time they arrive
+ *      at destination, the child could have left the system
+ *      or a new child could have joined.
+ *
+ *----------------------------------------------------4.10.1998-------
+ */
+int
+plaxtonGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP)
+{
+    dlink_node *node;
+    int count;
+    int imatch;
+    HintCacheNodeKey *current;
+    int check;
+
+    assert(initialized);
+    for (imatch = 0, count = 0; imatch <= qIndex; imatch++) {
+	count += childrenCountA[imatch];
+    }
+    if (!count) {
+	*retAddrAP = NULL;
+	return 0;
+    }
+    *retAddrAP =
+	(struct sockaddr_in *) xmalloc(count * sizeof(struct sockaddr_in));
+    for (imatch = 0, count = 0; imatch <= qIndex; imatch++) {
+	check = 0;
+	for (node = childrenListA[imatch].head; node; node = node->next) {
+	    current = node->data;
+	    check++;
+	    (*retAddrAP)[count] = hintCacheNodeKeyGetAddr(current);
+	    count++;
+	    debug(HCPLAX_DEBUG, 2)
+		("plaxtonGetChildAddrs: sending msg to child %s\n",
+		inet_ntoa((*retAddrAP)[count].sin_addr));
+	}
+	assert(check == childrenCountA[imatch]);
+    }
+    return count;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * nParentQs --
+ *
+ *          Return the number of parent q's to allocate.
+ *          We need to account for both the normal case
+ *          when we find a parent that matches an object
+ *          in more bits than we do, and the root
+ *          case when we match in k bits and so do some
+ *          other nodes, but no one matches in more than
+ *          k bits; in that case, we may not send
+ *          to the closest node that matches us in k bits.
+ *        
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.15.1998-------
+ */
+int
+plaxtonNParentQs(void)
+{
+    int normalParentCount, rootCaseCount;
+
+    assert(initialized);
+    assert(parentListA != NULL);
+    normalParentCount = nParentLevels * Plaxton_bucketsPerLevel;
+    rootCaseCount = BITS_PER_KEY;
+    return normalParentCount + rootCaseCount;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonParentQIndex --
+ *
+ *          Return the index of the parent queue to use
+ *          for messages about the specified URLKey or
+ *          set amIRoot to true if I have no parent
+ *          for that object.
+ *
+ *          I am trying to find someone who matches
+ *          the object in more bits than I do. To 
+ *          reduce the number of levels of hierarchy
+ *          I try to match bitsPerLevel bits at a
+ *          time. 
+ *
+ *          If I match in at least l*bitsPerLevel bits but
+ *          not in (l+1)*bitsPerLevel bits, then
+ *          the parent is the node that matches in 
+ *          the most bits between (l+1)*bPL and (l)*bPL
+ *
+ *          If there are multiple potential parents
+ *          that match in the same number of bits, choose
+ *          the closest one (all parent lists are maintained
+ *          in sorted order) unless I also match the
+ *          object in that many bits; in the latter case
+ *          we need to decide on a root from among
+ *          several equally qualified candidates. We
+ *          always choose the node with the highest
+ *          NodeKey in that case.
+ *
+ *          Note the key invariant for avoiding loops:
+ *          my parent always matches an object in more
+ *          bits than I do or matches in as many bits
+ *          as I do and has a higher ID.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.19.1998---------
+ */
+int
+plaxtonParentQIndex(URLKey * key, int *amIRoot)
+{
+    int match;
+    int nextLevelMatch;
+    int found, pindex;
+
+    assert(initialized);
+    /* XXX */
+    match = plaxtonMatchBits(key->key, myNodeKey);
+    if (match == nParentLevels * bitsPerLevel) {
+	/*
+	 * Match all bits. I am root!
+	 */
+	*amIRoot = 1;
+	return -9999999;
+    }
+
+    /* 
+     * Try for full or partial match at next level.
+     */
+    nextLevelMatch = ((match + bitsPerLevel) / bitsPerLevel) * bitsPerLevel;
+    found = scanForParentMatch(nextLevelMatch, match + 1, key,
+	&pindex, amIRoot);
+    if (found) {
+	assert(!*amIRoot);
+	return normalParentIndex(pindex);
+    }
+
+
+    /*
+     * I match in match bits, and didn't find anyone that matches
+     * in more. But, there may be other nodes that match the object 
+     * in the same number of bits (but differ from me in some higher bit). 
+     * We all need to agree on whom among us is the root. We need
+     * to do so in a way that avoids loops (and hopefully which
+     * gets everyone to agree on the same root.) Solution: if
+     * an object matches me in k bits and I know of no node
+     * that matches the object in more than k bits, choose as
+     * the root for that object, the node that matches the
+     * object (and me) in k bits and which has the highest
+     * known HintCacheNodeKey.
+     */
+    assert(!List_IsEmpty(&highestMatchA[match]));
+    if (((HintCacheNodeKey *) List_First(&highestMatchA[match]))->key == myNodeKey) {
+	*amIRoot = 1;
+	return -999999;
+    } else {
+	*amIRoot = 0;
+	return highestMatchIndex(match);
+    }
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * scanForParentMatch --
+ *
+ *          Find the bucket index in parentsListA for
+ *          a node matching between maxTry and minTry
+ *          bits (inclusive) for the specified key.
+ *          Return true if parent found and set 
+ *          parentIndexRet and amIRootRet.
+ *
+ *          As we look at fewer and fewer bits we
+ *          need to try all combinations of the
+ *          high-order bits we are masking off. 
+ *          We currently do this by probing different
+ *          entries in the table. It would be more
+ *          efficient to maintain auxiliary data
+ *          structures with all eligible nodes,
+ *          but the data structures here are already
+ *          more complicated than I like; Make it 
+ *          work first, then optimize performance later.
+ *
+ *          Return the node that matches in the most
+ *          possible bits. If more than one node
+ *          matches in a specific # of bits, return the
+ *          closest.
+ *
+ * Arguments:
+ *      None.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+static int
+scanForParentMatch(int maxTry, int minTry, const URLKey * key,
+    int *parentIndexRet, int *amIRootRet)
+{
+    HintCacheNodeKey *nk;
+    HintCacheKey tryKey;
+    int matchBits, permuteBits, permuteMax, ipermute;
+    int tryIndex;
+    int found = 0, bestIndex = -999999;
+    struct sockaddr_in bestSin, trySin;
+
+    /*
+     * This code assumes that we are looking to match
+     * a "level" in the tree.
+     */
+    assert(maxTry % bitsPerLevel == 0);
+    assert(maxTry - minTry < bitsPerLevel);
+
+    for (matchBits = maxTry; matchBits >= minTry; matchBits--) {
+	/*
+	 * Split the address into two parts, a set of low-order bits
+	 * that must match the target and a set of high-order
+	 * bits that are "don't care" for which we'll try all
+	 * permutations.
+	 */
+	permuteBits = maxTry - matchBits;
+	permuteMax = (1 << permuteBits) - 1;
+	for (ipermute = 0; ipermute <= permuteMax; ipermute++) {
+	    tryKey = makeMatchKey(key, matchBits, ipermute);
+	    tryIndex = fullMatchIndex(tryKey);
+	    if (parentListA[tryIndex].head != 0) {
+		/* parentListA[tryIndex] is not empty */
+		nk = parentListA[tryIndex].head->data;
+		if (!found) {
+		    found = 1;
+		    *amIRootRet = 0;
+		    bestSin = hintCacheNodeKeyGetAddr(nk);
+		    bestIndex = tryIndex;
+		} else {
+		    trySin = hintCacheNodeKeyGetAddr(nk);
+		    if (HCHier_compareDistanceFromMe(bestSin.sin_addr,
+			    trySin.sin_addr) > 0) {
+			bestSin = trySin;
+			bestIndex = tryIndex;
+			assert(*amIRootRet == 0);
+		    }
+		}
+	    }
+	}
+	if (found) {
+	    assert(*amIRootRet == 0);
+	    *parentIndexRet = bestIndex;
+	    return 1;
+	}
+    }				/* for matchBits */
+    assert(!found);
+    return 0;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * makeMatchKey --
+ *
+ *          Return a key that matches the specified key in the 
+ *          bottom <matchBits> bits, and add the prefix
+ *          permuteVal to the front. Remaining bits are all 0.
+ *          For example, if key is 110101101, matchBits is 4,
+ *          and permuteVal is 3 (11), then return
+ *               000111101  (zero-fill: 000 prefix: 11 match: 1101).
+ *
+ * Arguments:
+ *      None.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+static HintCacheKey
+makeMatchKey(const URLKey * key, int matchBits, int permuteVal)
+{
+    HintCacheKey tryKey, matchMask;
+
+    matchMask = (((HintCacheKey) 1) << matchBits) - 1;
+    tryKey = (key->key & matchMask) | (permuteVal << matchBits);
+    return tryKey;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * highestMatchIndex --
+ *
+ *          Return the network buffer index that we should
+ *          use for messages to the root node for objects
+ *          that match us and some other node in <matchBits>
+ *          bits and match no node in more than <matchBits>
+ *          bits.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *--------------------------------------------------------4.15.1998-----
+ */
+static int
+highestMatchIndex(int match)
+{
+    return maxParentBucket + 1 + match;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * normalParentIndex --
+ *
+ *          Return the network buffer index that we should
+ *          use for parents that match in the specified bucket
+ *          (where bucket is calculated as matchLevel * 2^bitsPerLevel
+ *          + key%2^bitsPerLevel).
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------------4.15.1998----
+ */
+static int
+normalParentIndex(int bucket)
+{
+    assert(bucket <= maxParentBucket);
+    return bucket;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * firstLevelBucketForMatch --
+ *
+ *          Return the index of the first bucket for the set
+ *          of buckets for the first non-matching level for
+ *          a key that we match in matchBits.            
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.19.1998-------
+ */
+static int
+firstLevelBucketForMatch(int match)
+{
+    int level;
+
+    assert(match <= BITS_PER_KEY);
+    level = (match / bitsPerLevel) * Plaxton_bucketsPerLevel;
+    return level;
+}
+
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonGetParentAddr --
+ *
+ *          Return the address to whom to send messages
+ *          from the specified parent queue in *retAddr.
+ *          Return nonzero on error.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.16.1998--------
+ */
+int
+plaxtonGetParentAddr(int index, struct sockaddr_in *retAddr)
+{
+    assert(initialized);
+    assert(index >= 0);
+    assert(parentListA != NULL);
+    if (index <= maxParentBucket) {
+	if (!List_IsEmpty(&parentListA[index])) {
+	    *retAddr = ((HintCacheNodeKey *) List_First(&parentListA[index]))->addr;
+	    debug(HCPLAX_DEBUG, 2)
+		("plaxtonGetParentAddr: Sending msg to parent %s\n",
+		inet_ntoa(retAddr->sin_addr));
+	    return 0;
+	} else {
+	    return 1;
+	}
+    } else {
+	/* XXX    index = index - maxParentBucket; */
+	index = index - maxParentBucket - 1;
+	assert(index < BITS_PER_KEY);
+	assert(index >= 0);
+	/*
+	 * List always contains at least me
+	 */
+	assert(!List_IsEmpty(&highestMatchA[index]));
+	if (((HintCacheNodeKey *) List_First(&highestMatchA[index]))->key == myNodeKey) {
+	    return 1;
+	} else {
+	    *retAddr = ((HintCacheNodeKey *) List_First(&highestMatchA[index]))->addr;
+	    debug(HCPLAX_DEBUG, 2)
+		("plaxtonGetParentAddr: Sending msg to parent %s\n",
+		inet_ntoa(retAddr->sin_addr));
+	    return 0;
+	}
+    }
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * HCPLax_addNode --
+ *
+ *          Add a node to the lists of parents.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.16.1998--------
+ */
+void
+plaxtonAddNode(struct sockaddr_in *newNode)
+{
+    assert(initialized);
+    assert(newNode);
+#if 1				/* XXX! - disabling parent&child lists */
+    addNodeParentList(newNode);
+#endif
+    addNodeHighestMatch(newNode);
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonRemoveNode --
+ *
+ *          Remove thenode from the lists of parents.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.16.1998------
+ */
+void
+plaxtonRemoveNode(struct sockaddr_in *goneNode)
+{
+    assert(initialized);
+    assert(goneNode);
+    removeNodeParentList(goneNode);
+    removeNodeHighestMatch(goneNode);
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonChangeDistance --
+ *
+ *          Change the distance (and perhaps the rank in sorted list)
+ *          of the specified node.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.16.1998-------
+ */
+void
+plaxtonchangeDistance(struct sockaddr_in *changeDistNode)
+{
+    assert(initialized);
+    assert(changeDistNode);
+    changeDistanceParentList(changeDistNode);
+    /*
+     * Don't need to tell HighestMatch list since that one is
+     * not sorted by distance.
+     */
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * addNodeParentList --
+ *
+ *          See definition of parentListA where it is declared.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.16.1998-----
+ */
+static void
+addNodeParentList(struct sockaddr_in *addNode)
+{
+    HintCacheNodeKey *n;
+    int index;
+    HintCacheNodeKey *current;
+    struct sockaddr_in s1, s2;
+
+    n = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey));
+    assert(n);
+    hintCacheNodeKeyInit(n, addNode);
+
+    index = parentListIndex(n);
+
+
+    if (List_IsEmpty(&parentListA[index])) {
+	List_Insert((dlink_node *) n, LIST_ATFRONT(&parentListA[index]));
+	return;
+    } else {
+	LIST_FORALL2(&parentListA[index], HintCacheNodeKey *, current) {
+	    if (HCHier_compareDistanceFromMe(hintCacheNodeKeyGetAddr(current).sin_addr,
+		    addNode->sin_addr) > 0) {
+		List_Insert((dlink_node *) n, LIST_BEFORE(current));
+		return;
+	    }
+	    /*
+	     * Check invariant that list is sorted by distance from me.
+	     */
+	    if ((dlink_node *) current != LIST_ATREAR(&parentListA[index])) {
+		s1 = hintCacheNodeKeyGetAddr(current);
+		s2 = hintCacheNodeKeyGetAddr((HintCacheNodeKey *) List_Next((dlink_node *)
+			current));
+		assert(HCHier_compareDistanceFromMe(s1.sin_addr,
+			s2.sin_addr) <= 0);
+	    }
+	}
+    }
+    List_Insert((dlink_node *) n, LIST_ATREAR(&parentListA[index]));
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * removeNodeParentList --
+ *
+ *          Remove the specified node from the parentList
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.16.1998---------
+ */
+static void
+removeNodeParentList(struct sockaddr_in *goneNode)
+{
+    int index;
+    dlink_node *node;
+    HintCacheNodeKey n, *current;
+    struct sockaddr_in s1, s2;
+
+    hintCacheNodeKeyInit(&n, goneNode);
+
+    index = parentListIndex(&n);
+
+    for (node = parentListA[index]; node; node = node->next) {
+	current = node->data;
+	if (!hintCacheNodeKeyCompare(&n, current)) {
+	    dlinkDelete(node, &parentListA[index]);
+	    xfree(current);
+	    return;
+	}
+	/*
+	 * Check invariant that list is sorted by distance from me.
+	 */
+	if ((dlink_node *) current != LIST_ATREAR(&parentListA[index])) {
+	    s1 = hintCacheNodeKeyGetAddr(current);
+	    s2 = hintCacheNodeKeyGetAddr((HintCacheNodeKey *) List_Next((dlink_node *) current));
+	    assert(hintCacheHierCompareDistanceFromMe(s1.sin_addr, s2.sin_addr) <= 0);
+	}
+    }
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * changeDistanceParentList --
+ *
+ *          Since we need to keep this list sorted by distance
+ *          from me, we need to reorder it if the distance 
+ *          to some node changes.
+ *
+ *          Note: right now we do the simple thing -- remove
+ *          and add the node. Faster implementations are possible.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.16.1998--------
+ */
+static void
+changeDistanceParentList(struct sockaddr_in *changeDistNode)
+{
+    removeNodeParentList(changeDistNode);
+    addNodeParentList(changeDistNode);
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * parentListIndex --
+ *
+ *          Return the index of the parent list for the element
+ *          with the specified nodeKey.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.19.1998------
+ */
+static int
+parentListIndex(HintCacheNodeKey * n)
+{
+    return fullMatchIndex(n->key);
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * fullMatchIndex --
+ *
+ *          Return the highest legal index into the parent list 
+ *          for object/node with the specified key.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.19.1998------
+ */
+static int
+fullMatchIndex(HintCacheKey k)
+{
+    int bits, levelsThatMatch, indexInBucket, index;
+
+    bits = plaxtonMatchBits(k, myNodeKey);
+    if (bits == nParentLevels * bitsPerLevel) {
+	/* 
+	 * I am root! want to match in all bits in last level 
+	 * This will force system to get right indexInBucket in 
+	 * last level.
+	 */
+	bits--;
+    }
+    levelsThatMatch = bits / bitsPerLevel;
+    indexInBucket =
+	(k >> (levelsThatMatch * bitsPerLevel)) % Plaxton_bucketsPerLevel;
+    index = firstLevelBucketForMatch(bits) + indexInBucket;
+    return index;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * addNodeHighestMatch --
+ *
+ *          Add the specified node to all highestMatch lists k
+ *          for for which the node matches me in at least the
+ *          bottom k bits. Keep each list sorted by key with
+ *          the head of the list containing the highest key.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.16.1998------
+ */
+static void
+addNodeHighestMatch(struct sockaddr_in *addNode)
+{
+    HintCacheNodeKey n;
+    int match, imatch;
+
+    hintCacheNodeKeyInit(&n, addNode);
+
+    match = plaxtonMatchBits(n.key, myNodeKey);
+    if (match == BITS_PER_KEY) {
+	match--;
+    }
+    for (imatch = 0; imatch <= match; imatch++) {
+	matchInsert(&highestMatchA[imatch], addNode);
+    }
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * matchInsert --
+ *
+ *          Insert new node key onto list sorted by node key.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------------4.16.1998----
+ */
+static void
+matchInsert(dlink_list *l, struct sockaddr_in *a)
+{
+    HintCacheNodeKey *current, *n;
+    dlink_node *node;
+
+    n = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey));
+    assert(n);
+    hintCacheNodeKeyInit(n, a);
+
+    /*
+     * Each list always contains at least me.
+     */
+    assert(l->head != 0);
+
+    for (node = l->head; node; node = node->next) {
+	current = node->data;
+	assert(current->key != n->key);
+	if (current->key < n->key) {
+	    /* Put 'n' right before 'current' */
+	    n->next = current;
+	    n->prev = current->prev;
+	    current->prev = current;
+	    n->prev->next = n;
+	    return;
+	}
+    }
+    assert(((HintCacheNodeKey *) l->tail->data)->key >= n->key);
+    dlinkAddTail(n, &n->links, l);
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * removeNodeHighestMatch --
+ *
+ *          Remove node from all lists k where node's key
+ *          matches my key in at least k bits.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------4.16.1998----------
+ */
+static void
+removeNodeHighestMatch(struct sockaddr_in *goneNode)
+{
+    HintCacheNodeKey n;
+    int match, imatch;
+
+    hintCacheNodeKeyInit(&n, goneNode);
+
+    match = plaxtonMatchBits(n.key, myNodeKey);
+    if (match == BITS_PER_KEY) {
+	match--;
+    }
+    for (imatch = 0; imatch <= match; imatch++) {
+	matchRemove(&highestMatchA[imatch], goneNode);
+    }
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * matchRemove --
+ *
+ *          Remove specified element from list.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *--------------------------------------------------4.16.1998-----------
+ */
+static void
+matchRemove(dlink_llist *list, struct sockaddr_in *a)
+{
+    HintCacheNodeKey *current, n;
+    dlink_node *node;
+
+    hintCacheNodeKeyInit(&n, a);
+    /*
+     * Each list always contains at least me.
+     */
+    assert(list->head != 0);
+
+    for (node = list->head; node; node = node->next) {
+	current = node->data;
+	if (!hintCacheNodeKeyCompare(current, &n)) {
+	    dlinkDelete(node, list);
+	    xfree(current);
+	    return;
+	}
+    }
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonCheckIfParent --
+ *
+ *          Return true if the specified node is, in fact, our
+ *          current parent for objects with the specified URL.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+int
+plaxtonCheckIfParent(URLKey key, struct sockaddr_in *candidate)
+{
+    int index, amIRoot;
+    struct sockaddr_in real;
+
+    assert(initialized);
+    index = plaxtonParentQIndex(&key, &amIRoot);
+    if (amIRoot) {
+	return 0;
+    }
+    if (plaxtonGetParentAddr(index, &real)) {
+	return 0;
+    }
+    if (candidate->sin_addr.s_addr == real.sin_addr.s_addr) {
+	return 1;
+    }
+    return 0;
+}
+
+
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * childAdd --
+ *
+ *          Add a child record to the appropriate child list.
+ *          Does NOT check to see if child is already on list --
+ *          caller should already have done it.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------4.9.1998----------
+ */
+static void
+childAdd(HintCacheNodeKey * key)
+{
+    int l;
+
+    l = plaxtonMatchBits(key->key, myNodeKey);
+    assert(l <= nChildLists);
+    dlinkAdd(key, &key->links, childrenListA[l]);
+    childrenCountA[l]++;
+    childrenCountTot++;
+    assert(childFind(key));
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * childFind --
+ *
+ *          Find the specified child if on the list.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-------------------------------------------------4.9.1998---------
+ */
+static HintCacheNodeKey *
+childFind(HintCacheNodeKey * key)
+{
+    HintCacheNodeKey *current;
+    dlink_node *node;
+    int l;
+
+    l = plaxtonMatchBits(key->key, myNodeKey);
+    assert(l <= nChildLists);
+    for (node = childrenListA[l].head; node ; node = node->next) {
+	current = node->data;
+	if (!hintCacheNodeKeyCompare(current, key)) {
+	    return current;
+	}
+    }
+    return NULL;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * matchBits --
+ *
+ *          Return the number of bits that match between the two
+ *          keys.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.10.1998-------
+ */
+int
+plaxtonMatchBits(HintCacheKey k1, HintCacheKey k2)
+{
+    int ibit;
+    HintCacheKey mask;
+
+    for (ibit = 0, mask = 0x1; ibit < nChildLists - 1; ibit++, mask = mask << 1) {
+	if ((k1 & mask) != (k2 & mask)) {
+	    return ibit;
+	}
+    }
+    return ibit;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonmyNodeKey --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      None.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+HintCacheKey
+plaxtonmyNodeKey(void)
+{
+    return myNodeKey;
+}
+
+
+#ifdef DOTEST
+/*
+ *------------------------------------------------------------------
+ *
+ * plaxtonSelfTest --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.10.1998------
+ */
+
+void
+plaxtonSelfTest()
+{
+    printf("plaxtonSelfTest...");
+    fflush(stdout);
+    testMakeMatchKey();
+    neighborsOutgoing = (HCNet *) xmalloc(sizeof(HCNet));
+    assert(neighborsOutgoing);
+    printf(".");
+    fflush(stdout);
+    HCNet_Init(neighborsOutgoing);
+    HCNet_SetTestMode(neighborsOutgoing);
+    selfTestChildren();
+    printf(".");
+    fflush(stdout);
+    selfTestParents();
+    printf(".");
+    fflush(stdout);
+    HCNet_Destroy(neighborsOutgoing);
+    xfree(neighborsOutgoing);
+    printf(".Done.\n");
+    fflush(stdout);
+    return;
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * selfTestChildren --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+static void
+selfTestChildren()
+{
+    int iaddr;
+    struct sockaddr_in n0;
+    static int CHECK_ADDR_BEGIN = 1000;
+    static int CHECK_ADDR_END = 2000;
+    static int CHECK_NOT_THERE_END = 3000;
+    static URLKey urlMatchAll, urlMatchNone, urlMatchOne, urlMatchEight;
+    int amILeaf = -1;
+    int childCount, allChildren;
+    struct sockaddr_in *childrenA = NULL;
+
+    assert(CHECK_ADDR_END > CHECK_ADDR_BEGIN);
+    assert(CHECK_ADDR_END < CHECK_NOT_THERE_END);
+
+
+
+    allChildren = CHECK_ADDR_END - CHECK_ADDR_BEGIN;
+    plaxtonInit(8);
+
+    assert(sizeof(URLKey) == sizeof(HintCacheKey));	/* bypassing normal init */
+    urlMatchAll.key = myNodeKey;
+    urlMatchNone.key = ~myNodeKey;
+    urlMatchOne.key = (~myNodeKey) ^ 0x1;
+    urlMatchEight.key = (~myNodeKey) ^ 0xFF;
+
+    assert(plaxtonNChildrenQs() == sizeof(HintCacheKey) * 8 + 1);
+    amILeaf = -1;
+    assert(plaxtonChildQIndex(&urlMatchAll, 0,
+	    &amILeaf) == sizeof(HintCacheKey) * 8);
+    assert(amILeaf == 1);
+    amILeaf = -1;
+    assert(plaxtonChildQIndex(&urlMatchNone, 0, &amILeaf) == 0);
+    assert(amILeaf == 1);
+    amILeaf = -1;
+    assert(plaxtonChildQIndex(&urlMatchOne, 0, &amILeaf) == 1);
+    assert(amILeaf == 1);
+    amILeaf = -1;
+    assert(plaxtonChildQIndex(&urlMatchEight, 0, &amILeaf) == 8);
+    assert(amILeaf == 1);
+    childrenA = (struct sockaddr_in *) 0x888888;
+    childCount = plaxtonGetChildAddrs(15, &childrenA);
+    assert(childCount == 0);
+    assert(childrenA == NULL);
+
+    for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_ADDR_END; iaddr++) {
+	n0.sin_addr.s_addr = iaddr;
+	n0.sin_port = 0;
+	plaxtonAddChild(&n0);
+    }
+
+    childCount = plaxtonGetChildAddrs(sizeof(HintCacheKey) * 8, &childrenA);
+    assert(childCount == allChildren);
+    assert(childrenA != NULL);
+    assert(selfTestFindAddr(CHECK_ADDR_BEGIN, childrenA, childCount));
+    assert(selfTestFindAddr((CHECK_ADDR_BEGIN + CHECK_ADDR_END) / 2,
+	    childrenA, childCount));
+    assert(selfTestFindAddr(CHECK_ADDR_END - 1, childrenA, childCount));
+    assert(!selfTestFindAddr(CHECK_ADDR_END, childrenA, childCount));
+    xfree(childrenA);
+
+    /*
+     * The nodes we inserted as children were random. Assuming 
+     * we inserted a reasonable number of them, it would be
+     * surprizing if more than, say, 60% matched us in the
+     * lowest bit or if fewer than, say, 40% match us in the
+     * lowest bit
+     */
+    if (allChildren >= 1000) {
+	childCount = plaxtonGetChildAddrs(0, &childrenA);
+	if (allChildren * 0.6 < childCount) {
+	    printf("WARNING WARNING WARNING WARNING\n");
+	    printf
+		("WARNING: Plaxton saw unlikely distribution of random children.\n");
+	    printf
+		("WARNING: (too many). This is very nearly an assertion failure.\n");
+	}
+	if (allChildren * 0.4 > childCount) {
+	    printf("WARNING WARNING WARNING WARNING\n");
+	    printf
+		("WARNING: Plaxton saw unlikely distribution of random children.\n");
+	    printf
+		("WARNING: (too few). This is very nearly an assertion failure.\n");
+	}
+	xfree(childrenA);
+    } else {
+	printf
+	    ("\nWARNING: Plaxton selftest skipping random match check (too few samples\n");
+    }
+
+    printf(".");
+    fflush(stdout);
+    for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_ADDR_END; iaddr++) {
+	n0.sin_addr.s_addr = iaddr;
+	n0.sin_port = 0;
+	assert(plaxtonCheckIfChild(&n0));
+	plaxtonRemoveChild(&n0);
+    }
+    printf(".");
+    fflush(stdout);
+    for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_NOT_THERE_END; iaddr++) {
+	n0.sin_addr.s_addr = iaddr;
+	n0.sin_port = 0;
+	assert(!plaxtonCheckIfChild(&n0));
+    }
+    plaxtonDestroy();
+    printf(".OK\n");
+}
+
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * selfTestFindAddr --
+ *
+ *          Return nonzero if the specified value is in
+ *          the array.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.10.1998-------
+ */
+static int
+selfTestFindAddr(int addr, struct sockaddr_in *childrenA, int childCount)
+{
+    struct sockaddr_in n0;
+    int ii;
+
+    assert(childrenA != NULL);
+    n0.sin_addr.s_addr = addr;
+    n0.sin_port = 0;
+    for (ii = 0; ii < childCount; ii++) {
+	assert(childrenA[ii].sin_port == 0);
+	if (childrenA[ii].sin_addr.s_addr == n0.sin_addr.s_addr) {
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * selfTestParents --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.19.1998--------
+ */
+static void
+selfTestParents(void)
+{
+    testParentsBinaryTree();
+    testParentsMultiRootCase();
+    testParentsInternals();
+    testParentsInternals2();
+    stressTestParents();
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * testParentsBinaryTree --
+ *
+ *          Test the following simple case: four nodes
+ *          with low-order bits: 00 01 10 11
+ * 
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.19.1998--------
+ */
+static void
+testParentsBinaryTree(void)
+{
+    int myId, targetId, caseCount;
+    struct sockaddr_in parents[4], retAddr;
+    int ii, hops, qIndex, iAmRoot;
+    HintCacheNodeKey key;
+    URLKey targetURLKey;
+
+    /* XXX Make sure that entire code merge happens. Funny little bug in
+     * tools.h that we fixed.
+     */
+    parents[0].sin_addr.s_addr = 10;
+    parents[0].sin_port = 0;
+    parents[1].sin_addr.s_addr = 11;
+    parents[1].sin_port = 0;
+    assert(SINCMP(&parents[0], &parents[1]));	/* if this fails, bug in SINCMP */
+
+    /*
+     * Try this test from every point of view
+     */
+    for (myId = 0; myId < 4; myId++) {
+	plaxtonInit(1);
+	assert(plaxtonNParentQs() == 192);
+	
+
+	/* 
+	 * Cheat to force my key to do right thing 
+	 */
+	myNodeKey = (HintCacheKey) myId;
+	for (ii = 0; ii < BITS_PER_KEY; ii++) {
+	    assert(highestMatchA[ii].head != 0);
+	    ((HintCacheNodeKey *) highestMatchA[ii].head->data)->key = myNodeKey;
+	}
+	
+	for (caseCount = 1; caseCount <= 3; caseCount++) {
+	    /*
+	     * Do all combinations of bottom two bits except my own
+	     */
+	    targetId = myId ^ caseCount;
+	    /* 
+	     * Search for a node that matches desired bits
+	     */
+	    for (ii = 0;; ii++) {
+		parents[caseCount].sin_addr.s_addr = myId * 1000 + ii;
+		parents[caseCount].sin_port = 0;
+		hintCacheNodeKeyInit(&key, &parents[caseCount]);
+		if ((key.key & 0x3) == targetId) {
+		    if (caseCount == 1) {
+			assert((key.key & 0x2) == (myNodeKey & 0x2));
+			assert((key.key & 0x1) != (myNodeKey & 0x1));
+			hops = 1;
+		    } else {
+			assert((key.key & 0x2) != (myNodeKey & 0x2));
+			hops = 2;
+		    }
+		    HCHier_newNode(&parents[caseCount], hops, 999);
+
+		    break;
+		}
+	    }
+	}
+
+
+	/*
+	 * Case 0: same in all bits
+	 */
+	targetURLKey.key = myId;
+	qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot);
+	assert(iAmRoot);
+
+
+	/*
+	 * Case 1: differ in bit 0 --> queue is at level 0
+	 * and the (key & 0x1)th queue within level 0
+	 */
+	targetURLKey.key = myId ^ 0x1;
+	qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot);
+	assert(!iAmRoot);
+	assert(qIndex == ((unsigned) targetURLKey.key & 0x1));
+	assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0);
+	assert(retAddr.sin_addr.s_addr == parents[1].sin_addr.s_addr);
+	assert(plaxtonCheckIfParent(targetURLKey, &parents[1]));
+	assert(!plaxtonCheckIfParent(targetURLKey, &parents[2]));
+	assert(!plaxtonCheckIfParent(targetURLKey, &parents[3]));
+
+
+	/*
+	 * Case 2: differ in bit 1; same bit 0 --> queue is
+	 * at level 1 and the (key & 0x1)the queue within level 1
+	 */
+	targetURLKey.key = myId ^ 0x2;
+	qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot);
+	assert(!iAmRoot);
+	assert(qIndex == 2 + (((unsigned) targetURLKey.key & 0x2) >> 1));
+	assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0);
+	assert(retAddr.sin_addr.s_addr == parents[2].sin_addr.s_addr);
+	assert(!plaxtonCheckIfParent(targetURLKey, &parents[1]));
+	assert(plaxtonCheckIfParent(targetURLKey, &parents[2]));
+	assert(!plaxtonCheckIfParent(targetURLKey, &parents[3]));
+
+	/* 
+	 * Case 3: differ in bits 0 and 1; should be same as case 1
+	 */
+	targetURLKey.key = myId ^ 0x3;
+	qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot);
+	assert(!iAmRoot);
+	assert(qIndex == ((unsigned) targetURLKey.key & 0x1));
+	assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0);
+	assert(retAddr.sin_addr.s_addr == parents[1].sin_addr.s_addr);
+	assert(plaxtonCheckIfParent(targetURLKey, &parents[1]));
+	assert(!plaxtonCheckIfParent(targetURLKey, &parents[2]));
+	assert(!plaxtonCheckIfParent(targetURLKey, &parents[3]));
+
+	plaxtonDestroy();
+    }
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * testParentsMultiRootCase --
+ *
+ *          Test the case where several nodes match
+ *          an object in k bits, and no nodes match in
+ *          more than k bits. Answer should be that the
+ *          highest key is the winner.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------4.19.1998--------
+ */
+static void
+testParentsMultiRootCase(void)
+{
+    int eligibleFound, ii;
+    struct sockaddr_in sin, maxAddr, retAddr;
+    static unsigned int nodeMask = 0xFF;
+    static unsigned int objMask = 0x3F;
+    HintCacheKey maxKey;
+    URLKey targetURLKey;
+    int qIndex, iAmRoot;
+    HintCacheNodeKey anotherNodeKey;
+
+    plaxtonInit(2);
+
+    assert(objMask < nodeMask);
+    assert((objMask & nodeMask) == objMask);
+
+    /*
+     * Create a bunch of nodes that are eligible to be the root for
+     * for an object that matches them (and us) in objMask bits
+     * and mismatches in the next bit
+     */
+    /* XXX   targetURLKey.key = (myNodeKey & objMask) ^ (nodeMask ^ objMask); */
+    targetURLKey.key = (myNodeKey & nodeMask) ^ (nodeMask ^ objMask);
+
+    qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot);
+    assert(iAmRoot);
+
+    maxKey = myNodeKey;
+    maxAddr = Config.Sockaddr.http->s;
+    ii = 0;
+    eligibleFound = 0;
+    while (eligibleFound < 40) {
+	sin.sin_addr.s_addr = 10000 + ii;
+	sin.sin_port = 0;
+	hintCacheNodeKeyInit(&anotherNodeKey, &sin);
+	if ((anotherNodeKey.key & nodeMask) == (myNodeKey & nodeMask)) {
+	    eligibleFound++;
+	    HCHier_newNode(&sin, 1000, 999);
+	    if (anotherNodeKey.key > maxKey) {
+		/*
+		 * Found new root for object 
+		 */
+		maxKey = anotherNodeKey.key;
+		maxAddr = sin;
+	    }
+	}
+	qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot);
+	if (maxKey == myNodeKey) {
+	    assert(iAmRoot);
+	}
+	if (iAmRoot) {
+	    assert(maxKey == myNodeKey);
+	} else {
+	    assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0);
+	    assert(qIndex >= nParentLevels * plaxtonbucketsPerLevel);
+	    assert(retAddr.sin_addr.s_addr == maxAddr.sin_addr.s_addr);
+	}
+	ii++;
+    }
+    plaxtonDestroy();
+
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * stressTestParents --
+ *
+ *          Add and remove a few bizillion nodes and elements. I don't
+ *          know what the right answers should be, but
+ *          I want to test to try to trigger assertion failures.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------4.19.1998--------
+ */
+static void
+stressTestParents(void)
+{
+    int ii;
+    URLKey targetURLKey;
+    int qIndex, iamRoot;
+    static int BIG = 100;	/* should be much bigger for good test */
+    struct sockaddr_in sin, retAddr;
+
+    plaxtonInit(4);
+
+    for (ii = 0; ii < BIG; ii++) {
+	sin.sin_addr.s_addr = 100000 + ii;
+	sin.sin_port = 0;
+	HCHier_newNode(&sin, 1000, 999);
+    }
+
+    for (ii = 0; ii < BIG; ii++) {
+	sin.sin_addr.s_addr = 100000 + ii;
+	sin.sin_port = 0;
+	plaxtonchangeDistance(&sin);
+    }
+
+
+    for (ii = 0; ii < BIG; ii++) {
+	targetURLKey.key = ii;
+	qIndex = plaxtonParentQIndex(&targetURLKey, &iamRoot);
+	if (!iamRoot) {
+	    assert(!plaxtonGetParentAddr(qIndex, &retAddr));
+	}
+    }
+
+    for (ii = 0; ii < BIG; ii++) {
+	sin.sin_addr.s_addr = 100000 + ii;
+	sin.sin_port = 0;
+	HCHier_delNode(&sin, 1000, 1999);
+    }
+
+    for (ii = 0; ii < BIG; ii++) {
+	targetURLKey.key = ii;
+	qIndex = plaxtonParentQIndex(&targetURLKey, &iamRoot);
+	if (!iamRoot) {
+	    assert(!plaxtonGetParentAddr(qIndex, &retAddr));
+	}
+    }
+
+    plaxtonDestroy();
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * testParentsInternals --
+ *
+ *          Test the internal data structures of the parents
+ *          for the non-multi-root case.
+ *          Set the local key address to 0 then
+ *          generate a quand-ary tree with all possible
+ *          values of node keys from  1..15, and make
+ *          sure that the nodes land in the right buckets
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------
+ */
+static void
+testParentsInternals(void)
+{
+    int ii, targetKey;
+    HintCacheNodeKey anotherNodeKey, *current, *next;
+    HintCacheKey k;
+    struct sockaddr_in sin, nodes[16];
+    int iAmRoot;
+    URLKey urlKey;
+    dlink_node *node;
+
+    plaxtonInit(2);
+    myNodeKey = 0;		/* Fake it out to make tests easier to write and read */
+
+    targetKey = 1;
+    ii = 0;
+    while (targetKey < 16) {
+	/*
+	 * Note: netdb only keeps distance info on granularity of
+	 * networks; we want to know what distances there are between
+	 * nodes, so make nodes be on different (hopfully unused) subnets
+	 */
+	sin.sin_addr.s_addr = 15000 + ii * 255;
+	sin.sin_port = 0;
+	if (netdbHintHops(sin.sin_addr))
+	    !=0) {
+	    ii++;
+	    continue;		/* Someone already used this address and gave it a distance */
+	    }
+	hintCacheNodeKeyInit(&anotherNodeKey, &sin);
+	if ((anotherNodeKey.key & 15) == targetKey) {
+	    nodes[targetKey] = sin;
+	    HCHier_newNode(&sin, targetKey * 1000, 999);
+	    targetKey++;
+	}
+	ii++;
+    }
+
+    /*
+     * The level-0 lists should be in sorted order
+     */
+    for (ii = 1; ii <= 3; ii++) {
+	for (node = parentListA[ii].head; node; node = node->next) {
+	    current = node->data;
+	    if (current != (HintCacheNodeKey *) parentListA[ii].tail->data)) {
+		next = (HintCacheNodeKey *) List_Next((dlink_node *) current);
+		assert(!List_IsAtEnd(&parentListA[ii], (dlink_node *) next));
+		assert(HCHier_compareDistanceFromMe(hintCacheNodeKeyGetAddr(current).
+			sin_addr, hintCacheNodeKeyGetAddr(next).sin_addr)
+		    <= 0);
+	    }
+	}
+    }
+
+    /*
+     * The level-0 lists XX01, XX10, and XX11 should each have
+     * four elements in the following order: 00--, 01--, 10--,
+     * and 11-- (where "--" is the index of the list)
+     */
+    for (ii = 1; ii <= 3; ii++) {
+	assert((&parentListA[ii])->prevPtr
+	    == (&parentListA[ii])->nextPtr->nextPtr->nextPtr->nextPtr);
+
+	k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr))->key;
+	assert((k & 3) == ii);
+	assert(((k & 15) >> 2) == 0);	/* 00 */
+
+	k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr))->key;
+	assert((k & 3) == ii);
+	assert(((k & 15) >> 2) == 1);	/* 01 */
+
+	k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr->nextPtr))->key;
+	assert((k & 3) == ii);
+	assert(((k & 15) >> 2) == 2);	/* 10 */
+
+	k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr->nextPtr->
+		nextPtr))->key;
+	assert((k & 3) == ii);
+	assert(((k & 15) >> 2) == 3);	/* 11 */
+
+	urlKey.key = 0xFFAA3400 | ii;
+	assert(plaxtonCheckIfParent(urlKey, &nodes[ii]));
+	assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == ii);
+	assert(!iAmRoot);
+    }
+    /*
+     * The level-1 lists 0100, 1000, 1100 should each
+     * have one element
+     */
+    /* 00 00 is list 4 and is empty */
+    assert(List_IsEmpty(&parentListA[4]));
+
+    /* 01 00 is list 5 and has one element "xxx0100" = 4 */
+    assert(parentListA[5].nextPtr->nextPtr == &parentListA[5]);
+    k = ((HintCacheNodeKey *) ((&parentListA[5])->nextPtr))->key;
+    assert((k & 15) == 4);
+    urlKey.key = 0xFFAA1204;
+    assert(plaxtonCheckIfParent(urlKey, &nodes[4]));
+    assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 5);
+    assert(!iAmRoot);
+
+    /* 10 00 is list 6 and has one element "xxx1000" = 8 */
+    assert(parentListA[6].nextPtr->nextPtr == &parentListA[6]);
+    k = ((HintCacheNodeKey *) ((&parentListA[6])->nextPtr))->key;
+    assert((k & 15) == 8);
+    urlKey.key = 0xFFAA1208;
+    assert(plaxtonCheckIfParent(urlKey, &nodes[8]));
+    assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 6);
+    assert(!iAmRoot);
+
+    /* 11 00 is list 7 and has one element "xxx1100" = 12 */
+    assert(parentListA[7].nextPtr->nextPtr == &parentListA[7]);
+    k = ((HintCacheNodeKey *) ((&parentListA[7])->nextPtr))->key;
+    assert((k & 15) == 12);
+    urlKey.key = 0xFFAA120C;
+    assert(plaxtonCheckIfParent(urlKey, &nodes[12]));
+    assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 7);
+    assert(!iAmRoot);
+
+    plaxtonDestroy();
+}
+
+
+/*
+ *------------------------------------------------------------------
+ *
+ * testParentsInternals2 --
+ *
+ *         Test finding parent when we can't match
+ *         entire next level.
+ *
+ * Arguments:
+ *      type1 arg1 -- description.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *--------------------------------------------------------5.4.1998----
+ */
+static void testParentsInternals2(void)
+{
+    int ii;
+    struct sockaddr_in sin;
+    HintCacheNodeKey anotherNodeKey;
+    URLKey urlKey;
+    int iAmRoot;
+
+        plaxtonInit(4);
+        myNodeKey = 0;		/* Fake it out to make tests easier to write and read */
+
+        ii = 0;
+    while (1)
+    {
+	/*
+	 * Note: netdb only keeps distance info on granularity of
+	 * networks; so make nodes be on different (hopfully unused) subnets
+	 */
+	sin.sin_addr.s_addr = 15000 + ii * 255;
+	sin.sin_port = 0;
+	if (netdbHintHops(sin.sin_addr) != 0)
+	{
+	    ii++;
+	    continue;		/* Someone already used this address and gave it a distance */
+	}
+	hintCacheNodeKeyInit(&anotherNodeKey, &sin);
+	/* 
+	 * Want 0110 0000 
+	 */
+	if ((anotherNodeKey.key & 0xFF) == 0x60) {
+	    HCHier_newNode(&sin, 1000, 999);
+	    break;
+	}
+	ii++;
+    }
+    assert((anotherNodeKey.key & 0xFF) == 0x60);
+    urlKey.key = 0x20;
+    assert(plaxtonCheckIfParent(urlKey, &sin));
+    assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 22);
+    assert(!iAmRoot);
+    plaxtonDestroy();
+}
+
+/*
+ *------------------------------------------------------------------
+ *
+ * testMakeMatchKey --
+ *
+ *          description.
+ *
+ * Arguments:
+ *      None.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------5.4.1998------
+ */
+static void testMakeMatchKey(void)
+{
+    URLKey key;
+    HintCacheKey ret;
+
+               key.key = 0xFFAABBCC;
+               ret = makeMatchKey(&key, 4, 0);
+               assert(ret == 0xC);
+               ret = makeMatchKey(&key, 4, 0xD);
+               assert(ret = 0xDC);
+               ret = makeMatchKey(&key, 0, 0xD);
+               assert(ret = 0xD);
+}
+
+#endif				/* DOTEST */
Index: squid/src/access_log.c
diff -u squid/src/access_log.c:1.17 squid/src/access_log.c:1.15.2.2
--- squid/src/access_log.c:1.17	Sun Jun 16 10:48:14 2002
+++ squid/src/access_log.c	Tue Sep  3 10:41:34 2002
@@ -64,6 +64,7 @@
     "TCP_MEM_HIT",
     "TCP_DENIED",
     "TCP_OFFLINE_HIT",
+    "TCP_PUT",
 #if LOG_TCP_REDIRECTS
     "TCP_REDIRECT",
 #endif
@@ -72,6 +73,7 @@
     "UDP_DENIED",
     "UDP_INVALID",
     "UDP_MISS_NOFETCH",
+    "UDP_PUT",
     "ICP_QUERY",
     "LOG_TYPE_MAX"
 };
Index: squid/src/acl.c
diff -u squid/src/acl.c:1.55 squid/src/acl.c:1.42.2.3
--- squid/src/acl.c:1.55	Sun Sep  1 09:30:41 2002
+++ squid/src/acl.c	Tue Sep  3 10:41:35 2002
@@ -363,7 +363,7 @@
     protocol_t protocol;
     for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
     while ((t = strtokFile())) {
-	protocol = urlParseProtocol(t);
+	protocol = urlParseProtocol(t, 0, 0);
 	q = memAllocate(MEM_INTLIST);
 	q->i = (int) protocol;
 	*(Tail) = q;
Index: squid/src/cache_cf.c
diff -u squid/src/cache_cf.c:1.47 squid/src/cache_cf.c:1.38.2.4
--- squid/src/cache_cf.c:1.47	Sun Sep  1 09:30:41 2002
+++ squid/src/cache_cf.c	Tue Sep  3 10:41:37 2002
@@ -1535,6 +1535,21 @@
 	    p->options.allow_miss = 1;
 	} else if (!strncasecmp(token, "max-conn=", 9)) {
 	    p->max_conn = xatoi(token + 9);
+	} else if (!strncasecmp(token, "dist", 4)) {
+	    p->options.dist = 1;
+	} else if (!strncasecmp(token, "fwdpush", 7)) {
+	    p->fwdpush = DistAllPeers;
+	    DistAllPeers = p;
+#if USE_ICP_DATA
+	} else if (!strncasecmp(token, "icpdata", 7)) {
+	    p->options.icpdata = 1;
+	} else if (!strncasecmp(token, "maxrate=", 8)) {
+	    p->maxrate = atoi(token + 8);
+#endif
+#if USE_HINT_CACHE
+	} else if (!strncasecmp(token, "nohint", 6)) {
+	    p->options.nohint = 1;
+#endif
 	} else {
 	    debug(3, 0) ("parse_peer: token='%s'\n", token);
 	    self_destruct();
Index: squid/src/cbdata.c
diff -u squid/src/cbdata.c:1.15 squid/src/cbdata.c:1.14.2.2
--- squid/src/cbdata.c:1.15	Sat Apr 13 16:09:15 2002
+++ squid/src/cbdata.c	Tue Sep  3 10:41:39 2002
@@ -136,6 +136,7 @@
     CREATE_CBDATA_FREE(peer, peerDestroy);
     CREATE_CBDATA(ps_state);
     CREATE_CBDATA(RemovalPolicy);
+    CREATE_CBDATA(Pusher);
     CREATE_CBDATA(RemovalPolicyWalker);
     CREATE_CBDATA(RemovalPurgeWalker);
     CREATE_CBDATA(store_client);
Index: squid/src/cf.data.pre
diff -u squid/src/cf.data.pre:1.79 squid/src/cf.data.pre:1.43.2.4
--- squid/src/cf.data.pre:1.79	Sun Sep  1 09:30:41 2002
+++ squid/src/cf.data.pre	Tue Sep  3 10:41:39 2002
@@ -279,6 +279,8 @@
 		     digest-url=url
 		     allow-miss
 		     max-conn
+ 		     dist
+ 		     nohint
 
 		     use 'proxy-only' to specify that objects fetched
 		     from this cache should not be saved locally.
@@ -385,6 +387,19 @@
 		     use 'max-conn' to limit the amount of connections Squid
 		     may open to this peer.
 
+		     'dist' tells squid to ask for consistency updates 
+                     via httpdist on all queries to that peer.
+
+		     'nohint' tells squid not to send hint cache updates
+                     to that peer.  The default is that updates are sent
+		     if hints are active.
+
+		     'icpdata' says to send pushes to this peer by the 
+		     UDP-based ICPDATA protocol instead of TCP.
+
+		     'maxrate=n' specifies the maximum rate to send
+		     ICPDATA data at.
+
 	NOTE: non-ICP neighbors must be specified as 'parent'.
 DOC_END
 
@@ -1405,6 +1420,11 @@
 	(off - for use when useragents generate nonce counts that
 	occasionally miss 1 (ie, 1,2,4,6)).
 
+	"nonce_strictness" on|off
+	Determines if squid requires increment-by-1 behaviour for nonce counts 
+	(on - the default), or strictly incrementing (off - for use when useragents
+	generate nonce counts that occasionally miss 1 (ie, 1,2,4,6)).
+
 	=== NTLM scheme options follow ===
 
 	"program" cmdline
@@ -3774,6 +3794,111 @@
 	time.  By default it is set to 10% of the Cache Digest.
 DOC_END
 
+NAME: hint_cache_listen
+IFDEF: USE_HINT_CACHE
+TYPE: onoff
+LOC: Config.onoff.hint_cache_listen
+DEFAULT: off
+DOC_START
+	This controls whether hint cache is used to decide where to 
+	forward misses.  Hint caches exchange data to track nearest
+	location and metadata of all URLs in a  hint cache cloud;
+	This variable also decides whether we listen to hints from
+	neighboring hint caches.
+DOC_END
+
+NAME: hint_cache_advertise
+IFDEF: USE_HINT_CACHE
+TYPE: onoff
+LOC: Config.onoff.hint_cache_advertise
+DEFAULT: off
+DOC_START
+	This controls whether we tell other caches about content in
+	our own cache.  We only want to do that if we are in a
+	position to efficiently serve requests from other caches.
+	
+	We encourage you to turn this on, as participation in the
+	hint cloud as a full neighbor brings greater value to
+	everybody, including yourself.
+DOC_END
+
+NAME: hint_cache_file
+IFDEF: USE_HINT_CACHE
+TYPE: string
+LOC: Config.Hints.cache_file
+DEFAULT: @DEFAULT_HINT_FILE@
+DOC_START
+	This is the name of the file holding the hint cache.  
+DOC_END
+
+NAME: hint_cache_size
+COMMENT: bytes
+IFDEF: USE_HINT_CACHE
+TYPE: int
+LOC: Config.Hints.size
+DEFAULT: 83886080
+DOC_START
+	This is the size of the hint cache, in bytes.  It has to be
+	big enough to hold location and metadata for all objects
+	tracked.
+DOC_END
+
+NAME: hint_cache_assoc
+IFDEF: USE_HINT_CACHE
+TYPE: int
+LOC: Config.Hints.assoc
+DEFAULT: 4
+DOC_START
+	Hint cache associativity.
+DOC_END
+
+NAME: hint_cache_interval
+IFDEF: USE_HINT_CACHE
+TYPE: int
+LOC: Config.Hints.intvl
+DEFAULT: 60
+DOC_START
+	Max interval between hint transmissions to neighbors, in
+	seconds.  Actual interval is randomly, uniformly distributed
+	between 0 and hint_cache_interval.
+DOC_END
+
+NAME: hint_cache_use_mmap
+IFDEF: USE_HINT_CACHE
+TYPE: onoff
+LOC: Config.onoff.hint_cache_use_mmap
+DEFAULT: off
+DOC_START
+	This tells the hint cache to access the hint cache file
+	using mmap() instead of standard file I/O.  A slight
+	speedup on machines with plenty of RAM.  If you are not
+	so long on RAM for your cache, leave it off.  It probably
+	isn't efficient unless you can hold almost the entire
+	cache in memory.  See hint_cache_size, above, for how
+	big your hint cache is.
+DOC_END
+
+NAME: hint_cache_join_interval
+IFDEF: USE_HINT_CACHE
+TYPE: int
+LOC: Config.Hints.join_intvl
+DEFAULT: 14400
+DOC_START
+	Max interval between join transmissions to neighbors, in
+	seconds.  Actual interval is randomly, uniformly distributed
+	between 0 and hint_cache_join_interval.  
+DOC_END
+
+NAME: hint_cache_holddown
+IFDEF: USE_HINT_CACHE
+TYPE: int
+LOC: Config.Hints.holddown
+DEFAULT: 900
+DOC_START
+	Amount of time to pass before we can assume that a hint
+	has finished propagating.
+DOC_END
+
 NAME: chroot
 TYPE: string
 LOC: Config.chroot_dir
Index: squid/src/client_side.c
diff -u squid/src/client_side.c:1.71 squid/src/client_side.c:1.45.2.5
--- squid/src/client_side.c:1.71	Sun Sep  1 09:30:42 2002
+++ squid/src/client_side.c	Tue Sep  3 10:41:41 2002
@@ -1986,6 +1986,9 @@
 	}
 	/* yes, continue */
 	http->log_type = LOG_TCP_MISS;
+    } else if (r->method == METHOD_PUT) {
+	putRecv(http);
+	return;
     } else {
 	http->log_type = clientProcessRequest2(http);
     }
@@ -2007,6 +2010,15 @@
 	    http->entry->mem_obj->method = r->method;
 	}
 	http->sc = storeClientListAdd(http->entry, http);
+	if (r->dist_type != DIST_NONE) {
+	    if (r->dist_type == DIST_DIST)
+		distNewUpdatee(http->entry, r->client_addr, r->dist_port);
+	    else {
+		/* DIST_UNDIST */
+		assert(r->dist_type == DIST_UNDIST);
+		distDelUpdatee(http->entry, r->client_addr, r->dist_port);
+	    }
+	}
 #if DELAY_POOLS
 	delaySetStoreClient(http->sc, delayClient(http));
 #endif
@@ -2252,7 +2264,8 @@
     *(*prefix_p + prefix_sz) = '\0';
     dlinkAdd(http, &http->active, &ClientActiveRequests);
 
-    debug(33, 5) ("parseHttpRequest: Request Header is\n%s\n", (*prefix_p) + *req_line_sz_p);
+    debug(33, 5) ("parseHttpRequest: Request Header is\n%s\n",
+		  http->hdr_str + *req_line_sz_p);
 #if THIS_VIOLATES_HTTP_SPECS_ON_URL_TRANSFORMATION
     if ((t = strchr(url, '#')))	/* remove HTML anchors */
 	*t = '\0';
@@ -2546,13 +2559,11 @@
 	if (nrequests == 0)
 	    fd_note(conn->fd, "Reading next request");
 	/* Process request */
-	http = parseHttpRequest(conn,
-	    &method,
-	    &parser_return_code,
-	    &prefix,
-	    &req_line_sz);
-	if (!http)
-	    safe_free(prefix);
+        http = parseHttpRequest(conn,
+            &method,
+            &parser_return_code,
+            &prefix,
+            &req_line_sz);
 	if (http) {
 	    assert(http->req_sz > 0);
 	    conn->in.offset -= http->req_sz;
@@ -2575,7 +2586,6 @@
 		err->request_hdrs = xstrdup(conn->in.buf);
 		http->entry = clientCreateStoreEntry(http, method, null_request_flags);
 		errorAppendEntry(http->entry, err);
-		safe_free(prefix);
 		break;
 	    }
 	    if ((request = urlParse(method, http->uri)) == NULL) {
@@ -2586,14 +2596,13 @@
 		http->al.http.code = err->http_status;
 		http->entry = clientCreateStoreEntry(http, method, null_request_flags);
 		errorAppendEntry(http->entry, err);
-		safe_free(prefix);
 		break;
 	    } else {
 		/* compile headers */
 		/* we should skip request line! */
-		if (!httpRequestParseHeader(request, prefix + req_line_sz))
+		if (!httpRequestParseHeader(request, http->hdr_str + req_line_sz))
 		    debug(33, 1) ("Failed to parse request headers: %s\n%s\n",
-			http->uri, prefix);
+			http->uri, http->hdr_str);
 		/* continue anyway? */
 	    }
 	    request->flags.accelerated = http->flags.accel;
@@ -2615,7 +2624,6 @@
 	    request->content_length = httpHeaderGetInt(&request->header,
 		HDR_CONTENT_LENGTH);
 	    request->flags.internal = http->flags.internal;
-	    safe_free(prefix);
 	    safe_free(http->log_uri);
 	    http->log_uri = xstrdup(urlCanonicalClean(request));
 	    request->client_addr = conn->peer.sin_addr;
Index: squid/src/comm.c
diff -u squid/src/comm.c:1.24 squid/src/comm.c:1.18.2.4
--- squid/src/comm.c:1.24	Thu Apr 18 23:30:40 2002
+++ squid/src/comm.c	Tue Sep  3 10:41:42 2002
@@ -631,6 +631,9 @@
 comm_close(int fd)
 {
     fde *F = NULL;
+#if USE_ICP_DATA
+   int isvfd;
+#endif     
 
     debug(5, 5) ("comm_close: FD %d\n", fd);
     assert(fd >= 0);
@@ -648,6 +651,9 @@
     if (F->ssl)
 	ssl_shutdown_method(fd);
 #endif
+#if USE_ICP_DATA
+    isvfd = (conn->comm_type == SOCK_VIRTUAL);
+#endif
     commSetTimeout(fd, -1, NULL, NULL);
     CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
     commCallCloseHandlers(fd);
@@ -660,7 +666,18 @@
     }
 #endif
     fd_close(fd);		/* update fdstat */
+#if USE_ICP_DATA
+    if (isvfd) {
+	/* flag for later reuse */
+	conn->comm_type = SOCK_VIRTUAL;
+    }
+    else {
+	debug(5, 9) ("comm_close: really closing fd %d \n", fd);
+	close(fd);
+    }
+#else /* USE_ICP_DATA */
     close(fd);
+#endif /* USE_ICP_DATA */
     statCounter.syscalls.sock.closes++;
 }
 
@@ -1027,3 +1044,47 @@
 	return 0;
     return F->defer_check(fd, F->defer_data);
 }
+
+#if USE_ICP_DATA
+/*
+ * Get fake file descriptor suitable for indexing through fd_table.
+ */
+int
+comm_virtual_fd()
+{
+    static int firstfd = -1;
+    struct in_addr nobody;
+    int vfd;
+    int i;
+    
+    if (firstfd == -1){
+	nobody.s_addr = INADDR_ANY;
+	firstfd = comm_open(SOCK_DGRAM, 0, nobody, 0, COMM_NONBLOCKING, "virtual");
+	vfd = firstfd;
+    }
+    else {
+	for (i = 0; i <= Biggest_FD; ++i) {
+	    if (fd_table[i].comm_type == SOCK_VIRTUAL && !fd_table[i].openned)
+		break;
+	} 
+	if (fd_table[i].comm_type != SOCK_VIRTUAL) {
+	    nobody.s_addr = INADDR_ANY;
+	    vfd = comm_open(SOCK_DGRAM, 0, nobody, 0, COMM_NONBLOCKING, "virtual");
+	    debug(5, 4, "comm_virtual_fd: opened new vfd %d (Biggest_FD = %d)\n",
+		   vfd, Biggest_FD);
+	    assert(vfd > -1);
+	}
+	else {
+	    vfd = i;
+	}
+    }
+    
+    fdstat_open(vfd, FD_SOCKET);
+    memset((char *) &fd_table[vfd], '\0', sizeof(FD_ENTRY));
+    fd_table[vfd].openned = 1;
+    fd_table[vfd].lifetime = -1;
+    fd_table[vfd].comm_type = SOCK_VIRTUAL;
+    debug(5, 7, "comm_virtual_fd: returning vfd %d \n", vfd);
+    return(vfd);
+}
+#endif /* USE_ICP_DATA */
Index: squid/src/defines.h
diff -u squid/src/defines.h:1.24 squid/src/defines.h:1.15.2.4
--- squid/src/defines.h:1.24	Thu Aug  8 13:15:19 2002
+++ squid/src/defines.h	Tue Sep  3 10:41:43 2002
@@ -313,6 +313,64 @@
 #define O_BINARY 0
 #endif
 
+/* put.c */
+#define P_ACTIVE(p)  ((p)->flags.connected | (p)->flags.connecting)
+
+#if USE_HINT_CACHE
+/* Hint Cache Interface */
+
+/* Not QUITE compatible with 1.0 due to different tolower treatment
+   of URLs before md5 coding. */
+#define HINT_CACHE_VERSION "2.0"   /* Protocol version */
+
+/* Returns true iff the hint cache is in operation. */
+#define HINT_CACHE_ACTIVE()  (HCDisk != NULL)
+
+#define URLKEY_COMPARE(k1, k2)   ((k1).key - (k2).key)
+
+/* Hint Cache Primitives */
+#define HCE_VALID(hce)      ((hce)->ipaddr.s_addr != INADDR_ANY &&\
+			     URLKEY_COMPARE((hce)->key, INVALID_URL_KEY))
+#define HCE_INVALIDATE(hce) ((hce)->ipaddr.s_addr  = INADDR_ANY, \
+			     (hce)->key = INVALID_URL_KEY);
+
+#define HINT_CACHE_KEY(e) (((URLKey *) ((e)->hchash.key)))
+
+/* Hint protocol event types */
+#define HC_InvalToParent  1
+#define HC_InvalToChild   2
+#define HC_InformToParent 3
+#define HC_InformToChild  4
+#define HC_NewVersion     5
+#define HC_Join           6
+#define HC_Leave          7
+#define HC_Ignore         8 /* Message supressed. Ignore it. */
+#define HC_NotChild       9 /* "I am not your child" */
+#define HC_Error         10
+
+/* Smallest an HCUPDATE can be (e.g., length of a v1 update). */
+#define HCU_MINLEN 24
+
+/* Hint Cache Disk */
+#define HCD_VERSION 2
+
+#define HCD_PREFETCH_THRESH 3
+
+#endif /* USE_HINT_CACHE */
+
+
+/* CygWin & Windows NT Port */
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+#define _WIN_OS_UNKNOWN	0
+#define _WIN_OS_WIN32S	1
+#define _WIN_OS_WIN95	2
+#define _WIN_OS_WIN98	3
+#define _WIN_OS_WINNT	4
+#define _WIN_OS_WIN2K	5
+#define _WIN_OS_WINXP	6
+#endif
+
+#define	HTTP_REQBUF_SZ	4096
 /*
  * Macro to find file access mode
  */
Index: squid/src/dist.c
diff -u /dev/null squid/src/dist.c:1.1.2.5
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/dist.c	Mon May 20 19:46:42 2002
@@ -0,0 +1,217 @@
+/*
+ * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * Distribution network algorithm.
+ *
+ * AUTHOR: Jon Kay, 1997
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+#include "squid.h"
+
+static void distUpdate(Updatee *u);
+
+static char urlbuf[MAX_URL + 48];
+
+peer *DistAllPeers = 0;
+
+/* Create new updatee ds & add to object's updatee list */
+Updatee *
+distNewUpdatee(StoreEntry *entry, struct in_addr host, u_short dport)
+{
+    Updatee *u;
+    
+    ++statCounter.dist.dists;
+    /* Don't add a client if it isn't interested in updates */
+    if (dport == 0)
+	return(NULL);
+    
+    /* Make sure new guy isn't already on list */
+    for (u = entry->updatees; u; u = u->next) {
+	if (u->saddr.sin_addr.s_addr == host.s_addr
+	    && u->saddr.sin_port == dport)
+	    return(u);
+    }
+
+    /* Need new updatee, alloc and add to list */
+    u = xcalloc(sizeof(*u), 1);
+    u->next = entry->updatees;
+    u->entry = entry;
+    u->saddr.sin_family = AF_INET;
+    u->saddr.sin_addr = host;
+    u->saddr.sin_port = dport;
+    u->lastmod = entry->lastmod;
+    entry->updatees = u;
+    ++statCounter.dist.updatees;
+    return(u);
+}
+
+void
+distDelUpdatee(StoreEntry *entry, struct in_addr host, int dport)
+{
+    Updatee *i, **optr;
+
+    ++statCounter.dist.undists;
+    optr = &entry->updatees;
+    for (i = entry->updatees; i; i = i->next) {
+	if (i->saddr.sin_addr.s_addr == host.s_addr
+	    && i->saddr.sin_port == dport) {
+	    (*optr) = i->next;
+	    --statCounter.dist.updatees;
+	    xfree(i);
+	}
+	optr = &i->next;
+    }
+}
+
+void
+distDelUpdatees(Updatee *u)
+{
+    Updatee *nu;
+
+    for ( ; u; u = nu) {
+	nu = u->next;
+	--statCounter.dist.updatees;
+	xfree(u);
+    }
+}
+
+void
+distUpdateeChangeEntry(StoreEntry *entry, Updatee *u)
+{
+    entry->updatees = u;
+    for ( ; u; u = u->next) {
+	u->entry = entry;
+    }
+}
+    
+
+/* Code to distribute contents of entry to updatees */
+
+static void
+distUpdate(Updatee *u)
+{
+    if (u->lastmod >= u->entry->lastmod)
+	/* Already has this version */
+	return;
+    u->lastmod = u->entry->lastmod;  /* Mark version being xferred */
+    
+    ++statCounter.dist.updates;
+    kb_incr(&statCounter.dist.update_kbytes, u->entry->mem_obj->inmem_hi);
+
+    u->p = putSend(u->entry, &u->saddr, (PF *) 0, 0, 1 /* dodist */);
+}
+
+/* Distribute entry contents to anybody interested */
+void
+distEntryUpdate(StoreEntry *entry, request_t *req, struct sockaddr_in *src)
+{
+    Updatee *u;
+    
+    ++statCounter.dist.content_upd;
+
+    /* Open distribution socket to everybody interested */
+    for (u = entry->updatees; u; u = u->next) {
+	assert(req);
+	/* Don't send updates to GET-requesting clients,
+	   when we happen to know their identity.  We do
+	   know with other peers and on DIST reqs. */
+	if (req->dist_type == DIST_DIST
+	    && req->dist_port == u->saddr.sin_port
+	    && req->my_addr.s_addr == u->saddr.sin_addr.s_addr)
+	    continue;
+	
+	/* No problems here - send it on out */
+	distUpdate(u);
+    }
+}
+
+
+/* Best-case object consistency support */
+
+/* Change url from http: to httpdist1234: */
+/* Note: returns pointer to static buffer - contents change on next call. */
+char *
+distifyUrl(char *url)
+{
+    char distbuf[48];  /* dist string holder */
+    int plen, poff;
+    char *eop;
+
+    /* Find the end of the protocol field */
+    if ((eop = strchr(url, ':')) == NULL)
+	/* Give up if not of form http://... */
+	return(url);
+    poff = eop - url;
+
+    snprintf(distbuf, sizeof(distbuf), "dist%d",
+	     ntohs(Config.Sockaddr.http->s.sin_port));
+    plen = strlen(distbuf);
+
+    /* Assemble the new URL */
+    xmemcpy(urlbuf, url, poff);
+    xmemcpy(urlbuf + poff, distbuf, plen);
+    xstrncpy(urlbuf + poff + plen, url + poff, MAX_URL);
+    
+    return(urlbuf);
+}
+
+
+/* Report on push stats */
+void
+statDistPrint(StoreEntry * sentry)
+{
+    statPutPrint(sentry);
+    
+    storeAppendPrintf(sentry, "\nDIST Statistics:\n\n");
+    storeAppendPrintf(sentry, "DIST requests: %d\n",
+		      statCounter.dist.dists);
+    storeAppendPrintf(sentry, "unDIST requests: %d\n", 
+		      statCounter.dist.undists);
+    storeAppendPrintf(sentry, "Updates Sent: %d\n", 
+		      statCounter.dist.updates);
+    storeAppendPrintf(sentry, "KBytes of Update Sent: %d\n", 
+		      statCounter.dist.update_kbytes);
+    storeAppendPrintf(sentry, "Content Updates: %d\n", 
+		      statCounter.dist.content_upd);
+    storeAppendPrintf(sentry, "Updatee Structures: %d\n", 
+		      statCounter.dist.updatees);
+    storeAppendPrintf(sentry, "Updatee Memory Consumption: %d\n",
+		      statCounter.dist.updatees * sizeof(Updatee));
+}
+
+
+/* Need this to make sure that reconfiguration gives correctly
+   updated FwdPushLinks */
+void
+distInit()
+{
+    DistAllPeers = 0;
+
+    cachemgrRegister("push", "Push Stats",
+	statDistPrint, 0, 1);
+}
+
+
Index: squid/src/enums.h
diff -u squid/src/enums.h:1.37 squid/src/enums.h:1.27.2.7
--- squid/src/enums.h:1.37	Sun Jul 21 14:48:03 2002
+++ squid/src/enums.h	Tue Sep  3 10:41:45 2002
@@ -48,6 +48,7 @@
     LOG_TCP_MEM_HIT,
     LOG_TCP_DENIED,
     LOG_TCP_OFFLINE_HIT,
+    LOG_TCP_PUT,
 #if LOG_TCP_REDIRECTS
     LOG_TCP_REDIRECT,
 #endif
@@ -56,6 +57,7 @@
     LOG_UDP_DENIED,
     LOG_UDP_INVALID,
     LOG_UDP_MISS_NOFETCH,
+    LOG_UDP_PUT,
     LOG_ICP_QUERY,
     LOG_TYPE_MAX
 } log_type;
@@ -92,6 +94,7 @@
     ERR_FTP_UNAVAILABLE,
     ERR_ONLY_IF_CACHED_MISS,	/* failure to satisfy only-if-cached request */
     ERR_TOO_BIG,
+    ERR_CONFLICT,
     TCP_RESET,
     ERR_MAX
 } err_type;
@@ -437,6 +440,9 @@
     PROTO_WHOIS,
     PROTO_INTERNAL,
     PROTO_HTTPS,
+#if USE_HINT_CACHE
+    PROTO_ROUTE,
+#endif
     PROTO_MAX
 } protocol_t;
 
@@ -705,6 +711,7 @@
     CBDATA_helper_stateful_server,
     CBDATA_HttpStateData,
     CBDATA_peer,
+    CBDATA_Pusher,
     CBDATA_ps_state,
     CBDATA_RemovalPolicy,
     CBDATA_RemovalPolicyWalker,
@@ -723,6 +730,28 @@
     VARY_CANCEL
 };
 
+enum {
+    DIST_NONE,
+    DIST_DIST,
+    DIST_UNDIST
+};
+
+#if USE_HINT_CACHE
+enum HintCacheNet_State {
+    HC_uninitialized,
+    HC_filling,
+    HC_full,
+    HC_destroyed
+};
+
+
+typedef enum HintCacheNeighborActionE {
+    NEIGHBOR_ADD,
+    NEIGHBOR_REMOVE
+} NeighborAction;
+
+#endif /* USE_HINT_CACHE */
+
 /*
  * Store digest state enum
  */
Index: squid/src/globals.h
diff -u squid/src/globals.h:1.17 squid/src/globals.h:1.14.2.4
--- squid/src/globals.h:1.17	Sun Jul 14 17:43:58 2002
+++ squid/src/globals.h	Tue Sep  3 10:41:47 2002
@@ -159,6 +159,19 @@
 extern RemovalPolicy *mem_policy;
 extern hash_table *proxy_auth_username_cache;	/* NULL */
 extern int incoming_sockets_accepted;
+extern peer *DistAllPeers;
+#if USE_HINT_CACHE
+extern hash_table hint_table;
+extern const URLKey INVALID_URL_KEY;
+extern HintCacheDisk *HCDisk;
+extern HintCacheNet *parentOutgoingA;
+extern HintCacheNet *childrenOutgoingA;
+extern HintCacheNet *neighborsOutgoing;
+extern HintCacheDisk *hcDisk;
+#if USE_DYNAMIC_HIERARCHY
+
+#endif /* USE_DYNAMIC_HIERARCHY */
+#endif /* USE_HINT_CACHE */
 #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
 extern unsigned int WIN32_OS_version;	/* 0 */
 extern char *WIN32_OS_string;	/* NULL */
Index: squid/src/http.c
diff -u squid/src/http.c:1.22 squid/src/http.c:1.17.2.6
--- squid/src/http.c:1.22	Sun Sep  1 09:30:42 2002
+++ squid/src/http.c	Tue Sep  3 10:41:48 2002
@@ -45,9 +45,7 @@
 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 *);
@@ -55,7 +53,7 @@
 static int httpCachableReply(HttpStateData *);
 static void httpMaybeRemovePublic(StoreEntry *, http_status);
 
-static void
+void
 httpStateFree(int fd, void *data)
 {
     HttpStateData *httpState = data;
@@ -79,9 +77,11 @@
 int
 httpCachable(method_t method)
 {
-    /* GET and HEAD are cachable. Others are not. */
-    if (method != METHOD_GET && method != METHOD_HEAD)
+    /* GET, PUT, and HEAD are cachable. Others are not. */
+    if (method != METHOD_GET && method != METHOD_HEAD &&
+ 	method != METHOD_PUT) {
 	return 0;
+    }
     /* else cachable */
     return 1;
 }
@@ -414,6 +414,7 @@
 	t = httpState->reply_hdr + k;
     }
     *t = '\0';
+    httpState->body_remain -= hdr_len - (t - httpState->reply_hdr);
     httpState->reply_hdr_state++;
     assert(httpState->reply_hdr_state == 1);
     ctx = ctx_enter(entry->mem_obj->url);
@@ -423,6 +424,9 @@
     /* Parse headers into reply structure */
     /* what happens if we fail to parse here? */
     httpReplyParse(reply, httpState->reply_hdr, hdr_len);
+    if (reply->content_length > 0) {
+        httpState->body_remain = reply->content_length + reply->hdr_sz;
+    }
     storeTimestampsSet(entry);
     /* Check if object is cacheable or not based on reply code */
     debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status);
@@ -531,7 +535,7 @@
 /* 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
+void
 httpReadReply(int fd, void *data)
 {
     HttpStateData *httpState = data;
@@ -610,7 +614,7 @@
 	fwdFail(httpState->fwd, err);
 	httpState->eof = 1;
 	comm_close(fd);
-    } else if (len == 0) {
+    } else if (len == 0 || len >= httpState->body_remain) {
 	/* Connection closed; retrieval done. */
 	httpState->eof = 1;
 	if (httpState->reply_hdr_state < 2)
@@ -621,8 +625,26 @@
 	     * we want to process the reply headers.
 	     */
 	    httpProcessReplyHeader(httpState, buf, len);
-	fwdComplete(httpState->fwd);
-	comm_close(fd);
+	else
+	    /* whole body is subtracted */
+	    httpState->body_remain -= len;
+	debug(50, 7) ("httpReadReply: body_remain = %d (len %d, state %d)\n",
+	      httpState->body_remain, len, httpState->reply_hdr_state);
+	if (len > 0) {
+	    storeAppend(entry, buf, len); 
+	    distEntryUpdate(entry, entry->mem_obj->request,
+			    httpState->peer ? &httpState->peer->in_addr : 0);
+	}
+	if (entry->mem_obj->request &&
+	    entry->mem_obj->request->method == METHOD_PUT) {
+	    putReplyAndClose(fd, entry);
+	    debug(50, 8) ("httpReadReply: called putReplyAndClose\n");
+	    /* putReplyAndClose calls storeComplete() */
+	}
+	else {
+	    fwdComplete(httpState->fwd);
+	    comm_close(fd);
+	}
     } else {
 	if (httpState->reply_hdr_state < 2) {
 	    httpProcessReplyHeader(httpState, buf, len);
@@ -639,7 +661,11 @@
 		    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
 	    }
 	}
+	httpState->body_remain -= len;
+	debug(50, 8) ("httpReadReply: %d remain\n", httpState->body_remain);
 	storeAppend(entry, buf, len);
+	distEntryUpdate(entry, entry->mem_obj->request,
+			httpState->peer ? &httpState->peer->in_addr : 0);
 	if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
 	    /*
 	     * the above storeAppend() call could ABORT this entry,
@@ -904,9 +930,16 @@
     http_state_flags flags)
 {
     const int offset = mb->size;
+    const char *url;
+    
+    url = strLen(request->urlpath) ? strBuf(request->urlpath) : "/";
+    if (request->flags.distify) {
+ 	/* Ask other cache for dist */
+ 	url = (const char *) distifyUrl((char *) url);
+    }
+    
     memBufPrintf(mb, "%s %s HTTP/1.0\r\n",
-	RequestMethodStr[request->method],
-	strLen(request->urlpath) ? strBuf(request->urlpath) : "/");
+	RequestMethodStr[request->method], url);
     /* build and pack headers */
     {
 	HttpHeader hdr;
@@ -983,6 +1016,7 @@
     HttpStateData *httpState;
     request_t *proxy_req;
     request_t *orig_req = fwd->request;
+    peer *peer;
     debug(11, 3) ("httpStart: \"%s %s\"\n",
 	RequestMethodStr[orig_req->method],
 	storeUrl(fwd->entry));
@@ -991,13 +1025,15 @@
     httpState->fwd = fwd;
     httpState->entry = fwd->entry;
     httpState->fd = fd;
+    httpState->body_remain = 0x7fffffff;
     if (fwd->servers)
 	httpState->peer = fwd->servers->peer;	/* might be NULL */
-    if (httpState->peer) {
+    peer = httpState->peer;
+    if (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;
+	xstrncpy(proxy_req->host, peer->host, SQUIDHOSTNAMELEN);
+	proxy_req->port = peer->http_port;
 	proxy_req->flags = orig_req->flags;
 	proxy_req->lastmod = orig_req->lastmod;
 	httpState->request = requestLink(proxy_req);
@@ -1008,8 +1044,12 @@
 	 * 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)
+	if (peer->options.proxy_only)
 	    storeReleaseRequest(httpState->entry);
+	/* Use consistency protocol for this request */
+	if (peer->options.dist) {
+	    httpState->request->flags.distify = 1;
+	}
 #if DELAY_POOLS
 	assert(delayIsNoDelay(fd) == 0);
 	if (httpState->peer->options.no_delay)
@@ -1107,3 +1147,32 @@
     version->major = major;
     version->minor = minor;
 }
+
+/*
+ * Create an httpState parallel to an existing clientHttpRequest
+ * Assumption: http->entry is either zero or locked.
+ */
+HttpStateData *
+httpStateFromClient(clientHttpRequest *http)
+{
+    HttpStateData *httpState;
+
+    /* Make me an httpState */
+    httpState = cbdataAlloc(HttpStateData);
+    
+    /* Fill in the blanks */
+    httpState->entry = http->entry;
+    httpState->request = http->request;
+    httpState->body_remain = 0x7fffffff;
+
+    assert(http->entry->lock_count >= 1);
+    /* Lock entry for a second time to reflect presence in httpState */
+    /* XXX - can't use storeLockObject() because is NOT_IN_MEMORY (!!!) */
+    httpState->entry->lock_count++;
+    assert(http->entry->lock_count >= 2);
+
+    /* Register new request pointer */
+    requestLink(httpState->request);
+
+    return(httpState);
+}
Index: squid/src/icp_data.c
diff -u /dev/null squid/src/icp_data.c:1.1.2.1
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/icp_data.c	Mon Dec 10 14:22:24 2001
@@ -0,0 +1,414 @@
+/*
+ * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * DEBUG: section 83  ICP data transmission
+ * AUTHOR: Jon Kay, 1999
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+static icpUdpData *UdpQueueHead = NULL;
+static icpUdpData *UdpQueueTail = NULL;
+icpQueue UdpCtlQ;
+static List_Links icpFragQ;
+ICPData_Stats icpdata_stats;
+
+static void icpRecvPush(int fd, struct sockaddr_in *from, icp_common_t *,
+			char *buf, int len);
+static icpFragList *icpFragNew(char *buf, int off, int nextoff, int totlen,
+			       icp_common_t *hdr, int isfirst);
+
+static icpFragList *icpFragFree(icpFragList *fl);
+
+
+#define ICP_PUTLINE "PUT %s HTTP/1.0\r\n"
+
+/* Fragment and encapsulate stuff to be sent */
+void
+icpSendData(int vfd, StoreEntry *entry, struct _pusher *p)
+{
+    int fd = theOutIcpConnection;
+    icpQueue *q = p->q;
+    int len, hdrlen, curlen;
+    struct icp_datab_s *dbhdr;
+    struct _http_reply *reply;
+    struct icp_data_s *dhdr;
+    char *firstline, *lnend;
+    icp_common_t *hdr;
+    char *buf, *tbuf;
+    icpUdpData *pktl;
+    int islast = 0;
+    int lchg, nllen, ollen;
+
+    ++icpdata_stats.nsends;
+    debug(12, 5, "icpDataSend: vfd %d fd %d '%s'\n", vfd, fd, entry->key);
+
+    reply = entry->mem_obj->reply;
+    curlen = entry->mem_obj->e_current_len;
+    if (p->objlen == 0)
+	p->objlen = reply->content_length + reply->hdr_sz;
+    
+    if (p->off < p->objlen)
+	/* Reregister handler */
+	/* excess storeRegisters deregistered in putSendDone() call */
+	storeRegister(entry, vfd, (PIF) icpSendData, p);
+
+    while (p->off < curlen) {
+	/* Allocate 8k page, and put AppendUdp and ICP headers at beginning */
+	buf = get_free_8k_page();
+	hdr = (icp_common_t *) buf;
+	tbuf = (char *) &hdr[1];
+
+	/* Fill in ICP header */
+	hdr->version = ICP_VERSION_CURRENT;
+	hdr->flags = 0;
+	hdr->pad = 0;
+	hdr->shostid = htonl(theOutICPAddr.s_addr);
+
+	/* Is this the last fragment? */
+	/* note: object_len == e_current_len iff storeComplete been called */
+	islast = (p->off + 8000 >= entry->mem_obj->e_current_len
+		  && (entry->object_len == curlen || p->objlen <= curlen));
+
+	if (p->off == 0) {
+	    /* First fragment */
+	    p->reqnum = htonl(storeReqnum(entry, METHOD_PUT));
+	    hdr->opcode = ICP_OP_DATABEG;
+	    dbhdr = (struct icp_datab_s *) tbuf;
+	    tbuf = (char *)  &dbhdr->db_data;
+	    dbhdr->db_ttl = htonl(8); /* XXX*/
+	    dbhdr->db_ts = htonl(entry->lastmod);
+	    hdrlen = sizeof(icp_common_t) + 12;
+	}
+	else {
+	    /* Remaining fragments */
+	    hdr->opcode = islast ? ICP_OP_DATAEND : ICP_OP_DATA;
+	    dhdr = (struct icp_data_s *) tbuf;
+	    tbuf = (char *) &dhdr->d_data;
+	    dhdr->d_offset = htonl(p->off);
+	    hdrlen = sizeof(icp_common_t) + 4;
+	}
+	       
+	storeClientCopy(entry, p->off, 8000, tbuf, &len, vfd);
+
+	if (p->off == 0) {
+	    /* Change the first line into a PUT line from a REPLY line */
+	    firstline = xmalloc(sizeof(ICP_PUTLINE) + strlen(entry->url));
+	    sprintf(firstline, ICP_PUTLINE, entry->url);
+	    lnend = strchr(tbuf, '\n');
+	    if (lnend == NULL) {
+		/* Not enough stuff to send. */
+		safe_free(firstline);
+		safe_free(buf);
+		storeUnregister(entry, vfd);
+		return;
+	    }
+	    while (lnend[1] == '\r' || lnend[1] == '\n')
+		++lnend;
+	    ollen = lnend - tbuf + 1;
+	    nllen = strlen(firstline);
+	    lchg = nllen - ollen;
+	    memmove(tbuf + nllen, tbuf + ollen, len - ollen);
+	    xmemcpy(tbuf, firstline, nllen);
+	    p->objlen += lchg;
+	    len += lchg;
+	    dbhdr->db_size = htonl(p->objlen);
+	}
+	    
+        p->off += len;
+	
+	hdr->length = hdrlen + len;
+	hdr->length = htons(hdr->length);
+	hdr->reqnum = p->reqnum;
+	
+	pktl = (icpUdpData *) xmalloc(sizeof(*pktl));
+	pktl->address = q->dst;
+	pktl->msg = buf;
+	pktl->len = hdrlen + len;
+	pktl->start = current_time;
+	pktl->logcode = LOG_TAG_NONE;
+	pktl->proto = PROTO_NONE;
+	AppendUdp(q, pktl);
+	if (q->maxrate)
+	    icpUdpReply(fd, q);
+	else
+	    commSetSelect(fd, COMM_SELECT_WRITE,
+			  (PF) icpUdpReply, (void *) q, 0);
+
+	if (islast)
+	    putSendDone(p->fd, p);
+    }
+
+    if (p->off >= p->objlen)
+	storeUnregister(entry, vfd);
+}
+
+void
+icpRecvData(int fd, struct sockaddr_in *src, icp_common_t *hdr, char *buf, int len)
+{
+    struct icp_datab_s *dbhdr;
+    struct icp_data_s *dhdr;
+    icpFragList *fl, *fl2, *efl;
+    int off, datalen, objlen;
+    int ismerged;
+    char *nbuf;
+    
+    if (len < sizeof(icp_common_t)) {
+	debug(12, 0, "icpRecvData: packet shorter than headers (%d bytes)\n", len);
+	return;
+    }
+    if (len < hdr->length) {
+	debug(12, 0, "icpRecvData: incomplete packet (%d bytes out of %d bytes)\n",
+	      len, hdr->length);
+	return;
+    }
+	
+    if (hdr->opcode == ICP_OP_DATABEG) {
+	dbhdr = (struct icp_datab_s *) buf;
+	buf = (char *) &dbhdr->db_data;
+	datalen = hdr->length - sizeof(icp_common_t) - 12;
+	off = 0;
+	objlen = ntohl(dbhdr->db_size);
+	if (objlen <= datalen) {
+	    /* One packet long - no defrag needed. */
+	    nbuf = xmalloc(objlen + 1);
+	    xmemcpy(nbuf, buf, objlen);
+	    icpRecvPush(fd, src, hdr, nbuf, objlen);
+	    return;
+	}
+    }
+    else if (hdr->opcode == ICP_OP_DATA || hdr->opcode == ICP_OP_DATAEND) {
+	/* A middle fragment */
+	dhdr = (struct icp_data_s *) buf;
+	buf = (char *) &dhdr->d_data;
+	datalen = hdr->length - sizeof(icp_common_t) - 4;
+	off = ntohl(dhdr->d_offset);
+	objlen = 0;
+    }
+    else {
+	debug(12, 0, "icpRecvData: invalid opcode %d\n", hdr->opcode);
+	return;
+    }
+
+    /* Find first fragment, with entry */
+    debug(12, 5, "icpRecvData: id 0x%x defragging %d-%d\n",
+	   hdr->reqnum, off, off + datalen);
+    ++icpdata_stats.nfrags;
+    efl = NULL;
+    ismerged = 0;
+    if (off == 0) {
+	assert(objlen);
+	fl = icpFragNew(buf, off, off + datalen, objlen, hdr, (int) efl);
+	LIST_FORALL2(&fl->links, icpFragList *, fl2); {
+	    /* Look for more fragments */
+	  loopstart:
+	    if (fl2->hdr.reqnum == hdr->reqnum && fl2->off == fl->nextoff) {
+		/* Consolidate this fragment */
+		
+		if (fl2->off == 0) {
+		    /* this is a dup */
+		    ++icpdata_stats.ndups;
+		    icpFragFree(fl);
+		    return;
+		}
+		
+		/* merge data */
+		if (fl->nextoff < fl2->nextoff)
+		    fl->nextoff = fl2->nextoff;
+		xmemcpy(fl->buf + fl2->off, fl2->buf, fl2->nextoff - fl2->off);
+
+		/* delete old fragment */
+		fl2 = icpFragFree(fl);
+		
+		goto loopstart;
+	    }
+	}
+    }
+    else {
+	LIST_FORALL2(&icpFragQ, icpFragList *, fl) {
+	    if (fl->hdr.reqnum == hdr->reqnum && fl->off == 0) {
+		if (!efl)
+		    efl = fl;
+		if (fl->nextoff == off) {
+		    /* Append to this packet */
+		    fl->nextoff += datalen;
+		    xmemcpy(fl->buf + off, buf, datalen);
+		    ismerged = 1;
+		    if (fl->off == 0 && fl->objlen > 0 && fl->nextoff >= fl->objlen) {
+			/* Assembly complete*/
+			icpRecvPush(fd, src, &fl->hdr, fl->buf, fl->objlen);
+			fl->buf = 0;
+			icpFragFree(fl);
+			return;
+		    }
+		}
+	    }
+	}
+	if (!ismerged)
+	    icpFragNew(buf, off, off + datalen, objlen, hdr, (int) efl);
+    }
+}
+
+static icpFragList *
+icpFragNew(char *buf, int off, int nextoff, int objlen,
+	   icp_common_t *hdr, int isfirst)
+{
+    icpFragList *fl;
+    int len;
+
+    fl = (icpFragList *) xmalloc(sizeof *fl);
+    List_Insert(&fl->links, LIST_ATREAR(&icpFragQ));
+
+    len = (off ? nextoff - off : objlen + 1);
+    fl->buf = xmalloc(len + 1);
+    
+    xmemcpy(fl->buf, buf, nextoff - off);
+    fl->lasttime = squid_curtime;
+    fl->hdr = *hdr;
+    fl->off = off;
+    fl->nextoff = nextoff;
+    fl->objlen = objlen;
+
+    return(fl);
+}
+
+static icpFragList *
+icpFragFree(icpFragList *fl)
+{
+    icpFragList *nfl;
+    
+#if 0
+    printf("icpFragFree: id 0x%x freeing %d-%d obj at 0x%x\n",
+	   fl->hdr.reqnum, fl->off, fl->nextoff, fl->buf);
+#endif
+    nfl = (icpFragList *) List_Next(&fl->links);
+    List_Remove(&fl->links);
+    if (fl->buf)
+	safe_free(fl->buf);
+    safe_free(fl);
+    return(nfl);
+}
+
+static void
+icpFragTimer()
+{
+    icpFragList *fl;
+#if 0 /* JSKDEBUG */
+    int nfrags = 0, mem = 0;
+#endif    
+
+    eventAdd("icpdata fragment timer", (EVH) icpFragTimer, NULL,
+	     Config.icp_frag_tmo);
+    
+    LIST_FORALL2(&icpFragQ, icpFragList *, fl) {
+      loopstart:
+	if ((char *) fl != (char *) &icpFragQ) {
+#if 0 /* JSKDEBUG */
+	    ++nfrags;
+	    mem += fl->objlen + sizeof(*fl);
+#endif    
+	    if (squid_curtime - fl->lasttime >= Config.icp_frag_tmo) {
+		++icpdata_stats.ntmofrags;
+		fl = icpFragFree(fl);
+		goto loopstart;
+	    }
+	}
+    }
+#if 0 /* JSKDEBUG */
+    printf("icpFragTimer: %d frags, for total of %d bytes used\n",
+	   nfrags, mem);
+#endif    
+}
+
+
+static void
+icpRecvPush(int fd, struct sockaddr_in *src, icp_common_t *hdr,char *buf, int len)
+{
+    icpStateData *icpState = xcalloc(sizeof(icpStateData), 1);
+    request_t *request = NULL;
+    int err;
+
+    debug(12, 3, "icpRecvPush on fd %d: Hi!\n", fd);
+    ++icpdata_stats.nrecvs;
+
+    /* Construct icpState */
+    icpState->start = current_time;
+    icpState->inbuf = buf;
+    icpState->inbufsize = 8192;
+    icpState->header = *hdr;
+    icpState->peer = *src;
+    icpState->log_addr = src->sin_addr;
+    icpState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr;
+    icpState->log_type = LOG_UDP_PUT;
+    icpState->me = *getMyAddr();
+    icpState->me.sin_port = Config.Port.icp;
+    icpState->entry = NULL;
+    icpState->in_offset = len;
+    icpState->fd = comm_virtual_fd();
+    
+    fd_note(fd, inet_ntoa(icpState->log_addr));
+    comm_add_close_handler(icpState->fd, icpStateFree, (void *) icpState);
+    
+    err = parseHttpRequest(icpState);
+    icpState->inbuf[icpState->in_offset] = '\0';    /* Terminate the string */
+    if (err == 1) {
+	if ((request = urlParse(icpState->method, icpState->url)) == NULL) {
+	    debug(12, 0, "icpRecvPush: Invalid URL: %s\n", icpState->url);
+	    return;
+	}
+	safe_free(icpState->log_url);
+	icpState->log_url = xstrdup(urlCanonicalClean(request));
+	request->http_ver = icpState->http_ver;
+	if (!urlCheckRequest(request)) {
+	    debug(12, 0, "icpRecvPush: Invalid request: %s\n");
+	    return;
+	}
+	icpState->request = requestLink(request);
+
+	/* XXX - Uncomment to make acls work with icpdata pushes */
+	/* Currently causes core dump, needs debugging */
+	/* clientAccessCheck(icpState, clientAccessCheckDone);*/
+    }
+    else if (err == 0) {
+	debug(12, 0, "icpRecvPush: got partial request\n");
+	return;
+    }
+    else { /* err == -1 */
+	debug(12, 0, "icpRecvPush: got invalid request\n");
+	return;
+    }
+
+    putRecv(icpState);
+}
+
+void
+icpDataInit()
+{
+    List_Init(&icpFragQ);
+    List_Init(&UdpCtlQ.links);
+    UdpCtlQ.nextsend.tv_sec = UdpCtlQ.nextsend.tv_usec = 0;
+    UdpCtlQ.maxrate = 0;
+    eventAdd("icpdata fragment timer", (EVH) icpFragTimer, NULL,
+	     Config.icp_frag_tmo);
+}
Index: squid/src/icp_v2.c
diff -u squid/src/icp_v2.c:1.6 squid/src/icp_v2.c:1.5.14.3
--- squid/src/icp_v2.c:1.6	Fri Aug  9 14:46:02 2002
+++ squid/src/icp_v2.c	Tue Sep  3 10:41:49 2002
@@ -302,6 +302,14 @@
 	neighborsUdpAck(key, &header, &from);
 	break;
 
+#if USE_ICP_DATA
+    case ICP_OP_DATABEG:
+    case ICP_OP_DATA:
+    case ICP_OP_DATAEND:
+	icpRecvData(fd, &from, &header, buf + sizeof(header), len);
+	break;
+#endif
+
     case ICP_INVALID:
     case ICP_ERR:
 	break;
Index: squid/src/icp_v3.c
diff -u squid/src/icp_v3.c:1.5 squid/src/icp_v3.c:1.4.44.3
--- squid/src/icp_v3.c:1.5	Fri Aug  9 14:46:02 2002
+++ squid/src/icp_v3.c	Tue Sep  3 10:41:49 2002
@@ -143,6 +143,14 @@
 	neighborsUdpAck(key, &header, &from);
 	break;
 
+#if USE_ICP_DATA
+    case ICP_OP_DATABEG:
+    case ICP_OP_DATA:
+    case ICP_OP_DATAEND:
+	icpRecvData(fd, &from, &header, buf + sizeof(header), len);
+	break;
+#endif
+
     case ICP_INVALID:
     case ICP_ERR:
 	break;
Index: squid/src/main.c
diff -u squid/src/main.c:1.36 squid/src/main.c:1.28.2.6
--- squid/src/main.c:1.36	Thu Aug  8 12:41:58 2002
+++ squid/src/main.c	Tue Sep  3 10:41:51 2002
@@ -336,6 +336,7 @@
     externalAclShutdown();
     storeDirCloseSwapLogs();
     errorClean();
+    distInit();
     enter_suid();		/* root to read config file */
     parseConfigFile(ConfigFile);
     setEffectiveUser();
@@ -511,6 +512,12 @@
 #if DELAY_POOLS
 	delayPoolsInit();
 #endif
+#if USE_HINT_CACHE
+	hintCacheInit();
+#endif	
+#if USE_ICP_DATA
+	icpDataInit();
+#endif
 	fwdInit();
     }
 #if USE_WCCP
@@ -626,6 +633,7 @@
 	eventInit();		/* eventInit() is required for config parsing */
 	storeFsInit();		/* required for config parsing */
 	authenticateSchemeInit();	/* required for config parsign */
+	distInit();             /* Needed for fwdall list */
 	parse_err = parseConfigFile(ConfigFile);
 
 	if (opt_parse_cfg_only)
Index: squid/src/mem.c
diff -u squid/src/mem.c:1.20 squid/src/mem.c:1.13.8.1
--- squid/src/mem.c:1.20	Sat Jul 20 18:06:07 2002
+++ squid/src/mem.c	Tue Sep  3 10:41:52 2002
@@ -323,10 +323,6 @@
 memInit(void)
 {
     int i;
-
-    debug(13, 1) ("Memory pools are '%s'; limit: %.2f MB\n",
-	(Config.onoff.mem_pools ? "on" : "off"), toMB(mem_idle_limit));
-
     /* set all pointers to null */
     memset(MemPools, '\0', sizeof(MemPools));
     /*
Index: squid/src/neighbors.c
diff -u squid/src/neighbors.c:1.19 squid/src/neighbors.c:1.14.2.2
--- squid/src/neighbors.c:1.19	Wed Aug 28 14:45:44 2002
+++ squid/src/neighbors.c	Tue Sep  3 10:41:53 2002
@@ -38,6 +38,8 @@
 /* count mcast group peers every 15 minutes */
 #define MCAST_COUNT_RATE 900
 
+
+
 static int peerAllowedToUse(const peer *, request_t *);
 static int peerWouldBePinged(const peer *, request_t *);
 static void neighborRemove(peer *);
Index: squid/src/protos.h
diff -u squid/src/protos.h:1.59 squid/src/protos.h:1.41.2.7
--- squid/src/protos.h:1.59	Sat Jul 20 05:33:16 2002
+++ squid/src/protos.h	Tue Sep  3 10:41:54 2002
@@ -180,6 +180,9 @@
 extern void commCloseAllSockets(void);
 extern void checkTimeouts(void);
 extern int commDeferRead(int fd);
+#if USE_ICP_DATA
+extern int comm_virtual_fd(void);
+#endif /* USE_ICP_DATA */
 
 
 /*
@@ -313,6 +316,9 @@
 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 HttpStateData *httpStateFromClient(clientHttpRequest *http);
+extern PF httpReadReply;
+extern PF httpStateFree;
 extern const char *httpMakeVaryMark(request_t * request, HttpReply * reply);
 
 /* ETag */
@@ -532,6 +538,12 @@
     int reqnum,
     int pad);
 extern int icpUdpSend(int, const struct sockaddr_in *, icp_common_t *, log_type, int);
+#if USE_ICP_DATA
+void icpSendData(int vfd, StoreEntry *entry, struct _pusher *p);
+void icpRecvData(int fd, struct sockaddr_in *src, icp_common_t *hdr,
+		 char *buf, int len);
+void icpDataInit();
+#endif
 extern PF icpHandleUdp;
 extern PF icpUdpSendQueue;
 extern PF httpAccept;
@@ -1102,7 +1114,8 @@
 
 extern char *url_convert_hex(char *org_url, int allocate);
 extern char *url_escape(const char *url);
-extern protocol_t urlParseProtocol(const char *);
+extern protocol_t urlParseProtocol(const char *, u_short *,
+				   int *);
 extern method_t urlParseMethod(const char *);
 extern void urlInitialize(void);
 extern request_t *urlParse(method_t, char *);
@@ -1288,6 +1301,26 @@
 extern void logfilePrintf(va_alist);
 #endif
 
+/* put.c */
+void putRecv(clientHttpRequest *);
+Pusher *putSend(StoreEntry *, struct sockaddr_in *, PF, void *,
+		int dodist);
+void putSendDone(int fd, void *data);
+void putReplyAndClose(int, StoreEntry *);
+void statPutPrint(StoreEntry * sentry);
+
+/* dist.c */
+extern Updatee *distNewUpdatee(StoreEntry *entry,
+			       struct in_addr host, u_short dport);
+extern void distDelUpdatees(Updatee *u);
+extern void distDelUpdatee(StoreEntry *entry, struct in_addr host, int dport);
+extern void distUpdateeChangeEntry(StoreEntry *entry, Updatee *u);
+extern void distEntryUpdate(StoreEntry *e, request_t *req,
+				     struct sockaddr_in *peer);
+extern char *distifyUrl(char *url);
+extern void distInputDone(StoreEntry *);
+void distInit();
+
 /*
  * Removal Policies
  */
@@ -1312,6 +1345,146 @@
  */
 extern StatCounters *snmpStatGet(int);
 
+
+#if USE_HINT_CACHE
+/* Hint Cache Interface */
+/* open existing cache; return nonzero on error */
+int hintCacheInit();
+void hintCacheCreate();              /* create new cache */
+void hintCacheDestroy();
+void hintCacheInformLocalCopy(StoreEntry *); /* tell hierarchy I have a copy */
+void hintCacheInvalLocalCopy(StoreEntry *); /* say I don't have a copy */
+int hintCacheActive();  /* Ask hint cache if it is operational. */
+struct sockaddr_in *hintCachefindNearest(char *url, struct sockaddr_in *);
+
+void hintCacheNodeKeyInit(NodeKey *k, const struct sockaddr_in *addrP);
+int hintCacheNodeKeyCompare(const NodeKey *k1, const NodeKey *k2);
+struct sockaddr_in hintCacheNodeKeyGetAddr(const NodeKey *k);
+HintCacheKey hintCacheNodeKeyKey(const struct sockaddr_in *addrP);
+
+void hintCacheEntryInit(HintCacheEntry *, URLKey, struct sockaddr_in *,
+			   unsigned int mtime);
+int hintCacheEntryCompare(HintCacheEntry *e1, HintCacheEntry *e2);
+void hintCacheEntryInitNet(HintCacheEntryNet *mungedEntry, HintCacheEntry *entry);
+void hintCacheEntryLocalFormatNet(HintCacheEntryNet *mungedEntry, HintCacheEntry *entry);
+
+int hintCacheUpdateCompare(HintCacheUpdate *u1, HintCacheUpdate *u2);
+void hintCacheUpdateInit(HintCacheUpdate *, int action, HintCacheEntry *, int hopcount);
+
+void hintCacheUpdateInitNet(HintCacheUpdateNet *mungedUpdate, HintCacheUpdate *update);
+void hintCacheUpdateLocalFormatNet(HintCacheUpdateNet *mungedUpdate, HintCacheUpdate *update);
+int hintCacheURLKeyCompare(URLKey *u1, URLKey *u2);
+StoreEntry *hintCacheStoreGet(URLKey urlkey);
+
+
+/* Hint Cache Disk */
+void hintCacheDiskInit(HintCacheDisk *d, char *diskPath);
+void hintCacheDiskClose(HintCacheDisk *d);
+void hintCacheDiskCreateFile(char *hcPath, int size, int associativity);
+void hintCacheDiskInformLocal(HintCacheDisk *d, URLKey key, unsigned mtime);
+void hintCacheDiskInvalLocal(HintCacheDisk *d, URLKey key, unsigned mtime);
+void hintCacheDiskPrefetch(HintCacheDisk *d, HintCacheUpdate *uArray, int nupdates);
+int hintCacheDiskNetInvalRecord(HintCacheDisk *d, HintCacheEntry *target, HintCacheEntry *survivor);
+int hintCacheDiskUpdateIfCloser(HintCacheDisk *d, HintCacheEntry *new);
+int hintCacheDiskFindNearest(HintCacheDisk *d, URLKey key, HintCacheEntry *match);
+void hintCacheDiskDeleteHintCache();
+
+long long unsigned  hintCacheEndian_llNetToMachine(long long unsigned net);
+long long unsigned hintCacheEndian_llMachineToNet(long long unsigned  mach);
+void hintCacheEndian_selfTest(void);
+
+void hintCacheInitNet(HintCacheNet *n);
+int hintCacheNetIsInitialized(void);
+ void hintCacheNetDestroy(HintCacheNet *n);
+void hintCacheNetEnqueue(HintCacheNet *, int action,
+			  HintCacheEntry *, int hopcount);
+int hintCacheNetBytesReady(HintCacheNet *n);
+void hintCacheNetComplete(HintCacheNet *n);
+void hintCacheNetDone(HintCacheNet *n);
+void hintCacheNetSendTo(HintCacheNet *, struct sockaddr_in *);
+void hintCacheNetSendJoin();
+void hintCacheNetDataArrives(char *data, int len, HintCacheNetHeader *hdr,
+				struct sockaddr_in *source);
+void hintCacheNetSetTestMode(HintCacheNet *n);
+int hintCacheNetGetTestCount(HintCacheNet *n);
+
+void hintCachePropLocalAction(StoreEntry *, int action);
+void hintCachePropHandleInvalToChild(HintCacheUpdate *update,
+				      struct sockaddr_in *src, int local);
+void hintCachePropHandleInformToChild(HintCacheUpdate *update,
+				       struct sockaddr_in *src, int local) ;
+void hintCachePropHandleInvalToParent(HintCacheUpdate *update,
+				       struct sockaddr_in *src, int local);
+void hintCachePropHandleInformToParent(HintCacheUpdate *update,
+					struct sockaddr_in *src, int local);
+
+void hintCacheNodelistInit(); /* constructor */
+void hintCacheNodelistDestroy(); /* destructor */
+void hintCacheNodelistSelfTest();
+void hintCacheNodelistLocalJoin(); /* I do a join */
+void hintCacheNodelistLocalLeave(); /* I do a leave */
+int hintCacheNodelistMyStatus(); /* Am I in or out? */
+void hintCacheNodelistNetJoin(struct sockaddr_in *sin, int hops, long long timeNS);
+void hintCacheNodelistNetLeave(struct sockaddr_in *sin, int hops, long long timeNS);
+void hintCacheNodelistIterStart(HintCacheNodeListIter *iter);
+int hintCacheNodelistIterCheck(HintCacheNodeListIter iter);
+void hintCacheNodelistIterNext(HintCacheNodeListIter *iter);
+int hintCacheNodelistIterGetAddr(HintCacheNodeListIter iter,
+				  struct sockaddr_in *ret);
+
+void hintCacheHierUpdateMembershipNeighbor(struct sockaddr_in *neighbor, 
+                                     NeighborAction);
+void hintCacheHierInit();
+void hintCacheHierDestroy();
+int hintCacheHierCompareDistanceFromMe(struct in_addr new, struct in_addr old);
+void hintCacheHierNewNode(struct sockaddr_in *sin, int hops, long long time);
+void hintCacheHierDelNode(struct sockaddr_in *sin, int hops, long long time);
+int hintCacheHierCheckIfParent(URLKey key, struct sockaddr_in *candidate);
+int hintCacheHierCheckIfChild(struct sockaddr_in *candidate);
+void hintCacheHierAddChild(struct sockaddr_in *child);
+void hintCacheHierRemoveChild(struct sockaddr_in *child);
+int hintCacheHierNChildrenQs();
+int hintCacheHierChildQIndex(URLKey *key, int iAmRoot, int *amILeaf);
+int hintCacheHierGetChildAddrs(int qIndex, struct sockaddr_in **retAddr);
+int hintCacheHierNParentQs();
+int hintCacheHierParentQIndex(URLKey *key, int *amIRoot);
+int hintCacheHierGetParentAddr(int index, struct sockaddr_in *retAddr);
+int hintCacheHierSendToParent(struct sockaddr_in *src, HintCacheUpdate *update,
+				 int msgtype);
+int hintCacheHierSendToSiblings(struct sockaddr_in *src, HintCacheUpdate *update,
+				   int msgtype, int siblingtype);
+
+#ifdef USE_DYNAMIC_HIERARCHY
+/* Plaxton Dynamic Hierarchy algorithm */
+void plaxtonInit(int bitsPerLevel);
+void plaxtonDestroy();
+int plaxtonChildQIndex(URLKey *key, int iAmRoot, int *amILeaf);
+int plaxtonNChildrenQsI();
+int plaxtonGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP);
+int plaxtonNParentQs();
+int plaxtonParentQIndex(URLKey *key, int *amIRoot);
+int plaxtonGetParentAddr(int index, struct sockaddr_in *retAddr);
+/*
+ * Callbacks when nodes added/removed/change distance 
+ */
+void plaxtonAddNode(struct sockaddr_in *newNode);
+void plaxtonRemoveNode(struct sockaddr_in *goneNode);
+void plaxtonChangeDistance(struct sockaddr_in *changeDistNode);
+int plaxtonCheckIfParent(URLKey key, struct sockaddr_in *candidate);
+int plaxtonCheckIfChild(struct sockaddr_in *candidate);
+void plaxtonAddChild(struct sockaddr_in *child);
+void plaxtonRemoveChild(struct sockaddr_in *child);
+int plaxtonMatchBits(HintCacheKey k1, HintCacheKey k2);
+HintCacheKey plaxtonMyNodeKey();
+
+extern int Plaxton_BucketsPerLevel;
+extern HintCacheNet *Plaxton_parentOutgoingA;
+extern HintCacheNet *Plaxton_childrenOutgoingA;
+extern HintCacheNet *Plaxton_neighborsOutgoing;
+#endif /* USE_DYNAMIC_HIERARCHY / Plaxton algorithm */
+
+#endif /* USE_HINT_CACHE */
+
 /* Vary support functions */
 int varyEvaluateMatch(StoreEntry * entry, request_t * req);
 
Index: squid/src/put.c
diff -u /dev/null squid/src/put.c:1.1.2.7
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/put.c	Tue Sep  3 10:41:55 2002
@@ -0,0 +1,457 @@
+/*
+ * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * DEBUG: section 81  PUT transmission and reception
+ * AUTHOR: Jon Kay, 1997
+ *
+ * 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.
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+#include "squid.h"
+
+#define PUT_REPLY_HDR()     "HTTP/1.0 200 OK\r\n"
+
+#define PUT_DELETE_GAP   (1<<18)
+
+static PF putRecvFree;
+static void putRecvError(clientHttpRequest *http,
+			 err_type error, http_status entry);
+static void putProcessHeader(HttpStateData *, clientHttpRequest *);
+static void putSendWrite(void *data, char *buf, ssize_t len);
+static CNCB putConnected;
+static CWCB putSendSent;
+
+/*
+ * Code for dealing with incoming PUT requests
+ */
+void
+putRecv(clientHttpRequest *http)
+{
+    request_t *request = http->request;
+    ConnStateData *conn = http->conn;
+    StoreEntry *entry, *oentry;
+    int lastmod, olastmod = -1;
+    HttpStateData *httpState;
+    request_flags rflags;
+    HttpReply *reply;
+    peer *p;
+    
+    http->request->flags.cachable = 1;
+    if (http->log_type != LOG_UDP_PUT)
+	http->log_type = LOG_TCP_PUT;
+    http->out.offset = 0;
+
+    oentry = storeGetPublic(http->uri, request->method);
+    if (oentry) {
+	olastmod = oentry->lastmod;
+	storeSetPrivateKey(oentry);
+    }
+    
+    /* Create private, blank entry */
+    *(unsigned int *) &rflags = 0;
+    rflags.cachable = 1;
+    entry = storeCreateEntry(http->uri, http->uri, rflags, request->method);
+
+    http->entry = entry;
+
+    /* Need a request pointer in the mem_obj */
+    requestLink(http->request);
+    entry->mem_obj->request = request;
+    
+    debug(81, 4) ("putRecv: %s for '%s'\n", log_tags[http->log_type],
+	  http->uri);
+
+    /* Update timestamp */
+    storeTimestampsSet(entry);
+
+    /* Create an HTTP context from client_side info */
+    assert(http->entry->lock_count >= 1 && http->entry->lock_count < 200);
+    httpState = httpStateFromClient(http);
+    assert(http->entry->lock_count >= 2 && http->entry->lock_count < 200);
+    httpState->entry = entry;
+    /* Prepare to reply and free httpState if PUT succeeds. */
+    comm_add_close_handler(conn->fd, putRecvFree, httpState);
+    
+    assert(http->entry->lock_count >= 2 && http->entry->lock_count < 200);
+    /* Parse the headers */
+    putProcessHeader(httpState, http);
+    reply = entry->mem_obj->reply;
+
+    /* Update the timestamp */
+    lastmod = entry->mem_obj->reply->last_modified;
+    if (lastmod > -1) {
+	if (lastmod < olastmod) {
+	    /* We do not accept old versions */
+	    ++statCounter.put.conflicts;
+	    putRecvError(http, ERR_CONFLICT, HTTP_CONFLICT);
+	    if (oentry)
+		storeSetPublicKey(oentry);
+	    /* putRecvFree will clean up on fd close */
+	    return;
+	}
+	/* Note: it's OK to overwrite the same version.  It just won't be
+	   propagated. */
+        entry->lastmod = lastmod;
+    }
+    else
+        /* Make it clear the version has changed even if no lastmod */
+        entry->lastmod = olastmod + 1;
+
+    if (oentry) {
+	/* This PUT request is good to go in.
+	 * Lose the old entry. */
+	distUpdateeChangeEntry(entry, oentry->updatees);
+	oentry->updatees = 0;
+	storeRelease(oentry);
+    }
+
+    /* Make sure dist knows about the sender, and distribute the update */
+    if (request->dist_type == DIST_DIST)
+        distNewUpdatee(entry, conn->peer.sin_addr, request->dist_port);
+    else if (request->dist_type == DIST_UNDIST)
+        distDelUpdatee(entry, conn->peer.sin_addr, request->dist_port);
+    distEntryUpdate(entry, request, &conn->peer);
+    
+    /* fwdpush support */
+    if (http->log_type == LOG_TCP_PUT) {
+        for (p = DistAllPeers; p; p = p->fwdpush) {
+#if USE_ICP_DATA
+	    if (p->options.icpdata) {
+	        putSend(entry, &p->in_addr, NULL, NULL, P_ICPDATA, p->icp_data_q);
+	    }
+	    else {
+#endif
+		struct sockaddr_in sin;
+		
+	        sin.sin_family = AF_INET;
+		sin.sin_addr = p->in_addr.sin_addr;
+		sin.sin_port = htons(p->http_port);
+		putSend(entry, &sin, NULL, NULL, 0);
+#if USE_ICP_DATA
+	    }
+#endif
+	}
+    }
+
+    /* Update stats */
+    ++statCounter.put.ins;
+
+    /* XXX - Can we use httpReplyParse to simplify this? */
+    
+    /* httpReadReply reads msgs with bodies */
+    if (entry->mem_obj->inmem_hi < reply->content_length + reply->hdr_sz) {
+	httpReadReply(conn->fd, httpState);
+    }
+    else
+	putReplyAndClose(conn->fd, entry);
+}
+
+
+/* Process PUT header. */
+static void
+putProcessHeader(HttpStateData *httpState, clientHttpRequest *client)
+{
+    static char replline[] = "HTTP/1.0 200 OK";
+    char *hdr = client->hdr_str;
+    ConnStateData *conn = client->conn;
+    int hdrlen;
+    int bodylen = conn->in.offset;  /* !yep! */
+    char *eol;
+
+    /* First change the PUT first line to a reply first line */
+    eol = strchr(hdr, '\r');
+    eol[0] = '\0';
+    strcpy(hdr, replline);
+    memset(hdr + sizeof(replline) - 1, ' ', eol - hdr - sizeof(replline) + 1);
+    eol[0] = '\r';
+
+    hdrlen = strlen(hdr);
+
+    httpProcessReplyHeader(httpState, hdr, hdrlen);
+    debug(81, 6) ("putProcessHeader: need %d bytes\n", httpState->body_remain);
+    
+    /* store header and start of data */
+    storeAppend(client->entry, hdr, hdrlen);
+    if (bodylen > 0)
+	storeAppend(client->entry, conn->in.buf, bodylen);
+    
+    httpState->body_remain -= client->entry->mem_obj->inmem_hi;
+    debug(81, 6) ("putProcessHeader: got %d bytes, %d remain\n",
+	   hdrlen + bodylen, httpState->body_remain);
+}
+
+void
+putClose(int fd, char *buf, size_t size, int errflag, void *data)
+{
+    comm_close(fd);        /* close fd and call putRecvFree */
+}
+
+void
+putReplyAndClose(int fd, StoreEntry *entry)
+{
+    storeComplete(entry);
+    
+    /* PUT succeeded, acknowledge this. */
+    if (entry->mem_obj->reply->sline.status == 200) {
+	debug(81, 6) ("putReplyAndClose: replying on %d\n", fd);
+	comm_write(fd, PUT_REPLY_HDR(), sizeof(PUT_REPLY_HDR()),
+		   putClose, 0, 0);
+    }
+    else {
+	/* Already aborted, hopefully with error msg */
+	debug(81, 2) ("putReplyAndClose: not replying - code = %d\n",
+	       entry->mem_obj->reply->sline.status);
+	comm_close(fd);        /* close fd and call putRecvFree */
+    }
+}
+
+static void
+putRecvFree(int fd, void *data)
+{
+    HttpStateData *httpState = data;
+    StoreEntry *entry = httpState->entry;
+
+    kb_incr(&statCounter.put.kbytes_in, entry->mem_obj->inmem_hi);
+    
+    httpStateFree(fd, httpState);
+    assert(entry->lock_count >= 1);
+    /* Last unlock will be from httpRequestFree */
+}
+
+static void
+putRecvError(clientHttpRequest *http,
+	     err_type error, http_status status)
+{
+    ErrorState *err;
+    
+    http->log_type = LOG_TCP_DENIED;
+    err = errorCon(error, status);
+    err->request = requestLink(http->request);
+    err->src_addr = http->conn->peer.sin_addr;
+    http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
+    errorAppendEntry(http->entry, err);
+}
+
+
+/* Output PUTs */
+
+/*
+ * Make up and send a PUT to a given location.
+ *
+ * The sockaddr_in does not have to persist when
+ * the call completes.
+ */
+Pusher *
+putSend(StoreEntry *entry, struct sockaddr_in *saddr,
+	PF *handler, void *arg, int dodist)
+{
+    struct in_addr nobody;
+    Pusher *p;
+    int fd;
+
+    /* Allocate memory for buffer and state tracking */
+    storeLockObject(entry);   /* Yes, we need this, even on top of StoreClient. */
+    p = cbdataAlloc(Pusher);
+    p->hdr.sc = storeClientListAdd(entry, p); 
+    p->hdr.flags.disting = dodist;
+    p->hdr.flags.active = 1;
+    p->hdr.off = 0;
+    p->hdr.objlen = 0;
+    p->hdr.entry = entry;
+    p->hdr.handler = handler;
+    p->hdr.arg = arg;
+#if USE_ICP_DATA
+    if (flags & P_ICPDATA) {
+	p->hdr.fd = comm_virtual_fd();
+	p->hdr.q = q;
+	q->dst = *saddr;
+	icpSendData(p->hdr.fd, entry, p);
+	return(p);
+    }
+    else
+	p->hdr.q = 0;
+#endif
+
+    /* Need to create and connect a PUT socket */
+    nobody.s_addr = INADDR_ANY;
+    p->hdr.fd = fd = comm_open(SOCK_STREAM, 0, nobody, 0, COMM_NONBLOCKING, "put");
+    if (fd == COMM_ERROR) {
+	debug(11, 1) ("putSend: Could not create new socket.\n");
+	putSendDone(-1, p);
+	return(0);
+    }
+    
+    /* Deal with socket closing */
+    comm_add_close_handler(fd, putSendDone, p);
+    
+    ++statCounter.put.outs;
+
+    /* Connect to this updatee */
+    strcpy(p->hdr.hname, inet_ntoa(saddr->sin_addr));
+    commConnectStart(fd, p->hdr.hname, ntohs(saddr->sin_port),
+		     putConnected, p);
+
+    return(p);
+}
+
+/* Update given updatee on contents of entry */
+static void
+putConnected(int fd, int commstat, void *data)
+{
+    Pusher *p = (Pusher *) data;
+    StoreEntry *entry = p->hdr.entry;
+    char *url;
+    
+    if (commstat == COMM_ERROR) {
+	/* XXX - this should be more sophisticated */
+	debug(11, 1) ("putConnected: Could not connect to %s\n", p->hdr.hname);
+	putSendDone(fd, p);
+	return;
+    }
+    
+    /* Figure out what URL to use */
+    url = entry->mem_obj->url;
+    if (p->hdr.flags.disting) {
+	url = distifyUrl(url);
+    }
+    
+    /* Compose header */
+    snprintf(p->data, sizeof(p->data), "PUT %s HTTP/1.0\r\n", url);
+    p->hdr.off = -strlen(p->data);
+    
+    /* Write object asynchronously, starting with header */
+    comm_write(fd, p->data, strlen(p->data), putSendSent, p, 0);
+}
+
+/* Xfer data from mem_obj to updatee */
+/* XXX - duplication with icpSendMoreData, etc. */
+static void
+putSendSent(int fd, char *obuf, size_t size, int errflag, void *data)
+{
+    Pusher *p = (Pusher *) data;
+    StoreEntry *entry = p->hdr.entry;
+    
+    debug(53, 5) ("putSendSent: FD %d '%s'\n", fd, entry->mem_obj->url);
+
+    if (errflag) {
+	debug(53, 3) ("putSendSent: write failed, errno %d\n", errno);
+	putSendDone(fd, p);
+	return;
+    }
+    
+    p->hdr.off += size;
+    
+    if (p->hdr.off >= entry->mem_obj->inmem_hi) {
+	/* We've sent everything we've seen so far */
+	if (entry->mem_obj->object_sz == entry->mem_obj->inmem_hi) {
+	    /* We've seen all we're gonna see of this version */
+	    /* note: object_len == inmem_hi iff storeComplete been called */
+	    putSendDone(fd, p);
+	    return;
+	}
+    }
+
+    storeClientCopy(p->hdr.sc, entry, p->hdr.off, 
+		    sizeof(p->data) - p->hdr.off,
+		    p->data, putSendWrite, p);
+}
+
+/* xlate storeClientCopy calling conventions to comm_write ones */
+static void
+putSendWrite(void *data, char *buf, ssize_t len)
+{
+    Pusher *p = (Pusher *) data;
+    int skipped;
+    char *tbuf;
+    
+    /*
+     * Skip over the first line, if this is the first call to putSendSent
+     * and that first line starts with HTTP/1.x.  That would be the first
+     * line in a server reply, and is incorrect in a PUT request.
+     */
+    if (p->hdr.off == 0) {
+        tbuf = strchr(p->data, '\n');
+	if (!tbuf)
+	    /* Malformatted or not enough data present yet.
+	     * Either way, don't propagate this message. */
+	    return;
+	
+	while (*++tbuf == '\r')
+	    ;
+	skipped = tbuf - p->data;
+	p->hdr.off += skipped;
+	len -= skipped;
+	buf += skipped;
+    }
+    else
+	tbuf = p->data;
+  
+    /* Do the work. */
+    comm_write(p->hdr.fd, buf, len, putSendSent, p, 0);
+}
+
+/* Send the object's data */
+void
+putSendDone(int fd, void *data)
+{
+    Pusher *p = data;
+    StoreEntry *entry = p->hdr.entry;
+
+    if (!(p->hdr.flags.active))
+	return;
+    p->hdr.flags.active = 0;
+
+    if (p->hdr.handler)
+	(*p->hdr.handler)(fd, p->hdr.arg);	
+    
+    kb_incr(&statCounter.put.kbytes_out, p->hdr.off);
+    storeUnregister(p->hdr.sc, entry, (void *) fd);
+    storeUnlockObject(entry);
+    
+    /* Free 8k buffer and pusher state along with it */
+    cbdataFree(p);
+
+    /* Don't close if ICP - ICP sends via theIcpOutConnection,
+     * which we cannot afford to close. */
+    if (fd != -1)
+	comm_close(fd);
+}
+
+
+/* Report on push stats */
+void
+statPutPrint(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "PUT Statistics:\n\n");
+    storeAppendPrintf(sentry, "PUTs Sent: %d\n",
+		      statCounter.put.outs);
+    storeAppendPrintf(sentry, "PUT KBytes Sent: %d\n",
+		      (int) statCounter.put.kbytes_out.kb);
+    storeAppendPrintf(sentry, "PUTs Received: %d\n", 
+		      statCounter.put.ins);
+    storeAppendPrintf(sentry, "PUT KBytes Received: %d\n", 
+		      (int) statCounter.put.kbytes_in.kb);
+    storeAppendPrintf(sentry, "Stale Objects Received: %d\n", 
+		      statCounter.put.conflicts);
+}
Index: squid/src/squid.h
diff -u squid/src/squid.h:1.19 squid/src/squid.h:1.13.2.3
--- squid/src/squid.h:1.19	Sun Sep  1 09:30:42 2002
+++ squid/src/squid.h	Tue Sep  3 10:41:56 2002
@@ -410,6 +410,10 @@
 #include "snprintf.h"
 #endif
 
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
 #define XMIN(x,y) ((x)<(y)? (x) : (y))
 #define XMAX(a,b) ((a)>(b)? (a) : (b))
 
Index: squid/src/stat.c
diff -u squid/src/stat.c:1.17 squid/src/stat.c:1.13.2.4
--- squid/src/stat.c:1.17	Sun Apr  7 17:38:18 2002
+++ squid/src/stat.c	Tue Sep  3 10:41:57 2002
@@ -816,6 +816,32 @@
     storeAppendPrintf(sentry, "aborted_requests = %f/sec\n",
 	XAVG(aborted_requests));
 
+    storeAppendPrintf(sentry, "dist.dists = %f/sec\n",
+		      XAVG(dist.dists));
+    storeAppendPrintf(sentry, "dist.undists = %f/sec\n", 
+		      XAVG(dist.undists));
+    storeAppendPrintf(sentry, "dist.updates = %f/sec\n", 
+		      XAVG(dist.updates));
+    storeAppendPrintf(sentry, "dist.update_kbytes = %f/sec\n", 
+		      XAVG(dist.update_kbytes.kb));
+    storeAppendPrintf(sentry, "dist.content_upd = %f/sec\n",
+		      XAVG(dist.content_upd));
+    storeAppendPrintf(sentry, "dist.updatees = %f/sec\n", 
+		      XAVG(dist.updatees));
+    storeAppendPrintf(sentry, "dist.updatees = %f/sec\n",
+		      XAVG(dist.updatees * sizeof(Updatee)));
+    
+    storeAppendPrintf(sentry, "put.outs = %f/sec\n",
+		      XAVG(put.outs));
+    storeAppendPrintf(sentry, "put.kbytes_out = %f/sec\n",
+		      XAVG(put.kbytes_out.kb));
+    storeAppendPrintf(sentry, "put.ins =: %f\n", 
+		      XAVG(put.ins));
+    storeAppendPrintf(sentry, "put.kbytes_in = %f/sec\n", 
+		      XAVG(put.kbytes_in.kb));
+    storeAppendPrintf(sentry, "put.conflicts = %f/sec\n", 
+		      XAVG(put.conflicts));
+
 #if USE_POLL
     storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", XAVG(syscalls.polls));
 #endif
@@ -1200,6 +1226,32 @@
 	f->swap.files_cleaned);
     storeAppendPrintf(sentry, "aborted_requests = %d\n",
 	f->aborted_requests);
+    
+    storeAppendPrintf(sentry, "dist.dists = %d\n",
+		      f->dist.dists);
+    storeAppendPrintf(sentry, "dist.undists = %d\n", 
+		      f->dist.undists);
+    storeAppendPrintf(sentry, "dist.updates = %d\n", 
+		      f->dist.updates);
+    storeAppendPrintf(sentry, "dist.update_kbytes = %d\n", 
+		      (int) f->dist.update_kbytes.kb);
+    storeAppendPrintf(sentry, "dist.content_upd = %d\n",
+		      f->dist.content_upd);
+    storeAppendPrintf(sentry, "dist.updatees = %d\n", 
+		      f->dist.updatees);
+    storeAppendPrintf(sentry, "dist.updatees = %d\n",
+		      f->dist.updatees * sizeof(Updatee));
+    
+    storeAppendPrintf(sentry, "put.outs = %d\n",
+		      f->put.outs);
+    storeAppendPrintf(sentry, "put.kbytes_out = %d\n",
+		      (int) f->put.kbytes_out.kb);
+    storeAppendPrintf(sentry, "put.ins =: %d\n", 
+		      f->put.ins);
+    storeAppendPrintf(sentry, "put.kbytes_in = %d\n", 
+		      (int) f->put.kbytes_in.kb);
+    storeAppendPrintf(sentry, "put.conflicts = %d\n", 
+		      f->put.conflicts);
 }
 
 void
Index: squid/src/store.c
diff -u squid/src/store.c:1.17 squid/src/store.c:1.16.2.3
--- squid/src/store.c:1.17	Thu Aug 15 11:14:04 2002
+++ squid/src/store.c	Tue Sep  3 10:41:57 2002
@@ -179,6 +179,8 @@
     if (e->mem_obj)
 	destroy_MemObject(e);
     storeHashDelete(e);
+    if (e->updatees)
+	distDelUpdatees(e->updatees);
     assert(e->hash.key == NULL);
     memFree(e, MEM_STOREENTRY);
 }
@@ -192,12 +194,22 @@
 	e, storeKeyText(key));
     e->hash.key = storeKeyDup(key);
     hash_join(store_table, &e->hash);
+#if USE_HINT_CACHE
+    if (HINT_CACHE_ACTIVE()) {
+	e->hchhash.key = e->hash.key;
+	hash_join(cache_table, &e->hchash);
+    }
+#endif
 }
 
 static void
 storeHashDelete(StoreEntry * e)
 {
     hash_remove_link(store_table, &e->hash);
+#if USE_HINT_CACHE
+    if (HINT_CACHE_ACTIVE())
+	hash_remove_link(hint_table, &e->hchash);
+#endif
     storeKeyFree(e->hash.key);
     e->hash.key = NULL;
 }
@@ -710,6 +722,9 @@
 	assert(e->mem_obj->nclients == 0);
 	return;
     }
+#if USE_HINT_CACHE
+    hintCacheInformLocalCopy(e->mem_obj->url, e);
+#endif
     e->mem_obj->object_sz = e->mem_obj->inmem_hi;
     e->store_status = STORE_OK;
     assert(e->mem_status == NOT_IN_MEMORY);
@@ -873,6 +888,11 @@
 	    destroy_StoreEntry(e);
 	}
     }
+
+#if USE_HINT_CACHE
+    hintCacheInvalLocalCopy(e);
+#endif
+    
     storeLog(STORE_LOG_RELEASE, e);
     if (e->swap_filen > -1) {
 	storeUnlink(e);
@@ -1000,6 +1020,20 @@
     storeInitHashValues();
     store_table = hash_create(storeKeyHashCmp,
 	store_hash_buckets, storeKeyHashHash);
+#if USE_HINT_CACHE
+    /*
+     * Need to be able to look up objects from hint
+     * cache key so we can invalidate obsolete objects
+     * based on hint cache updates.
+     * Note: the hint cache key is just the first 8 bytes
+     * of the 16-byte cache key, so storeKeyHashHash will
+     * always work.  Although, right now, sKHH only looks
+     * at the first 32 bits anyway, giving double protection.
+     */
+    if (HINT_CACHE_ACTIVE()) 
+	hint_table = hash_create(hintCacheURLKeyCompare,
+		 store_hash_buckets, storeKeyHashHash);
+#endif
     mem_policy = createRemovalPolicy(Config.memPolicy);
     storeDigestInit();
     storeLogOpen();
@@ -1056,6 +1090,12 @@
     if (store_digest)
 	cacheDigestDestroy(store_digest);
 #endif
+#if USE_HINT_CACHE
+    if (HINT_CACHE_ACTIVE()) {
+	hashFreeMemory(hint_table);
+	hint_table = NULL;
+    }
+#endif
     store_digest = NULL;
 }
 
Index: squid/src/store_key_md5.c
diff -u squid/src/store_key_md5.c:1.6 squid/src/store_key_md5.c:1.6.24.1
--- squid/src/store_key_md5.c:1.6	Fri Apr 13 17:31:02 2001
+++ squid/src/store_key_md5.c	Fri Dec 14 00:00:37 2001
@@ -99,6 +99,11 @@
     assert(id > 0);
     debug(20, 3) ("storeKeyPrivate: %s %s\n",
 	RequestMethodStr[method], url);
+
+    /* PUT goes to same namespace as GETs do, so treat them alike here */
+    if (method == METHOD_PUT)
+	method = METHOD_GET;
+    
     MD5Init(&M);
     MD5Update(&M, (unsigned char *) &id, sizeof(id));
     MD5Update(&M, (unsigned char *) &method, sizeof(method));
@@ -113,6 +118,11 @@
     static cache_key digest[MD5_DIGEST_CHARS];
     unsigned char m = (unsigned char) method;
     MD5_CTX M;
+
+    /* PUT goes to same namespace as GETs do, so treat them alike here */
+    if (m == METHOD_PUT)
+	m = METHOD_GET;
+    
     MD5Init(&M);
     MD5Update(&M, &m, sizeof(m));
     MD5Update(&M, (unsigned char *) url, strlen(url));
@@ -133,6 +143,11 @@
     unsigned char m = (unsigned char) method;
     const char *url = urlCanonical(request);
     MD5_CTX M;
+
+    /* PUT goes to same namespace as GETs do, so treat them alike here */
+    if (m == METHOD_PUT)
+	m = METHOD_GET;
+
     MD5Init(&M);
     MD5Update(&M, &m, sizeof(m));
     MD5Update(&M, (unsigned char *) url, strlen(url));
Index: squid/src/structs.h
diff -u squid/src/structs.h:1.65 squid/src/structs.h:1.47.2.7
--- squid/src/structs.h:1.65	Sun Sep  1 09:30:42 2002
+++ squid/src/structs.h	Tue Sep  3 10:41:58 2002
@@ -338,6 +338,12 @@
 
 #endif
 
+#if USE_HINT_CACHE
+struct _URLKey {
+  HintCacheKey key;
+};
+#endif
+
 #if DELAY_POOLS
 struct _delaySpec {
     int restore_bps;
@@ -588,6 +594,11 @@
 	int ie_refresh;
 	int vary_ignore_expire;
 	int pipeline_prefetch;
+#if USE_HINT_CACHE
+	int hint_cache_listen;
+	int hint_cache_advertise;
+	int hint_cache_use_mmap;
+#endif
 	int check_hostnames;
 	int via;
     } onoff;
@@ -681,6 +692,16 @@
 	int unclean_shutdown;
     } SSL;
 #endif
+#if USE_HINT_CACHE
+    struct {
+        char *cache_file;
+        int size;
+        int assoc;
+        int intvl;
+        int join_intvl;
+        int holddown;
+    } Hints;
+#endif
     wordlist *ext_methods;
     struct {
 	int high_rptm;
@@ -979,6 +1000,7 @@
     int fd;
     http_state_flags flags;
     FwdState *fwd;
+    int body_remain;
 };
 
 struct _icpUdpData {
@@ -1062,6 +1084,7 @@
     } out;
     HttpHdrRangeIter range_iter;	/* data for iterating thru range specs */
     size_t req_sz;		/* raw request size on input, not current request size */
+    char *hdr_str;              /* Copy of headers */
     StoreEntry *entry;
     StoreEntry *old_entry;
     log_type log_type;
@@ -1281,6 +1304,13 @@
 	unsigned int no_delay:1;
 #endif
 	unsigned int allow_miss:1;
+	unsigned int dist:1;
+#if USE_ICP_DATA
+	unsigned int icpdata:1;
+#endif
+#if USE_HINT_CACHE
+	unsigned int nohint:1;
+#endif	
 #if USE_CARP
 	unsigned int carp:1;
 #endif
@@ -1319,6 +1349,8 @@
     char *login;		/* Proxy authorization */
     time_t connect_timeout;
     int max_conn;
+    peer *fwdpush;      /* next peer on FwdPushLinks */
+    int max_rate;       /* Max push rate to this peer */
 };
 
 struct _net_db_name {
@@ -1547,6 +1579,10 @@
     ping_status_t ping_status:3;
     store_status_t store_status:3;
     swap_status_t swap_status:3;
+    Updatee *updatees;
+#if USE_HINT_CACHE
+    hash_link hchash;
+#endif
 };
 
 struct _SwapDir {
@@ -1623,6 +1659,7 @@
     unsigned int accelerated:1;
     unsigned int internal:1;
     unsigned int body_sent:1;
+    unsigned int distify:1;       /* Use dist reqs for consistency */
     unsigned int reset_tcp:1;
 };
 
@@ -1672,6 +1709,8 @@
     struct in_addr client_addr;
     struct in_addr my_addr;
     unsigned short my_port;
+    int dist_type;
+    unsigned short dist_port;
     HttpHeader header;
     ConnStateData *body_connection;	/* used by clientReadBody() */
     int content_length;
@@ -1870,6 +1909,21 @@
 	int outs;
 	int ins;
     } swap;
+    struct {
+        int dists;
+	int undists;
+	int updates;
+	kb_t update_kbytes;
+	int content_upd;
+	int updatees;
+    } dist;
+    struct {
+        int outs;
+	int ins;
+	kb_t kbytes_out;
+	kb_t kbytes_in;
+	int conflicts;
+    } put;
 };
 
 /* per header statistics */
@@ -2159,10 +2213,149 @@
     } flags;
 };
 
+
+
+/*
+ * Putting state.
+ */
+struct _PushHeader {
+    int fd;
+    store_client *sc;
+    struct {
+        unsigned int active:1;
+        unsigned int dead:1;
+        unsigned int disting:1;
+#ifdef USE_ICP_DATA
+        unsigned int icpdata:1;
+#endif
+    } flags;
+    int off;
+    int objlen;
+    StoreEntry *entry;
+    PF *handler;
+    void *arg;
+#ifdef USE_ICP_DATA
+    icpQueue *q;
+#endif
+    unsigned reqnum; /* ICP reqnum */
+    char hname[20];
+};
+
+struct _Pusher {
+    PushHeader hdr;
+    char data[16384 - sizeof(PushHeader)];
+};
+
 struct cache_dir_option {
     const char *name;
     void (*parse) (SwapDir * sd, const char *option, const char *value, int reconfiguring);
     void (*dump) (StoreEntry * e, const char *option, SwapDir * sd);
 };
 
+
+/* Tracking state for update ("push") requester */
+struct _updatee {
+    struct _updatee *next;
+    StoreEntry *entry;         /* Backpointer to relevant entry */
+    struct sockaddr_in saddr;
+    time_t lastmod;
+    Pusher *p;
+};
+
+
+#if USE_HINT_CACHE
+
+/* Hint Cache Interface */
+/*
+ * Primitive data types. All have a -Net format which has an
+ * agreed-upon endian-ness.
+ */
+
+
+struct _URLKeyNet {
+    HintCacheKey mungedKey;
+};
+
+struct _NodeKey {
+    dlink_node links;
+    HintCacheKey key;
+    struct sockaddr_in addr;
+};
+
+struct _HintCacheEntry {
+    URLKey         key;
+    struct in_addr ipaddr;
+    unsigned short port;
+    short          pad;    /* Compiler padding space */
+    unsigned int   mtime;  /* Last-modified time */
+};
+
+/* This is what goes onto the net */
+struct _HintCacheEntryNet {
+    URLKeyNet     mungedKey;
+    struct in_addr mungedIpaddr;
+    unsigned short mungedPort;
+    short          mungedPad;
+    unsigned int   mungedMtime;
+};
+
+struct _HintCacheUpdate {
+    unsigned char          action;
+    char                   hopcount;
+    char                   UNUSED;  /* Remove this field sometime XXX */
+    char                   pad1;
+    int                    pad2;
+    HintCacheEntry                entry;
+};
+
+struct _HintCacheUpdateNet {
+    unsigned char          mungedAction;
+    char                   mungedHopcount;
+    char                   mungedUNUSED; 
+    char                   mungedPad1;
+    int                    mungedPad2;
+    HintCacheEntryNet      mungedEntry;
+};
+
+/* Hint Cache Disk */
+struct _HintCacheDiskEntry {
+    HintCacheEntry      entry; 
+    unsigned int rtime; /* Time of entry receipt */
+};
+
+struct _HintCacheDisk {
+    unsigned int nbuckets;
+    int entriesPerBucket;
+    HintCacheDiskEntry *mmappedArray;
+    int fd;
+};
+
+typedef struct HintCacheNetS{
+    StoreEntry *sendBuffer;
+    int         sendLength;
+    enum HintCacheNet_State state;
+#ifdef DOTEST
+    int         testMode;
+    int         testCount;
+#endif
+} HintCacheNet;
+
+typedef struct HintCacheNetHeaderS {
+    unsigned short httpport;  /* Port of sending server */
+    unsigned short updlen;    /* Length of individual update */
+} HintCacheNetHeader;
+
+#endif /* USE_HINT_CACHE */
+
+#if USE_ICP_DATA
+typedef struct _icpDataStats {
+    int nsends;
+    int nrecvs;
+    int nfrags;
+    int ndups;
+    int ntmofrags;
+    int nbadfrags;
+} 
+#endif
+
 #endif /* SQUID_STRUCTS_H */
Index: squid/src/typedefs.h
diff -u squid/src/typedefs.h:1.27 squid/src/typedefs.h:1.25.2.6
--- squid/src/typedefs.h:1.27	Sun Jun 23 06:38:04 2002
+++ squid/src/typedefs.h	Tue Sep  3 10:42:00 2002
@@ -351,6 +351,37 @@
 
 typedef int STDIRSELECT(const StoreEntry *);
 
+/* PUT internal data structure */
+typedef struct _PushHeader PushHeader;
+typedef struct _Pusher Pusher;
+
+/* Automatic update ("push") requester */
+typedef struct _updatee Updatee;
+
+#if USE_HINT_CACHE
+/* Hint Cache Interface */
+typedef unsigned Net_unsigned;
+typedef long long unsigned Net_longlong;
+typedef unsigned long long HintCacheKey;
+typedef struct _URLKey URLKey;
+typedef struct _URLKeyNet URLKeyNet;
+typedef struct _NodeKey NodeKey;
+typedef struct _HintCacheEntry HintCacheEntry;
+typedef struct _HintCacheEntryNet HintCacheEntryNet;
+typedef struct _HintCacheUpdate HintCacheUpdate;
+typedef struct _HintCacheUpdateNet HintCacheUpdateNet;
+
+/* Hint Cache Disk */
+typedef struct _HintCacheDiskEntry HintCacheDiskEntry;
+typedef struct _HintCacheDisk HintCacheDisk;
+
+typedef dlink_node *HintCacheNodeListIter;
+#endif /* USE_HINT_CACHE */
+
+#if USE_ICP_DATA
+typedef struct _icpDataStats icpDataStats;
+#endif
+
 typedef struct _external_acl external_acl;
 typedef struct _external_acl_entry external_acl_entry;
 
Index: squid/src/url.c
diff -u squid/src/url.c:1.10 squid/src/url.c:1.7.2.3
--- squid/src/url.c:1.10	Fri Aug 23 19:06:24 2002
+++ squid/src/url.c	Tue Sep  3 10:42:01 2002
@@ -102,6 +102,9 @@
     "whois",
     "internal",
     "https",
+#if USE_HINT_CACHE
+    "route",
+#endif
     "TOTAL"
 };
 
@@ -195,30 +198,84 @@
 
 
 protocol_t
-urlParseProtocol(const char *s)
+urlParseProtocol(const char *s, u_short *dportp, int *dtypep)
 {
+    int proto;
+  
     /* test common stuff first */
-    if (strcasecmp(s, "http") == 0)
-	return PROTO_HTTP;
-    if (strcasecmp(s, "ftp") == 0)
-	return PROTO_FTP;
-    if (strcasecmp(s, "https") == 0)
-	return PROTO_HTTPS;
-    if (strcasecmp(s, "file") == 0)
-	return PROTO_FTP;
-    if (strcasecmp(s, "gopher") == 0)
-	return PROTO_GOPHER;
-    if (strcasecmp(s, "wais") == 0)
-	return PROTO_WAIS;
-    if (strcasecmp(s, "cache_object") == 0)
-	return PROTO_CACHEOBJ;
-    if (strcasecmp(s, "urn") == 0)
-	return PROTO_URN;
-    if (strcasecmp(s, "whois") == 0)
-	return PROTO_WHOIS;
-    if (strcasecmp(s, "internal") == 0)
-	return PROTO_INTERNAL;
-    return PROTO_NONE;
+    if (strncasecmp(s, "http", 4) == 0) {
+	s += 4;
+	proto = PROTO_HTTP;
+    }
+#if USE_HINT_CACHE    
+    else if (strncasecmp(s, "route", 5) == 0) {
+	s += 5;
+	proto = PROTO_ROUTE;
+    }
+#endif
+  else if (strncasecmp(s, "ftp", 3) == 0) {
+	s += 3;
+        proto = PROTO_FTP;
+    }
+    else if (strncasecmp(s, "https", 5) == 0) {
+	s += 5;
+	proto = PROTO_HTTPS;
+    }
+    else if (strncasecmp(s, "file", 4) == 0) {
+	s += 4;
+        proto = PROTO_FTP;
+    }
+    else if (strncasecmp(s, "gopher", 6) == 0) {
+	s += 6;
+	proto = PROTO_GOPHER;
+    }
+    else if (strncasecmp(s, "wais", 4) == 0) {
+	s += 4;
+	proto =PROTO_WAIS;
+    }
+    else if (strncasecmp(s, "cache_object", 12) == 0) {
+	s += 12;
+	proto = PROTO_CACHEOBJ;
+    }
+    else if (strncasecmp(s, "urn", 3) == 0) {
+	s += 3;
+	proto = PROTO_URN;
+    }
+    else if (strncasecmp(s, "whois", 5) == 0) {
+	s += 5;
+        proto = PROTO_WHOIS;
+    }
+    else if (strncasecmp(s, "internal", 8) == 0) {
+	s += 8;
+	proto = PROTO_INTERNAL;
+    }
+    else
+        proto = PROTO_NONE;
+
+    if (dportp != NULL) {
+	if (strncasecmp(s, "dist", 4) == 0) {
+	    s += 4;
+	    if (dportp != NULL)
+		*dportp = ntohs(atoi(s));
+	    if (dtypep)
+		*dtypep = DIST_DIST;
+	}
+	else if (strncasecmp(s, "undist", 6) == 0) {
+	    s += 6;
+	    if (dportp != NULL)
+		*dportp = ntohs(atoi(s));
+	    if (dtypep)
+		*dtypep = DIST_UNDIST;
+	}
+	else {
+	    if (dportp)
+		*dportp = 0;
+	    if (dtypep)
+		*dtypep = 0;
+	}
+    }
+    
+    return proto;
 }
 
 
@@ -256,7 +313,7 @@
     request_t *request = NULL;
     char *t = NULL;
     char *q = NULL;
-    int port;
+    int port, dport, dtype;
     protocol_t protocol = PROTO_NONE;
     int l;
     proto[0] = host[0] = urlpath[0] = login[0] = '\0';
@@ -276,7 +333,7 @@
     } else {
 	if (sscanf(url, "%[^:]://%[^/]%[^\r\n]", proto, host, urlpath) < 2)
 	    return NULL;
-	protocol = urlParseProtocol(proto);
+	protocol = urlParseProtocol(proto, &dport, &dtype);
 	port = urlDefaultPort(protocol);
 	/* Is there any login informaiton? */
 	if ((t = strrchr(host, '@'))) {
@@ -357,6 +414,8 @@
     xstrncpy(request->host, host, SQUIDHOSTNAMELEN);
     xstrncpy(request->login, login, MAX_LOGIN_SZ);
     request->port = (u_short) port;
+    request->dist_port = (u_short) dport;
+    request->dist_type = dtype;
     return request;
 }
 
Index: squid/src/webpush.c
diff -u /dev/null squid/src/webpush.c:1.1.2.2
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/webpush.c	Fri Dec 14 00:00:37 2001
@@ -0,0 +1,267 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#define OUTBUFLEN 65536
+/*#define OUTBUFLEN 1400*/
+
+char *malloc();
+void free();
+int atoi();
+int gethostname();
+int write();
+
+void usage();
+int puthdr(struct stat *st);
+void hfcopy(FILE *to, FILE *from, char *buf, int buflen, int hdrlen);
+
+char *verstr = "Server: Webpush 2.0, Squid PUT utility\r\n";
+
+static int port = 3128;
+static int verbose = 0;
+static int directfile = 0;
+static int async = 0;
+
+static char *cmdname;
+static char name[256];
+static char reply[BUFSIZ];
+static char *url = 0;
+static char *htfile = 0;
+static char *type = "text/html";
+static char outbuf[OUTBUFLEN];
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+    struct sockaddr_in addr;
+    int argcnt = 0;
+    struct stat st;
+    FILE *sp, *fp;
+    int hdrlen;
+    char *arg;
+    int code;
+    int s;
+    
+    cmdname = argv[0];
+    if (argc < 3)
+	usage();
+    while (--argc) {
+	arg = *++argv;
+	if (arg[0] == '-') {
+	    while (*++arg) {
+		switch(*arg) {
+		  case 'a':   /* Asynchronous - don't wait for reply */
+		    async = 1;
+		    break;
+		  case 'h':   /* Don't generate HTTP headers - already in file */
+		    directfile = 1;
+		    break;
+		  case 'p':   /* Specify port */
+		    --argc;
+		    if (argc < 1)
+			usage();
+		    port = atoi(*++argv);
+		    if (port == 0)
+			usage();
+		    break;
+		  case 't':   /* Specify Content-type */
+		    --argc;
+		    if (argc < 1)
+			usage();
+		    type = *++argv;
+			usage();
+		    break;
+		  case 'v':   /* Verbose */
+		    verbose = 1;
+		    break;
+		  default:
+		    usage();
+		}
+	    }
+	}
+	else {
+	    ++argcnt;
+	    if (argcnt == 1) {
+		/* First non-flagged arg is the URL */
+		url = arg;
+	    }
+	    else if (argcnt == 2) {
+		/* Second non-flagged arg is the file to push */
+		htfile = arg;
+	    }
+	    else
+		usage();
+	}
+    }
+
+    if (argcnt != 2)
+	usage();
+
+    s = socket(AF_INET, SOCK_STREAM, 0);
+    if (s == -1) {
+	perror("socket");
+	exit(1);
+    }
+
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(0x7f000001);
+    addr.sin_port = htons(port);
+    if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
+	perror("connect");
+	exit(1);
+    }
+    sp = fdopen(s, "r+");
+    if (sp == NULL) {
+	perror("socket fdopen");
+	exit(1);
+    }
+    
+    fp = fopen(htfile, "r");
+    if (fp == 0) {
+	perror(htfile);
+	exit(1);
+    }
+    
+    if (fstat(fileno(fp), &st) == -1) {
+	perror("fstat");
+	exit(1);
+    }
+
+    /* If directfile, then the file will already have HTTP headers */
+    if (!directfile) {
+	/* Generate header and send to proxy */
+	hdrlen = puthdr(&st);
+	if (verbose) {
+	    fwrite(outbuf, 1, hdrlen, stdout);
+	}
+    }
+
+    /* Copy file to proxy */
+    if (verbose)
+	printf("sending file to proxy\n");
+    hfcopy(sp, fp, outbuf, OUTBUFLEN, hdrlen);
+
+    /* Read response */
+    if (!async) {
+	if (verbose)
+	    printf("proxy response is:\n");
+	fread(reply, 1, sizeof(reply), sp);
+	reply[sizeof(reply) - 2] = '\n';
+	reply[sizeof(reply) - 1] = '\0';
+
+	/* Parse response */
+	sscanf(reply, "%s %d", name, &code);
+	
+	/* Print the complaint if the server seems unhappy */
+	if ((code != 200 && code != 204) || verbose)
+	    fputs(reply, stdout);
+    }
+    exit(0);
+}
+
+void usage(err)
+char *err;
+{
+    fprintf(stderr, "usage: %s [-h][-p port][-t content-type] <url> <file-to-push>\n", cmdname);
+    exit(1);
+}
+
+/* Generate PUT header */
+int puthdr(statp)
+struct stat *statp;
+{
+    struct tm *gmtime();
+    char *asctime();
+    char *timestr;
+    time_t now;
+    int hdrlen;
+
+    now = time(0);
+    timestr = asctime(gmtime(&now));
+    timestr[strlen(timestr) - 1] = '\0';
+
+    gethostname(name, sizeof(name));
+
+    if (url == 0) {
+	fprintf(stderr, "webpush internal problem - URL unknown\n");
+	exit(1);
+    }
+
+    hdrlen = 0;
+    sprintf(outbuf, "PUT %s HTTP/1.0\r\n", url);
+    hdrlen = strchr(outbuf, '\n') - outbuf + 1;
+    
+    sprintf(outbuf + hdrlen, "Date: %s GMT\r\n", timestr);
+    hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1;
+
+    sprintf(outbuf + hdrlen, verstr);
+    hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1;
+
+    sprintf(outbuf + hdrlen, "Content-type: %s\r\n", type);
+    hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1;
+
+    sprintf(outbuf + hdrlen, "Content-length: %d\r\n", (int) statp->st_size);
+    hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1;
+
+    timestr = asctime(gmtime(&statp->st_mtime));
+    timestr[strlen(timestr) - 1] = '\0';
+    sprintf(outbuf + hdrlen, "Last-modified: %s GMT\r\n\r\n", timestr);
+    hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 3;
+
+    if (verbose)
+	printf("PUT header amounts to %d bytes\n", hdrlen);
+    
+    return(hdrlen);
+}
+
+/* filecopy that makes allowances for an initial output header */
+void hfcopy(to, from, buf, buflen, hdrlen)
+FILE *to, *from;
+char *buf;
+int buflen;
+int hdrlen;
+{
+    int nmov, nwrote;
+    char *tbuf;
+
+    while (1) {
+	nmov = fread(buf + hdrlen, 1, buflen - hdrlen, from);
+	if (nmov == -1) {
+	    perror("filecopy read");
+	    exit(1);
+	}
+	if (nmov == 0) {
+	    if (!feof(from))
+		perror("webpost read");
+	    break;
+	}
+	nmov += hdrlen;
+
+	tbuf = buf;
+	do {
+	    if (verbose) 
+		write(1, buf, nmov);
+	    nwrote = write(fileno(to), buf, nmov);
+	    if (nwrote == -1) {
+		perror("filecopy write");
+		exit(1);
+	    }
+	    if (nwrote == 0)
+		break;
+	    nmov -= nwrote;
+	    tbuf += nwrote;
+	} while (nmov > 0);
+
+	/* Sent header in first go-round, done now */
+	hdrlen = 0;
+    }
+    if (verbose)
+	printf("filecopy complete - last move of %d chars\n", nmov);
+}
+
Index: squid/src/auth/basic/helpers/Makefile.am
diff -u /dev/null squid/src/auth/basic/helpers/Makefile.am:1.2.28.1
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/auth/basic/helpers/Makefile.am	Tue Sep  3 10:42:05 2002
@@ -0,0 +1,7 @@
+#  Makefile for storage modules in the Squid Object Cache server
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+
+DIST_SUBDIRS	= getpwnam LDAP MSNT multi-domain-NTLM NCSA PAM SMB YP SASL
+SUBDIRS		= @BASIC_AUTH_HELPERS@
Index: squid/src/auth/basic/helpers/LDAP/Makefile.am
diff -u /dev/null squid/src/auth/basic/helpers/LDAP/Makefile.am:1.2.28.2
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/auth/basic/helpers/LDAP/Makefile.am	Tue Sep  3 10:42:07 2002
@@ -0,0 +1,14 @@
+#
+#  Makefile for the Squid LDAP authentication helper
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+libexec_PROGRAMS 	= squid_ldap_auth
+man_MANS 		= squid_ldap_auth.8
+EXTRA_DIST		= squid_ldap_auth.8
+squid_ldap_auth_SOURCES	= squid_ldap_auth.c
+
+LDADD = -lldap -llber
Index: squid/src/auth/basic/helpers/MSNT/Makefile.am
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/Makefile.am:1.2.28.2
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/auth/basic/helpers/MSNT/Makefile.am	Tue Sep  3 10:42:10 2002
@@ -0,0 +1,22 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+
+libexec_PROGRAMS = msnt_auth
+
+msnt_auth_SOURCES = md4.c rfcnb-io.c rfcnb-util.c session.c msntauth.c \
+		msntauth.h smbdes.c smbencrypt.c smblib-util.c smblib.c \
+		valid.c denyusers.c allowusers.c confload.c \
+		byteorder.h rfcnb-common.h rfcnb-error.h rfcnb.h \
+		rfcnb-io.h rfcnb-priv.h rfcnb-util.h smblib-common.h \
+		smblib.h smblib-priv.h std-defines.h std-includes.h valid.h
+
+LDADD	= @XTRA_LIBS@
+
+INCLUDES      = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
+		-I$(top_srcdir)/src/
Index: squid/src/auth/basic/helpers/MSNT/README.html
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/README.html:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/auth/basic/helpers/MSNT/README.html	Tue Sep  3 10:42:10 2002
@@ -0,0 +1,355 @@
+<HTML>
+<HEAD>
+<TITLE>MSNTAUTH readme</TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+
+<!--
+If you require this document in text form, download the 
+HTML-text package from http://members.tripod.com/stellarx.
+-->
+
+<H1>
+MSNT Auth v2.0.3<BR>
+Squid web proxy NT authentication module<BR>
+Antonino Iannella, Stellar-X Pty Ltd<BR>
+Sun Sep  2 15:01:58 CST 2001
+</H1>
+
+<H2>Contents</H2>
+
+<UL>
+<LI> <A HREF="#introduction">Introduction</A>
+<LI> <A HREF="#installation">Installation</A>
+<LI> <A HREF="#compiling">Issues when compiling</A>
+<LI> <A HREF="#configuration">Configuration file</A>
+<LI> <A HREF="#denying">Denying users</A>
+<LI> <A HREF="#allowing">Allowing users</A>
+<LI> <A HREF="#squid">Squid.conf changes</A>
+<LI> <A HREF="#testing">Testing</A>
+<LI> <A HREF="#contact">Contact details</A>
+<LI> <A HREF="#reported">Reported problem</A>
+<LI> <A HREF="#changes">Revision history</A>
+</UL>
+
+<A NAME="introduction"><H2>Introduction</H2>
+
+<P>
+This is an authentication module for the Squid proxy server
+to authenticate users on an NT domain.
+
+<P>
+It originates from the Samba and SMB packages by Andrew Tridgell
+and Richard Sharpe. This version is sourced from the Pike
+authentication module by William Welliver (hwellive@intersil.com).
+
+<P>
+Usage is simple. It accepts a username and password on standard input.
+It will return OK if the username/password is valid for the domain,
+or ERR if there was some problem.
+Check syslog messages for reported problems.
+
+<P>
+Msntauth is released under the GNU General Public License and
+is available from 
+<A HREF="http://www.tripod.com/stellarx">http://www.tripod.com/stellarx</A>.
+It also ships with the Squid web proxy, 
+<A HREF="http://www.squid-proxy.org">http://www.squid-proxy.org</A>.
+
+<P>
+Msntauth has not been tested with Windows 2000 domains yet.
+
+<A NAME="installation"><H2>Installation</H2>
+
+<P>
+Make any changes to the source code you need.
+
+<P>
+If you are using the source provided with Squid, then Msntauth
+will be compiled when you compile Squid. Refer to Squid documentation
+for details.
+
+<P>
+If you have downloaded Msntauth from the Stellar-X website, then
+copy <CODE>Makefile.MSNT</CODE> to <CODE>Makefile</CODE>.
+Review the Makefile, and modify based on target platform or
+site requirements.
+
+<P>
+Type 'make', then 'make install', then 'make clean'.
+
+<P>
+To avoid using the makefile, it may compile with
+
+  gcc -O2 -s -o msntauth *.c
+
+<P>
+'Make install' will put 'msntauth' into
+/usr/local/squid/bin by default.
+
+<P>
+Hopefully nobody has problems compiling msntauth.
+
+<A NAME="compiling"><H2>Issues when compiling</H2>
+
+<P>
+The Makefile uses the GCC compiler, and assumes that it is in the current PATH.
+Msntauth is known to compile properly on Redhat Linux 6, and FreeBSD 3.1
+without problems. Other operating systems are untested,
+but use a recent copy of the GNU C compiler.
+In Smbencrypt.c, '#include <sys/vfs.h>' only gets included when
+compiled with Solaris.
+
+<P>
+When compiling under Solaris, the socket libraries must be linked to.
+In the Makefile, hash the default CFLAGS line, and unhash the Solaris
+CFLAGS line. It always helps to have /usr/ccs/bin in your path
+prior to compiling.
+
+<P>
+For Digital Unix/Tru64, review the INSTALL line in the makefile.
+
+<A NAME="configuration"><H2>Configuration file</H2>
+
+<P>
+Msntauth uses a configuration file as of version 2.
+The file is /usr/local/squid/etc/msntauth.conf.
+If this path needs to be changed, it is defined in confload.c -
+
+<PRE>
+  #define CONFIGFILE   "/usr/local/squid/etc/msntauth.conf"
+</PRE>
+
+<P>
+An example configuration file is provided. It looks like
+
+<PRE>
+# Sample MSNT authenticator configuration file
+# Antonino Iannella, Stellar-X Pty Ltd
+# Tue Sep 26 17:26:59 CST 2000
+
+server my_PDC           my_BDC          my_NTdomain
+server other_PDC        other_BDC       otherdomain
+
+denyusers       /usr/local/squid/etc/denyusers
+allowusers      /usr/local/squid/etc/allowusers
+</PRE>
+
+<P>
+All comments start with '#'.
+
+<P>
+NT servers are used to query user accounts. The 'server' lines
+are used for this, with the PDC, BDC, and NT domain as parameters.
+Up to 5 servers/domains can be queried. If this is not enough,
+modify the MAXSERVERS define in confload.c.
+At least one server must be specified, or msntauth will not
+run.
+Server names must be resolvable by the system. If not, msntauth
+reports an error. If you can't ping it, you might have a host
+resolution problem.
+You can't use NetBIOS hostnames, nor IP addresses.
+
+<P>
+When a user provides a username/password, each of these
+servers will be queried to authenticate the username.
+It stops after a user has been successfully authenticated,
+so it makes sense to specify the most commonly queried
+server first. Make sure the servers can be reached and
+are active, or else msntauth will start failing user accounts!
+
+<P>
+The 'denyusers' and 'allowusers' lines give the absolute path
+to files of user accounts. They can be used to deny or allow
+access to the proxy. Do not use these directives if you
+do not need these features.
+
+<A NAME="denying"><H2>Denying users</H2>
+
+<P>
+Users who are not allowed to access the web proxy can be added to
+the denied user list. This list is read around every minute, or when
+the msntauth process receives a SIGHUP signal.
+
+<P>
+The denied user file is set using the 'denyusers' directive
+in msntauth.h.  The denied user file
+contains a list of usernames in no particular structure or form.
+If the file does not exist, no users are denied.
+The file must be readable by the web proxy user.
+
+<P>
+Msntauth will send syslog messages if a user was denied,
+at LOG_USER facility.
+
+<A NAME="allowing"><H2>Allowing users</H2>
+
+<P>
+Similar to denying users, you can allow users to access the proxy
+by username. This is useful if only a number of people are
+allowed supposed to be accessing a proxy.
+
+<P>
+The allowed user file is set using the 'allowusers' directive
+in msntauth.h.
+If the file does not exist or if empty, all users are allowed.
+
+<P>
+You could make use of the SHOWMBRS tool in Microsoft Technet.
+This gives you a list of users which are in a particular
+NT Domain Group. This list can be made into the allowed users
+file.
+
+<P>
+Some other rules -
+
+<OL>
+<LI> The operation of the denied user file is independent of the
+allowed user file. The former file is checked first.
+<LI> You can use none, one, or both files.
+<LI> If a username appears in the denied user file, they will
+be denied, even if they are in the allowed user file.
+<LI> If a username is not in either file, they will be denied,
+because they have not been allowed.
+<LI> If the allowed user file is in use and is empty, all
+users will be allowed.
+</OL>
+
+<P>
+Hopefully this wasn't too confusing.
+
+<A NAME="squid"><H2>Squid.conf changes</H2>
+
+<P>
+Refer to Squid documentation for the required changes to squid.conf.
+You will need to set the following lines to enable authentication for
+your access list -
+
+<PRE>
+  acl <yourACL> proxy_auth REQUIRED
+  http_access allow password
+  http_access allow <yourACL>
+  http_access deny all
+</PRE>
+
+<P>
+You will also need to review the following directives. The number of
+msntauth children spawned is set with authenticate_children.
+The number of children needed is site-dependent, so some
+experimentation may be required to find the best number.
+There should be no visible delay in performance with Squid once
+msntauth is in use. As an example, a firm with 1500 users and a T1
+internet connection required a value of 30.-
+
+<PRE>
+  proxy_auth_realm enterprise web gateway
+  authenticate_program /usr/local/squid/bin/msntauth
+  authenticate_ttl 5
+  authenticate_children 20
+</PRE>
+
+<A NAME="testing"><H2>Testing</H2>
+
+<P>
+I strongly urge that Msntauth is tested prior to being used in a 
+production environment. It may behave differently on different platforms.
+To test it, run it from the command line. Enter username and password
+pairs separated by a space.
+
+<P>
+It should behave in the following way -
+<PRE>
+ - Press ENTER to get an OK or ERR message.
+ - Make sure pressing CTRL-D behaves the same as a carriage return.
+ - Make sure pressing CTRL-C aborts the program.
+ - Test that entering no details does not result in an OK or ERR message.
+ - Test that entering an invalid username and password results in
+   an ERR message. Note that if NT guest user access is allowed on
+   the PDC, an OK message may be returned instead of ERR.
+ - Test that entering an valid username and password results in an OK message.
+   Try usernames which are and aren't in the denied/allowed user files,
+   if they're in use.
+ - Test that entering a guest username and password returns the correct response.
+</PRE>
+
+<P>
+If the above didn't work as expected, you may need to modify the main()
+function in msntauth.c. Inform the maintainer of any problems.
+
+<P>
+Usernames cannot have whitespace in them, but passwords can.
+
+<P>
+As of version 2.0.3, the msntauth version can be found in the executable.
+Type this to retrieve it -
+
+<PRE>
+  strings msntauth | grep -i msntauth
+</PRE>
+
+<A NAME="contact"><H2>Contact details</H2>
+
+<P>
+To contact the maintainer of this package, email Antonino Iannella
+at antonino@rager.com.au, or antonino.iannella@santos.com.au, or ring
++61 8408 800 007.
+
+<P>
+The latest version may be found on http://members.tripod.com/stellarx.
+It is also distributed as part of Squid.
+
+<A NAME="reported"><H2>Reported problem</H2>
+
+<P>
+For an unknown username, Msntauth returns OK.
+This is because the PDC returns guest access for unknown users,
+even if guest access is disabled.
+This problem was reported by Mr Vadim Popov (vap@iilsr.minsk.by).
+I am not able to replicate this.
+
+<P>
+The tested environment consisted of PDC on Windows NT 4, SP 6.
+Squid 2.3 and Msntauth was tested on SuSe, RedHat, and Debian Linux.
+A fix was provided in case you have this problem.
+Apply the provided patch before compiling, using
+
+<PRE>
+  patch smblib.c < smblib.c.patch
+</PRE>
+
+<A NAME="changes"><H2>Revision history</H2>
+
+<P>
+The following sequence of changes have been made to improve msntauth.
+I have not had a chance to do too much testing due
+to lack of resources. There should be no problems, though.
+
+<UL>
+<LI>Added many patches from Duane Wessels to stop compilation errors (?)
+<LI>Improved the main() function yet again
+<LI>Created a more informative Makefile
+<LI>Added an 'allowed users' feature to complement the 'denied users' feature
+<LI>Stopped the use of alarm() which was causing problems under Solaris
+<LI>Added more syslog messages for authentication problems
+<LI>Added the use of a configuration file, instead of hard-coding NT server details
+<LI>Allowed for querying multiple NT servers and domains (this was a hot issue)
+<LI>Changed README into an HTML document to improve readability
+<LI>Removed denied/allowed username substring search limitation
+<LI>Fixed a bug which occurred when reading denied/allowed usernames
+<LI>Allows whitespace in passwords
+<LI>To check user list changes, doesn't use an alarm every minute.
+<LI>Fixed a sigaction compilation error, causing problems on FreeBSD and HPUX
+<LI>Removed a problem of finding a valid username as a substring in the denied user list.
+<LI>Support email address change from antonino@usa.net to antonino@rager.com.au.
+<LI>Msntauth was successfully tested on Tru64.
+<LI>PDC and BDC hostnames are now checked if they are resolvable.
+<LI>Smbencrypt.c does not have to be checked for Solaris systems any more.
+<LI>Imbedded version information in the executable.
+</UL>
+
+<P>
+Hopefully msntauth and Squid prove to be a valuable auditing combination.
+Feel free to send me success or problem stories.
+
+</BODY>
+</HTML>
Index: squid/src/auth/basic/helpers/MSNT/allowusers.c
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/allowusers.c:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/auth/basic/helpers/MSNT/allowusers.c	Tue Sep  3 10:42:10 2002
@@ -0,0 +1,193 @@
+
+/*
+ * allowusers.c
+ * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd
+ * Released under GPL, see COPYING-2.0 for details.
+ * 
+ * These routines are to allow users attempting to use the proxy which
+ * have been explicitly allowed by the system administrator.
+ * The code originated from denyusers.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#define NAMELEN     50		/* Maximum username length */
+
+/* Global variables */
+
+char *AllowedUsers;		/* Pointer to string of allowed users */
+off_t AllowUserSize;		/* Size of allowed users file */
+struct stat FileBuf;		/* Stat data buffer */
+time_t LastModTime;		/* Last allowed user file modification time */
+
+char Allowuserpath[MAXPATHLEN];	/* MAXPATHLEN defined in param.h */
+
+/* Function declarations */
+
+int Read_allowusers();
+int Check_ifuserallowed(char *);
+void Checkforchange();
+void Checktimer();
+
+/*
+ * Reads the allowed users file for all users to be permitted.
+ * Returns 0 if the user list was successfully loaded,
+ * and 1 in case of error.
+ * Logs any messages to the syslog daemon.
+ */
+
+int
+Read_allowusers()
+{
+    FILE *AFile;		/* Allowed users file pointer */
+    off_t APos = 0;		/* File counter */
+    char AChar;			/* Character buffer */
+
+    /* Stat the file. If it does not exist, save the size as zero.
+     * Clear the allowed user string. Return. */
+    if (stat(Allowuserpath, &FileBuf) == -1) {
+	if (errno == ENOENT) {
+	    LastModTime = (time_t) 0;
+	    AllowUserSize = 0;
+	    free(AllowedUsers);
+	    AllowedUsers = malloc(sizeof(char));
+	    AllowedUsers[0] = '\0';
+	    return 0;
+	} else {
+	    syslog(LOG_USER | LOG_ERR, strerror(errno));
+	    return 1;
+	}
+    }
+    /* If it exists, save the modification time and size */
+    LastModTime = FileBuf.st_mtime;
+    AllowUserSize = FileBuf.st_size;
+
+    /* Handle the special case of a zero length file */
+    if (AllowUserSize == 0) {
+	free(AllowedUsers);
+	AllowedUsers = malloc(sizeof(char));
+	AllowedUsers[0] = '\0';
+	return 0;
+    }
+    /* Free and allocate space for a string to store the allowed usernames */
+    free(AllowedUsers);
+
+    if ((AllowedUsers = malloc(sizeof(char) * (AllowUserSize + 3))) == NULL) {
+	syslog(LOG_USER | LOG_ERR, "Read_allowusers: malloc(AllowedUsers) failed.");
+	return 1;
+    }
+    /* Open the allowed users file. Report any errors. */
+
+    if ((AFile = fopen(Allowuserpath, "r")) == NULL) {
+	syslog(LOG_USER | LOG_ERR, "Read_allowusers: Failed to open allowed user file.");
+	syslog(LOG_USER | LOG_ERR, strerror(errno));
+	return 1;
+    }
+    /* Read user names into the AllowedUsers string.
+     * Make sure each string is delimited by a space. */
+
+    AllowedUsers[APos++] = ' ';
+
+    while (!feof(AFile)) {
+	if ((AChar = fgetc(AFile)) == EOF)
+	    break;
+	else {
+	    if (isspace(AChar))
+		AllowedUsers[APos++] = ' ';
+	    else
+		AllowedUsers[APos++] = toupper(AChar);
+	}
+    }
+
+    AllowedUsers[APos++] = ' ';
+    AllowedUsers[APos] = '\0';
+    fclose(AFile);
+    return 0;
+}
+
+/*
+ * Check to see if the username provided by Squid appears in the allowed
+ * user list. Returns 0 if the user was not found, and 1 if they were.
+ */
+
+int
+Check_ifuserallowed(char *ConnectingUser)
+{
+    static char CUBuf[NAMELEN + 1];
+    static char CUBuf1[NAMELEN + 1];
+    static int x;
+    static char AllowMsg[256];
+
+    /* If user string is empty, allow */
+    if (ConnectingUser[0] == '\0')
+	return 1;
+
+    /* If allowed user list is empty, allow all users.
+     * If no users are supposed to be using the proxy, stop squid instead. */
+    if (AllowUserSize == 0)
+	return 1;
+
+    /* Check if username string is found in the allowed user list.
+     * If so, allow. If not, deny. Reconstruct the username
+     * to have whitespace, to avoid finding wrong string subsets. */
+
+    sscanf(ConnectingUser, " %s ", CUBuf1);
+    sprintf(CUBuf, " %s ", CUBuf1);
+
+    for (x = 0; x <= strlen(CUBuf); x++)
+	CUBuf[x] = toupper(CUBuf[x]);
+
+    if (strstr(AllowedUsers, CUBuf) != NULL)
+	return 1;
+    else {			/* If NULL, they are not allowed to use the proxy */
+	sprintf(AllowMsg, "Did not allow access to user '%s'.", CUBuf1);
+	syslog(LOG_USER | LOG_ERR, AllowMsg);
+	return 0;
+    }
+}
+
+/*
+ * Checks if there has been a change in the allowed users file.
+ * If the modification time has changed, then reload the allowed user list.
+ * This function is called by the SIGHUP signal handler.
+ */
+
+void
+Check_forallowchange()
+{
+    struct stat ChkBuf;		/* Stat data buffer */
+
+    /* Stat the allowed users file. If it cannot be accessed, return. */
+
+    if (stat(Allowuserpath, &ChkBuf) == -1) {
+	if (errno == ENOENT) {
+	    LastModTime = (time_t) 0;
+	    AllowUserSize = 0;
+	    free(AllowedUsers);
+	    AllowedUsers = malloc(sizeof(char));
+	    AllowedUsers[0] = '\0';
+	    return;
+	} else {		/* Report error when accessing file */
+	    syslog(LOG_USER | LOG_ERR, strerror(errno));
+	    return;
+	}
+    }
+    /* If found, compare the modification time with the previously-recorded
+     * modification time.
+     * If the modification time has changed, reload the allowed user list.
+     * Log a message of its actions. */
+
+    if (ChkBuf.st_mtime != LastModTime) {
+	syslog(LOG_USER | LOG_INFO, "Check_forallowchange: Reloading allowed user list.");
+	Read_allowusers();
+    }
+}
Index: squid/src/auth/basic/helpers/MSNT/confload.c
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/confload.c:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/auth/basic/helpers/MSNT/confload.c	Tue Sep  3 10:42:11 2002
@@ -0,0 +1,249 @@
+
+/*
+ * confload.c
+ * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd
+ * Released under GPL, see COPYING-2.0 for details.
+ * 
+ * These routines load the msntauth configuration file.
+ * It stores the servers to query, sets the denied and
+ * allowed user files, and provides the 
+ * authenticating function.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <netdb.h>
+
+#include "msntauth.h"
+#include "valid.h"
+
+#define CONFIGFILE   "/usr/local/squid/etc/msntauth.conf"	/* Path to configuration file */
+#define DENYUSERSDEFAULT   "/usr/local/squid/etc/denyusers"
+#define ALLOWUSERSDEFAULT  "/usr/local/squid/etc/allowusers"
+
+#define MAXSERVERS 5		/* Maximum number of servers to query. This number can be increased. */
+#define NTHOSTLEN 65
+
+extern char Denyuserpath[MAXPATHLEN];	/* MAXPATHLEN defined in param.h */
+extern char Allowuserpath[MAXPATHLEN];
+
+typedef struct _ServerTuple {
+    char pdc[NTHOSTLEN];
+    char bdc[NTHOSTLEN];
+    char domain[NTHOSTLEN];
+} ServerTuple;
+
+ServerTuple ServerArray[MAXSERVERS];	/* Array of servers to query */
+int Serversqueried = 0;		/* Number of servers queried */
+
+/* Declarations */
+
+static void ProcessLine(char *);
+static void AddServer(char *, char *, char *);
+static int QueryServerForUser(int, char *, char *);
+
+/*
+ * Opens and reads the configuration file.
+ * Returns 0 on success, or 1 for error.
+ */
+
+int
+OpenConfigFile(void)
+{
+    FILE *ConfigFile;
+    char Confbuf[2049];		/* Line reading buffer */
+
+    /* Initialise defaults */
+
+    Serversqueried = 0;
+    strcpy(Denyuserpath, DENYUSERSDEFAULT);
+    strcpy(Allowuserpath, ALLOWUSERSDEFAULT);
+
+    /* Open file */
+    if ((ConfigFile = fopen(CONFIGFILE, "r")) == NULL) {
+	syslog(LOG_USER | LOG_ERR, "OpenConfigFile: Failed to open %s.", CONFIGFILE);
+	syslog(LOG_USER | LOG_ERR, strerror(errno));
+	return 1;
+    }
+    /* Read in, one line at a time */
+
+    while (!feof(ConfigFile)) {
+	Confbuf[0] = '\0';
+	fgets(Confbuf, 2049, ConfigFile);
+	ProcessLine(Confbuf);
+    }
+
+    /* Check that at least one server is being queried. Report error if not.
+     * Denied and allowed user files are hardcoded, so it's fine if they're
+     * not set in the confugration file. */
+
+    if (Serversqueried == 0) {
+	syslog(LOG_USER | LOG_ERR, "OpenConfigFile: No servers set in %s. At least one is needed.", CONFIGFILE);
+	return 1;
+    }
+    fclose(ConfigFile);
+    return 0;
+}
+
+/* Parses a configuration file line. */
+
+static void
+ProcessLine(char *Linebuf)
+{
+    char *Directive;
+    char *Param1;
+    char *Param2;
+    char *Param3;
+
+    /* Ignore empty lines */
+    if (strlen(Linebuf) == 0)
+	return;
+
+    /* Break up on whitespaces */
+    if ((Directive = strtok(Linebuf, " \t\n")) == NULL)
+	return;
+
+    /* Check for a comment line. If found, stop . */
+    if (Directive[0] == '#')
+	return;
+
+    /* Check for server line. Check for 3 parameters. */
+    if (strcasecmp(Directive, "server") == 0) {
+	Param1 = strtok(NULL, " \t\n");
+	Param2 = strtok(NULL, " \t\n");
+	Param3 = strtok(NULL, " \t\n");
+
+	if ((Param1[0] == '\0') ||
+	    (Param2[0] == '\0') ||
+	    (Param3[0] == '\0')) {
+	    syslog(LOG_USER | LOG_ERR, "ProcessLine: A 'server' line needs PDC, BDC, and domain parameters.");
+	    return;
+	}
+	AddServer(Param1, Param2, Param3);
+	return;
+    }
+    /* Check for denyusers line */
+    if (strcasecmp(Directive, "denyusers") == 0) {
+	Param1 = strtok(NULL, " \t\n");
+
+	if (Param1[0] == '\0') {
+	    syslog(LOG_USER | LOG_ERR, "ProcessLine: A 'denyusers' line needs a filename parameter.");
+	    return;
+	}
+	strcpy(Denyuserpath, Param1);
+	return;
+    }
+    /* Check for allowusers line */
+    if (strcasecmp(Directive, "allowusers") == 0) {
+	Param1 = strtok(NULL, " \t\n");
+
+	if (Param1[0] == '\0') {
+	    syslog(LOG_USER | LOG_ERR, "ProcessLine: An 'allowusers' line needs a filename parameter.");
+	    return;
+	}
+	strcpy(Allowuserpath, Param1);
+	return;
+    }
+    /* Reports error for unknown line */
+    syslog(LOG_USER | LOG_ERR, "ProcessLine: Ignoring '%s' line.", Directive);
+}
+
+/*
+ * Adds a server to query to the server array.
+ * Checks if the server IP is resolvable.
+ * Checks if the number of servers to query is not exceeded.
+ * Does not allow parameters longer than NTHOSTLEN.
+ */
+
+void
+AddServer(char *ParamPDC, char *ParamBDC, char *ParamDomain)
+{
+    if (Serversqueried + 1 > MAXSERVERS) {
+	syslog(LOG_USER | LOG_ERR, "AddServer: Ignoring '%s' server line; too many servers.", ParamPDC);
+	return;
+    }
+    if (gethostbyname(ParamPDC) == (struct hostent *) NULL) {
+	syslog(LOG_USER | LOG_ERR, "AddServer: Ignoring host '%s'. Cannot resolve its address.", ParamPDC);
+	return;
+    }
+    if (gethostbyname(ParamBDC) == (struct hostent *) NULL) {
+	syslog(LOG_USER | LOG_ERR, "AddServer: Ignoring host '%s'. Cannot resolve its address.", ParamBDC);
+	return;
+    }
+    Serversqueried++;
+    strncpy(ServerArray[Serversqueried].pdc, ParamPDC, NTHOSTLEN);
+    strncpy(ServerArray[Serversqueried].bdc, ParamBDC, NTHOSTLEN);
+    strncpy(ServerArray[Serversqueried].domain, ParamDomain, NTHOSTLEN);
+    ServerArray[Serversqueried].pdc[NTHOSTLEN - 1] = '\0';
+    ServerArray[Serversqueried].bdc[NTHOSTLEN - 1] = '\0';
+    ServerArray[Serversqueried].domain[NTHOSTLEN - 1] = '\0';
+}
+
+/*
+ * Cycles through all servers to query.
+ * Returns 0 if one server could authenticate the user.
+ * Returns 1 if no server authenticated the user.
+ */
+
+int
+QueryServers(char *username, char *password)
+{
+    int Queryresult = 1;	/* Default result is an error */
+    int x = 1;
+
+    while (x <= Serversqueried) {	/* Query one server. Change Queryresult if user passed. */
+	if (QueryServerForUser(x++, username, password) == 0) {
+	    Queryresult = 0;
+	    break;
+	}
+    }
+
+    return Queryresult;
+}
+
+/*
+ * Attempts to authenticate the user with one server.
+ * Logs syslog messages for different errors.
+ * Returns 0 on success, non-zero on failure.
+ */
+
+/* Define for systems which don't support it, like Solaris */
+#ifndef LOG_AUTHPRIV
+#define LOG_AUTHPRIV LOG_AUTH
+#endif
+
+int
+QueryServerForUser(int x, char *username, char *password)
+{
+    int result = 1;
+
+    result = Valid_User(username, password, ServerArray[x].pdc,
+	ServerArray[x].bdc, ServerArray[x].domain);
+
+    switch (result) {		/* Write any helpful syslog messages */
+    case 0:
+	break;
+    case 1:
+	syslog(LOG_AUTHPRIV | LOG_INFO, "Server error when checking %s.", username);
+	break;
+    case 2:
+	syslog(LOG_AUTHPRIV | LOG_INFO, "Protocol error when checking %s.", username);
+	break;
+    case 3:
+	syslog(LOG_AUTHPRIV | LOG_INFO, "Authentication failed for %s.", username);
+    }
+
+    return result;
+}
+
+/* Valid_User return codes -
+ * 
+ * 0 - User authenticated successfully.
+ * 1 - Server error.
+ * 2 - Protocol error.
+ * 3 - Logon error; Incorrect password or username given.
+ */
Index: squid/src/auth/basic/helpers/MSNT/denyusers.c
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/denyusers.c:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/auth/basic/helpers/MSNT/denyusers.c	Tue Sep  3 10:42:11 2002
@@ -0,0 +1,250 @@
+
+/*
+ * denyusers.c
+ * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd
+ * Released under GPL, see COPYING-2.0 for details.
+ * 
+ * These routines are to block users attempting to use the proxy which
+ * have been explicitly denied by the system administrator.
+ * Routines at the bottom also use the allowed user functions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#define NAMELEN     50		/* Maximum username length */
+
+/* Global variables */
+
+char *DeniedUsers;		/* Pointer to string of denied users */
+off_t DenyUserSize;		/* Size of denied user file */
+struct stat FileBuf;		/* Stat data buffer */
+time_t LastModTime;		/* Last denied user file modification time */
+
+char Denyuserpath[MAXPATHLEN];	/* MAXPATHLEN defined in param.h */
+
+/* Function declarations */
+
+int Read_denyusers();
+int Check_ifuserdenied(char *);
+int Check_user(char *);
+void Checktimer();
+void Check_forchange();
+void Check_fordenychange();
+extern void Check_forallowchange();	/* For allowed users */
+extern int Check_ifuserallowed(char *);
+
+/*
+ * Reads Denyuserpath for all users to be excluded.
+ * Returns 0 if the user list was successfully loaded,
+ * and 1 in case of error.
+ * Logs any messages to the syslog daemon.
+ */
+
+int
+Read_denyusers()
+{
+    FILE *DFile;		/* Denied user file pointer */
+    off_t DPos = 0;		/* File counter */
+    char DChar;			/* Character buffer */
+
+    /* Stat the file. If it does not exist, save the size as zero.
+     * Clear the denied user string. Return. */
+    if (stat(Denyuserpath, &FileBuf) == -1) {
+	if (errno == ENOENT) {
+	    LastModTime = (time_t) 0;
+	    DenyUserSize = 0;
+	    free(DeniedUsers);
+	    DeniedUsers = malloc(sizeof(char));
+	    DeniedUsers[0] = '\0';
+	    return 0;
+	} else {
+	    syslog(LOG_USER | LOG_ERR, strerror(errno));
+	    return 1;
+	}
+    }
+    /* If it exists, save the modification time and size */
+    LastModTime = FileBuf.st_mtime;
+    DenyUserSize = FileBuf.st_size;
+
+    /* Handle the special case of a zero length file */
+    if (DenyUserSize == 0) {
+	free(DeniedUsers);
+	DeniedUsers = malloc(sizeof(char));
+	DeniedUsers[0] = '\0';
+	return 0;
+    }
+    /* Free and allocate space for a string to store the denied usernames */
+    free(DeniedUsers);
+
+    if ((DeniedUsers = malloc(sizeof(char) * (DenyUserSize + 3))) == NULL) {
+	syslog(LOG_USER | LOG_ERR, "Read_denyusers: malloc(DeniedUsers) failed.");
+	return 1;
+    }
+    /* Open the denied user file. Report any errors. */
+
+    if ((DFile = fopen(Denyuserpath, "r")) == NULL) {
+	syslog(LOG_USER | LOG_ERR, "Read_denyusers: Failed to open denied user file.");
+	syslog(LOG_USER | LOG_ERR, strerror(errno));
+	return 1;
+    }
+    /* Read user names into the DeniedUsers string.
+     * Make sure each string is delimited by a space. */
+
+    DeniedUsers[DPos++] = ' ';
+
+    while (!feof(DFile)) {
+	if ((DChar = fgetc(DFile)) == EOF)
+	    break;
+	else {
+	    if (isspace(DChar))
+		DeniedUsers[DPos++] = ' ';
+	    else
+		DeniedUsers[DPos++] = toupper(DChar);
+	}
+    }
+
+    DeniedUsers[DPos++] = ' ';
+    DeniedUsers[DPos] = '\0';
+    fclose(DFile);
+    return 0;
+}
+
+/*
+ * Check to see if the username provided by Squid appears in the denied
+ * user list. Returns 0 if the user was not found, and 1 if they were.
+ */
+
+int
+Check_ifuserdenied(char *ConnectingUser)
+{
+    static char CUBuf[NAMELEN + 1];
+    static char CUBuf1[NAMELEN + 1];
+    static int x;
+    static char DenyMsg[256];
+
+    /* If user string is empty, deny */
+    if (ConnectingUser[0] == '\0')
+	return 1;
+
+    /* If denied user list is empty, allow */
+    if (DenyUserSize == 0)
+	return 0;
+
+    /* Check if username string is found in the denied user list.
+     * If so, deny. If not, allow. Reconstruct the username
+     * to have whitespace, to avoid finding wrong string subsets. */
+
+    sscanf(ConnectingUser, " %s ", CUBuf1);
+    sprintf(CUBuf, " %s ", CUBuf1);
+
+    for (x = 0; x <= strlen(CUBuf); x++)
+	CUBuf[x] = toupper(CUBuf[x]);
+
+    if (strstr(DeniedUsers, CUBuf) == NULL)
+	return 0;
+    else {
+	sprintf(DenyMsg, "Denied access to user '%s'.", CUBuf1);
+	syslog(LOG_USER | LOG_ERR, DenyMsg);
+	return 1;
+    }
+}
+
+/*
+ * Checks if there has been a change in the denied user file.
+ * If the modification time has changed, then reload the denied user list.
+ * This function is called by the SIGHUP signal handler.
+ */
+
+void
+Check_fordenychange()
+{
+    struct stat ChkBuf;		/* Stat data buffer */
+
+    /* Stat the denied user file. If it cannot be accessed, return. */
+
+    if (stat(Denyuserpath, &ChkBuf) == -1) {
+	if (errno == ENOENT) {
+	    LastModTime = (time_t) 0;
+	    DenyUserSize = 0;
+	    free(DeniedUsers);
+	    DeniedUsers = malloc(sizeof(char));
+	    DeniedUsers[0] = '\0';
+	    return;
+	} else {		/* Report error when accessing file */
+	    syslog(LOG_USER | LOG_ERR, strerror(errno));
+	    return;
+	}
+    }
+    /* If found, compare the modification time with the previously-recorded
+     * modification time.
+     * If the modification time has changed, reload the denied user list.
+     * Log a message of its actions. */
+
+    if (ChkBuf.st_mtime != LastModTime) {
+	syslog(LOG_USER | LOG_INFO, "Check_fordenychange: Reloading denied user list.");
+	Read_denyusers();
+    }
+}
+
+/*
+ * Decides if a user is denied or allowed.
+ * If they have been denied, or not allowed, return 1.
+ * Else return 0.
+ */
+
+int
+Check_user(char *ConnectingUser)
+{
+    if (Check_ifuserdenied(ConnectingUser) == 1)
+	return 1;
+
+    if (Check_ifuserallowed(ConnectingUser) == 0)
+	return 1;
+
+    return 0;
+}
+
+/*
+ * Checks the denied and allowed user files for change.
+ * This function is invoked when a SIGHUP signal is received.
+ * It is also run after every 60 seconds, at the next request.
+ */
+
+void
+Check_forchange()
+{
+    Check_fordenychange();
+    Check_forallowchange();
+}
+
+/*
+ * Checks the timer. If longer than 1 minute has passed since the last
+ * time someone has accessed the proxy, then check for changes in the
+ * denied user file. If longer than one minute hasn't passed, return.
+ */
+
+void
+Checktimer()
+{
+    static time_t Lasttime;	/* The last time the timer was checked */
+    static time_t Currenttime;	/* The current time */
+
+    Currenttime = time(NULL);
+
+    /* If timeout has expired, check the denied user file, else return */
+    if (difftime(Currenttime, Lasttime) < 60)
+	return;
+    else {
+	Check_forchange();
+	Lasttime = Currenttime;
+    }
+}
Index: squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:39 2004
+++ squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm	Tue Sep  3 10:42:11 2002
@@ -0,0 +1,13 @@
+Begin3
+Title:         msntauth 
+Version:       2.0 
+Entered-date:  01SEP01 
+Description:   Squid web proxy NT domain authentication module 
+Keywords:      Squid WWW proxy SMB NT domain authentication module source
+Author:         antonino@rager.com.au (Antonino Iannella)
+Maintained-by:  antonino@rager.com.au (Antonino Iannella)
+Primary-site:   sunsite.unc.edu /pub/Linux/system/network/misc
+		msntauth-v2.0.tgz
+Original-site:  http://members.tripod.com/stellarx
+Copying-policy: GPL
+End
Index: squid/src/auth/basic/helpers/MSNT/msntauth.c
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.c:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/MSNT/msntauth.c	Tue Sep  3 10:42:12 2002
@@ -0,0 +1,112 @@
+
+/*
+ * MSNT - Microsoft Windows NT domain squid authenticator module
+ * Version 2.0 by Stellar-X Pty Ltd, Antonino Iannella
+ * Sun Sep  2 14:39:53 CST 2001
+ * 
+ * Modified to act as a Squid authenticator module.
+ * Removed all Pike stuff.
+ * Returns OK for a successful authentication, or ERR upon error.
+ * 
+ * Uses code from -
+ * Andrew Tridgell 1997
+ * Richard Sharpe 1996
+ * Bill Welliver 1999
+ * Duane Wessels 2000 (wessels@squid-cache.org)
+ * 
+ * Released under GNU Public License
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <syslog.h>
+#include <sys/time.h>
+
+#include "msntauth.h"
+
+extern char version[];
+char msntauth_version[] = "Msntauth v2.0.3 (C) 2 Sep 2001 Stellar-X Antonino Iannella.";
+
+/* Main program for simple authentication.
+ * Reads the denied user file. Sets alarm timer.
+ * Scans and checks for Squid input, and attempts to validate the user.
+ */
+
+int
+main()
+{
+    char username[256];
+    char password[256];
+    char wstr[256];
+
+    /* Read configuration file. Abort wildly if error. */
+    if (OpenConfigFile() == 1)
+	return 1;
+
+    /* Read denied and allowed user files.
+     * If they fails, there is a serious problem.
+     * Check syslog messages. Deny all users while in this state.
+     * The msntauth process should then be killed. */
+
+    if ((Read_denyusers() == 1) || (Read_allowusers() == 1)) {
+	while (1) {
+	    fgets(wstr, 255, stdin);
+	    puts("ERR");
+	    fflush(stdout);
+	}
+    }
+    /* Make Check_forchange() the handle for HUP signals.
+     * Don't use alarms any more. I don't think it was very
+     * portable between systems. */
+    signal(SIGHUP, Check_forchange);
+
+    while (1) {
+	/* Read whole line from standard input. Terminate on break. */
+	if (fgets(wstr, 255, stdin) == NULL)
+	    break;
+
+	/* Clear any current settings. Read new ones. Use \n as a 
+	 * convenient EOL marker which is not even there. */
+	username[0] = '\0';
+	password[0] = '\0';
+	sscanf(wstr, "%s %[^\n]", username, password);	/* Extract parameters */
+
+	/* Check for invalid or blank entries */
+	if ((username[0] == '\0') || (password[0] == '\0')) {
+	    puts("ERR");
+	    fflush(stdout);
+	    continue;
+	}
+	Checktimer();		/* Check if the user lists have changed */
+
+	/* Check if user is explicitly denied or allowed.
+	 * If user passes both checks, they can be authenticated. */
+
+	if (Check_user(username) == 1)
+	    puts("ERR");
+	else {
+	    if (QueryServers(username, password) == 0)
+		puts("OK");
+	    else
+		puts("ERR");
+	}
+
+	fflush(stdout);
+    }
+
+    return 0;
+}
Index: squid/src/auth/basic/helpers/MSNT/msntauth.conf
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.conf:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/MSNT/msntauth.conf	Tue Sep  3 10:42:12 2002
@@ -0,0 +1,13 @@
+
+# Sample MSNT authenticator configuration file
+# Antonino Iannella, Stellar-X Pty Ltd
+# Sun Sep  2 15:52:31 CST 2001
+
+# NT hosts to use. Best to put their IP addresses in /etc/hosts.
+server my_PDC		my_BDC		my_NTdomain
+server other_PDC	other_BDC	otherdomain
+
+# Denied and allowed users. Comment these if not needed.
+denyusers	/usr/local/squid/etc/denyusers
+allowusers	/usr/local/squid/etc/allowusers
+
Index: squid/src/auth/basic/helpers/MSNT/msntauth.h
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/MSNT/msntauth.h	Tue Sep  3 10:42:12 2002
@@ -0,0 +1,8 @@
+extern int OpenConfigFile(void);
+extern int QueryServers(char *, char *);
+extern void Checktimer(void);
+extern void Check_forchange();
+extern int Read_denyusers(void);
+extern int Read_allowusers(void);
+extern int Check_user(char *);
+extern int QueryServers(char *, char *);
Index: squid/src/auth/basic/helpers/MSNT/rfcnb-io.c
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/rfcnb-io.c:1.3.2.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/MSNT/rfcnb-io.c	Tue Sep  3 10:42:13 2002
@@ -0,0 +1,419 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB IO Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* #include <features.h> */
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+#include <sys/uio.h>
+#include <sys/signal.h>
+#include <string.h>
+
+
+int RFCNB_Timeout = 0;		/* Timeout in seconds ... */
+
+void
+rfcnb_alarm(int sig)
+{
+
+    fprintf(stderr, "IO Timed out ...\n");
+
+}
+
+/* Set timeout value and setup signal handling */
+
+int
+RFCNB_Set_Timeout(int seconds)
+{
+#ifdef __GLIBC__
+    int temp;
+#endif
+    /* If we are on a Bezerkeley system, use sigvec, else sigaction */
+#ifndef SA_RESTART
+    struct sigvec invec, outvec;
+#else
+    struct sigaction inact, outact;
+#endif
+
+    RFCNB_Timeout = seconds;
+
+    if (RFCNB_Timeout > 0) {	/* Set up handler to ignore but not restart */
+
+#ifndef SA_RESTART
+	invec.sv_handler = (void (*)()) rfcnb_alarm;
+	invec.sv_mask = 0;
+	invec.sv_flags = SV_INTERRUPT;
+
+	if (sigvec(SIGALRM, &invec, &outvec) < 0)
+	    return (-1);
+#else
+	inact.sa_handler = (void (*)()) rfcnb_alarm;
+#ifdef SOLARIS
+	/* Solaris seems to have an array of vectors ... */
+	inact.sa_mask.__sigbits[0] = 0;
+	inact.sa_mask.__sigbits[1] = 0;
+	inact.sa_mask.__sigbits[2] = 0;
+	inact.sa_mask.__sigbits[3] = 0;
+#else
+#ifdef __GLIBC__
+	for (temp = 0; temp < 32; temp++)
+	    inact.sa_mask.__val[temp] = 0;
+#else
+	/* AI - If you have problems with this line, contact the author */
+	/* AI - This is the old line: inact.sa_mask = 0; */
+	memset(&inact.sa_mask, 0, sizeof(inact.sa_mask));
+#endif
+#endif
+	inact.sa_flags = 0;	/* Don't restart */
+
+	if (sigaction(SIGALRM, &inact, &outact) < 0)
+	    return (-1);
+
+#endif
+
+    }
+    return (0);
+
+}
+
+/* Discard the rest of an incoming packet as we do not have space for it
+ * in the buffer we allocated or were passed ...                         */
+
+int
+RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
+{
+    char temp[100];		/* Read into here */
+    int rest, this_read, bytes_read;
+
+    /* len is the amount we should read */
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Discard_Rest called to discard: %i\n", len);
+#endif
+
+    rest = len;
+
+    while (rest > 0) {
+
+	this_read = (rest > sizeof(temp) ? sizeof(temp) : rest);
+
+	bytes_read = read(con->fd, temp, this_read);
+
+	if (bytes_read <= 0) {	/* Error so return */
+
+	    if (bytes_read < 0)
+		RFCNB_errno = RFCNBE_BadRead;
+	    else
+		RFCNB_errno = RFCNBE_ConGone;
+
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	}
+	rest = rest - bytes_read;
+
+    }
+
+    return (0);
+
+}
+
+
+/* Send an RFCNB packet to the connection.
+ * 
+ * We just send each of the blocks linked together ... 
+ * 
+ * If we can, try to send it as one iovec ... 
+ * 
+ */
+
+int
+RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+{
+    int len_sent, tot_sent, this_len;
+    struct RFCNB_Pkt *pkt_ptr;
+    char *this_data;
+    int i;
+    struct iovec io_list[10];	/* We should never have more      */
+    /* If we do, this will blow up ... */
+
+    /* Try to send the data ... We only send as many bytes as len claims */
+    /* We should try to stuff it into an IOVEC and send as one write     */
+
+
+    pkt_ptr = pkt;
+    len_sent = tot_sent = 0;	/* Nothing sent so far */
+    i = 0;
+
+    while ((pkt_ptr != NULL) & (i < 10)) {	/* Watch that magic number! */
+
+	this_len = pkt_ptr->len;
+	this_data = pkt_ptr->data;
+	if ((tot_sent + this_len) > len)
+	    this_len = len - tot_sent;	/* Adjust so we don't send too much */
+
+	/* Now plug into the iovec ... */
+
+	io_list[i].iov_len = this_len;
+	io_list[i].iov_base = this_data;
+	i++;
+
+	tot_sent += this_len;
+
+	if (tot_sent == len)
+	    break;		/* Let's not send too much */
+
+	pkt_ptr = pkt_ptr->next;
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent);
+#endif
+
+    /* Set up an alarm if timeouts are set ... */
+
+    if (RFCNB_Timeout > 0)
+	alarm(RFCNB_Timeout);
+
+    if ((len_sent = writev(con->fd, io_list, i)) < 0) {		/* An error */
+
+	con->rfc_errno = errno;
+	if (errno == EINTR)	/* We were interrupted ... */
+	    RFCNB_errno = RFCNBE_Timeout;
+	else
+	    RFCNB_errno = RFCNBE_BadWrite;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+
+    }
+    if (len_sent < tot_sent) {	/* Less than we wanted */
+	if (errno == EINTR)	/* We were interrupted */
+	    RFCNB_errno = RFCNBE_Timeout;
+	else
+	    RFCNB_errno = RFCNBE_BadWrite;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+    }
+    if (RFCNB_Timeout > 0)
+	alarm(0);		/* Reset that sucker */
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Len sent = %i ...\n", len_sent);
+    RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent);	/* Print what send ... */
+
+#endif
+
+    return (len_sent);
+
+}
+
+/* Read an RFCNB packet off the connection. 
+ * 
+ * We read the first 4 bytes, that tells us the length, then read the
+ * rest. We should implement a timeout, but we don't just yet 
+ * 
+ */
+
+
+int
+RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+{
+    int read_len, pkt_len;
+    char hdr[RFCNB_Pkt_Hdr_Len];	/* Local space for the header */
+    struct RFCNB_Pkt *pkt_frag;
+    int more, this_time, offset, frag_len, this_len;
+    BOOL seen_keep_alive = TRUE;
+
+    /* Read that header straight into the buffer */
+
+    if (len < RFCNB_Pkt_Hdr_Len) {	/* What a bozo */
+
+#ifdef RFCNB_DEBUG
+	fprintf(stderr, "Trying to read less than a packet:");
+	perror("");
+#endif
+	RFCNB_errno = RFCNBE_BadParam;
+	return (RFCNBE_Bad);
+
+    }
+    /* We discard keep alives here ... */
+
+    if (RFCNB_Timeout > 0)
+	alarm(RFCNB_Timeout);
+
+    while (seen_keep_alive) {
+
+	if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) {		/* Problems */
+#ifdef RFCNB_DEBUG
+	    fprintf(stderr, "Reading the packet, we got:");
+	    perror("");
+#endif
+	    if (errno == EINTR)
+		RFCNB_errno = RFCNBE_Timeout;
+	    else
+		RFCNB_errno = RFCNBE_BadRead;
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	}
+	/* Now we check out what we got */
+
+	if (read_len == 0) {	/* Connection closed, send back eof?  */
+
+#ifdef RFCNB_DEBUG
+	    fprintf(stderr, "Connection closed reading\n");
+#endif
+
+	    if (errno == EINTR)
+		RFCNB_errno = RFCNBE_Timeout;
+	    else
+		RFCNB_errno = RFCNBE_ConGone;
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	}
+	if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) {
+
+#ifdef RFCNB_DEBUG
+	    fprintf(stderr, "RFCNB KEEP ALIVE received\n");
+#endif
+
+	} else {
+	    seen_keep_alive = FALSE;
+	}
+
+    }
+
+    /* What if we got less than or equal to a hdr size in bytes? */
+
+    if (read_len < sizeof(hdr)) {	/* We got a small packet */
+
+	/* Now we need to copy the hdr portion we got into the supplied packet */
+
+	memcpy(pkt->data, hdr, read_len);	/*Copy data */
+
+#ifdef RFCNB_DEBUG
+	RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
+#endif
+
+	return (read_len);
+
+    }
+    /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
+
+    pkt_len = RFCNB_Pkt_Len(hdr);
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len);
+#endif
+
+    /* Now copy in the hdr */
+
+    memcpy(pkt->data, hdr, sizeof(hdr));
+
+    /* Get the rest of the packet ... first figure out how big our buf is? */
+    /* And make sure that we handle the fragments properly ... Sure should */
+    /* use an iovec ...                                                    */
+
+    if (len < pkt_len)		/* Only get as much as we have space for */
+	more = len - RFCNB_Pkt_Hdr_Len;
+    else
+	more = pkt_len;
+
+    this_time = 0;
+
+    /* We read for each fragment ... */
+
+    if (pkt->len == read_len) {	/* If this frag was exact size */
+	pkt_frag = pkt->next;	/* Stick next lot in next frag */
+	offset = 0;		/* then we start at 0 in next  */
+    } else {
+	pkt_frag = pkt;		/* Otherwise use rest of this frag */
+	offset = RFCNB_Pkt_Hdr_Len;	/* Otherwise skip the header       */
+    }
+
+    frag_len = pkt_frag->len;
+
+    if (more <= frag_len)	/* If len left to get less than frag space */
+	this_len = more;	/* Get the rest ...                        */
+    else
+	this_len = frag_len - offset;
+
+    while (more > 0) {
+
+	if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) {	/* Problems */
+
+	    if (errno == EINTR) {
+
+		RFCNB_errno = RFCNB_Timeout;
+
+	    } else {
+		if (this_time < 0)
+		    RFCNB_errno = RFCNBE_BadRead;
+		else
+		    RFCNB_errno = RFCNBE_ConGone;
+	    }
+
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	}
+#ifdef RFCNB_DEBUG
+	fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len,
+	    this_time, this_len, more);
+#endif
+
+	read_len = read_len + this_time;	/* How much have we read ... */
+
+	/* Now set up the next part */
+
+	if (pkt_frag->next == NULL)
+	    break;		/* That's it here */
+
+	pkt_frag = pkt_frag->next;
+	this_len = pkt_frag->len;
+	offset = 0;
+
+	more = more - this_time;
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
+    RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
+#endif
+
+    if (read_len < (pkt_len + sizeof(hdr))) {	/* Discard the rest */
+
+	return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
+
+    }
+    if (RFCNB_Timeout > 0)
+	alarm(0);		/* Reset that sucker */
+
+    return (read_len + sizeof(RFCNB_Hdr));
+}
Index: squid/src/auth/basic/helpers/MSNT/smbencrypt.c
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smbencrypt.c:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/MSNT/smbencrypt.c	Tue Sep  3 10:42:14 2002
@@ -0,0 +1,209 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1997
+ * Modified by Jeremy Allison 1995.
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <string.h>
+#include <ctype.h>
+
+/* AI inclusion for Solaris filesystem */
+#ifdef SOLARIS
+#include <sys/vfs.h>
+#endif
+
+#include "smblib-priv.h"
+#define uchar unsigned char
+extern int DEBUGLEVEL;
+
+#include "byteorder.h"
+
+char *StrnCpy(char *dest, char *src, int n);
+void strupper(char *s);
+extern void E_P16(unsigned char *, unsigned char *);
+extern void E_P24(unsigned char *, unsigned char *, unsigned char *);
+extern void mdfour(unsigned char *, unsigned char *, int);
+
+
+/*
+ * This implements the X/Open SMB password encryption
+ * It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
+ * encrypted password into p24 */
+void
+SMBencrypt(uchar * passwd, uchar * c8, uchar * p24)
+{
+    uchar p14[15], p21[21];
+
+    memset(p21, '\0', 21);
+    memset(p14, '\0', 14);
+    StrnCpy((char *) p14, (char *) passwd, 14);
+
+    strupper((char *) p14);
+    E_P16(p14, p21);
+    E_P24(p21, c8, p24);
+}
+
+/* Routines for Windows NT MD4 Hash functions. */
+static int
+_my_wcslen(int16 * str)
+{
+    int len = 0;
+    while (*str++ != 0)
+	len++;
+    return len;
+}
+
+/*
+ * Convert a string into an NT UNICODE string.
+ * Note that regardless of processor type 
+ * this must be in intel (little-endian)
+ * format.
+ */
+
+static int
+_my_mbstowcs(int16 * dst, uchar * src, int len)
+{
+    int i;
+    int16 val;
+
+    for (i = 0; i < len; i++) {
+	val = *src;
+	SSVAL(dst, 0, val);
+	dst++;
+	src++;
+	if (val == 0)
+	    break;
+    }
+    return i;
+}
+
+/* 
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ */
+
+void
+E_md4hash(uchar * passwd, uchar * p16)
+{
+    int len;
+    int16 wpwd[129];
+
+    /* Password cannot be longer than 128 characters */
+    len = strlen((char *) passwd);
+    if (len > 128)
+	len = 128;
+    /* Password must be converted to NT unicode */
+    _my_mbstowcs(wpwd, passwd, len);
+    wpwd[len] = 0;		/* Ensure string is null terminated */
+    /* Calculate length in bytes */
+    len = _my_wcslen(wpwd) * sizeof(int16);
+
+    mdfour(p16, (unsigned char *) wpwd, len);
+}
+
+/* Does the NT MD4 hash then des encryption. */
+
+void
+SMBNTencrypt(uchar * passwd, uchar * c8, uchar * p24)
+{
+    uchar p21[21];
+
+    memset(p21, '\0', 21);
+
+    E_md4hash(passwd, p21);
+    E_P24(p21, c8, p24);
+}
+
+/* Does both the NT and LM owfs of a user's password */
+
+void
+nt_lm_owf_gen(char *pwd, char *nt_p16, char *p16)
+{
+    char passwd[130];
+    StrnCpy(passwd, pwd, sizeof(passwd) - 1);
+
+    /* Calculate the MD4 hash (NT compatible) of the password */
+    memset(nt_p16, '\0', 16);
+    E_md4hash((uchar *) passwd, (uchar *) nt_p16);
+
+    /* Mangle the passwords into Lanman format */
+    passwd[14] = '\0';
+    strupper(passwd);
+
+    /* Calculate the SMB (lanman) hash functions of the password */
+
+    memset(p16, '\0', 16);
+    E_P16((uchar *) passwd, (uchar *) p16);
+
+    /* clear out local copy of user's password (just being paranoid). */
+    bzero(passwd, sizeof(passwd));
+}
+
+/****************************************************************************
+line strncpy but always null terminates. Make sure there is room!
+****************************************************************************/
+char *
+StrnCpy(char *dest, char *src, int n)
+{
+    char *d = dest;
+    if (!dest)
+	return (NULL);
+    if (!src) {
+	*dest = 0;
+	return (dest);
+    }
+    while (n-- && (*d++ = *src++));
+    *d = 0;
+    return (dest);
+}
+
+void
+strupper(char *s)
+{
+    while (*s) {
+#if UNUSED_CODE
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+	if (lp_client_code_page() == KANJI_CODEPAGE) {
+
+	    if (is_shift_jis(*s)) {
+		if (is_sj_lower(s[0], s[1]))
+		    s[1] = sj_toupper2(s[1]);
+		s += 2;
+	    } else if (is_kana(*s)) {
+		s++;
+	    } else {
+		if (islower(*s))
+		    *s = toupper(*s);
+		s++;
+	    }
+	} else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+#endif /* UNUSED_CODE */
+	{
+	    if (islower(*s))
+		*s = toupper(*s);
+	    s++;
+	}
+    }
+}
Index: squid/src/auth/basic/helpers/MSNT/smblib-util.c
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smblib-util.c:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/MSNT/smblib-util.c	Tue Sep  3 10:42:15 2002
@@ -0,0 +1,803 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Utility Routines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "smblib-priv.h"
+
+#include "rfcnb.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *SMB_Prots[] =
+{"PC NETWORK PROGRAM 1.0",
+    "MICROSOFT NETWORKS 1.03",
+    "MICROSOFT NETWORKS 3.0",
+    "DOS LANMAN1.0",
+    "LANMAN1.0",
+    "DOS LM1.2X002",
+    "LM1.2X002",
+    "DOS LANMAN2.1",
+    "LANMAN2.1",
+    "Samba",
+    "NT LM 0.12",
+    "NT LANMAN 1.0",
+    NULL};
+
+int SMB_Types[] =
+{SMB_P_Core,
+    SMB_P_CorePlus,
+    SMB_P_DOSLanMan1,
+    SMB_P_DOSLanMan1,
+    SMB_P_LanMan1,
+    SMB_P_DOSLanMan2,
+    SMB_P_LanMan2,
+    SMB_P_LanMan2_1,
+    SMB_P_LanMan2_1,
+    SMB_P_NT1,
+    SMB_P_NT1,
+    SMB_P_NT1,
+    -1};
+
+/* Print out an SMB pkt in all its gory detail ... */
+
+void
+SMB_Print_Pkt(FILE fd, RFCNB_Pkt * pkt, BOOL command, int Offset, int Len)
+{
+
+    /* Well, just how do we do this ... print it I suppose */
+
+    /* Print out the SMB header ...                        */
+
+    /* Print the command                                   */
+
+    /* Print the other bits in the header                  */
+
+
+    /* etc                                                 */
+
+}
+
+/* Convert a DOS Date_Time to a local host type date time for printing */
+
+char *
+SMB_DOSTimToStr(int DOS_time)
+{
+    static char SMB_Time_Temp[48];
+    int DOS_sec, DOS_min, DOS_hour, DOS_day, DOS_month, DOS_year;
+
+    SMB_Time_Temp[0] = 0;
+
+    DOS_sec = (DOS_time & 0x001F) * 2;
+    DOS_min = (DOS_time & 0x07E0) >> 5;
+    DOS_hour = ((DOS_time & 0xF800) >> 11);
+
+    DOS_day = (DOS_time & 0x001F0000) >> 16;
+    DOS_month = (DOS_time & 0x01E00000) >> 21;
+    DOS_year = ((DOS_time & 0xFE000000) >> 25) + 80;
+
+    sprintf(SMB_Time_Temp, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month,
+	DOS_year, DOS_hour, DOS_min, DOS_sec);
+
+    return (SMB_Time_Temp);
+
+}
+
+/* Convert an attribute byte/word etc to a string ... We return a pointer
+ * to a static string which we guarantee is long enough. If verbose is 
+ * true, we print out long form of strings ...                            */
+
+char *
+SMB_AtrToStr(int attribs, BOOL verbose)
+{
+    static char SMB_Attrib_Temp[128];
+
+    SMB_Attrib_Temp[0] = 0;
+
+    if (attribs & SMB_FA_ROF)
+	strcat(SMB_Attrib_Temp, (verbose ? "Read Only " : "R"));
+
+    if (attribs & SMB_FA_HID)
+	strcat(SMB_Attrib_Temp, (verbose ? "Hidden " : "H"));
+
+    if (attribs & SMB_FA_SYS)
+	strcat(SMB_Attrib_Temp, (verbose ? "System " : "S"));
+
+    if (attribs & SMB_FA_VOL)
+	strcat(SMB_Attrib_Temp, (verbose ? "Volume " : "V"));
+
+    if (attribs & SMB_FA_DIR)
+	strcat(SMB_Attrib_Temp, (verbose ? "Directory " : "D"));
+
+    if (attribs & SMB_FA_ARC)
+	strcat(SMB_Attrib_Temp, (verbose ? "Archive " : "A"));
+
+    return (SMB_Attrib_Temp);
+
+}
+
+/* Pick up the Max Buffer Size from the Tree Structure ... */
+
+int
+SMB_Get_Tree_MBS(SMB_Tree_Handle tree)
+{
+    if (tree != NULL) {
+	return (tree->mbs);
+    } else {
+	return (SMBlibE_BAD);
+    }
+}
+
+/* Pick up the Max buffer size */
+
+int
+SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+	return (Con_Handle->max_xmit);
+    } else {
+	return (SMBlibE_BAD);
+    }
+
+}
+/* Pickup the protocol index from the connection structure                 */
+
+int
+SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+	return (Con_Handle->prot_IDX);
+    } else {
+	return (0xFFFF);	/* Invalid protocol */
+    }
+
+}
+
+/* Pick up the protocol from the connection structure                       */
+
+int
+SMB_Get_Protocol(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+	return (Con_Handle->protocol);
+    } else {
+	return (0xFFFF);	/* Invalid protocol */
+    }
+
+}
+
+/* Figure out what protocol was accepted, given the list of dialect strings */
+/* We offered, and the index back from the server. We allow for a user      */
+/* supplied list, and assume that it is a subset of our list                */
+
+int
+SMB_Figure_Protocol(char *dialects[], int prot_index)
+{
+    int i;
+
+    if (dialects == SMB_Prots) {	/* The jobs is easy, just index into table */
+
+	return (SMB_Types[prot_index]);
+    } else {			/* Search through SMB_Prots looking for a match */
+
+	for (i = 0; SMB_Prots[i] != NULL; i++) {
+
+	    if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) {	/* A match */
+
+		return (SMB_Types[i]);
+
+	    }
+	}
+
+	/* If we got here, then we are in trouble, because the protocol was not */
+	/* One we understand ...                                                */
+
+	return (SMB_P_Unknown);
+
+    }
+
+}
+
+
+/* Negotiate the protocol we will use from the list passed in Prots       */
+/* we return the index of the accepted protocol in NegProt, -1 indicates  */
+/* none acceptible, and our return value is 0 if ok, <0 if problems       */
+
+int
+SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[])
+{
+    struct RFCNB_Pkt *pkt;
+    int prots_len, i, pkt_len, prot, alloc_len;
+    char *p;
+
+    /* Figure out how long the prot list will be and allocate space for it */
+
+    prots_len = 0;
+
+    for (i = 0; Prots[i] != NULL; i++) {
+
+	prots_len = prots_len + strlen(Prots[i]) + 2;	/* Account for null etc */
+
+    }
+
+    /* The -1 accounts for the one byte smb_buf we have because some systems */
+    /* don't like char msg_buf[]                                             */
+
+    pkt_len = SMB_negp_len + prots_len;
+
+    /* Make sure that the pkt len is long enough for the max response ...   */
+    /* Which is a problem, because the encryption key len eec may be long   */
+
+    if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
+
+	alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
+
+    } else {
+
+	alloc_len = pkt_len;
+
+    }
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(alloc_len);
+
+    if (pkt == NULL) {
+
+	SMBlib_errno = SMBlibE_NoSpace;
+	return (SMBlibE_BAD);
+
+    }
+    /* Now plug in the bits we need */
+
+    bzero(SMB_Hdr(pkt), SMB_negp_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
+
+    /* Now copy the prot strings in with the right stuff */
+
+    p = (char *) (SMB_Hdr(pkt) + SMB_negp_buf_offset);
+
+    for (i = 0; Prots[i] != NULL; i++) {
+
+	*p = SMBdialectID;
+	strcpy(p + 1, Prots[i]);
+	p = p + strlen(Prots[i]) + 2;	/* Adjust len of p for null plus dialectID */
+
+    }
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+
+#ifdef DEBUG
+	fprintf(stderr, "Error sending negotiate protocol\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_SendFailed;	/* Failed, check lower layer errno */
+	return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, alloc_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error receiving response to negotiate\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_RecvFailed;	/* Failed, check lower layer errno */
+	return (SMBlibE_BAD);
+
+    }
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {	/* Process error */
+
+#ifdef DEBUG
+	fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+	SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_Remote;
+	return (SMBlibE_BAD);
+
+    }
+    if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
+
+#ifdef DEBUG
+	fprintf(stderr, "None of our protocols was accepted ... ");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_NegNoProt;
+	return (SMBlibE_BAD);
+
+    }
+    /* Now, unpack the info from the response, if any and evaluate the proto */
+    /* selected. We must make sure it is one we like ...                     */
+
+    Con_Handle->prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
+    Con_Handle->protocol = SMB_Figure_Protocol(Prots, prot);
+
+    if (Con_Handle->protocol == SMB_P_Unknown) {	/* No good ... */
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_ProtUnknown;
+	return (SMBlibE_BAD);
+
+    }
+    switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
+
+    case 0x01:			/* No more info ... */
+
+	break;
+
+    case 13:			/* Up to and including LanMan 2.1 */
+
+	Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset);
+	Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00);
+	Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask;
+
+	Con_Handle->max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset);
+	Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset);
+	Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset);
+	Con_Handle->Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset);
+	Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset);
+	Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset);
+	Con_Handle->Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset);
+
+	p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset);
+	fprintf(stderr, "%d", (int) (SMB_Hdr(pkt) + SMB_negrLM_buf_offset));
+	memcpy(Con_Handle->Encrypt_Key, p, 8);
+
+	p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle->Encrypt_Key_Len);
+
+	strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1);
+
+	break;
+
+    case 17:			/* NT LM 0.12 and LN LM 1.0 */
+
+	Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset);
+	Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00);
+	Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask;
+
+	Con_Handle->max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset);
+	Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset);
+	Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset);
+	Con_Handle->MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset);
+	Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset);
+	Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset);
+	Con_Handle->Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset);
+
+	p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset);
+	memcpy(Con_Handle->Encrypt_Key, p, 8);
+	p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset + Con_Handle->Encrypt_Key_Len);
+
+	strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1);
+
+	break;
+
+    default:
+
+#ifdef DEBUG
+	fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
+	fprintf(stderr, "  wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
+#endif
+
+	break;
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    return (0);
+
+}
+
+/* Get our hostname */
+
+void
+SMB_Get_My_Name(char *name, int len)
+{
+
+    if (gethostname(name, len) < 0) {	/* Error getting name */
+
+	strncpy(name, "unknown", len);
+
+	/* Should check the error */
+
+#ifdef DEBUG
+	fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
+	perror("");
+#endif
+
+    }
+    /* only keep the portion up to the first "." */
+
+
+}
+
+/* Send a TCON to the remote server ...               */
+
+SMB_Tree_Handle
+SMB_TreeConnect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle Tree_Handle,
+    char *path,
+    char *password,
+    char *device)
+{
+    struct RFCNB_Pkt *pkt;
+    int param_len, pkt_len;
+    char *p;
+    SMB_Tree_Handle tree;
+
+    /* Figure out how much space is needed for path, password, dev ... */
+
+    if ((path == NULL) | (password == NULL) | (device == NULL)) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n");
+#endif
+
+	SMBlib_errno = SMBlibE_BadParam;
+	return (NULL);
+
+    }
+    /* The + 2 is because of the \0 and the marker ...                    */
+
+    param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2;
+
+    /* The -1 accounts for the one byte smb_buf we have because some systems */
+    /* don't like char msg_buf[]                                             */
+
+    pkt_len = SMB_tcon_len + param_len;
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+	SMBlib_errno = SMBlibE_NoSpace;
+	return (NULL);		/* Should handle the error */
+
+    }
+    /* Now allocate a tree for this to go into ... */
+
+    if (Tree_Handle == NULL) {
+
+	tree = (SMB_Tree_Handle) malloc(sizeof(struct SMB_Tree_Structure));
+
+	if (tree == NULL) {
+
+	    RFCNB_Free_Pkt(pkt);
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    return (NULL);
+
+	}
+    } else {
+
+	tree = Tree_Handle;
+
+    }
+
+    tree->next = tree->prev = NULL;
+    tree->con = Con_Handle;
+    strncpy(tree->path, path, sizeof(tree->path));
+    strncpy(tree->device_type, device, sizeof(tree->device_type));
+
+    /* Now plug in the values ... */
+
+    bzero(SMB_Hdr(pkt), SMB_tcon_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, param_len);
+
+    /* Now copy the param strings in with the right stuff */
+
+    p = (char *) (SMB_Hdr(pkt) + SMB_tcon_buf_offset);
+    *p = SMBasciiID;
+    strcpy(p + 1, path);
+    p = p + strlen(path) + 2;
+    *p = SMBasciiID;
+    strcpy(p + 1, password);
+    p = p + strlen(password) + 2;
+    *p = SMBasciiID;
+    strcpy(p + 1, device);
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error sending TCon request\n");
+#endif
+
+	if (Tree_Handle == NULL)
+	    free(tree);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_SendFailed;
+	return (NULL);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+	if (Tree_Handle == NULL)
+	    free(tree);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_RecvFailed;
+	return (NULL);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {	/* Process error */
+
+#ifdef DEBUG
+	fprintf(stderr, "SMB_TCon failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+	if (Tree_Handle == NULL)
+	    free(tree);
+	SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_Remote;
+	return (NULL);
+
+    }
+    tree->tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset);
+    tree->mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset);
+
+#ifdef DEBUG
+    fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n",
+	tree->tid, tree->mbs);
+#endif
+
+    /* Now link the Tree to the Server Structure ... */
+
+    if (Con_Handle->first_tree == NULL) {
+
+	Con_Handle->first_tree = tree;
+	Con_Handle->last_tree = tree;
+
+    } else {
+
+	Con_Handle->last_tree->next = tree;
+	tree->prev = Con_Handle->last_tree;
+	Con_Handle->last_tree = tree;
+
+    }
+
+    RFCNB_Free_Pkt(pkt);
+    return (tree);
+
+}
+
+int
+SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard)
+{
+    struct RFCNB_Pkt *pkt;
+    int pkt_len;
+
+    pkt_len = SMB_tdis_len;
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+	SMBlib_errno = SMBlibE_NoSpace;
+	return (SMBlibE_BAD);	/* Should handle the error */
+
+    }
+    /* Now plug in the values ... */
+
+    bzero(SMB_Hdr(pkt), SMB_tdis_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle->con->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle->con->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle->con->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle->tid);
+    SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0);
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error sending TDis request\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_SendFailed;
+	return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_RecvFailed;
+	return (SMBlibE_BAD);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {	/* Process error */
+
+#ifdef DEBUG
+	fprintf(stderr, "SMB_TDis failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+	SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_Remote;
+	return (SMBlibE_BAD);
+
+    }
+    Tree_Handle->tid = 0xFFFF;	/* Invalid TID */
+    Tree_Handle->mbs = 0;	/* Invalid     */
+
+#ifdef DEBUG
+
+    fprintf(stderr, "Tree disconnect successful ...\n");
+
+#endif
+
+    /* What about the tree handle ? */
+
+    if (discard == TRUE) {	/* Unlink it and free it ... */
+
+	if (Tree_Handle->next == NULL)
+	    Tree_Handle->con->first_tree = Tree_Handle->prev;
+	else
+	    Tree_Handle->next->prev = Tree_Handle->prev;
+
+	if (Tree_Handle->prev == NULL)
+	    Tree_Handle->con->last_tree = Tree_Handle->next;
+	else
+	    Tree_Handle->prev->next = Tree_Handle->next;
+
+    }
+    RFCNB_Free_Pkt(pkt);
+    return (0);
+
+}
+
+/* Pick up the last LMBlib error ... */
+
+int
+SMB_Get_Last_Error()
+{
+
+    return (SMBlib_errno);
+
+}
+
+/* Pick up the last error returned in an SMB packet          */
+/* We will need macros to extract error class and error code */
+
+int
+SMB_Get_Last_SMB_Err()
+{
+
+    return (SMBlib_SMB_Error);
+
+}
+
+/* Pick up the error message associated with an error from SMBlib  */
+
+/* Keep this table in sync with the message codes in smblib-common.h */
+
+static char *SMBlib_Error_Messages[] =
+{
+
+    "Request completed sucessfully.",
+    "Server returned a non-zero SMB Error Class and Code.",
+    "A lower layer protocol error occurred.",
+    "Function not yet implemented.",
+    "The protocol negotiated does not support the request.",
+    "No space available for operation.",
+    "One or more bad parameters passed.",
+    "None of the protocols we offered were accepted.",
+    "The attempt to send an SMB request failed. See protocol error info.",
+    "The attempt to get an SMB response failed. See protocol error info.",
+    "The logon request failed, but you were logged in as guest.",
+    "The attempt to call the remote server failed. See protocol error info.",
+    "The protocol dialect specified in a NegProt and accepted by the server is unknown.",
+  /* This next one simplifies error handling */
+    "No such error code.",
+    NULL};
+
+void
+SMB_Get_Error_Msg(int msg, char *msgbuf, int len)
+{
+
+    if (msg >= 0) {
+
+	strncpy(msgbuf,
+	    SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg],
+	    len - 1);
+	msgbuf[len - 1] = 0;	/* Make sure it is a string */
+    } else {			/* Add the lower layer message ... */
+
+	char prot_msg[1024];
+
+	msg = -msg;		/* Make it positive */
+
+	strncpy(msgbuf,
+	    SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg],
+	    len - 1);
+
+	msgbuf[len - 1] = 0;	/* make sure it is a string */
+
+	if (strlen(msgbuf) < len) {	/* If there is space, put rest in */
+
+	    strncat(msgbuf, "\n\t", len - strlen(msgbuf));
+
+	    RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1);
+
+	    strncat(msgbuf, prot_msg, len - strlen(msgbuf));
+
+	}
+    }
+
+}
Index: squid/src/auth/basic/helpers/MSNT/smblib.c
diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smblib.c:1.2.62.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/MSNT/smblib.c	Tue Sep  3 10:42:15 2002
@@ -0,0 +1,554 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Routines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int SMBlib_errno;
+int SMBlib_SMB_Error;
+#define SMBLIB_ERRNO
+#define uchar unsigned char
+#include "smblib-priv.h"
+#include "smblib.h"
+#include "rfcnb-priv.h"
+#include "rfcnb.h"
+#include "rfcnb-util.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <signal.h>
+
+SMB_State_Types SMBlib_State;
+
+extern int RFCNB_Set_Sock_NoDelay(RFCNB_Con *, BOOL);
+extern void SMB_Get_My_Name(char *, int);
+
+/* Initialize the SMBlib package     */
+
+int
+SMB_Init()
+{
+
+    SMBlib_State = SMB_State_Started;
+
+    signal(SIGPIPE, SIG_IGN);	/* Ignore these ... */
+
+/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
+#ifdef SMBLIB_INSTRUMENT
+
+    SMBlib_Instrument_Init();
+
+#endif
+
+    return 0;
+
+}
+
+int
+SMB_Term()
+{
+
+#ifdef SMBLIB_INSTRUMENT
+
+    SMBlib_Instrument_Term();	/* Clean up and print results */
+
+#endif
+
+    return 0;
+
+}
+
+/* SMB_Create: Create a connection structure and return for later use */
+/* We have other helper routines to set variables                     */
+
+SMB_Handle_Type
+SMB_Create_Con_Handle(void)
+{
+
+    SMBlib_errno = SMBlibE_NotImpl;
+    return (NULL);
+
+}
+
+int
+SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
+{
+
+
+    if (RFCNB_Set_Sock_NoDelay(Con_Handle->Trans_Connect, yn) < 0) {
+
+#ifdef DEBUG
+#endif
+
+	fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
+
+    }
+    return (0);
+
+}
+
+/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
+/* or anything else ...                                                  */
+
+SMB_Handle_Type
+SMB_Connect_Server(SMB_Handle_Type Con_Handle,
+    char *server, char *NTdomain)
+{
+    SMB_Handle_Type con;
+    char called[80], calling[80], *address;
+    int i;
+
+    /* Get a connection structure if one does not exist */
+
+    con = Con_Handle;
+
+    if (Con_Handle == NULL) {
+
+	if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    return NULL;
+	}
+    }
+    /* Init some things ... */
+
+    strcpy(con->service, "");
+    strcpy(con->username, "");
+    strcpy(con->password, "");
+    strcpy(con->sock_options, "");
+    strcpy(con->address, "");
+    strcpy(con->desthost, server);
+    strcpy(con->PDomain, NTdomain);
+    strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
+    strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
+    con->first_tree = con->last_tree = NULL;
+
+    SMB_Get_My_Name(con->myname, sizeof(con->myname));
+
+    con->port = 0;		/* No port selected */
+
+    /* Get some things we need for the SMB Header */
+
+    con->pid = getpid();
+    con->mid = con->pid;	/* This will do for now ... */
+    con->uid = 0;		/* Until we have done a logon, no uid ... */
+    con->gid = getgid();
+
+    /* Now connect to the remote end, but first upper case the name of the
+     * service we are going to call, sine some servers want it in uppercase */
+
+    for (i = 0; i < strlen(server); i++)
+	called[i] = toupper(server[i]);
+
+    called[strlen(server)] = 0;	/* Make it a string */
+
+    for (i = 0; i < strlen(con->myname); i++)
+	calling[i] = toupper(con->myname[i]);
+
+    calling[strlen(con->myname)] = 0;	/* Make it a string */
+
+    if (strcmp(con->address, "") == 0)
+	address = con->desthost;
+    else
+	address = con->address;
+
+    con->Trans_Connect = RFCNB_Call(called,
+	calling,
+	address,		/* Protocol specific */
+	con->port);
+
+    /* Did we get one? */
+
+    if (con->Trans_Connect == NULL) {
+
+	if (Con_Handle == NULL) {
+	    Con_Handle = NULL;
+	    free(con);
+	}
+	SMBlib_errno = -SMBlibE_CallFailed;
+	return NULL;
+
+    }
+    return (con);
+
+}
+
+/* SMB_Connect: Connect to the indicated server                       */
+/* If Con_Handle == NULL then create a handle and connect, otherwise  */
+/* use the handle passed                                              */
+
+char *SMB_Prots_Restrict[] =
+{"PC NETWORK PROGRAM 1.0",
+    NULL};
+
+
+SMB_Handle_Type
+SMB_Connect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle * tree,
+    char *service,
+    char *username,
+    char *password)
+{
+    SMB_Handle_Type con;
+    char *host, *address;
+    char temp[80], called[80], calling[80];
+    int i;
+
+    /* Get a connection structure if one does not exist */
+
+    con = Con_Handle;
+
+    if (Con_Handle == NULL) {
+
+	if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    return NULL;
+	}
+    }
+    /* Init some things ... */
+
+    strcpy(con->service, service);
+    strcpy(con->username, username);
+    strcpy(con->password, password);
+    strcpy(con->sock_options, "");
+    strcpy(con->address, "");
+    strcpy(con->PDomain, SMBLIB_DEFAULT_DOMAIN);
+    strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
+    strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
+    con->first_tree = con->last_tree = NULL;
+
+    SMB_Get_My_Name(con->myname, sizeof(con->myname));
+
+    con->port = 0;		/* No port selected */
+
+    /* Get some things we need for the SMB Header */
+
+    con->pid = getpid();
+    con->mid = con->pid;	/* This will do for now ... */
+    con->uid = 0;		/* Until we have done a logon, no uid */
+    con->gid = getgid();
+
+    /* Now figure out the host portion of the service */
+
+    strcpy(temp, service);
+    /* AI - Added (char *) to stop compiler warnings */
+    host = (char *) strtok(temp, "/\\");	/* Separate host name portion */
+    strcpy(con->desthost, host);
+
+    /* Now connect to the remote end, but first upper case the name of the
+     * service we are going to call, sine some servers want it in uppercase */
+
+    for (i = 0; i < strlen(host); i++)
+	called[i] = toupper(host[i]);
+
+    called[strlen(host)] = 0;	/* Make it a string */
+
+    for (i = 0; i < strlen(con->myname); i++)
+	calling[i] = toupper(con->myname[i]);
+
+    calling[strlen(con->myname)] = 0;	/* Make it a string */
+
+    if (strcmp(con->address, "") == 0)
+	address = con->desthost;
+    else
+	address = con->address;
+
+    con->Trans_Connect = RFCNB_Call(called,
+	calling,
+	address,		/* Protocol specific */
+	con->port);
+
+    /* Did we get one? */
+
+    if (con->Trans_Connect == NULL) {
+
+	if (Con_Handle == NULL) {
+	    free(con);
+	    Con_Handle = NULL;
+	}
+	SMBlib_errno = -SMBlibE_CallFailed;
+	return NULL;
+
+    }
+    /* Now, negotiate the protocol */
+
+    if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
+
+	/* Hmmm what should we do here ... We have a connection, but could not
+	 * negotiate ...                                                      */
+
+	return NULL;
+
+    }
+    /* Now connect to the service ... */
+
+    if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
+
+	return NULL;
+
+    }
+    return (con);
+
+}
+
+/* Logon to the server. That is, do a session setup if we can. We do not do */
+/* Unicode yet!                                                             */
+
+int
+SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
+    char *PassWord)
+{
+    struct RFCNB_Pkt *pkt;
+    int param_len, pkt_len, pass_len;
+    char *p, pword[128];
+
+    /* First we need a packet etc ... but we need to know what protocol has  */
+    /* been negotiated to figure out if we can do it and what SMB format to  */
+    /* use ...                                                               */
+
+    if (Con_Handle->protocol < SMB_P_LanMan1) {
+
+	SMBlib_errno = SMBlibE_ProtLow;
+	return (SMBlibE_BAD);
+
+    }
+    strcpy(pword, PassWord);
+#ifdef PAM_SMB_ENC_PASS
+    if (Con_Handle->encrypt_passwords) {
+	pass_len = 24;
+	SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
+    } else
+#endif
+	pass_len = strlen(pword);
+
+
+    /* Now build the correct structure */
+
+    if (Con_Handle->protocol < SMB_P_NT1) {
+
+	param_len = strlen(UserName) + 1 + pass_len + 1 +
+	    strlen(Con_Handle->PDomain) + 1 +
+	    strlen(Con_Handle->OSName) + 1;
+
+	pkt_len = SMB_ssetpLM_len + param_len;
+
+	pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+	if (pkt == NULL) {
+
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    return (SMBlibE_BAD);	/* Should handle the error */
+
+	}
+	bzero(SMB_Hdr(pkt), SMB_ssetpLM_len);
+	SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+	*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+	*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
+	*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;	/* No extra command */
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle->pid);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
+
+	/* Now copy the param strings in with the right stuff */
+
+	p = (char *) (SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
+
+	/* Copy  in password, then the rest. Password has a null at end */
+
+	memcpy(p, pword, pass_len);
+
+	p = p + pass_len + 1;
+
+	strcpy(p, UserName);
+	p = p + strlen(UserName);
+	*p = 0;
+
+	p = p + 1;
+
+	strcpy(p, Con_Handle->PDomain);
+	p = p + strlen(Con_Handle->PDomain);
+	*p = 0;
+	p = p + 1;
+
+	strcpy(p, Con_Handle->OSName);
+	p = p + strlen(Con_Handle->OSName);
+	*p = 0;
+
+    } else {
+
+	/* We don't admit to UNICODE support ... */
+
+	param_len = strlen(UserName) + 1 + pass_len +
+	    strlen(Con_Handle->PDomain) + 1 +
+	    strlen(Con_Handle->OSName) + 1 +
+	    strlen(Con_Handle->LMType) + 1;
+
+	pkt_len = SMB_ssetpNTLM_len + param_len;
+
+	pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+	if (pkt == NULL) {
+
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    return (-1);	/* Should handle the error */
+
+	}
+	bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len);
+	SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+	*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+	*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
+	*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;	/* No extra command */
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
+
+	/* Now copy the param strings in with the right stuff */
+
+	p = (char *) (SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
+
+	/* Copy  in password, then the rest. Password has no null at end */
+
+	memcpy(p, pword, pass_len);
+
+	p = p + pass_len;
+
+	strcpy(p, UserName);
+	p = p + strlen(UserName);
+	*p = 0;
+
+	p = p + 1;
+
+	strcpy(p, Con_Handle->PDomain);
+	p = p + strlen(Con_Handle->PDomain);
+	*p = 0;
+	p = p + 1;
+
+	strcpy(p, Con_Handle->OSName);
+	p = p + strlen(Con_Handle->OSName);
+	*p = 0;
+	p = p + 1;
+
+	strcpy(p, Con_Handle->LMType);
+	p = p + strlen(Con_Handle->LMType);
+	*p = 0;
+
+    }
+
+    /* Now send it and get a response */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error sending SessSetupX request\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_SendFailed;
+	return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error receiving response to SessSetupAndX\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_RecvFailed;
+	return (SMBlibE_BAD);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {	/* Process error */
+
+#ifdef DEBUG
+	fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+	SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_Remote;
+	return (SMBlibE_BAD);
+
+    }
+#ifdef DEBUG
+    fprintf(stderr, "SessSetupAndX response. Action = %i\n",
+	SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
+#endif
+
+    /* Now pick up the UID for future reference ... */
+
+    Con_Handle->uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
+    RFCNB_Free_Pkt(pkt);
+
+    return (0);
+
+}
+
+
+/* Disconnect from the server, and disconnect all tree connects */
+
+int
+SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
+{
+
+    /* We just disconnect the connection for now ... */
+
+    RFCNB_Hangup(Con_Handle->Trans_Connect);
+
+    if (!KeepHandle)
+	free(Con_Handle);
+
+    return (0);
+
+}
Index: squid/src/auth/basic/helpers/PAM/Makefile.am
diff -u /dev/null squid/src/auth/basic/helpers/PAM/Makefile.am:1.2.28.2
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/PAM/Makefile.am	Tue Sep  3 10:42:17 2002
@@ -0,0 +1,15 @@
+#
+#  Makefile for the Squid PAM authentication helper
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+INCLUDES	= -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
+		  -I$(top_srcdir)/src/
+
+man_MANS		= pam_auth.8
+EXTRA_DIST		= pam_auth.8
+libexec_PROGRAMS	= pam_auth
+LDADD			= -lpam $(XTRA_LIBS)
Index: squid/src/auth/basic/helpers/PAM/pam_auth.8
diff -u /dev/null squid/src/auth/basic/helpers/PAM/pam_auth.8:1.1.6.2
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/PAM/pam_auth.8	Tue Sep  3 10:42:17 2002
@@ -0,0 +1,94 @@
+.TH pam_auth 8 "15 May 2002" "Squid PAM Auth"
+.
+.SH NAME
+pam_auth - Squid PAM authentication helper
+.
+.SH SYNOPSIS
+squid_pam_auth [-n "service name"] [-t TTL] [-o] [-1]
+.
+.SH DESCRIPTION
+This helper allows Squid to connect to a mostly any available PAM
+database to validate the user name and password of Basic HTTP
+authentication.
+.
+.TP
+.BI "-s " "service-name"
+Specifies the PAM service name Squid uses, defaults to "squid"
+.
+.TP
+.BI "-t " TTL
+Unless the -1 option is used, this specified for how long
+the connection to the PAM database should be kept open and
+reused for new logins. Defaults to 60 seconds.
+.
+.TP
+.BI "-o"
+Do not perform the PAM account management group (account
+expiration etc)
+
+.TP
+.BI "-1"
+Specifies "One shot" mode, where a new PAM connection will
+be opened for each new user. This is how PAM is normally
+used and may be required by some backend databases.
+The default is to reuse the PAM connection to maximize
+performance. (see -t above)
+.
+.SH CONFIGURATION
+.
+The program needs a PAM service to be configured in 
+.B /etc/pam.conf
+or
+.B /etc/pam.d/<servicename>
+.P
+The default service name is "squid", and the program makes use
+of the
+.BR "" ' auth "' and '" account '
+management groups to verify the password and the accounts validity.
+.P
+For details on how to configure PAM services, see the PAM
+documentation for your system. This manual does not cover PAM
+configuration details.
+.
+.SH NOTES
+.
+When used for authenticating to local UNIX shadow password databases
+the program must be running as root or else it won't have sufficient
+permissions to access the user password database. Such use of this
+program is not recommended, but if you absolutely need to then make
+the program setuid root
+.RS
+.P
+.B chown root pam_auth
+.br
+.B chmod u+s pam_auth
+.RE
+.P
+Please note that in such configurations it is also strongly recommended
+that the program is moved into a directory where normal users cannot
+access it, as this mode of operation will allow any local user to
+brute-force other users passwords. Also note the program has not been
+fully audited and the author cannot be held responsible for any security
+issues due to such installations.
+.
+.SH AUTHOR
+Squid pam_auth and this manual is written by
+.I Henrik Nordstrom <hno@squid-cache.org>
+.
+.SH COPYRIGHT
+Squid pam_auth and this manual is Copyright 1999,2002
+Henrik Nordstrom <hno@squid-cache.org>
+.
+.SH QUESTIONS
+Questions on the usage of this program can be sent to the
+.I Squid Users <squid-users@squid-cache.org>
+mailing list.
+.
+.SH REPORTING BUGS
+Report bugs or bug-fixes to
+.I Squid Bugs <squid-bugs@squid-cache.org>
+or ideas for new improvements to 
+.I Squid Developers <squid-dev@squid-cache.org>
+.
+.SH "SEE ALSO"
+.BR pam (8), " PAM Systems Administrator Guide"
Index: squid/src/auth/basic/helpers/SASL/.cvsignore
diff -u /dev/null squid/src/auth/basic/helpers/SASL/.cvsignore:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/SASL/.cvsignore	Tue Sep  3 10:42:17 2002
@@ -0,0 +1,2 @@
+.cvsignore
+Makefile.in
Index: squid/src/auth/basic/helpers/SASL/Makefile.am
diff -u /dev/null squid/src/auth/basic/helpers/SASL/Makefile.am:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/SASL/Makefile.am	Tue Sep  3 10:42:18 2002
@@ -0,0 +1,14 @@
+#
+#  Makefile for the Squid SASL authentication helper
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+INCLUDES	= -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
+		  -I$(top_srcdir)/src/
+
+libexec_PROGRAMS	= sasl_auth
+LDADD			= -lsasl $(XTRA_LIBS)
+EXTRA_DIST		= squid_sasl_auth squid_sasl_auth.conf
Index: squid/src/auth/basic/helpers/SASL/README
diff -u /dev/null squid/src/auth/basic/helpers/SASL/README:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/SASL/README	Tue Sep  3 10:42:18 2002
@@ -0,0 +1,49 @@
+This program authenticates users using SASL (specifically the
+cyrus-sasl authentication method).
+
+SASL is configurable (somewhat like PAM). Each service authenticating
+against SASL identifies itself with an application name. Each 
+"application" can be configured independently by the SASL administrator.
+
+For this authenticator, the SASL application name is, by default,
+
+	squid_sasl_auth
+
+To configure the authentication method used the file "squid_sasl_auth.conf" 
+can be placed in the appropriate location, usually "/usr/lib/sasl".
+
+The authentication database is defined by the "pwcheck_method" parameter.
+Only the "PLAIN" authentication mechanism is used.
+
+Examples:
+
+pwcheck_method:sasldb
+	use sasldb - the default if no conf file is installed.
+pwcheck_method:pam
+	use PAM
+pwcheck_method:passwd
+     use traditional /etc/passwd
+pwcheck_method:shadow
+     use slightly less traditional /etc/shadow
+
+Others methods may be supported by your cyrus-sasl implementation - 
+consult your cyrus-sasl documentation for information.
+
+Typically the authentication database (/etc/sasldb, /etc/shadow, pam)
+can not be accessed by a "normal" user. You should use setuid/setgid
+and an appropriate user/group on the executable to allow the
+authenticator to access the appropriate password database. If the
+access to the database is not permitted then the authenticator
+will typically fail with "-1, generic error".
+
+	chown root.mail sasl_auth
+	chmod ug+s sasl_auth
+
+If the application name ("squid_sasl_auth") will also be used for the
+pam service name if pwcheck_method:pam is chosen. And example pam
+configuration file  "squid_sasl_auth" is also included.
+
+
+Ian Castle
+ian.castle@coldcomfortfarm.net
+March 2002
Index: squid/src/auth/basic/helpers/SASL/sasl_auth.c
diff -u /dev/null squid/src/auth/basic/helpers/SASL/sasl_auth.c:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/SASL/sasl_auth.c	Tue Sep  3 10:42:18 2002
@@ -0,0 +1,103 @@
+/*
+ * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ *
+ * SASL authenticator module for Squid.
+ * Copyright (C) 2002 Ian Castle <ian.castle@coldcomfortfarm.net>
+ *
+ *  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.
+ *
+ * Install instructions:
+ *
+ * This program authenticates users against using cyrus-sasl
+ *
+ * Compile this program with: gcc -Wall -o sasl_auth sasl_auth.c -lsasl
+ *
+ */
+#include <sasl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define APP_NAME_SASL	"squid_sasl_auth"
+
+int
+main()
+{
+	char line[8192];
+	char *username, *password;
+	const char *errstr;
+
+	int rc;
+        sasl_conn_t *conn = NULL;
+
+	/* make standard output line buffered */
+	setvbuf(stdout, NULL, _IOLBF, 0);
+
+	rc = sasl_server_init( NULL, APP_NAME_SASL );
+
+	if ( rc != SASL_OK ) {
+		fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
+		fprintf( stdout, "ERR\n" );
+		return 1;
+	}
+
+	rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, 0, &conn );
+
+	if ( rc != SASL_OK ) {
+		fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
+		fprintf( stdout, "ERR\n" );
+		return 1;
+	}
+
+	while ( fgets( line, sizeof( line ), stdin )) {
+		username = &line[0];
+		password = strchr( line, '\n' );
+		if ( !password) {
+			fprintf( stderr, "authenticator: Unexpected input '%s'\n", line );
+			fprintf( stdout, "ERR\n" );
+			continue;
+		}
+		*password = '\0';
+		password = strchr ( line, ' ' );
+		if ( !password) {
+			fprintf( stderr, "authenticator: Unexpected input '%s'\n", line );
+			fprintf( stdout, "ERR\n" );
+			continue;
+		}
+		*password++ = '\0';
+
+		rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password), &errstr);
+
+		if ( rc != SASL_OK ) {
+			if ( errstr ) {
+				fprintf( stderr, "errstr %s\n", errstr );
+			}
+			if ( rc != SASL_BADAUTH ) {
+				fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
+			}
+			fprintf( stdout, "ERR\n" );
+		}
+		else {
+			fprintf( stdout, "OK\n" );
+		}
+
+	}
+
+        sasl_dispose( &conn );
+        sasl_done();
+
+	return 0;
+}
Index: squid/src/auth/basic/helpers/SASL/squid_sasl_auth
diff -u /dev/null squid/src/auth/basic/helpers/SASL/squid_sasl_auth:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/SASL/squid_sasl_auth	Tue Sep  3 10:42:18 2002
@@ -0,0 +1,7 @@
+#%PAM-1.0
+#
+# Example PAM service configuration file if using the sasl pam password
+# backend (pwcheck_method:pam)
+#
+auth       required     /lib/security/pam_pwdb.so shadow nullok
+account    required     /lib/security/pam_pwdb.so
Index: squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf
diff -u /dev/null squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf	Tue Sep  3 10:42:18 2002
@@ -0,0 +1 @@
+pwcheck_method:sasldb
Index: squid/src/auth/basic/helpers/winbind/Makefile.am
diff -u /dev/null squid/src/auth/basic/helpers/winbind/Makefile.am:1.5.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/winbind/Makefile.am	Tue Sep  3 10:42:22 2002
@@ -0,0 +1,11 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+
+libexec_PROGRAMS = wb_auth
+wb_auth_SOURCES = wb_basic_auth.c wb_common.c
+INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
+    -I$(top_srcdir)/src
+LDADD = -L$(top_builddir)/lib -lmiscutil -lntlmauth
Index: squid/src/auth/basic/helpers/winbind/samba_nss.h
diff -u /dev/null squid/src/auth/basic/helpers/winbind/samba_nss.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/winbind/samba_nss.h	Tue Sep  3 10:42:22 2002
@@ -0,0 +1,105 @@
+#ifndef _NSSWITCH_NSS_H
+#define _NSSWITCH_NSS_H
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.0
+
+   a common place to work out how to define NSS_STATUS on various
+   platforms
+
+   Copyright (C) Tim Potter 2000
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library 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
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#ifdef HAVE_NSS_COMMON_H
+
+/* Sun Solaris */
+
+#include <nss_common.h>
+#include <nss_dbdefs.h>
+#include <nsswitch.h>
+
+typedef nss_status_t NSS_STATUS;
+
+#define NSS_STATUS_SUCCESS     NSS_SUCCESS
+#define NSS_STATUS_NOTFOUND    NSS_NOTFOUND
+#define NSS_STATUS_UNAVAIL     NSS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN    NSS_TRYAGAIN
+
+#elif HAVE_NSS_H
+
+/* GNU */
+
+#include <nss.h>
+
+typedef enum nss_status NSS_STATUS;
+
+#elif HAVE_NS_API_H
+
+/* SGI IRIX */
+
+/* following required to prevent warnings of double definition
+ * of datum from ns_api.h
+*/
+#ifdef DATUM
+#define _DATUM_DEFINED
+#endif
+
+#include <ns_api.h>
+
+typedef enum
+{
+  NSS_STATUS_SUCCESS=NS_SUCCESS,
+  NSS_STATUS_NOTFOUND=NS_NOTFOUND,
+  NSS_STATUS_UNAVAIL=NS_UNAVAIL,
+  NSS_STATUS_TRYAGAIN=NS_TRYAGAIN
+} NSS_STATUS;
+
+#define NSD_MEM_STATIC 0
+#define NSD_MEM_VOLATILE 1
+#define NSD_MEM_DYNAMIC 2
+
+#elif defined(HPUX)
+/* HP-UX 11 */
+
+#include "nsswitch/hp_nss_common.h"
+#include "nsswitch/hp_nss_dbdefs.h"
+#include <nsswitch.h>
+
+#ifndef _HAVE_TYPEDEF_NSS_STATUS
+#define _HAVE_TYPEDEF_NSS_STATUS
+typedef nss_status_t NSS_STATUS;
+
+#define NSS_STATUS_SUCCESS     NSS_SUCCESS
+#define NSS_STATUS_NOTFOUND    NSS_NOTFOUND
+#define NSS_STATUS_UNAVAIL     NSS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN    NSS_TRYAGAIN
+#endif /* HPUX */
+
+#else /* Nothing's defined. Neither gnu nor sun nor hp */
+
+typedef enum
+{
+  NSS_STATUS_SUCCESS=0,
+  NSS_STATUS_NOTFOUND=1,
+  NSS_STATUS_UNAVAIL=2,
+  NSS_STATUS_TRYAGAIN=3
+} NSS_STATUS;
+
+#endif
+
+#endif /* _NSSWITCH_NSS_H */
Index: squid/src/auth/basic/helpers/winbind/wb_basic_auth.c
diff -u /dev/null squid/src/auth/basic/helpers/winbind/wb_basic_auth.c:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/winbind/wb_basic_auth.c	Tue Sep  3 10:42:22 2002
@@ -0,0 +1,121 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ *
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * 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 "wbntlm.h"
+#include "util.h"
+/* stdio.h is included in wbntlm.h */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/time.h>           /* for gettimeofday */
+#include <errno.h>              /* BUG: is this portable? */
+
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
+
+char debug_enabled=1;
+char *myname;
+pid_t mypid;
+
+NSS_STATUS winbindd_request(int req_type, 
+														struct winbindd_request *request,
+														struct winbindd_response *response);
+		 
+
+void do_authenticate(char *user, char *pass) {
+	struct winbindd_request request;
+	struct winbindd_response response;
+	NSS_STATUS winbindd_result;
+	
+	memset(&request,0,sizeof(struct winbindd_request));
+	memset(&response,0,sizeof(struct winbindd_response));
+
+	
+	strncpy(request.data.auth.user,user,sizeof(fstring)-1);
+	strncpy(request.data.auth.pass,pass,sizeof(fstring)-1);
+
+	winbindd_result = winbindd_request(WINBINDD_PAM_AUTH,
+																		 &request, &response);
+	debug("winbindd result: %d\n",winbindd_result);
+
+	if (winbindd_result==WINBINDD_OK) {
+		SEND("OK");
+	} else {
+		SEND("ERR");
+	}
+
+	return;												/* useless */
+}
+
+void manage_request(void) {
+  char buf[BUFFER_SIZE+1];
+	int length;
+	char *c, *user, *pass;
+  
+  if (fgets(buf, BUFFER_SIZE, stdin) == NULL) {
+    warn("fgets() failed! dying..... errno=%d (%s)\n", errno,
+          strerror(errno));
+    exit(1);    /* BIIG buffer */
+  }
+	
+  c=memchr(buf,'\n',BUFFER_SIZE);
+  if (c) {
+    *c='\0';
+		length=c-buf;
+	}
+  else {
+    warn("No newline in '%s'. Dying.\n",buf);
+		exit(1);
+	}
+  
+  debug("Got '%s' from squid (length: %d).\n",buf,length);
+	user=buf;
+
+	pass=memchr(buf,' ',length);
+	if (!pass) {
+		warn("Password not found. Denying access\n");
+		SEND("ERR");
+		return;
+	}
+	*pass='\0';
+	pass++;
+
+	do_authenticate(user,pass);
+
+}
+
+int main (int argc, char ** argv) {
+	if (argc > 0) {								/* should always be true */
+		myname=strrchr(argv[0],'/');
+		if (myname==NULL)
+			myname=argv[0];
+	} else {
+		myname="(unknown)";
+	}
+	mypid=getpid();
+  debug("ntlm winbindd auth helper build " __DATE__ ", " __TIME__
+        " starting up...\n");
+  /* initialize FDescs */
+  setbuf(stdout, NULL);
+  setbuf(stderr, NULL);
+
+  while(1) {
+    manage_request();
+  }
+  return 0;
+}
Index: squid/src/auth/basic/helpers/winbind/wb_common.c
diff -u /dev/null squid/src/auth/basic/helpers/winbind/wb_common.c:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/winbind/wb_common.c	Tue Sep  3 10:42:23 2002
@@ -0,0 +1,398 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.0
+
+   winbind client common code
+
+   Copyright (C) Tim Potter 2000
+   Copyright (C) Andrew Tridgell 2000
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library 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
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
+#include "config.h"
+
+
+/* Global variables.  These are effectively the client state information */
+
+int winbindd_fd = -1;           /* fd for winbindd socket */
+static char *excluded_domain;
+
+/* Free a response structure */
+
+void free_response(struct winbindd_response *response)
+{
+	/* Free any allocated extra_data */
+
+	if (response)
+		SAFE_FREE(response->extra_data);
+}
+
+/*
+  smbd needs to be able to exclude lookups for its own domain
+*/
+void winbind_exclude_domain(const char *domain)
+{
+	SAFE_FREE(excluded_domain);
+	excluded_domain = strdup(domain);
+}
+
+
+/* Initialise a request structure */
+
+void init_request(struct winbindd_request *request, int request_type)
+{
+        static char *domain_env;
+        static BOOL initialised;
+
+	request->length = sizeof(struct winbindd_request);
+
+	request->cmd = (enum winbindd_cmd)request_type;
+	request->pid = getpid();
+	request->domain[0] = '\0';
+
+	if (!initialised) {
+		initialised = True;
+		domain_env = getenv(WINBINDD_DOMAIN_ENV);
+	}
+
+	if (domain_env) {
+		strncpy(request->domain, domain_env,
+			sizeof(request->domain) - 1);
+		request->domain[sizeof(request->domain) - 1] = '\0';
+	}
+}
+
+/* Initialise a response structure */
+
+void init_response(struct winbindd_response *response)
+{
+	/* Initialise return value */
+
+	response->result = WINBINDD_ERROR;
+}
+
+/* Close established socket */
+
+void close_sock(void)
+{
+	if (winbindd_fd != -1) {
+		close(winbindd_fd);
+		winbindd_fd = -1;
+	}
+}
+
+/* Connect to winbindd socket */
+
+int winbind_open_pipe_sock(void)
+{
+	struct sockaddr_un sunaddr;
+	static pid_t our_pid;
+	struct stat st;
+	pstring path;
+	
+	if (our_pid != getpid()) {
+		close_sock();
+		our_pid = getpid();
+	}
+	
+	if (winbindd_fd != -1) {
+		return winbindd_fd;
+	}
+	
+	/* Check permissions on unix socket directory */
+	
+	if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) {
+		return -1;
+	}
+	
+	if (!S_ISDIR(st.st_mode) || 
+	    (st.st_uid != 0 && st.st_uid != geteuid())) {
+		return -1;
+	}
+	
+	/* Connect to socket */
+	
+	strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1);
+	path[sizeof(path) - 1] = '\0';
+	
+	strncat(path, "/", sizeof(path) - 1);
+	path[sizeof(path) - 1] = '\0';
+	
+	strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1);
+	path[sizeof(path) - 1] = '\0';
+	
+	ZERO_STRUCT(sunaddr);
+	sunaddr.sun_family = AF_UNIX;
+	strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
+	
+	/* If socket file doesn't exist, don't bother trying to connect
+	   with retry.  This is an attempt to make the system usable when
+	   the winbindd daemon is not running. */
+
+	if (lstat(path, &st) == -1) {
+		return -1;
+	}
+	
+	/* Check permissions on unix socket file */
+	
+	if (!S_ISSOCK(st.st_mode) || 
+	    (st.st_uid != 0 && st.st_uid != geteuid())) {
+		return -1;
+	}
+	
+	/* Connect to socket */
+	
+	if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+		return -1;
+	}
+	
+	if (connect(winbindd_fd, (struct sockaddr *)&sunaddr, 
+		    sizeof(sunaddr)) == -1) {
+		close_sock();
+		return -1;
+	}
+        
+	return winbindd_fd;
+}
+
+/* Write data to winbindd socket with timeout */
+
+int write_sock(void *buffer, int count)
+{
+	int result, nwritten;
+	
+	/* Open connection to winbind daemon */
+	
+ restart:
+	
+	if (winbind_open_pipe_sock() == -1) {
+		return -1;
+	}
+	
+	/* Write data to socket */
+	
+	nwritten = 0;
+	
+	while(nwritten < count) {
+		struct timeval tv;
+		fd_set r_fds;
+		
+		/* Catch pipe close on other end by checking if a read()
+		   call would not block by calling select(). */
+
+		FD_ZERO(&r_fds);
+		FD_SET(winbindd_fd, &r_fds);
+		ZERO_STRUCT(tv);
+		
+		if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) {
+			close_sock();
+			return -1;                   /* Select error */
+		}
+		
+		/* Write should be OK if fd not available for reading */
+		
+		if (!FD_ISSET(winbindd_fd, &r_fds)) {
+			
+			/* Do the write */
+			
+			result = write(winbindd_fd,
+				       (char *)buffer + nwritten, 
+				       count - nwritten);
+			
+			if ((result == -1) || (result == 0)) {
+				
+				/* Write failed */
+				
+				close_sock();
+				return -1;
+			}
+			
+			nwritten += result;
+			
+		} else {
+			
+			/* Pipe has closed on remote end */
+			
+			close_sock();
+			goto restart;
+		}
+	}
+	
+	return nwritten;
+}
+
+/* Read data from winbindd socket with timeout */
+
+static int read_sock(void *buffer, int count)
+{
+	int result = 0, nread = 0;
+
+	/* Read data from socket */
+	
+	while(nread < count) {
+		
+		result = read(winbindd_fd, (char *)buffer + nread, 
+			      count - nread);
+		
+		if ((result == -1) || (result == 0)) {
+			
+			/* Read failed.  I think the only useful thing we
+			   can do here is just return -1 and fail since the
+			   transaction has failed half way through. */
+			
+			close_sock();
+			return -1;
+		}
+		
+		nread += result;
+	}
+	
+	return result;
+}
+
+/* Read reply */
+
+int read_reply(struct winbindd_response *response)
+{
+	int result1, result2 = 0;
+
+	if (!response) {
+		return -1;
+	}
+	
+	/* Read fixed length response */
+	
+	if ((result1 = read_sock(response, sizeof(struct winbindd_response)))
+	    == -1) {
+		
+		return -1;
+	}
+	
+	/* We actually send the pointer value of the extra_data field from
+	   the server.  This has no meaning in the client's address space
+	   so we clear it out. */
+
+	response->extra_data = NULL;
+
+	/* Read variable length response */
+	
+	if (response->length > sizeof(struct winbindd_response)) {
+		int extra_data_len = response->length - 
+			sizeof(struct winbindd_response);
+		
+		/* Mallocate memory for extra data */
+		
+		if (!(response->extra_data = malloc(extra_data_len))) {
+			return -1;
+		}
+		
+		if ((result2 = read_sock(response->extra_data, extra_data_len))
+		    == -1) {
+			free_response(response);
+			return -1;
+		}
+	}
+	
+	/* Return total amount of data read */
+	
+	return result1 + result2;
+}
+
+/* 
+ * send simple types of requests 
+ */
+
+NSS_STATUS winbindd_send_request(int req_type, struct winbindd_request *request)
+{
+	struct winbindd_request lrequest;
+
+	/* Check for our tricky environment variable */
+
+	if (getenv(WINBINDD_DONT_ENV)) {
+		return NSS_STATUS_NOTFOUND;
+	}
+
+	/* smbd may have excluded this domain */
+	if (excluded_domain && 
+	    strcasecmp(excluded_domain, request->domain) == 0) {
+		return NSS_STATUS_NOTFOUND;
+	}
+
+	if (!request) {
+		ZERO_STRUCT(lrequest);
+		request = &lrequest;
+	}
+	
+	/* Fill in request and send down pipe */
+
+	init_request(request, req_type);
+	
+	if (write_sock(request, sizeof(*request)) == -1) {
+		return NSS_STATUS_UNAVAIL;
+	}
+	
+	return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Get results from winbindd request
+ */
+
+NSS_STATUS winbindd_get_response(struct winbindd_response *response)
+{
+	struct winbindd_response lresponse;
+
+	if (!response) {
+		ZERO_STRUCT(lresponse);
+		response = &lresponse;
+	}
+
+	init_response(response);
+
+	/* Wait for reply */
+	if (read_reply(response) == -1) {
+		return NSS_STATUS_UNAVAIL;
+	}
+
+	/* Throw away extra data if client didn't request it */
+	if (response == &lresponse) {
+		free_response(response);
+	}
+
+	/* Copy reply data from socket */
+	if (response->result != WINBINDD_OK) {
+		return NSS_STATUS_NOTFOUND;
+	}
+	
+	return NSS_STATUS_SUCCESS;
+}
+
+/* Handle simple types of requests */
+
+NSS_STATUS winbindd_request(int req_type, 
+				 struct winbindd_request *request,
+				 struct winbindd_response *response)
+{
+	NSS_STATUS status;
+
+	status = winbindd_send_request(req_type, request);
+	if (status != NSS_STATUS_SUCCESS) 
+		return(status);
+	return winbindd_get_response(response);
+}
Index: squid/src/auth/basic/helpers/winbind/wbntlm.h
diff -u /dev/null squid/src/auth/basic/helpers/winbind/wbntlm.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/winbind/wbntlm.h	Tue Sep  3 10:42:23 2002
@@ -0,0 +1,90 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>,
+ *
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * 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 _WBNTLM_H_
+#define _WBNTLM_H_
+
+#include "config.h"
+#include "ntlmauth.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+/*************** CONFIGURATION ***************/
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+/* the attempted entropy source. If it doesn't exist, random() is uesed */
+#define ENTROPY_SOURCE "/dev/urandom"
+
+#define DOMAIN "GCSINT"         /* TODO: fix ntlm_make_challenge */
+
+/************* END CONFIGURATION *************/
+
+/* Debugging stuff */
+extern char *myname;
+static char *__foo;
+extern pid_t mypid;
+extern char debug_enabled;
+
+#ifdef DEBUG
+#define __DO_DEBUG 1
+#else
+#define __DO_DEBUG 0
+#endif
+
+#ifdef __GNUC__     /* this is really a gcc-ism */
+#define warn(X...)  fprintf(stderr,"%s[%d](%s:%d): ", myname, mypid, \
+                    ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\
+                    __LINE__);\
+                    fprintf(stderr,X)
+#define debug(X...) if(__DO_DEBUG && debug_enabled) { warn(X); }
+#else /* __GNUC__ */
+static void
+debug(char *format,...)
+{
+}
+static void
+warn(char *format,...)
+{
+}
+#endif /* __GNUC__ */
+
+
+
+/* A couple of harmless helper macros */
+#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
+#ifdef __GNUC__
+#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); \
+                      printf(X "\n",Y)
+#else
+/* no gcc, no debugging. varargs macros are a gcc extension */
+#define SEND2 printf
+#endif
+
+typedef enum {
+  YES,
+  NO,
+  DONTKNOW
+} tristate;
+
+#define CHALLENGE_LEN 8
+#define BUFFER_SIZE 2010
+
+#endif /* _WBNTLM_H_ */
Index: squid/src/auth/basic/helpers/winbind/winbind_nss_config.h
diff -u /dev/null squid/src/auth/basic/helpers/winbind/winbind_nss_config.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/winbind/winbind_nss_config.h	Tue Sep  3 10:42:23 2002
@@ -0,0 +1,148 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.0
+
+   Winbind daemon for ntdom nss module
+
+   Copyright (C) Tim Potter 2000
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library 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
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#ifndef _WINBIND_NSS_CONFIG_H
+#define _WINBIND_NSS_CONFIG_H
+
+/* Include header files from data in config.h file */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_UNIXSOCKET
+#include <sys/un.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <pwd.h>
+#include "samba_nss.h"
+
+/* Declarations for functions in winbind_nss.c
+   needed in winbind_nss_solaris.c (solaris wrapper to nss) */
+
+NSS_STATUS _nss_winbind_setpwent(void);
+NSS_STATUS _nss_winbind_endpwent(void);
+NSS_STATUS _nss_winbind_getpwent_r(struct passwd* result, char* buffer,
+				   size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwuid_r(uid_t, struct passwd*, char* buffer,
+				   size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwnam_r(const char* name, struct passwd* result,
+				   char* buffer, size_t buflen, int* errnop);
+
+NSS_STATUS _nss_winbind_setgrent(void);
+NSS_STATUS _nss_winbind_endgrent(void);
+NSS_STATUS _nss_winbind_getgrent_r(struct group* result, char* buffer,
+				   size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getgrnam_r(const char *name,
+				   struct group *result, char *buffer,
+				   size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid,
+				   struct group *result, char *buffer,
+				   size_t buflen, int *errnop);
+
+/* I'm trying really hard not to include anything from smb.h with the
+   result of some silly looking redeclaration of structures. */
+
+#ifndef _PSTRING
+#define _PSTRING
+#define PSTRING_LEN 1024
+#define FSTRING_LEN 256
+typedef char pstring[PSTRING_LEN];
+typedef char fstring[FSTRING_LEN];
+#endif
+
+#ifndef _BOOL
+#define _BOOL			/* So we don't typedef BOOL again in vfs.h */
+#define False (0)
+#define True (1)
+#define Auto (2)
+typedef int BOOL;
+#endif
+
+#if !defined(uint32)
+#if (SIZEOF_INT == 4)
+#define uint32 unsigned int
+#elif (SIZEOF_LONG == 4)
+#define uint32 unsigned long
+#elif (SIZEOF_SHORT == 4)
+#define uint32 unsigned short
+#endif
+#endif
+
+#if !defined(uint16)
+#if (SIZEOF_SHORT == 4)
+#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+#else /* SIZEOF_SHORT != 4 */
+#define uint16 unsigned short
+#endif /* SIZEOF_SHORT != 4 */
+#endif
+
+#ifndef uint8
+#define uint8 unsigned char
+#endif
+
+/* zero a structure */
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+
+/* zero a structure given a pointer to the structure */
+#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); }
+    
+/* Some systems (SCO) treat UNIX domain sockets as FIFOs */
+
+#ifndef S_IFSOCK
+#define S_IFSOCK S_IFIFO
+#endif
+
+#ifndef S_ISSOCK
+#define S_ISSOCK(mode)  ((mode & S_IFSOCK) == S_IFSOCK)
+#endif
+
+#endif
Index: squid/src/auth/basic/helpers/winbind/winbindd_nss.h
diff -u /dev/null squid/src/auth/basic/helpers/winbind/winbindd_nss.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/basic/helpers/winbind/winbindd_nss.h	Tue Sep  3 10:42:23 2002
@@ -0,0 +1,202 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.0
+
+   Winbind daemon for ntdom nss module
+
+   Copyright (C) Tim Potter 2000
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library 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
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0)
+#endif
+
+#ifndef _WINBINDD_NTDOM_H
+#define _WINBINDD_NTDOM_H
+
+#define WINBINDD_SOCKET_NAME "pipe"            /* Name of PF_UNIX socket */
+#define WINBINDD_SOCKET_DIR  "/tmp/.winbindd"  /* Name of PF_UNIX dir */
+
+#define WINBINDD_DOMAIN_ENV  "WINBINDD_DOMAIN" /* Environment variables */
+#define WINBINDD_DONT_ENV    "_NO_WINBINDD"
+
+/* Update this when you change the interface.  */
+
+#define WINBIND_INTERFACE_VERSION 2
+
+/* Socket commands */
+
+enum winbindd_cmd {
+
+	WINBINDD_INTERFACE_VERSION,    /* Always a well known value */
+
+	/* Get users and groups */
+
+	WINBINDD_GETPWNAM,
+	WINBINDD_GETPWUID,
+	WINBINDD_GETGRNAM,
+	WINBINDD_GETGRGID,
+	WINBINDD_GETGROUPS,
+
+	/* Enumerate users and groups */
+
+	WINBINDD_SETPWENT,
+	WINBINDD_ENDPWENT,
+	WINBINDD_GETPWENT,
+	WINBINDD_SETGRENT,
+	WINBINDD_ENDGRENT,
+	WINBINDD_GETGRENT,
+
+	/* PAM authenticate and password change */
+
+	WINBINDD_PAM_AUTH,
+	WINBINDD_PAM_AUTH_CRAP,
+	WINBINDD_PAM_CHAUTHTOK,
+
+	/* List various things */
+
+	WINBINDD_LIST_USERS,         /* List w/o rid->id mapping */
+	WINBINDD_LIST_GROUPS,        /* Ditto */
+	WINBINDD_LIST_TRUSTDOM,
+
+	/* SID conversion */
+
+	WINBINDD_LOOKUPSID,
+	WINBINDD_LOOKUPNAME,
+
+	/* Lookup functions */
+
+	WINBINDD_SID_TO_UID,       
+	WINBINDD_SID_TO_GID,
+	WINBINDD_UID_TO_SID,
+	WINBINDD_GID_TO_SID,
+
+	/* Miscellaneous other stuff */
+
+	WINBINDD_CHECK_MACHACC,     /* Check machine account pw works */
+	WINBINDD_PING,              /* Just tell me winbind is running */
+	WINBINDD_INFO,              /* Various bit of info.  Currently just tidbits */
+
+	/* Placeholder for end of cmd list */
+
+	WINBINDD_NUM_CMDS
+};
+
+/* Winbind request structure */
+
+struct winbindd_request {
+	uint32 length;
+	enum winbindd_cmd cmd;   /* Winbindd command to execute */
+	pid_t pid;               /* pid of calling process */
+
+	union {
+		fstring username;    /* getpwnam */
+		fstring groupname;   /* getgrnam */
+		uid_t uid;           /* getpwuid, uid_to_sid */
+		gid_t gid;           /* getgrgid, gid_to_sid */
+		struct {
+			fstring user;
+			fstring pass;
+		} auth;              /* pam_winbind auth module */
+                struct {
+                        unsigned char chal[8];
+                        fstring user;
+                        fstring domain;
+                        fstring lm_resp;
+                        uint16 lm_resp_len;
+                        fstring nt_resp;
+                        uint16 nt_resp_len;
+                } auth_crap;
+                struct {
+                    fstring user;
+                    fstring oldpass;
+                    fstring newpass;
+                } chauthtok;         /* pam_winbind passwd module */
+		fstring sid;         /* lookupsid, sid_to_[ug]id */
+		fstring name;        /* lookupname */
+		uint32 num_entries;  /* getpwent, getgrent */
+	} data;
+	fstring domain;      /* {set,get,end}{pw,gr}ent() */
+};
+
+/* Response values */
+
+enum winbindd_result {
+	WINBINDD_ERROR,
+	WINBINDD_OK
+};
+
+/* Winbind response structure */
+
+struct winbindd_response {
+    
+	/* Header information */
+
+	uint32 length;                        /* Length of response */
+	enum winbindd_result result;          /* Result code */
+
+	/* Fixed length return data */
+	
+	union {
+		int interface_version;  /* Try to ensure this is always in the same spot... */
+		
+		/* getpwnam, getpwuid */
+		
+		struct winbindd_pw {
+			fstring pw_name;
+			fstring pw_passwd;
+			uid_t pw_uid;
+			gid_t pw_gid;
+			fstring pw_gecos;
+			fstring pw_dir;
+			fstring pw_shell;
+		} pw;
+
+		/* getgrnam, getgrgid */
+
+		struct winbindd_gr {
+			fstring gr_name;
+			fstring gr_passwd;
+			gid_t gr_gid;
+			int num_gr_mem;
+			int gr_mem_ofs;   /* offset to group membership */
+		} gr;
+
+		uint32 num_entries; /* getpwent, getgrent */
+		struct winbindd_sid {
+			fstring sid;        /* lookupname, [ug]id_to_sid */
+			int type;
+		} sid;
+		struct winbindd_name {
+			fstring name;       /* lookupsid */
+			int type;
+		} name;
+		uid_t uid;          /* sid_to_uid */
+		gid_t gid;          /* sid_to_gid */
+		struct winbindd_info {
+			char winbind_separator;
+			fstring samba_version;
+		} info;
+	} data;
+
+	/* Variable length return data */
+
+	void *extra_data;               /* getgrnam, getgrgid, getgrent */
+};
+
+#endif
Index: squid/src/auth/ntlm/helpers/Makefile.am
diff -u /dev/null squid/src/auth/ntlm/helpers/Makefile.am:1.2.28.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/Makefile.am	Tue Sep  3 10:42:29 2002
@@ -0,0 +1,7 @@
+#  Makefile for storage modules in the Squid Object Cache server
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+
+DIST_SUBDIRS	= fakeauth no_check SMB winbind
+SUBDIRS		= @NTLM_AUTH_HELPERS@
Index: squid/src/auth/ntlm/helpers/SMB/Makefile.am
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/Makefile.am:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/Makefile.am	Tue Sep  3 10:42:35 2002
@@ -0,0 +1,14 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+
+SUBDIRS = smbval
+
+libexec_PROGRAMS = ntlm_auth
+ntlm_auth_SOURCES = libntlmssp.c ntlm_auth.c ntlm.h
+INCLUDES      = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
+		-I$(top_srcdir)/src/ -I$(srcdir)/smbval
+LDADD		= smbval/libsmbvalid.a -L$(top_builddir)/lib -lntlmauth \
+		  -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
Index: squid/src/auth/ntlm/helpers/SMB/libntlmssp.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/libntlmssp.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/libntlmssp.c	Tue Sep  3 10:42:36 2002
@@ -0,0 +1,286 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * 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.
+ */
+
+typedef unsigned char uchar;
+
+#include "ntlm.h"
+#include "util.h"		/* from Squid */
+#include "valid.h"
+#include "smbencrypt.h"
+
+#if HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* these are part of rfcnb-priv.h and smblib-priv.h */
+extern int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+extern int SMB_Get_Last_Error();
+extern int RFCNB_Get_Last_Errno();
+
+#include "smblib-priv.h"	/* for SMB_Handle_Type */
+
+/* a few forward-declarations. Hackish, but I don't care right now */
+SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle, char *server, char *NTdomain);
+
+/* this one is reallllly haackiish. We really should be using anything from smblib-priv.h
+ */
+static char *SMB_Prots[] =
+{"PC NETWORK PROGRAM 1.0",
+    "MICROSOFT NETWORKS 1.03",
+    "MICROSOFT NETWORKS 3.0",
+    "DOS LANMAN1.0",
+    "LANMAN1.0",
+    "DOS LM1.2X002",
+    "LM1.2X002",
+    "DOS LANMAN2.1",
+    "LANMAN2.1",
+    "Samba",
+    "NT LM 0.12",
+    "NT LANMAN 1.0",
+    NULL
+};
+
+#if 0
+int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle);
+int SMB_Negotiate(void *Con_Handle, char *Prots[]);
+int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName, char *PassWord, char *Domain, int precrypted);
+#endif
+
+#ifdef DEBUG
+#define debug_dump_ntlmssp_flags dump_ntlmssp_flags
+#else /* DEBUG */
+#define debug_dump_ntlmssp_flags(X)	/* empty */
+#endif /* DEBUG */
+
+
+#define ENCODED_PASS_LEN 24
+static char challenge[NONCE_LEN];
+static char lmencoded_empty_pass[ENCODED_PASS_LEN],
+	ntencoded_empty_pass[ENCODED_PASS_LEN];
+SMB_Handle_Type handle = NULL;
+
+/* Disconnects from the DC. A reconnection will be done upon the next request
+ */
+void
+dc_disconnect()
+{
+    if (handle != NULL)
+	SMB_Discon(handle, 0);
+    handle = NULL;
+}
+
+int
+connectedp()
+{
+    return (handle != NULL);
+}
+
+
+/* Tries to connect to a DC. Returns 0 on failure, 1 on OK */
+int
+is_dc_ok(char *domain, char *domain_controller)
+{
+    SMB_Handle_Type h = SMB_Connect_Server(NULL, domain_controller, domain);
+    if (h == NULL)
+	return 0;
+    SMB_Discon(h, 0);
+    return 1;
+}
+
+
+static char errstr[1001];
+/* returns 0 on success, > 0 on failure */
+static int
+init_challenge(char *domain, char *domain_controller)
+{
+    int smberr;
+
+    if (handle != NULL) {
+	return 0;
+    }
+    debug("Connecting to server %s domain %s\n", domain_controller, domain);
+    handle = SMB_Connect_Server(NULL, domain_controller, domain);
+    smberr = SMB_Get_Last_Error();
+    SMB_Get_Error_Msg(smberr, errstr, 1000);
+
+
+    if (handle == NULL) {	/* couldn't connect */
+	debug("Couldn't connect to SMB Server. Error:%s\n", errstr);
+	return 1;
+    }
+    if (SMB_Negotiate(handle, SMB_Prots) < 0) {		/* An error */
+	debug("Error negotiating protocol with SMB Server\n");
+	SMB_Discon(handle, 0);
+	handle = NULL;
+	return 2;
+    }
+    if (handle->Security == 0) {	/* share-level security, unuseable */
+	debug("SMB Server uses share-level security .. we need user security.\n");
+	SMB_Discon(handle, 0);
+	handle = NULL;
+	return 3;
+    }
+    memcpy(challenge, handle->Encrypt_Key, NONCE_LEN);
+		SMBencrypt("",challenge,lmencoded_empty_pass);
+		SMBNTencrypt("",challenge,ntencoded_empty_pass);
+    return 0;
+}
+
+static char my_domain[100], my_domain_controller[100];
+const char *
+make_challenge(char *domain, char *domain_controller)
+{
+	/* trying to circumvent some strange problem wih pointers in SMBLib */
+	/* Ugly as hell, but the lib is going to be dropped... */
+	strcpy(my_domain,domain);
+	strcpy(my_domain_controller,domain_controller);
+    if (init_challenge(my_domain, my_domain_controller) > 0) {
+	return NULL;
+    }
+    return ntlm_make_challenge(my_domain, my_domain_controller, challenge, NONCE_LEN);
+}
+
+#define min(A,B) (A<B?A:B)
+
+int ntlm_errno;
+static char credentials[1024];	/* we can afford to waste */
+
+
+/* Fetches the user's credentials from the challenge.
+ * Returns NULL if domain or user is not defined
+ * No identity control is performed.
+ * WARNING! The result is static storage, shared with ntlm_check_auth
+ */
+char *
+fetch_credentials(ntlm_authenticate * auth, int auth_length)
+{
+    char *p = credentials;
+    lstring tmp;
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
+    if (tmp.str == NULL)
+	return NULL;
+    memcpy(p, tmp.str, tmp.l);
+    p += tmp.l;
+    *p++ = '\\';
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
+    if (tmp.str == NULL)
+	return NULL;
+    *(p + tmp.l) = '\0';
+    return credentials;
+}
+
+/* returns NULL on failure, or a pointer to
+ * the user's credentials (domain\\username)
+ * upon success. WARNING. It's pointing to static storage.
+ * In case of problem sets as side-effect ntlm_errno to one of the
+ * codes defined in ntlm.h
+ */
+char *
+ntlm_check_auth(ntlm_authenticate * auth, int auth_length)
+{
+    int rv;
+    char pass[25] /*, encrypted_pass[40] */;
+    char *domain = credentials;
+    char *user;
+    lstring tmp;
+
+    if (handle == NULL) {	/*if null we aren't connected, but it shouldn't happen */
+	debug("Weird, we've been disconnected\n");
+	ntlm_errno = NTLM_NOT_CONNECTED;
+	return NULL;
+    }
+
+/*      debug("fetching domain\n"); */
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
+    if (tmp.str == NULL || tmp.l == 0) {
+	debug("No domain supplied. Returning no-auth\n");
+	ntlm_errno = NTLM_LOGON_ERROR;
+	return NULL;
+    }
+    memcpy(domain, tmp.str, tmp.l);
+    user = domain + tmp.l;
+    *user++ = '\0';
+
+/*      debug("fetching user name\n"); */
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
+    if (tmp.str == NULL || tmp.l == 0) {
+	debug("No username supplied. Returning no-auth\n");
+	ntlm_errno = NTLM_LOGON_ERROR;
+	return NULL;
+    }
+    memcpy(user, tmp.str, tmp.l);
+    *(user + tmp.l) = '\0';
+
+		
+		/* Authenticating against the NT response doesn't seem to work... */
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse);
+    if (tmp.str == NULL || tmp.l == 0) {
+	fprintf(stderr, "No auth at all. Returning no-auth\n");
+	ntlm_errno = NTLM_LOGON_ERROR;
+	return NULL;
+    }
+		
+    memcpy(pass, tmp.str, tmp.l);
+    pass[25] = '\0';
+
+#if 1
+		debug ("Empty LM pass detection: user: '%s', ours:'%s', his: '%s'"
+					 "(length: %d)\n",
+					 user,lmencoded_empty_pass,tmp.str,tmp.l);
+		if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) {
+			fprintf(stderr,"Empty LM password supplied for user %s\\%s. "
+							"No-auth\n",domain,user);
+			ntlm_errno=NTLM_LOGON_ERROR;
+			return NULL;
+		}
+		
+		tmp = ntlm_fetch_string ((char *) auth, auth_length, &auth->ntresponse);
+		if (tmp.str != NULL && tmp.l != 0) {
+			debug ("Empty NT pass detection: user: '%s', ours:'%s', his: '%s'"
+						 "(length: %d)\n",
+						 user,ntencoded_empty_pass,tmp.str,tmp.l);
+			if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) {
+				fprintf(stderr,"Empty NT password supplied for user %s\\%s. "
+								"No-auth\n",domain,user);
+				ntlm_errno=NTLM_LOGON_ERROR;
+				return NULL;
+			}
+		}
+#endif
+
+		/* TODO: check against empty password!!!!! */
+		
+
+
+    debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass);
+
+    rv = SMB_Logon_Server(handle, user, pass, domain, 1);
+    debug("Login attempt had result %d\n", rv);
+
+    if (rv != NTV_NO_ERROR) {	/* failed */
+	ntlm_errno = rv;
+	return NULL;
+    }
+    *(user - 1) = '\\';		/* hack. Performing, but ugly. */
+
+    debug("credentials: %s\n", credentials);
+    return credentials;
+}
Index: squid/src/auth/ntlm/helpers/SMB/ntlm.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/ntlm.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/ntlm.h	Tue Sep  3 10:42:36 2002
@@ -0,0 +1,107 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>,
+ *        inspired by previous work by Andrew Doran <ad@interlude.eu.org>
+ *
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * 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 _NTLM_H_
+#define _NTLM_H_
+
+#include "config.h"
+#include "ntlmauth.h"
+
+/* for time_t */
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/************* CONFIGURATION ***************/
+/*
+ * define this if you want debugging
+ */
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+#define DEAD_DC_RETRY_INTERVAL 30
+
+/************* END CONFIGURATION ***************/
+
+#include <sys/types.h>
+
+
+/* Debugging stuff */
+
+#ifdef __GNUC__			/* this is really a gcc-ism */
+#ifdef DEBUG
+#include <stdio.h>
+#include <unistd.h>
+static char *__foo;
+extern char debug_enabled;
+#define debug(X...) if (debug_enabled) { \
+                    fprintf(stderr,"ntlm-auth[%d](%s:%d): ", getpid(), \
+                    ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\
+                    __LINE__);\
+                    fprintf(stderr,X); }
+#else /* DEBUG */
+#define debug(X...)		/* */
+#endif /* DEBUG */
+#else /* __GNUC__ */
+static void
+debug(char *format,...)
+{
+}
+
+#endif
+
+
+/* A couple of harmless helper macros */
+#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
+#ifdef __GNUC__
+#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
+#else
+/* no gcc, no debugging. varargs macros are a gcc extension */
+#define SEND2 printf
+#endif
+
+extern int ntlm_errno;
+#define NTLM_NO_ERROR 0
+#define NTLM_SERVER_ERROR 1
+#define NTLM_PROTOCOL_ERROR 2
+#define NTLM_LOGON_ERROR 3
+#define NTLM_UNTRUSTED_DOMAIN 4
+#define NTLM_BAD_PROTOCOL -1
+#define NTLM_NOT_CONNECTED 10
+
+
+const char *make_challenge(char *domain, char *controller);
+extern char *ntlm_check_auth(ntlm_authenticate * auth, int auth_length);
+extern char *fetch_credentials(ntlm_authenticate * auth, int auth_length);
+void dc_disconnect(void);
+int connectedp(void);
+int is_dc_ok(char *domain, char *domain_controller);
+
+typedef struct _dc dc;
+struct _dc {
+    char *domain;
+    char *controller;
+    time_t dead;		/* 0 if it's alive, otherwise time of death */
+    dc *next;
+};
+
+
+#endif /* _NTLM_H_ */
Index: squid/src/auth/ntlm/helpers/SMB/ntlm_auth.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/ntlm_auth.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/ntlm_auth.c	Tue Sep  3 10:42:36 2002
@@ -0,0 +1,475 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * 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 "config.h"
+#include "ntlmauth.h"
+#include "ntlm.h"
+#include "util.h"
+#include "smbval/smblib-common.h"
+#include "smbval/rfcnb-error.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+/* these are part of rfcnb-priv.h and smblib-priv.h */
+extern int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+extern int SMB_Get_Last_Error();
+extern int SMB_Get_Last_SMB_Err();
+extern int RFCNB_Get_Last_Error();
+
+#include <errno.h>
+
+#define BUFFER_SIZE 10240
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef DEBUG
+char error_messages_buffer[BUFFER_SIZE];
+#endif
+
+char load_balance = 0, protocol_pedantic = 0;
+#ifdef NTLM_FAIL_OPEN
+char last_ditch_enabled = 0;
+#endif
+
+dc *controllers = NULL;
+int numcontrollers = 0;
+dc *current_dc;
+
+char smb_error_buffer[1000];
+
+/* signal handler to be invoked when the authentication operation
+ * times out */
+static char got_timeout = 0;
+static void
+timeout_during_auth(int signum)
+{
+    dc_disconnect();
+}
+
+/* makes a null-terminated string upper-case. Changes CONTENTS! */
+static void
+uc(char *string)
+{
+    char *p = string, c;
+    while ((c = *p)) {
+	*p = toupper(c);
+	p++;
+    }
+}
+
+/* makes a null-terminated string lower-case. Changes CONTENTS! */
+static void
+lc(char *string)
+{
+    char *p = string, c;
+    while ((c = *p)) {
+	*p = tolower(c);
+	p++;
+    }
+}
+
+
+void
+send_bh_or_ld(char *bhmessage, ntlm_authenticate * failedauth, int authlen)
+{
+#ifdef NTLM_FAIL_OPEN
+    char *creds = NULL;
+    if (last_ditch_enabled) {
+	creds = fetch_credentials(failedauth, authlen);
+	if (creds) {
+	    lc(creds);
+	    SEND2("LD %s", creds);
+	} else {
+	    SEND("NA last-ditch on, but no credentials");
+	}
+    } else {
+#endif
+	SEND2("BH %s", bhmessage);
+#ifdef NTLM_FAIL_OPEN
+    }
+#endif
+}
+
+/*
+ * options:
+ * -b try load-balancing the domain-controllers
+ * -f fail-over to another DC if DC connection fails.
+ *    DEPRECATED and VERBOSELY IGNORED. This is on by default now.
+ * -l last-ditch-mode
+ * domain\controller ...
+ */
+char *my_program_name = NULL;
+
+void
+usage()
+{
+    fprintf(stderr,
+	"%s usage:\n%s [-b] [-f] [-d] domain\\controller [domain\\controller ...]\n-b, if specified, enables load-balancing among controllers\n-f, if specified, enables failover among controllers (DEPRECATED and always active)\n-l, if specified, changes behavior on domain controller failyures to\tlast-ditch.-d enables debugging statements if DEBUG was defined at build-time.\n\nYou MUST specify at least one Domain Controller.\nYou can use either \\ or / as separator between the domain name \n\tand the controller name\n",
+	my_program_name, my_program_name);
+}
+
+char debug_enabled=0;
+
+void
+process_options(int argc, char *argv[])
+{
+    int opt, j, had_error = 0;
+    dc *new_dc = NULL, *last_dc = NULL;
+    while (-1 != (opt = getopt(argc, argv, "bfld"))) {
+	switch (opt) {
+	case 'b':
+	    load_balance = 1;
+	    break;
+	case 'f':
+	    fprintf(stderr,
+		"WARNING. The -f flag is DEPRECATED and always active.\n");
+	    break;
+#ifdef NTLM_FAIL_OPEN
+	case 'l':
+	    last_ditch_enabled = 1;
+	    break;
+#endif
+	case 'd':
+		debug_enabled=1;
+		break;
+	default:
+	    fprintf(stderr, "unknown option: -%c. Exiting\n", opt);
+	    usage();
+	    had_error = 1;
+	}
+    }
+    if (had_error)
+	exit(1);
+    /* Okay, now begin filling controllers up */
+    /* we can avoid memcpy-ing, and just reuse argv[] */
+    for (j = optind; j < argc; j++) {
+	char *d, *c;
+	/* d will not be freed in case of non-error. Since we don't reconfigure,
+	 * it's going to live as long as the process anyways */
+	d = malloc(strlen(argv[j]) + 1);
+	strcpy(d, argv[j]);
+	debug("Adding domain-controller %s\n", d);
+	if (NULL == (c = strchr(d, '\\')) && NULL == (c = strchr(d, '/'))) {
+	    fprintf(stderr, "Couldn't grok domain-controller %s\n", d);
+	    free(d);
+	    continue;
+	}
+	/* more than one delimiter is not allowed */
+	if (NULL != strchr(c + 1, '\\') || NULL != strchr(c + 1, '/')) {
+	    fprintf(stderr, "Broken domain-controller %s\n", d);
+	    free(d);
+	    continue;
+	}
+	*c++ = '\0';
+	new_dc = (dc *) malloc(sizeof(dc));
+	if (!new_dc) {
+	    fprintf(stderr, "Malloc error while parsing DC options\n");
+	    free(d);
+	    continue;
+	}
+	/* capitalize */
+	uc(c);
+	uc(d);
+	numcontrollers++;
+	new_dc->domain = d;
+	new_dc->controller = c;
+	new_dc->dead = 0;
+	if (controllers == NULL) {	/* first controller */
+	    controllers = new_dc;
+	    last_dc = new_dc;
+	} else {
+	    last_dc->next = new_dc;	/* can't be null */
+	    last_dc = new_dc;
+	}
+    }
+    if (numcontrollers == 0) {
+	fprintf(stderr, "You must specify at least one domain-controller!\n");
+	usage();
+	exit(1);
+    }
+    last_dc->next = controllers;	/* close the queue, now it's circular */
+}
+
+/* tries connecting to the domain controllers in the "controllers" ring,
+ * with failover if the adequate option is specified.
+ */
+const char *
+obtain_challenge()
+{
+    int j = 0;
+    const char *ch = NULL;
+    for (j = 0; j < numcontrollers; j++) {
+	debug("obtain_challenge: selecting %s\\%s (attempt #%d)\n",
+	    current_dc->domain, current_dc->controller, j + 1);
+	if (current_dc->dead != 0) {
+	    if (time(NULL) - current_dc->dead >= DEAD_DC_RETRY_INTERVAL) {
+		/* mark helper as retry-worthy if it's so. */
+		debug("Reviving DC\n");
+		current_dc->dead = 0;
+	    } else {		/* skip it */
+		debug("Skipping it\n");
+		continue;
+	    }
+	}
+	/* else branch. Here we KNOW that the DC is fine */
+	debug("attempting challenge retrieval\n");
+	ch = make_challenge(current_dc->domain, current_dc->controller);
+	debug("make_challenge retuned %p\n", ch);
+	if (ch) {
+	    debug("Got it\n");
+	    return ch;		/* All went OK, returning */
+	}
+	/* Huston, we've got a problem. Take this DC out of the loop */
+	debug("Marking DC as DEAD\n");
+	current_dc->dead = time(NULL);
+	/* Try with the next */
+	debug("moving on to next controller\n");
+	current_dc = current_dc->next;
+    }
+    /* all DCs failed. */
+    return NULL;
+}
+
+
+void
+manage_request()
+{
+    ntlmhdr *fast_header;
+    char buf[BUFFER_SIZE];
+    const char *ch;
+    char *ch2, *decoded, *cred;
+    int plen;
+
+    if (fgets(buf, BUFFER_SIZE, stdin) == NULL) {
+	fprintf(stderr, "fgets() failed! dying..... errno=%d (%s)\n", errno,
+	    strerror(errno));
+	exit(1);		/* BIIG buffer */
+    }
+    debug("managing request\n");
+    ch2 = memchr(buf, '\n', BUFFER_SIZE);	/* safer against overrun than strchr */
+    if (ch2) {
+	*ch2 = '\0';		/* terminate the string at newline. */
+	ch = ch2;
+    }
+    debug("ntlm authenticator. Got '%s' from Squid\n", buf);
+
+    if (memcmp(buf, "KK ", 3) == 0) {	/* authenticate-request */
+	/* figure out what we got */
+	decoded = base64_decode(buf + 3);
+	/* Note: we don't need to manage memory at this point, since
+	 *  base64_decode returns a pointer to static storage.
+	 */
+
+	if (!decoded) {		/* decoding failure, return error */
+	    SEND("NA Packet format error, couldn't base64-decode");
+	    return;
+	}
+	/* fast-track-decode request type. */
+	fast_header = (struct _ntlmhdr *) decoded;
+
+	/* sanity-check: it IS a NTLMSSP packet, isn't it? */
+	if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) {
+	    SEND("NA Broken authentication packet");
+	    return;
+	}
+	switch (fast_header->type) {
+	case NTLM_NEGOTIATE:
+	    SEND("NA Invalid negotiation request received");
+	    return;
+	    /* notreached */
+	case NTLM_CHALLENGE:
+	    SEND
+		("NA Got a challenge. We refuse to have our authority disputed");
+	    return;
+	    /* notreached */
+	case NTLM_AUTHENTICATE:
+	    /* check against the DC */
+	    plen = strlen(buf) * 3 / 4;		/* we only need it here. Optimization */
+	    signal(SIGALRM, timeout_during_auth);
+	    alarm(30);
+	    cred = ntlm_check_auth((ntlm_authenticate *) decoded, plen);
+	    alarm(0);
+	    signal(SIGALRM, SIG_DFL);
+	    if (got_timeout != 0) {
+		fprintf(stderr, "ntlm-auth[%d]: Timeout during authentication.\n", getpid());
+		SEND("BH Timeout during authentication");
+		got_timeout = 0;
+		return;
+	    }
+	    if (cred == NULL) {
+		int smblib_err, smb_errorclass, smb_errorcode, nb_error;
+		if (ntlm_errno == NTLM_LOGON_ERROR) {	/* hackish */
+			SEND("NA Logon Failure");
+			return;
+		}
+		/* there was an error. We have two errno's to look at.
+		 * libntlmssp's erno is insufficient, we'll have to look at
+		 * the actual SMB library error codes, to acually figure
+		 * out what's happening. The thing has braindamaged interfacess..*/
+		smblib_err = SMB_Get_Last_Error();
+		smb_errorclass = SMBlib_Error_Class(SMB_Get_Last_SMB_Err());
+		smb_errorcode = SMBlib_Error_Code(SMB_Get_Last_SMB_Err());
+		nb_error = RFCNB_Get_Last_Error();
+		debug("No creds. SMBlib error %d, SMB error class %d, SMB error code %d, NB error %d\n",
+		    smblib_err, smb_errorclass, smb_errorcode, nb_error);
+		/* Should I use smblib_err? Actually it seems I can do as well
+		 * without it.. */
+		if (nb_error != 0) {	/* netbios-level error */
+		    send_bh_or_ld("NetBios error!",
+			(ntlm_authenticate *) decoded, plen);
+		    fprintf(stderr, "NetBios error code %d (%s)\n", nb_error,
+			RFCNB_Error_Strings[abs(nb_error)]);
+		    return;
+		}
+		switch (smb_errorclass) {
+		case SMBC_SUCCESS:
+		    debug("Huh? Got a SMB success code but could check auth..");
+		    SEND("NA Authentication failed");
+		    /*
+		     * send_bh_or_ld("SMB success, but no creds. Internal error?",
+		     * (ntlm_authenticate *) decoded, plen);
+		     */
+		    return;
+		case SMBC_ERRDOS:
+		    /*this is the most important one for errors */
+		    debug("DOS error\n");
+		    switch (smb_errorcode) {
+			/* two categories matter to us: those which could be
+			 * server errors, and those which are auth errors */
+		    case SMBD_noaccess:	/* 5 */
+			SEND("NA Access denied");
+			return;
+		    case SMBD_badformat:
+			SEND("NA bad format in authentication packet");
+			return;
+		    case SMBD_badaccess:
+			SEND("NA Bad access request");
+			return;
+		    case SMBD_baddata:
+			SEND("NA Bad Data");
+			return;
+		    default:
+			send_bh_or_ld("DOS Error",
+			    (ntlm_authenticate *) decoded, plen);
+			return;
+		    }
+		case SMBC_ERRSRV:	/* server errors */
+		    debug("Server error");
+		    switch (smb_errorcode) {
+			/* mostly same as above */
+		    case SMBV_badpw:
+			SEND("NA Bad password");
+			return;
+		    case SMBV_access:
+			SEND("NA Server access error");
+			return;
+		    default:
+			send_bh_or_ld("Server Error",
+			    (ntlm_authenticate *) decoded, plen);
+			return;
+		    }
+		case SMBC_ERRHRD:	/* hardware errors don't really matter */
+		    send_bh_or_ld("Domain Controller Hardware error",
+			(ntlm_authenticate *) decoded, plen);
+		    return;
+		case SMBC_ERRCMD:
+		    send_bh_or_ld("Domain Controller Command Error",
+			(ntlm_authenticate *) decoded, plen);
+		    return;
+		}
+	    }
+	    lc(cred);		/* let's lowercase them for our convenience */
+	    SEND2("AF %s", cred);
+	    return;
+	default:
+	    SEND("BH unknown authentication packet type");
+	    return;
+	}
+
+
+	return;
+    }
+    if (memcmp(buf, "YR", 2) == 0) {	/* refresh-request */
+	dc_disconnect();
+	ch = obtain_challenge();
+	/* Robert says we can afford to wait forever. I'll trust him on this
+	 * one */
+	while (ch == NULL) {
+	    sleep(30);
+	    ch = obtain_challenge();
+	}
+	SEND2("TT %s", ch);
+	return;
+    }
+    SEND("BH Helper detected protocol error");
+    return;
+/********* END ********/
+
+
+}
+
+int
+main(int argc, char *argv[])
+{
+
+    debug("ntlm_auth build " __DATE__ ", " __TIME__ " starting up...\n");
+#ifdef DEBUG
+    debug("changing dir to /tmp\n");
+    chdir("/tmp");
+#endif
+
+    my_program_name = argv[0];
+    process_options(argc, argv);
+
+    debug("options processed OK\n");
+
+    /* initialize FDescs */
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+
+    /* select the first domain controller we're going to use */
+    current_dc = controllers;
+    if (load_balance != 0 && numcontrollers > 1) {
+	int n;
+	pid_t pid = getpid();
+	n = pid % numcontrollers;
+	debug("load balancing. Selected controller #%d\n", n);
+	while (n > 0) {
+	    current_dc = current_dc->next;
+	    n--;
+	}
+    }
+    while (1) {
+	manage_request();
+    }
+    return 0;
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/Makefile.am
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/Makefile.am:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/Makefile.am	Tue Sep  3 10:42:37 2002
@@ -0,0 +1,13 @@
+# makefile for smblib
+
+INCLUDES      = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
+		-I$(top_srcdir)/src/
+
+noinst_LIBRARIES = libsmbvalid.a
+libsmbvalid_a_SOURCES = valid.c session.c rfcnb-util.c rfcnb-io.c \
+	smblib-util.c smblib.c smbencrypt.c smbdes.c md4.c byteorder.h \
+	rfcnb-error.h  rfcnb-util.h  smbencrypt.h     smblib.h        valid.h \
+	md4.h           rfcnb-io.h     rfcnb.h       smblib-common.h  std-defines.h \
+	rfcnb-common.h  rfcnb-priv.h   smbdes.h      smblib-priv.h    std-includes.h 
+
+##OBJS = smblib.o smblib-util.o file.o smb-errors.o exper.o smblib-api.o smbencrypt.o smbdes.o md4.o
Index: squid/src/auth/ntlm/helpers/SMB/smbval/byteorder.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/byteorder.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/byteorder.h	Tue Sep  3 10:42:38 2002
@@ -0,0 +1,80 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * SMB Byte handling
+ * Copyright (C) Andrew Tridgell 1992-1995
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file implements macros for machine independent short and 
+ * int manipulation
+ */
+
+#undef CAREFUL_ALIGNMENT
+
+/* we know that the 386 can handle misalignment and has the "right" 
+ * byteorder */
+#ifdef __i386__
+#define CAREFUL_ALIGNMENT 0
+#endif
+
+#ifndef CAREFUL_ALIGNMENT
+#define CAREFUL_ALIGNMENT 1
+#endif
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
+
+
+#if CAREFUL_ALIGNMENT
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
+#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
+#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
+#else
+/* this handles things for architectures like the 386 that can handle
+ * alignment errors */
+/*
+ * WARNING: This section is dependent on the length of int16 and int32
+ * being correct 
+ */
+#define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
+#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
+#define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
+#define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))
+#define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
+#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
+#define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
+#define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))
+#endif
+
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
Index: squid/src/auth/ntlm/helpers/SMB/smbval/md4.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/md4.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/md4.c	Tue Sep  3 10:42:38 2002
@@ -0,0 +1,209 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * a implementation of MD4 designed for use in the SMB authentication protocol
+ * Copyright (C) Andrew Tridgell 1997
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* NOTE: This code makes no attempt to be fast! 
+ * 
+ * It assumes that a int is at least 32 bits long
+ */
+#include <string.h>
+#include "std-defines.h"	/* for the types */
+
+static uint32 A, B, C, D;
+
+static uint32
+F(uint32 X, uint32 Y, uint32 Z)
+{
+    return (X & Y) | ((~X) & Z);
+}
+
+static uint32
+G(uint32 X, uint32 Y, uint32 Z)
+{
+    return (X & Y) | (X & Z) | (Y & Z);
+}
+
+static uint32
+H(uint32 X, uint32 Y, uint32 Z)
+{
+    return X ^ Y ^ Z;
+}
+
+static uint32
+lshift(uint32 x, int s)
+{
+    x &= 0xFFFFFFFF;
+    return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void
+mdfour64(uint32 * M)
+{
+    int j;
+    uint32 AA, BB, CC, DD;
+    uint32 X[16];
+
+    for (j = 0; j < 16; j++)
+	X[j] = M[j];
+
+    AA = A;
+    BB = B;
+    CC = C;
+    DD = D;
+
+    ROUND1(A, B, C, D, 0, 3);
+    ROUND1(D, A, B, C, 1, 7);
+    ROUND1(C, D, A, B, 2, 11);
+    ROUND1(B, C, D, A, 3, 19);
+    ROUND1(A, B, C, D, 4, 3);
+    ROUND1(D, A, B, C, 5, 7);
+    ROUND1(C, D, A, B, 6, 11);
+    ROUND1(B, C, D, A, 7, 19);
+    ROUND1(A, B, C, D, 8, 3);
+    ROUND1(D, A, B, C, 9, 7);
+    ROUND1(C, D, A, B, 10, 11);
+    ROUND1(B, C, D, A, 11, 19);
+    ROUND1(A, B, C, D, 12, 3);
+    ROUND1(D, A, B, C, 13, 7);
+    ROUND1(C, D, A, B, 14, 11);
+    ROUND1(B, C, D, A, 15, 19);
+
+    ROUND2(A, B, C, D, 0, 3);
+    ROUND2(D, A, B, C, 4, 5);
+    ROUND2(C, D, A, B, 8, 9);
+    ROUND2(B, C, D, A, 12, 13);
+    ROUND2(A, B, C, D, 1, 3);
+    ROUND2(D, A, B, C, 5, 5);
+    ROUND2(C, D, A, B, 9, 9);
+    ROUND2(B, C, D, A, 13, 13);
+    ROUND2(A, B, C, D, 2, 3);
+    ROUND2(D, A, B, C, 6, 5);
+    ROUND2(C, D, A, B, 10, 9);
+    ROUND2(B, C, D, A, 14, 13);
+    ROUND2(A, B, C, D, 3, 3);
+    ROUND2(D, A, B, C, 7, 5);
+    ROUND2(C, D, A, B, 11, 9);
+    ROUND2(B, C, D, A, 15, 13);
+
+    ROUND3(A, B, C, D, 0, 3);
+    ROUND3(D, A, B, C, 8, 9);
+    ROUND3(C, D, A, B, 4, 11);
+    ROUND3(B, C, D, A, 12, 15);
+    ROUND3(A, B, C, D, 2, 3);
+    ROUND3(D, A, B, C, 10, 9);
+    ROUND3(C, D, A, B, 6, 11);
+    ROUND3(B, C, D, A, 14, 15);
+    ROUND3(A, B, C, D, 1, 3);
+    ROUND3(D, A, B, C, 9, 9);
+    ROUND3(C, D, A, B, 5, 11);
+    ROUND3(B, C, D, A, 13, 15);
+    ROUND3(A, B, C, D, 3, 3);
+    ROUND3(D, A, B, C, 11, 9);
+    ROUND3(C, D, A, B, 7, 11);
+    ROUND3(B, C, D, A, 15, 15);
+
+    A += AA;
+    B += BB;
+    C += CC;
+    D += DD;
+
+    A &= 0xFFFFFFFF;
+    B &= 0xFFFFFFFF;
+    C &= 0xFFFFFFFF;
+    D &= 0xFFFFFFFF;
+
+    for (j = 0; j < 16; j++)
+	X[j] = 0;
+}
+
+static void
+copy64(uint32 * M, unsigned char *in)
+{
+    int i;
+
+    for (i = 0; i < 16; i++)
+	M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
+	    (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
+}
+
+static void
+copy4(unsigned char *out, uint32 x)
+{
+    out[0] = x & 0xFF;
+    out[1] = (x >> 8) & 0xFF;
+    out[2] = (x >> 16) & 0xFF;
+    out[3] = (x >> 24) & 0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void
+mdfour(unsigned char *out, unsigned char *in, int n)
+{
+    unsigned char buf[128];
+    uint32 M[16];
+    uint32 b = n * 8;
+    int i;
+
+    A = 0x67452301;
+    B = 0xefcdab89;
+    C = 0x98badcfe;
+    D = 0x10325476;
+
+    while (n > 64) {
+	copy64(M, in);
+	mdfour64(M);
+	in += 64;
+	n -= 64;
+    }
+
+    for (i = 0; i < 128; i++)
+	buf[i] = 0;
+    memcpy(buf, in, n);
+    buf[n] = 0x80;
+
+    if (n <= 55) {
+	copy4(buf + 56, b);
+	copy64(M, buf);
+	mdfour64(M);
+    } else {
+	copy4(buf + 120, b);
+	copy64(M, buf);
+	mdfour64(M);
+	copy64(M, buf + 64);
+	mdfour64(M);
+    }
+
+    for (i = 0; i < 128; i++)
+	buf[i] = 0;
+    copy64(M, buf);
+
+    copy4(out, A);
+    copy4(out + 4, B);
+    copy4(out + 8, C);
+    copy4(out + 12, D);
+
+    A = B = C = D = 0;
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/md4.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/md4.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/md4.h	Tue Sep  3 10:42:38 2002
@@ -0,0 +1 @@
+void mdfour(unsigned char *out, unsigned char *in, int n);
Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-common.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-common.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-common.h	Tue Sep  3 10:42:38 2002
@@ -0,0 +1,34 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Common Structures etc Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* A data structure we need */
+
+typedef struct RFCNB_Pkt {
+
+    char *data;			/* The data in this portion */
+    int len;
+    struct RFCNB_Pkt *next;
+
+} RFCNB_Pkt;
Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-error.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-error.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-error.h	Tue Sep  3 10:42:38 2002
@@ -0,0 +1,74 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Error Response Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Error responses */
+
+#define RFCNBE_Bad -1		/* Bad response */
+#define RFCNBE_OK 0
+
+/* these should follow the spec ... is there one ? */
+
+#define RFCNBE_NoSpace 1	/* Could not allocate space for a struct */
+#define RFCNBE_BadName 2	/* Could not translate a name            */
+#define RFCNBE_BadRead 3	/* Read sys call failed                  */
+#define RFCNBE_BadWrite 4	/* Write Sys call failed                 */
+#define RFCNBE_ProtErr 5	/* Protocol Error                        */
+#define RFCNBE_ConGone 6	/* Connection dropped                    */
+#define RFCNBE_BadHandle 7	/* Handle passed was bad                 */
+#define RFCNBE_BadSocket 8	/* Problems creating socket              */
+#define RFCNBE_ConnectFailed 9	/* Connect failed                        */
+#define RFCNBE_CallRejNLOCN 10	/* Call rejected, not listening on CN    */
+#define RFCNBE_CallRejNLFCN 11	/* Call rejected, not listening for CN   */
+#define RFCNBE_CallRejCNNP  12	/* Call rejected, called name not present */
+#define RFCNBE_CallRejInfRes 13	/* Call rejetced, name ok, no resources   */
+#define RFCNBE_CallRejUnSpec 14	/* Call rejected, unspecified error      */
+#define RFCNBE_BadParam      15	/* Bad parameters passed ...             */
+#define RFCNBE_Timeout       16	/* IO Timed out                          */
+
+/* Text strings for the error responses                                 */
+extern char *RFCNB_Error_Strings[];
+/*
+ * static char *RFCNB_Error_Strings[] = {
+ * 
+ * "RFCNBE_OK: Routine completed successfully.",
+ * "RFCNBE_NoSpace: No space available for a malloc call.",
+ * "RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
+ * "RFCNBE_BadRead: Read system call returned an error. Check errno.",
+ * "RFCNBE_BadWrite: Write system call returned an error. Check errno.",
+ * "RFCNBE_ProtErr: A protocol error has occurred.",
+ * "RFCNBE_ConGone: Connection dropped during a read or write system call.",
+ * "RFCNBE_BadHandle: Bad connection handle passed.",
+ * "RFCNBE_BadSocket: Problems creating socket.",
+ * "RFCNBE_ConnectFailed: Connection failed. See errno.",
+ * "RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
+ * "RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
+ * "RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
+ * "RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
+ * "RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
+ * "RFCNBE_BadParam: Bad parameters passed to a routine.",
+ * "RFCNBE_Timeout: IO Operation timed out ..."
+ * 
+ * };
+ */
Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.c	Tue Sep  3 10:42:38 2002
@@ -0,0 +1,400 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB IO Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* #include <features.h> */
+#include "config.h"
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+#include <sys/uio.h>
+#include <sys/signal.h>
+#include <string.h>
+
+int RFCNB_Timeout = 0;		/* Timeout in seconds ... */
+
+void
+rfcnb_alarm(int sig)
+{
+
+    fprintf(stderr, "IO Timed out ...\n");
+
+}
+
+/* Set timeout value and setup signal handling */
+
+int
+RFCNB_Set_Timeout(int seconds)
+{
+    /* If we are on a Bezerkeley system, use sigvec, else sigaction */
+#if HAVE_SIGACTION
+    struct sigaction inact, outact;
+#else
+    struct sigvec invec, outvec;
+#endif
+
+    RFCNB_Timeout = seconds;
+
+    if (RFCNB_Timeout > 0) {	/* Set up handler to ignore but not restart */
+
+#if HAVE_SIGACTION
+	inact.sa_handler = (void (*)()) rfcnb_alarm;
+	sigemptyset(&inact.sa_mask);
+	inact.sa_flags = 0;	/* Don't restart */
+
+	if (sigaction(SIGALRM, &inact, &outact) < 0)
+	    return (-1);
+#else
+	invec.sv_handler = (void (*)()) rfcnb_alarm;
+	invec.sv_mask = 0;
+	invec.sv_flags = SV_INTERRUPT;
+
+	if (sigvec(SIGALRM, &invec, &outvec) < 0)
+	    return (-1);
+#endif
+
+    }
+    return (0);
+
+}
+
+/* Discard the rest of an incoming packet as we do not have space for it
+ * in the buffer we allocated or were passed ...                         */
+
+int
+RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
+{
+    char temp[100];		/* Read into here */
+    int rest, this_read, bytes_read;
+
+    /* len is the amount we should read */
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Discard_Rest called to discard: %i\n", len);
+#endif
+
+    rest = len;
+
+    while (rest > 0) {
+
+	this_read = (rest > sizeof(temp) ? sizeof(temp) : rest);
+
+	bytes_read = read(con->fd, temp, this_read);
+
+	if (bytes_read <= 0) {	/* Error so return */
+
+	    if (bytes_read < 0)
+		RFCNB_errno = RFCNBE_BadRead;
+	    else
+		RFCNB_errno = RFCNBE_ConGone;
+
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	}
+	rest = rest - bytes_read;
+
+    }
+
+    return (0);
+
+}
+
+
+/* Send an RFCNB packet to the connection.
+ * 
+ * We just send each of the blocks linked together ... 
+ * 
+ * If we can, try to send it as one iovec ... 
+ * 
+ */
+
+int
+RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+{
+    int len_sent, tot_sent, this_len;
+    struct RFCNB_Pkt *pkt_ptr;
+    char *this_data;
+    int i;
+    struct iovec io_list[10];	/* We should never have more      */
+    /* If we do, this will blow up ... */
+
+    /* Try to send the data ... We only send as many bytes as len claims */
+    /* We should try to stuff it into an IOVEC and send as one write     */
+
+
+    pkt_ptr = pkt;
+    len_sent = tot_sent = 0;	/* Nothing sent so far */
+    i = 0;
+
+    while ((pkt_ptr != NULL) & (i < 10)) {	/* Watch that magic number! */
+
+	this_len = pkt_ptr->len;
+	this_data = pkt_ptr->data;
+	if ((tot_sent + this_len) > len)
+	    this_len = len - tot_sent;	/* Adjust so we don't send too much */
+
+	/* Now plug into the iovec ... */
+
+	io_list[i].iov_len = this_len;
+	io_list[i].iov_base = this_data;
+	i++;
+
+	tot_sent += this_len;
+
+	if (tot_sent == len)
+	    break;		/* Let's not send too much */
+
+	pkt_ptr = pkt_ptr->next;
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent);
+#endif
+
+    /* Set up an alarm if timeouts are set ... */
+
+    if (RFCNB_Timeout > 0)
+	alarm(RFCNB_Timeout);
+
+    if ((len_sent = writev(con->fd, io_list, i)) < 0) {		/* An error */
+
+	con->rfc_errno = errno;
+	if (errno == EINTR)	/* We were interrupted ... */
+	    RFCNB_errno = RFCNBE_Timeout;
+	else
+	    RFCNB_errno = RFCNBE_BadWrite;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+
+    }
+    if (len_sent < tot_sent) {	/* Less than we wanted */
+	if (errno == EINTR)	/* We were interrupted */
+	    RFCNB_errno = RFCNBE_Timeout;
+	else
+	    RFCNB_errno = RFCNBE_BadWrite;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+    }
+    if (RFCNB_Timeout > 0)
+	alarm(0);		/* Reset that sucker */
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Len sent = %i ...\n", len_sent);
+    RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent);	/* Print what send ... */
+
+#endif
+
+    return (len_sent);
+
+}
+
+/* Read an RFCNB packet off the connection. 
+ * 
+ * We read the first 4 bytes, that tells us the length, then read the
+ * rest. We should implement a timeout, but we don't just yet 
+ * 
+ */
+
+
+int
+RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+{
+    int read_len, pkt_len;
+    char hdr[RFCNB_Pkt_Hdr_Len];	/* Local space for the header */
+    struct RFCNB_Pkt *pkt_frag;
+    int more, this_time, offset, frag_len, this_len;
+    BOOL seen_keep_alive = TRUE;
+
+    /* Read that header straight into the buffer */
+
+    if (len < RFCNB_Pkt_Hdr_Len) {	/* What a bozo */
+
+#ifdef RFCNB_DEBUG
+	fprintf(stderr, "Trying to read less than a packet:");
+	perror("");
+#endif
+	RFCNB_errno = RFCNBE_BadParam;
+	return (RFCNBE_Bad);
+
+    }
+    /* We discard keep alives here ... */
+
+    if (RFCNB_Timeout > 0)
+	alarm(RFCNB_Timeout);
+
+    while (seen_keep_alive) {
+
+	if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) {		/* Problems */
+#ifdef RFCNB_DEBUG
+	    fprintf(stderr, "Reading the packet, we got:");
+	    perror("");
+#endif
+	    if (errno == EINTR)
+		RFCNB_errno = RFCNBE_Timeout;
+	    else
+		RFCNB_errno = RFCNBE_BadRead;
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	}
+	/* Now we check out what we got */
+
+	if (read_len == 0) {	/* Connection closed, send back eof?  */
+
+#ifdef RFCNB_DEBUG
+	    fprintf(stderr, "Connection closed reading\n");
+#endif
+
+	    if (errno == EINTR)
+		RFCNB_errno = RFCNBE_Timeout;
+	    else
+		RFCNB_errno = RFCNBE_ConGone;
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	}
+	if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) {
+
+#ifdef RFCNB_DEBUG
+	    fprintf(stderr, "RFCNB KEEP ALIVE received\n");
+#endif
+
+	} else {
+	    seen_keep_alive = FALSE;
+	}
+
+    }
+
+    /* What if we got less than or equal to a hdr size in bytes? */
+
+    if (read_len < sizeof(hdr)) {	/* We got a small packet */
+
+	/* Now we need to copy the hdr portion we got into the supplied packet */
+
+	memcpy(pkt->data, hdr, read_len);	/*Copy data */
+
+#ifdef RFCNB_DEBUG
+	RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
+#endif
+
+	return (read_len);
+
+    }
+    /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
+
+    pkt_len = RFCNB_Pkt_Len(hdr);
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len);
+#endif
+
+    /* Now copy in the hdr */
+
+    memcpy(pkt->data, hdr, sizeof(hdr));
+
+    /* Get the rest of the packet ... first figure out how big our buf is? */
+    /* And make sure that we handle the fragments properly ... Sure should */
+    /* use an iovec ...                                                    */
+
+    if (len < pkt_len)		/* Only get as much as we have space for */
+	more = len - RFCNB_Pkt_Hdr_Len;
+    else
+	more = pkt_len;
+
+    this_time = 0;
+
+    /* We read for each fragment ... */
+
+    if (pkt->len == read_len) {	/* If this frag was exact size */
+	pkt_frag = pkt->next;	/* Stick next lot in next frag */
+	offset = 0;		/* then we start at 0 in next  */
+    } else {
+	pkt_frag = pkt;		/* Otherwise use rest of this frag */
+	offset = RFCNB_Pkt_Hdr_Len;	/* Otherwise skip the header       */
+    }
+
+    frag_len = pkt_frag->len;
+
+    if (more <= frag_len)	/* If len left to get less than frag space */
+	this_len = more;	/* Get the rest ...                        */
+    else
+	this_len = frag_len - offset;
+
+    while (more > 0) {
+
+	if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) {	/* Problems */
+
+	    if (errno == EINTR) {
+
+		RFCNB_errno = RFCNB_Timeout;
+
+	    } else {
+		if (this_time < 0)
+		    RFCNB_errno = RFCNBE_BadRead;
+		else
+		    RFCNB_errno = RFCNBE_ConGone;
+	    }
+
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	}
+#ifdef RFCNB_DEBUG
+	fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len,
+	    this_time, this_len, more);
+#endif
+
+	read_len = read_len + this_time;	/* How much have we read ... */
+
+	/* Now set up the next part */
+
+	if (pkt_frag->next == NULL)
+	    break;		/* That's it here */
+
+	pkt_frag = pkt_frag->next;
+	this_len = pkt_frag->len;
+	offset = 0;
+
+	more = more - this_time;
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
+    RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
+#endif
+
+    if (read_len < (pkt_len + sizeof(hdr))) {	/* Discard the rest */
+
+	return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
+
+    }
+    if (RFCNB_Timeout > 0)
+	alarm(0);		/* Reset that sucker */
+
+    return (read_len + sizeof(RFCNB_Hdr));
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.h	Tue Sep  3 10:42:38 2002
@@ -0,0 +1,30 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB IO Routines Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
+
+int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
+
+void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt);
Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-priv.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-priv.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-priv.h	Tue Sep  3 10:42:39 2002
@@ -0,0 +1,156 @@
+#ifndef __RFCNB_H__
+#define __RFCNB_H__
+
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Defines we need */
+
+typedef unsigned short uint16;
+
+#define GLOBAL extern
+
+#include "rfcnb-error.h"
+#include "rfcnb-common.h"
+#include "byteorder.h"
+
+#ifdef RFCNB_PORT
+#define RFCNB_Default_Port RFCNB_PORT
+#else
+#define RFCNB_Default_Port 139
+#endif
+
+#define RFCNB_MAX_STATS 1
+
+/* Protocol defines we need */
+
+#define RFCNB_SESSION_MESSAGE 0
+#define RFCNB_SESSION_REQUEST 0x81
+#define RFCNB_SESSION_ACK 0x82
+#define RFCNB_SESSION_REJ 0x83
+#define RFCNB_SESSION_RETARGET 0x84
+#define RFCNB_SESSION_KEEP_ALIVE 0x85
+
+/* Structures      */
+
+typedef struct redirect_addr *redirect_ptr;
+
+struct redirect_addr {
+
+    struct in_addr ip_addr;
+    int port;
+    redirect_ptr next;
+
+};
+
+typedef struct RFCNB_Con {
+
+    int fd;			/* File descripter for TCP/IP connection */
+    int rfc_errno;		/* last error                            */
+    int timeout;		/* How many milli-secs before IO times out */
+    int redirects;		/* How many times we were redirected     */
+    struct redirect_addr *redirect_list;	/* First is first address */
+    struct redirect_addr *last_addr;
+
+} RFCNB_Con;
+
+typedef char RFCNB_Hdr[4];	/* The header is 4 bytes long with  */
+				    /* char[0] as the type, char[1] the */
+				    /* flags, and char[2..3] the length */
+
+/* Macros to extract things from the header. These are for portability
+ * between architecture types where we are worried about byte order     */
+
+#define RFCNB_Pkt_Hdr_Len        4
+#define RFCNB_Pkt_Sess_Len       72
+#define RFCNB_Pkt_Retarg_Len     10
+#define RFCNB_Pkt_Nack_Len       5
+#define RFCNB_Pkt_Type_Offset    0
+#define RFCNB_Pkt_Flags_Offset   1
+#define RFCNB_Pkt_Len_Offset     2	/* Length is 2 bytes plus a flag bit */
+#define RFCNB_Pkt_N1Len_Offset   4
+#define RFCNB_Pkt_Called_Offset  5
+#define RFCNB_Pkt_N2Len_Offset   38
+#define RFCNB_Pkt_Calling_Offset 39
+#define RFCNB_Pkt_Error_Offset   4
+#define RFCNB_Pkt_IP_Offset      4
+#define RFCNB_Pkt_Port_Offset    8
+
+/* The next macro isolates the length of a packet, including the bit in the
+ * flags                                                                   */
+
+#define RFCNB_Pkt_Len(p)  (PVAL(p, 3) | (PVAL(p, 2) << 8) |     \
+                          ((PVAL(p, RFCNB_Pkt_Flags_Offset) & 0x01) << 16))
+
+#define RFCNB_Put_Pkt_Len(p, v) (p[1] = (((v) >> 16) & 1)); \
+				(p[2] = (((v) >> 8) & 0xFF)); \
+				(p[3] = ((v) & 0xFF));
+
+#define RFCNB_Pkt_Type(p) (CVAL(p, RFCNB_Pkt_Type_Offset))
+
+/*typedef struct RFCNB_Hdr {
+ * 
+ * unsigned char type;
+ * unsigned char flags;
+ * int16 len;
+ * 
+ * } RFCNB_Hdr;
+ * 
+ * typedef struct RFCNB_Sess_Pkt {
+ * unsigned char type;
+ * unsigned char flags;
+ * int16 length;
+ * unsigned char n1_len;
+ * char called_name[33];
+ * unsigned char n2_len;
+ * char calling_name[33];
+ * } RFCNB_Sess_Pkt;
+ * 
+ * 
+ * typedef struct RFCNB_Nack_Pkt {
+ * 
+ * struct RFCNB_Hdr hdr;
+ * unsigned char error;
+ * 
+ * } RFCNB_Nack_Pkt;
+ * 
+ * typedef struct RFCNB_Retarget_Pkt {
+ * 
+ * struct RFCNB_Hdr hdr;
+ * int dest_ip;
+ * unsigned char port;
+ * 
+ * } RFCNB_Redir_Pkt; */
+
+/* Static variables */
+
+/* Only declare this if not defined */
+
+#ifndef RFCNB_ERRNO
+extern int RFCNB_errno;
+extern int RFCNB_saved_errno;	/* Save this from point of error */
+#endif
+
+#endif /* __RFCNB_H__ */
Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.c	Tue Sep  3 10:42:39 2002
@@ -0,0 +1,529 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Utility Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <malloc.h>
+
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+#include <arpa/inet.h>
+
+
+extern void (*Prot_Print_Routine) ();	/* Pointer to protocol print routine */
+
+/* Convert name and pad to 16 chars as needed */
+/* Name 1 is a C string with null termination, name 2 may not be */
+/* If SysName is true, then put a <00> on end, else space>       */
+
+void
+RFCNB_CvtPad_Name(char *name1, char *name2)
+{
+    char c, c1, c2;
+    int i, len;
+
+    len = strlen(name1);
+
+    for (i = 0; i < 16; i++) {
+
+	if (i >= len) {
+
+	    c1 = 'C';
+	    c2 = 'A';		/* CA is a space */
+
+	} else {
+
+	    c = name1[i];
+	    c1 = (char) ((int) c / 16 + (int) 'A');
+	    c2 = (char) ((int) c % 16 + (int) 'A');
+	}
+
+	name2[i * 2] = c1;
+	name2[i * 2 + 1] = c2;
+
+    }
+
+    name2[32] = 0;		/* Put in the nll ... */
+
+}
+
+/* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
+ * Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
+ * to produce the next byte in the name.
+ * 
+ * This routine assumes that AName is 16 bytes long and that NBName has 
+ * space for 32 chars, so be careful ... 
+ * 
+ */
+
+void
+RFCNB_AName_To_NBName(char *AName, char *NBName)
+{
+    char c, c1, c2;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+
+	c = AName[i];
+
+	c1 = (char) ((c >> 4) + 'A');
+	c2 = (char) ((c & 0xF) + 'A');
+
+	NBName[i * 2] = c1;
+	NBName[i * 2 + 1] = c2;
+    }
+
+    NBName[32] = 0;		/* Put in a null */
+
+}
+
+/* Do the reverse of the above ... */
+
+void
+RFCNB_NBName_To_AName(char *NBName, char *AName)
+{
+    char c, c1, c2;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+
+	c1 = NBName[i * 2];
+	c2 = NBName[i * 2 + 1];
+
+	c = (char) (((int) c1 - (int) 'A') * 16 + ((int) c2 - (int) 'A'));
+
+	AName[i] = c;
+
+    }
+
+    AName[i] = 0;		/* Put a null on the end ... */
+
+}
+
+/* Print a string of bytes in HEX etc */
+
+void
+RFCNB_Print_Hex(FILE * fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
+{
+    char c1, c2, outbuf1[33];
+    unsigned char c;
+    int i, j;
+    struct RFCNB_Pkt *pkt_ptr = pkt;
+    static char Hex_List[17] = "0123456789ABCDEF";
+
+    j = 0;
+
+    /* We only want to print as much as sepcified in Len */
+
+    while (pkt_ptr != NULL) {
+
+	for (i = 0;
+	    i < ((Len > (pkt_ptr->len) ? pkt_ptr->len : Len) - Offset);
+	    i++) {
+
+	    c = pkt_ptr->data[i + Offset];
+	    c1 = Hex_List[c >> 4];
+	    c2 = Hex_List[c & 0xF];
+
+	    outbuf1[j++] = c1;
+	    outbuf1[j++] = c2;
+
+	    if (j == 32) {	/* Print and reset */
+		outbuf1[j] = 0;
+		fprintf(fd, "    %s\n", outbuf1);
+		j = 0;
+	    }
+	}
+
+	Offset = 0;
+	Len = Len - pkt_ptr->len;	/* Reduce amount by this much */
+	pkt_ptr = pkt_ptr->next;
+
+    }
+
+    /* Print last lot in the buffer ... */
+
+    if (j > 0) {
+
+	outbuf1[j] = 0;
+	fprintf(fd, "    %s\n", outbuf1);
+
+    }
+    fprintf(fd, "\n");
+
+}
+
+/* Get a packet of size n */
+
+struct RFCNB_Pkt *
+RFCNB_Alloc_Pkt(int n)
+{
+    RFCNB_Pkt *pkt;
+
+    if ((pkt = (struct RFCNB_Pkt *) malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
+
+	RFCNB_errno = RFCNBE_NoSpace;
+	RFCNB_saved_errno = errno;
+	return (NULL);
+
+    }
+    pkt->next = NULL;
+    pkt->len = n;
+
+    if (n == 0)
+	return (pkt);
+
+    if ((pkt->data = (char *) malloc(n)) == NULL) {
+
+	RFCNB_errno = RFCNBE_NoSpace;
+	RFCNB_saved_errno = errno;
+	free(pkt);
+	return (NULL);
+
+    }
+    return (pkt);
+
+}
+
+/* Free up a packet */
+
+void
+RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
+{
+    struct RFCNB_Pkt *pkt_next;
+    char *data_ptr;
+
+    while (pkt != NULL) {
+
+	pkt_next = pkt->next;
+
+	data_ptr = pkt->data;
+
+	if (data_ptr != NULL)
+	    free(data_ptr);
+
+	free(pkt);
+
+	pkt = pkt_next;
+
+    }
+
+}
+
+/* Print an RFCNB packet */
+
+void
+RFCNB_Print_Pkt(FILE * fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
+{
+    char lname[17];
+
+    /* We assume that the first fragment is the RFCNB Header  */
+    /* We should loop through the fragments printing them out */
+
+    fprintf(fd, "RFCNB Pkt %s:", dirn);
+
+    switch (RFCNB_Pkt_Type(pkt->data)) {
+
+    case RFCNB_SESSION_MESSAGE:
+
+	fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt->data));
+	RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
+#ifdef RFCNB_PRINT_DATA
+	    RFCNB_Pkt_Len(pkt->data) - RFCNB_Pkt_Hdr_Len);
+#else
+	    40);
+#endif
+
+	if (Prot_Print_Routine != 0) {	/* Print the rest of the packet */
+
+	    Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
+		RFCNB_Pkt_Len(pkt->data) - RFCNB_Pkt_Hdr_Len);
+
+	}
+	break;
+
+    case RFCNB_SESSION_REQUEST:
+
+	fprintf(fd, "SESSION REQUEST: Length = %i\n",
+	    RFCNB_Pkt_Len(pkt->data));
+	RFCNB_NBName_To_AName((char *) (pkt->data + RFCNB_Pkt_Called_Offset), lname);
+	fprintf(fd, "  Called Name: %s\n", lname);
+	RFCNB_NBName_To_AName((char *) (pkt->data + RFCNB_Pkt_Calling_Offset), lname);
+	fprintf(fd, "  Calling Name: %s\n", lname);
+
+	break;
+
+    case RFCNB_SESSION_ACK:
+
+	fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
+	    RFCNB_Pkt_Len(pkt->data));
+
+	break;
+
+    case RFCNB_SESSION_REJ:
+	fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
+	    RFCNB_Pkt_Len(pkt->data));
+
+	if (RFCNB_Pkt_Len(pkt->data) < 1) {
+	    fprintf(fd, "   Protocol Error, short Reject packet!\n");
+	} else {
+	    fprintf(fd, "   Error = %x\n", CVAL(pkt->data, RFCNB_Pkt_Error_Offset));
+	}
+
+	break;
+
+    case RFCNB_SESSION_RETARGET:
+
+	fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
+	    RFCNB_Pkt_Len(pkt->data));
+
+	/* Print out the IP address etc and the port? */
+
+	break;
+
+    case RFCNB_SESSION_KEEP_ALIVE:
+
+	fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
+	    RFCNB_Pkt_Len(pkt->data));
+	break;
+
+    default:
+
+	break;
+    }
+
+}
+
+/* Resolve a name into an address */
+
+int
+RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
+{
+    int addr;			/* Assumes IP4, 32 bit network addresses */
+    struct hostent *hp;
+
+    /* Use inet_addr to try to convert the address */
+
+    if ((addr = inet_addr(host)) == INADDR_NONE) {	/* Oh well, a good try :-) */
+
+	/* Now try a name look up with gethostbyname */
+
+	if ((hp = gethostbyname(host)) == NULL) {	/* Not in DNS */
+
+	    /* Try NetBIOS name lookup, how the hell do we do that? */
+
+	    RFCNB_errno = RFCNBE_BadName;	/* Is this right? */
+	    RFCNB_saved_errno = errno;
+	    return (RFCNBE_Bad);
+
+	} else {		/* We got a name */
+
+	    memcpy((void *) Dest_IP, (void *) hp->h_addr_list[0], sizeof(struct in_addr));
+
+	}
+    } else {			/* It was an IP address */
+
+	memcpy((void *) Dest_IP, (void *) &addr, sizeof(struct in_addr));
+
+    }
+
+    return 0;
+
+}
+
+/* Disconnect the TCP connection to the server */
+
+int
+RFCNB_Close(int socket)
+{
+
+    close(socket);
+
+    /* If we want to do error recovery, here is where we put it */
+
+    return 0;
+
+}
+
+/* Connect to the server specified in the IP address.
+ * Not sure how to handle socket options etc.         */
+
+int
+RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
+{
+    struct sockaddr_in Socket;
+    int fd;
+
+    /* Create a socket */
+
+    if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {	/* Handle the error */
+
+	RFCNB_errno = RFCNBE_BadSocket;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+    }
+    bzero((char *) &Socket, sizeof(Socket));
+    memcpy((char *) &Socket.sin_addr, (char *) &Dest_IP, sizeof(Dest_IP));
+
+    Socket.sin_port = htons(port);
+    Socket.sin_family = PF_INET;
+
+    /* Now connect to the destination */
+
+    if (connect(fd, (struct sockaddr *) &Socket, sizeof(Socket)) < 0) {		/* Error */
+
+	close(fd);
+	RFCNB_errno = RFCNBE_ConnectFailed;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+    }
+    return (fd);
+
+}
+
+/* handle the details of establishing the RFCNB session with remote 
+ * end 
+ * 
+ */
+
+int
+RFCNB_Session_Req(struct RFCNB_Con *con,
+    char *Called_Name,
+    char *Calling_Name,
+    BOOL * redirect,
+    struct in_addr *Dest_IP,
+    int *port)
+{
+    char *sess_pkt;
+
+    /* Response packet should be no more than 9 bytes, make 16 jic */
+
+    char resp[16];
+    int len;
+    struct RFCNB_Pkt *pkt, res_pkt;
+
+    /* We build and send the session request, then read the response */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
+
+    if (pkt == NULL) {
+
+	return (RFCNBE_Bad);	/* Leave the error that RFCNB_Alloc_Pkt gives) */
+
+    }
+    sess_pkt = pkt->data;	/* Get pointer to packet proper */
+
+    sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
+    RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len - RFCNB_Pkt_Hdr_Len);
+    sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
+    sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
+
+    RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
+    RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
+
+    /* Now send the packet */
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Sending packet: ");
+
+#endif
+
+    if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
+
+	return (RFCNBE_Bad);	/* Should be able to write that lot ... */
+
+    }
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Getting packet.\n");
+
+#endif
+
+    res_pkt.data = resp;
+    res_pkt.len = sizeof(resp);
+    res_pkt.next = NULL;
+
+    if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
+
+	return (RFCNBE_Bad);
+
+    }
+    /* Now analyze the packet ... */
+
+    switch (RFCNB_Pkt_Type(resp)) {
+
+    case RFCNB_SESSION_REJ:	/* Didnt like us ... too bad */
+
+	/* Why did we get rejected ? */
+
+	switch (CVAL(resp, RFCNB_Pkt_Error_Offset)) {
+
+	case 0x80:
+	    RFCNB_errno = RFCNBE_CallRejNLOCN;
+	    break;
+	case 0x81:
+	    RFCNB_errno = RFCNBE_CallRejNLFCN;
+	    break;
+	case 0x82:
+	    RFCNB_errno = RFCNBE_CallRejCNNP;
+	    break;
+	case 0x83:
+	    RFCNB_errno = RFCNBE_CallRejInfRes;
+	    break;
+	case 0x8F:
+	    RFCNB_errno = RFCNBE_CallRejUnSpec;
+	    break;
+	default:
+	    RFCNB_errno = RFCNBE_ProtErr;
+	    break;
+	}
+
+	return (RFCNBE_Bad);
+	break;
+
+    case RFCNB_SESSION_ACK:	/* Got what we wanted ...      */
+
+	return (0);
+	break;
+
+    case RFCNB_SESSION_RETARGET:	/* Go elsewhere                */
+
+	*redirect = TRUE;	/* Copy port and ip addr       */
+
+	memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
+	*port = SVAL(resp, RFCNB_Pkt_Port_Offset);
+
+	return (0);
+	break;
+
+    default:			/* A protocol error */
+
+	RFCNB_errno = RFCNBE_ProtErr;
+	return (RFCNBE_Bad);
+	break;
+    }
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.h	Tue Sep  3 10:42:39 2002
@@ -0,0 +1,52 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Utility Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "std-includes.h"
+
+
+void RFCNB_CvtPad_Name(char *name1, char *name2);
+
+void RFCNB_AName_To_NBName(char *AName, char *NBName);
+
+void RFCNB_NBName_To_AName(char *NBName, char *AName);
+
+void RFCNB_Print_Hex(FILE * fd, struct RFCNB_Pkt *pkt, int Offset, int Len);
+
+struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
+
+void RFCNB_Print_Pkt(FILE * fd, char *dirn, struct RFCNB_Pkt *pkt, int len);
+
+int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP);
+
+int RFCNB_Close(int socket);
+
+int RFCNB_IP_Connect(struct in_addr Dest_IP, int port);
+
+int RFCNB_Session_Req(struct RFCNB_Con *con,
+    char *Called_Name,
+    char *Calling_Name,
+    BOOL * redirect,
+    struct in_addr *Dest_IP,
+    int *port);
Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb.h	Tue Sep  3 10:42:39 2002
@@ -0,0 +1,55 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Error responses */
+
+#include "rfcnb-error.h"
+#include "rfcnb-common.h"
+#include "smblib-priv.h"
+
+/* Defines we need */
+
+#define RFCNB_Default_Port 139
+
+/* Definition of routines we define */
+
+void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
+    int port);
+
+int RFCNB_Send(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
+
+int RFCNB_Recv(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
+
+int RFCNB_Hangup(void *con_Handle);
+
+void *RFCNB_Listen();
+
+void RFCNB_Get_Error(char *buffer, int buf_len);
+
+struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
+
+void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt);
+
+int RFCNB_Set_Sock_NoDelay(void *con_Handle, BOOL yn);
Index: squid/src/auth/ntlm/helpers/SMB/smbval/session.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/session.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:40 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/session.c	Tue Sep  3 10:42:40 2002
@@ -0,0 +1,389 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * Session Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+
+int RFCNB_errno = 0;
+int RFCNB_saved_errno = 0;
+#define RFCNB_ERRNO
+
+#include "std-includes.h"
+#include <netinet/tcp.h>
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+
+/* global data structures */
+
+char *RFCNB_Error_Strings[] =
+{
+
+    "RFCNBE_OK: Routine completed successfully.",
+    "RFCNBE_NoSpace: No space available for a malloc call.",
+    "RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
+    "RFCNBE_BadRead: Read system call returned an error. Check errno.",
+    "RFCNBE_BadWrite: Write system call returned an error. Check errno.",
+    "RFCNBE_ProtErr: A protocol error has occurred.",
+    "RFCNBE_ConGone: Connection dropped during a read or write system call.",
+    "RFCNBE_BadHandle: Bad connection handle passed.",
+    "RFCNBE_BadSocket: Problems creating socket.",
+    "RFCNBE_ConnectFailed: Connection failed. See errno.",
+    "RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
+    "RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
+    "RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
+    "RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
+    "RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
+    "RFCNBE_BadParam: Bad parameters passed to a routine.",
+    "RFCNBE_Timeout: IO Operation timed out ..."
+
+};
+
+int RFCNB_Stats[RFCNB_MAX_STATS];
+
+void (*Prot_Print_Routine) () = NULL;	/* Pointer to print routine */
+
+/* Set up a session with a remote name. We are passed Called_Name as a
+ * string which we convert to a NetBIOS name, ie space terminated, up to
+ * 16 characters only if we need to. If Called_Address is not empty, then
+ * we use it to connect to the remote end, but put in Called_Name ... Called 
+ * Address can be a DNS based name, or a TCP/IP address ...
+ */
+
+void *
+RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
+    int port)
+{
+    struct RFCNB_Con *con;
+    struct in_addr Dest_IP;
+    int Client;
+    BOOL redirect;
+    struct redirect_addr *redir_addr;
+    char *Service_Address;
+
+    /* Now, we really should look up the port in /etc/services ... */
+
+    if (port == 0)
+	port = RFCNB_Default_Port;
+
+    /* Create a connection structure first */
+
+    if ((con = (struct RFCNB_Con *) malloc(sizeof(struct RFCNB_Con))) == NULL) {	/* Error in size */
+
+	RFCNB_errno = RFCNBE_NoSpace;
+	RFCNB_saved_errno = errno;
+	return (NULL);
+
+    }
+    con->fd = -0;		/* no descriptor yet */
+    con->rfc_errno = 0;		/* no error yet */
+    con->timeout = 0;		/* no timeout   */
+    con->redirects = 0;
+    con->redirect_list = NULL;	/* Fix bug still in version 0.50 */
+
+    /* Resolve that name into an IP address */
+
+    Service_Address = Called_Name;
+    if (strcmp(Called_Address, "") != 0) {	/* If the Called Address = "" */
+	Service_Address = Called_Address;
+    }
+    if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) {	/* Error */
+
+	/* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */
+
+	return (NULL);
+
+    }
+    /* Now connect to the remote end */
+
+    redirect = TRUE;		/* Fudge this one so we go once through */
+
+    while (redirect) {		/* Connect and get session info etc */
+
+	redirect = FALSE;	/* Assume all OK */
+
+	/* Build the redirect info. First one is first addr called */
+	/* And tack it onto the list of addresses we called        */
+
+	if ((redir_addr = (struct redirect_addr *) malloc(sizeof(struct redirect_addr))) == NULL) {	/* Could not get space */
+
+	    RFCNB_errno = RFCNBE_NoSpace;
+	    RFCNB_saved_errno = errno;
+	    return (NULL);
+
+	}
+	memcpy((char *) &(redir_addr->ip_addr), (char *) &Dest_IP, sizeof(Dest_IP));
+	redir_addr->port = port;
+	redir_addr->next = NULL;
+
+	if (con->redirect_list == NULL) {	/* Stick on head */
+
+	    con->redirect_list = con->last_addr = redir_addr;
+
+	} else {
+
+	    con->last_addr->next = redir_addr;
+	    con->last_addr = redir_addr;
+
+	}
+
+	/* Now, make that connection */
+
+	if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) {	/* Error */
+
+	    /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */
+
+	    return (NULL);
+
+	}
+	con->fd = Client;
+
+	/* Now send and handle the RFCNB session request              */
+	/* If we get a redirect, we will comeback with redirect true 
+	 * and a new IP address in DEST_IP                            */
+
+	if ((errno = RFCNB_Session_Req(con,
+		    Called_Name,
+		    Calling_Name,
+		    &redirect, &Dest_IP, &port)) < 0) {
+
+	    /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */
+
+	    return (NULL);
+
+	}
+	if (redirect) {
+
+	    /* We have to close the connection, and then try again */
+
+	    (con->redirects)++;
+
+	    RFCNB_Close(con->fd);	/* Close it */
+
+	}
+    }
+
+    return (con);
+
+}
+
+/* We send a packet to the other end ... for the moment, we treat the 
+ * data as a series of pointers to blocks of data ... we should check the
+ * length ... */
+
+int
+RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length)
+{
+    struct RFCNB_Pkt *pkt;
+    char *hdr;
+    int len;
+
+    /* Plug in the header and send the data */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
+
+    if (pkt == NULL) {
+
+	RFCNB_errno = RFCNBE_NoSpace;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+
+    }
+    pkt->next = udata;		/* The user data we want to send */
+
+    hdr = pkt->data;
+
+    /* Following crap is for portability across multiple UNIX machines */
+
+    *(hdr + RFCNB_Pkt_Type_Offset) = RFCNB_SESSION_MESSAGE;
+    RFCNB_Put_Pkt_Len(hdr, Length);
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Sending packet: ");
+
+#endif
+
+    if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
+
+	/* No need to change RFCNB_errno as it was done by put_pkt ...     */
+
+	return (RFCNBE_Bad);	/* Should be able to write that lot ... */
+
+    }
+    /* Now we have sent that lot, let's get rid of the RFCNB Header and return */
+
+    pkt->next = NULL;
+
+    RFCNB_Free_Pkt(pkt);
+
+    return (len);
+
+}
+
+/* We pick up a message from the internet ... We have to worry about 
+ * non-message packets ...                                           */
+
+int
+RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length)
+{
+    struct RFCNB_Pkt *pkt;
+    int ret_len;
+
+    if (con_Handle == NULL) {
+
+	RFCNB_errno = RFCNBE_BadHandle;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+
+    }
+    /* Now get a packet from below. We allocate a header first */
+
+    /* Plug in the header and send the data */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
+
+    if (pkt == NULL) {
+
+	RFCNB_errno = RFCNBE_NoSpace;
+	RFCNB_saved_errno = errno;
+	return (RFCNBE_Bad);
+
+    }
+    pkt->next = Data;		/* Plug in the data portion */
+
+    if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
+
+#ifdef RFCNB_DEBUG
+	fprintf(stderr, "Bad packet return in RFCNB_Recv... \n");
+#endif
+
+	return (RFCNBE_Bad);
+
+    }
+    /* We should check that we go a message and not a keep alive */
+
+    pkt->next = NULL;
+
+    RFCNB_Free_Pkt(pkt);
+
+    return (ret_len);
+
+}
+
+/* We just disconnect from the other end, as there is nothing in the RFCNB */
+/* protocol that specifies any exchange as far as I can see                */
+
+int
+RFCNB_Hangup(struct RFCNB_Con *con_Handle)
+{
+
+    if (con_Handle != NULL) {
+	RFCNB_Close(con_Handle->fd);	/* Could this fail? */
+	free(con_Handle);
+    }
+    return 0;
+
+
+}
+
+/* Set TCP_NODELAY on the socket                                          */
+
+int
+RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, BOOL yn)
+{
+
+    return (setsockopt(con_Handle->fd, IPPROTO_TCP, TCP_NODELAY,
+	    (char *) &yn, sizeof(yn)));
+
+}
+
+
+/* Listen for a connection on a port???, when                             */
+/* the connection comes in, we return with the connection                 */
+
+void *
+RFCNB_Listen()
+{
+    fprintf(stderr, "RFCNB_Listen NOT IMPLEMENTED as yet!\n");
+    return NULL;
+}
+
+/* Pick up the last error response as a string, hmmm, this routine should */
+/* have been different ...                                                */
+
+void
+RFCNB_Get_Error(char *buffer, int buf_len)
+{
+
+    if (RFCNB_saved_errno <= 0) {
+	sprintf(buffer, "%s", RFCNB_Error_Strings[RFCNB_errno]);
+    } else {
+	sprintf(buffer, "%s\n\terrno:%s", RFCNB_Error_Strings[RFCNB_errno],
+	    strerror(RFCNB_saved_errno));
+    }
+
+}
+
+/* Pick up the last error response and returns as a code                 */
+
+int
+RFCNB_Get_Last_Error()
+{
+
+    return (RFCNB_errno);
+
+}
+
+/* Pick up saved errno as well */
+
+int
+RFCNB_Get_Last_Errno()
+{
+
+    return (RFCNB_saved_errno);
+
+}
+
+/* Pick up the last error response and return in string ...             */
+
+void
+RFCNB_Get_Error_Msg(int code, char *msg_buf, int len)
+{
+
+    strncpy(msg_buf, RFCNB_Error_Strings[abs(code)], len);
+
+}
+
+/* Register a higher level protocol print routine */
+
+void
+RFCNB_Register_Print_Routine(void (*fn) ())
+{
+
+    Prot_Print_Routine = fn;
+
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.c	Tue Sep  3 10:42:40 2002
@@ -0,0 +1,364 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * 
+ * a partial implementation of DES designed for use in the 
+ * SMB authentication protocol
+ * 
+ * Copyright (C) Andrew Tridgell 1997
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* NOTES: 
+ * 
+ * This code makes no attempt to be fast! In fact, it is a very
+ * slow implementation 
+ * 
+ * This code is NOT a complete DES implementation. It implements only
+ * the minimum necessary for SMB authentication, as used by all SMB
+ * products (including every copy of Microsoft Windows95 ever sold)
+ * 
+ * In particular, it can only do a unchained forward DES pass. This
+ * means it is not possible to use this code for encryption/decryption
+ * of data, instead it is only useful as a "hash" algorithm.
+ * 
+ * There is no entry point into this code that allows normal DES operation.
+ * 
+ * I believe this means that this code does not come under ITAR
+ * regulations but this is NOT a legal opinion. If you are concerned
+ * about the applicability of ITAR regulations to this code then you
+ * should confirm it for yourself (and maybe let me know if you come
+ * up with a different answer to the one above)
+ */
+
+
+
+static int perm1[56] =
+{57, 49, 41, 33, 25, 17, 9,
+    1, 58, 50, 42, 34, 26, 18,
+    10, 2, 59, 51, 43, 35, 27,
+    19, 11, 3, 60, 52, 44, 36,
+    63, 55, 47, 39, 31, 23, 15,
+    7, 62, 54, 46, 38, 30, 22,
+    14, 6, 61, 53, 45, 37, 29,
+    21, 13, 5, 28, 20, 12, 4};
+
+static int perm2[48] =
+{14, 17, 11, 24, 1, 5,
+    3, 28, 15, 6, 21, 10,
+    23, 19, 12, 4, 26, 8,
+    16, 7, 27, 20, 13, 2,
+    41, 52, 31, 37, 47, 55,
+    30, 40, 51, 45, 33, 48,
+    44, 49, 39, 56, 34, 53,
+    46, 42, 50, 36, 29, 32};
+
+static int perm3[64] =
+{58, 50, 42, 34, 26, 18, 10, 2,
+    60, 52, 44, 36, 28, 20, 12, 4,
+    62, 54, 46, 38, 30, 22, 14, 6,
+    64, 56, 48, 40, 32, 24, 16, 8,
+    57, 49, 41, 33, 25, 17, 9, 1,
+    59, 51, 43, 35, 27, 19, 11, 3,
+    61, 53, 45, 37, 29, 21, 13, 5,
+    63, 55, 47, 39, 31, 23, 15, 7};
+
+static int perm4[48] =
+{32, 1, 2, 3, 4, 5,
+    4, 5, 6, 7, 8, 9,
+    8, 9, 10, 11, 12, 13,
+    12, 13, 14, 15, 16, 17,
+    16, 17, 18, 19, 20, 21,
+    20, 21, 22, 23, 24, 25,
+    24, 25, 26, 27, 28, 29,
+    28, 29, 30, 31, 32, 1};
+
+static int perm5[32] =
+{16, 7, 20, 21,
+    29, 12, 28, 17,
+    1, 15, 23, 26,
+    5, 18, 31, 10,
+    2, 8, 24, 14,
+    32, 27, 3, 9,
+    19, 13, 30, 6,
+    22, 11, 4, 25};
+
+
+static int perm6[64] =
+{40, 8, 48, 16, 56, 24, 64, 32,
+    39, 7, 47, 15, 55, 23, 63, 31,
+    38, 6, 46, 14, 54, 22, 62, 30,
+    37, 5, 45, 13, 53, 21, 61, 29,
+    36, 4, 44, 12, 52, 20, 60, 28,
+    35, 3, 43, 11, 51, 19, 59, 27,
+    34, 2, 42, 10, 50, 18, 58, 26,
+    33, 1, 41, 9, 49, 17, 57, 25};
+
+
+static int sc[16] =
+{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static int sbox[8][4][16] =
+{
+    {
+	{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+	{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+	{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+	{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+    {
+	{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+	{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+	{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+	{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+    {
+	{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+	{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+	{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+	{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+    {
+	{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+	{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+	{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+	{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+    {
+	{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+	{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+	{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+	{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+    {
+	{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+	{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+	{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+	{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+    {
+	{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+	{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+	{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+	{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+    {
+	{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+	{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+	{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+	{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
+
+static void
+permute(char *out, char *in, int *p, int n)
+{
+    int i;
+    for (i = 0; i < n; i++)
+	out[i] = in[p[i] - 1];
+}
+
+static void
+lshift(char *d, int count, int n)
+{
+    char out[64];
+    int i;
+    for (i = 0; i < n; i++)
+	out[i] = d[(i + count) % n];
+    for (i = 0; i < n; i++)
+	d[i] = out[i];
+}
+
+static void
+concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+    while (l1--)
+	*out++ = *in1++;
+    while (l2--)
+	*out++ = *in2++;
+}
+
+static void
+xor(char *out, char *in1, char *in2, int n)
+{
+    int i;
+    for (i = 0; i < n; i++)
+	out[i] = in1[i] ^ in2[i];
+}
+
+static void
+dohash(char *out, char *in, char *key)
+{
+    int i, j, k;
+    char pk1[56];
+    char c[28];
+    char d[28];
+    char cd[56];
+    char ki[16][48];
+    char pd1[64];
+    char l[32], r[32];
+    char rl[64];
+
+    permute(pk1, key, perm1, 56);
+
+    for (i = 0; i < 28; i++)
+	c[i] = pk1[i];
+    for (i = 0; i < 28; i++)
+	d[i] = pk1[i + 28];
+
+    for (i = 0; i < 16; i++) {
+	lshift(c, sc[i], 28);
+	lshift(d, sc[i], 28);
+
+	concat(cd, c, d, 28, 28);
+	permute(ki[i], cd, perm2, 48);
+    }
+
+    permute(pd1, in, perm3, 64);
+
+    for (j = 0; j < 32; j++) {
+	l[j] = pd1[j];
+	r[j] = pd1[j + 32];
+    }
+
+    for (i = 0; i < 16; i++) {
+	char er[48];
+	char erk[48];
+	char b[8][6];
+	char cb[32];
+	char pcb[32];
+	char r2[32];
+
+	permute(er, r, perm4, 48);
+
+	xor(erk, er, ki[i], 48);
+
+	for (j = 0; j < 8; j++)
+	    for (k = 0; k < 6; k++)
+		b[j][k] = erk[j * 6 + k];
+
+	for (j = 0; j < 8; j++) {
+	    int m, n;
+	    m = (b[j][0] << 1) | b[j][5];
+
+	    n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << 1) | b[j][4];
+
+	    for (k = 0; k < 4; k++)
+		b[j][k] = (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
+	}
+
+	for (j = 0; j < 8; j++)
+	    for (k = 0; k < 4; k++)
+		cb[j * 4 + k] = b[j][k];
+	permute(pcb, cb, perm5, 32);
+
+	xor(r2, l, pcb, 32);
+
+	for (j = 0; j < 32; j++)
+	    l[j] = r[j];
+
+	for (j = 0; j < 32; j++)
+	    r[j] = r2[j];
+    }
+
+    concat(rl, r, l, 32, 32);
+
+    permute(out, rl, perm6, 64);
+}
+
+static void
+str_to_key(unsigned char *str, unsigned char *key)
+{
+    int i;
+
+    key[0] = str[0] >> 1;
+    key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
+    key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
+    key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
+    key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
+    key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
+    key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
+    key[7] = str[6] & 0x7F;
+    for (i = 0; i < 8; i++) {
+	key[i] = (key[i] << 1);
+    }
+}
+
+
+static void
+smbhash(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    int i;
+    char outb[64];
+    char inb[64];
+    char keyb[64];
+    unsigned char key2[8];
+
+    str_to_key(key, key2);
+
+    for (i = 0; i < 64; i++) {
+	inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+	keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+	outb[i] = 0;
+    }
+
+    dohash(outb, inb, keyb);
+
+    for (i = 0; i < 8; i++) {
+	out[i] = 0;
+    }
+
+    for (i = 0; i < 64; i++) {
+	if (outb[i])
+	    out[i / 8] |= (1 << (7 - (i % 8)));
+    }
+}
+
+void
+E_P16(unsigned char *p14, unsigned char *p16)
+{
+    unsigned char sp8[8] =
+    {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+    smbhash(p16, sp8, p14);
+    smbhash(p16 + 8, sp8, p14 + 7);
+}
+
+void
+E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+{
+    smbhash(p24, c8, p21);
+    smbhash(p24 + 8, c8, p21 + 7);
+    smbhash(p24 + 16, c8, p21 + 14);
+}
+
+void
+cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    unsigned char buf[8];
+
+    smbhash(buf, in, key);
+    smbhash(out, buf, key + 9);
+}
+
+void
+cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    unsigned char buf[8];
+    static unsigned char key2[8];
+
+    smbhash(buf, in, key);
+    key2[0] = key[7];
+    smbhash(out, buf, key2);
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.h	Tue Sep  3 10:42:40 2002
@@ -0,0 +1,2 @@
+void E_P16(unsigned char *p14, unsigned char *p16);
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.c	Tue Sep  3 10:42:40 2002
@@ -0,0 +1,207 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1997
+ * Modified by Jeremy Allison 1995.
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "std-includes.h"
+#include <string.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "smblib-priv.h"
+#include "md4.h"
+#include "smbdes.h"
+#define uchar unsigned char
+extern int DEBUGLEVEL;
+
+#include "byteorder.h"
+
+char *StrnCpy(char *dest, char *src, int n);
+void strupper(char *s);
+
+/*
+ * This implements the X/Open SMB password encryption
+ * It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
+ * encrypted password into p24 */
+void
+SMBencrypt(uchar * passwd, uchar * c8, uchar * p24)
+{
+    uchar p14[15], p21[21];
+
+    memset(p21, '\0', 21);
+    memset(p14, '\0', 14);
+    StrnCpy((char *) p14, (char *) passwd, 14);
+
+    strupper((char *) p14);
+    E_P16(p14, p21);
+    E_P24(p21, c8, p24);
+}
+
+/* Routines for Windows NT MD4 Hash functions. */
+static int
+_my_wcslen(int16 * str)
+{
+    int len = 0;
+    while (*str++ != 0)
+	len++;
+    return len;
+}
+
+/*
+ * Convert a string into an NT UNICODE string.
+ * Note that regardless of processor type 
+ * this must be in intel (little-endian)
+ * format.
+ */
+
+static int
+_my_mbstowcs(int16 * dst, uchar * src, int len)
+{
+    int i;
+    int16 val;
+
+    for (i = 0; i < len; i++) {
+	val = *src;
+	SSVAL(dst, 0, val);
+	dst++;
+	src++;
+	if (val == 0)
+	    break;
+    }
+    return i;
+}
+
+/* 
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ */
+
+void
+E_md4hash(uchar * passwd, uchar * p16)
+{
+    int len;
+    int16 wpwd[129];
+
+    /* Password cannot be longer than 128 characters */
+    len = strlen((char *) passwd);
+    if (len > 128)
+	len = 128;
+    /* Password must be converted to NT unicode */
+    _my_mbstowcs(wpwd, passwd, len);
+    wpwd[len] = 0;		/* Ensure string is null terminated */
+    /* Calculate length in bytes */
+    len = _my_wcslen(wpwd) * sizeof(int16);
+
+    mdfour(p16, (unsigned char *) wpwd, len);
+}
+
+/* Does the NT MD4 hash then des encryption. */
+
+void
+SMBNTencrypt(uchar * passwd, uchar * c8, uchar * p24)
+{
+    uchar p21[21];
+
+    memset(p21, '\0', 21);
+
+    E_md4hash(passwd, p21);
+    E_P24(p21, c8, p24);
+}
+
+/* Does both the NT and LM owfs of a user's password */
+
+void
+nt_lm_owf_gen(char *pwd, char *nt_p16, char *p16)
+{
+    char passwd[130];
+    StrnCpy(passwd, pwd, sizeof(passwd) - 1);
+
+    /* Calculate the MD4 hash (NT compatible) of the password */
+    memset(nt_p16, '\0', 16);
+    E_md4hash((uchar *) passwd, (uchar *) nt_p16);
+
+    /* Mangle the passwords into Lanman format */
+    passwd[14] = '\0';
+    strupper(passwd);
+
+    /* Calculate the SMB (lanman) hash functions of the password */
+
+    memset(p16, '\0', 16);
+    E_P16((uchar *) passwd, (uchar *) p16);
+
+    /* clear out local copy of user's password (just being paranoid). */
+    bzero(passwd, sizeof(passwd));
+}
+
+/****************************************************************************
+line strncpy but always null terminates. Make sure there is room!
+****************************************************************************/
+char *
+StrnCpy(char *dest, char *src, int n)
+{
+    char *d = dest;
+    if (!dest)
+	return (NULL);
+    if (!src) {
+	*dest = 0;
+	return (dest);
+    }
+    while (n-- && (*d++ = *src++));
+    *d = 0;
+    return (dest);
+}
+
+void
+strupper(char *s)
+{
+    while (*s) {
+	/*
+	 * #if !defined(KANJI_WIN95_COMPATIBILITY)
+	 * if(lp_client_code_page() == KANJI_CODEPAGE)
+	 * {
+	 * 
+	 * if (is_shift_jis (*s))
+	 * {
+	 * if (is_sj_lower (s[0], s[1]))
+	 * s[1] = sj_toupper2 (s[1]);
+	 * s += 2;
+	 * }
+	 * else if (is_kana (*s))
+	 * {
+	 * s++;
+	 * }
+	 * else
+	 * {
+	 * if (islower(*s))                           
+	 * *s = toupper(*s);
+	 * s++;
+	 * }
+	 * }
+	 * else
+	 * #endif *//* KANJI_WIN95_COMPATIBILITY */
+	{
+	    if (islower(*s))
+		*s = toupper(*s);
+	    s++;
+	}
+    }
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.h	Tue Sep  3 10:42:40 2002
@@ -0,0 +1,3 @@
+void SMBencrypt(uchar * passwd, uchar * c8, uchar * p24);
+void SMBNTencrypt(uchar * passwd, uchar * c8, uchar * p24);
+
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib-common.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib-common.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib-common.h	Tue Sep  3 10:42:41 2002
@@ -0,0 +1,189 @@
+#ifndef __SMBLIB_COMMON_H__
+#define __SMBLIB_COMMON_H__
+
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Common Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* To get the error class we want the first 8 bits */
+/* Because we just grab 4bytes from the SMB header, we have to re-order */
+/* here, but it makes the NtStatus part easier in future                */
+
+#define SMBlib_Error_Class(p) (p & 0x000000FF)
+
+/* To get the error code, we want the bottom 16 bits */
+
+#define SMBlib_Error_Code(p) (((unsigned int)p & 0xFFFF0000) >>16)
+
+/* Error CLASS codes and etc ... */
+
+#define SMBC_SUCCESS        0
+#define SMBC_ERRDOS         0x01
+#define SMBC_ERRSRV         0x02
+#define SMBC_ERRHRD         0x03
+#define SMBC_ERRCMD         0xFF
+
+/* Success error codes    */
+
+#define SMBS_BUFFERED       0x54
+#define SMBS_LOGGED         0x55
+#define SMBS_DISPLAYED      0x56
+
+/* ERRDOS Error codes     */
+
+#define SMBD_badfunc        0x01
+#define SMBD_badfile        0x02
+#define SMBD_badpath        0x03
+#define SMBD_nofids         0x04
+#define SMBD_noaccess       0x05
+#define SMBD_badfid         0x06
+#define SMBD_badmcb         0x07
+#define SMBD_nomem          0x08
+#define SMBD_badmem         0x09
+#define SMBD_badenv         0x0A
+#define SMBD_badformat      0x0B
+#define SMBD_badaccess      0x0C
+#define SMBD_baddata        0x0D
+#define SMBD_reserved       0x0E
+#define SMBD_baddrive       0x0F
+#define SMBD_remcd          0x10
+#define SMBD_diffdevice     0x11
+#define SMBD_nofiles        0x12
+#define SMBD_badshare       0x20
+#define SMBD_errlock        0x21
+#define SMBD_filexists      0x50
+
+/* Server errors ... */
+
+#define SMBV_error          0x01	/* Generic error */
+#define SMBV_badpw          0x02
+#define SMBV_badtype        0x03
+#define SMBV_access         0x04
+#define SMBV_invnid         0x05
+#define SMBV_invnetname     0x06
+#define SMBV_invdevice      0x07
+#define SMBV_qfull          0x31
+#define SMBV_qtoobig        0x32
+#define SMBV_qeof           0x33
+#define SMBV_invpfid        0x34
+#define SMBV_paused         0x51
+#define SMBV_msgoff         0x52
+#define SMBV_noroom         0x53
+#define SMBV_rmuns          0x57
+#define SMBV_nosupport      0xFFFF
+
+/* Hardware error codes ... */
+
+#define SMBH_nowrite        0x13
+#define SMBH_badunit        0x14
+#define SMBH_notready       0x15
+#define SMBH_badcmd         0x16
+#define SMBH_data           0x17
+#define SMBH_badreq         0x18
+#define SMBH_seek           0x19
+#define SMBH_badmedia       0x1A
+#define SMBH_badsector      0x1B
+#define SMBH_nopaper        0x1C
+#define SMBH_write          0x1D
+#define SMBH_read           0x1E
+#define SMBH_general        0x1F
+#define SMBH_badshare       0x20
+
+/* Access mode defines ... */
+
+#define SMB_AMODE_WTRU      0x4000
+#define SMB_AMODE_NOCACHE   0x1000
+#define SMB_AMODE_COMPAT    0x0000
+#define SMB_AMODE_DENYRWX   0x0010
+#define SMB_AMODE_DENYW     0x0020
+#define SMB_AMODE_DENYRX    0x0030
+#define SMB_AMODE_DENYNONE  0x0040
+#define SMB_AMODE_OPENR     0x0000
+#define SMB_AMODE_OPENW     0x0001
+#define SMB_AMODE_OPENRW    0x0002
+#define SMB_AMODE_OPENX     0x0003
+#define SMB_AMODE_FCBOPEN   0x00FF
+#define SMB_AMODE_LOCUNKN   0x0000
+#define SMB_AMODE_LOCMSEQ   0x0100
+#define SMB_AMODE_LOCMRAN   0x0200
+#define SMB_AMODE_LOCRAL    0x0300
+
+/* File attribute encoding ... */
+
+#define SMB_FA_ORD          0x00
+#define SMB_FA_ROF          0x01
+#define SMB_FA_HID          0x02
+#define SMB_FA_SYS          0x04
+#define SMB_FA_VOL          0x08
+#define SMB_FA_DIR          0x10
+#define SMB_FA_ARC          0x20
+
+/* Define the protocol types ... */
+
+#define SMB_P_Unknown      -1	/* Hmmm, is this smart? */
+#define SMB_P_Core         0
+#define SMB_P_CorePlus     1
+#define SMB_P_DOSLanMan1   2
+#define SMB_P_LanMan1      3
+#define SMB_P_DOSLanMan2   4
+#define SMB_P_LanMan2      5
+#define SMB_P_DOSLanMan2_1 6
+#define SMB_P_LanMan2_1    7
+#define SMB_P_NT1          8
+
+/* SMBlib return codes */
+/* We want something that indicates whether or not the return code was a   */
+/* remote error, a local error in SMBlib or returned from lower layer ...  */
+/* Wonder if this will work ...                                            */
+/* SMBlibE_Remote = 1 indicates remote error                               */
+/* SMBlibE_ values < 0 indicate local error with more info available       */
+/* SMBlibE_ values >1 indicate local from SMBlib code errors?              */
+
+#define SMBlibE_Success 0
+#define SMBlibE_Remote  1	/* Remote error, get more info from con        */
+#define SMBlibE_BAD     -1
+#define SMBlibE_LowerLayer 2	/* Lower layer error                           */
+#define SMBlibE_NotImpl 3	/* Function not yet implemented                */
+#define SMBlibE_ProtLow 4	/* Protocol negotiated does not support req    */
+#define SMBlibE_NoSpace 5	/* No space to allocate a structure            */
+#define SMBlibE_BadParam 6	/* Bad parameters                              */
+#define SMBlibE_NegNoProt 7	/* None of our protocols was liked             */
+#define SMBlibE_SendFailed 8	/* Sending an SMB failed                       */
+#define SMBlibE_RecvFailed 9	/* Receiving an SMB failed                     */
+#define SMBlibE_GuestOnly 10	/* Logged in as guest                          */
+#define SMBlibE_CallFailed 11	/* Call remote end failed                     */
+#define SMBlibE_ProtUnknown 12	/* Protocol unknown                          */
+#define SMBlibE_NoSuchMsg  13	/* Keep this up to date                       */
+
+typedef struct {		/* A structure for a Dirent */
+
+    unsigned char resume_key[21];	/* Don't touch this          */
+    unsigned char file_attributes;	/* Attributes of file        */
+    unsigned int date_time;	/* date and time of last mod */
+    unsigned int size;
+    char filename[13];		/* The name of the file      */
+
+} SMB_CP_dirent;
+
+#endif /* __SMBLIB_COMMON_H__ */
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib-priv.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib-priv.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib-priv.h	Tue Sep  3 10:42:41 2002
@@ -0,0 +1,651 @@
+#ifndef __SMBLIB_PRIV_H__
+#define __SMBLIB_PRIV_H__
+
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib private Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "std-defines.h"
+#include "smblib-common.h"
+#include <unistd.h>
+
+#include "byteorder.h"		/* Hmmm ... hot good */
+
+#define max(a,b) (a < b ? b : a)
+
+#define SMB_DEF_IDF 0x424D53FF	/* "\377SMB" */
+
+/* Core protocol commands */
+
+#define SMBmkdir      0x00	/* create directory */
+#define SMBrmdir      0x01	/* delete directory */
+#define SMBopen       0x02	/* open file */
+#define SMBcreate     0x03	/* create file */
+#define SMBclose      0x04	/* close file */
+#define SMBflush      0x05	/* flush file */
+#define SMBunlink     0x06	/* delete file */
+#define SMBmv         0x07	/* rename file */
+#define SMBgetatr     0x08	/* get file attributes */
+#define SMBsetatr     0x09	/* set file attributes */
+#define SMBread       0x0A	/* read from file */
+#define SMBwrite      0x0B	/* write to file */
+#define SMBlock       0x0C	/* lock byte range */
+#define SMBunlock     0x0D	/* unlock byte range */
+#define SMBctemp      0x0E	/* create temporary file */
+#define SMBmknew      0x0F	/* make new file */
+#define SMBchkpth     0x10	/* check directory path */
+#define SMBexit       0x11	/* process exit */
+#define SMBlseek      0x12	/* seek */
+#define SMBtcon       0x70	/* tree connect */
+#define SMBtdis       0x71	/* tree disconnect */
+#define SMBnegprot    0x72	/* negotiate protocol */
+#define SMBdskattr    0x80	/* get disk attributes */
+#define SMBsearch     0x81	/* search directory */
+#define SMBsplopen    0xC0	/* open print spool file */
+#define SMBsplwr      0xC1	/* write to print spool file */
+#define SMBsplclose   0xC2	/* close print spool file */
+#define SMBsplretq    0xC3	/* return print queue */
+#define SMBsends      0xD0	/* send single block message */
+#define SMBsendb      0xD1	/* send broadcast message */
+#define SMBfwdname    0xD2	/* forward user name */
+#define SMBcancelf    0xD3	/* cancel forward */
+#define SMBgetmac     0xD4	/* get machine name */
+#define SMBsendstrt   0xD5	/* send start of multi-block message */
+#define SMBsendend    0xD6	/* send end of multi-block message */
+#define SMBsendtxt    0xD7	/* send text of multi-block message */
+
+/* CorePlus protocol                                        */
+
+#define SMBlockread   0x13	/* Lock a range and read it */
+#define SMBwriteunlock 0x14	/* Unlock a range and then write */
+#define SMBreadbraw   0x1a	/* read a block of data without smb header ohead */
+#define SMBwritebraw  0x1d	/* write a block of data without smb header ohead */
+#define SMBwritec     0x20	/* secondary write request */
+#define SMBwriteclose 0x2c	/* write a file and then close it */
+
+/* DOS Extended Protocol                                    */
+
+#define SMBreadBraw      0x1A	/* read block raw */
+#define SMBreadBmpx      0x1B	/* read block multiplexed */
+#define SMBreadBs        0x1C	/* read block (secondary response) */
+#define SMBwriteBraw     0x1D	/* write block raw */
+#define SMBwriteBmpx     0x1E	/* write block multiplexed */
+#define SMBwriteBs       0x1F	/* write block (secondary request) */
+#define SMBwriteC        0x20	/* write complete response */
+#define SMBsetattrE      0x22	/* set file attributes expanded */
+#define SMBgetattrE      0x23	/* get file attributes expanded */
+#define SMBlockingX      0x24	/* lock/unlock byte ranges and X */
+#define SMBtrans         0x25	/* transaction - name, bytes in/out */
+#define SMBtranss        0x26	/* transaction (secondary request/response) */
+#define SMBioctl         0x27	/* IOCTL */
+#define SMBioctls        0x28	/* IOCTL  (secondary request/response) */
+#define SMBcopy          0x29	/* copy */
+#define SMBmove          0x2A	/* move */
+#define SMBecho          0x2B	/* echo */
+#define SMBopenX         0x2D	/* open and X */
+#define SMBreadX         0x2E	/* read and X */
+#define SMBwriteX        0x2F	/* write and X */
+#define SMBsesssetupX    0x73	/* Session Set Up & X (including User Logon) */
+#define SMBtconX         0x75	/* tree connect and X */
+#define SMBffirst        0x82	/* find first */
+#define SMBfunique       0x83	/* find unique */
+#define SMBfclose        0x84	/* find close */
+#define SMBinvalid       0xFE	/* invalid command */
+
+/* Any more ? */
+
+#define SMBdatablockID     0x01	/* A data block identifier */
+#define SMBdialectID       0x02	/* A dialect id            */
+#define SMBpathnameID      0x03	/* A pathname ID           */
+#define SMBasciiID         0x04	/* An ascii string ID      */
+#define SMBvariableblockID 0x05	/* A variable block ID     */
+
+/* some other defines we need */
+
+/* Flags defines ... */
+
+#define SMB_FLG2_NON_DOS    0x01	/* We know non dos names             */
+#define SMB_FLG2_EXT_ATR    0x02	/* We know about Extended Attributes */
+#define SMB_FLG2_LNG_NAM    0x04	/* Long names ?                      */
+
+typedef unsigned short WORD;
+typedef unsigned short UWORD;
+typedef unsigned int ULONG;
+typedef unsigned char BYTE;
+typedef unsigned char UCHAR;
+
+/* Some macros to allow access to actual packet data so that we */
+/* can change the underlying representation of packets.         */
+/*                                                              */
+/* The current formats vying for attention are a fragment       */
+/* approach where the SMB header is a fragment linked to the    */
+/* data portion with the transport protocol (rfcnb or whatever) */
+/* being linked on the front.                                   */
+/*                                                              */
+/* The other approach is where the whole packet is one array    */
+/* of bytes with space allowed on the front for the packet      */
+/* headers.                                                     */
+
+#define SMB_Hdr(p) (char *)(p -> data)
+
+/* SMB Hdr def for File Sharing Protocol? From MS and Intel,    */
+/* Intel PN 138446 Doc Version 2.0, Nov 7, 1988. This def also  */
+/* applies to LANMAN1.0 as well as the Core Protocol            */
+/* The spec states that wct and bcc must be present, even if 0  */
+
+/* We define these as offsets into a char SMB[] array for the   */
+/* sake of portability                                          */
+
+/* NOTE!. Some of the lenght defines, SMB_<protreq>_len do not include */
+/* the data that follows in the SMB packet, so the code will have to   */
+/* take that into account.                                             */
+
+#define SMB_hdr_idf_offset    0	/* 0xFF,'SMB' 0-3 */
+#define SMB_hdr_com_offset    4	/* BYTE       4   */
+#define SMB_hdr_rcls_offset   5	/* BYTE       5   */
+#define SMB_hdr_reh_offset    6	/* BYTE       6   */
+#define SMB_hdr_err_offset    7	/* WORD       7   */
+#define SMB_hdr_reb_offset    9	/* BYTE       9   */
+#define SMB_hdr_flg_offset    9	/* same as reb ... */
+#define SMB_hdr_res_offset    10	/* 7 WORDs    10  */
+#define SMB_hdr_res0_offset   10	/* WORD       10  */
+#define SMB_hdr_flg2_offset   10	/* WORD           */
+#define SMB_hdr_res1_offset   12	/* WORD       12  */
+#define SMB_hdr_res2_offset   14
+#define SMB_hdr_res3_offset   16
+#define SMB_hdr_res4_offset   18
+#define SMB_hdr_res5_offset   20
+#define SMB_hdr_res6_offset   22
+#define SMB_hdr_tid_offset    24
+#define SMB_hdr_pid_offset    26
+#define SMB_hdr_uid_offset    28
+#define SMB_hdr_mid_offset    30
+#define SMB_hdr_wct_offset    32
+
+#define SMB_hdr_len           33	/* 33 byte header?      */
+
+#define SMB_hdr_axc_offset    33	/* AndX Command         */
+#define SMB_hdr_axr_offset    34	/* AndX Reserved        */
+#define SMB_hdr_axo_offset    35	/* Offset from start to WCT of AndX cmd */
+
+/* Format of the Negotiate Protocol SMB */
+
+#define SMB_negp_bcc_offset   33
+#define SMB_negp_buf_offset   35	/* Where the buffer starts   */
+#define SMB_negp_len          35	/* plus the data             */
+
+/* Format of the Negotiate Response SMB, for CoreProtocol, LM1.2 and */
+/* NT LM 0.12. wct will be 1 for CoreProtocol, 13 for LM 1.2, and 17 */
+/* for NT LM 0.12                                                    */
+
+#define SMB_negrCP_idx_offset   33	/* Response to the neg req */
+#define SMB_negrCP_bcc_offset   35
+#define SMB_negrLM_idx_offset   33	/* dialect index           */
+#define SMB_negrLM_sec_offset   35	/* Security mode           */
+#define SMB_sec_user_mask       0x01	/* 0 = share, 1 = user     */
+#define SMB_sec_encrypt_mask    0x02	/* pick out encrypt        */
+#define SMB_negrLM_mbs_offset   37	/* max buffer size         */
+#define SMB_negrLM_mmc_offset   39	/* max mpx count           */
+#define SMB_negrLM_mnv_offset   41	/* max number of VCs       */
+#define SMB_negrLM_rm_offset    43	/* raw mode support bit vec */
+#define SMB_read_raw_mask       0x01
+#define SMB_write_raw_mask      0x02
+#define SMB_negrLM_sk_offset    45	/* session key, 32 bits    */
+#define SMB_negrLM_st_offset    49	/* Current server time     */
+#define SMB_negrLM_sd_offset    51	/* Current server date     */
+#define SMB_negrLM_stz_offset   53	/* Server Time Zone        */
+#define SMB_negrLM_ekl_offset   55	/* encryption key length   */
+#define SMB_negrLM_res_offset   57	/* reserved                */
+#define SMB_negrLM_bcc_offset   59	/* bcc                     */
+#define SMB_negrLM_len          61	/* 61 bytes ?              */
+#define SMB_negrLM_buf_offset   61	/* Where the fun begins    */
+
+#define SMB_negrNTLM_idx_offset 33	/* Selected protocol       */
+#define SMB_negrNTLM_sec_offset 35	/* Security more           */
+#define SMB_negrNTLM_mmc_offset 36	/* Different format above  */
+#define SMB_negrNTLM_mnv_offset 38	/* Max VCs                 */
+#define SMB_negrNTLM_mbs_offset 40	/* MBS now a long          */
+#define SMB_negrNTLM_mrs_offset 44	/* Max raw size            */
+#define SMB_negrNTLM_sk_offset  48	/* Session Key             */
+#define SMB_negrNTLM_cap_offset 52	/* Capabilities            */
+#define SMB_negrNTLM_stl_offset 56	/* Server time low         */
+#define SMB_negrNTLM_sth_offset 60	/* Server time high        */
+#define SMB_negrNTLM_stz_offset 64	/* Server time zone        */
+#define SMB_negrNTLM_ekl_offset 66	/* Encrypt key len         */
+#define SMB_negrNTLM_bcc_offset 67	/* Bcc                     */
+#define SMB_negrNTLM_len        69
+#define SMB_negrNTLM_buf_offset 69
+
+/* Offsets related to Tree Connect                                      */
+
+#define SMB_tcon_bcc_offset     33
+#define SMB_tcon_buf_offset     35	/* where the data is for tcon */
+#define SMB_tcon_len            35	/* plus the data              */
+
+#define SMB_tconr_mbs_offset    33	/* max buffer size         */
+#define SMB_tconr_tid_offset    35	/* returned tree id        */
+#define SMB_tconr_bcc_offset    37
+#define SMB_tconr_len           39
+
+#define SMB_tconx_axc_offset    33	/* And X Command                */
+#define SMB_tconx_axr_offset    34	/* reserved                     */
+#define SMB_tconx_axo_offset    35	/* Next command offset          */
+#define SMB_tconx_flg_offset    37	/* Flags, bit0=1 means disc TID */
+#define SMB_tconx_pwl_offset    39	/* Password length              */
+#define SMB_tconx_bcc_offset    41	/* bcc                          */
+#define SMB_tconx_buf_offset    43	/* buffer                       */
+#define SMB_tconx_len           43	/* up to data ...               */
+
+#define SMB_tconxr_axc_offset   33	/* Where the AndX Command is    */
+#define SMB_tconxr_axr_offset   34	/* Reserved                     */
+#define SMB_tconxr_axo_offset   35	/* AndX offset location         */
+
+/* Offsets related to tree_disconnect                                  */
+
+#define SMB_tdis_bcc_offset     33	/* bcc                     */
+#define SMB_tdis_len            35	/* total len               */
+
+#define SMB_tdisr_bcc_offset    33	/* bcc                     */
+#define SMB_tdisr_len           35
+
+/* Offsets related to Open Request                                     */
+
+#define SMB_open_mod_offset     33	/* Mode to open with       */
+#define SMB_open_atr_offset     35	/* Attributes of file      */
+#define SMB_open_bcc_offset     37	/* bcc                     */
+#define SMB_open_buf_offset     39	/* File name               */
+#define SMB_open_len            39	/* Plus the file name      */
+
+#define SMB_openx_axc_offset    33	/* Next command            */
+#define SMB_openx_axr_offset    34	/* Reserved                */
+#define SMB_openx_axo_offset    35	/* offset of next wct      */
+#define SMB_openx_flg_offset    37	/* Flags, bit0 = need more info */
+					  /* bit1 = exclusive oplock */
+					  /* bit2 = batch oplock     */
+#define SMB_openx_mod_offset    39	/* mode to open with       */
+#define SMB_openx_atr_offset    41	/* search attributes       */
+#define SMB_openx_fat_offset    43	/* File attributes         */
+#define SMB_openx_tim_offset    45	/* time and date of creat  */
+#define SMB_openx_ofn_offset    49	/* Open function           */
+#define SMB_openx_als_offset    51	/* Space to allocate on    */
+#define SMB_openx_res_offset    55	/* reserved                */
+#define SMB_openx_bcc_offset    63	/* bcc                     */
+#define SMB_openx_buf_offset    65	/* Where file name goes    */
+#define SMB_openx_len           65
+
+#define SMB_openr_fid_offset    33	/* FID returned            */
+#define SMB_openr_atr_offset    35	/* Attributes opened with  */
+#define SMB_openr_tim_offset    37	/* Last mod time of file   */
+#define SMB_openr_fsz_offset    41	/* File size 4 bytes       */
+#define SMB_openr_acc_offset    45	/* Access allowed          */
+#define SMB_openr_bcc_offset    47
+#define SMB_openr_len           49
+
+#define SMB_openxr_axc_offset   33	/* And X command           */
+#define SMB_openxr_axr_offset   34	/* reserved                */
+#define SMB_openxr_axo_offset   35	/* offset to next command  */
+#define SMB_openxr_fid_offset   37	/* FID returned            */
+#define SMB_openxr_fat_offset   39	/* File attributes returned */
+#define SMB_openxr_tim_offset   41	/* File creation date etc  */
+#define SMB_openxr_fsz_offset   45	/* Size of file            */
+#define SMB_openxr_acc_offset   49	/* Access granted          */
+
+#define SMB_clos_fid_offset     33	/* FID to close            */
+#define SMB_clos_tim_offset     35	/* Last mod time           */
+#define SMB_clos_bcc_offset     39	/* bcc                     */
+#define SMB_clos_len            41
+
+/* Offsets related to Write requests                                 */
+
+#define SMB_write_fid_offset    33	/* FID to write            */
+#define SMB_write_cnt_offset    35	/* bytes to write          */
+#define SMB_write_ofs_offset    37	/* location to write to    */
+#define SMB_write_clf_offset    41	/* advisory count left     */
+#define SMB_write_bcc_offset    43	/* bcc = data bytes + 3    */
+#define SMB_write_buf_offset    45	/* Data=0x01, len, data    */
+#define SMB_write_len           45	/* plus the data ...       */
+
+#define SMB_writr_cnt_offset    33	/* Count of bytes written  */
+#define SMB_writr_bcc_offset    35	/* bcc                     */
+#define SMB_writr_len           37
+
+/* Offsets related to read requests */
+
+#define SMB_read_fid_offset     33	/* FID of file to read     */
+#define SMB_read_cnt_offset     35	/* count of words to read  */
+#define SMB_read_ofs_offset     37	/* Where to read from      */
+#define SMB_read_clf_offset     41	/* Advisory count to go    */
+#define SMB_read_bcc_offset     43
+#define SMB_read_len            45
+
+#define SMB_readr_cnt_offset    33	/* Count of bytes returned */
+#define SMB_readr_res_offset    35	/* 4 shorts reserved, 8 bytes */
+#define SMB_readr_bcc_offset    43	/* bcc                     */
+#define SMB_readr_bff_offset    45	/* buffer format char = 0x01 */
+#define SMB_readr_len_offset    46	/* buffer len              */
+#define SMB_readr_len           45	/* length of the readr before data */
+
+/* Offsets for Create file                                           */
+
+#define SMB_creat_atr_offset    33	/* Attributes of new file ... */
+#define SMB_creat_tim_offset    35	/* Time of creation           */
+#define SMB_creat_dat_offset    37	/* 4004BCE :-)                */
+#define SMB_creat_bcc_offset    39	/* bcc                        */
+#define SMB_creat_buf_offset    41
+#define SMB_creat_len           41	/* Before the data            */
+
+#define SMB_creatr_fid_offset   33	/* FID of created file        */
+
+/* Offsets for Delete file                                           */
+
+#define SMB_delet_sat_offset    33	/* search attribites          */
+#define SMB_delet_bcc_offset    35	/* bcc                        */
+#define SMB_delet_buf_offset    37
+#define SMB_delet_len           37
+
+/* Offsets for SESSION_SETUP_ANDX for both LM and NT LM protocols    */
+
+#define SMB_ssetpLM_mbs_offset  37	/* Max buffer Size, allow for AndX */
+#define SMB_ssetpLM_mmc_offset  39	/* max multiplex count             */
+#define SMB_ssetpLM_vcn_offset  41	/* VC number if new VC             */
+#define SMB_ssetpLM_snk_offset  43	/* Session Key                     */
+#define SMB_ssetpLM_pwl_offset  47	/* password length                 */
+#define SMB_ssetpLM_res_offset  49	/* reserved                        */
+#define SMB_ssetpLM_bcc_offset  53	/* bcc                             */
+#define SMB_ssetpLM_len         55	/* before data ...                 */
+#define SMB_ssetpLM_buf_offset  55
+
+#define SMB_ssetpNTLM_mbs_offset 37	/* Max Buffer Size for NT LM 0.12  */
+					  /* and above                       */
+#define SMB_ssetpNTLM_mmc_offset 39	/* Max Multiplex count             */
+#define SMB_ssetpNTLM_vcn_offset 41	/* VC Number                       */
+#define SMB_ssetpNTLM_snk_offset 43	/* Session key                     */
+#define SMB_ssetpNTLM_cipl_offset 47	/* Case Insensitive PW Len         */
+#define SMB_ssetpNTLM_cspl_offset 49	/* Unicode pw len                  */
+#define SMB_ssetpNTLM_res_offset 51	/* reserved                        */
+#define SMB_ssetpNTLM_cap_offset 55	/* server capabilities             */
+#define SMB_ssetpNTLM_bcc_offset 59	/* bcc                             */
+#define SMB_ssetpNTLM_len        61	/* before data                     */
+#define SMB_ssetpNTLM_buf_offset 61
+
+#define SMB_ssetpr_axo_offset  35	/* Offset of next response ...    */
+#define SMB_ssetpr_act_offset  37	/* action, bit 0 = 1 => guest     */
+#define SMB_ssetpr_bcc_offset  39	/* bcc                            */
+#define SMB_ssetpr_buf_offset  41	/* Native OS etc                  */
+
+/* Offsets for SMB create directory                                         */
+
+#define SMB_creatdir_bcc_offset 33	/* only a bcc here                */
+#define SMB_creatdir_buf_offset 35	/* Where things start             */
+#define SMB_creatdir_len        35
+
+/* Offsets for SMB delete directory                                         */
+
+#define SMB_deletdir_bcc_offset 33	/* only a bcc here                */
+#define SMB_deletdir_buf_offset 35	/* where things start             */
+#define SMB_deletdir_len        35
+
+/* Offsets for SMB check directory                                          */
+
+#define SMB_checkdir_bcc_offset 33	/* Only a bcc here                */
+#define SMB_checkdir_buf_offset 35	/* where things start             */
+#define SMB_checkdir_len        35
+
+/* Offsets for SMB search                                                   */
+
+#define SMB_search_mdc_offset   33	/* Max Dir ents to return         */
+#define SMB_search_atr_offset   35	/* Search attributes              */
+#define SMB_search_bcc_offset   37	/* bcc                            */
+#define SMB_search_buf_offset   39	/* where the action is            */
+#define SMB_search_len          39
+
+#define SMB_searchr_dec_offset  33	/* Dir ents returned              */
+#define SMB_searchr_bcc_offset  35	/* bcc                            */
+#define SMB_searchr_buf_offset  37	/* Where the action starts        */
+#define SMB_searchr_len         37	/* before the dir ents            */
+
+#define SMB_searchr_dirent_len  43	/* 53 bytes                       */
+
+/* Defines for SMB transact and transact2 calls                             */
+
+#define SMB_trans_tpc_offset    33	/* Total param count              */
+#define SMB_trans_tdc_offset    35	/* total Data count               */
+#define SMB_trans_mpc_offset    37	/* Max params bytes to return     */
+#define SMB_trans_mdc_offset    39	/* Max data bytes to return       */
+#define SMB_trans_msc_offset    41	/* Max setup words to return      */
+#define SMB_trans_rs1_offset    42	/* Reserved byte                  */
+#define SMB_trans_flg_offset    43	/* flags                          */
+#define SMB_trans_tmo_offset    45	/* Timeout, long                  */
+#define SMB_trans_rs2_offset    49	/* Next reserved                  */
+#define SMB_trans_pbc_offset    51	/* Param Byte count in buf        */
+#define SMB_trans_pbo_offset    53	/* Offset to param bytes          */
+#define SMB_trans_dbc_offset    55	/* Data byte count in buf         */
+#define SMB_trans_dbo_offset    57	/* Data byte offset               */
+#define SMB_trans_suc_offset    59	/* Setup count - byte             */
+#define SMB_trans_rs3_offset    60	/* Reserved to pad ...            */
+#define SMB_trans_len           61	/* Up to setup, still need bcc    */
+
+#define SMB_transr_tpc_offset   33	/* Total param bytes returned     */
+#define SMB_transr_tdc_offset   35
+#define SMB_transr_rs1_offset   37
+#define SMB_transr_pbc_offset   39
+#define SMB_transr_pbo_offset   41
+#define SMB_transr_pdi_offset   43	/* parameter displacement         */
+#define SMB_transr_dbc_offset   45
+#define SMB_transr_dbo_offset   47
+#define SMB_transr_ddi_offset   49
+#define SMB_transr_suc_offset   51
+#define SMB_transr_rs2_offset   52
+#define SMB_transr_len          53
+
+/* Bit masks for SMB Capabilities ...                       */
+
+#define SMB_cap_raw_mode         0x0001
+#define SMB_cap_mpx_mode         0x0002
+#define SMB_cap_unicode          0x0004
+#define SMB_cap_large_files      0x0008
+#define SMB_cap_nt_smbs          0x0010
+#define SMB_rpc_remote_apis      0x0020
+#define SMB_cap_nt_status        0x0040
+#define SMB_cap_level_II_oplocks 0x0080
+#define SMB_cap_lock_and_read    0x0100
+#define SMB_cap_nt_find          0x0200
+
+/* SMB LANMAN api call defines */
+
+#define SMB_LMapi_SetUserInfo     0x0072
+#define SMB_LMapi_UserPasswordSet 0x0073
+
+/* Structures and defines we use in the client interface */
+
+/* The protocols we might support. Perhaps a bit ambitious, as only RFCNB */
+/* has any support so far 0(sometimes called NBT)                         */
+
+typedef enum {
+    SMB_RFCNB, SMB_IPXNB, SMB_NETBEUI, SMB_X25
+} SMB_Transport_Types;
+
+typedef enum {
+    SMB_Con_FShare, SMB_Con_PShare, SMB_Con_IPC
+} SMB_Con_Types;
+
+typedef enum {
+    SMB_State_NoState, SMB_State_Stopped, SMB_State_Started
+} SMB_State_Types;
+
+/* The following two arrays need to be in step!              */
+/* We must make it possible for callers to specify these ... */
+
+
+extern char *SMB_Prots[];
+
+/*
+ * static char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0", 
+ * "MICROSOFT NETWORKS 1.03",
+ * "MICROSOFT NETWORKS 3.0",
+ * "DOS LANMAN1.0",
+ * "LANMAN1.0",
+ * "DOS LM1.2X002",
+ * "LM1.2X002",
+ * "DOS LANMAN2.1",
+ * "LANMAN2.1",
+ * "Samba",
+ * "NT LM 0.12",
+ * "NT LANMAN 1.0",
+ * NULL};
+ */
+extern int SMB_Types[];
+
+/*
+ * static int SMB_Types[] = {SMB_P_Core,
+ * SMB_P_CorePlus,
+ * SMB_P_DOSLanMan1,
+ * SMB_P_DOSLanMan1,
+ * SMB_P_LanMan1,
+ * SMB_P_DOSLanMan2,
+ * SMB_P_LanMan2,
+ * SMB_P_LanMan2_1,
+ * SMB_P_LanMan2_1,
+ * SMB_P_NT1,
+ * SMB_P_NT1,
+ * SMB_P_NT1,
+ * -1};
+ */
+typedef struct SMB_Status {
+
+    union {
+	struct {
+	    unsigned char ErrorClass;
+	    unsigned char Reserved;
+	    unsigned short Error;
+	} DosError;
+	unsigned int NtStatus;
+    } status;
+} SMB_Status;
+
+typedef struct SMB_Tree_Structure *SMB_Tree_Handle;
+
+typedef struct SMB_Connect_Def *SMB_Handle_Type;
+
+struct SMB_Connect_Def {
+
+    SMB_Handle_Type Next_Con, Prev_Con;		/* Next and previous conn */
+    int protocol;		/* What is the protocol   */
+    int prot_IDX;		/* And what is the index  */
+    void *Trans_Connect;	/* The connection         */
+
+    /* All these strings should be malloc'd */
+
+    char service[80], username[80], password[80], desthost[80], sock_options[80];
+    char address[80], myname[80];
+
+    SMB_Tree_Handle first_tree, last_tree;	/* List of trees on this server */
+
+    int gid;			/* Group ID, do we need it?                      */
+    int mid;			/* Multiplex ID? We might need one per con       */
+    int pid;			/* Process ID                                    */
+
+    int uid;			/* Authenticated user id.                        */
+
+    /* It is pretty clear that we need to bust some of */
+    /* these out into a per TCon record, as there may  */
+    /* be multiple TCon's per server, etc ... later    */
+
+    int port;			/* port to use in case not default, this is a TCPism! */
+
+    int max_xmit;		/* Max xmit permitted by server                  */
+    int Security;		/* 0 = share, 1 = user                           */
+    int Raw_Support;		/* bit 0 = 1 = Read Raw supported, 1 = 1 Write raw */
+    BOOL encrypt_passwords;	/* FALSE = don't                          */
+    int MaxMPX, MaxVC, MaxRaw;
+    unsigned int SessionKey, Capabilities;
+    int SvrTZ;			/* Server Time Zone */
+    int Encrypt_Key_Len;
+    char Encrypt_Key[80], Domain[80], PDomain[80], OSName[80], LMType[40];
+    char Svr_OS[80], Svr_LMType[80], Svr_PDom[80];
+
+};
+
+#ifndef SMBLIB_DEFAULT_DOMAIN
+#define SMBLIB_DEFAULT_DOMAIN "STAFF"
+#endif
+#define SMBLIB_DEFAULT_OSNAME "UNIX of some type"
+#define SMBLIB_DEFAULT_LMTYPE "SMBlib LM2.1 minus a bit"
+#define SMBLIB_MAX_XMIT 65535
+
+#define SMB_Sec_Mode_Share 0
+#define SMB_Sec_Mode_User  1
+
+/* A Tree_Structure                       */
+
+struct SMB_Tree_Structure {
+
+    SMB_Tree_Handle next, prev;
+    SMB_Handle_Type con;
+    char path[129];
+    char device_type[20];
+    int mbs;			/* Local MBS */
+    int tid;
+
+};
+
+typedef struct SMB_File_Def SMB_File;
+
+struct SMB_File_Def {
+
+    SMB_Tree_Handle tree;
+    char filename[256];		/* We should malloc this ... */
+    UWORD fid;
+    unsigned int lastmod;
+    unsigned int size;		/* Could blow up if 64bit files supported */
+    UWORD access;
+    off_t fileloc;
+
+};
+
+/* global Variables for the library */
+
+extern SMB_State_Types SMBlib_State;
+
+#ifndef SMBLIB_ERRNO
+extern int SMBlib_errno;
+extern int SMBlib_SMB_Error;	/* last Error             */
+#endif
+
+SMB_Tree_Handle SMB_TreeConnect(SMB_Handle_Type con, SMB_Tree_Handle tree,
+    char *path, char *password, char *dev);
+
+int SMB_Init();
+void SMB_Get_My_Name(char *name, int len);
+int SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[]);
+int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle);
+
+int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
+    char *PassWord, char *UserDomain, int precrypted);
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+
+int SMB_Get_Last_Error();
+
+#endif /* __SMBLIB_PRIV_H__ */
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib-util.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib-util.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib-util.c	Tue Sep  3 10:42:41 2002
@@ -0,0 +1,801 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Utility Routines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "smblib-priv.h"
+#include <malloc.h>
+#include <string.h>
+
+#include "rfcnb.h"
+
+/* global data structures */
+
+static int SMB_Types[] =
+{SMB_P_Core,
+    SMB_P_CorePlus,
+    SMB_P_DOSLanMan1,
+    SMB_P_DOSLanMan1,
+    SMB_P_LanMan1,
+    SMB_P_DOSLanMan2,
+    SMB_P_LanMan2,
+    SMB_P_LanMan2_1,
+    SMB_P_LanMan2_1,
+    SMB_P_NT1,
+    SMB_P_NT1,
+    SMB_P_NT1,
+    -1};
+
+static char *SMB_Prots[] =
+{"PC NETWORK PROGRAM 1.0",
+    "MICROSOFT NETWORKS 1.03",
+    "MICROSOFT NETWORKS 3.0",
+    "DOS LANMAN1.0",
+    "LANMAN1.0",
+    "DOS LM1.2X002",
+    "LM1.2X002",
+    "DOS LANMAN2.1",
+    "LANMAN2.1",
+    "Samba",
+    "NT LM 0.12",
+    "NT LANMAN 1.0",
+    NULL};
+
+/* Print out an SMB pkt in all its gory detail ... */
+
+void
+SMB_Print_Pkt(FILE fd, RFCNB_Pkt * pkt, BOOL command, int Offset, int Len)
+{
+
+    /* Well, just how do we do this ... print it I suppose */
+
+    /* Print out the SMB header ...                        */
+
+    /* Print the command                                   */
+
+    /* Print the other bits in the header                  */
+
+
+    /* etc                                                 */
+
+}
+
+/* Convert a DOS Date_Time to a local host type date time for printing */
+
+char *
+SMB_DOSTimToStr(int DOS_time)
+{
+    static char SMB_Time_Temp[48];
+    int DOS_sec, DOS_min, DOS_hour, DOS_day, DOS_month, DOS_year;
+
+    SMB_Time_Temp[0] = 0;
+
+    DOS_sec = (DOS_time & 0x001F) * 2;
+    DOS_min = (DOS_time & 0x07E0) >> 5;
+    DOS_hour = ((DOS_time & 0xF800) >> 11);
+
+    DOS_day = (DOS_time & 0x001F0000) >> 16;
+    DOS_month = (DOS_time & 0x01E00000) >> 21;
+    DOS_year = ((DOS_time & 0xFE000000) >> 25) + 80;
+
+    sprintf(SMB_Time_Temp, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month,
+	DOS_year, DOS_hour, DOS_min, DOS_sec);
+
+    return (SMB_Time_Temp);
+
+}
+
+/* Convert an attribute byte/word etc to a string ... We return a pointer
+ * to a static string which we guarantee is long enough. If verbose is 
+ * true, we print out long form of strings ...                            */
+
+char *
+SMB_AtrToStr(int attribs, BOOL verbose)
+{
+    static char SMB_Attrib_Temp[128];
+
+    SMB_Attrib_Temp[0] = 0;
+
+    if (attribs & SMB_FA_ROF)
+	strcat(SMB_Attrib_Temp, (verbose ? "Read Only " : "R"));
+
+    if (attribs & SMB_FA_HID)
+	strcat(SMB_Attrib_Temp, (verbose ? "Hidden " : "H"));
+
+    if (attribs & SMB_FA_SYS)
+	strcat(SMB_Attrib_Temp, (verbose ? "System " : "S"));
+
+    if (attribs & SMB_FA_VOL)
+	strcat(SMB_Attrib_Temp, (verbose ? "Volume " : "V"));
+
+    if (attribs & SMB_FA_DIR)
+	strcat(SMB_Attrib_Temp, (verbose ? "Directory " : "D"));
+
+    if (attribs & SMB_FA_ARC)
+	strcat(SMB_Attrib_Temp, (verbose ? "Archive " : "A"));
+
+    return (SMB_Attrib_Temp);
+
+}
+
+/* Pick up the Max Buffer Size from the Tree Structure ... */
+
+int
+SMB_Get_Tree_MBS(SMB_Tree_Handle tree)
+{
+    if (tree != NULL) {
+	return (tree->mbs);
+    } else {
+	return (SMBlibE_BAD);
+    }
+}
+
+/* Pick up the Max buffer size */
+
+int
+SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+	return (Con_Handle->max_xmit);
+    } else {
+	return (SMBlibE_BAD);
+    }
+
+}
+/* Pickup the protocol index from the connection structure                 */
+
+int
+SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+	return (Con_Handle->prot_IDX);
+    } else {
+	return (0xFFFF);	/* Invalid protocol */
+    }
+
+}
+
+/* Pick up the protocol from the connection structure                       */
+
+int
+SMB_Get_Protocol(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+	return (Con_Handle->protocol);
+    } else {
+	return (0xFFFF);	/* Invalid protocol */
+    }
+
+}
+
+/* Figure out what protocol was accepted, given the list of dialect strings */
+/* We offered, and the index back from the server. We allow for a user      */
+/* supplied list, and assume that it is a subset of our list                */
+
+int
+SMB_Figure_Protocol(char *dialects[], int prot_index)
+{
+    int i;
+
+    if (dialects == SMB_Prots) {	/* The jobs is easy, just index into table */
+
+	return (SMB_Types[prot_index]);
+    } else {			/* Search through SMB_Prots looking for a match */
+
+	for (i = 0; SMB_Prots[i] != NULL; i++) {
+
+	    if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) {	/* A match */
+
+		return (SMB_Types[i]);
+
+	    }
+	}
+
+	/* If we got here, then we are in trouble, because the protocol was not */
+	/* One we understand ...                                                */
+
+	return (SMB_P_Unknown);
+
+    }
+
+}
+
+
+/* Negotiate the protocol we will use from the list passed in Prots       */
+/* we return the index of the accepted protocol in NegProt, -1 indicates  */
+/* none acceptible, and our return value is 0 if ok, <0 if problems       */
+
+int
+SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[])
+{
+    struct RFCNB_Pkt *pkt;
+    int prots_len, i, pkt_len, prot, alloc_len;
+    char *p;
+
+    /* Figure out how long the prot list will be and allocate space for it */
+
+    prots_len = 0;
+
+    for (i = 0; Prots[i] != NULL; i++) {
+
+	prots_len = prots_len + strlen(Prots[i]) + 2;	/* Account for null etc */
+
+    }
+
+    /* The -1 accounts for the one byte smb_buf we have because some systems */
+    /* don't like char msg_buf[]                                             */
+
+    pkt_len = SMB_negp_len + prots_len;
+
+    /* Make sure that the pkt len is long enough for the max response ...   */
+    /* Which is a problem, because the encryption key len eec may be long   */
+
+    if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
+
+	alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
+
+    } else {
+
+	alloc_len = pkt_len;
+
+    }
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(alloc_len);
+
+    if (pkt == NULL) {
+
+	SMBlib_errno = SMBlibE_NoSpace;
+	return (SMBlibE_BAD);
+
+    }
+    /* Now plug in the bits we need */
+
+    bzero(SMB_Hdr(pkt), SMB_negp_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
+
+    /* Now copy the prot strings in with the right stuff */
+
+    p = (char *) (SMB_Hdr(pkt) + SMB_negp_buf_offset);
+
+    for (i = 0; Prots[i] != NULL; i++) {
+
+	*p = SMBdialectID;
+	strcpy(p + 1, Prots[i]);
+	p = p + strlen(Prots[i]) + 2;	/* Adjust len of p for null plus dialectID */
+
+    }
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+
+#ifdef DEBUG
+	fprintf(stderr, "Error sending negotiate protocol\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_SendFailed;	/* Failed, check lower layer errno */
+	return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, alloc_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error receiving response to negotiate\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_RecvFailed;	/* Failed, check lower layer errno */
+	return (SMBlibE_BAD);
+
+    }
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {	/* Process error */
+
+#ifdef DEBUG
+	fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+	SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_Remote;
+	return (SMBlibE_BAD);
+
+    }
+    if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
+
+#ifdef DEBUG
+	fprintf(stderr, "None of our protocols was accepted ... ");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_NegNoProt;
+	return (SMBlibE_BAD);
+
+    }
+    /* Now, unpack the info from the response, if any and evaluate the proto */
+    /* selected. We must make sure it is one we like ...                     */
+
+    Con_Handle->prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
+    Con_Handle->protocol = SMB_Figure_Protocol(Prots, prot);
+
+    if (Con_Handle->protocol == SMB_P_Unknown) {	/* No good ... */
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_ProtUnknown;
+	return (SMBlibE_BAD);
+
+    }
+    switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
+
+    case 0x01:			/* No more info ... */
+
+	break;
+
+    case 13:			/* Up to and including LanMan 2.1 */
+
+	Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset);
+	Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00);
+	Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask;
+
+	Con_Handle->max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset);
+	Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset);
+	Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset);
+	Con_Handle->Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset);
+	Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset);
+	Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset);
+	Con_Handle->Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset);
+
+	p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset);
+	fprintf(stderr, "%8s", (char *) (SMB_Hdr(pkt) + SMB_negrLM_buf_offset));
+	memcpy(Con_Handle->Encrypt_Key, p, 8);
+
+	p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle->Encrypt_Key_Len);
+
+	strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1);
+
+	break;
+
+    case 17:			/* NT LM 0.12 and LN LM 1.0 */
+
+	Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset);
+	Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00);
+	Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask;
+
+	Con_Handle->max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset);
+	Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset);
+	Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset);
+	Con_Handle->MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset);
+	Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset);
+	Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset);
+	Con_Handle->Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset);
+
+	p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset);
+	memcpy(Con_Handle->Encrypt_Key, p, 8);
+	p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset + Con_Handle->Encrypt_Key_Len);
+
+	strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1);
+
+	break;
+
+    default:
+
+#ifdef DEBUG
+	fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
+	fprintf(stderr, "  wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
+#endif
+
+	break;
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    return (0);
+
+}
+
+/* Get our hostname */
+
+void
+SMB_Get_My_Name(char *name, int len)
+{
+
+    if (gethostname(name, len) < 0) {	/* Error getting name */
+
+	strncpy(name, "unknown", len);
+
+	/* Should check the error */
+
+#ifdef DEBUG
+	fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
+	perror("");
+#endif
+
+    }
+    /* only keep the portion up to the first "." */
+
+
+}
+
+/* Send a TCON to the remote server ...               */
+
+SMB_Tree_Handle
+SMB_TreeConnect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle Tree_Handle,
+    char *path,
+    char *password,
+    char *device)
+{
+    struct RFCNB_Pkt *pkt;
+    int param_len, pkt_len;
+    char *p;
+    SMB_Tree_Handle tree;
+
+    /* Figure out how much space is needed for path, password, dev ... */
+
+    if ((path == NULL) || (password == NULL) || (device == NULL)) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n");
+#endif
+
+	SMBlib_errno = SMBlibE_BadParam;
+	return (NULL);
+
+    }
+    /* The + 2 is because of the \0 and the marker ...                    */
+
+    param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2;
+
+    /* The -1 accounts for the one byte smb_buf we have because some systems */
+    /* don't like char msg_buf[]                                             */
+
+    pkt_len = SMB_tcon_len + param_len;
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+	SMBlib_errno = SMBlibE_NoSpace;
+	return (NULL);		/* Should handle the error */
+
+    }
+    /* Now allocate a tree for this to go into ... */
+
+    if (Tree_Handle == NULL) {
+
+	tree = (SMB_Tree_Handle) malloc(sizeof(struct SMB_Tree_Structure));
+
+	if (tree == NULL) {
+
+	    RFCNB_Free_Pkt(pkt);
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    return (NULL);
+
+	}
+    } else {
+
+	tree = Tree_Handle;
+
+    }
+
+    tree->next = tree->prev = NULL;
+    tree->con = Con_Handle;
+    strncpy(tree->path, path, sizeof(tree->path));
+    strncpy(tree->device_type, device, sizeof(tree->device_type));
+
+    /* Now plug in the values ... */
+
+    bzero(SMB_Hdr(pkt), SMB_tcon_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, param_len);
+
+    /* Now copy the param strings in with the right stuff */
+
+    p = (char *) (SMB_Hdr(pkt) + SMB_tcon_buf_offset);
+    *p = SMBasciiID;
+    strcpy(p + 1, path);
+    p = p + strlen(path) + 2;
+    *p = SMBasciiID;
+    strcpy(p + 1, password);
+    p = p + strlen(password) + 2;
+    *p = SMBasciiID;
+    strcpy(p + 1, device);
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error sending TCon request\n");
+#endif
+
+	if (Tree_Handle == NULL)
+	    free(tree);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_SendFailed;
+	return (NULL);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+	if (Tree_Handle == NULL)
+	    free(tree);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_RecvFailed;
+	return (NULL);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {	/* Process error */
+
+#ifdef DEBUG
+	fprintf(stderr, "SMB_TCon failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+	if (Tree_Handle == NULL)
+	    free(tree);
+	SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_Remote;
+	return (NULL);
+
+    }
+    tree->tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset);
+    tree->mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset);
+
+#ifdef DEBUG
+    fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n",
+	tree->tid, tree->mbs);
+#endif
+
+    /* Now link the Tree to the Server Structure ... */
+
+    if (Con_Handle->first_tree == NULL) {
+
+	Con_Handle->first_tree = tree;
+	Con_Handle->last_tree = tree;
+
+    } else {
+
+	Con_Handle->last_tree->next = tree;
+	tree->prev = Con_Handle->last_tree;
+	Con_Handle->last_tree = tree;
+
+    }
+
+    RFCNB_Free_Pkt(pkt);
+    return (tree);
+
+}
+
+int
+SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard)
+{
+    struct RFCNB_Pkt *pkt;
+    int pkt_len;
+
+    pkt_len = SMB_tdis_len;
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+	SMBlib_errno = SMBlibE_NoSpace;
+	return (SMBlibE_BAD);	/* Should handle the error */
+
+    }
+    /* Now plug in the values ... */
+
+    bzero(SMB_Hdr(pkt), SMB_tdis_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle->con->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle->con->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle->con->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle->tid);
+    SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0);
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error sending TDis request\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_SendFailed;
+	return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = -SMBlibE_RecvFailed;
+	return (SMBlibE_BAD);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {	/* Process error */
+
+#ifdef DEBUG
+	fprintf(stderr, "SMB_TDis failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+	SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_Remote;
+	return (SMBlibE_BAD);
+
+    }
+    Tree_Handle->tid = 0xFFFF;	/* Invalid TID */
+    Tree_Handle->mbs = 0;	/* Invalid     */
+
+#ifdef DEBUG
+
+    fprintf(stderr, "Tree disconnect successful ...\n");
+
+#endif
+
+    /* What about the tree handle ? */
+
+    if (discard == TRUE) {	/* Unlink it and free it ... */
+
+	if (Tree_Handle->next == NULL)
+	    Tree_Handle->con->first_tree = Tree_Handle->prev;
+	else
+	    Tree_Handle->next->prev = Tree_Handle->prev;
+
+	if (Tree_Handle->prev == NULL)
+	    Tree_Handle->con->last_tree = Tree_Handle->next;
+	else
+	    Tree_Handle->prev->next = Tree_Handle->next;
+
+    }
+    RFCNB_Free_Pkt(pkt);
+    return (0);
+
+}
+
+/* Pick up the last LMBlib error ... */
+
+int
+SMB_Get_Last_Error()
+{
+
+    return (SMBlib_errno);
+
+}
+
+/* Pick up the last error returned in an SMB packet          */
+/* We will need macros to extract error class and error code */
+
+int
+SMB_Get_Last_SMB_Err()
+{
+
+    return (SMBlib_SMB_Error);
+
+}
+
+/* Pick up the error message associated with an error from SMBlib  */
+
+/* Keep this table in sync with the message codes in smblib-common.h */
+
+static char *SMBlib_Error_Messages[] =
+{
+
+    "Request completed sucessfully.",
+    "Server returned a non-zero SMB Error Class and Code.",
+    "A lower layer protocol error occurred.",
+    "Function not yet implemented.",
+    "The protocol negotiated does not support the request.",
+    "No space available for operation.",
+    "One or more bad parameters passed.",
+    "None of the protocols we offered were accepted.",
+    "The attempt to send an SMB request failed. See protocol error info.",
+    "The attempt to get an SMB response failed. See protocol error info.",
+    "The logon request failed, but you were logged in as guest.",
+    "The attempt to call the remote server failed. See protocol error info.",
+    "The protocol dialect specified in a NegProt and accepted by the server is unknown.",
+  /* This next one simplifies error handling */
+    "No such error code.",
+    NULL};
+
+int
+SMB_Get_Error_Msg(int msg, char *msgbuf, int len)
+{
+
+    if (msg >= 0) {
+
+	strncpy(msgbuf,
+	    SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg],
+	    len - 1);
+	msgbuf[len - 1] = 0;	/* Make sure it is a string */
+    } else {			/* Add the lower layer message ... */
+
+	char prot_msg[1024];
+
+	msg = -msg;		/* Make it positive */
+
+	strncpy(msgbuf,
+	    SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg],
+	    len - 1);
+
+	msgbuf[len - 1] = 0;	/* make sure it is a string */
+
+	if (strlen(msgbuf) < len) {	/* If there is space, put rest in */
+
+	    strncat(msgbuf, "\n\t", len - strlen(msgbuf));
+
+	    RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1);
+
+	    strncat(msgbuf, prot_msg, len - strlen(msgbuf));
+
+	}
+    }
+    return 0;
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib.c	Tue Sep  3 10:42:42 2002
@@ -0,0 +1,575 @@
+
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Routines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <malloc.h>
+#include <ctype.h>
+#include <string.h>
+
+int SMBlib_errno;
+int SMBlib_SMB_Error;
+#define SMBLIB_ERRNO
+#define uchar unsigned char
+#include "smblib-priv.h"
+
+#include "rfcnb.h"
+#include "smbencrypt.h"
+
+#include <signal.h>
+
+/* #define DEBUG */
+
+SMB_State_Types SMBlib_State;
+
+/* Initialize the SMBlib package     */
+
+int
+SMB_Init()
+{
+
+    SMBlib_State = SMB_State_Started;
+
+    signal(SIGPIPE, SIG_IGN);	/* Ignore these ... */
+
+/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
+#ifdef SMBLIB_INSTRUMENT
+
+    SMBlib_Instrument_Init();
+
+#endif
+
+    return 0;
+
+}
+
+int
+SMB_Term()
+{
+
+#ifdef SMBLIB_INSTRUMENT
+
+    SMBlib_Instrument_Term();	/* Clean up and print results */
+
+#endif
+
+    return 0;
+
+}
+
+/* SMB_Create: Create a connection structure and return for later use */
+/* We have other helper routines to set variables                     */
+
+SMB_Handle_Type
+SMB_Create_Con_Handle()
+{
+
+    SMBlib_errno = SMBlibE_NotImpl;
+    return (NULL);
+
+}
+
+int
+SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
+{
+
+
+    if (RFCNB_Set_Sock_NoDelay(Con_Handle->Trans_Connect, yn) < 0) {
+
+#ifdef DEBUG
+#endif
+
+	fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
+
+    }
+    return (0);
+
+}
+
+/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
+/* or anything else ...                                                  */
+
+SMB_Handle_Type
+SMB_Connect_Server(SMB_Handle_Type Con_Handle,
+    char *server, char *NTdomain)
+{
+    SMB_Handle_Type con;
+    char called[80], calling[80], *address;
+    int i;
+
+    /* Get a connection structure if one does not exist */
+
+    con = Con_Handle;
+
+    if (Con_Handle == NULL) {
+
+	if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    return NULL;
+	}
+    }
+    /* Init some things ... */
+
+    strcpy(con->service, "");
+    strcpy(con->username, "");
+    strcpy(con->password, "");
+    strcpy(con->sock_options, "");
+    strcpy(con->address, "");
+    strcpy(con->desthost, server);
+    strcpy(con->PDomain, NTdomain);
+    strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
+    strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
+    con->first_tree = con->last_tree = NULL;
+
+    /* ugh. This is horribly broken. */
+/*   SMB_Get_My_Name(con -> myname, sizeof(con -> myname)); */
+    /* hacked by Kinkie */
+    i = gethostname(con->myname, sizeof(con->myname));
+    if (i == -1) {
+	strcpy(con->myname, "unknown");
+    } else {
+	if (NULL != (address = strchr(con->myname, '.'))) {
+	    *address = '\0';	/* truncate at first '.' */
+	}
+    }
+
+
+    con->port = 0;		/* No port selected */
+
+    /* Get some things we need for the SMB Header */
+
+    con->pid = getpid();
+    con->mid = con->pid;	/* This will do for now ... */
+    con->uid = 0;		/* Until we have done a logon, no uid ... */
+    con->gid = getgid();
+
+    /* Now connect to the remote end, but first upper case the name of the
+     * service we are going to call, sine some servers want it in uppercase */
+
+    for (i = 0; i < strlen(server); i++)
+	called[i] = toupper(server[i]);
+
+    called[strlen(server)] = 0;	/* Make it a string */
+
+    for (i = 0; i < strlen(con->myname); i++)
+	calling[i] = toupper(con->myname[i]);
+
+    calling[strlen(con->myname)] = 0;	/* Make it a string */
+
+    if (strcmp(con->address, "") == 0)
+	address = con->desthost;
+    else
+	address = con->address;
+
+    con->Trans_Connect = RFCNB_Call(called,
+	calling,
+	address,		/* Protocol specific */
+	con->port);
+
+    /* Did we get one? */
+
+    if (con->Trans_Connect == NULL) {
+
+	if (Con_Handle == NULL) {
+	    Con_Handle = NULL;
+	    free(con);
+	}
+	SMBlib_errno = -SMBlibE_CallFailed;
+	return NULL;
+
+    }
+    return (con);
+
+}
+
+/* SMB_Connect: Connect to the indicated server                       */
+/* If Con_Handle == NULL then create a handle and connect, otherwise  */
+/* use the handle passed                                              */
+
+char *SMB_Prots_Restrict[] =
+{"PC NETWORK PROGRAM 1.0",
+    NULL};
+
+
+SMB_Handle_Type
+SMB_Connect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle * tree,
+    char *service,
+    char *username,
+    char *password)
+{
+    SMB_Handle_Type con;
+    char *host, *address;
+    char temp[80], called[80], calling[80];
+    int i;
+
+    /* Get a connection structure if one does not exist */
+
+    con = Con_Handle;
+
+    if (Con_Handle == NULL) {
+
+	if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    return NULL;
+	}
+    }
+    /* Init some things ... */
+
+    strcpy(con->service, service);
+    strcpy(con->username, username);
+    strcpy(con->password, password);
+    strcpy(con->sock_options, "");
+    strcpy(con->address, "");
+    strcpy(con->PDomain, SMBLIB_DEFAULT_DOMAIN);
+    strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
+    strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
+    con->first_tree = con->last_tree = NULL;
+
+    SMB_Get_My_Name(con->myname, sizeof(con->myname));
+
+    con->port = 0;		/* No port selected */
+
+    /* Get some things we need for the SMB Header */
+
+    con->pid = getpid();
+    con->mid = con->pid;	/* This will do for now ... */
+    con->uid = 0;		/* Until we have done a logon, no uid */
+    con->gid = getgid();
+
+    /* Now figure out the host portion of the service */
+
+    strcpy(temp, service);
+    host = (char *) strtok(temp, "/\\");	/* Separate host name portion */
+    strcpy(con->desthost, host);
+
+    /* Now connect to the remote end, but first upper case the name of the
+     * service we are going to call, sine some servers want it in uppercase */
+
+    for (i = 0; i < strlen(host); i++)
+	called[i] = toupper(host[i]);
+
+    called[strlen(host)] = 0;	/* Make it a string */
+
+    for (i = 0; i < strlen(con->myname); i++)
+	calling[i] = toupper(con->myname[i]);
+
+    calling[strlen(con->myname)] = 0;	/* Make it a string */
+
+    if (strcmp(con->address, "") == 0)
+	address = con->desthost;
+    else
+	address = con->address;
+
+    con->Trans_Connect = RFCNB_Call(called,
+	calling,
+	address,		/* Protocol specific */
+	con->port);
+
+    /* Did we get one? */
+
+    if (con->Trans_Connect == NULL) {
+
+	if (Con_Handle == NULL) {
+	    free(con);
+	    Con_Handle = NULL;
+	}
+	SMBlib_errno = -SMBlibE_CallFailed;
+	return NULL;
+
+    }
+    /* Now, negotiate the protocol */
+
+    if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
+
+	/* Hmmm what should we do here ... We have a connection, but could not
+	 * negotiate ...                                                      */
+
+	return NULL;
+
+    }
+    /* Now connect to the service ... */
+
+    if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
+
+	return NULL;
+
+    }
+    return (con);
+
+}
+
+/* Logon to the server. That is, do a session setup if we can. We do not do */
+/* Unicode yet!                                                             */
+
+int
+SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
+    char *PassWord, char *UserDomain, int precrypted)
+{
+    struct RFCNB_Pkt *pkt;
+    int param_len, pkt_len, pass_len;
+    char *p, pword[128];
+
+    /* First we need a packet etc ... but we need to know what protocol has  */
+    /* been negotiated to figure out if we can do it and what SMB format to  */
+    /* use ...                                                               */
+
+    if (Con_Handle->protocol < SMB_P_LanMan1) {
+
+	SMBlib_errno = SMBlibE_ProtLow;
+	return (SMBlibE_BAD);
+
+    }
+    if (precrypted) {
+	pass_len = 24;
+	memcpy(pword, PassWord, 24);
+    } else {
+	strcpy(pword, PassWord);
+	if (Con_Handle->encrypt_passwords) {
+	    pass_len = 24;
+	    SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
+	} else
+	    pass_len = strlen(pword);
+    }
+
+    /* Now build the correct structure */
+
+    if (Con_Handle->protocol < SMB_P_NT1) {
+
+	param_len = strlen(UserName) + 1 + pass_len + 1 +
+	    strlen(UserDomain) + 1 +
+	    strlen(Con_Handle->OSName) + 1;
+
+	pkt_len = SMB_ssetpLM_len + param_len;
+
+	pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+	if (pkt == NULL) {
+
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    fprintf(stderr, "SMB_Logon_server: Couldn't allocate packet\n");
+	    return (SMBlibE_BAD);	/* Should handle the error */
+	}
+	bzero(SMB_Hdr(pkt), SMB_ssetpLM_len);
+	SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+	*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+	*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
+	*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;	/* No extra command */
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle->pid);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
+
+	/* Now copy the param strings in with the right stuff */
+
+	p = (char *) (SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
+
+	/* Copy  in password, then the rest. Password has a null at end */
+
+	memcpy(p, pword, pass_len);
+
+	p = p + pass_len + 1;
+
+	strcpy(p, UserName);
+	p = p + strlen(UserName);
+	*p = 0;
+
+	p = p + 1;
+
+	strcpy(p, UserDomain);
+	p = p + strlen(UserDomain);
+	*p = 0;
+	p = p + 1;
+
+	strcpy(p, Con_Handle->OSName);
+	p = p + strlen(Con_Handle->OSName);
+	*p = 0;
+
+    } else {
+
+	/* We don't admit to UNICODE support ... */
+
+	param_len = strlen(UserName) + 1 + pass_len +
+	    strlen(UserDomain) + 1 +
+	    strlen(Con_Handle->OSName) + 1 +
+	    strlen(Con_Handle->LMType) + 1;
+
+	pkt_len = SMB_ssetpNTLM_len + param_len;
+
+	pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+	if (pkt == NULL) {
+
+	    SMBlib_errno = SMBlibE_NoSpace;
+	    fprintf(stderr, "SMB_Logon_server: Couldn't allocate packet\n");
+	    return (-1);	/* Should handle the error */
+	}
+	bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len);
+	SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);	/* Plunk in IDF */
+	*(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+	*(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
+	*(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;	/* No extra command */
+	SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 1); /* Thanks Tridge! */
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
+	SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
+	SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
+
+	/* Now copy the param strings in with the right stuff */
+
+	p = (char *) (SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
+
+	/* Copy  in password, then the rest. Password has no null at end */
+
+	memcpy(p, pword, pass_len);
+
+	p = p + pass_len;
+
+	strcpy(p, UserName);
+	p = p + strlen(UserName);
+	*p = 0;
+
+	p = p + 1;
+
+	strcpy(p, UserDomain);
+	p = p + strlen(UserDomain);
+	*p = 0;
+	p = p + 1;
+
+	strcpy(p, Con_Handle->OSName);
+	p = p + strlen(Con_Handle->OSName);
+	*p = 0;
+	p = p + 1;
+
+	strcpy(p, Con_Handle->LMType);
+	p = p + strlen(Con_Handle->LMType);
+	*p = 0;
+
+    }
+
+    /* Now send it and get a response */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error sending SessSetupX request\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_SendFailed;
+	return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+	fprintf(stderr, "Error receiving response to SessSetupAndX\n");
+#endif
+
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_RecvFailed;
+	return (SMBlibE_BAD);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {	/* Process error */
+
+#ifdef DEBUG
+	fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+	SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+	RFCNB_Free_Pkt(pkt);
+	SMBlib_errno = SMBlibE_Remote;
+	return (SMBlibE_BAD);
+
+    }
+/** @@@ mdz: check for guest login { **/
+    if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1) {
+	/* do we allow guest login? NO! */
+	return (SMBlibE_BAD);
+
+    }
+/** @@@ mdz: } **/
+
+
+#ifdef DEBUG
+    fprintf(stderr, "SessSetupAndX response. Action = %i\n",
+	SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
+#endif
+
+    /* Now pick up the UID for future reference ... */
+
+    Con_Handle->uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
+    RFCNB_Free_Pkt(pkt);
+
+    return (0);
+
+}
+
+
+/* Disconnect from the server, and disconnect all tree connects */
+
+int
+SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
+{
+
+    /* We just disconnect the connection for now ... */
+    if (Con_Handle != NULL)
+	RFCNB_Hangup(Con_Handle->Trans_Connect);
+
+    if (!KeepHandle)
+	free(Con_Handle);
+
+    return (0);
+
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib.h	Tue Sep  3 10:42:42 2002
@@ -0,0 +1,98 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "std-defines.h"
+#include "smblib-common.h"
+
+/* Just define all the entry points */
+
+/* Create a handle to allow us to set/override some parameters ...       */
+
+void *SMB_Create_Con_Handle();
+
+/* Connect to a server, but do not do a tree con etc ... */
+
+void *SMB_Connect_Server(void *Con, char *server, char *NTdomain);
+
+/* Connect to a server and give us back a handle. If Con == NULL, create */
+/* The handle and populate it with defaults                              */
+
+void *SMB_Connect(void *Con, void **tree,
+    char *name, char *User, char *Password);
+
+/* Negotiate a protocol                                                  */
+
+int SMB_Negotiate(void *Con_Handle, char *Prots[]);
+
+/* Connect to a tree ...                                                 */
+
+void *SMB_TreeConnect(void *con_handle, void *tree_handle,
+    char *path, char *password, char *dev);
+
+/* Disconnect a tree ...                                                 */
+
+int SMB_TreeDisconect(void *tree_handle);
+
+/* Open a file                                                           */
+
+void *SMB_Open(void *tree_handle,
+    void *file_handle,
+    char *file_name,
+    unsigned short mode,
+    unsigned short search);
+
+/* Close a file                                                          */
+
+int SMB_Close(void *file_handle);
+
+/* Disconnect from server. Has flag to specify whether or not we keep the */
+/* handle.                                                                */
+
+int SMB_Discon(void *Con, BOOL KeepHandle);
+
+void *SMB_Create(void *Tree_Handle,
+    void *File_Handle,
+    char *file_name,
+    short search);
+
+int SMB_Delete(void *tree, char *file_name, short search);
+
+int SMB_Create_Dir(void *tree, char *dir_name);
+
+int SMB_Delete_Dir(void *tree, char *dir_name);
+
+int SMB_Check_Dir(void *tree, char *dir_name);
+
+int SMB_Get_Last_Error();
+
+int SMB_Get_Last_SMB_Err();
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+
+void *SMB_Logon_And_TCon(void *con, void *tree, char *user, char *pass,
+    char *service, char *st);
+
+
+#define SMBLIB_DEFAULT_DOMAIN "anydom"
Index: squid/src/auth/ntlm/helpers/SMB/smbval/std-defines.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/std-defines.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/std-defines.h	Tue Sep  3 10:42:42 2002
@@ -0,0 +1,49 @@
+#ifndef __STD_DEFINES__
+#define __STD_DEFINES__
+
+/* RFCNB Standard includes ... */
+/*
+ * 
+ * SMBlib Standard Includes
+ * 
+ * Copyright (C) 1996, Richard Sharpe
+ * 
+ * One day we will conditionalize these on OS types ... */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "squid_types.h"
+#define BOOL int16_t
+#define int16 int16_t
+#define uint16 u_int16_t
+#define int32 int32_t
+#define uint32 u_int32_t
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+
+#define TRUE 1
+#define FALSE 0
+
+#endif /* __STD_DEFINES__ */
Index: squid/src/auth/ntlm/helpers/SMB/smbval/std-includes.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/std-includes.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/std-includes.h	Tue Sep  3 10:42:42 2002
@@ -0,0 +1,47 @@
+/* RFCNB Standard includes ... */
+/*
+ * 
+ * RFCNB Standard Includes
+ * 
+ * Copyright (C) 1996, Richard Sharpe
+ * 
+ * One day we will conditionalize these on OS types ... */
+
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* the types are provided by squid's configure preocess */
+#include "squid_types.h"
+#define BOOL int16_t
+#define int16 int16_t
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* Pick up define for INADDR_NONE */
+
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
Index: squid/src/auth/ntlm/helpers/SMB/smbval/valid.c
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/valid.c:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/valid.c	Tue Sep  3 10:42:42 2002
@@ -0,0 +1,106 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include "smblib-priv.h"
+#include "valid.h"
+
+SMB_Handle_Type SMB_Connect_Server(void *, char *, char *);
+
+int
+Valid_User(char *USERNAME, char *PASSWORD, char *SERVER, char *BACKUP, char *DOMAIN)
+{
+    int pass_is_precrypted_p = 0;
+    char *SMB_Prots[] =
+    {
+/*              "PC NETWORK PROGRAM 1.0", */
+/*              "MICROSOFT NETWORKS 1.03", */
+/*              "MICROSOFT NETWORKS 3.0", */
+	"LANMAN1.0",
+	"LM1.2X002",
+	"Samba",
+/*              "NT LM 0.12", */
+/*              "NT LANMAN 1.0", */
+	NULL};
+    SMB_Handle_Type con;
+
+    SMB_Init();
+    con = SMB_Connect_Server(NULL, SERVER, DOMAIN);
+    if (con == NULL) {		/* Error ... */
+	con = SMB_Connect_Server(NULL, BACKUP, DOMAIN);
+	if (con == NULL) {
+	    return (NTV_SERVER_ERROR);
+	}
+    }
+    if (SMB_Negotiate(con, SMB_Prots) < 0) {	/* An error */
+	SMB_Discon(con, 0);
+	return (NTV_PROTOCOL_ERROR);
+    }
+    /* Test for a server in share level mode do not authenticate against it */
+    if (con->Security == 0) {
+	SMB_Discon(con, 0);
+	return (NTV_PROTOCOL_ERROR);
+    }
+    if (SMB_Logon_Server(con, USERNAME, PASSWORD, DOMAIN, pass_is_precrypted_p) < 0) {
+	SMB_Discon(con, 0);
+	return (NTV_LOGON_ERROR);
+    }
+    SMB_Discon(con, 0);
+    return (NTV_NO_ERROR);
+}
+
+void *
+NTLM_Connect(char *SERVER, char *BACKUP, char *DOMAIN, char *nonce)
+{
+    char *SMB_Prots[] =
+    {
+/*              "PC NETWORK PROGRAM 1.0", */
+/*              "MICROSOFT NETWORKS 1.03", */
+/*              "MICROSOFT NETWORKS 3.0", */
+	"LANMAN1.0",
+	"LM1.2X002",
+	"Samba",
+/*              "NT LM 0.12", */
+/*              "NT LANMAN 1.0", */
+	NULL};
+    SMB_Handle_Type con;
+
+    SMB_Init();
+    con = SMB_Connect_Server(NULL, SERVER, DOMAIN);
+    if (con == NULL) {		/* Error ... */
+	con = SMB_Connect_Server(NULL, BACKUP, DOMAIN);
+	if (con == NULL) {
+	    return (NULL);
+	}
+    }
+    if (SMB_Negotiate(con, SMB_Prots) < 0) {	/* An error */
+	SMB_Discon(con, 0);
+	return (NULL);
+    }
+    /* Test for a server in share level mode do not authenticate against it */
+    if (con->Security == 0) {
+	SMB_Discon(con, 0);
+	return (NULL);
+    }
+    memcpy(nonce, con->Encrypt_Key, 8);
+
+    return (con);
+}
+
+int
+NTLM_Auth(void *handle, char *USERNAME, char *PASSWORD, int flag)
+{
+    SMB_Handle_Type con = handle;
+
+    if (SMB_Logon_Server(con, USERNAME, PASSWORD, NULL, flag) < 0) {
+	return (NTV_LOGON_ERROR);
+    }
+    return (NTV_NO_ERROR);
+}
+
+void
+NTLM_Disconnect(void *handle)
+{
+    SMB_Handle_Type con = handle;
+    SMB_Discon(con, 0);
+}
Index: squid/src/auth/ntlm/helpers/SMB/smbval/valid.h
diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/valid.h:1.2.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/SMB/smbval/valid.h	Tue Sep  3 10:42:42 2002
@@ -0,0 +1,15 @@
+#ifndef _VALID_H_
+#define _VALID_H_
+/* SMB User verification function */
+
+#define NTV_NO_ERROR 0
+#define NTV_SERVER_ERROR 1
+#define NTV_PROTOCOL_ERROR 2
+#define NTV_LOGON_ERROR 3
+
+int Valid_User(char *USERNAME, char *PASSWORD, char *SERVER, char *BACKUP, char *DOMAIN);
+void *NTLM_Connect(char *SERVER, char *BACKUP, char *DOMAIN, char *nonce);
+int NTLM_Auth(void *handle, char *USERNAME, char *PASSWORD, int flag);
+void NTLM_Disconnect(void *handle);
+
+#endif
Index: squid/src/auth/ntlm/helpers/winbind/Makefile.am
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/Makefile.am:1.5.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/Makefile.am	Tue Sep  3 10:42:43 2002
@@ -0,0 +1,11 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+#
+
+libexec_PROGRAMS = wb_ntlmauth
+wb_ntlmauth_SOURCES = wb_ntlm_auth.c wb_common.c
+INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
+    -I$(top_srcdir)/src
+LDADD = -L$(top_builddir)/lib -lmiscutil -lntlmauth -lm
Index: squid/src/auth/ntlm/helpers/winbind/samba_nss.h
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/samba_nss.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/samba_nss.h	Tue Sep  3 10:42:43 2002
@@ -0,0 +1,105 @@
+#ifndef _NSSWITCH_NSS_H
+#define _NSSWITCH_NSS_H
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.0
+
+   a common place to work out how to define NSS_STATUS on various
+   platforms
+
+   Copyright (C) Tim Potter 2000
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library 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
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#ifdef HAVE_NSS_COMMON_H
+
+/* Sun Solaris */
+
+#include <nss_common.h>
+#include <nss_dbdefs.h>
+#include <nsswitch.h>
+
+typedef nss_status_t NSS_STATUS;
+
+#define NSS_STATUS_SUCCESS     NSS_SUCCESS
+#define NSS_STATUS_NOTFOUND    NSS_NOTFOUND
+#define NSS_STATUS_UNAVAIL     NSS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN    NSS_TRYAGAIN
+
+#elif HAVE_NSS_H
+
+/* GNU */
+
+#include <nss.h>
+
+typedef enum nss_status NSS_STATUS;
+
+#elif HAVE_NS_API_H
+
+/* SGI IRIX */
+
+/* following required to prevent warnings of double definition
+ * of datum from ns_api.h
+*/
+#ifdef DATUM
+#define _DATUM_DEFINED
+#endif
+
+#include <ns_api.h>
+
+typedef enum
+{
+  NSS_STATUS_SUCCESS=NS_SUCCESS,
+  NSS_STATUS_NOTFOUND=NS_NOTFOUND,
+  NSS_STATUS_UNAVAIL=NS_UNAVAIL,
+  NSS_STATUS_TRYAGAIN=NS_TRYAGAIN
+} NSS_STATUS;
+
+#define NSD_MEM_STATIC 0
+#define NSD_MEM_VOLATILE 1
+#define NSD_MEM_DYNAMIC 2
+
+#elif defined(HPUX)
+/* HP-UX 11 */
+
+#include "nsswitch/hp_nss_common.h"
+#include "nsswitch/hp_nss_dbdefs.h"
+#include <nsswitch.h>
+
+#ifndef _HAVE_TYPEDEF_NSS_STATUS
+#define _HAVE_TYPEDEF_NSS_STATUS
+typedef nss_status_t NSS_STATUS;
+
+#define NSS_STATUS_SUCCESS     NSS_SUCCESS
+#define NSS_STATUS_NOTFOUND    NSS_NOTFOUND
+#define NSS_STATUS_UNAVAIL     NSS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN    NSS_TRYAGAIN
+#endif /* HPUX */
+
+#else /* Nothing's defined. Neither gnu nor sun nor hp */
+
+typedef enum
+{
+  NSS_STATUS_SUCCESS=0,
+  NSS_STATUS_NOTFOUND=1,
+  NSS_STATUS_UNAVAIL=2,
+  NSS_STATUS_TRYAGAIN=3
+} NSS_STATUS;
+
+#endif
+
+#endif /* _NSSWITCH_NSS_H */
Index: squid/src/auth/ntlm/helpers/winbind/wb_common.c
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/wb_common.c:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/wb_common.c	Tue Sep  3 10:42:44 2002
@@ -0,0 +1,403 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.0
+
+   winbind client common code
+
+   Copyright (C) Tim Potter 2000
+   Copyright (C) Andrew Tridgell 2000
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library 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
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
+#include "config.h"
+
+
+/* Global variables.  These are effectively the client state information */
+
+int winbindd_fd = -1;		/* fd for winbindd socket */
+static char *excluded_domain;
+
+/* Free a response structure */
+
+void
+free_response(struct winbindd_response *response)
+{
+    /* Free any allocated extra_data */
+
+    if (response)
+	SAFE_FREE(response->extra_data);
+}
+
+/*
+  smbd needs to be able to exclude lookups for its own domain
+*/
+void
+winbind_exclude_domain(const char *domain)
+{
+    SAFE_FREE(excluded_domain);
+    excluded_domain = strdup(domain);
+}
+
+
+/* Initialise a request structure */
+
+void
+init_request(struct winbindd_request *request, int request_type)
+{
+    static char *domain_env;
+    static BOOL initialised;
+
+    request->length = sizeof(struct winbindd_request);
+
+    request->cmd = (enum winbindd_cmd) request_type;
+    request->pid = getpid();
+    request->domain[0] = '\0';
+
+    if (!initialised) {
+	initialised = True;
+	domain_env = getenv(WINBINDD_DOMAIN_ENV);
+    }
+
+    if (domain_env) {
+	strncpy(request->domain, domain_env, sizeof(request->domain) - 1);
+	request->domain[sizeof(request->domain) - 1] = '\0';
+    }
+}
+
+/* Initialise a response structure */
+
+void
+init_response(struct winbindd_response *response)
+{
+    /* Initialise return value */
+
+    response->result = WINBINDD_ERROR;
+}
+
+/* Close established socket */
+
+void
+close_sock(void)
+{
+    if (winbindd_fd != -1) {
+	close(winbindd_fd);
+	winbindd_fd = -1;
+    }
+}
+
+/* Connect to winbindd socket */
+
+int
+winbind_open_pipe_sock(void)
+{
+    struct sockaddr_un sunaddr;
+    static pid_t our_pid;
+    struct stat st;
+    pstring path;
+
+    if (our_pid != getpid()) {
+	close_sock();
+	our_pid = getpid();
+    }
+
+    if (winbindd_fd != -1) {
+	return winbindd_fd;
+    }
+
+    /* Check permissions on unix socket directory */
+
+    if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) {
+	return -1;
+    }
+
+    if (!S_ISDIR(st.st_mode) || (st.st_uid != 0 && st.st_uid != geteuid())) {
+	return -1;
+    }
+
+    /* Connect to socket */
+
+    strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1);
+    path[sizeof(path) - 1] = '\0';
+
+    strncat(path, "/", sizeof(path) - 1);
+    path[sizeof(path) - 1] = '\0';
+
+    strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1);
+    path[sizeof(path) - 1] = '\0';
+
+    ZERO_STRUCT(sunaddr);
+    sunaddr.sun_family = AF_UNIX;
+    strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
+
+    /* If socket file doesn't exist, don't bother trying to connect
+     * with retry.  This is an attempt to make the system usable when
+     * the winbindd daemon is not running. */
+
+    if (lstat(path, &st) == -1) {
+	return -1;
+    }
+
+    /* Check permissions on unix socket file */
+
+    if (!S_ISSOCK(st.st_mode) || (st.st_uid != 0 && st.st_uid != geteuid())) {
+	return -1;
+    }
+
+    /* Connect to socket */
+
+    if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+	return -1;
+    }
+
+    if (connect(winbindd_fd, (struct sockaddr *) &sunaddr,
+	    sizeof(sunaddr)) == -1) {
+	close_sock();
+	return -1;
+    }
+
+    return winbindd_fd;
+}
+
+/* Write data to winbindd socket with timeout */
+
+int
+write_sock(void *buffer, int count)
+{
+    int result, nwritten;
+
+    /* Open connection to winbind daemon */
+
+  restart:
+
+    if (winbind_open_pipe_sock() == -1) {
+	return -1;
+    }
+
+    /* Write data to socket */
+
+    nwritten = 0;
+
+    while (nwritten < count) {
+	struct timeval tv;
+	fd_set r_fds;
+
+	/* Catch pipe close on other end by checking if a read()
+	 * call would not block by calling select(). */
+
+	FD_ZERO(&r_fds);
+	FD_SET(winbindd_fd, &r_fds);
+	ZERO_STRUCT(tv);
+
+	if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) {
+	    close_sock();
+	    return -1;		/* Select error */
+	}
+
+	/* Write should be OK if fd not available for reading */
+
+	if (!FD_ISSET(winbindd_fd, &r_fds)) {
+
+	    /* Do the write */
+
+	    result = write(winbindd_fd,
+		(char *) buffer + nwritten, count - nwritten);
+
+	    if ((result == -1) || (result == 0)) {
+
+		/* Write failed */
+
+		close_sock();
+		return -1;
+	    }
+
+	    nwritten += result;
+
+	} else {
+
+	    /* Pipe has closed on remote end */
+
+	    close_sock();
+	    goto restart;
+	}
+    }
+
+    return nwritten;
+}
+
+/* Read data from winbindd socket with timeout */
+
+static int
+read_sock(void *buffer, int count)
+{
+    int result = 0, nread = 0;
+
+    /* Read data from socket */
+
+    while (nread < count) {
+
+	result = read(winbindd_fd, (char *) buffer + nread, count - nread);
+
+	if ((result == -1) || (result == 0)) {
+
+	    /* Read failed.  I think the only useful thing we
+	     * can do here is just return -1 and fail since the
+	     * transaction has failed half way through. */
+
+	    close_sock();
+	    return -1;
+	}
+
+	nread += result;
+    }
+
+    return result;
+}
+
+/* Read reply */
+
+int
+read_reply(struct winbindd_response *response)
+{
+    int result1, result2 = 0;
+
+    if (!response) {
+	return -1;
+    }
+
+    /* Read fixed length response */
+
+    if ((result1 = read_sock(response, sizeof(struct winbindd_response)))
+	== -1) {
+
+	return -1;
+    }
+
+    /* We actually send the pointer value of the extra_data field from
+     * the server.  This has no meaning in the client's address space
+     * so we clear it out. */
+
+    response->extra_data = NULL;
+
+    /* Read variable length response */
+
+    if (response->length > sizeof(struct winbindd_response)) {
+	int extra_data_len = response->length -
+	    sizeof(struct winbindd_response);
+
+	/* Mallocate memory for extra data */
+
+	if (!(response->extra_data = malloc(extra_data_len))) {
+	    return -1;
+	}
+
+	if ((result2 = read_sock(response->extra_data, extra_data_len))
+	    == -1) {
+	    free_response(response);
+	    return -1;
+	}
+    }
+
+    /* Return total amount of data read */
+
+    return result1 + result2;
+}
+
+/* 
+ * send simple types of requests 
+ */
+
+NSS_STATUS
+winbindd_send_request(int req_type, struct winbindd_request * request)
+{
+    struct winbindd_request lrequest;
+
+    /* Check for our tricky environment variable */
+
+    if (getenv(WINBINDD_DONT_ENV)) {
+	return NSS_STATUS_NOTFOUND;
+    }
+
+    /* smbd may have excluded this domain */
+    if (excluded_domain && strcasecmp(excluded_domain, request->domain) == 0) {
+	return NSS_STATUS_NOTFOUND;
+    }
+
+    if (!request) {
+	ZERO_STRUCT(lrequest);
+	request = &lrequest;
+    }
+
+    /* Fill in request and send down pipe */
+
+    init_request(request, req_type);
+
+    if (write_sock(request, sizeof(*request)) == -1) {
+	return NSS_STATUS_UNAVAIL;
+    }
+
+    return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Get results from winbindd request
+ */
+
+NSS_STATUS
+winbindd_get_response(struct winbindd_response * response)
+{
+    struct winbindd_response lresponse;
+
+    if (!response) {
+	ZERO_STRUCT(lresponse);
+	response = &lresponse;
+    }
+
+    init_response(response);
+
+    /* Wait for reply */
+    if (read_reply(response) == -1) {
+	return NSS_STATUS_UNAVAIL;
+    }
+
+    /* Throw away extra data if client didn't request it */
+    if (response == &lresponse) {
+	free_response(response);
+    }
+
+    /* Copy reply data from socket */
+    if (response->result != WINBINDD_OK) {
+	return NSS_STATUS_NOTFOUND;
+    }
+
+    return NSS_STATUS_SUCCESS;
+}
+
+/* Handle simple types of requests */
+
+NSS_STATUS
+winbindd_request(int req_type,
+    struct winbindd_request * request, struct winbindd_response * response)
+{
+    NSS_STATUS status;
+
+    status = winbindd_send_request(req_type, request);
+    if (status != NSS_STATUS_SUCCESS)
+	return (status);
+    return winbindd_get_response(response);
+}
Index: squid/src/auth/ntlm/helpers/winbind/wb_ntlm_auth.c
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/wb_ntlm_auth.c:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/wb_ntlm_auth.c	Tue Sep  3 10:42:44 2002
@@ -0,0 +1,425 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ * (C) 2002 Andrew Bartlett <abartlet@samba.org>
+ *
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * 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.
+ *
+ */
+/*
+ * TODO:
+ * -add handling of the -d flag
+ * -move all squid-helper-protocol-related operations to helper functions
+ * -remove the hard-coded target NT domain name
+ *
+ * - MAYBE move squid-helper-protocol-related opetations to an external
+ *   library?
+ */
+
+
+#include "wbntlm.h"
+#include "util.h"
+/* stdio.h is included in wbntlm.h */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/time.h>		/* for gettimeofday */
+#include <errno.h>		/* BUG: is this portable? */
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
+
+#ifndef min
+#define min(x,y) ((x)<(y)?(x):(y))
+#endif
+
+void
+authfail(char *domain, char *user, char *reason)
+{
+    /* TODO: -move away from SEND-type gcc-isms
+     *       -prepare for protocol extension as soon as rbcollins is ready
+     */
+    SEND2("NA %s\\%s auth failure because: %s", domain, user, reason);
+}
+
+void
+authok(const char *domain, const char *user)
+{
+    SEND2("AF %s\\%s", domain, user);
+}
+
+void
+sendchallenge(const char *challenge)
+{
+    SEND2("TT %s", challenge);
+}
+
+void
+helperfail(const char *reason)
+{
+    SEND2("BH %s", reason);
+}
+
+char debug_enabled = 0;
+char *myname;
+pid_t mypid;
+
+static void
+lc(char *string)
+{
+    char *p = string, c;
+    while ((c = *p)) {
+	*p = tolower(c);
+	p++;
+    }
+}
+
+static void
+uc(char *string)
+{
+    char *p = string, c;
+    while ((c = *p)) {
+	*p = toupper(c);
+	p++;
+    }
+}
+
+
+
+NSS_STATUS winbindd_request(int req_type,
+    struct winbindd_request *request, struct winbindd_response *response);
+
+
+static tristate have_urandom = DONTKNOW;
+FILE *urandom_file = NULL;
+
+void
+init_random()
+{
+    if (have_urandom == DONTKNOW) {
+	int result = 0;
+	struct stat st;
+	result = stat(ENTROPY_SOURCE, &st);
+	if (result != 0 || !(S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+	    debug("Entropy source " ENTROPY_SOURCE " is unavailable\n");
+	    have_urandom = NO;
+	}
+	if ((urandom_file = fopen(ENTROPY_SOURCE, "r")) == NULL) {
+	    unsigned int seed;
+	    struct timeval t;
+	    warn("Can't open entropy source " ENTROPY_SOURCE "\n");
+	    have_urandom = NO;
+	    gettimeofday(&t, NULL);
+	    seed = squid_random() * getpid() * t.tv_sec * t.tv_usec;
+	    squid_srandom(seed);
+	} else {
+	    have_urandom = YES;
+	}
+    }
+}
+
+static unsigned char challenge[CHALLENGE_LEN + 1];
+static char *
+build_challenge(void)
+{
+    size_t gotchars;
+    unsigned char j;
+    switch (have_urandom) {
+    case YES:
+	if ((gotchars = fread(&challenge, CHALLENGE_LEN, 1, urandom_file)) == 0) {
+	    /* couldn't get a challenge. Fall back to random() and friends.
+	     * notice that even a single changed byte is good enough for us */
+	    have_urandom = NO;
+	    return build_challenge();
+	}
+	return challenge;
+    case NO:
+	if (!(squid_random() % 100)) {	/* sometimes */
+	    init_random();
+	}
+	for (j = 0; j < CHALLENGE_LEN; j++)
+	    challenge[j] = (unsigned char) (squid_random() % 256);
+	return challenge;
+    default:
+	warn("Critical internal error. Somebody forgot to initialize "
+	    "the random system. Exiting.\n");
+	exit(1);
+    }
+}
+
+lstring lmhash, nthash;
+static char have_nthash = 0;	/* simple flag. A tad dirty.. */
+
+void
+do_authenticate(ntlm_authenticate * auth, int auth_length)
+{
+    lstring tmp;
+    int tocopy;
+    NSS_STATUS winbindd_result;
+    struct winbindd_request request;
+    struct winbindd_response response;
+    char *domain, *user;
+
+    memset(&request, 0, sizeof(struct winbindd_request));
+
+    memset(&response, 0, sizeof(struct winbindd_response));
+
+    /* domain */
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
+    if (tmp.str == NULL || tmp.l == 0) {	/* no domain supplied */
+	request.data.auth_crap.domain[0] = 0;
+    } else {
+	tocopy = min(tmp.l + 1, sizeof(fstring));
+	xstrncpy(request.data.auth_crap.domain, tmp.str, tocopy);
+    }
+
+    domain = request.data.auth_crap.domain;	/* just a shortcut */
+
+    /* username */
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
+    if (tmp.str == NULL || tmp.l == 0) {
+	authfail(domain, "-", "No username in request");
+	return;
+    }
+
+    tocopy = min(sizeof(fstring), tmp.l + 1);
+    xstrncpy(request.data.auth_crap.user, tmp.str, tocopy);
+    user = request.data.auth_crap.user;
+
+    /* now the LM hash */
+    lmhash = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse);
+    switch (lmhash.l) {
+    case 0:
+	warn("No lm hash provided by user %s\\%s\n", domain, user);
+	request.data.auth_crap.lm_resp_len = 0;
+	break;
+    case 24:
+	memcpy(request.data.auth_crap.lm_resp, lmhash.str, 24);
+	request.data.auth_crap.lm_resp_len = 24;
+	break;
+    default:
+	authfail(domain, user, "Broken LM hash response");
+	return;
+    }
+
+    nthash = ntlm_fetch_string((char *) auth, auth_length, &auth->ntresponse);
+    switch (nthash.l) {
+    case 0:
+	debug("no nthash\n");
+	request.data.auth_crap.nt_resp_len = 0;
+	break;
+    case 24:
+	memcpy(request.data.auth_crap.nt_resp, nthash.str, 24);
+	request.data.auth_crap.nt_resp_len = 24;
+	break;
+    default:
+	debug("nthash len = %d\n", nthash.l);
+	authfail(domain, user, "Broken NT hash response");
+	return;
+    }
+
+    debug("Checking user '%s\\%s' lmhash len =%d, have_nthash=%d, "
+	"nthash len=%d\n", domain, user, lmhash.l, have_nthash, nthash.l);
+
+    memcpy(request.data.auth_crap.chal, challenge, CHALLENGE_LEN);
+
+    winbindd_result = winbindd_request(WINBINDD_PAM_AUTH_CRAP,
+	&request, &response);
+    debug("winbindd result: %d\n", winbindd_result);
+
+    if (winbindd_result == WINBINDD_OK) {
+	lc(domain);
+	lc(user);
+	authok(domain, user);
+    } else {
+	char error_buf[200];
+	snprintf(error_buf, sizeof(error_buf), "Authentication Failure (%s)",
+	    response.data.auth.error_string);
+	authfail(domain, user, error_buf);
+    }
+    return;			/* useless */
+}
+
+void
+manage_request(char *target_domain)
+{
+    char buf[BUFFER_SIZE + 1];
+    char *c, *decoded;
+    ntlmhdr *fast_header;
+
+
+    if (fgets(buf, BUFFER_SIZE, stdin) == NULL) {
+	warn("fgets() failed! dying..... errno=%d (%s)\n", errno,
+	    strerror(errno));
+	exit(1);		/* BIIG buffer */
+    }
+
+    c = memchr(buf, '\n', BUFFER_SIZE);
+    if (c)
+	*c = '\0';
+    else {
+	warn("No newline in '%s'. Dying.\n", buf);
+	exit(1);
+    }
+
+    debug("Got '%s' from squid.\n", buf);
+    if (memcmp(buf, "YR", 2) == 0) {	/* refresh-request */
+	sendchallenge(ntlm_make_challenge(target_domain, NULL,
+		build_challenge(), CHALLENGE_LEN));
+	return;
+    }
+    if (strncmp(buf, "KK ", 3) != 0) {	/* not an auth-request */
+	helperfail("illegal request received");
+	warn("Illegal request received: '%s'\n", buf);
+	return;
+    }
+    /* At this point I'm sure it's a KK */
+    decoded = base64_decode(buf + 3);
+    if (!decoded) {		/* decoding failure, return error */
+	authfail("-", "-", "Auth-format error, base64-decoding error");
+	return;
+    }
+    fast_header = (struct _ntlmhdr *) decoded;
+
+    /* sanity-check: it IS a NTLMSSP packet, isn't it? */
+    if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) {
+	authfail("-", "-", "Broken NTLM packet, missing NTLMSSP signature");
+	return;
+    }
+    /* Understand what we got */
+    switch (fast_header->type) {
+    case NTLM_NEGOTIATE:
+	authfail("-", "-", "Received neg-request while expecting auth packet");
+	return;
+    case NTLM_CHALLENGE:
+	authfail("-", "-", "Received challenge. Refusing to abide");
+	return;
+    case NTLM_AUTHENTICATE:
+	do_authenticate((ntlm_authenticate *) decoded,
+	    (strlen(buf) - 3) * 3 / 4);
+	return;
+    default:
+	helperfail("Unknown authentication packet type");
+	return;
+    }
+    /* notreached */
+    return;
+}
+
+static char *
+get_winbind_domain(void)
+{
+    struct winbindd_response response;
+    char *domain;
+
+    ZERO_STRUCT(response);
+
+    /* Send off request */
+
+    if (winbindd_request(WINBINDD_DOMAIN_NAME, NULL, &response) !=
+	NSS_STATUS_SUCCESS) {
+	warn("could not obtain winbind domain name!\n");
+	exit(1);
+    }
+
+    domain = strdup(response.data.domain_name);
+    uc(domain);
+
+    warn("target domain is %s\n", domain);
+    return domain;
+}
+
+char *
+process_options(int argc, char *argv[])
+{
+    int opt;
+    char *target_domain = NULL;
+
+    while (-1 != (opt = getopt(argc, argv, "d"))) {
+	switch (opt) {
+	case 'd':
+	    debug_enabled = 1;
+	    break;
+	default:
+	    warn("Unknown option: -%c. Exiting\n", opt);
+	    exit(1);
+	    break;		/* not reached */
+	}
+	if (optind >= argc - 1) {
+	    target_domain = argv[optind];
+	    warn("target domain is %s\n", target_domain);
+	}
+    }
+    return target_domain;
+}
+
+void
+check_winbindd()
+{
+    NSS_STATUS r;
+    struct winbindd_request request;
+    struct winbindd_response response;
+    r = winbindd_request(WINBINDD_INTERFACE_VERSION, &request, &response);
+    if (r != WINBINDD_OK) {
+	warn("Can't contact winbindd. Dying\n");
+	exit(1);
+    }
+    if (response.data.interface_version != WINBIND_INTERFACE_VERSION) {
+	warn("Winbind protocol mismatch. Align squid and samba. Dying\n");
+	exit(1);
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+    char *target_domain;
+    if (argc > 0) {		/* should always be true */
+	myname = strrchr(argv[0], '/');
+	if (myname == NULL)
+	    myname = argv[0];
+	else
+	    myname++;
+    } else {
+	myname = "(unknown)";
+    }
+    mypid = getpid();
+    target_domain = process_options(argc, argv);
+    debug("ntlm winbindd auth helper build " __DATE__ ", " __TIME__
+	" starting up...\n");
+
+    check_winbindd();
+
+    if (target_domain == NULL) {
+	target_domain = get_winbind_domain();
+    }
+
+    /* initialize FDescs */
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+    init_random();
+    while (1) {
+	manage_request(target_domain);
+    }
+    return 0;
+}
Index: squid/src/auth/ntlm/helpers/winbind/wbntlm.h
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/wbntlm.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/wbntlm.h	Tue Sep  3 10:42:44 2002
@@ -0,0 +1,88 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>,
+ *
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * 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 _WBNTLM_H_
+#define _WBNTLM_H_
+
+#include "config.h"
+#include "ntlmauth.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+/*************** CONFIGURATION ***************/
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+/* the attempted entropy source. If it doesn't exist, random() is uesed */
+#define ENTROPY_SOURCE "/dev/urandom"
+
+/************* END CONFIGURATION *************/
+
+/* Debugging stuff */
+extern char *myname;
+static char *__foo;
+extern pid_t mypid;
+extern char debug_enabled;
+
+#ifdef DEBUG
+#define __DO_DEBUG 1
+#else
+#define __DO_DEBUG 0
+#endif
+
+#if defined(__GNUC__) || defined(__ICC)    /* this is really a gcc-ism */
+#define warn(X...)  fprintf(stderr,"%s[%d](%s:%d): ", myname, mypid, \
+                    ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\
+                    __LINE__);\
+                    fprintf(stderr,X)
+#define debug(X...) if(__DO_DEBUG && debug_enabled) { warn(X); }
+#else /* __GNUC__ */
+static void
+debug(char *format,...)
+{
+}
+static void
+warn(char *format,...)
+{
+}
+#endif /* __GNUC__ */
+
+
+
+/* A couple of harmless helper macros */
+#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
+#if defined(__GNUC__) || defined (__ICC)
+#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); \
+                      printf(X "\n",Y)
+#else
+/* no gcc, no debugging. varargs macros are a gcc extension */
+#define SEND2 printf
+#endif
+
+typedef enum {
+  YES,
+  NO,
+  DONTKNOW
+} tristate;
+
+#define CHALLENGE_LEN 8
+#define BUFFER_SIZE 2010
+
+#endif /* _WBNTLM_H_ */
Index: squid/src/auth/ntlm/helpers/winbind/winbind_nss_config.h
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/winbind_nss_config.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/winbind_nss_config.h	Tue Sep  3 10:42:44 2002
@@ -0,0 +1,148 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.0
+
+   Winbind daemon for ntdom nss module
+
+   Copyright (C) Tim Potter 2000
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library 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
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#ifndef _WINBIND_NSS_CONFIG_H
+#define _WINBIND_NSS_CONFIG_H
+
+/* Include header files from data in config.h file */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_UNIXSOCKET
+#include <sys/un.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <pwd.h>
+#include "samba_nss.h"
+
+/* Declarations for functions in winbind_nss.c
+   needed in winbind_nss_solaris.c (solaris wrapper to nss) */
+
+NSS_STATUS _nss_winbind_setpwent(void);
+NSS_STATUS _nss_winbind_endpwent(void);
+NSS_STATUS _nss_winbind_getpwent_r(struct passwd* result, char* buffer,
+				   size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwuid_r(uid_t, struct passwd*, char* buffer,
+				   size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwnam_r(const char* name, struct passwd* result,
+				   char* buffer, size_t buflen, int* errnop);
+
+NSS_STATUS _nss_winbind_setgrent(void);
+NSS_STATUS _nss_winbind_endgrent(void);
+NSS_STATUS _nss_winbind_getgrent_r(struct group* result, char* buffer,
+				   size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getgrnam_r(const char *name,
+				   struct group *result, char *buffer,
+				   size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid,
+				   struct group *result, char *buffer,
+				   size_t buflen, int *errnop);
+
+/* I'm trying really hard not to include anything from smb.h with the
+   result of some silly looking redeclaration of structures. */
+
+#ifndef _PSTRING
+#define _PSTRING
+#define PSTRING_LEN 1024
+#define FSTRING_LEN 256
+typedef char pstring[PSTRING_LEN];
+typedef char fstring[FSTRING_LEN];
+#endif
+
+#ifndef _BOOL
+#define _BOOL			/* So we don't typedef BOOL again in vfs.h */
+#define False (0)
+#define True (1)
+#define Auto (2)
+typedef int BOOL;
+#endif
+
+#if !defined(uint32)
+#if (SIZEOF_INT == 4)
+#define uint32 unsigned int
+#elif (SIZEOF_LONG == 4)
+#define uint32 unsigned long
+#elif (SIZEOF_SHORT == 4)
+#define uint32 unsigned short
+#endif
+#endif
+
+#if !defined(uint16)
+#if (SIZEOF_SHORT == 4)
+#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+#else /* SIZEOF_SHORT != 4 */
+#define uint16 unsigned short
+#endif /* SIZEOF_SHORT != 4 */
+#endif
+
+#ifndef uint8
+#define uint8 unsigned char
+#endif
+
+/* zero a structure */
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+
+/* zero a structure given a pointer to the structure */
+#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); }
+    
+/* Some systems (SCO) treat UNIX domain sockets as FIFOs */
+
+#ifndef S_IFSOCK
+#define S_IFSOCK S_IFIFO
+#endif
+
+#ifndef S_ISSOCK
+#define S_ISSOCK(mode)  ((mode & S_IFSOCK) == S_IFSOCK)
+#endif
+
+#endif
Index: squid/src/auth/ntlm/helpers/winbind/winbindd_nss.h
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/winbindd_nss.h:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/winbindd_nss.h	Tue Sep  3 10:42:44 2002
@@ -0,0 +1,216 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Winbind daemon for ntdom nss module
+
+   Copyright (C) Tim Potter 2000
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library 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
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0)
+#endif
+
+#ifndef _WINBINDD_NTDOM_H
+#define _WINBINDD_NTDOM_H
+
+#define WINBINDD_SOCKET_NAME "pipe"            /* Name of PF_UNIX socket */
+#define WINBINDD_SOCKET_DIR  "/tmp/.winbindd"  /* Name of PF_UNIX dir */
+
+#define WINBINDD_DOMAIN_ENV  "WINBINDD_DOMAIN" /* Environment variables */
+#define WINBINDD_DONT_ENV    "_NO_WINBINDD"
+
+/* Update this when you change the interface.  */
+
+#define WINBIND_INTERFACE_VERSION 4
+
+/* Socket commands */
+
+enum winbindd_cmd {
+
+	WINBINDD_INTERFACE_VERSION,    /* Always a well known value */
+
+	/* Get users and groups */
+
+	WINBINDD_GETPWNAM,
+	WINBINDD_GETPWUID,
+	WINBINDD_GETGRNAM,
+	WINBINDD_GETGRGID,
+	WINBINDD_GETGROUPS,
+
+	/* Enumerate users and groups */
+
+	WINBINDD_SETPWENT,
+	WINBINDD_ENDPWENT,
+	WINBINDD_GETPWENT,
+	WINBINDD_SETGRENT,
+	WINBINDD_ENDGRENT,
+	WINBINDD_GETGRENT,
+
+	/* PAM authenticate and password change */
+
+	WINBINDD_PAM_AUTH,
+	WINBINDD_PAM_AUTH_CRAP,
+	WINBINDD_PAM_CHAUTHTOK,
+
+	/* List various things */
+
+	WINBINDD_LIST_USERS,         /* List w/o rid->id mapping */
+	WINBINDD_LIST_GROUPS,        /* Ditto */
+	WINBINDD_LIST_TRUSTDOM,
+
+	/* SID conversion */
+
+	WINBINDD_LOOKUPSID,
+	WINBINDD_LOOKUPNAME,
+
+	/* Lookup functions */
+
+	WINBINDD_SID_TO_UID,       
+	WINBINDD_SID_TO_GID,
+	WINBINDD_UID_TO_SID,
+	WINBINDD_GID_TO_SID,
+
+	/* Miscellaneous other stuff */
+
+	WINBINDD_CHECK_MACHACC,     /* Check machine account pw works */
+	WINBINDD_PING,              /* Just tell me winbind is running */
+	WINBINDD_INFO,              /* Various bit of info.  Currently just tidbits */
+	WINBINDD_DOMAIN_NAME,       /* The domain this winbind server is a member of (lp_workgroup()) */
+
+	WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
+
+	/* Placeholder for end of cmd list */
+
+	WINBINDD_NUM_CMDS
+};
+
+/* Winbind request structure */
+
+struct winbindd_request {
+	uint32 length;
+	enum winbindd_cmd cmd;   /* Winbindd command to execute */
+	pid_t pid;               /* pid of calling process */
+
+	union {
+		fstring username;    /* getpwnam */
+		fstring groupname;   /* getgrnam */
+		uid_t uid;           /* getpwuid, uid_to_sid */
+		gid_t gid;           /* getgrgid, gid_to_sid */
+		struct {
+			fstring user;
+			fstring pass;
+		} auth;              /* pam_winbind auth module */
+                struct {
+                        unsigned char chal[8];
+                        fstring user;
+                        fstring domain;
+                        fstring lm_resp;
+                        uint16 lm_resp_len;
+                        fstring nt_resp;
+                        uint16 nt_resp_len;
+                } auth_crap;
+                struct {
+                    fstring user;
+                    fstring oldpass;
+                    fstring newpass;
+                } chauthtok;         /* pam_winbind passwd module */
+		fstring sid;         /* lookupsid, sid_to_[ug]id */
+		struct {
+			fstring dom_name;       /* lookupname */
+			fstring name;       
+		} name;
+		uint32 num_entries;  /* getpwent, getgrent */
+	} data;
+	fstring domain;      /* {set,get,end}{pw,gr}ent() */
+};
+
+/* Response values */
+
+enum winbindd_result {
+	WINBINDD_ERROR,
+	WINBINDD_OK
+};
+
+/* Winbind response structure */
+
+struct winbindd_response {
+    
+	/* Header information */
+
+	uint32 length;                        /* Length of response */
+	enum winbindd_result result;          /* Result code */
+
+	/* Fixed length return data */
+	
+	union {
+		int interface_version;  /* Try to ensure this is always in the same spot... */
+		
+		/* getpwnam, getpwuid */
+		
+		struct winbindd_pw {
+			fstring pw_name;
+			fstring pw_passwd;
+			uid_t pw_uid;
+			gid_t pw_gid;
+			fstring pw_gecos;
+			fstring pw_dir;
+			fstring pw_shell;
+		} pw;
+
+		/* getgrnam, getgrgid */
+
+		struct winbindd_gr {
+			fstring gr_name;
+			fstring gr_passwd;
+			gid_t gr_gid;
+			int num_gr_mem;
+			int gr_mem_ofs;   /* offset to group membership */
+		} gr;
+
+		uint32 num_entries; /* getpwent, getgrent */
+		struct winbindd_sid {
+			fstring sid;        /* lookupname, [ug]id_to_sid */
+			int type;
+		} sid;
+		struct winbindd_name {
+			fstring dom_name;       /* lookupsid */
+			fstring name;       
+			int type;
+		} name;
+		uid_t uid;          /* sid_to_uid */
+		gid_t gid;          /* sid_to_gid */
+		struct winbindd_info {
+			char winbind_separator;
+			fstring samba_version;
+		} info;
+		fstring domain_name;
+
+		struct auth_reply {
+			uint32 nt_status;
+			fstring nt_status_string;
+			fstring error_string;
+			int pam_error;
+		} auth;
+	} data;
+
+	/* Variable length return data */
+
+	void *extra_data;               /* getgrnam, getgrgid, getgrent */
+};
+
+#endif
Index: squid/src/auth/ntlm/helpers/winbind/patches/wb_common.patch
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/patches/wb_common.patch:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/patches/wb_common.patch	Tue Sep  3 10:42:45 2002
@@ -0,0 +1,11 @@
+--- samba-HEAD/source/nsswitch/wb_common.c	Sat Jan 12 23:12:11 2002
++++ squid-ntlm/src/auth/ntlm/helpers/winbind/wb_common.c	Sat Jan 12 23:45:03 2002
+@@ -25,6 +25,8 @@
+ 
+ #include "winbind_nss_config.h"
+ #include "winbindd_nss.h"
++#include "config.h"
++
+ 
+ /* Global variables.  These are effectively the client state information */
+ 
Index: squid/src/auth/ntlm/helpers/winbind/patches/winbind_nss_config.patch
diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/patches/winbind_nss_config.patch:1.3.10.1
--- /dev/null	Mon Jan 26 04:57:41 2004
+++ squid/src/auth/ntlm/helpers/winbind/patches/winbind_nss_config.patch	Tue Sep  3 10:42:45 2002
@@ -0,0 +1,20 @@
+--- samba-HEAD/source/nsswitch/winbind_nss_config.h	Wed Sep  5 10:11:16 2001
++++ squid-ntlm/src/auth/ntlm/helpers/winbind/winbind_nss_config.h	Sat Nov 24 00:32:05 2001
+@@ -27,7 +27,7 @@
+ 
+ /* Include header files from data in config.h file */
+ 
+-#include <config.h>
++#include "config.h"
+ 
+ #include <stdio.h>
+ 
+@@ -63,7 +63,7 @@
+ #include <sys/stat.h>
+ #include <errno.h>
+ #include <pwd.h>
+-#include "nsswitch/nss.h"
++#include "samba_nss.h"
+ 
+ /* Declarations for functions in winbind_nss.c
+    needed in winbind_nss_solaris.c (solaris wrapper to nss) */
squid-push-HEAD.new squid-push-HEAD differ: char 63, line 2
