From 5cc4b13a0c6d32d74d0cba17feeb6c5fbceaf25f Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Mon, 19 Mar 2007 18:36:24 -0400
Subject: [PATCH] Correctly parse message/rfc822; fixed html2text conversion; code cleanup

---
 CHANGELOG                      |    8 ++
 program/lib/html2text.inc      |   10 +-
 program/steps/mail/compose.inc |   17 +--
 skins/default/mail.css         |    7 +
 program/steps/mail/func.inc    |   45 ++++------
 program/steps/mail/get.inc     |    8 +-
 program/include/rcube_imap.inc |   88 ++++++++++++---------
 7 files changed, 98 insertions(+), 85 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 6288cbc..15e6c73 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,14 @@
 CHANGELOG RoundCube Webmail
 ---------------------------
 
+2007/03/19 (thomasb)
+----------
+- Don't download HTML message parts
+- Convert HTML parts to plaintext if 'prefer_html' is off
+- Correctly parse message/rfc822 parts (closes #1484045)
+- Code cleanup
+
+
 2007/03/18 (thomasb)
 ----------
 - Also use user_id for unique key in messages table (closes #1484074)
diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc
index f8e9e0a..3463ae2 100644
--- a/program/include/rcube_imap.inc
+++ b/program/include/rcube_imap.inc
@@ -988,10 +988,10 @@
     if (!($msg_id = $this->_uid2id($uid)))
       return FALSE;
 
-	$structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); 
-	$structure = iml_GetRawStructureArray($structure_str);
-	$struct = false;
-	
+    $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); 
+    $structure = iml_GetRawStructureArray($structure_str);
+    $struct = false;
+
     // parse structure and add headers
     if (!empty($structure))
       {
@@ -1013,9 +1013,9 @@
       if ($this->caching_enabled)
         $this->add_message_cache($cache_key, $msg_id, $headers, $struct);
       }
