http://qs1969.pair.com?node_id=277152
Category: Utility Scripts
Author/Contact Info ybiC
Description:

Checks Command Antivirus website for updated virus definition file, and fetches if newer than local copy.   Then inflates the self-extracting executable to an 'ms patch' file named for it's release date.   This msp file is copied to latest.msp which can be run (outside this program) to update client PCs.

From a perlish perspective, building this has been a great refresher, especially on minimizing the number of global variables, as I've been Away From Perl for months.   It's good to be back, even for code as straightforward as this.   8^)

Sample run:
http://download.commandcom.com/CSAV/deffiles/DEFMSP.EXE: 200 OK
PKSFX(R) Version 2.50 FAST! Self Extract Utility for Windows 95/NT 4-15-1998
Extracting files from .ZIP: c:/DEFMSP.EXE
Inflating: 030717.msp
1 valid msp file(s):
        030717.msp
Latest msp: 030717.msp
Today:       030723
030717.msp copied to current.msp
Done... <enter> to exit

#!c:\perl\bin\perl.exe

# csavfetch.pl
# pod at tail

use strict;           # avoid D'oh! bugs
use warnings;         # avoid D'oh! bugs
use LWP::UserAgent;   # mirror web file
use File::Copy;       # copy local file
use File::Basename;   # remove extension from filename
use Getopt::Long;     # support options+arguments
use Pod::Usage;       # avoid redundant &Usage()
$|++;                 # stdout hot

my (%dir, %file, %www, $opt_help, $opt_man, $opt_versions);
my $csavfetch_VER = '0.02.04';
GetOptions(
  'help!'     => \$opt_help,
  'man!'      => \$opt_man,
  'versions!' => \$opt_versions,
) or pod2usage(-verbose => 1) && exit;
pod2usage(-verbose => 1) && exit if defined $opt_help;
pod2usage(-verbose => 2) && exit if defined $opt_man;

### START CONFIG PARAMS ###
### START CONFIG PARAMS ###
print "Edit config params first\n" and exit;   # comment out this line
+ with a leading #
$dir{dest} = 'c:/';                            # trailing /
$file{src}   = 'DEFMSP.EXE';
$file{dest}  = $file{src};
$file{synt}  = ' -o';                          # overwrite
$file{ren}   = 'latest.msp';
$file{valid} = '^[0-9]{2}[0-1][0-9][0-3][0-9]\.msp$';   # yymmdd.msp
$www{site} = "http://download.commandcom.com";   # proto://host.dom
$www{path}      = '/CSAV/deffiles/';  # leading+trailing /
$www{realm}     = '';
$www{realmsite} = '';                 # host.dom:port
$www{id}        = '';
$www{pass}      = '';
$www{proxy}     = '';                 # http://host.dom:port
$www{agent}     = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gec
+ko/20030624';
$www{timeout}   = 60;
### END CONFIG PARAMS ###
### END CONFIG PARAMS ###

die "ERROR accessing $dir{dest}: $!\n" unless -d $dir{dest} && -w _;
die "ERROR entering $dir{dest}: $!\n"  unless chdir $dir{dest};

{ # Check for CSAV update, fetch only if newer than local:
  print "$www{site}$www{path}$file{src}: ";
  my $browser = new LWP::UserAgent;
  $browser->credentials($www{realmsite}, $www{realm}, $www{id} => $www
+{pass},);
  $browser->proxy(http => $www{proxy}) unless ($www{proxy} eq ''); 
  $browser->timeout($www{timeout});
  $browser->agent($www{agent});
  my $response = $browser->mirror("$www{site}$www{path}$file{src}", $f
+ile{dest});
  print $response->status_line . "\n";
  if($response->is_error()){
    die "ERROR accessing $www{site}$www{path}$file{src}";
  }
  exit unless ($response->status_line eq '200 OK');
}

# run self-extracting executable:
system("$file{dest}$file{synt}") and die "ERROR extracting $file{dest}
+: $!";

{ # read directory for latest msp file:
  opendir DESTDIR, $dir{dest} or die "ERROR opening $dir{dest}: $!\n";
  my @valid_msps= grep /$file{valid}/, readdir DESTDIR;
  closedir DESTDIR or die "ERROR closing $dir{dest}: $!\n";
  print "\n" . scalar @valid_msps, " valid msp file(s):\n";
  print "            $_\n" for @valid_msps;
  print "\nLatest msp: ", $file{msp} = (sort @valid_msps)[-1], "\n";
}

{ # filename/date validation:
  my %date;
  ( $date{sec},
    $date{min},
    $date{hour},
    $date{mday},
    $date{mon},
    $date{year}) = localtime(time);
  $date{stamp} = sprintf("%02d%02d%02d", $date{year}-100, $date{mon}+1
+, $date{mday});
  $file{basename} = fileparse($file{msp}, '\.msp');
  print "Today:      $date{stamp}\n";
  if($file{basename} > $date{stamp}){
    print "ERROR: $file{msp} is named for a future datestamp\n";
    exit;
  }
}

# copy latest msp to 'latest.msp' for user logon script:
copy($file{msp}, $file{ren})
  or die "ERROR copying $file{msp} to $file{ren}: $!";
print "$file{msp} copied to $file{ren}\n";

END{
  if(defined $opt_versions){
    print
      "\nModules, Perl, OS, Program info:\n",
      "  LWP::UserAgent        $LWP::UserAgent::VERSION\n",
      "  File::Copy            $File::Copy::VERSION\n",
      "  File::Basename        $File::Basename::VERSION\n",
      "  Pod::Usage            $Pod::Usage::VERSION\n",
      "  Getopt::Long          $Getopt::Long::VERSION\n",
      "  strict                $strict::VERSION\n",
      "  warnings              $warnings::VERSION\n",
      "  Perl                  $]\n",
      "  OS                    $^O\n",
      "  csavfetch.pl          $csavfetch_VER\n",
      "\n\n";
  }
  print "Done... <enter> to exit\n"; <>;
}

=head1 NAME

csavfetch.pl

=head1 SYNOPSIS

csavfetch.pl<enter>

Before running this program for the first time, you should
check its config parameters and edit as necessary.

=head1 DESCRIPTION

Checks Command Antivirus website for updated virus
definition file, and fetches if newer than local copy.
Then inflates the self-extracting executable to a 'ms patch'
file named for it's release date.  This msp file is copied
to 'latest.msp' which can be run (outside this program) to
update client PCs.

=head1 ARGUMENTS

 --help  print Options and Arguments instead of fetching CSAV update
 --man   print complete man page instead of fetching CSAV update

=head1 OPTIONS

 --versions   print Modules+Perl+OS+Program info after program run

=head1 AUTHOR

ybiC

=head1 CREDITS

Phat props to some guy named vroom

=head1 TESTED

 LWP::UserAgent        2.003
 File::Copy            2.05
 File::Basename        2.71
 Pod::Usage            1.14
 Getopt::Long          2.32
 strict                1.02
 warnings              1.00
 Perl                  5.008
 OS                    WinXPpro, Win98se


=head1 BUGS

None that I know of

=head1 TODO

 Test on WinNT
 Consolidate filename/date validation

=head1 UPDATES

 2003-07-23   08:20 CST
   Podify, Manulate, Helpify, Versionalize
   Post to Perlmonks Code Catacombs

 2003-07-19
   Initial working code

=cut