/[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.40 - (hide annotations) (download)
Tue Jan 6 09:02:41 2004 UTC (22 years, 6 months ago) by wakaba
Branch: MAIN
CVS Tags: before-dis2-200411, manakai-release-0-3-2, manakai-release-0-3-1, manakai-release-0-4-0, manakai-200612, HEAD
Branch point for: experimental-xml-parser-200401
Changes since 1.39: +5 -4 lines
(parse): Don't remove all Froms within text when use_magic_line.

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 wakaba 1.37 require 5.6.0; ## (require: v5.6.0 data type)
14 wakaba 1.1 package Message::Entity;
15     use strict;
16 wakaba 1.37 use vars qw(%DEFAULT %REG $VERSION);
17 wakaba 1.40 $VERSION=do{my @r=(q$Revision: 1.39 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
18 wakaba 1.1
19 wakaba 1.15 require Message::Util;
20 wakaba 1.8 require Message::Header;
21 wakaba 1.15 require Message::MIME::MediaType;
22     require Message::MIME::Encoding;
23 wakaba 1.9 use overload '""' => sub { $_[0]->stringify },
24     fallback => 1;
25 wakaba 1.37 *REG = \%Message::Util::REG;
26 wakaba 1.1
27 wakaba 1.14 ## Initialize of this class -- called by constructors
28     %DEFAULT = (
29 wakaba 1.15 -_METHODS => [qw|header body content_type id|],
30 wakaba 1.17 -_MEMBERS => [qw|header body _cte|],
31 wakaba 1.18 ## entity_header -- Don't clone.
32 wakaba 1.15 -accept_coderange => '7bit', ## 7bit / 8bit / binary
33     -body_default_charset => 'iso-2022-int-1',
34 wakaba 1.18 -body_default_charset_input => 'iso-2022-int-1',
35     -body_default_media_type => 'text',
36     -body_default_media_subtype => 'plain',
37 wakaba 1.17 -cte_default => '7bit',
38 wakaba 1.33 -fill_missing_fields => 1,
39     #add_ua => 1,
40     #fill_date => 1,
41     -fill_date_name => 'date',
42     -fill_destination => 0,
43     #fill_destination_ns
44     #fill_destination_resent_ns
45     #fill_from_ns
46     -fill_md5 => 0,
47     -fill_md5_name => 'md5',
48     #fill_msgid => 1,
49     -fill_msgid_name => 'message-id',
50     #fill_sender_ns
51 wakaba 1.39 -fill_source => 0,
52 wakaba 1.33 -recalc_md5 => 1,
53 wakaba 1.19 -force_mime_entity => 0,
54 wakaba 1.15 -format => 'mail-rfc2822',
55 wakaba 1.28 -guess_media_type => 1,
56 wakaba 1.30 #internal_charset_name
57 wakaba 1.22 -header_default_charset => 'iso-2022-int-1',
58     -header_default_charset_input => 'iso-2022-int-1',
59 wakaba 1.15 -linebreak_strict => 0, ## BUG: not work perfectly
60 wakaba 1.37 -output_magic_line => 1,
61 wakaba 1.15 -parse_all => 0,
62 wakaba 1.37 -remove_post_newline => 0,
63     -remove_pre_newline => 0,
64 wakaba 1.17 -text_coderange => 'binary',
65     ## '8bit' (MIME text/*) / 'binary' (HTTP text/*)
66 wakaba 1.8 #ua_field_name => 'user-agent',
67 wakaba 1.21 -ua_use_Config => 1,
68     -ua_use_Win32 => 1,
69 wakaba 1.15 -uri_mailto_safe_level => 4,
70 wakaba 1.37 -use_magic_line => 1,
71 wakaba 1.14 );
72     sub _init ($;%) {
73     my $self = shift;
74     my %options = @_;
75 wakaba 1.15 $self->{option} = {};
76     my $o = Message::Util::make_clone (\%DEFAULT);
77     for my $name (keys %$o) {
78     if (substr ($name, 0, 1) eq '-') {
79     $self->{option}->{substr ($name, 1)} = $$o{$name};
80     }
81     }
82 wakaba 1.14
83 wakaba 1.8 my @new_fields = ();
84     for my $name (keys %options) {
85     if (substr ($name, 0, 1) eq '-') {
86     $self->{option}->{substr ($name, 1)} = $options{$name};
87 wakaba 1.18 } elsif ($name eq 'entity_header') {
88     $self->{entity_header} = $options{entity_header};
89 wakaba 1.8 } else {
90 wakaba 1.18 push @new_fields, ($name => $options{$name});
91 wakaba 1.8 }
92     }
93 wakaba 1.18
94 wakaba 1.8 my $format = $self->{option}->{format};
95 wakaba 1.37 my $ns822 = $Message::Header::NS_phname2uri{'x-rfc822'};
96     my $nshttp = $Message::Header::NS_phname2uri{'x-http'};
97 wakaba 1.14 if ($format =~ /http/) {
98 wakaba 1.37 $self->{option}->{fill_date_ns} = $nshttp unless defined $options{-fill_date_ns};
99     $self->{option}->{fill_from_ns} = $nshttp unless defined $options{-fill_from_ns};
100     $self->{option}->{fill_ua_ns} = $nshttp unless defined $options{-fill_ua_ns};
101     $self->{option}->{fill_source} = 0 unless defined $options{-fill_source};
102 wakaba 1.15 $self->{option}->{accept_coderange} = 'binary';
103 wakaba 1.17 $self->{option}->{text_coderange} = 'binary';
104     $self->{option}->{cte_default} = 'binary';
105 wakaba 1.14 } else {
106 wakaba 1.38 if ($format =~ /mail-rfc822|mail-rfc2822/ && $format !~ /mime-entity/) {
107 wakaba 1.33 $self->{option}->{fill_destination} = 1;
108 wakaba 1.39 $self->{option}->{fill_source} = 1 unless defined $options{-fill_source};
109 wakaba 1.33 }
110 wakaba 1.37 $self->{option}->{fill_date_ns} = $ns822 unless defined $options{-fill_date_ns};
111     $self->{option}->{fill_from_ns} = $ns822 unless defined $options{-fill_from_ns};
112     $self->{option}->{fill_ua_ns} = $ns822 unless defined $options{-fill_ua_ns};
113 wakaba 1.17 $self->{option}->{text_coderange} = '8bit';
114 wakaba 1.15 if ($format =~ /news-usefor|smtp-8bitmime/) {
115     $self->{option}->{accept_coderange} = '8bit';
116     } else {
117     $self->{option}->{accept_coderange} = '7bit';
118     }
119 wakaba 1.14 }
120 wakaba 1.37 for (qw/fill_msgid_ns fill_msgid_from fill_mimever_ns fill_destination_ns fill_sender_ns/) {
121     $self->{option}->{$_} = $ns822;
122 wakaba 1.33 }
123     $self->{option}->{fill_destination_resent_ns} = $Message::Header::NS_phname2uri{'x-rfc822-resent'};
124 wakaba 1.8 unless (defined $self->{option}->{fill_date}) {
125 wakaba 1.18 $self->{option}->{fill_date} = $format !~ /mime-entity|cgi|uri-url-mailto/;
126 wakaba 1.8 }
127     unless (defined $self->{option}->{fill_msgid}) {
128 wakaba 1.18 $self->{option}->{fill_msgid} = $format !~ /mime-entity|http|uri-url-mailto/;
129 wakaba 1.8 }
130 wakaba 1.15 unless (defined $self->{option}->{fill_ct}) {
131     $self->{option}->{fill_ct} = $format !~ /http/;
132     }
133 wakaba 1.8 unless (defined $self->{option}->{fill_mimever}) {
134 wakaba 1.18 $self->{option}->{fill_mimever} = $format !~ /http|mime-entity/;
135     }
136     unless (defined $self->{option}->{add_ua}) {
137     $self->{option}->{add_ua} = $format !~ /mime-entity/;
138 wakaba 1.8 }
139 wakaba 1.22 unless ($self->{option}->{fill_ua_name}) {
140 wakaba 1.14 $self->{option}->{fill_ua_name} = $format =~ /response|cgi|uri-url-mailto/?
141 wakaba 1.8 'server': 'user-agent';
142     }
143 wakaba 1.37 unless (defined $options{-output_magic_line}) {
144     $self->{option}->{output_magic_line} = 0
145     if $format =~ /mail|news|mime/;
146     }
147 wakaba 1.8 @new_fields;
148     }
149    
150     =head1 CONSTRUCTORS
151    
152     The following methods construct new C<Message::Entity> objects:
153 wakaba 1.3
154 wakaba 1.8 =over 4
155    
156 wakaba 1.9 =item Message::Entity->new ([%initial-fields/options])
157 wakaba 1.1
158 wakaba 1.9 Constructs a new C<Message::Entity> object. You might pass some initial
159     C<field-name>-C<field-body> pairs and/or options as parameters to the constructor.
160    
161     Example:
162    
163     $msg = new Message::Entity
164     Content_Type => 'text/html',
165     X_URI => '<http://www.foo.example/>',
166     -format => 'mail-rfc2822' ## not to be header field
167     ;
168 wakaba 1.1
169     =cut
170    
171     sub new ($;%) {
172     my $class = shift;
173 wakaba 1.8 my $self = bless {}, $class;
174     my %new_field = $self->_init (@_);
175 wakaba 1.22 if (defined $new_field{body}) {
176 wakaba 1.8 $self->{body} = $new_field{body}; $new_field{body} = undef;
177 wakaba 1.18 $self->{body} = $self->_parse_value ([$self->content_type] => $self->{body})
178 wakaba 1.8 if $self->{option}->{parse_all};
179     }
180 wakaba 1.14 $self->{header} = new Message::Header
181     -format => $self->{option}->{format},
182 wakaba 1.22 -header_default_charset => $self->{option}->{header_default_charset},
183     -header_default_charset_input => $self->{option}->{header_default_charset_input},
184 wakaba 1.8 -parse_all => $self->{option}->{parse_all}, %new_field;
185 wakaba 1.1 $self;
186     }
187    
188 wakaba 1.9 =item Message::Entity->parse ($message, [%options])
189 wakaba 1.1
190 wakaba 1.9 Parses given C<message> (a message entity) and constructs a new C<Message::Entity>
191     object. You might pass some additional C<field-name>-C<field-body> pairs
192     or/and initial options as parameters to the constructor.
193 wakaba 1.8
194 wakaba 1.1 =cut
195    
196     sub parse ($$;%) {
197     my $class = shift;
198     my $message = shift;
199 wakaba 1.8 my $self = bless {}, $class;
200     my %new_field = $self->_init (@_);
201 wakaba 1.20 my $nl = "\x0D\x0A";
202 wakaba 1.25 unless ($self->{option}->{linebreak_strict}) {
203 wakaba 1.23 $nl = Message::Util::decide_newline ($message);
204 wakaba 1.20 }
205 wakaba 1.37 my ($hdr, $body);
206     $message =~ s/^(?:$nl)+//s if $self->{option}->{remove_pre_newline};
207     $message =~ s/(?:$nl)+$/$nl/s if $self->{option}->{remove_post_newline};
208     if ($self->{option}->{use_magic_line}) {
209     ## TODO: Reset format option?
210 wakaba 1.40 if ($message =~ s/^>?From (.+?)$nl//os) { ## Mail from line
211     ## TODO: Multiple from lines
212 wakaba 1.37 $new_field{'x-rfc822-mail-from'} = $1;
213     } elsif ($message =~ s#^($REG{http_token})\x20($REG{S_uri})\x20($REG{http_token})/([0-9]+)\.([0-9]+)$nl##gs) {
214     ## HTTP Request
215     ($self->{http_method}, $self->{http_request_uri},
216     $self->{http_protocol_name}, $self->{http_protocol_version})
217     = ($1, $2, uc $3, pack ('U2', $4, $5));
218     } elsif ($message =~ s#^($REG{http_token})/([0-9]+)\.([0-9]+)\x20([0-9][0-9][0-9]\x20.*?)$nl##gs) {
219     ## HTTP Response
220     ($self->{http_protocol_name}, $self->{http_protocol_version})
221     = (uc $1, pack ('U2', $2, $3));
222     $new_field{'x-http-status'} = $4;
223     } elsif ($message =~ s#^($REG{http_token})\x20($REG{S_uri})$nl##gs) {
224     ## HTTP/0.9 simple-request
225     ($self->{http_method}, $self->{http_request_uri},
226     $self->{http_protocol_name}, $self->{http_protocol_version})
227     = ($1, $2, 'HTTP', v0.9);
228     $message = $nl . $message; ## Has no header fields
229 wakaba 1.1 }
230     }
231 wakaba 1.37 if ($message !~ s/^$nl//s) {
232     ($hdr, $body) = split /$nl$nl/, $message, 2;
233     } else {
234     $hdr = ''; $body = $message;
235     $body =~ s/^$nl//s;
236     }
237 wakaba 1.8 $new_field{body} = undef if $new_field{body};
238 wakaba 1.37 ## Is this implemention good?
239     $self->{header} = parse Message::Header $hdr,
240 wakaba 1.22 -header_default_charset => $self->{option}->{header_default_charset},
241     -header_default_charset_input => $self->{option}->{header_default_charset_input},
242 wakaba 1.8 -parse_all => $self->{option}->{parse_all},
243 wakaba 1.37 -format => $self->{option}->{format},
244     %new_field; ## Additional header fields
245    
246     $self->{body} = $body;
247     $self->{body} = $self->_parse_value ([ $self->content_type ] => $self->{body})
248 wakaba 1.8 if $self->{option}->{parse_all};
249 wakaba 1.1 $self;
250     }
251    
252 wakaba 1.9 =back
253    
254 wakaba 1.8 =head1 METHODS
255    
256 wakaba 1.1 =head2 $self->header ([$new_header])
257    
258     Returns Message::Header unless $new_header.
259     Set $new_header instead of current C<header>.
260     If !ref $new_header, Message::Header->parse is automatically
261     called.
262    
263     =cut
264    
265 wakaba 1.9 ## TODO: to be compatible with HTTP::Message
266 wakaba 1.1 sub header ($;$) {
267     my $self = shift;
268     my $new_header = shift;
269     if (ref $new_header) {
270     $self->{header} = $new_header;
271     } elsif ($new_header) {
272 wakaba 1.4 $self->{header} = Message::Header->parse ($new_header,
273 wakaba 1.22 -header_default_charset => $self->{option}->{header_default_charset},
274     -header_default_charset_input => $self->{option}->{header_default_charset_input},
275 wakaba 1.8 -parse_all => $self->{option}->{parse_all},
276     -format => $self->{option}->{format});
277 wakaba 1.1 }
278 wakaba 1.14 unless (ref $self->{header} || length $self->{header}) {
279     $self->{header} = new Message::Header (
280 wakaba 1.22 -header_default_charset => $self->{option}->{header_default_charset},
281     -header_default_charset_input => $self->{option}->{header_default_charset_input},
282 wakaba 1.14 -parse_all => $self->{option}->{parse_all},
283     -format => $self->{option}->{format});
284 wakaba 1.2 }
285 wakaba 1.1 $self->{header};
286     }
287    
288     =head2 $self->body ([$new_body])
289    
290     Returns C<body> as string unless $new_body.
291     Set $new_body instead of current C<body>.
292    
293     =cut
294    
295     sub body ($;$) {
296     my $self = shift;
297     my $new_body = shift;
298     if ($new_body) {
299     $self->{body} = $new_body;
300     }
301 wakaba 1.18 $self->{body} = $self->_parse_value ([$self->content_type] => $self->{body})
302 wakaba 1.3 unless ref $self->{body};
303 wakaba 1.1 $self->{body};
304     }
305    
306 wakaba 1.18 ## [SG]et its entity header. This method is or can be used
307     ## when Message::Entity is used as a body (such as message/rfc822).
308     sub entity_header ($;$) {
309     my $self = shift;
310     my $new_header = shift;
311     if (ref $new_header) {
312     $self->{entity_header} = $new_header;
313     }
314     $self->{entity_header};
315     }
316    
317 wakaba 1.24 ## Note: If you once parse body (including parse_all => 1 option),
318     ## it might make validation failed.
319     sub md5_check ($) {
320     my $self = shift;
321     my $md5f = $self->{header}->field ('content-md5', -new_item_unless_exist => 0);
322     my $md5; $md5 = $md5f->value if ref $md5f;
323     unless ($md5) {
324     Carp::carp "md5_check: MD5 checksum not found";
325     return undef;
326     }
327     my $MD5;
328     eval q{
329 wakaba 1.34 require Digest::MD5;
330     $MD5 = ($self->Message::MIME::Encoding::encode_base64 (Digest::MD5::md5 ($self->{body})))[0];
331     $MD5 =~ tr/\x09\x0A\x0D\x20//d;
332     1} or Carp::croak $@;
333 wakaba 1.24 return $MD5 eq $md5? 1 : 0;
334     }
335    
336 wakaba 1.14 ## $self->_parse_value ($type, $value);
337     sub _parse_value ($$$) {
338 wakaba 1.3 my $self = shift;
339 wakaba 1.18 my ($mt,$mst) = @{ shift(@_) };
340 wakaba 1.14 my $value = shift;
341     return $value if ref $value;
342    
343     ## decode
344     $value = $self->_decode_body ($value);
345    
346 wakaba 1.18 my $mt_def = $Message::MIME::MediaType::type{$mt}->{$mst};
347     $mt_def = $Message::MIME::MediaType::type{$mt}->{'/default'} unless ref $mt_def;
348     $mt_def = $Message::MIME::MediaType::type{'/default'}->{'/default'}
349     unless ref $mt_def;
350     my $handler = $mt_def->{handler}
351     || $Message::MIME::MediaType::type{$mt}->{'/default'}->{handler}
352     || $Message::MIME::MediaType::type{'/default'}->{'/default'}->{handler};
353     ## Ummmmmm....
354     if (ref $handler eq 'CODE') {
355     $handler = &$handler ($self, $mt, $mst);
356     }
357     my $vtype = $handler->[0];
358     my %vopt = (
359     -format => $self->{option}->{format},
360 wakaba 1.25 -linebreak_strict => $self->{option}->{linebreak_strict},
361 wakaba 1.18 -media_type => $mt,
362     -media_subtype => $mst,
363     -parse_all => $self->{option}->{parse_all},
364     -body_default_charset => $self->{option}->{body_default_charset},
365     -body_default_charset_input => $self->{option}->{body_default_charset_input},
366 wakaba 1.30 -internal_charset_name => $self->{option}->{internal_charset_name},
367 wakaba 1.18 entity_header => $self->{header},
368     );
369     ## Media type specified option/parameters
370     if (ref $handler->[1] eq 'HASH') {
371     for (keys %{$handler->[1]}) {
372     $vopt{$_} = ${$handler->[1]}{$_};
373     }
374     }
375     ## Inherited options
376     if (ref $handler->[2] eq 'ARRAY') {
377     for (@{$handler->[2]}) {
378     $vopt{'-'.$_} = $self->{option}->{$_};
379     }
380     }
381    
382 wakaba 1.14 if ($vtype eq ':none:') {
383     return $value;
384     } elsif (defined $value) {
385     eval "require $vtype" or Carp::croak qq{<parse>: $vtype: Can't load package: $@};
386 wakaba 1.18 return $vtype->parse ($value, %vopt);
387 wakaba 1.3 } else {
388 wakaba 1.14 eval "require $vtype" or Carp::croak qq{<parse>: $vtype: Can't load package: $@};
389 wakaba 1.18 return $vtype->new (%vopt);
390 wakaba 1.3 }
391     }
392    
393 wakaba 1.14 sub _decode_body ($$) {
394     my $self = shift;
395     my $value = shift;
396     ## MIME CTE
397 wakaba 1.22 my $cte = $self->{_cte} || '';
398 wakaba 1.14 my $ctef = $self->header->field ('content-transfer-encoding',
399     -new_item_unless_exist => 0);
400     $cte = $ctef->value if ref $ctef;
401 wakaba 1.15 my $f = $Message::MIME::Encoding::DECODER{$cte};
402 wakaba 1.14 if (ref $f) {
403     ($value, $cte) = &$f ($self, $value);
404     }
405     $self->{_cte} = $cte;
406     $value;
407     }
408    
409 wakaba 1.15 sub _encode_body ($$\%) {
410 wakaba 1.14 my $self = shift;
411     my $value = shift;
412 wakaba 1.15 my $option = shift;
413 wakaba 1.14 ## MIME CTE
414 wakaba 1.17 my $current_cte = $self->{_cte} || 'binary';
415     my $ctef = $self->{header}->field ('content-transfer-encoding',
416 wakaba 1.14 -new_item_unless_exist => 0);
417 wakaba 1.15 my $cte = ''; $cte = lc $ctef->value if ref $ctef;
418 wakaba 1.16 my %enoption;
419 wakaba 1.15 ## Get media type of entity body and its accept CTE list
420     my ($mt,$mst) = $self->content_type;
421     my $mt_def = $Message::MIME::MediaType::type{$mt}->{$mst};
422     $mt_def = $Message::MIME::MediaType::type{$mt}->{'/default'}
423 wakaba 1.18 unless ref $mt_def;
424 wakaba 1.15 $mt_def = $Message::MIME::MediaType::type{'/default'}->{'/default'}
425     unless ref $mt_def;
426 wakaba 1.16 $enoption{mt_is_text} = 1
427     if $mt eq 'text' || $mt eq 'multipart' || $mt eq 'message';
428 wakaba 1.23 $enoption{mt_is_text} = 1 if $mt_def->{text_content};
429 wakaba 1.16 my ($charset, $charset_def) = '';
430     if ($mt_def->{mime_charset}) {
431     ## If CT is able to have its charset parameter,
432 wakaba 1.17 my $ct = $self->{header}->field ('content-type',
433 wakaba 1.16 -new_item_unless_exist => 0);
434     $charset = $ct->parameter ('charset') if ref $ct;
435     if ($charset) {
436     $charset_def = $Message::MIME::Charset::CHARSET{$charset};
437     } else {
438     $charset_def = $Message::MIME::Charset::CHARSET{'*default'};
439 wakaba 1.31 ## Note: 'encoding_after_encode' option's value is hardcoded.
440 wakaba 1.16 }
441 wakaba 1.18 } else { ## Don't have mime style "charset" parameter
442     $charset_def = {mime_text => 1};
443 wakaba 1.16 }
444     $charset_def = {} unless ref $charset_def; ## dummy
445 wakaba 1.31 #if ($charset_def->{mime_text} != 1) { ## See also Note above
446     if (Message::MIME::Charset::is_mime_text ($charset || '*default') != 1) {
447 wakaba 1.18 $enoption{mt_is_text} = 0 if $mt eq 'text';
448 wakaba 1.17 my $ct = $self->{header}->field ('content-type');
449     $ct->not_mime_text ($option->{text_coderange} eq 'binary'? 0:1);
450     }
451 wakaba 1.15 ## If accept CTE list is defined,
452 wakaba 1.16 for my $def ($charset_def, $mt_def) {
453     if (ref $def->{accept_cte} eq 'ARRAY') {
454     my $f = 1; for (@{$def->{accept_cte}}) {
455     if ($cte eq $_) {$f = 0; last}
456     }
457     if ($f) { ## If CTE is not accepted,
458     $cte = $def->{accept_cte}->[0];
459     }
460 wakaba 1.15 }
461     }
462     if ($current_cte eq 'binary' || ($current_cte && $current_cte ne $cte)) {
463     my $de = $Message::MIME::Encoding::DECODER{$current_cte};
464     my $en = $Message::MIME::Encoding::ENCODER{$cte || 'binary'};
465     if (ref $de && ref $en) {
466     my ($e, $decoded);
467     ($decoded, $e) = &$de ($self, $value);
468     ## Check transparent coderange
469 wakaba 1.16 my $cr = $self->Message::MIME::Encoding::decide_coderange
470     ($decoded, \%enoption);
471 wakaba 1.15 if ($option->{accept_coderange} eq '8bit') {
472     if ($cr eq 'binary') {
473 wakaba 1.16 $cte = $charset_def->{cte_7bit_preferred}
474     || $mt_def->{cte_7bit_preferred} || 'base64';
475 wakaba 1.15 $en = $Message::MIME::Encoding::ENCODER{$cte};
476     }
477     } elsif ($option->{accept_coderange} eq '7bit') {
478     if ($cr eq 'binary' || $cr eq '8bit') {
479 wakaba 1.16 $cte = $charset_def->{cte_7bit_preferred}
480     || $mt_def->{cte_7bit_preferred} || 'base64';
481 wakaba 1.15 $en = $Message::MIME::Encoding::ENCODER{$cte};
482 wakaba 1.18 if ($mt eq 'message') {
483     my $ct = $self->{header}->field ('content-type');
484     $ct->not_mime_text ($option->{text_coderange} eq 'binary'? 0:1);
485     }
486 wakaba 1.15 }
487     }
488     if ($e eq 'binary') {
489 wakaba 1.16 ($value, $e) = &$en ($self, $decoded, \%enoption);
490 wakaba 1.17 $e = '' if ($e eq $option->{cte_default});
491     $e = '' if $e eq '7bit'
492     && ( $option->{cte_default} eq '8bit'
493     || $option->{cte_default} eq 'binary');
494     $e = '' if $e eq '8bit' && $option->{cte_default} eq 'binary';
495     if ($e) {
496     $ctef = $self->{header}->field ('content-transfer-encoding')
497 wakaba 1.15 unless ref $ctef;
498     $ctef->value ($e);
499 wakaba 1.17 } elsif (ref $ctef) {
500     $ctef->value ('');
501     }
502 wakaba 1.15 } else {
503 wakaba 1.17 $ctef = $self->{header}->field ('content-transfer-encoding')
504 wakaba 1.15 unless ref $ctef;
505     $ctef->value ($current_cte);
506     }
507 wakaba 1.14 } else { ## Can't encode by given CTE
508 wakaba 1.17 $ctef = $self->{header}->field ('content-transfer-encoding')
509 wakaba 1.15 unless ref $ctef;
510 wakaba 1.14 $ctef->value ($current_cte);
511     }
512     }
513 wakaba 1.17 if (ref $ctef && $ctef->value eq '') {
514     $self->{header}->delete ('content-transfer-encoding');
515     }
516 wakaba 1.14 $value;
517     }
518    
519 wakaba 1.1 =head2 $self->stringify ([%option])
520    
521     Returns the C<message> as a string.
522    
523     =cut
524    
525     sub stringify ($;%) {
526     my $self = shift;
527 wakaba 1.8 my %params = @_;
528     my %option = %{$self->{option}};
529     for (grep {/^-/} keys %params) {$option{substr ($_, 1)} = $params{$_}}
530 wakaba 1.18 my ($header, $body, $body0);
531 wakaba 1.14 if (ref $self->{body}) {
532 wakaba 1.18 $self->{body}->entity_header ($self->{header});
533 wakaba 1.27 $body0 = $self->{body}->stringify (-parent_format => $option{format},
534 wakaba 1.14 -linebreak_strict => $option{linebreak_strict});
535     } else {
536 wakaba 1.18 $body0 = $self->{body};
537 wakaba 1.14 }
538 wakaba 1.18 $body = $self->_encode_body ($body0, \%option);
539 wakaba 1.14 if (ref $self->{header}) {
540 wakaba 1.15 my $ns_content = $Message::Header::NS_phname2uri{content};
541 wakaba 1.33 my $filler;
542     $filler = sub {
543     my ($hdr, $exist, $hdr_option) = @_;
544     ## Date: (RFC 822, HTTP)
545     if ($option{fill_date}
546 wakaba 1.34 && !$exist->{$option{fill_date_name}.':'.$option{fill_date_ns}}) {
547     $hdr->field
548 wakaba 1.33 ($option{fill_date_name}, -ns => $option{fill_date_ns})->unix_time (time);
549     }
550     ## Message-ID: (RFC 822)
551     if ($option{fill_msgid}
552 wakaba 1.34 && !$exist->{$option{fill_msgid_name}.':'.$option{fill_msgid_ns}}) {
553     my $from = $hdr->field
554 wakaba 1.33 ('from', -ns => $option{fill_msgid_from_ns}, -new_item_unless_exist => 0);
555     $from = $from->addr_spec if ref $from;
556 wakaba 1.34 $hdr->field ($option{fill_msgid_name}, -ns => $option{fill_msgid_ns})
557     ->generate (addr_spec => $from) if $from;
558 wakaba 1.33 } # fill_msgid
559     ## To:, CC:, BCC:, Resent-To:, Resent-Cc:, Resent-Bcc: (RFC 822)
560     if ($option{fill_destination}) {
561 wakaba 1.34 if ( !$exist->{ 'to:'.$option{fill_destination_ns} }
562     && !$exist->{ 'cc:'.$option{fill_destination_ns} }
563     && !$exist->{ 'bcc:'.$option{fill_destination_ns} }
564     && !$exist->{ 'to:'.$option{fill_destination_resent_ns} }
565     && !$exist->{ 'cc:'.$option{fill_destination_resent_ns} }
566     && !$exist->{ 'bcc:'.$option{fill_destination_resent_ns} } ) {
567 wakaba 1.33 $hdr->add (bcc => '');
568     }
569     }
570     ## From:, Sender:
571     if ($option{fill_source}) {
572     ## From:
573 wakaba 1.34 if (!$exist->{ 'from:'.$option{fill_from_ns} }) {
574 wakaba 1.33 $hdr->add (from => 'Unknown source <[email protected]>',
575     -ns => $option{fill_from_ns});
576     ## From: exists, Sender: not exist
577 wakaba 1.34 } elsif (!$exist->{ 'sender:'.$option{fill_sender_ns} }) {
578 wakaba 1.33 my $from = $hdr->field ('from', -ns => $option{fill_from_ns});
579     if ($from->count > 1) {
580     $hdr->field ('sender', -ns => $option{fill_sender_ns})
581     ->add ($from->item (0, -by => 'index'));
582     }
583     }
584     }
585     ## Content-MD5:
586 wakaba 1.34 if (($option{fill_md5} && !$exist->{ $option{fill_md5_name} .':'. $ns_content})
587     || ($option{recalc_md5} && $exist->{ $option{fill_md5_name} .':'. $ns_content})) {
588 wakaba 1.33 my $md5;
589     eval q{
590 wakaba 1.34 require Digest::MD5;
591     $md5 = ($self->Message::MIME::Encoding::encode_base64 (Digest::MD5::md5 ($body0)))[0];
592 wakaba 1.33 $md5 =~ tr/\x09\x0A\x0D\x20//d;
593 wakaba 1.34 1} or Carp::carp $@;
594 wakaba 1.33 if ($md5) {
595 wakaba 1.34 my $md5f = $hdr->field ($option{fill_md5_name}, -ns => $ns_content);
596 wakaba 1.33 $md5f->value ($md5);
597     }
598 wakaba 1.24 }
599 wakaba 1.33 my $ismime = 0;
600 wakaba 1.34 for (keys %$exist) {if (/:$ns_content$/) { $ismime = 1; last }}
601 wakaba 1.33 unless ($ismime) {
602 wakaba 1.34 $ismime = 1 if $option{force_mime_entity}
603     || $option{fill_md5}
604     || $option{body_default_media_type} ne 'text'
605     || $option{body_default_media_subtype} ne 'plain';
606 wakaba 1.15 }
607 wakaba 1.33 if ($ismime) {
608     ## Content-Type: (MIME, HTTP)
609 wakaba 1.34 if ($option{fill_ct} && !$exist->{'type:'.$ns_content}) {
610     my $ct = $hdr->field ('type', -ns => $ns_content);
611 wakaba 1.33 $ct->media_type ($option{body_default_media_type}.'/'
612     .$option{body_default_media_subtype});
613     $ct->replace (Message::MIME::Charset::name_minimumize ($option{body_default_charset} => $body0));
614     }
615     ## MIME-Version: (MIME)
616     if ($option{fill_mimever}
617 wakaba 1.34 && !$exist->{'mime-version:'.$option{fill_mimever_ns}}) {
618     ## BUG: doesn't support rfc1049, HTTP (ie. non-MIME) content-*: fields
619     $hdr->add ('mime-version' => '1.0',
620 wakaba 1.33 -parse => 0, -ns => $option{fill_mimever_ns});
621     }
622     } # $ismime
623     ## User-Agent: (USEFOR, HTTP)
624     if ($option{add_ua}) {
625 wakaba 1.34 $hdr->field ($option{fill_ua_name})->add_our_name (
626 wakaba 1.33 -use_Config => $option{ua_use_Config},
627     -use_Win32 => $option{ua_use_Win32},
628 wakaba 1.40 -date => q$Date: 2002/12/28 09:10:16 $,
629 wakaba 1.33 );
630 wakaba 1.8 }
631 wakaba 1.33 } if $option{fill_missing_fields};
632    
633     if ($option{format} =~ /uri-url-mailto/
634     && $self->{header}->field_exist ('type', -ns => $ns_content)
635 wakaba 1.12 && $option{uri_mailto_safe_level} > 1) {
636 wakaba 1.33 $self->{header}->field ('type', -ns => $ns_content)->media_type ('text/plain');
637 wakaba 1.12 }
638 wakaba 1.33 $header = $self->{header}->stringify (
639     -format => $option{format},
640     -linebreak_strict => $option{linebreak_strict},
641     -uri_mailto_safe_level => $option{uri_mailto_safe_level},
642     ($filler? (-hook_stringify_fill_fields => $filler) :()),
643     );
644 wakaba 1.7 } else {
645     $header = $self->{header};
646 wakaba 1.12 unless ($option{linebreak_strict}) {
647     ## bare \x0D and bare \x0A are unsafe
648     $header =~ s/\x0D(?=[^\x09\x0A\x20])/\x0D\x20/g;
649     $header =~ s/\x0A(?=[^\x09\x20])/\x0A\x20/g;
650     }
651 wakaba 1.7 }
652 wakaba 1.12 if ($option{format} =~ /uri-url-mailto/) {
653 wakaba 1.14 if ($option{format} =~ /rfc1738/) {
654     my $to = $self->{header}->stringify (-format => $option{format},
655     -uri_mailto_safe_level => $option{uri_mailto_safe_level});
656     $to? 'mailto:'.$to: '';
657     } else {
658     my $f = $option{format}; $f =~ s/-mailto/-mailto-to/;
659     my $to = $self->{header}->stringify (-format => $f,
660     -uri_mailto_safe_level => $option{uri_mailto_safe_level});
661     $body =~ s/([^:@+\$A-Za-z0-9\-_.!~*])/sprintf('%%%02X', ord $1)/ge;
662     if (length $body) {
663     $header .= '&' if $header;
664     $header .= 'body='.$body;
665     }
666     $header = '?'.$header if $header;
667     $to||$header? 'mailto:'.$to.$header: '';
668 wakaba 1.12 }
669     } else {
670 wakaba 1.37 ## Magic line (<- named by the author of this module:-)
671     my $mline;
672     if ($option{use_magic_line} && $option{output_magic_line}) {
673     if ($option{format} =~ /mail|news/ && ref $self->{header}) {
674     my $mfrom = $self->{header}->field ('mail-from', -new_item_unless_exist=>0);
675     $mline = sprintf 'From %s', $mfrom->value if ref $mfrom;
676     } elsif ($option{format} =~ /http.+?request/) {
677     $mline = sprintf '%s %s %s/%vd', $self->{http_method} || 'GET',
678     $self->{http_request_uri} || '/', $self->{http_protocol_name} || 'HTTP',
679     $self->{http_protocol_version} || v1.0;
680     } elsif ($option{format} =~ /http.+?response/ && ref $self->{header}
681     && $option{format} !~ /cgi/) {
682     my $s = $self->{header}->field ('x-http-status');
683     $mline = sprintf '%s/%vd %s', $self->{http_protocol_name} || 'HTTP',
684     $self->{http_protocol_version} || v1.0, $s->value || '200 OK';
685     }
686     }
687     $mline .= "\x0D\x0A" if $mline;
688     $mline = '' unless $mline;
689    
690 wakaba 1.15 $header .= "\x0D\x0A" if $header && $header !~ /\x0D\x0A$/;
691 wakaba 1.37 $mline.$header."\x0D\x0A".$body;
692 wakaba 1.12 }
693 wakaba 1.1 }
694 wakaba 1.8 *as_string = \&stringify;
695 wakaba 1.1
696    
697 wakaba 1.9 =head1 SHORTCUT METHOD FOR MESSAGE PROPERTIES
698    
699     =over 4
700    
701     =item $self->content_type ([%options])
702 wakaba 1.1
703 wakaba 1.9 Returns Internet media type of message body
704     (aka MIME type, content type). Only media type
705     (type/subtype pair) is returned, i.e. no parameter
706     is returned, if any. To get such value, or to set
707     new value, use C<field> method.
708 wakaba 1.1
709 wakaba 1.9 Default is C<text/plain>.
710 wakaba 1.3
711 wakaba 1.9 Example:
712 wakaba 1.3
713 wakaba 1.9 $msg->field ('Content-Type')->media_type ('text/html');
714     print $msg->content_type; ## text/html
715 wakaba 1.3
716     =cut
717    
718     sub content_type ($;%) {
719 wakaba 1.8 my $self = shift;
720 wakaba 1.15 my $ct = $self->{header}->field ('content-type', -new_item_unless_exist => 0);
721 wakaba 1.28 my ($mt, $mst);
722 wakaba 1.15 unless (ref $ct) {
723 wakaba 1.28 $mt = $self->{option}->{body_default_media_type};
724     $mst = $self->{option}->{body_default_media_subtype};
725     if ($mt ne 'text' || $mst ne 'plain') {
726 wakaba 1.18 $ct = $self->{header}->field ('content-type');
727 wakaba 1.28 $ct->media_type_major ($mt);
728     $ct->media_type_minor ($mst);
729     }
730 wakaba 1.37 if ($self->{option}->{guess_media_type} && $self->{body} && !ref $self->{body}
731     && $self->{option}->{format} =~ /mail|news/) {
732 wakaba 1.29 if ($self->{body} =~ /^-----BEGIN PGP SIGNED MESSAGE-----\x0D?$/m
733     && $self->{body} =~ /^-----BEGIN PGP SIGNATURE-----\x0D?$/m
734     && $self->{body} =~ /^-----END PGP SIGNATURE-----\x0D?$/m) {
735     $ct = $self->{header}->field ('content-type') unless ref $ct;
736     $mt = $ct->media_type_major ('text');
737     $mst = $ct->media_type_minor ('x-pgp-cleartext-signed');
738     } elsif ($self->{body} =~ /^-----BEGIN PGP [A-Z\x20]+-----\x0D?$/m
739     && $self->{body} =~ /^-----END PGP [A-Z\x20]+-----\x0D?$/m) {
740     $ct = $self->{header}->field ('content-type') unless ref $ct;
741     $mt = $ct->media_type_major ('application');
742     $mst = $ct->media_type_minor ('pgp');
743     $ct->parameter (format => 'text');
744     } elsif ($self->{body} =~ /^-+ start of forwarded message \(RFC 934 encapsulation\) -+\x0D?$/m) {
745     $ct = $self->{header}->field ('content-type') unless ref $ct;
746     $mt = $ct->media_type_major ('text');
747     $mst = $ct->media_type_minor ('x-message-rfc934');
748     } elsif ($self->{body} =~ /^-{70,70}\x0D?$/m
749     && $self->{body} =~ /^-{30,30}\x0D?$/m
750     && $self->{body} =~ /\x0D?\x0A-{30,30}\x0D?\x0A\x0D?\x0AEnd of.+?Digest.*?\x0D?\x0A\*+(?:\x0D?\x0A)*$/s) {
751     $ct = $self->{header}->field ('content-type') unless ref $ct;
752     $mt = $ct->media_type_major ('text');
753     $mst = $ct->media_type_minor ('x-message-rfc1153');
754     } elsif ($self->{body} =~ /^-----PRIVACY-ENHANCED MESSAGE BOUNDARY-----\x0D?$/m) {
755     $ct = $self->{header}->field ('content-type') unless ref $ct;
756     $mt = $ct->media_type_major ('text');
757     $mst = $ct->media_type_minor ('x-message-pem');
758 wakaba 1.37 } elsif ($self->{body} =~ /^#(?:HELO|EHLO)/mi
759     && $self->{body} =~ /^#MAIL FROM:/mi
760     && $self->{body} !~ /^[^#]/m) {
761     ## RFC 976 Batch SMTP (BSMTP) message
762     $ct = $self->{header}->field ('content-type') unless ref $ct;
763     $mt = $ct->media_type_major ('application');
764     $mst = $ct->media_type_minor ('x-batch-smtp');
765 wakaba 1.29 }
766 wakaba 1.28 }
767     } else {
768     ($mt, $mst) = ($ct->media_type_major, $ct->media_type_minor);
769     }
770     if ($self->{option}->{guess_media_type}) {
771     if ($mt eq 'text' && $mst eq 'plain') {
772     my $mls = $self->{header}->field ('x-mlserver', -new_item_unless_exist => 0);
773     if (ref $mls && $mls =~ /fml/) {
774     my $s = $self->{header}->field ('subject', -new_item_unless_exist => 0);
775     if (index ($s, 'RFC934(mh-burst)') >= 0) {
776     $ct = $self->{header}->field ('content-type') unless ref $ct;
777 wakaba 1.29 $mt = $ct->media_type_major ('text');
778     $mst = $ct->media_type_minor ('x-message-rfc934');
779     $ct->delete ('charset');
780     } elsif (index ($s, 'Digest (RFC1153)') >= 0) {
781     $ct = $self->{header}->field ('content-type') unless ref $ct;
782     $mt = $ct->media_type_major ('text');
783     $mst = $ct->media_type_minor ('x-message-rfc1153');
784 wakaba 1.28 $ct->delete ('charset');
785     }
786     }
787 wakaba 1.18 }
788 wakaba 1.15 }
789     if (wantarray) {
790 wakaba 1.28 ($mt, $mst);
791 wakaba 1.15 } else {
792 wakaba 1.38 ref $ct ? $ct->media_type : sprintf '%s/%s', $mt, $mst;
793 wakaba 1.15 }
794 wakaba 1.1 }
795 wakaba 1.15 *media_type = \&content_type;
796 wakaba 1.1
797 wakaba 1.9 =item $self->id
798    
799     Returns ID of message entity. If there are C<Message-ID:>
800     field, its value is returned. Unless, but there are
801     C<Content-ID:> field, it is returned. Without both of
802     fields, C<""> is returned.
803    
804     =cut
805    
806 wakaba 1.5 sub id ($) {
807     my $self = shift;
808     return scalar $self->{header}->field ('message-id')->id
809     if $self->{header}->field_exist ('message-id');
810 wakaba 1.9 return scalar $self->{header}->field ('content-id')->id
811     if $self->{header}->field_exist ('content-id');
812 wakaba 1.8 '';
813 wakaba 1.5 }
814    
815 wakaba 1.35 sub sender ($;%) {
816     my $self = shift;
817     my %params = @_;
818     my %option = %{$self->{option}};
819     $option{use_x_envelope_from} = 1; ## X-Envelope-From:
820     $option{use_normal} = 1; ## From:, Sender:
821     $option{use_resent} = 1; ## Resent-From:, Resent-Sender:
822     my $hdr = $self->{header};
823     if ($option{use_x_envelope_from} && $hdr->field_exist ('x-envelope-from')) {
824     return $hdr->field ('x-envelope-from')->addr_spec;
825     } elsif ($option{use_resent} && $hdr->field_exist ('resent-sender')) {
826     ## TODO: Resent block support
827     return $hdr->field ('resent-sender')->addr_spec;
828     } elsif ($option{use_resent} && $hdr->field_exist ('resent-from')) {
829     ## TODO: Resent block support
830     return $hdr->field ('resent-from')->addr_spec;
831     } elsif ($option{use_normal} && $hdr->field_exist ('sender')) {
832     return $hdr->field ('sender')->addr_spec;
833     } elsif ($option{use_normal} && $hdr->field_exist ('from')) {
834     return $hdr->field ('from')->addr_spec;
835     }
836     undef;
837     }
838    
839     sub destination ($;%) {
840     my $self = shift;
841     my %params = @_;
842     my %option = %{$self->{option}};
843     $option{use_x_envelope_to} = 1; ## X-Envelope-To:
844     $option{use_normal} = 1; ## To:, Cc:, Bcc:
845     $option{use_resent} = 1; ## Resent-To:, Resent-Cc:, Resent-Bcc:
846     for (grep {/^-/} keys %params) {$option{substr ($_, 1)} = $params{$_}}
847     my $hdr = $self->{header};
848     my @to;
849 wakaba 1.37 if ($option{use_x_envelope_to} && $hdr->field_exist ('x-rfc822-x-envelope-to')) {
850     @to = $hdr->field ('x-rfc822-x-envelope-to')->addr_spec;
851     } elsif ($option{use_resent} && $hdr->field_exist ('x-rfc822-resent-from')) {
852 wakaba 1.35 ## TODO: Resent block support
853 wakaba 1.37 @to = ($hdr->field ('x-rfc822-resent-to')->addr_spec,
854     $hdr->field ('x-rfc822-resent-cc')->addr_spec,
855     $hdr->field ('x-rfc822-resent-bcc')->addr_spec);
856 wakaba 1.35 } elsif ($option{use_normal}) {
857 wakaba 1.37 @to = ($hdr->field ('x-rfc822-to')->addr_spec,
858     $hdr->field ('x-rfc822-cc')->addr_spec,
859     $hdr->field ('x-rfc822-bcc')->addr_spec);
860 wakaba 1.35 }
861     @to;
862     }
863    
864 wakaba 1.36 sub list_name ($) {
865     my $self = shift;
866     my $hdr = $self->{header};
867     if ($hdr->field_exist ('list-id')) {
868     my $lname = $hdr->field ('list-id')->display_name;
869     return $lname if length $lname;
870     }
871     my $v = sub {
872     my $name = shift;
873     my $f = $hdr->field ($name, -new_item_unless_exist => 0);
874     return $f->value if ref $f;
875     undef;
876     };
877     ## BUG: list-name "0" is not supported.
878     my $lname = &$v ('x-ml-name') || &$v ('x-mailing-list-name')
879     || &$v ('x-mailinglist-name') || &$v ('ml-name');
880     return $lname if length $lname;
881     if ($hdr->field_exist ('x-sequence')) {
882     if ($hdr->field ('x-sequence')->value =~ /^(\S+)\s+\d+$/) {
883     return $1;
884     }
885     }
886     if ($hdr->field_exist ('subject')) {
887 wakaba 1.37 my $s = $hdr->field ('subject');
888     return $s->list_name if $s->method_available ('list_name');
889 wakaba 1.36 }
890     undef;
891     }
892    
893     sub list_count ($) {
894     my $self = shift;
895     my $hdr = $self->{header};
896     my $v = sub {
897     my $name = shift;
898     my $f = $hdr->field ($name, -new_item_unless_exist => 0);
899     return $f->value if ref $f;
900     undef;
901     };
902     ## BUG: list-count 0 is not supported.
903     my $lc = &$v ('x-mail-count') || &$v ('x-ml-count') || &$v ('x-mailinglist-id')
904     || &$v ('mail-count') || &$v ('x-article-no') || &$v ('x-ml-counter')
905     || &$v ('x-ml-id') || &$v ('x-ml-sequence') || &$v ('x-serial-no')
906     || &$v ('x-seqno');
907     return $lc if $lc;
908     if ($hdr->field_exist ('x-sequence')) {
909 wakaba 1.38 my $s = $hdr->field ('x-sequence')->value;
910     if ($s =~ /^\S+\s+(\d+)$/) {
911     return $1;
912     } elsif ($s =~ /(\d+)/) {
913 wakaba 1.36 return $1;
914     }
915     }
916     if ($hdr->field_exist ('subject')) {
917 wakaba 1.37 my $s = $hdr->field ('subject');
918     return $s->list_count if $s->method_available ('list_count');
919 wakaba 1.36 }
920     undef;
921     }
922    
923 wakaba 1.9 =back
924    
925     =head1 MISC. METHODS
926    
927     =over 4
928    
929     =item $self->option ( $option-name / $option-name, $option-value, ...)
930    
931     If @_ == 1, returns option value. Else...
932    
933     Set option value. You can pass multiple option name-value pair
934     as parameter. Example:
935    
936     $msg->option (format => 'mail-rfc822',
937     capitalize => 0);
938     print $msg->option ('format'); ## mail-rfc822
939    
940     =cut
941    
942     sub option ($@) {
943     my $self = shift;
944     if (@_ == 1) {
945     return $self->{option}->{ $_[0] };
946     }
947 wakaba 1.18 my %option = @_;
948 wakaba 1.9 while (my ($name, $value) = splice (@_, 0, 2)) {
949     $self->{option}->{$name} = $value;
950     }
951 wakaba 1.32 if ($option{-recursive} && ($self->content_type)[0] ne 'message') {
952 wakaba 1.18 $self->{header}->option (%option);
953     $self->{body}->option (%option) if ref $self->{body};
954     }
955 wakaba 1.9 }
956    
957     =item $self->clone ()
958 wakaba 1.8
959     Returns a copy of Message::Entity object.
960    
961     =cut
962    
963     sub clone ($) {
964     my $self = shift;
965     my $clone = new Message::Entity;
966 wakaba 1.14 $clone->{option} = Message::Util::make_clone ($self->{option});
967     for (@{$self->{option}->{_MEMBERS}}) {
968     $clone->{$_} = Message::Util::make_clone ($self->{$_});
969 wakaba 1.8 }
970     $clone;
971     }
972 wakaba 1.5
973 wakaba 1.14 my %_method_default_list = qw(new 1 parse 1 stringify 1 option 1 clone 1 method_available 1);
974     sub method_available ($$) {
975     my $self = shift;
976     my $name = shift;
977     return 1 if $_method_default_list{$name};
978     for (@{$self->{option}->{_METHODS}}) {
979     return 1 if $_ eq $name;
980     }
981     0;
982     }
983    
984 wakaba 1.30 sub import ($;%) {
985     my $self = shift;
986     my %option = @_;
987     for (keys %option) {
988     $DEFAULT{$_} = $option{$_};
989     }
990     if ($option{-body_default_charset} && !$option{-body_default_charset_input}) {
991     $DEFAULT{-body_default_charset_input} = $option{-body_default_charset};
992     }
993     if ($option{-header_default_charset} && !$option{-header_default_charset_input}) {
994     $DEFAULT{-header_default_charset_input} = $option{-header_default_charset};
995     }
996     }
997    
998 wakaba 1.9 =back
999    
1000 wakaba 1.11 =head1 C<format>
1001    
1002     =over 2
1003    
1004     =item mail-rfc650
1005    
1006     Internet mail message, defined by IETF RFC 650
1007    
1008     =item mail-rfc724
1009    
1010     Internet mail message, defined by IETF RFC 724
1011    
1012     =item mail-rfc733
1013    
1014     Internet mail message, defined by IETF RFC 733
1015    
1016     =item mail-rfc822
1017    
1018     Internet mail message, defined by IETF RFC 822
1019    
1020 wakaba 1.35 =item mail-rfc822+rfc1123
1021    
1022     Internet mail message, defined by IETF RFC 822, ammended by RFC 1123
1023    
1024 wakaba 1.11 =item mail-rfc2822
1025    
1026     Internet mail message, defined by IETF RFC 2822
1027    
1028     =item mime-1.0
1029    
1030     MIME entity
1031    
1032     =item mime-1.0-rfc1341
1033    
1034     MIME entity, defined by RFC 1341 (and RFC 1342)
1035    
1036     =item mime-1.0-rfc1521
1037    
1038     MIME entity, defined by RFC 1521 and 1522
1039    
1040     =item mime-1.0-rfc2045
1041    
1042     MIME entity, defined by RFC 2045,..., 2049
1043    
1044     =item news-bnews
1045    
1046     Usenet Bnews format
1047    
1048     =item news-rfc850
1049    
1050     Usenet news format, defined by IETF RFC 850
1051    
1052     =item news-rfc1036
1053    
1054     Usenet news format, defined by IETF RFC 1036
1055    
1056     =item news-son-of-rfc1036
1057    
1058     Usenet news format, defined by son-of-RFC1036
1059    
1060     =item news-usefor
1061    
1062     Usenet news format, defined by usefor-article (IETF Internet Draft)
1063    
1064     =item http-1.0-rfc1945
1065    
1066     HTTP/1.0 message, defined by IETF RFC 1945
1067    
1068     =item http-1.0-rfc1945-request
1069    
1070     HTTP/1.0 request message, defined by IETF RFC 1945
1071    
1072     =item http-1.0-rfc1945-response
1073    
1074     HTTP/1.0 response message, defined by IETF RFC 1945
1075    
1076     =item http-1.1-rfc2068
1077    
1078     HTTP/1.1 message, defined by IETF RFC 2068
1079    
1080     =item http-1.1-rfc2068-request
1081    
1082     HTTP/1.1 request message, defined by IETF RFC 2068
1083    
1084     =item http-1.1-rfc2068-response
1085    
1086     HTTP/1.1 response message, defined by IETF RFC 2068
1087    
1088     =item http-1.1-rfc2616
1089    
1090     HTTP/1.1 message, defined by IETF RFC 2616
1091    
1092     =item http-1.1-rfc2616-request
1093    
1094     HTTP/1.1 request message, defined by IETF RFC 2616
1095    
1096     =item http-1.1-rfc2616-response
1097    
1098     HTTP/1.1 response message, defined by IETF RFC 2616
1099    
1100     =item http-cgi-1.1
1101    
1102     CGI/1.1 output (for HTTP), defined by coar-cgi-v11 (IETF Internet Draft)
1103    
1104     =item http-cgi-1.2
1105    
1106     CGI/1.2 output, defined by coar-cgi-v12 (to be IETF Internet Draft)
1107    
1108     =item http-sip-2.0
1109    
1110     SIP/2.0 message, defined by IETF RFC 2543
1111    
1112     =item http-sip-2.0-request
1113    
1114     SIP/2.0 request message, defined by IETF RFC 2543
1115    
1116     =item http-sip-2.0-response
1117    
1118     SIP/2.0 response message, defined by IETF RFC 2543
1119    
1120     =item http-sip-cgi
1121    
1122     SIP/2.0 CGI (IETF Internet Draft)
1123    
1124     =item cpim-1.0
1125    
1126     CPIM/1.0 (IETF Internet Draft)
1127    
1128 wakaba 1.35 =item uri-url-mailto
1129 wakaba 1.12
1130     mailto: URL scheme
1131    
1132     =item uri-url-mailto-rfc1738
1133    
1134     mailto: URL scheme (defined by RFC 1738)
1135    
1136 wakaba 1.35 =item uri-url-mailto-rfc2368
1137 wakaba 1.12
1138     mailto: URL scheme (defined by RFC 2368)
1139    
1140 wakaba 1.35 =item uri-url-mailto-to
1141 wakaba 1.12
1142     C<to> part of mailto: URL scheme (for internal use only)
1143    
1144 wakaba 1.11 =back
1145    
1146 wakaba 1.1 =head1 EXAMPLE
1147    
1148     use Message::Entity;
1149 wakaba 1.9 my $msg = new Message::Entity From => '[email protected]',
1150     Subject => 'Example message',
1151     To => '[email protected]',
1152     -format => 'mail-rfc2822',
1153     body => $body;
1154 wakaba 1.1 $msg->header ($header);
1155     $msg->body ($body);
1156     print $msg;
1157    
1158 wakaba 1.3 =head1 SEE ALSO
1159    
1160     Message::* Perl modules
1161     <http://suika.fam.cx/~wakaba/Message-pm/>
1162    
1163 wakaba 1.1 =head1 LICENSE
1164    
1165 wakaba 1.39 Copyright 2002 Wakaba <[email protected]>.
1166 wakaba 1.1
1167     This program is free software; you can redistribute it and/or modify
1168     it under the terms of the GNU General Public License as published by
1169     the Free Software Foundation; either version 2 of the License, or
1170     (at your option) any later version.
1171    
1172     This program is distributed in the hope that it will be useful,
1173     but WITHOUT ANY WARRANTY; without even the implied warranty of
1174     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1175     GNU General Public License for more details.
1176    
1177     You should have received a copy of the GNU General Public License
1178     along with this program; see the file COPYING. If not, write to
1179     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1180     Boston, MA 02111-1307, USA.
1181    
1182     =head1 CHANGE
1183    
1184     See F<ChangeLog>.
1185 wakaba 1.40 $Date: 2002/12/28 09:10:16 $
1186 wakaba 1.1
1187     =cut
1188    
1189     1;

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24