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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (hide annotations) (download)
Sun Jun 23 12:10:16 2002 UTC (22 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.13: +67 -42 lines
2002-06-23  Wakaba <w@suika.fam.cx>

	* AngleQuoted.pm (%REG): Don't define regex locally.
	(Moved to Message::Util).
	* ContentType.pm, Date.pm, UA.pm,
	ValueParams.pm: Fix some codes not to be warned
	as 'Use of uninitialized value'.
	* Structured.pm 
	(header_default_charset, header_default_charset_input):
	New options.

1 wakaba 1.1
2     =head1 NAME
3    
4 wakaba 1.7 Message::Field::Params --- Perl module for Internet message
5     field body consist of parameters, such as C<Content-Type:> field
6 wakaba 1.1
7     =cut
8    
9     package Message::Field::Params;
10     use strict;
11     require 5.6.0;
12     use re 'eval';
13 wakaba 1.14 use vars qw(%DEFAULT @ISA %REG $VERSION);
14     $VERSION=do{my @r=(q$Revision: 1.13 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
15 wakaba 1.3 require Message::Util;
16 wakaba 1.7 require Message::Field::Structured;
17     push @ISA, qw(Message::Field::Structured);
18    
19     use overload '""' => sub { $_[0]->stringify },
20     '0+' => sub { $_[0]->count },
21     '.=' => sub { $_[0]->add ($_[1], ['', value => 1]); $_[0] },
22     fallback => 1;
23    
24 wakaba 1.14 %REG = %Message::Util::REG;
25 wakaba 1.7 ## Inherited: comment, quoted_string, domain_literal, angle_quoted
26     ## WSP, FWS, atext, atext_dot, token, attribute_char
27     ## S_encoded_word
28     ## M_quoted_string
29 wakaba 1.1
30 wakaba 1.7 $REG{param} = qr/(?:$REG{atext_dot}|$REG{quoted_string}|$REG{angle_quoted})(?:$REG{atext_dot}|$REG{quoted_string}|$REG{WSP}|,)*/;
31 wakaba 1.8 $REG{param_nocomma} = qr/(?:$REG{atext_dot}|$REG{quoted_string}|$REG{angle_quoted})(?:$REG{atext_dot}|$REG{quoted_string}|$REG{WSP})*/;
32 wakaba 1.1 ## more naive C<parameter>. (Comma is allowed for RFC 1049)
33 wakaba 1.9 $REG{param_free} = qr/(?:[^\x09\x20\x22\x3B\x3C]|$REG{quoted_string}|$REG{angle_quoted})(?:[^\x22\x3B\x3C]|$REG{quoted_string})*/;
34 wakaba 1.1 $REG{parameter} = qr/$REG{token}=(?:$REG{token}|$REG{quoted_string})?/;
35     ## as defined by RFC 2045, not RFC 2231.
36    
37 wakaba 1.9 #$REG{M_parameter} = qr/($REG{token})=($REG{token}|$REG{quoted_string})?/;
38     $REG{M_parameter} = qr/($REG{token})=($REG{quoted_string}|[^\x22]*)/;
39 wakaba 1.1 ## as defined by RFC 2045, not RFC 2231.
40     $REG{M_parameter_name} = qr/($REG{attribute_char}+)(?:\*([0-9]+)(\*)?|(\*))/;
41     ## as defined by RFC 2231.
42     $REG{M_parameter_extended_value} = qr/([^']*)'([^']*)'($REG{token}*)/;
43     ## as defined by RFC 2231, but more naive.
44    
45 wakaba 1.14 %DEFAULT = (
46     -_HASH_NAME => 'param',
47 wakaba 1.9 -delete_fws => 1,## BUG: this option MUST be '1'.
48     ## parameter parser cannot procede CFWS.
49 wakaba 1.10 #encoding_after_encode
50     #encoding_before_decode
51     #field_param_name
52     #field_name
53     #format
54     #hook_encode_string
55     #hook_decode_string
56 wakaba 1.8 -parameter_rule => 'param',
57 wakaba 1.7 -parameter_name_case_sensible => 0,
58 wakaba 1.13 -parameter_value_max_length => 60,
59     -parameter_value_split_length => 35,
60 wakaba 1.7 -parameter_value_unsafe_rule => {'*default' => 'NON_http_attribute_char'},
61     -parse_all => 0,
62 wakaba 1.8 -separator => '; ',
63     -separator_regex => qr/$REG{FWS};$REG{FWS}/,
64 wakaba 1.14 -use_comment => 1,
65 wakaba 1.7 -use_parameter_extension => 0,
66 wakaba 1.10 #value_type
67 wakaba 1.14 );
68    
69     =head1 CONSTRUCTORS
70    
71     The following methods construct new objects:
72    
73     =over 4
74    
75     =cut
76    
77     ## Initialize of this class -- called by constructors
78     sub _init ($;%) {
79     my $self = shift;
80     my %options = @_;
81 wakaba 1.7 $self->SUPER::_init (%DEFAULT, %options);
82     $self->{param} = [];
83 wakaba 1.11 my $fname = $self->{option}->{field_name};
84 wakaba 1.8 if ($fname eq 'p3p') {
85     $self->{option}->{parameter_rule} = 'param_nocomma';
86     $self->{option}->{separator} = ', ';
87     $self->{option}->{separator_regex} = qr/$REG{FWS},$REG{FWS}/;
88     }
89 wakaba 1.7 if ($self->{option}->{format} =~ /^http-sip/) {
90     $self->{option}->{encoding_before_decode} = 'utf-8';
91     $self->{option}->{encoding_after_decode} = 'utf-8';
92     } elsif ($self->{option}->{format} =~ /^http/) {
93     $self->{option}->{encoding_before_decode} = 'iso-8859-1';
94     $self->{option}->{encoding_after_decode} = 'iso-8859-1';
95 wakaba 1.14 } ## TODO: news-usefor -> x-junet8
96 wakaba 1.7 }
97    
98     =item $p = Message::Field::Params->new ([%options])
99    
100     Constructs a new object. You might pass some options as parameters
101     to the constructor.
102    
103     =cut
104    
105 wakaba 1.14 ## Inherited
106 wakaba 1.1
107 wakaba 1.7 =item $p = Message::Field::Params->parse ($field-body, [%options])
108 wakaba 1.1
109 wakaba 1.7 Constructs a new object with given field body. You might pass
110     some options as parameters to the constructor.
111 wakaba 1.1
112     =cut
113    
114     sub parse ($$;%) {
115     my $class = shift;
116 wakaba 1.7 my $self = bless {}, $class;
117 wakaba 1.1 my $body = shift;
118 wakaba 1.7 $self->_init (@_);
119 wakaba 1.14 $body = Message::Util::delete_comment ($body)
120     if $self->{option}->{use_comment};
121 wakaba 1.7 $body = $self->_delete_fws ($body) if $self->{option}->{delete_fws};
122 wakaba 1.1 my @b = ();
123 wakaba 1.8 $body =~ s{$REG{FWS}($REG{$self->{option}->{parameter_rule}})
124     (?:$self->{option}->{separator_regex}|$)}{
125 wakaba 1.1 my $param = $1;
126     push @b, $self->_parse_param ($param);
127     }goex;
128     @b = $self->_restore_param (@b);
129     $self->_save_param (@b);
130     $self;
131     }
132    
133     sub _parse_param ($$) {
134     my $self = shift;
135     my $param = shift;
136     if ($param =~ /^$REG{M_parameter}$/) {
137 wakaba 1.7 my ($name, $value) = ($self->_n11n_param_name ($1), $2);
138 wakaba 1.1 my ($seq, $isencoded, $charset, $lang) = (-1, 0, '', '');
139     if ($name =~ /^$REG{M_parameter_name}$/) {
140     ($name, $seq, $isencoded) = ($1, $4?-1:$2, ($3||$4)?1:0);
141     }
142     if ($isencoded && $value =~ /^$REG{M_parameter_extended_value}$/) {
143     ($charset, $lang, $value) = ($1, $2, $3);
144     }
145     return [$name, {value => $value, seq => $seq, is_encoded => $isencoded,
146     charset => $charset, language => $lang, is_parameter => 1}];
147     } else {
148     return [$param, {is_parameter => 0}];
149     }
150     }
151    
152     sub _restore_param ($@) {
153     my $self = shift;
154     my @p = @_;
155     my @ret;
156     my %part;
157     for my $i (@p) {
158     if ($i->[1]->{is_parameter}) {
159     my $p = $i->[1];
160     if ($p->{seq}<0) {
161     my $s = $p->{value};
162     if ($p->{is_encoded}) {
163     $s =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/chr(hex($1))/eg;
164 wakaba 1.3 my %s = &{$self->{option}->{hook_decode_string}} ($self, $s,
165     language => $p->{language}, charset => $p->{charset},
166     type => 'parameter/encoded');
167 wakaba 1.14 if ($p->{charset} && !$s{charset}) {
168     $p->{charset_to_be} = $p->{charset}; ## Original charset
169     }
170 wakaba 1.3 ($s, $p->{charset}, $p->{language}) = (@s{qw(value charset language)});
171 wakaba 1.9 } elsif ($p->{is_internal}) {
172     $s = $p->{value};
173 wakaba 1.1 } else {
174 wakaba 1.3 my $q = 0;
175 wakaba 1.7 ($s,$q) = Message::Util::unquote_if_quoted_string ($p->{value});
176 wakaba 1.3 my %s = &{$self->{option}->{hook_decode_string}} ($self, $s,
177     type => ($q?'parameter/quoted':'parameter'));
178     ($s, $p->{charset}, $p->{language}) = (@s{qw(value charset language)});
179 wakaba 1.1 }
180     push @ret, [$i->[0], {value => $s, language => $p->{language},
181 wakaba 1.14 charset => $p->{charset},
182     charset_to_be => $p->{charset_to_be},
183     is_parameter => 1}];
184 wakaba 1.1 } else {
185     $part{$i->[0]}->[$p->{seq}] = {
186 wakaba 1.7 value => scalar Message::Util::unquote_if_quoted_string ($p->{value}),
187 wakaba 1.1 language => $p->{language}, charset => $p->{charset},
188     is_encoded => $p->{is_encoded}};
189     }
190 wakaba 1.3 } else {
191 wakaba 1.9 #my $q = 0;
192     #($i->[0], $q) = Message::Util::unquote_if_quoted_string ($i->[0]);
193     #my %s = &{$self->{option}->{hook_decode_string}} ($self, $i->[0],
194     # type => ($q?'phrase/quoted':'phrase'));
195     push @ret, [Message::Util::decode_quoted_string ($self, $i->[0]),
196     {is_parameter => 0}];
197 wakaba 1.3 }
198 wakaba 1.1 }
199     for my $name (keys %part) {
200     my $t = join '', map {
201     my $v = $_;
202     my $s = $v->{value};
203     $s =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/chr(hex($1))/eg if $v->{is_encoded};
204     $s;
205     } @{$part{$name}};
206 wakaba 1.3 my %s = &{$self->{option}->{hook_decode_string}} ($self, $t,
207     type => 'parameter/encoded');
208 wakaba 1.14 if ($part{$name}->[0]->{charset} && !$s{charset}) { ## Original charset
209     $part{$name}->[0]->{charset_to_be} = $part{$name}->[0]->{charset};
210     }
211     ($t,@{$part{$name}->[0]}{qw(charset language)})=(@s{qw(value charset language)});
212 wakaba 1.1 push @ret, [$name, {value => $t, charset => $part{$name}->[0]->{charset},
213 wakaba 1.14 charset_to_be => $part{$name}->[0]->{charset_to_be},
214 wakaba 1.1 language => $part{$name}->[0]->{language},
215     is_parameter => 1}];
216     }
217     @ret;
218     }
219    
220 wakaba 1.11 ## $self->_save_param (@parameters)
221     ## --- Save parameter values to $self
222 wakaba 1.1 sub _save_param ($@) {
223     my $self = shift;
224 wakaba 1.11 my @p = @_;
225     $self->_parse_param_value (\@p) if $self->{option}->{parse_all};
226     $self->{param} = \@p;
227     $self;
228     }
229     *__save_param = \&_save_param; ## SHOULD NOT BE OVERRIDDEN!
230    
231     ## $self->_parse_param_value (\@parameters)
232     ## --- Parse each values of parameters
233     sub _parse_param_value ($\@) {
234     my $self = shift;
235     my $p = shift;
236     @$p = map {
237     if ($_->[1]->{is_parameter}) {
238 wakaba 1.9 $_->[1]->{value} = $self->_parse_value ($_->[0] => $_->[1]->{value});
239     }
240     $_;
241 wakaba 1.11 } @$p;
242     #$p;
243 wakaba 1.1 }
244    
245 wakaba 1.7 =back
246    
247     =head1 METHODS
248    
249     =over 4
250    
251     =item $p->add ($name => [$value], [$name => $value,...])
252 wakaba 1.1
253     Adds parameter name=value pair.
254    
255     Example:
256 wakaba 1.7 $p->add (title => 'foo of bar'); ## title="foo of bar"
257     $p->add (subject => 'hogehoge, foo'); ## subject*=''hogehoge%2C%20foo
258     $p->add (foo => ['bar', language => 'en']) ## foo*='en'bar
259     $p->add ('text/plain', ['', value => 1]) ## text/plain
260 wakaba 1.1
261     This method returns array reference of (name, {value => value, attribute...}).
262    
263     Available options: charset (charset name), language (language tag),
264     value (1/0, see example above).
265    
266     =cut
267    
268 wakaba 1.14 sub _add_hash_check ($$$\%) {
269     my $self = shift;
270     my ($name, $value, $option) = @_;
271     my $value_option = {};
272     if (ref $value eq 'ARRAY') {
273     ($value, %$value_option) = @$value;
274     }
275     if ($value_option->{value}) { ## Non-value parameter
276     $name = $self->_parse_value ('*novalue' => $name) if $$option{parse};
277     return (1, $name => [$name, {is_parameter => 0}]);
278     }
279     if ($$option{validate} && !$value_option->{value}
280     && $name =~ /^$REG{NON_http_attribute_char}$/) {
281     if ($$option{dont_croak}) {
282     return (0);
283     } else {
284     Carp::croak qq{add: $name: Invalid parameter name};
285     }
286     $value = $self->_parse_value ($name => $value) if $$option{parse};
287     }
288     (1, $name => [$name => {value => $value, is_parameter => 1,
289     charset_to_be => $value_option->{charset},
290     language => $value_option->{language},
291     }]);
292     }
293    
294    
295     sub Xadd ($$;$%) {
296 wakaba 1.1 my $self = shift;
297 wakaba 1.7 my %gp = @_;
298     my %option = %{$self->{option}};
299     for (grep {/^-/} keys %gp) {$option{substr ($_, 1)} = $gp{$_}}
300     $option{parse} = 1 if defined wantarray;
301     my $p;
302     for (grep {/^[^-]/} keys %gp) {
303     my ($name, $value, %po) = ($self->_n11n_param_name ($_));
304     if (ref $gp{$_}) {($value, %po) = @{$gp{$_}}} else {$value = $gp{$_}}
305     $p = [$name, {value => $value, charset => $po{charset},
306     is_parameter => 1, language => $po{language}}];
307     $p->[1]->{is_parameter} = 0 if !$value && $po{value};
308     Carp::croak "add: \$name contains of non-attribute-char: $name"
309     if $p->[1]->{is_parameter} && $name =~ /$REG{NON_http_attribute_char}/;
310 wakaba 1.9 $p->[1]->{value} = $self->_parse_value ($name => $p->[1]->{value})
311 wakaba 1.7 if $option{parse};
312     if ($option{prepend}) {
313     unshift @{$self->{param}}, $p;
314     } else {
315     push @{$self->{param}}, $p;
316     }
317 wakaba 1.1 }
318 wakaba 1.7 $p->[1]->{is_parameter}? $p->[1]->{value}: $p->[0];
319 wakaba 1.1 }
320 wakaba 1.7
321     sub replace ($%) {
322 wakaba 1.1 my $self = shift;
323 wakaba 1.7 my %gp = @_;
324     my %option = %{$self->{option}};
325     for (grep {/^-/} keys %gp) {$option{substr ($_, 1)} = $gp{$_}}
326     $option{parse} = 1 if defined wantarray;
327     my $p;
328     for (grep {/^[^-]/} keys %gp) {
329     my ($name, $value, %po) = ($self->_n11n_param_name ($_));
330 wakaba 1.12 if (ref $gp{$_} eq 'ARRAY') {($value, %po) = @{$gp{$_}}} else {$value = $gp{$_}}
331 wakaba 1.7 $p = [$name, {value => $value, charset => $po{charset},
332     is_parameter => 1, language => $po{language}}];
333 wakaba 1.8 $p->[1]->{is_parameter} = 0 if !defined ($value) && $po{value};
334 wakaba 1.7 Carp::croak "replace: \$name contains of non-attribute-char: $name"
335     if $p->[1]->{is_parameter} && $name =~ /$REG{NON_http_attribute_char}/;
336 wakaba 1.9 $p->[1]->{value} = $self->_parse_value ($name => $p->[1]->{value})
337 wakaba 1.7 if $option{parse};
338     my $f = 0;
339     for my $param (@{$self->{param}}) {
340     if ($param->[0] eq $name) {$param = $p; $f = 1}
341 wakaba 1.1 }
342 wakaba 1.7 push @{$self->{param}}, $p unless $f == 1;
343 wakaba 1.1 }
344 wakaba 1.7 $p->[1]->{is_parameter}? $p->[1]->{value}: $p->[0];
345 wakaba 1.1 }
346    
347 wakaba 1.8 ## TODO: multiple parameters support
348 wakaba 1.1 sub delete ($$;%) {
349     my $self = shift;
350 wakaba 1.7 my ($name, $index) = ($self->_n11n_param_name (shift), shift);
351 wakaba 1.1 my $i = 0;
352     for my $param (@{$self->{param}}) {
353     if ($param->[0] eq $name) {
354     $i++;
355     if ($index == 0 || $i == $index) {
356     undef $param;
357     return $self if $i == $index;
358     }
359     }
360     }
361     $self;
362     }
363    
364     sub count ($;$%) {
365     my $self = shift;
366 wakaba 1.7 my $name = $self->_n11n_param_name (shift);
367 wakaba 1.1 unless ($name) {
368     $self->_delete_empty ();
369     return $#{$self->{param}}+1;
370     }
371     my $count = 0;
372     for my $param (@{$self->{param}}) {
373     if ($param->[0] eq $name) {
374     $count++;
375     }
376     }
377     $count;
378     }
379    
380    
381 wakaba 1.7 sub parameter ($$;$%) {
382 wakaba 1.1 my $self = shift;
383 wakaba 1.7 my $name = $self->_n11n_param_name (shift);
384 wakaba 1.1 my $newvalue = shift;
385 wakaba 1.7 return $self->replace ($name => $newvalue,@_) if defined $newvalue;
386 wakaba 1.1 my @ret;
387     for my $param (@{$self->{param}}) {
388     if ($param->[0] eq $name) {
389     unless (wantarray) {
390 wakaba 1.3 $param->[1]->{value}
391 wakaba 1.9 = $self->_parse_value ($name => $param->[1]->{value});
392 wakaba 1.1 return $param->[1]->{value};
393     } else {
394 wakaba 1.3 $param->[1]->{value}
395 wakaba 1.9 = $self->_parse_value ($name => $param->[1]->{value});
396 wakaba 1.1 push @ret, $param->[1]->{value};
397     }
398     }
399     }
400 wakaba 1.14 wantarray? @ret: undef;
401 wakaba 1.1 }
402    
403     sub parameter_name ($$;$) {
404     my $self = shift;
405     my $i = shift;
406     my $newname = shift;
407     if ($newname) {
408 wakaba 1.4 return 0 if $newname =~ /$REG{NON_http_attribute_char}/;
409 wakaba 1.1 $self->{param}->[$i]->[0] = $newname;
410     }
411     $self->{param}->[$i]->[0];
412     }
413     sub parameter_value ($$;$) {
414     my $self = shift;
415     my $i = shift;
416     my $newvalue = shift;
417     if ($newvalue) {
418 wakaba 1.9 $newvalue = $self->_parse_value ($self->{param}->[$i]->[0] => $newvalue);
419 wakaba 1.1 $self->{param}->[$i]->[1]->{value} = $newvalue;
420     }
421     $self->{param}->[$i]->[1]->{value}
422 wakaba 1.9 = $self->_parse_value
423 wakaba 1.1 ($self->{param}->[$i]->[0] => $self->{param}->[$i]->[1]->{value});
424     $self->{param}->[$i]->[1]->{value};
425     }
426    
427    
428     sub _delete_empty ($) {
429     my $self = shift;
430 wakaba 1.11 $self->{param} = [grep {ref $_} @{$self->{param}}];
431 wakaba 1.1 }
432    
433    
434 wakaba 1.7 =item $field-body = $p->stringify ()
435 wakaba 1.1
436 wakaba 1.7 Returns C<field-body> as a string.
437 wakaba 1.1
438     =cut
439    
440     sub stringify ($;%) {
441     my $self = shift;
442 wakaba 1.7 my %o = @_;
443     my %option = %{$self->{option}};
444     for (grep {/^-/} keys %o) {$option{substr ($_, 1)} = $o{$_}}
445     $self->_delete_empty;
446 wakaba 1.9 my @ret = ();
447     $self->scan (sub {
448     my $self = shift;
449     my ($n => $v) = @_[0 => 2]; #$_->[1];
450     return unless $self->_stringify_params_check (@_[0 => 2]);
451 wakaba 1.1 my $new = '';
452     if ($v->{is_parameter}) {
453     my ($encoded, @value) = (0, '');
454 wakaba 1.3 my (%e) = &{$self->{option}->{hook_encode_string}} ($self,
455 wakaba 1.14 $v->{value}, charset => $v->{charset_to_be},
456     current_charset => $v->{charset}, language => $v->{language},
457 wakaba 1.3 type => 'parameter');
458 wakaba 1.11 if (!defined $e{value}) {
459 wakaba 1.8 $value[0] = undef;
460     } elsif ($option{use_parameter_extension} && ($e{charset} || $e{language}
461 wakaba 1.3 || $e{value} =~ /[\x00\x0D\x0A\x80-\xFF]/)) {
462 wakaba 1.1 my ($charset, $lang);
463     $encoded = 1;
464 wakaba 1.3 ($charset, $lang) = ($e{charset}, $e{language});
465 wakaba 1.1 ## Note: %-quoting for charset and for language is not allowed.
466     ## But charset name can be included non-sttribute-char such as "'".
467     ## How can we treat this?
468 wakaba 1.4 $charset =~ s/($REG{NON_http_attribute_char})/sprintf('%%%02X', ord $1)/ge;
469     $lang =~ s/($REG{NON_http_attribute_char})/sprintf('%%%02X', ord $1)/ge;
470 wakaba 1.7 if (length $e{value} > $option{parameter_value_max_length}) {
471 wakaba 1.13 for my $i (0..length ($e{value})/$option{parameter_value_split_length}) {
472     $value[$i] = substr ($e{value},
473     $i*$option{parameter_value_split_length},
474     $option{parameter_value_split_length});
475 wakaba 1.1 }
476 wakaba 1.3 } else {$value[0] = $e{value}}
477 wakaba 1.1 for my $i (0..$#value) {
478 wakaba 1.4 $value[$i] =~
479     s/($REG{NON_http_attribute_char})/sprintf('%%%02X', ord $1)/ge;
480 wakaba 1.1 }
481     $value[0] = "${charset}'${lang}'".$value[0];
482 wakaba 1.3 } elsif (length $e{value} == 0) {
483 wakaba 1.1 $value[0] = '""';
484     } else {
485 wakaba 1.7 if ($option{use_parameter_extension}
486     && length $e{value} > $option{parameter_value_max_length}) {
487 wakaba 1.13 for my $i (0..length ($e{value})/$option{parameter_value_split_length}) {
488 wakaba 1.7 $value[$i] = Message::Util::quote_unsafe_string
489 wakaba 1.13 (substr ($e{value}, $i*$option{parameter_value_split_length},
490     $option{parameter_value_split_length}),
491 wakaba 1.4 unsafe => 'NON_http_attribute_char');
492 wakaba 1.1 }
493     } else {
494 wakaba 1.9 my $unsafe = $self->{option}->{parameter_value_unsafe_rule}->{$n}
495 wakaba 1.7 || $self->{option}->{parameter_value_unsafe_rule}->{'*default'};
496     $value[0] = Message::Util::quote_unsafe_string
497     ($e{value}, unsafe => $unsafe);
498 wakaba 1.1 }
499     }
500     ## Note: quoted-string for parameter name is not allowed.
501     ## But it is better than output bare non-atext.
502     if ($#value == 0) {
503     $new =
504 wakaba 1.9 Message::Util::quote_unsafe_string ($n,
505 wakaba 1.7 unsafe => 'NON_attribute_char')
506 wakaba 1.8 .($encoded?'*':'').'='.$value[0]
507     if defined $value[0];
508 wakaba 1.1 } else {
509     my @new;
510 wakaba 1.7 my $name = Message::Util::quote_unsafe_string
511 wakaba 1.9 ($n, unsafe => 'NON_http_attribute_char');
512 wakaba 1.1 for my $i (0..$#value) {
513     push @new, $name.'*'.$i.($encoded?'*':'').'='.$value[$i];
514     }
515 wakaba 1.11 $new = join $self->{option}->{separator}, @new;
516 wakaba 1.1 }
517     } else {
518 wakaba 1.3 my %e = &{$self->{option}->{hook_encode_string}} ($self,
519 wakaba 1.9 $n, type => 'phrase');
520 wakaba 1.7 $new = Message::Util::quote_unsafe_string ($e{value},
521 wakaba 1.4 unsafe => 'NON_http_token_wsp');
522 wakaba 1.1 }
523 wakaba 1.11 push @ret, $new if length $new;
524 wakaba 1.9 });
525     join $self->{option}->{separator}, @ret;
526 wakaba 1.1 }
527 wakaba 1.7 *as_string = \&stringify;
528 wakaba 1.1
529 wakaba 1.9 sub _stringify_params_check ($$$) {
530     my $self = shift;
531     my ($name, $value) = @_;
532     1;
533     }
534    
535 wakaba 1.7 sub scan ($&) {
536     my ($self, $sub) = @_;
537     #my $sort;
538     #$sort = \&_header_cmp if $self->{option}->{sort} eq 'good-practice';
539     #$sort = {$a cmp $b} if $self->{option}->{sort} eq 'alphabetic';
540     my @param = @{$self->{param}};
541     #if (ref $sort) {
542     # @field = sort $sort @{$self->{param}};
543     #}
544     for my $param (@param) {
545 wakaba 1.9 &$sub($self, $param->[0] => $param->[1]->{value}, $param->[1]);
546 wakaba 1.7 }
547     }
548    
549 wakaba 1.8 =item $option-value = $p->option ($option-name)
550 wakaba 1.1
551 wakaba 1.7 Gets option value.
552    
553 wakaba 1.8 =item $p->option ($option-name, $option-value, ...)
554 wakaba 1.7
555     Set option value(s). You can pass multiple option name-value pair
556     as parameter when setting.
557 wakaba 1.1
558     =cut
559    
560 wakaba 1.7 sub option ($;$%) {
561 wakaba 1.1 my $self = shift;
562 wakaba 1.7 my $format = $self->{option}->{format};
563     $self->SUPER::option (@_);
564     if ($format ne $self->{option}->{format}) {
565     $self->scan (sub {
566     if (ref $_[1]) {
567     $_[1]->option (-format => $self->{option}->{format});
568     }
569     });
570 wakaba 1.1 }
571     }
572    
573 wakaba 1.9 ## value_type: Inherited
574 wakaba 1.1
575 wakaba 1.7 sub value_unsafe_rule ($$;$%) {
576 wakaba 1.1 my $self = shift;
577 wakaba 1.7 if (@_ == 1) {
578     return $self->{option}->{parameter_value_unsafe_rule}->{ $_[0] };
579     }
580     while (my ($name, $value) = splice (@_, 0, 2)) {
581     $name = $self->_n11n_param_name ($name);
582     $self->{option}->{parameter_value_unsafe_rule}->{$name} = $value;
583     }
584 wakaba 1.1 }
585    
586 wakaba 1.8 =item $clone = $p->clone ()
587 wakaba 1.1
588 wakaba 1.7 Returns a copy of the object.
589 wakaba 1.1
590     =cut
591    
592 wakaba 1.7 sub clone ($) {
593 wakaba 1.1 my $self = shift;
594 wakaba 1.7 $self->_delete_empty;
595     my $clone = $self->SUPER::clone;
596     $clone->{param} = Message::Util::make_clone ($self->{param});
597     $clone->{value_type} = Message::Util::make_clone ($self->{value_type});
598     $clone;
599 wakaba 1.1 }
600    
601     sub _delete_fws ($$) {
602     my $self = shift;
603     my $body = shift;
604 wakaba 1.3 $body =~ s{($REG{quoted_string}|$REG{domain_literal})|((?:$REG{token}|$REG{S_encoded_word})(?:$REG{WSP}+(?:$REG{token}|$REG{S_encoded_word}))+)|$REG{WSP}+}{
605     my ($o,$p) = ($1,$2);
606     if ($o) {$o}
607     elsif ($p) {$p=~s/$REG{WSP}+/\x20/g;$p}
608     else {''}
609 wakaba 1.1 }gex;
610     $body;
611     }
612    
613 wakaba 1.7 sub _n11n_param_name ($$) {
614     my $self = shift;
615     my $s = shift;
616     $s = lc $s unless $self->{option}->{parameter_name_case_sensible};
617     $s;
618     }
619    
620 wakaba 1.1 =head1 LICENSE
621    
622     Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
623    
624     This program is free software; you can redistribute it and/or modify
625     it under the terms of the GNU General Public License as published by
626     the Free Software Foundation; either version 2 of the License, or
627     (at your option) any later version.
628    
629     This program is distributed in the hope that it will be useful,
630     but WITHOUT ANY WARRANTY; without even the implied warranty of
631     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
632     GNU General Public License for more details.
633    
634     You should have received a copy of the GNU General Public License
635     along with this program; see the file COPYING. If not, write to
636     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
637     Boston, MA 02111-1307, USA.
638    
639     =head1 CHANGE
640    
641     See F<ChangeLog>.
642 wakaba 1.14 $Date: 2002/06/16 10:42:06 $
643 wakaba 1.1
644     =cut
645    
646     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24