#! /usr/bin/perl

#
#  Post-Installation script to complete the installation process.
#
#  In case of e.g. Solaris pkg systems, this should be run as one of
#  post-installation steps at those packages!
#
#  - To move into place (conditionally) various prototype files
#  - To fill in configuration information into MAILSHARE/db/
#    files, if nothing in there to begin with...
#

# - MAILSHARE/forms/proto       --> MAILSHARE/forms (conditionally)
# - MAILSHARE/proto/*.{conf,cf} --> MAILSHARE/      (conditionally)
# - MAILSHARE/cf/proto/*.cf     --> MAILSHARE/cf/   (conditionally)
# - MAILVAR/db/proto/*          --> MAILVAR/db/     (conditionally)



# ------------------------------------------
# Common file comparison sub-program
# Args: - base directory 
#

sub compare_files {
    local ($DIR) = @_;
    local ($x);

    chdir "${DIR}/proto" || die ("Can't chdir('${DIR}/proto/')");

    opendir DH, "." || die ("Opendir('.') failed!");
    local(@files) = readdir(DH);
    closedir(DH);

    foreach $x (@files) {
	next if ($x eq '.' || $x eq '..');
	next if ($x =~ m/^.*\.md5$/o);

	& compare_file($x);
    }
}


sub compare_file {
    local($x) = @_;
    local($s1,$s2,$y);

    if ( ! -f "${x}.md5" ) {
	if ( ! -f "../${x}" ) {
	    # A new file, easy to know that we can recalc the MD5SUM.
	    rename("$x", "../$x");
	    system("$MD5SUM -b ../$x > $x.md5");
	} else {
	    # Don't overwrite!
	    if ( $STYLE eq 'OLD') {
		if (!system("cmp -s $x ../$x")) {
		    # MATCH of the files
		    system("$MD5SUM -b ../$x > $x.md5");
		} else {
		    # Non-match of the files, sum the NEW file!
		    system("$MD5SUM -b $x > $x.md5");
		}
	    } else {
		printf "File exists, but no MD5 sum?? $DIR/$x\n";
		# Sum the NEW file
		system("$MD5SUM -b $x > $x.md5");
	    }
	}
    }
    if ( -f "$x" && -f "${x}.md5" ) {
	# Still file exists, destination has this file ??
	# Lets compare MD5 sums
	# Destination file
	local($md1,$md2,$l,$junk);
	$l=`$MD5SUM -b "../$x"`;
	($md1,$junk) = split(' ',$l);
	# And its associated MD5 signature file
	$l=`cat $x.md5`;
	($md2,$junk) = split(' ',$l);
	# printf "File: $x MD1=$md1 MD2=$md2\n";
	if ( $md1 eq $md2 ) {
	    # They do match! We overwrite old file with new
	   unlink("../$x");
	   rename("$x", "../$x");
	   system("$MD5SUM -b ../$x > $x.md5");
	}
    }
    if ( -f "$x" ) {
	$y = $x;
	$y =~ s!/proto/!/!;
	printf "File $DIR/$y has mismatching MD5 sum.\n";
	printf "    won't overwrite it with $DIR/$x.\n";
    }
}


# ----------  POSTOFFICE DIRECTORY BUILDER ------------

sub dirprealloc {
    local($DIR,$DSIZE,$DFILES) = @_;
    local(@st);

    $DSIZE *= 1000;

    local($NAME) = "filenamefilenamefilenamefilenamefilenamefilenamefilenamefilenamefilename";

    local($NUM) = 2;
    open(OFP, "> $DIR/filename.0");
    close(OFP);

    # Just in case the names in directories are limited...
    $NAME = "filenam" unless(link("$DIR/filename.0","$DIR/$NAME.1"));

    @st = stat("${DIR}/."); # Can't fail ( -- eh ? )
    local($SIZE) = $st[7];

    while ($SIZE < $DSIZE && $NUM < $DFILES) {
	# Link as long as you can -- or size is desired..
	link("$DIR/filename.0","$DIR/$NAME.$NUM") || last;

	@st = stat("${DIR}/."); # Can't fail ( -- eh ? )
	$SIZE = $st[7];

	++$NUM;
    }


    # Now clean up after allocations..
    
    opendir DH, "$DIR/." || die ("Opendir('$DIR/.') failed!");
    local(@files) = readdir(DH);
    closedir(DH);
    local($x);
    foreach $x (@files) {
	next if ($x eq '.' || $x eq '..');
	unlink("$DIR/$x");
    }
}

