#!/usr/local/bin/perl # FlasH BBS Pro version 1.41 # # Script written by Shigeto Nakazawa.(1997/1/17) # < http://www7.big.or.jp/~jawa/ > # This script is free. # ////////////////////////////////////////////////////////// # // オプションの設定変更はここから始まります。 // # ////////////////////////////////////////////////////////// # ---------------------------------------------------------- # 記事の最大登録数等を設定できます。 # ---------------------------------------------------------- $max_size = 999 *1024; # 記事削除開始記録ファイルサイズ(約nバイト 最低 1500) $max_tree = 10; # リストに表示するツリーの数です。 $max_msg = 8000; # 投稿を受理する最大文字数(半角 n 文字) $new_kiji = 10; # 最新情報に[NEW]をつける数 # ---------------------------------------------------------- # この掲示板の管理者(あなた)の情報です。 # ---------------------------------------------------------- $admin_name = 'segu'; # あなたの名前(ハンドルネーム)を書きます。 $admin_email = 'segu@psxemu.com'; # あなたのメールアドレスを書きます。 # ---------------------------------------------------------- # この掲示板のカスタマイズ項目です。 # ---------------------------------------------------------- $title = "Segu's ToolBox Message Board (JP)"; # 掲示板のタイトル $body_text = '#FFFFFF'; # タグの設定 $body_link = '#FFFF00'; # リンクの色 $body_alink = '#FF0000'; # クリック中のリンクの色 $body_vlink = '#7F7F00'; # 既にクリック済みのリンクの色 $body_bgcolor = '#000000'; # 背景の色 $body_back = ''; # 背景画像 $backurl = "../indexj.html"; # 帰りの URL $date = "year/mon/day hour:min"; # 時間表示フォーマット $date_type = 1; # 一桁のとき二桁に修正するか? # 0:しない 1:する(時分秒) 2:する(全て) $em_color = "#FFFFFF"; # 強調色の色(数字等) $kiji_title_color = "#FFFFFF"; # 記事のタイトルの色 $kiji_title_bgcolor = "#0000FF"; # 記事のタイトルの背景色 #$form_bgcolor = "#CED1B5"; # 記事投稿フォームの背景色 $form_bgcolor = "#C0C0C0"; # 記事投稿フォームの背景色 $res_color = "#AAAA00"; # 記事につくレスの色 $gif_allnews = 'images/all.gif'; # 一括購読用の GIF IMAGE $gif_news = 'images/docs.gif'; # 標準購読用の GIF IMAGE $gif_new_news = 'images/new.gif'; # 最新記事用の GIF IMAGE $gif_space = 'images/blank.gif'; # 透明 の GIF IMAGE(ダミー画像) $gif_width = 20; # GIF IMAGE の横幅 $gif_height = 14; # GIF IMAGE の縦幅 $tree_width = 30; # Tree Width(ツリーがずれます?) $html_title=<<"_EOF_"; # HTML 文の設定(タイトル)
Title

click here!


