- Fix format=flowed handling (#1486989) + small improvements in plain messages parsing

release-0.6
alecpl 14 years ago
parent fc552950d3
commit 99b8c1e2ac

@ -21,6 +21,7 @@ CHANGELOG RoundCube Webmail
- Re-added 'Close' button in upload form (#1486930, #1486823)
- Fix handling of charsets with LATIN-* label
- Fix messages background image handling in some cases (#1486990)
- Fix format=flowed handling (#1486989)
RELEASE 0.4
-----------

@ -214,23 +214,22 @@ class rcube_message
if ($mimetype == 'text/plain') {
$out = $this->imap->get_message_part($this->uid, $mime_id, $part);
// re-format format=flowed content
if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed')
$out = self::unfold_flowed($out);
break;
}
else if ($mimetype == 'text/html') {
$html_part = $this->imap->get_message_part($this->uid, $mime_id, $part);
$out = $this->imap->get_message_part($this->uid, $mime_id, $part);
// remove special chars encoding
$trans = array_flip(get_html_translation_table(HTML_ENTITIES));
$html_part = strtr($html_part, $trans);
$out = strtr($out, $trans);
// create instance of html2text class
$txt = new html2text($html_part);
$txt = new html2text($out);
$out = $txt->get_text();
break;
}
}
@ -604,10 +603,51 @@ class rcube_message
*/
public static function unfold_flowed($text)
{
return preg_replace(
array('/-- (\r?\n)/', '/^ /m', '/(.) \r?\n/', '/--%SIGEND%(\r?\n)/'),
array('--%SIGEND%\\1', '', '\\1 ', '-- \\1'),
$text);
$text = preg_split('/\r?\n/', $text);
$last = -1;
$q_level = 0;
foreach ($text as $idx => $line) {
if ($line[0] == '>' && preg_match('/^(>+\s*)/', $line, $regs)) {
$q = strlen(str_replace(' ', '', $regs[0]));
$line = substr($line, strlen($regs[0]));
if ($q == $q_level && isset($text[$last])
&& $text[$last][strlen($text[$last])-1] == ' '
) {
$text[$last] .= $line;
unset($text[$idx]);
}
else {
$last = $idx;
}
}
else {
$q = 0;
if ($line == '-- ') {
$last = $idx;
}
else {
// remove space-stuffing
$line = preg_replace('/^\s/', '', $line);
if (isset($text[$last])
&& $text[$last] != '-- '
&& $text[$last][strlen($text[$last])-1] == ' '
) {
$text[$last] .= $line;
unset($text[$idx]);
}
else {
$text[$idx] = $line;
$last = $idx;
}
}
}
$q_level = $q;
}
return implode("\r\n", $text);
}
@ -616,17 +656,25 @@ class rcube_message
*/
public static function format_flowed($text, $length = 72)
{
$out = '';
foreach (preg_split('/\r?\n/', trim($text)) as $line) {
// don't wrap quoted lines (to avoid wrapping problems)
if ($line[0] != '>')
$line = rc_wordwrap(rtrim($line, "\r\n"), $length - 1, " \r\n");
$out .= $line . "\r\n";
$text = preg_split('/\r?\n/', $text);
foreach ($text as $idx => $line) {
if ($line != '-- ') {
if ($line[0] == '>' && preg_match('/^(>+)/', $line, $regs)) {
$prefix = $regs[0];
$level = strlen($prefix);
$line = rtrim(substr($line, $level));
$line = $prefix . rc_wordwrap($line, $length - $level - 2, " \r\n$prefix ");
}
else {
$line = ' ' . rc_wordwrap(rtrim($line), $length - 2, " \r\n ");
}
$text[$idx] = $line;
}
}
return $out;
return implode("\r\n", $text);
}
}

@ -735,7 +735,7 @@ function rcmail_print_body($part, $p = array())
// plaintext postprocessing
if ($part->ctype_secondary == 'plain')
$body = rcmail_plain_body($body);
$body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed');
// allow post-processing of the message body
$data = $RCMAIL->plugins->exec_hook('message_part_after', array('type' => $part->ctype_secondary, 'body' => $body) + $data);
@ -747,75 +747,102 @@ function rcmail_print_body($part, $p = array())
/**
* Handle links and citation marks in plain text message
*
* @param string Plain text string
* @param string Plain text string
* @param boolean Text uses format=flowed
*
* @return string Formatted HTML string
*/
function rcmail_plain_body($body)
function rcmail_plain_body($body, $flowed=false)
{
// make links and email-addresses clickable
$replacements = new rcube_string_replacer;
$replacer = new rcube_string_replacer;
// search for patterns like links and e-mail addresses
$body = preg_replace_callback($replacements->link_pattern, array($replacements, 'link_callback'), $body);
$body = preg_replace_callback($replacements->mailto_pattern, array($replacements, 'mailto_callback'), $body);
$body = preg_replace_callback($replacer->link_pattern, array($replacer, 'link_callback'), $body);
$body = preg_replace_callback($replacer->mailto_pattern, array($replacer, 'mailto_callback'), $body);
// split body into single lines
$a_lines = preg_split('/\r?\n/', $body);
$q_lines = array();
$quote_level = 0;
$last = -1;
// find/mark quoted lines...
for ($n=0, $cnt=count($a_lines); $n < $cnt; $n++) {
$q = 0;
if ($a_lines[$n][0] == '>' && preg_match('/^(>+\s*)+/', $a_lines[$n], $regs)) {
$q = strlen(preg_replace('/\s/', '', $regs[0]));
$a_lines[$n] = substr($a_lines[$n], strlen($regs[0]));
$a_lines[$n] = substr($a_lines[$n], strlen($regs[0]));
if ($q > $quote_level)
$q_lines[$n]['quote'] = $q - $quote_level;
$a_lines[$n] = $replacer->get_replacement($replacer->add(
str_repeat('<blockquote>', $q - $quote_level))) . $a_lines[$n];
else if ($q < $quote_level)
$q_lines[$n]['endquote'] = $quote_level - $q;
$a_lines[$n] = $replacer->get_replacement($replacer->add(
str_repeat('</blockquote>', $quote_level - $q))) . $a_lines[$n];
else if ($flowed) {
// previous line is flowed
if (isset($a_lines[$last])
&& $a_lines[$last][strlen($a_lines[$last])-1] == ' ') {
// merge lines (and remove space-stuffing)
$a_lines[$last] .= $a_lines[$n];
unset($a_lines[$n]);
}
else
$last = $n;
}
}
else {
$q = 0;
if ($flowed) {
// sig separator - line is fixed
if ($a_lines[$n] == '-- ') {
$last = $n;
}
else {
// remove space-stuffing
if ($a_lines[$n][0] == ' ')
$a_lines[$n] = substr($a_lines[$n], 1);
// previous line is flowed?
if (isset($a_lines[$last])
&& $a_lines[$last] != '-- '
&& $a_lines[$last][strlen($a_lines[$last])-1] == ' '
) {
$a_lines[$last] .= $a_lines[$n];
unset($a_lines[$n]);
}
else {
$last = $n;
}
}
if ($quote_level > 0)
$a_lines[$last] = $replacer->get_replacement($replacer->add(
str_repeat('</blockquote>', $quote_level))) . $a_lines[$last];
}
else if ($quote_level > 0)
$a_lines[$n] = $replacer->get_replacement($replacer->add(
str_repeat('</blockquote>', $quote_level))) . $a_lines[$n];
}
else if ($quote_level > 0)
$q_lines[$n]['endquote'] = $quote_level;
$quote_level = $q;
}
// quote plain text
$body = Q(join("\n", $a_lines), 'replace', false);
$body = Q(join("\n", $a_lines), '', false);
// colorize signature
if (($sp = strrpos($body, '-- ')) !== false)
if (($sp == 0 || $body[$sp-1] == "\n") && $body[$sp+3] == "\n") {
$body = substr($body, 0, max(0, $sp))
.'<span class="sig">'.substr($body, $sp).'</span>';
if (($sp = strrpos($body, "-- \n")) !== false) {
if (($sp == 0 || $body[$sp-1] == "\n")) {
// do not touch blocks with more that 10 lines
if (substr_count($body, "\n", $sp) < 10)
$body = substr($body, 0, max(0, $sp))
.'<span class="sig">'.substr($body, $sp).'</span>';
}
}
// colorize quoted lines
$a_lines = preg_split('/\n/', $body);
foreach ($q_lines as $i => $q)
if ($q['quote'])
$a_lines[$i] = str_repeat('<blockquote>', $q['quote']) . $a_lines[$i];
else if ($q['endquote'])
$a_lines[$i] = str_repeat('</blockquote>', $q['endquote']) . $a_lines[$i];
// insert the links for urls and mailtos
$body = $replacements->resolve(join("\n", $a_lines));
return $body;
}
// insert url/mailto links and citation tags
$body = $replacer->resolve($body);
/**
* add a string to the replacement array and return a replacement string
*/
function rcmail_str_replacement($str, &$rep)
{
static $count = 0;
$rep[$count] = stripslashes($str);
return "##string_replacement{".($count++)."}##";
return $body;
}
@ -983,10 +1010,6 @@ function rcmail_message_body($attrib)
$plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array(
'part' => $part, 'prefix' => ''));
// re-format format=flowed content
if ($part->ctype_secondary == "plain" && $part->ctype_parameters['format'] == "flowed")
$part->body = rcube_message::unfold_flowed($part->body);
$body = rcmail_print_body($part, array('safe' => $safe_mode, 'plain' => !$CONFIG['prefer_html']));
if ($part->ctype_secondary == 'html') {

@ -461,9 +461,9 @@ else {
$message_body = $plugin['body'];
// compose format=flowed content if enabled and not a reply message
if (empty($_SESSION['compose']['reply_msgid']) && ($flowed = $RCMAIL->config->get('send_format_flowed', true)))
$message_body = rcube_message::format_flowed($message_body, $LINE_LENGTH);
// compose format=flowed content if enabled
if ($flowed = $RCMAIL->config->get('send_format_flowed', true))
$message_body = rcube_message::format_flowed($message_body, min($LINE_LENGTH+2, 79));
else
$message_body = rc_wordwrap($message_body, $LINE_LENGTH, "\r\n");

Loading…
Cancel
Save