File Coverage

lib/Sisimai/Lhost/X2.pm
Criterion Covered Total %
statement 43 43 100.0
branch 16 18 88.8
condition 3 4 75.0
subroutine 6 6 100.0
pod 2 2 100.0
total 70 73 95.8


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::X2;
2 18     18   6469 use parent 'Sisimai::Lhost';
  18         39  
  18         105  
3 18     18   1115 use feature ':5.10';
  18         47  
  18         1338  
4 18     18   119 use strict;
  18         53  
  18         744  
5 18     18   95 use warnings;
  18         42  
  18         10319  
6              
7 2     2 1 1311 sub description { 'Unknown MTA #2' }
8             sub make {
9             # Detect an error from Unknown MTA #2
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.7
15 228     228 1 737 my $class = shift;
16 228   100     685 my $mhead = shift // return undef;
17 227   50     639 my $mbody = shift // return undef;
18              
19 227 100       890 return undef unless index($mhead->{'from'}, 'MAILER-DAEMON@') > -1;
20 107 100       597 return undef unless $mhead->{'subject'} =~ /\A(?>Delivery[ ]failure|fail(?:ure|ed)[ ]delivery)/;
21              
22 26         68 state $indicators = __PACKAGE__->INDICATORS;
23 26         52 state $rebackbone = qr|^--- Original message follows[.]|m;
24 26         62 state $startingof = { 'message' => ['Unable to deliver message to the following address'] };
25              
26 26         98 my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
27 26         142 my $emailsteak = Sisimai::RFC5322->fillet($mbody, $rebackbone);
28 26         54 my $readcursor = 0; # (Integer) Points the current cursor position
29 26         46 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
30 26         44 my $v = undef;
31              
32 26         149 for my $e ( split("\n", $emailsteak->[0]) ) {
33             # Read error messages and delivery status lines from the head of the email
34             # to the previous line of the beginning of the original message.
35 175 100       289 unless( $readcursor ) {
36             # Beginning of the bounce message or message/delivery-status part
37 52 100       203 $readcursor |= $indicators->{'deliverystatus'} if index($e, $startingof->{'message'}->[0]) == 0;
38 52         86 next;
39             }
40 123 50       242 next unless $readcursor & $indicators->{'deliverystatus'};
41 123 100       225 next unless length $e;
42              
43             # Message from example.com.
44             # Unable to deliver message to the following address(es).
45             #
46             # :
47             # This user doesn't have a example.com account (kijitora@example.com) [0]
48 87         116 $v = $dscontents->[-1];
49              
50 87 100       254 if( $e =~ /\A[<]([^ ]+[@][^ ]+)[>]:\z/ ) {
51             # :
52 36 100       103 if( $v->{'recipient'} ) {
53             # There are multiple recipient addresses in the message body.
54 10         33 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
55 10         21 $v = $dscontents->[-1];
56             }
57 36         99 $v->{'recipient'} = $1;
58 36         70 $recipients++;
59              
60             } else {
61             # This user doesn't have a example.com account (kijitora@example.com) [0]
62 51         159 $v->{'diagnosis'} .= ' '.$e;
63             }
64             }
65 26 50       91 return undef unless $recipients;
66              
67 26         180 $_->{'diagnosis'} = Sisimai::String->sweep($_->{'diagnosis'}) for @$dscontents;
68 26         130 return { 'ds' => $dscontents, 'rfc822' => $emailsteak->[1] };
69             }
70              
71             1;
72             __END__