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


BEGIN {
    unshift @INC, "$ENV{CX_ROOT}/lib/perl";
}
use CXLog;
use CXUtils;

my $real_product_id=CXUtils::get_real_product_id();


#####
#
# Configuration file creation / upgrade
#
#####

sub detect_shortcutdirs($)
{
    my ($section)=@_;
    my $dirs=$section->get("ManagedShortcutDirs");
    if (!defined $dirs and $> == 0)
    {
        my @list;
        push @list, "/usr/bin" if (-d "/usr/bin" and -w "/usr/bin");
        push @list, "\${CX_ROOT}/bin";
        $section->set("ManagedShortcutDirs", join(":", @list)) if (@list);
    }

    $dirs=$section->get("PrivateShortcutDirs");
    if (!defined $dirs)
    {
        my @list;
        push @list, "\${HOME}/bin";
        push @list, "\${CX_ROOT}/bin" if ($> != 0);
        $section->set("PrivateShortcutDirs", join(":", @list)) if (@list);
    }
}

sub create_crossover_config($$)
{
    my ($filename, $productid)=@_;

    my $template="$ENV{CX_ROOT}/share/crossover/data/$real_product_id.conf";
    if (!-e $template)
    {
        cxerr("unable to find '$template'\n");
        exit 1;
    }
    require CXRWConfig;
    my $cxconfig=CXRWConfig->new($template);

    my $s=$cxconfig->get_section("CrossOver");
    return if (!$s);

    detect_shortcutdirs($s);

    if (-f "/etc/linspire-version")
    {
        my $status=`dpkg -s forward-oss-utils 2>&1`;
        cxlog($status);
        if ($? == 0 and
            $status !~ /^Status:.*(?:not-installed|config-files)$/m and
           $status =~ /^Version: 0.9$/m)
        {
            # Make sure not to use MIDI because forward-oss-utils does not
            # support it and will either crash the system or CrossOver.
            my $s=$cxconfig->append_section("EnvironmentVariables");
            $s->set("MIDIDEV", "/dev/no-sequencer");
        }
    }

    $cxconfig->set_filename($filename);
    if (!$cxconfig->save())
    {
        cxwarn("unable to save '$filename': $!\n");
    }
}

