#!/bin/sh
if test -n "`perl -V | grep "5\.0"`"
then
	echo -n "FATAL: You appear to have perl "
	for WORD in `perl -v | grep "^This is "`
	do  
		echo $WORD
	done | grep "5" | xargs echo -n
	echo ", but version 5.8 is required."
	exit 1
fi
exec perl -wx $0 "$@"
	if 0;
#!perl -w
#line 16

package sgisync;

###############################################################################
#
# sgisync - Automatically fetch IRIX patches from support.sgi.com
#
###############################################################################
#
# Version:		0.63
# Last updated:	03/06/2008	Stuart Shelton [SRCS]
#
# Changes:
# 0.1			Fork from nekosync
# 0.2			Sync with nekosync 1.2r21, merge with sgifetch
# 0.3			Can now actually determine download locations!
# 0.4			Download and unpack functionality added, sync
#				with nekosync 1.2r22
# 0.5			Cleanups and '--list'
# 0.51			Fix display of which package owns clashing files
# 0.6			Escape username and password strings
# 0.61			... without needing URI::Escape ;)
# 0.62			Clean up output, be more permissive with --list
# 0.63			Better perl version checking
# 0.64			Ensure that there really is data to download, rather than HTML
#

#
# Note that, unfortunately, there is no support for the version of Perl packaged
# with IRIX.
#

require 5.008008;

use strict;

#use Data::Dumper;
#use URI::Escape;

use constant VERSION => "0.64";
use constant RELEASE => "6.5.30";

use constant TRUE => 1;
use constant FALSE => 0;

my $name = 'sgisync';
my $agent = $name . "/" . VERSION;

use File::stat;
use Getopt::Long;
use IO::Handle;

use Symbol qw( qualify_to_ref gensym );


#
# Forward declarations - helps to find things ;)
#
sub ifverbose( $;$ );
sub ifnotverbose( $ );
sub ifdebug( $;$ );
sub ifnotdebug( $ );
sub getheader( $$ );
sub qopen( *;$$ );
sub readconfig( $ );
sub checkforupdate( $ );
sub dumpconfig( ;$ );
sub safemkdir( $ );
sub setupdirs( $$$ );
sub removeoldfiles( $$$\@ );
sub findorphanfiles( $\% );
sub unpackfiles( \@$$ );
sub syncdist( $$$$\% );
sub curlget( $;$$$$$ );
sub main();


my $site = 'http://files.irix-tools.homeunix.net/irix';
my $update = "_versions/$name-history";

## Variables below here can be over-ridden in the config file

my $distloc = '/usr/tmp/support.sgi.com/dist';
my $instloc = '/usr/tmp/support.sgi.com/inst';
my $oldloc  = 'old';
my $tmploc  = '/usr/tmp';

my $gnupath = '/usr/nekoware/bin';

my $release;

my ( $tar, $curl, $curlargs );

my $verbose = FALSE;
my $debug = FALSE;
my $safe = TRUE;
my $pretend = TRUE;
my $delete = FALSE;
my $extract = TRUE;
my $list = FALSE;

my $warnlevel = 5;

my $usecolour = FALSE;
my $termcolour = FALSE;

my $launchswmgr = TRUE;
my $updatecheck = TRUE;

## Do not edit below this line

my $configured = FALSE;

my $show = FALSE;

my $width = ( ( $ENV{ COLUMNS } or 80 ) - 2 );
$width = 50 if $width < 50;

my ( $reset, $bold, $nobold, $black, $red, $green, $yellow, $blue ) = ("") x 8;
my ( $bang, $dash, $dot, $eroteme, $plus, $star ) = undef;
#  ( "!",   "-",   ".",  "?",      "+",   "*" );

my $info   = "INFO:   ";
my $notice = "NOTICE: ";
my $warn   = "WARN:   ";
my $fatal  = "FATAL:  ";

my %messages;
my %errors;

my $fetch = 0;	# Index from zero ;)
my $globalcounter = 0;
my $sgiuser;
my $sgipass;


#
## Utility subroutines
#

