Filename | /usr/share/perl5/Mail/Address.pm |
Statements | Executed 9 statements in 1.32ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 13µs | 30µs | BEGIN@6 | Mail::Address::
1 | 1 | 1 | 7µs | 32µs | BEGIN@11 | Mail::Address::
1 | 1 | 1 | 6µs | 16µs | BEGIN@9 | Mail::Address::
0 | 0 | 0 | 0s | 0s | Version | Mail::Address::
0 | 0 | 0 | 0s | 0s | _complete | Mail::Address::
0 | 0 | 0 | 0s | 0s | _extract_name | Mail::Address::
0 | 0 | 0 | 0s | 0s | _find_next | Mail::Address::
0 | 0 | 0 | 0s | 0s | _tokenise | Mail::Address::
0 | 0 | 0 | 0s | 0s | address | Mail::Address::
0 | 0 | 0 | 0s | 0s | comment | Mail::Address::
0 | 0 | 0 | 0s | 0s | format | Mail::Address::
0 | 0 | 0 | 0s | 0s | host | Mail::Address::
0 | 0 | 0 | 0s | 0s | name | Mail::Address::
0 | 0 | 0 | 0s | 0s | new | Mail::Address::
0 | 0 | 0 | 0s | 0s | parse | Mail::Address::
0 | 0 | 0 | 0s | 0s | phrase | Mail::Address::
0 | 0 | 0 | 0s | 0s | set_or_get | Mail::Address::
0 | 0 | 0 | 0s | 0s | user | Mail::Address::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # Copyrights 1995-2014 by [Mark Overmeer <perl@overmeer.net>]. | ||||
2 | # For other contributors see ChangeLog. | ||||
3 | # See the manual pages for details on the licensing terms. | ||||
4 | # Pod stripped from pm file by OODoc 2.01. | ||||
5 | package Mail::Address; | ||||
6 | 2 | 32µs | 2 | 47µs | # spent 30µs (13+17) within Mail::Address::BEGIN@6 which was called:
# once (13µs+17µs) by C4::Letters::BEGIN@23 at line 6 # spent 30µs making 1 call to Mail::Address::BEGIN@6
# spent 17µs making 1 call to vars::import |
7 | 1 | 400ns | $VERSION = '2.13'; | ||
8 | |||||
9 | 2 | 22µs | 2 | 26µs | # spent 16µs (6+10) within Mail::Address::BEGIN@9 which was called:
# once (6µs+10µs) by C4::Letters::BEGIN@23 at line 9 # spent 16µs making 1 call to Mail::Address::BEGIN@9
# spent 10µs making 1 call to strict::import |
10 | |||||
11 | 2 | 1.26ms | 2 | 58µs | # spent 32µs (7+26) within Mail::Address::BEGIN@11 which was called:
# once (7µs+26µs) by C4::Letters::BEGIN@23 at line 11 # spent 32µs making 1 call to Mail::Address::BEGIN@11
# spent 26µs making 1 call to Exporter::import |
12 | |||||
13 | # use locale; removed in version 1.78, because it causes taint problems | ||||
14 | |||||
15 | sub Version { our $VERSION } | ||||
16 | |||||
- - | |||||
19 | # given a comment, attempt to extract a person's name | ||||
20 | sub _extract_name | ||||
21 | { # This function can be called as method as well | ||||
22 | my $self = @_ && ref $_[0] ? shift : undef; | ||||
23 | |||||
24 | local $_ = shift | ||||
25 | or return ''; | ||||
26 | |||||
27 | # Using encodings, too hard. See Mail::Message::Field::Full. | ||||
28 | return '' if m/\=\?.*?\?\=/; | ||||
29 | |||||
30 | # trim whitespace | ||||
31 | s/^\s+//; | ||||
32 | s/\s+$//; | ||||
33 | s/\s+/ /; | ||||
34 | |||||
35 | # Disregard numeric names (e.g. 123456.1234@compuserve.com) | ||||
36 | return "" if /^[\d ]+$/; | ||||
37 | |||||
38 | s/^\((.*)\)$/$1/; # remove outermost parenthesis | ||||
39 | s/^"(.*)"$/$1/; # remove outer quotation marks | ||||
40 | s/\(.*?\)//g; # remove minimal embedded comments | ||||
41 | s/\\//g; # remove all escapes | ||||
42 | s/^"(.*)"$/$1/; # remove internal quotation marks | ||||
43 | s/^([^\s]+) ?, ?(.*)$/$2 $1/; # reverse "Last, First M." if applicable | ||||
44 | s/,.*//; | ||||
45 | |||||
46 | # Change casing only when the name contains only upper or only | ||||
47 | # lower cased characters. | ||||
48 | unless( m/[A-Z]/ && m/[a-z]/ ) | ||||
49 | { # Set the case of the name to first char upper rest lower | ||||
50 | s/\b(\w+)/\L\u$1/igo; # Upcase first letter on name | ||||
51 | s/\bMc(\w)/Mc\u$1/igo; # Scottish names such as 'McLeod' | ||||
52 | s/\bo'(\w)/O'\u$1/igo; # Irish names such as 'O'Malley, O'Reilly' | ||||
53 | s/\b(x*(ix)?v*(iv)?i*)\b/\U$1/igo; # Roman numerals, eg 'Level III Support' | ||||
54 | } | ||||
55 | |||||
56 | # some cleanup | ||||
57 | s/\[[^\]]*\]//g; | ||||
58 | s/(^[\s'"]+|[\s'"]+$)//g; | ||||
59 | s/\s{2,}/ /g; | ||||
60 | |||||
61 | $_; | ||||
62 | } | ||||
63 | |||||
64 | sub _tokenise | ||||
65 | { local $_ = join ',', @_; | ||||
66 | my (@words,$snippet,$field); | ||||
67 | |||||
68 | s/\A\s+//; | ||||
69 | s/[\r\n]+/ /g; | ||||
70 | |||||
71 | while ($_ ne '') | ||||
72 | { $field = ''; | ||||
73 | if(s/^\s*\(/(/ ) # (...) | ||||
74 | { my $depth = 0; | ||||
75 | |||||
76 | PAREN: while(s/^(\(([^\(\)\\]|\\.)*)//) | ||||
77 | { $field .= $1; | ||||
78 | $depth++; | ||||
79 | while(s/^(([^\(\)\\]|\\.)*\)\s*)//) | ||||
80 | { $field .= $1; | ||||
81 | last PAREN unless --$depth; | ||||
82 | $field .= $1 if s/^(([^\(\)\\]|\\.)+)//; | ||||
83 | } | ||||
84 | } | ||||
85 | |||||
86 | carp "Unmatched () '$field' '$_'" | ||||
87 | if $depth; | ||||
88 | |||||
89 | $field =~ s/\s+\Z//; | ||||
90 | push @words, $field; | ||||
91 | |||||
92 | next; | ||||
93 | } | ||||
94 | |||||
95 | if( s/^("(?:[^"\\]+|\\.)*")\s*// # "..." | ||||
96 | || s/^(\[(?:[^\]\\]+|\\.)*\])\s*// # [...] | ||||
97 | || s/^([^\s()<>\@,;:\\".[\]]+)\s*// | ||||
98 | || s/^([()<>\@,;:\\".[\]])\s*// | ||||
99 | ) | ||||
100 | { push @words, $1; | ||||
101 | next; | ||||
102 | } | ||||
103 | |||||
104 | croak "Unrecognised line: $_"; | ||||
105 | } | ||||
106 | |||||
107 | push @words, ","; | ||||
108 | \@words; | ||||
109 | } | ||||
110 | |||||
111 | sub _find_next | ||||
112 | { my ($idx, $tokens, $len) = @_; | ||||
113 | |||||
114 | while($idx < $len) | ||||
115 | { my $c = $tokens->[$idx]; | ||||
116 | return $c if $c eq ',' || $c eq ';' || $c eq '<'; | ||||
117 | $idx++; | ||||
118 | } | ||||
119 | |||||
120 | ""; | ||||
121 | } | ||||
122 | |||||
123 | sub _complete | ||||
124 | { my ($class, $phrase, $address, $comment) = @_; | ||||
125 | |||||
126 | @$phrase || @$comment || @$address | ||||
127 | or return undef; | ||||
128 | |||||
129 | my $o = $class->new(join(" ",@$phrase), join("",@$address), join(" ",@$comment)); | ||||
130 | @$phrase = @$address = @$comment = (); | ||||
131 | $o; | ||||
132 | } | ||||
133 | |||||
134 | |||||
135 | sub new(@) | ||||
136 | { my $class = shift; | ||||
137 | bless [@_], $class; | ||||
138 | } | ||||
139 | |||||
140 | |||||
141 | sub parse(@) | ||||
142 | { my $class = shift; | ||||
143 | my @line = grep {defined} @_; | ||||
144 | my $line = join '', @line; | ||||
145 | |||||
146 | my (@phrase, @comment, @address, @objs); | ||||
147 | my ($depth, $idx) = (0, 0); | ||||
148 | |||||
149 | my $tokens = _tokenise @line; | ||||
150 | my $len = @$tokens; | ||||
151 | my $next = _find_next $idx, $tokens, $len; | ||||
152 | |||||
153 | local $_; | ||||
154 | for(my $idx = 0; $idx < $len; $idx++) | ||||
155 | { $_ = $tokens->[$idx]; | ||||
156 | |||||
157 | if(substr($_,0,1) eq '(') { push @comment, $_ } | ||||
158 | elsif($_ eq '<') { $depth++ } | ||||
159 | elsif($_ eq '>') { $depth-- if $depth } | ||||
160 | elsif($_ eq ',' || $_ eq ';') | ||||
161 | { warn "Unmatched '<>' in $line" if $depth; | ||||
162 | my $o = $class->_complete(\@phrase, \@address, \@comment); | ||||
163 | push @objs, $o if defined $o; | ||||
164 | $depth = 0; | ||||
165 | $next = _find_next $idx+1, $tokens, $len; | ||||
166 | } | ||||
167 | elsif($depth) { push @address, $_ } | ||||
168 | elsif($next eq '<') { push @phrase, $_ } | ||||
169 | elsif( /^[.\@:;]$/ || !@address || $address[-1] =~ /^[.\@:;]$/ ) | ||||
170 | { push @address, $_ } | ||||
171 | else | ||||
172 | { warn "Unmatched '<>' in $line" if $depth; | ||||
173 | my $o = $class->_complete(\@phrase, \@address, \@comment); | ||||
174 | push @objs, $o if defined $o; | ||||
175 | $depth = 0; | ||||
176 | push @address, $_; | ||||
177 | } | ||||
178 | } | ||||
179 | @objs; | ||||
180 | } | ||||
181 | |||||
182 | |||||
183 | sub phrase { shift->set_or_get(0, @_) } | ||||
184 | sub address { shift->set_or_get(1, @_) } | ||||
185 | sub comment { shift->set_or_get(2, @_) } | ||||
186 | |||||
187 | sub set_or_get($) | ||||
188 | { my ($self, $i) = (shift, shift); | ||||
189 | @_ or return $self->[$i]; | ||||
190 | |||||
191 | my $val = $self->[$i]; | ||||
192 | $self->[$i] = shift if @_; | ||||
193 | $val; | ||||
194 | } | ||||
195 | |||||
196 | |||||
197 | 1 | 200ns | my $atext = '[\-\w !#$%&\'*+/=?^`{|}~]'; | ||
198 | sub format | ||||
199 | { my @addrs; | ||||
200 | |||||
201 | foreach (@_) | ||||
202 | { my ($phrase, $email, $comment) = @$_; | ||||
203 | my @addr; | ||||
204 | |||||
205 | if(defined $phrase && length $phrase) | ||||
206 | { push @addr | ||||
207 | , $phrase =~ /^(?:\s*$atext\s*)+$/o ? $phrase | ||||
208 | : $phrase =~ /(?<!\\)"/ ? $phrase | ||||
209 | : qq("$phrase"); | ||||
210 | |||||
211 | push @addr, "<$email>" | ||||
212 | if defined $email && length $email; | ||||
213 | } | ||||
214 | elsif(defined $email && length $email) | ||||
215 | { push @addr, $email; | ||||
216 | } | ||||
217 | |||||
218 | if(defined $comment && $comment =~ /\S/) | ||||
219 | { $comment =~ s/^\s*\(?/(/; | ||||
220 | $comment =~ s/\)?\s*$/)/; | ||||
221 | } | ||||
222 | |||||
223 | push @addr, $comment | ||||
224 | if defined $comment && length $comment; | ||||
225 | |||||
226 | push @addrs, join(" ", @addr) | ||||
227 | if @addr; | ||||
228 | } | ||||
229 | |||||
230 | join ", ", @addrs; | ||||
231 | } | ||||
232 | |||||
233 | |||||
234 | sub name | ||||
235 | { my $self = shift; | ||||
236 | my $phrase = $self->phrase; | ||||
237 | my $addr = $self->address; | ||||
238 | |||||
239 | $phrase = $self->comment | ||||
240 | unless defined $phrase && length $phrase; | ||||
241 | |||||
242 | my $name = $self->_extract_name($phrase); | ||||
243 | |||||
244 | # first.last@domain address | ||||
245 | if($name eq '' && $addr =~ /([^\%\.\@_]+([\._][^\%\.\@_]+)+)[\@\%]/) | ||||
246 | { ($name = $1) =~ s/[\._]+/ /g; | ||||
247 | $name = _extract_name $name; | ||||
248 | } | ||||
249 | |||||
250 | if($name eq '' && $addr =~ m#/g=#i) # X400 style address | ||||
251 | { my ($f) = $addr =~ m#g=([^/]*)#i; | ||||
252 | my ($l) = $addr =~ m#s=([^/]*)#i; | ||||
253 | $name = _extract_name "$f $l"; | ||||
254 | } | ||||
255 | |||||
256 | length $name ? $name : undef; | ||||
257 | } | ||||
258 | |||||
259 | |||||
260 | sub host | ||||
261 | { my $addr = shift->address || ''; | ||||
262 | my $i = rindex $addr, '@'; | ||||
263 | $i >= 0 ? substr($addr, $i+1) : undef; | ||||
264 | } | ||||
265 | |||||
266 | |||||
267 | sub user | ||||
268 | { my $addr = shift->address || ''; | ||||
269 | my $i = rindex $addr, '@'; | ||||
270 | $i >= 0 ? substr($addr,0,$i) : $addr; | ||||
271 | } | ||||
272 | |||||
273 | 1 | 2µs | 1; |