/**************************************************************************/
/**                                                                      **/
/**            WWW cgi statistics generating program                     **/
/**                                                                      **/
/**               (c) 1995 Takoyaki Software Ltd.                        **/
/**                                                                      **/
/**                        ------------                                  **/
/**                                                                      **/
/**  Idea, programming, and magic are the personal copyright of          **/
/**  Dylan Cuthbert (dylan@takoyaki.demon.co.uk)                         **/
/**                                                                      **/
/**************************************************************************/
/* __PASSLOCK=wilbur                                                      */
/**************************************************************************/
/* Version modifications                                                  */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
#ifdef __GO32__
#include <osfcn.h>
#endif


#define VERSION "v0.8"

#define LOGFILE "/home/vinz/httpd_1.3/logs/access_log"

#define GRAPHDISPLAY

#ifdef __GO32__
#define GIF_24_FILE "graph24.gif"
#define GIF_24_WWW "graph24.gif"
#else
#define GIF_24_FILE "/home/vinz/www/images/graph24.gif"
#define GIF_24_WWW "/images/graph24.gif"
#endif

#define GIF_24_BAR_WIDTH 7
#define GIF_24_BAR_SPACE 9
#define GIF_24_BAR_COLOUR G_LIGHTRED
#define GIF_24_BAR_SHADOW G_BLACK
#define GIF_24_X (GIF_24_BAR_SPACE*24+10)
#define GIF_24_Y 200

/**************************************************/
/* structures to store the data from the log file */

struct host {
	struct host *next;
	struct host *prev;
	char *name;
	unsigned long count;
	unsigned long amount;
	};

struct page {
	struct page *next;
	struct page *prev;
	char *name;
	unsigned long count;
	unsigned long amount;
	};

struct accessdate {
	struct accessdate *next;
	struct accessdate *prev;
	int year;
	int month;
	int day;
	int firsthour;
	int lasthour;
	unsigned long hourlist[24];
	};

unsigned int no_of_accesses=0;
unsigned int no_of_realpages=0;
unsigned int no_of_gifs=0;
unsigned int unique_hosts=0;
unsigned int unique_pages=0;
unsigned int total_data=0;
unsigned int total_hours=0;
unsigned int average_max=0;

struct host *hosts=NULL;
struct page *pages=NULL;
struct accessdate *dates=NULL;

/** Allow up to 10000 entries in a form (a little over the top maybe?) **/

#define MAX_ENTRIES 10000

#define STOPCHAR 0x07

/** if an entry can't be found return an empty string with this macro **/

#define entry(num,label) (((num)==-1)?"":entries[(num)].label)

/** structure for form entries received from the client **/

typedef struct {
    char *name;
    char *val;
} entry;

/** routines in util.c (public domain) **/

char *makeword(char *line, char stop);
char *fmakeword(FILE *f, char stop, int *len);
char x2c(char *what);
void unescape_url(char *url);
void plustospace(char *str);

entry entries[MAX_ENTRIES];
int max;

char wordbuf[10240];

#define G_BLACK 0
#define G_BLUE 1
#define G_GREEN 2
#define G_CYAN 3
#define G_RED 4
#define G_MAGENTA 5
#define G_BROWN 6
#define G_GREY 7
#define G_DARKGREY 8
#define G_LIGHTBLUE 9
#define G_LIGHTGREEN 10
#define G_LIGHTCYAN 11
#define G_LIGHTRED 12
#define G_PINK 13
#define G_YELLOW 14
#define G_WHITE 15

int gifsizex;
int gifsizey;
unsigned char *currentgif;

unsigned char image_0[] =
	"        "
	" 000    "
	"00 00   "
	"00 00   "
	"00 00   "
	"00 00   "
	" 000    "
	"        ";


unsigned char image_1[] =
	"        "
	" 00     "
	"000     "
	" 00     "
	" 00     "
	" 00     "
	"0000    "
	"        ";

unsigned char image_2[] =
	"        "
	" 000    "
	"00 00   "
	"   00   "
	" 000    "
	"00      "
	"00000   "
	"        ";


