/[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.14 - (hide annotations) (download)
Wed Apr 3 13:31:36 2002 UTC (22 years, 7 months 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 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.1 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 wakaba 1.14 my %DEFAULT = (
48 wakaba 1.1 capitalize => 1,
49     fold_length => 70,
50 wakaba 1.14 #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 wakaba 1.1 );
59 wakaba 1.14 $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 wakaba 1.4 {$DEFAULT{field_type}->{$_} = 'Message::Field::Structured'}
88 wakaba 1.14 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 wakaba 1.4 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 wakaba 1.14 x-envelope-to x-ml-address x-ml-command x-ml-to x-nfrom x-nto))
94 wakaba 1.4 {$DEFAULT{field_type}->{$_} = 'Message::Field::Address'}
95 wakaba 1.14 for (qw(date date-received delivery-date expires
96     expire-date nntp-posting-date posted reply-by resent-date x-tcup-date))
97 wakaba 1.4 {$DEFAULT{field_type}->{$_} = 'Message::Field::Date'}
98 wakaba 1.14 for (qw(article-updates client-date content-id in-reply-to message-id
99     references resent-message-id see-also supersedes))
100 wakaba 1.6 {$DEFAULT{field_type}->{$_} = 'Message::Field::MsgID'}
101 wakaba 1.7 for (qw(accept accept-charset accept-encoding accept-language
102 wakaba 1.8 content-language
103 wakaba 1.12 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 wakaba 1.8 x-brother x-daughter x-respect x-moe x-syster x-wife))
107 wakaba 1.7 {$DEFAULT{field_type}->{$_} = 'Message::Field::CSV'}
108 wakaba 1.12 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 wakaba 1.1
113 wakaba 1.14 ## 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 wakaba 1.1
182 wakaba 1.14 $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 wakaba 1.1
189     =cut
190    
191     sub new ($;%) {
192     my $class = shift;
193 wakaba 1.14 my $self = bless {}, $class;
194     $self->_init (@_);
195 wakaba 1.1 $self;
196     }
197    
198 wakaba 1.14 =head2 Message::Header->parse ($header, [%initial-fields/options])
199 wakaba 1.1
200 wakaba 1.14 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 wakaba 1.1
204     =cut
205    
206     sub parse ($$;%) {
207     my $class = shift;
208     my $header = shift;
209 wakaba 1.14 my $self = bless {}, $class;
210     $self->_init (@_);
211     $header =~ s/\x0D?\x0A$REG{WSP}/\x20/gos; ## unfold
212 wakaba 1.1 for my $field (split /\x0D?\x0A/, $header) {
213     if ($field =~ /$REG{M_fromline}/) {
214 wakaba 1.9 my $body = $1;
215     $body = $self->_field_body ($body, 'mail-from')
216 wakaba 1.14 if $self->{option}->{parse_all};
217 wakaba 1.9 push @{$self->{field}}, {name => 'mail-from', body => $body};
218 wakaba 1.1 } elsif ($field =~ /$REG{M_field}/) {
219 wakaba 1.9 my ($name, $body) = (lc $1, $2);
220 wakaba 1.1 $name =~ s/$REG{WSP}+$//;
221     $body =~ s/$REG{WSP}+$//;
222 wakaba 1.14 $body = $self->_field_body ($body, $name) if $self->{option}->{parse_all};
223 wakaba 1.9 push @{$self->{field}}, {name => $name, body => $body};
224 wakaba 1.1 }
225     }
226     $self;
227     }
228    
229 wakaba 1.14 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 wakaba 1.1 =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 wakaba 1.5 $field->{body} = $self->_field_body ($field->{body}, $name);
278     return $field->{body};
279 wakaba 1.1 } else {
280 wakaba 1.5 $field->{body} = $self->_field_body ($field->{body}, $name);
281     push @ret, $field->{body};
282 wakaba 1.1 }
283     }
284     }
285 wakaba 1.9 if ($#ret < 0) {
286     return $self->add ($name);
287     }
288 wakaba 1.1 @ret;
289     }
290    
291 wakaba 1.9 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 wakaba 1.2 =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 wakaba 1.4 my $i = shift;
318 wakaba 1.5 $self->{field}->[$i]->{body}
319     = $self->_field_body ($self->{field}->[$i]->{body}, $self->{field}->[$i]->{name});
320     $self->{field}->[$i]->{body};
321 wakaba 1.4 }
322    
323     sub _field_body ($$$) {
324     my $self = shift;
325     my ($body, $name) = @_;
326 wakaba 1.5 unless (ref $body) {
327 wakaba 1.4 my $type = $self->{option}->{field_type}->{$name}
328 wakaba 1.7 || $self->{option}->{field_type}->{':DEFAULT'};
329 wakaba 1.14 eval "require $type" or Carp::croak ("_field_body: $type: $@");
330 wakaba 1.5 unless ($body) {
331 wakaba 1.14 $body = $type->new (-field_name => $name,
332     -format => $self->{option}->{format});
333 wakaba 1.5 } else {
334 wakaba 1.14 $body = $type->parse ($body, -field_name => $name,
335     -format => $self->{option}->{format});
336 wakaba 1.5 }
337 wakaba 1.4 }
338 wakaba 1.5 $body;
339 wakaba 1.2 }
340    
341 wakaba 1.1 =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 wakaba 1.14 =head2 $self->add ($field-name, $field-body, [$name, $body, ...])
356 wakaba 1.1
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 wakaba 1.14 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 wakaba 1.1 =cut
376    
377 wakaba 1.14 sub add ($%) {
378 wakaba 1.1 my $self = shift;
379 wakaba 1.14 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 wakaba 1.8 }
396 wakaba 1.14 $body if $option{parse};
397 wakaba 1.1 }
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 wakaba 1.14 sub replace ($%) {
410 wakaba 1.1 my $self = shift;
411 wakaba 1.14 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 wakaba 1.1 for my $field (@{$self->{field}}) {
425 wakaba 1.14 if (defined $new_field{$field->{name}}) {
426     $body = $new_field {$field->{name}};
427 wakaba 1.1 $field->{body} = $body;
428 wakaba 1.14 $new_field{$field->{name}} = undef;
429 wakaba 1.1 }
430     }
431 wakaba 1.14 for (keys %new_field) {
432     push @{$self->{field}}, {name => $_, body => $new_field{$_}};
433     }
434     $body if $option{parse};
435 wakaba 1.1 }
436    
437 wakaba 1.14 =head2 $self->delete ($field-name, [$name, ...])
438 wakaba 1.1
439     Deletes C<field> named as $field_name.
440    
441     =cut
442    
443 wakaba 1.14 sub delete ($@) {
444 wakaba 1.1 my $self = shift;
445 wakaba 1.14 my %delete;
446     for (@_) {$delete{lc $_} = 1}
447 wakaba 1.1 for my $field (@{$self->{field}}) {
448 wakaba 1.14 undef $field if $delete{$field->{name}};
449 wakaba 1.1 }
450     }
451    
452 wakaba 1.2 =head2 $self->count ([$field_name])
453 wakaba 1.1
454     Returns the number of times the given C<field> appears.
455 wakaba 1.2 If no $field_name is given, returns the number
456     of fields. (Same as $#$self+1)
457 wakaba 1.1
458     =cut
459    
460 wakaba 1.2 sub count ($;$) {
461 wakaba 1.1 my $self = shift;
462     my ($name) = (lc shift);
463 wakaba 1.2 unless ($name) {
464     $self->_delete_empty_field ();
465     return $#{$self->{field}}+1;
466     }
467 wakaba 1.1 my $count = 0;
468     for my $field (@{$self->{field}}) {
469     if ($field->{name} eq $name) {
470     $count++;
471     }
472     }
473     $count;
474     }
475    
476 wakaba 1.14 =head2 $self->rename ($field-name, $new-name, [$old, $new,...])
477 wakaba 1.12
478 wakaba 1.14 Renames C<$field-name> as C<$new-name>.
479 wakaba 1.12
480     =cut
481    
482 wakaba 1.14 sub rename ($%) {
483 wakaba 1.12 my $self = shift;
484 wakaba 1.14 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 wakaba 1.12 for my $field (@{$self->{field}}) {
496 wakaba 1.14 if (length $new_name{$field->{name}}) {
497     $field->{name} = $new_name{$field->{name}};
498 wakaba 1.12 }
499     }
500 wakaba 1.14 $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 wakaba 1.12 }
542    
543 wakaba 1.1 =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 wakaba 1.14 my %params = @_;
552     my %option = %{$self->{option}};
553     for (grep {/^-/} keys %params) {$option{substr ($_, 1)} = $params{$_}}
554 wakaba 1.1 my @ret;
555 wakaba 1.14 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 wakaba 1.12 my $fbody;
565 wakaba 1.14 if (ref $body) {
566     $fbody = $body->stringify (-format => $option{format});
567 wakaba 1.12 } else {
568 wakaba 1.14 $fbody = $body;
569 wakaba 1.12 }
570 wakaba 1.14 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 wakaba 1.5 push @ret, $name.': '.$self->fold ($fbody);
575 wakaba 1.14 });
576 wakaba 1.3 my $ret = join ("\n", @ret);
577 wakaba 1.14 $ret? $ret."\n": '';
578 wakaba 1.1 }
579 wakaba 1.14 *as_string = \&stringify;
580 wakaba 1.1
581 wakaba 1.12 =head2 $self->option ($option_name, [$option_value])
582 wakaba 1.1
583 wakaba 1.12 Set/gets new value of the option.
584 wakaba 1.1
585     =cut
586    
587 wakaba 1.14 sub option ($@) {
588 wakaba 1.1 my $self = shift;
589 wakaba 1.14 if (@_ == 1) {
590     return $self->{option}->{ shift (@_) };
591     }
592     while (my ($name, $value) = splice (@_, 0, 2)) {
593     $name =~ s/^-//;
594 wakaba 1.12 $self->{option}->{$name} = $value;
595     if ($name eq 'format') {
596     for my $f (@{$self->{field}}) {
597 wakaba 1.14 if (ref $f->{body}) {
598     $f->{body}->option (-format => $value);
599 wakaba 1.12 }
600     }
601     }
602     }
603 wakaba 1.1 }
604    
605 wakaba 1.4 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 wakaba 1.7 || $self->{option}->{field_type}->{':DEFAULT'};
614 wakaba 1.4 }
615    
616 wakaba 1.1 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 wakaba 1.11 $x .= "$1\n "
645 wakaba 1.1 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 wakaba 1.14 =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 wakaba 1.1 =head1 EXAMPLE
695    
696     ## Print field list
697    
698     use Message::Header;
699     my $header = Message::Header->parse ($header);
700    
701 wakaba 1.2 for my $i (0..$#$header) {
702     print $header->field_name ($i), "\t=> ", $header->field_body ($i), "\n";
703 wakaba 1.1 }
704    
705    
706     ## Make simple header
707    
708 wakaba 1.2 use Message::Header;
709 wakaba 1.1 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 wakaba 1.14 =head1 ACKNOWLEDGEMENTS
724    
725     Some of codes are taken from other modules such as
726     HTTP::Header, Mail::Header.
727    
728 wakaba 1.1 =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 wakaba 1.14 $Date: 2002/04/01 05:32:37 $
751 wakaba 1.1
752     =cut
753    
754     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24