| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Sisimai::RFC1123; |
|
2
|
92
|
|
|
92
|
|
106701
|
use v5.26; |
|
|
92
|
|
|
|
|
325
|
|
|
3
|
92
|
|
|
92
|
|
532
|
use strict; |
|
|
92
|
|
|
|
|
205
|
|
|
|
92
|
|
|
|
|
3662
|
|
|
4
|
92
|
|
|
92
|
|
529
|
use warnings; |
|
|
92
|
|
|
|
|
176
|
|
|
|
92
|
|
|
|
|
4884
|
|
|
5
|
92
|
|
|
92
|
|
3296
|
use Sisimai::String; |
|
|
92
|
|
|
|
|
234
|
|
|
|
92
|
|
|
|
|
3095
|
|
|
6
|
92
|
|
|
92
|
|
1697
|
use Sisimai::RFC791; |
|
|
92
|
|
|
|
|
186
|
|
|
|
92
|
|
|
|
|
135511
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
state $Sandwiched = [ |
|
9
|
|
|
|
|
|
|
# (Postfix) postfix/src/smtp/smtp_proto.c: "host %s said: %s (in reply to %s)", |
|
10
|
|
|
|
|
|
|
# - : host re2.example.com[198.51.100.2] said: 550 ... |
|
11
|
|
|
|
|
|
|
# - : host r2.example.org[198.51.100.18] refused to talk to me: |
|
12
|
|
|
|
|
|
|
["host ", " said: "], |
|
13
|
|
|
|
|
|
|
["host ", " talk to me: "], |
|
14
|
|
|
|
|
|
|
["while talking to ", ":"], # (Sendmail) ... while talking to mx.bouncehammer.jp.: |
|
15
|
|
|
|
|
|
|
["host ", " ["], # (Exim) host mx.example.jp [192.0.2.20]: 550 5.7.0 |
|
16
|
|
|
|
|
|
|
[" by ", ". ["], # (Gmail) ...for the recipient domain example.jp by mx.example.jp. [192.0.2.1]. |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# (MailFoundry) |
|
19
|
|
|
|
|
|
|
# - Delivery failed for the following reason: Server mx22.example.org[192.0.2.222] failed with: 550... |
|
20
|
|
|
|
|
|
|
# - Delivery failed for the following reason: mail.example.org[192.0.2.222] responded with failure: 552.. |
|
21
|
|
|
|
|
|
|
["delivery failed for the following reason: ", " with"], |
|
22
|
|
|
|
|
|
|
["remote system: ", "("], # (MessagingServer) Remote system: dns;mx.example.net (mx. -- |
|
23
|
|
|
|
|
|
|
["smtp server <", ">"], # (X6) SMTP Server rejected recipient ... |
|
24
|
|
|
|
|
|
|
["-mta: ", ">"], # (MailMarshal) Reporting-MTA: |
|
25
|
|
|
|
|
|
|
[" : ", "["], # (SendGrid) cat:000000: : 192.0.2.1 : mx.example.jp:[192.0.2.2]... |
|
26
|
|
|
|
|
|
|
]; |
|
27
|
|
|
|
|
|
|
state $StartAfter = [ |
|
28
|
|
|
|
|
|
|
"generating server: ", # (Exchange2007) en-US/Generating server: mta4.example.org |
|
29
|
|
|
|
|
|
|
"serveur de g", # (Exchange2007) fr-FR/Serveur de gènèration |
|
30
|
|
|
|
|
|
|
"server di generazione", # (Exchange2007) it-CH |
|
31
|
|
|
|
|
|
|
"genererande server", # (Exchange2007) sv-SE |
|
32
|
|
|
|
|
|
|
]; |
|
33
|
|
|
|
|
|
|
state $ExistUntil = [ |
|
34
|
|
|
|
|
|
|
" did not like our ", # (Dragonfly) mail-inbound.libsisimai.net [192.0.2.25] did not like our DATA: ... |
|
35
|
|
|
|
|
|
|
]; |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub is_internethost { |
|
38
|
|
|
|
|
|
|
# Check that the argument is a valid Internet hostname or not |
|
39
|
|
|
|
|
|
|
# @param [String] argv0 String to be checked |
|
40
|
|
|
|
|
|
|
# @return [Boolean] 0: is not a valid hostname |
|
41
|
|
|
|
|
|
|
# 1: is a valid hostname |
|
42
|
|
|
|
|
|
|
# @since v5.2.0 |
|
43
|
23548
|
|
|
23548
|
1
|
329215
|
my $class = shift; |
|
44
|
23548
|
|
100
|
|
|
71760
|
my $argv0 = shift || return 0; |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Deal "localhost", "localhost6" as a valid hostname |
|
47
|
21577
|
100
|
100
|
|
|
76496
|
return 1 if $argv0 eq 'localhost' || $argv0 eq 'localhost6'; |
|
48
|
21309
|
100
|
66
|
|
|
84558
|
return 0 if length $argv0 > 255 || length $argv0 < 4; |
|
49
|
21303
|
100
|
|
|
|
51775
|
return 0 if index($argv0, ".") == -1; |
|
50
|
20989
|
100
|
|
|
|
49885
|
return 0 if index($argv0, "..") > -1; |
|
51
|
20687
|
100
|
|
|
|
37357
|
return 0 if index($argv0, "--") > -1; |
|
52
|
20676
|
50
|
|
|
|
40312
|
return 0 if index($argv0, ".") == 0; |
|
53
|
20676
|
50
|
|
|
|
38255
|
return 0 if index($argv0, "-") == 0; |
|
54
|
20676
|
100
|
|
|
|
53723
|
return 0 if substr($argv0, -1, 1) eq "-"; |
|
55
|
|
|
|
|
|
|
|
|
56
|
20675
|
|
|
|
|
107953
|
my @characters = split("", uc $argv0); |
|
57
|
20675
|
|
|
|
|
35945
|
for my $e ( @characters ) { |
|
58
|
|
|
|
|
|
|
# Check each characater is a number or an alphabet |
|
59
|
304263
|
|
|
|
|
345958
|
my $f = ord $e; |
|
60
|
304263
|
100
|
|
|
|
454132
|
return 0 if $f < 45; # 45 = '-' |
|
61
|
304045
|
100
|
|
|
|
462337
|
return 0 if $f == 47; # 47 = '/' |
|
62
|
303672
|
100
|
100
|
|
|
733637
|
return 0 if $f > 57 && $f < 65; # 57 = '9', 65 = 'A' |
|
63
|
302586
|
100
|
|
|
|
503504
|
return 0 if $f > 90; # 90 = 'Z' |
|
64
|
|
|
|
|
|
|
} |
|
65
|
|
|
|
|
|
|
|
|
66
|
18825
|
|
|
|
|
35820
|
my $p1 = rindex($argv0, "."); |
|
67
|
18825
|
50
|
|
|
|
37068
|
my $cv = substr($argv0, $p1 + 1,); return 0 if length $cv > 63; |
|
|
18825
|
|
|
|
|
39479
|
|
|
68
|
18825
|
|
|
|
|
56124
|
for my $e ( split("", $cv) ) { |
|
69
|
|
|
|
|
|
|
# The top level domain should not include a number |
|
70
|
46495
|
100
|
66
|
|
|
58971
|
my $f = ord $e; return 0 if $f > 47 && $f < 58; |
|
|
46495
|
|
|
|
|
152642
|
|
|
71
|
|
|
|
|
|
|
} |
|
72
|
17419
|
|
|
|
|
118797
|
return 1; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub is_domainliteral { |
|
76
|
|
|
|
|
|
|
# returns true if the domain part is [IPv4:...] or [IPv6:...]. |
|
77
|
|
|
|
|
|
|
# @param string email Email address. |
|
78
|
|
|
|
|
|
|
# @return bool 0: the domain part is not a domain literal. |
|
79
|
|
|
|
|
|
|
# 1: the domain part is a domain literal. |
|
80
|
10539
|
|
|
10539
|
1
|
20789
|
my $class = shift; |
|
81
|
10539
|
|
100
|
|
|
30171
|
my $email = shift || return 0; |
|
82
|
|
|
|
|
|
|
|
|
83
|
10538
|
|
|
|
|
18373
|
$email =~ s/\A[<]//g; $email =~ s/[>]\z//g; |
|
|
10538
|
|
|
|
|
16539
|
|
|
84
|
10538
|
100
|
|
|
|
21066
|
return 0 if length $email < 16; # e@[IPv4:0.0.0.0] is 16 characters |
|
85
|
10157
|
100
|
|
|
|
35605
|
return 0 if substr($email, -1, 1) ne ']'; |
|
86
|
|
|
|
|
|
|
|
|
87
|
13
|
100
|
|
|
|
24
|
my $lastb = rindex($email, '@[IPv'); return 0 if $lastb < 0; |
|
|
13
|
|
|
|
|
61
|
|
|
88
|
12
|
|
|
|
|
46
|
my $dpart = [split('@', $email)]->[-1]; |
|
89
|
|
|
|
|
|
|
|
|
90
|
12
|
100
|
|
|
|
56
|
if( index($email, '@[IPv4:') > 0 ) { |
|
|
|
100
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# neko@[IPv4:192.0.2.25] |
|
92
|
4
|
|
|
|
|
11
|
my $ipv4a = substr($email, $lastb + 7,); |
|
93
|
4
|
|
|
|
|
8
|
$ipv4a = substr($ipv4a, 0, length($ipv4a) - 1); |
|
94
|
4
|
|
|
|
|
60
|
return Sisimai::RFC791->is_ipv4address($ipv4a); |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
} elsif( index($email, '@[IPv6:') > 0 ) { |
|
97
|
|
|
|
|
|
|
# neko@[IPv6:2001:0DB8:0000:0000:0000:0000:0000:0001] |
|
98
|
|
|
|
|
|
|
# neko@[IPv6:2001:0DB8:0000:0000:0000:0000:0000:0001] |
|
99
|
|
|
|
|
|
|
# IPv6-address-literal = "IPv6:" IPv6-addr |
|
100
|
|
|
|
|
|
|
# IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp |
|
101
|
|
|
|
|
|
|
# IPv6-hex = 1*4HEXDIG |
|
102
|
|
|
|
|
|
|
# IPv6-full = IPv6-hex 7(":" IPv6-hex) |
|
103
|
|
|
|
|
|
|
# IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::" |
|
104
|
|
|
|
|
|
|
# [IPv6-hex *5(":" IPv6-hex)] |
|
105
|
|
|
|
|
|
|
# ; The "::" represents at least 2 16-bit groups of |
|
106
|
|
|
|
|
|
|
# ; zeros. No more than 6 groups in addition to the |
|
107
|
|
|
|
|
|
|
# ; "::" may be present. |
|
108
|
|
|
|
|
|
|
# IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal |
|
109
|
|
|
|
|
|
|
# IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::" |
|
110
|
|
|
|
|
|
|
# [IPv6-hex *3(":" IPv6-hex) ":"] |
|
111
|
|
|
|
|
|
|
# IPv4-address-literal |
|
112
|
|
|
|
|
|
|
# ; The "::" represents at least 2 16-bit groups of |
|
113
|
|
|
|
|
|
|
# ; zeros. No more than 4 groups in addition to the |
|
114
|
|
|
|
|
|
|
# ; "::" and IPv4-address-literal may be present. |
|
115
|
7
|
100
|
66
|
|
|
50
|
return 1 if length $dpart > 2 && rindex($dpart, ':') > 7; |
|
116
|
|
|
|
|
|
|
} |
|
117
|
2
|
|
|
|
|
8
|
return 0 |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub find { |
|
121
|
|
|
|
|
|
|
# find() returns a valid internet hostname found from the argument |
|
122
|
|
|
|
|
|
|
# @param string argv1 String including hostnames |
|
123
|
|
|
|
|
|
|
# @return string A valid internet hostname found in the argument |
|
124
|
|
|
|
|
|
|
# @since v5.2.0 |
|
125
|
1824
|
|
|
1824
|
0
|
18714
|
my $class = shift; |
|
126
|
1824
|
|
100
|
|
|
8740
|
my $argv1 = shift || return ""; |
|
127
|
|
|
|
|
|
|
|
|
128
|
1814
|
|
|
|
|
6679
|
my $sourcetext = lc $argv1; |
|
129
|
1814
|
|
|
|
|
3699
|
my $sourcelist = []; |
|
130
|
1814
|
|
|
|
|
4530
|
my $foundtoken = []; |
|
131
|
1814
|
|
|
|
|
3192
|
my $thelongest = 0; |
|
132
|
1814
|
|
|
|
|
3234
|
my $hostnameis = ""; |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# Replace some string for splitting by " " |
|
135
|
|
|
|
|
|
|
# - mx.example.net[192.0.2.1] => mx.example.net [192.0.2.1] |
|
136
|
|
|
|
|
|
|
# - mx.example.jp:[192.0.2.1] => mx.example.jp :[192.0.2.1] |
|
137
|
1814
|
|
|
|
|
17669
|
s/\[/ [/g, s/\(/ (/g, s/
|
|
138
|
1814
|
|
|
|
|
11201
|
s/\]/] /g, s/\)/) /g, s/> /g for $sourcetext; # Suffix a space character behind each bracket |
|
139
|
1814
|
|
|
|
|
11215
|
s/:/: /g, s/;/; /g for $sourcetext; # Suffix a space character behind : and ; |
|
140
|
1814
|
|
|
|
|
9981
|
$sourcetext = Sisimai::String->sweep($sourcetext); |
|
141
|
|
|
|
|
|
|
|
|
142
|
1814
|
|
|
|
|
3426
|
MAKELIST: while(1) { |
|
143
|
1814
|
|
|
|
|
4338
|
for my $e ( @$Sandwiched ) { |
|
144
|
|
|
|
|
|
|
# Check a hostname exists between the $e->[0] and $e->[1] at array "Sandwiched" |
|
145
|
|
|
|
|
|
|
# Each array in Sandwiched have 2 elements |
|
146
|
17110
|
100
|
|
|
|
34210
|
next unless Sisimai::String->aligned(\$sourcetext, $e); |
|
147
|
|
|
|
|
|
|
|
|
148
|
199
|
|
|
|
|
667
|
my $p1 = index($sourcetext, $e->[0]); |
|
149
|
199
|
|
|
|
|
600
|
my $p2 = index($sourcetext, $e->[1]); |
|
150
|
199
|
|
|
|
|
455
|
my $cw = length $e->[0]; |
|
151
|
199
|
100
|
|
|
|
833
|
next if $p1 + $cw >= $p2; |
|
152
|
|
|
|
|
|
|
|
|
153
|
166
|
|
|
|
|
1622
|
$sourcelist = [split(" ", substr($sourcetext, $p1 + $cw, $p2 - $cw - $p1))]; |
|
154
|
166
|
|
|
|
|
776
|
last MAKELIST; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Check other patterns which are not sandwiched |
|
158
|
1648
|
|
|
|
|
3814
|
for my $e ( @$StartAfter ) { |
|
159
|
|
|
|
|
|
|
# $StartAfter have some strings, not an array. |
|
160
|
6310
|
100
|
|
|
|
10486
|
my $p1 = index($sourcetext, $e); next if $p1 < 0; |
|
|
6310
|
|
|
|
|
14095
|
|
|
161
|
101
|
|
|
|
|
231
|
my $cw = length $e; |
|
162
|
101
|
|
|
|
|
530
|
$sourcelist = [split(" ", substr($sourcetext, $p1 + $cw,))]; |
|
163
|
101
|
|
|
|
|
350
|
last MAKELIST; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
1547
|
|
|
|
|
4006
|
for my $e ( @$ExistUntil ) { |
|
167
|
|
|
|
|
|
|
# ExistUntil have some strings, not an array. |
|
168
|
1547
|
100
|
|
|
|
3382
|
my $p1 = index($sourcetext, $e); next if $p1 < 0; |
|
|
1547
|
|
|
|
|
8348
|
|
|
169
|
2
|
|
|
|
|
7
|
$sourcelist = [split(" ", substr($sourcetext, 0, $p1))]; |
|
170
|
2
|
|
|
|
|
4
|
last MAKELIST; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
1545
|
50
|
|
|
|
33171
|
$sourcelist = [split(" ", $sourcetext)] if scalar @$sourcelist == 0; |
|
174
|
1545
|
|
|
|
|
7466
|
last MAKELIST; |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
|
|
177
|
1814
|
|
|
|
|
3952
|
for my $e ( @$sourcelist ) { |
|
178
|
|
|
|
|
|
|
# Pick some strings which is 4 or more length, is including "." character |
|
179
|
49607
|
100
|
|
|
|
96649
|
substr($e, -1, 1, "") if substr($e, -1, 1) eq "."; # Remove "." at the end of the string |
|
180
|
49607
|
|
|
|
|
73044
|
$e =~ y/[]()<>:;//d; # Remove brackets, colon, and semi-colon |
|
181
|
|
|
|
|
|
|
|
|
182
|
49607
|
100
|
100
|
|
|
138619
|
next if length $e < 4 || index($e, ".") < 0 || __PACKAGE__->is_internethost($e) == 0; |
|
|
|
|
100
|
|
|
|
|
|
183
|
1140
|
|
|
|
|
3939
|
push @$foundtoken, $e; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
1814
|
100
|
|
|
|
12111
|
return "" if scalar @$foundtoken == 0; |
|
186
|
585
|
100
|
|
|
|
4439
|
return $foundtoken->[0] if scalar @$foundtoken == 1; |
|
187
|
|
|
|
|
|
|
|
|
188
|
161
|
|
|
|
|
607
|
for my $e ( @$foundtoken ) { |
|
189
|
|
|
|
|
|
|
# Returns the longest hostname |
|
190
|
716
|
100
|
|
|
|
1016
|
my $cw = length $e; next if $thelongest >= $cw; |
|
|
716
|
|
|
|
|
1495
|
|
|
191
|
184
|
|
|
|
|
398
|
$hostnameis = $e; |
|
192
|
184
|
|
|
|
|
342
|
$thelongest = $cw; |
|
193
|
|
|
|
|
|
|
} |
|
194
|
161
|
|
|
|
|
1869
|
return $hostnameis; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
1; |
|
198
|
|
|
|
|
|
|
__END__ |