#!/usr/bin/perl # Guestbook program (version 1.14) # # Copyright 2001-2002 Felippe Mora use 5.004; # as written needs Perl 5.004 or later use strict; # enforce declarations and quoting use CGI qw(:standard); # import shortcuts use Fcntl qw(:flock); # imports LOCK_EX, LOCK_SH, LOCK_NB $| = 1; my ( $URL, $GUESTFILE, $MAXSAVE, $PERPAGE, $BLOCKIMAGES, $CAPITALIZE, $TITLE, $WELCOME, $BGIMAGE, $BGCOLOR, $FORMCOLOR, $ERRCOLOR, $HOURADJUST, $TZONE, $new, # new entry in the guestbook @entries, # holds all entries $entry, # one particular entry $timestamp, # date and time (adjustable for different timezones) $ip, $remotehost, # IP, DNS address of message sender $link, # email or URL of guest $formatted_message, # message with HTML line breaks inserted $count, # total number of messages $number, # message being displayed $page, $newpage, # page number being displayed, new page to display $next, $remaining, # number of previous messages on next page, remaining $sorry, # error message regarding user entry ); ### site defaults $GUESTFILE = "guestbook"; # name of guestbook file $MAXSAVE = 100; # how many messages to save $PERPAGE = 20; # how many messages per page $BLOCKIMAGES = 0; # block inline images from messages $CAPITALIZE = 1; # capitalize names $TITLE = "Cousins Picninc's Guestbook"; # page title $WELCOME = "The NEW Cousins Picnic's Guestbook:"; #

$WELCOME

$BGIMAGE = ''; $BGCOLOR = 'green'; # overall background color $FORMCOLOR = '#ffff00'; # background color for input form $ERRCOLOR = 'red'; # font color for error messages $HOURADJUST = 0; # add this local hour $TZONE = 'EST'; # to display this time zone # # automatically adjusts for ### # daylight savings (EST -> EDT, etc) print header, start_html(-TITLE => $TITLE, -BACKGROUND => $BGIMAGE, -BGCOLOR => "$BGCOLOR"), h2($WELCOME); $new = CGI->new(); # get request $URL = $new->script_name(); # capture script URL greet($new->param("name")); # greet any special visitors if ($CAPITALIZE) { # capatalize visitors name my $name = $new->param("name"); $name =~ s/(\w+)/\u$1/g; $new->param("name",$name); } if ($new->param("message") =~ m/\S/) { # new (non-null) message if ($BLOCKIMAGES && $new->param("message") =~ m/<\s*IMG\s*.*SRC\s*=/i) { $sorry = 'Sorry, you cannot embed images in messages.'; } elsif (!($new->param("name") =~ m/\S/)) { $sorry = 'You have to enter a name to send a message.'. ' [Be creative and make one up.]'; } else { $timestamp = get_time(); $new->param("date", $timestamp); # set the current date/time $new->param("agent",$ENV{'HTTP_USER_AGENT'}); # save remote agent $ip = $ENV{'REMOTE_HOST'}; # save remote host address $remotehost = hostname($ip) || $ip; $new->param("host", $remotehost); @entries = ($new); # save message to array }; }; # open the file for read-write (preserving old contents) if (-e $GUESTFILE) { open(CHANDLE, "+< $GUESTFILE") || bail("cannot open $GUESTFILE: $!"); } else { open(CHANDLE, "+> $GUESTFILE") || bail("cannot open $GUESTFILE: $!"); } # get exclusive lock on the guestbook flock(CHANDLE, LOCK_EX) || bail("cannot flock $GUESTFILE: $!"); # grab up to $MAXSAVE old entries, newset first while (!eof(CHANDLE) && @entries < $MAXSAVE) { $entry = CGI->new(\*CHANDLE); # pass the filehandle by reference push @entries, $entry; $count++; } seek(CHANDLE, 0, 0) || bail("cannot rewind $GUESTFILE: !"); foreach $entry (@entries) { $entry->save(\*CHANDLE); # pass the filehandle by reference } truncate(CHANDLE, tell(CHANDLE)) || bail("cannot truncate $GUESTFILE: $!"); close(CHANDLE) || bail("cannot close $GUESTFILE: $!"); print hr; # table around table produces a colored border in Netscape print "All messages should now be posted in the Forums

View entries form the OLD Guestbook\n"; print hr; print "
$sorry
", hr if ($sorry); # display user entry error message $page = $new->param("page") || 1; # get page to be displayed if ($page > 1) { # print "go back" message if needed $newpage = $page-1; print "
Show $PERPAGE more recent messages

\n"; } $number=0; foreach $entry (@entries) { if (($page-1)*$PERPAGE <= $number) { # display only the proper if ($number < $page*$PERPAGE) { # number of messages for each page $formatted_message = $entry->param("message"); $formatted_message =~ s/(.+)\n/$1
/g; # preserve line breaks $link = $entry->param("email"); if ($link) { if ($link =~ m/@/) { printf ("%s\n", $link, $entry->param("name")); } else { $link =~ s/^http:(\/\/|\\)//; printf ("%s\n", $link, $entry->param("name")); }; } else { printf ("%s\n", $entry->param("name")); }; printf (" %s

%s\n", $entry->param("date"), $formatted_message ); # this is another way to preserve line breaks, but it doesn't look as nice: # printf (" %s

%s
\n", # $entry->param("date"), # $entry->param("message")); print hr; }; }; $number++; } $remaining = $count-$PERPAGE*$page; # number of older messages if ($remaining > 0) { if ($remaining < $PERPAGE) { # determine number on next page $next = $remaining; } else { $next = $PERPAGE; }; $newpage = $page + 1 ; # next page number print "
Show $next of $remaining earlier messages

\n"; }; ### uncomment these lines to add a VersaCounter to page # (adjust directory paths and options as necessary) #{ #local $ENV{'DOCUMENT_URI'} = '/cgi-bin/guestbk'; # page name #local $ENV{'REQUEST_METHOD'} = 'GET'; # ensure GET method #local $ENV{'QUERY_STRING'} = 'header=0&show=nothing'; # counter options #print `/usr/local/www/cgi-bin/counter`; # call counter #} ### print end_html; sub greet { my %special = ( 'bill clinton' => 'Thank you, Mr. President' ); foreach (keys %special) { $sorry = $special{$_} if ($_[0] =~ m/$_/i); }; } sub get_time { my ( $sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$dst, @months ); @months = ("January","February","March","April","May","June","July", "August","September","October","November","December"); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$dst) = localtime(time()+$HOURADJUST*3600); if ($hour < 10) { $hour = '0'.$hour; } if ($min < 10) { $min = '0'.$min; } if ($sec < 10) { $sec = '0'.$sec; } $year += 1900; # Y2K OK! $TZONE =~ tr/S/D/ if ($dst); # fix time zone string for daylight savings return $timestamp = "$months[$mon] $mday, $year $hour:$min:$sec ($TZONE)"; } sub hostname { my (@bytes, $packedaddr, $host_name ); @bytes = split(/\./, $_[0]); $packedaddr = pack("C4",@bytes); $host_name = (gethostbyaddr($packedaddr, 2))[0]; return($host_name); } sub bail { # print errors directly to browser my $error = "@_"; print h1("Error:"), p($error), end_html; die $error; }