File Coverage

lib/Sisimai/Lhost/mFILTER.pm
Criterion Covered Total %
statement 61 63 96.8
branch 33 40 82.5
condition 25 31 80.6
subroutine 6 6 100.0
pod 2 2 100.0
total 127 142 89.4


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::mFILTER;
2 38     38   3460 use parent 'Sisimai::Lhost';
  38         64  
  38         200  
3 38     38   2592 use v5.26;
  38         265  
4 38     38   156 use strict;
  38         175  
  38         876  
5 38     38   273 use warnings;
  38         75  
  38         25289  
6              
7 1     1 1 2 sub description { 'Digital Arts m-FILTER: https://www.daj.jp/bs/mf/' }
8             sub inquire {
9             # Detect an error from Digital Arts m-FILTER
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.1
15 903     903 1 2667 my $class = shift;
16 903   100     1855 my $mhead = shift // return undef;
17 902   100     1685 my $mbody = shift // return undef;
18              
19 901         1790 state $indicators = __PACKAGE__->INDICATORS;
20 901         1071 state $boundaries = ['-------original message', '-------original mail info'];
21 901         1090 state $startingof = {
22             'command' => ['-------SMTP command'],
23             'error' => ['-------server message'],
24             };
25              
26             # X-Mailer: m-FILTER
27 901         972 my $proceedsto = 0;
28 901 100 100     2500 $proceedsto = 1 if defined $mhead->{'x-mailer'} && $mhead->{'x-mailer'} eq 'm-FILTER';
29 901 100 100     1564 $proceedsto ||= 1 if grep { index($$mbody, $_) > 1 } @$boundaries;
  1802         4772  
30 901 100 50     1792 $proceedsto ||= 1 if grep { index($$mbody, $_) > 1 } $startingof->{'command'}->@*;
  901         4327  
31 901 100 50     1535 $proceedsto ||= 1 if grep { index($$mbody, $_) > 1 } $startingof->{'error'}->@*;
  901         2339  
32 901 100       2119 return undef unless $proceedsto;
33              
34 27         69 my $dscontents = [__PACKAGE__->DELIVERYSTATUS]; my $v = undef;
  27         33  
35 27         82 my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries);
36 27         31 my $readcursor = 0; # (Integer) Points the current cursor position
37 27         25 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
38 27         56 my $markingset = {'diagnosis' => 0, 'command' => 0};
39              
40 27         121 for my $e ( split("\n", $emailparts->[0]) ) {
41             # Read error messages and delivery status lines from the head of the email to the previous
42             # line of the beginning of the original message.
43 351 100       401 unless( $readcursor ) {
44             # Beginning of the bounce message or message/delivery-status part
45 162 100 66     410 if( index($e, '@') > 1 && index($e, ' ') < 0 && Sisimai::Address->is_emailaddress($e) ) {
      100        
46 27         42 $readcursor |= $indicators->{'deliverystatus'};
47             }
48             }
49 351 100 100     610 next if ($readcursor & $indicators->{'deliverystatus'}) == 0 || $e eq "";
50              
51             # このメールは「m-FILTER」が自動的に生成して送信しています。
52             # メールサーバーとの通信中、下記の理由により
53             # このメールは送信できませんでした。
54             #
55             # 以下のメールアドレスへの送信に失敗しました。
56             # kijitora@example.jp
57             #
58             #
59             # -------server message
60             # 550 5.1.1 unknown user
61             #
62             # -------SMTP command
63             # DATA
64             #
65             # -------original message
66 135         130 $v = $dscontents->[-1];
67              
68 135 100 100     323 if( index($e, '@') > 0 && index($e, ' ') < 0 ) {
    100 66        
69             # 以下のメールアドレスへの送信に失敗しました。
70             # kijitora@example.jp
71 27 50       54 if( $v->{'recipient'} ) {
72             # There are multiple recipient addresses in the message body.
73 0         0 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
74 0         0 $v = $dscontents->[-1];
75             }
76 27         55 $v->{'recipient'} = $e;
77 27         31 $recipients++;
78              
79             } elsif( length $e == 4 && index($e, ' ') < 0 ) {
80             # -------SMTP command
81             # DATA
82 27 50       40 next if $v->{'command'};
83 27 50       58 $v->{'command'} = $e if $markingset->{'command'};
84              
85             } else {
86             # Get error message and SMTP command
87 81 100       150 if( $e eq $startingof->{'error'}->[0] ) {
    100          
88             # -------server message
89 27         51 $markingset->{'diagnosis'} = 1;
90              
91             } elsif( $e eq $startingof->{'command'}->[0] ) {
92             # -------SMTP command
93 27         33 $markingset->{'command'} = 1;
94              
95             } else {
96             # 550 5.1.1 unknown user
97 27 50       38 next if index($e, '-') == 0;
98 27 50       42 next if $v->{'diagnosis'};
99 27         34 $v->{'diagnosis'} = $e;
100             }
101             } # End of error message part
102             }
103 27 50       71 return undef unless $recipients;
104              
105 27         40 for my $e ( @$dscontents ) {
106             # Get localhost and remote host name from Received header.
107 27 50       50 next unless scalar $mhead->{'received'}->@*;
108 27         35 my $rheads = $mhead->{'received'};
109 27         106 my $rhosts = Sisimai::RFC5322->received($rheads->[-1]);
110              
111 27   33     112 $e->{'lhost'} ||= shift Sisimai::RFC5322->received($rheads->[0])->@*;
112 27         73 for my $ee ( $rhosts->[0], $rhosts->[1] ) {
113             # Avoid "... by m-FILTER"
114 54 100       115 next unless rindex($ee, '.') > -1;
115 27         45 $e->{'rhost'} = $ee;
116             }
117             }
118 27         130 return {"ds" => $dscontents, "rfc822" => $emailparts->[1]};
119             }
120              
121             1;
122             __END__