-	
-	return $struct;
-	}
+      
+    return $struct;
+    }
 
   
   /**
@@ -1047,8 +1047,8 @@
       for ($i=0, $count=0; $i<count($part); $i++)
         if (is_array($part[$i]) && count($part[$i]) > 5)
           $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id);
-
-      return $struct;      
+          
+      return $struct;
       }
     
     
@@ -1056,30 +1056,30 @@
     $struct->ctype_primary = strtolower($part[0]);
     $struct->ctype_secondary = strtolower($part[1]);
     $struct->mimetype = $struct->ctype_primary.'/'.$struct->ctype_secondary;
-	
+
     // read content type parameters
-	if (is_array($part[2]))
-	  {
-	  $struct->ctype_parameters = array();
+    if (is_array($part[2]))
+      {
+      $struct->ctype_parameters = array();
       for ($i=0; $i<count($part[2]); $i+=2)
         $struct->ctype_parameters[strtolower($part[2][$i])] = $part[2][$i+1];
         
       if (isset($struct->ctype_parameters['charset']))
         $struct->charset = $struct->ctype_parameters['charset'];
-	  }
-	  
-	// read content encoding
-	if (!empty($part[5]) && $part[5]!='NIL')
-	  {
-	  $struct->encoding = strtolower($part[5]);
-	  $struct->headers['content-transfer-encoding'] = $struct->encoding;
-	  }
-	  
-	// get part size
-	if (!empty($part[6]) && $part[6]!='NIL')
-	  $struct->size = intval($part[6]);
+      }
+    
+    // read content encoding
+    if (!empty($part[5]) && $part[5]!='NIL')
+      {
+      $struct->encoding = strtolower($part[5]);
+      $struct->headers['content-transfer-encoding'] = $struct->encoding;
+      }
+    
+    // get part size
+    if (!empty($part[6]) && $part[6]!='NIL')
+      $struct->size = intval($part[6]);
 
-	// read part disposition
+    // read part disposition
     $di = count($part) - 2;
     if ((is_array($part[$di]) && count($part[$di]) == 2 && is_array($part[$di][1])) ||
         (is_array($part[--$di]) && count($part[$di]) == 2))
@@ -1099,25 +1099,36 @@
         if (is_array($part[8][$i]) && count($part[8][$i]) > 5)
           $struct->parts[] = $this->_structure_part($part[8][$i], ++$count, $struct->mime_id);
       }
-      
-	// get part ID
-	if (!empty($part[3]) && $part[3]!='NIL')
-	  {
-	  $struct->content_id = $part[3];
-	  $struct->headers['content-id'] = $part[3];
-	  
-	  if (empty($struct->disposition))
-	    $struct->disposition = 'inline';
-	  }
+
+    // get part ID
+    if (!empty($part[3]) && $part[3]!='NIL')
+      {
+      $struct->content_id = $part[3];
+      $struct->headers['content-id'] = $part[3];
+    
+      if (empty($struct->disposition))
+        $struct->disposition = 'inline';
+      }
 
     // fetch message headers if message/rfc822
     if ($struct->ctype_primary=='message')
       {
       $headers = iil_C_FetchPartBody($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id.'.HEADER');
       $struct->headers = $this->_parse_headers($headers);
+      
+      if (is_array($part[8]) && empty($struct->parts))
+        $struct->parts[] = $this->_structure_part($part[8], ++$count, $struct->mime_id);
       }
-  
-  	return $struct;
+      
+    // normalize filename property
+    if (!empty($struct->d_parameters['filename']))
+      $struct->filename = $this->decode_mime_string($struct->d_parameters['filename']);
+    else if (!empty($struct->ctype_parameters['name']))
+      $struct->filename = $this->decode_mime_string($struct->ctype_parameters['name']);
+    else if (!empty($struct->headers['content-description']))
+      $struct->filename = $this->decode_mime_string($struct->headers['content-description']);
+      
+    return $struct;
     }
     
   
@@ -2510,6 +2521,7 @@
   var $ctype_secondary = 'plain';
   var $mimetype = 'text/plain';
   var $disposition = '';
+  var $filename = '';
   var $encoding = '8bit';
   var $charset = '';
   var $size = 0;
diff --git a/program/lib/html2text.inc b/program/lib/html2text.inc
index eabe15c..0ac72f7 100644
--- a/program/lib/html2text.inc
+++ b/program/lib/html2text.inc
@@ -112,7 +112,7 @@
         "/[\n\t]+/",                             // Newlines and tabs
         '/<script[^>]*>.*?<\/script>/i',         // <script>s -- which strip_tags supposedly has problems with
         //'/<!-- .* -->/',                         // Comments -- which strip_tags might have problem a with
-        '/<a href="([^"]+)"[^>]*>(.+?)<\/a>/ie', // <a href="">
+        '/<a [^>]*href="([^"]+)"[^>]*>(.+?)<\/a>/ie', // <a href="">
         '/<h[123][^>]*>(.+?)<\/h[123]>/ie',      // H1 - H3
         '/<h[456][^>]*>(.+?)<\/h[456]>/ie',      // H4 - H6
         '/<p[^>]*>/i',                           // <P>
@@ -160,11 +160,11 @@
         '',                                     // Non-legal carriage return
         ' ',                                    // Newlines and tabs
         '',                                     // <script>s -- which strip_tags supposedly has problems with
-        //'',                                     // Comments -- which strip_tags might have problem a with
+        //'',                                  // Comments -- which strip_tags might have problem a with
         '$this->_build_link_list("\\1", "\\2")', // <a href="">
         "strtoupper(\"\n\n\\1\n\n\")",          // H1 - H3
-        "ucwords(\"\n\n\\1\n\n\")",             // H4 - H6
-        "\n",                                   // <P>
+        "ucwords(\"\n\n\\1\n\")",               // H4 - H6
+        "\n\n",                                 // <P>
         "\n",                                   // <br>
         'strtoupper("\\1")',                    // <b>
         '_\\1_',                                // <i>
@@ -255,7 +255,7 @@
      *  @access public
      *  @return void
      */
-    function html2text( $source = '', $from_file = false, $do_link_table = true )
+    function html2text( $source = '', $from_file = false, $produce_link_table = true )
     {
         if ( !empty($source) ) {
             $this->set_html($source, $from_file);
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index 1c2639d..a794e98 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -401,8 +401,8 @@
       $body = rcmail_first_text_part($MESSAGE);
       $isHtml = false;
       }
-    if (strlen($body))
-      $body = rcmail_create_forward_body($body, $isHtml);
+
+    $body = rcmail_create_forward_body($body, $isHtml);
     }
   else if ($compose_mode == RCUBE_COMPOSE_DRAFT)
     {
@@ -564,10 +564,9 @@
   }
 
   // add attachments
-  if (!isset($_SESSION['compose']['forward_attachments']) &&
-      is_array($MESSAGE['parts']) && sizeof($MESSAGE['parts'])>1)
+  if (!isset($_SESSION['compose']['forward_attachments']) && is_array($MESSAGE['parts']))
     rcmail_write_compose_attachments($MESSAGE);
-
+    
   return $prefix.$body;
   }
 
@@ -598,7 +597,7 @@
     {
     if ($part->ctype_primary != 'message' && $part->ctype_primary != 'text' &&
         ($part->disposition=='attachment' || $part->disposition=='inline' || $part->headers['content-id'] ||
-         (empty($part->disposition) && ($part->d_parameters['filename'] || $part->ctype_parameters['name']))))
+         (empty($part->disposition) && $part->filename)))
       {
       $tmp_path = tempnam($temp_dir, 'rcmAttmnt');
       if ($fp = fopen($tmp_path, 'w'))
@@ -606,13 +605,9 @@
         fwrite($fp, $IMAP->get_message_part($message['UID'], $pid, $part->encoding));
         fclose($fp);
         
-        $filename = !empty($part->d_parameters['filename']) ? $part->d_parameters['filename'] :
-                     (!empty($part->ctype_parameters['name']) ? $part->ctype_parameters['name'] :
-                      (!empty($part->headers['content-description']) ? $part->headers['content-description'] : 'file'));
-
         $_SESSION['compose']['attachments'][] = array(
-          'name' => rcube_imap::decode_mime_string($filename),
           'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary,
+          'name' => $part->filename,
           'path' => $tmp_path
           );
         }
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index be9558f..e5e4db8 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -727,6 +727,14 @@
   
   $body = is_array($part->replaces) ? strtr($part->body, $part->replaces) : $part->body;
 
+  // convert html to text/plain
+  if ($part->ctype_secondary=='html' && $plain)
+    {
+    $txt = new html2text($body, false, true);
+    $body = $txt->get_text();
+    $part->ctype_secondary = 'plain';
+    }
+    
   // text/html
   if ($part->ctype_secondary=='html')
     {
@@ -975,7 +983,7 @@
 
       // part is file/attachment
       else if ($mail_part->disposition=='attachment' || $mail_part->disposition=='inline' || $mail_part->headers['content-id'] ||
-               (empty($mail_part->disposition) && ($mail_part->d_parameters['filename'] || $mail_part->ctype_parameters['name'])))
+               (empty($mail_part->disposition) && $mail_part->filename))
         {
         // skip apple resource forks
         if ($message_ctype_secondary=='appledouble' && $secondary_type=='applefile')
@@ -984,18 +992,12 @@
         // part belongs to a related message
         if ($message_ctype_secondary=='related' && $mail_part->headers['content-id'])
           {
-          $mail_part->filename = rcube_imap::decode_mime_string($mail_part->d_parameters['filename']);
           $mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']);
           $sa_inline_objects[] = $mail_part;
           }
         // is regular attachment
-        else if (($fname = $mail_part->d_parameters['filename']) ||
-                 ($fname = $mail_part->ctype_parameters['name']) ||
-                 ($fname = $mail_part->headers['content-description']))
-          {
-          $mail_part->filename = rcube_imap::decode_mime_string($fname);
+        else if ($mail_part->filename)
           $a_attachments[] = $mail_part;
-          }
         }
       }
 
@@ -1018,16 +1020,8 @@
     }
 
   // message is single part non-text
