#!/usr/bin/perl

;##########################################################################
;#
;# WebFORM v4.4 <フリーソフト>
;#
;#  (c)CGI-RESCUE
;#  http://www.rescue.ne.jp/
;#
;# Hostory
;# 06/Jun/1998 v3.0 セキュリティ強化
;# 08/Aug/1998 v3.1 カーボンコピー処理改善
;# 29/Oct/1998 v4.0 カーボンコピー処理はセキュリティの問題で廃止
;# 16/Feb/2006 v4.1 スパムに対する脆弱性を修正
;# 08/Jul/2006 v4.2 スパムに対する脆弱性を修正(v4.1の修正ミスを修正)
;# 13/Nov/2006 v4.3 スパムメール防止機能を追加（スパムキー機能）
;# 18/Jan/2007 v4.4 スパムに対する脆弱性を修正、およびSENDMAILの誤作動データの置換処理
;#
;##########################################################################

#------ 初期設定 ----------------------------------------------------------

#■日本語コード変換ライブラリ
require './jcode.pl';

#■SENDMAILの設定
$sendmail = '/usr/sbin/sendmail';

#■受信先メールアドレス
$mailto = 'roxy@bea.hi-ho.ne.jp';

#■名称
$title = 'お問合わせ';

#■画面のボディ設定
$body = '<body bgcolor="#ffffff">';

#■記入者メールアドレス( name="email"の時 )未入力でも送信する  1:する 0:しない
#  メールアドレスはあくまでも記入者の申告であり、正しいかどうかは分かりません。
$mailcheck = 1;

#■タイトル欄に入力がない場合のデフォルト値
$subject = '- NO SUBJECT -';

#■スパムキー機能を使う場合のキーワード設定
#
#  画面に表示した単語、文章、文字列を入力させたり、それを画像にしたものを入力させる（目の不自由な方には対応できないことに留意）、
#  または質問の答えを書かせるなどして、このＣＧＩの送信機能を悪用して自動で送信してくるスパムを、
#  自動（ロボット）では処理できない段取りを挿入することにより防止する機能です。
#
#  スパムキー <input type="text" name="spam_key">
#
#  のように、｢name=｣を｢spam_key｣にして入力した内容は、ＣＧＩ内に設定したキーワードと
# 「一致」(半角・全角・大文字・小文字などは区別される)しなければ送信しないという機能です。
#  これを設定しても、ＣＧＩ内にキーワードを設定しない場合は設定エラーになります。キーワードを設定しても、フォームに設定しない場合は無視されます。
#  キーワードは '' の間に設定してください。例：'日本' 例：'123'

$spam_base_key = '';

#--------------------------------------------------------------------------

### 時刻取得
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
@mon_array = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
@wday_array = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
$date_now = sprintf("%s, %02d %s %04d %02d:%02d:%02d +0900 (JST)",$wday_array[$wday],$mday,$mon_array[$mon],$year +1900,$hour,$min,$sec); # JSTは日本標準時という意味です

### データ入力
if ($ENV{'REQUEST_METHOD'} ne "POST") { &error('エラー','標準入力 METHOD=POST でご利用ください.'); }
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
if ($buffer eq '') { &error('エラー','このプログラムは直接起動できません.','使い方を確認してください.'); }
$ref = &encTag($ENV{'HTTP_REFERER'});
$buffer2 = $ENV{'QUERY_STRING'};
if ($buffer2 ne '') { &error('エラー','標準入力 METHOD=POST でご利用ください.','または、クエリーにデータが検出されました.'); }