sub ifverbose( $;$ ) {
	my ( $true, $false ) = @_;

	my $OUT;
	my $message = ( $verbose ? $true : $false );
	
	return undef unless $message;

	if( $message =~ m/^(\e\[\d+m)?\S+:\s/sm ) {
		my $colour = ( $message =~ m/^\e/ ? "" : $green );
		$message =~ s/^(.*):(\s*)(.*)$/$colour$1$reset:$2$3$reset/;
		open ( $OUT, ">&", STDERR ) or die "${fatal}Cannot dup STDERR: $!\n";
	} else {
#		chomp $message;
#		$message =~ s/^\s+// if $message !~ /^\s*$/;
#		$message = "$info$message$reset\n" if $message !~ /^\s*$/;
		open ( $OUT, ">&", STDOUT ) or die "${fatal}Cannot dup STDOUT: $!\n";
		autoflush STDOUT TRUE;
	}
	print $OUT $message;
	close( $OUT );
	return TRUE;
} # ifverbose

sub ifnotverbose( $ ) {
	return ifverbose( undef, shift );
} # ifnotverbose

sub ifdebug( $;$ ) {
	my ( $true, $false ) = @_;

	my $OUT;
	my $message = ( $debug ? $true : $false );
	
	return undef unless $message;

	if( $debug ) {
		if( $message =~ m/^(\e\[\d+m)?\S+:\s/sm ) {
			my $colour = ( $message =~ m/^\e/ ? "" : $blue );
			$message =~ s/^(.*):(\s*)(.*)$/$colour$1$reset:$2$3$reset/;
		} else {
			$message =~ s/^debug://i;
			$message =~ s/^\s+//;
			chomp $message;
			$message = "${blue}DEBUG$reset:  " . $message . "$reset\n"
				if $message !~ /^\s*$/;
		}

		open ( $OUT, ">&", STDERR ) or die "${fatal}Cannot dup STDERR: $!\n";
	} else {
		# I don't think this code-path is actually used...
		open ( $OUT, ">&", STDOUT ) or die "${fatal}Cannot dup STDOUT: $!\n";
	}
	print $OUT $message;
	close( $OUT );
	return TRUE;
} # ifdebug

sub ifnotdebug( $ ) {
	return ifdebug( undef, shift );
} # ifnotdebug

#
# Scary wrapper around open to redirect STDERR away from the console
#  - thanks, Paul! :)
#
sub qopen( *;$$ ) {
	$_[0] = gensym() unless( defined $_[0] );
	my $file = qualify_to_ref( shift, caller() );

	open( my $STDERR_SAVE, ">&", STDERR )
		or die "${fatal}Cannot dup STDERR: $!\n";
	open( STDERR, ">/dev/null" ) or die "${fatal}Cannot open /dev/null: $!\n";

	my ( $return, $bang );
	eval {
		if ( scalar @_ == 1 ) {
			$return = open( $file, shift );
		} else {
			$return = open( $file, shift, shift );
		}
		$bang = $!;
	};

	open( STDERR, ">&", $STDERR_SAVE );

	die "$@\n" if $@;

	$! = $bang;
	return $return;
} # qopen

#
# Source user variables...
#

sub readconfig( $ ) {
	my $filename = shift;
	my $File;

	return undef unless $filename;

	if( not open( $File, "<", $filename ) ) {
		ifverbose( "${warn}Cannot read from file \"$filename\": $!\n" );
	} else {
		if( wantarray ) {
			local $/ = "";
			my @list = <$File>;
			close $File;
			return @list;
		} else {
			local $/ = undef;
			my $string = <$File>;
			close $File;
			return $string;
		}
	}
} # readconfig

sub checkforupdate( $ ) {
	my $message = shift;
	my $version;

	return "Utility setup incomplete" unless defined $curl and defined $site
		and defined $update;

	my $command = join( ' ', $curl, '-A "' . $agent . '"'
		                   , '-f "' . "$site/$update" . '"', "|" );
	qopen( my $File, $command ) or return undef;
	while( <$File> ) {
		chomp;
		$version = $_;
	}
	return undef unless defined $version;

	if( VERSION eq $version ) {
		return '';
	} else {
		if( $message ) {
			print "${notice}You are using $name " . VERSION . " whilst the "
			    . "latest version is $version\n";
			print "        Please visit $site/ to download the\n";
			print "        most recent release of $name\n";
		}
		return $version;
	}
} # checkforupdate

sub dumpconfig( ;$ ) {
	my $extconf = shift;

	my $error = "$bold$red";
	my $problem = "$bold$blue";
	my $noerror = "$reset";

	my $warning = "[$error!$noerror]";
	my $marginal = "[$problem?$noerror]";
	my $okay = "   ";
	my $notfound = "${error}Not found$noerror";

	print "\nFile Locations\n";
	print "--------------\n\n";
	if( defined $extconf and -r $extconf ) {
		print "$okay Configuration file:                   = \"$extconf\"\n";
	} else {
		print "$warning Configuration file:                      "
		    . "$notfound\n";
	}
	print "" . ( ( defined $distloc and -d $distloc and -w $distloc )
	    ? "$okay " : "$warning " ) . "tardist download path:   --dist"
	    . ( defined $distloc ? "       = \"$distloc\""
	                         : "          $notfound" ) . "\n";
	print "" . ( ( defined $instloc and -d $instloc and -w $instloc )
	    ? "$okay " : "$warning " ) . "Path for unpacked files: --inst"
	    . ( defined $instloc ? "       = \"$instloc\""
	                         : "          $notfound" ) . "\n";
	print "" . ( ( defined $tmploc and -d $tmploc and -w $tmploc )
	    ? "$okay " : "$warning " ) . "Temporary Directory:     --temp"
	    . ( defined $tmploc ? "       = \"$tmploc\""
	                        : "          $notfound" ) . "\n";
	if( defined $distloc and defined $oldloc ) {
		print "" . ( ( -d "$distloc/$oldloc" and -w "$distloc/$oldloc" )
		    ? "$okay " : "$warning " )
		    . "Directory for old files: --old        = \"$oldloc\"\n";
		print "    (resolves to:                           "
		    . "\"$distloc/$oldloc\")\n";
	} else {
		print "$warning Directory for old files: --old           $notfound\n";
	}

	print "\nBinary locations\n";
	print "----------------\n\n";
	# What can we look for to try to guess whether this path is sound?
	print "" . ( ( defined $gnupath and -x "$gnupath/curl" ) ? "$okay "
	                                                         : "$warning " )
	    . "Path to GNU binaries:    --path"
	    . ( defined $gnupath ? "       = \"$gnupath\""
	                         : "          $notfound" ) . "\n";
	if( defined $tar ) {
		if( -x $tar ) {
			eval { system( "$tar --version >/dev/null 2>&1" ) };
			if( $@ or $? ) {
				print "$marginal "
				    . "tar command:             --tar        = \"$tar ...\" "
				    . "(${problem}not GNU tar$noerror)\n";
			} else {
				print "$okay "
				    . "tar command:             --tar        = \"$tar ...\"\n";
			}
		} else {
			print "$warning "
			    . "tar command:             --tar        = \"$tar ...\"\n";
		}
	} else {
		print "$warning tar command:             --tar           "
		    . "$notfound\n"
	}
	if( defined $curl ) {
		my $space = '';
		print "" . ( -x "$curl" ? "$okay " : "$warning " )
		    . "curl command:            --curl       = \"$curl ...\"\n";
	} else {
		print "$warning curl command:            --curl          "
		    . "$notfound\n";
	}

	print "\nGeneral settings\n";
	print "----------------\n\n";
	print "IRIX version:                --release    = " . ( defined( $release ) ? "\"$release\"" : "<not set>" ) . "\n";
	print "SupportFolio username:       --user       = " . ( defined( $sgiuser ) ? "\"$sgiuser\"" : "<not set>" ) . "\n";
	print "SupportFolio password:       --pass       = " . ( defined( $sgipass ) ? "<set>" : "<not set>" ) . "\n";
	print "\n";
	print "Verbose output:              --"
	    . ( $verbose ? "" : "no" ) . "verbose\n";
	print "Debug output:                --"
	    . ( $debug ? "" : "no" ) . "debug\n";
	print "Safe file handling:          --"
	    . ( $safe ? "" : "no" ) . "safe\n";
	print "Modify filesystem:           --"
	    . ( $pretend ? "" : "no" ) . "pretend\n";
	print "Delete obsolete files:       --"
	    . ( $delete ? "" : "no" ) . "delete\n";
	print "Unpack downloaded packages:  --"
	    . ( $extract ? "" : "no" ) . "extract\n";
	print "\n";
	print "Deletion warning threshold:  --warn       = \"$warnlevel\"\n";
	print "\n";
	print "Terminal width:              --width      = \""
	    . ( $width + 2 ) . "\"\n";
	print "\n";
	print "${red}C${green}o${blue}l${yellow}o${red}u${green}r$reset:"
	    . "                      --"
	    . ( $usecolour ? "" : "no" ) . "colour" . ( $usecolour ? "  " : "" );
	print "     "
	    . "(But your current terminal doesn't support colour!)" 
	    if( $usecolour and not $termcolour);
	print "\n\n";
	print "Launch swmgr on completion:  --"
	    . ( $launchswmgr ? "" : "no" ) . "swmgr\n";
	print "\n";
	print "Correctly configured:        --configured =  "
	    . ( ( not defined $configured or $configured ) ? "yes"
	                                                   : "${error}no$noerror" ) . "\n";
	print "\nVersions\n";
	print "--------\n\n";
	print "$name version:                            \"" . VERSION . "\"\n";
	if( $updatecheck ) {
		print "$name latest version:                     ";
		my $latest = checkforupdate( FALSE );
		if( defined $latest ) {
			if( $latest eq "" ) {
				print "\"" . VERSION . "\"\n";
				$latest = "yes";
			} else {
				print "\"$latest\"\n";
				$latest = "${error}no$noerror";
			}
		} else {
			print " unknown\n";
			$latest = "unknown";
		}
		print "$name is up to date:                       $latest\n";
	}
	print "Check for updates?           --update     =  "
	    . ( $updatecheck ? "yes" : "no" ) . "\n";
} # dumpconfig

sub safemkdir( $ ) {
	my $dir = shift;

	return TRUE unless defined $dir and not $dir eq "";
	return undef if $dir eq "/";

	( my $parent = $dir ) =~ s#/+#/#g;
	if( $parent =~ m#^/[^/]*$# ) {	## Fix vim syntax highlighting
		$parent = "/";
	} else {
		$parent =~ s#/[^/]+$##;		## Fix vim syntax highlighting
	}

	if( not -d $parent ) {
		my $result = safemkdir( $parent );
		if( defined $result ) {
			if( $result ) {
				# mkdir failed
				return TRUE;
			} else {
				# safe mode is on
				return FALSE;
			}
		}
	}

	if( not -d $dir ) {
		if( $safe ) {
			return FALSE;
		} else {
			return TRUE if( not mkdir( $dir ) );
		}
	}

	return undef;
} # safemkdir

sub setupdirs( $$$ ) {
	my ( $dloc, $iloc, $oloc ) = @_;

	my %dirs;
	$dirs{ "$dloc" } = "Distribution/download" if $dloc;
	$dirs{ "$iloc" } = "Installation" if $iloc;
	$dirs{ "$dloc/$oloc" } = "Backup" if $oloc;
	$dirs{ "$tmploc" } = "Temporary" if $tmploc;
	foreach my $dir ( keys( %dirs ) ) {
		my $desc = $dirs{ $dir };
		if( defined( my $error = safemkdir( "$dir" ) ) ) {
			if( $error ) {
				print STDERR "$fatal$desc directory \"$dir\" does not "
				           . "exist\n";
				die "        and cannot be created\n";
			} else {
				print STDERR "$fatal$desc directory \"$dir\" does not "
				           . "exist\n";
				die "        Safe mode enabled - not creating\n";
			}
		}
	}

	return undef;
} # setupdirs

sub removeoldfiles( $$$\@ ) {
	my ( $dloc, $oloc, $delete, $oldpackages ) = @_;

	return FALSE unless defined $dloc and -d $dloc;
	return FALSE unless -w $dloc or $pretend;
	return FALSE if defined $oloc
		and not ( -d "$dloc/$oloc" and ( -w "$dloc/$oloc" or $pretend ) );

	return undef unless defined $oloc or $delete;
	return undef unless scalar( @$oldpackages ) and not $safe;

	autoflush STDOUT TRUE;

	if( $delete ) {
		ifnotverbose( "Removing obsolete files       " );
	} else {
		ifnotverbose( "Moving obsolete files         " );
	}

	my $counter = 0;

	while( my $file = pop @$oldpackages ) {
		if( -d $file ) {
			ifverbose( "\"$file\" is a directory!\n", $bang );
			$counter++ if defined $width;
		} else {
			if( $delete ) {
				unlink( $file ) or die "${fatal}Error unlinking \"$file\": $!\n"
					unless $pretend;
			} else {
				my $dest = "$dloc";
				$dest .= "/$oloc" if $oloc;
				eval {
					0 == system( "mv -f \"$file\" \"$dest/\"" )
						or die "${fatal}Error moving $file - $!\n"
				} unless $pretend;
			}
			ifverbose( "\"$file\" " . ( $delete ? "removed" : "moved" ) . "\n"
			         , $dot );
			$counter++ if defined $width;
		}
		if( defined $width && not $verbose ) {
			if( ( $counter + 30 ) > $width ) {
				$counter = 0;
				print "\n" . " " x 30;
			}
		}
	}
	ifnotverbose( "\n" );

	return undef;
} # removeoldfiles

sub findorphanfiles( $\% ) {
	my ( $iloc, $instfiles ) = @_;
	my @deletions;

	return FALSE unless defined $iloc and -d $iloc;

	ifnotverbose( "Checking for orphaned files   " );
	opendir( my $Inst, $iloc )
		or die "${fatal}Cannot opendir on \"$iloc\": $!\n";
	my @files = readdir( $Inst );

	my $counter = 0;

	while( my $file = pop @files ) {
		next if -d "$iloc/$file";
		next if $file =~ /^.(.)?$/;
		if( not exists $instfiles -> { $file } ) {
			push( @deletions, "$iloc/$file" );
			ifverbose( "$file doesn't belong to any current package\n", $dash );
			$counter++ if defined $width;
		}
		if( defined $width && not $verbose ) {
			if( ( $counter + 30 ) > $width ) {
				$counter = 0;
				print "\n" . " " x 30;
			}
		}
	}
	closedir( $Inst );
	ifnotverbose( "\n" );

	return removeoldfiles( $iloc, undef, TRUE, @deletions );
} # findorphanfiles

sub unpackfiles( \@$$ ) {
	my ( $files, $dloc, $iloc ) = @_;
	my %instfiles;
	my $lastname;

	return FALSE unless scalar( @$files );
	return FALSE unless defined $dloc and -d $dloc;
	return FALSE unless defined $iloc and -d $iloc;
	return FALSE unless -w $iloc or $pretend;

	ifnotverbose( "Unpacking updated files       " );
	ifdebug( "\n" );

	my $counter = 0;
	my $continue = TRUE;

	foreach my $file ( @$files ) {
		my ( $name ) = ( $file =~ m/^(.*)\.tardist$/ );

		my $replace = FALSE;
		my $state;

		ifverbose( "Processing " . $name . " ...\n" );
		my $command = join( ' ', $tar, "-tvf", '"' . "$dloc/$file" . '"', "|" );
		qopen( my $File, $command )
			or die "${fatal}Cannot open pipe to $tar: $!\n";
		while( <$File> ) {
			my @fields = split( /\s+/ );
			if( 6 == scalar @fields or 8 == scalar @fields ) {
				my $filename;
				if( 6 == scalar @fields ) {
					( $filename = $fields[ 5 ] ) =~ s#^\./##;
				} elsif ( 8 == scalar @fields ) {
					( $filename = $fields[ 7 ] ) =~ s#^\./##;
				} else {
					die "${fatal}Invalid output read from $tar\n";
				}
				# tardists include an empty directory entry...
				next if not $filename;

				if( exists $instfiles{ $filename } ) {
					$messages{ $file } = "$filename from $name clashes with "
					                   . "files from another\n\tpackage"
					                   . ( defined $lastname
					                     ? " (probably $lastname)" : "" );
				} else {
					# Change of logic here - only a few files should have a
					# chance of clashing, so only remember tardists with one
					# of these...
					$lastname = $name if $filename =~ m/swmgr\.README/i or not defined $lastname;
					my $size = $fields[ 2 ];
					$instfiles{ $filename } = $size;
					if( scalar( my $result = stat( "$iloc/$filename" ) ) ) {
						my $fsize = $result -> size;
						if( not ( $size eq $fsize ) ) {
							$replace = TRUE;
							ifdebug( "$yellow$iloc/$filename from $name has "
							       . "changed from $size to $fsize" );
						}
					} else {
						$replace = TRUE;
						ifdebug( "${red}stat() failed on $iloc/$filename" );
					}
				}
				if( $replace ) {
					my $command;
					eval { system( "$tar --version >/dev/null 2>&1" ) };
					if( $@ or $? ) {
						# Assume SGI tar
						$command = join( ' ', 'cd "' . "$iloc" . '" &&'
						                    , $tar, '-xf'
						                    , '"' . "$dloc/$file" . '"'
						                    , '>/dev/null 2>&1' 
						                    , ';', 'cd -'
						                    , '>/dev/null 2>&1' );
					} else {
						# Assume GNU tar
						$command = join( ' ', $tar, '-xf'
						                    , '"' . "$dloc/$file" . '"'
						                    , '-C' , $iloc
						                    , '>/dev/null 2>&1' );
					}
					ifdebug( "$green\$command is \"$command\"" )
						if defined $command;
					if( not $pretend  and defined $command ) {
						ifverbose( "Unpacking $file\n" );
						eval { system( $command ) };
						if( $@ or $? ) {
							$errors{ $file } = "$file is corrupt and cannot be "
							                 . "unpacked";
							ifverbose( "\n${warn}Unable to unpack "
							         . "$file: $@ ($?)\n" );
							$state = '!';
						} else {
							ifverbose( "Unpacked $name successfully\n" );
							$state = '+' if not defined $state or
							             ( defined $state and $state eq '.' );
						}
					}
				} else {
					ifverbose( "$filename from $file unchanged\n" );
					$state = '.' if not defined $state;
				}
			} else {
				ifdebug( "${red}Unknown format returned from "
				       . "$tar: \"$reset@fields$red\"" );
				ifverbose( "${warn}Archive listing failed: $@\n" );
				$state = '!';
				$continue = FALSE;
			}
		}
		if( defined $state and $state eq '.' ) {
			ifnotverbose( $dot );
		} elsif( defined $state and $state eq '+' ) {
			ifnotverbose( $plus );
		} elsif( not defined $state or $state eq '!' ) {
			ifnotverbose( $bang );
		} else {
			ifnotverbose( $eroteme );
		}
		$counter++ if defined $width;
		if( defined $width && not $verbose ) {
			if( ( $counter + 30 ) > $width ) {
				$counter = 0;
				print "\n" . " " x 30;
			}
		}
	}

	print STDOUT "\n";

	if( $continue ) {
		return findorphanfiles( $iloc, %instfiles );
	} else {
		return undef;
	}
} # unpackfiles

sub syncdist( $$$$\% ) {
	my ( $dloc, $iloc, $oloc, $delete, $patches ) = @_;
	my @downloads;
	my @oldpackages;
	my $counter = 0;
	my $checksum;

	return FALSE unless defined $dloc;
	return FALSE unless -d $dloc and -w $dloc;
	return FALSE unless $patches;
	return FALSE unless defined $curl and -x $curl;


	autoflush STDOUT TRUE;

	my $contents = undef;
	my $File;

	my $uptodate = 0;

	chdir $dloc or die "${fatal}Cannot chdir to \"$dloc\"\n";
	ifnotverbose( "\nChecking for updated files   " );
	print "\n" if $debug;
	foreach my $patch ( sort( keys( %$patches ) ) ) {
		my $download = $patches -> { $patch }{ 'download' };
		( my $file = $download ) =~ s!^.*/([^/]+)$!$1!;		#!# Fix highlighting
		$patches -> { $patch }{ 'file' } = $file;

		if( curlget( $download, undef, $fetch++, "--head", TRUE ) =~
		    m/\r\nContent-Length:\s+(\d+)\r\n/is ) {
			$patches -> { $patch }{ 'size' } = $1;
		} else {
			ifdebug( "Could not retrieve size for $file from server: removing "
			       . "patch $patch" );
			delete $patches -> { $patch };
			next;
		}
		ifdebug( "Found size " . $patches -> { $patch }{ 'size' }
		       . " for $file\n" );

		ifdebug( "Looking for " . $file . "\n" );
		if( -r $file ) {
			open( my $File, "<", $file )
				or die "${fatal}Cannot open $file: $!\n";
			my $result = stat( $file )
				or die "stat() failed on $dloc/$file\n";
			my $size = $result -> size;
			if( $size eq $patches -> { $patch }{ 'size' } ) {
				ifverbose( "$file is of correct size\n",
				         ( $debug ? undef : $dot ) );
				$uptodate++;
				$counter++ if defined $width;
			} else {
				ifverbose( "$file: File size $size does not match server "
				         . "file length " . $patches -> { $patch }{ 'size' }
				         . "\n", $star );
				push( @downloads, $download );
				$counter++ if defined $width;
			}
		} else {
			push( @downloads, $download );
			ifverbose( $file . ": Does not exist on local filesystem\n"
			         , $plus );
			$counter++ if defined $width;
		}
		if( defined $width && not $verbose ) {
			if( ( $counter + 30 ) > $width ) {
				$counter = 0;
				print "\n" . " " x 30;
			}
		}
	}

	opendir( my $Dist, $dloc ) or die "${fatal}Cannot opendir on $dloc: $!\n";
	{
		my @files = readdir( $Dist );
		while( my $file = pop @files ) {
			next if -d "$dloc/$file";
			next unless $file =~ /\.tardist$/;

			( my $patch = $file ) =~ s/[^\d]//g;
			$patch =~ s/^0+//g;
			if( not( exists $patches -> { $patch } ) ) {
				push( @oldpackages, "$dloc/$file" );
				ifverbose( "${notice}$file removed from remote "
				         . "archive\n", $dash );
				$counter++ if defined $width;
			}
			if( defined $width && not $verbose ) {
				if( ( $counter + 30 ) > $width ) {
					$counter = 0;
					print "\n" . " " x 30;
				}
			}
		}
		closedir( $Dist );
	}

	my $number = scalar( @downloads );
	my $spaces = length( $number );

	ifnotverbose( "\n" );
	print "\n" . $uptodate . " file" . ( 1 == $uptodate ? " is"
	                                                    : "s are" )
	     . " up to date, " . scalar( @oldpackages) . " file"
	     . ( 1 == scalar( @oldpackages ) ? " is" : "s are" )
	     . " obsolete and $number " . ( 1 == $number ? "file is"
	                                                 : "files are" )
	     . " new or ha" . ( 1 == $number ? "s" : "ve" ) . "\nbeen "
	     . "modified\n\n";


	if( scalar( @oldpackages ) >= $warnlevel ) {
		print STDERR "\n${warn}More than $warnlevel packages will be "
		           . "removed!\n";
		print STDOUT "        Press ctrl+c now to cancel\n\n";
		sleep( 5 );
	}

	@downloads = sort( @downloads );
	$number = 0;

	if( @downloads ) {
		print "Downloading IRIX $release patches ... "
			. ( ( not $debug and not $verbose ) ? "|" : " " )
			if not $debug and not $verbose;
		while( my $download = pop @downloads ) {
			( my $file = $download ) =~ s!^.*/([^/]+)$!$1!; #!# Fix highlighting
			open( my $OutFile, ">", $dloc . "/" . $file )
				or die "${fatal}Cannot open $file for writing: $!\n";
			print $OutFile curlget( $download, undef, $number++, undef
				                  , FALSE, 10 );
			close( $OutFile );
		}
		print "\bdone\n\n" if not $verbose;
	}

	my @files;
	foreach my $patch ( sort( keys( %$patches ) ) ) {
		push @files, $patches -> { $patch }{ 'file' };
	}
	unpackfiles( @files, $dloc, $iloc ) if defined $iloc and $extract;
	removeoldfiles( $dloc, $oloc, $delete, @oldpackages );
	return undef;
} # syncdist

sub curlget( $;$$$$$ ) {
	my ( $page, $form, $number, $options, $quiet, $speed ) = @_;
	my $modulus = 1;
	my $output = '';

	autoflush STDOUT TRUE;

	$modulus = $speed if defined $speed;
	$quiet = FALSE if not defined $quiet;

	my $args = ( defined $options ? join( ' ', $options, $curlargs )
	                              : $curlargs );
	my $command = join( ' ', $curl, '-A "' . $agent . '"', $args,
	                    ( defined $form ? '-d "' . $form . '"'
	                                    : ''
	                    ), '--location "' . $page . '"', "|" );
	( my $displaypage = $page ) =~ s/\?.*$//;
	if( not $quiet ) {
		if( $verbose ) {
			print "(" . ( $number < 100 ? " " : "" )
			          . ( $number <  10 ? " " : "" )
			          . $number . ") $displaypage ... "
			    . ( ( not $quiet and not $debug ) ? "|" : " " );
			print "\n" if $debug;
		}
		ifdebug( "Running \"$command\"" );
	}
	qopen( my $InFile, $command )
	    or die "${fatal}Cannot open pipe to $curl: $!\n";
	my $counter = $verbose ? 0 : $globalcounter;
	my $iteration = 0;
	my @characters = ( '/', '-', '\\', '|' );
	my $size = scalar( @characters );
	while( my $data = <$InFile> ) {
		if( not $quiet and not $debug and 0 eq ( $iteration++ % $modulus ) ) {
			print "\b" . $characters[ $counter++ % $size ];
		}
		$output .= "$data";
	}
	$globalcounter = $counter % $size if not $verbose;
	if( close( $InFile ) ) {
		print "\bdone\n" if not $quiet and not $debug and $verbose;
		return $output;
	} else {
		ifnotverbose( "\b\n" ) if not $quiet;
		print STDERR "$warn$curl returned $? - Bad path or "
		           . "corrupt download?\n";
		return undef;
	}
} # curlget

sub main() {
	our ( $opt_version, $opt_help, $opt_colour, $opt_show, $opt_configured
	    , $opt_pretend, $opt_width, $opt_check, $opt_extract, $opt_release );

	sub showconfig( $;$$ ) {
		my ( $optionname, $configfile, $configname ) = @_;

		my $usenext = FALSE;
		my $showconfig = FALSE;

		# The former makes more sense, the latter is correct for this usage ;)
		#$configname = $optionname if not defined $configname;
		$configname = ( defined $configfile ? $configfile : $optionname )
			if not defined $configname;

		foreach my $option ( @ARGV ) {
			if( not $usenext ) {
				if( $option =~ m/^--show=\S+|^--showconfig=\S+/i ) {
					( my $argument = $option ) =~ s/^.*=//;
					$showconfig = TRUE if $argument =~ m/^$optionname$/i;
				} elsif( $option =~ m/^--show$|^--showconfig$/i ) {
					$usenext = TRUE;
				}
			} else {
				$showconfig = TRUE if $option =~ m/^$optionname$/i;
			}
			if( $showconfig and defined $configfile ) {
				if( -r $configfile ) {
					print "$name " . VERSION . " $configname values:\n";
					dumpconfig( $configfile );
					exit 0;
				} else {
					die "No configuration file found\n";
				}
			} elsif( $showconfig ) {
				print "$name " . VERSION . " $configname values:\n";
				dumpconfig();
				exit 0;
			}
		}
	}

	showconfig( "default(s)?", undef, "default" );

	my $extconf;
	$extconf = "/usr/nekoware/etc/$name.conf"
		if -r "/usr/nekoware/etc/$name.conf";
	$extconf = $ENV{ HOME } . "/.$name.conf"
		if -r $ENV{ HOME } . "/.$name.conf";
	$extconf = "/etc/$name.conf" unless defined $extconf;

	if( -r $extconf ) {
		# If there's a config file, it either sets $configured, or has been
		# edited...
		$configured = undef;
		eval readconfig( $extconf );
	}

	showconfig( "file", $extconf );

	Getopt::Long::Configure( "posix_default", "bundling", "gnu_compat" );
	GetOptions(
		  'check|checkonly!'
		, 'colour|color!'
		, 'configured|config!'
		, 'curl=s' =>				\$curl
		, 'debug!' =>				\$debug
		, 'delete|del!' =>			\$delete
		, 'distloc|dist|d=s' =>		\$distloc
		, 'extract|unpack!'
		, 'gnupath|gnu|path|g=s' =>	\$gnupath
		, 'help|h'
		, 'instloc|inst|i=s' =>		\$instloc
		, 'list|l!' =>				\$list
		, 'oldloc|old|o=s' =>		\$oldloc
		, 'password|pass=s' =>	\$sgipass
		, 'pretend|p!'
		, 'release|r=s'
		, 'safe!' =>				\$safe
		, 'show|showconfig:s'
		, 'swmgr|launch|s!' =>		\$launchswmgr
		, 'tar=s' =>				\$tar
		, 'tmploc|tmp|temp|t=s' =>	\$tmploc
		, 'update!' =>				\$updatecheck
		, 'user=s' =>				\$sgiuser
		, 'verbose!' =>				\$verbose
		, 'version|v'
		, 'warn|w=i' =>				\$warnlevel
		, 'width|columns=i'
	) or die "\n";

	if( defined $opt_version and $opt_version ) {
		print "$name version " . VERSION . "\n";
		exit 0;
	}
	if( defined $opt_help and $opt_help ) {
		print "Usage: $name [--user=<username>] [--pass=<password>] [settings] [options]\n\n";
		print "                 settings = { [--dist=<path>] [--inst=<path>] [--temp=<path>]\n";
		print "                              [--old=<directory>]\n";
		print "                              [--release=<IRIX release>]\n";
		print "                              [--path=<path>] [--tar=<path>] [--curl=<path>]\n";
		print "                              [--warn=<number>] [--width=<number>]\n";
		print "                            }\n";
		print "                 options  = { [--colour] [--configured] [--debug]\n";
		print "                              [--delete] [--extract] [--list] [--pretend]\n";
		print "                              [--safe] [--showconfig[=default|=file|=actual]]\n";
		print "                              [--swmgr] [--update] [--verbose]\n";
		print "                            }\n";
		print "\n";
		print "                 Note: --debug implies --pretend, use --nopretend to override.\n";
		exit 0;
	}

	if( not defined $sgiuser or not defined $sgipass ) {
		die "${fatal}A username and password must be supplied!\n";
	}

	if( not defined $opt_colour or ( defined $opt_colour and $opt_colour ) ) {
		$usecolour = TRUE;

		if( defined( $ENV{ TERM } ) and $ENV{ TERM } =~ /xterm|screen/ ) {
			$termcolour = TRUE;
			$reset = "\e[0m";
			$bold = "\e[1m";
			$nobold = "\e[22m";
			$black = "\e[30m";
			$red = "\e[31m";
			$green = "\e[32m";
			$yellow = "\e[33m";
			$blue = "\e[34m";
		} else {
			$termcolour = FALSE;
		}

		$info = "${green}INFO$reset:   ";
		$notice = "${blue}NOTICE$reset: ";
		$warn = "${red}WARN$reset:   ";
		$fatal = "$bold${red}FATAL$reset:  ";

		$bang = "$red!" if not defined $bang;
		$dash = "$yellow-" if not defined $dash;
		$dot = "$blue." if not defined $dot;
		$eroteme = "$yellow?" if not defined $eroteme;
		$plus = "$green+" if not defined $plus;
		$star = "$green*" if not defined $star;
	}
	$bang    = "!" if not defined $bang;
	$dash    = "-" if not defined $dash;
	$dot     = "." if not defined $dot;
	$eroteme = "?" if not defined $eroteme;
	$plus    = "+" if not defined $plus;
	$star    = "*" if not defined $star;

	# We can't use $reset here, because the '[' needs escaping :(
	$bang    = "$bang$reset"    if $bang    !~ m/\e\[0m$/;
	$dash    = "$dash$reset"    if $dash    !~ m/\e\[0m$/;
	$dot     = "$dot$reset"     if $dot     !~ m/\e\[0m$/;
	$eroteme = "$eroteme$reset" if $eroteme !~ m/\e\[0m$/;
	$plus    = "$plus$reset"    if $plus    !~ m/\e\[0m$/;
	$star    = "$star$reset"    if $star    !~ m/\e\[0m$/;

	if( defined $opt_pretend and not $opt_pretend ) {
		$pretend = FALSE;
	}
	if( defined $opt_configured and $opt_configured ) {
		$configured = TRUE;
	}
	if( defined $opt_extract ) {
		$extract = $opt_extract;
	}
	if( defined $opt_width ) {
		$width = int( $opt_width ) - 2;
	}

	if( not defined $release ) {
		if( not defined $opt_release ) {
			if( $opt_release = `/sbin/uname -R` ) {
				$opt_release =~ s/^.* //;
				chomp $opt_release;
			} else {
				print STDERR "${warn}IRIX release not defined - defaulting to "
				           . RELEASE . "\n";
				$opt_release = RELEASE;
			}
		}
	} else {
		$opt_release = $release;
	}
	$opt_release =~ s/\.0$// if defined $opt_release;
	if( defined $opt_release and
	    $opt_release =~ m/^([5,6]\.[1-5])\.?([1-9][0-9]?)?([mf])?$/ ) {
		my $major = $1 if defined $1;
		my $minor = $2 if defined $2;
		my $stream = $3 if defined $3;

		if( defined $major ) {
			if( defined $minor and "6.5" eq $major and
			    ( $minor > 1 and $minor < 22 ) and not defined $stream ) {
				print STDERR "${warn}IRIX releases from 6.5.2 to 6.5.21 "
				           . "require a feature stream\n";
				$opt_release = "${major}.${minor}m";
			}
		} else {
			$release = $opt_release if not defined $release;
			undef $opt_release;
		}

		$opt_release =~ s/[mf]$// if defined $major and defined $minor and
		    "6.5" eq $major and ( $minor < 2 or $minor > 21 );
	} else {
		$release = $opt_release if not defined $release;
		undef $opt_release;
	}
	if( not defined $opt_release ) {
		print "${warn}Unrecognised IRIX release \"$release\"\n"
		    if defined $release;
		$opt_release = RELEASE;
	}
	$release = $opt_release;
	if( not $list and not ( defined $opt_check and $opt_check ) ) {
		print STDERR "\n";
		print STDERR "${info}Using IRIX release $release\n\n";
	}

	if( defined $gnupath and -d $gnupath and -x "$gnupath/bash" ) {
		eval { chomp( $curl = `$gnupath/bash -c "type -pf $gnupath/curl"` ) }
			if( not defined $curl or not -x $curl );
		eval { chomp( $tar = `$gnupath/bash -c "type -pf $gnupath/tar"` ) }
			if( not defined $tar or not -x $tar );
	}
	eval { chomp( $tar = `bash -c "type -pf tar"` ) }
		if( not defined $tar or not -x $tar );
	eval { chomp( $curl = `bash -c "type -pf curl"` ) }
		if( not defined $curl or not -x $curl );

	$tar = undef unless -x $tar;
	$curl = undef unless -x $curl;

	if( defined $opt_check and $opt_check ) {
		ifverbose( "Checking version information...\n" );
		my $latest = checkforupdate( TRUE );
		if( defined $latest ) {
			print "$name " . VERSION . " is up to date\n" if $latest eq "";
			exit 0;
		} else {
			print STDERR "Cannot download version information from\n"
			           . "$site/$update\n";
			exit 1;
		}
	}

	if( defined $opt_show ) {
		if( $opt_show eq "default" or $opt_show eq "file" ) {
			die "${fatal}Uncaught show option: $opt_show\n";
		} elsif( $opt_show eq "" or $opt_show eq "actual" ) {
			print "$name " . VERSION . " actual values:\n";
			dumpconfig( $extconf );
			exit 0;
		} else {
			die "${fatal}Unknown argument: $opt_show\n";
		}
	}

	if( not -r $extconf ) {
		print STDERR "${notice}No external configuration file found, using "
		           . ( ( not $configured ) ? "defaults..."
		                                   : "only command line options..." )
		           . "\n\n";
	}

	die "$name has not yet been configured - please edit\n  $extconf and "
	  . "ensure that sane defaults are set before\n  re-running.\n"
		if defined( $configured ) and ( not $configured ) and ( not $show );

	die "${fatal}Working directories not set\n"
		unless defined $distloc and defined $instloc;
	die "${fatal}Cannot find working \'tar\' binary\n"
		unless defined $tar and -x $tar;
	die "${fatal}Cannot find working \'curl\' binary\n"
		unless defined $curl and -x $curl;

	$width = undef if $debug;

	if( $updatecheck ) {
		ifverbose( "Checking version information...\n" );
		my $latest = checkforupdate( TRUE );
		if( defined $latest ) {
			print "\n" unless $latest eq "";
		} else {
			if( defined $site and defined $update ) {
				print STDERR "${warn}Cannot download version information from\n"
				    . "        $site/$update\n\n";
			} else {
				print STDERR "${warn}Cannot download version information\n";
			}
		}
	}

	my $escape = sub {
		my( $string ) = @_; 
		$string =~ s/([^a-zA-Z0-9_\-. ])/uc sprintf( "%%%02x", ord( $1 ) )/eg; 
		# Convert spaces to plus symbols...
		$string =~ tr/ /+/;
		return $string; 
	};

	eval "use URI::Escape;";
	if( $@ ) {
		ifdebug( "URI::Escape not found - using internal routine\n" );
	} else {
		$escape = \&uri_escape;
	}

	my $document = undef;
	my $seenlicense = FALSE;

	$curlargs = "--insecure --compressed --cookie-jar '$tmploc/.$name.cookies' "
	          . "--cookie '$tmploc/.$name.cookies'";

	my $host = "support.sgi.com";
	my $path = "login";
	my $page = 'http://support.sgi.com/';
	my $form = undef;

	if( not $list ) {
		setupdirs( $distloc, $instloc, $oldloc );
		die "${fatal}No write access to \"$distloc\"\n"
			unless -d $distloc and -w $distloc;
		die "${fatal}No write access to \"$instloc\"\n"
			unless -d $instloc and -w $instloc;
		die "${fatal}No write access to \"$distloc/$oldloc\"\n" if not $delete
			and ( not -d "$distloc/$oldloc" or not -w "$distloc/$oldloc/" );
	}

#	return FALSE unless -d $dloc and -w $dloc;
	print "Fetching data from support.sgi.com, please wait ... "
	            . ( ( not $debug and not $verbose ) ? "|" : " " )
		if not $debug and not $verbose;

#	if( $debug and $verbose ) {
#		print curlget( $page, $form, $fetch++ );
#	} else {
		die "Page fetch error\n"
		    if not defined curlget( $page, $form, $fetch++ );
#	}

	$page = 'https://support.sgi.com/login';
	$form = "PAGE_NAME=LOGIN&ORIGINAL_URL=%2F&ORIGINAL_QUERY=&USER_ID=" . $escape -> ( $sgiuser ) . "&PASSWORD=" . $escape -> ( $sgipass ) . "&Sign+In.x=0&Sign+In.y=0";
	print "      Logging in with username $sgiuser, password $sgipass ...\n"
		if defined $sgiuser and defined $sgipass and $verbose and not $debug;
	ifdebug( "form data is \"$form\"" );
	if( $debug and $verbose ) {
		print curlget( $page, $form, $fetch++ );
	} else {
		die "Page fetch error\n"
		    if not defined curlget( $page, $form, $fetch++ );
	}

	$page = "https://support.sgi.com/browse_request/irix_patches_by_os";
	$form = "PAGE_LIST_SIZE=-1";
	
	$document = curlget( $page, $form, $fetch++ );
#	if( $debug and $verbose and defined $document ) {
#		print $document;
#	} else {
		die "Page fetch error\n" if not defined $document;
#	}
	if( $debug or $list or $document !~ m/$release/i ) {
		print "\berror\n" if $document !~ m/$release/i;
		print "\bdone\n" if $list and not $verbose;
		print "\n" if $list;
		my $releaseokay = FALSE;
		my @document = split( /\n/, $document );
		print "Available IRIX releases:\n" if $list;
		my $counter = 1;
		foreach my $line ( grep( m!<td align="left" >IRIX ([0-9.mf]+)</td>!g,
		                         @document ) ) {
			my $version = $1
			    if $line =~ m!<td align="left" >IRIX ([0-9.mf]*)</td>!i;
			ifverbose( "${info}Found IRIX release " . $version . "\n",
			    ( $list ? $version . ( $counter++ % 4 ? "\t"
			                                          : "\n" )
			            : undef ) ) if defined $version;
			$releaseokay = TRUE if $version eq $release;
		}
		if( $list ) {
			print "\n" if not $verbose;
			print "\n${warn}IRIX release $release not found\n"
				if not $releaseokay;
			exit 0;
		}
		die "${fatal}IRIX release $release not found\n" if not $releaseokay;
	}
	ifverbose( "${notice}IRIX release $release found...\n" );

	$page = "https://support.sgi.com/browse_request/irix_patch_browse_results"
	      . "?OPERATING_SYSTEM=IRIX+$release";
	$form = "PAGE_LIST_SIZE=-1";
	$document = curlget( $page, $form, $fetch++ );
#	if( $debug and $verbose and defined $document ) {
#		print $document;
#	} else {
		die "Page fetch error\n" if not defined $document;
#	}
	my %patches;
	{
		$document =~ s/^.*<!-- END LEFT NAV -->[^\n]*\n//s;
		$document =~ s/<!-- Start Paging Footer -->.*$//s;

		my @document = split( /<tr valign="top"  /, $document );
		my $count = 0;

		foreach my $section ( @document ) {
			my ( $patch, $description, $date, $download );
			if( $section =~ m!<td class="small"><span class="">IRIX Patch ([0-9]+): (.*)</span></td>! ) {
				$patch = $1 if defined $1;
				$description = $2 if defined $2;
			}
			if( $section =~ m!<td class="small" align="center">(\d{2}-...-\d{4})</td>! ) {
				$date = $1 if defined $1;
			}
			if( $section =~ m!<a  class="boldlink" href="javascript:contentpopup\('([^']+)'\)"! ) {
				$download = $1 if defined $1;
			}
			if( $section =~ m!<img src="/media/images/common/html_doc.gif"! ) {
				ifverbose( "${warn}Patch $patch has HTML content-type - ignoring\n" );
				$errors{ $patch } = "Patch $patch will not be downloaded as it is flagged as HTML";
				undef $description;
				undef $date;
				undef $download;
			}
			if( defined $patch and defined $description and
			    defined $date and defined $download ) {
				$patches{ $patch }{ 'description' } = $description;
				$patches{ $patch }{ 'date' } = $date;
				$patches{ $patch }{ 'download' } = $download;
				$count++;
			}
		}
		die "${fatal}No patches found for IRIX release $release :(\n"
		    if 0 == $count;
	}
	if( $debug ) {
		foreach my $patch ( keys %patches ) {
			ifdebug( "Patch $patch has download location "
			       . $patches{ $patch }{ 'download' } );
		}
	}
	foreach my $patch ( keys %patches ) {
		my ( $tardist, $action, $cmd, $location );
		$page = "https://support.sgi.com" . $patches{ $patch }{ 'download' };
		$document = curlget( $page, undef, $fetch++ );
#		if( $debug and $verbose and defined $document ) {
#			print $document;
#		} else {
			die "Page fetch error\n" if not defined $document;
#		}
		foreach my $line ( grep( m!<td><a href="terms_conditions\?.*">HTTP</a></td>!g, split( /\n/, $document ) ) ) {
			$line =~ m!<td><a href="(terms_conditions\?srv=download.sgi.com&amp;pro=http&amp;cmd=\w+)">HTTP</a></td>!;
			$tardist = $1 if defined $1;
		}
		if( defined $tardist )  {
			$page =~ s!/[^/]+$!/$tardist!; #!# Fix hilighting
			$document = curlget( $page, undef, $fetch++ );
		} else {
			die "\nCannot find tardist in document \"$page\"\n";
		}
#		if( $debug and $verbose and defined $document ) {
#			print $document;
#		} else {
			die "Page fetch error\n" if not defined $document;
#		}
		if( not $seenlicense and
		    $document =~ m!^.*<textarea[^>]+>(.*)</textarea>!s ) {
			print "\bdone\n" if not $debug and not $verbose;
			print "\n$1\n\n";
			$seenlicense = TRUE;
			print "Continuing to fetch data from support.sgi.com"
				. ", please wait ... " . ( $debug ? "\n" : "|" )
				if not $verbose;
		}

		$document =~ s/^.*<form method="POST"\n/<form method="POST" /s;
		if( $document =~ m!action="([^"]+)">!s ) {
			$action = $1 if defined $1;
		}
		if( $document =~ m!name="cmd:string"\s*value="([^"]+)" />!s ) {
			$cmd = $1 if defined $1;
		}
		if( defined $action and defined $cmd ) {
			$page = "https://support.sgi.com" . $action;
			$form = "cmd:string=$cmd&srv:string=download.sgi.com&"
			      . "pro:string=http&agree:string=I%20Agree";
			$document = curlget( $page, $form, $fetch++ );
#			if( $debug and $verbose and defined $document ) {
#				print $document;
#			} else {
				die "Page fetch error\n" if not defined $document;
#			}
			if( $document =~ m!<meta http-equiv="Refresh" content="\d+; URL=([^"]+)">! ) {
				$location = $1 if defined $1;

				if ( defined $location ) {
					ifdebug( "Found download location \"$location\" for "
					       . "patch $patch" );
					$patches{ $patch }{ 'download' } = $location;
				} else {
					ifdebug( "Removing patch $patch - cannot discover "
					       . "download location" );
					delete $patches{ $patch };
				}
			}
		}
	}

	# Close message from main() - this is messy :(
	print "\bdone\n" if not $debug and not $verbose;

	syncdist( $distloc, $instloc, $oldloc, $delete, %patches );

#	print STDERR "\n" if( %messages );
#	foreach my $message ( sort( values( %messages ) ) ) {
#		print STDERR "$info$message\n";
#	}
#	print STDERR "\n" if( %messages );
#	print STDERR "\n" if( %errors and not %messages );
#	foreach my $message ( sort( values( %errors ) ) ) {
#		print STDERR "$warn$message\n";
#	}
#	print STDERR "\n" if( %errors );

	print STDERR "\n" if( %errors );
	foreach my $message ( sort( values( %errors ) ) ) {
		print STDERR "$warn$message\n";
	}
	print STDERR "\n" if( %errors );
	print STDERR "\n" if( %messages and not %errors );
	foreach my $message ( sort( values( %messages ) ) ) {
		print STDERR "$info$message\n";
	}
	print STDERR "\n" if( %messages );

	my $error;

	if( $launchswmgr ) {
		my $command;
		if( defined $ENV{ DISPLAY } and $ENV{ DISPLAY }
		    and -x "/usr/sbin/SoftwareManager"
		  ) {
			$command = "/usr/sbin/SoftwareManager";
			print "Launching SoftwareManager... ";
		} elsif( -x "/usr/sbin/inst" ) {
			$command = "/usr/sbin/inst";
			print "Launching inst... ";
		} else {
			print STDERR "${fatal}SoftwareManager not present or \$DISPLAY not "
			           . "set and inst not present\n";
			$error = TRUE;
		}
		if( not defined $error ) {
			$command .= " -f $instloc";
			system( $command );
		}
	}

	if( defined $error ) {
		print STDERR "\n$fatal$name encountered an error and aborted:\n";
		die "\tPlease check the output of \"$name --show\" for configuration "
		  . "problems\n";
	} else {
		print "\n$name finished at " . gmtime() . "\n";
		exit 0;
	}
} # main

main();
1;

# vi:set syntax=perl nowrap ts=4:
