#!/usr/bin/perl

## -------------------------------------------------------------------
##
## Aero Chat ver1.b Modified by Mimosa
## Original Script: WINDY v1.31 (2000/08/15) (C) KENT WEB 2000
##
## -------------------------------------------------------------------

$ver = 'Aero v1.b'; # バージョン情報

#============#
#  設定項目  #
#============#

# 文字コード変換ライブラリ取込む
require './jcode.pl';

# スクリプト名 (この掲示板のファイル名)
$script = "./aero.cgi";

# ログファイル（フルパスで記述する場合は / から始まるパス）
$logfile = "./aero.log";

# 参加者ファイル（フルパスで記述する場合は / から始まるパス）
$memfile = "./member.dat";

# methodの形式 (POST or GET)
$method = 'POST';

# タイトル名
$title = "Chat Room";

# タイトル文字のサイズ
$t_size = '12pt';
# 本文全体の文字サイズ
$t_base = '10pt';

# タイトル文字のフォントタイプ
# 日本語ならＭＳ Ｐゴシック、MS UI Gothicなど
$t_face = "Arial";

# タイトル文字の色
$t_color = "#20C9FF";

# 背景色、文字色等を指定
$bground = "";			# 壁紙を使用する場合 (http://から記述）
$bgcolor = "#FFFFFF";		# 背景色
$text    = "#696969";		# 文字色
$link    = "#696969";		# リンク色（訪問済）
$vlink   = "#696969";		# 　〃　　（既訪問）
$alink   = "#00BFFF";		# 　〃　　（訪問中）

# 最大保有記事数（これを超える記事は自動削除される）
$max = 30;

# 戻り先のURL (http://から記述してもよい)
$homepage = 'http://contest2.thinkquest.jp/tqj2003/60004/top2.html';

# タグの許可 (0=no 1=yes)
$tagkey = 0;

# 色指定（上下は必ずペアで指定）
@CLR = ('#B8DC80','#20C9FF','C100C1','000080','DF0000','#FF80C0','#FFCF70','800000');
@IRO = ('Leaf','Blue','Indigo','Violet','Red','Pink','Peach','Maroon');

# 入退室のあいさつ
$in_msg  = 'さん、いらっしゃい。';	# 入室あいさつ
$out_msg = 'さん、さようなら。';	# 退室あいさつ

# 発言部の前につくポインタ
$point = '●';

# 発言と発言の間に水平線を挿入 (0=水平線を入れる 1=スペースのみ)
$space = 0;

# 発言後フォーカスをフォームへ自動移動 (0=no 1=yes)
$jvfocus = 1;

# ファイルロックの指定 (0=no 1=yes)
# yes の場合「ディレクトリ」のパーミッションを７７７か７０１にする
$lockkey = 0;

# ロックファイル名（フルパスで記述する場合は / から始まるパス）
$lockfile = "./aero.lock";

#=======================================================================================
#	設定完了。ここから下は、perlの知識がある人のみ改造を行ってください。
#=======================================================================================

# メイン処理
&decode;
if ($mode eq "regist" && $com) { &regist; }
elsif ($mode eq 'into') { &regist('into'); }
elsif ($mode eq 'out') { &out; }
&html;

#------------------#
#  HTMLのヘッダー  #
#------------------#
sub header {
	print "Content-type: text/html\n\n";
	print "<html>\n<head>\n";
	print "<META HTTP-EQUIV=\"Content-type\" CONTENT=\"text/html; charset=Shift_JIS\">\n";

	# 発言後フォーカスをフォームへ自動移動 (kapiさん式)
	if (($jvfocus && $mode eq 'into') || ($jvfocus && $mode eq 'regist')) {

		$focus = " onLoad=\"return textfocus()\"";
		print "<script language=\"JavaScript\">\n";
		print "<!--\n";
		print "function textfocus(){\n";
		print "document.windy.comment.focus();\n";
		print "return true;\n";
		print "}\n";
		print "//-->\n";
		print "</script>\n";
	}
	print <<"EOM";
	<STYLE TYPE="text/css">
	<!--
	body, tr, td { font-size: $t_base; font-family: 'Arial' 'MS UI Gothic' }
	small        { font-size: 8pt }

	a	  { text-decoration:none }
	a:hover   { color:$alink }
-->
	</STYLE>
	<title>$title</title></head>
EOM
	print "<body background=\"$bground\" bgcolor=\"$bgcolor\" text=\"$text\" link=\"$link\" vlink=\"$vlink\" alink=\"$alink\"$focus>\n";
}

