File Coverage

lib/Sisimai/Lhost/Activehunter.pm
Criterion Covered Total %
statement 43 45 95.5
branch 16 20 80.0
condition 4 7 57.1
subroutine 6 6 100.0
pod 2 2 100.0
total 71 80 88.7


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::Activehunter;
2 15     15   7086 use parent 'Sisimai::Lhost';
  15         37  
  15         79  
3 15     15   935 use feature ':5.10';
  15         52  
  15         1047  
4 15     15   96 use strict;
  15         32  
  15         328  
5 15     15   77 use warnings;
  15         29  
  15         8647  
6              
7 2     2 1 1268 sub description { 'TransWARE Active!hunter' };
8             sub make {
9             # Detect an error from TransWARE Active!hunter
10             # @param [Hash] mhead Message headers of a bounce email
11             # @param [String] mbody Message body of a bounce email
12             # @return [Hash] Bounce data list and message/rfc822 part
13             # @return [Undef] failed to parse or the arguments are missing
14             # @since v4.1.1
15 199     199 1 761 my $class = shift;
16 199   100     582 my $mhead = shift // return undef;
17 198   50     521 my $mbody = shift // return undef;
18              
19             # 'from' => qr/\A"MAILER-DAEMON"/,
20             # 'subject' => qr/FAILURE NOTICE :/,
21 198 100       749 return undef unless defined $mhead->{'x-ahmailid'};
22              
23 11         64 state $indicators = __PACKAGE__->INDICATORS;
24 11         40 state $rebackbone = qr|^Content-Type:[ ]message/rfc822|m;
25 11         28 state $startingof = { 'message' => [' ----- The following addresses had permanent fatal errors -----'] };
26              
27 11         52 my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
28 11         106 my $emailsteak = Sisimai::RFC5322->fillet($mbody, $rebackbone);
29 11         54 my $readcursor = 0; # (Integer) Points the current cursor position
30 11         27 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
31 11         43 my $v = undef;
32              
33 11         91 for my $e ( split("\n", $emailsteak->[0]) ) {
34             # Read error messages and delivery status lines from the head of the email
35             # to the previous line of the beginning of the original message.
36 121 100       190 unless( $readcursor ) {
37             # Beginning of the bounce message or delivery status part
38 66 100       196 $readcursor |= $indicators->{'deliverystatus'} if index($e, $startingof->{'message'}->[0]) == 0;
39 66         93 next;
40             }
41 55 50       129 next unless $readcursor & $indicators->{'deliverystatus'};
42 55 100       108 next unless length $e;
43              
44             # ----- The following addresses had permanent fatal errors -----
45             #
46             # >>> kijitora@example.org
47             #
48             # ----- Transcript of session follows -----
49             # 550 sorry, no mailbox here by that name (#5.1.1 - chkusr)
50 33         56 $v = $dscontents->[-1];
51              
52 33 100       144 if( $e =~ /\A[>]{3}[ \t]+.+[<]([^ ]+?[@][^ ]+?)[>]\z/ ) {
53             # >>> kijitora@example.org
54 11 50       40 if( $v->{'recipient'} ) {
55             # There are multiple recipient addresses in the message body.
56 0         0 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
57 0         0 $v = $dscontents->[-1];
58             }
59 11         42 $v->{'recipient'} = $1;
60 11         20 $recipients++;
61              
62             } else {
63             # ----- Transcript of session follows -----
64             # 550 sorry, no mailbox here by that name (#5.1.1 - chkusr)
65 22 100       99 next unless $e =~ /\A[0-9A-Za-z]+/;
66 11 50       57 next if length $v->{'diagnosis'};
67 11   33     64 $v->{'diagnosis'} ||= $e;
68             }
69             }
70 11 50       45 return undef unless $recipients;
71              
72 11         54 require Sisimai::String;
73 11         106 $_->{'diagnosis'} = Sisimai::String->sweep($_->{'diagnosis'}) for @$dscontents;
74 11         151 return { 'ds' => $dscontents, 'rfc822' => $emailsteak->[1] };
75             }
76              
77             1;
78             __END__