/[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.17 - (hide annotations) (download)
Sat Jun 1 05:40:55 2002 UTC (24 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.16: +42 -11 lines
2002-06-01  wakaba <w@suika.fam.cx>

	* Entity.pm (_encode_body): Some bug fixes and
	better support of CT/CTE/charset.
	(_parse_value): Passes options 'body_default_charset'
	and 'body_default_charset_input' and parameter
	'header' to body class.
	* Util.pm (encode_body_string, encode_header_string):
	Returns minimum charset name if available.

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24