#!/usr/bin/perl -w
#*****************************************************************************
# 
#  ooffice - Wrapper script for OpenOffice.org
# 
#  Based on the Mandrake work.
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License version 2, as
#  published by the Free Software Foundation.
# 
#  This program 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 this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# 
#*****************************************************************************

use strict;
use IO::Handle;
use Fcntl ':flock';

my $Debug = $ENV{OOO_DEBUG};
my $DebugRH = $ENV{OOO_RH_DEBUG};

# Define the vendor of this particular OOo pacakge
my $VendorName = 'RedHat';
# Define the distribution this package is targetted at
my $DistroName = 'RHEL4';
# Substituted by the build system:
# Define OpenOffice.org version
my $Version = '1.1.5';
# Define system installation directory
# Autoconf totally sucks for @libdir@ type substitution
my $SystemInstallDir = '/usr/lib/ooo-1.1';
# Suffix for parallel installable versioning
my $BinSuffix = '';
# ooo-build version
my $OOO_BUILDVERSION = '1.3.17';
# Debugging

if ( $DebugRH ) {
	$Debug = 1;
	$VendorName = "RedHat";
}
if ($Debug && $Version =~ /^\@/) {
    $Version = "1.1.3";
    $SystemInstallDir = "/usr/lib/ooo-1.1";
    $BinSuffix = '';
}
my $TargetVersion = "OpenOffice.org $Version";
my $ConfigSuffix = $Version;
$ConfigSuffix =~ s/([0-9]+\.[0-9]+).*/$1/;
# alternative $ConfigSuffix; useful if the default one is in use and
# --disable-update is selected
my $ConfigSuffixAlt = $Version;
$ConfigSuffixAlt =~ s/([0-9]+\.[0-9]+\.[0-9]+).*/$1/;
# Define lock-file for this script
my $LockFile = "$ENV{HOME}/.openoffice-lock";
# Define user OOo versions file
my $VersionFile = "$ENV{HOME}/.sversionrc";

# path where the configuration for this version of OOo is installed
my $UserInstallDir;
# default path where to install the configuration
my $UserInstallDirDefault;
# an alternative default path
my $UserInstallDirDefaultAlt;

my $HomeDirStem = '.ooo-';
if ( $VendorName eq "RedHat" ) {
    if ( $DistroName eq "RHEL3" ) {
        $HomeDirStem = '.openoffice';
        $ConfigSuffix = '';
        $ConfigSuffixAlt = '';
    } else {
        $HomeDirStem = '.rhopenoffice';
    }
}
# Define user installation directory
$UserInstallDirDefault = "$ENV{HOME}/$HomeDirStem$ConfigSuffix";
$UserInstallDirDefaultAlt = "$ENV{HOME}/$HomeDirStem$ConfigSuffixAlt";

# Define OOo setup program
my $SetupProgram = "$SystemInstallDir/program/setup";
# Where gconftool is...
my $GConfTool = 'gconftool-2';
# GConf configuration keys
my $ConfQuickstart = '/apps/ooo/quickstart';
# Note about default format key values:
# MS = Force MS Office to be default
# OO = Force OOo to be default
my $ConfDefaultFormat = '/apps/ooo/default-format';
# enable update by default
my $EnableUpdate = 1;

sub GetConfBool($)
{
    my ($path) = @_;
    my ($value, $ret);

    $value = `$GConfTool --get $path 2>&1`;

    if (!$value) {
	$ret = 0;
    } elsif ($value =~ m/^true.*/i ||
	     $value =~ m/^yes.*/i ||
	     $value =~ m/^on.*/i) {
	$ret = 1;
    } else {
	$ret = 0;
    }

    return $ret;
}

sub ReadVersionFile($) {
    my ($file) = @_;
    my $e;
    my %entries;
    my $Rc;

    if (open ($Rc, "$file")) {
        while (<$Rc>) {
            chomp;
            if (/^\[(\w+)\]/) {
                $entries{$1} = $e = { };
            }
            elsif (/^([^=]+)=([^\r\n]+)/) {
                $e->{$1} = $2;
            }
        }
        close ($Rc);
    }
    %entries;
}

sub DoWriteVersionFile(%$) {
    my ($config, $file) = @_;
    local *F;
    
    if ($file) {
        open F, ">$file" or die "Cant write to $file\n";
        select F;
    }
    local $\ = "\n";
    while (my ($secname, $secvars) = each %$config) {
        print "[$secname]";
        while (my ($key, $value) = each %$secvars) {
            print "$key=$value";
        }
        print "";
    }
    if ($file) {
        close F;
        select STDOUT;
    }
}

