#!@PERL_PATH@ -w

######################################################################
#
# EPrints 2 installer : Handles upgrading, simple command detection,
# and the creation of the SystemSettings.pm file. This doesn't do the
# mySQL install, etc. - you'll need the SuperInstaller for that.
#
######################################################################
# __LICENSE__
######################################################################

my %from_configure;
$from_configure{"dist_path"}="@DIST_PATH@";
$from_configure{"perl"}="@PERL_PATH@";
$from_configure{"prefix"}="@PREFIX@";
$from_configure{"user"}="@INSTALL_USER@";
$from_configure{"group"}="@INSTALL_GROUP@";
$from_configure{"disable_df"}=@DISABLE_DF@;
$from_configure{"virtualhost"}="@VIRTUALHOST@";

$from_configure{"unzip"}="@UNZIP_PATH@";
$from_configure{"tar"}="@TAR_PATH@";
$from_configure{"gunzip"}="@GUNZIP_PATH@";
$from_configure{"wget"}="@WGET_PATH@";
$from_configure{"sendmail"}="@SENDMAIL_PATH@";
$from_configure{"smtp_server"}="@SMTP_SERVER@";
$from_configure{"latex"}="@LATEX_PATH@";
$from_configure{"dvips"}="@DVIPS_PATH@";
$from_configure{"convert"}="@CONVERT_PATH@";

$from_configure{"enable_gdome"}="@ENABLE_GDOME@";
$from_configure{"apache"}="@APACHE@";

######################################################################

if( 
	$from_configure{"apache"} ne "" && 
	$from_configure{"apache"} ne "1" && 
	$from_configure{"apache"} ne "2" )
{
	print "Apache version must be '1' or '2'.\n";
	print "re-run configure with new options.\n";
	exit 1;
}

######################################################################

if( defined $ARGV[0] ) { print "Destination directory overridden to: $ARGV[0]\n"; }

use strict;
use Cwd;
use Digest::MD5;
use Data::Dumper;

#
# Set the umask so nothing goes odd on systems which
# change it.
#
umask( 0022 );

#
# Grab version id number from VERSION file.
#

my( $version_id, $version ) = read_version( $from_configure{"dist_path"}."/VERSION" );

### Trim perfix if needed 

