File Coverage

lib/Sisimai/Lhost/ApacheJames.pm
Criterion Covered Total %
statement 57 59 96.6
branch 32 44 72.7
condition 9 16 56.2
subroutine 6 6 100.0
pod 2 2 100.0
total 106 127 83.4


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::ApacheJames;
2 37     37   3976 use parent 'Sisimai::Lhost';
  37         81  
  37         251  
3 37     37   2903 use v5.26;
  37         148  
4 37     37   213 use strict;
  37         82  
  37         1056  
5 37     37   159 use warnings;
  37         111  
  37         31244  
6              
7 1     1 1 4 sub description { 'James: https://james.apache.org/' }
8             sub inquire {
9             # Detect an error from Apache James
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.26
15 888     888 1 3715 my $class = shift;
16 888   100     2528 my $mhead = shift // return undef;
17 887   100     2726 my $mbody = shift // return undef;
18 886 50 0     1607 my $match = 0; $match ||= 1 if $mhead->{'subject'} eq '[BOUNCE]';
  886         3418  
19 886 100 50     6042 $match ||= 1 if defined $mhead->{'message-id'} && rindex($mhead->{'message-id'}, '.JavaMail.') > -1;
      100        
20 886 50 0     2176 $match ||= 1 if grep { rindex($_, 'JAMES SMTP Server') > -1 } $mhead->{'received'}->@*;
  1714         5883  
21 886 100       3969 return undef unless $match;
22              
23 6         28 state $indicators = __PACKAGE__->INDICATORS;
24 6         12 state $boundaries = ["Content-Type: message/rfc822"];
25 6         13 state $startingof = {
26             # apache-james-2.3.2/src/java/org/apache/james/transport/mailets/
27             # AbstractNotify.java|124: out.println("Error message below:");
28             # AbstractNotify.java|128: out.println("Message details:");
29             "message" => ["Message details:"],
30             };
31              
32 6         35 my $dscontents = [__PACKAGE__->DELIVERYSTATUS]; my $v = $dscontents->[-1];
  6         14  
33 6         27 my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries);
34 6         10 my $readcursor = 0; # Points the current cursor position
35 6         10 my $recipients = 0; # The number of 'Final-Recipient' header
36 6         29 my $alternates = ["", "", "", ""]; # [Envelope-From, Header-From, Date, Subject]
37              
38 6         64 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 84 100       118 unless( $readcursor ) {
42             # Beginning of the bounce message or message/delivery-status part
43 36 100       79 if( index($e, $startingof->{"message"}->[0]) == 0 ) {
44             # Message details:
45             # Subject: Nyaaan
46 6         12 $readcursor |= $indicators->{"deliverystatus"}; next;
  6         11  
47             }
48 30 100       62 $v->{"diagnosis"} .= $e." " if $e ne "";
49 30         44 next;
50             }
51 48 50 33     113 next if ($readcursor & $indicators->{'deliverystatus'}) == 0 || $e eq "";
52              
53             # Message details:
54             # Subject: Nyaaan
55             # Sent date: Thu Apr 29 01:20:50 JST 2015
56             # MAIL FROM: shironeko@example.jp
57             # RCPT TO: kijitora@example.org
58             # From: Neko
59             # To: kijitora@example.org
60             # Size (in bytes): 1024
61             # Number of lines: 64
62 48 100       160 if( index($e, " RCPT TO: ") == 0 ) {
    100          
    100          
    100          
    100          
63             # RCPT TO: kijitora@example.org
64 6 50       17 if( $v->{"recipient"} ) {
65             # There are multiple recipient addresses in the message body.
66 0         0 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
67 0         0 $v = $dscontents->[-1];
68             }
69 6         10 $v->{"recipient"} = substr($e, 12,);
70 6         10 $recipients++;
71              
72             } elsif( index($e, " Sent date: ") == 0 ) {
73             # Sent date: Thu Apr 29 01:20:50 JST 2015
74 6         11 $v->{"date"} = substr($e, 13,);
75 6         11 $alternates->[2] = $v->{"date"};
76              
77             } elsif( index($e, " Subject: ") == 0 ) {
78             # Subject: Nyaaan
79 6         21 $alternates->[3] = substr($e, 11,);
80              
81             } elsif( index($e, " MAIL FROM: ") == 0 ) {
82             # MAIL FROM: shironeko@example.jp
83 6         13 $alternates->[0] = substr($e, 13,);
84              
85             } elsif( index($e, " From: ") == 0 ) {
86             # From: Neko
87 6         12 $alternates->[1] = substr($e, 8,);
88             }
89             }
90 6 50       30 return undef unless $recipients;
91              
92 6 50       18 if( $emailparts->[1] eq "" ) {
93             # The original message is empty
94 6 50       22 $emailparts->[1] .= sprintf("From: %s\n", $alternates->[1]) if $alternates->[1] ne "";
95 6 50       18 $emailparts->[1] .= sprintf("Date: %s\n", $alternates->[2]) if $alternates->[2] ne "";
96             }
97 6 50       46 if( index($emailparts->[1], "Return-Path: ") < 0 ) {
98             # Set the envelope from address as a Return-Path: header
99 6 50       20 $emailparts->[1] .= sprintf("Return-Path: <%s>\n", $alternates->[0]) if $alternates->[0] ne "";
100             }
101 6 50       40 if( index($emailparts->[1], "\nSubject: ") < 0 ) {
102             # Set the envelope from address as a Return-Path: header
103 6 50       33 $emailparts->[1] .= sprintf("Subject: %s\n", $alternates->[3]) if $alternates->[3] ne "";
104             }
105 6         38 $_->{"diagnosis"} = Sisimai::String->sweep($_->{"diagnosis"}) for @$dscontents;
106 6         31 return {"ds" => $dscontents, "rfc822" => $emailparts->[1]};
107             }
108              
109             1;
110             __END__