#!/usr/local/bin/perl

#--------------------------
# Generic Apply Collecter
#--------------------------

use Lib::WebReq;
use Lib::Templet;
use Lib::StrCodec;
#use Lib::StrCodecOS;		# 社外提供用（バイナリ販売の場合はこちらをStrCodecモジュールとすること）
use Lib::CsvParse;
use Lib::ConfParse;
use Lib::NetDeal;
use Lib::FileClerk;
use Lib::Appraise;

#-----------------------------------------------------------------------------------------------------------------------
#    gac.cgi … 初期バージョン
#
# gac-1a.cgi … データファイル書き出し項目の別ファイル化対応
#
# gac-1b.cgi … パックデータによる初期パラメータ受取り機能
#　　　　　　　　　→ メールを中継した処理に対応するため
#　　　　　　　　　→→ 生成されるURLが長すぎるため、破棄
#
# gac-1c.cgi … 外部プログラム（メールや他CGI）を中継した処理に対応
#　　　　　　　　　→ テンポラリファイルを生成する方式に変更
#
# gac-1d.cgi … 選択型フォームタグ（radio、checkbox、select）対応
#
# gac-1e.cgi … リカバリログ機能、一括エラーメッセージ、ファイル未出力データ確認機能対応
#
# gac-1f.cgi … データ検索機能、全角文字列チェック機能
#
# gac-1g.cgi … ユニークコード生成機能
#
# gac-1h.cgi … 空フォーム補完機能、管理情報の暗号化、期間ダウンロード機能
#
# gac-1i.cgi … フロー分岐機能、chekbox未選択チェック用の項目連結機能、レイアウト確認機能
#
# gac-1j.cgi … 選択型フォームチェック機能、チェック項目ソート機能
#
# gac-1k.cgi … 稼動期間指定機能の拡張、空フォーム補完機能の拡張、携帯メールチェック機能、
#					入力文字数制限機能、売り切り用稼動期間制限機能
#
# gac-1l.cgi … ファイル名が読みにくいので欠番
#
# gac-1m.cgi … 環境変数取り込み機能、連結機能のバグフィックス
#
# gac-1n.cgi … 反復部展開指定機能、configからのリクエストパラメータ追加機能、パラメータ関係のバグフィックス
#
# gac-1o.cgi … ファイル名が読みにくいので欠番
#
# gac-1p.cgi … データ保存パスの変更機能
#
# gac-1q.cgi … checkbox選択結果反映支援機能
#
#　　　（予定） EUCコード対応（しないかも）、申し込み数チェック機能、インラインスクリプト機能
#
#-----------------------------------------------------------------------------------------------------------------------


	%reqHash;				# リクエストパラメータを格納するハッシュ
	%confHash;				# 設定情報を格納するハッシュ

	%CsvFields;				# CSVのフィールド情報を格納するハッシュ

	%CheckListSortInfo;		# チェック項目をソートする際に使用する順序情報

	@DenyDomainList;		# 受付を拒否するメアドのドメイン一覧（正規表現文字列）を格納する配列

	$TimeSerial = time;		# プログラム起動時の時間シリアル値


	&main();
	exit(0);


#---------------------------------------------------------------------
# メイン
#
#　　　長くなってキモチ悪い…。orz
#
sub main {

	my $eMess;
	my $rPage;

	my $ePage;
	my $exStr = '';

	my $flg;
	my $cnt;

	my $LockFlag;

	&WebReq::RequestParamToHash( \%reqHash );

#	$reqHash{$confHash{'Operate'}{'JumpTag'}} =~ s/^\s+|\s+$//g;



#	return if (&BestIfUsedBy( 2005,4,25 ) < 0);

		# ※強制サービス停止機能（バイナリ売り切り用）
		# 
		# 　稼動最終日を過ぎると真っ白い画面を出力する。
		# 
		# 　　　&BestIfUsedBy( 2005,4,25 )
		# 
		# 　のように指定した場合、2005年4月25日 23時59分59秒を過ぎるまで稼動する。
		# 
		# 　バイナリ化したものを売り切る場合にはコメントアウトを外し、
		# 　パラメータを再設定したうえでコンパイルすること。
		# 
		# 　　※ 動作テストを忘れずに。
		# 　　　 ~~~~~~~~~~~~~~~~~~~~~~

	&initialize();

	return if (&LayoutView() != 0);		# レイアウト閲覧モード

	$flg = &Download();

	return if ($flg == 0);

	if ($flg < 0) {		# 致命的エラー

		&WebReq::PrintContentType();
		&WebReq::PrintErrorPage('GAC: Fatal error','データの取り出しに失敗しました。');
		return;

	}

	&InOperateTerm();	# 稼動期間チェック



	&FlowBranch();	# フロー分岐処理

	if (&ParamErrorCheckMulti( \$ePage,\$exStr,$reqHash{$confHash{'Operate'}{'JumpTag'}} ) > 0) {		# 一括パラメータチェック

		$reqHash{$confHash{'Operate'}{'JumpTag'}} = $ePage;
	}

	if (&ParamErrorCheckSingle( \$ePage,$reqHash{$confHash{'Operate'}{'JumpTag'}} ) > 0) {				# 単項目パラメータチェック

		$reqHash{$confHash{'Operate'}{'JumpTag'}} = $ePage;
	}

	$LockFlag = NecessityCheckForFileLock();

	if ($LockFlag != 0) {
		if (LockupFile() < 0) {	# ファイルをロックする

			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error','ファイルのロックに失敗しました。');
			return;
		}
	}


	if (($LockFlag & 2) != 0) {		# 中継用テンポラリデータファイル処理

		if (&InsertRecordToLeapTemporally() < 0){

			&FileClerk::Unlock();

			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error','テンポラリデータファイルの処理に失敗しました。');
			return;
		}
	}

	if (($LockFlag & 1) != 0) {		# データを保存するページの場合

		if (&CreateSerialCode() < 0) {	# シリアルコード生成

			&FileClerk::Unlock();

			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error','シリアルコードの生成に失敗しました。');
			return;
		}


		if ($confHash{'Operate'}{'Mode'} eq 'wCheck') {		# デバッグモード（書き出されていないパラメータの一覧を表示）

			&FileClerk::Unlock();

			&PrintWriteParamCheckPage();
			return;
		}


		if (&AppendRecoveryLog() < 0) {		# リカバリ用ログの出力

			&FileClerk::Unlock();

			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error','ログの出力に失敗しました。');
			return;
		}


		if (&WriteToDataFile() < 0) {		# データ書き出し

			&FileClerk::Unlock();

			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error','データの出力に失敗しました。');
			return;
		}
	}


	if (($LockFlag & 4) != 0) {		# データの検索結果を表示するページの場合

		$flg = &SearchDataToReqHash();

		if ($flg <= 0) {

			&FileClerk::Unlock();
			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error',"データの検索に失敗しました($flg)。");
			return;
		}
	}

	if (($LockFlag & 8) != 0) {		# ユニークコードの生成


		$cnt = &FileClerk::IncreaseCounterModeMAGI( ''.&GetDataStorageFolderPath().'/counter/Uniq' );		# ユニークコード用カウンタを取り出す

		if ($cnt < 0) {
			&FileClerk::Unlock();
			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error',"ユニークコードの生成に失敗しました($cnt)。");
			return;
		}

		$reqHash{$confHash{'Serial'}{'Unique'}} = &StrCodec::CreateAttestCode( $cnt );	# ユニークコードを生成
	}


	&FileClerk::Unlock() if ($LockFlag != 0);


	if (&SendMailByScreen( $reqHash{$confHash{'Operate'}{'JumpTag'}} ) < 0) {	# メールを送信する

			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error','メール送信に失敗しました。');
			return;
	}


	&GetRepetitionInfoFromConfig( \$exStr,$reqHash{$confHash{'Operate'}{'JumpTag'}} );

	&WebReq::PrintContentType();
#&WebReq::PrintErrorPage('GAC: Debug',$exStr);



	&PrintScreen( $reqHash{$confHash{'Operate'}{'JumpTag'}},$exStr );
}


#-------------------------------------------------------------------------------
# 初期化
#
sub initialize {

	my $confgPath;
	my @dtType = (	'STRINGDATE',	'STRINGTIME' );

	my $ecd;

	if ( $reqHash{'CoName'} eq '') {

		&WebReq::PrintContentType();
		&WebReq::PrintErrorPage('GAC: Fatal error','コンテンツ名を指定してください。');
		return(-1);
	}

	$confgPath = './data/'.$reqHash{'CoName'}.'/default.conf';

	if (&ConfParse::ReadConfigFile( \%confHash,$confgPath ) < 0) {

		&WebReq::PrintContentType();
		&WebReq::PrintErrorPage('GAC: Fatal error','設定ファイルが読み込めません。');
		return(-1);
	}

	&ReadDenyDomainListFile();	# 受付禁止ドメイン（メアド）の読み込み


	($NetDeal::OperateMode = -1) if ($confHash{'Operate'}{'Mode'} eq 'test');	# テスト動作モード


	if ($reqHash{ $confHash{'Leap'}{'Tag'} } ne '') {		# 外部プログラムによる中継処理の対応

		$ecd = &ExtendLeapTemporallyToHash( \%reqHash,$reqHash{ $confHash{'Leap'}{'Tag'} } );

		if ($ecd == 1) {		# 該当データなし

			$reqHash{$confHash{'Operate'}{'JumpTag'}} = $confHash{'Leap'}{'ErrorPage'};
			$reqHash{$confHash{'Leap'}{'Tag'}} = '';

		} elsif ($ecd < 0) {	# 読み出し／データ展開エラー

			&WebReq::PrintContentType();
			&WebReq::PrintErrorPage('GAC: Fatal error','中継ファイルからデータが取得できません。');
			return(-1);
		}
	}

	&ConfParse::GetServerInfoToHash( \%confHash,'Server','' );

	&ExtendCsvFieldInfo();

	if (&ExtentCryptSeed() < 0) {

		&WebReq::PrintContentType();
		&WebReq::PrintErrorPage('GAC: Fatal error','簡易暗号化パラメータを確認してください');
		return(-1);
	}

	$reqHash{'hostinfo'} = &NetDeal::IPaddrToRemoteHost();
	$reqHash{'useragent'} = &NetDeal::GetUserAgentString();

	($reqHash{'apply_date'},$reqHash{'apply_time'}) = &StrCodec::GetDateTimeString( \@dtType,$TimeSerial );


	if ($reqHash{$confHash{'Operate'}{'JumpTag'}} eq ''){		# 画面遷移キーワードが未定義の場合

		$reqHash{$confHash{'Operate'}{'JumpTag'}} = $confHash{'Operate'}{'DefScreen'};
	}

	if ($confHash{'Bundle'}{'Tag'} eq '') {		# パックデータの展開処理

		&WebReq::PrintContentType();
		&WebReq::PrintErrorPage('GAC: Fatal error','パックデータ関連の設定をしてください');
		return(-1);

	}

	if ($reqHash{ $confHash{'Bundle'}{'Tag'} } ne '') {
		&WebReq::UnpackParcel( \%reqHash,$reqHash{$confHash{'Bundle'}{'Tag'}} );		# パックしたリクエストパラメータを展開する
	}

	&GetEnvToRequestHash($reqHash{$confHash{'Operate'}{'JumpTag'}});			# 任意の環境変数取り込み
	&RequestParamToHashFromConfig($reqHash{$confHash{'Operate'}{'JumpTag'}});	# リクエストパラメータの設定ファイルからの追加

	&SubstituteEmptyForm();				# 空フォーム補完
	&RelationalFormSupplement();		# 関連フォーム補完
	&FlipFlopFormSupplement();			# 空文字列連動フォーム補完（主にcheckbox対応）

	&JoinRequestParam();	# 連結生成するリクエストパラメータの処理

	&PackRequestParam();	# でもってもいっぺんパックする

	&SetStatusToReqHashFromRadioOrPulldown('R');	# ラジオボタンの選択状態を次のページに伝えるための処理
	&SetStatusToReqHashFromRadioOrPulldown('P');	# プルダウンの選択状態を次のページに伝えるための処理
	&SetStatusToReqHashFromCheckBox();				# チェックボックスの選択状態を次のページに伝えるための処理

	$reqHash{'ScriptURL'} = $confHash{'Server'}{'Protocol'}.'://'.$confHash{'Server'}{'ServerName'}.$confHash{'Server'}{'ScriptURI'};
}


