File Coverage

blib/lib/Mail/DomainKeys/Message.pm
Criterion Covered Total %
statement 119 165 72.1
branch 40 78 51.2
condition 14 36 38.8
subroutine 14 19 73.6
pod 0 15 0.0
total 187 313 59.7


line stmt bran cond sub pod time code
1             # Copyright (c) 2004 Anthony D. Urso. All rights reserved.
2             # This program is free software; you can redistribute it and/or
3             # modify it under the same terms as Perl itself.
4              
5             package Mail::DomainKeys::Message;
6              
7 6     6   295570 use strict;
  6         17  
  6         1597  
8              
9             our $VERSION = "0.88";
10              
11             sub load {
12 6     6   9103 use Mail::Address;
  6         27080  
  6         436  
13 6     6   13789 use Mail::DomainKeys::Header;
  6         17  
  6         254  
14 6     6   6227 use Mail::DomainKeys::Signature;
  6         24  
  6         28646  
15              
16 6     6 0 20 my $type = shift;
17 6         29 my %prms = @_;
18              
19 6         16 my $self = {};
20              
21              
22 6         15 my $file;
23              
24 6 50       31 if ($prms{'File'}) {
25 6 50 33     89 if (ref $prms{'File'} and (ref $prms{'File'} eq "GLOB" or
      33        
26             $prms{'File'}->isa("IO::Handle"))) {
27 6         19 $file = $prms{'File'};
28             } else {
29 0         0 return;
30             }
31             } else {
32 0         0 $file = \*STDIN;
33             }
34              
35 6         15 my $lnum = 0;
36              
37 6         12 my @head;
38              
39 6 50       23 if ($prms{'HeadString'}) {
40 0         0 foreach (split /\n/, $prms{'HeadString'}) {
41 0         0 s/\r$//;
42 0 0       0 last if /^$/;
43 0 0 0     0 if (/^\s/ and $head[$lnum-1]) {
44             #$head[$lnum-1]->append($_);
45 0         0 $head[$lnum-1]->append("\n" . $_);
46 0         0 next;
47             }
48 0         0 $head[$lnum] =
49             parse Mail::DomainKeys::Header(String => $_);
50              
51 0         0 $lnum++;
52             }
53             } else {
54 6         49 while (<$file>) {
55 60         84 chomp;
56 60         160 s/\r$//;
57 60 100       179 last if /^$/;
58 54 100 66     273 if (/^\s/ and $head[$lnum-1]) {
59             #$head[$lnum-1]->append($_);
60 18         91 $head[$lnum-1]->append("\n" . $_);
61 18         92 next;
62             }
63 36         190 $head[$lnum] =
64             parse Mail::DomainKeys::Header(String => $_);
65              
66 36         120 $lnum++;
67             }
68             }
69              
70 6         23 $self->{'HEAD'} = \@head;
71              
72 6         180 my %seen = (FROM => 0, SIGN => 0, SNDR => 0);
73              
74 6         20 foreach my $hdr (@head) {
75 36         211 $hdr->signed($seen{'SIGN'});
76              
77 36 50       121 $hdr->key or
78             return;
79              
80 36 100 66     118 if ($hdr->key =~ /^From$/i and !$seen{'FROM'}) {
    50 33        
    100 66        
81 6         119 my @list = parse Mail::Address($hdr->vunfolded);
82 6         1817 $self->{'FROM'} = $list[0];
83 6         30 $seen{'FROM'} = 1;
84             } elsif ($hdr->key =~ /^Sender$/i and !$seen{'SNDR'}) {
85 0         0 my @list = parse Mail::Address($hdr->vunfolded);
86 0         0 $self->{'SNDR'} = $list[0];
87 0         0 $seen{'SNDR'} = 1;
88             } elsif ($hdr->key =~ /^DomainKey-Signature$/i and
89             not $seen{'SIGN'}) {
90 6         34 $self->{'SIGN'} = parse Mail::DomainKeys::Signature(
91             String => $hdr->vunfolded);
92 6         24 $seen{'SIGN'} = 1;
93             }
94             }
95              
96 6 50       38 if ($prms{'BodyReference'}) {
97 0         0 $self->{'BODY'} = $prms{'BodyReference'};
98             } else {
99 6         13 my @body;
100              
101 6         53 while (<$file>) {
102 71         89 chomp;
103 71         223 s/\r$//;
104 71         680 push @body, $_;
105             }
106              
107 6         31 $self->{'BODY'} = \@body;
108             }
109              
110              
111 6         42 bless $self, $type;
112             }
113              
114             sub canonify {
115 6     6 0 10 my $self = shift;
116              
117              
118 6 50       28 $self->signature->method or
119             return;
120              
121 6 100       19 $self->signature->method eq "nofws" and
122             return $self->nofws;
123              
124 3 50       17 $self->signature->method eq "simple" and
125             return $self->simple;
126              
127 0         0 return;
128             }
129              
130             sub gethline {
131 0     0 0 0 my $self = shift;
132 0 0       0 my $hdrs = shift or
133             return;
134              
135 0         0 my %hmap = map { lc($_) => 1 } (split(/:/, $hdrs));
  0         0  
136              
137 0         0 my @found = ();
138 0         0 foreach my $hdr (@{$self->head}) {
  0         0  
139 0 0       0 if ($hmap{lc($hdr->key)}) {
140 0         0 push(@found, $hdr->key);
141 0         0 delete $hmap{$hdr->key};
142             }
143             }
144              
145 0         0 my $res = join(':', @found);
146 0         0 return $res;
147             }
148              
149             sub nofws {
150 3     3 0 19 my $self = shift;
151              
152 3         11 my $text;
153             my @headers_used;
154              
155              
156 3         7 foreach my $hdr (@{$self->head}) {
  3         18  
157 18 100 66     59 $hdr->signed or $self->signature->signing or
158             next;
159 15 50       35 $self->signature->wantheader($hdr->key) or
160             next;
161 15         49 push @headers_used, lc $hdr->key;
162 15         51 my $line = $hdr->unfolded;
163             #$line =~ s/[\s\r\n]//g;
164 15         132 $line =~ s/[ \t\r\n]//g;
165 15         54 $text .= $line . "\r\n";
166             }
167              
168 3 50       13 if ($self->signature->signheaderlist) {
169 0         0 $self->signature->headerlist(join(":", @headers_used));
170             }
171              
172             # delete trailing blank lines
173 3         8 foreach (reverse @{$self->{'BODY'}}) {
  3         19  
174 24 100       64 /[^\s\r\n]/ and # last non-blank line
175             last;
176 21         44 /^[\s\r\n]*$/ and
177 21 50       91 pop @{$self->{'BODY'}};
178             }
179              
180             # make sure there is a body before adding a seperator line
181 3 50       7 (scalar @{$self->{'BODY'}}) and
  3         99  
182             $text .= "\r\n";
183              
184 3         7 foreach my $lin (@{$self->{'BODY'}}) {
  3         10  
185 15         23 my $str = $lin;
186 15         47 $str =~ s/[\s\r\n]//g;
187 15         32 $text .= $str . "\r\n";
188             }
189              
190 3         21 return $text;
191             }
192              
193             sub simple {
194 3     3 0 6 my $self = shift;
195              
196 3         5 my $text;
197             my @headers_used;
198              
199              
200 3         8 foreach my $hdr (@{$self->head}) {
  3         14  
201 18 100 66     56 $hdr->signed or $self->signature->signing or
202             next;
203 15 50       36 $self->signature->wantheader($hdr->key) or
204             next;
205 15         60 push @headers_used, lc $hdr->key;
206             #$text .= $hdr->line . "\r\n";
207 15         45 my $lin = $hdr->line . "\n";
208 15         61 $lin =~ s/\n/\r\n/gs;
209 15         41 $text .= $lin;
210             }
211              
212 3 50       23 if ($self->signature->signheaderlist) {
213 0         0 $self->signature->headerlist(join(":", @headers_used));
214             }
215              
216             # delete trailing blank lines
217 3         27 foreach (reverse @{$self->{'BODY'}}) {
  3         13  
218 22 100       70 /[^\r\n]/ and # last non-blank line
219             last;
220 19         41 /^[\r\n]*$/ and
221 19 50       144 pop @{$self->{'BODY'}};
222             }
223              
224             # make sure there is a body before adding a seperator line
225 3 50       193 (scalar @{$self->{'BODY'}}) and
  3         16  
226             $text .= "\r\n";
227              
228 3         6 foreach my $lin (@{$self->{'BODY'}}) {
  3         9  
229 16         22 my $str = $lin;
230 16         23 $str =~ s/\r?\n\z//;
231 16         45 $text .= $str . "\r\n";
232             }
233              
234 3         28 return $text;
235             }
236              
237             sub sign {
238 0     0 0 0 my $self = shift;
239 0         0 my %prms = @_;
240              
241 0         0 my $sign = new Mail::DomainKeys::Signature(
242             Method => $prms{'Method'},
243             Domain => $self->senderdomain,
244             Selector => $prms{'Selector'},
245             SignHeaders => $prms{'SignHeaders'},
246             Signing => 1);
247              
248 0         0 $self->signature($sign);
249              
250 0   0     0 $sign->sign(Text => $self->canonify, Private => $prms{'Private'},
251             Sender => ($self->sender or $self->from));
252              
253              
254 0         0 return $sign;
255             }
256              
257             sub verify {
258 6     6 0 20 my $self = shift;
259              
260              
261 6 50       32 $self->signed or
262             return;
263              
264 6   33     21 return $self->signature->verify(Text => $self->canonify,
265             Sender => ($self->sender or $self->from),
266             SenderHdr => $self->sender, FromHdr => $self->from);
267             }
268              
269             sub body {
270 0     0 0 0 my $self = shift;
271              
272 0 0       0 (@_) and
273             $self->{'BODY'} = shift;
274              
275 0         0 $self->{'BODY'};
276             }
277              
278             sub from {
279 12     12 0 21 my $self = shift;
280              
281 12 50       44 (@_) and
282             $self->{'FROM'} = shift;
283              
284 12         99 $self->{'FROM'};
285             }
286              
287             sub head {
288 6     6 0 201 my $self = shift;
289              
290 6 50       106 (@_) and
291             $self->{'HEAD'} = shift;
292              
293 6         26 $self->{'HEAD'}
294             }
295              
296             sub sender {
297 12     12 0 22 my $self = shift;
298              
299 12 50       53 (@_) and
300             $self->{'SNDR'} = shift;
301              
302 12         244 $self->{'SNDR'};
303             }
304              
305             sub senderdomain {
306 0     0 0 0 my $self = shift;
307              
308 0 0       0 $self->sender and
309             return $self->sender->host;
310              
311 0 0       0 $self->from and
312             return $self->from->host;
313              
314 0         0 return;
315             }
316              
317             sub signature {
318 75     75 0 8121 my $self = shift;
319              
320 75 50       385 (@_) and
321             $self->{'SIGN'} = shift;
322              
323 75         428 $self->{'SIGN'};
324             }
325              
326             sub signed {
327 6     6 0 11 my $self = shift;
328              
329 6 50       86 $self->signature and
330             return 1;
331              
332 0           return;
333             }
334              
335             sub testing {
336 0     0 0   my $self = shift;
337              
338 0 0 0       $self->signed and $self->signature->testing and
339             return 1;
340              
341 0           return;
342             }
343              
344             1;