File Coverage

inc/Email/Address.pm
Criterion Covered Total %
statement 73 112 65.1
branch 19 42 45.2
condition 5 12 41.6
subroutine 15 20 75.0
pod 9 10 90.0
total 121 196 61.7


line stmt bran cond sub pod time code
1             #line 1
2 11     11   51873 package Email::Address;
  11         23  
  11         564  
3             use strict;
4             ## no critic RequireUseWarnings
5             # support pre-5.6
6 11         17968  
7             use vars qw[$VERSION $COMMENT_NEST_LEVEL $STRINGIFY
8             $COLLAPSE_SPACES
9 11     11   58 %PARSE_CACHE %FORMAT_CACHE %NAME_CACHE
  11         17  
10             $addr_spec $angle_addr $name_addr $mailbox];
11              
12             my $NOCACHE;
13              
14             $VERSION = '1.892';
15             $COMMENT_NEST_LEVEL ||= 2;
16             $STRINGIFY ||= 'format';
17             $COLLAPSE_SPACES = 1 unless defined $COLLAPSE_SPACES; # who wants //=? me!
18              
19             #line 42
20              
21             my $CTL = q{\x00-\x1F\x7F};
22             my $special = q{()<>\\[\\]:;@\\\\,."};
23              
24             my $text = qr/[^\x0A\x0D]/;
25              
26             my $quoted_pair = qr/\\$text/;
27              
28             my $ctext = qr/(?>[^()\\]+)/;
29             my ($ccontent, $comment) = (q{})x2;
30             for (1 .. $COMMENT_NEST_LEVEL) {
31             $ccontent = qr/$ctext|$quoted_pair|$comment/;
32             $comment = qr/\s*\((?:\s*$ccontent)*\s*\)\s*/;
33             }
34             my $cfws = qr/$comment|\s+/;
35              
36             my $atext = qq/[^$CTL$special\\s]/;
37             my $atom = qr/$cfws*$atext+$cfws*/;
38             my $dot_atom_text = qr/$atext+(?:\.$atext+)*/;
39             my $dot_atom = qr/$cfws*$dot_atom_text$cfws*/;
40              
41             my $qtext = qr/[^\\"]/;
42             my $qcontent = qr/$qtext|$quoted_pair/;
43             my $quoted_string = qr/$cfws*"$qcontent+"$cfws*/;
44              
45             my $word = qr/$atom|$quoted_string/;
46              
47             # XXX: This ($phrase) used to just be: my $phrase = qr/$word+/; It was changed
48             # to resolve bug 22991, creating a significant slowdown. Given current speed
49             # problems. Once 16320 is resolved, this section should be dealt with.
50             # -- rjbs, 2006-11-11
51             #my $obs_phrase = qr/$word(?:$word|\.|$cfws)*/;
52              
53             # XXX: ...and the above solution caused endless problems (never returned) when
54             # examining this address, now in a test:
55             # admin+=E6=96=B0=E5=8A=A0=E5=9D=A1_Weblog-- ATAT --test.socialtext.com
56             # So we disallow the hateful CFWS in this context for now. Of modern mail
57             # agents, only Apple Web Mail 2.0 is known to produce obs-phrase.
58             # -- rjbs, 2006-11-19
59             my $simple_word = qr/$atom|\.|\s*"$qcontent+"\s*/;
60             my $obs_phrase = qr/$simple_word+/;
61              
62             my $phrase = qr/$obs_phrase|(?:$word+)/;
63              
64             my $local_part = qr/$dot_atom|$quoted_string/;
65             my $dtext = qr/[^\[\]\\]/;
66             my $dcontent = qr/$dtext|$quoted_pair/;
67             my $domain_literal = qr/$cfws*\[(?:\s*$dcontent)*\s*\]$cfws*/;
68             my $domain = qr/$dot_atom|$domain_literal/;
69              
70             my $display_name = $phrase;
71              
72             #line 133
73              
74             $addr_spec = qr/$local_part\@$domain/;
75             $angle_addr = qr/$cfws*<$addr_spec>$cfws*/;
76             $name_addr = qr/$display_name?$angle_addr/;
77             $mailbox = qr/(?:$name_addr|$addr_spec)$comment*/;
78              
79             sub _PHRASE () { 0 }
80             sub _ADDRESS () { 1 }
81             sub _COMMENT () { 2 }
82             sub _ORIGINAL () { 3 }
83             sub _IN_CACHE () { 4 }
84              
85             #line 176
86              
87             sub __get_cached_parse {
88             return if $NOCACHE;
89              
90             my ($class, $line) = @_;
91              
92             return @{$PARSE_CACHE{$line}} if exists $PARSE_CACHE{$line};
93             return;
94             }
95              
96             sub __cache_parse {
97             return if $NOCACHE;
98            
99             my ($class, $line, $addrs) = @_;
100              
101             $PARSE_CACHE{$line} = $addrs;
102             }
103              
104             sub parse {
105             my ($class, $line) = @_;
106             return unless $line;
107              
108             $line =~ s/[ \t]+/ /g if $COLLAPSE_SPACES;
109              
110             if (my @cached = $class->__get_cached_parse($line)) {
111             return @cached;
112             }
113              
114             my (@mailboxes) = ($line =~ /$mailbox/go);
115             my @addrs;
116             foreach (@mailboxes) {
117             my $original = $_;
118              
119             my @comments = /($comment)/go;
120             s/$comment//go if @comments;
121              
122             my ($user, $host, $com);
123             ($user, $host) = ($1, $2) if s/<($local_part)\@($domain)>//o;
124             if (! defined($user) || ! defined($host)) {
125             s/($local_part)\@($domain)//o;
126             ($user, $host) = ($1, $2);
127             }
128              
129             my ($phrase) = /($display_name)/o;
130              
131             for ( $phrase, $host, $user, @comments ) {
132             next unless defined $_;
133             s/^\s+//;
134             s/\s+$//;
135             $_ = undef unless length $_;
136             }
137              
138             my $new_comment = join q{ }, @comments;
139             push @addrs,
140             $class->new($phrase, "$user\@$host", $new_comment, $original);
141             $addrs[-1]->[_IN_CACHE] = [ \$line, $#addrs ]
142             }
143              
144             $class->__cache_parse($line, \@addrs);
145             return @addrs;
146             }
147              
148             #line 252
149              
150             sub new {
151             my ($class, $phrase, $email, $comment, $orig) = @_;
152             $phrase =~ s/\A"(.+)"\z/$1/ if $phrase;
153              
154             bless [ $phrase, $email, $comment, $orig ] => $class;
155             }
156              
157             #line 274
158              
159             sub purge_cache {
160             %NAME_CACHE = ();
161             %FORMAT_CACHE = ();
162             %PARSE_CACHE = ();
163             }
164              
165             #line 290
166              
167             sub disable_cache {
168             my ($class) = @_;
169             $class->purge_cache;
170             $NOCACHE = 1;
171             }
172              
173             sub enable_cache {
174             $NOCACHE = undef;
175             }
176              
177             #line 350
178 3 50   3   11  
179             BEGIN {
180 3         5 my %_INDEX = (
181             phrase => _PHRASE,
182 3 50       11 address => _ADDRESS,
  0         0  
183 3         11 comment => _COMMENT,
184             original => _ORIGINAL,
185             );
186              
187 3 50   3   10 for my $method (keys %_INDEX) {
188             no strict 'refs';
189 3         8 my $index = $_INDEX{ $method };
190             *$method = sub {
191 3         8 if ($_[1]) {
192             if ($_[0][_IN_CACHE]) {
193             my $replicant = bless [ @{$_[0]} ] => ref $_[0];
194             $PARSE_CACHE{ ${ $_[0][_IN_CACHE][0] } }[ $_[0][_IN_CACHE][1] ]
195 3     3 1 22 = $replicant;
196 3 50       10 $_[0][_IN_CACHE] = undef;
197             }
198 3 50       14 $_[0]->[ $index ] = $_[1];
199             } else {
200 3 50       15 $_[0]->[ $index ];
201 0         0 }
202             };
203             }
204 3         872 }
205 3         7  
206 3         9 sub host { ($_[0]->[_ADDRESS] =~ /\@($domain)/o)[0] }
207 0         0 sub user { ($_[0]->[_ADDRESS] =~ /($local_part)\@/o)[0] }
208              
209 0         0 #line 391
210 0 0       0  
211             sub format {
212 0         0 local $^W = 0; ## no critic
213 0 0       0 return $FORMAT_CACHE{"@{$_[0]}"} if exists $FORMAT_CACHE{"@{$_[0]}"};
214 0 0 0     0 $FORMAT_CACHE{"@{$_[0]}"} = $_[0]->_format;
215 0         0 }
216 0         0  
217             sub _format {
218             my ($self) = @_;
219 0         0  
220             unless (
221 0         0 defined $self->[_PHRASE] && length $self->[_PHRASE]
222 0 0       0 ||
223 0         0 defined $self->[_COMMENT] && length $self->[_COMMENT]
224 0         0 ) {
225 0 0       0 return $self->[_ADDRESS];
226             }
227              
228 0         0 my $format = sprintf q{%s <%s> %s},
229 0         0 $self->_enquoted_phrase, $self->[_ADDRESS], $self->[_COMMENT];
230              
231 0         0 $format =~ s/^\s+//;
232             $format =~ s/\s+$//;
233              
234 3         11 return $format;
235 3         11 }
236              
237             sub _enquoted_phrase {
238             my ($self) = @_;
239              
240             my $phrase = $self->[_PHRASE];
241              
242             # if it's encoded -- rjbs, 2007-02-28
243             return $phrase if $phrase =~ /\A=\?.+\?=\z/;
244              
245             $phrase =~ s/\A"(.+)"\z/$1/;
246             $phrase =~ s/\"/\\"/g;
247              
248             return qq{"$phrase"};
249             }
250              
251             #line 448
252              
253             sub name {
254 226     226 1 30451 local $^W = 0;
255 226 100       1122 return $NAME_CACHE{"@{$_[0]}"} if exists $NAME_CACHE{"@{$_[0]}"};
256             my ($self) = @_;
257 226         1286 my $name = q{};
258             if ( $name = $self->[_PHRASE] ) {
259             $name =~ s/^"//;
260             $name =~ s/"$//;
261             $name =~ s/($quoted_pair)/substr $1, -1/goe;
262             } elsif ( $name = $self->[_COMMENT] ) {
263             $name =~ s/^\(//;
264             $name =~ s/\)$//;
265             $name =~ s/($quoted_pair)/substr $1, -1/goe;
266             $name =~ s/$comment/ /go;
267             } else {
268             ($name) = $self->[_ADDRESS] =~ /($local_part)\@/o;
269             }
270             $NAME_CACHE{"@{$_[0]}"} = $name;
271             }
272              
273             #line 496
274              
275             sub as_string {
276 2     2 1 6 warn 'altering $Email::Address::STRINGIFY is deprecated; subclass instead'
277 2         5 if $STRINGIFY ne 'format';
278 2         6  
279             $_[0]->can($STRINGIFY)->($_[0]);
280             }
281              
282             use overload '""' => 'as_string';
283              
284             #line 511
285              
286             1;
287              
288             __END__