#!/usr/bin/perl
#------------------------------------------------------------------------------
# $Id$
#------------------------------------------------------------------------------
# License Uploader CGI
#
# Copyright (c) BAYBITS LLC. All rights reserved.
#------------------------------------------------------------------------------

use utf8;
use strict;
use Encode;
use CGI;
use HTML::Template;
use TF::CommonUtils;
use File::Copy;
#global
my $binpass				= $ENV{'TF_BIN_ROOT'};
my $sbinpass			= $ENV{'TF_SBIN_ROOT'};
my $CONFD				= $ENV{'TF_CONFIG_ROOT'};
my $APCONFD				= $ENV{'TF_APCONFIG_ROOT'};
my $LCCHECKER			= $APCONFD . '/license_checker';
my $LANGPARAM			= TF::CommonUtils::getLangPriority();
my $TEMPLATE_FILE		= './tmpl/lcuploader.tmpl.'. $LANGPARAM;
my $pagetitle 			= $ENV{'TF_FOLDER_LICENSEUPLOADER'} || '';
my $PAGETITLE			= TF::CommonUtils::decodeUTF8($pagetitle);
my $BRAND				= $ENV{'TF_BRANDNAME'} || '';
my $USERTYPE			= $ENV{'TF_USERTYPE'} || 'normal';
my $TF_LICENSEUPLOADER  = $ENV{'TF_LICENSEUPLOADER'} || 'off'; 
my $PAGEIMG				= $ENV{'TF_FOLDER_LICENSEUPLOADER_IMG'} || '';
my $CONFDTMP			= $CONFD . '/tmp/';
# (note) ここで定義されたファイル名、ディレクトリ名は $apache/bin/jobs/lcupdate.sh で意識しています.
my $LICENSE_FILE 		= 'tf_license.conf';
my $LICENSE_FILEPATH	= $CONFDTMP . '/' . $LICENSE_FILE;
my $LICENSE_TMP_FILE 	= 'tf_license.tmp';
my $LICENSE_TMP_FILEPATH= $CONFDTMP . '/' . $LICENSE_TMP_FILE;
my $LICENSE_BAK			= 'tf_license.bak';
my $LICENSE_BAKPATH		= $CONFD . '/' . $LICENSE_BAK;
my $LICENSE_BAKSRC		= $CONFD . '/' . $LICENSE_FILE;
my $RESTART_FILE		= $CONFDTMP .  '/.restart';
my $sizecheck;
my $new_license;
my $license;
my $chklicense;
my $chkup				= 0;
my $wchk;
my $i;
my $err;
my $MAXSIZE = 8;
my($user,$usera,$fopt,$nif,$nip,$st,$du);	
my $trial;
my $progress 			= 0;
my $result;
my $result2;
my $MSGTABLE_ja			= {
						CGIError		=> "CGIエラーです",
						mErrCGI			=> 'CGIモジュールの生成に失敗しました',
						NoFileErr		=> 'アップロードするファイルが選択されていません',
						LcErr			=> 'ライセンスに誤りがあります。販売元までお問い合わせください',
						Title			=> '更新しました',
						NoReboot		=> '新しいライセンスは次回サーバ起動時に反映されます',
						Reboot			=> '約１分後に反映されます。しばらくお待ちください',
						Duration		=> '無制限',
						FileErr			=> 'ライセンスファイルに誤りがあります。ファイルが大きすぎます',
					};
my $MSGTABLE_en			= {
						CGIError		=> 'CGI error found.',
						mErrCGI			=> 'Failed to create cgi module.',
						NoFileErr		=> 'Upload file has not been selected.',
						LcErr			=> 'The mistake is found in the license. Please inquire until the sales origin.',
						Title 			=> 'It updated it.',
						NoReboot		=> 'When the server will start next time. a new license is reflected.',
						Reboot			=> 'It will be reflected in about one minute. Please wait for a while.',
						Duration		=> 'unlimited',
						FileErr			=> 'The mistake is found in the license. The file is too large.',
					};
my $MSGTABLE		= ($LANGPARAM eq 'ja') ? $MSGTABLE_ja : $MSGTABLE_en;

