File Coverage

blib/lib/Email/Simple/Header.pm
Criterion Covered Total %
statement 140 144 97.2
branch 61 72 84.7
condition 12 21 57.1
subroutine 21 21 100.0
pod 11 11 100.0
total 245 269 91.0


line stmt bran cond sub pod time code
1 22     22   139492 use v5.12.0;
  22         89  
2 22     22   118 use warnings;
  22         39  
  22         866  
3             package Email::Simple::Header 2.218;
4             # ABSTRACT: the header of an Email::Simple message
5              
6 22     22   119 use Carp ();
  22         44  
  22         49758  
7              
8             our @CARP_NOT = qw(Email::Simple);
9              
10             require Email::Simple;
11              
12             #pod =head1 SYNOPSIS
13             #pod
14             #pod my $email = Email::Simple->new($text);
15             #pod
16             #pod my $header = $email->header_obj;
17             #pod print $header->as_string;
18             #pod
19             #pod =head1 DESCRIPTION
20             #pod
21             #pod This method implements the headers of an Email::Simple object. It is a very
22             #pod minimal interface, and is mostly for private consumption at the moment.
23             #pod
24             #pod =method new
25             #pod
26             #pod my $header = Email::Simple::Header->new($head, \%arg);
27             #pod
28             #pod C<$head> is a string containing a valid email header, or a reference to such a
29             #pod string. If a reference is passed in, don't expect that it won't be altered.
30             #pod
31             #pod Valid arguments are:
32             #pod
33             #pod crlf - the header's newline; defaults to CRLF
34             #pod
35             #pod =cut
36              
37             # We need to be able to:
38             # * get all values by lc name
39             # * produce all pairs, with case intact
40              
41             sub new {
42 58     58 1 8563 my ($class, $head, $arg) = @_;
43              
44 58 100       156 my $head_ref = ref $head ? $head : \$head;
45              
46 58   100     209 my $self = { mycrlf => $arg->{crlf} || "\x0d\x0a", };
47              
48 58         187 my $headers = $class->_header_to_list($head_ref, $self->{mycrlf});
49              
50             # for my $header (@$headers) {
51             # push @{ $self->{order} }, $header->[0];
52             # push @{ $self->{head}{ $header->[0] } }, $header->[1];
53             # }
54             #
55             # $self->{header_names} = { map { lc $_ => $_ } keys %{ $self->{head} } };
56 58         133 $self->{headers} = $headers;
57              
58 58         260 bless $self => $class;
59             }
60              
61             sub _header_to_list {
62 58     58   128 my ($self, $head, $mycrlf) = @_;
63              
64 58 100       84 Carp::carp 'Header with wide characters' if ${$head} =~ /[^\x00-\xFF]/;
  58         695  
65              
66 58         150 my @headers;
67              
68 58         189 my $crlf = Email::Simple->__crlf_re;
69              
70 58         857 while ($$head =~ m/\G(.+?)$crlf/go) {
71 443         1148 local $_ = $1;
72              
73 443 100 100     2009 if (/^\s+/ or not /^([^:]+):\s*(.*)/) {
74             # This is a continuation line. We fold it onto the end of
75             # the previous header.
76 49 100       105 next if !@headers; # Well, that sucks. We're continuing nothing?
77              
78 48         166 (my $trimmed = $_) =~ s/^\s+//;
79 48 100       189 $headers[-1][0] .= $headers[-1][0] =~ /\S/ ? " $trimmed" : $trimmed;
80 48         268 $headers[-1][1] .= "$mycrlf$_";
81             } else {
82 394         2442 push @headers, $1, [ $2, $_ ];
83             }
84             }
85              
86 58         215 return \@headers;
87             }
88              
89             #pod =method as_string
90             #pod
91             #pod my $string = $header->as_string(\%arg);
92             #pod
93             #pod This returns a stringified version of the header.
94             #pod
95             #pod =cut
96              
97             # RFC 2822, 3.6:
98             # ...for the purposes of this standard, header fields SHOULD NOT be reordered
99             # when a message is transported or transformed. More importantly, the trace
100             # header fields and resent header fields MUST NOT be reordered, and SHOULD be
101             # kept in blocks prepended to the message.
102              
103             sub as_string {
104 53     53 1 127 my ($self, $arg) = @_;
105 53   50     276 $arg ||= {};
106              
107 53         91 my $header_str = '';
108              
109 53         100 my $headers = $self->{headers};
110              
111 53         152 my $fold_arg = {
112             # at => (exists $arg->{fold_at} ? $arg->{fold_at} : $self->default_fold_at),
113             # indent => (exists $arg->{fold_indent} ? $arg->{fold_indent} : $self->default_fold_indent),
114             at => $self->_default_fold_at,
115             indent => $self->_default_fold_indent,
116             };
117              
118 53         151 for (my $i = 0; $i < @$headers; $i += 2) {
119 459 100       893 if (ref $headers->[ $i + 1 ]) {
120 400         733 $header_str .= $headers->[ $i + 1 ][1] . $self->crlf;
121             } else {
122 59         140 my $header = "$headers->[$i]: $headers->[$i + 1]";
123              
124 59         114 $header_str .= $self->_fold($header, $fold_arg);
125             }
126             }
127              
128 53         219 return $header_str;
129             }
130              
131             #pod =method header_names
132             #pod
133             #pod This method returns a list of the unique header names found in this header, in
134             #pod no particular order.
135             #pod
136             #pod =cut
137              
138             sub header_names {
139 6     6 1 12 my $headers = $_[0]->{headers};
140              
141 6         9 my %seen;
142 14         59 grep { !$seen{ lc $_ }++ }
143 6         28 map { $headers->[ $_ * 2 ] } 0 .. @$headers / 2 - 1;
  14         30  
144             }
145              
146             #pod =method header_raw_pairs
147             #pod
148             #pod my @pairs = $header->header_raw_pairs;
149             #pod my $first_name = $pairs[0];
150             #pod my $first_value = $pairs[1];
151             #pod
152             #pod This method returns a list of all the field/value pairs in the header, in the
153             #pod order that they appear in the header. (Remember: don't try assigning that to a
154             #pod hash. Some fields may appear more than once!)
155             #pod
156             #pod =method header_pairs
157             #pod
158             #pod L is another name for L, which was the original
159             #pod name for the method and which you'll see most often. In general, though, it's
160             #pod better to be explicit and use L. (In Email::MIME,
161             #pod L exists for letting the library do the header decoding for
162             #pod you.)
163             #pod
164             #pod =cut
165              
166             sub header_raw_pairs {
167 12     12 1 22 my ($self) = @_;
168              
169 12         19 my @pairs = map {; _str_value($_) } @{ $self->{headers} };
  92         184  
  12         28  
170              
171 12         157 return @pairs;
172             }
173              
174             sub header_pairs {
175 12     12 1 25 my ($self) = @_;
176 12         25 $self->header_raw_pairs;
177             }
178              
179             #pod =method header_raw
180             #pod
181             #pod my $first_value = $header->header_raw($field);
182             #pod my $nth_value = $header->header_raw($field, $index);
183             #pod my @all_values = $header->header_raw($field);
184             #pod
185             #pod This method returns the value or values of the given header field. If the
186             #pod named field does not appear in the header, this method returns false.
187             #pod
188             #pod =method header
189             #pod
190             #pod This method just calls C. It's the older name for C,
191             #pod but it can be a problem because L, a subclass of Email::Simple,
192             #pod makes C
return the header's decoded value.
193             #pod
194             #pod =cut
195              
196 165 100   165   641 sub _str_value { return ref $_[0] ? $_[0][0] : $_[0] }
197              
198             sub header_raw {
199 78     78 1 8162 my ($self, $field, $index) = @_;
200              
201 78         145 my $headers = $self->{headers};
202 78         176 my $lc_field = lc $field;
203              
204 78 100 66     276 if (wantarray and not defined $index) {
205 22         50 return map { _str_value($headers->[ $_ * 2 + 1 ]) }
206 10         45 grep { lc $headers->[ $_ * 2 ] eq $lc_field } 0 .. @$headers / 2 - 1;
  53         111  
207             } else {
208 68 100       160 $index = 0 unless defined $index;
209 68         181 my $max = @$headers / 2 - 1;
210 68 100       240 my @indexes = $index >= 0 ? (0 .. $max) : reverse(0 .. $max);
211 68 100       175 $index = -1-$index if $index < 0;
212 68         134 for (@indexes) {
213 1 100   1   720 next unless lc $headers->[ $_ * 2 ] eq $lc_field;
  1         16  
  1         16  
  253         609  
214 95 100       255 return _str_value($headers->[ $_ * 2 + 1 ]) if $index-- == 0;
215             }
216 17         29811 return undef;
217             }
218             }
219              
220             *header = \&header_raw;
221              
222             #pod =method header_raw_set
223             #pod
224             #pod $header->header_raw_set($field => @values);
225             #pod
226             #pod This method updates the value of the given header. Existing headers have their
227             #pod values set in place. Additional headers are added at the end. If no values
228             #pod are given to set, the header will be removed from to the message entirely.
229             #pod
230             #pod =method header_set
231             #pod
232             #pod L is another name for L, which was the original
233             #pod name for the method and which you'll see most often. In general, though, it's
234             #pod better to be explicit and use L. (In Email::MIME,
235             #pod L exists for letting the library do the header encoding for
236             #pod you.)
237             #pod
238             #pod =cut
239              
240             # Header fields are lines composed of a field name, followed by a colon (":"),
241             # followed by a field body, and terminated by CRLF. A field name MUST be
242             # composed of printable US-ASCII characters (i.e., characters that have values
243             # between 33 and 126, inclusive), except colon. A field body may be composed
244             # of any US-ASCII characters, except for CR and LF.
245              
246             # However, a field body may contain CRLF when used in header "folding" and
247             # "unfolding" as described in section 2.2.3.
248              
249             sub header_raw_set {
250 26     26 1 68 my ($self, $field, @data) = @_;
251              
252 26 100       217 Carp::carp "Header name '$field' with wide characters" if $field =~ /[^\x00-\xFF]/;
253 26 100       257 Carp::carp "Value for '$field' header with wide characters" if grep /[^\x00-\xFF]/, @data;
254              
255             # I hate this block. -- rjbs, 2006-10-06
256 26 50       114 if ($Email::Simple::GROUCHY) {
257 0 0       0 Carp::croak "field name contains illegal characters"
258             unless $field =~ /^[\x21-\x39\x3b-\x7e]+$/;
259 0 0       0 Carp::carp "field name is not limited to hyphens and alphanumerics"
260             unless $field =~ /^[\w-]+$/;
261             }
262              
263 26         61 my $headers = $self->{headers};
264              
265 26         65 my $lc_field = lc $field;
266 154         307 my @indices = grep { lc $headers->[$_] eq $lc_field }
267 26         114 map { $_ * 2 } 0 .. @$headers / 2 - 1;
  154         251  
268              
269 26 100       140 if (@indices > @data) {
    100          
270 2         5 my $overage = @indices - @data;
271 2         5 splice @{$headers}, $_, 2 for reverse @indices[ -$overage .. -1 ];
  3         8  
272 2         9 pop @indices for (1 .. $overage);
273             } elsif (@data > @indices) {
274 15         38 my $underage = @data - @indices;
275 15         40 for (1 .. $underage) {
276 15         38 push @$headers, $field, undef; # temporary value
277 15         40 push @indices, $#$headers - 1;
278             }
279             }
280              
281 26         81 for (0 .. $#indices) {
282 29         79 $headers->[ $indices[$_] + 1 ] = $data[$_];
283             }
284              
285 26 100       105 return wantarray ? @data : $data[0];
286             }
287              
288             sub header_set {
289 17     17 1 49 my ($self, $field, @data) = @_;
290 17         44 $self->header_raw_set($field, @data);
291             }
292              
293             #pod =method header_raw_prepend
294             #pod
295             #pod $header->header_raw_prepend($field => $value);
296             #pod
297             #pod This method adds a new instance of the name field as the first field in the
298             #pod header.
299             #pod
300             #pod =cut
301              
302             sub header_raw_prepend {
303 9     9 1 22 my ($self, $field, $value) = @_;
304              
305 9 50       21 Carp::confess("tried to prepend raw header with undefined field name")
306             unless defined $field;
307              
308 9 50       17 Carp::confess(qq{tried to prepend raw header "$field" with undefined value})
309             unless defined $value;
310              
311 9         13 unshift @{ $self->{headers} }, $field => $value;
  9         27  
312              
313 9         22 return;
314             }
315              
316             #pod =method header_rename
317             #pod
318             #pod $header->header_rename($field, $new_name, $nth);
319             #pod
320             #pod This renames the named field to the new name. If C<$nth> is given, only the
321             #pod Ith instance of the field will be renamed. It is fatal to rename an
322             #pod instance that does not exist. The first instance of a header is the 0th.
323             #pod
324             #pod If C<$nth> is omitted, all instances of the header are renamed.
325             #pod
326             #pod When picking headers to rename, C<$field> is matched case insensitively. So,
327             #pod given this header:
328             #pod
329             #pod happythoughts: yes
330             #pod HappyThoughts: so many
331             #pod hapPyThouGhts: forever
332             #pod
333             #pod Then this code...
334             #pod
335             #pod $header->rename_header('happythoughts', 'Delights');
336             #pod
337             #pod ...will result in this:
338             #pod
339             #pod Delights: yes
340             #pod Delights: so many
341             #pod Delights: forever
342             #pod
343             #pod Headers may be rewrapped as a result of renaming.
344             #pod
345             #pod =cut
346              
347             sub header_rename {
348 9     9 1 2405 my ($self, $field, $new_name, $n) = @_;
349              
350 9         16 my $headers = $self->{headers};
351 9         14 my $lc_field = lc $field;
352              
353 51         95 my @indices = grep { lc $headers->[$_] eq $lc_field }
354 9         26 map { $_ * 2 } 0 .. @$headers / 2 - 1;
  51         78  
355              
356 9 100       24 if (defined $n) {
357 5 100       12 if ($n < 0) { Carp::confess("negative header index makes no sense") }
  1         199  
358 4 100       10 if ($n > $#indices) { Carp::confess("$n exceeds count of $field headers") }
  1         100  
359              
360 3         7 @indices = $indices[$n];
361             }
362              
363 7         13 for my $i (@indices) {
364 14         23 $headers->[$i] = $new_name;
365 14 100       26 if (ref $headers->[$i + 1]) {
366 9         23 $headers->[$i + 1] = $headers->[ $i + 1 ][0];
367             }
368             }
369              
370 7         15 return;
371             }
372              
373             #pod =method crlf
374             #pod
375             #pod This method returns the newline string used in the header.
376             #pod
377             #pod =cut
378              
379 454     454 1 1326 sub crlf { $_[0]->{mycrlf} }
380              
381             # =method fold
382             #
383             # my $folded = $header->fold($line, \%arg);
384             #
385             # Given a header string, this method returns a folded version, if the string is
386             # long enough to warrant folding. This method is used internally.
387             #
388             # Valid arguments are:
389             #
390             # at - fold lines to be no longer than this length, if possible
391             # if given and false, never fold headers
392             # indent - indent lines with this string
393              
394             # =cut
395              
396             sub _fold {
397 59     59   117 my ($self, $line, $arg) = @_;
398 59   50     137 $arg ||= {};
399              
400 59 50       117 $arg->{at} = $self->_default_fold_at unless exists $arg->{at};
401              
402 59 50       107 $arg->{indent} = $self->_default_fold_indent unless exists $arg->{indent};
403              
404 59   33     127 my $indent = $arg->{indent} || $self->_default_fold_indent;
405              
406             # We will not folder headers if...
407             # * the header has vertical whitespace
408             # * all vertical whitespace is followed by horizontal whitespace or END
409 59 100       166 if ($line =~ /\n/) {
410 21 100       59 if ($line =~ s/\n([^\s\t])/\n$indent$1/g) {
411 1         271 Carp::carp("bad space in header: newline followed by non-space: $line");
412             } else {
413 20 100       54 $line .= $self->crlf unless $line =~ /\n$/;
414 20         66 return $line;
415             }
416             }
417              
418 39 50 33     218 return $line . $self->crlf unless $arg->{at} and $arg->{at} > 0;
419              
420 39   33     85 my $limit = ($arg->{at} || $self->_default_fold_at) - 1;
421              
422 39 100       117 return $line . $self->crlf if length $line <= $limit;
423              
424 3         11 return $self->__fold_objless($line, $limit, $indent, $self->crlf);
425              
426             }
427              
428             sub __fold_objless {
429 28     28   70 my ($self, $line, $limit, $indent, $crlf) = @_;
430              
431             # We know it will not contain any new lines at present
432 28         46 my $folded = "";
433 28         67 while (length $line) {
434 33 50       303 if ($line =~ s/^(.{0,$limit})(\s|\z)//) {
435 33         106 $folded .= $1 . $crlf;
436 33 100       108 $folded .= $indent if length $line;
437             } else {
438             # Basically nothing we can do. :(
439 0         0 $folded .= $line . $crlf;
440 0         0 last;
441             }
442             }
443              
444 28         106 return $folded;
445             }
446              
447             # =method default_fold_at
448             #
449             # This method (provided for subclassing) returns the default length at which to
450             # try to fold header lines. The default default is 78.
451             #
452             # =cut
453              
454 53     53   120 sub _default_fold_at { 78 }
455              
456             # =method default_fold_indent
457             #
458             # This method (provided for subclassing) returns the default string used to
459             # indent folded headers. The default default is a single space.
460             #
461             # =cut
462              
463 53     53   156 sub _default_fold_indent { " " }
464              
465             1;
466              
467             __END__