From 6b6f2e83de0e5b48ba48583206bd456508554540 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Thu, 20 May 2010 17:28:30 -0400
Subject: [PATCH] Display and send messages with format=flowed (#1484370), fixes word wrapping issues (#1486543)

---
 CHANGELOG                         |    1 
 program/steps/mail/compose.inc    |   27 +-------
 program/steps/mail/func.inc       |   43 +++++++-------
 config/main.inc.php.dist          |   13 +++-
 program/include/rcube_message.php |   36 ++++++++++++
 program/steps/mail/sendmail.inc   |   15 +++-
 6 files changed, 84 insertions(+), 51 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 909b8bb..125c980 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG RoundCube Webmail
 ===========================
 
+- Read and send messages with format=flowed (#1484370), fixes word wrapping issues (#1486543)
 - Fix duplicated attachments when forwarding a message (#1486487)
 - Fix message/rfc822 attachments containing only attachments are not parsed properly (#1486743)
 - Fix %00 character in winmail.dat attachments names (#1486738)
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 07f1873..8af7248 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -5,7 +5,7 @@
  | Main configuration file                                               |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland                 |
+ | Copyright (C) 2005-2010, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  +-----------------------------------------------------------------------+
@@ -188,10 +188,10 @@
 $rcmail_config['max_group_members'] = 0; 
 
 // add this user-agent to message headers when sending
-$rcmail_config['useragent'] = 'RoundCube Webmail/'.RCMAIL_VERSION;
+$rcmail_config['useragent'] = 'Roundcube Webmail/'.RCMAIL_VERSION;
 
 // use this name to compose page titles
-$rcmail_config['product_name'] = 'RoundCube Webmail';
+$rcmail_config['product_name'] = 'Roundcube Webmail';
 
 // try to load host-specific configuration
 // see http://trac.roundcube.net/wiki/Howto_Config for more details
@@ -214,6 +214,13 @@
 // leave empty for auto-detection
 $rcmail_config['mail_header_delimiter'] = NULL;
 
+// number of chars allowed for line when wrapping text.
+// text wrapping is done when composing/sending messages
+$rcmail_config['line_length'] = 66;
+
+// send plaintext messages as format=flowed
+$rcmail_config['send_format_flowed'] = true;
+
 // session domain: .example.org
 $rcmail_config['session_domain'] = '';
 
diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php
index 05b0151..47fe3d7 100644
--- a/program/include/rcube_message.php
+++ b/program/include/rcube_message.php
@@ -198,6 +198,10 @@
 
       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') {
@@ -477,5 +481,37 @@
   }
 
 
+  /**
+   * Interpret a format=flowed message body according to RFC 2646
+   *
+   * @param string  Raw body formatted as flowed text
+   * @return string Interpreted text with unwrapped lines and stuffed space removed
+   */
+  public static function unfold_flowed($text)
+  {
+    return preg_replace(
+      array('/-- (\r?\n)/',   '/^ /m',  '/(.) \r?\n/',  '/--%SIGEND%(\r?\n)/'),
+      array('--%SIGEND%\\1',  '',       '\\1 ',         '-- \\1'),
+      $text);
+  }
+  
+  /**
+   * Wrap the given text to comply with RFC 2646
+   */
+  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), $length - 1, " \r\n");
+
+      $out .= $line . "\r\n";
+    }
+    
+    return $out;
+  }
+
 }
 
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index 50f11a3..0b18d12 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -134,7 +134,7 @@
   $OUTPUT->set_env('show_sig', false);
 
 // set line length for body wrapping
-$LINE_LENGTH = $RCMAIL->config->get('line_length', 75);
+$LINE_LENGTH = $RCMAIL->config->get('line_length', 72);
 
 if (!empty($msg_uid))
 {
@@ -597,30 +597,13 @@
         $body = substr($body, 0, max(0, $sp-1));
     }
 
-    // soft-wrap message first
-    $body = rcmail_wrap_quoted($body, $LINE_LENGTH);
-
-    $body = rtrim($body, "\r\n");
-
-    if ($body) {
-      // split body into single lines
-      $a_lines = preg_split('/\r?\n/', $body);
-
-      // add > to each line
-      for ($n=0; $n<sizeof($a_lines); $n++) {
-        if (strpos($a_lines[$n], '>')===0)
-          $a_lines[$n] = '>'.$a_lines[$n];
-        else
-          $a_lines[$n] = '> '.$a_lines[$n];
-      }
- 
-      $body = join("\n", $a_lines);
-    }
+    // soft-wrap and quote message text
+    $body = rcmail_wrap_and_quote(rtrim($body, "\r\n"), $LINE_LENGTH);
 
     // add title line(s)
