line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
1
|
|
|
1
|
|
416
|
use strict; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
24
|
|
2
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
32
|
|
3
|
|
|
|
|
|
|
package Email::Simple::Test::TraceHeaders 0.091703; |
4
|
|
|
|
|
|
|
# ABSTRACT: generate sample trace headers for testing |
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
4
|
use Carp (); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
27
|
|
7
|
1
|
|
|
1
|
|
359
|
use Email::Date::Format (); |
|
1
|
|
|
|
|
2874
|
|
|
1
|
|
|
|
|
19
|
|
8
|
1
|
|
|
1
|
|
376
|
use Email::Simple; |
|
1
|
|
|
|
|
3882
|
|
|
1
|
|
|
|
|
25
|
|
9
|
1
|
|
|
1
|
|
5
|
use Email::Simple::Creator; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
16
|
|
10
|
1
|
|
|
1
|
|
403
|
use Sub::Exporter::Util (); |
|
1
|
|
|
|
|
14775
|
|
|
1
|
|
|
|
|
40
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
|
|
6
|
use Sub::Exporter -setup => { |
13
|
|
|
|
|
|
|
exports => [ prev => \'_build_prev' ], |
14
|
|
|
|
|
|
|
groups => [ helpers => [ qw(prev) ] ], |
15
|
1
|
|
|
1
|
|
6
|
}; |
|
1
|
|
|
|
|
2
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# For now, we'll only generate one style of Received header: postfix |
18
|
|
|
|
|
|
|
# It's what I encounter the most, and it's simple and straightforward. |
19
|
|
|
|
|
|
|
# In the future, we'll be flexible, maybe. -- rjbs, 2009-06-19 |
20
|
|
|
|
|
|
|
my %POSTFIX_FMT = ( |
21
|
|
|
|
|
|
|
for => q{from %s (%s [%s]) by %s (Postfix) with ESMTP id %s for <%s>; %s}, |
22
|
|
|
|
|
|
|
nofor => q{from %s (%s [%s]) by %s (Postfix) with ESMTP id %s%s; %s}, |
23
|
|
|
|
|
|
|
); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
#pod =head1 METHODS |
26
|
|
|
|
|
|
|
#pod |
27
|
|
|
|
|
|
|
#pod =head2 trace_headers |
28
|
|
|
|
|
|
|
#pod |
29
|
|
|
|
|
|
|
#pod my $header_strings = Email::Simple::Test::TraceHeaders->trace_headers(\%arg); |
30
|
|
|
|
|
|
|
#pod |
31
|
|
|
|
|
|
|
#pod This returns an arrayref of "Received" header strings. |
32
|
|
|
|
|
|
|
#pod |
33
|
|
|
|
|
|
|
#pod At present, all headers are produced in Postfix style. |
34
|
|
|
|
|
|
|
#pod |
35
|
|
|
|
|
|
|
#pod At present the only valid argument is C, which is an arrayref of hashrefs |
36
|
|
|
|
|
|
|
#pod describing hops. Each hashref should have the following entries: |
37
|
|
|
|
|
|
|
#pod |
38
|
|
|
|
|
|
|
#pod from_helo - the hostname given in the sending host's HELO |
39
|
|
|
|
|
|
|
#pod from_rdns - the hostname found by looking up the PTR for the sender's ip |
40
|
|
|
|
|
|
|
#pod from_ip - the IP addr of the sending host |
41
|
|
|
|
|
|
|
#pod by_name - the hostname of the receiving host |
42
|
|
|
|
|
|
|
#pod queue_id - the id of the mail queue entry created upon receipt |
43
|
|
|
|
|
|
|
#pod env_to - the recipient of the message (an email addr) |
44
|
|
|
|
|
|
|
#pod time - the timestamp on the header |
45
|
|
|
|
|
|
|
#pod |
46
|
|
|
|
|
|
|
#pod At present, these are all required. In the future they may have more flexible |
47
|
|
|
|
|
|
|
#pod semantics, and more formats for output of hops may be supported. |
48
|
|
|
|
|
|
|
#pod |
49
|
|
|
|
|
|
|
#pod =cut |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub trace_headers { |
52
|
1
|
|
|
1
|
1
|
3
|
my ($self, $arg) = @_; |
53
|
|
|
|
|
|
|
|
54
|
1
|
50
|
|
|
|
11
|
Carp::confess("no hops provided") unless $arg->{hops}; |
55
|
|
|
|
|
|
|
|
56
|
1
|
|
|
|
|
2
|
my @received; |
57
|
|
|
|
|
|
|
my %last; |
58
|
1
|
|
|
|
|
2
|
for my $hop (@{ $arg->{hops} }) { |
|
1
|
|
|
|
|
7
|
|
59
|
3
|
|
|
|
|
13
|
my %hop = (%$hop); |
60
|
|
|
|
|
|
|
|
61
|
3
|
|
|
|
|
9
|
for my $key (keys %hop) { |
62
|
20
|
100
|
|
|
|
37
|
if (ref $hop->{$key} eq 'CODE') { |
63
|
3
|
|
|
|
|
7
|
$hop{ $key } = $hop{$key}->(\%last); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
my $env_to = ref $hop{env_to} ? $hop{env_to} |
68
|
3
|
100
|
|
|
|
11
|
: $hop{env_to} ? [ $hop{env_to} ] |
|
|
100
|
|
|
|
|
|
69
|
|
|
|
|
|
|
: [ ]; |
70
|
|
|
|
|
|
|
|
71
|
3
|
100
|
|
|
|
9
|
my $fmt = @$env_to == 1 ? $POSTFIX_FMT{for} : $POSTFIX_FMT{nofor}; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
push @received, sprintf $fmt, |
74
|
|
|
|
|
|
|
$hop{from_helo}, |
75
|
|
|
|
|
|
|
$hop{from_rdns}, |
76
|
|
|
|
|
|
|
$hop{from_ip}, |
77
|
|
|
|
|
|
|
$hop{by_name}, # by_ip someday? |
78
|
|
|
|
|
|
|
$hop{queue_id}, |
79
|
|
|
|
|
|
|
@$env_to == 1 ? $env_to->[0] : '', |
80
|
3
|
100
|
|
|
|
11
|
(Email::Date::Format::email_gmdate($hop{time}) . ' (GMT)'); |
81
|
|
|
|
|
|
|
|
82
|
3
|
|
|
|
|
85
|
%last = %hop; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
1
|
|
|
|
|
5
|
return [ reverse @received ]; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
#pod =head2 create_email |
89
|
|
|
|
|
|
|
#pod |
90
|
|
|
|
|
|
|
#pod my $email_simple = Email::Simple::Test::TraceHeaders->create_email( |
91
|
|
|
|
|
|
|
#pod \%trace_arg |
92
|
|
|
|
|
|
|
#pod ); |
93
|
|
|
|
|
|
|
#pod |
94
|
|
|
|
|
|
|
#pod This creates and returns an Email::Simple message with trace headers created by |
95
|
|
|
|
|
|
|
#pod C>. |
96
|
|
|
|
|
|
|
#pod |
97
|
|
|
|
|
|
|
#pod =cut |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub create_email { |
100
|
1
|
|
|
1
|
1
|
4
|
my ($self, $arg) = @_; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
my $email = Email::Simple->create( |
103
|
|
|
|
|
|
|
header => [ |
104
|
1
|
|
|
|
|
2
|
(map {; Received => $_ } @{ $self->trace_headers($arg) }), |
|
3
|
|
|
|
|
13
|
|
|
1
|
|
|
|
|
3
|
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
From => '"X. Ample" ', |
107
|
|
|
|
|
|
|
To => '"E. Xampe" ', |
108
|
|
|
|
|
|
|
], |
109
|
|
|
|
|
|
|
body => "This is a test message.\n", |
110
|
|
|
|
|
|
|
); |
111
|
|
|
|
|
|
|
|
112
|
1
|
|
|
|
|
763
|
return $email; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
#pod =head1 HELPERS |
116
|
|
|
|
|
|
|
#pod |
117
|
|
|
|
|
|
|
#pod Some routines can be exported to make it easier to set up trace headers. |
118
|
|
|
|
|
|
|
#pod |
119
|
|
|
|
|
|
|
#pod You can get them all with: |
120
|
|
|
|
|
|
|
#pod |
121
|
|
|
|
|
|
|
#pod use Email::Simple::Test::TraceHeaders -helpers; |
122
|
|
|
|
|
|
|
#pod |
123
|
|
|
|
|
|
|
#pod =head2 prev |
124
|
|
|
|
|
|
|
#pod |
125
|
|
|
|
|
|
|
#pod This helper gets a value from the previous hop. So, given these hops: |
126
|
|
|
|
|
|
|
#pod |
127
|
|
|
|
|
|
|
#pod { ..., by_name => 'mx.example.com', ... }, |
128
|
|
|
|
|
|
|
#pod { ..., from_rdns => prev('by_name'), ... }, |
129
|
|
|
|
|
|
|
#pod |
130
|
|
|
|
|
|
|
#pod ...the second hop will have F as its C parameter. |
131
|
|
|
|
|
|
|
#pod |
132
|
|
|
|
|
|
|
#pod =cut |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub _build_prev { |
135
|
1
|
|
|
1
|
|
168
|
my ($self) = @_; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub { |
138
|
3
|
|
|
3
|
|
90
|
my ($name) = @_; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub { |
141
|
3
|
|
|
3
|
|
4
|
my ($last) = @_; |
142
|
3
|
|
|
|
|
7
|
$last->{ $name }; |
143
|
|
|
|
|
|
|
} |
144
|
3
|
|
|
|
|
24
|
} |
145
|
1
|
|
|
|
|
4
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
1; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
__END__ |