#!/usr/local/bin/perl # ============================================================================= # BestBBS!! v.0.4.3 # # This software has been developed by Taichi Maruyama . # This file must be encoded in shift-jis encoding. $PROG_NAME = 'BestBBS!!'; $PROG_VERSION = '0.4.3'; require 'jcode.pl'; # ============================================================================= # 高度な設定 # # 詳しくは readme.txt をご覧ください。 # ■ パスワードの暗号化 # パスワードを crypt を利用して暗号化するかどうかの設定です。 # 利用する場合は1。利用しない場合は 0。デフォルトは 1。 # サーバーが WindowsNT の場合は、0 にしておきましょう。 $USE_CRYPT = 1; # ■ 設定ファイル # プログラムの動作に関する設定を保存するファイル名です。 # $USE_CRYPT を 0 にした場合は、この名前は必ず変更してください。 # パスワードが外部の人間にわかってしまう場合があります。 $CONF_FILE = "config.txt"; # ■ 選択できる表示件数 # 1回で表示できる件数を以下から選択できるようにします。 # 通常はこのままで良いでしょう。あまり大きい値を設定すると、サーバーに負荷がか # かり迷惑になりますので、気をつけてください。 @SELECT_LINES = (5, 10, 15, 20, 30, 40); # ■ ログファイルディレクトリ(最後に / は入れない) # ログファイルをプログラム本体と別のディレクトリに保存する場合、そのパスを設定 # してください。  ex) $LOG_DIR = 'bbs'; $LOG_DIR = '.'; # ■ ログファイル名 # ログファイルの名前を設定できます。 $LOG_FILE = 'utter.log'; # ■ ファイル・プログラム自体の文字コード # このプログラム、設定ファイルで利用している文字コードを指定することができます。 # 'jis', 'sjis', 'euc' を記述することができます。普通は、'sjis' でOKです。 # 文字コードに JISや EUCしか利用できないといった環境で動かす場合にここを変更しま # す。ここで設定を変えた場合、すべてのファイルをここで設定した文字コードに変換す # る必要があります。 # ブラウザで設定する文字コードは「表示する時の文字コード」ですので、混同されない # ようにしてください。 $FILE_JCODE = 'euc'; # ■ 投稿される記事に対して許可するタグ # 投稿される記事に対して許可するHTMLタグを設定できます。 # デフォルトを参考にして記述してみてください。 %UTTER_TAG = ( '
', '', #この行は削除しないでください '', '', '', '', ']*>', '', ']*>', '' ); # ■ カレントの記事を示すマーク # 記事詳細表示画面中のツリー表示で、現在開いている記事を示すマークを指定します。 $CURRENT_MARK = '<---'; # ============================================================================= # 発言ログ定義 $UTT_NO = 0; #記事番号 $UTT_NAME = 1; #投稿者名前 $UTT_MAIL = 2; #投稿者メールアドレス $UTT_URL = 3; #URL $UTT_TITLE = 4; #タイトル $UTT_UTTER = 5; #記事本体 $UTT_DATE = 6; #投稿時間 $UTT_HOST = 7; #リモートホスト $UTT_PSWD = 8; #編集用パスワード $UTT_PARENT = 9; #元になる記事(自分が親なら0) $UTT_FEED = 10; #フィードバックの有無 $UTT_FNO = 11; #フィードバック記事番号 # ============================================================================= # 設定ログ定義 $CONF_TITLE = 0; #BBSタイトル $CONF_HOME = 1; #ホームページ $CONF_PSWD = 2; #管理者パスワード $CONF_NEW = 3; #新規投稿フォームURL $CONF_JCODE = 4; #使用する日本語コード $CONF_TZONE = 5; #日本との時差 $CONF_NOTITLE = 6; #タイトル無しの場合のタイトル $CONF_LINES = 7; #デフォルトの表示行数 $CONF_NREP = 8; #最新の記事判定数 $CONF_MAX = 9; #スレッド最大保存数 $CONF_BGC = 10; #バックグラウンドカラー $CONF_TEXTC = 11; #テキストカラー $CONF_LINKC = 12; #リンクカラー $CONF_VLINKC = 13; #アクセス済みカラー $CONF_BARC = 14; #記事表示基本色 $CONF_NREPC = 15; #新規投稿基本色 $CONF_BGFILE = 16; #バックグラウンドURL $CONF_MESSAGE = 17; #メッセージ $CONF_TLINES = 18; #時間順記事表示のデフォルト $CONF_DETAILS = 19; #記事の中身まで表示するか? # ============================================================================= # 曜日定数定義 $WDAY = 6; $YEAR = 5; $MON = 4; $DAY = 3; $HOUR = 2; $MIN = 1; $SEC = 0; # ============================================================================= # 各種設定 &GetConfig(*conf); #BBS タイトル $MAIN_TITLE = $conf[$CONF_TITLE]; #貴様のホームページ $YOUR_URL = $conf[$CONF_HOME]; #貴様のパスワード $YOUR_PSWD = $conf[$CONF_PSWD]; #新規投稿URL $NEW_URL = $conf[$CONF_NEW]; #使用日本語コード $USE_JCODE = $conf[$CONF_JCODE]; #タイトルがない場合のタイトル $NO_TITLE = $conf[$CONF_NOTITLE]; #日本との時差 $T_ZONE = $conf[$CONF_TZONE]; #デフォルトの表示件数 $DEFAULT_LINES = $conf[$CONF_LINES]; #最新の記事判定数 $NEW_REPORT = $conf[$CONF_NREP]; #記事最大保存数 $REPORT_MAX = $conf[$CONF_MAX]; #バックグラウンド基本カラー $BG_COLOR = "#" . $conf[$CONF_BGC]; #テキスト基本カラー $TEXT_COLOR = "#" . $conf[$CONF_TEXTC]; #アンカー基本カラー $LINK_COLOR = "#" . $conf[$CONF_LINKC]; #アンカー(アクセス済み)基本カラー $VLINK_COLOR = "#" . $conf[$CONF_VLINKC]; #記事表示メインカラー $BAR_COLOR = "#" . $conf[$CONF_BARC]; #新規投稿色 $NREP_COLOR = "#" . $conf[$CONF_NREPC]; #バックグラウンド $BG_FILE = $conf[$CONF_BGFILE]; #ボードの説明文 $INFO_MESSAGE = $conf[$CONF_MESSAGE]; $INFO_MESSAGE =~ s/\t/\n/g; #記事表示の保存数 $DEFAULT_TLINES = $conf[$CONF_TLINES]; #記事の詳細表示 ($REPORT_DETAILS = $conf[$CONF_DETAILS]) || ($REPORT_DETAILS = 0); # ============================================================================= # メインルーチン &Initialize; if ($mode eq "") { &PrintMain; } elsif ($mode eq "nw") { &RegistUtter($fm_parent); &PrintThanx; } elsif ($mode eq "fd") { &PrintReport($fm_parent); } elsif ($mode eq "cfp") { &PrintConfigForm; } elsif ($mode eq "cfc") { &ChangeConfig; } elsif ($mode eq "nf") { &PrintNewReport; } elsif ($mode eq "del") { &PrintDelete; } elsif ($mode eq "sc") { &SearchData; } elsif ($mode eq "ps") { &PrintCheckPasswd; } else { &PrintMain; } exit(0); # ================================================================================== # 各種初期化 sub Initialize { local(@TagS, @TagE); #自分のスクリプト名 $script = &basic'GetFileName($0); #アクセス時間 @ac_time = &basic'GetNowTime($T_ZONE); #年号表示は下2桁 $ac_time[$YEAR] = $ac_time[$YEAR] % 100; #フォームの内容を取得 &basic'GetForm(*form); #動作モードを取得 ($mode = $ARGV[0]) || ($mode = $form{'md'}); #リモートホスト $ac_host = $ENV{'REMOTE_HOST'}; #名前 $fm_name = $form{'name'}; #電子メール $fm_mail = $form{'mail'}; #URL $fm_url = $form{'url'}; if($mode eq "nf" || $mode eq "fd") { &basic'GetCookies(*cookie); ($fm_name, $fm_mail, $fm_url) = split(/\t/, $cookie{'DATA'}); } # タイトル $fm_title = $form{'title'}; # 発言 $fm_utter = $form{'utter'}; # 親記事 $fm_parent = $form{'parent'}; # クッキー $fm_cookie = $form{'cookie'}; # 編集用パスワード ($fm_epswd = $form{'epswd'}) || ($fm_epswd = $YOUR_PSWD); # 設定変更用パスワード $fm_cpswd = $form{'cpswd'}; # 表示形式(0=ツリー 1=時間) ($fm_dtype = $form{'dtype'}) || ($fm_dtype = 0); # 表示件数 if($fm_dtype == 0) { ($fm_lines = $form{'lines'}) || ($fm_lines = $DEFAULT_LINES); } else { ($fm_lines = $form{'lines'}) || ($fm_lines = $DEFAULT_TLINES); } # メッセージの表示開始位置 ($fm_start = $form{'st'}) || ($fm_start = 0); # 日本語コードの変換 &jcode'convert(*fm_name, $FILE_JCODE); &jcode'convert(*fm_title, $FILE_JCODE); &jcode'convert(*fm_utter, $FILE_JCODE); #字数制限 $fm_name = substr($fm_name, 0, 40); $fm_mail = substr($fm_mail, 0, 40); #改行コード変換 / 制御記号抹殺 $fm_name =~ s/\015\012|\015|\012/
/g; $fm_name =~ tr/\x00-\x1f//d; $fm_utter =~ s/\015\012|\015|\012/
/g; $fm_utter =~ tr/\x00-\x1f//d; $fm_mail =~ s/\015\012|\015|\012/
/g; $fm_mail =~ tr/\x00-\x1f//d; $fm_url =~ s/\015\012|\015|\012/
/g; $fm_url =~ tr/\x00-\x1f//d; $fm_title =~ s/\015\012|\015|\012/
/g; $fm_title =~ tr/\x00-\x1f//d; #アンカータグ unless ($fm_utter =~ /]*TARGET[^<>]*>/i) { $fm_utter =~ s/(]*)>/$1 TARGET="_blank">/gi; } #タグを禁止 &HTML'AvoidTag(*fm_name); &HTML'AvoidTag(*fm_mail); &HTML'AvoidTag(*fm_url); &HTML'AvoidTag(*fm_title); #発言項目のタグの許可 &SetTag(*TagS, *TagE, *UTTER_TAG); &HTML'ValidateTag(*fm_utter, *TagS, *TagE); } # ============================================================================= # メイン画面の表示 sub PrintMain { local($message, $strtype, $line, $rcount, $dcount, $lastflag); #時間別だったら記事主体の表示 $fm_dtype ? ($strtype = '記事') : ($strtype = 'スレッド'); $lastflag = 0; $message .= <<"__HTML__"; Content-type: text/html $MAIN_TITLE

