File Coverage

blib/lib/E/Mail/Acme.pm
Criterion Covered Total %
statement 205 257 79.7
branch 49 92 53.2
condition 6 13 46.1
subroutine 44 50 88.0
pod n/a
total 304 412 73.7


line stmt bran cond sub pod time code
1 3     3   88365 use strict;
  3         9  
  3         6015  
2             ## no critic warnings # let's be 5.00x compatible
3              
4             package E'Mail::Acme;
5              
6             $E'Mail::Acme::VERSION = 1555;
7              
8             my $CRLF = "\x0d\x0a";
9              
10             use overload '""' => sub {
11 8     8   1788 my ($self) = @_;
12              
13 8 50       16 if (@{$self->[ @$self ]}) {
  8         99  
14 0 0 0     0 unless (($self->{'content-type'}->[0]||'') =~ qr{^multipart/}) {
15 0 0       0 warn "content-type set, but not multipart on multipart message"
16             if $self->{'content-type'};
17 0         0 delete $self->{'content-type'};
18 0         0 $self->{'content-type'} = qq{multipart/mixed};
19             }
20              
21 0 0       0 unless ($self->{'content-type'}->[0] =~ qr{boundary="(?:[^"]+)"}) {
22 0         0 $self->{'content-type'}->[0] .= qq{; boundary="$self->[@$self+1]"};
23             }
24             }
25              
26             join(
27 8         25 $CRLF,
28             $self->{''},
29 8         122 join($CRLF, @{ $_[0] }, '')
30             . (
31 8         21 @{ $_[0]->[ @{ $_[0] } ] }
  0         0  
32 0         0 ? "$CRLF--$_[0]->[ @{ $_[0] } + 1 ]$CRLF"
33 8 50       42 . join("--$_[0]->[ @{ $_[0] } + 1 ]$CRLF", @{ $_[0]->[ @{ $_[0] } ] })
  0         0  
  0         0  
34 0         0 . "--$_[0]->[ @{ $_[0] } + 1 ]--$CRLF"
35             : ''
36             )
37             );
38 3     3   7204 };
  3         16298  
  3         37  
39              
40             use overload '&{}' => sub {
41 1     1   789 my ($self) = @_;
42             sub {
43 1     1   2 my ($program) = @_;
44 1 50 33     10 $program = 'sendmail' unless defined $program and length $program;
45              
46 1 50       6 if ($program !~ m{[/\\]}) {
47 0         0 path: for my $dir (split /:/, $ENV{PATH}) {
48 0 0       0 if ( -x "$dir/program" ) {
49 0         0 $program = "$dir/program";
50 0         0 last path;
51             }
52             }
53             }
54              
55 1 50       5 open $self, "| $program -t -oi -f $self->{from}->[0]" or die;
56 1 50       314 print $self $self or die;
57 1 50       11022 close $self or die;
58             }
59 3     3   940 };
  3         17  
  3         20  
  1         8  
60              
61             use overload '@{}' => sub {
62 55 100   55   106 tie @{*{$_[0]}}, q unless @{*{$_[0]}};#'
  19         23  
  19         105  
  55         57  
  55         342  
63 55         682 return \@{*{$_[0]}};
  55         56  
  55         345  
64 3     3   654 };
  3         11  
  3         26  
65              
66 3     3   159 use Scalar::Util qw(refaddr); # XXX
  3         6  
  3         614  
67              
68             use overload '%{}' => sub {
69 22 100   22   666 tie %{*{$_[0]}}, q unless %{*{$_[0]}};#'
  9         61  
  9         201  
  22         26  
  22         141  
70 22         55 return \%{*{$_[0]}};
  22         29  
  22         160  
71 3     3   15 };
  3         5  
  3         22  
72              
73 3     3   364 use overload fallback => 1;
  3         7  
  3         19  
