#!/usr/bin/perl
# cpanel - autofixer/buildeximconf                Copyright(c) 2010 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

BEGIN { unshift @INC, '/usr/local/cpanel'; }

use strict;
use SafeFile                ();
use Cpanel::cPanelFunctions ();
use Cpanel::FileUtils       ();
use Cpanel::LoadFile        ();

require '/scripts/checkexim.pl';

my $cpconf = Cpanel::cPanelFunctions::loadcpconf();

my ( $eximbin, $eximversion, $hasdomainkeys ) = geteximinfo();

my $compat_add_header = 0;
if ( $eximversion < 4.62 ) {
    print "@!" x 40 . "\n";
    print "Warning, you are running an old version of exim that has known problems.  You should update to exim 4.62 or later as soon as possible.\n";
    print "@!" x 40 . "\n";
    $compat_add_header = 1;
}
my $compat_notquit = 1;
if ( $eximversion < 4.68 ) {
    print "@!" x 40 . "\n";
    print "Warning, you are running an old version of exim that cannot fight spam as well as newer versions.  You should update to exim 4.68 or later as soon as possible.\n";
    print "@!" x 40 . "\n";
    $compat_notquit = 0;
}
my $hasmaildir = int $cpconf->{'maildir'};

if ( !-e '/etc/exim.conf.dist' ) {
    print "$0: fatal: /etc/exim.conf.dist is missing\n";
    exit;
}

my $cf;
my @KILLCF;
my %CF;

#default options
my @OFF_DEFAULT_FILTERS = ( 'fail_spam_score_over_100', 'fail_spam_score_over_125', 'fail_spam_score_over_150', 'fail_spam_score_over_175' );
my @OFF_DEFAULT_ACLS = ( 'spamhaus_rbl', 'spamcop_rbl', 'spamhaus_spamcop_rbl', 'deny_spam_score_over_100', 'deny_spam_score_over_125', 'deny_spam_score_over_150', 'deny_spam_score_over_175' );
my $acl_spam_header        = '***SPAM***';
my $acl_max_spam_scan_size = 200;
my $senderverify           = 1;
my $callouts               = 1;
my $systemfilter           = '/etc/cpanel_exim_system_filter';
my $quotadiscard           = 0;
my $setsenderheader        = 0;
my $recpvrfymsg            = 1;
my $hasboxtrapper          = $cpconf->{'skipboxtrapper'} ? 0 : 1;
my $useoldspam             = 0;
my $rbl_whitelist;
my %ACLBLOCKS;
my %ACLINSERTS;
my %FILTERS;
my %ACLS;

if ( !-e '/etc/trustedmailhosts' ) {
    Cpanel::FileUtils::touchfile('/etc/trustedmailhosts');
}

if ( opendir my $acls_opts, '/usr/local/cpanel/etc/exim/acls' ) {
    while ( my $aclsblock = readdir $acls_opts ) {
        next if ( $aclsblock =~ /^\./ );
        if ( opendir my $acls_iopts, '/usr/local/cpanel/etc/exim/acls/' . $aclsblock ) {
            while ( my $acl = readdir $acls_iopts ) {
                next if $acl =~ m/^\./;
                $ACLS{$acl} = 1;
                push @{ $ACLBLOCKS{$aclsblock} }, $acl;
            }
            closedir $acls_iopts;
        }
    }
    closedir $acls_opts;
}

foreach my $acl (@OFF_DEFAULT_ACLS) {
    $ACLS{$acl} = 0;
}

if ( opendir my $filter_opts, '/usr/local/cpanel/etc/exim/sysfilter/options' ) {
    while ( my $filter = readdir $filter_opts ) {
        next if $filter =~ m/^\./;
        $FILTERS{$filter} = 1;
    }
    closedir $filter_opts;
}

foreach my $filter (@OFF_DEFAULT_FILTERS) {
    $FILTERS{$filter} = 0;
}

system '/usr/local/cpanel/bin/migratessl';    #make sure ssl certs are converted!

