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   6545 use parent 'Sisimai::Lhost';
  18         33  
  18         122  
3 18     18   1098 use feature ':5.10';
  18         31  
  18         1243  
4 18     18   106 use strict;
  18         48  
  18         432  
5 18     18   104 use warnings;
  18         30  
  18         10410  
6              
7 2     2 1 1229 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 740 my $class = shift;
16 228   100     698 my $mhead = shift // return undef;
17 227   50     576 my $mbody = shift // return undef;
18              
19 227 100       985 return undef unless index($mhead->{'from'}, 'MAILER-DAEMON@') > -1;
20 107 100       713 return undef unless $mhead->{'subject'} =~ /\A(?>Delivery[ ]failure|fail(?:ure|ed)[ ]delivery)/;
21              
22 26         100 state $indicators = __PACKAGE__->INDICATORS;
23 26         62 state $rebackbone = qr|^--- Original message follows[.]|m;
24 26         61 state $startingof = { 'message' => ['Unable to deliver message to the following address'] };
25              
26 26         106 my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
27 26         156 my $emailsteak = Sisimai::RFC5322->fillet($mbody, $rebackbone);
28 26         97 my $readcursor = 0; # (Integer) Points the current cursor position
29 26         88 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
30 26         45 my $v = undef;
31              
32 26         158 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       307 unless( $readcursor ) {
36             # Beginning of the bounce message or message/delivery-status part
37 52 100       240 $readcursor |= $indicators->{'deliverystatus'} if index($e, $startingof->{'message'}->[0]) == 0;
38 52         78 next;
39             }
40 123 50       216 next unless $readcursor & $indicators->{'deliverystatus'};
41 123 100       211 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         121 $v = $dscontents->[-1];
49              
50 87 100       274 if( $e =~ /\A[<]([^ ]+[@][^ ]+)[>]:\z/ ) {
51             # :
52 36 100       125 if( $v->{'recipient'} ) {
53             # There are multiple recipient addresses in the message body.
54 10         58 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
55 10         25 $v = $dscontents->[-1];
56             }
57 36         111 $v->{'recipient'} = $1;
58 36         55 $recipients++;
59              
60             } else {
61             # This user doesn't have a example.com account (kijitora@example.com) [0]
62 51         175 $v->{'diagnosis'} .= ' '.$e;
63             }
64             }
65 26 50       95 return undef unless $recipients;
66              
67 26         207 $_->{'diagnosis'} = Sisimai::String->sweep($_->{'diagnosis'}) for @$dscontents;
68 26         159 return { 'ds' => $dscontents, 'rfc822' => $emailsteak->[1] };
69             }
70              
71             1;
72             __END__