#!/usr/local/bin/perl
#
### CGI掲示板(超簡易版) SD-Note-Spade Ver.1.0
###
### (C) 2000 Sentora Dori
### http://www.lowpower.iis.u-tokyo.ac.jp/~hat
#
########## 変数設定 ##########
#----- 手動設定部 -----
# 掲示板データファイルをおくディレクトリのパス
$basedir = "./";
# 掲示板データファイル名 (要変更)
$bbsfile = 'SDnote00.txt';
# 掲示板のタイトル (要変更)
$title = '道里千虎の掲示板';
# コメント
$comment = '';
# 背景の色
$bgcolor = '#FFFFFF';
# 背景に埋め込む画像
$bgimage = '';
# 1ページに表示される記事の数
$pagesize = 3;
# ファイルに記録しておく記事の数
#(記事がこれ以上になると古いものから削除される。0に設定すると削除なし。)
$maxarticle = 100;
# post: postメソッド get: getメソッド
$method = 'post';
# 漢字コード(sjis or jis or euc)
$kanjicode = 'sjis';
#----- 自動設定部 -----
$needname = 1;
$needsubject = 1;
$maxmessage = 3000;
$notecolor = '#FF0000';
$tableborder = 0;
$tablecolor = '';
$showmail = 1;
$showurl = 1;
$uselock =1;
$jcodelib ='./jcode.pl';
$thisurl = 'SDnoteS10.cgi';
$signature = 'bbs';
########## 変数設定(ここまで) ##########
$bbsfile = $basedir.$bbsfile;
#----- 漢字コード設定 -----
require "$jcodelib";
if ($kanjicode eq 'sjis') {
$contenttype = "";
# $contenttype = "";
} elsif ($kanjicode eq 'euc') {
$contenttype = "";
# $contenttype = "";
} elsif ($kanjicode eq 'jis') {
$contenttype = "";
}
##### format #####
#----- ユーザからの情報取得 -----
&init_form($kanjicode);
$bakaddr = $ENV{'REMOTE_ADDR'};
$bakhost = $ENV{'REMOTE_HOST'};
($bakaddr eq $bakhost) && ($hostname = gethostbyaddr(pack("C4", split(/\./, $bakaddr)), 2));
$hostaddress = $bakaddr;
#----- 変数入力 -----
$bbs_name = $form{'bbs_name'};
$bbs_subject = $form{'bbs_subject'};
$bbs_mail = $form{'bbs_mail'};
$bbs_url = $form{'bbs_url'};
$bbs_message = $form{'bbs_message'};
$bbs_command = $form{'bbs_command'};
$bbs_id = $form{'bbs_id'};
$bbs_hostname = $form{'bbs_hostname'};
$bbs_hostaddress = $form{'bbs_hostaddress'};
$bbs_pagenumber = $form{'bbs_pagenumber'};
#----- タグ禁止 -----
$bbs_name = &norm_input($bbs_name);
$bbs_subject = &norm_input($bbs_subject);
$bbs_mail = &norm_input($bbs_mail);
$bbs_url = &norm_input($bbs_url);
$bbs_message = &norm_input($bbs_message);
$bbs_id = &norm_input($bbs_id);
##### branch(入力されたコマンドによる分岐) #####
if ($bbs_command eq 'read') {
&do_read;
} elsif ($bbs_command eq 'write') {
&do_write;
} else {
&do_read;
}
exit(0);
###### do(コマンド実行) #####
#----- 記事を読む(単に表示する) -----
sub do_read {
&show_article;
}
#----- 記事を書く(ファイルに書いて表示する) -----
sub do_write {
### a 入力情報の検証 ###;
$error= '';
if ($needname == 1 && $bbs_name eq '') {
$error .= '名前が入力されていません。
';
}
if ($needsubject == 1 && $bbs_subject eq '') {
$error .= '題名が入力されていません。
';
}
if ($bbs_message eq '') {
$error .= 'メッセージが入力されていません。
';
}
if ($error) {
&print_error("$error");
}
if ($maxlength >0 && length($bbs_message) > $maxmessage) {
&print_error('メッセージが長すぎます。');
}
### b ファイルへ書き込み ###
&open_file(BBS, "+<$bbsfile", "No bbs file");
&lock_file(BBS);
@bbs = ;
# 掲示板ファイルかどうかチェック
($sign, $masterpass) = splice(@bbs, 0, 2);
chop($sign);
chop($masterpass);
if ($sign ne $signature) {
&unlock_file(BBS);
&close_file(BBS);
&print_error("Not BBS file");
}
# リロードかどうかチェックし連続書き込みを防止する
($print_id, $print_name, $print_mail, $print_url, $print_date, $print_pass, $print_subject, $print_message, $print_hostname, $print_hostaddress) = split(/,/, $bbs[0]);
if ($print_name eq $bbs_name && $print_subject eq $bbs_subject && $print_message eq $bbs_message) {
&unlock_file(BBS);
&close_file(BBS);
&show_article;
exit(0);
}
# 書き込み準備
seek(BBS, 0, 0);
print BBS "$sign\n";
print BBS "$masterpass\n";
$datestr = &get_date_string;
if ($bbs_url eq 'http://') {
$bbs_url = '';
}
# 書き込み位置検出
$id = 1;
for ($i = 0; $i < @bbs; $i++) {
($bakid) = split(/,/, $bbs[$i]);
if ($bakid >= $id) {
$id = $bakid + 1;
}
}
$writeline = "$id,$bbs_name,$bbs_mail,$bbs_url,$datestr,$encpass,$bbs_subject,$bbs_message,$hostname,$hostaddress\n";
unshift(@bbs, $writeline);
if ($maxarticle != 0) {
splice (@bbs, $maxarticle);
}
# 書き込み
print BBS @bbs;
truncate(BBS, tell(BBS));
&unlock_file(BBS);
&close_file(BBS);
### c 表示 ###
&show_article;
}
##### show(HTML表示) #####
#----- 書き込み用フォームと記事を表示する -----
sub show_article {
@file_info = stat($bbsfile);
if ($file_info[7] == 0) {
&open_file(BBS, "+<$bbsfile", "No BBS file");
seek(BBS, 0, 0);
print BBS "$signature\n";
print BBS "\n";
&close_file(BBS);
}
# open
&open_file(BBS, "$bbsfile", "No BBS file");
@bbs = ;
&close_file(BBS);
# check signiture
($sign, $masterpass) = splice(@bbs, 0, 2);
chop($sign);
chop($masterpass);
$number_article = $#bbs + 1;
if ($sign ne $signature) {
&print_error("No BBS file");
}
print "Content-type: text/html\n";
print "\n";
# ヘッダ表示
print <<"END_SHOW_ARTICLE_HEAD";
$contenttype
$title
$title
$comment
END_SHOW_ARTICLE_HEAD
# 書き込み用フォーム表示
if ($needname) {
$print_needname ='(必須)';
} else {
$print_needname = '';
}
if ($needsubject) {
$print_needsubject ='(必須)';
} else {
$print_needsubject = '';
}
if ($maxarticle != 0) {
$print_note = "保存されるメッセージは$maxarticle個で、古い順に消えていきます。
";
}
$maxmessage_zenkaku = int($maxmessage / 2);
print <<"END_SHOW_ARTICLE_INPUTFORM";
半角カナ・タグは使えません。最大の文字の長さは全角で$maxmessage_zenkaku文字です。
$print_note
END_SHOW_ARTICLE_INPUTFORM
# 記事表示
print "\n";
$article_start = $bbs_pagenumber * $pagesize;
$article_end = $article_start + $pagesize;
if ($article_end < $number_article) {
$bbs_pagenumber++;
$shownextpagebutton = 1;
}
if ($article_end > $number_article) {
$article_end = $number_article;
}
for ($i = $article_start; $i<$article_end; $i++) {
($print_id, $print_name, $print_mail, $print_url, $print_date, $print_pass, $print_subject, $print_message, $print_hostname, $print_hostaddress) = split(/,/, $bbs[$i]);
if ($showmail && $print_mail) {
$print_nametag = "$print_name";
} else {
$print_nametag = "$print_name";
}
if ($showurl) {
$print_urltag = "$print_url";
} else {
$print_urltag = "";
}
print <<"END_SHOW_ARTICLE_ARTICLE";
No.$print_id   $print_nametag  
題名: $print_subject  
$print_urltag   $print_date
END_SHOW_ARTICLE_ARTICLE
}
# フッター表示
if ($shownextpagebutton) {
print <<"END_SHOW_NEXTPAGEBUTTON";
END_SHOW_NEXTPAGEBUTTON
}
print <<"END_SHOW_ARTICLE_FOOT";
END_SHOW_ARTICLE_FOOT
}
##### サブ処理 #####
#----- 時刻文字列の取得 -----
sub get_date_string {
local(@week) = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
local($sec, $min, $hour, $day, $mon, $year, $weekday) = localtime(time);
$year += 1900;
$mon++;
if ($hour < 10) {
$hour = "0$hour";
}
if ($min < 10) {
$min = "0$min";
}
if ($sec < 10) {
$sec = "0$sec";
}
$weekstr = $week[$weekday] ;
return "$year-$mon-$day ($weekstr) $hour:$min";
}
##### 入出力処理 ######
#----- ブラウザへの入力データの取得 -----
sub init_form {
local($query, @dataarray, $data, $property, $value, $charcode, $method);
$charcode = $_[0];
$method = $ENV{'REQUEST_METHOD'};
$method =~ tr/A-Z/a-z/;
if ($method eq 'post') {
read(STDIN, $query, $ENV{'CONTENT_LENGTH'});
} else {
$query = $ENV{'QUERY_STRING'};
}
@dataarray = split(/&/, $query);
foreach $data (@dataarray) {
($property, $value) = split(/=/, $data);
$value =~ tr/+/ /;
$value =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg;
&jcode'convert(*value, $charcode);
$form{$property} = $value;
}
}
#----- 入力データからのタグ、メタ文字の消去 -----
sub norm_input {
local($string) = @_;
$string =~ s/&/&/g;
$string =~ s/"/"/g;
$string =~ s/</g;
$string =~ s/>/>/g;
$string =~ s/,/,/g;
$string =~ s/\r\n/\n/g;
$string =~ s/\r/\n/g;
$string =~ s/\n\n/
/g;
$string =~ s/\n/
/g;
return $string;
}
##### ファイル処理 #####
#----- ファイルオープン -----
sub open_file {
local(*FILE, $name, $msg) = @_;
if (!open(FILE, $name)) {
&print_error("$msg");
}
seek(FILE, 0, 0);
}
#----- ファイルクローズ -----
sub close_file {
local(*FILE) = @_;
close(FILE);
}
#----- ファイルロック -----
sub lock_file {
local(*FILE) = @_;
if ($uselock) {
eval("flock(FILE, 2)");
if ($@) {
&print_error("Cannot use flock");
}
}
}
#----- ファイルアンロック -----
sub unlock_file {
local(*FILE) = @_;
if ($uselock) {
eval("flock(FILE, 8)");
}
}
##### エラー処理 #####
#----- エラー文を出力し終了 -----
sub print_error {
local($msg) = @_;
print "Content-type: text/html\n\n";
print <<"END_PRINT_ERROR";
$contenttype
$msg
$msg
戻る
END_PRINT_ERROR
exit(0);
}