#!/usr/local/bin/perl
#
# このtrees.txtはtrees.cgiに名前を変更してからご利用ください。
# 電子掲示板 -Trees- v2.03 FreeSoft
# (c)www.rescue.ne.jp
#
# for UNIX/SJIS
#
# [設置構成例] 詳しくはreadme.txtを参照のこと.
#
# ┣━/data/ <777>
# ┃
# ┣ jcode.pl <644>
# ┣ trees.cgi <755>
# ┣ password.cgi <666>
#
# [履歴]
# v 1.00 07/MAY/1999 初版
# v 1.01 08/MAY/1999 一覧の表示題名文字数設定
# v 1.02 17/JUN/1999 タグ有効時は
コードを出力しないように修正
# v 1.03 09/JUL/1999 タグ処理の変数ミスを修正
# ------- ここを境にデータの完全互換はありませんが、重大な支障なくデータは後継できます.
# v 2.00 10/JUL/1999 コメントメール機能,プレビュー機能,半角カナ対策,New!画像に縦横サイズ設定,コメント有り記事の削除を制限する機能
# v 2.01 11/JUL/1999 削除関係のバグを修正
# v 2.02 15/JUL/1999 意味不明のバグの修正
# v 2.03 30/APR/2000 MAC版IE5対応のためにインデントタグの修正、クッキーのURLコンコード化
#-- 必須設定 ------------------------------------------------------------------
#●管理者のメールアドレス(半角で正しく)
$administrator = 'あなたのEメールアドレス';
#●画面の「終了」リンク先(URL)
$bye = 'http://ホームページなどのURL/';
#●タイトルなどの冒頭メッセージ(HTML書式)
$title = <<'EOF';
**掲示板
EOF
# $.... = <<'EOF';
# この間に記述します.
# 複数行可能.
# EOF
#●ブラウザのタイトルバーの名称(1行のみ)
$title_bar = <<'EOF';
**掲示板
EOF
#-- 任意設定 ------------------------------------------------------------------
#●画面の色や背景の設定 (HTML書式)
$body = '';
#●バーの色
$cellcolor = '#ffeedd';
#●ホスト名の表示 1:する 0:しない
$view_host = 1;
#●タグの許可(運用途中で変更しないこと) 1:する(自動URLリンク無効) 0:しない
$allow_html = 0;
#●1画面に表示する行数(デフォルト値)
$def = 20;
#● 記録モードのデフォルトチェック値 0:改行無効 1:図表モード 2:改行有効
$chk = 2;
#●時刻設定
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
@wday_array = ('日','月','火','水','木','金','土');
#●このプログラムの場所をURLで設定(設定しなければ自動検出)
$reload = '';
#●$reloadで設定した設置URL以外のフォームからの投稿を禁止する処置 する:1 しない:0
$ref_axs = 0;
#●日本語コード変換ライブラリ(パス値) .. 2.0以上のバージョンのもの
require './jcode.pl';
#●データディレクトリの場所(パス値)
$data_dir = './data/';
#●管理者用パスワードファイル(パス値)
$pwd_file = './password.cgi';
#●コメントがある記事を管理者以外が削除できないように 1:する 0:しない
$delsave = 1;
#●コメントお知らせ機能を 1:使う 0:使わない
# (使う状態でコメント機能を利用している記事であっても、この設定が0になればメールしません)
$resmail = 0;
#○コメントお知らせ機能を使う場合に設定する --------↓
#○sendmailの設定(パス値)
$sendmail = '/usr/lib/sendmail';
#○メールの題名
$mail_subject = '**掲示板からのお知らせ';
#○メール本文の冒頭に入れる文章($mail_val = <<'EOF';とEOFの間に記述する)
$mail_val = <<'EOF';
「わたしのホームページ」 http://www.foo.bar/~user/ の
「**掲示板」へお越しください。
EOF
#○メール本文の終わりに入れる文章(シグネチャ/署名)
$mail_val2 = <<'EOF';
---------------------------------------------
MyHomePage http://www.foo.bar/ user@mail.host
EOF
#---------------------------------------------------↑
#●コメントに階層番号を 0:つけない 1:付ける
$attnum = 1;
#●ツリー構成用罫線
$keisen = '┣';
#●番号を囲む括弧(左)
$kakko_l = '【';
#●番号を囲む括弧(右)
$kakko_r = '】';
#●クリックポイント印
$point = '≪';
#●クリックポイント印の色
$pointc = '#ff3333';
#●一覧時の題名文字数制限(byte)
$subject_max_length = 100;
#-- 過去ログ設定 --------------------------------------------------------------
#●過去ログ機能を 1:使う 0:使わない
$log = 0;
#●過去ログの場所(パス値)と名称
%LOG = (
'' , '',
);
#-- 高度な設定 ----------------------------------------------------------------
#●手順
$prot = 'http';
#●クッキーを認識する範囲(通常はこのままでよい)
# 詳しいことは http://www.netscape.com/newsref/std/cookie_spec.html のpathの項目をご覧ください.
$path = '';
#------------------------------------------------------------------------------
if ($jcode'version < 2) { &error('ライブラリ異常','jcode.plは2.0以降のバージョンを設置してください.'); }
if ($reload ne '') { $SCRIPT_NAME = $reload; } # プログラム名の指定設定
else { $SCRIPT_NAME = $ENV{'SCRIPT_NAME'}; } # 自動設定
if ($SCRIPT_NAME eq '') { &error("設定エラー",'(E1)'); } # $SCRIPT_NAMEはクッキー名にも使う
$wcheck = 'wwwbbs.wck'; # 同内容連続投稿防止ファイル名
$lockfile = 'wwwbbs.lock'; # ロックファイル名
$date_now = sprintf("%04d/%01d/%01d(%s)%02d:%02d",$year +1900,$mon +1,$mday,$wday_array[$wday],$hour,$min); # 時刻構成
&decode_cookie($SCRIPT_NAME); # クッキー取得
$cname = $SCRIPT_NAME . '2'; &decode_cookie($cname); # 既読位置取得
$cname = $SCRIPT_NAME . '3'; &decode_cookie($cname); # 一覧数取得
if ($COOKIE{'list'} > 0) { $def = $COOKIE{'list'}; } # 行数設定
if ($COOKIE{'mode'} eq '') { $COOKIE{'mode'} = 't'; } # 一覧モード設定
$cmd = $ENV{'QUERY_STRING'}; # クエリー入力
@pairs = split(/&/,$cmd);
foreach $pair (@pairs) {
($name,$value) = split(/=/,$pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$CMD{$name} = $value; # クエリーデータはコマンド用連想配列へ
}
read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); # 標準入力
@pairs = split(/&/,$buffer);
foreach $pair (@pairs) {
($key,$val) = split(/=/,$pair);
$val =~ tr/+/ /;
$val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
&jcode'h2z_sjis(*val); # 半角カナ→全角(SJIS)変換
&jcode'convert(*val,'sjis'); # SJIS変換
if ($key eq 'preview') { $preview = 1; } # プレビュー処理の検知
$val =~ s/\t//g; # タブコードを無効化
$val =~ s/\r\n/\n/g; # Win → Unix
$val =~ s/\r/\n/g; # Mac → Unix
unless ($key eq 'value') { # 内容文以外はタグを無視
$val =~ s/&/&/g;
$val =~ s/"/"/g;
$val =~ s/</g;
$val =~ s/>/>/g;
}
$in{$key} = $val;
}
if ($preview) { &prev; exit; } # プレビュー処理へ
if (!-e $pwd_file) { &error("エラー","(E2)"); }
if ($in{'action'} eq 'setpwd') { &setpwd; }
if (-z $pwd_file || $CMD{'action'} eq 'resetpwd') { &setpwd_form; }
($admin) = &master_check; # 管理者権限確認(管理パスワードなら$admin値は1)
# 過去ログ選択
if (!$log) { $in{'log'} = $CMD{'log'} = ''; }
if ($CMD{'log'} ne '') { $in{'log'} = $CMD{'log'}; }
if ($in{'log'} ne '') {
$data_dir = $in{'log'};
if (!-d $data_dir) { &error("過去ログが見つかりません","(E18)"); }
$LOG_NAME = $LOG{$data_dir};
$CMD{'log'} = $in{'log'};
$title_bar .= " - $LOG_NAME";
$newms = '一覧';
}
else { $newms = '最新の一覧'; }
chdir($data_dir); # ディレクトリ移動
if (!$CMD{'log'}) { &lock; } # ファイルロック
if ($CMD{'st'}) { $in{'start'} = $CMD{'st'} - 1; } # リスト位置
if ($in{'action'} ne '') { $CMD{'action'} = $in{'action'}; } # アクション値をコマンドにもコピー
if ($CMD{'search'} ne '') { $in{'search'} = $CMD{'search'}; }
if ($CMD{'mode'} ne '') { $in{'mode'} = $CMD{'mode'}; }
if ($CMD{'t'}) { # クリックポイント処理
if ($in{'v'} =~ /\D/) { &error("エラー","数字は半角文字で入力してください."); }
if (-e "$in{'v'}\.msg") { $CMD{'e'} = 'msg'; }
elsif (-e "$in{'v'}\.res") { $CMD{'e'} = 'res'; }
else { &error("File Not Found","$numberは削除されています."); }
$CMD{'lp'} = $CMD{'v'} = $in{'v'};
}
elsif ($CMD{'tw'} ne '') { $CMD{'t'} = $CMD{'tw'}; }
if ($CMD{'v'} =~ /(\d+)/ && $CMD{'e'} =~ /(msg|res)/) { &view($CMD{'v'},$CMD{'e'}); } # 記事表示
elsif ($CMD{'image'} eq 'new') { &image($CMD{'image'}); }
elsif ($CMD{'image'} eq 'copyright') { &image($CMD{'image'}); }
elsif ($CMD{'bye'} ne '') { &bye; }
elsif ($CMD{'mc'}) {
# リストモード変更
$cook="uname\:$COOKIE{'uname'}\,email\:$COOKIE{'email'}\,pwd\:$COOKIE{'pwd'}\,mode\:$CMD{'mc'}";
$cook =~ s/([^0-9A-Za-z_])/"%" . unpack("H2",$1)/ge; # URLエンコード
$cook =~ tr/ /+/;
print "Set-Cookie: $SCRIPT_NAME=$cook; path=$path; expires=$date_gmt\n";
$COOKIE{'mode'} = $CMD{'mc'};
&list;
}
else {
if ($in{'start'} eq '') { $start = 0; } # リスト開始位置
else { $start = $in{'start'} + 1; }
if ($CMD{'action'} eq 'post' && !$CMD{'log'}) { &post; } # 投稿画面へ
elsif ($in{'action'} eq 'write' && !$CMD{'log'}) { &write; } # 記録処理へ
elsif ($in{'action'} eq 'remove' && !$CMD{'log'}) { # 削除処理へ
($result) = &remove;
if (!$result) { $alldel = 1; }
if ($in{'search'} ne '') { &search; }
else { &list; }
}
elsif ($in{'search'} ne '') { &search; } # 検索リスト
else { &list; } # 通常リスト
}
if (-e $lockfile) { unlink $lockfile; } # ロック解除
exit;
sub getdir {
local($type) = @_;
$od_check = (eval { opendir(DIR,'.'); }, $@ eq "");
if (!$od_check) {&error("エラー","(E3)"); }
@newls = ();
@list = readdir(DIR); # ファイル名の抽出
foreach $file (@list) {
next if -d $file;
if ($type eq 'n') {
# 番号順一覧
if ($file =~ /(\d+)\.tre/) { next; }
if ($file =~ /(\d+)\.(msg|res)/) { push(@newls,"$1\.$2"); }
}
else {
# ツリー一覧
if ($file =~ /(\d+)\.tre/) { push(@newls,"$1\.tre"); }
}
}
close(DIR);
@newls = sort { $b <=> $a; } @newls;
$all = @newls;
}
sub getlast {
$od_check = (eval { opendir(DIR,'.'); }, $@ eq "");
if (!$od_check) {&error("エラー","(E3)"); }
@newls2 = ();
@list = readdir(DIR);
foreach $file (@list) {
next if -d $file;
if ($file =~ /(\d+)\.tre/) { next; }
if ($file =~ /(\d+)\.(msg|res)/) { push(@newls2,"$1\.$2"); }
}
close(DIR);
@newls2 = sort { $b <=> $a; } @newls2;
return($newls2[0]); # 最高番号検出
}
sub list {
if ($in{'search'} ne '') {
if ($in{'search'} =~ /[&"<>]/) { &error("入力文字制限","検索文字列に記号の入力はできません."); }
$keys = $target = $in{'search'};
$keys =~ s/ / /g;
$target =~ s/ / /g;
$target =~ s/(\W)/\\$1/g;
@keys = split(/\\\s+/,$target);
}
&getdir($COOKIE{'mode'});
if ($in{'cls'}) { # 行数変更
$def = $in{'ls'};
print "Set-Cookie: $SCRIPT_NAME" . '3' . "=list:$def; path=$path; expires=$date_gmt\n";
}
# 一覧行の検討
if ($all <= ($start + $def - 1)) { $end = $all - 1; }
else { $end = $start + $def - 1; }
if ($COOKIE{'mode'} eq 'n') { $mc = 't'; $mc2 = 'ツリー一覧'; }
else { $mc = 'n'; $mc2 = '番号順一覧'; }
&html_head;
print "$body\n";
print "$title\n";
if ($all != 0) {
print "\n";
if ($start != 0 || $cmd ne '' || $CMD{'log'}) { print "〔前の画面〕"; }
if (!$CMD{'log'}) { print "〔新しい話題〕"; }
print "〔検索〕";
print "〔$newms〕";
print "〔$mc2〕";
if ($CMD{'log'}) { print "〔最新のログ〕"; }
if (!$CMD{'log'}) { print "〔全て読んだことにする〕"; }
if (!$CMD{'log'}) { print "〔全て読んだことにして終了〕"; }
print "〔終了〕";
print "
\n";
if ($CMD{'log'}) { $COOKIE{'rp'} = ''; }
elsif ($COOKIE{'rp'} ne '' && $start == 0) {
($lastf) = &getlast;
($lastnum,$ext) = split(/\./,$lastf,2);
$rp2 = $COOKIE{'rp'} + 1;
if ($COOKIE{'rp'} > $lastnum) { $COOKIE{'rp'} = $lastnum; }
else {
print "《 あなたの最終アクセス日 $COOKIE{'lastlogin'} 既読番号 〜No.$COOKIE{'rp'} 》\n";
print "
\n";
if ($COOKIE{'rp'} < $lastnum) {
if ($rp2 == $lastnum) { $msg = $rp2; } else { $msg = "$rp2〜$lastnum"; }
print "- 前回より、$msgが新規投稿されています.\n";
if ($COOKIE{'mode'} ne 'n') { print "
- まとめて見るには〔$mc2〕にすると便利です.\n"; }
}
print "
\n";
}
}
if ($alldel) { print "\n"; }
if ($LOG_NAME ne '') { print "$LOG_NAME
\n"; }
print "\n";
if ($start != 0) { print "- ↑\n"; }
foreach $num ($start .. $end) {
$k = ''; # 罫線クリア
if ($COOKIE{'mode'} eq 'n') {
# 時系列形式
($file,$ext) = split(/\./,$newls[$num],2); # ファイル名と拡張子に分ける
if ($ext eq 'msg') { $cell = " bgcolor=$cellcolor"; } else { $cell = ''; }
if ($CMD{'bk'} == $file || $res_bk == $file) { $file2 = ""; } else { $file2 = $file; }
if (-s $newls[$num] == 0) { print "
- \n"; next; }
($result) = &gethead($newls[$num],0); # 記事ヘッダの取得(第2引数が0でヘッダのみ、1で@VALに内容文を取得)
if (!$result) { print "
- $kakko_l$file$kakko_r" . "Read Error E10($newls[$num])\n"; next; }
if ($HD{'email'} ne '') { $HD{'uname'} = "$HD{'uname'}"; }
if ($file > $COOKIE{'rp'} && $COOKIE{'rp'} ne '') { $new = ""; } else { $new = ''; }
if (length($HD{'subject'}) > $subject_max_length) { $HD{'subject'} = substr($HD{'subject'},0,$subject_max_length -1); $HD{'subject'} = $HD{'subject'} . '..'; }
$line = "$kakko_l$file2$kakko_r\$new $HD{'subject'} $HD{'date'} $HD{'uname'} ($HD{'size'})";
$line = "";
print "
- $line\n";
}
else {
# スレッド形式
if (open(TREE,"$newls[$num]")) {
@trees = ;
close(TREE);
}
else { print "
- $kakko_l$file$kakko_r" . "Read Error E11($HD{'tree'}\.tre)\n"; next; }
foreach $line (@trees) {
$line =~ s/\n//g;
if ($line =~ /
- /) { next; }
elsif ($line =~ /
/) { print "\n"; next; }
elsif ($line =~ /<\/DL>/) { print "
\n"; next; }
elsif ($line =~ /- \!(\d+)\.(msg|res)/) {
$num = $1;
$ext = $2;
if ($CMD{'bk'} == $num || $res_bk == $num) { $num2 = ""; } else { $num2 = $num; }
if ($ext eq 'res') { $k = $keisen; }
if ($ext eq 'msg') { print "
- \n"; }
else { print "
- $k$kakko_l$num2$kakko_r 削除\n"; }
next;
}
elsif ($line =~ /
- \D*(\d+)\.(msg|res)/) {
$num = $1;
$ext = $2;
$file = "$num\.$ext";
if ($CMD{'bk'} == $num || $res_bk == $num) { $num2 = ""; } else { $num2 = $num; }
if (-s $file == 0) {
if ($ext eq 'msg') { print "
- \n"; }
else { print "
- $k$kakko_l$num2$kakko_r 削除\n"; }
next;
}
($result) = &gethead($file,0);
if (!$result) {
if ($ext eq 'res') { $k = $keisen; }
print "$k$kakko_l$num2$kakko_r" . "Read Error E10($file)\n";
next;
}
if ($file > $COOKIE{'rp'} && $COOKIE{'rp'} ne '') { $new = ""; } else { $new = ''; }
if ($HD{'email'} ne '') { $HD{'uname'} = "$HD{'uname'}"; }
if (length($HD{'subject'}) > $subject_max_length) { $HD{'subject'} = substr($HD{'subject'},0,$subject_max_length -1); $HD{'subject'} = $HD{'subject'} . '..'; }
$change = "$kakko_l$num2$kakko_r\$new $HD{'subject'} $HD{'date'} $HD{'uname'} ($HD{'size'}) ";
$line =~ s/$file/$change/;
$line =~ s/
- //;
if ($ext eq 'msg') { $line = ""; }
else { $k = $keisen; }
}
print "
- $k$line\n";
}
}
}
print "
\n";
}
else {
print "\n";
if (!$CMD{'log'}) { print "〔新しい話題〕"; }
print "〔$newms〕";
if ($CMD{'log'}) { print "〔最新のログ〕"; }
print "〔終了〕";
print "\n";
print "メッセージはありません.
\n";
}
print "
\n";
if ($all != 0) {
print "\n";
if ($start != 0 || $cmd ne '' || $CMD{'log'}) { print "〔前の画面〕"; }
if (!$CMD{'log'}) { print "〔新しい話題〕"; }
print "〔$newms〕";
print "〔$mc2〕";
if ($CMD{'log'}) { print "〔最新のログ〕"; }
if (!$CMD{'log'}) { print "〔全て読んだことにする〕"; }
if (!$CMD{'log'}) { print "〔全て読んだことにして終了〕"; }
print "〔終了〕";
print "\n";
}
print "
\n";
$i = $all - 1;
if ($end < $i) {
print "\n";
}
if ($all != 0) {
print <<"EOF";
|
EOF
if ($start == 0) { # 最初の画面だけ表示する
print <<"EOF";
EOF
}
}
if ($start == 0 && $all != 0) {
if ($COOKIE{'mode'} ne 'n') { $mes = '↑コメント記事はカウントされません.'; }
print <<"EOF";
|
$mes\n";
# 必ず表示してくださいね
print "
\n";
if (!$CMD{'log'}) { print ""; }
print "〔管理者への問合せ〕\n"; # 管理に関して当サイトに問合せが来ることがある為
print " ( )内は記事サイズ