summaryrefslogtreecommitdiff
path: root/cpan/lib/Mail/Address.pm
diff options
context:
space:
mode:
authorfukachan <fukachan>2001-01-19 13:55:05 +0000
committerfukachan <fukachan>2001-01-19 13:55:05 +0000
commitd63380e790c2f93ae981a0425b85d22601c1acaa (patch)
tree255ceabf69b7a95c02f3a648ddf4c194f66eeb3b /cpan/lib/Mail/Address.pm
parent4377641665acbf1a4a83883241afe392e88ec112 (diff)
downloadfml8-d63380e790c2f93ae981a0425b85d22601c1acaa.tar.gz
fml8-d63380e790c2f93ae981a0425b85d22601c1acaa.tar.bz2
fml8-d63380e790c2f93ae981a0425b85d22601c1acaa.zip
Initial revision
Diffstat (limited to 'cpan/lib/Mail/Address.pm')
-rw-r--r--cpan/lib/Mail/Address.pm424
1 files changed, 424 insertions, 0 deletions
diff --git a/cpan/lib/Mail/Address.pm b/cpan/lib/Mail/Address.pm
new file mode 100644
index 00000000..74a6b580
--- /dev/null
+++ b/cpan/lib/Mail/Address.pm
@@ -0,0 +1,424 @@
+# Mail::Address.pm
+#
+# Copyright (c) 1995-8 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# This program is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+
+package Mail::Address;
+use strict;
+
+use Carp;
+use vars qw($VERSION);
+use locale;
+
+$VERSION = "1.17";
+sub Version { $VERSION }
+
+#
+# given a comment, attempt to extract a person's name
+#
+
+sub _extract_name
+{
+ local $_ = shift || '';
+
+ # trim whitespace
+ s/^\s+//;
+ s/\s+$//;
+ s/\s+/ /;
+
+ # Disregard numeric names (e.g. 123456.1234@compuserve.com)
+ return "" if /^[\d ]+$/;
+
+ # remove outermost parenthesis
+ s/^\(|\)$//g;
+
+ # remove outer quotation marks
+ s/^"|"$//g;
+
+ # remove embedded comments
+ s/\(.*\)//g;
+
+ # reverse "Last, First M." if applicable
+ s/^([^\s]+) ?, ?(.*)$/$2 $1/;
+ s/,.*//;
+
+ # Set the case of the name to first char upper rest lower
+ # Upcase first letter on name
+ s/\b(\w+)/\L\u$1/igo;
+
+ # Scottish names such as 'McLeod'
+ s/\bMc(\w)/Mc\u$1/igo;
+
+ # Irish names such as 'O'Malley, O'Reilly'
+ s/\bo'(\w)/O'\u$1/igo;
+
+ # Roman numerals, eg 'Level III Support'
+ s/\b(x*(ix)?v*(iv)?i*)\b/\U$1/igo;
+
+ # some cleanup
+ s/\[[^\]]*\]//g;
+ s/(^[\s'"]+|[\s'"]+$)//g;
+ s/\s{2,}/ /g;
+
+ return $_;
+}
+
+sub _tokenise {
+ local($_) = join(',', @_);
+ my(@words,$snippet,$field);
+
+ s/\A\s+//;
+ s/[\r\n]+/ /g;
+
+ while ($_ ne '')
+ {
+ $field = '';
+ if( s/^\s*\(/(/ ) # (...)
+ {
+ my $depth = 0;
+
+ PAREN: while(s/^(\(([^\(\)\\]|\\.)*)//)
+ {
+ $field .= $1;
+ $depth++;
+ while(s/^(([^\(\)\\]|\\.)*\)\s*)//)
+ {
+ $field .= $1;
+ last PAREN unless --$depth;
+ $field .= $1 if s/^(([^\(\)\\]|\\.)+)//;
+ }
+ }
+
+ carp "Unmatched () '$field' '$_'"
+ if $depth;
+
+ $field =~ s/\s+\Z//;
+ push(@words, $field);
+
+ next;
+ }
+
+ s/^("([^"\\]|\\.)*")\s*// # "..."
+ || s/^(\[([^\]\\]|\\.)*\])\s*// # [...]
+ || s/^([^\s\Q()<>\@,;:\\".[]\E]+)\s*//
+ || s/^([\Q()<>\@,;:\\".[]\E])\s*//
+ and do { push(@words, $1); next; };
+
+ croak "Unrecognised line: $_";
+ }
+
+ push(@words, ",");
+
+ \@words;
+}
+
+sub _find_next {
+ my $idx = shift;
+ my $tokens = shift;
+ my $len = shift;
+ while($idx < $len) {
+ my $c = $tokens->[$idx];
+ return $c if($c eq "," || $c eq "<");
+ $idx++;
+ }
+ return "";
+}
+
+sub _complete {
+ my $pkg = shift;
+ my $phrase = shift;
+ my $address = shift;
+ my $comment = shift;
+ my $o = undef;
+
+ if(@{$phrase} || @{$comment} || @{$address}) {
+ $o = $pkg->new(join(" ",@{$phrase}),
+ join("", @{$address}),
+ join(" ",@{$comment}));
+ @{$phrase} = ();
+ @{$address} = ();
+ @{$comment} = ();
+ }
+
+ return $o;
+}
+
+
+sub new {
+ my $pkg = shift;
+ my $me = bless [@_], $pkg;
+ return $me;
+}
+
+
+sub parse {
+ my $pkg = shift;
+
+ local $_;
+
+ my @phrase = ();
+ my @comment = ();
+ my @address = ();
+ my @objs = ();
+ my $depth = 0;
+ my $idx = 0;
+ my $tokens = _tokenise(grep { defined $_} @_);
+ my $len = scalar(@{$tokens});
+ my $next = _find_next($idx,$tokens,$len);
+
+ for( ; $idx < $len ; $idx++) {
+ $_ = $tokens->[$idx];
+
+ if(substr($_,0,1) eq "(") {
+ push(@comment,$_);
+ }
+ elsif($_ eq '<') {
+ $depth++;
+ }
+ elsif($_ eq '>') {
+ $depth-- if($depth);
+ unless($depth) {
+ my $o = _complete($pkg,\@phrase, \@address, \@comment);
+ push(@objs, $o) if(defined $o);
+ $depth = 0;
+ $next = _find_next($idx,$tokens,$len);
+ }
+ }
+ elsif($_ eq ',') {
+ warn "Unmatched '<>'" if($depth);
+ my $o = _complete($pkg,\@phrase, \@address, \@comment);
+ push(@objs, $o) if(defined $o);
+ $depth = 0;
+ $next = _find_next($idx+1,$tokens,$len);
+ }
+ elsif($depth) {
+ push(@address,$_);
+ }
+ elsif($next eq "<") {
+ push(@phrase,$_);
+ }
+ elsif($_ =~ /\A[\Q.\@:;\E]\Z/ || !scalar(@address) || $address[$#address] =~ /\A[\Q.\@:;\E]\Z/) {
+ push(@address,$_);
+ }
+ else {
+ warn "Unmatched '<>'" if($depth);
+ my $o = _complete($pkg,\@phrase, \@address, \@comment);
+ push(@objs, $o) if(defined $o);
+ $depth = 0;
+ push(@address,$_);
+ }
+ }
+ @objs;
+}
+
+sub set_or_get {
+ my $me = shift;
+ my $i = shift;
+ my $val = $me->[$i];
+
+ $me->[$i] = shift if(@_);
+
+ $val;
+}
+
+
+sub phrase { set_or_get(shift,0,@_) }
+sub address { set_or_get(shift,1,@_) }
+sub comment { set_or_get(shift,2,@_) }
+
+
+sub format {
+ my @fmts = ();
+ my $me;
+
+ foreach $me (@_) {
+ my($phrase,$addr,$comment) = @{$me};
+ my @tmp = ();
+
+ if(defined $phrase && length($phrase)) {
+ push(@tmp, $phrase);
+ push(@tmp, "<" . $addr . ">") if(defined $addr && length($addr));
+ }
+ else {
+ push(@tmp, $addr) if(defined $addr && length($addr));
+ }
+ if(defined($comment) && $comment =~ /\S/) {
+ $comment =~ s/^\s*\(?/(/;
+ $comment =~ s/\)?\s*$/)/;
+ }
+ push(@tmp, $comment) if(defined $comment && length($comment));
+ push(@fmts, join(" ", @tmp)) if(scalar(@tmp));
+ }
+
+ return join(", ", @fmts);
+}
+
+
+sub name
+{
+ my $me = shift;
+ my $phrase = $me->phrase;
+ my $addr = $me->address;
+
+ $phrase = $me->comment unless(defined($phrase) && length($phrase));
+
+ my $name = _extract_name($phrase);
+
+ # first.last@domain address
+ if($name eq '' && $addr =~ /([^\%\.\@_]+([\._][^\%\.\@_]+)+)[\@\%]/o)
+ {
+ ($name = $1) =~ s/[\._]+/ /go;
+ $name = _extract_name($name);
+ }
+
+ if($name eq '' && $addr =~ m#/g=#oi)
+ # X400 style address
+ {
+ my ($f) = $addr =~ m#g=([^/]*)#oi;
+ my ($l) = $addr =~ m#s=([^/]*)#io;
+
+ $name = _extract_name($f . " " . $l);
+ }
+
+ return length($name) ? $name : undef;
+}
+
+
+sub host {
+ my $me = shift;
+ my $addr = $me->address;
+ my $i = rindex($addr,'@');
+
+ my $host = ($i >= 0) ? substr($addr,$i+1) : undef;
+
+ return $host;
+}
+
+
+sub user {
+ my $me = shift;
+ my $addr = $me->address;
+ my $i = index($addr,'@');
+
+ my $user = ($i >= 0) ? substr($addr,0,$i) : $addr;
+
+ return $user;
+}
+
+
+sub path {
+ return ();
+}
+
+
+sub canon {
+ my $me = shift;
+ return ($me->host, $me->user, $me->path);
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Mail::Address - Parse mail addresses
+
+=head1 SYNOPSIS
+
+ use Mail::Address;
+
+ my @addrs = Mail::Address->parse($line);
+
+ foreach $addr (@addrs) {
+ print $addr->format,"\n";
+ }
+
+=head1 DESCRIPTION
+
+C<Mail::Address> extracts and manipulates RFC822 compilant email
+addresses. As well as being able to create C<Mail::Address> objects
+in the normal manner, C<Mail::Address> can extract addresses from
+the To and Cc lines found in an email message.
+
+=head1 CONSTRUCTORS
+
+=over 4
+
+=item new( PHRASE, ADDRESS, [ COMMENT ])
+
+ Mail::Address->new("Perl5 Porters", "perl5-porters@africa.nicoh.com");
+
+Create a new C<Mail::Address> object which represents an address with the
+elements given. In a message these 3 elements would be seen like:
+
+ PHRASE <ADDRESS> (COMMENT)
+ ADDRESS (COMMENT)
+
+=item parse( LINE )
+
+ Mail::Address->parse($line);
+
+Parse the given line a return a list of extracted C<Mail::Address> objects.
+The line would normally be one taken from a To,Cc or Bcc line in a message
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item phrase ()
+
+Return the phrase part of the object.
+
+=item address ()
+
+Return the address part of the object.
+
+=item comment ()
+
+Return the comment part of the object
+
+=item format ()
+
+Return a string representing the address in a suitable form to be placed
+on a To,Cc or Bcc line of a message
+
+=item name ()
+
+Using the information contained within the object attempt to identify what
+the person or groups name is
+
+=item host ()
+
+Return the address excluding the user id and '@'
+
+=item user ()
+
+Return the address excluding the '@' and the mail domain
+
+=item path ()
+
+Unimplemented yet but should return the UUCP path for the message
+
+=item canon ()
+
+Unimplemented yet but should return the UUCP canon for the message
+
+=back
+
+=head1 AUTHOR
+
+Graham Barr <gbarr@pobox.com>
+
+=head1 COPYRIGHT
+
+Copyright (c) 1995-8 Graham Barr. All rights reserved. This program is free
+software; you can redistribute it and/or modify it under the same terms
+as Perl itself.
+
+=cut
+