my $dist = 'dist';
if ( -e "/etc/exim.conf.mailman2.dist" && -e "/var/cpanel/mailman2" ) {
    if ( -e "/var/clamd" && -e "/usr/sbin/clamd" && -e "/etc/exim.conf.mailman2.exiscan.dist" ) {
        $dist = 'mailman2.exiscan.dist';
    }
    else {
        $dist = 'mailman2.dist';
    }
}

open( EXIMCOPTS, '/etc/exim.conf.localopts' );
while (<EXIMCOPTS>) {
    chomp();
    my ( $opt, $value ) = split( /=/, $_ );
    if ( $opt =~ /^acl_(\S+)/ ) {
        if ( $value eq '0' ) { $ACLS{$1} = 0; }
        if ( $value eq '1' ) { $ACLS{$1} = 1; }
    }
    elsif ( $opt =~ /^filter_(\S+)/ ) {
        if ( $value eq '0' ) { $FILTERS{$1} = 0; }
        if ( $value eq '1' ) { $FILTERS{$1} = 1; }
    }
    elsif ( $opt eq 'spam_header'        && $value && $value ne '' ) { $acl_spam_header        = $value; }
    elsif ( $opt eq 'max_spam_scan_size' && $value && $value ne '' ) { $acl_max_spam_scan_size = $value; }
    elsif ( $opt eq 'rbl_whitelist'      && $value && $value ne '' ) { $rbl_whitelist          = $value; }
    elsif ( $opt eq 'callouts'               && $value eq '0' ) { $callouts        = 0; }
    elsif ( $opt eq 'senderverify'           && $value eq '0' ) { $senderverify    = 0; }
    elsif ( $opt eq 'hiderecpfailuremessage' && $value eq '1' ) { $recpvrfymsg     = 0; }
    elsif ( $opt eq 'setsenderheader'        && $value eq '1' ) { $setsenderheader = 1; }
    elsif ( $opt eq 'useoldspam'             && $value eq '1' ) { $useoldspam      = 1; }
    elsif ( $opt eq 'systemfilter' ) { $systemfilter = $value; }
    elsif ( $opt eq 'quotadiscard' && $value eq '1' ) { $quotadiscard = 1; }
}
close(EXIMCOPTS);

if ( !$compat_notquit ) {
    $ACLS{'ratelimit'} = 0;
}

if ( !-e $systemfilter || $systemfilter eq '/etc/cpanel_exim_system_filter' ) {
    print "Enabled system filter options: ";
    my @FLOPTS;
    $systemfilter = '/etc/cpanel_exim_system_filter';
    my $filter_source_dir = '/usr/local/cpanel/etc/exim/sysfilter';
    my $flock = SafeFile::safeopen( \*ANTIV, '>', '/etc/cpanel_exim_system_filter' );
    _slurpout( $filter_source_dir . '/default', \*ANTIV );
    foreach my $filter ( keys %FILTERS ) {
        next if ( !$FILTERS{$filter} );
        push @FLOPTS, $filter;
        _slurpout( $filter_source_dir . '/options/' . $filter, \*ANTIV );
    }
    SafeFile::safeclose( \*ANTIV, $flock );
    print join( '|', @FLOPTS );
    print "\n";
}

open( EXIMD, '/etc/exim.conf.local' );
while (<EXIMD>) {
    if (/^\@([^\@]+)\@/) {
        my $oldcf = $cf;
        $cf = $1;
        $CF{$oldcf} =~ s/^[\n\r]*|[\n\r]*$//g;
    }
    elsif (/^\%([^\%]+)\%/) {
        my $oldcf = $cf;
        $cf = $1;
        $CF{$oldcf} =~ s/^[\n\r]*|[\n\r]*$//g;
    }
    else {
        if ( $cf eq 'CONFIG' && /=[\t\s]*$/ ) {
            my $optname = ( split( /=/, $_ ) )[0];
            $optname =~ s/^\s+|\s+$//g;
            push( @KILLCF, $optname );
            next();
        }
        $CF{$cf} .= $_;
    }
}
close(EXIMD);
$CF{$cf} =~ s/^[\n\r]*|[\n\r]*$//g;

