#!/usr/bin/perl

#┌─────────────────────────────────
#│ COM BOARD v5.1 (2004/02/06)
#│ Copyright (c) KentWeb
#│ webmaster@kent-web.com
#│ http://www.kent-web.com/
#└─────────────────────────────────
$ver = 'COM-BBS v5.1';
#┌─────────────────────────────────
#│[ 注意事項 ]
#│ 1. このスクリプトはフリーソフトです。このスクリプトを使用した
#│    いかなる損害に対して作者は一切の責任を負いません。
#│ 2. 設置に関する質問はサポート掲示板にお願いいたします。
#│    直接メールによる質問は一切お受けいたしておりません。
#└─────────────────────────────────

#-------------------------------------------------
#  設定項目
#-------------------------------------------------

# ライブラリ取込
require './jcode.pl';

# タイトル
$title = "KARIYADO Elementary School";

# タイトルの色
$t_col = "#555555";

# タイトル文字サイズ
$t_size  = '24px';

# 本文文字サイズ
$b_size = '13px';

# 文字のフォントタイプ
$b_face = '"MS UI Gothic", "MS Pゴシック", Osaka';

# 背景色、文字色など
$bg = "http://www.kariyado-e.ed.jp/cbs/enbo.jpg";		# 壁紙 (http://から記述)
$bc = "#F0F0F0";	# 背景色
$te = "#000000";	# 文字色を指定
$li = "#0000FF";	# リンク色を指定(未訪問)
$vl = "#800080";	# リンク色を指定(既訪問)

# 戻り先のURL (index.htmlなど)
$homepage = '../index.html';

# 最大記事数
$max = 300;

# パスワード(英数字で指定)
$pass = 'yadokari';

# 横割フレーム (0=no 1=yes)
$yoko_frame = 0;

# 投稿項目に「題名」を使う (0=no 1=yes)
$subject = 1;

# 投稿項目に「URL」を使用 (0=no 1=yes)
$urlkey = 0;

# スクリプトファイル名
$script  = './cbs.cgi';

# ログファイル
$logfile = './cbslog.cgi';

# 記事タイトルの色
$subcol = "#dd0000";

# 1ページ当たりの記事表示数
$p_log = 10;

# ロックファイル機構
#  → 0=no 1=symlink関数 2=mkdir関数
$lockkey = 0;

# ロックファイル名
$lockfile = './lock/combbs.lock';

# URL自動リンク機能 (0=no 1=yes)
$autolink = 1;

# メール通知機能
#  0 : 通知しない
#  1 : 通知する → 自分の投稿記事も通知する
#  2 : 通知する → 自分の投稿記事は通知しない
$mailing = 0;

# メール通知先 (メール通知する時)
$mailto = 'tamba@kamezaki-e.ed.jp';

# sendmailパス(メール通知する時)
$sendmail = '/usr/lib/sendmail';

# タイトルに画像を使用する場合(画像ファイルをhttp://から記述)
$t_img = "";
$t_w = 150;	# 横幅
$t_h = 80;	# 縦幅

# タグ広告挿入オプション
#  → <!-- 上部 --> <!-- 下部 --> の代わりに「広告タグ」を挿入する。
#  → 広告タグ以外に、MIDIタグ や LimeCounter等のタグにも使用可能です。
$banner1 = '<!-- 上部 -->';	# 表示部上部に挿入
$banner2 = '<!-- 下部 -->';	# 表示部下部に挿入

# 記事の更新は method=POST 限定する場合(セキュリティ対策)
#  → 0=no 1=yes
$postonly = 1;

# 他サイトから投稿排除時に指定する場合(セキュリティ対策)
#  → 掲示板のURLをhttp://から書く
$baseUrl = '';

# 投稿制限(セキュリティ対策)
#  0 : しない
#  1 : 同一IPアドレスからの投稿間隔を制限する
#  2 : 全ての投稿間隔を制限する
$regCtl = 1;

# 制限投稿間隔(秒数)
#  → $regCtl での投稿間隔
$wait = 60;

# ホスト取得方法
# 0 : gethostbyaddr関数を使わない
# 1 : gethostbyaddr関数を使う
$gethostbyaddr = 0;

# アクセス制限(半角スペースで区切る)
#  → 拒否するホスト名又はIPアドレスを記述(アスタリスク可)
#  → 記述例 $deny = '*.anonymizer.com 211.154.120.*';
$deny = '60.6.60.*'; '61.199.77.*'; '60.40.51.*'; 

