#!/usr/bin/perl

## Web ANQ v1.4
## (C) 1997-1999 Kent Web (1999/09/18)
## E-Mail webmaster@kent-web.com
## Home   http://www.kent-web.com/

$ver = 'Anq v1.4'; # バージョン情報（修正不要）

## ---[注意事項ほか]--------------------------------------------------
## 1. このスクリプトはフリーソフトです。このスクリプトを使用したいか
##    なる損害に対して作者は一切の責任を負いません。
## 2. 設置に関する質問はサポート掲示板にお願いいたします。メールによる
##    質問はご遠慮ください。
## -------------------------------------------------------------------

# jcode.plが同一ディレクトリにある場合
require './jcode.pl';

#============#
#    設定    #
#============#

# タイトル名
$title = "このページについて";

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

# タイトル文字のタイプ
$t_face = "ＭＳ Ｐゴシック";

# タイトル文字の大きさ (1=特大 2=大 3=中 4=小)
$t_size = '2';

# スクリプト名
$script = "anq.cgi";

# ログファイル名
$logfile = "./anq.log";

# 管理用パスワード
$pass = 'harada';

# グラフ画像 (絶対パスだと http://から)
$graph = "./graph.gif";

# 戻り先 (絶対パスだと http://から)
$home = "../index2.html";

# bodyタグ
$body = '<body bgcolor="black" text="snow" link="#0000FF" vlink="#800080">';

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

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

# ロックファイル名
$lockfile = "anq.lock";

# ロックファイルディレクトリ
#  --> このディレクトリのパーミッションは 777 に設定
$lockdir = ".";

# サブタイトル
#  --> タイトル下にサブタイトルを記述します。（タグ使用可）
$subtitle = <<"EOM";
<!-- ここから -->
<OL>
  <LI>このページのご感想等をお聞かせて下さい。
</OL>
<!-- ここまで -->
EOM

#============#
#  設定完了  #
#============#

# ロックファイルを再定義
$lockfile = "$lockdir\/$lockfile";

## メイン処理 ##
&decode;
if ($mode eq 'regist') { &regist; }
if ($mode eq 'admin') { &admin; }
&html;

## --- 初期画面を表示
sub html {
	if ($t_size == 1) { $tag1='<h1>'; $tag2='</h1>'; }
	elsif ($t_size == 2) { $tag1='<h2>'; $tag2='</h2>'; }
	elsif ($t_size == 3) { $tag1='<h3>'; $tag2='</h3>'; }
	else { $tag1='<h4>'; $tag2='</h4>'; }

	&header;
	print <<"EOM";
<a href="$home" target="_top">▲ <b>TOP</b></a>
<center>
<hr width=60%>
<font color="$t_color" face="$t_face">$tag1$title$tag2</font>
<hr width=60%>
<P><table>
<tr><td>$subtitle</td></tr>
</table>
EOM

	open(IN,"$logfile") || &error("Open Error : $logfile","no");
	$total=0;
	while ($_ = <IN>) {
		($no,$item,$count,$addr) = split(/<>/, $_);

		$no{$no}    = $no;
		$item{$no}  = $item;
		$count{$no} = $count;

		$total += $count;
	}
	close(IN);

	$all = &filler($total);
	print "<form action=\"$script\" method=\"$method\">\n";
	print "<input type=hidden name=mode value=\"regist\">\n";
	print "<caption>有効投票：<b>$all</b>件</caption>\n";
	print "<table border=1 cellpadding=2 cellspacing=0>\n";
	print "<tr><th>順位</th><th>回答</th><th>項目</th><th>得票数</th><th>割合</th></tr>\n";

	# 回答がすべて 0 のとき
	if ($total == 0) {
		open(IN,"$logfile") || &error("Open Error : $logfile","no");
		while ($_ = <IN>) {
			($no,$item,$count,$addr) = split(/<>/, $_);

			print "<tr><th>1</th><th><input type=checkbox name=no value=\"$no\"></th>";
			print "<td><b>$item</b></td><th>$count</th>";
			print "<td><img src=\"$graph\" height=15 width=\"1\">&#32";
			print "<small>0.0\%</small></td></tr>\n";
		}
		close(IN);
	}
	# ソート処理
	else {
	    # ランク用中間ファイル
	    $rank1 = 0;
	    $rank2 = 1;
	    $count_tmp = 0;

	    # ソート処理
	    foreach (sort { ($count{$b} <=> $count{$a}) || ($a cmp $b) } keys(%count)) {
		($count{$_} == $count_tmp) || ($rank1 = $rank2);

		$per = int(($count{$_}*1000 / $total)+0.5) / 10;
		$per = sprintf("%.1f", $per);
		$width = int($per * 5);
		if ($width < 1) { $width = 1; }

		# 桁区切り
		$cnt = &filler($count{$_});

		print "<tr><th>$rank1</th><th><input type=checkbox name=no value=\"$_\"></th>";
		print "<td><b>$item{$_}</b></td><td align=right><b>$cnt</b></td>";
		print "<td><img src=\"$graph\" height=15 width=\"$width\">&#32";
		print "<small>$per\%</small></td></tr>\n";

		$count_tmp = $count{$_};
		$rank2++;
	    }
	}
	print "</table>\n";
	print "<P><input type=submit value=\"回答する\"><input type=reset value=\"リセット\">\n";
	print "</form>\n";

	# 管理用フォーム
	print "<div align=right>\n";
	print "<form action=\"$script\" method=\"$method\">\n";
	print "<input type=hidden name=mode value=\"admin\">\n";
	print "<input type=password name=pass size=8>";
	print "<input type=submit value=\"管理用\">\n";
	print "</form></div>\n";

	# 著作権表示（削除不可）
	print "<small><!-- $ver -->\n";
	print "- <a href=\"http://www.kent-web.com/\" target=_top>Web Anq</a> -";
	print "</small></center>\n";
	print "</body></html>\n";
	exit;
}

