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   5149 use parent 'Sisimai::Lhost';
  18         28  
  18         86  
3 18     18   995 use feature ':5.10';
  18         31  
  18         1074  
4 18     18   81 use strict;
  18         31  
  18         427  
5 18     18   73 use warnings;
  18         46  
  18         9215  
6              
7 2     2 1 976 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 651 my $class = shift;
16 228   100     532 my $mhead = shift // return undef;
17 227   50     570 my $mbody = shift // return undef;
18              
19 227 100       932 return undef unless index($mhead->{'from'}, 'MAILER-DAEMON@') > -1;
20 107 100       545 return undef unless $mhead->{'subject'} =~ /\A(?>Delivery[ ]failure|fail(?:ure|ed)[ ]delivery)/;
21              
22 26         58 state $indicators = __PACKAGE__->INDICATORS;
23 26         44 state $rebackbone = qr|^--- Original message follows[.]|m;
24 26         42 state $startingof = { 'message' => ['Unable to deliver message to the following address'] };
25              
26 26         78 my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
27 26         129 my $emailsteak = Sisimai::RFC5322->fillet($mbody, $rebackbone);
28 26         56 my $readcursor = 0; # (Integer) Points the current cursor position
29 26         39 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
30 26         41 my $v = undef;
31              
32 26         123 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       219 unless( $readcursor ) {
36             # Beginning of the bounce message or message/delivery-status part
37 52 100       178 $readcursor |= $indicators->{'deliverystatus'} if index($e, $startingof->{'message'}->[0]) == 0;
38 52         62 next;
39             }
40 123 50       176 next unless $readcursor & $indicators->{'deliverystatus'};
41 123 100       165 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         88 $v = $dscontents->[-1];
49              
50 87 100       260 if( $e =~ /\A[<]([^ ]+[@][^ ]+)[>]:\z/ ) {
51             # :
52 36 100       122 if( $v->{'recipient'} ) {
53             # There are multiple recipient addresses in the message body.
54 10         27 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
55 10         17 $v = $dscontents->[-1];
56             }
57 36         86 $v->{'recipient'} = $1;
58 36         52 $recipients++;
59              
60             } else {
61             # This user doesn't have a example.com account (kijitora@example.com) [0]
62 51         123 $v->{'diagnosis'} .= ' '.$e;
63             }
64             }
65 26 50       86 return undef unless $recipients;
66              
67 26         162 $_->{'diagnosis'} = Sisimai::String->sweep($_->{'diagnosis'}) for @$dscontents;
68 26         115 return { 'ds' => $dscontents, 'rfc822' => $emailsteak->[1] };
69             }
70              
71             1;
72             __END__