#!/usr/bin/perl --
# Semiautomatic configuration script for Debian's Exim package.
# Used after installation to configure a mail system, and can be run
# at any later time (though --force may be needed).
# Copyright 1994 Ian Jackson.  There is NO WARRANTY.
# Modified for exim by Tim Cutts.  Still NO WARRANTY!
# See /usr/doc/exim for more information.

$|=1;

$etc='/etc';

if ($ARGV[0] eq '--force') { $force=1; shift; }

if (-f "$etc/exim.conf") {
    if ($force) {
        print "Ignoring existing exim configuration. Previous versions of\n";
	print "/etc/exim.conf, /etc/aliases and /etc/mailname will be kept,\n";
	print "suffixed with .O";
    } else {
        print "Your mail system (exim) is already configured; I\'ll leave\n";
	print "the existing configuration untouched.\n\n";
	print "Use --force to ignore it.\n";
        exit(0);
    }
}

$rfc1035_label_re= '[A-Za-z]([-0-9A-Za-z]*[0-9A-Za-z])?';
$rfc1035_domain_re= "$rfc1035_label_re(\\.$rfc1035_label_re)*";
$rfc1035_domain_explain=
    "Each component must start with a letter, end with an alphanum and ".
    "contain\n only alphanums and hyphens.  Components must be separated ".
    "by full stops.";

chop($syshostname=`hostname --fqdn`);
$? && die "hostname --fqdn gave non-zero exit code $?   $syshostname\n";

if ($syshostname !~ m/^$rfc1035_domain_re$/) {
    print STDERR
	"Error: system's FQDN hostname ($syshostname) doesn't match\n".
	    "RFC1035 syntax; cannot configure the mail system.\n";
    exit(1);
}

open(P,"</etc/passwd") || die "cannot read /etc/passwd: $!\n";
@passwd1=@passwd2=<P>;
close(P);

@redirusers= grep(s/^(\w+):([^:]+):(\d+):\d+:.*\n/$1/ &&
                  length($2) < 13 && $3 < 100, @passwd1);

$defaultpostmaster= (grep(s/^(\w+):([^:]+):(\d+):\d+:.*\n/$1/ &&
                          length($2) >= 13 && $3 >= 100, @passwd2))[0];

$redirinmessage= join(' ',@redirusers);
push(@redirusers,'');
$redirinalias= join(": root\n",@redirusers);

sub inetde {
    do {
        print @_,
	"Do you want to ignore this potential problem and configure your\n".
	    "mail system anyway, or would you rather not do so now ?\n".
		"Configure now ?  (n/y) ";
	
	$!=0; defined($response=<STDIN>) || die "eximconfig: EOF/error on stdin: $!\n";
    } while ($response !~ m/^\s*[yn]?\s*$/i);
    $response =~ m/y/i || exit 1;
}


