#!/usr/bin/perl

###################################
# Orax SDI Agent
###################################

use LWP::Simple;
use LWP::UserAgent;
use HTTP::Request::Common;
use LWP::Protocol::https;
use File::Basename;

use Time::Local;
use Time::HiRes qw(gettimeofday sleep usleep time);
use Crypt::Lite;
use Encode;
use Encode::Locale;
use Encode::Byte;

use threads;
use threads::shared;
use File::Spec;

my $stm = time;
my $OS = $^O;
my $VERSION = "5.3.2a";
my $version_note = "Automation command no longer redirects error to stdin";
my $url = ""; 
my $system_id = ""; 
my $http_proxy = "";
my $auto_cmd = ""; 
my $conf_path = "/dr1/agent";
my $scrext = "sh";
my $processid = $$;

## START LOGGING
my $fs = `wc -l $conf_path/SDIAgent.log | awk '{ print \$1 }'`; chomp($fs);
print "Log file lines: ($fs)\n";
if ($fs > 1000) { open(LOGF,">$conf_path/SDIAgent.log"); } else { open(LOGF,">>$conf_path/SDIAgent.log"); }

## CHECK FOR RUNNING AGENTS
if (&check_for_running_agent) { print "Agent running! Exiting...\n\n"; exit; }

## START AGENT ###
&set_env;
if ($url eq "" || $system_id eq "") { 
	## EXIT IF NOT SETUP
	print "Agent not setup! Exiting...\n\n";
	exit;
}

#my $iaddr = `/sbin/ip route | grep src | awk '{ print \$9 }' | head -n1`; chomp($iaddr);
#my $iaddr = `/sbin/ip route | grep src | awk -F" src " '{ print \$2 }' | awk '{ print \$1 }' | head -n1`; chomp($iaddr);
my $iaddr = `/sbin/ip a |grep global | head -n1 | awk '{ print \$2 }' | awk -F"/" '{ print \$1 }'`; chomp($iaddr);
my $hostnm = `/bin/hostname`; chomp($hostnm);
## Check ARM processor and Automation Command setting (ARM ignored - Jan 2021)
my $hsys = `/bin/uname -a | grep armv | wc -l`; chomp($hsys); 
if ($auto_cmd ne "ON") { $hsys = 0; } elsif ($auto_cmd eq "ON") { $hsys = 1; }

print "Agent IP: $iaddr ($hostnm)\n";
print LOGF "Agent IP: $iaddr ($hostnm)\n";

## Create Cache directory if missing
if (! -e "$conf_path/cache") { `mkdir -p $conf_path/cache`; }

our $ic_lt :shared;
our $oc_lt :shared;
our $sc_lt :shared;
$ic_lt = time; $oc_lt = time; $sc_lt = time;

## START THREADS
print LOGF "Starting threads: \n";
##################################################
my $ic_thr;
my $oc_thr;

if ($hsys == 1) { # Only start for ARM processor

	## INPUT CLIENT (Concept)
	$ic_thr = threads->new('connect_input_client');

	## OUTPUT CLIENT
	$oc_thr = threads->new('connect_output_client');
}

## SCRIPT CHECKING
my $sc_thr = threads->new('check_scripts');
`sleep 1`;
##################################################

my $tcnt = 1; if ($hsys == 1) { $tcnt = 3; }
my $bcnt = 1; if ($hsys == 1) { $bcnt = 3; }
print "$tcnt threads started - logging to SDIAgent.log, entering wait state...\n\n";
while ($tcnt == $bcnt) {
	&get_time;
	$tcnt = 0;
	if ($hsys == 1) {
		if ($ic_thr->is_running()) { $tcnt++; }
		if ($oc_thr->is_running()) { $tcnt++; }
	}
	if ($sc_thr->is_running()) { $tcnt++; }
	print LOGF "$tcnt threads at $sysdate $systime...\n";
	`sleep 60`; 
	## Check thread last times
	#printf LOGF "Time for IC: %0.1f\n",time - $ic_lt;
	#printf LOGF "Time for OC: %0.1f\n",time - $oc_lt;
	#printf LOGF "Time for SC: %0.1f\n",time - $sc_lt;
	if ($hsys == 1) {
		if (time - $ic_lt > 70) { $tcnt--; print "Last time failed for IC!\n"; }
		if (time - $oc_lt > 70) { $tcnt--; print "Last time failed for OC!\n"; }
	}
	if (time - $sc_lt > 90) { $tcnt--; print "Last time failed for SC!\n"; }
}

if ($hsys == 1) {
	$ic_thr->detach();
	$oc_thr->detach();
}
$sc_thr->detach();
close(LOGF);
exit;



## STOP LOGGING AND EXIT
#######################################################################



