/[suikacvs]/messaging/manakai/lib/Message/Field/Addresses.pm
Suika

Contents of /messaging/manakai/lib/Message/Field/Addresses.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations) (download)
Sun Jun 9 11:08:27 2002 UTC (22 years, 5 months ago) by wakaba
Branch: MAIN
CVS Tags: before-dis2-200411, manakai-release-0-3-2, manakai-release-0-3-1, manakai-release-0-4-0, manakai-200612, msg-0-1, HEAD
Branch point for: branch-suikawiki-1, experimental-xml-parser-200401, stable
Changes since 1.3: +9 -4 lines
2002-06-09  wakaba <w@suika.fam.cx>

	* Addresses.pm (_delete_match): 'addr-spec': new 'by' option.
	* ContentType.pm:
	- (_save_param): Call _parse_param_value if parse_all.
	- (_parse_value): New function.  Check Message::MIME::MediaType.
	* CSV.pm (use_comment): New option.
	* Date.pm:
	- (zone): New method.
	- (set_datetime): Likewise.
	* Mailbox.pm (display_name): New method.
	* Numval.pm (use_comment): New option.
	* Param.pm (_parse_param_value): New function.
	* Structured.pm:
	- (_add_return_value, _replace_return_value): New functions.
	- (_parse_value): Sync with Message::Entity's.
	- (option): Sync with Message::Entity's.
	- (option): '-recursive': new option.
	- (_option_recursive): New function.

