File Coverage

blib/lib/MIME/EcoEncode/Param.pm
Criterion Covered Total %
statement 243 379 64.1
branch 107 220 48.6
condition 12 27 44.4
subroutine 7 7 100.0
pod 0 4 0.0
total 369 637 57.9


line stmt bran cond sub pod time code
1             # Copyright (C) 2013 MURATA Yasuhisa
2             # This program is free software; you can redistribute it and/or
3             # modify it under the same terms as Perl itself.
4              
5             package MIME::EcoEncode::Param;
6              
7 1     1   22379 use 5.008005;
  1         4  
  1         38  
8 1     1   6 use strict;
  1         2  
  1         40  
9 1     1   11 use warnings;
  1         2  
  1         5352  
10              
11             require Exporter;
12              
13             our @ISA = qw(Exporter);
14             our @EXPORT_OK = qw($VERSION);
15             our @EXPORT = qw(mime_eco_param mime_deco_param);
16             our $VERSION = '0.95';
17              
18             our $HEAD; # head string
19             our $HTL; # head + tail length
20             our $LF; # line feed
21             our $BPL; # bytes per line
22             our $UTF8;
23             our $REG_W;
24              
25             sub mime_eco_param {
26 9     9 0 18617 my $str = shift;
27              
28 9 100       29 return '' unless defined $str;
29 8 100       22 return '' if $str eq '';
30              
31 7         42 my ($trailing_crlf) = ($str =~ /(\x0d?\x0a|\x0d)$/);
32 7         15 $str =~ tr/\n\r//d;
33 7 100       28 if ($str =~ /^\s*$/) {
34 1 50       7 return $trailing_crlf ? $str . $trailing_crlf : $str;
35             }
36              
37 6   100     24 my $charset = shift || 'UTF-8';
38              
39 6         7 our $HEAD; # head string
40              
41 6         8 my $cs;
42             my $type; # 0: RFC 2231, 1: "Q", 2: "B"
43 6 50       29 if ($charset =~ /^([-0-9A-Za-z_]+)(\'[^\']*\')?$/i) {
    0          
44 6         16 $cs = lc($1);
45 6         8 $type = 0;
46 6 100       20 $HEAD = $2 ? $charset : $charset . "''";
47             }
48             elsif ($charset =~ /^([-0-9A-Za-z_]+)(\*[^\?]*)?(\?[QB])?$/i) {
49 0         0 $cs = lc($1);
50 0 0       0 if (defined $3) {
51 0 0       0 $type = (lc($3) eq '?q') ? 1 : 2;
52 0         0 $HEAD = '=?' . $charset . '?';
53             }
54             else {
55 0         0 $type = 2;
56 0         0 $HEAD = '=?' . $charset . '?B?';
57             }
58             }
59             else { # invalid option
60 0         0 return undef;
61             }
62              
63 6         8 our $HTL; # head + tail length
64 6   100     21 our $LF = shift || "\n"; # line feed
65 6   100     16 our $BPL = shift || 76; # bytes per line
66 6         8 our $UTF8 = 1;
67 6         23 our $REG_W = qr/(.)/;
68              
69 6         11 my $jp = 0;
70 6         7 my $np;
71              
72 6         8 $HTL = length($HEAD) + 2;
73              
74 6 100       14 if ($cs ne 'utf-8') {
75 2         3 $UTF8 = 0;
76 2 100       9 if ($cs eq 'iso-2022-jp') {
    50          
    0          
    0          
    0          
77 1         3 $jp = 1;
78             }
79             elsif ($cs eq 'shift_jis') {
80             # range of 2nd byte : [\x40-\x7e\x80-\xfc]
81 1         3 $REG_W = qr/([\x81-\x9f\xe0-\xfc]?.)/;
82             }
83             elsif ($cs eq 'gb2312') { # Simplified Chinese
84             # range of 2nd byte : [\xa1-\xfe]
85 0         0 $REG_W = qr/([\xa1-\xfe]?.)/;
86             }
87             elsif ($cs eq 'euc-kr') { # Korean
88             # range of 2nd byte : [\xa1-\xfe]
89 0         0 $REG_W = qr/([\xa1-\xfe]?.)/;
90             }
91             elsif ($cs eq 'big5') { # Traditional Chinese
92             # range of 2nd byte : [\x40-\x7e\xa1-\xfe]
93 0         0 $REG_W = qr/([\x81-\xfe]?.)/;
94             }
95             else { # Single Byte (Latin, Cyrillic, ...)
96             ;
97             }
98             }
99              
100 6         21 $str =~ s/^(\s*)//; # leading whitespace
101 6         12 my $sps = $1;
102 6         16 my ($param, $value) = split('=', $str, 2);
103              
104 6 100       13 unless (defined $value) {
105 3 50       15 return $trailing_crlf ? $str . $trailing_crlf : $str;
106             }
107              
108 3         4 my $quote = 0;
109              
110 3 50       10 if ($value =~ s/^\s*"(.*)"$/$1/) {
111 0         0 $quote = 1;
112             }
113 3 50       7 if ($value eq '') {
114 0 0       0 return $trailing_crlf ? $str . $trailing_crlf : $str;
115             }
116              
117 3         6 my $result = "$sps$param=";
118 3         4 my $v_len = length($value);
119 3         4 my $ll_len = length($result);
120              
121 3 50 33     16 if (!$quote && $value !~ /[^\w!#\$&\+-\.\^`\{\|}~]/) { # regular token
122 0 0 0     0 if ($type or $ll_len + $v_len <= $BPL) {
123 0         0 $result .= $value;
124 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
125             }
126              
127 0         0 my $n = 0;
128 0         0 my $c;
129             my $p_str;
130              
131 0         0 $result = "$sps$param\*0=";
132 0         0 $ll_len += 2;
133 0         0 while ($value =~ /(.)/g) {
134 0         0 $c = $1;
135 0 0       0 if ($ll_len + 1 > $BPL) {
136 0         0 $n++;
137 0         0 $p_str = " $param\*$n=";
138 0         0 $result .= "$LF$p_str$c";
139 0         0 $ll_len = 1 + length($p_str);
140             }
141             else {
142 0         0 $result .= $c;
143 0         0 $ll_len++;
144             }
145             }
146 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
147             }
148 3 50 33     9 if ($quote && $value !~ /[^\t\x20-\x7e]/) { # regular quoted-string
149 0 0 0     0 if ($type or $ll_len + $v_len + 2 <= $BPL) {
150 0         0 $result .= "\"$value\"";
151 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
152             }
153              
154 0         0 my $n = 0;
155 0         0 my $vc;
156             my $vc_len;
157 0         0 my $p_str;
158              
159 0         0 $result = "$sps$param\*0=\"";
160 0         0 $ll_len += 3;
161 0         0 while ($value =~ /(\\.|.)/g) {
162 0         0 $vc = $1;
163 0         0 $vc_len = length($vc);
164 0 0       0 if ($ll_len + $vc_len + 1 > $BPL) {
165 0         0 $n++;
166 0         0 $p_str = " $param\*$n=\"";
167 0         0 $result .= "\"$LF$p_str$vc";
168 0         0 $ll_len = $vc_len + length($p_str);
169             }
170             else {
171 0         0 $result .= $vc;
172 0         0 $ll_len += $vc_len;
173             }
174             }
175 0         0 $result .= '"';
176 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
177             }
178              
179             #
180             # extended parameter (contain regular parameter)
181             #
182              
183 3 100       6 if ($jp) {
184 1 50       4 if ($type == 0) {
185 1         6 return param_enc_jp($param, $value, $sps, $trailing_crlf, $quote);
186             }
187              
188 0 0       0 if ($type == 1) { # "Q" encoding
189 0         0 require MIME::EcoEncode::JP_Q;
190 0         0 $MIME::EcoEncode::JP_Q::HEAD = $HEAD;
191 0         0 $MIME::EcoEncode::JP_Q::HTL = $HTL;
192 0         0 $MIME::EcoEncode::JP_Q::LF = $LF;
193 0         0 $MIME::EcoEncode::JP_Q::BPL = $BPL;
194 0         0 $MIME::EcoEncode::JP_Q::MODE = 0;
195              
196 0         0 my $enc =
197             MIME::EcoEncode::JP_Q::add_ew_jp_q($value,
198             length($result) + 1,
199             \$np, 1, 1);
200 0 0       0 if ($enc eq ' ') {
201 0         0 $enc =
202             MIME::EcoEncode::JP_Q::add_ew_jp_q($value, 2, \$np, 1);
203 0         0 $result .= "$LF \"$enc\"";
204             }
205             else {
206 0         0 $result .= "\"$enc\"";
207             }
208 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
209             }
210             else { # "B" encoding
211 0         0 require MIME::EcoEncode::JP_B;
212 0         0 $MIME::EcoEncode::JP_B::HEAD = $HEAD;
213 0         0 $MIME::EcoEncode::JP_B::HTL = $HTL;
214 0         0 $MIME::EcoEncode::JP_B::LF = $LF;
215 0         0 $MIME::EcoEncode::JP_B::BPL = $BPL;
216              
217 0         0 my $enc =
218             MIME::EcoEncode::JP_B::add_ew_jp_b($value,
219             length($result) + 1,
220             \$np, 1, 1);
221 0 0       0 if ($enc eq ' ') {
222 0         0 $enc =
223             MIME::EcoEncode::JP_B::add_ew_jp_b($value, 2, \$np, 1);
224 0         0 $result .= "$LF \"$enc\"";
225             }
226             else {
227 0         0 $result .= "\"$enc\"";
228             }
229 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
230             }
231             }
232              
233 2 50       5 if ($type == 0) {
234 2         27 return param_enc($param, $value, $sps, $trailing_crlf, $quote);
235             }
236 0 0       0 if ($type == 1) { # "Q" encoding
237 0         0 require MIME::EcoEncode;
238 0         0 $MIME::EcoEncode::HEAD = $HEAD;
239 0         0 $MIME::EcoEncode::HTL = $HTL;
240 0         0 $MIME::EcoEncode::LF = $LF;
241 0         0 $MIME::EcoEncode::BPL = $BPL;
242 0         0 $MIME::EcoEncode::REG_W = $REG_W;
243              
244 0         0 my $enc =
245             MIME::EcoEncode::add_ew_q($value, length($result) + 1,
246             \$np, 1, 1);
247 0 0       0 if ($enc eq ' ') {
248 0         0 $enc =
249             MIME::EcoEncode::add_ew_q($value, 2, \$np, 1);
250 0         0 $result .= "$LF \"$enc\"";
251             }
252             else {
253 0         0 $result .= "\"$enc\"";
254             }
255 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
256             }
257             else { # "B" encoding
258 0         0 require MIME::EcoEncode;
259 0         0 $MIME::EcoEncode::HEAD = $HEAD;
260 0         0 $MIME::EcoEncode::HTL = $HTL;
261 0         0 $MIME::EcoEncode::LF = $LF;
262 0         0 $MIME::EcoEncode::BPL = $BPL;
263 0         0 $MIME::EcoEncode::REG_W = $REG_W;
264              
265 0         0 my $enc =
266             MIME::EcoEncode::add_ew_b($value, length($result) + 1,
267             \$np, 1, 1);
268 0 0       0 if ($enc eq ' ') {
269 0         0 $enc =
270             MIME::EcoEncode::add_ew_b($value, 2, \$np, 1);
271 0         0 $result .= "$LF \"$enc\"";
272             }
273             else {
274 0         0 $result .= "\"$enc\"";
275             }
276 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
277             }
278             }
279              
280              
281             sub param_enc {
282 2     2 0 20 my $param = shift;
283 2         3 my $value = shift;
284 2         3 my $sps = shift;
285 2         2 my $trailing_crlf = shift;
286 2         3 my $quote = shift;
287              
288 2         7 my $result;
289             my $ll_len;
290              
291 2         3 our $UTF8;
292 2         2 our $REG_W;
293 2         2 our $HEAD;
294              
295 2 50       5 $value = "\"$value\"" if $quote;
296 2         2 my $vstr = $value;
297              
298 2         9 $value =~ s/([^\w!#\$&\+-\.\^`\{\|}~])/
299 57         132 sprintf("%%%X",ord($1))/egox;
300              
301 2         5 $result = "$sps$param\*=$HEAD";
302 2 50       7 if (length($result) + length($value) <= $BPL) {
303 0         0 $result .= $value;
304 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
305             }
306              
307 2         3 my $n = 0;
308 2         2 my $nn = 1;
309 2         2 my $w1;
310             my $p_str;
311 0         0 my $w;
312 0         0 my $w_len;
313 2         3 my $chunk = '';
314 2         3 my $ascii = 1;
315              
316 2         3 $result = "$sps$param\*0\*=$HEAD";
317 2         4 $ll_len = length($result);
318              
319 2 100       13 utf8::decode($vstr) if $UTF8; # UTF8 flag on
320              
321 2         12 while ($vstr =~ /$REG_W/g) {
322 54         74 $w1 = $1;
323 54 100       90 utf8::encode($w1) if $UTF8; # UTF8 flag off
324 54         47 $w_len = length($w1); # size of one character
325              
326 54         329 $value =~ /((?:%..|.){$w_len})/g;
327 54         80 $w = $1;
328 54         51 $w_len = length($w);
329              
330 54 100       91 $ascii = 0 if $w_len > 1;
331              
332             # 1 is ';'
333 54 100       86 if ($ll_len + $w_len + 1 > $BPL) {
334 5         11 $p_str = " $param\*$nn\*=";
335 5 50       8 if ($ascii) {
336 0 0       0 if ($n == 0) {
337 0         0 $result = "$sps$param\*0=$HEAD$chunk$w;";
338             }
339             else {
340 0         0 $result .= "$LF $param\*$n=$chunk$w;";
341             }
342 0         0 $ll_len = length($p_str);
343 0         0 $chunk = '';
344             }
345             else {
346 5 100       8 if ($n == 0) {
347 2         5 $result = "$result$chunk;";
348             }
349             else {
350 3         9 $result .= "$LF $param\*$n\*=$chunk;";
351             }
352 5         6 $ll_len = length($p_str) + $w_len;
353 5         6 $chunk = $w;
354             }
355 5 100       10 $ascii = 1 if $w_len == 1;
356 5         5 $n = $nn;
357 5         22 $nn++;
358             }
359             else {
360 49         44 $chunk .= $w;
361 49         197 $ll_len += $w_len;
362             }
363             }
364 2 50       4 if ($ascii) {
365 0 0       0 if ($chunk eq '') {
366 0         0 chop($result);
367             }
368             else {
369 0         0 $result .= "$LF $param\*$n=$chunk";
370             }
371             }
372             else {
373 2         6 $result .= "$LF $param\*$n\*=$chunk";
374             }
375 2 50       18 return $trailing_crlf ? $result . $trailing_crlf : $result;
376             }
377              
378              
379             sub param_enc_jp {
380 1     1 0 2 my $param = shift;
381 1         2 my $value = shift;
382 1         2 my $sps = shift;
383 1         2 my $trailing_crlf = shift;
384 1         2 my $quote = shift;
385              
386 1         1 my $result;
387             my $ll_len;
388              
389 1         2 our $HEAD;
390              
391 1 50       5 $value = "\"$value\"" if $quote;
392 1         1 my $vstr = $value;
393              
394 1         5 $value =~ s/([^\w!#\$&\+-\.\^`\{\|}~])/
395 22         61 sprintf("%%%X",ord($1))/egox;
396              
397 1         4 $result = "$sps$param\*=$HEAD";
398 1 50       5 if (length($result) + length($value) <= $BPL) {
399 0         0 $result .= $value;
400 0 0       0 return $trailing_crlf ? $result . $trailing_crlf : $result;
401             }
402              
403 1         2 my $n = 0;
404 1         2 my $nn = 1;
405 1         1 my $p_str;
406 1         2 my $ascii = 1;
407              
408 1         1 my $ee_str = '%1B%28B';
409 1         2 my $ee_len = 7;
410              
411 1         2 my $vstr_len = length($vstr);
412              
413 1         1 my $k_in = 0; # ascii: 0, zen: 1 or 2, han: 9
414 1         2 my $k_in_bak = 0;
415 1         1 my $ec;
416 1         2 my ($w, $w_len) = ('', 0);
417 1         2 my ($chunk, $chunk_len) = ('', 0);
418 1         22 my ($w1, $w1_bak);
419 0         0 my $enc_len;
420              
421 1         6 $vstr =~ s/\e\(B$//;
422 1         4 $result = "$sps$param\*0\*=$HEAD";
423 1         42 $ll_len = length($result);
424              
425 1         6 while ($vstr =~ /\e(..)|./g) {
426 43         48 $ec = $1;
427 43         74 $value =~ /(%1B(?:%..|.)(?:%..|.)|(?:%..|.))/g;
428 43         46 $w1 = $1;
429 43         42 $w .= $w1;
430 43 100       56 if (defined $ec) {
431 7         10 $w1_bak = $w1;
432 7 100       16 if ($ec eq '(B') {
    100          
433 3         3 $k_in = 0;
434             }
435             elsif ($ec eq '$B') {
436 3         4 $k_in = 1;
437             }
438             else {
439 1         2 $k_in = 9;
440             }
441 7         18 next;
442             }
443             else {
444 36 100       76 if ($k_in == 1) {
    100          
445 9         8 $k_in = 2;
446 9         20 next;
447             }
448             elsif ($k_in == 2) {
449 9         7 $k_in = 1;
450             }
451             }
452 27         26 $w_len = length($w);
453 27 100       41 $enc_len = $w_len + ($k_in ? $ee_len : 0);
454 27 100       43 $ascii = 0 if $w_len > 1;
455              
456             # 1 is ';'
457 27 100       42 if ($ll_len + $enc_len + 1 > $BPL) {
458 4         10 $p_str = " $param\*$nn\*=";
459 4 50       6 if ($ascii) {
460 0 0       0 if ($n == 0) {
461 0         0 $result = "$sps$param\*0=$HEAD$chunk$w;";
462             }
463             else {
464 0         0 $result .= "$LF $param\*$n=$chunk$w;";
465             }
466 0         0 $ll_len = length($p_str);
467 0         0 $chunk = '';
468             }
469             else {
470 4 100       7 if ($k_in_bak) {
471 1         2 $chunk .= $ee_str;
472 1 50       2 if ($k_in) {
473 1 50       3 if ($k_in_bak == $k_in) {
474 1         1 $w = $w1_bak . $w;
475 1         2 $w_len += length($w1_bak);
476             }
477             }
478             else {
479 0         0 $w = $w1;
480 0         0 $w_len = length($w1);
481             }
482             }
483 4 100       7 if ($n == 0) {
484 1         2 $result = "$result$chunk;";
485             }
486             else {
487 3         8 $result .= "$LF $param\*$n\*=$chunk;";
488             }
489 4         5 $ll_len = length($p_str) + $w_len;
490 4         8 $chunk = $w;
491             }
492 4 50       16 $ascii = 1 if $w_len == 1;
493 4         5 $n = $nn;
494 4         4 $nn++;
495             }
496             else {
497 23         23 $chunk .= $w;
498 23         22 $ll_len += $w_len;
499             }
500 27         27 $k_in_bak = $k_in;
501 27         40 $w = '';
502 27         68 $w_len = 0;
503             }
504 1 50       4 if ($ascii) {
505 0 0       0 if ($chunk eq '') {
506 0         0 chop($result);
507             }
508             else {
509 0         0 $result .= "$LF $param\*$n=$chunk";
510             }
511             }
512             else {
513 1 50       3 $chunk .= $ee_str if $k_in_bak;
514 1         4 $result .= "$LF $param\*$n\*=$chunk";
515             }
516 1 50       10 return $trailing_crlf ? $result . $trailing_crlf : $result;
517             }
518              
519              
520             sub mime_deco_param {
521 9     9 0 1842 my $str = shift;
522 9 50 33     47 if ((!defined $str) || $str eq '') {
523 0 0       0 return ('') x 5 if wantarray;
524 0         0 return '';
525             }
526              
527 9         41 my ($trailing_crlf) = ($str =~ /(\x0d?\x0a|\x0d)$/);
528 9         21 $str =~ tr/\n\r//d;
529 9 50       31 if ($str =~ /^\s*$/) {
530 0 0       0 return ($trailing_crlf ? $str . $trailing_crlf : $str,
    0          
531             ('') x 4) if wantarray;
532 0 0       0 return $trailing_crlf ? $str . $trailing_crlf : $str;
533             }
534              
535 9         29 $str =~ s/^(\s*)//; # leading whitespace
536 9         17 my $sps = $1;
537              
538 9         11 my $result = '';
539 9         9 my ($param, $value, $charset, $lang);
540 9         22 my ($param0, $value0, $charset0, $lang0) = ('') x 4;
541              
542 9         10 my $bq_on = shift; # "B/Q" decode ON/OFF
543 9 100       17 $bq_on = 1 unless defined $bq_on;
544              
545 9 100       17 if ($bq_on) {
546 8         382 $str =~ /([^=]*)=\s*"(.*?[^\\])"\s*/;
547 8         16 ($param, $value) = ($1, $2);
548              
549 8         28 my $reg_ew =
550             qr{^
551             =\?
552             ([-0-9A-Za-z_]+) # charset
553             (?:\*([A-Za-z]{1,8} # language
554             (?:-[A-Za-z]{1,8})*))? # (RFC 2231 section 5)
555             \?
556             (?:
557             [Bb]\?([0-9A-Za-z\+\/]+={0,2})\?= # "B" encoding
558             |
559             [Qq]\?([\x21-\x3e\x40-\x7e]+)\?= # "Q" encoding
560             )}x;
561              
562 8 100 100     110 if ($value and $value =~ qr/$reg_ew(\s|$)/) { # "B" or "Q"
563 1         4 ($charset0, $lang0) = ($1, $2);
564 1 50       5 $lang0 = '' unless defined $lang0;
565 1         2 $param0 = $param;
566              
567 1         847 require MIME::Base64;
568 1         790 MIME::Base64->import();
569              
570 1         720 require MIME::QuotedPrint;
571 1         252 MIME::QuotedPrint->import();
572              
573 1         2 my ($b_enc, $q_enc);
574              
575 1         3 for my $w (split /\s+/, $value) {
576 1 50       57 if ($w =~ qr/$reg_ew$/o) {
577 1         5 ($charset, $lang, $b_enc, $q_enc) = ($1, $2, $3, $4);
578 1 50       4 if (defined $q_enc) {
579 0         0 $q_enc =~ tr/_/ /;
580 0         0 $value0 .= decode_qp($q_enc);
581             }
582             else {
583 1         13 $value0 .= decode_base64($b_enc);
584             }
585             }
586             }
587 1 50       5 if (lc($charset0) eq
588             'iso-2022-jp') { # remove redundant ESC sequences
589 0         0 $value0 =~ s/(\e..)([^\e]+)\e\(B(?=\1)/$1$2\n/g;
590 0         0 $value0 =~ s/\n\e..//g;
591 0         0 $value0 =~ s/\e\(B(\e..)/$1/g;
592             }
593 1         3 $result = "$sps$param0=\"$value0\"";
594 1 50       3 if (wantarray) {
595 0 0       0 return ($trailing_crlf ? $result . $trailing_crlf : $result,
596             $param0, $charset0, $lang0, $value0);
597             }
598 1 50       8 return $trailing_crlf ? $result . $trailing_crlf : $result;
599             }
600             }
601              
602 8         17 my ($param0_init, $cs_init, $quote) = (0) x 3;
603 8         9 my %params;
604              
605 8         102 while ($str =~ /([^=]*)=(\s*".*?[^\\]";?|\S*)\s*/g) {
606 22         47 ($param, $value) = ($1, $2);
607 22         54 $value =~ s/;$//;
608 22 100       61 if ($value =~ s/^\s*"(.*)"$/$1/) {
609 5         8 $quote = 1;
610             }
611 22 100       63 if ($param =~ s/\*$//) {
612 17 100       30 if (!$cs_init) {
613 6 50       30 if ($value =~ /^(.*?)'(.*?)'(.*)/) {
614 6         18 ($charset0, $lang0, $value) = ($1, $2, $3);
615             }
616 6         7 $cs_init = 1;
617             }
618 17         47 $value =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
  112         314  
619             }
620 22 100       41 if (!$param0_init) {
621 8         19 $param =~ s/\*0$//;
622 8         13 $param0 = $param;
623 8         8 $param0_init = 1;
624             }
625 22         102 $params{$param} = $value;
626             }
627              
628 8         12 my $n = keys %params;
629              
630 8 50       19 $result = ($n == 0) ? "$sps$str" : "$sps$param0=";
631 8         11 $value0 = $params{$param0};
632 8 50       14 $value0 = '' unless defined $value0;
633 8 100       22 if ($n > 1) {
634 6         14 for (my $i = 1; $i < $n; $i++) {
635 14         24 $value = $params{$param0 . "\*$i"};
636 14 50       45 $value0 .= $value if defined $value;
637             }
638             }
639 8 100       16 if (lc($charset0) eq 'iso-2022-jp') { # remove redundant ESC sequences
640 1         12 $value0 =~ s/(\e..)([^\e]+)\e\(B(?=\1)/$1$2\n/g;
641 1         4 $value0 =~ s/\n\e..//g;
642 1         3 $value0 =~ s/\e\(B(\e..)/$1/g;
643             }
644 8 100       20 $result .= ($quote ? "\"$value0\"" : $value0);
645 8 50       13 if (wantarray) {
646 0 0 0     0 if (!$cs_init and $quote) {
647 0         0 $value0 =~ s/\\(.)/$1/g;
648             }
649 0 0       0 return ($trailing_crlf ? $result . $trailing_crlf : $result,
650             $param0, $charset0, $lang0, $value0);
651             }
652 8 100       61 return $trailing_crlf ? $result . $trailing_crlf : $result;
653             }
654              
655             1;