#!/usr/bin/perl # # BBMATIC BBS FOR THE WEB # Web forum for hosting user discussions featuring dynamic # databases, frames, auto E-Mail and multiple subject forums. # # Filename: bbmat.cgi # Copyright: 1996,1997,1998,1999 by Joe DePasquale # Last revised: August 1, 1999 # E-Mail: crypt@getcruising.com # Website: http://www.GetCruising.com # ######################################################################## # # # This script and accompanying files may be distributed freely # # and modified, provided this header with my name, E-Mail address and # # this notice remain intact. Ownership rights remain with me. You may # # not sell this script without my approval. # # # # This script comes with no guarantee or warranty except for my good # # intentions. By using this code you agree to indemnify me from any # # liability that might arise from it's use. # # # # There is no technical support for this script, neither am I a # # professional programmer. Refer to 'HELPME.TXT' for further guidance. # # # ######################################################################## # # CONFIGURE THE SCRIPT: # # Change these sample paths to the actual paths on your server: # Your Unix system date and sendmail commands $dateCmd = '/bin/date'; $mailCmd = '/usr/sbin/sendmail'; # Your E-Mail address - note mandatory backslash before \@ $myMail = "seekreeper\@gmail.com"; # Unix path to bbmat directory $bbmatDir = "haha.bigwussy.net/bbmat"; # URL to the bbmat directory $bbmatUrl = "http://haha.bigwussy.net/bbmat"; # URL to bbmat.cgi $scriptUrl = "http://haha.bigwussy.net/cgi-bin/bbmat.cgi"; # Link to exit from manager $exitUrl = "http://google.com"; # Here you define one or more forums using a keyword and path to # the directory where each can be found. You will create the directories # in a later step. The 'how2bbm.txt' document will explain what to place # there. For simplicity you can use your chosen keywords as the names # of the directories as in the example. Use short alphanumeric keywords. %Script = ( 'html','haha.bigwussy.net/bbmat/html', 'fun','haha.bigwussy.net/bbmat/fun', ); # Select one of the above keywords as the default forum. $script = 'fun'; # If BBMATIC frame(s) will be nested inside your own frames set to 'Y' $nested = 'N'; # OPTIONAL - YOU CAN EDIT THESE VARIABLES IF DESIRED: # You will probably want to use your imagination and list some # inappropriate words that you want to exclude from being posted. @badWords = ("cheesebrain","undulate"); # Maximum length in CHARACTERS to DISPLAY on the main page # for subjects and followup comments. $maxSubj = 250; $maxComm = 60; # Set maximum length in CHARACTERS for a subject or comment. If # exceeded, the text will be truncated. Default is 5120 = 5KB. $maxLength = 5120; # If you want a signature file attached to mail messages, # uncomment the next line and enter the correct Unix path .. # $MYSIG = "/usr/home/yourpath/to/mysig.txt"; # .. otherwise uncomment the next 2 lines and replace with your info .. $myName = "Austen Satterlee"; $homeUrl = "Haha.bigwussy.net"; # If you don't want to backup the bbm.dat file, set $bakFlag to 'N', # otherwise set bakTime, bakMax and bak Dir in the 'if' loop .. $bakFlag = 'N'; if ($bakFlag eq 'Y') { $bakTime = 2; # days btwn backups $bakMax = 7; # days to keep backups # Unix path to backup directory $bakDir = "/usr/home/yourpath/to/bak"; # END OF INSTALLATION - SHOULD NOT CHANGE STUFF BELOW THIS LINE ###################################################################### chop ($jDate = `$dateCmd +"%j"`); } chop ($mdyStamp = `$dateCmd +"%D"`); chop ($timeStamp = `$dateCmd +"%a %D %H%M%Z"`); chop ($dateStamp = `$dateCmd +"%y%m%d"`); if ($dateStamp <10000) { $dateStamp += 1000000; } # Read and parse Input from GET/POST and init variables print "Content-Type: text/html\nPragma: no-cache\n"; print "Expires: Wed, 01 Jan 1997 12:00:00 GMT\n\n"; if ($ENV{'QUERY_STRING'}) { $buffer = $ENV{'QUERY_STRING'}; } elsif ($ENV{'CONTENT_LENGTH'}) { read (STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); } @cgiPairs = split(/&/,$buffer); foreach $cgiPair (@cgiPairs) { ($name,$value) = split(/=/,$cgiPair); $value =~ s/\+/ /g; $value =~ s/%(..)/pack("c",hex($1))/ge; $Form{$name} .= "\0" if (defined($Form{$name})); $Form{$name} .= "$value"; } undef $name; undef $value; # ensure a valid script is selected if ($Script{$Form{'script'}}) { $script = $Form{'script'}; } $scriptDir = $Script{$script}; $BBMCFG = "$scriptDir/bbm.cfg"; $BBMCNT = "$scriptDir/bbm.cnt"; $BBMDAT = "$scriptDir/bbm.dat"; $BBMOLD = "$scriptDir/bbmold.dat"; $BBMFLK = "$scriptDir/bbm.flk"; $BBMTEMP = "$scriptDir/bbmtemp.html"; open (CFG,"<$BBMCFG") || &endIt ("Missing or Invalid Selection!"); @bbmCfg = ; close (CFG); chop ($headTitle = shift (@bbmCfg)); chop ($bodyTag = shift (@bbmCfg)); chop ($bodyTitle = shift (@bbmCfg)); if (defined $Form{'manager'}) { $BBMPWD = "$bbmatDir/bbmat.pwd"; require "./bbman.pl"; &bbman; exit; } if ($bakFlag eq 'Y') {$BBMBAK = "$bakDir/bbm$script$jDate.bak";} $addUrl = "$bbmatUrl/bbadd.gif"; $moreUrl = "$bbmatUrl/bbmore.gif"; $purUrl = "$bbmatUrl/pin-pur.gif"; $helpUrl = "$bbmatUrl/bbmhelp.html"; $botUrl = "$bbmatUrl/bbmbot.html"; $shortUrl = substr ($scriptUrl,rindex($scriptUrl,'/')+1); if (defined $Form{'frames'}) { if ($Form{'frames'} eq 'N') { $frames = 'N'; } else { $targetMain = ' target="BBM_MAIN"'; $targetBot = ' target="BBM_BOT"'; $frames = ''; } } ######################################################################## # Case: NEW SUBJECT if ($Form{'newsubject'}) { if ($Form{'name'} && $Form{'email'} && $Form{'text'} && $Form{'subject'}) { open (LOCK,">$BBMFLK") || &endIt; if (!flock (LOCK,2)) { &endIt; } &validate ($Form{'name'},$Form{'email'},$Form{'text'},$Form{'subject'}); # assign next subject nbr open (CNT,"+<$BBMCNT") || &endIt; flock (CNT,2); seek (CNT,0,0); $subjNbr = ; if ($subjNbr =~ /\n$/) { chop ($subjNbr); } $subjNbr++; seek (CNT,0,0); print CNT "$subjNbr"; truncate (CNT,tell(CNT)); close (CNT); if ((length $text) > $maxSubj) { $mainTxt = substr ($text,0,$maxSubj); @textWords = split(/ /,$mainTxt); $mainTxt = join (" ",@textWords[0..$#textWords-1]); # leave off chopped words $fileTxt = substr ($text,(length $mainTxt)+1); $SUBJFILE = "$scriptDir/bbm$subjNbr.txt"; open (SUBJECT,">$SUBJFILE") || &endIt; flock (SUBJECT,2); seek (SUBJECT,0,0); chmod (0666,$SUBJFILE); print SUBJECT "$fileTxt\n"; truncate (SUBJECT,tell(SUBJECT)); close (SUBJECT); } else { $mainTxt = $text; } $mainTxt =~ s/<(br|p)>//g; # update BBMDAT $newSubj = join ("\|",$subjNbr,'0',$subject,$name,$email,$mdyStamp,$mainTxt,"\n"); open (BBM,"+<$BBMDAT") || &endIt; flock (BBM,2); seek (BBM,0,0); @bbmFile = ; unshift @bbmFile,$newSubj; seek (BBM,0,0); print (BBM @bbmFile); truncate (BBM,tell(BBM)); close (BBM); close (LOCK); &message; } else { &endIt ("One or more required fields is blank."); } } # END NewSubject ######################################################################## # CASE: ADD COMMENT elsif ($Form{'addcomment'}) { if ($Form{'name'} && $Form{'email'} && $Form{'text'}) { open (LOCK,">$BBMFLK") || &endIt; if (!flock (LOCK,2)) { &endIt; } &validate ($Form{'name'},$Form{'email'},$Form{'text'}); # append to or create subject file $subjNbr = $Form{'subjnbr'}; $subject = $Form{'subject'}; $SUBJFILE = "$scriptDir/bbm$subjNbr.txt"; if ((length $text) > $maxComm) { $mainTxt = substr ($text,0,$maxComm); @textWords = split(/ /,$mainTxt); $mainTxt = join (" ",@textWords[0..$#textWords-1]); # leave off chopped words $fileTxt = substr ($text,(length $mainTxt)+1); } else { $mainTxt = $text; } $mainTxt =~ s/<(br|p)>//g; # insert new comment in BBMDAT open (BBM,"+<$BBMDAT") || &endIt; flock (BBM,2); seek (BBM,0,0); @bbmFile = ; $x = $#bbmFile; $swapFlag = 'N'; do { @bbmLine = split (/\|/,$bbmFile[$x],2); if ($bbmLine[0] < $subjNbr) { $bbmFile[$x+1] = $bbmFile[$x]; } elsif ($bbmLine[0] == $subjNbr) { $lineNbr = $bbmLine[1]+1; $newComm = join ("\|",$subjNbr,$lineNbr,$Form{'mailme'},$name,$email,$mdyStamp,$mainTxt,"\n"); $bbmFile[$x+1] = $newComm; do { @bbmLine = split (/\|/,$bbmFile[$x]); # send E-Mail to all in thread if ($bbmLine[1] == 0 || $bbmLine[2] eq 'Y') { $MailTo{$bbmLine[4]} = 'Y'; } $x--; } until ($bbmLine[1] == 0); $swapFlag = 'Y'; &mailTo (keys %MailTo); } $x--; } until ($swapFlag eq 'Y' || $x<0); seek (BBM,0,0); print BBM @bbmFile; truncate (BBM,tell(BBM)); close (BBM); if ($swapFlag eq 'N') { &endIt ("Requested subject $subjNbr not found."); } # create subject file if not exist, insert comment if ($fileTxt) { if (-e $SUBJFILE) { open (SUBJECT,"+<$SUBJFILE") || &endIt; flock (SUBJECT,2); seek (SUBJECT,0,0); @subjFile = ; } else { open (SUBJECT,">$SUBJFILE") || &endIt; flock (SUBJECT,2); seek (SUBJECT,0,0); chmod (0666,$SUBJFILE); } $subjFile[$lineNbr] = $fileTxt; for $x (0..$lineNbr) { if ($subjFile[$x] !~ /\n$/) { $subjFile[$x] .= "\n"; } } seek (SUBJECT,0,0); print SUBJECT @subjFile; truncate (SUBJECT,tell(SUBJECT)); close (SUBJECT); } close (LOCK); &message; } else { &endIt ("One or more required fields is blank."); } } # END AddComment ######################################################################## # Case: Display Subject Page and Add Comment Form elsif ($Form{'getsubject'}) { $subjNbr = $Form{'getsubject'}; $SUBJFILE = "$scriptDir/bbm$subjNbr.txt"; print qq|\n$headTitle\n|; print qq|\n$bodyTag\n|; if (-e $SUBJFILE) { open (SUBJECT,"<$SUBJFILE") || &endIt; flock (SUBJECT,1); seek (SUBJECT,0,0); @subjFile = ; close (SUBJECT); } $foundFlag ='N'; open (BBM,"<$BBMDAT") || &endIt; flock (BBM,1); seek (BBM,0,0); while (($bbmLine = ) && $foundFlag eq 'N') { ($nbr,$lineNbr,$mailme,$name,$email,$mdyStamp,$mainTxt,$eol) = split (/\|/,$bbmLine); if ($subjNbr == $nbr) { if ($lineNbr ==0) { $subject = $mailme; print qq|[View Comments] [Add Your Comments] [Help & Tutorial]

