| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Sisimai::RFC1894; |
|
2
|
88
|
|
|
88
|
|
128007
|
use v5.26; |
|
|
88
|
|
|
|
|
303
|
|
|
3
|
88
|
|
|
88
|
|
471
|
use strict; |
|
|
88
|
|
|
|
|
141
|
|
|
|
88
|
|
|
|
|
2290
|
|
|
4
|
88
|
|
|
88
|
|
646
|
use warnings; |
|
|
88
|
|
|
|
|
382
|
|
|
|
88
|
|
|
|
|
4678
|
|
|
5
|
88
|
|
|
88
|
|
43461
|
use Sisimai::String; |
|
|
88
|
|
|
|
|
409
|
|
|
|
88
|
|
|
|
|
6686
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
88
|
|
|
|
|
11169
|
use constant FIELDINDEX => [qw| |
|
8
|
|
|
|
|
|
|
Action Arrival-Date Diagnostic-Code Final-Recipient Last-Attempt-Date Original-Recipient |
|
9
|
|
|
|
|
|
|
Received-From-MTA Remote-MTA Reporting-MTA Status X-Actual-Recipient X-Original-Message-ID |
|
10
|
88
|
|
|
88
|
|
870
|
|]; |
|
|
88
|
|
|
|
|
180
|
|
|
11
|
88
|
|
|
|
|
103341
|
use constant FIELDTABLE => { |
|
12
|
|
|
|
|
|
|
# Return pairs that a field name and key name defined in Sisimai::Lhost class |
|
13
|
|
|
|
|
|
|
'action' => 'action', |
|
14
|
|
|
|
|
|
|
'arrival-date' => 'date', |
|
15
|
|
|
|
|
|
|
'diagnostic-code' => 'diagnosis', |
|
16
|
|
|
|
|
|
|
'final-recipient' => 'recipient', |
|
17
|
|
|
|
|
|
|
'last-attempt-date' => 'date', |
|
18
|
|
|
|
|
|
|
'original-recipient'=> 'alias', |
|
19
|
|
|
|
|
|
|
'received-from-mta' => 'lhost', |
|
20
|
|
|
|
|
|
|
'remote-mta' => 'rhost', |
|
21
|
|
|
|
|
|
|
'reporting-mta' => 'lhost', |
|
22
|
|
|
|
|
|
|
'status' => 'status', |
|
23
|
|
|
|
|
|
|
'x-actual-recipient'=> 'alias', |
|
24
|
88
|
|
|
88
|
|
542
|
}; |
|
|
88
|
|
|
|
|
166
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub match { |
|
27
|
|
|
|
|
|
|
# Check the argument matches with a field defined in RFC3464 |
|
28
|
|
|
|
|
|
|
# @param [String] argv0 A line including field and value defined in RFC3464 |
|
29
|
|
|
|
|
|
|
# @return [Integer] 0: did not matched, 1,2: matched |
|
30
|
|
|
|
|
|
|
# @since v4.25.0 |
|
31
|
27691
|
|
|
27691
|
1
|
67235
|
my $class = shift; |
|
32
|
27691
|
|
50
|
|
|
60151
|
my $argv0 = shift || return 0; |
|
33
|
27691
|
|
50
|
|
|
63001
|
my $label = __PACKAGE__->label($argv0) || return 0; |
|
34
|
27691
|
|
|
|
|
38443
|
my $match = 0; |
|
35
|
|
|
|
|
|
|
|
|
36
|
27691
|
|
|
|
|
37009
|
state $fieldnames = [ |
|
37
|
|
|
|
|
|
|
# https://tools.ietf.org/html/rfc3464#section-2.2 |
|
38
|
|
|
|
|
|
|
# Some fields of a DSN apply to all of the delivery attempts described by that DSN. At |
|
39
|
|
|
|
|
|
|
# most, these fields may appear once in any DSN. These fields are used to correlate the |
|
40
|
|
|
|
|
|
|
# DSN with the original message transaction and to provide additional information which |
|
41
|
|
|
|
|
|
|
# may be useful to gateways. |
|
42
|
|
|
|
|
|
|
# |
|
43
|
|
|
|
|
|
|
# The following fields (not defined in RFC 3464) are used in Sisimai |
|
44
|
|
|
|
|
|
|
# - X-Original-Message-ID: <....> (GSuite) |
|
45
|
|
|
|
|
|
|
# |
|
46
|
|
|
|
|
|
|
# The following fields are not used in Sisimai: |
|
47
|
|
|
|
|
|
|
# - Original-Envelope-Id |
|
48
|
|
|
|
|
|
|
# - DSN-Gateway |
|
49
|
|
|
|
|
|
|
{ |
|
50
|
|
|
|
|
|
|
'arrival-date' => ':', |
|
51
|
|
|
|
|
|
|
'received-from-mta' => ';', |
|
52
|
|
|
|
|
|
|
'reporting-mta' => ';', |
|
53
|
|
|
|
|
|
|
'x-original-message-id' => '@', |
|
54
|
|
|
|
|
|
|
}, |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# https://tools.ietf.org/html/rfc3464#section-2.3 |
|
57
|
|
|
|
|
|
|
# A DSN contains information about attempts to deliver a message to one or more recipi- |
|
58
|
|
|
|
|
|
|
# ents. The delivery information for any particular recipient is contained in a group of |
|
59
|
|
|
|
|
|
|
# contiguous per-recipient fields. Each group of per-recipient fields is preceded by a |
|
60
|
|
|
|
|
|
|
# blank line. |
|
61
|
|
|
|
|
|
|
# |
|
62
|
|
|
|
|
|
|
# The following fields (not defined in RFC 3464) are used in Sisimai |
|
63
|
|
|
|
|
|
|
# - X-Actual-Recipient: RFC822; .... |
|
64
|
|
|
|
|
|
|
# |
|
65
|
|
|
|
|
|
|
# The following fields are not used in Sisimai: |
|
66
|
|
|
|
|
|
|
# - Will-Retry-Until |
|
67
|
|
|
|
|
|
|
# - Final-Log-ID |
|
68
|
|
|
|
|
|
|
{ |
|
69
|
|
|
|
|
|
|
'action' => 'e', |
|
70
|
|
|
|
|
|
|
'diagnostic-code' => ';', |
|
71
|
|
|
|
|
|
|
'final-recipient' => ';', |
|
72
|
|
|
|
|
|
|
'last-attempt-date' => ':', |
|
73
|
|
|
|
|
|
|
'original-recipient' => ';', |
|
74
|
|
|
|
|
|
|
'remote-mta' => ';', |
|
75
|
|
|
|
|
|
|
'status' => '.', |
|
76
|
|
|
|
|
|
|
'x-actual-recipient' => ';', |
|
77
|
|
|
|
|
|
|
}, |
|
78
|
|
|
|
|
|
|
]; |
|
79
|
|
|
|
|
|
|
|
|
80
|
27691
|
|
|
|
|
92313
|
FIELDS0: for my $e ( keys $fieldnames->[0]->%* ) { |
|
81
|
|
|
|
|
|
|
# Per-Message fields |
|
82
|
104890
|
100
|
|
|
|
173282
|
next unless $label eq $e; |
|
83
|
4363
|
50
|
|
|
|
14954
|
next unless index($argv0, $fieldnames->[0]->{ $label }) > 1; |
|
84
|
4363
|
|
|
|
|
6010
|
$match = 1; last; |
|
|
4363
|
|
|
|
|
5889
|
|
|
85
|
|
|
|
|
|
|
} |
|
86
|
27691
|
100
|
|
|
|
64290
|
return $match if $match > 0; |
|
87
|
|
|
|
|
|
|
|
|
88
|
23328
|
|
|
|
|
64122
|
FIELDS1: for my $e ( keys $fieldnames->[1]->%* ) { |
|
89
|
|
|
|
|
|
|
# Per-Recipient fields |
|
90
|
158044
|
100
|
|
|
|
260712
|
next unless $label eq $e; |
|
91
|
10360
|
100
|
|
|
|
29984
|
next unless index($argv0, $fieldnames->[1]->{ $label }) > 1; |
|
92
|
10298
|
|
|
|
|
13213
|
$match = 2; last; |
|
|
10298
|
|
|
|
|
13234
|
|
|
93
|
|
|
|
|
|
|
} |
|
94
|
23328
|
|
|
|
|
77653
|
return $match; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub label { |
|
98
|
|
|
|
|
|
|
# Returns a field name as a label from the given string |
|
99
|
|
|
|
|
|
|
# @param [String] argv0 A line including field and value defined in RFC3464 |
|
100
|
|
|
|
|
|
|
# @return [String] Field name as a label |
|
101
|
|
|
|
|
|
|
# @since v4.25.15 |
|
102
|
44037
|
|
|
44037
|
1
|
83249
|
my $class = shift; |
|
103
|
44037
|
|
50
|
|
|
81138
|
my $argv0 = shift || return ""; |
|
104
|
44037
|
|
50
|
|
|
204367
|
return lc((split(':', $argv0, 2))[0]) || ""; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub field { |
|
108
|
|
|
|
|
|
|
# Check the argument is including field defined in RFC3464 and return values |
|
109
|
|
|
|
|
|
|
# @param [String] argv0 A line including field and value defined in RFC3464 |
|
110
|
|
|
|
|
|
|
# @return [Array] ['field-name', 'value-type', 'Value', 'field-group'] |
|
111
|
|
|
|
|
|
|
# @since v4.25.0 |
|
112
|
16332
|
|
|
16332
|
1
|
327660
|
my $class = shift; |
|
113
|
16332
|
|
100
|
|
|
30899
|
my $argv0 = shift || return undef; |
|
114
|
|
|
|
|
|
|
|
|
115
|
16331
|
|
|
|
|
23513
|
state $subtypeset = {"addr" => "RFC822", "cdoe" => "SMTP", "host" => "DNS"}; |
|
116
|
16331
|
|
|
|
|
19278
|
state $actionlist = ["failed", "delayed", "delivered", "relayed", "expanded"]; |
|
117
|
16331
|
|
|
|
|
20877
|
state $correction = {'deliverable' => 'delivered', 'expired' => 'failed', 'failure' => 'failed'}; |
|
118
|
16331
|
|
|
|
|
20709
|
state $fieldgroup = { |
|
119
|
|
|
|
|
|
|
'original-recipient' => 'addr', |
|
120
|
|
|
|
|
|
|
'final-recipient' => 'addr', |
|
121
|
|
|
|
|
|
|
'x-actual-recipient' => 'addr', |
|
122
|
|
|
|
|
|
|
'diagnostic-code' => 'code', |
|
123
|
|
|
|
|
|
|
'arrival-date' => 'date', |
|
124
|
|
|
|
|
|
|
'last-attempt-date' => 'date', |
|
125
|
|
|
|
|
|
|
'received-from-mta' => 'host', |
|
126
|
|
|
|
|
|
|
'remote-mta' => 'host', |
|
127
|
|
|
|
|
|
|
'reporting-mta' => 'host', |
|
128
|
|
|
|
|
|
|
'action' => 'list', |
|
129
|
|
|
|
|
|
|
'status' => 'stat', |
|
130
|
|
|
|
|
|
|
'x-original-message-id' => 'text', |
|
131
|
|
|
|
|
|
|
}; |
|
132
|
16331
|
|
|
|
|
22467
|
state $captureson = { |
|
133
|
|
|
|
|
|
|
"addr" => ["Final-Recipient", "Original-Recipient", "X-Actual-Recipient"], |
|
134
|
|
|
|
|
|
|
"code" => ["Diagnostic-Code"], |
|
135
|
|
|
|
|
|
|
"date" => ["Arrival-Date", "Last-Attempt-Date"], |
|
136
|
|
|
|
|
|
|
"host" => ["Received-From-MTA", "Remote-MTA", "Reporting-MTA"], |
|
137
|
|
|
|
|
|
|
"list" => ["Action"], |
|
138
|
|
|
|
|
|
|
"stat" => ["Status"], |
|
139
|
|
|
|
|
|
|
#"text" => ["X-Original-Message-ID", "Final-Log-ID", "Original-Envelope-ID"], |
|
140
|
|
|
|
|
|
|
}; |
|
141
|
|
|
|
|
|
|
|
|
142
|
16331
|
|
|
|
|
50505
|
my $parts = [split(":", $argv0, 2)]; # ["Final-Recipient", " rfc822; "] |
|
143
|
16331
|
|
50
|
|
|
41176
|
my $label = __PACKAGE__->label($argv0) || return undef; |
|
144
|
16331
|
|
100
|
|
|
44648
|
my $group = $fieldgroup->{ $label } || return undef; |
|
145
|
16326
|
100
|
|
|
|
37312
|
return undef unless exists $captureson->{ $group }; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# Try to match with each pattern of Per-Message field, Per-Recipient field |
|
148
|
|
|
|
|
|
|
# - 0: Field-Name |
|
149
|
|
|
|
|
|
|
# - 1: Sub Type: RFC822, DNS, X-Unix, and so on) |
|
150
|
|
|
|
|
|
|
# - 2: Value |
|
151
|
|
|
|
|
|
|
# - 3: Field Group(addr, code, date, host, stat, text) |
|
152
|
|
|
|
|
|
|
# - 4: Comment |
|
153
|
16161
|
|
|
|
|
40142
|
my $table = [$label, "", "", $group, ""]; $parts->[1] = Sisimai::String->sweep($parts->[1]); |
|
|
16161
|
|
|
|
|
64290
|
|
|
154
|
|
|
|
|
|
|
|
|
155
|
16161
|
100
|
100
|
|
|
91425
|
if( $group eq 'addr' || $group eq 'code' || $group eq 'host' ) { |
|
|
|
100
|
100
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# - Final-Recipient: RFC822; kijitora@nyaan.jp |
|
157
|
|
|
|
|
|
|
# - Diagnostic-Code: SMTP; 550 5.1.1 ... User Unknown |
|
158
|
|
|
|
|
|
|
# - Remote-MTA: DNS; mx.example.jp |
|
159
|
8160
|
50
|
|
|
|
17463
|
if( index($parts->[1], ";" ) > 0 ) { |
|
160
|
|
|
|
|
|
|
# There is a valid sub type (including ";") |
|
161
|
8160
|
|
|
|
|
25438
|
my $v = [split(";", $parts->[1], 2)]; |
|
162
|
8160
|
50
|
|
|
|
28439
|
$table->[1] = uc Sisimai::String->sweep($v->[0]) if scalar @$v > 0; |
|
163
|
8160
|
50
|
|
|
|
27388
|
$table->[2] = Sisimai::String->sweep($v->[1]) if scalar @$v > 1; |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
} else { |
|
166
|
|
|
|
|
|
|
# There is no sub type like "Diagnostic-Code: 550 5.1.1 ..." |
|
167
|
0
|
|
|
|
|
0
|
$table->[2] = Sisimai::String->sweep($parts->[1]); |
|
168
|
0
|
|
0
|
|
|
0
|
$table->[1] = $subtypeset->{ $group } || ""; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
8160
|
100
|
|
|
|
21562
|
$table->[2] = lc $table->[2] if $group eq "host"; |
|
171
|
8160
|
50
|
|
|
|
39487
|
$table->[2] = '' if $table->[2] =~ /\A\s+\z/; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
} elsif( $group eq "list" ) { |
|
174
|
|
|
|
|
|
|
# Action: failed |
|
175
|
|
|
|
|
|
|
# Check that the value is an available value defined in "actionlist" or not. |
|
176
|
|
|
|
|
|
|
# When the value is invalid, convert to an available value defined in "correction" |
|
177
|
3604
|
|
|
|
|
8937
|
my $v = lc $parts->[1]; |
|
178
|
3604
|
100
|
|
|
|
9667
|
$table->[2] = $v if grep { $v eq $_ } @$actionlist; |
|
|
18020
|
|
|
|
|
37698
|
|
|
179
|
3604
|
|
100
|
|
|
17851
|
$table->[2] ||= $correction->{ $v }; |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
} else { |
|
182
|
|
|
|
|
|
|
# Other groups such as Status:, Arrival-Date:, or X-Original-Message-ID:. |
|
183
|
|
|
|
|
|
|
# There is no ";" character in the field. |
|
184
|
|
|
|
|
|
|
# - Status: 5.2.2 |
|
185
|
|
|
|
|
|
|
# - Arrival-Date: Mon, 21 May 2018 16:09:59 +0900 |
|
186
|
4397
|
100
|
|
|
|
11796
|
$table->[2] = $group eq "date" ? $parts->[1] : lc $parts->[1]; |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
16161
|
100
|
|
|
|
64083
|
if( Sisimai::String->aligned(\$table->[2], [" (", ")"]) ) { |
|
190
|
|
|
|
|
|
|
# Extract text enclosed in parentheses as comments |
|
191
|
|
|
|
|
|
|
# Reporting-MTA: dns; mr21p30im-asmtp004.me.example.com (tcp-daemon) |
|
192
|
1739
|
|
|
|
|
3938
|
my $p1 = index($table->[2], " ("); |
|
193
|
1739
|
|
|
|
|
3458
|
my $p2 = index($table->[2], ")"); |
|
194
|
1739
|
|
|
|
|
5620
|
$table->[4] = substr($table->[2], $p1 + 2, $p2 - $p1 - 2); |
|
195
|
1739
|
|
|
|
|
8082
|
$table->[2] = substr($table->[2], 0, $p1); |
|
196
|
|
|
|
|
|
|
} |
|
197
|
16161
|
|
|
|
|
68009
|
return $table; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
1; |
|
201
|
|
|
|
|
|
|
__END__ |