1 wakaba 1.1
2     =head1 NAME
3    
4 wakaba 1.2 Message::Field::Addresses --- Perl module for comma separated
5     Internet mail address list
6 wakaba 1.1
7     =cut
8    
9     package Message::Field::Addresses;
10     require 5.6.0;
11     use strict;
12     use re 'eval';
13 wakaba 1.2 use vars qw(%DEFAULT @ISA %REG $VERSION);
14 wakaba 1.4 $VERSION=do{my @r=(q$Revision: 1.3 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
15 wakaba 1.1 require Message::Field::CSV;
16     push @ISA, qw(Message::Field::CSV);
17 wakaba 1.2 %REG = %Message::Field::CSV::REG;
18 wakaba 1.1 $REG{SC_angle_addr} = qr/<(?:$REG{quoted_string}|$REG{domain_literal}|$REG{comment}|[^\x22\x28\x5B\x3E])+>|<>/;
19 wakaba 1.3 $REG{SC_group} = qr/:(?:$REG{comment}|$REG{quoted_string}|(??{$REG{SC_group}})|$REG{domain_literal}|$REG{SC_angle_addr}|[^\x22\x28\x5B\x3A\x3E\x3B])*;/;
20 wakaba 1.1
21     =head1 CONSTRUCTORS
22    
23     The following methods construct new objects:
24    
25     =over 4
26    
27     =cut
28    
29     ## Initialize of this class -- called by constructors
30 wakaba 1.2 %DEFAULT = (
31     -_METHODS => [qw|add count delete item display_name is_group value_type scan
32     comment_add comment_count comment_delete comment_item|],
33     -_MEMBERS => [qw|group_name group_name_comment|],
34 wakaba 1.1 -by => 'display-name', ## Default key for item, delete,...
35     -can_have_group => 1,
36     #encoding_after_encode
37     #encoding_before_decode
38     #field_name
39     #field_param_name
40     #format
41     #hook_encode_string
42     #hook_decode_string
43     -is_group => 0,
44 wakaba 1.2 #max
45 wakaba 1.1 -output_comment => 1,
46     -output_group_name_comment => 1,
47     #parse_all
48     -remove_comment => 0, ## This option works for PARENT class
49     #value_type
50     );
51 wakaba 1.2 sub _init ($;%) {
52     my $self = shift;
53     my %options = @_;
54     my $DEFAULT = Message::Util::make_clone (\%DEFAULT);
55     $self->SUPER::_init (%$DEFAULT, %options);
56     my (%mailbox, %group);
57 wakaba 1.1
58 wakaba 1.2 $self->{option}->{can_have_group} = 0
59     if $self->{option}->{field_param_name} eq 'group';
60    
61     my $field = $self->{option}->{field_name};
62     my $format = $self->{option}->{format};
63     ## rfc1036 = RFC 1036 + son-of-RFC1036
64     if ($field eq 'from' || $field eq 'resent-from') {
65     $self->{option}->{can_have_group} = 0;
66     $self->{option}->{max} = 1 if $format =~ /rfc1036|http/;
67     } elsif ($field eq 'mail-copies-to') {
68     $mailbox{-use_keyword} = 1;
69     } elsif ($field eq 'reply-to') {
70     $self->{option}->{can_have_group} = 0;
71     $self->{option}->{max} = 1 if $format =~ /rfc1036/;
72     } elsif ($field eq 'approved' || $field eq 'x-approved') {
73     $self->{option}->{can_have_group} = 0;
74     $self->{option}->{max} = 1 if $format =~ /news-rfc1036/;
75     }
76    
77     $self->{option}->{value_type}->{mailbox} = ['Message::Field::Mailbox',
78     {%mailbox}];
79     $self->{option}->{value_type}->{group} = ['Message::Field::Addresses',
80     {-is_group => 1, %group}];
81 wakaba 1.1 }
82    
83 wakaba 1.2 =item $addrs = Message::Field::Addresses->new ([%options])
84    
85     Constructs a new object. You might pass some options as parameters
86     to the constructor.
87    
88     =cut
89    
90     ## Inherited
91    
92     =item $addrs = Message::Field::Addresses->parse ($field-body, [%options])
93    
94     Constructs a new object with given field body. You might pass
95     some options as parameters to the constructor.
96    
97     =cut
98    
99     ## Inherited
100 wakaba 1.1
101     sub _parse_list ($$) {
102     my $self = shift;
103     my $fb = shift;
104     my @ids;
105     if ($self->{option}->{is_group}) {
106     $fb =~ s{^((?:$REG{quoted_string}|$REG{comment}|[^\x22\x28\x2C\x3A\x3C\x5B])+):}{
107     my ($gname, @gcomment) = Message::Util::delete_comment_to_array ($self, $1);
108     $self->{group_name} = Message::Util::decode_quoted_string ($self, $gname);
109     $self->{group_name_comment} = \@gcomment;
110     ''}gex;
111     $fb =~ s{;((?:$REG{comment}|$REG{WSP})*)$}{
112     my (undef, @gcomment) = Message::Util::delete_comment_to_array ($self, $1);
113     $self->{comment} = \@gcomment;
114     ''}gex;
115     }
116     $fb =~ s{(?:$REG{quoted_string}|$REG{comment}|[^\x22\x28\x2C\x3A\x3C\x5B]|$REG{SC_group}|$REG{SC_angle_addr}|$REG{domain_literal})+}{
117     my $s = $&; $s =~ s/^$REG{WSP}+//; $s =~ s/$REG{WSP}+$//;
118 wakaba 1.3 if ($s =~ /^(?:$REG{quoted_string}|$REG{comment}|[^\x22\x28\x2C\x3A-\x3C\x5B])*:/) {
119 wakaba 1.2 $s = $self->_parse_value (group => $s) if $self->{option}->{parse_all};
120     $s = {type => 'group', value => $s};
121 wakaba 1.1 } else { ## address or keyword
122 wakaba 1.2 $s = $self->_parse_value (mailbox => $s) if $self->{option}->{parse_all};
123     $s = {type => 'mailbox', value => $s};
124 wakaba 1.1 }
125     push @ids, $s;
126     }goex;
127     @ids;
128     }
129    
130     =back
131    
132     =head1 METHODS
133    
134     =over 4
135    
136 wakaba 1.2 =item $addrs->add ({-name => $value}, $addr1, $addr2, $addr3,...)
137    
138     Adds mail address(es).
139    
140     First argument is hash reference to name/value pairs
141     of options. This is optional.
142    
143     Following is list of additional items. Each item
144     can be given as array reference. An array reference
145     is interpreted as [$item-body, $item-option-name =>
146     $item-option-value, $name => $value,...].
147     Available item-options are:
148    
149     =over 2
150    
151     =item C<group>
152    
153     Group name which C<$item-body> belongs to. If there
154     is no such name of group, new group is created.
155    
156     =item C<type> = 'mailbox' / 'group' (default 'group')
157    
158     Format of C<$item-body>. If 'group' is specified,
159     <$item-body> is treated as RFC 2822 group. Otherwise,
160     it is added as a mailbox.
161    
162     =back
163    
164     =item $count = $addrs->count ([%options])
165    
166     Returns the number of items. A 'type' option is available.
167     For example, C<$addrs-E<gt>count (-type =E<gt> 'group')>
168     returns the number of groups.
169    
170     =item $addrs->delete ({%options}, $item-key, $key,...)
171    
172     Deletes items that are matched with (one of) given key.
173     C<{%options}> is optional.
174    
175     C<by> option is used to specify what sort of value given keys are.
176     C<display-name>, the default value, indicates
177     keys are display-name of items to be removed.
178    
179     For C<by> option, value C<index> is also available.
180    
181     C<type> option is also available. Its value is 'mailbox'
182     and 'group'. Default is both of them.
183    
184 wakaba 1.1 =cut
185    
186     ## add, count, delete: Inherited
187    
188     sub _add_array_check ($$\%) {
189     my $self = shift;
190     my ($value, $option) = @_;
191     my $value_option = {};
192     if (ref $value eq 'ARRAY') {
193     ($value, %$value_option) = @$value;
194     }
195     if (length $value_option->{group}) {
196 wakaba 1.2 my $g = $self->item ($value_option->{group}, -type => 'group');
197     delete $value_option->{group};
198     $g->add (Message::Util::make_clone ($option), [$value, %$value_option]);
199     (0);
200     } else {
201     my $type = $value_option->{type} || 'mailbox';
202     $value = $self->_parse_value ($type => $value) if $$option{parse};
203     $$option{parse} = 0;
204     (1, value => {type => $type, value => $value});
205 wakaba 1.1 }
206     }
207    
208     sub _delete_match ($$$\%\%) {
209     my $self = shift;
210     my ($by, $i, $list, $option) = @_;
211     return 0 unless ref $$i; ## Already removed
212     return 0 if $$option{type} && $$i->{type} ne $$option{type};
213     if ($by eq 'display-name') {
214 wakaba 1.2 $$i->{value} = $self->_parse_value ($$i->{type}, $$i->{value});
215     return 1 if ref $$i->{value} && $$list{$$i->{value}->display_name};
216 wakaba 1.4 } elsif ($by eq 'addr-spec') {
217     $$i->{value} = $self->_parse_value ($$i->{type}, $$i->{value});
218     return 1 if ref $$i->{value} && $$list{$$i->{value}->addr_spec};
219 wakaba 1.1 }
220     0;
221     }
222     *_item_match = \&_delete_match;
223    
224     ## Returns returned item value \$item-value, \%option
225     sub _item_return_value ($\$\%) {
226 wakaba 1.4 if (ref ${$_[1]}->{value}) {
227 wakaba 1.1 ${$_[1]}->{value};
228     } else {
229 wakaba 1.2 ${$_[1]}->{value} = $_[0]->_parse_value (${$_[1]}->{type}, ${$_[1]}->{value});
230     ${$_[1]}->{value};
231 wakaba 1.1 }
232     }
233 wakaba 1.4 *_add_return_value = \&_item_return_value;
234 wakaba 1.1
235 wakaba 1.2 ## Returns returned (new created) item value $name, \%option
236     sub _item_new_value ($$\%) {
237     my $type = $_[2]->{type} || 'mailbox';
238     my $v = $_[0]->_parse_value ($type, '');
239     $v->display_name ($_[1]) if ref $v && length $_[1] && $_[2]->{by} eq 'display-name';
240     {type => $type, value => $v};
241     }
242    
243 wakaba 1.1 sub is_group ($;$) {
244     if (defined $_[1]) {
245     $_[0]->{option}->{is_group} = $_[1];
246     }
247     $_[0]->{option}->{is_group};
248     }
249    
250 wakaba 1.2 sub have_group ($) {
251     my $self = shift;
252     for (@{$self->{$self->{option}->{_ARRAY_NAME}}}) {
253     return 1 if $_->{type} eq 'group';
254     }
255     0;
256     }
257    
258 wakaba 1.1 sub display_name ($;$) {
259     if (defined $_[1]) {
260     $_[0]->{group_name} = $_[1];
261     }
262     $_[0]->{group_name};
263     }
264    
265 wakaba 1.3 sub addr_spec ($;%) {
266     my $self = shift;
267     my @a;
268     for (@{$self->{$self->{option}->{_ARRAY_NAME}}}) {
269 wakaba 1.4 $_->{value} = $self->_parse_value
270     ($_->{type} => $_->{value}) unless ref $_->{value};
271 wakaba 1.3 if (ref $_->{value}) {
272     push @a, $_->{value}->addr_spec (@_);
273     } elsif (length $_->{value}) {
274     push @a, $_->{value};
275     }
276     }
277     wantarray? @a: $a[0];
278     }
279 wakaba 1.2
280 wakaba 1.1 ## stringify: Inherited
281     #*as_string = \&stringify;
282    
283     sub stringify ($;%) {
284     my $self = shift;
285     my %o = @_;
286     my %option = %{$self->{option}};
287     for (grep {/^-/} keys %o) {$option{substr ($_, 1)} = $o{$_}}
288     my $m = $self->SUPER::stringify (@_);
289     my $g = '';
290     if ($option{is_group}) {
291     my %s = &{$option{hook_encode_string}} ($self,
292     $self->{group_name}, type => 'phrase');
293     $g .= Message::Util::quote_unsafe_string
294     ($s{value}, unsafe => 'NON_atext_wsp');
295     }
296     if ($option{output_comment} && $option{output_group_name_comment}) {
297     if (!$option{is_group} && length $self->{group_name}) {
298     $g .= ' ('. $self->Message::Util::encode_ccontent ($self->{group_name}) .':)';
299     }
300     for (@{$self->{group_name_comment}}) {
301     $g .= ' ('. $self->Message::Util::encode_ccontent ($_) .')';
302     }
303     }
304     if ($option{is_group}) {
305     $m = $g . (length $m? ': ': ':') . $m . ';';
306     } else {
307 wakaba 1.2 $m = $g . (length $g? ' ': '') . $m;
308 wakaba 1.1 }
309     if ($option{output_comment} && !$option{output_group_name_comment}) {
310     for (@{$self->{group_name_comment}}) {
311     $m .= ' ('. $self->Message::Util::encode_ccontent ($_) .')';
312     }
313     }
314     if ($option{output_comment}) {
315     for (@{$self->{comment}}) {
316     $m .= ' ('. $self->Message::Util::encode_ccontent ($_) .')';
317     }
318     }
319     $m;
320     }
321     *as_string = \&stringify;
322     sub _stringify_item ($$\%) {
323     my $self = shift;
324     my $item = shift;
325     my $option = shift;
326     if (!$$option{can_have_group} && ref $item->{value}) {
327     $item->{value}->stringify (-is_group => 0);
328     } else {
329     $item->{value};
330     }
331     }
332    
333     ## option, value_type, clone, method_available: Inherited
334    
335     =head1 LICENSE
336    
337     Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
338    
339     This program is free software; you can redistribute it and/or modify
340     it under the terms of the GNU General Public License as published by
341     the Free Software Foundation; either version 2 of the License, or
342     (at your option) any later version.
343    
344     This program is distributed in the hope that it will be useful,
345     but WITHOUT ANY WARRANTY; without even the implied warranty of
346     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
347     GNU General Public License for more details.
348    
349     You should have received a copy of the GNU General Public License
350     along with this program; see the file COPYING. If not, write to
351     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
352     Boston, MA 02111-1307, USA.
353    
354     =head1 CHANGE
355    
356     See F<ChangeLog>.
357 wakaba 1.4 $Date: 2002/05/15 07:29:09 $
358 wakaba 1.1
359     =cut
360    
361     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24