#!/usr/local/bin/perl
# counter.xbm - Perl script to keep count of users of a
# home page.
#
# Credits:
#   Original C code:  Frans van Hoesel (hoesel@chem.rug.nl)
#   Original port to Perl: Dan Rich (drich@corp.sgi.com)
#   Modifications for cgi: Michael Nelson (m.l.nelson@larc.nasa.gov)
#   Modifications for NSF: Mike Morse (mmorse@nsf.gov)
#   Modified from NSF version: Spencer Thomas (spencer.thomas@med.umich.edu)
#   Modified for flexible use: Stefan Powell (spowell@netaccess.on.ca)
#
# Note: This script should be renamed to counter.xbm
#

push(@INC,'/usr/local/etc/httpd/cgi-bin');
require 'cgi-lib.pl';

select STDOUT;
$|=1;

# Suck stuff from httpd
&ReadParse;


   &initialize;
   &incrementCount;     
   if ($ENV{PATH_INFO} && $ENV{PATH_INFO} =~ /.*\/text(\/.*)?/) {
       &writeTextCounter;
   } else {
       &generateBitmap;
       &writeBitmap;
   } 
   exit(0);


sub writeTextCounter {
    print ("Content-type: text/html\n\n");
    print ("<HTML><HEAD><TITLE>Visitor counter</TITLE></HEAD>\n");
    print ("<BODY>You are visitor number <B>$totalReads</B></BODY></HTML>\n");
}

