--- /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: