File Coverage

blib/lib/MIME/BodyMunger.pm
Criterion Covered Total %
statement 33 47 70.2
branch 8 24 33.3
condition 2 4 50.0
subroutine 7 9 77.7
pod 2 2 100.0
total 52 86 60.4


line stmt bran cond sub pod time code
1 2     2   14 use strict;
  2         4  
  2         57  
2 2     2   10 use warnings;
  2         3  
  2         94  
3             package MIME::BodyMunger 0.007;
4             # ABSTRACT: rewrite the content of text parts, minding charset
5              
6 2     2   11 use Carp ();
  2         4  
  2         30  
7 2     2   8 use Encode;
  2         4  
  2         151  
8 2     2   1005 use Variable::Magic ();
  2         2486  
  2         1101  
9              
10             #pod =head1 SYNOPSIS
11             #pod
12             #pod MIME::BodyMunger->rewrite_content(
13             #pod $mime_entity,
14             #pod sub {
15             #pod my ($body_ref) = @_;
16             #pod $$body_ref =~ s/zig/zag/;
17             #pod },
18             #pod );
19             #pod
20             #pod =head1 DESCRIPTION
21             #pod
22             #pod MIME::BodyMunger provides methods for rewriting text parts. These methods
23             #pod take care of character sets for you so that you can treat everything like text
24             #pod instead of worrying about content transfer encoding or character set encoding.
25             #pod
26             #pod At present, only MIME::Entity messages can be handled. Other types will be
27             #pod added in the future.
28             #pod
29             #pod =method rewrite_content
30             #pod
31             #pod MIME::BodyMunger->rewrite_content($message, sub { ... });
32             #pod
33             #pod This method uses the given callback to rewrite the content (body) of the
34             #pod message. It decodes the content (using Content-Transfer-Encoding and the
35             #pod Content-Type charset (or ISO-8859-1, if none is given)) and provides a
36             #pod reference to the character string to the coderef. If the content is altered,
37             #pod the body will be re-encoded into the original charset and the message will be
38             #pod updated.
39             #pod
40             #pod The callback is invoked like this:
41             #pod
42             #pod $code->(\$content, $message);
43             #pod
44             #pod In the future, there should be an option to re-encode to an alternate charset.
45             #pod
46             #pod =cut
47              
48             sub rewrite_content {
49 0     0 1 0 my ($self, $entity, $code) = @_;
50              
51 0 0       0 Carp::confess "rewrite_content called on non-text part"
52             unless $entity->effective_type =~ qr{\Atext/(?:html|plain)(?:$|;)}i;
53              
54 0   0     0 my $charset = $entity->head->mime_attr('content-type.charset')
55             || 'ISO-8859-1';
56              
57 0 0       0 $charset = 'MacRoman' if lc $charset eq 'macintosh';
58              
59 0 0       0 Carp::carp(qq{rewriting message in unknown charset "$charset"})
60             unless my $known_charset = Encode::find_encoding($charset);
61              
62 0         0 my $changed = 0;
63 0     0   0 my $got_set = Variable::Magic::wizard(set => sub { $changed = 1 });
  0         0  
64              
65 0 0       0 my $body = $known_charset
66             ? Encode::decode($charset, $entity->bodyhandle->as_string)
67             : $entity->bodyhandle->as_string;
68              
69 0         0 Variable::Magic::cast($body, $got_set);
70 0         0 $code->(\$body, $entity);
71              
72 0 0       0 if ($changed) {
73 0         0 my $io = $entity->open('w');
74 0 0       0 $io->print($known_charset ? Encode::encode($charset, $body) : $body);
75             }
76             }
77              
78             #pod =method rewrite_lines
79             #pod
80             #pod MIME::BodyMunger->rewrite_lines($message, sub { ... });
81             #pod
82             #pod This method behaves like C, but the callback is invoked once
83             #pod per line, like this:
84             #pod
85             #pod local $_ = $line;
86             #pod $code->($message);
87             #pod
88             #pod If any line is changed, the entire body will be reencoded and updated.
89             #pod
90             #pod =cut
91              
92             sub rewrite_lines {
93 8     8 1 23 my ($self, $entity, $code) = @_;
94              
95 8 50       21 Carp::confess "rewrite_lines called on non-text part"
96             unless $entity->effective_type =~ qr{\Atext/(?:html|plain)(?:$|;)}i;
97              
98 8   100     1169 my $charset = $entity->head->mime_attr('content-type.charset')
99             || 'ISO-8859-1';
100              
101 8 100       944 $charset = 'MacRoman' if lc $charset eq 'macintosh';
102              
103 8 50       30 Carp::carp(qq{rewriting message in unknown charset "$charset"})
104             unless my $known_charset = Encode::find_encoding($charset);
105              
106 8         4444 my $changed = 0;
107 8     26   49 my $got_set = Variable::Magic::wizard(set => sub { $changed = 1 });
  26         161  
108              
109 8         285 my @lines = $entity->bodyhandle->as_lines;
110              
111 8         2321 for my $line (@lines) {
112 13 50       46 local $_ = $known_charset ? Encode::decode($charset, $line) : $line;
113 13         671 Variable::Magic::cast($_, $got_set);
114 13         38 $code->(\$_, $entity);
115 13         37 Variable::Magic::dispell($_, $got_set);
116 13         31 $line = $_;
117             };
118              
119 8 100       31 if ($changed) {
120 7         28 my $io = $entity->open('w');
121 7 50       1155 $io->print($known_charset ? Encode::encode($charset, $_) : $_) for @lines;
122             }
123             }
124              
125             #pod =head1 THANKS
126             #pod
127             #pod Thanks to Pobox.com and Listbox.com, who sponsored the development of this
128             #pod module.
129             #pod
130             #pod Thanks to Brian Cassidy for writing some tests for the initial release.
131             #pod
132             #pod =cut
133              
134             1;
135              
136             __END__