| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Mail::Colander::Message; |
|
2
|
1
|
|
|
1
|
|
14
|
use v5.24; |
|
|
1
|
|
|
|
|
4
|
|
|
3
|
1
|
|
|
1
|
|
6
|
use Moo; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
8
|
|
|
4
|
1
|
|
|
1
|
|
496
|
use experimental qw< signatures >; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
|
|
{ our $VERSION = '0.004' } |
|
6
|
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
990
|
use Email::Address::XS qw< parse_email_addresses >; |
|
|
1
|
|
|
|
|
3622
|
|
|
|
1
|
|
|
|
|
83
|
|
|
8
|
1
|
|
|
1
|
|
9
|
use Scalar::Util qw< blessed >; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
60
|
|
|
9
|
1
|
|
|
1
|
|
6
|
use Ouch qw< :trytiny_var >; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
9
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub coerce_entity ($input) { |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# allow for getting another Mail::Colander::Message object to be passed |
|
14
|
|
|
|
|
|
|
# as entity, just go to its inner entity in this case |
|
15
|
|
|
|
|
|
|
if (my $class = blessed($input)) { |
|
16
|
|
|
|
|
|
|
return $input->entity if $class eq __PACKAGE__; |
|
17
|
|
|
|
|
|
|
return $input; |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# not blessed, consider this as a message to be parsed |
|
21
|
|
|
|
|
|
|
require MIME::Parser; |
|
22
|
|
|
|
|
|
|
my $parser = MIME::Parser->new; |
|
23
|
|
|
|
|
|
|
$parser->output_to_core(1); |
|
24
|
|
|
|
|
|
|
return $parser->parse_data($input); |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
} |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub expand_addresses ($addrs) { |
|
29
|
|
|
|
|
|
|
[ map { $_->address } map { parse_email_addresses($_) } $addrs->@* ]; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub trim ($string) { $string =~ s{\A\s+|\s+\z}{}rgmxs } |
|
33
|
|
|
|
|
|
|
|
|
34
|
1
|
|
|
1
|
|
504
|
use namespace::clean; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
11
|
|
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
has entity => (is => 'ro', coerce => \&coerce_entity); |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# the cache is for memoizing tamed addresses |
|
39
|
|
|
|
|
|
|
has cache_for => (is => 'ro', default => sub { return {} }); |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
has $_ => (is => 'lazy', init_arg => undef) |
|
42
|
|
|
|
|
|
|
for qw< from to cc bcc recipients subject >; |
|
43
|
|
|
|
|
|
|
|
|
44
|
0
|
|
|
0
|
|
|
sub _build_to ($self) { $self->bare_addresses('to') } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
45
|
0
|
|
|
0
|
|
|
sub _build_cc ($self) { $self->bare_addresses('cc') } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
46
|
0
|
|
|
0
|
|
|
sub _build_bcc ($self) { $self->bare_addresses('bcc') } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
47
|
0
|
|
|
0
|
|
|
sub _build_recipients ($self) { $self->bare_addresses(qw< to cc bcc >) } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
48
|
0
|
|
|
0
|
|
|
sub _build_from ($self) { trim($self->entity->head->get(from => 0)) } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
49
|
0
|
|
|
0
|
|
|
sub _build_subject ($self) { $self->entity->head->get(subject => 0) } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
51
|
0
|
|
|
0
|
1
|
|
sub header_all ($self, $key) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
52
|
0
|
|
0
|
|
|
|
$self->cache_for->{headers}{$key} |
|
53
|
|
|
|
|
|
|
//= [ $self->entity->head->get_all($key) ]; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
0
|
|
|
0
|
1
|
|
sub header_first ($self, $key) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
57
|
0
|
|
|
|
|
|
my $all = $self->header_all($key); |
|
58
|
0
|
0
|
|
|
|
|
return $all->@* ? $all->[0] : undef; |
|
59
|
|
|
|
|
|
|
} |
|
60
|
|
|
|
|
|
|
|
|
61
|
0
|
|
|
0
|
1
|
|
sub bare_addresses ($self, @types) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
62
|
0
|
|
0
|
|
|
|
my $af = $self->cache_for->{bare_addresses} //= {}; |
|
63
|
0
|
|
|
0
|
|
|
my $cache_fetcher = sub ($type) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
64
|
0
|
|
0
|
|
|
|
return $af->{$type} //= do { |
|
65
|
0
|
|
|
|
|
|
my %seen; |
|
66
|
|
|
|
|
|
|
[ |
|
67
|
0
|
|
|
|
|
|
grep { ! $seen{$_}++ } |
|
68
|
0
|
|
|
|
|
|
map { $_->address } |
|
69
|
0
|
|
|
|
|
|
map { parse_email_addresses($_) } |
|
|
0
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
$self->entity->head->get_all($type) |
|
71
|
|
|
|
|
|
|
]; |
|
72
|
|
|
|
|
|
|
}; |
|
73
|
0
|
|
|
|
|
|
}; |
|
74
|
|
|
|
|
|
|
|
|
75
|
0
|
|
|
|
|
|
my (@list, %seen_type, %seen_address); |
|
76
|
0
|
0
|
|
|
|
|
for (map { $_ eq 'recipients' ? qw< from cc bcc > : $_ } @types) { |
|
|
0
|
|
|
|
|
|
|
|
77
|
0
|
0
|
|
|
|
|
next if $seen_type{$_}++; # don't bother |
|
78
|
0
|
|
|
|
|
|
push @list, grep { ! $seen_address{$_} } $cache_fetcher->($_)->@*; |
|
|
0
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
} |
|
80
|
0
|
|
|
|
|
|
return \@list; |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
|
|
83
|
0
|
|
|
0
|
1
|
|
sub create ($package, $entity) { $package->new(entity => $entity) } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
1; |