unsigned char image_3[] =
	"        "
	"0000    "
	"   00   "
	" 000    "
	"   00   "
	"   00   "
	"0000    "
	"        ";

unsigned char image_6[] =
	"        "
	" 00     "
	"00      "
	"0000    "
	"00 00   "
	"00 00   "
	" 000    "
	"        ";

unsigned char image_8[] =
	"        "
	" 000    "
	"00 00   "
	" 000    "
	"00 00   "
	"00 00   "
	" 000    "
	"        ";


/**********************************************/
/* allocate memory required for the gif image */


void allocgif(int xs, int ys)
	{
	gifsizex = xs;
	gifsizey = ys;
	currentgif = (unsigned char *)calloc(xs*ys,1);
	}

/**********************************************/
/* free the gif                               */

void freegif()
	{
	free(currentgif);
	}
/**********************************************/
/* plot a colour into the gif file            */

void gifplot(int x,int y,int colour)
	{
	currentgif[gifsizex*y+x] = colour;
	}

/**********************************************/
void gifrect(int x,int y,int wid,int hei,int colour)
	{
	int m,n;

	for (m=0;m<hei;m++)
		{
		for (n=0;n<wid;n++)
			{
			gifplot(x+n,y+m,colour);
			}
		}
	}

/**********************************************/
void gifcopyimage(int x,int y,int sx,int sy,unsigned char *image,int colour)
	{
	int m,n;

	for (m=0;m<sy;m++)
		for (n=0;n<sx;n++)
			if (image[n+m*sy]!=0 && image[n+m*sy]!=' ') gifplot(x+n,y+m,colour);
	}

/**********************************************/
/* write the gif file out to a file           */

void gifwrite(char *fn)
	{
	FILE *fp;
	if (fp = fopen(fn,"wb"))
		{
		fwrite(currentgif,gifsizex*gifsizey,1,fp);
		fclose(fp);
		}
	}

/**********************************************/
/* convert the raw data into a real gif file  */

void convert2gif(char *fn,char *on)
	{
	char temp[200];

	remove(on);
	sprintf(temp,"raw2gif>%s -q -s %d %d %s",on,gifsizex,gifsizey,fn);
	system(temp);
	}

/**********************************************/

void gif24hour()
	{
	int n,m;
	struct accessdate *d;
	int averages[24];
	int hits[24];
	int max;

	allocgif(GIF_24_X,GIF_24_Y);

	
	for (m=0;m<GIF_24_Y;m++)
		{
		for (n=0;n<GIF_24_X;n++)
			{
			gifplot(n,m,(m+n)&15);
			}
		}

	for (n=0;n<24;n++)
		{
		averages[n] = 0;
		hits[n] = 0;
		}

	d = dates;

	while (d)
		{
		for (n=d->firsthour;n<=d->lasthour;n++)
			{
			averages[n] += d->hourlist[n];
			hits[n]++;
			}
		d = d->next;
		}

	max = 0;
	for (n=0;n<24;n++)
		{
		if (averages[n]!=0)
			{
			averages[n] /= hits[n];
			if (averages[n]>max) max = averages[n];
			}
		}

	if (max == 0) max = 1;

	for (n=0;n<24;n++)
		{
		if (averages[n] != 0)
			{
			gifrect(2+n*GIF_24_BAR_SPACE,190-(averages[n]*180)/max,GIF_24_BAR_WIDTH,(averages[n]*180)/max,GIF_24_BAR_SHADOW);
			gifrect(2+n*GIF_24_BAR_SPACE+2,190-(averages[n]*180)/max-2,GIF_24_BAR_WIDTH,(averages[n]*180)/max,GIF_24_BAR_COLOUR);
			}
		}

	average_max = max;

	gifrect(0,191,GIF_24_X,9,G_GREY);

	gifcopyimage(2,192,8,8,image_0,G_BLACK);
	gifcopyimage(2+GIF_24_X/4,192,8,8,image_6,G_BLACK);
	gifcopyimage(2+GIF_24_X/2-6,192,8,8,image_1,G_BLACK);
	gifcopyimage(2+GIF_24_X/2,192,8,8,image_2,G_BLACK);
	gifcopyimage(2+(GIF_24_X/4)*3-6,192,8,8,image_1,G_BLACK);
	gifcopyimage(2+(GIF_24_X/4)*3,192,8,8,image_8,G_BLACK);
	gifcopyimage(GIF_24_X-16,192,8,8,image_2,G_BLACK);
	gifcopyimage(GIF_24_X-16+6,192,8,8,image_3,G_BLACK);

	gifwrite("test.raw");
	convert2gif("test.raw",GIF_24_FILE);

	freegif();
	}



/**********************************************/
/** Search through the FORM contents for a   **/
/** label of the specified name              **/

int findname(char *s)
	{
	int n;

	for (n=0;n<max;n++)
		if (stricmp(entries[n].name,s)==0) return n;

	return -1;
	}


/**********************************************/
void copyfile(char *backupname,char *fn)
	{
	FILE *out,*in;

	if (out = fopen(backupname,"w"))
		{
		if (in = fopen(fn,"r"))
			{

			while (!feof(in))
				fputc(fgetc(in),out);

			fclose(in);
			}
		fclose(out);
		}
	}

/**********************************************/
char *makebackupname(char *fn)
	{
	static char backupname[128];

	if (strlen(fn)>100) fn[100]='\0';

	strcpy(backupname,fn);

	if (strrchr(backupname,'.'))
		strcpy(strrchr(backupname,'.')+1,"bak");
	else strcpy(backupname+strlen(backupname),".bak");

	return backupname;
	}

/**********************************************/
void makebackup(char *fn)
	{

	copyfile(makebackupname(fn),fn);
	}


/*************************************************/
/** get a line of text from the file            **/
/** the line is separated by special characters **/
/** defined as STOPCHAR                         **/

char *fgetline(FILE *fp)
	{
	char *w=wordbuf;

	while(!feof(fp) && fgetc(fp)!=STOPCHAR)
		;

	while(!feof(fp) && (w-wordbuf)<10240-1)
		{
		*w++ = fgetc(fp);
		if (w[-1] == STOPCHAR)
			{
			w[-1] = '\0';
			break;
			}
		}
	w[0] = '\0';
	return wordbuf;
	}

/************************************************/
/** scan until a certain character in the file **/

void fscanfor(FILE *fp,char *c)
	{
	while (!feof(fp))
		{
		if (strchr(c,fgetc(fp))) return;
		}
	}
/**********************************************/
/** get a word from the file                 **/

char *fgetword(FILE *fp)
	{
	char *w=wordbuf;
	char c;

	while(!feof(fp))
		{
		c = fgetc(fp);
		if (!isspace(c)) break;
		}

	if (!isspace(c)) *w++ = c;

	while(!feof(fp))
		{
		*w++ = fgetc(fp);
		if (w[-1] == ' ' || isspace(w[-1]))
			{
			w[-1] = '\0';
			break;
			}
		}
	*w = '\0';
	return wordbuf;
	}


/**********************************************/
/** get a word up to a trailing character    **/

char *fgetwordc(FILE *fp, char *t)
	{
	char *w=wordbuf;
	char c;

	while(!feof(fp))
		{
		c = fgetc(fp);
		if (!strchr(t,c)) break;
		}

	if (!strchr(t,c)) *w++ = c;

	while(!feof(fp))
		{
		*w++ = fgetc(fp);
		if (strchr(t,w[-1]))
			{
			w[-1] = '\0';
			break;
			}
		}
	*w = '\0';
	return wordbuf;
	}


/**********************************************/
void htmlchar(char c)
	{
	if (c=='<' || c=='>' || c=='&' || c == 0x0d || (c<32 && c!='\t' && c!=0x0a))
		{
		switch(c)
			{
			case '<':
				printf("&lt;");
				break;
			case '&':
				printf("&amp;");
				break;
			case '>':
				printf("&gt;");
				break;
			default:
				break;
			}
		}
	else printf("%c",c);
	return;
	}

/**********************************************/
void filterfile(char *file)
	{
	FILE *fp;
	char c;

	if (fp=fopen(file,"r"))
		{
		while (!feof(fp))
			{
			c = fgetc(fp);
			htmlchar(c);
			}
		fclose(fp);
		}
	}