#--------------#
#  記事表示部  #
#--------------#
sub html {
	# 表示開始
	&header;

	if ($mode eq 'into' || $mode eq 'regist') {
		print "<form name=\"windy\" method=\"$method\" action=\"$script\">\n";
		print "<input type=hidden name=mode value=\"regist\">\n";
		print "<input type=hidden name=name value=\"$name\">\n";
		print "<input type=hidden name=email value=\"$email\">\n";
		print "<input type=text name=comment size=50>";
		print "<input type=submit value=\"発言／リロード\">";
		print "<input type=reset value=\"クリア\"><br>\n";
		print "<table><tr><td nowrap>文字色 <select name=color>\n";

		foreach (0 .. $#CLR) {
			if ($color eq "$CLR[$_]") {
				print "<option value=\"$CLR[$_]\" selected>$IRO[$_]\n";
			} else {
				print "<option value=\"$CLR[$_]\">$IRO[$_]\n";
			}
		}

		print "</select></form></td><td width=20></td>\n";
		print "<td><form method=\"$method\" action=\"$script\">\n";
		print "<input type=hidden name=mode value=\"out\">\n";
		print "<input type=hidden name=name value=\"$name\">\n";
		print "<input type=submit value=\"退室する\"></form></td>\n";
		print "</tr></table>\n";
		# 参加者表示
		&member;
		print "<small>参加者($num)：$member</small><br>\n";
		if ($space == 1) { print "<hr size='1'>\n"; }

	}
	else {
		# クッキーを取得
		&get_cookie;

		print "<font color=\"$t_color\" style=\"font-size:$t_size\" face=\"$t_face\">$title</font>\n";
		print "&nbsp; / / <a href=\"$homepage\">Back</a> / /<br>\n";
		print "<hr size='1'>\n";
		print "<form method=\"$method\" action=\"$script\">\n";
		print "<input type=hidden name=mode value=\"into\">\n";
		print "<table border=0>\n";
		print "<tr><td>Name</td>\n";
		print "<td><input type=text name=name size=25 value=\"$c_name\"></td>\n";
		print "<td rowspan=3 width=80></td>\n";
		print "<td rowspan=3 valign='top' align='center' nowrap><small>\n";
		print "- 文字色をお選び下さい -<br>\n";

		# クッキーの色情報がない場合
		if ($c_color eq '') { $c_color = $CLR[0]; }

		$i=0;
		$br = @CLR / 2;
		foreach (0 .. $#CLR) {
			if ($c_color eq "$CLR[$_]") {
				print "<input type=radio name=color value=\"$CLR[$_]\" checked><font color=\"$CLR[$_]\">■</font>\n";
			} else {
				print "<input type=radio name=color value=\"$CLR[$_]\"><font color=\"$CLR[$_]\">■</font>\n";
			}
			$i++;
			if ($i >= $br) { print '<br>'; $i=0; }
		}

		print "</small></td></tr>\n";
		print "<tr><td>E-mail</td>\n";
		print "<td><input type=text name=email size=25 value=\"$c_email\"></td></tr>\n";
		print "<tr><td colspan=2><input type=submit value=\"入室する\"> <input type=reset value=\"リセット\"></td></tr>\n";
		print "</table></form>\n";
		if ($space == 1) { print "<hr size='1'><br>\n"; }
	}

	# ログを展開
	open(IN,"$logfile") || &error("Open Error : $logfile");
	while (<IN>) {
		$head = $point;
		local($date,$name,$mail,$com,$color,$ip) = split(/<>/);

		if ($mail) { $head = "<a href=\"mailto\:$mail\">$point</a>"; }
		if ($space == 1) {
		print "$head <font color=\"$color\"><b>$name</b> > $com</font> <small>($date)<br>\n";
		print "<br></small>\n";
		} else {
		print "<hr size='1'>$head <font color=\"$color\"><b>$name</b> > $com</font> <small>($date)</small>\n";
		}
	}
	close(IN);

	# 著作権表示（削除禁止）
	print "<hr size='1'><center><small><!-- $ver -->\n";
	print "- <a href='http://www2u.biglobe.ne.jp/~APercher/retro/' target='_blank'>Aero Chat</a>\n";
	print "/ <a href='http://www.kent-web.com/' target='_blank'>Original</a> -\n";
	print "</small></center>\n";
	print "</body></html>\n";
	exit;
}