-    $prefix = rc_wordwrap(sprintf("On %s, %s wrote:\n",
+    $prefix = sprintf("On %s, %s wrote:\n",
       $MESSAGE->headers->date,
-      $MESSAGE->get_header('from')), $LINE_LENGTH);
+      $MESSAGE->get_header('from'));
 
     $suffix = '';
     
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 951e777..fcb0229 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -933,6 +933,10 @@
         if (!isset($part->body))
           $part->body = $MESSAGE->get_part_content($part->mime_id);
 
+        // 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')
@@ -1161,40 +1165,37 @@
 
 /**
  * Wrap text to a given number of characters per line
- * but respect the mail quotation of replies messages (>)
+ * but respect the mail quotation of replies messages (>).
+ * Finally add another quotation level by prpending the lines
+ * with >
  *
  * @param string Text to wrap
  * @param int The line width
  * @return string The wrapped text
  */
-function rcmail_wrap_quoted($text, $max = 76)
+function rcmail_wrap_and_quote($text, $length = 72)
 {
   // Rebuild the message body with a maximum of $max chars, while keeping quoted message.
+  $max = min(78, $length + 8);
   $lines = preg_split('/\r?\n/', trim($text));
   $out = '';
 
   foreach ($lines as $line) {
-    if (strlen($line) > $max) {
-      if (preg_match('/^([>\s]+)/', $line, $regs)) {
-        $length = strlen($regs[0]);
-        $prefix = substr($line, 0, $length);
-
-        // Remove '> ' from the line, then wordwrap() the line
-        $line = rc_wordwrap(substr($line, $length), $max - $length);
-
-        // Rebuild the line with '> ' at the beginning of each 'subline'
-        $newline = '';
-        foreach (explode("\n", $line) as $l) {
-          $newline .= $prefix . $l . "\n";
-        }
-
-        // Remove the righest newline char
-        $line = rtrim($newline);
+    // don't wrap already quoted lines
+    if ($line[0] == '>')
+      $line = '>' . rtrim($line);
+    else if (mb_strlen($line) > $max) {
+      $newline = '';
+      foreach(explode("\n", rc_wordwrap($line, $length - 2)) as $l) {
+        if (strlen($l))
+          $newline .= '> ' . $l . "\n";
+        else
+          $newline .= ">\n";
       }
-      else {
-        $line = rc_wordwrap($line, $max);
-      }
+      $line = rtrim($newline);
     }
+    else
+      $line = '> ' . $line;
 
     // Append the line
     $out .= $line . "\n";
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index e7f5b95..8e43b37 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -5,7 +5,7 @@
  | program/steps/mail/sendmail.inc                                       |
  |                                                                       |
  | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland                 |
+ | Copyright (C) 2005-2010, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -440,11 +440,16 @@
   // look for "emoticon" images from TinyMCE and copy into message as attachments
   $message_body = rcmail_attach_emoticons($MAIL_MIME);
 }
-else
-  {
-  $message_body = rc_wordwrap($message_body, $LINE_LENGTH, "\r\n");
+else {
   if ($footer)
     $message_body .= "\r\n" . $footer;
+  
+  // 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);
+  else
+    $message_body = rc_wordwrap($message_body, min(79, $LINE_LENGTH + 8), "\r\n");  // +8: be generous with quoted lines
+  
   $message_body = wordwrap($message_body, 998, "\r\n", true);
   if (!strlen($message_body)) { 
     // empty message body breaks attachment handling in drafts 
@@ -503,7 +508,7 @@
 $MAIL_MIME->setParam('head_encoding', 'quoted-printable');
 $MAIL_MIME->setParam('head_charset', $message_charset);
 $MAIL_MIME->setParam('html_charset', $message_charset);
-$MAIL_MIME->setParam('text_charset', $message_charset);
+$MAIL_MIME->setParam('text_charset', $message_charset . ($flowed ? ";\r\n format=flowed" : ''));
 
 // encoding subject header with mb_encode provides better results with asian characters
 if (function_exists('mb_encode_mimeheader'))

--
Gitblit v1.9.1