#-------------------------------------------------
#  設定完了
#-------------------------------------------------

# COM BOARDのメイン処理
$ret = &decode;
&axsCheck;
if (!$ret) {
	if ($yoko_frame) { &y_frame; }
	else { &t_frame; }
}
if ($mode eq "admin") { &admin; }
elsif ($mode eq "form") { &form; }
elsif ($mode eq "regist") { &regist; }
elsif ($mode eq "howto") { &howto; }
elsif ($mode eq "find") { &find; }
elsif ($mode eq "msg_del") { &msg_del; }
&html_log;

#-------------------------------------------------
#  アクセス制限
#-------------------------------------------------
sub axsCheck {
	# IP&ホスト取得
	$host = $ENV{'REMOTE_HOST'};
	$addr = $ENV{'REMOTE_ADDR'};
	if ($gethostbyaddr && ($host eq "" || $host eq $addr)) {
		$host = gethostbyaddr(pack("C4", split(/\./, $addr)), 2);
	}
	if ($host eq "") { $host = $addr; }

	local($flag)=0;
	foreach ( split(/\s+/, $deny) ) {
		s/\./\\\./g;
		s/\*/\.\*/g;
		s/\?/\.\?/g;
		if ($host =~ /$_/i || $addr =~ /$_/i) { $flag=1; last; }
	}
	if ($flag) { &error("アクセスを許可されていません"); }
}

#-------------------------------------------------
#  HTMLのヘッダー
#-------------------------------------------------
sub header {
	if ($headflag) { return; }

	print "Content-type: text/html\n\n";
	print <<EOM;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">
<head>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
<META HTTP-EQUIV="Content-Style-Type" content="text/css">
<STYLE TYPE="text/css">
<!--
body,tr,td,th { font-size: $b_size; font-family: $b_face }
-->
</STYLE>
<title>$title</title></head>
EOM
	$headflag=1;
}

#-------------------------------------------------
#  縦割フレーム出力
#-------------------------------------------------
sub t_frame {
	&header;
	print <<EOM;
<frameset cols="*,283">
<frame name="log" src="$script?mode=log">
<frame name="form" src="$script?mode=form">
<noframes>
<body>フレーム非対応のブラウザの方はご利用できません
</body></noframes></frameset>
</html>
EOM
	exit;
}

#-------------------------------------------------
#  横割フレーム出力
#-------------------------------------------------
sub y_frame {
	&header;
	print <<EOM;
<frameset rows="*,200">
<frame name="log" src="$script?mode=log">
<frame name="form" src="$script?mode=form">
<noframes>
<body>フレーム非対応のブラウザの方はご利用できません
</body></noframes></frameset>
</html>
EOM
	exit;
}

#-------------------------------------------------
#  投稿フォーム
#-------------------------------------------------
sub form {
	# クッキー取得
	local($cnam,$ceml,$curl,$cpwd) = &get_cookie;
	if (!$curl) { $curl = 'http://'; }

	# HTML出力
	print "Content-type: text/html\n\n";
	print <<EOM;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">
<head>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
<STYLE TYPE="text/css">
<!--
body,tr,td,th { font-size:$b_size; font-family:"$b_face" }
-->
</STYLE>
<title>$title</title>
<SCRIPT LANGUAGE="JavaScript">
<!--
function autoclear() {
  if (self.document.send) {
   if (self.document.cmode && self.document.cmode.autoclear) {
    if (self.document.cmode.autoclear.checked) {
     if (self.document.send.sub) {
      self.document.send.sub.value = "";
      self.document.send.sub.focus();
     }
    if (self.document.send.comment) {
      self.document.send.comment.value = "";
      self.document.send.comment.focus();
    }
    if (self.document.send.url) {
      self.document.send.url.value = "http://$ck{'url'}";
      self.document.send.url.focus();
    }
   }
  }
 }
}
// -->
</SCRIPT>
</head>
$body
<form name="send" method="POST" action="$script" target="log" ONSUBMIT="setTimeout(&quot;autoclear()&quot;,10)">
<input type=hidden name=mode value="regist">
EOM

	# フレーム
	if ($yoko_frame) { &yokoForm; }
	else { &tateForm; }

	print "</body></html>\n";
	exit;
}

#-------------------------------------------------
#  縦フォーム
#-------------------------------------------------
sub tateForm {
	print <<EOM;
Name<br><input type=text name=name size=25 value="$cnam"><br>
E-mail<br><input type=text name=email size=25 value="$ceml"><br>
EOM

	# 題名を使用する場合
	if ($subject) {
		print "Title<br><input type=text name=sub size=25><br>\n";
	}

	print <<EOM;
<br>Comment</font><br>
<textarea cols=33 rows=7 name=comment wrap=soft></textarea><br>
<input type=submit value="It contributes"><input type=reset value="Clear">
Delete key<input type=password name=pwd size=6 value="$cpwd"><br>
EOM

	if ($urlkey) {
		print "<p>参照先<br>";
		print "<input type=text name=url size=30 value=\"$curl\">\n";
	}

	print <<EOM;
</form><form name=cmode>
<input type=checkbox name=autoclear checked>
Automatic utterance elimination </form>
EOM
}

#-------------------------------------------------
#  横フォーム
#-------------------------------------------------
sub yokoForm {
	print <<EOM;
<div align="center">
<table>
<tr>
  <td><b>お名前</b></td>
  <td><input type=text name=name size=25 value="$cnam"></td>
</tr>
<tr>
  <td><b>E-mail</b></td>
  <td><input type=text name=email size=25 value="$ceml"></td>
</tr>
EOM

	if ($subject) {
		print "<tr><td><b>タイトル</b></td>";
		print "<td><input type=text name=sub size=33>\n";
	}

	print <<EOM;
<input type=submit value="投稿する">
<input type=reset value="リセット">
<tr><td colspan=2><b>コメント</b><br>
<textarea cols=54 rows=6 name=comment wrap=soft></textarea></td></tr>
EOM

	if ($urlkey) { 
		print "<tr><td><B>参照先</B></td>";
		print "<td><input type=text name=url size=53 value=\"$curl\"></td></tr>\n";
	}

	print <<EOM;
<tr>
  <td><b>削除キー</b></td>
  <td><input type=password name=pwd size=8 value="$ck{'pwd'}">
	(英数字で8文字以内)</td></form>
</tr>
<tr>
  <td></td>
  <td><form name=cmode>
	<input type=checkbox name=autoclear checked>
	発言自動消去</form></td>
</tr>
</table>
</div>
EOM
}

#-------------------------------------------------
#  記事表示部
#-------------------------------------------------
sub html_log {
	local($i,$next,$back,$no,$date,$name,$eml,$sub,$com,$url);

	&header;
	print <<EOM;
$body
| <a href="$homepage" target="_top">top</a>
| <a href="$script?mode=howto"></a>
| <a href="$script?mode=find">Retrieval</a>
| <a href="$script?mode=admin">Managemen</a>
|
EOM

	print "<div align=\"center\">\n";
	print "$banner1<p>\n" if ($banner1 ne "<!-- 上部 -->");

	# タイトル部
	if ($t_img) {
		print "<img src=\"$t_img\" width=\"$t_w\" height=\"$t_h\" alt=\"$title\">\n";
	} else {
		print "<b style=\"color:$t_col;font-size:$t_size\">$title</b>\n";
	}

	print "</div><dl>\n";

	$i=0;
	open(IN,"$logfile") || &error("Open Error: $logfile");
	while (<IN>) {
		$i++;
		if ($i < $page + 1) { next; }
		if ($i > $page + $p_log) { last; }

		($no,$date,$nam,$eml,$sub,$com,$url) = split(/<>/);
		if ($eml) { $nam = "<a href=\"mailto:$eml\">$nam</a>"; }

		if ($autolink) { &auto_link($com); }
		if ($url) { $com .= "<p><a href=\"$url\" target=\"_blank\">$url</a>"; }

		print "<dt><hr>[<b>$no</b>] ";
		if ($subject) {
			print "<b style='color:$subcol'>$sub</b> ";
			print "Contributor :<b>$nam</b> Contribution day:$date<br><br>\n";
		} else {
			print "<b>$nam</b> - $date<br><br>\n";
		}
		print "<dd>$com<br><br>\n";
	}
	close(IN);

	print <<EOM;
<dt><hr>
</dl>
EOM

	$next = $page + $p_log;
	$back = $page - $p_log;

	print "<table align=left><tr>\n";
	if ($back >= 0) {
		print "<td><form action=\"$script\">\n";
		print "<input type=hidden name=page value=\"$back\">\n";
		print "<input type=submit value=\"Before$p_log件\"></form></td>\n";
	}
	if ($next < $i) {
		print "<td><form action=\"$script\">\n";
		print "<input type=hidden name=page value=\"$next\">\n";
		print "<input type=submit value=\"next$p_log件\"></form></td>\n";
	}

	# 著作権表示(削除禁止)
	print <<EOM;
</tr></table>
<table align=right>
<tr><td>
<form method="POST" action="$script">
<input type=hidden name=mode value="msg_del">
No<input type=text name=no size=3>
Delete key<input type=password size=4 name=delkey>
<input type=submit value="Delete"></form>
</td></tr></table><br clear=all>
<div align="center">$banner2
<p><!-- $ver -->
<span style="font-size:10px;font-family:Verdana,Helvetica,Arial">
- <a href='http://www.kent-web.com/' target='_top'>Com Board</a> -
</span>
</div>
</body>
</html>
EOM
	exit;
}

