File Coverage

blib/lib/Email/Simple/FromHandle.pm
Criterion Covered Total %
statement 71 76 93.4
branch 13 20 65.0
condition 14 22 63.6
subroutine 17 18 94.4
pod 8 8 100.0
total 123 144 85.4


line stmt bran cond sub pod time code
1 4     4   2286 use strict;
  4         8  
  4         95  
2 4     4   16 use warnings;
  4         7  
  4         164  
3             package Email::Simple::FromHandle 0.055;
4 4     4   1426 use Email::Simple 2.004;
  4         15053  
  4         100  
5 4     4   1486 use parent 'Email::Simple';
  4         937  
  4         18  
6             # ABSTRACT: an Email::Simple but from a handle
7              
8             #pod =head1 SYNOPSIS
9             #pod
10             #pod use Email::Simple::FileHandle;
11             #pod
12             #pod open my $fh, "<", "email.msg";
13             #pod
14             #pod my $email = Email::Simple::FromHandle->new($fh);
15             #pod
16             #pod print $email->as_string;
17             #pod # or
18             #pod $email->stream_to(\*STDOUT);
19             #pod
20             #pod =head1 DESCRIPTION
21             #pod
22             #pod This is a subclass of Email::Simple which can accept filehandles as the source
23             #pod of an email. It will keep a reference to the filehandle and read from it when
24             #pod it needs to access the body. It does not load the entire body into memory and
25             #pod keep it there.
26             #pod
27             #pod =cut
28              
29 4     4   205 use Carp ();
  4         8  
  4         51  
30 4     4   1472 use IO::String;
  4         8601  
  4         115  
31 4     4   21 use Fcntl qw(SEEK_SET);
  4         8  
  4         2928  
