File Coverage

blib/lib/Mail/Message/Field/Addresses.pm
Criterion Covered Total %
statement 110 121 90.9
branch 46 64 71.8
condition 12 20 60.0
subroutine 18 20 90.0
pod 11 12 91.6
total 197 237 83.1


line stmt bran cond sub pod time code
1             # Copyrights 2001-2021 by [Mark Overmeer ].
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.02.
5             # This code is part of distribution Mail-Message. Meta-POD processed with
6             # OODoc into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package Mail::Message::Field::Addresses;
10 21     21   1057 use vars '$VERSION';
  21         52  
  21         1404  
11             $VERSION = '3.011';
12              
13 21     21   134 use base 'Mail::Message::Field::Structured';
  21         51  
  21         9167  
14              
15 21     21   166 use strict;
  21         48  
  21         497  
16 21     21   150 use warnings;
  21         65  
  21         779  
17              
18 21     21   11586 use Mail::Message::Field::AddrGroup;
  21         75  
  21         757  
19 21     21   11060 use Mail::Message::Field::Address;
  21         60  
  21         679  
20 21     21   145 use List::Util 'first';
  21         66  
  21         37305  
21              
22              
23             #------------------------------------------
24             # what is permitted for each field.
25              
26             my $address_list = {groups => 1, multi => 1};
27             my $mailbox_list = {multi => 1};
28             my $mailbox = {};
29              
30             my %accepted = # defaults to $address_list
31             ( from => $mailbox_list
32             , sender => $mailbox
33             );
34              
35             sub init($)
36 12     12 0 33 { my ($self, $args) = @_;
37              
38 12         161 $self->{MMFF_groups} = [];
39              
40 12         50 ( my $def = lc $args->{name} ) =~ s/^resent\-//;
41 12   66     72 $self->{MMFF_defaults} = $accepted{$def} || $address_list;
42              
43 12         43 my ($body, @body);
44 12 100       52 if($body = $args->{body})
45 11 50       47 { @body = ref $body eq 'ARRAY' ? @$body : ($body);
46 11 50       49 return () unless @body;
47             }
48              
49 12 50 33     71 if(@body > 1 || ref $body[0])
50 0         0 { $self->addAddress($_) foreach @body;
51 0         0 delete $args->{body};
52             }
53              
54 12 50       60 $self->SUPER::init($args) or return;
55 12         132 $self;
56             }
57              
58             #------------------------------------------
59              
60              
61             sub addAddress(@)
62 21     21 1 39 { my $self = shift;
63 21 50 33     98 my $email = @_ && ref $_[0] ? shift : undef;
64 21         62 my %args = @_;
65 21   100     81 my $group = delete $args{group} || '';
66              
67 21 50       45 $email = Mail::Message::Field::Address->new(%args)
68             unless defined $email;
69              
70 21   66     63 my $set = $self->group($group) || $self->addGroup(name => $group);
71 21         150 $set->addAddress($email);
72 21         43 $email;
73             }
74              
75              
76             sub addGroup(@)
77 11     11 1 57 { my $self = shift;
78 11 50       91 my $group = @_ == 1 ? shift
79             : Mail::Message::Field::AddrGroup->new(@_);
80              
81 11         691 push @{$self->{MMFF_groups}}, $group;
  11         36  
82 11         61 $group;
83             }
84              
85              
86             sub group($)
87 24     24 1 49 { my ($self, $name) = @_;
88 24 50       55 $name = '' unless defined $name;
89 24     23   191 first { lc($_->name) eq lc($name) } $self->groups;
  23         92  
90             }
91              
92              
93 39     39 1 2183 sub groups() { @{shift->{MMFF_groups}} }
  39         259  
94              
95              
96 0     0 1 0 sub groupNames() { map {$_->name} shift->groups }
  0         0  
97              
98              
99 7     7 1 2457 sub addresses() { map {$_->addresses} shift->groups }
  5         21  
