#!/usr/bin/perl -w 
#------------------------------------------------------------------------------
# $Id$
#------------------------------------------------------------------------------
# Download operation-log file CGI
#
# Copyright (c) BAYBITS LLC. All rights reserved.
#------------------------------------------------------------------------------
use strict;
use utf8;
use URI::Escape;
use CGI;
use Time::Local;
use HTML::Template;
use XML::DOM;
use TF::GroupList;
use TF::XMLUtils;
use TF::CommonUtils;
use Encode;
binmode(STDOUT,":utf8");

# (note)
#    CSV ファイルはデフォルトでは"Shift_JIS"エンコードで出力されます.
#    Excelを使って表示することも可能となります.
#
#    しかし日本語以外がファイル名として使用されるシーンでは、必ず文字化けします.
#    そのようなケースでは、文字化けを起こさないUTF-8にすることをお勧めします.
#
#    UTF-8にするには、$csv_sjis = 0 と記述して下さい.
#
my $csv_sjis = 1;	# Shift_JIS で出力する場合: 1 / UTF-8の場合: 0

# global
my $LOCATION		= $ENV{'TF_LOCATION'} || '';
my $BRAND 			= $ENV{'TF_BRANDNAME'} || '';
my $USERID          = $ENV{'REMOTE_USER'} || '';
my $PASSWD          = $ENV{'TF_USERPLAINPASSWORD'} || '';
my $LANGPARAM		= TF::CommonUtils::getLangPriority();
my ($SCHEMA,$SERVER_PORT,$URI_PREFIX) = TF::CommonUtils::getCgiConnectInfo();
my $URL             = $URI_PREFIX . $LOCATION;
my $USERTYPE		= $ENV{'TF_USERTYPE'} || 'normal';
my $USERPRIVILEGE   = $ENV{'TF_USERPRIVILEGE'} || '';
my $TEMPLATE_FILE 	= './tmpl/opshowlog.tmpl.' . $LANGPARAM;
my $TF_LOGOPERATION	= $ENV{'TF_LOGOPERATION'} || 'off';
my $dir_pass		= $ENV{'TF_LOGFILE_ROOT'} || '/var/log/teamfile';
my $pagetitle		= $ENV{'TF_FOLDER_LOGOPERATION'} || '';
my $PAGETITLE		= TF::CommonUtils::decodeUTF8($pagetitle);
my $PAGEIMG			= $ENV{'TF_FOLDER_LOGOPERATION_IMG'} || '';
my $MSGTABLE_ja 	= {
					CGIError        => "CGIエラーです",
					mErrNoLogEntryT => 'インフォメーション',
					mErrNoLogEntry	=> '対象の操作ログは存在しませんでした。',
					mErrCGI			=> 'CGIモジュールの生成に失敗しました。',
					mErrRangeParam  => '「抽出範囲」が正しく指定されておりません。',
					mErrNoCmd       => '操作パラメータが指定されておりません。',
					mErrInvalidCmd  => '操作パラメータが正しくありませんでした。',
					mErrTargetGroup => '操作ログ対象が指定されておりません。',
					mErrInvalidType => '出力形式が正しくありませんでした。',
					mErrAccessDeny  => '操作ログの表示は制限されています。',
					mMethodName1	=> '取得',
					mMethodName2	=> '登録',
					mMethodName3	=> 'フォルダ作成',
					mMethodName4	=> '削除',
					mMethodName5	=> '移動',
					mMethodName6	=> '名前変更',
					mMethodName7	=> 'コピー',
					mMethodName8	=> 'ロック',
					mMethodName9	=> 'アンロック',
					mRight			=> '成功',
					mWrong			=> '失敗'
				};
my $MSGTABLE_en 	= {
					CGIError        => "CGI error found.",
					mErrNoLogEntryT => 'Information',
					mErrNoLogEntry  => 'The Operation log entry for this target was not found.',
					mErrCGI			=> 'Failed to create cgi module.',
					mErrRangeParam  => 'Invalid "Range" parameter.',
					mErrNoCmd       => 'The operation parameter was not specified.',
					mErrInvalidCmd  => 'Invalid operation parameter.',
					mErrTargetGroup => 'The target of operation log was not specified.',
					mErrInvalidType => 'Invalid "type" of output.',
					mErrAccessDeny  => 'You could not access this operation log.',
					mMethodName1	=> 'GET',
					mMethodName2	=> 'PUT',
					mMethodName3	=> 'MKCOL',
					mMethodName4	=> 'DELETE',
					mMethodName5	=> 'MOVE',
					mMethodName6	=> 'RENAME',
					mMethodName7	=> 'COPY',
					mMethodName8	=> 'LOCK',
					mMethodName9	=> 'UNLOCK',
					mRight			=> 'Success',
					mWrong			=> 'Failure'
			};
my $MSGTABLE		= ($LANGPARAM eq 'ja') ? $MSGTABLE_ja : $MSGTABLE_en;


if (!$LOCATION || !$USERTYPE || $USERTYPE eq 'limited' || $TF_LOGOPERATION ne 'on') {
	TF::CommonUtils::showAccessDeny();
	die'';
}

main();

