#!/usr/bin/perl

require "config.pl";

 $time = time();
 ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
 $hour1=$hour+1;
 $mon++;
 $year += 1900;
 $lastyear = $year-1;
 $lastyear2 = $year-2;

&read_post;

if ($INPUT{'charge_info'}){ &charge_info; }
if ($INPUT{'billing_contact'}){ &billing_contact; }
else{ &cc_form; }

#################################
sub charge_info{

	$INPUT{'cc'}=~s/\D//g;
	unless (cc_validate($INPUT{'cc'})){ &error('Credit card number is not correct'); }
	if (!$INPUT{'year'} || !$INPUT{'month'} || !$INPUT{'day'}){ &error('Charge Date is not defined'); }
	my $transaction_date = date_to_epoch($INPUT{'year'},$INPUT{'month'},$INPUT{'day'});

	# cc_md5=[md5_value_of_creditcard], merchant_ids=[comma_separated_mids], transaction_date=[epoch_format_date]

	my $post = "ACTION=MERCHANT_CS&cc_md5=".URLEncode(md5_create($INPUT{'cc'}))."&merchant_ids=".URLEncode($merchant_ids)."&transaction_date=".$transaction_date;

	my $rez;
	($rez,$hdr,$err)=curl_request($gateway_url,'',$post);

	unless ($rez){ &error('connection error'); }

	my %RZ = record_to_hash('',$rez);

	my $EML_DATA;

	if ($RZ{'ERROR'}){ &error( $RZ{'ERROR_CODE'}." - ".$RZ{'ERROR_MESSAGE'}); }
	elsif(!$RZ{'SUCCESS'}){ &error('CONNECTION RESPONSE IS NOT CORRECT'); }

	my @TRANSDATA = split(/\n/,$RZ{'TRANSDATA'});


	my $count=0;
	my $phone_verified="";
	my $phone="";

	my $OUTPUT = '<table border=1 width=90% cellpadding=5 cellspacing=0 bgcolor="#FFFFEB">';

	foreach my $line(@TRANSDATA){
		$count++;
		my %RE = record_to_hash('',$line);
		if ($RE{'phone_verified'}){ $phone_verified=1; }
		$phone = $RE{'phone'};
		$OUTPUT.= <<EOF;

<tr><td bgcolor="#DFDFDA"> [$count]  Transaction ID:	$RE{'id1'}</td></tr>
<tr><td>
<pre>
ORDER DATE:  	$RE{'date_order'} (GMT)
CHARGE DATE:	$RE{'date_auth'} (GMT)

Amount:		\$$RE{'AMOUNT'} USD

Name:	  	$RE{'NAME'}
Street: 	$RE{'address'}
City: 		$RE{'city'}
State: 		$RE{'state'}
Zip: 		$RE{'zip'}
Country: 	$RE{'country'}

IP Address:	$RE{'ip'}
IP Country:  	$RE{'ip_geo'}
IP State: 	$RE{'MAXMIND_ip_region'}
IP ISP: 	$RE{'MAXMIND_ip_isp'} / $RE{'MAXMIND_ip_org'}

Email:          $RE{'email_masked'}  (for privacy reason a part of email address is masked with "*")
Phone:          $RE{'phone'}
</pre></td></tr>
EOF

	$EML_DATA.=<<EOF;
name:		$RE{'NAME'}
date:		$RE{'date_order'}
amount:		$RE{'AMOUNT'}
trans ID:	$RE{'id1'}
order EML:	$RE{'email_masked'}
phone:		$RE{'phone'}
order IP:	$RE{'ip'}
browser:	$RE{'useragent'}
-----------------------------

EOF
		$OUTPUT.="</table>";
	}

	$EML_DATA = encode($EML_DATA);

	if ($phone_verified){
		$VERIFIED_PHONE_MSG="<font color=green>NOTE: The submitted credit card number was authorized by phone. A cardholder answered an authorization call at the number $phone and confirmed it. The voice conversation is stored as the proof of purchase.</font><br><br>";
	}
	my $trword = "transaction";
	$trword	.= "s" if ($count > 1);

	print "Content-type: text/html\n\n";
	print <<EOF;
	We found $count $trword matching the submitted credit card number. The charge details are the following:<br><br>

$OUTPUT
$VERIFIED_PHONE_MSG
<font color=gray>
All background information of all orders including internet address and an unique identifier of personal computer of the purchaser were recorded at the time of purchase.<br>
In case of credit card fraud, all collected information will be submitted to a domestic cyber crime police unit for investigation.<br>
</font>
<br>

<form name="contactform" method="post" action="">
<input type="hidden" name="EDATA" 		value="$EML_DATA">
<script language="JavaScript">
<!--
	function reason_change(){
		var msg = "";
		if (document.contactform.reason.value == "FRAUD"){
			msg='You are reporting CREDIT CARD FRAUD.<br><br>'
			   +'BY SUBMITTING THIS REQUEST YOU HEREBY AGREES THAT:<br><br>'
			   +'<li> You carefully reviewed shown above transaction details and declares that it was made not by you and is made without your authorization.</li>'
			   +'<li> This request will be forwarded to the BANK Security Department for investigation. All personal order information along with internet logs and IP address will be applied to this fraud case.</li>'
			   +'<li> The amount of transaction will be credited back to the credit card</li>'
			   +'<li> Credit card Number will be blacklisted and cannot be used for further online purchases</li>'
			   +'<li> In the case of FALSE REPORT, all investigation expenses will be collected from the initiator of misstatement. Credit score may be affected. </li>';

			document.getElementById("warn").innerHTML = '<table border=0 bgcolor=red cellpadding=5><tr><td><font size=3 color="#EEEEB0"><b>'+msg+'</b></font></td></tr></table>';
		}
		else if (document.contactform.reason.value == "UNSATISFIED"){
			msg='You are reporting a problem with purchased product.<br><br>'
			   +'Please describe below the details of your problem.'
			document.getElementById("warn").innerHTML = '<table border=0 bgcolor=red><tr><td><font size=3 color="#EEEEB0"><b>'+msg+'</b></font></td></tr></table>';
		}
		else{
			document.getElementById("warn").innerHTML = "";
		}
	}
//-->
</script>

<table border=1 width=90% cellpadding=5 cellspacing=0 bgcolor="#EBEBFF">
<tr><td bgcolor="#DBDBDF">
	 To contact us regarding the order, please fill the form below.
</td></tr>
<tr><td> SELECT SUBJECT: 
	<select name="reason" onchange="reason_change();">
		<option name=""			value=""		> ---- select subject ---- </option>
		<option name="FRAUD" 		value="FRAUD"		> Report credit card FRAUD. The order was made without my authorization!</option>
		<option name="UNSATISFIED" 	value="UNSATISFIED"	> I have problem with with purchased product.</option>
		<option name="OTHER"		value="OTHER"		> Just ask a question </option>
	</select>
</td></tr>
<tr><td>
<div id="warn"></div>
</td></tr>
<tr><td>
	Your Email: <input type=text name="from" maxlength=100></textarea>
</td></tr>
<tr><td>
	Your Message: <br>
	<textarea name="body" rows=10 cols=50></textarea>
</td></tr>
<tr><td> 
	<input type="submit" name="billing_contact" value="    SUBMIT    ">
</td></tr>

</table>

</form>
EOF
	exit;
}

