1
2########################################################
3# Please file all bug reports, patches, and feature
4# requests under:
5#      https://sourceforge.net/p/logwatch/_list/tickets
6# Help requests and discusion can be filed under:
7#      https://sourceforge.net/p/logwatch/discussion/
8########################################################
9
10########################################################
11# Originally written by:
12#    Dariusz Nierada <dnierada@kat.supermedia.pl>
13########################################################
14
15########################################################
16# Default Detail Levels:
17#     0: Prints MisFormatted log lines (should never happen)
18#        Virus/Malware blocks (if AntiVirus configured)
19#        Prints protocol violations (by category)
20#        Prints address verification rejections
21#        Prints administrative rejections (by category)
22#        Prints Refused Relay count
23#
24#     5: Prints Queue Run count
25#        Prints server Stop/Start
26#
27#    10: Prints Refused Relay (individual lines)
28#        Prints Per Message Tracking
29########################################################
30
31########################################################
32## Copyright (c) 2008 Gary Allen Vollink
33## Covered under the included MIT/X-Consortium License:
34##    http://www.opensource.org/licenses/mit-license.php
35## All modifications and contributions by other persons to
36## this script are assumed to have been donated to the
37## Logwatch project and thus assume the above copyright
38## and licensing terms.  If you want to make contributions
39## under your own copyright or a different license this
40## must be explicitly stated in the contribution an the
41## Logwatch project reserves the right to not accept such
42## contributions.  If you have made significant
43## contributions to this script and want to claim
44## copyright please contact logwatch-devel@lists.sourceforge.net.
45#########################################################
46
47use Logwatch ':dates';
48use warnings;
49
50$Detail       = $ENV{'LOGWATCH_DETAIL_LEVEL'}  || 0;
51
52$LvlBadFormat    = $ENV{'exim_misformat'}     || 0;
53$LvlRestarts     = $ENV{'exim_restart'}       || 5;
54$LvlVirus        = $ENV{'exim_virus'}         || 0;
55$LvlProtocol      = $ENV{'exim_protocol'}      || 0;
56$LvlProtocolLines = $ENV{'exim_protocol_lines'}|| 5;
57$LvlDontAccept   = $ENV{'exim_dontaccept'}    || 0;
58$LvlDontAcceptLines = $ENV{'exim_dontaccept_lines'}    || 0;
59$LvlVerify       = $ENV{'exim_verify'}        || 0;
60$LvlVerifyLines  = $ENV{'exim_verify_lines'}  || 5;
61$LvlRuns         = $ENV{'exim_runs'}          || 5;
62$LvlRelay        = $ENV{'exim_relay'}         || 0;
63$LvlRelayLines   = $ENV{'exim_relay_lines'}   || 10;
64$LvlMsgs         = $ENV{'exim_mesgs'}         || 10;
65
66# procedura sortujaca tak jak ja chce (bo tamta sotrowala po ASCII)
67# procedure to compare numbers at the beginning of submitted strings.
68#  .. Which in this case is the message count for a given message ID.
69sub wedlug_liczb {
70    ($aa) = ($a =~ /^(\d+).+/);
71    ($bb) = ($b =~ /^(\d+).+/);
72    $aa <=> $bb;
73}
74
75# START
76
77my $SearchDate = TimeFilter("%Y-%m-%d %H:%M:%S");
78$StartQueue = 0;
79$EndQueue = 0;
80
81# Regex to match IPv4 addresses and IPv6 addresses
82# IPv6 part could be made more strict
83my $IPAddress = qr/\d+\.\d+\.\d+\.\d+|[a-fA-F0-9]*:[a-fA-F0-9:]+/;
84
85my $MatchedDate = 0;
86
87while (defined($ThisLine = <STDIN>)) {
88   chomp($ThisLine);
89    # pobierz dzisiejsza date z 2002-03-31 22:13:48 ...
90    # Collect this line's date, e.g. 2002-03-31 22:13:48 ...
91   do {
92      if ( $ThisLine =~ /^ Suggested action: use keep_environment./ ) {
93         $KeepEnv++ if $MatchedDate;
94         next;
95      }
96      $BadFormat{$ThisLine}++;
97      next;
98   } unless ($year1,$month1,$day1,$h1,$m1,$s1) = ($ThisLine =~ /^(\d+)\-(\d+)\-(\d+)\s(\d+):(\d+):(\d+)\s.+/);
99
100   unless ($ThisLine =~ /^$SearchDate /o) {
101      $MatchedDate = 0;
102      next;
103   }
104   $MatchedDate = 1;
105
106   if ( $ThisLine =~ /End queue run\:/ ) {
107      $EndQueue++;
108   }
109   elsif ( $ThisLine =~ /Start queue run\:/ ) {
110      $StartQueue++;
111   }
112   elsif ( $ThisLine =~ /sender verify defer/ ) {
113      # ignore this; it's temporary
114   }
115   elsif ( $ThisLine =~ /unknown variable name/ ) {
116      # ignore this temporarily
117   }
118   elsif ( $ThisLine =~ /ignoring AUTH=.*? \(client not authenticated\)/ ) {
119      # ignore this; it is a warning.
120   }
121   elsif ( $ThisLine =~ /cwd=.*? \d args: / ) {
122      # ignore this; it is exim (or an Exim sub-command) starting.
123   }
124   elsif ( $ThisLine =~ /[Rr]ecipient verify fail/ ) {
125      $RecipVerify{$ThisLine}++;
126   }
127   elsif ( $ThisLine =~ /[Ss]ender verify fail/ ) {
128      $SendVerify{$ThisLine}++;
129   }
130   elsif ( $ThisLine =~ /Warning: purging the environment./ ) {
131      $Purging++;
132   }
133   elsif ( $ThisLine =~ /fragments administratively prohib/ ) {
134      $DontAccept{$ThisLine}++;
135   }
136   elsif ( $ThisLine =~ /unqualified (sender|recipient) rejected/ ) {
137      $DontAccept{$ThisLine}++;
138   }
139   elsif ( $ThisLine =~ /do not accept mail / ) {
140      $DontAccept{$ThisLine}++;
141   }
142   elsif ( $ThisLine =~ /rejected connection in .connect. ACL/ ) {
143      # Likely policy rejections
144      $DontAccept{$ThisLine}++;
145   }
146   elsif ( $ThisLine =~ /believed to be spam/ ) {
147      $DontAccept{$ThisLine}++;
148   }
149   elsif ( $ThisLine =~ /[Ww]arning: dnsbl\.sorbs\.net/ ) {
150      $DontAccept{$ThisLine}++;
151   }
152   elsif ( $ThisLine =~ /mail not permitted from/ ) {
153      $DontAccept{$ThisLine}++;
154   }
155   elsif ( $ThisLine =~ /file, which is blacklisted/ ) {
156      $DontAccept{$ThisLine}++;
157   }
158   elsif ( $ThisLine =~ /not accept Windows executables/ ) {
159      $DontAccept{$ThisLine}++;
160   }
161   elsif ( $ThisLine =~ /remote host address is the local host/ ) {
162      $DontAccept{$ThisLine}++;
163   }
164   elsif ( $ThisLine =~ /message contains malware/ ) {
165      # Exim <= 4.44 with ExiScan-ACL Patch (Running AntiVirus Software)
166      $Virus{$ThisLine}++;
167   }
168   elsif ( $ThisLine =~ /message contains a [vV]irus/ ) {
169      # Exim >= 4.50 compiled with WITH_CONTENT_SCAN=yes (Running AntiVirus Software)
170      $Virus{$ThisLine}++;
171   }
172   elsif ( $ThisLine =~ /SMTP connection from/ ) {
173      # Common error from SPAM hosts.
174      $Proto{$ThisLine}++;
175   }
176   elsif ( $ThisLine =~ /SMTP syntax error in/ ) {
177      # Common error from SPAM hosts.
178      $Proto{$ThisLine}++;
179   }
180   elsif ( $ThisLine =~ /remote host used my name in HELO/ ) {
181      # Common error from SPAM hosts.
182      $Proto{$ThisLine}++;
183   }
184   elsif ( $ThisLine =~ /remote host used IP address in HELO/ ) {
185      # Common error from SPAM hosts.
186      $Proto{$ThisLine}++;
187   }
188   elsif ( $ThisLine =~ /unexpected disconnection while reading SMTP command/ ) {
189      # Common error from SPAM hosts.
190      $Proto{$ThisLine}++;
191   }
192   elsif ( $ThisLine =~ /SMTP protocol violation/ ) {
193      # Common error from SPAM hosts.
194      $Proto{$ThisLine}++;
195   }
196   elsif ( $ThisLine =~ /SMTP command timeout/ ) {
197      # Common error from SPAM hosts.
198      $Proto{$ThisLine}++;
199   }
200   elsif ( $ThisLine =~ /SMTP data timeout/ ) {
201      # Common error from SPAM hosts.
202      $Proto{$ThisLine}++;
203   }
204   elsif ( $ThisLine =~ /incomplete transaction \(([\s\w]+)\) from/ ) {
205      # Common error from SPAM hosts (after recipient reject/callout).
206      $Proto{$ThisLine}++;
207   }
208   elsif ( $ThisLine =~ /SMTP protocol synchronization error \(([\s\w:]+)\):/ ) {
209      # Spammer who does not wait before sending crap
210      $Proto{$ThisLine}++;
211   }
212   elsif ( $ThisLine =~ /dropped: too many nonmail commands/ ) {
213      # Often someone who tries lots of transactions
214      $Proto{$ThisLine}++;
215   }
216   elsif ( $ThisLine =~ /dropped: too many syntax or protocol errors/ ) {
217      # Often someone who tries lots of transactions
218      $Proto{$ThisLine}++;
219   }
220   elsif ( $ThisLine =~ /SMTP protocol error in \"[^\"]+\"/ ) {
221      # Some hosts ask for TLS even when not offered (generalised to all cmds)
222      $Proto{$ThisLine}++;
223   }
224   elsif ( $ThisLine =~ /TLS error on connection from (\S+) \(([^)]*)\) \[(\S+)\]:(\d+) I=\[(\S+)\]:(\d+) \(send\): Error in the push function\./ ) {
225      # Ignore this, office 365 connector early disconnect.
226   }
227   elsif ( $ThisLine =~ /authenticator failed for/ ) {
228      $Proto{$ThisLine}++;
229   }
230   elsif ( $ThisLine =~ /Connection from .* too many connections from that IP address/ ) {
231      # Some hosts make lots of simultaneous connections
232	  # this is an extra error message when logging is high
233	  # and since another message duplicates it, we can just ignore this
234   }
235   elsif ( $ThisLine =~ /rejected [HE][EH]LO from\s/ ) {
236      # Typically due to underscores _ in the HELO line
237      #   (a common protocol violation)
238      # Also can be due to odd escape sequences
239      #   (never seen from a valid MX)
240      $Proto{$ThisLine}++;
241   }
242   elsif ( $ThisLine =~ /SIGHUP received\: re-exec/ ) {
243      push @Restart, "$year1-$month1-$day1 $h1:$m1:$s1 (stop)";
244   }
245   elsif ( $ThisLine =~ /daemon started\:/ ) {
246      push @Restart, "$year1-$month1-$day1 $h1:$m1:$s1 (start)";
247   }
248   elsif ( $ThisLine =~ /rejected RCPT.*greylist/) {
249      $Greylist++;
250      push @GreylistH, $ThisLine;
251   }
252   elsif ( $ThisLine =~ /refused relay/ || $ThisLine =~ /rejected RCPT/ ) {
253      $Relay++;
254      push @RelayH, $ThisLine;
255   }
256   elsif ( $ThisLine =~ /no host name found for IP address/ ) {
257      $ReverseLookup++;
258      push @ReverseLookupH, $ThisLine;
259   }
260   elsif ( $ThisLine =~ /no IP address found for host/ ) {
261      $Lookup++;
262      push @LookupH, $ThisLine;
263   }
264   elsif ( $ThisLine =~ /DKIM: .* \[verification succeeded\]/ ) {
265      # Ignore successful DKIM verification reports
266      # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-support_for_dkim_domainkeys_identified_mail.html
267   }
268   elsif ( $ThisLine =~ /^\d+\-\d+\-\d+\s\d+\:\d+\:\d+\s(\+\d+\s)?\w+\-\w+\-\w+\s/ ) { # inne wiadomosci przesylane przez EXIMA
269    # Collect Message ID specific notes...
270    ($mdate,$mtime,$mid,$mrest) = ($ThisLine =~ /^(\d+\-\d+\-\d+)\s(\d+\:\d+\:\d+)\s(?:\+\d+\s)?(\w+\-\w+\-\w+)(.+)/);
271      # Count of individual Message Lines, used for sort
272    $licze++;         # Dodaje taki licznik aby potem przy wypisaniu posortowac po nim, bo wypisywal nie po kolei
273    $mmsg{$mid}{$licze.$mrest} = "$mdate $mtime";
274
275   }
276   else
277   {
278      $OtherList{$ThisLine}++;
279   }
280} #end while
281
282# Print MisFormatted log lines (should never happen)
283if ($Detail >= $LvlBadFormat) {
284   if (%BadFormat) {
285      print "\n***** BAD FORMAT (Possible data corruption or Exim bug) *****\n";
286      foreach $ThisOne (keys %BadFormat) {
287         print "$ThisOne\n";
288      }
289   }
290}
291
292# Print server Stops/Starts
293if ($Detail >= $LvlRestarts) {
294   if (@Restart) {
295      print "\n--- Exim Restarted ---\n";
296      foreach $ThisOne (sort @Restart) {
297         print "  $ThisOne\n";
298      }
299   }
300}
301
302if ($Purging) {
303   print "    Warning: purging the environment. : $Purging Time(s)\n";
304}
305if ($KeepEnv) {
306   print "    ... Suggested action: use keep_environment. : $KeepEnv Time(s)\n";
307}
308
309if ($Detail >= $LvlRuns) {
310   if (($StartQueue >0 ) or ($EndQueue > 0)) {
311      print "\n--- Queue Runners ---\n";
312      # Start Queue
313      $StartQueue and print "  Start queue run: $StartQueue Time(s)\n";
314      # End Queue
315      $EndQueue and print "  End queue run: $EndQueue Time(s)\n";
316   }
317}
318
319if ($Detail >= $LvlVerify) {
320   if ((@SendVerify) and (@RecipVerify)) {
321      print "\n--- Address Verification ---\n";
322   }
323   if (@SendVerify) {
324      # Sender Verifies
325      $SendVerify and print "\nSender Verify failures: $SendVerify Time(s)\n";
326
327      if ($Detail >= $LvlVerifyLines) {
328         foreach $ThisOne (@SendVerify) {
329            print "  $ThisOne\n";
330         }
331      }
332   }
333   if (@RecipVerify) {
334      # Recip Verifies
335      $RecipVerify and print "Recipient Verify failures: $RecipVerify Time(s)\n";
336
337      if ($Detail >= $LvlVerifyLines) {
338         foreach $ThisOne (@RecipVerify) {
339            print "  $ThisOne\n";
340         }
341      }
342   }
343}
344
345if ($Detail >= $LvlRelay) {
346   if (@GreylistH) {
347
348      print "\n--- Greylisted $Greylist times\n";
349
350      if ( $Detail >= $LvlRelayLines ) {
351         print   "--- Lines follow:\n\n";
352
353         foreach $ThisOne (@GreylistH) {
354            print "$ThisOne\n";
355         }
356      }
357   }
358   if (@RelayH) {
359
360      print "\n--- Refused Relays $Relay times\n";
361
362      if ( $Detail >= $LvlRelayLines ) {
363         print   "--- Lines follow:\n\n";
364
365         foreach $ThisOne (@RelayH) {
366            print "$ThisOne\n";
367         }
368      }
369   }
370}
371
372if ($Detail >= $LvlVirus) {
373   # Print Blocked Viruses/Malware
374   if (%Virus) {
375      my (%vir);
376      print "\n--- Virus/Malware Blocked ---\n";
377      foreach $ThisOne (sort(keys %Virus)) {
378         # Need mid empty...
379         $mid = "";
380         # Virus name holder...
381         $cc = "";
382         # Extract exim date and time string...
383         ($mdate, $mtime) = ($ThisOne =~ m/^(\d+-\d+-\d+)\s(\d+\:\d+\:\d+)\s/);
384         # Link date and time (looks cleaner)...
385         $aa = "$mdate $mtime";
386         # Extract the REAL IP address...
387         ($bb) = ($ThisOne =~ m/\s\[($IPAddress)\][\s:]/);
388            # Exim >= 4.50 compiled with, WITH_CONTENT_SCAN=yes
389         # Default warning looks like this...
390            # rejected after DATA: This message contains a [vV]irus (%s).
391         if ($ThisOne =~ m/virus \((.*?)\)/) {
392            $cc = $1;
393         }
394            # Exim <= 4.44 with ExiScan-ACL patch
395            # rejected after DATA: This message contains malware (%s)
396         elsif ($ThisOne =~ m/malware \((.*?)\)/) {
397            $cc = $1;
398         }
399         # There is probably a more graceful way to do this...
400         if (defined( $vir{$cc} )) {
401            # Assign current value to temporary (mid)
402            $mid = $vir{$cc};
403         }
404         # Set current value to (old value)+new value+','
405         $vir{$cc} = "$mid$aa : IP:$bb,";
406      }
407      # Print the results...
408      foreach $ThisOne (sort(keys %vir)) {
409         print "Virus: [$ThisOne]\n";
410         foreach $aa ( sort( split /,/, $vir{$ThisOne} )) {
411            print "   $aa\n";
412         }
413      }
414   }
415}
416
417if ($Detail >= $LvlDontAccept) {
418   # Print Administrative Prohibitions
419   if (%DontAccept) {
420      my (%spam, %detail);
421      my (@errList);
422
423      # Probable SPAM hosts...
424      print "\n--- Admin Policy Blocking ---\n";
425      foreach $ThisOne (sort(keys %DontAccept)) {
426         # We need this blank.
427         $mid = "";
428         # IP address/current issue holder.
429         $bb = "";
430         # Extract exim date and time string...
431         ($mdate, $mtime) = ($ThisOne =~ m/^(\d+-\d+-\d+)\s(\d+\:\d+\:\d+)\s/);
432         # Link date and time (looks cleaner)...
433         $aa = "$mdate $mtime";
434
435         if ( $ThisOne =~ m/do not accept mail from ([\w\*-._]+)@([\w.-_]+)/ ) {
436            $cc = "Blocked Email Domain";
437            $bb = "$1\@$2";
438         }
439         elsif ( $ThisOne =~ m/rejected connection in .connect. ACL/ ) {
440            $cc = "Blocked Host";
441            ( $bb ) = ($ThisOne =~ m/\[(\d+\.\d+\.\d+\.\d+)\]/);
442         }
443         elsif ( $ThisOne =~ m/mail not permitted from sender ([\w\*-_.]+)@([\w.-_]+)/ ) {
444            $cc = "Blocked Email Address";
445            $bb = "$1\@$2";
446         }
447         elsif ( $ThisOne =~ m/contains attached ".(.*)" file, which is blacklisted/ ) {
448            $cc = "Blocked Attachment";
449            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
450         }
451         elsif ( $ThisOne =~ /believed to be spam/ ) {
452            $cc = "Blocked Fragmented Message";
453            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
454         }
455         elsif ( $ThisOne =~ /[Ww]arning: dnsbl\.sorbs\.net/ ) {
456            $cc = "Blocked by DNSBL (SORBS)";
457            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
458         }
459         elsif ( $ThisOne =~ /fragments administratively prohibited/ ) {
460            $cc = "Blocked Fragmented Message";
461            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
462         }
463         elsif ( $ThisOne =~ m/unqualified sender rejected: <(.*)>/ ) {
464            $cc = "Unqualified Sender";
465            $bb = "$1";
466         }
467         elsif ( $ThisOne =~ m/unqualified recipient rejected: <(.*)>/ ) {
468            $cc = "Unqualified Receipient";
469            $bb = "$1";
470         }
471         elsif ( $ThisOne =~ m/not accept Windows executables/ ) {
472            $cc = "Blocked Attachment";
473            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
474         }
475         elsif ( $ThisOne =~ m/remote host address is the local host/ ) {
476            $cc = "Invalid local domain";
477            ( $bb ) = ($ThisOne =~ m/\@[^>]+/);
478         }
479         else {
480            # If we picked up a malfunction but didn't collect it here,
481            # no need to make the user suffer with superfluous error
482            # messages.
483            #next;
484            print "Didn't Summarize: $ThisOne\n";
485         }
486         if ($cc =~ m/Blocked/ ) {
487            # hash of blocked things
488            my $h = {};
489            if (!defined($detail{$cc})) {
490               # debug print "add type $cc\n" ;
491               $detail{$cc} = $h;
492            }
493            $h = $detail{$cc};
494
495            if (defined($h{$bb})) {
496               # debug print "add $bb to ".$h{$bb}."\n" ;
497               $h{$bb} = $h{$bb} + 1;
498            }
499            else {
500               $h{$bb} = 1;
501               # debug print "start $bb at ".$h{$bb}."\n" ;
502            }
503            # marker
504            $spam{$cc} = "";
505         }
506         else {
507
508            if (defined( $spam{$cc} )) {
509               $mid = $spam{$cc};
510            }
511            $spam{$cc} = "$mid$aa : $bb,";
512
513         }
514      }
515      foreach $ThisOne (sort(keys %spam)) {
516         if ($Detail >= $LvlDontAcceptLines) {
517            if ($spam{$cc} eq "") {
518               print "  $ThisOne\n";
519               my $h = $detail{$ThisOne};
520               foreach $aa (sort(keys %h) ) {
521                  print "    $aa : ".$h{$aa}." times\n";
522               }
523            }
524            else {
525               print "  $ThisOne\n";
526               foreach $aa ( sort( split /,/, $spam{$ThisOne} )) {
527                  print "    $aa\n";
528               }
529            }
530         }
531         else {
532            @errList = split /,/, $spam{$ThisOne};
533            print "  $ThisOne ".scalar @errList." times\n";
534         }
535      }
536   }
537}
538
539if ($Detail >= $LvlProtocol) {
540# Print Protocol Violations
541   if (%Proto) {
542      my (%spam);
543
544      # Probable SPAM hosts...
545      print "\n--- Bad Hosts ---\n";
546      foreach $ThisOne (sort(keys %Proto)) {
547         # We need this blank.
548         $mid = "";
549         # IP address/current issue holder.
550         $bb = "";
551         $cc = "";
552         # Extract exim date and time string...
553         ($mdate, $mtime) = ($ThisOne =~ m/^(\d+-\d+-\d+)\s(\d+\:\d+\:\d+)\s/);
554         # Link date and time (looks cleaner)...
555         $aa = "$mdate $mtime";
556
557         if ( $ThisOne =~ m/SMTP protocol violation\:\s(.*?\(.*?\))\:/ ) {
558            $cc = $1;
559            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
560         }
561         elsif ( $ThisOne =~ /unexpected disconnection while reading SMTP command/ ) {
562            $cc = "Sudden disconnect while expecting remote input";
563            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
564         }
565         elsif ( $ThisOne =~ m/rejected ([HE][EH])LO from \[($IPAddress)\]\:\s(.*?):\s(.*?)$/ ) {
566            $cc = "Rejected HELO/EHLO: $3";
567            $bb = "$2 ($1LO $4)";
568         }
569         elsif ( $ThisOne =~ /SMTP data timeout \(message abandoned\) on connection from/ ) {
570            $cc = "SMTP Timeout errors";
571            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
572         }
573         elsif ( $ThisOne =~ /SMTP command timeout on connection from/ ) {
574            $cc = "SMTP Timeout errors";
575            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
576         }
577         elsif ( $ThisOne =~ /syntactically invalid argument/ ) {
578            $cc = "SMTP Syntax errors";
579            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
580         }
581         elsif ( $ThisOne =~ /SMTP syntax error in/ ) {
582            $cc = "SMTP Syntax errors";
583            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
584         }
585         elsif ( $ThisOne =~ /remote host used my name in HELO/ ) {
586            $cc = "My name in HELO";
587            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
588         }
589         elsif ( $ThisOne =~ /remote host used IP address in HELO/ ) {
590            $cc = "IP address in HELO";
591            ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/);
592         }
593         elsif ( $ThisOne =~ /incomplete transaction (\(.*\))/ ) {
594            $bb = "SMTP transaction cut short $1";
595            $SmtpConnection{$bb}++;
596         }
597         elsif ( $ThisOne =~ /SMTP protocol synchronization error/ ) {
598            $bb = "SMTP protocol synchronization error";
599            $SmtpConnection{$bb}++;
600         }
601         elsif ( $ThisOne =~ /dropped: too many nonmail commands/ ) {
602            $bb = "Connection dropped after too many nonmail SMTP commands";
603            $SmtpConnection{$bb}++;
604         }
605         elsif ( $ThisOne =~ /dropped: too many syntax or protocol errors/ ) {
606            $bb = "Connection dropped after too many syntax/protocol errors";
607            $SmtpConnection{$bb}++;
608         }
609         elsif ( $ThisOne =~ /(SMTP protocol error in \"\w+\")/ ) {
610            $bb = $1;
611            $SmtpConnection{$bb}++;
612         }
613         elsif ( $ThisOne =~ /authenticator failed for \([^)]*\) \[($IPAddress)\]:\d+ I=\[$IPAddress\]:\d+: (.*) \(/ ) {
614            $bb = $1;
615            $SmtpConnection{$bb}++;
616         }
617         elsif ( $ThisOne =~ /SMTP connection from/ ) {
618            if ( $ThisOne =~ /lost while reading message data/ ) {
619               $bb = "SMTP connection lost while reading message data";
620            }
621            elsif ( $ThisOne =~ /Connection reset by peer/ ) {
622               $bb = "SMTP connection lost when connection reset by peer ";
623            }
624            elsif ( $ThisOne =~ /lost/ ) {
625               $bb = "SMTP connection lost (non-specific)";
626            }
627            elsif ( $ThisOne =~ /closed by QUIT/ ) {
628               $bb = "SMTP connection closed by QUIT";
629            }
630            elsif ( $ThisOne =~ /closed after SIGTERM/ ) {
631               $bb = "SMTP connection closed after SIGTERM";
632            }
633            elsif ( $ThisOne =~ /TCP\/IP connection count/ ) {
634               $bb = "SMTP connection TCP/IP connection count (warning)";
635            }
636            if ( $bb ne "" ) {
637               $SmtpConnection{$bb}++;
638            }
639         }
640         else {
641            # If we picked up a malfunction but didn't collect it here,
642            # no need to make the user suffer with superfluous error
643            # messages.
644            #next;
645            print "Didn't Summarize: $ThisOne\n";
646         }
647         if (defined( $spam{$cc} )) {
648            $mid = $spam{$cc};
649         }
650         # We're picking things up in this larger block that do not
651         #  ... fit into this mold, so - let's make sure that this is valid
652         #  ... before we set it:
653         if (( $cc ne '' ) && ( $bb ne '' )) {
654            $spam{$cc} = "$mid$aa : IP:$bb,";
655         }
656      }
657      foreach $ThisOne (sort(keys %spam)) {
658         if ($Detail >= $LvlProtocolLines) {
659            print " $ThisOne:\n";
660            foreach $aa ( sort( split /,/, $spam{$ThisOne} )) {
661               print "    $aa\n";
662            }
663         }
664         else {
665            @errList = split /,/, $spam{$ThisOne};
666            print "  $ThisOne ".scalar @errList." times\n";
667         }
668      }
669
670      if ( %SmtpConnection ) {
671         print "\n--- SMTP Connection Issues \n";
672         foreach $ThisOne (keys %SmtpConnection) {
673            $bb = $SmtpConnection{$ThisOne};
674            print "  $ThisOne: $bb Time(s)\n";
675         }
676      }
677
678      if (@ReverseLookupH) {
679         print "\n--- Failed Reverse Lookups \n";
680         print "--- $ReverseLookup  Time(s)\n\n";
681
682         if ($Detail >= $LvlProtocolLines) {
683            foreach $ThisOne (@ReverseLookupH) {
684               print "   $ThisOne\n";
685            }
686         }
687      }
688
689      if (@LookupH) {
690         print "\n--- Failed Reverse Lookups \n";
691         print "--- (eg. spam try): $Lookup  Time(s)\n\n";
692
693         if ($Detail >= $LvlProtocolLines) {
694            foreach $ThisOne (@LookupH) {
695               print "$ThisOne\n";
696            }
697         }
698      }
699   }
700}
701
702if ($Detail >= $LvlMsgs) {
703   # Messages by ID
704   if (keys %mmsg ) {
705      my $tmsgcount=0;
706      my $tmsgrcpts=0;
707      print "\n--- Messages history ---\n\n";
708      # mmsg is hashed by message id, which is sorted by time
709      foreach $tmsg (sort keys %mmsg) {
710        my @tmsgkeys = sort {wedlug_liczb} keys %{$mmsg{$tmsg}};
711        my $immed_deliv = 1;
712        $immed_deliv = 0 unless $tmsgkeys[0] =~ /^\d+ <=/;
713        foreach my $key (@tmsgkeys[1..$#tmsgkeys-1]) {
714         $immed_deliv = 0 unless $key =~ /^\d+ [-=]>/;
715        }
716        $immed_deliv = 0 unless $tmsgkeys[$#tmsgkeys] =~ /^\d+ Completed/;
717        my $qttmsgcount = 0;
718        my $oldqttmsg = '';
719        if (!$immed_deliv) {
720         print "\-MsgID: $tmsg\: \n";
721         foreach $ttmsg (@tmsgkeys) {
722             $qttmsg = $ttmsg;
723             $qttmsg =~ s/^\d+//; # wywal licznik na poczatku (te od sortowania)
724             $qttmsg =~ s/P\=e*smtp S.+//; # wywal koncowki typu:  P=smtp S=372023 id=
725             if ($oldqttmsg eq $qttmsg) {
726         $qttmsgcount++;
727             } else {
728         $oldqttmsg = $qttmsg;
729         if ($qttmsgcount > 0) {
730            print "\tlast message repeated $qttmsgcount times\n";
731            $qttmsgcount = 0;
732         }
733         print "\t$mmsg{$tmsg}{$ttmsg}$qttmsg\n";
734             }
735         }
736         if ($qttmsgcount > 0) {
737            print "\tlast message repeated $qttmsgcount times\n";
738         }
739        } else {
740         $tmsgcount++;
741         $tmsgrcpts+=$#tmsgkeys-1;
742        }
743      }
744      print "$tmsgcount messages delivered immediately ";
745      print "to $tmsgrcpts total recipients\n";
746   }
747}
748
749# INNE Badziewia
750if (keys %OtherList) {
751   print "\n**Unmatched Entries**\n";
752   foreach $line (sort {$a cmp $b} keys %OtherList) {
753      print "$line: $OtherList{$line} Time(s)\n";
754   }
755}
756
757exit(0);
758
759# vi: shiftwidth=3 tabstop=3 syntax=perl et
760# Local Variables:
761# mode: perl
762# perl-indent-level: 3
763# indent-tabs-mode: nil
764# End:
765