/[suikacvs]/test/cvs
Suika

Contents of /test/cvs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (hide annotations) (download)
Fri Apr 5 14:56:26 2002 UTC (22 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.14: +40 -11 lines
2002-04-05  wakaba <w@suika.fam.cx>

	* Util.pm: Add some functions from Message::Field::Structured.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24