### デコード
@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;
	$name =~ tr/+/ /;
	$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;

	&jcode'convert(*name,'sjis'); &jcode'convert(*value,'sjis');

	#$value =~ s/http/"><s>te&st<\/s>/;#debug用

	if ($value =~ /\r\n/) { $value =~ s/\r//g; } # 改行コードをUNIX(\n)に統一
	elsif ($value =~ /\r/) { $value =~ s/\r/\n/g; }

	if ($name eq "location") { $lct = &encTag($value); }
	elsif ($name eq "c_copy" && $value eq "on") { $cc = "on"; }
	elsif ($name eq "no_check" && $value eq "on") { $nocheck = "on"; }
	elsif ($name eq "space_check" && $value eq "on") { $spcheck = "on"; }
	elsif ($name eq "no_check") { ; }
	elsif ($name eq "ref_url") { $ref_url = &encTag($value); }
	elsif ($name eq "ref_name") { $ref_name = &encTag($value); }
	elsif ($name eq "spam_key") { $spam_key = $value; $spam = 1; }
	elsif ($name eq "subject" && $value ne "") { $subject = &encTag($value); }
	elsif ($name eq "subject") { ; }
	elsif ($name eq "ref_page") { $ref = &encTag($value); }
	elsif ($name eq "password") {

		$password = $value;
		push(@DATA_N,$name);
		push(@DATA_V,$value);
	}
	else {
		if ($name =~ /^email/i || $name =~ /^e\-mail/i) {

			$value =~ s/　/ /g;
			if ($value =~ / / || $value =~ /;/) { $value = ""; }
			if (!($value =~ /(.*)\@(.*)\.(.*)/)) { $value = ""; }

			$email = $value;
		}

		push(@DATA_N,$name);
		push(@DATA_V,$value);

		$name = &encTag($name);
		$value = &encTag($value);
		push(@DATA_NS,$name);
		push(@DATA_VS,$value);
	}
}

### 入力チェック
$ref =~ s/\n|\r//g; # 汚染チェック
$lct =~ s/\n|\r//g; # 汚染チェック
if (!$mailcheck && $email eq '') { &error('エラー','Ｅメールを入力してください.'); }
if ($mailcheck && $email eq '') { $email = 'anonymous@on.the.net'; } # メール未記入でも送信する場合の仮メールアドレス
if ($spcheck eq "on") {	foreach (@DATA_V) { if ($_ eq "") { &error('送信できません','受信者の意向により、全ての項目を埋めないと送信できません.'); } }}
if ($mailto eq '' || !($mailto =~ /(.*)\@(.*)\.(.*)/)) { &error('設定ミス','受信先メールアドレスが設定されていません.'); }
if ($spam_base_key eq '' && $spam) { &error('設定ミス','スパムキー用のキーワードが設定されていません.'); }
if ($spam_base_key ne '' && $spam_base_key ne $spam_key) { &error('送信できません','画面に書かれていることに従ってキーワードを入力してください.'); }
if ($nocheck eq "on") { &sendmail; } # 確認画面を出さずに送信へ

### 内容確認画面出力
print "Content-type: text/html\n\n";
print <<"EOF";
<html>
<head>
<title>$title</title>
<META HTTP-EQUIV=Content-Type CONTENT="text/html; charset=Shift_JIS">
</head>
$body
<h1>内容確認</h1>
<form method="POST" action="webform.cgi">
<blockquote>
<table border=0 cellpadding=3 cellspacing=3>
<tr><td bgcolor="#ffcccc"><b><font size=+1>項目</font></b></td><td bgcolor="#ffcccc"><b><font size=+1>内容</font></b></td></tr>
EOF

$count = @DATA_NS;

foreach (0..$count-1) {

	print "<input type=hidden name=\"$DATA_NS[($_)]\" value=\"$DATA_VS[($_)]\">\n";
	print "<tr><td bgcolor=\"#ffeedd\">$DATA_NS[($_)] <br></td>";

	if ($DATA_VS[($_)] =~ /\n/) { print "<td bgcolor=\"#ffffff\"><pre>$DATA_VS[($_)]</pre></td></tr>\n"; }
	else { print "<td bgcolor=\"#ffffff\">$DATA_VS[($_)]</td></tr>\n"; }
	print "</td></tr>\n";
}

print "</table></blockquote><p>\n";

print "<input type=hidden name=\"no_check\" value=\"on\">\n";
print "<input type=hidden name=\"ref_page\" value=\"$ref\">\n";

