# Copyrights 2001-2007 by Mark Overmeer.
# For other contributors see ChangeLog.
# See the manual pages for details on the licensing terms.
# Pod stripped from pm file by OODoc 1.03.
use strict;
use warnings;
package Mail::Message::Body;
use vars '$VERSION';
$VERSION = '2.079';
use base 'Mail::Reporter';
use Carp;
use MIME::Types;
use File::Basename 'basename';
my MIME::Types $mime_types;
sub encode(@)
{ my ($self, %args) = @_;
# simplify the arguments
my $type_from = $self->type;
my $type_to = $args{mime_type} || $type_from->clone;
$type_to = Mail::Message::Field->new('Content-Type' => $type_to)
unless ref $type_to;
if(my $charset = delete $args{charset})
{ # Charset conversions are ignored for now.
$type_to->attribute(charset => $charset);
}
my $transfer = $args{transfer_encoding} || $self->transferEncoding->clone;
$transfer = Mail::Message::Field->new('Content-Transfer-Encoding' =>
$transfer) unless ref $transfer;
# What will we do?
# my $mime_was = lc $type_from;
# my $mime_to = lc $type_to;
# If possible, update unify() too.
# my $char_was = $type_from->attribute('charset');
# my $char_to = $type_to->attribute('charset');
my $trans_was = lc $self->transferEncoding;
my $trans_to = lc $transfer;
#
# The only translations implemented now is content transfer encoding.
#
#warn "Translate ($trans_was) -> ($trans_to)\n";
return $self if $trans_was eq $trans_to;
my $bodytype = $args{result_type} || ref $self;
my $decoded;
if($trans_was eq 'none') {$decoded = $self}
elsif(my $decoder = $self->getTransferEncHandler($trans_was))
{ $decoded = $decoder->decode($self, result_type => $bodytype) }
else
{ $self->log(WARNING =>
"No decoder defined for transfer encoding $trans_was.");
return $self;
}
my $encoded;
if($trans_to eq 'none') {$encoded = $decoded}
elsif(my $encoder = $self->getTransferEncHandler($trans_to))
{ $encoded = $encoder->encode($decoded, result_type => $bodytype) }
else
{ $self->log(WARNING =>
"No encoder defined for transfer encoding $trans_to.");
return $decoded;
}
$encoded;
}
#------------------------------------------
sub check()
{ my $self = shift;
return $self if $self->checked;
my $eol = $self->eol;
my $encoding = $self->transferEncoding->body;
return $self->eol($eol)
if $encoding eq 'none';
my $encoder = $self->getTransferEncHandler($encoding);
my $checked
= $encoder
? $encoder->check($self)->eol($eol)
: $self->eol($eol);
$checked->checked(1);
$checked;
}
#------------------------------------------
sub encoded()
{ my $self = shift;
return $self->check
unless $self->transferEncoding eq 'none';
$mime_types ||= MIME::Types->new;
my $mime = $mime_types->type($self->type->body);
$self->encode(transfer_encoding =>
defined $mime ? $mime->encoding : 'base64');
}
#------------------------------------------
sub unify($)
{ my ($self, $body) = @_;
return $self if $self==$body;
my $mime = $self->type;
my $transfer = $self->transferEncoding;
my $encoded = $body->encode
( mime_type => $mime
, transfer_encoding => $transfer
);
# Encode makes the best of it, but is it good enough?
my $newmime = $encoded->type;
return unless $newmime eq $mime;
return unless $transfer eq $encoded->transferEncoding;
# Character transformation not possible yet.
# my $want_charset= $mime->attribute('charset') || '';
# my $got_charset = $newmime->attribute('charset') || '';
# return unless $want_charset eq $got_charset;
$encoded;
}
#------------------------------------------
sub isBinary()
{ my $self = shift;
$mime_types ||= MIME::Types->new(only_complete => 1);
my $type = $self->type or return 1;
my $mime = $mime_types->type($type->body) or return 1;
$mime->isBinary;
}
#------------------------------------------
sub isText() { not shift->isBinary }
#------------------------------------------
sub dispositionFilename(;$)
{ my $self = shift;
my $raw;
my $field;
if($field = $self->disposition)
{ $raw = $field->attribute('filename')
|| $field->attribute('file')
|| $field->attribute('name');
}
if(!defined $raw && ($field = $self->type))
{ $raw = $field->attribute('filename')
|| $field->attribute('file')
|| $field->attribute('name');
}
return $raw unless @_;
my $dir = shift;
my $filename = '';
if(defined $raw)
{ $filename = basename $raw;
$filename =~ s/[^\w.-]//;
}
unless(length $filename)
{ my $ext = ($self->mimeType->extensions)[0] || 'raw';
my $unique;
for($unique = 'part-0'; 1; $unique++)
{ my $out = File::Spec->catfile($dir, "$unique.$ext");
open IN, "<", $out or last; # does not exist: can use it
close IN;
}
$filename = "$unique.$ext";
}
File::Spec->catfile($dir, $filename);
}
#------------------------------------------
my %transfer_encoder_classes =
( base64 => 'Mail::Message::TransferEnc::Base64'
, binary => 'Mail::Message::TransferEnc::Binary'
, '8bit' => 'Mail::Message::TransferEnc::EightBit'
, 'quoted-printable' => 'Mail::Message::TransferEnc::QuotedPrint'
, '7bit' => 'Mail::Message::TransferEnc::SevenBit'
);
my %transfer_encoders; # they are reused.
sub getTransferEncHandler($)
{ my ($self, $type) = @_;
return $transfer_encoders{$type}
if exists $transfer_encoders{$type}; # they are reused.
my $class = $transfer_encoder_classes{$type};
return unless $class;
eval "require $class";
confess "Cannot load $class: $@\n" if $@;
$transfer_encoders{$type} = $class->new;
}
#------------------------------------------
sub addTransferEncHandler($$)
{ my ($this, $name, $what) = @_;
my $class;
if(ref $what)
{ $transfer_encoders{$name} = $what;
$class = ref $what;
}
else
{ delete $transfer_encoders{$name};
$class = $what;
}
$transfer_encoder_classes{$name} = $class;
$this;
}
1;
syntax highlighted by Code2HTML, v. 0.9.1