#-------------------------------------------------
#  記事投稿
#-------------------------------------------------
sub regist {
	local($no,$dat,$nam,$eml,$sub,$com,$url,$hos,$pw,$tim,@file,@w);

	# 投稿チェック
	if ($postonly && !$post_flag) { &error("不正なアクセスです"); }
	if ($baseUrl) { &refCheck; }

	# 名前とコメントは必須
	if ($in{'name'} eq "") { &error("名前が入力されていません"); }
	if ($in{'comment'} eq "") { &error("コメントが入力されていません"); }
	if ($in{'email'} && $in{'email'}!~ /[\w\.\-]+\@[\w\.\-]+\.[a-zA-Z]{2,6}$/)
		{ &error("Eメールの入力内容が不正です"); }
	if ($in{'url'} eq "http://" || $in{'url'} eq "https://") { $in{'url'}=""; }

	# ロック処理
	&lock if ($lockkey);

	# ログを開く
	open(IN,"$logfile") || &error("Open Error: $logfile");
	@file = <IN>;
	close(IN);

	# 重複投稿チェック
	local($no,$dat,$nam,$eml,$sub,$com,$url,$hos,$pw,$tim) = split(/<>/, $file[0]);
	if ($in{'name'} eq $nam && $in{'comment'} eq $com)
		{ &error("二重投稿は禁止です"); }

	# 連続投稿チェック
	$time = time;
	$flag=0;
	if ($regCtl == 1) {
		if ($host eq $hos && $time - $tim < $wait) { $flag=1; }
	} elsif ($regCtl == 2) {
		if ($time - $tim < $wait) { $flag=1; }
	}
	if ($flag) {
		&error("現在投稿制限中です。もうしばらくたってから投稿をお願いします");
	}

	# 記事Noを採番
	$no++;

	# 削除キーを暗号化
	if ($in{'pwd'} ne "") { $pwd = &encrypt($in{'pwd'}); }

	# 時間を取得
	local($min,$hour,$mday,$mon,$year,$wday) = (localtime($time))[1..6];
	@w = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
	$date = sprintf("%04d/%02d/%02d(%s) %02d:%02d",
			$year+1900,$mon+1,$mday,$w[$wday],$hour,$min);

	# 更新
	while ($max <= @file) { pop(@file); }
	unshift(@file,"$no<>$date<>$in{'name'}<>$in{'email'}<>$in{'sub'}<>$in{'comment'}<>$in{'url'}<>$host<>$pwd<>$time<>\n");
	open(OUT,">$logfile") || &error("Write Error: $logfile");
	print OUT @file;
	close(OUT);

	# ロック解除
	&unlock if ($lockkey);

	# クッキーを発行
	&set_cookie($in{'name'},$in{'email'},$in{'url'},$in{'pwd'});

	# メール通知処理
	if ($mailing == 1) { &mail_to; }
	elsif ($mailing == 2 && $in{'email'} ne $mailto) { &mail_to; }
}

