diff -urN thttpd-2.21/Makefile.in thttpd-2.21-mnx/Makefile.in
--- thttpd-2.21/Makefile.in	Thu Mar 29 21:36:21 2001
+++ thttpd-2.21-mnx/Makefile.in	Thu Nov 22 16:02:15 2001
@@ -39,19 +39,19 @@
 # CONFIGURE: The group that the web directory belongs to.  This is so that
 # the makeweb program can be installed set-group-id to that group, and make
 # subdirectories.  If you're not going to use makeweb, ignore this.
-WEBGROUP =	www
+WEBGROUP =	www-data
 
 # CONFIGURE: Directory for CGI executables.
 CGIBINDIR =	$(WEBDIR)/cgi-bin
 
 # You shouldn't need to edit anything below here.
 
-CC =		@CC@
+CC =		@CC@ -Wall -g
 CCOPT =		@V_CCOPT@
 DEFS =		@DEFS@
 INCLS =		-I.
 CFLAGS =	$(CCOPT) $(DEFS) $(INCLS)
-LDFLAGS =	@LDFLAGS@
+LDFLAGS =	@LDFLAGS@ -lmysqlclient
 LIBS =		@LIBS@
 NETLIBS =	@V_NETLIBS@
 INSTALL =	@INSTALL@
@@ -62,7 +62,7 @@
 	@rm -f $@
 	$(CC) $(CFLAGS) -c $*.c
 
-SRC =		thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c syslog.c
+SRC =		thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c syslog.c vhost.c
 
 OBJ =		$(SRC:.c=.o) @LIBOBJS@
 
@@ -80,6 +80,7 @@
 thttpd: $(OBJ)
 	@rm -f $@
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(NETLIBS)
+        
 
 libhttpd.o:		mime_encodings.h
 mime_encodings.h:	mime_encodings.txt
@@ -163,11 +164,12 @@
 	  rm -rf $$name ; \
 	  gzip $$name.tar
 
-thttpd.o:	config.h version.h libhttpd.h fdwatch.h mmc.h timers.h match.h
+thttpd.o:	config.h version.h libhttpd.h fdwatch.h mmc.h timers.h match.h vhostconf.h machineconf.h
 libhttpd.o:	config.h version.h libhttpd.h mime_encodings.h mime_types.h \
-		mmc.h timers.h match.h tdate_parse.h
+		mmc.h timers.h match.h tdate_parse.h vhostconf.h machineconf.h
 fdwatch.o:	fdwatch.h
 mmc.o:		mmc.h
 timers.o:	timers.h
 match.o:	match.h
 tdate_parse.o:	tdate_parse.h
+vhost.o:	vhostconf.h machineconf.h
diff -urN thttpd-2.21/config.h thttpd-2.21-mnx/config.h
--- thttpd-2.21/config.h	Tue Apr 10 00:57:36 2001
+++ thttpd-2.21-mnx/config.h	Wed Nov 14 13:20:43 2001
@@ -183,9 +183,7 @@
 ** having to give the -v command line flag.  You can still disable it at
 ** runtime with the -nov flag.
 */
-#ifdef notdef
 #define ALWAYS_VHOST
-#endif
 
 /* CONFIGURE: If you're using the vhost feature and you have a LOT of
 ** virtual hostnames (like, hundreds or thousands), you will want to
@@ -214,7 +212,36 @@
 #define VHOST_DIRLEVELS 2
 #define VHOST_DIRLEVELS 3
 #endif
+/* CONFIGURE:
+** You can use the mapping between vhost and path from a mysql table, just define
+** it here:
+*/
+
+#define VHOST_MYSQL
+#ifdef VHOST_MYSQL
+
+/* CONFIGURE:
+** Interval for reloading the table from the mysql db
+*/
+
+#define VHOST_RELOAD_TIME 600
 
+
+/* CONFIGURE:
+** Define special logging of requests through unix domain sockets
+*/
+
+#define ADVCOUNTER
+
+/* CONFIGURE:
+** Define custom error 404 file name
+*/
+#define ERR404FILENAME "/banners/404.html"
+/* CONFIGURE:
+** Define redirection based on referer domain
+*/
+#define REFERER_REDIR
+#endif
 /* CONFIGURE: Define this if you want to always use a global passwd file,
 ** without having to give the -P command line flag.  You can still disable
 ** it at runtime with the -noP flag.
@@ -227,7 +254,7 @@
 ** initializing.  If this user (or the one specified by the -u flag) does
 ** not exist, the program will refuse to run.
 */
-#define DEFAULT_USER "nobody"
+#define DEFAULT_USER "www-data"
 
 /* CONFIGURE: When started as root, the program can automatically chdir()
 ** to the home directory of the user specified by -u or DEFAULT_USER.
@@ -316,7 +343,7 @@
 /* CONFIGURE: A list of index filenames to check.  The files are searched
 ** for in this order.
 */
-#define INDEX_NAMES "index.html", "index.htm", "Default.htm", "index.cgi"
+#define INDEX_NAMES "index.html", "index.htm"
 
 /* CONFIGURE: If this is defined then thttpd will automatically generate
 ** index pages for directories that don't have an explicit index file.
@@ -325,7 +352,7 @@
 ** individual directories by merely doing a "chmod 711" on them - the
 ** standard Unix file permission to allow file access but disable "ls".
 */
-#define GENERATE_INDEXES
+#undef GENERATE_INDEXES
 
 /* CONFIGURE: Whether to log unknown request headers.  Most sites will not
 ** want to log them, which will save them a bit of CPU time.
diff -urN thttpd-2.21/libhttpd.c thttpd-2.21-mnx/libhttpd.c
--- thttpd-2.21/libhttpd.c	Sat Apr 21 03:11:32 2001
+++ thttpd-2.21-mnx/libhttpd.c	Thu Nov 22 16:27:40 2001
@@ -76,6 +76,68 @@
 #  include <ndir.h>
 # endif
 #endif
+#ifdef VHOST_MYSQL
+#include "vhostconf.h"
+
+extern struct node *vh_list;
+extern struct banner *bn_list;
+extern struct rfr_rdr *redir_list;
+extern int vh_list_len, bn_list_len,rd_list_len;
+int numreq=0;
+
+#endif
+/*
+ Global variables
+ static stuff doesn't really work as planned, so they all are here
+ */
+char* tempfilename;
+int maxtempfilename = 0;
+char* header;
+int maxheader = 0;
+char* authpath;
+int maxauthpath = 0;
+char* prevauthpath;
+int maxprevauthpath = 0;
+char* prevuser;
+int maxprevuser = 0;
+char* prevcryp;
+int maxprevcryp = 0;
+char* location;
+char* header;
+int maxlocation = 0;
+char* temp;
+int maxtemp = 0;
+char* checked;
+char* rest;
+int maxchecked = 0, maxrest = 0;
+int maxnames = 0;
+char* names;
+char** nameptrs;
+char* name;
+int maxname = 0;
+char* rname;
+int maxrname = 0;
+char* encrname;
+int maxencrname = 0;
+char* buf;
+int maxbuf = 0;
+char* indexname;
+int maxindexname = 0;
+
+#ifdef AUTH_FILE
+char* dirname;
+int maxdirname = 0;
+#endif
+char* refhost = (char*) 0;
+int refhost_size = 0;
+
+
+#ifdef ADVCOUNTER
+#include <sys/un.h>
+extern int UDSfd;
+long log_errors;
+extern struct sockaddr_un UDSaddr;
+#endif
 
 extern char* crypt( const char* key, const char* setting );
 
