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   6003 use parent 'Sisimai::Lhost';
  18         40  
  18         164  
3 18     18   1103 use feature ':5.10';
  18         50  
  18         1245  
4 18     18   104 use strict;
  18         35  
  18         384  
5 18     18   99 use warnings;
  18         38  
  18         14177  
6              
7 2     2 1 1206 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 792 my $class = shift;
16 208   100     685 my $mhead = shift // return undef;
17 207   50     575 my $mbody = shift // return undef;
18 207         340 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     919 $match ||= 1 if $mhead->{'subject'} eq '[BOUNCE]';
24 207 100 50     1320 $match ||= 1 if defined $mhead->{'message-id'} && rindex($mhead->{'message-id'}, '.JavaMail.') > -1;
      100        
25 207 50 0     465 $match ||= 1 if grep { rindex($_, 'JAMES SMTP Server') > -1 } @{ $mhead->{'received'} };
  386         1030  
  207         592  
26 207 100       694 return undef unless $match;
27              
28 6         33 state $indicators = __PACKAGE__->INDICATORS;
29 6         22 state $rebackbone = qr|^Content-Type:[ ]message/rfc822|m;
30 6         18 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         31 my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
39 6         37 my $emailsteak = Sisimai::RFC5322->fillet($mbody, $rebackbone);
40 6         14 my $readcursor = 0; # (Integer) Points the current cursor position
41 6         15 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
42 6         13 my $diagnostic = ''; # (String) Alternative diagnostic message
43 6         9 my $subjecttxt = undef; # (String) Alternative Subject text
44 6         102 my $gotmessage = 0; # (Integer) Flag for error message
45 6         71 my $v = undef;
46              
47 6         59 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       160 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       158 next unless $readcursor & $indicators->{'deliverystatus'};
56 108 100       154 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         89 $v = $dscontents->[-1];
68              
69 84 100       233 if( $e =~ /\A[ ][ ]RCPT[ ]TO:[ ]([^ ]+[@][^ ]+)\z/ ) {
    100          
    100          
70             # RCPT TO: kijitora@example.org
71 6 50       21 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         21 $v->{'recipient'} = $1;
77 6         11 $recipients++;
78              
79             } elsif( $e =~ /\A[ ][ ]Sent[ ]date:[ ](.+)\z/ ) {
80             # Sent date: Thu Apr 29 01:20:50 JST 2015
81 6         20 $v->{'date'} = $1;
82              
83             } elsif( $e =~ /\A[ ][ ]Subject:[ ](.+)\z/ ) {
84             # Subject: Nyaaan
85 6         21 $subjecttxt = $1;
86              
87             } else {
88 66 100       109 next if $gotmessage == 1;
89              
90 24 100       40 if( $v->{'diagnosis'} ) {
91             # Get an error message text
92 18 100       32 if( $e eq 'Message details:' ) {
93             # Message details:
94             # Subject: nyaan
95             # ...
96 6         14 $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         32 $v->{'diagnosis'} .= ' '.$e;
103             }
104             } else {
105             # Error message below:
106             # 550 - Requested action not taken: no such user here
107 6 50       19 $v->{'diagnosis'} = $e if $e eq $startingof->{'error'}->[0];
108 6 50       30 $v->{'diagnosis'} .= ' '.$e unless $gotmessage;
109             }
110             }
111             }
112 6 50       24 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       40 $emailsteak->[1] .= sprintf("Subject: %s\n", $subjecttxt) unless $emailsteak->[1] =~ /^Subject:/m;
117 6   33     60 $_->{'diagnosis'} = Sisimai::String->sweep($_->{'diagnosis'} || $diagnostic) for @$dscontents;
118 6         36 return { 'ds' => $dscontents, 'rfc822' => $emailsteak->[1] };
119             }
120              
121             1;
122             __END__