---------------------
PatchSet 5307 
Date: 2002/10/09 00:23:15
Author: rbcollins
Branch: rbcollins_cxxtest
Tag: (none) 
Log:
and more

Members: 
	include/hash.h:1.4.44.3->1.4.44.4 
	include/profiling.h:1.2.4.1->1.2.4.2 
	include/radix.h:1.8->1.8.16.1 
	include/splay.h:1.6->1.6.20.1 
	include/util.h:1.11.20.6->1.11.20.7 
	src/Makefile.am:1.29.2.15->1.29.2.16 
	src/asn.c:1.18.2.1->1.18.2.2(DEAD) 
	src/asn.cc:1.1->1.1.2.1 
	src/cache_diff.c:1.7->1.7.6.1(DEAD) 
	src/cache_diff.cc:1.1->1.1.2.1 
	src/cache_manager.c:1.7.84.1->1.7.84.2(DEAD) 
	src/cache_manager.cc:1.1->1.1.2.1 
	src/cachemgr.c:1.13->1.13.6.1(DEAD) 
	src/cachemgr.cc:1.1->1.1.2.1 
	src/carp.c:1.8.18.1->1.8.18.2(DEAD) 
	src/carp.cc:1.1->1.1.2.1 
	src/cbdata.c:1.16.2.2->1.16.2.3(DEAD) 
	src/cbdata.cc:1.1->1.1.2.1 
	src/cf_gen.c:1.14->1.14.6.1(DEAD) 
	src/cf_gen.cc:1.1->1.1.2.1 
	src/cf_gen_defines:1.5->1.5.40.1 
	src/clientStream.c:1.3->1.3.8.1(DEAD) 
	src/clientStream.cc:1.1->1.1.2.1 
	src/clientStream.h:1.2.18.1->1.2.18.2 
	src/client_db.c:1.7.2.1->1.7.2.2(DEAD) 
	src/client_db.cc:1.1->1.1.2.1 
	src/dnsserver.c:1.6->1.6.14.1(DEAD) 
	src/dnsserver.cc:1.1->1.1.2.1 
	src/ipcache.c:1.19.6.1->1.19.6.2(DEAD) 
	src/ipcache.cc:1.1->1.1.2.1 
	src/snmp_agent.c:1.9->1.9.44.1(DEAD) 
	src/snmp_agent.cc:1.1->1.1.2.1 
	src/store_swapmeta.c:1.8.44.1->1.8.44.2(DEAD) 
	src/store_swapmeta.cc:1.1->1.1.2.1 

Index: squid/include/hash.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/hash.h,v
retrieving revision 1.4.44.3
retrieving revision 1.4.44.4
diff -u -r1.4.44.3 -r1.4.44.4
--- squid/include/hash.h	6 Oct 2002 12:31:51 -0000	1.4.44.3
+++ squid/include/hash.h	9 Oct 2002 00:23:15 -0000	1.4.44.4
@@ -1,5 +1,5 @@
 /*
- * $Id: hash.h,v 1.4.44.3 2002/10/06 12:31:51 rbcollins Exp $
+ * $Id: hash.h,v 1.4.44.4 2002/10/09 00:23:15 rbcollins Exp $
  */
 
 #ifndef SQUID_HASH_H
@@ -39,7 +39,7 @@
 SQUIDCEXTERN void hashFreeItems(hash_table *, HASHFREE *);
 SQUIDCEXTERN HASHHASH hash_string;
 SQUIDCEXTERN HASHHASH hash4;
-extern const char *hashKeyStr(hash_link *);
+SQUIDCEXTERN const char *hashKeyStr(hash_link *);
 
 /*
  *  Here are some good prime number choices.  It's important not to
Index: squid/include/profiling.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/Attic/profiling.h,v
retrieving revision 1.2.4.1
retrieving revision 1.2.4.2
diff -u -r1.2.4.1 -r1.2.4.2
--- squid/include/profiling.h	6 Oct 2002 06:07:43 -0000	1.2.4.1
+++ squid/include/profiling.h	9 Oct 2002 00:23:15 -0000	1.2.4.2
@@ -86,7 +86,7 @@
     XPROF_LAST
 } xprof_type;
 
-#define XP_NOBEST 9999999999
+#define XP_NOBEST (hrtime_t)-1
 
 typedef struct _xprof_stats_node xprof_stats_node;
 typedef struct _xprof_stats_data xprof_stats_data;
Index: squid/include/radix.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/radix.h,v
retrieving revision 1.8
retrieving revision 1.8.16.1
diff -u -r1.8 -r1.8.16.1
--- squid/include/radix.h	21 Apr 2002 07:41:03 -0000	1.8
+++ squid/include/radix.h	9 Oct 2002 00:23:15 -0000	1.8.16.1
@@ -1,5 +1,5 @@
 /*
- * $Id: radix.h,v 1.8 2002/04/21 07:41:03 squidadm Exp $
+ * $Id: radix.h,v 1.8.16.1 2002/10/09 00:23:15 rbcollins Exp $
  */
 
 #ifndef SQUID_RADIX_H
@@ -80,7 +80,7 @@
  * Annotations to tree concerning potential routes applying to subtrees.
  */
 
-extern struct squid_radix_mask {
+SQUIDCEXTERN struct squid_radix_mask {
     short rm_b;			/* bit offset; -1-index(netmask) */
     char rm_unused;		/* cf. rn_bmask */
     unsigned char rm_flags;	/* cf. rn_flags */
@@ -118,18 +118,18 @@
 };
 
 
-extern void squid_rn_init (void);
-extern int squid_rn_inithead(void **, int);
-extern int squid_rn_refines(void *, void *);
-extern int squid_rn_walktree(struct squid_radix_node_head *, int (*)(struct squid_radix_node *, void *), void *);
-extern struct squid_radix_node *squid_rn_addmask(void *, int, int);
-extern struct squid_radix_node *squid_rn_addroute(void *, void *, struct squid_radix_node_head *, struct squid_radix_node[2]);
-extern struct squid_radix_node *squid_rn_delete(void *, void *, struct squid_radix_node_head *);
-extern struct squid_radix_node *squid_rn_insert(void *, struct squid_radix_node_head *, int *, struct squid_radix_node[2]);
-extern struct squid_radix_node *squid_rn_match(void *, struct squid_radix_node_head *);
-extern struct squid_radix_node *squid_rn_newpair(void *, int, struct squid_radix_node[2]);
-extern struct squid_radix_node *squid_rn_search(void *, struct squid_radix_node *);
-extern struct squid_radix_node *squid_rn_search_m(void *, struct squid_radix_node *, void *);
-extern struct squid_radix_node *squid_rn_lookup(void *, void *, struct squid_radix_node_head *);
+SQUIDCEXTERN void squid_rn_init (void);
+SQUIDCEXTERN int squid_rn_inithead(void **, int);
+SQUIDCEXTERN int squid_rn_refines(void *, void *);
+SQUIDCEXTERN int squid_rn_walktree(struct squid_radix_node_head *, int (*)(struct squid_radix_node *, void *), void *);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_addmask(void *, int, int);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_addroute(void *, void *, struct squid_radix_node_head *, struct squid_radix_node[2]);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_delete(void *, void *, struct squid_radix_node_head *);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_insert(void *, struct squid_radix_node_head *, int *, struct squid_radix_node[2]);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_match(void *, struct squid_radix_node_head *);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_newpair(void *, int, struct squid_radix_node[2]);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_search(void *, struct squid_radix_node *);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_search_m(void *, struct squid_radix_node *, void *);
+SQUIDCEXTERN struct squid_radix_node *squid_rn_lookup(void *, void *, struct squid_radix_node_head *);
 
 #endif /* SQUID_RADIX_H */
Index: squid/include/splay.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/splay.h,v
retrieving revision 1.6
retrieving revision 1.6.20.1
diff -u -r1.6 -r1.6.20.1
--- squid/include/splay.h	6 Apr 2002 11:34:49 -0000	1.6
+++ squid/include/splay.h	9 Oct 2002 00:23:15 -0000	1.6.20.1
@@ -1,5 +1,5 @@
 /*
- * $Id: splay.h,v 1.6 2002/04/06 11:34:49 squidadm Exp $
+ * $Id: splay.h,v 1.6.20.1 2002/10/09 00:23:15 rbcollins Exp $
  */
 
 #ifndef SQUID_SPLAY_H
@@ -15,12 +15,12 @@
 typedef void SPLAYWALKEE(void *nodedata, void *state);
 typedef void SPLAYFREE(void *);
 
-extern int splayLastResult;
+SQUIDCEXTERN int splayLastResult;
 
-extern splayNode *splay_insert(void *, splayNode *, SPLAYCMP *);
-extern splayNode *splay_splay(const void *, splayNode *, SPLAYCMP *);
-extern splayNode *splay_delete(const void *, splayNode *, SPLAYCMP *);
-extern void splay_destroy(splayNode *, SPLAYFREE *);
-extern void splay_walk(splayNode *, SPLAYWALKEE *, void *);
+SQUIDCEXTERN splayNode *splay_insert(void *, splayNode *, SPLAYCMP *);
+SQUIDCEXTERN splayNode *splay_splay(const void *, splayNode *, SPLAYCMP *);
+SQUIDCEXTERN splayNode *splay_delete(const void *, splayNode *, SPLAYCMP *);
+SQUIDCEXTERN void splay_destroy(splayNode *, SPLAYFREE *);
+SQUIDCEXTERN void splay_walk(splayNode *, SPLAYWALKEE *, void *);
 
 #endif /* SQUID_SPLAY_H */
Index: squid/include/util.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/util.h,v
retrieving revision 1.11.20.6
retrieving revision 1.11.20.7
diff -u -r1.11.20.6 -r1.11.20.7
--- squid/include/util.h	8 Oct 2002 11:11:34 -0000	1.11.20.6
+++ squid/include/util.h	9 Oct 2002 00:23:15 -0000	1.11.20.7
@@ -1,5 +1,5 @@
 /*
- * $Id: util.h,v 1.11.20.6 2002/10/08 11:11:34 rbcollins Exp $
+ * $Id: util.h,v 1.11.20.7 2002/10/09 00:23:15 rbcollins Exp $
  *
  * AUTHOR: Harvest Derived
  *
@@ -61,7 +61,7 @@
 #define _etext etext
 #endif
 
-extern const char *getfullhostname(void);
+SQUIDCEXTERN const char *getfullhostname(void);
 SQUIDCEXTERN const char *mkhttpdlogtime(const time_t *);
 SQUIDCEXTERN const char *mkrfc1123(time_t);
 SQUIDCEXTERN char *uudecode(const char *);
Index: squid/src/Makefile.am
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Makefile.am,v
retrieving revision 1.29.2.15
retrieving revision 1.29.2.16
diff -u -r1.29.2.15 -r1.29.2.16
--- squid/src/Makefile.am	8 Oct 2002 14:57:57 -0000	1.29.2.15
+++ squid/src/Makefile.am	9 Oct 2002 00:23:15 -0000	1.29.2.16
@@ -15,7 +15,7 @@
 endif
 
 if USE_SNMP
-SNMPSOURCE = snmp_core.c snmp_agent.c
+SNMPSOURCE = snmp_core.c snmp_agent.cc
 else
 SNMPSOURCE = 
 endif
@@ -95,21 +95,21 @@
 	$(UNLINKD) \
 	cachemgr$(CGIEXT)
 
-cf_gen_SOURCES = cf_gen.c defines.h
+cf_gen_SOURCES = cf_gen.cc defines.h
 nodist_cf_gen_HEADER = cf_gen_defines.h
 cf_gen.$(OBJEXT): cf_gen_defines.h
 squidclient_SOURCES = client.cc
-cachemgr__CGIEXT__SOURCES = cachemgr.c
+cachemgr__CGIEXT__SOURCES = cachemgr.cc
 
 EXTRA_squid_SOURCES = \
 	delay_pools.c \
 	dns.c \
-	dnsserver.c \
+	dnsserver.cc \
 	dns_internal.c \
 	htcp.cc \
 	leakfinder.c \
 	snmp_core.c \
-	snmp_agent.c \
+	snmp_agent.cc \
 	unlinkd.cc \
 	ssl_support.c \
 	ssl_support.h \
@@ -118,19 +118,19 @@
 squid_SOURCES = \
 	access_log.cc \
 	acl.cc \
-	asn.c \
+	asn.cc \
 	authenticate.cc \
 	cache_cf.cc \
 	CacheDigest.cc \
-	cache_manager.c \
-	carp.c \
-	cbdata.c \
-	client_db.c \
+	cache_manager.cc \
+	carp.cc \
+	cbdata.cc \
+	client_db.cc \
 	client_side.c \
 	client_side_reply.cc \
 	client_side_request.c \
 	client_side_request.h \
-	clientStream.c \
+	clientStream.cc \
 	clientStream.h \
 	comm.c \
 	comm_select.c \
@@ -172,7 +172,7 @@
 	ident.cc \
 	internal.c \
 	ipc.c \
-	ipcache.c \
+	ipcache.cc \
 	IPInterception.cc \
 	IPInterception.h \
 	$(LEAKFINDERSOURCE) \
@@ -213,7 +213,7 @@
 	store_log.c \
 	store_rebuild.c \
 	store_swapin.c \
-	store_swapmeta.c \
+	store_swapmeta.cc \
 	store_swapout.c \
 	structs.h \
 	tools.c \
@@ -259,6 +259,8 @@
 	pinger.c \
 	debug.c
 
+dnsserver_SOURCES = dnsserver.cc
+
 nodist_pinger_SOURCES = \
 	globals.c
 
--- squid/src/asn.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,475 +0,0 @@
-
-/*
- * $Id: asn.c,v 1.18.2.1 2002/10/04 07:07:19 rbcollins Exp $
- *
- * DEBUG: section 53    AS Number handling
- * AUTHOR: Duane Wessels, Kostas Anagnostakis
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "radix.h"
-#include "StoreClient.h"
-#include "Store.h"
-
-#define WHOIS_PORT 43
-#define	AS_REQBUF_SZ	4096
-
-/* BEGIN of definitions for radix tree entries */
-
-/* int in memory with length */
-typedef u_char m_int[1 + sizeof(unsigned int)];
-#define store_m_int(i, m) \
-    (i = htonl(i), m[0] = sizeof(m_int), xmemcpy(m+1, &i, sizeof(unsigned int)))
-#define get_m_int(i, m) \
-    (xmemcpy(&i, m+1, sizeof(unsigned int)), ntohl(i))
-
-/* END of definitions for radix tree entries */
-
-/* Head for ip to asn radix tree */
-struct squid_radix_node_head *AS_tree_head;
-
-/*
- * Structure for as number information. it could be simply 
- * an intlist but it's coded as a structure for future
- * enhancements (e.g. expires)
- */
-struct _as_info {
-    intlist *as_number;
-    time_t expires;		/* NOTUSED */
-};
-
-struct _ASState {
-    StoreEntry *entry;
-    store_client *sc;
-    request_t *request;
-    int as_number;
-    off_t offset;
-    int reqofs;
-    char reqbuf[AS_REQBUF_SZ];
-};
-
-typedef struct _ASState ASState;
-typedef struct _as_info as_info;
-
-/* entry into the radix tree */
-struct _rtentry {
-    struct squid_radix_node e_nodes[2];
-    as_info *e_info;
-    m_int e_addr;
-    m_int e_mask;
-};
-
-typedef struct _rtentry rtentry;
-
-static int asnAddNet(char *, int);
-static void asnCacheStart(int as);
-static STCB asHandleReply;
-static int destroyRadixNode(struct squid_radix_node *rn, void *w);
-static int printRadixNode(struct squid_radix_node *rn, void *w);
-static void asnAclInitialize(acl * acls);
-static void asStateFree(void *data);
-static void destroyRadixNodeInfo(as_info *);
-static OBJH asnStats;
-
-/* PUBLIC */
-
-int
-asnMatchIp(void *data, struct in_addr addr)
-{
-    unsigned long lh;
-    struct squid_radix_node *rn;
-    as_info *e;
-    m_int m_addr;
-    intlist *a = NULL;
-    intlist *b = NULL;
-    lh = ntohl(addr.s_addr);
-    debug(53, 3) ("asnMatchIp: Called for %s.\n", inet_ntoa(addr));
-
-    if (AS_tree_head == NULL)
-	return 0;
-    if (addr.s_addr == no_addr.s_addr)
-	return 0;
-    if (addr.s_addr == any_addr.s_addr)
-	return 0;
-    store_m_int(lh, m_addr);
-    rn = squid_rn_match(m_addr, AS_tree_head);
-    if (rn == NULL) {
-	debug(53, 3) ("asnMatchIp: Address not in as db.\n");
-	return 0;
-    }
-    debug(53, 3) ("asnMatchIp: Found in db!\n");
-    e = ((rtentry *) rn)->e_info;
-    assert(e);
-    for (a = (intlist *) data; a; a = a->next)
-	for (b = e->as_number; b; b = b->next)
-	    if (a->i == b->i) {
-		debug(53, 5) ("asnMatchIp: Found a match!\n");
-		return 1;
-	    }
-    debug(53, 5) ("asnMatchIp: AS not in as db.\n");
-    return 0;
-}
-
-static void
-asnAclInitialize(acl * acls)
-{
-    acl *a;
-    intlist *i;
-    debug(53, 3) ("asnAclInitialize\n");
-    for (a = acls; a; a = a->next) {
-	if (a->type != ACL_DST_ASN && a->type != ACL_SRC_ASN)
-	    continue;
-	for (i = a->data; i; i = i->next)
-	    asnCacheStart(i->i);
-    }
-}
-
-/* initialize the radix tree structure */
-
-extern int squid_max_keylen;	/* yuck.. this is in lib/radix.c */
-
-CBDATA_TYPE(ASState);
-void
-asnInit(void)
-{
-    static int inited = 0;
-    squid_max_keylen = 40;
-    CBDATA_INIT_TYPE(ASState);
-    if (0 == inited++)
-	squid_rn_init();
-    squid_rn_inithead((void **) &AS_tree_head, 8);
-    asnAclInitialize(Config.aclList);
-    cachemgrRegister("asndb", "AS Number Database", asnStats, 0, 1);
-}
-
-void
-asnFreeMemory(void)
-{
-    squid_rn_walktree(AS_tree_head, destroyRadixNode, AS_tree_head);
-    destroyRadixNode((struct squid_radix_node *) 0, (void *) AS_tree_head);
-}
-
-static void
-asnStats(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "Address    \tAS Numbers\n");
-    squid_rn_walktree(AS_tree_head, printRadixNode, sentry);
-}
-
-/* PRIVATE */
-
-
-static void
-asnCacheStart(int as)
-{
-    LOCAL_ARRAY(char, asres, 4096);
-    StoreEntry *e;
-    request_t *req;
-    ASState *asState;
-    StoreIOBuffer readBuffer = EMPTYIOBUFFER;
-    asState = cbdataAlloc(ASState);
-    debug(53, 3) ("asnCacheStart: AS %d\n", as);
-    snprintf(asres, 4096, "whois://%s/!gAS%d", Config.as_whois_server, as);
-    asState->as_number = as;
-    req = urlParse(METHOD_GET, asres);
-    assert(NULL != req);
-    asState->request = requestLink(req);
-    if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
-	e = storeCreateEntry(asres, asres, null_request_flags, METHOD_GET);
-	asState->sc = storeClientListAdd(e, asState);
-	fwdStart(-1, e, asState->request);
-    } else {
-	storeLockObject(e);
-	asState->sc = storeClientListAdd(e, asState);
-    }
-    asState->entry = e;
-    asState->offset = 0;
-    asState->reqofs = 0;
-    readBuffer.offset = asState->offset;
-    readBuffer.length = AS_REQBUF_SZ;
-    readBuffer.data = asState->reqbuf;
-    storeClientCopy(asState->sc,
-	e,
-	readBuffer,
-	asHandleReply,
-	asState);
-}
-
-static void
-asHandleReply(void *data, StoreIOBuffer result)
-{
-    ASState *asState = data;
-    StoreEntry *e = asState->entry;
-    char *s;
-    char *t;
-    char *buf = asState->reqbuf;
-    int leftoversz = -1;
-
-    debug(53, 3) ("asHandleReply: Called with size=%u\n", result.length);
-    debug(53, 3) ("asHandleReply: buffer='%s'\n", buf);
-
-    /* First figure out whether we should abort the request */
-    if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
-	asStateFree(asState);
-	return;
-    }
-    if (result.length == 0 && e->mem_obj->inmem_hi > 0) {
-	asStateFree(asState);
-	return;
-    } else if (result.flags.error) {
-	debug(53, 1) ("asHandleReply: Called with Error set and size=%u\n", result.length);
-	asStateFree(asState);
-	return;
-    } else if (HTTP_OK != e->mem_obj->reply->sline.status) {
-	debug(53, 1) ("WARNING: AS %d whois request failed\n",
-	    asState->as_number);
-	asStateFree(asState);
-	return;
-    }
-    /*
-     * Next, attempt to parse our request
-     * Remembering that the actual buffer size is retsize + reqofs!
-     */
-    s = buf;
-    while (s - buf < (result.length + asState->reqofs) && *s != '\0') {
-	while (*s && xisspace(*s))
-	    s++;
-	for (t = s; *t; t++) {
-	    if (xisspace(*t))
-		break;
-	}
-	if (*t == '\0') {
-	    /* oof, word should continue on next block */
-	    break;
-	}
-	*t = '\0';
-	debug(53, 3) ("asHandleReply: AS# %s (%d)\n", s, asState->as_number);
-	asnAddNet(s, asState->as_number);
-	s = t + 1;
-    }
-
-    /*
-     * Next, grab the end of the 'valid data' in the buffer, and figure
-     * out how much data is left in our buffer, which we need to keep
-     * around for the next request
-     */
-    leftoversz = (asState->reqofs + result.length) - (s - buf);
-    assert(leftoversz >= 0);
-
-    /*
-     * Next, copy the left over data, from s to s + leftoversz to the
-     * beginning of the buffer
-     */
-    xmemmove(buf, s, leftoversz);
-
-    /*
-     * Next, update our offset and reqofs, and kick off a copy if required
-     */
-    asState->offset += result.length;
-    asState->reqofs = leftoversz;
-    debug(53, 3) ("asState->offset = %ld\n", (long int) asState->offset);
-    if (e->store_status == STORE_PENDING) {
-	StoreIOBuffer tempBuffer = EMPTYIOBUFFER;
-	debug(53, 3) ("asHandleReply: store_status == STORE_PENDING: %s\n", storeUrl(e));
-	tempBuffer.offset = asState->offset;
-	tempBuffer.length = AS_REQBUF_SZ - asState->reqofs;
-	tempBuffer.data = asState->reqbuf + asState->reqofs;
-	storeClientCopy(asState->sc,
-	    e,
-	    tempBuffer,
-	    asHandleReply,
-	    asState);
-    } else if (asState->offset < e->mem_obj->inmem_hi) {
-	StoreIOBuffer tempBuffer = EMPTYIOBUFFER;
-	debug(53, 3) ("asHandleReply: asState->offset < e->mem_obj->inmem_hi %s\n", storeUrl(e));
-	tempBuffer.offset = asState->offset;
-	tempBuffer.length = AS_REQBUF_SZ - asState->reqofs;
-	tempBuffer.data = asState->reqbuf + asState->reqofs;
-	storeClientCopy(asState->sc,
-	    e,
-	    tempBuffer,
-	    asHandleReply,
-	    asState);
-    } else {
-	debug(53, 3) ("asHandleReply: Done: %s\n", storeUrl(e));
-	asStateFree(asState);
-    }
-}
-
-static void
-asStateFree(void *data)
-{
-    ASState *asState = data;
-    debug(53, 3) ("asnStateFree: %s\n", storeUrl(asState->entry));
-    storeUnregister(asState->sc, asState->entry, asState);
-    storeUnlockObject(asState->entry);
-    requestUnlink(asState->request);
-    cbdataFree(asState);
-}
-
-
-/* add a network (addr, mask) to the radix tree, with matching AS
- * number */
-
-static int
-asnAddNet(char *as_string, int as_number)
-{
-    rtentry *e = xmalloc(sizeof(rtentry));
-    struct squid_radix_node *rn;
-    char dbg1[32], dbg2[32];
-    intlist **Tail = NULL;
-    intlist *q = NULL;
-    as_info *asinfo = NULL;
-    struct in_addr in_a, in_m;
-    long mask, addr;
-    char *t;
-    int bitl;
-
-    t = strchr(as_string, '/');
-    if (t == NULL) {
-	debug(53, 3) ("asnAddNet: failed, invalid response from whois server.\n");
-	return 0;
-    }
-    *t = '\0';
-    addr = inet_addr(as_string);
-    bitl = atoi(t + 1);
-    if (bitl < 0)
-	bitl = 0;
-    if (bitl > 32)
-	bitl = 32;
-    mask = bitl ? 0xfffffffful << (32 - bitl) : 0;
-
-    in_a.s_addr = addr;
-    in_m.s_addr = mask;
-    xstrncpy(dbg1, inet_ntoa(in_a), 32);
-    xstrncpy(dbg2, inet_ntoa(in_m), 32);
-    addr = ntohl(addr);
-    /*mask = ntohl(mask); */
-    debug(53, 3) ("asnAddNet: called for %s/%s\n", dbg1, dbg2);
-    memset(e, '\0', sizeof(rtentry));
-    store_m_int(addr, e->e_addr);
-    store_m_int(mask, e->e_mask);
-    rn = squid_rn_lookup(e->e_addr, e->e_mask, AS_tree_head);
-    if (rn != NULL) {
-	asinfo = ((rtentry *) rn)->e_info;
-	if (intlistFind(asinfo->as_number, as_number)) {
-	    debug(53, 3) ("asnAddNet: Ignoring repeated network '%s/%d' for AS %d\n",
-		dbg1, bitl, as_number);
-	} else {
-	    debug(53, 3) ("asnAddNet: Warning: Found a network with multiple AS numbers!\n");
-	    for (Tail = &asinfo->as_number; *Tail; Tail = &(*Tail)->next);
-	    q = xcalloc(1, sizeof(intlist));
-	    q->i = as_number;
-	    *(Tail) = q;
-	    e->e_info = asinfo;
-	}
-    } else {
-	q = xcalloc(1, sizeof(intlist));
-	q->i = as_number;
-	asinfo = xmalloc(sizeof(asinfo));
-	asinfo->as_number = q;
-	rn = squid_rn_addroute(e->e_addr, e->e_mask, AS_tree_head, e->e_nodes);
-	rn = squid_rn_match(e->e_addr, AS_tree_head);
-	assert(rn != NULL);
-	e->e_info = asinfo;
-    }
-    if (rn == 0) {
-	xfree(e);
-	debug(53, 3) ("asnAddNet: Could not add entry.\n");
-	return 0;
-    }
-    e->e_info = asinfo;
-    return 1;
-}
-
-static int
-destroyRadixNode(struct squid_radix_node *rn, void *w)
-{
-    struct squid_radix_node_head *rnh = (struct squid_radix_node_head *) w;
-
-    if (rn && !(rn->rn_flags & RNF_ROOT)) {
-	rtentry *e = (rtentry *) rn;
-	rn = squid_rn_delete(rn->rn_key, rn->rn_mask, rnh);
-	if (rn == 0)
-	    debug(53, 3) ("destroyRadixNode: internal screwup\n");
-	destroyRadixNodeInfo(e->e_info);
-	xfree(rn);
-    }
-    return 1;
-}
-
-static void
-destroyRadixNodeInfo(as_info * e_info)
-{
-    intlist *prev = NULL;
-    intlist *data = e_info->as_number;
-    while (data) {
-	prev = data;
-	data = data->next;
-	xfree(prev);
-    }
-    xfree(data);
-}
-
-static int
-mask_len(u_long mask)
-{
-    int len = 32;
-    if (mask == 0)
-	return 0;
-    while ((mask & 1) == 0) {
-	len--;
-	mask >>= 1;
-    }
-    return len;
-}
-
-static int
-printRadixNode(struct squid_radix_node *rn, void *w)
-{
-    StoreEntry *sentry = w;
-    rtentry *e = (rtentry *) rn;
-    intlist *q;
-    as_info *asinfo;
-    struct in_addr addr;
-    struct in_addr mask;
-    assert(e);
-    assert(e->e_info);
-    (void) get_m_int(addr.s_addr, e->e_addr);
-    (void) get_m_int(mask.s_addr, e->e_mask);
-    storeAppendPrintf(sentry, "%15s/%d\t",
-	inet_ntoa(addr), mask_len(ntohl(mask.s_addr)));
-    asinfo = e->e_info;
-    assert(asinfo->as_number);
-    for (q = asinfo->as_number; q; q = q->next)
-	storeAppendPrintf(sentry, " %d", q->i);
-    storeAppendPrintf(sentry, "\n");
-    return 0;
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/asn.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,474 @@
+
+/*
+ * $Id: asn.cc,v 1.1.2.1 2002/10/09 00:23:15 rbcollins Exp $
+ *
+ * DEBUG: section 53    AS Number handling
+ * AUTHOR: Duane Wessels, Kostas Anagnostakis
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "radix.h"
+#include "StoreClient.h"
+#include "Store.h"
+
+#define WHOIS_PORT 43
+#define	AS_REQBUF_SZ	4096
+
+/* BEGIN of definitions for radix tree entries */
+
+/* int in memory with length */
+typedef u_char m_int[1 + sizeof(unsigned int)];
+#define store_m_int(i, m) \
+    (i = htonl(i), m[0] = sizeof(m_int), xmemcpy(m+1, &i, sizeof(unsigned int)))
+#define get_m_int(i, m) \
+    (xmemcpy(&i, m+1, sizeof(unsigned int)), ntohl(i))
+
+/* END of definitions for radix tree entries */
+
+/* Head for ip to asn radix tree */
+struct squid_radix_node_head *AS_tree_head;
+
+/*
+ * Structure for as number information. it could be simply 
+ * an intlist but it's coded as a structure for future
+ * enhancements (e.g. expires)
+ */
+struct _as_info {
+    intlist *as_number;
+    time_t expires;		/* NOTUSED */
+};
+
+struct _ASState {
+    StoreEntry *entry;
+    store_client *sc;
+    request_t *request;
+    int as_number;
+    off_t offset;
+    int reqofs;
+    char reqbuf[AS_REQBUF_SZ];
+};
+
+typedef struct _ASState ASState;
+typedef struct _as_info as_info;
+
+/* entry into the radix tree */
+struct _rtentry {
+    struct squid_radix_node e_nodes[2];
+    as_info *e_info;
+    m_int e_addr;
+    m_int e_mask;
+};
+
+typedef struct _rtentry rtentry;
+
+static int asnAddNet(char *, int);
+static void asnCacheStart(int as);
+static STCB asHandleReply;
+static int destroyRadixNode(struct squid_radix_node *rn, void *w);
+static int printRadixNode(struct squid_radix_node *rn, StoreEntry *);
+static void asnAclInitialize(acl * acls);
+static void asStateFree(void *data);
+static void destroyRadixNodeInfo(as_info *);
+static OBJH asnStats;
+
+/* PUBLIC */
+
+int
+asnMatchIp(void *data, struct in_addr addr)
+{
+    unsigned long lh;
+    struct squid_radix_node *rn;
+    as_info *e;
+    m_int m_addr;
+    intlist *a = NULL;
+    intlist *b = NULL;
+    lh = ntohl(addr.s_addr);
+    debug(53, 3) ("asnMatchIp: Called for %s.\n", inet_ntoa(addr));
+
+    if (AS_tree_head == NULL)
+	return 0;
+    if (addr.s_addr == no_addr.s_addr)
+	return 0;
+    if (addr.s_addr == any_addr.s_addr)
+	return 0;
+    store_m_int(lh, m_addr);
+    rn = squid_rn_match(m_addr, AS_tree_head);
+    if (rn == NULL) {
+	debug(53, 3) ("asnMatchIp: Address not in as db.\n");
+	return 0;
+    }
+    debug(53, 3) ("asnMatchIp: Found in db!\n");
+    e = ((rtentry *) rn)->e_info;
+    assert(e);
+    for (a = (intlist *) data; a; a = a->next)
+	for (b = e->as_number; b; b = b->next)
+	    if (a->i == b->i) {
+		debug(53, 5) ("asnMatchIp: Found a match!\n");
+		return 1;
+	    }
+    debug(53, 5) ("asnMatchIp: AS not in as db.\n");
+    return 0;
+}
+
+static void
+asnAclInitialize(acl * acls)
+{
+    acl *a;
+    intlist *i;
+    debug(53, 3) ("asnAclInitialize\n");
+    for (a = acls; a; a = a->next) {
+	if (a->type != ACL_DST_ASN && a->type != ACL_SRC_ASN)
+	    continue;
+	for (i = (intlist *)a->data; i; i = i->next)
+	    asnCacheStart(i->i);
+    }
+}
+
+/* initialize the radix tree structure */
+
+extern int squid_max_keylen;	/* yuck.. this is in lib/radix.c */
+
+CBDATA_TYPE(ASState);
+void
+asnInit(void)
+{
+    static int inited = 0;
+    squid_max_keylen = 40;
+    CBDATA_INIT_TYPE(ASState);
+    if (0 == inited++)
+	squid_rn_init();
+    squid_rn_inithead((void **) &AS_tree_head, 8);
+    asnAclInitialize(Config.aclList);
+    cachemgrRegister("asndb", "AS Number Database", asnStats, 0, 1);
+}
+
+void
+asnFreeMemory(void)
+{
+    squid_rn_walktree(AS_tree_head, destroyRadixNode, AS_tree_head);
+    destroyRadixNode((struct squid_radix_node *) 0, (void *) AS_tree_head);
+}
+
+static void
+asnStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "Address    \tAS Numbers\n");
+    squid_rn_walktree(AS_tree_head, printRadixNode, sentry);
+}
+
+/* PRIVATE */
+
+
+static void
+asnCacheStart(int as)
+{
+    LOCAL_ARRAY(char, asres, 4096);
+    StoreEntry *e;
+    request_t *req;
+    ASState *asState;
+    StoreIOBuffer readBuffer = EMPTYIOBUFFER;
+    asState = cbdataAlloc(ASState);
+    debug(53, 3) ("asnCacheStart: AS %d\n", as);
+    snprintf(asres, 4096, "whois://%s/!gAS%d", Config.as_whois_server, as);
+    asState->as_number = as;
+    req = urlParse(METHOD_GET, asres);
+    assert(NULL != req);
+    asState->request = requestLink(req);
+    if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
+	e = storeCreateEntry(asres, asres, null_request_flags, METHOD_GET);
+	asState->sc = storeClientListAdd(e, asState);
+	fwdStart(-1, e, asState->request);
+    } else {
+	storeLockObject(e);
+	asState->sc = storeClientListAdd(e, asState);
+    }
+    asState->entry = e;
+    asState->offset = 0;
+    asState->reqofs = 0;
+    readBuffer.offset = asState->offset;
+    readBuffer.length = AS_REQBUF_SZ;
+    readBuffer.data = asState->reqbuf;
+    storeClientCopy(asState->sc,
+	e,
+	readBuffer,
+	asHandleReply,
+	asState);
+}
+
+static void
+asHandleReply(void *data, StoreIOBuffer result)
+{
+    ASState *asState = (ASState *)data;
+    StoreEntry *e = asState->entry;
+    char *s;
+    char *t;
+    char *buf = asState->reqbuf;
+    int leftoversz = -1;
+
+    debug(53, 3) ("asHandleReply: Called with size=%u\n", result.length);
+    debug(53, 3) ("asHandleReply: buffer='%s'\n", buf);
+
+    /* First figure out whether we should abort the request */
+    if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
+	asStateFree(asState);
+	return;
+    }
+    if (result.length == 0 && e->mem_obj->inmem_hi > 0) {
+	asStateFree(asState);
+	return;
+    } else if (result.flags.error) {
+	debug(53, 1) ("asHandleReply: Called with Error set and size=%u\n", result.length);
+	asStateFree(asState);
+	return;
+    } else if (HTTP_OK != e->mem_obj->reply->sline.status) {
+	debug(53, 1) ("WARNING: AS %d whois request failed\n",
+	    asState->as_number);
+	asStateFree(asState);
+	return;
+    }
+    /*
+     * Next, attempt to parse our request
+     * Remembering that the actual buffer size is retsize + reqofs!
+     */
+    s = buf;
+    while (s - buf < (off_t)(result.length + asState->reqofs) && *s != '\0') {
+	while (*s && xisspace(*s))
+	    s++;
+	for (t = s; *t; t++) {
+	    if (xisspace(*t))
+		break;
+	}
+	if (*t == '\0') {
+	    /* oof, word should continue on next block */
+	    break;
+	}
+	*t = '\0';
+	debug(53, 3) ("asHandleReply: AS# %s (%d)\n", s, asState->as_number);
+	asnAddNet(s, asState->as_number);
+	s = t + 1;
+    }
+
+    /*
+     * Next, grab the end of the 'valid data' in the buffer, and figure
+     * out how much data is left in our buffer, which we need to keep
+     * around for the next request
+     */
+    leftoversz = (asState->reqofs + result.length) - (s - buf);
+    assert(leftoversz >= 0);
+
+    /*
+     * Next, copy the left over data, from s to s + leftoversz to the
+     * beginning of the buffer
+     */
+    xmemmove(buf, s, leftoversz);
+
+    /*
+     * Next, update our offset and reqofs, and kick off a copy if required
+     */
+    asState->offset += result.length;
+    asState->reqofs = leftoversz;
+    debug(53, 3) ("asState->offset = %ld\n", (long int) asState->offset);
+    if (e->store_status == STORE_PENDING) {
+	StoreIOBuffer tempBuffer = EMPTYIOBUFFER;
+	debug(53, 3) ("asHandleReply: store_status == STORE_PENDING: %s\n", storeUrl(e));
+	tempBuffer.offset = asState->offset;
+	tempBuffer.length = AS_REQBUF_SZ - asState->reqofs;
+	tempBuffer.data = asState->reqbuf + asState->reqofs;
+	storeClientCopy(asState->sc,
+	    e,
+	    tempBuffer,
+	    asHandleReply,
+	    asState);
+    } else if (asState->offset < e->mem_obj->inmem_hi) {
+	StoreIOBuffer tempBuffer = EMPTYIOBUFFER;
+	debug(53, 3) ("asHandleReply: asState->offset < e->mem_obj->inmem_hi %s\n", storeUrl(e));
+	tempBuffer.offset = asState->offset;
+	tempBuffer.length = AS_REQBUF_SZ - asState->reqofs;
+	tempBuffer.data = asState->reqbuf + asState->reqofs;
+	storeClientCopy(asState->sc,
+	    e,
+	    tempBuffer,
+	    asHandleReply,
+	    asState);
+    } else {
+	debug(53, 3) ("asHandleReply: Done: %s\n", storeUrl(e));
+	asStateFree(asState);
+    }
+}
+
+static void
+asStateFree(void *data)
+{
+    ASState *asState = (ASState *)data;
+    debug(53, 3) ("asnStateFree: %s\n", storeUrl(asState->entry));
+    storeUnregister(asState->sc, asState->entry, asState);
+    storeUnlockObject(asState->entry);
+    requestUnlink(asState->request);
+    cbdataFree(asState);
+}
+
+
+/* add a network (addr, mask) to the radix tree, with matching AS
+ * number */
+
+static int
+asnAddNet(char *as_string, int as_number)
+{
+    rtentry *e = (rtentry *)xmalloc(sizeof(rtentry));
+    struct squid_radix_node *rn;
+    char dbg1[32], dbg2[32];
+    intlist **Tail = NULL;
+    intlist *q = NULL;
+    as_info *asinfo = NULL;
+    struct in_addr in_a, in_m;
+    long mask, addr;
+    char *t;
+    int bitl;
+
+    t = strchr(as_string, '/');
+    if (t == NULL) {
+	debug(53, 3) ("asnAddNet: failed, invalid response from whois server.\n");
+	return 0;
+    }
+    *t = '\0';
+    addr = inet_addr(as_string);
+    bitl = atoi(t + 1);
+    if (bitl < 0)
+	bitl = 0;
+    if (bitl > 32)
+	bitl = 32;
+    mask = bitl ? 0xfffffffful << (32 - bitl) : 0;
+
+    in_a.s_addr = addr;
+    in_m.s_addr = mask;
+    xstrncpy(dbg1, inet_ntoa(in_a), 32);
+    xstrncpy(dbg2, inet_ntoa(in_m), 32);
+    addr = ntohl(addr);
+    /*mask = ntohl(mask); */
+    debug(53, 3) ("asnAddNet: called for %s/%s\n", dbg1, dbg2);
+    memset(e, '\0', sizeof(rtentry));
+    store_m_int(addr, e->e_addr);
+    store_m_int(mask, e->e_mask);
+    rn = squid_rn_lookup(e->e_addr, e->e_mask, AS_tree_head);
+    if (rn != NULL) {
+	asinfo = ((rtentry *) rn)->e_info;
+	if (intlistFind(asinfo->as_number, as_number)) {
+	    debug(53, 3) ("asnAddNet: Ignoring repeated network '%s/%d' for AS %d\n",
+		dbg1, bitl, as_number);
+	} else {
+	    debug(53, 3) ("asnAddNet: Warning: Found a network with multiple AS numbers!\n");
+	    for (Tail = &asinfo->as_number; *Tail; Tail = &(*Tail)->next);
+	    q = (intlist *)xcalloc(1, sizeof(intlist));
+	    q->i = as_number;
+	    *(Tail) = q;
+	    e->e_info = asinfo;
+	}
+    } else {
+	q = (intlist *)xcalloc(1, sizeof(intlist));
+	q->i = as_number;
+	asinfo = (as_info *)xmalloc(sizeof(asinfo));
+	asinfo->as_number = q;
+	rn = squid_rn_addroute(e->e_addr, e->e_mask, AS_tree_head, e->e_nodes);
+	rn = squid_rn_match(e->e_addr, AS_tree_head);
+	assert(rn != NULL);
+	e->e_info = asinfo;
+    }
+    if (rn == 0) {
+	xfree(e);
+	debug(53, 3) ("asnAddNet: Could not add entry.\n");
+	return 0;
+    }
+    e->e_info = asinfo;
+    return 1;
+}
+
+static int
+destroyRadixNode(struct squid_radix_node *rn, void *w)
+{
+    struct squid_radix_node_head *rnh = (struct squid_radix_node_head *) w;
+
+    if (rn && !(rn->rn_flags & RNF_ROOT)) {
+	rtentry *e = (rtentry *) rn;
+	rn = squid_rn_delete(rn->rn_key, rn->rn_mask, rnh);
+	if (rn == 0)
+	    debug(53, 3) ("destroyRadixNode: internal screwup\n");
+	destroyRadixNodeInfo(e->e_info);
+	xfree(rn);
+    }
+    return 1;
+}
+
+static void
+destroyRadixNodeInfo(as_info * e_info)
+{
+    intlist *prev = NULL;
+    intlist *data = e_info->as_number;
+    while (data) {
+	prev = data;
+	data = data->next;
+	xfree(prev);
+    }
+    xfree(data);
+}
+
+static int
+mask_len(u_long mask)
+{
+    int len = 32;
+    if (mask == 0)
+	return 0;
+    while ((mask & 1) == 0) {
+	len--;
+	mask >>= 1;
+    }
+    return len;
+}
+
+static int
+printRadixNode(struct squid_radix_node *rn, StoreEntry *sentry)
+{
+    rtentry *e = (rtentry *) rn;
+    intlist *q;
+    as_info *asinfo;
+    struct in_addr addr;
+    struct in_addr mask;
+    assert(e);
+    assert(e->e_info);
+    (void) get_m_int(addr.s_addr, e->e_addr);
+    (void) get_m_int(mask.s_addr, e->e_mask);
+    storeAppendPrintf(sentry, "%15s/%d\t",
+	inet_ntoa(addr), mask_len(ntohl(mask.s_addr)));
+    asinfo = e->e_info;
+    assert(asinfo->as_number);
+    for (q = asinfo->as_number; q; q = q->next)
+	storeAppendPrintf(sentry, " %d", q->i);
+    storeAppendPrintf(sentry, "\n");
+    return 0;
+}
--- squid/src/cache_diff.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,292 +0,0 @@
-
-/*
- * $Id: cache_diff.c,v 1.7 2002/09/01 16:30:41 squidadm Exp $
- *
- * AUTHOR: Alex Rousskov
- *
- * 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.
- *
- */
-
-/*
- * Computes the difference between the contents of two caches
- * using swap logs
- * Reports the percentage of common files and other stats
- */
-
-#include "squid.h"
-
-typedef struct {
-    const char *name;
-    hash_table *hash;
-    int count;			/* #currently cached entries */
-    int scanned_count;		/* #scanned entries */
-    int bad_add_count;		/* #duplicate adds */
-    int bad_del_count;		/* #dels with no prior add */
-} CacheIndex;
-
-
-typedef struct _CacheEntry {
-    const cache_key *key;
-    struct _CacheEntry *next;
-    /* storeSwapLogData s; */
-    unsigned char key_arr[MD5_DIGEST_CHARS];
-} CacheEntry;
-
-
-/* copied from url.c */
-const char *RequestMethodStr[] =
-{
-    "NONE",
-    "GET",
-    "POST",
-    "PUT",
-    "HEAD",
-    "CONNECT",
-    "TRACE",
-    "PURGE"
-};
-
-
-static int cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file);
-
-
-static CacheEntry *
-cacheEntryCreate(const storeSwapLogData * s)
-{
-    CacheEntry *e = xcalloc(1, sizeof(CacheEntry));
-    assert(s);
-    /* e->s = *s; */
-    xmemcpy(e->key_arr, s->key, MD5_DIGEST_CHARS);
-    e->key = &e->key_arr[0];
-    return e;
-}
-
-static void
-cacheEntryDestroy(CacheEntry * e)
-{
-    assert(e);
-    xfree(e);
-}
-
-static CacheIndex *
-cacheIndexCreate(const char *name)
-{
-    CacheIndex *idx;
-    if (!name || !strlen(name))
-	return NULL;
-
-    idx = xcalloc(1, sizeof(CacheIndex));
-    idx->name = name;
-    idx->hash = hash_create(storeKeyHashCmp, 2e6, storeKeyHashHash);
-
-    return idx;
-}
-
-static void
-cacheIndexDestroy(CacheIndex * idx)
-{
-    hash_link *hashr = NULL;
-    if (idx) {
-	/* destroy hash list contents */
-	hash_first(idx->hash);
-	while (hashr = hash_next(idx->hash)) {
-	    hash_remove_link(idx->hash, hashr);
-	    cacheEntryDestroy((CacheEntry *) hashr);
-	}
-	/* destroy the hash table itself */
-	hashFreeMemory(idx->hash);
-	xfree(idx);
-    }
-}
-
-static int
-cacheIndexAddLog(CacheIndex * idx, const char *fname)
-{
-    FILE *file;
-    int scanned_count = 0;
-    assert(idx);
-    assert(fname && strlen(fname));
-
-    file = fopen(fname, "r");
-    if (!file) {
-	fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno));
-	return 0;
-    }
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-    setmode(fileno(file), O_BINARY);
-#endif
-    scanned_count = cacheIndexScan(idx, fname, file);
-
-    fclose(file);
-    return scanned_count;
-}
-
-static void
-cacheIndexInitReport(CacheIndex * idx)
-{
-    assert(idx);
-    fprintf(stderr, "%s: bad swap_add:  %d\n",
-	idx->name, idx->bad_add_count);
-    fprintf(stderr, "%s: bad swap_del:  %d\n",
-	idx->name, idx->bad_del_count);
-    fprintf(stderr, "%s: scanned lines: %d\n",
-	idx->name, idx->scanned_count);
-}
-
-static int
-cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file)
-{
-    int count = 0;
-    storeSwapLogData s;
-    fprintf(stderr, "%s scanning\n", fname);
-    while (fread(&s, sizeof(s), 1, file) == 1) {
-	count++;
-	idx->scanned_count++;
-	/* if (s.op <= SWAP_LOG_NOP || s.op >= SWAP_LOG_MAX)
-	 * continue; */
-	if (s.op == SWAP_LOG_ADD) {
-	    CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key);
-	    if (olde) {
-		idx->bad_add_count++;
-	    } else {
-		CacheEntry *e = cacheEntryCreate(&s);
-		hash_join(idx->hash, &e->hash);
-		idx->count++;
-	    }
-	} else if (s.op == SWAP_LOG_DEL) {
-	    CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key);
-	    if (!olde)
-		idx->bad_del_count++;
-	    else {
-		assert(idx->count);
-		hash_remove_link(idx->hash, (hash_link *) olde);
-		cacheEntryDestroy(olde);
-		idx->count--;
-	    }
-	} else {
-	    fprintf(stderr, "%s:%d: unknown swap log action\n", fname, count);
-	    exit(-3);
-	}
-    }
-    fprintf(stderr, "%s:%d: scanned (size: %d bytes)\n",
-	fname, count, (int) (count * sizeof(CacheEntry)));
-    return count;
-}
-
-static void
-cacheIndexCmpReport(CacheIndex * idx, int shared_count)
-{
-    assert(idx && shared_count <= idx->count);
-
-    printf("%s:\t %7d = %7d + %7d (%7.2f%% + %7.2f%%)\n",
-	idx->name,
-	idx->count,
-	idx->count - shared_count,
-	shared_count,
-	xpercent(idx->count - shared_count, idx->count),
-	xpercent(shared_count, idx->count));
-}
-
-static void
-cacheIndexCmp(CacheIndex * idx1, CacheIndex * idx2)
-{
-    int shared_count = 0;
-    int hashed_count = 0;
-    hash_link *hashr = NULL;
-    CacheIndex *small_idx = idx1;
-    CacheIndex *large_idx = idx2;
-    assert(idx1 && idx2);
-
-    /* check our guess */
-    if (idx1->count > idx2->count) {
-	small_idx = idx2;
-	large_idx = idx1;
-    }
-    /* find shared_count */
-    hash_first(small_idx->hash);
-    for (hashr = hash_next(small_idx->hash)) {
-	hashed_count++;
-	if (hash_lookup(large_idx->hash, hashr->key))
-	    shared_count++;
-    }
-    assert(hashed_count == small_idx->count);
-
-    cacheIndexCmpReport(idx1, shared_count);
-    cacheIndexCmpReport(idx2, shared_count);
-}
-
-
-static int
-usage(const char *prg_name)
-{
-    fprintf(stderr, "usage: %s <label1>: <swap_state>... <label2>: <swap_state>...\n",
-	prg_name);
-    return -1;
-}
-
-int
-main(int argc, char *argv[])
-{
-    CacheIndex *CacheIdx[2];
-    CacheIndex *idx = NULL;
-    int idxCount = 0;
-    int i;
-
-    if (argc < 5)
-	return usage(argv[0]);
-
-    for (i = 1; i < argc; ++i) {
-	const int len = strlen(argv[i]);
-	if (!len)
-	    return usage(argv[0]);
-	if (argv[i][len - 1] == ':') {
-	    idxCount++;
-	    if (len < 2 || idxCount > 2)
-		return usage(argv[0]);
-	    idx = cacheIndexCreate(argv[i]);
-	    CacheIdx[idxCount - 1] = idx;
-	} else {
-	    if (!idx)
-		return usage(argv[0]);
-	    cacheIndexAddLog(idx, argv[i]);
-	}
-    }
-
-    if (idxCount != 2)
-	return usage(argv[0]);
-
-    cacheIndexInitReport(CacheIdx[0]);
-    cacheIndexInitReport(CacheIdx[1]);
-
-    cacheIndexCmp(CacheIdx[0], CacheIdx[1]);
-
-    cacheIndexDestroy(CacheIdx[0]);
-    cacheIndexDestroy(CacheIdx[1]);
-
-    return 1;
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/cache_diff.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,292 @@
+
+/*
+ * $Id: cache_diff.cc,v 1.1.2.1 2002/10/09 00:23:15 rbcollins Exp $
+ *
+ * AUTHOR: Alex Rousskov
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Computes the difference between the contents of two caches
+ * using swap logs
+ * Reports the percentage of common files and other stats
+ */
+
+#include "squid.h"
+
+typedef struct {
+    const char *name;
+    hash_table *hash;
+    int count;			/* #currently cached entries */
+    int scanned_count;		/* #scanned entries */
+    int bad_add_count;		/* #duplicate adds */
+    int bad_del_count;		/* #dels with no prior add */
+} CacheIndex;
+
+
+typedef struct _CacheEntry {
+    const cache_key *key;
+    struct _CacheEntry *next;
+    /* storeSwapLogData s; */
+    unsigned char key_arr[MD5_DIGEST_CHARS];
+} CacheEntry;
+
+
+/* copied from url.c */
+const char *RequestMethodStr[] =
+{
+    "NONE",
+    "GET",
+    "POST",
+    "PUT",
+    "HEAD",
+    "CONNECT",
+    "TRACE",
+    "PURGE"
+};
+
+
+static int cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file);
+
+
+static CacheEntry *
+cacheEntryCreate(const storeSwapLogData * s)
+{
+    CacheEntry *e = xcalloc(1, sizeof(CacheEntry));
+    assert(s);
+    /* e->s = *s; */
+    xmemcpy(e->key_arr, s->key, MD5_DIGEST_CHARS);
+    e->key = &e->key_arr[0];
+    return e;
+}
+
+static void
+cacheEntryDestroy(CacheEntry * e)
+{
+    assert(e);
+    xfree(e);
+}
+
+static CacheIndex *
+cacheIndexCreate(const char *name)
+{
+    CacheIndex *idx;
+    if (!name || !strlen(name))
+	return NULL;
+
+    idx = xcalloc(1, sizeof(CacheIndex));
+    idx->name = name;
+    idx->hash = hash_create(storeKeyHashCmp, 2e6, storeKeyHashHash);
+
+    return idx;
+}
+
+static void
+cacheIndexDestroy(CacheIndex * idx)
+{
+    hash_link *hashr = NULL;
+    if (idx) {
+	/* destroy hash list contents */
+	hash_first(idx->hash);
+	while (hashr = hash_next(idx->hash)) {
+	    hash_remove_link(idx->hash, hashr);
+	    cacheEntryDestroy((CacheEntry *) hashr);
+	}
+	/* destroy the hash table itself */
+	hashFreeMemory(idx->hash);
+	xfree(idx);
+    }
+}
+
+static int
+cacheIndexAddLog(CacheIndex * idx, const char *fname)
+{
+    FILE *file;
+    int scanned_count = 0;
+    assert(idx);
+    assert(fname && strlen(fname));
+
+    file = fopen(fname, "r");
+    if (!file) {
+	fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno));
+	return 0;
+    }
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+    setmode(fileno(file), O_BINARY);
+#endif
+    scanned_count = cacheIndexScan(idx, fname, file);
+
+    fclose(file);
+    return scanned_count;
+}
+
+static void
+cacheIndexInitReport(CacheIndex * idx)
+{
+    assert(idx);
+    fprintf(stderr, "%s: bad swap_add:  %d\n",
+	idx->name, idx->bad_add_count);
+    fprintf(stderr, "%s: bad swap_del:  %d\n",
+	idx->name, idx->bad_del_count);
+    fprintf(stderr, "%s: scanned lines: %d\n",
+	idx->name, idx->scanned_count);
+}
+
+static int
+cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file)
+{
+    int count = 0;
+    storeSwapLogData s;
+    fprintf(stderr, "%s scanning\n", fname);
+    while (fread(&s, sizeof(s), 1, file) == 1) {
+	count++;
+	idx->scanned_count++;
+	/* if (s.op <= SWAP_LOG_NOP || s.op >= SWAP_LOG_MAX)
+	 * continue; */
+	if (s.op == SWAP_LOG_ADD) {
+	    CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key);
+	    if (olde) {
+		idx->bad_add_count++;
+	    } else {
+		CacheEntry *e = cacheEntryCreate(&s);
+		hash_join(idx->hash, &e->hash);
+		idx->count++;
+	    }
+	} else if (s.op == SWAP_LOG_DEL) {
+	    CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key);
+	    if (!olde)
+		idx->bad_del_count++;
+	    else {
+		assert(idx->count);
+		hash_remove_link(idx->hash, (hash_link *) olde);
+		cacheEntryDestroy(olde);
+		idx->count--;
+	    }
+	} else {
+	    fprintf(stderr, "%s:%d: unknown swap log action\n", fname, count);
+	    exit(-3);
+	}
+    }
+    fprintf(stderr, "%s:%d: scanned (size: %d bytes)\n",
+	fname, count, (int) (count * sizeof(CacheEntry)));
+    return count;
+}
+
+static void
+cacheIndexCmpReport(CacheIndex * idx, int shared_count)
+{
+    assert(idx && shared_count <= idx->count);
+
+    printf("%s:\t %7d = %7d + %7d (%7.2f%% + %7.2f%%)\n",
+	idx->name,
+	idx->count,
+	idx->count - shared_count,
+	shared_count,
+	xpercent(idx->count - shared_count, idx->count),
+	xpercent(shared_count, idx->count));
+}
+
+static void
+cacheIndexCmp(CacheIndex * idx1, CacheIndex * idx2)
+{
+    int shared_count = 0;
+    int hashed_count = 0;
+    hash_link *hashr = NULL;
+    CacheIndex *small_idx = idx1;
+    CacheIndex *large_idx = idx2;
+    assert(idx1 && idx2);
+
+    /* check our guess */
+    if (idx1->count > idx2->count) {
+	small_idx = idx2;
+	large_idx = idx1;
+    }
+    /* find shared_count */
+    hash_first(small_idx->hash);
+    for (hashr = hash_next(small_idx->hash)) {
+	hashed_count++;
+	if (hash_lookup(large_idx->hash, hashr->key))
+	    shared_count++;
+    }
+    assert(hashed_count == small_idx->count);
+
+    cacheIndexCmpReport(idx1, shared_count);
+    cacheIndexCmpReport(idx2, shared_count);
+}
+
+
+static int
+usage(const char *prg_name)
+{
+    fprintf(stderr, "usage: %s <label1>: <swap_state>... <label2>: <swap_state>...\n",
+	prg_name);
+    return -1;
+}
+
+int
+main(int argc, char *argv[])
+{
+    CacheIndex *CacheIdx[2];
+    CacheIndex *idx = NULL;
+    int idxCount = 0;
+    int i;
+
+    if (argc < 5)
+	return usage(argv[0]);
+
+    for (i = 1; i < argc; ++i) {
+	const int len = strlen(argv[i]);
+	if (!len)
+	    return usage(argv[0]);
+	if (argv[i][len - 1] == ':') {
+	    idxCount++;
+	    if (len < 2 || idxCount > 2)
+		return usage(argv[0]);
+	    idx = cacheIndexCreate(argv[i]);
+	    CacheIdx[idxCount - 1] = idx;
+	} else {
+	    if (!idx)
+		return usage(argv[0]);
+	    cacheIndexAddLog(idx, argv[i]);
+	}
+    }
+
+    if (idxCount != 2)
+	return usage(argv[0]);
+
+    cacheIndexInitReport(CacheIdx[0]);
+    cacheIndexInitReport(CacheIdx[1]);
+
+    cacheIndexCmp(CacheIdx[0], CacheIdx[1]);
+
+    cacheIndexDestroy(CacheIdx[0]);
+    cacheIndexDestroy(CacheIdx[1]);
+
+    return 1;
+}
--- squid/src/cache_manager.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,350 +0,0 @@
-
-/*
- * $Id: cache_manager.c,v 1.7.84.1 2002/10/04 07:07:20 rbcollins Exp $
- *
- * DEBUG: section 16    Cache Manager Objects
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "Store.h"
-
-#define MGR_PASSWD_SZ 128
-
-typedef struct {
-    StoreEntry *entry;
-    char *action;
-    char *user_name;
-    char *passwd;
-} cachemgrStateData;
-
-typedef struct _action_table {
-    char *action;
-    char *desc;
-    OBJH *handler;
-    struct {
-	unsigned int pw_req:1;
-	unsigned int atomic:1;
-    } flags;
-    struct _action_table *next;
-} action_table;
-
-static action_table *cachemgrFindAction(const char *action);
-static cachemgrStateData *cachemgrParseUrl(const char *url);
-static void cachemgrParseHeaders(cachemgrStateData * mgr, const request_t * request);
-static int cachemgrCheckPassword(cachemgrStateData *);
-static void cachemgrStateFree(cachemgrStateData * mgr);
-static char *cachemgrPasswdGet(cachemgr_passwd *, const char *);
-static const char *cachemgrActionProtection(const action_table * at);
-static OBJH cachemgrShutdown;
-static OBJH cachemgrMenu;
-static OBJH cachemgrOfflineToggle;
-
-action_table *ActionTable = NULL;
-
-void
-cachemgrRegister(const char *action, const char *desc, OBJH * handler, int pw_req_flag, int atomic)
-{
-    action_table *a;
-    action_table **A;
-    if (cachemgrFindAction(action) != NULL) {
-	debug(16, 3) ("cachemgrRegister: Duplicate '%s'\n", action);
-	return;
-    }
-    a = xcalloc(1, sizeof(action_table));
-    a->action = xstrdup(action);
-    a->desc = xstrdup(desc);
-    a->handler = handler;
-    a->flags.pw_req = pw_req_flag;
-    a->flags.atomic = atomic;
-    for (A = &ActionTable; *A; A = &(*A)->next);
-    *A = a;
-    debug(16, 3) ("cachemgrRegister: registered %s\n", action);
-}
-
-static action_table *
-cachemgrFindAction(const char *action)
-{
-    action_table *a;
-    for (a = ActionTable; a != NULL; a = a->next) {
-	if (0 == strcmp(a->action, action))
-	    return a;
-    }
-    return NULL;
-}
-
-static cachemgrStateData *
-cachemgrParseUrl(const char *url)
-{
-    int t;
-    LOCAL_ARRAY(char, host, MAX_URL);
-    LOCAL_ARRAY(char, request, MAX_URL);
-    LOCAL_ARRAY(char, password, MAX_URL);
-    action_table *a;
-    cachemgrStateData *mgr = NULL;
-    const char *prot;
-    t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password);
-    if (t < 2) {
-	xstrncpy(request, "menu", MAX_URL);
-#ifdef _SQUID_OS2_
-	/*
-	 * emx's sscanf insists of returning 2 because it sets request
-	 * to null
-	 */
-    } else if (request[0] == '\0') {
-	xstrncpy(request, "menu", MAX_URL);
-#endif
-    } else if ((a = cachemgrFindAction(request)) == NULL) {
-	debug(16, 1) ("cachemgrParseUrl: action '%s' not found\n", request);
-	return NULL;
-    } else {
-	prot = cachemgrActionProtection(a);
-	if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
-	    debug(16, 1) ("cachemgrParseUrl: action '%s' is %s\n", request, prot);
-	    return NULL;
-	}
-    }
-    /* set absent entries to NULL so we can test if they are present later */
-    mgr = xcalloc(1, sizeof(cachemgrStateData));
-    mgr->user_name = NULL;
-    mgr->passwd = t == 3 ? xstrdup(password) : NULL;
-    mgr->action = xstrdup(request);
-    return mgr;
-}
-
-static void
-cachemgrParseHeaders(cachemgrStateData * mgr, const request_t * request)
-{
-    const char *basic_cookie;	/* base 64 _decoded_ user:passwd pair */
-    const char *passwd_del;
-    assert(mgr && request);
-    basic_cookie = httpHeaderGetAuth(&request->header, HDR_AUTHORIZATION, "Basic");
-    if (!basic_cookie)
-	return;
-    if (!(passwd_del = strchr(basic_cookie, ':'))) {
-	debug(16, 1) ("cachemgrParseHeaders: unknown basic_cookie format '%s'\n", basic_cookie);
-	return;
-    }
-    /* found user:password pair, reset old values */
-    safe_free(mgr->user_name);
-    safe_free(mgr->passwd);
-    mgr->user_name = xstrdup(basic_cookie);
-    mgr->user_name[passwd_del - basic_cookie] = '\0';
-    mgr->passwd = xstrdup(passwd_del + 1);
-    /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */
-    debug(16, 9) ("cachemgrParseHeaders: got user: '%s' passwd: '%s'\n", mgr->user_name, mgr->passwd);
-}
-
-/*
- * return 0 if mgr->password is good
- */
-static int
-cachemgrCheckPassword(cachemgrStateData * mgr)
-{
-    char *pwd = cachemgrPasswdGet(Config.passwd_list, mgr->action);
-    action_table *a = cachemgrFindAction(mgr->action);
-    assert(a != NULL);
-    if (pwd == NULL)
-	return a->flags.pw_req;
-    if (strcmp(pwd, "disable") == 0)
-	return 1;
-    if (strcmp(pwd, "none") == 0)
-	return 0;
-    if (!mgr->passwd)
-	return 1;
-    return strcmp(pwd, mgr->passwd);
-}
-
-static void
-cachemgrStateFree(cachemgrStateData * mgr)
-{
-    safe_free(mgr->action);
-    safe_free(mgr->user_name);
-    safe_free(mgr->passwd);
-    storeUnlockObject(mgr->entry);
-    xfree(mgr);
-}
-
-void
-cachemgrStart(int fd, request_t * request, StoreEntry * entry)
-{
-    cachemgrStateData *mgr = NULL;
-    ErrorState *err = NULL;
-    action_table *a;
-    debug(16, 3) ("objectcacheStart: '%s'\n", storeUrl(entry));
-    if ((mgr = cachemgrParseUrl(storeUrl(entry))) == NULL) {
-	err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND);
-	err->url = xstrdup(storeUrl(entry));
-	errorAppendEntry(entry, err);
-	entry->expires = squid_curtime;
-	return;
-    }
-    mgr->entry = entry;
-    storeLockObject(entry);
-    entry->expires = squid_curtime;
-    debug(16, 5) ("CACHEMGR: %s requesting '%s'\n",
-	fd_table[fd].ipaddr, mgr->action);
-    /* get additional info from request headers */
-    cachemgrParseHeaders(mgr, request);
-    /* Check password */
-    if (cachemgrCheckPassword(mgr) != 0) {
-	/* build error message */
-	ErrorState *err;
-	HttpReply *rep;
-	err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED);
-	/* warn if user specified incorrect password */
-	if (mgr->passwd)
-	    debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n",
-		mgr->user_name ? mgr->user_name : "<unknown>",
-		fd_table[fd].ipaddr, mgr->action);
-	else
-	    debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n",
-		mgr->user_name ? mgr->user_name : "<unknown>",
-		fd_table[fd].ipaddr, mgr->action);
-	err->request = requestLink(request);
-	rep = errorBuildReply(err);
-	errorStateFree(err);
-	/*
-	 * add Authenticate header, use 'action' as a realm because
-	 * password depends on action
-	 */
-	httpHeaderPutAuth(&rep->header, "Basic", mgr->action);
-	/* move info to the mem_obj->reply */
-	httpReplyAbsorb(entry->mem_obj->reply, rep);
-	/* store the reply */
-	httpReplySwapOut(entry->mem_obj->reply, entry);
-	entry->expires = squid_curtime;
-	storeComplete(entry);
-	cachemgrStateFree(mgr);
-	return;
-    }
-    debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n",
-	mgr->user_name ? mgr->user_name : "<unknown>",
-	fd_table[fd].ipaddr, mgr->action);
-    /* retrieve object requested */
-    a = cachemgrFindAction(mgr->action);
-    assert(a != NULL);
-    if (a->flags.atomic)
-	storeBuffer(entry);
-    {
-	http_version_t version;
-	HttpReply *rep = entry->mem_obj->reply;
-	/* prove there are no previous reply headers around */
-	assert(0 == rep->sline.status);
-	httpBuildVersion(&version, 1, 0);
-	httpReplySetHeaders(rep,
-	    version,
-	    HTTP_OK,
-	    NULL,
-	    "text/plain",
-	    -1,			/* C-Len */
-	    squid_curtime,	/* LMT */
-	    squid_curtime);
-	httpReplySwapOut(rep, entry);
-    }
-    a->handler(entry);
-    if (a->flags.atomic) {
-	storeBufferFlush(entry);
-	storeComplete(entry);
-    }
-    cachemgrStateFree(mgr);
-}
-
-static void
-cachemgrShutdown(StoreEntry * entryunused)
-{
-    debug(16, 0) ("Shutdown by command.\n");
-    shut_down(0);
-}
-
-static void
-cachemgrOfflineToggle(StoreEntry * sentry)
-{
-    Config.onoff.offline = !Config.onoff.offline;
-    debug(16, 0) ("offline_mode now %s.\n",
-	Config.onoff.offline ? "ON" : "OFF");
-    storeAppendPrintf(sentry, "offline_mode is now %s\n",
-	Config.onoff.offline ? "ON" : "OFF");
-}
-
-static const char *
-cachemgrActionProtection(const action_table * at)
-{
-    char *pwd;
-    assert(at);
-    pwd = cachemgrPasswdGet(Config.passwd_list, at->action);
-    if (!pwd)
-	return at->flags.pw_req ? "hidden" : "public";
-    if (!strcmp(pwd, "disable"))
-	return "disabled";
-    if (strcmp(pwd, "none") == 0)
-	return "public";
-    return "protected";
-}
-
-static void
-cachemgrMenu(StoreEntry * sentry)
-{
-    action_table *a;
-    for (a = ActionTable; a != NULL; a = a->next) {
-	storeAppendPrintf(sentry, " %-22s\t%s\t%s\n",
-	    a->action, a->desc, cachemgrActionProtection(a));
-    }
-}
-
-static char *
-cachemgrPasswdGet(cachemgr_passwd * a, const char *action)
-{
-    wordlist *w;
-    while (a != NULL) {
-	for (w = a->actions; w != NULL; w = w->next) {
-	    if (0 == strcmp(w->key, action))
-		return a->passwd;
-	    if (0 == strcmp(w->key, "all"))
-		return a->passwd;
-	}
-	a = a->next;
-    }
-    return NULL;
-}
-
-void
-cachemgrInit(void)
-{
-    cachemgrRegister("menu",
-	"This Cachemanager Menu",
-	cachemgrMenu, 0, 1);
-    cachemgrRegister("shutdown",
-	"Shut Down the Squid Process",
-	cachemgrShutdown, 1, 1);
-    cachemgrRegister("offline_toggle",
-	"Toggle offline_mode setting",
-	cachemgrOfflineToggle, 1, 1);
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/cache_manager.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,350 @@
+
+/*
+ * $Id: cache_manager.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 16    Cache Manager Objects
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "Store.h"
+
+#define MGR_PASSWD_SZ 128
+
+typedef struct {
+    StoreEntry *entry;
+    char *action;
+    char *user_name;
+    char *passwd;
+} cachemgrStateData;
+
+typedef struct _action_table {
+    char *action;
+    char *desc;
+    OBJH *handler;
+    struct {
+	unsigned int pw_req:1;
+	unsigned int atomic:1;
+    } flags;
+    struct _action_table *next;
+} action_table;
+
+static action_table *cachemgrFindAction(const char *action);
+static cachemgrStateData *cachemgrParseUrl(const char *url);
+static void cachemgrParseHeaders(cachemgrStateData * mgr, const request_t * request);
+static int cachemgrCheckPassword(cachemgrStateData *);
+static void cachemgrStateFree(cachemgrStateData * mgr);
+static char *cachemgrPasswdGet(cachemgr_passwd *, const char *);
+static const char *cachemgrActionProtection(const action_table * at);
+static OBJH cachemgrShutdown;
+static OBJH cachemgrMenu;
+static OBJH cachemgrOfflineToggle;
+
+action_table *ActionTable = NULL;
+
+void
+cachemgrRegister(const char *action, const char *desc, OBJH * handler, int pw_req_flag, int atomic)
+{
+    action_table *a;
+    action_table **A;
+    if (cachemgrFindAction(action) != NULL) {
+	debug(16, 3) ("cachemgrRegister: Duplicate '%s'\n", action);
+	return;
+    }
+    a = (action_table *)xcalloc(1, sizeof(action_table));
+    a->action = xstrdup(action);
+    a->desc = xstrdup(desc);
+    a->handler = handler;
+    a->flags.pw_req = pw_req_flag;
+    a->flags.atomic = atomic;
+    for (A = &ActionTable; *A; A = &(*A)->next);
+    *A = a;
+    debug(16, 3) ("cachemgrRegister: registered %s\n", action);
+}
+
+static action_table *
+cachemgrFindAction(const char *action)
+{
+    action_table *a;
+    for (a = ActionTable; a != NULL; a = a->next) {
+	if (0 == strcmp(a->action, action))
+	    return a;
+    }
+    return NULL;
+}
+
+static cachemgrStateData *
+cachemgrParseUrl(const char *url)
+{
+    int t;
+    LOCAL_ARRAY(char, host, MAX_URL);
+    LOCAL_ARRAY(char, request, MAX_URL);
+    LOCAL_ARRAY(char, password, MAX_URL);
+    action_table *a;
+    cachemgrStateData *mgr = NULL;
+    const char *prot;
+    t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password);
+    if (t < 2) {
+	xstrncpy(request, "menu", MAX_URL);
+#ifdef _SQUID_OS2_
+	/*
+	 * emx's sscanf insists of returning 2 because it sets request
+	 * to null
+	 */
+    } else if (request[0] == '\0') {
+	xstrncpy(request, "menu", MAX_URL);
+#endif
+    } else if ((a = cachemgrFindAction(request)) == NULL) {
+	debug(16, 1) ("cachemgrParseUrl: action '%s' not found\n", request);
+	return NULL;
+    } else {
+	prot = cachemgrActionProtection(a);
+	if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
+	    debug(16, 1) ("cachemgrParseUrl: action '%s' is %s\n", request, prot);
+	    return NULL;
+	}
+    }
+    /* set absent entries to NULL so we can test if they are present later */
+    mgr = (cachemgrStateData *)xcalloc(1, sizeof(cachemgrStateData));
+    mgr->user_name = NULL;
+    mgr->passwd = t == 3 ? xstrdup(password) : NULL;
+    mgr->action = xstrdup(request);
+    return mgr;
+}
+
+static void
+cachemgrParseHeaders(cachemgrStateData * mgr, const request_t * request)
+{
+    const char *basic_cookie;	/* base 64 _decoded_ user:passwd pair */
+    const char *passwd_del;
+    assert(mgr && request);
+    basic_cookie = httpHeaderGetAuth(&request->header, HDR_AUTHORIZATION, "Basic");
+    if (!basic_cookie)
+	return;
+    if (!(passwd_del = strchr(basic_cookie, ':'))) {
+	debug(16, 1) ("cachemgrParseHeaders: unknown basic_cookie format '%s'\n", basic_cookie);
+	return;
+    }
+    /* found user:password pair, reset old values */
+    safe_free(mgr->user_name);
+    safe_free(mgr->passwd);
+    mgr->user_name = xstrdup(basic_cookie);
+    mgr->user_name[passwd_del - basic_cookie] = '\0';
+    mgr->passwd = xstrdup(passwd_del + 1);
+    /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */
+    debug(16, 9) ("cachemgrParseHeaders: got user: '%s' passwd: '%s'\n", mgr->user_name, mgr->passwd);
+}
+
+/*
+ * return 0 if mgr->password is good
+ */
+static int
+cachemgrCheckPassword(cachemgrStateData * mgr)
+{
+    char *pwd = cachemgrPasswdGet(Config.passwd_list, mgr->action);
+    action_table *a = cachemgrFindAction(mgr->action);
+    assert(a != NULL);
+    if (pwd == NULL)
+	return a->flags.pw_req;
+    if (strcmp(pwd, "disable") == 0)
+	return 1;
+    if (strcmp(pwd, "none") == 0)
+	return 0;
+    if (!mgr->passwd)
+	return 1;
+    return strcmp(pwd, mgr->passwd);
+}
+
+static void
+cachemgrStateFree(cachemgrStateData * mgr)
+{
+    safe_free(mgr->action);
+    safe_free(mgr->user_name);
+    safe_free(mgr->passwd);
+    storeUnlockObject(mgr->entry);
+    xfree(mgr);
+}
+
+void
+cachemgrStart(int fd, request_t * request, StoreEntry * entry)
+{
+    cachemgrStateData *mgr = NULL;
+    ErrorState *err = NULL;
+    action_table *a;
+    debug(16, 3) ("objectcacheStart: '%s'\n", storeUrl(entry));
+    if ((mgr = cachemgrParseUrl(storeUrl(entry))) == NULL) {
+	err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND);
+	err->url = xstrdup(storeUrl(entry));
+	errorAppendEntry(entry, err);
+	entry->expires = squid_curtime;
+	return;
+    }
+    mgr->entry = entry;
+    storeLockObject(entry);
+    entry->expires = squid_curtime;
+    debug(16, 5) ("CACHEMGR: %s requesting '%s'\n",
+	fd_table[fd].ipaddr, mgr->action);
+    /* get additional info from request headers */
+    cachemgrParseHeaders(mgr, request);
+    /* Check password */
+    if (cachemgrCheckPassword(mgr) != 0) {
+	/* build error message */
+	ErrorState *err;
+	HttpReply *rep;
+	err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED);
+	/* warn if user specified incorrect password */
+	if (mgr->passwd)
+	    debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n",
+		mgr->user_name ? mgr->user_name : "<unknown>",
+		fd_table[fd].ipaddr, mgr->action);
+	else
+	    debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n",
+		mgr->user_name ? mgr->user_name : "<unknown>",
+		fd_table[fd].ipaddr, mgr->action);
+	err->request = requestLink(request);
+	rep = errorBuildReply(err);
+	errorStateFree(err);
+	/*
+	 * add Authenticate header, use 'action' as a realm because
+	 * password depends on action
+	 */
+	httpHeaderPutAuth(&rep->header, "Basic", mgr->action);
+	/* move info to the mem_obj->reply */
+	httpReplyAbsorb(entry->mem_obj->reply, rep);
+	/* store the reply */
+	httpReplySwapOut(entry->mem_obj->reply, entry);
+	entry->expires = squid_curtime;
+	storeComplete(entry);
+	cachemgrStateFree(mgr);
+	return;
+    }
+    debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n",
+	mgr->user_name ? mgr->user_name : "<unknown>",
+	fd_table[fd].ipaddr, mgr->action);
+    /* retrieve object requested */
+    a = cachemgrFindAction(mgr->action);
+    assert(a != NULL);
+    if (a->flags.atomic)
+	storeBuffer(entry);
+    {
+	http_version_t version;
+	HttpReply *rep = entry->mem_obj->reply;
+	/* prove there are no previous reply headers around */
+	assert(0 == rep->sline.status);
+	httpBuildVersion(&version, 1, 0);
+	httpReplySetHeaders(rep,
+	    version,
+	    HTTP_OK,
+	    NULL,
+	    "text/plain",
+	    -1,			/* C-Len */
+	    squid_curtime,	/* LMT */
+	    squid_curtime);
+	httpReplySwapOut(rep, entry);
+    }
+    a->handler(entry);
+    if (a->flags.atomic) {
+	storeBufferFlush(entry);
+	storeComplete(entry);
+    }
+    cachemgrStateFree(mgr);
+}
+
+static void
+cachemgrShutdown(StoreEntry * entryunused)
+{
+    debug(16, 0) ("Shutdown by command.\n");
+    shut_down(0);
+}
+
+static void
+cachemgrOfflineToggle(StoreEntry * sentry)
+{
+    Config.onoff.offline = !Config.onoff.offline;
+    debug(16, 0) ("offline_mode now %s.\n",
+	Config.onoff.offline ? "ON" : "OFF");
+    storeAppendPrintf(sentry, "offline_mode is now %s\n",
+	Config.onoff.offline ? "ON" : "OFF");
+}
+
+static const char *
+cachemgrActionProtection(const action_table * at)
+{
+    char *pwd;
+    assert(at);
+    pwd = cachemgrPasswdGet(Config.passwd_list, at->action);
+    if (!pwd)
+	return at->flags.pw_req ? "hidden" : "public";
+    if (!strcmp(pwd, "disable"))
+	return "disabled";
+    if (strcmp(pwd, "none") == 0)
+	return "public";
+    return "protected";
+}
+
+static void
+cachemgrMenu(StoreEntry * sentry)
+{
+    action_table *a;
+    for (a = ActionTable; a != NULL; a = a->next) {
+	storeAppendPrintf(sentry, " %-22s\t%s\t%s\n",
+	    a->action, a->desc, cachemgrActionProtection(a));
+    }
+}
+
+static char *
+cachemgrPasswdGet(cachemgr_passwd * a, const char *action)
+{
+    wordlist *w;
+    while (a != NULL) {
+	for (w = a->actions; w != NULL; w = w->next) {
+	    if (0 == strcmp(w->key, action))
+		return a->passwd;
+	    if (0 == strcmp(w->key, "all"))
+		return a->passwd;
+	}
+	a = a->next;
+    }
+    return NULL;
+}
+
+void
+cachemgrInit(void)
+{
+    cachemgrRegister("menu",
+	"This Cachemanager Menu",
+	cachemgrMenu, 0, 1);
+    cachemgrRegister("shutdown",
+	"Shut Down the Squid Process",
+	cachemgrShutdown, 1, 1);
+    cachemgrRegister("offline_toggle",
+	"Toggle offline_mode setting",
+	cachemgrOfflineToggle, 1, 1);
+}
--- squid/src/cachemgr.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,753 +0,0 @@
-
-/*
- * $Id: cachemgr.c,v 1.13 2002/09/01 16:30:41 squidadm Exp $
- *
- * DEBUG: section 0     CGI Cache Manager
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "config.h"
-
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-#if HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#if HAVE_GRP_H
-#include <grp.h>
-#endif
-#if HAVE_GNUMALLOC_H
-#include <gnumalloc.h>
-#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
-#include <malloc.h>
-#endif
-#if HAVE_MEMORY_H
-#include <memory.h>
-#endif
-#if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_)	/* protect NEXTSTEP */
-#define _SQUID_NETDB_H_
-#include <netdb.h>
-#endif
-#if HAVE_PWD_H
-#include <pwd.h>
-#endif
-#if HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#if HAVE_TIME_H
-#include <time.h>
-#endif
-#if HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#if HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>	/* needs sys/time.h above it */
-#endif
-#if HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#if HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#if HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#if HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#if HAVE_SYS_UN_H
-#include <sys/un.h>
-#endif
-#if HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-#if HAVE_LIBC_H
-#include <libc.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
-#if HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#if HAVE_BSTRING_H
-#include <bstring.h>
-#endif
-#if HAVE_CRYPT_H
-#include <crypt.h>
-#endif
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#include <assert.h>
-
-#include "util.h"
-#include "snprintf.h"
-
-typedef struct {
-    char *hostname;
-    int port;
-    char *action;
-    char *user_name;
-    char *passwd;
-    char *pub_auth;
-} cachemgr_request;
-
-/*
- * Debugging macros (info goes to error_log on your web server)
- * Note: do not run cache manager with non zero debugging level 
- *       if you do not debug, it may write a lot of [sensitive]
- *       information to your error log.
- */
-
-/* debugging level 0 (disabled) - 3 (max) */
-#define DEBUG_LEVEL 0
-#define debug(level) if ((level) <= DEBUG_LEVEL && DEBUG_LEVEL > 0)
-
-/*
- * Static variables and constants
- */
-static const time_t passwd_ttl = 60 * 60 * 3;	/* in sec */
-static const char *script_name = "/cgi-bin/cachemgr.cgi";
-static const char *progname = NULL;
-static time_t now;
-static struct in_addr no_addr;
-
-/*
- * Function prototypes
- */
-#define safe_free(str) { if (str) { xfree(str); (str) = NULL; } }
-static const char *safe_str(const char *str);
-static const char *xstrtok(char **str, char del);
-static void print_trailer(void);
-static void auth_html(const char *host, int port, const char *user_name);
-static void error_html(const char *msg);
-static char *menu_url(cachemgr_request * req, const char *action);
-static int parse_status_line(const char *sline, const char **statusStr);
-static cachemgr_request *read_request(void);
-static char *read_get_request(void);
-static char *read_post_request(void);
-
-static void make_pub_auth(cachemgr_request * req);
-static void decode_pub_auth(cachemgr_request * req);
-static void reset_auth(cachemgr_request * req);
-static const char *make_auth_header(const cachemgr_request * req);
-
-
-static const char *
-safe_str(const char *str)
-{
-    return str ? str : "";
-}
-
-/* relaxed number format */
-static int
-is_number(const char *str)
-{
-    return strspn(str, "\t -+01234567890./\n") == strlen(str);
-}
-
-static const char *
-xstrtok(char **str, char del)
-{
-    if (*str) {
-	char *p = strchr(*str, del);
-	char *tok = *str;
-	int len;
-	if (p) {
-	    *str = p + 1;
-	    *p = '\0';
-	} else
-	    *str = NULL;
-	/* trim */
-	len = strlen(tok);
-	while (len && xisspace(tok[len - 1]))
-	    tok[--len] = '\0';
-	while (xisspace(*tok))
-	    tok++;
-	return tok;
-    } else
-	return "";
-}
-
-static void
-print_trailer(void)
-{
-    printf("<HR noshade size=\"1px\">\n");
-    printf("<ADDRESS>\n");
-    printf("Generated %s, by %s/%s@%s\n",
-	mkrfc1123(now), progname, VERSION, getfullhostname());
-    printf("</ADDRESS></BODY></HTML>\n");
-}
-
-static void
-auth_html(const char *host, int port, const char *user_name)
-{
-    if (!user_name)
-	user_name = "";
-    if (!host || !strlen(host))
-	host = "localhost";
-    printf("Content-Type: text/html\r\n\r\n");
-    printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
-    printf("<HTML><HEAD><TITLE>Cache Manager Interface</TITLE>\n");
-    printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE></HEAD>\n");
-    printf("<BODY><H1>Cache Manager Interface</H1>\n");
-    printf("<P>This is a WWW interface to the instrumentation interface\n");
-    printf("for the Squid object cache.</P>\n");
-    printf("<HR noshade size=\"1px\">\n");
-    printf("<FORM METHOD=\"GET\" ACTION=\"%s\">\n", script_name);
-    printf("<TABLE BORDER=\"0\" CELLPADDING=\"10\" CELLSPACING=\"1\">\n");
-    printf("<TR><TH ALIGN=\"left\">Cache Host:</TH><TD><INPUT NAME=\"host\" ");
-    printf("size=\"30\" VALUE=\"%s\"></TD></TR>\n", host);
-    printf("<TR><TH ALIGN=\"left\">Cache Port:</TH><TD><INPUT NAME=\"port\" ");
-    printf("size=\"30\" VALUE=\"%d\"></TD></TR>\n", port);
-    printf("<TR><TH ALIGN=\"left\">Manager name:</TH><TD><INPUT NAME=\"user_name\" ");
-    printf("size=\"30\" VALUE=\"%s\"></TD></TR>\n", user_name);
-    printf("<TR><TH ALIGN=\"left\">Password:</TH><TD><INPUT TYPE=\"password\" NAME=\"passwd\" ");
-    printf("size=\"30\" VALUE=\"\"></TD></TR>\n");
-    printf("</TABLE><BR CLEAR=\"all\">\n");
-    printf("<INPUT TYPE=\"submit\" VALUE=\"Continue...\">\n");
-    printf("</FORM>\n");
-    print_trailer();
-}
-
-static void
-error_html(const char *msg)
-{
-    printf("Content-Type: text/html\r\n\r\n");
-    printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
-    printf("<HTML><HEAD><TITLE>Cache Manager Error</TITLE>\n");
-    printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE></HEAD>\n");
-    printf("<BODY><H1>Cache Manager Error</H1>\n");
-    printf("<P>\n%s</P>\n", msg);
-    print_trailer();
-}
-
-/* returns http status extracted from status line or -1 on parsing failure */
-static int
-parse_status_line(const char *sline, const char **statusStr)
-{
-    const char *sp = strchr(sline, ' ');
-    if (statusStr)
-	*statusStr = NULL;
-    if (strncasecmp(sline, "HTTP/", 5) || !sp)
-	return -1;
-    while (xisspace(*++sp));
-    if (!xisdigit(*sp))
-	return -1;
-    if (statusStr)
-	*statusStr = sp;
-    return atoi(sp);
-}
-
-static char *
-menu_url(cachemgr_request * req, const char *action)
-{
-    static char url[1024];
-    snprintf(url, sizeof(url), "%s?host=%s&port=%d&user_name=%s&operation=%s&auth=%s",
-	script_name,
-	req->hostname,
-	req->port,
-	safe_str(req->user_name),
-	action,
-	safe_str(req->pub_auth));
-    return url;
-}
-
-static const char *
-munge_menu_line(const char *buf, cachemgr_request * req)
-{
-    char *x;
-    const char *a;
-    const char *d;
-    const char *p;
-    char *a_url;
-    char *buf_copy;
-    static char html[2 * 1024];
-    if (strlen(buf) < 1)
-	return buf;
-    if (*buf != ' ')
-	return buf;
-    buf_copy = x = xstrdup(buf);
-    a = xstrtok(&x, '\t');
-    d = xstrtok(&x, '\t');
-    p = xstrtok(&x, '\t');
-    a_url = xstrdup(menu_url(req, a));
-    /* no reason to give a url for a disabled action */
-    if (!strcmp(p, "disabled"))
-	snprintf(html, sizeof(html), "<LI type=\"circle\">%s (disabled)<A HREF=\"%s\">.</A>\n", d, a_url);
-    else
-	/* disable a hidden action (requires a password, but password is not in squid.conf) */
-    if (!strcmp(p, "hidden"))
-	snprintf(html, sizeof(html), "<LI type=\"circle\">%s (hidden)<A HREF=\"%s\">.</A>\n", d, a_url);
-    else
-	/* disable link if authentication is required and we have no password */
-    if (!strcmp(p, "protected") && !req->passwd)
-	snprintf(html, sizeof(html), "<LI type=\"circle\">%s (requires <a href=\"%s\">authentication</a>)<A HREF=\"%s\">.</A>\n",
-	    d, menu_url(req, "authenticate"), a_url);
-    else
-	/* highlight protected but probably available entries */
-    if (!strcmp(p, "protected"))
-	snprintf(html, sizeof(html), "<LI type=\"square\"><A HREF=\"%s\"><font color=\"#FF0000\">%s</font></A>\n",
-	    a_url, d);
-    /* public entry or unknown type of protection */
-    else
-	snprintf(html, sizeof(html), "<LI type=\"disk\"><A HREF=\"%s\">%s</A>\n", a_url, d);
-    xfree(a_url);
-    xfree(buf_copy);
-    return html;
-}
-
-static const char *
-munge_other_line(const char *buf, cachemgr_request * req)
-{
-    static const char *ttags[] =
-    {"td", "th"};
-    static char html[4096];
-    static int table_line_num = 0;
-    static int next_is_header = 0;
-    int is_header = 0;
-    const char *ttag;
-    char *buf_copy;
-    char *x, *p;
-    int l = 0;
-    /* does it look like a table? */
-    if (!strchr(buf, '\t') || *buf == '\t') {
-	/* nope, just text */
-	snprintf(html, sizeof(html), "%s%s",
-	    table_line_num ? "</table>\n<pre>" : "", buf);
-	table_line_num = 0;
-	return html;
-    }
-    /* start html table */
-    if (!table_line_num) {
-	l += snprintf(html + l, sizeof(html) - l, "</pre><table cellpadding=\"2\" cellspacing=\"1\">\n");
-	next_is_header = 0;
-    }
-    /* remove '\n' */
-    is_header = (!table_line_num || next_is_header) && !strchr(buf, ':') && !is_number(buf);
-    ttag = ttags[is_header];
-    /* record starts */
-    l += snprintf(html + l, sizeof(html) - l, "<tr>");
-    /* substitute '\t' */
-    buf_copy = x = xstrdup(buf);
-    if ((p = strchr(x, '\n')))
-	*p = '\0';
-    while (x && strlen(x)) {
-	int column_span = 1;
-	const char *cell = xstrtok(&x, '\t');
-	while (x && *x == '\t') {
-	    column_span++;
-	    x++;
-	}
-	l += snprintf(html + l, sizeof(html) - l, "<%s colspan=\"%d\" align=\"%s\">%s</%s>",
-	    ttag, column_span,
-	    is_header ? "center" : is_number(cell) ? "right" : "left",
-	    cell, ttag);
-    }
-    xfree(buf_copy);
-    /* record ends */
-    l += snprintf(html + l, sizeof(html) - l, "</tr>\n");
-    next_is_header = is_header && strstr(buf, "\t\t");
-    table_line_num++;
-    return html;
-}
-
-static int
-read_reply(int s, cachemgr_request * req)
-{
-    char buf[4 * 1024];
-    FILE *fp = fdopen(s, "r");
-    /* interpretation states */
-    enum {
-	isStatusLine, isHeaders, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError
-    } istate = isStatusLine;
-    int parse_menu = 0;
-    const char *action = req->action;
-    const char *statusStr = NULL;
-    int status = -1;
-    if (0 == strlen(req->action))
-	parse_menu = 1;
-    else if (0 == strcasecmp(req->action, "menu"))
-	parse_menu = 1;
-    if (fp == NULL) {
-	perror("fdopen");
-	return 1;
-    }
-    if (parse_menu)
-	action = "menu";
-    /* read reply interpreting one line at a time depending on state */
-    while (istate < isEof) {
-	if (!fgets(buf, sizeof(buf), fp))
-	    istate = istate == isForward ? isForwardEof : isEof;
-	switch (istate) {
-	case isStatusLine:
-	    /* get HTTP status */
-	    /* uncomment the following if you want to debug headers */
-	    /* fputs("\r\n\r\n", stdout); */
-	    status = parse_status_line(buf, &statusStr);
-	    istate = status == 200 ? isHeaders : isForward;
-	    /* if cache asks for authentication, we have to reset our info */
-	    if (status == 401 || status == 407) {
-		reset_auth(req);
-		status = 403;	/* Forbiden, see comments in case isForward: */
-	    }
-	    /* this is a way to pass HTTP status to the Web server */
-	    if (statusStr)
-		printf("Status: %d %s", status, statusStr);	/* statusStr has '\n' */
-	    break;
-	case isHeaders:
-	    /* forward header field */
-	    if (!strcmp(buf, "\r\n")) {		/* end of headers */
-		fputs("Content-Type: text/html\r\n", stdout);	/* add our type */
-		istate = isBodyStart;
-	    }
-	    if (strncasecmp(buf, "Content-Type:", 13))	/* filter out their type */
-		fputs(buf, stdout);
-	    break;
-	case isBodyStart:
-	    printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
-	    printf("<HTML><HEAD><TITLE>CacheMgr@%s: %s</TITLE>\n",
-		req->hostname, action);
-	    printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}TABLE{background-color:#333333;border:0pt;padding:0pt}TH,TD{background-color:#ffffff}--></STYLE>\n");
-	    printf("</HEAD><BODY>\n");
-	    if (parse_menu) {
-		printf("<H2><a href=\"%s\">Cache Manager</a> menu for %s:</H2>",
-		    menu_url(req, "authenticate"), req->hostname);
-		printf("<UL>\n");
-	    } else {
-		printf("<P><A HREF=\"%s\">%s</A>\n<HR noshade size=\"1px\">\n",
-		    menu_url(req, "menu"), "Cache Manager menu");
-		printf("<PRE>\n");
-	    }
-	    istate = isBody;
-	    /* yes, fall through, we do not want to loose the first line */
-	case isBody:
-	    /* interpret [and reformat] cache response */
-	    if (parse_menu)
-		fputs(munge_menu_line(buf, req), stdout);
-	    else
-		fputs(munge_other_line(buf, req), stdout);
-	    break;
-	case isForward:
-	    /* forward: no modifications allowed */
-	    /*
-	     * Note: we currently do not know any way to get browser.reply to
-	     * 401 to .cgi because web server filters out all auth info. Thus we
-	     * disable authentication headers for now.
-	     */
-	    if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19));	/* skip */
-	    else
-		fputs(buf, stdout);
-	    break;
-	case isEof:
-	    /* print trailers */
-	    if (parse_menu)
-		printf("</UL>\n");
-	    else
-		printf("</table></PRE>\n");
-	    print_trailer();
-	    istate = isSuccess;
-	    break;
-	case isForwardEof:
-	    /* indicate that we finished processing an "error" sequence */
-	    istate = isError;
-	    break;
-	default:
-	    printf("%s: internal bug: invalid state reached: %d", script_name, istate);
-	    istate = isError;
-	}
-    }
-    close(s);
-    return 0;
-}
-
-static int
-process_request(cachemgr_request * req)
-{
-    const struct hostent *hp;
-    static struct sockaddr_in S;
-    int s;
-    int l;
-    static char buf[2 * 1024];
-    if (req == NULL) {
-	auth_html(CACHEMGR_HOSTNAME, CACHE_HTTP_PORT, "");
-	return 1;
-    }
-    if (req->hostname == NULL) {
-	req->hostname = xstrdup(CACHEMGR_HOSTNAME);
-    }
-    if (req->port == 0) {
-	req->port = CACHE_HTTP_PORT;
-    }
-    if (req->action == NULL) {
-	req->action = xstrdup("");
-    }
-    if (!strcmp(req->action, "authenticate")) {
-	auth_html(req->hostname, req->port, req->user_name);
-	return 0;
-    }
-    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-	snprintf(buf, 1024, "socket: %s\n", xstrerror());
-	error_html(buf);
-	return 1;
-    }
-    memset(&S, '\0', sizeof(struct sockaddr_in));
-    S.sin_family = AF_INET;
-    if ((hp = gethostbyname(req->hostname)) != NULL) {
-	assert(hp->h_length <= sizeof(S.sin_addr.s_addr));
-	xmemcpy(&S.sin_addr.s_addr, hp->h_addr, hp->h_length);
-    } else if (safe_inet_addr(req->hostname, &S.sin_addr))
-	(void) 0;
-    else {
-	snprintf(buf, 1024, "Unknown host: %s\n", req->hostname);
-	error_html(buf);
-	return 1;
-    }
-    S.sin_port = htons(req->port);
-    if (connect(s, (struct sockaddr *) &S, sizeof(struct sockaddr_in)) < 0) {
-	snprintf(buf, 1024, "connect: %s\n", xstrerror());
-	error_html(buf);
-	return 1;
-    }
-    l = snprintf(buf, sizeof(buf),
-	"GET cache_object://%s/%s HTTP/1.0\r\n"
-	"Accept: */*\r\n"
-	"%s"			/* Authentication info or nothing */
-	"\r\n",
-	req->hostname,
-	req->action,
-	make_auth_header(req));
-    write(s, buf, l);
-    debug(1) fprintf(stderr, "wrote request: '%s'\n", buf);
-    return read_reply(s, req);
-}
-
-int
-main(int argc, char *argv[])
-{
-    char *s;
-    cachemgr_request *req;
-    safe_inet_addr("255.255.255.255", &no_addr);
-    now = time(NULL);
-    if ((s = strrchr(argv[0], '/')))
-	progname = xstrdup(s + 1);
-    else
-	progname = xstrdup(argv[0]);
-    if ((s = getenv("SCRIPT_NAME")) != NULL)
-	script_name = xstrdup(s);
-    req = read_request();
-    return process_request(req);
-}
-
-static char *
-read_post_request(void)
-{
-    char *s;
-    char *buf;
-    int len;
-    if ((s = getenv("REQUEST_METHOD")) == NULL)
-	return NULL;
-    if (0 != strcasecmp(s, "POST"))
-	return NULL;
-    if ((s = getenv("CONTENT_LENGTH")) == NULL)
-	return NULL;
-    if ((len = atoi(s)) <= 0)
-	return NULL;
-    buf = xmalloc(len + 1);
-    fread(buf, len, 1, stdin);
-    buf[len] = '\0';
-    return buf;
-}
-
-static char *
-read_get_request(void)
-{
-    char *s;
-    if ((s = getenv("QUERY_STRING")) == NULL)
-	return NULL;
-    return xstrdup(s);
-}
-
-static cachemgr_request *
-read_request(void)
-{
-    char *buf;
-    cachemgr_request *req;
-    char *s;
-    char *t;
-    char *q;
-    if ((buf = read_post_request()) != NULL)
-	(void) 0;
-    else if ((buf = read_get_request()) != NULL)
-	(void) 0;
-    else
-	return NULL;
-    if (strlen(buf) == 0)
-	return NULL;
-    req = xcalloc(1, sizeof(cachemgr_request));
-    for (s = strtok(buf, "&"); s != NULL; s = strtok(NULL, "&")) {
-	t = xstrdup(s);
-	if ((q = strchr(t, '=')) == NULL)
-	    continue;
-	*q++ = '\0';
-	if (0 == strcasecmp(t, "host") && strlen(q))
-	    req->hostname = xstrdup(q);
-	else if (0 == strcasecmp(t, "port") && strlen(q))
-	    req->port = atoi(q);
-	else if (0 == strcasecmp(t, "user_name") && strlen(q))
-	    req->user_name = xstrdup(q);
-	else if (0 == strcasecmp(t, "passwd") && strlen(q))
-	    req->passwd = xstrdup(q);
-	else if (0 == strcasecmp(t, "auth") && strlen(q))
-	    req->pub_auth = xstrdup(q), decode_pub_auth(req);
-	else if (0 == strcasecmp(t, "operation"))
-	    req->action = xstrdup(q);
-    }
-    make_pub_auth(req);
-    debug(1) fprintf(stderr, "cmgr: got req: host: '%s' port: %d uname: '%s' passwd: '%s' auth: '%s' oper: '%s'\n",
-	safe_str(req->hostname), req->port, safe_str(req->user_name), safe_str(req->passwd), safe_str(req->pub_auth), safe_str(req->action));
-    return req;
-}
-
-
-/* Routines to support authentication */
-
-/*
- * Encodes auth info into a "public" form. 
- * Currently no powerful encryption is used.
- */
-static void
-make_pub_auth(cachemgr_request * req)
-{
-    static char buf[1024];
-    safe_free(req->pub_auth);
-    debug(3) fprintf(stderr, "cmgr: encoding for pub...\n");
-    if (!req->passwd || !strlen(req->passwd))
-	return;
-    /* host | time | user | passwd */
-    snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
-	req->hostname,
-	(int) now,
-	req->user_name ? req->user_name : "",
-	req->passwd);
-    debug(3) fprintf(stderr, "cmgr: pre-encoded for pub: %s\n", buf);
-    debug(3) fprintf(stderr, "cmgr: encoded: '%s'\n", base64_encode(buf));
-    req->pub_auth = xstrdup(base64_encode(buf));
-}
-
-static void
-decode_pub_auth(cachemgr_request * req)
-{
-    char *buf;
-    const char *host_name;
-    const char *time_str;
-    const char *user_name;
-    const char *passwd;
-
-    debug(2) fprintf(stderr, "cmgr: decoding pub: '%s'\n", safe_str(req->pub_auth));
-    safe_free(req->passwd);
-    if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
-	return;
-    buf = xstrdup(base64_decode(req->pub_auth));
-    debug(3) fprintf(stderr, "cmgr: length ok\n");
-    /* parse ( a lot of memory leaks, but that is cachemgr style :) */
-    if ((host_name = strtok(buf, "|")) == NULL)
-	return;
-    debug(3) fprintf(stderr, "cmgr: decoded host: '%s'\n", host_name);
-    if ((time_str = strtok(NULL, "|")) == NULL)
-	return;
-    debug(3) fprintf(stderr, "cmgr: decoded time: '%s' (now: %d)\n", time_str, (int) now);
-    if ((user_name = strtok(NULL, "|")) == NULL)
-	return;
-    debug(3) fprintf(stderr, "cmgr: decoded uname: '%s'\n", user_name);
-    if ((passwd = strtok(NULL, "|")) == NULL)
-	return;
-    debug(2) fprintf(stderr, "cmgr: decoded passwd: '%s'\n", passwd);
-    /* verify freshness and validity */
-    if (atoi(time_str) + passwd_ttl < now)
-	return;
-    if (strcasecmp(host_name, req->hostname))
-	return;
-    debug(1) fprintf(stderr, "cmgr: verified auth. info.\n");
-    /* ok, accept */
-    xfree(req->user_name);
-    req->user_name = xstrdup(user_name);
-    req->passwd = xstrdup(passwd);
-    xfree(buf);
-}
-
-static void
-reset_auth(cachemgr_request * req)
-{
-    safe_free(req->passwd);
-    safe_free(req->pub_auth);
-}
-
-static const char *
-make_auth_header(const cachemgr_request * req)
-{
-    static char buf[1024];
-    off_t l = 0;
-    const char *str64;
-    if (!req->passwd)
-	return "";
-
-    snprintf(buf, sizeof(buf), "%s:%s",
-	req->user_name ? req->user_name : "",
-	req->passwd);
-
-    str64 = base64_encode(buf);
-    l += snprintf(buf, sizeof(buf), "Authorization: Basic %s\r\n", str64);
-    assert(l < sizeof(buf));
-    l += snprintf(&buf[l], sizeof(buf) - l,
-	"Proxy-Authorization: Basic %s\r\n", str64);
-    return buf;
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/cachemgr.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,753 @@
+
+/*
+ * $Id: cachemgr.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 0     CGI Cache Manager
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "config.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_GRP_H
+#include <grp.h>
+#endif
+#if HAVE_GNUMALLOC_H
+#include <gnumalloc.h>
+#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#include <malloc.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_)	/* protect NEXTSTEP */
+#define _SQUID_NETDB_H_
+#include <netdb.h>
+#endif
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>	/* needs sys/time.h above it */
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if HAVE_LIBC_H
+#include <libc.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <assert.h>
+
+#include "util.h"
+#include "snprintf.h"
+
+typedef struct {
+    char *hostname;
+    int port;
+    char *action;
+    char *user_name;
+    char *passwd;
+    char *pub_auth;
+} cachemgr_request;
+
+/*
+ * Debugging macros (info goes to error_log on your web server)
+ * Note: do not run cache manager with non zero debugging level 
+ *       if you do not debug, it may write a lot of [sensitive]
+ *       information to your error log.
+ */
+
+/* debugging level 0 (disabled) - 3 (max) */
+#define DEBUG_LEVEL 0
+#define debug(level) if ((level) <= DEBUG_LEVEL && DEBUG_LEVEL > 0)
+
+/*
+ * Static variables and constants
+ */
+static const time_t passwd_ttl = 60 * 60 * 3;	/* in sec */
+static const char *script_name = "/cgi-bin/cachemgr.cgi";
+static const char *progname = NULL;
+static time_t now;
+static struct in_addr no_addr;
+
+/*
+ * Function prototypes
+ */
+#define safe_free(str) { if (str) { xfree(str); (str) = NULL; } }
+static const char *safe_str(const char *str);
+static const char *xstrtok(char **str, char del);
+static void print_trailer(void);
+static void auth_html(const char *host, int port, const char *user_name);
+static void error_html(const char *msg);
+static char *menu_url(cachemgr_request * req, const char *action);
+static int parse_status_line(const char *sline, const char **statusStr);
+static cachemgr_request *read_request(void);
+static char *read_get_request(void);
+static char *read_post_request(void);
+
+static void make_pub_auth(cachemgr_request * req);
+static void decode_pub_auth(cachemgr_request * req);
+static void reset_auth(cachemgr_request * req);
+static const char *make_auth_header(const cachemgr_request * req);
+
+
+static const char *
+safe_str(const char *str)
+{
+    return str ? str : "";
+}
+
+/* relaxed number format */
+static int
+is_number(const char *str)
+{
+    return strspn(str, "\t -+01234567890./\n") == strlen(str);
+}
+
+static const char *
+xstrtok(char **str, char del)
+{
+    if (*str) {
+	char *p = strchr(*str, del);
+	char *tok = *str;
+	int len;
+	if (p) {
+	    *str = p + 1;
+	    *p = '\0';
+	} else
+	    *str = NULL;
+	/* trim */
+	len = strlen(tok);
+	while (len && xisspace(tok[len - 1]))
+	    tok[--len] = '\0';
+	while (xisspace(*tok))
+	    tok++;
+	return tok;
+    } else
+	return "";
+}
+
+static void
+print_trailer(void)
+{
+    printf("<HR noshade size=\"1px\">\n");
+    printf("<ADDRESS>\n");
+    printf("Generated %s, by %s/%s@%s\n",
+	mkrfc1123(now), progname, VERSION, getfullhostname());
+    printf("</ADDRESS></BODY></HTML>\n");
+}
+
+static void
+auth_html(const char *host, int port, const char *user_name)
+{
+    if (!user_name)
+	user_name = "";
+    if (!host || !strlen(host))
+	host = "localhost";
+    printf("Content-Type: text/html\r\n\r\n");
+    printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
+    printf("<HTML><HEAD><TITLE>Cache Manager Interface</TITLE>\n");
+    printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE></HEAD>\n");
+    printf("<BODY><H1>Cache Manager Interface</H1>\n");
+    printf("<P>This is a WWW interface to the instrumentation interface\n");
+    printf("for the Squid object cache.</P>\n");
+    printf("<HR noshade size=\"1px\">\n");
+    printf("<FORM METHOD=\"GET\" ACTION=\"%s\">\n", script_name);
+    printf("<TABLE BORDER=\"0\" CELLPADDING=\"10\" CELLSPACING=\"1\">\n");
+    printf("<TR><TH ALIGN=\"left\">Cache Host:</TH><TD><INPUT NAME=\"host\" ");
+    printf("size=\"30\" VALUE=\"%s\"></TD></TR>\n", host);
+    printf("<TR><TH ALIGN=\"left\">Cache Port:</TH><TD><INPUT NAME=\"port\" ");
+    printf("size=\"30\" VALUE=\"%d\"></TD></TR>\n", port);
+    printf("<TR><TH ALIGN=\"left\">Manager name:</TH><TD><INPUT NAME=\"user_name\" ");
+    printf("size=\"30\" VALUE=\"%s\"></TD></TR>\n", user_name);
+    printf("<TR><TH ALIGN=\"left\">Password:</TH><TD><INPUT TYPE=\"password\" NAME=\"passwd\" ");
+    printf("size=\"30\" VALUE=\"\"></TD></TR>\n");
+    printf("</TABLE><BR CLEAR=\"all\">\n");
+    printf("<INPUT TYPE=\"submit\" VALUE=\"Continue...\">\n");
+    printf("</FORM>\n");
+    print_trailer();
+}
+
+static void
+error_html(const char *msg)
+{
+    printf("Content-Type: text/html\r\n\r\n");
+    printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
+    printf("<HTML><HEAD><TITLE>Cache Manager Error</TITLE>\n");
+    printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE></HEAD>\n");
+    printf("<BODY><H1>Cache Manager Error</H1>\n");
+    printf("<P>\n%s</P>\n", msg);
+    print_trailer();
+}
+
+/* returns http status extracted from status line or -1 on parsing failure */
+static int
+parse_status_line(const char *sline, const char **statusStr)
+{
+    const char *sp = strchr(sline, ' ');
+    if (statusStr)
+	*statusStr = NULL;
+    if (strncasecmp(sline, "HTTP/", 5) || !sp)
+	return -1;
+    while (xisspace(*++sp));
+    if (!xisdigit(*sp))
+	return -1;
+    if (statusStr)
+	*statusStr = sp;
+    return atoi(sp);
+}
+
+static char *
+menu_url(cachemgr_request * req, const char *action)
+{
+    static char url[1024];
+    snprintf(url, sizeof(url), "%s?host=%s&port=%d&user_name=%s&operation=%s&auth=%s",
+	script_name,
+	req->hostname,
+	req->port,
+	safe_str(req->user_name),
+	action,
+	safe_str(req->pub_auth));
+    return url;
+}
+
+static const char *
+munge_menu_line(const char *buf, cachemgr_request * req)
+{
+    char *x;
+    const char *a;
+    const char *d;
+    const char *p;
+    char *a_url;
+    char *buf_copy;
+    static char html[2 * 1024];
+    if (strlen(buf) < 1)
+	return buf;
+    if (*buf != ' ')
+	return buf;
+    buf_copy = x = xstrdup(buf);
+    a = xstrtok(&x, '\t');
+    d = xstrtok(&x, '\t');
+    p = xstrtok(&x, '\t');
+    a_url = xstrdup(menu_url(req, a));
+    /* no reason to give a url for a disabled action */
+    if (!strcmp(p, "disabled"))
+	snprintf(html, sizeof(html), "<LI type=\"circle\">%s (disabled)<A HREF=\"%s\">.</A>\n", d, a_url);
+    else
+	/* disable a hidden action (requires a password, but password is not in squid.conf) */
+    if (!strcmp(p, "hidden"))
+	snprintf(html, sizeof(html), "<LI type=\"circle\">%s (hidden)<A HREF=\"%s\">.</A>\n", d, a_url);
+    else
+	/* disable link if authentication is required and we have no password */
+    if (!strcmp(p, "protected") && !req->passwd)
+	snprintf(html, sizeof(html), "<LI type=\"circle\">%s (requires <a href=\"%s\">authentication</a>)<A HREF=\"%s\">.</A>\n",
+	    d, menu_url(req, "authenticate"), a_url);
+    else
+	/* highlight protected but probably available entries */
+    if (!strcmp(p, "protected"))
+	snprintf(html, sizeof(html), "<LI type=\"square\"><A HREF=\"%s\"><font color=\"#FF0000\">%s</font></A>\n",
+	    a_url, d);
+    /* public entry or unknown type of protection */
+    else
+	snprintf(html, sizeof(html), "<LI type=\"disk\"><A HREF=\"%s\">%s</A>\n", a_url, d);
+    xfree(a_url);
+    xfree(buf_copy);
+    return html;
+}
+
+static const char *
+munge_other_line(const char *buf, cachemgr_request * req)
+{
+    static const char *ttags[] =
+    {"td", "th"};
+    static char html[4096];
+    static int table_line_num = 0;
+    static int next_is_header = 0;
+    int is_header = 0;
+    const char *ttag;
+    char *buf_copy;
+    char *x, *p;
+    int l = 0;
+    /* does it look like a table? */
+    if (!strchr(buf, '\t') || *buf == '\t') {
+	/* nope, just text */
+	snprintf(html, sizeof(html), "%s%s",
+	    table_line_num ? "</table>\n<pre>" : "", buf);
+	table_line_num = 0;
+	return html;
+    }
+    /* start html table */
+    if (!table_line_num) {
+	l += snprintf(html + l, sizeof(html) - l, "</pre><table cellpadding=\"2\" cellspacing=\"1\">\n");
+	next_is_header = 0;
+    }
+    /* remove '\n' */
+    is_header = (!table_line_num || next_is_header) && !strchr(buf, ':') && !is_number(buf);
+    ttag = ttags[is_header];
+    /* record starts */
+    l += snprintf(html + l, sizeof(html) - l, "<tr>");
+    /* substitute '\t' */
+    buf_copy = x = xstrdup(buf);
+    if ((p = strchr(x, '\n')))
+	*p = '\0';
+    while (x && strlen(x)) {
+	int column_span = 1;
+	const char *cell = xstrtok(&x, '\t');
+	while (x && *x == '\t') {
+	    column_span++;
+	    x++;
+	}
+	l += snprintf(html + l, sizeof(html) - l, "<%s colspan=\"%d\" align=\"%s\">%s</%s>",
+	    ttag, column_span,
+	    is_header ? "center" : is_number(cell) ? "right" : "left",
+	    cell, ttag);
+    }
+    xfree(buf_copy);
+    /* record ends */
+    l += snprintf(html + l, sizeof(html) - l, "</tr>\n");
+    next_is_header = is_header && strstr(buf, "\t\t");
+    table_line_num++;
+    return html;
+}
+
+static int
+read_reply(int s, cachemgr_request * req)
+{
+    char buf[4 * 1024];
+    FILE *fp = fdopen(s, "r");
+    /* interpretation states */
+    enum {
+	isStatusLine, isHeaders, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError
+    } istate = isStatusLine;
+    int parse_menu = 0;
+    const char *action = req->action;
+    const char *statusStr = NULL;
+    int status = -1;
+    if (0 == strlen(req->action))
+	parse_menu = 1;
+    else if (0 == strcasecmp(req->action, "menu"))
+	parse_menu = 1;
+    if (fp == NULL) {
+	perror("fdopen");
+	return 1;
+    }
+    if (parse_menu)
+	action = "menu";
+    /* read reply interpreting one line at a time depending on state */
+    while (istate < isEof) {
+	if (!fgets(buf, sizeof(buf), fp))
+	    istate = istate == isForward ? isForwardEof : isEof;
+	switch (istate) {
+	case isStatusLine:
+	    /* get HTTP status */
+	    /* uncomment the following if you want to debug headers */
+	    /* fputs("\r\n\r\n", stdout); */
+	    status = parse_status_line(buf, &statusStr);
+	    istate = status == 200 ? isHeaders : isForward;
+	    /* if cache asks for authentication, we have to reset our info */
+	    if (status == 401 || status == 407) {
+		reset_auth(req);
+		status = 403;	/* Forbiden, see comments in case isForward: */
+	    }
+	    /* this is a way to pass HTTP status to the Web server */
+	    if (statusStr)
+		printf("Status: %d %s", status, statusStr);	/* statusStr has '\n' */
+	    break;
+	case isHeaders:
+	    /* forward header field */
+	    if (!strcmp(buf, "\r\n")) {		/* end of headers */
+		fputs("Content-Type: text/html\r\n", stdout);	/* add our type */
+		istate = isBodyStart;
+	    }
+	    if (strncasecmp(buf, "Content-Type:", 13))	/* filter out their type */
+		fputs(buf, stdout);
+	    break;
+	case isBodyStart:
+	    printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
+	    printf("<HTML><HEAD><TITLE>CacheMgr@%s: %s</TITLE>\n",
+		req->hostname, action);
+	    printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}TABLE{background-color:#333333;border:0pt;padding:0pt}TH,TD{background-color:#ffffff}--></STYLE>\n");
+	    printf("</HEAD><BODY>\n");
+	    if (parse_menu) {
+		printf("<H2><a href=\"%s\">Cache Manager</a> menu for %s:</H2>",
+		    menu_url(req, "authenticate"), req->hostname);
+		printf("<UL>\n");
+	    } else {
+		printf("<P><A HREF=\"%s\">%s</A>\n<HR noshade size=\"1px\">\n",
+		    menu_url(req, "menu"), "Cache Manager menu");
+		printf("<PRE>\n");
+	    }
+	    istate = isBody;
+	    /* yes, fall through, we do not want to loose the first line */
+	case isBody:
+	    /* interpret [and reformat] cache response */
+	    if (parse_menu)
+		fputs(munge_menu_line(buf, req), stdout);
+	    else
+		fputs(munge_other_line(buf, req), stdout);
+	    break;
+	case isForward:
+	    /* forward: no modifications allowed */
+	    /*
+	     * Note: we currently do not know any way to get browser.reply to
+	     * 401 to .cgi because web server filters out all auth info. Thus we
+	     * disable authentication headers for now.
+	     */
+	    if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19));	/* skip */
+	    else
+		fputs(buf, stdout);
+	    break;
+	case isEof:
+	    /* print trailers */
+	    if (parse_menu)
+		printf("</UL>\n");
+	    else
+		printf("</table></PRE>\n");
+	    print_trailer();
+	    istate = isSuccess;
+	    break;
+	case isForwardEof:
+	    /* indicate that we finished processing an "error" sequence */
+	    istate = isError;
+	    break;
+	default:
+	    printf("%s: internal bug: invalid state reached: %d", script_name, istate);
+	    istate = isError;
+	}
+    }
+    close(s);
+    return 0;
+}
+
+static int
+process_request(cachemgr_request * req)
+{
+    const struct hostent *hp;
+    static struct sockaddr_in S;
+    int s;
+    int l;
+    static char buf[2 * 1024];
+    if (req == NULL) {
+	auth_html(CACHEMGR_HOSTNAME, CACHE_HTTP_PORT, "");
+	return 1;
+    }
+    if (req->hostname == NULL) {
+	req->hostname = xstrdup(CACHEMGR_HOSTNAME);
+    }
+    if (req->port == 0) {
+	req->port = CACHE_HTTP_PORT;
+    }
+    if (req->action == NULL) {
+	req->action = xstrdup("");
+    }
+    if (!strcmp(req->action, "authenticate")) {
+	auth_html(req->hostname, req->port, req->user_name);
+	return 0;
+    }
+    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+	snprintf(buf, 1024, "socket: %s\n", xstrerror());
+	error_html(buf);
+	return 1;
+    }
+    memset(&S, '\0', sizeof(struct sockaddr_in));
+    S.sin_family = AF_INET;
+    if ((hp = gethostbyname(req->hostname)) != NULL) {
+	assert(hp->h_length >= 0 && (size_t)hp->h_length <= sizeof(S.sin_addr.s_addr));
+	xmemcpy(&S.sin_addr.s_addr, hp->h_addr, hp->h_length);
+    } else if (safe_inet_addr(req->hostname, &S.sin_addr))
+	(void) 0;
+    else {
+	snprintf(buf, 1024, "Unknown host: %s\n", req->hostname);
+	error_html(buf);
+	return 1;
+    }
+    S.sin_port = htons(req->port);
+    if (connect(s, (struct sockaddr *) &S, sizeof(struct sockaddr_in)) < 0) {
+	snprintf(buf, 1024, "connect: %s\n", xstrerror());
+	error_html(buf);
+	return 1;
+    }
+    l = snprintf(buf, sizeof(buf),
+	"GET cache_object://%s/%s HTTP/1.0\r\n"
+	"Accept: */*\r\n"
+	"%s"			/* Authentication info or nothing */
+	"\r\n",
+	req->hostname,
+	req->action,
+	make_auth_header(req));
+    write(s, buf, l);
+    debug(1) fprintf(stderr, "wrote request: '%s'\n", buf);
+    return read_reply(s, req);
+}
+
+int
+main(int argc, char *argv[])
+{
+    char *s;
+    cachemgr_request *req;
+    safe_inet_addr("255.255.255.255", &no_addr);
+    now = time(NULL);
+    if ((s = strrchr(argv[0], '/')))
+	progname = xstrdup(s + 1);
+    else
+	progname = xstrdup(argv[0]);
+    if ((s = getenv("SCRIPT_NAME")) != NULL)
+	script_name = xstrdup(s);
+    req = read_request();
+    return process_request(req);
+}
+
+static char *
+read_post_request(void)
+{
+    char *s;
+    char *buf;
+    int len;
+    if ((s = getenv("REQUEST_METHOD")) == NULL)
+	return NULL;
+    if (0 != strcasecmp(s, "POST"))
+	return NULL;
+    if ((s = getenv("CONTENT_LENGTH")) == NULL)
+	return NULL;
+    if ((len = atoi(s)) <= 0)
+	return NULL;
+    buf = (char *)xmalloc(len + 1);
+    fread(buf, len, 1, stdin);
+    buf[len] = '\0';
+    return buf;
+}
+
+static char *
+read_get_request(void)
+{
+    char *s;
+    if ((s = getenv("QUERY_STRING")) == NULL)
+	return NULL;
+    return xstrdup(s);
+}
+
+static cachemgr_request *
+read_request(void)
+{
+    char *buf;
+    cachemgr_request *req;
+    char *s;
+    char *t;
+    char *q;
+    if ((buf = read_post_request()) != NULL)
+	(void) 0;
+    else if ((buf = read_get_request()) != NULL)
+	(void) 0;
+    else
+	return NULL;
+    if (strlen(buf) == 0)
+	return NULL;
+    req = (cachemgr_request *)xcalloc(1, sizeof(cachemgr_request));
+    for (s = strtok(buf, "&"); s != NULL; s = strtok(NULL, "&")) {
+	t = xstrdup(s);
+	if ((q = strchr(t, '=')) == NULL)
+	    continue;
+	*q++ = '\0';
+	if (0 == strcasecmp(t, "host") && strlen(q))
+	    req->hostname = xstrdup(q);
+	else if (0 == strcasecmp(t, "port") && strlen(q))
+	    req->port = atoi(q);
+	else if (0 == strcasecmp(t, "user_name") && strlen(q))
+	    req->user_name = xstrdup(q);
+	else if (0 == strcasecmp(t, "passwd") && strlen(q))
+	    req->passwd = xstrdup(q);
+	else if (0 == strcasecmp(t, "auth") && strlen(q))
+	    req->pub_auth = xstrdup(q), decode_pub_auth(req);
+	else if (0 == strcasecmp(t, "operation"))
+	    req->action = xstrdup(q);
+    }
+    make_pub_auth(req);
+    debug(1) fprintf(stderr, "cmgr: got req: host: '%s' port: %d uname: '%s' passwd: '%s' auth: '%s' oper: '%s'\n",
+	safe_str(req->hostname), req->port, safe_str(req->user_name), safe_str(req->passwd), safe_str(req->pub_auth), safe_str(req->action));
+    return req;
+}
+
+
+/* Routines to support authentication */
+
+/*
+ * Encodes auth info into a "public" form. 
+ * Currently no powerful encryption is used.
+ */
+static void
+make_pub_auth(cachemgr_request * req)
+{
+    static char buf[1024];
+    safe_free(req->pub_auth);
+    debug(3) fprintf(stderr, "cmgr: encoding for pub...\n");
+    if (!req->passwd || !strlen(req->passwd))
+	return;
+    /* host | time | user | passwd */
+    snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
+	req->hostname,
+	(int) now,
+	req->user_name ? req->user_name : "",
+	req->passwd);
+    debug(3) fprintf(stderr, "cmgr: pre-encoded for pub: %s\n", buf);
+    debug(3) fprintf(stderr, "cmgr: encoded: '%s'\n", base64_encode(buf));
+    req->pub_auth = xstrdup(base64_encode(buf));
+}
+
+static void
+decode_pub_auth(cachemgr_request * req)
+{
+    char *buf;
+    const char *host_name;
+    const char *time_str;
+    const char *user_name;
+    const char *passwd;
+
+    debug(2) fprintf(stderr, "cmgr: decoding pub: '%s'\n", safe_str(req->pub_auth));
+    safe_free(req->passwd);
+    if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
+	return;
+    buf = xstrdup(base64_decode(req->pub_auth));
+    debug(3) fprintf(stderr, "cmgr: length ok\n");
+    /* parse ( a lot of memory leaks, but that is cachemgr style :) */
+    if ((host_name = strtok(buf, "|")) == NULL)
+	return;
+    debug(3) fprintf(stderr, "cmgr: decoded host: '%s'\n", host_name);
+    if ((time_str = strtok(NULL, "|")) == NULL)
+	return;
+    debug(3) fprintf(stderr, "cmgr: decoded time: '%s' (now: %d)\n", time_str, (int) now);
+    if ((user_name = strtok(NULL, "|")) == NULL)
+	return;
+    debug(3) fprintf(stderr, "cmgr: decoded uname: '%s'\n", user_name);
+    if ((passwd = strtok(NULL, "|")) == NULL)
+	return;
+    debug(2) fprintf(stderr, "cmgr: decoded passwd: '%s'\n", passwd);
+    /* verify freshness and validity */
+    if (atoi(time_str) + passwd_ttl < now)
+	return;
+    if (strcasecmp(host_name, req->hostname))
+	return;
+    debug(1) fprintf(stderr, "cmgr: verified auth. info.\n");
+    /* ok, accept */
+    xfree(req->user_name);
+    req->user_name = xstrdup(user_name);
+    req->passwd = xstrdup(passwd);
+    xfree(buf);
+}
+
+static void
+reset_auth(cachemgr_request * req)
+{
+    safe_free(req->passwd);
+    safe_free(req->pub_auth);
+}
+
+static const char *
+make_auth_header(const cachemgr_request * req)
+{
+    static char buf[1024];
+    size_t stringLength = 0;
+    const char *str64;
+    if (!req->passwd)
+	return "";
+
+    snprintf(buf, sizeof(buf), "%s:%s",
+	req->user_name ? req->user_name : "",
+	req->passwd);
+
+    str64 = base64_encode(buf);
+    stringLength += snprintf(buf, sizeof(buf), "Authorization: Basic %s\r\n", str64);
+    assert(stringLength < sizeof(buf));
+    stringLength += snprintf(&buf[stringLength], sizeof(buf) - stringLength,
+	"Proxy-Authorization: Basic %s\r\n", str64);
+    return buf;
+}
--- squid/src/carp.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,193 +0,0 @@
-
-/*
- * $Id: carp.c,v 1.8.18.1 2002/10/04 07:07:20 rbcollins Exp $
- *
- * DEBUG: section 39    Cache Array Routing Protocol
- * AUTHOR: Henrik Nordstrom
- * BASED ON: carp.c by Eric Stern and draft-vinod-carp-v1-03.txt
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "Store.h"
-
-#if USE_CARP
-
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-static int n_carp_peers = 0;
-static peer **carp_peers = NULL;
-static OBJH carpCachemgr;
-
-static int
-peerSortWeight(const void *a, const void *b)
-{
-    const peer *const *p1 = a, *const *p2 = b;
-    return (*p1)->weight - (*p2)->weight;
-}
-
-void
-carpInit(void)
-{
-    int W = 0;
-    int K;
-    int k;
-    double P_last, X_last, Xn;
-    peer *p;
-    peer **P;
-    char *t;
-    /* Clean up */
-    for (k = 0; k < n_carp_peers; k++) {
-	cbdataReferenceDone(carp_peers[k]);
-    }
-    safe_free(carp_peers);
-    n_carp_peers = 0;
-    /* find out which peers we have */
-    for (p = Config.peers; p; p = p->next) {
-	if (!p->options.carp)
-	    continue;
-	assert(p->type == PEER_PARENT);
-	if (p->weight == 0)
-	    continue;
-	n_carp_peers++;
-	W += p->weight;
-    }
-    if (n_carp_peers == 0)
-	return;
-    carp_peers = xcalloc(n_carp_peers, sizeof(*carp_peers));
-    /* Build a list of the found peers and calculate hashes and load factors */
-    for (P = carp_peers, p = Config.peers; p; p = p->next) {
-	if (!p->options.carp)
-	    continue;
-	if (p->weight == 0)
-	    continue;
-	/* calculate this peers hash */
-	p->carp.hash = 0;
-	for (t = p->host; *t != 0; t++)
-	    p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *t;
-	p->carp.hash += p->carp.hash * 0x62531965;
-	p->carp.hash = ROTATE_LEFT(p->carp.hash, 21);
-	/* and load factor */
-	p->carp.load_factor = ((double) p->weight) / (double) W;
-	if (floor(p->carp.load_factor * 1000.0) == 0.0)
-	    p->carp.load_factor = 0.0;
-	/* add it to our list of peers */
-	*P++ = cbdataReference(p);
-    }
-    /* Sort our list on weight */
-    qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight);
-    /* Calculate the load factor multipliers X_k
-     *
-     * X_1 = pow ((K*p_1), (1/K))
-     * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
-     * X_k += pow ((X_{k-1}, {K-k+1})
-     * X_k = pow (X_k, {1/(K-k+1)})
-     * simplified to have X_1 part of the loop
-     */
-    K = n_carp_peers;
-    P_last = 0.0;		/* Empty P_0 */
-    Xn = 1.0;			/* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
-    X_last = 0.0;		/* Empty X_0, nullifies the first pow statement */
-    for (k = 1; k <= K; k++) {
-	double Kk1 = (double) (K - k + 1);
-	p = carp_peers[k - 1];
-	p->carp.load_multiplier = (Kk1 * (p->carp.load_factor - P_last)) / Xn;
-	p->carp.load_multiplier += pow(X_last, Kk1);
-	p->carp.load_multiplier = pow(p->carp.load_multiplier, 1.0 / Kk1);
-	Xn *= p->carp.load_multiplier;
-	X_last = p->carp.load_multiplier;
-	P_last = p->carp.load_factor;
-    }
-    cachemgrRegister("carp", "CARP information", carpCachemgr, 0, 1);
-}
-
-peer *
-carpSelectParent(request_t * request)
-{
-    int k;
-    const char *c;
-    peer *p = NULL;
-    peer *tp;
-    unsigned int user_hash = 0;
-    unsigned int combined_hash;
-    double score;
-    double high_score = 0;
-    const char *key = NULL;
-
-    if (n_carp_peers == 0)
-	return NULL;
-
-    key = urlCanonical(request);
-
-    /* calculate hash key */
-    debug(39, 2) ("carpSelectParent: Calculating hash for %s\n", key);
-    for (c = key; *c != 0; c++)
-	user_hash += ROTATE_LEFT(user_hash, 19) + *c;
-    /* select peer */
-    for (k = 0; k < n_carp_peers; k++) {
-	tp = carp_peers[k];
-	combined_hash = (user_hash ^ tp->carp.hash);
-	combined_hash += combined_hash * 0x62531965;
-	combined_hash = ROTATE_LEFT(combined_hash, 21);
-	score = combined_hash * tp->carp.load_multiplier;
-	debug(39, 3) ("carpSelectParent: %s combined_hash %u score %.0f\n",
-	    tp->host, combined_hash, score);
-	if ((score > high_score) && peerHTTPOkay(tp, request)) {
-	    p = tp;
-	    high_score = score;
-	}
-    }
-    if (p)
-	debug(39, 2) ("carpSelectParent: selected %s\n", p->host);
-    return p;
-}
-
-static void
-carpCachemgr(StoreEntry * sentry)
-{
-    peer *p;
-    int sumfetches = 0;
-    storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
-	"Hostname",
-	"Hash",
-	"Multiplier",
-	"Factor",
-	"Actual");
-    for (p = Config.peers; p; p = p->next)
-	sumfetches += p->stats.fetches;
-    for (p = Config.peers; p; p = p->next) {
-	storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
-	    p->host, p->carp.hash,
-	    p->carp.load_multiplier,
-	    p->carp.load_factor,
-	    sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
-    }
-}
-
-#endif
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/carp.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,193 @@
+
+/*
+ * $Id: carp.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 39    Cache Array Routing Protocol
+ * AUTHOR: Henrik Nordstrom
+ * BASED ON: carp.c by Eric Stern and draft-vinod-carp-v1-03.txt
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "Store.h"
+
+#if USE_CARP
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+static int n_carp_peers = 0;
+static peer **carp_peers = NULL;
+static OBJH carpCachemgr;
+
+static int
+peerSortWeight(const void *a, const void *b)
+{
+    const peer *const *p1 = a, *const *p2 = b;
+    return (*p1)->weight - (*p2)->weight;
+}
+
+void
+carpInit(void)
+{
+    int W = 0;
+    int K;
+    int k;
+    double P_last, X_last, Xn;
+    peer *p;
+    peer **P;
+    char *t;
+    /* Clean up */
+    for (k = 0; k < n_carp_peers; k++) {
+	cbdataReferenceDone(carp_peers[k]);
+    }
+    safe_free(carp_peers);
+    n_carp_peers = 0;
+    /* find out which peers we have */
+    for (p = Config.peers; p; p = p->next) {
+	if (!p->options.carp)
+	    continue;
+	assert(p->type == PEER_PARENT);
+	if (p->weight == 0)
+	    continue;
+	n_carp_peers++;
+	W += p->weight;
+    }
+    if (n_carp_peers == 0)
+	return;
+    carp_peers = xcalloc(n_carp_peers, sizeof(*carp_peers));
+    /* Build a list of the found peers and calculate hashes and load factors */
+    for (P = carp_peers, p = Config.peers; p; p = p->next) {
+	if (!p->options.carp)
+	    continue;
+	if (p->weight == 0)
+	    continue;
+	/* calculate this peers hash */
+	p->carp.hash = 0;
+	for (t = p->host; *t != 0; t++)
+	    p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *t;
+	p->carp.hash += p->carp.hash * 0x62531965;
+	p->carp.hash = ROTATE_LEFT(p->carp.hash, 21);
+	/* and load factor */
+	p->carp.load_factor = ((double) p->weight) / (double) W;
+	if (floor(p->carp.load_factor * 1000.0) == 0.0)
+	    p->carp.load_factor = 0.0;
+	/* add it to our list of peers */
+	*P++ = cbdataReference(p);
+    }
+    /* Sort our list on weight */
+    qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight);
+    /* Calculate the load factor multipliers X_k
+     *
+     * X_1 = pow ((K*p_1), (1/K))
+     * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
+     * X_k += pow ((X_{k-1}, {K-k+1})
+     * X_k = pow (X_k, {1/(K-k+1)})
+     * simplified to have X_1 part of the loop
+     */
+    K = n_carp_peers;
+    P_last = 0.0;		/* Empty P_0 */
+    Xn = 1.0;			/* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
+    X_last = 0.0;		/* Empty X_0, nullifies the first pow statement */
+    for (k = 1; k <= K; k++) {
+	double Kk1 = (double) (K - k + 1);
+	p = carp_peers[k - 1];
+	p->carp.load_multiplier = (Kk1 * (p->carp.load_factor - P_last)) / Xn;
+	p->carp.load_multiplier += pow(X_last, Kk1);
+	p->carp.load_multiplier = pow(p->carp.load_multiplier, 1.0 / Kk1);
+	Xn *= p->carp.load_multiplier;
+	X_last = p->carp.load_multiplier;
+	P_last = p->carp.load_factor;
+    }
+    cachemgrRegister("carp", "CARP information", carpCachemgr, 0, 1);
+}
+
+peer *
+carpSelectParent(request_t * request)
+{
+    int k;
+    const char *c;
+    peer *p = NULL;
+    peer *tp;
+    unsigned int user_hash = 0;
+    unsigned int combined_hash;
+    double score;
+    double high_score = 0;
+    const char *key = NULL;
+
+    if (n_carp_peers == 0)
+	return NULL;
+
+    key = urlCanonical(request);
+
+    /* calculate hash key */
+    debug(39, 2) ("carpSelectParent: Calculating hash for %s\n", key);
+    for (c = key; *c != 0; c++)
+	user_hash += ROTATE_LEFT(user_hash, 19) + *c;
+    /* select peer */
+    for (k = 0; k < n_carp_peers; k++) {
+	tp = carp_peers[k];
+	combined_hash = (user_hash ^ tp->carp.hash);
+	combined_hash += combined_hash * 0x62531965;
+	combined_hash = ROTATE_LEFT(combined_hash, 21);
+	score = combined_hash * tp->carp.load_multiplier;
+	debug(39, 3) ("carpSelectParent: %s combined_hash %u score %.0f\n",
+	    tp->host, combined_hash, score);
+	if ((score > high_score) && peerHTTPOkay(tp, request)) {
+	    p = tp;
+	    high_score = score;
+	}
+    }
+    if (p)
+	debug(39, 2) ("carpSelectParent: selected %s\n", p->host);
+    return p;
+}
+
+static void
+carpCachemgr(StoreEntry * sentry)
+{
+    peer *p;
+    int sumfetches = 0;
+    storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
+	"Hostname",
+	"Hash",
+	"Multiplier",
+	"Factor",
+	"Actual");
+    for (p = Config.peers; p; p = p->next)
+	sumfetches += p->stats.fetches;
+    for (p = Config.peers; p; p = p->next) {
+	storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
+	    p->host, p->carp.hash,
+	    p->carp.load_multiplier,
+	    p->carp.load_factor,
+	    sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
+    }
+}
+
+#endif
--- squid/src/cbdata.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,323 +0,0 @@
-
-/*
- * $Id: cbdata.c,v 1.16.2.2 2002/10/04 22:35:17 rbcollins Exp $
- *
- * DEBUG: section 45    Callback Data Registry
- * ORIGINAL AUTHOR: Duane Wessels
- * Modified by Moez Mahfoudh (08/12/2000)
- *
- * 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.
- *
- */
-
-/*
- * These routines manage a set of registered callback data pointers.
- * One of the easiest ways to make Squid coredump is to issue a 
- * callback to for some data structure which has previously been
- * freed.  With these routines, we register (add) callback data
- * pointers, lock them just before registering the callback function,
- * validate them before issuing the callback, and then free them
- * when finished.
- */
-
-#include "squid.h"
-#include "Store.h"
-
-static int cbdataCount = 0;
-#if CBDATA_DEBUG
-dlink_list cbdataEntries;
-#endif
-
-typedef struct _cbdata {
-    int valid;
-    int locks;
-    int type;
-#if CBDATA_DEBUG
-    dlink_node link;
-    const char *file;
-    int line;
-#endif
-    long y;			/* cookie used while debugging */
-    union {
-	void *pointer;
-	double double_float;
-	int integer;
-    } data;
-} cbdata;
-
-static OBJH cbdataDump;
-
-struct {
-    MemPool *pool;
-    FREE *free_func;
-}     *cbdata_index = NULL;
-int cbdata_types = 0;
-
-#define OFFSET_OF(type, member) ((int)(char *)&((type *)0L)->member)
-#define CBDATA_COOKIE	0xDEADBEEF
-#define CBDATA_CHECK(c) assert(c->y == ((long)c ^ CBDATA_COOKIE))
-
-static void
-cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
-{
-    char *label;
-    if (type >= cbdata_types) {
-	cbdata_index = xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
-	memset(&cbdata_index[cbdata_types], 0,
-	    (type + 1 - cbdata_types) * sizeof(*cbdata_index));
-	cbdata_types = type + 1;
-    }
-    if (cbdata_index[type].pool)
-	return;
-    label = xmalloc(strlen(name) + 20);
-    snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
-    assert(OFFSET_OF(cbdata, data) == (sizeof(cbdata) - sizeof(((cbdata *) NULL)->data)));
-    cbdata_index[type].pool = memPoolCreate(label, size + OFFSET_OF(cbdata, data));
-    cbdata_index[type].free_func = free_func;
-}
-
-cbdata_type
-cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
-{
-    if (type)
-	return type;
-    type = cbdata_types;
-    cbdataInternalInitType(type, name, size, free_func);
-    return type;
-}
-
-void
-cbdataInit(void)
-{
-    debug(45, 3) ("cbdataInit\n");
-    cachemgrRegister("cbdata",
-	"Callback Data Registry Contents",
-	cbdataDump, 0, 1);
-#define CREATE_CBDATA(type) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), NULL)
-#define CREATE_CBDATA_FREE(type, free_func) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), free_func)
-    /* XXX
-     * most of these should be moved out to their respective module.
-     */
-    CREATE_CBDATA(acl_access);
-    CREATE_CBDATA(aclCheck_t);
-    CREATE_CBDATA(clientHttpRequest);
-    CREATE_CBDATA(ConnStateData);
-    CREATE_CBDATA(ErrorState);
-    CREATE_CBDATA(FwdState);
-    CREATE_CBDATA(generic_cbdata);
-    CREATE_CBDATA(helper);
-    CREATE_CBDATA(helper_server);
-    CREATE_CBDATA(statefulhelper);
-    CREATE_CBDATA(helper_stateful_server);
-    CREATE_CBDATA_FREE(peer, peerDestroy);
-    CREATE_CBDATA(ps_state);
-    CREATE_CBDATA(RemovalPolicy);
-    CREATE_CBDATA(RemovalPolicyWalker);
-    CREATE_CBDATA(RemovalPurgeWalker);
-}
-
-void *
-#if CBDATA_DEBUG
-cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
-#else
-cbdataInternalAlloc(cbdata_type type)
-#endif
-{
-    cbdata *p;
-    assert(type > 0 && type < cbdata_types);
-    p = memPoolAlloc(cbdata_index[type].pool);
-    p->type = type;
-    p->valid = 1;
-    p->locks = 0;
-#if CBDATA_DEBUG
-    p->file = file;
-    p->line = line;
-#endif
-    p->y = (long) p ^ CBDATA_COOKIE;
-    cbdataCount++;
-
-#if CBDATA_DEBUG
-    dlinkAdd(p, &p->link, &cbdataEntries);
-#endif
-    return (void *) &p->data;
-}
-
-void *
-#if CBDATA_DEBUG
-cbdataInternalFreeDbg(void *p, const char *file, int line)
-#else
-cbdataInternalFree(void *p)
-#endif
-{
-    cbdata *c;
-    FREE *free_func;
-#if CBDATA_DEBUG
-    debug(45, 3) ("cbdataFree: %p %s:%d\n", p, file, line);
-#else
-    debug(45, 3) ("cbdataFree: %p\n", p);
-#endif
-    c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
-    CBDATA_CHECK(c);
-    c->valid = 0;
-    if (c->locks) {
-	debug(45, 3) ("cbdataFree: %p has %d locks, not freeing\n",
-	    p, c->locks);
-	return NULL;
-    }
-    cbdataCount--;
-    debug(45, 3) ("cbdataFree: Freeing %p\n", p);
-#if CBDATA_DEBUG
-    dlinkDelete(&c->link, &cbdataEntries);
-#endif
-    free_func = cbdata_index[c->type].free_func;
-    if (free_func)
-	free_func((void *) p);
-    memPoolFree(cbdata_index[c->type].pool, c);
-    return NULL;
-}
-
-void
-#if CBDATA_DEBUG
-cbdataInternalLockDbg(const void *p, const char *file, int line)
-#else
-cbdataInternalLock(const void *p)
-#endif
-{
-    cbdata *c;
-    if (p == NULL)
-	return;
-    c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
-#if CBDATA_DEBUG
-    debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p, c ? c->locks + 1 : -1, file, line);
-#else
-    debug(45, 3) ("cbdataLock: %p=%d\n", p, c ? c->locks + 1 : -1);
-#endif
-    CBDATA_CHECK(c);
-    c->locks++;
-}
-
-void
-#if CBDATA_DEBUG
-cbdataInternalUnlockDbg(const void *p, const char *file, int line)
-#else
-cbdataInternalUnlock(const void *p)
-#endif
-{
-    cbdata *c;
-    FREE *free_func;
-    if (p == NULL)
-	return;
-    c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
-#if CBDATA_DEBUG
-    debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p, c ? c->locks - 1 : -1, file, line);
-#else
-    debug(45, 3) ("cbdataUnlock: %p=%d\n", p, c ? c->locks - 1 : -1);
-#endif
-    CBDATA_CHECK(c);
-    assert(c != NULL);
-    assert(c->locks > 0);
-    c->locks--;
-    if (c->valid || c->locks)
-	return;
-    cbdataCount--;
-    debug(45, 3) ("cbdataUnlock: Freeing %p\n", p);
-#if CBDATA_DEBUG
-    dlinkDelete(&c->link, &cbdataEntries);
-#endif
-    free_func = cbdata_index[c->type].free_func;
-    if (free_func)
-	free_func((void *) p);
-    memPoolFree(cbdata_index[c->type].pool, c);
-}
-
-int
-cbdataReferenceValid(const void *p)
-{
-    cbdata *c;
-    if (p == NULL)
-	return 1;		/* A NULL pointer cannot become invalid */
-    debug(45, 3) ("cbdataReferenceValid: %p\n", p);
-    c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
-    CBDATA_CHECK(c);
-    assert(c->locks > 0);
-    return c->valid;
-}
-
-int
-#if CBDATA_DEBUG
-cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
-#else
-cbdataInternalReferenceDoneValid(void **pp, void **tp)
-#endif
-{
-    void *p = (void *) *pp;
-    int valid = cbdataReferenceValid(p);
-    *pp = NULL;
-#if CBDATA_DEBUG
-    cbdataInternalUnlockDbg(p, file, line);
-#else
-    cbdataInternalUnlock(p);
-#endif
-    if (valid) {
-	*tp = p;
-	return 1;
-    } else {
-	*tp = NULL;
-	return 0;
-    }
-}
-
-
-static void
-cbdataDump(StoreEntry * sentry)
-{
-#if CBDATA_DEBUG
-    dlink_node *n;
-    cbdata *p;
-    int i;
-#endif
-    storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
-#if CBDATA_DEBUG
-    storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
-    for (n = cbdataEntries.head; n; n = n->next) {
-	p = n->data;
-	storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", p->valid ? ' ' : '!', &p->data, p->type, p->locks, p->file, p->line);
-    }
-    storeAppendPrintf(sentry, "\n");
-    storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
-    for (i = 1; i < cbdata_types; i++) {
-	MemPool *pool = cbdata_index[i].pool;
-	if (pool) {
-	    int obj_size = pool->obj_size - OFFSET_OF(cbdata, data);
-	    storeAppendPrintf(sentry, "%s\t%d\t%d\t%d\n", pool->label + 7, obj_size, pool->meter.inuse.level, obj_size * pool->meter.inuse.level);
-	}
-    }
-#else
-    storeAppendPrintf(sentry, "detailed allocation information only available when compiled with CBDATA_DEBUG\n");
-#endif
-    storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/cbdata.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,323 @@
+
+/*
+ * $Id: cbdata.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 45    Callback Data Registry
+ * ORIGINAL AUTHOR: Duane Wessels
+ * Modified by Moez Mahfoudh (08/12/2000)
+ *
+ * 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.
+ *
+ */
+
+/*
+ * These routines manage a set of registered callback data pointers.
+ * One of the easiest ways to make Squid coredump is to issue a 
+ * callback to for some data structure which has previously been
+ * freed.  With these routines, we register (add) callback data
+ * pointers, lock them just before registering the callback function,
+ * validate them before issuing the callback, and then free them
+ * when finished.
+ */
+
+#include "squid.h"
+#include "Store.h"
+
+static int cbdataCount = 0;
+#if CBDATA_DEBUG
+dlink_list cbdataEntries;
+#endif
+
+typedef struct _cbdata {
+    int valid;
+    int locks;
+    int type;
+#if CBDATA_DEBUG
+    dlink_node link;
+    const char *file;
+    int line;
+#endif
+    long y;			/* cookie used while debugging */
+    union {
+	void *pointer;
+	double double_float;
+	int integer;
+    } data;
+} cbdata;
+
+static OBJH cbdataDump;
+
+struct CBDataIndex {
+    MemPool *pool;
+    FREE *free_func;
+}     *cbdata_index = NULL;
+int cbdata_types = 0;
+
+#define OFFSET_OF(type, member) ((int)(char *)&((type *)0L)->member)
+#define CBDATA_COOKIE	(long)0xDEADBEEF
+#define CBDATA_CHECK(c) assert(c->y == ((long)c ^ CBDATA_COOKIE))
+
+static void
+cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
+{
+    char *label;
+    if (type >= cbdata_types) {
+	cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
+	memset(&cbdata_index[cbdata_types], 0,
+	    (type + 1 - cbdata_types) * sizeof(*cbdata_index));
+	cbdata_types = type + 1;
+    }
+    if (cbdata_index[type].pool)
+	return;
+    label = (char *)xmalloc(strlen(name) + 20);
+    snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
+    assert(OFFSET_OF(cbdata, data) == (sizeof(cbdata) - sizeof(((cbdata *) NULL)->data)));
+    cbdata_index[type].pool = memPoolCreate(label, size + OFFSET_OF(cbdata, data));
+    cbdata_index[type].free_func = free_func;
+}
+
+cbdata_type
+cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
+{
+    if (type)
+	return type;
+    type = (cbdata_type)cbdata_types;
+    cbdataInternalInitType(type, name, size, free_func);
+    return type;
+}
+
+void
+cbdataInit(void)
+{
+    debug(45, 3) ("cbdataInit\n");
+    cachemgrRegister("cbdata",
+	"Callback Data Registry Contents",
+	cbdataDump, 0, 1);
+#define CREATE_CBDATA(type) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), NULL)
+#define CREATE_CBDATA_FREE(type, free_func) cbdataInternalInitType(CBDATA_##type, #type, sizeof(type), free_func)
+    /* XXX
+     * most of these should be moved out to their respective module.
+     */
+    CREATE_CBDATA(acl_access);
+    CREATE_CBDATA(aclCheck_t);
+    CREATE_CBDATA(clientHttpRequest);
+    CREATE_CBDATA(ConnStateData);
+    CREATE_CBDATA(ErrorState);
+    CREATE_CBDATA(FwdState);
+    CREATE_CBDATA(generic_cbdata);
+    CREATE_CBDATA(helper);
+    CREATE_CBDATA(helper_server);
+    CREATE_CBDATA(statefulhelper);
+    CREATE_CBDATA(helper_stateful_server);
+    CREATE_CBDATA_FREE(peer, peerDestroy);
+    CREATE_CBDATA(ps_state);
+    CREATE_CBDATA(RemovalPolicy);
+    CREATE_CBDATA(RemovalPolicyWalker);
+    CREATE_CBDATA(RemovalPurgeWalker);
+}
+
+void *
+#if CBDATA_DEBUG
+cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
+#else
+cbdataInternalAlloc(cbdata_type type)
+#endif
+{
+    cbdata *p;
+    assert(type > 0 && type < cbdata_types);
+    p = (cbdata *)memPoolAlloc(cbdata_index[type].pool);
+    p->type = type;
+    p->valid = 1;
+    p->locks = 0;
+#if CBDATA_DEBUG
+    p->file = file;
+    p->line = line;
+#endif
+    p->y = (long) p ^ CBDATA_COOKIE;
+    cbdataCount++;
+
+#if CBDATA_DEBUG
+    dlinkAdd(p, &p->link, &cbdataEntries);
+#endif
+    return (void *) &p->data;
+}
+
+void *
+#if CBDATA_DEBUG
+cbdataInternalFreeDbg(void *p, const char *file, int line)
+#else
+cbdataInternalFree(void *p)
+#endif
+{
+    cbdata *c;
+    FREE *free_func;
+#if CBDATA_DEBUG
+    debug(45, 3) ("cbdataFree: %p %s:%d\n", p, file, line);
+#else
+    debug(45, 3) ("cbdataFree: %p\n", p);
+#endif
+    c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
+    CBDATA_CHECK(c);
+    c->valid = 0;
+    if (c->locks) {
+	debug(45, 3) ("cbdataFree: %p has %d locks, not freeing\n",
+	    p, c->locks);
+	return NULL;
+    }
+    cbdataCount--;
+    debug(45, 3) ("cbdataFree: Freeing %p\n", p);
+#if CBDATA_DEBUG
+    dlinkDelete(&c->link, &cbdataEntries);
+#endif
+    free_func = cbdata_index[c->type].free_func;
+    if (free_func)
+	free_func((void *) p);
+    memPoolFree(cbdata_index[c->type].pool, c);
+    return NULL;
+}
+
+void
+#if CBDATA_DEBUG
+cbdataInternalLockDbg(const void *p, const char *file, int line)
+#else
+cbdataInternalLock(const void *p)
+#endif
+{
+    cbdata *c;
+    if (p == NULL)
+	return;
+    c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
+#if CBDATA_DEBUG
+    debug(45, 3) ("cbdataLock: %p=%d %s:%d\n", p, c ? c->locks + 1 : -1, file, line);
+#else
+    debug(45, 3) ("cbdataLock: %p=%d\n", p, c ? c->locks + 1 : -1);
+#endif
+    CBDATA_CHECK(c);
+    c->locks++;
+}
+
+void
+#if CBDATA_DEBUG
+cbdataInternalUnlockDbg(const void *p, const char *file, int line)
+#else
+cbdataInternalUnlock(const void *p)
+#endif
+{
+    cbdata *c;
+    FREE *free_func;
+    if (p == NULL)
+	return;
+    c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
+#if CBDATA_DEBUG
+    debug(45, 3) ("cbdataUnlock: %p=%d %s:%d\n", p, c ? c->locks - 1 : -1, file, line);
+#else
+    debug(45, 3) ("cbdataUnlock: %p=%d\n", p, c ? c->locks - 1 : -1);
+#endif
+    CBDATA_CHECK(c);
+    assert(c != NULL);
+    assert(c->locks > 0);
+    c->locks--;
+    if (c->valid || c->locks)
+	return;
+    cbdataCount--;
+    debug(45, 3) ("cbdataUnlock: Freeing %p\n", p);
+#if CBDATA_DEBUG
+    dlinkDelete(&c->link, &cbdataEntries);
+#endif
+    free_func = cbdata_index[c->type].free_func;
+    if (free_func)
+	free_func((void *) p);
+    memPoolFree(cbdata_index[c->type].pool, c);
+}
+
+int
+cbdataReferenceValid(const void *p)
+{
+    cbdata *c;
+    if (p == NULL)
+	return 1;		/* A NULL pointer cannot become invalid */
+    debug(45, 3) ("cbdataReferenceValid: %p\n", p);
+    c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data));
+    CBDATA_CHECK(c);
+    assert(c->locks > 0);
+    return c->valid;
+}
+
+int
+#if CBDATA_DEBUG
+cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
+#else
+cbdataInternalReferenceDoneValid(void **pp, void **tp)
+#endif
+{
+    void *p = (void *) *pp;
+    int valid = cbdataReferenceValid(p);
+    *pp = NULL;
+#if CBDATA_DEBUG
+    cbdataInternalUnlockDbg(p, file, line);
+#else
+    cbdataInternalUnlock(p);
+#endif
+    if (valid) {
+	*tp = p;
+	return 1;
+    } else {
+	*tp = NULL;
+	return 0;
+    }
+}
+
+
+static void
+cbdataDump(StoreEntry * sentry)
+{
+#if CBDATA_DEBUG
+    dlink_node *n;
+    cbdata *p;
+    int i;
+#endif
+    storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
+#if CBDATA_DEBUG
+    storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
+    for (n = cbdataEntries.head; n; n = n->next) {
+	p = n->data;
+	storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", p->valid ? ' ' : '!', &p->data, p->type, p->locks, p->file, p->line);
+    }
+    storeAppendPrintf(sentry, "\n");
+    storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
+    for (i = 1; i < cbdata_types; i++) {
+	MemPool *pool = cbdata_index[i].pool;
+	if (pool) {
+	    int obj_size = pool->obj_size - OFFSET_OF(cbdata, data);
+	    storeAppendPrintf(sentry, "%s\t%d\t%d\t%d\n", pool->label + 7, obj_size, pool->meter.inuse.level, obj_size * pool->meter.inuse.level);
+	}
+    }
+#else
+    storeAppendPrintf(sentry, "detailed allocation information only available when compiled with CBDATA_DEBUG\n");
+#endif
+    storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
+}
--- squid/src/cf_gen.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,669 +0,0 @@
-
-/*
- * $Id: cf_gen.c,v 1.14 2002/09/01 16:30:42 squidadm Exp $
- *
- * DEBUG: none          Generate squid.conf.default and cf_parser.h
- * AUTHOR: Max Okumoto
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-/*****************************************************************************
- * Abstract:	This program parses the input file and generates code and
- *		files used to configure the variables in squid.
- *		(ie it creates the squid.conf.default file from the cf.data file)
- *
- *		The output files are as follows:
- *		cf_parser.h - this file contains, default_all() which
- *			  initializes variables with the default
- *			  values, parse_line() that parses line from
- *			  squid.conf.default, dump_config that dumps the
- *			  current the values of the variables.
- *		squid.conf.default - default configuration file given to the server
- *			 administrator.
- *****************************************************************************/
-
-#include "config.h"
-#include "cf_gen_defines.h"
-
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-#if HAVE_ASSERT_H
-#include <assert.h>
-#endif
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-#include <io.h>
-#endif
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#include "util.h"
-
-#define MAX_LINE	1024	/* longest configuration line */
-#define _PATH_PARSER		"cf_parser.h"
-#define _PATH_SQUID_CONF	"squid.conf.default"
-
-enum State {
-    sSTART,
-    s1,
-    sDOC,
-    sNOCOMMENT,
-    sEXIT
-};
-
-typedef struct Line {
-    char *data;
-    struct Line *next;
-} Line;
-
-typedef struct EntryAlias {
-    struct EntryAlias *next;
-    char *name;
-} EntryAlias;
-
-typedef struct Entry {
-    char *name;
-    EntryAlias *alias;
-    char *type;
-    char *loc;
-    char *default_value;
-    Line *default_if_none;
-    char *comment;
-    char *ifdef;
-    Line *doc;
-    Line *nocomment;
-    int array_flag;
-    struct Entry *next;
-} Entry;
-
-
-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_default_if_none(Entry *, FILE *);
-
-static void
-lineAdd(Line ** L, const char *str)
-{
-    while (*L)
-	L = &(*L)->next;
-    *L = xcalloc(1, sizeof(Line));
-    (*L)->data = xstrdup(str);
-}
-
-int
-main(int argc, char *argv[])
-{
-    FILE *fp;
-    char *input_filename = argv[1];
-    const char *output_filename = _PATH_PARSER;
-    const char *conf_filename = _PATH_SQUID_CONF;
-    int linenum = 0;
-    Entry *entries = NULL;
-    Entry *curr = NULL;
-    enum State state;
-    int rc = 0;
-    char *ptr = NULL;
-#ifdef _SQUID_OS2_
-    const char *rmode = "rt";
-#else
-    const char *rmode = "r";
-#endif
-
-    /*-------------------------------------------------------------------*
-     * Parse input file
-     *-------------------------------------------------------------------*/
-
-    /* Open input file */
-    if ((fp = fopen(input_filename, rmode)) == NULL) {
-	perror(input_filename);
-	exit(1);
-    }
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-    setmode(fileno(fp), O_TEXT);
-#endif
-    state = sSTART;
-    while (feof(fp) == 0 && state != sEXIT) {
-	char buff[MAX_LINE];
-	char *t;
-	if (NULL == fgets(buff, MAX_LINE, fp))
-	    break;
-	linenum++;
-	if ((t = strchr(buff, '\n')))
-	    *t = '\0';
-	switch (state) {
-	case sSTART:
-	    if ((strlen(buff) == 0) || (!strncmp(buff, "#", 1))) {
-		/* ignore empty and comment lines */
-		(void) 0;
-	    } else if (!strncmp(buff, "NAME:", 5)) {
-		char *name, *aliasname;
-		if ((name = strtok(buff + 5, WS)) == NULL) {
-		    printf("Error in input file\n");
-		    exit(1);
-		}
-		curr = calloc(1, sizeof(Entry));
-		curr->name = xstrdup(name);
-		while ((aliasname = strtok(NULL, WS)) != NULL) {
-		    EntryAlias *alias = calloc(1, sizeof(EntryAlias));
-		    alias->next = curr->alias;
-		    alias->name = xstrdup(aliasname);
-		    curr->alias = alias;
-		}
-		state = s1;
-	    } else if (!strcmp(buff, "EOF")) {
-		state = sEXIT;
-	    } else if (!strcmp(buff, "COMMENT_START")) {
-		curr = calloc(1, sizeof(Entry));
-		curr->name = xstrdup("comment");
-		curr->loc = xstrdup("none");
-		state = sDOC;
-	    } else {
-		printf("Error on line %d\n", linenum);
-		printf("--> %s\n", buff);
-		exit(1);
-	    }
-	    break;
-
-	case s1:
-	    if ((strlen(buff) == 0) || (!strncmp(buff, "#", 1))) {
-		/* ignore empty and comment lines */
-		(void) 0;
-	    } else if (!strncmp(buff, "COMMENT:", 8)) {
-		ptr = buff + 8;
-		while (xisspace(*ptr))
-		    ptr++;
-		curr->comment = xstrdup(ptr);
-	    } else if (!strncmp(buff, "DEFAULT:", 8)) {
-		ptr = buff + 8;
-		while (xisspace(*ptr))
-		    ptr++;
-		curr->default_value = xstrdup(ptr);
-	    } else if (!strncmp(buff, "DEFAULT_IF_NONE:", 16)) {
-		ptr = buff + 16;
-		while (xisspace(*ptr))
-		    ptr++;
-		lineAdd(&curr->default_if_none, ptr);
-	    } else if (!strncmp(buff, "LOC:", 4)) {
-		if ((ptr = strtok(buff + 4, WS)) == NULL) {
-		    printf("Error on line %d\n", linenum);
-		    exit(1);
-		}
-		curr->loc = xstrdup(ptr);
-	    } else if (!strncmp(buff, "TYPE:", 5)) {
-		if ((ptr = strtok(buff + 5, WS)) == NULL) {
-		    printf("Error on line %d\n", linenum);
-		    exit(1);
-		}
-		/* hack to support arrays, rather than pointers */
-		if (0 == strcmp(ptr + strlen(ptr) - 2, "[]")) {
-		    curr->array_flag = 1;
-		    *(ptr + strlen(ptr) - 2) = '\0';
-		}
-		curr->type = xstrdup(ptr);
-	    } else if (!strncmp(buff, "IFDEF:", 6)) {
-		if ((ptr = strtok(buff + 6, WS)) == NULL) {
-		    printf("Error on line %d\n", linenum);
-		    exit(1);
-		}
-		curr->ifdef = xstrdup(ptr);
-	    } else if (!strcmp(buff, "DOC_START")) {
-		state = sDOC;
-	    } else if (!strcmp(buff, "DOC_NONE")) {
-		/* add to list of entries */
-		curr->next = entries;
-		entries = curr;
-		state = sSTART;
-	    } else {
-		printf("Error on line %d\n", linenum);
-		exit(1);
-	    }
-	    break;
-
-	case sDOC:
-	    if (!strcmp(buff, "DOC_END") || !strcmp(buff, "COMMENT_END")) {
-		Line *head = NULL;
-		Line *line = curr->doc;
-		/* reverse order of doc lines */
-		while (line != NULL) {
-		    Line *tmp;
-		    tmp = line->next;
-		    line->next = head;
-		    head = line;
-		    line = tmp;
-		}
-		curr->doc = head;
-		/* add to list of entries */
-		curr->next = entries;
-		entries = curr;
-		state = sSTART;
-	    } else if (!strcmp(buff, "NOCOMMENT_START")) {
-		state = sNOCOMMENT;
-	    } else {
-		Line *line = calloc(1, sizeof(Line));
-		line->data = xstrdup(buff);
-		line->next = curr->doc;
-		curr->doc = line;
-	    }
-	    break;
-
-	case sNOCOMMENT:
-	    if (!strcmp(buff, "NOCOMMENT_END")) {
-		Line *head = NULL;
-		Line *line = curr->nocomment;
-		/* reverse order of lines */
-		while (line != NULL) {
-		    Line *tmp;
-		    tmp = line->next;
-		    line->next = head;
-		    head = line;
-		    line = tmp;
-		}
-		curr->nocomment = head;
-		state = sDOC;
-	    } else {
-		Line *line = calloc(1, sizeof(Line));
-		line->data = xstrdup(buff);
-		line->next = curr->nocomment;
-		curr->nocomment = line;
-	    }
-	    break;
-
-	case sEXIT:
-	    assert(0);		/* should never get here */
-	    break;
-	}
-    }
-    if (state != sEXIT) {
-	printf("Error unexpected EOF\n");
-	exit(1);
-    } else {
-	/* reverse order of entries */
-	Entry *head = NULL;
-
-	while (entries != NULL) {
-	    Entry *tmp;
-
-	    tmp = entries->next;
-	    entries->next = head;
-	    head = entries;
-	    entries = tmp;
-	}
-	entries = head;
-    }
-    fclose(fp);
-
-    /*-------------------------------------------------------------------*
-     * Generate default_all()
-     * Generate parse_line()
-     * Generate dump_config()
-     * Generate free_all()
-     * Generate example squid.conf.default file
-     *-------------------------------------------------------------------*/
-
-    /* Open output x.c file */
-    if ((fp = fopen(output_filename, "w")) == NULL) {
-	perror(output_filename);
-	exit(1);
-    }
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-    setmode(fileno(fp), O_TEXT);
-#endif
-    fprintf(fp,
-	"/*\n"
-	" * Generated automatically from %s by %s\n"
-	" *\n"
-	" * Abstract: This file contains routines used to configure the\n"
-	" *           variables in the squid server.\n"
-	" */\n"
-	"\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);
-    fclose(fp);
-
-    /* Open output x.conf file */
-    if ((fp = fopen(conf_filename, "w")) == NULL) {
-	perror(conf_filename);
-	exit(1);
-    }
-#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
-    setmode(fileno(fp), O_TEXT);
-#endif
-    gen_conf(entries, fp);
-    fclose(fp);
-
-    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);
-	if (entry->default_if_none == NULL)
-	    continue;
-	if (entry->ifdef)
-	    fprintf(fp, "#if %s\n", entry->ifdef);
-	if (entry->default_if_none) {
-	    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");
-	}
-	if (entry->ifdef)
-	    fprintf(fp, "#endif\n");
-    }
-    fprintf(fp, "}\n\n");
-}
-
-static void
-gen_parse(Entry * head, FILE * fp)
-{
-    Entry *entry;
-    char *name;
-    EntryAlias *alias;
-
-    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"
-	);
-
-    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);
-	name = entry->name;
-	alias = entry->alias;
-      next_alias:
-	fprintf(fp, "\telse if (!strcmp(token, \"%s\"))\n", 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 (alias) {
-	    name = alias->name;
-	    alias = alias->next;
-	    goto next_alias;
-	}
-	if (entry->ifdef)
-	    fprintf(fp, "#endif\n");
-    }
-
-    fprintf(fp,
-	"\telse\n"
-	"\t\tresult = 0; /* failure */\n"
-	"\treturn(result);\n"
-	"}\n\n"
-	);
-}
-
-static void
-gen_dump(Entry * head, FILE * fp)
-{
-    Entry *entry;
-    fprintf(fp,
-	"static void\n"
-	"dump_config(StoreEntry *entry)\n"
-	"{\n"
-	);
-    for (entry = head; entry != NULL; entry = entry->next) {
-	assert(entry->loc);
-	if (strcmp(entry->loc, "none") == 0)
-	    continue;
-	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");
-    }
-    fprintf(fp, "}\n\n");
-}
-
-static void
-gen_free(Entry * head, FILE * fp)
-{
-    Entry *entry;
-    fprintf(fp,
-	"static void\n"
-	"free_all(void)\n"
-	"{\n"
-	);
-    for (entry = head; entry != NULL; entry = entry->next) {
-	assert(entry->loc);
-	if (strcmp(entry->loc, "none") == 0)
-	    continue;
-	if (strcmp(entry->name, "comment") == 0)
-	    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, "}\n\n");
-}
-
-static int
-defined(char *name)
-{
-    int i = 0;
-    if (!name)
-	return 1;
-    for (i = 0; strcmp(defines[i].name, name) != 0; i++) {
-	assert(defines[i].name);
-    }
-    return defines[i].defined;
-}
-
-static const char *
-available_if(char *name)
-{
-    int i = 0;
-    assert(name);
-    for (i = 0; strcmp(defines[i].name, name) != 0; i++) {
-	assert(defines[i].name);
-    }
-    return defines[i].enable;
-}
-
-static void
-gen_conf(Entry * head, FILE * fp)
-{
-    Entry *entry;
-    char buf[8192];
-    Line *def = NULL;
-
-    for (entry = head; entry != NULL; entry = entry->next) {
-	Line *line;
-	int blank = 1;
-
-	if (!strcmp(entry->name, "comment"))
-	    (void) 0;
-	else
-	    fprintf(fp, "#  TAG: %s", entry->name);
-	if (entry->comment)
-	    fprintf(fp, "\t%s", entry->comment);
-	fprintf(fp, "\n");
-	if (!defined(entry->ifdef)) {
-	    fprintf(fp, "# Note: This option is only available if Squid is rebuilt with the\n");
-	    fprintf(fp, "#       %s option\n#\n", available_if(entry->ifdef));
-	}
-	for (line = entry->doc; line != NULL; line = line->next) {
-	    fprintf(fp, "#%s\n", 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");
-	    fprintf(fp, "#Default:\n");
-	    while (def != NULL) {
-		line = def;
-		def = line->next;
-		fprintf(fp, "# %s\n", line->data);
-		xfree(line->data);
-		xfree(line);
-	    }
-	    blank = 1;
-	}
-	if (entry->nocomment && blank)
-	    fprintf(fp, "#\n");
-	for (line = entry->nocomment; line != NULL; line = line->next) {
-	    fprintf(fp, "%s\n", line->data);
-	}
-	if (entry->doc != NULL) {
-	    fprintf(fp, "\n");
-	}
-    }
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/cf_gen.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,669 @@
+
+/*
+ * $Id: cf_gen.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: none          Generate squid.conf.default and cf_parser.h
+ * AUTHOR: Max Okumoto
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/*****************************************************************************
+ * Abstract:	This program parses the input file and generates code and
+ *		files used to configure the variables in squid.
+ *		(ie it creates the squid.conf.default file from the cf.data file)
+ *
+ *		The output files are as follows:
+ *		cf_parser.h - this file contains, default_all() which
+ *			  initializes variables with the default
+ *			  values, parse_line() that parses line from
+ *			  squid.conf.default, dump_config that dumps the
+ *			  current the values of the variables.
+ *		squid.conf.default - default configuration file given to the server
+ *			 administrator.
+ *****************************************************************************/
+
+#include "config.h"
+#include "cf_gen_defines.h"
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_ASSERT_H
+#include <assert.h>
+#endif
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+#include <io.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "util.h"
+
+#define MAX_LINE	1024	/* longest configuration line */
+#define _PATH_PARSER		"cf_parser.h"
+#define _PATH_SQUID_CONF	"squid.conf.default"
+
+enum State {
+    sSTART,
+    s1,
+    sDOC,
+    sNOCOMMENT,
+    sEXIT
+};
+
+typedef struct Line {
+    char *data;
+    struct Line *next;
+} Line;
+
+typedef struct EntryAlias {
+    struct EntryAlias *next;
+    char *name;
+} EntryAlias;
+
+typedef struct Entry {
+    char *name;
+    EntryAlias *alias;
+    char *type;
+    char *loc;
+    char *default_value;
+    Line *default_if_none;
+    char *comment;
+    char *ifdef;
+    Line *doc;
+    Line *nocomment;
+    int array_flag;
+    struct Entry *next;
+} Entry;
+
+
+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_default_if_none(Entry *, FILE *);
+
+static void
+lineAdd(Line ** L, const char *str)
+{
+    while (*L)
+	L = &(*L)->next;
+    *L = (Line *)xcalloc(1, sizeof(Line));
+    (*L)->data = xstrdup(str);
+}
+
+int
+main(int argc, char *argv[])
+{
+    FILE *fp;
+    char *input_filename = argv[1];
+    const char *output_filename = _PATH_PARSER;
+    const char *conf_filename = _PATH_SQUID_CONF;
+    int linenum = 0;
+    Entry *entries = NULL;
+    Entry *curr = NULL;
+    enum State state;
+    int rc = 0;
+    char *ptr = NULL;
+#ifdef _SQUID_OS2_
+    const char *rmode = "rt";
+#else
+    const char *rmode = "r";
+#endif
+
+    /*-------------------------------------------------------------------*
+     * Parse input file
+     *-------------------------------------------------------------------*/
+
+    /* Open input file */
+    if ((fp = fopen(input_filename, rmode)) == NULL) {
+	perror(input_filename);
+	exit(1);
+    }
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+    setmode(fileno(fp), O_TEXT);
+#endif
+    state = sSTART;
+    while (feof(fp) == 0 && state != sEXIT) {
+	char buff[MAX_LINE];
+	char *t;
+	if (NULL == fgets(buff, MAX_LINE, fp))
+	    break;
+	linenum++;
+	if ((t = strchr(buff, '\n')))
+	    *t = '\0';
+	switch (state) {
+	case sSTART:
+	    if ((strlen(buff) == 0) || (!strncmp(buff, "#", 1))) {
+		/* ignore empty and comment lines */
+		(void) 0;
+	    } else if (!strncmp(buff, "NAME:", 5)) {
+		char *name, *aliasname;
+		if ((name = strtok(buff + 5, WS)) == NULL) {
+		    printf("Error in input file\n");
+		    exit(1);
+		}
+		curr = (Entry *)calloc(1, sizeof(Entry));
+		curr->name = xstrdup(name);
+		while ((aliasname = strtok(NULL, WS)) != NULL) {
+		    EntryAlias *alias = (EntryAlias *)calloc(1, sizeof(EntryAlias));
+		    alias->next = curr->alias;
+		    alias->name = xstrdup(aliasname);
+		    curr->alias = alias;
+		}
+		state = s1;
+	    } else if (!strcmp(buff, "EOF")) {
+		state = sEXIT;
+	    } else if (!strcmp(buff, "COMMENT_START")) {
+		curr = (Entry *)calloc(1, sizeof(Entry));
+		curr->name = xstrdup("comment");
+		curr->loc = xstrdup("none");
+		state = sDOC;
+	    } else {
+		printf("Error on line %d\n", linenum);
+		printf("--> %s\n", buff);
+		exit(1);
+	    }
+	    break;
+
+	case s1:
+	    if ((strlen(buff) == 0) || (!strncmp(buff, "#", 1))) {
+		/* ignore empty and comment lines */
+		(void) 0;
+	    } else if (!strncmp(buff, "COMMENT:", 8)) {
+		ptr = buff + 8;
+		while (xisspace(*ptr))
+		    ptr++;
+		curr->comment = xstrdup(ptr);
+	    } else if (!strncmp(buff, "DEFAULT:", 8)) {
+		ptr = buff + 8;
+		while (xisspace(*ptr))
+		    ptr++;
+		curr->default_value = xstrdup(ptr);
+	    } else if (!strncmp(buff, "DEFAULT_IF_NONE:", 16)) {
+		ptr = buff + 16;
+		while (xisspace(*ptr))
+		    ptr++;
+		lineAdd(&curr->default_if_none, ptr);
+	    } else if (!strncmp(buff, "LOC:", 4)) {
+		if ((ptr = strtok(buff + 4, WS)) == NULL) {
+		    printf("Error on line %d\n", linenum);
+		    exit(1);
+		}
+		curr->loc = xstrdup(ptr);
+	    } else if (!strncmp(buff, "TYPE:", 5)) {
+		if ((ptr = strtok(buff + 5, WS)) == NULL) {
+		    printf("Error on line %d\n", linenum);
+		    exit(1);
+		}
+		/* hack to support arrays, rather than pointers */
+		if (0 == strcmp(ptr + strlen(ptr) - 2, "[]")) {
+		    curr->array_flag = 1;
+		    *(ptr + strlen(ptr) - 2) = '\0';
+		}
+		curr->type = xstrdup(ptr);
+	    } else if (!strncmp(buff, "IFDEF:", 6)) {
+		if ((ptr = strtok(buff + 6, WS)) == NULL) {
+		    printf("Error on line %d\n", linenum);
+		    exit(1);
+		}
+		curr->ifdef = xstrdup(ptr);
+	    } else if (!strcmp(buff, "DOC_START")) {
+		state = sDOC;
+	    } else if (!strcmp(buff, "DOC_NONE")) {
+		/* add to list of entries */
+		curr->next = entries;
+		entries = curr;
+		state = sSTART;
+	    } else {
+		printf("Error on line %d\n", linenum);
+		exit(1);
+	    }
+	    break;
+
+	case sDOC:
+	    if (!strcmp(buff, "DOC_END") || !strcmp(buff, "COMMENT_END")) {
+		Line *head = NULL;
+		Line *line = curr->doc;
+		/* reverse order of doc lines */
+		while (line != NULL) {
+		    Line *tmp;
+		    tmp = line->next;
+		    line->next = head;
+		    head = line;
+		    line = tmp;
+		}
+		curr->doc = head;
+		/* add to list of entries */
+		curr->next = entries;
+		entries = curr;
+		state = sSTART;
+	    } else if (!strcmp(buff, "NOCOMMENT_START")) {
+		state = sNOCOMMENT;
+	    } else {
+		Line *line = (Line *)calloc(1, sizeof(Line));
+		line->data = xstrdup(buff);
+		line->next = curr->doc;
+		curr->doc = line;
+	    }
+	    break;
+
+	case sNOCOMMENT:
+	    if (!strcmp(buff, "NOCOMMENT_END")) {
+		Line *head = NULL;
+		Line *line = curr->nocomment;
+		/* reverse order of lines */
+		while (line != NULL) {
+		    Line *tmp;
+		    tmp = line->next;
+		    line->next = head;
+		    head = line;
+		    line = tmp;
+		}
+		curr->nocomment = head;
+		state = sDOC;
+	    } else {
+		Line *line = (Line *)calloc(1, sizeof(Line));
+		line->data = xstrdup(buff);
+		line->next = curr->nocomment;
+		curr->nocomment = line;
+	    }
+	    break;
+
+	case sEXIT:
+	    assert(0);		/* should never get here */
+	    break;
+	}
+    }
+    if (state != sEXIT) {
+	printf("Error unexpected EOF\n");
+	exit(1);
+    } else {
+	/* reverse order of entries */
+	Entry *head = NULL;
+
+	while (entries != NULL) {
+	    Entry *tmp;
+
+	    tmp = entries->next;
+	    entries->next = head;
+	    head = entries;
+	    entries = tmp;
+	}
+	entries = head;
+    }
+    fclose(fp);
+
+    /*-------------------------------------------------------------------*
+     * Generate default_all()
+     * Generate parse_line()
+     * Generate dump_config()
+     * Generate free_all()
+     * Generate example squid.conf.default file
+     *-------------------------------------------------------------------*/
+
+    /* Open output x.c file */
+    if ((fp = fopen(output_filename, "w")) == NULL) {
+	perror(output_filename);
+	exit(1);
+    }
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+    setmode(fileno(fp), O_TEXT);
+#endif
+    fprintf(fp,
+	"/*\n"
+	" * Generated automatically from %s by %s\n"
+	" *\n"
+	" * Abstract: This file contains routines used to configure the\n"
+	" *           variables in the squid server.\n"
+	" */\n"
+	"\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);
+    fclose(fp);
+
+    /* Open output x.conf file */
+    if ((fp = fopen(conf_filename, "w")) == NULL) {
+	perror(conf_filename);
+	exit(1);
+    }
+#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
+    setmode(fileno(fp), O_TEXT);
+#endif
+    gen_conf(entries, fp);
+    fclose(fp);
+
+    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);
+	if (entry->default_if_none == NULL)
+	    continue;
+	if (entry->ifdef)
+	    fprintf(fp, "#if %s\n", entry->ifdef);
+	if (entry->default_if_none) {
+	    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");
+	}
+	if (entry->ifdef)
+	    fprintf(fp, "#endif\n");
+    }
+    fprintf(fp, "}\n\n");
+}
+
+static void
+gen_parse(Entry * head, FILE * fp)
+{
+    Entry *entry;
+    char *name;
+    EntryAlias *alias;
+
+    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"
+	);
+
+    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);
+	name = entry->name;
+	alias = entry->alias;
+      next_alias:
+	fprintf(fp, "\telse if (!strcmp(token, \"%s\"))\n", 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 (alias) {
+	    name = alias->name;
+	    alias = alias->next;
+	    goto next_alias;
+	}
+	if (entry->ifdef)
+	    fprintf(fp, "#endif\n");
+    }
+
+    fprintf(fp,
+	"\telse\n"
+	"\t\tresult = 0; /* failure */\n"
+	"\treturn(result);\n"
+	"}\n\n"
+	);
+}
+
+static void
+gen_dump(Entry * head, FILE * fp)
+{
+    Entry *entry;
+    fprintf(fp,
+	"static void\n"
+	"dump_config(StoreEntry *entry)\n"
+	"{\n"
+	);
+    for (entry = head; entry != NULL; entry = entry->next) {
+	assert(entry->loc);
+	if (strcmp(entry->loc, "none") == 0)
+	    continue;
+	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");
+    }
+    fprintf(fp, "}\n\n");
+}
+
+static void
+gen_free(Entry * head, FILE * fp)
+{
+    Entry *entry;
+    fprintf(fp,
+	"static void\n"
+	"free_all(void)\n"
+	"{\n"
+	);
+    for (entry = head; entry != NULL; entry = entry->next) {
+	assert(entry->loc);
+	if (strcmp(entry->loc, "none") == 0)
+	    continue;
+	if (strcmp(entry->name, "comment") == 0)
+	    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, "}\n\n");
+}
+
+static int
+defined(char *name)
+{
+    int i = 0;
+    if (!name)
+	return 1;
+    for (i = 0; strcmp(defines[i].name, name) != 0; i++) {
+	assert(defines[i].name);
+    }
+    return defines[i].defined;
+}
+
+static const char *
+available_if(char *name)
+{
+    int i = 0;
+    assert(name);
+    for (i = 0; strcmp(defines[i].name, name) != 0; i++) {
+	assert(defines[i].name);
+    }
+    return defines[i].enable;
+}
+
+static void
+gen_conf(Entry * head, FILE * fp)
+{
+    Entry *entry;
+    char buf[8192];
+    Line *def = NULL;
+
+    for (entry = head; entry != NULL; entry = entry->next) {
+	Line *line;
+	int blank = 1;
+
+	if (!strcmp(entry->name, "comment"))
+	    (void) 0;
+	else
+	    fprintf(fp, "#  TAG: %s", entry->name);
+	if (entry->comment)
+	    fprintf(fp, "\t%s", entry->comment);
+	fprintf(fp, "\n");
+	if (!defined(entry->ifdef)) {
+	    fprintf(fp, "# Note: This option is only available if Squid is rebuilt with the\n");
+	    fprintf(fp, "#       %s option\n#\n", available_if(entry->ifdef));
+	}
+	for (line = entry->doc; line != NULL; line = line->next) {
+	    fprintf(fp, "#%s\n", 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");
+	    fprintf(fp, "#Default:\n");
+	    while (def != NULL) {
+		line = def;
+		def = line->next;
+		fprintf(fp, "# %s\n", line->data);
+		xfree(line->data);
+		xfree(line);
+	    }
+	    blank = 1;
+	}
+	if (entry->nocomment && blank)
+	    fprintf(fp, "#\n");
+	for (line = entry->nocomment; line != NULL; line = line->next) {
+	    fprintf(fp, "%s\n", line->data);
+	}
+	if (entry->doc != NULL) {
+	    fprintf(fp, "\n");
+	}
+    }
+}
Index: squid/src/cf_gen_defines
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/cf_gen_defines,v
retrieving revision 1.5
retrieving revision 1.5.40.1
diff -u -r1.5 -r1.5.40.1
--- squid/src/cf_gen_defines	3 Dec 2001 08:03:21 -0000	1.5
+++ squid/src/cf_gen_defines	9 Oct 2002 00:23:16 -0000	1.5.40.1
@@ -33,5 +33,5 @@
 	print "},"
 }
 END {
-	print "{(void *)0L, 0}};"
+	print "{(char const *)0L, (char const *)0L, 0}};"
 }
--- squid/src/clientStream.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,275 +0,0 @@
-
-/*
- * $Id: clientStream.c,v 1.3 2002/09/24 10:59:14 rbcollins Exp $
- *
- * DEBUG: section 87    Client-side Stream routines.
- * AUTHOR: Robert Collins
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-/*
- * A client Stream is a uni directional pipe, with the usual non-blocking
- * asynchronous approach present elsewhere in squid.
- *
- * Each pipe node has a data push function, and a data request function.
- * This limits flexability - the data flow is no longer assembled at each
- * step. 
- *
- * An alternative approach is to pass each node in the pipe the call-
- * back to use on each IO call. This allows the callbacks to be changed 
- * very easily by a participating node, but requires more maintenance 
- * in each node (store the call  back to the msot recent IO request in 
- * the nodes context.) Such an approach also prevents dynamically 
- * changing the pipeline from outside without an additional interface
- * method to extract the callback and context from the next node.
- *
- * One important characteristic of the stream is that the readfunc
- * on the terminating node, and the callback on the first node
- * will be NULL, and never used.
- */
-
-#include "squid.h"
-#include "clientStream.h"
-
-CBDATA_TYPE(clientStreamNode);
-
-/*
- * TODO: rather than each node undeleting the next, have a clientStreamDelete
- * that walks the list
- */
-
-/*
- * clientStream quick notes:
- *
- * Each node including the HEAD of the clientStream has a cbdataReference
- * held by the stream. Freeing the stream then removes that reference
- * and cbdataFrees every node.
- * Any node with other References, and all nodes downstream will only 
- * free when those references are released.
- * Stream nodes MAY hold references to the data member of the node. 
- *
- * Specifically - on creation no reference is made. 
- * If you pass a data variable to a node, give it an initial reference.
- * If the data member is non-null on FREE, cbdataFree WILL be called.
- * This you must never call cbdataFree on your own context without
- * explicitly setting the stream node data member to NULL and
- * cbdataReferenceDone'ing it.
- *
- * No data member may hold a reference to it's stream node.
- * The stream guarantees that DETACH will be called before
- * freeing the node, alowing data members to cleanup.
- * 
- * If a node's data holds a reference to something that needs to
- * free the stream a circular reference list will occur.
- * This results no data being freed until that reference is removed.
- * One way to accomplish this is to explicitly remove the
- * data from your own node before freeing the stream.
- *
- * (i.e. 
- * mycontext = this->data;
- * cbdataReferenceDone (mycontext);
- * clientStreamFreeLinst (this->head);
- * cbdataFree (mycontext);
- * return;
- */
-
-/* Local functions */
-static FREE clientStreamFree;
-
-clientStreamNode *
-clientStreamNew(CSR * readfunc, CSCB * callback, CSD * detach, CSS * status,
-    void *data)
-{
-    clientStreamNode *temp;
-    CBDATA_INIT_TYPE_FREECB(clientStreamNode, clientStreamFree);
-    temp = cbdataAlloc(clientStreamNode);
-    temp->readfunc = readfunc;
-    temp->callback = callback;
-    temp->detach = detach;
-    temp->status = status;
-    temp->data = data;
-    return temp;
-}
-
-/*
- * Initialise a client Stream.
- * list is the stream
- * func is the read function for the head
- * callback is the callback for the tail
- * tailbuf and taillen are the initial buffer and length for the tail.
- */
-void
-clientStreamInit(dlink_list * list, CSR * func, CSD * rdetach, CSS * readstatus,
-    void *readdata, CSCB * callback, CSD * cdetach, void *callbackdata,
-    StoreIOBuffer tailBuffer)
-{
-    clientStreamNode *temp = clientStreamNew(func, NULL, rdetach, readstatus,
-	readdata);
-    dlinkAdd(temp, &temp->node, list);
-    cbdataReference(temp);
-    temp->head = list;
-    clientStreamInsertHead(list, NULL, callback, cdetach, NULL, callbackdata);
-    temp = list->tail->data;
-    temp->readBuffer = tailBuffer;
-}
-
-/*
- * Doesn't actually insert at head. Instead it inserts one *after*
- * head. This is because HEAD is a special node, as is tail
- * This function is not suitable for inserting the real HEAD.
- * TODO: should we always initalise the buffers and length, to 
- * allow safe insertion of elements in the downstream cycle?
- */
-void
-clientStreamInsertHead(dlink_list * list, CSR * func, CSCB * callback,
-    CSD * detach, CSS * status, void *data)
-{
-    clientStreamNode *temp;
-
-    /* test preconditions */
-    assert(list != NULL);
-    assert(list->head);
-    temp = clientStreamNew(func, callback, detach, status, data);
-    temp->head = list;
-    debug(87, 3)
-	("clientStreamInsertHead: Inserted node %p with data %p after head\n",
-	temp, data);
-    dlinkAddAfter(temp, &temp->node, list->head, list);
-    cbdataReference(temp);
-}
-
-/*
- * Callback the next node the in chain with it's requested data
- */
-void
-clientStreamCallback(clientStreamNode * this, clientHttpRequest * http,
-    HttpReply * rep, StoreIOBuffer replyBuffer)
-{
-    clientStreamNode *next;
-    assert(this && http && this->node.next);
-    next = this->node.next->data;
-
-    debug(87,
-	3) ("clientStreamCallback: Calling %p with cbdata %p from node %p\n",
-	next->callback, next->data, this);
-    next->callback(next, http, rep, replyBuffer);
-}
-
-/*
- * Call the previous node in the chain to read some data
- */
-void
-clientStreamRead(clientStreamNode * this, clientHttpRequest * http,
-    StoreIOBuffer readBuffer)
-{
-    /* place the parameters on the 'stack' */
-    clientStreamNode *prev;
-    assert(this && http && this->node.prev);
-    prev = this->node.prev->data;
-
-    debug(87, 3) ("clientStreamRead: Calling %p with cbdata %p from node %p\n",
-	prev->readfunc, prev->data, this);
-    this->readBuffer = readBuffer;
-    prev->readfunc(prev, http);
-}
-
-/*
- * Detach from the stream - only allowed for terminal members
- */
-void
-clientStreamDetach(clientStreamNode * this, clientHttpRequest * http)
-{
-    clientStreamNode *prev = NULL;
-    clientStreamNode *temp = this;
-
-    if (this->node.prev) {
-	prev = this->node.prev->data;
-    }
-    assert(this->node.next == NULL);
-    debug(87, 3) ("clientStreamDetach: Detaching node %p\n", this);
-    /* And clean up this node */
-    /* ESI TODO: push refcount class through to head */
-    cbdataReferenceDone(temp);
-    cbdataFree(this);
-    /* and tell the prev that the detach has occured */
-    /*
-     * We do it in this order so that the detaching node is always
-     * at the end of the list
-     */
-    if (prev) {
-	debug(87, 3) ("clientStreamDetach: Calling %p with cbdata %p\n",
-	    prev->detach, prev->data);
-	prev->detach(prev, http);
-    }
-}
-
-/*
- * Abort the stream - detach every node in the pipeline.
- */
-void
-clientStreamAbort(clientStreamNode * this, clientHttpRequest * http)
-{
-    dlink_list *list;
-
-    assert(this != NULL);
-    assert(http != NULL);
-    list = this->head;
-    debug(87, 3) ("clientStreamAbort: Aborting stream with tail %p\n",
-	list->tail);
-    if (list->tail) {
-	clientStreamDetach(list->tail->data, http);
-    }
-}
-
-/*
- * Call the upstream node to find it's status 
- */
-clientStream_status_t
-clientStreamStatus(clientStreamNode * this, clientHttpRequest * http)
-{
-    clientStreamNode *prev;
-    assert(this && http && this->node.prev);
-    prev = this->node.prev->data;
-    return prev->status(prev, http);
-}
-
-/* Local function bodies */
-void
-clientStreamFree(void *foo)
-{
-    clientStreamNode *this = foo;
-
-    debug(87, 3) ("Freeing clientStreamNode %p\n", this);
-    if (this->data) {
-	cbdataFree(this->data);
-    }
-    if (this->node.next || this->node.prev) {
-	dlinkDelete(&this->node, this->head);
-    }
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/clientStream.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,290 @@
+
+/*
+ * $Id: clientStream.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 87    Client-side Stream routines.
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with thisObject program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/*
+ * A client Stream is a uni directional pipe, with the usual non-blocking
+ * asynchronous approach present elsewhere in squid.
+ *
+ * Each pipe node has a data push function, and a data request function.
+ * This limits flexability - the data flow is no longer assembled at each
+ * step. 
+ *
+ * An alternative approach is to pass each node in the pipe the call-
+ * back to use on each IO call. This allows the callbacks to be changed 
+ * very easily by a participating node, but requires more maintenance 
+ * in each node (store the call  back to the msot recent IO request in 
+ * the nodes context.) Such an approach also prevents dynamically 
+ * changing the pipeline from outside without an additional interface
+ * method to extract the callback and context from the next node.
+ *
+ * One important characteristic of the stream is that the readfunc
+ * on the terminating node, and the callback on the first node
+ * will be NULL, and never used.
+ */
+
+#include "squid.h"
+#include "clientStream.h"
+
+CBDATA_TYPE(clientStreamNode);
+
+/*
+ * TODO: rather than each node undeleting the next, have a clientStreamDelete
+ * that walks the list
+ */
+
+/*
+ * clientStream quick notes:
+ *
+ * Each node including the HEAD of the clientStream has a cbdataReference
+ * held by the stream. Freeing the stream then removes that reference
+ * and cbdataFrees every node.
+ * Any node with other References, and all nodes downstream will only 
+ * free when those references are released.
+ * Stream nodes MAY hold references to the data member of the node. 
+ *
+ * Specifically - on creation no reference is made. 
+ * If you pass a data variable to a node, give it an initial reference.
+ * If the data member is non-null on FREE, cbdataFree WILL be called.
+ * This you must never call cbdataFree on your own context without
+ * explicitly setting the stream node data member to NULL and
+ * cbdataReferenceDone'ing it.
+ *
+ * No data member may hold a reference to it's stream node.
+ * The stream guarantees that DETACH will be called before
+ * freeing the node, alowing data members to cleanup.
+ * 
+ * If a node's data holds a reference to something that needs to
+ * free the stream a circular reference list will occur.
+ * This results no data being freed until that reference is removed.
+ * One way to accomplish thisObject is to explicitly remove the
+ * data from your own node before freeing the stream.
+ *
+ * (i.e. 
+ * mycontext = thisObject->data;
+ * cbdataReferenceDone (mycontext);
+ * clientStreamFreeLinst (thisObject->head);
+ * cbdataFree (mycontext);
+ * return;
+ */
+
+/* Local functions */
+static FREE clientStreamFree;
+
+clientStreamNode *
+clientStreamNew(CSR * readfunc, CSCB * callback, CSD * detach, CSS * status,
+    void *data)
+{
+    clientStreamNode *temp;
+    CBDATA_INIT_TYPE_FREECB(clientStreamNode, clientStreamFree);
+    temp = cbdataAlloc(clientStreamNode);
+    temp->readfunc = readfunc;
+    temp->callback = callback;
+    temp->detach = detach;
+    temp->status = status;
+    temp->data = data;
+    return temp;
+}
+
+/*
+ * Initialise a client Stream.
+ * list is the stream
+ * func is the read function for the head
+ * callback is the callback for the tail
+ * tailbuf and taillen are the initial buffer and length for the tail.
+ */
+void
+clientStreamInit(dlink_list * list, CSR * func, CSD * rdetach, CSS * readstatus,
+    void *readdata, CSCB * callback, CSD * cdetach, void *callbackdata,
+    StoreIOBuffer tailBuffer)
+{
+    clientStreamNode *temp = clientStreamNew(func, NULL, rdetach, readstatus,
+	readdata);
+    dlinkAdd(temp, &temp->node, list);
+    cbdataReference(temp);
+    temp->head = list;
+    clientStreamInsertHead(list, NULL, callback, cdetach, NULL, callbackdata);
+    temp = (clientStreamNode *)list->tail->data;
+    temp->readBuffer = tailBuffer;
+}
+
+/*
+ * Doesn't actually insert at head. Instead it inserts one *after*
+ * head. This is because HEAD is a special node, as is tail
+ * This function is not suitable for inserting the real HEAD.
+ * TODO: should we always initalise the buffers and length, to 
+ * allow safe insertion of elements in the downstream cycle?
+ */
+void
+clientStreamInsertHead(dlink_list * list, CSR * func, CSCB * callback,
+    CSD * detach, CSS * status, void *data)
+{
+    clientStreamNode *temp;
+
+    /* test preconditions */
+    assert(list != NULL);
+    assert(list->head);
+    temp = clientStreamNew(func, callback, detach, status, data);
+    temp->head = list;
+    debug(87, 3)
+	("clientStreamInsertHead: Inserted node %p with data %p after head\n",
+	temp, data);
+    dlinkAddAfter(temp, &temp->node, list->head, list);
+    cbdataReference(temp);
+}
+
+/*
+ * Callback the next node the in chain with it's requested data
+ */
+void
+clientStreamCallback(clientStreamNode * thisObject, clientHttpRequest * http,
+    HttpReply * rep, StoreIOBuffer replyBuffer)
+{
+    clientStreamNode *next;
+    assert(thisObject && http && thisObject->node.next);
+    next = thisObject->next();
+
+    debug(87,
+	3) ("clientStreamCallback: Calling %p with cbdata %p from node %p\n",
+	next->callback, next->data, thisObject);
+    next->callback(next, http, rep, replyBuffer);
+}
+
+/*
+ * Call the previous node in the chain to read some data
+ */
+void
+clientStreamRead(clientStreamNode * thisObject, clientHttpRequest * http,
+    StoreIOBuffer readBuffer)
+{
+    /* place the parameters on the 'stack' */
+    clientStreamNode *prev;
+    assert(thisObject && http && thisObject->prev());
+    prev = thisObject->prev();
+
+    debug(87, 3) ("clientStreamRead: Calling %p with cbdata %p from node %p\n",
+	prev->readfunc, prev->data, thisObject);
+    thisObject->readBuffer = readBuffer;
+    prev->readfunc(prev, http);
+}
+
+/*
+ * Detach from the stream - only allowed for terminal members
+ */
+void
+clientStreamDetach(clientStreamNode * thisObject, clientHttpRequest * http)
+{
+    clientStreamNode *prev = thisObject->prev();
+    clientStreamNode *temp = thisObject;
+
+    assert(thisObject->node.next == NULL);
+    debug(87, 3) ("clientStreamDetach: Detaching node %p\n", thisObject);
+    /* And clean up thisObject node */
+    /* ESI TODO: push refcount class through to head */
+    cbdataReferenceDone(temp);
+    cbdataFree(thisObject);
+    /* and tell the prev that the detach has occured */
+    /*
+     * We do it in thisObject order so that the detaching node is always
+     * at the end of the list
+     */
+    if (prev) {
+	debug(87, 3) ("clientStreamDetach: Calling %p with cbdata %p\n",
+	    prev->detach, prev->data);
+	prev->detach(prev, http);
+    }
+}
+
+/*
+ * Abort the stream - detach every node in the pipeline.
+ */
+void
+clientStreamAbort(clientStreamNode * thisObject, clientHttpRequest * http)
+{
+    dlink_list *list;
+
+    assert(thisObject != NULL);
+    assert(http != NULL);
+    list = thisObject->head;
+    debug(87, 3) ("clientStreamAbort: Aborting stream with tail %p\n",
+	list->tail);
+    if (list->tail) {
+	clientStreamDetach((clientStreamNode *)list->tail->data, http);
+    }
+}
+
+/*
+ * Call the upstream node to find it's status 
+ */
+clientStream_status_t
+clientStreamStatus(clientStreamNode * thisObject, clientHttpRequest * http)
+{
+    clientStreamNode *prev;
+    assert(thisObject && http && thisObject->node.prev);
+    prev = (clientStreamNode *)thisObject->node.prev->data;
+    return prev->status(prev, http);
+}
+
+/* Local function bodies */
+void
+clientStreamFree(void *foo)
+{
+    clientStreamNode *thisObject = (clientStreamNode *)foo;
+
+    debug(87, 3) ("Freeing clientStreamNode %p\n", thisObject);
+    if (thisObject->data) {
+	cbdataFree(thisObject->data);
+    }
+    if (thisObject->node.next || thisObject->node.prev) {
+	dlinkDelete(&thisObject->node, thisObject->head);
+    }
+}
+
+_clientStreamNode *
+_clientStreamNode::prev() const
+{
+    if (node.prev)
+	return (_clientStreamNode *)node.prev->data;
+    else
+	return NULL;
+}
+
+_clientStreamNode *
+_clientStreamNode::next() const
+{
+    if (node.next)
+	return (_clientStreamNode *)node.next->data;
+    else
+	return NULL;
+}
Index: squid/src/clientStream.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Attic/clientStream.h,v
retrieving revision 1.2.18.1
retrieving revision 1.2.18.2
diff -u -r1.2.18.1 -r1.2.18.2
--- squid/src/clientStream.h	4 Oct 2002 11:09:07 -0000	1.2.18.1
+++ squid/src/clientStream.h	9 Oct 2002 00:23:16 -0000	1.2.18.2
@@ -1,6 +1,6 @@
 
 /*
- * $Id: clientStream.h,v 1.2.18.1 2002/10/04 11:09:07 rbcollins Exp $
+ * $Id: clientStream.h,v 1.2.18.2 2002/10/09 00:23:16 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -47,6 +47,11 @@
 
 
 struct _clientStreamNode {
+#ifdef __cplusplus
+public:
+    _clientStreamNode *prev() const;
+    _clientStreamNode *next() const;
+#endif
     dlink_node node;
     dlink_list *head;		/* sucks I know, but hey, the interface is limited */
     CSR *readfunc;
--- squid/src/client_db.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,337 +0,0 @@
-
-/*
- * $Id: client_db.c,v 1.7.2.1 2002/10/04 07:07:21 rbcollins Exp $
- *
- * DEBUG: section 0     Client Database
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "Store.h"
-
-
-static hash_table *client_table = NULL;
-static ClientInfo *clientdbAdd(struct in_addr addr);
-static FREE clientdbFreeItem;
-
-static ClientInfo *
-clientdbAdd(struct in_addr addr)
-{
-    ClientInfo *c;
-    c = memAllocate(MEM_CLIENT_INFO);
-    c->hash.key = xstrdup(inet_ntoa(addr));
-    c->addr = addr;
-    hash_join(client_table, &c->hash);
-    statCounter.client_http.clients++;
-    return c;
-}
-
-void
-clientdbInit(void)
-{
-    if (client_table)
-	return;
-    client_table = hash_create((HASHCMP *) strcmp, 467, hash_string);
-    cachemgrRegister("client_list",
-	"Cache Client List",
-	clientdbDump,
-	0, 1);
-}
-
-void
-clientdbUpdate(struct in_addr addr, log_type ltype, protocol_t p, size_t size)
-{
-    char *key;
-    ClientInfo *c;
-    if (!Config.onoff.client_db)
-	return;
-    key = inet_ntoa(addr);
-    c = (ClientInfo *) hash_lookup(client_table, key);
-    if (c == NULL)
-	c = clientdbAdd(addr);
-    if (c == NULL)
-	debug_trap("clientdbUpdate: Failed to add entry");
-    if (p == PROTO_HTTP) {
-	c->Http.n_requests++;
-	c->Http.result_hist[ltype]++;
-	kb_incr(&c->Http.kbytes_out, size);
-	if (logTypeIsATcpHit(ltype))
-	    kb_incr(&c->Http.hit_kbytes_out, size);
-    } else if (p == PROTO_ICP) {
-	c->Icp.n_requests++;
-	c->Icp.result_hist[ltype]++;
-	kb_incr(&c->Icp.kbytes_out, size);
-	if (LOG_UDP_HIT == ltype)
-	    kb_incr(&c->Icp.hit_kbytes_out, size);
-    }
-}
-
-/*
- * clientdbEstablished()
- * This function tracks the number of currently established connections
- * for a client IP address.  When a connection is accepted, call this
- * with delta = 1.  When the connection is closed, call with delta =
- * -1.  To get the current value, simply call with delta = 0.
- */
-int
-clientdbEstablished(struct in_addr addr, int delta)
-{
-    char *key;
-    ClientInfo *c;
-    if (!Config.onoff.client_db)
-	return 0;
-    key = inet_ntoa(addr);
-    c = (ClientInfo *) hash_lookup(client_table, key);
-    if (c == NULL)
-	c = clientdbAdd(addr);
-    if (c == NULL)
-	debug_trap("clientdbUpdate: Failed to add entry");
-    c->n_established += delta;
-    return c->n_established;
-}
-
-#define CUTOFF_SECONDS 3600
-int
-clientdbCutoffDenied(struct in_addr addr)
-{
-    char *key;
-    int NR;
-    int ND;
-    double p;
-    ClientInfo *c;
-    if (!Config.onoff.client_db)
-	return 0;
-    key = inet_ntoa(addr);
-    c = (ClientInfo *) hash_lookup(client_table, key);
-    if (c == NULL)
-	return 0;
-    /*
-     * If we are in a cutoff window, we don't send a reply
-     */
-    if (squid_curtime - c->cutoff.time < CUTOFF_SECONDS)
-	return 1;
-    /*
-     * Calculate the percent of DENIED replies since the last
-     * cutoff time.
-     */
-    NR = c->Icp.n_requests - c->cutoff.n_req;
-    if (NR < 150)
-	NR = 150;
-    ND = c->Icp.result_hist[LOG_UDP_DENIED] - c->cutoff.n_denied;
-    p = 100.0 * ND / NR;
-    if (p < 95.0)
-	return 0;
-    debug(1, 0) ("WARNING: Probable misconfigured neighbor at %s\n", key);
-    debug(1, 0) ("WARNING: %d of the last %d ICP replies are DENIED\n", ND, NR);
-    debug(1, 0) ("WARNING: No replies will be sent for the next %d seconds\n",
-	CUTOFF_SECONDS);
-    c->cutoff.time = squid_curtime;
-    c->cutoff.n_req = c->Icp.n_requests;
-    c->cutoff.n_denied = c->Icp.result_hist[LOG_UDP_DENIED];
-    return 1;
-}
-
-
-void
-clientdbDump(StoreEntry * sentry)
-{
-    ClientInfo *c;
-    log_type l;
-    int icp_total = 0;
-    int icp_hits = 0;
-    int http_total = 0;
-    int http_hits = 0;
-    storeAppendPrintf(sentry, "Cache Clients:\n");
-    hash_first(client_table);
-    while ((c = (ClientInfo *) hash_next(client_table))) {
-	storeAppendPrintf(sentry, "Address: %s\n", hashKeyStr(&c->hash));
-	storeAppendPrintf(sentry, "Name: %s\n", fqdnFromAddr(c->addr));
-	storeAppendPrintf(sentry, "Currently established connections: %d\n",
-	    c->n_established);
-	storeAppendPrintf(sentry, "    ICP Requests %d\n",
-	    c->Icp.n_requests);
-	for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; l++) {
-	    if (c->Icp.result_hist[l] == 0)
-		continue;
-	    icp_total += c->Icp.result_hist[l];
-	    if (LOG_UDP_HIT == l)
-		icp_hits += c->Icp.result_hist[l];
-	    storeAppendPrintf(sentry,
-		"        %-20.20s %7d %3d%%\n",
-		log_tags[l],
-		c->Icp.result_hist[l],
-		percent(c->Icp.result_hist[l], c->Icp.n_requests));
-	}
-	storeAppendPrintf(sentry, "    HTTP Requests %d\n",
-	    c->Http.n_requests);
-	for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; l++) {
-	    if (c->Http.result_hist[l] == 0)
-		continue;
-	    http_total += c->Http.result_hist[l];
-	    if (logTypeIsATcpHit(l))
-		http_hits += c->Http.result_hist[l];
-	    storeAppendPrintf(sentry,
-		"        %-20.20s %7d %3d%%\n",
-		log_tags[l],
-		c->Http.result_hist[l],
-		percent(c->Http.result_hist[l], c->Http.n_requests));
-	}
-	storeAppendPrintf(sentry, "\n");
-    }
-    storeAppendPrintf(sentry, "TOTALS\n");
-    storeAppendPrintf(sentry, "ICP : %d Queries, %d Hits (%3d%%)\n",
-	icp_total, icp_hits, percent(icp_hits, icp_total));
-    storeAppendPrintf(sentry, "HTTP: %d Requests, %d Hits (%3d%%)\n",
-	http_total, http_hits, percent(http_hits, http_total));
-}
-
-static void
-clientdbFreeItem(void *data)
-{
-    ClientInfo *c = data;
-    safe_free(c->hash.key);
-    memFree(c, MEM_CLIENT_INFO);
-}
-
-void
-clientdbFreeMemory(void)
-{
-    hashFreeItems(client_table, clientdbFreeItem);
-    hashFreeMemory(client_table);
-    client_table = NULL;
-}
-
-#if SQUID_SNMP
-struct in_addr *
-client_entry(struct in_addr *current)
-{
-    ClientInfo *c = NULL;
-    char *key;
-    if (current) {
-	key = inet_ntoa(*current);
-	hash_first(client_table);
-	while ((c = (ClientInfo *) hash_next(client_table))) {
-	    if (!strcmp(key, hashKeyStr(&c->hash)))
-		break;
-	}
-	c = (ClientInfo *) hash_next(client_table);
-    } else {
-	hash_first(client_table);
-	c = (ClientInfo *) hash_next(client_table);
-    }
-    hash_last(client_table);
-    if (c)
-	return (&c->addr);
-    else
-	return (NULL);
-
-}
-
-variable_list *
-snmp_meshCtblFn(variable_list * Var, snint * ErrP)
-{
-    variable_list *Answer = NULL;
-    static char key[15];
-    ClientInfo *c = NULL;
-    int aggr = 0;
-    log_type l;
-    *ErrP = SNMP_ERR_NOERROR;
-    debug(49, 6) ("snmp_meshCtblFn: Current : \n");
-    snmpDebugOid(6, Var->name, Var->name_length);
-    snprintf(key, sizeof(key), "%d.%d.%d.%d", Var->name[LEN_SQ_NET + 3], Var->name[LEN_SQ_NET + 4],
-	Var->name[LEN_SQ_NET + 5], Var->name[LEN_SQ_NET + 6]);
-    debug(49, 5) ("snmp_meshCtblFn: [%s] requested!\n", key);
-    c = (ClientInfo *) hash_lookup(client_table, key);
-    if (c == NULL) {
-	debug(49, 5) ("snmp_meshCtblFn: not found.\n");
-	*ErrP = SNMP_ERR_NOSUCHNAME;
-	return NULL;
-    }
-    switch (Var->name[LEN_SQ_NET + 2]) {
-    case MESH_CTBL_ADDR:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) c->addr.s_addr,
-	    SMI_IPADDRESS);
-	break;
-    case MESH_CTBL_HTBYTES:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) c->Http.kbytes_out.kb,
-	    SMI_COUNTER32);
-	break;
-    case MESH_CTBL_HTREQ:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) c->Http.n_requests,
-	    SMI_COUNTER32);
-	break;
-    case MESH_CTBL_HTHITS:
-	aggr = 0;
-	for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; l++) {
-	    if (logTypeIsATcpHit(l))
-		aggr += c->Http.result_hist[l];
-	}
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) aggr,
-	    SMI_COUNTER32);
-	break;
-    case MESH_CTBL_HTHITBYTES:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) c->Http.hit_kbytes_out.kb,
-	    SMI_COUNTER32);
-	break;
-    case MESH_CTBL_ICPBYTES:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) c->Icp.kbytes_out.kb,
-	    SMI_COUNTER32);
-	break;
-    case MESH_CTBL_ICPREQ:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) c->Icp.n_requests,
-	    SMI_COUNTER32);
-	break;
-    case MESH_CTBL_ICPHITS:
-	aggr = c->Icp.result_hist[LOG_UDP_HIT];
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) aggr,
-	    SMI_COUNTER32);
-	break;
-    case MESH_CTBL_ICPHITBYTES:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) c->Icp.hit_kbytes_out.kb,
-	    SMI_COUNTER32);
-	break;
-    default:
-	*ErrP = SNMP_ERR_NOSUCHNAME;
-	debug(49, 5) ("snmp_meshCtblFn: illegal column.\n");
-	break;
-    }
-    return Answer;
-}
-
-#endif /*SQUID_SNMP */
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/client_db.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,343 @@
+
+/*
+ * $Id: client_db.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 0     Client Database
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "Store.h"
+
+
+static hash_table *client_table = NULL;
+static ClientInfo *clientdbAdd(struct in_addr addr);
+static FREE clientdbFreeItem;
+
+static ClientInfo *
+clientdbAdd(struct in_addr addr)
+{
+    ClientInfo *c;
+    c = (ClientInfo *)memAllocate(MEM_CLIENT_INFO);
+    c->hash.key = xstrdup(inet_ntoa(addr));
+    c->addr = addr;
+    hash_join(client_table, &c->hash);
+    statCounter.client_http.clients++;
+    return c;
+}
+
+void
+clientdbInit(void)
+{
+    if (client_table)
+	return;
+    client_table = hash_create((HASHCMP *) strcmp, 467, hash_string);
+    cachemgrRegister("client_list",
+	"Cache Client List",
+	clientdbDump,
+	0, 1);
+}
+
+void
+clientdbUpdate(struct in_addr addr, log_type ltype, protocol_t p, size_t size)
+{
+    char *key;
+    ClientInfo *c;
+    if (!Config.onoff.client_db)
+	return;
+    key = inet_ntoa(addr);
+    c = (ClientInfo *) hash_lookup(client_table, key);
+    if (c == NULL)
+	c = clientdbAdd(addr);
+    if (c == NULL)
+	debug_trap("clientdbUpdate: Failed to add entry");
+    if (p == PROTO_HTTP) {
+	c->Http.n_requests++;
+	c->Http.result_hist[ltype]++;
+	kb_incr(&c->Http.kbytes_out, size);
+	if (logTypeIsATcpHit(ltype))
+	    kb_incr(&c->Http.hit_kbytes_out, size);
+    } else if (p == PROTO_ICP) {
+	c->Icp.n_requests++;
+	c->Icp.result_hist[ltype]++;
+	kb_incr(&c->Icp.kbytes_out, size);
+	if (LOG_UDP_HIT == ltype)
+	    kb_incr(&c->Icp.hit_kbytes_out, size);
+    }
+}
+
+/*
+ * clientdbEstablished()
+ * This function tracks the number of currently established connections
+ * for a client IP address.  When a connection is accepted, call this
+ * with delta = 1.  When the connection is closed, call with delta =
+ * -1.  To get the current value, simply call with delta = 0.
+ */
+int
+clientdbEstablished(struct in_addr addr, int delta)
+{
+    char *key;
+    ClientInfo *c;
+    if (!Config.onoff.client_db)
+	return 0;
+    key = inet_ntoa(addr);
+    c = (ClientInfo *) hash_lookup(client_table, key);
+    if (c == NULL)
+	c = clientdbAdd(addr);
+    if (c == NULL)
+	debug_trap("clientdbUpdate: Failed to add entry");
+    c->n_established += delta;
+    return c->n_established;
+}
+
+#define CUTOFF_SECONDS 3600
+int
+clientdbCutoffDenied(struct in_addr addr)
+{
+    char *key;
+    int NR;
+    int ND;
+    double p;
+    ClientInfo *c;
+    if (!Config.onoff.client_db)
+	return 0;
+    key = inet_ntoa(addr);
+    c = (ClientInfo *) hash_lookup(client_table, key);
+    if (c == NULL)
+	return 0;
+    /*
+     * If we are in a cutoff window, we don't send a reply
+     */
+    if (squid_curtime - c->cutoff.time < CUTOFF_SECONDS)
+	return 1;
+    /*
+     * Calculate the percent of DENIED replies since the last
+     * cutoff time.
+     */
+    NR = c->Icp.n_requests - c->cutoff.n_req;
+    if (NR < 150)
+	NR = 150;
+    ND = c->Icp.result_hist[LOG_UDP_DENIED] - c->cutoff.n_denied;
+    p = 100.0 * ND / NR;
+    if (p < 95.0)
+	return 0;
+    debug(1, 0) ("WARNING: Probable misconfigured neighbor at %s\n", key);
+    debug(1, 0) ("WARNING: %d of the last %d ICP replies are DENIED\n", ND, NR);
+    debug(1, 0) ("WARNING: No replies will be sent for the next %d seconds\n",
+	CUTOFF_SECONDS);
+    c->cutoff.time = squid_curtime;
+    c->cutoff.n_req = c->Icp.n_requests;
+    c->cutoff.n_denied = c->Icp.result_hist[LOG_UDP_DENIED];
+    return 1;
+}
+
+log_type &operator++ (log_type &aLogType)
+{
+    aLogType = (log_type)(++(int)aLogType);
+    return aLogType;
+}
+
+
+void
+clientdbDump(StoreEntry * sentry)
+{
+    ClientInfo *c;
+    log_type l;
+    int icp_total = 0;
+    int icp_hits = 0;
+    int http_total = 0;
+    int http_hits = 0;
+    storeAppendPrintf(sentry, "Cache Clients:\n");
+    hash_first(client_table);
+    while ((c = (ClientInfo *) hash_next(client_table))) {
+	storeAppendPrintf(sentry, "Address: %s\n", hashKeyStr(&c->hash));
+	storeAppendPrintf(sentry, "Name: %s\n", fqdnFromAddr(c->addr));
+	storeAppendPrintf(sentry, "Currently established connections: %d\n",
+	    c->n_established);
+	storeAppendPrintf(sentry, "    ICP Requests %d\n",
+	    c->Icp.n_requests);
+	for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; ++l) {
+	    if (c->Icp.result_hist[l] == 0)
+		continue;
+	    icp_total += c->Icp.result_hist[l];
+	    if (LOG_UDP_HIT == l)
+		icp_hits += c->Icp.result_hist[l];
+	    storeAppendPrintf(sentry,
+		"        %-20.20s %7d %3d%%\n",
+		log_tags[l],
+		c->Icp.result_hist[l],
+		percent(c->Icp.result_hist[l], c->Icp.n_requests));
+	}
+	storeAppendPrintf(sentry, "    HTTP Requests %d\n",
+	    c->Http.n_requests);
+	for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; ++l) {
+	    if (c->Http.result_hist[l] == 0)
+		continue;
+	    http_total += c->Http.result_hist[l];
+	    if (logTypeIsATcpHit(l))
+		http_hits += c->Http.result_hist[l];
+	    storeAppendPrintf(sentry,
+		"        %-20.20s %7d %3d%%\n",
+		log_tags[l],
+		c->Http.result_hist[l],
+		percent(c->Http.result_hist[l], c->Http.n_requests));
+	}
+	storeAppendPrintf(sentry, "\n");
+    }
+    storeAppendPrintf(sentry, "TOTALS\n");
+    storeAppendPrintf(sentry, "ICP : %d Queries, %d Hits (%3d%%)\n",
+	icp_total, icp_hits, percent(icp_hits, icp_total));
+    storeAppendPrintf(sentry, "HTTP: %d Requests, %d Hits (%3d%%)\n",
+	http_total, http_hits, percent(http_hits, http_total));
+}
+
+static void
+clientdbFreeItem(void *data)
+{
+    ClientInfo *c = (ClientInfo *)data;
+    safe_free(c->hash.key);
+    memFree(c, MEM_CLIENT_INFO);
+}
+
+void
+clientdbFreeMemory(void)
+{
+    hashFreeItems(client_table, clientdbFreeItem);
+    hashFreeMemory(client_table);
+    client_table = NULL;
+}
+
+#if SQUID_SNMP
+struct in_addr *
+client_entry(struct in_addr *current)
+{
+    ClientInfo *c = NULL;
+    char *key;
+    if (current) {
+	key = inet_ntoa(*current);
+	hash_first(client_table);
+	while ((c = (ClientInfo *) hash_next(client_table))) {
+	    if (!strcmp(key, hashKeyStr(&c->hash)))
+		break;
+	}
+	c = (ClientInfo *) hash_next(client_table);
+    } else {
+	hash_first(client_table);
+	c = (ClientInfo *) hash_next(client_table);
+    }
+    hash_last(client_table);
+    if (c)
+	return (&c->addr);
+    else
+	return (NULL);
+
+}
+
+variable_list *
+snmp_meshCtblFn(variable_list * Var, snint * ErrP)
+{
+    variable_list *Answer = NULL;
+    static char key[15];
+    ClientInfo *c = NULL;
+    int aggr = 0;
+    log_type l;
+    *ErrP = SNMP_ERR_NOERROR;
+    debug(49, 6) ("snmp_meshCtblFn: Current : \n");
+    snmpDebugOid(6, Var->name, Var->name_length);
+    snprintf(key, sizeof(key), "%d.%d.%d.%d", Var->name[LEN_SQ_NET + 3], Var->name[LEN_SQ_NET + 4],
+	Var->name[LEN_SQ_NET + 5], Var->name[LEN_SQ_NET + 6]);
+    debug(49, 5) ("snmp_meshCtblFn: [%s] requested!\n", key);
+    c = (ClientInfo *) hash_lookup(client_table, key);
+    if (c == NULL) {
+	debug(49, 5) ("snmp_meshCtblFn: not found.\n");
+	*ErrP = SNMP_ERR_NOSUCHNAME;
+	return NULL;
+    }
+    switch (Var->name[LEN_SQ_NET + 2]) {
+    case MESH_CTBL_ADDR:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) c->addr.s_addr,
+	    SMI_IPADDRESS);
+	break;
+    case MESH_CTBL_HTBYTES:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) c->Http.kbytes_out.kb,
+	    SMI_COUNTER32);
+	break;
+    case MESH_CTBL_HTREQ:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) c->Http.n_requests,
+	    SMI_COUNTER32);
+	break;
+    case MESH_CTBL_HTHITS:
+	aggr = 0;
+	for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; l++) {
+	    if (logTypeIsATcpHit(l))
+		aggr += c->Http.result_hist[l];
+	}
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) aggr,
+	    SMI_COUNTER32);
+	break;
+    case MESH_CTBL_HTHITBYTES:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) c->Http.hit_kbytes_out.kb,
+	    SMI_COUNTER32);
+	break;
+    case MESH_CTBL_ICPBYTES:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) c->Icp.kbytes_out.kb,
+	    SMI_COUNTER32);
+	break;
+    case MESH_CTBL_ICPREQ:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) c->Icp.n_requests,
+	    SMI_COUNTER32);
+	break;
+    case MESH_CTBL_ICPHITS:
+	aggr = c->Icp.result_hist[LOG_UDP_HIT];
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) aggr,
+	    SMI_COUNTER32);
+	break;
+    case MESH_CTBL_ICPHITBYTES:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) c->Icp.hit_kbytes_out.kb,
+	    SMI_COUNTER32);
+	break;
+    default:
+	*ErrP = SNMP_ERR_NOSUCHNAME;
+	debug(49, 5) ("snmp_meshCtblFn: illegal column.\n");
+	break;
+    }
+    return Answer;
+}
+
+#endif /*SQUID_SNMP */
--- squid/src/dnsserver.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,354 +0,0 @@
-
-/*
- * $Id: dnsserver.c,v 1.6 2002/07/01 16:06:40 squidadm Exp $
- *
- * DEBUG: section 0     DNS Resolver
- * AUTHOR: Harvest Derived
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "config.h"
-
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-#if HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#if HAVE_GRP_H
-#include <grp.h>
-#endif
-#if HAVE_GNUMALLOC_H
-#include <gnumalloc.h>
-#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
-#include <malloc.h>
-#endif
-#if HAVE_MEMORY_H
-#include <memory.h>
-#endif
-#if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_)	/* protect NEXTSTEP */
-#define _SQUID_NETDB_H_
-#include <netdb.h>
-#endif
-#if HAVE_PWD_H
-#include <pwd.h>
-#endif
-#if HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#if HAVE_TIME_H
-#include <time.h>
-#endif
-#if HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#if HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>	/* needs sys/time.h above it */
-#endif
-#if HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#if HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#if HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#if HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#if HAVE_SYS_UN_H
-#include <sys/un.h>
-#endif
-#if HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-#if HAVE_LIBC_H
-#include <libc.h>
-#endif
-#ifdef HAVE_SYS_SYSCALL_H
-#include <sys/syscall.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#if HAVE_BSTRING_H
-#include <bstring.h>
-#endif
-#ifdef HAVE_CRYPT_H
-#include <crypt.h>
-#endif
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#if HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
-#if HAVE_ARPA_NAMESER_H
-#include <arpa/nameser.h>
-#endif
-#if HAVE_RESOLV_H
-#include <resolv.h>
-#endif
-
-#include "util.h"
-#include "snprintf.h"
-
-#if !defined(_SQUID_AIX_)
-extern int h_errno;
-#endif
-
-#if LIBRESOLV_DNS_TTL_HACK
-extern int _dns_ttl_;		/* this is a really *dirty* hack - bne */
-#endif
-
-#ifdef _SQUID_NEXT_
-/* This is a really bloody hack. frank@langen.bull.de
- * Workaround bug in gethostbyname which sets h_errno wrong
- * WARNING: This hack queries only the resolver and not NetInfo or YP
- */
-struct hostent *_res_gethostbyname(char *name);
-#define gethostbyname _res_gethostbyname
-#endif /* _SQUID_NEXT_ */
-
-static struct in_addr no_addr;
-
-#ifdef _SQUID_OS2_
-struct state _res =
-{0};				/* it's not in any of the libraries */
-#endif
-
-/* error messages from gethostbyname() */
-static char *
-my_h_msgs(int x)
-{
-    if (x == HOST_NOT_FOUND)
-	return "Host not found (authoritative)";
-    else if (x == TRY_AGAIN)
-	return "Host not found (non-authoritative)";
-    else if (x == NO_RECOVERY)
-	return "Non recoverable errors";
-    else if (x == NO_DATA || x == NO_ADDRESS)
-	return "Valid name, no data record of requested type";
-    else
-	return "Unknown DNS problem";
-}
-
-#define REQ_SZ 512
-
-static void
-lookup(const char *buf)
-{
-    const struct hostent *result = NULL;
-    int reverse = 0;
-    int ttl = 0;
-    int retry = 0;
-    int i;
-    struct in_addr addr;
-    if (0 == strcmp(buf, "$shutdown"))
-	exit(0);
-    if (0 == strcmp(buf, "$hello")) {
-	printf("$alive\n");
-	return;
-    }
-    /* check if it's already an IP address in text form. */
-    for (;;) {
-	if (safe_inet_addr(buf, &addr)) {
-	    reverse = 1;
-	    result = gethostbyaddr((char *) &addr.s_addr, 4, AF_INET);
-	} else {
-	    result = gethostbyname(buf);
-	}
-	if (NULL != result)
-	    break;
-	if (h_errno != TRY_AGAIN)
-	    break;
-	if (++retry == 3)
-	    break;
-	sleep(1);
-    }
-    if (NULL == result) {
-	if (h_errno == TRY_AGAIN) {
-	    printf("$fail Name Server for domain '%s' is unavailable.\n", buf);
-	} else {
-	    printf("$fail DNS Domain '%s' is invalid: %s.\n",
-		buf, my_h_msgs(h_errno));
-	}
-	return;
-    }
-#if LIBRESOLV_DNS_TTL_HACK
-    /* DNS TTL handling - bne@CareNet.hu
-     * for first try it's a dirty hack, by hacking getanswer
-     * to place the ttl in a global variable */
-    if (_dns_ttl_ > -1)
-	ttl = _dns_ttl_;
-#endif
-    if (reverse) {
-	printf("$name %d %s\n", ttl, result->h_name);
-	return;
-    }
-    printf("$addr %d", ttl);
-    for (i = 0; NULL != result->h_addr_list[i]; i++) {
-	if (32 == i)
-	    break;
-	xmemcpy(&addr, result->h_addr_list[i], sizeof(addr));
-	printf(" %s", inet_ntoa(addr));
-    }
-    printf("\n");
-}
-
-static void
-usage(void)
-{
-    fprintf(stderr, "usage: dnsserver -Dhv -s nameserver\n"
-	"\t-D             Enable resolver RES_DEFNAMES and RES_DNSRCH options\n"
-	"\t-h             Help\n"
-	"\t-v             Version\n"
-	"\t-s nameserver  Specify alternate name server(s).  'nameserver'\n"
-	"\t               must be an IP address, -s option may be repeated\n");
-}
-
-int
-main(int argc, char *argv[])
-{
-    char request[512];
-    char *t = NULL;
-    int c;
-    int opt_s = 0;
-    extern char *optarg;
-
-    safe_inet_addr("255.255.255.255", &no_addr);
-
-#if HAVE_RES_INIT
-    res_init();
-#ifdef RES_DEFAULT
-    _res.options = RES_DEFAULT;
-#endif
-#ifdef RES_DEFNAMES
-    _res.options &= ~RES_DEFNAMES;
-#endif
-#ifdef RES_DNSRCH
-    _res.options &= ~RES_DNSRCH;
-#endif
-#endif
-
-    while ((c = getopt(argc, argv, "Dhs:v")) != -1) {
-	switch (c) {
-	case 'D':
-#ifdef RES_DEFNAMES
-	    _res.options |= RES_DEFNAMES;
-#endif
-#ifdef RES_DNSRCH
-	    _res.options |= RES_DNSRCH;
-#endif
-	    break;
-	case 's':
-#if HAVE_RES_INIT
-	    if (opt_s == 0) {
-		_res.nscount = 0;
-		/*
-		 * Setting RES_INIT here causes coredumps when -s is
-		 * used with -D option.  It looks to me like setting
-		 * RES_INIT is wrong.  The resolver code sets RES_INIT
-		 * after calling res_init().  When we change the _res
-		 * structure and set RES_INIT, some internal resolver
-		 * structures get confused.             -DW 2.1.p1
-		 */
-#if SEEMS_WRONG
-		_res.options |= RES_INIT;
-#endif
-		opt_s = 1;
-	    } else if (_res.nscount == MAXNS) {
-		fprintf(stderr, "Too many -s options, only %d are allowed\n",
-		    MAXNS);
-		break;
-	    }
-#if HAVE_RES_NSADDR_LIST
-	    _res.nsaddr_list[_res.nscount] = _res.nsaddr_list[0];
-	    safe_inet_addr(optarg, &_res.nsaddr_list[_res.nscount++].sin_addr);
-#elif HAVE_RES_NS_LIST
-	    _res.ns_list[_res.nscount] = _res.ns_list[0];
-	    safe_inet_addr(optarg, &_res.ns_list[_res.nscount++].addr.sin_addr);
-#else /* Unknown NS list format */
-	    fprintf(stderr, "-s is not supported on this resolver\n");
-#endif
-#else /* !HAVE_RES_INIT */
-	    fprintf(stderr, "-s is not supported on this resolver\n");
-#endif /* HAVE_RES_INIT */
-	    break;
-	case 'v':
-	    printf("dnsserver version %s\n", VERSION);
-	    exit(0);
-	    break;
-	case 'h':
-	default:
-	    usage();
-	    exit(1);
-	    break;
-	}
-    }
-
-    for (;;) {
-	memset(request, '\0', REQ_SZ);
-	if (fgets(request, REQ_SZ, stdin) == NULL)
-	    exit(1);
-	t = strrchr(request, '\n');
-	if (t == NULL)		/* Ignore if no newline */
-	    continue;
-	*t = '\0';		/* strip NL */
-	if ((t = strrchr(request, '\r')) != NULL)
-	    *t = '\0';		/* strip CR */
-	lookup(request);
-	fflush(stdout);
-    }
-    /* NOTREACHED */
-    return 0;
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/dnsserver.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,354 @@
+
+/*
+ * $Id: dnsserver.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 0     DNS Resolver
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "config.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_GRP_H
+#include <grp.h>
+#endif
+#if HAVE_GNUMALLOC_H
+#include <gnumalloc.h>
+#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#include <malloc.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_)	/* protect NEXTSTEP */
+#define _SQUID_NETDB_H_
+#include <netdb.h>
+#endif
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>	/* needs sys/time.h above it */
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if HAVE_LIBC_H
+#include <libc.h>
+#endif
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#if HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+
+#include "util.h"
+#include "snprintf.h"
+
+#if !defined(_SQUID_AIX_)
+extern int h_errno;
+#endif
+
+#if LIBRESOLV_DNS_TTL_HACK
+extern int _dns_ttl_;		/* this is a really *dirty* hack - bne */
+#endif
+
+#ifdef _SQUID_NEXT_
+/* This is a really bloody hack. frank@langen.bull.de
+ * Workaround bug in gethostbyname which sets h_errno wrong
+ * WARNING: This hack queries only the resolver and not NetInfo or YP
+ */
+struct hostent *_res_gethostbyname(char *name);
+#define gethostbyname _res_gethostbyname
+#endif /* _SQUID_NEXT_ */
+
+static struct in_addr no_addr;
+
+#ifdef _SQUID_OS2_
+struct state _res =
+{0};				/* it's not in any of the libraries */
+#endif
+
+/* error messages from gethostbyname() */
+static char *
+my_h_msgs(int x)
+{
+    if (x == HOST_NOT_FOUND)
+	return "Host not found (authoritative)";
+    else if (x == TRY_AGAIN)
+	return "Host not found (non-authoritative)";
+    else if (x == NO_RECOVERY)
+	return "Non recoverable errors";
+    else if (x == NO_DATA || x == NO_ADDRESS)
+	return "Valid name, no data record of requested type";
+    else
+	return "Unknown DNS problem";
+}
+
+#define REQ_SZ 512
+
+static void
+lookup(const char *buf)
+{
+    const struct hostent *result = NULL;
+    int reverse = 0;
+    int ttl = 0;
+    int retry = 0;
+    int i;
+    struct in_addr addr;
+    if (0 == strcmp(buf, "$shutdown"))
+	exit(0);
+    if (0 == strcmp(buf, "$hello")) {
+	printf("$alive\n");
+	return;
+    }
+    /* check if it's already an IP address in text form. */
+    for (;;) {
+	if (safe_inet_addr(buf, &addr)) {
+	    reverse = 1;
+	    result = gethostbyaddr((char *) &addr.s_addr, 4, AF_INET);
+	} else {
+	    result = gethostbyname(buf);
+	}
+	if (NULL != result)
+	    break;
+	if (h_errno != TRY_AGAIN)
+	    break;
+	if (++retry == 3)
+	    break;
+	sleep(1);
+    }
+    if (NULL == result) {
+	if (h_errno == TRY_AGAIN) {
+	    printf("$fail Name Server for domain '%s' is unavailable.\n", buf);
+	} else {
+	    printf("$fail DNS Domain '%s' is invalid: %s.\n",
+		buf, my_h_msgs(h_errno));
+	}
+	return;
+    }
+#if LIBRESOLV_DNS_TTL_HACK
+    /* DNS TTL handling - bne@CareNet.hu
+     * for first try it's a dirty hack, by hacking getanswer
+     * to place the ttl in a global variable */
+    if (_dns_ttl_ > -1)
+	ttl = _dns_ttl_;
+#endif
+    if (reverse) {
+	printf("$name %d %s\n", ttl, result->h_name);
+	return;
+    }
+    printf("$addr %d", ttl);
+    for (i = 0; NULL != result->h_addr_list[i]; i++) {
+	if (32 == i)
+	    break;
+	xmemcpy(&addr, result->h_addr_list[i], sizeof(addr));
+	printf(" %s", inet_ntoa(addr));
+    }
+    printf("\n");
+}
+
+static void
+usage(void)
+{
+    fprintf(stderr, "usage: dnsserver -Dhv -s nameserver\n"
+	"\t-D             Enable resolver RES_DEFNAMES and RES_DNSRCH options\n"
+	"\t-h             Help\n"
+	"\t-v             Version\n"
+	"\t-s nameserver  Specify alternate name server(s).  'nameserver'\n"
+	"\t               must be an IP address, -s option may be repeated\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+    char request[512];
+    char *t = NULL;
+    int c;
+    int opt_s = 0;
+    extern char *optarg;
+
+    safe_inet_addr("255.255.255.255", &no_addr);
+
+#if HAVE_RES_INIT
+    res_init();
+#ifdef RES_DEFAULT
+    _res.options = RES_DEFAULT;
+#endif
+#ifdef RES_DEFNAMES
+    _res.options &= ~RES_DEFNAMES;
+#endif
+#ifdef RES_DNSRCH
+    _res.options &= ~RES_DNSRCH;
+#endif
+#endif
+
+    while ((c = getopt(argc, argv, "Dhs:v")) != -1) {
+	switch (c) {
+	case 'D':
+#ifdef RES_DEFNAMES
+	    _res.options |= RES_DEFNAMES;
+#endif
+#ifdef RES_DNSRCH
+	    _res.options |= RES_DNSRCH;
+#endif
+	    break;
+	case 's':
+#if HAVE_RES_INIT
+	    if (opt_s == 0) {
+		_res.nscount = 0;
+		/*
+		 * Setting RES_INIT here causes coredumps when -s is
+		 * used with -D option.  It looks to me like setting
+		 * RES_INIT is wrong.  The resolver code sets RES_INIT
+		 * after calling res_init().  When we change the _res
+		 * structure and set RES_INIT, some internal resolver
+		 * structures get confused.             -DW 2.1.p1
+		 */
+#if SEEMS_WRONG
+		_res.options |= RES_INIT;
+#endif
+		opt_s = 1;
+	    } else if (_res.nscount == MAXNS) {
+		fprintf(stderr, "Too many -s options, only %d are allowed\n",
+		    MAXNS);
+		break;
+	    }
+#if HAVE_RES_NSADDR_LIST
+	    _res.nsaddr_list[_res.nscount] = _res.nsaddr_list[0];
+	    safe_inet_addr(optarg, &_res.nsaddr_list[_res.nscount++].sin_addr);
+#elif HAVE_RES_NS_LIST
+	    _res.ns_list[_res.nscount] = _res.ns_list[0];
+	    safe_inet_addr(optarg, &_res.ns_list[_res.nscount++].addr.sin_addr);
+#else /* Unknown NS list format */
+	    fprintf(stderr, "-s is not supported on this resolver\n");
+#endif
+#else /* !HAVE_RES_INIT */
+	    fprintf(stderr, "-s is not supported on this resolver\n");
+#endif /* HAVE_RES_INIT */
+	    break;
+	case 'v':
+	    printf("dnsserver version %s\n", VERSION);
+	    exit(0);
+	    break;
+	case 'h':
+	default:
+	    usage();
+	    exit(1);
+	    break;
+	}
+    }
+
+    for (;;) {
+	memset(request, '\0', REQ_SZ);
+	if (fgets(request, REQ_SZ, stdin) == NULL)
+	    exit(1);
+	t = strrchr(request, '\n');
+	if (t == NULL)		/* Ignore if no newline */
+	    continue;
+	*t = '\0';		/* strip NL */
+	if ((t = strrchr(request, '\r')) != NULL)
+	    *t = '\0';		/* strip CR */
+	lookup(request);
+	fflush(stdout);
+    }
+    /* NOTREACHED */
+    return 0;
+}
--- squid/src/ipcache.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,823 +0,0 @@
-
-/*
- * $Id: ipcache.c,v 1.19.6.1 2002/10/04 07:07:26 rbcollins Exp $
- *
- * DEBUG: section 14    IP Cache
- * AUTHOR: Harvest Derived
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "Store.h"
-
-typedef struct _ipcache_entry ipcache_entry;
-
-struct _ipcache_entry {
-    hash_link hash;		/* must be first */
-    time_t lastref;
-    time_t expires;
-    ipcache_addrs addrs;
-    IPH *handler;
-    void *handlerData;
-    char *error_message;
-    struct timeval request_time;
-    dlink_node lru;
-    unsigned short locks;
-    struct {
-	unsigned int negcached:1;
-	unsigned int fromhosts:1;
-    } flags;
-};
-
-static struct {
-    int requests;
-    int replies;
-    int hits;
-    int misses;
-    int negative_hits;
-    int errors;
-    int ghbn_calls;		/* # calls to blocking gethostbyname() */
-    int release_locked;
-} IpcacheStats;
-
-static dlink_list lru_list;
-
-static FREE ipcacheFreeEntry;
-#if USE_DNSSERVERS
-static HLPCB ipcacheHandleReply;
-#else
-static IDNSCB ipcacheHandleReply;
-#endif
-static IPH dummy_handler;
-static int ipcacheExpiredEntry(ipcache_entry *);
-static int ipcache_testname(void);
-#if USE_DNSSERVERS
-static ipcache_entry *ipcacheParse(const char *buf);
-#else
-static ipcache_entry *ipcacheParse(rfc1035_rr *, int);
-#endif
-static ipcache_entry *ipcache_get(const char *);
-static void ipcacheLockEntry(ipcache_entry *);
-static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
-static void ipcacheUnlockEntry(ipcache_entry *);
-static void ipcacheRelease(ipcache_entry *);
-
-static ipcache_addrs static_addrs;
-static hash_table *ip_table = NULL;
-
-static long ipcache_low = 180;
-static long ipcache_high = 200;
-
-#if LIBRESOLV_DNS_TTL_HACK
-extern int _dns_ttl_;
-#endif
-
-static int
-ipcache_testname(void)
-{
-    wordlist *w = NULL;
-    debug(14, 1) ("Performing DNS Tests...\n");
-    if ((w = Config.dns_testname_list) == NULL)
-	return 1;
-    for (; w; w = w->next) {
-	IpcacheStats.ghbn_calls++;
-	if (gethostbyname(w->key) != NULL)
-	    return 1;
-    }
-    return 0;
-}
-
-/* removes the given ipcache entry */
-static void
-ipcacheRelease(ipcache_entry * i)
-{
-    hash_remove_link(ip_table, (hash_link *) i);
-    dlinkDelete(&i->lru, &lru_list);
-    ipcacheFreeEntry(i);
-}
-
-static ipcache_entry *
-ipcache_get(const char *name)
-{
-    if (ip_table != NULL)
-	return (ipcache_entry *) hash_lookup(ip_table, name);
-    else
-	return NULL;
-}
-
-static int
-ipcacheExpiredEntry(ipcache_entry * i)
-{
-    /* all static entries are locked, so this takes care of them too */
-    if (i->locks != 0)
-	return 0;
-    if (i->addrs.count == 0)
-	if (0 == i->flags.negcached)
-	    return 1;
-    if (i->expires > squid_curtime)
-	return 0;
-    return 1;
-}
-
-void
-ipcache_purgelru(void *voidnotused)
-{
-    dlink_node *m;
-    dlink_node *prev = NULL;
-    ipcache_entry *i;
-    int removed = 0;
-    eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
-    for (m = lru_list.tail; m; m = prev) {
-	if (memInUse(MEM_IPCACHE_ENTRY) < ipcache_low)
-	    break;
-	prev = m->prev;
-	i = m->data;
-	if (i->locks != 0)
-	    continue;
-	ipcacheRelease(i);
-	removed++;
-    }
-    debug(14, 9) ("ipcache_purgelru: removed %d entries\n", removed);
-}
-
-/* purges entries added from /etc/hosts (or whatever). */
-static void
-purge_entries_fromhosts(void)
-{
-    dlink_node *m = lru_list.head;
-    ipcache_entry *i = NULL, *t;
-    while (m) {
-	if (i != NULL) {	/* need to delay deletion */
-	    ipcacheRelease(i);	/* we just override locks */
-	    i = NULL;
-	}
-	t = m->data;
-	if (t->flags.fromhosts)
-	    i = t;
-	m = m->next;
-    }
-    if (i != NULL)
-	ipcacheRelease(i);
-}
-
-/* create blank ipcache_entry */
-static ipcache_entry *
-ipcacheCreateEntry(const char *name)
-{
-    static ipcache_entry *i;
-    i = memAllocate(MEM_IPCACHE_ENTRY);
-    i->hash.key = xstrdup(name);
-    i->expires = squid_curtime + Config.negativeDnsTtl;
-    return i;
-}
-
-static void
-ipcacheAddEntry(ipcache_entry * i)
-{
-    hash_link *e = hash_lookup(ip_table, i->hash.key);
-    if (NULL != e) {
-	/* avoid colission */
-	ipcache_entry *q = (ipcache_entry *) e;
-	ipcacheRelease(q);
-    }
-    hash_join(ip_table, &i->hash);
-    dlinkAdd(i, &i->lru, &lru_list);
-    i->lastref = squid_curtime;
-}
-
-/* walks down the pending list, calling handlers */
-static void
-ipcacheCallback(ipcache_entry * i)
-{
-    IPH *callback = i->handler;
-    void *cbdata;
-    i->lastref = squid_curtime;
-    if (!i->handler)
-	return;
-    ipcacheLockEntry(i);
-    callback = i->handler;
-    i->handler = NULL;
-    if (cbdataReferenceValidDone(i->handlerData, &cbdata)) {
-	dns_error_message = i->error_message;
-	callback(i->flags.negcached ? NULL : &i->addrs, cbdata);
-    }
-    ipcacheUnlockEntry(i);
-}
-
-static ipcache_entry *
-#if USE_DNSSERVERS
-ipcacheParse(const char *inbuf)
-{
-    LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
-    char *token;
-    static ipcache_entry i;
-    int j;
-    int k;
-    int ipcount = 0;
-    int ttl;
-    char A[32][16];
-    memset(&i, '\0', sizeof(i));
-    i.expires = squid_curtime;
-    i.flags.negcached = 1;
-    if (inbuf == NULL) {
-	debug(14, 1) ("ipcacheParse: Got <NULL> reply\n");
-	i.error_message = xstrdup("Internal Squid Error");
-	return &i;
-    }
-    xstrncpy(buf, inbuf, DNS_INBUF_SZ);
-    debug(14, 5) ("ipcacheParse: parsing: {%s}\n", buf);
-    token = strtok(buf, w_space);
-    if (NULL == token) {
-	debug(14, 1) ("ipcacheParse: Got <NULL>, expecting '$addr'\n");
-	return &i;
-    }
-    if (0 == strcmp(token, "$fail")) {
-	i.expires = squid_curtime + Config.negativeDnsTtl;
-	token = strtok(NULL, "\n");
-	assert(NULL != token);
-	i.error_message = xstrdup(token);
-	return &i;
-    }
-    if (0 != strcmp(token, "$addr")) {
-	debug(14, 1) ("ipcacheParse: Got '%s', expecting '$addr'\n", token);
-	return &i;
-    }
-    token = strtok(NULL, w_space);
-    if (NULL == token) {
-	debug(14, 1) ("ipcacheParse: Got <NULL>, expecting TTL\n");
-	return &i;
-    }
-    i.flags.negcached = 0;
-    ttl = atoi(token);
-    if (ttl > 0)
-	i.expires = squid_curtime + ttl;
-    else
-	i.expires = squid_curtime + Config.positiveDnsTtl;
-    while (NULL != (token = strtok(NULL, w_space))) {
-	xstrncpy(A[ipcount], token, 16);
-	if (++ipcount == 32)
-	    break;
-    }
-    if (0 == ipcount) {
-	i.addrs.in_addrs = NULL;
-	i.addrs.bad_mask = NULL;
-    } else {
-	i.addrs.in_addrs = xcalloc(ipcount, sizeof(struct in_addr));
-	i.addrs.bad_mask = xcalloc(ipcount, sizeof(unsigned char));
-    }
-    for (j = 0, k = 0; k < ipcount; k++) {
-	if (safe_inet_addr(A[k], &i.addrs.in_addrs[j]))
-	    j++;
-	else
-	    debug(14, 1) ("ipcacheParse: Invalid IP address '%s'\n", A[k]);
-    }
-    i.addrs.count = (unsigned char) j;
-    return &i;
-}
-#else
-ipcacheParse(rfc1035_rr * answers, int nr)
-{
-    static ipcache_entry i;
-    int k;
-    int j;
-    int na = 0;
-    memset(&i, '\0', sizeof(i));
-    i.expires = squid_curtime + Config.negativeDnsTtl;
-    i.flags.negcached = 1;
-    if (nr < 0) {
-	debug(14, 3) ("ipcacheParse: Lookup failed (error %d)\n",
-	    rfc1035_errno);
-	assert(rfc1035_error_message);
-	i.error_message = xstrdup(rfc1035_error_message);
-	return &i;
-    }
-    if (nr == 0) {
-	debug(14, 3) ("ipcacheParse: No DNS records\n");
-	i.error_message = xstrdup("No DNS records");
-	return &i;
-    }
-    assert(answers);
-    for (j = 0, k = 0; k < nr; k++) {
-	if (answers[k].type != RFC1035_TYPE_A)
-	    continue;
-	if (answers[k]._class != RFC1035_CLASS_IN)
-	    continue;
-	na++;
-    }
-    if (na == 0) {
-	debug(14, 1) ("ipcacheParse: No Address records\n");
-	i.error_message = xstrdup("No Address records");
-	return &i;
-    }
-    i.flags.negcached = 0;
-    i.addrs.in_addrs = xcalloc(na, sizeof(struct in_addr));
-    i.addrs.bad_mask = xcalloc(na, sizeof(unsigned char));
-    i.addrs.count = (unsigned char) na;
-    for (j = 0, k = 0; k < nr; k++) {
-	if (answers[k].type != RFC1035_TYPE_A)
-	    continue;
-	if (answers[k]._class != RFC1035_CLASS_IN)
-	    continue;
-	if (j == 0)
-	    i.expires = squid_curtime + answers[k].ttl;
-	assert(answers[k].rdlength == 4);
-	xmemcpy(&i.addrs.in_addrs[j++], answers[k].rdata, 4);
-	debug(14, 3) ("ipcacheParse: #%d %s\n",
-	    j - 1,
-	    inet_ntoa(i.addrs.in_addrs[j - 1]));
-    }
-    assert(j == na);
-    return &i;
-}
-#endif
-
-static void
-#if USE_DNSSERVERS
-ipcacheHandleReply(void *data, char *reply)
-#else
-ipcacheHandleReply(void *data, rfc1035_rr * answers, int na)
-#endif
-{
-    generic_cbdata *c = data;
-    ipcache_entry *i = c->data;
-    ipcache_entry *x = NULL;
-    cbdataFree(c);
-    c = NULL;
-    IpcacheStats.replies++;
-    statHistCount(&statCounter.dns.svc_time,
-	tvSubMsec(i->request_time, current_time));
-#if USE_DNSSERVERS
-    x = ipcacheParse(reply);
-#else
-    x = ipcacheParse(answers, na);
-#endif
-    assert(x);
-    i->addrs = x->addrs;
-    i->error_message = x->error_message;
-    i->expires = x->expires;
-    i->flags = x->flags;
-    ipcacheAddEntry(i);
-    ipcacheCallback(i);
-}
-
-void
-ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
-{
-    ipcache_entry *i = NULL;
-    const ipcache_addrs *addrs = NULL;
-    generic_cbdata *c;
-    assert(handler != NULL);
-    debug(14, 4) ("ipcache_nbgethostbyname: Name '%s'.\n", name);
-    IpcacheStats.requests++;
-    if (name == NULL || name[0] == '\0') {
-	debug(14, 4) ("ipcache_nbgethostbyname: Invalid name!\n");
-	handler(NULL, handlerData);
-	return;
-    }
-    if ((addrs = ipcacheCheckNumeric(name))) {
-	handler(addrs, handlerData);
-	return;
-    }
-    i = ipcache_get(name);
-    if (NULL == i) {
-	/* miss */
-	(void) 0;
-    } else if (ipcacheExpiredEntry(i)) {
-	/* hit, but expired -- bummer */
-	ipcacheRelease(i);
-	i = NULL;
-    } else {
-	/* hit */
-	debug(14, 4) ("ipcache_nbgethostbyname: HIT for '%s'\n", name);
-	if (i->flags.negcached)
-	    IpcacheStats.negative_hits++;
-	else
-	    IpcacheStats.hits++;
-	i->handler = handler;
-	i->handlerData = cbdataReference(handlerData);
-	ipcacheCallback(i);
-	return;
-    }
-    debug(14, 5) ("ipcache_nbgethostbyname: MISS for '%s'\n", name);
-    IpcacheStats.misses++;
-    i = ipcacheCreateEntry(name);
-    i->handler = handler;
-    i->handlerData = cbdataReference(handlerData);
-    i->request_time = current_time;
-    c = cbdataAlloc(generic_cbdata);
-    c->data = i;
-#if USE_DNSSERVERS
-    dnsSubmit(hashKeyStr(&i->hash), ipcacheHandleReply, c);
-#else
-    idnsALookup(hashKeyStr(&i->hash), ipcacheHandleReply, c);
-#endif
-}
-
-/* initialize the ipcache */
-void
-ipcache_init(void)
-{
-    int n;
-    debug(14, 3) ("Initializing IP Cache...\n");
-    memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
-    memset(&lru_list, '\0', sizeof(lru_list));
-    /* test naming lookup */
-    if (!opt_dns_tests) {
-	debug(14, 4) ("ipcache_init: Skipping DNS name lookup tests.\n");
-    } else if (!ipcache_testname()) {
-	fatal("ipcache_init: DNS name lookup tests failed.");
-    } else {
-	debug(14, 1) ("Successful DNS name lookup tests...\n");
-    }
-    memset(&static_addrs, '\0', sizeof(ipcache_addrs));
-    static_addrs.in_addrs = xcalloc(1, sizeof(struct in_addr));
-    static_addrs.bad_mask = xcalloc(1, sizeof(unsigned char));
-    ipcache_high = (long) (((float) Config.ipcache.size *
-	    (float) Config.ipcache.high) / (float) 100);
-    ipcache_low = (long) (((float) Config.ipcache.size *
-	    (float) Config.ipcache.low) / (float) 100);
-    n = hashPrime(ipcache_high / 4);
-    ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
-    cachemgrRegister("ipcache",
-	"IP Cache Stats and Contents",
-	stat_ipcache_get, 0, 1);
-    memDataInit(MEM_IPCACHE_ENTRY, "ipcache_entry", sizeof(ipcache_entry), 0);
-}
-
-const ipcache_addrs *
-ipcache_gethostbyname(const char *name, int flags)
-{
-    ipcache_entry *i = NULL;
-    ipcache_addrs *addrs;
-    assert(name);
-    debug(14, 3) ("ipcache_gethostbyname: '%s', flags=%x\n", name, flags);
-    IpcacheStats.requests++;
-    i = ipcache_get(name);
-    if (NULL == i) {
-	(void) 0;
-    } else if (ipcacheExpiredEntry(i)) {
-	ipcacheRelease(i);
-	i = NULL;
-    } else if (i->flags.negcached) {
-	IpcacheStats.negative_hits++;
-	dns_error_message = i->error_message;
-	return NULL;
-    } else {
-	IpcacheStats.hits++;
-	i->lastref = squid_curtime;
-	return &i->addrs;
-    }
-    if ((addrs = ipcacheCheckNumeric(name)))
-	return addrs;
-    IpcacheStats.misses++;
-    if (flags & IP_LOOKUP_IF_MISS)
-	ipcache_nbgethostbyname(name, dummy_handler, NULL);
-    return NULL;
-}
-
-static void
-ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
-{
-    int k;
-    storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
-	hashKeyStr(&i->hash),
-	i->flags.fromhosts ? 'H' : ' ',
-	i->flags.negcached ? 'N' : ' ',
-	(int) (squid_curtime - i->lastref),
-	(int) ((i->flags.fromhosts ? -1 : i->expires - squid_curtime)),
-	(int) i->addrs.count,
-	(int) i->addrs.badcount);
-    for (k = 0; k < (int) i->addrs.count; k++) {
-	storeAppendPrintf(sentry, " %15s-%3s", inet_ntoa(i->addrs.in_addrs[k]),
-	    i->addrs.bad_mask[k] ? "BAD" : "OK ");
-    }
-    storeAppendPrintf(sentry, "\n");
-}
-
-/* process objects list */
-void
-stat_ipcache_get(StoreEntry * sentry)
-{
-    dlink_node *m;
-    assert(ip_table != NULL);
-    storeAppendPrintf(sentry, "IP Cache Statistics:\n");
-    storeAppendPrintf(sentry, "IPcache Entries: %d\n",
-	memInUse(MEM_IPCACHE_ENTRY));
-    storeAppendPrintf(sentry, "IPcache Requests: %d\n",
-	IpcacheStats.requests);
-    storeAppendPrintf(sentry, "IPcache Hits: %d\n",
-	IpcacheStats.hits);
-    storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n",
-	IpcacheStats.negative_hits);
-    storeAppendPrintf(sentry, "IPcache Misses: %d\n",
-	IpcacheStats.misses);
-    storeAppendPrintf(sentry, "Blocking calls to gethostbyname(): %d\n",
-	IpcacheStats.ghbn_calls);
-    storeAppendPrintf(sentry, "Attempts to release locked entries: %d\n",
-	IpcacheStats.release_locked);
-    storeAppendPrintf(sentry, "\n\n");
-    storeAppendPrintf(sentry, "IP Cache Contents:\n\n");
-    storeAppendPrintf(sentry, " %-29.29s %3s %6s %6s %1s\n",
-	"Hostname",
-	"Flg",
-	"lstref",
-	"TTL",
-	"N");
-    for (m = lru_list.head; m; m = m->next)
-	ipcacheStatPrint(m->data, sentry);
-}
-
-static void
-dummy_handler(const ipcache_addrs * addrsnotused, void *datanotused)
-{
-    return;
-}
-
-void
-ipcacheInvalidate(const char *name)
-{
-    ipcache_entry *i;
-    if ((i = ipcache_get(name)) == NULL)
-	return;
-    i->expires = squid_curtime;
-    /*
-     * NOTE, don't call ipcacheRelease here becuase we might be here due
-     * to a thread started from a callback.
-     */
-}
-
-ipcache_addrs *
-ipcacheCheckNumeric(const char *name)
-{
-    struct in_addr ip;
-    /* check if it's already a IP address in text form. */
-    if (!safe_inet_addr(name, &ip))
-	return NULL;
-    static_addrs.count = 1;
-    static_addrs.cur = 0;
-    static_addrs.in_addrs[0].s_addr = ip.s_addr;
-    static_addrs.bad_mask[0] = FALSE;
-    static_addrs.badcount = 0;
-    return &static_addrs;
-}
-
-static void
-ipcacheLockEntry(ipcache_entry * i)
-{
-    if (i->locks++ == 0) {
-	dlinkDelete(&i->lru, &lru_list);
-	dlinkAdd(i, &i->lru, &lru_list);
-    }
-}
-
-static void
-ipcacheUnlockEntry(ipcache_entry * i)
-{
-    assert(i->locks > 0);
-    i->locks--;
-    if (ipcacheExpiredEntry(i))
-	ipcacheRelease(i);
-}
-
-void
-ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
-{
-    ipcache_entry *i;
-    unsigned char k;
-    assert(name || ia);
-    if (NULL == ia) {
-	if ((i = ipcache_get(name)) == NULL)
-	    return;
-	if (i->flags.negcached)
-	    return;
-	ia = &i->addrs;
-    }
-    for (k = 0; k < ia->count; k++) {
-	if (++ia->cur == ia->count)
-	    ia->cur = 0;
-	if (!ia->bad_mask[ia->cur])
-	    break;
-    }
-    if (k == ia->count) {
-	/* All bad, reset to All good */
-	debug(14, 3) ("ipcacheCycleAddr: Changing ALL %s addrs from BAD to OK\n",
-	    name);
-	for (k = 0; k < ia->count; k++)
-	    ia->bad_mask[k] = 0;
-	ia->badcount = 0;
-	ia->cur = 0;
-    }
-    debug(14, 3) ("ipcacheCycleAddr: %s now at %s\n", name,
-	inet_ntoa(ia->in_addrs[ia->cur]));
-}
-
-/*
- * Marks the given address as BAD and calls ipcacheCycleAddr to
- * advance the current pointer to the next OK address.
- */
-void
-ipcacheMarkBadAddr(const char *name, struct in_addr addr)
-{
-    ipcache_entry *i;
-    ipcache_addrs *ia;
-    int k;
-    if ((i = ipcache_get(name)) == NULL)
-	return;
-    ia = &i->addrs;
-    for (k = 0; k < (int) ia->count; k++) {
-	if (ia->in_addrs[k].s_addr == addr.s_addr)
-	    break;
-    }
-    if (k == (int) ia->count)	/* not found */
-	return;
-    if (!ia->bad_mask[k]) {
-	ia->bad_mask[k] = TRUE;
-	ia->badcount++;
-	debug(14, 2) ("ipcacheMarkBadAddr: %s [%s]\n", name, inet_ntoa(addr));
-    }
-    ipcacheCycleAddr(name, ia);
-}
-
-void
-ipcacheMarkGoodAddr(const char *name, struct in_addr addr)
-{
-    ipcache_entry *i;
-    ipcache_addrs *ia;
-    int k;
-    if ((i = ipcache_get(name)) == NULL)
-	return;
-    ia = &i->addrs;
-    for (k = 0; k < (int) ia->count; k++) {
-	if (ia->in_addrs[k].s_addr == addr.s_addr)
-	    break;
-    }
-    if (k == (int) ia->count)	/* not found */
-	return;
-    if (!ia->bad_mask[k])	/* already OK */
-	return;
-    ia->bad_mask[k] = FALSE;
-    ia->badcount--;
-    debug(14, 2) ("ipcacheMarkGoodAddr: %s [%s]\n", name, inet_ntoa(addr));
-}
-
-static void
-ipcacheFreeEntry(void *data)
-{
-    ipcache_entry *i = data;
-    safe_free(i->addrs.in_addrs);
-    safe_free(i->addrs.bad_mask);
-    safe_free(i->hash.key);
-    safe_free(i->error_message);
-    memFree(i, MEM_IPCACHE_ENTRY);
-}
-
-void
-ipcacheFreeMemory(void)
-{
-    hashFreeItems(ip_table, ipcacheFreeEntry);
-    hashFreeMemory(ip_table);
-    ip_table = NULL;
-}
-
-/* Recalculate IP cache size upon reconfigure */
-void
-ipcache_restart(void)
-{
-    ipcache_high = (long) (((float) Config.ipcache.size *
-	    (float) Config.ipcache.high) / (float) 100);
-    ipcache_low = (long) (((float) Config.ipcache.size *
-	    (float) Config.ipcache.low) / (float) 100);
-    purge_entries_fromhosts();
-}
-
-/*
- *  adds a "static" entry from /etc/hosts.  
- *  returns 0 upon success, 1 if the ip address is invalid
- */
-int
-ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
-{
-    ipcache_entry *i;
-    struct in_addr ip;
-    if (!safe_inet_addr(ipaddr, &ip)) {
-	if (strchr(ipaddr, ':') && strspn(ipaddr, "0123456789abcdefABCDEF:") == strlen(ipaddr)) {
-	    debug(14, 3) ("ipcacheAddEntryFromHosts: Skipping IPv6 address '%s'\n", ipaddr);
-	} else {
-	    debug(14, 1) ("ipcacheAddEntryFromHosts: Bad IP address '%s'\n",
-		ipaddr);
-	}
-	return 1;
-    }
-    if ((i = ipcache_get(name))) {
-	if (1 == i->flags.fromhosts) {
-	    ipcacheUnlockEntry(i);
-	} else if (i->locks > 0) {
-	    debug(14, 1) ("ipcacheAddEntryFromHosts: can't add static entry"
-		" for locked name '%s'\n", name);
-	    return 1;
-	} else {
-	    ipcacheRelease(i);
-	}
-    }
-    i = ipcacheCreateEntry(name);
-    i->addrs.count = 1;
-    i->addrs.cur = 0;
-    i->addrs.badcount = 0;
-    i->addrs.in_addrs = xcalloc(1, sizeof(struct in_addr));
-    i->addrs.bad_mask = xcalloc(1, sizeof(unsigned char));
-    i->addrs.in_addrs[0].s_addr = ip.s_addr;
-    i->addrs.bad_mask[0] = FALSE;
-    i->flags.fromhosts = 1;
-    ipcacheAddEntry(i);
-    ipcacheLockEntry(i);
-    return 0;
-}
-
-#ifdef SQUID_SNMP
-/*
- * The function to return the ip cache statistics to via SNMP
- */
-
-variable_list *
-snmp_netIpFn(variable_list * Var, snint * ErrP)
-{
-    variable_list *Answer = NULL;
-    debug(49, 5) ("snmp_netIpFn: Processing request:\n");
-    snmpDebugOid(5, Var->name, Var->name_length);
-    *ErrP = SNMP_ERR_NOERROR;
-    switch (Var->name[LEN_SQ_NET + 1]) {
-    case IP_ENT:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    memInUse(MEM_IPCACHE_ENTRY),
-	    SMI_GAUGE32);
-	break;
-    case IP_REQ:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    IpcacheStats.requests,
-	    SMI_COUNTER32);
-	break;
-    case IP_HITS:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    IpcacheStats.hits,
-	    SMI_COUNTER32);
-	break;
-    case IP_PENDHIT:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    0,
-	    SMI_GAUGE32);
-	break;
-    case IP_NEGHIT:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    IpcacheStats.negative_hits,
-	    SMI_COUNTER32);
-	break;
-    case IP_MISS:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    IpcacheStats.misses,
-	    SMI_COUNTER32);
-	break;
-    case IP_GHBN:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    IpcacheStats.ghbn_calls,
-	    SMI_COUNTER32);
-	break;
-    case IP_LOC:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    IpcacheStats.release_locked,
-	    SMI_COUNTER32);
-	break;
-    default:
-	*ErrP = SNMP_ERR_NOSUCHNAME;
-	snmp_var_free(Answer);
-	return (NULL);
-    }
-    return Answer;
-}
-
-#endif /*SQUID_SNMP */
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/ipcache.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,823 @@
+
+/*
+ * $Id: ipcache.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 14    IP Cache
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "Store.h"
+
+typedef struct _ipcache_entry ipcache_entry;
+
+struct _ipcache_entry {
+    hash_link hash;		/* must be first */
+    time_t lastref;
+    time_t expires;
+    ipcache_addrs addrs;
+    IPH *handler;
+    void *handlerData;
+    char *error_message;
+    struct timeval request_time;
+    dlink_node lru;
+    unsigned short locks;
+    struct {
+	unsigned int negcached:1;
+	unsigned int fromhosts:1;
+    } flags;
+};
+
+static struct {
+    int requests;
+    int replies;
+    int hits;
+    int misses;
+    int negative_hits;
+    int errors;
+    int ghbn_calls;		/* # calls to blocking gethostbyname() */
+    int release_locked;
+} IpcacheStats;
+
+static dlink_list lru_list;
+
+static FREE ipcacheFreeEntry;
+#if USE_DNSSERVERS
+static HLPCB ipcacheHandleReply;
+#else
+static IDNSCB ipcacheHandleReply;
+#endif
+static IPH dummy_handler;
+static int ipcacheExpiredEntry(ipcache_entry *);
+static int ipcache_testname(void);
+#if USE_DNSSERVERS
+static ipcache_entry *ipcacheParse(const char *buf);
+#else
+static ipcache_entry *ipcacheParse(rfc1035_rr *, int);
+#endif
+static ipcache_entry *ipcache_get(const char *);
+static void ipcacheLockEntry(ipcache_entry *);
+static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
+static void ipcacheUnlockEntry(ipcache_entry *);
+static void ipcacheRelease(ipcache_entry *);
+
+static ipcache_addrs static_addrs;
+static hash_table *ip_table = NULL;
+
+static long ipcache_low = 180;
+static long ipcache_high = 200;
+
+#if LIBRESOLV_DNS_TTL_HACK
+extern int _dns_ttl_;
+#endif
+
+static int
+ipcache_testname(void)
+{
+    wordlist *w = NULL;
+    debug(14, 1) ("Performing DNS Tests...\n");
+    if ((w = Config.dns_testname_list) == NULL)
+	return 1;
+    for (; w; w = w->next) {
+	IpcacheStats.ghbn_calls++;
+	if (gethostbyname(w->key) != NULL)
+	    return 1;
+    }
+    return 0;
+}
+
+/* removes the given ipcache entry */
+static void
+ipcacheRelease(ipcache_entry * i)
+{
+    hash_remove_link(ip_table, (hash_link *) i);
+    dlinkDelete(&i->lru, &lru_list);
+    ipcacheFreeEntry(i);
+}
+
+static ipcache_entry *
+ipcache_get(const char *name)
+{
+    if (ip_table != NULL)
+	return (ipcache_entry *) hash_lookup(ip_table, name);
+    else
+	return NULL;
+}
+
+static int
+ipcacheExpiredEntry(ipcache_entry * i)
+{
+    /* all static entries are locked, so this takes care of them too */
+    if (i->locks != 0)
+	return 0;
+    if (i->addrs.count == 0)
+	if (0 == i->flags.negcached)
+	    return 1;
+    if (i->expires > squid_curtime)
+	return 0;
+    return 1;
+}
+
+void
+ipcache_purgelru(void *voidnotused)
+{
+    dlink_node *m;
+    dlink_node *prev = NULL;
+    ipcache_entry *i;
+    int removed = 0;
+    eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
+    for (m = lru_list.tail; m; m = prev) {
+	if (memInUse(MEM_IPCACHE_ENTRY) < ipcache_low)
+	    break;
+	prev = m->prev;
+	i = (ipcache_entry *)m->data;
+	if (i->locks != 0)
+	    continue;
+	ipcacheRelease(i);
+	removed++;
+    }
+    debug(14, 9) ("ipcache_purgelru: removed %d entries\n", removed);
+}
+
+/* purges entries added from /etc/hosts (or whatever). */
+static void
+purge_entries_fromhosts(void)
+{
+    dlink_node *m = lru_list.head;
+    ipcache_entry *i = NULL, *t;
+    while (m) {
+	if (i != NULL) {	/* need to delay deletion */
+	    ipcacheRelease(i);	/* we just override locks */
+	    i = NULL;
+	}
+	t = (ipcache_entry*)m->data;
+	if (t->flags.fromhosts)
+	    i = t;
+	m = m->next;
+    }
+    if (i != NULL)
+	ipcacheRelease(i);
+}
+
+/* create blank ipcache_entry */
+static ipcache_entry *
+ipcacheCreateEntry(const char *name)
+{
+    static ipcache_entry *i;
+    i = (ipcache_entry *)memAllocate(MEM_IPCACHE_ENTRY);
+    i->hash.key = xstrdup(name);
+    i->expires = squid_curtime + Config.negativeDnsTtl;
+    return i;
+}
+
+static void
+ipcacheAddEntry(ipcache_entry * i)
+{
+    hash_link *e = (hash_link *)hash_lookup(ip_table, i->hash.key);
+    if (NULL != e) {
+	/* avoid colission */
+	ipcache_entry *q = (ipcache_entry *) e;
+	ipcacheRelease(q);
+    }
+    hash_join(ip_table, &i->hash);
+    dlinkAdd(i, &i->lru, &lru_list);
+    i->lastref = squid_curtime;
+}
+
+/* walks down the pending list, calling handlers */
+static void
+ipcacheCallback(ipcache_entry * i)
+{
+    IPH *callback = i->handler;
+    void *cbdata;
+    i->lastref = squid_curtime;
+    if (!i->handler)
+	return;
+    ipcacheLockEntry(i);
+    callback = i->handler;
+    i->handler = NULL;
+    if (cbdataReferenceValidDone(i->handlerData, &cbdata)) {
+	dns_error_message = i->error_message;
+	callback(i->flags.negcached ? NULL : &i->addrs, cbdata);
+    }
+    ipcacheUnlockEntry(i);
+}
+
+static ipcache_entry *
+#if USE_DNSSERVERS
+ipcacheParse(const char *inbuf)
+{
+    LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
+    char *token;
+    static ipcache_entry i;
+    int j;
+    int k;
+    int ipcount = 0;
+    int ttl;
+    char A[32][16];
+    memset(&i, '\0', sizeof(i));
+    i.expires = squid_curtime;
+    i.flags.negcached = 1;
+    if (inbuf == NULL) {
+	debug(14, 1) ("ipcacheParse: Got <NULL> reply\n");
+	i.error_message = xstrdup("Internal Squid Error");
+	return &i;
+    }
+    xstrncpy(buf, inbuf, DNS_INBUF_SZ);
+    debug(14, 5) ("ipcacheParse: parsing: {%s}\n", buf);
+    token = strtok(buf, w_space);
+    if (NULL == token) {
+	debug(14, 1) ("ipcacheParse: Got <NULL>, expecting '$addr'\n");
+	return &i;
+    }
+    if (0 == strcmp(token, "$fail")) {
+	i.expires = squid_curtime + Config.negativeDnsTtl;
+	token = strtok(NULL, "\n");
+	assert(NULL != token);
+	i.error_message = xstrdup(token);
+	return &i;
+    }
+    if (0 != strcmp(token, "$addr")) {
+	debug(14, 1) ("ipcacheParse: Got '%s', expecting '$addr'\n", token);
+	return &i;
+    }
+    token = strtok(NULL, w_space);
+    if (NULL == token) {
+	debug(14, 1) ("ipcacheParse: Got <NULL>, expecting TTL\n");
+	return &i;
+    }
+    i.flags.negcached = 0;
+    ttl = atoi(token);
+    if (ttl > 0)
+	i.expires = squid_curtime + ttl;
+    else
+	i.expires = squid_curtime + Config.positiveDnsTtl;
+    while (NULL != (token = strtok(NULL, w_space))) {
+	xstrncpy(A[ipcount], token, 16);
+	if (++ipcount == 32)
+	    break;
+    }
+    if (0 == ipcount) {
+	i.addrs.in_addrs = NULL;
+	i.addrs.bad_mask = NULL;
+    } else {
+	i.addrs.in_addrs = xcalloc(ipcount, sizeof(struct in_addr));
+	i.addrs.bad_mask = xcalloc(ipcount, sizeof(unsigned char));
+    }
+    for (j = 0, k = 0; k < ipcount; k++) {
+	if (safe_inet_addr(A[k], &i.addrs.in_addrs[j]))
+	    j++;
+	else
+	    debug(14, 1) ("ipcacheParse: Invalid IP address '%s'\n", A[k]);
+    }
+    i.addrs.count = (unsigned char) j;
+    return &i;
+}
+#else
+ipcacheParse(rfc1035_rr * answers, int nr)
+{
+    static ipcache_entry i;
+    int k;
+    int j;
+    int na = 0;
+    memset(&i, '\0', sizeof(i));
+    i.expires = squid_curtime + Config.negativeDnsTtl;
+    i.flags.negcached = 1;
+    if (nr < 0) {
+	debug(14, 3) ("ipcacheParse: Lookup failed (error %d)\n",
+	    rfc1035_errno);
+	assert(rfc1035_error_message);
+	i.error_message = xstrdup(rfc1035_error_message);
+	return &i;
+    }
+    if (nr == 0) {
+	debug(14, 3) ("ipcacheParse: No DNS records\n");
+	i.error_message = xstrdup("No DNS records");
+	return &i;
+    }
+    assert(answers);
+    for (j = 0, k = 0; k < nr; k++) {
+	if (answers[k].type != RFC1035_TYPE_A)
+	    continue;
+	if (answers[k]._class != RFC1035_CLASS_IN)
+	    continue;
+	na++;
+    }
+    if (na == 0) {
+	debug(14, 1) ("ipcacheParse: No Address records\n");
+	i.error_message = xstrdup("No Address records");
+	return &i;
+    }
+    i.flags.negcached = 0;
+    i.addrs.in_addrs = (struct in_addr *)xcalloc(na, sizeof(struct in_addr));
+    i.addrs.bad_mask = (unsigned char *)xcalloc(na, sizeof(unsigned char));
+    i.addrs.count = (unsigned char) na;
+    for (j = 0, k = 0; k < nr; k++) {
+	if (answers[k].type != RFC1035_TYPE_A)
+	    continue;
+	if (answers[k]._class != RFC1035_CLASS_IN)
+	    continue;
+	if (j == 0)
+	    i.expires = squid_curtime + answers[k].ttl;
+	assert(answers[k].rdlength == 4);
+	xmemcpy(&i.addrs.in_addrs[j++], answers[k].rdata, 4);
+	debug(14, 3) ("ipcacheParse: #%d %s\n",
+	    j - 1,
+	    inet_ntoa(i.addrs.in_addrs[j - 1]));
+    }
+    assert(j == na);
+    return &i;
+}
+#endif
+
+static void
+#if USE_DNSSERVERS
+ipcacheHandleReply(void *data, char *reply)
+#else
+ipcacheHandleReply(void *data, rfc1035_rr * answers, int na)
+#endif
+{
+    generic_cbdata *c = (generic_cbdata *)data;
+    ipcache_entry *i = (ipcache_entry *)c->data;
+    ipcache_entry *x = NULL;
+    cbdataFree(c);
+    c = NULL;
+    IpcacheStats.replies++;
+    statHistCount(&statCounter.dns.svc_time,
+	tvSubMsec(i->request_time, current_time));
+#if USE_DNSSERVERS
+    x = ipcacheParse(reply);
+#else
+    x = ipcacheParse(answers, na);
+#endif
+    assert(x);
+    i->addrs = x->addrs;
+    i->error_message = x->error_message;
+    i->expires = x->expires;
+    i->flags = x->flags;
+    ipcacheAddEntry(i);
+    ipcacheCallback(i);
+}
+
+void
+ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
+{
+    ipcache_entry *i = NULL;
+    const ipcache_addrs *addrs = NULL;
+    generic_cbdata *c;
+    assert(handler != NULL);
+    debug(14, 4) ("ipcache_nbgethostbyname: Name '%s'.\n", name);
+    IpcacheStats.requests++;
+    if (name == NULL || name[0] == '\0') {
+	debug(14, 4) ("ipcache_nbgethostbyname: Invalid name!\n");
+	handler(NULL, handlerData);
+	return;
+    }
+    if ((addrs = ipcacheCheckNumeric(name))) {
+	handler(addrs, handlerData);
+	return;
+    }
+    i = ipcache_get(name);
+    if (NULL == i) {
+	/* miss */
+	(void) 0;
+    } else if (ipcacheExpiredEntry(i)) {
+	/* hit, but expired -- bummer */
+	ipcacheRelease(i);
+	i = NULL;
+    } else {
+	/* hit */
+	debug(14, 4) ("ipcache_nbgethostbyname: HIT for '%s'\n", name);
+	if (i->flags.negcached)
+	    IpcacheStats.negative_hits++;
+	else
+	    IpcacheStats.hits++;
+	i->handler = handler;
+	i->handlerData = cbdataReference(handlerData);
+	ipcacheCallback(i);
+	return;
+    }
+    debug(14, 5) ("ipcache_nbgethostbyname: MISS for '%s'\n", name);
+    IpcacheStats.misses++;
+    i = ipcacheCreateEntry(name);
+    i->handler = handler;
+    i->handlerData = cbdataReference(handlerData);
+    i->request_time = current_time;
+    c = cbdataAlloc(generic_cbdata);
+    c->data = i;
+#if USE_DNSSERVERS
+    dnsSubmit(hashKeyStr(&i->hash), ipcacheHandleReply, c);
+#else
+    idnsALookup(hashKeyStr(&i->hash), ipcacheHandleReply, c);
+#endif
+}
+
+/* initialize the ipcache */
+void
+ipcache_init(void)
+{
+    int n;
+    debug(14, 3) ("Initializing IP Cache...\n");
+    memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
+    memset(&lru_list, '\0', sizeof(lru_list));
+    /* test naming lookup */
+    if (!opt_dns_tests) {
+	debug(14, 4) ("ipcache_init: Skipping DNS name lookup tests.\n");
+    } else if (!ipcache_testname()) {
+	fatal("ipcache_init: DNS name lookup tests failed.");
+    } else {
+	debug(14, 1) ("Successful DNS name lookup tests...\n");
+    }
+    memset(&static_addrs, '\0', sizeof(ipcache_addrs));
+    static_addrs.in_addrs = (struct in_addr *)xcalloc(1, sizeof(struct in_addr));
+    static_addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
+    ipcache_high = (long) (((float) Config.ipcache.size *
+	    (float) Config.ipcache.high) / (float) 100);
+    ipcache_low = (long) (((float) Config.ipcache.size *
+	    (float) Config.ipcache.low) / (float) 100);
+    n = hashPrime(ipcache_high / 4);
+    ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
+    cachemgrRegister("ipcache",
+	"IP Cache Stats and Contents",
+	stat_ipcache_get, 0, 1);
+    memDataInit(MEM_IPCACHE_ENTRY, "ipcache_entry", sizeof(ipcache_entry), 0);
+}
+
+const ipcache_addrs *
+ipcache_gethostbyname(const char *name, int flags)
+{
+    ipcache_entry *i = NULL;
+    ipcache_addrs *addrs;
+    assert(name);
+    debug(14, 3) ("ipcache_gethostbyname: '%s', flags=%x\n", name, flags);
+    IpcacheStats.requests++;
+    i = ipcache_get(name);
+    if (NULL == i) {
+	(void) 0;
+    } else if (ipcacheExpiredEntry(i)) {
+	ipcacheRelease(i);
+	i = NULL;
+    } else if (i->flags.negcached) {
+	IpcacheStats.negative_hits++;
+	dns_error_message = i->error_message;
+	return NULL;
+    } else {
+	IpcacheStats.hits++;
+	i->lastref = squid_curtime;
+	return &i->addrs;
+    }
+    if ((addrs = ipcacheCheckNumeric(name)))
+	return addrs;
+    IpcacheStats.misses++;
+    if (flags & IP_LOOKUP_IF_MISS)
+	ipcache_nbgethostbyname(name, dummy_handler, NULL);
+    return NULL;
+}
+
+static void
+ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
+{
+    int k;
+    storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
+	hashKeyStr(&i->hash),
+	i->flags.fromhosts ? 'H' : ' ',
+	i->flags.negcached ? 'N' : ' ',
+	(int) (squid_curtime - i->lastref),
+	(int) ((i->flags.fromhosts ? -1 : i->expires - squid_curtime)),
+	(int) i->addrs.count,
+	(int) i->addrs.badcount);
+    for (k = 0; k < (int) i->addrs.count; k++) {
+	storeAppendPrintf(sentry, " %15s-%3s", inet_ntoa(i->addrs.in_addrs[k]),
+	    i->addrs.bad_mask[k] ? "BAD" : "OK ");
+    }
+    storeAppendPrintf(sentry, "\n");
+}
+
+/* process objects list */
+void
+stat_ipcache_get(StoreEntry * sentry)
+{
+    dlink_node *m;
+    assert(ip_table != NULL);
+    storeAppendPrintf(sentry, "IP Cache Statistics:\n");
+    storeAppendPrintf(sentry, "IPcache Entries: %d\n",
+	memInUse(MEM_IPCACHE_ENTRY));
+    storeAppendPrintf(sentry, "IPcache Requests: %d\n",
+	IpcacheStats.requests);
+    storeAppendPrintf(sentry, "IPcache Hits: %d\n",
+	IpcacheStats.hits);
+    storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n",
+	IpcacheStats.negative_hits);
+    storeAppendPrintf(sentry, "IPcache Misses: %d\n",
+	IpcacheStats.misses);
+    storeAppendPrintf(sentry, "Blocking calls to gethostbyname(): %d\n",
+	IpcacheStats.ghbn_calls);
+    storeAppendPrintf(sentry, "Attempts to release locked entries: %d\n",
+	IpcacheStats.release_locked);
+    storeAppendPrintf(sentry, "\n\n");
+    storeAppendPrintf(sentry, "IP Cache Contents:\n\n");
+    storeAppendPrintf(sentry, " %-29.29s %3s %6s %6s %1s\n",
+	"Hostname",
+	"Flg",
+	"lstref",
+	"TTL",
+	"N");
+    for (m = lru_list.head; m; m = m->next)
+	ipcacheStatPrint((ipcache_entry *)m->data, sentry);
+}
+
+static void
+dummy_handler(const ipcache_addrs * addrsnotused, void *datanotused)
+{
+    return;
+}
+
+void
+ipcacheInvalidate(const char *name)
+{
+    ipcache_entry *i;
+    if ((i = ipcache_get(name)) == NULL)
+	return;
+    i->expires = squid_curtime;
+    /*
+     * NOTE, don't call ipcacheRelease here becuase we might be here due
+     * to a thread started from a callback.
+     */
+}
+
+ipcache_addrs *
+ipcacheCheckNumeric(const char *name)
+{
+    struct in_addr ip;
+    /* check if it's already a IP address in text form. */
+    if (!safe_inet_addr(name, &ip))
+	return NULL;
+    static_addrs.count = 1;
+    static_addrs.cur = 0;
+    static_addrs.in_addrs[0].s_addr = ip.s_addr;
+    static_addrs.bad_mask[0] = FALSE;
+    static_addrs.badcount = 0;
+    return &static_addrs;
+}
+
+static void
+ipcacheLockEntry(ipcache_entry * i)
+{
+    if (i->locks++ == 0) {
+	dlinkDelete(&i->lru, &lru_list);
+	dlinkAdd(i, &i->lru, &lru_list);
+    }
+}
+
+static void
+ipcacheUnlockEntry(ipcache_entry * i)
+{
+    assert(i->locks > 0);
+    i->locks--;
+    if (ipcacheExpiredEntry(i))
+	ipcacheRelease(i);
+}
+
+void
+ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
+{
+    ipcache_entry *i;
+    unsigned char k;
+    assert(name || ia);
+    if (NULL == ia) {
+	if ((i = ipcache_get(name)) == NULL)
+	    return;
+	if (i->flags.negcached)
+	    return;
+	ia = &i->addrs;
+    }
+    for (k = 0; k < ia->count; k++) {
+	if (++ia->cur == ia->count)
+	    ia->cur = 0;
+	if (!ia->bad_mask[ia->cur])
+	    break;
+    }
+    if (k == ia->count) {
+	/* All bad, reset to All good */
+	debug(14, 3) ("ipcacheCycleAddr: Changing ALL %s addrs from BAD to OK\n",
+	    name);
+	for (k = 0; k < ia->count; k++)
+	    ia->bad_mask[k] = 0;
+	ia->badcount = 0;
+	ia->cur = 0;
+    }
+    debug(14, 3) ("ipcacheCycleAddr: %s now at %s\n", name,
+	inet_ntoa(ia->in_addrs[ia->cur]));
+}
+
+/*
+ * Marks the given address as BAD and calls ipcacheCycleAddr to
+ * advance the current pointer to the next OK address.
+ */
+void
+ipcacheMarkBadAddr(const char *name, struct in_addr addr)
+{
+    ipcache_entry *i;
+    ipcache_addrs *ia;
+    int k;
+    if ((i = ipcache_get(name)) == NULL)
+	return;
+    ia = &i->addrs;
+    for (k = 0; k < (int) ia->count; k++) {
+	if (ia->in_addrs[k].s_addr == addr.s_addr)
+	    break;
+    }
+    if (k == (int) ia->count)	/* not found */
+	return;
+    if (!ia->bad_mask[k]) {
+	ia->bad_mask[k] = TRUE;
+	ia->badcount++;
+	debug(14, 2) ("ipcacheMarkBadAddr: %s [%s]\n", name, inet_ntoa(addr));
+    }
+    ipcacheCycleAddr(name, ia);
+}
+
+void
+ipcacheMarkGoodAddr(const char *name, struct in_addr addr)
+{
+    ipcache_entry *i;
+    ipcache_addrs *ia;
+    int k;
+    if ((i = ipcache_get(name)) == NULL)
+	return;
+    ia = &i->addrs;
+    for (k = 0; k < (int) ia->count; k++) {
+	if (ia->in_addrs[k].s_addr == addr.s_addr)
+	    break;
+    }
+    if (k == (int) ia->count)	/* not found */
+	return;
+    if (!ia->bad_mask[k])	/* already OK */
+	return;
+    ia->bad_mask[k] = FALSE;
+    ia->badcount--;
+    debug(14, 2) ("ipcacheMarkGoodAddr: %s [%s]\n", name, inet_ntoa(addr));
+}
+
+static void
+ipcacheFreeEntry(void *data)
+{
+    ipcache_entry *i = (ipcache_entry *)data;
+    safe_free(i->addrs.in_addrs);
+    safe_free(i->addrs.bad_mask);
+    safe_free(i->hash.key);
+    safe_free(i->error_message);
+    memFree(i, MEM_IPCACHE_ENTRY);
+}
+
+void
+ipcacheFreeMemory(void)
+{
+    hashFreeItems(ip_table, ipcacheFreeEntry);
+    hashFreeMemory(ip_table);
+    ip_table = NULL;
+}
+
+/* Recalculate IP cache size upon reconfigure */
+void
+ipcache_restart(void)
+{
+    ipcache_high = (long) (((float) Config.ipcache.size *
+	    (float) Config.ipcache.high) / (float) 100);
+    ipcache_low = (long) (((float) Config.ipcache.size *
+	    (float) Config.ipcache.low) / (float) 100);
+    purge_entries_fromhosts();
+}
+
+/*
+ *  adds a "static" entry from /etc/hosts.  
+ *  returns 0 upon success, 1 if the ip address is invalid
+ */
+int
+ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
+{
+    ipcache_entry *i;
+    struct in_addr ip;
+    if (!safe_inet_addr(ipaddr, &ip)) {
+	if (strchr(ipaddr, ':') && strspn(ipaddr, "0123456789abcdefABCDEF:") == strlen(ipaddr)) {
+	    debug(14, 3) ("ipcacheAddEntryFromHosts: Skipping IPv6 address '%s'\n", ipaddr);
+	} else {
+	    debug(14, 1) ("ipcacheAddEntryFromHosts: Bad IP address '%s'\n",
+		ipaddr);
+	}
+	return 1;
+    }
+    if ((i = ipcache_get(name))) {
+	if (1 == i->flags.fromhosts) {
+	    ipcacheUnlockEntry(i);
+	} else if (i->locks > 0) {
+	    debug(14, 1) ("ipcacheAddEntryFromHosts: can't add static entry"
+		" for locked name '%s'\n", name);
+	    return 1;
+	} else {
+	    ipcacheRelease(i);
+	}
+    }
+    i = ipcacheCreateEntry(name);
+    i->addrs.count = 1;
+    i->addrs.cur = 0;
+    i->addrs.badcount = 0;
+    i->addrs.in_addrs = (struct in_addr *)xcalloc(1, sizeof(struct in_addr));
+    i->addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
+    i->addrs.in_addrs[0].s_addr = ip.s_addr;
+    i->addrs.bad_mask[0] = FALSE;
+    i->flags.fromhosts = 1;
+    ipcacheAddEntry(i);
+    ipcacheLockEntry(i);
+    return 0;
+}
+
+#ifdef SQUID_SNMP
+/*
+ * The function to return the ip cache statistics to via SNMP
+ */
+
+variable_list *
+snmp_netIpFn(variable_list * Var, snint * ErrP)
+{
+    variable_list *Answer = NULL;
+    debug(49, 5) ("snmp_netIpFn: Processing request:\n");
+    snmpDebugOid(5, Var->name, Var->name_length);
+    *ErrP = SNMP_ERR_NOERROR;
+    switch (Var->name[LEN_SQ_NET + 1]) {
+    case IP_ENT:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    memInUse(MEM_IPCACHE_ENTRY),
+	    SMI_GAUGE32);
+	break;
+    case IP_REQ:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    IpcacheStats.requests,
+	    SMI_COUNTER32);
+	break;
+    case IP_HITS:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    IpcacheStats.hits,
+	    SMI_COUNTER32);
+	break;
+    case IP_PENDHIT:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    0,
+	    SMI_GAUGE32);
+	break;
+    case IP_NEGHIT:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    IpcacheStats.negative_hits,
+	    SMI_COUNTER32);
+	break;
+    case IP_MISS:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    IpcacheStats.misses,
+	    SMI_COUNTER32);
+	break;
+    case IP_GHBN:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    IpcacheStats.ghbn_calls,
+	    SMI_COUNTER32);
+	break;
+    case IP_LOC:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    IpcacheStats.release_locked,
+	    SMI_COUNTER32);
+	break;
+    default:
+	*ErrP = SNMP_ERR_NOSUCHNAME;
+	snmp_var_free(Answer);
+	return (NULL);
+    }
+    return Answer;
+}
+
+#endif /*SQUID_SNMP */
--- squid/src/snmp_agent.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,462 +0,0 @@
-
-/*
- * $Id: snmp_agent.c,v 1.9 2001/10/24 09:42:13 squidadm Exp $
- *
- * DEBUG: section 49     SNMP Interface
- * AUTHOR: Kostas Anagnostakis
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-
-#include "squid.h"
-#include "cache_snmp.h"
-
-/************************************************************************
-
- SQUID MIB Implementation
-
- ************************************************************************/
-
-variable_list *
-snmp_sysFn(variable_list * Var, snint * ErrP)
-{
-    variable_list *Answer = NULL;
-    debug(49, 5) ("snmp_sysFn: Processing request:\n");
-    snmpDebugOid(5, Var->name, Var->name_length);
-    *ErrP = SNMP_ERR_NOERROR;
-    switch (Var->name[LEN_SQ_SYS]) {
-    case SYSVMSIZ:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    store_mem_size >> 10,
-	    ASN_INTEGER);
-	break;
-    case SYSSTOR:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    store_swap_size,
-	    ASN_INTEGER);
-	break;
-    case SYS_UPTIME:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    tvSubDsec(squid_start, current_time) * 100,
-	    SMI_TIMETICKS);
-	break;
-    default:
-	*ErrP = SNMP_ERR_NOSUCHNAME;
-	break;
-    }
-    return Answer;
-}
-
-variable_list *
-snmp_confFn(variable_list * Var, snint * ErrP)
-{
-    variable_list *Answer = NULL;
-    const char *cp = NULL;
-    debug(49, 5) ("snmp_confFn: Processing request with magic %d!\n", Var->name[8]);
-    *ErrP = SNMP_ERR_NOERROR;
-    switch (Var->name[LEN_SQ_CONF]) {
-    case CONF_ADMIN:
-	Answer = snmp_var_new(Var->name, Var->name_length);
-	Answer->type = ASN_OCTET_STR;
-	Answer->val_len = strlen(Config.adminEmail);
-	Answer->val.string = (u_char *) xstrdup(Config.adminEmail);
-	break;
-    case CONF_VERSION:
-	Answer = snmp_var_new(Var->name, Var->name_length);
-	Answer->type = ASN_OCTET_STR;
-	Answer->val_len = strlen(appname);
-	Answer->val.string = (u_char *) xstrdup(appname);
-	break;
-    case CONF_VERSION_ID:
-	Answer = snmp_var_new(Var->name, Var->name_length);
-	Answer->type = ASN_OCTET_STR;
-	Answer->val_len = strlen(VERSION);
-	Answer->val.string = (u_char *) xstrdup(VERSION);
-	break;
-    case CONF_STORAGE:
-	switch (Var->name[LEN_SQ_CONF + 1]) {
-	case CONF_ST_MMAXSZ:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) Config.memMaxSize >> 20,
-		ASN_INTEGER);
-	    break;
-	case CONF_ST_SWMAXSZ:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) Config.Swap.maxSize >> 10,
-		ASN_INTEGER);
-	    break;
-	case CONF_ST_SWHIWM:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) Config.Swap.highWaterMark,
-		ASN_INTEGER);
-	    break;
-	case CONF_ST_SWLOWM:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) Config.Swap.lowWaterMark,
-		ASN_INTEGER);
-	    break;
-	default:
-	    *ErrP = SNMP_ERR_NOSUCHNAME;
-	    break;
-	}
-	break;
-    case CONF_LOG_FAC:
-	Answer = snmp_var_new(Var->name, Var->name_length);
-	if (!(cp = Config.debugOptions))
-	    cp = "None";
-	Answer->type = ASN_OCTET_STR;
-	Answer->val_len = strlen(cp);
-	Answer->val.string = (u_char *) xstrdup(cp);
-	break;
-    default:
-	*ErrP = SNMP_ERR_NOSUCHNAME;
-	break;
-    }
-    return Answer;
-}
-
-variable_list *
-snmp_meshPtblFn(variable_list * Var, snint * ErrP)
-{
-    variable_list *Answer = NULL;
-    struct in_addr *laddr;
-    char *cp = NULL;
-    peer *p = NULL;
-    int cnt = 0;
-    debug(49, 5) ("snmp_meshPtblFn: peer %d requested!\n", Var->name[LEN_SQ_MESH + 3]);
-    *ErrP = SNMP_ERR_NOERROR;
-    laddr = oid2addr(&Var->name[LEN_SQ_MESH + 3]);
-    for (p = Config.peers; p != NULL; p = p->next, cnt++)
-	if (p->in_addr.sin_addr.s_addr == laddr->s_addr)
-	    break;
-    if (p == NULL) {
-	*ErrP = SNMP_ERR_NOSUCHNAME;
-	return NULL;
-    }
-    switch (Var->name[LEN_SQ_MESH + 2]) {
-    case MESH_PTBL_NAME:
-	cp = p->host;
-	Answer = snmp_var_new(Var->name, Var->name_length);
-	Answer->type = ASN_OCTET_STR;
-	Answer->val_len = strlen(cp);
-	Answer->val.string = (u_char *) xstrdup(cp);
-	break;
-    case MESH_PTBL_IP:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) p->in_addr.sin_addr.s_addr,
-	    SMI_IPADDRESS);
-	break;
-    case MESH_PTBL_HTTP:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) p->http_port,
-	    ASN_INTEGER);
-	break;
-    case MESH_PTBL_ICP:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) p->icp.port,
-	    ASN_INTEGER);
-	break;
-    case MESH_PTBL_TYPE:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) p->type,
-	    ASN_INTEGER);
-	break;
-    case MESH_PTBL_STATE:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) neighborUp(p),
-	    ASN_INTEGER);
-	break;
-    case MESH_PTBL_SENT:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    p->stats.pings_sent,
-	    ASN_INTEGER);
-	break;
-    case MESH_PTBL_PACKED:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    p->stats.pings_acked,
-	    ASN_INTEGER);
-	break;
-    case MESH_PTBL_FETCHES:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    p->stats.fetches,
-	    SMI_COUNTER32);
-	break;
-    case MESH_PTBL_RTT:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    p->stats.rtt,
-	    ASN_INTEGER);
-	break;
-    case MESH_PTBL_IGN:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    p->stats.ignored_replies,
-	    SMI_COUNTER32);
-	break;
-    case MESH_PTBL_KEEPAL_S:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    p->stats.n_keepalives_sent,
-	    SMI_COUNTER32);
-	break;
-    case MESH_PTBL_KEEPAL_R:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    p->stats.n_keepalives_recv,
-	    SMI_COUNTER32);
-	break;
-    default:
-	*ErrP = SNMP_ERR_NOSUCHNAME;
-	break;
-    }
-    return Answer;
-}
-
-variable_list *
-snmp_prfSysFn(variable_list * Var, snint * ErrP)
-{
-    variable_list *Answer = NULL;
-    static struct rusage rusage;
-    debug(49, 5) ("snmp_prfSysFn: Processing request with magic %d!\n", Var->name[LEN_SQ_PRF + 1]);
-    *ErrP = SNMP_ERR_NOERROR;
-    switch (Var->name[LEN_SQ_PRF + 1]) {
-    case PERF_SYS_PF:
-	squid_getrusage(&rusage);
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    rusage_pagefaults(&rusage),
-	    SMI_COUNTER32);
-	break;
-    case PERF_SYS_NUMR:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    IOStats.Http.reads,
-	    SMI_COUNTER32);
-	break;
-    case PERF_SYS_MEMUSAGE:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) statMemoryAccounted() >> 10,
-	    ASN_INTEGER);
-	break;
-    case PERF_SYS_CPUTIME:
-	squid_getrusage(&rusage);
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) rusage_cputime(&rusage),
-	    ASN_INTEGER);
-	break;
-    case PERF_SYS_CPUUSAGE:
-	squid_getrusage(&rusage);
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) dpercent(rusage_cputime(&rusage), tvSubDsec(squid_start, current_time)),
-	    ASN_INTEGER);
-	break;
-    case PERF_SYS_MAXRESSZ:
-	squid_getrusage(&rusage);
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) rusage_maxrss(&rusage),
-	    ASN_INTEGER);
-	break;
-    case PERF_SYS_CURLRUEXP:
-	/* No global LRU info anymore */
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    0,
-	    SMI_TIMETICKS);
-	break;
-    case PERF_SYS_CURUNLREQ:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) statCounter.unlink.requests,
-	    SMI_COUNTER32);
-	break;
-    case PERF_SYS_CURUNUSED_FD:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) Squid_MaxFD - Number_FD,
-	    SMI_GAUGE32);
-	break;
-    case PERF_SYS_CURRESERVED_FD:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) RESERVED_FD,
-	    SMI_GAUGE32);
-	break;
-    case PERF_SYS_NUMOBJCNT:
-	Answer = snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) memInUse(MEM_STOREENTRY),
-	    SMI_COUNTER32);
-	break;
-    default:
-	*ErrP = SNMP_ERR_NOSUCHNAME;
-	break;
-    }
-    return Answer;
-}
-
-variable_list *
-snmp_prfProtoFn(variable_list * Var, snint * ErrP)
-{
-    variable_list *Answer = NULL;
-    static StatCounters *f = NULL;
-    static StatCounters *l = NULL;
-    double x;
-    int minutes;
-    debug(49, 5) ("snmp_prfProtoFn: Processing request with magic %d!\n", Var->name[LEN_SQ_PRF]);
-    *ErrP = SNMP_ERR_NOERROR;
-    switch (Var->name[LEN_SQ_PRF + 1]) {
-    case PERF_PROTOSTAT_AGGR:	/* cacheProtoAggregateStats */
-	switch (Var->name[LEN_SQ_PRF + 2]) {
-	case PERF_PROTOSTAT_AGGR_HTTP_REQ:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.client_http.requests,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_HTTP_HITS:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.client_http.hits,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_HTTP_ERRORS:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.client_http.errors,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.client_http.kbytes_in.kb,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.client_http.kbytes_out.kb,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_ICP_S:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.icp.pkts_sent,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_ICP_R:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.icp.pkts_recv,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_ICP_SKB:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.icp.kbytes_sent.kb,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_ICP_RKB:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.icp.kbytes_recv.kb,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_REQ:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.server.all.requests,
-		SMI_INTEGER);
-	    break;
-	case PERF_PROTOSTAT_AGGR_ERRORS:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.server.all.errors,
-		SMI_INTEGER);
-	    break;
-	case PERF_PROTOSTAT_AGGR_KBYTES_IN:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.server.all.kbytes_in.kb,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_KBYTES_OUT:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.server.all.kbytes_out.kb,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_CURSWAP:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) store_swap_size,
-		SMI_COUNTER32);
-	    break;
-	case PERF_PROTOSTAT_AGGR_CLIENTS:
-	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
-		(snint) statCounter.client_http.clients,
-		SMI_COUNTER32);
-	    break;
-	default:
-	    *ErrP = SNMP_ERR_NOSUCHNAME;
-	    break;
-	}
-	return Answer;
-    case PERF_PROTOSTAT_MEDIAN:
-	if (Var->name_length == LEN_SQ_PRF + 5)
-	    minutes = Var->name[LEN_SQ_PRF + 4];
-	else
-	    break;
-	if ((minutes < 1) || (minutes > 60))
-	    break;
-	f = snmpStatGet(0);
-	l = snmpStatGet(minutes);
-	debug(49, 8) ("median: min= %d, %d l= %p , f = %p\n", minutes,
-	    Var->name[LEN_SQ_PRF + 3], l, f);
-	debug(49, 8) ("median: l= %p , f = %p\n", l, f);
-	switch (Var->name[LEN_SQ_PRF + 3]) {
-	case PERF_MEDIAN_TIME:
-	    x = minutes;
-	    break;
-	case PERF_MEDIAN_HTTP_ALL:
-	    x = statHistDeltaMedian(&l->client_http.all_svc_time,
-		&f->client_http.all_svc_time);
-	    break;
-	case PERF_MEDIAN_HTTP_MISS:
-	    x = statHistDeltaMedian(&l->client_http.miss_svc_time,
-		&f->client_http.miss_svc_time);
-	    break;
-	case PERF_MEDIAN_HTTP_NM:
-	    x = statHistDeltaMedian(&l->client_http.nm_svc_time,
-		&f->client_http.nm_svc_time);
-	    break;
-	case PERF_MEDIAN_HTTP_HIT:
-	    x = statHistDeltaMedian(&l->client_http.hit_svc_time,
-		&f->client_http.hit_svc_time);
-	    break;
-	case PERF_MEDIAN_ICP_QUERY:
-	    x = statHistDeltaMedian(&l->icp.query_svc_time, &f->icp.query_svc_time);
-	    break;
-	case PERF_MEDIAN_ICP_REPLY:
-	    x = statHistDeltaMedian(&l->icp.reply_svc_time, &f->icp.reply_svc_time);
-	    break;
-	case PERF_MEDIAN_DNS:
-	    x = statHistDeltaMedian(&l->dns.svc_time, &f->dns.svc_time);
-	    break;
-	case PERF_MEDIAN_RHR:
-	    x = statRequestHitRatio(minutes);
-	    break;
-	case PERF_MEDIAN_BHR:
-	    x = statByteHitRatio(minutes);
-	    break;
-	default:
-	    *ErrP = SNMP_ERR_NOSUCHNAME;
-	    return NULL;
-	}
-	return snmp_var_new_integer(Var->name, Var->name_length,
-	    (snint) x,
-	    SMI_INTEGER);
-    }
-    *ErrP = SNMP_ERR_NOSUCHNAME;
-    return NULL;
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/snmp_agent.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,462 @@
+
+/*
+ * $Id: snmp_agent.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 49     SNMP Interface
+ * AUTHOR: Kostas Anagnostakis
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+
+#include "squid.h"
+#include "cache_snmp.h"
+
+/************************************************************************
+
+ SQUID MIB Implementation
+
+ ************************************************************************/
+
+variable_list *
+snmp_sysFn(variable_list * Var, snint * ErrP)
+{
+    variable_list *Answer = NULL;
+    debug(49, 5) ("snmp_sysFn: Processing request:\n");
+    snmpDebugOid(5, Var->name, Var->name_length);
+    *ErrP = SNMP_ERR_NOERROR;
+    switch (Var->name[LEN_SQ_SYS]) {
+    case SYSVMSIZ:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    store_mem_size >> 10,
+	    ASN_INTEGER);
+	break;
+    case SYSSTOR:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    store_swap_size,
+	    ASN_INTEGER);
+	break;
+    case SYS_UPTIME:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    tvSubDsec(squid_start, current_time) * 100,
+	    SMI_TIMETICKS);
+	break;
+    default:
+	*ErrP = SNMP_ERR_NOSUCHNAME;
+	break;
+    }
+    return Answer;
+}
+
+variable_list *
+snmp_confFn(variable_list * Var, snint * ErrP)
+{
+    variable_list *Answer = NULL;
+    const char *cp = NULL;
+    debug(49, 5) ("snmp_confFn: Processing request with magic %d!\n", Var->name[8]);
+    *ErrP = SNMP_ERR_NOERROR;
+    switch (Var->name[LEN_SQ_CONF]) {
+    case CONF_ADMIN:
+	Answer = snmp_var_new(Var->name, Var->name_length);
+	Answer->type = ASN_OCTET_STR;
+	Answer->val_len = strlen(Config.adminEmail);
+	Answer->val.string = (u_char *) xstrdup(Config.adminEmail);
+	break;
+    case CONF_VERSION:
+	Answer = snmp_var_new(Var->name, Var->name_length);
+	Answer->type = ASN_OCTET_STR;
+	Answer->val_len = strlen(appname);
+	Answer->val.string = (u_char *) xstrdup(appname);
+	break;
+    case CONF_VERSION_ID:
+	Answer = snmp_var_new(Var->name, Var->name_length);
+	Answer->type = ASN_OCTET_STR;
+	Answer->val_len = strlen(VERSION);
+	Answer->val.string = (u_char *) xstrdup(VERSION);
+	break;
+    case CONF_STORAGE:
+	switch (Var->name[LEN_SQ_CONF + 1]) {
+	case CONF_ST_MMAXSZ:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) Config.memMaxSize >> 20,
+		ASN_INTEGER);
+	    break;
+	case CONF_ST_SWMAXSZ:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) Config.Swap.maxSize >> 10,
+		ASN_INTEGER);
+	    break;
+	case CONF_ST_SWHIWM:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) Config.Swap.highWaterMark,
+		ASN_INTEGER);
+	    break;
+	case CONF_ST_SWLOWM:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) Config.Swap.lowWaterMark,
+		ASN_INTEGER);
+	    break;
+	default:
+	    *ErrP = SNMP_ERR_NOSUCHNAME;
+	    break;
+	}
+	break;
+    case CONF_LOG_FAC:
+	Answer = snmp_var_new(Var->name, Var->name_length);
+	if (!(cp = Config.debugOptions))
+	    cp = "None";
+	Answer->type = ASN_OCTET_STR;
+	Answer->val_len = strlen(cp);
+	Answer->val.string = (u_char *) xstrdup(cp);
+	break;
+    default:
+	*ErrP = SNMP_ERR_NOSUCHNAME;
+	break;
+    }
+    return Answer;
+}
+
+variable_list *
+snmp_meshPtblFn(variable_list * Var, snint * ErrP)
+{
+    variable_list *Answer = NULL;
+    struct in_addr *laddr;
+    char *cp = NULL;
+    peer *p = NULL;
+    int cnt = 0;
+    debug(49, 5) ("snmp_meshPtblFn: peer %d requested!\n", Var->name[LEN_SQ_MESH + 3]);
+    *ErrP = SNMP_ERR_NOERROR;
+    laddr = oid2addr(&Var->name[LEN_SQ_MESH + 3]);
+    for (p = Config.peers; p != NULL; p = p->next, cnt++)
+	if (p->in_addr.sin_addr.s_addr == laddr->s_addr)
+	    break;
+    if (p == NULL) {
+	*ErrP = SNMP_ERR_NOSUCHNAME;
+	return NULL;
+    }
+    switch (Var->name[LEN_SQ_MESH + 2]) {
+    case MESH_PTBL_NAME:
+	cp = p->host;
+	Answer = snmp_var_new(Var->name, Var->name_length);
+	Answer->type = ASN_OCTET_STR;
+	Answer->val_len = strlen(cp);
+	Answer->val.string = (u_char *) xstrdup(cp);
+	break;
+    case MESH_PTBL_IP:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) p->in_addr.sin_addr.s_addr,
+	    SMI_IPADDRESS);
+	break;
+    case MESH_PTBL_HTTP:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) p->http_port,
+	    ASN_INTEGER);
+	break;
+    case MESH_PTBL_ICP:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) p->icp.port,
+	    ASN_INTEGER);
+	break;
+    case MESH_PTBL_TYPE:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) p->type,
+	    ASN_INTEGER);
+	break;
+    case MESH_PTBL_STATE:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) neighborUp(p),
+	    ASN_INTEGER);
+	break;
+    case MESH_PTBL_SENT:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    p->stats.pings_sent,
+	    ASN_INTEGER);
+	break;
+    case MESH_PTBL_PACKED:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    p->stats.pings_acked,
+	    ASN_INTEGER);
+	break;
+    case MESH_PTBL_FETCHES:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    p->stats.fetches,
+	    SMI_COUNTER32);
+	break;
+    case MESH_PTBL_RTT:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    p->stats.rtt,
+	    ASN_INTEGER);
+	break;
+    case MESH_PTBL_IGN:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    p->stats.ignored_replies,
+	    SMI_COUNTER32);
+	break;
+    case MESH_PTBL_KEEPAL_S:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    p->stats.n_keepalives_sent,
+	    SMI_COUNTER32);
+	break;
+    case MESH_PTBL_KEEPAL_R:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    p->stats.n_keepalives_recv,
+	    SMI_COUNTER32);
+	break;
+    default:
+	*ErrP = SNMP_ERR_NOSUCHNAME;
+	break;
+    }
+    return Answer;
+}
+
+variable_list *
+snmp_prfSysFn(variable_list * Var, snint * ErrP)
+{
+    variable_list *Answer = NULL;
+    static struct rusage rusage;
+    debug(49, 5) ("snmp_prfSysFn: Processing request with magic %d!\n", Var->name[LEN_SQ_PRF + 1]);
+    *ErrP = SNMP_ERR_NOERROR;
+    switch (Var->name[LEN_SQ_PRF + 1]) {
+    case PERF_SYS_PF:
+	squid_getrusage(&rusage);
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    rusage_pagefaults(&rusage),
+	    SMI_COUNTER32);
+	break;
+    case PERF_SYS_NUMR:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    IOStats.Http.reads,
+	    SMI_COUNTER32);
+	break;
+    case PERF_SYS_MEMUSAGE:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) statMemoryAccounted() >> 10,
+	    ASN_INTEGER);
+	break;
+    case PERF_SYS_CPUTIME:
+	squid_getrusage(&rusage);
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) rusage_cputime(&rusage),
+	    ASN_INTEGER);
+	break;
+    case PERF_SYS_CPUUSAGE:
+	squid_getrusage(&rusage);
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) dpercent(rusage_cputime(&rusage), tvSubDsec(squid_start, current_time)),
+	    ASN_INTEGER);
+	break;
+    case PERF_SYS_MAXRESSZ:
+	squid_getrusage(&rusage);
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) rusage_maxrss(&rusage),
+	    ASN_INTEGER);
+	break;
+    case PERF_SYS_CURLRUEXP:
+	/* No global LRU info anymore */
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    0,
+	    SMI_TIMETICKS);
+	break;
+    case PERF_SYS_CURUNLREQ:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) statCounter.unlink.requests,
+	    SMI_COUNTER32);
+	break;
+    case PERF_SYS_CURUNUSED_FD:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) Squid_MaxFD - Number_FD,
+	    SMI_GAUGE32);
+	break;
+    case PERF_SYS_CURRESERVED_FD:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) RESERVED_FD,
+	    SMI_GAUGE32);
+	break;
+    case PERF_SYS_NUMOBJCNT:
+	Answer = snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) memInUse(MEM_STOREENTRY),
+	    SMI_COUNTER32);
+	break;
+    default:
+	*ErrP = SNMP_ERR_NOSUCHNAME;
+	break;
+    }
+    return Answer;
+}
+
+variable_list *
+snmp_prfProtoFn(variable_list * Var, snint * ErrP)
+{
+    variable_list *Answer = NULL;
+    static StatCounters *f = NULL;
+    static StatCounters *l = NULL;
+    double x;
+    int minutes;
+    debug(49, 5) ("snmp_prfProtoFn: Processing request with magic %d!\n", Var->name[LEN_SQ_PRF]);
+    *ErrP = SNMP_ERR_NOERROR;
+    switch (Var->name[LEN_SQ_PRF + 1]) {
+    case PERF_PROTOSTAT_AGGR:	/* cacheProtoAggregateStats */
+	switch (Var->name[LEN_SQ_PRF + 2]) {
+	case PERF_PROTOSTAT_AGGR_HTTP_REQ:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.client_http.requests,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_HTTP_HITS:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.client_http.hits,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_HTTP_ERRORS:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.client_http.errors,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.client_http.kbytes_in.kb,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.client_http.kbytes_out.kb,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_ICP_S:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.icp.pkts_sent,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_ICP_R:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.icp.pkts_recv,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_ICP_SKB:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.icp.kbytes_sent.kb,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_ICP_RKB:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.icp.kbytes_recv.kb,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_REQ:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.server.all.requests,
+		SMI_INTEGER);
+	    break;
+	case PERF_PROTOSTAT_AGGR_ERRORS:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.server.all.errors,
+		SMI_INTEGER);
+	    break;
+	case PERF_PROTOSTAT_AGGR_KBYTES_IN:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.server.all.kbytes_in.kb,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_KBYTES_OUT:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.server.all.kbytes_out.kb,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_CURSWAP:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) store_swap_size,
+		SMI_COUNTER32);
+	    break;
+	case PERF_PROTOSTAT_AGGR_CLIENTS:
+	    Answer = snmp_var_new_integer(Var->name, Var->name_length,
+		(snint) statCounter.client_http.clients,
+		SMI_COUNTER32);
+	    break;
+	default:
+	    *ErrP = SNMP_ERR_NOSUCHNAME;
+	    break;
+	}
+	return Answer;
+    case PERF_PROTOSTAT_MEDIAN:
+	if (Var->name_length == LEN_SQ_PRF + 5)
+	    minutes = Var->name[LEN_SQ_PRF + 4];
+	else
+	    break;
+	if ((minutes < 1) || (minutes > 60))
+	    break;
+	f = snmpStatGet(0);
+	l = snmpStatGet(minutes);
+	debug(49, 8) ("median: min= %d, %d l= %p , f = %p\n", minutes,
+	    Var->name[LEN_SQ_PRF + 3], l, f);
+	debug(49, 8) ("median: l= %p , f = %p\n", l, f);
+	switch (Var->name[LEN_SQ_PRF + 3]) {
+	case PERF_MEDIAN_TIME:
+	    x = minutes;
+	    break;
+	case PERF_MEDIAN_HTTP_ALL:
+	    x = statHistDeltaMedian(&l->client_http.all_svc_time,
+		&f->client_http.all_svc_time);
+	    break;
+	case PERF_MEDIAN_HTTP_MISS:
+	    x = statHistDeltaMedian(&l->client_http.miss_svc_time,
+		&f->client_http.miss_svc_time);
+	    break;
+	case PERF_MEDIAN_HTTP_NM:
+	    x = statHistDeltaMedian(&l->client_http.nm_svc_time,
+		&f->client_http.nm_svc_time);
+	    break;
+	case PERF_MEDIAN_HTTP_HIT:
+	    x = statHistDeltaMedian(&l->client_http.hit_svc_time,
+		&f->client_http.hit_svc_time);
+	    break;
+	case PERF_MEDIAN_ICP_QUERY:
+	    x = statHistDeltaMedian(&l->icp.query_svc_time, &f->icp.query_svc_time);
+	    break;
+	case PERF_MEDIAN_ICP_REPLY:
+	    x = statHistDeltaMedian(&l->icp.reply_svc_time, &f->icp.reply_svc_time);
+	    break;
+	case PERF_MEDIAN_DNS:
+	    x = statHistDeltaMedian(&l->dns.svc_time, &f->dns.svc_time);
+	    break;
+	case PERF_MEDIAN_RHR:
+	    x = statRequestHitRatio(minutes);
+	    break;
+	case PERF_MEDIAN_BHR:
+	    x = statByteHitRatio(minutes);
+	    break;
+	default:
+	    *ErrP = SNMP_ERR_NOSUCHNAME;
+	    return NULL;
+	}
+	return snmp_var_new_integer(Var->name, Var->name_length,
+	    (snint) x,
+	    SMI_INTEGER);
+    }
+    *ErrP = SNMP_ERR_NOSUCHNAME;
+    return NULL;
+}
--- squid/src/store_swapmeta.c	Wed Feb 14 01:07:37 2007
+++ /dev/null	Wed Feb 14 01:07:22 2007
@@ -1,160 +0,0 @@
-
-/*
- * $Id: store_swapmeta.c,v 1.8.44.1 2002/10/04 07:07:29 rbcollins Exp $
- *
- * DEBUG: section 20    Storage Manager Swapfile Metadata
- * AUTHOR: Kostas Anagnostakis
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "Store.h"
-
-static tlv **
-storeSwapTLVAdd(int type, const void *ptr, size_t len, tlv ** tail)
-{
-    tlv *t = memAllocate(MEM_TLV);
-    t->type = (char) type;
-    t->length = (int) len;
-    t->value = xmalloc(len);
-    xmemcpy(t->value, ptr, len);
-    *tail = t;
-    return &t->next;		/* return new tail pointer */
-}
-
-void
-storeSwapTLVFree(tlv * n)
-{
-    tlv *t;
-    while ((t = n) != NULL) {
-	n = t->next;
-	xfree(t->value);
-	memFree(t, MEM_TLV);
-    }
-}
-
-/*
- * Build a TLV list for a StoreEntry
- */
-tlv *
-storeSwapMetaBuild(StoreEntry * e)
-{
-    tlv *TLV = NULL;		/* we'll return this */
-    tlv **T = &TLV;
-    const char *url;
-    const char *vary;
-    assert(e->mem_obj != NULL);
-    assert(e->swap_status == SWAPOUT_WRITING);
-    url = storeUrl(e);
-    debug(20, 3) ("storeSwapMetaBuild: %s\n", url);
-    T = storeSwapTLVAdd(STORE_META_KEY, e->hash.key, MD5_DIGEST_CHARS, T);
-    T = storeSwapTLVAdd(STORE_META_STD, &e->timestamp, STORE_HDR_METASIZE, T);
-    T = storeSwapTLVAdd(STORE_META_URL, url, strlen(url) + 1, T);
-    vary = e->mem_obj->vary_headers;
-    if (vary)
-	T = storeSwapTLVAdd(STORE_META_VARY_HEADERS, vary, strlen(vary) + 1, T);
-    return TLV;
-}
-
-char *
-storeSwapMetaPack(tlv * tlv_list, int *length)
-{
-    int buflen = 0;
-    tlv *t;
-    off_t j = 0;
-    char *buf;
-    assert(length != NULL);
-    buflen++;			/* STORE_META_OK */
-    buflen += sizeof(int);	/* size of header to follow */
-    for (t = tlv_list; t; t = t->next)
-	buflen += sizeof(char) + sizeof(int) + t->length;
-    buflen++;			/* STORE_META_END */
-    buf = xmalloc(buflen);
-    buf[j++] = (char) STORE_META_OK;
-    xmemcpy(&buf[j], &buflen, sizeof(int));
-    j += sizeof(int);
-    for (t = tlv_list; t; t = t->next) {
-	buf[j++] = (char) t->type;
-	xmemcpy(&buf[j], &t->length, sizeof(int));
-	j += sizeof(int);
-	xmemcpy(&buf[j], t->value, t->length);
-	j += t->length;
-    }
-    buf[j++] = (char) STORE_META_END;
-    assert((int) j == buflen);
-    *length = buflen;
-    return buf;
-}
-
-tlv *
-storeSwapMetaUnpack(const char *buf, int *hdr_len)
-{
-    tlv *TLV;			/* we'll return this */
-    tlv **T = &TLV;
-    char type;
-    int length;
-    int buflen;
-    off_t j = 0;
-    assert(buf != NULL);
-    assert(hdr_len != NULL);
-    if (buf[j++] != (char) STORE_META_OK)
-	return NULL;
-    xmemcpy(&buflen, &buf[j], sizeof(int));
-    j += sizeof(int);
-    /*
-     * sanity check on 'buflen' value.  It should be at least big
-     * enough to hold one type and one length.
-     */
-    if (buflen <= (sizeof(char) + sizeof(int)))
-	    return NULL;
-    while (buflen - j > (sizeof(char) + sizeof(int))) {
-	type = buf[j++];
-	/* VOID is reserved, but allow some slack for new types.. */
-	if (type <= STORE_META_VOID || type > STORE_META_END + 10) {
-	    debug(20, 0) ("storeSwapMetaUnpack: bad type (%d)!\n", type);
-	    break;
-	}
-	xmemcpy(&length, &buf[j], sizeof(int));
-	if (length < 0 || length > (1 << 16)) {
-	    debug(20, 0) ("storeSwapMetaUnpack: insane length (%d)!\n", length);
-	    break;
-	}
-	j += sizeof(int);
-	if (j + length > buflen) {
-	    debug(20, 0) ("storeSwapMetaUnpack: overflow!\n");
-	    debug(20, 0) ("\ttype=%d, length=%d, buflen=%d, offset=%d\n",
-		type, length, buflen, (int) j);
-	    break;
-	}
-	T = storeSwapTLVAdd(type, &buf[j], (size_t) length, T);
-	j += length;
-    }
-    *hdr_len = buflen;
-    return TLV;
-}
--- /dev/null	Wed Feb 14 01:07:22 2007
+++ squid/src/store_swapmeta.cc	Wed Feb 14 01:07:37 2007
@@ -0,0 +1,160 @@
+
+/*
+ * $Id: store_swapmeta.cc,v 1.1.2.1 2002/10/09 00:23:16 rbcollins Exp $
+ *
+ * DEBUG: section 20    Storage Manager Swapfile Metadata
+ * AUTHOR: Kostas Anagnostakis
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "Store.h"
+
+static tlv **
+storeSwapTLVAdd(int type, const void *ptr, size_t len, tlv ** tail)
+{
+    tlv *t = (tlv *)memAllocate(MEM_TLV);
+    t->type = (char) type;
+    t->length = (int) len;
+    t->value = xmalloc(len);
+    xmemcpy(t->value, ptr, len);
+    *tail = t;
+    return &t->next;		/* return new tail pointer */
+}
+
+void
+storeSwapTLVFree(tlv * n)
+{
+    tlv *t;
+    while ((t = n) != NULL) {
+	n = t->next;
+	xfree(t->value);
+	memFree(t, MEM_TLV);
+    }
+}
+
+/*
+ * Build a TLV list for a StoreEntry
+ */
+tlv *
+storeSwapMetaBuild(StoreEntry * e)
+{
+    tlv *TLV = NULL;		/* we'll return this */
+    tlv **T = &TLV;
+    const char *url;
+    const char *vary;
+    assert(e->mem_obj != NULL);
+    assert(e->swap_status == SWAPOUT_WRITING);
+    url = storeUrl(e);
+    debug(20, 3) ("storeSwapMetaBuild: %s\n", url);
+    T = storeSwapTLVAdd(STORE_META_KEY, e->hash.key, MD5_DIGEST_CHARS, T);
+    T = storeSwapTLVAdd(STORE_META_STD, &e->timestamp, STORE_HDR_METASIZE, T);
+    T = storeSwapTLVAdd(STORE_META_URL, url, strlen(url) + 1, T);
+    vary = e->mem_obj->vary_headers;
+    if (vary)
+	T = storeSwapTLVAdd(STORE_META_VARY_HEADERS, vary, strlen(vary) + 1, T);
+    return TLV;
+}
+
+char *
+storeSwapMetaPack(tlv * tlv_list, int *length)
+{
+    int buflen = 0;
+    tlv *t;
+    off_t j = 0;
+    char *buf;
+    assert(length != NULL);
+    buflen++;			/* STORE_META_OK */
+    buflen += sizeof(int);	/* size of header to follow */
+    for (t = tlv_list; t; t = t->next)
+	buflen += sizeof(char) + sizeof(int) + t->length;
+    buflen++;			/* STORE_META_END */
+    buf = (char *)xmalloc(buflen);
+    buf[j++] = (char) STORE_META_OK;
+    xmemcpy(&buf[j], &buflen, sizeof(int));
+    j += sizeof(int);
+    for (t = tlv_list; t; t = t->next) {
+	buf[j++] = (char) t->type;
+	xmemcpy(&buf[j], &t->length, sizeof(int));
+	j += sizeof(int);
+	xmemcpy(&buf[j], t->value, t->length);
+	j += t->length;
+    }
+    buf[j++] = (char) STORE_META_END;
+    assert((int) j == buflen);
+    *length = buflen;
+    return buf;
+}
+
+tlv *
+storeSwapMetaUnpack(const char *buf, int *hdr_len)
+{
+    tlv *TLV;			/* we'll return this */
+    tlv **T = &TLV;
+    char type;
+    int length;
+    int buflen;
+    off_t j = 0;
+    assert(buf != NULL);
+    assert(hdr_len != NULL);
+    if (buf[j++] != (char) STORE_META_OK)
+	return NULL;
+    xmemcpy(&buflen, &buf[j], sizeof(int));
+    j += sizeof(int);
+    /*
+     * sanity check on 'buflen' value.  It should be at least big
+     * enough to hold one type and one length.
+     */
+    if (buflen <= (off_t) (sizeof(char) + sizeof(int)))
+	    return NULL;
+    while (buflen - j > (off_t)(sizeof(char) + sizeof(int))) {
+	type = buf[j++];
+	/* VOID is reserved, but allow some slack for new types.. */
+	if (type <= STORE_META_VOID || type > STORE_META_END + 10) {
+	    debug(20, 0) ("storeSwapMetaUnpack: bad type (%d)!\n", type);
+	    break;
+	}
+	xmemcpy(&length, &buf[j], sizeof(int));
+	if (length < 0 || length > (1 << 16)) {
+	    debug(20, 0) ("storeSwapMetaUnpack: insane length (%d)!\n", length);
+	    break;
+	}
+	j += sizeof(int);
+	if (j + length > buflen) {
+	    debug(20, 0) ("storeSwapMetaUnpack: overflow!\n");
+	    debug(20, 0) ("\ttype=%d, length=%d, buflen=%d, offset=%d\n",
+		type, length, buflen, (int) j);
+	    break;
+	}
+	T = storeSwapTLVAdd(type, &buf[j], (size_t) length, T);
+	j += length;
+    }
+    *hdr_len = buflen;
+    return TLV;
+}