## --- 投票受付処理
sub regist {
	# 一時ファイルを定義
	$temp = "$$";
	if ($temp eq '') {
		srand;
		$temp = 1000000000000000 * rand;
	}
	$tmpfile = "$lockdir\/$temp\.tmp";

	# IPアドレスを取得
	$addr = $ENV{'REMOTE_ADDR'};

	# ロック処理
	if ($lockkey == 1) { &lock1; }
	elsif ($lockkey == 2) { &lock2; }

	open(IN,"$logfile") || &error("Open Error : $logfile","lock");
	open(OUT,">$tmpfile") || &error("Open Error : Temp File","lock");
	while ($_ = <IN>) {
		$flag=0;
		($no,$item,$count,$ip) = split(/<>/, $_);

		foreach $ans (@ANS) {
			if ($no eq "$ans") { $flag=1; last; }
		}
		if ($flag) {
			if ($addr ne "$ip") { $count++; }
			print OUT "$no<>$item<>$count<>$addr<>\n";
		}
		else {
			print OUT $_;
		}
	}
	close(OUT);
	close(IN);

	chmod (0666,$tmpfile);
	rename ($tmpfile,$logfile) || &error("Rename Error","lock");
	if (-e $tmpfile) { unlink($tmpfile); }

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

	# 完了メッセージ
	&header;
	print <<"EOM";
<center>
<P><hr width="75%">
<P><h3>ご回答ありがとうございました。</h3>
<P><form action="$script" method="GET">
<input type=submit value="一覧にもどる">
</form>
<P><hr width="75%">
</center>
</body></html>
EOM
	exit;
}