74              
75             {
76             package E'Mail::Acme::HeaderFieldValues;
77             our @ISA = qw(E'Mail::Acme::Base);
78              
79             sub TIEARRAY {
80 23     23   43 my ($class, $name, $gutter) = @_;
81 23         108 bless [ $name, $gutter ] => $class;
82             }
83              
84             sub FETCHSIZE {
85 13     13   18 my ($self) = @_;
86            
87 13         28 my $gut = $self->[1]->();
88              
89 13         18 my $hits = 0;
90 13         34 i: for (my $i = 0; $i < $#$gut; $i += 2) {
91 27 50       66 lc $gut->[ $i ] eq lc $self->_idx(0) and $hits++;
92             }
93              
94 13         46 return $hits;
95             }
96              
97             sub EXISTS {
98 0     0   0 my ($self, $idx) = @_;
99 0         0 return $idx <= $self->FETCHSIZE;
100             }
101              
102             sub FETCH {
103 26     26   201 my ($self, $idx) = @_;
104              
105 26         62 my $gut = $self->_idx(1)->();
106              
107 26         87 i: for (my $i = 0; $i < $#$gut; $i += 2) {
108 53 50       129 lc $gut->[ $i ] eq lc $self->_idx(0) or next i;
109 53 100       11747 return $gut->[ $i + 1 ] if $idx == 0;
110 32         84 $idx--;
111             }
112              
113 5         18 return;
114             }
115              
116             sub DELETE {
117 0     0   0 my ($self, $idx) = @_;
118 0         0 $self->SPLICE($idx, 1);
119             }
120              
121             sub CLEAR {
122 1     1   2 my ($self) = @_;
123 1         4 $self->SPLICE(0, $self->FETCHSIZE);
124             }
125              
126 1     1   4 sub EXTEND { }
127              
128             sub SPLICE {
129 4     4   11 my ($self, $idx, $length, @new) = @_;
130              
131 4 100       13 if ($idx >= $self->FETCHSIZE) {
132 1         4 return $self->PUSH(@new);
133             }
134              
135 3         9 my $gut = $self->_idx(1)->();
136              
137 3         12 i: for (my $i = 0; $i < $#$gut; $i += 2) {
138 8 50       22 lc $gut->[ $i ] eq lc $self->_idx(0) or next;
139 8 100       20 if ($idx == 0) {
140 6 100       15 if ($length == 0) {
141 3         7 splice @$gut, $i, 0, map { $self->_idx(0), $_ } @new;
  1         3  
142 3         9 return;
143             }
144              
145 3 100       9 if (@new) {
146 2         6 $gut->[ $i ] = $self->_idx(0);
147 2         5 $gut->[ $i + 1 ] = shift @new;
148             } else {
149 1         4 splice @$gut, $i, 2;
150 1         2 $i -= 2;
151             }
152 3         10 $length--;
153             } else {
154 2         7 $idx--;
155             }
156             }
157              
158 0         0 $self->PUSH(@new);
159             }
160              
161             sub PUSH {
162 1     1   3 my ($self, @new) = @_;
163              
164 1         3 my $gut = $self->_idx(1)->();
165 1         8 push @$gut, $self->_idx(0), $_ for @new;
166             }
167              
168             sub STORE {
169 5     5   10 my ($self, $idx, $value) = @_;
170              
171 5         12 my $gut = $self->_idx(1)->();
172              
173 5 50       13 if ($idx >= $self->FETCHSIZE) {
174 5         11 push @$gut, $self->_idx(0), $value;
175 5         52 return $value;
176             }
177              
178 0         0 i: for (my $i = 0; $i < $#$gut; $i += 2) {
179 0 0       0 lc $gut->[ $i ] eq lc $self->_idx(0) or next;
180 0 0       0 if ($idx == 0) {
181 0         0 $gut->[ $i ] = $self->_idx(0);
182 0         0 $gut->[ $i + 1 ] = $value;
183 0         0 return $value;
184             }
185 0         0 $idx--;
186             }
187             }
188             }
189              
190             {
191             package E'Mail::Acme::Body;
192             our @ISA = qw(E'Mail::Acme::Base);
193              
194             my $i = 0;
195             sub TIEARRAY {
196 19     19   27 my ($class) = @_;
197              
198 19         155 my $self = {
199             lines => [],
200             parts => [],
201             bound => time . '-' . $$ . '-' . $i++ . $^T,
202             };
203 19         173 bless $self => $class;
204             }
205              
206             sub CLEAR {
207 1     1   3 my ($self) = @_;
208 1         3 $self->{lines} = [];
209 1         7 $self->{parts} = [];
210             }
211              
212 1     1   6 sub EXTEND { }
213              
214             sub FETCHSIZE {
215 131     131   211 my ($self) = @_;
216 131 50       562 warn "calling FETCHSIZE\n" if $::foo;
217 131         126 my $size = scalar @{ $self->{lines} };
  131         582  
218 131         450 return $size;
219             }
220              
221             sub FETCH {
222 49     49   104 my ($self, $idx) = @_;
223              
224 49 50       134 warn "calling FETCH $idx\n" if $::foo;
225 49         290 my $size = $self->FETCHSIZE;
226 49 100       193 if ($idx == $size) {
    50          
227 18         208 return $self->{parts};
228             } elsif ($idx == $size + 1) {
229 0         0 return $self->{bound};
230             }
231              
232 31         162 $self->{lines}[$idx];
233             }
234              
235             sub _values {
236 42     42   62 my ($self, $value) = @_;
237 42 100       83 return $value if ref $value;
238 40         183 my @values = split /\x0d\x0a|\x0a\x0d|\x0a|\x0d/, $value;
239             }
240              
241             sub STORE {
242 2     2   8 my ($self, $idx, @values) = @_;
243 2         7 $self->SPLICE($idx, 1,
244 2 50       5 map { my @v = $self->_values($_); @v ? @v : '' } @values
  2         15  
245             );
246             }
247              
248             sub SPLICE {
249 8     8   22 my ($self, $idx, $length, @values) = @_;
250              
251 8         10 my @to_splice;
252             my @parts;
253              
254 8 100       13 for my $v (map { my @v = $self->_values($_); @v ? @v : '' } @values) {
  23         46  
  23         77  
255             # The E:: is a concession to v5.6.x
256 23 100 33     31 if (eval { $v->isa("E'Mail::Acme") or $v->isa("E::Mail::Acme") }) {
  23 100       325  
    50          
257 1         4 push @parts, $v;
258 22         65 } elsif (ref $v eq 'ARRAY' or eval { overload::Method($v, '@{}') }) {
259 0 0       0 push @to_splice, map { my @v = $self->_values($_); @v ? @v : '' } @$v;
  0         0  
  0         0  
260             } else {
261 22         608 push @to_splice, $v;
262             }
263             }
264              
265 8         15 push @{ $self->{parts} }, @parts;
  8         19  
266 8         12 splice @{ $self->{lines} }, $idx, $length, @to_splice;
  8         54  
267             }
268              
269             sub PUSH {
270 5     5   187 my ($self, @values) = @_;
271              
272 17         55 $self->SPLICE(
273             $self->FETCHSIZE,
274             0,
275 5 100       17 map { my @v = $self->_values($_); @v ? @v : '' } @values
  17         68  
276             );
277             }
278             }
279              
280             {
281             package E'Mail::Acme::HeaderField;
282             our @ISA = qw(E'Mail::Acme::Base);
283              
284             sub TIESCALAR {
285 21     21   35 my ($class, $name, $gutter) = @_;
286 21         342 bless [ $name, $gutter ] => $class;
287             }
288              
289             sub _str_first {
290 0     0   0 my ($self) = @_;
291              
292 0         0 my $gut = $self->_idx(1)->();
293            
294 0         0 i: for (my $i = 0; $i < $#$gut; $i += 2) {
295 0 0       0 lc $gut->[ $i ] eq lc $self->_idx(0) and return $gut->[ $i + 1 ];
296             }
297             }
298              
299             sub _str_all {
300 1     1   170 my ($self) = @_;
301              
302 1         3 my $string = '';
303              
304 1         7 my $gut = $self->_idx(1)->();
305 1         6 i: for (my $i = 0; $i < $#$gut; $i += 2) {
306 1 50       5 lc $gut->[ $i ] eq lc $self->_idx(0) and
307             $string .= $gut->[$i] . ': ' . $gut->[$i + 1] . $CRLF;
308             }
309 1         10 return $string;
310             }
311              
312             sub _values_obj {
313 23     23   367 my ($self) = @_;
314              
315 23         64 tie my @values, "E'Mail::Acme::HeaderFieldValues",
316             $self->_idx(0),
317             $self->_idx(1),
318             ;
319              
320 23         125 \@values;
321             }
322              
323             use overload
324 3         20 '""' => '_str_all',
325             '@{}' => '_values_obj',
326 3     3   8255 fallback => 1;
  3         9  
327             }
328              
329             { # package E'Mail::Acme::Header
330             package E'Mail::Acme::Header;
331             @E'Mail::Acme::Header::ISA = qw(E'Mail::Acme::Base);
332              
333             sub TIEHASH {
334 9     9   21 my ($class, $e_mail) = @_;
335 9         56 bless {
336             obj => $e_mail,
337             hdr => []
338             } => $class;
339             }
340              
341             sub FETCH {
342 29     29   376 my ($self, $key) = @_;
343              
344 29 100       93 return $self->_str_all if $key eq '';
345              
346             return tie my $field, "E'Mail::Acme::HeaderField",
347             $key,
348 49     49   107 sub { $self->{hdr} }
349 21         131 ;
350             }
351              
352             sub EXISTS {
353 0     0   0 my ($self, $key) = @_;
354              
355 0         0 i: for (my $i = 0; $i < $#{$self->{hdr}}; $i += 2) {
  0         0  
356 0 0       0 return 1 if lc $self->{hdr}[$i] eq lc $key;
357             }
358 0         0 return;
359             }
360              
361             sub STORE {
362 14     14   35 my ($self, $key, $value) = @_;
363              
364 14 50       38 return $self->DELETE($key) if ! defined $value;
365              
366 14 100 66     51 if (
367             ref $value eq 'ARRAY'
368             or
369 12         39 eval { overload::Method($value, '@{}') }
370             ) {
371 2 50       8 $self->DELETE($key), return $self->FETCH($key) unless @$value;
372 2         15 $self->STORE($key, $_) for @$value;
373 2         10 return $self->FETCH($key);
374             }
375              
376 12         5012 push @{ $self->_attr('hdr') }, $key, $value;
  12         45  
377              
378 12         35 return $self->FETCH($key);
379             }
380              
381             sub DELETE {
382 0     0   0 my ($self, $key) = @_;
383              
384 0 0       0 return unless $#{ $self->{hdr} } >= 1;
  0         0  
385              
386 0         0 i: for (my $i = $#{$self->{hdr}} - 1; $i >= 0; $i -= 2) {
  0         0  
387 0 0       0 lc $self->{hdr}[$i] eq lc $key or next i;
388 0         0 splice @{ $self->{hdr} }, $i, 2;
  0         0  
389             }
390             }
391              
392             sub FIRSTKEY {
393 13     13   115 my ($self) = @_;
394              
395 13         407 delete $self->{iter};
396 13         37 $self->{iter} = { };
397              
398 13         28 i: for (my $i = 0; $i < $#{$self->{hdr}}; $i += 2) {
  43         128  
399 30   100     174 my $v = $self->{iter}{ lc $self->{hdr}[$i] } ||= [];
400 30         142 push @$v, $self->{hdr}[ $i + 1 ];
401             }
402              
403 13         20 return each %{ $self->{iter} };
  13         63  
404             }
405              
406             sub NEXTKEY {
407 0     0   0 my ($self, $prev) = @_;
408              
409 0 0       0 die "error during e'mail header transnaviation" unless $self->{iter};
410 0         0 return each %{ $self->{iter} };
  0         0  
411             }
412              
413             sub _str_all {
414 8     8   14 my ($self) = @_;
415              
416 8         20 my $string = '';
417 8         16 i: for (my $i = 0; $i < $#{$self->{hdr}}; $i += 2) {
  18         442  
418 10         49 $string .= $self->{hdr}[$i] . ': ' . $self->{hdr}[$i + 1] . $CRLF;
419             }
420 8         30 return $string;
421             }
422              
423             use overload
424 3         22 fallback => 1,
425             '""' => '_str_all',
426 3     3   4875 ;
  3         7  
427             }
428              
429             { # Utility constructor class
430             package E'Mail;
431             sub Acme {
432 9     9   33786 my $guts = {};
433              
434 3     3   4245 use Symbol;
  3         5434  
  3         1803  
435 9         34 my $self = Symbol::gensym;
436 9         272 bless $self => "E'Mail::Acme";
437             };
438             }
439              
440             {
441             package E'Mail::Acme::Base;
442             sub _idx {
443 179     179   230 my ($self, $idx) = @_;
444 179         328 my $orig_class = ref $self;
445 179         430 bless $self => "E'Mail::Acme::HoldingPattern";
446 179         249 my $value = $self->[$idx];
447 179         364 bless $self => $orig_class;
448 179         737 return $value;
449             }
450              
451             sub _attr {
452 12     12   22 my ($self, $key) = @_;
453 12         65 my $orig_class = ref $self;
454 12         43 bless $self => "E'Mail::Acme::HoldingPattern";
455 12         26 my $value = $self->{$key};
456 12         26 bless $self => $orig_class;
457 12         43 return $value;
458             }
459             }
460              
461             E'Mail::Acme;#'
462              
463             __END__