#!/usr/local/bin/perl
#
# AUTOKEEN LITE - v0.924
#
# Brought to you by the fine people at Keenspot (http://www.keenspot.com)
#
# Autokeen Lite is a comic strip archive system, programmed by Darren Bleuel
# (gav@nukees.com).  It is fully public domain and open source.  I ask that
# if you make changes to this script, you not remove my name or Keenspot's
# from these comment lines, and that you drop me a line about your changes,
# if they are significant.
#
#
# Installation of Autokeen Lite requires that your webhost allows cgi
# scripts.  Download this program to your cgi directory and configure 
# the "SETUP VARIABLES" below to correspond to your system.
#
# HAVE A SUPER KEEN DAY!
#
# Other info:
# Please note that I learned perl programming from a reference manual, not a
# programming manual, so some routines may seem less than perfectly efficient.
# I don't know how compatible this code will be with operating systems other
# than Linux or Unix.  I'd appreciate feedback in this area.

#
# SETUP VARIABLES
# ---------------
#

# The following is the absolute pathname to your account space where your
# html files are installed.
$path = "/home/nukees/public_html/";

# $webpath is the path relative to your home directory on your website.
$url = "http://www.nukees.com/";

# This is the directory, relative to "$path", where your comics are stored,
# if stored locally. 
$comicdir = "comics/";

# This is the directory, relative to "$url", from where this program will be
# run.
$cgidir = "cgi-bin/";

# This is the directory, relative to "$path", where your images are stored
# for the "forward" and "backward" buttons, etc.  (See README.txt for more)
$imagedir = "images/";

# Here are some other options that can be customized if you really feel it's
# necessary.  See manual for further details.
$dailytemplate = "dailytemplate.html";
$indextemplate = "indextemplate.html";
$storylinefile = "storylines.txt";

# This is the number of hours by which your system clock will be adjusted
# if in a different time zone (Example: +3 will adjust from PST to EST).
$timeoffset = 0;

# START OF PROGRAM
# ----------------
#
# Don't change anything below this line unless you know what you're doing.
#-----------------------------------------------------------------------------

$programname = $0;
$programname =~ s/.*(\/|\\)//;
$path .= "/" if ($path !~ /(\/|\\)$/);
$comicdir .= "/" if ($comicdir !~ /(\/|\\)$/);
$cgidir .= "/" if ($cgidir !~ /(\/|\\)$/);
$imagedir .= "/" if ($imagedir !~ /(\/|\\)$/);
$url .= "/" if ($url !~ /(\/|\\)$/);

# I'm sure there was a more elegant way to do the above, but what the hell
# do I care?

print "Content-type: text/html\r\n\r\n";
 
$timenow = time();
($sec,$min,$hour,$day,$month,$year) = (localtime($timenow+(3600*$timeoffset)))[0,1,2,3,4,5];

$month = "0".$month if (++$month < 10); 
$day = "0".$day if ($day < 10);
$year += 1900;
$sec = "0".$sec if ($sec < 10);
$min = "0".$min if ($min < 10);

$truetoday = $year.$month.$day;

%tags = ("***comic***" => "todays_comics",
	 "***date***" => "echodate",
	 "***year***" => "echoyear",
	 "***month***" => "echomonth",
	 "***day***" => "echoday",
	 "***dayofweek***" => "echodayofweek",
	 "***next***" => "nextday",
	 "***previous***" => "prevday",
	 "***first***" => "firstday",
	 "***last***" => "lastday",
	 "***storylines***" => "sldropdown");

@taglist = keys(%tags);

$qs = $ENV{'QUERY_STRING'};
@qs = split(/&/,$qs);
foreach $i (0..$#qs) {
    $qs[$i] =~ s/\+/ /g;
    $qs[$i] =~ s/%(..)/pack("c",hex($1))/ge;
    ($name, $value) = split(/=/,$qs[$i],2);
    $qs{$name} = $value;
}

$strip = $qs{"strip"};
$date = $qs{"date"};

$date = $qs if ($date eq "" && $strip eq "");

