#!/usr/bin/perl
#
#Usage:
#
#TO ACCESS THE FORM:
#
#1: Sign Our Guestbook
#
#2:
#
#
#TO ACCESS THE BOOK:
#
#1: View Our Guestbook
#
#2:
#
######################################################################
### PURPOSE: DEFINE USER VARIABLES ###
######################################################################
#---enter physical directory paths-----------------------------------#
$fullLogPath ='/usr/home/sal/velvetblue/guestbook/guestbook.dat';
$fullLockPath ='/usr/home/sal/velvetblue/guestbook/guestbook.lock';
$BackupDataPath ='/usr/home/sal/velvetblue/guestbook/backup.dat';
$ScriptName ='http://www.velvetblue.com/guestbook/guestbook.cgi';
#---personal variables alter at will---------------------------------#
$SiteName ='Velvet Blue';
$MaxEntriesBeforeBackupStops ='200';
$BackupInterval ='20';
$SMTPHost ='velvetblue.com';
$SMTPPort ='25';
$MailEntryTo ='sitesubmit@velvetblue.com';
$MailSubject ="New $SiteName Guestbook Entry";
#---options: 0 for off 1 for on--------------------------------------#
$FilterProfanity =0;
$EmailNewEntries =0;
$EmailHTML =0;
$NoOutsideAccess =0;
$OneEntryPerHour =0;
$AllowHTML =0;
######################################################################
### PURPOSE: SET THE SCRIPT VARIABLES ###
######################################################################
#---script variables do not alter------------------------------------#
$In = "$ENV{'QUERY_STRING'}";
$ThisHost = "$ENV{'REMOTE_HOST'}";
$Version = "2.0";
@ReferingPage =split (/\//,$ENV{HTTP_REFERER});
$ServerName = "$ENV{'SERVER_NAME'}";
$BackupName = "guestbak";
#---no Access if called outside server-------------------------------#
if ($ServerName ne @ReferingPage[2] && $NoOutsideAccess){&NoAccess;}
######################################################################
### PURPOSE: NO OUTSIDE SERVER ACCESS ###
######################################################################
#--------------------------------------------------------------------#
sub NoAccess {
print "Content-type: text/html\n\n";
print qq~
Access Denied:
You have no permission to access this script from your server.
~;
exit;
}
######################################################################
### PURPOSE: CALL THE SUBROUTINES ###
######################################################################
#---call the subroutines---------------------------------------------#
&Header;
&TimeToday;
# &SetSwear;
&Query;
&BackupCheck;
print "test\n";
exit;
&Query;
&BackupCheck;
&SelectLog;
&ReadLogFile;
&CheckUser;
&WhichPage;
&Footer;
######################################################################
### PURPOSE: DETERMINE WHICH PAGE TO RETURN ###
######################################################################
#---find out read or write or form-----------------------------------#
sub WhichPage {
if ($Action eq 'Read')
{&Book;}
elsif ($Action eq 'Form')
{&Form;}
elsif ($writeThisUser ne '1' && $OneEntryPerHour)
{&error('You have already signed the Guestbook today')}
elsif ($Action eq 'Write')
{&Blank; &Backup; &WriteLogFile; &Response;
if ($EmailNewEntries){&SendMail;}}
else {&error('Invalid Guestbook Command')}
}
######################################################################
### PURPOSE: DEFINE TIME ###
######################################################################
#--------------------------------------------------------------------#
sub TimeToday {
($seconds,$minutes,$hours,$date,$month,$year,$weekday) = localtime(time);
#---pad the hours minutes and seconds--------------------------------#
if ($seconds < 10) { $seconds = "0$seconds"; }
if ($minutes < 10) { $minutes = "0$minutes"; }
if ($hours < 10) { $hours = "0$hours"; }
$month++;
#---set the date for today-------------------------------------------#
$Date = "$month\-$date\-$year";
$time = "$hours\:$minutes\:$seconds";
}
######################################################################
### PURPOSE: HANDLE ERROR MESSAGES ###
######################################################################
#--------------------------------------------------------------------#
sub error {
$error = shift(@_);
print qq~
Guestbook Error:
$error.
~;
exit;
}
######################################################################
### PURPOSE: INVALID FIELD RESPONSE ###
######################################################################
#--------------------------------------------------------------------#
sub TryAgain {
$error = shift(@_);
print qq~
Guestbook Error:
$error.
Try Again
~;
exit;
}
######################################################################
### PURPOSE: PRINT PAGE HEADER ###
######################################################################
#--------------------------------------------------------------------#
sub Header {
print "Content-type: text/html\n\n";
print "VelvetBlue.Com Guestbook\n";
print "$SiteName Guestbook
\n";
print "
\n";
return;
}
######################################################################
### PURPOSE: PRINT PAGE FOOTER ###
######################################################################
#--------------------------------------------------------------------#
sub Footer {
print "
Read - Write\n";
print "";
}
######################################################################
### PURPOSE: ALLOW ONE ENTRY PER HOUR ###
######################################################################
#--------------------------------------------------------------------#
sub CheckUser {
if ($ThisHost eq $d && substr ($c,0,2) eq $hours){$writeThisUser=0;}
else {$writeThisUser=1;}
}
######################################################################
### PURPOSE: DEMOZIFY QUERY STRING ###
######################################################################
#--------------------------------------------------------------------#
sub Query {
#---split the string by topic----------------------------------------#
@InString=split (/&/,$In);
foreach $x (0..$#InString){
#---creates the spaces-----------------------------------------------#
$InString[$x] =~ s/\+/ /g;
#---create a value array---------------------------------------------#
($trash,@UserInfo[$x])=split(/=/,$InString[$x]);
#---demozify---------------------------------------------------------#
@UserInfo[$x] =~ s/%(..)/pack("c",hex($1))/ge;
}
#---set the finished variables---------------------------------------#
$Action =@UserInfo[0];
$Log =@UserInfo[1];
$Name =StripSwear("\u@UserInfo[2]");
$Email =StripSwear("@UserInfo[3]");
$Homepage =StripSwear("@UserInfo[4]");
$Found =@UserInfo[5];
$Comment =StripSwear("\u@UserInfo[6]");
}
######################################################################
### PURPOSE: CHECK FOR BLANK FIELDS ###
######################################################################
#--------------------------------------------------------------------#
sub Blank{
#---no name field----------------------------------------------------#
if (!$Name || length $Name eq '1')
{&TryAgain('Name Field Required');}
#---invalid characters in email field--------------------------------#
if ($Email =~ tr/;,<>*|`&$!#()[]{}:'"//)
{&TryAgain('Invalid Characters In Email Field');}
#---incomplete homepage adress---------------------------------------#
if (substr ($Homepage,0,3) eq 'www')
{$Homepage='http://'.$Homepage;}
#---no comment field-------------------------------------------------#
if (!$Comment || length $Comment eq '1')
{&TryAgain('Comment Field Required');}
#---no email field---------------------------------------------------#
if (!$Email){$Email="No Email Given."; $WriteEmail=$Email}
else {$WriteEmail="$Email"}
#---no homepage field------------------------------------------------#
if (!$Homepage){$Homepage="No Homepage Given."; $WriteHome=$Homepage}
elsif (substr($Homepage,0,7) ne 'http://'){$WriteHome="$Homepage"}
else {$WriteHome="$Homepage"}
}
######################################################################
### PURPOSE: DEFINE SWEAR WORDS ###
######################################################################
#--------------------------------------------------------------------#
sub SetSwear{
$x='a'; for ($i=1;$i<=26;$i++)
{ @A[$i] = $x++ ; 9 }
@Swear[1] = @A[4].@A[1].@A[13].@A[14];
@Swear[2] = @A[19].@A[8].@A[9].@A[20];
@Swear[3] = @A[1].@A[19].@A[19];
@Swear[4] =@A[6].@A[21].@A[3].@A[11];
@Swear[5] =@A[2].@A[9].@A[20].@A[3].@A[8];
@Swear[6] =@A[16].@A[18].@A[9].@A[3].@A[11];
@Swear[7] =@A[4].@A[9].@A[3].@A[11];
@Swear[8] =@A[3].@A[21].@A[14].@A[20];
@Swear[9] =@A[16].@A[21].@A[19].@A[19].@A[25];
@Swear[10]=@A[23].@A[8].@A[15].@A[18].@A[5];
@Swear[11]=@A[19].@A[12].@A[21].@A[20];
@Swear[12]=@A[20].@A[23].@A[1].@A[20];
@Swear[13]=@A[1].@A[19].@A[19].@A[8].@A[15].@A[12].@A[5];
@Swear[14]=@A[19].@A[8].@A[9].@A[20].@A[8].@A[5].@A[1].@A[4];
@Swear[15]=@A[6].@A[21].@A[3].@A[11].@A[8].@A[5].@A[1].@A[4];
@Swear[16]=@A[6].@A[21].@A[3].@A[11].@A[5].@A[18];
@Swear[17]=@A[19].@A[12].@A[9].@A[20];
@Swear[18]=@A[7].@A[15].@A[4].@A[4].@A[1].@A[13].@A[14];
@Swear[19]=@A[6].@A[21].@A[3].@A[11].@A[9].@A[14].@A[7];
@Swear[20]=@A[20].@A[9].@A[20];
@Swear[21]=@A[20].@A[9].@A[20].@A[19];
@Swear[22]=@A[3].@A[15].@A[3].@A[11].@A[19].@A[21].@A[3].@A[11].@A[9].@A[14].@A[7];
@Swear[23]=@A[3].@A[15].@A[3].@A[11].@A[19].@A[21].@A[3].@A[11].@A[5].@A[18];
@Swear[24]=@A[12].@A[9].@A[3].@A[11].@A[9].@A[14].@A[7];
@Swear[25]=@A[3].@A[15].@A[3].@A[11];
@Swear[26]=@A[6].@A[18].@A[9].@A[3].@A[11].@A[8].@A[5].@A[1].@A[4];
@Swear[27]=@A[2].@A[1].@A[19].@A[20].@A[1].@A[18].@A[4];
@Swear[28]=@A[2].@A[1].@A[19].@A[20].@A[1].@A[18].@A[4].@A[1].@A[19].@A[19];
@Swear[29]=@A[19].@A[21].@A[3].@A[11].@A[9].@A[14].@A[7];
}
######################################################################
### PURPOSE: STRIP OUT SWEARING ###
######################################################################
#--------------------------------------------------------------------#
sub StripSwear{
$Words=shift (@_);
if ($FilterProfanity)
{for ($y=1;$y<=$#Swear;$y++){$Words =~ s/@Swear[$y]//gi;}}
if (!$AllowHTML)
{$Words =~ s/<([^>]|\n)*>//g;}
$Words =~ s/\|//g;
return $Words;
}
######################################################################
### PURPOSE: OPEN A LOCK FILE ###
######################################################################
#--------------------------------------------------------------------#
sub startLock {
while(-f $fullLockPath){select(undef,undef,undef,0.1);}
open(LOCKFILE, ">$fullLockPath") || &error("Could Not Open $fullLockPath");}
######################################################################
### PURPOSE: CLOSE & DELETE A LOCK FILE ###
######################################################################
#--------------------------------------------------------------------#
sub endLock {close(LOCKFILE) || &error("Could Not Close $fullLockPath");
unlink($fullLockPath) || &error("Could Not Delete $fullLockPath");}
######################################################################
### PURPOSE: OPEN THE LOG AND READ ###
######################################################################
#--------------------------------------------------------------------#
sub ReadLogFile {
&startLock;
open(COUNT,"$BackupName") || &create;
#---exit sub if creating new file------------------------------------#
if ($creating==1){exit;}
#---read the data strings--------------------------------------------#
while(){
#---split the data strings-------------------------------------------#
($a,$b,$c,$d,$e,$f,$g,$h,$i) = split(/,/,$_,9);
#---write the strings into arrays------------------------------------#
@UserNumber[$z] =$a;
@EntryDate[$z] =$b;
@EntryTime[$z] =$c;
@IPAddress[$z] =$d;
@UserName[$z] =$e;
@UserEmail[$z] =$f;
@UserHomepage[$z] =$g;
@UserFound[$z] =$h;
@UserComment[$z] =$i;
$z++;
}
#---increase the counter---------------------------------------------#
$count = $a; if ($count==0){$count=1;} else {$count++;}
close(COUNT) || &error("Could Not Close $fullLogPath");
&endLock;
}
######################################################################
### PURPOSE: WRITE & REPLACE THE LOG ###
######################################################################
#--------------------------------------------------------------------#
sub WriteLogFile {
#---what to write----------------------------------------------------#
$LogStringHidden="$count\,$Date\,$time\,$ENV{'REMOTE_HOST'}";
$LogStringSent=",$Name\,$Email\,$Homepage\,$Found\,$Comment\n";
#---write the new information----------------------------------------#
&startLock;
open(LOG, ">>$fullLogPath") || &error("Could Not Open $fullLogPath");
print LOG $LogStringHidden.$LogStringSent;
close(LOG) || &error("Could Not Close $fullLogPath");
&endLock;
}
######################################################################
### PURPOSE: CREATE LOG FILE ON FIRST RUN ###
######################################################################
#--------------------------------------------------------------------#
sub create {
#---tell the read function that file is created instead--------------#
$creating=1;
$count=1;
#---create the new file----------------------------------------------#
&endLock;
&startLock;
open(LOG, ">>$fullLogPath") || &error("Open $fullLogPath to write.");
print LOG $LogStringHidden;
close(LOG) || &error("Close $fullLogPath for write.");
&endLock;
#---write the creation message---------------------------------------#
print qq~
Guestbook $Version has just created a log file at
$fullLogPath
Your Guestbook should function properly now. Please click here to add your first entry or click here to read the guestbook.
~;
}
######################################################################
### PURPOSE: CREATE LOG BACKUPS ###
######################################################################
#--------------------------------------------------------------------#
sub Backup {
#---create the new backup filename-----------------------------------#
$countx=$count-1;
$BackupName=~s/\./$countx./;
#---determine if a backup should be created--------------------------#
for ($Bak=$BackupInterval; $Bak<=$MaxEntriesBeforeBackupStops;
($Bak=$Bak+$BackupInterval)){
if ($count eq $Bak+1){
#---rename the current log-------------------------------------------#
rename ($fullLogPath, $BackupName);
#---create the new log-----------------------------------------------#
&startLock;
open(LOG, ">$BackupDataPath") || &error("Open $BackupDataPath");
print LOG $Bak;
close(LOG) || &error("Close $BackupDataPath");
&endLock;
}}}
######################################################################
### PURPOSE: SELECT A LOG TO READ ###
######################################################################
#--------------------------------------------------------------------#
sub SelectLog {
#---is requested log file valid?-------------------------------------#
for ($Bak=$BackupInterval; $Bak<=$MaxEntriesBeforeBackupStops;
($Bak=$Bak+$BackupInterval))
{if ($Log eq $Bak){$BackupName=~s/\./$Bak./;}}}
######################################################################
### PURPOSE: CHECK FOR BACKUPS ###
######################################################################
#--------------------------------------------------------------------#
sub BackupCheck {
#---open the backup file and check for last backup-------------------#
&startLock;
open(LOG, "$BackupDataPath") || &BackupNone;
@BackupNumberRead = ;
$BackupNumberRead = scalar(@BackupNumberRead);
close(LOG);
&endLock;
}
######################################################################
### PURPOSE: RETURN NO BACKUP ###
######################################################################
#--------------------------------------------------------------------#
sub BackupNone {
$BackupNumberRead='0';
}
######################################################################
### PURPOSE: LINK TO BACKUPS ###
######################################################################
#--------------------------------------------------------------------#
sub LinkToBackups {
#---open form--------------------------------------------------------#
print "
";
}
######################################################################
### PURPOSE: RESPOND TO NEW ENTRY ###
######################################################################
#--------------------------------------------------------------------#
sub Response {
#---response returned------------------------------------------------#
print qq~
$Name, thank you for signing our Guestbook.
Your entry has been sent with the following information:
| Name: | $Name
|
| Email: |
$WriteEmail
|
| Homepage: |
$WriteHome
|
| Found Us By: |
$Found |
| Comment: |
$Comment |
Guestbook Entry $count Signed on $Date at $time.
Read the Guestbook
~;
&Message;
}
######################################################################
### PURPOSE: COMPOSE THE EMAIL MESSAGE ###
######################################################################
#--------------------------------------------------------------------#
sub Message {
if ($EmailHTML){
#---if email html switch is on--------------------------------------#
$Coding='text/html; charset=us-ascii';
#---compose email body----------------------------------------------#
$Message.="";
$Message.="
|
";
$Message.="| Name: | ";
$Message.="$Name |
";
$Message.="| Email: | ";
$Message.="$Email |
";
$Message.="| Homepage: | ";
$Message.="$Homepage |
";
$Message.="| Found Us By: | ";
$Message.="$Found |
";
$Message.="| Comment: | ";
$Message.="$Comment |
";
$Message.="
|
";
$Message.="| Book Entry: | ";
$Message.="$count |
";
$Message.="| IP Address: | ";
$Message.="$ThisHost |
";
$Message.="| Browser: | ";
$Message.="$ENV{'HTTP_USER_AGENT'} |
";
$Message.="| Signed On: | ";
$Message.="$Date at $time |
";
$Message.="
|
";
$Message.="Email Courtesy of Guestbook $Version by David Wolf";
}
else {
#---if email html switch is off-------------------------------------#
$Coding='text/plain; charset=us-ascii';
#---compose email body----------------------------------------------#
$Message.="Name: $Name\n";
$Message.="Email: $Email\n";
$Message.="Homepage: $Homepage\n";
$Message.="Found Us By: $Found\n";
$Message.="Comment: $Comment\n\n";
$Message.="------------------------------------------------\n\n";
$Message.="Book Entry: $count\n";
$Message.="IP Address: $ThisHost\n";
$Message.="Browser: $ENV{'HTTP_USER_AGENT'}\n";
$Message.="Signed On: $Date at $time\n\n";
$Message.="------------------------------------------------\n\n";
$Message.="Email Courtesy of Guestbook $Version by David Wolf\n";
}
}
######################################################################
### PURPOSE: WRITE THE BOOK PAGE ###
######################################################################
#--------------------------------------------------------------------#
sub Book {
&LinkToBackups;
#---look through all the entries-------------------------------------#
for ($inc=0;$inc<=$#UserNumber;$inc++){
#---blank email tag--------------------------------------------------#
if (@UserEmail[$inc] eq "No Email Given."){$WriteEmail=@UserEmail[$inc]}
else {$WriteEmail="@UserEmail[$inc]"}
#---blank homepage tag-----------------------------------------------#
if (@UserHomepage[$inc] eq "No Homepage Given.")
{$WriteHome=@UserHomepage[$inc]}
elsif (substr(@UserHomepage[$inc],0,7) ne 'http://')
{$WriteHome=@UserHomepage[$inc]}
else {$WriteHome="";
$WriteHome.="@UserHomepage[$inc]"}
#---write the guestbook display page---------------------------------#
print qq~
\n\n \n\n
| Name: |
@UserName[$inc] |
| Email: |
$WriteEmail |
| Homepage:
| $WriteHome
|
| Found Us By: |
@UserFound[$inc] |
| Comment: |
@UserComment[$inc] |
Guestbook Entry @UserNumber[$inc] Signed on @EntryDate[$inc]
at @EntryTime[$inc].
\n\n\n
~;
}}
######################################################################
### PURPOSE: WRITE THE FORM ###
######################################################################
#--------------------------------------------------------------------#
sub Form {
print qq~
~;
}
######################################################################
### PURPOSE: EMAIL THE RESPONSE ###
######################################################################
#--------------------------------------------------------------------#
sub SendMail {
$SMTPPort ||= 25;
my $AF_INET = 2;
my $SOCK_STREAM = 1;
my $sockaddr = 'S n a4 x8';
($name,$aliases,$proto) = getprotobyname('tcp');
($name,$aliases,$SMTPPort) = getservbyname ($SMTPPort,'tcp')
unless $SMTPPort =~ /^\d+$/;;
($name,$aliases,$type,$len,$thataddr) = gethostbyname ($SMTPHost);
my $this = pack($sockaddr, $AF_INET, 0, $thisaddr);
my $that = pack($sockaddr, $AF_INET, $SMTPPort, $thataddr);
socket(S, $AF_INET, $SOCK_STREAM, $proto) or print "Could not open socket: $!";
connect(S,$that) or print "Could not connect to $thataddr: $!";
select(S); $| = 1; select(STDOUT); $a=;
print S "HELO $MailEntryTo\n"; $a=;
print S "MAIL FROM:$Email\n"; $a=;
print S "RCPT TO:<$MailEntryTo>\n"; $a=;
print S "DATA \n"; $a=;
print S "From: \"$Name\" <$Email>\n";
print S "X-Mailer: Guestbook X-Mailer\n";
print S "MIME-Version: 1.0\n";
print S "To: $MailEntryTo\n";
print S "Subject: $MailSubject\n";
print S "Content-Type: $Coding\n";
print S "Content-Transfer-Encoding: 7bit\n";
print S "\n";
print S "$Message\n";
print S ".\n"; $a=;
print S "QUIT";
}