_EOF_ # ↑ この _EOF_ は必要です。 $html_info=<<"_EOF_"; # HTML 文の設定(案内) _EOF_ # ↑ この _EOF_ は必要です。 # ---------------------------------------------------------- # クッキー、ファイル、セキュリティー関連 # 書き換える必要がある場合を除いては変更してはいけません。 # ---------------------------------------------------------- # ここにこのCGIの正確な URL (http://〜) を書いておくと # 他サイトから不正に投稿されたものを拒否できます。 $base_url = "http://segu.psxemu.com/cgi/fbbs.cgi"; $cookie_name = 'segufbbs'; # クッキーのID $jcode = './jcode.pl'; # jcode.pl のある場所 (URLじゃないよ) $logfile = './fbbs_log.cgi'; # 記録用ファイル (URLじゃないよ) $countfile = './fbbs_cnt.cgi'; # カウンタファイル (URLじゃないよ) $lock1 = './fbbs1l.cgi'; # 鍵ファイル(1) (URLじゃないよ) $lock2 = './fbbs2l.cgi'; # 鍵ファイル(2) (URLじゃないよ) $lock_flag = 1; # 鍵ファイルの 1:使用 0:不使用 # ////////////////////////////////////////////////////////// # // オプションの設定変更はここまでです。 // # ////////////////////////////////////////////////////////// # [ メイン処理 ] # $ID = $FORM{'id'}; &check_code; &read_form; &get_cookie; &check_cookie; @logs = &read_file($logfile); if ($FORM{'md'} eq 'reg') { ®ist; } elsif ($FORM{'md'} eq 'del') { &delete; } elsif ($FORM{'md'} eq 'viw') { &view; } elsif ($FORM{'md'} eq 'new') { &html_header("新規投稿");print"
\n";&html_form('root'); } elsif ($FORM{'md'} eq 'set') { &set; } elsif ($FORM{'md'} eq 'num') { &number; } else { &ichiran; } &html_footer; exit 0; # [ ヘッダー部分表示 ] # sub html_header { local($sub_title) = $_[0]; local($font_size) = ($COOKIE{'font'} > 0) + 3; print "Content-type: text/html\n\n"; print<<"_EOF_"; $title [$sub_title] $html_title [ トップページへ戻る / 利用規定/利用方法 / 一覧表\示 / 最新記事 / 新規投稿 / 管理用 ]

_EOF_ } # [ 著作権等の表示(必ず著作権を表示すること) ] # sub html_footer { print<<"_EOF_";


Admin: $admin_name / FlasH BBS Pro v1.41 [Shigeto Nakazawa]
_EOF_ } # [ 一覧表示 ] # sub ichiran { &set_cookie; &html_header("一覧表\示"); $count = (&read_file($countfile))[0]; $tree = $COOKIE{'tree'}; if ($tree > @logs) { $tree = 0; } if (!$tree) { $tree = 0; } $tree = int($tree/$max_tree)*$max_tree; print<<"_EOF_"; $html_info
 
_EOF_ print"
\n";
    $end_tree = $tree + $max_tree;
    if ($end_tree > @logs) { $end_tree = @logs; }
    for ($i=$tree;$i<$end_tree;$i++) {
        print"
"; @datas = ÷_log($logs[$i]); foreach (@datas) { local($no,$res,$lx,$tn,$title,$name,$email,$date,$act) = ÷_data($_); if ($res eq 'root') { print ""; } else { local($space_width) = $gif_width+$tree_width*$lx; print ""; } print ""; if ($no > $count - $new_kiji) { print ""; } else { print ""; } print "$title : "; if ($COOKIE{'name'} eq $name) { print "$name"; } else { print $name; } print " ($date)\n"; } } print"
\n"; } # [ 個別で記事の内容を表示する ] # sub view { &html_header("記事($FORM{'no'})"); @kiji_datas = ÷_log(&search_no2data($FORM{'tn'},@logs)); $kiji_data = &search_no2data($FORM{'no'},@kiji_datas); print"
\n"; &kiji_view($kiji_data); print"
\n"; local($no,$rq_res,$lx,$tn,$title,$name,$email,$date,$rq_act,$file_pwd,$rhost,$ipad,$comment) = ÷_data($kiji_data); foreach (@kiji_datas) { local($no,$res,$lx,$tn,$title,$name,$email,$date,$act,$pwd,$rhost,$ipad,$comment) = ÷_data($_); if ($rq_res == $no) { $parent = "▲ $title : $name($date)\n"; } if (($res == $FORM{'no'}) && ($res ne 'root')) { $children .= "▼ $title : $name($date)\n"; } } if ($rq_res eq 'root') { $parent = "この記事がルート記事です。"; } elsif (!$parent) { $parent = "元になった記事はみつかりませんでした。"; } if (!$children) { $children = "返事はありません。"; } print<<"_EOF_";
[この記事の元になった記事です。 ]

$parent


[この記事に対する返事です。]

$children


この記事に返事を出す場合は下の投稿フォームに書き込んで下さい。
_EOF_ if ($rq_act > 6) { print "

残念ながら返事は書けないようです。
\n"; return 0; } if ($title =~ /^Re\[(\d+)\]:/){ local($ct) = $1; $ct++; $title =~ s/Re\[\d+\]:/Re\[$ct\]:/; } elsif ($title =~ /^Re:/){ $title =~ s/Re:/Re\[2\]:/; } else { $title = "Re:$title"; } $comment = "
$comment"; $comment =~ s/
((>)+)/\n$1>/ig; $comment =~ s/
/\n> /ig; $comment =~ s/\n//; &html_form($FORM{'no'},$title,$comment,$FORM{'tn'},$lx); if (crypt($COOKIE{'pwd'},"FlasH_BBS_Pro") eq $file_pwd) { print<<"_EOF_";
(完全に削除されない場合があります。)
_EOF_ } } # [ セット表示 ] # sub set { &html_header("セット表\示"); print<<"_EOF_";
セット表\示