#######################################################################
### AGENT THREADS & FUNCTIONS #########################################
#######################################################################

#######################################################################
sub connect_input_client {

	print LOGF "Input thread started!\n";
	my @mfile; if (-e "$conf_path/oraxagent.auto") { open(INF,"$conf_path/oraxagent.auto"); @mfile=<INF>; close(INF); }
	my @inp;

	## INSECURE COMMANDS !!
	my $irl = $url; #$irl =~ s/https/http/g;

	foreach (@mfile) {
		chomp($_);
		my ($atp,$adet) = split(/=/,$_);
		if ($atp eq "INPUT") {
			my ($ain,$acmd) = split(/\:/,$adet);
			my ($iio,$imet,$imv) = split(/,/,$ain);
			my @iac = split(/,/,$acmd);
			my $ichk = "INPUT" . $iio . "TRIGGER";
			my $itt = "rising"; my $itp = "down"; my $inn = 1; my $wop = 0;
			if (substr($iio,1) eq "off") { $itt = "falling"; $itp = "up"; $inn = 0; $wop = 1; }
			$iio =~ s/[onf]//g;
			#my $ocmd = "$ichk :::echo $ichk; export PATH=\$PATH:/usr/local/bin; gpio mode $iio $itp; gpio wfi $iio $itt; if [ \`gpio read $iio\` -eq $inn ]; then ";
			my $ocmd = "$ichk :::echo $ichk; export PATH=\$PATH:/usr/local/bin; gpio mode $iio $itp; while echo; do while gpio read $iio | grep \"$wop\"; do sleep 0.1; done; if [ \`gpio read $iio\` -eq $inn ]; then ";
			my $bc = $ocmd;
			my $tcmd;
			foreach (@iac) { 
				if (substr($_,0,3) eq "sms") { 
					my $mess = substr($_,13); if ($mess eq "") { $mess = "Input $iio activated on System $system_id"; }
					$ocmd .= "wget -O /dev/null \"$url/portal/mon_command.app?$system_id&$mess&SEND_SMS&" . substr($_,3,10) . "\"; "; 
				}	
				elsif (substr($_,0,1) eq "s") { $ocmd .= "/bin/sleep " . substr($_,1) . "; "; }
				elsif (substr($_,0,2) eq "rc") {
					my ($rsid,$rcmd) = split(/cmd/,substr($_,2));
					$ocmd .= "wget -O /dev/null \"$url/portal/mon_command.app?$rsid&NEWCMD&$rcmd\"; ";
				} elsif (substr($_,0,2) eq "rx") {
					my @prms = split(/&/,substr($_,2));
					$ocmd .= "wget -O /dev/null \"$url/xc?run_code&$prms[0]&$prms[1]&$prms[2]&RAW\"; ";
				} elsif (substr($_,0,1) eq "r") {
					my ($rsid,$rio) = split(/p/,substr($_,1));
					my $fss = "1"; if (eval {$rio =~ qr/off/}) { $fss = "0"; }
					$rio =~ s/[a-z]//g;
					$ocmd .= "wget -O /dev/null \"$url/portal/mon_command.app?$rsid&NEWCMD&$rio&$fss\"; ";
				} elsif (substr($_,0,2) eq "if") {
					my $fss = "1"; if (eval {$_ =~ qr/off/}) { $fss = "0"; }
					my $fpn = $_; $fpn =~ s/[a-z]//g;
					$ocmd .= "if [ \`gpio read $fpn\` -eq $fss ]; then ";
					$tcmd = " fi; "
				} elsif (substr($_,0,4) eq "else") { 
					$ocmd .= "else "; 
				} elsif (substr($_,0,1) eq "w") { 
					my $wtp = substr($_,1); my $wio = $wtp; $wio =~ s/[onf]//g; $wtp =~ s/[0-1]//g;
					my $wtt = "rising"; $wop = 0; if ($wtp eq "off") { $wtt = "falling"; $wop = 1; }
					#$ocmd .= "gpio wfi $wio $wtt; "; 
					$ocmd .= "while gpio read $wio | grep \"$wop\" do sleep 0.1; done; "; 
					#$ocmd .= "gpio mode $wio down; gpio wfi $wio $wtt; "; 
				}	
				elsif (substr($_,0,4) eq "cmd(") { my $ccm = substr($_,4,length($_)-5); $ocmd .= "$ccm; "; }
				elsif (substr($_,0,2) eq "on") { $ocmd .= "gpio mode " . substr($_,2) . " out; gpio write " . substr($_,2) . " 1; "; }
				elsif (substr($_,0,3) eq "off") { $ocmd .= "gpio mode " . substr($_,3) . " out; gpio write " . substr($_,3) . " 0; "; }	
			}
			if ($bc eq $ocmd) { $ocmd .= "echo \"Input detected!\"; "; }
			$ocmd .= $tcmd . " fi; ";
			$ocmd .= " done";

			if ($imet ne "") { 
				my $tmm = time . $metcnt; my $eresult = &encrypt($imv);
				$ocmd .= " mdt=`date +\%s`; echo \"$imet|\$mdt|$eresult\" > $conf_path/cache/oraxagent_\$mdt.upl"; 
				$metcnt++;
			}
			push(@inp,$ocmd);
		}
	}


	while (true) {
		foreach (@inp) {
			my ($ichk,$icmd) = split(/:::/,$_); $ichk =~ s/ //g;
			if (substr($ichk,0,5) eq "INPUT" && length($icmd) > 5) {
				my $ochk = `ps -ef | grep $ichk | grep -v "grep $ichk" | wc -l`; chomp($ochk);
				if ($ochk < 1) {
					print "Starting $ichk... ($icmd)\n";
					#my $dbug = &get_url("$irl/portal/mon_command.app?$system_id&Input thread started on system $system_id ($ichk/$ochk)&SEND_SMS&0826299915",110); # Longer timeout

					my $cm_thr = threads->new(sub { 

						print LOGF "Started input trigger thread at $sysdate $systime...\n($content)\n"; 
						my $trgfb = `$content`; $trgfb =~ s/\n//g;
						print LOGF "Done!\n"; 
						`$icmd`;

					})->detach();
				} 
			}
		}
		`sleep 1`; ## Workaround
		lock($ic_lt); $ic_lt = time;
	}
}

