#!/usr/bin/perl

require 5.002;
use strict 'subs';
use English;
use Debconf::Client::ConfModule ':all';

# do not print anything to STDOUT, as debconf will interpret it as a command.
# This is not an issue with preinst/postinst scripts written in shell,
# because their confmodule reshuffles their fds for them. The perl binding
# does not, so we have to refrain from using stdout ourselves. The same thing
# holds for any child commands we spawn: stderr is ok, but stdout is not.

sub debug ($) {
    my($msg) = @_;
    print STDERR $msg;
}

sub check_uid($$$$$$) {
    my ($name, $uid, $gid, $gecos, $home, $shell) = @_;
    my $ok = 1;

    debug("Checking user $name (uid $uid, gid $gid, homedir $home)... ");
    @name_entry = getpwnam("$name");
    if ( @name_entry == () ) {
	my @uid_entry = getpwuid($uid);
	if ( @uid_entry == () ) {
	    system("adduser --system --no-create-home --quiet --home $home --gid $gid --uid $uid --gecos \'$gecos\' $name >/dev/null 2>&1");
	    if ( $? != 0 ) {
		debug("\n Error while adding user $name!\n");
		$ok = 0;
	    }
	    else {
		debug("added.\n");
	    }
	    system("chsh -s $shell $name >/dev/null");
	}
	else {
	    debug("error!\n Uid $uid is being used by user $uid_entry[0]\n");
	    $ok = 0;
	}
    }
    else {
	if ( $name_entry[3] != $gid ) {
	    debug("error!\n") if $ok;
	    debug(" User $name has primary group $name_entry[3] instead of $gid\n");
	    $ok = 0;
	}
	if ( $name_entry[2] != $uid ) {
	    debug("error!\n") if $ok;
	    debug(" User $name has uid $name_entry[2] instead of $uid\n");
	    $ok = 0;
	}
	if ( $name_entry[7] ne $home ) {
	    debug("error!\n") if $ok;
	    debug(" User $name has home directory $name_entry[7] instead of $home\n");
	    $ok = 0;
	}
	if ( $ok ) {
	    debug("ok.\n");
	}
    }
    return $ok;
}

sub check_gid($$@) {
    my ($name, $gid, @members) = @_;
    my $ok = 1;

    debug("Checking group $name (gid $gid)... ");
    @name_entry = getgrnam($name);
    if ( @name_entry == () ) {
	my @gid_entry = getgrgid($gid);
	if ( @gid_entry == () ) {
	    system("addgroup --quiet --gid $gid $name >/dev/null");
	    if ( $? != 0 ) {
		debug("\n Error while adding group $name\n");
		$ok = 0;
	    }
	    else {
		debug("added.\n");
	    }
	}
	else {
	    debug("error!\n Gid $gid is being used by group $gid_entry[0]\n");
	    $ok = 0;
	}
    }
    else {
	if ( $name_entry[2] != $gid ) {
	    debug("error!\n Group $name has gid $name_entry[2] instead of $gid\n");
	    $ok = 0;
	}
	if ( $ok ) {
	    debug("ok.\n");
	}
    }
    return $ok;
}

sub is_qmail_installed {
    my $qmail_installed = 0;

    debug("Checking if qmail is already installed on this computer... ");

    $qmail_home = '';
    if ( -d '/var/qmail' ) {
	debug("\n Found /var/qmail directory");
	$qmail_home = '/var/qmail';
	$qmail_installed = 1;
    }
    else {
	$qmail_home = `qmail-home`;
	if ( $qmail_home ne '') {
	    debug("\n Found qmail home directory at $qmail_home (using qmail-home program)");
	    $qmail_installed = 1;
	}
    }

    if ( -d '/var/spool/qmail' ) {
	debug("\n Found qmail spool directory at /var/spool/qmail");
	$qmail_installed = 1;
    }
    if ( -d '/etc/qmail' ) {
	debug("\n Found qmail control directory at /etc/qmail");
	$qmail_installed = 1;
    }
    
    if ( (-r '/etc/inetd.conf') and `fgrep -q qmail-smtpd /etc/inetd.conf` ) {
	debug("\n Found reference to qmail-smtpd in /etc/inetd.conf");
	$qmail_installed = 1;
    }
    if ( (-r '/etc/xinetd.conf') and `fgrep -q qmail-smtpd /etc/xinetd.conf` ) {
	debug("\n Found reference to qmail-smtpd in /etc/xinetd.conf");
	$qmail_installed = 1;
    }

    if ( -x '/etc/init.d/qmail' ) {
	debug("\n Found /etc/init.d/qmail script");
	$qmail_installed = 1;
    }
    elsif ( `fgrep -q qmail-start /etc/init.d/*` ) {
	debug("\n Found reference to qmail-start in /etc/init.d directory");
	$qmail_installed = 1;
    }
    if ( -x '/etc/rc.local' and `fgrep -q qmail-start /etc/rc.local` ) {
	debug("\n Found reference to qmail-start in /etc/rc.local");
	$qmail_installed = 1;
    }

    if ( `killall -0 qmail-send >/dev/null 2>&1` ) {
	debug("\n Found qmail-send process running");
	$qmail_installed = 1;
    }

    if ( $qmail_installed == 1) {
    	debug("yes.\nPre-existing qmail installation detected.  Override? [yN] ");
	$answer = <STDIN>;
	chop $answer;

	if ($answer =~ /[yY]/ ) {
		debug("Overriding.  Qmail is not installed.\n");
		$qmail_installed = 0;
	} else {
		debug("Not overriding.  Qmail is installed.\n");
		$qmail_installed = 1;
	}

    } else {
    	debug("no.");
    }

    debug("\n");
    return $qmail_installed;
}
	