my @REPLACELIST;
my %REPLACETEXT;

if ( !$CF{'ACLBLOCK'} ) {
    $CF{'ACLBLOCK'} = Cpanel::LoadFile::loadfile("/usr/local/cpanel/etc/exim/defacls/$dist");
}

foreach my $aclblock ( keys %ACLBLOCKS ) {
    my @ENABLEDACLS;
    print "Enabled ACL options in block $aclblock: ";

    foreach my $acl ( @{ $ACLBLOCKS{$aclblock} } ) {
        if ( !$ACLS{$acl} || $ACLS{$acl} eq '0' ) { next; }
        push @ENABLEDACLS, $acl;
        $ACLINSERTS{$aclblock} .= Cpanel::LoadFile::loadfile( '/usr/local/cpanel/etc/exim/acls/' . $aclblock . '/' . $acl );
    }
    print join( '|', @ENABLEDACLS );
    print "\n";
    foreach my $aclblock ( keys %ACLINSERTS ) {
        $CF{'ACLBLOCK'} =~ s/^\s*\[\s*\%\s*\Q$aclblock\E\s*\%\s*\]/$ACLINSERTS{$aclblock}/gm;
    }
}

if ( $CF{'ACLBLOCK'} !~ /^\s*acl_connect:/m ) {
    print "Disabling the ratelimit & spammerlist acl because the custom acl block prevented us from installing the acl_connect acls.\n";
    $ACLS{'spammerlist'} = 0;    #if the acls are not in the block we cannot add them
    $ACLS{'ratelimit'}   = 0;    #if the acls are not in the block we cannot add them
}

if ( $ACLS{'ratelimit'} && $CF{'ACLBLOCK'} !~ /^\s*acl_notquit:/m ) {
    print "Disabling the ratelimit acl because the custom acl block prevented us from installing the acl_notquit acls.\n";
    $ACLS{'ratelimit'} = 0;      #if the acls are not in the block we cannot add them
}

my %ACL_OPTS;
$ACL_OPTS{'ACL_MAX_SPAM_SCAN_SIZE'} = int $acl_max_spam_scan_size || 200;
$ACL_OPTS{'ACL_SPAM_HEADER'}        = $acl_spam_header            || '***SPAM***';
$ACL_OPTS{'ACL_RBL_WHITELIST'}      = '';

if ($rbl_whitelist) {
    my @hostlist = split( /[\;\,\:\s]+/, $rbl_whitelist );
    if (@hostlist) {
        $ACL_OPTS{'ACL_RBL_WHITELIST'} = '     ! hosts = ' . join( ' : ', @hostlist );
    }
}

foreach my $aclblock ( keys %ACL_OPTS ) {
    $CF{'ACLBLOCK'} =~ s/\[\s*\%\s*\Q$aclblock\E\s*\%\s*\]/$ACL_OPTS{$aclblock}/gm;
}

$CF{'ACLBLOCK'} =~ s/^\s*\[\s*\%\s*[^\%]+\s*\%\s*\]//gm;    #remove any missing ones

if ($useoldspam) {
    my @ACLB     = split( /\n/, $CF{'ACLBLOCK'} );
    my $blkstart = 0;
    my $skipacl  = 0;
    my $line     = 0;
    my %KL;
    foreach my $acll (@ACLB) {
        if ( $acll =~ /^\s*$/ ) {
            $blkstart = 0;
            $skipacl  = 0;
        }
        elsif ($skipacl) {
            $KL{$line} = 1;
        }
        elsif ( $blkstart == 0 ) {
            $blkstart = $line;
        }
        if ( $acll =~ /^\s*spam\s*=\s*/ || $acll =~ /^\s*add_header\s*=\s*\"?\'?X-Spam-Status/ || $acll =~ /perl\{(acl_checksa_deliver|acl_checkusersa)/ ) {
            $skipacl = 1;
            for ( my $i = $blkstart; $i <= $line; $i++ ) {
                $KL{$i} = 1;
            }
        }
        $line++;
    }
    if ( ( scalar keys %KL ) ) {
        foreach my $line ( sort { $a <=> $b } keys %KL ) {
            print qq{[useoldspam -- deleting line: $line] "$ACLB[$line]"\n};
            $ACLB[$line] = '';
        }
        $CF{'ACLBLOCK'} = join( "\n", @ACLB );
    }
}