100              
101              
102             sub addAttribute($;@)
103 0     0 1 0 { my $self = shift;
104 0         0 $self->log(ERROR => 'No attributes for address fields.');
105 0         0 $self;
106             }
107              
108             #------------------------------------------
109              
110              
111             sub parse($)
112 11     11 1 32 { my ($self, $string) = @_;
113 11         33 my ($group, $email) = ('', undef);
114 11         116 $string =~ s/\s+/ /gs;
115              
116 11         25 while(1)
117 45         148 { (my $comment, $string) = $self->consumeComment($string);
118              
119 45 100       159 if($string =~ s/^\s*\;//s ) { $group = ''; next } # end group
  3         8  
  3         7  
120 42 100       143 if($string =~ s/^\s*\,//s ) { next } # end address
  12         29  
121              
122 30         85 (my $email, $string) = $self->consumeAddress($string);
123 30 100       74 if(defined $email)
124             { # Pattern starts with e-mail address
125 5         17 ($comment, $string) = $self->consumeComment($string);
126 5 50       20 $email->comment($comment) if defined $comment;
127             }
128             else
129             { # Pattern not plain address
130 25         83 my $real_phrase = $string =~ m/^\s*\"/;
131 25         87 (my $phrase, $string) = $self->consumePhrase($string);
132              
133 25 100       70 if(defined $phrase)
134 21         80 { ($comment, $string) = $self->consumeComment($string);
135              
136 21 100       83 if($string =~ s/^\s*\://s )
137 3         9 { $group = $phrase;
138             # even empty groups must appear
139 3 50       9 $self->addGroup(name=>$group) unless $self->group($group);
140 3         14 next;
141             }
142             }
143              
144 22         35 my $angle;
145 22 100       138 if($string =~ s/^\s*\<([^>]*)\>//s) { $angle = $1 }
  18 50       55  
    100          
146             elsif($real_phrase)
147 0 0       0 { $self->log(ERROR => "Ignore unrelated phrase `$1'")
148             if $string =~ s/^\s*\"(.*?)\r?\n//;
149 0         0 next;
150             }
151             elsif(defined $phrase)
152 1         5 { ($angle = $phrase) =~ s/\s+/./g;
153 1         3 undef $phrase;
154             }
155              
156 22         71 ($comment, $string) = $self->consumeComment($string);
157              
158             # remove obsoleted route info.
159 22 100       73 return 1 unless defined $angle;
160 19         48 $angle =~ s/^\@.*?\://;
161              
162 19         51 ($email, $angle) = $self->consumeAddress($angle
163             , phrase => $phrase, comment => $comment);
164             }
165              
166 24 100       119 $self->addAddress($email, group => $group) if defined $email;
167 24 100       252 return 1 if $string =~ m/^\s*$/s;
168             }
169              
170 0         0 $self->log(WARNING => 'Illegal part in address field '.$self->Name.
171             ": $string\n");
172              
173 0         0 0;
174             }
175              
176             sub produceBody()
177 4     4 1 22 { my @groups = sort {$a->name cmp $b->name} shift->groups;
  4         31  
178              
179 4 50       37 @groups or return '';
180 4 100       28 @groups > 1 or return $groups[0]->string;
181              
182 2 50 33     9 my $plain
183             = $groups[0]->name eq '' && $groups[0]->addresses
184             ? (shift @groups)->string.','
185             : '';
186              
187 2         9 join ' ', $plain, map({$_->string} @groups);
  3         12  
188             }
189              
190              
191             sub consumeAddress($@)
192 49     49 1 123 { my ($self, $string, @options) = @_;
193              
194 49         75 my ($local, $shorter, $loccomment);
195 49 100       259 if($string =~ s/^\s*"((?:\\.|[^"])*)"\s*\@/@/)
196             { # local part is quoted-string rfc2822
197 1         8 ($local, $shorter) = ($1, $string);
198 1         6 $local =~ s/\\"/"/g;
199             }
200             else
201 48         159 { ($local, $shorter, $loccomment) = $self->consumeDotAtom($string);
202 48 100       160 $local =~ s/\s//g if defined $local;
203             }
204              
205 49 100 100     309 return (undef, $string)
206             unless defined $local && $shorter =~ s/^\s*\@//;
207            
208 21         86 (my $domain, $shorter, my $domcomment) = $self->consumeDomain($shorter);
209 21 50       56 return (undef, $string) unless defined $domain;
210              
211             # loccomment and domcomment ignored
212 21         121 my $email = Mail::Message::Field::Address
213             ->new(username => $local, domain => $domain, @options);
214              
215 21         188 ($email, $shorter);
216             }
217              
218              
219             sub consumeDomain($)
220 21     21 1 48 { my ($self, $string) = @_;
221              
222 21 50       59 return ($self->stripCFWS($1), $string)
223             if $string =~ s/\s*(\[(?:[^[]\\]*|\\.)*\])//;
224              
225 21         61 my ($atom, $rest, $comment) = $self->consumeDotAtom($string);
226 21 50       77 $atom =~ s/\s//g if defined $atom;
227 21         64 ($atom, $rest, $comment);
228             }
229              
230             #------------------------------------------
231              
232              
233             1;