sub upgrade_crossover_config($$$)
{
    my ($filename, $productid, $opt_old_version)=@_;

    require CXUpgrade;
    cxlog("\nUpgrading '$filename'\n\n");
    my $src=CXUpgrade->new($filename);
    if (!$src)
    {
        cxlog("unable to read '$filename': $!\n");
        $src=CXUpgrade->new(undef);
    }
    my $s=$src->get("CrossOver");
    my $old_version;
    $old_version=$s->get("ProductVersion") if (defined $s);
    $old_version=$opt_old_version || "1.3.1" if (!defined $old_version);
    cxlog("Old Version=$old_version\n");
    $old_version=~s/[^0-9.].*$//;

    my $backup="$filename.$old_version";
    if (-f $filename and !-f $backup)
    {
        require File::Copy;
        if (!File::Copy::copy($filename,$backup))
        {
            cxwarn("unable to write backup to '$backup': $!\n");
        }
    }

    my $template="$ENV{CX_ROOT}/share/crossover/data/$real_product_id.conf";
    my $dst=CXUpgrade->new($template);
    if (!defined $dst)
    {
        cxerr("unable to read '$template': $!\n");
        return $old_version;
    }


    # Tweak the configuration values
    my $bottle=$src->add("BottleDefaults");
    $s=$src->get("CrossOver");
    if (defined $s)
    {
        # We never keep these settings from the old file
        $s->remove_field("Product");
        $s->remove_field("ProductID");
        $s->remove_field("ProductName");
        $s->remove_field("ProductVersion");
        $s->remove_field("BuildTimestamp");

        # ConfigFileVersion has been removed
        $s->remove_field("ConfigFileVersion");

        if ($old_version lt "5.0")
        {
            detect_shortcutdirs($s);

            my $plugindirs=$s->get("LinuxNSPluginDirs");
            if ($plugindirs)
            {
                my $scope=($> == 0 ? "Managed" : "Private");
                $s->set("${scope}LinuxNSPluginDirs", $plugindirs);
                $s->remove_field("LinuxNSPluginDirs");
            }
        }

        # LinuxBrowser -> PreferredBrowser
        my $value=$s->get("LinuxBrowser");
        if (defined $value)
        {
            $s->set("PreferredBrowser",$value);
        }
        $s->remove_field("LinuxBrowser");

        # Update MIMEIgnoreList
        my $d=$s->get("MIMEIgnoreList") || "";
        if ($d =~ m!^text/html(?::text/plain:application/x-crossover-doc)?$!)
        {
            $s->remove_field("MIMEIgnoreList");
        }
    }

    # [BottleDefaults] / MyDocumentsDir has been removed
    $bottle->remove_field("MyDocumentsDir");

    $s=$src->get("MIMEAliases");
    if (defined $s)
    {
        my $d;
        $d=$s->get("application/msexcel") || "";
        $s->remove_field("application/msexcel") if ($d eq "application/vnd.ms-excel");

        $d=$s->get("application/mspowerpoint") || "";
        $s->remove_field("application/mspowerpoint") if ($d eq "application/vnd.ms-powerpoint");

        $d=$s->get("video/x-ms-asf") || "";
        $s->remove_field("video/x-ms-asf") if ($d eq "video/x-ms-wmv");
    }

    $s=$src->get("OfficeSetup");
    if (defined $s)
    {
        # UrlOnlineUpdate does not exist anymore
        $s->remove_field("UrlOnlineUpdate");

        # MIMEIgnoreList moved to [CrossOver]
        my $field=$s->get_field("MIMEIgnoreList");
        my $d=$src->get("CrossOver");
        if (defined $field and defined $d)
        {
            $d->add_field($field);
        }
        $s->remove_field("MIMEIgnoreList");

        # MyDocsDir does not exist anymore
        $s->remove_field("MyDocsDir");

        # HttpProxyHost & HttpProxyPort moved to [BottleDefaults]
        $field=$s->get_field("HttpProxyHost");
        if (defined $field)
        {
            $s->remove_field("HttpProxyHost");
            $bottle->add_field($field);
        }
        $field=$s->get_field("HttpProxyPort");
        if (defined $field)
        {
            $s->remove_field("HttpProxyPort");
            $bottle->add_field($field);
        }
    }

    $s=$src->get("Default");
    if (defined $s)
    {
        # MainPath, WinePrefix, RootMode & SkipDebianMenus do not exist anymore
        $s->remove_field("MainPath");
        $s->remove_field("WinePrefix");
        $s->remove_field("RootMode");
        $s->remove_field("SkipDebianMenus");

        # WinePrefixCreate moved to cxbottle.conf
        $s->remove_field("WinePrefixCreate");

        # LDAssumeKernel and WineDebugLevel have been removed
        $s->remove_field("LDAssumeKernel");
        $s->remove_field("WineDebugLevel");

        # Update the LDPreload field
        my $value=$s->get("LDPreload");
        if (defined $value)
        {
            # LDPreload="" is now what ';LDPreload' does
            $s->remove_field("LDPreload") if ($value eq "");
        }
        elsif (defined $s->get_field("LDPreload"))
        {
            # ';LDPreload' now should be written as follows
            $s->set("LDPreload","\${LD_PRELOAD}");
        }

        # MenuPrefix moved to [BottleDefaults] and cxbottle.conf
        $value=$s->get("MenuPrefix");
        $bottle->set("MenuRoot",$value) if (defined $value);
        $s->remove_field("MenuPrefix");

        # And finally, rename this section to [Wine]
        $src->rename($s,"Wine");
    }

    # Do the final merge and write the new configuration file
    $dst->merge($src);
    $dst->write($filename);

    return $old_version;
}



#####
#
# Main
#
#####

# Parse the command line arguments
my $opt_productid;
my $opt_old_version;
my $opt_install_bottles;
my $opt_verbose;
my $opt_help;
require CXOpts;
my $cxopts=CXOpts->new();
$cxopts->add_options(["productid=s"     => \$opt_productid,
                      "old-version=s"   => \$opt_old_version,
                      "install-bottles" => \$opt_install_bottles,
                      "verbose!"        => \$opt_verbose,
                      "?|h|help"        => \$opt_help
                     ]);
my $err=$cxopts->parse();
CXLog::fdopen(2) if ($opt_verbose);


# Verify command line options
my $usage;
if ($err)
{
    cxerr("$err\n");
    $usage=2;
}
elsif ($opt_help)
{
    $usage=0;
}
else
{
    if (!$opt_productid)
    {
        cxerr("you must specify the product id\n");
        $usage=2;
    }
    $opt_old_version="" if (!defined $opt_old_version);
    $opt_old_version=~s/[^0-9.].*$//;
}