if ( $CF{'ACLBLOCK'} =~ /^\s*spam\s*=/m ) {
    print "Detected spam handling in acls, disabling spamassassin in routers & transports!.\n";
    if ( !-e '/etc/exim.aclspam' ) {
        open( my $exim_spam2fh, '>', '/etc/exim.aclspam' );
        close($exim_spam2fh);
        print "Running /usr/local/cpanel/bin/vfilterfix --force\n";
        system( '/usr/local/cpanel/bin/vfilterfix', '--force' );
    }
    else {
        print "SpamAssassin method remains unchanged\n";
    }
    my @DISABLE = ( "virtual_sa_user", "sa_localuser", "virtual_sa_userdelivery", "local_sa_delivery" );
    foreach my $sec (@DISABLE) {
        $REPLACETEXT{$sec} = "\n        \n";
    }
    push @REPLACELIST, @DISABLE;
}
else {
    if ( -e '/etc/exim.aclspam' ) {
        unlink('/etc/exim.aclspam');
        print "Running /usr/local/cpanel/bin/vfilterfix --force\n";
        system( '/usr/local/cpanel/bin/vfilterfix', '--force' );
    }
    else {
        print "SpamAssassin method remains unchanged\n";
    }
}

if ($recpvrfymsg) {
    foreach my $cf ( keys %CF ) {
        if (   $cf =~ /ACL/
            && $CF{$cf} =~ /^[\s\t]*message[\s\t]*=[\s\t]*\"The recipient cannot be verified.*/m ) {
            $CF{$cf} =~ s/^[\s\t]*message[\s\t]*=[\s\t]*\"The recipient cannot be verified.*//gm;
        }
    }
}

if ( !$senderverify ) {
    foreach my $cf ( keys %CF ) {
        if ( $cf =~ /ACL/ && $CF{$cf} =~ /^[\s\t]*require[\s\t]*verify[\s\t]*=[\s\t]*sender/m ) {
            $CF{$cf} =~ s/^[\s\t]*require[\s\t]*verify[\s\t]*=[\s\t]*sender.*//gm;
        }
    }
}

if ($compat_add_header) {
    foreach my $cf ( keys %CF ) {
        if ( $cf =~ /ACL/ && $CF{$cf} =~ /^\s*add_header/m ) {
            $CF{$cf} =~ s/^(\s*)add_header/$1message/mg;
        }
    }
}

if ( !$callouts ) {
    foreach my $cf ( keys %CF ) {
        if ( $cf =~ /ACL/ && $CF{$cf} =~ /^[\s\t]*require[\s\t]*verify[\s\t]*=[\s\t]*/m ) {
            $CF{$cf} =~ s/\/callout=?\d*s?//g;
        }
    }
}

if ($quotadiscard) {
    $CF{'RETRYSTART'} =~ s/.*quota.*//gm;
    $CF{'RETRYSTART'} = "*\t\t\tquota\n" . $CF{'BEGINRETRY'};
}

my @CCONF = split( /\n/, $CF{'CONFIG'} );
foreach my $cfopt (@CCONF) {
    if ( $cfopt =~ /=/ ) {
        my ($optname);
        ( $optname, undef ) = split( /=/, $cfopt );
        $optname =~ s/^\s+|\s+$//g;
        push( @KILLCF, $optname );
    }
}
print "Configured options list is: " . join( '|', @KILLCF ) . "\n";

