#! /bin/sh /usr/share/dpatch/dpatch-run
## 200_exim_support.diff.dpatch by  <Craig Box <packages@itpartners.co.nz>>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Add exim support to Mailgraph

@DPATCH@

--- mailgraph-1.10/mailgraph.pl	2004-10-26 08:27:09.000000000 +1300
+++ mailgraph-1.10exim2/mailgraph.pl	2005-11-09 15:37:07.488902064 +1300
@@ -280,6 +280,17 @@
     croak "Internal error: unknown type: $self->{type}";
 }
 
+use Date::Calc qw(Mktime);
+
+sub seconds {
+my($year, $month, $day, $hour, $min, $sec) = (pop @_) =~
+  /(\d\d\d\d)-(\d\d)-(\d\d)\s(\d\d):(\d\d):(\d\d)/;
+my $time = Mktime($year,$month,$day, $hour, $min, $sec);
+return $time;
+}
+
+
+
 #####################################################################
 #####################################################################
 #####################################################################
@@ -315,7 +326,8 @@
 
 # prototypes
 sub daemonize();
-sub process_line($);
+sub process_line_exim($);
+sub process_line_postfix($);
 sub event_sent($);
 sub event_received($);
 sub event_bounced($);
@@ -340,6 +352,7 @@
 	print "  --daemon-pid=FILE  write PID to FILE instead of /var/run/mailgraph.pid\n";
 	print "  --daemon-rrd=DIR   write RRDs to DIR instead of /var/log\n";
 	print "  --daemon-log=FILE  write verbose-log to FILE instead of /var/log/mailgraph.log\n";
+        print "  -e, --exim         exim mode.  read's main log format log instead of syslog\n";
 	print "  --ignore-localhost ignore mail to/from localhost (used for virus scanner)\n";
 	print "  --ignore-host=HOST ignore mail to/from HOST (used for virus scanner)\n";
 	print "  --only-mail-rrd    update only the mail rrd\n";
@@ -355,6 +368,7 @@
 	Getopt::Long::Configure('no_ignore_case');
 	GetOptions(\%opt, 'help|h', 'cat|c', 'logfile|l=s', 'logtype|t=s', 'version|V',
 		'year|y=i', 'host=s', 'verbose|v+', 'daemon|d!',
+                'exim|e',
 		'daemon_pid|daemon-pid=s', 'daemon_rrd|daemon-rrd=s',
 		'daemon_log|daemon-log=s', 'ignore-localhost!', 'ignore-host=s',
 		'only-mail-rrd', 'only-virus-rrd', 'rrd_name|rrd-name=s',
@@ -382,20 +396,35 @@
 	else {
 		$file = File::Tail->new(name=>$logfile, tail=>-1);
 	}
-	my $parser = new Parse::Syslog($file, year => $opt{year}, arrayref => 1,
-		type => defined $opt{logtype} ? $opt{logtype} : 'syslog');
 
-	if(not defined $opt{host}) {
-		while(my $sl = $parser->next) {
-			process_line($sl);
-		}
-	}
-	else {
-		my $host = qr/^$opt{host}$/i;
-		while(my $sl = $parser->next) {
-			process_line($sl) if $sl->[1] =~ $host;
-		}
-	}
+        if ($opt{exim}) {
+                if ($opt{cat}) {
+                        open(LOG, "< $file") or die "Couldn't open log file $file";;
+                        while (my $sl = <LOG>) {
+                                process_line_exim($sl);
+                        }
+                } else {
+                        while (my $sl = $file->read) {
+                                process_line_exim($sl);
+                        }
+                }
+        } else {
+        	my $parser = new Parse::Syslog($file, year => $opt{year}, 
+                        arrayref => 1,
+	        	type => defined $opt{logtype} ? $opt{logtype} : 'syslog');
+
+        	if(not defined $opt{host}) {
+	        	while(my $sl = $parser->next) {
+		        	process_line_postfix($sl);
+        		}
+        	}
+        	else {
+	        	my $host = qr/^$opt{host}$/i;
+		        while(my $sl = $parser->next) {
+			        process_line_postfix($sl) if $sl->[1] =~ $host;
+                	}       
+        	}
+        }
 }
 
 sub daemonize()
