diff -r 59cd8ce44290 -r 2fdc6206e792 exiacl.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/exiacl.pl Fri Aug 19 13:10:19 2005 +0000 @@ -0,0 +1,175 @@ +#! /usr/bin/perl +# © Heiko Schlittermann +# $Id$ +# $URL$ +use constant USAGE => << '#'; +!ME! [options] [-- exim native options] + + --[no]log show the log output [!$Cf->log!] + --[no]debug show debug debug output [!$Cf->debug!] + + --from=s from: [!$Cf->from!] + --to=s to: [!$Cf->to!] + + --Helo=s HELO [!$Cf->Helo!] + --From=s MAIL FROM: [!$Cf->From!] + --To=s RCPT TO: [!$Cf->To!] + + --src=s src ip/name [!$Cf->src!] + --dst=s dst ip/name [!$Cf->dst!] + + --exim=s exim binary [!$Cf->exim!] + --config=s exim config file [!$Cf->config!] + + $Id$ + $URL$ +# + + +use strict; +use warnings; +use AppConfig; +use IPC::Open3; +use IO::Select; +use Socket; +use File::Basename; + + +sub exim_option($); +sub read_exim($); +sub write_exim($@); +sub addr(@); +sub hostname() { chomp (my $h = `hostname -f`); return $h; } + +use constant ME => basename $0; +use constant HOSTNAME => hostname; +use constant CONFIG => ( + { CASE => 1 }, + + log => { ARGS => "!", DEFAULT => 1 }, + debug => { ARGS => "!", DEFAULT => 0 }, + + from => { ARGS => "=s" }, + to => { ARGS => "=s" }, + + Helo => { ARGS => "=s", ALIAS => "ehlo" }, + From => { ARGS => "=s" }, + To => { ARGS => "=s" }, + + src => { ARGS => "=s", DEFAULT => "172.20.1.8" }, + dst => { ARGS => "=s" }, # exim primary_hostname + + exim => { ARGS => "=s", DEFAULT => $ENV{EXIM} || "exim" }, + config => { ARGS => "=s", DEFAULT => $ENV{EXIM_CONF} || "/etc/exim/exim.conf.t" , + ALIAS => "C" }, + + help => { ARGS => "!" }, + +); + + + +my $Cf; +$Cf = new AppConfig CONFIG or die; + $Cf->dst(addr(exim_option("primary_hostname"))); + $Cf->getopt(qw(pass_through no_ignore_case)) or die $@; + + $Cf->From($Cf->from) unless $Cf->From; + $Cf->To($Cf->to) unless $Cf->To; + + $Cf->Helo((split/@/, $Cf->from||"")[1] || HOSTNAME) + unless $Cf->Helo; + $Cf->dst(addr(HOSTNAME)) unless $Cf->dst; + + $@ = ""; + foreach (qw/from to src dst/) { + $Cf->get($_) or $@ = join " ", $@, $_; + } + + die ME.": Missing values: $@\n" if $@; + + +MAIN: { + die "Config file for exim not readable ".$Cf->config.": $!\n" if not -r $Cf->config; + + my ($w, $r); + my @cmd = ($Cf->exim, + -C => $Cf->config, + -oMi => addr($Cf->dst), + -bhc => addr($Cf->src), + @ARGV); # remaining args are exim native + + if ($Cf->help) { + ($_ = USAGE) =~ s/!(.*?)!/eval $1||""/egs; + print; exit; + } + + my $s = new IO::Select; + + print "**> @cmd\n"; + + open3($w, $r, undef, @cmd) or die "Can't run @cmd: $!\n"; + + read_exim $r; + write_exim $w, "EHLO ".$Cf->Helo."\n"; + read_exim $r; + write_exim $w, "MAIL FROM: ".$Cf->From."\n"; + read_exim $r; + write_exim $w, "RCPT TO: ".$Cf->to."\n"; + read_exim $r; + write_exim $w, "DATA\n"; + read_exim $r; + write_exim $w, "From: ".$Cf->from."\n"; + write_exim $w, "To: ".$Cf->to."\n"; + write_exim $w, "Subject: Test\n"; + + if (not -t STDIN) { + write_exim $w, "\n"; + while (<>) { + write_exim $w, $_; + } + } + + write_exim $w, "\n.\n"; + read_exim $r; + write_exim $w, "QUIT\n"; + + +} + +sub read_exim($) { + my $fh = shift; + while (<$fh>) { + /^\d\d\d/ and print("< $_") and next; + /^LOG/ and print and next if $Cf->log; + print and next if $Cf->debug; + } continue { + last if /^\d\d\d\s/; + } + exit if /^5/; +} + +sub write_exim($@) { + my $fh = shift; + print "> ", @_; + print $fh @_; +} + + +{ + my %opts; +sub exim_option($) { + my $opt = shift; + my $exim = $Cf->exim; + if (!%opts) { + %opts = map { chomp; /^(.*?)\s*=\s*(.*)/ ? ($1, $2) : (/no_(.*)/ ? ($1, 0) : ($_, 1)) } grep !/^\s*$/, `$exim -bP`; + } + $opts{$opt} +} } + + +sub addr(@) { + map { inet_ntoa scalar gethostbyname $_ } @_; +} + +# vim:sts=4 sw=4 aw ai sm: