From 81b573d98ae143bd11b37ff2027bfad78e2d460c Mon Sep 17 00:00:00 2001 From: alecpl Date: Tue, 16 Sep 2008 08:49:28 +0000 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/include/rcube_message.php | 5 ++- program/lib/imap.inc | 66 ++++++++++++++++++++----------- program/steps/mail/compose.inc | 2 +- 5 files changed, 66 insertions(+), 28 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e185a5e7c..02a2900b0 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 1b5ec1670..54f0757b7 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -1283,9 +1283,10 @@ class rcube_imap * @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 @@ class rcube_imap // 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 @@ class rcube_imap } 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 @@ class rcube_imap $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 c18db4bdd..f2e4be3ef 100644 --- a/program/include/rcube_message.php +++ b/program/include/rcube_message.php @@ -117,12 +117,13 @@ class rcube_message * 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 eb30d42c5..17197d872 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 @@ function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part) { 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 @@ function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode) { 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 @@ function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode) { $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 @@ function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode) { } 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 e45662de5..b25a7dee6 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -596,7 +596,7 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) $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(