File Coverage

lib/Sisimai/Lhost/KDDI.pm
Criterion Covered Total %
statement 59 63 93.6
branch 25 34 73.5
condition 12 23 52.1
subroutine 6 6 100.0
pod 2 2 100.0
total 104 128 81.2


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::KDDI;
2 40     40   4537 use parent 'Sisimai::Lhost';
  40         78  
  40         413  
3 40     40   7266 use v5.26;
  40         154  
4 40     40   273 use strict;
  40         73  
  40         1239  
5 40     40   241 use warnings;
  40         107  
  40         36650  
6              
7 1     1 1 4 sub description { 'au by KDDI: https://www.au.kddi.com' }
8             sub inquire {
9             # Detect an error from au by KDDI
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.0.0
15 914     914 1 4300 my $class = shift;
16 914   100     5535 my $mhead = shift // return undef;
17 913   100     3314 my $mbody = shift // return undef;
18 912 50 0     1516 my $match = 0; $match ||= 1 if Sisimai::String->aligned(\$mhead->{'from'}, ['no-reply@.', '.dion.ne.jp']);
  912         8233  
19 912 100 50     4918 $match ||= 1 if $mhead->{'reply-to'} && $mhead->{'reply-to'} eq 'no-reply@app.auone-net.jp';
      100        
20 912 50 0     2716 $match ||= 1 if grep { rindex($_, 'ezweb.ne.jp (') > -1 } $mhead->{'received'}->@*;
  1775         4778  
21 912 50 0     2209 $match ||= 1 if grep { rindex($_, '.au.com (') > -1 } $mhead->{'received'}->@*;
  1775         4317  
22 912 100       3530 return undef unless $match;
23              
24 16         55 state $indicators = __PACKAGE__->INDICATORS;
25 16         30 state $boundaries = ['Content-Type: message/rfc822'];
26 16         51 state $startingof = {'message' => ['Your mail sent on:', 'Your mail attempted to be delivered on:']};
27 16         44 state $messagesof = {
28             'mailboxfull' => ['As their mailbox is full'],
29             'norelaying' => ['Due to the following SMTP relay error'],
30             'hostunknown' => ['As the remote domain doesnt exist'],
31             };
32              
33 16         112 my $dscontents = [__PACKAGE__->DELIVERYSTATUS]; my $v = undef;
  16         36  
34 16         74 my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries);
35 16         33 my $readcursor = 0; # (Integer) Points the current cursor position
36 16         24 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
37              
38 16         109 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 138 100       232 unless( $readcursor ) {
42             # Beginning of the bounce message or message/delivery-status part
43 106 100       142 $readcursor |= $indicators->{'deliverystatus'} if grep { index($e, $_) == 0 } $startingof->{'message'}->@*;
  212         397  
44             }
45 138 100 66     376 next if ($readcursor & $indicators->{'deliverystatus'}) == 0 || $e eq "";
46              
47 48         88 $v = $dscontents->[-1];
48 48 100       196 if( index($e, ' Could not be delivered to: <') > -1 ) {
    100          
49             # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
50             # Could not be delivered to: <******@**.***.**>
51             # As their mailbox is full.
52 16 50       37 if( $v->{'recipient'} ) {
53             # There are multiple recipient addresses in the message body.
54 0         0 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
55 0         0 $v = $dscontents->[-1];
56             }
57              
58 16         169 my $r = Sisimai::Address->s3s4(substr($e, index($e, '<') + 1, ));
59 16 50       84 next unless Sisimai::Address->is_emailaddress($r);
60 16         66 $v->{'recipient'} = $r;
61 16         40 $recipients++;
62              
63             } elsif( index($e, 'Your mail sent on: ') > -1 ) {
64             # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
65 16         52 $v->{'date'} = substr($e, 19, );
66              
67             } else {
68             # As their mailbox is full.
69 16 50       80 $v->{'diagnosis'} .= $e.' ' if index($e, ' ') == 0;
70             }
71             }
72 16 50       55 return undef unless $recipients;
73              
74 16         98 require Sisimai::SMTP::Command;
75 16         30 for my $e ( @$dscontents ) {
76 16         90 $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'});
77 16   50     159 $e->{'command'} = Sisimai::SMTP::Command->find($e->{'diagnosis'}) || '';
78              
79 16 50 33     63 if( defined $mhead->{'x-spasign'} && $mhead->{'x-spasign'} eq 'NG' ) {
80             # Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by KDDI)
81             # Filtered recipient returns message that include 'X-SPASIGN' header
82 0         0 $e->{'reason'} = 'filtered';
83              
84             } else {
85 16 50       41 if( $e->{'command'} eq 'RCPT' ) {
86             # set "userunknown" when the remote server rejected after RCPT command.
87 0         0 $e->{'reason'} = 'userunknown';
88              
89             } else {
90             # SMTP command is not RCPT
91 16         68 SESSION: for my $r ( keys %$messagesof ) {
92             # Verify each regular expression of session errors
93 42 100       70 next unless grep { index($e->{'diagnosis'}, $_) > -1 } $messagesof->{ $r }->@*;
  42         115  
94 16         34 $e->{'reason'} = $r;
95 16         40 last;
96             }
97             }
98             }
99             }
100 16         118 return {"ds" => $dscontents, "rfc822" => $emailparts->[1]};
101             }
102              
103             1;
104             __END__