From 81b573d98ae143bd11b37ff2027bfad78e2d460c Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Tue, 16 Sep 2008 04:49:28 -0400
Subject: [PATCH] - Reduced memory footprint when forwarding attachments (#1485345) - Fixed endless loop in iil_C_HandlePartBody() - rcube_message::get_part_content() speed up using 3rd argument of rcube_imap::get_message_part()

---
 CHANGELOG                         |    4 ++
 program/include/rcube_imap.php    |   17 +++++++-
 program/steps/mail/compose.inc    |    2 
 program/lib/imap.inc              |   66 ++++++++++++++++++++++-----------
 program/include/rcube_message.php |    5 +-
 5 files changed, 66 insertions(+), 28 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index e185a5e..02a2900 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,10 @@
 CHANGELOG RoundCube Webmail
 ---------------------------
 
+2008/09/16 (alec)
+----------
+- Reduced memory footprint when forwarding attachments (#1485345)
+
 2008/09/15 (thomasb)
 ----------
 - Redesign of the identities settings (#1484042)
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 1b5ec16..54f0757 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -1283,9 +1283,10 @@
    * @param  string Part number
    * @param  object rcube_message_part Part object created by get_structure()
    * @param  mixed  True to print part, ressource to write part contents in
+   * @param  resource File pointer to save the message part
    * @return string Message/part body if not printed
    */
-  function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL)
+  function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL)
     {
     if (!($msg_id = $this->_uid2id($uid)))
       return FALSE;
@@ -1293,6 +1294,7 @@
     // get part encoding if not provided
     if (!is_object($o_part))
       {
+      write_log('errors', 'get_message_part: !is_object');
       $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); 
       $structure = iml_GetRawStructureArray($structure_str);
       $part_type = iml_GetPartTypeCode($structure, $part);
@@ -1318,7 +1320,10 @@
       }
     else
       {
-      $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 1);
+      if ($fp && $o_part->encoding == 'base64')
+        return iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 3, $fp);
+      else
+        $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 1);
 
       // decode part body
       if ($o_part->encoding)
@@ -1333,8 +1338,14 @@
 
         $body = rcube_charset_convert($body, $o_part->charset);
         }
+      
+      if ($fp)
+        {
+        fwrite($fp, $body);
+	return true;
+        }
       }
-
+    
     return $body;
     }
 
diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php
index c18db4b..f2e4be3 100644
--- a/program/include/rcube_message.php
+++ b/program/include/rcube_message.php
@@ -117,12 +117,13 @@
    * Get content of a specific part of this message
    *
    * @param string Part MIME-ID
+   * @param resource File pointer to save the message part
    * @return string Part content
    */
-  public function get_part_content($mime_id)
+  public function get_part_content($mime_id, $fp=NULL)
   {
     if ($part = $this->mime_parts[$mime_id])
-      return $this->imap->get_message_part($this->uid, $mime_id, $part);
+      return $this->imap->get_message_part($this->uid, $mime_id, $part, NULL, $fp);
     else
       return null;
   }
diff --git a/program/lib/imap.inc b/program/lib/imap.inc
index eb30d42..17197d8 100644
--- a/program/lib/imap.inc
+++ b/program/lib/imap.inc
@@ -65,6 +65,7 @@
 		- RFC3501 [7.1] don't call CAPABILITY if was returned in server 
 		  optional resposne in iil_Connect(), added iil_C_GetCapability()
 		- remove 'undisclosed-recipients' string from 'To' header
+		- iil_C_HandlePartBody(): added 6th argument and fixed endless loop
 
 ********************************************************/
 
@@ -2353,19 +2354,19 @@
 	return $result;
 }
 
-function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode) {
+function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode, $file=NULL) {
 	/* modes:
-        1: return string
+        1: return string (or write to $file pointer)
         2: print
-        3: base64 and print
+        3: base64 and print (or write to $file pointer)
 	*/
 	
 	$fp     = $conn->fp;
 	$result = false;
 	if (($part == 0) || empty($part)) {
-	    $part = 'TEXT';
+		$part = 'TEXT';
 	}
-    
+	
 	if (iil_C_Select($conn, $mailbox)) {
     		$reply_key = '* ' . $id;
         
@@ -2399,8 +2400,11 @@
 	                if ($mode == 2) {
         		        echo $result;
 	                } else if ($mode == 3) {
-        		        echo base64_decode($result);
-	                }
+				if ($file)
+					fwrite($file, base64_decode($result));
+        		    	else
+					echo base64_decode($result);
+			}			     
     		} else if ($line[$len-1] == '}') {
 	                //multi-line request, find sizes of content and receive that many bytes
         		$from     = strpos($line, '{') + 1;
@@ -2408,34 +2412,47 @@
         		$len      = $to - $from;
 	                $sizeStr  = substr($line, $from, $len);
         		$bytes    = (int)$sizeStr;
-	                $received = 0;
 
-        		while ($received < $bytes) {
-            			$remaining = $bytes - $received;
-		                $line      = iil_ReadLine($fp, 1024);
+        		while ($bytes > 0) {
+    		                $line      = iil_ReadLine($fp, 1024);
             			$len       = strlen($line);
                 
-		                if ($len > $remaining) {
-            			        $line = substr($line, 0, $remaining);
+		                if ($len > $bytes) {
+            			        $line = substr($line, 0, $bytes);
 		                }
-            			$received += strlen($line);
+            			$bytes -= strlen($line);
+
 		                if ($mode == 1) {
-            			        $result .= rtrim($line, "\t\r\n\0\x0B") . "\n";
+					if ($file)
+						fwrite($file, rtrim($line, "\t\r\n\0\x0B") . "\n");
+            			        else
+						$result .= rtrim($line, "\t\r\n\0\x0B") . "\n";
 		                } else if ($mode == 2) {
             			        echo rtrim($line, "\t\r\n\0\x0B") . "\n";
 		                } else if ($mode == 3) {
-            				echo base64_decode($line);
-            			}
+					if ($file)
+						fwrite($file, base64_decode($line));
+            				else
+						echo base64_decode($line);
+				}
         		}
     		}
-	        // read in anything up until 'til last line
+	        // read in anything up until last line
 		do {
         		$line = iil_ReadLine($fp, 1024);
 		} while (!iil_StartsWith($line, $key));
         
+		if ($mode == 3 && $file) {
+			return true;
+		}
+	
     		if ($result) {
 	    		$result = rtrim($result, "\t\r\n\0\x0B");
-        		return $result; // substr($result, 0, strlen($result)-1);
+			if ($file) {
+				fwrite($file, $result);
+				return true;
+			}	
+			return $result; // substr($result, 0, strlen($result)-1);
     		}
     		
 		return false;
@@ -2444,13 +2461,18 @@
 	}
     
 	if ($mode==1) {
+		if ($file) {
+			fwrite($file, $result);
+			return true;
+		}
     		return $result;
 	}
-	return $received;
+	
+	return false;
 }
 
-function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part) {
-	return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
+function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part, $file=NULL) {
+	return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1, $file);
 }
 
 function iil_C_PrintPartBody(&$conn, $mailbox, $id, $part) {
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index e45662d..b25a7de 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -596,7 +596,7 @@
       $tmp_path = tempnam($temp_dir, 'rcmAttmnt');
       if ($fp = fopen($tmp_path, 'w'))
       {
-        fwrite($fp, $message->get_part_content($pid));
+        $message->get_part_content($pid, $fp);
         fclose($fp);
         
         $_SESSION['compose']['attachments'][] = array(

--
Gitblit v1.9.1