binmode(STDOUT,":utf8");
if ($TF_LICENSEUPLOADER ne 'on' ||!$USERTYPE || $USERTYPE ne 'admin') {
	TF::CommonUtils::showAccessDeny();
	die 'admin only';
}
main();
#
# main
#
sub main {
	my	$cgi = CGI->new;
	if (!$cgi) {
		binmode(STDOUT,":utf8");
		TF::CommonUtils::showErrorPage($MSGTABLE->{CGIError},$LANGPARAM);
		print STDERR "CGI Object error";
		return;
	}

	if ($cgi->cgi_error) {
		binmode (STDOUT, ":utf8");
		TF::CommonUtils::showErrorPage($MSGTABLE->{CGIError} . $cgi->cgi_error,$LANGPARAM);
		print STDERR "CGI Error(" . $cgi->cgi->error . ")";
		return;
	}
	# CGIパラメータの取得とライセンスのパース
	my ($cmd,$file,$reboot) = parseCgiParams($cgi);
	#ライセンスファイルをアップロードした場合
	if ($cmd eq 'upload') {
		if ($file eq undef) {
			TF::CommonUtils::showErrorPage($MSGTABLE->{NoFileErr}, $LANGPARAM);
			print STDERR "No upload file";
			return;
		}
		$err = upload($file);
		if ($err == 1) {
			return;
		}
		($new_license,$chklicense) = getlicense($binpass,$CONFDTMP,$LICENSE_TMP_FILE);
		$chkup = $chklicense;
		#ライセンスファイルが壊れている場合はファイルを削除する
		if ($chkup != 0) {
			TF::CommonUtils::showErrorPage("$MSGTABLE->{LcErr}",$LANGPARAM);
			print STDERR "License error";
			$result2 = unlink("$LICENSE_TMP_FILEPATH");
			if ($result2 != 1) {
				print STDERR "Temp file deletion failed";
			}
			return;
		}
		($user,$usera,$fopt,$nif,$nip,$st,$du) = parselicense($new_license);	
	}
	#リセットボタンを押した場合
	elsif ($cmd eq 'reset') {
		$result = unlink("$LICENSE_TMP_FILEPATH");
		if ($result != 1) {
			TF::CommonUtils::showErrorPage("$MSGTABLE->{CGIErr}",$LANGPARAM);
			print STDERR "Temp file deletion failed";
			return;
		}
		if (-e "$RESTART_FILE") {	
			$result2 = unlink("$RESTART_FILE");
			if ($result2 != 1) {
				print STDERR "Restart file deletion failed";
				return;
			}
		}
		($license,$chklicense) = getlicense($binpass,$CONFD,$LICENSE_FILE);
		($user,$usera,$fopt,$nif,$nip,$st,$du) = parselicense($license);	
	}
	#反映ボタンを押した場合
	elsif ($cmd eq 'apply') {
		($i,$wchk) = checklicense($sbinpass,$LCCHECKER);
		#ライセンスファイルが正しくない場合
		if ($wchk != 0) {
			$result = unlink("$LICENSE_TMP_FILEPATH");
			if ($result != 1) {
				print STDERR "Temp file deletion failed";
				return;
			}
			TF::CommonUtils::showErrorPage($MSGTABLE->{LcErr},$LANGPARAM);
			print STDERR "License error of license_checker";
			return;
		}
		else {
			#現在のライセンスファイルをバックアップする
			copy("$LICENSE_BAKSRC","$LICENSE_BAKPATH");
			#tempファイルをtf_license.confにリネーム
			rename "$LICENSE_TMP_FILEPATH","$LICENSE_FILEPATH";
			#再起動用ファイル.restartを先に出力、出力できない場合はリネームしたファイルを削除
			if (!open(OUT, ">$RESTART_FILE")) {
				unlink("$LICENSE_FILEPATH");
				print STDERR "Can't open .restart";
				return;
			}
			binmode OUT;
			close OUT;
			#再起動をしない場合.restartを削除
			if ($reboot == 0) {
				$result = unlink("$RESTART_FILE");
				TF::CommonUtils::showMessagePage($MSGTABLE->{NoReboot},$LANGPARAM,$MSGTABLE->{Title});	
				exit;
			}
			#再起動を行う場合
			elsif ($reboot == 1) {
				TF::CommonUtils::showMessagePage($MSGTABLE->{Reboot},$LANGPARAM,$MSGTABLE->{Title});
				exit;
			}
		}
	}
	else {
		($license,$chklicense) = getlicense($binpass,$CONFD,$LICENSE_FILE);
		($user,$usera,$fopt,$nif,$nip,$st,$du) = parselicense($license);	
	}
	$st += (86400*$du);
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($st);
	if ($du == 0 && $chkup == 0) {
		$trial = $MSGTABLE->{Duration};
	}
	elsif ($chkup != 0) {
		$trial = "";
	}
	else {
		$trial = sprintf("%04d/%02d/%02d %02d:%02d:%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec);
	}
	#オプション
	my $chopt;
	my $x;
	my @option = (0,0,0,0,0,0,0);
	for ($i = 1; $i < 8; $i++) {
		$chopt = $fopt;	
		for ($x = 1; $x < $i; $x++) {
			$chopt = $chopt / 2;
		}
		$chopt = $chopt & 0x01;
		if ($chopt == 0x01) {
			$option[$i-1] = 1;
		}
	}
	my $DB			 =	@option[1];
	my $LDAP		 = 	@option[2];
	my $virus 		 = 	@option[3];
	my $Enciph 		 =  @option[4];
	my $AutoDelete   = 	@option[5];
	my $Extcmd   	 =  @option[6];
	if (-e "$LICENSE_FILEPATH") {
		$progress = 1;
	}
	#画面出力
	if (!open (TEMPLATE,"<$TEMPLATE_FILE")) {
		TF::CommonUtils::showTemplateOpenErr($LANGPARAM);
		return;
	}
	binmode (TEMPLATE , ":utf8");
	my $htmltmpl = HTML::Template->new( filehandle => *TEMPLATE,
	case_sensitive => 1,
	die_on_bad_params => 0);
	$htmltmpl ->param(	
		brandname => $BRAND,
		pagetitle => $PAGETITLE,
		pageimg	  => $PAGEIMG,
		user	  => $user,
		usera	  => $usera,
		nif		  => $nif,
		IP		  => $nip,
		trial	  => $trial,
		DB		  => $DB,
		LDAP	  => $LDAP,
		virus	  => $virus,
		Enciph	  => $Enciph,
		AutoDelete=> $AutoDelete,
		Extcmd	  => $Extcmd,
		chkup	  => $chkup,
		progre	  => $progress,
	);
	print "Content-Type: text/html; charset=UTF-8\n\n";
	print $htmltmpl->output;
	close(TEMPLATE);
}

#
#ライセンスデコード処理
#
sub getlicense {	
	my $pass = @_[0];	
	my $CONFD = @_[1];
	my $getlicense = @_[2];
	my $license = `$pass/tfslcvalidator -f $CONFD/$getlicense -p`;
	my $chklicense = `echo $?`;
	return($license,$chklicense);
}
#
#ライセンスアップロード処理
#
sub upload {
	my $buffer;
	my $FH = @_[0];

	if (!open(OUT, ">$LICENSE_TMP_FILEPATH")) {
		TF::CommonUtils::showTemplateOpenErr($LANGPARAM);
		return 1;
	}
	binmode OUT;
	$sizecheck = 0;
	while (read($FH, $buffer, 1024)) { # Read form $fh insted of $file
		
		if ($sizecheck < $MAXSIZE) { 
			print OUT $buffer;
		}
		else {
			
		}
		$sizecheck++;
	}
	close OUT;
	if ($sizecheck > $MAXSIZE){
		print STDERR "The file is too large.";
		$result2 = unlink("$LICENSE_TMP_FILEPATH");
		if ($result2 != 1) {
			print STDERR "Temp file deletion failed";
		}
		TF::CommonUtils::showErrorPage($MSGTABLE->{FileErr},$LANGPARAM);
		return 1;
	}
	return 0;
}
#
# URLパラメータの取得とパース
#
sub parseCgiParams {
	my $cgi = @_[0];
	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      = $cgi->param('cmd');
	my $file     = $cgi->upload('file');
	my $reboot   = $cgi->param('reboot');
	# パラメータのvalidation
	return ($cmd,$file,$reboot);
}
#
#ライセンスのパース
#
sub parselicense {
	if (@_[0] =~/u=(\d+);ua=(\d+);fopt=(\d+);nif=([^;]+);nip=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3});st=(\d+)\ntp=(\w+);st=(\d+);du=(\d+)/) {
		return ($1,$2,$3,$4,$5,$8,$9);
	}
}

#
#ライセンスチェック
#
sub checklicense {
	my	$pass = @_[0];
	my	$LCCHECKER = @_[1];
	my  $Emes = `$pass/httpd -t -f $LCCHECKER 2>&1`;
	my	$wchk  =  $?/256;
	if ($wchk != 0) {
		$Emes =~ s/\n/   /g;
		print STDERR $Emes;
	}
	
	return ($Emes,$wchk);
}

