#!/usr/local/bin/perl
#
# add-alias [-r] [-o owner] [-f file] [-c comment] alias value
#
# This script will add a sendmail alias to the system
# alias file.  If the alias already exists, it will not
# be added, unless the -r (replace) option is given.
#
# To specify a non-standard path for the system aliases
# use `-f file'
#
# $Id: add-alias,v 1.2 1993/11/12 06:51:08 aks Exp $
# $Source: /fs/dokoka/home/aks/src/mail/majordomo/RCS/add-alias,v $
#
require 'shlock.pl';

($PROG = $0) =~ s=^.*/==;	# get basename

while (@ARGV && substr($ARGV[0],0,1) eq '-') {
    $_ = shift;
    /^-f(.*)/ && do { 
	$file = $1 || shift || 
	    die "$PROG: Missing argument for -f option.\n";
	-e $file || die "$PROG: file $file does not exist.\n";
	-f _ || die "$PROG: file $file is not a plain file.\n";
	-w _ || $debug || die "$PROG: file $file cannot be updated.\n";
	next;
    };
    /^-o(.*)/ && do {
	$owner = $1 || shift ||
	    die "$PROG: Missing argument for -o option.\n";
	$owner =~ s/<(.*)>/\1/g;	# clean up
	$owner =~ /^[-.\w]+@[-.\w]+$/ ||
	    die "$PROG: Bad email address: \"$owner\"; use \"login@host.domain\"\n";
	next;
    };
    /^-c(.*)/ && do {
	$comment = $1 || shift ||
	    die "$PROG: Missing argument for -c option.\n";
	next;
    };
    /^-r/ && do { $replace++; next; };
    /^-d/ && do { $debug++; next; };
    /^-v/ && do { $verbose++; next; };
    die "$PROG: unknown option: $_\n";
}

$alias = shift(@ARGV);		# get the alias
$value = join(' ',@ARGV);	# get the rest of the line

$alias && $value || 
    die "usage: $PROG [-r] [-d] [-f file] [-o owner] [-c comment] alias value\n";

# do some sanity/security checks -- don't let this script be
# used to change certain really important aliases.

if ($alias =~ /^postmaster$|^root$|^mailer-daemon$|^uucp$/i) {
    die "$PROG: sorry, the alias \"$alias\" must be changed manually.\n";
}

$file = '/usr/lib/aliases' unless $file;
if ($debug) {
    $temp = '/usr/tmp/aliases';
    unless (-f $temp) {
	print STDERR "Copying $file to $temp...\n";
	system("cp $file $temp");
    }
    $file = $temp;
}
$old = "$file.old";
$new = "$file.new";

&lopen(ALIASES,'',$file) || die "Couldn't lock $file: $!\n";
open(NEW,">$new") || &Die("Open \">$new\" failed: $!");
while (<ALIASES>) {
    if (/^$alias:/) {		# look for the alias
	$found++;		# found it
	print STDERR "Found alias \"$alias\": " if $verbose;
	if ($replace) {
	    $old_comment .= $preceding_comment;
	    $preceding_comment = '';	# throw away the preceding comments
	    $junk++;
	    print STDERR "replacing..\n";
	    next;		# and don't print it
	}
	print STDERR "not changed.\n";
	$junk = '';
    } elsif ($owner && /^owner-$alias:/) {
	$old_owner = $_;
	print STDERR "Found alias \"owner-$alias\": " if $verbose;
	if ($replace) {		# replacing it?
	    $old_comment .= $preceding_comment;
	    $preceding_comment = '';	# throw away the comments before it
	    $junk++;
	    print STDERR "replacing..\n";
	    next;		# and don't print it
	}
	print STDERR "not changed.\n";
	$junk = '';
    } elsif (/^#/) {
	$preceding_comment .= $_;
	next;
    } elsif (/^\s+\S/ && $junk) {	# are we throwing something away?
	next;			# keep trashing it
    } else {
	$junk = '';		# no more junk
    }
    if ($preceding_comment) {	# dump any collected preceding comments
	print NEW $preceding_comment;
	$preceding_comment = '';
    }
    print NEW;
}
print NEW $preceding_comment if $preceding_comment;
if (!$found || $replace) {
    if ($comment) {		# new comments?
	print STDERR "Adding comment for alias \"$alias\"..\n" if $verbose;
	print NEW "#\n";
	print NEW "# $comment\n" if $comment;
	print NEW "#\n";
    } elsif ($found && $old_comment) {	# don't lose the old comment
	print STDERR "Using previous comment for alias \"$alias\"..\n" if $verbose;
	print NEW $old_comment;
    }
    print NEW $alias.": ".$value."\n";
    if ($owner) {
	print NEW "owner-$alias: ".$owner."\n";
    } elsif ($old_owner) {
	print NEW $old_owner;	# don't forget previous owner
    }
    close NEW;
    unlink $old;
    rename($file,$old) || &Die("rename(\"$file\",\"$old\") failed: $!");
    rename($new,$file) || &Die("rename(\"$new\",\"$file\") failed: $!");
} else {
    close NEW;
    unlink $new;
}
&lclose(ALIASES);
print STDERR "Output left in $file\n" if $debug;
exit;

sub Die {
    local($msg) = shift;
    local($num) = $!;
    $msg .= "\n" unless substr($msg,-1,1) eq "\n";
    warn $msg;
    &lclose(ALIASES);
    close NEW;
    unlink $new;
    exit($num || -1);
}
