File Coverage

blib/lib/Mail/MboxParser/Mail/Body.pm
Criterion Covered Total %
statement 53 130 40.7
branch 13 52 25.0
condition 8 26 30.7
subroutine 10 18 55.5
pod 5 6 83.3
total 89 232 38.3


line stmt bran cond sub pod time code
1             # Mail::MboxParser - object-oriented access to UNIX-mailboxes
2             # Body.pm - the (textual) body of an email
3             #
4             # Copyright (C) 2001 Tassilo v. Parseval
5             # This program is free software; you can redistribute it and/or
6             # modify it under the same terms as Perl itself.
7              
8             # Version: $Id: Body.pm,v 1.14 2002/02/21 09:06:14 parkerpine Exp $
9              
10             package Mail::MboxParser::Mail::Body;
11              
12             require 5.004;
13              
14 19     19   108 use Carp;
  19         40  
  19         1644  
15              
16 19     19   106 use strict;
  19         239  
  19         737  
17 19     19   93 use base qw(Exporter);
  19         31  
  19         1674  
18 19     19   102 use vars qw($VERSION @EXPORT @ISA $AUTOLOAD $_HAVE_NOT_URI_FIND);
  19         44  
  19         2893  
19             $VERSION = "0.15";
20             @EXPORT = qw();
21             @ISA = qw(Mail::MboxParser::Base Mail::MboxParser::Mail);
22              
23 19     19   44421 use overload '""' => sub { shift->as_string }, fallback => 1;
  19     4   27741  
  19         362  
  4         16  