#-------------------------------------------------
#  ユーザ記事削除
#-------------------------------------------------
sub msg_del {
	local($num,$date,$name,$email,$sub,$com,$url,$host,$pw,$pw2,$flag,$match,@data);

	# 投稿チェック
	if ($postonly && !$post_flag) { &error("不正なアクセスです"); }
	if ($baseUrl) { &refCheck; }

	if ($in{'no'} eq "") { &error("記事NOが入力されていません"); }
	if ($in{'delkey'} eq "") { &error("削除キーが入力されていません"); }

	# ロック開始
	if ($lockkey) { &lock; }

	# ログ読み込み
	$flag=0; @data=();
	open(IN,"$logfile") || &error("Open Error: $logfile");
	while (<IN>) {
		($num,$date,$name,$email,$sub,$com,$url,$host,$pw) = split(/<>/);

		if ($in{'no'} == $num) {
			if ($pw) { $pw2=$pw; $flag=1; }
			else { $flag=2; }
			next;
		}
		push(@data,$_);
	}
	close(IN);

	if ($flag == 0) { &error("記事Noが不正です"); }
	elsif ($flag == 2) { &error("削除キーが設定されていません"); }

	# パスワードを照合
	$match = &decrypt($in{'delkey'}, $pw2);
	if ($match != 1) { &error("削除キーが違います"); }

	# ログを更新
	open(OUT,">$logfile") || &error("Write Error: $logfile");
	print OUT @data;
	close(OUT);

	# ロック解除
	if ($lockkey) { &unlock; }

	# 記事表示画面に戻る
	&html_log;
}

#-------------------------------------------------
#  留意事項
#-------------------------------------------------
sub howto {
	&header;
	print <<EOM;
$body
[<a href="$script?mode=log">戻る</a>]
<center>
<h3>掲示板の利用上の注意</h3>
<table width="95%" border=1 cellpadding=15>
<tr><td bgcolor="#FFFFFF">
<font color="#000000">
  <ol>
  <li>この掲示板は<b>クッキー対応</b>です。1度記事を投稿いただくと、
      おなまえ、Eメール、URLの情報は2回目以降は自動入力されます。
     (ただし利用者のブラウザがクッキー対応の場合)
  <li>投稿内容には、<b>タグは一切使用できません。</b>
  <li>記事を投稿する上での必須入力項目は<b>「おなまえ」</b>と<b>「メッセージ」</b>です。
  <li>記事には、<b>半角カナは一切使用しないで下さい。</b>文字化けの原因となります。
  <li>記事の保持件数は<b>最大 $max件</b>です。それを超えると古い順に自動削除されます。
  <li>過去の投稿記事から<b>「キーワード」によって簡易検索ができます。
     </b>トップメニューの<a href="$script?mode=find">「ワード検索」</a>
      のリンクをクリックすると検索モードとなります。
  <li>管理者が著しく不利益と判断する記事や他人を誹謗中傷する記事は予\告\なく削除することがあります。
  </ol>
</font>
</td></tr></table>
</center>
</body>
</html>
EOM
	exit;
}

#-------------------------------------------------
#  ワード検索
#-------------------------------------------------
sub find {
	&header;
	print <<EOM;
$body
[<a href="$script?mode=log">戻る</a>]
<ul>
<li>検索したいキーワードを入力し検索ボタンを押してください。
<li>キーワードはスペースで区切って複数指定することができます。
<form action="$script" method="POST">
<input type=hidden name=mode value="find">
キーワード <input type=text name=word size=30 value="$in{'word'}">
条件 <select name=cond>
EOM

	foreach ("AND", "OR") {
		if ($in{'cond'} eq $_) {
			print "<option value=\"$_\" selected>$_\n";
		} else {
			print "<option value=\"$_\">$_\n";
		}
	}
	print "</select> 表\示 <select name=view>\n";
	foreach (10,15,20,25,30) {
		if ($in{'view'} == $_) {
			print "<option value=\"$_\" selected>$_件\n";
		} else {
			print "<option value=\"$_\">$_件\n";
		}
	}

	print <<EOM;
</select>
<input type=submit value=" 検索 ">
</form>
</ul>
EOM

	# ワード検索の実行と結果表示
	if ($in{'word'} ne "") {

		local($no,$ymd,$nam,$eml,$sub,$com,$url,$i,
			$wd,$flag,$next,$back,$enwd,@wd,@find);

		# 入力内容を整理
		$in{'word'} =~ s/\x81\x40/ /g;
		@wd = split(/\s+/, $in{'word'});

		# 検索
		print "<dl>\n";
		open(IN,"$logfile") || &error("Open Error: $logfile");
		while (<IN>) {
			$flag=0;
			foreach $wd (@wd) {
				if (index($_,$wd) >= 0) {
					$flag=1;
					if ($in{'cond'} eq 'OR') { last; }
				} else {
					if ($in{'cond'} eq 'AND') { $flag=0; last; }
				}
			}
			if ($flag) {
				$i++;
				next if ($i < $page + 1);
				next if ($i > $page + $in{'view'});

				push(@find,$_);
			}
		}
		close(IN);

		# 結果を表示
		print "<dt>▽ <b>$in{'word'}</b> に関連する記事は<b>$i</b>件見つかりました。\n";

		foreach (@find) {
			($no,$ymd,$nam,$eml,$sub,$com,$url) = split(/<>/);
			if ($eml) { $nam="<a href=\"mailto:$eml\">$nam</a>"; }
			if ($url) { $com .= "<p><a href=\"$url\" target=\"_blank\">$url</a>"; }

			# 結果を表示
			print "<dt><hr>[<b>$no</b>] ";
			print "<b style='color:$subcol'>$sub</b> " if ($subject);
			print "投稿者:<b>$nam</b> 投稿日:$ymd<br><br>\n";
			print "<dd>$com<br><br>\n";
		}

		print "<dt><hr></dl>\n";

		$next = $page + $in{'view'};
		$back = $page - $in{'view'};
		$enwd = &url_enc($in{'word'});

		if ($back >= 0) {
			print "[<a href=\"$script?mode=find&page=$back&word=$enwd&view=$in{'view'}&cond=$in{'cond'}\">前の$in{'view'}件</a>]\n";
		}
		if ($next < $i) {
			print "[<a href=\"$script?mode=find&page=$next&word=$enwd&view=$in{'view'}&cond=$in{'cond'}\">次の$in{'view'}件</a>]\n";
		}
	}

	print "</body></html>\n";
	exit;
}

