/[suikacvs]/test/cvs
Suika

Contents of /test/cvs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (show annotations) (download)
Wed Apr 3 13:31:36 2002 UTC (22 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.13: +354 -139 lines
2002-04-03  wakaba <w@suika.fam.cx>

	* Entity.pm, Header.pm: Updated.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24