#############################################################################
sub billing_contact{

	unless ($INPUT{'body'}){	&error('ERROR: "Your Message is emply" '); }
	unless ($INPUT{'reason'}){	&error('ERROR: "Please select SUBJECT." '); }
	unless ($INPUT{'from'}){	&error('ERROR: "Please fill your EMAIL." '); }
	unless ($INPUT{'from'}=~/^([\w\-\.\_]+\@[\w\-\.]+\.[a-zA-Z]{2,4})$/){	&error("ERROR: EMAIL address is incorrect - .$INPUT{'from'} "); }

	my $SUBJECT;
	$SUBJECT = "BILLING INQUIRY: $INPUT{'reason'}";
	$SUBJECT = "REFUND REQUEST: $INPUT{'reason'}"  if ($INPUT{'reason'}=~/^(FRAUD|UNSATISFIED)$/);
	$SUBJECT = "BILLING INQUIRY: $INPUT{'reason'}" if ($INPUT{'reason'}=~/^(OTHER)$/);

	my $EML_DATA = decode($INPUT{'EDATA'});

	my $FROM=$INPUT{'from'};

	my $MESSAGE=<<EOF;
$EML_DATA
$INPUT{'body'}
------------------------------------
Sender IP:	$ENV{'REMOTE_ADDR'};
Sender Br:	$ENV{'HTTP_USER_AGENT'}
EOF
	open(MAIL, "|$mail_prog -t") || &error("Could not send out email");
	print MAIL "To: $TO_MAIL \n";
	print MAIL "From: $FROM \n";
	print MAIL "Subject: $SUBJECT \n\n";
	print MAIL "$MESSAGE";
	print MAIL "\n\n";
	close (MAIL);

	print "Content-type: text/plain\n\n";
	print <<EOF;
	Your request has been successfully received and will be answered within 48 hours.

	Thank you.

EOF
	exit;
}

