/[suikacvs]/messaging/manakai/lib/Message/Header.pm
Suika

Contents of /messaging/manakai/lib/Message/Header.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (hide annotations) (download)
Sun Apr 21 04:28:46 2002 UTC (22 years, 7 months ago) by wakaba
Branch: MAIN
Changes since 1.16: +9 -5 lines
2002-04-21  wakaba <w@suika.fam.cx>

	* Entity.pm (pod:C<format>): New section.

1 wakaba 1.1
2     =head1 NAME
3    
4     Message::Header Perl module
5    
6     =head1 DESCRIPTION
7    
8     Perl module for RFC 822/2822 message C<header>.
9    
10     =cut
11    
12     package Message::Header;
13     use strict;
14 wakaba 1.14 use vars qw($VERSION %REG);
15 wakaba 1.1 $VERSION = '1.00';
16 wakaba 1.14 use Carp ();
17 wakaba 1.15 use overload '@{}' => sub { shift->_delete_empty_field->{field} },
18     '""' => sub { shift->stringify },
19     fallback => 1;
20 wakaba 1.1
21     $REG{WSP} = qr/[\x09\x20]/;
22     $REG{FWS} = qr/[\x09\x20]*/;
23     $REG{M_field} = qr/^([^\x3A]+):$REG{FWS}([\x00-\xFF]*)$/;
24     $REG{M_fromline} = qr/^\x3E?From$REG{WSP}+([\x00-\xFF]*)$/;
25     $REG{UNSAFE_field_name} = qr/[\x00-\x20\x3A\x7F-\xFF]/;
26    
27     =head2 options
28    
29     These options can be getten/set by C<get_option>/C<set_option>
30     method.
31    
32     =head3 capitalize = 0/1
33    
34     (First character of) C<field-name> is capitalized
35     when C<stringify>. (Default = 1)
36    
37     =head3 fold_length = numeric value
38    
39     Length of line used to fold. (Default = 70)
40    
41     =head3 mail_from = 0/1
42    
43     Outputs "From " line (known as Un*x From, Mail-From, and so on)
44     when C<stringify>. (Default = 0)
45    
46     =cut
47    
48 wakaba 1.15 =head1 CONSTRUCTORS
49    
50     The following methods construct new C<Message::Header> objects:
51    
52     =over 4
53    
54 wakaba 1.16 =cut
55    
56 wakaba 1.15 ## Initialize
57 wakaba 1.14 my %DEFAULT = (
58 wakaba 1.1 capitalize => 1,
59 wakaba 1.17 fold => 1,
60 wakaba 1.1 fold_length => 70,
61 wakaba 1.17 field_format_pattern => '%s: %s',
62 wakaba 1.14 #field_type => {},
63     format => 'mail-rfc2822',
64     mail_from => 0,
65     output_bcc => 0,
66     parse_all => 0,
67     sort => 'none',
68     translate_underscore => 1,
69     validate => 1,
70 wakaba 1.1 );
71 wakaba 1.14 $DEFAULT{field_type} = {
72     ':DEFAULT' => 'Message::Field::Unstructured',
73    
74     received => 'Message::Field::Received',
75     'x-received' => 'Message::Field::Received',
76    
77     'content-type' => 'Message::Field::ContentType',
78 wakaba 1.15 'auto-submitted' => 'Message::Field::ValueParams',
79 wakaba 1.17 'content-disposition' => 'Message::Field::ValueParams',
80 wakaba 1.14 link => 'Message::Field::ValueParams',
81     archive => 'Message::Field::ValueParams',
82     'x-face-type' => 'Message::Field::ValueParams',
83    
84     subject => 'Message::Field::Subject',
85     'x-nsubject' => 'Message::Field::Subject',
86    
87     'list-software' => 'Message::Field::UA',
88     'user-agent' => 'Message::Field::UA',
89     server => 'Message::Field::UA',
90    
91 wakaba 1.15 ## Numeric value
92 wakaba 1.14 'content-length' => 'Message::Field::Numval',
93     lines => 'Message::Field::Numval',
94     'max-forwards' => 'Message::Field::Numval',
95     'mime-version' => 'Message::Field::Numval',
96 wakaba 1.15 'x-jsmail-priority' => 'Message::Field::Numval',
97 wakaba 1.16 'x-mail-count' => 'Message::Field::Numval',
98     'x-ml-count' => 'Message::Field::Numval',
99 wakaba 1.15 'x-priority' => 'Message::Field::Numval',
100 wakaba 1.14
101     path => 'Message::Field::Path',
102     };
103 wakaba 1.16 for (qw(archive cancel-lock content-features content-md5
104     disposition-notification-options encoding
105     importance injector-info
106     pics-label posted-and-mailed precedence list-id message-type
107     original-recipient priority
108     sensitivity status x-face x-msmail-priority xref))
109 wakaba 1.4 {$DEFAULT{field_type}->{$_} = 'Message::Field::Structured'}
110 wakaba 1.16 ## Not supported yet, but to be supported...
111     for (qw(abuse-reports-to apparently-to approved approved-by bcc cc complaints-to
112 wakaba 1.15 delivered-to disposition-notification-to envelope-to
113 wakaba 1.16 errors-to from mail-copies-to mail-followup-to mail-reply-to
114     notice-requested-upon-delivery-to read-receipt-to register-mail-reply-requested-by
115     reply-to resent-bcc
116 wakaba 1.4 resent-cc resent-to resent-from resent-sender return-path
117 wakaba 1.16 return-receipt-to return-receipt-requested-to sender to x-abuse-reports-to
118     x-admin x-approved
119     x-beenthere
120     x-confirm-reading-to
121 wakaba 1.4 x-complaints-to x-envelope-from x-envelope-sender
122 wakaba 1.16 x-envelope-to x-ml-address x-ml-command x-ml-to x-nfrom x-nto
123     x-rcpt-to x-sender x-x-sender))
124 wakaba 1.4 {$DEFAULT{field_type}->{$_} = 'Message::Field::Address'}
125 wakaba 1.14 for (qw(date date-received delivery-date expires
126 wakaba 1.16 expire-date nntp-posting-date posted posted-date reply-by resent-date
127     x-originalarrivaltime x-tcup-date))
128 wakaba 1.4 {$DEFAULT{field_type}->{$_} = 'Message::Field::Date'}
129 wakaba 1.14 for (qw(article-updates client-date content-id in-reply-to message-id
130 wakaba 1.16 obsoletes references replaces resent-message-id see-also supersedes))
131 wakaba 1.6 {$DEFAULT{field_type}->{$_} = 'Message::Field::MsgID'}
132 wakaba 1.7 for (qw(accept accept-charset accept-encoding accept-language
133 wakaba 1.8 content-language
134 wakaba 1.12 content-transfer-encoding encrypted followup-to keywords
135     list-archive list-digest list-help list-owner
136     list-post list-subscribe list-unsubscribe list-url uri newsgroups
137 wakaba 1.16 posted-to
138 wakaba 1.8 x-brother x-daughter x-respect x-moe x-syster x-wife))
139 wakaba 1.7 {$DEFAULT{field_type}->{$_} = 'Message::Field::CSV'}
140 wakaba 1.12 for (qw(content-alias content-base content-location location referer
141     url x-home-page x-http_referer
142     x-info x-pgp-key x-ml-url x-uri x-url x-web))
143     {$DEFAULT{field_type}->{$_} = 'Message::Field::URI'}
144 wakaba 1.1
145 wakaba 1.14 ## taken from L<HTTP::Header>
146     # "Good Practice" order of HTTP message headers:
147     # - General-Headers
148     # - Request-Headers
149     # - Response-Headers
150     # - Entity-Headers
151     # (From draft-ietf-http-v11-spec-rev-01, Nov 21, 1997)
152     my @header_order = qw(
153     mail-from x-envelope-from relay-version path status
154    
155     cache-control connection date pragma transfer-encoding upgrade trailer via
156    
157     accept accept-charset accept-encoding accept-language
158     authorization expect from host
159     if-modified-since if-match if-none-match if-range if-unmodified-since
160     max-forwards proxy-authorization range referer te user-agent
161    
162     accept-ranges age location proxy-authenticate retry-after server vary
163     warning www-authenticate
164    
165     mime-version
166     allow content-base content-encoding content-language content-length
167     content-location content-md5 content-range content-type
168     etag expires last-modified content-style-type content-script-type
169     link
170    
171     xref
172     );
173     my %header_order;
174    
175     sub _init ($;%) {
176     my $self = shift;
177     my %options = @_;
178     $self->{field} = [];
179     $self->{option} = \%DEFAULT;
180     my @new_fields = ();
181     for my $name (keys %options) {
182     if (substr ($name, 0, 1) eq '-') {
183     $self->{option}->{substr ($name, 1)} = $options{$name};
184     } else {
185     push @new_fields, ($name => $options{$name});
186     }
187     }
188     $self->add (@new_fields, -parse => $self->{option}->{parse_all})
189     if $#new_fields > -1;
190    
191     my $format = $self->{option}->{format};
192 wakaba 1.17 if ($format =~ /cgi/) {
193 wakaba 1.14 unshift @header_order, qw(content-type location);
194     $self->{option}->{sort} = 'good-practice';
195 wakaba 1.17 $self->{option}->{fold} = 0;
196 wakaba 1.14 } elsif ($format =~ /^http/) {
197     $self->{option}->{sort} = 'good-practice';
198     }
199    
200     # Make alternative representations of @header_order. This is used
201     # for sorting.
202     my $i = 1;
203     for (@header_order) {
204     $header_order{$_} = $i++ unless $header_order{$_};
205     }
206     }
207    
208 wakaba 1.15 =item Message::Header->new ([%initial-fields/options])
209 wakaba 1.14
210     Constructs a new C<Message::Headers> object. You might pass some initial
211     C<field-name>-C<field-body> pairs and/or options as parameters to the constructor.
212    
213 wakaba 1.15 Example:
214 wakaba 1.1
215 wakaba 1.14 $hdr = new Message::Headers
216     Date => 'Thu, 03 Feb 1994 00:00:00 +0000',
217     Content_Type => 'text/html',
218     Content_Location => 'http://www.foo.example/',
219     -format => 'mail-rfc2822' ## not to be header field
220     ;
221 wakaba 1.1
222     =cut
223    
224     sub new ($;%) {
225     my $class = shift;
226 wakaba 1.14 my $self = bless {}, $class;
227     $self->_init (@_);
228 wakaba 1.1 $self;
229     }
230    
231 wakaba 1.15 =item Message::Header->parse ($header, [%initial-fields/options])
232 wakaba 1.1
233 wakaba 1.14 Parses given C<header> and constructs a new C<Message::Headers>
234     object. You might pass some additional C<field-name>-C<field-body> pairs
235     or/and initial options as parameters to the constructor.
236 wakaba 1.1
237     =cut
238    
239     sub parse ($$;%) {
240     my $class = shift;
241     my $header = shift;
242 wakaba 1.14 my $self = bless {}, $class;
243     $self->_init (@_);
244     $header =~ s/\x0D?\x0A$REG{WSP}/\x20/gos; ## unfold
245 wakaba 1.1 for my $field (split /\x0D?\x0A/, $header) {
246     if ($field =~ /$REG{M_fromline}/) {
247 wakaba 1.9 my $body = $1;
248     $body = $self->_field_body ($body, 'mail-from')
249 wakaba 1.14 if $self->{option}->{parse_all};
250 wakaba 1.9 push @{$self->{field}}, {name => 'mail-from', body => $body};
251 wakaba 1.1 } elsif ($field =~ /$REG{M_field}/) {
252 wakaba 1.9 my ($name, $body) = (lc $1, $2);
253 wakaba 1.1 $name =~ s/$REG{WSP}+$//;
254     $body =~ s/$REG{WSP}+$//;
255 wakaba 1.14 $body = $self->_field_body ($body, $name) if $self->{option}->{parse_all};
256 wakaba 1.9 push @{$self->{field}}, {name => $name, body => $body};
257 wakaba 1.1 }
258     }
259     $self;
260     }
261    
262 wakaba 1.15 =item Message::Header->parse_array (\@header, [%initial-fields/options])
263    
264     Parses given C<header> and constructs a new C<Message::Headers>
265     object. Same as C<Message::Header-E<lt>parse> but this method
266     is given an array reference. You might pass some additional
267     C<field-name>-C<field-body> pairs or/and initial options
268     as parameters to the constructor.
269    
270     =cut
271    
272 wakaba 1.14 sub parse_array ($\@;%) {
273     my $class = shift;
274     my $header = shift;
275     Carp::croak "parse_array: first argument is not an array reference"
276     unless ref $header eq 'ARRAY';
277     my $self = bless {}, $class;
278     $self->_init (@_);
279     while (1) {
280     my $field = shift @$header;
281     while (1) {
282     if ($$header[0] =~ /^$REG{WSP}/) {
283     $field .= shift @$header;
284     } else {last}
285     }
286     $field =~ tr/\x0D\x0A//d; ## BUG: not safe for bar CR/LF
287     if ($field =~ /$REG{M_fromline}/) {
288     my $body = $1;
289     $body = $self->_field_body ($body, 'mail-from')
290     if $self->{option}->{parse_all};
291     push @{$self->{field}}, {name => 'mail-from', body => $body};
292     } elsif ($field =~ /$REG{M_field}/) {
293     my ($name, $body) = (lc $1, $2);
294     $name =~ s/$REG{WSP}+$//;
295     $body =~ s/$REG{WSP}+$//;
296     $body = $self->_field_body ($body, $name) if $self->{option}->{parse_all};
297     push @{$self->{field}}, {name => $name, body => $body};
298     }
299     last if $#$header < 0;
300     }
301     $self;
302     }
303    
304 wakaba 1.15 =back
305    
306     =head1 METHODS
307    
308 wakaba 1.1 =head2 $self->field ($field_name)
309    
310     Returns C<field-body> of given C<field-name>.
311     When there are two or more C<field>s whose name is C<field-name>,
312     this method return all C<field-body>s as array. (On scalar
313     context, only first one is returned.)
314    
315     =cut
316    
317     sub field ($$) {
318     my $self = shift;
319     my $name = lc shift;
320     my @ret;
321     for my $field (@{$self->{field}}) {
322     if ($field->{name} eq $name) {
323     unless (wantarray) {
324 wakaba 1.5 $field->{body} = $self->_field_body ($field->{body}, $name);
325     return $field->{body};
326 wakaba 1.1 } else {
327 wakaba 1.5 $field->{body} = $self->_field_body ($field->{body}, $name);
328     push @ret, $field->{body};
329 wakaba 1.1 }
330     }
331     }
332 wakaba 1.9 if ($#ret < 0) {
333     return $self->add ($name);
334     }
335 wakaba 1.1 @ret;
336     }
337    
338 wakaba 1.9 sub field_exist ($$) {
339     my $self = shift;
340     my $name = lc shift;
341     my @ret;
342     for my $field (@{$self->{field}}) {
343     return 1 if ($field->{name} eq $name);
344     }
345     0;
346     }
347    
348 wakaba 1.2 =head2 $self->field_name ($index)
349    
350     Returns C<field-name> of $index'th C<field>.
351    
352     =head2 $self->field_body ($index)
353    
354     Returns C<field-body> of $index'th C<field>.
355    
356     =cut
357    
358     sub field_name ($$) {
359     my $self = shift;
360     $self->{field}->[shift]->{name};
361     }
362     sub field_body ($$) {
363     my $self = shift;
364 wakaba 1.4 my $i = shift;
365 wakaba 1.5 $self->{field}->[$i]->{body}
366     = $self->_field_body ($self->{field}->[$i]->{body}, $self->{field}->[$i]->{name});
367     $self->{field}->[$i]->{body};
368 wakaba 1.4 }
369    
370     sub _field_body ($$$) {
371     my $self = shift;
372     my ($body, $name) = @_;
373 wakaba 1.5 unless (ref $body) {
374 wakaba 1.4 my $type = $self->{option}->{field_type}->{$name}
375 wakaba 1.7 || $self->{option}->{field_type}->{':DEFAULT'};
376 wakaba 1.14 eval "require $type" or Carp::croak ("_field_body: $type: $@");
377 wakaba 1.5 unless ($body) {
378 wakaba 1.16 $body = $type->new (-field_name => $name,
379     -format => $self->{option}->{format}
380     , field_name => $name, format => $self->{option}->{format});
381 wakaba 1.5 } else {
382 wakaba 1.14 $body = $type->parse ($body, -field_name => $name,
383 wakaba 1.16 -format => $self->{option}->{format},
384     field_name => $name,format => $self->{option}->{format});
385 wakaba 1.5 }
386 wakaba 1.4 }
387 wakaba 1.5 $body;
388 wakaba 1.2 }
389    
390 wakaba 1.1 =head2 $self->field_name_list ()
391    
392     Returns list of all C<field-name>s. (Even if there are two
393     or more C<field>s which have same C<field-name>, this method
394     returns ALL names.)
395    
396     =cut
397    
398     sub field_name_list ($) {
399     my $self = shift;
400     $self->_delete_empty_field ();
401     map {$_->{name}} @{$self->{field}};
402     }
403    
404 wakaba 1.16 =item $hdr->add ($field-name, $field-body, [$name, $body, ...])
405 wakaba 1.1
406 wakaba 1.16 Adds some field name/body pairs. Even if there are
407     one or more fields named given C<$field-name>,
408     given name/body pairs are ADDed. Use C<replace>
409     to remove same-name-fields.
410 wakaba 1.1
411 wakaba 1.14 Instead of field name-body pair, you might pass some options.
412     Four options are available for this method.
413    
414     C<-parse>: Parses and validates C<field-body>, and returns
415     C<field-body> object. (When multiple C<field-body>s are
416     added, returns only last one.) (Default: C<defined wantarray>)
417    
418     C<-prepend>: New fields are not appended,
419     but prepended to current fields. (Default: C<0>)
420    
421     C<-translate-underscore>: Do C<field-name> =~ tr/_/-/. (Default: C<1>)
422    
423     C<-validate>: Checks whether C<field-name> is valid or not.
424    
425 wakaba 1.1 =cut
426    
427 wakaba 1.14 sub add ($%) {
428 wakaba 1.1 my $self = shift;
429 wakaba 1.14 my %fields = @_;
430     my %option = %{$self->{option}};
431     $option{parse} = defined wantarray unless defined $option{parse};
432     for (grep {/^-/} keys %fields) {$option{substr ($_, 1)} = $fields{$_}}
433     my $body;
434     for (grep {/^[^-]/} keys %fields) {
435     my $name = lc $_; $body = $fields{$_};
436     $name =~ tr/_/-/ if $option{translate_underscore};
437     Carp::croak "add: $name: invalid field-name"
438     if $option{validate} && $name =~ /$REG{UNSAFE_field_name}/;
439     $body = $self->_field_body ($body, $name) if $option{parse};
440     if ($option{prepend}) {
441     unshift @{$self->{field}}, {name => $name, body => $body};
442     } else {
443     push @{$self->{field}}, {name => $name, body => $body};
444     }
445 wakaba 1.8 }
446 wakaba 1.14 $body if $option{parse};
447 wakaba 1.1 }
448    
449     =head2 $self->relace ($field_name, $field_body)
450    
451     Set the C<field-body> named C<field-name> as $field_body.
452     If $field_name C<field> is already exists, it is replaced
453     by new $field_body value. If not, new C<field> is inserted.
454     (If there are some C<field> named as $field_name,
455     first one is used and the others are not changed.)
456    
457     =cut
458    
459 wakaba 1.14 sub replace ($%) {
460 wakaba 1.1 my $self = shift;
461 wakaba 1.14 my %params = @_;
462     my %option = %{$self->{option}};
463     $option{parse} = defined wantarray unless defined $option{parse};
464     for (grep {/^-/} keys %params) {$option{substr ($_, 1)} = $params{$_}}
465 wakaba 1.15 my (%new_field);
466 wakaba 1.14 for (grep {/^[^-]/} keys %params) {
467     my $name = lc $_;
468     $name =~ tr/_/-/ if $option{translate_underscore};
469     Carp::croak "replace: $name: invalid field-name"
470     if $option{validate} && $name =~ /$REG{UNSAFE_field_name}/;
471     $params{$_} = $self->_field_body ($params{$_}, $name) if $option{parse};
472     $new_field{$name} = $params{$_};
473     }
474 wakaba 1.15 my $body = (%new_field)[-1];
475 wakaba 1.1 for my $field (@{$self->{field}}) {
476 wakaba 1.14 if (defined $new_field{$field->{name}}) {
477 wakaba 1.15 $field->{body} = $new_field {$field->{name}};
478 wakaba 1.14 $new_field{$field->{name}} = undef;
479 wakaba 1.1 }
480     }
481 wakaba 1.14 for (keys %new_field) {
482     push @{$self->{field}}, {name => $_, body => $new_field{$_}};
483     }
484     $body if $option{parse};
485 wakaba 1.1 }
486    
487 wakaba 1.14 =head2 $self->delete ($field-name, [$name, ...])
488 wakaba 1.1
489     Deletes C<field> named as $field_name.
490    
491     =cut
492    
493 wakaba 1.14 sub delete ($@) {
494 wakaba 1.1 my $self = shift;
495 wakaba 1.16 my %delete; for (@_) {$delete{lc $_} = 1}
496 wakaba 1.1 for my $field (@{$self->{field}}) {
497 wakaba 1.14 undef $field if $delete{$field->{name}};
498 wakaba 1.1 }
499     }
500    
501 wakaba 1.2 =head2 $self->count ([$field_name])
502 wakaba 1.1
503     Returns the number of times the given C<field> appears.
504 wakaba 1.2 If no $field_name is given, returns the number
505     of fields. (Same as $#$self+1)
506 wakaba 1.1
507     =cut
508    
509 wakaba 1.2 sub count ($;$) {
510 wakaba 1.1 my $self = shift;
511     my ($name) = (lc shift);
512 wakaba 1.2 unless ($name) {
513     $self->_delete_empty_field ();
514     return $#{$self->{field}}+1;
515     }
516 wakaba 1.1 my $count = 0;
517     for my $field (@{$self->{field}}) {
518     if ($field->{name} eq $name) {
519     $count++;
520     }
521     }
522     $count;
523     }
524    
525 wakaba 1.14 =head2 $self->rename ($field-name, $new-name, [$old, $new,...])
526 wakaba 1.12
527 wakaba 1.14 Renames C<$field-name> as C<$new-name>.
528 wakaba 1.12
529     =cut
530    
531 wakaba 1.14 sub rename ($%) {
532 wakaba 1.12 my $self = shift;
533 wakaba 1.14 my %params = @_;
534     my %option = %{$self->{option}};
535     for (grep {/^-/} keys %params) {$option{substr ($_, 1)} = $params{$_}}
536     my %new_name;
537     for (grep {/^[^-]/} keys %params) {
538     my ($old => $new) = (lc $_ => lc $params{$_});
539     $new =~ tr/_/-/ if $option{translate_underscore};
540     Carp::croak "rename: $new: invalid field-name"
541     if $option{validate} && $new =~ /$REG{UNSAFE_field_name}/;
542     $new_name{$old} = $new;
543     }
544 wakaba 1.12 for my $field (@{$self->{field}}) {
545 wakaba 1.14 if (length $new_name{$field->{name}}) {
546     $field->{name} = $new_name{$field->{name}};
547 wakaba 1.12 }
548     }
549 wakaba 1.14 $self if defined wantarray;
550     }
551    
552    
553     =item $self->scan(\&doit)
554    
555     Apply a subroutine to each header field in turn. The callback routine is
556     called with two parameters; the name of the field and a single value.
557     If the header has more than one value, then the routine is called once
558     for each value.
559    
560     =cut
561    
562     sub scan ($&) {
563     my ($self, $sub) = @_;
564     my $sort;
565     $sort = \&_header_cmp if $self->{option}->{sort} eq 'good-practice';
566     $sort = {$a cmp $b} if $self->{option}->{sort} eq 'alphabetic';
567     my @field = @{$self->{field}};
568     if (ref $sort) {
569     @field = sort $sort @{$self->{field}};
570     }
571     for my $field (@field) {
572     next if $field->{name} =~ /^_/;
573     &$sub($field->{name} => $field->{body});
574     }
575     }
576    
577     # Compare function which makes it easy to sort headers in the
578     # recommended "Good Practice" order.
579     ## taken from HTTP::Header
580     sub _header_cmp
581     {
582     my ($na, $nb) = ($a->{name}, $b->{name});
583     # Unknown headers are assign a large value so that they are
584     # sorted last. This also helps avoiding a warning from -w
585     # about comparing undefined values.
586     $header_order{$na} = 999 unless defined $header_order{$na};
587     $header_order{$nb} = 999 unless defined $header_order{$nb};
588    
589     $header_order{$na} <=> $header_order{$nb} || $na cmp $nb;
590 wakaba 1.12 }
591    
592 wakaba 1.1 =head2 $self->stringify ([%option])
593    
594     Returns the C<header> as a string.
595    
596     =cut
597    
598     sub stringify ($;%) {
599     my $self = shift;
600 wakaba 1.14 my %params = @_;
601     my %option = %{$self->{option}};
602     for (grep {/^-/} keys %params) {$option{substr ($_, 1)} = $params{$_}}
603 wakaba 1.1 my @ret;
604 wakaba 1.14 if ($option{mail_from}) {
605     my $fromline = $self->field ('mail-from');
606     push @ret, 'From '.$fromline if $fromline;
607     }
608     $self->scan (sub {
609     my ($name, $body) = (@_);
610     return unless length $name;
611     return if $option{mail_from} && $name eq 'mail-from';
612     return if !$option{output_bcc} && ($name eq 'bcc' || $name eq 'resent-bcc');
613 wakaba 1.12 my $fbody;
614 wakaba 1.14 if (ref $body) {
615     $fbody = $body->stringify (-format => $option{format});
616 wakaba 1.12 } else {
617 wakaba 1.14 $fbody = $body;
618 wakaba 1.12 }
619 wakaba 1.14 return unless length $fbody;
620     $fbody =~ s/\x0D(?=[^\x09\x0A\x20])/\x0D\x20/g;
621     $fbody =~ s/\x0A(?=[^\x09\x20])/\x0A\x20/g;
622     $name =~ s/((?:^|-)[a-z])/uc($1)/ge if $option{capitalize};
623 wakaba 1.17 $fbody = $self->_fold ($fbody) if $self->{option}->{fold};
624     push @ret, sprintf $self->{option}->{field_format_pattern}, $name, $fbody;
625 wakaba 1.14 });
626 wakaba 1.3 my $ret = join ("\n", @ret);
627 wakaba 1.14 $ret? $ret."\n": '';
628 wakaba 1.1 }
629 wakaba 1.14 *as_string = \&stringify;
630 wakaba 1.1
631 wakaba 1.12 =head2 $self->option ($option_name, [$option_value])
632 wakaba 1.1
633 wakaba 1.12 Set/gets new value of the option.
634 wakaba 1.1
635     =cut
636    
637 wakaba 1.14 sub option ($@) {
638 wakaba 1.1 my $self = shift;
639 wakaba 1.14 if (@_ == 1) {
640     return $self->{option}->{ shift (@_) };
641     }
642     while (my ($name, $value) = splice (@_, 0, 2)) {
643     $name =~ s/^-//;
644 wakaba 1.12 $self->{option}->{$name} = $value;
645     if ($name eq 'format') {
646     for my $f (@{$self->{field}}) {
647 wakaba 1.14 if (ref $f->{body}) {
648     $f->{body}->option (-format => $value);
649 wakaba 1.12 }
650     }
651     }
652     }
653 wakaba 1.1 }
654    
655 wakaba 1.4 sub field_type ($$;$) {
656     my $self = shift;
657     my $field_name = shift;
658     my $new_field_type = shift;
659     if ($new_field_type) {
660     $self->{option}->{field_type}->{$field_name} = $new_field_type;
661     }
662     $self->{option}->{field_type}->{$field_name}
663 wakaba 1.7 || $self->{option}->{field_type}->{':DEFAULT'};
664 wakaba 1.4 }
665    
666 wakaba 1.1 sub _delete_empty_field ($) {
667     my $self = shift;
668     my @ret;
669     for my $field (@{$self->{field}}) {
670     push @ret, $field if $field->{name};
671     }
672     $self->{field} = \@ret;
673     $self;
674     }
675    
676 wakaba 1.17 sub _fold ($$;$) {
677 wakaba 1.1 my $self = shift;
678     my $string = shift;
679     my $len = shift || $self->{option}->{fold_length};
680     $len = 60 if $len < 60;
681    
682     ## This code is taken from Mail::Header 1.43 in MailTools,
683     ## by Graham Barr (Maintained by Mark Overmeer <mailtools@overmeer.net>).
684     my $max = int($len - 5); # 4 for leading spcs + 1 for [\,\;]
685     my $min = int($len * 4 / 5) - 4;
686     my $ml = $len;
687    
688     if (length($string) > $ml) {
689     #Split the line up
690     # first bias towards splitting at a , or a ; >4/5 along the line
691     # next split a whitespace
692     # else we are looking at a single word and probably don't want to split
693     my $x = "";
694 wakaba 1.11 $x .= "$1\n "
695 wakaba 1.1 while($string =~ s/^$REG{WSP}*(
696     [^"]{$min,$max}?[\,\;]
697     |[^"]{1,$max}$REG{WSP}
698     |[^\s"]*(?:"[^"]*"[^\s"]*)+$REG{WSP}
699     |[^\s"]+$REG{WSP}
700     )
701     //x);
702     $x .= $string;
703     $string = $x;
704     $string =~ s/(\A$REG{WSP}+|$REG{WSP}+\Z)//sog;
705     $string =~ s/\s+\n/\n/sog;
706     }
707     $string;
708     }
709    
710 wakaba 1.14 =head2 $self->clone ()
711    
712     Returns a copy of Message::Header object.
713    
714     =cut
715    
716     sub clone ($) {
717     my $self = shift;
718     my $clone = new Message::Header;
719     for my $name (%{$self->{option}}) {
720     if (ref $self->{option}->{$name} eq 'HASH') {
721     $clone->{option}->{$name} = {%{$self->{option}->{$name}}};
722     } elsif (ref $self->{option}->{$name} eq 'ARRAY') {
723     $clone->{option}->{$name} = [@{$self->{option}->{$name}}];
724     } else {
725     $clone->{option}->{$name} = $self->{option}->{$name};
726     }
727     }
728     for (@{$self->{field}}) {
729     $clone->add ($_->{name}, scalar $_->{body});
730     }
731     $clone;
732     }
733    
734     =head1 NOTE
735    
736     =head2 C<field-name>
737    
738     The header field name is not case sensitive. To make the life
739     easier for perl users who wants to avoid quoting before the => operator,
740     you can use '_' as a synonym for '-' in header field names
741     (this behaviour can be suppressed by setting
742     C<translate_underscore> option to C<0> value).
743    
744 wakaba 1.1 =head1 EXAMPLE
745    
746     ## Print field list
747    
748     use Message::Header;
749     my $header = Message::Header->parse ($header);
750    
751 wakaba 1.2 for my $i (0..$#$header) {
752     print $header->field_name ($i), "\t=> ", $header->field_body ($i), "\n";
753 wakaba 1.1 }
754    
755    
756     ## Make simple header
757    
758 wakaba 1.2 use Message::Header;
759 wakaba 1.1 use Message::Field::Address;
760     my $header = new Message::Header;
761    
762     my $from = new Message::Field::Address;
763     $from->add ('foo@foo.example', name => 'F. Foo');
764     my $to = new Message::Field::Address;
765     $to->add ('bar@bar.example', name => 'Mr. Bar');
766     $to->add ('hoge@foo.example', name => 'Hoge-san');
767     $header->add ('From' => $from);
768     $header->add ('To' => $to);
769     $header->add ('Subject' => 'Re: Meeting');
770     $header->add ('References' => '<hoge.msgid%foo@foo.example>');
771     print $header;
772    
773 wakaba 1.14 =head1 ACKNOWLEDGEMENTS
774    
775     Some of codes are taken from other modules such as
776     HTTP::Header, Mail::Header.
777    
778 wakaba 1.1 =head1 LICENSE
779    
780     Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
781    
782     This program is free software; you can redistribute it and/or modify
783     it under the terms of the GNU General Public License as published by
784     the Free Software Foundation; either version 2 of the License, or
785     (at your option) any later version.
786    
787     This program is distributed in the hope that it will be useful,
788     but WITHOUT ANY WARRANTY; without even the implied warranty of
789     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
790     GNU General Public License for more details.
791    
792     You should have received a copy of the GNU General Public License
793     along with this program; see the file COPYING. If not, write to
794     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
795     Boston, MA 02111-1307, USA.
796    
797     =head1 CHANGE
798    
799     See F<ChangeLog>.
800 wakaba 1.17 $Date: 2002/04/19 12:00:36 $
801 wakaba 1.1
802     =cut
803    
804     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24