@@ -169,8 +231,12 @@
 static int my_snprintf( char* str, size_t size, const char* format, ... );
 
 
+
 static int reap_time;
 
+
+
+
 static void
 child_reaper( ClientData client_data, struct timeval* nowP )
     {
@@ -591,8 +657,13 @@
 static void
 clear_ndelay( httpd_conn* hc )
     {
-    int flags, newflags;
-
+	int flags, newflags;
+	/*
+	 XXX: wtf to turn off nonblocking???
+	 there is a bug somewhere, it tries to read from nonblocking socket...
+         so as a temporary measure, I disable it here - maniax
+         */
+    return;
     flags = fcntl( hc->conn_fd, F_GETFL, 0 );
     if ( flags != -1 )
 	{
@@ -651,17 +722,29 @@
 	    add_response( hc, buf );
 	    }
 	if ( partial_content )
-	    {
+	{
+#ifdef VHOST_MYSQL
+	    (void) my_snprintf( buf, sizeof(buf),
+		"Content-Range: bytes %ld-%ld/%d\r\nContent-Length: %ld\r\n",
+		(long) hc->init_byte_loc, (long) hc->end_byte_loc, length,
+				(long) ( hc->end_byte_loc - hc->init_byte_loc + 1 +hc->ban+hc->ban_u) );
+#else
 	    (void) my_snprintf( buf, sizeof(buf),
 		"Content-Range: bytes %ld-%ld/%d\r\nContent-Length: %ld\r\n",
 		(long) hc->init_byte_loc, (long) hc->end_byte_loc, length,
-		(long) ( hc->end_byte_loc - hc->init_byte_loc + 1 ) );
+				(long) ( hc->end_byte_loc - hc->init_byte_loc + 1 ) );
+#endif
 	    add_response( hc, buf );
 	    }
 	else if ( length >= 0 )
-	    {
+	{
+#ifdef VHOST_MYSQL
 	    (void) my_snprintf( buf, sizeof(buf),
-		"Content-Length: %d\r\n", length );
+				"Content-Length: %d\r\n", length +hc->ban+hc->ban_u );
+#else
+	    (void) my_snprintf( buf, sizeof(buf),
+				"Content-Length: %d\r\n", length );
+#endif
 	    add_response( hc, buf );
 	    }
 	if ( extraheads[0] != '\0' )
@@ -773,12 +856,80 @@
     }
 
 
+#ifdef REFERER_REDIR
+int referer_redirect(httpd_conn *hc)
+{
+	static char rfr[128];
+        char *cp,*cp2;
+	static char headstr[] = "Location: ";
+        int i,m=2;
+
+	if (hc->referer==NULL)
+                return 1;
+
+	memset(rfr,0,sizeof(rfr));
+	cp=hc->referer;
+	if (strncmp(cp,"http://",7)==0) cp+=7;
+	cp2=strchr(cp,'/');
+	if (cp2!=NULL)
+	{
+		strncpy(rfr,cp,(size_t) (cp2-cp) );
+                rfr[(size_t) (cp2-cp)]=0;
+	}
+	else  	strcpy(rfr,cp);
+        cp=rfr;
+	for (i=strlen(cp);i>0;i--)
+	{
+		if ( *(cp+i)=='.')
+		{
+			m--; if (m==0) break;
+		};
+	}
+	if (i!=0)
+	{
+		cp++;
+		cp+=i;
+	}
+	/* okay,we have the domain, let's try to match it */
+        m=rdr_bin_search(redir_list,rd_list_len, cp);
+	if (m==-1)
+	{
+		return 1;
+	}
+	else
+	{
+		httpd_realloc_str( &header, &maxheader, sizeof(headstr) + strlen( redir_list[m].url ) );
+		(void) my_snprintf( header, maxheader,
+				    "%s%s\r\n", headstr, redir_list[m].url );
+		send_response( hc, 302, err302title, header, err302form, redir_list[m].url );
+		return 0;
+	}
+}
+
+#endif
+
+
 void
 httpd_send_err( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg )
-    {
+{
+
 #ifdef ERR_DIR
+    static char filename[1000];
+#endif
+#ifdef VHOST_MYSQL
+#ifdef ERR404FILENAME
+    /*
+     We want our own err404...
+     */
 
-    char filename[1000];
+    if ( (status==404) || (status==400) )
+    {
+	if ( send_err_file( hc, status, title, extraheads, ERR404FILENAME) )
+	    return;
+    }
+#endif
+#endif
+#ifdef ERR_DIR
 
     /* Try virtual host error page. */
     if ( hc->hs->vhost && hc->hostdir[0] != '\0' )
@@ -842,8 +993,6 @@
 static void
 send_authenticate( httpd_conn* hc, char* realm )
     {
-    static char* header;
-    static int maxheader = 0;
     static char headstr[] = "WWW-Authenticate: Basic realm=\"";
 
     httpd_realloc_str(
@@ -966,8 +1115,6 @@
 static int
 auth_check2( httpd_conn* hc, char* dirname  )
     {
-    static char* authpath;
-    static int maxauthpath = 0;
     struct stat sb;
     char authinfo[500];
     char* authpass;
@@ -975,14 +1122,7 @@
     FILE* fp;
     char line[500];
     char* cryp;
-    static char* prevauthpath;
-    static int maxprevauthpath = 0;
     static time_t prevmtime;
-    static char* prevuser;
-    static int maxprevuser = 0;
-    static char* prevcryp;
-    static int maxprevcryp = 0;
-
     /* Construct auth filename. */
     httpd_realloc_str(
 	&authpath, &maxauthpath, strlen( dirname ) + 1 + sizeof(AUTH_FILE) );
@@ -1111,9 +1251,6 @@
 static void
 send_dirredirect( httpd_conn* hc )
     {
-    static char* location;
-    static char* header;
-    static int maxlocation = 0, maxheader = 0;
     static char headstr[] = "Location: ";
 
     httpd_realloc_str( &location, &maxlocation, strlen( hc->encodedurl ) + 1 );
@@ -1124,7 +1261,7 @@
     (void) my_snprintf( header, maxheader,
 	"%s%s\r\n", headstr, location );
     send_response( hc, 302, err302title, header, err302form, location );
-    }
+}
 
 
 char*
@@ -1205,8 +1342,6 @@
 static int
 tilde_map_1( httpd_conn* hc )
     {
-    static char* temp;
-    static int maxtemp = 0;
     int len;
     static char* prefix = TILDE_MAP_1;
 
@@ -1228,8 +1363,10 @@
 static int
 tilde_map_2( httpd_conn* hc )
     {
+#ifndef VHOST_MYSQL
     static char* temp;
     static int maxtemp = 0;
+#endif
     static char* postfix = TILDE_MAP_2;
     char* cp;
     struct passwd* pw;
@@ -1287,14 +1424,18 @@
     {
     httpd_sockaddr sa;
     int sz;
-    static char* tempfilename;
-    static int maxtempfilename = 0;
     char* cp1;
     int len;
 #ifdef VHOST_DIRLEVELS
     int i;
     char* cp2;
 #endif /* VHOST_DIRLEVELS */
+#ifdef VHOST_MYSQL
+    int tmp,j,j0;
+    time_t tm0;
+    struct tm *stt0;
+    char *ext;
+#endif
 
     /* Figure out the virtual hostname. */
     if ( hc->reqhost[0] != '\0' )
@@ -1347,9 +1488,71 @@
 	*cp2++ = '/';
 	}
     (void) strcpy( cp2, hc->hostname );
-#else /* VHOST_DIRLEVELS */
+#endif
+#ifdef VHOST_MYSQL
+    tmp=bin_search(vh_list,vh_list_len,hc->hostname);
+    if (tmp==-1)
+    {
+	    /* not found , fall back to default method*/
+
+	    /* XXX may be error404 shoud be sent instead of that?
+	     it shoudn't mind in real life, because it shoudn't be found
+             if it's something more than a mere index.html
+             */
+	    httpd_realloc_str( &hc->hostdir, &hc->maxhostdir, strlen( hc->hostname ) );
+	    (void) strcpy( hc->hostdir, hc->hostname );
+
+    }
+    else
+    {
+	    httpd_realloc_str(&hc->hostdir,&hc->maxhostdir,strlen(vh_list[tmp].path));
+	    (void) strcpy (hc->hostdir,vh_list[tmp].path);
+
+	    ext=rindex(hc->origfilename,'.');
+	    if ( ext==NULL) ext=hc->origfilename;
+	    else ext++;
+
+	    /*
+	     XXX this looks bad
+             there should be some way to make it look right
+	     */
+
+	    /*
+	     Rules: If it ends with / (e.g. dirindex, if exists), .htm or .html,or doesn't have
+	     any path ( like http://www.xxx.com ) it should have banners put.
+             */
+	    if ( ( hc->origfilename[strlen(hc->origfilename)-1]=='/') ||
+		   (strcasecmp(ext,"htm")==0) ||
+	           (strcasecmp(ext,"html")==0) ||
+	           (ext[0]==0))
+	    {
+		    for (j=0;j<bn_list_len;j++)
+		    {
+			    if (strcmp(vh_list[tmp].adv, bn_list[j].name)==0)
+			    {
+				    time(&tm0);
+				    stt0=localtime(&tm0);
+				    numreq++;
+				    j0=numreq%bn_list[j].num;
+				    hc->banner=bn_list[j].days[stt0->tm_wday].banner[j0];
+				    hc->banner_under=bn_list[j].days[stt0->tm_wday].banner_under[j0];
+				    hc->ban=bn_list[j].days[stt0->tm_wday].fsizes[j0];
+				    hc->ban_u=bn_list[j].days[stt0->tm_wday].fsizes_und[j0];
+				    break;
+			    }
+		    }
+	    }
+
+    }
+    /*
+     XXX FIX!!! stupid ifdefs, etc
+     */
+#endif
+#ifndef VHOST_MYSQL
+#ifndef VHOST_DIRLEVELS
     httpd_realloc_str( &hc->hostdir, &hc->maxhostdir, strlen( hc->hostname ) );
     (void) strcpy( hc->hostdir, hc->hostname );
+#endif
 #endif /* VHOST_DIRLEVELS */
 
     /* Prepend hostdir to the filename. */
@@ -1377,10 +1580,7 @@
 static char*
 expand_symlinks( char* path, char** restP, int no_symlink, int tildemapped )
     {
-    static char* checked;
-    static char* rest;
     char link[5000];
-    static int maxchecked = 0, maxrest = 0;
     int checkedlen, restlen, linklen, prevcheckedlen, prevrestlen, nlinks, i;
     char* r;
     char* cp1;
@@ -1686,6 +1886,15 @@
     hc->keep_alive = 0;
     hc->should_linger = 0;
     hc->file_address = (char*) 0;
+#ifdef VHOST_MYSQL
+    hc->banner=(char *) (1) ;
+    hc->banner_under=(char *) (1);
+    hc->ban=0;
+    hc->ban_u=0;
+    hc->fpos=0;
+    hc->bpos=0;
+    hc->bpos_u=0;
+#endif
     return GC_OK;
     }
 
@@ -2508,16 +2717,7 @@
     DIR* dirp;
     struct dirent* de;
     int namlen;
-    static int maxnames = 0;
     int nnames;
-    static char* names;
-    static char** nameptrs;
-    static char* name;
-    static int maxname = 0;
-    static char* rname;
-    static int maxrname = 0;
-    static char* encrname;
-    static int maxencrname = 0;
     FILE* fp;
     int i, r;
     struct stat sb;
@@ -2776,9 +2976,6 @@
     {
     char* cp;
     int size;
-    static char* buf;
-    static int maxbuf = 0;
-
     size = strlen( fmt ) + strlen( arg );
     if ( size > maxbuf )
 	httpd_realloc_str( &buf, &maxbuf, size );
@@ -3341,25 +3538,29 @@
 static int
 really_start_request( httpd_conn* hc, struct timeval* nowP )
     {
-    static char* indexname;
-    static int maxindexname = 0;
     static const char* index_names[] = { INDEX_NAMES };
     int i;
-#ifdef AUTH_FILE
-    static char* dirname;
-    static int maxdirname = 0;
-#endif /* AUTH_FILE */
+#ifdef VHOST_MYSQL
+    char *ext;
+#endif
     int expnlen, indxlen;
     char* cp;
     char* pi;
 
     expnlen = strlen( hc->expnfilename );
 
+#ifdef REFERER_REDIR
+    if ( referer_redirect(hc) == 0 )
+	    return -1;
+#endif
+
+
     if ( hc->method != METHOD_GET && hc->method != METHOD_HEAD &&
 	 hc->method != METHOD_POST )
 	{
 	httpd_send_err(
-	    hc, 501, err501title, "", err501form, httpd_method_str( hc->method ) );
+	           hc, 501, err501title, "", err501form, httpd_method_str( hc->method ) );
+
 	return -1;
 	}
 
@@ -3570,12 +3771,46 @@
 	    hc->encodedurl );
 	return -1;
 	}
+#ifdef VHOST_MYSQL
+
+    ext=rindex(hc->origfilename,'.');
+    if ( ext==NULL) ext=hc->origfilename;
+    else ext++;
+    /* check if the extension is valid */
+    /*
+     XXX this SUX! someone should do it with cfg or mysql stuff
+     */
+
+    if  (! ((strcasecmp(ext,"html")==0) ||
+	    (strcasecmp(ext,"htm")==0) ||
+	    (strcasecmp(ext,"js")==0) ||
+	    (strcasecmp(ext,"jpg")==0) ||
+	    (strcasecmp(ext,"jpeg")==0) ||
+	    (strcasecmp(ext,"gif")==0) ||
+	    (strcasecmp(ext,"css")==0) ||
+	    (strcasecmp(ext,"png")==0) ||
+	    (strcasecmp(ext,"txt")==0) ||
+	    (strcasecmp(ext,"ico")==0) ||
+	    (strcasecmp(ext,"xml")==0) ||
+	    (strcasecmp(ext,"bmp")==0) ||
+	    (hc->origfilename[strlen(hc->origfilename)-1]=='/')||
+	    (ext[0]==0)))
+    {
+	    /* deny the request */
+	httpd_send_err( hc, 403, err403title, "",
+	    ERROR_FORM( err403form, "The requested URL '%.80s' is forbidden.\n" ),
+	    hc->encodedurl );
+	    return -1;
+    }
+
+#endif
 
     /* Fill in end_byte_loc, if necessary. */
     if ( hc->got_range &&
 	 ( hc->end_byte_loc == -1 || hc->end_byte_loc >= hc->sb.st_size ) )
 	hc->end_byte_loc = hc->sb.st_size - 1;
 
+
     figure_mime( hc );
 
     if ( hc->method == METHOD_HEAD )
@@ -3625,10 +3860,10 @@
 static void
 make_log_entry( httpd_conn* hc, struct timeval* nowP )
     {
+#ifndef ADVCOUNTER
     char* ru;
     char url[305];
     char bytes[40];
-
     if ( hc->hs->no_log )
 	return;
 
@@ -3712,7 +3947,37 @@
 	    "%.80s - %.80s \"%.80s %.200s %.80s\" %d %s \"%.200s\" \"%.80s\"",
 	    httpd_ntoa( &hc->client_addr ), ru,
 	    httpd_method_str( hc->method ), url, hc->protocol,
-	    hc->status, bytes, hc->referer, hc->useragent );
+		hc->status, bytes, hc->referer, hc->useragent );
+#else
+
+    /*
+     Let's not make the compiler to allocate memory every time for this buffer
+     */
+    static char log_outp[512];
+
+    /*
+     generate packet to be sent to the counter
+     */
+    memset(log_outp,0,512);
+    snprintf(log_outp,512,"%s|%s|/%s|%ld|%s|",hc->hostname,httpd_ntoa( &hc->client_addr ),hc->origfilename,hc->fsize,hc->referer);
+    if ((write(UDSfd, log_outp,strlen(log_outp)) < 0) && (errno != EAGAIN))
+    {
+	if (connect(UDSfd, (struct sockaddr *) &UDSaddr, sizeof(UDSaddr)) < 0)
+	{
+		log_errors++;
+		/*
+                 XXX should this be tuneable ?
+                 */
+	    if(log_errors==50000)
+	    {
+		syslog(LOG_ERR,"Reconnection to counter failed, %s",strerror(errno));
+		log_errors=0;
+	    }
+	}
+    }
+
+
+#endif
     }
 
 
@@ -3729,11 +3994,11 @@
     r = really_check_referer( hc );
 
     if ( ! r )
-	{
+	{/*
 	syslog(
 	    LOG_INFO, "%.80s non-local referer \"%.80s\" \"%.80s\"",
 	    httpd_ntoa( &hc->client_addr ), hc->encodedurl,
-	    hc->referer );
+	    hc->referer );*/
 	httpd_send_err(
 	    hc, 403, err403title, "",
 	    ERROR_FORM( err403form, "You must supply a local referer to get URL '%.80s' from this server.\n" ),
@@ -3751,8 +4016,6 @@
     char* cp1;
     char* cp2;
     char* cp3;
-    static char* refhost = (char*) 0;
-    static int refhost_size = 0;
     char *lp;
 
     hs = hc->hs;
diff -urN thttpd-2.21/libhttpd.h thttpd-2.21-mnx/libhttpd.h
--- thttpd-2.21/libhttpd.h	Fri Apr 13 08:37:17 2001
+++ thttpd-2.21-mnx/libhttpd.h	Wed Nov  7 13:29:55 2001
@@ -49,6 +49,8 @@
 #define RENEW(o,t,n) ((t*) realloc( (void*) o, sizeof(t) * (n) ))
 
 
+
+
 /* The httpd structs. */
 
 /* A multi-family sockaddr. */
@@ -136,7 +138,18 @@
     int should_linger;
     struct stat sb;
     int conn_fd;
+    /*
+     XXX ?
+     Little modification to the standart way thttpd server files
+     We use file prt and file position, so we can serve it easily,
+     I haven't found any other convinietnt way with writev() ....
+     (Don't want to think what it would be without writev()
+     */
     char* file_address;
+    char* banner, *banner_under;
+    off_t ban,ban_u; 
+    off_t fsize;
+    off_t fpos,bpos,bpos_u;
     } httpd_conn;
 
 /* Methods. */
diff -urN thttpd-2.21/machineconf.h thttpd-2.21-mnx/machineconf.h
--- thttpd-2.21/machineconf.h	Thu Jan  1 02:00:00 1970
+++ thttpd-2.21-mnx/machineconf.h	Thu Nov 22 16:01:42 2001
@@ -0,0 +1,6 @@
+#define DBHOST "localhost"
+#define DBNAME "test0"
+#define DBUSER "root"
+#define DBPASS ""
+#define UDSPATH "/tmp/testsock"
+#define BANNER_BASE "/home/banners"
diff -urN thttpd-2.21/mmc.c thttpd-2.21-mnx/mmc.c
--- thttpd-2.21/mmc.c	Sat Apr 14 00:02:15 2001
+++ thttpd-2.21-mnx/mmc.c	Fri Nov  9 14:30:21 2001
@@ -32,6 +32,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <syslog.h>
+#include <time.h>
 
 #ifdef HAVE_MMAP
 #include <sys/mman.h>
diff -urN thttpd-2.21/sample.cfg thttpd-2.21-mnx/sample.cfg
--- thttpd-2.21/sample.cfg	Thu Jan  1 02:00:00 1970
+++ thttpd-2.21-mnx/sample.cfg	Wed Oct 24 13:30:36 2001
@@ -0,0 +1 @@
+urlpat=**.jpg|**.gif|**.jpeg|**.bmp|**.png|**.js
diff -urN thttpd-2.21/thttpd.c thttpd-2.21-mnx/thttpd.c
--- thttpd-2.21/thttpd.c	Sun Apr 15 19:09:20 2001
+++ thttpd-2.21-mnx/thttpd.c	Thu Nov 22 14:28:54 2001
@@ -58,7 +58,18 @@
 #include "mmc.h"
 #include "timers.h"
 #include "match.h"
-
+#ifdef VHOST_MYSQL
+#include "vhostconf.h"
+extern struct node *vh_list;
+extern struct banner *bn_list;
+extern struct rfr_rdr *redir_list;
+extern int vh_list_len,bn_list_len,rd_list_len;
+#endif
+#ifdef ADVCOUNTER
+#include <sys/un.h>
+int UDSfd;
+struct sockaddr_un UDSaddr;
+#endif
 
 static char* argv0;
 static int debug;
@@ -157,6 +168,72 @@
 static void logstats( struct timeval* nowP );
 static void thttpd_logstats( long secs );
 
+#ifdef VHOST_MYSQL
+static void reload_vhost(ClientData client_data, struct timeval* nowP);
+#endif
+
+
+
+#ifdef VHOST_MYSQL
+void reload_vhost(ClientData client_data, struct timeval* nowP)
+{
+	/*
+	 we don't fscken care about the function parameters :)
+	 */
+	struct node *vh_list0;
+	struct banner *bn_list0;
+        struct rfr_rdr *redir_list0;
+	int vh_list_len0,bn_list_len0,rd_list_len0;
+
+	/*
+	 we do it transactionally
+	 e.g. connect do db load everything, and if it's ok - switch to the new
+         sets and free the old ones.
+	 */
+        syslog(LOG_ERR,"Reloading vhost\n");
+	vh_list0=vh_init_struct(&vh_list_len0);
+	if (vh_list0==NULL) return;
+	bn_list0=init_banners_list(&bn_list_len0);
+	if (bn_list0==NULL)
+	{
+		/*
+		 XXX: This could crash the server, but I prefer not to make
+		 a memory leak here... and vh_init_struct guarantees that if vh_list0!=NULL,
+                 then it was allocated.
+                 */
+                free_vh_list(vh_list0,vh_list_len0);
+                return;
+	};
+#ifdef REFERER_REDIR
+	redir_list0=rdr_list_init(&rd_list_len0);
+	if (redir_list0==NULL)
+	{
+		free_vh_list(vh_list0,vh_list_len0);
+		free_bn_list(bn_list0,bn_list_len0);
+                return;
+	}
+#endif
+        syslog(LOG_ERR,"Vhosts reloaded\n");
+	free_vh_list(vh_list,vh_list_len);
+	vh_list=vh_list0;
+	vh_list_len=vh_list_len0;
+	free_bn_list(bn_list,bn_list_len);
+	bn_list=bn_list0;
+	bn_list_len=bn_list_len0;
+#ifdef REFERER_REDIR
+	free_rdr_list(redir_list,rd_list_len);
+	redir_list=redir_list0;
+	rd_list_len=rd_list_len0;
+#endif
+        syslog(LOG_ERR,"Switched vhosts/banners\n");
+
+}
+void handle_segv(int sig)
+{
+	logstats(NULL);
+        exit(2);
+}
+#endif
 
 static void
 handle_term( int sig )
@@ -171,9 +248,10 @@
 static void
 handle_hup( int sig )
     {
-    FILE* logfp;
 
-    if ( no_log )
+#ifndef ADVCOUNTER
+    FILE* logfp;
+	if ( no_log )
 	return;
 
     /* Re-open the log file. */
@@ -188,6 +266,7 @@
 	(void) fcntl( fileno( logfp ), F_SETFD, 1 );
 	httpd_set_logfp( hs, logfp );
 	}
+#endif
     }
 
 
@@ -223,6 +302,10 @@
     int gotv4, gotv6;
     struct timeval tv;
 
+#ifdef ADVCOUNTER
+    long int flg=0;
+#endif
+
     argv0 = argv[0];
 
     cp = strrchr( argv0, '/' );
@@ -262,6 +345,7 @@
     if ( throttlefile != (char*) 0 )
 	read_throttlefile( throttlefile );
 
+#ifndef ADVCOUNTER
     /* Log file. */
     if ( logfile != (char*) 0 )
 	{
@@ -284,6 +368,10 @@
 	}
     else
 	logfp = (FILE*) 0;
+#else
+    no_log = 1 ;
+    logfp = (FILE*) 0;
+#endif
 
     /* Figure out uid/gid from user. */
     pwd = getpwnam( user );
@@ -401,6 +489,35 @@
 	    }
 	}
 
+#ifdef VHOST_MYSQL
+    vh_list=vh_init_struct(&vh_list_len);
+    if (vh_list==NULL) exit(1);
+    bn_list=init_banners_list(&bn_list_len);
+    if (bn_list==NULL) exit(1);
+#ifdef REFERER_REDIR
+    redir_list=rdr_list_init(&rd_list_len);
+    if (redir_list==NULL) exit(1);
+#endif
+#ifdef ADVCOUNTER
+    UDSfd = socket(AF_UNIX,SOCK_DGRAM,0);
+    if (UDSfd == -1 )
+    {
+	(void) fprintf( stderr, "error creating unix domain socket %s \n",strerror(errno));
+	exit( 1 );
+    }
+    bzero( (char *) &UDSaddr, sizeof(UDSaddr));
+    strcpy(UDSaddr.sun_path, UDSPATH);
+    UDSaddr.sun_family=AF_UNIX;
+    fcntl(UDSfd, F_GETFL, flg);
+    flg |= O_NONBLOCK;
+    fcntl(UDSfd, F_SETFL, flg);
+
+    if (connect(UDSfd, (struct sockaddr *) &UDSaddr, sizeof(UDSaddr)) < 0)
+    {
+	    (void) fprintf( stderr, "error connecting to %s, %s\n",UDSPATH,strerror(errno));
+    }
+#endif
+#endif
     /* Set up to catch signals. */
     (void) signal( SIGTERM, handle_term );
     (void) signal( SIGINT, handle_term );
@@ -409,7 +526,9 @@
     got_usr1 = 0;
     (void) signal( SIGUSR1, handle_usr1 );
     (void) signal( SIGUSR2, handle_usr2 );
-
+#ifdef VHOST_MYSQL
+    (void) signal( SIGSEGV, handle_segv );
+#endif
     /* Initialize the timer package. */
     tmr_init();
 
@@ -447,6 +566,14 @@
 	exit( 1 );
 	}
 #endif /* STATS_TIME */
+#ifdef VHOST_MYSQL
+    /* Set up vhost reload timer */
+    if (tmr_create((struct timeval*) 0,reload_vhost,JunkClientData,VHOST_RELOAD_TIME*1000L,1)==NULL)
+    {
+	(void) fprintf( stderr, "error creating timer\n");
+        exit(1);
+    };
+#endif
     start_time = stats_time = time( (time_t*) 0 );
     stats_connections = stats_bytes = 0L;
     stats_simultaneous = 0;
@@ -520,7 +647,7 @@
     (void) gettimeofday( &tv, (struct timezone*) 0 );
     while ( ( ! terminate ) || numconnects > 0 )
 	{
-	/* Do the fd watch. */
+	    /* Do the fd watch. */
 	num_ready = fdwatch( tmr_mstimeout( &tv ) );
 	if ( num_ready < 0 )
 	    {
@@ -538,7 +665,7 @@
 	    }
 
 	/* Is it a new connection? */
-	if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 && 
+	if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 &&
 	     fdwatch_check_fd( hs->listen6_fd ) )
 	    {
 	    if ( handle_newconnect( &tv, hs->listen6_fd ) )
@@ -548,7 +675,7 @@
 		*/
 		continue;
 	    }
-	if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 && 
+	if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 &&
 	     fdwatch_check_fd( hs->listen4_fd ) )
 	    {
 	    if ( handle_newconnect( &tv, hs->listen4_fd ) )
@@ -997,7 +1124,7 @@
 	}
 
     if ( aiv4 == (struct addrinfo*) 0 )
-	*gotv4P = 0; 
+	*gotv4P = 0;
     else
 	{
 	if ( sa4_len < aiv4->ai_addrlen )
@@ -1012,7 +1139,7 @@
 	*gotv4P = 1;
 	}
     if ( aiv6 == (struct addrinfo*) 0 )
-	*gotv6P = 0; 
+	*gotv6P = 0;
     else
 	{
 	if ( sa6_len < aiv6->ai_addrlen )
@@ -1382,7 +1509,12 @@
 	c->bytes_to_send = hc->end_byte_loc + 1;
 	}
     else
-	c->bytes_to_send = hc->bytes_to_send;
+        c->bytes_to_send = hc->bytes_to_send;
+
+#ifdef VHOST_MYSQL
+        hc->fsize=c->bytes_to_send;
+        c->bytes_to_send+= hc->ban+hc->ban_u;
+#endif
 
     /* Check if it's already handled. */
     if ( hc->file_address == (char*) 0 )
@@ -1420,6 +1552,13 @@
     }
 
 
+/*
+ XXX
+ In reallity, this works
+ it doesn't make it any prettier, and it should be rewriten , IMO
+ volunteers?:)
+ */
+
 static void
 handle_send( connecttab* c, struct timeval* tvP )
     {
@@ -1428,7 +1567,12 @@
     time_t elapsed;
     httpd_conn* hc = c->hc;
 
+    /* XXX
+     REALLY fucked ifdefs
+     e.g. "Don't do this at home"
+     */
     /* Do we need to write the headers first? */
+#ifndef VHOST_MYSQL
     if ( hc->responselen == 0 )
 	{
 	/* No, just write the file. */
@@ -1437,10 +1581,17 @@
 	    MIN( c->bytes_to_send - c->bytes_sent, c->limit ) );
 	}
     else
-	{
+    {
+#endif
 	/* Yes.  We'll combine headers and file into a single writev(),
 	** hoping that this generates a single packet.
 	*/
+
+	    /*
+	     XXX
+             watch the fun...
+	     */
+#ifndef VHOST_MYSQL
 	struct iovec iv[2];
 
 	iv[0].iov_base = hc->response;
@@ -1448,8 +1599,27 @@
 	iv[1].iov_base = &(hc->file_address[c->bytes_sent]);
 	iv[1].iov_len = MIN( c->bytes_to_send - c->bytes_sent, c->limit );
 	sz = writev( hc->conn_fd, iv, 2 );
-	}
+#else
+	struct iovec iv[4];
+
+	iv[0].iov_base = hc->response;
+	iv[0].iov_len = hc->responselen;
+
+	iv[1].iov_base = &(hc->banner[hc->bpos]);
+	iv[1].iov_len = hc->ban-hc->bpos;
+
+	iv[2].iov_base = &(hc->file_address[hc->fpos]);
+        iv[2].iov_len = hc->fsize-hc->fpos;
 
+	iv[3].iov_base = &(hc->banner_under[hc->bpos_u]);
+	iv[3].iov_len = hc->ban_u-hc->bpos_u;
+
+	sz = writev( hc->conn_fd, iv, 4 );
+
+#endif
+#ifndef VHOST_MYSQL
+	}
+#endif
     if ( sz == 0 ||
 	 ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) )
 	{
@@ -1519,6 +1689,49 @@
     /* And update how much of the file we wrote. */
     c->bytes_sent += sz;
     c->hc->bytes_sent += sz;
+#ifdef VHOST_MYSQL
+
+    /*
+     That's the only good thing here
+     logic: use sz to find where we are in the writing - move the relevant positions,
+     and if we're finished with some file, don't fsck with it any mode.
+     sz=0 is needed for the next if's to go through. It shoud be simplier with goto, but
+     no, not today.
+     */
+    if  ( (sz>=(hc->ban-hc->bpos)) || (hc->bpos==hc->ban))
+    {
+            /* first banner served, no fscking with the pos */
+            sz -= (hc->ban-hc->bpos);
+	    hc->bpos=hc->ban;
+
+    } else
+    {
+	    hc->bpos+=sz;
+            sz=0;
+    }
+    if  ( (sz>=(hc->fsize-hc->fpos)) || (hc->fsize==hc->fpos)) /* file is served already */
+    {
+            sz-=(hc->fsize-hc->fpos);
+            hc->fpos=hc->fsize;
+    }
+    else
+    {
+	    hc->fpos+=sz;
+            sz=0;
+    }
+    if  ( (sz>=(hc->ban_u-hc->bpos_u)) || (hc->ban_u==hc->bpos_u)) /* second banner is served already */
+    {
+            sz-=(hc->ban_u-hc->bpos_u);
+            hc->bpos_u=hc->ban_u;
+    }
+    else
+    {
+	    hc->bpos_u+=sz;
+    }
+
+
+
+#endif
 
     /* Are we done? */
     if ( c->bytes_sent >= c->bytes_to_send )
@@ -1737,9 +1950,11 @@
     c->idle_send_timer = (Timer*) 0;
     if ( c->conn_state != CNST_FREE )
 	{
-	syslog( LOG_INFO,
+#ifndef VHOST_MYSQL
+	    syslog( LOG_INFO,
 	    "%.80s connection timed out sending",
-	    httpd_ntoa( &c->hc->client_addr ) );
+		    httpd_ntoa( &c->hc->client_addr ) );
+#endif
 	clear_connection( c, nowP );
 	}
     }