#-------------------------------------------------------------------------------
# 値の有無によって関連指定されたリクエストパラメータの値を設定する
#
sub FlipFlopFormSupplement {

	my $tHash;
	my $cbForm;

	my @ele;
	my $prm;

	$tHash = $confHash{'FlipFlop'};

	foreach $cbForm ( keys(%$tHash) ){

		@ele = split(/,/,$confHash{'FlipFlop'}{$cbForm});

		foreach $prm (@ele){
			&FlipFlopFormSupplement_sub( $cbForm,$prm );
		}
	}
}


sub FlipFlopFormSupplement_sub {

	my $cbn = $_[0];	# checkboxのフォーム名
	my $prm = $_[1];	# パラメータ文字列（ひとつぶん）

	my $obForm;
	my $exParam;
	my $vaParam;
	my $sjKeywd;

	return unless ($prm =~ /\s*(\S+)\s*\((.*)\|(.*)\)\s*@\s*(\S+)/);		# パラメータを展開

	$obForm  = $1;		# 設定を格納するリクエストパラメータ名
	$exParam = $2;		# 設定するパラメータ（値ありの場合）
	$vaParam = $3;		# 設定するパラメータ（値なしの場合）
	$sjKeywd = $4;		# 対象となる画面の遷移キーワード

	$exParam  =~ s/^\s+|\s+$//g;
	$vaParam  =~ s/^\s+|\s+$//g;

	return if ($obForm eq '');	# 格納するリクエストパラメータが指定されていない。

	return if ($sjKeywd ne $reqHash{$confHash{'Operate'}{'JumpTag'}});	# 該当出力画面ではない

	if ($reqHash{$cbn} ne '') {

		$reqHash{$obForm} = $exParam;
	} else {
		$reqHash{$obForm} = $vaParam
	}


}


#-------------------------------------------------------------------------------
# データ保存パスを生成する
#
#　戻り値
#　　データ保存ディレクトリのフルパス
#
sub GetDataStorageFolderPath {

	my $dfp  = $confHash{'DataFile'}{'Folder'};
	my $defa = './data/'.$reqHash{'CoName'};

	return( $defa ) if ($dfp eq '');	# 指定されていない
	return( $defa ) unless (-d $dfp);	# 指定されたディレクトリが存在しない

	return( $dfp );
}


#-------------------------------------------------------------------------------
# 設定情報で指定されたのリクエストパラメータをハッシュに展開する
#
#　※ 強制上書きなので注意のこと
#
#  書式：
#　　Bury = 画面遷移キーワード,キー文字列1:値文字列1,キー文字列2:値文字列2,…
#
sub RequestParamToHashFromConfig {

	my $npInfo	= $_[0];		# 画面遷移キーワード

	my @list;
	my $token;
	my $key;
	my $val;

	return unless (exists($confHash{'Bury'}{$npInfo}));

	@list = split(/,/,$confHash{'Bury'}{$npInfo});		# 画面に指定された追加リクエストパラメータを展開する

	foreach $token (@list){

		next unless ($token =~ /(\w+):(.+)/);

		$key = $1;
		$key =~ s/^\s+|\s+$//g;

		$val = $2;
		$val =~ s/^\s+|\s+$//g;

		$reqHash{$key} = $val;
	}

}


#-------------------------------------------------------------------------------
# 設定情報内の反復部展開情報を取り出す
#
#  書式：
#　　Repetition = 画面遷移キーワード:展開キーワード,展開数,オフセット数値
#
sub GetRepetitionInfoFromConfig {

	my $exstr	= $_[0];		# 展開情報文字列を追加するスカラー変数への参照
	my $npInfo	= $_[1];		# 画面遷移キーワード


	my $tHash;
	my $tKey;

	my @ele;
	my $np;
	my $rk;


	$tHash = $confHash{'Repetition'};

	foreach $tKey ( keys(%$tHash) ){

		undef @ele;

		next unless ($tKey =~ /(\w+):(\w+)/);

		$np = $1;
		$rk = $2;

		@ele = split(/,/,$confHash{'Repetition'}{$tKey});

		next if ($np ne $npInfo);

		($$exstr .= ';') if (length($$exstr) > 0);

		$$exstr .= ($rk.','.$ele[0].','.$ele[1]);
	}
}



#-------------------------------------------------------------------------------
# レイアウト閲覧モード
#
#　戻り値
#　　 1：表示した
#　　 0：表示しなかった
#
sub LayoutView {

	my $lscr = $reqHash{'Layout'};
	my $exStr = '';

	return(0) if ($confHash{'Screen'}{$lscr} eq '');	# 該当ページなし

	$reqHash{'ScriptURL'} = '#';	# 次ページへジャンプできないようにしてしまう

	&WebReq::PrintContentType();
	&PrintScreen( $lscr,$exStr );

	return(1);
}


#-------------------------------------------------------------------------------
# フロー分岐キーワードをチェックして次に出力する画面遷移キーワードを設定する
#
#　戻り値
#　　 1：変更した
#　　 0：変更しなかった
#
sub FlowBranch {

	my $npage = $reqHash{$confHash{'Operate'}{'JumpTag'}};

	my @brList;
	my $jcTag;

	my $key;
	my $scr;

	my $flg = 0;

	return(0) if ($confHash{'FlowBranch'}{$npage} eq '');		# 分岐指定ページではない

	@brList = split(/,/,$confHash{'FlowBranch'}{$npage});

	$jcTag = shift(@brList);	# 分岐キーワードを格納しているリクエストパラメータ名を取り出す
	$jcTag =~ s/^\s+|\s+$//g;

	foreach $pair (@brList) {

		($key,$scr) = split(/:/,$pair);

		$key =~ s/^\s+|\s+$//g;
		$scr =~ s/^\s+|\s+$//g;

		if ($key eq $reqHash{$jcTag}) {

			$reqHash{$confHash{'Operate'}{'JumpTag'}} = $scr;	# オリジナルの画面遷移キーワードを書き換える
			$flg = 1;
			last;
		}
	}

	return( $flg );

}


#---------------------------------------------------------------------
# 設定ファイルで指定された環境変数をリクエストパラメータに取り込む
#
sub GetEnvToRequestHash {

	my $np = $_[0];		# 画面遷移キーワード

	my $tHash;

	my $fName;
	my $vName;
	my @ele;
	my $sk;

	$np =~ s/^\s+|\s+$//g;


	$tHash = $confHash{'Getenv'};

	foreach $fName ( keys(%$tHash) ){

		@ele = split(/,/,$confHash{'Getenv'}{$fName});

		$vName = shift @ele;		# 環境変数名を取り出す


		if (scalar(@ele) == 0) {	# 取り込みするページの画面キーワードが指定されていない場合

			$reqHash{$fName} = $ENV{$vName};

		} else {

			foreach $sk (@ele) {

				$sk =~ s/^\s+|\s+$//g;

				if ($np eq $sk) {
					$reqHash{$fName} = $ENV{$vName};
					last;
				}
			}
		}
	}
}


#-------------------------------------------------------------------------------
# 設定ファイルで指定されたフォームの内容を補完する
#
sub SubstituteEmptyForm {

	my $tHash;
	my $eForm;

	$tHash = $confHash{'Substitute'};

	foreach $eForm ( keys(%$tHash) ){
		($reqHash{$eForm} = $reqHash{$confHash{'Substitute'}{$eForm}}) if ($reqHash{$eForm} eq '');		# 指定フォームが空だったら補完
	}

}


#-------------------------------------------------------------------------------
# 関連指定されたフォームの内容を補完する
#
sub RelationalFormSupplement {

	my $tHash;

	my $dForm;
	my $sForm;

	my @ele;

	my $duo;

	my $dv;
	my $sv;


	$tHash = $confHash{'Relation'};

	foreach $dForm ( keys(%$tHash) ){

		@ele = split(/\s*,\s*/,$confHash{'Relation'}{$dForm});

		$sForm = shift @ele;

		unless ($ele[0] =~ /:/) {	# 三番目のパラメータがコロンを含まない場合、タグ名と判断してその値を使用する

			@ele = split(/\s*,\s*/,$reqHash{$ele[0]} );

		}


		foreach $duo (@ele) {

			if ($duo =~ /\s*(\S+)\s*:\s*(\S+)/) {

				$dv = $1;
				$sv = $2;

			} elsif ($duo =~ /\s*:\s*(\S+)/) {

				$dv = '';
				$sv = $1;

			} else {

				next;

			}

			if ($reqHash{$sForm} eq $sv) {

				$reqHash{$dForm} = $dv;

				last;
			}
		}

	}

}


