###########################################################################
# Parse for INCM_MODULE
# INCM Plug-in用 Parseモジュール  by GETWILD'74
# 2004/01/27  Ver1.46beta
###########################################################################

 # 一　五明さんのCMLIB15を参考にしました

package Parse;

###########################################################################
#                                                                         #
#  +++ 解析関係 +++                                                       #
#                                                                         #
#                                                                         #

#--------------------------------------------------------------------------
#  Parseクラスのインスタンス生成
#--------------------------------------------------------------------------
sub new{
	my $Class = shift;
	my ($Prm, $Reg) = @_;
	my $Param = {};
	my $DATA = $Param->{DATA} = $INCM_MODULE::DATA;
	my $INI = $DATA->CallObj('INI');

	$Param->{Parse}{Prm} = $Prm;
	$Param->{Parse}{Reg} = $Reg;

	my @IniParam = grep (/^L_(Prm|Reg)/, split("\n", $DATA->CallObj('INI')->GetIni('Basic'))); 
	foreach my $IniParam (@IniParam) {
		if ($IniParam =~ /^L_Prm([^=]+)=(.+)/) {
			&SetPrmL($Param->{Parse}{Prm}, $1, $2);
		} elsif ($IniParam =~ /^L_Reg([^=]+)=(.+)/) {
			&SetPrmL($Param->{Parse}{Reg}, $1, $2);
		}
	}

	sub SetPrmL {
		my $Ref = shift;
		my $Key = shift;
		my $Value = shift;
		my @Names = split(/:/, $Key);
		my $LastName;
		while (my $Name = shift @Names) {
			if (@Names > 0) {
				$Ref = \%{$Ref->{$Name}};
			} else {
				$LastName = $Name;
			}
		}
		if ($Value =~ /^.*?=>.*?,?/) {
			my @Pair = split(/,/, $Value);
			foreach my $Pair (@Pair) {
				my ($vKey, $vValue) = split(/=>/, $Pair);
				$vValue =~ s/#Comma#/,/;
				$Ref->{$LastName}{$vKey} = $vValue;
			}
		} elsif ($Value =~ /[^\\],/) {
			my @Array = split(/,/, $Value);
			@{$Ref->{$LastName}} = @Array;
		} else {
			$Ref->{$LastName} = $Value;
		}
	}

	foreach my $Type (@{$Param->{Parse}{Prm}{Type}}) {
		$Param->{Parse}{Prm}{Main}{ReadPoint} = 'Date' if ($Type eq 'Date' && !$Param->{Parse}{Prm}{Main}{ReadPoint});
	}

	foreach my $Types (@{$Param->{Parse}{Prm}{Type}}) {
		my $Type = 'Main' if ($Types eq 'Date' || $Types eq 'Thread');
		my $DatePrm = $Param->{Parse}{Reg}{$Type}{Date}{Value};
		if ($Param->{Parse}{Reg}{$Type}{Date}{Opt} eq 'Easy') {
			$Param->{Parse}{Reg}{$Type}{Date}{DatePrm}{Y} = $1 if ($DatePrm =~ /Y(\d)/);
			$Param->{Parse}{Reg}{$Type}{Date}{DatePrm}{M} = $1 if ($DatePrm =~ /M(\d)/);
			$Param->{Parse}{Reg}{$Type}{Date}{DatePrm}{D} = $1 if ($DatePrm =~ /D(\d)/);
			$Param->{Parse}{Reg}{$Type}{Date}{DatePrm}{H} = $1 if ($DatePrm =~ /H(\d)/);
			$Param->{Parse}{Reg}{$Type}{Date}{DatePrm}{'m'} = $1 if ($DatePrm =~ /m(\d)/);
			$DatePrm =~ s/[YMDHm]\d/(\\d+)/g;
			$Param->{Parse}{Reg}{$Type}{Date}{Value} = $DatePrm;
		}
	}

	foreach my $Type (keys %{$Param->{Parse}{Reg}}) {
		next if ($Type =~ /^\d{3}$/);
		my @WKEY;
		$Param->{Parse}{Reg}{$Type}{WKEY} = undef;
		foreach my $Name (keys %{$Param->{Parse}{Reg}{$Type}}) {
			next if ($Name eq 'WKEY' || $Name eq 'Comment' || $Name eq 'Attachment');
			push (@WKEY, "$Name,$Param->{Parse}{Reg}{$Type}{$Name}{No}");
		}
		@{$Param->{Parse}{Reg}{$Type}{WKEY}} = sort {(split(',', $a))[1] <=> (split(',', $b))[1]} @WKEY;
	}

	$DATA->DebugWrite;
	bless $Param, $Class;
}

#--------------------------------------------------------------------------
#  解析パラメータを返す
#--------------------------------------------------------------------------
sub GetPrm{
	my $Class = shift;
	my @Param = @_;
	my @ParamDebug = @Param;
	my $Ref = $Class->{Parse}{Prm}; my $LastName;
	while (my $Name = shift @Param) {
		if (@Param > 0) {
			$Ref = $Ref->{$Name};
		} else {
			$LastName = $Name;
		}
	}
	return $Ref->{$LastName};
}

#--------------------------------------------------------------------------
#  記事解析定義を返す
#--------------------------------------------------------------------------
sub GetReg{
	my $Class = shift;
	my @Param = @_;
	my @ParamDebug = @Param;
	my $Ref = $Class->{Parse}{Reg}; my $LastName;
	while (my $Name = shift @Param) {
		if (@Param > 0) {
			$Ref = $Ref->{$Name};
		} else {
			$LastName = $Name;
		}
	}
	return $Ref->{$LastName};
}

#--------------------------------------------------------------------------
#  記事解析結果を返す
#--------------------------------------------------------------------------
sub GetResult{
	my $Class = shift;
	my @Param = @_;
	my @ParamDebug = @Param;
	my $Ref = $Class->{Result}; my $LastName;
	while (my $Name = shift @Param) {
		if (@Param > 0) {
			$Ref = $Ref->{$Name};
		} else {
			$LastName = $Name;
		}
	}
	return $Ref->{$LastName};
}

#--------------------------------------------------------------------------
#  記事かどうか特定する
#--------------------------------------------------------------------------
sub Found{
	my $Class = shift;
	my $Type = $Class->{DATA}->GetRound('Type');
	my $STR = $Class->{DATA}{String};
	my $PTR = $Class->{Parse}{Reg}{$Type}{$Class->{Parse}{Prm}{$Type}{Found}}{Value};
	my $Pass = $Class->{Parse}{Prm}{$Type}{PassFound};
	my $Debug = '$Class->{Parse}{Prm}{'.$Type.'}{Found} = '.$Class->{Parse}{Prm}{$Type}{Found}."\n";
	$Debug .= '			$PTR = '.$PTR."\n";
	$Debug .= '			$Pass = '.$Pass."\n";

	if ($Pass && $STR =~ /$Pass/) {
		$Debug .= '			return = 1[Pass]';
		$Class->{DATA}->DebugWrite(Code => $Debug);
		return 1;
	} elsif ($PTR eq 'AUTO' || $Class->{Parse}{Reg}{$Type}{$Class->{Parse}{Prm}{$Type}{Found}}{Opt} eq 'Easy') {
		if ($Class->{Parse}{Prm}{$Type}{Found} eq 'Date') {
			my $Date;
			$Date = $Class->GetDate;
			if ($Date) {
				$Debug .= '			return = 1';
				$Class->{DATA}->DebugWrite(Code => $Debug);
				return 1;
			}
		}
	} elsif ($STR =~ /$PTR/) {
		$Debug .= '			return = 1';
		$Class->{DATA}->DebugWrite(Code => $Debug);
		return 1;
	} else {
		$Debug .= '			return = 0';
		$Class->{DATA}->DebugWrite(Code => $Debug);
		return 0;
	}
}

#--------------------------------------------------------------------------
#  TITLEタグを抽出
#--------------------------------------------------------------------------
sub GetTitle{
	my $Class = shift;
	my $Title = shift;
	my $DATA = $Class->{DATA};
	my $RET = "";

	my $HTTP = $DATA->CallObj('HTTP');
	my $LOG = $DATA->CallObj('LOG');

	my $CmtNo;
	if ($Title->{SetNo}) {
		$CmtNo = $DATA->GetRound('CMT', 'No');
	}

	if ($Title->{Mode} eq 'Fix') {
		my $Fix = $Title->{Value};
		$RET = "#T:$CmtNo$Fix\n#N:0\n#U:0\n#B:0\n";
	} else {
		my $CnvMethode = $DATA->GetRound('CnvMethod');
		while (my $STR = $HTTP->Read("\n")) {
			CodeCnv->$CnvMethode(\$STR) if ($CnvMethode);
			$LOG->Write($STR);
			if ($Title->{Mode} eq 'Match') {
				if ($STR =~ /$Title->{Value}/i) {
					$STR = $1; $STR =~ s/[\r\n]//g;
					$STR =~ s/$Title->{Cut}//;
					$RET = "#T:$CmtNo$STR\n#N:0\n#U:0\n#B:0\n";
					CMT->DelTag(\$RET); last;
					CMT->UnAmp(\$RET); last;
				}
			} elsif ($STR =~ /^([^<]*)<\/title/i || $STR =~ /<title>(.*?)<\/title>/i) {
				$STR = $1; $STR =~ s/[\r\n]//g;
				$STR =~ s/$Title->{Cut}//;
				$RET = "#T:$CmtNo$STR\n#N:0\n#U:0\n#B:0\n";
				CMT->UnAmp(\$RET); last;
			}
		}
	}
	$RET;		# 戻り値
}