my @CONFIG_OPTS;
my @PROVIDEDOPTS;
open( my $opt_fh, '/usr/local/cpanel/etc/exim/config_options' );
while ( my $cfopt = readline($opt_fh) ) {
    push @CONFIG_OPTS, $cfopt;
}
close($opt_fh);

my $test_acl;
my $in_acl;
my %HAS_ACL_CONTENT;
my %ACL_CONTENT;
my @ACL_BLOCK = split( /\n/, $CF{'ACLBLOCK'} );
foreach (@ACL_BLOCK) {
    if (/^\s*([^\s\:]+):\s*$/m) {
        $test_acl                   = $1;
        $HAS_ACL_CONTENT{$test_acl} = 0;
        $in_acl                     = 1;
    }
    elsif ( /^\s*\#/ || /^\s*$/ ) {
        next;
    }
    elsif ($in_acl) {
        $ACL_CONTENT{$test_acl} .= $_;
        $HAS_ACL_CONTENT{$test_acl} = 1;
    }
}

if ( $HAS_ACL_CONTENT{'acl_connect'} ) {
    if ( $ACL_CONTENT{'acl_connect'} !~ m/accept[\n\s\r]*$/ ) {
        print "acl_connect not installed because it does not have an accept at the end.\n";
    }
    else {
        push @CONFIG_OPTS, 'acl_smtp_connect = acl_connect';
    }
}
else {
    print "acl_connect is empty.. excluding this acl.\n";
}

if ( $HAS_ACL_CONTENT{'acl_notquit'} ) {
    push @CONFIG_OPTS, 'acl_smtp_notquit = acl_notquit';
}
else {
    print "acl_notquit is empty.. excluding this acl.\n";
}

while ( my $cfopt = shift(@CONFIG_OPTS) ) {
    if ( $cfopt =~ /=/ ) {
        my ($optname);
        ( $optname, undef ) = split( /=/, $cfopt );
        $optname =~ s/^\s+|\s+$//g;
        if ( !grep( /^\Q$optname\E$/, @KILLCF ) ) {
            $CF{'CONFIG'} .= "\n$cfopt\n";
            push( @PROVIDEDOPTS, $optname );
            push( @KILLCF,       $optname );
        }
    }
}

push @PROVIDEDOPTS, "spamd_address";
push @KILLCF,       "spamd_address";
if ( -e "/var/run/spamd.sock" ) {
    $CF{'CONFIG'} .= "\nspamd_address = /var/run/spamd.sock\n";
}
else {
    $CF{'CONFIG'} .= "\nspamd_address = 127.0.0.1 783\n";
}

print "Provided options list is: " . join( '|', @PROVIDEDOPTS ) . "\n";

if ( -e '/etc/myexim.key' && -e '/etc/myexim.crt' ) {
    push( @KILLCF, 'tls_certificate' );
    push( @KILLCF, 'tls_privatekey' );
    $CF{'CONFIG'} .= "\ntls_certificate = /etc/myexim.crt\n";
    $CF{'CONFIG'} .= "\ntls_privatekey = /etc/myexim.key\n";
    print "Using user installed ssl certificate in key (/etc/myexim.key & /etc/myexim.crt)\n";
}

push( @KILLCF, 'system_filter' );
if ( $CF{'CONFIG'} =~ m/^[\s\t]*system_filter=.*/m ) {
    if ( $systemfilter eq '' ) {
        $CF{'CONFIG'} =~ s/^[\s\t]*system_filter=.*//gm;
    }
    else {
        $CF{'CONFIG'} =~ s/^[\s\t]*system_filter=.*/system_filter=${systemfilter}/gm;
    }
}
else {
    if ( $systemfilter ne '' ) {
        $CF{'CONFIG'} .= "\nsystem_filter=${systemfilter}\n\n";
    }
}