#-------------------------------------------------------------------------------
# ファイルからレコードを検索して置換文字列ハッシュに展開する
#
#　戻り値
#　　 1：該当あり
#　　 0：該当無し
#　　　　　　　　（負の数でエラー）
#
sub SearchDataToReqHash {

	my $resF;
	my $resR;

	my $key;
	my $pad;
	my $off;


	return(-5) if (&CheckAdminAccount() < 0);	# 管理アカウントNG

	return(-2) unless ( $confHash{'Retrieve'}{'Tag'} =~ /([a-zA-Z0-9_]+)\s*,\s*([0-9]+)/ );	# 検索語のタグ名と桁数の補正値を取り出す

	$key = $1;
	$pad = $2;

	$scw = $reqHash{$key};

	if ($pad > 0) {						# 桁数補正が入っていて
		if ($scw =~ /^[0-9]+$/) {		# 検索語が数値の場合

			$scw = sprintf( '%0'.$pad.'d' , $scw);
		}
	}

	$key = $confHash{'Serial'}{'TagName'};

	return(-3) if ($key eq '');		# シリアルコードのフィールド名が未指定

	($off,$pad) = CsvParse::getFieldInfoByName( \%CsvFields,$key );

	return(-4) if ($off < 0);		# シリアルコードを保存する設定になっていない

	$resF = &SearchToPast( \$resR,$off,$scw );

	&CsvParse::CsvToHash( \%reqHash,$resR,'L',\%CsvFields,'','F' ) if ($resF == 1);	# ヒットしてたら展開する

	return( $resF );
}


#-------------------------------------------------------------------------------
# 現在日付から過去に向かって、シリアルコードが一致するデータを検索する
#
#　戻り値
#　　 1：該当あり
#　　 0：該当無し
#　　-1：エラー
#
sub SearchToPast {

	my $res		= $_[0];	# 検索結果を格納するスカラー変数の参照
	my $off		= $_[1];	# 比較対象のフィールド番号
	my $scw		= $_[2];	# 比較文字列

	my @type = ( 'YEAR','MONTH','DATE' );

	my $y;
	my $m;
	my $d;

	my $bDate;
	my $nDate;

	my $flg;
	my $rec;

	($y,$m,$d) = &StrCodec::GetDateTimeString( \@type );

	$confHash{'Retrieve'}{'Begin'} =~ /([0-9]{4})\s*\/\s*([0-9]{1,2})\s*\/\s*([0-9]{1,2})/;

	$bDate = sprintf("%04d%02d%02d",$1,$2,$3);

	for(;;){

		$flg = &SearchSerlalInFile( \$rec,$y,$m,$d,$off,$scw );

		last if ($flg != 0);	# 検索ヒットかエラー

		if (--$d == 0) {
			$d = 31;

			if (--$m == 0){
				$m = 12;

				last if (--$y < 0);
			}
		}

		$nDate = sprintf("%04d%02d%02d",$y,$m,$d);

		last if ($nDate lt $bDate);
	}

	($$res = $rec) if ($flg == 1);		# ヒットした場合

	return($flg);
}


#-------------------------------------------------------------------------------
# 指定ファイルを読み込みシリアルコードに一致するデータを検索する
#
#　戻り値
#　　 1：該当あり
#　　 0：該当無し
#　　-1：エラー
#
sub SearchSerlalInFile {

	my $res		= $_[0];	# 検索結果を格納するスカラー変数の参照
	my $year	= $_[1];	# データを保存した日付（年）
	my $month	= $_[2];	# データを保存した日付（月）
	my $date	= $_[3];	# データを保存した日付（日）
	my $off		= $_[4];	# 比較対象のフィールド番号
	my $scw		= $_[5];	# 比較文字列

	my @recs;
	my $t;
	my @ele;

	$path = &MakeDataFilePath( sprintf("%04d%02d%02d.csv",$year,$month,$date) );


	$t = &FileClerk::ReadLines( \@recs,$path,'I' );

	return(-1) if ($t < 0);		# 読み込みエラー
	return(0)  if ($t = 0);		# データ無し

	for($t=0;$t<scalar(@recs);$t++){

		@ele = &CsvParse::ToArray( $recs[$t],'L' );		# 簡易展開なので直にデータを触る場合は注意のこと

		if ($ele[$off] eq $scw) {

			$$res = $recs[$t];
			last;
		}

		undef @ele;
	}

	return(0) if ($t == scalar(@recs));		# 該当無し

	return(1);
}


#-------------------------------------------------------------------------------
# ファイルへ書き出すデータをチェックをするページを出力する
#
#
sub PrintWriteParamCheckPage {

	my @wList;
	my @uList;

	my $hdc;
	my @page;

	&GetWritedAndUnwritedDataList( \@wList,\@uList );

	$hdc =<< '__EOB__';
		<table width=="700">
		<tr>
		<td width="5">&nbsp;</td>
		<td width="30"><hr></td>
		<td width="140">&nbsp;Writed Param&nbsp;</td>
		<td><hr></td>
		</tr>
		</table>
__EOB__

	push @page,$hdc;
	push @page,@wList;


	$hdc =<< '__EOB__';
		<table width=="700">
		<tr>
		<td width="5">&nbsp;</td>
		<td width="30"><hr></td>
		<td width="140">&nbsp;Un-writed Param&nbsp;</td>
		<td><hr></td>
		</tr>
		</table>
__EOB__

	push @page,$hdc;
	push @page,@uList;


	$hdc =<< '__EOB__';
		<table width=="700">
		<tr>
		<td width="5">&nbsp;</td>
		<td><hr></td>
		</tr>
		</table>
__EOB__

	push @page,$hdc;

	&WebReq::PrintContentType();
	&WebReq::PrintErrorPage('GAC: Debug mode',\@page);
}


#-------------------------------------------------------------------------------
# 書き出しデータと書き出されていないデータの一覧を表示形式で取り出す
#
sub GetWritedAndUnwritedDataList {

	my $wList = $_[0];		# 書き出したデータの一覧を格納する配列の参照
	my $uList = $_[1];		# 書き出されなかったデータの一覧を格納する配列の参照

	my @wl;
	my @ul;
	my $t;

	my $key;
	my $line;

	my %tHash;

	my 

	@wl = split(/,/,$confHash{'DataFile'}{'List'});

	for($t=0;$t<scalar(@wl);$t++){
		$wl[$t] =~ s/^\s+|\s+$//g;
	}

	$line = '<table>'."\n";		# 書き出したデータの名前と値をテーブル形式で生成する

	foreach $key (@wl){

		$line .= '<tr><td widtH="30">&nbsp;</td><td><tt><font color="forestgreen">';
		$line .= $key;
		$line .= '</font></tt></td><td>：</td><td><font color="mediumblue">';
		$line .= $reqHash{$key};
		$line .= '</font></td></tr>';
		$line .= "\n";
	}

	$line .= '</table>';

	push @$wList,$line;



	foreach( keys(%reqHash) ){			# 書き出されていないデータの名前一覧をテーブル形式で生成する
		$tHash{$_} = 0;
	}

	foreach(@wl){
		(delete $tHash{$_}) if ( exists($tHash{$_}) );		# 書き出し指定のあるものを除去
	}

	@ul = sort( keys(%tHash) );


	$line = '<table>'."\n";		# 書き出したデータの名前と値をテーブル形式で生成する

	foreach $key (@ul){

		$line .= '<tr><td widtH="30">&nbsp;</td><td><tt><font color="forestgreen">';
		$line .= $key;
		$line .= '</font></tt></td></tr>';
		$line .= "\n";
	}
	$line .= '</table>';

	push @$uList,$line;
}


#-------------------------------------------------------------------------------
# リカバリ用のログを出力する
#
#　　※リカバリ用のログは設定ファイルが置いてあるディレクトリの
#　　　直下に作られた'log'ディレクトリに日付別に生成される。
#
# 戻り値
#　負の数でエラー
#
sub AppendRecoveryLog {

	my $path;
	my $rec;

	my @tar;

	$path = &MakeDataFilePath('','log');		# ログデータのパスを生成する

	push @tar,$reqHash{'apply_date'};
	push @tar,$reqHash{'apply_time'};
	push @tar,$reqHash{$confHash{'Serial'}{'TagName'}} if ($confHash{'Serial'}{'TagName'} ne '');
	push @tar,$reqHash{$confHash{'Bundle'}{'Tag'}};

	$rec = &CsvParse::ToCsv( \@tar,scalar(@tar) );

	return( &FileClerk::Append( $path,$rec."\n" ) );
}


#-------------------------------------------------------------------------------
# 設定で指定されたチェックボックスの選択状態を置換文字列ハッシュに反映させる
#
#　　※チェックボックスの名前は キーワード+枝番三桁(001〜) で構成しておくこと。
#
#　戻り値
#　　セットした項目の数／負の数でエラー
#
sub SetStatusToReqHashFromCheckBox {

	my $tHash = $confHash{'CheckBox'};

	my $fname;

	my $res;
	my $sum = 0;
	my $ef = 0;


	foreach $fname ( keys(%$tHash) ){

		$res = &SetStatusToReqHashFromCheckBox_sub($fname);
		if ($res < 0){
			$ef = $res;
		} else {
			$sum += $res;
		}
	}

	return(-1) if ($ef < 0);

	return($sum);
}