_EOF_
    @kiji_datas = ÷_log(&search_no2data($FORM{'tn'},@logs));
    foreach (@kiji_datas) {
        local($no,$res,$lx,$tn,$title,$name,$email,$date,$act) = ÷_data($_);
        $no = int($no);
        $reply[$res] .= "$no-";
        if ($res eq 'root') {
            print "";
        } else {
            local($space_width) = $gif_width+$tree_width*$lx;
            print "";
        }
        print "$title : $name($date)\n";
    }
    foreach $data (@kiji_datas) {
        local($no,$res,$lx,$tn,$title,$name,$email,$date,$act,$pwd,$rhost,$ipad,$comment) = ÷_data($data);
        $no = int($no);
        print<<"_EOF_";


返事を書く|リスト
$no _EOF_ if ($res eq 'root') { print" Root\n"; } else { $res = int($res); print"[$res]\n"; } print"\n"; if (!$reply[$no]) { print"なし\n"; } else { chop($reply[$no]); local(@replys) = split(/-/,$reply[$no]); foreach (@replys) { print"[$_]\n"; } } print"
\n"; &kiji_view($data); print<<"_EOF_";

_EOF_ } } # [ 最新記事一括機能 ] # sub number { &html_header("最新記事"); print<<"_EOF_";
最近の記事 $new_kiji件を表\示しています。
_EOF_ $count = (&read_file($countfile))[0]; foreach (@logs) { @datas = ÷_log($_); foreach $data (@datas) { local($no,$res,$lx,$tn,$title,$name,$email,$date,$act) = ÷_data($data); if ($no > $count - $new_kiji) { push(@nums,$data); } } } @nums = reverse(sort(@nums)); foreach $data (@nums) { local($no,$res,$lx,$tn,$title,$name,$email,$date,$act,$pwd,$rhost,$ipad,$comment) = ÷_data($data); print<<"_EOF_";


返事を書く|セットで表\示
_EOF_ &kiji_view($data); print<<"_EOF_";

_EOF_ } } # [ 投稿フォームを表示 ] # base 42, ie 3 85, ie 4 55, other 55 sub html_form { local($no,$title,$comment,$tn,$lx) = (@_); if ($no eq '') { $no = 'root'; } $nam_wid = 35; $com_wid = 60; $agent = $ENV{'HTTP_USER_AGENT'}; if ($agent =~ /MSIE 3/i) { $nam_wid = 65; $com_wid = 121; } elsif ($agent =~ /MSIE 4/i) { $nam_wid = 65; $com_wid = 90; } elsif (($agent =~ /[ja]/i) && ($agent =~ /3\./)) { $nam_wid = 46; $com_wid = 90; } print<<"_EOF_";
Subject
From
E-Mail
_EOF_ } # [ 記事内容を表示 ] # sub kiji_view { local($data) = $_[0]; local($no,$res,$lx,$tn,$title,$name,$email,$date,$act,$tm_pwd,$rhost,$ipad,$comment) = ÷_data($data); $comment ="$comment"; &jcode'convert(*comment,'euc'); $comment =~ s/>(>[^<]*)/>$1<\/FONT>/g; $comment =~ s/(http:\/\/[\w\.\~\-\/\?\&\+\=\:\@\%]+)/$1<\/A>/ig; $comment =~ s/(ftp:\/\/[\w\.\~\-\/]+)/$1<\/A>/ig; $comment =~ s/([\w\.\-]+)\@([\w\.\-]+)/$1\@$2<\/A>/ig; &jcode'convert(*comment,$mojicode); if ($email) { $name = "$name"; } print<<"_EOF_";
$title
$name ($date)

