line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Exim::SpoolMessage; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
20759
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
4
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
25
|
|
5
|
1
|
|
|
1
|
|
5
|
use vars qw($AUTOLOAD); |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
46
|
|
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
4
|
use Carp qw(carp croak); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
63
|
|
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
5
|
use Fcntl qw(:DEFAULT SEEK_SET); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
480
|
|
10
|
1
|
|
|
1
|
|
814
|
use Mail::Header; |
|
1
|
|
|
|
|
5074
|
|
|
1
|
|
|
|
|
1115
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Exim::SpoolMessage - Read and parse Exim spool files. |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=cut |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
our $VERSION = '0.05'; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 SYNOPSIS |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
Exim::SpoolMessage provides access to the messages stored in Exim's |
25
|
|
|
|
|
|
|
spool directory. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
The format of the Exim spool files is described in section 53 of the |
28
|
|
|
|
|
|
|
Exim specification document. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
use Exim::SpoolMessage; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my $msg = Exim::SpoolMessage->load('/var/spool/exim/input', |
33
|
|
|
|
|
|
|
'1N4toN-000G2Z-6M'); |
34
|
|
|
|
|
|
|
print "Return-path: <", $msg->return_path, ">\n"; |
35
|
|
|
|
|
|
|
print $msg->head->as_string(), "\n", @{$msg->body}; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
The module was written in order to be able to provide external commands |
38
|
|
|
|
|
|
|
access to the contents of the message during message filtering process. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head2 Exim::SpoolMessage->load($input_dir, $message_id) |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
Takes to parameters - location of the input directory where spool files |
45
|
|
|
|
|
|
|
are located and the message id of the desired message. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
NOTE: $input_dir has to be location of the directory where spool files |
48
|
|
|
|
|
|
|
are located. If split_spool_directory it will not equal to the spool |
49
|
|
|
|
|
|
|
directory. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
Returns an object with a lot of methods, please see below for details. |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
The constructor croaks on errors. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=cut |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub load { |
58
|
0
|
|
|
0
|
1
|
|
my $proto = shift; |
59
|
0
|
|
0
|
|
|
|
my $class = ref($proto) || $proto; |
60
|
0
|
0
|
|
|
|
|
my $dir = shift or croak 'Missing input directory'; |
61
|
0
|
0
|
|
|
|
|
my $id = shift or croak 'Missing message id'; |
62
|
0
|
|
|
|
|
|
my $self = {input_dir => $dir, message_id => $id}; |
63
|
0
|
|
|
|
|
|
bless $self, $class; |
64
|
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
|
my %keys = keys %{$self}; |
|
0
|
|
|
|
|
|
|
66
|
0
|
|
|
|
|
|
delete @keys{qw(input_dir message_id)}; |
67
|
0
|
|
|
|
|
|
delete @{$self}{keys %keys}; |
|
0
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
0
|
0
|
|
|
|
|
open my $hh, "$self->{'input_dir'}/$self->{'message_id'}-H" or |
70
|
|
|
|
|
|
|
croak "Cannot open '$self->{'input_dir'}/$self->{'message_id'}-H': $!"; |
71
|
0
|
0
|
|
|
|
|
open my $dh, "$self->{'input_dir'}/$self->{'message_id'}-D" or |
72
|
|
|
|
|
|
|
croak "Cannot open '$self->{'input_dir'}/$self->{'message_id'}-D': $!"; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# The format of the Exim spool files is described in section 53 of the |
75
|
|
|
|
|
|
|
# Exim specification. |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# The first line contains the final component of the file name. |
78
|
0
|
|
|
|
|
|
chomp(my $tmp = <$hh>); |
79
|
0
|
0
|
|
|
|
|
croak "Corrupted spool file '$self->{'message_id'}-H'" |
80
|
|
|
|
|
|
|
if $tmp ne "$self->{'message_id'}-H"; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# The second line contains the login name for the uid of the process |
84
|
|
|
|
|
|
|
# that called Exim to read the message, followed by the numerical uid |
85
|
|
|
|
|
|
|
# and gid. |
86
|
0
|
|
|
|
|
|
chomp($tmp = <$hh>); |
87
|
0
|
|
|
|
|
|
@{$self}{qw(caller_name caller_uid caller_gid)} = split / /, $tmp, 3; |
|
0
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# The third line of the file contains the address of the message’s |
90
|
|
|
|
|
|
|
# sender as transmitted in the envelope, contained in angle brackets. |
91
|
|
|
|
|
|
|
# The sender address is empty for bounce messages. |
92
|
0
|
|
|
|
|
|
chomp($tmp = <$hh>); |
93
|
0
|
|
|
|
|
|
($self->{'return_path'} = $tmp) =~ s/^<(.+)>$/$1/; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# The fourth line contains two numbers. The first is the time that the |
96
|
|
|
|
|
|
|
# message was received, in the conventional Unix form – the number of |
97
|
|
|
|
|
|
|
# seconds since the start of the epoch. The second number is a count of |
98
|
|
|
|
|
|
|
# the number of messages warning of delayed delivery that have been |
99
|
|
|
|
|
|
|
# sent to the sender. |
100
|
0
|
|
|
|
|
|
chomp($tmp = <$hh>); |
101
|
0
|
|
|
|
|
|
@{$self}{qw(time_received warning_count)} = split / /, $tmp, 2; |
|
0
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# There follow a number of lines starting with a hyphen. |
104
|
|
|
|
|
|
|
# These can appear in any order, and are omitted when not relevant. |
105
|
0
|
|
|
|
|
|
while (1) { |
106
|
|
|
|
|
|
|
# -acl |
107
|
|
|
|
|
|
|
# -aclc |
108
|
|
|
|
|
|
|
# -aclm |
109
|
|
|
|
|
|
|
# -active_hostname |
110
|
|
|
|
|
|
|
# -allow_unqualified_recipient |
111
|
|
|
|
|
|
|
# -allow_unqualified_sender |
112
|
|
|
|
|
|
|
# -auth_id |
113
|
|
|
|
|
|
|
# -auth_sender |
114
|
|
|
|
|
|
|
# -body_linecount |
115
|
|
|
|
|
|
|
# -body_zerocount |
116
|
|
|
|
|
|
|
# -deliver_firsttime |
117
|
|
|
|
|
|
|
# -frozen |
118
|
|
|
|
|
|
|
# -helo_name |
119
|
|
|
|
|
|
|
# -host_address . |
120
|
|
|
|
|
|
|
# -host_auth |
121
|
|
|
|
|
|
|
# -host_lookup_failed |
122
|
|
|
|
|
|
|
# -host_name |
123
|
|
|
|
|
|
|
# -ident |
124
|
|
|
|
|
|
|
# -interface_address . |
125
|
|
|
|
|
|
|
# -local |
126
|
|
|
|
|
|
|
# -localerror |
127
|
|
|
|
|
|
|
# -local_scan |
128
|
|
|
|
|
|
|
# -manual_thaw |
129
|
|
|
|
|
|
|
# -N |
130
|
|
|
|
|
|
|
# -received_protocol |
131
|
|
|
|
|
|
|
# -sender_set_untrusted |
132
|
|
|
|
|
|
|
# -spam_score_int |
133
|
|
|
|
|
|
|
# -tls_certificate_verified |
134
|
|
|
|
|
|
|
# -tls_cipher |
135
|
|
|
|
|
|
|
# -tls_peerdn |
136
|
0
|
|
|
|
|
|
chomp($tmp = <$hh>); |
137
|
0
|
0
|
|
|
|
|
if ($tmp =~ /^-(acl[mc]) (\d+) (\d+)/) { |
|
|
0
|
|
|
|
|
|
138
|
0
|
|
|
|
|
|
my ($key, $num, $len) = ($1, $2 + 1); |
139
|
0
|
|
|
|
|
|
read $hh, $tmp, $len; |
140
|
0
|
|
|
|
|
|
chomp($self->{$key} = $tmp); |
141
|
0
|
|
|
|
|
|
next; |
142
|
|
|
|
|
|
|
} elsif ($tmp =~ /^-acl (\d+) (\d+)/) { |
143
|
0
|
|
|
|
|
|
my ($num, $len) = ($1, $2 + 1); |
144
|
0
|
0
|
|
|
|
|
my $key = ($num < 10) ? 'acl_c' . $num : 'acl_m' . ($num - 10); |
145
|
0
|
|
|
|
|
|
read $hh, $tmp, $len; |
146
|
0
|
|
|
|
|
|
chomp($self->{$key} = $tmp); |
147
|
0
|
|
|
|
|
|
next; |
148
|
|
|
|
|
|
|
} |
149
|
0
|
0
|
|
|
|
|
last if $tmp !~ s/^-//; |
150
|
0
|
|
|
|
|
|
my ($key, $val) = split / /, $tmp, 2; |
151
|
0
|
|
|
|
|
|
$self->{"opt_$key"} = $val; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Following the options there is a list of those addresses to which the |
155
|
|
|
|
|
|
|
# message is not to be delivered. This set of addresses is initialized from |
156
|
|
|
|
|
|
|
# the command line when the -t option is used and |
157
|
|
|
|
|
|
|
# extract_addresses_remove_arguments is set; otherwise it starts out empty. |
158
|
|
|
|
|
|
|
# Whenever a successful delivery is made, the address is added to this set. |
159
|
|
|
|
|
|
|
# The addresses are kept internally as a balanced binary tree, and it is a |
160
|
|
|
|
|
|
|
# representation of that tree which is written to the spool file. If an |
161
|
|
|
|
|
|
|
# address is expanded via an alias or forward file, the original address is |
162
|
|
|
|
|
|
|
# added to the tree when deliveries to all its child addresses are |
163
|
|
|
|
|
|
|
# complete. |
164
|
|
|
|
|
|
|
# |
165
|
|
|
|
|
|
|
# If the tree is empty, there is a single line in the spool file containing |
166
|
|
|
|
|
|
|
# just the text "XX”. Otherwise, each line consists of two letters, which |
167
|
|
|
|
|
|
|
# are either Y or N, followed by an address. |
168
|
0
|
|
|
|
|
|
while (1) { |
169
|
0
|
|
|
|
|
|
chomp($tmp = <$hh>); |
170
|
0
|
0
|
|
|
|
|
last if $tmp !~ /^[XYN][XYN]/; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# After the non-recipients tree, there is a list of the message’s |
174
|
|
|
|
|
|
|
# recipients. This is a simple list, preceded by a count. It includes all |
175
|
|
|
|
|
|
|
# the original recipients of the message, including those to whom the |
176
|
|
|
|
|
|
|
# message has already been delivered. |
177
|
|
|
|
|
|
|
# |
178
|
|
|
|
|
|
|
# In the simplest case, the list contains one address per line. |
179
|
|
|
|
|
|
|
# |
180
|
|
|
|
|
|
|
# However, when a child address has been added to the top-level addresses |
181
|
|
|
|
|
|
|
# as a result of the use of the one_time option on a redirect router, each |
182
|
|
|
|
|
|
|
# line is of the following form: |
183
|
|
|
|
|
|
|
# |
184
|
|
|
|
|
|
|
# ,# |
185
|
|
|
|
|
|
|
# |
186
|
|
|
|
|
|
|
# The 01 flag bit indicates the presence of the three other fields that |
187
|
|
|
|
|
|
|
# follow the top-level address. Other bits may be used in future to support |
188
|
|
|
|
|
|
|
# additional fields. The is the offset in the recipients |
189
|
|
|
|
|
|
|
# list of the original parent of the "one time" address. The first two |
190
|
|
|
|
|
|
|
# fields are the envelope sender that is associated with this address and |
191
|
|
|
|
|
|
|
# its length. If the length is zero, there is no special envelope sender |
192
|
|
|
|
|
|
|
# (there are then two space characters in the line). A non-empty field can |
193
|
|
|
|
|
|
|
# arise from a redirect router that has an errors_to setting. |
194
|
0
|
|
|
|
|
|
$self->{'recipients'} = []; |
195
|
0
|
|
|
|
|
|
for my $i (1 .. $tmp) { |
196
|
0
|
|
|
|
|
|
chomp($tmp = <$hh>); |
197
|
0
|
|
|
|
|
|
push @{$self->{'recipients'}}, $tmp; |
|
0
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# A blank line separates the envelope and status information from the |
201
|
|
|
|
|
|
|
# headers which follow. |
202
|
0
|
|
|
|
|
|
$tmp = <$hh>; |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# A header may occupy several lines of the file, and |
205
|
|
|
|
|
|
|
# to save effort when reading it in, each header is preceded by a number |
206
|
|
|
|
|
|
|
# and an identifying character. The number is the number of characters in |
207
|
|
|
|
|
|
|
# the header, including any embedded newlines and the terminating newline. |
208
|
|
|
|
|
|
|
# The character is one of the following: |
209
|
|
|
|
|
|
|
# |
210
|
|
|
|
|
|
|
# header in which Exim has no special interest |
211
|
|
|
|
|
|
|
# B Bcc: header |
212
|
|
|
|
|
|
|
# C Cc: header |
213
|
|
|
|
|
|
|
# F From: header |
214
|
|
|
|
|
|
|
# I Message-id: header |
215
|
|
|
|
|
|
|
# P Received: header – P for "postmark" |
216
|
|
|
|
|
|
|
# R Reply-To: header |
217
|
|
|
|
|
|
|
# S Sender: header |
218
|
|
|
|
|
|
|
# T To: header |
219
|
|
|
|
|
|
|
# * replaced or deleted header |
220
|
0
|
|
|
|
|
|
my $pos = tell $hh; |
221
|
0
|
|
|
|
|
|
my @headers; |
222
|
0
|
|
|
|
|
|
while (defined(my $line = <$hh>)) { |
223
|
0
|
0
|
|
|
|
|
$line =~ /^((\d+)([ BCFIPRST*]) )/ or next; |
224
|
0
|
|
|
|
|
|
$pos += length($1); |
225
|
0
|
|
|
|
|
|
my ($len, $char) = ($2, $3); |
226
|
0
|
|
|
|
|
|
seek $hh, $pos, SEEK_SET; |
227
|
0
|
|
|
|
|
|
read $hh, $tmp, $len; |
228
|
0
|
0
|
|
|
|
|
push @headers, $tmp if $char ne '*'; |
229
|
0
|
|
|
|
|
|
$pos = tell $hh; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# The first line contains the final component of the file name. |
233
|
0
|
|
|
|
|
|
chomp($tmp = <$dh>); |
234
|
0
|
0
|
|
|
|
|
croak "Corrupted spool file '$self->{'message_id'}-D'" |
235
|
|
|
|
|
|
|
if $tmp ne "$self->{'message_id'}-D"; |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# The data portion of the message is kept in the -D file on its own. |
238
|
0
|
|
|
|
|
|
my @body; |
239
|
0
|
|
|
|
|
|
while (defined(my $line = <$dh>)) { |
240
|
0
|
|
|
|
|
|
push @body, $line; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
close $hh; |
244
|
0
|
|
|
|
|
|
close $dh; |
245
|
|
|
|
|
|
|
|
246
|
0
|
|
|
|
|
|
$self->{'head'} = Mail::Header->new(\@headers, Modify => 0); |
247
|
0
|
|
|
|
|
|
$self->{'body'} = \@body; |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
|
return $self; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head1 METHODS |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head2 $msg->head |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Mail::Header object with the message headers. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head2 $msg->body |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Reference to an array with the contents of the message body. Each |
261
|
|
|
|
|
|
|
item represents a line of the body. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 Other methods |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
In addition, there are many other mehotds that will provide access to |
266
|
|
|
|
|
|
|
various details related to the message. Please consult the Exim |
267
|
|
|
|
|
|
|
documentation. |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Available methods (not all may be present and there may be |
270
|
|
|
|
|
|
|
other as well): |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=over |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=item * $msg->message_id |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=item * $msg->caller_name |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=item * $msg->caller_uid |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=item * $msg->caller_gid |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=item * $msg->return_path |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=item * $msg->time_received |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=item * $msg->warning_count |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=item * $msg->aclc* |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=item * $msg->aclm* |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=item * $msg->opt_active_hostname |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=item * $msg->opt_allow_unqualified_recipient |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=item * $msg->opt_allow_unqualified_sender |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=item * $msg->opt_auth_id |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=item * $msg->opt_auth_sender |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=item * $msg->opt_body_linecount |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=item * $msg->opt_body_zerocount |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=item * $msg->opt_deliver_firsttime |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=item * $msg->opt_frozen |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=item * $msg->opt_helo_name |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=item * $msg->opt_host_address |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=item * $msg->opt_host_auth |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=item * $msg->opt_host_lookup_failed |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=item * $msg->opt_host_name |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=item * $msg->opt_ident |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=item * $msg->opt_interface_address |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=item * $msg->opt_local |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=item * $msg->opt_localerror |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=item * $msg->opt_local_scan |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=item * $msg->opt_manual_thaw |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=item * $msg->opt_received_protocol |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=item * $msg->opt_sender_set_untrusted |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=item * $msg->opt_spam_score_int |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=item * $msg->opt_tls_certificate_verified |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=item * $msg->opt_tls_cipher |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=item * $msg->opt_tls_peerdn |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=item * $msg->recipients |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=back |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=cut |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=head1 AUTHOR |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
Kirill Miazine |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
Copyright 2009 Kirill Miazine. |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
This software is distributed under an ISC style license, please see |
361
|
|
|
|
|
|
|
for details. |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=cut |
364
|
|
|
|
|
|
|
|
365
|
0
|
|
|
0
|
|
|
sub DESTROY { 1; } |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub AUTOLOAD { |
368
|
0
|
|
|
0
|
|
|
my $self = shift; |
369
|
0
|
|
|
|
|
|
my ($attr) = ($AUTOLOAD =~ /::([^:]+)$/); |
370
|
|
|
|
|
|
|
|
371
|
0
|
0
|
0
|
|
|
|
if ($attr =~ /^([a-zA-Z0-9_]+)$/ and exists $self->{$attr}) { |
372
|
0
|
|
|
|
|
|
eval "sub $attr { shift->{'$attr'} }"; |
373
|
0
|
|
|
|
|
|
return $self->{$attr}; |
374
|
|
|
|
|
|
|
} else { |
375
|
0
|
|
|
|
|
|
croak "Unknown attribute '$attr'"; |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
1; |