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-2022 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.03.
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   682 use vars '$VERSION';
  21         53  
  21         1200  
11             $VERSION = '3.012';
12              
13 21     21   128 use base 'Mail::Message::Field::Structured';
  21         37  
  21         7076  
14              
15 21     21   143 use strict;
  21         49  
  21         392  
16 21     21   124 use warnings;
  21         46  
  21         510  
17              
18 21     21   8943 use Mail::Message::Field::AddrGroup;
  21         66  
  21         562  
19 21     21   8491 use Mail::Message::Field::Address;
  21         56  
  21         628  
20 21     21   123 use List::Util 'first';
  21         36  
  21         30195  
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 13     13 0 29 { my ($self, $args) = @_;
37              
38 13         136 $self->{MMFF_groups} = [];
39              
40 13         33 ( my $def = lc $args->{name} ) =~ s/^resent\-//;
41 13   66     55 $self->{MMFF_defaults} = $accepted{$def} || $address_list;
42              
43 13         17 my ($body, @body);
44 13 100       35 if($body = $args->{body})
45 12 50       44 { @body = ref $body eq 'ARRAY' ? @$body : ($body);
46 12 50       32 return () unless @body;
47             }
48              
49 13 50 33     52 if(@body > 1 || ref $body[0])
50 0         0 { $self->addAddress($_) foreach @body;
51 0         0 delete $args->{body};
52             }
53              
54 13 50       47 $self->SUPER::init($args) or return;
55 13         75 $self;
56             }
57              
58             #------------------------------------------
59              
60              
61             sub addAddress(@)
62 22     22 1 30 { my $self = shift;
63 22 50 33     81 my $email = @_ && ref $_[0] ? shift : undef;
64 22         66 my %args = @_;
65 22   100     62 my $group = delete $args{group} || '';
66              
67 22 50       45 $email = Mail::Message::Field::Address->new(%args)
68             unless defined $email;
69              
70 22   66     43 my $set = $self->group($group) || $self->addGroup(name => $group);
71 22         108 $set->addAddress($email);
72 22         39 $email;
73             }
74              
75              
76             sub addGroup(@)
77 12     12 1 35 { my $self = shift;
78 12 50       71 my $group = @_ == 1 ? shift
79             : Mail::Message::Field::AddrGroup->new(@_);
80              
81 12         559 push @{$self->{MMFF_groups}}, $group;
  12         29  
82 12         36 $group;
83             }
84              
85              
86             sub group($)
87 25     25 1 43 { my ($self, $name) = @_;
88 25 50       43 $name = '' unless defined $name;
89 25     23   123 first { lc($_->name) eq lc($name) } $self->groups;
  23         73  
90             }
91              
92              
93 41     41 1 1463 sub groups() { @{shift->{MMFF_groups}} }
  41         189  
94              
95              
96 0     0 1 0 sub groupNames() { map {$_->name} shift->groups }
  0         0  
97              
98              
99 8     8 1 2011 sub addresses() { map {$_->addresses} shift->groups }
  6         19  
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 12     12 1 23 { my ($self, $string) = @_;
113 12         27 my ($group, $email) = ('', undef);
114 12         88 $string =~ s/\s+/ /gs;
115              
116 12         20 while(1)
117 46         115 { (my $comment, $string) = $self->consumeComment($string);
118              
119 46 100       161 if($string =~ s/^\s*\;//s ) { $group = ''; next } # end group
  3         5  
  3         6  
120 43 100       116 if($string =~ s/^\s*\,//s ) { next } # end address
  12         21  
121              
122 31         68 (my $email, $string) = $self->consumeAddress($string);
123 31 100       65 if(defined $email)
124             { # Pattern starts with e-mail address
125 5         16 ($comment, $string) = $self->consumeComment($string);
126 5 50       15 $email->comment($comment) if defined $comment;
127             }
128             else
129             { # Pattern not plain address
130 26         58 my $real_phrase = $string =~ m/^\s*\"/;
131 26         64 (my $phrase, $string) = $self->consumePhrase($string);
132              
133 26 100       53 if(defined $phrase)
134 22         52 { ($comment, $string) = $self->consumeComment($string);
135              
136 22 100       61 if($string =~ s/^\s*\://s )
137 3         5 { $group = $phrase;
138             # even empty groups must appear
139 3 50       7 $self->addGroup(name=>$group) unless $self->group($group);
140 3         11 next;
141             }
142             }
143              
144 23         37 my $angle;
145 23 100       130 if($string =~ s/^\s*\<([^>]*)\>//s) { $angle = $1 }
  19 50       44  
    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         4 { ($angle = $phrase) =~ s/\s+/./g;
153 1         2 undef $phrase;
154             }
155              
156 23         50 ($comment, $string) = $self->consumeComment($string);
157              
158             # remove obsoleted route info.
159 23 100       57 return 1 unless defined $angle;
160 20         33 $angle =~ s/^\@.*?\://;
161              
162 20         42 ($email, $angle) = $self->consumeAddress($angle
163             , phrase => $phrase, comment => $comment);
164             }
165              
166 25 100       82 $self->addAddress($email, group => $group) if defined $email;
167 25 100       202 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 10 { my @groups = sort {$a->name cmp $b->name} shift->groups;
  4         25  
178              
179 4 50       23 @groups or return '';
180 4 100       13 @groups > 1 or return $groups[0]->string;
181              
182 2 50 33     5 my $plain
183             = $groups[0]->name eq '' && $groups[0]->addresses
184             ? (shift @groups)->string.','
185             : '';
186              
187 2         6 join ' ', $plain, map({$_->string} @groups);
  3         7  
188             }
189              
190              
191             sub consumeAddress($@)
192 51     51 1 99 { my ($self, $string, @options) = @_;
193              
194 51         68 my ($local, $shorter, $loccomment);
195 51 100       160 if($string =~ s/^\s*"((?:\\.|[^"])*)"\s*\@/@/)
196             { # local part is quoted-string rfc2822
197 1         4 ($local, $shorter) = ($1, $string);
198 1         11 $local =~ s/\\"/"/g;
199             }
200             else
201 50         115 { ($local, $shorter, $loccomment) = $self->consumeDotAtom($string);
202 50 100       119 $local =~ s/\s//g if defined $local;
203             }
204              
205 51 100 100     228 return (undef, $string)
206             unless defined $local && $shorter =~ s/^\s*\@//;
207            
208 22         54 (my $domain, $shorter, my $domcomment) = $self->consumeDomain($shorter);
209 22 50       43 return (undef, $string) unless defined $domain;
210              
211             # loccomment and domcomment ignored
212 22         87 my $email = Mail::Message::Field::Address
213             ->new(username => $local, domain => $domain, @options);
214              
215 22         147 ($email, $shorter);
216             }
217              
218              
219             sub consumeDomain($)
220 22     22 1 41 { my ($self, $string) = @_;
221              
222 22 50       44 return ($self->stripCFWS($1), $string)
223             if $string =~ s/\s*(\[(?:[^[]\\]*|\\.)*\])//;
224              
225 22         45 my ($atom, $rest, $comment) = $self->consumeDotAtom($string);
226 22 50       53 $atom =~ s/\s//g if defined $atom;
227 22         58 ($atom, $rest, $comment);
228             }
229              
230             #------------------------------------------
231              
232              
233             1;