sub WriteVersionFile(%) {
    my (%config) = @_;
    DoWriteVersionFile \%config, "$VersionFile";
}

sub sniff_old_path($)
{
    my $fname = shift;
    my $file;
    my $path;

    open ($file, $fname) || $Debug && print "Failed to open '$file': $!";
    while (<$file>) {
	m/xlink:href=\"([^\"]*)\"/i || next;
	$path = $1;
	$path =~ m|share/basic| && last;
    }
    close ($file);

    if (defined $path) {
	$path =~ s|^file://||;
	$path =~ s|/share/basic/.*||;
    }
    return $path;
}

sub rewrite_file_paths($$$)
{
    my ($fname, $old, $new) = @_;
    my ($old_file, $new_file);
    
    if (!open ($old_file, "$fname")) {
	$Debug && print "Couldn't find $fname for re-writing: $!\n";
	return;
    }
    open ($new_file, ">$fname.new") || die "Failed re-writing $fname: $!";
    while (<$old_file>) {
	s|file://$old|file://$new|g;
	print $new_file $_;
    }
    close $old_file || die "Failed to close $fname: $!";
    close $new_file || die "Failed to close $fname.new: $!";

    rename "$fname.new", "$fname" || die "Failed to replace $fname: $!";
}

sub rewrite_paths()
{
    my @files = ( 'user/basic/dialog.xlc',
		  'user/basic/script.xlc',
		  'user/registry/data/org/openoffice/Office/Views.xcu',
		  'user/registry/data/org/openoffice/ucb/Hierarchy.xcu',
		  'user/registry/data/org/openoffice/ucb/Store.xcu' );
    my $old_path = sniff_old_path ($UserInstallDir . '/' . $files[0]);

    if (!defined $old_path ||
	$old_path eq $SystemInstallDir) {
	$Debug && print "Not changing install location on upgrade; no re-write";
	return;
    }
    print "Replacing $old_path with $SystemInstallDir\n";

    for my $file (@files) {
	rewrite_file_paths ($UserInstallDir . '/' . $file,
			    $old_path, $SystemInstallDir);
    }
}

#=============================================================================
# Main
#=============================================================================

# Parse command line arguments
my @ooo_argv;
my $session_quickstart;
my $widgets_set;
my $UserInstallDirPreferred;
while ($ARGV[0]) {
    $_ = shift;
    if (m/^--session-quickstart/) {
	$session_quickstart = 1;
    } elsif (m/^--widgets-set/) {
	$widgets_set = shift;
	(defined $widgets_set) || die "Error: The option --widgets-set requires a value\n" .
	                            "For example: --widgets-set gtk\n";
    } elsif (m/^--config-path/) {
	$UserInstallDirPreferred = shift;
	(defined $UserInstallDirPreferred) || die "Error: The option --config-path requires a value\n" .
	                            "For example: --config-path $UserInstallDirDefault\n";
    } elsif (m/^--enable-update/) {
        $EnableUpdate = 1;
    } elsif (m/^--disable-update/) {
        $EnableUpdate = 0;
    } elsif (m/^--version/) {
	print "This is OpenOffice.org version $Version built with ooo-build-$OOO_BUILDVERSION\n";
	exit 0;
    } else {
        push @ooo_argv, $_;
    }
}

if (!@ooo_argv) {
    my $arg;
    if ($0 =~ m/\/oo(calc|draw|impress|math|web|writer)$BinSuffix$/) {
        $arg = "-$1";
    } elsif ($0 =~ m/\/oofromtemplate$BinSuffix$/) {
        $arg = "slot:5500";
    }

    if ($arg) {
        push @ooo_argv, "$arg";
        $Debug && print "Append arg: $arg\n";
    }
} else {
    $Debug && print "Ignoring type - since have filenames\n";
}

my $Lock;

$Debug && print "Taking lock: $LockFile\n";
open ($Lock, ">$LockFile") || print "Can't open $LockFile\n";
flock ($Lock, LOCK_EX) || print "Warning: can't flock $LockFile\n";
$Debug && print "Obtained lock: $LockFile\n";

my %config;
my $config_changed = 0;


sub config_remove_by_path($$)
{
    my $config = shift;
    my $path = shift;
    my $versions = $config->{'Versions'};
    my $changed = 0;
    
    foreach (keys %$versions) {
	if ($versions->{$_} eq $path) {
	    delete $versions->{$_};
	    $changed++;
	}
    }

    return $changed;
}

# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=245561
sub clean_symlinks($)
{
    my $config = shift;
    my $versions = $config->{'Versions'};
    
    foreach (keys %$versions) {
	my $path = $versions->{$_};
	$path =~ s|file://||;

	my @known_links = ( "user/work", "work" );

	for my $subdir (@known_links) {
	    if (-l "$path/$subdir") {
#		print "Removing $path/$subdir\n";
		unlink "$path/$subdir" || die "Too risky to install with $path/$subdir: $!";
	    }
	}
    }
}

sub create_setup_config
{
    # default setting
    my $destination_path = "$UserInstallDirDefault";
    my $update_mode = "IF_AVAILABLE";

    # update setting
    $destination_path = "$UserInstallDirDefaultAlt" if (!($EnableUpdate) && -e "$UserInstallDirDefault");
    $destination_path = "$UserInstallDirPreferred" if (defined $UserInstallDirPreferred);
    $update_mode = "NEVER" unless ($EnableUpdate);

    my $SetupConfigTmp;
    chomp($SetupConfigTmp = `mktemp /tmp/ooo-wrapper.autoresponse.file.XXXXXX`);
  
    open F, ">$SetupConfigTmp" or die "Cant write to $SetupConfigTmp\n";
  
    print F <<"EOF";
[ENVIRONMENT]
INSTALLATIONMODE=INSTALL_WORKSTATION
INSTALLATIONTYPE=WORKSTATION
DESTINATIONPATH=$destination_path
UPDATEMODE=$update_mode

[JAVA]
JavaSupport=none
EOF

    close (F);
    return $SetupConfigTmp;
}

if (defined $widgets_set) {
    $ENV{SAL_USE_VCLPLUGIN} = $widgets_set;
}

sub check_user_installation
{
    if ( -r "$VersionFile" ) {
	%config = ReadVersionFile "$VersionFile";
    }

    if (exists $config{Versions}->{$TargetVersion}) {
	$UserInstallDir = "$config{Versions}->{$TargetVersion}";
	$UserInstallDir =~ s/file\:\/\///;

	# Prune broken looking installs & force a re-install
	if ( ! -d $UserInstallDir || ! -e "$UserInstallDir/soffice" ) {
    	    $config_changed += config_remove_by_path (\%config, "file://$UserInstallDir");
	}

	if (%config && $config_changed) {
    	    $Debug && print "Write version file\n";
    	    WriteVersionFile %config;
	}
    }
    $UserInstallDir;
}

check_user_installation();

# Perform a user install / upgrade, if necessary.
if (! exists $config{'Versions'}->{$TargetVersion}) {
    # We can safely do the installation now
    my $SetupConfig = create_setup_config();
    # We also must make sure setup can find the libraries it needs
    my $setup_cmd = "LD_LIBRARY_PATH=$SystemInstallDir:$SystemInstallDir/program " .
                    "$SetupProgram -R:$SetupConfig -v -nogui";
    if (!$Debug) {
	$setup_cmd .= " > ~/.openoffice-install-log 2>&1";
    }

    clean_symlinks (\%config);

    $Debug && print "Calling setup: '$setup_cmd'\n";
    my $setup_failed = system ($setup_cmd);
    unlink $SetupConfig;
    $setup_failed && die "Installation of OpenOffice.org $Version failed:\n '$setup_cmd'\n";

    check_user_installation() || die "Installation of OpenOffice.org $Version was not successfull.\nCheck ~/.openoffice-install-log log file for details.\n";

    rewrite_paths();
}

sub symlinkf { unlink $_[1]; symlink $_[0], $_[1] }
symlinkf "$SystemInstallDir/program/soffice", "$UserInstallDir/soffice";
symlinkf "$SystemInstallDir/program/setup",   "$UserInstallDir/setup";

my $format = `$GConfTool --get $ConfDefaultFormat 2>&1`;

# See "Note about default format key values" above for values
# expected of the gconf key used here
# Only set MS as default if forced.
if ($format =~ m/^MS/i) {
    $ENV{OOO_MS_DEFAULTS}="1";
}

flock ($Lock, LOCK_UN);
close ($Lock);
$Debug && print "Released lock: $LockFile\n";

if (defined $widgets_set) {
    $ENV{SAL_USE_VCLPLUGIN} = $widgets_set;
}

if ($session_quickstart) {
    my $do_qstart = GetConfBool ($ConfQuickstart);
    if (!$do_qstart) {
	exit 1;
    }
    $Debug && print "Execute quickstarter\n";
    push @ooo_argv, '-quickstart';
}

if (!(-f '/proc/version')) {
    print STDERR "\n\n --- Warning - OO.o will not work without a mounted /proc filesystem --- \n\n\n";
}

# And here we go. ;-)
exec "$UserInstallDir/soffice", @ooo_argv
