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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations) (download)
Tue Mar 26 05:31:55 2002 UTC (22 years, 8 months ago) by wakaba
Branch: MAIN
Changes since 1.2: +52 -7 lines
2002-03-26  wakaba <w@suika.fam.cx>

	* UA.pm: New module.

1
2 =head1 NAME
3
4 Message::Field::Structured Perl module
5
6 =head1 DESCRIPTION
7
8 Perl module for RFC 822/2822 structured C<field>s.
9
10 =cut
11
12 package Message::Field::Structured;
13 require 5.6.0;
14 use strict;
15 use re 'eval';
16 use vars qw(%DEFAULT %REG $VERSION);
17 $VERSION=do{my @r=(q$Revision: 1.3 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
18 require Message::Util;
19
20 use overload '""' => sub {shift->stringify};
21
22 $REG{comment} = qr/\x28(?:\x5C[\x00-\xFF]|[\x00-\x0C\x0E-\x27\x2A-\x5B\x5D-\xFF]|(??{$REG{comment}}))*\x29/;
23 $REG{quoted_string} = qr/\x22(?:\x5C[\x00-\xFF]|[\x00-\x0C\x0E-\x21\x23-\x5B\x5D-\xFF])*\x22/;
24 $REG{domain_literal} = qr/\x5B(?:\x5C[\x00-\xFF]|[\x00-\x0C\x0E-\x5A\x5E-\xFF])*\x5D/;
25
26 $REG{WSP} = qr/[\x20\x09]+/;
27 $REG{FWS} = qr/[\x20\x09]*/;
28 $REG{M_quoted_string} = qr/\x22((?:\x5C[\x00-\xFF]|[\x00-\x0C\x0E-\x21\x23-\x5B\x5D-\xFF])*)\x22/;
29 $REG{M_comment} = qr/\x28((?:\x5C[\x00-\xFF]|[\x00-\x0C\x0E-\x27\x2A-\x5B\x5D-\xFF]|(??{$REG{comment}}))*)\x29/;
30
31 $REG{NON_atom} = qr/[^\x09\x20\x21\x23-\x27\x2A\x2B\x2D\x2F\x30-\x39\x3D\x3F\x41-\x5A\x5E-\x7E]/;
32
33 %DEFAULT = (
34 encoding_after_encode => '*default',
35 encoding_before_decode => '*default',
36 hook_encode_string => #sub {shift; (value => shift, @_)},
37 \&Message::Util::encode_header_string,
38 hook_decode_string => #sub {shift; (value => shift, @_)},
39 \&Message::Util::decode_header_string,
40 );
41
42 =head2 Message::Field::Structured->new ()
43
44 Return empty Message::Field::Structured object.
45
46 =cut
47
48 sub new ($;%) {
49 my $class = shift;
50 my $self = bless {option => {@_}}, $class;
51 for (keys %DEFAULT) {$self->{option}->{$_} ||= $DEFAULT{$_}}
52 $self;
53 }
54
55 =head2 Message::Field::Structured->parse ($unfolded_field_body)
56
57 Parse structured C<field-body>.
58
59 =cut
60
61 sub parse ($$;%) {
62 my $class = shift;
63 my $self = bless {option => {@_}}, $class;
64 for (keys %DEFAULT) {$self->{option}->{$_} ||= $DEFAULT{$_}}
65 my $field_body = $self->_decode_qcontent (shift);
66 $self->{field_body} = $field_body;
67 $self;
68 }
69
70 =head2 $self->stringify ()
71
72 Returns C<field-body> as a string.
73
74 =cut
75
76 sub stringify ($) {
77 my $self = shift;
78 $self->_encode_qcontent ($self->{field_body});
79 }
80
81 =head2 $self->as_plain_string ()
82
83 Returns C<field-body> contents as a plain text fragment.
84 C<quoted-string> and C<quoted-pair> in C<comment> are
85 unquoted, so return value of this method can be invalid
86 as a part of the C<field>.
87
88 =cut
89
90 sub as_plain_string ($) {
91 my $self = shift;
92 $self->unquote_quoted_string ($self->unquote_comment ($self->{field_body}));
93 }
94
95 ## Decode C<qcontent> (content of C<quoted-string>).
96 sub _decode_qcontent ($$) {
97 my $self = shift;
98 my $quoted_string = shift;
99 $quoted_string =~ s{$REG{M_quoted_string}}{
100 my ($qtext) = ($1);
101 $qtext =~ s/\x5C([\x00-\xFF])/$1/g;
102 my %s = &{$self->{option}->{hook_decode_string}} ($self, $qtext,
103 type => 'phrase/quoted');
104 $s{value} =~ s/([\x22\x5C])([\x20-\xFF])?/"\x5C$1".($2?"\x5C$2":'')/ge;
105 '"'.$s{value}.'"';
106 }goex;
107 $quoted_string;
108 }
109
110 ## Encode C<qcontent> (content of C<quoted-string>).
111 sub _encode_qcontent ($$) {
112 my $self = shift;
113 my $quoted_string = shift;
114 $quoted_string =~ s{$REG{M_quoted_string}}{
115 my ($qtext) = ($1);
116 $qtext =~ s/\x5C([\x00-\xFF])/$1/g;
117 my %s = &{$self->{option}->{hook_encode_string}} ($self, $qtext,
118 type => 'phrase/quoted');
119 $s{value} =~ s/([\x22\x5C])([\x20-\xFF])?/"\x5C$1".($2?"\x5C$2":'')/ge;
120 '"'.$s{value}.'"';
121 }goex;
122 $quoted_string;
123 }
124
125 sub quote_unsafe_string ($$) {
126 my $self = shift;
127 my $string = shift;
128 if ($string =~ /$REG{NON_atom}/ || $string =~ /$REG{WSP}$REG{WSP}+/) {
129 $string =~ s/([\x22\x5C])([\x20-\xFF])?/"\x5C$1".($2?"\x5C$2":'')/ge;
130 $string = '"'.$string.'"';
131 }
132 $string;
133 }
134
135 =head2 $self->unquote_quoted_string ($string)
136
137 Unquote C<quoted-string>. Get rid of C<DQUOTE>s and
138 C<REVERSED SOLIDUS> included in C<quoted-pair>.
139 This method is intended for internal use.
140
141 =cut
142
143 sub unquote_quoted_string ($$) {
144 my $self = shift;
145 my $quoted_string = shift;
146 $quoted_string =~ s{$REG{M_quoted_string}}{
147 my $qtext = $1;
148 $qtext =~ s/\x5C([\x00-\xFF])/$1/g;
149 $qtext;
150 }goex;
151 $quoted_string;
152 }
153
154 sub unquote_comment ($$) {
155 my $self = shift;
156 my $quoted_string = shift;
157 $quoted_string =~ s{$REG{M_comment}}{
158 my $qtext = $1;
159 $qtext =~ s/\x5C([\x00-\xFF])/$1/g;
160 '('.$qtext.')';
161 }goex;
162 $quoted_string;
163 }
164
165 =head2 $self->delete_comment ($field_body)
166
167 Remove all C<comment> in given strictured C<field-body>.
168 This method is intended for internal use.
169
170 =cut
171
172 sub delete_comment ($$) {
173 my $self = shift;
174 my $body = shift;
175 $body =~ s{($REG{quoted_string}|$REG{domain_literal})|$REG{comment}}{
176 my $o = $1; $o? $o : ' ';
177 }gex;
178 $body;
179 }
180
181 =head1 EXAMPLE
182
183 use Message::Field::Structured;
184
185 my $field_body = '"This is an example of <\"> (quotation mark)."
186 (Comment within \q\u\o\t\e\d\-\p\a\i\r\(\s\))';
187 my $field = Message::Field::Structured->parse ($field_body);
188
189 print $field->as_plain_string;
190
191 =head1 LICENSE
192
193 Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
194
195 This program is free software; you can redistribute it and/or modify
196 it under the terms of the GNU General Public License as published by
197 the Free Software Foundation; either version 2 of the License, or
198 (at your option) any later version.
199
200 This program is distributed in the hope that it will be useful,
201 but WITHOUT ANY WARRANTY; without even the implied warranty of
202 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
203 GNU General Public License for more details.
204
205 You should have received a copy of the GNU General Public License
206 along with this program; see the file COPYING. If not, write to
207 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
208 Boston, MA 02111-1307, USA.
209
210 =head1 CHANGE
211
212 See F<ChangeLog>.
213
214 =cut
215
216 1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24