#############################################################################
sub cc_validate{
    my ($number) = @_;
    my ($i, $sum, $weight);
    
    return 0 if $number =~ /[^\d\s]/;

    $number =~ s/\D//g;

    return 0 unless length($number) >= 13 && 0+$number;

    for ($i = 0; $i < length($number) - 1; $i++) {
	$weight = substr($number, -1 * ($i + 2), 1) * (2 - ($i % 2));
	$sum += (($weight < 10) ? $weight : ($weight - 9));
    }

    return 1 if substr($number, -1) == (10 - $sum % 10) % 10;
    return 0;
}

#####################################
sub date_to_epoch{	# USAGE: ([year],[month],[day],[hour],[min],[sec])

	my $year=$_[0];
	my $month=$_[1];
	my $day=$_[2];
	my $hour=$_[3];
	my $min=$_[4];
	my $sec=$_[5];

	if (!$month || !$year || !day){ &error_log("date_to_epoch: wrong parameters: $year $month $day"); return; }
	eval ('use Time::Local;');
	if ($@) { &error_log('DE','date_to_epoch: cannot load Time::Local,'.$@); return; }

	my $DATE_UTC = timelocal($sec, $min, $hour, $day, ($month-1), $year);

	return $DATE_UTC;
}
####################
sub URLEncode {
    my $theURL = $_[0];
   $theURL =~ s/([\W])/"%" . uc(sprintf("%2.2x",ord($1)))/eg;
   return $theURL;
}

