File Coverage

lib/Sisimai/Lhost/ApacheJames.pm
Criterion Covered Total %
statement 58 60 96.6
branch 29 38 76.3
condition 8 16 50.0
subroutine 6 6 100.0
pod 2 2 100.0
total 103 122 84.4


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::ApacheJames;
2 18     18   6091 use parent 'Sisimai::Lhost';
  18         35  
  18         94  
3 18     18   1140 use feature ':5.10';
  18         39  
  18         1236  
4 18     18   113 use strict;
  18         35  
  18         408  
5 18     18   92 use warnings;
  18         28  
  18         14593  
6              
7 2     2 1 1245 sub description { 'Java Apache Mail Enterprise Server' }
8             sub make {
9             # Detect an error from ApacheJames
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.26
15 208     208 1 682 my $class = shift;
16 208   100     661 my $mhead = shift // return undef;
17 207   50     459 my $mbody = shift // return undef;
18 207         328 my $match = 0;
19              
20             # 'subject' => qr/\A\[BOUNCE\]\z/,
21             # 'received' => qr/JAMES SMTP Server/,
22             # 'message-id' => qr/\d+[.]JavaMail[.].+[@]/,
23 207 50 0     589 $match ||= 1 if $mhead->{'subject'} eq '[BOUNCE]';
24 207 100 50     1128 $match ||= 1 if defined $mhead->{'message-id'} && rindex($mhead->{'message-id'}, '.JavaMail.') > -1;
      100        
25 207 50 0     328 $match ||= 1 if grep { rindex($_, 'JAMES SMTP Server') > -1 } @{ $mhead->{'received'} };
  386         1028  
  207         484  
26 207 100       641 return undef unless $match;
27              
28 6         32 state $indicators = __PACKAGE__->INDICATORS;
29 6         21 state $rebackbone = qr|^Content-Type:[ ]message/rfc822|m;
30 6         22 state $startingof = {
31             # apache-james-2.3.2/src/java/org/apache/james/transport/mailets/
32             # AbstractNotify.java|124: out.println("Error message below:");
33             # AbstractNotify.java|128: out.println("Message details:");
34             'message' => [''],
35             'error' => ['Error message below:'],
36             };
37              
38 6         25 my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
39 6         37 my $emailsteak = Sisimai::RFC5322->fillet($mbody, $rebackbone);
40 6         17 my $readcursor = 0; # (Integer) Points the current cursor position
41 6         17 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
42 6         15 my $diagnostic = ''; # (String) Alternative diagnostic message
43 6         10 my $subjecttxt = undef; # (String) Alternative Subject text
44 6         11 my $gotmessage = 0; # (Integer) Flag for error message
45 6         8 my $v = undef;
46              
47 6         61 for my $e ( split("\n", $emailsteak->[0]) ) {
48             # Read error messages and delivery status lines from the head of the email
49             # to the previous line of the beginning of the original message.
50 114 100       165 unless( $readcursor ) {
51             # Beginning of the bounce message or message/delivery-status part
52 6 50       29 $readcursor |= $indicators->{'deliverystatus'} if index($e, $startingof->{'message'}->[0]) == 0;
53 6         12 next;
54             }
55 108 50       168 next unless $readcursor & $indicators->{'deliverystatus'};
56 108 100       156 next unless length $e;
57              
58             # Message details:
59             # Subject: Nyaaan
60             # Sent date: Thu Apr 29 01:20:50 JST 2015
61             # MAIL FROM: shironeko@example.jp
62             # RCPT TO: kijitora@example.org
63             # From: Neko
64             # To: kijitora@example.org
65             # Size (in bytes): 1024
66             # Number of lines: 64
67 84         105 $v = $dscontents->[-1];
68              
69 84 100       272 if( $e =~ /\A[ ][ ]RCPT[ ]TO:[ ]([^ ]+[@][^ ]+)\z/ ) {
    100          
    100          
70             # RCPT TO: kijitora@example.org
71 6 50       25 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 6         18 $v->{'recipient'} = $1;
77 6         10 $recipients++;
78              
79             } elsif( $e =~ /\A[ ][ ]Sent[ ]date:[ ](.+)\z/ ) {
80             # Sent date: Thu Apr 29 01:20:50 JST 2015
81 6         18 $v->{'date'} = $1;
82              
83             } elsif( $e =~ /\A[ ][ ]Subject:[ ](.+)\z/ ) {
84             # Subject: Nyaaan
85 6         29 $subjecttxt = $1;
86              
87             } else {
88 66 100       102 next if $gotmessage == 1;
89              
90 24 100       51 if( $v->{'diagnosis'} ) {
91             # Get an error message text
92 18 100       35 if( $e eq 'Message details:' ) {
93             # Message details:
94             # Subject: nyaan
95             # ...
96 6         16 $gotmessage = 1;
97              
98             } else {
99             # Append error message text like the followng:
100             # Error message below:
101             # 550 - Requested action not taken: no such user here
102 12         38 $v->{'diagnosis'} .= ' '.$e;
103             }
104             } else {
105             # Error message below:
106             # 550 - Requested action not taken: no such user here
107 6 50       18 $v->{'diagnosis'} = $e if $e eq $startingof->{'error'}->[0];
108 6 50       32 $v->{'diagnosis'} .= ' '.$e unless $gotmessage;
109             }
110             }
111             }
112 6 50       31 return undef unless $recipients;
113              
114             # Set the value of $subjecttxt as a Subject if there is no original message
115             # in the bounce mail.
116 6 50       43 $emailsteak->[1] .= sprintf("Subject: %s\n", $subjecttxt) unless $emailsteak->[1] =~ /^Subject:/m;
117 6   33     56 $_->{'diagnosis'} = Sisimai::String->sweep($_->{'diagnosis'} || $diagnostic) for @$dscontents;
118 6         48 return { 'ds' => $dscontents, 'rfc822' => $emailsteak->[1] };
119             }
120              
121             1;
122             __END__