| 10 |
|
|
| 11 |
=cut |
=cut |
| 12 |
|
|
| 13 |
|
require 5.6.0; ## (require: v5.6.0 data type) |
| 14 |
package Message::Entity; |
package Message::Entity; |
| 15 |
use strict; |
use strict; |
| 16 |
use vars qw(%DEFAULT $VERSION); |
use vars qw(%DEFAULT %REG $VERSION); |
| 17 |
$VERSION=do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r}; |
$VERSION=do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r}; |
| 18 |
|
|
| 19 |
require Message::Util; |
require Message::Util; |
| 22 |
require Message::MIME::Encoding; |
require Message::MIME::Encoding; |
| 23 |
use overload '""' => sub { $_[0]->stringify }, |
use overload '""' => sub { $_[0]->stringify }, |
| 24 |
fallback => 1; |
fallback => 1; |
| 25 |
|
*REG = \%Message::Util::REG; |
| 26 |
|
|
| 27 |
## Initialize of this class -- called by constructors |
## Initialize of this class -- called by constructors |
| 28 |
%DEFAULT = ( |
%DEFAULT = ( |
| 30 |
-_MEMBERS => [qw|header body _cte|], |
-_MEMBERS => [qw|header body _cte|], |
| 31 |
## entity_header -- Don't clone. |
## entity_header -- Don't clone. |
| 32 |
-accept_coderange => '7bit', ## 7bit / 8bit / binary |
-accept_coderange => '7bit', ## 7bit / 8bit / binary |
|
#add_ua => 1, |
|
| 33 |
-body_default_charset => 'iso-2022-int-1', |
-body_default_charset => 'iso-2022-int-1', |
| 34 |
-body_default_charset_input => 'iso-2022-int-1', |
-body_default_charset_input => 'iso-2022-int-1', |
| 35 |
-body_default_media_type => 'text', |
-body_default_media_type => 'text', |
| 36 |
-body_default_media_subtype => 'plain', |
-body_default_media_subtype => 'plain', |
| 37 |
-cte_default => '7bit', |
-cte_default => '7bit', |
| 38 |
#fill_date => 1, |
-fill_missing_fields => 1, |
| 39 |
-fill_date_name => 'date', |
#add_ua => 1, |
| 40 |
-fill_md5 => 0, |
#fill_date => 1, |
| 41 |
-fill_md5_name => 'md5', |
-fill_date_name => 'date', |
| 42 |
#fill_msgid => 1, |
-fill_destination => 0, |
| 43 |
-fill_msgid_name => 'message-id', |
#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 |
|
-fill_source => 0, |
| 52 |
|
-recalc_md5 => 1, |
| 53 |
-force_mime_entity => 0, |
-force_mime_entity => 0, |
| 54 |
-format => 'mail-rfc2822', |
-format => 'mail-rfc2822', |
| 55 |
|
-guess_media_type => 1, |
| 56 |
|
#internal_charset_name |
| 57 |
-header_default_charset => 'iso-2022-int-1', |
-header_default_charset => 'iso-2022-int-1', |
| 58 |
-header_default_charset_input => 'iso-2022-int-1', |
-header_default_charset_input => 'iso-2022-int-1', |
|
-hook_init_fill_options => sub {}, |
|
|
-hook_stringify_fill_fields => sub {}, |
|
| 59 |
-linebreak_strict => 0, ## BUG: not work perfectly |
-linebreak_strict => 0, ## BUG: not work perfectly |
| 60 |
|
-output_magic_line => 1, |
| 61 |
-parse_all => 0, |
-parse_all => 0, |
| 62 |
-recalc_md5 => 1, |
-remove_post_newline => 0, |
| 63 |
|
-remove_pre_newline => 0, |
| 64 |
-text_coderange => 'binary', |
-text_coderange => 'binary', |
| 65 |
## '8bit' (MIME text/*) / 'binary' (HTTP text/*) |
## '8bit' (MIME text/*) / 'binary' (HTTP text/*) |
| 66 |
#ua_field_name => 'user-agent', |
#ua_field_name => 'user-agent', |
| 67 |
-ua_use_Config => 1, |
-ua_use_Config => 1, |
| 68 |
-ua_use_Win32 => 1, |
-ua_use_Win32 => 1, |
| 69 |
-uri_mailto_safe_level => 4, |
-uri_mailto_safe_level => 4, |
| 70 |
|
-use_magic_line => 1, |
| 71 |
); |
); |
| 72 |
sub _init ($;%) { |
sub _init ($;%) { |
| 73 |
my $self = shift; |
my $self = shift; |
| 92 |
} |
} |
| 93 |
|
|
| 94 |
my $format = $self->{option}->{format}; |
my $format = $self->{option}->{format}; |
| 95 |
|
my $ns822 = $Message::Header::NS_phname2uri{'x-rfc822'}; |
| 96 |
|
my $nshttp = $Message::Header::NS_phname2uri{'x-http'}; |
| 97 |
if ($format =~ /http/) { |
if ($format =~ /http/) { |
| 98 |
$self->{option}->{fill_date_ns} = $Message::Header::NS_phname2uri{'x-http'}; |
$self->{option}->{fill_date_ns} = $nshttp unless defined $options{-fill_date_ns}; |
| 99 |
$self->{option}->{fill_msgid_from_ns} = $Message::Header::NS_phname2uri{'x-http'}; |
$self->{option}->{fill_from_ns} = $nshttp unless defined $options{-fill_from_ns}; |
| 100 |
$self->{option}->{fill_ua_ns} = $Message::Header::NS_phname2uri{'x-http'}; |
$self->{option}->{fill_ua_ns} = $nshttp unless defined $options{-fill_ua_ns}; |
| 101 |
|
$self->{option}->{fill_source} = 0 unless defined $options{-fill_source}; |
| 102 |
$self->{option}->{accept_coderange} = 'binary'; |
$self->{option}->{accept_coderange} = 'binary'; |
| 103 |
$self->{option}->{text_coderange} = 'binary'; |
$self->{option}->{text_coderange} = 'binary'; |
| 104 |
$self->{option}->{cte_default} = 'binary'; |
$self->{option}->{cte_default} = 'binary'; |
| 105 |
} else { |
} else { |
| 106 |
$self->{option}->{fill_date_ns} = $Message::Header::NS_phname2uri{'x-rfc822'}; |
if ($format =~ /mail-rfc822|mail-rfc2822/ && $format !~ /mime-entity/) { |
| 107 |
$self->{option}->{fill_msgid_from_ns} = $Message::Header::NS_phname2uri{'x-rfc822'}; |
$self->{option}->{fill_destination} = 1; |
| 108 |
$self->{option}->{fill_ua_ns} = $Message::Header::NS_phname2uri{'x-rfc822'}; |
$self->{option}->{fill_source} = 1 unless defined $options{-fill_source}; |
| 109 |
|
} |
| 110 |
|
$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 |
$self->{option}->{text_coderange} = '8bit'; |
$self->{option}->{text_coderange} = '8bit'; |
| 114 |
if ($format =~ /news-usefor|smtp-8bitmime/) { |
if ($format =~ /news-usefor|smtp-8bitmime/) { |
| 115 |
$self->{option}->{accept_coderange} = '8bit'; |
$self->{option}->{accept_coderange} = '8bit'; |
|
#$self->{option}->{cte_default} = '8bit'; |
|
| 116 |
} else { |
} else { |
| 117 |
$self->{option}->{accept_coderange} = '7bit'; |
$self->{option}->{accept_coderange} = '7bit'; |
| 118 |
} |
} |
| 119 |
} |
} |
| 120 |
$self->{option}->{fill_msgid_ns} = $Message::Header::NS_phname2uri{'x-rfc822'}; |
for (qw/fill_msgid_ns fill_msgid_from fill_mimever_ns fill_destination_ns fill_sender_ns/) { |
| 121 |
$self->{option}->{fill_mimever_ns} = $Message::Header::NS_phname2uri{'x-rfc822'}; |
$self->{option}->{$_} = $ns822; |
| 122 |
|
} |
| 123 |
|
$self->{option}->{fill_destination_resent_ns} = $Message::Header::NS_phname2uri{'x-rfc822-resent'}; |
| 124 |
unless (defined $self->{option}->{fill_date}) { |
unless (defined $self->{option}->{fill_date}) { |
| 125 |
$self->{option}->{fill_date} = $format !~ /mime-entity|cgi|uri-url-mailto/; |
$self->{option}->{fill_date} = $format !~ /mime-entity|cgi|uri-url-mailto/; |
| 126 |
} |
} |
| 140 |
$self->{option}->{fill_ua_name} = $format =~ /response|cgi|uri-url-mailto/? |
$self->{option}->{fill_ua_name} = $format =~ /response|cgi|uri-url-mailto/? |
| 141 |
'server': 'user-agent'; |
'server': 'user-agent'; |
| 142 |
} |
} |
| 143 |
&{ $self->{option}->{hook_init_fill_options} } ($self, $self->{option}); |
unless (defined $options{-output_magic_line}) { |
| 144 |
|
$self->{option}->{output_magic_line} = 0 |
| 145 |
|
if $format =~ /mail|news|mime/; |
| 146 |
|
} |
| 147 |
@new_fields; |
@new_fields; |
| 148 |
} |
} |
| 149 |
|
|
| 161 |
Example: |
Example: |
| 162 |
|
|
| 163 |
$msg = new Message::Entity |
$msg = new Message::Entity |
|
Date => 'Thu, 03 Feb 1994 00:00:00 +0000', |
|
| 164 |
Content_Type => 'text/html', |
Content_Type => 'text/html', |
| 165 |
X_URI => '<http://www.foo.example/>', |
X_URI => '<http://www.foo.example/>', |
| 166 |
-format => 'mail-rfc2822' ## not to be header field |
-format => 'mail-rfc2822' ## not to be header field |
| 202 |
unless ($self->{option}->{linebreak_strict}) { |
unless ($self->{option}->{linebreak_strict}) { |
| 203 |
$nl = Message::Util::decide_newline ($message); |
$nl = Message::Util::decide_newline ($message); |
| 204 |
} |
} |
| 205 |
## BUG: binary unsafe yet! |
my ($hdr, $body); |
| 206 |
my @header = (); |
$message =~ s/^(?:$nl)+//s if $self->{option}->{remove_pre_newline}; |
| 207 |
my @body = split /$nl/, $message; |
$message =~ s/(?:$nl)+$/$nl/s if $self->{option}->{remove_post_newline}; |
| 208 |
while (1) { |
if ($self->{option}->{use_magic_line}) { |
| 209 |
my $line = shift @body; |
## TODO: Reset format option? |
| 210 |
unless (length($line)) { |
if ($message =~ s/>?From (.+?)$nl//gs) { ## Mail from line |
| 211 |
last; |
$new_field{'x-rfc822-mail-from'} = $1; |
| 212 |
} else { |
} elsif ($message =~ s#^($REG{http_token})\x20($REG{S_uri})\x20($REG{http_token})/([0-9]+)\.([0-9]+)$nl##gs) { |
| 213 |
push @header, $line; |
## HTTP Request |
| 214 |
|
($self->{http_method}, $self->{http_request_uri}, |
| 215 |
|
$self->{http_protocol_name}, $self->{http_protocol_version}) |
| 216 |
|
= ($1, $2, uc $3, pack ('U2', $4, $5)); |
| 217 |
|
} elsif ($message =~ s#^($REG{http_token})/([0-9]+)\.([0-9]+)\x20([0-9][0-9][0-9]\x20.*?)$nl##gs) { |
| 218 |
|
## HTTP Response |
| 219 |
|
($self->{http_protocol_name}, $self->{http_protocol_version}) |
| 220 |
|
= (uc $1, pack ('U2', $2, $3)); |
| 221 |
|
$new_field{'x-http-status'} = $4; |
| 222 |
|
} elsif ($message =~ s#^($REG{http_token})\x20($REG{S_uri})$nl##gs) { |
| 223 |
|
## HTTP/0.9 simple-request |
| 224 |
|
($self->{http_method}, $self->{http_request_uri}, |
| 225 |
|
$self->{http_protocol_name}, $self->{http_protocol_version}) |
| 226 |
|
= ($1, $2, 'HTTP', v0.9); |
| 227 |
|
$message = $nl . $message; ## Has no header fields |
| 228 |
} |
} |
| 229 |
} |
} |
| 230 |
|
if ($message !~ s/^$nl//s) { |
| 231 |
|
($hdr, $body) = split /$nl$nl/, $message, 2; |
| 232 |
|
} else { |
| 233 |
|
$hdr = ''; $body = $message; |
| 234 |
|
$body =~ s/^$nl//s; |
| 235 |
|
} |
| 236 |
$new_field{body} = undef if $new_field{body}; |
$new_field{body} = undef if $new_field{body}; |
| 237 |
$self->{header} = parse_array Message::Header \@header, |
## Is this implemention good? |
| 238 |
|
$self->{header} = parse Message::Header $hdr, |
| 239 |
-header_default_charset => $self->{option}->{header_default_charset}, |
-header_default_charset => $self->{option}->{header_default_charset}, |
| 240 |
-header_default_charset_input => $self->{option}->{header_default_charset_input}, |
-header_default_charset_input => $self->{option}->{header_default_charset_input}, |
| 241 |
-parse_all => $self->{option}->{parse_all}, |
-parse_all => $self->{option}->{parse_all}, |
| 242 |
-format => $self->{option}->{format}, %new_field; |
-format => $self->{option}->{format}, |
| 243 |
$self->{body} = join ($nl, @body) . $nl; |
%new_field; ## Additional header fields |
| 244 |
$self->{body} = $self->_parse_value ([$self->content_type] => $self->{body}) |
|
| 245 |
|
$self->{body} = $body; |
| 246 |
|
$self->{body} = $self->_parse_value ([ $self->content_type ] => $self->{body}) |
| 247 |
if $self->{option}->{parse_all}; |
if $self->{option}->{parse_all}; |
| 248 |
$self; |
$self; |
| 249 |
} |
} |
| 325 |
} |
} |
| 326 |
my $MD5; |
my $MD5; |
| 327 |
eval q{ |
eval q{ |
| 328 |
require Digest::MD5; require MIME::Base64; |
require Digest::MD5; |
| 329 |
$MD5 = MIME::Base64::encode (Digest::MD5::md5 ($self->{body})); |
$MD5 = ($self->Message::MIME::Encoding::encode_base64 (Digest::MD5::md5 ($self->{body})))[0]; |
| 330 |
$MD5 =~ tr/\x09\x0A\x0D\x20//d; |
$MD5 =~ tr/\x09\x0A\x0D\x20//d; |
| 331 |
} or Carp::croak $@; |
1} or Carp::croak $@; |
| 332 |
return $MD5 eq $md5? 1 : 0; |
return $MD5 eq $md5? 1 : 0; |
| 333 |
} |
} |
| 334 |
|
|
| 362 |
-parse_all => $self->{option}->{parse_all}, |
-parse_all => $self->{option}->{parse_all}, |
| 363 |
-body_default_charset => $self->{option}->{body_default_charset}, |
-body_default_charset => $self->{option}->{body_default_charset}, |
| 364 |
-body_default_charset_input => $self->{option}->{body_default_charset_input}, |
-body_default_charset_input => $self->{option}->{body_default_charset_input}, |
| 365 |
|
-internal_charset_name => $self->{option}->{internal_charset_name}, |
| 366 |
entity_header => $self->{header}, |
entity_header => $self->{header}, |
| 367 |
); |
); |
| 368 |
## Media type specified option/parameters |
## Media type specified option/parameters |
| 435 |
$charset_def = $Message::MIME::Charset::CHARSET{$charset}; |
$charset_def = $Message::MIME::Charset::CHARSET{$charset}; |
| 436 |
} else { |
} else { |
| 437 |
$charset_def = $Message::MIME::Charset::CHARSET{'*default'}; |
$charset_def = $Message::MIME::Charset::CHARSET{'*default'}; |
| 438 |
## Note: 'encoding_after_encode' option (available for header |
## Note: 'encoding_after_encode' option's value is hardcoded. |
|
## field, but not for message body) is hardcoded. |
|
| 439 |
} |
} |
| 440 |
} else { ## Don't have mime style "charset" parameter |
} else { ## Don't have mime style "charset" parameter |
| 441 |
$charset_def = {mime_text => 1}; |
$charset_def = {mime_text => 1}; |
| 442 |
} |
} |
| 443 |
$charset_def = {} unless ref $charset_def; ## dummy |
$charset_def = {} unless ref $charset_def; ## dummy |
| 444 |
if ($charset_def->{mime_text} != 1) { |
#if ($charset_def->{mime_text} != 1) { ## See also Note above |
| 445 |
|
if (Message::MIME::Charset::is_mime_text ($charset || '*default') != 1) { |
| 446 |
$enoption{mt_is_text} = 0 if $mt eq 'text'; |
$enoption{mt_is_text} = 0 if $mt eq 'text'; |
| 447 |
my $ct = $self->{header}->field ('content-type'); |
my $ct = $self->{header}->field ('content-type'); |
| 448 |
$ct->not_mime_text ($option->{text_coderange} eq 'binary'? 0:1); |
$ct->not_mime_text ($option->{text_coderange} eq 'binary'? 0:1); |
| 529 |
my ($header, $body, $body0); |
my ($header, $body, $body0); |
| 530 |
if (ref $self->{body}) { |
if (ref $self->{body}) { |
| 531 |
$self->{body}->entity_header ($self->{header}); |
$self->{body}->entity_header ($self->{header}); |
| 532 |
$body0 = $self->{body}->stringify (-format => $option{format}, |
$body0 = $self->{body}->stringify (-parent_format => $option{format}, |
| 533 |
-linebreak_strict => $option{linebreak_strict}); |
-linebreak_strict => $option{linebreak_strict}); |
| 534 |
} else { |
} else { |
| 535 |
$body0 = $self->{body}; |
$body0 = $self->{body}; |
| 536 |
} |
} |
| 537 |
$body = $self->_encode_body ($body0, \%option); |
$body = $self->_encode_body ($body0, \%option); |
| 538 |
if (ref $self->{header}) { |
if (ref $self->{header}) { |
|
my %exist; |
|
|
for ($self->{header}->field_name_list) {$exist{$_} = 1} |
|
|
&{ $option{hook_stringify_fill_fields} } ($self, \%exist, \%option); |
|
| 539 |
my $ns_content = $Message::Header::NS_phname2uri{content}; |
my $ns_content = $Message::Header::NS_phname2uri{content}; |
| 540 |
if ($option{fill_date} |
my $filler; |
| 541 |
&& !$exist{$option{fill_date_name}.':'.$option{fill_date_ns}}) { |
$filler = sub { |
| 542 |
$self->{header}->field |
my ($hdr, $exist, $hdr_option) = @_; |
| 543 |
($option{fill_date_name}, -ns => $option{fill_date_ns})->unix_time (time); |
## Date: (RFC 822, HTTP) |
| 544 |
} |
if ($option{fill_date} |
| 545 |
if ($option{fill_msgid} |
&& !$exist->{$option{fill_date_name}.':'.$option{fill_date_ns}}) { |
| 546 |
&& !$exist{$option{fill_msgid_name}.':'.$option{fill_msgid_ns}}) { |
$hdr->field |
| 547 |
my $from = $self->{header}->field |
($option{fill_date_name}, -ns => $option{fill_date_ns})->unix_time (time); |
|
('from', -ns => $option{fill_msgid_from_ns}, -new_item_unless_exist => 0); |
|
|
$from = $from->addr_spec if ref $from; |
|
|
$self->{header}->field |
|
|
($option{fill_msgid_name}, -ns => $option{fill_msgid_ns}) |
|
|
->generate (addr_spec => $from) |
|
|
if $from; |
|
|
} # fill_msgid |
|
|
if (($option{fill_md5} && !$exist{ $option{fill_md5_name} .':'. $ns_content}) |
|
|
|| ($option{recalc_md5} && $exist{ $option{fill_md5_name} .':'. $ns_content})) { |
|
|
my $md5; |
|
|
eval q{ |
|
|
require Digest::MD5; require MIME::Base64; |
|
|
$md5 = MIME::Base64::encode (Digest::MD5::md5 ($body0)); |
|
|
$md5 =~ tr/\x09\x0A\x0D\x20//d; |
|
|
} or Carp::carp $@; |
|
|
if ($md5) { |
|
|
my $md5f = $self->{header}->field ($option{fill_md5_name}, -ns => $ns_content); |
|
|
$md5f->value ($md5); |
|
| 548 |
} |
} |
| 549 |
} |
## Message-ID: (RFC 822) |
| 550 |
my $ismime = 0; |
if ($option{fill_msgid} |
| 551 |
for (keys %exist) {if (/:$ns_content$/) { $ismime = 1; last }} |
&& !$exist->{$option{fill_msgid_name}.':'.$option{fill_msgid_ns}}) { |
| 552 |
unless ($ismime) { |
my $from = $hdr->field |
| 553 |
$ismime = 1 if $option{force_mime_entity}; |
('from', -ns => $option{fill_msgid_from_ns}, -new_item_unless_exist => 0); |
| 554 |
$ismime = 1 if $option{fill_md5}; |
$from = $from->addr_spec if ref $from; |
| 555 |
$ismime = 1 if $option{body_default_media_type} ne 'text'; |
$hdr->field ($option{fill_msgid_name}, -ns => $option{fill_msgid_ns}) |
| 556 |
$ismime = 1 if $option{body_default_media_subtype} ne 'plain'; |
->generate (addr_spec => $from) if $from; |
| 557 |
} |
} # fill_msgid |
| 558 |
if ($ismime) { |
## To:, CC:, BCC:, Resent-To:, Resent-Cc:, Resent-Bcc: (RFC 822) |
| 559 |
if ($option{fill_ct} && !$exist{'type:'.$ns_content}) { |
if ($option{fill_destination}) { |
| 560 |
my $ct = $self->{header}->field ('type', |
if ( !$exist->{ 'to:'.$option{fill_destination_ns} } |
| 561 |
-parse => 1, -ns => $ns_content); |
&& !$exist->{ 'cc:'.$option{fill_destination_ns} } |
| 562 |
$ct->media_type ($option{body_default_media_type}.'/' |
&& !$exist->{ 'bcc:'.$option{fill_destination_ns} } |
| 563 |
.$option{body_default_media_subtype}); |
&& !$exist->{ 'to:'.$option{fill_destination_resent_ns} } |
| 564 |
$ct->replace (Message::MIME::Charset::name_minimumize ($option{body_default_charset} => $body0)); |
&& !$exist->{ 'cc:'.$option{fill_destination_resent_ns} } |
| 565 |
|
&& !$exist->{ 'bcc:'.$option{fill_destination_resent_ns} } ) { |
| 566 |
|
$hdr->add (bcc => ''); |
| 567 |
|
} |
| 568 |
|
} |
| 569 |
|
## From:, Sender: |
| 570 |
|
if ($option{fill_source}) { |
| 571 |
|
## From: |
| 572 |
|
if (!$exist->{ 'from:'.$option{fill_from_ns} }) { |
| 573 |
|
$hdr->add (from => 'Unknown source <[email protected]>', |
| 574 |
|
-ns => $option{fill_from_ns}); |
| 575 |
|
## From: exists, Sender: not exist |
| 576 |
|
} elsif (!$exist->{ 'sender:'.$option{fill_sender_ns} }) { |
| 577 |
|
my $from = $hdr->field ('from', -ns => $option{fill_from_ns}); |
| 578 |
|
if ($from->count > 1) { |
| 579 |
|
$hdr->field ('sender', -ns => $option{fill_sender_ns}) |
| 580 |
|
->add ($from->item (0, -by => 'index')); |
| 581 |
|
} |
| 582 |
|
} |
| 583 |
|
} |
| 584 |
|
## Content-MD5: |
| 585 |
|
if (($option{fill_md5} && !$exist->{ $option{fill_md5_name} .':'. $ns_content}) |
| 586 |
|
|| ($option{recalc_md5} && $exist->{ $option{fill_md5_name} .':'. $ns_content})) { |
| 587 |
|
my $md5; |
| 588 |
|
eval q{ |
| 589 |
|
require Digest::MD5; |
| 590 |
|
$md5 = ($self->Message::MIME::Encoding::encode_base64 (Digest::MD5::md5 ($body0)))[0]; |
| 591 |
|
$md5 =~ tr/\x09\x0A\x0D\x20//d; |
| 592 |
|
1} or Carp::carp $@; |
| 593 |
|
if ($md5) { |
| 594 |
|
my $md5f = $hdr->field ($option{fill_md5_name}, -ns => $ns_content); |
| 595 |
|
$md5f->value ($md5); |
| 596 |
|
} |
| 597 |
} |
} |
| 598 |
if ($option{fill_mimever} |
my $ismime = 0; |
| 599 |
&& !$exist{'mime-version:'.$option{fill_mimever_ns}}) { |
for (keys %$exist) {if (/:$ns_content$/) { $ismime = 1; last }} |
| 600 |
## BUG: doesn't support rfc10]49, HTTP (ie. non-MIME) content-*: fields |
unless ($ismime) { |
| 601 |
$self->{header}->add ('mime-version' => '1.0', |
$ismime = 1 if $option{force_mime_entity} |
| 602 |
-parse => 0, -ns => $option{fill_mimever_ns}); |
|| $option{fill_md5} |
| 603 |
|
|| $option{body_default_media_type} ne 'text' |
| 604 |
|
|| $option{body_default_media_subtype} ne 'plain'; |
| 605 |
} |
} |
| 606 |
} # $ismime |
if ($ismime) { |
| 607 |
if ($option{format} =~ /uri-url-mailto/ && $exist{'type:$ns_content'} |
## Content-Type: (MIME, HTTP) |
| 608 |
|
if ($option{fill_ct} && !$exist->{'type:'.$ns_content}) { |
| 609 |
|
my $ct = $hdr->field ('type', -ns => $ns_content); |
| 610 |
|
$ct->media_type ($option{body_default_media_type}.'/' |
| 611 |
|
.$option{body_default_media_subtype}); |
| 612 |
|
$ct->replace (Message::MIME::Charset::name_minimumize ($option{body_default_charset} => $body0)); |
| 613 |
|
} |
| 614 |
|
## MIME-Version: (MIME) |
| 615 |
|
if ($option{fill_mimever} |
| 616 |
|
&& !$exist->{'mime-version:'.$option{fill_mimever_ns}}) { |
| 617 |
|
## BUG: doesn't support rfc1049, HTTP (ie. non-MIME) content-*: fields |
| 618 |
|
$hdr->add ('mime-version' => '1.0', |
| 619 |
|
-parse => 0, -ns => $option{fill_mimever_ns}); |
| 620 |
|
} |
| 621 |
|
} # $ismime |
| 622 |
|
## User-Agent: (USEFOR, HTTP) |
| 623 |
|
if ($option{add_ua}) { |
| 624 |
|
$hdr->field ($option{fill_ua_name})->add_our_name ( |
| 625 |
|
-use_Config => $option{ua_use_Config}, |
| 626 |
|
-use_Win32 => $option{ua_use_Win32}, |
| 627 |
|
-date => q$Date$, |
| 628 |
|
); |
| 629 |
|
} |
| 630 |
|
} if $option{fill_missing_fields}; |
| 631 |
|
|
| 632 |
|
if ($option{format} =~ /uri-url-mailto/ |
| 633 |
|
&& $self->{header}->field_exist ('type', -ns => $ns_content) |
| 634 |
&& $option{uri_mailto_safe_level} > 1) { |
&& $option{uri_mailto_safe_level} > 1) { |
| 635 |
$self->{header}->field ('content-type')->media_type ('text/plain'); |
$self->{header}->field ('type', -ns => $ns_content)->media_type ('text/plain'); |
| 636 |
} |
} |
| 637 |
if ($option{add_ua}) { |
$header = $self->{header}->stringify ( |
| 638 |
$self->{header}->field ($option{fill_ua_name})->add_our_name ( |
-format => $option{format}, |
| 639 |
-use_Config => $option{ua_use_Config}, |
-linebreak_strict => $option{linebreak_strict}, |
| 640 |
-use_Win32 => $option{ua_use_Win32}, |
-uri_mailto_safe_level => $option{uri_mailto_safe_level}, |
| 641 |
); |
($filler? (-hook_stringify_fill_fields => $filler) :()), |
| 642 |
} |
); |
|
$header = $self->{header}->stringify (-format => $option{format}, |
|
|
-linebreak_strict => $option{linebreak_strict}, |
|
|
-uri_mailto_safe_level => $option{uri_mailto_safe_level}); |
|
| 643 |
} else { |
} else { |
| 644 |
$header = $self->{header}; |
$header = $self->{header}; |
| 645 |
unless ($option{linebreak_strict}) { |
unless ($option{linebreak_strict}) { |
| 666 |
$to||$header? 'mailto:'.$to.$header: ''; |
$to||$header? 'mailto:'.$to.$header: ''; |
| 667 |
} |
} |
| 668 |
} else { |
} else { |
| 669 |
|
## Magic line (<- named by the author of this module:-) |
| 670 |
|
my $mline; |
| 671 |
|
if ($option{use_magic_line} && $option{output_magic_line}) { |
| 672 |
|
if ($option{format} =~ /mail|news/ && ref $self->{header}) { |
| 673 |
|
my $mfrom = $self->{header}->field ('mail-from', -new_item_unless_exist=>0); |
| 674 |
|
$mline = sprintf 'From %s', $mfrom->value if ref $mfrom; |
| 675 |
|
} elsif ($option{format} =~ /http.+?request/) { |
| 676 |
|
$mline = sprintf '%s %s %s/%vd', $self->{http_method} || 'GET', |
| 677 |
|
$self->{http_request_uri} || '/', $self->{http_protocol_name} || 'HTTP', |
| 678 |
|
$self->{http_protocol_version} || v1.0; |
| 679 |
|
} elsif ($option{format} =~ /http.+?response/ && ref $self->{header} |
| 680 |
|
&& $option{format} !~ /cgi/) { |
| 681 |
|
my $s = $self->{header}->field ('x-http-status'); |
| 682 |
|
$mline = sprintf '%s/%vd %s', $self->{http_protocol_name} || 'HTTP', |
| 683 |
|
$self->{http_protocol_version} || v1.0, $s->value || '200 OK'; |
| 684 |
|
} |
| 685 |
|
} |
| 686 |
|
$mline .= "\x0D\x0A" if $mline; |
| 687 |
|
$mline = '' unless $mline; |
| 688 |
|
|
| 689 |
$header .= "\x0D\x0A" if $header && $header !~ /\x0D\x0A$/; |
$header .= "\x0D\x0A" if $header && $header !~ /\x0D\x0A$/; |
| 690 |
$header."\x0D\x0A".$body; |
$mline.$header."\x0D\x0A".$body; |
| 691 |
} |
} |
| 692 |
} |
} |
| 693 |
*as_string = \&stringify; |
*as_string = \&stringify; |
| 717 |
sub content_type ($;%) { |
sub content_type ($;%) { |
| 718 |
my $self = shift; |
my $self = shift; |
| 719 |
my $ct = $self->{header}->field ('content-type', -new_item_unless_exist => 0); |
my $ct = $self->{header}->field ('content-type', -new_item_unless_exist => 0); |
| 720 |
|
my ($mt, $mst); |
| 721 |
unless (ref $ct) { |
unless (ref $ct) { |
| 722 |
if ($self->{option}->{body_default_media_type} ne 'text' |
$mt = $self->{option}->{body_default_media_type}; |
| 723 |
|| $self->{option}->{body_default_media_subtype} ne 'plain') { |
$mst = $self->{option}->{body_default_media_subtype}; |
| 724 |
|
if ($mt ne 'text' || $mst ne 'plain') { |
| 725 |
$ct = $self->{header}->field ('content-type'); |
$ct = $self->{header}->field ('content-type'); |
| 726 |
$ct->media_type_major ($self->{option}->{body_default_media_type}); |
$ct->media_type_major ($mt); |
| 727 |
$ct->media_type_minor ($self->{option}->{body_default_media_subtype}); |
$ct->media_type_minor ($mst); |
| 728 |
|
} |
| 729 |
|
if ($self->{option}->{guess_media_type} && $self->{body} && !ref $self->{body} |
| 730 |
|
&& $self->{option}->{format} =~ /mail|news/) { |
| 731 |
|
if ($self->{body} =~ /^-----BEGIN PGP SIGNED MESSAGE-----\x0D?$/m |
| 732 |
|
&& $self->{body} =~ /^-----BEGIN PGP SIGNATURE-----\x0D?$/m |
| 733 |
|
&& $self->{body} =~ /^-----END PGP SIGNATURE-----\x0D?$/m) { |
| 734 |
|
$ct = $self->{header}->field ('content-type') unless ref $ct; |
| 735 |
|
$mt = $ct->media_type_major ('text'); |
| 736 |
|
$mst = $ct->media_type_minor ('x-pgp-cleartext-signed'); |
| 737 |
|
} elsif ($self->{body} =~ /^-----BEGIN PGP [A-Z\x20]+-----\x0D?$/m |
| 738 |
|
&& $self->{body} =~ /^-----END PGP [A-Z\x20]+-----\x0D?$/m) { |
| 739 |
|
$ct = $self->{header}->field ('content-type') unless ref $ct; |
| 740 |
|
$mt = $ct->media_type_major ('application'); |
| 741 |
|
$mst = $ct->media_type_minor ('pgp'); |
| 742 |
|
$ct->parameter (format => 'text'); |
| 743 |
|
} elsif ($self->{body} =~ /^-+ start of forwarded message \(RFC 934 encapsulation\) -+\x0D?$/m) { |
| 744 |
|
$ct = $self->{header}->field ('content-type') unless ref $ct; |
| 745 |
|
$mt = $ct->media_type_major ('text'); |
| 746 |
|
$mst = $ct->media_type_minor ('x-message-rfc934'); |
| 747 |
|
} elsif ($self->{body} =~ /^-{70,70}\x0D?$/m |
| 748 |
|
&& $self->{body} =~ /^-{30,30}\x0D?$/m |
| 749 |
|
&& $self->{body} =~ /\x0D?\x0A-{30,30}\x0D?\x0A\x0D?\x0AEnd of.+?Digest.*?\x0D?\x0A\*+(?:\x0D?\x0A)*$/s) { |
| 750 |
|
$ct = $self->{header}->field ('content-type') unless ref $ct; |
| 751 |
|
$mt = $ct->media_type_major ('text'); |
| 752 |
|
$mst = $ct->media_type_minor ('x-message-rfc1153'); |
| 753 |
|
} elsif ($self->{body} =~ /^-----PRIVACY-ENHANCED MESSAGE BOUNDARY-----\x0D?$/m) { |
| 754 |
|
$ct = $self->{header}->field ('content-type') unless ref $ct; |
| 755 |
|
$mt = $ct->media_type_major ('text'); |
| 756 |
|
$mst = $ct->media_type_minor ('x-message-pem'); |
| 757 |
|
} elsif ($self->{body} =~ /^#(?:HELO|EHLO)/mi |
| 758 |
|
&& $self->{body} =~ /^#MAIL FROM:/mi |
| 759 |
|
&& $self->{body} !~ /^[^#]/m) { |
| 760 |
|
## RFC 976 Batch SMTP (BSMTP) message |
| 761 |
|
$ct = $self->{header}->field ('content-type') unless ref $ct; |
| 762 |
|
$mt = $ct->media_type_major ('application'); |
| 763 |
|
$mst = $ct->media_type_minor ('x-batch-smtp'); |
| 764 |
|
} |
| 765 |
|
} |
| 766 |
|
} else { |
| 767 |
|
($mt, $mst) = ($ct->media_type_major, $ct->media_type_minor); |
| 768 |
|
} |
| 769 |
|
if ($self->{option}->{guess_media_type}) { |
| 770 |
|
if ($mt eq 'text' && $mst eq 'plain') { |
| 771 |
|
my $mls = $self->{header}->field ('x-mlserver', -new_item_unless_exist => 0); |
| 772 |
|
if (ref $mls && $mls =~ /fml/) { |
| 773 |
|
my $s = $self->{header}->field ('subject', -new_item_unless_exist => 0); |
| 774 |
|
if (index ($s, 'RFC934(mh-burst)') >= 0) { |
| 775 |
|
$ct = $self->{header}->field ('content-type') unless ref $ct; |
| 776 |
|
$mt = $ct->media_type_major ('text'); |
| 777 |
|
$mst = $ct->media_type_minor ('x-message-rfc934'); |
| 778 |
|
$ct->delete ('charset'); |
| 779 |
|
} elsif (index ($s, 'Digest (RFC1153)') >= 0) { |
| 780 |
|
$ct = $self->{header}->field ('content-type') unless ref $ct; |
| 781 |
|
$mt = $ct->media_type_major ('text'); |
| 782 |
|
$mst = $ct->media_type_minor ('x-message-rfc1153'); |
| 783 |
|
$ct->delete ('charset'); |
| 784 |
|
} |
| 785 |
|
} |
| 786 |
} |
} |
|
return wantarray? ($self->{option}->{body_default_media_type}, |
|
|
$self->{option}->{body_default_media_subtype}): |
|
|
$self->{option}->{body_default_media_type}.'/' |
|
|
.$self->{option}->{body_default_media_subtype}; |
|
| 787 |
} |
} |
| 788 |
if (wantarray) { |
if (wantarray) { |
| 789 |
($ct->media_type_major, $ct->media_type_minor); |
($mt, $mst); |
| 790 |
} else { |
} else { |
| 791 |
$ct->media_type; |
ref $ct ? $ct->media_type : sprintf '%s/%s', $mt, $mst; |
| 792 |
} |
} |
| 793 |
} |
} |
| 794 |
*media_type = \&content_type; |
*media_type = \&content_type; |
| 811 |
''; |
''; |
| 812 |
} |
} |
| 813 |
|
|
| 814 |
|
sub sender ($;%) { |
| 815 |
|
my $self = shift; |
| 816 |
|
my %params = @_; |
| 817 |
|
my %option = %{$self->{option}}; |
| 818 |
|
$option{use_x_envelope_from} = 1; ## X-Envelope-From: |
| 819 |
|
$option{use_normal} = 1; ## From:, Sender: |
| 820 |
|
$option{use_resent} = 1; ## Resent-From:, Resent-Sender: |
| 821 |
|
my $hdr = $self->{header}; |
| 822 |
|
if ($option{use_x_envelope_from} && $hdr->field_exist ('x-envelope-from')) { |
| 823 |
|
return $hdr->field ('x-envelope-from')->addr_spec; |
| 824 |
|
} elsif ($option{use_resent} && $hdr->field_exist ('resent-sender')) { |
| 825 |
|
## TODO: Resent block support |
| 826 |
|
return $hdr->field ('resent-sender')->addr_spec; |
| 827 |
|
} elsif ($option{use_resent} && $hdr->field_exist ('resent-from')) { |
| 828 |
|
## TODO: Resent block support |
| 829 |
|
return $hdr->field ('resent-from')->addr_spec; |
| 830 |
|
} elsif ($option{use_normal} && $hdr->field_exist ('sender')) { |
| 831 |
|
return $hdr->field ('sender')->addr_spec; |
| 832 |
|
} elsif ($option{use_normal} && $hdr->field_exist ('from')) { |
| 833 |
|
return $hdr->field ('from')->addr_spec; |
| 834 |
|
} |
| 835 |
|
undef; |
| 836 |
|
} |
| 837 |
|
|
| 838 |
|
sub destination ($;%) { |
| 839 |
|
my $self = shift; |
| 840 |
|
my %params = @_; |
| 841 |
|
my %option = %{$self->{option}}; |
| 842 |
|
$option{use_x_envelope_to} = 1; ## X-Envelope-To: |
| 843 |
|
$option{use_normal} = 1; ## To:, Cc:, Bcc: |
| 844 |
|
$option{use_resent} = 1; ## Resent-To:, Resent-Cc:, Resent-Bcc: |
| 845 |
|
for (grep {/^-/} keys %params) {$option{substr ($_, 1)} = $params{$_}} |
| 846 |
|
my $hdr = $self->{header}; |
| 847 |
|
my @to; |
| 848 |
|
if ($option{use_x_envelope_to} && $hdr->field_exist ('x-rfc822-x-envelope-to')) { |
| 849 |
|
@to = $hdr->field ('x-rfc822-x-envelope-to')->addr_spec; |
| 850 |
|
} elsif ($option{use_resent} && $hdr->field_exist ('x-rfc822-resent-from')) { |
| 851 |
|
## TODO: Resent block support |
| 852 |
|
@to = ($hdr->field ('x-rfc822-resent-to')->addr_spec, |
| 853 |
|
$hdr->field ('x-rfc822-resent-cc')->addr_spec, |
| 854 |
|
$hdr->field ('x-rfc822-resent-bcc')->addr_spec); |
| 855 |
|
} elsif ($option{use_normal}) { |
| 856 |
|
@to = ($hdr->field ('x-rfc822-to')->addr_spec, |
| 857 |
|
$hdr->field ('x-rfc822-cc')->addr_spec, |
| 858 |
|
$hdr->field ('x-rfc822-bcc')->addr_spec); |
| 859 |
|
} |
| 860 |
|
@to; |
| 861 |
|
} |
| 862 |
|
|
| 863 |
|
sub list_name ($) { |
| 864 |
|
my $self = shift; |
| 865 |
|
my $hdr = $self->{header}; |
| 866 |
|
if ($hdr->field_exist ('list-id')) { |
| 867 |
|
my $lname = $hdr->field ('list-id')->display_name; |
| 868 |
|
return $lname if length $lname; |
| 869 |
|
} |
| 870 |
|
my $v = sub { |
| 871 |
|
my $name = shift; |
| 872 |
|
my $f = $hdr->field ($name, -new_item_unless_exist => 0); |
| 873 |
|
return $f->value if ref $f; |
| 874 |
|
undef; |
| 875 |
|
}; |
| 876 |
|
## BUG: list-name "0" is not supported. |
| 877 |
|
my $lname = &$v ('x-ml-name') || &$v ('x-mailing-list-name') |
| 878 |
|
|| &$v ('x-mailinglist-name') || &$v ('ml-name'); |
| 879 |
|
return $lname if length $lname; |
| 880 |
|
if ($hdr->field_exist ('x-sequence')) { |
| 881 |
|
if ($hdr->field ('x-sequence')->value =~ /^(\S+)\s+\d+$/) { |
| 882 |
|
return $1; |
| 883 |
|
} |
| 884 |
|
} |
| 885 |
|
if ($hdr->field_exist ('subject')) { |
| 886 |
|
my $s = $hdr->field ('subject'); |
| 887 |
|
return $s->list_name if $s->method_available ('list_name'); |
| 888 |
|
} |
| 889 |
|
undef; |
| 890 |
|
} |
| 891 |
|
|
| 892 |
|
sub list_count ($) { |
| 893 |
|
my $self = shift; |
| 894 |
|
my $hdr = $self->{header}; |
| 895 |
|
my $v = sub { |
| 896 |
|
my $name = shift; |
| 897 |
|
my $f = $hdr->field ($name, -new_item_unless_exist => 0); |
| 898 |
|
return $f->value if ref $f; |
| 899 |
|
undef; |
| 900 |
|
}; |
| 901 |
|
## BUG: list-count 0 is not supported. |
| 902 |
|
my $lc = &$v ('x-mail-count') || &$v ('x-ml-count') || &$v ('x-mailinglist-id') |
| 903 |
|
|| &$v ('mail-count') || &$v ('x-article-no') || &$v ('x-ml-counter') |
| 904 |
|
|| &$v ('x-ml-id') || &$v ('x-ml-sequence') || &$v ('x-serial-no') |
| 905 |
|
|| &$v ('x-seqno'); |
| 906 |
|
return $lc if $lc; |
| 907 |
|
if ($hdr->field_exist ('x-sequence')) { |
| 908 |
|
my $s = $hdr->field ('x-sequence')->value; |
| 909 |
|
if ($s =~ /^\S+\s+(\d+)$/) { |
| 910 |
|
return $1; |
| 911 |
|
} elsif ($s =~ /(\d+)/) { |
| 912 |
|
return $1; |
| 913 |
|
} |
| 914 |
|
} |
| 915 |
|
if ($hdr->field_exist ('subject')) { |
| 916 |
|
my $s = $hdr->field ('subject'); |
| 917 |
|
return $s->list_count if $s->method_available ('list_count'); |
| 918 |
|
} |
| 919 |
|
undef; |
| 920 |
|
} |
| 921 |
|
|
| 922 |
=back |
=back |
| 923 |
|
|
| 924 |
=head1 MISC. METHODS |
=head1 MISC. METHODS |
| 946 |
my %option = @_; |
my %option = @_; |
| 947 |
while (my ($name, $value) = splice (@_, 0, 2)) { |
while (my ($name, $value) = splice (@_, 0, 2)) { |
| 948 |
$self->{option}->{$name} = $value; |
$self->{option}->{$name} = $value; |
|
if ($name eq 'format') { |
|
|
$self->header->option (-format => $value); |
|
|
} |
|
| 949 |
} |
} |
| 950 |
if ($option{-recursive}) { |
if ($option{-recursive} && ($self->content_type)[0] ne 'message') { |
| 951 |
$self->{header}->option (%option); |
$self->{header}->option (%option); |
| 952 |
$self->{body}->option (%option) if ref $self->{body}; |
$self->{body}->option (%option) if ref $self->{body}; |
| 953 |
} |
} |
| 980 |
0; |
0; |
| 981 |
} |
} |
| 982 |
|
|
| 983 |
|
sub import ($;%) { |
| 984 |
|
my $self = shift; |
| 985 |
|
my %option = @_; |
| 986 |
|
for (keys %option) { |
| 987 |
|
$DEFAULT{$_} = $option{$_}; |
| 988 |
|
} |
| 989 |
|
if ($option{-body_default_charset} && !$option{-body_default_charset_input}) { |
| 990 |
|
$DEFAULT{-body_default_charset_input} = $option{-body_default_charset}; |
| 991 |
|
} |
| 992 |
|
if ($option{-header_default_charset} && !$option{-header_default_charset_input}) { |
| 993 |
|
$DEFAULT{-header_default_charset_input} = $option{-header_default_charset}; |
| 994 |
|
} |
| 995 |
|
} |
| 996 |
|
|
| 997 |
=back |
=back |
| 998 |
|
|
| 999 |
=head1 C<format> |
=head1 C<format> |
| 1016 |
|
|
| 1017 |
Internet mail message, defined by IETF RFC 822 |
Internet mail message, defined by IETF RFC 822 |
| 1018 |
|
|
| 1019 |
|
=item mail-rfc822+rfc1123 |
| 1020 |
|
|
| 1021 |
|
Internet mail message, defined by IETF RFC 822, ammended by RFC 1123 |
| 1022 |
|
|
| 1023 |
=item mail-rfc2822 |
=item mail-rfc2822 |
| 1024 |
|
|
| 1025 |
Internet mail message, defined by IETF RFC 2822 |
Internet mail message, defined by IETF RFC 2822 |
| 1100 |
|
|
| 1101 |
CGI/1.1 output (for HTTP), defined by coar-cgi-v11 (IETF Internet Draft) |
CGI/1.1 output (for HTTP), defined by coar-cgi-v11 (IETF Internet Draft) |
| 1102 |
|
|
|
=item http-1.0-cgi-1.1 |
|
|
|
|
|
CGI/1.1 output (for HTTP/1.0), defined by coar-cgi-v11 (IETF Internet Draft) |
|
|
|
|
|
=item http-1.1-cgi-1.1 |
|
|
|
|
|
CGI/1.1 output (for HTTP/1.1), defined by coar-cgi-v11 (IETF Internet Draft) |
|
|
|
|
| 1103 |
=item http-cgi-1.2 |
=item http-cgi-1.2 |
| 1104 |
|
|
| 1105 |
CGI/1.2 output, defined by coar-cgi-v12 (to be IETF Internet Draft) |
CGI/1.2 output, defined by coar-cgi-v12 (to be IETF Internet Draft) |
| 1106 |
|
|
|
=item http-1.0-cgi-1.2 |
|
|
|
|
|
CGI/1.2 output (for HTTP/1.0), defined by coar-cgi-v11 (IETF Internet Draft) |
|
|
|
|
|
=item http-1.1-cgi-1.2 |
|
|
|
|
|
CGI/1.2 output (for HTTP/1.1), defined by coar-cgi-v11 (IETF Internet Draft) |
|
|
|
|
| 1107 |
=item http-sip-2.0 |
=item http-sip-2.0 |
| 1108 |
|
|
| 1109 |
SIP/2.0 message, defined by IETF RFC 2543 |
SIP/2.0 message, defined by IETF RFC 2543 |
| 1124 |
|
|
| 1125 |
CPIM/1.0 (IETF Internet Draft) |
CPIM/1.0 (IETF Internet Draft) |
| 1126 |
|
|
| 1127 |
=item uri-url-mailto-mail-rfc822, uri-url-mailto-mail-rfc2822 |
=item uri-url-mailto |
| 1128 |
|
|
| 1129 |
mailto: URL scheme |
mailto: URL scheme |
| 1130 |
|
|
| 1132 |
|
|
| 1133 |
mailto: URL scheme (defined by RFC 1738) |
mailto: URL scheme (defined by RFC 1738) |
| 1134 |
|
|
| 1135 |
=item uri-url-mailto-rfc2368, uri-url-mailto-rfc2822 |
=item uri-url-mailto-rfc2368 |
| 1136 |
|
|
| 1137 |
mailto: URL scheme (defined by RFC 2368) |
mailto: URL scheme (defined by RFC 2368) |
| 1138 |
|
|
| 1139 |
=item uri-url-mailto-to-mail-rfc822, uri-url-mailto-to-mail-rfc2822 |
=item uri-url-mailto-to |
| 1140 |
|
|
| 1141 |
C<to> part of mailto: URL scheme (for internal use only) |
C<to> part of mailto: URL scheme (for internal use only) |
| 1142 |
|
|
| 1161 |
|
|
| 1162 |
=head1 LICENSE |
=head1 LICENSE |
| 1163 |
|
|
| 1164 |
Copyright 2002 wakaba E<lt>[email protected]<gt>. |
Copyright 2002 Wakaba <[email protected]>. |
| 1165 |
|
|
| 1166 |
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
| 1167 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |