#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define PLAIN
#define DATASIZE 256

static const char *ua[] = 
{
    "mozilla", "msie", "chimera", "iexplore", "opera",
    "links", "lynx", "w3m" "amaya", "avant", "ncsa",
    "dillo", "gnome-vfs", "java", "jakarta",
    "coldfusion", "go!zilla", "gozilla", "netants",
    "nokia", "panasonic", 0
};

int main(int argc, const char *argv[])
{
    char *ip = 0;
    const char *fn = 0;
    char buffer[16];
    unsigned long data[DATASIZE];
    unsigned long addr = 0, i, j;
    int file;
    
    printf("Content-type: text/plain\n\n");

    /* Extract filename from end of query */
    fn = getenv("QUERY_STRING");
    if(!fn)
    {
	printf("No filename\n");
	return -1;
    }
    while(*fn && (*fn<'a' || *fn>'z')) fn++;
    if(!*fn) fn = 0;
    else
      for(i=0;fn[i];i++)
	if(i>32 || fn[i]<'a' || fn[i]>'z')
	  fn = 0;
    if(!fn)
    {
	printf("Invalid filename\n");
	return -1;
    }

    /* Open data file */
    chdir("/var/www/counters");
    file = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
    if(file==-1)
    {
	printf("File error\n");
	return -1;
    }

    memset(data, 0, sizeof(data));

    j = 0;
    while(i = read(file, ((unsigned char*)data)+j, sizeof(data)-j))
    {
	if(i>0)
	  j += i;
	else if(errno!=EINTR)
	{
	    printf("Read error\n");
	    return -1;
	}
    }

    /* Check that this is a valid useragent. */
    fn = getenv("USER_AGENT");
    if(fn)
      for(i=0;ua[i];i++)
        if(strncasecmp(fn, ua[i], strlen(ua[i])) == 0)
          break;
    if(fn && ua[i]!=0)
    {  
        /* Extract remote host IP addr */
        ip = getenv("HTTP_X_FORWARDED_FOR");
        if(!ip) ip = getenv("REMOTE_ADDR");
        if(!ip)
        {
            printf("No remote IP\n");
            return -1;
        }
        
        /* Convert IP string to 32-bit number */
        while(*ip)
        {
            addr = (addr << 8) + strtol(ip, &ip, 10);
            while(*ip && (*ip<'0' || *ip>'9')) ip++;
        }    
        
        /* Search through the datafile for this IP address */
        for(i=1;i<DATASIZE;i++)
          if(data[i]==addr)
            break;
        
        /* If it wasn't found, update and write the file */
        if(i==DATASIZE)
        {
            data[data[0]%(DATASIZE-1)+1] = addr;
            data[0]++;
            lseek(file, SEEK_SET, 0);
            
            j = 0;
            while(i = write(file, ((unsigned char*)data)+j, sizeof(data)-j))
            {
                if(i>0)
                  j += i;
                else if(errno!=EINTR)
                {
                    printf("Write error\n");
                    return -1;
                }
            }
        }
    }

#ifdef PLAIN
    printf("%d\n", data[0]);
#else
    switch(data[0]%100)
    {
     case 11:
     case 12:
     case 13:
	printf("%dth\n", data[0]);
     default:
	switch(data[0]%10)
	{
	 case 1: printf("%dst\n", data[0]); break;
	 case 2: printf("%dnd\n", data[0]); break;
	 case 3: printf("%drd\n", data[0]); break;
	 default: printf("%dth\n", data[0]); break;
	}
    }
#endif
    
    return 0;
}
