File Coverage

blib/lib/Mail/MboxParser/Mail.pm
Criterion Covered Total %
statement 205 331 61.9
branch 76 156 48.7
condition 10 53 18.8
subroutine 27 38 71.0
pod 19 21 90.4
total 337 599 56.2


line stmt bran cond sub pod time code
1             # Mail::MboxParser - object-oriented access to UNIX-mailboxes
2             #
3             # Copyright (C) 2001 Tassilo v. Parseval
4             # This program is free software; you can redistribute it and/or
5             # modify it under the same terms as Perl itself.
6              
7             # Version: $Id: Mail.pm,v 1.53 2005/11/23 09:30:12 parkerpine Exp $
8              
9             package Mail::MboxParser::Mail;
10              
11             require 5.004;
12              
13 19     19   25537 use base qw(Exporter Mail::MboxParser::Base);
  19         33  
  19         4074  
14              
15             # ----------------------------------------------------------------
16              
17             =head1 NAME
18              
19             Mail::MboxParser::Mail - Provide mail-objects and methods upon
20              
21             =head1 SYNOPSIS
22              
23             See L for an outline on usage. Examples however are also
24             provided in this manpage further below.
25              
26             =head1 DESCRIPTION
27              
28             Mail::MboxParser::Mail objects are usually not created directly though, in
29             theory, they could be. A description of the provided methods can be found in
30             L.
31              
32             However, go on reading if you want to use methods from MIME::Entity and learn
33             about overloading.
34              
35             =head1 METHODS
36              
37             =cut
38              
39 19     19   21857 use Mail::MboxParser::Mail::Body;
  19         55  
  19         1303  
40 19     19   15526 use Mail::MboxParser::Mail::Convertable;
  19         52  
  19         1268  
41 19     19   103 use Carp;
  19         32  
  19         1271  
42              
43 19     19   241 use strict;
  19         34  
  19         624  
44 19     19   87 use vars qw($VERSION @EXPORT $AUTOLOAD $NL);
  19         34  
  19         2188  
45             $VERSION = "0.45";
46             @EXPORT = qw();
47              
48             # we'll use it to store the MIME::Parser
49             my $Parser;
50              
51 19     19   105 use overload '""' => \&as_string, fallback => 1;
  19         32  
  19         205  
52              
53 19     19   3925 BEGIN { $Mail::MboxParser::Mail::NL = "\n" }
54              
55             use constant
56 19   50 19   123 HAVE_ENCODE => eval { require Encode; 1 } || 0;
  19         36  
  19         37  
57             use constant
58 19   50 19   205 HAVE_MIMEWORDS => eval { require MIME::Words; 1 } || 0;
  19         45  
  19         71  