for (;;) {

    undef @files;


# Which major configuration ?
    next unless &query(
"I can do some automatic configuration of your mail system, by asking you
a number of questions.  Later you may to confirm and/or correct your answers.
In any case, comprehensive information on configuring exim is in the eximdoc
package and in /usr/doc/exim/spec.txt

You must choose one of the options below:

 (1) Internet site: you send and receive Internet mail on this
     machine, using SMTP over TCP/IP.

 (2) Satellite system
     All mail is sent to a smart host for delivery, following processing by
     aliases and/or .forward files.  root and postmaster mail is delivered
     according to /etc/aliases.

 (3) Local delivery only:
     You are not on a network.  Mail for local users is delivered.

 (4) No configuration:
     No configuration will be done now; your mail system will be broken and
     should not be used.  You must then do the configuration yourself later or
     run this script, /usr/sbin/eximconfig, as root.

Select a number from 1 to 4, from the list above.",
           'configtype',
           -f '/usr/sbin/inetd' ? '1' : '3',
           'm/^[1234]$/');

    if ($configtype == 4) {
        print "\nMail configuration skipped.\n";
	print "WARNING: Do not start exim until you have configured it!\n";
	print "A bare bones configuration can be found in /usr/doc/exim/example.conf\n";
        exit 0;
    }

    if ($configtype < 3 && !(-x '/usr/sbin/inetd')) {
        print "Warning!  You don't appear to have a TCP/IP system installed.";
	print "Your mailer will not be able to use SMTP without it.\n\n";
    } 

# What are the hostnames for this system ?
    &query(
"What is the `visible' mail name of your system ?
This will appear on From: lines of outgoing messages,
unless you are setting up as a satellite system, in
which case it should be this system's name.",
           'visiblename',
           $syshostname,
           'm/^$rfc1035_domain_re$/ ||
            &reswarn("This must conform to RFC1035\'s requirements.\n".
                     "$rfc1035_domain_explain")') || next if $configtype < 3;

    $visiblename= $syshostname if $configtype == 3;

    &setfileshort("mailname","$visiblename\n");
    
    &query(
"Does this system have any other names which may appear on incoming
mail messages, apart from the visible name above ($visiblename)
and the system's hostname ($syshostname) ?
If so enter them here, separated with spaces or commas.  If there are
none, say \`none'.",
           'hostnames',
           'none',
           '1', 'e') || next if $configtype < 3;
    @names= $configtype < 3 ? split(/[ \t,]+/,$hostnames) : ();

    $warnexh= 0;
    
    grep(((m/^$rfc1035_domain_re$/ ||
           ($warnexh= 1,
            (print STDERR "\n Warning - name \`$_' doesn't conform to RFC1035".
                          " requirements.")))),
         @names);

    if ($warnexh) { print STDERR "\n$rfc1035_domain_explain\n"; }
    
    unshift(@names, $visiblename);

    if ($configtype == 2){

# If we are a satellite system, where is mail to go?
RR:	&query(
"Since this is going to be a satellite system, I need to
know where to send mail for users on $syshostname; in other words
the machine on which you will read your mail.

Where will your users read their mail?",
	       'readhost',
	       '',
	       '1', '') || next;

	if (!$readhost =~ m/^$rfc1035_domain_re$/) {
	    print STDERR "\n Warning - \`$1' does not conform to RFC1035";
	    print STDERR "\n$rfc1035_domain_explain\n";
	}

	if ($readhost eq $syshostname) {
	    print STDERR "\n This is a satellite system, specify a system\n";
	    print STDERR " other than $syshostname. \n\n";
	    goto RR;
	}

RS:	&query(
"Which machine will actually will act as the smarthost and deliver mail
for and generated by $syshostname?",
	       'smtphost',
	       $readhost,
	       '1', '') || next;

	if (!$smtphost =~ m/^$rfc1035_domain_re$/){
	    print STDERR "\n Warning - name \`$_' doesn't conform to FRC1035".
		" requirements.";
	    print STDERR "\n$rfc1035_domain_explain\n";
	}

	if ($smtphost eq $syshostname) {
	    print STDERR "\n This is a satellite system, specify a system\n";
	    print STDERR " other than $syshostname. \n\n";
	    goto RS;
	}

	@rewriters = ();

	for (@names){

	    push(@rewriters,
		 "^(root|postmaster|mailer-daemon)\@$_ \$\{1\}\@in.limbo Ffr");

	    push(@rewriters,
		 "*\@$_ \$\{1\}\@$readhost Ffr");

	}

    }

    shift (@names) if $syshostname eq $visiblename;

    $colonhostnames= join(':',@names);


# Who is to receive postmaster mail ?
    &query(
"Mail for the \`postmaster' and \`root' accounts is usually redirected
to one or more user accounts, of the actual system administrators.
By default, I'll set things up so that mail for \`postmaster' and for
various system accounts is redirected to \`root', and mail for \`root'
is redirected to a real user.  This can be changed by editing /etc/aliases.

Note that postmaster-mail should usually be read on the system it is
directed to, rather than being forwarded elsewhere, so (at least one of)
the users you choose should not redirect their mail off this machine.

Which user account(s) should system administrator mail go to ?
Enter one or more usernames separated by spaces or commas .  Enter
\`none' if you want to leave this mail in \`root's mailbox - NB this
is strongly discouraged.  Also, note that usernames should be lowercase !",
           'postmasters',
           $defaultpostmaster,
           'm/^([-_a-z0-9]+[ \t,]*)*$/ ||
            &reswarn("\nUsernames must consist of lowercase alphanums, or - and _.\n")',
           'e') || next ;
    @postmasters= split(/[ \t,]+/,$postmasters);
    
    $confdescrip= 
"Mail generated on this system will have \`".( $configtype == 2 ?
"$readhost" : "$visiblename"
)."' used
as the host part (after the \@) in the From: field and similar places.
";
    $confdescrip.= "
Message-ID's, Received lines, etc. will use the system's canonical
hostname, which is currently set to $syshostname.

The following hostname(s) will be recognised as referring to this system:
 ".join(', ',@names)."\n" ;

    $confdescrip.="Mail for postmaster, root, etc. will be sent to ".
	(@postmasters ? join(', ',@postmasters) : 'root').".\n";

    if ($configtype != 2){
	$confdescrip.= "\nLocal mail is delivered.\n";
    }
    else
    {
	$fuser = $postmasters[0];

	push(@rewriters,
	     "*\@in.limbo $fuser\@$readhost Ffr");

	$rewriters = join("\n", @rewriters);
	
	for (@postmasters) {
	    $_ = "real-$_" unless /@/;
	}
    }

    $rootalias= @postmasters ? "root: ".join(',',@postmasters)."\n" : '';

    &setfile('aliases',
	     '# This is the aliases file - it says who gets mail for whom.',
	     "
postmaster: root
$rootalias
$redirinalias
mailer-daemon: postmaster");


###########################################################################
# START WRITING EXIM.CONF HERE
###########################################################################

    &setfile('exim.conf',
'# This is the main exim configuration file.',
'# General configuration here, such as local domains

'."
qualify_domain = $visiblename
local_domains = $colonhostnames
".'
local_domains_include_host = true
local_domains_include_host_literals = true
never_users = root
trusted_users = mail
'.($configtype == 1 ? "smtp_verify = true\n":'')
.'gecos_pattern = ^([^,:]*)
gecos_name = $1

received_header_text = "Received: \
          ${if def:sender_fullhost {from ${sender_fullhost} \
          ${if def:sender_ident {(${sender_ident})}}\n\t}\
          {${if def:sender_ident {from ${sender_ident} }}}}\
          by ${primary_hostname} \
          ${if def:received_protocol {with ${received_protocol}}} \
          (Exim ${version_number} #${compile_number})\n\t\
          id ${message_id} (Debian)"
end

######################################################################
#                      TRANPORTS CONFIGURATION                       #
######################################################################

local_delivery:
  driver = appendfile;
  group = mail
  mode = 0660
  file = /var/spool/mail/${local_part}

address_pipe:
  driver = pipe;

address_file:
  driver = appendfile

address_reply:
  driver = autoreply

'. ($configtype < 3 ? 
'
 # General configuration for SMTP delivery
smtp:
  driver = smtp;
':'').
'

end

######################################################################
#                      DIRECTORS CONFIGURATION                       #
######################################################################

'. ($configtype == 2 ? '
real_local:
  prefix = real-,
  driver = localuser,
  transport = local_delivery;
' : '' ). '

system_aliases:
  driver = aliasfile;
  file = /etc/aliases,
  search_type = lsearch
# user = list
# Uncomment the above line if you are running smartlist

userforward:
  no_verify,
  driver = forwardfile;
  file = .forward,
  modemask = 002,
  filter

'. ($configtype == 2 ? "
smart:
  driver = smartuser;
  new_address = \$\{local_part\}\@$readhost

" : '
localuser:
  driver = localuser,
  transport = local_delivery;

' ). '
end

######################################################################
#                      ROUTERS CONFIGURATION                         #
######################################################################

'. ($configtype == 1 ? '

# This router routes to remote hosts over SMTP using a DNS lookup with
# default options.

lookuphost:
  driver = lookuphost,
  transport = smtp;

literal:
  driver = ipliteral,
  transport = smtp;
':''). ($configtype == 2 ?  "
smarthost:
  driver = domainlist,
  transport = smtp;
  route_list = \"* $smtphost bydns_a\"
":''). ($configtype == 3 ? '

# Stand-alone system, so no routers configured.

':'').
'
end

######################################################################
#                      RETRY CONFIGURATION                           #
######################################################################

# Domain               Error       Retries
# ------               -----       -------

*                      *           F,2h,15m; G,16h,2h,1.5; F,4d,8h

end

######################################################################
#                      REWRITE CONFIGURATION                         #
######################################################################
'. ( $configtype != 2 ? '

# There are no rewriting specifications in this default configuration file.

':"
# These rewriters make sure the mail messages appear to have originated
# from the real mail-reading host.

$rewriters

").
'
# End of Exim configuration file
'
);

    if ($configtype == 1){
	$condescrip .= "
Outbound remote mail is looked up in the Internet DNS, and delivered
using that data if any is found; otherwise such messages are bounced.
";
    }

    if ($configtype == 2){
	$condescrip .= "
All mail except that for root and postmaster is being routed and delivered
via $smtphost.  root and postmaster are locally delivered.  You can force
local delivery by prefixing a user ID with \`real-\'.  This will bypass
all .forward and alias processing.  eg \"real-joe\" will be delivered locally
to user joe.
";
    }

    if ($configtype == 3){
	$condescrip .= "Any mail destined for remote addresses is bounced.";
    }

    do {
        print "\n\nThe following configuration has been entered:

$confdescrip

Is this OK ?  Hit Return or type \`y' to confirm it and install,
or \`n' to make changes (in which case we'll go round again, giving you
your previous answers as defaults.     (y/n) ";

	$!=0; defined($what=<STDIN>) || die "smailconfig: EOF/error on stdin: $!\n";
    } while ($what !~ m/^\s*[yn]?\s*$/i);
    last unless $what =~ m/^n/i;
}

sub setfileshort {
    local ($filename,$value) = @_;
    push(@files,$filename);
    $filecontents{$filename}= $value;
}

sub setfile {
    local ($filename,$value1,$value2,$d) = @_;
    chop($d=`date`);
    $v=
"$value1\
# It was originally generated by `eximconfig', part of the exim package
# distributed with Debian, but it may edited by the mail system administrator.
# This file originally generated by eximconfig at $d
# See exim info section for details of the things that can be configured here.
$value2";
    push(@files,$filename);
    $filecontents{$filename}=$v;
}

sub reswarn {
    print STDERR "$_[0]\n";
    return 0;
}

sub query {
    local ($question, $varname, $default, $check, $opts) = @_;
    local ($allowempty, $response, $e);
    print "\n";
    $allowempty= $opts =~ m/e/;
    if (eval "defined(\$$varname)") {
        $default= eval "\$$varname";
        $default='none' if $default eq '' && $allowempty;
    }
    for (;;) {
        print "$question\nEnter value (";
        print "default=\`$default', " if length($default);
        print "\`x' to restart): ";
	$!=0; defined($iread=<STDIN>) || die "smailconfig: EOF/error on stdin: $!\n";
        $_= $iread; s/^\s+//; s/\s+$//;
        return 0 if m/^x$/i;
        $_= $default if $_ eq '';
        if (!length($_)) {
            print "  Sorry, you must enter a value.\n";
            next;
        }
        $_= '' if $_ eq 'none' && $allowempty;
        $response= $_;
        last if eval $check;
        if (length($@)) {
            print STDERR "  Aargh, bug - bug - please report:\n$@\nin\n $check\n";
            last;
        } else {
            print "  Sorry, that value is not acceptable.\n";
        }
    }
    $e= "\$$varname = \$response;";
    eval $e; length($@) && die "aargh - internal error ($e): $@";
    1;
}


for $f (@files) {
    open(N,">$etc/$f.postinstnew") || die "Error creating $etc/$f.postinstnew: $!\n";
    print(N $filecontents{$f}) || die "Error writing $etc/$f.postinstnew: $!\n";
    close(N) || die "Error closing $etc/$f.postinstnew: $!\n";
}

while (defined($f= pop(@files))) {
    if ( -f "$etc/$f") {
	print "\nKeeping previous $etc/$f as $etc/$f.O\n";
	rename("$etc/$f", "$etc/$f.O") || die "Error renaming original $etc/$f: $!\n";
    }
    rename("$etc/$f.postinstnew","$etc/$f") || die "Error installing $etc/$f: $!\n";
}

print "
Configuration installed.

";