####################
sub URLDecode{
	my $theURL = $_[0];
	$theURL =~ tr/+/ /;
	$theURL =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
	return $theURL;
}
####################
sub md5_create{
	my $string=$_[0];
	require Digest::MD5; 
	$md5 = Digest::MD5->new; 
	$md5->add($string); 
	$digest = $md5->hexdigest; 
	$digest = uc($digest);
	return $digest;
}
#########################################
sub read_post{
	my $buffer;
	read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
	my @pairs = split(/&/, $buffer);
	foreach $pair (@pairs) {
		my ($name, $value) = split(/=/, $pair);
		unless ($name=~/[-_\.a-zA-Z0-9\s]+/){ &error('invalid input name: '.$name);}
		unless ($value=~/[-a-zA-Z0-9_\.\+\%\s]*/){ &error('invalid input value: '.$value);}
		$value =~ tr/+/ /;
		$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
		if ($value=~/\x00|\xFF/){ &error('illegal chars in input');}
		if ($INPUT{$name}) { $INPUT{$name} = $INPUT{$name}.",".$value; }
		else { $INPUT{$name} = $value; }
	}
}
########################################################################
sub curl_request{		# USE:    ([url],[referrer],[post],[login],[password],[connect_timeout],[max_connect_time])
				# RETURN: ([content],[header],[error_message])
	my $url = $_[0];
	my $ref = $_[1];
	my $post = $_[2];
	my $login = $_[3];
	my $passw = $_[4];
	my $rez;

	my $connect_timeout = 20;
	my $max_connect_time = 600;

	if ($_[5] >=1 ){ $connect_timeout	= $_[5]; }
	if ($_[6] >=1 ){ $max_connect_time	= $_[6]; }

	unless ($url=~/^https?\:\/\/[\w\.\-\_]+\:?\d{0,5}\/?.*$/s){
		return ('','','ERROR: invalid url');
	}
	unless (($ref=~/^https?\:\/\/[\w\.\-\_]+\:?\d{0,5}\/?.*$/s)||(!$ref)){
		return ('','','ERROR: invalid ref');
	}

	my $curl = "curl";
	my $curl_opt='';
#	$curl_opt.=' --max-filesize 100000';						# set limits
#	$curl_opt.=' --retry 2 --retry-delay 5';
	$curl_opt.=" --connect-timeout $connect_timeout --max-time $max_connect_time ";		# set limits
	$curl_opt.=" -i -k";						# include header to output, allow insecure ssl
	$curl_opt.=" -e $ref" if ($ref);
	$curl_opt.=" --data-ascii \"$post\"" if ($post);			# POST
	$curl_opt.=" -basic \"$login:$passw\"" if ($login && $passw);	# BASIC AUTH
	#open (README, "$curl $curl_opt \"$url\" 2>&1 |");		# receiving STDERR within STDOUT (best for debug)
	open (README, "$curl $curl_opt \"$url\" 2>/dev/null |"); 	# disregarding STDERR
	my $response=<README>;
	my ($header,$contin)="";  
	while (<README>){
		tr/\000-\037//d;
		if ((!$_)&&($response=~/\S+ 100/)){ $response=""; }	# deal with "HTTP/1.1 100 Continue"
		elsif(!$_){ last; }
		if (!$response){$response=$_;}
		$header.=$_."\n";
	}
	my $content=join ("", <README>); # Ñ÷èòûâàåì îñòàòîê îòâåòà.
	close (README);

	my $resp_code=$1 if $response=~/\S+ (\d+)/; 

#open (DD,">>./_curl");
#print DD "\n---\n$curl $curl_opt \"$url\"\n$content\n$header\n";
#close (DD);

	if ($resp_code >= 300 and $resp_code < 400) {
		return curl_request($1, $url) if $header=~/Location:\s+(.+)$/m;
		return ("",$header,"CONNECTION ERROR: $response");
	}elsif($response=~/200/) {
		return ($content,$header,"");
	}
	elsif($response){
		return ("",$header,"CONNECTION ERROR: $response");
	}
	else{
		return ("","","CONNECTION ERROR: destination unreachable");
	}

}
#####################################################################
sub record_to_hash{			# making hash values from a record string
					# USAGE:    (HASH_NAME, STRING_RECORD)
					# EXAMPLE1:  ('VENDOR','a=1&b=2&c=3')	RESULT: make global %hash
					# EXAMPLE2:  ('','a=1&b=2&c=3')		RESULT: returns localized %hash
	my $hash_name=$_[0];
	my $string=$_[1];

	my %HSH=();

	if ($hash_name){
		eval('%'.$hash_name.'=();');
	}

	unless ($string=~/^[-a-zA-Z0-9_\.\,\;\+\%\s\=\&]+$/s){ &error_log('HR','record_to_hash: invalid STRING submitted 2: '.$string); return; }

	if ($hash_name){
		unless ($hash_name=~/^[a-zA-Z0-9_]+$/s){ &error_log('HR','record_to_hash: invalid HASH name submitted 2: '.$hash_name); return; }
	}
	my @pairs = split(/&/, $string);
	foreach $pair (@pairs) {
		my ($name, $value) = split(/=/, $pair);
	
		unless ($name=~/^[-_\.a-zA-Z0-9\s]+$/){ &error_log('HR','record_to_hash: invalid name in db record: '.$name."<br>".$string); return; }
		unless ($value=~/^[-a-zA-Z0-9_\.\,\;\+\%\s]*$/){ &error_log('HR','record_to_hash: invalid input in db record: '.$value); return; }
	
		$value =~ tr/+/ /;
		$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
	
		if ($value=~/\x00|\xFF/){ &error('record_to_hash: illegal chars in db string'); return; }
		
		if ($hash_name){
			eval('$'.$hash_name.'{$name} = $value;');
		}
		else{
			$HSH{$name} = $value;
		}
	}
	if (!$hash_name){
		return %HSH;
	}
}