59              
60             # ----------------------------------------------------------------
61              
62             =over 4
63              
64             =item B
65              
66             This is usually not called directly but instead by C. You could
67             however create a mail-object manually providing the header and body each as
68             either one string or as an array-ref representing the lines.
69              
70             Here is a common scenario: Retrieving mails from a remote POP-server using
71             Mail::POP3Client and directly feeding each mail to
72             Cnew>:
73              
74             use Mail::POP3Client;
75             use Mail::MboxParser::Mail;
76            
77             my $pop = new Mail::POP3Client (...);
78              
79             for my $i (1 .. $pop->Count) {
80             my $msg = Mail::MboxParser::Mail->new( [ $pop->Head($i) ],
81             [ $pop->Body($i) ] );
82             $msg->store_all_attachments( path => '/home/user/dump' );
83             }
84              
85             The above effectively behaves like an attachment-only retriever.
86              
87             =back
88              
89             =cut
90              
91             sub init (@) {
92 151     151 0 351 my ($self, @args) = @_;
93 151         255 my ($header, $body, $conf) = @args;
94              
95 151 100       2410 $self->{HEADER} = ref $header ? $header : [ split /$NL/, $header ];
96 151         420 $self->{HEADER_HASH} = \&_split_header;
97 151 100       547 $self->{BODY} = ref $body ? $body : [ split /$NL/, $body ];
98 151         522 $self->{TOP_ENTITY} = 0;
99 151         285 $self->{ARGS} = $conf;
100              
101 151 50       551 if (! $self->{ARGS}->{uudecode} ) {
102             # set default for 'uudecode' option
103 151         334 $self->{ARGS}->{uudecode} = 0;
104             }
105              
106             # make sure line-endings are ok if called directly
107 151 100       521 if (caller(1) ne 'Mail::MboxParser') {
108 4         9 $self->{ARGS}->{join_string} = '';
109 4         6 for (@{ $self->{HEADER} }, @{ $self->{BODY} }) {
  4         7  
  4         10  
110 260 50       490 $_ .= "\n" unless /.*\n$/;
111             }
112 4 50       25 push @{ $self->{HEADER} }, "\n" if $self->{HEADER}->[-1] ne "\n";
  4         12  
113             }
114 151         1036 $self;
115             }
116              
117             # ----------------------------------------------------------------
118              
119             =over 4
120              
121             =item B
122              
123             Returns the mail-header as a hash-ref with header-fields as keys. All keys are
124             turned to lower-case, so C<$header{Subject}> has to be written as
125             C<$header{subject}>.
126              
127             If a header-field occurs more than once in the header, the value of the key is
128             an array_ref. Example:
129              
130             my $field = $msg->header->{field};
131             print $field->[0]; # first occurance of 'field'
132             print $field->[1]; # second one
133             ...
134              
135             =back
136              
137             =cut
138              
139             sub header() {
140 56     56 1 107 my $self = shift;
141 56   100     398 my $decode = $self->{ARGS}->{decode} || 'NEVER';
142 56         319 $self->reset_last;
143              
144 56         278 return $self->{HEADER_HASH}->($self, $self->{HEADER}, $decode);
145             }
146              
147             # ----------------------------------------------------------------
148              
149             =over 4
150              
151             =item B
152              
153             Returns the "From "-line of the message.
154              
155             =back
156              
157             =cut
158              
159             sub from_line() {
160 6     6 1 11 my $self = shift;
161 6         38 $self->reset_last;
162            
163 6 50       34 $self->{HEADER_HASH}->($self, $self->{HEADER}, 'NEVER')
164             if !exists $self->{FROM};
165            
166 6 50       34 if (! exists $self->{FROM}) {
167 0         0 $self->{LAST_ERR} = "Message did not contain a From-line";
168 0         0 return;
169             }
170 6         32 $self->{FROM};
171             }
172              
173             # ----------------------------------------------------------------
174              
175             =over 4
176              
177             =item B
178              
179             This method returns the "Received: "-lines of the message as a list.
180              
181             =back
182              
183             =cut
184              
185             sub trace () {
186 6     6 1 12 my $self = shift;
187 6         19 $self->reset_last;
188              
189 6 50       20 $self->{HEADER_HASH}->($self, $self->{HEADER}, 'NEVER')
190             if ! exists $self->{TRACE};
191              
192 6 50       18 if (! exists $self->{TRACE}) {
193 0         0 $self->{LAST_ERR} = "Message did not contain any Received-lines";
194 0         0 return;
195             }
196              
197 6         8 @{ $self->{TRACE} };
  6         29  
198             }
199              
200             # ----------------------------------------------------------------
201              
202             =over 4
203              
204             =item B
205              
206             =item B
207              
208             Returns a Mail::MboxParser::Mail::Body object. For methods upon that see
209             further below. When called with the argument n, the n-th body of the message is
210             retrieved. That is, the body of the n-th entity.
211              
212             Sets C<$mail-Eerror> if something went wrong.
213              
214             =back
215              
216             =cut
217              
218             sub body(;$) {
219 22     22 1 40 my ($self, $num) = @_;
220 22         78 $self->reset_last;
221              
222 22 50 66     104 if (defined $num && $num >= $self->num_entities) {
223 0         0 $self->{LAST_ERR} = "No such body";
224 0         0 return;
225             }
226              
227             # body needs the "Content-type: ... boundary=" stuff
228             # in order to decide which lines are part of signature and
229             # which lines are not (ie denote a MIME-part)
230 22         29 my $bound;
231              
232             # particular entity desired?
233             # we need to read the header of this entity then :-(
234 22 100       50 if (defined $num) {
235 18         37 my $ent = $self->get_entities($num);
236 18 100       46 if ($bound = $ent->head->get('content-type')) {
237 6         225 $bound =~ /boundary="(.*)"/; $bound = $1;
  6         10  
238             }
239 18         443 return Mail::MboxParser::Mail::Body->new($ent, $bound, $self->{ARGS});
240             }
241            
242             # else
243 4 50       17 if ($bound = $self->header->{'content-type'}) {
244 4         11 $bound =~ /boundary="(.*)"/; $bound = $1;
  4         10  
245             }
246 4 50       39 return ref $self->{TOP_ENTITY} eq 'MIME::Entity'
247             ? Mail::MboxParser::Mail::Body->new($self->{TOP_ENTITY}, $bound, $self->{ARGS})
248             : Mail::MboxParser::Mail::Body->new(scalar $self->get_entities(0), $bound, $self->{ARGS});
249             }
250              
251             # ----------------------------------------------------------------
252              
253             =over 4
254              
255             =item B
256              
257             This will return an index number that represents what Mail::MboxParser::Mail
258             considers to be the actual (main)-body of an email. This is useful if you don't
259             know about the structure of a message but want to retrieve the message's
260             signature for instance:
261              
262             $signature = $msg->body($msg->find_body)->signature;
263              
264             Changes are good that find_body does what it is supposed to do.
265              
266             =back
267              
268             =cut
269              
270             sub find_body() {
271 36     36 1 16165 my $self = shift;
272 36         98 $self->{LAST_ERR} = "Could not find a suitable body at all";
273 36         52 my $num = -1;
274 36         245 for my $part ($self->parts_DFS) {
275 40         1038 $num++;
276 40 100       112 if ($part->effective_type eq 'text/plain') {
277 36         4263 $self->reset_last; last;
  36         64  
278             }
279             }
280 36         183 return $num;
281             }
282              
283             # ----------------------------------------------------------------
284              
285             =over 4
286              
287             =item B
288              
289             Returns a Mail::MboxParser::Mail::Convertable object. For details on what you
290             can do with it, read L.
291              
292             =back
293              
294             =cut
295              
296             sub make_convertable(@) {
297 0     0 1 0 my $self = shift;
298 0 0       0 return ref $self->{TOP_ENTITY} eq 'MIME::Entity'
299             ? Mail::MboxParser::Mail::Convertable->new($self->{TOP_ENTITY})
300             : Mail::MboxParser::Mail::Convertable->new($self->get_entities(0));
301             }
302              
303             # ----------------------------------------------------------------
304              
305             =over 4
306              
307             =item B
308              
309             Returns the specified raw field from the message header, that is: the fieldname
310             is not stripped off nor is any decoding done. Returns multiple lines as needed
311             if the field is "Received" or another multi-line field. Not case sensitive.
312              
313             C always returns one string regardless of how many times the field
314             occured in the header. Multiple occurances are separated by a newline and
315             multiple whitespaces squeezed to one. That means you can process each occurance
316             of the field thusly:
317              
318             for my $field ( split /\n/, $msg->get_field('received') ) {
319             # do something with $field
320             }
321              
322             Sets C<$mail-Eerror> if the field was not found in which case
323             C returns C.
324              
325             =back
326              
327             =cut
328              
329             sub get_field($) {
330 4     4 1 10 my ($self, $fieldname) = @_;
331 4         14 $self->reset_last;
332              
333 4         37 my @headerlines = ref $self->{HEADER}
334 4 50       18 ? @{$self->{HEADER}}
335             : split /$NL/, $self->{HEADER};
336 4         40 chomp @headerlines;
337              
338 4         7 my ($ret, $inretfield);
339 4         11 foreach my $bit (@headerlines) {
340 100 100       504 if ($bit =~ /^\s/) {
    100          
341 42 100       92 if ($inretfield) {
342 2         11 $bit =~ s/\s+/ /g;
343 2         18 $ret .= $bit;
344             }
345             }
346             elsif ($bit =~ /^$fieldname/i) {
347 4         26 $bit =~ s/\s+/ /g;
348 4         7 $inretfield++;
349 4 50       12 if (defined $ret) { $ret .= "\n" . $bit }
  0         0  
350 4         10 else { $ret .= $bit }
351             }
352 54         103 else { $inretfield = 0; }
353             }
354            
355 4 50       13 $self->{LAST_ERR} = "No such field" if not $ret;
356 4         27 return $ret;
357             }
358            
359             # ----------------------------------------------------------------
360              
361             =over 4
362              
363             =item B
364              
365             Returns a hash-ref with the two fields 'name' and 'email'. Returns C if
366             empty. The name-field does not necessarily contain a value either. Example:
367            
368             print $mail->from->{email};
369              
370             On behalf of suggestions I received from users, from() tries to be smart when
371             'name'is empty and 'email' has the form 'first.name@host.com'. In this case,
372             'name' is set to "First Name".
373              
374             =back
375              
376             =cut
377              
378             sub from() {
379 0     0 1 0 my $self = shift;
380 0         0 $self->reset_last;
381              
382 0         0 my $from = $self->header->{from};
383 0         0 my ($name, $email) = split /\s\
384 0 0       0 $email =~ s/\>$//g unless not $email;
385 0 0 0     0 if ($name && ! $email) {
386 0         0 $email = $name;
387 0         0 $name = "";
388 0 0       0 $name = ucfirst($1) . " " . ucfirst($2) if $email =~ /^(.*?)\.(.*)@/;
389             }
390 0         0 return {(name => $name, email => $email)};
391             }
392              
393             # ----------------------------------------------------------------
394              
395             =over 4
396              
397             =item B
398              
399             Returns an array of hash-references of all to-fields in the mail-header. Fields
400             are the same as those of C<$mail-Efrom>. Example:
401              
402             for my $recipient ($mail->to) {
403             print $recipient->{name} || "", "\n";
404             print $recipient->{email};
405             }
406              
407             The same 'name'-smartness applies here as described under C.
408              
409             =back
410              
411             =cut
412              
413 0     0 1 0 sub to() { shift->_recipients("to") }
414              
415             # ----------------------------------------------------------------
416              
417             =over 4
418              
419             =item B
420              
421             Identical with to() but returning the hash-refed "Cc: "-line.
422              
423             The same 'name'-smartness applies here as described under C.
424              
425             =back
426              
427             =cut
428              
429 0     0 1 0 sub cc() { shift->_recipients("cc") }
430              
431             # ----------------------------------------------------------------
432              
433             =over 4
434              
435             =item B
436              
437             Returns the message-id of a message cutting off the leading and trailing '<'
438             and '>' respectively.
439              
440             =back
441              
442             =cut
443              
444             sub id() {
445 0     0 1 0 my $self = shift;
446 0         0 $self->reset_last;
447 0         0 $self->header->{'message-id'} =~ /\<(.*)\>/;
448 0         0 $1;
449             }
450              
451             # ----------------------------------------------------------------
452              
453             # --------------------
454             # MIME-related methods
455             #---------------------
456              
457             # ----------------------------------------------------------------
458              
459             =over 4
460              
461             =item B
462              
463             Returns the number of MIME-entities. That is, the number of sub-entitities
464             actually. If 0 is returned and you think this is wrong, check
465             C<$mail-Elog>.
466              
467             =back
468              
469             =cut
470              
471             sub num_entities() {
472 502     502 1 10458 my $self = shift;
473 502         1274 $self->reset_last;
474             # force list contest becaus of wantarray in get_entities
475 502 100       1478 $self->{NUM_ENT} = () = $self->get_entities unless defined $self->{NUM_ENT};
476 502         2240 return $self->{NUM_ENT};
477             }
478              
479             # ----------------------------------------------------------------
480              
481             =over 4
482              
483             =item B
484              
485             =item B
486              
487             Either returns an array of all MIME::Entity objects or one particular if called
488             with a number. If no entity whatsoever could be found, an empty list is
489             returned.
490              
491             C<$mail-Elog> instantly called after get_entities will give you some
492             information of what internally may have failed. If set, this will be an error
493             raised by MIME::Entity but you don't need to worry about it at all. It's just
494             for the record.
495              
496             =back
497              
498             =cut
499              
500             sub get_entities(@) {
501 445     445 1 671 my ($self, $num) = @_;
502 445         1191 $self->reset_last;
503              
504 445 50 66     1808 if (defined $num && $num >= $self->num_entities) {
505 0         0 $self->{LAST_ERR} = "No such entity";
506 0         0 return;
507             }
508              
509 445 100       1437 if (ref $self->{TOP_ENTITY} ne 'MIME::Entity') {
510              
511 97 100       257 if (! defined $Parser) {
512 11         44 eval { require MIME::Parser; };
  11         15269  
513 11         1241435 $Parser = new MIME::Parser; $Parser->output_to_core(1);
  11         1909  
514 11         1256 $Parser->extract_uuencode($self->{ARGS}->{uudecode});
515             }
516              
517 97         382 my $data = $self->as_string;
518 97         494 $self->{TOP_ENTITY} = $Parser->parse_data($data);
519             }
520              
521 445         498429 my @parts = eval { $self->{TOP_ENTITY}->parts_DFS; };
  445         1620  
522 445 50       7325 $self->{LAST_LOG} = $@ if $@;
523 445 100       2411 return wantarray ? @parts : $parts[$num];
524             }
525              
526             # ----------------------------------------------------------------
527              
528             # just overriding MIME::Entity::parts()
529             # to work around its strange behaviour
530            
531 2     2 0 270 sub parts(@) { shift->get_entities(@_) }
532              
533             # ----------------------------------------------------------------
534              
535             =over 4
536              
537             =item B
538              
539             Returns the body of the n-th MIME::Entity as a single string, undef otherwise
540             in which case you could check C<$mail-Eerror>.
541              
542             =back
543              
544             =cut
545              
546             sub get_entity_body($) {
547 0     0 1 0 my $self = shift;
548 0         0 my $num = shift;
549 0         0 $self->reset_last;
550              
551 0 0 0     0 if ($num < $self->num_entities &&
552             $self->get_entities($num)->bodyhandle) {
553 0         0 return $self->get_entities($num)->bodyhandle->as_string;
554             }
555             else {
556 0         0 $self->{LAST_ERR} = "$num: No such entity";
557 0         0 return;
558             }
559             }
560              
561             # ----------------------------------------------------------------
562              
563             =over 4
564              
565             =item B FILEHANDLE)>
566              
567             Stores the stringified body of n-th entity to the specified filehandle. That's
568             basically the same as:
569              
570             my $body = $mail->get_entity_body(0);
571             print FILEHANDLE $body;
572              
573             and could be shortened to this:
574              
575             $mail->store_entity_body(0, handle => \*FILEHANDLE);
576              
577             It returns a true value on success and undef on failure. In this case, examine
578             the value of $mail->error since the entity you specified with 'n' might not
579             exist.
580              
581             =back
582              
583             =cut
584              
585             sub store_entity_body($@) {
586 0     0 1 0 my $self = shift;
587 0         0 my ($num, %args) = @_;
588 0         0 $self->reset_last;
589              
590 0 0 0     0 if (not $num || (not exists $args{handle} &&
      0        
591             ref $args{handle} ne 'GLOB')) {
592 0         0 croak <
593             Wrong number or type of arguments for store_entity_body. Second argument must
594             have the form handle => \*FILEHANDLE.
595             EOC
596             }
597              
598 0         0 binmode $args{handle};
599 0         0 my $b = $self->get_entity_body($num);
600 0 0       0 print { $args{handle} } $b if defined $b;
  0         0  
601 0         0 return 1;
602             }
603              
604             # ----------------------------------------------------------------
605              
606             =over 4
607              
608             =item B
609              
610             =item B
611              
612             It is really just a call to store_entity_body but it will take care that the
613             n-th entity really is a saveable attachment. That is, it wont save anything
614             with a MIME-type of, say, text/html or so.
615              
616             Unless further 'options' have been given, an attachment (if found) is stored
617             into the current directory under the recommended filename given in the
618             MIME-header. 'options' are specified in key/value pairs:
619              
620             key: | value: | description:
621             ===========|================|===============================
622             path | relative or | directory to store attachment
623             (".") | absolute |
624             | path |
625             -----------|----------------|-------------------------------
626             encode | encoding | Some platforms store files
627             | suitable for | in e.g. UTF-8. Specify the
628             | Encode::encode | appropriate encoding here and
629             | | and the filename will be en-
630             | | coded accordingly.
631             -----------|----------------|-------------------------------
632             store_only | a compiled | store only files whose file
633             | regex-pattern | names match this pattern
634             -----------|----------------|-------------------------------
635             code | an anonym | first argument will be the
636             | subroutine | $msg-object, second one the
637             | | index-number of the current
638             | | MIME-part
639             | | should return a filename for
640             | | the attachment
641             -----------|----------------|-------------------------------
642             prefix | prefix for | all filenames are prefixed
643             | filenames | with this value
644             -----------|----------------|-------------------------------
645             args | additional | this array-ref will be passed
646             | arguments as | on to the 'code' subroutine
647             | array-ref | as a dereferenced array
648              
649              
650             Example:
651              
652             $msg->store_attachment(1,
653             path => "/home/ethan/",
654             code => sub {
655             my ($msg, $n, @args) = @_;
656             return $msg->id."+$n";
657             },
658             args => [ "Foo", "Bar" ]);
659              
660             This will save the attachment found in the second entity under the name that
661             consists of the message-ID and the appendix "+1" since the above code works on
662             the second entity (that is, with index = 1). 'args' isn't used in this example
663             but should demonstrate how to pass additional arguments. Inside the 'code' sub,
664             @args equals ("Foo", "Bar").
665              
666             If 'path' does not exist, it will try to create the directory for you.
667              
668             You can specify to save only files matching a certain pattern. To do that, use
669             the store-only switch:
670              
671             $msg->store_attachment(1, path => "/home/ethan/",
672             store_only => qr/\.jpg$/i);
673              
674             The above will only save files that end on '.jpg', not case-sensitive. You
675             could also use a non-compiled pattern if you want, but that would make for
676             instance case-insensitive matching a little cumbersome:
677              
678             store_only => '(?i)\.jpg$'
679            
680             If you are working on a platform that requires a certain encoding for filenames
681             on disk, you can use the 'encode' option. This becomes necessary for instance on
682             Mac OS X which internally is UTF-8 based. If the filename contains 8bit characters
683             (like the German umlauts or French accented characters as in 'é'), storing the
684             attachment under a non-encoded name will most likely fail. In this case, use something
685             like this:
686              
687             $msg->store_attachment(1, path => '/tmp', encode => 'utf-8');
688              
689             See L for a list of encodings that you may use.
690            
691             Returns the filename under which the attachment has been saved. undef is
692             returned in case the entity did not contain a saveable attachement, there was
693             no such entity at all or there was something wrong with the 'path' you
694             specified. Check C<$mail-Eerror> to find out which of these possibilities
695             apply.
696              
697             =back
698              
699             =cut
700              
701             sub store_attachment($@) {
702 0     0 1 0 my $self = shift;
703 0         0 my ($num, %args) = @_;
704 0         0 $self->reset_last;
705              
706 0   0     0 my $path = $args{path} || ".";
707 0         0 $path =~ s/\/$//;
708              
709 0   0     0 my $prefix = $args{prefix} || "";
710              
711 0 0 0     0 if (defined $args{code} && ref $args{code} ne 'CODE') {
712 0         0 carp <
713             Warning: Second argument for store_attachment must be
714             a coderef. Using filename from header instead
715             EOW
716 0         0 delete @args{ qw(code args) };
717             }
718              
719 0 0       0 if ($num < $self->num_entities) {
720 0         0 my $file = $self->_get_attachment( $num );
721 0 0       0 return if ! defined $file;
722              
723 0 0 0     0 if (-e $path && not -d _) {
724 0         0 $self->{LAST_ERR} = "$path is a file";
725 0         0 return;
726             }
727              
728 0 0       0 if (not -e _) {
729 0 0       0 if (not mkdir $path, 0755) {
730 0         0 $self->{LAST_ERR} = "Could not create directory $path: $!";
731 0         0 return;
732             }
733             }
734              
735 0 0       0 if (defined $args{code}) {
736 0         0 $file = $args{code}->($self, $num, @{$args{args}})
  0         0  
737             }
738            
739             #if ($file =~ /=\?.*\?=/ and HAVE_MIMEWORDS) { # decode qp if possible
740             # $file = MIME::Words::decode_mimewords($file);
741             #}
742            
743 0 0 0     0 return if defined $args{store_only} and $file !~ /$args{store_only}/;
744              
745 0 0 0     0 if ($args{encode} and HAVE_ENCODE) {
746 0         0 $file = Encode::encode($args{encode}, $file);
747             }
748              
749 0         0 local *ATT;
750 0 0       0 if (open ATT, ">$path/$prefix$file") {
751 0         0 $self->store_entity_body($num, handle => \*ATT);
752 0         0 close ATT ;
753 0         0 return "$prefix$file";
754              
755             }
756             else {
757 0         0 $self->{LAST_ERR} = "Could not create $path/$prefix$file: $!";
758 0         0 return;
759             }
760             }
761             else {
762 0         0 $self->{LAST_ERR} = "$num: No such entity";
763 0         0 return;
764             }
765             }
766              
767             # ----------------------------------------------------------------
768              
769             =over 4
770              
771             =item B
772              
773             =item B
774              
775             Walks through an entire mail and stores all apparent attachments. 'options' are
776             exactly the same as in C with the same behaviour if no
777             options are given.
778              
779             Returns a list of files that have been succesfully saved and an empty list if
780             no attachment could be extracted.
781              
782             C<$mail-Eerror> will tell you possible failures and a possible explanation
783             for that.
784              
785             =back
786              
787             =cut
788              
789             sub store_all_attachments(@) {
790 0     0 1 0 my $self = shift;
791 0         0 my %args = @_;
792 0         0 $self->reset_last;
793              
794 0 0 0     0 if (defined $args{code} and ref $args{code} ne 'CODE') {
795 0         0 carp <
796             Warning: Second argument for store_all_attachments must be a coderef.
797             Using filename from header instead
798             EOW
799 0         0 delete @args{ qw(code args) };
800             }
801 0         0 my @files;
802              
803 0 0 0     0 if (! exists $args{path} || $args{path} eq '') {
804 0         0 $args{path} = '.';
805             }
806              
807 0         0 for (0 .. $self->num_entities - 1) {
808 0         0 push @files, $self->store_attachment($_, %args);
809             }
810              
811 0 0       0 $self->{LAST_ERR} = "Found no attachment at all" if ! @files;
812 0         0 return @files;
813             }
814              
815             # ----------------------------------------------------------------
816              
817             =over 4
818              
819             =item B
820              
821             =item B
822              
823             This method returns a mapping from attachment-names (if those are savable) to
824             index-numbers of the MIME-part that represents this attachment. It returns a
825             hash-reference, the file-names being the key and the index the value:
826              
827             my $mapping = $msg->get_attachments;
828             for my $filename (keys %$mapping) {
829             print "$filename => $mapping->{$filename}\n";
830             }
831              
832             If called with a string as argument, it tries to look up this filename. If it
833             can't be found, undef is returned. In this case you also should have an
834             error-message patiently awaiting you in the return value of
835             C<$mail-Eerror>.
836              
837             Even though it looks tempting, don't do the following:
838              
839             # BAD!
840              
841             for my $file (qw/file1.ext file2.ext file3.ext file4.ext/) {
842             print "$file is in message ", $msg->id, "\n"
843             if defined $msg->get_attachments($file);
844             }
845              
846             The reason is that C is currently B optimized to cache
847             the filename mapping. So, each time you call it on (even the same) message, it
848             will scan it from beginning to end. Better would be:
849              
850             # GOOD!
851              
852             my $mapping = $msg->get_attachments;
853             for my $file (qw/file1.ext file2.ext file3.ext file4.ext/) {
854             print "$file is in message ", $msg->id, "\n"
855             if exists $mapping->{$file};
856             }
857              
858             =back
859              
860             =cut
861              
862             sub get_attachments(;$) {
863 100     100 1 2894 my ($self, $name) = @_;
864 100         645 $self->reset_last;
865 100         157 my %mapping;
866              
867 100         276 for my $num (0 .. $self->num_entities - 1) {
868 144         450 my $file = $self->_get_attachment($num);
869 144 100       558 $mapping{ $file } = $num if defined $file;
870             }
871              
872 100 100       268 if ($name) {
873 13 100       60 if (! exists $mapping{$name}) {
874 1         5 $self->{LAST_ERR} = "$name: No such attachment";
875 1         9 return;
876             } else {
877 12         93 return $mapping{$name}
878             }
879             }
880              
881 87 100       416 if (keys %mapping == 0) {
882 80         158 $self->{LAST_ERR} = "No attachments at all";
883 80         354 return;
884             }
885              
886 7         42 return \%mapping;
887             }
888              
889             sub _get_attachment {
890 144     144   227 my ($self, $num) = @_;
891 144         271 my $file = eval { $self->get_entities($num)->head->recommended_filename };
  144         517  
892 144         37535 $self->{LAST_LOG} = $@;
893 144 100       373 if (! $file) {
894             # test for Content-Disposition
895 124 100       310 if (! $self->get_entities($num)->head->get('content-disposition')) {
896 88         2322 return;
897             } else {
898 36         1452 my ($type, $filename) = split /;\s*/,
899             $self->get_entities($num)->head->get('content-disposition');
900 36 50       1360 if ($type eq 'attachment') {
901 0 0       0 if ($filename =~ /filename\*?=(.*?''?)?(.*)$/) {
902 0         0 ($file = $2) =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  0         0  
903             }
904             }
905             }
906             }
907              
908 56 100       168 return if not $file;
909            
910 20 50 50     147 if ($file =~ /=\?.*\?=/ and HAVE_MIMEWORDS) { # decode qp if possible
911 0         0 $file = MIME::Words::decode_mimewords($file);
912             }
913            
914 20         58 return $file;
915             }
916            
917             # ----------------------------------------------------------------
918              
919             =over 4
920              
921             =item B
922              
923             Returns the message as one string. This is the method that string overloading
924             depends on, so these two are the same:
925              
926             print $msg;
927            
928             print $msg->as_string;
929              
930             =back
931              
932             =cut
933              
934             sub as_string {
935 145     145 1 1152 my $self = shift;
936 145         380 my $js = $self->{ARGS}->{join_string};
937 145         199 return join $js, @{ $self->{HEADER} }, @{ $self->{BODY} };
  145         348  
  145         3206  
938             }
939              
940             sub _recipients($) {
941 0     0   0 my ($self, $field) = @_;
942 0         0 $self->reset_last;
943              
944 0         0 my $rec = $self->header->{$field};
945 0 0       0 if (! $rec) {
946 0         0 $self->{LAST_ERR} = "'$field' not in header";
947 0         0 return;
948             }
949            
950 0         0 $rec =~ s/(?<=\@)(.*?),/$1\n/g;
951 0         0 my @recs = split /\n/, $rec;
952 0         0 s/^\s+//, s/\s+$// for @recs; # remove leading or trailing whitespaces
953 0         0 my @rec_line;
954 0         0 for my $pair (@recs) {
955 0         0 my ($name, $email) = split /\s
956 0 0       0 $email =~ s/\>$//g if $email;
957 0 0 0     0 if ($name && ! $email) {
958 0         0 $email = $name;
959 0         0 $name = "";
960 0 0       0 $name = ucfirst($1) . " " . ucfirst($2) if $email =~ /^(.*?)\.(.*)@/;
961             }
962 0         0 push @rec_line, {(name => $name, email => $email)};
963             }
964              
965 0         0 return @rec_line;
966             }
967              
968             # patch provided by Kenn Frankel
969             # additional corrections by Nathan Uno
970             sub _split_header {
971 62     62   223 local $/ = $NL;
972 62         329 my ($self, $header, $decode) = @_;
973 62         76 my @headerlines = @{ $header };
  62         839  
974              
975 62         89 my @header;
976 62 50       663 chomp @headerlines if ref $header;
977 62         117 foreach my $bit (@headerlines) {
978 2254         5944 $bit =~ s/\s+$//; # discard trailing whitespace
979 2254 100       6161 if ($bit =~ s/^\s+/ /) { $header[-1] .= $bit }
  1096         2311  
980 1158         1971 else { push @header, $bit }
981             }
982            
983 62         271 my ($key, $value);
984 0         0 my %header;
985 62         232 for (@header) {
986 1158 100       3352 if (/^Received:\s/) { push @{$self->{TRACE}}, substr($_, 10) }
  414 100       400  
  414         1410  
987 54         316 elsif (/^From /) { $self->{FROM} = $_ }
988             else {
989 690         929 my $idx = index $_, ": ";
990 690         1061 $key = substr $_, 0, $idx;
991 690 100       1490 $value = $idx != -1 ? substr $_, $idx + 2 : "";
992 690 50 33     2898 if ($decode eq 'ALL' || $decode eq 'HEADER') {
993 19     19   239 use MIME::Words qw(:all);
  19         38  
  19         9073  
994 0         0 $value = decode_mimewords($value);
995             }
996              
997             # if such a field is already there => make array-ref
998 690 50       1333 if (exists $header{lc($key)}) {
999 0         0 my $elem = $header{lc($key)};
1000 0 0       0 my @data = ref $elem ? @$elem : $elem;
1001 0         0 push @data, $value;
1002 0         0 $header{lc($key)} = [ @data ];
1003             }
1004             else {
1005 690         2000 $header{lc($key)} = $value;
1006             }
1007             }
1008             }
1009 62         821 return \%header;
1010             }
1011              
1012             sub AUTOLOAD {
1013 40     40   667 my ($self, @args) = @_;
1014 40         256 (my $call = $AUTOLOAD) =~ s/.*:://;
1015              
1016             # for backward-compatibility
1017 40 50       133 if ($call eq 'store_attachement') {
1018 0         0 return $self->store_attachment(@args);
1019             }
1020 40 50       152 if ($call eq 'store_all_attachements') {
1021 0         0 return $self->store_all_attachments(@args);
1022             }
1023            
1024             # test some potential classes that might implement $call
1025 19     19   124 { no strict 'refs';
  19         36  
  19         7766  
  40         55  
1026 40         84 for my $class (qw/MIME::Entity Mail::Internet/) {
1027 40         2837 eval "require $class";
1028             # we found a Class that implements $call
1029 40 50       351218 if ($class->can($call)) {
1030              
1031             # MIME::Entity needed
1032 40 50       115 if ($class eq 'MIME::Entity') {
1033              
1034 40 100       105 if (! defined $Parser) {
1035 4         8 eval { require MIME::Parser };
  4         5068  
1036 4         61102 $Parser = new MIME::Parser;
1037 4         632 $Parser->output_to_core(1);
1038 4         60 $Parser->extract_uuencode($self->{ARGS}->{uudecode});
1039             }
1040 40         142 my $js = $self->{ARGS}->{join_string};
1041 40 100       146 $self->{TOP_ENTITY} = $Parser->parse_data(join $js, @{$self->{HEADER}}, @{$self->{BODY}})
  20         61  
  20         668  
1042             if ref $self->{TOP_ENTITY} ne 'MIME::Entity';
1043 40         116911 return $self->{TOP_ENTITY}->$call(@args);
1044             }
1045              
1046             # Mail::Internet needed
1047 0 0         if ($class eq 'Mail::Internet') {
1048 0           return Mail::Internet->new([ split /\n/, join "", ref $self->{HEADER}
1049 0 0         ? @{$self->{HEADER}}
1050             : $self->{HEADER} . $self->{BODY} ]);
1051             }
1052             }
1053             } # end 'for'
1054             } # end 'no strict refs' block
1055             }
1056              
1057 0     0     sub DESTROY {
1058             }
1059              
1060              
1061             1;
1062              
1063             __END__