diff -urN thttpd-2.21/timers.c thttpd-2.21-mnx/timers.c
--- thttpd-2.21/timers.c	Fri Apr 13 08:37:49 2001
+++ thttpd-2.21-mnx/timers.c	Fri Nov  9 14:20:25 2001
@@ -188,7 +188,6 @@
     /* Add the new timer to the proper active list. */
     l_add( t );
     ++active_count;
-
     return t;
     }
 
diff -urN thttpd-2.21/vhost.c thttpd-2.21-mnx/vhost.c
--- thttpd-2.21/vhost.c	Thu Jan  1 02:00:00 1970
+++ thttpd-2.21-mnx/vhost.c	Thu Nov 22 14:23:36 2001
@@ -0,0 +1,349 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <mysql/mysql.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "vhostconf.h"
+
+struct node *vh_list;
+struct banner *bn_list;
+struct rfr_rdr *redir_list;
+int vh_list_len,bn_list_len,rd_list_len;
+
+/*
+ Allocates memory for *tmp, and loads the vhost map in it. Sets n accordingly.
+ */
+
+struct node *vh_init_struct(int *n)
+{
+
+	MYSQL *conn;
+	MYSQL_RES * result;
+	MYSQL_ROW row;
+        struct node *tmp;
+
+
+	conn=mysql_init(NULL);
+	if (conn==NULL)
+	{
+		syslog(LOG_ERR,"Error initalizing mysql handle");
+                return NULL;
+	}
+	if (mysql_real_connect(conn,DBHOST,DBUSER,DBPASS,DBNAME,0,NULL,0)==NULL)
+	{
+		syslog(LOG_ERR,"Error connecting to the database");
+                return NULL;
+	}
+
+	/*
+	 I use string constant for the query, because I haven't thought of a way to
+         make it more flexible for the moment.
+	 */
+
+
+	if(mysql_real_query(conn,QUERY,strlen(QUERY)+1)!=0)
+	{
+		syslog(LOG_ERR,"Error querying the database");
+		return NULL;
+	}
+	result=mysql_store_result(conn);
+	/*
+	 Okay, we have the results , let's allocate some memory and parse them
+	 */
+
+	tmp=(struct node *) malloc(sizeof(struct node) * mysql_num_rows(result));
+
+	row=mysql_fetch_row(result);
+        (*n)=0;
+	while (row!=NULL)
+	{
+                tmp[*n].vhost=strdup(row[0]);
+		tmp[*n].path=strdup(row[1]);
+                tmp[*n].adv=strdup(row[2]);
+		(*n)++;
+		row=mysql_fetch_row(result);
+	}
+	mysql_free_result(result);
+        mysql_close(conn);
+        return tmp;
+}
+
+struct banner *init_banners_list(int *n)
+{
+	MYSQL *conn;
+	MYSQL_RES * result;
+	MYSQL_ROW row;
+	struct banner *tmp;
+	int i,j,fd;
+        struct stat st0;
+        char fname[255];
+
+	conn=mysql_init(NULL);
+	if (conn==NULL)
+	{
+		syslog(LOG_ERR,"Error initalizing mysql handle");
+                return NULL;
+	}
+	if (mysql_real_connect(conn,DBHOST,DBUSER,DBPASS,DBNAME,0,NULL,0)==NULL)
+	{
+		syslog(LOG_ERR,"Error connecting to the database");
+                return NULL;
+	}
+
+	/*
+	 I use string constant for the query, because I haven't thought of a way to
+         make it more flexible for the moment.
+	 */
+
+	if(mysql_real_query(conn,QUERY_BAN,strlen(QUERY_BAN)+1)!=0)
+	{
+		syslog(LOG_ERR,"Error querying the database %s",QUERY_BAN);
+		return NULL;
+	}
+	result=mysql_store_result(conn);
+	/*
+	 Okay, we have the results , let's allocate some memory and parse them
+	 */
+
+	tmp=(struct banner *) malloc(sizeof(struct banner) * mysql_num_rows(result));
+
+	row=mysql_fetch_row(result);
+	(*n)=0;
+
+	while (row!=NULL)
+	{
+                tmp[*n].name=strdup(row[0]);
+		tmp[*n].num=atoi(row[1]);
+
+		row=mysql_fetch_row(result);
+		/*
+                 mmaping the files....
+		 */
+		for (i=0;i<tmp[*n].num;i++)
+		{
+			for(j=0;j<7;j++)
+			{
+
+				/*
+				 XXX:
+                                 Repeating code twice sux, fix this
+                                 */
+                                                 /*adv 7  1banner*/
+				snprintf(fname,255,"%s/%s/%d/%dbanner.html", BANNER_BASE, tmp[*n].name,j,i+1);
+				fd=open(fname,O_RDONLY);
+				if (fd>0)
+				{
+					fstat(fd,&st0);
+					if (st0.st_size!=0)
+					{
+						tmp[*n].days[j].banner[i]=(char *) mmap(NULL,st0.st_size,PROT_READ,MAP_PRIVATE,fd,0);
+                                                tmp[*n].days[j].fsizes[i]=st0.st_size;
+					}
+					else
+					{
+						/* lets' follow the thttpd ideas here - never mmap zero length file */
+						tmp[*n].days[j].banner[i]=(char *) (1);
+                                                tmp[*n].days[j].fsizes[i]=0;
+					}
+                                        close(fd);
+				}
+				snprintf(fname,255,"%s/%s/%d/%dbanner_under.html", BANNER_BASE, tmp[*n].name,j,i+1);
+				fd=open(fname,O_RDONLY);
+				if (fd>0)
+				{
+					fstat(fd,&st0);
+					if (st0.st_size!=0)
+					{
+						tmp[*n].days[j].banner_under[i]=(char *) mmap(NULL,st0.st_size,PROT_READ,MAP_PRIVATE,fd,0);
+                                                tmp[*n].days[j].fsizes_und[i]=st0.st_size;
+					}
+					else
+					{
+						/* lets' follow the thttpd ideas here - never mmap zero length file */
+						tmp[*n].days[j].banner_under[i]=(char *) (1);
+                                                tmp[*n].days[j].fsizes_und[i]=0;
+					}
+                                        close(fd);
+				}
+
+			}
+
+		}
+		(*n)++;
+
+	}
+	mysql_free_result(result);
+        mysql_close(conn);
+        return tmp;
+
+}
+
+struct rfr_rdr *rdr_list_init (int *n)
+{
+	MYSQL *conn;
+	MYSQL_RES * result;
+	MYSQL_ROW row;
+        struct rfr_rdr *tmp;
+
+
+	conn=mysql_init(NULL);
+	if (conn==NULL)
+	{
+		syslog(LOG_ERR,"Error initalizing mysql handle");
+                return NULL;
+	}
+	if (mysql_real_connect(conn,DBHOST,DBUSER,DBPASS,DBNAME,0,NULL,0)==NULL)
+	{
+		syslog(LOG_ERR,"Error connecting to the database");
+                return NULL;
+	}
+
+	/*
+	 I use string constant for the query, because I haven't thought of a way to
+         make it more flexible for the moment.
+	 */
+
+
+	if(mysql_real_query(conn,QUERY_RDR,strlen(QUERY_RDR)+1)!=0)
+	{
+		syslog(LOG_ERR,"Error querying the database");
+		return NULL;
+	}
+	result=mysql_store_result(conn);
+	/*
+	 Okay, we have the results , let's allocate some memory and parse them
+	 */
+
+	tmp=(struct rfr_rdr *) malloc(sizeof(struct rfr_rdr) * mysql_num_rows(result));
+
+	row=mysql_fetch_row(result);
+        (*n)=0;
+	while (row!=NULL)
+	{
+                tmp[*n].domain=strdup(row[0]);
+		tmp[*n].url=strdup(row[1]);
+		(*n)++;
+		row=mysql_fetch_row(result);
+	}
+	mysql_free_result(result);
+        mysql_close(conn);
+        return tmp;
+
+}
+
+
+void free_rdr_list(struct rfr_rdr *tmp, int len)
+{
+
+	int i;
+
+	for (i=0;i<len;i++)
+	{
+                free(tmp[i].domain);
+		free(tmp[i].url);
+	}
+        free(tmp);
+
+}
+
+
+void free_vh_list(struct node *tmp, int len)
+{
+	/*
+	 simple feeing of the list (not exactly list :) some kind
+         of array)
+         */
+
+	int i;
+
+	for (i=0;i<len;i++)
+	{
+                free(tmp[i].vhost);
+		free(tmp[i].path);
+                free(tmp[i].adv);
+	}
+        free(tmp);
+}
+
+void free_bn_list(struct banner *tmp,int len)
+{
+	/*
+	 not so simple freeing of the list....
+	 */
+
+	int i,j,k;
+
+	for (i=0;i<len;i++)
+	{
+		for (j=0;j<7;j++)
+		{
+
+			for (k=0;k<tmp[i].num;k++)
+			{
+				if (tmp[i].days[j].fsizes[k]!=0)
+					munmap (tmp[i].days[j].banner[k],tmp[i].days[j].fsizes[k]);
+				if (tmp[i].days[j].fsizes_und[k]!=0)
+					munmap (tmp[i].days[j].banner_under[k],tmp[i].days[j].fsizes_und[k]);
+			}
+		}
+
+
+	}
+        free(tmp);
+}
+
+
+/*
+ Searches for vhost position in *table
+ Uses simple binary search in sorted array, tests proved that it's fast enough
+ (30 000 searches in 30 000 elements array took about 100 ms , not like the
+ linear search,that took about 100 s )
+ */
+
+int bin_search(struct node *tbl, int n, char *tosrch)
+{
+	int k,i,left,right;
+
+	left=0;
+	right=n;
+	while (left!=right)
+	{
+		i=(left+right)/2;
+		k=strcmp(tosrch,tbl[i].vhost);
+		if (k==0) return i;
+		if (k<0) right=i;
+		else
+			if (left==i) return -1 ;
+			else left=i;
+
+	}
+        return -1;
+}
+
+int rdr_bin_search(struct rfr_rdr *tbl, int n, char *tosrch)
+{
+	int k,i,left,right;
+
+	left=0;
+	right=n;
+	while (left!=right)
+	{
+		i=(left+right)/2;
+		k=strcmp(tosrch,tbl[i].domain);
+		if (k==0) return i;
+		if (k<0) right=i;
+		else
+			if (left==i) return -1 ;
+			else left=i;
+
+	}
+        return -1;
+}
diff -urN thttpd-2.21/vhostconf.h thttpd-2.21-mnx/vhostconf.h
--- thttpd-2.21/vhostconf.h	Thu Jan  1 02:00:00 1970
+++ thttpd-2.21-mnx/vhostconf.h	Thu Nov 22 16:02:51 2001
@@ -0,0 +1,59 @@
+#include "machineconf.h"
+/* Please, god,root, let mysql sort the results like strcmp.... */
+#define QUERY "select hostname,path,advtype from vhost order by hostname"
+#define QUERY_BAN "select advtype,num from numban"
+#define QUERY_RDR "select umatch, url from redir where type='referer' order by umatch"
+
+#include <syslog.h>
+
+/*
+ Vhost list struct
+ */
+struct node
+{
+    char *vhost;
+    char *path;
+    char *adv;
+
+};
+
+/* banners stuff */
+struct day
+{
+	char *banner[10];
+        int fsizes[10];
+	char *banner_under[10];
+        int fsizes_und[10];
+
+};
+struct banner
+{
+	char *name;
+	int num;
+        struct day days[7];
+};
+
+
+/*
+
+  Referer redirection struct
+
+  */
+
+struct rfr_rdr
+{
+	char *domain;
+	char *url;
+};
+
+
+/* forward declarations */
+
+struct node *vh_init_struct(int *n);
+struct banner *init_banners_list(int *n);
+struct rfr_rdr *rdr_list_init (int *n);
+int bin_search(struct node *tbl, int n,char *tosrch);
+int rdr_bin_search(struct rfr_rdr *tbl, int n, char *tosrch);
+void free_vh_list(struct node *tmp, int len);
+void free_bn_list(struct banner *tmp,int len);
+void free_rdr_list(struct rfr_rdr *list, int len);
