/[suikacvs]/test/cvs
Suika

Contents of /test/cvs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.16 - (show annotations) (download)
Fri Apr 19 12:00:36 2002 UTC (22 years ago) by wakaba
Branch: MAIN
Changes since 1.15: +37 -20 lines
2002-04-05  wakaba <w@suika.fam.cx>

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

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24