File Coverage

lib/Sisimai/Lhost/FML.pm
Criterion Covered Total %
statement 43 45 95.5
branch 12 16 75.0
condition 6 7 85.7
subroutine 6 6 100.0
pod 2 2 100.0
total 69 76 90.7


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::FML;
2 40     40   3281 use parent 'Sisimai::Lhost';
  40         58  
  40         200  
3 40     40   2571 use v5.26;
  40         111  
4 40     40   176 use strict;
  40         88  
  40         840  
5 40     40   142 use warnings;
  40         66  
  40         18033  
6              
7 1     1 1 2 sub description { 'fml mailing list server/manager: https://www.fml.org/' };
8             sub inquire {
9             # Detect an error from fml mailing list server/manager
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.22.3
15 901     901 1 3022 my $class = shift;
16 901   100     1754 my $mhead = shift // return undef;
17 900   100     1972 my $mbody = shift // return undef;
18              
19 899 100       2162 return undef unless defined $mhead->{'x-mlserver'};
20 10 50       36 return undef unless index($mhead->{'from'}, '-admin@') > 0;
21 10 50       29 return undef unless index($mhead->{'message-id'}, '.FML') > 1;
22              
23 10         14 state $boundaries = ['Original mail as follows:'];
24 10         26 state $errortitle = {
25             'rejected' => [
26             ' are not member',
27             'NOT MEMBER article from ',
28             'reject mail ',
29             'Spam mail from a spammer is rejected',
30             ],
31             'systemerror' => [
32             'fml system error message',
33             'Loop Alert: ',
34             'Loop Back Warning: ',
35             'WARNING: UNIX FROM Loop',
36             ],
37             'securityerror' => ['Security Alert'],
38             };
39              
40 10         44 my $dscontents = [__PACKAGE__->DELIVERYSTATUS]; my $v = undef;
  10         12  
41 10         41 my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries);
42 10         12 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
43              
44 10         44 for my $e ( split("\n", $emailparts->[0]) ) {
45             # Read error messages and delivery status lines from the head of the email to the previous
46             # line of the beginning of the original message.
47 65 100       73 next unless length $e;
48              
49             # Duplicated Message-ID in <2ndml@example.com>. Original mail as follows:
50 40         44 $v = $dscontents->[-1];
51              
52 40         40 my $p1 = index($e, '<');
53 40         36 my $p2 = rindex($e, '>');
54 40 100 66     66 if( $p1 > 0 && $p2 > 0 ) {
55             # You are not a member of this mailing list .
56 10 50       21 if( $v->{'recipient'} ) {
57             # There are multiple recipient addresses in the message body.
58 0         0 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
59 0         0 $v = $dscontents->[-1];
60             }
61 10         30 $v->{'recipient'} = substr($e, $p1 + 1, $p2 - $p1 - 1);
62 10         13 $v->{'diagnosis'} = $e;
63 10         13 $recipients++;
64              
65             } else {
66             # If you know the general guide of this list, please send mail with the mail body
67 30         39 $v->{'diagnosis'} .= $e;
68             }
69             }
70 10 50       29 return undef unless $recipients;
71              
72 10         14 for my $e ( @$dscontents ) {
73             # Error messages in the message body did not matched
74 10         86 for my $f ( keys %$errortitle ) {
75             # Try to match with the Subject string
76 19 100       37 next unless grep { index($mhead->{'subject'}, $_) > -1 } $errortitle->{ $f }->@*;
  64         103  
77 10         11 $e->{'reason'} = $f;
78 10         16 last;
79             }
80             }
81 10         38 return {"ds" => $dscontents, "rfc822" => $emailparts->[1]};
82             }
83              
84             1;
85             __END__