@@ -480,7 +509,95 @@
 	$rrd_inited=1;
 }
 
-sub process_line($)
+sub process_line_exim($) 
+{
+        my($ip,$host,$email,$edomain,$domain,$thissize,$old,$new);
+        my($tod,$m_hour,$m_min,$id,$flag);
+        my $line = shift;
+        $_ = $line;
+        return if length($_) < 38;
+        return unless $_ =~ /^(\d{4}\-\d\d-\d\d\s(\d\d):(\d\d):\d\d( [-+]\d\d\d\d)?)/o;
+        $tod = $1;
+        my $time = seconds($tod);
+        my($extra) = defined($4)? 6 : 0;
+        $id   = substr($_, 20 + $extra, 16);
+        $flag = substr($_, 37 + $extra, 2);
+
+        # return unless ($flag =~ /<=|=>|->|==|\*\*|Co/);
+        #Strip away the timestamp, ID and flag (which could be "Com" for completed)
+        $_ = substr($_, 40 + $extra);  # PH
+
+        $host = "local";                #Host is local unless otherwise specified.
+        $domain = "localdomain";        #Domain is localdomain unless otherwise specified.
+
+        # Do some pattern matches to get the host and IP address.
+        # We expect lines to be of the form "H=[IpAddr]" or "H=Host [IpAddr]" or
+        # "H=Host (UnverifiedHost) [IpAddr]" or "H=(UnverifiedHost) [IpAddr]".
+        # We do 2 separate matches to keep the matches simple and fast.
+        if ($_ =~ /\sH=(\S+)/) {
+                $host = $1;
+
+                ($ip) = /\sH=.*?(\s\[[^]]+\])/;
+                # If there is only an IP address, it will be in $host and $ip will be
+                # unset. That is OK, because we only use $ip in conjunction with $host
+                # below. But make it empty to avoid warning messages.
+                $ip = "" if !defined $ip;
+
+        }
+
+        # sender email
+        $email = (/^(\S+)/) ? $1 : "";
+        # sender email domain
+        $edomain = (/^\S*?\@(\S+)/) ? lc($1) : "";
+
+        if ($flag eq "<=") {
+                $thissize = (/\sS=(\d+)( |$)/) ? $1 : 0;
+                if ($host ne "local") {
+                        print "RECEIVED: $line\n" if $opt{verbose} > 0;
+                        event($time, 'received');
+                }
+        } elsif ($flag eq "=>") {
+                if ($host ne "local") {
+                        print "SENT $line\n" if $opt{verbose} > 0;
+                        event($time, 'sent');
+                }
+        } elsif ($flag eq "**") {
+                print "BOUNCED $line\n" if $opt{verbose} > 0;
+                event($time, 'bounced');
+                if (/R=bounce_virus/) {
+                        print "VIRUS $line\n" if $opt{verbose} > 0;
+                        event($time, 'virus');
+                }
+        } elsif ($flag eq "H=" and /rejected after DATA: ([\w_]+)/) {
+                print "REJECTED $line\n" if $opt{verbose} > 0;
+                event($time, 'rejected');
+                SWITCH: {
+                        "SPAM" eq $1 && do {
+                                print "SPAM $line\n" if $opt{verbose} > 0;
+                                event($time, 'spam');
+                                last SWITCH;
+                        };
+                        "MALWARE" eq $1 && do {
+                                print "MALWARE $line\n" if $opt{verbose} > 0;
+                                event($time, 'virus');
+                                last SWITCH;
+                        };
+                        "MIME_ERROR" eq $1 && do {
+                                print "MIME_ERROR $line\n" if $opt{verbose} > 0;
+                                last SWITCH;
+                        };
+                        "BAD_ATTACHMENT" eq $1 && do {
+                                print "BAD_ATTACHMENT $line\n" if $opt{verbose} > 0;
+                                last SWITCH;
+                        };
+                #       $nothing = 1;
+                }
+        } else {
+                print "ignoring line: flag=$flag; host=$host; line=$line\n";
+        }        
+}
+
+sub process_line_postfix($)
 {
 	my $sl = shift;
 	my $time = $sl->[0];
