Before this page
See the advice for a novice first, where you make compulsory changes on the first line (path) and the basic set up for the url, directory, etc.
#!/usr/local/bin/perl

################
# basic set up #
################
$basurl = "http://your_url/";
$bbs = "http://your_url/bbs.cgi";
$setup = "http://your_url/setup.cgi";
$basdir = "/your_directory/";
$addrss = 'nobody@visitware.com';
$smpath = "/usr/sbin/sendmail";
$seed = "za";
$sfile = "secret.dat";
$ifile = "index.html";
     :
     :

You may change other basic setting and HTML or a part of HTML (see the advice for a little learnt).

Or you may change something a little more than HTML (see the advice for a good HTML user).

Handling inputs
Now you may try some real "Perl" scripting.
###############
# main script #
###############
     :
     :
$value =~ s/%0D%0A/<br>/g;
$value =~ s/%0A/<br>/g;
$value =~ s/%0D/<br>/g;
$value =~ s/%09/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/g;
$value =~ s/%3C/&lt;/g;
$value =~ s/%3E/&gt;/g;
This is for bbs.cgi only. setup.cgi has its fourth line $value =~ s/%09/ /g; or a space instead of many &nbsp;. And it does not have last two lines.

The three lines at the top change return_key (LF+CR for windows, LF for UNIX and CR for Macintosh) to <BR> (HTML tag for return_key). You can ignore all "return" and put entire article into one paragraph by replacing <br> by a space, such as $value =~ s/%0D%0A/ /g; etc.

The middle one, $value =~ s/%09/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/g; changes a tab to five spaces. Firstly, HTML cannot understand an ordinary tab. And secondly, I assigned a tab a special meaning within the perl scripting. So, this conversion is technically necessary. But if you do not like it, you may have a space (just like setup.cgi) instead of 5 &nbsp; between "$value =~ s/%09/" and "/g;" which converts a tab to a space and looks
$value =~ s/%09/ /g;

prof Board's bbs.cgi does not accept HTML tags sent by a guest. If you want HTML tags able, delete the last two lines
$value =~ s/%3C/&lt;/g;
and
$value =~ s/%3E/&gt;/g;
But you do so only after you learn the message board security and understand the risk your board masters are going to take.

Tighter security by "private_html"
If you can have "private_html" in your directory which can not be seen from the net, you can enhance the security level by placing secret.dat in it. First, create "private_html" outside of "public_html" in your directory if you do not have it yet. You are going to create/upload a blank file secret.dat in it. But before the file upload, open setup.cgi and find
### secret directory ###
There are two of them. "chdir" (change directory) command line chdir $basdir or &error... may follow. Change it to
### secret directory ###
chdir "/your_directory/private_html/" or &error1($erro5,$erro3,$!);
Replace your_directory by your directory in the server. Also find
### base directory ###
Again, you find two of them. base directory, however, are not followed by "chdir". You insert new "chdir" and make them
### base directory ###
chdir $basdir or &error2($erro5,$erro3,$!);
Then open bbs.cgi and you find only one
### secret directory ###
chdir $basdir or &error1("LINE-274",$erro5,$erro3,$!);
change it to
### secret directory ###
chdir "/your_directory/private_html/" or &error1("LINE-274",$erro5,$erro3,$!);
The permission of "private_html" is 777 and secret.dat 666.

Tighter security by deleting secret.dat
If you are going to have a limited number of message boards (maybe 20 or 30) and you creat them at once, you can increase the security by importing the secret.dat into bbs.cgi. (And setup.cgi and secret.dat must be deleted from the web site once the set up is finished.)

Open bbs.cgi and find ID & password check
#########################
# check ID and password #
#########################
sub check
{
### secret directory ###
chdir $basdir or &error1("LINE-274",$erro5,$erro3,$!);

$crptd = crypt($data{'pswd'},$seed);

open(DATAF, "<$sfile") or &error1("LINE-278",$erro1,$erro3,$!);
while ($dataf = <DATAF>) {
($name,$pswd,$udir,$mail) = split(/\t/,$dataf);
if ($data{'name'} eq $name) {
if ($crptd eq $pswd) {
close DATAF;
if ($data{'do'} eq "login") {&login;}
if ($data{'do'} eq "delete") {&delete;}
&error1($erro6);} else {&error1($erro8);}
}
}
&error1($erro9);
}

Rewrite all of it to
#########################
# check ID and password #
#########################
sub check
{
$list = <<'USER_LIST';
USER_LIST

$crptd = crypt($data{'pswd'},$seed);

local(@user) = split(/\n/, $list);

foreach (@user) {
($name,$pswd,$udir,$mail) = split(/\t/);
if ($data{'name'} eq $name) {
if ($crptd eq $pswd) {
if ($data{'do'} eq "login") {&login;}
if ($data{'do'} eq "delete") {&delete;}
&error1($erro6);} else {&error1($erro8);}
}
}
&error1($erro9);
}

