#!/usr/bin/perl
use strict;
use Getopt::Std;
use Fcntl qw(:DEFAULT :flock);
require 5.005;

my $usageStr = <<"END_OF_CODE";
Usage: monitor.pl -d <DansGuardian conf dir> -u user -i IP -t seconds [-h -v]

    -d defaults to /etc/dansguardian
    -u and -i are mutually exclusive, you can only specify one
       or the other.  If virusscanner.conf is sorting by
       user and you specify IP then we blow an error, etc.
    -t allows you to specify how long to sleep between checks.
       defaults to 1.
    -h displays this help message.
    -v displays the version of this script.
END_OF_CODE

my $confDir = "/etc/dansguardian";
my $sleepTime = 1;
my $user = "";
my $IP = "";

# get the command line arguments.
my %opts;
getopt('d:u:hvi:t:', \%opts);
foreach my $option (keys %opts)
{
  #print "option = '$option', value = '$opts{$option}'\n";
  if ($option eq "d")
  {
    if (! -d $opts{$option})
    {
      programHeader();
      print "Error:  The specified DansGuardian config directory does not exist!  Dir = '$opts{$option}'.  Error=$!\n";
      usage(1);
    }
    $confDir = $opts{$option};
  }
  elsif ($option eq "t")
  {
    if ($opts{$option} !~ /^(\d+)$/)
    {
      programHeader();
      print "Error:  Sleep Time = '$opts{$option}' is invalid!\n";
      usage(1);
    }
    $sleepTime = $opts{$option};
  }
  elsif ($option eq "h")
  {
    programHeader();
    usage(0);
  }
  elsif ($option eq "v")
  {
    programHeader();
    exit 0;
  }
  elsif ($option eq "u")
  {
    if ($opts{$option} !~ /^(.+)$/)
    {
      programHeader();
      print "Error: '$opts{$option}' is invalid for -$option!\n";
      usage(1);
    }
    $user = $opts{$option};
  }
  elsif ($option eq "i")
  {
    if ($opts{$option} !~ /^([01]?\d?\d|2[0-4]\d|25[0-5])\.([01]?\d?\d|2[0-4]\d|25[0-5])\.([01]?\d?\d|2[0-4]\d|25[0-5])\.([01]?\d?\d|2[0-4]\d|25[0-5])$/)
    {
      programHeader();
      print "Error: '$opts{$option}' is invalid for -$option!\n";
      usage(1);
    }
    $IP = $opts{$option};
  }
  else
  {
    programHeader();
    print "Error:  -$option is an unknown option!\n";
    usage(1);
  }
}

if (scalar @ARGV > 0)
{
  usage(1);
}

programHeader();  # output the program Header.

# make sure we have the necessary files.
if (! -e "$confDir/virusscanner.conf")
{
  die "Error:  virusscanner.conf does not exist!\n";
}
if (! -e "$confDir/config.pl")
{
  die "Error:  config.pl does not exist!\n";
}

# setup the INC path
unshift @INC, $confDir;

require 'logger.pl';
require 'config.pl';

# instantiate the config parser code from the
$Config::ConfigFile = "$confDir/virusscanner.conf";  # make sure we point at the correct config file. (non-standard location support)

Config::ReadConfig($Config::ConfigFile);

# verify the specified IP or user is valid in this scenario.
if ($Config::StatusGroupedBy eq "uname")
{
  if (length $user == 0)
  {
    print "Error:  You must specify a user to monitor!\n";
    usage(1);
  }
}
else
{
  if (length $IP == 0)
  {
    print "Error:  You must specify an IP Address to monitor!\n";
    usage(1);
  }
}

my $sortBy = ($Config::StatusGroupedBy eq "uname" ? $user : $IP);

while (1)
{
  # output the seperator
  my $date = `/bin/date`;  
  chomp $date;

  print "** $date ********************************\n\n";
  # see if the status directory exists
  if (-d "$Config::DownloadDir/status/$sortBy")
  {
    # get a list of all files in the directory.
    my @files = glob("$Config::DownloadDir/status/$sortBy/*");
    if (scalar @files > 0)
    {
      print "Processing " . int(scalar @files) . " status files...\n";
      foreach my $fileName (@files)
      {
        (my $file = $fileName) =~ s/^$Config::DownloadDir\/status\/$sortBy\///;  # get rid of the path.

        # open the file for reading.
        if (!open(STATUS, "$fileName"))
        {
          print "Warning:  Failed to open file '$fileName' for reading!  $!\n";
          next;
        }

        # get a read lock on the file.
        if(!flock(STATUS, LOCK_SH))
        {
          print "Warning:  Failed to get a read lock on file '$fileName'!  $!\n";
          next;
        }

        # read the contents.
        my @data = <STATUS>;  # suck in the file.

        close(STATUS);

        # now output the data.
        print join("", @data);
        print "\n";
      }
    }
    else
    {
      print "status directory '$sortBy' is currently empty...\n";
    }
  }
  else
  {
    print "status directory '$sortBy' does not yet exist.\n";
  }

  # sleep
  sleep $sleepTime;
}

sub programHeader
{
  print "DansGuardian Anti-Virus Monitor Script v1.0\n";
}

sub usage
{
  my $errorCode = shift;

  print $usageStr;
  exit $errorCode;
}
