# RPM Package Management System
# Copyright (C) 1995 Red Hat, Inc
#
# This program 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.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.

require "dbrecord.pl";
require "dbmisc.pl";
require "misc.pl";
require "run.pl";

# this doesn't do anything about removing direcories, or recognizing
# config files

sub douninstall {
    local (%spec, $test) = @_;
    local ($package, %paths, %conflicts, $fileinfo, $ostr, %ospec);
    local ($i, $file, $list, $label, $newlist, $olabel, $pathindex, $md5);
    local ($dbmd5, @infoline, %md5list);

    # get a list of files not to delete
    %shared = &findshared(1, 0, *md5list, *spec);

    if ($spec{"subpackage:0:name"}) {
	$label = "$spec{name}-" . $spec{"subpackage:0:name"} . 
		    ":${version}:$spec{release}";
	$name = "$spec{name}-" . $spec{"subpackage:0:name"};
    } else {
	$label = "$spec{name}:${version}:$spec{release}";
	$name = $spec{name};
    }

    debug("label is $label");
    debug("rearranging shared list");

    # this list is arranged by *package* get it be by files instead
    foreach $package (keys(%shared)) {
	debug("$package contains shared files");

	$ostr = $Packages{$package};
	if (!defined $ostr) { 
	    &error("RPM database is corrupt. Use --rebuild to ",
		   "reconstruct it");
	}
	%ospec = strtorec($ostr, "all");

	foreach $fileinfo (split(" ", $shared{$package}))
	{
	    ($filenum, $ofilenum) = ($fileinfo =~ /(.*):(.*)/);
	    $paths{$ospec{"subpackage:0:file:$ofilenum:path"}} = 1;
	    debug($ospec{"subpackage:0:file:$ofilenum:path"}, 
			 " is shared with ", $ospec{name});
	}
    }

    $prescript = $PostIndex{"$label:pre"};
    $postscript = $PostIndex{"$label:post"};

    &debug("running preuninstall script");
    if (! $test && $prescript) {
	if (&run_script($prescript)) {
	    return 1
	}
    }

    for ($i = 0; $i < $spec{"subpackage:0:fileC"}; $i++) {
	$file = $spec{"subpackage:0:file:$i:path"};

	&debug("looking at $file");

	if (($spec{"subpackage:0:file:$i:state"} eq "normal") 
		&& !$paths{$file}) {
	    if (&is_directory($spec{"subpackage:0:file:$i:info"})) {
		debug("removing directory $file");
		if (!&safe_rmdir($file, $test)) {
		    warning("directory $file could not be removed");
		}
	    } elsif (&is_config($spec{"subpackage:0:file:$i:info"})) {
		debug("found config file");
		$md5 = &md5($file);
		@infofile = split(" ",$spec{"subpackage:0:file:$i:info"});
		$dbmd5 = $infofile[2];
		if ($md5 eq $dbmd5) {
		    debug("removing $file");
		    if (&safe_unlink($file, $test) != 1) {
			warning("$file could not be removed");
		    }
		} else {
		    normal("moving $file to $file.rpmsave");
		    if (!&safe_rename($file, "$file.rpmsave", $test)) {
			warning("could not rename $file to $file.rpmsave");
		    }
		}
	    } else {
		debug("removing $file");
		if (safe_unlink($file, $test) != 1) {
		    warning("$file could not be removed");
		}
	    }
	} else {
	    debug("keeping $file");
	} 

	$list = $PathIndex{$file};
	if (!(defined $list)) {
	    debug("can't find $file");
	    warning("RHS database may be corrupt");
	} else {
	    debug("old list: $list label: $label");
	    $newlist = "";
	    foreach $fileinfo (split(" ", $list)) {
		if ($fileinfo ne "$label:$i") {
		    if ($newlist) {
			$newlist = "$newlist $fileinfo";
		    } else {
			$newlist = $fileinfo;
		    }
		}
	    }
	    debug("new list: $newlist");
	    if (!$newlist && !$test) {
		debug("erasing PathIndex entry");
		delete($PathIndex{$file});
	    } elsif (!$test) {
		$PathIndex{$file} = $newlist;
	    }
	}
    }

    debug("removing spec and icon index");
    if (!$test) {
	delete($Packages{$label});
	delete($IconIndex{$label});
	delete($PostIndex{"$label:pre"});
	delete($PostIndex{"$label:post"});
    }
    
    &debug("removing from name index");
    $list = $NameIndex{$name};
    &debug("\$NameIndex{$name} is $list label is $label");
    if (!defined $list) {
	&warning("RPM database may be corrupt");
    } else {
	$newlist = "";
	foreach $fileinfo (split(" ", $list)) {
	    &debug("uninstalling $label -- found $fileinfo");
	    if ($fileinfo ne $label) {
		if ($newlist) {
		    $newlist = "$newlist $fileinfo";
		} else {
		    $newlist = $fileinfo;
		}
	    }
	}
	if (!$newlist && !$test) {
	    debug("erasing \$NameIndex{$name} entry");
	    delete($NameIndex{$name});
	} elsif (!$test) {
	    debug("setting \$NameIndex{$name} to $newlist");
	    $NameIndex{$name} = $newlist;
	}
    }

    &debug("running postuninstall script");
    if (! $test && $postscript) {
	if (&run_script($postscript)) {
	    return 1
	}
    }
}

sub uninstallpackage {
    local($force, $test, $nosub, $package) = @_;
    local($str, %rec, $subpackages, $i, $name, $version, $release);

    debug("Uninstalling $package");

    ($name, $version, $release, $rest) = 
		$package =~ /([^:]*):([^:]*):([^:]*)(.*)/;

    $label = "$name:$version:$release";
    $str = $Packages{$label};
    if (!defined $str) {
	&error("RPM database corrupt -- use --rebuild to rebuilt it");
    }

    %rec = &strtorec($str, "all");

    &douninstall(%rec, $test);
}

sub uninstallpackages {
    local($force, $test, $nosub, @list) = @_;
    local($package, @pacakges, $packagespec);

    &opendatabase("rw");

    foreach $packagespec (@list) {
	@packages = &getmatches($packagespec);
 	if (@packages == 0) {
	    warning("no packages matching $packagespec found");
	    next;
	} elsif (@packages > 1 && !$force) {
	    warning("$package specifies multiple packages (@packages)");
	    warning("to remove them, use the --force option");
	    next;
	}

	foreach $package (@packages) {
	    &uninstallpackage($force, $test, $nosub, $package);
	}
    }

    &closedatabase;
}

sub safe_unlink {
    local ($fn, $test) = @_;

    if (!$test) {
	return unlink($fn);
    }

    return 1;
}

sub safe_rmdir {
    local ($fn, $test) = @_;

    if (!$test) {
	return rmdir($fn);
    }

    return 1;
}

sub safe_rename {
    local ($fn, $targ, $test) = @_;

    if (!$test) {
	return rename($fn, $targ);
    }

    return 1;
}

1;
