This patch is generated from the generic_modules branch of HEAD in squid
Wed Sep 29 01:31:10 2004 GMT
See http://devel.squid-cache.org/

Index: squid/acconfig.h
diff -u squid/acconfig.h:1.8 squid/acconfig.h:1.4.18.3
--- squid/acconfig.h:1.8	Sat Apr 14 06:06:33 2001
+++ squid/acconfig.h	Fri Apr 27 07:24:55 2001
@@ -110,13 +110,6 @@
 #undef ALARM_UPDATES_TIME
 
 /*
- * Define this to include code which lets you specify access control
- * elements based on ethernet hardware addresses.  This code uses
- * functions found in 4.4 BSD derviations (e.g. FreeBSD, ?).
- */
-#undef USE_ARP_ACL
-
-/*
  * Define this to include code for the Hypertext Cache Protocol (HTCP)
  */
 #undef USE_HTCP
Index: squid/configure.in
diff -u squid/configure.in:1.21 squid/configure.in:1.17.4.6
--- squid/configure.in:1.21	Sat May  5 13:47:58 2001
+++ squid/configure.in	Sat May 12 06:06:03 2001
@@ -492,7 +492,7 @@
 	    sleep 10
 	    ;;
      esac
-     AC_DEFINE(USE_ARP_ACL)
+     CONF_MODULES="$CONF_MODULES acl_arp"
    fi
 ])
 
@@ -864,6 +864,37 @@
 fi
 AC_SUBST(DIGEST_AUTH_HELPERS)
 
+dnl Select generic modules to build
+dnl we may inherit preset CONF_MODULES from AUTH & FS & REPL above
+AC_ARG_ENABLE(modules,
+[  --enable-modules=\"list of modules\"
+                          This option selects which generic modules to build.
+                          Generic modules can plugin into several parts of squid
+                          and autoregister their capabilities with squid. For a list
+                          of available modules see the src/modules directory.],
+[ case "$enableval" in
+  yes)
+    for module in $srcdir/src/modules/*; do
+	if test -f $module/Makefile.in; then
+	    CONF_MODULES="$CONF_MODULES `basename $module`"
+	fi
+    done
+    ;;
+  no)
+    ;;
+  *)
+    CONF_MODULES="$CONF_MODULES `echo $enableval|sed -e 's/,/ /g;s/  */ /g'`"
+  esac
+])
+if test -n "$CONF_MODULES"; then
+    echo "Generic modules built: $CONF_MODULES"
+    AC_SUBST(CONF_MODULES)
+    CONF_MODULE_OBJS="modules/`echo $CONF_MODULES|sed -e's% %.a modules/%g'`.a"
+    AC_SUBST(CONF_MODULE_OBJS)
+    CONF_MODULE_LIBS="`echo $CONF_MODULE_OBJS|sed -e's%module/%%g'`"
+    AC_SUBST(CONF_MODULE_LIBS)
+fi
+
 dnl Enable "NTLM fail open"
 AC_ARG_ENABLE(ntlm-fail-open,
 [  --enable-ntlm-fail-open Enable NTLM fail open, where a helper that fails one of the
@@ -1970,6 +2001,15 @@
 	fi
 done
 
+MOD_MAKEFILES=""
+for module in `find $srcdir/src/modules -type d -print`; do
+        if test -f $module/Makefile.in; then
+            dir=`echo $module | sed -e "s|^$srcdir/||"`
+            MOD_MAKEFILES="$MOD_MAKEFILES ./$dir/Makefile"
+        fi
+done
+
+
 AC_OUTPUT(\
 	./makefile \
 	./lib/Makefile \
@@ -1984,6 +2024,7 @@
 	$REPL_MAKEFILES \
 	./src/auth/Makefile \
 	$AUTH_MAKEFILES \
+	$MOD_MAKEFILES \
 	./contrib/Makefile \
 	$SNMP_MAKEFILE \
 	./icons/Makefile \
Index: squid/doc/debug-sections.txt
diff -u squid/doc/debug-sections.txt:1.3 squid/doc/debug-sections.txt:1.3.10.2
--- squid/doc/debug-sections.txt:1.3	Sun Jan  7 15:53:36 2001
+++ squid/doc/debug-sections.txt	Wed Feb 14 05:49:21 2001
@@ -86,3 +86,4 @@
 section 79    HTTP Meter Header
 section 80    WCCP
 section 81    Store Removal/Replacement policy
+section 84    Generic Module Routines
Index: squid/include/squid_parser.h
diff -u /dev/null squid/include/squid_parser.h:1.1.2.3
--- /dev/null	Tue Sep 28 18:35:55 2004
+++ squid/include/squid_parser.h	Sat Apr 28 04:16:46 2001
@@ -0,0 +1,181 @@
+/*
+ * $Id$
+ *
+ * * * * * * * * Legal stuff * * * * * * *
+ *
+ * (C) 2001 Robert Collins <rbtcollins@hotmail.com>
+ *
+ *  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
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * * * * * * * * Declaration of intents * * * * * * *
+ *
+ * Here are defined an interface to squid's runtime-parser which is able
+ * To manage many of the issues in parsing the config file automaticall.
+ */
+
+/*
+
+#include "defines.h"
+#include "enums.h"
+#include "typedefs.h"
+#include "structs.h"
+#include "protos.h"
+
+*/
+
+#ifndef _SQUID_PARSER_H_
+#define _SQUID_PARSER_H_
+
+/* parser types */
+typedef struct _parserTypeNode parserTypeNode;
+typedef struct _parserNameNode parserNameNode;
+typedef struct _includefile_t includefile_t;
+typedef struct _instance_name instance_name;
+typedef struct _instance_node instance_node;
+typedef void PARSER_PARSE(parserNameNode *, void *);
+typedef void PARSER_FREE (parserNameNode *, void *);
+/* the next one is different to the cache_cf entries, because it has to be */
+typedef void PARSER_DUMP (StoreEntry *, const char *, void const *const);
+typedef void PARSER_DEFAULT_NONE(void *);
+typedef void PARSER_NAME_DOCUMENT(void);
+typedef int  PARSER_POST_PARSE(void);
+
+struct _includefile_t {
+    includefile_t * next;
+    char *filename;
+};
+
+struct _instance_name {
+    dlink_node node;
+    dlink_list instances;
+    char *namestr;
+    parserTypeNode *type;
+    PARSER_DEFAULT_NONE  *default_none;
+    PARSER_NAME_DOCUMENT *documentfunc;
+    PARSER_POST_PARSE    *post_parse_func;
+};
+
+struct _instance_node {
+    dlink_node node;
+    dlink_list *head;
+    char *namestr;
+    void *data;
+    parserNameNode *parserName;
+    instance_name *name;
+};
+
+struct _parserTypeNode {
+    dlink_node node;
+    const char *typestr;
+    PARSER_PARSE *parsefunc;
+    PARSER_FREE  *freefunc;
+    PARSER_DUMP  *dumpfunc;
+    struct {
+        unsigned int registered:1;
+    } flags;
+};
+
+struct _parserNameNode {
+    dlink_node node;
+    dlink_list children;
+    dlink_list *head;
+    const char *namestr;
+    parserTypeNode *type;
+    parserNameNode *parent;
+    PARSER_DEFAULT_NONE  *default_none;
+    PARSER_NAME_DOCUMENT *documentfunc;
+    PARSER_POST_PARSE    *post_parse_func;
+    void *location;
+    struct {
+        unsigned int registered:1;
+    } flags;
+};
+
+
+/*
+ * cache_cf.c
+ */
+extern void parserAddDocumentOption(const char *option);
+extern int parserDoDocument(const char *file_name);
+extern int parserReconfigure(const char *file_name);
+extern PARSER_FREE free_intlist;
+extern int intlistFind(intlist * list, int i);
+extern const char *wordlistAdd(wordlist **, const char *);
+extern void wordlistAddWl(wordlist **, wordlist *);
+extern void wordlistJoin(wordlist **, wordlist **);
+extern wordlist *wordlistDup(const wordlist *);
+extern void wordlistDestroy(wordlist **);
+extern void configFreeMemory(void);
+extern void wordlistCat(const wordlist *, MemBuf * mb);
+extern void allocate_new_swapdir(cacheSwap *);
+extern void self_destruct(void);
+extern int GetInteger(void);
+
+/* extra functions from cache_cf.c useful for lib modules */
+extern void default_line(const char *);
+extern PARSER_PARSE parse_int;
+extern PARSER_PARSE parse_eol;
+extern PARSER_PARSE parse_wordlist;
+extern PARSER_PARSE parse_wordlistFromFile;
+extern PARSER_FREE  free_wordlist;
+extern PARSER_DUMP  dump_wordlist;
+extern void requirePathnameExists(const char *name, const char *path);
+extern PARSER_PARSE parse_time_t;
+
+/* read from a file. Acts like strtok, but reads tokens from a file. */
+extern char * strtokFile(void);
+
+/* support for dynamic cache types */
+extern void parserRegisterType(const char *, PARSER_PARSE *, PARSER_FREE *, PARSER_DUMP *);
+extern void parserDeregisterType(parserTypeNode *);
+extern parserTypeNode *parserTypeByName(const char *);
+/* name, type */
+extern void parserRegisterName(parserNameNode *, const char *, parserTypeNode *, void *, PARSER_DEFAULT_NONE *, PARSER_NAME_DOCUMENT *, PARSER_POST_PARSE *);
+extern void parserDeregisterName(parserNameNode *);
+extern parserNameNode *parserNameByName(const char *);
+
+/* heirarchical parsing */
+//extern void parserRegisterInstanceType(parserNameNode *, const char *, PARSER_PARSE *, PARSER_FREE *, PARSER_DUMP *);
+
+
+void * parserRegisterInstanceName(const char *, parserTypeNode *, PARSER_DEFAULT_NONE *, PARSER_POST_PARSE *);
+extern instance_node *InstanceByNameStr(instance_name *, const char *);
+extern int parse_directive(parserNameNode *);
+
+#endif /* _SQUID_PARSER_H_ */
Index: squid/include/version.h
diff -u squid/include/version.h:1.4 squid/include/version.h:1.4.30.1
--- squid/include/version.h:1.4	Tue Nov 14 05:03:47 2000
+++ squid/include/version.h	Wed Feb 21 02:21:53 2001
@@ -4,7 +4,7 @@
  *  SQUID_VERSION - String for version id of this distribution
  */
 #ifndef SQUID_VERSION
-#define SQUID_VERSION	"2.5.DEVEL"
+#define SQUID_VERSION	"2.5.DEVEL-Modules"
 #endif
 
 #ifndef SQUID_RELEASE_TIME
Index: squid/src/Makefile.in
diff -u squid/src/Makefile.in:1.10 squid/src/Makefile.in:1.7.4.10
--- squid/src/Makefile.in:1.10	Sat May  5 13:47:38 2001
+++ squid/src/Makefile.in	Sat May 12 06:06:03 2001
@@ -18,7 +18,7 @@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
-SUBDIRS		= fs repl auth
+SUBDIRS		= fs repl auth modules
 
 # Gotta love the DOS legacy
 #
@@ -51,6 +51,8 @@
 
 AUTH_OBJS	= @AUTH_OBJS@
 AUTH_MODULES	= @AUTH_MODULES@
+INTERNAL_MODULE_OBJS	= @CONF_MODULE_OBJS@
+INTERNAL_MODULES	= @CONF_MODULES@
 CC		= @CC@
 MAKEDEPEND	= @MAKEDEPEND@
 INSTALL		= @INSTALL@
@@ -95,7 +97,6 @@
 		access_log.o \
 		acl.o \
 		asn.o \
-		auth_modules.o \
 		authenticate.o \
 		cache_cf.o \
 		CacheDigest.o \
@@ -138,6 +139,7 @@
 		icp_v3.o \
 		ident.o \
 		internal.o \
+		internal_modules.o \
 		ipc.o \
 		ipcache.o \
 		@LEAKFINDER_OBJS@ \
@@ -147,6 +149,7 @@
 		MemPool.o \
 		MemBuf.o \
 		mime.o \
+		modules.o \
 		multicast.o \
 		neighbors.o \
 		net_db.o \
@@ -157,7 +160,6 @@
 		redirect.o \
 		referer.o \
 		refresh.o \
-		repl_modules.o \
 		send-announce.o \
 		@SNMP_OBJS@ \
 		ssl.o \
@@ -173,7 +175,6 @@
 		store_dir.o \
 		store_key_md5.o \
 		store_log.o \
-		store_modules.o \
 		store_rebuild.o \
 		store_swapin.o \
 		store_swapmeta.o \
@@ -206,19 +207,14 @@
 DEFAULTS        = \
 	-DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
 
-all:    squid.conf
-	@for dir in $(SUBDIRS); do \
-		echo "Making $@ in $$dir..."; \
-		(cd $$dir ; $(MAKE) $(MFLAGS) prefix="$(prefix)" $@) || exit 1; \
-	done
-	@$(MAKE) $(MFLAGS) $(PROGS) $(UTILS) $(SUID_UTILS) $(CGIPROGS)
+all:    squid.conf squid.conf.old $(PROGS) $(UTILS) $(SUID_UTILS) $(CGIPROGS)
 
 $(OBJS): $(top_srcdir)/include/version.h ../include/autoconf.h
 
 $(SNMP_OBJS): ../snmplib/libsnmp.a $(top_srcdir)/include/cache_snmp.h
 
-$(SQUID_EXE): $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS)
-	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS) $(SQUID_LIBS)
+$(SQUID_EXE): $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS) $(INTERNAL_MODULE_OBJS)
+	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS) $(INTERNAL_MODULE_OBJS) $(SQUID_LIBS)
 
 globals.o: globals.c Makefile
 	$(CC) -c globals.c $(CFLAGS) -I$(srcdir) $(DEFAULTS)
@@ -255,8 +251,11 @@
 
 cache_cf.o: cf_parser.c
 
-squid.conf: cf_parser.c
-	@sh -c "test -f squid.conf || ./cf_gen cf.data"
+squid.conf.old: cf_parser.c
+	@sh -c "test -f squid.conf.old || ./cf_gen cf.data"
+
+squid.conf: $(SQUID_EXE)
+	@sh -c "./$(SQUID_EXE) -c internalonly -c all > squid.conf"
 
 cf_parser.c: cf.data cf_gen
 	./cf_gen cf.data
@@ -287,35 +286,35 @@
 	s%@DEFAULT_PREFIX@%$(DEFAULT_PREFIX)%g;"\
 	< $(srcdir)/cf.data.pre >$@
 
-store_modules.c: store_modules.sh Makefile 
-	sh $(srcdir)/store_modules.sh $(STORE_MODULES) >store_modules.c
+$(STORE_OBJS): store_modules
 
-store_modules.o: store_modules.c
-	$(CC) -c store_modules.c $(CFLAGS) -I$(srcdir)
+store_modules:
+	@echo "Making all in fs..."; \
+	 (cd fs ; $(MAKE) $(MFLAGS) prefix="$(prefix)" all) || exit 1;
 
-$(STORE_OBJS):
-	@sh -c "cd `dirname $@` && $(MAKE) $(MFLAGS) `basename $@`"
+$(REPL_OBJS): repl_modules
 
-repl_modules.c: repl_modules.sh Makefile 
-	sh $(srcdir)/repl_modules.sh $(REPL_POLICIES) >repl_modules.c
+repl_modules:
+	@echo "Making all in repl..."; \
+	 (cd repl ; $(MAKE) $(MFLAGS) prefix="$(prefix)" all) || exit 1;
 
-repl_modules.o: repl_modules.c
-	$(CC) -c repl_modules.c $(CFLAGS) -I$(srcdir)
+$(AUTH_OBJS): auth_modules
 
-$(REPL_OBJS):
-	@sh -c "cd `dirname $@` && $(MAKE) $(MFLAGS) `basename $@`"
+auth_modules:
+	@echo "Making all in auth..."; \
+	 (cd auth ; $(MAKE) $(MFLAGS) prefix="$(prefix)" all) || exit 1;
 
-repl_modules repl/stamp:
-	@sh -c "cd repl && $(MAKE) all"
+internal_modules.c: internal_modules.sh Makefile
+	sh $(srcdir)/internal_modules.sh $(INTERNAL_MODULES) $(AUTH_MODULES) $(REPL_POLICIES) $(STORE_MODULES) >internal_modules.c
 
-auth_modules.c: auth_modules.sh Makefile
-	sh $(srcdir)/auth_modules.sh $(AUTH_MODULES) >auth_modules.c
+internal_modules.o: internal_modules.c
+	$(CC) -c internal_modules.c $(CFLAGS) -I$(srcdir)
 
-auth_modules.o: auth_modules.c
-	$(CC) -c auth_modules.c $(CFLAGS) -I$(srcdir)
+$(INTERNAL_MODULE_OBJS): internal_modules
 
-$(AUTH_OBJS):
-	@sh -c "cd `dirname $@` && $(MAKE) $(MFLAGS) `basename $@`"
+internal_modules:
+	@echo "Making all in modules..."; \
+	 (cd modules ; $(MAKE) $(MFLAGS) prefix="$(prefix)" all) || exit 1;
 
 install-mkdirs:
 	-@if test ! -d $(prefix); then \
@@ -425,7 +424,7 @@
 clean: 
 	-rm -rf *.o *pure_* core $(PROGS) $(UTILS) $(CGIPROGS) $(SUID_UTILS)
 	-rm -f cf_gen cf_gen_defines.h cf_parser.c cf.data globals.c string_arrays.c
-	-rm -f store_modules.c repl_modules.c auth_modules.c squid.conf
+	-rm -f internal_modules.c squid.conf
 	@for dir in $(SUBDIRS); do \
 		echo "Making $@ in $$dir..."; \
 		(cd $$dir ; $(MAKE) $(MFLAGS) prefix="$(prefix)" $@) || exit 1; \
Index: squid/src/MemPool.c
diff -u squid/src/MemPool.c:1.5 squid/src/MemPool.c:1.5.8.1
--- squid/src/MemPool.c:1.5	Fri Jan 12 00:20:32 2001
+++ squid/src/MemPool.c	Wed Apr 25 05:28:59 2001
@@ -118,13 +118,14 @@
     int dirty_count = 0;
     for (i = 0; i < Pools.count; i++) {
 	MemPool *pool = Pools.items[i];
-	if (memPoolInUseCount(pool)) {
-	    memPoolDescribe(pool);
-	    dirty_count++;
-	} else {
-	    memPoolDestroy(pool);
-	    Pools.items[i] = NULL;
-	}
+        if (pool)
+	    if (memPoolInUseCount(pool)) {
+		memPoolDescribe(pool);
+		dirty_count++;
+	    } else {
+		memPoolDestroy(pool);
+		Pools.items[i] = NULL;
+	    }
     }
     if (dirty_count)
 	debug(63, 2) ("memCleanModule: %d pools are left dirty\n", dirty_count);
@@ -221,9 +222,13 @@
 void
 memPoolDestroy(MemPool * pool)
 {
+    int i;
     assert(pool);
     stackClean(&pool->pstack);
     xfree(pool);
+    for (i = 0; i < Pools.count; i++) 
+	if (Pools.items[i]==pool)
+	    Pools.items[i]=NULL;
 }
 
 void *
Index: squid/src/acl.c
diff -u squid/src/acl.c:1.29 squid/src/acl.c:1.21.4.22
--- squid/src/acl.c:1.29	Thu Apr  5 23:49:27 2001
+++ squid/src/acl.c	Sun May 13 04:28:36 2001
@@ -35,41 +35,53 @@
 
 #include "squid.h"
 #include "splay.h"
+#include "squid_parser.h"
+#include "acl.h"
 
-static int aclFromFile = 0;
-static FILE *aclFile;
+/* this is the list of acl names to parser types */
+static dlink_list aclNames = {NULL,NULL};
 
-static void aclParseDomainList(void *curlist);
-static void aclParseUserList(void **current);
-static void aclParseIpList(void *curlist);
+/* this is the parent instance_name that acls live under */
+static void * aclinstances = NULL;
+static aclName * proxy_auth_name = NULL;
+static aclName * proxy_auth_regex_name = NULL;
+
+MemPool * acl_pool = NULL;
+MemPool * acl_deny_info_list_pool = NULL;
+MemPool * acl_ip_data_pool = NULL;
+MemPool * acl_name_list_pool = NULL;
+MemPool * acl_time_data_pool = NULL;
+MemPool * acl_proxy_auth_match_pool = NULL;
+MemPool * acl_user_data_pool = NULL;
+acl * AclMatchedAcl = NULL;
+
+static PARSER_PARSE aclParseDomainList;
+static PARSER_PARSE aclParseUserList;
+static PARSER_PARSE aclParseIpList;
+static PARSER_PARSE aclParseRegexList;
 #if UNUSED_CODE
 static void aclParseIntlist(void *curlist);
 #endif
-#if SQUID_SNMP
-static void aclParseWordList(void *curlist);
-#endif
-static void aclParseProtoList(void *curlist);
-static void aclParseMethodList(void *curlist);
-static void aclParseTimeSpec(void *curlist);
-static void aclParseIntRange(void *curlist);
-static char *strtokFile(void);
+static PARSER_PARSE aclParseProtoList;
+static PARSER_PARSE aclParseMethodList;
+static PARSER_PARSE aclParseTimeSpec;
+static PARSER_PARSE aclParseIntRange;
+static PARSER_PARSE parse_denyinfo;
 static void aclDestroyAclList(acl_list * list);
-static void aclDestroyTimeList(acl_time_data * data);
-static void aclDestroyIntRange(intrange *);
+static PARSER_FREE aclDestroyTimeSpecList;
+static PARSER_FREE aclDestroyIntRange;
+static PARSER_FREE free_denyinfo;
 static void aclLookupProxyAuthStart(aclCheck_t * checklist);
 static void aclLookupProxyAuthDone(void *data, char *result);
 static struct _acl *aclFindByName(const char *name);
-static int aclMatchAcl(struct _acl *, aclCheck_t *);
 static int aclMatchIntegerRange(intrange * data, int i);
-static int aclMatchTime(acl_time_data * data, time_t when);
+static int aclMatchTimeSpec(acl_time_data * data, time_t when);
 static int aclMatchUser(void *proxyauth_acl, char *user);
-static int aclMatchIp(void *dataptr, struct in_addr c);
+static int aclMatchIp(void *, struct in_addr);
 static int aclMatchDomainList(void *dataptr, const char *);
-static int aclMatchIntegerRange(intrange * data, int i);
 #if SQUID_SNMP
 static int aclMatchWordList(wordlist *, const char *);
 #endif
-static squid_acl aclStrToType(const char *s);
 static int decode_addr(const char *, struct in_addr *, struct in_addr *);
 static void aclCheck(aclCheck_t * checklist);
 static void aclCheckCallback(aclCheck_t * checklist, allow_t answer);
@@ -88,6 +100,7 @@
 static wordlist *aclDumpIntRangeList(intrange * data);
 static wordlist *aclDumpProtoList(intlist * data);
 static wordlist *aclDumpMethodList(intlist * data);
+static PARSER_DUMP dump_denyinfo;
 static SPLAYCMP aclIpNetworkCompare;
 static SPLAYCMP aclHostDomainCompare;
 static SPLAYCMP aclDomainCompare;
@@ -95,211 +108,105 @@
 static SPLAYWALKEE aclDumpDomainListWalkee;
 static SPLAYFREE aclFreeIpData;
 
-#if USE_ARP_ACL
-static void aclParseArpList(void *curlist);
-static int decode_eth(const char *asc, char *eth);
-static int aclMatchArp(void *dataptr, struct in_addr c);
-static wordlist *aclDumpArpList(void *);
-static SPLAYCMP aclArpCompare;
-static SPLAYWALKEE aclDumpArpListWalkee;
-#endif
-static int aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, char *MatchParam);
-
-static char *
-strtokFile(void)
-{
-    char *t, *fn;
-    LOCAL_ARRAY(char, buf, 256);
-
-  strtok_again:
-    if (!aclFromFile) {
-	t = (strtok(NULL, w_space));
-	if (t && (*t == '\"' || *t == '\'')) {
-	    /* quote found, start reading from file */
-	    fn = ++t;
-	    while (*t && *t != '\"' && *t != '\'')
-		t++;
-	    *t = '\0';
-	    if ((aclFile = fopen(fn, "r")) == NULL) {
-		debug(28, 0) ("strtokFile: %s not found\n", fn);
-		return (NULL);
-	    }
-#if defined(_SQUID_CYGWIN_)
-	    setmode(fileno(aclFile), O_TEXT);
-#endif
-	    aclFromFile = 1;
-	} else {
-	    return t;
-	}
-    }
-    /* aclFromFile */
-    if (fgets(buf, 256, aclFile) == NULL) {
-	/* stop reading from file */
-	fclose(aclFile);
-	aclFromFile = 0;
-	goto strtok_again;
-    } else {
-	t = buf;
-	/* skip leading and trailing white space */
-	t += strspn(buf, w_space);
-	t[strcspn(t, w_space)] = '\0';
-	/* skip comments */
-	if (*t == '#')
-	    goto strtok_again;
-	/* skip blank lines */
-	if (!*t)
-	    goto strtok_again;
-	return t;
-    }
-}
+static int aclCacheMatchAcl(dlink_list * cache, acl *, char *MatchParam);
 
-static squid_acl
-aclStrToType(const char *s)
-{
-    if (!strcmp(s, "src"))
-	return ACL_SRC_IP;
-    if (!strcmp(s, "dst"))
-	return ACL_DST_IP;
-    if (!strcmp(s, "myip"))
-	return ACL_MY_IP;
-    if (!strcmp(s, "domain"))
-	return ACL_DST_DOMAIN;
-    if (!strcmp(s, "dstdomain"))
-	return ACL_DST_DOMAIN;
-    if (!strcmp(s, "srcdomain"))
-	return ACL_SRC_DOMAIN;
-    if (!strcmp(s, "dstdom_regex"))
-	return ACL_DST_DOM_REGEX;
-    if (!strcmp(s, "srcdom_regex"))
-	return ACL_SRC_DOM_REGEX;
-    if (!strcmp(s, "time"))
-	return ACL_TIME;
-    if (!strcmp(s, "pattern"))
-	return ACL_URLPATH_REGEX;
-    if (!strcmp(s, "urlpath_regex"))
-	return ACL_URLPATH_REGEX;
-    if (!strcmp(s, "url_regex"))
-	return ACL_URL_REGEX;
-    if (!strcmp(s, "port"))
-	return ACL_URL_PORT;
-    if (!strcmp(s, "myport"))
-	return ACL_MY_PORT;
-    if (!strcmp(s, "maxconn"))
-	return ACL_MAXCONN;
-#if USE_IDENT
-    if (!strcmp(s, "ident"))
-	return ACL_IDENT;
-    if (!strcmp(s, "ident_regex"))
-	return ACL_IDENT_REGEX;
-#endif
-    if (!strncmp(s, "proto", 5))
-	return ACL_PROTO;
-    if (!strcmp(s, "method"))
-	return ACL_METHOD;
-    if (!strcmp(s, "browser"))
-	return ACL_BROWSER;
-    if (!strcmp(s, "proxy_auth"))
-	return ACL_PROXY_AUTH;
-    if (!strcmp(s, "proxy_auth_regex"))
-	return ACL_PROXY_AUTH_REGEX;
-    if (!strcmp(s, "src_as"))
-	return ACL_SRC_ASN;
-    if (!strcmp(s, "dst_as"))
-	return ACL_DST_ASN;
-#if SQUID_SNMP
-    if (!strcmp(s, "snmp_community"))
-	return ACL_SNMP_COMMUNITY;
-#endif
-#if SRC_RTT_NOT_YET_FINISHED
-    if (!strcmp(s, "src_rtt"))
-	return ACL_NETDB_SRC_RTT;
-#endif
-#if USE_ARP_ACL
-    if (!strcmp(s, "arp"))
-	return ACL_SRC_ARP;
-#endif
-    if (!strcmp(s, "req_mime_type"))
-	return ACL_REQ_MIME_TYPE;
-    if (!strcmp(s, "rep_mime_type"))
-	return ACL_REP_MIME_TYPE;
-    return ACL_NONE;
-}
-
-const char *
-aclTypeToStr(squid_acl type)
-{
-    if (type == ACL_SRC_IP)
-	return "src";
-    if (type == ACL_DST_IP)
-	return "dst";
-    if (type == ACL_MY_IP)
-	return "myip";
-    if (type == ACL_DST_DOMAIN)
-	return "dstdomain";
-    if (type == ACL_SRC_DOMAIN)
-	return "srcdomain";
-    if (type == ACL_DST_DOM_REGEX)
-	return "dstdom_regex";
-    if (type == ACL_SRC_DOM_REGEX)
-	return "srcdom_regex";
-    if (type == ACL_TIME)
-	return "time";
-    if (type == ACL_URLPATH_REGEX)
-	return "urlpath_regex";
-    if (type == ACL_URL_REGEX)
-	return "url_regex";
-    if (type == ACL_URL_PORT)
-	return "port";
-    if (type == ACL_MY_PORT)
-	return "myport";
-    if (type == ACL_MAXCONN)
-	return "maxconn";
-#if USE_IDENT
-    if (type == ACL_IDENT)
-	return "ident";
-    if (type == ACL_IDENT_REGEX)
-	return "ident_regex";
-#endif
-    if (type == ACL_PROTO)
-	return "proto";
-    if (type == ACL_METHOD)
-	return "method";
-    if (type == ACL_BROWSER)
-	return "browser";
-    if (type == ACL_PROXY_AUTH)
-	return "proxy_auth";
-    if (type == ACL_PROXY_AUTH_REGEX)
-	return "proxy_auth_regex";
-    if (type == ACL_SRC_ASN)
-	return "src_as";
-    if (type == ACL_DST_ASN)
-	return "dst_as";
-#if SQUID_SNMP
-    if (type == ACL_SNMP_COMMUNITY)
-	return "snmp_community";
-#endif
-#if SRC_RTT_NOT_YET_FINISHED
-    if (type == ACL_NETDB_SRC_RTT)
-	return "src_rtt";
-#endif
-#if USE_ARP_ACL
-    if (type == ACL_SRC_ARP)
-	return "arp";
-#endif
-    if (type == ACL_REQ_MIME_TYPE)
-	return "req_mime_type";
-    if (type == ACL_REP_MIME_TYPE)
-	return "rep_mime_type";
-    return "ERROR";
+static ACLMATCH aclMatchSrc;
+static ACLMATCH aclMatchDst;
+static ACLMATCH aclMatchMyip;
+static ACLMATCH aclMatchSrcDomain;
+static ACLMATCH aclMatchDstDomain;
+static ACLMATCH aclMatchDstDomain;
+static ACLMATCH aclMatchSrcDomain;
+static ACLMATCH aclMatchSrcDomain;
+static ACLMATCH aclMatchUrlPathRegex;
+static ACLMATCH aclMatchUrlPathRegex;
+static ACLMATCH aclMatchUrlRegex;
+static ACLMATCH aclMatchBrowser;
+static ACLMATCH aclMatchRepMimeType;
+static ACLMATCH aclMatchReqMimeType;
+static ACLMATCH aclMatchIdent;
+static ACLMATCH aclMatchIdentRegex;
+static ACLMATCH aclMatchProxyAuthModule;
+static ACLMATCH aclMatchTime;
+static ACLMATCH aclMatchMaxConn;
+static ACLMATCH aclMatchUrlPort;
+static ACLMATCH aclMatchMyPort;
+static ACLMATCH aclMatchSNMPCommunity;
+static ACLMATCH aclMatchProto;
+static ACLMATCH aclMatchMethod;
+static ACLMATCH aclMatchSrcAsn;
+static ACLMATCH aclMatchDstAsn;
+#if SRC_RTT_NOT_YET_FINISHED 
+static ACLMATCH aclMatchSrcRTT;
+#endif
+
+CBDATA_TYPE (aclName);
+
+static void
+aclNameFree(void *data)
+{
+    aclName *Name=data;
+    dlinkDelete(&Name->node,&aclNames);
+    debug(3,0)("aclNameFree freed name %s\n",Name->namestr);
+    safe_free(Name->namestr);
+    cbdataUnlock(Name->type);
+}
+
+
+/* FIXME: should this be merged into cache_cf ? */
+aclName *
+aclNameByName(const char *name)
+{
+    dlink_node *node;
+    node=aclNames.head;
+    while (node && strcmp(((aclName *)node->data)->namestr,name)) {
+        node=node->next;
+
+    }
+    if (node)
+        return (aclName *)node->data;
+    else
+        return NULL;
+}
+
+aclName * 
+aclRegisterAclName(const char *namestr, parserTypeNode *parserType, ACLMATCH *Match) {
+    aclName *Name;
+    if ((Name=aclNameByName(namestr))==NULL) {
+	/* register the type */
+	debug(28,3)("aclRegisterAclName new name '%s'\n",Name);
+    if (aclNames.head == NULL)
+        CBDATA_INIT_TYPE_FREECB(aclName,aclNameFree);
+    Name=cbdataAlloc(aclName);
+    Name->namestr=xstrdup(namestr);
+    Name->type=parserType;
+    Name->match=Match;
+    cbdataLock(parserType);
+//    Name->default_none=default_none;
+//    Name->post_parse_func=post_parse_func;
+    dlinkAddTail(Name,&Name->node,&aclNames);
+    return Name;
+} else {
+    debug(28,0)("parserRegisterInstanceName already registered name '%s'\n",Name);
+    return NULL;
+    /* TODO: fatal this */
+    }
 }
 
 static acl *
 aclFindByName(const char *name)
 {
+    instance_node *acl_instance;
+#if NEVER
     acl *a;
     for (a = Config.aclList; a; a = a->next)
 	if (!strcasecmp(a->name, name))
 	    return a;
+#endif
+    acl_instance=InstanceByNameStr(aclinstances,name);
+    if (acl_instance)
+	return acl_instance->data;
+    
     return NULL;
 }
 
@@ -321,7 +228,7 @@
 #endif
 
 static void
-aclParseIntRange(void *curlist)
+aclParseIntRange(parserNameNode *parserName, void *curlist)
 {
     intrange **Tail;
     intrange *q = NULL;
@@ -341,7 +248,7 @@
 }
 
 static void
-aclParseProtoList(void *curlist)
+aclParseProtoList(parserNameNode *parserName, void *curlist)
 {
     intlist **Tail;
     intlist *q = NULL;
@@ -356,7 +263,7 @@
 }
 
 static void
-aclParseMethodList(void *curlist)
+aclParseMethodList(parserNameNode *parserName, void *curlist)
 {
     intlist **Tail;
     intlist *q = NULL;
@@ -370,6 +277,143 @@
     }
 }
 
+static void
+name_document_deny_info(void){
+        printf(
+"#  TAG: deny_info"
+"\n"
+"#\tUsage:   deny_info err_page_name acl\n"
+"#\tExample: deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys\n"
+"#\n"
+"#\tThis can be used to return a ERR_ page for requests which\n"
+"#\tdo not pass the 'http_access' rules.  A single ACL will cause\n"
+"#\tthe http_access check to fail.  If a 'deny_info' line exists\n"
+"#\tfor that ACL then Squid returns a corresponding error page.\n"
+"#\n"
+"#\tYou may use ERR_ pages that come with Squid or create your own pages\n"
+"#\tand put them into the configured errors/ directory.\n"
+"#\n"
+"#Default:\n"
+"# none\n"
+"\n"
+        );}
+
+static void
+parse_denyinfo(parserNameNode *parserName, void * data)
+{
+    acl_deny_info_list ** head=( acl_deny_info_list **)data;
+/* maex@space.net (05.09.96)
+ *    get the info for redirecting "access denied" to info pages
+ *      TODO (probably ;-)
+ *      currently there is no optimization for
+ *      - more than one deny_info line with the same url
+ *      - a check, whether the given acl really is defined
+ *      - a check, whether an acl is added more than once for the same url
+ */
+    char *t = NULL;
+    acl_deny_info_list *A = NULL;
+    acl_deny_info_list *B = NULL;
+    acl_deny_info_list **T = NULL;
+    acl_name_list *L = NULL;
+    acl_name_list **Tail = NULL;
+
+    /* first expect a page name */
+    if ((t = strtok(NULL, w_space)) == NULL) {
+        debug(28, 0) ("%s line %d: %s\n",
+            cfg_filename, config_lineno, config_input_line);
+        debug(28, 0) ("parse_denyinfo: missing 'error page' parameter.\n");
+        return;
+    }
+    A = memPoolAlloc(acl_deny_info_list_pool);
+    A->err_page_id = errorReservePageId(t);
+    A->err_page_name = xstrdup(t);
+    A->next = (acl_deny_info_list *) NULL;
+    /* next expect a list of ACL names */
+    /* FIXME: verify the names exist, and look them up and lock them.
+     * Possibly a postparse thing. 
+     */	
+    Tail = &A->acl_list;
+    while ((t = strtok(NULL, w_space))) {
+        L = memPoolAlloc(acl_name_list_pool);
+        xstrncpy(L->name, t, ACL_NAME_SZ);
+        *Tail = L;
+        Tail = &L->next;
+    }
+    if (A->acl_list == NULL) {
+        debug(28, 0) ("%s line %d: %s\n",
+            cfg_filename, config_lineno, config_input_line);
+        debug(28, 0) ("parse_denyinfo: deny_info line contains no ACL's, skipping\n");
+        memPoolFree(acl_deny_info_list_pool, A);
+        return;
+    }
+    for (B = *head, T = head; B; T = &B->next, B = B->next);    /* find the tail */
+    *T = A;
+
+    cbdataLock(parserName);
+}
+
+static void
+dump_denyinfo(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl_deny_info_list *var=*(acl_deny_info_list **)data;
+    acl_name_list *a;
+    while (var != NULL) {
+        storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
+        for (a = var->acl_list; a != NULL; a = a->next)
+            storeAppendPrintf(entry, " %s", a->name);
+        storeAppendPrintf(entry, "\n");
+        var = var->next;
+    }
+}
+
+static void
+free_denyinfo(parserNameNode *parserName, void * data)
+{
+    acl_deny_info_list ** list=( acl_deny_info_list **)data;
+    acl_deny_info_list *a = NULL;
+    acl_deny_info_list *a_next = NULL;
+    acl_name_list *l = NULL;
+    acl_name_list *l_next = NULL;
+    for (a = *list; a; a = a_next) {
+        for (l = a->acl_list; l; l = l_next) {
+            l_next = l->next;
+            memPoolFree(acl_name_list_pool, l);
+            l = NULL;
+        }
+        a_next = a->next;
+	safe_free (a->err_page_name);
+        memPoolFree(acl_deny_info_list_pool, a);
+        a = NULL;
+        cbdataUnlock(parserName);
+    }
+    *list = NULL;
+}
+
+#if 0
+/* maex@space.net (06.09.1996)
+ *    destroy an _acl_deny_info_list */
+
+void
+aclDestroyDenyInfoList(acl_deny_info_list ** list)
+{
+    acl_deny_info_list *a = NULL;
+    acl_deny_info_list *a_next = NULL;
+    acl_name_list *l = NULL;
+    acl_name_list *l_next = NULL;
+
+    for (a = *list; a; a = a_next) {
+        for (l = a->acl_list; l; l = l_next) {
+            l_next = l->next;
+            safe_free(l);
+        }
+        a_next = a->next;
+        xfree(a->err_page_name);
+        memPoolFree(acl_deny_info_list_pool, a);
+    }
+    *list = NULL;
+}
+#endif
+
 /*
  * Decode a ascii representation (asc) of a IP adress, and place
  * adress and netmask information in addr and mask.
@@ -416,7 +460,6 @@
     return 1;
 }
 
-
 #define SCAN_ACL1       "%[0123456789.]-%[0123456789.]/%[0123456789.]"
 #define SCAN_ACL2       "%[0123456789.]-%[0123456789.]%c"
 #define SCAN_ACL3       "%[0123456789.]/%[0123456789.]"
@@ -428,7 +471,7 @@
     LOCAL_ARRAY(char, addr1, 256);
     LOCAL_ARRAY(char, addr2, 256);
     LOCAL_ARRAY(char, mask, 256);
-    acl_ip_data *q = memAllocate(MEM_ACL_IP_DATA);
+    acl_ip_data *q = memPoolAlloc(acl_ip_data_pool);
     acl_ip_data *r;
     acl_ip_data **Q;
     struct hostent *hp;
@@ -465,7 +508,7 @@
 	Q = &q;
 	for (x = hp->h_addr_list; x != NULL && *x != NULL; x++) {
 	    if ((r = *Q) == NULL)
-		r = *Q = memAllocate(MEM_ACL_IP_DATA);
+		r = *Q = memPoolAlloc(acl_ip_data_pool);
 	    xmemcpy(&r->addr1.s_addr, *x, sizeof(r->addr1.s_addr));
 	    r->addr2.s_addr = 0;
 	    r->mask.s_addr = no_addr.s_addr;	/* 255.255.255.255 */
@@ -516,7 +559,7 @@
 /******************/
 
 static void
-aclParseIpList(void *curlist)
+aclParseIpList(parserNameNode *parserName, void *curlist)
 {
     char *t = NULL;
     splayNode **Top = curlist;
@@ -531,14 +574,14 @@
 }
 
 static void
-aclParseTimeSpec(void *curlist)
+aclParseTimeSpec(parserNameNode *parserName, void *curlist)
 {
     acl_time_data *q = NULL;
     acl_time_data **Tail;
     int h1, m1, h2, m2;
     char *t = NULL;
     for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
-    q = memAllocate(MEM_ACL_TIME_DATA);
+    q = memPoolAlloc(acl_time_data_pool);
     while ((t = strtokFile())) {
 	if (*t < '0' || *t > '9') {
 	    /* assume its day-of-week spec */
@@ -584,7 +627,7 @@
 		debug(28, 0) ("%s line %d: %s\n",
 		    cfg_filename, config_lineno, config_input_line);
 		debug(28, 0) ("aclParseTimeSpec: IGNORING Bad time range\n");
-		memFree(q, MEM_ACL_TIME_DATA);
+		memPoolFree(acl_time_data_pool, q);
 		return;
 	    }
 	    q->start = h1 * 60 + m1;
@@ -593,7 +636,7 @@
 		debug(28, 0) ("%s line %d: %s\n",
 		    cfg_filename, config_lineno, config_input_line);
 		debug(28, 0) ("aclParseTimeSpec: IGNORING Reversed time range\n");
-		memFree(q, MEM_ACL_TIME_DATA);
+		memPoolFree(acl_time_data_pool, q);
 		return;
 	    }
 	}
@@ -607,7 +650,7 @@
 }
 
 void
-aclParseRegexList(void *curlist)
+aclParseRegexList(parserNameNode *parserName, void *curlist)
 {
     relist **Tail;
     relist *q = NULL;
@@ -642,19 +685,10 @@
     }
 }
 
-#if SQUID_SNMP
-static void
-aclParseWordList(void *curlist)
-{
-    char *t = NULL;
-    while ((t = strtokFile()))
-	wordlistAdd(curlist, t);
-}
-#endif
-
 static void
-aclParseUserList(void **current)
+aclParseUserList(parserNameNode *parserName, void *curlist)
 {
+    void **current= curlist;
     char *t = NULL;
     acl_user_data *data;
     splayNode *Top = NULL;
@@ -662,7 +696,7 @@
     debug(28, 2) ("aclParseUserList: parsing user list\n");
     if (*current == NULL) {
 	debug(28, 3) ("aclParseUserList: current is null. Creating\n");
-	*current = memAllocate(MEM_ACL_USER_DATA);
+	*current = memPoolAlloc(acl_user_data_pool);
     }
     data = *current;
     Top = data->names;
@@ -700,7 +734,7 @@
 /**********************/
 
 static void
-aclParseDomainList(void *curlist)
+aclParseDomainList(parserNameNode *parserName, void *curlist)
 {
     char *t = NULL;
     splayNode **Top = curlist;
@@ -711,157 +745,84 @@
 }
 
 void
-aclParseAclLine(acl ** head)
+aclParseAclLine(parserNameNode *parserName, void *data)
 {
+    acl ** head=(acl **)data;
+    aclName *aclname;
+
     /* we're already using strtok() to grok the line */
-    char *t = NULL;
+    char *token = NULL;
     acl *A = NULL;
-    LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
-    squid_acl acltype;
-    int new_acl = 0;
+//    LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
+    parserTypeNode * parserType=NULL;
 
-    /* snarf the ACL name */
-    if ((t = strtok(NULL, w_space)) == NULL) {
-	debug(28, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(28, 0) ("aclParseAclLine: missing ACL name.\n");
-	return;
-    }
-    xstrncpy(aclname, t, ACL_NAME_SZ);
     /* snarf the ACL type */
-    if ((t = strtok(NULL, w_space)) == NULL) {
+    if ((token = strtok(NULL, w_space)) == NULL) {
 	debug(28, 0) ("%s line %d: %s\n",
 	    cfg_filename, config_lineno, config_input_line);
 	debug(28, 0) ("aclParseAclLine: missing ACL type.\n");
 	return;
     }
-    if ((acltype = aclStrToType(t)) == ACL_NONE) {
+
+    /* is there a aclname for this? */
+    debug (28,0) ("acl name string %s\n",token);
+    aclname = aclNameByName(token);
+    if (aclname) {
+        parserType=aclname->type;
+        debug (28,0) ("found parserType %s\n",parserType->typestr);
+    } else {
 	debug(28, 0) ("%s line %d: %s\n",
 	    cfg_filename, config_lineno, config_input_line);
-	debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", t);
+	debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", token);
+	/* flush the line */
+	while (strtok(NULL, w_space));
 	return;
     }
-    if ((A = aclFindByName(aclname)) == NULL) {
-	debug(28, 3) ("aclParseAclLine: Creating ACL '%s'\n", aclname);
-	A = memAllocate(MEM_ACL);
-	xstrncpy(A->name, aclname, ACL_NAME_SZ);
-	A->type = acltype;
-	A->cfgline = xstrdup(config_input_line);
-	new_acl = 1;
-    } else {
-	if (acltype != A->type) {
-	    debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different type, skipping.\n", A->name);
-	    return;
-	}
-	debug(28, 3) ("aclParseAclLine: Appending to '%s'\n", aclname);
-	new_acl = 0;
+
+    /* We only get called once to assign the function: if data is already used, bomb */
+    if (*head) {
+        debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different type, skipp
+ing.\n", parserName->namestr);
+        /* flush the line */
+        while (strtok(NULL, w_space));
+        return;
     }
+
+    debug(28, 3) ("aclParseAclLine: Creating new ACL\n");
+    A = memPoolAlloc(acl_pool);
+    xstrncpy(A->name, parserName->namestr, ACL_NAME_SZ);
+    A->cfgline = xstrdup(config_input_line);
+    A->aclname=aclname; 
+
     /*
      * Here we set AclMatchedName in case we need to use it in a
      * warning message in aclDomainCompare().
      */
-    AclMatchedName = aclname;	/* ugly */
-    switch (A->type) {
-    case ACL_SRC_IP:
-    case ACL_DST_IP:
-    case ACL_MY_IP:
-	aclParseIpList(&A->data);
-	break;
-    case ACL_SRC_DOMAIN:
-    case ACL_DST_DOMAIN:
-	aclParseDomainList(&A->data);
-	break;
-    case ACL_TIME:
-	aclParseTimeSpec(&A->data);
-	break;
-    case ACL_URL_REGEX:
-    case ACL_URLPATH_REGEX:
-    case ACL_BROWSER:
-    case ACL_SRC_DOM_REGEX:
-    case ACL_DST_DOM_REGEX:
-    case ACL_REQ_MIME_TYPE:
-    case ACL_REP_MIME_TYPE:
-	aclParseRegexList(&A->data);
-	break;
-    case ACL_SRC_ASN:
-    case ACL_MAXCONN:
-    case ACL_DST_ASN:
-#if SRC_RTT_NOT_YET_FINISHED
-    case ACL_NETDB_SRC_RTT:
-	aclParseIntlist(&A->data);
-	break;
-#endif
-    case ACL_URL_PORT:
-    case ACL_MY_PORT:
-	aclParseIntRange(&A->data);
-	break;
-#if USE_IDENT
-    case ACL_IDENT:
-	aclParseUserList(&A->data);
-	break;
-    case ACL_IDENT_REGEX:
-	aclParseRegexList(&A->data);
-	break;
-#endif
-    case ACL_PROTO:
-	aclParseProtoList(&A->data);
-	break;
-    case ACL_METHOD:
-	aclParseMethodList(&A->data);
-	break;
-    case ACL_PROXY_AUTH:
-	if (authenticateSchemeCount() == 0) {
-	    debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
-because no authentication schemes were compiled.\n", A->cfgline);
-	} else if (authenticateActiveSchemeCount() == 0) {
-	    debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
-because no authentication schemes are fully configured.\n", A->cfgline);
-	} else {
-	    aclParseUserList(&A->data);
-	}
-	break;
-    case ACL_PROXY_AUTH_REGEX:
-	if (authenticateSchemeCount() == 0) {
-	    debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
-because no authentication schemes were compiled.\n", A->cfgline);
-	} else if (authenticateActiveSchemeCount() == 0) {
-	    debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
-because no authentication schemes are fully configured.\n", A->cfgline);
-	} else {
-	    aclParseRegexList(&A->data);
-	}
-	break;
-#if SQUID_SNMP
-    case ACL_SNMP_COMMUNITY:
-	aclParseWordList(&A->data);
-	break;
-#endif
-#if USE_ARP_ACL
-    case ACL_SRC_ARP:
-	aclParseArpList(&A->data);
-	break;
-#endif
-    case ACL_NONE:
-    case ACL_ENUM_MAX:
-	fatal("Bad ACL type");
-	break;
-    }
+/*    AclMatchedName = aclname;	*/ /* ugly */
+/* TODO: it might be cleaner for the sub type should be registered via a one off 
+ * instance - no new registrations allowed. Ideally this is declaritive (list the 
+ * allowed types, specify one type per child */
+    /* back strtok up a step. Yummy - Should be macroised */
+    *(token + strlen(token))=' ';
+    *(token-2) = 'A';
+    *(token-1) = ' ';
+    strtok(token-2,w_space);
+debug(28,0)("***%s\n",A->aclname->namestr);
+    parserRegisterName(parserName, A->aclname->namestr, parserType, &(A->data), NULL, NULL, NULL);
+    /* parse the rest of the line. */
+    parse_directive(parserName);
     /*
      * Clear AclMatchedName from our temporary hack
      */
     AclMatchedName = NULL;	/* ugly */
-    if (!new_acl)
-	return;
     if (A->data == NULL) {
 	debug(28, 0) ("aclParseAclLine: IGNORING invalid ACL: %s\n",
 	    A->cfgline);
-	memFree(A, MEM_ACL);
+	memPoolFree(acl_pool, A);
 	return;
     }
-    /* append */
-    while (*head)
-	head = &(*head)->next;
     *head = A;
+
 }
 
 /* does name lookup, returns page_id */
@@ -888,66 +849,6 @@
     return ERR_NONE;
 }
 
-/* does name lookup, returns if it is a proxy_auth acl */
-int
-aclIsProxyAuth(const char *name)
-{
-    acl *a = aclFindByName(name);
-    if (a)
-	return a->type == ACL_PROXY_AUTH;
-    return 0;
-}
-
-
-/* maex@space.net (05.09.96)
- *    get the info for redirecting "access denied" to info pages
- *      TODO (probably ;-)
- *      currently there is no optimization for
- *      - more than one deny_info line with the same url
- *      - a check, whether the given acl really is defined
- *      - a check, whether an acl is added more than once for the same url
- */
-
-void
-aclParseDenyInfoLine(acl_deny_info_list ** head)
-{
-    char *t = NULL;
-    acl_deny_info_list *A = NULL;
-    acl_deny_info_list *B = NULL;
-    acl_deny_info_list **T = NULL;
-    acl_name_list *L = NULL;
-    acl_name_list **Tail = NULL;
-
-    /* first expect a page name */
-    if ((t = strtok(NULL, w_space)) == NULL) {
-	debug(28, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(28, 0) ("aclParseDenyInfoLine: missing 'error page' parameter.\n");
-	return;
-    }
-    A = memAllocate(MEM_ACL_DENY_INFO_LIST);
-    A->err_page_id = errorReservePageId(t);
-    A->err_page_name = xstrdup(t);
-    A->next = (acl_deny_info_list *) NULL;
-    /* next expect a list of ACL names */
-    Tail = &A->acl_list;
-    while ((t = strtok(NULL, w_space))) {
-	L = memAllocate(MEM_ACL_NAME_LIST);
-	xstrncpy(L->name, t, ACL_NAME_SZ);
-	*Tail = L;
-	Tail = &L->next;
-    }
-    if (A->acl_list == NULL) {
-	debug(28, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(28, 0) ("aclParseDenyInfoLine: deny_info line contains no ACL's, skipping\n");
-	memFree(A, MEM_ACL_DENY_INFO_LIST);
-	return;
-    }
-    for (B = *head, T = head; B; T = &B->next, B = B->next);	/* find the tail */
-    *T = A;
-}
-
 void
 aclParseAccessLine(acl_access ** head)
 {
@@ -1032,12 +933,100 @@
     return !splayLastResult;
 }
 
+static int
+aclMatchSrc(acl * ae, aclCheck_t *checklist, unsigned int flags)
+{
+    debug(28, 3) ("aclMatchSrc: checking '%s'\n", ae->cfgline);
+    return aclMatchIp(&ae->data, checklist->src_addr);
+}
+
+static int
+aclMatchMyip(acl *ae, aclCheck_t *checklist, unsigned int flags)
+{
+    debug(28, 3) ("aclMatchMyip: checking '%s'\n", ae->cfgline);
+    return aclMatchIp(&ae->data, checklist->my_addr);
+}
+
+static int
+aclMatchDst(acl * ae, aclCheck_t *checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    const ipcache_addrs *ia = NULL;
+    int k;
+    debug(28, 3) ("aclMatchDst: checking '%s'\n", ae->cfgline);
+    if (NULL == r) {
+	debug(28, 1) ("WARNING: '%s' ACL is used but there is no"
+	    " HTTP request -- access denied.\n", ae->name);
+	return 0;
+    }
+    ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
+    if (ia) {
+	if (checklist->lastcheckowner==ae) {
+	    checklist->lastcheckowner=NULL;
+	    checklist->lastcheckstate=ACL_LOOKUP_NONE;
+	}
+        for (k = 0; k < (int) ia->count; k++) {
+            if (aclMatchIp(&ae->data, ia->in_addrs[k]))
+                return 1;
+        }
+        return 0;
+    } else if (checklist->lastcheckowner==NULL) {
+	debug(28, 3) ("aclMatchDst: Can't yet compare '%s' ACL for '%s'\n",
+            ae->name, r->host);
+	checklist->lastcheckowner=ae;
+	checklist->lastcheckstate=ACL_LOOKUP_PENDING;
+	ipcache_nbgethostbyname(checklist->request->host,
+	    aclLookupDstIPDone, checklist);
+	return ACL_MATCH_NEED_LOOKUP;
+    } else if (checklist->lastcheckowner==ae) {
+	/* ACL_LOOKUP_DONE is/should be caught by if (ia) */
+        debug(28, 0) ("aclMatchDst: Probable bug *****"
+	    "Call to aclMatchDst with lastcheckowner but no IP found with"
+	    " '%s' ACL for '%s'\n",
+            ae->name, r->host);
+        return 0;
+    } else {
+	if (checklist->lastcheckowner==ae) {
+	    checklist->lastcheckowner=NULL;
+	    checklist->lastcheckstate=ACL_LOOKUP_NONE;
+	}
+        return aclMatchIp(&ae->data, no_addr);
+    }
+#if 0
+    } else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) {
+        debug(28, 3) ("aclMatchDst: Can't yet compare '%s' ACL for '%s'\n",
+            ae->name, r->host);
+        checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEEDED;
+        return 0;
+    } else {
+        return aclMatchIp(&ae->data, no_addr);
+    }
+#endif
+#if 0
+ if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NEEDED) {
+     checklist->state[ACL_DST_IP] = ACL_LOOKUP_PENDING;
+     ipcache_nbgethostbyname(checklist->request->host,
+         aclLookupDstIPDone, checklist);
+     return;
+ }
+#endif
+}
+
+static void
+aclLookupDstIPDone(const ipcache_addrs * ia, void *data)
+{
+    aclCheck_t *checklist = data;
+    /* We don't reset the owner because the owner needs to test it */
+    checklist->lastcheckstate = ACL_LOOKUP_DONE;
+    aclCheck(checklist);
+}
+
 /**********************/
 /* aclMatchDomainList */
 /**********************/
 
 static int
-aclMatchDomainList(void *dataptr, const char *host)
+aclMatchDomainList(void * dataptr, const char *host)
 {
     splayNode **Top = dataptr;
     if (host == NULL)
@@ -1049,31 +1038,416 @@
     return !splayLastResult;
 }
 
-int
-aclMatchRegex(relist * data, const char *word)
+static int
+aclMatchDstDomain(acl * ae, aclCheck_t * checklist, unsigned int flags)
 {
-    relist *first, *prev;
-    if (word == NULL)
-	return 0;
-    debug(28, 3) ("aclMatchRegex: checking '%s'\n", word);
-    first = data;
-    prev = NULL;
-    while (data) {
-	debug(28, 3) ("aclMatchRegex: looking for '%s'\n", data->pattern);
-	if (regexec(&data->regex, word, 0, 0, 0) == 0) {
-	    if (prev != NULL) {
-		/* shift the element just found to the second position
-		 * in the list */
-		prev->next = data->next;
-		data->next = first->next;
-		first->next = data;
-	    }
-	    return 1;
-	}
-	prev = data;
-	data = data->next;
+    request_t *r = checklist->request;
+    const ipcache_addrs *ia = NULL;
+    const char *fqdn = NULL;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: '%s' ACL is used but there is no"
+            " HTTP request -- access denied.\n",ae->name);
+        return 0;
+    }
+   debug(28, 3) ("aclMatchDstDomain: checking '%s'\n", ae->cfgline);
+
+    if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
+        return aclMatchDomainList(&ae->data, r->host);
+    fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
+    if (fqdn) {
+        if (checklist->lastcheckowner==ae) {
+            checklist->lastcheckowner=NULL;
+            checklist->lastcheckstate=ACL_LOOKUP_NONE;
+        }
+        return aclMatchDomainList(&ae->data, fqdn);
+    }
+    if (checklist->lastcheckowner==NULL) {
+        debug(28, 3) ("aclMatchDstDomain: Can't yet compare '%s' ACL for '%s'\n",
+            ae->name, inet_ntoa(ia->in_addrs[0]));
+        checklist->lastcheckowner=ae;
+        checklist->lastcheckstate=ACL_LOOKUP_PENDING;
+	checklist->dst_addr = ia->in_addrs[0];
+	fqdncache_nbgethostbyaddr(checklist->dst_addr,
+	    aclLookupDstFQDNDone, checklist);
+        return ACL_MATCH_NEED_LOOKUP;
+    } else if (checklist->lastcheckowner==ae) {
+        /* ACL_LOOKUP_DONE is/should be caught by if (ia) */
+        debug(28, 0) ("aclMatchDstDomain: Probable bug *****"
+            "Call to aclMatchDstDomain with lastcheckowner but no IP found with"
+            " '%s' ACL for '%s'\n",
+            ae->name, r->host);
+        return 0;
+    }
+    if (checklist->lastcheckowner==ae) {
+        checklist->lastcheckowner=NULL;
+        checklist->lastcheckstate=ACL_LOOKUP_NONE;
     }
-    return 0;
+    return aclMatchDomainList(&ae->data, "none");
+}
+
+static void
+aclLookupDstFQDNDone(const char *fqdn, void *data)
+{
+    aclCheck_t *checklist = data;
+    /* We don't reset the owner because the owner needs to test it */
+    checklist->lastcheckstate = ACL_LOOKUP_DONE;
+    aclCheck(checklist);
+#if 0
+    aclCheck_t *checklist = data;
+    checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
+    aclCheck(checklist);
+#endif
+}
+
+static int
+aclMatchSrcDomain(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    const char *fqdn = NULL;
+    debug(28, 3) ("aclMatchSrcDomain: checking '%s'\n", ae->cfgline);
+
+    fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
+    if (fqdn) {
+        if (checklist->lastcheckowner==ae) {
+            checklist->lastcheckowner=NULL;
+            checklist->lastcheckstate=ACL_LOOKUP_NONE;
+        }
+        return aclMatchDomainList(&ae->data, fqdn);
+    } else if (checklist->lastcheckowner==NULL) {
+        debug(28, 3) ("aclMatchSrcDomain: Can't yet compare '%s' ACL for '%s'\n",
+            ae->name, inet_ntoa(checklist->src_addr));
+	checklist->lastcheckowner=ae;
+	checklist->lastcheckstate=ACL_LOOKUP_PENDING;
+	fqdncache_nbgethostbyaddr(checklist->src_addr,
+	    aclLookupSrcFQDNDone, checklist);
+        return ACL_MATCH_NEED_LOOKUP;
+    } else if (checklist->lastcheckowner==ae) {
+        /* ACL_LOOKUP_DONE is/should be caught by if (ia) */
+        debug(28, 0) ("aclMatchSrcDomain: Probable bug *****"
+            "Call to aclMatchSrcDomain with lastcheckowner but no host info found with"
+            " '%s' ACL\n",
+            ae->name);
+        return 0;
+    }
+    if (checklist->lastcheckowner==ae) {
+        checklist->lastcheckowner=NULL;
+        checklist->lastcheckstate=ACL_LOOKUP_NONE;
+    }
+    return aclMatchDomainList(&ae->data, "none");
+}
+
+static void
+aclLookupSrcFQDNDone(const char *fqdn, void *data)
+{
+    aclCheck_t *checklist = data;
+    /* We don't reset the owner because the owner needs to test it */
+    checklist->lastcheckstate = ACL_LOOKUP_DONE;
+    aclCheck(checklist);
+#if 0
+    aclCheck_t *checklist = data;
+    checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_DONE;
+    aclCheck(checklist);
+#endif
+}
+
+/*****************
+ * aclMatchRegex *
+ *****************/
+
+int
+aclMatchRegex(relist * data, const char *word)
+{
+    relist *first, *prev;
+    if (word == NULL)
+	return 0;
+    debug(28, 3) ("aclMatchRegex: checking '%s'\n", word);
+    first = data;
+    prev = NULL;
+    while (data) {
+	debug(28, 3) ("aclMatchRegex: looking for '%s'\n", data->pattern);
+	if (regexec(&data->regex, word, 0, 0, 0) == 0) {
+	    if (prev != NULL) {
+		/* shift the element just found to the second position
+		 * in the list */
+		prev->next = data->next;
+		data->next = first->next;
+		first->next = data;
+	    }
+	    return 1;
+	}
+	prev = data;
+	data = data->next;
+    }
+    return 0;
+}
+
+static int
+aclMatchUrlPathRegex(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    char *esc_buf;
+    int k;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: 'urlpathregex' ACL is used but there is no"
+            " HTTP request -- access denied.\n");
+        return 0;
+    }
+    debug(28, 3) ("aclMatchUrlPathRegex: checking '%s'\n", ae->cfgline);
+    esc_buf = xstrdup(strBuf(r->urlpath));
+    rfc1738_unescape(esc_buf);
+    k = aclMatchRegex(ae->data, esc_buf);
+    safe_free(esc_buf);
+    return k;
+}
+
+static int
+aclMatchUrlRegex(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    char *esc_buf;
+    int k;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: 'url_regex' ACL is used but there is no"
+            " HTTP request -- access denied.\n");
+        return 0;
+    }
+    debug(28, 3) ("aclMatchUrlRegex: checking '%s'\n", ae->cfgline);
+    esc_buf = xstrdup(urlCanonical(r));
+    rfc1738_unescape(esc_buf);
+    k = aclMatchRegex(ae->data, esc_buf);
+    safe_free(esc_buf);
+    return k;
+}
+
+static int
+aclMatchBrowser(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    const char *browser;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: 'browser' ACL is used but there is no"
+            " HTTP request -- access denied.\n");
+        return 0;
+    }
+    browser = httpHeaderGetStr(&r->header, HDR_USER_AGENT);
+    if (NULL == browser)
+        return 0;
+    return aclMatchRegex(ae->data, browser);
+}
+
+static int
+aclMatchReqMimeType(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    const char *header;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: 'req_mime_type' ACL is used but there is no"
+            " HTTP request -- access denied.\n");
+        return 0;
+    }
+
+    header = httpHeaderGetStr(&r->header,
+        HDR_CONTENT_TYPE);
+    if (NULL == header)
+        header = "";
+    return aclMatchRegex(ae->data, header);
+}
+
+
+static int
+aclMatchRepMimeType(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    const char *header;
+    if (!checklist->reply) {
+        debug(28, 1) ("WARNING: 'rep_mime_type' ACL is used but there is no"
+            " HTTP reply -- access denied.\n");
+        return 0;
+    }
+    header = httpHeaderGetStr(&checklist->reply->header, HDR_CONTENT_TYPE);
+    if (NULL == header)
+        header = "";
+    return aclMatchRegex(ae->data, header);
+}
+
+#if USE_IDENT
+static int
+aclMatchIdent(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    if (checklist->rfc931[0]) {
+        return aclMatchUser(ae->data, checklist->rfc931);
+    } else {
+        checklist->lastcheckowner=ae;
+        checklist->lastcheckstate=ACL_LOOKUP_PENDING;
+        debug(28, 3) ("aclCheck: Doing ident lookup\n");
+        if (cbdataValid(checklist->conn)) {
+            identStart(&checklist->conn->me, &checklist->conn->peer,
+            aclLookupIdentDone, checklist);
+            return ACL_MATCH_NEED_LOOKUP;
+        } else {
+            debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n");
+            cbdataUnlock(checklist->conn);
+            checklist->conn = NULL;
+            return ACL_MATCH_INSUFFICIENT_INFORMATION;
+        }
+    }
+}
+
+static int
+aclMatchIdentRegex(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    if (checklist->lastcheckowner==ae) {
+        checklist->lastcheckowner=NULL;
+        checklist->lastcheckstate=ACL_LOOKUP_NONE;
+    }
+    if (checklist->rfc931[0]) {
+        return aclMatchRegex(ae->data, checklist->rfc931);
+    } else {
+        checklist->lastcheckowner=ae;
+        checklist->lastcheckstate=ACL_LOOKUP_PENDING;
+	debug(28, 3) ("aclCheck: Doing ident lookup\n");
+	if (cbdataValid(checklist->conn)) {
+	    identStart(&checklist->conn->me, &checklist->conn->peer,
+	    aclLookupIdentDone, checklist);
+	    return ACL_MATCH_NEED_LOOKUP;
+	} else {
+	    debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n");
+	    cbdataUnlock(checklist->conn);
+	    checklist->conn = NULL;
+	    return ACL_MATCH_INSUFFICIENT_INFORMATION;
+	}
+    }
+}
+
+static void
+aclLookupIdentDone(const char *ident, void *data)
+{
+    aclCheck_t *checklist = data;
+    if (ident) {
+        xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
+#if DONT
+        xstrncpy(checklist->request->authuser, ident, USER_IDENT_SZ);
+#endif
+    } else {
+        xstrncpy(checklist->rfc931, dash_str, USER_IDENT_SZ);
+    }
+    /*
+     * Cache the ident result in the connection, to avoid redoing ident lookup
+     * over and over on persistent connections
+     */
+    if (cbdataValid(checklist->conn) && !checklist->conn->rfc931[0])
+        xstrncpy(checklist->conn->rfc931, checklist->rfc931, USER_IDENT_SZ);
+    aclCheck(checklist);
+}
+#endif
+
+static int
+aclMatchProxyAuth(acl * , http_hdr_type headertype,
+    auth_user_request_t * auth_user_request, aclCheck_t * checklist);
+
+static int
+aclMatchProxyAuthModule(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    http_hdr_type headertype;
+    if (NULL == r) {
+        return ACL_MATCH_INSUFFICIENT_INFORMATION;
+    } else if (!r->flags.accelerated) {
+        /* Proxy authorization on proxy requests */
+        headertype = HDR_PROXY_AUTHORIZATION;
+    } else if (r->flags.internal) {
+        /* WWW authorization on accelerated internal requests */
+        headertype = HDR_AUTHORIZATION;
+    } else {
+#if AUTH_ON_ACCELERATION
+        /* WWW authorization on accelerated requests */
+        headertype = HDR_AUTHORIZATION;
+#else
+//FIXME
+        debug(28, 1) ("aclMatchProxyAuthModule: proxy_auth acls not applicable "
+		"on accelerated requests.\n");
+        return ACL_MATCH_INSUFFICIENT_INFORMATION;
+#endif
+    }
+
+    if (checklist->lastcheckowner==ae) {
+        checklist->lastcheckowner=NULL;
+        checklist->lastcheckstate=ACL_LOOKUP_NONE;
+    }
+    /* Check the credentials */
+    switch (aclMatchProxyAuth(ae, headertype,
+            checklist->auth_user_request, checklist)) {
+    case 0:
+        debug(28, 4) ("aclMatchProxyAuthModule: returning  0 user authenticated "
+		"but not authorised.\n");
+        /* Authenticated but not Authorised for this ACL */
+        return 0;
+    case 1:
+        debug(28, 4) ("aclMatchProxyAuthModule: returning  1 user authenticated "
+		"and authorised.\n");
+        /* Authenticated and Authorised for this ACL */
+        return 1;
+    case -2:
+        debug(28, 4) ("aclMatchProxyAuthModule: returning 0 sending authentication "
+		"challenge.\n");
+        /* Authentication credentials invalid or missing. */
+        /* Or partway through NTLM handshake. A proxy_Authenticate header
+         * gets sent to the client. */
+	/* Client is required to resend the request with correct authentication
+	 * credentials. (This may be part of a stateful auth protocol.
+	 * The request is denied.
+	 */
+	debug(28, 6) ("aclCheck: requiring Proxy Auth header.\n");
+	return ACL_MATCH_INSUFFICIENT_INFORMATION;
+    case -1:
+        debug(28, 4) ("aclMatchProxyAuthModule: returning 0 sending credentials "
+		"to helper.\n");
+        /*
+         * we need to validate the password
+         */
+	checklist->lastcheckowner=ae;
+	checklist->lastcheckstate=ACL_LOOKUP_PENDING;
+	debug(28, 3)
+	    ("aclCheck: checking password via authenticator\n");
+	aclLookupProxyAuthStart(checklist);
+        return ACL_MATCH_NEED_LOOKUP;
+    default:
+	return 0;
+    }
+}
+
+static void
+aclLookupProxyAuthDone(void *data, char *result)
+{
+    aclCheck_t *checklist = data;
+    auth_user_request_t *auth_user_request;
+    /* We don't reset the owner because the owner needs to test it */
+    checklist->lastcheckstate = ACL_LOOKUP_DONE;
+    if (result != NULL)
+        fatal("AclLookupProxyAuthDone: Old code floating around somewhere.\nMake clean and
+ if that doesn't work, report a bug to the squid developers.\n");
+    /* state info check */
+    assert(checklist->conn != NULL);
+    auth_user_request = checklist->auth_user_request;
+    if (!authenticateValidateUser(auth_user_request)) {
+        /* credentials could not be checked either way
+         * restart the whole process */
+        checklist->conn->auth_user_request = NULL;
+        checklist->conn->auth_type = AUTH_BROKEN;
+        checklist->auth_user_request = NULL;
+        authenticateAuthUserRequestUnlock(auth_user_request);
+        aclCheck(checklist);
+        return;
+    }
+    aclCheck(checklist);
+}
+
+static int
+aclMatchMaxConn(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    int k;
+    k = clientdbEstablished(checklist->src_addr, 0);
+    // FIXME we should drop the connection this request was made on or all other
+    // Requests will fail until the link times out.
+    return ((k > (int) ae->data) ? 1 : 0);
 }
 
 static int
@@ -1122,8 +1496,7 @@
  * RBC
  */
 static int
-aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data,
-    char *MatchParam)
+aclCacheMatchAcl(dlink_list * cache, acl * ae, char *MatchParam)
 {
     int matchrv;
     acl_proxy_auth_match_cache *auth_match;
@@ -1131,29 +1504,36 @@
     link = cache->head;
     while (link) {
 	auth_match = link->data;
-	if (auth_match->acl_data == data) {
-	    debug(28, 4) ("aclCacheMatchAcl: cache hit on acl '%d'\n", data);
+	if (auth_match->acl_data == ae->data) {
+	    debug(28, 4) ("aclCacheMatchAcl: cache hit on acl '%d'\n", ae->data);
 	    return auth_match->matchrv;
 	}
 	link = link->next;
     }
     auth_match = NULL;
     /* match the user in the acl. They are not cached. */
-    switch (acltype) {
-    case ACL_PROXY_AUTH:
-	matchrv = aclMatchUser(data, MatchParam);
-	break;
-    case ACL_PROXY_AUTH_REGEX:
-	matchrv = aclMatchRegex(data, MatchParam);
-    default:
+#if 0
+    /* WARNING: this does _not_ sanity check the ACL type. ONLY use for cacheable 
+     * acl responses
+     */
+    matchrv = ae->aclname->match(data, MatchParam);
+#endif
+    /* TODO: we need a generic way of getting down to these functions to make acl 
+     * result caching extendible...
+     */
+    if (ae->aclname==proxy_auth_name) {
+	matchrv = aclMatchUser(ae->data, MatchParam);
+    } else if (ae->aclname==proxy_auth_regex_name) {
+	matchrv = aclMatchRegex(ae->data, MatchParam);
+    } else {
 	/* This is a fatal to ensure that aclCacheMatchAcl calls are _only_
 	 * made for supported acl types */
 	fatal("aclCacheMatchAcl: unknown or unexpected ACL type");
 	return 0;		/* NOTREACHED */
     }
-    auth_match = memAllocate(MEM_ACL_PROXY_AUTH_MATCH);
+    auth_match = memPoolAlloc(acl_proxy_auth_match_pool);
     auth_match->matchrv = matchrv;
-    auth_match->acl_data = data;
+    auth_match->acl_data = ae->data;
     dlinkAddTail(auth_match, &auth_match->link, cache);
     return matchrv;
 }
@@ -1169,7 +1549,7 @@
 	tmplink = link;
 	link = link->next;
 	dlinkDelete(tmplink, cache);
-	memFree(auth_match, MEM_ACL_PROXY_AUTH_MATCH);
+	memPoolFree(acl_proxy_auth_match_pool, auth_match);
     }
 }
 
@@ -1180,9 +1560,8 @@
  * -2 : send data to the client
  */
 static int
-aclMatchProxyAuth(void *data, http_hdr_type headertype,
-    auth_user_request_t * auth_user_request, aclCheck_t * checklist,
-    squid_acl acltype)
+aclMatchProxyAuth(acl * ae, http_hdr_type headertype,
+    auth_user_request_t * auth_user_request, aclCheck_t * checklist)
 {
     /* checklist is used to register user name when identified, nothing else */
     const char *proxy_auth;
@@ -1192,7 +1571,7 @@
     /* General program flow in proxy_auth acls
      * 1. Consistency checks: are we getting sensible data
      * 2. Call the authenticate* functions to establish a authenticated user
-     * 4. look up the username in acltype (and cache the result against the 
+     * 4. look up the username in acl (and cache the result against the 
      *     username
      */
 
@@ -1326,7 +1705,7 @@
 	authenticateAuthUserRequestUnlock(auth_user_request);
 	/* check to see if we have matched the user-acl before */
 	return aclCacheMatchAcl(&auth_user_request->auth_user->
-	    proxy_match_cache, acltype, data,
+	    proxy_match_cache, ae,
 	    authenticateUserRequestUsername(auth_user_request));
     }
     /* this acl check completed */
@@ -1397,7 +1776,7 @@
 }
 
 static int
-aclMatchTime(acl_time_data * data, time_t when)
+aclMatchTimeSpec(acl_time_data * data, time_t when)
 {
     static time_t last_when = 0;
     static struct tm tm;
@@ -1408,7 +1787,7 @@
 	xmemcpy(&tm, localtime(&when), sizeof(struct tm));
     }
     t = (time_t) (tm.tm_hour * 60 + tm.tm_min);
-    debug(28, 3) ("aclMatchTime: checking %d in %d-%d, weekbits=%x\n",
+    debug(28, 3) ("aclMatchTimeSpec: checking %d in %d-%d, weekbits=%x\n",
 	(int) t, (int) data->start, (int) data->stop, data->weekbits);
 
     if (t < data->start || t > data->stop)
@@ -1416,6 +1795,30 @@
     return data->weekbits & (1 << tm.tm_wday) ? 1 : 0;
 }
 
+static int
+aclMatchTime(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    return aclMatchTimeSpec(ae->data, squid_curtime);
+}
+
+static int
+aclMatchUrlPort(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: 'req_mime_type' ACL is used but there is no"
+            " HTTP request -- access denied.\n");
+        return 0;
+    }
+    return aclMatchIntegerRange(ae->data, (int) r->port);
+}
+
+static int
+aclMatchMyPort(acl * ae, aclCheck_t * checklist, unsigned int flags)
+{
+    return aclMatchIntegerRange(ae->data, (int) checklist->my_port);
+}
+
 #if SQUID_SNMP
 static int
 aclMatchWordList(wordlist * w, const char *word)
@@ -1429,279 +1832,129 @@
     }
     return 0;
 }
+
+static int
+aclMatchSNMPCommunity(acl * ae, aclCheck_t *checklist, unsigned int flags)
+{
+    return aclMatchWordList(ae->data, checklist->snmp_community);
+}
 #endif
 
+static int 
+aclMatchProto(acl * ae, aclCheck_t *checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: 'proto' ACL is used but there is no"
+            " HTTP request -- access denied.\n");
+        return 0;
+    }
+    return aclMatchInteger(ae->data, r->protocol);
+}
+
 static int
-aclMatchAcl(acl * ae, aclCheck_t * checklist)
+aclMatchMethod(acl * ae, aclCheck_t *checklist, unsigned int flags)
+{
+    request_t *r = checklist->request;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: 'method' ACL is used but there is no"
+            " HTTP request -- access denied.\n");
+        return 0;
+    }
+    return aclMatchInteger(ae->data, r->method);
+}
+
+
+static int
+aclMatchSrcAsn(acl * ae, aclCheck_t *checklist, unsigned int flags)
+{
+    return asnMatchIp(ae->data, checklist->src_addr);
+}
+
+static int
+aclMatchDstAsn(acl * ae, aclCheck_t *checklist, unsigned int flags)
 {
     request_t *r = checklist->request;
     const ipcache_addrs *ia = NULL;
-    const char *fqdn = NULL;
-    char *esc_buf;
-    const char *header;
-    const char *browser;
     int k;
-    http_hdr_type headertype;
-    if (!ae)
-	return 0;
-    switch (ae->type) {
-    case ACL_DST_IP:
-    case ACL_DST_DOMAIN:
-    case ACL_DST_DOM_REGEX:
-    case ACL_URLPATH_REGEX:
-    case ACL_URL_PORT:
-    case ACL_PROTO:
-    case ACL_METHOD:
-    case ACL_DST_ASN:
-	/* These ACL types require checklist->request */
-	if (NULL == r) {
-	    debug(28, 1) ("WARNING: '%s' ACL is used but there is no"
-		" HTTP request -- access denied.\n", ae->name);
-	    return 0;
-	}
-	break;
-    default:
-	break;
-    }
-    debug(28, 3) ("aclMatchAcl: checking '%s'\n", ae->cfgline);
-    switch (ae->type) {
-    case ACL_SRC_IP:
-	return aclMatchIp(&ae->data, checklist->src_addr);
-	/* NOTREACHED */
-    case ACL_MY_IP:
-	return aclMatchIp(&ae->data, checklist->my_addr);
-	/* NOTREACHED */
-    case ACL_DST_IP:
-	ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
-	if (ia) {
-	    for (k = 0; k < (int) ia->count; k++) {
-		if (aclMatchIp(&ae->data, ia->in_addrs[k]))
-		    return 1;
-	    }
-	    return 0;
-	} else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) {
-	    debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
-		ae->name, r->host);
-	    checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEEDED;
-	    return 0;
-	} else {
-	    return aclMatchIp(&ae->data, no_addr);
-	}
-	/* NOTREACHED */
-    case ACL_DST_DOMAIN:
-	if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
-	    return aclMatchDomainList(&ae->data, r->host);
-	fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
-	if (fqdn)
-	    return aclMatchDomainList(&ae->data, fqdn);
-	if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
-	    debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
-		ae->name, inet_ntoa(ia->in_addrs[0]));
-	    checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
-	    return 0;
-	}
-	return aclMatchDomainList(&ae->data, "none");
-	/* NOTREACHED */
-    case ACL_SRC_DOMAIN:
-	fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
-	if (fqdn) {
-	    return aclMatchDomainList(&ae->data, fqdn);
-	} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
-	    debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
-		ae->name, inet_ntoa(checklist->src_addr));
-	    checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
-	    return 0;
-	}
-	return aclMatchDomainList(&ae->data, "none");
-	/* NOTREACHED */
-    case ACL_DST_DOM_REGEX:
-	if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
-	    return aclMatchRegex(ae->data, r->host);
-	fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
-	if (fqdn)
-	    return aclMatchRegex(ae->data, fqdn);
-	if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
-	    debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
-		ae->name, inet_ntoa(ia->in_addrs[0]));
-	    checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
-	    return 0;
-	}
-	return aclMatchRegex(ae->data, "none");
-	/* NOTREACHED */
-    case ACL_SRC_DOM_REGEX:
-	fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
-	if (fqdn) {
-	    return aclMatchRegex(ae->data, fqdn);
-	} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
-	    debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
-		ae->name, inet_ntoa(checklist->src_addr));
-	    checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
-	    return 0;
-	}
-	return aclMatchRegex(ae->data, "none");
-	/* NOTREACHED */
-    case ACL_TIME:
-	return aclMatchTime(ae->data, squid_curtime);
-	/* NOTREACHED */
-    case ACL_URLPATH_REGEX:
-	esc_buf = xstrdup(strBuf(r->urlpath));
-	rfc1738_unescape(esc_buf);
-	k = aclMatchRegex(ae->data, esc_buf);
-	safe_free(esc_buf);
-	return k;
-	/* NOTREACHED */
-    case ACL_URL_REGEX:
-	esc_buf = xstrdup(urlCanonical(r));
-	rfc1738_unescape(esc_buf);
-	k = aclMatchRegex(ae->data, esc_buf);
-	safe_free(esc_buf);
-	return k;
-	/* NOTREACHED */
-    case ACL_MAXCONN:
-	k = clientdbEstablished(checklist->src_addr, 0);
-	return ((k > ((intlist *) ae->data)->i) ? 1 : 0);
-	/* NOTREACHED */
-    case ACL_URL_PORT:
-	return aclMatchIntegerRange(ae->data, (int) r->port);
-	/* NOTREACHED */
-    case ACL_MY_PORT:
-	return aclMatchIntegerRange(ae->data, (int) checklist->my_port);
-	/* NOTREACHED */
-#if USE_IDENT
-    case ACL_IDENT:
-	if (checklist->rfc931[0]) {
-	    return aclMatchUser(ae->data, checklist->rfc931);
-	} else {
-	    checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
-	    return 0;
-	}
-	/* NOTREACHED */
-    case ACL_IDENT_REGEX:
-	if (checklist->rfc931[0]) {
-	    return aclMatchRegex(ae->data, checklist->rfc931);
-	} else {
-	    checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
-	    return 0;
-	}
-	/* NOTREACHED */
-#endif
-    case ACL_PROTO:
-	return aclMatchInteger(ae->data, r->protocol);
-	/* NOTREACHED */
-    case ACL_METHOD:
-	return aclMatchInteger(ae->data, r->method);
-	/* NOTREACHED */
-    case ACL_BROWSER:
-	browser = httpHeaderGetStr(&checklist->request->header, HDR_USER_AGENT);
-	if (NULL == browser)
-	    return 0;
-	return aclMatchRegex(ae->data, browser);
-	/* NOTREACHED */
-    case ACL_PROXY_AUTH:
-    case ACL_PROXY_AUTH_REGEX:
-	if (NULL == r) {
-	    return -1;
-	} else if (!r->flags.accelerated) {
-	    /* Proxy authorization on proxy requests */
-	    headertype = HDR_PROXY_AUTHORIZATION;
-	} else if (r->flags.internal) {
-	    /* WWW authorization on accelerated internal requests */
-	    headertype = HDR_AUTHORIZATION;
-	} else {
-#if AUTH_ON_ACCELERATION
-	    /* WWW authorization on accelerated requests */
-	    headertype = HDR_AUTHORIZATION;
-#else
-	    debug(28, 1) ("aclMatchAcl: proxy_auth %s not applicable on accelerated requests.\n", ae->name);
-	    return -1;
-#endif
-	}
-	/* Check the credentials */
-	switch (aclMatchProxyAuth(ae->data, headertype,
-		checklist->auth_user_request, checklist, ae->type)) {
-	case 0:
-	    debug(28, 4) ("aclMatchAcl: returning  0 user authenticated but not authorised.\n");
-	    /* Authenticated but not Authorised for this ACL */
-	    return 0;
-	case 1:
-	    debug(28, 4) ("aclMatchAcl: returning  1 user authenticated and authorised.\n");
-	    /* Authenticated and Authorised for this ACL */
-	    return 1;
-	case -2:
-	    debug(28, 4) ("aclMatchAcl: returning 0 sending authentication challenge.\n");
-	    /* Authentication credentials invalid or missing. */
-	    /* Or partway through NTLM handshake. A proxy_Authenticate header
-	     * gets sent to the client. */
-	    checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED;
-	    return 0;
-	case -1:
-	    debug(28, 4) ("aclMatchAcl: returning 0 sending credentials to helper.\n");
-	    /*
-	     * we need to validate the password
-	     */
-	    checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_NEEDED;
-	    return 0;
-	}
-	/* NOTREACHED */
-#if SQUID_SNMP
-    case ACL_SNMP_COMMUNITY:
-	return aclMatchWordList(ae->data, checklist->snmp_community);
-#endif
-    case ACL_SRC_ASN:
-	return asnMatchIp(ae->data, checklist->src_addr);
-    case ACL_DST_ASN:
-	ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
-	if (ia) {
-	    for (k = 0; k < (int) ia->count; k++) {
-		if (asnMatchIp(ae->data, ia->in_addrs[k]))
-		    return 1;
-	    }
-	    return 0;
-	} else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NONE) {
-	    debug(28, 3) ("asnMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
-		ae->name, r->host);
-	    checklist->state[ACL_DST_ASN] = ACL_LOOKUP_NEEDED;
-	} else {
-	    return asnMatchIp(ae->data, no_addr);
-	}
-	return 0;
-#if USE_ARP_ACL
-    case ACL_SRC_ARP:
-	return aclMatchArp(&ae->data, checklist->src_addr);
-#endif
-    case ACL_REQ_MIME_TYPE:
-	header = httpHeaderGetStr(&checklist->request->header,
-	    HDR_CONTENT_TYPE);
-	if (NULL == header)
-	    header = "";
-	return aclMatchRegex(ae->data, header);
-	/* NOTREACHED */
-    case ACL_REP_MIME_TYPE:
-	if (!checklist->reply)
-	    return 0;
-	header = httpHeaderGetStr(&checklist->reply->header, HDR_CONTENT_TYPE);
-	if (NULL == header)
-	    header = "";
-	return aclMatchRegex(ae->data, header);
-	/* NOTREACHED */
-    case ACL_NONE:
-    case ACL_ENUM_MAX:
-	break;
+    if (NULL == r) {
+        debug(28, 1) ("WARNING: 'dst_asn' ACL is used but there is no"
+            " HTTP request -- access denied.\n");
+        return 0;
+    }
+
+    ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
+    if (ia) {
+        if (checklist->lastcheckowner==ae) {
+            checklist->lastcheckowner=NULL;
+            checklist->lastcheckstate=ACL_LOOKUP_NONE;
+        }
+        for (k = 0; k < (int) ia->count; k++) {
+            if (asnMatchIp(ae->data, ia->in_addrs[k]))
+                return 1;
+        }
+        return 0;
+    } else if (checklist->lastcheckowner==NULL) {
+        debug(28, 3) ("asnMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
+            ae->name, r->host);
+	checklist->lastcheckowner=ae;
+	checklist->lastcheckstate=ACL_LOOKUP_PENDING;
+	ipcache_nbgethostbyname(checklist->request->host,
+	    aclLookupDstIPforASNDone, checklist);
+	return ACL_MATCH_NEED_LOOKUP;
+    } else if (checklist->lastcheckowner==ae) {
+        /* ACL_LOOKUP_DONE is/should be caught by if (ia) */
+        debug(28, 0) ("aclMatchDstAsn: Probable bug *****"
+            "Call to aclMatchDstAsn with lastcheckowner but no IP found with"
+            " '%s' ACL for '%s'\n",
+            ae->name, r->host);
+        return 0;
+    } else {
+        if (checklist->lastcheckowner==ae) {
+            checklist->lastcheckowner=NULL;
+            checklist->lastcheckstate=ACL_LOOKUP_NONE;
+        }
+        return asnMatchIp(ae->data, no_addr);
     }
-    debug(28, 0) ("aclMatchAcl: '%s' has bad type %d\n",
-	ae->name, ae->type);
     return 0;
 }
 
-int
-aclMatchAclList(const acl_list * list, aclCheck_t * checklist)
+static void
+aclLookupDstIPforASNDone(const ipcache_addrs * ia, void *data)
+{
+    aclCheck_t *checklist = data;
+    /* We don't reset the owner because the owner needs to test it */
+    checklist->lastcheckstate = ACL_LOOKUP_DONE;
+    aclCheck(checklist);
+}
+
+/* test each acl in a list for a match.
+ * if the result does not match the logic test, stop iterating and return
+ * allowed match rvs are : ACL_MATCH_NEED_LOOKUP, ACL_MATCH_FOUND, ACL_MATCH_NOTFOUND
+ */
+
+/* TODO: cache acl results for a given request. This will lower CPU use with reused
+ * regex's in multiple lists (ie
+ *
+ * http_access deny !expensive_test src1
+ * http_access allow exepnsive_test group2
+ */
+
+static int
+aclMatchAclList(const acl_list * list, aclCheck_t * checklist, unsigned int flags)
 {
+    int result;
     while (list) {
 	AclMatchedName = list->acl->name;
+	AclMatchedAcl  = list->acl;
 	debug(28, 3) ("aclMatchAclList: checking %s%s\n",
 	    list->op ? null_string : "!", list->acl->name);
-	if (aclMatchAcl(list->acl, checklist) != list->op) {
+	if ((result=list->acl->aclname->match(list->acl, checklist, flags)) != list->op) {
 	    debug(28, 3) ("aclMatchAclList: returning 0\n");
+	    if (result==ACL_MATCH_NEED_LOOKUP)
+		return ACL_MATCH_NEED_LOOKUP;
+	    if (result==ACL_MATCH_INSUFFICIENT_INFORMATION)
+		return ACL_MATCH_INSUFFICIENT_INFORMATION;
 	    return 0;
 	}
 	list = list->next;
@@ -1717,7 +1970,8 @@
     debug(28, 5) ("aclCheckFast: list: %p\n", A);
     while (A) {
 	allow = A->allow;
-	if (aclMatchAclList(A->acl_list, checklist))
+	/* we never get -1 as a result, -1 is only allowed for non FASTCHECKS */
+	if (aclMatchAclList(A->acl_list, checklist, ACL_FASTCHECK))
 	    return allow == ACCESS_ALLOWED;
 	A = A->next;
     }
@@ -1731,7 +1985,6 @@
     allow_t allow = ACCESS_DENIED;
     const acl_access *A;
     int match;
-    ipcache_addrs *ia;
     while ((A = checklist->access_list) != NULL) {
 	/*
 	 * If the _acl_access is no longer valid (i.e. its been
@@ -1744,82 +1997,32 @@
 	}
 	debug(28, 3) ("aclCheck: checking '%s'\n", A->cfgline);
 	allow = A->allow;
-	match = aclMatchAclList(A->acl_list, checklist);
-	if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NEEDED) {
-	    checklist->state[ACL_DST_IP] = ACL_LOOKUP_PENDING;
-	    ipcache_nbgethostbyname(checklist->request->host,
-		aclLookupDstIPDone, checklist);
-	    return;
-	} else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NEEDED) {
-	    checklist->state[ACL_DST_ASN] = ACL_LOOKUP_PENDING;
-	    ipcache_nbgethostbyname(checklist->request->host,
-		aclLookupDstIPforASNDone, checklist);
+	switch (match = aclMatchAclList(A->acl_list, checklist, 0)) {
+	case ACL_MATCH_NEED_LOOKUP:
+	    /* the current list needs to perform a lookup of some sort */
 	    return;
-	} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NEEDED) {
-	    checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_PENDING;
-	    fqdncache_nbgethostbyaddr(checklist->src_addr,
-		aclLookupSrcFQDNDone, checklist);
-	    return;
-	} else if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NEEDED) {
-	    ia = ipcacheCheckNumeric(checklist->request->host);
-	    if (ia == NULL) {
-		checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
-		return;
-	    }
-	    checklist->dst_addr = ia->in_addrs[0];
-	    checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_PENDING;
-	    fqdncache_nbgethostbyaddr(checklist->dst_addr,
-		aclLookupDstFQDNDone, checklist);
-	    return;
-	} else if (checklist->state[ACL_PROXY_AUTH] == ACL_LOOKUP_NEEDED) {
-	    debug(28, 3)
-		("aclCheck: checking password via authenticator\n");
-	    aclLookupProxyAuthStart(checklist);
-	    checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_PENDING;
-	    return;
-	} else if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED) {
-	    /* Client is required to resend the request with correct authentication
-	     * credentials. (This may be part of a stateful auth protocol.
-	     * The request is denied.
-	     */
-	    debug(28, 6) ("aclCheck: requiring Proxy Auth header.\n");
-	    allow = ACCESS_REQ_PROXY_AUTH;
-	    match = -1;
-	}
-#if USE_IDENT
-	else if (checklist->state[ACL_IDENT] == ACL_LOOKUP_NEEDED) {
-	    debug(28, 3) ("aclCheck: Doing ident lookup\n");
-	    if (cbdataValid(checklist->conn)) {
-		identStart(&checklist->conn->me, &checklist->conn->peer,
-		    aclLookupIdentDone, checklist);
-		checklist->state[ACL_IDENT] = ACL_LOOKUP_PENDING;
-		return;
-	    } else {
-		debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n");
-		cbdataUnlock(checklist->conn);
-		checklist->conn = NULL;
-		allow = 0;
-		match = -1;
-	    }
-	}
-#endif
-	/*
-	 * We are done with this _acl_access entry.  Either the request
-	 * is allowed, denied, requires authentication, or we move on to
-	 * the next entry.
-	 */
-	cbdataUnlock(A);
-	if (match) {
+	    break;
+	case ACL_MATCH_INSUFFICIENT_INFORMATION:
+	    /* There is not enough information in the checklist to determine a match
+	     * or non-match
+	     */
+	    allow = ACCESS_DENIED;
+	case ACL_MATCH_FOUND:
+	    cbdataUnlock(A);
 	    debug(28, 3) ("aclCheck: match found, returning %d\n", allow);
 	    aclCheckCallback(checklist, allow);
 	    return;
+	    break;
+	case ACL_MATCH_NOTFOUND:
+	    cbdataUnlock(A);
+	    checklist->access_list = A->next;
+	    /*
+	     * Lock the next _acl_access entry
+	     */
+	    if (A->next)
+		cbdataLock(A->next);
+	    break;
 	}
-	checklist->access_list = A->next;
-	/*
-	 * Lock the next _acl_access entry
-	 */
-	if (A->next)
-	    cbdataLock(A->next);
     }
     debug(28, 3) ("aclCheck: NO match found, returning %d\n", allow != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED);
     aclCheckCallback(checklist, allow != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED);
@@ -1853,91 +2056,12 @@
     aclChecklistFree(checklist);
 }
 
-#if USE_IDENT
-static void
-aclLookupIdentDone(const char *ident, void *data)
-{
-    aclCheck_t *checklist = data;
-    if (ident) {
-	xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
-#if DONT
-	xstrncpy(checklist->request->authuser, ident, USER_IDENT_SZ);
-#endif
-    } else {
-	xstrncpy(checklist->rfc931, dash_str, USER_IDENT_SZ);
-    }
-    /*
-     * Cache the ident result in the connection, to avoid redoing ident lookup
-     * over and over on persistent connections
-     */
-    if (cbdataValid(checklist->conn) && !checklist->conn->rfc931[0])
-	xstrncpy(checklist->conn->rfc931, checklist->rfc931, USER_IDENT_SZ);
-    aclCheck(checklist);
-}
-#endif
-
-static void
-aclLookupDstIPDone(const ipcache_addrs * ia, void *data)
-{
-    aclCheck_t *checklist = data;
-    checklist->state[ACL_DST_IP] = ACL_LOOKUP_DONE;
-    aclCheck(checklist);
-}
-
-static void
-aclLookupDstIPforASNDone(const ipcache_addrs * ia, void *data)
-{
-    aclCheck_t *checklist = data;
-    checklist->state[ACL_DST_ASN] = ACL_LOOKUP_DONE;
-    aclCheck(checklist);
-}
-
-static void
-aclLookupSrcFQDNDone(const char *fqdn, void *data)
-{
-    aclCheck_t *checklist = data;
-    checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_DONE;
-    aclCheck(checklist);
-}
-
-static void
-aclLookupDstFQDNDone(const char *fqdn, void *data)
-{
-    aclCheck_t *checklist = data;
-    checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
-    aclCheck(checklist);
-}
-
-static void
-aclLookupProxyAuthDone(void *data, char *result)
-{
-    aclCheck_t *checklist = data;
-    auth_user_request_t *auth_user_request;
-    checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE;
-    if (result != NULL)
-	fatal("AclLookupProxyAuthDone: Old code floating around somewhere.\nMake clean and if that doesn't work, report a bug to the squid developers.\n");
-    /* state info check */
-    assert(checklist->conn != NULL);
-    auth_user_request = checklist->auth_user_request;
-    if (!authenticateValidateUser(auth_user_request)) {
-	/* credentials could not be checked either way
-	 * restart the whole process */
-	checklist->conn->auth_user_request = NULL;
-	checklist->conn->auth_type = AUTH_BROKEN;
-	checklist->auth_user_request = NULL;
-	authenticateAuthUserRequestUnlock(auth_user_request);
-	aclCheck(checklist);
-	return;
-    }
-    aclCheck(checklist);
-}
-
 aclCheck_t *
 aclChecklistCreate(const acl_access * A, request_t * request, const char *ident)
 {
-    int i;
     aclCheck_t *checklist;
     checklist = cbdataAlloc(aclCheck_t);
+    memset (checklist, '\0', sizeof (aclCheck_t));
     checklist->access_list = A;
     /*
      * aclCheck() makes sure checklist->access_list is a valid
@@ -1950,13 +2074,10 @@
 	checklist->my_addr = request->my_addr;
 	checklist->my_port = request->my_port;
     }
-    for (i = 0; i < ACL_ENUM_MAX; i++)
-	checklist->state[i] = ACL_LOOKUP_NONE;
 #if USE_IDENT
     if (ident)
 	xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
 #endif
-    checklist->auth_user_request = NULL;
     return checklist;
 }
 
@@ -1969,29 +2090,25 @@
     aclCheck(checklist);
 }
 
-
-
-
-
-
-
 /*********************/
 /* Destroy functions */
 /*********************/
 
 static void
-aclDestroyTimeList(acl_time_data * data)
+aclDestroyTimeSpecList(parserNameNode *parserName, void * dataptr)
 {
+    acl_time_data * data = dataptr;
     acl_time_data *next = NULL;
     for (; data; data = next) {
 	next = data->next;
-	memFree(data, MEM_ACL_TIME_DATA);
+	memPoolFree(acl_time_data_pool, data);
     }
 }
 
 void
-aclDestroyRegexList(relist * data)
+aclDestroyRegexList(parserNameNode *parserName, void * dataptr)
 {
+    relist * data = dataptr;
     relist *next = NULL;
     for (; data; data = next) {
 	next = data->next;
@@ -2004,19 +2121,36 @@
 static void
 aclFreeIpData(void *p)
 {
-    memFree(p, MEM_ACL_IP_DATA);
+    memPoolFree(acl_ip_data_pool, p);
+}
+
+static void
+aclDestroyIpList(parserNameNode *parserName, void * data)
+{
+    acl ** head=(acl **)data;
+    acl *a=*head;
+    if (a)
+	splay_destroy(a->data,aclFreeIpData);
+}
+
+static void
+aclDestroyDomainList(parserNameNode *parserName, void * data)
+{
+    acl ** head=(acl **)data;
+    acl *a=*head;
+    if (a)
+	splay_destroy(a->data, xfree);
 }
 
 static void
-aclFreeUserData(void *data)
+aclDestroyUserList(parserNameNode *parserName, void *data)
 {
     acl_user_data *d = data;
     if (d->names)
 	splay_destroy(d->names, xfree);
-    memFree(d, MEM_ACL_USER_DATA);
+    memPoolFree(acl_user_data_pool, d);
 }
 
-
 void
 aclDestroyAcls(acl ** head)
 {
@@ -2025,69 +2159,9 @@
     for (a = *head; a; a = next) {
 	next = a->next;
 	debug(28, 3) ("aclDestroyAcls: '%s'\n", a->cfgline);
-	switch (a->type) {
-	case ACL_SRC_IP:
-	case ACL_DST_IP:
-	case ACL_MY_IP:
-	    splay_destroy(a->data, aclFreeIpData);
-	    break;
-#if USE_ARP_ACL
-	case ACL_SRC_ARP:
-#endif
-	case ACL_DST_DOMAIN:
-	case ACL_SRC_DOMAIN:
-	    splay_destroy(a->data, xfree);
-	    break;
-#if SQUID_SNMP
-	case ACL_SNMP_COMMUNITY:
-	    wordlistDestroy((wordlist **) & a->data);
-	    break;
-#endif
-#if USE_IDENT
-	case ACL_IDENT:
-	    aclFreeUserData(a->data);
-	    break;
-#endif
-	case ACL_PROXY_AUTH:
-	    aclFreeUserData(a->data);
-	    break;
-	case ACL_TIME:
-	    aclDestroyTimeList(a->data);
-	    break;
-#if USE_IDENT
-	case ACL_IDENT_REGEX:
-#endif
-	case ACL_PROXY_AUTH_REGEX:
-	case ACL_URL_REGEX:
-	case ACL_URLPATH_REGEX:
-	case ACL_BROWSER:
-	case ACL_SRC_DOM_REGEX:
-	case ACL_DST_DOM_REGEX:
-	case ACL_REP_MIME_TYPE:
-	case ACL_REQ_MIME_TYPE:
-	    aclDestroyRegexList(a->data);
-	    break;
-	case ACL_PROTO:
-	case ACL_METHOD:
-	case ACL_SRC_ASN:
-	case ACL_DST_ASN:
-#if SRC_RTT_NOT_YET_FINISHED
-	case ACL_NETDB_SRC_RTT:
-#endif
-	case ACL_MAXCONN:
-	    intlistDestroy((intlist **) & a->data);
-	    break;
-	case ACL_URL_PORT:
-	case ACL_MY_PORT:
-	    aclDestroyIntRange(a->data);
-	    break;
-	case ACL_NONE:
-	case ACL_ENUM_MAX:
-	    debug(28, 1) ("aclDestroyAcls: no case for ACL type %d\n", a->type);
-	    break;
-	}
 	safe_free(a->cfgline);
-	memFree(a, MEM_ACL);
+	memPoolFree(acl_pool, a);
+	// Should we be locking the aclname struct and unlocking here?
     }
     *head = NULL;
 }
@@ -2118,32 +2192,10 @@
     *list = NULL;
 }
 
-/* maex@space.net (06.09.1996)
- *    destroy an _acl_deny_info_list */
-
-void
-aclDestroyDenyInfoList(acl_deny_info_list ** list)
-{
-    acl_deny_info_list *a = NULL;
-    acl_deny_info_list *a_next = NULL;
-    acl_name_list *l = NULL;
-    acl_name_list *l_next = NULL;
-
-    for (a = *list; a; a = a_next) {
-	for (l = a->acl_list; l; l = l_next) {
-	    l_next = l->next;
-	    safe_free(l);
-	}
-	a_next = a->next;
-	xfree(a->err_page_name);
-	memFree(a, MEM_ACL_DENY_INFO_LIST);
-    }
-    *list = NULL;
-}
-
 static void
-aclDestroyIntRange(intrange * list)
+aclDestroyIntRange(parserNameNode *parserName, void * data)
 {
+    intrange * list = data;
     intrange *w = NULL;
     intrange *n = NULL;
     for (w = list; w; w = n) {
@@ -2375,62 +2427,211 @@
     return W;
 }
 
-wordlist *
-aclDumpGeneric(const acl * a)
+static void
+dump_IpList(StoreEntry * entry, const char *name, void const * const data)
 {
-    debug(28, 3) ("aclDumpGeneric: %s type %d\n", a->name, a->type);
-    switch (a->type) {
-    case ACL_SRC_IP:
-    case ACL_DST_IP:
-    case ACL_MY_IP:
-	return aclDumpIpList(a->data);
-    case ACL_SRC_DOMAIN:
-    case ACL_DST_DOMAIN:
-	return aclDumpDomainList(a->data);
-#if SQUID_SNMP
-    case ACL_SNMP_COMMUNITY:
-	return wordlistDup(a->data);
-#endif
-#if USE_IDENT
-    case ACL_IDENT:
-	return aclDumpUserList(a->data);
-    case ACL_IDENT_REGEX:
-	return aclDumpRegexList(a->data);
-#endif
-    case ACL_PROXY_AUTH:
-	return aclDumpUserList(a->data);
-    case ACL_TIME:
-	return aclDumpTimeSpecList(a->data);
-    case ACL_PROXY_AUTH_REGEX:
-    case ACL_URL_REGEX:
-    case ACL_URLPATH_REGEX:
-    case ACL_BROWSER:
-    case ACL_SRC_DOM_REGEX:
-    case ACL_DST_DOM_REGEX:
-    case ACL_REQ_MIME_TYPE:
-    case ACL_REP_MIME_TYPE:
-	return aclDumpRegexList(a->data);
-    case ACL_SRC_ASN:
-    case ACL_MAXCONN:
-    case ACL_DST_ASN:
-	return aclDumpIntlistList(a->data);
-    case ACL_URL_PORT:
-    case ACL_MY_PORT:
-	return aclDumpIntRangeList(a->data);
-    case ACL_PROTO:
-	return aclDumpProtoList(a->data);
-    case ACL_METHOD:
-	return aclDumpMethodList(a->data);
-#if USE_ARP_ACL
-    case ACL_SRC_ARP:
-	return aclDumpArpList(a->data);
-#endif
-    case ACL_NONE:
-    case ACL_ENUM_MAX:
-	break;
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_IpList: %s %s\n", name, ae->name);
+        v = w = aclDumpIpList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_IpList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static void
+dump_DomainList(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_DomainList: %s %s\n", name, ae->name);
+        v = w = aclDumpDomainList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_DomainList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static void
+dump_RegexList(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_RegexList: %s %s\n", name, ae->name);
+        v = w = aclDumpRegexList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_RegexList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static void
+dump_TimeSpec(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_TimeSpec: %s %s\n", name, ae->name);
+        v = w = aclDumpTimeSpecList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_TimeSpec: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static void
+dump_intlistList(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_intlistList: %s %s\n", name, ae->name);
+        v = w = aclDumpIntlistList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_intlistList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static void
+dump_IntRangeList(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_IntRangeList: %s %s\n", name, ae->name);
+        v = w = aclDumpIntRangeList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_IntRangeList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static void
+dump_UserList(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_UserList: %s %s\n", name, ae->name);
+        v = w = aclDumpUserList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_UserList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static void
+dump_ProtoList(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_ProtoList: %s %s\n", name, ae->name);
+        v = w = aclDumpProtoList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_ProtoList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static void
+dump_MethodList(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_MethodList: %s %s\n", name, ae->name);
+        v = w = aclDumpMethodList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_MethodList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
     }
-    debug(28, 1) ("aclDumpGeneric: no case for ACL type %d\n", a->type);
-    return NULL;
 }
 
 /*
@@ -2443,9 +2644,13 @@
 aclPurgeMethodInUse(acl_access * a)
 {
     acl_list *b;
+    aclName *method = aclNameByName("method");
+    if (!method)
+	/* method name not present */
+	return 0;
     for (; a; a = a->next) {
 	for (b = a->acl_list; b; b = b->next) {
-	    if (ACL_METHOD != b->acl->type)
+	    if (method != b->acl->aclname)
 		continue;
 	    if (aclMatchInteger(b->acl->data, METHOD_PURGE))
 		return 1;
@@ -2454,380 +2659,310 @@
     return 0;
 }
 
+/* === CONFIG SUPPORT ROUTINES === */
 
-#if USE_ARP_ACL
-/* ==== BEGIN ARP ACL SUPPORT ============================================= */
+static int
+check_null_acl()
+{
+//    return a == NULL;
+    // FIXME: heal the abstraction
+    parserNameNode *parserName = parserNameByName("acl");
+    return (parserName->children.head==NULL);
+}
+/* temp home to test with */
+static void
+default_if_none_acl(void * data){
+        if (check_null_acl()) {
+                default_line("acl all src 0.0.0.0/0.0.0.0");
+        }
+}
+
+static void
+name_document_acl(void){
+        printf(
+"\n"
+"# ACCESS CONTROLS\n"
+"# -----------------------------------------------------------------------------\n"
+"\n"
+"#  TAG: acl"
+"\n"
+"#\tDefining an Access List\n"
+"#\n"
+"#\tacl aclname acltype string1 ...\n"
+"#\tacl aclname acltype \"file\" ...\n"
+"#\n"
+"#\twhen using \"file\", the file should contain one item per line\n"
+"#\n"
+"#\tacltype is one of src dst srcdomain dstdomain url_pattern\n"
+"#\t\turlpath_pattern time port proto method browser user\n"
+"#\n"
+"#\tBy default, regular expressions are CASE-SENSITIVE.  To make\n"
+"#\tthem case-insensitive, use the -i option.\n"
+"#\n"
+"#\tacl aclname src      ip-address/netmask ... (clients IP address)\n"
+"#\tacl aclname src      addr1-addr2/netmask ... (range of addresses)\n"
+"#\tacl aclname dst      ip-address/netmask ... (URL host's IP address)\n"
+"#\tacl aclname myip     ip-address/netmask ... (local socket IP address)\n"
+"#\n"
+"#\tacl aclname srcdomain   .foo.com ...    # reverse lookup, client IP\n"
+"#\tacl aclname dstdomain   .foo.com ...    # Destination server from URL\n"
+"#\tacl aclname srcdom_regex [-i] xxx ...   # regex matching client name\n"
+"#\tacl aclname dstdom_regex [-i] xxx ...   # regex matching server\n"
+"#\t  # For dstdomain and dstdom_regex  a reverse lookup is tried if a IP\n"
+"#\t  # based URL is used. The name \"none\" is used if the reverse lookup\n"
+"#\t  # fails.\n"
+"#\n"
+"#\tacl aclname time     [day-abbrevs]  [h1:m1-h2:m2]\n"
+"#\t    day-abbrevs:\n"
+"#\t\tS - Sunday\n"
+"#\t\tM - Monday\n"
+"#\t\tT - Tuesday\n"
+"#\t\tW - Wednesday\n"
+"#\t\tH - Thursday\n"
+"#\t\tF - Friday\n"
+"#\t\tA - Saturday\n"
+"#\t    h1:m1 must be less than h2:m2\n"
+"#\tacl aclname url_regex [-i] ^http:// ...\t# regex matching on whole URL\n"
+"#\tacl aclname urlpath_regex [-i] \\.gif$ ...\t# regex matching on URL path\n"
+"#\tacl aclname port     80 70 21 ...\n"
+"#\tacl aclname port     0-1024 ...\t\t# ranges allowed\n"
+"#\tacl aclname myport   3128 ...\t\t# (local socket TCP port)\n"
+"#\tacl aclname proto    HTTP FTP ...\n"
+"#\tacl aclname method   GET POST ...\n"
+"#\tacl aclname browser  [-i] regexp\n"
+"#\t  # pattern match on User-Agent header\n"
+"#\tacl aclname ident    username ...\n"
+"#\tacl aclname ident_regex [-i] pattern ...\n"
+"#\t  # string match on ident output.\n"
+"#\t  # use REQUIRED to accept any non-null ident.\n"
+"#\tacl aclname src_as   number ... \n"
+"#\tacl aclname dst_as   number ...\n"
+"#\t  # Except for access control, AS numbers can be used for\n"
+"#\t  # routing of requests to specific caches. Here's an \n"
+"#\t  # example for routing all requests for AS#1241 and only \n"
+"#\t  # those to mycache.mydomain.net:\n"
+"#\t  # acl asexample dst_as 1241\n"
+"#\t  # cache_peer_access mycache.mydomain.net allow asexample\n"
+"#\t  # cache_peer_access mycache_mydomain.net deny all\n"
+"#\n"
+"#\tacl aclname proxy_auth username ...\n"
+"#\tacl aclname proxy_auth_regex [-i] pattern ...\n"
+"#\t  # list of valid usernames\n"
+"#\t  # use REQUIRED to accept any valid username.\n"
+"#\t  #\n"
+"#\t  # NOTE: when a Proxy-Authentication header is sent but it is not\n"
+"#\t  # needed during ACL checking the username is NOT logged\n"
+"#\t  # in access.log.\n"
+"#\t  #\n"
+"#\t  # NOTE: proxy_auth requires a EXTERNAL authentication program\n"
+"#\t  # to check username/password combinations (see\n"
+"#\t  # authenticate_program).\n"
+"#\t  #\n"
+"#\t  # WARNING: proxy_auth can't be used in a transparent proxy. It\n"
+"#\t  # collides with any authentication done by origin servers. It may\n"
+"#\t  # seem like it works at first, but it doesn't.\n"
+"#\t  #\n"
+"#\t  # NOTE: Authentication schemes need to be defined before proxy_auth ACL's \n"
+"#\t  # in the squid.conf file.\n"
+"#\t  # See authenticate_* commands.\n"
+"#\n"
+"#\tacl aclname snmp_community string ...\n"
+"#\t  # A community string to limit access to your SNMP Agent\n"
+"#\t  # Example:\n"
+"#\t  # \n"
+"#\t  #\tacl snmppublic snmp_community public\n"
+"#\n"
+"#\tacl aclname maxconn number\n"
+"#\t  # This will be matched when the client's IP address has\n"
+"#\t  # more than <number> HTTP connections established.\n"
+"#\n"
+"#\tacl req_mime_type mime-type1 ...\n"
+"#\t  # regex match agains the mime type of the request generated\n"
+"#\t  # by the client. Can be used to detect file upload or some\n"
+"#\t  # types HTTP tunelling requests.\n"
+"#\t  # NOTE: This does NOT match the reply. You cannot use this\n"
+"#\t  # to match the returned file type.\n"
+"#\n"
+"#\tacl rep_mime_type mime-type1 ...\n"
+"#\t  # regex match against the mime type of the reply recieved by\n"
+"#\t  # squid. Can be used to detect file download or some\n"
+"#\t  # types HTTP tunelling requests.\n"
+"#\t  # NOTE: This has no effect in http_access rules. It only has\n"
+"#\t  # effect in rules that affect the reply data stream such as\n"
+"#\t  # http_reply_access.\n"
+"#\n"
+"#\n"
+"#Examples:\n"
+"#acl myexample dst_as 1241\n"
+"#acl password proxy_auth REQUIRED\n"
+"#acl fileupload req_mime_type -i ^multipart/form-data$\n"
+"#acl javascript rep_mime_type -i ^application/x-javascript$\n"
+"#\n"
+"#Default:\n"
+"# acl all src 0.0.0.0/0.0.0.0\n"
+"#\n"
+"#Recommended minimum configuration:\n"
+"acl all src 0.0.0.0/0.0.0.0\n"
+"acl manager proto cache_object\n"
+"acl localhost src 127.0.0.1/255.255.255.255\n"
+"acl SSL_ports port 443 563\n"
+"acl Safe_ports port 80\t\t# http\n"
+"acl Safe_ports port 21\t\t# ftp\n"
+"acl Safe_ports port 443 563\t# https, snews\n"
+"acl Safe_ports port 70\t\t# gopher\n"
+"acl Safe_ports port 210\t\t# wais\n"
+"acl Safe_ports port 1025-65535\t# unregistered ports\n"
+"acl Safe_ports port 280\t\t# http-mgmt\n"
+"acl Safe_ports port 488\t\t# gss-http\n"
+"acl Safe_ports port 591\t\t# filemaker\n"
+"acl Safe_ports port 777\t\t# multiling http\n"
+"acl CONNECT method CONNECT\n"
+"\n"
+        );}
 
-/*
- * From:    dale@server.ctam.bitmcnit.bryansk.su (Dale)
- * To:      wessels@nlanr.net
- * Subject: Another Squid patch... :)
- * Date:    Thu, 04 Dec 1997 19:55:01 +0300
- * ============================================================================
- * 
- * Working on setting up a proper firewall for a network containing some
- * Win'95 computers at our Univ, I've discovered that some smart students
- * avoid the restrictions easily just changing their IP addresses in Win'95
- * Contol Panel... It has been getting boring, so I took Squid-1.1.18
- * sources and added a new acl type for hard-wired access control:
- * 
- * acl <name> arp <Ethernet address> ...
- * 
- * For example,
- * 
- * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38
- *
- * NOTE: Linux code by David Luyer <luyer@ucs.uwa.edu.au>.
- *       Original (BSD-specific) code no longer works.
- *       Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
- */
 
-#ifdef _SQUID_SOLARIS_
-#include <sys/sockio.h>
-#else
-#include <sys/sysctl.h>
-#endif
-#ifdef _SQUID_LINUX_
-#include <net/if_arp.h>
-#include <sys/ioctl.h>
-#else
-#include <net/if_dl.h>
-#endif
-#include <net/route.h>
-#include <net/if.h>
-#if HAVE_NETINET_IF_ETHER_H
-#include <netinet/if_ether.h>
-#endif
 
-/*
- * Decode an ascii representation (asc) of an ethernet adress, and place
- * it in eth[6].
- */
-static int
-decode_eth(const char *asc, char *eth)
+
+void
+aclRegisterAclDirective(void)
 {
-    int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
-    if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) {
-	debug(28, 0) ("decode_eth: Invalid ethernet address '%s'\n", asc);
-	return 0;		/* This is not valid address */
-    }
-    eth[0] = (u_char) a1;
-    eth[1] = (u_char) a2;
-    eth[2] = (u_char) a3;
-    eth[3] = (u_char) a4;
-    eth[4] = (u_char) a5;
-    eth[5] = (u_char) a6;
-    return 1;
+
+//    parserRegisterName("acl",parserTypeByName("instance_node"),&Config.aclList2,default_if_none_acl,name_document_acl, NULL);
+//  parserRegisterInstanceType("
 }
 
-static acl_arp_data *
-aclParseArpData(const char *t)
+static void
+dump_acl(StoreEntry * entry, const char *name, void const * const data)
 {
-    LOCAL_ARRAY(char, eth, 256);
-    acl_arp_data *q = xcalloc(1, sizeof(acl_arp_data));
-    debug(28, 5) ("aclParseArpData: %s\n", t);
-    if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) {
-	debug(28, 0) ("aclParseArpData: Bad ethernet address: '%s'\n", t);
-	safe_free(q);
-	return NULL;
-    }
-    if (!decode_eth(eth, q->eth)) {
-	debug(28, 0) ("%s line %d: %s\n",
-	    cfg_filename, config_lineno, config_input_line);
-	debug(28, 0) ("aclParseArpData: Ignoring invalid ARP acl entry: can't parse '%s'\n", eth);
-	safe_free(q);
-	return NULL;
+    acl * ae=*(acl * *)data;
+//    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 0) ("dump_acl: %s %s\n", name, ae->name);
+        v = NULL; // w = aclDumpGeneric(ae);
+        while (v != NULL) {
+            debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                ae->aclname->namestr,
+                v->key);
+            v = v->next;
+        }
+//        wordlistDestroy(&w);
+        ae = ae->next;
     }
-    return q;
 }
 
-
-/*******************/
-/* aclParseArpList */
-/*******************/
 static void
-aclParseArpList(void *curlist)
+free_acl(parserNameNode *parserName, void *data)
 {
-    char *t = NULL;
-    splayNode **Top = curlist;
-    acl_arp_data *q = NULL;
-    while ((t = strtokFile())) {
-	if ((q = aclParseArpData(t)) == NULL)
-	    continue;
-	*Top = splay_insert(q, *Top, aclArpCompare);
-    }
+    int used;
+    acl ** ae=(acl **)data;
+    used=!check_null_acl(*ae);
+    aclDestroyAcls(ae);
+//    if (used)
+//      cbdataUnlock(parserName);
 }
 
-/***************/
-/* aclMatchArp */
-/***************/
-static int
-aclMatchArp(void *dataptr, struct in_addr c)
+void
+aclParserRegister(void)
 {
-#if defined(_SQUID_LINUX_)
-    struct arpreq arpReq;
-    struct sockaddr_in ipAddr;
-    unsigned char ifbuffer[sizeof(struct ifreq) * 64];
-    struct ifconf ifc;
-    struct ifreq *ifr;
-    int offset;
-    splayNode **Top = dataptr;
-    /*
-     * The linux kernel 2.2 maintains per interface ARP caches and
-     * thus requires an interface name when doing ARP queries.
-     * 
-     * The older 2.0 kernels appear to use a unified ARP cache,
-     * and require an empty interface name
-     * 
-     * To support both, we attempt the lookup with a blank interface
-     * name first. If that does not succeed, the try each interface
-     * in turn
-     */
-    /*
-     * Set up structures for ARP lookup with blank interface name
-     */
-    ipAddr.sin_family = AF_INET;
-    ipAddr.sin_port = 0;
-    ipAddr.sin_addr = c;
-    memset(&arpReq, '\0', sizeof(arpReq));
-    xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
-    /* Query ARP table */
-    if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
-	/* Skip non-ethernet interfaces */
-	if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
-	    return 0;
-	}
-	debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
-	    arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
-	    arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
-	    arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
-	/* Do lookup */
-	*Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
-	debug(28, 3) ("aclMatchArp: '%s' %s\n",
-	    inet_ntoa(c), splayLastResult ? "NOT found" : "found");
-	return (0 == splayLastResult);
-    }
-    /* lookup list of interface names */
-    ifc.ifc_len = sizeof(ifbuffer);
-    ifc.ifc_buf = ifbuffer;
-    if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) {
-	debug(28, 1) ("Attempt to retrieve interface list failed: %s\n",
-	    xstrerror());
-	return 0;
-    }
-    if (ifc.ifc_len > sizeof(ifbuffer)) {
-	debug(28, 1) ("Interface list too long - %d\n", ifc.ifc_len);
-	return 0;
-    }
-    /* Attempt ARP lookup on each interface */
-    offset = 0;
-    while (offset < ifc.ifc_len) {
-	ifr = (struct ifreq *) (ifbuffer + offset);
-	offset += sizeof(*ifr);
-	/* Skip loopback and aliased interfaces */
-	if (0 == strncmp(ifr->ifr_name, "lo", 2))
-	    continue;
-	if (NULL != strchr(ifr->ifr_name, ':'))
-	    continue;
-	debug(28, 4) ("Looking up ARP address for %s on %s\n", inet_ntoa(c),
-	    ifr->ifr_name);
-	/* Set up structures for ARP lookup */
-	ipAddr.sin_family = AF_INET;
-	ipAddr.sin_port = 0;
-	ipAddr.sin_addr = c;
-	memset(&arpReq, '\0', sizeof(arpReq));
-	xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
-	strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1);
-	arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0';
-	/* Query ARP table */
-	if (-1 == ioctl(HttpSockets[0], SIOCGARP, &arpReq)) {
-	    /*
-	     * Query failed.  Do not log failed lookups or "device
-	     * not supported"
-	     */
-	    if (ENXIO == errno)
-		(void) 0;
-	    else if (ENODEV == errno)
-		(void) 0;
-	    else
-		debug(28, 1) ("ARP query failed: %s: %s\n",
-		    ifr->ifr_name, xstrerror());
-	    continue;
-	}
-	/* Skip non-ethernet interfaces */
-	if (arpReq.arp_ha.sa_family != ARPHRD_ETHER)
-	    continue;
-	debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x on %s\n",
-	    arpReq.arp_ha.sa_data[0] & 0xff,
-	    arpReq.arp_ha.sa_data[1] & 0xff,
-	    arpReq.arp_ha.sa_data[2] & 0xff,
-	    arpReq.arp_ha.sa_data[3] & 0xff,
-	    arpReq.arp_ha.sa_data[4] & 0xff,
-	    arpReq.arp_ha.sa_data[5] & 0xff, ifr->ifr_name);
-	/* Do lookup */
-	*Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
-	/* Return if match, otherwise continue to other interfaces */
-	if (0 == splayLastResult) {
-	    debug(28, 3) ("aclMatchArp: %s found on %s\n",
-		inet_ntoa(c), ifr->ifr_name);
-	    return 1;
-	}
-	/*
-	 * Should we stop looking here? Can the same IP address
-	 * exist on multiple interfaces?
-	 */
-    }
-#elif defined(_SQUID_SOLARIS_)
-    struct arpreq arpReq;
-    struct sockaddr_in ipAddr;
-    unsigned char ifbuffer[sizeof(struct ifreq) * 64];
-    struct ifconf ifc;
-    struct ifreq *ifr;
-    int offset;
-    splayNode **Top = dataptr;
-    /*
-     * Set up structures for ARP lookup with blank interface name
-     */
-    ipAddr.sin_family = AF_INET;
-    ipAddr.sin_port = 0;
-    ipAddr.sin_addr = c;
-    memset(&arpReq, '\0', sizeof(arpReq));
-    xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
-    /* Query ARP table */
-    if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
-	/*
-	 *  Solaris (at least 2.6/x86) does not use arp_ha.sa_family -
-	 * it returns 00:00:00:00:00:00 for non-ethernet media 
-	 */
-	if (arpReq.arp_ha.sa_data[0] == 0 &&
-	    arpReq.arp_ha.sa_data[1] == 0 &&
-	    arpReq.arp_ha.sa_data[2] == 0 &&
-	    arpReq.arp_ha.sa_data[3] == 0 &&
-	    arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0)
-	    return 0;
-	debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
-	    arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
-	    arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
-	    arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
-	/* Do lookup */
-	*Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
-	debug(28, 3) ("aclMatchArp: '%s' %s\n",
-	    inet_ntoa(c), splayLastResult ? "NOT found" : "found");
-	return (0 == splayLastResult);
-    }
-#else
-    WRITE ME;
+    // This should be in the acl module init code.
+    if (!acl_pool)
+	acl_pool = memPoolCreate("acl", sizeof(acl));
+    if (!acl_deny_info_list_pool)
+	acl_deny_info_list_pool = memPoolCreate("acl_deny_info_list", 
+	    sizeof(acl_deny_info_list));
+    if (!acl_ip_data_pool)
+	acl_ip_data_pool = memPoolCreate("acl_ip_data", sizeof(acl_ip_data));
+    if (!acl_name_list_pool)
+	acl_name_list_pool = memPoolCreate("acl_name_list", sizeof(acl_name_list));
+    if (!acl_time_data_pool)
+	acl_time_data_pool = memPoolCreate("acl_time_data", sizeof(acl_time_data));
+    if (!acl_proxy_auth_match_pool)
+	acl_proxy_auth_match_pool = memPoolCreate("acl_proxy_auth_match_cache",
+	    sizeof(acl_proxy_auth_match_cache));
+    if (!acl_user_data_pool)
+	acl_user_data_pool = memPoolCreate("acl_user_data", sizeof(acl_user_data));
+
+    /* register the ACL types */
+    parserRegisterType("acl",aclParseAclLine,free_acl,dump_acl);
+
+    parserRegisterType("denyinfo",parse_denyinfo,free_denyinfo,dump_denyinfo);
+
+    parserRegisterType("iplist", aclParseIpList, aclDestroyIpList, dump_IpList );
+    parserRegisterType("domainlist", aclParseDomainList, aclDestroyDomainList, dump_DomainList);
+    parserRegisterType("regexlist", aclParseRegexList, aclDestroyRegexList, dump_RegexList);
+    parserRegisterType("timespec", aclParseTimeSpec, aclDestroyTimeSpecList, dump_TimeSpec);
+    parserRegisterType("intlist", aclParseIntRange, free_intlist, dump_intlistList);
+    parserRegisterType("intrange", aclParseIntRange, aclDestroyIntRange, dump_IntRangeList);
+    parserRegisterType("userlist", aclParseUserList, aclDestroyUserList, dump_UserList);
+    parserRegisterType("aclwordlist", parse_wordlistFromFile, free_wordlist, dump_wordlist);
+    parserRegisterType("protolist", aclParseProtoList, free_intlist, dump_ProtoList);
+    parserRegisterType("methodlist", aclParseMethodList, free_intlist, dump_MethodList);
+#if 0
+    parserRegisterType("arplist", aclParseArpList, aclDestroyArpList, dump_ArpList);
+#endif
+
+    parserRegisterName(NULL, "deny_info",parserTypeByName("denyinfo"),
+	&Config.denyInfoList,NULL,name_document_deny_info, NULL);
+
+    /* register the acl instance names */
+    aclRegisterAclName("src", parserTypeByName("iplist"), aclMatchSrc);
+    aclRegisterAclName("dst", parserTypeByName("iplist"), aclMatchDst);
+    aclRegisterAclName("myip", parserTypeByName("iplist"), aclMatchMyip);
+
+    aclRegisterAclName("srcdomain", parserTypeByName("domainlist"), aclMatchSrcDomain);
+    aclRegisterAclName("dstdomain", parserTypeByName("domainlist"), aclMatchDstDomain);
+    aclRegisterAclName("domain", parserTypeByName("domainlist"), aclMatchDstDomain);
+
+    aclRegisterAclName("dstdom_regex", parserTypeByName("regexlist"), aclMatchSrcDomain);
+    aclRegisterAclName("srcdom_regex", parserTypeByName("regexlist"), aclMatchSrcDomain);
+    aclRegisterAclName("pattern",      parserTypeByName("regexlist"), aclMatchUrlPathRegex);
+    aclRegisterAclName("urlpath_regex", parserTypeByName("regexlist"), aclMatchUrlPathRegex);
+    aclRegisterAclName("url_regex",    parserTypeByName("regexlist"), aclMatchUrlRegex);
+    aclRegisterAclName("browser", parserTypeByName("regexlist"), aclMatchBrowser);
+    aclRegisterAclName("req_mime_type", parserTypeByName("regexlist"), aclMatchRepMimeType);
+    aclRegisterAclName("rep_mime_type", parserTypeByName("regexlist"), aclMatchReqMimeType);
+#if USE_IDENT
+    aclRegisterAclName("ident", parserTypeByName("userlist"), aclMatchIdent);
+    aclRegisterAclName("ident_regex", parserTypeByName("regexlist"), aclMatchIdentRegex);
 #endif
-    /*
-     * Address was not found on any interface
-     */
-    debug(28, 3) ("aclMatchArp: %s NOT found\n", inet_ntoa(c));
-    return 0;
-}
+    proxy_auth_name = aclRegisterAclName("proxy_auth", parserTypeByName("userlist"), aclMatchProxyAuthModule);
+    proxy_auth_regex_name = aclRegisterAclName("proxy_auth_regex", parserTypeByName("regexlist"), aclMatchProxyAuthModule);
 
-static int
-aclArpCompare(const void *a, const void *b)
-{
-#if defined(_SQUID_LINUX_)
-    const unsigned short *d1 = a;
-    const unsigned short *d2 = b;
-    if (d1[0] != d2[0])
-	return (d1[0] > d2[0]) ? 1 : -1;
-    if (d1[1] != d2[1])
-	return (d1[1] > d2[1]) ? 1 : -1;
-    if (d1[2] != d2[2])
-	return (d1[2] > d2[2]) ? 1 : -1;
-#elif defined(_SQUID_SOLARIS_)
-    const unsigned char *d1 = a;
-    const unsigned char *d2 = b;
-    if (d1[0] != d2[0])
-	return (d1[0] > d2[0]) ? 1 : -1;
-    if (d1[1] != d2[1])
-	return (d1[1] > d2[1]) ? 1 : -1;
-    if (d1[2] != d2[2])
-	return (d1[2] > d2[2]) ? 1 : -1;
-    if (d1[3] != d2[3])
-	return (d1[3] > d2[3]) ? 1 : -1;
-    if (d1[4] != d2[4])
-	return (d1[4] > d2[4]) ? 1 : -1;
-    if (d1[5] != d2[5])
-	return (d1[5] > d2[5]) ? 1 : -1;
-#else
-    WRITE ME;
+    aclRegisterAclName("time", parserTypeByName("timespec"), aclMatchTime);
+
+    aclRegisterAclName("maxconn", parserTypeByName("int"), aclMatchMaxConn);
+
+    aclRegisterAclName("port", parserTypeByName("intrange"), aclMatchUrlPort);
+    aclRegisterAclName("myport", parserTypeByName("intrange"), aclMatchMyPort);
+#if SQUID_SNMP
+    aclRegisterAclName("snmp_community", parserTypeByName("aclwordlist"), aclMatchSNMPCommunity);
 #endif
-    return 0;
-}
 
-#if UNUSED_CODE
-/**********************************************************************
-* This is from the pre-splay-tree code for BSD
-* I suspect the Linux approach will work on most O/S and be much
-* better - <luyer@ucs.uwa.edu.au>
-***********************************************************************
-static int
-checkARP(u_long ip, char *eth)
-{
-    int mib[6] =
-    {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
-    size_t needed;
-    char *buf, *next, *lim;
-    struct rt_msghdr *rtm;
-    struct sockaddr_inarp *sin;
-    struct sockaddr_dl *sdl;
-    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
-	debug(28, 0) ("Can't estimate ARP table size!\n");
-	return 0;
-    }
-    if ((buf = xmalloc(needed)) == NULL) {
-	debug(28, 0) ("Can't allocate temporary ARP table!\n");
-	return 0;
-    }
-    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
-	debug(28, 0) ("Can't retrieve ARP table!\n");
-	xfree(buf);
-	return 0;
-    }
-    lim = buf + needed;
-    for (next = buf; next < lim; next += rtm->rtm_msglen) {
-	rtm = (struct rt_msghdr *) next;
-	sin = (struct sockaddr_inarp *) (rtm + 1);
-	sdl = (struct sockaddr_dl *) (sin + 1);
-	if (sin->sin_addr.s_addr == ip) {
-	    if (sdl->sdl_alen)
-		if (!memcmp(LLADDR(sdl), eth, 6)) {
-		    xfree(buf);
-		    return 1;
-		}
-	    break;
-	}
-    }
-    xfree(buf);
-    return 0;
-}
-**********************************************************************/
+    aclRegisterAclName("proto", parserTypeByName("protolist"), aclMatchProto);
+    aclRegisterAclName("method", parserTypeByName("methodlist"), aclMatchMethod);
+
+    aclRegisterAclName("src_as", parserTypeByName("intlist"), aclMatchSrcAsn);
+    aclRegisterAclName("dst_as", parserTypeByName("intlist"), aclMatchDstAsn);
+
+#if 0
+#if USE_ARP_ACL
+    aclRegisterAclName("arp", parserTypeByName("arplist"), aclMatchSrcArp);
+#endif
 #endif
 
-static void
-aclDumpArpListWalkee(void *node, void *state)
-{
-    acl_arp_data *arp = node;
-    wordlist **W = state;
-    static char buf[24];
-    while (*W != NULL)
-	W = &(*W)->next;
-    snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
-	arp->eth[0], arp->eth[1], arp->eth[2], arp->eth[3],
-	arp->eth[4], arp->eth[5]);
-    wordlistAdd(state, buf);
-}
+#if SRC_RTT_NOT_YET_FINISHED
+    aclRegisterAclName("src_rtt", parserTypeByName("intlist"),aclMatchSrcRTT);
+#endif
 
-static wordlist *
-aclDumpArpList(void *data)
-{
-    wordlist *w = NULL;
-    splay_walk(data, aclDumpArpListWalkee, &w);
-    return w;
-}
 
-/* ==== END ARP ACL SUPPORT =============================================== */
-#endif /* USE_ARP_ACL */
+    if (aclinstances)
+        debug(3,0)("reconfiguring is broken just now!!! \n\n");
+    /* this creates a hierarchical branch */
+    aclinstances = parserRegisterInstanceName("acl", parserTypeByName("acl"), NULL, NULL);
+    /* this registers the hierarchical branch as "acl" */
+    parserRegisterName(NULL, "acl", parserTypeByName("instance_node"), aclinstances, default_if_none_acl, name_document_acl, NULL);
+}
Index: squid/src/acl.h
diff -u /dev/null squid/src/acl.h:1.1.2.6
--- /dev/null	Tue Sep 28 18:35:57 2004
+++ squid/src/acl.h	Sat May 12 08:22:30 2001
@@ -0,0 +1,109 @@
+
+/*
+ * $Id$
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef _ACL_H_
+#define _ACL_H_
+
+typedef enum {
+    /* callback in progress */
+    ACL_MATCH_NEED_LOOKUP = -1,
+    /* as it says */
+    ACL_MATCH_NOTFOUND = 0,
+    /* likewise */
+    ACL_MATCH_FOUND = 1,
+    /* cannot check at all, but don't treat as a match or a non-match */
+    ACL_MATCH_INSUFFICIENT_INFORMATION = 2
+} acl_match_rv;
+
+typedef struct _aclName aclName;
+/* pointer to a pointer to the acl data, a pointer to the checklist, and a flag block */
+typedef int ACLMATCH(acl * , aclCheck_t *, unsigned int);
+
+struct _acl {
+    char name[ACL_NAME_SZ];
+    aclName *aclname;
+    void *data;
+    char *cfgline;
+    acl *next;
+};
+
+struct _acl_user_data {
+    splayNode *names;
+    struct {
+        unsigned int case_insensitive:1;
+        unsigned int required:1;
+    } flags;
+};
+
+
+struct _acl_ip_data {
+    struct in_addr addr1;       /* if addr2 non-zero then its a range */
+    struct in_addr addr2;
+    struct in_addr mask;
+    acl_ip_data *next;          /* used for parsing, not for storing */
+};
+
+struct _acl_time_data {
+    int weekbits;
+    int start;
+    int stop;
+    acl_time_data *next;
+};
+
+struct _aclName {
+    dlink_node node;
+    char * namestr;
+    parserTypeNode *type;
+    ACLMATCH *match;
+};
+
+struct _acl_name_list {
+    char name[ACL_NAME_SZ];
+    acl_name_list *next;
+};
+
+struct _acl_proxy_auth_match_cache {
+    dlink_node link;
+    int matchrv;
+    void *acl_data;
+};
+
+extern aclName *aclRegisterAclName(const char *, parserTypeNode *, ACLMATCH *);
+extern aclName *aclNameByName(const char *);
+
+/* global variables for acl code */
+extern acl * AclMatchedAcl;
+
+#define ACL_FASTCHECK 0x0001
+
+#endif /* ACL_H */
Index: squid/src/asn.c
diff -u squid/src/asn.c:1.10 squid/src/asn.c:1.9.4.4
--- squid/src/asn.c:1.10	Sat Mar  3 02:44:31 2001
+++ squid/src/asn.c	Wed Apr 25 17:09:08 2001
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "acl.h"
 
 #define WHOIS_PORT 43
 
@@ -88,7 +89,7 @@
 static STCB asHandleReply;
 static int destroyRadixNode(struct radix_node *rn, void *w);
 static int printRadixNode(struct radix_node *rn, void *w);
-static void asnAclInitialize(acl * acls);
+static void asnAclInitialize();
 static void asStateFree(void *data);
 static void destroyRadixNodeInfo(as_info *);
 static OBJH asnStats;
@@ -133,13 +134,32 @@
 }
 
 static void
-asnAclInitialize(acl * acls)
+asnAclInitialize()
 {
     acl *a;
     intlist *i;
+    parserNameNode *aclparserName = parserNameByName("acl");
+    parserNameNode *parserName;
+    aclName *srcName, *dstName; 
+    dlink_node *node;
     debug(53, 3) ("asnAclInitialize\n");
-    for (a = acls; a; a = a->next) {
-	if (a->type != ACL_DST_ASN && a->type != ACL_SRC_ASN)
+
+    // FIXME: heal the abstraction
+    if (!aclparserName || aclparserName->children.head==NULL)
+	return;
+
+    srcName = aclNameByName("src_as");
+    dstName = aclNameByName("dst_as");
+    /* we're not a module yet: these _must_be registered */
+    assert(srcName);
+    assert(dstName);
+
+    node=aclparserName->children.head;
+    while (node) {
+	parserName=node->data;
+	node=node->next;
+	a=parserName->location;
+	if (a->aclname != srcName && a->aclname != dstName)
 	    continue;
 	for (i = a->data; i; i = i->next)
 	    asnCacheStart(i->i);
@@ -159,7 +179,7 @@
     if (0 == inited++)
 	rn_init();
     rn_inithead((void **) &AS_tree_head, 8);
-    asnAclInitialize(Config.aclList);
+    asnAclInitialize();
     cachemgrRegister("asndb", "AS Number Database", asnStats, 0, 1);
 }
 
Index: squid/src/auth_modules.sh
diff -u squid/src/auth_modules.sh:1.2 squid/src/auth_modules.sh:removed
--- squid/src/auth_modules.sh:1.2	Sun Jan  7 16:02:37 2001
+++ squid/src/auth_modules.sh	Tue Sep 28 18:35:57 2004
@@ -1,15 +0,0 @@
-#!/bin/sh
-echo "/* automatically generated by $0 $*"
-echo " * do not edit"
-echo " */"
-echo "#include \"squid.h\""
-echo ""
-for module in "$@"; do
-   echo "extern AUTHSSETUP authSchemeSetup_${module};"
-done
-echo "void authSchemeSetup(void)"
-echo "{"
-for module in "$@"; do
-   echo "	authSchemeAdd(\"$module\", authSchemeSetup_${module});"
-done
-echo "}"
Index: squid/src/authenticate.c
diff -u squid/src/authenticate.c:1.13 squid/src/authenticate.c:1.12.4.3
--- squid/src/authenticate.c:1.13	Fri Mar  9 16:58:00 2001
+++ squid/src/authenticate.c	Sat Mar 31 01:52:19 2001
@@ -59,8 +59,8 @@
 {
     authScheme *scheme;
     int i;
-    for (i = 0; i < Config.authConfig.n_configured; i++) {
-	scheme = Config.authConfig.schemes + i;
+    for (i = 0; i < Config.authSchemes.n_configured; i++) {
+	scheme = Config.authSchemes.schemes + i;
 	if ((strncasecmp(proxy_auth, scheme->typestr, strlen(scheme->typestr)) == 0) &&
 	    (authscheme_list[scheme->Id].Active()))
 	    return 1;
@@ -345,20 +345,14 @@
 }
 
 void
-authenticateSchemeInit(void)
-{
-    authSchemeSetup();
-}
-
-void
-authenticateInit(authConfig * config)
+authenticateInit(authSchemes * config)
 {
     int i;
     authScheme *scheme;
     for (i = 0; i < config->n_configured; i++) {
 	scheme = config->schemes + i;
 	if (authscheme_list[scheme->Id].init && authscheme_list[scheme->Id].configured()) {
-	    authscheme_list[scheme->Id].init(scheme);
+	    authscheme_list[scheme->Id].init();
 	}
     }
     if (!proxy_auth_username_cache)
@@ -416,8 +410,8 @@
 	    int i;
 	    authScheme *scheme;
 	    /* call each configured & running authscheme */
-	    for (i = 0; i < Config.authConfig.n_configured; i++) {
-		scheme = Config.authConfig.schemes + i;
+	    for (i = 0; i < Config.authSchemes.n_configured; i++) {
+		scheme = Config.authSchemes.schemes + i;
 		if (authscheme_list[scheme->Id].Active())
 		    authscheme_list[scheme->Id].authFixHeader(auth_user_request, rep, type,
 			request);
@@ -635,7 +629,7 @@
  * called to add another auth scheme module
  */
 void
-authSchemeAdd(char *type, AUTHSSETUP * setup)
+authSchemeAdd(const char *type, AUTHSSETUP * setup)
 {
     int i;
     debug(29, 4) ("authSchemeAdd: adding %s", type);
Index: squid/src/cache_cf.c
diff -u squid/src/cache_cf.c:1.24 squid/src/cache_cf.c:1.18.4.32
--- squid/src/cache_cf.c:1.24	Tue May  8 08:27:00 2001
+++ squid/src/cache_cf.c	Sat May 12 06:06:03 2001
@@ -35,6 +35,9 @@
 
 #include "squid.h"
 
+// FIXME: we should be a stub file - not needing acl code.
+#include "acl.h"
+
 #if SQUID_SNMP
 #include "snmp.h"
 #endif
@@ -58,34 +61,75 @@
 static struct cache_dir_option common_cachedir_options[];
 
 static void update_maxobjsize(void);
-static void configDoConfigure(void);
-static void parse_refreshpattern(refresh_t **);
+static int  configDoConfigure(void);
+static PARSER_PARSE parse_refreshpattern;
 static int parseTimeUnits(const char *unit);
 static void parseTimeLine(time_t * tptr, const char *units);
-static void parse_ushort(u_short * var);
-static void parse_string(char **);
-void parse_wordlist(wordlist **);
-static void default_all(void);
+static PARSER_PARSE parse_ushort;
+static PARSER_PARSE parse_string;
+PARSER_PARSE parse_wordlist;
 static void defaults_if_none(void);
+void default_line(const char *);
 static int parse_line(char *);
 static void parseBytesLine(size_t * bptr, const char *units);
 static size_t parseBytesUnits(const char *unit);
 static void free_all(void);
+static void parserRegisterAllTypes(void);
+static void parserRegisterCFTypes(void);
+static void parserDeregisterAllTypes(void);
+static void parserRegisterAllNames(void);
+static void parserRegisterCFNames(void);
+static void parserDeregisterAllNames(void);
 void requirePathnameExists(const char *name, const char *path);
 static OBJH dump_config;
-static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
-static void parse_http_header_access(header_mangler header[]);
-static void free_http_header_access(header_mangler header[]);
-static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
-static void parse_http_header_replace(header_mangler * header);
-static void free_http_header_replace(header_mangler * header);
-static void parse_denyinfo(acl_deny_info_list ** var);
-static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
-static void free_denyinfo(acl_deny_info_list ** var);
-static void parse_sockaddr_in_list(sockaddr_in_list **);
-static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
-static void free_sockaddr_in_list(sockaddr_in_list **);
+static PARSER_DUMP dump_http_header_access;
+static PARSER_PARSE parse_http_header_access;
+static PARSER_FREE free_http_header_access;
+static PARSER_DUMP dump_http_header_replace;
+static PARSER_PARSE parse_http_header_replace;
+static PARSER_FREE free_http_header_replace;
+static PARSER_PARSE parse_sockaddr_in_list;
+static PARSER_DUMP dump_sockaddr_in_list;
+static PARSER_FREE free_sockaddr_in_list;
 static int check_null_sockaddr_in_list(const sockaddr_in_list *);
+
+/* create instances */
+static PARSER_PARSE parse_instance_node;
+static PARSER_FREE free_instance_node;
+static PARSER_DUMP dump_instance_node;
+/* refer to instances */
+static PARSER_PARSE parse_instance_reference;
+static PARSER_FREE free_instance_reference;
+static PARSER_DUMP dump_instance_reference;
+
+/* self documentating support */
+typedef struct _docoptionNode docoptionNode;
+typedef struct _docoptions docoptions;
+struct _docoptionNode {
+    docoptionNode *next;
+    char *name;
+};
+struct _docoptions {
+    docoptionNode *head;
+    struct {
+        unsigned int internalonly:1;
+        unsigned int all:1;
+    } flags;
+};
+
+static docoptions *DoDocumentOptions = NULL;
+
+/* dynamic type and name support */
+parserTypeNode *parserTypeByName(const char *);
+void parserRegisterType(const char *, PARSER_PARSE *, PARSER_FREE *, PARSER_DUMP *);
+void parserDeregisterType(parserTypeNode *);
+parserNameNode *parserNameByName(const char *name);
+void parserRegisterName(parserNameNode *, const char *, parserTypeNode *, void *, PARSER_DEFAULT_NONE *, PARSER_NAME_DOCUMENT *, PARSER_POST_PARSE *);
+void parserDeregisterName(parserNameNode *);
+static int parserNameDoPostParse(void);
+static int parse_line(char *buff);
+static void free_all(void);
+
 #if USE_SSL
 static void parse_https_port_list(https_port_list **);
 static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
@@ -102,6 +146,8 @@
 	cfg_filename, config_lineno, config_input_line);
 }
 
+/* Generic wordlist routines - should be in a library! */
+
 void
 wordlistDestroy(wordlist ** list)
 {
@@ -166,9 +212,13 @@
     return D;
 }
 
+/****************** END OF WORDLIST ROUTINES ****************/
+
 void
-intlistDestroy(intlist ** list)
+free_intlist(parserNameNode *parserName, void *data)
 {
+    intlist ** list=data;
+
     intlist *w = NULL;
     intlist *n = NULL;
     for (w = *list; w; w = n) {
@@ -188,12 +238,6 @@
     return 0;
 }
 
-
-/*
- * Use this #define in all the parse*() functions.  Assumes char *token is
- * defined
- */
-
 int
 GetInteger(void)
 {
@@ -226,21 +270,22 @@
     char *token = NULL;
     char *tmp_line;
     int err_count = 0;
-    free_all();
-    default_all();
+    int local_lineno;
+    const char *local_filename;
     if ((fp = fopen(file_name, "r")) == NULL)
 	fatalf("Unable to open configuration file: %s: %s",
 	    file_name, xstrerror());
 #if defined(_SQUID_CYGWIN_)
     setmode(fileno(fp), O_TEXT);
 #endif
-    cfg_filename = file_name;
-    if ((token = strrchr(cfg_filename, '/')))
-	cfg_filename = token + 1;
+    local_filename = file_name;
+    if ((token = strrchr(local_filename, '/')))
+	local_filename = token + 1;
     memset(config_input_line, '\0', BUFSIZ);
-    config_lineno = 0;
+    local_lineno = 0;
     while (fgets(config_input_line, BUFSIZ, fp)) {
-	config_lineno++;
+	config_lineno=(local_lineno++);
+	cfg_filename = local_filename;
 	if ((token = strchr(config_input_line, '\n')))
 	    *token = '\0';
 	if (config_input_line[0] == '#')
@@ -258,8 +303,21 @@
 	safe_free(tmp_line);
     }
     fclose(fp);
+    return err_count;
+}
+
+int
+parserReconfigure(const char *file_name)
+{
+    int err_count = 0;
+    free_all();
+    parserDeregisterAllNames();
+    parserDeregisterAllTypes();
+    parserRegisterAllTypes();
+    parserRegisterAllNames();
+    err_count=parseConfigFile(file_name);
     defaults_if_none();
-    configDoConfigure();
+    err_count += configDoConfigure();
     cachemgrRegister("config",
 	"Current Squid Configuration",
 	dump_config,
@@ -267,10 +325,11 @@
     return err_count;
 }
 
-static void
+static int
 configDoConfigure(void)
 {
     LOCAL_ARRAY(char, buf, BUFSIZ);
+    int rv=0;
     memset(&Config2, '\0', sizeof(SquidConfig2));
     /* init memory as early as possible */
     memConfigure();
@@ -415,6 +474,8 @@
 	Config2.effectiveGroupID = grp->gr_gid;
     }
     urlExtMethodConfigure();
+    rv += parserNameDoPostParse();
+    return rv;
 }
 
 /* Parse a time specification from the config file.  Store the
@@ -509,43 +570,16 @@
  * Max
  *****************************************************************************/
 
-static void
-dump_acl(StoreEntry * entry, const char *name, acl * ae)
-{
-    wordlist *w;
-    wordlist *v;
-    while (ae != NULL) {
-	debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
-	v = w = aclDumpGeneric(ae);
-	while (v != NULL) {
-	    debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
-	    storeAppendPrintf(entry, "%s %s %s %s\n",
-		name,
-		ae->name,
-		aclTypeToStr(ae->type),
-		v->key);
-	    v = v->next;
-	}
-	wordlistDestroy(&w);
-	ae = ae->next;
-    }
-}
-
-static void
-parse_acl(acl ** ae)
-{
-    aclParseAclLine(ae);
-}
-
-static void
-free_acl(acl ** ae)
+static int
+check_null_acl_access(acl_access * a)
 {
-    aclDestroyAcls(ae);
+    return a == NULL;
 }
 
 static void
-dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
+dump_acl_access(StoreEntry * entry, const char *name, void const * const data)
 {
+    acl_access *head=*(acl_access **)data;
     acl_list *l;
     while (head != NULL) {
 	storeAppendPrintf(entry, "%s %s",
@@ -562,26 +596,37 @@
 }
 
 static void
-parse_acl_access(acl_access ** head)
+parse_acl_access(parserNameNode *parserName, void * data)
 {
+    acl_access ** head=(acl_access **)data;
+    if (check_null_acl_access(*head))
+	cbdataLock(parserName);
     aclParseAccessLine(head);
 }
 
 static void
-free_acl_access(acl_access ** head)
+free_acl_access(parserNameNode *parserName, void * data)
 {
+    int used;
+    acl_access ** head=(acl_access **)data;
+    used = !check_null_acl_access(*head);
     aclDestroyAccessList(head);
+    if (used)
+	cbdataUnlock(parserName);
 }
 
 static void
-dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
+dump_address(StoreEntry * entry, const char *name, void const * const data)
 {
+    struct in_addr addr=*(struct in_addr *)data;
     storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
 }
 
 static void
-parse_address(struct in_addr *addr)
+parse_address(parserNameNode *parserName, void * data)
 {
+    /* no memory allocated - no need to lock the NameNode */
+    struct in_addr *addr=data;
     const struct hostent *hp;
     char *token = strtok(NULL, w_space);
 
@@ -596,26 +641,29 @@
 }
 
 static void
-free_address(struct in_addr *addr)
+free_address(parserNameNode *parserName, void * data)
 {
+    struct in_addr *addr=data;
     memset(addr, '\0', sizeof(struct in_addr));
 }
 
 #if DELAY_POOLS
 
+/*
+ * TODO: FIXME: Delay pools spits out an incorrect config on dump with the new dump code.
+ * The delay pools parseing code is one big chunk, not broken out per type.
+ * The parserName should get locked and freed here, but to hard for now
+ */
+
+
 /* do nothing - free_delay_pool_count is the magic free function.
  * this is why delay_pool_count isn't just marked TYPE: ushort
  */
-#define free_delay_pool_class(X)
-#define free_delay_pool_access(X)
-#define free_delay_pool_rates(X)
-#define dump_delay_pool_class(X, Y, Z)
-#define dump_delay_pool_access(X, Y, Z)
-#define dump_delay_pool_rates(X, Y, Z)
 
 static void
-free_delay_pool_count(delayConfig * cfg)
+free_delay_pool_count(parserNameNode *parserName, void * data)
 {
+    delayConfig * cfg=data;
     int i;
 
     if (!cfg->pools)
@@ -634,9 +682,14 @@
     memset(cfg, 0, sizeof(*cfg));
 }
 
+#define free_delay_pool_class free_delay_pool_count
+#define free_delay_pool_access free_delay_pool_count
+#define free_delay_pool_rates  free_delay_pool_count
+
 static void
-dump_delay_pool_count(StoreEntry * entry, const char *name, delayConfig cfg)
+dump_delay_pool_count(StoreEntry * entry, const char *name, void const * const data)
 {
+    delayConfig cfg=*(delayConfig *)data;
     int i;
     LOCAL_ARRAY(char, nom, 32);
 
@@ -666,14 +719,19 @@
     }
 }
 
+#define dump_delay_pool_class  dump_delay_pool_count
+#define dump_delay_pool_access dump_delay_pool_count
+#define dump_delay_pool_rates  dump_delay_pool_count
+
 static void
-parse_delay_pool_count(delayConfig * cfg)
+parse_delay_pool_count(parserNameNode *parserName, void * data)
 {
+    delayConfig * cfg=data;
     if (cfg->pools) {
 	debug(3, 0) ("parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config\n");
-	free_delay_pool_count(cfg);
+	free_delay_pool_count(parserName, cfg);
     }
-    parse_ushort(&cfg->pools);
+    parse_ushort(parserName, &cfg->pools);
     delayInitDelayData(cfg->pools);
     cfg->class = xcalloc(cfg->pools, sizeof(u_char));
     cfg->rates = xcalloc(cfg->pools, sizeof(delaySpecSet *));
@@ -681,16 +739,17 @@
 }
 
 static void
-parse_delay_pool_class(delayConfig * cfg)
+parse_delay_pool_class(parserNameNode *parserName, void * data)
 {
+    delayConfig * cfg=data;
     ushort pool, class;
 
-    parse_ushort(&pool);
+    parse_ushort(parserName, &pool);
     if (pool < 1 || pool > cfg->pools) {
 	debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
 	return;
     }
-    parse_ushort(&class);
+    parse_ushort(parserName, &class);
     if (class < 1 || class > 3) {
 	debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d class %d not in 1 .. 3\n", pool, class);
 	return;
@@ -711,14 +770,15 @@
 }
 
 static void
-parse_delay_pool_rates(delayConfig * cfg)
+parse_delay_pool_rates(parserNameNode *parserName, void * data)
 {
+    delayConfig * cfg=data;
     ushort pool, class;
     int i;
     delaySpec *ptr;
     char *token;
 
-    parse_ushort(&pool);
+    parse_ushort(parserName, &pool);
     if (pool < 1 || pool > cfg->pools) {
 	debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
 	return;
@@ -756,35 +816,38 @@
 }
 
 static void
-parse_delay_pool_access(delayConfig * cfg)
+parse_delay_pool_access(parserNameNode *parserName, void * data)
 {
+    delayConfig * cfg=data;
     ushort pool;
 
-    parse_ushort(&pool);
+    parse_ushort(parserName, &pool);
     if (pool < 1 || pool > cfg->pools) {
 	debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
 	return;
     }
-    aclParseAccessLine(&cfg->access[pool - 1]);
+    parse_acl_access(parserName, &cfg->access[pool - 1]);
 }
 #endif
 
 static void
-dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
+dump_http_header_access(StoreEntry * entry, const char *name, void const * const data)
 {
+    header_mangler *header=(header_mangler *)data;
     int i;
     for (i = 0; i < HDR_ENUM_END; i++) {
 	if (header[i].access_list != NULL) {
 	    storeAppendPrintf(entry, "%s ", name);
 	    dump_acl_access(entry, httpHeaderNameById(i),
-		header[i].access_list);
+		&header[i].access_list);
 	}
     }
 }
 
 static void
-parse_http_header_access(header_mangler header[])
+parse_http_header_access(parserNameNode *parserName, void * data)
 {
+    header_mangler *header=data;
     int id, i;
     char *t = NULL;
     if ((t = strtok(NULL, w_space)) == NULL) {
@@ -806,7 +869,7 @@
 	return;
     }
     if (id != HDR_ENUM_END) {
-	parse_acl_access(&header[id].access_list);
+	parse_acl_access(parserName, &header[id].access_list);
     } else {
 	char *next_string = t + strlen(t) - 1;
 	*next_string = 'A';
@@ -814,25 +877,26 @@
 	for (i = 0; i < HDR_ENUM_END; i++) {
 	    char *new_string = xstrdup(next_string);
 	    strtok(new_string, w_space);
-	    parse_acl_access(&header[i].access_list);
+	    parse_acl_access(parserName, &header[i].access_list);
 	    safe_free(new_string);
 	}
     }
 }
 
 static void
-free_http_header_access(header_mangler header[])
+free_http_header_access(parserNameNode *parserName, void * data)
 {
+    header_mangler *header=data;
     int i;
     for (i = 0; i < HDR_ENUM_END; i++) {
-	free_acl_access(&header[i].access_list);
+	free_acl_access(parserName, &header[i].access_list);
     }
 }
 
 static void
-dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
-    header[])
+dump_http_header_replace(StoreEntry * entry, const char *name, void const * const data)
 {
+    header_mangler *header=(header_mangler *)data;
     int i;
     for (i = 0; i < HDR_ENUM_END; i++) {
 	if (NULL == header[i].replacement)
@@ -843,8 +907,9 @@
 }
 
 static void
-parse_http_header_replace(header_mangler header[])
+parse_http_header_replace(parserNameNode *parserName, void * data)
 {
+    header_mangler *header=data;
     int id, i;
     char *t = NULL;
     if ((t = strtok(NULL, w_space)) == NULL) {
@@ -880,8 +945,9 @@
 }
 
 static void
-free_http_header_replace(header_mangler header[])
+free_http_header_replace(parserNameNode *parserName, void * data)
 {
+    header_mangler *header=data;
     int i;
     for (i = 0; i < HDR_ENUM_END; i++) {
 	if (header[i].replacement != NULL)
@@ -900,8 +966,9 @@
 }
 
 static void
-dump_cachedir(StoreEntry * entry, const char *name, cacheSwap swap)
+dump_cachedir(StoreEntry * entry, const char *name, void const * const data)
 {
+    cacheSwap swap=*(cacheSwap *)data;
     SwapDir *s;
     int i;
     for (i = 0; i < swap.n_configured; i++) {
@@ -926,68 +993,66 @@
     return s == NULL;
 }
 
+/*
+ * TODO: this is a bit clunky...
+ *
+ */
+
 static void
-allocate_new_authScheme(authConfig * cfg)
+allocate_new_authScheme(authSchemes * cfg)
 {
     if (cfg->schemes == NULL) {
-	cfg->n_allocated = 4;
-	cfg->schemes = xcalloc(cfg->n_allocated, sizeof(authScheme));
+        cfg->n_allocated = 4;
+        cfg->schemes = xcalloc(cfg->n_allocated, sizeof(authScheme));
     }
     if (cfg->n_allocated == cfg->n_configured) {
-	authScheme *tmp;
-	cfg->n_allocated <<= 1;
-	tmp = xcalloc(cfg->n_allocated, sizeof(authScheme));
-	xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme));
-	xfree(cfg->schemes);
-	cfg->schemes = tmp;
+        authScheme *tmp;
+        cfg->n_allocated <<= 1;
+        tmp = xcalloc(cfg->n_allocated, sizeof(authScheme));
+        xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme));
+        xfree(cfg->schemes);
+        cfg->schemes = tmp;
     }
 }
 
 static void
-parse_authparam(authConfig * config)
+parse_authscheme(parserNameNode *parserName, void * data)
 {
+    authSchemes * config=(authSchemes *) data;
     char *type_str;
-    char *param_str;
     authScheme *scheme = NULL;
     int type, i;
 
     if ((type_str = strtok(NULL, w_space)) == NULL)
-	self_destruct();
-
-    if ((param_str = strtok(NULL, w_space)) == NULL)
-	self_destruct();
+        self_destruct();
 
     if ((type = authenticateAuthSchemeId(type_str)) == -1) {
-	debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
-	return;
+        debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
+        return;
     }
     for (i = 0; i < config->n_configured; i++) {
-	if (config->schemes[i].Id == type) {
-	    scheme = config->schemes + i;
-	}
+        if (config->schemes[i].Id == type) {
+            scheme = config->schemes + i;
+        }
     }
 
     if (scheme == NULL) {
-	allocate_new_authScheme(config);
-	scheme = config->schemes + config->n_configured;
-	config->n_configured++;
-	scheme->Id = type;
-	scheme->typestr = authscheme_list[type].typestr;
+        allocate_new_authScheme(config);
+        scheme = config->schemes + config->n_configured;
+        config->n_configured++;
+        scheme->Id = type;
+        scheme->typestr = authscheme_list[type].typestr;
     }
-    authscheme_list[type].parse(scheme, config->n_configured, param_str);
 }
 
 static void
-free_authparam(authConfig * cfg)
+free_authscheme(parserNameNode *parserName, void * data)
 {
-    authScheme *scheme;
+    authSchemes * cfg=(authSchemes *) data;
+    authScheme *scheme = NULL;
     int i;
-    /* DON'T FREE THESE FOR RECONFIGURE */
-    if (reconfiguring)
-	return;
     for (i = 0; i < cfg->n_configured; i++) {
-	scheme = cfg->schemes + i;
-	authscheme_list[scheme->Id].freeconfig(scheme);
+        scheme = cfg->schemes + i;
     }
     safe_free(cfg->schemes);
     cfg->schemes = NULL;
@@ -996,13 +1061,145 @@
 }
 
 static void
-dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
+dump_authscheme(StoreEntry * entry, const char *name, void const * data)
 {
+    authSchemes * cfg=*(authSchemes **) data;
     authScheme *scheme;
     int i;
-    for (i = 0; i < cfg.n_configured; i++) {
-	scheme = cfg.schemes + i;
-	authscheme_list[scheme->Id].dump(entry, name, scheme);
+    for (i = 0; i < cfg->n_configured; i++) {
+	scheme = cfg->schemes + i;
+	storeAppendPrintf(entry, "%s %s\n", name, scheme->typestr);
+    }
+}
+
+
+
+CBDATA_TYPE(modNode);
+/* Operation of modNode cbdata:
+ * config allocates the record, and free frees it.
+ * any configuration that depends on the record 
+ * locks it and
+ * any matching free configuration 
+ * unlocks it
+ */
+
+const char *
+mod_type_str(const mod_t type)
+{
+    switch (type) {
+    case MOD_INTERNAL:
+	return "internal";
+	break;
+    case MOD_EXTERNAL:
+	return "external";
+	break;
+    default:
+	return "unknown";
+	break;
+    }
+}
+
+
+/* TODO: write a cbdataFree handler for modNode's. */
+static void
+parse_mod_install(parserNameNode *parserName, void *data)
+{
+    modConfig * cfg = data;
+    char *type_str = NULL, *name_str = NULL;
+    mod_t type = MOD_NONE;
+    modNode *node = NULL;
+    dlink_node *linknode;
+
+    int rv;
+
+    linknode = cfg->modules.head;
+    if (!linknode)
+	/* first run */
+	CBDATA_INIT_TYPE(modNode);
+
+    if ((type_str = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+
+    if ((name_str = strtok(NULL, w_space)) == NULL)
+	self_destruct();
+
+    /* find the module if it's currently configured */
+    while (linknode && strcasecmp((*(modNode *) (linknode->data)).namestr, name_str)) {
+	linknode = linknode->next;
+    }
+
+    if (linknode == NULL) {
+	/* ignore the type if it is already configured. */
+	if (strcasecmp(type_str, "internal") == 0) {
+	    /* internal module */
+	    type = MOD_INTERNAL;
+	} else if (strcasecmp(type_str, "external") == 0) {
+	    /* external module */
+	    debug(3, 0) ("external modules not supported yet\n");
+	}
+	if (type == MOD_NONE)
+	    self_destruct();
+
+	node = cbdataAlloc(modNode);
+	assert(node);
+	node->type = type;
+	node->namestr = xstrdup(name_str);
+	if (type == MOD_INTERNAL)
+	    rv = mod_internal_install(node->namestr, node);
+#if 0
+	else if (type == MOD_EXTERNAL)
+	    rv = mod_external_install(node->namestr, node);
+#endif
+	else
+	    rv = 0;
+	if (rv)
+	    dlinkAddTail(node, &node->node, &cfg->modules);
+	else {
+	    safe_free(node->namestr);
+	    cbdataFree(node);
+	    node=NULL;
+	}
+    } else {
+	node = linknode->data;
+    }
+
+    if (node)
+	cbdataLock(parserName);
+    /* call the modules configuration routine, if any */
+
+}
+
+static void
+free_mod_install(parserNameNode *parserName, void *data)
+{
+    modConfig * cfg=data;
+    dlink_node *node, *tmpnode;
+    modNode *module;
+    node = cfg->modules.head;
+    while (node) {
+	tmpnode = node;
+	module = node->data;
+	node = node->next;
+	if (module->uninstall(module->namestr)) {
+	    dlinkDelete(tmpnode, &cfg->modules);
+	    safe_free(module->namestr);
+	    cbdataFree(module);
+	    cbdataUnlock(parserName);
+	}
+    }
+}
+
+static void
+dump_mod_install(StoreEntry * entry, const char *name, void const *data)
+{
+    modConfig const * cfg=data;
+    dlink_node *node;
+    modNode *module;
+    node = cfg->modules.head;
+    while (node) {
+	module = node->data;
+	storeAppendPrintf(entry, "mod_install %s %s\n",mod_type_str(module->type),module->namestr);
+	node = node->next;
     }
 }
 
@@ -1027,6 +1224,10 @@
 find_fstype(char *type)
 {
     int i;
+    if (!storefs_list) {
+	debug(3,0)("No fs module installed\n");
+	return (-1);
+    }
     for (i = 0; storefs_list[i].typestr != NULL; i++) {
 	if (strcasecmp(type, storefs_list[i].typestr) == 0) {
 	    return i;
@@ -1035,9 +1236,11 @@
     return (-1);
 }
 
+
 static void
-parse_cachedir(cacheSwap * swap)
+parse_cachedir(parserNameNode *parserName, void * data)
 {
+    cacheSwap * swap=data;
     char *type_str;
     char *path_str;
     SwapDir *sd;
@@ -1100,6 +1303,8 @@
     swap->n_configured++;
     /* Update the max object size */
     update_maxobjsize();
+    /* lock the Name so it doesn't get freed out from under us */
+    cbdataLock(parserName);
 }
 
 static void
@@ -1194,17 +1399,23 @@
 }
 
 static void
-free_cachedir(cacheSwap * swap)
+free_cachedir(parserNameNode *parserName, void * data)
 {
+    cacheSwap * swap=data;
     SwapDir *s;
     int i;
     /* DON'T FREE THESE FOR RECONFIGURE */
+    /* TODO: implement runtime cache_dir removal.
+     * in progress items should have the cachedir cbdata locked via some reference chain
+     * so the actual free will only occur when the last reference disappears 
+     */
     if (reconfiguring)
 	return;
     for (i = 0; i < swap->n_configured; i++) {
 	s = swap->swapDirs + i;
 	s->freefs(s);
 	xfree(s->path);
+	cbdataUnlock(parserName);
     }
     safe_free(swap->swapDirs);
     swap->swapDirs = NULL;
@@ -1232,8 +1443,9 @@
 }
 
 static void
-dump_peer(StoreEntry * entry, const char *name, peer * p)
+dump_peer(StoreEntry * entry, const char *name, void const * const data)
 {
+    peer * p=*(peer **)data;
     domain_ping *d;
     domain_type *t;
     LOCAL_ARRAY(char, xname, 128);
@@ -1266,8 +1478,9 @@
 }
 
 static void
-parse_peer(peer ** head)
+parse_peer(parserNameNode *parserName, void * data)
 {
+    peer ** head=(peer **)data;
     char *token = NULL;
     peer *p;
     int i;
@@ -1371,11 +1584,13 @@
     *head = p;
     Config.npeers++;
     peerClearRR(p);
+    cbdataLock(parserName);
 }
 
 static void
-free_peer(peer ** P)
+free_peer(parserNameNode *parserName, void * data)
 {
+    peer ** P=(peer **)data;
     peer *p;
     while ((p = *P) != NULL) {
 	*P = p->next;
@@ -1385,13 +1600,15 @@
 	p->digest = NULL;
 #endif
 	cbdataFree(p);
+	cbdataUnlock(parserName);
     }
     Config.npeers = 0;
 }
 
 static void
-dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
+dump_cachemgrpasswd(StoreEntry * entry, const char *name, void const * const data)
 {
+    cachemgr_passwd * list=*(cachemgr_passwd **)data;
     wordlist *w;
     while (list != NULL) {
 	if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
@@ -1407,14 +1624,15 @@
 }
 
 static void
-parse_cachemgrpasswd(cachemgr_passwd ** head)
+parse_cachemgrpasswd(parserNameNode *parserName, void * data)
 {
+    cachemgr_passwd ** head=(cachemgr_passwd **)data;
     char *passwd = NULL;
     wordlist *actions = NULL;
     cachemgr_passwd *p;
     cachemgr_passwd **P;
-    parse_string(&passwd);
-    parse_wordlist(&actions);
+    parse_string(parserName, &passwd);
+    parse_wordlist(parserName, &actions);
     p = xcalloc(1, sizeof(cachemgr_passwd));
     p->passwd = passwd;
     p->actions = actions;
@@ -1423,8 +1641,9 @@
 }
 
 static void
-free_cachemgrpasswd(cachemgr_passwd ** head)
+free_cachemgrpasswd(parserNameNode *parserName, void * data)
 {
+    cachemgr_passwd ** head=(cachemgr_passwd **)data;
     cachemgr_passwd *p;
     while ((p = *head) != NULL) {
 	*head = p->next;
@@ -1435,46 +1654,7 @@
 }
 
 static void
-dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
-{
-    acl_name_list *a;
-    while (var != NULL) {
-	storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
-	for (a = var->acl_list; a != NULL; a = a->next)
-	    storeAppendPrintf(entry, " %s", a->name);
-	storeAppendPrintf(entry, "\n");
-	var = var->next;
-    }
-}
-
-static void
-parse_denyinfo(acl_deny_info_list ** var)
-{
-    aclParseDenyInfoLine(var);
-}
-
-void
-free_denyinfo(acl_deny_info_list ** list)
-{
-    acl_deny_info_list *a = NULL;
-    acl_deny_info_list *a_next = NULL;
-    acl_name_list *l = NULL;
-    acl_name_list *l_next = NULL;
-    for (a = *list; a; a = a_next) {
-	for (l = a->acl_list; l; l = l_next) {
-	    l_next = l->next;
-	    memFree(l, MEM_ACL_NAME_LIST);
-	    l = NULL;
-	}
-	a_next = a->next;
-	memFree(a, MEM_ACL_DENY_INFO_LIST);
-	a = NULL;
-    }
-    *list = NULL;
-}
-
-static void
-parse_peer_access(void)
+parse_peer_access(parserNameNode *parserName, void * data)
 {
     char *host = NULL;
     peer *p;
@@ -1485,11 +1665,23 @@
 	    cfg_filename, config_lineno, host);
 	return;
     }
-    aclParseAccessLine(&p->access);
+    parse_acl_access(parserName, &p->access);
+}
+
+static void
+free_peer_access(parserNameNode *parserName, void * data)
+{
+    /* nop as it's currently freed with the peer */
 }
 
 static void
-parse_hostdomain(void)
+dump_peer_access(StoreEntry * entry, const char *name, void const * const data)
+{
+    /* nop as it's currently dumped with the peer settings */
+}
+
+static void
+parse_hostdomain(parserNameNode *parserName, void * data)
 {
     char *host = NULL;
     char *domain = NULL;
@@ -1517,7 +1709,19 @@
 }
 
 static void
-parse_hostdomaintype(void)
+free_hostdomain(parserNameNode *parserName, void * data)
+{
+    /* nop as it's currently freed with the peer */
+}
+
+static void
+dump_hostdomain(StoreEntry * entry, const char *name, void const * const data)
+{
+    /* nop as it's currently dumped with the peer settings */
+}
+
+static void
+parse_hostdomaintype(parserNameNode *parserName, void * data)
 {
     char *host = NULL;
     char *type = NULL;
@@ -1543,10 +1747,23 @@
     }
 }
 
+static void
+free_hostdomaintype(parserNameNode *parserName, void * data)
+{
+    /* nop as it's currently freed with the peer */
+}
+
+static void
+dump_hostdomaintype(StoreEntry * entry, const char *name, void const * const data)
+{
+    /* nop as it's currently dumped with the peer settings */
+}
+
 #if UNUSED_CODE
 static void
-dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
+dump_ushortlist(StoreEntry * entry, const char *name, void const * const data)
 {
+    ushortlist * u=*(ushortlist **)data;
     while (u) {
 	storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
 	u = u->next;
@@ -1590,34 +1807,39 @@
 #endif
 
 static void
-dump_int(StoreEntry * entry, const char *name, int var)
+dump_int(StoreEntry * entry, const char *name, void const * const data)
 {
+    int var=*(int *)data;
     storeAppendPrintf(entry, "%s %d\n", name, var);
 }
 
 void
-parse_int(int *var)
+parse_int(parserNameNode *parserName, void * data)
 {
+    int *var=data;
     int i;
     i = GetInteger();
     *var = i;
 }
 
 static void
-free_int(int *var)
+free_int(parserNameNode *parserName, void * data)
 {
+    int *var=data;
     *var = 0;
 }
 
 static void
-dump_onoff(StoreEntry * entry, const char *name, int var)
+dump_onoff(StoreEntry * entry, const char *name, void const * const data)
 {
+    int var=*(int *)data;
     storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
 }
 
 static void
-parse_onoff(int *var)
+parse_onoff(parserNameNode *parserName, void * data)
 {
+    int *var=data;
     char *token = strtok(NULL, w_space);
 
     if (token == NULL)
@@ -1633,8 +1855,9 @@
 #define free_eol free_string
 
 static void
-dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
+dump_refreshpattern(StoreEntry * entry, const char *name, void const * const data)
 {
+    refresh_t * head=*(refresh_t **)data;
     while (head != NULL) {
 	storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
 	    name,
@@ -1659,8 +1882,9 @@
 }
 
 static void
-parse_refreshpattern(refresh_t ** head)
+parse_refreshpattern(parserNameNode *parserName, void * data)
 {
+    refresh_t ** head=(refresh_t **)data;
     char *token;
     char *pattern;
     time_t min = 0;
@@ -1758,8 +1982,9 @@
 }
 
 static void
-free_refreshpattern(refresh_t ** head)
+free_refreshpattern(parserNameNode *parserName, void * data)
 {
+    refresh_t ** head=(refresh_t **)data;
     refresh_t *t;
     while ((t = *head) != NULL) {
 	*head = t->next;
@@ -1770,15 +1995,17 @@
 }
 
 static void
-dump_string(StoreEntry * entry, const char *name, char *var)
+dump_string(StoreEntry * entry, const char *name, void const * const data)
 {
+    char *var=*(char **)data;
     if (var != NULL)
 	storeAppendPrintf(entry, "%s %s\n", name, var);
 }
 
 static void
-parse_string(char **var)
+parse_string(parserNameNode *parserName, void * data)
 {
+    char **var=(char **)data;
     char *token = strtok(NULL, w_space);
     safe_free(*var);
     if (token == NULL)
@@ -1787,14 +2014,16 @@
 }
 
 static void
-free_string(char **var)
+free_string(parserNameNode *parserName, void * data)
 {
+    char **var=(char **) data;
     safe_free(*var);
 }
 
 void
-parse_eol(char *volatile *var)
+parse_eol(parserNameNode *parserName, void * data)
 {
+    char *volatile *var=(char *volatile*)data;
     unsigned char *token = strtok(NULL, null_string);
     safe_free(*var);
     if (token == NULL)
@@ -1807,64 +2036,74 @@
 }
 
 static void
-dump_time_t(StoreEntry * entry, const char *name, time_t var)
+dump_time_t(StoreEntry * entry, const char *name, void const * const data)
 {
+    time_t var=*(time_t *)data;
     storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
 }
 
 void
-parse_time_t(time_t * var)
+parse_time_t(parserNameNode *parserName, void * data)
 {
+    time_t * var=data;
     parseTimeLine(var, T_SECOND_STR);
 }
 
 static void
-free_time_t(time_t * var)
+free_time_t(parserNameNode *parserName, void * data)
 {
+    time_t * var=data;
     *var = 0;
 }
 
 static void
-dump_size_t(StoreEntry * entry, const char *name, size_t var)
+dump_size_t(StoreEntry * entry, const char *name, void const * const data)
 {
+    size_t var=*(size_t *)data;
     storeAppendPrintf(entry, "%s %d\n", name, (int) var);
 }
 
 static void
-dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
+dump_b_size_t(StoreEntry * entry, const char *name, void const * const data)
 {
+    size_t var=*(size_t *)data;
     storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
 }
 
 static void
-dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
+dump_kb_size_t(StoreEntry * entry, const char *name, void const * const data)
 {
+    size_t var=*(size_t *)data;
     storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
 }
 
 static void
-parse_size_t(size_t * var)
+parse_size_t(parserNameNode *parserName, void * data)
 {
+    size_t * var=data;
     int i;
     i = GetInteger();
     *var = (size_t) i;
 }
 
 static void
-parse_b_size_t(size_t * var)
+parse_b_size_t(parserNameNode *parserName, void * data)
 {
+    size_t * var=data;
     parseBytesLine(var, B_BYTES_STR);
 }
 
 static void
-parse_kb_size_t(size_t * var)
+parse_kb_size_t(parserNameNode *parserName, void * data)
 {
+    size_t * var=data;
     parseBytesLine(var, B_KBYTES_STR);
 }
 
 static void
-free_size_t(size_t * var)
+free_size_t(parserNameNode *parserName, void * data)
 {
+    size_t * var=data;
     *var = 0;
 }
 
@@ -1874,20 +2113,23 @@
 #define free_gb_size_t free_size_t
 
 static void
-dump_ushort(StoreEntry * entry, const char *name, u_short var)
+dump_ushort(StoreEntry * entry, const char *name, void const * const data)
 {
+    u_short var=*(u_short *)data;
     storeAppendPrintf(entry, "%s %d\n", name, var);
 }
 
 static void
-free_ushort(u_short * u)
+free_ushort(parserNameNode *parserName, void * data)
 {
+    u_short * u=data;
     *u = 0;
 }
 
 static void
-parse_ushort(u_short * var)
+parse_ushort(parserNameNode *parserName, void * data)
 {
+    u_short * var=data;
     int i;
 
     i = GetInteger();
@@ -1896,9 +2138,10 @@
     *var = (u_short) i;
 }
 
-static void
-dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
+void
+dump_wordlist(StoreEntry * entry, const char *name, void const * const data)
 {
+    wordlist * list=*(wordlist **)data;
     while (list != NULL) {
 	storeAppendPrintf(entry, "%s %s\n", name, list->key);
 	list = list->next;
@@ -1906,32 +2149,41 @@
 }
 
 void
-parse_wordlist(wordlist ** list)
+parse_wordlist(parserNameNode *parserName, void * data)
 {
+    wordlist ** list=data;
     char *token;
     while ((token = strtok(NULL, w_space)))
 	wordlistAdd(list, token);
 }
 
+void
+parse_wordlistFromFile(parserNameNode *parserName, void * data)
+{
+    wordlist ** list=data;
+    char *token;
+    while ((token = strtokFile()))
+        wordlistAdd(list, token);
+}
+
 static int
 check_null_wordlist(wordlist * w)
 {
     return w == NULL;
 }
 
-static int
-check_null_acl_access(acl_access * a)
+void
+free_wordlist(parserNameNode *parserName, void * data)
 {
-    return a == NULL;
+    wordlistDestroy(data);
 }
 
-#define free_wordlist wordlistDestroy
-
 #define free_uri_whitespace free_int
 
 static void
-parse_uri_whitespace(int *var)
+parse_uri_whitespace(parserNameNode *parserName, void * data)
 {
+    int *var=data;
     char *token = strtok(NULL, w_space);
     if (token == NULL)
 	self_destruct();
@@ -1951,8 +2203,9 @@
 
 
 static void
-dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
+dump_uri_whitespace(StoreEntry * entry, const char *name, void const * const data)
 {
+    int var=*(int *)data;
     char *s;
     if (var == URI_WHITESPACE_ALLOW)
 	s = "allow";
@@ -1967,30 +2220,41 @@
     storeAppendPrintf(entry, "%s %s\n", name, s);
 }
 
+/* TODO: allow named removal policies. Then the cachedir takes the first 
+ * removal policy, or a named override. 
+ * Reason for this: removal policies have to copy their settings when being 
+ * assigned to cache_dir's at the moment. Is this good ?
+ * Result of this change: removal policies cblock their settings, and
+ * when freed only release if no cache dir is using them
+ */
+
 static void
-free_removalpolicy(RemovalPolicySettings ** settings)
+free_removalpolicy(parserNameNode *parserName, void * data)
 {
+    RemovalPolicySettings ** settings=(RemovalPolicySettings **)data;
     if (!*settings)
 	return;
-    free_string(&(*settings)->type);
-    free_wordlist(&(*settings)->args);
+    free_string(parserName, &(*settings)->type);
+    free_wordlist(parserName, &(*settings)->args);
     xfree(*settings);
     *settings = NULL;
 }
 
 static void
-parse_removalpolicy(RemovalPolicySettings ** settings)
+parse_removalpolicy(parserNameNode *parserName, void * data)
 {
+    RemovalPolicySettings ** settings=(RemovalPolicySettings **)data;
     if (*settings)
-	free_removalpolicy(settings);
+	free_removalpolicy(parserName, settings);
     *settings = xcalloc(1, sizeof(**settings));
-    parse_string(&(*settings)->type);
-    parse_wordlist(&(*settings)->args);
+    parse_string(parserName, &(*settings)->type);
+    parse_wordlist(parserName, &(*settings)->args);
 }
 
 static void
-dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
+dump_removalpolicy(StoreEntry * entry, const char *name, void const * const data)
 {
+    RemovalPolicySettings * settings=*(RemovalPolicySettings * *)data;
     wordlist *args;
     storeAppendPrintf(entry, "%s %s", name, settings->type);
     args = settings->args;
@@ -2002,6 +2266,130 @@
 }
 
 
+CBDATA_TYPE(includefile_t);
+
+static void
+parse_include(parserNameNode *parserName, void * data)
+{
+    includefile_t **includefile=(includefile_t **)data;
+    includefile_t *link,*tmp_link;
+    char *tempstr=NULL;
+    if (! *includefile) 
+	CBDATA_INIT_TYPE(includefile_t);
+
+    parse_eol(parserName, &tempstr);
+
+    link=*includefile;
+    while (link && link->next)
+	link=link->next;
+ 
+    tmp_link=cbdataAlloc(includefile_t);
+    tmp_link->next=NULL;
+    tmp_link->filename=tempstr;
+
+    if (link) 
+	link->next=tmp_link;
+    else
+        *includefile=tmp_link;
+
+    parseConfigFile(tmp_link->filename);
+}
+
+static void
+free_include(parserNameNode *parserName, void * data)
+{
+    /* we don't need to process the file data, just free the linked list */
+    includefile_t **includefile=(includefile_t **)data;
+    includefile_t *link;
+    while (*includefile) {
+	free_eol(parserName, &(*includefile)->filename);
+	link=(*includefile)->next;
+	cbdataFree(*includefile);
+	*includefile=link;
+    }
+}
+
+static void
+dump_include(StoreEntry * entry, const char *name, void const * const data)
+{
+    includefile_t *link=*(includefile_t **)data;
+    while (link) {
+	storeAppendPrintf(entry,"%s %s\n",name,link->filename);
+	link=link->next;
+    }
+}
+
+/* Insert any new 'core' types here for registration */
+static void
+parserRegisterAllTypes(void)
+{
+    parserRegisterCFTypes();
+    parserRegisterType("instance_node", parse_instance_node, free_instance_node, dump_instance_node);
+
+//    parserRegisterType("acl",aclParseAclLine,free_acl,dump_acl);
+}
+
+
+//parserRegisterType("acl",parse_acl,free_acl,dump_acl);
+
+
+void *parserRegisterInstanceName(const char *, parserTypeNode *, PARSER_DEFAULT_NONE *, PARSER_POST_PARSE *);
+
+#if 0
+static void * aclinstances = NULL;
+
+#define default_if_none_acl NULL
+#define name_document_acl NULL
+#endif
+
+PARSER_DEFAULT_NONE default_if_no_instances;
+
+/* Insert any new 'core' names here for registration */
+static void
+parserRegisterAllNames(void)
+{
+    
+    parserRegisterCFNames();
+
+    /* ACL.C routines: should be in acl.c */
+
+    aclParserRegister();
+
+//    parserRegisterName("acl",parserTypeByName("instance_node"),&Config.aclList2,default_if_none_acl,name_document_acl, NULL);
+
+#if 0
+    if (aclinstances)
+	debug(3,0)("bwahhahhahaha\n\n");
+    aclinstances = parserRegisterInstanceName("acl", parserTypeByName("acl"), name_document_acl, NULL);
+
+    parserRegisterName(NULL, "acl", parserTypeByName("instance_node"), aclinstances, default_if_none_acl, name_document_acl, NULL);
+
+#endif
+
+/* instance called acl 
+ to parse use type foo */
+
+
+
+/*
+instance type called acl.
+
+registerinstancetype acl
+
+list referred to as acl
+acl has location foo.
+
+
+list has a new entry of type instance at location instance-location.
+in foo, add to the type list,
+instance, location.
+
+list has a new entry of type acl at location acl-location
+in foo add to the type list
+acl, location
+*/
+}
+
 #include "cf_parser.c"
 
 peer_t
@@ -2022,8 +2410,9 @@
 }
 
 static void
-parse_sockaddr_in_list(sockaddr_in_list ** head)
+parse_sockaddr_in_list(parserNameNode *parserName, void * data)
 {
+    sockaddr_in_list ** head =(sockaddr_in_list **)data;
     char *token;
     char *t;
     char *host;
@@ -2062,8 +2451,9 @@
 }
 
 static void
-dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
+dump_sockaddr_in_list(StoreEntry * e, const char *n, void const * const data)
 {
+    sockaddr_in_list * s=*(sockaddr_in_list **)data;
     while (s) {
 	storeAppendPrintf(e, "%s %s:%d\n",
 	    n,
@@ -2074,8 +2464,9 @@
 }
 
 static void
-free_sockaddr_in_list(sockaddr_in_list ** head)
+free_sockaddr_in_list(parserNameNode *parserName, void * data)
 {
+    sockaddr_in_list ** head=(sockaddr_in_list **)data;
     sockaddr_in_list *s;
     while ((s = *head) != NULL) {
 	*head = s->next;
@@ -2089,6 +2480,147 @@
     return NULL == s;
 }
 
+
+parserNameNode *parserNameByNodeName(dlink_list *, const char *);
+
+CBDATA_TYPE(instance_name);
+CBDATA_TYPE(instance_node);
+
+/* this code is broken. The fault is that not all instances will start at root.
+ * the solution is to store the instance list as the config data for the parent nore 
+ * of the instance
+ */
+static dlink_list instance_names = {NULL,NULL};
+
+void 
+default_if_no_instances(void *data)
+{
+    instance_name *Name=data;
+    if (Name->instances.head==NULL)
+	if (Name->default_none)
+	    Name->default_none(NULL);
+}
+
+/* the free function only occurs when the mempoolfree is about to occur.
+ * for persistent types, the config function locks the Name node
+ */
+static void
+parserInstanceNameFree(void *data)
+{
+    instance_name *Name=data;
+    dlinkDelete(&Name->node,&instance_names);
+    debug(3,0)("parserNameFree freed name %s\n",Name->namestr);
+    safe_free(Name->namestr);
+    cbdataUnlock(Name->type);
+}
+
+
+/* FIXME: this may need a parent option */
+instance_name *
+parserInstanceNameByName(const char *name)
+{
+    dlink_node *node;
+    node=instance_names.head;
+    while (node && strcmp(((instance_name *)node->data)->namestr,name)) {
+        node=node->next;
+	
+    }
+    if (node)
+        return (instance_name *)node->data;
+    else
+        return NULL;
+}
+
+void * parserRegisterInstanceName(const char *namestr, parserTypeNode *parserType, PARSER_DEFAULT_NONE *default_none, PARSER_POST_PARSE *post_parse_func)
+{
+    instance_name *Name;
+    if ((Name=parserInstanceNameByName(namestr))==NULL) {
+    /* register the type */
+    debug(3,3)("parserRegisterInstanceName new name '%s'\n",Name);
+    if (instance_names.head==NULL)
+        CBDATA_INIT_TYPE_FREECB(instance_name,parserInstanceNameFree);
+    Name=cbdataAlloc(instance_name);
+    Name->namestr=xstrdup(namestr);
+    Name->type=parserType;
+    cbdataLock(parserType);
+    Name->default_none=default_none;
+    Name->post_parse_func=post_parse_func;
+    dlinkAddTail(Name,&Name->node,&instance_names);
+    return Name;
+} else {
+    debug(3,0)("parserRegisterInstanceName already registered name '%s'\n",Name);
+    return NULL;
+    /* TODO: fatal this */
+    }
+}
+
+static void
+InstanceNodeFree(void *data)
+{
+    instance_node *instance=data;
+    dlinkDelete(&instance->node, (instance->head));
+    debug(3,0)("parserNameFree freed name %s\n",instance->parserName->namestr);
+    cbdataUnlock(instance->name);
+}
+
+instance_node *
+InstanceByNameStr(instance_name *Name, const char *namestr)
+{
+    dlink_node *node;
+    node=Name->instances.head;
+    while (node && strcmp(((instance_node *)node->data)->namestr,namestr)) {
+	node=node->next;
+    }
+    if (node)
+	return (instance_node *)node->data;
+    else
+	return NULL;
+}
+
+/* Called when an unrecognised child of an "instance" type is seen */
+static void
+parse_instance_node(parserNameNode *parserName, void * data)
+{
+    char *token = NULL;
+    instance_name *Name=data;
+    instance_node *instance=NULL;
+    if ((token = strtok(NULL, w_space)) == NULL) {
+	debug(3, 0) (" %s line %d: %s\n",
+	    cfg_filename, config_lineno, config_input_line);
+	debug(3, 0) ("parse_instance_node: missing instance name.\n");
+	return;
+    }
+ 
+    if ((instance=InstanceByNameStr(Name,token))==NULL) {
+	/* register me */
+        if (Name->instances.head==NULL)
+	    CBDATA_INIT_TYPE_FREECB(instance_node,InstanceNodeFree);
+	instance=cbdataAlloc(instance_node);
+    
+	debug(3,0)("parsing new instance name %s\n",token);
+
+	instance->namestr=xstrdup(token);
+	instance->head=&Name->instances;
+	instance->data=NULL;
+	parserRegisterName(parserName, instance->namestr, Name->type, &instance->data, NULL, NULL, NULL);
+	instance->parserName=parserNameByNodeName(&parserName->children, instance->namestr);
+	assert(instance->parserName);
+	dlinkAddTail(instance,&instance->node, instance->head);
+    }
+    /* parse that instance */
+    instance->parserName->type->parsefunc(instance->parserName, instance->parserName->location);
+}
+
+static void
+free_instance_node(parserNameNode *parserName, void * data)
+{
+}
+
+static void
+dump_instance_node(StoreEntry * e, const char *n, void const * const data)
+{
+}
+
 #if USE_SSL
 static void
 parse_https_port_list(https_port_list ** head)
@@ -2193,3 +2725,465 @@
     if (stat(path, &sb) < 0)
 	fatalf("%s: %s", path, xstrerror());
 }
+
+/* dynamic parser support routines */
+
+CBDATA_TYPE(parserTypeNode);
+CBDATA_TYPE(parserNameNode);
+
+static void
+parserTypeFree(void *data)
+{
+    parserTypeNode *parserType=data;
+    dlinkDelete(&parserType->node,&parserTypes);
+    debug(3,0)("parserTypeFree freed type %s\n",parserType->typestr);
+}
+
+parserTypeNode *
+parserTypeByName(const char *typestr) 
+{
+    dlink_node *node;
+    node=parserTypes.head;
+    while (node && strcmp(((parserTypeNode *)node->data)->typestr,typestr)) {
+        node=node->next;
+    }
+    if (node)
+	return (parserTypeNode *)node->data;
+    else
+	return NULL;
+}
+
+void
+parserRegisterType(const char *typestr, PARSER_PARSE *parsefunc, PARSER_FREE *freefunc, PARSER_DUMP *dumpfunc)
+{
+    parserTypeNode *parserType;
+    if ((parserType=parserTypeByName(typestr))==NULL) {
+	/* register the type */
+	debug(3,3)("parserRegisterType new type '%s'\n",typestr);
+        if (parserTypes.head==NULL)
+	    CBDATA_INIT_TYPE_FREECB(parserTypeNode,parserTypeFree);
+	parserType=cbdataAlloc(parserTypeNode);
+	parserType->typestr=typestr;
+	parserType->parsefunc=parsefunc;
+	parserType->freefunc=freefunc;
+	parserType->dumpfunc=dumpfunc;
+	parserType->flags.registered=0;
+	dlinkAddTail(parserType,&parserType->node,&parserTypes);
+    } else {
+	/* confirm the pointers are the same */
+	debug(3,3)("parserRegisterType already registered type '%s'\n",typestr);
+	if ((parserType->parsefunc!=parsefunc) ||
+	    (parserType->freefunc!=freefunc) ||
+	    (parserType->dumpfunc!=dumpfunc)) {
+	    debug(3,0)("parserRegisterType already registered type '%s' has different function pointers!\n",typestr);
+	}
+    }
+    if (parserType->flags.registered==0) {
+	cbdataLock(parserType);
+	parserType->flags.registered=1;
+    }
+}
+
+void parserDeregisterType(parserTypeNode *parserType)
+{
+    if (!parserType)
+	return;
+    debug(3,3)("parserDeregisterType '%s'\n",parserType->typestr);
+    cbdataFree(parserType);
+    if (parserType->flags.registered==1) {
+	cbdataUnlock(parserType);
+	parserType->flags.registered=0;
+    }
+}
+
+static void
+parserDeregisterAllTypes(void)
+{
+    dlink_node *node;
+    node=parserTypes.head;
+    while (node) {
+	parserDeregisterType(node->data);
+        node=node->next;
+    }
+}
+
+/* the free function only occurs when the mempoolfree is about to occur.
+ * for persistent types, the config function locks the Name node
+ */
+static void
+parserNameFree(void *data)
+{
+    parserNameNode *parserName=data;
+    dlink_node *node;
+    dlinkDelete(&parserName->node,parserName->head);
+    debug(3,0)("parserNameFree freed name %s\n",parserName->namestr);
+
+    node=parserName->children.head;
+    while (node) {
+	parserDeregisterName(node->data);
+	node=node->next;
+    } 
+
+    cbdataUnlock(parserName->type);
+}
+
+parserNameNode *
+parserNameByNodeName(dlink_list *parent, const char *name)
+{
+    dlink_node *node;
+    node=parent->head;
+    while (node && strcmp(((parserNameNode *)node->data)->namestr,name)) {
+        node=node->next;
+    }
+    if (node)
+        return (parserNameNode *)node->data;
+    else
+        return NULL;
+}
+
+parserNameNode *
+parserNameByName(const char *name)
+{
+    return parserNameByNodeName(&parserNames,name);
+}
+
+/* register a new name for the config file 
+ * a name is the first symbol on a line in the config file.
+ * TODO: check for conflicts with cf.data.pre declared names
+ * TODO: check for conflicts with dynamically registered names.
+ * TODO: have cf_parser.c dynamically register all the config file builtin types,
+ * ignoring errors (because they have been migrated to auto register ).
+ */
+void
+parserRegisterName(parserNameNode *parent, const char *name, parserTypeNode *parserType, void *location, 
+    PARSER_DEFAULT_NONE *default_none, PARSER_NAME_DOCUMENT *documentfunc, PARSER_POST_PARSE *post_parse_func)
+{
+    parserNameNode *parserName;
+
+        
+    if ((parserName=parserNameByNodeName(parent ? &parent->children : &parserNames, name))==NULL) {
+    /* register the type */
+    debug(3,3)("parserRegisterName new name '%s'\n",name);
+    if (parserNames.head==NULL)
+        CBDATA_INIT_TYPE_FREECB(parserNameNode,parserNameFree);
+    parserName=cbdataAlloc(parserNameNode);
+    parserName->namestr=name;
+    parserName->type=parserType;
+    cbdataLock(parserType);
+    parserName->location=location;
+    parserName->default_none=default_none;
+    parserName->documentfunc=documentfunc;
+    parserName->post_parse_func=post_parse_func;
+    parserName->head = parent ? &parent->children : &parserNames;
+    parserName->parent = parent;
+    parserName->children.head=NULL;
+    parserName->children.tail=NULL;
+    dlinkAddTail(parserName,&parserName->node,parserName->head);
+} else {
+    /* confirm the pointers are the same */
+    debug(3,3)("parserRegisterName already registered name '%s'\n",name);
+    if ((parserName->type!=parserType) ||
+        (parserName->location!=location) ||
+	(parserName->default_none!=default_none) ||
+	(parserName->documentfunc!=documentfunc) ||
+	(parserName->post_parse_func!=post_parse_func)) {
+        debug(3,0)("parserRegisterName already registered name '%s' has a different type, location, default_if_none function or document function.\n",name);
+    }
+}
+    if (parserName->flags.registered==0) {
+	cbdataLock(parserName);
+	parserName->flags.registered=1;
+    }
+}
+
+void
+parserDeregisterName(parserNameNode *parserName)
+{
+    if (!parserName)
+	return;
+    debug(3,0)("parserDeregisterName '%s'\n",parserName->namestr);
+    cbdataFree(parserName);
+    if (parserName->flags.registered==1) {
+	cbdataUnlock(parserName);
+	parserName->flags.registered=0;
+    }
+}
+
+/* TODO: we might hit a null pointer here if the node gets unlinked under us */
+static void
+parserDeregisterAllNames(void)
+{
+    dlink_node *node;
+    node=parserNames.head;
+    while (node) {
+        parserDeregisterName(node->data);
+        node=node->next;
+    }
+}
+
+static int
+parserNameDoPostParse(void)
+{
+    dlink_node *node;
+    int rv=0;
+    node=parserNames.head;
+    while (node) {
+	if (((parserNameNode *)node->data)->post_parse_func)
+	    rv+=((parserNameNode *)node->data)->post_parse_func();
+	node=node->next;
+    }
+    return rv;
+}
+
+void
+default_line(const char *s)
+{
+        LOCAL_ARRAY(char, tmp_line, BUFSIZ);
+        memset(tmp_line, '\0', BUFSIZ);
+        xstrncpy(tmp_line, s, BUFSIZ);
+        xstrncpy(config_input_line, s, BUFSIZ);
+        config_lineno++;
+        parse_line(tmp_line);
+}
+
+
+/* this backs strtok up a step after checking the next result. IT ALTERS THE STRING.
+ * (Users should copy out any needed data from the current symbol before calling)
+ */
+static int
+peek_line(char *current_token)
+{
+    char *token;
+    char saved;
+    size_t saved_len;
+    saved=current_token[strlen(current_token)-1];
+    saved_len = strlen(current_token+strlen(current_token)+1);
+    if ((token = strtok(NULL, w_space)) == NULL)
+	/* Fail if no more tokens on this line */
+	return 0;
+    debug(3,8)("next token %s\n",token);
+    /* back up strtok a step. Yummy */
+    if (strlen(token) != saved_len)
+	/* next symbol is not last sympbol */
+	*(token + strlen(token))=' ';
+    current_token[strlen(current_token)-1] = saved;
+    *(token-1) = ' ';
+    strtok(current_token,w_space);
+    return 1;
+}
+
+int
+parse_directive(parserNameNode *parent)
+{
+    char *token="dummy";
+    parserNameNode *parserName, *currentName=parent;
+    if ((token = strtok(NULL, w_space)) == NULL)
+	return 0;       /* fail on directives with no data */
+    while (token) { //peek_line(token)
+	if ((parserName=parserNameByNodeName(parent ? &currentName->children : &parserNames, token))==NULL) {
+	    /* unregistered child, parse as normal. */
+	    /* back up strtok a step. Yummy */
+	    debug(0,0)("parse_directive: no child for %s\n", token);
+	    if (peek_line(token))
+		/* there are more elements to the line */
+		*(token + strlen(token))=' ';
+	    *(token-2) = 'A';
+	    *(token-1) = ' ';
+	    strtok(token-2,w_space);
+	    currentName->type->parsefunc(currentName, currentName->location);
+	    if ((token = strtok(NULL, w_space)) == NULL)
+		return 1; /* finish at end of the line */
+	} else {
+	    debug(0,0)("parse_directive: known child %s\n", token);
+	    /* registered child node */
+	    currentName=parserName;
+	    /* eat the token we just stepped along */
+	    token = strtok(NULL, w_space);
+//	    parserName->type->parsefunc(parserName, parserName->location);
+//	    if ((token = strtok(NULL, w_space)) == NULL)
+//		return 1; /* finish at end of the line */
+	}
+    }
+    /* unreached */
+    return 1;
+}
+
+static int
+parse_line(char *buff)
+{
+    char *token;
+    parserNameNode *parserName;
+    debug(0,10)("parse_line: %s\n", buff);
+    if ((token = strtok(buff, w_space)) == NULL)
+        return 1;       /* ignore empty lines */
+    if ((parserName=parserNameByName(token))==NULL) {
+	/* unregistered name */
+	return 0;
+    } else {
+	/* registered name */
+	if (parserName->children.head)
+	    return parse_directive(parserName);
+	else
+	    parserName->type->parsefunc(parserName, parserName->location);
+	return 1;
+    }
+}
+
+char *
+strtokFile(void)
+{
+    char *t, *fn;
+    LOCAL_ARRAY(char, buf, 256);
+    static int strFromFile = 0;
+    static FILE *strFile;
+
+  strtok_again:
+    if (!strFromFile) {
+        t = (strtok(NULL, w_space));
+        if (t && (*t == '\"' || *t == '\'')) {
+            /* quote found, start reading from file */
+            fn = ++t;
+            while (*t && *t != '\"' && *t != '\'')
+                t++;
+            *t = '\0';
+            if ((strFile = fopen(fn, "r")) == NULL) {
+                debug(28, 0) ("strtokFile: %s not found\n", fn);
+                return (NULL);
+            }
+#if defined(_SQUID_CYGWIN_)
+            setmode(fileno(strFile), O_TEXT);
+#endif
+            strFromFile = 1;
+        } else {
+            return t;
+        }
+    }
+    /* strFromFile */
+    if (fgets(buf, 256, strFile) == NULL) {
+        /* stop reading from file */
+        fclose(strFile);
+        strFromFile = 0;
+        goto strtok_again;
+    } else {
+        t = buf;
+        /* skip leading and trailing white space */
+        t += strspn(buf, w_space);
+        t[strcspn(t, w_space)] = '\0';
+        /* skip comments */
+        if (*t == '#')
+            goto strtok_again;
+        /* skip blank lines */
+        if (!*t)
+            goto strtok_again;
+        return t;
+    }
+}
+
+
+static void
+dump_config(StoreEntry *entry)
+{
+    dlink_node *node;
+    node=parserNames.head;
+    while (node) {
+	((parserNameNode *)node->data)->type->dumpfunc(entry,
+	    ((parserNameNode *)node->data)->namestr,
+	    ((parserNameNode *)node->data)->location);
+	node=node->next;
+    }
+}
+
+static void
+free_all(void)
+{
+    dlink_node *node;
+    node=parserNames.head;
+    while (node) {
+	((parserNameNode *)node->data)->type->freefunc((parserNameNode *)node->data, ((parserNameNode *)node->data)->location);
+	node=node->next;
+    }
+}
+
+static void
+defaults_if_none(void)
+{
+    dlink_node *node;
+    node=parserNames.head;
+    while (node) {
+	if (((parserNameNode *)node->data)->default_none)
+	    ((parserNameNode *)node->data)->default_none(((parserNameNode *)node->data)->location);
+	node=node->next;
+    }
+}
+
+void
+parserAddDocumentOption(const char *option)
+{
+    docoptionNode *node;
+    if (!DoDocumentOptions) {
+	/* first parameter */
+	DoDocumentOptions=xcalloc(1, sizeof(docoptions));
+	assert(DoDocumentOptions);
+	DoDocumentOptions->head=NULL;
+	DoDocumentOptions->flags.internalonly=0;
+	DoDocumentOptions->flags.all=0;
+    }
+    if (strcasecmp(option,"internalonly")==0) {
+	DoDocumentOptions->flags.internalonly=1;
+    } else if (strcasecmp(option,"all")==0) {
+	DoDocumentOptions->flags.all=1;
+    } else {
+	node=xcalloc(1, sizeof(docoptionNode));
+	assert(node);
+	node->next=DoDocumentOptions->head;
+	node->name=xstrdup(option);
+	DoDocumentOptions->head=node;
+    }
+}
+
+int
+parserDoDocument(const char *file_name)
+{
+    int rv;
+    assert(DoDocumentOptions);
+    /* if not internal_only */
+    if (!DoDocumentOptions->flags.internalonly) {
+        rv= parserReconfigure(file_name);
+    } else {
+        free_all();
+        parserDeregisterAllNames();
+        parserDeregisterAllTypes();
+	parserRegisterAllTypes();
+	parserRegisterAllNames();
+	rv = !mod_internal_install("all", NULL);
+	defaults_if_none();
+	/* don't try to apply the config.  configDoConfigure(); */
+    }
+    if (DoDocumentOptions->flags.all) {
+	/* print all names */
+	dlink_node *node;
+	node=parserNames.head;
+	while (node) {
+	    if (((parserNameNode *)node->data)->documentfunc)
+		((parserNameNode *)node->data)->documentfunc();
+	    else
+		printf("directive '%s' has no documented options\n",((parserNameNode *)node->data)->namestr);
+	    node=node->next;
+	}    
+    } else {
+	/* print chosen names */
+	parserNameNode *parserName;
+	docoptionNode *node=DoDocumentOptions->head;
+	while (node) {
+	    if ((parserName = parserNameByName(node->name))) 
+		if (parserName->documentfunc)
+		  parserName->documentfunc();
+		else
+		  printf("directive '%s' has no documented options\n",node->name);
+	    else
+		printf("directive '%s' not found.\n",node->name);
+	    node=node->next;
+	}
+    }
+    return rv;
+}
Index: squid/src/cf.data.pre
diff -u squid/src/cf.data.pre:1.27 squid/src/cf.data.pre:1.21.4.15
--- squid/src/cf.data.pre:1.27	Fri May  4 06:39:12 2001
+++ squid/src/cf.data.pre	Sat May 12 06:06:03 2001
@@ -48,6 +48,65 @@
 
 COMMENT_END
 
+NAME: include
+TYPE: include
+DEFAULT: none
+LOC: Config.files 
+DOC_START
+	Including config files. 
+
+	Squid supports breaking the single large config file into 
+	sub files by the use of the include directive. The include 
+	directives can be placed at any point in the main config file,
+	and in included config files.
+NOCOMMENT_START
+# include /etc/squidacl.conf
+NOCOMMENT_END
+DOC_END
+
+COMMENT_START
+ MODULE OPTIONS
+ -----------------------------------------------------------------------------
+        Squid's module architecture allows dynamic addition and removal
+	of code from the code base. Modules _must_ be registered before they
+	are used or referenced (even from other config lines).
+COMMENT_END
+
+NAME: mod_register
+TYPE: mod_install
+DEFAULT: none
+LOC: Config.modules
+DOC_START
+	usage: mod_register internal|external modulename
+
+	External modules are not implemented yet.
+NOCOMMENT_START
+# Uncomment the following modules to match your compiled internal modules.
+
+# the following line registers all compiled in modules. To turn some off,
+# comment the next line out, and then uncomment the lower lines as appropriate.
+mod_register internal all
+
+# replacement policy modules
+#mod_register internal lru
+#mod_register internal heap
+
+# object store modules
+#mod_register internal ufs
+#mod_register internal aufs
+#mod_register internal diskd
+#mod_register internal null
+#mod_register internal coss
+
+# authentication scheme modules
+#mod_register internal basic
+#mod_register internal ntlm
+#mod_register internal digest
+
+NOCOMMENT_END
+DOC_END
+
+
 COMMENT_START
  NETWORK OPTIONS
  -----------------------------------------------------------------------------
@@ -357,7 +416,7 @@
 NAME: cache_peer_domain cache_host_domain
 TYPE: hostdomain
 DEFAULT: none
-LOC: none
+LOC: Config.peers
 DOC_START
 	Use to limit the domains for which a neighbor cache will be
 	queried.  Usage:
@@ -390,7 +449,7 @@
 NAME: neighbor_type_domain
 TYPE: hostdomaintype
 DEFAULT: none
-LOC: none
+LOC: Config.peers 
 DOC_START
 	usage: neighbor_type_domain parent|sibling domain domain ...
 
@@ -1193,17 +1252,14 @@
 	are sent.
 DOC_END
 
-NAME: auth_param
-TYPE: authparam
-LOC: Config.authConfig
+NAME: authenticate_scheme
+TYPE: authscheme
+LOC: Config.authSchemes
 DEFAULT: none
 DOC_START
-	This is used to pass parameters to the various authentication
-	schemes.
-	format: auth_param scheme parameter [setting]
-	
-	auth_param basic program @DEFAULT_PREFIX@/bin/ncsa_auth @DEFAULT_PREFIX@/etc/passwd	
-	would tell the basic authentication scheme it's program parameter.
+	What order the configured authentication schemes should be 
+        presented to the user agent.
+	format: authenticate_scheme scheme
 
 	The order that authentication prompts are presented to the client_agent
 	is dependant on the order the scheme first appears in config file.
@@ -1213,150 +1269,6 @@
 	have difficulties (don't recognise the schemes offered even if you are using
 	basic) then either put basic first, or disable the other schemes (by commenting
 	out their program entry).
-
-	Once an authentication scheme is fully configured, it can only be shutdown
-	by shutting squid down and restarting. Changes can be made on the fly and
-	activated with a reconfigure. I.E. You can change to a different helper, 
-	but not unconfigure the helper completely.
-
-	=== Parameters for the basic scheme follow. ===
-	
-	"program" cmdline
-	Specify the command for the external authenticator.  Such a
-	program reads a line containing "username password" and replies
-	"OK" or "ERR" in an endless loop.  If you use an authenticator,
-	make sure you have 1 acl of type proxy_auth.  By default, the
-	authenticate_program is not used.
-
-	If you want to use the traditional proxy authentication,
-	jump over to the ../auth_modules/NCSA directory and
-	type:
-		% make
-		% make install
-
-	Then, set this line to something like
-
-	auth_param basic program @DEFAULT_PREFIX@/bin/ncsa_auth @DEFAULT_PREFIX@/etc/passwd
-
-	"children" numberofchildren
-	The number of authenticator processes to spawn (no default). If you
-	start too few Squid will have to wait for them to process a backlog
-	of usercode/password verifications, slowing it down. When password
-	verifications are done via a (slow) network you are likely to need
-	lots of authenticator processes.
-	auth_param basic children 5
-
-	"realm" realmstring
-	Specifies the realm name which is to be reported to the client for
-	the basic proxy authentication scheme (part of the text the user will
-	see when prompted their username and password). Their is no default.
-	auth_param basic realm Squid proxy-caching web server
-
-	"credentialsttl" timetolive
-	Specifies how long squid assumes an externally validated username:password
-	pair is valid for - in other words how often the helper program is called 
-	for that user. Set this low to force revalidation with short lived passwords.
-	Note that setting this high does not impact your susceptability to replay
-	attacks unless you are using a one-time password system (such as SecureID).
-	If you are using such a system, you will be vulnerable to replay attacks
-	unless you also enable the IP ttl is strict option.
-
-	=== Parameters for the digest scheme follow ===
-
-	"program" cmdline
-	Specify the command for the external authenticator.  Such a
-	program reads a line containing "username":"realm" and replies
-	with the appropriate H(A1) value base64 encoded. See rfc 2616 for
-	the definition of H(A1).  If you use an authenticator,
-	make sure you have 1 acl of type proxy_auth.  By default, 
-	authentication is not used.
-
-	If you want to use build a authenticator,
-	jump over to the ../digest_auth_modules directory and choose the 
-	authenticator to use. It it's directory type
-        	% make
-	        % make install
-
-	Then, set this line to something like
-
-	auth_param digest program @DEFAULT_PREFIX@/bin/digest_auth_pw @DEFAULT_PREFIX@/etc/digpass
-
-
-	"children" numberofchildren
-	The number of authenticator processes to spawn (no default). If you
-	start too few Squid will have to wait for them to process a backlog
-	of H(A1) calculations, slowing it down. When the H(A1) calculations
-	are done via a (slow) network you are likely to need lots of 
-	authenticator processes.
-	auth_param digest children 5
-
-	"realm" realmstring
-	Specifies the realm name which is to be reported to the client for
-	the digest proxy authentication scheme (part of the text the user will
-	see when prompted their username and password). There is no default.
-	auth_param digest realm Squid proxy-caching web server
-
-	"nonce_garbage_interval" timeinterval
-	Specifies the interval that nonces that have been issued to client_agent's
-	are checked for validity.
-
-	"nonce_max_duration" timeinterval
-	Specifies the maximum length of time a given nonce will be valid for. 
-
-	"nonce_max_count" number
-	Specifies the maximum number of times a given nonce can be used.
-
-	=== NTLM scheme options follow ===
-
-	"program" cmdline
-	Specify the command for the external ntlm authenticator.  Such a
-	program reads a line containing the uuencoded NEGOTIATE and replies
-	with the ntlm CHALLENGE, then waits for the response and answers with
-	"OK" or "ERR" in an endless loop.  If you use an ntlm authenticator,
-	make sure you have 1 acl of type proxy_auth.  By default, the
-	ntlm authenticator_program is not used.
-
-	auth_param ntlm program @DEFAULT_PREFIX@/bin/ntlm_auth
-
-	"children" numberofchildren
-	The number of authenticator processes to spawn (no default). If you
-	start too few Squid will have to wait for them to process a backlog
-	of credential verifications, slowing it down. When crendential
-	verifications are done via a (slow) network you are likely to need
-	lots of authenticator processes.
-	auth_param ntlm children 5
-
-	"max_challenge_reuses" number
-	The maximum number of times a challenge given by a ntlm authentication
-	helper can be reused. Increasing this number increases your exposure 
-	to replay attacks on your network. 0 means use the challenge only once. 
-	(disable challenge caching)
-	See max_ntlm_challenge_lifetime for more information.
-	auth_param ntlm max_challenge_reuses 0
-
-	"max_challenge_lifetime" timespan
-	The maximum time period that a ntlm challenge is reused over.
-	The actual period will be the minimum of this time AND the number of 
-	reused challenges.
-	auth_param ntlm max_challenge_lifetime 2 minutes
-
-NOCOMMENT_START
-#Recommended minimum configuration:
-#auth_param digest program <uncomment and complete this line>
-#auth_param digest children 5
-#auth_param digest realm Squid proxy-caching web server
-#auth_param digest nonce_garbage_interval 5 minutes
-#auth_param digest nonce_max_duration 30 minutes
-#auth_param digest nonce_max_count 50
-#auth_param ntlm program <uncomment and complete this line to activate>
-#auth_param ntlm children 5
-#auth_param ntlm max_challenge_reuses 0
-#auth_param ntlm max_challenge_lifetime 2 minutes
-#auth_param basic program <uncomment and complete this line>
-auth_param basic children 5
-auth_param basic realm Squid proxy-caching web server
-auth_param basic credentialsttl 2 hours
-NOCOMMENT_END
 DOC_END
 
 NAME: authenticate_cache_garbage_interval
@@ -1832,8 +1744,10 @@
 
 NAME: acl
 TYPE: acl
+IFDEF: NEVER
 LOC: Config.aclList
 DEFAULT: none
+DEFAULT_IF_NONE: all src 0.0.0.0/0.0.0.0
 DOC_START
 	Defining an Access List
 
@@ -1910,6 +1824,10 @@
 	  # WARNING: proxy_auth can't be used in a transparent proxy. It
 	  # collides with any authentication done by origin servers. It may
 	  # seem like it works at first, but it doesn't.
+	  #
+	  # NOTE: Authentication schemes need to be defined before proxy_auth ACL's 
+	  # in the squid.conf file.
+	  # See authenticate_* commands.
 
 	acl aclname snmp_community string ...
 	  # A community string to limit access to your SNMP Agent
@@ -2081,7 +1999,7 @@
 NAME: cache_peer_access
 TYPE: peer_access
 DEFAULT: none
-LOC: none
+LOC: Config.peers 
 DOC_START
 	Similar to 'cache_peer_domain' but provides more flexibility by
 	using ACL elements.
@@ -2419,23 +2337,6 @@
 DOC_END
 
 
-NAME: deny_info
-TYPE: denyinfo
-LOC: Config.denyInfoList
-DEFAULT: none
-DOC_START
-	Usage:   deny_info err_page_name acl
-	Example: deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys
-
-	This can be used to return a ERR_ page for requests which
-	do not pass the 'http_access' rules.  A single ACL will cause
-	the http_access check to fail.  If a 'deny_info' line exists
-	for that ACL then Squid returns a corresponding error page.
-
-	You may use ERR_ pages that come with Squid or create your own pages
-	and put them into the configured errors/ directory.
-DOC_END
-
 NAME: memory_pools
 COMMENT: on|off
 TYPE: onoff
Index: squid/src/cf_gen.c
diff -u squid/src/cf_gen.c:1.7 squid/src/cf_gen.c:1.7.8.12
--- squid/src/cf_gen.c:1.7	Fri Jan 12 00:20:32 2001
+++ squid/src/cf_gen.c	Sun Mar 11 13:43:09 2001
@@ -41,11 +41,11 @@
  *		The output files are as follows:
  *		cf_parser.c - this file contains, default_all() which
  *			  initializes variables with the default
- *			  values, parse_line() that parses line from
- *			  squid.conf, dump_config that dumps the
- *			  current the values of the variables.
- *		squid.conf - default configuration file given to the server
- *			 administrator.
+ *			  values, parserRegisterCFTypes() which registers
+ *			  all the cf.data.pre types, parserRegisterCFNames()
+ *			  which registers all the cf.data.pre Names.
+ *		squid.conf.old - legacy version of th default configuration 
+ * 			file given to the server administrator.
  *****************************************************************************/
 
 #include "config.h"
@@ -77,7 +77,7 @@
 
 #define MAX_LINE	1024	/* longest configuration line */
 #define _PATH_PARSER		"cf_parser.c"
-#define _PATH_SQUID_CONF	"squid.conf"
+#define _PATH_SQUID_CONF	"squid.conf.old"
 
 enum State {
     sSTART,
@@ -108,12 +108,96 @@
 
 
 static const char WS[] = " \t";
-static int gen_default(Entry *, FILE *);
-static void gen_parse(Entry *, FILE *);
-static void gen_dump(Entry *, FILE *);
-static void gen_free(Entry *, FILE *);
 static void gen_conf(Entry *, FILE *);
+static void gen_registertypes(Entry *, FILE *);
+static int gen_registernames(Entry *, FILE *);
 static void gen_default_if_none(Entry *, FILE *);
+static void gen_document(Entry *, FILE *);
+
+
+static struct {
+    unsigned char code;
+    char *quote;
+} printfstandardentities[] =
+
+{
+    /* NOTE: The quoted form MUST not be larger than 6 character.
+     * see close to the MemPool commend below
+     */
+    {
+        '\"', "\\\""
+    },
+    {
+        '\\',"\\\\"
+    },
+    {
+	'%',"%%"
+    },
+    {
+        '\t',"\\t"
+    },
+    {
+        '\0', "\0"
+    }
+};
+
+/*
+ *  printf_quote - Returns a static buffer containing the quoted
+ *  string.
+ */
+char *
+printf_quote(const char *string)
+{
+    static char *buf;
+    static size_t bufsize = 0;
+    const char *src;
+    char *dst;
+    int i;
+
+    /* XXX This really should be implemented using a MemPool, but
+     * MemPools are not yet available in lib...
+     */
+    if (buf == NULL || strlen(string) * 6 > bufsize) {
+        xfree(buf);
+        bufsize = strlen(string) * 6 + 1;
+        buf = xcalloc(bufsize, 1);
+    }
+    for (src = string, dst = buf; *src; src++) {
+        char *escape = NULL;
+        const unsigned char ch = *src;
+
+        /* Walk thru the list of HTML Entities that must be quoted to
+         * display safely
+         */
+        for (i = 0; printfstandardentities[i].code; i++) {
+            if (ch == printfstandardentities[i].code) {
+                escape = printfstandardentities[i].quote;
+                break;
+            }
+        }
+        /* Encode control chars just to be on the safe side, and make
+         * sure all 8-bit characters are encoded to protect from buggy
+         * clients
+         */
+        if (!escape && (ch <= 0x1F || ch >= 0x7f) && ch != '\n' && ch != '\r') {
+            static char dec_encoded[7];
+            snprintf(dec_encoded, sizeof dec_encoded, "\\%03o", (int) ch);
+            escape = dec_encoded;
+        }
+        if (escape) {
+            /* Ok, An escaped form was found above. Use it */
+            strncpy(dst, escape, 6);
+            dst += strlen(escape);
+        } else {
+            /* Apparently there is no need to escape this character */
+            *dst++ = ch;
+        }
+    }
+    /* Nullterminate and return the result */
+    *dst = '\0';
+    return (buf);
+}
+
 
 static void
 lineAdd(Line ** L, char *str)
@@ -321,10 +405,8 @@
     fclose(fp);
 
     /*-------------------------------------------------------------------*
-     * Generate default_all()
-     * Generate parse_line()
-     * Generate dump_config()
-     * Generate free_all()
+     * Generate parserRegisterCFTypes()
+     * Generate parserRegisterCFNames()
      * Generate example squid.conf file
      *-------------------------------------------------------------------*/
 
@@ -346,11 +428,10 @@
 	"\n",
 	input_filename, argv[0]
 	);
-    rc = gen_default(entries, fp);
     gen_default_if_none(entries, fp);
-    gen_parse(entries, fp);
-    gen_dump(entries, fp);
-    gen_free(entries, fp);
+    gen_registertypes(entries, fp);
+    gen_document(entries, fp);
+    rc = gen_registernames(entries, fp);
     fclose(fp);
 
     /* Open output x.conf file */
@@ -367,73 +448,11 @@
     return (rc);
 }
 
-static int
-gen_default(Entry * head, FILE * fp)
-{
-    Entry *entry;
-    int rc = 0;
-    fprintf(fp,
-	"static void\n"
-	"default_line(const char *s)\n"
-	"{\n"
-	"\tLOCAL_ARRAY(char, tmp_line, BUFSIZ);\n"
-	"\txstrncpy(tmp_line, s, BUFSIZ);\n"
-	"\txstrncpy(config_input_line, s, BUFSIZ);\n"
-	"\tconfig_lineno++;\n"
-	"\tparse_line(tmp_line);\n"
-	"}\n"
-	);
-    fprintf(fp,
-	"static void\n"
-	"default_all(void)\n"
-	"{\n"
-	"\tcfg_filename = \"Default Configuration\";\n"
-	"\tconfig_lineno = 0;\n"
-	);
-    for (entry = head; entry != NULL; entry = entry->next) {
-	assert(entry->name);
-	assert(entry != entry->next);
-
-	if (!strcmp(entry->name, "comment"))
-	    continue;
-	if (entry->loc == NULL) {
-	    fprintf(stderr, "NO LOCATION FOR %s\n", entry->name);
-	    rc |= 1;
-	    continue;
-	}
-	if (entry->default_value == NULL) {
-	    fprintf(stderr, "NO DEFAULT FOR %s\n", entry->name);
-	    rc |= 1;
-	    continue;
-	}
-	assert(entry->default_value);
-	if (entry->ifdef)
-	    fprintf(fp, "#if %s\n", entry->ifdef);
-	if (strcmp(entry->default_value, "none") == 0) {
-	    fprintf(fp, "\t/* No default for %s */\n", entry->name);
-	} else {
-	    fprintf(fp, "\tdefault_line(\"%s %s\");\n",
-		entry->name,
-		entry->default_value);
-	}
-	if (entry->ifdef)
-	    fprintf(fp, "#endif\n");
-    }
-    fprintf(fp, "\tcfg_filename = NULL;\n");
-    fprintf(fp, "}\n\n");
-    return rc;
-}
-
 static void
 gen_default_if_none(Entry * head, FILE * fp)
 {
     Entry *entry;
     Line *line;
-    fprintf(fp,
-	"static void\n"
-	"defaults_if_none(void)\n"
-	"{\n"
-	);
     for (entry = head; entry != NULL; entry = entry->next) {
 	assert(entry->name);
 	assert(entry->loc);
@@ -441,124 +460,192 @@
 	    continue;
 	if (entry->ifdef)
 	    fprintf(fp, "#if %s\n", entry->ifdef);
-	if (entry->default_if_none) {
+	fprintf(fp,
+	    "static void\n"
+	    "default_if_none_%s(void * data)"
+	    "{\n"
+	    "\tif (check_null_%s(%s)) {\n",
+	    entry->name,
+	    entry->type,
+	    entry->loc);
+	for (line = entry->default_if_none; line; line = line->next)
 	    fprintf(fp,
-		"\tif (check_null_%s(%s)) {\n",
-		entry->type,
-		entry->loc);
-	    for (line = entry->default_if_none; line; line = line->next)
-		fprintf(fp,
-		    "\t\tdefault_line(\"%s %s\");\n",
-		    entry->name,
-		    line->data);
-	    fprintf(fp, "\t}\n");
-	}
+		"\t\tdefault_line(\"%s %s\");\n",
+		entry->name,
+		line->data);
+	fprintf(fp, "\t}\n}\n%s", entry->ifdef ? "" : "\n");
 	if (entry->ifdef)
-	    fprintf(fp, "#endif\n");
+	    fprintf(fp, "#endif\n%s", entry->ifdef ? "\n" : "");
     }
-    fprintf(fp, "}\n\n");
 }
 
 static void
-gen_parse(Entry * head, FILE * fp)
+gen_registertypes(Entry * head, FILE * fp)
 {
     Entry *entry;
-
     fprintf(fp,
-	"static int\n"
-	"parse_line(char *buff)\n"
-	"{\n"
-	"\tint\tresult = 1;\n"
-	"\tchar\t*token;\n"
-	"\tdebug(0,10)(\"parse_line: %%s\\n\", buff);\n"
-	"\tif ((token = strtok(buff, w_space)) == NULL)\n"
-	"\t\t(void) 0;\t/* ignore empty lines */\n"
-	);
-
+        "static void\n"
+        "parserRegisterCFTypes(void)\n"
+        "{\n"
+        );
     for (entry = head; entry != NULL; entry = entry->next) {
-	if (strcmp(entry->name, "comment") == 0)
-	    continue;
-	if (entry->ifdef)
-	    fprintf(fp, "#if %s\n", entry->ifdef);
-	fprintf(fp, "\telse if (!strcmp(token, \"%s\"))\n",
-	    entry->name
-	    );
-	assert(entry->loc);
-	if (strcmp(entry->loc, "none") == 0) {
-	    fprintf(fp,
-		"\t\tparse_%s();\n",
-		entry->type
-		);
-	} else {
-	    fprintf(fp,
-		"\t\tparse_%s(&%s%s);\n",
-		entry->type, entry->loc,
-		entry->array_flag ? "[0]" : ""
-		);
-	}
-	if (entry->ifdef)
-	    fprintf(fp, "#endif\n");
+        assert(entry->loc);
+        if (strcmp(entry->name, "comment") == 0)
+            continue;
+        if (entry->ifdef)
+            fprintf(fp, "#if %s\n", entry->ifdef);
+        fprintf(fp, "\tparserRegisterType(\"%s\",parse_%s,free_%s,dump_%s);\n",
+            entry->type,
+            entry->type,
+	    entry->type,
+	    entry->type);
+        if (entry->ifdef)
+            fprintf(fp, "#endif\n");
     }
-
-    fprintf(fp,
-	"\telse\n"
-	"\t\tresult = 0; /* failure */\n"
-	"\treturn(result);\n"
-	"}\n\n"
-	);
+    fprintf(fp, "}\n\n");
 }
 
-static void
-gen_dump(Entry * head, FILE * fp)
+static int
+gen_registernames(Entry * head, FILE * fp)
 {
     Entry *entry;
+    int rc=0;
     fprintf(fp,
-	"static void\n"
-	"dump_config(StoreEntry *entry)\n"
-	"{\n"
-	);
+        "#define default_if_none_NULL NULL\nstatic void\n"
+        "parserRegisterCFNames(void)\n"
+        "{\n"
+	"\tcfg_filename=\"Default Configuration\";"
+	"\tconfig_lineno = 0;"
+        );
     for (entry = head; entry != NULL; entry = entry->next) {
-	assert(entry->loc);
-	if (strcmp(entry->loc, "none") == 0)
-	    continue;
+        assert(entry->loc);
 	if (strcmp(entry->name, "comment") == 0)
 	    continue;
-	if (entry->ifdef)
-	    fprintf(fp, "#if %s\n", entry->ifdef);
-	fprintf(fp, "\tdump_%s(entry, \"%s\", %s);\n",
-	    entry->type,
-	    entry->name,
-	    entry->loc);
-	if (entry->ifdef)
-	    fprintf(fp, "#endif\n");
+        if (strcmp(entry->loc, "none") == 0) {
+	    printf("location \"none\" not valid  for name %s\n", entry->name);
+	    exit(1);
+	}
+        if (entry->ifdef)
+            fprintf(fp, "#if %s\n", entry->ifdef);
+	fprintf(fp, "\tparserRegisterName(NULL, \"%s\",parserTypeByName(\"%s\"),&%s%s,default_if_none_%s,name_document_%s, NULL);\n",
+            entry->name,
+            entry->type,
+            entry->loc,
+            entry->array_flag ? "[0]" : "",
+	    entry->default_if_none ? entry->name : "NULL",
+	    entry->name);
+	if (entry->default_value == NULL) {
+	    fprintf(stderr, "NO DEFAULT FOR %s\n", entry->name);
+	    rc |= 1;
+	}
+	if (strcmp(entry->default_value, "none") == 0) {
+            fprintf(fp, "\t/* No default for %s */\n", entry->name);
+        } else {
+            fprintf(fp, "\tdefault_line(\"%s %s\");\n",
+                entry->name,
+                entry->default_value);
+        }
+        if (entry->ifdef)
+            fprintf(fp, "#endif\n");
     }
     fprintf(fp, "}\n\n");
+    return rc;
 }
 
+
+
+
 static void
-gen_free(Entry * head, FILE * fp)
+gen_document(Entry * head, FILE * fp)
 {
     Entry *entry;
-    fprintf(fp,
-	"static void\n"
-	"free_all(void)\n"
-	"{\n"
-	);
+    Line *line;
+    Line *def = NULL;
+    Line *comm = NULL;
+    char buf[8192];
     for (entry = head; entry != NULL; entry = entry->next) {
-	assert(entry->loc);
-	if (strcmp(entry->loc, "none") == 0)
-	    continue;
-	if (strcmp(entry->name, "comment") == 0)
+	int blank = 1;
+        assert(entry->name);
+        assert(entry->loc);
+        if (entry->ifdef)
+            fprintf(fp, "#if %s\n", entry->ifdef);
+	if (!strcmp(entry->name, "comment"))
+	{
+	    lineAdd(&comm, "");
+	    for (line = entry->doc; line != NULL; line = line->next) {
+		sprintf(buf, "#%s", line->data);
+		lineAdd(&comm, buf);
+	    }
+	    lineAdd(&comm,"");
 	    continue;
-	if (entry->ifdef)
-	    fprintf(fp, "#if %s\n", entry->ifdef);
-	fprintf(fp, "\tfree_%s(&%s%s);\n",
-	    entry->type, entry->loc,
-	    entry->array_flag ? "[0]" : "");
-	if (entry->ifdef)
-	    fprintf(fp, "#endif\n");
+	}
+        fprintf(fp,
+                "static void\n"
+                "name_document_%s(void)"
+                "{\n"
+                "\tprintf(\n",
+		entry->name);
+
+	if (comm) {
+	    while (comm != NULL) {
+	        line = comm;
+	        comm = line->next;
+	        fprintf(fp, "\"%s\\n\"\n", printf_quote(line->data));
+	        xfree(line->data);
+	        xfree(line);
+	    }
+	    blank = 1;
+	}
+	fprintf(fp, "\"#  TAG: %s\"\n",
+                entry->name);
+        if (entry->comment)
+                fprintf(fp, "\"\t%s\"\n", printf_quote(entry->comment));
+        fprintf(fp, "\"\\n\"\n");
+
+	for (line = entry->doc; line != NULL; line = line->next) {
+	    fprintf(fp, "\"#%s\\n\"\n", printf_quote(line->data));
+	}
+	if (entry->default_value && strcmp(entry->default_value, "none") != 0) {
+	    sprintf(buf, "%s %s", entry->name, entry->default_value);
+	    lineAdd(&def, buf);
+	}
+        if (entry->default_if_none) {
+	    for (line = entry->default_if_none; line; line = line->next) {
+		sprintf(buf, "%s %s", entry->name, line->data);
+		lineAdd(&def, buf);
+	    }
+	}
+	if (entry->nocomment)
+	    blank = 0;
+	if (!def && entry->doc && !entry->nocomment &&
+	    strcmp(entry->name, "comment") != 0)
+	    lineAdd(&def, "none");
+	if (def && (entry->doc || entry->nocomment)) {
+	    if (blank)
+	        fprintf(fp, "\"#\\n\"\n");
+	    fprintf(fp, "\"#Default:\\n\"\n");
+	    while (def != NULL) {
+	        line = def;
+	        def = line->next;
+	        fprintf(fp, "\"# %s\\n\"\n", printf_quote(line->data));
+	        xfree(line->data);
+	        xfree(line);
+	    }
+	    blank = 1;
+	}
+	if (entry->nocomment && blank)
+	    fprintf(fp, "\"#\\n\"\n");
+	for (line = entry->nocomment; line != NULL; line = line->next) {
+	    fprintf(fp, "\"%s\\n\"\n", printf_quote(line->data));
+	}
+	if (entry->doc != NULL) {
+	    fprintf(fp, "\"\\n\"\n");
+	}
+            fprintf(fp, "\t);}\n%s", entry->ifdef ? "" : "\n");
+        
+        if (entry->ifdef)
+            fprintf(fp, "#endif\n%s", entry->ifdef ? "\n" : "");
     }
-    fprintf(fp, "}\n\n");
 }
 
 static int
Index: squid/src/client_side.c
diff -u squid/src/client_side.c:1.28 squid/src/client_side.c:1.18.4.7
--- squid/src/client_side.c:1.28	Fri May  4 06:39:12 2001
+++ squid/src/client_side.c	Sat May 12 08:22:30 2001
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "acl.h"
 
 #if IPF_TRANSPARENT
 #if HAVE_SYS_IOCTL_H
@@ -247,7 +248,10 @@
 	http->log_type = LOG_TCP_DENIED;
 	http->entry = clientCreateStoreEntry(http, http->request->method,
 	    null_request_flags);
-	if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) {
+	if (!strncmp(AclMatchedAcl->aclname->namestr, "proxy_auth", 10)) {
+/* The test above was 
+ * if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) {
+ */
 	    if (!http->flags.accel) {
 		/* Proxy authorisation needed */
 		status = HTTP_PROXY_AUTHENTICATION_REQUIRED;
Index: squid/src/dlink.h
diff -u /dev/null squid/src/dlink.h:1.1.2.1
--- /dev/null	Tue Sep 28 18:35:58 2004
+++ squid/src/dlink.h	Mon Apr 23 15:28:33 2001
@@ -0,0 +1,51 @@
+
+/*
+ * $Id$
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef _DLINK_H_
+#define _DLINK_H_
+
+typedef struct _dlink_node dlink_node;
+typedef struct _dlink_list dlink_list;
+
+struct _dlink_node {
+    void *data;
+    dlink_node *prev;
+    dlink_node *next;
+};
+
+struct _dlink_list {
+    dlink_node *head;
+    dlink_node *tail;
+};
+
+#endif /* DLINK_H */
Index: squid/src/enums.h
diff -u squid/src/enums.h:1.21 squid/src/enums.h:1.14.4.11
--- squid/src/enums.h:1.21	Fri Apr 20 14:35:33 2001
+++ squid/src/enums.h	Sun May 13 02:49:51 2001
@@ -93,51 +93,9 @@
 } err_type;
 
 typedef enum {
-    ACL_NONE,
-    ACL_SRC_IP,
-    ACL_DST_IP,
-    ACL_MY_IP,
-    ACL_SRC_DOMAIN,
-    ACL_DST_DOMAIN,
-    ACL_SRC_DOM_REGEX,
-    ACL_DST_DOM_REGEX,
-    ACL_TIME,
-    ACL_URLPATH_REGEX,
-    ACL_URL_REGEX,
-    ACL_URL_PORT,
-    ACL_MY_PORT,
-#if USE_IDENT
-    ACL_IDENT,
-    ACL_IDENT_REGEX,
-#endif
-    ACL_PROTO,
-    ACL_METHOD,
-    ACL_BROWSER,
-    ACL_PROXY_AUTH,
-    ACL_PROXY_AUTH_REGEX,
-    ACL_SRC_ASN,
-    ACL_DST_ASN,
-#if USE_ARP_ACL
-    ACL_SRC_ARP,
-#endif
-#if SQUID_SNMP
-    ACL_SNMP_COMMUNITY,
-#endif
-#if SRC_RTT_NOT_YET_FINISHED
-    ACL_NETDB_SRC_RTT,
-#endif
-    ACL_MAXCONN,
-    ACL_REQ_MIME_TYPE,
-    ACL_REP_MIME_TYPE,
-    ACL_ENUM_MAX
-} squid_acl;
-
-typedef enum {
     ACL_LOOKUP_NONE,
-    ACL_LOOKUP_NEEDED,
     ACL_LOOKUP_PENDING,
     ACL_LOOKUP_DONE,
-    ACL_PROXY_AUTH_NEEDED,
 } acl_lookup_state;
 
 enum {
@@ -155,6 +113,12 @@
 };
 
 typedef enum {
+    MOD_NONE,
+    MOD_INTERNAL,
+    MOD_EXTERNAL
+} mod_t;
+
+typedef enum {
     PEER_NONE,
     PEER_SIBLING,
     PEER_PARENT,
@@ -554,16 +518,16 @@
     MEM_16K_BUF,
     MEM_32K_BUF,
     MEM_64K_BUF,
-    MEM_ACL,
-    MEM_ACL_DENY_INFO_LIST,
-    MEM_ACL_IP_DATA,
+//    MEM_ACL,
+//    MEM_ACL_DENY_INFO_LIST,
+//    MEM_ACL_IP_DATA,
     MEM_ACL_LIST,
-    MEM_ACL_NAME_LIST,
+//    MEM_ACL_NAME_LIST,
     MEM_AUTH_USER_T,
     MEM_AUTH_USER_HASH,
-    MEM_ACL_PROXY_AUTH_MATCH,
-    MEM_ACL_USER_DATA,
-    MEM_ACL_TIME_DATA,
+//    MEM_ACL_PROXY_AUTH_MATCH,
+//    MEM_ACL_USER_DATA,
+//    MEM_ACL_TIME_DATA,
 #if USE_CACHE_DIGESTS
     MEM_CACHE_DIGEST,
 #endif
Index: squid/src/globals.h
diff -u squid/src/globals.h:1.10 squid/src/globals.h:1.7.8.3
--- squid/src/globals.h:1.10	Sat May  5 13:47:38 2001
+++ squid/src/globals.h	Sat May 12 06:06:03 2001
@@ -153,6 +153,8 @@
 extern ssize_t store_maxobjsize;	/* -1 */
 extern RemovalPolicy *mem_policy;
 extern hash_table *proxy_auth_username_cache;	/* NULL */
+extern dlink_list parserTypes; 
+extern dlink_list parserNames;
 extern int incoming_sockets_accepted;
 #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
 extern unsigned int WIN32_OS_version;	/* 0 */
Index: squid/src/internal_modules.sh
diff -u /dev/null squid/src/internal_modules.sh:1.1.2.2
--- /dev/null	Tue Sep 28 18:35:58 2004
+++ squid/src/internal_modules.sh	Fri Feb 23 19:04:01 2001
@@ -0,0 +1,28 @@
+#!/bin/sh
+echo "/* automatically generated by $0 $*"
+echo " * do not edit"
+echo " */"
+echo "#include \"squid.h\""
+echo ""
+for module in "$@"; do
+   echo "extern MOD_INSTALL mod_install_${module};"
+   echo "extern MOD_UNINSTALL mod_uninstall_${module};"
+done
+echo "int mod_internal_install(const char *namestr, modNode *module)"
+echo "{"
+echo "    if (strcasecmp(namestr,\"all\")==0) {"
+echo "	/* register all internal modules */"
+for module in "$@"; do
+   echo "	default_line(\"mod_register internal $module\");"
+done
+echo "        return -1;"
+echo "    } else"
+for module in "$@"; do
+   echo "    if (strcasecmp(namestr,\"$module\")==0) {"
+   echo "	mod_register(\"$module\", mod_install_${module}, mod_uninstall_${module}, module);"
+   echo "	return -1;"
+   echo "    } else"
+done
+echo    "       debug(3,0)(\"mod_internal_install: unrecognised module '%s'.\n\",namestr);"
+echo    "    return 0;"
+echo "}"
Index: squid/src/main.c
diff -u squid/src/main.c:1.23 squid/src/main.c:1.19.4.8
--- squid/src/main.c:1.23	Sat May  5 13:47:38 2001
+++ squid/src/main.c	Sat May 12 06:06:03 2001
@@ -38,6 +38,7 @@
 /* for error reporting from xmalloc and friends */
 extern void (*failure_notify) (const char *);
 
+static int opt_do_document = 0;
 static int opt_send_signal = -1;
 static int opt_no_daemon = 0;
 static int opt_parse_cfg_only = 0;
@@ -83,8 +84,13 @@
 usage(void)
 {
     fprintf(stderr,
-	"Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n"
+	"Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [[-k signal]|[-c directive]]\n"
 	"       -a port   Specify HTTP port number (default: %d).\n"
+	"       -c directive\n"
+	"                 Write the configuration help for that directive to std out\n"
+	"                 Special directives:\n"
+	"                    all           Write all directives\n"
+	"                    internalonly  Do not parse config-file for modules\n"
 	"       -d level  Write debugging to stderr also.\n"
 	"       -f file   Use given config-file instead of\n"
 	"                 %s\n"
@@ -115,8 +121,12 @@
     extern char *optarg;
     int c;
 
-    while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) {
+    while ((c = getopt(argc, argv, "CDFNRSVYXa:c:d:f:hk:m::su:vz?")) != -1) {
 	switch (c) {
+	case 'c':
+	    opt_do_document = 1;
+	    parserAddDocumentOption(optarg);
+	    break;
 	case 'C':
 	    opt_catch_signals = 0;
 	    break;
@@ -346,7 +356,7 @@
     authenticateShutdown();
     storeDirCloseSwapLogs();
     errorClean();
-    parseConfigFile(ConfigFile);
+    parserReconfigure(ConfigFile);
     _db_init(Config.Log.log, Config.debugOptions);
     ipcache_restart();		/* clear stuck entries */
     authenticateUserCacheRestart();	/* clear stuck ACL entries */
@@ -359,7 +369,7 @@
     idnsInit();
 #endif
     redirectInit();
-    authenticateInit(&Config.authConfig);
+    authenticateInit(&Config.authSchemes);
 #if USE_WCCP
     wccpInit();
 #endif
@@ -400,7 +410,7 @@
     dnsInit();
 #endif
     redirectInit();
-    authenticateInit(&Config.authConfig);
+    authenticateInit(&Config.authSchemes);
 }
 
 static void
@@ -480,7 +490,7 @@
     idnsInit();
 #endif
     redirectInit();
-    authenticateInit(&Config.authConfig);
+    authenticateInit(&Config.authSchemes);
     useragentOpenLog();
     refererOpenLog();
     httpHeaderInitModule();	/* must go before any header processing (e.g. the one in errorInitialize) */
@@ -630,13 +640,15 @@
 	memInit();
 	cbdataInit();
 	eventInit();		/* eventInit() is required for config parsing */
-	storeFsInit();		/* required for config parsing */
-	authenticateSchemeInit();	/* required for config parsign */
-	parse_err = parseConfigFile(ConfigFile);
+	if (!opt_do_document)
+	    parse_err = parserReconfigure(ConfigFile);
+	else
+	    parse_err = parserDoDocument(ConfigFile);
 
-	if (opt_parse_cfg_only)
+	if (opt_parse_cfg_only || opt_do_document)
 	    return parse_err;
     }
+
     if (-1 == opt_send_signal)
 	if (checkRunningPid())
 	    exit(1);
Index: squid/src/mem.c
diff -u squid/src/mem.c:1.12 squid/src/mem.c:1.8.8.4
--- squid/src/mem.c:1.12	Fri Apr 20 14:35:33 2001
+++ squid/src/mem.c	Fri Apr 27 07:24:57 2001
@@ -193,21 +193,21 @@
     memDataInit(MEM_32K_BUF, "32K Buffer", 32768, 10);
     memDataInit(MEM_64K_BUF, "64K Buffer", 65536, 10);
     memDataInit(MEM_CLIENT_SOCK_BUF, "Client Socket Buffer", CLIENT_SOCK_SZ, 0);
-    memDataInit(MEM_ACL, "acl", sizeof(acl), 0);
-    memDataInit(MEM_ACL_DENY_INFO_LIST, "acl_deny_info_list",
-	sizeof(acl_deny_info_list), 0);
-    memDataInit(MEM_ACL_IP_DATA, "acl_ip_data", sizeof(acl_ip_data), 0);
+//    memDataInit(MEM_ACL, "acl", sizeof(acl), 0);
+//    memDataInit(MEM_ACL_DENY_INFO_LIST, "acl_deny_info_list",
+//	sizeof(acl_deny_info_list), 0);
+//    memDataInit(MEM_ACL_IP_DATA, "acl_ip_data", sizeof(acl_ip_data), 0);
     memDataInit(MEM_ACL_LIST, "acl_list", sizeof(acl_list), 0);
-    memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0);
-    memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0);
+//    memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0);
+//    memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0);
     memDataInit(MEM_AUTH_USER_T, "auth_user_t",
 	sizeof(auth_user_t), 0);
     memDataInit(MEM_AUTH_USER_HASH, "auth_user_hash_pointer",
 	sizeof(auth_user_hash_pointer), 0);
-    memDataInit(MEM_ACL_PROXY_AUTH_MATCH, "acl_proxy_auth_match_cache",
-	sizeof(acl_proxy_auth_match_cache), 0);
-    memDataInit(MEM_ACL_USER_DATA, "acl_user_data",
-	sizeof(acl_user_data), 0);
+//    memDataInit(MEM_ACL_PROXY_AUTH_MATCH, "acl_proxy_auth_match_cache",
+//	sizeof(acl_proxy_auth_match_cache), 0);
+//    memDataInit(MEM_ACL_USER_DATA, "acl_user_data",
+//	sizeof(acl_user_data), 0);
 #if USE_CACHE_DIGESTS
     memDataInit(MEM_CACHE_DIGEST, "CacheDigest", sizeof(CacheDigest), 0);
 #endif
Index: squid/src/modules.c
diff -u /dev/null squid/src/modules.c:1.1.6.1
--- /dev/null	Tue Sep 28 18:35:58 2004
+++ squid/src/modules.c	Wed Feb 14 05:51:42 2001
@@ -0,0 +1,54 @@
+
+/*
+ * $Id$
+ *
+ * DEBUG: section 84    Modules Interface
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+
+/* TEMPORARY HOME FOR DOCUMENTATION:
+ *
+ * the uninstall function returns true for 'I uninstalled succesfully' and
+ * not true for 'I didn't uninstall'. Some modules may not uninstall ever,
+ * and some may only uninstall if there are no references - it's
+ * up to the module.
+ */
+
+#include "squid.h"
+
+void 
+mod_register(const char *namestr, MOD_INSTALL *install, MOD_UNINSTALL *uninstall, modNode *module) {
+    debug(84,1)("mod_register: registering %s\n");
+    module->install=install;
+    module->uninstall=uninstall;
+    /* this may be skippable here ... */
+    install(namestr);
+}
Index: squid/src/protos.h
diff -u squid/src/protos.h:1.27 squid/src/protos.h:1.18.4.27
--- squid/src/protos.h:1.27	Tue May  8 08:27:00 2001
+++ squid/src/protos.h	Sun May 13 02:49:51 2001
@@ -47,56 +47,39 @@
 char *log_quote(const char *header);
 
 /* acl.c */
+extern void aclParserRegister(void);
 extern aclCheck_t *aclChecklistCreate(const struct _acl_access *,
     request_t *,
     const char *ident);
 extern void aclNBCheck(aclCheck_t *, PF *, void *);
 extern int aclCheckFast(const struct _acl_access *A, aclCheck_t *);
 extern void aclChecklistFree(aclCheck_t *);
-extern int aclMatchAclList(const acl_list * list, aclCheck_t * checklist);
 extern void aclDestroyAccessList(struct _acl_access **list);
 extern void aclDestroyAcls(acl **);
 extern void aclParseAccessLine(struct _acl_access **);
-extern void aclParseAclLine(acl **);
+extern PARSER_PARSE aclParseAclLine;
+#if 0
 extern int aclIsProxyAuth(const char *name);
+#endif
 extern err_type aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name);
 extern void aclParseDenyInfoLine(struct _acl_deny_info_list **);
-extern void aclDestroyDenyInfoList(struct _acl_deny_info_list **);
-extern void aclDestroyRegexList(struct _relist *data);
+#if 0
+extern PARSER_FREE aclDestroyRegexList;
 extern int aclMatchRegex(relist * data, const char *word);
-extern void aclParseRegexList(void *curlist);
-extern const char *aclTypeToStr(squid_acl);
-extern wordlist *aclDumpGeneric(const acl *);
+extern PARSER_PARSE aclParseRegexList;
+#endif
 extern int aclPurgeMethodInUse(acl_access *);
 extern void aclCacheMatchFlush(dlink_list * cache);
+extern void aclRegisterAclDirective(void);
 
 /*
  * cache_cf.c
+ * FIXME: these should be registered by the appropriate "area" of squid, not in 
+ * cache_cf.c
  */
-extern int parseConfigFile(const char *file_name);
-extern void intlistDestroy(intlist **);
-extern int intlistFind(intlist * list, int i);
-extern const char *wordlistAdd(wordlist **, const char *);
-extern void wordlistAddWl(wordlist **, wordlist *);
-extern void wordlistJoin(wordlist **, wordlist **);
-extern wordlist *wordlistDup(const wordlist *);
-extern void wordlistDestroy(wordlist **);
-extern void configFreeMemory(void);
-extern void wordlistCat(const wordlist *, MemBuf * mb);
-extern void allocate_new_swapdir(cacheSwap *);
-extern void self_destruct(void);
-extern int GetInteger(void);
-
-/* extra functions from cache_cf.c useful for lib modules */
-extern void parse_int(int *var);
-extern void parse_eol(char *volatile *var);
-extern void parse_wordlist(wordlist ** list);
-extern void requirePathnameExists(const char *name, const char *path);
-extern void parse_time_t(time_t * var);
 extern void parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring);
 extern void dump_cachedir_options(StoreEntry * e, struct cache_dir_option *options, SwapDir * sd);
 
-
 /*
  * cbdata.c
  */
@@ -723,16 +706,12 @@
 extern void redirectInit(void);
 extern void redirectShutdown(void);
 
-/* auth_modules.c */
-extern void authSchemeSetup(void);
-
 /* authenticate.c */
 extern void authenticateAuthUserMerge(auth_user_t *, auth_user_t *);
 extern auth_user_t *authenticateAuthUserNew(const char *);
 extern int authenticateAuthSchemeId(const char *typestr);
 extern void authenticateStart(auth_user_request_t *, RH *, void *);
-extern void authenticateSchemeInit(void);
-extern void authenticateInit(authConfig *);
+extern void authenticateInit(authSchemes *);
 extern void authenticateShutdown(void);
 extern void authenticateFixHeader(HttpReply *, auth_user_request_t *, request_t *, int);
 extern void authenticateAddTrailer(HttpReply *, auth_user_request_t *, request_t *, int);
@@ -760,7 +739,7 @@
 extern char *authenticateUserRequestUsername(auth_user_request_t *);
 extern int authenticateValidateUser(auth_user_request_t *);
 extern void authenticateOnCloseConnection(ConnStateData * conn);
-extern void authSchemeAdd(char *type, AUTHSSETUP * setup);
+extern void authSchemeAdd(const char *type, AUTHSSETUP * setup);
 
 extern void refreshAddToList(const char *, int, time_t, int, time_t);
 extern int refreshIsCachable(const StoreEntry *);
@@ -920,16 +899,9 @@
 extern void storeEntryReset(StoreEntry *);
 extern void storeHeapPositionUpdate(StoreEntry *, SwapDir *);
 extern void storeSwapFileNumberSet(StoreEntry * e, sfileno filn);
-extern void storeFsInit(void);
 extern void storeFsDone(void);
-extern void storeFsAdd(char *, STSETUP *);
-extern void storeReplAdd(char *, REMOVALPOLICYCREATE *);
-
-/* store_modules.c */
-extern void storeFsSetup(void);
-
-/* repl_modules.c */
-extern void storeReplSetup(void);
+extern void storeFsAdd(const char *, STSETUP *);
+extern void storeReplAdd(const char *, REMOVALPOLICYCREATE *);
 
 /* store_io.c */
 extern storeIOState *storeCreate(StoreEntry *, STFNCB *, STIOCB *, void *);
@@ -1302,6 +1274,11 @@
  */
 extern StatCounters *snmpStatGet(int);
 
+/* internal_modules.sh */
+extern int mod_internal_install(const char *, modNode *);
+/* modules.c */
+extern void mod_register(const char * namestr, MOD_INSTALL *, MOD_UNINSTALL *, modNode *);
+
 /* Vary support functions */
 int varyEvaluateMatch(StoreEntry * entry, request_t * req);
 
Index: squid/src/repl_modules.sh
diff -u squid/src/repl_modules.sh:1.2 squid/src/repl_modules.sh:removed
--- squid/src/repl_modules.sh:1.2	Sat Oct 21 08:16:13 2000
+++ squid/src/repl_modules.sh	Tue Sep 28 18:35:58 2004
@@ -1,15 +0,0 @@
-#!/bin/sh
-echo "/* automatically generated by $0 $*"
-echo " * do not edit"
-echo " */"
-echo "#include \"squid.h\""
-echo ""
-for module in "$@"; do
-   echo "extern REMOVALPOLICYCREATE createRemovalPolicy_${module};"
-done
-echo "void storeReplSetup(void)"
-echo "{"
-for module in "$@"; do
-   echo "	storeReplAdd(\"$module\", createRemovalPolicy_${module});"
-done
-echo "}"
Index: squid/src/store.c
diff -u squid/src/store.c:1.12 squid/src/store.c:1.9.8.4
--- squid/src/store.c:1.12	Fri Apr 13 17:31:02 2001
+++ squid/src/store.c	Fri Apr 27 07:24:57 2001
@@ -1286,21 +1286,6 @@
 }
 
 /*
- * storeFsInit
- *
- * This routine calls the SETUP routine for each fs type.
- * I don't know where the best place for this is, and I'm not going to shuffle
- * around large chunks of code right now (that can be done once its working.)
- */
-void
-storeFsInit(void)
-{
-    storeReplSetup();
-    storeFsSetup();
-}
-
-
-/*
  * similar to above, but is called when a graceful shutdown is to occur
  * of each fs module.
  */
@@ -1319,7 +1304,7 @@
  * called to add another store fs module
  */
 void
-storeFsAdd(char *type, STSETUP * setup)
+storeFsAdd(const char *type, STSETUP * setup)
 {
     int i;
     /* find the number of currently known storefs types */
@@ -1338,7 +1323,7 @@
  * called to add another store removal policy module
  */
 void
-storeReplAdd(char *type, REMOVALPOLICYCREATE * create)
+storeReplAdd(const char *type, REMOVALPOLICYCREATE * create)
 {
     int i;
     /* find the number of currently known repl types */
Index: squid/src/store_modules.sh
diff -u squid/src/store_modules.sh:1.2 squid/src/store_modules.sh:removed
--- squid/src/store_modules.sh:1.2	Sat Oct 21 08:16:13 2000
+++ squid/src/store_modules.sh	Tue Sep 28 18:35:58 2004
@@ -1,15 +0,0 @@
-#!/bin/sh
-echo "/* automatically generated by $0 $*"
-echo " * do not edit"
-echo " */"
-echo "#include \"squid.h\""
-echo ""
-for module in "$@"; do
-   echo "extern STSETUP storeFsSetup_${module};"
-done
-echo "void storeFsSetup(void)"
-echo "{"
-for module in "$@"; do
-   echo "	storeFsAdd(\"$module\", storeFsSetup_${module});"
-done
-echo "}"
Index: squid/src/structs.h
diff -u squid/src/structs.h:1.33 squid/src/structs.h:1.24.4.24
--- squid/src/structs.h:1.33	Tue May  8 08:27:00 2001
+++ squid/src/structs.h	Sun May 13 02:49:51 2001
@@ -33,51 +33,8 @@
 
 #include "config.h"
 #include "splay.h"
-
-struct _dlink_node {
-    void *data;
-    dlink_node *prev;
-    dlink_node *next;
-};
-
-struct _dlink_list {
-    dlink_node *head;
-    dlink_node *tail;
-};
-
-struct _acl_user_data {
-    splayNode *names;
-    struct {
-	unsigned int case_insensitive:1;
-	unsigned int required:1;
-    } flags;
-};
-
-
-struct _acl_ip_data {
-    struct in_addr addr1;	/* if addr2 non-zero then its a range */
-    struct in_addr addr2;
-    struct in_addr mask;
-    acl_ip_data *next;		/* used for parsing, not for storing */
-};
-
-struct _acl_time_data {
-    int weekbits;
-    int start;
-    int stop;
-    acl_time_data *next;
-};
-
-struct _acl_name_list {
-    char name[ACL_NAME_SZ];
-    acl_name_list *next;
-};
-
-struct _acl_proxy_auth_match_cache {
-    dlink_node link;
-    int matchrv;
-    void *acl_data;
-};
+/* FIXME: remove this - no global structures should refer to the parser library */
+#include "squid_parser.h"
 
 struct _auth_user_hash_pointer {
     /* first two items must be same as hash_link */
@@ -133,22 +90,19 @@
  */
 
 struct _authscheme_entry {
-    char *typestr;
+    const char *typestr;
     AUTHSACTIVE *Active;
     AUTHSADDHEADER *AddHeader;
     AUTHSADDTRAILER *AddTrailer;
     AUTHSAUTHED *authenticated;
     AUTHSAUTHUSER *authAuthenticate;
     AUTHSCONFIGURED *configured;
-    AUTHSDUMP *dump;
     AUTHSFIXERR *authFixHeader;
     AUTHSFREE *FreeUser;
-    AUTHSFREECONFIG *freeconfig;
     AUTHSUSERNAME *authUserUsername;
     AUTHSONCLOSEC *oncloseconnection;	/*optional */
     AUTHSDECODE *decodeauth;
     AUTHSDIRECTION *getdirection;
-    AUTHSPARSE *parse;
     AUTHSINIT *init;
     AUTHSREQFREE *requestFree;
     AUTHSSHUTDOWN *donefunc;
@@ -163,11 +117,9 @@
 /* private data types */
 struct _authScheme {
     /* pointer to the authscheme_list's string entry */
-    char *typestr;
+    const char *typestr;
     /* the scheme id in the authscheme_list */
     int Id;
-    /* the scheme's configuration details. */
-    void *scheme_data;
 };
 
 struct _acl_deny_info_list {
@@ -177,14 +129,6 @@
     acl_deny_info_list *next;
 };
 
-#if USE_ARP_ACL
-
-struct _acl_arp_data {
-    char eth[6];
-};
-
-#endif
-
 struct _String {
     /* never reference these directly! */
     unsigned short int size;	/* buffer size; 64K limit */
@@ -219,14 +163,6 @@
 
 #endif
 
-struct _acl {
-    char name[ACL_NAME_SZ];
-    squid_acl type;
-    void *data;
-    char *cfgline;
-    acl *next;
-};
-
 struct _acl_list {
     int op;
     acl *acl;
@@ -252,7 +188,8 @@
     ConnStateData *conn;	/* hack for ident and NTLM */
     char rfc931[USER_IDENT_SZ];
     auth_user_request_t *auth_user_request;
-    acl_lookup_state state[ACL_ENUM_MAX];
+    acl_lookup_state lastcheckstate;
+    acl * lastcheckowner;
 #if SQUID_SNMP
     char *snmp_community;
 #endif
@@ -292,6 +229,18 @@
     sockaddr_in_list *next;
 };
 
+struct _modNode {
+    dlink_node node;
+    char *namestr;
+    mod_t type;
+    MOD_INSTALL   *install;
+    MOD_UNINSTALL *uninstall;
+};
+
+struct _modConfig {
+    dlink_list modules;
+};
+
 #if USE_SSL
 struct _https_port_list {
     https_port_list *next;
@@ -333,6 +282,8 @@
 };
 
 struct _SquidConfig {
+    modConfig modules;
+    includefile_t *files;
     struct {
 	size_t maxSize;
 	int highWaterMark;
@@ -552,7 +503,10 @@
 	int vary_ignore_expire;
 	int pipeline_prefetch;
     } onoff;
+#if 0
     acl *aclList;
+    dlink_list aclList2;
+#endif
     struct {
 	acl_access *http;
 	acl_access *icp;
@@ -572,11 +526,11 @@
 	acl_access *reply;
     } accessList;
     acl_deny_info_list *denyInfoList;
-    struct _authConfig {
+    struct _authSchemes {
 	authScheme *schemes;
 	int n_allocated;
-	int n_configured;
-    } authConfig;
+        int n_configured;
+    } authSchemes;
     struct {
 	size_t list_width;
 	int list_wrap;
@@ -1479,7 +1433,7 @@
 };
 
 struct _SwapDir {
-    char *type;
+    const char *type;
     int cur_size;
     int low_size;
     int max_size;
@@ -2063,7 +2017,7 @@
  */
 
 struct _storefs_entry {
-    char *typestr;
+    const char *typestr;
     STFSPARSE *parsefunc;
     STFSRECONFIGURE *reconfigurefunc;
     STFSSHUTDOWN *donefunc;
@@ -2074,7 +2028,7 @@
  */
 
 struct _storerepl_entry {
-    char *typestr;
+    const char *typestr;
     REMOVALPOLICYCREATE *create;
 };
 
Index: squid/src/typedefs.h
diff -u squid/src/typedefs.h:1.21 squid/src/typedefs.h:1.15.4.17
--- squid/src/typedefs.h:1.21	Tue May  8 08:27:00 2001
+++ squid/src/typedefs.h	Sat May 12 06:06:03 2001
@@ -34,6 +34,9 @@
 #ifndef _TYPEDEFS_H_
 #define _TYPEDEFS_H_
 
+/* FIXME: this shouldn't be a global include */
+#include "dlink.h"
+
 typedef unsigned int store_status_t;
 typedef unsigned int mem_status_t;
 typedef unsigned int ping_status_t;
@@ -149,12 +152,10 @@
 typedef struct _refresh_t refresh_t;
 typedef struct _CommWriteStateData CommWriteStateData;
 typedef struct _ErrorState ErrorState;
-typedef struct _dlink_node dlink_node;
-typedef struct _dlink_list dlink_list;
 typedef struct _StatCounters StatCounters;
 typedef struct _tlv tlv;
 typedef struct _storeSwapLogData storeSwapLogData;
-typedef struct _authConfig authConfig;
+typedef struct _authSchemes authSchemes;
 typedef struct _cacheSwap cacheSwap;
 typedef struct _StatHist StatHist;
 typedef struct _String String;
@@ -190,6 +191,15 @@
 
 typedef struct _http_version_t http_version_t;
 
+/* modules.c */
+typedef struct _modConfig modConfig;
+typedef struct _modNode modNode;
+
+/* name to register under */
+typedef void MOD_INSTALL(const char *);
+typedef unsigned int MOD_UNINSTALL(const char *);
+/* end modules.c */
+
 #if SQUID_SNMP
 typedef variable_list *(oid_ParseFn) (variable_list *, snint *);
 typedef struct _snmp_request_t snmp_request_t;
@@ -297,16 +307,13 @@
 typedef int AUTHSCONFIGURED(void);
 typedef void AUTHSDECODE(auth_user_request_t *, const char *);
 typedef int AUTHSDIRECTION(auth_user_request_t *);
-typedef void AUTHSDUMP(StoreEntry *, const char *, authScheme *);
 typedef void AUTHSFIXERR(auth_user_request_t *, HttpReply *, http_hdr_type, request_t *);
 typedef void AUTHSADDHEADER(auth_user_request_t *, HttpReply *, int);
 typedef void AUTHSADDTRAILER(auth_user_request_t *, HttpReply *, int);
 typedef void AUTHSFREE(auth_user_t *);
-typedef void AUTHSFREECONFIG(authScheme *);
 typedef char *AUTHSUSERNAME(auth_user_t *);
 typedef void AUTHSONCLOSEC(ConnStateData *);
-typedef void AUTHSPARSE(authScheme *, int, char *);
-typedef void AUTHSINIT(authScheme *);
+typedef void AUTHSINIT(void);
 typedef void AUTHSREQFREE(auth_user_request_t *);
 typedef void AUTHSSETUP(authscheme_entry_t *);
 typedef void AUTHSSHUTDOWN(void);
Index: squid/src/auth/basic/auth_basic.c
diff -u squid/src/auth/basic/auth_basic.c:1.11 squid/src/auth/basic/auth_basic.c:1.9.4.8
--- squid/src/auth/basic/auth_basic.c:1.11	Wed Mar 21 15:43:33 2001
+++ squid/src/auth/basic/auth_basic.c	Sat Mar 31 01:52:20 2001
@@ -56,47 +56,135 @@
 static AUTHSCONFIGURED authBasicConfigured;
 static AUTHSDIRECTION authenticateBasicDirection;
 static AUTHSDECODE authenticateBasicDecodeAuth;
-static AUTHSDUMP authBasicCfgDump;
 static AUTHSFIXERR authenticateBasicFixErrorHeader;
 static AUTHSFREE authenticateBasicFreeUser;
-static AUTHSFREECONFIG authBasicFreeConfig;
-static AUTHSPARSE authBasicParse;
 static AUTHSINIT authBasicInit;
 static AUTHSSTART authenticateBasicStart;
 static AUTHSSTATS authenticateBasicStats;
 static AUTHSUSERNAME authenticateBasicUsername;
 static AUTHSSHUTDOWN authBasicDone;
 
+static PARSER_NAME_DOCUMENT authBasicDocumentProgram;
+static PARSER_NAME_DOCUMENT authBasicDocumentChildren;
+static PARSER_NAME_DOCUMENT authBasicDocumentRealm;
+static PARSER_NAME_DOCUMENT authBasicDocumentTTL;
+
 static helper *basicauthenticators = NULL;
 
-static auth_basic_config *basicConfig = NULL;
+static auth_basic_config basicConfig= {0,NULL,NULL,0};
 
 static int authbasic_initialised = 0;
 MemPool *basic_data_pool = NULL;
 
+/* config parsing */
 
-/*
- *
- * Public Functions
- *
- */
+static void
+authBasicDocumentProgram(void)
+{
+    printf("#  TAG: authenticate_basic_program cmdline\n"
+"#\tSpecify the command for the external authenticator.  Such a\n"
+"#\tprogram reads a line containing \"username password\" and replies\n"
+"#\t\"OK\" or \"ERR\" in an endless loop.  If you use an authenticator,\n"
+"#\tmake sure you have 1 acl of type proxy_auth.  By default, the\n"
+"#\tauthenticate_program is not used.\n"
+"#\n"
+"#\tIf you want to use the traditional proxy authentication,\n"
+"#\tjump over to the src/auth/basic/helpers/NCSA directory and\n"
+"#\ttype:\n"
+"#\t        %% make\n"
+"#\t        %% make install\n"
+"#\n"
+"#\tThen, set this line to something like\n"
+"#\n"
+"#\tauth_param basic program /usr/local/squid/bin/ncsa_auth /usr/local/squid/etc/passwd\n\n");
+}
+
+static void
+authBasicDocumentChildren(void)
+{
+    printf("#  TAG: authenticate_basic_children children\n"
+"#\tThe number of authenticator processes to spawn (no default). If you\n"
+"#\tstart too few Squid will have to wait for them to process a backlog\n"
+"#\tof usercode/password verifications, slowing it down. When password\n"
+"#\tverifications are done via a (slow) network you are likely to need\n"
+"#\tlots of authenticator processes.\n"
+"#Default:\n"
+"# authenticate_basic_children 5\n\n");
+}
 
-AUTHSSETUP authSchemeSetup_basic;
+static void
+authBasicDocumentRealm(void)
+{
+    printf("#  TAG: authenticate_basic_realm realm\n"
+"#\tSpecifies the realm name which is to be reported to the client for\n"
+"#\tthe basic proxy authentication scheme (part of the text the user will\n"
+"#\tsee when prompted their username and password).\n"
+"#\tauth_param basic realm Squid proxy-caching web server\n"
+"#Default:\n"
+"# authenticate_basic_realm Squid proxy-caching web server\n\n");
+}
+
+static void
+authBasicDocumentTTL(void)
+{
+    printf("#  TAG: authenticate_basic_ttl ttl\n"
+"#\tSpecifies how long squid assumes an externally validated username:password\n"
+"#\tpair is valid for - in other words how often the helper program is called\n"
+"#\tfor that user. Set this low to force revalidation with short lived passwords.\n"
+"#\tNote that setting this high does not impact your susceptability to replay\n"
+"#\tattacks unless you are using a one-time password system (such as SecureID).\n"
+"#\tIf you are using such a system, you will be vulnerable to replay attacks\n"
+"#\tunless you also enable the IP ttl is strict option.\n"
+"#Default:\n"
+"# authenticate_basic_ttl 2 hours\n\n");
+}
+
+static AUTHSSETUP authSchemeSetup_basic;
 
+/* register as a module */
 void
+mod_install_basic (const char *namestr)
+{
+    authSchemeAdd(namestr, authSchemeSetup_basic);
+    parserRegisterName(NULL, "authenticate_basic_program", parserTypeByName("wordlist"), &basicConfig.authenticate, NULL, authBasicDocumentProgram, NULL);
+    parserRegisterName(NULL, "authenticate_basic_children", parserTypeByName("int"), &basicConfig.authenticateChildren, NULL, authBasicDocumentChildren, NULL);
+    default_line("authenticate_basic_children 5");
+    parserRegisterName(NULL, "authenticate_basic_realm", parserTypeByName("eol"), &basicConfig.basicAuthRealm, NULL, authBasicDocumentRealm, NULL);
+    default_line("authenticate_basic_realm Squid proxy-caching web server");
+    parserRegisterName(NULL, "authenticate_basic_ttl", parserTypeByName("time_t"), &basicConfig.credentialsTTL, NULL, authBasicDocumentTTL, NULL);
+    default_line("authenticate_basic_ttl 2 hours");
+
+    /* until we support mod_uninstall we need to keep the names active indefinately */
+    cbdataLock(parserNameByName("authenticate_basic_program"));
+    cbdataLock(parserNameByName("authenticate_basic_children"));
+    cbdataLock(parserNameByName("authenticate_basic_realm"));
+    cbdataLock(parserNameByName("authenticate_basic_ttl"));
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_basic(const char *namestr) {
+    /* deregistration should simply _queue_ the wish to deregister. 
+     * Actual deregistration takes place when their are no more references 
+     * to anything.
+     * this work will be undertaken in auth_rewrite when the configuration 
+     * and modules work is merged via HEAD.
+     */
+    return 0;
+}
+
+
+static void
 authSchemeSetup_basic(authscheme_entry_t * authscheme)
 {
     assert(!authbasic_initialised);
     authscheme->Active = authenticateBasicActive;
-    authscheme->parse = authBasicParse;
-    authscheme->dump = authBasicCfgDump;
     authscheme->init = authBasicInit;
     authscheme->authAuthenticate = authenticateBasicAuthenticateUser;
     authscheme->authenticated = authenticateBasicAuthenticated;
     authscheme->configured = authBasicConfigured;
     authscheme->authFixHeader = authenticateBasicFixErrorHeader;
     authscheme->FreeUser = authenticateBasicFreeUser;
-    authscheme->freeconfig = authBasicFreeConfig;
     authscheme->authStart = authenticateBasicStart;
     authscheme->authStats = authenticateBasicStats;
     authscheme->authUserUsername = authenticateBasicUsername;
@@ -135,9 +223,10 @@
 static int
 authBasicConfigured()
 {
-    if ((basicConfig != NULL) && (basicConfig->authenticate != NULL) &&
-	(basicConfig->authenticateChildren != 0) &&
-	(basicConfig->basicAuthRealm != NULL)) {
+    if ((basicConfig.authenticate != NULL) &&
+	(basicConfig.authenticateChildren != 0) &&
+	(basicConfig.basicAuthRealm != NULL)) {
+	requirePathnameExists("authenticate_basic_program", basicConfig.authenticate->key);
 	debug(29, 9) ("authBasicConfigured: returning configured\n");
 	return 1;
     }
@@ -149,7 +238,7 @@
 authenticateBasicAuthenticated(auth_user_request_t * auth_user_request)
 {
     basic_data *basic_auth = auth_user_request->auth_user->scheme_data;
-    if ((auth_user_request->auth_user->flags.credentials_ok == 1) && (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL > squid_curtime))
+    if ((auth_user_request->auth_user->flags.credentials_ok == 1) && (basic_auth->credentials_checkedtime + basicConfig.credentialsTTL > squid_curtime))
 	return 1;
     debug(29, 4) ("User not authenticated or credentials need rechecking.\n");
     return 0;
@@ -182,7 +271,7 @@
     basic_auth = auth_user->scheme_data;
 
     /* are we about to recheck the credentials externally? */
-    if ((basic_auth->credentials_checkedtime + basicConfig->credentialsTTL) <= squid_curtime) {
+    if ((basic_auth->credentials_checkedtime + basicConfig.credentialsTTL) <= squid_curtime) {
 	debug(29, 4) ("authBasicAuthenticate: credentials expired - rechecking\n");
 	return;
     }
@@ -207,7 +296,7 @@
     case 0:			/* not checked */
 	return -1;
     case 1:			/* checked & ok */
-	if (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL <= squid_curtime)
+	if (basic_auth->credentials_checkedtime + basicConfig.credentialsTTL <= squid_curtime)
 	    return -1;
 	return 0;
     case 2:			/* paused while waiting for a username:password check on another request */
@@ -221,27 +310,12 @@
 void
 authenticateBasicFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
 {
-    if (basicConfig->authenticate) {
-	debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicConfig->basicAuthRealm);
-	httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicConfig->basicAuthRealm);
+    if (basicConfig.authenticate) {
+	debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicConfig.basicAuthRealm);
+	httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicConfig.basicAuthRealm);
     }
 }
 
-/* free any allocated configuration details */
-void
-authBasicFreeConfig(authScheme * scheme)
-{
-    if (basicConfig == NULL)
-	return;
-    assert(basicConfig == scheme->scheme_data);
-    if (basicConfig->authenticate)
-	wordlistDestroy(&basicConfig->authenticate);
-    if (basicConfig->basicAuthRealm)
-	safe_free(basicConfig->basicAuthRealm);
-    xfree(basicConfig);
-    basicConfig = NULL;
-}
-
 void
 authenticateBasicFreeUser(auth_user_t * auth_user)
 {
@@ -297,52 +371,6 @@
 }
 
 static void
-authBasicCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
-{
-    auth_basic_config *config = scheme->scheme_data;
-    wordlist *list = config->authenticate;
-    storeAppendPrintf(entry, "%s %s", name, "basic");
-    while (list != NULL) {
-	storeAppendPrintf(entry, " %s", list->key);
-	list = list->next;
-    }
-    storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s credentialsttl %d seconds\n",
-	name, "basic", config->basicAuthRealm,
-	name, "basic", config->authenticateChildren,
-	name, "basic", config->credentialsTTL);
-
-}
-
-static void
-authBasicParse(authScheme * scheme, int n_configured, char *param_str)
-{
-    if (scheme->scheme_data == NULL) {
-	assert(basicConfig == NULL);
-	/* this is the first param to be found */
-	scheme->scheme_data = xmalloc(sizeof(auth_basic_config));
-	memset(scheme->scheme_data, 0, sizeof(auth_basic_config));
-	basicConfig = scheme->scheme_data;
-	basicConfig->authenticateChildren = 5;
-	basicConfig->credentialsTTL = 2 * 60 * 60;	/* two hours */
-    }
-    basicConfig = scheme->scheme_data;
-    if (strcasecmp(param_str, "program") == 0) {
-	if (basicConfig->authenticate)
-	    wordlistDestroy(&basicConfig->authenticate);
-	parse_wordlist(&basicConfig->authenticate);
-	requirePathnameExists("authparam basic program", basicConfig->authenticate->key);
-    } else if (strcasecmp(param_str, "children") == 0) {
-	parse_int(&basicConfig->authenticateChildren);
-    } else if (strcasecmp(param_str, "realm") == 0) {
-	parse_eol(&basicConfig->basicAuthRealm);
-    } else if (strcasecmp(param_str, "credentialsttl") == 0) {
-	parse_time_t(&basicConfig->credentialsTTL);
-    } else {
-	debug(28, 0) ("unrecognised basic auth scheme parameter '%s'\n", param_str);
-    }
-}
-
-static void
 authenticateBasicStats(StoreEntry * sentry)
 {
     storeAppendPrintf(sentry, "Basic Authenticator Statistics:\n");
@@ -533,17 +561,17 @@
 /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
  * config file */
 static void
-authBasicInit(authScheme * scheme)
+authBasicInit(void)
 {
     static int init = 0;
-    if (basicConfig->authenticate) {
+    if (basicConfig.authenticate) {
 	if (!basic_data_pool)
 	    basic_data_pool = memPoolCreate("Basic Scheme User Data", sizeof(basic_data));
 	authbasic_initialised = 1;
 	if (basicauthenticators == NULL)
 	    basicauthenticators = helperCreate("basicauthenticator");
-	basicauthenticators->cmdline = basicConfig->authenticate;
-	basicauthenticators->n_to_start = basicConfig->authenticateChildren;
+	basicauthenticators->cmdline = basicConfig.authenticate;
+	basicauthenticators->n_to_start = basicConfig.authenticateChildren;
 	basicauthenticators->ipc_type = IPC_TCP_SOCKET;
 	helperOpenServers(basicauthenticators);
 	if (!init) {
@@ -570,7 +598,7 @@
     basic_auth = auth_user_request->auth_user->scheme_data;
     debug(29, 9) ("authenticateStart: '%s:%s'\n", basic_auth->username,
 	basic_auth->passwd);
-    if (basicConfig->authenticate == NULL) {
+    if (basicConfig.authenticate == NULL) {
 	handler(data, NULL);
 	return;
     }
Index: squid/src/auth/digest/auth_digest.c
diff -u squid/src/auth/digest/auth_digest.c:1.5 squid/src/auth/digest/auth_digest.c:1.4.4.6
--- squid/src/auth/digest/auth_digest.c:1.5	Sat Mar  3 02:44:33 2001
+++ squid/src/auth/digest/auth_digest.c	Sat Mar 31 01:52:20 2001
@@ -48,6 +48,9 @@
     cbdataFree(r);
 }
 
+/* register with the authentication framework */
+static AUTHSSETUP authSchemeSetup_digest;
+
 /* Digest Scheme */
 
 static HLPCB authenticateDigestHandleReply;
@@ -61,12 +64,9 @@
 static AUTHSCONFIGURED authDigestConfigured;
 static AUTHSDIRECTION authenticateDigestDirection;
 static AUTHSDECODE authenticateDigestDecodeAuth;
-static AUTHSDUMP authDigestCfgDump;
 static AUTHSFIXERR authenticateDigestFixHeader;
 static AUTHSFREE authenticateDigestUserFree;
-static AUTHSFREECONFIG authDigestFreeConfig;
 static AUTHSINIT authDigestInit;
-static AUTHSPARSE authDigestParse;
 static AUTHSREQFREE authDigestAURequestFree;
 static AUTHSSTART authenticateDigestStart;
 static AUTHSSTATS authenticateDigestStats;
@@ -77,7 +77,7 @@
 
 static hash_table *digest_nonce_cache;
 
-static auth_digest_config *digestConfig = NULL;
+static auth_digest_config digestConfig = { 0, NULL, NULL, 0, 0, 0};
 
 static int authdigest_initialised = 0;
 MemPool *digest_user_pool = NULL;
@@ -208,7 +208,7 @@
     if (!digest_nonce_cache) {
 	digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
 	assert(digest_nonce_cache);
-	eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1);
+	eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig.nonceGCInterval, 1);
     }
 }
 
@@ -268,7 +268,7 @@
     }
     debug(29, 3) ("authenticateDigestNonceCacheCleanup: Finished cleaning the nonce cache.\n");
     if (authenticateDigestActive())
-	eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1);
+	eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig.nonceGCInterval, 1);
 }
 
 void
@@ -354,8 +354,8 @@
     if (!nonce)
 	return -1;
     /* has it's max duration expired? */
-    if (nonce->noncedata.creationtime + digestConfig->noncemaxduration < current_time.tv_sec) {
-	debug(29, 4) ("authDigestNonceIsStale: Nonce is too old. %d %d %d\n", nonce->noncedata.creationtime, digestConfig->noncemaxduration, current_time.tv_sec);
+    if (nonce->noncedata.creationtime + digestConfig.noncemaxduration < current_time.tv_sec) {
+	debug(29, 4) ("authDigestNonceIsStale: Nonce is too old. %d %d %d\n", nonce->noncedata.creationtime, digestConfig.noncemaxduration, current_time.tv_sec);
 	nonce->flags.valid = 0;
 	return -1;
     }
@@ -364,7 +364,7 @@
 	nonce->flags.valid = 0;
 	return -1;
     }
-    if (nonce->nc > digestConfig->noncemaxuses) {
+    if (nonce->nc > digestConfig.noncemaxuses) {
 	debug(29, 4) ("authDigestNoncelastRequest: Nonce count over user limit\n");
 	nonce->flags.valid = 0;
 	return -1;
@@ -383,7 +383,7 @@
 	debug(29, 4) ("authDigestNoncelastRequest: Nonce count about to overflow\n");
 	return -1;
     }
-    if (nonce->nc == digestConfig->noncemaxuses - 1) {
+    if (nonce->nc == digestConfig.noncemaxuses - 1) {
 	debug(29, 4) ("authDigestNoncelastRequest: Nonce count about to hit user limit\n");
 	return -1;
     }
@@ -552,34 +552,116 @@
     debug(29, 2) ("authenticateDigestDone: Digest authentication shut down.\n");
 }
 
+/* register as a module */
+
+static void
+authDigestDocumentProgram(void)
+{
+    printf("#  TAG: authenticate_digest_program cmdline\n"
+"#\tSpecify the command for the external authenticator.  Such a\n"
+"#\tprogram reads a line containing \"username\":\"realm\" and replies\n"
+"#\twith the appropriate H(A1) value base64 encoded. See rfc 2616 for\n"
+"#\tthe definition of H(A1).  If you use an authenticator,\n"
+"#\tmake sure you have 1 acl of type proxy_auth.  By default,\n"
+"#\tauthentication is not used.\n"
+"#\n"
+"#\tIf you want to use build a authenticator,\n"
+"#\tjump over to the ../digest_auth_modules directory and choose the\n"
+"#\tauthenticator to use. It it's directory type\n"
+"#\t        %% make\n"
+"#\t        %% make install\n"
+"#\n"
+"#\tThen, set this line to something like\n"
+"#\n"
+"#\tauthenticate_digest_program @DEFAULT_PREFIX@/bin/digest_auth_pw @DEFAULT_PREFIX@/etc/digpass\n\n");
+}
+
+static void
+authBasicDocumentChildren(void)
+{
+    printf("#  TAG: authenticate_digest_children numberofchildren\n"
+"#\tThe number of authenticator processes to spawn (no default). If you\n"
+"#\tstart too few Squid will have to wait for them to process a backlog\n"
+"#\tof H(A1) calculations, slowing it down. When the H(A1) calculations\n"
+"#\tare done via a (slow) network you are likely to need lots of\n"
+"#\tauthenticator processes.\n"
+"#Default:\n"
+"# authenticate_digest_childrem 5\n\n");
+}
+
+static void
+authBasicDocumentRealm(void)
+{
+    printf("#  TAG: authenticate_digest_realm realmstring\n"
+"#\tSpecifies the realm name which is to be reported to the client for\n"
+"#\tthe digest proxy authentication scheme (part of the text the user will\n"
+"#\tsee when prompted their username and password).\n"
+"#\tauth_param digest realm Squid proxy-caching web server\n"
+"#Default:\n"
+"# authenticate_digest_realm Squid proxy-caching web server\n\n");
+}
+
+static void
+authBasicDocumentGCInterval(void)
+{
+    printf("#  TAG: authenticate_digest_nonce_garbage_interval interval\n"
+"#\tSpecifies the interval that nonces that have been issued to client_agent's\n"
+"#\tare checked for validity.\n"
+"#Default:\n"
+"# authenticate_digest_nonce_garbage_interval 5 minutes\n\n");
+}
+
+static void
+authBasicDocumentNonceDuration(void)
+{
+    printf("#  TAG: authenticate_digest_nonce_max_duration duration\n"
+"#\tSpecifies the maximum length of time a given nonce will be valid for.\n"
+"#Default:\n"
+"# authenticate_digest_nonce_max_duration 30 minutes\n\n");
+}
+
 static void
-authDigestCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
+authBasicDocumentNonceCount(void)
 {
-    auth_digest_config *config = scheme->scheme_data;
-    wordlist *list = config->authenticate;
-    debug(29, 9) ("authDigestCfgDump: Dumping configuration\n");
-    storeAppendPrintf(entry, "%s %s", name, "digest");
-    while (list != NULL) {
-	storeAppendPrintf(entry, " %s", list->key);
-	list = list->next;
-    }
-    storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s nonce_max_count %d\n%s %s nonce_max_duration %d seconds\n%s %s nonce_garbage_interval %d seconds\n",
-	name, "digest", config->digestAuthRealm,
-	name, "digest", config->authenticateChildren,
-	name, "digest", config->noncemaxuses,
-	name, "digest", config->noncemaxduration,
-	name, "digest", config->nonceGCInterval);
+    printf("#  TAG: authenticate_digest_nonce_max_count count\n"
+"#\tSpecifies the maximum number of times a given nonce can be used.\n"
+"#Default:\n"
+"# authenticate_digest_nonce_max_count 50\n\n");
 }
 
 void
+mod_install_digest (const char *namestr)
+{
+    authSchemeAdd(namestr, authSchemeSetup_digest);
+    parserRegisterName(NULL, "authenticate_digest_program", parserTypeByName("wordlist"), &digestConfig.authenticate, NULL, authDigestDocumentProgram, NULL);
+    parserRegisterName(NULL, "authenticate_digest_children", parserTypeByName("int"), &digestConfig.authenticateChildren, NULL, authBasicDocumentChildren, NULL);
+    parserRegisterName(NULL, "authenticate_digest_realm", parserTypeByName("eol"), &digestConfig.digestAuthRealm, NULL, authBasicDocumentRealm, NULL);
+    parserRegisterName(NULL, "authenticate_digest_nonce_garbage_interval", parserTypeByName("time_t"), &digestConfig.nonceGCInterval, NULL, authBasicDocumentGCInterval, NULL);
+    parserRegisterName(NULL, "authenticate_digest_nonce_max_duration", parserTypeByName("time_t"), &digestConfig.noncemaxduration, NULL, authBasicDocumentNonceDuration, NULL);
+    parserRegisterName(NULL, "authenticate_digest_nonce_max_count", parserTypeByName("int"), &digestConfig.noncemaxuses, NULL, authBasicDocumentNonceCount, NULL);
+
+    /* until we support mod_uninstall we need to keep the names active indefinately */
+    cbdataLock(parserNameByName("authenticate_digest_program"));
+    cbdataLock(parserNameByName("authenticate_digest_children"));
+    cbdataLock(parserNameByName("authenticate_digest_realm"));
+    cbdataLock(parserNameByName("authenticate_digest_nonce_garbage_interval"));
+    cbdataLock(parserNameByName("authenticate_digest_nonce_max_duration"));
+    cbdataLock(parserNameByName("authenticate_digest_nonce_max_count"));
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_digest(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
+
+static void
 authSchemeSetup_digest(authscheme_entry_t * authscheme)
 {
     assert(!authdigest_initialised);
     authscheme->Active = authenticateDigestActive;
     authscheme->configured = authDigestConfigured;
-    authscheme->parse = authDigestParse;
-    authscheme->freeconfig = authDigestFreeConfig;
-    authscheme->dump = authDigestCfgDump;
     authscheme->init = authDigestInit;
     authscheme->authAuthenticate = authenticateDigestAuthenticateUser;
     authscheme->authenticated = authDigestAuthenticated;
@@ -607,10 +689,12 @@
 int
 authDigestConfigured()
 {
-    if ((digestConfig != NULL) && (digestConfig->authenticate != NULL) &&
-	(digestConfig->authenticateChildren != 0) &&
-	(digestConfig->digestAuthRealm != NULL) && (digestConfig->noncemaxduration > -1))
+    if ((digestConfig.authenticate != NULL) &&
+	(digestConfig.authenticateChildren != 0) &&
+	(digestConfig.digestAuthRealm != NULL) && (digestConfig.noncemaxduration > -1)) {
+	requirePathnameExists("authenticate_digest_program", digestConfig.authenticate->key);
 	return 1;
+    }
     return 0;
 }
 
@@ -733,7 +817,7 @@
 	return;
 #endif
 
-    if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) {
+    if ((digestConfig.authenticate) && authDigestNonceLastRequest(digest_request->nonce)) {
 	digest_request->flags.authinfo_sent = 1;
 	debug(29, 9) ("authDigestAddHead: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce));
 	httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce));
@@ -759,7 +843,7 @@
 	return;
     type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
 
-    if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) {
+    if ((digestConfig.authenticate) && authDigestNonceLastRequest(digest_request->nonce)) {
 	debug(29, 9) ("authDigestAddTrailer: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce));
 	httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce));
     }
@@ -777,10 +861,10 @@
 	digest_request = auth_user_request->scheme_data;
 	stale = authDigestNonceIsStale(digest_request->nonce);
     }
-    if (digestConfig->authenticate) {
-	debug(29, 9) ("authenticateFixHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s\n", type, digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false");
+    if (digestConfig.authenticate) {
+	debug(29, 9) ("authenticateFixHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s\n", type, digestConfig.digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false");
 	/* in the future, for WWW auth we may want to support the domain entry */
-	httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s", digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false");
+	httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s", digestConfig.digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false");
     }
 }
 
@@ -845,18 +929,18 @@
 /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
  * config file */
 static void
-authDigestInit(authScheme * scheme)
+authDigestInit(void)
 {
     static int init = 0;
-    if (digestConfig->authenticate) {
+    if (digestConfig.authenticate) {
 	authDigestUserSetup();
 	authDigestRequestSetup();
 	authenticateDigestNonceSetup();
 	authdigest_initialised = 1;
 	if (digestauthenticators == NULL)
 	    digestauthenticators = helperCreate("digestauthenticator");
-	digestauthenticators->cmdline = digestConfig->authenticate;
-	digestauthenticators->n_to_start = digestConfig->authenticateChildren;
+	digestauthenticators->cmdline = digestConfig.authenticate;
+	digestauthenticators->n_to_start = digestConfig.authenticateChildren;
 	digestauthenticators->ipc_type = IPC_TCP_SOCKET;
 	helperOpenServers(digestauthenticators);
 	if (!init) {
@@ -868,61 +952,6 @@
     }
 }
 
-
-/* free any allocated configuration details */
-void
-authDigestFreeConfig(authScheme * scheme)
-{
-    if (digestConfig == NULL)
-	return;
-    assert(digestConfig == scheme->scheme_data);
-    if (digestConfig->authenticate)
-	wordlistDestroy(&digestConfig->authenticate);
-    if (digestConfig->digestAuthRealm)
-	safe_free(digestConfig->digestAuthRealm);
-    xfree(digestConfig);
-    digestConfig = NULL;
-}
-
-static void
-authDigestParse(authScheme * scheme, int n_configured, char *param_str)
-{
-    if (scheme->scheme_data == NULL) {
-	assert(digestConfig == NULL);
-	/* this is the first param to be found */
-	scheme->scheme_data = xmalloc(sizeof(auth_digest_config));
-	memset(scheme->scheme_data, 0, sizeof(auth_digest_config));
-	digestConfig = scheme->scheme_data;
-	digestConfig->authenticateChildren = 5;
-	/* 5 minutes */
-	digestConfig->nonceGCInterval = 5 * 60;
-	/* 30 minutes */
-	digestConfig->noncemaxduration = 30 * 60;
-	/* 50 requests */
-	digestConfig->noncemaxuses = 50;
-    }
-    digestConfig = scheme->scheme_data;
-    if (strcasecmp(param_str, "program") == 0) {
-	if (digestConfig->authenticate)
-	    wordlistDestroy(&digestConfig->authenticate);
-	parse_wordlist(&digestConfig->authenticate);
-	requirePathnameExists("authparam digest program", digestConfig->authenticate->key);
-    } else if (strcasecmp(param_str, "children") == 0) {
-	parse_int(&digestConfig->authenticateChildren);
-    } else if (strcasecmp(param_str, "realm") == 0) {
-	parse_eol(&digestConfig->digestAuthRealm);
-    } else if (strcasecmp(param_str, "nonce_garbage_interval") == 0) {
-	parse_time_t(&digestConfig->nonceGCInterval);
-    } else if (strcasecmp(param_str, "nonce_max_duration") == 0) {
-	parse_time_t(&digestConfig->noncemaxduration);
-    } else if (strcasecmp(param_str, "nonce_max_count") == 0) {
-	parse_int(&digestConfig->noncemaxuses);
-    } else {
-	debug(28, 0) ("unrecognised digest auth scheme parameter '%s'\n", param_str);
-    }
-}
-
-
 static void
 authenticateDigestStats(StoreEntry * sentry)
 {
@@ -1309,7 +1338,7 @@
     digest_user = auth_user_request->auth_user->scheme_data;
     debug(29, 9) ("authenticateStart: '\"%s\":\"%s\"'\n", digest_user->username,
 	digest_request->realm);
-    if (digestConfig->authenticate == NULL) {
+    if (digestConfig.authenticate == NULL) {
 	handler(data, NULL);
 	return;
     }
Index: squid/src/auth/ntlm/auth_ntlm.c
diff -u squid/src/auth/ntlm/auth_ntlm.c:1.9 squid/src/auth/ntlm/auth_ntlm.c:1.7.6.7
--- squid/src/auth/ntlm/auth_ntlm.c:1.9	Fri Mar  9 16:58:00 2001
+++ squid/src/auth/ntlm/auth_ntlm.c	Sat Mar 31 03:07:23 2001
@@ -47,6 +47,9 @@
     cbdataFree(r);
 }
 
+/* register with the authentication framework */
+static AUTHSSETUP authSchemeSetup_ntlm;
+
 /* NTLM Scheme */
 static HLPSCB authenticateNTLMHandleReply;
 static HLPSCB authenticateNTLMHandleplaceholder;
@@ -58,13 +61,10 @@
 static AUTHSFREE authenticateNTLMFreeUser;
 static AUTHSDIRECTION authenticateNTLMDirection;
 static AUTHSDECODE authenticateDecodeNTLMAuth;
-static AUTHSDUMP authNTLMCfgDump;
-static AUTHSFREECONFIG authNTLMFreeConfig;
 static AUTHSINIT authNTLMInit;
 static AUTHSONCLOSEC authenticateNTLMOnCloseConnection;
 static AUTHSUSERNAME authenticateNTLMUsername;
 static AUTHSREQFREE authNTLMAURequestFree;
-static AUTHSPARSE authNTLMParse;
 static AUTHSSTART authenticateNTLMStart;
 static AUTHSSTATS authenticateNTLMStats;
 static AUTHSSHUTDOWN authNTLMDone;
@@ -82,10 +82,98 @@
 MemPool *ntlm_helper_state_pool = NULL;
 MemPool *ntlm_user_pool = NULL;
 MemPool *ntlm_request_pool = NULL;
-static auth_ntlm_config *ntlmConfig = NULL;
+static auth_ntlm_config ntlmConfig = { 0, NULL, 0, 0 };
 
 static hash_table *proxy_auth_cache = NULL;
 
+/* 
+ * Module support 
+ */
+
+/* parse functions */
+
+static void
+authNTLMDocumentProgram(void)
+{
+    printf("#  TAG: authenticate_ntlm_program cmdline\n"
+"#\tSpecify the command for the external ntlm authenticator.  Such a\n"
+"#\tprogram reads a line containing the uuencoded NEGOTIATE and replies\n"
+"#\twith the ntlm CHALLENGE, then waits for the response and answers with\n"
+"#\t\"OK\" or \"ERR\" in an endless loop.  If you use an ntlm authenticator,\n"
+"#\tmake sure you have 1 acl of type proxy_auth.  By default, the\n"
+"#\tntlm authenticator_program is not used.\n"
+"#\n"
+"#\tauth_param ntlm program /usr/local/squid/bin/ntlm_auth\n\n");
+}
+
+static void
+authNTLMDocumentChildren(void)
+{
+    printf("#  TAG: authenticate_ntlm_children children\n"
+"#\tThe number of authenticator processes to spawn (no default). If you\n"
+"#\tstart too few Squid will have to wait for them to process a backlog\n"
+"#\tof credential verifications, slowing it down. When crendential\n"
+"#\tverifications are done via a (slow) network you are likely to need\n"
+"#\tlots of authenticator processes.\n"
+"#Default:\n"
+"# authenticate_ntlm_children 5\n\n");
+}
+
+static void
+authNTLMDocumentChallengeUses(void)
+{
+    printf("#  TAG: authenticate_ntlm_max_challenge_reuses reusecount\n"
+"#\tThe maximum number of times a challenge given by a ntlm authentication\n"
+"#\thelper can be reused. Increasing this number increases your exposure\n"
+"#\tto replay attacks on your network. 0 means use the challenge only once.\n"
+"#\t(disable challenge caching)\n"
+"#\tSee max_ntlm_challenge_lifetime for more information.\n"
+"#Default:\n"
+"# authenticate_ntlm_max_challenge_reuses 0\n\n");
+}
+
+static void
+authNTLMDocumentChallengeLifetime(void)
+{
+    printf("#  TAG: authenticate_ntlm_max_challenge_lifetime lifetime\n"
+"#\tThe maximum time period that a ntlm challenge is reused over.\n"
+"#\tThe actual period will be the minimum of this time AND the number of\n"
+"#\treused challenges.\n"
+"#Default:\n"
+"# authenticate_ntlm_max_challenge_lifetime 2 minutes\n\n");
+}
+
+/* register as a module */
+void
+mod_install_ntlm (const char *namestr)
+{
+    authSchemeAdd(namestr, authSchemeSetup_ntlm);
+    parserRegisterName(NULL, "authenticate_ntlm_program", parserTypeByName("wordlist"), &ntlmConfig.authenticate, NULL, authNTLMDocumentProgram, NULL);
+    parserRegisterName(NULL, "authenticate_ntlm_children", parserTypeByName("int"), &ntlmConfig.authenticateChildren, NULL, authNTLMDocumentChildren, NULL);
+    default_line("authenticate_ntlm_children 5");
+    parserRegisterName(NULL, "authenticate_ntlm_max_challenge_reuses", parserTypeByName("int"), &ntlmConfig.challengeuses, NULL, authNTLMDocumentChallengeUses, NULL);
+    default_line("authenticate_ntlm_max_challenge_reuses 0");
+    parserRegisterName(NULL, "authenticate_ntlm_max_challenge_lifetime", parserTypeByName("time_t"), &ntlmConfig.challengelifetime, NULL, authNTLMDocumentChallengeLifetime, NULL);
+    default_line("authenticate_ntlm_max_challenge_lifetime 2 minutes");
+
+    /* until we support mod_uninstall we need to keep the names active indefinately */
+    cbdataLock(parserNameByName("authenticate_ntlm_program"));
+    cbdataLock(parserNameByName("authenticate_ntlm_children"));
+    cbdataLock(parserNameByName("authenticate_max_challenge_reuses"));
+    cbdataLock(parserNameByName("authenticate_max_challenge_lifetime"));
+}
+
+
+
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_ntlm(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
+
+
 /*
  *
  * Private Functions
@@ -122,77 +210,13 @@
     debug(29, 2) ("authNTLMDone: NTLM authentication Shutdown.\n");
 }
 
-/* free any allocated configuration details */
-void
-authNTLMFreeConfig(authScheme * scheme)
-{
-    if (ntlmConfig == NULL)
-	return;
-    assert(ntlmConfig == scheme->scheme_data);
-    if (ntlmConfig->authenticate)
-	wordlistDestroy(&ntlmConfig->authenticate);
-    xfree(ntlmConfig);
-    ntlmConfig = NULL;
-}
-
 static void
-authNTLMCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
-{
-    auth_ntlm_config *config = scheme->scheme_data;
-    wordlist *list = config->authenticate;
-    storeAppendPrintf(entry, "%s %s", name, "ntlm");
-    while (list != NULL) {
-	storeAppendPrintf(entry, " %s", list->key);
-	list = list->next;
-    }
-    storeAppendPrintf(entry, "\n%s %s children %d\n%s %s max_challenge_reuses %d\n%s %s max_challenge_lifetime %d seconds\n",
-	name, "ntlm", config->authenticateChildren,
-	name, "ntlm", config->challengeuses,
-	name, "ntlm", config->challengelifetime);
-
-}
-
-static void
-authNTLMParse(authScheme * scheme, int n_configured, char *param_str)
-{
-    if (scheme->scheme_data == NULL) {
-	assert(ntlmConfig == NULL);
-	/* this is the first param to be found */
-	scheme->scheme_data = xmalloc(sizeof(auth_ntlm_config));
-	memset(scheme->scheme_data, 0, sizeof(auth_ntlm_config));
-	ntlmConfig = scheme->scheme_data;
-	ntlmConfig->authenticateChildren = 5;
-	ntlmConfig->challengeuses = 0;
-	ntlmConfig->challengelifetime = 60;
-    }
-    ntlmConfig = scheme->scheme_data;
-    if (strcasecmp(param_str, "program") == 0) {
-	if (ntlmConfig->authenticate)
-	    wordlistDestroy(&ntlmConfig->authenticate);
-	parse_wordlist(&ntlmConfig->authenticate);
-	requirePathnameExists("authparam ntlm program", ntlmConfig->authenticate->key);
-    } else if (strcasecmp(param_str, "children") == 0) {
-	parse_int(&ntlmConfig->authenticateChildren);
-    } else if (strcasecmp(param_str, "max_challenge_reuses") == 0) {
-	parse_int(&ntlmConfig->challengeuses);
-    } else if (strcasecmp(param_str, "max_challenge_lifetime") == 0) {
-	parse_time_t(&ntlmConfig->challengelifetime);
-    } else {
-	debug(28, 0) ("unrecognised ntlm auth scheme parameter '%s'\n", param_str);
-    }
-}
-
-
-void
 authSchemeSetup_ntlm(authscheme_entry_t * authscheme)
 {
     assert(!authntlm_initialised);
     authscheme->Active = authenticateNTLMActive;
     authscheme->configured = authNTLMConfigured;
-    authscheme->parse = authNTLMParse;
-    authscheme->dump = authNTLMCfgDump;
     authscheme->requestFree = authNTLMAURequestFree;
-    authscheme->freeconfig = authNTLMFreeConfig;
     authscheme->init = authNTLMInit;
     authscheme->authAuthenticate = authenticateNTLMAuthenticateUser;
     authscheme->authenticated = authNTLMAuthenticated;
@@ -210,10 +234,10 @@
 /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
  * config file */
 static void
-authNTLMInit(authScheme * scheme)
+authNTLMInit(void)
 {
     static int ntlminit = 0;
-    if (ntlmConfig->authenticate) {
+    if (ntlmConfig.authenticate) {
 	if (!ntlm_helper_state_pool)
 	    ntlm_helper_state_pool = memPoolCreate("NTLM Helper State data", sizeof(ntlm_helper_state_t));
 	if (!ntlm_user_pool)
@@ -226,8 +250,8 @@
 	if (!proxy_auth_cache)
 	    proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
 	assert(proxy_auth_cache);
-	ntlmauthenticators->cmdline = ntlmConfig->authenticate;
-	ntlmauthenticators->n_to_start = ntlmConfig->authenticateChildren;
+	ntlmauthenticators->cmdline = ntlmConfig.authenticate;
+	ntlmauthenticators->n_to_start = ntlmConfig.authenticateChildren;
 	ntlmauthenticators->ipc_type = IPC_TCP_SOCKET;
 	ntlmauthenticators->datapool = ntlm_helper_state_pool;
 	ntlmauthenticators->IsAvailable = authenticateNTLMHelperServerAvailable;
@@ -253,7 +277,10 @@
 int
 authNTLMConfigured()
 {
-    if ((ntlmConfig != NULL) && (ntlmConfig->authenticate != NULL) && (ntlmConfig->authenticateChildren != 0) && (ntlmConfig->challengeuses > -1) && (ntlmConfig->challengelifetime > -1)) {
+    if ((ntlmConfig.authenticate != NULL) &&
+	(ntlmConfig.authenticateChildren != 0) && (ntlmConfig.challengeuses > -1)
+	&& (ntlmConfig.challengelifetime > -1)) {
+	requirePathnameExists("authenticate_ntlm_program", ntlmConfig.authenticate->key);
 	debug(29, 9) ("authNTLMConfigured: returning configured\n");
 	return 1;
     }
@@ -292,7 +319,7 @@
 authenticateNTLMFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
 {
     ntlm_request_t *ntlm_request;
-    if (ntlmConfig->authenticate) {
+    if (ntlmConfig.authenticate) {
 	/* New request, no user details */
 	if (auth_user_request == NULL) {
 	    debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type);
@@ -605,12 +632,12 @@
 	debug(29, 5) ("authenticateNTLMChangeChallenge: first use\n");
 	return 0;
     }
-    if (helperstate->challengeuses > ntlmConfig->challengeuses) {
-	debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge uses (%d) exceeded max uses (%d)\n", helperstate->challengeuses, ntlmConfig->challengeuses);
+    if (helperstate->challengeuses > ntlmConfig.challengeuses) {
+	debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge uses (%d) exceeded max uses (%d)\n", helperstate->challengeuses, ntlmConfig.challengeuses);
 	return 1;
     }
-    if (helperstate->renewed + ntlmConfig->challengelifetime < squid_curtime) {
-	debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge exceeded max lifetime by %d seconds\n", squid_curtime - (helperstate->renewed + ntlmConfig->challengelifetime));
+    if (helperstate->renewed + ntlmConfig.challengelifetime < squid_curtime) {
+	debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge exceeded max lifetime by %d seconds\n", squid_curtime - (helperstate->renewed + ntlmConfig.challengelifetime));
 	return 1;
     }
     debug(29, 9) ("Challenge is to be reused\n");
@@ -661,7 +688,7 @@
 
     debug(29, 9) ("authenticateNTLMStart: state '%d'\n", ntlm_request->auth_state);
     debug(29, 9) ("authenticateNTLMStart: '%s'\n", sent_string);
-    if (ntlmConfig->authenticate == NULL) {
+    if (ntlmConfig.authenticate == NULL) {
 	debug(29, 0) ("authenticateNTLMStart: no NTLM program specified:'%s'\n", sent_string);
 	handler(data, NULL);
 	return;
Index: squid/src/fs/aufs/store_dir_aufs.c
diff -u squid/src/fs/aufs/store_dir_aufs.c:1.18 squid/src/fs/aufs/store_dir_aufs.c:1.13.4.5
--- squid/src/fs/aufs/store_dir_aufs.c:1.18	Tue May  8 08:27:00 2001
+++ squid/src/fs/aufs/store_dir_aufs.c	Sat May 12 06:06:03 2001
@@ -118,8 +118,22 @@
 static void storeAufsDirInitBitmap(SwapDir *);
 static int storeAufsDirValidFileno(SwapDir *, sfileno, int);
 
-/* The MAIN externally visible function */
-STSETUP storeFsSetup_aufs;
+static STSETUP storeFsSetup_aufs;
+
+/* register as a module
+ */
+void
+mod_install_aufs (const char *namestr)
+{
+    storeFsAdd(namestr, storeFsSetup_aufs);
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_aufs(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
 
 /*
  * These functions were ripped straight out of the heart of store_dir.c.
@@ -1697,7 +1711,7 @@
     asyncufs_initialised = 0;
 }
 
-void
+static void
 storeFsSetup_aufs(storefs_entry_t * storefs)
 {
     assert(!asyncufs_initialised);
Index: squid/src/fs/coss/store_dir_coss.c
diff -u squid/src/fs/coss/store_dir_coss.c:1.13 squid/src/fs/coss/store_dir_coss.c:1.10.4.4
--- squid/src/fs/coss/store_dir_coss.c:1.13	Tue May  8 08:35:26 2001
+++ squid/src/fs/coss/store_dir_coss.c	Sat May 12 06:06:26 2001
@@ -87,8 +87,22 @@
 static STFSRECONFIGURE storeCossDirReconfigure;
 static STDUMP storeCossDirDump;
 
-/* The "only" externally visible function */
-STSETUP storeFsSetup_coss;
+static STSETUP storeFsSetup_coss;
+
+/* register as a module
+ */
+void
+mod_install_coss (const char *namestr)
+{
+    storeFsAdd(namestr, storeFsSetup_coss);
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_coss(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
 
 static char *
 storeCossDirSwapLogFile(SwapDir * sd, const char *ext)
@@ -851,7 +865,7 @@
     coss_initialised = 0;
 }
 
-void
+static void
 storeFsSetup_coss(storefs_entry_t * storefs)
 {
     assert(!coss_initialised);
Index: squid/src/fs/diskd/store_dir_diskd.c
diff -u squid/src/fs/diskd/store_dir_diskd.c:1.23 squid/src/fs/diskd/store_dir_diskd.c:1.14.4.6
--- squid/src/fs/diskd/store_dir_diskd.c:1.23	Tue May  8 08:27:01 2001
+++ squid/src/fs/diskd/store_dir_diskd.c	Sat May 12 06:06:26 2001
@@ -128,8 +128,22 @@
 static void storeDiskdStats(StoreEntry * sentry);
 static void storeDiskdDirSync(SwapDir *);
 
-/* The only externally visible interface */
-STSETUP storeFsSetup_diskd;
+static STSETUP storeFsSetup_diskd;
+
+/* register as a module
+ */
+void
+mod_install_diskd (const char *namestr)
+{
+    storeFsAdd(namestr, storeFsSetup_diskd);
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_diskd(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
 
 /*
  * These functions were ripped straight out of the heart of store_dir.c.
@@ -1940,7 +1954,7 @@
     diskd_initialised = 0;
 }
 
-void
+static void
 storeFsSetup_diskd(storefs_entry_t * storefs)
 {
     assert(!diskd_initialised);
Index: squid/src/fs/null/store_null.c
diff -u squid/src/fs/null/store_null.c:1.2 squid/src/fs/null/store_null.c:1.2.6.2
--- squid/src/fs/null/store_null.c:1.2	Sat Feb 10 08:49:07 2001
+++ squid/src/fs/null/store_null.c	Thu Feb 15 14:29:25 2001
@@ -49,8 +49,22 @@
 static STLOGCLEANDONE storeNullDirWriteCleanDone;
 static EVH storeNullDirRebuildComplete;
 
-/* The only externally visible interface */
-STSETUP storeFsSetup_null;
+static STSETUP storeFsSetup_null;
+
+/* register as a module
+ */
+void
+mod_install_null (const char *namestr)
+{
+    storeFsAdd(namestr, storeFsSetup_null);
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_null(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
 
 static void
 storeNullDirReconfigure(SwapDir * sd, int index, char *path)
@@ -118,7 +132,7 @@
 
 /* Setup and register the store module */
 
-void
+static void
 storeFsSetup_null(storefs_entry_t * storefs)
 {
     assert(!null_initialised);
Index: squid/src/fs/ufs/store_dir_ufs.c
diff -u squid/src/fs/ufs/store_dir_ufs.c:1.17 squid/src/fs/ufs/store_dir_ufs.c:1.12.4.5
--- squid/src/fs/ufs/store_dir_ufs.c:1.17	Tue May  8 08:27:01 2001
+++ squid/src/fs/ufs/store_dir_ufs.c	Sat May 12 06:06:26 2001
@@ -116,7 +116,22 @@
 static void storeUfsDirInitBitmap(SwapDir *);
 static int storeUfsDirValidFileno(SwapDir *, sfileno, int);
 
-STSETUP storeFsSetup_ufs;
+static STSETUP storeFsSetup_ufs;
+
+/* register as a module
+ */
+void
+mod_install_ufs (const char *namestr)
+{
+    storeFsAdd(namestr, storeFsSetup_ufs);
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_ufs(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
 
 /*
  * These functions were ripped straight out of the heart of store_dir.c.
@@ -1676,7 +1691,7 @@
     ufs_initialised = 0;
 }
 
-void
+static void
 storeFsSetup_ufs(storefs_entry_t * storefs)
 {
     assert(!ufs_initialised);
Index: squid/src/modules/Makefile.in
diff -u /dev/null squid/src/modules/Makefile.in:1.1.6.1
--- /dev/null	Tue Sep 28 18:36:02 2004
+++ squid/src/modules/Makefile.in	Wed Feb 14 05:51:42 2001
@@ -0,0 +1,36 @@
+#  Makefile for modules in the Squid Object Cache server
+#
+#  $Id$
+#
+
+SUBDIRS		= @CONF_MODULES@
+OUTLIBS		= @CONF_MODULE_LIBS@
+
+all install:
+	@test -z "$(SUBDIRS)" || for dir in $(SUBDIRS); do \
+           sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1; \
+        done; 
+
+$(OUTLIBS):
+	@sh -c "cd `basename $@ .a` && $(MAKE) $(MFLAGS) ../$@"
+
+clean:
+	-rm -f *.a stamp
+	-for dir in *; do \
+            if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1;\
+            fi; \
+        done
+
+distclean:
+	-rm -f *.a Makefile
+	-for dir in *; do \
+            if [ -f $$dir/Makefile ]; then \
+                sh -c "cd $$dir && $(MAKE) $(MFLAGS) distclean"; \
+            fi; \
+        done
+
+.DEFAULT:
+	@test -z "$(SUBDIRS)" || for dir in $(SUBDIRS); do \
+           sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1; \
+        done
Index: squid/src/modules/acl_arp/Makefile.in
diff -u /dev/null squid/src/modules/acl_arp/Makefile.in:1.1.2.1
--- /dev/null	Tue Sep 28 18:36:02 2004
+++ squid/src/modules/acl_arp/Makefile.in	Fri Apr 27 01:30:04 2001
@@ -0,0 +1,70 @@
+#
+#  Makefile for the ntlm authentication scheme module for the Squid Object Cache server
+#
+#  $Id$
+#
+
+MODULE		= acl_arp
+
+#SUBDIRS		= helpers
+
+top_srcdir	= @top_srcdir@
+VPATH		= @srcdir@
+
+CC		= @CC@
+MAKEDEPEND	= @MAKEDEPEND@
+AR_R		= @AR_R@
+RANLIB		= @RANLIB@
+AC_CFLAGS	= @CFLAGS@
+SHELL		= /bin/sh
+
+INCLUDE		= -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/
+CFLAGS 		= $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+
+OUT		= ../$(MODULE).a
+
+OBJS	 	= \
+		acl_arp.o
+
+
+all install: $(OUT)
+	@for dir in $(SUBDIRS); do \
+	    if [ -f $$dir/Makefile ]; then \
+	        sh -c "cd $$dir && $(MAKE) $@" || exit 1; \
+	    fi; \
+	done;
+
+$(OUT): $(OBJS)
+	@rm -f ../stamp
+	$(AR_R) $(OUT) $(OBJS)
+	$(RANLIB) $(OUT)
+
+$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h
+
+.c.o:
+	@rm -f ../stamp
+	$(CC) $(CFLAGS) -c $<
+
+clean: 
+	-rm -rf *.o *pure_* core ../$(MODULE).a
+	-for dir in *; do \
+	    if [ -f $$dir/Makefile ]; then \
+	        sh -c "cd $$dir && $(MAKE) clean"; \
+	    fi; \
+	done
+
+distclean:	clean
+	-rm -f Makefile
+	-rm -f Makefile.bak
+	-rm -f tags
+	-for dir in *; do \
+	    if [ -f $$dir/Makefile ]; then \
+	        sh -c "cd $$dir && $(MAKE) distclean"; \
+	    fi; \
+	done
+
+tags:
+	ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch]
+
+depend:
+	$(MAKEDEPEND) $(INCLUDE) -fMakefile *.c
Index: squid/src/modules/acl_arp/acl_arp.c
diff -u /dev/null squid/src/modules/acl_arp/acl_arp.c:1.1.2.1
--- /dev/null	Tue Sep 28 18:36:02 2004
+++ squid/src/modules/acl_arp/acl_arp.c	Fri Apr 27 01:30:04 2001
@@ -0,0 +1,487 @@
+
+/*
+ * $Id$
+ *
+ * DEBUG: section 28    ACL
+ * AUTHOR: Several
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "squid_parser.h"
+#include "acl.h"
+
+struct _acl_arp_data {
+    char eth[6];
+};
+
+
+static PARSER_PARSE aclParseArpList;
+static PARSER_FREE  aclDestroyArpList;
+static PARSER_DUMP  dump_ArpList;
+static ACLMATCH     aclMatchSrcArp;
+static int decode_eth(const char *asc, char *eth);
+static int aclMatchArp(void *dataptr, struct in_addr c);
+static wordlist *aclDumpArpList(void *);
+static SPLAYCMP aclArpCompare;
+static SPLAYWALKEE aclDumpArpListWalkee;
+
+/* register as a module */
+void
+mod_install_acl_arp (const char *namestr)
+{
+    parserRegisterType("arplist", aclParseArpList, aclDestroyArpList, dump_ArpList);
+    aclRegisterAclName("arp", parserTypeByName("arplist"), aclMatchSrcArp);	
+  /* Register global configuration parameters */
+}
+
+/* deregister as a module */
+void
+mod_uninstall_acl_arp(const char *namestr) {
+    /* Deregister global configurationparameters */
+//FIXME:    aclDeregisterAclName("arp");
+//FIXME:    parserDeregisterName("arplist");
+
+}
+
+
+/* ==== BEGIN ARP ACL SUPPORT ============================================= */
+
+/*
+ * From:    dale@server.ctam.bitmcnit.bryansk.su (Dale)
+ * To:      wessels@nlanr.net
+ * Subject: Another Squid patch... :)
+ * Date:    Thu, 04 Dec 1997 19:55:01 +0300
+ * ============================================================================
+ *
+ * Working on setting up a proper firewall for a network containing some
+ * Win'95 computers at our Univ, I've discovered that some smart students
+ * avoid the restrictions easily just changing their IP addresses in Win'95
+ * Contol Panel... It has been getting boring, so I took Squid-1.1.18
+ * sources and added a new acl type for hard-wired access control:
+ *
+ * acl <name> arp <Ethernet address> ...
+ *
+ * For example,
+ *
+ * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38
+ *
+ * NOTE: Linux code by David Luyer <luyer@ucs.uwa.edu.au>.
+ *       Original (BSD-specific) code no longer works.
+ *       Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
+ */
+
+#ifdef _SQUID_SOLARIS_
+#include <sys/sockio.h>
+#else
+#include <sys/sysctl.h>
+#endif
+#ifdef _SQUID_LINUX_
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#else
+#include <net/if_dl.h>
+#endif
+#include <net/route.h>
+#include <net/if.h>
+#if HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
+
+/*
+ * Decode an ascii representation (asc) of an ethernet adress, and place
+ * it in eth[6].
+ */
+static int
+decode_eth(const char *asc, char *eth)
+{
+    int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
+    if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) {
+        debug(28, 0) ("decode_eth: Invalid ethernet address '%s'\n", asc);
+        return 0;               /* This is not valid address */
+    }
+    eth[0] = (u_char) a1;
+    eth[1] = (u_char) a2;
+    eth[2] = (u_char) a3;
+    eth[3] = (u_char) a4;
+    eth[4] = (u_char) a5;
+    eth[5] = (u_char) a6;
+    return 1;
+}
+
+static acl_arp_data *
+aclParseArpData(const char *t)
+{
+    LOCAL_ARRAY(char, eth, 256);
+    acl_arp_data *q = xcalloc(1, sizeof(acl_arp_data));
+    debug(28, 5) ("aclParseArpData: %s\n", t);
+    if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) {
+        debug(28, 0) ("aclParseArpData: Bad ethernet address: '%s'\n", t);
+        safe_free(q);
+        return NULL;
+    }
+    if (!decode_eth(eth, q->eth)) {
+        debug(28, 0) ("%s line %d: %s\n",
+            cfg_filename, config_lineno, config_input_line);
+        debug(28, 0) ("aclParseArpData: Ignoring invalid ARP acl entry: can't parse '%s'\n", eth);
+        safe_free(q);
+        return NULL;
+    }
+    return q;
+}
+
+
+/*******************/
+/* aclParseArpList */
+/*******************/
+static void
+aclParseArpList(parserNameNode *parserName, void *curlist)
+{
+    char *t = NULL;
+    splayNode **Top = curlist;
+    acl_arp_data *q = NULL;
+    while ((t = strtokFile())) {
+        if ((q = aclParseArpData(t)) == NULL)
+            continue;
+        *Top = splay_insert(q, *Top, aclArpCompare);
+    }
+}
+
+/***************/
+/* aclMatchArp */
+/***************/
+static int
+aclMatchArp(void *dataptr, struct in_addr c)
+{
+#if defined(_SQUID_LINUX_)
+    struct arpreq arpReq;
+    struct sockaddr_in ipAddr;
+    unsigned char ifbuffer[sizeof(struct ifreq) * 64];
+    struct ifconf ifc;
+    struct ifreq *ifr;
+    int offset;
+    splayNode **Top = dataptr;
+    /*
+     * The linux kernel 2.2 maintains per interface ARP caches and
+     * thus requires an interface name when doing ARP queries.
+     *
+     * The older 2.0 kernels appear to use a unified ARP cache,
+     * and require an empty interface name
+     *
+     * To support both, we attempt the lookup with a blank interface
+     * name first. If that does not succeed, the try each interface
+     * in turn
+     */
+    /*
+     * Set up structures for ARP lookup with blank interface name
+     */
+    ipAddr.sin_family = AF_INET;
+    ipAddr.sin_port = 0;
+    ipAddr.sin_addr = c;
+    memset(&arpReq, '\0', sizeof(arpReq));
+    xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
+    /* Query ARP table */
+    if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
+        /* Skip non-ethernet interfaces */
+        if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
+            return 0;
+        }
+        debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
+            arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
+            arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
+            arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
+        /* Do lookup */
+        *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
+        debug(28, 3) ("aclMatchArp: '%s' %s\n",
+            inet_ntoa(c), splayLastResult ? "NOT found" : "found");
+        return (0 == splayLastResult);
+    }
+    /* lookup list of interface names */
+    ifc.ifc_len = sizeof(ifbuffer);
+    ifc.ifc_buf = ifbuffer;
+    if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) {
+        debug(28, 1) ("Attempt to retrieve interface list failed: %s\n",
+            xstrerror());
+        return 0;
+    }
+    if (ifc.ifc_len > sizeof(ifbuffer)) {
+        debug(28, 1) ("Interface list too long - %d\n", ifc.ifc_len);
+        return 0;
+    }
+    /* Attempt ARP lookup on each interface */
+    offset = 0;
+    while (offset < ifc.ifc_len) {
+        ifr = (struct ifreq *) (ifbuffer + offset);
+        offset += sizeof(*ifr);
+        /* Skip loopback and aliased interfaces */
+        if (0 == strncmp(ifr->ifr_name, "lo", 2))
+            continue;
+        if (NULL != strchr(ifr->ifr_name, ':'))
+            continue;
+        debug(28, 4) ("Looking up ARP address for %s on %s\n", inet_ntoa(c),
+            ifr->ifr_name);
+        /* Set up structures for ARP lookup */
+        ipAddr.sin_family = AF_INET;
+        ipAddr.sin_port = 0;
+        ipAddr.sin_addr = c;
+        memset(&arpReq, '\0', sizeof(arpReq));
+        xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
+        strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1);
+        arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0';
+        /* Query ARP table */
+        if (-1 == ioctl(HttpSockets[0], SIOCGARP, &arpReq)) {
+            /*
+             * Query failed.  Do not log failed lookups or "device
+             * not supported"
+             */
+            if (ENXIO == errno)
+                (void) 0;
+            else if (ENODEV == errno)
+                (void) 0;
+            else
+                debug(28, 1) ("ARP query failed: %s: %s\n",
+                    ifr->ifr_name, xstrerror());
+            continue;
+        }
+        /* Skip non-ethernet interfaces */
+        if (arpReq.arp_ha.sa_family != ARPHRD_ETHER)
+            continue;
+        debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x on %s\n",
+            arpReq.arp_ha.sa_data[0] & 0xff,
+            arpReq.arp_ha.sa_data[1] & 0xff,
+            arpReq.arp_ha.sa_data[2] & 0xff,
+            arpReq.arp_ha.sa_data[3] & 0xff,
+            arpReq.arp_ha.sa_data[4] & 0xff,
+            arpReq.arp_ha.sa_data[5] & 0xff, ifr->ifr_name);
+        /* Do lookup */
+        *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
+        /* Return if match, otherwise continue to other interfaces */
+        if (0 == splayLastResult) {
+            debug(28, 3) ("aclMatchArp: %s found on %s\n",
+                inet_ntoa(c), ifr->ifr_name);
+            return 1;
+        }
+        /*
+         * Should we stop looking here? Can the same IP address
+         * exist on multiple interfaces?
+         */
+    }
+#elif defined(_SQUID_SOLARIS_)
+    struct arpreq arpReq;
+    struct sockaddr_in ipAddr;
+    unsigned char ifbuffer[sizeof(struct ifreq) * 64];
+    struct ifconf ifc;
+    struct ifreq *ifr;
+    int offset;
+    splayNode **Top = dataptr;
+    /*
+     * Set up structures for ARP lookup with blank interface name
+     */
+    ipAddr.sin_family = AF_INET;
+    ipAddr.sin_port = 0;
+    ipAddr.sin_addr = c;
+    memset(&arpReq, '\0', sizeof(arpReq));
+    xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
+    /* Query ARP table */
+    if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
+        /*
+         *  Solaris (at least 2.6/x86) does not use arp_ha.sa_family -
+         * it returns 00:00:00:00:00:00 for non-ethernet media
+         */
+        if (arpReq.arp_ha.sa_data[0] == 0 &&
+            arpReq.arp_ha.sa_data[1] == 0 &&
+            arpReq.arp_ha.sa_data[2] == 0 &&
+            arpReq.arp_ha.sa_data[3] == 0 &&
+            arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0)
+            return 0;
+        debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
+            arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
+            arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
+            arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
+        /* Do lookup */
+        *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
+        debug(28, 3) ("aclMatchArp: '%s' %s\n",
+            inet_ntoa(c), splayLastResult ? "NOT found" : "found");
+        return (0 == splayLastResult);
+    }
+#else
+    WRITE ME;
+#endif
+    /*
+     * Address was not found on any interface
+     */
+    debug(28, 3) ("aclMatchArp: %s NOT found\n", inet_ntoa(c));
+    return 0;
+}
+
+static int
+aclMatchSrcArp(void **dataptr, aclCheck_t *checklist)
+{
+    return aclMatchArp(dataptr, checklist->src_addr);
+}
+
+
+static void
+aclDestroyArpList(parserNameNode *parserName, void * data)
+{
+    acl ** head=(acl **)data;
+    acl *a=*head;
+    if (a)
+        splay_destroy(a->data, xfree);
+}
+
+static void
+dump_ArpList(StoreEntry * entry, const char *name, void const * const data)
+{
+    acl * ae=*(acl * *)data;
+    wordlist *w;
+    wordlist *v;
+    while (ae != NULL) {
+        debug(3, 3) ("dump_ArpList: %s %s\n", name, ae->name);
+        v = w = aclDumpArpList(ae->data);
+        while (v != NULL) {
+            debug(3, 3) ("dump_ArpList: %s %s %s\n", name, ae->name, v->key);
+            storeAppendPrintf(entry, "%s %s %s %s\n",
+                name,
+                ae->name,
+                aclTypeToStr(ae->type),
+                v->key);
+            v = v->next;
+        }
+        wordlistDestroy(&w);
+        ae = ae->next;
+    }
+}
+
+static int
+aclArpCompare(const void *a, const void *b)
+{
+#if defined(_SQUID_LINUX_)
+    const unsigned short *d1 = a;
+    const unsigned short *d2 = b;
+    if (d1[0] != d2[0])
+        return (d1[0] > d2[0]) ? 1 : -1;
+    if (d1[1] != d2[1])
+        return (d1[1] > d2[1]) ? 1 : -1;
+    if (d1[2] != d2[2])
+        return (d1[2] > d2[2]) ? 1 : -1;
+#elif defined(_SQUID_SOLARIS_)
+    const unsigned char *d1 = a;
+    const unsigned char *d2 = b;
+    if (d1[0] != d2[0])
+        return (d1[0] > d2[0]) ? 1 : -1;
+    if (d1[1] != d2[1])
+        return (d1[1] > d2[1]) ? 1 : -1;
+    if (d1[2] != d2[2])
+        return (d1[2] > d2[2]) ? 1 : -1;
+    if (d1[3] != d2[3])
+        return (d1[3] > d2[3]) ? 1 : -1;
+    if (d1[4] != d2[4])
+        return (d1[4] > d2[4]) ? 1 : -1;
+    if (d1[5] != d2[5])
+        return (d1[5] > d2[5]) ? 1 : -1;
+#else
+    WRITE ME;
+#endif
+    return 0;
+}
+
+#if UNUSED_CODE
+/**********************************************************************
+* This is from the pre-splay-tree code for BSD
+* I suspect the Linux approach will work on most O/S and be much
+* better - <luyer@ucs.uwa.edu.au>
+***********************************************************************
+static int
+checkARP(u_long ip, char *eth)
+{
+    int mib[6] =
+    {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
+    size_t needed;
+    char *buf, *next, *lim;
+    struct rt_msghdr *rtm;
+    struct sockaddr_inarp *sin;
+    struct sockaddr_dl *sdl;
+    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+        debug(28, 0) ("Can't estimate ARP table size!\n");
+        return 0;
+    }
+    if ((buf = xmalloc(needed)) == NULL) {
+        debug(28, 0) ("Can't allocate temporary ARP table!\n");
+        return 0;
+    }
+    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+        debug(28, 0) ("Can't retrieve ARP table!\n");
+        xfree(buf);
+        return 0;
+    }
+    lim = buf + needed;
+    for (next = buf; next < lim; next += rtm->rtm_msglen) {
+        rtm = (struct rt_msghdr *) next;
+        sin = (struct sockaddr_inarp *) (rtm + 1);
+        sdl = (struct sockaddr_dl *) (sin + 1);
+        if (sin->sin_addr.s_addr == ip) {
+            if (sdl->sdl_alen)
+                if (!memcmp(LLADDR(sdl), eth, 6)) {
+                    xfree(buf);
+                    return 1;
+                }
+            break;
+        }
+    }
+    xfree(buf);
+    return 0;
+}
+**********************************************************************/
+#endif
+
+static void
+aclDumpArpListWalkee(void *node, void *state)
+{
+    acl_arp_data *arp = node;
+    wordlist **W = state;
+    static char buf[24];
+    while (*W != NULL)
+        W = &(*W)->next;
+    snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
+        arp->eth[0], arp->eth[1], arp->eth[2], arp->eth[3],
+        arp->eth[4], arp->eth[5]);
+    wordlistAdd(state, buf);
+}
+
+static wordlist *
+aclDumpArpList(void *data)
+{
+    wordlist *w = NULL;
+    splay_walk(data, aclDumpArpListWalkee, &w);
+    return w;
+}
+
+/* ==== END ARP ACL SUPPORT =============================================== */
+
Index: squid/src/repl/heap/store_repl_heap.c
diff -u squid/src/repl/heap/store_repl_heap.c:1.8 squid/src/repl/heap/store_repl_heap.c:1.6.4.3
--- squid/src/repl/heap/store_repl_heap.c:1.8	Fri Mar 16 09:22:14 2001
+++ squid/src/repl/heap/store_repl_heap.c	Sat Mar 31 01:52:21 2001
@@ -37,7 +37,26 @@
 #include "heap.h"
 #include "store_heap_replacement.h"
 
-REMOVALPOLICYCREATE createRemovalPolicy_heap;
+static REMOVALPOLICYCREATE createRemovalPolicy_heap;
+
+/* Module Support
+ */
+
+/* register as a module 
+ */
+void
+mod_install_heap (const char *namestr)
+{
+    storeReplAdd(namestr, createRemovalPolicy_heap);
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_heap(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
+
 
 static int nr_heap_policies = 0;
 
@@ -250,7 +269,7 @@
     cbdataFree(policy);
 }
 
-RemovalPolicy *
+static RemovalPolicy *
 createRemovalPolicy_heap(wordlist * args)
 {
     RemovalPolicy *policy;
Index: squid/src/repl/lru/store_repl_lru.c
diff -u squid/src/repl/lru/store_repl_lru.c:1.7 squid/src/repl/lru/store_repl_lru.c:1.6.4.3
--- squid/src/repl/lru/store_repl_lru.c:1.7	Sat Mar  3 02:44:34 2001
+++ squid/src/repl/lru/store_repl_lru.c	Sat Mar 31 01:52:21 2001
@@ -35,7 +35,7 @@
 
 #include "squid.h"
 
-REMOVALPOLICYCREATE createRemovalPolicy_lru;
+static REMOVALPOLICYCREATE createRemovalPolicy_lru;
 
 typedef struct _LruPolicyData LruPolicyData;
 struct _LruPolicyData {
@@ -48,6 +48,26 @@
     } type;
 };
 
+
+/* Module Support
+ */
+
+/* register as a module
+ */
+void
+mod_install_lru (const char *namestr)
+{
+    storeReplAdd(namestr, createRemovalPolicy_lru);
+}
+
+/* deregister as a module */
+unsigned int
+mod_uninstall_lru(const char *namestr) {
+    /* deregistration not supported for this module */
+    return 0;
+}
+
+
 /* Hack to avoid having to remember the RemovalPolicyNode location.
  * Needed by the purge walker to clear the policy information
  */
@@ -256,7 +276,7 @@
     cbdataFree(policy);
 }
 
-RemovalPolicy *
+static RemovalPolicy *
 createRemovalPolicy_lru(wordlist * args)
 {
     RemovalPolicy *policy;