$INFO_MESSAGE


__HTML__ $message .= &PrintMenu; $message .= <<"__HTML__";
▼ 表\示できる$strtypeの数を変更できます。
表\示件数:
__HTML__ #
#

▼ キーワード検索ができます。
# #キーワード: # #

if($fm_dtype == 1) { open(LOG, "$LOG_DIR/$LOG_FILE"); eval 'flock(LOG, 2)'; if($REPORT_DETAILS == 0) { $message .= "記事を時間順に表\示\n"; $message .= "
\n"; } $message .= "
\n"; $rcount = 0; $dcount = 0; while() { @data = split(/\t/); &basic'DelCrFromList(*data); if($fm_start <= $rcount) { #時間の表示 ($dmon, $dday, $dhour, $dmin) = $data[$UTT_DATE] =~ /^..(..)(..)(..)(..)../; $date_str = sprintf("%02d/%02d %02d:%02d", $dmon, $dday, $dhour, $dmin); if($REPORT_DETAILS == 0) { $message .= <<"__HTML__";
No. $data[$UTT_NO] $data[$UTT_TITLE]- $data[$UTT_NAME] ($date_str)
__HTML__ } else { $message .= <<"__HTML__";
$data[$UTT_TITLE] __HTML__ if($data[$UTT_MAIL] eq "") { $message .= <<"__HTML__"; 投稿者: $data[$UTT_NAME] __HTML__ } else { $message .= <<"__HTML__"; 投稿者: $data[$UTT_NAME] __HTML__ } if($data[$UTT_URL] ne "") { $message .= <<"__HTML__";
$data[$UTT_URL] __HTML__ } $message .= <<"__HTML__";

$data[$UTT_UTTER]

コメントを書く

No. $data[$UTT_NO] $date_str
__HTML__ } $dcount++; } $rcount++; if($dcount >= $fm_lines) { $lastflag = 1; last; } } ($lastflag) || ($LastSignal = 1); $message .= "
\n"; eval 'flock(LOG, 8)'; close(LOG); } else { #スレッドの表示 $message .= "記事をツリー状に表\示\n"; $message .= "
\n"; $message .= &PrintThread($fm_lines, $fm_start); } (($before_start = $fm_start - $fm_lines) < 0) && ($before_start = 0); $next_start = $fm_start + $fm_lines; $message .= "\n"; if($fm_start > 0) { $message .= <<"__HTML__"; __HTML__ } if(!$LastSignal) { $message .= <<"__HTML__"; __HTML__ } $message .= "
\n"; #ライセンス表示 $message .= "


