line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Sisimai::Message; |
2
|
82
|
|
|
82
|
|
174233
|
use feature ':5.10'; |
|
82
|
|
|
|
|
236
|
|
|
82
|
|
|
|
|
6128
|
|
3
|
82
|
|
|
82
|
|
466
|
use strict; |
|
82
|
|
|
|
|
142
|
|
|
82
|
|
|
|
|
1675
|
|
4
|
82
|
|
|
82
|
|
380
|
use warnings; |
|
82
|
|
|
|
|
132
|
|
|
82
|
|
|
|
|
1942
|
|
5
|
82
|
|
|
82
|
|
24822
|
use Sisimai::RFC5322; |
|
82
|
|
|
|
|
173
|
|
|
82
|
|
|
|
|
2543
|
|
6
|
82
|
|
|
82
|
|
27949
|
use Sisimai::Address; |
|
82
|
|
|
|
|
197
|
|
|
82
|
|
|
|
|
2503
|
|
7
|
82
|
|
|
82
|
|
22146
|
use Sisimai::String; |
|
82
|
|
|
|
|
243
|
|
|
82
|
|
|
|
|
3136
|
|
8
|
82
|
|
|
82
|
|
34364
|
use Sisimai::Order; |
|
82
|
|
|
|
|
254
|
|
|
82
|
|
|
|
|
2913
|
|
9
|
82
|
|
|
82
|
|
531
|
use Sisimai::Lhost; |
|
82
|
|
|
|
|
208
|
|
|
82
|
|
|
|
|
1574
|
|
10
|
82
|
|
|
82
|
|
36600
|
use Sisimai::MIME; |
|
82
|
|
|
|
|
252
|
|
|
82
|
|
|
|
|
4230
|
|
11
|
|
|
|
|
|
|
use Class::Accessor::Lite ( |
12
|
82
|
|
|
|
|
1054
|
'new' => 0, |
13
|
|
|
|
|
|
|
'rw' => [ |
14
|
|
|
|
|
|
|
'from', # [String] UNIX From line |
15
|
|
|
|
|
|
|
'header', # [Hash] Header part of an email |
16
|
|
|
|
|
|
|
'ds', # [Array] Parsed data by Sisimai::Lhost |
17
|
|
|
|
|
|
|
'rfc822', # [Hash] Header part of the original message |
18
|
|
|
|
|
|
|
'catch' # [Any] The results returned by hook method |
19
|
|
|
|
|
|
|
] |
20
|
82
|
|
|
82
|
|
655
|
); |
|
82
|
|
|
|
|
221
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
my $ToBeLoaded = []; |
23
|
|
|
|
|
|
|
my $TryOnFirst = []; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub new { |
26
|
|
|
|
|
|
|
# Constructor of Sisimai::Message |
27
|
|
|
|
|
|
|
# @param [Hash] argvs Email text data |
28
|
|
|
|
|
|
|
# @options argvs [String] data Entire email message |
29
|
|
|
|
|
|
|
# @options argvs [Array] load User defined MTA module list |
30
|
|
|
|
|
|
|
# @options argvs [Array] order The order of MTA modules |
31
|
|
|
|
|
|
|
# @options argvs [Code] hook Reference to callback method |
32
|
|
|
|
|
|
|
# @return [Sisimai::Message] Structured email data or Undef if each |
33
|
|
|
|
|
|
|
# value of the arguments are missing |
34
|
2822
|
|
|
2822
|
1
|
24480
|
my $class = shift; |
35
|
2822
|
|
|
|
|
6671
|
my $argvs = { @_ }; |
36
|
2822
|
|
|
|
|
4440
|
my $param = {}; |
37
|
2822
|
|
50
|
|
|
6403
|
my $email = $argvs->{'data'} || return undef; |
38
|
2822
|
|
|
|
|
11941
|
my $thing = { 'from' => '', 'header' => {}, 'rfc822' => '', 'ds' => [], 'catch' => undef }; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# 1. Load specified MTA modules |
41
|
2822
|
|
|
|
|
6285
|
for my $e ('load', 'order') { |
42
|
|
|
|
|
|
|
# Order of MTA modules |
43
|
5644
|
100
|
|
|
|
11647
|
next unless exists $argvs->{ $e }; |
44
|
1
|
50
|
|
|
|
5
|
next unless ref $argvs->{ $e } eq 'ARRAY'; |
45
|
1
|
50
|
|
|
|
2
|
next unless scalar @{ $argvs->{ $e } }; |
|
1
|
|
|
|
|
3
|
|
46
|
1
|
|
|
|
|
3
|
$param->{ $e } = $argvs->{ $e }; |
47
|
|
|
|
|
|
|
} |
48
|
2822
|
|
|
|
|
7990
|
$ToBeLoaded = __PACKAGE__->load(%$param); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# 2. Split email data to headers and a body part. |
51
|
2822
|
50
|
|
|
|
6440
|
return undef unless my $aftersplit = __PACKAGE__->divideup(\$email); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# 3. Convert email headers from text to hash reference |
54
|
2822
|
|
|
|
|
5455
|
$thing->{'from'} = $aftersplit->[0]; |
55
|
2822
|
|
|
|
|
7032
|
$thing->{'header'} = __PACKAGE__->makemap(\$aftersplit->[1]); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# 4. Decode and rewrite the "Subject:" header |
58
|
2822
|
50
|
|
|
|
7180
|
if( $thing->{'header'}->{'subject'} ) { |
59
|
|
|
|
|
|
|
# Decode MIME-Encoded "Subject:" header |
60
|
2822
|
|
|
|
|
5205
|
my $s = $thing->{'header'}->{'subject'}; |
61
|
2822
|
100
|
|
|
|
14829
|
my $q = Sisimai::MIME->is_mimeencoded(\$s) ? Sisimai::MIME->mimedecode([split(/[ ]/, $s)]) : $s; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# Remove "Fwd:" string from the "Subject:" header |
64
|
2822
|
100
|
|
|
|
9159
|
if( lc($q) =~ /\A[ \t]*fwd?:[ ]*(.*)\z/ ) { |
65
|
|
|
|
|
|
|
# Delete quoted strings, quote symbols(>) |
66
|
29
|
|
|
|
|
163
|
$q = $1; |
67
|
29
|
|
|
|
|
435
|
$aftersplit->[2] =~ s/^[>]+[ ]//gm; |
68
|
29
|
|
|
|
|
196
|
$aftersplit->[2] =~ s/^[>]$//gm; |
69
|
|
|
|
|
|
|
} |
70
|
2822
|
|
|
|
|
6271
|
$thing->{'header'}->{'subject'} = $q; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# 5. Rewrite message body for detecting the bounce reason |
74
|
2822
|
|
|
|
|
12716
|
$TryOnFirst = Sisimai::Order->make($thing->{'header'}->{'subject'}); |
75
|
2822
|
|
100
|
|
|
15290
|
$param = { 'hook' => $argvs->{'hook'} || undef, 'mail' => $thing, 'body' => \$aftersplit->[2] }; |
76
|
2822
|
100
|
|
|
|
10891
|
return undef unless my $bouncedata = __PACKAGE__->parse(%$param); |
77
|
2813
|
50
|
|
|
|
8261
|
return undef unless keys %$bouncedata; |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# 6. Rewrite headers of the original message in the body part |
80
|
2813
|
|
|
|
|
11382
|
$thing->{ $_ } = $bouncedata->{ $_ } for ('ds', 'catch', 'rfc822'); |
81
|
2813
|
|
66
|
|
|
8893
|
my $r = $bouncedata->{'rfc822'} || $aftersplit->[2]; |
82
|
2813
|
100
|
|
|
|
10139
|
$thing->{'rfc822'} = ref $r ? $r : __PACKAGE__->makemap(\$r, 1); |
83
|
|
|
|
|
|
|
|
84
|
2813
|
|
|
|
|
18537
|
return bless($thing, $class); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub load { |
88
|
|
|
|
|
|
|
# Load MTA modules which specified at 'order' and 'load' in the argument |
89
|
|
|
|
|
|
|
# @param [Hash] argvs Module information to be loaded |
90
|
|
|
|
|
|
|
# @options argvs [Array] load User defined MTA module list |
91
|
|
|
|
|
|
|
# @options argvs [Array] order The order of MTA modules |
92
|
|
|
|
|
|
|
# @return [Array] Module list |
93
|
|
|
|
|
|
|
# @since v4.20.0 |
94
|
2823
|
|
|
2823
|
0
|
4998
|
my $class = shift; |
95
|
2823
|
|
|
|
|
3931
|
my $argvs = { @_ }; |
96
|
|
|
|
|
|
|
|
97
|
2823
|
|
|
|
|
3575
|
my @modulelist; |
98
|
2823
|
|
|
|
|
3464
|
my $tobeloaded = []; |
99
|
|
|
|
|
|
|
|
100
|
2823
|
|
|
|
|
3926
|
for my $e ('load', 'order') { |
101
|
|
|
|
|
|
|
# The order of MTA modules specified by user |
102
|
5646
|
100
|
|
|
|
10366
|
next unless exists $argvs->{ $e }; |
103
|
1
|
50
|
|
|
|
4
|
next unless ref $argvs->{ $e } eq 'ARRAY'; |
104
|
1
|
50
|
|
|
|
2
|
next unless scalar @{ $argvs->{ $e } }; |
|
1
|
|
|
|
|
3
|
|
105
|
|
|
|
|
|
|
|
106
|
1
|
50
|
|
|
|
3
|
push @modulelist, @{ $argvs->{'order'} } if $e eq 'order'; |
|
1
|
|
|
|
|
3
|
|
107
|
1
|
50
|
|
|
|
3
|
next unless $e eq 'load'; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Load user defined MTA module |
110
|
0
|
|
|
|
|
0
|
for my $v ( @{ $argvs->{'load'} } ) { |
|
0
|
|
|
|
|
0
|
|
111
|
|
|
|
|
|
|
# Load user defined MTA module |
112
|
0
|
|
|
|
|
0
|
eval { |
113
|
0
|
|
|
|
|
0
|
(my $modulepath = $v) =~ s|::|/|g; |
114
|
0
|
|
|
|
|
0
|
require $modulepath.'.pm'; |
115
|
|
|
|
|
|
|
}; |
116
|
0
|
0
|
|
|
|
0
|
next if $@; |
117
|
0
|
|
|
|
|
0
|
push @$tobeloaded, $v; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
2823
|
|
|
|
|
4693
|
for my $e ( @modulelist ) { |
122
|
|
|
|
|
|
|
# Append the custom order of MTA modules |
123
|
6
|
50
|
|
|
|
9
|
next if grep { $e eq $_ } @$tobeloaded; |
|
15
|
|
|
|
|
22
|
|
124
|
6
|
|
|
|
|
10
|
push @$tobeloaded, $e; |
125
|
|
|
|
|
|
|
} |
126
|
2823
|
|
|
|
|
6384
|
return $tobeloaded; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub divideup { |
130
|
|
|
|
|
|
|
# Divide email data up headers and a body part. |
131
|
|
|
|
|
|
|
# @param [String] email Email data |
132
|
|
|
|
|
|
|
# @return [Array] Email data after split |
133
|
|
|
|
|
|
|
# @since v4.14.0 |
134
|
2822
|
|
|
2822
|
0
|
3926
|
my $class = shift; |
135
|
2822
|
|
50
|
|
|
6147
|
my $email = shift // return undef; |
136
|
2822
|
|
|
|
|
6945
|
my $block = ['', '', '']; # 0:From, 1:Header, 2:Body |
137
|
|
|
|
|
|
|
|
138
|
2822
|
100
|
|
|
|
30576
|
$$email =~ s/\r\n/\n/gm if rindex($$email, "\r\n") > -1; |
139
|
2822
|
50
|
|
|
|
131024
|
$$email =~ s/[ \t]+$//gm if $$email =~ /[ \t]+$/; |
140
|
|
|
|
|
|
|
|
141
|
2822
|
|
|
|
|
24725
|
($block->[1], $block->[2]) = split(/\n\n/, $$email, 2); |
142
|
2822
|
50
|
|
|
|
7327
|
return undef unless $block->[1]; |
143
|
2822
|
50
|
|
|
|
6075
|
return undef unless $block->[2]; |
144
|
|
|
|
|
|
|
|
145
|
2822
|
100
|
|
|
|
7742
|
if( substr($block->[1], 0, 5) eq 'From ' ) { |
146
|
|
|
|
|
|
|
# From MAILER-DAEMON Tue Feb 11 00:00:00 2014 |
147
|
387
|
|
|
|
|
2017
|
$block->[0] = [split(/\n/, $block->[1], 2)]->[0]; |
148
|
387
|
|
|
|
|
1468
|
$block->[0] =~ y/\r\n//d; |
149
|
|
|
|
|
|
|
} else { |
150
|
|
|
|
|
|
|
# Set pseudo UNIX From line |
151
|
2435
|
|
|
|
|
3521
|
$block->[0] = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014'; |
152
|
|
|
|
|
|
|
} |
153
|
2822
|
50
|
|
|
|
12122
|
$block->[1] .= "\n" unless $block->[1] =~ /\n\z/; |
154
|
|
|
|
|
|
|
|
155
|
2822
|
|
|
|
|
5370
|
for my $e ('image/', 'application/', 'text/html') { |
156
|
|
|
|
|
|
|
# https://github.com/sisimai/p5-sisimai/issues/492, Reduce email size |
157
|
8466
|
|
|
|
|
9369
|
my $p0 = 0; |
158
|
8466
|
|
|
|
|
8623
|
my $p1 = 0; |
159
|
8466
|
100
|
|
|
|
12750
|
my $ep = $e eq 'text/html' ? ' |