## --- 管理モード
sub admin {
	if ($FORM{'pass'} ne "$pass") { &error("パスワードが違います。","no"); }

	# 項目追加処理
	if ($FORM{'item'}) {

		# ロック処理
		if ($lockkey == 1) { &lock1; }
		elsif ($lockkey == 2) { &lock2; }

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

		$no++;

		open(OUT,">>$logfile") || &error("Write Error : $logfile","lock");
		print OUT "$no<>$item<>0<><>\n";
		close(OUT);

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

	}
	# 削除処理
	if ($DEL[0]) {
		# 一時ファイルを定義
		$temp = "$$";
		if ($temp eq '') {
			srand;
			$temp = 1000000000000000 * rand;
		}
		$tmpfile = "$lockdir\/$temp\.tmp";

		# ロック処理
		if ($lockkey == 1) { &lock1; }
		elsif ($lockkey == 2) { &lock2; }

		open(IN,"$logfile") || &error("Open Error : $logfile","lock");
		open(OUT,">$tmpfile") || &error("Write Error : Temp File","lock");
		while ($_ = <IN>) {
			$flag=0;
			($no,$item) = split(/<>/, $_);
			foreach $del (@DEL) {
				if ($no eq "$del") { $flag=1; last; }
			}
			if ($flag == 0) { print OUT $_; }
		}
		close(OUT);
		close(IN);

		chmod (0666,$tmpfile);
		rename ($tmpfile,$logfile) || &error("Rename Error","lock");
		if (-e $tmpfile) { unlink($tmpfile); }

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

	&header;
	print <<"EOM";
[<a href="$script\?">初期画面に戻る</a>]
<table width="100%"><tr><th bgcolor="#0000A0">
<font color="#FFFFFF">管理モード</font>
</th></tr></table>
<P><blockquote>
<h4>1. 項目の追加</h4>
<form action="$script" method="$method">
<input type=hidden name=pass value="$FORM{'pass'}">
<input type=hidden name=mode value="admin">
項目 <input type=text name=item size=30>
<input type=submit value="項目を追加">
</form>
<P><hr>
<h4>2. データのメンテ</h4>
<form action="$script" method="$method">
<input type=hidden name=pass value="$FORM{'pass'}">
<input type=hidden name=mode value="admin">
<table border=1>
<tr>
  <th>削除</th><th>項目</th><th>得票数</th>
</tr>
EOM
	open(IN,"$logfile") || &error("Open Error : $logfile","no");
	while ($_ = <IN>) {
		($no,$item,$count) = split(/<>/, $_);
		print "<tr><th><input type=checkbox name=del value=\"$no\"></th>";
		print "<td><b>$item</b></td><th>$count</th></tr>\n";
	}
	close(IN);

	print "</table>\n";
	print "<P><input type=submit value=\"メンテする\"><input type=reset value=\"リセット\">\n";
	print "</form></blockquote>\n";
	print "</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;

		# 回答情報
		if ($name eq 'no') { push(@ANS,$value); }

		# 削除情報
		if ($name eq 'del') { push(@DEL,$value); }

		$FORM{$name} = $value;
	}
	$mode = $FORM{'mode'};
	$item = $FORM{'item'};

	# 項目はS-JISコード変換
	&jcode'convert(*item,'sjis');
}

## --- HTMLヘッダ
sub header {
	$HEAD = 1; # ヘッダ表示フラグ

	print "Content-type: text/html\n\n";
	print <<"EOM";
<html>
<head>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
<STYLE type="text/css">
<!--
body, tr, td { font-size: 10pt }
-->
</STYLE>
<title>$title</title></head>
$body
EOM
}

## --- エラー処理
sub error {
	if ($_[1] eq "lock" && -e $lockfile) { unlink($lockfile); }
	if (-e $tmpfile) { unlink($tmpfile); }

	if ($HEAD eq "") { &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;
}

## --- ロックファイル（symlink関数）
sub lock1 {
	local($retry) = 5;
	while (!symlink(".", $lockfile)) {
		if (--$retry <= 0) { &error("LOCK is BUSY","lock"); }
		sleep(1);
	}
}

## --- ロックファイル（open関数）
sub lock2 {
	local($flag) = 0;
	foreach (1 .. 5) {
		if (-e $lockfile) { sleep(1); }
		else {
			open(LOCK,">$lockfile") || &error("Write Error : $lockfile","lock");
			close(LOCK);
			$flag = 1;
			last;
		}
	}
	if ($flag == 0) { &error("LOCK is BUSY","lock"); }
}

## --- 桁区切り
sub filler {
	local($_) = $_[0];
	1 while s/(.*\d)(\d\d\d)/$1,$2/;
	return $_;
}
