File Coverage

blib/lib/Mail/Message/Attachment/Stripper.pm
Criterion Covered Total %
statement 52 54 96.3
branch 16 24 66.6
condition 3 5 60.0
subroutine 13 13 100.0
pod 3 3 100.0
total 87 99 87.8


line stmt bran cond sub pod time code
1             package Mail::Message::Attachment::Stripper;
2              
3 1     1   5346 use strict;
  1         3  
  1         152  
4 1     1   8 use warnings;
  1         2  
  1         64  
5              
6             our $VERSION = '1.01';
7              
8 1     1   17 use Carp;
  1         3  
  1         3879  
9              
10             =head1 NAME
11              
12             Mail::Message::Attachment::Stripper - Strip the attachments from a mail
13              
14             =head1 SYNOPSIS
15              
16             my $stripper = Mail::Message::Attachment::Stripper->new($mail);
17              
18             my Mail::Message $msg = $stripper->message;
19             my @attachments = $stripper->attachments;
20              
21             =head1 DESCRIPTION
22              
23             Given a Mail::Message object, detach all attachments from the
24             message. These are then available separately.
25              
26             =head1 METHODS
27              
28             =head2 new
29              
30             my $stripper = Mail::Message::Attachment::Stripper->new($mail);
31              
32             This should be instantiated with a Mail::Message object.
33              
34             =head2 message
35              
36             my Mail::Message $msg = $stripper->message;
37              
38             This returns the message with all the attachments detached. This will
39             alter both the body and the header of the message.
40              
41             =head2 attachments
42              
43             my @attachments = $stripper->attachments;
44              
45             This returns a list of all the attachments we found in the message,
46             as a hash of { filename, content_type, payload }.
47              
48             =cut
49              
50             sub new {
51 2     2 1 1018408 my ($class, $msg) = @_;
52 2 50       8 croak "Need a message" unless eval { $msg->isa("Mail::Message") };
  2         18  
53 2         19 bless { _msg => $msg }, $class;
54             }
55              
56             sub message {
57 2     2 1 6 my $self = shift;
58 2 50       16 $self->_detach_all unless exists $self->{_atts};
59 2         50 return $self->{_msg};
60             }
61              
62             sub attachments {
63 3     3 1 779 my $self = shift;
64 3 50       19 $self->_detach_all unless exists $self->{_atts};
65 3 50       12 return $self->{_atts} ? @{ $self->{_atts} } : ();
  3         18  
66             }
67              
68             sub _detach_all {
69 2     2   5 my $self = shift;
70 2         4 my $mm = $self->{_msg};
71              
72 2         8 $self->{_atts} = [];
73 2         7 $self->{_body} = [];
74              
75 2         8 $self->_handle_part($mm);
76 2         748 $mm->body(Mail::Message::Body->new(data => $self->{_body}));
77 2         20335 $self;
78             }
79              
80             sub _handle_part {
81 2     2   5 my ($self, $mm) = @_;
82              
83             # According to Mail::Message docs, this ternary is not required. However,
84             # $Mail_Message->parts calls $Mail_Message->deleted which is
85             # unimplemented
86 2 50       10 foreach my $part ($mm->isMultipart ? $mm->parts : $mm) {
87 6 100       326723 if ($self->_is_inline_text($part)) {
    50          
88 2         84 $self->_gather_body($part);
89             } elsif ($self->_should_recurse($part)) {
90 0         0 $self->_handle_part($part);
91             } else {
92 4         37 $self->_gather_att($part);
93             }
94             }
95             }
96              
97             sub _gather_body { # Gen 25:8
98 2     2   6 my ($self, $part) = @_;
99 2         4 push @{ $self->{_body} }, $part->decoded->lines;
  2         19  
100             }
101              
102             sub _gather_att {
103 4     4   8 my ($self, $part) = @_;
104              
105             # stringification is required for safety
106 4         9 push @{ $self->{_atts} },
  4         75  
107             {
108             content_type => $part->body->mimeType . "",
109             payload => $part->decoded . "",
110             filename => $self->_filename_for($part),
111             };
112             }
113              
114             sub _should_recurse {
115 4     4   105 my ($self, $part) = @_;
116 4 100       24 return 0 if lc($part->body->mimeType) eq "message/rfc822";
117 3 50       67 return 1 if $part->isMultipart;
118 3         305 return 0;
119             }
120              
121             sub _is_inline_text {
122 6     6   21 my ($self, $part) = @_;
123 6 100       38 if ($part->body->mimeType eq "text/plain") {
124 3         533 my $disp = $part->head->get("Content-Disposition");
125 3 100 66     72 return 1 if $disp && $disp =~ /inline/;
126 1 50       34 return 0 if $self->_filename_for($part);
127 0         0 return 1;
128             }
129 3         5595 return 0;
130             }
131              
132             sub _filename_for {
133 5     5   150417 my ($self, $part) = @_;
134 5         36 my $disp = $part->head->get("Content-Disposition");
135 5         119 my $type = $part->head->get("Content-Type");
136 5   50     108 return ($disp && $disp->attribute("filename"))
137             || ($type && $type->attribute("name"))
138             || "";
139             }
140              
141             =head1 BUGS and QUERIES
142              
143             Please direct all correspondence regarding this module to:
144             bug-Mail-Message-Attachment-Stripper@rt.cpan.org
145              
146             =head1 COPYRIGHT AND LICENSE
147              
148             Copyright (C) 2002-2005 Kasei
149              
150             This program is free software; you can redistribute it and/or modify it under
151             the terms of the GNU General Public License; either version 2 of the License,
152             or (at your option) any later version.
153              
154             This program is distributed in the hope that it will be useful, but WITHOUT
155             ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
156             FOR A PARTICULAR PURPOSE.
157              
158             =cut
159              
160              
161             1;