File Coverage

blib/lib/Mail/RFC822/Address.pm
Criterion Covered Total %
statement 39 40 97.5
branch 9 10 90.0
condition n/a
subroutine 6 6 100.0
pod 2 4 50.0
total 56 60 93.3


line stmt bran cond sub pod time code
1             package Mail::RFC822::Address;
2              
3 1     1   697 use strict;
  1         2  
  1         37  
4 1     1   6 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  1         2  
  1         942  
5              
6             require Exporter;
7              
8             @ISA = qw(Exporter);
9              
10             # Items to export into callers namespace by default. Note: do not export
11             # names by default without a very good reason. Use EXPORT_OK instead.
12             # Do not simply export all your public functions/methods/constants.
13              
14             @EXPORT_OK = qw( valid validlist );
15              
16             @EXPORT = qw(
17            
18             );
19             $VERSION = '0.3';
20              
21              
22             my $rfc822re;
23              
24             # Preloaded methods go here.
25             my $lwsp = "(?:(?:\\r\\n)?[ \\t])";
26              
27             sub make_rfc822re {
28             # Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
29             # comment. We must allow for lwsp (or comments) after each of these.
30             # This regexp will only work on addresses which have had comments stripped
31             # and replaced with lwsp.
32              
33 1     1 0 2 my $specials = '()<>@,;:\\\\".\\[\\]';
34 1         3 my $controls = '\\000-\\031';
35              
36 1         2 my $dtext = "[^\\[\\]\\r\\\\]";
37 1         4 my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$lwsp*";
38              
39 1         5 my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$lwsp)*\"$lwsp*";
40              
41             # Use zero-width assertion to spot the limit of an atom. A simple
42             # $lwsp* causes the regexp engine to hang occasionally.
43 1         5 my $atom = "[^$specials $controls]+(?:$lwsp+|\\Z|(?=[\\[\"$specials]))";
44 1         4 my $word = "(?:$atom|$quoted_string)";
45 1         4 my $localpart = "$word(?:\\.$lwsp*$word)*";
46              
47 1         4 my $sub_domain = "(?:$atom|$domain_literal)";
48 1         4 my $domain = "$sub_domain(?:\\.$lwsp*$sub_domain)*";
49              
50 1         3 my $addr_spec = "$localpart\@$lwsp*$domain";
51              
52 1         4 my $phrase = "$word*";
53 1         7 my $route = "(?:\@$domain(?:,\@$lwsp*$domain)*:$lwsp*)";
54 1         16 my $route_addr = "\\<$lwsp*$route?$addr_spec\\>$lwsp*";
55 1         14 my $mailbox = "(?:$addr_spec|$phrase$route_addr)";
56              
57 1         21 my $group = "$phrase:$lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
58 1         16 my $address = "(?:$mailbox|$group)";
59              
60 1         14 return "$lwsp*$address";
61             }
62              
63             sub strip_comments {
64 79     79 0 113 my $s = shift;
65             # Recursively remove comments, and replace with a single space. The simpler
66             # regexps in the Email Addressing FAQ are imperfect - they will miss escaped
67             # chars in atoms, for example.
68              
69 79         1272 while ($s =~ s/^((?:[^"\\]|\\.)*
70             (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*)
71             \((?:[^()\\]|\\.)*\)/$1 /osx) {}
72 79         160 return $s;
73             }
74              
75             # valid: returns true if the parameter is an RFC822 valid address
76             #
77             sub valid ($) {
78 67     67 1 3588 my $s = strip_comments(shift);
79              
80 67 100       137 if (!$rfc822re) {
81 1         5 $rfc822re = make_rfc822re();
82             }
83              
84 67         4145 return $s =~ m/^$rfc822re$/so;
85             }
86              
87             # validlist: In scalar context, returns true if the parameter is an RFC822
88             # valid list of addresses.
89             #
90             # In list context, returns an empty list on failure (an invalid
91             # address was found); otherwise a list whose first element is the
92             # number of addresses found and whose remaining elements are the
93             # addresses. This is needed to disambiguate failure (invalid)
94             # from success with no addresses found, because an empty string is
95             # a valid list.
96              
97             sub validlist ($) {
98 12     12 1 1706 my $s = strip_comments(shift);
99              
100 12 50       31 if (!$rfc822re) {
101 0         0 $rfc822re = make_rfc822re();
102             }
103             # * null list items are valid according to the RFC
104             # * the '1' business is to aid in distinguishing failure from no results
105              
106 12         15 my @r;
107 12 100       4632 if($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so) {
108 10         2538 while($s =~ m/(?:^|,$lwsp*)($rfc822re)/gos) {
109 15         130 push @r, $1;
110             }
111 10 100       53 return wantarray ? (scalar(@r), @r) : 1;
112             }
113             else {
114 2 100       10 return wantarray ? () : 0;
115             }
116             }
117              
118             1;
119             __END__