if( $from_configure{"prefix"} =~ s#/$## )
{
	print "Removing trailing slash from prefix.\n";
}

### Print out some key information, which is bound to
### cause problems if incorrect.

# shorter variables for clarity later
my $from_path = $from_configure{dist_path};
my $to_path = $from_configure{prefix};
# Implement DESTDIR support for GNU compatibility.
# If an argument is specified install there instead.
if( defined $ARGV[0] ) { $to_path = $ARGV[0]; }

print "Installing from: $from_path\n";

my $system_settings_file = "$to_path/perl_lib/EPrints/SystemSettings.pm";
my $upgrade = 0;
if( -e $system_settings_file )
{
	$upgrade = 1;
	print "Previous install detected at install location.\n";
	print "Upgrading to: $to_path\n";
}
else
{
	print "Installing to: $to_path\n";
	print "Installing as user: ".$from_configure{"user"}."\n";
	print "Installing as group: ".$from_configure{"group"}."\n";
}

my $systemsettings = {};

$systemsettings->{"version_history"} = [ $version_id ];

#
# Set up some default settings.
#
$systemsettings->{"invocation"} = {
	zip     => '$(unzip) 1>/dev/null 2>&1 -qq -o -d $(DIR) $(ARC)',
	targz   => '$(gunzip) -c < $(ARC) 2>/dev/null | $(tar) xf - -C $(DIR) >/dev/null 2>&1',
	wget    => '$(wget)  -r -L -q -m -nH -np --execute="robots=off" --cut-dirs=$(CUTDIRS) $(URL)',
	sendmail => '$(sendmail) -oi -t -odb --',
	latex => '$(latex) \'$(SOURCE)\'',
	dvips => '$(dvips) \'$(SOURCE)\' -o \'$(TARGET)\'',
	convert_crop_white => '$(convert) -crop 0x0 -bordercolor white -border 4x4 \'$(SOURCE)\' \'$(TARGET)\'' 
};

$systemsettings->{"archive_extensions"} = {};
$systemsettings->{"archive_formats"} = [];
if( $from_configure{"unzip"} ne "" )
{
	$systemsettings->{"archive_extensions"}->{"zip"} = ".zip" ;
	push @{$systemsettings->{"archive_formats"}},"zip";
}
if( $from_configure{"tar"} ne "" && $from_configure{"gunzip"} ne "" )
{
	$systemsettings->{"archive_extensions"}->{"targz"} = ".tar.gz" ;
	push @{$systemsettings->{"archive_formats"}},"targz";
}

$systemsettings->{"executables"} = {};
foreach( 
	"unzip", "tar", "gunzip", "wget", 
	"sendmail", "latex", "dvips", "convert" )
{
	next unless( defined $from_configure{$_} );
	$systemsettings->{"executables"}->{$_} = $from_configure{$_};
}

$systemsettings->{"disable_df"} = $from_configure{"disable_df"};
$systemsettings->{"virtualhost"} = $from_configure{"virtualhost"};



if( $upgrade )
{
	unless( require $system_settings_file )
	{
		print <<END;
Failed to read previous values from system settings file:
$system_settings_file - Aborting.
END
		exit 1;
	}

	print "Previous version of eprints is: ";
	print $EPrints::SystemSettings::conf->{"version_id"}."\n";

	# create a minimal version history if there was not one already
	if( !defined $EPrints::SystemSettings::conf->{"version_history"} )
	{
		$EPrints::SystemSettings::conf->{"version_history"} =
			[ $EPrints::SystemSettings::conf->{"version_id"} ];
	}

	# Current values take precedence.
	foreach( keys %$EPrints::SystemSettings::conf )
	{
		if( defined $systemsettings->{$_} )
		{
			$systemsettings->{$_} = merge_fields(
				$EPrints::SystemSettings::conf->{$_}, 
				$systemsettings->{$_} );
		}
		else
		{
			$systemsettings->{$_} = 
				$EPrints::SystemSettings::conf->{$_};
		}
	}
	$systemsettings->{"user"} = $EPrints::SystemSettings::conf->{"user"};
	$systemsettings->{"group"} = $EPrints::SystemSettings::conf->{"group"};

	print "Upgrading as user: ".$systemsettings->{"user"}."\n";
	print "Upgrading as group: ".$systemsettings->{"group"}."\n";
	$upgrade = 1;
}
else
{	
	$systemsettings->{"user"} = $from_configure{"user"};
	$systemsettings->{"group"} = $from_configure{"group"};
	$systemsettings->{"base_path"} = $from_configure{"prefix"};
}

$systemsettings->{"version_id"} = $version_id;
$systemsettings->{"version"} = $version;

set( 'smtp_server', \%from_configure, $systemsettings, '' );
set( 'enable_gdome', \%from_configure, $systemsettings, 0 );
set( 'show_ids_in_log', \%from_configure, $systemsettings, 0 );
set( 'apache', \%from_configure, $systemsettings, "2" );


# Check the user exists

unless( getpwnam($systemsettings->{"user"}) )
{
	print "User ".$from_configure{"user"}." does not exist. Aborting.\n";
	exit 1;
}


# Check the group exists

unless( getgrnam($systemsettings->{"group"}) )
{
	print "Group ".$from_configure{"group"}." does not exist. Aborting.\n";
	exit 1;
}

my(undef,undef,$uid) = getpwnam($systemsettings->{"user"});
my(undef,undef,$gid) = getgrnam($systemsettings->{"group"});

my %oldhashes = ();

# If we are upgrading and have a digest file, read the digests into a hash
# to check them against the files in place to see if they've changed.

if( $upgrade )
{
	my $sigfile = "$to_path/SIGNATURES";
	if (-e $sigfile )
	{
		print "Loading SIGNATURES...\n";
		open(SIGS, $sigfile ) || die "Can't open $sigfile";
		binmode(SIGS);
		foreach(<SIGS>)
		{
			chomp;
			my( $file, $digest ) = split( " ", $_);
			$oldhashes{$file} = $digest;
		}
		close(SIGS);
	}
	else
	{
		print "Upgrading, but could not find an old SIGNATURES file.\n";
	}
}






#
# Actual install starts here.
#
ensure_dir( $to_path, $uid, $gid, 0755 );

my $newhashes = [];

my @normal_dirs = ( "defaultcfg", "cfg", "docs", "perl_lib","testdata" );

my @executable_dirs = ( "bin", "cgi", "testdata/bin" );

my @base_files = ( "VERSION", "CHANGELOG", "COPYING", "NEWS", "AUTHORS", "README" ); 

foreach my $dir (@normal_dirs)
{
	install_dir($from_path, $dir, 0644, $uid, $gid, $to_path, \%oldhashes, $newhashes);
}
foreach my $dir (@executable_dirs)
{
	install_dir($from_path, $dir, 0755, $uid, $gid, $to_path, \%oldhashes, $newhashes);
}
foreach my $file (@base_files)
{
	install_file($from_path, $file, "", 0644, $uid, $gid, $to_path, \%oldhashes, $newhashes );
}

ensure_dir( "$to_path/archives", $uid, $gid, 0755 );
ensure_dir( "$to_path/perl_lib/EPrints/LocalPlugin", $uid, $gid, 0755 );

write_sigs( $to_path, $newhashes, $uid, $gid );


save_settings( 
	$system_settings_file, 
	$systemsettings, 
	$systemsettings->{user}, 
	$systemsettings->{group} );

if( $systemsettings->{smtp_server} eq "" && !$upgrade )
{
	print <<END;

WARNING: You have not set a value for smtp_server. Edit the
SystemSettings file and set the smtp_server option to be your local 
SMTP server. If you don't then outgoing email won't work.

END
}

print "\n";

exit;











######################################################################
# 
# set( $param, $hash_from_configure, $systemsettings, $default )
# 
# Set the $param param in systemsettings to the $param passed
# in from configure.
# If nothing was passed in by configure and a value is not already
# set, then set it to the $default.
#
######################################################################

sub set
{
	my( $param, $from_configure, $systemsettings, $default ) = @_;

	if( defined $from_configure->{$param} && $from_configure->{$param} ne '' )
	{
		# a setting has actually been configured by configure
		$systemsettings->{$param} = $from_configure->{$param};
		return;
	}

	if( !defined $systemsettings->{$param} )
	{
		# no setting is defined at all, not even ""
		# so use the default
		$systemsettings->{$param} = $default;
		return;
	}

	return;
}




sub save_settings
{
	my( $sysfile, $syshash, $user, $group ) = @_;

	my(undef,undef,$uid,$gid) = getpwnam($user);

	my $dumper = Data::Dumper->new( 
		[ $syshash ] , 
		[ 'EPrints::SystemSettings::conf' ] );

	print "Writing $sysfile\n";
	unless( open(FILEOUT, ">".$sysfile) )
	{
		print "Failed to write $sysfile\n";
		exit 1;
	}
	binmode(FILEOUT);
	print FILEOUT <<SPIEL;
######################################################################
#
# These are your system settings (as autogenerated by the installer).
# We suggest that you do not alter these, as future installers will
# probably override them.
# 
######################################################################
#
# This file is part of EPrints 2.
#
# EPrints 2 is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# EPrints 2 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EPrints 2; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
######################################################################

# This file should only be use'd by EPrints::Config
package EPrints::SystemSettings;

SPIEL

	print FILEOUT $dumper->Dump();
	print FILEOUT "\n1;";
	close(FILEOUT);

	chmod( 0644, $sysfile );
	chown($uid, $gid, $sysfile );
}

sub merge_fields
{
	my($hash1, $hash2) = @_;
	my %outhash;
	my $type = ref $hash1;
	if($type eq "HASH")
	{
		# $hash1 takes precedence
		foreach(keys %$hash1)
		{
			$outhash{$_} = $hash1->{$_};
		}
		foreach(keys %$hash2)
		{
			$outhash{$_} = $hash2->{$_} unless defined $outhash{$_};
		}
		return \%outhash;
	}
	elsif($type eq "ARRAY")
	{
		if (defined $hash1)
		{
			foreach(@$hash1)
			{
				$outhash{$_} = 1 if defined $_;
			}
		}
		if (defined $hash2)
		{
			foreach(@$hash2)
			{
				$outhash{$_} = 1 if defined $_;
			}
		}
		return [keys %outhash];
	}
	else
	{
		return $hash1;
	}
	
}



#######################################

sub detect_df 
{

	my $dir = "/";
	my ($fmt, $res);

	# try with statvfs..
	eval 
	{  
		{
			package main;
			require "sys/syscall.ph";
		}
		$fmt = "\0" x 512;
		$res = syscall (&main::SYS_statvfs, $dir, $fmt) ;
		$res == 0;
	}
	# try with statfs..
	|| eval 
	{ 
		{
			package main;
			require "sys/syscall.ph";
		}	
		$fmt = "\0" x 512;
		$res = syscall (&main::SYS_statfs, $dir, $fmt);
		$res == 0;
	}
}



# Post installation bits

sub write_sigs
{
	my( $dir, $sigs, $uid, $gid ) = @_;

	my $sigfile = $dir.'/SIGNATURES';
	# Dump out signature file
	unless( open (SIGOUT, ">".$sigfile ) )
	{
		print "Unable to write $sigfile: $!\n";
		exit 1;
	}
	binmode(SIGOUT);
		
	foreach(@{$sigs})
	{
		print SIGOUT $_;
	}
	close(SIGOUT);
	chown($uid, $gid, $sigfile );
	chmod( 0644, $sigfile );
}

# Calculate the MD5 digest of a file.

sub get_digest
{
	my($file) = @_;
	unless( open(FILE, $file) )
	{
		print "Can't open '$file': $!\n";
		exit 1;
	}
	binmode(FILE);
	my $outdigest = new Digest::MD5;
	foreach(<FILE>)
	{
		$outdigest->add($_);
	}
	close(FILE);
	return $outdigest->hexdigest;
}

# Install $file from directory $dir into $dest. The permissions
# from $perms are set, and the group and user are set from $group
# and $user. The %hash is used for MD5 comparisions - currently
# not doing anything active, but checking is enabled.

sub install_file
{
	my($distdir, $file, $dir, $perms, $uid, $gid, $dest, $sighash, $newsigs ) = @_;

	return unless (-e $distdir."/$dir/$file");
	my $outdigest = Digest::MD5->new;
	my @linesout = ();	
	my $currline = "";
	open(INFILE, $distdir."/$dir/$file");
	binmode(INFILE);
	if ($dir eq "bin" || $dir eq "testdata/bin")
	{
		if ($file eq "startup.pl")
		{
			$currline = "use lib '".$dest."/perl_lib';\n";
			$outdigest->add($currline);
			push @linesout, $currline;
		}
		else
		{
			$currline = "#!".$from_configure{perl}." -w -I".$dest."/perl_lib\n";
			$outdigest->add($currline);
			push @linesout, $currline;
		}
		my $skipme = <INFILE>;	
	}
	while(my $line=<INFILE>)
	{
		chomp $line; 
		$currline = "$line\n";
		$outdigest->add($currline);
		push @linesout, $currline;
	}		
	close(INFILE);
	push @{$newsigs}, "$dir/$file ".$outdigest->hexdigest."\n";

	if ($sighash->{"$dir/$file"} && -e "$dest/$dir/$file")
	{
		my $repl_digest = get_digest("$dest/$dir/$file");
		if ($repl_digest ne $sighash->{"$dir/$file"})
		{
			move_out_of_harms_way( "$dest/$dir/$file" );
		}
	}

	unless( open(OUTFILE, ">$dest/$dir/$file") )
	{
		print "\nCan't write to $dest/$dir/$file : $!\n";
		exit 1;
	}
	binmode(OUTFILE);
	foreach(@linesout)
	{
		print OUTFILE $_;
	}	
	close(OUTFILE);

	unless( chmod($perms, "$dest/$dir/$file") )
	{
		print "\nUnable to chmod $dest/$dir/$file : $!\n";
		exit 1;
	}
	unless( chown($uid, $gid, "$dest/$dir/$file") )
	{
		print "\nUnable to chown $dest/$dir/$file : $!\n";
		exit 1;
	}
}

sub install_dir
{
	my( $distdir, $dir, $perms, $uid, $gid, $dest, $sighash, $newsigs ) = @_;

	unless( opendir(INDIR, $dir) )
	{
		print "Unable to open package directory: $dir. $!\n";
		exit 1;
	}
	my @dirs = ();
	my @files = ();
	mkdir("$dest/$dir", 0755);
	unless( chown($uid, $gid, "$dest/$dir") )
	{
		print "\nUnable to chown $dest/$dir : $!\n"; 
		exit 1;
	}

	while(my $item = readdir(INDIR))
	{
		next if( $item eq "." || $item eq ".." );
		if( -d $distdir."/$dir/$item" ) 
		{ 
			push(@dirs, $item); 
		}
		else 
		{ 
			push(@files, $item); 
		}
	}
	closedir(INDIR);
	foreach(@files)
	{
		install_file($distdir, $_, $dir, $perms, $uid, $gid, $dest, $sighash, $newsigs );
	}
	foreach(@dirs)
	{
		install_dir($distdir, "$dir/".$_, $perms, $uid, $gid, $dest, $sighash, $newsigs );
	}
}

##############################################################

sub upgrade
{
	my( $base_path, $dist_path, $user, $group ) = @_;

	
	my(undef,undef,$uid,$gid) = getpwnam($user);
	print "Upgrading files : [";


	print <<HOORAY;
======================================================================

 Upgrade successful. You should now:

 - su to $user
 - make any changes described by the "updating" chapter of
   the documentation.
 - re-run bin/generate_apacheconf (the just-installed version, 
   not the version that came in the tar.gz.
 - restart your web server
 - restart the eprints indexer

 - To find and share ideas and problems try the EPrints technical
    mailing list and wiki at http://eprints.org/software/

======================================================================
HOORAY
}


sub full_install
{
	my( $base_path, $dist_path, $user, $group ) = @_;



	

	print <<HOORAY;

======================================================================
Hooray! Your EPrints2 installation was successful!
======================================================================

 What Now?

 - su to root
 - Open your apache.conf file, and make the
   following alterations:
   o Add the line
       Include $base_path/cfg/apache.conf
   o Replace the 'User <username>' line with
       User $user
   o Replace the 'Group <groupname>' line with
       Group $group
 - su to $user
 - Move into $base_path and run:
     bin/configure_archive

 Good Luck!

 - To find and share ideas and problems try the EPrints technical
    mailing list and wiki at http://eprints.org/software/

======================================================================
HOORAY
}

sub move_out_of_harms_way
{
	my( $file ) = @_;

	my @date = localtime;
	my $safename = sprintf( 
		"%s.backup.%04d-%02d-%02d", 
		$file, 
		$date[5]+1900, 
		$date[4]+1, 
		$date[3] );

	my $n = 0;
	while( -e $safename )
	{
		++$n;
		$safename = sprintf( 
			"%s.backup.%04d-%02d-%02d.%d", 
			$file, 
			$date[5]+1900, 
			$date[4]+1, 
			$date[3],
			$n );
	}

	rename $file, $safename;

	print "\n$file has been modified.\nSaving old version as $safename\n";
}


sub read_version
{
	my( $vfile ) = @_;

	unless( open(VERSIONIN, $from_configure{"dist_path"}."/VERSION") )
	{
		print "No VERSION file in distribution - invalid distribution?\n";
		exit 1;
	}
	binmode(VERSIONIN);
	my $version_id = <VERSIONIN>;
	unless( defined($version_id) ) 
	{
		print "Undefined version number.\n";
		exit 1;
	}
	chomp($version_id);
	my $version = <VERSIONIN>;
	unless( defined($version) ) 
	{
		print "Undefined version description.\n"; 
		exit 1;
	}
	chomp($version);
	close(VERSIONIN);

	return( $version_id, $version );
}

sub ensure_dir
{
	my( $dir, $uid, $gid, $mode ) = @_;

	if( !-d $dir ) 
	{
		if( !mkdir($dir, $mode) )
		{
			print "Unable to make dir: $dir.\n";
			print "Aborting!\n";
			exit 1;
		}
	}		
	
	unless( chown($uid, $gid, $dir) )
	{
		print "Unable to chown ".$dir." : $!\n"; 
		print "Aborting!\n";
		exit 1;
	}

	return;
}