if (opendir(DIR, "$path$comicdir")) {
    @files = readdir(DIR);
    closedir DIR;
} else {
    print "can't opendir $path$comicdir: $!";
    exit;
}

@comics = sort {($a =~ /^\D*(\d+)/)[0] <=> ($b =~ /^\D*(\d+)/)[0] || ($a =~ /^\D*(\d+.*)\./)[0] cmp ($b =~ /^\D*(\d+.*)\./)[0] || $a cmp $b} @files;

$ncom = $#comics;
$j = 0;

for ($i = 0; $i <= $ncom; $i++) {
    ($comicdates[$i-$j] = $comics[$i-$j]) =~ s/\D*(\d*)?.*/$1/;
    if ($comics[$i-$j] =~ /\d+.*\.(gif|jpg|html|GIF|JPG|HTML|htm|HTM|txt|TXT)$/ && $comicdates[$i-$j] <= $truetoday) {
	$comichash{$comicdates[$i-$j]} = $i-$j if ($comicdates[$i-$j] ne $lastdate);
	$lastdate = $comicdates[$i-$j];
    }
    else {
	splice (@comics, $i-$j++, 1);
    }
}

splice (@comicdates, $#comicdates, 1) if ($comicdates[-1] > $truetoday);

$today = $date;
($today = $strip) =~ s/\D*(\d+)?.*/$1/ if ($today eq "");
$today = $comicdates[$#comics] if ($today eq "");
$infile = "$path$dailytemplate";
$infile = "$path$indextemplate" if ($today eq $comicdates[$#comics]);

parsetags($infile,"-");

sub parsetags {
    my $infile = $_[0];
    my $outfile = $_[1];
    if (open(FILE, $infile)) {
	my $page = "";
	while (<FILE>) {
	    my $line = $_;
	    foreach $tag (@taglist) {
		if ($line =~ /\Q$tag\E/) {
		    $subr = $tags{$tag};
		    $replace = &$subr;
		    $line =~ s/\Q$tag\E/$replace/g;
		}
	    }
	    $page .= $line;
	}

	open(OUTFILE, ">$outfile") ? (print OUTFILE $page) : (print ("$outfile could not be opened for writing.\n"));
	close(OUTFILE);
	close(FILE);
    }
    else {
	print "$infile could not be opened for reading\n";
    }
}

# The following subroutine, "dayofweek" can return three different values,
# depending on the second arguement:
#
# 0: Normal operation.  Returns the Day of Week (Sunday, Monday, etc).
# 1: Returns the Day of Week as a numeral (Sun=0, Mon=1, etc).
# 2: Returns the number of days since 1/1/1968
#
# First arguement is the date, in YYYYMMDD format

sub dayofweek {
    my $daytab = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
		  [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]];
    my @daynames = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
    my $date = $_[0];
    my $flag = $_[1];
    my $year = substr($date,0,length($date)-4);
    my $month = substr($date,length($date)-4,2)-1;
    my $day = substr($date,length($date)-2,2);
    $day += $$daytab[leapyear($year)][$month] while (--$month>=0);
    $day += (365 + leapyear($year)) while (--$year>=1968);
    if ($flag == 0) {
	return $daynames[$day%7];
    }
    elsif ($flag == 1) {
	return $day%7;
    }
    else {
	return $day;
    }
}

# Note:  It has not been "offically" adopted that the year 4000 will not be a
# leap year, as would be logical by our current leap year rules.  However, I
# expect that this rule will be adopted if civilization, calendars, and/or 
# this program still exist in the year 4000, and therefore I have made the 
# following routine Y4K compliant.

sub leapyear {
    return ($_[0]%4 == 0 && $_[0]%100 !=0 || $_[0]%400 == 0 && $_[0]%4000 != 0)
    }

sub days2date {
    my $daytab = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
		  [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]];
    my $day = $_[0];
    my $year = 1968;
    my $month = 0;
    $day -= (365 + leapyear($year++)) while ($day-(365+leapyear($year))>0);
    $day -= $$daytab[leapyear($year)][$month++] while ($day-$$daytab[leapyear($year)][$month] > 0);
    $month++;
    $day = "0".$day if ($day < 10);
    $month = "0".$month if ($month < 10);
    return $year.$month.$day;
}

sub gifdim ($) {
    my $filename = $_[0];
    
    open(GIF, $filename) || (warn "$filename not readable\n" && return undef, undef);
    my $buf = '';
    my $n = read GIF, $buf, 10;
    close GIF;

    return (undef, undef) if $n < 10;
    my ($head, $width, $height) = unpack("A6vv", $buf);
    return (undef, undef) unless $head =~ /^GIF8[79]a/;
    return ($height,$width);
}

#----------------------------------------------------------------------------#
# jpegsize : gets the width and height (in pixels) of a jpeg file
# Andrew Tong, werdna@ugcs.caltech.edu           February 14, 1995
# modified slightly by alex@ed.ac.uk, and again by gav@nuc.berkeley.edu
sub jpegSize {
  my ($filename) = @_;
  my ($done) = 0;
  my ($height) = 0;
  my ($width) = 0;

  open(JPEG, $filename) || (warn "$filename not readable\n" && return undef, undef);

  read(JPEG, $c1, 1); read(JPEG, $c2, 1);
  if( !((ord($c1) == 0xFF) && (ord($c2) == 0xD8))){
    print "This is not a JPEG!";
    $done=1;
  }
  while (ord($ch) != 0xDA && !$done) {
    # Find next marker (JPEG markers begin with 0xFF)
    # This can hang the program!!
    while (ord($ch) != 0xFF) {  read(JPEG, $ch, 1); }
    # JPEG markers can be padded with unlimited 0xFF's
    while (ord($ch) == 0xFF) { read(JPEG, $ch, 1); }
    # Now, $ch contains the value of the marker.
    if ((ord($ch) >= 0xC0) && (ord($ch) <= 0xC3)) {
      read (JPEG, $junk, 3); read(JPEG, $s, 4);
      ($a,$b,$c,$d)=unpack("C"x4,$s);
      $height = $a<<8|$b;
      $width = $c<<8|$d;
      $done=1;
    } else {
      # We **MUST** skip variables, since FF's within variable names are
      # NOT valid JPEG markers
      read (JPEG, $s, 2); 
      ($c1, $c2) = unpack("C"x2,$s); 
      $length = $c1<<8|$c2;
      if( ($length < 2) ){
	  print "Erroneous JPEG marker length";
	  $done=1;
      } else {
	  read(JPEG, $junk, $length-2);
      }
  }
}
  return ($height,$width);
}
#----------------------------------------------------------------------------#


sub echocomic {
    my $text = "";
    if (-f "$path$comicdir$comicfile") {
	if ($comicfile =~ /(gif|GIF)$/) {
	    ($heightref, $widthref) = gifdim("$path$comicdir$comicfile");
	    $text .= "<IMG ALT=\"Today\'s Comic\" BORDER=0 SRC=\"$url$comicdir$comicfile\" WIDTH=\"" . $widthref . "\" HEIGHT=\"" . $heightref . "\"> ";
	}
	elsif ($comicfile =~ /(jpg|JPG)$/) {
	    ($heightref, $widthref) = jpegSize("$path$comicdir$comicfile");
	    $text .= "<IMG ALT=\"Today\'s Comics\" BORDER=0 SRC=\"$url$comicdir$comicfile\" WIDTH=\"$widthref\" HEIGHT=\"$heightref\"> ";
	}
	elsif ($comicfile =~ /(html|HTML|txt|TXT|htm|HTM)$/) {
	    if (!(open(HTMLFILE, "$path$comicdir$comicfile"))) {
		print "$path$comicdir$comicfile not readable.";
		exit;
	    }
	    while (<HTMLFILE>) {
		$text .= $_;
	    }
	    close(HTMLFILE);
	}
	return $text;
    }
    else {
	print "$path$comicdir$comicfile not readable.\n";
	return "";
    }
}

sub todays_comics {
    my $text = "";
    my $next = "";
    my $i = $comichash{$today};
    local $comicfile = $comics[$i];
    while ($comicdates[$i] eq $today && $i <= $#comics) {
	$text .= echocomic();
	$comicfile = $comics[++$i];
    }
    return $text;

}

sub showdaytag {
    my $file = $_[0];
    my $alt = $_[1];
    my $imagefile = "$file.gif";
    (my $height, my $width) = gifdim("$path$imagedir$file.gif") if (-f "$path$imagedir$file.gif");
    if (-f "$path$imagedir$file.jpg") {
	$imagefile = "$file.jpg";
	($height, $width) = jpegSize("$path$imagedir$file.jpg") if (-f "$path$imagedir$file.jpg");
    }
    $height ? return qq~<a href="$link"><img border=0 alt="$alt" src="$url$imagedir$imagefile" width=$width height=$height></a>~ : return qq~<a href="$link">$alt</a>~;
}

sub firstday {
    my $firstdate = $comicdates[0];
    return "" if ($firstdate >= $today);
    local $link = "$url$cgidir$programname\?date=$firstdate";
    return showdaytag("firstday","The First Comic");
}

sub prevday {
    my $j=$#comics;
    do {
	$prevdate = $comicdates[$j--];
    } until ($prevdate < $today || $j < 0);
    return "" if ($today <= $prevdate);
    local $link = "$url$cgidir$programname\?date=$prevdate";
    return showdaytag("previousday","Previous Comic");
}

sub nextday {
    my $j=0;
    do {
	$nextdate = $comicdates[$j++];
    } until ($nextdate > $today || $j > $#comics);
    return "" if ($today >= $nextdate);
#    my $nextdate = $comicdates[$comichash[$today]+1];
    local $link = "$url$cgidir$programname\?date=$nextdate";
    return showdaytag("nextday","Next Comic");
}

sub lastday {
    my $lastdate = $comicdates[$#comics];
    return "" if ($lastdate <= $today);
    local $link = "$url$cgidir$programname\?date=$lastdate";
    return showdaytag("lastday","Today\'s Comic");
}

sub echodate {
    my $mo = echomonth();
    my $yr = echoyear();
    my $dy = echoday();
    my $dw = dayofweek($today,0);
    return "$dw, $mo $dy, $yr";
}

sub echomonth {
    my @monthnames = (January, February, March, April, May, June, July, August,
		   September, October, November, December);
    return $monthnames[substr($today,length($today)-4,2)-1];
}

sub echoyear {
    return substr($today,0,length($today)-4);
}

sub echoday {
    return substr($today,length($today)-2,2)+0;
}

sub echodayofweek {
    return dayofweek($today,0);
}

sub sldropdown {
    my $text = "$path$storylinefile";
    if (open (DROPDOWN, "$path$storylinefile")) {
	$text = "<table border=0 cellspacing=0 cellpadding=0><td><form method=GET name=storyline action=$url$cgidir$programname><select name=\"date\">\n";
	my $flag = 0;
	while (<DROPDOWN>) {
	    my $line = $_;
	    chomp $line;
	    ($date = $line) =~ s/.*,(.*)/$1/;
	    ($desc = $line) =~ s/(.*),.*/$1/;
	    $date =~ s/ //;
	    if ($date =~ /\//) {
		my @dayparts = split /\//, $date;
		$dayparts[0] = "0".$dayparts[0] if ($dayparts[0] < 10);
		$dayparts[1] = "0".$dayparts[1] if ($dayparts[1] < 10);
		$date = $dayparts[2].$dayparts[0].$dayparts[1];
	    }
	    $date =~ s/\D*//g;
	    my $fromday = "";
	    if ($today < $date && $date != 0 && $flag == 0) {
		$text =~ s/\">(.*)<\/option>\n$/\" SELECTED>$1<\/option>\n/;
		$flag = 1;
	    }
	    $text .= "<option value=\"$date\">$desc</option>\n";
	}
	$text =~ s/\">(.*)<\/option>\n$/\" SELECTED>$1<\/option>\n/ if ($flag == 0);
	$text.="</select>&nbsp;<input type=submit value=\"Go\"></td></form></table>\n";
    }
    return $text;
}
