File Coverage

blib/lib/Mail/Exim/MainLogParser.pm
Criterion Covered Total %
statement 22 58 37.9
branch 0 14 0.0
condition 1 26 3.8
subroutine 7 10 70.0
pod 3 3 100.0
total 33 111 29.7


line stmt bran cond sub pod time code
1             package Mail::Exim::MainLogParser;
2 1     1   14167 use strict;
  1         2  
  1         26  
3              
4             BEGIN {
5 1     1   5 use Exporter ();
  1         2  
  1         28  
6 1     1   5 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         4  
  1         87  
7 1     1   3 $VERSION = '0.01';
8 1         11 @ISA = qw(Exporter);
9 1         3 @EXPORT = qw();
10 1         2 @EXPORT_OK = qw(&EximMainLoglineParse);
11 1         23 %EXPORT_TAGS = ();
12             }
13              
14             BEGIN {
15 1     1   5 use vars qw(%EXIM_FLAGS %EXIM_FIELD_IDENFIERS);
  1         2  
  1         113  
16              
17             # As of 2017-06-08
18             # Source: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-log_files.html
19 1     1   9 %EXIM_FLAGS = (
20             '<=' => 'message arrival',
21             '(=' => 'message fakereject',
22             '=>' => 'normal message delivery',
23             '->' => 'additional address in same delivery',
24             '>>' => 'cutthrough message delivery',
25             '*>' => 'delivery suppressed by -N',
26             '**' => 'delivery failed; address bounced',
27             '==' => 'delivery deferred; temporary problem',
28             );
29 1         515 %EXIM_FIELD_IDENFIERS = (
30             A => 'authenticator name (and optional id and sender)',
31             C => ('SMTP confirmation on delivery'. '; '.
32             'command list for "no mail in SMTP session”'),
33             CV => 'certificate verification status',
34             D => 'duration of "no mail in SMTP session”',
35             DN => 'distinguished name from peer certificate',
36             DS => 'DNSSEC secured lookups',
37             DT => 'on => lines: time taken for a delivery',
38             F => 'sender address (on delivery lines)',
39             H => 'host name and IP address',
40             I => 'local interface used',
41             K => 'CHUNKING extension used',
42             id => 'message id for incoming message',
43             P => ('on <= lines: protocol used'. '; '.
44             'on => and ** lines: return path'),
45             PRDR => 'PRDR extension used',
46             PRX => 'on <= and => lines: proxy address',
47             Q => 'alternate queue name',
48             QT => ('on => lines: time spent on queue so far'. '; '.
49             'on "Completed” lines: time spent on queue'),
50             R => ('on <= lines: reference for local bounce'. '; '.
51             'on => >> ** and == lines: router name'),
52             S => 'size of message in bytes',
53             SNI => 'server name indication from TLS client hello',
54             ST => 'shadow transport name',
55             T => ('on <= lines: message subject (topic)'. '; '.
56             'on => ** and == lines: transport name'),
57             U => 'local user or RFC 1413 identity',
58             X => 'TLS cipher suite'
59             );
60             }
61              
62              
63             sub new
64             {
65 1     1 1 17 my ($class, %parameters) = @_;
66              
67 1   33     10 my $self = bless ({}, ref ($class) || $class);
68              
69 1         4 return $self;
70             }
71              
72             sub _exim_log_main__parse($) {
73 0   0 0     my $line = shift || return undef;
74 0           my @line = split(/\s/,$line);
75 0 0         return undef unless scalar @line >= 3;
76 0           my $l = {
77             date => shift @line,
78             time => shift @line
79             };
80              
81             # Exim ID: 1dIyz2-0002mc-5x
82 0 0         if ($line[0] =~ /......\-......\-../) {
83 0           $l->{eximid} = shift @line;
84             } else {
85 0           $l->{eximid} = undef;
86             }
87              
88             # Exim log line flag
89 0 0         if ($line[0] =~ /\<\=|\(\=|\=\>|\-\>|\>\>|\*\>|\*\*|\=\=/) {
90 0           $l->{flag} = shift @line;
91             } else {
92             # mail rejected or completed!
93 0           $l->{flag} = undef;
94             }
95              
96             # Exim Mail Address
97 0 0 0       if (($line[0] !~ /^[A-Zid]{1,4}\=.+/) && ($line[0] =~ /.+\@.+/)) {
98 0           $l->{address} = shift @line;
99 0   0       while ((defined $line[0]) && ($line[0] !~ /^[A-Zid]{1,4}\=.+/)) {
100 0 0 0       if ( ((!defined $l->{flag}) || ((defined $l->{flag}) && ($l->{flag} eq '**'))) && ($l->{address} =~ /\:$/)) {
      0        
101 0           chop $l->{address};
102 0           last;
103             }
104 0           $l->{address} .= (" " . shift @line);
105             }
106             }
107              
108             # Exim field identifiers and messages
109 0           $l->{args} = [];
110 0           while (scalar @line >= 1) {
111 0 0         if ($line[0] =~ /^([A-Zid]{1,4})\=(.+)/) {
112 0           my $this_arg = $1;
113 0           my $this_val = $2;
114 0           shift @line;
115 0   0       while ( (scalar @line >= 1) && (($line[0] =~ /^\[.+\]/) || ($line[0] =~ /^\(.+\)/)) ) {
      0        
116 0           $this_val .= (" " . shift @line);
117             }
118 0           push(@{$l->{args}},{$this_arg => $this_val});
  0            
119             } else {
120 0           $l->{message} = shift @line;
121 0   0       while ((defined $line[0]) && ($line[0] !~ /^[A-Zid]{1,4}\=.+/)) {
122 0           $l->{message} .= (" " . shift @line);
123             }
124             }
125             }
126              
127 0 0         if (scalar @line >= 1) {
128 0           die ("Error Parsing Line: $line\n"."Unparsed log line data: ".join("; ",@line)."\n");
129             }
130              
131 0           return $l;
132             }
133              
134             sub EximMainLoglineParse($) {
135 0     0 1   return _exim_log_main__parse($_[0]);
136             }
137              
138             sub parse($) {
139 0     0 1   my $self = shift;
140 0           return _exim_log_main__parse($_[0]);
141             }
142              
143             1;
144             __END__