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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (hide annotations) (download)
Sat Jun 15 07:15:59 2002 UTC (22 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.4: +75 -120 lines
2002-06-15  wakaba <w@suika.fam.cx>

	* AngleQuoted.pm: New module.
	* Mailbox.pm, URI.pm: Use AngleQuoted.pm

1 wakaba 1.1
2     =head1 NAME
3    
4     Message::Field::Mailbox --- A perl module for an Internet
5     mail address (mailbox) which is part of Internet Messages
6    
7     =cut
8    
9     package Message::Field::Mailbox;
10     require 5.6.0;
11     use strict;
12     use re 'eval';
13     use vars qw(%DEFAULT @ISA %REG $VERSION);
14 wakaba 1.5 $VERSION=do{my @r=(q$Revision: 1.4 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
15     require Message::Field::AngleQuoted;
16     push @ISA, qw(Message::Field::AngleQuoted);
17 wakaba 1.1
18     %REG = %Message::Util::REG;
19     $REG{sub_domain} = qr/$REG{atext}|$REG{domain_literal}/;
20     $REG{domain} = qr/$REG{sub_domain}(?:$REG{FWS}\.$REG{FWS}$REG{sub_domain})*/;
21     $REG{route} = qr/\x40$REG{FWS}$REG{domain}(?:[\x09\x20,]*\x40$REG{FWS}$REG{domain})*$REG{FWS}:/;
22    
23     =head1 CONSTRUCTORS
24    
25     The following methods construct new objects:
26    
27     =over 4
28    
29     =cut
30    
31     ## Initialize of this class -- called by constructors
32     %DEFAULT = (
33     -_ARRAY_NAME => 'route',
34     -_ARRAY_VALTYPE => 'domain',
35 wakaba 1.2 -_MEMBERS => [qw|display_name route local_part domain keyword|],
36     -_METHODS => [qw|addr_spec display_name local_part domain keyword
37     have_group comment_add comment_delete comment_item
38     comment_count route_add route_count route_delete
39     route_item|],
40 wakaba 1.5 -allow_empty => 0,
41 wakaba 1.1 -by => 'domain',
42     -comment_to_display_name => 1,
43     -default_domain => 'localhost',
44     #encoding_after_encode
45     #encoding_before_decode
46     #-encoding_after_encode_domain => 'unknown-8bit',
47     #-encoding_before_decode_domain => 'unknown-8bit',
48     -encoding_after_encode_local_part => 'unknown-8bit',
49     -encoding_before_decode_local_part => 'unknown-8bit',
50     #field_param_name
51     #field_name
52     -fill_domain => 1,
53     #format
54     #hook_encode_string
55     #hook_decode_string
56     -must_have_addr_spec => 1,
57 wakaba 1.5 #output_angle_bracket => 1,
58     #output_comment => 1,
59     #output_display_name => 1,
60     #output_keyword => 0,
61 wakaba 1.1 -output_route => 0,
62 wakaba 1.5 #parse_all => 0, ## = parse_domain + parse_local_part
63     -parse_domain => 0,
64     -parse_local_part => 0, ## not implemented.
65     #unsafe_rule_of_display_name => 'NON_http_attribute_char_wsp',
66     -unsafe_rule_of_local_part => 'NON_http_attribute_char_wsp',
67     #unsafe_rule_of_keyword => 'NON_atext',
68     -use_comment_in_angle => 1,
69     #use_keyword => 0,
70 wakaba 1.1 );
71 wakaba 1.5
72 wakaba 1.1 sub _init ($;%) {
73     my $self = shift;
74     my %options = @_;
75     my $DEFAULT = Message::Util::make_clone (\%DEFAULT);
76     $self->SUPER::_init (%$DEFAULT, %options);
77 wakaba 1.3 $self->{option}->{value_type}->{domain} = ['Message::Field::Domain', {
78 wakaba 1.1 #-encoding_after_encode => $self->{option}->{encoding_after_encode_domain},
79     #-encoding_before_decode => $self->{option}->{encoding_before_decode_domain},
80     },];
81    
82     my $format = $self->{option}->{format};
83 wakaba 1.3 my $field = $self->{option}->{field_name};
84 wakaba 1.1 if ($format =~ /mail-rfc822/) {
85 wakaba 1.2 $self->{option}->{output_route} = 1
86 wakaba 1.1 if $field eq 'from' || $field eq 'resent-from'
87     || $field eq 'sender' || $field eq 'resent-sender'
88     || $field eq 'to' || $field eq 'cc' || $field eq 'bcc'
89     || $field eq 'resent-to' || $field eq 'resent-cc'
90     || $field eq 'resent-bcc' || $field eq 'reply-to'
91     || $field eq 'resent-reply-to' || $field eq 'return-path';
92     }
93 wakaba 1.3 if ($field eq 'mail-copies-to') {
94 wakaba 1.1 $self->{option}->{use_keyword} = 1;
95 wakaba 1.2 $self->{option}->{output_keyword} = 1;
96 wakaba 1.1 }
97 wakaba 1.3 if ($field eq 'return-path') {
98 wakaba 1.5 $self->{option}->{allow_empty} = 1;
99     $self->{option}->{allow_empty} = 0
100     if $format =~ /rfc822/ && $format !~ /rfc1123/;
101 wakaba 1.1 $self->{option}->{output_display_name} = 0;
102 wakaba 1.5 $self->{option}->{output_comment} = 0
103     if $format =~ /smtp/;
104 wakaba 1.1 ## RFC [2]822 allows CFWS, but [2]821 does NOT.
105     }
106 wakaba 1.5 #if ($format =~ /http/) {
107     # $self->{option}->{unsafe_rule_local_part} = 'NON_http_attribute_char_wsp';
108     #}
109 wakaba 1.1 }
110    
111 wakaba 1.3 =item $m = Message::Field::Mailbox->new ([%options])
112 wakaba 1.1
113     Constructs a new object. You might pass some options as parameters
114     to the constructor.
115    
116     =cut
117    
118     ## Inherited
119    
120 wakaba 1.3 =item $m = Message::Field::Mailbox->parse ($field-body, [%options])
121 wakaba 1.1
122     Constructs a new object with given field body. You might pass
123     some options as parameters to the constructor.
124    
125     =cut
126    
127 wakaba 1.5 ## $self->_save_value ($value, $display_name, \@comment)
128     sub _save_value ($$\@%) {
129     my $self = shift;
130     my ($v, $dn, $comment, %misc) = @_;
131 wakaba 1.1 my $parse_lp = $self->{option}->{parse_local_part}
132     || $self->{option}->{parse_all};
133     my $parse_dm = $self->{option}->{parse_domain}
134     || $self->{option}->{parse_all};
135 wakaba 1.5 $v = Message::Util::remove_meaningless_wsp ($v);
136     if ($v =~ /^($REG{route})?((?:$REG{quoted_string}|[^\x22])+?)\x40((?:$REG{domain_literal}|[^\x5B\x40])+)$/) {
137 wakaba 1.1 my $route = $1;
138     $self->{local_part} = $2; $self->{domain} = $3;
139     $self->{domain} = $self->_parse_value ('domain' => $self->{domain})
140     if $parse_dm;
141     $route =~ s{\x40$REG{FWS}($REG{domain})}{
142     my $d = $1;
143 wakaba 1.5 $d = $self->_parse_value (domain => $d) if $parse_dm;
144 wakaba 1.1 push @{$self->{route}}, $d;
145     }gex;
146 wakaba 1.5 } elsif (length $v) {
147     $self->{local_part} = $v;
148 wakaba 1.1 }
149     $self->{local_part}
150     = $self->Message::Util::decode_quoted_string ($self->{local_part},
151     type => 'word',
152     charset => $self->{option}->{encoding_before_decode_local_part});
153 wakaba 1.5 $self->{comment} = $comment;
154     $self->{display_name} = $dn;
155     $self->{keyword} = $misc{keyword};
156 wakaba 1.1 }
157    
158 wakaba 1.5 ## display_name: Inherited
159 wakaba 1.4
160 wakaba 1.1 sub local_part ($;$) {
161     my $self = shift;
162     my $newlp = shift;
163     $self->{local_part} = $newlp if defined $newlp;
164     $self->{local_part};
165     }
166    
167     sub domain ($;$) {
168     my $self = shift;
169     my $newdomain = shift;
170     if (defined $newdomain) {
171 wakaba 1.5 $newdomain = $self->_parse_value (domain => $newdomain)
172 wakaba 1.1 if $self->{option}->{parse_domain} || $self->{option}->{parse_all};
173     $self->{domain} = $newdomain;
174     }
175     $self->{domain};
176     }
177    
178     sub keyword ($;$) {
179     my $self = shift;
180     return unless $self->{option}->{use_keyword};
181     my $newkey = shift;
182     $self->{keyword} = $newkey if defined $newkey;
183     $self->{keyword};
184     }
185    
186 wakaba 1.5 sub route_add ($@) { shift->SUPER::add (@_) }
187     sub route_count ($@) { shift->SUPER::count (@_) }
188     sub route_delete ($@) { shift->SUPER::delete (@_) }
189     sub route_item ($@) { shift->SUPER::item (@_) }
190 wakaba 1.1
191     sub _delete_match ($$$\%\%) {
192     my $self = shift;
193     my ($by, $i, $list, $option) = @_;
194 wakaba 1.5 return 0 unless ref $$i; ## Already removed
195 wakaba 1.1 return 0 if $$option{type} && $$i->{type} ne $$option{type};
196     if ($by eq 'domain') {
197 wakaba 1.5 $$i = $self->_parse_value (domain => $$i);
198 wakaba 1.1 return 1 if $list->{$$i};
199     }
200     0;
201     }
202     *_item_match = \&_delete_match;
203    
204     ## Returns returned item value \$item-value, \%option
205     sub _item_return_value ($\$\%) {
206     if (ref ${$_[1]}) {
207     ${$_[1]};
208     } else {
209     ${$_[1]} = $_[0]->_parse_value (domain => ${$_[1]});
210     ${$_[1]};
211     }
212     }
213     sub _item_new_value ($$\%) {
214 wakaba 1.5 $_[0]->_parse_value (domain => ($_[2]->{by} eq 'domain'? $_[1]: ''));
215 wakaba 1.1 }
216    
217 wakaba 1.5 sub have_group ($) { 0 }
218 wakaba 1.2
219     sub addr_spec ($;%) {
220     my $self = shift;
221     my %o = (
222     -output_angle_bracket => 0,
223     -output_comment => 0,
224     -output_display_name => 0,
225     -output_keyword => 0,
226     -output_route => 0,
227     );
228     $self->stringify (%o, @_);
229     }
230 wakaba 1.5 *value = \&addr_spec;
231 wakaba 1.2
232 wakaba 1.5 ## $self->_stringify_value (\%option)
233     sub _stringify_value ($\%) {
234 wakaba 1.1 my $self = shift;
235 wakaba 1.5 my $option = shift;
236     my %r;
237     my %s = &{$option->{hook_encode_string}} ($self,
238 wakaba 1.1 $self->{local_part}, type => 'word',
239 wakaba 1.5 charset => $option->{encoding_after_encode_local_part});
240     my $as = Message::Util::quote_unsafe_string ($s{value},
241     unsafe => $option->{unsafe_rule_local_part});
242 wakaba 1.1 my $d = '' . $self->{domain};
243 wakaba 1.5 $d ||= $option->{default_domain} if $option->{fill_domain};
244 wakaba 1.1 $as .= '@' . $d if length $d && length $as;
245 wakaba 1.5 if ($option->{output_angle_bracket}) {
246     if ($option->{output_route}) {
247 wakaba 1.1 my $route = join ',', grep {$_ ne '@'}
248     map {'@'.$_} @{$self->{route}};
249     $as = $route . ':' . $as if $route;
250     }
251     }
252 wakaba 1.5 $r{value} = $as;
253     $r{display_name} = $self->{display_name};
254     $r{comment} = $self->{comment};
255     $r{keyword} = $self->{keyword};
256     %r;
257     }
258    
259     ## $self->_option_recursive (\%argv)
260     sub _option_recursive ($\%) {
261     my $self = shift;
262     my $o = shift;
263     for (@{$self->{route}}) {
264     $_->option (%$o) if ref $_;
265 wakaba 1.1 }
266 wakaba 1.5 $self->{local_part}->option (%$o) if ref $self->{local_part};
267     $self->{domain}->option (%$o) if ref $self->{domain};
268 wakaba 1.1 }
269    
270     =head1 LICENSE
271    
272     Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
273    
274     This program is free software; you can redistribute it and/or modify
275     it under the terms of the GNU General Public License as published by
276     the Free Software Foundation; either version 2 of the License, or
277     (at your option) any later version.
278    
279     This program is distributed in the hope that it will be useful,
280     but WITHOUT ANY WARRANTY; without even the implied warranty of
281     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
282     GNU General Public License for more details.
283    
284     You should have received a copy of the GNU General Public License
285     along with this program; see the file COPYING. If not, write to
286     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
287     Boston, MA 02111-1307, USA.
288    
289     =head1 CHANGE
290    
291     See F<ChangeLog>.
292 wakaba 1.5 $Date: 2002/06/09 11:08:28 $
293 wakaba 1.1
294     =cut
295    
296     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24