/[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.26 - (hide annotations) (download)
Mon Jul 8 12:39:39 2002 UTC (24 years ago) by wakaba
Branch: MAIN
Changes since 1.25: +6 -2 lines
2002-07-08  Wakaba <w@suika.fam.cx>

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24