#--------------------------------------------------------------------------
#  GetForm:	Form情報の取得
#--------------------------------------------------------------------------
sub GetForm{
	my $Class = shift;
	my $Param = { @_ };
	my $IconList = "";
	local ($/, $Form, $SubFlag, $Title, $HR, $Option, $STR, $Name, $Check, $Value)
					 = (">", "", 0, "No title", "<hr", "", "", "", "", "");

	my $HTTP = $Class->HandleSet(Select => 'HTTP');
	my $LOG  = $Class->HandleSet(Select => 'LOG');

	print STDOUT "\nForm scanning...\n";

	while ($STR = <$HTTP>) {
		print $LOG $STR;
		if ($STR =~ /<\/form/i) { last; }				# 入力フォーム最後なら解析終了
		elsif ($STR =~ /<form/i) {						# 書き込み先アドレス抽出
			$HR = "<HR" if ($STR =~ /<FORM/);			# タグが大文字
			$STR =~ /action *=[ \"]*([^\" >]+)/i; $Class->{UpUrl} = $1;
			if ($Class->{UpUrl} =~ /^\//) { $Class->{UpUrl} = "http://$Class->{Host}$Class->{UpUrl}"; }
			else {
				$Class->{UpUrl} =~ s/^\.\///;
				my $a = $Class->{Uri}; $a =~ s/[^\/]+$//;
				$Class->{UpUrl} = "http://$Class->{Host}$a$Class->{UpUrl}";
			}
		}
		elsif ($STR =~ /<hr/i) { last if ($SubFlag); }
		elsif ($STR =~ /<textarea/i) {
			$STR =~ /name *=[ \"]*([^ "\>]+)/i; $Form .= "\&$1=\$M";
		}
		elsif ($STR =~ /<select/i) {
			$STR =~ /name *=[ \"]*([^ "\>]+)/i; $Name = $1; $Option = "";
		}
		elsif ($STR =~ /^([^\xff]*)<option .*?value *=[ \"]*([^ "\>]+)/i) {
			my $sval = $2; my $slbl = $1; $slbl =~ s/(\r|\n| |　)*$//;
			$slbl =~ s/,/，/g;
			$Option = $sval if ($STR =~ /selected/ || (!$Option));
			$IconList .= "$slbl,$sval," if ($Name =~ /icon/i);
		}
		elsif ($STR =~ /^([^\xff]*)<\/select/i) {
			my $slbl = $1; $slbl =~ s/(\r|\n| |　)*$//; $slbl =~ s/,/，/g;
			$IconList .= "$slbl," if ($Name =~ /icon/i);
			$Form .= "\&$Name=$Option";
		}
 #<option value="1.gif">アイコン1\n<option value="2.gif">アイコン2\n</select>

		elsif ($STR =~ /<input/i)  {
			$Check = /checked/;
			$STR =~ /name *=[ \"]*([^ \">]+)/i;  $Name = $1;
			$Value = ""; $Value = $1 if $STR =~ /value *=[ \"]*([^\" >]+)/i;

			if ($STR =~ /type *=[ \"]*([^ \">]+)/i) { $STR = $1; }
			else { $STR = "text"; }

			if   ($STR =~ /submit/i)   { $SubFlag = 1; }
			elsif($STR =~ /hidden/i)   { $Form .= "\&$Name=$Value"; }
			elsif($STR =~ /radio/i)    { $Form .= "\&$Name=$Value" if($Check); }
			elsif($STR =~ /checkbox/i) { $Form .= "\&$Name=$Value" if($Check); }
			elsif($STR =~ /password/i) { $Form .= "\&$Name=\$K"; }
			elsif($STR =~ /text/i){
				$STR = $Name;
				if   ($STR =~ /mail/i) { $Form .= "\&$STR=\$E"; }
				elsif($STR =~ /name|nm|handle|sender|namae/i) { $Form .= "\&$STR=\$N"; }
				elsif($STR =~ /(title|sub)/i) { $Form .= "\&$STR=\$T"; }
				elsif($STR =~ /(url|link|web|home|page)/i) { $Form .= "\&$STR=\$H"; }
				elsif($STR =~ /res/i) { $Form .= "\&$STR=\$Sr"; }
				elsif($STR =~ /(rmkey|key|city|pass)/i) { $Form .= "\&$STR=\$K"; }
				else { $Form .= "\&$STR=???"; }
			}
		}
		elsif ($STR =~ /^([^<]+)<\/title/i) { $Title = $1; $Title =~ s/[\r\n]//g; }
	}

	$/ = $HR;

	$Form =~ s/^\&/POST,\$c,/;
 #print "#T:$title\n#N:0\n#U:0\n#B:0\n";

	$IconList =~ s/^[^\,]*,//;
	$IconList =~ s/([^\,]*),([^\,]*),/$2,$1,/g;
	$IconList =~ s/,$//;
	$Class->{IconList} = $IconList;

 return $Form;				# 戻り値
}

#--------------------------------------------------------------------------
#  GetDate:	日付の取得
#   GetDate;
#    午前12時→0、午前0〜11時そのまま、
#    午後12時そのまま、午後0〜11時→+12
#--------------------------------------------------------------------------
sub GetDate{
	my $Class = shift;
	my $Param = { @_ };
	my $DATA = $Class->{DATA};
	my $Date = $DATA->{String};
	my $Type = $DATA->GetRound('Type');
	my ($e, $f) = ("", "");

	# 変換用英月名
	my %Month=("Jan" => 1,  "Feb" => 2,  "Mar" => 3,  "Apr" => 4,  "May" => 5,  "Jun" => 6,
			"Jul" => 7,  "Aug" => 8,  "Sep" => 9,  "Oct" => 10, "Nov" => 11, "Dec" => 12);

	if ($Class->{Parse}{Reg}{$Type}{Date}{Opt} eq 'Easy') {
		if ($Date =~ /$Class->{Parse}{Reg}{$Type}{Date}{Value}/) {
			my %DatePrm = %{$Class->{Parse}{Reg}{Main}{Date}{DatePrm}};
			if (!$DatePrm{Y}) {
				$Date = sprintf("/%2.2d/%2.2d,%2.2d:%2.2d", ${$DatePrm{M}},${$DatePrm{D}},${$DatePrm{H}},${$DatePrm{'m'}});
			} else {
				$Date = sprintf("%2.2d/%2.2d/%2.2d,%2.2d:%2.2d", ${$DatePrm{Y}},${$DatePrm{M}},${$DatePrm{D}},${$DatePrm{H}},${$DatePrm{'m'}});
			}
		} else { $Date = ''; }
	} elsif ($Date =~ /((\d+)年)? *(\d+)月 *(\d+)日(\D+)(\d+)時 *(\d+)分/) {
		$e = $5; $f = $6 + 12;
		$Date = sprintf("$2/%2.2d/%2.2d,%2.2d:%2.2d", $3,$4,$6,$7);
		$Date =~ s/\,\d\d:/\,00:/  if ($e =~ /午前/ && ($f == 24));
		$Date =~ s/\,\d\d:/\,$f:/  if ($e =~ /午後/ && ($f != 24));

	} elsif ($Date =~ /((\d+)\/)?(\d+)\/(\d+)[^\d\n]+(\d+):(\d+)/) {
		if ($1) {
			$Date = sprintf("%2.2d/%2.2d/%2.2d,%2.2d:%2.2d", $2,$3,$4,$5,$6);
		} else {
			$Date = sprintf("/%2.2d/%2.2d,%2.2d:%2.2d", $3,$4,$5,$6);
		}

	} elsif ($Date =~ /(\d+)[\/\.] ?(\d+)[\/\.] ?(\d+)[^\d\n]+(\d+):(\d+)/) {
		$Date = sprintf("$1/%2.2d/%2.2d,%2.2d:%2.2d", $2,$3,$4,$5);

	} elsif ($Date =~ /(\d+)[ \n]+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ \n]+(\d\d\d\d)[ \n]+(\d+):(\d+):\d+/) {
		$Date = sprintf("$3/%2.2d/%2.2d,%2.2d:%2.2d", $Month{$2},$1,$4,$5);

	} elsif ($Date =~ /(\d\d?)\/ ?(\d\d?)[ \(]*(Sun|Mon|Tue|Wed|Thu|Fri|Sat|日|月|火|水|木|金|土| *)[ \)]*(\d\d?):(\d\d?)/) {
		$Date = sprintf("/%2.2d/%2.2d,%2.2d:%2.2d", $1,$2,$4,$5);

	} elsif ($Date =~ /((\d+))?[\/-] ?(\d\d?)[\/-] ?(\d\d?)[ \(]*(Sun|Mon|Tue|Wed|Thu|Fri|Sat|日|月|火|水|木|金|土| *)[ \)]*((\d\d?):(\d\d?))?/) {
		$Date = sprintf("$2/%2.2d/%2.2d,%2.2d:%2.2d", $3,$4,$7,$8);

	} elsif ($Date =~ /(\d+)[\/\.] ?(\d+)[-^\d\n]+(\d+):(\d+)/) {
		$Date = sprintf("/%2.2d/%2.2d,%2.2d:%2.2d", $1,$2,$3,$4);

	} elsif ($Date =~ /(\d+)?\/?(\d+)\/(\d+)/) {
		if ($1) {
			$Date = sprintf("%2.2d/%2.2d/%2.2d,00:00", $1,$2,$3);
		} else {
			$Date = sprintf("/%2.2d/%2.2d,00:00", $2,$3);
		}

	} else {
		$Date = '';
	}

	if ($Date =~ /^\/(\d\d)/) {					# 年が無いシステムで補完
		($e, $f) = (localtime)[5,4];					# 年,月
		$e -= 1  if (($f+2) < $1);						# 1ヶ月後より後なら前年
		$e += 1900;
		$Date = $e.$Date;

	} elsif ($Date =~ s/^(\d{1,3})\///) {			# 4桁以下なら年を補完
		$e = $1 + 1900;  $e += 100 if ($e < 1980);
		$Date = "$e/$Date";
	}

	if ($Class->{Parse}{Reg}{$Type}{PassDate}{Value} && !$Date) {
		$Date = $Class->{Result}{$Type}{Date} if ($DATA->{String} =~ /$Class->{Parse}{Reg}{$Type}{PassDate}{Value}/);
	}

	$Class->{Result}{$Type}{Date} = $Date if ($Date);
	return $Date;			# 戻り値
}

#--------------------------------------------------------------------------
#  GetUrl:		HPのアドレス抽出
#   
#--------------------------------------------------------------------------
sub GetUrl{

	my $Class = shift;
	my $Mode = shift;
	my $STR; my $Url;
	my $DATA = $Class->{DATA};
	my $Type = $DATA->GetRound('Type');
	$Class->{Result}{$Type}{Url} = '' if ($Mode ne 'Shape');
	$Class->{Result}{$Type}{UData}{Url} ='';

	if ($DATA->GetRound('String' ,'Head')) {
		$STR = $DATA->GetRound('String' ,'Head');
	} else {
		$STR = $DATA->{String};
	}

	# 抽出&整形
	if ($Mode eq 'Shape') {
		$Url = $Class->{Result}{$Type}{Url};
	} else {
		if($STR =~ /<a *href *= *[\"\']?(http:[^\"\'\n> ]+)/i){
			$Url = $1;
			if (my $Eval = $Class->{Parse}{Reg}{$Type}{Url}{Eval}) {
				$Url = eval($Eval);
			}
		}
	}
	my $UrlLink = $Url;
	if ($Url) {
		if ($DATA->CallObj('INCM')->GetMode('HtmlView')) {
			$UrlLink = "<a href =\"$Url\" target=\"_blank\">$Url</a><br>";
		}
		$Class->{Result}{$Type}{UData}{Url} = "     $UrlLink\n" unless ($DATA->CallObj('INCM')->GetMode('UpLoad'));
		$Class->{Result}{$Type}{Url} = "H:$Url\n";
	}

	return $Url;
}

#--------------------------------------------------------------------------
#  GetMail:		メールアドレス抽出
#   
#--------------------------------------------------------------------------
sub GetMail{

	my $Class = shift;
	my $Mode = shift;
	my $STR;
	my ($Mail, $MailLink);
	my $DATA = $Class->{DATA};
	my $Type = $DATA->GetRound('Type');
	$Class->{Result}{$Type}{Mail} = '' if ($Mode ne 'Shape');
	$Class->{Result}{$Type}{UData}{Mail} ='';

	if ($DATA->GetRound('String' ,'Head')) {
		$STR = $DATA->GetRound('String' ,'Head');
	} else {
		$STR = $DATA->{String};
	}

	# 抽出&整形
	if ($Mode eq 'Shape') {
		$Mail = $Class->{Result}{$Type}{Mail};
		$MailLink = "mailto:$Mail";
	} else {
		if($STR =~ /<a *href *= *[\"\']?(mailto:([^\"\'\n> ]+))/i){
			$MailLink = $1; $Mail = $2;
		}
	}
	if ($Mail) {
		if ($DATA->CallObj('INCM')->GetMode('HtmlView')) {
			$MailLink = "<a href =\"$MailLink\">$Mail</a><br>";
		}
		$Class->{Result}{$Type}{UData}{Mail} = "     $MailLink\n" unless ($DATA->CallObj('INCM')->GetMode('UpLoad'));
		$Class->{Result}{$Type}{Mail} = "E:$Mail\n";
	}

	return $Mail
}

#--------------------------------------------------------------------------
#  HTMLソースの解析とCMT出力処理
#--------------------------------------------------------------------------
sub Parse{
	my $Class = shift;
	my $STR;
	my $DATA = $Class->{DATA};
	my $Type = $DATA->GetRound('Type');
	my $String = $DATA->{String};
	my $Debug;
	$Debug = 'Type = '.$Type."\n";

	# 定義があれば記事をヘッダと本文に分割
	$Debug .= '			HeadBody = '.$Class->{Parse}{Prm}{$Type}{HeadBody}."\n";
	if ($Class->{Parse}{Prm}{$Type}{HeadBody}) {
		my ($Head, $Body) = split(/$Class->{Parse}{Prm}{$Type}{HeadBody}/, $String);
		$DATA->SetRound(Name => 'String,Head', Data => $Head);
		$DATA->SetRound(Name => 'String,Body', Data => $Body);
		$Debug .= '			Head = '.$Head."\n";
		$Debug .= '			Body = '.$Body."\n";
	}

	# ヘッダ用文字列セット
	if ($DATA->GetRound('String' ,'Head')) {
		$STR = $DATA->GetRound('String' ,'Head');
	} else {
		$STR = $String;
	}

	# 記事ヘッダ解析
	foreach my $Key (@{$Class->{Parse}{Reg}{$Type}{WKEY}}) {
		$Key = (split(',', $Key))[0];
		next if ($Key =~ /^CommentC?$/);
		$Option = 's'.$Class->{Parse}{Reg}{$Type}{$Key}{Opt};
		my $CKey = $Key; $CKey =~ s/C$//;
		my %ParseCom;
		if ($Class->{Result}{$Type}{Root} && $Key =~ /C$/) {
			%ParseCom = %{$Class->{Parse}{Reg}{$Type}{$Key}};
		} elsif (!$Class->{Result}{$Type}{Root} && $Key !~ /C$/) {
			%ParseCom = %{$Class->{Parse}{Reg}{$Type}{$Key}};
		} elsif ($Class->{Result}{$Type}{Root} && $Key !~ /C$/ && !$Class->{Parse}{Reg}{$Type}{$Key.C}{Value}) {
			%ParseCom = %{$Class->{Parse}{Reg}{$Type}{$Key}};
		}
		next if (!$ParseCom{Value});
		my $StrBak = $STR; my $StrFlag;
		if ($ParseCom{Str} eq 'All') {
			$STR = $DATA->{String}; $StrFlag = 1;
		} elsif ($ParseCom{Str} eq 'Body') {
			$STR = $DATA->GetRound('String', Body);
			$StrFlag = 1;
		}
		if ($ParseCom{Value} eq 'Pass' || $ParseCom{Value} eq 'TreeNumData') {
			$Class->{Result}{$Type}{$CKey} = '';
			next;
		}
		'##' =~ /#(.*?)#/;
		if ($ParseCom{Value} eq 'AUTO') {
			if ($CKey eq 'Date') {
				$Class->GetDate;
			} elsif ($CKey eq 'Mail') {
				$Class->GetMail;
			} elsif ($CKey eq 'Url') {
				$Class->GetUrl;
			}
		} elsif ($Option eq 'sEasy') {
			if ($CKey eq 'Date' && $STR =~ /$ParseCom{Value}/) {
				$Class->GetDate;
			} elsif ($ParseCom{Set}) {
				$Class->{Result}{$Type}{$CKey} = $Class->{Result}{$Type}{Bak}{$ParseCom{Set}};
			}
		} elsif ($Option =~ /m/) {
			if ($Option =~ /i/) {
				$STR =~ /$ParseCom{Value}/is;
				$Class->{Result}{$Type}{$CKey} = ${$ParseCom{Match}};
			} else {
				$STR =~ /$ParseCom{Value}/s;
				$Class->{Result}{$Type}{$CKey} = ${$ParseCom{Match}};
			}
		} else {
			if ($Option =~ /i/) {
				$STR =~ s/$ParseCom{Value}//is;
				$Class->{Result}{$Type}{$CKey} = ${$ParseCom{Match}};
			} else {
				$STR =~ s/$ParseCom{Value}//s;
				$Class->{Result}{$Type}{$CKey} = ${$ParseCom{Match}};
			}
		}
		if ($Key =~ /^Option([^\d]+)(\d+)/) {
			my ($OptName, $OptNo) = ($1, $2);
			$OptName .= 'C' if ($Key =~ /C$/);
			$Class->{Result}{$Type}{Option}{$OptName} = $OptNo if ($Class->{Result}{$Type}{Option}{$OptName} < $OptNo);
		}
		if ($ParseCom{Eval}) {
			my $Text = $Class->{Result}{$Type}{$CKey};
			$Class->{Result}{$Type}{$CKey} = eval($ParseCom{Eval});
		}
		if ($CKey eq 'Mail' || $CKey eq 'Url') {
			if ($ParseCom{Value} ne 'AUTO') {
				my $Method = "Get$CKey";
				$Class->$Method('Shape');
			}
		}
		if ($CKey eq 'Date' && $ParseCom{Shape}) {
			my $Date = $Class->{Result}{$Type}{$CKey};
			$Class->{Result}{$Type}{$CKey} = eval($ParseCom{Shape});
		}
		if ($StrFlag) {
			$StrFlag = undef;
			$STR = $StrBak;
		}
		$Debug .= '			$Class->{Result}{'.$Type.'}{'.$CKey.'} = '.$Class->{Result}{$Type}{$CKey}."\n";
	}

	foreach my $BakKey (keys %{$Class->{Result}{$Type}}) {
		$Class->{Result}{$Type}{Bak}{$BakKey} = $Class->{Result}{$Type}{$BakKey};
	}

	# 本文用文字列セット
	if ($DATA->GetRound('String' ,'Body')) {
		$STR = $DATA->GetRound('String' ,'Body');
	} else {
		$STR = $String;
	}

	# 記事本文解析
	my @ParseCom;
	if ($Class->{Result}{$Type}{Root} && $Class->{Parse}{Reg}{$Type}{CommentC}{Value}) {
		%ParseCom = %{$Class->{Parse}{Reg}{$Type}{CommentC}};
		$Option = 's'.$Class->{Parse}{Reg}{$Type}{CommentC}{Opt};
	} else {
		%ParseCom = %{$Class->{Parse}{Reg}{$Type}{Comment}};
		$Option = 's'.$Class->{Parse}{Reg}{$Type}{Comment}{Opt};
	}
	if ($ParseCom{Value}) {
		if ($Option =~ /m/) {
			if ($Option =~ /i/) {
				$STR =~ /$ParseCom{Value}/is;
				$Class->{Result}{$Type}{Comment} = ${$ParseCom{Match}};
			} else {
				$STR =~ /$ParseCom{Value}/s;
				$Class->{Result}{$Type}{Comment} = ${$ParseCom{Match}};
			}
		} else {
			if ($Option =~ /i/) {
				$STR =~ s/$ParseCom{Value}//is;
				$Class->{Result}{$Type}{Comment} = ${$ParseCom{Match}};
			} else {
				$STR =~ s/$ParseCom{Value}//s;
				$Class->{Result}{$Type}{Comment} = ${$ParseCom{Match}};
			}
		}
		if ($ParseCom{Eval}) {
			eval($ParseCom{Eval});
		}
		$Debug .= '			$Class->{Result}{'.$Type.'}{Comment} = '.$Class->{Result}{$Type}{Comment}."\n";
	}

	# 添付ファイル解析
	foreach my $Attachment (@{$Class->{Parse}{Reg}{$Type}{Attachment}}) {
		if (my $PTR = $Attachment->{Value}) {
			$Debug .= '			Attachment = Read'."\n";
			my $STR = $Class->{Result}{$Type}{$Attachment->{Target}};
			if ($Attachment->{Target} eq 'Head') {
				$STR = $DATA->GetRound('String' ,'Head');
			} elsif ($Attachment->{Target} eq 'Body') {
				$STR = $DATA->GetRound('String' ,'Body');
			} elsif ($Attachment->{Target} eq 'String') {
				$STR = $String;
			}
			my $INI = $DATA->CallObj('INI');
			my $UriBase = $INI->GetParam('Host').$INI->GetParam('Uri'); $UriBase =~ s/[^\/]+$//;
			$UriBase = 'http://'.$UriBase;
			if ($INI->GetParam('FileDown', 'L') && $STR =~ /$PTR/) {
				my $URL;
				$URL = $UriBase if (${$Attachment->{Match}} !~ /^http:/);
				$STR =~ /$PTR/;
				my $FileUrl = ${$Attachment->{Match}};
				if ($FileUrl =~ /^http/) {
					$URL = $FileUrl;
				} else {
					$FileUrl =~ s/^[\.]+\///;
					$URL .= $FileUrl;
				}
				my $File = $1 if ($URL =~ /\/([^\/]+)$/);
				$DATA->CallObj('HTTP')->FileDownLoad($URL, $File);
				if ($File =~ /\.(png|jpg|jpeg|gif)$/i) {
					$STR =~ s/$PTR/#img src="DownLoad\/$File"#/;
				} else {
					$STR =~ s/$PTR/#a href="DownLoad\/$File"#$File#\/a#/;
				}
				$Class->{Result}{$Type}{Comment} = $STR;
			} else {
				my $PUT1 = '[添付ファイル:';
				my $PUT2 = ']<br>'; my $AtStr;
				$PUT2 =~ s/<br>/\n/ if($Class->{DATA}->CallObj('INI')->GetParam('BBS_Name', 'L') =~ /^CMT/);
				if ($STR =~ /$PTR/ && ${$Attachment->{Match}} !~ /^http:/) {
					$PUT1 .= $UriBase ;
					$STR =~ /$PTR/; my $URL = ${$Attachment->{Match}};
					$URL =~ s/^[\.]+\///;
					$AtStr = $PUT1.$URL.$PUT2;
				} elsif ($STR =~ /$PTR/) {
					$AtStr = $PUT1.${$Attachment->{Match}}.$PUT2;
				}
				$Class->{Result}{$Type}{Comment} .= $AtStr;
			}
		}
	}

	if ($Class->{Parse}{Reg}{$Type}{ResNum}{Value} eq 'TreeNumData') {
		$Debug .= '			TreeNumData = Read'."\n";
		my $DataType = $Class->{Parse}{Reg}{$Type}{ResNum}{Set};
		$Class->{Result}{$Type}{ResNum} = $1 if ($Class->{Result}{$DataType}{TreeNumData} =~ / $Class->{Result}{$Type}{Num}:(\d+)/);
	}

	# 記事番号＆ルート記事設定
	$Class->{Result}{$Type}{Num} = '*' unless ($Class->{Result}{$Type}{Num});
	if ($Class->{Result}{$Type}{Root}) {
		$Class->{Result}{$Type}{ResNum} = $Class->{Result}{$Type}{NumBak};
	} elsif (!$Class->{Parse}{Reg}{$Type}{ResNum}{Value}) {
		$Class->{Result}{$Type}{ResNum} = '';
		$Class->{Result}{$Type}{NumBak} = $Class->{Result}{$Type}{Num};
	} elsif ($Class->{Result}{$Type}{ResNum} eq $Class->{Result}{$Type}{Num}) {
		$Class->{Result}{$Type}{ResNum} = '';
	}
	$Debug .= '			$Class->{Result}{'.$Type.'}{ResNum} = '.$Class->{Result}{$Type}{ResNum};

	$DATA->DebugWrite(Code => $Debug);
}

#--------------------------------------------------------------------------
#  スクリプト種別の自動判別
#--------------------------------------------------------------------------
sub AutoSelect {
	my $Class = shift;
	my $Param = { @_ };
	my ($BBS_Name, $BBS_Ver);
	my $HOST = $Param->{HOST}; # 解析用HOST定義
	my $URL  = $Param->{URL};  # 解析用URL定義
	my $HTML = $Param->{HTML}; # 解析用HTML定義
	my $PtrCnt = 0; # 標準出力クリア用カウンタ
	my $HTTP = $Param->{DATA}->CallObj('HTTP');
	my $INI = $Param->{DATA}->CallObj('INI');
	my $PlugName;
	my $SetUrl = 'http://'.$INI->GetParam('Host').$INI->GetParam('Uri');
	my $SetHost = $INI->GetParam('Host');

	LOOP:{
		print STDOUT "\n",'掲示板判別中 : ';

		foreach my $Key (keys %{$HOST}) {
			if ($PtrCnt > 100) {
				print STDOUT "\n",'掲示板判別中 : '; $PtrCnt =0;
			}
			print STDOUT '.'; $PtrCnt++;
			my ($Name, $Ver) = $$HOST{$Key}->($SetUrl);
			if ($Name && $Ver) {
					$BBS_Name = $INI->SetParam('BBS_Name', 'L', $Name);
					$BBS_Ver = $INI->SetParam('BBS_Ver', 'L', $Ver);
					$PlugName = $Key; $PlugName =~ s/^([^_]+)_.*?$/$1/;
					last;
			}
		}

		foreach my $Key (keys %{$URL}) {
			if ($PtrCnt > 100) {
				print STDOUT "\n",'掲示板判別中 : '; $PtrCnt =0;
			}
			print STDOUT '.'; $PtrCnt++;
			my ($Name, $Ver) = $$URL{$Key}->($SetUrl);
			if ($Name && $Ver) {
					$BBS_Name = $INI->SetParam('BBS_Name', 'L', $Name);
					$BBS_Ver = $INI->SetParam('BBS_Ver', 'L', $Ver);
					$PlugName = $Key; $PlugName =~ s/^([^_]+)_.*?$/$1/;
					last;
			}
		}

		while (my $STR = $HTTP->Read("\n")) {
			$Class->{Auto}{PointBody} = 1 if ($STR =~ /<body/i);
			if ($PtrCnt > 100) {
				print STDOUT "\n",'掲示板判別中 : '; $PtrCnt =0;
			}
			my $RET = $Class->HtmlPerse(String => $STR, DATA => $Param->{DATA});
			redo LOOP if ($RET eq 'Redo');
			next if ($STR !~ /$Param->{Skip}/s && $Param->{Skip});
			last if ($BBS_Name);
			foreach my $Key (keys %{$HTML}) {
				print STDOUT '.'; $PtrCnt++;
				my ($Name, $Ver) = $$HTML{$Key}->($STR);
				if ($Name && $Ver) {
					$BBS_Name = $INI->SetParam('BBS_Name', 'L', $Name);
					$BBS_Ver = $INI->SetParam('BBS_Ver', 'L', $Ver);
					$PlugName = $Key; $PlugName =~ s/^([^_]+)_.*?$/$1/;
					last;
				}
			}
		}
	}

	if (!$Class->{Auto}{PointBody}) {
		while (my $STR = $HTTP->Read("\n")) {
			$Class->HtmlPerse(String => $STR, DATA => $Param->{DATA});
			last if ($STR =~ /<body/i);
		}
	}

	my $Debug = '$PlugName = '.$PlugName."\n";
	$Debug .= '			$BBS_Name = '.$BBS_Name."\n";
	$Debug .= '			$BBS_Ver = '.$BBS_Ver;
	$Param->{DATA}->DebugWrite(Code => $Debug);

	unless ($BBS_Name) { IO->Error('判別失敗'); }
	print STDOUT "\n",'BBS TYPE = ', $BBS_Name, ' Ver', $BBS_Ver;

	my ($PK, $Call) = caller;
	if ($PK eq 'NewAuto') {
		return $PlugName, $INI->GetBbsData;
	} else {
		return $INI->GetBbsData;
	}

}

#--------------------------------------------------------------------------
#  初回HTML解析
#--------------------------------------------------------------------------
sub HtmlPerse {
	my $Class = shift;
	my $Param = { @_ };
	my $DATA = $Class->{DATA};
	my $STR = $Param->{String};
	my %Code = ('EUC-JP' => 'EucCnv', 'euc-jp' => 'EucCnv', 'X-EUC-JP' => 'EucCnv', 'x-euc-jp' => 'EucCnv',
							'UTF-8' => 'Utf8Cnv', 'utf-8' => 'Utf8Cnv');

	if ($STR =~ /<frame (name=\"?(log|view)\"? )?src=[^?]+\?(.*?)\"?>/) {
		if ($Class->{Uri} =~ /\/[^\/]+\?.+$/) {
			$Class->{Uri} .= '&'.$3;
		} else {
			$Class->{Uri} .= '?'.$3;
		}
		$Class->HttpReq || IO->Error('接続に失敗しました');
		return 'Redo';
	} elsif ($STR =~ m#<META .*? charset *= *(.*?)\">#i || $STR =~ m#Content-type: text/html; charset=([^ \r\n]+)#i) {
		my $Type = $1;
		my $CnvMethod = $Code{$1} if ($Code{$1});
		$DATA->CallObj('INI')->SetParam('CharSet', 'L', $CnvMethod);
		$DATA->SetRound(Name => 'CnvMethod', Data => $CnvMethod);
		my $Debug = 'CharSet = '.$CnvMethod."\n";
		$Debug .= '			$Type = '.$Type;
		$DATA->DebugWrite(Code => $Debug);
	}
}

#--------------------------------------------------------------------------
#  Topic情報取得
#--------------------------------------------------------------------------
sub GetTopic{
	my $Class = shift;
	my $Type = shift;
	my $DATA = $Class->{DATA};
	$DATA->SetRound(Name => 'Type', Data => $Type);
	my $Parse = $DATA->CallObj('Parse');
	my ($NextType, $NextFlag);
	foreach my $TypeText (@{$Class->{Parse}{Prm}{Type}}) {
		if ($TypeText eq $Type) { $NextFlag = 1; next; }
		if ($NextFlag == 1) { $NextType = $TypeText; last; }
	}
	$NextType = 'Main' if ($NextType eq 'Thread' || $NextType eq 'Date');
	if ($Class->{Parse}{Prm}{$NextType}{List} eq $Type) {
		$DATA->SetRound(Name => 'Mode,'.$NextType.',Tree', Data => 1);
	}
	my $RetSetList;
	if ($DATA->GetBasic($Type, 'List')) {
		$RetSetList = $DATA->SetList;
	}
	my $Tree = $DATA->GetRound('Mode',$Type,'Tree');
	my @List; local($List);

	# BaseUrlの設定
	$BaseUri = $DATA->CallObj('INI')->GetParam('Uri');

	# 記事数カウンタ等初期化
	$DATA->SetRound(Name => $Type.',Count,AtclMax', Data => 0);
	$DATA->PrintInfo(PageCountReset => 1);

	# 出力メッセージ設定
	my $InfoMes = 'GetTopic Page #Page#:';
	if (my $Mes = $Class->GetPrm($Type, 'InfoMes')) {
		$InfoMes = $Mes;
	}

	ATCL:{

		$DATA->SetRound(Name => $Type.',ReadEnd', Data => 0);
		unless($Tree) {
			if (!$DATA->GetRound($Type, 'NextPageFlag')) {
				# HTTP接続
				my $Uri = eval($Class->{Parse}{Prm}{$Type}{Uri}) if ($Class->{Parse}{Prm}{$Type}{Uri});
				$DATA->CallObj('HTTP')->GetHttp(Param => $DATA->CallObj('HTTP')->SetPageParam, Uri => $Uri);

				# CMTヘッダ用の設定
				$DATA->CallObj('HeadCMT')->SetHead;

				return if ($RetSetList);
			}
		}

		$DATA->SetRound(Name => 'Count,Info', Data => 0);

		# 各ページ毎の記事数
		$DATA->PrintInfo(AtclCountReset => 1, Info => $InfoMes, PageCount => 1);

		my $Page = $DATA->GetRound($Type, 'Count', 'Page');

		Tree:{
			if ($Tree) {
				@List = @{$Parse->GetResult('GetList', $Parse->GetPrm($Type, 'List'), $Page)} if (!@List);
				last ATCL if (!@List);
				my $Uri;
				if ($Parse->GetPrm($Type, 'PullList') eq 'Shift') {
					$List = shift(@List);
				} else {
					$List = pop(@List);
				}
				$Uri = $List->{List};
				my $SetUri;
				if ($Uri =~ /[^\?]+\?/) {
					$SetUri = $BaseUri.$Uri
				} elsif ($BaseUri =~ /\?/) {
					$SetUri = $BaseUri.'&'.$Uri
				} elsif ($BaseUri =~ /[^\.]+\.[^\.]+$/) {
					$SetUri = $BaseUri.'?'.$Uri
				} else {
					$SetUri = $BaseUri.$Uri
				}
				# 接続出来た
				if($DATA->CallObj('HTTP')->HttpReq(Uri => $SetUri, NoMes => 1, IO => 1)){
					if ($DATA->GetRound('Count', 'Info') > 30) {
						$DATA->PrintInfo(AtclCountReset => 1, Info => $InfoMes, InfoCountReset => 1);
					}
					IO->StdOut('o'); $DATA->{Round}{Count}{Info}++;
				# 接続出来ない
				}else{
					IO->StdOut('x'); next;
				}
			}

			# ページ頭読み飛ばし
			$DATA->CallObj('HTTP')->ReadStep(Read => 'Top');

			# 区切り設定
			$DATA->CallObj('HTTP')->ReadStep(Set => 'Step');
			# 文字コード設定
			my $CnvMethode = $DATA->GetRound('CnvMethod');

			# 区切り毎に、ファイル終端まで $_に読む
			while ($DATA->{String} = $DATA->CallObj('HTTP')->Read) {
				# 文字コード変換
				CodeCnv->$CnvMethode(\$DATA->{String}) if ($CnvMethode);
				# 次ページ解析
				$Class->GetNextPage(\$DATA->{String}) if (!$Class->GetResult($Type, 'NextParam'));

				# LOGへの書き出し
				$DATA->{String} .= "\n\n<!-- ### Step ### -->\n\n" if ($DATA->CallObj('DEBUG'));
				$DATA->CallObj('LOG')->PrintLog(ParaGraphCnv => 1, Parent => $Class);

				# ページ末読み飛ばし
				$DATA->CallObj('HTTP')->ReadStep(Read => 'Bottom');

				if ($DATA->GetRound('Count', 'Info') > 30) {
					$DATA->PrintInfo(Info => $InfoMes, InfoCountReset => 1);
				}

				# Foundが取得出来たら記事とみなす
				if($Class->Found){
					# 読み取り状況表示
					$DATA->PrintInfo(Parent => '.', AtclCount => 1);
					# 解析
					$Class->Parse;
					# 解析結果のセット
					my $Page = $DATA->GetRound($Type, 'Count', 'Page');
					my %Result = %{$Class->{Result}{$Type}};
					push @{$Class->{Result}{GetList}{$Type}{$Page}}, \%Result if ($Class->{Result}{$Type}{List});
					# 未読ポインタより古ければ終了
					last ATCL if($DATA->CompareDate == 1);
					# 未読ポインタ更新チェック
					$DATA->NewPtr;
				}
				last if ($DATA->GetRound($Type, 'ReadEnd'));
			}							# ← while(<HTTP>)の終わり

			if ($Tree) {
				if (!@List) {
					redo ATCL if (@{$Parse->GetResult('GetList', $Parse->GetPrm($Type, 'List'), $Page+1)});
				}
				redo Tree if (@List);
			}
		}							# ← Tree:の終わり

#####  次のページ  #####

		last ATCL unless ($DATA->CallObj('HTTP')->NextPage);			# 戻り値が偽なら抜ける
		redo ATCL;

	}							# ← ATCL: の終わり
}

#--------------------------------------------------------------------------
#  TreeListのセット
#--------------------------------------------------------------------------
sub SetTreeList {
	my $Class = shift;
	my $Param = shift;
	@{$Class->{TreeList}} = @{$Param};
}

#--------------------------------------------------------------------------
#  Tree情報取得
#--------------------------------------------------------------------------
sub GetTree {
	my $Class = shift;
	my $Type = shift;
	my $DATA = $Class->{DATA};
	$DATA->SetRound(Name => 'Type', Data => $Type);
	my $Parse = $DATA->CallObj('Parse');
	my ($Pos, @RootArray); $Pos = 0;
	my ($NextType, $NextFlag);
	foreach my $TypeText (@{$Class->{Parse}{Prm}{Type}}) {
		if ($TypeText eq $Type) { $NextFlag = 1; next; }
		if ($NextFlag == 1) { $NextType = $TypeText; last; }
	}
	$NextType = 'Main' if ($NextType eq 'Thread' || $NextType eq 'Date');
	if ($Class->{Parse}{Prm}{$NextType}{List} eq $Type) {
		$DATA->SetRound(Name => 'Mode,'.$NextType.',Tree', Data => 1);
	}
	my $Tree = $DATA->GetRound('Mode',$Type,'Tree');
	my @List; local($List);

	# BaseUrlの設定
	$BaseUri = $DATA->CallObj('INI')->GetParam('Uri');

	# 記事数カウンタ等初期化
	$DATA->SetRound(Name => $Type.',Count,AtclMax', Data => 0);
	$DATA->PrintInfo(PageCountReset => 1);

	# 出力メッセージ設定
	my $InfoMes = 'GetTree Page #Page#:';
	if (my $Mes = $Class->GetPrm($Type, 'InfoMes')) {
		$InfoMes = $Mes;
	}

	ATCL:{

		$DATA->SetRound(Name => $Type.',ReadEnd', Data => 0);
		unless($Tree) {
			if (!$DATA->GetRound($Type, 'NextPageFlag')) {
				# HTTP接続
				my $Uri = eval($Class->{Parse}{Prm}{$Type}{Uri}) if ($Class->{Parse}{Prm}{$Type}{Uri});
				$DATA->CallObj('HTTP')->GetHttp(Param => $DATA->CallObj('HTTP')->SetPageParam, Uri => $Uri);

				# CMTヘッダ用の設定
				$DATA->CallObj('HeadCMT')->SetHead;
			}
		}

		$DATA->SetRound(Name => 'Count,Info', Data => 0);

		# 各ページ毎の記事数
		$DATA->PrintInfo(AtclCountReset => 1, Info => $InfoMes, PageCount => 1);

		my $Page = $DATA->GetRound($Type, 'Count', 'Page');

		Tree:{
			if ($Tree) {
				@List = @{$Parse->GetResult('GetList', $Parse->GetPrm($Type, 'List'), $Page)} if (!@List);
				last ATCL if (!@List);
				my $Uri;
				if ($Parse->GetPrm($Type, 'PullList') eq 'Shift') {
					$List = shift(@List);
				} else {
					$List = pop(@List);
				}
				$Uri = $List->{List};
				my $SetUri;
				if ($Uri =~ /[^\?]+\?/) {
					$SetUri = $BaseUri.$Uri
				} elsif ($BaseUri =~ /\?/) {
					$SetUri = $BaseUri.'&'.$Uri
				} elsif ($BaseUri =~ /[^\.]+\.[^\.]+$/) {
					$SetUri = $BaseUri.'?'.$Uri
				} else {
					$SetUri = $BaseUri.$Uri
				}
				# 接続出来た
				if($DATA->CallObj('HTTP')->HttpReq(Uri => $SetUri, NoMes => 1, IO => 1)){
					if ($DATA->GetRound('Count', 'Info') > 30) {
						$DATA->PrintInfo(AtclCountReset => 1, Info => $InfoMes, InfoCountReset => 1);
					}
					IO->StdOut('o'); $DATA->{Round}{Count}{Info}++;
				# 接続出来ない
				}else{
					IO->StdOut('x'); next;
				}
			}

			# ページ頭読み飛ばし
			$DATA->CallObj('HTTP')->ReadStep(Read => 'Top');

			# 区切り設定
			$DATA->CallObj('HTTP')->ReadStep(Set => 'Step');
			# 文字コード設定
			my $CnvMethode = $DATA->GetRound('CnvMethod');

			# 区切り毎に、ファイル終端まで $_に読む
			while ($DATA->{String} = $DATA->CallObj('HTTP')->Read) {
				# 文字コード変換
				CodeCnv->$CnvMethode(\$DATA->{String}) if ($CnvMethode);
				# 次ページ解析
				$Class->GetNextPage(\$DATA->{String}) if (!$Class->GetResult($Type, 'NextParam'));

				# LOGへの書き出し
				$DATA->{String} .= "\n\n<!-- ### Step ### -->\n\n" if ($DATA->CallObj('DEBUG'));
				$DATA->CallObj('LOG')->PrintLog(ParaGraphCnv => 1, Parent => $Class);

				# ページ末読み飛ばし
				$DATA->CallObj('HTTP')->ReadStep(Read => 'Bottom');

				if ($DATA->GetRound('Count', 'Info') > 30) {
					$DATA->PrintInfo(Info => $InfoMes, InfoCountReset => 1);
				}

				# Foundが取得出来たら記事とみなす
				if($Class->Found){
					# 読み取り状況表示
					$DATA->PrintInfo(Parent => '.', AtclCount => 1);
					# 解析
					$Class->Parse;
					# 解析結果のセット
					my $Page = $DATA->GetRound($Type, 'Count', 'Page');
					my %Result = %{$Class->{Result}{$Type}};
					push @{$Class->{Result}{GetList}{$Type}{$Page}}, \%Result if ($Class->{Result}{$Type}{List});
					# 未読ポインタより古ければ終了
					last ATCL if($DATA->CompareDate == 1);
					# 未読ポインタ更新チェック
					$DATA->NewPtr;
				}

				# ノード解析
				if ($Class->{Parse}{Prm}{$Type}{ParseTree} && $Class->{Result}{$Type}{Num}) {
					my $Num = $Class->{Result}{$Type}{Num};
					if ($Class->{Result}{$Type}{$Class->{Parse}{Prm}{$Type}{ParseTree}{Root}}) {
						$Pos = 0;
					} elsif (my $Eval = $Class->{Parse}{Prm}{$Type}{ParseTree}{Eval}) {
						$Eval =~ s/TreePos/$Class->{Result}{$Type}{TreePos}/;
						$Pos = eval($Eval);
					} else {
						$Pos = $Class->{Result}{$Type}{TreePos};
					}
					$RootArray[$Pos] = $Num;
					$Class->{Result}{$Type}{TreeNumData} .= " $Num:$RootArray[$Pos - 1]" if($Pos > 0);
				}

				last if ($DATA->GetRound($Type, 'ReadEnd'));
			}							# ← while(<HTTP>)の終わり

			if ($Tree) {
				if (!@List) {
					redo ATCL if (@{$Parse->GetResult('GetList', $Parse->GetPrm($Type, 'List'), $Page+1)});
				}
				redo Tree if (@List);
			}
		}							# ← Tree:の終わり

#####  次のページ  #####

		last ATCL unless ($DATA->CallObj('HTTP')->NextPage);			# 戻り値が偽なら抜ける
		redo ATCL;

	}							# ← ATCL: の終わり
}

#			# 拡張解析
#			foreach my $org (@{$Class->{Parse}{orgParse}}) {
#				my ($reg, $pos, $name, $tree, $reg2, $pos2) = split(/,/, $org);
#				if ($tree) {
#					if ($Class->{Parent}{String} =~ /$reg2/) {
#						my $no = ${$pos2};
#						$Class->{Parent}{String} =~ /$reg/;
#						$Class->{Result}{orgTree}{$name}{$no} = ${$pos};
#					}
#				}
#			}
#		}	# ←R_HEAD終了
#		if ($PageCnt) { last ATCL unless ($PageCnt -= 1); }
#		elsif ($LastPtr == 0 || $Page <= $LastPage) { last ATCL; }
#

#--------------------------------------------------------------------------
#  別HTML取得
#--------------------------------------------------------------------------
sub GetOther{
	my $Class = shift;
	my $Type = shift;
	my $DATA = $Class->{DATA};
	$DATA->SetRound(Name => 'Type', Data => $Type);
	my $File = IO->new;

	# HTTP接続
	$DATA->CallObj('HTTP')->GetHttp(Param => $DATA->CallObj('HTTP')->SetPageParam);

	# CMTヘッダ用の設定
	$DATA->CallObj('HeadCMT')->SetHead;

	# 記事数カウンタ等初期化
	$DATA->SetRound(Name => 'Main,Count,AtclMax', Data => 0);
	$DATA->PrintInfo(PageCountReset => 1);

	# 出力メッセージ設定
	my $InfoMes = 'GetOther Page #Page#:';
	if (my $Mes = $Class->GetPrm($Type, 'InfoMes')) {
		$InfoMes = $Mes;
	}

	ATCL:{

		$DATA->SetRound(Name => 'Count,Info', Data => 0);

		# 各ページ毎の記事数
		$DATA->PrintInfo(AtclCountReset => 1, Info => $InfoMes, PageCount => 1);

		# ページ頭読み飛ばし
		$DATA->CallObj('HTTP')->ReadStep(Read => 'Top');

		# 区切り設定
		$DATA->CallObj('HTTP')->ReadStep(Set => 'Step');
		# 文字コード設定
		my $CnvMethode = $DATA->GetRound('CnvMethod');

		# 区切り毎に、ファイル終端まで $_に読む
		while ($DATA->{String} = $DATA->CallObj('HTTP')->Read) {
			# 文字コード変換
			CodeCnv->$CnvMethode(\$DATA->{String}) if ($CnvMethode);
			# 次ページ解析
			$Class->GetNextPage(\$DATA->{String}) if (!$Class->GetResult($Type, 'NextParam'));

			# LOGへの書き出し
			$DATA->CallObj('LOG')->PrintLog(ParaGraphCnv => 1, Parent => $Class);

			# ページ末読み飛ばし
			$DATA->CallObj('HTTP')->ReadStep(Read => 'Bottom');

			if ($DATA->GetRound('Count', 'Info') > 30) {
				$DATA->PrintInfo(Info => $InfoMes, InfoCountReset => 1);
			}

			# OtherFile解析
			if ($Class->{Parse}{Prm}{$Type}{FileName}{OtherFile}) {
				if (!$Class->{Result}{$Type}{FileName}{OtherFile}) {
					if ($DATA->{String} =~ /$Class->{Parse}{Prm}{$Type}{FileName}{OtherFile}{Value}/s) {
						$Class->{Result}{$Type}{FileName}{OtherFile} = ${$Class->{Parse}{Prm}{$Type}{FileName}{OtherFile}{Match}};
						next;
					} else { next }
				}
			}

			# OtherHead解析
			if (!$Class->{Result}{$Type}{Head}) {
				if ($DATA->{String} =~ /$Class->{Parse}{Prm}{$Type}{Head}{Value}/s) {
					$Class->{Result}{$Type}{Head} = ${$Class->{Parse}{Prm}{$Type}{Head}{Match}};
					$File->PrintOtherHead;
					next;
				} else { next }
			}

			# Foundが取得出来たら記事とみなす
			if($Class->Found){
				# 読み取り状況表示
				$DATA->PrintInfo(Parent => '.', AtclCount => 1);
				# 解析
				$Class->Parse;
				# 解析結果の出力
				$Class->{Result}{$Type}{Line} .= ' ';
				$Class->{Result}{$Type}{Line2} .= ' ' if ($Class->{Result}{$Type}{Line2});
				$Class->{Result}{$Type}{Line3} .= " " if ($Class->{Result}{$Type}{Line3});
				$File->Write($Class->{Result}{$Type}{Line}.$Class->{Result}{$Type}{Line2}.$Class->{Result}{$Type}{Line3}."\n");
			}
		}							# ← while(<HTTP>)の終わり

#####  次のページ  #####

		last ATCL unless ($DATA->CallObj('HTTP')->NextPage);			# 戻り値が偽なら抜ける
		redo ATCL;

	}							# ← ATCL: の終わり
}

#--------------------------------------------------------------------------
#  GetNextPage: 次ページ解析
#--------------------------------------------------------------------------
sub GetNextPage {
	my $Class = shift;
	my $STR = shift; $STR = $$STR;
	my $DATA = $Class->{DATA};
	my $Type = $DATA->GetRound('Type');
	my $Parse = $DATA->CallObj('Parse');
	my $NextParam = $Parse->GetResult($Type, 'NextParam');
	my $NextPages = $Parse->GetPrm('Pages', $Type, 'NextPage');

	return 0 if (!$NextPages->{Found});

	if (!$NextParam) {
		if ($NextPages->{Type} eq 'Form') {
			if ($STR =~ /$NextPages->{Found}/s) {
				my $MatchForm;
				my @Forms = split(/<\/form>/i, $STR);
				foreach my $Form (@Forms) {
					if ($Form =~ /$NextPages->{Found}/s) {
						$Form =~ /(<form.*?)$/si;
						$MatchForm = $1;
						last;
					}
				}
				my @Params = split(/>\n?/, $MatchForm);
				foreach my $Param (@Params) {
					$Param =~ /\n?<input *type *= *["']?([^"' ]+)["']? *name *= *["']?([^"' ]+)["']? *value *= *["']?([^"' ]*)["']?/is;
					$NextParam .= "$2=$3&" if ($2);
					$Param =~ /action *= *["']?([^"' ]+)["']?/i;
					if (my $Action = $1) {
						if ($NextPages->{GetAction}{Type} eq 'Url') {
							$Class->{Result}{$Type}{NextUrl} = $Action;
						} elsif ($NextPages->{GetAction}{Type} eq 'Uri') {
							my $Uri = $DATA->CallObj('INI')->GetParam('Uri');
							$Action =~ s/[^\.]\.\///g;
							while ($Action =~ s/\.\.\///) {
								if ($Uri =~ m#/[^/]+/$#) {
									$Uri =~ s#/[^/]+/$#/#;
								} elsif ($Uri =~ m#/[^/]+/[^/]+$#) {
									$Uri =~ s#/[^/]+/[^/]+$#/#;
								}
							}
							$Class->{Result}{$Type}{NextUri} = $Uri.$Action;
						} elsif ($NextPages->{GetAction}{Type} eq 'Cgi') {
							$Action =~ s/^\.\///g;
							$Class->{Result}{$Type}{NextCgi} = $Action;
						}
					}
				}
				$NextParam =~ s/\&$//;
			}
		} elsif ($NextPages->{Type} eq 'Anchor') {
			if ($STR =~ /$NextPages->{Found}/s) {
				$NextParam = ${$NextPages->{Match}};
				if ($NextPages->{GetAction}{Type} eq 'Url') {
					$Class->{Result}{$Type}{NextUrl} = $NextParam;
					$NextParam = 'dummy=0';
				} elsif ($NextPages->{GetAction}{Type} eq 'Uri') {
					my $Uri = $DATA->CallObj('INI')->GetParam('Uri');
					$NextParam =~ s/[^\.]\.\///g;
					while ($NextParam =~ s/\.\.\///) {
						if ($Uri =~ m#/[^/]+/$#) {
							$Uri =~ s#/[^/]+/$#/#;
						} elsif ($Uri =~ m#/[^/]+/[^/]+$#) {
							$Uri =~ s#/[^/]+/[^/]+$#/#;
						}
					}
					$Class->{Result}{$Type}{NextUri} = $Uri.$NextParam;
					$NextParam = 'dummy=0';
				} elsif ($NextPages->{GetAction}{Type} eq 'Cgi') {
					$NextParam =~ s/^\.\///g;
					$Class->{Result}{$Type}{NextCgi} = $NextParam;
					$NextParam = 'dummy=0';
				}
			}
		}
	}
	if ($NextParam) {
		$NextParam =~ s/&amp;/&/g;
		my $Debug = '$NextParam = '.$NextParam."\n";
		$Debug .= '			$Type = '.$Type;
		$DATA->DebugWrite(Code => $Debug);
	}
	return $Class->{Result}{$Type}{NextParam} = $NextParam
}

#--------------------------------------------------------------------------
#  GetUpUrl: 投稿用Url解析
#--------------------------------------------------------------------------
sub GetUpUrl {
	my $Class = shift;
	my $STR = shift; $STR = $$STR;
	my $DATA = $Class->{DATA};
	my $Type = $DATA->GetRound('Type');
	my $Parse = $DATA->CallObj('Parse');
	my $UpUrls = $DATA->GetBasic('UpUrl');

	return 0 if (!$UpUrls->{Found});
	my $MatchForm;

	if (!$UpUrls->{Parse}) {
		if ($UpUrls->{HtmlType} eq 'Form') {
			if ($STR =~ /$UpUrls->{Found}/s) {
				my @Forms = split(/<\/form>/i, $STR);
				foreach my $Form (@Forms) {
					if ($Form =~ /$UpUrls->{Found}/s) {
						$Form =~ /(<form.*?)$/si;
						$MatchForm = $1;
						last;
					}
				}
			}
		} elsif ($UpUrls->{HtmlType} eq 'Anchor') {
			if ($STR =~ /$UpUrls->{Found}/s) {
				$MatchForm = ${$UpUrls->{Match}};
			}
		}
	}
	if ($MatchForm) {
		$MatchForm =~ /action *= *["']?([^"' ]+)["']?/i;
		if (my $Action = $1) {
			if ($UpUrls->{SetType} eq 'Url') {
				$UpUrls->{Url} = $Action;
			} elsif ($UpUrls->{SetType} eq 'Uri') {
				my $Uri = $DATA->CallObj('INI')->GetParam('Uri');
				$Action =~ s/[^\.]\.\///g;
				while ($Action =~ s/\.\.\///) {
					if ($Uri =~ m#/[^/]+/$#) {
						$Uri =~ s#/[^/]+/$#/#;
					} elsif ($Uri =~ m#/[^/]+/[^/]+$#) {
						$Uri =~ s#/[^/]+/[^/]+$#/#;
					}
				}
				$UpUrls->{Uri} = $Uri.$Action;
			} elsif ($UpUrls->{SetType} eq 'Cgi') {
				$Action =~ s/^\.\///;
				$UpUrls->{Cgi} = $Action;
			}
		} else {
			if ($UpUrls->{SetType} eq 'Url') {
				$UpUrls->{Url} = $MatchForm;
			} elsif ($UpUrls->{SetType} eq 'Uri') {
				my $Uri = $DATA->CallObj('INI')->GetParam('Uri');
				$MatchForm =~ s/[^\.]\.\///g;
				while ($MatchForm =~ s/\.\.\///) {
					if ($Uri =~ m#/[^/]+/$#) {
						$Uri =~ s#/[^/]+/$#/#;
					} elsif ($Uri =~ m#/[^/]+/[^/]+$#) {
						$Uri =~ s#/[^/]+/[^/]+$#/#;
					}
				}
				$UpUrls->{Uri} = $Uri.$MatchForm;
			} elsif ($UpUrls->{SetType} eq 'Cgi') {
				$MatchForm =~ s/^\.\///;
				$UpUrls->{Cgi} = $MatchForm;
			}
		}
		$UpUrls->{Parse} = 1;
	}
	if ($UpUrls) {
		my $Debug = '$UpUrls = '.$UpUrls."\n";
		$Debug .= '			$Type = '.$Type;
		$DATA->DebugWrite(Code => $Debug);
	}
	return $UpUrls;
}

1;

#####  Parse : 覚え書き等  ################################################
__END__

#・Ver0.01 2002/05/20
#  INCM_MODULEから分離

#・Ver0.02 2002/07/08
#  掲示板判定をハッシュからサブルーチンへの定義へ変更
#  したことに関する処理の変更

#・Ver0.03 2002/08/26
#  記事解析処理に返信用のヘッダ処理を追加

#・Ver0.04 2002/08/27
#  ツリーのページ指定取得に対応

#・Ver0.05 2002/10/22
#  日付の解析に「MM/DD-hh:mm」形式を追加

#・Ver0.06 2002/10/29
#  記事ヘッダと本文の分割処理追加
#  添付ファイルアドレスの取得処理を修正

#・Ver0.07 2002/11/16
#  Tree取得の場合はBaseURLの?以降の引数をカットするように修正

#・Ver0.08〜0.10 2002/11/19
#  解析用パラメータおよび正規表現を詳細設定での設定に対応

#・Ver0.11〜0.20 2002/11/20
#  全体的な修正

#・Ver0.21 2002/11/20
#  ページタイトル取得時に余分な部分を除去する処理を追加

#・Ver0.22 2002/11/22
#  フレーム解析のミス修正

#・Ver0.23〜0.25 2002/11/24
#  初回解析時にEUC判定をするようにした
#  ツリー解析時に文字コード変換処理を追加
#  ページタイトル取得時に文字コード変換処理を追加

#・Ver0.26 2002/11/28
#  初回解析時にUTF8判定をするようにした

#・Ver0.27 2002/11/29
#  文字コード判別後の設定に関する不具合修正

#・Ver0.28 2002/12/04
#  EUC判別が出来なくなっていた不具合修正

#・Ver0.29〜0.45 2003/02/07
#  全体的な修正、インスタンスを生成するように変更

#・Ver0.46 2003/02/14
#  URLからの自動判定に関する不具合修正

#・Ver0.47 2003/02/20
#  SetTreeListメソッド追加

#・Ver0.48 2003/02/24
#  GetDateメソッドの不具合修正

#・Ver0.49〜50 2003/03/04
#  文字コード判定にX-EUC-JPを追加
#  NewAUTOプラグインからの呼出しに対応

#・Ver0.51〜0.52 2003/03/11
#  インスタンス生成時に未読ポインタに関する自動設定追加
#  日付書式の適用に関する処理追加

#・Ver0.53 2003/03/11
#  GetDateメソッドの正規表現を利用した場合の不具合修正

#・Ver0.54 2003/03/13
#  GetUrlメソッドを詳細設定での定義に対応

#・Ver0.55〜56 2003/04/03
#  GetTreeメソッドにノード解析を追加
#  Parseメソッドのレス元取得をノード解析に対応

#・Ver0.57〜0.59 2003/04/10
#  添付ファイルのアドレス設定を一部変更
#  ツリー解析に拡張解析処理を追加
#  記事解析時の解析にツリー解析を利用した場合の処理を追加

#・Ver0.60〜0.63 2003/04/15
#  記事の属性に対応
#  Url取得に拡張処理を追加
#  GetTreeで未読ポインタがNo.の場合はページめくりを回避
#  掲示板タイトル取得の拡張パターンマッチ処理を追加

#・Ver0.64 2003/04/15
#  添付ファイルのURL取得に関する不具合修正

#・Ver0.65〜0.81 2003/05/06
#  Dataクラスに対応
#  デバッグ出力に対応
#  記事判定メソッドの追加
#  Mail&Urlの取得メソッドの追加
#  GetPrm&GetReg&GetResultメソッドの追加
#  GetTopicメソッドの追加
#  添付ファイル取得処理の修正
#  次ページ解析メソッドの追加

#・Ver0.82〜0.85 2003/05/07
#  次ページ解析にUrl取得処理追加
#  投稿用Url取得メソッド追加

#・Ver0.86 2003/05/11
#  Parseメソッドに解析元の文字列を指定する処理追加

#・Ver0.87 2003/05/12
#  0.86の処理追加による不具合修正

#・Ver0.88 2003/05/14
#  文字コード解析を修正

#・Ver0.89〜0.95 2003/05/15
#  GetOther(別HTML解析)メソッドの追加

#・Ver0.96〜1.00 2003/05/20
#  newの不具合修正
#  GetTopicを複数巡回に対応
#  GetNextPageの修正とAnchorタイプの拡張
#  日付の整形処理追加
#  ルート記事判定の不具合修正

#・Ver1.01〜1.15 2003/05/20
#  TreeLoopメソッドの削除
#  GetTreeを大幅に修正

#・Ver1.16〜1.18 2003/05/21
#  GetTopicを定義による範囲指定に対応
#  GetUpUrlの記述ミス修正
#  GetUrlに拡張整形処理追加

#・Ver1.19 2003/05/21
#  GetDateの不具合修正

#・Ver1.20 2003/05/22
#  添付ファイル解析処理の変更

#・Ver1.21〜1.22 2003/05/23
#  AutoSelectにホストによる解析追加
#  HtmlParseの文字コード判定に文字コードの種類を追加

#・Ver1.23 2003/05/24
#  Parseに解析後の本文拡張整形処理を追加

#・Ver1.24 2003/05/24
#  GetTreeのノード解析の不具合修正

#・Ver1.25〜1.27 2003/05/28
#  インスタンス生成を複数巡回定義に対応
#  GetTitleにタグ除去処理を追加
#  GetTitleに番号を付けるオプションを追加

#・Ver1.28 2003/05/28
#  GetTitleの番号を付けるオプションの不具合修正

#・Ver1.29 2003/05/30
#  GetDateの不具合修正

#・Ver1.30〜1.32 2003/06/03
#  Parseのオプション解析に関する処理修正
#  Parseに解析後の各項目拡張整形処理を追加
#  Parseで$1をクリアにする処理を追加

#・Ver1.33〜1.34 2003/06/04
#  GetUrlの拡張整形処理を削除
#  Parseの解析後の各項目拡張整形処理の位置変更

#・Ver1.35〜1.36 2003/06/10
#  デバッグ出力の見直し
#  Parseの添付ファイル解析を修正

#・Ver1.37 2003/06/11
#  Parseの回避処理記述ミスを修正

#・Ver1.38〜1.40 2003/06/11
#  GetOtherの拡張

#・Ver1.41 2003/06/12
#  Parseの前解析結果保持の記述ミス修正

#・Ver1.42〜1.43 2003/06/17
#  GetTreeで記事番号がある場合のみノード解析するように修正
#  GetNextPageの結果をamp;から&に置換する処理追加

#・Ver1.44 2003/06/21
#  GetDateに日付のみのパターン追加

#・Ver1.45 2003/10/08
#  GetDateの日付解析に関する不具合修正

#・Ver1.46 2004/01/27
#  詳細設定にて日付の取得を正規表現で記述できるように修正