sub mkpostofficedir {
    local($DIR,$MOD,$HASH,$DSIZE,$DFILES) = @_;

    $MOD = 02000 + oct($MOD);

    chdir($POSTOFFICE);
    if ( ! -d "${DIR}/." ) {

	printf "Constructing dir: %s hash=%s\n",$DIR,$HASH;

	mkdir $DIR, $MOD || die "mkdir ${DIR} failed!";
	chmod $MOD, $DIR || die "chmod ${DIR} failed!";
	& dirprealloc($DIR, $DSIZE, $DFILES);
	local($xx,$yy);
	if ($HASH eq 'HASH') {
	    foreach $xx ('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z') {
		mkdir "$DIR/$xx", $MOD || die "mkdir ${DIR}/$xx failed!";
		chmod $MOD, "$DIR/$xx" || die "chmod ${DIR}/$xx failed!";
		& dirprealloc("$DIR/$xx", $DSIZE, $DFILES);
	    }
	}
	if ($HASH eq 'HASH2') {
	    foreach $xx ('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z') {
		mkdir "$DIR/$xx", $MOD || die "mkdir ${DIR}/$xx failed!";
		chmod $MOD, "$DIR/$xx" || die "chmod ${DIR}/$xx failed!";
		& dirprealloc("$DIR/$xx", $DSIZE, $DFILES);
	    }
	    foreach $xx ('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z') {
		foreach $yy ('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z') {
		    mkdir "$DIR/$xx/$yy", $MOD || die "mkdir ${DIR}/$xx/$yy failed!";
		    chmod $MOD, "$DIR/$xx/$yy" || die "chmod ${DIR}/$xx/$yy failed!";
		    & dirprealloc("$DIR/$xx/$yy", $DSIZE, $DFILES);
		}
	    }
	}
    }
}

# -----------------  pick_zenv() ----------------------

sub pick_zenv {

    my ($ZCONFIG) = '/etc/zmailer/zmailer.conf';

    open(ZZ, "< ".$ZCONFIG) || die "No ZCONFIG file at '$ZCONFIG'";
    while (<ZZ>) {
	chomp;
	local($n,$l) = split(/=/,$_,2);
	$ZENV{$n} = $l  if ($n =~ m/^[A-Z0-9a-z]/);
    }
    close(ZZ);
}

# ------------------  MAIN PROGRAM --------------------

$MKDIR = "mkdir -p";
%ZENV  = ();

& pick_zenv();

$POSTOFFICE = $ZENV{'POSTOFFICE'};
$MAILSHARE  = $ZENV{'MAILSHARE'};
$MAILVAR    = $ZENV{'MAILVAR'};
$MAILBIN    = $ZENV{'MAILBIN'};

die "Failed to pick POSTOFFICE from /etc/zmailer/zmailer.conf !?"
    if (!defined $POSTOFFICE || $POSTOFFICE eq '');

$MD5SUM = "/usr/bin/md5sum";

$STYLE = '';
if ($ARGV[0] eq '-MD5') {
    $STYLE = 'MD5';
    shift @ARGV;
} elsif ($ARGV[0] eq '-OLDSTYLE') {
    $STYLE = 'OLD';
    shift @ARGV;
} else {
    printf "post-install.sh [-MD5|-OLDSTYLE]\n";
    exit 1;
}

if ($STYLE eq '') {
    printf "post-install.sh [-MD5|-OLDSTYLE]\n";
    printf " On first time around, it is SUGGESTED that you use\n";
    printf " the  -OLDSTYLE   option....\n";
    exit 1;
}

# trap 'echo "Directory access failure; DIR=$DIR/proto"' 0

# exit 99 # Sorry, not yet!

if ( ! -d "$MAILSHARE/bak" ) {
    system("$MKDIR $MAILSHARE/bak");
}

foreach $x ("$MAILSHARE", "$MAILSHARE/forms", "$MAILSHARE/cf", "$MAILVAR/db") {
    & compare_files($x);
}

# ----------------------------
#    Database prototypes ???

foreach $x (qw("$MAILSHARE/proto/router.cf $MAILSHARE/proto/scheduler.conf
	 $MAILSHARE/proto/smtpserver.conf  $MAILSHARE/proto/sm.conf
	 $MAILSHARE/proto/smtp-tls.conf
	 $MAILVAR/db/proto/dbases.conf
	 $MAILVAR/db/proto/aliases         $MAILVAR/db/proto/localnames
	 $MAILVAR/db/proto/fqdnaliases     $MAILVAR/db/proto/routes
	 $MAILVAR/db/proto/smtp-policy.src $MAILVAR/db/proto/smtp-policy.mx
	 $MAILVAR/db/proto/smtp-policy.relay")) {

    $y = $x;
    $y =~ s!/proto/!/!;
    if ( -f $x ) {
	printf "**** Verify  $y  file!\n"
	    unless (system("cmp -s $x $y"));
    }
}

system("$MAILBIN/zmailer newdb");

system("$MAILBIN/policy-builder.sh -n");

if (! -d "$POSTOFFICE/.") {
    system("$MKDIR -p $POSTOFFICE");
}
system("chmod 2755 $POSTOFFICE/.");
system("chmod g+s $POSTOFFICE/.");

#  subdir protchmod "no"/"HASH"/"HASH2" dirpreallocsize
& mkpostofficedir('deferred',     '750', 'no',    6, 9999);
& mkpostofficedir('TLSsrvrcache', '700', 'HASH',  6, 9999);
& mkpostofficedir('TLSclntcache', '700', 'HASH',  6, 9999);
& mkpostofficedir('freezer',      '750', 'no',    6, 9999);
& mkpostofficedir('postman',      '750', 'no',    6, 9999);
& mkpostofficedir('public',      '1777', 'no',    6, 9999);
& mkpostofficedir('queue',        '750', 'HASH2', 6, 9999);
& mkpostofficedir('transport',    '750', 'HASH2', 6, 9999);
& mkpostofficedir('router',      '1777', 'HASH',  6, 9999);

printf "
***
*** Remember to verify input databases, and then execute commands:
***    $MAILBIN/zmailer newdb
***    $MAILBIN/policy-builder.sh (-n)
***
";

#trap "" 0
exit 0;

1;
