#!/usr/bin/perl # プロバイダーの指示による
#
# --- dengon.cgi 記事閲覧 (Apache) 実施1版 ---
#
$ENV{'TZ'} = "JST-9"; # Set timezone
@wdays = ( "日", "月", "火", "水", "木", "金", "土", "日" );
#
# --- 設置状態により変える -----------------------------------
$progrm_name = "dengon.cgi";
$msg_logfile = "./dengon.log"; # 対象ファイルにより変更
$msg_tmpfile = "./dengon.tmp"; # フォルダにより変更
$msg_lockfda = "./msgboardloc"; # フォルダにより変更
$jcode_pfile = "./jcode.pl"; # フォルダにより変更
$adminiPass = "......"; # 管理者Password ←★変えるべき★
$allow_html = 1; # Allow HTML tags
$max_msgs = 500; # Maximum number of messages
$kj_last = 0; # (notUsed)作業用(Paging前の最終記事SeqNo):変えない
$henmssg = ""; # TextAreaの初期値(変更のとき使う)
# rmdir($msg_lockfda); # <--- File unlock
#
# --- 環境変数の取得 -----------------------------------------
#
$usr_adr = $ENV{'REMOTE_ADDR'};
$usr_cook = $ENV{'HTTP_COOKIE'};
# --- クッキー情報の取得→(@cookTbl) ---
@a = split(/; /, $usr_cook); # ; (space)で分解
foreach $x (@a) {
if ($x =~ /^MsgL2=/) { # MsgL2=で始まっていたら
$x =~ s/MsgL2=//;
@cookTbl = split(/,/, $x); # $cookTbl[0]=名前,$cookTbl[1]=Key
}
}
#
# --- 管理者か? ---
if ($usr_adr eq "127.0.0.1" || $cookTbl[1] eq $adminiPass) {
$myself = "yes";
} else {
$myself = "no";
}
#
# --- Japanese KANJI code ------------------------------------
#
if (-f $jcode_pfile) {
$jflag = true;
require $jcode_pfile;
$code = ord(substr("漢", 0, 1));
if ($code == 0xb4) {
$ccode = "euc";
$hcode = "x-euc-jp";
} elsif ($code == 0x1b) {
$ccode = "jis";
$hcode = "iso-2022-jp";
} else {
$ccode = "sjis";
$hcode = "x-sjis";
}
}
#
# --- File lock -----------------------------------------------
#
foreach $i ( 1, 2, 3 ) {
if (mkdir($msg_lockfda, 0755)) {
last;
} elsif ($i == 1) {
($mtime) = (stat($msg_lockfda))[9];
if ($mtime < time() - 600) {
rmdir($msg_lockfda);
}
} elsif ($i < 3) {
sleep(1);
} else {
print "Content-type: text/html\n";
print "\n";
print "
メッセージリスト \n";
print "\n";
print "メッセージリスト \n";
print " \n";
print "只今、メッセージ閲覧が混雑、しばらく後で再度アクセスして下さい。\n";
print " \n";
print "\n";
exit(1);
}
}
#
# --- 記事の最大番号取得 ---
$maxnumb = 0;
$msgnumb[0] = 0; # メッセージ番号の変数
open(IN, $msg_logfile); # log fileは空でも必ずある
while () { # log fileの第1行を読む
if ($_ =~ /\e/) { # \eがあれば
@msgnumb = split(/\e/, $_); # \eで分解(最初はッセージ番号)
if ($msgnumb[0] > $maxnumb) {$maxnumb = $msgnumb[0];}
}
}
close(IN);
#
# --- Read from 標準入力 ------------------------------------------------
#
if ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN, $query_string, $ENV{'CONTENT_LENGTH'});
@a = split(/&/, $query_string);
foreach $x (@a) {
($name, $value) = split(/=/, $x);
$value =~ tr/+/ /; # spaceは"+"で来る
$value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; # URL文字列のDeCode
if ($jflag) {
&jcode'convert(*value, "euc");
}
if ($allow_html) { # "","0",0は偽、以外は真
$value =~ s//-->/g;
} else {
$value =~ s/&/&/g;
$value =~ s/"/"/g;
$value =~ s/</g;
$value =~ s/>/>/g;
}
if ($jflag) { # jcode.plファイルが存在すれば
&jcode'convert(*value, $ccode);
}
if ($name eq "dspchk") {$name = $name . $value;} # (★)工夫した
$FORM{$name} = $value;
}
}
#
# --- 初期表示 ------------------------------------------------------------
#
if ($ARGV[0] eq "") {
&hyohyoj();
rmdir($msg_lockfda);
exit(0);
}
#
# --- (SUB) タイトル一覧表示のHTML document 作成 ---------------------------
#
sub hyohyoj {
print "Content-type: text/html\n";
print "\n";
print "\n";
print " \n";
print "伝言板 \n";
print "\n";
print "\n";
print " 伝言板 : 読者と作者の情報交換 \n";
print " \n";
print " これは(書き込み者と主宰者)の1対1伝言板です。 \n";
print " 記事を読む場合、書き込み時のパスワードを必要とします。 \n";
print " 主宰者が返信した場合、元記事と同じパスワードで見られます。 \n";
print " \n";
print "
\n";
#
print " \n";
print "\n";
print " \n";
print "書き込みフォームは下にあり \n";
print " \n";
print "伝言タイトル一覧 \n";
print "内容を表\示したいタイトルにチェックをつけてください。";
print " (最大記事番号=$maxnumb) \n";
print "
\n";
#
# --- 記事選択フォーム ---------------------
#
print "\n";
#
# --- (変更)削除フォーム -------------
#
print "変更・削除フォーム \n";
print "\n";
#
# --- 投稿フォーム ---------------------
#
print " \n";
print "\n";
print "\n";
print "";
print "\n";
print "\n";
print " The story begins thirty years before when the Earnshaw family lived at Wuthering Heights consisting \n";
print "of, as well as the mother and father, Hindley, a boy of fourteen, and six-year-old Catherine, the same \n";
print "person that he had dreamt about and the mother of the present mistress. In that year, Mr Earnshaw \n";
print "travels to Liverpool where he finds a homeless, gypsy boy of about seven whom he decides to adopt as \n";
print "his son. He names him \"Heathcliff\". Hindley, who finds himself excluded from his father's affections by \n";
print "this newcomer, quickly learns to hate him but Catherine grows very attached to him. Soon Heathcliff and \n";
print "Catherine are like twins, spending hours on the moors together and hating every moment apart.\n";
print " \n";
print "
\n";
print "\n";
print " \n";
print " \n";
print "書き込みフォーム ";
print "記入者欄は省略して下さい。特に書きたいなら書いてよい。 \n";
print "\n";
print " \n";
print " トップページ \n";
print "\n";
}
#
#--- 記事変更フォーム ---------------------------------
#
sub kjhenkou {
print "Content-type: text/html\n";
print "\n";
print "\n";
print " \n";
print "記事変更 \n";
print "\n";
print "記事変更フォーム ";
print " 記入者欄は省略して下さい。 \n";
print "\n";
print "\n";
}
#
# --- 記事内容表示 ------------------------------------------------------
#
if ($ARGV[0] eq "etsuran") {
print "Content-type: text/html\n";
print "\n";
print "\n";
print " \n";
print "メッセージ閲覧 \n";
print "\n";
print "";
print "記事内容表\示 \n";
#
# --- 記事保存ファイルの読込、htmlの組立 ---
$delkey = $FORM{'PASWRD'};
$kjdspln = 0;
open(IN, $msg_logfile);
$kjheader[0] = 0;
while () {
if ($_ =~ /\e/) { # \eがあれば
@kjheader = split(/\e/, $_); # \eで分解
$kjban = $kjheader[0];
$name = "dspchk$kjban";
$dspflg = 0;
if ($FORM{$name} == $kjban) {
$dspflg = 1;
$kjdspln ++;
$kjheader[4] =~ s/\n//;
if ($kjdspln > 1) { print " \n"; }
if ($delkey eq $adminiPass || $delkey eq $kjheader[4]) {
print " \n";
print "$kjban:";
print "$kjheader[1] ";
## print " 投稿者 :$kjheader[2] ";
## print " $kjheader[3] ";
if ($kjheader[2] eq "" || $kjheader[2] =~ /省略/) {
print " ";
} else {
print " 投稿者:$kjheader[2] ";
}
if ($delkey eq $adminiPass) { print " ($kjheader[4])"; }
print "\n\n";
} else {
print "
\n";
print "$kjban:";
print "
$kjheader[1] ";
if ($kjheader[2] eq "" || $kjheader[2] =~ /省略/) {
print " ";
} else {
print "
投稿者:$kjheader[2] ";
}
print "
\n";
print "---(パスワードが違う)--- \n";
$dspflg = 0;
}
}
} else {
if ($dspflg == 1) {print;} # これが無いと出ない
}
}
close(IN);
print "
\n";
print "
\n";
print " 指定された password($delkey) \n";
print " トップページ \n";
print "\n";
rmdir($msg_lockfda);
exit(0);
}
#
# --- When 変更 --------------------------------------------------------------
#
if ($ARGV[0] eq "innyou" && $FORM{'DELKUB'} eq "変更") {
$wildel = $FORM{'DELBAN'};
if ($FORM{'DELKEY'} eq "") {
rmdir($msg_lockfda);
&errmsg("記事に設定した照合キーを入力してください。");
}
$delkey = $FORM{'DELKEY'};
$nowban = 0;
$delcnt = 0;
$gyocnt = -1;
#
# --- Read log-file ---
open(IN, $msg_logfile);
$kjheader[0] = 0;
while () {
if ($_ =~ /\e/) { # \eがあれば
@kjheader = split(/\e/, $_); # \eで分解
$nowban = $kjheader[0];
$nowkey = $kjheader[4];
$nowkey =~ s/\n//;
if ($nowban eq $wildel) {
if ($nowkey eq $delkey) {
$delcnt = 1;
$FORM{'DAIMEI'} = "$kjheader[1]";
} else {
rmdir($msg_lockfda);
&errmsg("照合キーが違います。($FORM{'DELKEY'})"); #($nowkey)
}
}
}
# --- 記事を一時保管 ---
if ($nowban eq $wildel) {
$gyocnt++;
$_ =~ s/ | //g;
$gyomoj[$gyocnt] = $_;
} else {
if ($gyocnt > -1) {last;}
}
}
close(IN);
if ($delcnt == 0) {
rmdir($msg_lockfda); # <--- File unlock
&errmsg("(変更)番号に該当する記事がありません。");
}
$FORM{'PRENUM'} = $wildel;
$FORM{'PREKUB'} = "変更";
#
# --- 記事の編集 ---
$henmssg = "";
$iiimax = $gyocnt;
if ($iiimax >= 0) {
$gyomoj[$iiimax] =~ s/\n//g; # Add 少し効果ある
for ($iii = 1; $iii <= $iiimax; $iii++) {
$henmssg = $henmssg . $gyomoj[$iii];
}
}
$henmssg =~ s/\n$//; # 最後の"\n"のみ取り除く
&kjhenkou();
rmdir($msg_lockfda); # <--- File unlock
exit(0);
}
#
# --- When(仮)削除 ------------------------------------------------------------------
#
if ($ARGV[0] eq "innyou" && $FORM{'DELKUB'} eq "削除") {
$wildel = $FORM{'DELBAN'};
$wilkey = $FORM{'DELKEY'};
# --- 削除の確認 ---
print "Content-type: text/html\n";
print "\n";
print "\n";
print " \n";
print "削除の確認 \n";
print "\n";
print "\n";
print "削除指示の確認 \n";
print "確かに削除するとき、下をクリック。 削除キャンセルなら戻って下さい。 \n";
print "\n";
print " \n";
print " \n";
print " \n";
print " \n";
print "記事番号 ($wildel) password($wilkey) ";
print " \n";
print "\n";
rmdir($msg_lockfda); # <--- File unlock ------
exit(0);
}
#
# --- When 削除 ------------------------------------------------------------------
#
if ($ARGV[0] eq "innyou" && $FORM{'DELKUB'} eq "削除する") {
$wildel = $FORM{'DELBAN'};
$nowban = 0;
$nowkey = "";
$delcnt = 0; # 削除該当あったか否か
$delkey = $FORM{'DELKEY'};
#
# --- Copy log -> tmp ---
open(IN, $msg_logfile);
open(OUT, "> $msg_tmpfile");
$msgnumb[0] = 0;
while () {
if ($_ =~ /\e/) { # \eがあれば
@msgnumb = split(/\e/, $_); # \eで分解
if ($msgnumb[0] > 0) {
$nowban = $msgnumb[0];
$nowkey = $msgnumb[4];
if ($nowban == $wildel) {
$nowkey =~ s/\n//; # add
if ($delkey eq $adminiPass || $nowkey eq $delkey) {
$delcnt = 1;
$delkij = $msgnumb[1];
} else {
rmdir($msg_lockfda);
&errmsg("削除キーが違います。($FORM{'DELKEY'})");
}
}
}
}
if ($nowban != $wildel) {print OUT;}
}
close(IN);
close(OUT);
if ($delcnt == 0) {
rmdir($msg_lockfda); # <--- File unlock
&errmsg("(削除)番号に該当する文書がありません。");
}
#
# --- Copy tmp -> log ---
open(IN, $msg_tmpfile);
open(OUT, "> $msg_logfile");
while () {
print OUT;
}
close(IN);
close(OUT);
#
# --- Print HTML --------------
print "Content-type: text/html\n";
print "\n";
print "\n";
print " \n";
print "伝言ボード \n";
print "\n"; # #e8f8d0
print "伝言ボード \n";
print "$wildel番「$delkij」を削除しました。 password($delkey) \n";
print " \n";
print "[戻る]ボタンで、3度戻る。 または下記で。 \n";
print " トップページ \n";
print "\n";
rmdir($msg_lockfda); # <--- File unlock
exit(0);
}
#
# --- 送信(投稿)時の処理 --------------------------------------------
#
if ($ARGV[0] eq "toukou") {
# --- add:アラシ対策 ---
for ($iii = 0; $iii < length($FORM{'DAIMEI'}); $iii++) {
$ichiji = substr($FORM{'DAIMEI'}, $iii, 1);
if ($ichiji =~ /[a-zA-Z0-9\ \/:._\-]/) { } else { $alpnum = "NO"; last;}
}
if ($alpnum eq "NO") { } else {
rmdir($msg_lockfda);
&errmsg("error");
}
# --- 未入力ほかチェック ---
if ($FORM{'MESSAGE'} eq "") {
rmdir($msg_lockfda);
&errmsg("空メッセージはいけません。");
}
if ($FORM{'PREKUB'} ne "変更" && " $date ($usr_adr)" eq $LastTitle) {
rmdir($msg_lockfda);
&errmsg("連続投稿はできません。");
}
# --- クッキー情報の設定 ---
$set_cook = "$FORM{'SHIMEI'},$FORM{'DELKEY'}";
$set_yuko = "Fri, 1-Jan-2020 01:01:01 GMT";
print "Set-Cookie: MsgL2=$set_cook; expires=$set_yuko\n"; # クッキー出力
# --- メッセージ番号Count-up:新規のみだが,変更でも害なし ---
$maxnumb ++;
if ($maxnumb < 10) {$maxnumb = "00" . $maxnumb;}
elsif ($maxnumb < 100) {$maxnumb = "0" . $maxnumb;}
$msgnumb[0] = $maxnumb;
# --- Pre-Append messages. --------------
$henban = $FORM{'PRENUM'};
$henkub = $FORM{'PREKUB'};
$FORM{'PRENUM'} = "";
$FORM{'PREKUB'} = "";
$found = 0;
open(IN, $msg_logfile);
open(OUT, "> $msg_tmpfile");
if ($henkub eq "変更") {
while ($logbuf = ) {
if ($logbuf =~ /\e/) { # \eがあれば
@kjheader = split(/\e/, $logbuf); # \eで分解
if ($kjheader[0] eq $henban) {
$found = 1;
$logHozon = $logbuf; # 記事ヘッダを一時記憶
} else {
if ($found == 1) {$found = 2; last;}
}
}
if ($found == 0) {print OUT $logbuf;} # 変更対象記事の直前まで出力
}
if ($found == 0) {
rmdir($msg_lockfda);
&errmsg("対象番号の記事がありません。(削除済か?)");
}
}
# --- メッセージ記録の内容調整 ------------- # 下は完全でないが,3改行ぐらいならOK
$FORM{'MESSAGE'} =~ s/\r\n*$//g; # ←「1個以上の\r\nで終わる」か?
$FORM{'MESSAGE'} =~ s/\r*$//g; # ←「1個以上の\rで終わる」か?
$FORM{'MESSAGE'} =~ s/\n*$//g; # ←「1個以上の\nで終わる」か?
$FORM{'MESSAGE'} =~ s/\r/ /g; # \rはリターン、標準入力ではこうなる
# --- 変更:旧タイトルと変更したメッセージをLOGファイルに記録 ---
if ($henkub eq "変更") {
@kjheader = split(/\e/, $logHozon); # \eで分解
print OUT "$kjheader[0]\e$FORM{'DAIMEI'}\e$FORM{'SHIMEI'}\e";
print OUT "$kjheader[3]\e$kjheader[4]";
print OUT "$FORM{'MESSAGE'} \n"; # メッセージ
# --- 新規:新メッセージをLOGファイルに記録 ----------
} else {
$delkey = $FORM{'DELKEY'};
# -- 番号・タイトル・名前・日付(IPadr)・delky --
print OUT "$msgnumb[0]\e$FORM{'DAIMEI'}\e$FORM{'SHIMEI'}\e";
print OUT " $date ($usr_adr)\e$delkey\n";
# -- メッセージ --
if ($FORM{'MESSAGE'} ne "") {print OUT "$FORM{'MESSAGE'} \n";}
}
# --- Append-2 messages. --------------
if ($found == 2) {print OUT $logbuf;} # 変更書込の時;次記事ヘッダ読んでるから
while () { # 後続Logの転記
print OUT;
}
close(IN);
close(OUT);
#
# --- Copy .tmp to .log -------------------------
open(IN, $msg_tmpfile);
open(OUT, "> $msg_logfile");
$msgs = 0;
while () {
if ($_ =~ /\e/) { # \eがあれば
if ($max_msgs != 0) {
if ($msgs++ >= $max_msgs) {last;}
}
}
print OUT;
}
close(IN);
close(OUT);
&outhtml();
rmdir($msg_lockfda); # <--- File unlock
exit(0);
}
#
# ---- (SUB) Print HTML document -----------------------------------------
#
sub outhtml {
# --- Print HTML(投稿後の記事のみ表示) --------------
print "Content-type: text/html\n";
print "\n";
print "\n";
print " \n";
print "伝言ボード \n";
print "\n"; # #e8f8d0
print "伝言ボード \n";
if ($henkub eq "変更") {print " ($henban番記事を変更しました。)\n";}
else {print " (新規)書き込みを受理しました。[戻る]ボタンで、2回戻る。 または下記で。\n";}
# ---add sta-----------------------------------------------
print " \n";
print "\n";
if ($henkub eq "変更") {print "変更した記事 \n";}
else {print "新規記事内容 \n";}
# --- 記事保存ファイルの読込、htmlの組立 ---
open(IN, $msg_logfile);
$kjcnt = 0;
while () {
if ($henkub eq "") {
if ($_ =~ /\e/) { # \eがあれば
if ($kjcnt == 1) { last; } # Loopから出る
$kjcnt ++;
@kjheader = split(/\e/, $_); # \eで分解
$kjban = $kjheader[0];
print " \n";
print "$kjban:";
print "$kjheader[1] ";
if ($kjheader[2] eq "" || $kjheader[2] =~ /省略/) {
print " ";
} else {
print " 投稿者:$kjheader[2] ";
}
print "\n";
} else {
print;
}
} elsif ($henkub eq "変更") {
if ($_ =~ /\e/) { # \eがあれば
if ($kjcnt == 1) { last; } # Loopから出る
@kjheader = split(/\e/, $_); # \eで分解
$kjban = $kjheader[0];
if ($kjban == $henban) {
$kjcnt = 1;
print "
\n";
print "$kjban:";
print "
$kjheader[1] ";
if ($kjheader[2] eq "" || $kjheader[2] =~ /省略/) {
print " ";
} else {
print "
投稿者:$kjheader[2] ";
}
print "
\n";
}
} else {
if ($kjcnt == 1) {print;}
}
}
}
close(IN);
print "
\n";
print "
\n";
# ---add end-----------------------------------------------
print " トップページ \n";
print "\n";
}
#
# --- (SUB) Print ERROR document ---------------------------------------------
#
sub errmsg {
print "Content-type: text/html\n";
print "\n";
print "\n";
print "\n";
print " \n";
print "エラー \n";
print "\n";
print "\n";
print "エラー \n";
print " \n";
print "$_[0]\n"; # <-- 引数はここに来るらしい
print "\n";
print "\n";
exit(0);
}
#
# --- 引数エラーに備えて(開発段階のみ) ------
#
rmdir($msg_lockfda);
&errmsg("自己診断:CGI プログラム(msglst2.cgi)の引数エラー");