if ($lct ne "") { print "<input type=hidden name=\"location\" value=\"$lct\">\n"; }
if ($cc eq "on") { print "<input type=hidden name=\"c_copy\" value=\"on\">\n"; }
if ($ref_url ne "") { print "<input type=hidden name=\"ref_url\" value=\"$ref_url\">\n"; }
if ($ref_name ne "") { print "<input type=hidden name=\"ref_name\" value=\"$ref_name\">\n"; }
if ($subject ne "") { print "<input type=hidden name=\"subject\" value=\"$subject\">\n"; }
if ($password ne "") { print "<input type=hidden name=\"password\" value=\"$password\">\n"; }
if ($spam_key ne "") { print "<input type=hidden name=\"spam_key\" value=\"$spam_key\">\n"; }

if ($email eq '' || $email =~ /\,/) { print "<font size=+2><b>メールアドレスを正しく１つ入力しないと送信できません</b></font><p>\n"; }
else { print "<input type=submit value=\"  送 信  \"><p>\n"; }

print "</form><p><hr>\n";
print "<i>送信先：<a href=\"mailto:$mailto\">$mailto</a><i>\n";
print "<p></body></html>\n";
exit;

sub sendmail {

	$email =~ s/\n//g; # 汚染チェック
	if (length($email) > 255) { &error('エラー','メールアドレスの長さ制限は255バイトまでです.'); }
	if ($email =~ /\,/) { &error('エラー','メールアドレスを正しく１つ入力しないと送信できません.'); }

	$subject =~ s/\n//g; # 汚染チェック
	if (length($subject) > 255) { &error('エラー','メール題名の長さ制限は255バイト(全角はその半分)までです.'); }

	$host = $ENV{'REMOTE_HOST'};
	$addr = $ENV{'REMOTE_ADDR'};
	if ($host eq "" || $host eq $addr) { $host = gethostbyaddr(pack('C4',split(/\./,$host)),2) || $addr; }

	if (!(open(OUT,"| $sendmail -t"))) { &error('システム異常','申し訳ありませんが何らかの原因で処理できません.'); }

	print OUT "X-Mailer: WebFORM v4.4 by CGI-RESCUE\n";
	print OUT "X-HTTP-User-Agent: " . &encTag($ENV{'HTTP_USER_AGENT'}) . "\n";
	print OUT "X-Remote-host: $host \[$addr\]\n";
	$Ref = &decTag($ref); print OUT "X-HTTP-REFERER: $Ref\n";
	print OUT "Errors-To: $mailto\n";
	print OUT "To: $mailto\n";
	print OUT "From: $email\n";
	$Subject = &decTag($subject); &jis("Subject: $Subject"); print OUT "$msg\n";
	print OUT "Date: $date_now\n";
	print OUT "Content-Transfer-Encoding: 7bit\n";
	print OUT "Content-Type: text/plain\; charset=\"ISO-2022-JP\"\n\n";

	&jis("--- ここから ---"); print OUT "$msg\n\n";

	$count = @DATA_N;
	foreach (0..$count-1) {

		if ($DATA_V[$_] =~ /\n/) { &jis("$DATA_N[$_] =\n\n$DATA_V[$_]\n"); print OUT "$msg\n"; }
		else { &jis("$DATA_N[$_] = $DATA_V[$_]"); print OUT "$msg\n"; }
	}

	&jis("--- ここまで ---"); print OUT "\n$msg\n";

	close(OUT);

	if ($cc eq "on" && $lct ne '') {

		print "Content-type: text/html\n\n";
		print "<html><head><title>$title</title>\n";
		print "<META HTTP-EQUIV=Content-Type CONTENT=\"text/html; charset=Shift_JIS\"></head>\n";
		print "$body\n";
		print "<h1>送信完了</h1>\n";
		print "ただ今<a href=\"mailto:$mailto\">$mailto</a>宛てに送信された内容は以下の通りです.<br>\n";
		print "内容の写しとしてお控えください.<p>\n";
		print "<form>\n";
		print "<blockquote>\n";
		print "<textarea cols=70 rows=20>";
		&cc;
		print "</textarea></form></blockquote><p>\n";
		print "<h3>[<a href=\"$lct\" target=\"_top\">コピーしたら次へ</a>]</h3>";
	}
	elsif ($cc eq "on") {

		print "Content-type: text/html\n\n";
		print "<html><head><title>$title</title>\n";
		print "<META HTTP-EQUIV=Content-Type CONTENT=\"text/html; charset=Shift_JIS\"></head>\n";
		print "$body\n";
		print "<h1>送信完了</h1>\n";
		print "ただ今<a href=\"mailto:$mailto\">$mailto</a>宛てに送信された内容は以下の通りです.<br>\n";
		print "内容の写しとしてお控えください.<p>\n";
		print "<form>\n";
		print "<blockquote>\n";
		print "<textarea cols=70 rows=20>";
		&cc;
		print "</textarea></form></blockquote><p>\n";
		if ($ref_url ne '' && $ref_name ne '') { &jcode'convert(*ref_name,'sjis'); print "<h3>[<a href=\"$ref_url\" target=\"_top\">$ref_name</a>]</h3>"; }
		print "</body></html>\n";
	}
	elsif ($lct ne '') { print "Location: $lct\n\n"; }
	else {
		print "Content-type: text/html\n\n";
		print "<html><head><title>$title</title>\n";
		print "<META HTTP-EQUIV=Content-Type CONTENT=\"text/html; charset=Shift_JIS\"></head>\n";
        	print "$body\n";
		print "<H1>送信完了</H1>\n";
		print "ご記入されたものは<a href=\"mailto:$mailto\">$mailto</a>宛てに電子メールされました.<br>\n";
		print "Thank you for sending comments to $mailto .<p>\n";
		if ($ref_url ne '' && $ref_name ne '') { &jcode'convert(*ref_name,'sjis'); print "<h3>[<a href=\"$ref_url\" target=\"_top\">$ref_name</a>]</h3>"; }
		print "<p></body></html>\n";
	}
	exit;
}

sub cc {

	print "Date: $date_now\n";
	print "To: $mailto\n";
	print "Subject: $subject\n\n";

	foreach (0..$count-1) {

		if ($DATA_VS[$_] =~ /\n/) { print "$DATA_NS[$_] =\n\n$DATA_VS[$_]\n"; }
		else { print "$DATA_NS[$_] = $DATA_VS[$_]\n"; }
	}
}

sub jis {

	$msg = $_[0];
	local(@msg);

	@msg = split(/\n/,$msg);
	foreach $i (0..$#msg) {

		if ($msg[$i] eq '.') { splice(@msg,$i,1,'..'); }
	}

	$msg = join("\n",@msg);

	&jcode'convert(*msg, 'jis');
}

sub encTag {

	local($line) = $_[0];
	$line =~ s/"/&quot;/g;
	$line =~ s/</&lt;/g;
	$line =~ s/>/&gt;/g;
	$line;
}

sub decTag {

	local($line) = $_[0];
	$line =~ s/&quot;/"/g;
	$line =~ s/&lt;/</g;
	$line =~ s/&gt;/>/g;
	$line;
}

sub error {

	print "Content-type: text/html\n\n";
        print "<html><head><title>$title</title>\n";
	print "<META HTTP-EQUIV=Content-Type CONTENT=\"text/html; charset=Shift_JIS\"></head>\n";
        print "$body\n";
        print "<h1>$_[0]</h1>\n";
	print "<h3>$_[1]</h3>\n";

	if ($ref eq '') {

		print "※ フォームページが取得できません.<br>\n";
		print "※ ブラウザの[戻る]ボタンを押して前の画面に移動してください.<p>\n";
	}
	else {

		print "※ フォームページ　<a href=\"$ref\">$ref</a><br>\n";
		print "※ フォームページへ戻るか、ブラウザの[戻る]ボタンを押して前の画面に移動してください.<p>\n";
	}

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