if ($setsenderheader) {
    push( @KILLCF, 'local_from_check' );
    if ( $CF{'CONFIG'} =~ m/^[\s\t]*local_from_check.*/m ) {
        if ( $systemfilter eq '' ) {
            $CF{'CONFIG'} =~ s/^[\s\t]*local_from_check.*//gm;
        }
        else {
            $CF{'CONFIG'} =~ s/^[\s\t]*local_from_check.*/local_from_check = true/gm;
        }
    }
    else {
        if ( $systemfilter ne '' ) {
            $CF{'CONFIG'} .= "\nlocal_from_check = true\n";
        }
    }
}

my @INSERTS;
if ( opendir my $inserts_dh, '/usr/local/cpanel/etc/exim/cf' ) {
    @INSERTS = readdir $inserts_dh;
    @INSERTS = grep !/^\./, @INSERTS;
    closedir $inserts_dh;
}

my @INSERTLIST;
my %INSERTTEXT;
foreach my $insert (@INSERTS) {
    next if ( $insert eq 'virtual_sa_user' && !$quotadiscard );    #the virtual_user_maildir_overquota router is in this file actually

    next if ( -B '/usr/local/cpanel/etc/exim/cf/' . $insert );
    open( INST, '/usr/local/cpanel/etc/exim/cf/' . $insert );
    push( @INSERTLIST, $insert );
    while (<INST>) {
        $INSERTTEXT{$insert} .= $_;
    }
    $INSERTTEXT{$insert} =~ s/[\r\n]+$//g;
    close(INST);
}
my $insertregex = join( '|', @INSERTLIST );

print "Exim Insert Regex is: ${insertregex}\n";

my @REPLACES;
if ( opendir my $replaces_dh, '/usr/local/cpanel/etc/exim/replacecf' ) {
    @REPLACES = sort readdir $replaces_dh;
    @REPLACES = grep !/^\./, @REPLACES;
    closedir $replaces_dh;

}

foreach my $insert (@REPLACES) {
    next if ( -B '/usr/local/cpanel/etc/exim/replacecf/' . $insert );
    next if ( -d _ );
    next if ( grep( /^\Q$insert\E/, @REPLACELIST ) );                   #replaced by other means
    push( @REPLACELIST, $insert );
    if ( $hasdomainkeys && -e '/usr/local/cpanel/etc/exim/replacecf/domainkeys/' . $insert ) {
        open( INST, '/usr/local/cpanel/etc/exim/replacecf/domainkeys/' . $insert );
    }
    else {
        open( INST, '/usr/local/cpanel/etc/exim/replacecf/' . $insert );
    }
    while (<INST>) {
        $REPLACETEXT{$insert} .= $_;
    }
    $REPLACETEXT{$insert} =~ s/[\r\n]+$//g;
    close(INST);
}
my $replaceinsertregex = join( '|', @REPLACELIST );

print "Exim Replace Regex is: $replaceinsertregex\n";

my @MATCHINSERTS;
if ( opendir my $matchinserts_dh, '/usr/local/cpanel/etc/exim/matchcf' ) {
    @MATCHINSERTS = readdir $matchinserts_dh;
    @MATCHINSERTS = grep !/^\./, @MATCHINSERTS;
    closedir $matchinserts_dh;
}

my @MATCHINSERTLIST;
my %MATCHINSERTTEXT;
foreach my $insert (@MATCHINSERTS) {
    next if ( -B '/usr/local/cpanel/etc/exim/matchcf/' . $insert );
    push( @MATCHINSERTLIST, $insert );
    open( INST, '/usr/local/cpanel/etc/exim/matchcf/' . $insert );
    while (<INST>) {
        $MATCHINSERTTEXT{$insert} .= $_;
    }
    $MATCHINSERTTEXT{$insert} =~ s/[\r\n]+$//g;
    close(INST);
}
my $matchinsertregex = join( '|', @MATCHINSERTLIST );

print "Exim Match Insert Regex is: $matchinsertregex\n";