/**********************************************/
void editfile(char *file, char *pass)
	{
	FILE *fp;
	int n;
	char c;

	printf("<H1>Edit WWW Page</H1>\n");

	printf("<FORM ACTION=author METHOD=POST ENCTYPE=\"application/x-www-form-urlencoded\"><HR>\n");

	printf("Filename:<BR> <INPUT TYPE=text NAME=openfile VALUE=\"%s\" SIZE=20><BR>\n",file);
	printf("Password:<BR> <INPUT TYPE=password NAME=password VALUE=\"%s\" SIZE=20><BR>\n",pass);

	printf("<HR>");

	printf("<H3>TEXT EDITOR</H3><TEXTAREA ROWS=30 COLS=80 NAME=textbody>");

	filterfile(file);

	printf("</TEXTAREA>");

	printf("<HR><INPUT TYPE=submit VALUE=\"Save\"><INPUT TYPE=reset>\n");
	printf("</FORM><HR>");

	printf("<FORM ACTION=author METHOD=GET ENCTYPE=\"application/x-www-form-urlencoded\">\n");
	printf("<INPUT TYPE=submit VALUE=\"Abort\">\n");
	printf("Quit without saving, returns to Open File page.</FORM><HR>");

	printf("<FORM ACTION=author METHOD=POST ENCTYPE=\"application/x-www-form-urlencoded\">\n");
	printf("<INPUT TYPE=hidden VALUE=%s NAME=REVERT>",file);
	printf("<INPUT TYPE=hidden VALUE=%s NAME=REVERTPASS>",pass);
	printf("<INPUT TYPE=submit VALUE=\"Revert to backup\">\n");
	printf("Revert to older version of file.</FORM><HR>");

	printf("<HR><i>HTML authoring system %s</i> (c) 1994 Takoyaki Software Ltd.",VERSION);


	}

/**********************************************/

#if 0

/* not needed with new system */

char *EncodePassword(char *pass)
	{
	static char newpass[20];
	char pwd[20];
	int n;

	if (strlen(pass)>10) pass[10]='\0';

	if (strlen(pass)<6)
		sprintf(pwd,"%s%s",pass,pass);
	else strcpy(pwd,pass);

	if (strlen(pwd)&1) strcpy(pwd+strlen(pwd),"Z");

	for (n=0;n<strlen(pwd);n+=2)
		{
		newpass[n/2] = (((pwd[n]-32)+pwd[n+1]-32)&31)+65;
		}

	newpass[n/2] = '\0';

	return newpass;
	}

#endif

/**********************************************/
int scanfile(char *fn,char *s)
	{
	int n=0;
	char c;
	FILE *fp;

	if (s[0]=='\0') return 1;

	if (fp = fopen(fn,"r"))
		{

		while (!feof(fp))
			{
			c = fgetc(fp);
			if (s[n] == c)
				{
				n++;
				if (s[n]=='\0')
					{
					c = fgetc(fp);
					fclose(fp);
					if (isalpha(c)) return 0;
					return 1;
					}
				}
			else n=0;
			}
		fclose(fp);
		}
	else return 0;

	return 0;
	}



/**************************************************/
/* add a new host entry or update an existing one */

void addhost(char *hostname, int datalength)
	{
	struct host *h=hosts;

	while (h)
		{
		if (stricmp(hostname,h->name)==0)
			{
			h->count++;
			h->amount += datalength;
			return;
			}
		h=h->next;
		}

	h = calloc(sizeof(struct host),1);

	h->count = 1;
	h->amount = datalength;

	unique_hosts++;

	if (hosts) hosts->prev = h;
	h->next = hosts;
	hosts = h;

	h->name = strdup(hostname);

	}

/**************************************************/

int gifpage(char *pagename)
	{
	char *s;

	if (s = strrchr(pagename,'.'))
		if (strnicmp(s,".gif",4)==0) return 1;

	if (s = strrchr(pagename,'.'))
		if (strnicmp(s,".xbm",4)==0) return 2;

	return 0;
	}

/**************************************************/