$comment

_EOF_ } # [ 記事登録処理 ] # sub regist { local($title,$name,$email,$comment,$lx,$tn,$pwd,$ref_url) = ($FORM{'title'},$FORM{'name'},$FORM{'email'},$FORM{'comment'},$FORM{'lx'},$FORM{'tn'},$FORM{'pwd'},$ENV{'HTTP_REFERER'}); $title =~ s/\r\n//g; $title =~ s/\r|\n//g; $name =~ s/\r\n//g; $name =~ s/\r|\n//g; $email =~ s/\r\n//g; $email =~ s/\r|\n//g; $comment =~ s/\r\n/
/g; $comment =~ s/\r|\n/
/g; $lx++; $pwd =~ s/\r\n//g; $pwd =~ s/\r|\n//g; $ref_url =~ s/\?(.|\n)*//g; s/\%7E/\~/g; if($base_url && ($ref_url !~ $base_url)){ &error(1,"不当なアクセスです。$ref_url
\n"); } if (length($title) > 80) { &error(1,"タイトルの記入漏れ、又は文字数制限を過えています。"); } elsif (!$title) { $title = "無題"; } if ((!$name) || (length($name) > 42)) { &error(1,"名前の記入漏れ、又は文字数制限を過えています。"); } if ((($email !~ /(.*)\@(.*)\.(.*)/) && ($email)) || (length($email) > 120)) { &error(1,"メールアドレスの間違い、又は文字数制限を過えています。"); } if ((!$comment) || (length($comment) > $max_msg)) { &error(1,"メッセージの記入漏れ、又は文字数制限を越えています。"); } if ((!$pwd) || (length($pwd) > 8)) { $pwd = &make_pwd; } $file_pwd = crypt($pwd,"FlasH_BBS_Pro"); &get_date; $count = (&read_file($countfile))[0]; if (++$count > 9999) { &error(1,"カウンターエラーです。管理者はエディタで最適化を行って下さい。"); } &write_file($countfile,$count); $count = substr("0000",length($count)).$count; $rhost = &change_code($ENV{'REMOTE_HOST'}); $ipad = &change_code($ENV{'REMOTE_ADDR'}); if ($FORM{'no'} eq 'root') { $kiji_data = "$count<>root<>0<>$count<>$title<>$name<>$email<>$date<>0<>$file_pwd<>$rhost<>$ipad<>$comment\n"; unshift(@logs,$kiji_data); } else { foreach $tree (@logs) { if ($tn == (split(/<>/,$tree))[0]) { @datas = ÷_log($tree); $flag1 = 0; $flag2 = 0; $kiji_data = "$count<>$FORM{'no'}<>$lx<>$tn<>$title<>$name<>$email<>$date<>0<>$file_pwd<>$rhost<>$ipad<>$comment"; foreach $data (@datas) { if (($flag2 == 1) && ($temp_lx >= (split(/<>/,$data))[2])){ $tree_data = "$tree_data<#>$kiji_data"; $flag2 = 2; } if ($flag1) { $tree_data = "$tree_data<#>$data"; } else { $tree_data = $data; $flag1 = 1; } if (($FORM{'no'} == (split(/<>/,$data))[0]) && (!$flag2)) { $flag2 = 1; $temp_lx = (split(/<>/,$data))[2]; } } if ($flag2 == 1){ $tree_data = "$tree_data<#>$kiji_data"; } unshift (@new,"$tree_data\n"); } else { push (@new,$tree); } } @logs = @new; } if ($max_size <1500) { $max_size = 1500; } $size = (stat($logfile))[7]; while ($size > $max_size) { $size -= length(pop(@logs)); } &write_file($logfile,@logs); $COOKIE{'name'} = $name; $COOKIE{'email'} = $email; $COOKIE{'pwd'} = $pwd; &set_cookie; &html_header("投稿受理報告"); print<<"_EOF_";
以下の内容で登録されました。  