#######################################################################
sub connect_output_client {

	print LOGF "Output thread started!\n";
	while (true) {
		&get_time; 

		## INSECURE COMMANDS !!
		my $irl = $url; #$irl =~ s/https/http/g;

		my $content = &get_url("$irl/portal/mon_command.app?$system_id&AUTOCMD",110); # Longer timeout
		if ($content ne "NC" && $content ne "") { 

			## FEEDBACK
			my $fbs; my $fbid;
			if (eval { $content =~ qr/ FBSYS /}) { $fbs = "system"; ($content,$fbid) = split(/ FBSYS /,$content); }
			elsif (eval { $content =~ qr/ FBCMD /}) { $fbs = "cmd"; ($content,$fbid) = split(/ FBCMD /,$content); }

			if (substr($content,0,10) eq "QUEUETHIS ") {

					$content = substr($content,10);

					print LOGF "Started output cmd thread at $sysdate $systime...\n($content)\n"; 
					my $cmdfb = `$content`; $cmdfb =~ s/\n//g; $cmdfb =~ s/&/RPAMP/g; $cmdfb =~ s/#/%23/g;
					print LOGF "Done!\n"; 

					if ($fbs eq "system") { my $fb = &get_url("$irl/portal/mon_command.app?$system_id&$cmdfb&V$VERSION&$iaddr"); }
					elsif ($fbs eq "cmd" && $fbid ne "") { my $fb = &get_url("$irl/portal/mon_command.app?$system_id&CMD_FB&$cmdfb&$fbid"); }

			## CAMERA IMAGE
			} elsif ($content eq "FETCH_CAM_LAST") { 
			
				#`raspistill -t 1 -n -q 60 -w 1024 -h 640 -o /dev/shm/limg$system_id.jpg`;
				#`convert $fil -strip -interlace Plane -quality 40% $fil`; 
				#&post_file("$irl/portal/mon_save_file.app?$system_id",-1,"/dev/shm/limg$system_id.jpg");

				## Schedule raspistill to dump to /dev/shm/image.jpg continually - see SDI Raspi Notes for detail
				`rm -f /dev/shm/limg$system_id.jpg; cp /dev/shm/image.jpg /dev/shm/limg$system_id.jpg`; 
				&post_file("$irl/portal/mon_save_file.app?$system_id",-1,"/dev/shm/limg$system_id.jpg");

			## DO SCREENSHOT & UPLOAD IMAGE
			} elsif ($content eq "SCREENSHOT") { 

				`sudo -u pi rm -f /home/pi/screen.png;`;
				`sudo -u pi DISPLAY=:0 scrot /home/pi/screen.png`;
				if (-e "/home/pi/screen.png") {
					&post_file("$irl/portal/mon_save_file.app?$system_id",-1,"/home/pi/screen.png");
					my $fb = &get_url("$irl/portal/mon_command.app?$system_id&SCREENSHOT RECEIVED&V$VERSION&$iaddr");
				} else {
					my $fb = &get_url("$irl/portal/mon_command.app?$system_id&SCREENSHOT FAILED&V$VERSION&$iaddr");
				}
			

			## CAMERA IMAGE - MULTIPLE
			} elsif (substr($content,0,11) eq "FETCH_CAM_N") { 

				## Schedule raspistill to dump to /dev/shm/image.jpg continually - see SDI Raspi Notes for detail
				my $tms = $content; $tms =~ s/[A-Z_]//g;
				if ($tms > 1 && $tms < 30) {
					for ($tt=0;$tt<$tms;$tt++) {
						`rm -f /dev/shm/limg$system_id.jpg; cp /dev/shm/image.jpg /dev/shm/limg$system_id.jpg`; 
						&post_file("$irl/portal/mon_save_file.app?$system_id",-1,"/dev/shm/limg$system_id.jpg");
						`sleep 1`;
					}
				}
			
			## UPLOAD FILE 
			} elsif (substr($content,0,8) eq "BKPFILE:") { 

				## BKPFILE:2345:/share/File.jpg
				my ($jnk,$bid,$fls) = split(/\:/,$content);
				if ( -r "$fls") { 
					print LOGF "Backup file upload: ($content)\n"; 
					print LOGF &post_file("$irl/portal/mon_save_file.app?$bid",-3,$fls,"preserve"); 
					print LOGF "Done!\n"; 
				}

			} else {

				my $cm_thr = threads->new(sub { 

					print LOGF "Started output cmd thread at $sysdate $systime...\n($content)\n"; 
					my $cmdfb = `$content`; $cmdfb =~ s/\n/RPLF/g; $cmdfb =~ s/&/RPAMP/g; $cmdfb =~ s/#/%23/g;
					print LOGF "Done!\n"; 

					if ($fbs eq "system") { my $fb = &get_url("$irl/portal/mon_command.app?$system_id&$cmdfb&V$VERSION&$iaddr"); }
					elsif ($fbs eq "cmd" && $fbid ne "") { my $fb = &get_url("$irl/portal/mon_command.app?$system_id&CMD_FB&$cmdfb&$fbid"); }

				})->detach();

			}
				
		} else { print LOGF "No output cmd at $sysdate $systime\n"; }
		lock($oc_lt); $oc_lt = time;
	}
}