void adddate(int year, int month, int day, int hour)
	{
	struct accessdate *d=dates;
	int n;

	while (d)
		{
		if (d->year == year && d->month == month && d->day == day)
			{
			if (d->firsthour>hour) d->firsthour = hour;
			if (d->lasthour<hour) d->lasthour = hour;
			if (d->hourlist[hour] == 0) total_hours++;
			d->hourlist[hour]++;
			return;
			}
		d = d->next;
		}


	d = calloc(sizeof(struct accessdate),1);

	for (n=0;n<23;n++)
		{
		d->hourlist[n] = (n==hour)?1:0;
		}

	d->firsthour = hour;
	d->lasthour = hour;

	d->year = year;
	d->month = month;
	d->day = day;

	total_hours++;

	if (dates) dates->prev = d;
	d->next = dates;
	dates = d;

	}
/**************************************************/
/* add a new page entry or update an existing one */

void addpage(char *pagename, int datalength)
	{
	struct page *p=pages;

	total_data+= datalength;

	while (p)
		{
		if (stricmp(pagename,p->name)==0)
			{
			p->count++;
			p->amount += datalength;
			return;
			}
		p=p->next;
		}

	p = calloc(sizeof(struct page),1);

	p->count = 1;
	p->amount = datalength;

	switch(gifpage(pagename))
		{
		case 0:
			no_of_realpages++;
			unique_pages++;
			break;
		case 1:
			no_of_gifs++;
			break;
			default:
				break;
		}

	if (pages) pages->prev = p;
	p->next = pages;
	pages = p;

	p->name = strdup(pagename);

	}

/**********************************************/


void sortdata(struct host **list)
	{
	struct host *h = *list,*n;
	int passed=1;

	if (!h || !h->next) return;

/* bubble sort the list */

	while (passed)
		{
		passed = 0;
		h = *list;

		while (n = h->next)
			{

			if (n->count > h->count)
				{
/* swap the two entries */
				h->next = n->next;
				n->prev = h->prev;

				n->next = h;
				h->prev = n;

				if (h->next) h->next->prev = h;
				if (n->prev) n->prev->next = n;
				else *list = n;

				n = h;
				passed = 1;
				}
			h = n;
			}

		}

	}

/**********************************************/
void sortdates(struct accessdate **list)
	{
	struct accessdate *h = *list,*n;
	int passed=1;

	if (!h || !h->next) return;

/* bubble sort the list */

	while (passed)
		{
		passed = 0;
		h = *list;

		while (n = h->next)
			{

			if (n->year < h->year ||
				(n->year == h->year && n->month < h->month) ||
				(n->year == h->year && n->month == h->month && n->day < h->day))
				{
/* swap the two entries */
				h->next = n->next;
				n->prev = h->prev;

				n->next = h;
				h->prev = n;

				if (h->next) h->next->prev = h;
				if (n->prev) n->prev->next = n;
				else *list = n;

				n = h;
				passed = 1;
				}
			h = n;
			}

		}

	}
/**********************************************/
/* Load in the logfile and process it         */
/* example of format is as follows:

ccews03.center.osaka-u.ac.jp - - [29/Jan/1995:14:50:47 +0900] "GET /cgi-bin/fleamark?topic=Seeking HTTP/1.0" 200 3878
trinity.llnl.gov - - [29/Jan/1995:14:39:10 +0900] "GET / HTTP/1.0" 200 5244

*/