my @PERLS;
if ( opendir my $perls_dh, '/usr/local/cpanel/etc/exim/perl' ) {
    @PERLS = readdir $perls_dh;
    @PERLS = grep !/^\./, @PERLS;
    closedir $perls_dh;
}
my $inkill      = 0;
my $incfkill    = 0;
my $inblockkill = 0;

open( EXIMC, '>', '/etc/exim.conf.buildtest' );
open( EXIMD, '<', '/etc/exim.conf.' . $dist );
while (<EXIMD>) {
    if (m/^\@([^\@]+)\@/) {
        $inblockkill = 0;
        $cf          = $1;
        print EXIMC $CF{$cf} . "\n\n";
    }
    elsif (m/^\%([^\%]+)\%/) {
        $inblockkill = 0;
        my $pushcf = $1;
        my $acf    = $pushcf;
        $acf =~ s/^BEGIN//g;
        $acf =~ s/^END//g;
        if ( $pushcf =~ m/^BEGIN/ ) {
            if ( $CF{$acf} ne '' ) {
                $incfkill = 1;
            }
        }
        if ( $pushcf =~ m/^END/ ) {
            if ( $CF{$acf} ne '' ) {
                print EXIMC $CF{$acf} . "\n\n";
            }
            $incfkill = 0;
        }
        next;
    }
    else {
        if ( !$hasmaildir ) {
            if (m/^\s+maildir_format/) {
                print "[mbox support] removed maildir_format line.\n";
                next();
            }
            elsif (m/^\s+directory\s*=/) {
                print "[mbox support] switched directory to file= and replaced '/.' with '/' .\n";
                s/^(\s+)directory\s*=/$1file =/g;
                s/\/\./\//g;
                s/\/mail\"/\/mail\/inbox\"/g;
                s/\/(\$\{local_part\})\"/\/$1\/inbox\"/g;
            }
        }
        next if $incfkill == 1;
        if ($inblockkill) {
            if ( m/^\s*[^\s\:]+\:/ || m/^\s*$/ ) { $inblockkill = 0; }
            else                                 { next; }
        }
        if ( $cf =~ m/ACL/ ) {
            if (m/^[\s\t]*require[\s\t]*verify[\s\t]*=[\s\t]*/) {
                if ( !$senderverify ) { next; }
                if ( !$callouts )     { s/\/callout//g; }
            }
            elsif ( $compat_add_header && m/^\s*add_header/ ) {
                s/^(\s*)add_header/$1message/g;
            }
        }
        if ( $cf eq 'CONFIG' ) {
            if ( !$inkill ) {
                foreach my $killcf (@KILLCF) {
                    if ( m/^${killcf}\s/ || m/^${killcf}=/ ) {
                        $inkill = 1;
                    }
                }
            }
            if ( !$inkill ) {
                print EXIMC;
            }
            if ($inkill) {
                if ( !m/\\\s*$/ ) {
                    $inkill = 0;
                }
            }
        }
        else {
            if ( length($matchinsertregex) > 3 && m/(${matchinsertregex})/ ) {
                print EXIMC "$MATCHINSERTTEXT{$1}\n";
            }
            if ( length($insertregex) > 3 && m/^(${insertregex}):/ ) {
                my $regexm            = $1;
                my $boxtrapper_needed = 0;
                if ( $INSERTTEXT{$regexm} =~ m/boxtrapper/i ) {
                    $boxtrapper_needed = 1;
                }
                my $maildir_needed = 0;
                if ( $INSERTTEXT{$regexm} =~ m/maildir/i ) {
                    $maildir_needed = 1;
                }
                if ( !$hasboxtrapper && $boxtrapper_needed ) {
                    print "Skipping $regexm insert as it requires boxtrapper and it is disabled.\n";
                }
                elsif ( !$hasmaildir && $maildir_needed ) {
                    print "Skipping $regexm insert as it requires maildir and it is not enabled.\n";
                }
                else {
                    if ($maildir_needed) {
                        print "Adding maildir specific $regexm to exim config\n";
                    }
                    print EXIMC "$INSERTTEXT{$regexm}\n";
                }
            }
            if ( length($replaceinsertregex) > 3 && m/(${replaceinsertregex}):/ ) {
                $inblockkill = 1;
                print EXIMC "$REPLACETEXT{$1}\n";
            }

            next if $inblockkill;
            print EXIMC;
        }
    }
}
close(EXIMD);
close(EXIMC);

my $goodconf = 0;
open( EXIM, "$eximbin -bV -C /etc/exim.conf.buildtest 2>&1|" );
while (<EXIM>) {
    if (m/Configuration file is/i) {
        $goodconf = 1;
        next;
    }
    print;
}
close(EXIM);
if ( !$goodconf ) {
    print "<b>Configuration file has an invalid syntax.  Please try again.</b>\n";
    if ( !-e '/etc/exim.conf' ) {
        open( EXIMC, '>', '/etc/exim.conf' );
        if ( -e '/etc/exim.conf.mailman2.dist' && -e '/var/cpanel/mailman2' ) {
            open( EXIMD, '/etc/exim.conf.mailman2.dist' );
        }
        else {
            open( EXIMD, '/etc/exim.conf.dist' );
        }
        while (<EXIMD>) {
            if ( !m/^\@[^\@]+\@/ && !m/^\%[^\%]+\%/ ) {
                print EXIMC;
            }
        }
    }
    close(EXIMC);
    close(EXIMD);
}
else {
    print "Configuration file passes test!  New configuration file was installed.\n";
    system( 'cp', '-f', '/etc/exim.conf.buildtest', '/etc/exim.conf' );

    print "Exim Perl Load List is: " . join( '|', @PERLS ) . "\n";
    print "/etc/exim.pl.local installed!\n";
    open( EXLOCAL, ">", "/etc/exim.pl.local" );
    chmod( 0755, '/etc/exim.pl.local' );
    foreach my $perls (@PERLS) {
        next if ( -B '/usr/local/cpanel/etc/exim/perl/' . $perls );
        open( PRL, '/usr/local/cpanel/etc/exim/perl/' . $perls );
        while (<PRL>) {
            print EXLOCAL;
        }
        close(PRL);
    }
    print EXLOCAL "\n1;\n";
    close(EXLOCAL);

    if ( -e '/usr/local/etc/exim/configure' ) {
        system( 'cp', '-f', '/etc/exim.conf', '/usr/local/etc/exim/configure' );
    }

    if ($hasdomainkeys) {
        Cpanel::FileUtils::touchfile('/etc/domain_keys_active');
    }
    else {
        unlink('/etc/domain_keys_active');
    }
}

if ( !-e $systemfilter ) {
    $systemfilter = '';
}

checkeximperms();

system '/scripts/mailscannerupdate', '--force';
system '/usr/local/cpanel/bin/updateauthtab';
system '/scripts/eximcron';

sub _slurpout {
    my $file  = shift;
    my $fh    = shift;
    my $ilock = SafeFile::safeopen( \*IF, '<', $file );
    while ( readline( \*IF ) ) {
        print {$fh} $_;
    }
    SafeFile::safeclose( \*IF, $ilock );
}

sub geteximinfo {
    my $eximbin;
    if ( -e '/usr/sbin/exim' ) {
        $eximbin = '/usr/sbin/exim';
    }
    elsif ( -e '/usr/local/sbin/exim' ) {
        $eximbin = '/usr/local/sbin/exim';
    }
    elsif ( -e '/usr/sbin/sendmail' ) {
        $eximbin = '/usr/sbin/sendmail';
    }
    else {
        die 'Exim Binary not found!';
    }

    my $hasdomainkeys = 0;
    my $eximFversion = Cpanel::SafeRun::saferun( $eximbin, '-bV' );
    $eximFversion =~ /version\s+([\d\.]+)/;
    my $eximver = $1;
    if ( $eximFversion =~ /domainkeys/i ) {
        $hasdomainkeys = 1;
    }
    return ( $eximbin, $eximver, $hasdomainkeys );
}

