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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations) (download)
Wed Mar 20 09:56:26 2002 UTC (22 years, 8 months ago) by wakaba
Branch: MAIN
2002-03-20  wakaba <w@suika.fam.cx>

	* MsgID.pm, Received.pm, Subject.pm: New modules.
	* MsgID/: New directory.

1 wakaba 1.1
2     =head1 NAME
3    
4     Message::Field::Received Perl module
5    
6     =head1 DESCRIPTION
7    
8     Perl module for RFC 821/822/2821/2822 Received C<field>.
9    
10     =cut
11    
12     package Message::Field::Received;
13     require 5.6.0;
14     use strict;
15     use re 'eval';
16     use vars qw(%OPTION %REG $VERSION);
17     $VERSION = '1.00';
18    
19     use Message::Field::Date;
20     use overload '@{}' => sub {shift->_delete_empty_item->{item}},
21     '""' => sub {shift->stringify};
22    
23     $REG{comment} = qr/\x28(?:\x5C[\x00-\xFF]|[\x00-\x0C\x0E-\x27\x2A-\x5B\x5D-\xFF]+|(??{$REG{comment}}))*\x29/;
24     $REG{quoted_string} = qr/\x22(?:\x5C[\x00-\xFF]|[\x00-\x0C\x0E-\x21\x23-\x5B\x5D-\xFF])*\x22/;
25     $REG{domain_literal} = qr/\x5B(?:\x5C[\x00-\xFF]|[\x00-\x0C\x0E-\x5A\x5E-\xFF])*\x5D/;
26    
27     $REG{WSP} = qr/[\x20\x09]+/;
28     $REG{FWS} = qr/[\x20\x09]*/;
29     $REG{atext} = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2F\x30-\x39\x3D\x3F\x41-\x5A\x5E-\x7E]+/;
30     $REG{dot_atom} = qr/$REG{atext}(?:$REG{FWS}\x2E$REG{FWS}$REG{atext})*/;
31     $REG{dot_word} = qr/(?:$REG{atext}|$REG{quoted_string})(?:$REG{FWS}\x2E$REG{FWS}(?:$REG{atext}|$REG{quoted_string}))*/;
32     $REG{domain} = qr/(?:$REG{dot_atom}|$REG{domain_literal})/;
33     $REG{addr_spec} = qr/$REG{dot_word}$REG{FWS}\x40$REG{FWS}$REG{domain}/;
34     $REG{msg_id} = qr/<$REG{FWS}$REG{addr_spec}$REG{FWS}>/;
35     $REG{item_name} = qr/[A-Za-z][0-9A-Za-z-]*[0-9A-Za-z]/;
36     ## strictly, item-name = ALPHA *(["-"] (ALPHA / DIGIT))
37     $REG{M_name_val_pair} = qr/($REG{item_name})$REG{FWS}($REG{msg_id}|$REG{addr_spec}|$REG{domain}|$REG{atext})/;
38     $REG{date_time} = qr/(?:[A-Za-z]+$REG{FWS},$REG{FWS})?[0-9]+$REG{WSP}*[A-Za-z]+$REG{WSP}*[0-9]+$REG{WSP}+[0-9]+$REG{FWS}:$REG{WSP}*[0-9]+(?:$REG{FWS}:$REG{WSP}*[0-9]+)?$REG{FWS}(?:[A-Za-z]+|[+-]$REG{WSP}*[0-9]+)/;
39     $REG{asctime} = qr/[A-Za-z]+$REG{WSP}*[A-Za-z]+$REG{WSP}*[0-9]+$REG{WSP}+[0-9]+$REG{FWS}:$REG{WSP}*[0-9]+$REG{FWS}:$REG{WSP}*[0-9]+$REG{WSP}+[0-9]+/;
40    
41     %OPTION = (
42     );
43    
44     =head2 Message::Field::Received->new ()
45    
46     Return empty received object.
47    
48     =cut
49    
50     sub new ($;%) {
51     my $self = bless {}, shift;
52     my %option = @_;
53     for (%OPTION) {$option{$_} ||= $OPTION{$_}}
54     $self->{option} = \%option;
55     $self->{date_time} = new Message::Field::Date;
56     $self;
57     }
58    
59     =head2 Message::Field::Received->parse ($unfolded_field_body)
60    
61     Parse Received: C<field-body>.
62    
63     =cut
64    
65     sub parse ($$;%) {
66     my $self = bless {}, shift;
67     my $field_body = shift;
68     my %option = @_;
69     for (%OPTION) {$option{$_} ||= $OPTION{$_}}
70     $self->{option} = \%option;
71     $field_body = $self->delete_comment ($field_body);
72     $field_body =~ s{;$REG{FWS}($REG{date_time})$REG{FWS}$}{
73     $self->{date_time} = Message::Field::Date->parse ($1);
74     '';
75     }ex;
76     unless ($self->{date_time}) {
77     if ($field_body =~ /($REG{asctime})/) { ## old USENET format
78     $self->{date_time} = Message::Field::Date->parse ($1);
79     return $self;
80     } else { ## broken!
81     $field_body =~ s/;[^;]+$//;
82     $self->{date_time} = new Message::Field::Date (unknown => 1);
83     }
84     }
85     $field_body =~ s{$REG{M_name_val_pair}$REG{FWS}}{
86     my ($name, $value) = (lc $1, $2);
87     $name =~ tr/-/_/;
88     push @{$self->{item}}, [$name => $value];
89     ''
90     }goex;
91     $self;
92     }
93    
94     =head2 $self->items ()
95    
96     Return item list hash that contains of C<name-val-list>
97     array references.
98    
99     =cut
100    
101     sub items ($) {@{shift->{item}}}
102    
103     sub item_name ($$) {
104     my $self = shift;
105     my $i = shift;
106     $self->{item}->[$i]->[0];
107     }
108    
109     sub item_value ($$) {
110     my $self = shift;
111     my $i = shift;
112     $self->{item}->[$i]->[1];
113     }
114    
115     sub item ($$) {
116     my $self = shift;
117     my $name = lc shift;
118     my @ret;
119     for my $item (@{$self->{item}}) {
120     if ($item->[0] eq $name) {
121     unless (wantarray) {
122     return $item->[1];
123     } else {
124     push @ret, $item->[1];
125     }
126     }
127     }
128     @ret;
129     }
130    
131     sub date_time ($) {
132     my $self = shift;
133     $self->{date_time};
134     }
135    
136     =head2 $self->add ($item_name, $item_value)
137    
138     Add an C<nama-val-pair>.
139    
140     Note that this method (and other methods) does not check
141     C<item-val-pair> is valid as RFC (2)82[12] definition or not.
142     (But only C<item-name> is changed when C<stringify>.)
143    
144     =cut
145    
146     sub add ($$$) {
147     my $self = shift;
148     my ($name, $value) = @_;
149     push @{$self->{item}}, [$name, $value];
150     $self;
151     }
152    
153     sub replace ($$$) {
154     my $self = shift;
155     my ($name => $value) = (lc shift => shift);
156     for my $item (@{$self->{item}}) {
157     if ($item->[0] eq $name) {
158     $item->[1] = $value;
159     return $self;
160     }
161     }
162     push @{$self->{item}}, [$name => $value];
163     $self;
164     }
165    
166     =head2 $self->delete ($item_name, [$index])
167    
168     Deletes C<name-val-pair> named as $item_name.
169     If $index is specified, only $index'th C<name-val-pair> is deleted.
170     If not, ($index == 0), all C<name-val-pair>s that have the C<item-name>
171     $item_name are deleted.
172    
173     =cut
174    
175     sub delete ($$;$) {
176     my $self = shift;
177     my ($name, $index) = (lc shift, shift);
178     my $i = 0;
179     for my $item (@{$self->{item}}) {
180     if ($item->[0] eq $name) {
181     $i++;
182     if ($index == 0 || $i == $index) {
183     undef $item;
184     return $self if $i == $index;
185     }
186     }
187     }
188     $self;
189     }
190    
191     =head2 $self->count ([$item_name])
192    
193     Returns the number of times the given C<item-name>'ed
194     C<name-val-pair> appears.
195     If no $item_name is given, returns the number
196     of fields. (Same as $#$self+1)
197    
198     =cut
199    
200     sub count ($;$) {
201     my $self = shift;
202     my ($name) = (lc shift);
203     unless ($name) {
204     $self->_delete_empty_item ();
205     return $#{$self->{item}}+1;
206     }
207     my $count = 0;
208     for my $item (@{$self->{item}}) {
209     if ($item->[0] eq $name) {
210     $count++;
211     }
212     }
213     $count;
214     }
215    
216     sub _delete_empty_item ($) {
217     my $self = shift;
218     my @ret;
219     for my $item (@{$self->{item}}) {
220     push @ret, $item if $item->[0];
221     }
222     $self->{item} = \@ret;
223     $self;
224     }
225    
226    
227    
228     sub stringify ($;%) {
229     my $self = shift;
230     my %option = @_;
231     my @return;
232     $self->_delete_empty_item;
233     for my $item (@{$self->{item}}) {
234     push @return, $item->[0], $item->[1] if $item->[0] =~ /^$REG{item_name}$/;
235     }
236     join (' ', @return).'; '.$self->{date_time}->as_rfc2822_time;
237     }
238    
239     sub as_string ($;%) {shift->stringify (@_)}
240    
241     =head2 $self->delete_comment ($field_body)
242    
243     Remove all C<comment> in given strictured C<field-body>.
244     This method is intended for internal use.
245    
246     =cut
247    
248     sub delete_comment ($$) {
249     my $self = shift;
250     my $body = shift;
251     $body =~ s{($REG{quoted_string}|$REG{domain_literal})|$REG{comment}}{
252     my $o = $1; $o? $o : ' ';
253     }gex;
254     $body;
255     }
256    
257     =head1 EXAMPLE
258    
259     ## Compose field-body for To: field.
260    
261     use Message::Field::Address;
262     my $addr = new Message::Field::Address;
263     $addr->add ('foo@example.org', name => 'Mr. foo bar');
264     $addr->add ('webmaster@example.org', group => 'administrators');
265     $addr->add ('postmaster@example.org', group => 'administrators');
266    
267     my $field_body = $addr->stringify ();
268    
269    
270     ## Output parsed address-list tree.
271    
272     use Message::Field::Address;
273     my $addr = Message::Field::Address->parse ($field_body);
274    
275     for my $i (@$addr) {
276     if ($i->{type} eq 'group') {
277     print "\x40 $i->{display_name}: \n";
278     for my $j (@{$i->{address}}) {
279     print "\t- $j->{display_name} <$j->{route}$j->{addr_spec}>\n";
280     }
281     } else {
282     print "- $i->{display_name} <$i->{route}$i->{addr_spec}>\n";
283     }
284     }
285    
286     =head1 LICENSE
287    
288     Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
289    
290     This program is free software; you can redistribute it and/or modify
291     it under the terms of the GNU General Public License as published by
292     the Free Software Foundation; either version 2 of the License, or
293     (at your option) any later version.
294    
295     This program is distributed in the hope that it will be useful,
296     but WITHOUT ANY WARRANTY; without even the implied warranty of
297     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
298     GNU General Public License for more details.
299    
300     You should have received a copy of the GNU General Public License
301     along with this program; see the file COPYING. If not, write to
302     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
303     Boston, MA 02111-1307, USA.
304    
305     =head1 CHANGE
306    
307     See F<ChangeLog>.
308     $Date: 2002/03/16 01:26:30 $
309    
310     =cut
311    
312     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24