\n|; print qq|Subject: $subject

\n|; print qq|Posted By $name ($email) On $mdyStamp:
\n|; print qq|$mainTxt $subjFile[$lineNbr]\n


\nFollowup Comments:\n
|; } else # comment { print qq|* Added By
$name ($email) On $mdyStamp:
\n|; print qq|$mainTxt $subjFile[$lineNbr]\n
|; } } elsif ($subjNbr > $nbr) { $foundFlag = 'Y'; } } close (BBM); print <<__SUBJFORM;
Add Your Comment:

Subject: $subject
Alert me of new posts on this subject.

Message:

Name:

E-Mail Address:

Press OR to start over.
Please PRESS ONCE AND WAIT FOR RESPONSE.

BBMATIC BBS FOR THE WEB is one of Joe's CGI Scripts From The Crypt!

__SUBJFORM } # End getsubject ######################################################################## # Display the main BBMATIC page elsif (defined $frames) { open (TEMP,"<$BBMTEMP") || &endIt; @tempFile = ; close (TEMP); open (BBM,"<$BBMDAT") || &endIt; flock (BBM,1); seek (BBM,0,0); @bbmFile = ; close (BBM); foreach $tempLine (@tempFile) { if ($tempLine =~ //) { if ($frames eq 'N') { print qq|This is FULL SCREEN mode. Switch to SPLIT SCREEN ?
\n|; } else { print qq|This is SPLIT SCREEN mode. Switch to FULL SCREEN ?
\n|; } print qq|[1] Read Full Text on any of the open subjects by clicking the MORE button.\n|; print qq|If no additional text is available, the button will not appear.
\n|; print qq|[2] To Add A Comment On An Open Subject, click the ADD button next to the SUBJECT OR
\n|; print qq|[3] To Open a New Subject for Comments, use this link to ADD A NEW SUBJECT.
\n|; print qq|For more complete information see the OVERVIEW & TUTORIAL
\n|; foreach $line (@bbmFile) { ($subjNbr,$lineNbr,$mailme,$name,$email,$mdyStamp,$mainTxt,$eol) = split (/\|/,$line); if ($lineNbr ==0) # subject { $subject = $mailme; print qq|\n


\n $subject\n|; print qq|
Posted By $name On $mdyStamp\n|; print qq|
$mainTxt$cont\n|; } else # comment { print qq|
* Added By $name On $mdyStamp|; print qq|
$mainTxt$cont\n|; } } } elsif ($tempLine =~ //) { print <<__MAINBOT; ADD A NEW SUBJECT:

Use this form to open a subject for discussion if it's not yet listed above. To post a followup COMMENT on any subject on this page, use the "Add a Comment" link beneath that subject. For detailed instructions click Overview & Tutorial.

Subject:

Message:

Name:

E-Mail Address:

Press or to start over.
PRESS ONCE AND WAIT FOR RESPONSE.

BBMATIC BBS FOR THE WEB is one of Joe's CGI Scripts From The Crypt! __MAINBOT } else { print "$tempLine"; } } if ($bakFlag eq 'Y' && ($jDate % $bakTime ==0) && !-e $BBMBAK) { &backUp (@bbmFile); } } # end ifdefined ######################################################################## # Default CASE: Output BBM frameset else { if ($ENV{'HTTP_USER_AGENT'} =~ /Mozilla\/(\d+\.?\d*).*/i) { $mozilla = "Your Mozilla version is: $1"; } print <<__BBMFRAME; $headTitle This is your browser: $ENV{'HTTP_USER_AGENT'}<br> $mozilla <p> You need Mozilla 2.0 or higher to see the FRAMES on this page, but for now use the <a href="$shortUrl?script=$script&frames=N">No-Frames Version</a>. <p> __BBMFRAME } # end default exit; # end main program ######################################################################## sub message # ack new post and redisplay main page { print qq|\n$headTitle\n|; print qq|\n|; print qq|\n$bodyTag\n|; print qq|

THANK YOU!
\nYour comments have been posted.
\n|; print qq|

\nIf the MAIN PAGE does not reload here in 5 seconds,
\n|; print qq|click to REFRESH or
\n|; print qq|use your browser's [RELOAD] button.\n

\n\n|; } # End message sub mailTo # E-mail to all in thread when new posting { if (open (SIG,"<$MYSIG")) { @mySig = ; close (SIG); } foreach $_ (@_) { if (open (MAIL,"|$mailCmd -t")) { print MAIL "To: $_\nFrom: $myMail\nSubject: $headTitle\n\n"; print MAIL "A followup to your posting has been received.\n\"$subject\".\n\n"; print MAIL "You can link directly to the BBS at -\n$returnUrl\n\n"; print MAIL "Thank You for making use of our resources at\n$headTitle\!\n"; print MAIL "Please bookmark us and visit frequently!\n\n"; if (@mySig) { print MAIL "@mySig"; } else { print MAIL "$myName <$myMail>\n$homeUrl\n"; } close (MAIL); } sleep 1; } } # end mailTo sub validate # check text length, badwords & convert HTML { @fields = @_; # chop if text field over maxLength if (length $fields[2] > $maxLength) { $fields[2] = substr($fields[2],0,$maxLength); } # 0=name 1=email 2=text 3=subject for ($x=0; $x<=$#fields; $x++) { if ($x==2 || $x==3) { chop ($fields[$x]) if $fields[$x] =~ /\n$/; $fields[$x] =~ s'&(amp;)?'&'g; $fields[$x] =~ s'"'"'g; $fields[$x] =~ s'<'<'g; $fields[$x] =~ s'>'>'g; if ($x==2) { $fields[$x] =~ s/(\w+.*)(\r?\n){2,}/$1