\n"; $message .= &PrintAuthor; $message .= <<"__HTML__"; __HTML__ &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # スレッドの表示 sub PrintThread { local($lines, $start) = @_; local($_, $i, $dcount, $lastflag, $rcount, $message); local(@data, @buf); $lastflag = 0; # 記事を表示した回数 $dcount = 0; # 読み込んだ記事の数 $rcount = 0; open(LOG, "$LOG_DIR/$LOG_FILE"); eval 'flock(LOG, 2)'; @buf = ; close(LOG); for($i = 0; $i < scalar(@buf); $i++) { @data = split(/\t/, $buf[$i]); if($data[$UTT_PARENT] == 0) { if($start <= $rcount) { &basic'DelCrFromList(*data); $message .= &MakeThread(*buf, $data[$UTT_NO]); $dcount++; } $rcount++; } if($dcount >= $lines){ $lastflag = 1; last; } } ($lastflag) || ($LastSignal = 1); $message; } # ============================================================================= # スレッド1個を作成 sub MakeThread { local(*buf, $no, $check_no) = @_; local($_, $i, $j, $count, $dmon, $dday, $dhour, $dmin, $newrep, $message, $checkmark); local(@data); $count = 0; ($check_no) || ($check_no = 0); $newrep = (split(/\t/, $buf[0]))[$UTT_NO]; for($i = 0; $i < scalar(@buf); $i++) { @data = split(/\t/, $buf[$i]); if($data[$UTT_NO] == $no){ &basic'DelCrFromList(*data); if($check_no == $no && $check_no) { $checkmark = " $CURRENT_MARK"; } else { $checkmark = ""; } #時間の表示 ($dmon, $dday, $dhour, $dmin) = $data[$UTT_DATE] =~ /^..(..)(..)(..)(..)../; $date_str = sprintf("%02d/%02d %02d:%02d", $dmon, $dday, $dhour, $dmin); #最新記事は番号の色を変更 if($newrep - $NEW_REPORT < $data[$UTT_NO]) { $newcol = $NREP_COLOR; } else { $newcol = $TEXT_COLOR; } $message .= "
\n"; $message .= <<"__HTML__";
No. $data[$UTT_NO] $data[$UTT_TITLE]- $data[$UTT_NAME] ($date_str)$checkmark
__HTML__ for($j = 0; $j < $data[$UTT_FEED]; $j++) { $message .= &MakeThread(*buf, $data[$UTT_FNO + $j], $check_no); } $message .= "
\n"; last; } $count++; } $message; } # ============================================================================= # 発言を表示 sub PrintReport { local($parent) = @_; local($message, $mostparent, $retitle); local(@data, @buf); &GetUtterData($parent, *data) || &Error'PrintMessage("