# Print usage
if (defined $usage)
{
    my $name0=cxname0();
    print STDERR "Usage: $name0 --productid productid [--old-version oldversion] [--install-bottles] [--verbose]\n";
    exit $usage;
}

# Create or upgrade the CrossOver configuration
require CXBottle;
CXBottle::get_crossover_config();
my $filename="$ENV{CX_ROOT}/etc/$opt_productid.conf";
if (!-f $filename)
{
    create_crossover_config($filename, $opt_productid);
}
else
{
    $opt_old_version=upgrade_crossover_config($filename, $opt_productid, $opt_old_version);
}

# Upgrade or install the bottles
if ($opt_old_version ne "" and $opt_old_version lt "5.0")
{
    if ($opt_productid eq $real_product_id)
    {
        # Delete the legacy menus, associations and plugins
        my @scopes=("private");
        push @scopes, "managed" if ($> == 0);
        foreach my $scope (@scopes)
        {
            cxsystem("$ENV{CX_ROOT}/bin/cxmenu", "--removeall",
                     "--pattern", "legacy", "--scope", $scope,
                     "--ignorelist", "");
            cxsystem("$ENV{CX_ROOT}/bin/cxassoc", "--removeall",
                     "--pattern", "legacy", "--scope", $scope,
                     "--ignorelist", "");
        }
    }
    # - The above commands also deleted the legacy menus, associations and
    #   plugins of existing bottles. This makes it almost impossible to
    #   use them. So trigger an upgrade of the bottles (letting the wine
    #   script do all the work) which will re-install them too.
    # - Also, always try to trigger an upgrade of the (presumably) managed
    #   bottles as they are mostly used by non-root users and those users
    #   cannot upgrade them.
}

# Call get_crossover_config() to get CX_(MANAGED_)BOTTLE_PATH.
CXBottle::get_crossover_config();
my $builtin_bottles="";

foreach my $scope ("managed", "private")
{
    my $path=($scope eq "private" ? $ENV{CX_BOTTLE_PATH} : $ENV{CX_MANAGED_BOTTLE_PATH});
    foreach my $dir (split /:+/, $path)
    {
        next if ($dir eq "");

        my $dh;
        next if (!opendir($dh, $dir));
        foreach my $dentry (readdir $dh)
        {
            next if ($dentry =~ /^(?:\.\.?|default)$/);

            # Note that bottles may not have a cxbottle.conf file yet
            next if (!-f "$dir/$dentry/system.reg");

            if ($builtin_bottles and $dentry =~ /^(?:$builtin_bottles)$/)
            {
                # This will also trigger an upgrade if needed
                cxsystem("$ENV{CX_ROOT}/bin/cxbottle",
                         "--bottle", $dentry, "--scope", $scope,
                         "--restored", "--default", "--install");
            }
            elsif ($opt_install_bottles)
            {
                # Check whether the bottle is meant to be installed
                require CXConfig;
                my $cxbottle=CXConfig->new("$dir/$dentry/cxbottle.conf");
                my $bottle=$cxbottle->get_section("Bottle");
                my $installed;
                if (($bottle->get("MenuMode") || "") =~ /^install$/i)
                {
                    cxsystem("$ENV{CX_ROOT}/bin/cxmenu",
                             "--bottle", $dentry, "--scope", $scope,
                             "--install");
                    $installed=1;
                }
                if (($bottle->get("AssocMode") || "") =~ /^install$/i)
                {
                    cxsystem("$ENV{CX_ROOT}/bin/cxassoc",
                             "--bottle", $dentry, "--scope", $scope,
                             "--install");
                    $installed=1;
                }
                if (($bottle->get("NSPluginMode") || "") =~ /^install$/i)
                {
                    cxsystem("$ENV{CX_ROOT}/bin/cxnsplugin",
                             "--bottle", $dentry, "--scope", $scope,
                             "--install");
                    $installed=1;
                }
                if (!$installed and $scope eq "managed")
                {
                    # Even if it is not installed, upgrade the managed
                    # bottles as not doing so could require upgrading the RPM
                    # bottle package too
                    cxsystem("$ENV{CX_ROOT}/bin/wine",
                             "--bottle", $dentry, "--scope", $scope,
                             "--ux-app", "true");
                }
            }
            elsif ($scope eq "managed")
            {
                # Upgrade the managed bottles as not doing so
                # could require upgrading the RPM bottle package too
                cxsystem("$ENV{CX_ROOT}/bin/wine",
                         "--bottle", $dentry, "--scope", $scope,
                         "--ux-app", "true");
            }
        }
        closedir($dh);
    }
}

exit 0;