sub writeBitmap {
   print ("Content-type: image/x-xbitmap\n\n");
   if ($isHigh) {
      printf ("#define count_width %d\n#define count_height 16\n", 
              $len*8);
   }
   else {
      printf ("#define count_width %d\n#define count_height 10\n", 
              $len*8);
   }
   printf STDOUT "static char count_bits[] = {\n";
   for($i = 0; $i < ($#bytes + 1); $i++) {
      print("0x$bytes[$i]");
      if ($i != $#bytes) {
         print(",");
         if (($i+1) % 7 == 0) {
            print("\n");
         }
      }
   }
   print("};\n");
}

# generateBitmap() - $count contains number to display
#                    $minLen contains minimum number of digits to display
#                    $isHigh is one for 16 bit high numbers (else 10)
#                    $isInverse is one for reverse video (white on black);
sub generateBitmap {
   $count = $totalReads;
   @bytes = ();
   $len = length($count) > $minLen ? length($count) : $minLen;
   $formattedCount = sprintf("%0${len}d",$count);
   if ($isHigh) {
      for ($i = 0; $i < $len*3; $i++ ) {
         if ($isInverse) {
            push(@bytes,"ff");       # add three blank rows to each digit
         }
         else {
            push(@bytes,"00");
         }
      }
   }
   for ($y=0; $y < 10; $y++) {
       for ($x=0; $x < $len; $x++) {
           $digit = substr($formattedCount,$x,1);
           if ($isInverse) {             # $inv = 1 for inverted text
               $byte = substr(@invdigits[$digit],$y*3,2);
           } 
           else {
               $byte = substr(@digits[$digit],$y*3,2);
           }
           push(@bytes,$byte);
       }
   }
   if ($isHigh) {
      for ($i = 0; $i < $len*3; $i++ ) {
         if ($isInverse) {
            push(@bytes,"ff");       # add three blank rows to each digit
         }
         else {
            push(@bytes,"00");
         }
      }
   }
}


sub initialize {
   $minLen = 7;           # minimum number of digits in bigmap
   $isHigh = 1;           # if 1, digits are 16 pixels high, to
                          # allow room for border
   $isInverse = 1;        # If 1, digits are white on black
   $counterdir = "counters/";
   $remote_host = $ENV{'REMOTE_HOST'};
   if ($#in < 0) {
     $scriptURL = "http://" . $ENV{'SERVER_NAME'} . ":" . $ENV{'SERVER_PORT'} . $ENV{'SCRIPT_NAME'};
     print ("Content-type: text/html\n\n");
     print ("<HTML><HEAD><TITLE>Visitor counter</TITLE></HEAD>\n");
     print ("<BODY><h1>counter.xbm</h1>To put a visitor counter like this \n");
     print ("<IMG SRC=\"$scriptURL?unique_id\">\n");
     print ("on your web page, put an image tag in your HTML document like:<br>\n");
     print ("&lt;IMG SRC=\"$scriptURL?unique_id\"&gt;<br>\n");
     print ("where \"unique_id\" is a unique identifier for your counter.<p>\n");
     print ("When creating a new counter you can set the starting value by adding a count parameter to the URL. So if the counter \"qwerty\" didn't exist, accessing the URL<br>\n");
     print ("$scriptURL?qwerty&COUNT=1234<br>\n");
     print ("will create a new counter called \"qwerty\" with its counter set to 1234.<br>The counter can only be set when creating a new counter.\n");
     print ("<hr></BODY></HTML>\n");
     exit;
   }
   else {
     $countername = $in[0];
     $countername =~ s/\W//g;
     $counterFile = $counterdir . $countername;
     if (!( -f $counterFile )) {
       $start = $in{'COUNT'} -1;
       open(CNTRFILE,">$counterFile");
       print CNTRFILE "$start\n";
       close(CNTRFILE);
     }
   }

   $lockWait = 5;         # number of seconds to wait for lock
   # bitmap for each digit
   #  Each digit is 8 pixels wide, 10 high
   #  @invdigits are white on black, @digits black on white
   @invdigits = ("c3 99 99 99 99 99 99 99 99 c3",  # 0
                 "cf c7 cf cf cf cf cf cf cf c7",  # 1
                 "c3 99 9f 9f cf e7 f3 f9 f9 81",  # 2
                 "c3 99 9f 9f c7 9f 9f 9f 99 c3",  # 3
                 "cf cf c7 c7 cb cb cd 81 cf 87",  # 4
                 "81 f9 f9 f9 c1 9f 9f 9f 99 c3",  # 5
                 "c7 f3 f9 f9 c1 99 99 99 99 c3",  # 6
                 "81 99 9f 9f cf cf e7 e7 f3 f3",  # 7
                 "c3 99 99 99 c3 99 99 99 99 c3",  # 8
                 "c3 99 99 99 99 83 9f 9f cf e3"); # 9
   
   
      @digits = ("3c 66 66 66 66 66 66 66 66 3c",  # 0
                 "30 38 30 30 30 30 30 30 30 30",  # 1
                 "3c 66 60 60 30 18 0c 06 06 7e",  # 2
                 "3c 66 60 60 38 60 60 60 66 3c",  # 3
                 "30 30 38 38 34 34 32 7e 30 78",  # 4
                 "7e 06 06 06 3e 60 60 60 66 3c",  # 5
                 "38 0c 06 06 3e 66 66 66 66 3c",  # 6
                 "7e 66 60 60 30 30 18 18 0c 0c",  # 7
                 "3c 66 66 66 3c 66 66 66 66 3c",  # 8
                 "3c 66 66 66 66 7c 60 60 30 1c"); # 9
}

sub incrementCount {
   if (&lockFile == 1) {
      $count = "0";
      return;
   }
   &incrementTotalReads;
   &unlockFile;
}


sub unlockFile {
   unlink("$counterFile.lock");
}

sub lockFile {
   $lockCount = 0;
   while (-f "$counterFile.lock") { 
      if ($lockCount > $lockWait) {
         $count = 0;
         return 1;             # forget it (would be nice to log though)
      }
      sleep 1; 
      $lockCount++;
   }
   open(LOCK,">$counterFile.lock") || die("Can't open $counterFile.lock: $!\n");
   return 0;
}



sub incrementTotalReads {
   if (-e $counterFile) {
     open(COUNT,"$counterFile") || die("Can't open $counterFile: $!\n");
   }
   $totalReads = <COUNT>;
   chop $totalReads;
   close(COUNT);
   
   $totalReads++ if $remote_host ne "kite.netcom.com";
   
   open(COUNT,">$counterFile") || die "$0: can\'t open $counterFile: $!\n";
   print (COUNT "$totalReads\n");
   close(COUNT);
}