#######################################################################
sub check_scripts {

	print LOGF "Metric thread started!\n";	
	while (true) {
		&get_time;
		my $fstm = time;
		printf LOGF "SystemID:$system_id, PID:$processid (%0.0f) TIME: $sysdate $systime\n",time - $stm;	
		&check_command;
		printf LOGF "Completed agent command check (%0.0f)\n",time - $stm;
		&collect_metrics;
		printf LOGF "Completed metric collection (%0.0f)\n",time - $stm;
		&flush_metrics;
		printf LOGF "Completed upload (%0.0f)\n",time - $stm;
		while ((time - $fstm) < 60) { `sleep 1`; }
		$sc_lt = time;
	}
}


#######################################################################
# System Functions                                                    #
#######################################################################
#######################################################################
sub check_for_running_agent {

        my $proc_cnt = 0;
	$proc_cnt = `ps -ef |grep "perl ./oraxagent.pl" |grep -v grep |grep -v log| wc -l`;
	chomp($proc_cnt);
        if ($proc_cnt > 1) { return 1; }
        return 0;
}




##################################################################
sub encrypt { # param ("text") RETURN encrypted text
    
	my $crypt = Crypt::Lite->new( debug => 0, encoding => 'hex8');
	my $encrypted = $crypt->encrypt($_[0], 'qs21');
	return "rs24hD0z" . $encrypted;
    
}

#######################################################################
sub set_env {
    
    open(INF,"$conf_path/oraxagent.met"); my @mfile=<INF>; close(INF);
    foreach my $mln (@mfile) {
        chomp($mln);
        my ($macro,$mlm) = split(/:::/,$mln);
        #print "Found:$macro-->$mlm\n";
        my @ml=split(/\|/,$mlm);
        if ($macro eq "ENVIRONMENT") {
            my @envo=split(/"cr"/,$mlm);
            foreach my $eln (@envo) {
                my ($evar,$eval)=split(/=/,$eln);
                $ENV{$evar} = "$eval"; #print "Setting: $evar = $eval\n";
            }
        }
    }
    
    open(INF,"$conf_path/oraxagent.conf"); my @mfile=<INF>; close(INF);
    foreach my $mln (@mfile) {
        chomp($mln);
        my ($macro,$mlm) = split(/:::/,$mln);
	$mlm =~ s/ //g;
        if ($macro eq "URL") { $url = $mlm; } 
        elsif ($macro eq "SYSTEMID") { $system_id = $mlm; } 
        elsif ($macro eq "CMD") { $auto_cmd = $mlm; } 
        #elsif ($macro eq "HTTP_PROXY" && $mlm ne "") { $http_proxy=$mlm; } #print "Proxy Server: $http_proxy\n"; } 
    }

    ## clear legacy files
    if ($url eq "" || $system_id eq "") { `cd $conf_path/; rm -f cache/* oraxagent.met oraxagent.last oraxagent.upl oraxagent.log error*`; }
    
    return 1;
}

