#!/usr/bin/perl

################################################################################
# 
# 汎用メールフォーム pgdmailform.cgi
# PGD WORKS by Akira Motojima
# http://pgd.jp/
# 
# 
#-------------------------------------------------------------------------------
# 
# ○ 動作環境
# Perl5
# /usr/sbin/sendmail が使えること 
# モジュール HTML::Template, Jcode が動作すること 
# モジュール HTML::Template, Jcode が動作すること 
# 
#-------------------------------------------------------------------------------
# 
# ○ 設定
# 
# ./lib/pgdmailform_config.cgi を編集してください。
# 詳細はファイル中のコメントを参照
# 
#-------------------------------------------------------------------------------
# 
# ○ 実行
# 
# http://-------/****/pgdmailform.cgi
# 別テンプレートで実行の場合は
# http://-------/****/pgdmailform.cgi?type=TYPE
# 
#-------------------------------------------------------------------------------
# 
# ○ テンプレートの設置
# 
# ./template/default/ タイプが指定されていなければこちらが利用される
# ./template/TYPE/    タイプが指定されている場合
#                     但しファイルがなければdefaultのファイルが利用される(mail.txtを除く)
# 
# テンプレートの書式については ./template/default/form.html 中のコメントを参照
# 
#-------------------------------------------------------------------------------
# 
# ○ 履歴
# 
# 2008/05/25 Unicode::Japanese が有ればメール送信時のjis変換をJcodeを代替するようにした
# 2008/04/28 修正
# 2008/03/13 作成
# 
################################################################################


##### require

use lib './lib/';
use strict;

use CGI qw/:standard/;
use CGI::Carp qw(fatalsToBrowser set_message); set_message(' ');
use HTML::Template;
use Jcode;

require 'pgdmailform_common.cgi';
require 'pgdmailform_config.cgi';
require 'pgdmailform_sendmail.cgi';
require 'pgduserinfo.cgi';


##### run

my $in = new CGI;
my %in;
foreach my $key ($in->param) {
	my @list = $in->param($key);
	$in{$key} = join('/',@list);
}

# フォームタイプの取得
my $type = $in{'type'};
if ($type eq '') { $type = 'default';}
if (!$PgdMailFormConfig::type_available{$type}) { die("このフォームは現在利用できません。");}

# 遷移状態の取得
my $mode = $in{'mode'};
delete $in{'mode'}; # 引数のhiddenによるまとめ渡しから除外する

if ($mode eq 'check') {
	&check_and_send;
} elsif ($mode eq 'send') {
	&check_and_send;
} else {
	&form;
}

exit;


##### routine