_EOF_ &kiji_view($kiji_data); &html_footer; exit; } # [ 投稿者削除処理 ] # sub delete { @kiji_datas = ÷_log(&search_no2data($FORM{'tn'},@logs)); $kiji_data = &search_no2data($FORM{'no'},@kiji_datas); local($no,$res,$lx,$tn,$title,$name,$email,$date,$act,$file_pwd,$rhost,$ipad,$comment) = ÷_data($kiji_data); if (crypt($COOKIE{'pwd'},"FlasH_BBS_Pro") ne $file_pwd) { &error(1,"指定した記事の削除はできません。"); } &get_date; $kazu = @kiji_datas; if ($kazu == 1) { foreach $data (@logs) { if ($FORM{'no'} != (split(/<>/,$data))[0]) { push(@new,$data); } } } else { $kiji_data = "$no<>$res<>$lx<>$tn<>[投稿者削除]<>$name<><>$date<>8<>Null<>$rhost<>$ipad<>投稿者によって削除されました。($date)"; $flag = 0; foreach $data (@kiji_datas) { if ($flag) { $tree_data .= "<#>"; } else { $flag = 1; } if ($FORM{'no'} == (split(/<>/,$data))[0]) { $tree_data .= $kiji_data; } else { $tree_data .= $data; } } $tree_data =~ s/\n//; foreach $data (@logs) { if ($FORM{'tn'} != (split(/<>/,$data))[0]) { push(@new,$data); } else { push(@new,"$tree_data\n"); } } } &write_file($logfile,@new); &html_header("投稿者削除"); print<<"_EOF_";

記事の内容を削除しました。

ツリー掲示板の性質上、完全には削除されない場合があります(レス等がある場合)
完全に削除することを望む場合は管理者にお伝え下さい。