#-------------------------------------------------
#  管理モード
#-------------------------------------------------
sub admin {
	local($no,$date,$nam,$eml,$sub,$com,$url,$host);

	# 認証
	if ($in{'pass'} eq "") { &enter; }
	elsif ($in{'pass'} ne $pass) { &error("パスワードが違います"); }

	# 削除
	if ($in{'no'}) {

		local($f,$del,$no,@new);

		# ロック開始
		&lock if ($lockkey);

		open(IN,"$logfile") || &error("Open Error: $logfile");
		while (<IN>) {
			($no) = split(/<>/);

			$f=0;
			foreach $del ( split(/\0/, $in{'no'}) ) {
				if ($no == $del) { $f++; last; }
			}
			if (!$f) { push(@new,$_); }
		}
		close(IN);

		# 更新
		open(OUT,">$logfile") || &error("Write Error: $logfile");
		print OUT @new;
		close(OUT);

		# ロック解除
		&unlock if ($lockkey);
	}

	&header;
	print <<EOM;
$body
[<a href="$script?mode=log">掲示板に戻る</a>]
<form action="$script" method="POST">
<input type=hidden name=mode value="admin">
<input type=hidden name=pass value="$in{'pass'}">
<input type=submit value="削除する">
<dl>
EOM

	# 記事展開
	open(IN,"$logfile") || &error("Open Error: $logfile");
	while (<IN>) {
		($no,$date,$nam,$eml,$sub,$com,$url,$host) = split(/<>/);
		if ($eml) { $nam = "<a href=\"mailto:$eml\">$nam</a>"; }
		$com =~ s/<[^>]*(>|$)//g;
		if (length($com) > 60) {
			$com = substr($com,0,58);
			$com .= "...";
		}

		print "<dt><hr><input type=checkbox name=no value=\"$no\">[$no] ";
		print "<b style='color:$subcol'>$sub</b> - " if ($subject);
		print "$nam &lt;$date&gt; 【$host】<dd>$com\n";
	}
	close(IN);

	print <<EOM;
<dt><hr>
</dl>
</form>
</body>
</html>
EOM
	exit;
}

#-------------------------------------------------
#  入室画面
#-------------------------------------------------
sub enter {
	&header;
	print <<EOM;
$body
<div align="center">
<b>パスワードを入力して下さい</b>
<form action="$script" method="POST">
<input type=hidden name=mode value="admin">
<input type=password name=pass size=8>
<input type=submit value=" 認証 ">
</form></div>
</body>
</html>
EOM
	exit;
}