Next, download secret.dat. (And delete it from the web space for good.) Suppose the content of secret.dat is
a zaFtxccKBrJRg a a@a.com
b zalUnUsS29UUQ b b@b.com
c za3M6dhjwtOaw c c@c.com
Copy and paste it to bbs.cgi
#########################
# check ID and password #
#########################
sub check
{
$list = <<'USER_LIST';
a zaFtxccKBrJRg a a@a.com
b zalUnUsS29UUQ b b@b.com
c za3M6dhjwtOaw c c@c.com

USER_LIST

$crptd = crypt($data{'pswd'},$seed);

local(@user) = split(/\n/, $list);

foreach (@user) {
($name,$pswd,$udir,$mail) = split(/\t/);
if ($data{'name'} eq $name) {
if ($crptd eq $pswd) {
if ($data{'do'} eq "login") {&login;}
if ($data{'do'} eq "delete") {&delete;}
&error1($erro6);} else {&error1($erro8);}
}
}
&error1($erro9);
}

ID & password list is now placed between $list = <<'USER_LIST'; and USER_LIST. (Please note you must use single quotes here. And you cannot have USER_LIST as a name of user, etc.) Upload new bbs.cgi to replace the old one.

Handling message-board index
You can change the way the new link is added to the link page when a new user created a message board.
#############################
# create new board (action) #
#############################
     :
     :
### new link start ###
     :
     :
### add link ###
     :
print LOCK $dataf;
if ($dataf =~ /^<!--NEW USER-->/) {
print LOCK "<!--$udir--><a href=\"$udir/$ifile\"><b>$data{'title'}</b></a><br>$data{'desi'}<hr>\n";
$newbd = "New MessageBoard is made";
}
setup.cgi only.
By default (see the above), a link to the latest board is added to the top of existing links. You can rewrite the script to
### add link ###
     :
if ($dataf =~ /^<!--NEW USER-->/) {
print LOCK "<!--$udir--><a href=\"$udir/$ifile\"><b>$data{'title'}</b></a><br>$data{'desi'}<hr>\n";
$newbd = "New MessageBoard is made";
}
print LOCK $dataf;
and the latest link comes to the bottom of all links. Please note, you use \" within ".

If you do not need the link page, you may delete, not just the above part, but everything between ### new link start ### to ### new link end ### and insert
### new link start ###
unlink $tfile or &error1($erro1,$erro9,$!);
### new link end ###
and you go down to find ### old link start ### to ### old link end ### and rewrite to
### old link start ###
unlink $tfile or &error1($erro1,$erro9,$!);
### old link end ###
Though, just deleting <!--NEW USER--> from the link page also works.

Handling data for a guest's message
In bbs.cgi
#################
# add new entry #
#################
     :
     :
$posted = gmtime($time);
sets the time a guest posted an article. This can be replaced by $posted = localtime($time); for the local time instead of Greenwich mean time. But this local time is the server's time, not necessary yours. Suppose you are one hour ahead of Greenwich time, you are (60 x 60 ) = 3600 seconds fast. You can have the time $posted = gmtime($time + 3600); for your local time.

By default, guest's email address will be hidden into his name when he posts an article on a board.
#################
# add new entry #
#################
     :
     :
if ($data{'email'}) {$data{'name'} = "<a href=\"mailto:$data{'email'}\">$data{'name'}</a>";}
bbs.cgi only.
Here it says if $data{'email'} or the guest's email address does exist, 'mailto' link is added to $data{'name'} the guest's name. If you change this line to
#################
# add new entry #
#################
     :
     :
if ($data{'email'}) {$data{'email'} = "<a href=\"mailto:$data{'email'}\">$data{'email'}</a>";}
and add $data{'email'} somewhere in ### new data ###, you have the separate item for the email address. Please note \" in " again.

Ban access
You can limit the access by checking the IP address, $ENV{'REMOTE_ADDR'} or checking the browser, $ENV{'HTTP_USER_AGENT'}. To ban an IP address, go to
################
# main script #
################
if ($ENV{'REQUEST_METHOD'} ne 'POST') {&admin;}
and insert
################
# main script #
################
if ($ENV{'REMOTE_ADDR'} eq '123.456.78.90') {die "You cannot be here\n";}
if ($ENV{'REQUEST_METHOD'} ne 'POST') {&admin;}
applicable for both bbs.cgi and setup.cgi.
Replace 123.456.78.90 by an IP address of someone you do not like. Also you can have better wording than You cannot be here.