232 lines
4.9 KiB
Perl
232 lines
4.9 KiB
Perl
# Copyrights 1995-2018 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 2.02.
|
|
# This code is part of the bundle MailTools. Meta-POD processed with
|
|
# OODoc into POD and HTML manual-pages. See README.md for Copyright.
|
|
# Licensed under the same terms as Perl itself.
|
|
|
|
package Mail::Field;
|
|
use vars '$VERSION';
|
|
$VERSION = '2.20';
|
|
|
|
|
|
use strict;
|
|
|
|
use Carp;
|
|
use Mail::Field::Generic;
|
|
|
|
|
|
sub _header_pkg_name
|
|
{ my $header = lc shift;
|
|
$header =~ s/((\b|_)\w)/\U$1/g;
|
|
|
|
if(length($header) > 8)
|
|
{ my @header = split /[-_]+/, $header;
|
|
my $chars = int((7 + @header) / @header) || 1;
|
|
$header = substr join('', map {substr $_,0,$chars} @header), 0, 8;
|
|
}
|
|
else
|
|
{ $header =~ s/[-_]+//g;
|
|
}
|
|
|
|
'Mail::Field::' . $header;
|
|
}
|
|
|
|
sub _require_dir
|
|
{ my($class, $dir, $dir_sep) = @_;
|
|
|
|
local *DIR;
|
|
opendir DIR, $dir
|
|
or return;
|
|
|
|
my @inc;
|
|
foreach my $f (readdir DIR)
|
|
{ $f =~ /^([\w\-]+)/ or next;
|
|
my $p = $1;
|
|
my $n = "$dir$dir_sep$p";
|
|
|
|
if(-d $n )
|
|
{ _require_dir("${class}::$f", $n, $dir_sep);
|
|
}
|
|
else
|
|
{ $p =~ s/-/_/go;
|
|
eval "require ${class}::$p";
|
|
|
|
# added next warning in 2.14, may be ignored for ancient code
|
|
warn $@ if $@;
|
|
}
|
|
}
|
|
closedir DIR;
|
|
}
|
|
|
|
sub import
|
|
{ my $class = shift;
|
|
|
|
if(@_)
|
|
{ local $_;
|
|
eval "require " . _header_pkg_name($_) || die $@
|
|
for @_;
|
|
return;
|
|
}
|
|
|
|
my ($dir, $dir_sep);
|
|
foreach my $f (grep defined $INC{$_}, keys %INC)
|
|
{ next if $f !~ /^Mail(\W)Field\W/i;
|
|
$dir_sep = $1;
|
|
# $dir = ($INC{$f} =~ /(.*Mail\W+Field)/i)[0] . $dir_sep;
|
|
($dir = $INC{$f}) =~ s/(Mail\W+Field).*/$1$dir_sep/;
|
|
last;
|
|
}
|
|
|
|
_require_dir('Mail::Field', $dir, $dir_sep);
|
|
}
|
|
|
|
# register a header class, this creates a new method in Mail::Field
|
|
# which will call new on that class
|
|
sub register
|
|
{ my $thing = shift;
|
|
my $method = lc shift;
|
|
my $class = shift || ref($thing) || $thing;
|
|
|
|
$method =~ tr/-/_/;
|
|
$class = _header_pkg_name $method
|
|
if $class eq "Mail::Field";
|
|
|
|
croak "Re-register of $method"
|
|
if Mail::Field->can($method);
|
|
|
|
no strict 'refs';
|
|
*{$method} = sub {
|
|
shift;
|
|
$class->can('stringify') or eval "require $class" or die $@;
|
|
$class->_build(@_);
|
|
};
|
|
}
|
|
|
|
# the *real* constructor
|
|
# if called with one argument then the `parse' method will be called
|
|
# otherwise the `create' method is called
|
|
|
|
sub _build
|
|
{ my $self = bless {}, shift;
|
|
@_==1 ? $self->parse(@_) : $self->create(@_);
|
|
}
|
|
|
|
#-------------
|
|
|
|
sub new
|
|
{ my $class = shift;
|
|
my $field = lc shift;
|
|
$field =~ tr/-/_/;
|
|
$class->$field(@_);
|
|
}
|
|
|
|
|
|
sub combine {confess "Combine not implemented" }
|
|
|
|
our $AUTOLOAD;
|
|
sub AUTOLOAD
|
|
{ my $method = $AUTOLOAD;
|
|
$method =~ s/.*:://;
|
|
|
|
$method =~ /^[^A-Z\x00-\x1f\x80-\xff :]+$/
|
|
or croak "Undefined subroutine &$AUTOLOAD called";
|
|
|
|
my $class = _header_pkg_name $method;
|
|
|
|
unless(eval "require $class")
|
|
{ my $tag = $method;
|
|
$tag =~ s/_/-/g;
|
|
$tag = join '-',
|
|
map { /^[b-df-hj-np-tv-z]+$|^MIME$/i ? uc($_) : ucfirst(lc $_) }
|
|
split /\-/, $tag;
|
|
|
|
no strict;
|
|
@{"${class}::ISA"} = qw(Mail::Field::Generic);
|
|
*{"${class}::tag"} = sub { $tag };
|
|
}
|
|
|
|
Mail::Field->can($method)
|
|
or $class->register($method);
|
|
|
|
goto &$AUTOLOAD;
|
|
}
|
|
|
|
|
|
# Of course, the functionality should have been in the Mail::Header class
|
|
sub extract
|
|
{ my ($class, $tag, $head) = (shift, shift, shift);
|
|
|
|
my $method = lc $tag;
|
|
$method =~ tr/-/_/;
|
|
|
|
if(@_==0 && wantarray)
|
|
{ my @ret;
|
|
my $text; # need real copy!
|
|
foreach $text ($head->get($tag))
|
|
{ chomp $text;
|
|
push @ret, $class->$method($text);
|
|
}
|
|
return @ret;
|
|
}
|
|
|
|
my $idx = shift || 0;
|
|
my $text = $head->get($tag,$idx)
|
|
or return undef;
|
|
|
|
chomp $text;
|
|
$class->$method($text);
|
|
}
|
|
|
|
#-------------
|
|
|
|
# before 2.00, this method could be called as class method, however
|
|
# not all extensions supported that.
|
|
sub create
|
|
{ my ($self, %arg) = @_;
|
|
%$self = ();
|
|
$self->set(\%arg);
|
|
}
|
|
|
|
|
|
# before 2.00, this method could be called as class method, however
|
|
# not all extensions supported that.
|
|
sub parse
|
|
{ my $class = ref shift;
|
|
confess "parse() not implemented";
|
|
}
|
|
|
|
#-------------
|
|
|
|
sub stringify { confess "stringify() not implemented" }
|
|
|
|
|
|
sub tag
|
|
{ my $thing = shift;
|
|
my $tag = ref($thing) || $thing;
|
|
$tag =~ s/.*:://;
|
|
$tag =~ s/_/-/g;
|
|
|
|
join '-',
|
|
map { /^[b-df-hj-np-tv-z]+$|^MIME$/i ? uc($_) : ucfirst(lc $_) }
|
|
split /\-/, $tag;
|
|
}
|
|
|
|
|
|
sub set(@) { confess "set() not implemented" }
|
|
|
|
# prevent the calling of AUTOLOAD for DESTROY :-)
|
|
sub DESTROY {}
|
|
|
|
#-------------
|
|
|
|
sub text
|
|
{ my $self = shift;
|
|
@_ ? $self->parse(@_) : $self->stringify;
|
|
}
|
|
|
|
#-------------
|
|
|
|
1;
|