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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (show annotations) (download)
Sat Dec 28 08:45:50 2002 UTC (21 years, 11 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, HEAD
Branch point for: branch-suikawiki-1, experimental-xml-parser-200401
Changes since 1.12: +9 -5 lines
*** empty log message ***

1
2 =head1 NAME
3
4 Message::Field::Subject -- Perl module for Internet
5 message header C<Subject:> field body
6
7 =cut
8
9 package Message::Field::Subject;
10 use strict;
11 use vars qw(%DEFAULT @ISA %REG $VERSION);
12 $VERSION=do{my @r=(q$Revision: 1.12 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
13 require Message::Field::Structured;
14 push @ISA, q(Message::Field::Structured);
15
16 %REG = %Message::Util::REG;
17 $REG{news_control} = qr/^cmsg$REG{WSP}+/;
18 $REG{prefix_fwd} = qr/(?i)(?:Fwd?|Forward)/;
19 $REG{prefix_list} = qr/[(\[][A-Za-z0-9._-]+[\x20:-]\d+[)\]]/;
20 $REG{M_prefix_list} = qr/[(\[]([A-Za-z0-9._-]+)[\x20:-](\d+)[)\]]/;
21 $REG{M_was_subject} = qr/\([Ww][Aa][Ss][:\x09\x20]$REG{FWS}(.+?)$REG{FWS}\)$REG{FWS}$/;
22 $REG{message_from_subject} = qr/^$REG{FWS}(?i)Message from \S+$REG{FWS}$/;
23 if ($^V gt v5.7.2) {
24 $REG{prefix_re} = q/(?i)Re|Sv|Odp
25 |\x{8FD4} ## Hen
26 /;
27 $REG{prefix_advertisement} = qr/
28 (?i)ADV?:
29 |[!\x{FF01}] $REG{FWS} \x{5E83}[\x{543F}\x{544A}] $REG{FWS} [!\x{FF01}]
30 ## ! kou koku !
31 |[!\x{FF01}] $REG{FWS} [\x{9023}\x{F99A}]\x{7D61}\x{65B9}\x{6CD5}\x{7121}\x{3057}? $REG{FWS} [!\x{FF01}]
32 ## ! ren raku hou hou nashi !
33 |[\x{672A}\x{672B}] [\x09\x0A\x0D\x20\x{3000}]*
34 \x{627F} [\x09\x0A\x0D\x20\x{3000}]*
35 \x{8AFE} [\x09\x0A\x0D\x20\x{3000}]*
36 \x{5E83} [\x09\x0A\x0D\x20\x{3000}]*
37 [\x{543F}\x{544A}] [\x09\x0A\x0D\x20\x{3000}]* [\x{203B}\x{0FBF}]
38 ## mi shou daku kou koku *
39 /x;
40 } else {
41 $REG{prefix_re} = qr/(?i)Re|Sv|Odp/;
42 $REG{prefix_advertisement} = qr/(?i)ADV?:/;
43 }
44 $REG{prefix_general} = qr/((?:$REG{prefix_re}|$REG{prefix_fwd})\^?[\[\(]?\d*[\]\)]?[:>]$REG{FWS})+/x;
45 $REG{prefix_general_list} = qr/($REG{prefix_general}|$REG{FWS}$REG{prefix_list}$REG{FWS})+/x;
46
47 %DEFAULT = (
48 -_MEMBERS => [qw/is list_count list_name news_control was_subject/],
49 -_METHODS => [qw/as_plain_string is list_count list_name
50 news_control was_subject value value_type/],
51 #encoding_after_encode
52 #encoding_before_decode
53 -format_news_control => 'cmsg %s',
54 -format_prefix_fwd => 'Fwd: %s',
55 -format_prefix_list => '[%s:%05d] %s',
56 -format_prefix_re => 'Re: %s',
57 -format_was_subject => '%s (was: %s)',
58 #field_param_name
59 #field_name
60 #field_ns
61 #format
62 #header_default_charset
63 #header_default_charset_input
64 #hook_encode_string
65 #hook_decode_string
66 -output_general_prefix => 1,
67 -output_list_prefix => 0,
68 -output_news_control => 1,
69 -output_was_subject => 1, ## ["-"] 1*DIGIT
70 #parse_all
71 -parse_was_subject => 1,
72 -use_general_prefix => 1,
73 -use_list_prefix => 1,
74 -use_message_from_subject => 0,
75 -use_news_control => 1,
76 -use_was_subject => 1,
77 #value_type
78 );
79
80 =head1 CONSTRUCTORS
81
82 The following methods construct new objects:
83
84 =over 4
85
86 =cut
87
88 ## Initialize of this class -- called by constructors
89 sub _init ($;%) {
90 my $self = shift;
91 my %options = @_;
92 $self->SUPER::_init (%DEFAULT, %options);
93
94 my $fname = $self->{option}->{field_name};
95 if ($fname =~ /^x-.subject$/) {
96 $self->{option}->{use_list_prefix} = 0 unless defined $options{-use_list_prefix};
97 $self->{option}->{use_news_control} = 0 unless defined $options{-use_news_control};
98 $self->{option}->{use_message_from_subject} = 0 unless defined $options{-use_message_from_subject};
99 }
100
101 #$self->{option}->{value_type}->{news_control} = ['Message::Field::UsenetControl',{}, [qw//]];
102 $self->{option}->{value_type}->{was_subject} = ['Message::Field::Subject',{},
103 [qw/format_news_control format_prefix_fwd format_prefix_re
104 format_was_subject output_general_prefix output_list_prefix
105 output_news_control output_was_subject parse_was_subject
106 use_general_prefix use_list_prefix use_news_control use_was_subject/]];
107 }
108
109 =item $subject = Message::Field::Subject->new ([%options])
110
111 Constructs a new C<Message::Field::Subject> object. You might pass some
112 options as parameters to the constructor.
113
114 =cut
115
116 ## Inherited
117
118 =item $subject = Message::Field::Subject->parse ($field-body, [%options])
119
120 Constructs a new C<Message::Field::Subject> object with
121 given field body. You might pass some options as parameters to the constructor.
122
123 =cut
124
125 sub parse ($$;%) {
126 my $class = shift;
127 my $self = bless {}, $class;
128 my $body = shift;
129 $self->_init (@_);
130 my $option = $self->{option};
131 if ($option->{use_news_control} && $body =~ s/$REG{news_control}//) {
132 $self->{news_control} = $body;
133 return $self;
134 }
135 my $value = '';
136 my %s = &{$self->{option}->{hook_decode_string}} ($self,
137 $body,
138 type => 'text',
139 charset => $option->{encoding_before_decode},
140 );
141 if ($s{charset}) { ## Convertion failed
142 $self->{_charset} = $s{charset};
143 $self->{value} = $s{value};
144 return $self;
145 } elsif (!$s{success}) {
146 $self->{_charset} = $self->{option}->{header_default_charset_input};
147 $self->{value} = $s{value};
148 return $self;
149 }
150 $value = $s{value};
151 #if (!$option->{parse_all}) {
152 # $self->{value} = $value;
153 # return $self;
154 #}
155 if ($option->{use_general_prefix}) {
156 if ($option->{use_list_prefix} && $value =~ s/^($REG{prefix_general_list})//x) {
157 my $prefix = $1;
158 $self->{is}->{reply} = 1 if $prefix =~ /$REG{prefix_re}/x;
159 $self->{is}->{foward} = 1 if $prefix =~ /$REG{prefix_fwd}/x;
160 ($self->{list_name}, $self->{list_count}) = ($1, $2)
161 if $prefix =~ /$REG{M_prefix_list}/x;
162 } elsif ($value =~ s/^($REG{prefix_general})//x) {
163 my $prefix = $1;
164 $self->{is}->{reply} = 1 if $prefix =~ /$REG{prefix_re}/x;
165 $self->{is}->{foward} = 1 if $prefix =~ /$REG{prefix_fwd}/x;
166 }
167 } elsif ($option->{use_list_prefix} && $value =~ s/^$REG{FWS}$REG{M_prefix_list}(?:$REG{FWS}$REG{prefix_list})*$REG{FWS}//x) {
168 ($self->{list_name}, $self->{list_count}) = ($1, $2);
169 }
170 if ($option->{use_was_subject} && $value =~ s/$REG{M_was_subject}//) {
171 my $was = $1;
172 if ($option->{parse_was_subject}) {
173 my %option;
174 for (keys %$option) {
175 $option{ '-'.$_ } = Message::Util::make_clone ($option->{ $_ });
176 }
177 $self->{was_subject} = ref ($self)->parse ($was,
178 -hook_decode_string => sub { shift; (value => shift, @_) },
179 %option);
180 } else {
181 $self->{was_subject} = $was;
182 }
183 }
184 if ($option->{use_message_from_subject} && $value =~ s/$REG{message_from_subject}//) {
185 $self->{is}->{message_from_subject} = 1;
186 }
187 $self->{value} = $value;
188 $self;
189 }
190
191 =back
192
193 =head1 METHODS
194
195 =over 4
196
197 =cut
198
199 sub value ($;$) {
200 my $self = shift;
201 my $v = shift;
202 if (defined $v) {
203 $self->{value} = $v;
204 }
205 $self->{value};
206 }
207
208 sub list_name ($) { $_[0]->{list_name} }
209 sub list_count ($) { $_[0]->{list_count} }
210
211 =item $body = $subject->stringify
212
213 Retruns subject field body as string. String is encoded
214 for message if necessary.
215
216 =cut
217
218 sub stringify ($;%) {
219 my $self = shift;
220 my %o = @_; my %option = %{$self->{option}};
221 for (grep {/^-/} keys %o) {$option{substr ($_, 1)} = $o{$_}}
222 if ($option{use_news_control} && $option{output_news_control}
223 && $self->{news_control}) {
224 my $c = $self->{news_control};
225 return '' unless length $c;
226 return sprintf $option{format_news_control}, $c;
227 }
228 if ($self->{_charset}) {
229 return $self->{value};
230 } else {
231 my $value = $self->{value};
232 if ($option{use_general_prefix} && $option{output_general_prefix}) {
233 $value = sprintf $option{format_prefix_re}, $value if $self->{is}->{reply};
234 $value = sprintf $option{format_prefix_fwd}, $value if $self->{is}->{foward};
235 }
236 if ($option{use_list_prefix} && $option{output_list_prefix}) {
237 $value = sprintf $option{format_prefix_list},
238 $self->{list_name}, $self->{list_count}, $value
239 if length $self->{list_name} && defined $self->{list_count};
240 }
241 if ($option{use_was_subject} && $option{output_was_subject} > 0) {
242 my $was;
243 if (ref $self->{was_subject}) {
244 my %opt = @_;
245 $opt{-output_was_subject} = $opt{output_was_subject}
246 unless defined $opt{-output_was_subject};
247 $opt{-output_was_subject}--;
248 $was = $self->{was_subject}->as_plain_string (%opt);
249 } elsif (length $self->{was_subject}) {
250 $was = $self->{was_subject};
251 }
252 $value = sprintf $option{format_was_subject}, $value, $was if defined $was;
253 }
254 my (%e) = &{$option{hook_encode_string}} ($self,
255 $value,
256 charset => $option{encoding_after_encode},
257 current_charset => $option{internal_charset},
258 type => 'text',
259 );
260 return $e{value};
261 }
262 }
263 *as_string = \&stringify;
264
265 =item $body = $subject->as_plain_string
266
267 Returns subject field body as string. Unlike C<stringify>,
268 retrun string of this method is not encoded (i.e. returned
269 in internal code).
270
271 =cut
272
273 sub as_plain_string ($;%) {
274 my $self = shift;
275 $self->stringify (
276 -hook_encode_string => sub { shift; (value => shift, @_) },
277 @_,
278 );
279 }
280
281
282
283 =item $bool = $subject->is ($attribute [=> $bool])
284
285 Set/gets attribute value.
286
287 Example:
288
289 $isreply = $subject->is ('re');
290 ## Strictly, this checks whether start with "Re: " or not.
291
292 $subject->is (foward => 1, re => 0);
293
294 =cut
295
296 sub is ($@) {
297 my $self = shift;
298 if (@_ == 1) {
299 my $query = shift;
300 if ($query eq 'advertisement') {
301 return $self->{value} =~ /$REG{prefix_advertisement}/x? 1:0;
302 } else {
303 return $self->{is}->{ $_[0] };
304 }
305 }
306 while (my ($name, $value) = splice (@_, 0, 2)) {
307 $self->{is}->{ $name } = $value;
308 }
309 }
310
311 =item $old_subject = $subject->was_subject
312
313 Returns I<was: > subject.
314
315 =cut
316
317 sub was_subject ($) {
318 my $self = shift;
319 $self->{was_subject} = $self->_parse_all (was => $self->{was_subject})
320 if $self->{option}->{parse_all};
321 $self->{was_subject};
322 }
323
324 sub news_control ($) {
325 my $self = shift;
326 $self->{news_control} = $self->_parse_all (was => $self->{news_control})
327 if $self->{option}->{parse_all};
328 $self->{news_control};
329 }
330
331 =item $clone = $subject->clone ()
332
333 Returns a copy of the object.
334
335 =cut
336
337 ## Inherited
338
339 =head1 LICENSE
340
341 Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
342
343 This program is free software; you can redistribute it and/or modify
344 it under the terms of the GNU General Public License as published by
345 the Free Software Foundation; either version 2 of the License, or
346 (at your option) any later version.
347
348 This program is distributed in the hope that it will be useful,
349 but WITHOUT ANY WARRANTY; without even the implied warranty of
350 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
351 GNU General Public License for more details.
352
353 You should have received a copy of the GNU General Public License
354 along with this program; see the file COPYING. If not, write to
355 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
356 Boston, MA 02111-1307, USA.
357
358 =head1 CHANGE
359
360 See F<ChangeLog>.
361 $Date: 2002/11/13 08:08:52 $
362
363 =cut
364
365 1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24