#
# main
#
sub main {

	# CGIパラメータの取得とvalidation
	my ($cmd, $type, $egid, $logdays, $ecgid, $rec) = parseCgiParams();
	if (!$cmd) {
		return;
	}

	my $gid = TF::CommonUtils::decipherNumericValue($egid);

	my $isAlldownload = 0;
	if ($cmd eq 'alldown') {
		$isAlldownload = 1;
	}

	# 操作対象となるグループの名前一覧を取得する
	my ($showname,@webgroup) = getGroupNames($gid, $isAlldownload,$rec);
	if (!$isAlldownload) {
		my $found_gid = 0;
		# 個々のグループをクリックしてダウンロードする場合、$gid が@webgroup に含まれているはず
		foreach (@webgroup) {
			if ($_->{id} eq $gid) {
				$found_gid = 1;
				last;
			}
		}
		if ($found_gid == 0) {
			# 不正アクセスである
			TF::CommonUtils::showErrorPage($MSGTABLE->{mErrAccessDeny}, $LANGPARAM);
			return;
		}
	}

	my $found		= undef;
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
	$year +=1900;
	$mon++;
	my ($ysec,$ymin,$yhour,$ymday,$ymon,$yyear,$ywday,$yyday,$yisdst) = localtime(time-24*3600);
	$yyear +=1900;
	$ymon++;

	opendir(DIR,"$dir_pass");
	my @dirfile = readdir(DIR);
	@dirfile = sort @dirfile;
	closedir(DIR);
	my $chkwrite = 0;
	my @table = ();
	my %tmp;
	my $openfile;
	my $chklocation = $LOCATION;
	my $csvFileName = "oplog.csv";

	my $i;
	if ($logdays eq "TODAY") {
		$openfile = sprintf("%04d%02d%02d",$year,$mon,$mday);
		$chkwrite = parseloop($openfile,\@webgroup,$chklocation,\@table,$chkwrite);
		$csvFileName = buildCsvFileName($openfile, $openfile, $csvFileName);
	}
	elsif ($logdays eq "YESTERDAY") {
		$openfile = sprintf ("%04d%02d%02d",$yyear,$ymon,$ymday);
		$chkwrite = parseloop($openfile,\@webgroup,$chklocation,\@table,$chkwrite);
		$csvFileName = buildCsvFileName($openfile, $openfile, $csvFileName);
	}
	elsif ($logdays eq "LASTWEEK") {
		my $fist_name = undef;
		for($i=7;$i>=0;$i--){
			my ($sec7,$min7,$hour7,$mday7,$mon7,$year7,$wday7,$yday7,$isdst7) = localtime(time-24*3600*$i);
			$year7 +=1900;
			$mon7++;
			$openfile = sprintf("%04d%02d%02d",$year7,$mon7,$mday7);
			$chkwrite = parseloop($openfile,\@webgroup,$chklocation,\@table,$chkwrite);
			if (!$fist_name) {
				$fist_name = $openfile;
			}
		}
		$csvFileName = buildCsvFileName($fist_name, $openfile, $csvFileName);
	}
	elsif ($logdays eq "THISMONTH") {
		my $first_name = sprintf("%04d%02d",$year,$mon);
		my $tmfname ="access_log.$first_name\\d\\d";

		foreach my $line (@dirfile) {
			if($line =~ /$tmfname$/) {
				my @line = split(/\./,$line);
				$chkwrite = parseloop($line[1],\@webgroup,$chklocation,\@table,$chkwrite);
			}
		}
		my $today = sprintf("%04d%02d%02d",$year,$mon,$mday);
		$csvFileName = buildCsvFileName($first_name . "01", $today, $csvFileName);
	}
	elsif ($logdays eq "LASTMONTH") {
		my $lastsec = timelocal(0,0,0,1,$mon - 1,$year) - 24*3600;
		my ($lsec,$lmin,$lhour,$lmday,$lmon,$lyear,$lwday,$lyday,$lisdst) = localtime($lastsec);
		my $lastmonth = sprintf("%04d%02d%02d",$lyear + 1900,$lmon + 1,$lmday);

		$mon--;
		if($mon == 0){
			$mon = 12;
			$year--;
		}
		my $first_name = sprintf("%04d%02d",$year,$mon);
		my $tmfname = "access_log.$first_name\\d\\d";
		foreach my $line (@dirfile){
			if($line =~/$tmfname$/){
				my @line = split(/\./,$line);
				$chkwrite = parseloop($line[1],\@webgroup,$chklocation,\@table,$chkwrite);
			}
		}
		$csvFileName = buildCsvFileName($first_name . "01", $lastmonth, $csvFileName);
	}

	#
	# 出力
	#
	if($type eq "web") {
		#
		# Web 表示
		#
		if (!open(TEMPLATE,"<$TEMPLATE_FILE")) {
			TF::CommonUtils::showTemplateOpemErr($LANGPARAM);
			return;
		}
		my $group = $webgroup[0];
		binmode(TEMPLATE,":utf8");
		my $htmltmpl = HTML::Template->new( filehandle => *TEMPLATE,
											case_sensitive => 1,
											die_on_bad_params => 0);
		if ($showname){
			$showname = TF::CommonUtils::decodeUTF8($showname);
			$htmltmpl->param(	brandname => $BRAND,
								pagetitle => $PAGETITLE,
								pageimg	=> $PAGEIMG,
								LOOP_LOG => \@table,
								GROUPNAME => $showname,
								ecgid     => $ecgid,
								logdays   => $logdays,
								egid	  => $egid,
								type	  => $type,
								REC		  => $rec,
								USR		  => $USERTYPE,
								);
		}
		else {
			$group->{name} = TF::CommonUtils::decodeUTF8($group->{name});
			$htmltmpl->param(	brandname => $BRAND,
								pagetitle => $PAGETITLE,
								pageimg	=> $PAGEIMG,
								LOOP_LOG => \@table,
								GROUPNAME => $group->{name},
								ecgid     => $ecgid,
								logdays   => $logdays,
								egid	  => $egid,
								type	  => $type,
								REC		  => $rec,
								USR		  => $USERTYPE,
	
							);
		}
		print "Content-type: text/html; charset=UTF-8\n\n";
		print $htmltmpl->output;

		close(TEMPLATE);
	}
	else {
		#
		# CSV ダウンロード
		#
		my $line2;
		my $found = 0;

		foreach $line2 (@table) {
			if (!$found) {
				if ($csv_sjis == 1) {
					binmode(STDOUT,":encoding(cp932)");
				}
				print "Content-type:application/octet-stream\r\n";
				print "Content-Disposition:attachment; filename=$csvFileName\n\n";
				$found = 1;
			}

			my $folder = $line2->{'FOLDER'};
			my $dstpass =$line2->{'dstpass'};
			my $file = $line2->{'FILE'};
			my $dstfile = $line2->{'dstfile'};
			$folder =~ s/\"/\"\"/;
			$dstpass =~ s/\"/\"\"/;
			$file =~ s/\"/\"\"/;
			$dstfile =~ s/\"/\"\"/;

			print "$line2->{'IP'},$line2->{'ID'},$line2->{'TIME'},$line2->{'METHOD'},\"$folder\",\"$dstpass\",\"$file\",\"$dstfile\",$line2->{'RorW'}\r\n";
		}

		if ($found == 0){
			TF::CommonUtils::showMessagePage(   $MSGTABLE->{mErrNoLogEntry},
				                                $LANGPARAM,
										     $MSGTABLE->{mErrNoLogEntryT});
			return;
		}
	}
}