システムエラーです。管理者に報告して下さい。\n"); #時間の表示 $data[$UTT_DATE] =~ /^(..)(..)(..)(..)(..)(..)/; $date_str = "$1/$2/$3 $4:$5:$6"; #一番親の記事を探す $mostparent = &GetParentNo($data[$UTT_NO]); #記事引用 $quote = "No.$data[$UTT_NO]「$data[$UTT_TITLE]」で $data[$UTT_NAME] さんは書きました。\\r\\n"; $quote .= ">$data[$UTT_UTTER]"; #$quote =~ s/"/\\"/g; $quote =~ s/'/\\'/g; $quote =~ s/
/\\r\\n>/g; $quote = ">" . $quote . "\\r\\n\\r\\n"; #レスタイトル if ($data[$UTT_TITLE] =~ s/^Re://){ $retitle = "Re[2]:$data[$UTT_TITLE]"; } elsif ($data[$UTT_TITLE] =~ s/^Re\[(\d+)\]://){ $reno = $1 + 1; $retitle = "Re[$reno]:$data[$UTT_TITLE]"; } else { $retitle = "Re: $data[$UTT_TITLE]"; } #クリッカブルURL $data[$UTT_UTTER] =~ s/
(http:\/\/[a-zA-Z0-9_\-\.\/~]+)/
$1<\/A>/; $data[$UTT_UTTER] =~ s/
(ftp:\/\/[a-zA-Z0-9_\-\.\/~]+)/
$1<\/A>/; $message .= <<"__HTML__"; Content-type: text/html $data[$UTT_TITLE] [記事をツリー上に表\示] [記事を時間順に表\示] [コメントを投稿]


【記事番号:$data[$UTT_NO]】 $data[$UTT_TITLE] __HTML__ if($data[$UTT_MAIL] eq "") { $message .= <<"__HTML__";

投稿者: $data[$UTT_NAME] __HTML__ } else { $message .= <<"__HTML__";

投稿者: $data[$UTT_NAME] __HTML__ } if($data[$UTT_URL] ne "") { $message .= <<"__HTML__";
URL: $data[$UTT_URL] __HTML__ } $message .= <<"__HTML__";
投稿日時: $date_str

$data[$UTT_UTTER]

__HTML__ #関連記事を表示 if($data[$UTT_FEED] > 0 || $data[$UTT_PARENT] > 0) { $message .= <<"__HTML__";


関連記事
__HTML__ open(LOG, "$LOG_DIR/$LOG_FILE"); eval 'flock(LOG, 2)'; @buf = ; close(LOG); $message .= &MakeThread(*buf, $mostparent, $data[$UTT_NO]); } $message .= <<"__HTML__";
コメントを投稿
名前(必ず記入してください):

メールアドレス(省略可):

URL(省略可):

件名(必ず記入して下さい):

記事(必ず記入して下さい):
記事を引用する

名前・メール・URLを記憶する

__HTML__ $message .= &PrintAuthor; $message .= <<"__HTML__"; __HTML__ &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # 発言をログに登録 sub RegistUtter { local($parent) = @_; local($_, $errormsg, $h_no, $count, $lastp); local(@buf, @data); #未記入チェック ($fm_name eq "") && ($errormsg .= "

名前が未入力です。\n"); ($fm_utter eq "") && ($errormsg .= "

発言が未入力です。\n"); ($fm_parent eq "") && ($errormsg .= "

正規の登録方法をとって下さい。\n"); ($fm_title eq "") && ($fm_title .= "$NO_TITLE"); #未記入があればエラーを出して終了 ($errormsg ne "") && &Error'PrintMessage($errormsg); #ファイルオープン open(LOG, "+<$LOG_DIR/$LOG_FILE") || &Error'PrintMessage("

ファイルオープンエラーです。\n"); eval 'flock(LOG, 2)'; #データをバッファへ格納 @buf = ; #記事番号を作成 $h_no = (split(/\t/, $buf[0]))[0] + 1; #発言番号 $data[$UTT_NO] = $h_no; #投稿者名前 $data[$UTT_NAME] = $fm_name; #投稿者メールアドレス $data[$UTT_MAIL] = $fm_mail; #URL $data[$UTT_URL] = $fm_url; #記事タイトル $data[$UTT_TITLE] = $fm_title; #記事本体 $data[$UTT_UTTER] = $fm_utter; #投稿時間 $data[$UTT_DATE] = sprintf("%02d%02d%02d%02d%02d%02d", $ac_time[$YEAR], $ac_time[$MON], $ac_time[$DAY], $ac_time[$HOUR], $ac_time[$MIN], $ac_time[$SEC]); #リモートホスト $data[$UTT_HOST] = $ac_host; #暗号化編集用パスワード $data[$UTT_PSWD] = &basic'MakePasswd($fm_epswd); #親記事 $data[$UTT_PARENT] = $parent; #フィードバックの有無 $data[$UTT_FEED] = 0; #フィードバック記事番号 $data[$UTT_FNO] = ""; #新規記事を挿入 unshift(@buf, join("\t", @data)."\n"); #フィードバックがある場合・・・ if($parent != 0) { $count = 0; foreach(@buf) { undef @data; @data = split(/\t/); if($data[$UTT_NO] == $parent) { &basic'DelCrFromList(*data); $data[$UTT_FEED]++; $data[$UTT_FNO + $data[$UTT_FEED] - 1] = $h_no; $buf[$count] = join("\t", @data) . "\n"; last; } $count++; } } #ログに書き出し seek(LOG, 0, 0); print LOG @buf; #ごみの御掃除 eval 'truncate(LOG, tell(LOG));'; #ファイルをアンロックしてクローズ close(LOG); # 記事を永久保存しない場合 if ($REPORT_MAX != 99999) { $count = 0; foreach(@buf){ if ((split(/\t/))[$UTT_PARENT] == 0){ $count++; if($count > $REPORT_MAX) { &DeleteThread((split(/\t/))[$UTT_NO]); } } } } } # ============================================================================= # 記事の検索 sub SearchData { local($errormsg, $message, $find, $this_key, $this_obj, $count, $hitmsg, $i, $j); local(@data); #検索文字列 @fm_key = split(/\s/, $form{'key'}); $count = 0; if(scalar(@fm_key) == 0) { $errormsg .= "