#-------------------------------------------------------------------------------
# １グループのチェックボックスの選択状態を置換文字列ハッシュに反映させる
#
#　　※チェックボックスの名前は キーワード+枝番三桁(001〜) で構成しておくこと。
#
#　戻り値
#　　セットした項目の数／負の数でエラー
#
sub SetStatusToReqHashFromCheckBox_sub {

	my $fname = $_[0];			# チェックボックス名の枝番部分を除いたもの

	my $st;
	my $ed;

	my $t;

	my $key;
	my $sum = 0;


	return(-1) unless ($confHash{'CheckBox'}{$fname} =~ /-/);	# パラメータがハイフンでつながっていない

	$st = $`;
	$ed = $';

	$st =~ s/^\s+|\s+$//g;
	$ed =~ s/^\s+|\s+$//g;

	return(-2) unless ($st =~ /^[0-9]+$/);		# 範囲の先端が数字で指定されていない
	return(-3) unless ($ed =~ /^[0-9]+$/);		# 範囲の終端が数字で指定されていない

	if ($ed < $st) {	# 偏屈な指定に対応

		$t = $ts;
		$st = $ed;
		$ed =$t;
	}

	for($t=$st;$t<=$ed;$t++){

		$key = sprintf("%s%03d",$fname,$t);

		next if ( $reqHash{$key} eq '' );

		$reqHash{'Checked'.$key} = 'checked';
		$sum++;
	}

	return($sum);
}


#-------------------------------------------------------------------------------
# ラジオボタンとプルダウンメニューの選択状態を置換文字列ハッシュに反映させる
#
#　戻り値
#　　セットした項目の数／負の数でエラー
#
sub SetStatusToReqHashFromRadioOrPulldown {

	my $ftype = $_[0];	# フォームのタイプ（'R'…ラジオボタン／'P'…プルダウンメニュー）

	my $tHash;
	my $fname;

	my $key;
	my $val;

	my $sum=0;

	if ($ftype eq 'R'){

		$tHash = $confHash{'Radio'};

	} elsif ($ftype eq 'P') {

		$tHash = $confHash{'PullDown'};

	} else {

		return(-1);		# フォームタイプエラー

	}

	foreach $fname ( keys(%$tHash) ){

		$num = &GetSelectedAtRadioOrPulldown( $fname,$ftype );

		next if ($num < 0);

		if ($ftype eq 'R'){

			$key = 'Checked';

		} else {

			$key = 'Selected';

		}

		$val = lc($key);		# まぁ、lcはいらん気もするが…。

		$key .= ($fname.sprintf("%03d",$num));

		$reqHash{$key} = $val;

		$sum++;
	}

	return($sum);
}


#-------------------------------------------------------------------------------
# ラジオボタンとプルダウンメニューの選択項目の番号を返す
#
#　戻り値
#　　選択されている項目の番号（1〜）
#　　選択されていない場合、デフォルトとして指定された項目番号
#
#　　　※戻り値が負の数だった場合はデフォルトとして指定された項目がない
#
sub GetSelectedAtRadioOrPulldown {

	my $fname = $_[0];	# フォーム名
	my $ftype = $_[1];	# フォームのタイプ（'R'…ラジオボタン／'P'…プルダウンメニュー）

	my $cfln;
	my @elements;
	my $defa;

	my $t;


	if ($ftype eq 'R'){

		$cfln = $confHash{'Radio'}{$fname};

	} elsif ($ftype eq 'P') {

		$cfln = $confHash{'PullDown'}{$fname};

	}

	return(-2) if ($cfln eq '');	# 空文字列 → 該当設定なし

	@elements = split(/,/,$cfln);

	return(-3) if (scalar(@elements) < 2);	# 設定項目が足りない

	$defa = shift( @elements );

	$defa =~ s/^\s+|\s+$//g;
	return(-4) unless ($defa =~ /^\-{0,1}[0-9]+$/);		# 先頭項目が数値ではない

	for($t=0;$t<scalar(@elements);$t++){
		$elements[$t] =~ s/^\s+|\s+$//g;

		last if ($elements[$t] eq $reqHash{$fname});
	}

	return($defa) if ($t == scalar(@elements));		# 該当なし

	return($t+1);
}


#-------------------------------------------------------------------------------
# ロックファイルの生成が必要かどうかを判定する
#
#　戻り値
#　　bit0 … データ書き出し
#　　bit1 … テンポラリデータファイル操作
#　　bit2 … データ検索
#　　bit3 … ユニークコード生成
#
sub NecessityCheckForFileLock {

	my $bits = 0;

	my $curpag = $reqHash{$confHash{'Operate'}{'JumpTag'}};

	my $cur;
	my $nex;
	my $cu;

	my @tar;

#	return(0) if ($curpag eq '');
	if ($curpag eq '') {
		$curpag = $reqHash{$confHash{'Operate'}{'JumpTag'}} = $confHash{'Operate'}{'DefScreen'};
	}

	($bits |= 4) if ($curpag eq $confHash{'Retrieve'}{'Screen'});	# データ検索

	($bits |= 1) if ($curpag eq $confHash{'DataFile'}{'Save'});	# データ書き出し

	@tar = split(/,/,$confHash{'Leap'}{'Generate'});
	foreach $cn ( @tar ){	# テンポラリデータファイル操作

		($cur,$nex) = split(/:/,$cn);
		last if ($curpag eq $cur);
	}

	($bits |= 2) if ($curpag eq $cur);

	if ($confHash{'Serial'}{'Unique'} ne '') {								# ユニークコードタグが指定されていて
		($bits |= 8) if ($reqHash{$confHash{'Serial'}{'Unique'}} eq '');	# ユニークコードが生成されていない場合
	}

	return($bits);
}


#-------------------------------------------------------------------------------
# 中継用テンポラリデータファイル用の該当レコードを読み出し、ハッシュに展開する
#
#　戻り値
#　　負の数でエラー
#
sub ExtendLeapTemporallyToHash {

	my $rHash	= $_[0];		# データを展開するハッシュの参照
	my $key		= $_[1];		# キー文字列

	my $path = ''.&GetDataStorageFolderPath().'/csv/'.$confHash{'Leap'}{'File'};

	my @recs;
	my @ele;

	return(-1) if (&FileClerk::ReadLines( \@recs,$path,'I' ) < 0);

	foreach $csv (@recs) {

		@ele = &CsvParse::ToArray( $csv,'L' );

		last if ($ele[0] eq $key);
	}

	return(1) unless ($ele[0] eq $key);		# 該当データなし

	return(-2) if (&StrCodec::UnpackCipher( $rHash,$ele[1],'F' ) < 0);

	return(0);
}


#-------------------------------------------------------------------------------
# 中継用テンポラリデータファイル用のレコードを生成する
#
#	※ ファイルロックは呼び出し側で行なうこと。
#
#　戻り値
#　　負の数でエラー
#
sub MakeRecordForLeapTemporally {

	my $uCode = $_[0];		# 生成したユニークコードを格納する変数の参照
	my $rec   = $_[1];		# 生成したレコード文字列を格納する変数の参照
	my $np    = $_[2];		# 中継後に出力するページの画面キーワード

	my $cFolder = ''.&GetDataStorageFolderPath().'/counter/Leap';
	my $cnt;

	my %tHash;		# パック用のデータを格納するテンポラリハッシュ
	my @tar;
	my $key;

	@tar = split(/,/,$confHash{'Leap'}{'List'});	# 格納するデータ一覧を生成する

	foreach $key (@tar) {
		$key =~ s/^\s+|\s+$//g;
		$tHash{$key} = $reqHash{$key};
	}

	$tHash{ $confHash{'Operate'}{'JumpTag'} } = $np;

	$pstr = &StrCodec::PackCipher( \%tHash );	# データをパックする

	$cnt = &FileClerk::IncreaseCounterModeMAGI( $cFolder );		# 中継用ユニークコード用カウンタを取り出す

	return(-1) if ($cnt < 0);	# エラー

	$$uCode = &StrCodec::CreateAttestCode( $cnt );	# ユニークコードを生成

	undef @tar;
	push @tar,$$uCode;
	push @tar,$pstr;

	$$rec = &CsvParse::ToCsv( \@tar,2 );

	return(0);
}


#-------------------------------------------------------------------------------
# 中継用テンポラリデータファイルにレコードを追加する
#
#	※ ファイルロックは呼び出し側で行なうこと。
#
#　戻り値
#　　 1：追加した
#　　 0：追加していない
#　　　　　負の数でエラー
#
sub InsertRecordToLeapTemporally {

	my @recs;

	my $cn;
	my $cur;
	my $nex;

	my $uc;
	my $rc;

	my $curpag = $reqHash{$confHash{'Operate'}{'JumpTag'}};

	my $maxcnt = $confHash{'Leap'}{'Count'};

	my $path = ''.&GetDataStorageFolderPath().'/csv/'.$confHash{'Leap'}{'File'};

	($maxcnt = 1000) unless ($maxcnt =~ /^[0-9]+$/);	# 最大レコード数が数値で与えられていなければ既定値を指定

	foreach $cn ( split(/,/,$confHash{'Leap'}{'Generate'}) ){	# 出力するページかどうかをチェックする

		($cur,$nex) = split(/:/,$cn);
		$cur =~ s/^\s+|\s+$//g;

		last if ($curpag eq $cur);
	}

	return(0) if ($curpag ne $cur);		# 処理対象のページではない

	return(-1) if (&FileClerk::ReadLines( \@recs,$path,'I' ) < 0);

	return(-2) if (&MakeRecordForLeapTemporally( \$uc,\$rc,$nex ) < 0);


	$reqHash{ $confHash{'Leap'}{'Tag'} } = $uc;		# ユニークコードをリクエストパラメータに格納

	unshift @recs,$rc;

	splice(@recs,$maxcnt) if (scalar(@recs) > $maxcnt);	# 最大数を超えていたら余計なレコードを削除


	return(-3) if (&FileClerk::Overwrite( $path,\@recs ) < 0);		# 書き出し失敗 → 致命的エラー

	return(1);
}


#-------------------------------------------------------------------------------
# 出力ページキーワードにあわせてメールを送信する
#
#　戻り値
#　　負の数でエラー
#
sub SendMailByScreen {

	my $scr = $_[0];		# ページキーワード

	my @mes;
	my $me;
	my $cnt = 0;

	return(0) if ($confHash{'MailSend'}{$scr} eq '');	# メール送信指定がない。

	@mes = split(/,/,$confHash{'MailSend'}{$scr});

	foreach $me (@mes) {

		($cnt++) if (&MailSender( $me ) >= 0);

	}

	return($cnt - scalar(@mes));	# 送信できないものがあれば負の数になる
}


#-------------------------------------------------------------------------------
# ダウンロード処理
#
sub Download {

	my $dstr;
	my @recs;

	my @period;
	my $flg;


	$flg = &DownLoadParamCheck( \@period );

	return(1) if ($flg < 0);	# パラメータがそろっていない

	if ($flg == 0) {	# 当日モード

		$dstr = sprintf("%04d%02d%02d",$period[0],$period[1],$period[2]);
		return(-1) if (&ReadDataForDownload( \@recs,$dstr ) < 0);

	} else {			# 期間モード

		return(-1) if (ReadDataForDownload2( \@recs,\@period ) < 0);

		$dstr = sprintf("%04d%02d%02d-%04d%02d%02d",@period);
	}

	print "Content-Type: application/download\n";

	print 'Content-Disposition: filename="'.$dstr.'.csv"'."\n\n";

	foreach(@recs){
		print "$_\n";
	}

	return(0);
}


#-------------------------------------------------------------------------------
# ダウンロードモードのパラメータチェック
#
#　戻り値
#　　 1：期間モード
#　　 0：単独日付モード
#　　-1：エラー
#
sub DownLoadParamCheck {

	my $dArray = $_[0];		# 日付を格納する配列の参照（開始年、開始月、開始日、終端年、終端月、終端日）

	my $dfc1,$dfc2;
	my @tmp;

	return(-1) if (&CheckAdminAccount() < 0);	# アカウントが×

	return(-1) unless( $confHash{'Download'}{'DateTag'} =~ /(\w+)\s*,\s*(\w+)\s*,\s*(\w+)/);	# 単独日付もしくは開始日を取得

	$$dArray[0] = $reqHash{ $1 };
	$$dArray[1] = $reqHash{ $2 };
	$$dArray[2] = $reqHash{ $3 };

	$$dArray[0] =~ s/^\s+|\s+$//g;
	$$dArray[1] =~ s/^\s+|\s+$//g;
	$$dArray[2] =~ s/^\s+|\s+$//g;


	$dfc1 = sprintf("%04d/%02d/%02d",$$dArray[0],$$dArray[1],$$dArray[2]);
	return(-1) if (&Appraise::ValidDateString( \$dfc1 ) < 0);

	return(0) unless( $confHash{'Download'}{'TermTag'} =~ /(\w+)\s*,\s*(\w+)\s*,\s*(\w+)/);		# 終端日を取得

	$$dArray[3] = $reqHash{ $1 };
	$$dArray[4] = $reqHash{ $2 };
	$$dArray[5] = $reqHash{ $3 };

	$$dArray[3] =~ s/^\s+|\s+$//g;
	$$dArray[4] =~ s/^\s+|\s+$//g;
	$$dArray[5] =~ s/^\s+|\s+$//g;

	$dfc2 = sprintf("%04d/%02d/%02d",$$dArray[3],$$dArray[4],$$dArray[5]);
	return(-1) if (&Appraise::ValidDateString( \$dfc2 ) < 0);

	return(0) if ($dfc1 eq $dfc2);

	if ($dfc1 gt $dfc2) {	# 期間が逆転している

		@tmp = splice(@$dArray,0,3);
		push @$dArray,@tmp
	}

	return( 1 );
}


#-------------------------------------------------------------------------------
# 指定ファイルを読み込んでダウンロード用のCSVデータの配列に変換する（期間用）
#
#　戻り値
#　　取り出したレコード数
#
sub ReadDataForDownload2 {

	my $resArry = $_[0];	# データを格納する配列の参照
	my $dArry   = $_[1];	# 期間情報を格納した配列の参照

	my $y =  $$dArry[0];
	my $m =  $$dArry[1];
	my $d =  $$dArry[2];

	my $termD = sprintf("%04d%02d%02d",$$dArry[3],$$dArry[4],$$dArry[5]);	# 終端日付文字列を生成
	my $lodaD;

	my @tArray;
	my $flg;
	my $sum = 0;


	while(1){

		$lodaD = sprintf("%04d%02d%02d",$y,$m,$d);

		$flg = ReadDataForDownload( \@tArray,$lodaD );

		last if ($flg < 0);		# 読み込みエラー

		push @$resArry,@tArray;
		$sum += $flg;

		undef @tArray;

		return if ($lodaD eq $termD);

		if ((++$d) > 31) {
			$d = 1;
			if ((++$m) > 12) {
				$m = 1;
				$y++;
			}
		}

	}

	return(-1) if ($flg< 0);

	return( $sum );
}


#-------------------------------------------------------------------------------
# 指定ファイルを読み込んでダウンロード用のCSVデータの配列に変換する（単独日付用）
#
#　戻り値
#　　取り出したレコード数
#
sub ReadDataForDownload {

	my $resArry = $_[0];	# データを格納する配列の参照
	my $dStr    = $_[1];	# ダウンロードするデータの日付文字列（YYYYMMDD形式）

	my $flg;

	my @ele;
	my $t;
	my $u;


	return(-1) if (LockupFile() < 0);
	$flg = &FileClerk::ReadLines( $resArry,&MakeDataFilePath( $dStr.'.csv' ) );
	&FileClerk::Unlock();

	return(-2) if ($flg < 0);

	for($t=0;$t<scalar(@$resArry);$t++){

		last if (&CsvParse::CsvToArray( \@ele,$$resArry[$t],'L',\%CsvFields ) < 0);

		for($u=0;$u<scalar(@ele);$u++){

			$ele[$u] =~ s/\r|\n/ /g;	# 改行コードを空白に変換して
			$ele[$u] =~ s/\s{2,}/ /g;	# 連続した空白を統合する。
		}

		$$resArry[$t] = &CsvParse::ToCsv( \@ele,scalar(@ele) );
	}

	return(-3) if ($t != scalar(@$resArry));	# 終端まで処理していない

	return($t);
}


#-------------------------------------------------------------------------------
# ID＆パスワードチェック
#
#　戻り値
#　　 0：OK
#　　-1：NG
#
sub CheckAdminAccount {

	my $tagID;
	my $tagPW;

	return(-1) unless( $confHash{'Download'}{'UserTag'} =~ /(\w+)\s*,\s*(\w+)/);

	&ExtendCryptoAdminInfo();

	$tagID = $reqHash{ $1 };
	$tagPW = $reqHash{ $2 };

	$tagID =~ s/^\s+|\s+$//g;
	$tagPW =~ s/^\s+|\s+$//g;

	return(-1) if ($tagID eq '');
	return(-1) if ($tagPW eq '');

	return(-1) if ($confHash{'Caretaker'}{$tagID} ne $tagPW);	# パスワードが×

	return(0);
}


#-------------------------------------------------------------------------------
# 暗号化管理ユーザー情報を設定ハッシュに展開する
#
sub ExtendCryptoAdminInfo {

	my @cList;
	my $info;
	my %tHash;

	return if ($confHash{'GateKeeper'}{'KeyMaster'} eq '');

	@cList = split(/,/,$confHash{'GateKeeper'}{'KeyMaster'});	

	foreach $info (@cList) {
		$info =~ s/^\s+|\s+$//g;

		&StrCodec::UnpackCipher( \%tHash,$info,'F' );
		$confHash{'Caretaker'}{ $tHash{'ID'}  } = $tHash{'PW'};

		undef %tHash;
	}
}


#-------------------------------------------------------------------------------
# ファイルをロックする
#
#　戻り値
#　　負の数でロック失敗
#
sub LockupFile {

	return( &FileClerk::Lock(&MakeDataFilePath( 'LockFile' )) );
}


#-------------------------------------------------------------------------------
# 稼動期間チェック
#
#　　※期間外だった場合、画面遷移キーワードを上書きする
#
#　戻り値
#　　負の数で期間外
#
sub InOperateTerm {

	my $st;
	my $ed;

	my $now;

	my $jTag = $confHash{'Operate'}{'JumpTag'};

	if ($reqHash{$jTag} ne '') {
		return(0) if ($reqHash{$jTag} eq $confHash{'Operate'}{'DwnScreen'});	# ダウンロードページ出力モード
	}

	if ($confHash{'Operate'}{'Mode'} eq 'stop') {			# 強制サービス停止モードか？

		$reqHash{$jTag} = $confHash{'Operate'}{'CloScreen'};
		return(-1);
	}

	if ($confHash{'Operate'}{'Term'} =~ /(\d{4}\/\d{1,2}\/\d{1,2}\.\d{1,2}:\d{1,2})\s*,\s*(\d{4}\/\d{1,2}\/\d{1,2}\.\d{1,2}:\d{1,2})/) {		# 日時モード

		$st = $1;
		$ed = $2;

		$st =~ /(\d{4})\/(\d{1,2})\/(\d{1,2})\.(\d{1,2}):(\d{1,2})/;
		$st = sprintf("%04d%02d%02d%02d%02d00",$1,$2,$3,$4,$5);

		$ed =~ /(\d{4})\/(\d{1,2})\/(\d{1,2})\.(\d{1,2}):(\d{1,2})/;
		$ed = sprintf("%04d%02d%02d%02d%02d00",$1,$2,$3,$4,$5);


	} elsif ($confHash{'Operate'}{'Term'} =~ /(\d{4}\/\d{1,2}\/\d{1,2})\s*,\s*(\d{4}\/\d{1,2}\/\d{1,2})/) {		# 日付モード

		$st = $1;
		$ed = $2;

		$st =~ /(\d{4})\/(\d{1,2})\/(\d{1,2})/;
		$st = sprintf("%04d%02d%02d000000",$1,$2,$3);

		$ed =~ /(\d{4})\/(\d{1,2})\/(\d{1,2})/;
		$ed = sprintf("%04d%02d%02d235959",$1,$2,$3);

	} else {

		return(0);

	}

	$now = &StrCodec::GetDateTimeString( 'FLAT',$TimeSerial );

	return(0) if (($now ge $st) && ($now le $ed));

	$reqHash{$jTag} = $confHash{'Operate'}{'CloScreen'};
	return(-1);
}


#-------------------------------------------------------------------------------
# 期限切れ強制停止判定
#
#　戻り値
#　　負の数で賞味期限切れ
#
sub BestIfUsedBy {

	my $ds;
	my $fdt;
	my $now;

	$ds = $_[0].'/'.$_[1].'/'.$_[2];
	$fds = sprintf("%04d%02d%02d235959",$_[0],$_[1],$_[2]);


	if (&Appraise::ValidDateString( \$ds ) == 0) {

		$now = &StrCodec::GetDateTimeString( 'FLATDATE',$TimeSerial );

		return(0) if ($now le $fds);
	}

	&WebReq::PrintContentType();
	&WebReq::PrintErrorPage('GAC: Service terminateed','');

	return(-1);
}


#-------------------------------------------------------------------------------
# 画面遷移キーワードで指定される画面を出力する
#
sub PrintScreen {

	my $keyword = $_[0];	# 画面遷移キーワード
	my $ExInfo  = $_[1];	# 反復部展開情報



	my $tPath;
	my $conte;

	$reqHash{'BaseURL'} = $confHash{'Server'}{'Protocol'}.'://'.$confHash{'Server'}{'ServerName'}.'/'.$confHash{'Folder'}{'Template'}.'/';


	$tPath = $confHash{'Server'}{'DocRoot'}.'/'.$confHash{'Folder'}{'Template'}.'/';

	unless (-f $tPath.$confHash{'Screen'}{$keyword}) {

		$tPath .= $confHash{'Screen'}{$confHash{'Operate'}{'DefScreen'}}

	} else {

		$tPath .= $confHash{'Screen'}{$keyword}

	}

	return( &Templet::ReadTemplateToStdout( $tPath,\%reqHash,$ExInfo,'' ) );
}


#-------------------------------------------------------------------------------
# 選択系フォーム（radio,checkbox,select）の選択済みパラメータを
#　　伝達するためのリクエストパラメータ名（checked…001等）一覧を生成する。
#
#　戻り値
#　　リクエストパラメータ名を格納したリスト
#
sub SelectFormNameToCheckedParamNameRS {	# radio、select用

	my $prefix = $_[0];		# 接頭文字列（'Checked'、'Selected'）
	my $tHash  = $_[1];		# 一覧化するパラメータを格納したハッシュの参照（$confHash{'Radio'}{'…'} の $confHash{'Radio'}）

	my @res;

	my $key;
	my @val;
	my $t;

	foreach $key (keys(%$tHash)){

		@val = split(/,/,$$tHash{$key});
		shift(@val);

		for($t=0;$t<scalar(@val);$t++){
			push @res,sprintf("%s%s%03d",$prefix,$key,$t+1);
		}

		undef @val;
	}

	return( @res );
}


sub SelectFormNameToCheckedParamNameC {		# checkbox用

	my $tHash  = $_[0];		# 一覧化するパラメータを格納したハッシュの参照（$confHash{'CheckBox'}{'…'} の $confHash{'CheckBox'}）

	my @res;

	my $key;
	my @val;
	my $t;

	foreach $key (keys(%$tHash)){

		next unless($$tHash{$key} =~ /^\s*([0-9]+)\s*\-\s*([0-9]+)\s*$/);

		if ($1<$2) {
			push @val,$1;
			push @val,$2;
		} else {
			push @val,$2;
			push @val,$1;
		}

		for($t=$val[0];$t<=$val[1];$t++){
			push @res,sprintf("Checked%s%03d",$key,$t);
		}
	}

	return( @res );

}


#-------------------------------------------------------------------------------
# リクエストパラメータをパックする
#
#　戻り値
#　　負の数でエラー
#
sub PackRequestParam {

	my $pac;

	my @deter = ( 'CoName','hostinfo','useragent','apply_date','apply_time','SelCode' );

	my @ele;

	return(-1) if ($confHash{'Bundle'}{'Tag'} eq '');

	push @deter,$confHash{'Operate'}{'JumpTag'};	# 可変なもの。
	push @deter,$confHash{'Bundle'}{'Tag'};			# 再帰してどーする。

	if ($confHash{'Bundle'}{'Exclude'} ne '') {		# ユーザー指定除外リスト

		@ele = split(/\s*,\s*/,$confHash{'Bundle'}{'Exclude'});

		foreach(@ele){
			next if ($_ eq '');
			push @deter,$_;
		}
	}

	push @deter,&SelectFormNameToCheckedParamNameRS( 'Checked', $confHash{'Radio'} );			# 選択系フォーム対応
	push @deter,&SelectFormNameToCheckedParamNameRS( 'Selected',$confHash{'PullDown'} );
	push @deter,&SelectFormNameToCheckedParamNameC( $confHash{'CheckBox'} );


	&WebReq::PackParcel( \$pac,\%reqHash,\@deter );

	$reqHash{$confHash{'Bundle'}{'Tag'}} = $pac;

	return(0);
}


#-------------------------------------------------------------------------------
# リクエストパラメータをCSVに変換してファイルに書き出す
#
#　戻り値
#　　負の数でエラー
#
sub WriteToDataFile {

	my $rec;
	my $flg;
	my $path;


	$flg = &CsvParse::HashToCsv( \$rec,\%reqHash,\%CsvFields );

	return(-1) if ($flg < 0);		# レコード生成失敗

	$path = MakeDataFilePath();

	$flg = &FileClerk::Append( $path,"$rec\n" );

	return(-2) if ($flg < 0);

	return(0);
}


#-------------------------------------------------------------------------------
# データファイルのパスを生成する
#
#　戻り値
#　　パス文字列
#
sub MakeDataFilePath {

	my $fName = $_[0];			# ファイル名（省略時、日付から生成）
	my $fFold = $_[1];			# フォルダ名（省略時、デフォルトの'csv'）

	my $bzdOff;

	($fFold = 'csv') if ($fFold eq '');

	if ($fName eq '') {

		if ($confHash{'DataFile'}{'BusinessDate'} =~ /\w+\s*,\s*([0-9]+)/) {	# 営業日モードか？
			$bzdOff = $1;
		} else {
			$bzdOff = 0;
		}

		$fName  = &StrCodec::GetDateTimeString( 'FLATDATE',$TimeSerial-$bzdOff*3600 );
		$fName .= '.csv';
	}

	return( ''.&GetDataStorageFolderPath().'/'.$fFold.'/'.$fName );
}


#-------------------------------------------------------------------------------
# チェック項目のソート情報を生成する（チェック分類ひとつぶん）
#
sub MakeCheckListSortInfo_sub {

	my $rar		= $_[0];	# 結果を格納する配列の参照
	my $key		= $_[1];	# チェックの種類を指定する文字列（Check,Same,Mono,Slave,Either）


	my $clha;
	my %rch;

	@$rar = split(/\s*,\s*/,$confHash{'CheckSort'}{$key});		# ソート指定に設定されている順をとりだす。

	if ($key eq 'Generic') {

		foreach(@$rar){
			$rch{$_} = 1;
		}

		foreach( ('Check','Same','Either','Slave','Mono','Length') ){

			(push @$rar,$_) unless ( exists($rch{$_}) );
		}

	} else {

		$clha = $confHash{$key};

		foreach( keys(%$clha) ){
			$rch{$_} = 1;			# 値はダミー
		}

		foreach( @$rar ){
			delete $rch{$_};		# ソート指定に含まれるものを削除して
		}

		foreach( keys(%rch) ) {
			push @$rar,$_;			# 未指定のものを後ろに連結する
		}
	}

}


#-------------------------------------------------------------------------------
# チェック項目のソート情報を生成する（全体）
#
#　※エラー項目のソート機能で使用する
#
#　戻り値
#　　チェック項目の数
#
sub MakeCheckListSortInfo {

	my @gar;
	my $cate;

	my @tar;
	my $key;
	my $seq = 0;

	&MakeCheckListSortInfo_sub( \@gar,'Generic' );	# 全体の並び順を取り出す。

	foreach $cate (@gar) {

		&MakeCheckListSortInfo_sub( \@tar,$cate );	# 各カテゴリの順番を取り出す

		foreach $key (@tar) {
			$CheckListSortInfo{$cate.':'.$key} = $seq;
			$seq++;
		}

		undef @tar;
	}

	return( $seq );
}


#-------------------------------------------------------------------------------
# チェック項目を指定された順番で再配置する
#
#　戻り値
#　　ソート設定が指定されていない場合、負の数
#
sub SortChecklList {

	my $ar = $_[0];		# チェック項目一覧を格納した配列の参照

	return(-1) if ($confHash{'CheckSort'}{'Generic'} eq '');	# ソートが指定されていない。

	&MakeCheckListSortInfo();	# ソート情報を生成する

	@$ar = sort{ $CheckListSortInfo{$a} <=> $CheckListSortInfo{$b} }( @$ar );

	return(0);
}


#-------------------------------------------------------------------------------
# リクエストパラメータの項目チェック・一括モード
#
#　戻り値
#　　エラーの個数
#
sub ParamErrorCheckMulti {

	my $eScr  = $_[0];	# エラー表示ページの画面戦意キーワードを格納するスカラー変数の参照
	my $exStr = $_[1];	# 反復擬似タグの展開パラメータ文字列を格納するスカラー変数の参照
	my $cScr  = $_[2];	# パラメータチェックをするページの画面戦意キーワード

	my $cnt;
	my @rArr;
	my $iScr;

	my $lpKey;
	my $lpEle;

	my $t;

	return(0) if ($confHash{'VerifyScreen'}{$cScr} eq '');	# チェック指定が無い → 正常終了

	$cnt = &RequestParamCheck_sub( \@rArr,$eScr,\$iScr,$confHash{'VerifyScreen'}{$cScr} );
	return(0) if ($cnt == 0);

	if ($confHash{'Operate'}{'MultiError'} =~ /(\w+)\s*,\s*(\w+)\s*,\s*(\w+)/) {	# 一括チェックが指定されている

		$lpKey = $1;	# ループ擬似タグのキーワード
		$lpEle = $2;	# ループ展開時のメッセージの識別子

		$reqHash{$3} = $iScr;		# 再入力ページ

		for($t=0;$t<$cnt;$t++){
			$reqHash{ $lpKey.sprintf("%04d",$t).$lpEle } = $rArr[$t];	# エラーメッセージをハッシュに展開
		}

		$$exStr = $lpKey.',0,'.$cnt;	# 反復擬似タグ展開情報を生成する

		return( $cnt );
	}

	return(0);
}


#-------------------------------------------------------------------------------
# リクエストパラメータの項目チェック・単独モード
#
#　戻り値
#　　エラーの個数
#
sub ParamErrorCheckSingle {

	my $eScr = $_[0];	# エラー表示ページの画面戦意キーワードを格納するスカラー変数の参照
	my $cScr = $_[1];	# パラメータチェックをするページの画面戦意キーワード

	my $cnt;
	my @rArr;
	my $iScr;

	return(0) if ($confHash{'CheckScreen'}{$cScr} eq '');	# チェック指定が無い → 正常終了

	$cnt = &RequestParamCheck_sub( \@rArr,$eScr,\$iScr,$confHash{'CheckScreen'}{$cScr} );
	return(0) if ($cnt == 0);

	if ($confHash{'Operate'}{'ErrorTag'} =~ /(\w+)\s*,\s*(\w+)/) {

		$reqHash{$1} = $rArr[0];	# エラーメッセージ（最初のひとつ）
		$reqHash{$2} = $iScr;		# 再入力ページ

		return( $cnt );
	}

	return(0);
}



#-------------------------------------------------------------------------------
# チェック項目を重複除去用のハッシュに展開
#
sub CheckItemToListTempHash {

	my $hash = $_[0];		# 重複除去用ハッシュの参照
	my $item = $_[1];		# チェック項目名（例、Check:YourNmae、CHECKなど）

	my $th;

	if ($item =~ /[0-9A-Za-z_]+:[0-9A-Za-z_]+/) {	# '分類名：項目名'だった場合

		$$hash{$item} = 1;
		return;
	}

	if ($item eq 'ALL') {	# 全項目指定の場合 → 再帰で全項目をセットする

		&CheckItemToListTempHash( $hash,'CHECK');
		&CheckItemToListTempHash( $hash,'SAME');
		&CheckItemToListTempHash( $hash,'EITHER');
		&CheckItemToListTempHash( $hash,'SLAVE');
		&CheckItemToListTempHash( $hash,'MONO');
		&CheckItemToListTempHash( $hash,'LENGTH');

		return;
	}


	$item = lc($item);
	$item = ucfirst($item);

	$th = $confHash{ $item };

	foreach (keys(%$th)) {
		$$hash{ $item.':'.$_ } = 1;
	}
}


#-------------------------------------------------------------------------------
# リクエストパラメータの項目チェック（全指定項目）
#
#　戻り値
#　　エラーの個数
#
sub RequestParamCheck_sub {

	my $resA = $_[0];	# エラーメッセージを格納する配列の参照
	my $errP = $_[1];	# エラー表示ページの画面遷移キーワードを格納するスカラー変数の参照
	my $inpP = $_[2];	# 再入力ページの画面遷移キーワードを格納するスカラー変数の参照
	my $prmS = $_[3];	# チェックパラメータ文字列

	my @ele;
	my $item;

	my %itemHash;
	my @itemList;

	my $cate;
	my $tag;
	my $em;

	@ele = split(/\s*,\s*/,$prmS);

	$$errP = shift @ele;		# エラーページの画面遷移キーワード
	$$inpP = shift @ele;		# 入力ページの画面遷移キーワード

	foreach $item (@ele) {
		&CheckItemToListTempHash ( \%itemHash,$item );	# チェック項目を重複削除用ハッシュに展開する
	}

	@itemList = keys(%itemHash);

	$sdes = &SortChecklList( \@itemList );

	foreach $item (@itemList) {

		next unless ($item =~ /([0-9A-Za-z_]+):([0-9A-Za-z_]+)/);

		$cate = $1;
		$tag  = $2;

		if ($cate eq 'Check') {

			$em = CheckRequestParam_sub2($tag);
			(push @tar,$em) if ($em ne '');;

		} elsif ($cate eq 'Same') {

			$em = CheckSamenessRequestParam_sub($tag);
			(push @tar,$em) if ($em ne '');;

		} elsif ($cate eq 'Length') {

			$em = CheckLengthRequestParam_sub($tag);
			(push @tar,$em) if ($em ne '');;

		} elsif ( ($cate eq 'Either')||($cate eq 'Slave')||($cate eq 'Mono') ) {

			$em = CheckRelationalRequestParam_sub( $cate,$tag );
			(push @tar,$em) if ($em ne '');;
		}

	}

	if ($sdes < 0) {
		@$resA = sort(@tar);
	} else {
		@$resA = @tar;
	}

	return( scalar(@$resA) );
}


#-------------------------------------------------------------------------------
# 連携入力欄チェック（checkbox系）
#
#　※主にcheckbox同士やcheckboxとテキスト入力欄との連携を検証する機能
#
#　戻り値
#　　エラーメッセージ／空文字列でエラーなし
#
sub CheckRelationalRequestParam_sub {

	my $mode = $_[0];		# チェックするモード('Mono'／'Slave'／'Either')
	my $mTag = $_[1];		# 主対象リクエストパラメータ名

	my $cPar;
	my @tags;
	my $eMess;

	my $mFlg = 0;
	my $sCnt = 0;


	$cPar = $confHash{$mode}{$mTag};

	@tags = split(/\s*,\s*/,$cPar);

	return('Err:設定ファイル') if (scalar(@tags) < 2);

	$eMess = shift @tags;

	($mFlg = 1) if ($reqHash{$mTag} ne '');		# 主対象リクエストパラメータに値が定義されているかチェックする

	foreach(@tags){
		($sCnt++) if ($reqHash{$_} ne '');	# 値が定義されている従対象リクエストパラメータの数を勘定する
	}

	if ($mode eq 'Mono') {

		return( $eMess ) if (($mFlg != 0) && ($sCnt > 0));		# 同時に設定されていたらエラー

		return( '' );


	} elsif ($mode eq 'Slave') {

		return('') if ($mFlg == 0);			# 主対象がセットされていなければ後のチェックをスキップ

		return( $eMess ) if ($sCnt == 0);	# 主対象と従対象が同時に設定されていない場合はエラー

		return( '' );


	} elsif ($mode eq 'Either') {

		return( $eMess ) if (($mFlg == 0) && ($sCnt == 0));		# どれかが設定されていなかったらエラー

		return( '' );
	}


	return('Err:設定ファイル');
}


#-------------------------------------------------------------------------------
# 入力文字列長チェック
#
#　戻り値
#　　エラー箇所を示す文字列／空文字列で異常なし
#
sub CheckLengthRequestParam_sub {

	my $key = $_[0];	# チェックするリクエストパラメータのキー文字列

	my @ele;
	my $emess;

	my $len;

	@ele = split(/\s*,\s*/,$confHash{'Length'}{$key});

	return('Err:設定ファイル') if (scalar(@ele) < 2);

	$emess = $ele[0];	# エラーメッセージ
	$len = $ele[1];		# 文字列長

	return('Err:設定ファイル') unless ($len =~ /^[0-9]+$/);

	return( $emess ) if (length($reqHash{$key}) > $len);

	return('');
}


#-------------------------------------------------------------------------------
# 多重入力欄のチェック（設定一エントリ分）
#
#　戻り値
#　　エラー箇所を示す文字列／空文字列で異常なし
#
sub CheckSamenessRequestParam_sub {

	my $key = $_[0];	# チェックするリクエストパラメータのキー文字列

	my @ele;
	my $emess;

	my $flg = 0;

	@ele = split(/\s*,\s*/,$confHash{'Same'}{$key});

	return('Err:設定ファイル') if (scalar(@ele) < 2);


	$emess = shift @ele;

	foreach $k (@ele){

		if ($reqHash{$key} ne $reqHash{$k}) {
			$flg = -1;
			last;
		}
	}

	($emess = '') if ($flg == 0);

	return( $emess );
}


#-------------------------------------------------------------------------------
# ひとつのリクエストパラメータをチェックする
#
#　戻り値
#　　エラー箇所を示す文字列／空文字列で異常なし
#
sub CheckRequestParam_sub2 {

	my $key = $_[0];	# チェックするリクエストパラメータのキー文字列

	my @ele;

	my $t;
	my $flg = -1;

	my $val;
	my $ctp;
	my $emess;

	@ele = split(/\s*,\s*/,$confHash{'Check'}{$key});
	return('Err:設定ファイル') if (scalar(@ele) < 2);

	$emess = shift @ele;				# エラーメッセージを取り出す

	for($t=0;$t<scalar(@ele);$t++){
		($flg = 0) if ($ele[$t] eq 'EmptyOK');
	}


	$val = $reqHash{$key};

	if ($flg == 0) {					# EmptyOKが指定されていて
		return('') if ($val eq '');		# 内容が空の場合
	}

	foreach $ctp (@ele){


		next if ($ctp eq 'EmptyOK');

		$flg = &CheckRequestParam_sub1( \$val,$ctp );

		last if ($flg < 0);

	}

	return($emess) if ($flg < 0);

	$reqHash{$key} = $val;


	return('');
}


#-------------------------------------------------------------------------------
# リクエストパラメータの内容を各チェックタイプに合わせて検証する
#
#　戻り値
#　　負の数でエラー、またはチェックに適合しない
#
sub CheckRequestParam_sub1 {

	my $rqParam	= $_[0];	# リクエストパラメータの値を格納したスカラー変数の参照
	my $cType	= $_[1];	# チェックタイプ文字列

	my $res;


	if ($cType eq 'EmptyNG') {							# 空項目NG

		if ($$rqParam eq '') {
			return(-1);
		} else {
			return(0);
		}

	} elsif ($cType eq 'Mail') {						# メールアドレス

		return( &Appraise::ValidMailAddress( $rqParam ) );

	} elsif ($cType eq 'DenyDomain') {					# メールアドレスの禁止ドメイン

		return( &ForbidDomainCheckForMailAddr( $rqParam ) );

	} elsif ($cType eq 'Number') {						# 整数文字列

		return( &Appraise::ValidNumberString( $rqParam ) );

	} elsif ($cType eq 'HalfWidth') {					# 半角文字列

		if ($$rqParam =~ /^[\x20-\x7e]+$/) {
			return(0);
		} else {
			return(-1);
		}

	} elsif ($cType eq 'FullWidth') {					# 全角文字列

		return( &Appraise::CheckFullWidthOnly( $$rqParam ) );

	} elsif ($cType eq 'Date') {						# 日付文字列

		return( &Appraise::ValidDateString( $rqParam ) );

	} elsif ($cType eq 'Time') {						# 時刻文字列

		return( &Appraise::ValidTimeString( $rqParam ) );

	} elsif ($cType eq 'NoFuture') {					# 未来の日付

		return( &DateCompareToNow($$rqParam) );

	} elsif ($cType eq 'Zip') {							# 郵便番号文字列

		return( &Appraise::ValidZipCodeString( $rqParam ) );

	} elsif ($cType eq 'Phone') {						# 電話番号文字列

		return( &Appraise::ValidPhoneCodeString( $rqParam ) );

	} elsif ($cType eq 'HandyNG') {						# 携帯電話NG

		$res = &Appraise::ValidPhoneCodeString( $rqParam );

		return( -2 ) if ($res == 1);
		return( $res );

	} elsif ($cType eq 'Prefec') {						# 都道府県名 in 住所

		return( &Appraise::PrefectureInAddress( $$rqParam ) );

	} elsif ($cType eq 'KanaH') {						# 全角ひらがな文字列

		return( &Appraise::CheckKanaOnly( $$rqParam,'H' ) );

	} elsif ($cType eq 'KanaK') {						# 全角カタカナ文字列

		return( &Appraise::CheckKanaOnly( $$rqParam,'K' ) );

	}

	return(-1);		# いわゆるパラメータエラー
}


#-------------------------------------------------------------------------------
# 与えられたメールアドレスが禁止ドメインリストに含まれるか調べる
#
#　戻り値
#　　負の数で禁止ドメイン
#
sub ForbidDomainCheckForMailAddr {

	my $mAddr = $_[0];		# 調べるメールアドレス文字列
	my $res = 0;
	my $rex;

	my $ma;

	$ma = lc($$mAddr);

	$ma =~ s/\s//g;	# 空白文字除去

	return(0) if (scalar( @DenyDomainList ) == 0);		# 禁止ドメインリストが空 → 誰の挑戦でも受けるモード

	foreach $rex (@DenyDomainList) {
		if ($ma =~ $rex) {
			$res = -1;
			last;
		}
	}

	return($res);
}


#-------------------------------------------------------------------------------
# 与えられた日付文字列を現在日付と比較する
#
#　戻り値
#　　負の数で未来の日付
#
sub DateCompareToNow {

	my $dts = $_[0];

	my $dt;
	my $dtn;

	return(-2) unless ($$dts =~ /([0-9]{4})\/([0-9]{1,2})\/([0-9]{1,2})/);

	$dt = $1*10000+$2*100+$3;	# 日付をフラットな時刻にする

	$dtn = &StrCodec::GetDateTimeString('FLATDATE',$TimeSerial);

	return(-1) if ($dt > $dtn);

	return(0);
}


#-------------------------------------------------------------------------------
# シリアルコードを生成する
#
#　戻り値
#　　 1：生成した
#　　 0：生成しなかった
#　　-1：エラー
#
sub CreateSerialCode {

	my $cFolder = ''.&GetDataStorageFolderPath().'/counter/Serial';

	my $rpKey = $confHash{'Serial'}{'TagName'};
	my $prefix = $confHash{'Serial'}{'Prefix'};
	my $format = $confHash{'Serial'}{'Format'};


	my @ele;
	my $flg = 0;
	my $k;
	my $cnt = -1;

	my $sStr = '';


	return(0) if ($rpKey eq '');
	return(0) if ($prefix eq '');
	return(0) if ($format eq '');

	@ele = split(/,/,$format);

	foreach $k (@ele){

		$k =~ s/^\s+//g;
		$k =~ s/\s+$//g;

		next if ($k eq '');

		($sStr .= '-') if ($sStr ne '');

		if ($k eq 'prefix') {			# 接頭文字列

			$sStr .= $prefix;

		} elsif ($k eq 'date') {		# 日付（YYYYMMDD）

			$sStr .= &StrCodec::GetDateTimeString('FLATDATE',$TimeSerial);

		} elsif ($k eq 'time') {		# 時刻（hhmmss）

			$sStr .= &StrCodec::GetDateTimeString('FLATTIME',$TimeSerial);

		} elsif ($k eq 'datetime') {	# 日時（YYYYMMDDhhmmss）

			$sStr .= &StrCodec::GetDateTimeString('FLAT',$TimeSerial);

		} elsif ($k eq 'number') {		# 通し番号

			if ($cnt < 0) {
				$cnt = &FileClerk::IncreaseCounterModeMAGI( $cFolder );
			}

			if ($cnt >= 0) {

				$sStr .= sprintf("%06d",$cnt);

			} else {

				$flg = -1;

			}

		} else {						# お前なんか知らない。

			$flg = -1;

		}
	}

	return(-1) if ($flg < 0);

	$reqHash{ $rpKey } = $sStr;

	return(1);
}


#-------------------------------------------------------------------------------
# 設定情報からデータを取り出して送信する
#
#　戻り値
#　　送信した回数／負の数でエラー
#
sub MailSender {

	my $drec = $_[0];	# 送信情報設定が書かれているディレクティブ名

	my $To;
	my $From;
	my $Subj;
	my $Cont = '';

	my $tPath;
	my @cAr;
	my $flg;

	return(0) if ($confHash{$drec}{'To'} eq '');			# 必要なパラメータが設定されていない場合（一応、正常終了扱い）
	return(0) if ($confHash{$drec}{'From'} eq '');
	return(0) if ($confHash{$drec}{'Subject'} eq '');
	return(0) if ($confHash{$drec}{'Content'} eq '');


	$To = &RejoinToAddr($confHash{$drec}{'To'});
	$From = $confHash{$drec}{'From'};
	$Subj = $confHash{$drec}{'Subject'};

	&Templet::ExpandTemplateText( \$Subj,'',\%reqHash,'','' );

	$tPath = $confHash{'Server'}{'DocRoot'}.'/'.$confHash{'Folder'}{'Template'}.'/'. $confHash{$drec}{'Content'};

	$flg = FileClerk::ReadLines( \@cAr,$tPath,'R');

	return(-1) if ($flg < 0);

	foreach(@cAr){
		($Cont .= "\n") if ($Cont ne '');
		$Cont .= $_;
	}

	Templet::ExpandTemplateText( \$Cont,'',\%reqHash,'','' );

	$flg = &NetDeal::SendMail( $To,$From,'','',$Subj,$Cont );


	($flg -= 1)  if ($flg < 0);

	return( $flg );
}


#-------------------------------------------------------------------------------
# メールの宛先アドレスを展開して再連結する。
#
#　戻り値
#　　再構成した宛先アドレス文字列
#
sub RejoinToAddr {

	my $ota = $_[0];	# 宛先アドレス文字列

	my @org;
	my @dst;

	my $ta;


	@org = split(/,/,$ota);

	foreach $ta (@org){

		$ta =~ s/\s+//g;	# メールアドレスに空白文字はいらねぇ。

		unless ($ta =~ /@/) {		# メールアドレスでないものが指定されていた場合、

			$ta = $reqHash{$ta};	# それをキーとしてリクエストパラメータを検索する

			$ta =~ s/\s+//g;
		}

		(push @dst,$ta) if ($ta =~ /@/);
	}

	return( join( ',',@dst ) );
}


#-------------------------------------------------------------------------------
# 受付拒否ドメインリストを読み込む
#
sub ReadDenyDomainListFile {

	my $cfFolder = ''.&GetDataStorageFolderPath().'/';

	if ($confHash{'Operate'}{'DenyDomain'} ne '') {	

		if (&FileClerk::ReadLines( \@DenyDomainList,$cfFolder.$confHash{'Operate'}{'DenyDomain'},'I' ) < 0) {

			undef @DenyDomainList;
		}

	}
}


#-------------------------------------------------------------------------------
# リクエストパラメータを連結する
#
sub JoinRequestParam {

	my $th;
	my $k;

	$th = $confHash{'Merge'};

	foreach $k ( keys( %$th ) ){

		&JoinRequestParam_sub( $k );
	}


	$th = $confHash{'Join'};

	foreach $k ( keys( %$th ) ){

		&JoinRequestParam_sub2( $k );
	}

}


sub JoinRequestParam_sub {		# ↑のサブルーチン（Merge用）

	my $newKey = $_[0];		# 連結したデータを格納するハッシュのキー文字列

	my @list;
	my $delm;
	my $newVal = '';

	@list = split( /,/,$confHash{'Merge'}{$newKey} );

	$delm = shift(@list);
	$delm =~ s/^\s+|\s+$//g;

	foreach(@list){

		$_ =~ s/^\s+|\s+$//g;

		last if ($_ eq '');
		next if ($reqHash{ $_ } eq '');

		($newVal .= $delm) if ($newVal ne '');

		$newVal .= $reqHash{ $_ };
	}

	$reqHash{ $newKey } = $newVal;
}


sub JoinRequestParam_sub2 {		# 同上（Join用）

	my $newKey = $_[0];		# 連結したデータを格納するハッシュのキー文字列

	my @list;
	my $newVal = '';

	@list = split( /,/,$confHash{'Join'}{$newKey} );

	foreach(@list){

		$_ =~ s/^\s+|\s+$//g;

		$newVal .= $reqHash{ $_ };
	}

	$reqHash{ $newKey } = $newVal;
}


#-------------------------------------------------------------------------------
# 外部ファイルに記述されたCSV行のフィールド構造を読み出す
#
sub ReadCsvFieldInfoFromExternalFile {

	my $cfFolder = ''.&GetDataStorageFolderPath().'/';

	my @list;

	if ($confHash{'DataFile'}{'List'} eq '') {			# 書き出しリストが未定義で
		if ($confHash{'DataFile'}{'ListEx'} ne '') {	# 外部ファイルが指定されている場合

			if (&FileClerk::ReadLines( \@list,$cfFolder.$confHash{'DataFile'}{'ListEx'},'I' ) > 0) {

				$confHash{'DataFile'}{'List'} = join(',',@list);

			}
		}
	}

	undef @list;

	if ($confHash{'DataFile'}{'Crypt'} eq '') {			# 暗号化リストが未定義で
		if ($confHash{'DataFile'}{'CryptEx'} ne '') {	# 外部ファイルが指定されている場合

			if (&FileClerk::ReadLines( \@list,$cfFolder.$confHash{'DataFile'}{'CryptEx'},'I' ) > 0) {

				$confHash{'DataFile'}{'Crypt'} = join(',',@list);

			}
		}
	}

	undef @list;

	if ($confHash{'Leap'}{'List'} eq '') {			# 中継時保存リストが未定義で
		if ($confHash{'Leap'}{'ListEx'} ne '') {	# 外部ファイルが指定されている場合

			if (&FileClerk::ReadLines( \@list,$cfFolder.$confHash{'Leap'}{'ListEx'},'I' ) > 0) {

				$confHash{'Leap'}{'List'} = join(',',@list);

			}
		}
	}

}


#-------------------------------------------------------------------------------
# 保存するデータCSV行のフィールド構造を展開する
#
sub ExtendCsvFieldInfo {

	my @afn;
	my %cfn;

	my $cnt = 1;


	&ReadCsvFieldInfoFromExternalFile();

	return if ($confHash{'DataFile'}{'List'} eq '');

	if ($confHash{'DataFile'}{'Crypt'} ne '') {

		@afn = split(/,/,$confHash{'DataFile'}{'Crypt'});

		foreach(@afn){
			$_ =~ s/\s+$//g;
			$_ =~ s/^\s+//g;

			$cfn{$_} = 1;
		}
	}


	@afn = split(/,/,$confHash{'DataFile'}{'List'});

	foreach(@afn){
		$_ =~ s/\s+$//g;
		$_ =~ s/^\s+//g;

		if ($cfn{$_} == 1) {

			$CsvFields{$_} = -1 * $cnt;
		} else {

			$CsvFields{$_} = $cnt;
		}

		$cnt++;
	}
}


#-------------------------------------------------------------------------------
# 暗号化パラメータの初期化
#
sub ExtentCryptSeed {

	my @seed;
	my $flg = 0;

	if ($confHash{'DataFile'}{'Seed'} eq ''){

		if ($confHash{'DataFile'}{'Crypt'} ne '') {

			return(-1);
		} else {

			return(0);
		}
	}

	@seed = split(/,/,$confHash{'DataFile'}{'Seed'});

	foreach(@seed){
		unless ($_ =~ /^[0-9]{1,2}$/) {
			$flg = -1;
			last;
		}
	}

	return(-1) if ($flg < 0);	# フォーマットエラー

	return(-1) if ( ($seed[0] < 1) || ($seed[0] > 62) );
	return(-1) if ($seed[1] > 63);
	return(-1) if ($seed[2] > 63);
	return(-1) if ($seed[1] == $seed[2]);

	&StrCodec::InitCipherBase( @seed );

	return(0);
}