#######################################################################
sub write_error_script { # parms ( filename, script, cmd )
    
	if ($_[1] ne "") {
		open(SCR,">$_[0]"); print SCR $_[1]; close(SCR) or die;
	} elsif ($_[2] ne "") {
		my $cmd = $_[0]; $cmd =~ s/vbs/cmd/;
		open(SCR,">$cmd"); print SCR $_[2]; close(SCR) or die;
	}
	$result = "Script Error";
	return 1;
}


#######################################################################
sub execute_script {
    
	my $now = time; 
	my @ml=split(/\|/,$_[0]);
	my $mscript = $ml[4]; $mscript =~ s/\[PIPE\]/\|/g; $mscript =~ s/"cr"/\n/g;
	my @scrl = split(/\n/,$mscript);
    
	if ($ml[1] == 1440 && eval { $mscript =~ qr/execution_time/ } ) {
		my $extm; 
		my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
		foreach my $el (@scrl) { if (substr($el,0,15) eq "execution_time=") { $extm = substr($el,15); } }
		my ($exhr,$exmi) = split(/:/,$extm); my $exnx = "$year-$mon-$mday $extm";
		$now = timelocal(00,$exmi,$exhr,$mday,$mon,$year);
		#printf "EXECUTION TIME: $extm (Now: $exnx / $now / %0f)\n",time;
		#print "EXECUTION TIME: $extm\n";
		shift(@scrl); $mscript = ""; foreach my $ln (@scrl) { $mscript = $mscript . "$ln\n"; }
	}
    
	my $oscr = "";
	my $write = 0;
	my $cscr = "";
	if ( eval { $mscript =~ qr/BEGIN_SCRIPT/ } ) {
		#print "Writing sub-script\n";
		
		foreach $ln (@scrl) {
			if ($write == 2) { $cscr = $cscr . "$ln\n"; }
			if ($ln eq "END_SCRIPT") { $write = 2; }
			if ($write == 1) { $oscr = $oscr . "$ln\n"; }
			if ($ln eq "BEGIN_SCRIPT") { $write = 1; }
		}
		open(SCR,">./oraxagent.scr"); print SCR $oscr; close(SCR);
		if ($OS eq "linux") { 
			open(SCR,">$conf_path/metric$ml[0].scr"); print SCR $oscr; close(SCR);
			`chmod +x $conf_path/metric$ml[0].scr`; 
			$cscr =~ s/EXEC_SCRIPT/$conf_path\/metric$ml[0].scr/g;
		} else {
			open(SCR,">$conf_path/metric$ml[0].vbs"); print SCR $oscr; close(SCR);
			$cscr =~ s/EXEC_SCRIPT/"$conf_path"\/metric$ml[0].vbs/g;
		}
		$mscript=$cscr;
        
	} 
	#print "SCRIPT:$mscript\n";
    
	our $result=`$mscript` or &write_error_script("$conf_path/error$ml[0].$scrext",$oscr,$mscript);
    #print "RESULT:$result\n";
	my $eresult;
	
	if ($result ne "Script Error") {
		$result =~ s/\n/ /g;
		#$result =~ s/ //g;
		$result =~ s/REPLACE_SPACE/ /g;
		$result =~ s/\t/ /g;
		$result =~ s/  / /g;
		## REMOVE TRAILING SPACE
		if (substr($result,length($result)-1,1) eq " ") { $result = substr($result,0,length($result)-1); }
		print LOGF "Metric $ml[0] Result: \[$result\]\n";
		$eresult = &encrypt($result);
	} else {
		print LOGF "Metric $ml[0] Error!\n";
		$eresutl = "";
	}
    
	## UPDATE LAST FILE ###	
	open(INF,"$conf_path/oraxagent.last");	my @mupl=<INF>;	close(INF);
	
	open(OUT,">$conf_path/oraxagent.last");
	foreach my $mll (@mupl) {
		chomp($mll);
		my @mls=split(/\|/,$mll);
		if ($mls[0] ne $ml[0]) { print OUT "$mll\n"; }
	}
	print OUT "$ml[0]\|$now\|$result\n"; 
	close(OUT) or die;
	
	## SAVE TO METRIC CACHE
	my $tmm = time . $metcnt;
        if (! -e "$conf_path/cache") { `mkdir -p $conf_path/cache`; }
        open(OUT,">>$conf_path/cache/oraxagent_$tmm.upl"); print OUT "$ml[0]\|$now\|$eresult\n"; close(OUT);
        $metcnt++;
    
    
	return 1;
	
}

