#!/usr/bin/perl -w
# (c) Copyright 2002-2008. CodeWeavers, Inc.
use strict;

my $deb_package="crossover-games-demo";
my $rpm_package="crossover-games-demo";
my $sun_package="cxgames";


# Portable which(1) implementation
sub cxwhich($$;$)
{
    my ($dirs, $app, $noexec)=@_;
    if ($app =~ /^\//)
    {
        return $app if ((-x $app or $noexec) and -f $app);
    }
    elsif ($app =~ /\//)
    {
        require Cwd;
        my $path=Cwd::cwd() . "/$app";
        return $path if ((-x $path or $noexec) and -f $path);
    }
    else
    {
        foreach my $dir (split /:/, $dirs)
        {
            return "$dir/$app" if ($dir ne "" and (-x "$dir/$app" or $noexec) and -f "$dir/$app");
        }
    }
    return undef;
}

# Fast dirname() implementation
sub _cxdirname($)
{
    my ($path)=@_;
    return undef if (!defined $path);
    return "." if ($path !~ s!/+[^/]+/*$!!s);
    return "/" if ($path eq "");
    return $path;
}

# Locate where CrossOver is installed by looking for the directory
# where this this script is located, unwinding symlinks on the way
sub locate_cx_root()
{
    if (!defined $ENV{CX_ROOT})
    {
        my $argv0=cxwhich($ENV{PATH},$0);
        $argv0=$0 if (!defined $argv0);
        if ($argv0 !~ m+^/+)
        {
            require Cwd;
            $argv0=Cwd::cwd() . "/$argv0";
        }
        my $dir=_cxdirname($argv0);
        while (!-x "$dir/cxmenu" or !-f "$dir/cxmenu")
        {
            last if (!-l $argv0);
            $argv0=readlink($argv0);
            $argv0="$dir/$argv0" if ($argv0 !~ m+^/+);
            $dir=_cxdirname($argv0);
        }
        $dir =~ s%(/\.)*$%%;
        $dir =~ s%(/\./(\./)*)%/%;
        $ENV{CX_ROOT}=_cxdirname($dir);
    }
    if (!-x "$ENV{CX_ROOT}/bin/cxmenu" or !-f "$ENV{CX_ROOT}/bin/cxmenu")
    {
        my $name0=$0;
        $name0 =~ s+^.*/++;
        print STDERR "$name0:error: could not find CrossOver in '$ENV{CX_ROOT}'\n";
        exit 1;
    }
    return $ENV{CX_ROOT};
}

BEGIN {
    unshift @INC, locate_cx_root() . "/lib/perl";
}
use CXLog;
use CXUtils;

my $productid=CXUtils::get_product_id();
my $productname=CXUtils::get_product_name();


# Process command-line options
my $opt_verbose=1 if (defined $ENV{CX_LOG});
my $opt_help;
require CXOpts;
my $cxopts=CXOpts->new();
$cxopts->add_options(["verbose!"    => \$opt_verbose,
                      "?|h|help"    => \$opt_help
                     ]);
my $err=$cxopts->parse();
CXLog::fdopen(2) if ($opt_verbose);


# Validate the command line options
my $usage;
if ($err)
{
    cxerr("$err\n");
    $usage=2;
}
elsif ($opt_help)
{
    $usage=0;
}
if (defined $usage)
{
    my $name0=cxname0();
    if ($usage)
    {
        cxerr("try '$name0 --help' for more information\n");
        exit $usage;
    }
    print "Usage: $name0 [--verbose] [--help]\n";

    print "\n";
    print "Uninstalls CrossOver or removes its files from your account.\n";

    print "\n";
    print "Options:\n";
    print "  --verbose    Print more information about what is going on\n";
    print "  --help, -h   Shows this help message\n";
    exit 0;
}


# Determine what mode we should be operating in
my $pre_msg;
my $mode;
my $post_msg;
my $err_msg;
my $button_list;
if (-w $ENV{CX_ROOT})
{
    $mode="uninstall";
    if ($> == 0)
    {
        # Check if there is any managed bottle
        my $has_bottle;
        foreach my $dir ("$ENV{CX_ROOT}/support",
                         "$ENV{HOME}/.$productid")
        {
            next if (!-d $dir);
            if (opendir(my $dh, $dir))
            {
                foreach my $dentry (readdir $dh)
                {
                    next if ($dentry =~ /^\.\.?$/);
                    if (-f "$ENV{CX_ROOT}/support/$dentry/cxbottle.conf")
                    {
                        $has_bottle=1;
                        last;
                    }
                }
                closedir($dh);
            }
            last if ($has_bottle);
        }
        if ($has_bottle)
        {
            $pre_msg=cxgettext("Windows applications and C: drives are contained in bottles. Some of these bottles are maybe used system-wide, so removing them will impact each user.\n");
        }
        else
        {
            $pre_msg="";
            $button_list="Proceed:1,Cancel:2",
        }
        $pre_msg.=cxgettext("Before uninstalling \%s, make sure to uninstall it from each user's environment. To do so, run '\%s' in their account.", $productname, "$ENV{CX_ROOT}/bin/cxuninstall");
        $pre_msg.=cxgettext("Do you want to delete root's bottles in addition to uninstalling \%s?", $productname);
    }
    else
    {
        # Single user
        $pre_msg=cxgettext("This will remove \%s from your system.", $productname);
        $pre_msg.=cxgettext("\n\nThis installation of CrossOver includes Windows applications and data contained in one or more bottles. Do you want to delete these bottles in addition to uninstalling \%s?", $productname);
    }
    $post_msg=cxgettext("\%s has been removed.", $productname);
    $err_msg=cxgettext("An error occurred while uninstalling \%s.", $productname);
    $button_list="Uninstall and delete bottles:0,Uninstall but keep bottles:1,Cancel:2",
}
else
{
    $mode="user";
    $pre_msg=cxgettext("This operation will remove all files created by \%s in your account.", $productname);
    $pre_msg.=cxgettext("\nYou will still be able to use Windows applications that were installed system-wide, if any. But all the Windows applications you installed as well as the C: drives contained in your bottles will be deleted.");
    $post_msg=cxgettext("\%s has been removed from your account.\nTo fully uninstall it, run '\%s' as root.",
        $productname, "$ENV{CX_ROOT}/bin/cxuninstall");
    $err_msg=cxgettext("An error occurred while removing the \%s files.", $productname);
    $button_list="Proceed:0,Cancel:2",
}

# Warn the user
my $rc=cxmessage(
    "-title", "\%s Uninstall", "-title", "$productname",
    "-buttons", $button_list,
    "-default", "Cancel",
    "-image", CXUtils::get_std_icon("cxuninstall.xpm"),
    "\%s", $pre_msg);
if ($rc == 0)
{
    $ENV{CX_PURGE}="all";
}
elsif ($rc == 256)
{
    $ENV{CX_PURGE}="desktopdata";
}
else
{
    # The user hit Cancel, closed the window or killed cxmessage
    exit 1;
}


# Uninstall
sub uninstall()
{
    if (-f "$ENV{CX_ROOT}/.uninstall")
    {
        # This is a Loki package
        cxlog("Starting the Loki uninstaller\n");
        if (!rename("$ENV{CX_ROOT}/.uninstall","$ENV{CX_ROOT}/uninstall"))
        {
            cxerr("unable to rename '.uninstall' to 'uninstall'\n");
            return 1;
        }

        # only one element so this will be interpreted as a command line
        my $rc=cxsystem(shquote_string("$ENV{CX_ROOT}/uninstall"));
        if ($rc != 0 and $ENV{CX_PURGE} ne "desktopdata")
        {
            rename("$ENV{CX_ROOT}/uninstall","$ENV{CX_ROOT}/.uninstall");
            return 1;
        }
        return 0;
    }

    my $rpm=cxwhich($ENV{PATH},"rpm");
    if (defined $rpm and cxsystem("rpm -q $rpm_package >/dev/null 2>&1")==0)
    {
        return cxsystem("rpm","-e","$rpm_package");
    }

    my $dpkg=cxwhich($ENV{PATH},"dpkg");
    if (defined $dpkg)
    {
        foreach my $package ($deb_package, "ia32-$deb_package")
        {
            my $status=cxbackquote("dpkg -s $package 2>&1");
            if ($? == 0 and $status !~ /^Status:.*(?:not-installed|config-files)$/m)
            {
                # This is a Debian package
                return cxsystem("dpkg", "--purge", "$package");
            }
        }
    }

    my $pkgrm=cxwhich($ENV{PATH},"pkgrm");
    if (defined $pkgrm and cxsystem("pkginfo", "-q", $sun_package)==0)
    {
        # This is a Solaris package
        my $cxpurge="$ENV{CX_ROOT}/cxpurge";
        my $fh;
        if (!open($fh, ">", $cxpurge))
        {
            cxerr("unable to open '$cxpurge' for writing: $!\n");
            return 1;
        }
        print $fh "$ENV{CX_PURGE}\n";
        close($fh);
	my @cmd=("pkgrm");
	push @cmd, "-v" if (CXLog::is_on() and !defined CXLog::get_filename());
	push @cmd, $sun_package;
        return cxsystem(@cmd);
        unlink $cxpurge;
    }

    cxerr("unable to determine how to uninstall $productname\n");
    return 1;
}

my $pid=fork();
if ($pid==0)
{
    # Child code
    cxexec("$ENV{CX_ROOT}/bin/cxtcl", "utils/cxwait.itcl", "Uninstalling");
    exit 1;
}
$rc=0;
if ($mode eq "uninstall")
{
    $rc|=uninstall();
}
else
{
    $rc|=cxsystem("$ENV{CX_ROOT}/bin/cxmenu", "--removeall",
                  "--pattern", "$productid-", "--ignorelist", "");
    $rc|=cxsystem("$ENV{CX_ROOT}/bin/cxassoc", "--removeall",
                  "--pattern", "$productid-", "--ignorelist", "");
    my $dir="$ENV{HOME}/.$productid";
    if (-d $dir)
    {
        cxlog("Deleting the '$dir' directory\n");
        require File::Path;
        if (!File::Path::rmtree($dir))
        {
            cxerr("unable to delete the '$ENV{HOME}/.$productid' directory\n");
        }
    }
}

kill(9,$pid) if (defined $pid);
# Our xmessage may be gone now
my $cxmessage="$ENV{CX_ROOT}/bin/cxmessage";
$cxmessage=cxwhich($ENV{PATH},"xmessage") if (!-f $cxmessage);

if ($rc != 0)
{
    if (defined $cxmessage)
    {
        cxsystem("$cxmessage",
                 "-title","Uninstall Failed",
                 "-buttons","OK",
                 "-default","OK",
                 $err_msg);
    }
    else
    {
        cxerr("$err_msg\n");
    }
    exit 1;
}

# Notify of completion and of next step
if (defined $cxmessage)
{
    cxsystem("$cxmessage",
             "-title","Uninstall Complete",
             "-buttons","OK",
             "-default","OK",
             $post_msg);
}
exit 0;
