#!/usr/bin/perl

##################################
##
## vt_scan_db_version.pl
##
## Checks scan results of all files in current directory and subdirectories with virustotal.com
## If it hasn't been scanned, upload it and check results later.
##
##################################

## scan by actual file type, or take extension literally.
## set this to 1 to scan exe files with .tmp extension, and the like.
## This switches the @extension_priority array below to scan by _actual_
## file type, rather than file type the extension claims.
##
## Any executable that has a non-standard extension (.tmp, .this_is_not_a_virus, etc.)
## will be given the file type of 'hidden-exe'.
## Any extension which should be text but isn't (.txt, .ini, .inf, etc) will be
## given the file tyep of 'hidden-txt'.
## Any Microsoft Office document which doesn't have a standard MS Office extension
## will be given the file type of 'hidden-mso'.
## Internet Explorer cache files (commonly named index.dat) are given
## an 'ie-dat' file type.
##
## Place these in your extension priority where you would like it to be scanned.
$scan_by_file_type = 1;


## extension priority
## scan these extensions first, to find likely infections before unlikely ones.
## This must end with '%' in order to scan all files.  Otherwise, it will
## only scan files with the given extensions.
## Case sensitivity is dependent on settings of SQL server.  CB Services data store is
## not case sensitive, so "file.sys" and "FILE.SYS" will both be given the same priority.
#@extension_priority = ('sys', 'drv', 'exe', 'pf', 'dll', 'pif', 'vbs', 'msi', 'ocx', 
#'ini', 'scr', 'cpl', 'cab', 'dot', 'swf', 'pdf', 'inf', 'tmp', 'dat', '%');
@extension_priority = (
'sys', 'drv', 'exe', 'dll',
#'pf', 
'scr', 'cpl', 'ocx', 'ime', 'ax', 'pif', 
'hidden-exe',
'com', 'vbs', 'msi', 'cab', 'dot', 'swf', 'fdf',  
'mui', 'tmp', 'dat', '386', 'js', 'bat', 'cmd',
'inf',
'bin', 
#'mp3',
'wma', 'rtf', 'hlp', 'jar', 'ex_', 'ini', 'prc', 'par', 'hta', 'wsh',
'vxd', 
'hidden-txt', 'hidden-mso', 
#, 'chm'
#, '%'
);

## Some filetypes/extensions are infectable, but can potentially expose private information
## if sent to web services for scanning.  These are separated into two groups, depending on
## the likelihood of these filetypes containing private information.  These groups are then
## added to the scanning list by the $scan_privacy_extensions setting.  Setting this to 0 will
## only scan the above list, @extension_priority.  Setting this to 1 will also scan extensions
## in the @privacy_extension_1_priority array.  These are less likely to contain private information.
## Settings $scan_privacy_extensions to 2 will also scan the filetypes in @privacy_extension_2_priority.
## Settings $scan_privacy_extensions to 3 will also scan the filetypes in @privacy_extension_3_priority.
## These higher number filetypes are more likely to contain private information, so be wary with this setting.
## Default is 1, to scan filetypes in the first group.
$scan_privacy_extensions = 1;

@privacy_extension_1_priority = ('dot', 'xlt', 'sh', 'pl', 'zip'
);

@privacy_extension_2_priority = ('html', 'pdf', 'php'
 );

@privacy_extension_3_priority = ('doc', 'docx', 'mdb', 'xls', 'ppt', 'pps'
);



### vbe, js, jse, wsf, wsh
##*.ACM;*.ACV;*.ADT;*.BTM;*.CLA;*.CSC;*.CSH;*.HTT;
##*.JSE;*.JTD;*.MSO;*.OBD;*.OBT;*.PM;*.POT;*.SHB;*.SHS;*.SMM;*.VBE;
##*.VSD;*.VSS;*.VST;*.WSF;*.OVA;*.OVB;*.OVC;*.OVD;*.OVE;*.OVF;*.OVG;*.OVH;*.OVI;*.OVJ;*.OVK;*.OVL;*.OVM;*.OVN;*.OVO;*.OVP;*.OVQ;
##*.OVR;*.OVS;*.OVT;*.OVU;*.OVV;*.OVW;*.OVX;*.OVY;*.OVZ;*.OV0;*.OV1;*.OV2;*.OV3;*.OV4;*.OV5;*.OV6;*.OV7;*.OV8;*.OV9;*.XLA;*.XLB;*.XLC;*.XLD;*.XLE;
##*.XLF;*.XLG;*.XLH;*.XLI;*.XLJ;*.XLK;*.XLL;*.XLM;*.XLN;*.XLO;*.XLP;*.XLQ;*.XLR;*.XLT;*.XLU;*.XLV;*.XLW;*.XLX;*.XLY;*.XLZ;*.XL0;*.XL1;*.XL2;*.XL3;*.XL4;
##*.XL5;*.XL6;*.XL7;*.XL8;*.XL9;*.MPA;*.MPB;*.MPC;*.MPD;*.MPE;*.MPF;*.MPG;*.MPH;*.MPI;*.MPJ;*.MPK;*.MPL;*.MPM;*.MPN;*.MPO;*.MPP;*.MPQ;*.MPR;
##*.MPS;*.MPT;*.MPU;*.MPV;*.MPW;*.MPX;*.MPY;*.MPZ;*.MP0;*.MP1;*.MP2;*.MP4;*.MP5;*.MP6;*.MP7;*.MP8;*.MP9


## Set this to 1 to scan filetypes that are currently unrecognized by this program.  These will be scanned
## last in the list of whatever filetypes have been selected to be scanned, with the exception of the all_files
## setting below.  Note that the unix 'file' command returns 'data' for filetypes it does not recognize.
## These filetypes will not be included if this is set to 1, as they are given a filetype of 'data'.  If
## these filetypes are to be scanned, an extension of 'data' should be included in a priority list somewhere,
## or $scan_all_files should be set to 1.  This setting is simply to scan explicit filetypes which have not 
## yet been coded into this program to be recognized.
$scan_unknown_filetypes = 0;

## Scan all files.  This will scan all remaining files after the priority extensions are completed.
## Usually unnecessary if $scan_by_filetype is set to 1, as plaintext files, among other
## filetypes, are not infectable. (This does not include .inf text files, which can contain
## malicious installers, but these are treated as a separate, not plaintext filetype.)
$scan_all_files = 0;



## file extensions to not scan at all. 
## Be VERY careful with this.  You can easily skip scanning viruses entirely if 
## you're too liberal with this setting.  It's recommended to leave as default.
## It's not yet fully implemented, so this setting currently does nothing.
##########     @do_not_scan = ('log', 'txt');


## scan_only_priority_filetypes controls whether scanning stops after the priority filetype list
## is complete (1) or whether all other files are scanned after completing the priority list (0)
$scan_only_priority_filetypes = 1;

## hash_only_priority_filetypes set to 1 only stores hashes for files in the priority list.
## Note that this will prevent other filetypes from being scanned, even if 
## scan_only_priority_filetypes is set to 0.
$hash_only_priority_filetypes = 0;


## biggest filesize that VT is currently accepting through web interface.
$max_file_size_to_scan = 19700000;

## largest number of files to be scanning at VT, before needing to pull some results.
$max_files_to_scan_at_once = 500000;

## rescan all infected files.  Setting this to 1 (true) will hopefully reduce false positives
## from scan results already stored locally.
$rescan_infected = 1;

## only rescan infected files if total detections is less than this setting.
## Setting this to 4 or so will rescan the potentially false positives, but not
## the 39/42 massively infected files, saving rescan time.
$rescan_only_if_detections_less_than = 4;
$rescan_only_if_age_greater_than = 3;
$rescan_only_if_span_less_than = 180;

