use strict;
use CGI qw(:standard :html3 escape unescape);
use Apache::Constants qw(:common);
use Apache::File ();
use Apache::Util qw(ht_time escape_uri unescape_uri escape_html);
use Fcntl qw( :DEFAULT :flock );
use POSIX qw(strftime);
use DB_File;
use vars qw(@FIELDS %REQUIRED $GUESTBOOKFILE %HoA);
local *DBM;
@FIELDS = qw(First_Name Last_Name
Email_Address1 Email_Address2 Website
Home_Phone Work_Phone Cell_Phone Other_Phone
Street_Address1 Street_Address2 City State Zip
Country Birthday Gender);
sub write_guestbook {
unless (TieLock($GUESTBOOKFILE, 1)) {
print strong('Sorry, an error occurred: unable to open ' . $GUESTBOOKFILE),p();
return;
}
my $i = param("HoAindex"); # check for an update
unless ($i) {
## increment the sequencer.
$HoA{sequence} = 0 unless exists $HoA{sequence};
$i = ++$HoA{sequence};
}
my $date = strftime('%d-%b-%Y %R',localtime);
$HoA{$i} = join(">", ($date), map {escape(param($_))} (@FIELDS));
unTieLock($GUESTBOOKFILE);
return( "Thank you ". param('First_Name')
.", for signing the guestbook.");
}
sub delete_guestbook {
unless (TieLock($GUESTBOOKFILE, 1)) {
print strong('Sorry, an error occurred: unable to open ' . $GUESTBOOKFILE),p();
return;
}
my $i = param("HoAindex"); # get the delete index
unless ($i) {
print strong('Sorry, an error occurred: unable to get entry index ' . $GUESTBOOKFILE),p();
return;
}
delete $HoA{$i};
unTieLock($GUESTBOOKFILE);
return( "Thank you ". param('First_Name')
.", your delete has been completed.");
}
sub load_address {
my $fname = param('First_Name');
my $lname = param('Last_Name');
my $return_msg;
unless (TieLock($GUESTBOOKFILE, 0)) {
print strong('Sorry, an error occurred: unable to open ' . $GUESTBOOKFILE),p();
return;
}
my @data;
for my $addr (sort keys %HoA) {
@data = map {unescape($_)} split( ">", $HoA{$addr}, 18);
$data[0] = $addr; #overlay the date with the key.
last if ($fname eq $data[1]) && ($lname eq $data[2]);
if ($data[0] eq "sequence") {
@data = ();
$return_msg = "Sorry ". param('First_Name')
.", but your existing entry has not been found.";
}
}
unTieLock($GUESTBOOKFILE);
return ($return_msg, @data);
}
sub view_guestbook {
my $guestbook;
my @rows;
unless (TieLock($GUESTBOOKFILE, 0)) {
print strong('Sorry, an error occurred: unable to open ' . $GUESTBOOKFILE),p();
return;
}
for my $addr (sort keys %HoA) {
next if $addr eq "sequence";
my @data = map {unescape($_)." "} split( ">", $HoA{$addr}, 18);
unshift @rows, td(\@data);
}
unshift @rows, th(['Entry Date',@FIELDS]);
$guestbook .= p(
table({-border=>'1', -hspace=>'5',
-cellspacing=>'1', -cellpadding=>'4'},
TR(\@rows)));
unTieLock($GUESTBOOKFILE);
return ($guestbook);
}
sub TieLock { # tie and lock the dbm file.
my $path = shift;
my $for_writing = shift;
my $lock_type;
if ($for_writing) {
$lock_type = LOCK_EX;
}
else {
$lock_type = LOCK_SH;
}
my $db = tie %HoA, 'DB_File', $path, O_RDWR | O_CREAT, 0666, $DB_HASH
or die "[Error processing $path ] $!";
my $fd = $db->fd;
open DBM, "+<&=$fd" or die "Could not dup DBM for lock: $!";
# now try to lock it
my $success;
my $tries = 0;
while ($tries++ < 10) {
last if $success = flock (DBM, $lock_type|LOCK_NB);
print p("Waiting for $lock_type lock on AddressBook file...");
sleep(1); # wait a second
}
undef $db;
unless ($success) {
warn("Couldn't get lock for $lock_type");
return;
}
return 1;
}
sub unTieLock { # untie the dbm file.
untie %HoA;
close DBM;
}