#-------------------------------------------------
#  デコード処理
#-------------------------------------------------
sub decode {
	local($buf, $key, $val);
	undef(%in);

	if ($ENV{'REQUEST_METHOD'} eq "POST") {
		$post_flag=1;
		if ($ENV{'CONTENT_LENGTH'} > 51200) { &error("投稿量が大きすぎます"); }
		read(STDIN, $buf, $ENV{'CONTENT_LENGTH'});
	} else {
		$post_flag=0;
		$buf = $ENV{'QUERY_STRING'};
	}

	foreach ( split(/&/, $buf) ) {
		($key, $val) = split(/=/);
		$val =~ tr/+/ /;
		$val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("H2", $1)/eg;

		# S-JISコード変換
		&jcode'convert(*val, "sjis");

		# タグ処理
		$val =~ s/&/&amp;/g;
		$val =~ s/"/&quot;/g;
		$val =~ s/</&lt;/g;
		$val =~ s/>/&gt;/g;
		$val =~ s/\0//g;

		# 改行処理
		if ($key eq "comment") {
			$val =~ s/\r\n/<br>/g;
			$val =~ s/\r/<br>/g;
			$val =~ s/\n/<br>/g;
		} else {
			$val =~ s/\r//g;
			$val =~ s/\n//g;
		}
		$in{$key} .= "\0" if (defined($in{$key}));
		$in{$key} .= $val;
	}
	if ($subject && $in{'sub'} eq "") { $in{'sub'} = "無題"; }
	$page = $in{'page'};
	$mode = $in{'mode'};

	# タイムゾーン設定
	$ENV{'TZ'} = "JST-9";

	if ($bg) { $bg = "background=\"$bg\""; }
	$body = "<body bgcolor=\"$bc\" text=\"$te\" link=\"$li\" vlink=\"$vl\" $bg>\n";

	# 返り値
	if ($buf) { return (1); } else { return (0); }
}

#-------------------------------------------------
#  ロック処理
#-------------------------------------------------
sub lock {
	local($retry) = 5;

	# 古いロックは削除
	if (-e $lockfile) {
		local($mtime) = (stat($lockfile))[9];
		if ($mtime < time - 30) { &unlock; }
	}

	# symlink関数式ロック
	if ($lockkey == 1) {
		while (!symlink(".", $lockfile)) {
			if (--$retry <= 0) { &error('Lock is busy'); }
			sleep(1);
		}

	# mkdir関数式ロック
	} elsif ($lockkey == 2) {
		while (!mkdir($lockfile, 0755)) {
			if (--$retry <= 0) { &error('Lock is busy'); }
			sleep(1);
		}
	}
	$lockflag=1;
}

#-------------------------------------------------
#  ロック解除
#-------------------------------------------------
sub unlock {
	if ($lockkey == 1) { unlink($lockfile); }
	elsif ($lockkey == 2) { rmdir($lockfile); }

	$lockflag=0;
}

#-------------------------------------------------
#  メール送信
#-------------------------------------------------
sub mail_to {
	local($msub,$mcom,$mbody);

	# タイトルを定義
	$msub = "[$title : $no] $in{'sub'}";

	# 本文の改行・タグを復元
	$mcom = $in{'comment'};
	$mcom =~ s/<br>/\n/g;
	$mcom =~ s/&lt;/</g;
	$mcom =~ s/&gt;/>/g;
	$mcom =~ s/&quot;/"/g;
	$mcom =~ s/&amp;/&/g;

	# 本文を定義
	$mbody = <<"EOM";
投稿日時:$date
ホスト名:$host
ブラウザ:$ENV{'HTTP_USER_AGENT'}

おなまえ:$in{'name'}
Eメール:$in{'email'}
EOM

	if ($subject) { $mbody .= "タイトル:$in{'sub'}\n"; }
	$mbody .= "\n$mcom\n";

	# 題名をBASE64化
	$msub = &base64($msub);

	# メールアドレスがない場合は管理者アドレスに置き換え
	if ($in{'email'} eq "") { $email = $mailto; }
	else { $email = $in{'email'}; }

	# sendmail送信
	open(MAIL,"| $sendmail -t") || &error("メール送信失敗");
	print MAIL "To: $mailto\n";
	print MAIL "From: $email\n";
	print MAIL "Subject: $msub\n";
	print MAIL "MIME-Version: 1.0\n";
	print MAIL "Content-type: text/plain; charset=ISO-2022-JP\n";
	print MAIL "Content-Transfer-Encoding: 7bit\n";
	print MAIL "X-Mailer: $ver\n\n";
	foreach ( split(/\n/, $mbody) ) {
		&jcode'convert(*_, 'jis', 'sjis');
		print MAIL $_, "\n";
	}
	close(MAIL);
}

