File Coverage

lib/Sisimai/Lhost/X2.pm
Criterion Covered Total %
statement 47 48 97.9
branch 27 28 96.4
condition 20 27 74.0
subroutine 6 6 100.0
pod 2 2 100.0
total 102 111 91.8


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::X2;
2 36     36   4230 use parent 'Sisimai::Lhost';
  36         76  
  36         263  
3 36     36   3694 use v5.26;
  36         149  
4 36     36   181 use strict;
  36         64  
  36         1078  
5 36     36   212 use warnings;
  36         59  
  36         25897  
6              
7 1     1 1 5 sub description { 'Unknown MTA #2' }
8             sub inquire {
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 decode or the arguments are missing
14             # @since v4.1.7
15 913     913 1 3613 my $class = shift;
16 913   100     2946 my $mhead = shift // return undef;
17 912   100     2383 my $mbody = shift // return undef;
18 911 100 50     1454 my $match = 0; $match ||= 1 if index($mhead->{'from'}, 'MAILER-DAEMON@') > -1;
  911         6190  
19 911 100 100     3274 $match ||= 1 if index($mhead->{'subject'}, 'Delivery failure') == 0;
20 911 100 50     2877 $match ||= 1 if index($mhead->{'subject'}, 'failure delivery') == 0;
21 911 100 50     3973 $match ||= 1 if index($mhead->{'subject'}, 'failed delivery') == 0;
22 911 100       3745 return undef unless $match > 0;
23              
24 323         840 state $indicators = __PACKAGE__->INDICATORS;
25 323         548 state $boundaries = ['--- Original message follows.'];
26 323         517 state $startingof = {
27             'message' => [
28             'Unable to deliver message to the following address',
29             'This Delivery Status Notification is sent from MTA',
30             ]
31             };
32              
33 323         1733 my $dscontents = [__PACKAGE__->DELIVERYSTATUS]; my $v = undef;
  323         715  
34 323         1839 my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries);
35 323         659 my $readcursor = 0; # (Integer) Points the current cursor position
36 323         564 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
37              
38 323         4916 for my $e ( split("\n", $emailparts->[0]) ) {
39             # Read error messages and delivery status lines from the head of the email to the previous
40             # line of the beginning of the original message.
41 12224 100       17335 unless( $readcursor ) {
42             # Beginning of the bounce message or message/delivery-status part
43 12036 100       15057 $readcursor |= $indicators->{'deliverystatus'} if grep { index($e, $_) == 0 } $startingof->{'message'}->@*;
  24072         42914  
44 12036         14308 next;
45             }
46 188 100 66     811 next if ($readcursor & $indicators->{'deliverystatus'}) == 0 || $e eq "";
47              
48             # Message from example.com.
49             # Unable to deliver message to the following address(es).
50             #
51             # :
52             # This user doesn't have a example.com account (kijitora@example.com) [0]
53             #
54             # --- OR ---
55             #
56             # This Delivery Status Notification is sent from MTA...
57             #
58             # Your delivery to the following address has been failed.
59             # Please refer to the below for details.
60             # ------------------------------------------------------
61             #
62             # Delivery failed: kijitora@example.co.jp
63             # 192.0.2.25 does not like recipient.
64             # Remote host said[Response Message]: 550 5.1.1 :
65             # Recipient address rejected: User unknown in local recipient table
66             # Giving up on 192.0.2.25.
67             # STEP: RCPT TO
68 137         214 $v = $dscontents->[-1];
69              
70 137 100 66     1212 if( index($e, '<') == 0 && Sisimai::String->aligned(\$e, ['<', '@', '>:']) ||
    50 66        
    100 100        
71             index($e, 'Delivery failed: ') == 0 && Sisimai::String->aligned(\$e, ['failed: ', '@']) ) {
72             # :
73             # Delivery failed: kijitora@example.co.jp
74 46 100       156 if( $v->{'recipient'} ) {
75             # There are multiple recipient addresses in the message body.
76 10         60 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
77 10         22 $v = $dscontents->[-1];
78             }
79 46 100       226 $v->{'recipient'} = substr($e, 1, length($e) - 3 ) if index($e, '<') == 0;
80 46   66     170 $v->{'recipient'} ||= substr($e, index($e, ': ') + 2,);
81 46         178 $recipients++;
82              
83             } elsif( index($e, 'STTEP: ') == 0 ) {
84             # STEP: RCPT TO
85             # STEP: DATA SEND
86 0         0 $v->{'command'} = Sisimai::SMTP::Command->find($e)
87              
88             } elsif( index($e, '-----') != 0 ) {
89             # This user doesn't have a example.com account (kijitora@example.com) [0]
90 86         268 $v->{'diagnosis'} .= ' '.$e;
91             }
92             }
93 323 100       3919 return undef unless $recipients;
94              
95 36         215 $_->{'diagnosis'} = Sisimai::String->sweep($_->{'diagnosis'}) for @$dscontents;
96 36         261 return {"ds" => $dscontents, "rfc822" => $emailparts->[1]};
97             }
98              
99             1;
100             __END__