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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.24 - (hide annotations) (download)
Sun Jul 7 00:46:07 2002 UTC (24 years ago) by wakaba
Branch: MAIN
Changes since 1.23: +48 -11 lines
2002-07-07  Wakaba <w@suika.fam.cx>

	* Entity.pm (check_md5): New method.
	* Entity.pm (fill_md5, fill_md5_name, recalc_md5): New options.

1 wakaba 1.1
2     =head1 NAME
3    
4     Message::Entity Perl module
5    
6     =head1 DESCRIPTION
7    
8     Perl module for RFC 822/2822 C<message>.
9     MIME multipart will be also supported (but not implemented yet).
10    
11     =cut
12    
13     package Message::Entity;
14     use strict;
15 wakaba 1.15 use vars qw(%DEFAULT $VERSION);
16 wakaba 1.24 $VERSION=do{my @r=(q$Revision: 1.23 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
17 wakaba 1.1
18 wakaba 1.15 require Message::Util;
19 wakaba 1.8 require Message::Header;
20 wakaba 1.15 require Message::MIME::MediaType;
21     require Message::MIME::Encoding;
22 wakaba 1.9 use overload '""' => sub { $_[0]->stringify },
23     fallback => 1;
24 wakaba 1.1
25 wakaba 1.14 ## Initialize of this class -- called by constructors
26     %DEFAULT = (
27 wakaba 1.15 -_METHODS => [qw|header body content_type id|],
28 wakaba 1.17 -_MEMBERS => [qw|header body _cte|],
29 wakaba 1.18 ## entity_header -- Don't clone.
30 wakaba 1.15 -accept_coderange => '7bit', ## 7bit / 8bit / binary
31 wakaba 1.18 #add_ua => 1,
32 wakaba 1.15 -body_default_charset => 'iso-2022-int-1',
33 wakaba 1.18 -body_default_charset_input => 'iso-2022-int-1',
34     -body_default_media_type => 'text',
35     -body_default_media_subtype => 'plain',
36 wakaba 1.17 -cte_default => '7bit',
37 wakaba 1.8 #fill_date => 1,
38 wakaba 1.15 -fill_date_name => 'date',
39 wakaba 1.24 -fill_md5 => 0,
40     -fill_md5_name => 'md5',
41 wakaba 1.8 #fill_msgid => 1,
42 wakaba 1.15 -fill_msgid_name => 'message-id',
43 wakaba 1.19 -force_mime_entity => 0,
44 wakaba 1.15 -format => 'mail-rfc2822',
45 wakaba 1.22 -header_default_charset => 'iso-2022-int-1',
46     -header_default_charset_input => 'iso-2022-int-1',
47 wakaba 1.15 -linebreak_strict => 0, ## BUG: not work perfectly
48     -parse_all => 0,
49 wakaba 1.24 -recalc_md5 => 1,
50 wakaba 1.17 -text_coderange => 'binary',
51     ## '8bit' (MIME text/*) / 'binary' (HTTP text/*)
52 wakaba 1.8 #ua_field_name => 'user-agent',
53 wakaba 1.21 -ua_use_Config => 1,
54     -ua_use_Win32 => 1,
55 wakaba 1.15 -uri_mailto_safe_level => 4,
56 wakaba 1.14 );
57     sub _init ($;%) {
58     my $self = shift;
59     my %options = @_;
60 wakaba 1.15 $self->{option} = {};
61     my $o = Message::Util::make_clone (\%DEFAULT);
62     for my $name (keys %$o) {
63     if (substr ($name, 0, 1) eq '-') {
64     $self->{option}->{substr ($name, 1)} = $$o{$name};
65     }
66     }
67 wakaba 1.14
68 wakaba 1.8 my @new_fields = ();
69     for my $name (keys %options) {
70     if (substr ($name, 0, 1) eq '-') {
71     $self->{option}->{substr ($name, 1)} = $options{$name};
72 wakaba 1.18 } elsif ($name eq 'entity_header') {
73     $self->{entity_header} = $options{entity_header};
74 wakaba 1.8 } else {
75 wakaba 1.18 push @new_fields, ($name => $options{$name});
76 wakaba 1.8 }
77     }
78 wakaba 1.18
79 wakaba 1.8 my $format = $self->{option}->{format};
80 wakaba 1.14 if ($format =~ /http/) {
81 wakaba 1.24 $self->{option}->{fill_date_ns} = $Message::Header::NS_phname2uri{'x-http'};
82     $self->{option}->{fill_msgid_from_ns} = $Message::Header::NS_phname2uri{'x-http'};
83     $self->{option}->{fill_ua_ns} = $Message::Header::NS_phname2uri{'x-http'};
84 wakaba 1.15 $self->{option}->{accept_coderange} = 'binary';
85 wakaba 1.17 $self->{option}->{text_coderange} = 'binary';
86     $self->{option}->{cte_default} = 'binary';
87 wakaba 1.14 } else {
88 wakaba 1.24 $self->{option}->{fill_date_ns} = $Message::Header::NS_phname2uri{'x-rfc822'};
89     $self->{option}->{fill_msgid_from_ns} = $Message::Header::NS_phname2uri{'x-rfc822'};
90     $self->{option}->{fill_ua_ns} = $Message::Header::NS_phname2uri{'x-rfc822'};
91 wakaba 1.17 $self->{option}->{text_coderange} = '8bit';
92 wakaba 1.15 if ($format =~ /news-usefor|smtp-8bitmime/) {
93     $self->{option}->{accept_coderange} = '8bit';
94 wakaba 1.18 #$self->{option}->{cte_default} = '8bit';
95 wakaba 1.15 } else {
96     $self->{option}->{accept_coderange} = '7bit';
97     }
98 wakaba 1.14 }
99 wakaba 1.24 $self->{option}->{fill_msgid_ns} = $Message::Header::NS_phname2uri{'x-rfc822'};
100     $self->{option}->{fill_mimever_ns} = $Message::Header::NS_phname2uri{'x-rfc822'};
101 wakaba 1.8 unless (defined $self->{option}->{fill_date}) {
102 wakaba 1.18 $self->{option}->{fill_date} = $format !~ /mime-entity|cgi|uri-url-mailto/;
103 wakaba 1.8 }
104     unless (defined $self->{option}->{fill_msgid}) {
105 wakaba 1.18 $self->{option}->{fill_msgid} = $format !~ /mime-entity|http|uri-url-mailto/;
106 wakaba 1.8 }
107 wakaba 1.15 unless (defined $self->{option}->{fill_ct}) {
108     $self->{option}->{fill_ct} = $format !~ /http/;
109     }
110 wakaba 1.8 unless (defined $self->{option}->{fill_mimever}) {
111 wakaba 1.18 $self->{option}->{fill_mimever} = $format !~ /http|mime-entity/;
112     }
113     unless (defined $self->{option}->{add_ua}) {
114     $self->{option}->{add_ua} = $format !~ /mime-entity/;
115 wakaba 1.8 }
116 wakaba 1.22 unless ($self->{option}->{fill_ua_name}) {
117 wakaba 1.14 $self->{option}->{fill_ua_name} = $format =~ /response|cgi|uri-url-mailto/?
118 wakaba 1.8 'server': 'user-agent';
119     }
120     @new_fields;
121     }
122    
123     =head1 CONSTRUCTORS
124    
125     The following methods construct new C<Message::Entity> objects:
126 wakaba 1.3
127 wakaba 1.8 =over 4
128    
129 wakaba 1.9 =item Message::Entity->new ([%initial-fields/options])
130 wakaba 1.1
131 wakaba 1.9 Constructs a new C<Message::Entity> object. You might pass some initial
132     C<field-name>-C<field-body> pairs and/or options as parameters to the constructor.
133    
134     Example:
135    
136     $msg = new Message::Entity
137     Date => 'Thu, 03 Feb 1994 00:00:00 +0000',
138     Content_Type => 'text/html',
139     X_URI => '<http://www.foo.example/>',
140     -format => 'mail-rfc2822' ## not to be header field
141     ;
142 wakaba 1.1
143     =cut
144    
145     sub new ($;%) {
146     my $class = shift;
147 wakaba 1.8 my $self = bless {}, $class;
148     my %new_field = $self->_init (@_);
149 wakaba 1.22 if (defined $new_field{body}) {
150 wakaba 1.8 $self->{body} = $new_field{body}; $new_field{body} = undef;
151 wakaba 1.18 $self->{body} = $self->_parse_value ([$self->content_type] => $self->{body})
152 wakaba 1.8 if $self->{option}->{parse_all};
153     }
154 wakaba 1.14 $self->{header} = new Message::Header
155     -format => $self->{option}->{format},
156 wakaba 1.22 -header_default_charset => $self->{option}->{header_default_charset},
157     -header_default_charset_input => $self->{option}->{header_default_charset_input},
158 wakaba 1.8 -parse_all => $self->{option}->{parse_all}, %new_field;
159 wakaba 1.1 $self;
160     }
161    
162 wakaba 1.9 =item Message::Entity->parse ($message, [%options])
163 wakaba 1.1
164 wakaba 1.9 Parses given C<message> (a message entity) and constructs a new C<Message::Entity>
165     object. You might pass some additional C<field-name>-C<field-body> pairs
166     or/and initial options as parameters to the constructor.
167 wakaba 1.8
168 wakaba 1.1 =cut
169    
170     sub parse ($$;%) {
171     my $class = shift;
172     my $message = shift;
173 wakaba 1.8 my $self = bless {}, $class;
174     my %new_field = $self->_init (@_);
175 wakaba 1.20 my $nl = "\x0D\x0A";
176     unless ($self->{option}->{strict_linebreak}) {
177 wakaba 1.23 $nl = Message::Util::decide_newline ($message);
178 wakaba 1.20 }
179 wakaba 1.24 ## BUG: binary unsafe yet!
180 wakaba 1.20 my @header = ();
181     my @body = split /$nl/, $message;
182 wakaba 1.8 while (1) {
183     my $line = shift @body;
184     unless (length($line)) {
185     last;
186 wakaba 1.1 } else {
187 wakaba 1.8 push @header, $line;
188 wakaba 1.1 }
189     }
190 wakaba 1.8 $new_field{body} = undef if $new_field{body};
191     $self->{header} = parse_array Message::Header \@header,
192 wakaba 1.22 -header_default_charset => $self->{option}->{header_default_charset},
193     -header_default_charset_input => $self->{option}->{header_default_charset_input},
194 wakaba 1.8 -parse_all => $self->{option}->{parse_all},
195     -format => $self->{option}->{format}, %new_field;
196 wakaba 1.24 $self->{body} = join ($nl, @body) . $nl;
197 wakaba 1.18 $self->{body} = $self->_parse_value ([$self->content_type] => $self->{body})
198 wakaba 1.8 if $self->{option}->{parse_all};
199 wakaba 1.1 $self;
200     }
201    
202 wakaba 1.9 =back
203    
204 wakaba 1.8 =head1 METHODS
205    
206 wakaba 1.1 =head2 $self->header ([$new_header])
207    
208     Returns Message::Header unless $new_header.
209     Set $new_header instead of current C<header>.
210     If !ref $new_header, Message::Header->parse is automatically
211     called.
212    
213     =cut
214    
215 wakaba 1.9 ## TODO: to be compatible with HTTP::Message
216 wakaba 1.1 sub header ($;$) {
217     my $self = shift;
218     my $new_header = shift;
219     if (ref $new_header) {
220     $self->{header} = $new_header;
221     } elsif ($new_header) {
222 wakaba 1.4 $self->{header} = Message::Header->parse ($new_header,
223 wakaba 1.22 -header_default_charset => $self->{option}->{header_default_charset},
224     -header_default_charset_input => $self->{option}->{header_default_charset_input},
225 wakaba 1.8 -parse_all => $self->{option}->{parse_all},
226     -format => $self->{option}->{format});
227 wakaba 1.1 }
228 wakaba 1.14 unless (ref $self->{header} || length $self->{header}) {
229     $self->{header} = new Message::Header (
230 wakaba 1.22 -header_default_charset => $self->{option}->{header_default_charset},
231     -header_default_charset_input => $self->{option}->{header_default_charset_input},
232 wakaba 1.14 -parse_all => $self->{option}->{parse_all},
233     -format => $self->{option}->{format});
234 wakaba 1.2 }
235 wakaba 1.1 $self->{header};
236     }
237    
238     =head2 $self->body ([$new_body])
239    
240     Returns C<body> as string unless $new_body.
241     Set $new_body instead of current C<body>.
242    
243     =cut
244    
245     sub body ($;$) {
246     my $self = shift;
247     my $new_body = shift;
248     if ($new_body) {
249     $self->{body} = $new_body;
250     }
251 wakaba 1.18 $self->{body} = $self->_parse_value ([$self->content_type] => $self->{body})
252 wakaba 1.3 unless ref $self->{body};
253 wakaba 1.1 $self->{body};
254     }
255    
256 wakaba 1.18 ## [SG]et its entity header. This method is or can be used
257     ## when Message::Entity is used as a body (such as message/rfc822).
258     sub entity_header ($;$) {
259     my $self = shift;
260     my $new_header = shift;
261     if (ref $new_header) {
262     $self->{entity_header} = $new_header;
263     }
264     $self->{entity_header};
265     }
266    
267 wakaba 1.24 ## Note: If you once parse body (including parse_all => 1 option),
268     ## it might make validation failed.
269     sub md5_check ($) {
270     my $self = shift;
271     my $md5f = $self->{header}->field ('content-md5', -new_item_unless_exist => 0);
272     my $md5; $md5 = $md5f->value if ref $md5f;
273     unless ($md5) {
274     Carp::carp "md5_check: MD5 checksum not found";
275     return undef;
276     }
277     my $MD5;
278     eval q{
279     require Digest::MD5; require MIME::Base64;
280     $MD5 = MIME::Base64::encode (Digest::MD5::md5 ($self->{body}));
281     $MD5 =~ tr/\x09\x0A\x0D\x20//d;
282     } or Carp::croak $@;
283     return $MD5 eq $md5? 1 : 0;
284     }
285    
286 wakaba 1.14 ## $self->_parse_value ($type, $value);
287     sub _parse_value ($$$) {
288 wakaba 1.3 my $self = shift;
289 wakaba 1.18 my ($mt,$mst) = @{ shift(@_) };
290 wakaba 1.14 my $value = shift;
291     return $value if ref $value;
292    
293     ## decode
294     $value = $self->_decode_body ($value);
295    
296 wakaba 1.18 my $mt_def = $Message::MIME::MediaType::type{$mt}->{$mst};
297     $mt_def = $Message::MIME::MediaType::type{$mt}->{'/default'} unless ref $mt_def;
298     $mt_def = $Message::MIME::MediaType::type{'/default'}->{'/default'}
299     unless ref $mt_def;
300     my $handler = $mt_def->{handler}
301     || $Message::MIME::MediaType::type{$mt}->{'/default'}->{handler}
302     || $Message::MIME::MediaType::type{'/default'}->{'/default'}->{handler};
303     ## Ummmmmm....
304     if (ref $handler eq 'CODE') {
305     $handler = &$handler ($self, $mt, $mst);
306     }
307     my $vtype = $handler->[0];
308     my %vopt = (
309     -format => $self->{option}->{format},
310     -media_type => $mt,
311     -media_subtype => $mst,
312     -parse_all => $self->{option}->{parse_all},
313     -body_default_charset => $self->{option}->{body_default_charset},
314     -body_default_charset_input => $self->{option}->{body_default_charset_input},
315     entity_header => $self->{header},
316     );
317     ## Media type specified option/parameters
318     if (ref $handler->[1] eq 'HASH') {
319     for (keys %{$handler->[1]}) {
320     $vopt{$_} = ${$handler->[1]}{$_};
321     }
322     }
323     ## Inherited options
324     if (ref $handler->[2] eq 'ARRAY') {
325     for (@{$handler->[2]}) {
326     $vopt{'-'.$_} = $self->{option}->{$_};
327     }
328     }
329    
330 wakaba 1.14 if ($vtype eq ':none:') {
331     return $value;
332     } elsif (defined $value) {
333     eval "require $vtype" or Carp::croak qq{<parse>: $vtype: Can't load package: $@};
334 wakaba 1.18 return $vtype->parse ($value, %vopt);
335 wakaba 1.3 } else {
336 wakaba 1.14 eval "require $vtype" or Carp::croak qq{<parse>: $vtype: Can't load package: $@};
337 wakaba 1.18 return $vtype->new (%vopt);
338 wakaba 1.3 }
339     }
340    
341 wakaba 1.14 sub _decode_body ($$) {
342     my $self = shift;
343     my $value = shift;
344     ## MIME CTE
345 wakaba 1.22 my $cte = $self->{_cte} || '';
346 wakaba 1.14 my $ctef = $self->header->field ('content-transfer-encoding',
347     -new_item_unless_exist => 0);
348     $cte = $ctef->value if ref $ctef;
349 wakaba 1.15 my $f = $Message::MIME::Encoding::DECODER{$cte};
350 wakaba 1.14 if (ref $f) {
351     ($value, $cte) = &$f ($self, $value);
352     }
353     $self->{_cte} = $cte;
354     $value;
355     }
356    
357 wakaba 1.15 sub _encode_body ($$\%) {
358 wakaba 1.14 my $self = shift;
359     my $value = shift;
360 wakaba 1.15 my $option = shift;
361 wakaba 1.14 ## MIME CTE
362 wakaba 1.17 my $current_cte = $self->{_cte} || 'binary';
363     my $ctef = $self->{header}->field ('content-transfer-encoding',
364 wakaba 1.14 -new_item_unless_exist => 0);
365 wakaba 1.15 my $cte = ''; $cte = lc $ctef->value if ref $ctef;
366 wakaba 1.16 my %enoption;
367 wakaba 1.15 ## Get media type of entity body and its accept CTE list
368     my ($mt,$mst) = $self->content_type;
369     my $mt_def = $Message::MIME::MediaType::type{$mt}->{$mst};
370     $mt_def = $Message::MIME::MediaType::type{$mt}->{'/default'}
371 wakaba 1.18 unless ref $mt_def;
372 wakaba 1.15 $mt_def = $Message::MIME::MediaType::type{'/default'}->{'/default'}
373     unless ref $mt_def;
374 wakaba 1.16 $enoption{mt_is_text} = 1
375     if $mt eq 'text' || $mt eq 'multipart' || $mt eq 'message';
376 wakaba 1.23 $enoption{mt_is_text} = 1 if $mt_def->{text_content};
377 wakaba 1.16 my ($charset, $charset_def) = '';
378     if ($mt_def->{mime_charset}) {
379     ## If CT is able to have its charset parameter,
380 wakaba 1.17 my $ct = $self->{header}->field ('content-type',
381 wakaba 1.16 -new_item_unless_exist => 0);
382     $charset = $ct->parameter ('charset') if ref $ct;
383     if ($charset) {
384     $charset_def = $Message::MIME::Charset::CHARSET{$charset};
385     } else {
386     $charset_def = $Message::MIME::Charset::CHARSET{'*default'};
387     ## Note: 'encoding_after_encode' option (available for header
388     ## field, but not for message body) is hardcoded.
389     }
390 wakaba 1.18 } else { ## Don't have mime style "charset" parameter
391     $charset_def = {mime_text => 1};
392 wakaba 1.16 }
393     $charset_def = {} unless ref $charset_def; ## dummy
394 wakaba 1.17 if ($charset_def->{mime_text} != 1) {
395 wakaba 1.18 $enoption{mt_is_text} = 0 if $mt eq 'text';
396 wakaba 1.17 my $ct = $self->{header}->field ('content-type');
397     $ct->not_mime_text ($option->{text_coderange} eq 'binary'? 0:1);
398     }
399 wakaba 1.15 ## If accept CTE list is defined,
400 wakaba 1.16 for my $def ($charset_def, $mt_def) {
401     if (ref $def->{accept_cte} eq 'ARRAY') {
402     my $f = 1; for (@{$def->{accept_cte}}) {
403     if ($cte eq $_) {$f = 0; last}
404     }
405     if ($f) { ## If CTE is not accepted,
406     $cte = $def->{accept_cte}->[0];
407     }
408 wakaba 1.15 }
409     }
410     if ($current_cte eq 'binary' || ($current_cte && $current_cte ne $cte)) {
411     my $de = $Message::MIME::Encoding::DECODER{$current_cte};
412     my $en = $Message::MIME::Encoding::ENCODER{$cte || 'binary'};
413     if (ref $de && ref $en) {
414     my ($e, $decoded);
415     ($decoded, $e) = &$de ($self, $value);
416     ## Check transparent coderange
417 wakaba 1.16 my $cr = $self->Message::MIME::Encoding::decide_coderange
418     ($decoded, \%enoption);
419 wakaba 1.15 if ($option->{accept_coderange} eq '8bit') {
420     if ($cr eq 'binary') {
421 wakaba 1.16 $cte = $charset_def->{cte_7bit_preferred}
422     || $mt_def->{cte_7bit_preferred} || 'base64';
423 wakaba 1.15 $en = $Message::MIME::Encoding::ENCODER{$cte};
424     }
425     } elsif ($option->{accept_coderange} eq '7bit') {
426     if ($cr eq 'binary' || $cr eq '8bit') {
427 wakaba 1.16 $cte = $charset_def->{cte_7bit_preferred}
428     || $mt_def->{cte_7bit_preferred} || 'base64';
429 wakaba 1.15 $en = $Message::MIME::Encoding::ENCODER{$cte};
430 wakaba 1.18 if ($mt eq 'message') {
431     my $ct = $self->{header}->field ('content-type');
432     $ct->not_mime_text ($option->{text_coderange} eq 'binary'? 0:1);
433     }
434 wakaba 1.15 }
435     }
436     if ($e eq 'binary') {
437 wakaba 1.16 ($value, $e) = &$en ($self, $decoded, \%enoption);
438 wakaba 1.17 $e = '' if ($e eq $option->{cte_default});
439     $e = '' if $e eq '7bit'
440     && ( $option->{cte_default} eq '8bit'
441     || $option->{cte_default} eq 'binary');
442     $e = '' if $e eq '8bit' && $option->{cte_default} eq 'binary';
443     if ($e) {
444     $ctef = $self->{header}->field ('content-transfer-encoding')
445 wakaba 1.15 unless ref $ctef;
446     $ctef->value ($e);
447 wakaba 1.17 } elsif (ref $ctef) {
448     $ctef->value ('');
449     }
450 wakaba 1.15 } else {
451 wakaba 1.17 $ctef = $self->{header}->field ('content-transfer-encoding')
452 wakaba 1.15 unless ref $ctef;
453     $ctef->value ($current_cte);
454     }
455 wakaba 1.14 } else { ## Can't encode by given CTE
456 wakaba 1.17 $ctef = $self->{header}->field ('content-transfer-encoding')
457 wakaba 1.15 unless ref $ctef;
458 wakaba 1.14 $ctef->value ($current_cte);
459     }
460     }
461 wakaba 1.17 if (ref $ctef && $ctef->value eq '') {
462     $self->{header}->delete ('content-transfer-encoding');
463     }
464 wakaba 1.14 $value;
465     }
466    
467 wakaba 1.1 =head2 $self->stringify ([%option])
468    
469     Returns the C<message> as a string.
470    
471     =cut
472    
473     sub stringify ($;%) {
474     my $self = shift;
475 wakaba 1.8 my %params = @_;
476     my %option = %{$self->{option}};
477     for (grep {/^-/} keys %params) {$option{substr ($_, 1)} = $params{$_}}
478 wakaba 1.18 my ($header, $body, $body0);
479 wakaba 1.14 if (ref $self->{body}) {
480 wakaba 1.18 $self->{body}->entity_header ($self->{header});
481     $body0 = $self->{body}->stringify (-format => $option{format},
482 wakaba 1.14 -linebreak_strict => $option{linebreak_strict});
483     } else {
484 wakaba 1.18 $body0 = $self->{body};
485 wakaba 1.14 }
486 wakaba 1.18 $body = $self->_encode_body ($body0, \%option);
487 wakaba 1.14 if (ref $self->{header}) {
488 wakaba 1.15 my %exist;
489     for ($self->{header}->field_name_list) {$exist{$_} = 1}
490     my $ns_content = $Message::Header::NS_phname2uri{content};
491 wakaba 1.14 if ($option{fill_date}
492     && !$exist{$option{fill_date_name}.':'.$option{fill_date_ns}}) {
493     $self->{header}->field
494     ($option{fill_date_name}, -ns => $option{fill_date_ns})->unix_time (time);
495     }
496     if ($option{fill_msgid}
497     && !$exist{$option{fill_msgid_name}.':'.$option{fill_msgid_ns}}) {
498     my $from = $self->{header}->field
499     ('from', -ns => $option{fill_msgid_from_ns}, -new_item_unless_exist => 0);
500     $from = $from->addr_spec if ref $from;
501     $self->{header}->field
502     ($option{fill_msgid_name}, -ns => $option{fill_msgid_ns})
503     ->generate (addr_spec => $from)
504 wakaba 1.8 if $from;
505 wakaba 1.15 } # fill_msgid
506 wakaba 1.24 if (($option{fill_md5} && !$exist{ $option{fill_md5_name} .':'. $ns_content})
507     || ($option{recalc_md5} && $exist{ $option{fill_md5_name} .':'. $ns_content})) {
508     my $md5;
509     eval q{
510     require Digest::MD5; require MIME::Base64;
511     $md5 = MIME::Base64::encode (Digest::MD5::md5 ($body0));
512     $md5 =~ tr/\x09\x0A\x0D\x20//d;
513     } or Carp::carp $@;
514     if ($md5) {
515     my $md5f = $self->{header}->field ($option{fill_md5_name}, -ns => $ns_content);
516     $md5f->value ($md5);
517     }
518     }
519 wakaba 1.15 my $ismime = 0;
520     for (keys %exist) {if (/:$ns_content$/) { $ismime = 1; last }}
521 wakaba 1.18 unless ($ismime) {
522 wakaba 1.19 $ismime = 1 if $option{force_mime_entity};
523 wakaba 1.24 $ismime = 1 if $option{fill_md5};
524 wakaba 1.18 $ismime = 1 if $option{body_default_media_type} ne 'text';
525     $ismime = 1 if $option{body_default_media_subtype} ne 'plain';
526     }
527 wakaba 1.15 if ($ismime) {
528     if ($option{fill_ct} && !$exist{'type:'.$ns_content}) {
529     my $ct = $self->{header}->field ('type',
530     -parse => 1, -ns => $ns_content);
531 wakaba 1.18 $ct->media_type ($option{body_default_media_type}.'/'
532     .$option{body_default_media_subtype});
533     $ct->replace (Message::MIME::Charset::name_minimumize ($option{body_default_charset} => $body0));
534 wakaba 1.15 }
535     if ($option{fill_mimever}
536     && !$exist{'mime-version:'.$option{fill_mimever_ns}}) {
537     ## BUG: doesn't support rfc10]49, HTTP (ie. non-MIME) content-*: fields
538 wakaba 1.14 $self->{header}->add ('mime-version' => '1.0',
539     -parse => 0, -ns => $option{fill_mimever_ns});
540 wakaba 1.8 }
541 wakaba 1.15 } # $ismime
542 wakaba 1.14 if ($option{format} =~ /uri-url-mailto/ && $exist{'type:$ns_content'}
543 wakaba 1.12 && $option{uri_mailto_safe_level} > 1) {
544     $self->{header}->field ('content-type')->media_type ('text/plain');
545     }
546 wakaba 1.21 if ($option{add_ua}) {
547     $self->{header}->field ($option{fill_ua_name})->add_our_name (
548     -use_Config => $option{ua_use_Config},
549     -use_Win32 => $option{ua_use_Win32},
550     );
551     }
552 wakaba 1.12 $header = $self->{header}->stringify (-format => $option{format},
553     -linebreak_strict => $option{linebreak_strict},
554     -uri_mailto_safe_level => $option{uri_mailto_safe_level});
555 wakaba 1.7 } else {
556     $header = $self->{header};
557 wakaba 1.12 unless ($option{linebreak_strict}) {
558     ## bare \x0D and bare \x0A are unsafe
559     $header =~ s/\x0D(?=[^\x09\x0A\x20])/\x0D\x20/g;
560     $header =~ s/\x0A(?=[^\x09\x20])/\x0A\x20/g;
561     }
562 wakaba 1.7 }
563 wakaba 1.12 if ($option{format} =~ /uri-url-mailto/) {
564 wakaba 1.14 if ($option{format} =~ /rfc1738/) {
565     my $to = $self->{header}->stringify (-format => $option{format},
566     -uri_mailto_safe_level => $option{uri_mailto_safe_level});
567     $to? 'mailto:'.$to: '';
568     } else {
569     my $f = $option{format}; $f =~ s/-mailto/-mailto-to/;
570     my $to = $self->{header}->stringify (-format => $f,
571     -uri_mailto_safe_level => $option{uri_mailto_safe_level});
572     $body =~ s/([^:@+\$A-Za-z0-9\-_.!~*])/sprintf('%%%02X', ord $1)/ge;
573     if (length $body) {
574     $header .= '&' if $header;
575     $header .= 'body='.$body;
576     }
577     $header = '?'.$header if $header;
578     $to||$header? 'mailto:'.$to.$header: '';
579 wakaba 1.12 }
580     } else {
581 wakaba 1.15 $header .= "\x0D\x0A" if $header && $header !~ /\x0D\x0A$/;
582     $header."\x0D\x0A".$body;
583 wakaba 1.12 }
584 wakaba 1.1 }
585 wakaba 1.8 *as_string = \&stringify;
586 wakaba 1.1
587    
588 wakaba 1.9 =head1 SHORTCUT METHOD FOR MESSAGE PROPERTIES
589    
590     =over 4
591    
592     =item $self->content_type ([%options])
593 wakaba 1.1
594 wakaba 1.9 Returns Internet media type of message body
595     (aka MIME type, content type). Only media type
596     (type/subtype pair) is returned, i.e. no parameter
597     is returned, if any. To get such value, or to set
598     new value, use C<field> method.
599 wakaba 1.1
600 wakaba 1.9 Default is C<text/plain>.
601 wakaba 1.3
602 wakaba 1.9 Example:
603 wakaba 1.3
604 wakaba 1.9 $msg->field ('Content-Type')->media_type ('text/html');
605     print $msg->content_type; ## text/html
606 wakaba 1.3
607     =cut
608    
609     sub content_type ($;%) {
610 wakaba 1.8 my $self = shift;
611 wakaba 1.15 my $ct = $self->{header}->field ('content-type', -new_item_unless_exist => 0);
612     unless (ref $ct) {
613 wakaba 1.18 if ($self->{option}->{body_default_media_type} ne 'text'
614     || $self->{option}->{body_default_media_subtype} ne 'plain') {
615     $ct = $self->{header}->field ('content-type');
616     $ct->media_type_major ($self->{option}->{body_default_media_type});
617     $ct->media_type_minor ($self->{option}->{body_default_media_subtype});
618     }
619     return wantarray? ($self->{option}->{body_default_media_type},
620     $self->{option}->{body_default_media_subtype}):
621     $self->{option}->{body_default_media_type}.'/'
622     .$self->{option}->{body_default_media_subtype};
623 wakaba 1.15 }
624     if (wantarray) {
625     ($ct->media_type_major, $ct->media_type_minor);
626     } else {
627     $ct->media_type;
628     }
629 wakaba 1.1 }
630 wakaba 1.15 *media_type = \&content_type;
631 wakaba 1.1
632 wakaba 1.9 =item $self->id
633    
634     Returns ID of message entity. If there are C<Message-ID:>
635     field, its value is returned. Unless, but there are
636     C<Content-ID:> field, it is returned. Without both of
637     fields, C<""> is returned.
638    
639     =cut
640    
641 wakaba 1.5 sub id ($) {
642     my $self = shift;
643     return scalar $self->{header}->field ('message-id')->id
644     if $self->{header}->field_exist ('message-id');
645 wakaba 1.9 return scalar $self->{header}->field ('content-id')->id
646     if $self->{header}->field_exist ('content-id');
647 wakaba 1.8 '';
648 wakaba 1.5 }
649    
650 wakaba 1.9 =back
651    
652     =head1 MISC. METHODS
653    
654     =over 4
655    
656     =item $self->option ( $option-name / $option-name, $option-value, ...)
657    
658     If @_ == 1, returns option value. Else...
659    
660     Set option value. You can pass multiple option name-value pair
661     as parameter. Example:
662    
663     $msg->option (format => 'mail-rfc822',
664     capitalize => 0);
665     print $msg->option ('format'); ## mail-rfc822
666    
667     =cut
668    
669     sub option ($@) {
670     my $self = shift;
671     if (@_ == 1) {
672     return $self->{option}->{ $_[0] };
673     }
674 wakaba 1.18 my %option = @_;
675 wakaba 1.9 while (my ($name, $value) = splice (@_, 0, 2)) {
676     $self->{option}->{$name} = $value;
677     if ($name eq 'format') {
678     $self->header->option (-format => $value);
679     }
680     }
681 wakaba 1.18 if ($option{-recursive}) {
682     $self->{header}->option (%option);
683     $self->{body}->option (%option) if ref $self->{body};
684     }
685 wakaba 1.9 }
686    
687     =item $self->clone ()
688 wakaba 1.8
689     Returns a copy of Message::Entity object.
690    
691     =cut
692    
693     sub clone ($) {
694     my $self = shift;
695     my $clone = new Message::Entity;
696 wakaba 1.14 $clone->{option} = Message::Util::make_clone ($self->{option});
697     for (@{$self->{option}->{_MEMBERS}}) {
698     $clone->{$_} = Message::Util::make_clone ($self->{$_});
699 wakaba 1.8 }
700     $clone;
701     }
702 wakaba 1.5
703 wakaba 1.14 my %_method_default_list = qw(new 1 parse 1 stringify 1 option 1 clone 1 method_available 1);
704     sub method_available ($$) {
705     my $self = shift;
706     my $name = shift;
707     return 1 if $_method_default_list{$name};
708     for (@{$self->{option}->{_METHODS}}) {
709     return 1 if $_ eq $name;
710     }
711     0;
712     }
713    
714 wakaba 1.9 =back
715    
716 wakaba 1.11 =head1 C<format>
717    
718     =over 2
719    
720     =item mail-rfc650
721    
722     Internet mail message, defined by IETF RFC 650
723    
724     =item mail-rfc724
725    
726     Internet mail message, defined by IETF RFC 724
727    
728     =item mail-rfc733
729    
730     Internet mail message, defined by IETF RFC 733
731    
732     =item mail-rfc822
733    
734     Internet mail message, defined by IETF RFC 822
735    
736     =item mail-rfc2822
737    
738     Internet mail message, defined by IETF RFC 2822
739    
740     =item mime-1.0
741    
742     MIME entity
743    
744     =item mime-1.0-rfc1341
745    
746     MIME entity, defined by RFC 1341 (and RFC 1342)
747    
748     =item mime-1.0-rfc1521
749    
750     MIME entity, defined by RFC 1521 and 1522
751    
752     =item mime-1.0-rfc2045
753    
754     MIME entity, defined by RFC 2045,..., 2049
755    
756     =item news-bnews
757    
758     Usenet Bnews format
759    
760     =item news-rfc850
761    
762     Usenet news format, defined by IETF RFC 850
763    
764     =item news-rfc1036
765    
766     Usenet news format, defined by IETF RFC 1036
767    
768     =item news-son-of-rfc1036
769    
770     Usenet news format, defined by son-of-RFC1036
771    
772     =item news-usefor
773    
774     Usenet news format, defined by usefor-article (IETF Internet Draft)
775    
776     =item http-1.0-rfc1945
777    
778     HTTP/1.0 message, defined by IETF RFC 1945
779    
780     =item http-1.0-rfc1945-request
781    
782     HTTP/1.0 request message, defined by IETF RFC 1945
783    
784     =item http-1.0-rfc1945-response
785    
786     HTTP/1.0 response message, defined by IETF RFC 1945
787    
788     =item http-1.1-rfc2068
789    
790     HTTP/1.1 message, defined by IETF RFC 2068
791    
792     =item http-1.1-rfc2068-request
793    
794     HTTP/1.1 request message, defined by IETF RFC 2068
795    
796     =item http-1.1-rfc2068-response
797    
798     HTTP/1.1 response message, defined by IETF RFC 2068
799    
800     =item http-1.1-rfc2616
801    
802     HTTP/1.1 message, defined by IETF RFC 2616
803    
804     =item http-1.1-rfc2616-request
805    
806     HTTP/1.1 request message, defined by IETF RFC 2616
807    
808     =item http-1.1-rfc2616-response
809    
810     HTTP/1.1 response message, defined by IETF RFC 2616
811    
812     =item http-cgi-1.1
813    
814     CGI/1.1 output (for HTTP), defined by coar-cgi-v11 (IETF Internet Draft)
815    
816     =item http-1.0-cgi-1.1
817    
818     CGI/1.1 output (for HTTP/1.0), defined by coar-cgi-v11 (IETF Internet Draft)
819    
820     =item http-1.1-cgi-1.1
821    
822     CGI/1.1 output (for HTTP/1.1), defined by coar-cgi-v11 (IETF Internet Draft)
823    
824     =item http-cgi-1.2
825    
826     CGI/1.2 output, defined by coar-cgi-v12 (to be IETF Internet Draft)
827    
828     =item http-1.0-cgi-1.2
829    
830     CGI/1.2 output (for HTTP/1.0), defined by coar-cgi-v11 (IETF Internet Draft)
831    
832     =item http-1.1-cgi-1.2
833    
834     CGI/1.2 output (for HTTP/1.1), defined by coar-cgi-v11 (IETF Internet Draft)
835    
836     =item http-sip-2.0
837    
838     SIP/2.0 message, defined by IETF RFC 2543
839    
840     =item http-sip-2.0-request
841    
842     SIP/2.0 request message, defined by IETF RFC 2543
843    
844     =item http-sip-2.0-response
845    
846     SIP/2.0 response message, defined by IETF RFC 2543
847    
848     =item http-sip-cgi
849    
850     SIP/2.0 CGI (IETF Internet Draft)
851    
852     =item cpim-1.0
853    
854     CPIM/1.0 (IETF Internet Draft)
855    
856 wakaba 1.12 =item uri-url-mailto-mail-rfc822, uri-url-mailto-mail-rfc2822
857    
858     mailto: URL scheme
859    
860     =item uri-url-mailto-rfc1738
861    
862     mailto: URL scheme (defined by RFC 1738)
863    
864     =item uri-url-mailto-rfc2368, uri-url-mailto-rfc2822
865    
866     mailto: URL scheme (defined by RFC 2368)
867    
868     =item uri-url-mailto-to-mail-rfc822, uri-url-mailto-to-mail-rfc2822
869    
870     C<to> part of mailto: URL scheme (for internal use only)
871    
872 wakaba 1.11 =back
873    
874 wakaba 1.1 =head1 EXAMPLE
875    
876     use Message::Entity;
877 wakaba 1.9 my $msg = new Message::Entity From => '[email protected]',
878     Subject => 'Example message',
879     To => '[email protected]',
880     -format => 'mail-rfc2822',
881     body => $body;
882 wakaba 1.1 $msg->header ($header);
883     $msg->body ($body);
884     print $msg;
885    
886 wakaba 1.3 =head1 SEE ALSO
887    
888     Message::* Perl modules
889     <http://suika.fam.cx/~wakaba/Message-pm/>
890    
891 wakaba 1.1 =head1 LICENSE
892    
893     Copyright 2002 wakaba E<lt>[email protected]<gt>.
894    
895     This program is free software; you can redistribute it and/or modify
896     it under the terms of the GNU General Public License as published by
897     the Free Software Foundation; either version 2 of the License, or
898     (at your option) any later version.
899    
900     This program is distributed in the hope that it will be useful,
901     but WITHOUT ANY WARRANTY; without even the implied warranty of
902     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
903     GNU General Public License for more details.
904    
905     You should have received a copy of the GNU General Public License
906     along with this program; see the file COPYING. If not, write to
907     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
908     Boston, MA 02111-1307, USA.
909    
910     =head1 CHANGE
911    
912     See F<ChangeLog>.
913 wakaba 1.24 $Date: 2002/07/02 06:37:56 $
914 wakaba 1.1
915     =cut
916    
917     1;

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24