-  else
-    {
-    if (($fname = $structure->d_parameters['filename']) ||
-        ($fname = $structure->ctype_parameters['name']) ||
-        ($fname = $structure->headers['content-description']))
-      {
-      $structure->filename = rcube_imap::decode_mime_string($fname);
-      $a_attachments[] = $structure;
-      }
-    }
+  else if ($structure->filename)
+    $a_attachments[] = $structure;
 
   return array($a_return_parts, $a_attachments);
   }
@@ -1136,11 +1130,11 @@
         if (!isset($part->body))
           $part->body = $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part);
 
-        $body = rcmail_print_body($part, $safe_mode);
+        $body = rcmail_print_body($part, $safe_mode, !$CONFIG['prefer_html']);
         $out .= '<div class="message-part">';
         
         if ($part->ctype_secondary != 'plain')
-          $out .= rcmail_mod_html_body($body, $attrib['id']);
+          $out .= rcmail_sanitize_html($body, $attrib['id']);
         else
           $out .= $body;
 
@@ -1180,7 +1174,7 @@
 
 
 // modify a HTML message that it can be displayed inside a HTML page
-function rcmail_mod_html_body($body, $container_id)
+function rcmail_sanitize_html($body, $container_id)
   {
   // remove any null-byte characters before parsing
   $body = preg_replace('/\x00/', '', $body);
@@ -1452,22 +1446,19 @@
   $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary'));
   $out = '<table '. $attrib_str . ">\n";
   
-  $filename = $part->d_parameters['filename'] ? $part->d_parameters['filename'] : $part->ctype_parameters['name'];
-  $filesize = $part->size;
-  
   if ($filename)
     {
     $out .= sprintf('<tr><td class="title">%s</td><td>%s</td><td>[<a href="./?%s">%s</a>]</tr>'."\n",
                     Q(rcube_label('filename')),
-                    Q(rcube_imap::decode_mime_string($filename)),
+                    Q($part->filename),
                     str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']),
                     Q(rcube_label('download')));
     }
     
-  if ($filesize)
+  if ($part->size)
     $out .= sprintf('<tr><td class="title">%s</td><td>%s</td></tr>'."\n",
                     Q(rcube_label('filesize')),
-                    show_bytes($filesize));
+                    show_bytes($part->size));
   
   $out .= "\n</table>";
   
diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc
index 521f477..11688f1 100644
--- a/program/steps/mail/get.inc
+++ b/program/steps/mail/get.inc
@@ -59,16 +59,12 @@
     {
     $ctype_primary = strtolower($part->ctype_primary);
     $ctype_secondary = strtolower($part->ctype_secondary);
-
     $mimetype = sprintf('%s/%s', $ctype_primary, $ctype_secondary);
-    $filename = $part->d_parameters['filename'] ? $part->d_parameters['filename'] : $part->ctype_parameters['name'];
 
     header("Expires: 0");
     header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
     header("Cache-Control: private", false);
     header("Content-Transfer-Encoding: binary");
-    header(sprintf('Content-Disposition: attachment; filename="%s";',
-                   $filename ? rcube_imap::decode_mime_string($filename) : "roundcube.$ctype_secondary"));
 
     // send download headers
     if ($_GET['_download'])
@@ -110,6 +106,10 @@
       }
     else
       {
+      header(sprintf('Content-Disposition: %s; filename="%s";',
+                     $part->disposition ? $part->disposition : 'attachment',
+                     $part->filename ? $part->filename : "roundcube.$ctype_secondary"));
+
       // turn off output buffering and print part content
       $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part->encoding, true);
       }
diff --git a/skins/default/mail.css b/skins/default/mail.css
index 4e9c0d7..1399941 100644
--- a/skins/default/mail.css
+++ b/skins/default/mail.css
@@ -628,7 +628,14 @@
   width: 100%;
   background-color: #EBEBEB;
   table-layout: fixed;
+}
 
+#messagebody table.headers-table
+{
+  width: auto;
+  margin: 6px 8px;
+  background-color: #F4F4F4;
+  border: 1px solid #ccc;
 }
 
 table.headers-table tr td

--
Gitblit v1.9.1