sub form {
	
	my ($form_value,$error_list) = @_;
	
	# html テンプレート
	my $html_template_file = $PgdMailFormCommon::template_dir . $type . '/' . $PgdMailFormCommon::template_form;
	
	# テンプレートが無ければデフォルトテンプレートを利用する
	if (!-e $html_template_file) { $html_template_file = $PgdMailFormCommon::template_dir . 'default/' . $PgdMailFormCommon::template_form;}
	
	# テンプレートの選択
	my $tmpl = HTML::Template->new(
		'die_on_bad_params' => 0,
		'filename' => $html_template_file,
	);
	
	# HTMLテンプレート パラメータ
	$tmpl->param(
		'type' => $type,
		'error_count' => scalar keys %{$error_list},
	);
	
	# 初期代入値、エラー値をテンプレートに引き渡す
	foreach my $key (keys %{$form_value}) {
		
		# input/textarea用
		$tmpl->param($key => %{$form_value}->{$key});
		
		# select/radio/checkbox用 値はURLエンコードを行う
		my $keystr = %{$form_value}->{$key};
		$keystr =~ s/([^a-zA-Z0-9_.!~*'()-])/'%'.unpack('H2',$1)/eg;
		$keystr = $key . '-' . $keystr;
		$tmpl->param($keystr => 1);
		
	}
	foreach my $key (keys %{$error_list}) { $tmpl->param("error-$key" => %{$error_list}->{$key});}
	
	# 環境変数をテンプレートに送る
	$tmpl->param(%ENV);
	
	print "Content-Type: text/html\n\n";
	print $tmpl->output();
	
}


sub check_and_send {
	
	# 必須項目一覧の取得
	my @required_list = split(/[^\w\-\_]+/,$in{'required'});
	my %required_list;
	foreach my $key (@required_list) {
		if ($key =~ /^[\w\-\_]+$/) {
			$required_list{$key} = 1;
		}
	}
	
	my @loop_list = ();
	my %form_value;
	my %error_list;
	foreach my $key (keys %in) {
		
		if ($key eq '') { next;}
		
		# 値、キーのサイズのチェック
		if (length $in{$key} > $PgdMailFormCommon::max_size || length $key > $PgdMailFormCommon::max_size) {
			$error_list{$key} = 1;
		}
		
		# フォーマットチェック
		if ($in{$key} ne '') {
			if (($key =~ /^zip$/i || $key =~ /^zip[^12].+/i) && $in{$key} !~ /^\d{3}\-?\d{4}$/) { $error_list{$key} = 1;}
			if ($key =~ /^zip1/i && $in{$key} !~ /^\d{3}$/) { $error_list{$key} = 1;}
			elsif ($key =~ /^zip2/i && $in{$key} !~ /^\d{4}$/) { $error_list{$key} = 1;}
			if ($key =~ /^(tel|fax)/i && $in{$key} !~ /^\d[\d\-]+\d$/) { $error_list{$key} = 1;}
			if ($key =~ /^email/i && $in{$key} !~ /^[\w\.\-\_\,\/\?\+]+\@\w+[\w\-\.]+\.[\w\-\.]+\w$/) { $error_list{$key} = 1;}
		}
		
		# 特例エラーチェック
		if ($key eq 'email2' && $in{'email2'} ne $in{'email'}) { $error_list{$key} = 1;}
		#elsif ($key eq 'age' && $in{$key} ne '' && $in{$key} < 10) { $error_list{$key} = 1;}
		
		if ($in{$key} ne '') {
			
			# 値の格納 loop用
			my %row_data;
			$row_data{'key'} = $key;
			$row_data{'value'} = $in{$key};
			push(@loop_list,\%row_data);
			
			$form_value{$key} = $in{$key};
			
		}
		
	}
	
	# 必須項目のチェック
	foreach my $key (keys %required_list) {
		
		my $error_flg = 0;
		
		# まず値がなければエラーとする
		if ($in{$key} eq '') {
			$error_flg = 1;
		}
		
		# checkbox の場合の key-数字 に値が一つでもあればエラーを解除
		foreach my $key_in (keys %in) {
			if ($key_in !~ /^$key\-\d+$/) { next;}
			if ($in{$key_in} ne '') { $error_flg = 0;}
		}
		
		# エラーだった場合テンプレートに出力
		if ($error_flg) {
			$error_list{$key} = 1;
		}
		
	}
	
	# エラーが有る場合はフォームに差し戻す
	if (scalar keys %error_list != 0) {
		&form(\%form_value,\%error_list);
		exit;
	}
	
	# checkモードの場合確認画面を表示する
	if ($mode eq 'check') {
		
		# html テンプレート
		my $html_template_file = $PgdMailFormCommon::template_dir . $type . '/' . $PgdMailFormCommon::template_check;
		
		# テンプレートが無ければデフォルトテンプレートを利用する
		if (!-e $html_template_file) { $html_template_file = $PgdMailFormCommon::template_dir . 'default/' . $PgdMailFormCommon::template_check;}
		
		# テンプレートの選択
		my $tmpl = HTML::Template->new(
			'die_on_bad_params' => 0,
			'filename' => $html_template_file,
		);
		
		# HTMLテンプレート パラメータ
		$tmpl->param('loop_list' => \@loop_list);
		
		# 入力された情報をテンプレートに出力
		$tmpl->param(%form_value);
		
		# 環境変数をテンプレートに送る
		$tmpl->param(%ENV);
		
		print "Content-Type: text/html\n\n";
		print $tmpl->output();
		
	# sendモードの場合メールを送信する
	} elsif ($mode eq 'send') {
		
		# ユーザ情報全般の取得
		my %userinfo = ();
		&Userinfo::GetUserInfo(\%userinfo);
		
		##### メールの送信
		
		# メールテンプレート
		# タイプに対応するメールテンプレートが無い場合は設置忘れと見なしてデフォルトテンプレートを呼び出さずエラーとする
		my $mail_template_file = $PgdMailFormCommon::template_dir . $type . '/' . $PgdMailFormCommon::template_mail;
		
		# テンプレートが無ければエラー
		if (!-e $mail_template_file) { die('メールテンプレートが設置されていません。');}
		
		# テンプレートの選択
		my $mail = HTML::Template->new(
			'die_on_bad_params' => 0,
			'filename' => $mail_template_file,
		);
		
		# HTMLテンプレート パラメータ
		$mail->param(
			'loop_list' => \@loop_list,
		);
		
		# 入力された情報をテンプレートに出力
		$mail->param(%form_value);
		
		# ユーザ情報をテンプレートに出力
		foreach my $key (keys %userinfo) { $mail->param("userinfo-$key" => $userinfo{$key});}
		
		# 環境変数をテンプレートに送る
		$mail->param(%ENV);
		
		# メール送信先のセレクト
		if (!$PgdMailFormConfig::mail_to{$type}) { $PgdMailFormConfig::mail_to{$type} = $PgdMailFormConfig::mail_to{'default'};}
		if (!$PgdMailFormConfig::mail_cc{$type}) { $PgdMailFormConfig::mail_cc{$type} = $PgdMailFormConfig::mail_cc{'default'};}
		
		my %maildata = (
			'From' => $in{'email'},
			'To' => $PgdMailFormConfig::mail_to{$type},
			'Cc' => $PgdMailFormConfig::mail_cc{$type},
			'Bcc' => $PgdMailFormConfig::mail_bcc{$type},
			'Subject' => $PgdMailFormConfig::mail_subject{$type},
			'Return-Path' => '',
			'Data' => $mail->output(),
		);
		
		# Unicode -> JIS 文字化け対策置換
		if ($PgdMailFormConfig::utf8_char_fix) {
			
			# フォーム画面のhtmlテンプレート
			my $html_template_file = $PgdMailFormCommon::template_dir . $type . '/' . $PgdMailFormCommon::template_form;
			
			# テンプレートが無ければデフォルトテンプレートを利用する
			if (!-e $html_template_file) { $html_template_file = $PgdMailFormCommon::template_dir . 'default/' . $PgdMailFormCommon::template_form;}
			
			open(FILE,$html_template_file);
			flock(FILE,1);
			my @template_text = <FILE>;
			flock(FILE,8);
			close(DATA);
			
			my $template_text = join('',@template_text);
			
			# UTF8で有れば置換を行う
			if(Jcode::getcode($template_text) eq 'utf8') {
				
				foreach my $key (keys %maildata) {
					
					$maildata{$key} =~ s/\xEF\xBD\x9E/\xE3\x80\x9C/g;	# チルダ EFBD9E E3809C
					$maildata{$key} =~ s/\xEF\xBC\x8D/\xE2\x88\x92/g;	# ハイフン EFBC8D E28892
					$maildata{$key} =~ s/\xE2\x88\xA5/\xE2\x80\x96/g;	# 平行記号 E288A5 E28096
					
				}
				
			}
			
		}
		
		# メール送信
		&PgdMailFormSendmail::sendmail(\%maildata) or die("メールの送信に失敗しました [$@]");
		
		##### 送信者向け自動返答メールの送信
		
		# メールテンプレート
		my $mail_sender_template_file = $PgdMailFormCommon::template_dir . $type . '/' . $PgdMailFormCommon::template_mail_sender;
		
		# テンプレートがある場合のみ送信
		if (-e $mail_sender_template_file) {
			
			# テンプレートの選択
			my $mail_sender = HTML::Template->new(
				'die_on_bad_params' => 0,
				'filename' => $mail_sender_template_file,
			);
			
			# HTMLテンプレート パラメータ
			$mail_sender->param(
				'loop_list' => \@loop_list,
			);
			
			# 入力された情報をテンプレートに出力
			foreach my $key (keys %form_value) {
				
				$mail_sender->param($key => $form_value{$key});
				
				# 変数名にエンコードした値を付けてテンプレートに出力(TMPL_IF判定用)
				my $keystr = $form_value{$key};
				$keystr =~ s/([^a-zA-Z0-9_.!~*'()-])/'%'.unpack('H2',$1)/eg;
				$keystr = $key . '-' . $keystr;
				$mail_sender->param($keystr => 1);
				
			}
			
			# ユーザ情報をテンプレートに出力
			foreach my $key (keys %userinfo) { $mail_sender->param("userinfo-$key" => $userinfo{$key});}
			
			# 環境変数をテンプレートに送る
			$mail_sender->param(%ENV);
			
			# メールFromのセレクト mail_sender_to が設定されていればそちらを、されていなければ送信先メールアドレスをFromにセット。
			my $mail_from;
			if ($PgdMailFormConfig::mail_sender_to{$type}) {
				$mail_from = $PgdMailFormConfig::mail_sender_to{$type};
			} else {
				$mail_from = $PgdMailFormConfig::mail_to{$type};
			}
			
			my %maildata = (
				'From' => $mail_from,
				'To' => $in{'email'},
				'Subject' => $PgdMailFormConfig::mail_sender_subject{$type},
				'Return-Path' => '',
				'Data' => $mail_sender->output(),
			);
			
			# メール送信
			&PgdMailFormSendmail::sendmail(\%maildata) or die("メールの送信に失敗しました [$@]");
		
		}
		
		##### 送信完了画面出力
		
		# html テンプレート
		my $html_template_file = $PgdMailFormCommon::template_dir . $type . '/' . $PgdMailFormCommon::template_send;
		
		# テンプレートが無ければデフォルトテンプレートを利用する
		if (!-e $html_template_file) { $html_template_file = $PgdMailFormCommon::template_dir . 'default/' . $PgdMailFormCommon::template_send;}
		
		# テンプレートの選択
		my $tmpl = HTML::Template->new(
			'die_on_bad_params' => 0,
			'filename' => $html_template_file,
		);
		
		# 入力された情報をテンプレートに出力
		$tmpl->param(%form_value);
		
		# 環境変数をテンプレートに送る
		$tmpl->param(%ENV);
		
		print "Content-Type: text/html\n\n";
		print $tmpl->output();
		
	} else {
		
		die('mode が正しくありません。');
		
	}
	
}