void loadstats(char *fn)
	{
	FILE *fp;
	char *s;
	char hostname[128];
	char pagename[256];
	unsigned long size;
	int scanforend=0;
	int n,av1,av2,busyhour,busy,busyday,busymonth,busyyear;
	struct page *p;
	struct host *h;
	int year,month,day,hour;
	struct accessdate *d;
	char *months[12] =
		{
		"Jan","Feb","Mar","Apr","May","Jun",
		"Jul","Aug","Sep","Oct","Nov","Dec"
		};


	if (fp = fopen(fn,"r"))
		{

		while (!feof(fp))
			{
			if (scanforend) fscanfor(fp,"\r\n");
			if (feof(fp)) continue;
			scanforend = 1;

			if (!(s = fgetword(fp))) continue;

			strncpy(hostname,s,sizeof(hostname)-1);

/* insert date/time parsing here */

#if 1
			fscanfor(fp,"[");
			if (!(s = fgetword(fp))) continue;
			day = strtol(s,NULL,10);

			if (!strchr(s,'/')) continue;
			s = strchr(s,'/')+1;

/* find out the number of the month */
			for (n=0;n<12 && n>=0;n++)
				if (strnicmp(months[n],s,3) == 0) n = -n-2;

			if (n < 0)
				{
				month = -n;

/* now get the year */

				if (!strchr(s,'/')) continue;
				s = strchr(s,'/')+1;
				year = strtol(s,NULL,10);

/* now get the hour */

				if (!strchr(s,':')) continue;
				s = strchr(s,':')+1;
				hour = strtol(s,NULL,10);

/* add a date entry */


				adddate(year,month,day,hour);

				
				}
#endif

			fscanfor(fp,"]");
			if (feof(fp)) continue;

/* get the command */
			if (!(s = fgetword(fp))) continue;

			if (stricmp("\"GET",s)!=0) continue;

/* get the page name */
			if (!(s = fgetwordc(fp,"\""))) continue;

			if (strchr(s,' ')) *strchr(s,' ') = '\0';

			strncpy(pagename,s,sizeof(pagename)-1);

/* skip code number */
			if (!(s = fgetword(fp))) continue;
/* grab the size of the page in bytes */
			if (!(s = fgetword(fp))) continue;
			size = strtol(s,NULL,10);

			addhost(hostname,size);
			addpage(pagename,size);

			no_of_accesses++;
			scanforend = 0;

			}
		

		
		fclose(fp);
		}
	else
		{
		printf("<HR><H1>Error</H1>No logfile, therefore no data, sorry.<HR>\n");
		return;
		}

	sortdata(&hosts);
	sortdata((struct host **)&pages);
	sortdates(&dates);

	total_hours=0;
	busyhour = 0;
	busy = 0;
	d = dates;
	av1=0;
#if 1
	while (d)
		{
		for (n=d->firsthour;n<=d->lasthour;n++)
			{
			av1 += d->hourlist[n];
			if (d->hourlist[n]>busy)
				{
				busyhour = n;
				busyday = d->day;
				busymonth = d->month;
				busyyear = d->year;
				busy = d->hourlist[n];
				}
			total_hours++;
			}
		d = d->next;
		}

	av1 /= total_hours;
#endif

	gif24hour();

	printf("<TITLE>Kansai-WWW Statistics Page</TITLE>");
	printf("<H1>Kansai-WWW Server Statistics</H1>");

	if (d = dates)
	while (d->next)
		d = d->next;

#if 1
	printf("<I>This information is automatically generated from the current\n"
		"access log which contains data for <B>%d/%d/%d (%d:00) -> %d/%d/%d (%d:00)</B>.</i>\n"
		,dates->year,dates->month,dates->day,dates->firsthour
		,d->year,d->month,d->day,d->lasthour
		);
#endif

	printf("<HR>");

	printf("<H2>GENERAL INFORMATION</H2>");

	printf("<P><B>No. of accesses regardless of type:</B> %lu<BR>\n",no_of_accesses);
	printf("<B>Amount of data sent:</B> %lu(Kb)<BR>\n",total_data/1024);
	printf("<B>No. of unique pages accessed:</B> %lu<BR>\n",unique_pages);
	printf("<B>No. of different surfers connected:</B> %lu<BR>\n",unique_hosts);
	printf("<B>No. of different GIF images downloaded:</B> %lu<BR>\n",no_of_gifs);
	printf("<B>Average no. of accesses per hour:</B> %lu<BR>\n",av1);
	printf("<B>Busiest hour logged with %lu accesses:</B> %lu:00 - %lu:00 (%d/%d/%d)<BR>\n"
		,busy
		,busyhour,(busyhour+1>23)?0:busyhour+1
		,busyyear,busymonth,busyday);

	printf("<P>");

#ifdef GRAPHDISPLAY
	printf("<HR><H2>AVERAGE HOURLY USAGE</H2>");

	printf("<IMG ALIGN=TOP SRC=\"%s\"> <i>(peak=%d accesses)</i><BR>",GIF_24_WWW,average_max);

#endif


/*
	printf("Unique hosts: %lu\n"
		"Unique pages: %lu\n"
		"No. of accesses: %lu\n"
		"No. of real pages: %lu\n"
		"No. of GIFS: %lu\n"
		"Total data: %lu\n"
		,unique_hosts,unique_pages,no_of_accesses,no_of_realpages,no_of_gifs,total_data/1024);
*/

	p = pages;
	n = 1;

	printf("<HR><H2>TOP 20 MOST POPULAR PAGES</H2><OL>");
	while (p && n<21)
		{
		if (gifpage(p->name)==0)
			{
			printf("<LI><A HREF=\"%s\">%s</A> <i>(%lu times)</i>\n",p->name,p->name,p->count);
			n++;
			}
		p = p->next;
		}
	printf("</OL>");


	h = hosts;
	n = 1;

	printf("<HR><H2>TOP 20 NET-SURFING HOSTS</H2><OL>");
	while (h && n<21)
		{
		printf("<LI>%s <i>(%lu times)</i>\n",h->name,h->count);
		n++;
		h = h->next;
		}
	printf("</OL>");

#if 1
	p = pages;
	n = 1;

	printf("<HR><H2>TOP 20 MOST POPULAR GIFS</H2><OL>");
	while (p && n<21)
		{
		if (gifpage(p->name)==1)
			{
			printf("<LI><A HREF=\"%s\">%s</A> <i>(%lu times, %lu bytes)</i>\n",p->name,p->name,p->count,p->amount/p->count);
			n++;
			}
		p = p->next;
		}
	printf("</OL>");

#endif

	printf("<HR><i>(c) 1995 Takoyaki Software Ltd. (%s)</i>",VERSION);

	}