#######################################################################
sub collect_metrics {
    
    if ( ! -e "$conf_path/oraxagent.met" ) { &download_config; }
    
    open(INF,"$conf_path/oraxagent.met");
    my @mfile=<INF>;
    close(INF);
    
    open(INF,"$conf_path/oraxagent.last");
    my @mlast=<INF>;
    close(INF);


    
    my $now = time; 
    our $metcnt = 0;

    foreach my $mln (@mfile) {
        chomp($mln);
        my ($macro,$mlm) = split(/:::/,$mln);
        my @ml=split(/\|/,$mlm);
        if ($macro eq "METRIC" && $ml[1] ne "") {
            #print "\nReading last call of metric interval ($ml[1]) on $systime for $ml[0]\n";
            
            my ($md,$mh,$mm);
            my $last_time=0;
            my ($sec,$min,$hr,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
            my @wday = ("Sun","Mon","Tue","Wed","Thu","Fri","Sat");
            $wday = $wday[$wday];
            ## Monthly and weekly metrics
            if (eval {$ml[1] =~ qr/:/}) {
                ($md,$mh,$mm) = split(/:/,$ml[1]);
                $ml[1] = "999999999";
                #print "Found monthly metric: $md,$mh,$mm (current time: $wday, $mday - $hr:$min)\n";
            }
            foreach my $mll (@mlast) {
                chomp($mll);
                my @mls=split(/\|/,$mll);
                if ($mls[0] eq $ml[0]) { $last_time = $mls[1]; }
            }
            #print "Last TIme: $last_time (Now: $now)\n";
            
            
            if (
                (($md eq $wday || $md eq "Day") && $mh == $hr && $mm == $min && $now >= ($last_time + 60)) ## Weekly intervals
                || ($md == $mday && $mh == $hr && $mm == $min && $now >= ($last_time + 60)) ## Monthly intervals
                || ($md eq "" && $now >= ($last_time + ($ml[1] * 60)))  ## Normal intervals
                ) {
                if ($ml[0] ne "") {
                    #print "Running script for: $ml[0] at $systime\n\n";
                    &execute_script($mlm);
                } else { print "No script to run!"; }
            } #else { print "Not now\n\n"; }
        }
	}
    
    return 1;
}


#######################################################################
sub flush_metrics {

	my $linkfail = 0;
	my $upls = `ls -tr $conf_path/cache/oraxagent_*.upl`;
 	my @upl = split(/\n/,$upls);
 	foreach (@upl) {
	   my $cfl = $_;
	   #print "Uploading: ($cfl)\n";
	   my $mln = `cat $cfl`; chomp($mln); my @ml=split(/\|/,$mln);
	   my $auth_key = (($ml[1] - 1218950210) * $ml[0]) * 1.3;
	   my $jtime=((time / 3.45) * 1.37);
	   my $rjtime=((time / 1.45) * 2.37);
	   my $metid=sprintf "%06.0f%0.8f.%08.22f",$ml[0] * 3.8293,$auth_key,$rjtime;
           if ($linkfail > 3) { print OUT "$mln\n"; }
           elsif ($linkfail > 30) { print OUT "Link failure.  Restarting.  Exiting.\n"; exit; }
	   elsif (&upload_metric($ml[0],$ml[2],$ml[1],$metid) eq "OK") { `rm -f $cfl`; } else { print LOGF "Failed!\n"; $linkfail++; }

 	}

	## UPLOAD URL
	my $uprs = `ls -tr $conf_path/cache/upload*.url`;
	my @upl = split(/\n/,$uprs);
	foreach (@upl) {
		my $cfl = $_;
		#print "Uploading: ($cfl)\n";
		my $mln = `cat $cfl`; chomp($mln);
		if ($linkfail > 3) { print OUT "$mln\n"; }
		elsif (&get_url($mln) ne "") { `rm -f $cfl`; } else { print LOGF "Failed!\n"; $linkfail++; }
	}
	return 1;

}


#######################################################################
sub check_command {
    
    my $aaddr = $iaddr;	if ($iaddr ne "" && $hostnm ne "") { $aaddr .= "($hostnm)"; }

	## INSECURE COMMANDS !!
	my $irl = $url; #$irl =~ s/https/http/g;

    my $command=&get_url("$irl/portal/mon_command.app?$system_id&&V$VERSION&$aaddr");
    chomp($command);
    if ($command eq "CONFIG") {
        &download_config;
    } elsif ($command eq "RESET") {
        `cd $conf_path/; rm -f oraxagent.last oraxagent.met oraxagent.log error* cache/*`;
    } elsif ($command eq "REBOOT") {
        `/sbin/reboot`;
    } elsif ($command eq "AUTO_CONFIG") {
    	my $cnnf=&get_url("$url/portal/mon_command.app?$system_id&AUTO_CONFIG");
        open(CNF,">$conf_path/oraxagent.auto"); print CNF $cnnf; close(CNF);
	my $jbs = `ps -ef | grep INPUT | grep TRIGGER | awk '{ print \$2 }'`; chomp($jbs);
	my @jbb = split(/\n/,$jbs); foreach (@jbb) { if ($_ ne "") { `kill -9 $_`; } }
	exit;
    } elsif (substr($command,0,9) eq "CONFIGURE") {
	my @confs = split(/;;;/,$command);
	my ($nurl,$nsys,$ncmd,$nwif,$npss,$dash,$kiosk);
	foreach (@confs) {
		my ($tt,$vv) = split(/:::/,$_);
		if ($tt eq "URL") { $nurl = $vv; }
		elsif ($tt eq "SYSID") { $nsys = $vv; }
		elsif ($tt eq "CMD") { if ($vv eq "TRUE") { $ncmd = "ON"; } }
		elsif ($tt eq "WIFI") { $nwif = $vv; }
		elsif ($tt eq "WPS") { $npss = $vv; }
		elsif ($tt eq "DASH") { $dash = $vv; }
		elsif ($tt eq "KIOSK") { $kiosk = $vv; }
	}
	if ($nurl ne "") {
		print LOGF "Updating agent configuration!!!\n";
		open(ACON,">$conf_path/oraxagent.conf"); print ACON "URL:::$nurl\nSYSTEMID:::$nsys\nCMD:::$ncmd\n"; close(ACON);
		if ($nwif ne "") {
			open(WCON,">/etc/wpa_supplicant/wpa_supplicant.conf"); 
			print WCON "
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
ssid=\"$nwif\"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP TKIP
group=CCMP TKIP
psk=\"$npss\"
}
"; 
			close(WCON);
		}
		if ($dash ne "") {
			my $chrome = "chromium-browser";
			if ( -e "/usr/bin/chromium") { $chrome = "chromium"; }

			## KIOSK Setup
my $kiosk = "
\@xset s off
\@xset -dpms
\@xset s noblank
\@unclutter -idle 0
\@$chrome --noerrdialogs --kiosk --incognito $dash
";
if ($kiosk eq "term") {
	$kiosk = "\@$chrome --noerrdialogs --kiosk $dash";
} elsif ($kiosk eq "full") {
	$kiosk = "\@$chrome --noerrdialogs --start-fullscreen $dash";
}

			open(DASH,">/etc/xdg/lxsession/LXDE-pi/autostart"); 
			print DASH $kiosk;
			close(DASH);
		}
		`cd $conf_path/; rm -f oraxagent.last oraxagent.met oraxagent.log error* cache/*`;
		`/sbin/reboot`;

	} else { print LOGF "Ignoring incorrect update!\n"; }



    } elsif ($command eq "DISABLE") {
        `cd $conf_path/; rm -f oraxagent.conf oraxagent.last oraxagent.met oraxagent.log error* cache/*`;
    } elsif ($command eq "DIE") {
        exit;
    } elsif ($command eq "UPDATE") {
        print "Updating Linux Agent\n\n";
        `if (/usr/bin/wget -O $conf_path/oraxagent.new "https://orax.oraxsdi.com/files/oraxagent.pl"); then /bin/mv $conf_path/oraxagent.new $conf_path/oraxagent.pl; /bin/chmod +x $conf_path/oraxagent.pl; else echo "Error - not updated!"; fi`; 
	exit;
    } elsif ($command ne "") {
	$command =~ s/\[PIPE\]/|/g; 
        my $result=`$command > "$conf_path"/oraxagent.res; echo "\nAGENTDONE" >>"$conf_path"/oraxagent.res &`;
        $result=`cat $conf_path/oraxagent.res`; 
	$result =~ s/\n/RPLF/g; $result =~ s/&/RPAMP/g; $result =~ s/#/%23/g; 
        print LOGF "EXECUTING NEW COMMAND on $hr:$min $dd-$mm-$yyyy:\n$command\nRESULT: $result\n\n";
        if (! eval { $result =~ qr/AGENTDONE/ } ) { $result = "Process running..."; }
        my $result=&get_url("$irl/portal/mon_command.app?$system_id&$result&V$VERSION&$iaddr");
    }
    
    return 1;
}