## rescan if total scanners is too low.
## VT used to only scan with 30-35 programs.
## this will rescan all really old results, regardless of date span.
$rescan_if_scanners_less_than = 38;

## If difference between first VT scan and last VT scan is bigger than this,
## assume a non-infection result is permanent.
## I.E. - if they haven't found a virus in the file in the first six months, they're
## likely not going to find one at all.
$date_span_for_no_rescan = 60;


## oldest scan results to trust, in days.  Lower this during major breakouts.
## this value is ignored if the scan span is greater than the above setting.
$days_old_to_rescan = 5;

## how long to sleep in seconds between web requests so as not to overwhelm VT.
$sleep_between_files = 12;

## when a file has been uploaded to VT, let at least this many seconds pass
## before requesting results for that file.
$allow_seconds_for_new_upload_scan = 450;

## sometimes VT messes up on file uploads.
## retry the upload, up to this number of times.
$max_retries_for_upload = 3;


## authentication shit...
$vt_api_key = '472d92cc24580fed2bcb562aa27a1742612be5913bb91712f4ff5826eca96345';
$db_host = '172.20.1.3';
$db_name = 'vt_scan';
$db_user = 'vt_scan';
$db_pass = 'vt_scan';

$debug = 2;

###################################################################################
#################  DO NOT CHANGE ANYTHING BELOW THIS LINE!!!   ####################
###################################################################################

use Data::Dumper;
use DBI;
use File::Find;
use File::Basename;
use Cwd;
use Digest::SHA;
use Digest::MD5;
use LWP;

$| = 1;
$upload_borked = 0;


## Completely assemble filetypes list, depending on above settings.
if ($scan_privacy_extensions >= 1)
	{
	@extension_priority = (@extension_priority, @privacy_extension_1_priority);
	if ($scan_privacy_extensions >= 2)
		{
		@extension_priority = (@extension_priority, @privacy_extension_2_priority);
		if ($scan_privacy_extensions >= 3)
			{
			@extension_priority = (@extension_priority, @privacy_extension_3_priority);
		}
	}
}
if ($scan_unknown_filetypes)
	{
	@extension_priority = (@extension_priority, 'zyxwv');
}
if ($scan_all_files)
	{
	@extension_priority = (@extension_priority, '%');
}

## Make sure program is running within authorized environment::

#$ps_output = `ps -A | grep openvpn`;

## check if running from Live CD.
$authorized_user = 0;
$live_cd = 0;
open(PARTITIONFILEHANDLE, '/proc/partitions') or die "Unauthorized environment detected.\n";
while($partline = <PARTITIONFILEHANDLE>)
	{
	#print "Partline: ".$partline."\n";
	if ($partline =~ m/loop.$/)
		{
		$live_cd = 1;
	}
}
close PARTITIONFILEHANDLE;

## check if OpenVPN running, and with correct client IP address range.
if ( -e '/proc/sys/net/ipv4/conf/tun0' || -e '/proc/sys/net/ipv6/conf/tun0')
	{
	$tun_interface = `/sbin/ifconfig tun0`;
} else
	{
	$tun_interface = "blahdy";
}

$openvpn_running_correctly = 0;

if ($tun_interface =~ m/inet addr:10\.10\.0/)
	{
	$openvpn_running_correctly = 1;
}

## check if OpenVPN configuration files have correct hashes
$hashcheck_passed = 1;
$passed_hashcheck_count = 0;
@files_to_check_hashes = ('/etc/openvpn/ca.crt', '/etc/openvpn/client.conf',
				'/etc/openvpn/crit-cd1.crt', '/etc/openvpn/crit-cd1.key');
for ($file_index_hashcheck = 0; $file_index_hashcheck < 4; $file_index_hashcheck++)
	{
	if ( -e $files_to_check_hashes[$file_index_hashcheck])
		{
		open(MD5HANDLE, $files_to_check_hashes[$file_index_hashcheck]) or die "Error verifying runtime authorization.\n";
		binmode(MD5HANDLE);
		$md5obj = Digest::MD5->new;
	    $md5obj->addfile(*MD5HANDLE);
		close MD5HANDLE;
		$hashcheckMD5 = $md5obj->hexdigest;
		if ($hashcheckMD5 eq '164ba62b0727c17ab2e9037a866c92a5' || 
			$hashcheckMD5 eq 'dc6b70de1a188764346e943a5f1db246' ||
			$hashcheckMD5 eq 'a4287b340d75a7b0ce0a722a2c6bc4ec' ||
			$hashcheckMD5 eq '5a23bfbc0a2aaed27fd9ce930f96cea1')
			{
			$passed_hashcheck_count++;
		} else
			{
			$hashcheck_passed = 0;
			print "Failed MD5: ".$files_to_check_hashes[$file_index_hashcheck]."\n";
		}

		$sha1obj = Digest::SHA->new(1);
		$sha1obj->addfile($files_to_check_hashes[$file_index_hashcheck]);
		$hashcheckSHA1 = $sha1obj->hexdigest;
		if ($hashcheckSHA1 eq '5767a7ef0d97c5abccf5f1ab57353d335a6fdd0c' || 
			$hashcheckSHA1 eq '2b9317d6530f484e6a21dd2af8476a421c3446e9' ||
			$hashcheckSHA1 eq 'a305c24a6afc4822ac10a4d0e15f883959aa4781' ||
			$hashcheckSHA1 eq 'd48222479c51c378a7771c2c0fabeec593ed349c')
			{
			$passed_hashcheck_count++;
		} else
			{
			$hashcheck_passed = 0;
			print "Failed SHA1: ".$files_to_check_hashes[$file_index_hashcheck]."\n";
		}

		$sha256obj = Digest::SHA->new(256);
	    $sha256obj->addfile($files_to_check_hashes[$file_index_hashcheck]);
		$hashcheckSHA256 = $sha256obj->hexdigest;
		if ($hashcheckSHA256 eq '114640ec5777841b8486fba750b25f784394b7855527050777eff14c5bcc40f0' || 
			$hashcheckSHA256 eq '0f00d9eb8cbc523e0ff2f5dce9e6ef2b76caafcdfd3f22afb7623b8c2c1d98bc' ||
			$hashcheckSHA256 eq '403074ab2efeb87f014af692517b2366fb2956ca51c59817b453ac408c1fe276' ||
			$hashcheckSHA256 eq '7a8fe3441a1a66d320b9aad8bf4a408b0033f395ce5ad4e6123551ccbdda4c42')
			{
			$passed_hashcheck_count++;
		} else
			{
			$hashcheck_passed = 0;
			print "Failed SHA256: ".$files_to_check_hashes[$file_index_hashcheck]."\n";
		}
	} else
		{
		$hashcheck_passed = 0;
###		die "Unauthorized environment detected when opening hashcheck files.\n";
	}
}

### do authorized user check here, instead of forcing.
$full_key = '123456789012345678901234567890123456789045cb07a04400ebf573691e369f84a06706bc';
if ( -e $licence_file)
	{
	open(LICENCEFILE, $licence_file) or die "Error reading licence file.\n Check file permissions.\n\n";
	$full_key = <LICENCEFILE>;
	chomp $full_key;
}