#--------------------#
#  ログ書き込み処理  #
#--------------------#
sub regist {
	# 名前の入力がなければエラー
	if ($in{'name'} eq "") { &error("名前の入力がありません"); }

	if ($_[0] eq 'into') {
		&set_cookie;

		$n_name = "<small>管理人</small>";
		$com = "$name" . "$in_msg";
		$n_email = "";
		$n_color = $text;
	}
	elsif ($_[0] eq 'out') {
		$n_name = "<small>管理人</small>";
		$com = "$name" . "$out_msg";
		$n_email = "";
		$n_color = $text;
	}
	else {
		$n_name = $name;
		$n_email = $email;
		$n_color = $color;
	}

	# ファイルロック
	if ($lockkey) { &lock; }

	# ログを読み込み
	open(IN,"$logfile") || &error("Open Error : $logfile");
	@lines = <IN>;
	close(IN);

	# 最大記事数処理
	while ($max <= @lines) { pop(@lines); }

	# ログ更新処理
	unshift (@lines,"$date<>$n_name<>$n_email<>$com<>$n_color<>$addr<>\n");
	open(OUT,">$logfile") || &error("Write Error : $logfile");
	print OUT @lines;
	close(OUT);

	# ロック解除
	if (-e $lockfile) { unlink($lockfile); }
}

#------------#
#  退室処理  #
#------------#
sub out {
	&regist('out');

	&header;
	print "<center><h3>$nameさん、ありがとうございました。</h3>\n";
	print "[ <a href=\"$homepage\" target=\"_top\">トップに戻る</a> ]</center><P>\n";
	if ($space == 1) { print "<hr size='1'>\n"; }

	open(IN,"$logfile") || &error("Open Error : $logfile");
	while (<IN>) {
		($date,$name,$email,$com,$color,$ip) = split(/<>/);
		if ($space == 1) { print "$point <font color=\"$color\"><B>$name</B> > $com</font> <small>($date)<br><br></small>\n"; }
		else {
		print "<hr size='1'>$point <font color=\"$color\"><B>$name</B> > $com</font> <small>($date)</small>\n"; }
	}
	close(IN);

	print "<hr size='1'>\n</body></html>\n";
	exit;
}

#----------------#
#  デコード処理  #
#----------------#
sub decode {
	if ($ENV{'REQUEST_METHOD'} eq "POST") {
		read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
	} else { $buffer = $ENV{'QUERY_STRING'}; }
	@pairs = split(/&/, $buffer);
	foreach $pair (@pairs) {
		($name, $value) = split(/=/, $pair);
		$value =~ tr/+/ /;
		$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

		# 文字コード変換
		&jcode'convert(*value,'sjis');

		# タグ処理
		if ($tagkey) {
			$value =~ s/<!--(.|\n)*-->//g;
			$value =~ s/<>/&lt;&gt;/g;
		} else {
			$value =~ s/</&lt;/g;
			$value =~ s/>/&gt;/g;
			$value =~ s/\"/&quot;/g;
		}

		$value =~ s/\n//g;
		$value =~ s/\r//g;
		$value =~ s/\t//g;

		$in{$name} = $value;
	}

	$name  = $in{'name'};
	$com   = $in{'comment'};
	$email = $in{'email'};
	$mode  = $in{'mode'};
	$color = $in{'color'};

	# 時間の取得
	$ENV{'TZ'} = "JST-9";
	$times = time;
	($sec,$min,$hour,$mday,$mon) = localtime($times);

	# 日時のフォーマット
	$date = sprintf("%02d/%02d-%02d:%02d:%02d",$mon+1,$mday,$hour,$min,$sec);

	# IPアドレスを取得
	$addr = $ENV{'REMOTE_ADDR'};
	if ($name eq "") { $name = $addr; }
}