#
# read log and parse 
# 
sub parseloop {
	my $filename = $_[0];
	if (!open (IN, "$dir_pass/access_log.$filename")) {
		return;
	}
	my $webgroup_ref = $_[1];
	if (!@{$webgroup_ref}[0]) {
		return;
	}

	my $location = $_[2];
	$location =~ s/^\///g;
	$location = TF::CommonUtils::escapeRegularExpression($location);

	my $table_ref = $_[3];
	my $chkwrite = $_[4];
	while (<IN>) {
		if($_ =~/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - ([^\/\\:\*\?\"<>\|]+) (\[\d{2}\/\D{3}\/\d{4}:\d{2}:\d{2}:\d{2} \+\d{4}\]) "([A-Z]+) \/($location)(\/Group%20Folder\/)(\S+) HTTP\/1\.[0-1]" (\d{1,3}) ([\d-]+) ("[^"]*") ("[^"]*")/){
			my $ip = $1;
			my $id = $2;
			my @time;
			$time[2] = substr($3,1,2);
			my $chkday = $time[2];
			$time[1] = substr($3,4,3);
			my $chkmon = $time[1];
			$time[0] = substr($3,8,4);
			my $chkyear = $time[0];
			$time[3] = substr($3,13,8);
			my $chkhour = substr($3,13,2);
			my $chkmin = substr($3,16,2);
			my $chksec = substr($3,19,2);
			$chkmon = getmonth($chkmon);
			my $httpstats = $8;
			my $fsize = $9;
			my $usragent = $10;
# (note) 将来サポート予定
#			my $destination = $11;
#			my	($dstpass,$dstfile) = "";
#			if($destination ne "\"-\""){
#				($dstpass,$dstfile) = getdst($destination);
#			}
			
			$time[1] = getmonth($time[1]);
			my $tmps = "$time[0]\/"."$time[1]\/";
			my $tmpss = "$time[2] "."$time[3]";
			my $time = $tmps.$tmpss;
			my $chk=0;
			my($groupname,$parent_uri,$fname,$method) = parseUri($7);
			$groupname = URLd($groupname);
			$groupname = TF::CommonUtils::decodeUTF8($groupname);	
			my $webg = '';
			foreach (@{$webgroup_ref}) {
				if($_->{compname} eq $groupname || $_->{id} eq $groupname) {
					$webg = $_;
					$chk =0;
					last;
				}
				else{
					$chk =1;
				}
			}
			if($chk ==1){
				next;
			}
			# メソッドがGET で WEBDAV_METHOD=PROPFIND であれば表示の必要なし
			if ($4 eq "GET" && $method eq "PROPFIND") {
				next;
			}

			# POST 以外のメソッドではWEBDAV_METHODの値を利用しないのでリクエストメソッドで置き換え
			if($4 ne 'POST') {
				$method = $4;
			}
			my	($Succes,$right,$methodname) = rightorwrong($method,$httpstats);

			# (note)
			# 	MKCOL, LOCK, UNLOCK, COPY, MOVE は書き込みオペレーションですが
			# 	初版では表示されないことになりました.
			#
			if (($method eq "PUT" || $method eq "GET" || $method eq "DELETE") && ($id ne '-')) {

				my $epochtime = timelocal($chksec,$chkmin,$chkhour,$chkday,$chkmon - 1,$chkyear - 1900);
				# ログ日付がグループの作成日付よりも古ければ破棄する (外部仕様です)
				if ($epochtime <= $webg->{creationdt}) {
					next;
				}

				my %tmp;
				$chkwrite = 1;
				$tmp{IP} = $ip;
				$tmp{ID} = $id;
				$tmp{TIME} = $time;
				$tmp{METHOD} = $methodname;
				if ($parent_uri) {
					$parent_uri = URLd($parent_uri);
					$parent_uri = TF::CommonUtils::decodeUTF8($parent_uri);
					$parent_uri = $webg->{compname} . "/" . $parent_uri;
				}
				else {
					$parent_uri = $webg->{compname};
				}
				$tmp{FOLDER} = $parent_uri;
				$fname = URLd($fname);
				$tmp{FILE} = TF::CommonUtils::decodeUTF8($fname);
				$tmp{RorW} = $right;

# (note) 将来サポート予定
#				$dstpass = $webg . "/"."$dstpass";
#				$dstpass = URLd($dstpass);
#				$tmp{dstpass} = $dstpass;
				$tmp{dstpass} = "";
#				$dstfile = URLd($dstfile);
#				$tmp{dstfile} = $dstfile;
				$tmp{dstfile} = "";
				push(@{$table_ref}, \%tmp);	
			}
		}
	}
	close(IN);
	return $chkwrite;
}

#
# get right and output method 
#
sub rightorwrong {
	my $Succes;
	my $right;
	my ($method,$httpstats) =@_;
	if($method eq 'GET'){
		$method = "$MSGTABLE->{mMethodName1}";
		if($httpstats == 200){
			$Succes = "OK";
			$right = "$MSGTABLE->{mRight}";
		}
		elsif ($httpstats == 206){
			$Succes = "Partial Content";
			$right = "$MSGTABLE->{mRight}";
		}
		elsif ($httpstats == 304) {
			$Succes = "Not modified";
			$right = "$MSGTABLE->{mRight}";
		}
		else{
			$Succes = "failed";
			$right = "$MSGTABLE->{mWrong}";
		}
	}
	elsif($method eq 'PUT'){
		$method = "$MSGTABLE->{mMethodName2}";
		if($httpstats == 201){
			$Succes = "Created";
			$right = "$MSGTABLE->{mRight}";
		}
		elsif($httpstats ==204){
			$Succes = "No Content";
			$right  = "$MSGTABLE->{mRight}";
		}
		elsif($httpstats == 200){
			$Succes = "OK";
			$right = "$MSGTABLE->{mRight}";
		}
		else{
			$Succes = "failed";
			$right = "$MSGTABLE->{mWrong}";
		}
	}
	elsif($method eq 'MKCOL'){
		$method = "$MSGTABLE->{mMethodName3}";
		if($httpstats == 201){
			$Succes = "Created";
			$right = "$MSGTABLE->{mRight}";
		}
		elsif($httpstats == 200){
			$Succes = "OK";
			$right = "$MSGTABLE->{mRight}";
		}
		else{
			$Succes = "failed";
			$right = "$MSGTABLE->{mWrong}";
		}
	}
	elsif($method eq 'POST'){
		if($httpstats ==200){
			$Succes ="OK";
		}
		else{
			$Succes ="failed";
		}
	}
	elsif($method eq 'DELETE'){
		$method = "$MSGTABLE->{mMethodName4}";
		if($httpstats == 204){
			$Succes = "No Content";
			$right = "$MSGTABLE->{mRight}";
		}
		elsif($httpstats == 404){
			$Succes = "Not Found";
			$right = "$MSGTABLE->{mRight}";
		}
		elsif($httpstats == 200){
			$Succes = "";
			$right = "$MSGTABLE->{mRight}";
		}
		else{
			$Succes = "failed";
			$right = "$MSGTABLE->{mWrong}";
		
		}
	}
	elsif($method eq 'MOVE'){
		$method = "$MSGTABLE->{mMethodName5}";
		if($httpstats == 201){
			$Succes = "Created";
			$right = "$MSGTABLE->{mRight}";
		}
		else{
			$Succes = "failed";
			$right = "$MSGTABLE->{mWrong}";
		}
	}
	elsif($method eq 'COPY'){
		$method = "$MSGTABLE->{mMethodName7}";
		if($httpstats == 201){
			$Succes = "Created";
			$right = "$MSGTABLE->{mRight}";
		}
		else{
			$Succes = "failed";
			$right = "$MSGTABLE->{mWrong}";
		}
	}
	elsif($method eq 'LOCK'){
		$method = "$MSGTABLE->{mMethodName8}";
		if($httpstats == 200){
			$Succes = "OK";
			$right = "$MSGTABLE->{mRight}";
		}
		else{
			$Succes = "failed";
			$right = "$MSGTABLE->{mWrong}";
		}
	}
	elsif($method eq 'UNLOCK'){
		$method = "$MSGTABLE->{mMethodName9}";
		if($httpstats == 204){
			$Succes = "No Content";
			$right = "$MSGTABLE->{mRight}";
		}
		else{
			$Succes = "failed";
			$right = "$MSGTABLE->{mWrong}";
		}
	}
	return ($Succes,$right,$method);
}

#
# parse log
#
sub parseUri {
	my $uri = shift || '';
	my $groupname = '';
	my $parent_uri = '';
	my $fname = '';
	my $method;

	my ($uri_part, $uparam_str) = split(/\?/, $uri);

	# parse URL parameters
	my %uparam_h = parseUriParams($uparam_str);

	# remove double-slash and end-slash
	$uri_part =~ s/[\/]+/\//g;
	$uri_part =~ s/\/$//g;

	# parse URI
	$method = $uparam_h{'WEBDAV_METHOD'} || '';
	if($method eq 'PUT'){
		if ($uri_part =~ /^([^\/]+)\/*(.*)$/) {
			$groupname = $1;
			$parent_uri = $2;
			$fname = $uparam_h{'name'} || '';
		}
	}
	else{
		if($uri_part =~ /^([^\/]+)\/([^\/]+)$/) {
			$groupname = $1;
			$parent_uri = "";
			$fname = $2;
		}
		elsif ($uri_part =~ /^([^\/]+)\/(.*)\/([^\/]+)$/) {
			$groupname = $1;
			$parent_uri = $2;
			$fname = $3;
		}
	}

	return ($groupname,$parent_uri,$fname,$method);
}

#
# get groupname,parent_uri,fname
#
sub parseUriParams {
	my $param_str = shift || undef;
	my %uparam_h ;
	if($param_str){
		my@uparams = split (/&/,$param_str);

		for my $keyval (@uparams){
			my ($key,$val) = split(/=/,$keyval);
			$uparam_h{$key} = $val;
		}
	}
	return %uparam_h;
}

#
# get month
#
sub getmonth {
	my $mon;
	my $data = $_[0];
	if($data eq 'Jan'){
		$mon = "01";
	}
	elsif($data eq 'Feb'){
		$mon = "02";
	}
	elsif($data eq 'Mar'){
		$mon = "03";
	}
	elsif($data eq 'Apr'){
		$mon = "04";
	}
	elsif($data eq 'May'){
		$mon = "05";
	}
	elsif($data eq 'Jun'){
		$mon = "06";
	}
	elsif($data eq 'Jul'){
		$mon = "07";
	}
	elsif($data eq 'Aug'){
		$mon = "08";
	}
	elsif($data eq 'Sep'){
		$mon = "09";
	}
	elsif($data eq 'Oct'){
		$mon = "10";
	}
	elsif($data eq 'Nov'){
		$mon = "11";
	}
	elsif($data eq 'Dec'){
		$mon = "12";
	}
	else{
	}
	return $mon;
}

#
# get destination
#
sub getdst {
	if($_[0] =~ /"http[s]?:\/\/[\w%-_:]+\/[\w%-_]+\/Group%20Folder\/([[\w%-_]+\/_]*)\/([\w%-_]+)"/){
	}
	elsif($_[0]=~ /"http[s]?:\/\/[\w%-_:]+\/[\w%-_]+\/([[\w%-_]+\/?]*)\/([\w%-_]+)"/){
	}
	else{
	}
	return ($1,$2);
}

#
# URL decode 
#
sub URLd {
	my $URLdecode = $_[0];
	$URLdecode =~tr/+/ /;
	$URLdecode =~s/%([a-fA-F0-9]{2})/pack("C",hex($1))/eg;
	return $URLdecode;
}

#
# Parse CGI parameters
#
sub parseCgiParams {
	my $cgi = new CGI;
	if( ! $cgi ) {
		TF::CommonUtils::showErrorPage($MSGTABLE->{CGIError}, $LANGPARAM);
		print STDERR "CGI Object error";
		return undef;
	}

	if( $cgi->cgi_error ) {
		TF::CommonUtils::showErrorPage($MSGTABLE->{CGIError} . '(' . $cgi->cgi_error . ')', $LANGPARAM);
		print STDERR "CGI Error (" . $cgi->cgi->error . ")";
		return undef;
	}

	# URLパラメータの取得
	my $cmd      = TF::CommonUtils::escapeHTML(scalar $cgi->param('hidCmd'), 0);
	my $type     = TF::CommonUtils::escapeHTML(scalar $cgi->param('hidType'), 0);
	my $egid     = TF::CommonUtils::escapeHTML(scalar $cgi->param('hidEgid'), 0);
	my $logdays  = TF::CommonUtils::escapeHTML(scalar $cgi->param('selLogRange'), 0);
	my $ecgid    = TF::CommonUtils::escapeHTML(scalar $cgi->param('hidEcgid'), 0);
	my $rec      = TF::CommonUtils::escapeHTML(scalar $cgi->param('recursive'), 0);

	# パラメータのvalidation
	if (!$cmd) {
		# コマンドパラメータは必須
		TF::CommonUtils::showErrorPage($MSGTABLE->{mErrNoCmd}, $LANGPARAM);
		return undef;
	}
	if ($cmd ne 'alldown' && $cmd ne 'down') {
		# alldown, down 以外はNG
		TF::CommonUtils::showErrorPage($MSGTABLE->{mErrInvalidCmd}, $LANGPARAM);
		return undef;
	}

	if (!$type || ($type ne 'csv' && $type ne 'web')) {
		# csv, web 以外はNG
		TF::CommonUtils::showErrorPage($MSGTABLE->{mErrInvalidType}, $LANGPARAM);
		return undef;
	}
	if ($cmd eq 'alldown' && $type eq 'web') {
		# 組み合わせが正しくない
		TF::CommonUtils::showErrorPage($MSGTABLE->{mErrInvalidType}, $LANGPARAM);
		return undef;
	}

	if (!$egid && $cmd eq 'down') {
		# 1グループの操作ログ取得ではグループIDは必須
		TF::CommonUtils::showErrorPage($MSGTABLE->{mErrTargetGroup}, $LANGPARAM);
		return undef;
	}
	$egid  = TF::CommonUtils::decodeUTF8($egid);
	$ecgid = TF::CommonUtils::decodeUTF8($ecgid);

	if (!$logdays) {
		# 抽出範囲は必須
		TF::CommonUtils::showErrorPage($MSGTABLE->{mErrRangeParam}, $LANGPARAM);
		return undef;
	}
	if ($logdays ne "TODAY" && $logdays ne "YESTERDAY" && $logdays ne "LASTWEEK" && $logdays ne "THISMONTH" && $logdays ne "LASTMONTH") {
		# 抽出範囲は必須
		TF::CommonUtils::showErrorPage($MSGTABLE->{mErrRangeParam}, $LANGPARAM);
		return undef;
	}

	return ($cmd, $type, $egid, $logdays, $ecgid ,$rec);
}

#
# Get groupnames from TeamFile server
#
# [ Use environment value ]
# 	$URL, $USERID, $PASSWD, $USERTYPE
#
sub getGroupNames {

	my $gid   = shift || '';
	my $isAll = shift || 0;
	my $rec   = shift || '';
	my @groupnames = ();

	my $glist = TF::GroupList->new();
	my $queryGroupStatus = undef;
	my $isAdmin = undef;
	my $lcname = $LOCATION;
	$lcname =~ s/\///g;
	
	# グループ制約適用の有無を取得
	my $use_grpconstraints = 1;
	if ($USERPRIVILEGE =~ /group-constraints-ignore/) {
		$use_grpconstraints = 0;
	}
	my $showname = "";

	#
	# グループ一覧を取得
	#
	#
	# 管理者 の場合
	#
	if ($USERTYPE eq 'admin') {
		if ($isAll && $rec ne 'on') {
			# まとめてダウンロードであれば、全グループのリストを取得
			#再帰的に取得しない場合

			$queryGroupStatus = $glist->queryGroupList($URL,$USERID,$PASSWD,$gid);
			if($queryGroupStatus == 207 ) {
				foreach ($glist->getIDList()) {
					my $str = $glist->getGroupFolderName($_,$lcname);
					my $name = $glist->getName($_);
					utf8::encode($name);
					$str = URLd($str);
					$str = TF::CommonUtils::decodeUTF8($str);

					# $gid 以外のグループを記録する
					if ($gid && $_ eq $gid) {
						next;
					}
					push( @groupnames,{	compname => $str,
										name => $name,
										id => $_,
										creationdt => $glist->getGroupCreationDt($_)
									});
				}
			}
		}
		elsif ($isAll && $rec eq 'on') {
			#まとめてダウンロードかつ、再帰的に取得する場合、全てのグループを取得
			$queryGroupStatus = $glist->queryGroupTreeList($URL,$USERID,$PASSWD,$gid);
			if ($queryGroupStatus == 207) {
				foreach ($glist->getIDList()) {
					my $str = $glist->getGroupFolderName($_,$lcname);
					my $name = $glist->getName($_);
					utf8::encode($name);
					$str = URLd($str);
					$str = TF::CommonUtils::decodeUTF8($str);
					my $child = $glist->getChildCount($_);

					if($gid && $_ eq $gid) {
						next;
					}
					push( @groupnames,{ compname => $str,
										name => $name,
										id => $_,
										creationdt => $glist->getGroupCreationDt($_)
					
					});
					if ($child && $child > 0) {
						getRecursive($URL,$USERID,$PASSWD,$gid,$lcname,\@groupnames);
					}
				}
			}
		}
		elsif (!$isAll && $rec ne 'on') {
			#個別に取得
			$queryGroupStatus = $glist->queryGroup($URL,$USERID,$PASSWD,$gid);
			if ($queryGroupStatus == 207) {
				foreach ($glist->getIDList()) {
					my $str = $glist->getGroupFolderName($_,$lcname);
					my $name = $glist->getName($_);
					utf8::encode($name);
					$str = URLd($str);
					$str = TF::CommonUtils::decodeUTF8($str);
					# (note) queryGroup なので戻ってくるグループは1つだけ 
					$showname = $name;
					push ( @groupnames,{ compname => $str,
										 name => $name,
										 id => $_,
										 creationdt => $glist->getGroupCreationDt($_)
					});
				}
			}
		}


		
		elsif (!$isAll && $rec eq 'on') {
			$queryGroupStatus = $glist->queryGroupTreeList($URL,$USERID,$PASSWD,$gid);
			if ($queryGroupStatus == 207) {
				foreach ($glist->getIDList()) {
					my $str = $glist->getGroupFolderName($_,$lcname);
					my $name = $glist->getName($_);
					my $child = $glist->getChildCount($_);
					utf8::encode($name);
					$str = URLd($str);
					$str = TF::CommonUtils::decodeUTF8($str);
					if ($gid && $gid eq $_) {
						$showname = $name;
					}
					push( @groupnames,{	compname => $str,
										name => $name,
										id => $_,
										creationdt => $glist->getGroupCreationDt($_)
									});
					if($child && $child > 0) {
						getRecursive($URL,$USERID,$PASSWD,$gid,$lcname,\@groupnames);		
					}	
				}
			}
		}
	}
	#
	# グループリーダの場合
	#
	elsif ($USERTYPE eq 'groupleader') {
		# まとめてダウンロードの場合
		if ($isAll && $rec ne 'on') {
			# まとめてダウンロードであれば、管理グループのリストを取得

			$queryGroupStatus = $glist->queryGroupList($URL,$USERID,$PASSWD,$gid);
			if($queryGroupStatus == 207 ) {
				foreach ($glist->getIDList()) {
					my $str = $glist->getGroupFolderName($_,$lcname);
					my $name = $glist->getName($_);
					utf8::encode($name);

					# $gid 以外のグループを記録する
					if ($gid && $_ eq $gid) {
						next;
					}
					push( @groupnames,{	compname => $str,
										name => $name,
										id => $_,
										creationdt => $glist->getGroupCreationDt($_)
									});
				}
			}

			# トップフォルダの検索では所属グループも取得する
			if (!$gid) {
				my $glist2 = TF::GroupList->new();
				my $queryGroupStatus2 = $glist2->queryAvailableGroupList($URL,$USERID,$PASSWD);
				if($queryGroupStatus2 == 207 ) {

					foreach ($glist2->getIDList()) {
						# 操作ログ制約によりブロックされていればスキップ
						if ($glist2->hasOplogConstraints($_) && $use_grpconstraints) {
							next;
						}
						# 非アクティブグループは表示しないグループリーダの場合
						if (!$glist2->isActive($_)) {
							next;
						}
						my $str = $glist2->getGroupFolderName($_,$lcname);
						my $name = $glist2->getName($_);
						utf8::encode($name);
						$str = URLd($str);
						$str = TF::CommonUtils::decodeUTF8($str);

						# まとめてダウンロードの場合にはそのまま記録する
						push( @groupnames,{	compname => $str,
											name => $name,
											id => $_,
											creationdt => $glist2->getGroupCreationDt($_)
											});
					}
				}
			}
		}
		elsif($isAll && $rec eq 'on') {
		# まとめてダウンロードであれば、管理グループのリストを取得

			$queryGroupStatus = $glist->queryGroupTreeList($URL,$USERID,$PASSWD,$gid);
			if($queryGroupStatus == 207 ) {
				foreach ($glist->getIDList()) {
					my $str = $glist->getGroupFolderName($_,$lcname);
					my $name = $glist->getName($_);
					my $child = $glist->getChildCount($_);
					utf8::encode($name);
					$str = URLd($str);
					$str = TF::CommonUtils::decodeUTF8($str);

					# $gid 以外のグループを記録する
					if ($gid && $_ eq $gid) {
						next;
					}
					push( @groupnames,{	compname => $str,
										name => $name,
										id => $_,
										creationdt => $glist->getGroupCreationDt($_)
									});
					if ($child && $child > 0) {
						getRecursive($URL,$USERID,$PASSWD,$gid,$lcname,\@groupnames);
					}
				}
			}

			# トップフォルダの検索では所属グループも取得する
			if (!$gid) {
				my $glist2 = TF::GroupList->new();
				my $queryGroupStatus2 = $glist2->queryAvailableGroupList($URL,$USERID,$PASSWD);
				if($queryGroupStatus2 == 207 ) {

					foreach ($glist2->getIDList()) {
						# 操作ログ制約によりブロックされていればスキップ
						if ($glist2->hasOplogConstraints($_) && $use_grpconstraints) {
							next;
						}
						# 非アクティブグループは表示しないグループリーダの場合
						if (!$glist2->isActive($_)) {
							next;
						}
						my $str = $glist2->getGroupFolderName($_,$lcname);
						my $name = $glist2->getName($_);
						utf8::encode($name);
						$str = URLd($str);
						$str = TF::CommonUtils::decodeUTF8($str);

						# まとめてダウンロードの場合にはそのまま記録する
						push( @groupnames,{	compname => $str,
											name => $name,
											id => $_,
											creationdt => $glist2->getGroupCreationDt($_)
											});
					}
				}
			}	
		}
		# 個別ダウンロードの場合
		elsif (!$isAll && $rec ne 'on') {
			my $search_gid;
			# $gid のグループだけを検索する
			$queryGroupStatus = $glist->queryGroupTreeList($URL,$USERID,$PASSWD,$gid);
			if ($queryGroupStatus == 207) {
				foreach ($glist->getIDList()) {
					my $str = $glist->getGroupFolderName($_,$lcname);
					my $name = $glist->getName($_);
					utf8::encode($name);
					$str = URLd($str);
					$str = TF::CommonUtils::decodeUTF8($str);
					# (note) queryGroup なので戻ってくるグループは1つだけ 
					push( @groupnames,{	compname => $str,
										name => $name,
										id => $_,
										creationdt => $glist->getGroupCreationDt($_)
									});
					$search_gid = $_;
					last;
				}
			}

			# 上記で取得できなかったら、所属グループも検索してみる
			if (!$search_gid) {
				my $glist2 = TF::GroupList->new();
				my $queryGroupStatus2 = $glist2->queryAvailableGroupList($URL,$USERID,$PASSWD);
				if($queryGroupStatus2 == 207 ) {

					foreach ($glist2->getIDList()) {
						# 操作ログ制約によりブロックされていればスキップ
						if ($glist2->hasOplogConstraints($_) && $use_grpconstraints) {
							next;
						}
						# 非アクティブグループは表示しない
						if (!$glist2->isActive($_)) {
							next;
						}

						my $str  = $glist2->getGroupFolderName($_,$lcname);
						my $name = $glist2->getName($_);
						utf8::encode($name);
						$str = URLd($str);
						$str = TF::CommonUtils::decodeUTF8($str);					
						if ($_ eq $gid) {
							push( @groupnames,{	compname => $str,
												name => $name,
												id => $_,
												creationdt => $glist2->getGroupCreationDt($_)
											});
							last;
						}
						# それ以外は無視
					}
				}
			}
		}
	
	elsif(!$isAll && $rec eq 'on'){
			my $search_gid;
			# $gid のグループだけを検索する
			$queryGroupStatus = $glist->queryGroupTreeList($URL,$USERID,$PASSWD,$gid);
			if ($queryGroupStatus == 207) {
				foreach ($glist->getIDList()) {
					my $str = $glist->getGroupFolderName($_,$lcname);
					my $name = $glist->getName($_);
					my $child = $glist->getChildCount($_);
					utf8::encode($name);
					$str = URLd($str);
					$str = TF::CommonUtils::decodeUTF8($str);

					# (note) queryGroup なので戻ってくるグループは1つだけ 
					push( @groupnames,{	compname => $str,
										name => $name,
										id => $_,
										creationdt => $glist->getGroupCreationDt($_)
									});
					$search_gid = $_;
					if ($child && $child > 0) {
						getRecursive($URL,$USERID,$PASSWD,$gid,$lcname,\@groupnames);
					}
	#				last;
				}
			}

			# 上記で取得できなかったら、所属グループも検索してみる
			if (!$search_gid) {
				my $glist2 = TF::GroupList->new();
				my $queryGroupStatus2 = $glist2->queryAvailableGroupList($URL,$USERID,$PASSWD);
				if($queryGroupStatus2 == 207 ) {

					foreach ($glist2->getIDList()) {
						# 操作ログ制約によりブロックされていればスキップ
						if ($glist2->hasOplogConstraints($_) && $use_grpconstraints) {
							next;
						}
						# 非アクティブグループは表示しない
						if (!$glist2->isActive($_)) {
							next;
						}

						my $str  = $glist2->getGroupFolderName($_,$lcname);
						my $name = $glist2->getName($_);
						utf8::encode($name);
						$str = URLd($str);
						$str = TF::CommonUtils::decodeUTF8($str);
						
						if ($_ eq $gid) {
							push( @groupnames,{	compname => $str,
												name => $name,
												id => $_,
												creationdt => $glist2->getGroupCreationDt($_)
											});
							last;
						}
						# それ以外は無視
					}
				}
			}
		}
	}
	
	#
	# 一般ユーザの場合
	#
	else {
		$queryGroupStatus = $glist->queryAvailableGroupList($URL,$USERID,$PASSWD);
		if($queryGroupStatus == 207 ) {

			foreach ($glist->getIDList()) {
				# 操作ログ制約によりブロックされていればスキップ
				if ($glist->hasOplogConstraints($_) && $use_grpconstraints) {
					next;
				}
				# 非アクティブグループは表示しない (一般ユーザの場合)
				if (!$glist->isActive($_)) {
					next;
				}

				my $str = $glist->getGroupFolderName($_,$lcname);
				my $name = $glist->getName($_);
				utf8::encode($name);
				$str = URLd($str);
				$str = TF::CommonUtils::decodeUTF8($str);
				if ($isAll) {
					# まとめてダウンロードの場合にはそのまま記録する
					push( @groupnames,{	compname => $str,
										name => $name,
										id => $_,
										creationdt => $glist->getGroupCreationDt($_)
									});
				}
				else {
					# 通常ダウンロードでは指定された見つかった(=所属していた)グループのみを記録する
					if ($_ eq $gid) {
						push( @groupnames,{	compname => $str,
											name => $name,
											id => $_,
											creationdt => $glist->getGroupCreationDt($_)
										});
						last;
					}
					# それ以外は無視
				}
			}
		}
	}

	return ($showname,@groupnames);
}

#
# Build CSV filename
#
sub buildCsvFileName {
	my ($from, $to, $suffix) = @_;

	return $from . "-" . $to . "_" . $suffix;
}

sub getRecursive {
	my $URL = shift || '';
	my $USERID = shift || '';
	my $PASSWD = shift || '';
	my $gid = shift || '';
	my $lcname = shift || '';
	my $groupnames = shift || '';
	my $glist = TF::GroupList->new();	
	my $queryGroupStatus = $glist->queryGroupTreeList($URL,$USERID,$PASSWD,$gid);
	if ($queryGroupStatus == 207) {
		foreach ($glist->getIDList()) {
			if ($gid eq $_){
				next;
			}
			my $str = $glist->getGroupFolderName($_,$lcname);
			my $name = $glist->getName($_);
			my $child = $glist->getChildCount($_);
		#	utf8::encode($name);
			push( @$groupnames,{ 		compname => $str,
								 name => $name,
								 id => $_,
								 creationdt => $glist->getGroupCreationDt($_)
								});
			if($child && $child > 0) {
				getRecursive($URL,$USERID,$PASSWD,$_,$lcname,$groupnames);
			}
		}
	}
}