/**********************************************/
/* the starting point of life as we know it   */

main(int argc, char *argv[]) {
	register int x,m=0,n;
	int cl;
	FILE *fp;
	char *cl2;

/* this is a header to say we are going to give Mosaic a html doc */

	printf("Content-type: text/html%c%c",10,10);

/*********************************************************/
/**  Deal with GET requests                             **/
/**                                                     **/
/*********************************************************/

/* Check if its a GET or a POST request */

	if (strcmp(getenv("REQUEST_METHOD"),"POST"))
		{
/* if a GET request the data is sent as an environment variable */

		cl2 = getenv("QUERY_STRING");
		if(cl2 == NULL)
			{
			max = 0;
			}
		else
			{

/* pull the data out of the environment variable */
			cl2 = strdup(cl2);
			for(x=0;cl2[0] != '\0';x++) {
				m=x;
				entries[x].val = makeword(cl2,'&');
				plustospace(entries[x].val);
				unescape_url(entries[x].val);
				entries[x].name = makeword(entries[x].val,'=');
				}
			max = m+1;
			}

		loadstats(LOGFILE);
		return;
		}

/* now to deal with METHOD=POST type requests */

/* make sure the content type is readable by us */

	if(strcmp(getenv("CONTENT_TYPE"),"application/x-www-form-urlencoded")) {
		printf("<HR>There has been an error in the sending of the data.<BR>");
		printf("Please go back to the page and re-send.<HR>");
		printf("If the problem persists contact: <ADDRESS>dylan@takoyaki.demon.co.uk</ADDRESS>");
		exit(1);
		}

/* get the amount of data sent */

	cl = atoi(getenv("CONTENT_LENGTH"));

/* read in each item */

	for(x=0;cl && (!feof(stdin));x++) {
		m=x;
		entries[x].val = fmakeword(stdin,'&',&cl);
		plustospace(entries[x].val);
		unescape_url(entries[x].val);
		entries[x].name = makeword(entries[x].val,'=');
		}
	max = m+1;

/**********************************************************************/
/*  METHOD=POST data manipulation                                     */
/*                                                                    */
/**********************************************************************/


}

/* LE FIN */

