#!/usr/local/bin/perl -w

# Fetch patches from Sun's public patch server. This is pretty much
# duplicating a lot of the work done by other scripts, but heck, I
# didn't know about them at the time. Sun's own tool is next to
# useless if you don't have a Sunsolve login.
#
# Waider 1998ish
use Net::FTP;
use POSIX; # for uname

$ftp = undef;

# You may wish to edit these
$PATCHHOST='sunsolve.sun.co.uk';
$PATCHDIR='/pub/patches';
$SHOWREV='/usr/bin/showrev -p';

# Check OS version
$os = (uname)[0];
$osver = (uname)[2];

# Gah. SunOS $osver is 5.x instead of Solaris' 2.x. I guess subtract 3...
$osver = $osver - 3 if ( $os eq 'SunOS' );

$RECOMMENDED=$osver.'_Recommended.README';

$|=1;

print "Fetching $RECOMMENDED from Sun...";
maybe_fetch_file( $RECOMMENDED );
print "done.\n";

open( PLIST, "$SHOWREV|" ) || die $!;
open( RECOM, "<$RECOMMENDED" ) || die $!;

while( <PLIST> )
{
	(undef, $patch, undef) = split;
	($id, $rev) = split(/-/, $patch);
	$erev = $installed{ $id };
	$erev ||= '00';
	$installed{ $id } = $rev if $rev > $erev;
}
%recommended = map 
{ 
	if ( /^[0-9][0-9][0-9][0-9][0-9][0-9]\-[0-9][0-9]\s+/ )
	{
		chomp; 
		($patch, undef) = split;
		($id, $rev) = split(/-/, $patch); 
		$id => $rev ;
	}
	else
	{
		'dud' => 'dud';
	}
} <RECOM>;

close( RECOM );
close( PLIST );

%patches = map { $_ => $_ } keys %installed;
for( keys %recommended )
{
	$patches{ $_ } = $_ unless $_ =~ /dud/;
}
@patches = sort keys %patches;

print "Patch Report\nID\tInstalled\tRecommended\tAction\n";

for( @patches )
{
	$inst = $installed{ $_ };
	$rec = $recommended{ $_ };
	$inst ||= '00';
	$rec ||= '00';

	$action = ( $inst < $rec ) ? "not installed..." : "installed\n";

	printf "$_ \t%s\t\t%s\t\t%s", $inst, $rec, $action;
	if ( $action eq "not installed..." )
	{
	  while( !maybe_fetch_file( "$_-$rec.tar.Z" )) { print "."; }
	  print "d/l'd.\n";
	}
}

if ( $ftp )
{  
	$ftp->close();
}

sub maybe_fetch_file()
{
	$file = shift;

	# check for local copy of the file
	if ( -r $file )
	{
		# stat local copy, get mtime & size
		(undef, undef, undef, undef, undef, undef, undef, $locsz,
		 undef, $loctm, undef, undef, undef ) = stat( $file );
	}
	else
	{
		$locsz = 0;
		$loctm = 0;
	}

	# check if ftp connection is live, reopen if necessary
	if ( !defined( $ftp ) || !ref( $ftp ) || !$ftp->pwd )
	{
		$ftp = Net::FTP->new( $PATCHHOST, Debug=>1 );
		$ftp->login( 'anonymous', 'waider@scope.ie' );
		$ftp->cwd( $PATCHDIR );
		$ftp->pasv();
		$ftp->binary();
	}

	# FIXME check that file exists on server!

	# check mtime & size of remote copy
	$remsz = $ftp->size( $file ) or die $!;

	# if mtime of local is more recent & sizes match, return
	if ( $remsz == $locsz )
	{
		$remtm = $ftp->mdtm( $file );
		if ( $remtm <= $loctm )
		{
			return 1;
		}
	}

	# fetch file
	# try to recover from partial fetch
	if ( $locsz ) {
	  print "recovering...";
	  $ftp->get( $file, $file, $locsz ) or die $!;
	} else {
	  print "fetching...";
	  $ftp->get( $file ) or die $!;
	}

	1;
}