キーワードを入力してください。\n"; } #未記入があればエラーを出して終了 ($errormsg ne "") && &Error'PrintMessage($errormsg); $message .= <<"__HTML__"; Content-type: text/html $MAIN_TITLE

$INFO_MESSAGE


__HTML__ $message .= &PrintMenu; $message .= <<"__HTML__";
▼ 再検索することができます。
キーワード:

XxXxXxXxX
__HTML__ open(LOG, "$LOG_DIR/$LOG_FILE"); eval 'flock(LOG, 2)'; while() { undef @data; chop; @data = split(/\t/); $result = 1; for ($i = 0; $i < scalar(@fm_key); $i++) { $this_key = $fm_key[$i]; $find = 0; $this_key =~ s/(\W)/\\$1/; &jcode'convert(*this_key, 'euc'); for ($j = $UTT_NO; $j <= $UTT_UTTER; $j++) { $this_obj = $data[$j]; &jcode'convert(*this_obj, 'euc'); if($this_obj =~ /^([\x00-\x7F]|[\x8E\xA1-\xFE][\xA1-\xFE]|\x8F[\xA1-\xFE]{2})*$this_key/i) { $find = 1; last; } } $result = $result & $find; } if($result == 1) { #時間の表示 $data[$UTT_DATE] =~ /^..(..)(..)(..)(..)../; $date_str = sprintf("%02d/%02d %02d:%02d", $1, $2, $3, $4); $message .= <<"__HTML__";
No. $data[$UTT_NO] $data[$UTT_TITLE]- $data[$UTT_NAME] ($date_str)
__HTML__ $count++; } } close(LOG); #ライセンス表示 $message .= "


\n"; $message .= &PrintAuthor; $message .= <<"__HTML__"; __HTML__ if($count > 0) { $hitmsg = "$count 件の記事が見つかりました。\n"; } else { $hitmsg = "該当する記事は見つかりませんでした。\n"; } $message =~ s/XxXxXxXxX/$hitmsg/; &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # 設定フォームの表示 sub PrintConfigForm { local($message, $errmsg); $errmsg .= <<"__ERR__"; 認証に失敗しました。
パスワード入力画面はこちらです。 __ERR__ # パスワード認証 if ($USE_CRYPT == 1) { &basic'CheckPasswd($fm_cpswd, $conf[$CONF_PSWD]) || &Error'PrintMessage($errmsg); } else { ($fm_cpswd eq $conf[$CONF_PSWD]) || &Error'PrintMessage($errmsg); } $message .= <<"__HTML__"; Content-type: text/html $MAIN_TITLE [基本設定] __HTML__ $message .= &PrintMenu; $message .= <<"__HTML__";
プログラムの基本設定を変更できます。

会議室のタイトル:

ホームページ:

新規投稿フォームURL:

記事にタイトルがない場合のタイトル

使用する日本語コード:

日本との時差: 時間

デフォルトの表\示件数:

デフォルトの表\示件数(時間順):

記事最大保存数 (99999-永久保存)

最新の記事判定数:

時間順表\示の際の記事本体表\示:
__HTML__ if($REPORT_DETAILS == 0) { $message .= <<"__HTML__"; OFF ON __HTML__ } else { $message .= <<"__HTML__"; OFF ON __HTML__ } $message .= <<"__HTML__";

バックグラウンドカラー:(000000〜FFFFFF)

テキストカラー:(000000〜FFFFFF)

リンクカラー:(000000〜FFFFFF)

リンクカラー(アクセス済み):(000000〜FFFFFF)

最新記事の色:(000000〜FFFFFF):

壁紙URL(無い場合は未記入):

メイン画面の説明等(HTMLで記入すること):

パスワード(変更したい場合のみ入力)

パスワード(変更したい場合のみ上と同じデータを入力)

パスワードを入力して設定変更ボタンを押して下さい。


記事の削除

削除したい記事番号を入力して、削除ボタンを押すと、即削除されます。 ただし、削除したい記事にフォロー記事がある場合、フォロー記事も削除されてしまいますので、 ご注意ください。

記事番号:

パスワード:

__HTML__ &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # 新規記事投稿フォーム表示 sub PrintNewReport { $message .= <<"__HTML__"; Content-type: text/html 新規投稿フォーム 新規記事投稿
名前:

メールアドレス:

URL:

件名:

記事:

名前・メール・URLを記憶する

__HTML__ &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # Thanx Message sub PrintThanx { local($message, $exp, $path, $domain); #クッキーをセット if($fm_cookie eq "on"){ $exp = &basic'GetGMT(time + 24 * 5 * 60 * 60); ($path = $ENV{'SCRIPT_NAME'}) =~ s/(.*)\/.*$/$1/; $domain = $ENV{'SERVER_NAME'}; $message .= <<"__COOKIE__"; Set-Cookie: DATA=$fm_name\t$fm_mail\t$fm_url; expires=$exp __COOKIE__ } $message.= <<"__HTML__"; Content-type: text/html ありがとうございました
ありがとうございました

あなたの投稿を受け付けました。下のメニューからお戻りください。 この画面でリロードしないでください。


__HTML__ $message .= &PrintMenu($message); $message .= "
\n"; &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # パスワード要求 sub PrintCheckPasswd { local($message); $message .= <<"__HTML__"; Content-type: text/html 管理者用ページ
パスワードを入力してください