$assigned_key = substr($full_key, 0, 40);
$key_check = substr($full_key, 40);
$sha1obj = Digest::SHA->new(1);
$sha1obj->add($assigned_key);
$hashcheckSHA1 = $sha1obj->hexdigest;
print "\n\nAssigned key: ".$assigned_key."\n"; 
print "Licence SHA1: ".$hashcheckSHA1."\n";
$first_15_SHA1 = substr($hashcheckSHA1, 0, 15);
print "First 15: ".$first_15_SHA1."\n";
$assigned_key_plus_first_15_SHA1 = $assigned_key.$first_15_SHA1;
print "Building check w/SHA1: ".$assigned_key_plus_first_15_SHA1."\n";
$sha256obj = Digest::SHA->new(256);
$sha256obj->add($assigned_key_plus_first_15_SHA1);
$hashcheckSHA256 = $sha256obj->hexdigest;
print "Licence SHA256: ".$hashcheckSHA256."\n";
$last_24_SHA256 = substr($hashcheckSHA256, 24);
print "Last 24: ".$last_24_SHA256."\n";
$assigned_key_15_SHA1_24_SHA256 = $assigned_key_plus_first_15_SHA1.$last_24_SHA256;
print "Building check w/SHA256: ".$assigned_key_15_SHA1_24_SHA256."\n";
$last_bit = substr($assigned_key_15_SHA1_24_SHA256, 41);
$sha1obj = Digest::SHA->new(1);
$sha1obj->add($last_bit);
$hashcheckSHA1 = $sha1obj->hexdigest;
$final_key_middle_bit = substr($last_bit, 6, 16);
$final_key_last_bit = substr($hashcheckSHA1, 20);
$final_key = $assigned_key.$final_key_middle_bit.$final_key_last_bit;
print "Final key: ".$final_key."\n\n";
if ($final_key_middle_bit.$final_key_last_bit eq $key_check)
	{
	print "Licence verified.\n\n";
	$authorized_user = 1;
} else
	{
	print "Licence key is invalid.\n";
	print "Stop stealing software, you dirty terrorist PIRATE!!! LOL ;)\n\n";
}




if (($live_cd == 0 || $openvpn_running_correctly == 0 || $hashcheck_passed == 0 ||
		$passed_hashcheck_count < 12)  && $authorized_user == 0)
	{
	print "\nUnauthorized environment detected.\n\n";
	print "Please contact CB Services for licensing requirements.\n";
	print "Contact information available at http://www.cbserviceslondon.com/\n\n";
	

	print "LiveCD: ".$live_cd."\n";
	print "OpenVPN: ".$openvpn_running_correctly."\n";
	print "Hashcheck passed: ".$hashcheck_passed."\n";
	die "Hashcheck count: ".$passed_hashcheck_count."\n";
	
}

 


$db_host_cbs = '172.20.1.3';
$db_name_cbs = 'vt_scan';
$db_user_cbs = 'vt_scan';
$db_pass_cbs = 'vt_scan';

if (!defined($db_host))
	{
	$db_host = $db_host_cbs;
	$db_name = $db_name_cbs;
	$db_user = $db_user_cbs;
	$db_pass = $db_pass_cbs;
}
$current_scanning_count = 0;

$curdir = getcwd;
if ($curdir ne "/")
	{
	$curdir = $curdir . "/";
}
#print "$curdir\n\n";

##### create LWP user agent....

$ua = new LWP::UserAgent;
#$ua = new LWP::RobotUA;
#$ua->agent("MSIE 7.0 - Mozilla Compatible - Scanbot/0.1.1");
$ua->agent("Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; GTB6.3; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729)");
####push @{ $ua->requests_redirectable }, 'POST';

#$ua->delay( 15/60 );

#### create database connection....
($dbh = DBI->connect("DBI:mysql:$db_name_cbs;host=$db_host_cbs", "$db_user_cbs","$db_pass_cbs"))
    or die "Error connecting to CB Services database\n";
($dbh_local = DBI->connect("DBI:mysql:$db_name;host=$db_host", "$db_user","$db_pass"))
    or die "Error connecting to local database\n";
$dbh->{'mysql_auto_reconnect'} = 1;
$dbh_local->{'mysql_auto_reconnect'} = 1;

$hashes_table = 'hashes';
$results_table = 'results';
$scanning_table = 'scanning';
$infected_table = 'infected';
$vt_already_checked = 'AlreadyChecked';
$jotti_already_checked = 'JAC';

##$insert_prpst = $dbh->prepare("INSERT INTO $results_table 
					#(MD5, SHA1, SHA256, LocalLastScan, VTLastScan, VTFirstScan, VTResult)
					# VALUES (?, ?, ?, NOW(), ?, ?, ?)");