#######################################################################
sub download_config {
    
    my $content=&get_url("$url/portal/mon_config.app?$system_id");
    if ($content ne "") {
        print LOGF "CONFIG UPDATE at $hr:$min $dd-$mm-$yyyy:\n"; # $content\n\n";
        open(OUT,">$conf_path/oraxagent.met"); print OUT $content; close(OUT) or die;
    }
    
    return 1;
}


#######################################################################
sub upload_metric {
    
    my $meth = "POSTR"; 
    my $content=&post_metric("$url/portal/mon_save_metric.app?$_[0]&$meth&$_[2]&$_[3]&$iaddr",$_[1]);
    
    if (substr($content,0,5) ne "Saved") { 
        print LOGF "Metric $_[0] uploading error: $content";
        return "NOT"; 
    } else { 
        print LOGF "Metric $_[0] upload result: $content";
        ## UPLOAD FILE IF DETECTED ####
        if (substr($content,0,10) eq "Saved File") {
            my ($feed,$fld,$mid) = split(/:/,$content);
            if ( -r "$conf_path/$fld") {
                print LOGF &post_file("$url/portal/mon_save_file.app?$_[0]",$mid,"$conf_path/$fld");
            }
        } 
        return "OK"; 
    }
    
}



#######################################################################
sub get_url { # parms ( url, timeout )
    
    my $target=$_[0];
    #print "Connecting to : $target ...\n";
    my $ua = new LWP::UserAgent();
    my $tio = 60; if ($_[1] ne "") { $tio = $_[1]; }
    $ua->timeout($tio);
    if ($http_proxy ne "") { $ua->proxy('http',$http_proxy); }
    my $resp = $ua->request(GET "$target");
    $_ = $resp->{_content};
    $content = $_, "\n";
    if (substr($content,0,3) eq "500" || eval { $content =~ qr/t connect to/ }) { $rcontent = ""; print LOGF "Could not connect!!\n\n"; sleep 5; }
    else { $rcontent=$content; }
    return "$rcontent";
}