/gm; $fields[$x] =~ s/(\w+.*)\r?\n/$1
/g; } } else { $fields[$x] =~ s/<(.)*>//g; } $fields[$x] =~ s/\|/|/g; # convert PIPE to html if ($x==1) { $fields[$x] =~ s/\s//g; if ($fields[$x] !~ /\S+\@\S+(\.\S+)+/) { &endIt ("Invalid E-MAIL Address entered."); } } else { $fields[$x] =~ s/(\f|\n|\r|\t)//g; if ($x==0 && $fields[0] !~ /\w+/) { &endIt ("Invalid NAME entered."); } } foreach $badWord (@badWords) { if ($fields[$x] =~/\b$badWord\b/i) { &endIt ("WHOOPS! You used a naughty word."); } } } ($name,$email,$text,$subject) = @fields; } # End Validate sub backUp # Backup data and delete old backups { @bakData = @_; open (BAK,">$BBMBAK") || &endIt; print (BAK @bakData); close (BAK); chmod (0666,$BBMBAK); opendir (BAKDIR,$bakDir); @bakFiles = grep (/bbm$script\d{3}\.bak/, readdir(BAKDIR)); closedir (BAKDIR); foreach $bakFile (@bakFiles) { if (-M "$bakDir/$bakFile" > $bakMax) { unlink "$bakDir/$bakFile"; } } } # end backup sub endIt # Correctible user error { print qq|\n$headTitle\n|; print qq|\n$bodyTag\n$bodyTitle\n

\n|; print qq|ERROR:
\n|; if ($_[0]) { print "$_[0]"; } else { print "Server made a Boo-Boo! $!"; } print qq|
\n

Use your browser's [BACK] button and try again.\n|; print qq|

\n\n|; exit; } # end endIt