$| = 1;

$action = shift;
debug("Performing $action\n");

if ( $action eq 'install' ) {
    $old_version = shift;
    if ( ! defined $old_version || $old_version eq '' ) {
	debug("First installation of the Debian qmail package...\n");
	# Check if a non-Debian qmail is installed...
	if ( is_qmail_installed() ) {
	    debug("Please remove your copy of qmail before installing the qmail Debian package.\n\n");
	    exit 1;
	}
	# Check for qmail uids and gids
	my $errors;
	
	$errors++ unless check_gid('qmail', 64010, ());
	#$errors++ unless check_gid('nogroup', 65534, ());

	$errors++ unless check_uid('alias', 64010, 65534, 'qmail alias', '/var/qmail/alias', '/bin/sh');
	$errors++ unless check_uid('qmaild', 64011, 65534, 'qmail daemon', '/var/qmail', '/bin/sh');
	$errors++ unless check_uid('qmails', 64012, 64010, 'qmail send', '/var/qmail', '/bin/sh');
	$errors++ unless check_uid('qmailr', 64013, 64010, 'qmail remote', '/var/qmail', '/bin/sh');
	$errors++ unless check_uid('qmailq', 64014, 64010, 'qmail queue', '/var/qmail', '/bin/sh');
	$errors++ unless check_uid('qmaill', 64015, 65534, 'qmail log', '/var/qmail', '/bin/sh');
	$errors++ unless check_uid('qmailp', 64016, 65534, 'qmail pw', '/var/qmail', '/bin/sh');
	#$errors++ unless check_uid('nobody', 65534, 65534, 'nobody', '/tmp', '/bin/sh');

	if ( $errors ) {
	    debug("\n$errors entries have errors. Please correct these errors and reinstall qmail.\n");
	    exit 2;
	}
    }

    # Make sure there are no smtp entries in /etc/inetd.conf
    # Kludge around smail buggy /etc/inetd.conf handling. (Grr.)
    my $fixed_smail = 0;
    my $found_commented = 0;
    my $found_uncommented = 0;
    my $new_inetd = "/etc/inetd.conf.qmail-preinst.$$";
    open I, '</etc/inetd.conf' or die "Could not open /etc/inetd.conf\n";
    open N, ">$new_inetd" or die "Could not create $new_inetd\n";
    while (<I>) {
	if ( m|^\# *smtp\s+.*/usr/sbin/in.smtpd.*\(will be restored by smail postinst\)\s*$| ) {
                $fixed_smail = 1;
		next;
            } elsif ( m/^\# *smtp\s+/ ) {
                $found_commented= 1;
            } elsif ( m/^smtp\s+/ ) {
                $found_uncommented= 1;
            }
	print N or die "Cannot write to $new_inetd\n";
	}
    close N or die "Could not close $new_inetd\n";
    close I or die "Could not close /etc/inetd.conf\n";
    if ( $found_commented or $found_uncommented ) {
	debug("Your /etc/inetd.conf already containts entries for the SMTP service.\n");
	debug("Please remove all SMTP entries from /etc/inetd.conf (even those commented out)\n");
	debug("and reinstall the qmail package.\n\n");
	exit 1; 
    }
    if ( $fixed_smail ) {
	debug("Removing commented smtp entry left by buggy version of smail postinst... ");
	rename "$new_inetd", '/etc/inetd.conf' or die "failed!\n";
	debug("done.\n");
    }
} elsif ($action eq 'upgrade') {
    $old_version = shift;
     if ($old_version =~ /1.03/ ) {
     	debug("You are upgrading from version 1.03 \n");
	debug("Checking control files ... \n");
	if (-l "/var/qmail/control") {
		debug("Control files installed in /etc/qmail\n");
	} else {
		debug("Control files installed in /var/qmail/control \n");
		debug("Moving control files from /var/qmail/control to /etc/qmail \n");
		`tar -cSpf - -C /var/qmail/control . | tar -xvSpf - -C /etc/qmail && rm -rf /var/qmail/control`;
	}
	debug("Checking alias files location ... \n");
	if (-d "/usr/lib/qmail/alias") {
		debug("Alias files found in /usr/lib/qmail ... moving ...\n");
		debug("Copying /usr/lib/qmail/alias to /var/lib/qmail/alias \n");
		`tar -cSpf - -C /usr/lib/qmail/alias/ . | tar -xvSpf - -C /var/lib/qmail/alias`;
		debug("I have left the files in /usr/lib/qmail/alias.\n");
		debug("You can remove them to free up space.\n");
	}
     }
}

exit 0;