$insert_prpst = $dbh->prepare("INSERT INTO $results_table 
			(MD5, SHA1, SHA256, LocalLastScan, VTFirstScan, VTLastScan,
				VTResult, Detections, Scanners) VALUES (?, ?, ?, NOW(), ?, ?, ?, ?, ?)");
$update_prpst = $dbh->prepare("UPDATE $results_table set LocalLastScan = NOW(), VTLastScan = ?, VTFirstScan = ?, VTResult = ?, Detections = ?, Scanners = ? where MD5 = ? && SHA1 = ? && SHA256 = ?");
$local_results_prpst = $dbh->prepare("SELECT *, DATEDIFF(VTLastScan, VTFirstScan) as span, DATEDIFF(NOW(), VTLastScan) as age from $results_table where MD5 = ? && SHA1 = ? && SHA256 = ?");
$infected_prpst = $dbh->prepare("INSERT INTO $infected_table (SysID, MD5, SHA1, SHA256, Filename, Infected, Scanned) VALUES (?, ?, ?, ?, ?, ?, ?)");
$daterange_prpst = $dbh_local->prepare("SELECT DATEDIFF(?, ?) as scanrange");
$dateage_prpst = $dbh_local->prepare("SELECT DATEDIFF(NOW(), ?) as age");
$hash_insert_prpst = $dbh_local->prepare("INSERT INTO $hashes_table (SysID, MD5, SHA1, SHA256, Filename, Extension, Filetype) VALUES (?, ?, ?, ?, ?, ?, ?)");
if ($scan_by_file_type == 1)
	{
	$storedhash_prpst = $dbh_local->prepare("SELECT MD5, SHA1, SHA256, Filename from $hashes_table where SysID = ? && Filetype like ? && $vt_already_checked = 'N'");
} else
	{
	$storedhash_prpst = $dbh_local->prepare("SELECT MD5, SHA1, SHA256, Filename from $hashes_table where SysID = ? && Extension like ? && $vt_already_checked = 'N'");
}
$delete_storedhash_prpst = $dbh_local->prepare("UPDATE $hashes_table set $vt_already_checked = 'Y' where SysID = ? && SHA256 = ? && SHA1 = ? && MD5 = ? && Filename = ?");
$scanning_insert_prpst = $dbh->prepare("INSERT INTO $scanning_table (SysID, MD5, SHA1, SHA256, Filename, Extension, ResultURL) VALUES (?, ?, ?, ?, ?, ?, ?)");
##$scanning_select_prpst = $dbh->prepare("SELECT MD5, SHA1, SHA256, Filename, ResultURL from $scanning_table where SysID = ? && Extension = ? && AlreadyRescanned = 'N'");
$scanning_select_prpst = $dbh->prepare("SELECT MD5, SHA1, SHA256, Filename, ResultURL from $scanning_table where SysID = ? && AlreadyRescanned = 'N' && TIMESTAMPDIFF(SECOND, UploadTime, NOW()) > ? ORDER BY UploadTime");
$check_if_scanning_prpst = $dbh->prepare("SELECT Filename, SysID, ResultURL from $scanning_table where SHA256 = ? && SHA1 = ? && MD5 = ? && SysID = ?");
$check_if_scanning_recent_prpst = $dbh->prepare("SELECT Filename, Extension, ResultURL from $scanning_table where SHA256 = ? && SHA1 = ? && MD5 = ? && TIMESTAMPDIFF(SECOND, UploadTime, NOW()) < ?");
$scanning_count_prpst = $dbh->prepare("SELECT COUNT(Filename) from $scanning_table where SysID = ? && AlreadyRescanned = 'N'");
$scanning_update_prpst = $dbh->prepare("UPDATE $scanning_table set AlreadyRescanned = 'Y' where SysID = ? && SHA256 = ? && SHA1 = ? && MD5 = ?");

$reset_broken_hash_prpst = $dbh_local->prepare("UPDATE $hashes_table set $vt_already_checked = 'N' where SysID = ? && SHA256 = ? && SHA1 = ? && MD5 = ? && Filename = ?");
$reset_broken_scan_prpst = $dbh->prepare("DELETE from $scanning_table where SysID = ? && SHA256 = ? && SHA1 = ? && MD5 = ? && Filename = ?");


$file_being_scanned = 0;
$files_queued_on_rescan = 0;


##### Assign generic system ID if none supplied.
##### deprecated - SysID is required.

@ARGV=qw(anontest) if not @ARGV;

$sysid = $ARGV[0];
##print "ARGV1: ".$ARGV[1]." ..\n";
if ($ARGV[1] eq "-h")
	{
	$hash_system = 1;
	$scan_system = 0;
} elsif ($ARGV[1] eq "-s")
	{
	$hash_system = 0;
	$scan_system = 1;
} elsif ($ARGV[1] eq "-a")
	{
	$hash_system = 1;
	$scan_system = 1;
} elsif (!defined($ARGV[1]))
	{
	print "\nStupid n00bz!!\n";
	print "Usage: vt_scan_db_version.pl <SysID> <-h|-s|-a>\n";
	print "-h : Only hash files.  Don't scan.\n";
	print "-s : Only scan files.  Don't hash. (Hashing must already be complete for this SysID.\n";
	die "-a : Do both.\n\n\n";
} else
	{
	print "\nStupid n00bz!!\n";
	print "Usage: vt_scan_db_version.pl <SysID> <-h|-s|-a>\n";
	print "-h : Only hash files.  Don't scan.\n";
	print "-s : Only scan files.  Don't hash. (Hashing must already be complete for this SysID.\n";
	die "-a : Do both.\n\n\n";
}
	
#### find all files and directories in current tree, and run sub "hashall" on each.

if ($hash_system == 1)
	{
	if ($hash_only_priority_filetypes == 1)
		{
		for($extension_index = 0; $extension_index <= scalar @extension_priority; $extension_index++)
			{
			$extensions_to_hash[$extension_priority[$extension_index]] = 1;
		}
	}
	finddepth(\&hashall, qw(.)); 
}



# start scanning
if ($scan_system == 1)
	{
	if ($debug >= 1)
		{
		print "Scanning system...\n";
		print $#extension_priority." file types priority specified.\n";
	}
	for ($extension_index = 0; $extension_index <= scalar @extension_priority; $extension_index++)
		{
		if ($debug >= 1)
			{
			print "\n\nScanning .".$extension_priority[$extension_index]." files\n";
		}
## SELECT MD5, SHA1, SHA256, Filename from $hashes_table where SysID = ? && Extension like ?");	
		$storedhash_prpst->execute($sysid, $extension_priority[$extension_index]);
		while (@filename_row = $storedhash_prpst->fetchrow_array())
			{
            $local_results = 0;
			print "\n\n";
			$file_path=$filename_row[3];
			$file_path =~ /\.([A-Za-z0-9]{2,8}$)/;
			$extension = $1;

			print "File: ".$file_path."\n";
			if ($debug >= 1)
				{
				print "Filetype/Extension: ".$extension_priority[$extension_index]."\n";
			}
		#####  check filesize

			if ($debug >= 2)
			   {
				print "After checking size file path: ".$file_path."\n";
			}
			$fileMD5 = $filename_row[0];
			$fileSHA1 = $filename_row[1];
			$fileSHA256 = $filename_row[2];
			&check_local_results($file_path);
			if ($results eq '' || $local_results_no_good == 1)
				{
				if ($debug >= 1 && $results eq '')
					{
					print "No local results.  Sending hash...\n";
				} elsif ($debug >= 1 && ($results ne ''))
					{
					print "Local results found, but no good...\n";
				}
				if ($debug >= 1)
					{
					print "Calling send_hash function for: ".$file_path."\n";
				}
				&send_hash($file_path);
				if ($results eq '' || $vt_results_no_good == 1)
					{
					if ($debug >= 1 && $results eq '')
						{
						print "No VT results. Uploading file...\n";
						print "Results: ".$results."\n";
						$upload_borked = 0;
						&upload_file($file_path);
						#print "Upload borked: ".$upload_borked;
						###die;
						#while ($upload_borked >= 1 && $upload_borked <= $max_retries_for_upload - 1)
            #  {
            #  sleep $sleep_between_files;
            #  sleep $sleep_between_files;
            #  &upload_file($file_path);
            #}
					} elsif ($debug >= 1 && $results ne '')
						{
						print "VT results found, but no good...\n";
						&reupload_file($file_path);
					}
				} elsif ($detected eq "queued")
					{
					print "Still waiting on VT.\n";
				}  else
					{
					if ($debug >= 1)
						{
						print "Using VT results...\n";
						if ($detected > 0)
							{
							if ($infected_prpst->execute($sysid, $fileMD5, $fileSHA1, $fileSHA256,
										$file_path, $detected, $total_scanners))
								{
								$delete_storedhash_prpst->execute($sysid, $fileSHA256, 
									$fileSHA1, $fileMD5, $file_path);
							}
						} else
							{
							$delete_storedhash_prpst->execute($sysid, $fileSHA256, 
								$fileSHA1, $fileMD5, $file_path);
						}

					}
					
				}
				sleep $sleep_between_files / 2 ;

			} else
				{
				$local_results = 1;
				print "Already have acceptable local results.\n";
				if ($debug >= 1)
					{
					print "Results: ".$detected."/".$total_scanners."\n";
				}
				if ($detected > 0)
					{
					if ($infected_prpst->execute($sysid, $fileMD5, $fileSHA1, $fileSHA256,
								$file_path, $detected, $total_scanners))
						{
						$delete_storedhash_prpst->execute($sysid, $fileSHA256, 
							$fileSHA1, $fileMD5, $file_path);
					}
				} else
					{
					$delete_storedhash_prpst->execute($sysid, $fileSHA256, 
						$fileSHA1, $fileMD5, $file_path);
				}
			}
		#####   don't beat the crap out of virustotal.com
			if ($local_results == 0)
				{
				sleep $sleep_between_files;
			} else
				{
				$local_results = 0;
			}
		}
		
		if ($extension_index > 0)
			{
			$rescanning_now = 1;
			&pull_scanning_results();
			$rescanning_now = 0;
		}
		
	}
	if ($files_queued_on_rescan == 1)
		{
		print "I'm done, but some files didn't scan.\n";
		print "When I went back for results, at least one file was still queued.\n";
		print "Sleeping 5 minutes and retrying";
		sleep 300;
		&pull_scanning_results();
		
	} else
		{
		print "I'm done. Exiting now....\n";
	}
}

if ($scan_system == 1)
	{
	&pull_scanning_results();
}





















sub hashall {
###  reset local variables
	$localMD5 = "";
	$localSHA1 = "";
	$localSHA256 = "";
	$extension = "";


	print "\n\n";
#####  remove ./ from beginning of each filename if it's there.
	if ($File::Find::name =~ m/^\.\//)
		{
		$fpath=substr($File::Find::name, 2);
	} else
		{
		$fpath = $File::Find::name;
	}
#####  add full path for absolute filename, if not in root directory.
	if (!($fpath =~ m/^\//))
		{
		print "Adding current dir to filepath...\n";
		$file_path="$curdir"."$fpath";
	} else
		{
		$file_path = $fpath;
	}
	print "Raw file: ".$fpath."\n";
	print "File: ".$file_path."\n";

#####  make sure file is not a directory.
	if (!(-d $file_path) && !(-p $file_path))
		{
		if ($debug >= 1)
            {
            #print "\n";
		    print "Initial file path: ".$file_path."\n";
        }
#####  check filesize

		if (-s $file_path <= $max_file_size_to_scan && -s $file_path > 0)
			{
			if ($debug >= 2)
                {
                print "After checking size file path: ".$file_path."\n";
            }
			$file_path =~ /\.([A-Za-z0-9_-]{2,8}$)/;
			#if (defined($1))
			#	{
			$extension = lc($1);
			chomp $extension;
			$shell_file_path = $file_path;
			$shell_file_path =~ s/\\/\\\\/g;
			$shell_file_path =~ s/\(/\\\(/g;
			$shell_file_path =~ s/\)/\\\)/g;
			$shell_file_path =~ s/ /\\\ /g;
			$shell_file_path =~ s/\&/\\\&/g;
			$shell_file_path =~ s/\$/\\\$/g;
			$shell_file_path =~ s/'/\\\'/g;
			if ($debug <= 2)
				{
				print "Shell file path: ".$shell_file_path."\n";
			}

			$file_type_query = `file -b $shell_file_path`;
			
######  find all legit executables first, and name type as actual extension.		
			
			if ($extension eq 'exe' || $extension eq 'dll' ||
					$extension eq 'scr' || $extension eq 'cpl' ||
					$extension eq 'ocx' || $extension eq 'ime' || 
					$extension eq 'sys' || $extension eq 'drv' ||
					$extension eq 'mui')
				{
				$file_type = lc($extension);
######  then find all other executables, and call them hidden-exe type.
			} elsif ($file_type_query =~ m/ executable/)
				{
				$file_type = 'hidden-exe';
			} elsif ($file_type_query =~ m/ELF 32-bit LSV relocatable/)
				{
				$file_type = 'exe'
			} elsif ($file_type_query =~ m/MS-DOS batch file text/)
				{
				$file_type = 'bat';
			} elsif ($file_type_query =~ m/ASCII C\+\+ program text/ && $extension eq 'js')
				{
				$file_type = 'js';
			} elsif ($file_type_query =~ m/PHP script text/)
				{
				$file_type = 'php';
			} elsif ($file_type_query =~ m/with CRLF line terminators/ && $extension eq 'vbs')
				{
				$file_type = 'vbs';
			} elsif ($file_type_query =~ m/with CRLF line terminators/ && $extension eq 'inf')
				{
				$file_type = 'inf';
			} elsif ($file_type_query =~ m/with CRLF line terminators/ && $extension eq 'ini')
				{
				$file_type = 'ini';
			} elsif ($extension eq 'vbs' || $extension eq 'inf' || $extension eq 'ini')
				{
				$file_type = 'hidden-txt';
			} elsif ($file_type_query =~ m/with CRLF line terminators/ || 
						$file_type_query =~ m/with no line terminators/ || 
						$file_type_query =~ m/CR line terminators/ || 
						$file_type_query =~ m/ LF line terminators/ ||
						$file_type_query =~ m/ASCII text/ ||
						$file_type_query =~ m/ASCII news text/ ||
						$file_type_query =~ m/Sendmail frozen configuration/)
				{
				$file_type = 'txt';
			} elsif ($file_type_query =~ m/Microsoft ASF/)
				{
				$file_type = 'wma';
			} elsif ($file_type_query =~ m/Zip archive data/ && $extension eq 'docx')
				{
				$file_type = 'docx';
			} elsif ($file_type_query =~ m/Zip archive data/ && $extension eq 'xlsx')
				{
				$file_type = 'xlsx';
			} elsif ($file_type_query =~ m/Zip archive data/)
				{
				$file_type = 'zip';
			} elsif ($file_type_query =~ m/RAR archive data/)
				{
				$file_type = 'rar';
			} elsif ($file_type_query =~ m/PDF document/)
				{
				$file_type = 'pdf';
			} elsif ($file_type_query =~ m/FDF document/)
				{
				$file_type = 'fdf';
			} elsif ($file_type_query =~ m/MS Windows HtmlHelp Data/)
				{
				$file_type = 'chm';
			} elsif ($file_type_query =~ m/MS Windows 95 Internet shortcut text/)
				{
				$file_type = 'url';
			} elsif ($file_type_query =~ m/MS Windows shortcut/)
				{
				$file_type = 'lnk';
			} elsif ($file_type_query =~ m/JPEG image data/)
				{
				$file_type = 'jpg';
			} elsif ($file_type_query =~ m/rich text format/)
				{
				$file_type = 'rtf';
			} elsif ($file_type_query =~ m/TrueType font data/)
				{
				$file_type = 'ttf';
			} elsif ($file_type_query =~ m/PNG image data/)
				{
				$file_type = 'png';
			} elsif ($file_type_query =~ m/HTML document text/)
				{
				$file_type = 'html';
			} elsif ($file_type_query =~ m/exported SGML document text/)
				{
				$file_type = 'sgml';
			} elsif ($file_type_query =~ m/XML  document text/)
				{
				$file_type = 'xml';
			} elsif ($file_type_query =~ m/^XPConnect Typelib/)
				{
				$file_type = 'xpt';
			} elsif ($file_type_query =~ m/^TIFF image data/)
				{
				$file_type = 'tiff';
			} elsif ($file_type_query =~ m/^Macromedia Flash data/)
				{
				$file_type = 'swf';
			} elsif ($file_type_query =~ m/XML document text/)
				{
				$file_type = 'xml';
			} elsif ($file_type_query =~ m/Microsoft Excel .{0,5}Worksheet/)
				{
				$file_type = 'xls';
			} elsif ($file_type_query =~ m/Microsoft Office Document/ && 
						($extension eq 'doc' || $extension eq 'ppt'))
				{
				$file_type = $extension;
			} elsif ($file_type_query =~ m/Microsoft Access Database/)
				{
				$file_type = 'mdb';
			} elsif ($file_type_query =~ m/Microsoft Office Document/)
				{
				$file_type = 'hidden-mso';
			} elsif ($file_type_query =~ m/\(Corel\/WP\)/)
				{
				$file_type = 'wpd';
			} elsif ($file_type_query =~ m/Lotus 1-2-3 wk4 document data/)
				{
				$file_type = 'wk4';
			} elsif ($file_type_query =~ m/Lotus 1-2-3/)
				{
				$file_type = 'wb2';
			} elsif ($file_type_query =~ m/RIFF / && $file_type_query =~ m/WAVE audio/)
				{
				$file_type = 'wav';
			} elsif ($file_type_query =~ m/RIFF / && $file_type_query =~ m/animated cursor/)
				{
				$file_type = 'ani';
			} elsif ($file_type_query =~ m/RIFF / && $file_type_query =~ m/AVI/ && $file_type_query =~ m/video/)
				{
				$file_type = 'avi';
			} elsif ($file_type_query =~ m/RIFF /)
				{
				$file_type = 'riff';			
			} elsif ($file_type_query =~ m/PC bitmap/)
				{
				$file_type = 'bmp';
			} elsif ($file_type_query =~ m/GIF image data/)
				{
				$file_type = 'gif';
			} elsif ($file_type_query =~ m/Lisp\/Scheme /)
				{
				$file_type = 'htt';
			} elsif ($file_type_query =~ m/Windows Registry text/)
				{
				$file_type = 'reg';
			} elsif ($file_type_query =~ m/MS Windows registry file, NT\/2000 or above/)
				{
				$file_type = 'regbin';
			} elsif ($file_type_query =~ m/PNG image/)
				{
				$file_type = 'png';
			} elsif ($file_type_query =~ m/PFM data/)
				{
				$file_type = 'pfm';
			} elsif ($file_type_query =~ m/PostScript Type 1 font program dat/)
				{
				$file_type = 'pfb';
			} elsif ($file_type_query =~ m/PostScript document text/)
				{
				$file_type = 'ps';
			} elsif ($file_type_query =~ m/OpenType font data/)
				{
				$file_type = 'otf';
			} elsif ($file_type_query =~ m/PalmOS application/)
				{
				$file_type = 'prc';
			} elsif ($file_type_query =~ m/MS Windows icon resource/)
				{
				$file_type = 'ico';
			} elsif ($file_type_query =~ m/PDP-11 UNIX\/RT ldp/)
				{
				$file_type = 'pnf';
			} elsif ($file_type_query =~ m/Par archive data/)
				{
				$file_type = 'par';
			} elsif ($file_type_query =~ m/Standard MIDI data/)
				{
				$file_type = 'mid';
			} elsif ($file_type_query =~ m/diff output text/)
				{
				$file_type = 'diff';
			} elsif ($file_type_query =~ m/Internet Explorer cache file/)
				{
				$file_type = 'ie-dat';
			} elsif ($file_type_query =~ m/MS Windows 3.x help file/)
				{
				$file_type = 'hlp';
			} elsif ($file_type_query =~ m/DOS code page font data collection/)
				{
				$file_type = 'cpi';
			} elsif ($file_type_query =~ m/DBase 3 index file/)
				{
				$file_type = 'db3';
			} elsif ($file_type_query =~ m/BIOS \(ia32\) ROM Ext. IBM comp. Video/)
				{
				$file_type = 'rom';
			} elsif ($file_type_query =~ m/Microsoft Cabinet archive data/)
				{
				$file_type = 'cab';
			} elsif ($file_type_query =~ m/Microsoft ICM Color Profile/)
				{
				$file_type = 'icm';
			} elsif ($file_type_query =~ m/SysEx File/)
				{
				$file_type = 'sysex';


#			} elsif ($file_type_query =~ m//)
#				{
#				$file_type = '';
				
			} elsif ($file_type_query =~ m/^data/ || $file_type_query =~ m/GLS_BINARY_LSB_FIRST/)
				{
				$file_type = 'data';
			} else
				{
				$file_type = 'zyxwv';
				$unknown_file_types{$file_type_query} = 1;
			}
			if ($debug >= 2)
				{
				print "Extension: ".$extension."\n";
				print "Real extn: ".$file_type."\n";
				print "File type: ".$file_type_query."\n";
			}

			if ($scan_by_file_type == 1)
				{
				if ($hash_only_priority_filetypes == 1 && $extensions_to_hash[$file_type] == 1)
					{
					&hashcalc($file_path);
					if ($debug >= 1)
						{
						print "Storing hashes...\n";
					}
					$hash_insert_prpst->execute($sysid, $localMD5,
											$localSHA1, $localSHA256,
											$file_path, $extension, $file_type);
				} elsif ($hash_only_priority_filetypes == 1)
					{
					print "Not hashing ".$file_path."\n";
				} else
					{
					&hashcalc($file_path);
					if ($debug >= 1)
						{
						print "Storing hashes...\n";
					}
					$hash_insert_prpst->execute($sysid, $localMD5,
											$localSHA1, $localSHA256,
											$file_path, $extension, $file_type);
				}	
			} else
				{
				if ($hash_only_priority_filetypes == 1 && $extensions_to_hash[$extension] == 1)
					{
					&hashcalc($file_path);
					if ($debug >= 1)
						{
						print "Storing hashes...\n";
					}
					$hash_insert_prpst->execute($sysid, $localMD5,
											$localSHA1, $localSHA256,
											$file_path, $extension, $file_type);
				} elsif ($hash_only_priority_filetypes == 1)
					{
					print "Not hashing ".$file_path."\n";
				} else
					{
					&hashcalc($file_path);
					if ($debug >= 1)
						{
						print "Storing hashes...\n";
					}
					$hash_insert_prpst->execute($sysid, $localMD5,
											$localSHA1, $localSHA256,
											$file_path, $extension, $file_type);
				}
			}	

		} else
			{
			print "File zero-sized, or too big...\n";
		}	
	} else
		{
		print "Not a regular file...\n";
	}
}









sub hashcalc
    {
 #####  calculate SHA hashes for file.
    if ($debug >= 2)
       {
       print "Hashing: ".$file_path."\n";
    } elsif ($debug >= 1)
		{
		print "Hashing...\n";
	}
    open(MD5HANDLE, $file_path) or print "Can't open '$file_path' for MD5: $!";
    binmode(MD5HANDLE);
    $md5obj = Digest::MD5->new;
    $md5obj->addfile(*MD5HANDLE);
    close MD5HANDLE;
    $localMD5 = $md5obj->hexdigest;
    if ($debug >= 1)
		{
		print "Local MD5: ".$localMD5."\n";
	}
    $sha1obj = Digest::SHA->new(1);
    $sha1obj->addfile($file_path);
    $localSHA1 = $sha1obj->hexdigest;
    if ($debug >= 1)
		{
		print "Local SHA1: ".$localSHA1."\n";
	}
    $sha256obj = Digest::SHA->new(256);
    $sha256obj->addfile($file_path);
    $localSHA256 = $sha256obj->hexdigest;
    if ($debug >= 1)
		{
		print "Local SHA256: ".$localSHA256."\n";
	}
}




sub check_local_results
    {
	$results = '';
	$detected = '';
	$total_scanners = '';
	$span = '';
	$age = '';
	$local_results_no_good = 0;
	$local_results = 0;
    $local_results_prpst->execute($fileMD5,
                      $fileSHA1,
                      $fileSHA256);

    my @row;
    if (@row = $local_results_prpst->fetchrow_array())
		{
		if ($debug >= 1)
			{
			print "Using local results...\n";
		}
		$results = $row[6];
		$detected = $row[7];
		$total_scanners = $row[8];
		$span = $row[9];
		$age = $row[10];
		$local_results = 1;
		if (($age > $days_old_to_rescan && $span < $date_span_for_no_rescan) || 
					$rescan_if_scanners_less_than > $total_scanners || 
					($detected > 0 && $detected < $rescan_only_if_detections_less_than &&
					$age > $rescan_only_if_age_greater_than	&& 
					$span < $rescan_only_if_span_less_than && $rescan_infected == 1))
			{	
			$local_results_no_good = 1;
		}
	}
		
}





sub send_hash
    {
	##SELECT Filename, Extension, ResultURL from $scanning_table where SHA256 = ? && SHA1 = ? && MD5 = ? && TIMESTAMPDIFF(SECOND, UploadTime, NOW()) < ?

	$check_if_scanning_recent_prpst->execute($fileSHA256, $fileSHA1, $fileMD5, $allow_seconds_for_new_upload_scan);
	
	if (!(@check_scanning_row = $check_if_scanning_recent_prpst->fetchrow_array()))

	######################## check if file was recently uploaded for scan.
		{
		$send_hash_file_path = $file_path;
		if ($debug >= 2)
		   {
		   print "Sending hash for ".$send_hash_file_path."\n";
		}
	#####  submit SHA256 hash to virustotal....

	##  my $req = new HTTP::Request POST => 'http://www.virustotal.com/vt/en/consultamd5';
		my $req = new HTTP::Request POST => 'http://www.virustotal.com/search.html';
		$req->content_type('application/x-www-form-urlencoded');
	##  $req->content('hash='.$all_files{$send_hash_file_path}{'SHA256'});
		$req->content('chain='.$fileSHA256);
		if ($debug >= 2)
		   {
		   print "Hash for upload: ".$fileSHA256."\n";
		}
		scanstart:
		my $res = $ua->request($req);
		$response = $res->header(Location);
		print "Location: ".$response."\n";
	##  print $response;
	#   if ($response =~ /href...(buscaHash.html.notfound)/)
		if ($response =~ /(notfound=1)/)
		   {
		   print "Not yet scanned...\n";
		   $unscanned_files{$send_hash_file_path} = 1;
		} elsif ($response =~ /report.html/)
		   {
		   $results_URL = $response;
		   if ($debug >= 1)
			  {
			  print "Results are at: ".$results_URL."\n";
			  print "Storing URL....\n";
		   }
		   $resultURL = $results_URL;
		   sleep $sleep_between_files;
		   &pull_results($send_hash_file_path);
		} elsif ($response =~ /invalid/)
		   {
		   print "Received invalid response...\n ...sleeping 30 seconds\n";
		   sleep 30;
		   goto scanstart;
		} else
		   {
		   print "Random borkage during hash upload.......\n";
		   print $res->content."\n\n\n";
		   sleep 30;
		   goto scanstart;
		}
	} else
		{
		print "File uploaded within last ".$allow_seconds_for_new_upload_scan." seconds.  Not checking yet.\n";
		
##INSERT INTO $scanning_table (SysID, MD5, SHA1, SHA256, Filename, Extension, ResultURL) VALUES (?, ?, ?, ?, ?, ?, ?)");
		$scanning_insert_prpst->execute($sysid, $fileMD5, $fileSHA1, $fileSHA256, 
				$file_path, $check_scanning_row[1], $check_scanning_row[2]);
		
	}
}




sub pull_results
	{
	$vt_results_no_good = 0;
	$results_file_path = $file_path;
        my $reupload = 0;
	if ($_[1] == 1)
           {
           #$results_file_path = $curdir.$_[0];
           #$results_file_path = $_[0];
           $this_is_a_rescan = 1;
           #$_[1] = 0;
        }
	if ($debug >= 2)
           {
           print "Filename ".$results_file_path."\n";
           print "Result URL: ".$resultURL."\n";
        }
	my $req = new HTTP::Request GET => $resultURL;
	my $res = $ua->request($req);
	$response = $res->content;
##	print $response;
	if ($response =~ /Submission date.{50}([0123456789:-\s]{19})/)
		{
		$last_scan_date = $1;
	} else
		{
		$last_scan_date = 'Error';
	}
#	$1 = "fucked";
  #$sub_date = "NULL";
	if ($response =~ /Current sta.{55}([a-z]{5,15})/)
		{
		$current_status = $1;
	} else
		{
		$current_status = 'Error';
	}
#	$1 = "fucked";
	if ($response =~ /orcentaje.{21}(\d{1,2})/)
		{
		$detected = $1;
	} else
		{
		$detected = 'Error';
	}
	if ($response =~ /status-total.{3}(\d{1,2})/)
		{
		$total_scanners = $1;
	} else
		{
		$total_scanners = 'Error';
	}
	if ($response =~ /First seen.{9}([0123456789:-\s]{19})/)
		{
		$first_seen = $1;
		if ($debug >= 1)
			{
			print "Found first scan date: ".$first_seen." ..\n";
		}
	} else
		{
		$first_seen = 'Error';
	}
	$results = $detected."/".$total_scanners;
	my @spancalc_query = $daterange_prpst->execute($last_scan_date, $first_seen);
	@spancalc_row = $daterange_prpst->fetchrow_array();
	$span = $spancalc_row[0];
	my @age_query = $dateage_prpst->execute($last_scan_date);
	@age_row = $dateage_prpst->fetchrow_array();
	$age = $age_row[0];
	if ($debug >= 1)
		{
		print "First seen: ".$first_seen."\n";
		print "Last scanned: ".$last_scan_date."\n";
		print "Status: ".$current_status."\n";
		print "Result: ".$detected."/".$total_scanners."\n";
		print "VT Scan age: ".$age."\n";
		print "VT Scan span: ".$span."\n";
	}
	if ($current_status eq "finished")
		{
		print "Finding hashes...\n";
		#####$status = $1;
		$response =~ /MD5.nbsp..nbsp..nbsp...\/span..([0123456789abcdef]{32})/;
		$VTMD5 = $1;
		$response =~ /SHA1.nbsp..nbsp...\/span..([0123456789abcdef]{40})/;
		$VTSHA1 = $1;
		$response =~ /SHA256..\/span..([0123456789abcdef]{64})/;
		$VTSHA256 = $1;
		if ($debug >= 2)
			{
			print "VT MD5: ".$VTMD5."\n";
			print "VT SHA1: ".$VTSHA1."\n";
			print "VT SHA256: ".$VTSHA256."\n";
		}

		print "Status: ".$current_status."\n";
		print "Virus detection: $detected / $total_scanners\n";
####		$received = $1;
		print "Received: ".$last_scan_date."\n";
### if no results, too old results with too short date span, 
### infected and rescan infected is set, scanners total is too low...etc.
		if (($age > $days_old_to_rescan && $span < $date_span_for_no_rescan) || 
					($detected > 0 && $detected < $rescan_only_if_detections_less_than &&
					$age > $rescan_only_if_age_greater_than &&
					$span < $rescan_only_if_span_less_than && $rescan_infected == 1) || 
					$total_scanners < $rescan_if_scanners_less_than)
			{
			$vt_results_no_good = 1;
		}
		if ($results eq '' || $vt_results_no_good == 1)
			{
			if ($debug >= 2)
				{
				print "Setting reupload to 1 because:\n";
				print "Results: ".$results."\n";
				print "VT results bad: ".$vt_results_no_good."\n";
			} 
			$reupload = 1;
		} else
			{
			$reupload = 0;
		}
		#$all_files{$results_file_path}{'results'} = $detected."/".$total_scanners;
		#$all_files{$results_file_path}{'detected'} = $detected;
		#$all_files{$results_file_path}{'scanned'} = $total_scanners;
		if (!$local_results && $detected > 0)
			{
			if ($rescan_infected == 0 || $rescanning_now == 1)
				{
				$infected_prpst->execute($sysid, $fileMD5,
								  $fileSHA1,
								  $fileSHA256,
								  $file_path,
								  $detected, $total_scanners);
			}
		#	$insert_prpst->execute($fileMD5, $fileSHA1, $fileSHA256,
		#						$first_seen, $last_scan_date, 
		#						$results, $detected, $total_scanners);
		} elsif ($local_results && $detected > 0)
			{
			if ($rescan_infected == 0 || $rescanning_now == 1)
				{
				$infected_prpst->execute($sysid, $fileMD5,
								$fileSHA1, $fileSHA256,
								$file_path,
								$detected, $total_scanners);
			}
## UPDATE $results_table set LocalLastScan = NOW(), VTLastScan = ?, VTFirstScan = ?, 
## VTResult = ?, Detections = ?, Scanners = ? where MD5 = ? && SHA1 = ? && SHA256 = ?");

		#	$update_prpst->execute($last_Scan_date, $first_seen,
		#							$results, $detected, $total_scanners,
		#							$fileMD5, $fileSHA1, $fileSHA256);
			
		}
		if ($debug >= 2)
			{
			print "Local results: ".$local_results_no_good."\n";
			print "Reupload: ".$reupload."\n";
		}
		if ($reupload == 0 && $local_results_no_good == 0)
			{
			print "THIS IS A FIRST LOCAL SCAN!!\n";
			$insert_prpst->execute($fileMD5, $fileSHA1, $fileSHA256,
								$first_seen, $last_scan_date,
								$results, $detected, $total_scanners);
		} else
			{
			print "THIS IS A LOCAL UPDATE!!\n";
			$update_prpst->execute($last_scan_date, $first_seen,
							$results,
							$detected,
							$total_scanners,
							$fileMD5,
							$fileSHA1,
							$fileSHA256);
			}
		return 1;
	} elsif ($current_status eq 'queued' || $current_status eq 'scanning')
 		{
		$files_queued_on_rescan = 1;
	} elsif ($response =! m/not found/)
		{
		print "Result not found...\n";
### Need to reset scan/upload to look like unscanned file here!!!
##$reset_broken_hash_prpst -- UPDATE $hashes_table set $vt_already_checked = 'N' where 
##						SysID = ? && SHA256 = ? && SHA1 = ? && MD5 = ? && Filename = ?");
##$reset_broken_scan_prpst -- DELETE from $scanning_table where SysID = ? && SHA256 = ? 
##							&& SHA1 = ? && MD5 = ? && Filename = ?");
$reset_broken_hash_prpst->execute($sysid, $fileSHA256, $fileSHA1, $fileMD5, $file_path);
$reset_broken_scan_prpst->execute($sysid, $fileSHA256, $fileSHA1, $fileMD5, $file_path);

		
	} else
		{
		print "Something weird happened..\n";
	}
}





sub upload_file
	{
	$upload_file_path = $file_path;
## SELECT Filename, SysID, ResultURL from $scanning_table where SHA256 = ? && SHA1 = ? && MD5 = ? && SysID = ?

	$check_if_scanning_prpst->execute($fileSHA256, $fileSHA1, $fileMD5, $sysid);
	
	if (@check_scanning_row = $check_if_scanning_prpst->fetchrow_array())
		{
		$file_being_scanned = 1;
		print "Hash already being scanned as:\n";
		print $check_scanning_row[1]."--".$check_scanning_row[0]."\n";
		if ($scanning_insert_prpst->execute($sysid, 
							$fileMD5, $fileSHA1, $fileSHA256, 
							$upload_file_path, $extension, $check_scanning_row[2]))
			{
## UPDATE $hashes_table set $vt_already_checked = 'Y' where SysID = ? && SHA256 = ? && SHA1 = ? && MD5 = ?");
			$delete_storedhash_prpst->execute($sysid, $fileSHA256, $fileSHA1, $fileMD5, $file_path);
		}
	} else
		{
		$filesize = -s $upload_file_path;
	######################	print "Filesize:  ".$filesize."\n";
		if ($filesize < $max_file_size_to_scan)
			{
			if ($debug >= 1)
					   {
			   print "Uploading...\n";
					}
			my $browser = LWP::UserAgent->new;
			 ######################
			 ######################
			 ###   changed to test public API file upload
			 ##############################
			my $response = $browser->post('http://www.virustotal.com/file-upload/file_upload',
				[file => [$upload_file_path]],
				'Content_Type' => 'multipart/form-data');
			####       my $response = $browser->post('http://www.virustotal.com/api/scan_file.json',
			####                [file => [$upload_file_path]],
			####                'key' => $vt_api_key,
			####                'Content_Type' => 'multipart/form-data'
			####                );
			##$response = $response->content;
	##################		print "Content: ". $response->content;
			if ($debug >= 3)
				{
				print "Response content: ".$response->content;
			}
			#print Dumper($response);
		##      die;
			$results_URL = $response->header(Location);
			$resultURL = $results_URL;
			if (defined($resultURL) && $resultURL ne '' && !($resultURL =~ m/index.html/))
				{
				$results_URL =~ s/reanalysis/report/g;
				if ($debug >= 2)
					{
					print "Result URL: ".$results_URL."\n";
					print "Location: ".$location."\n";
				}
				if ($debug >= 1)
					{
					print "Storing hashes and result URL...\n";
				}	
				if ($scanning_insert_prpst->execute($sysid, $fileMD5, $fileSHA1, $fileSHA256, $upload_file_path, $extension, $results_URL))
					{
					if ($debug >= 2)
            {
            print "Recording scanning status for file....\n";
          }
				## UPDATE $hashes_table set $vt_already_checked = 'Y' where SysID = ? && SHA256 = ? && SHA1 = ? && MD5 = ?");
					$delete_storedhash_prpst->execute($sysid, $fileSHA256, $fileSHA1, $fileMD5, $file_path);
			#$scanned_files{$upload_file_path} = 1;
					$current_scanning_count++;
				}
			
			} else
				{
				print "Borkage during result retrieval...\n";
				#$upload_borked++;
				#return 1;
			}
		}
	}
}





sub reupload_file
	{
	$upload_borked = 0;
	&upload_file($file_path);
	print "Upload borked: ".$upload_borked."\n";;
	####die;
	#while ($upload_borked >= 1 && $upload_borked <= $max_retries_for_upload - 1)
  #  {
  #  sleep $sleep_between_files;
  #  sleep $sleep_between_files;
  #  &upload_file($file_path);
  #}



####	&upload_file($file_path);
	$force_scan_URL = "http://www.virustotal.com".$resultURL."&amp;force=1";
	sleep $sleep_between_files;
	if ($file_being_scanned == 0)
		{
		my $browser = LWP::UserAgent->new;
		print "Forcing rescan...\n";
		print "Rescan URL: ".$force_scan_URL."\n";
		my $force_scan = $browser->get($force_scan_URL);
		#print "Response:\n";
		#print $force_scan->content();
		sleep $sleep_between_files;
	} else
		{
		$file_being_scanned = 0;
	}
}





sub pull_scanning_results
	{
## SELECT MD5, SHA1, SHA256, Filename, ResultURL from $scanning_table where SysID = ? && Extension = ? && AlreadyRescanned = 'N'");
##	$scanning_select_prpst->execute($sysid, $extension_priority[$extension_index - 1]);
	$scanning_select_prpst->execute($sysid, $allow_seconds_for_new_upload_scan);
	while (@filename_row = $scanning_select_prpst->fetchrow_array())
		{
		print "\n\n";
		$file_path=$filename_row[3];

		print "File: ".$file_path."\n";
	#####  check filesize

		if ($debug >= 2)
		   {
			print "Rescanning file path: ".$file_path."\n";
		}
		$fileMD5 = $filename_row[0];
		$fileSHA1 = $filename_row[1];
		$fileSHA256 = $filename_row[2];
#		$resultURL = "http://www.virustotal.com".$filename_row[4];
		$resultURL = $filename_row[4];
		$resultURL =~ s/^\//http:\/\/www\.virustotal\.com\//;
		if ($debug >= 2)
			{
			print "Rescan URL: ".$resultURL."\n";
		}
		&check_local_results($file_path);
		if ($results eq '' || $local_results_no_good == 1)
			{
			if ($debug >= 1)
				{
				print "Pulling results...\n";
			}
			&pull_results($file_path, 1);
	#####   don't beat the crap out of virustotal.com
		sleep $sleep_between_files;

		} elsif ($local_results_no_good == 1)
			{
			if ($debug >= 1)
				{
				print "Pulling results...\n";
			}
			&pull_results($file_path, 1);
	#####   don't beat the crap out of virustotal.com
		sleep $sleep_between_files;
		}
		if (defined($results) && $results ne '')
			{
## UPDATE $scanning_table set AlreadyRescanned = 'Y' where SysID = ? && SHA256 = ? && SHA1 = ? && MD5 = ?
			$scanning_update_prpst->execute($sysid, $fileSHA256, $fileSHA1, $fileMD5);
		}
	}


	
}