_EOF_ } # [ データ処理関連汎用サブ ] # sub divide_log { local($data) = $_[0]; chop($data); return split(/<#>/,$data); } sub divide_data { return split(/<>/,$_[0]); } sub search_no2data { local($no,@datas) = @_; local($data); foreach $data (@datas) { if ($no == (split(/<>/,$data))[0]) { return $data; } } return 0; } # [ フォームからデータ取得 ] # sub read_form { local($pair,$buffer); if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } local(@pairs) = split(/&/,$buffer); foreach $pair (@pairs) { local($name,$value) = split(/=/,$pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; $FORM{$name} = &change_code($value); } } # [ クッキー処理 ] # sub check_cookie { local($text); foreach $text ('font','sort','tree','form','new_mail','res_mail') { if (($FORM{$text} ne '') && ($COOKIE{$text} ne $FORM{$text})) { $COOKIE{$text} = $FORM{$text}; } } } sub get_cookie { local($pair,%DUMMY); local($cookies) = $ENV{'HTTP_COOKIE'}; local(@pairs) = split(/;/,$cookies); foreach $pair (@pairs) { local($name,$value) = split(/=/,$pair); $name =~ s/ //g; $DUMMY{$name} = $value; } @pairs = split(/,/,$DUMMY{$cookie_name}); foreach $pair (@pairs) { local($name,$value) = split(/:/,$pair); $COOKIE{$name} = &change_code($value); } } sub set_cookie { local($cook) = "name\:$COOKIE{'name'}\,email\:$COOKIE{'email'}\,pwd\:$COOKIE{'pwd'}\,font\:$COOKIE{'font'}\,sort\:$COOKIE{'sort'}\,tree\:$COOKIE{'tree'}\,form\:$COOKIE{'form'}\,new_mail\:$COOKIE{'new_mail'}\,res_mail\:$COOKIE{'res_mail'}"; $ENV{'TZ'} = "GMT"; # 国際標準時の取得 local($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime(time + 30*24*60*60); if ($year < 99) { $year += 100; } $year += 1900; if ($sec < 10) { $sec = "0$sec"; } if ($min < 10) { $min = "0$min"; } if ($hour < 10) { $hour = "0$hour"; } if ($mday < 10) { $mday = "0$mday"; } $mon = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec')[$mon]; $youbi = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')[$wday]; $date_gmt = "$youbi, $mday\-$mon\-$year $hour:$min:$sec GMT"; print "Set-Cookie: $cookie_name=$cook; expires=$date_gmt\n"; } # [ 文字コード関連 ] # sub check_code { if (!(-r $jcode)) { &error(1,"jcode.pl がありません"); } require $jcode; local($text) = ord(substr("中澤重人=じゃわ(^-^;;",0,1)); if ($text == 0xc3) { $mojicode = "euc"; $charset_code = "x-euc-jp"; } elsif ($text == 0x92) { $mojicode = "sjis";$charset_code = "x-sjis"; } else { &error(1,"サポートしてない文字コードです"); } } sub change_code { local($text)=$_[0]; &jcode'convert(*text,$mojicode); if ($mojicode eq 'sjis') { &jcode'h2z_sjis(*text); } if ($mojicode eq 'euc') { &jcode'h2z_euc(*text); } $text =~ s//>/g; return $text; } # [ 日付取得 ] # sub get_date { $ENV{'TZ'} = "JST-9"; # TimeZone (日本時間 = 国際標準時(JST) - 9時間) local($sec,$min,$hour,$day,$mon,$year) = localtime(); if ($year < 99) { $year += 100; } $year += 1900; $year = substr($year,length($year)-2,2); $mon++; if ($date_type) { if ($sec < 10) { $sec = "0$sec"; } # 秒の修正 if ($min < 10) { $min = "0$min"; } # 分 〃 if ($hour < 10) { $hour = "0$hour"; } # 時 〃 if ($date_type > 1) { if ($mon < 10) { $mon = "0$mon"; } # 月 〃 if ($day < 10) { $day = "0$day"; } # 日 〃 } } $date =~ s/year/$year/ig; $date =~ s/mon/$mon/ig; $date =~ s/day/$day/ig; $date =~ s/hour/$hour/ig; $date =~ s/min/$min/ig; $date =~ s/sec/$sec/ig; } # [ 記録ファイルの処理 ] # sub read_file { local($logfile) = $_[0]; &lock_file($lock1);&lock_file($lock2); if ($lock_error) { &error(1,"ロックファイルを検出しました。時間をおいてご利用下さい。"); } if (!open(IN,$logfile)) { &unlock_file; &error(1,"記録ファイルの読み込み不可"); } local(@files) = ; close(IN); &unlock_file($lock2);&unlock_file($lock1); return @files; } sub write_file { local($logfile,@lines) = @_; &lock_file($lock1);&lock_file($lock2); if ($lock_error) { &error(1,"ロックファイルを検出しました。時間をおいてご利用下さい。"); } if (!open(OUT,">$logfile")) { &unlock_file; &error(1,"記録ファイルの書き込み不可"); } print OUT @lines; close(OUT); &unlock_file($lock2);&unlock_file($lock1); return @lines; } # [ ロック機構 ] # sub lock_file { local($lockfile) = $_[0]; if (!$lock_flag) { return 1; } local($retry) = 5; while (-f $lockfile) { if ($retry-- <= 0) { local($mtime) = (stat($lockfile))[9]; if ($mtime < time()-60*15) { &unlock_file($lockfile); } $lock_error = 1; return 1; } sleep 1; } open (LOCK,">$lockfile"); close(LOCK); return 1; } sub unlock_file { local($lockfile) = $_[0]; unlink($lockfile); } # [ パスワード処理 ] sub make_pwd { local($pwd) = ''; srand; for ($i=0;$i<8;$i++) { $pwd .= substr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",int(rand(62)),1); } return $pwd; } # [ エラー処理 ] # sub error { ($err,$err_msg) = @_; if ($err) { print "Content-type: text/html\n\n"; } print<<"_EOF_";

エラー:$err_msg
_EOF_ exit; }