File Coverage

blib/lib/Matts/Message.pm
Criterion Covered Total %
statement 6 152 3.9
branch 0 40 0.0
condition 0 4 0.0
subroutine 2 24 8.3
pod 0 19 0.0
total 8 239 3.3


line stmt bran cond sub pod time code
1              
2             package Matts::Message;
3 1     1   5 use strict;
  1         1  
  1         42  
4 1     1   932 use MIME::Base64 qw(encode_base64);
  1         875  
  1         1661  
5              
6             sub new {
7 0     0 0   bless {
8             encodings => [],
9             bin_headers => {},
10             headers => {},
11             body_parts => [],
12             attachments => [],
13             raw => '',
14             }, shift;
15             }
16              
17             sub raw_headers {
18 0     0 0   my $self = shift;
19 0           return $self->{raw};
20             }
21              
22             sub header {
23 0     0 0   my $self = shift;
24 0           my $k = shift;
25 0           my $key = lc($k);
26 0 0         if (@_) {
27 0           $self->{raw} .= "$k: @_";
28 0 0         if (exists $self->{headers}{$key}) {
29 0           push @{$self->{headers}{$key}}, @_;
  0            
30             }
31             else {
32 0           $self->{headers}{$key} = [@_];
33             }
34 0           return $self->{headers}{$key}[-1];
35             }
36            
37 0 0         if (wantarray) {
38 0 0         return unless exists $self->{headers}{$key};
39 0           return @{$self->{headers}{$key}};
  0            
40             }
41             else {
42 0 0         return '' unless exists $self->{headers}{$key};
43 0           return $self->{headers}{$key}[-1];
44             }
45             }
46              
47             sub binary_header {
48 0     0 0   my $self = shift;
49 0           my $key = lc(shift);
50 0 0         if (@_) {
51 0 0         if (exists $self->{bin_headers}{$key}) {
52 0           push @{$self->{bin_headers}{$key}}, @_;
  0            
53             }
54             else {
55 0           $self->{bin_headers}{$key} = [@_];
56             }
57 0           return $self->{bin_headers}{$key}[-1];
58             }
59            
60 0 0         if (wantarray) {
61 0 0         return unless exists $self->{bin_headers}{$key};
62 0           return @{$self->{bin_headers}{$key}};
  0            
63             }
64             else {
65 0 0         return '' unless exists $self->{bin_headers}{$key};
66 0           return $self->{bin_headers}{$key}[-1];
67             }
68             }
69              
70             sub header_del {
71 0     0 0   my $self = shift;
72 0           my $header = lc(shift);
73 0           $self->{raw} =~ s/^$header:.*?^(\S)/$1/ism;
74 0           delete $self->{headers}{$header};
75             }
76              
77             sub headers {
78 0     0 0   my $self = shift;
79 0           return keys %{$self->{headers}};
  0            
80             }
81              
82             sub binary_headers {
83 0     0 0   my $self = shift;
84 0           return keys %{$self->{bin_headers}};
  0            
85             }
86              
87             sub add_body_part {
88 0     0 0   my $self = shift;
89 0           my ($type, $fh) = @_;
90 0   0       $type ||= 'text/plain';
91 0           my $enc = 'null';
92 0 0         if ($type =~ s/;(.*$)//) { # strip everything after first semi-colon
93 0           my $cs = $1;
94 0 0         if ($cs =~ /charset="?([\w-]+)/) {
95 0           $enc = $1;
96             }
97             }
98 0           $type =~ s/[^a-zA-Z\/]//g; # strip inappropriate chars
99 0           push @{ $self->{encodings} }, $enc;
  0            
100 0           push @{ $self->{body_parts} }, [ $type => $fh ];
  0            
101             }
102              
103             sub add_attachment {
104 0     0 0   my $self = shift;
105 0           my ($type, $fh, $name) = @_;
106 0           push @{ $self->{attachments} }, {
  0            
107             filename => $name,
108             type => $type,
109             fh => $fh,
110             };
111             }
112              
113             sub body {
114 0     0 0   my $self = shift;
115 0           my $type = shift;
116 0 0         return unless @{ $self->{body_parts} };
  0            
117 0 0         if ($type) {
118             # warn("body has ", scalar(@{ $self->{body_parts} }), " [$type]\n");
119 0           foreach my $body ( @{ $self->{body_parts} } ) {
  0            
120             # warn("type: $body->[0]\n");
121 0 0         if (lc($type) eq lc($body->[0])) {
122 0 0         return wantarray ? @$body : $body->[1];
123             }
124             }
125             }
126            
127 0 0         return wantarray ? @{ $self->{body_parts}[0] } : $self->{body_parts}[0][1];
  0            
128             }
129              
130             sub bodies {
131 0     0 0   my $self = shift;
132 0           my @ret;
133 0           foreach my $body ( @{ $self->{body_parts} } ) {
  0            
134 0           push @ret, lc($body->[0]), $body->[1];
135             }
136 0           return @ret;
137             }
138              
139             sub body_enc {
140 0     0 0   my $self = shift;
141 0           my ($id) = @_;
142 0           return $self->{encodings}[$id];
143             }
144              
145             sub attachment {
146 0     0 0   my $self = shift;
147 0           return $self->{attachments}[shift];
148             }
149              
150             sub attachments {
151 0     0 0   my $self = shift;
152 0           return @{ $self->{attachments} };
  0            
153             }
154              
155             sub num_attachments {
156 0     0 0   my $self = shift;
157 0           return scalar @{ $self->{attachments} };
  0            
158             }
159              
160             sub to_string {
161 0     0 0   my $self = shift;
162            
163 0           my $output = '';
164 0     0     my $sub = sub { $output .= join('', @_) };
  0            
165 0           $self->_walk_tree($sub);
166 0           return $output;
167             }
168              
169             sub size {
170 0     0 0   my $self = shift;
171 0 0         @_ and $self->{size} = shift;
172 0           $self->{size};
173             }
174              
175             sub mtime {
176 0     0 0   my $self = shift;
177 0 0         @_ and $self->{mtime} = shift;
178 0           $self->{mtime};
179             }
180              
181             sub dump {
182 0     0 0   my $self = shift;
183 0           my ($fh) = @_;
184 0   0       $fh ||= \*STDOUT;
185            
186 0     0     my $sub = sub { print $fh @_ };
  0            
187 0           $self->_walk_tree($sub);
188             }
189              
190             sub _walk_tree {
191 0     0     my $msg = shift;
192 0           my ($sub) = @_;
193            
194             # Munge the whole thing into a big old multipart/mixed thingy.
195 0           $msg->header_del('content-type');
196 0           my $boundary = "----=_NextPart_000_" . $$ . time;
197 0           $msg->header('Content-Type', "multipart/mixed; boundary=\"$boundary\"\n");
198              
199 0           $sub->($msg->raw_headers);
200              
201             # Output Received headers first.
202             #foreach my $value ($msg->header('Received')) {
203             # $sub->("Received: $value\n");
204             #}
205              
206             # Output remaining headers in random order
207             #foreach my $header ($msg->headers) {
208             # next if lc($header) eq 'received';
209             #foreach my $value ($msg->header($header)) {
210             # $header =~ s/(^|-)(\w)/$1 . uc($2)/eg;
211             #$sub->("$header: $value\n");
212             #}
213             #}
214 0           $sub->("\n");
215              
216 0           $sub->("This is a dump of a parsed message. Ignore this bit.\n\n");
217              
218 0           $sub->("--$boundary\n");
219              
220 0           my $body_boundary = "----=_NextPart_111_" . $$ . time;
221 0           $sub->("Content-Type: multipart/alternate; boundary=\"$body_boundary\"\n");
222 0           $sub->("\n");
223 0           my @body_parts = $msg->bodies;
224              
225 0           while (@body_parts) {
226 0           my ($type, $fh) = splice(@body_parts, 0, 2);
227 0           $sub->("--$body_boundary\n");
228 0           $sub->("Content-Type: $type\n");
229 0 0         if ($type !~ /^text\//) {
230 0           $sub->("Content-Transfer-Encoding: base64\n");
231 0           $sub->("\n");
232 0           local $/;
233 0           $sub->(encode_base64(<$fh>));
234 0           $sub->("\n");
235             }
236             else {
237 0           $sub->("Content-Transfer-Encoding: 8bit\n");
238 0           $sub->("\n");
239 0           local $/;
240 0           $sub->(<$fh>);
241 0           $sub->("\n");
242             }
243             }
244 0           $sub->("--$body_boundary--\n\n");
245            
246 0           foreach my $att ($msg->attachments) {
247 0           $sub->("--$boundary\n");
248 0           $sub->("Content-Type: $att->{type}\n");
249 0           $sub->("Content-Disposition: attachment; filename=$att->{filename}\n");
250 0           $sub->("Content-Transfer-Encoding: base64\n");
251 0           $sub->("\n");
252              
253 0           my $fh = $att->{fh};
254 0           local $/;
255 0           $sub->(encode_base64(<$fh>));
256 0           $sub->("\n");
257             }
258              
259 0           $sub->("--$boundary--\n");
260             }
261              
262             1;
263             __END__