__HTML__ $message .= &PrintMenu($message); $message .= "
\n"; &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # 設定を変更 sub ChangeConfig { local($message, $errmsg); # 認証 if ($USE_CRYPT == 1) { &basic'CheckPasswd($fm_cpswd, $conf[$CONF_PSWD]) || &Error'PrintMessage("

認証に失敗しました。\n"); } else { ($fm_cpswd eq $conf[$CONF_PSWD]) || &Error'PrintMessage("

認証に失敗しました。\n"); } #タイトル $MAIN_TITLE = $form{'conf_title'}; #貴様のホームページ $YOUR_URL = $form{'conf_home'}; #新しいパスワード $NEW_PSWD = $form{'conf_pswd'}; ($NEW_PSWD, $check) = split(/\0/, $NEW_PSWD); ($NEW_PSWD ne $check) && &Error'PrintMessage("

新しいパスワードが正しく入力されていません。\n"); if($NEW_PSWD eq "") { $NEW_PSWD = $YOUR_PSWD; } else { if($USE_CRYPT == 1){ $NEW_PSWD = &basic'MakePasswd($NEW_PSWD); } } #新規投稿URL $NEW_URL = $form{'conf_new'}; #使用日本語コード $USE_JCODE = $form{'conf_jcode'}; #タイトルがない場合のタイトル $NO_TITLE = $form{'conf_notitle'}; #日本との時差 $T_ZONE = $form{'conf_tzone'}; #デフォルトの表示件数 $DEFAULT_LINES = $form{'conf_lines'}; #デフォルトの表示件数(記事順表示の場合) $DEFAULT_TLINES = $form{'conf_tlines'}; #最新の記事判定数 $NEW_REPORT = $form{'conf_nrep'}; #記事の保存数 $REPORT_MAX = $form{'conf_max'}; #バックグラウンド基本カラー $BG_COLOR = $form{'conf_bgc'}; #テキスト基本カラー $TEXT_COLOR = $form{'conf_textc'}; #アンカー基本カラー $LINK_COLOR = $form{'conf_linkc'}; #アンカー(アクセス済み)基本カラー $VLINK_COLOR = $form{'conf_vlinkc'}; #記事表示メインカラー(廃止) $BAR_COLOR = ""; #新規投稿色 $NREP_COLOR = $form{'conf_nrepc'};; #バックグラウンド $BG_FILE = $form{'conf_bgfile'}; #ボードの説明文 $INFO_MESSAGE = $form{'conf_message'}; # 記事の詳細表示 $REPORT_DETAILS = $form{'conf_details'}; $INFO_MESSAGE =~ s/\015\012|\015|\012/\t/g; $INFO_MESSAGE =~ tr/\x00-\x1f//d; ##########チェック機能を徐々に追加############# ($NO_TITLE eq "") && ($errmsg .= "

記事タイトルがない場合のタイトルが未入力です。\n"); ($errmsg ne "") && &Error'PrintMessage($errmsg); ############################################### $config .= <<"__CONF__"; $MAIN_TITLE $YOUR_URL $NEW_PSWD $NEW_URL $USE_JCODE $T_ZONE $NO_TITLE $DEFAULT_LINES $NEW_REPORT $REPORT_MAX $BG_COLOR $TEXT_COLOR $LINK_COLOR $VLINK_COLOR $BAR_COLOR $NREP_COLOR $BG_FILE $INFO_MESSAGE $DEFAULT_TLINES $REPORT_DETAILS __CONF__ &jcode'convert(*config, $FILE_JCODE); open(LOG, ">$LOG_DIR/$CONF_FILE"); eval 'flock(LOG, 2)'; print LOG $config; close(LOG); $message .= <<"__HTML__"; Content-type: text/html $MAIN_TITLE 設定を変更しました!


__HTML__ $message .= &PrintMenu; $message .= <<"__HTML__";
__HTML__ &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # スレッドを削除してメッセージを表示 sub PrintDelete { local($message, $fno); if($USE_CRYPT == 1) { &basic'CheckPasswd($fm_cpswd, $conf[$CONF_PSWD]) || &Error'PrintMessage("

認証に失敗しました。\n"); } else { ($fm_cpswd eq $conf[$CONF_PSWD]) || &Error'PrintMessage("

認証に失敗しました。\n"); } $fno = $form{'fno'}; ($fno =~ /\D/) && &Error'PrintMessage("

削除する記事番号は数字で指定して下さい!\n"); &DeleteThread($fno) || &Error'PrintMessage("

削除する記事が見つかりませんでした。\n"); $message .= <<"__HTML__"; Content-type: text/html $MAIN_TITLE [記事削除] 記事番号 $fno を削除しました!


