diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index 54f7d106a..a6c09c845 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -437,12 +437,13 @@ class rcube_mime /** * Interpret a format=flowed message body according to RFC 2646 * - * @param string $text Raw body formatted as flowed text - * @param string $mark Mark each flowed line with specified character + * @param string $text Raw body formatted as flowed text + * @param string $mark Mark each flowed line with specified character + * @param boolean $delsp Remove the trailing space of each flowed line * * @return string Interpreted text with unwrapped lines and stuffed space removed */ - public static function unfold_flowed($text, $mark = null) + public static function unfold_flowed($text, $mark = null, $delsp = false) { $text = preg_split('/\r?\n/', $text); $last = -1; @@ -464,6 +465,9 @@ class rcube_mime && isset($text[$last]) && $text[$last][strlen($text[$last])-1] == ' ' && !preg_match('/^>+ {0,1}$/', $text[$last]) ) { + if ($delsp) { + $text[$last] = substr($text[$last], 0, -1); + } $text[$last] .= $line; unset($text[$idx]); @@ -487,6 +491,9 @@ class rcube_mime && $text[$last] != '-- ' && $text[$last][strlen($text[$last])-1] == ' ' ) { + if ($delsp) { + $text[$last] = substr($text[$last], 0, -1); + } $text[$last] .= $line; unset($text[$idx]); diff --git a/program/lib/Roundcube/rcube_text2html.php b/program/lib/Roundcube/rcube_text2html.php index 73e8b788c..ce8c37799 100644 --- a/program/lib/Roundcube/rcube_text2html.php +++ b/program/lib/Roundcube/rcube_text2html.php @@ -48,6 +48,8 @@ class rcube_text2html 'space' => "\xC2\xA0", // enables format=flowed parser 'flowed' => false, + // enables delsp=yes parser + 'delsp' => false, // enables wrapping for non-flowed text 'wrap' => true, // line-break tag @@ -150,7 +152,8 @@ class rcube_text2html if ($this->config['flowed']) { $flowed_char = 0x01; - $text = rcube_mime::unfold_flowed($text, chr($flowed_char)); + $delsp = $this->config['delsp']; + $text = rcube_mime::unfold_flowed($text, chr($flowed_char), $delsp); } // search for patterns like links and e-mail addresses and replace with tokens diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index b6f4195ad..982cbb727 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -910,7 +910,7 @@ function rcmail_compose_part_body($part, $isHtml = false) } // add HTML formatting - $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed'); + $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed', $part->ctype_parameters['delsp'] == 'yes'); } } else { @@ -927,7 +927,7 @@ function rcmail_compose_part_body($part, $isHtml = false) } else { if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { - $body = rcube_mime::unfold_flowed($body); + $body = rcube_mime::unfold_flowed($body, null, $part->ctype_parameters['delsp'] == 'yes'); } // try to remove the signature diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 8ef4986d3..e09ba6365 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -956,7 +956,9 @@ function rcmail_print_body($body, $part, $p = array()) // plaintext postprocessing if ($part->ctype_secondary == 'plain') { - $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed'); + $flowed = $part->ctype_parameters['format'] == 'flowed'; + $delsp = $part->ctype_parameters['delsp'] == 'yes'; + $body = rcmail_plain_body($body, $flowed, $delsp); } // allow post-processing of the message body @@ -974,9 +976,10 @@ function rcmail_print_body($body, $part, $p = array()) * * @return string Formatted HTML string */ -function rcmail_plain_body($body, $flowed = false) +function rcmail_plain_body($body, $flowed = false, $delsp = false) { - $options = array('flowed' => $flowed, 'wrap' => !$flowed, 'replacer' => 'rcmail_string_replacer'); + $options = array('flowed' => $flowed, 'wrap' => !$flowed, 'replacer' => 'rcmail_string_replacer', + 'delsp' => $delsp); $text2html = new rcube_text2html($body, false, $options); $body = $text2html->get_html(); diff --git a/tests/Framework/Mime.php b/tests/Framework/Mime.php index f3f0d0b81..bbab0e64b 100644 --- a/tests/Framework/Mime.php +++ b/tests/Framework/Mime.php @@ -170,6 +170,20 @@ class Framework_Mime extends PHPUnit_Framework_TestCase $this->assertEquals($unfolded, rcube_mime::unfold_flowed($flowed), "Test correct unfolding of quoted lines [2]"); } + /** + * Test format=flowed delsp=yes unfolding (RFC3676) + */ + function test_unfold_flowed_delsp() + { + $flowed = "そしてジョバンニはすぐうしろの天気輪の柱が \r\n" + ."いつかぼんやりした三角標の形になって、しば \r\n" + ."らく蛍のように、ぺかぺか消えたりともったり \r\n" + ."しているのを見ました。"; + $unfolded = "そしてジョバンニはすぐうしろの天気輪の柱がいつかぼんやりした三角標の形になって、しばらく蛍のように、ぺかぺか消えたりともったりしているのを見ました。"; + + $this->assertEquals($unfolded, rcube_mime::unfold_flowed($flowed, null, true), "Test correct unfolding of flowed DelSp=Yes lines"); + } + /** * Test wordwrap() */ diff --git a/tests/Framework/Text2Html.php b/tests/Framework/Text2Html.php index 03c4bd097..c85e44a4c 100644 --- a/tests/Framework/Text2Html.php +++ b/tests/Framework/Text2Html.php @@ -19,6 +19,7 @@ class Framework_Text2Html extends PHPUnit_Framework_TestCase 'break' => '
', 'links' => false, 'flowed' => false, + 'delsp' => false, 'wrap' => false, 'space' => '_', // replace UTF-8 non-breaking space for simpler testing 'nobr_start' => '>', @@ -70,7 +71,30 @@ class Framework_Text2Html extends PHPUnit_Framework_TestCase $data[] = array(">aaaa \n>bbbb\ncccc dddd", "
aaaa bbbb
>cccc_dddd<", $options); $data[] = array("\x02\x03", ">\x02\x03<", $options); + $options['flowed'] = true; + $options['delsp'] = true; + + $data[] = array(" aaaa", "aaaa", $options); + $data[] = array("aaaa aaaa", ">aaaa_aaaa<", $options); + $data[] = array("aaaa aaaa", ">aaaa__aaaa<", $options); + $data[] = array("aaaa aaaa", ">aaaa___aaaa<", $options); + $data[] = array("aaaa\taaaa", ">aaaa____aaaa<", $options); + $data[] = array("aaaa\naaaa", "aaaa
aaaa", $options); + $data[] = array("aaaa\n aaaa", "aaaa
aaaa", $options); + $data[] = array("aaaa\n aaaa", "aaaa
>_aaaa<", $options); + $data[] = array("aaaa\n aaaa", "aaaa
>__aaaa<", $options); + $data[] = array("\taaaa", ">____aaaa<", $options); + $data[] = array("\naaaa", "
aaaa", $options); + $data[] = array("\n aaaa", "
aaaa", $options); + $data[] = array("\n aaaa", "
>_aaaa<", $options); + $data[] = array("\n aaaa", "
>__aaaa<", $options); + $data[] = array("aaaa\n\nbbbb", "aaaa

bbbb", $options); + $data[] = array(">aaaa \n>aaaa", "
aaaaaaaa
", $options); + $data[] = array(">aaaa\n>aaaa", "
aaaa
aaaa
", $options); + $data[] = array(">aaaa \n>bbbb\ncccc dddd", "
aaaabbbb
>cccc_dddd<", $options); + $options['flowed'] = false; + $options['delsp'] = false; $options['wrap'] = true; $data[] = array(">>aaaa bbbb\n>>\n>>>\n>cccc\n\ndddd eeee",