#####################
sub error{
	$msg = $_[0];
		print "Content-type: text/plain\n\n";
		print "SYSTEM ERROR: $msg";
		exit;
	return;
}

#########################################
sub cc_form{

	print "Content-type: text/html\n\n";
	print <<EOF;

<html>
<head>
<title>$COMPANY - BILLING SUPPORT</title>
</head>
<body>

<center>
<form method=post action="" autocomplete=off>
<table border=0 width=100% height=100%><tr><td align=center valign=middle>

	<br><b><font size=5 color=blue>$COMPANY - CREDIT CARD CHARGE INFORMATION</font></b><br><br>

	<table border=0 width=400 cellspacing=5>
		<tr><td colspan=2>To find the details of a credit card charge on your statement please fill and submit the following form.</td></tr>
		<tr><td colspan=2 height=20>&nbsp</td></tr>
		<tr><td align=right> <b>Cardholder Name:</b> </td><td align=left><input type=text name=name></td></tr>
		<tr><td align=right> <b>Credit Card Number:</b> </td><td align=left><input type=text name=cc></td></tr>
		<tr><td align=right> <b>Date Of Charge:</b> </td><td align=left> <select name=year><option value="">Year</option><option value="$year">$year</option><option value="$lastyear">$lastyear</option><option value="$lastyear2">$lastyear2</option></select><select name=month><option value="">Month</option><option value="01">1 - Jan</option><option value="02">2 - Feb</option><option value="03">3 - Mar</option><option value="04">4 - Apr</option><option value="05">5 - May</option><option value="06">6 - Jun</option><option value="07">7 - Jul</option><option value="08">8 - Aug</option><option value="09">9 - Sep</option><option value="10">10 - Oct</option><option value="11">11 - Nov</option><option value="12">12 - Dec</option></select><select name=day><option value="">Day</option><option value="01">1</option><option value="02">2</option><option value="03">3</option><option value="04">4</option><option value="05">5</option><option value="06">6</option><option value="07">7</option><option value="08">8</option><option value="09">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option><option value="21">21</option><option value="22">22</option><option value="23">23</option><option value="24">24</option><option value="25">25</option><option value="26">26</option><option value="27">27</option><option value="28">28</option><option value="29">29</option><option value="30">30</option><option value="31">31</option></select></td></tr>
		<tr><td colspan=2>&nbsp</td></tr>
		<tr><td colspan=2 align=center><input type=submit name=charge_info></td></tr>
	</table>

</td></tr></table>
</center>
</form>
</body>
</html>
EOF
	exit;
}

##############################
sub encode ($;$)
{
    my $res = "";
    my $eol = $_[1];
    $eol = "\n" unless defined $eol;
    pos($_[0]) = 0;                          # ensure start at the beginning
    while ($_[0] =~ /(.{1,45})/gs) {
	$res .= substr(pack('u', $1), 1);
	chop($res);
    }
    $res =~ tr|` -_|AA-Za-z0-9+/|;               # `# help emacs
    # fix padding at the end
    my $padding = (3 - length($_[0]) % 3) % 3;
    $res =~ s/.{$padding}$/'=' x $padding/e if $padding;
    # break encoded string into lines of no more than 76 characters each
    $res;
}
sub decode($)
{
    local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123]

    my $str = shift;
    my $res = "";

    $str =~ tr|A-Za-z0-9+=/||cd;            # remove non-base64 chars
    if (length($str) % 4) {
        require Carp;
        Carp::carp("Length of base64 data not a multiple of 4")
    }
    $str =~ s/=+$//;                        # remove padding
    $str =~ tr|A-Za-z0-9+/| -_|;            # convert to uuencoded format
    while ($str =~ /(.{1,60})/gs) {
        my $len = chr(32 + length($1)*3/4); # compute length byte
        $res .= unpack("u", $len . $1 );    # uudecode
    }
    $res;
}