__HTML__ $message .= &PrintMenu; $message .= <<"__HTML__";
__HTML__ &jcode'convert(*message, $USE_JCODE); print $message; } # ============================================================================= # 指定されたスレッドを削除 sub DeleteThread { local($fno) = @_; local($count, $i, $j, $flg); local(@data, @buf); open(LOG, "+<$LOG_DIR/$LOG_FILE"); eval 'flock(LOG, 2)'; @buf = ; $flg = 0; for($i = 0; $i < scalar(@buf); $i++) { @data = split(/\t/, $buf[$i]); if($data[$UTT_NO] == $fno) { &basic'DelCrFromList(*data); $buf[$i] = ""; #親記事から自分を削除 if ($data[$UTT_PARENT] != 0) { &delete_child(*buf, $data[$UTT_PARENT], $data[$UTT_NO]); } for($j = 0; $j < $data[$UTT_FEED]; $j++) { &delete_data(*buf, $data[$UTT_FNO + $j]); } $flg = 1; last; } } seek(LOG, 0, 0); print LOG @buf; eval 'truncate(LOG, tell(LOG));'; close(LOG); $flg; } sub delete_data { local(*buf, $fno) = @_; local(@data); local($count, $i, $j); for($i = 0; $i < scalar(@buf); $i++){ @data = split(/\t/, $buf[$i]); if($data[$UTT_NO] == $fno) { $buf[$i] = ""; #親記事から自分を削除 if ($data[$UTT_PARENT] != 0) { &delete_child(*buf, $data[$UTT_PARENT], $data[$UTT_NO]); } for($j = 0; $j < $data[$UTT_FEED]; $j++) { &delete_data(*buf, $data[$UTT_FNO + $j]); } last; } } } # ============================================================================= # 親記事から子記事削除 sub delete_child { local(*buf, $parent, $child) = @_; local(@data); local($i, $count) = 0; $debug = 2; foreach(@buf) { @data = split(/\t/); if($data[$UTT_NO] == $parent) { &basic'DelCrFromList(*data); #フィードの数だけ記事検索 for($i = 0; $i < $data[$UTT_FEED]; $i++) { if($data[$UTT_FNO + $i] == $child){ splice(@data, $UTT_FNO + $i, 1); last; } } #フィード数を減らす $data[$UTT_FEED] --; $buf[$count] = join("\t", @data)."\n"; last; } $count++; } } # ============================================================================= # 指定ファイルの漢字コード変換 sub ConvertFileEncode { local($fname, $encoding) = @_; local($_, *LOG, $line, $count); open(LOG, "+<$LOG_DIR/$LOG_FILE"); eval 'flock(LOG, 2)'; @buf = ; $count = 0; for ($count = 0; $count < scalar(@buf); $count++) { $buf[$count] = &basic'ConvertEncode($buf[$count], $encoding); } seek(LOG, 0, 0); print LOG @buf; eval 'truncate(LOG, tell(LOG))'; close(LOG); } # ============================================================================= # 一番親記事を表示 sub GetParentNo { local($fno) = @_; local($_, $flg, @buf, @data); $flg = 0; &GetUtterData($fno, *data); if ($data[$UTT_PARENT] == 0){ return $fno; } else { return &GetParentNo($data[$UTT_PARENT]); } } # ============================================================================= # 指定されたデータを取り出す sub GetUtterData { local($fno, *temp) = @_; local($flg); open(LOG, "$LOG_DIR/$LOG_FILE"); eval 'flock(LOG, 2)'; $flg = 0; while() { chop; @temp = split(/\t/); if($temp[$UTT_NO] == $fno) { $flg = 1; last; } } close(LOG); $flg; } # ============================================================================= # 設定ファイルを取り出す sub GetConfig { local(*data) = @_; open(LOG, "$LOG_DIR/$CONF_FILE"); eval 'flock(LOG, 2)'; @data = ; close(LOG); &basic'DelCrFromList(*data); } # ============================================================================= # ライセンス表示 sub PrintAuthor { local($message); $message .= <<"__HTML__";
$PROG_NAME $PROG_VERSION __HTML__ $message; } # ============================================================================= # メニュー表示 sub PrintMenu { local($message); $message .= <<"__HTML__"; [記事をツリー表\示] [記事を時間順に表\示] [新しく記事を投稿] [管理ページ] [ホームページへ] __HTML__ $message; } # ============================================================================= # タグ許可と閉じ忘れ防止用の配列を用意(ログ) sub SetTag { local(*TagS, *TagE, *taglist) = @_; local($_); foreach(keys(%taglist)) { push(@TagS, $_); push(@TagE, $taglist{$_}); } } package Error; # ============================================================================= # エラーメッセージを出して終了 sub PrintMessage { local ($errormsg) = @_; local($_, $message); $message .= <<"__HTML__"; Content-type: text/html $main'MAIN_TITLE エラーが発生しました

エラーが発生しました。内容は以下の通りです。


$errormsg