24              
25             BEGIN {
26 19     19   2662 eval { require URI::Find; };
  19         10586  
27 19 50       141 if ($@) {
28 19         29426 $_HAVE_NOT_URI_FIND = 1;
29             }
30             }
31              
32             sub init(@) {
33 22     22 0 40 my ($self, $ent, $bound, $conf) = @_;
34 22         77 $self->{CONTENT} = $ent->body;
35 22         44957 $self->{BOUNDARY} = $bound; # the one in Content-type
36 22         129 $self->{ARGS} = $conf;
37              
38 22   50     129 $self->{ARGS}->{decode} ||= 'NEVER';
39              
40 22 50       116 $self->_make_decoder($ent->head->mime_encoding)
41             if $self->{ARGS}->{decode} =~ /BODY|ALL/;;
42 22         121 $self;
43             }
44              
45             sub _make_decoder {
46 0     0   0 my ($self, $enc) = @_;
47 0 0       0 if ($enc eq 'base64') {
48 0         0 require MIME::Base64;
49 0     0   0 return $self->{DECODER} = sub { MIME::Base64::decode_base64(shift) };
  0         0  
50             }
51 0 0       0 if ($enc eq 'quoted-printable') {
52 0         0 require MIME::QuotedPrint;
53 0     0   0 return $self->{DECODER} = sub { MIME::QuotedPrint::decode_qp(shift) };
  0         0  
54             }
55 0     0   0 $self->{DECODER} = sub { $_[0] };
  0         0  
56             }
57              
58             sub as_string {
59 4     4 1 9 my ($self, %args) = @_;
60 4         27 $self->reset_last;
61 4 50       15 return join "", $self->as_lines(strip_sig => 1) if $args{strip_sig};
62 4         10 my $decode = $self->{ARGS}->{decode};
63 4 50 33     25 if ($decode eq 'BODY' || $decode eq 'ALL') {
64 0         0 return join "", map { $self->{DECODER}->($_) } @{$self->{CONTENT}};
  0         0  
  0         0  
65             }
66 4         6 return join "", @{$self->{CONTENT}};
  4         38  
67             }
68            
69              
70             sub as_lines() {
71 0     0 1 0 my ($self, %args) = @_;
72 0         0 $self->reset_last;
73 0         0 my $decode = $self->{ARGS}->{decode};
74 0 0 0     0 if ($decode eq 'BODY' || $decode eq 'ALL') {
75 0         0 return map { $self->{DECODER}->($_) } @{$self->{CONTENT}};
  0         0  
  0         0  
76             }
77              
78 0 0       0 return @{$self->{CONTENT}} if ! $args{strip_sig};
  0         0  
79              
80 0         0 my @lines;
81 0         0 for (@{ $self->{CONTENT} }) {
  0         0  
82 0 0       0 last if /^--\040?[\r\n]?$/;
83 0         0 push @lines, $_;
84             }
85 0         0 return @lines;
86             }
87            
88            
89             sub signature() {
90 18     18 1 54 my $self = shift;
91 18         63 $self->reset_last;
92 18         36 my $decode = $self->{ARGS}->{decode};
93 18         24 my $bound = $self->{BOUNDARY};
94              
95 18         24 my @signature;
96 18         22 my $seperator = 0;
97 18         20 for (@{$self->{CONTENT}}) {
  18         43  
98              
99             # we are still outside the signature
100 560 100 100     1690 if (! /^--\040?[\r\n]?$/ && not $seperator) {
    100          
101 532         542 next;
102             }
103              
104             # we hit the signature delimiter (--)
105 6         7 elsif (not $seperator) { $seperator = 1; next }
  6         9  
106              
107 22         30 chomp;
108              
109             # we are inside signature: is line perhaps MIME-boundary?
110 22 0 33     44 last if $bound && /^--\Q$bound\E/ && $seperator;
      33        
111              
112             # none of the above => signature line
113 22         42 push @signature, $_;
114             }
115            
116 18 100       57 $self->{LAST_ERR} = "No signature found" if !@signature;
117 18 50 33     80 if ($decode eq 'BODY' || $decode eq 'ALL') {
118 0         0 $_ = $self->{DECODER}->($_) for @signature;
119             }
120 18 100       56 return @signature if $seperator;
121 12         36 return ();
122             }
123              
124             sub extract_urls(@) {
125 0     0 1   my ($self, %args) = @_;
126 0           $self->reset_last;
127              
128 0 0         $args{unique} = 0 if not exists $args{unique};
129              
130 0 0         if ($_HAVE_NOT_URI_FIND) {
131 0           carp <
132             You need the URI::Find module in order to use extract_urls.
133             EOW
134 0           return;
135             }
136             else {
137 0           my @uris; my %seen;
138              
139 0           for my $line (@{$self->{CONTENT}}) {
  0            
140 0           chomp $line;
141             URI::Find::find_uris($line, sub {
142 0     0     my (undef, $url) = @_;
143 0           $line =~ s/^\s+|\s+$//;
144 0 0         if (not $seen{$url}) {
145 0           push @uris, { url => $url, context => $line };
146             }
147 0 0         $seen{$url}++ if $args{unique};
148             }
149 0           );
150             }
151 0 0         $self->{LAST_ERR} = "No URLs found" if @uris == 0;
152              
153 0           return @uris;
154             }
155             }
156              
157             sub quotes() {
158 0     0 1   my $self = shift;
159 0           my $decode = $self->{ARGS}->{decode};
160 0           $self->reset_last;
161              
162 0           my %ret;
163 0           my $q = 0; # num of '>'
164 0           my $in = 0; # being inside a quote
165 0           my $last = 0; # num of quotes in last line
166              
167 0           for (@{$self->{CONTENT}}) {
  0            
168              
169 0 0 0       if ($decode eq 'ALL' || $decode eq 'BODY') {
170 0           $_ = $self->{DECODER}->($_);
171             }
172            
173             # count quotation signs
174 0           $q = 0;
175 0           my $t = "a" x length;
176 0           for my $c (unpack $t, $_) {
177 0 0         if ($c eq '>') { $q++ }
  0            
178 0 0 0       if ($c ne '>' && $c ne ' ') { last }
  0            
179             }
180              
181             # first: create a hash-element for level $q
182 0 0         if (! exists $ret{$q}) {
183 0           $ret{$q} = [];
184             }
185              
186             # if last line had the same level as current one:
187             # attach the line to the last one
188 0 0         if ($last == $q) {
189 0 0         if (@{$ret{$q}} == 0) { $ret{$q}->[$q] .= $_ }
  0            
  0            
190 0           else { $ret{$q}->[-1] .= $_ }
191             }
192             # if not:
193             # create a new array-element in the appropriate hash-element
194             else {
195 0           push @{$ret{$q}}, $_;
  0            
196             }
197 0           $last = $q;
198             }
199 0           return \%ret;
200             }
201              
202              
203             1;
204              
205             __END__