#-------------------------------------------------
#  クッキー発行
#-------------------------------------------------
sub set_cookie {
	local(@cook) = @_;
	local($gmt, $cook, @t, @m, @w);

	@t = gmtime(time + 60*24*60*60);
	@m = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
	@w = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');

	# 国際標準時を定義
	$gmt = sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT",
			$w[$t[6]], $t[3], $m[$t[4]], $t[5]+1900, $t[2], $t[1], $t[0]);

	# 保存データをURLエンコード
	foreach (@cook) {
		s/(\W)/sprintf("%%%02X", unpack("C", $1))/eg;
		$cook .= "$_<>";
	}

	# 格納
	print "Set-Cookie: COMBBS=$cook; expires=$gmt\n";
}

#-------------------------------------------------
#  クッキー取得
#-------------------------------------------------
sub get_cookie {
	local($key, $val, *cook);

	# クッキーを取得
	$cook = $ENV{'HTTP_COOKIE'};

	# 該当IDを取り出す
	foreach ( split(/;/, $cook) ) {
		($key, $val) = split(/=/);
		$key =~ s/\s//g;
		$cook{$key} = $val;
	}

	# データをURLデコードして復元
	foreach ( split(/<>/, $cook{'COMBBS'}) ) {
		s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;

		push(@cook,$_);
	}
	return (@cook);
}

#-------------------------------------------------
#  エラー処理
#-------------------------------------------------
sub error {
	if ($lockflag) { &unlock; }

	&header;
	print <<EOM;
$body
<div align="center">
<h3>ERROR !</h3>
<font color="#dd0000">$_[0]</font>
<p>
<form>
<input type=button value="前画面に戻る" onClick="history.back()">
</form>
</div>
</body>
</html>
EOM
	exit;
}

#-------------------------------------------------
#  自動リンク処理
#-------------------------------------------------
sub auto_link {
	$_[0] =~ s/([^=^\"]|^)(http\:[\w\.\~\-\/\?\&\+\=\:\@\%\;\#]+)/$1<a href=\"$2\" target=\"_top\">$2<\/a>/g;
}

#-------------------------------------------------
#  URLエンコード
#-------------------------------------------------
sub url_enc {
	local($_) = @_;

	s/(\W)/'%' . unpack('H2', $1)/eg;
	s/\s/+/g;
	$_;
}

#-------------------------------------------------
#  crypt暗号
#-------------------------------------------------
sub encrypt {
	local($in) = @_;
	local($salt, $enc, @s);

	@s = ('a'..'z', 'A'..'Z', '0'..'9', '.', '/');
	srand;
	$salt = $s[int(rand(@s))] . $s[int(rand(@s))];
	$enc = crypt($in, $salt) || crypt ($in, '$1$' . $salt);
	$enc;
}

#-------------------------------------------------
#  crypt照合
#-------------------------------------------------
sub decrypt {
	local($in, $dec) = @_;

	local $salt = $dec =~ /^\$1\$(.*)\$/ && $1 || substr($dec, 0, 2);
	if (crypt($in, $salt) eq $dec || crypt($in, '$1$' . $salt) eq $dec) {
		return (1);
	} else {
		return (0);
	}
}

#-------------------------------------------------
#  REFチェック
#-------------------------------------------------
sub refCheck {
	local($ref) = $ENV{'HTTP_REFERER'};
	$ref =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("H2", $1)/eg;

	$baseUrl =~ s/(\W)/\\$1/g;
	if ($ref && $ref !~ /$baseUrl/i) { &error("不正なアクセスです"); }
}

#-------------------------------------------------
#  BASE64変換
#-------------------------------------------------
#	とほほのWWW入門で公開されているルーチンを
#	参考にしました。( http://tohoho.wakusei.ne.jp/ )
sub base64 {
	local($sub) = @_;
	&jcode'convert(*sub, 'jis', 'sjis');

	$sub =~ s/\x1b\x28\x42/\x1b\x28\x4a/g;
	$sub = "=?iso-2022-jp?B?" . &b64enc($sub) . "?=";
	$sub;
}
sub b64enc {
	local($ch)="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	local($x, $y, $z, $i);
	$x = unpack("B*", $_[0]);
	for ($i=0; $y=substr($x,$i,6); $i+=6) {
		$z .= substr($ch, ord(pack("B*", "00" . $y)), 1);
		if (length($y) == 2) {
			$z .= "==";
		} elsif (length($y) == 4) {
			$z .= "=";
		}
	}
	$z;
}


__END__