32              
33             my $crlf = qr/\x0a\x0d|\x0d\x0a|\x0a|\x0d/; # We are liberal in what we accept.
34              
35             #pod =head1 METHODS
36             #pod
37             #pod In addition to the standard L interface, the following methods
38             #pod are provided:
39             #pod
40             #pod =head2 handle
41             #pod
42             #pod This returns the handle given to construct the message. If the message was
43             #pod constructed with a string instead, it returns an IO::String object.
44             #pod
45             #pod =cut
46              
47 45     45 1 286 sub handle { $_[0]->{handle} }
48              
49             #pod =head2 body_pos
50             #pod
51             #pod This method returns the position in the handle at which the body begins. This
52             #pod is used for seeking when re-reading the body.
53             #pod
54             #pod =cut
55              
56 31     31 1 487 sub body_pos { $_[0]->{body_pos} }
57              
58             #pod =head2 reset_handle
59             #pod
60             #pod This method seeks the handle to the body position and resets the header-line
61             #pod iterator.
62             #pod
63             #pod For unseekable handles (pipes, sockets), this will die.
64             #pod
65             #pod =cut
66              
67             sub _is_seekable {
68 16     16   19 my ($self) = @_;
69             # on solaris, tell($pipe) == -1, and seeking on a pipe appears to discard the
70             # data waiting
71 16 50       32 return unless $self->body_pos >= 0;
72             # on linux, seeking on a pipe is safe and returns ''
73 16 100       24 return unless seek($self->handle, 0, 1);
74             # fall through: it must be seekable
75 14         76 return 1;
76             }
77              
78             sub reset_handle {
79 16     16 1 4374 my ($self) = @_;
80              
81             # Don't die the first time we try to read from a pipe/socket/etc.
82             # TODO: When reading from something non-seekable, should we
83             # give the option to store data into a temp file, or something similar?
84 16 100 100     33 return unless $self->_is_seekable || $self->{_seek}++;
85              
86 15         22 delete $self->{_get_head_lines};
87              
88 15 100       25 seek $self->handle, $self->body_pos, SEEK_SET
89             or Carp::croak "can't seek: $!";
90             }
91              
92             #pod =head2 getline
93             #pod
94             #pod $str = $email->getline;
95             #pod
96             #pod This method returns either the next line from the headers or the next line from
97             #pod the underlying filehandle. It only returns a single line, regardless of
98             #pod context. Returns C on EOF.
99             #pod
100             #pod =cut
101              
102             sub getline {
103 0     0 1 0 my ($self) = @_;
104 0 0       0 unless ($self->{_get_head_lines}) {
105             $self->{_get_head_lines} = [
106 0         0 split(/(?<=\n)/, $self->header_obj->as_string),
107             $self->crlf,
108             ];
109             }
110 0         0 my $handle = $self->handle;
111 0   0     0 return shift @{$self->{_get_head_lines}} || <$handle>;
112             }
113              
114             #pod =head2 stream_to
115             #pod
116             #pod $email->stream_to($fh, [ \%arg ]);
117             #pod
118             #pod This method efficiently writes the message to the passed-in filehandle.
119             #pod
120             #pod The second argument may be a hashref of options:
121             #pod
122             #pod =over 4
123             #pod
124             #pod =item B
125             #pod
126             #pod Whether or not to call C<< $self->reset_handle >> before reading the message
127             #pod (default true).
128             #pod
129             #pod =item B
130             #pod
131             #pod Number of bytes to read from C<< $self->handle >> at once (default 65536).
132             #pod
133             #pod =item B
134             #pod
135             #pod Coderef to use to print instead of C. This coderef will
136             #pod receive two arguments, the 'filehandle' (which need not be a real filehandle at
137             #pod all) and the current chunk of data.
138             #pod
139             #pod =back
140             #pod
141             #pod =cut
142              
143             sub _stream_to_print {
144 2     2   124 my $fh = shift;
145 2 50       4 print {$fh} @_ or Carp::croak "can't print buffer: $!";
  2         26  
146             }
147              
148             sub stream_to {
149 3     3 1 28 my ($self, $fh, $arg) = @_;
150 3   100     22 $arg ||= {};
151 3 50       17 $arg->{reset_handle} = 1 unless exists $arg->{reset_handle};
152             # 65536 is a randomly-chosen magical number that's large enough to be a win
153             # over line-by-line reading but small enough not to impinge very much upon
154             # ram usage -- hdp, 2006-11-27
155 3   50     15 $arg->{chunk_size} ||= 65536;
156 3   100     15 $arg->{write} ||= \&_stream_to_print;
157 3         13 $arg->{write}->($fh, $self->header_obj->as_string . $self->crlf);
158 3 50       189 $self->reset_handle if $arg->{reset_handle};
159 3         7 my $buf;
160 3         8 while (read($self->handle, $buf, $arg->{chunk_size}) > 0) {
161 3         11 $arg->{write}->($fh, $buf);
162             }
163             }
164              
165             #### Methods that override Email::Simple below
166              
167             sub new {
168 6     6 1 2579 my ($class, $handle, $arg) = @_;
169              
170 6   50     110 $arg ||= {};
171 6   33     121 $arg->{header_class} ||= $class->default_header_class;
172              
173 6 50       54 return Email::Simple->new($handle, $arg) unless ref $handle;
174              
175 6         27 my ($head, $mycrlf) = $class->_split_head_from_body($handle);
176              
177 6         48 my $self = bless {
178             handle => $handle,
179             body_pos => tell($handle),
180             mycrlf => $mycrlf,
181             }, $class;
182              
183             $self->header_obj_set(
184 6         102 $arg->{header_class}->new($head, { crlf => $self->crlf })
185             );
186              
187 6         1917 return $self;
188             }
189              
190             sub _split_head_from_body {
191 6     6   21 my ($class, $handle) = @_;
192              
193 6         44 my $text = q{};
194              
195             # XXX it is stupid to use <> if we're really going to have multiple forms
196             # of crlf, but it is expedient to keep doing so for now. -- hdp, 2006-11-28
197             # theoretically, this should be ok, because it will only fail if lines are
198             # terminated with \x0d, which wouldn't be ok for network transport anyway.
199 6         12 my $mycrlf;
200 6         1481 while (<$handle>) {
201 123 100 100     434 last if $mycrlf and /\A$mycrlf\z/;
202 117         179 $text .= $_;
203 117         808 ($mycrlf) = /($crlf)\z/;
204             }
205              
206 6   50     38 return ($text, $mycrlf || "\n");
207             }
208              
209             sub body_set {
210 2     2 1 429 my $self = shift;
211 2         2 my $body = shift;
212              
213 2         9 my $handle = IO::String->new(\$body);
214 2         70 $self->{handle} = $handle;
215 2         7 $self->{body_pos} = 0;
216             }
217              
218             sub body {
219 7     7 1 5882 my $self = shift;
220 7         11 scalar do {
221 7         30 local $/; ## no critic Local, Punctuation
222 7         24 $self->reset_handle;
223 6         37 my $handle = $self->handle;
224 6         132 <$handle>;
225             };
226             }
227              
228             #pod =head1 CREDITS
229             #pod
230             #pod Ricardo SIGNES wrote Email::Simple.
231             #pod
232             #pod Numerous improvement, especially streamability the handling of pipes, were made
233             #pod by Hans Dieter Pearcey.
234             #pod
235             #pod =cut
236              
237             1;
238              
239             __END__