/[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.1 - (hide annotations) (download)
Tue May 14 13:42:40 2002 UTC (22 years, 6 months ago) by wakaba
Branch: MAIN
2002-05-15  wakaba <w@suika.fam.cx>

	* Addresses.pm, Mailbox.pm, Domain.pm
	(son-of-Address.pm's): New modules.
	* Structured.pm:
	- (method_available): New method.
	- (clone): Checks _MEMBERS option.
	- (comment_add, comment_count, comment_delete, comment_item):
	New methods.
	- (item): Implemented.
	- (_delete_empty): Commentout default action.
	- (add, replace): Fix bug (parse option didn't work).
	* MsgID.pm: Don't use non-(ALPHA / DIGIT) as the first
	character of id-left.
	* Date.pm: Understands month name "Sept".

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24