$main'MAIN_TITLE __HTML__ &jcode'convert(*message, $main'USE_JCODE); print $message; exit(0); } package HTML; # ============================================================================= # タグの禁止 sub AvoidTag { local(*temp) = @_; local($_, $i); for($i = 0; $i < scalar(@temp); $i++) { $temp[$i] =~ s/&/&/g; $temp[$i] =~ s/"/"/g; $temp[$i] =~ s//>/g; } } # ============================================================================= # タグの許可 sub ValidateTag { local(*alias,*tagAs,*tagBs) = @_; local($tagA,$tagB,$match,$b,$f,$_); $alias =~ tr/<>/\x1e\x1f/; foreach (0 .. scalar(@tagAs) - 1) { ($tagA = $tagAs[$_]) =~ tr/<>/\x1e\x1f/; ($tagB = $tagBs[$_]) =~ tr/<>/\x1e\x1f/; while($alias =~ /$tagA/i) { $b = $`; $f = $'; ($match = $&) =~ tr/\x1e\x1f/<>/; (($match =~ s/"/"/g) % 2) && ($match =~ s/>/">/); if (($tagB) && ($f =~ s/$tagB/$tagBs[$_]/i)) { $alias = join("",$b,$match,$f); } else { $alias = join("",$b,$match,$f,$tagBs[$_]); } } } $alias =~ s/\x1e/</g; $alias =~ s/\x1f/>/g; 1; } # ============================================================================= # 文字列をURL形式に変換("*.@-"も変換) sub UrlEncode { local(*alias) = @_; local($_); $alias =~ s/([^0-9A-Za-z_])/"%".unpack("H2",$1)/ge; $alias =~ tr/ /+/; } # ============================================================================= # URL形式を文字列に変換 sub UrlDecode { local(*alias) = @_; local($_); $alias =~ s/%([\dA-F]{2})/pack("c",hex($1))/ge; } package basic; @wday = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); @jwday = ('日', '月', '火', '水', '木', '金', '土'); @weekday = ( 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); @mon = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); @month = ( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'); @holiday = ( '0101', '0115', '0211', '0321', '0429', '0503', '0504', '0505', '0720', '0915', '0923', '1010', '1103', '1123', '1223'); # ============================================================================= # 漢字コード変換 sub ConvertEncode { local($str, $encoding) = @_; local($_, *LOG); &jcode'convert(*str, $encoding); $str; } # ============================================================================= # 空のファイルを作る sub MakeNewFile { local($fname) = @_; open(NEW, ">$fname") || return(0); close(NEW); return(1); } # ============================================================================= # パス名からファイル名をとりだす sub GetFileName { local($fname) = @_; if ($fname =~ /\\|\//) { $fname =~ /[^\\\/]*$/; $fname = $&; } $fname; } # ============================================================================= # 配列から改行を除く sub DelCrFromList { local(*list) = @_; local($_); foreach(@list) { $_ =~ s/\n//g; } } # ============================================================================= # フォームのデコード sub GetForm { local(*temp) = @_; local($key,$value); ($ENV{'REQUEST_METHOD'} eq 'GET') && ($_ = $ENV{'QUERY_STRING'}); ($ENV{'REQUEST_METHOD'} eq 'POST') && read(STDIN,$_,$ENV{'CONTENT_LENGTH'}); tr/+/ /; foreach (split(/&/)) { ($key,$value) = split(/=/); $key =~ s/%(..)/pack("c",hex($1))/ge; $value =~ s/%(..)/pack("c",hex($1))/ge; if (defined($temp{$key})) { $temp{$key} = join("\0", $temp{$key}, $value); } else { $temp{$key} = $value; } } } # ============================================================================= # パスワードを暗号化 sub MakePasswd { local($plain) = @_; local($salt, $passwd); srand($$ | time); $salt = pack("c*", int(rand(26))) + 0x41 + 0x20 * int(rand(2)); $salt .= pack("c*", int(rand(26))) + 0x41 + 0x20 * int(rand(2)); $salt .= int(rand(10000)); $passwd = crypt($plain, $salt); #暗号化されたパスワードを返す $passwd; } # ============================================================================= # パスワードチェック # # 引数 = チェックしたいパスワード、暗号化されたパスワード # 返値 = 合格=1 不合格=0 sub CheckPasswd { local($guess, $pass) = @_; if(crypt($guess, $pass) eq $pass){ return(1); } else { return(0); } } # ============================================================================= # 曜日->RGBカラー # # 引数 = 日曜-0 〜 土曜-6 # 返値 = #rrggbb sub WdayToRGB { local($wday, $col) = @_; if($wday == 0) { $col = "#FF0000"; } elsif ($wday == 6) { $col = "#0077FF"; } else { $col = "#000000"; } $col; } # ============================================================================= # 曜日の算出 # # 引数=年(4ケタ)、月、日の順番で渡す # 返値=曜日(0-sun,6-sat) sub DayOfWeek { local($year, $month, $day) = @_; if($month == 1 || $month == 2) { $year--; $month += 12; } return(($year + int($year / 4) - int($year / 100) + int($year / 400) + int((13 * $month + 8) / 5) + $day) % 7); } # ============================================================================= # 分->hh:mmの算出 # # 引数=0:00からの経過分 # 返値=hh:mm (hh=00-24) sub MinToStr24 { local($minutes) = @_; local($hour, $min); $hour = int($minutes / 60) % 24; $min = $minutes % 60; sprintf("%d:%02d", $hour, $min); } # ============================================================================= # 分->hh:mmの算出(経過時間) # # 引数=0:00からの経過分 # 返値=hh:mm sub MinToStr { local($minutes) = @_; local($hour, $min); $hour = int($minutes / 60); $min = $minutes % 60; sprintf("%d:%02d", $hour, $min); } #============================================================== # hh:mm->0:00からの経過分数の算出(経過時間) # # 引数=(hh, mm) # 返値=経過分数 sub StrToMin { local($hour, $min) = @_; $hour * 60 + $min; } # ============================================================================= # 現在の時間を取得 # # 引数=日本との時差 # 返値=(秒、分、時、日、月、年、曜日(0-sun,6-sat) sub GetNowTime { local($t_zone) = @_; local(@ret_day); #現在時刻を取得 @ret_day = (localtime(time+60*60*$t_zone))[0..6]; $ret_day[4]++; @ret_day; } # ============================================================================= # クッキーをもらう sub GetCookies { local(*cookies) = @_; local($_, $key, $value); foreach (split(/; /,$ENV{'HTTP_COOKIE'})) { ($key,$value) = split(/=/,$_); $cookies{$key} = $value; } } # ============================================================================= # グリニッジ標準時刻(引数 = time , 返り値 = 文字列) sub GetGMT { local($sec,$min,$hour,$mday,$mon,$year,$wday,$_); ($sec,$min,$hour,$mday,$mon,$year,$wday) = gmtime($_[0]); $wday = ("Sun","Mon","Tue","Wed","Thu","Fri","Sat")[$wday]; $mon = ("Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec")[$mon]; if($year < 70) { $year += 2000; } else { $year += 1900; } sprintf("$wday, %02d-$mon-$year %02d:%02d:%02d GMT", $mday,$hour,$min,$sec); } 1;