#######################################################################
sub post_metric { # parms ( url, mresult )
    
    my $url=$_[0];
    my $mresult=$_[1];
    #print "Connecting to : $url ...\n";
    my $ua = new LWP::UserAgent();
    $ua->timeout(60);
    #my $ua = LWP::UserAgent::ProxyAny->new; $ua->env_proxy; $ua->timeout(120); #$ua->use_alarm(0); #$ua->use_eval(0);
    my $resp = $ua->post("$url",{ mresult => $mresult });
    $_ = $resp->{_content};
    $content = $_, "\n";
    if (substr($content,0,3) eq "500" || eval { $content =~ qr/t connect to/ }) { $rcontent = ""; print LOGF "Could not connect!!\n\n"; sleep 5; }
    else { $rcontent=$content; }
    return "$rcontent";
}


#######################################################################
sub post_file { # parms ( url, mid, mfile, preserve )
	
	my $url   = $_[0];
	my $mid   = $_[1];
	my $fname = $_[2];
	#print "Connecting to : $url ($mid / $fname)...\n";
		
	## Using Curl for large files
	#print "/usr/bin/curl -F\"mid=$mid\" -F\"upfile=\@$fname\" $url\n";
	my $result = `/usr/bin/curl -F"mid=$mid" -F"upfile=\@$fname" "$url"`; chomp($result);
	return $result;

	# put timeouts, proxy etc into the useragent if needed
	my $ua = new LWP::UserAgent();
        $ua->timeout(360);
	#my $ua = LWP::UserAgent::ProxyAny->new; $ua->env_proxy; $ua->timeout(120); #$ua->use_alarm(0); #$ua->use_eval(0);
	my $req = POST $url, Content_Type => 'form-data',
    Content      => [
    mid => $mid,
    upfile =>  [ $fname ]
    ];
	my $response = $ua->request($req);
    my $result = $response->content;
    
    if (eval {$result =~ qr/File Success/} && $_[3] ne "preserve") {
        ## Delete uploaded file
        #$fname =~ s/ /\\ /g;
        unlink $fname or print LOGF "Cannot delete $fname!";
    }
	
	return $result;
    
}


#######################################################################
sub get_time {
    
    ($sec,$min,$hr,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    $mm = $mon + 1;
    if ($min <= 9) { $min = "0$min"; }
    if ($hr <= 9) { $hr = "0$hr"; }
    if ($mm <= 9) { $mm = "0$mm"; }
    $yy = $year + 1900;
    if ($mday <= 9) { $mday = "0$mday"; }
    $dd = $mday;
    $yyyy = $yy;
    
    our $sysdate="$dd-$mm-$yyyy";
    our $systime="$hr:$min";
    
    return 1;
}

    


1;