#------------------#
#  クッキーの発行  #
#------------------#
sub set_cookie {
	# クッキーは60日間有効
	($secg,$ming,$hourg,$mdayg,$mong,$yearg,$wdayg)	= gmtime(time + 60*24*60*60);

	@mons = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
	@week = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');

	$gm_date = sprintf("%s\, %02d-%s-%04d %02d:%02d:%02d GMT",
		$week[$wdayg],$mdayg,$mons[$mong],$yearg+1900,$hourg,$ming,$secg);
	$cook = "name\:$name\,email\:$email\,color\:$color";
	print "Set-Cookie: WINDY=$cook; expires=$gm_date\n";
}

#------------------#
#  クッキーを取得  #
#------------------#
sub get_cookie {
	$cookie = $ENV{'HTTP_COOKIE'};

	@pairs = split(/;/, $cookie);
	foreach $pair (@pairs) {
		local($name, $value) = split(/=/, $pair);
		$name =~ s/ //g;
		$DUMMY{$name} = $value;
	}
	@pairs = split(/,/, $DUMMY{'WINDY'});
	foreach $pair (@pairs) {
		local($name, $value) = split(/:/, $pair);
		$COOKIE{$name} = $value;
	}
	$c_name  = $COOKIE{'name'};
	$c_email = $COOKIE{'email'};
	$c_color = $COOKIE{'color'};

	if ($in{'name'})  { $c_name  = $in{'name'}; }
	if ($in{'email'}) { $c_email = $in{'email'}; }
	if ($in{'color'}) { $c_color = $in{'color'}; }
}

#--------------#
#  エラー処理  #
#--------------#
sub error {
	if (-e $lockfile) { unlink($lockfile); }

	&header;
	print "<center><hr width='75%'><P><h3>ERROR !</h3>\n";
	print "<P><font color=red><B>$_[0]</B></font>\n";
	print "<P><hr width='75%'></center>\n";
	print "</body></html>\n";
	exit;
}

#------------------------#
#  ロックファイルの生成  #
#------------------------#
sub lock {
	local($lflag) = 0;
	foreach (1 .. 5) {
		if (-e $lockfile) { sleep(1); }
		else {
			open(LOCK,">$lockfile") || &error("Can't create $lockfile");
			close(LOCK);
			$lflag = 1;
			last;
		}
	}
	if ($lflag == 0) { &error("LOCK is BUSY"); }
}

#--------------#
#  在室者処理  #
#--------------#
sub member {
	open(IN,"$memfile") || &error("Open Error : $memfile");
	@data = <IN>;
	close(IN);

	$member="";
	@new=();
	$flag=0;
	$flag2=0;
	foreach (@data) {
		($time2,$name2,$host2) = split(/<>/);
		# 60秒以上発言のない者は削除
		if ($times-60 > $time2) { next; }
		elsif ($host2 eq "$addr") {
			# 退室者は削除
			if ($_[0] eq 'bye') { next; }

			# ホスト名が同一であれば時間と名前を更新
			$_ = "$times<>$name<>$addr<>\n";
			$name2 = $name;
			$flag=1;
		}
		# 更新用配列 @new に追加
		if ($name2 ne "$host2") {
			push(@new,$_);

			# 参加者表示用文字列を作成
			if (!$flag2) { $member .= "$name2◇"; $flag2=1; }
			else { $member .= "$name2◆"; $flag2=0; }
		}
	}
	# 新規参加者を追加
	if (!$flag && !$bye) {
		if ($name ne "$host") {
			push(@new,"$times<>$name<>$addr<>\n");
			if (!$flag2) { $member .= "$name◇"; }
			else { $member .= "$name◆"; }
		}
	}
	# 参加者数を認識
	$num = @new;

	# ファイル更新
	open(OUT,">$memfile") || &error("Write Error : $memfile");
	eval "flock(OUT,2);";
	truncate(OUT,0);
	seek(OUT,0,0);
	print OUT @new;
	close(OUT);
}
