From 91790e41f3fa307658077043bc2fa5f71e270cf4 Mon Sep 17 00:00:00 2001 From: alecpl Date: Tue, 9 Feb 2010 13:10:12 +0000 Subject: - Fix attachment excessive memory use, support messages of any size (#1484660) --- program/include/rcube_imap.php | 20 +++- program/include/rcube_mail_mime.php | 190 ------------------------------------ program/include/rcube_smtp.php | 28 ++++-- 3 files changed, 33 insertions(+), 205 deletions(-) delete mode 100644 program/include/rcube_mail_mime.php (limited to 'program/include') diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 6ab0b6a88..ecde6f958 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -1699,17 +1699,27 @@ class rcube_imap /** * Append a mail message (source) to a specific mailbox * - * @param string Target mailbox - * @param string Message source + * @param string Target mailbox + * @param string The message source string or filename + * @param string Headers string if $message contains only the body + * @param boolean True if $message is a filename + * * @return boolean True on success, False on error */ - function save_message($mbox_name, &$message) + function save_message($mbox_name, &$message, $headers='', $is_file=false) { $mailbox = $this->mod_mailbox($mbox_name); // make sure mailbox exists - if (($mailbox == 'INBOX') || in_array($mailbox, $this->_list_mailboxes())) - $saved = iil_C_Append($this->conn, $mailbox, $message); + if (($mailbox == 'INBOX') || in_array($mailbox, $this->_list_mailboxes())) { + if ($is_file) { + $separator = rcmail::get_instance()->config->header_delimiter(); + $saved = iil_C_AppendFromFile($this->conn, $mailbox, $message, + $headers, $separator.$separator); + } + else + $saved = iil_C_Append($this->conn, $mailbox, $message); + } if ($saved) { diff --git a/program/include/rcube_mail_mime.php b/program/include/rcube_mail_mime.php deleted file mode 100644 index 2176e6452..000000000 --- a/program/include/rcube_mail_mime.php +++ /dev/null @@ -1,190 +0,0 @@ - | - +-----------------------------------------------------------------------+ - - $Id$ - -*/ - - -/** - * Replacement PEAR:Mail_mime with some additional or overloaded methods - * - * @package Mail - */ -class rcube_mail_mime extends Mail_mime -{ - - protected $mime_content; - - /** - * Set build parameters - */ - function setParam($param) - { - if (is_array($param)) { - $this->_build_params = array_merge($this->_build_params, $param); - } - } - - /** - * Adds an image to the list of embedded images. - * - * @param string $file The image file name OR image data itself - * @param string $c_type The content type - * @param string $name The filename of the image. - * Only use if $file is the image data - * @param bool $isfilename Whether $file is a filename or not - * Defaults to true - * @param string $contentid Desired Content-ID of MIME part - * Defaults to generated unique ID - * @return mixed true on success or PEAR_Error object - * @access public - */ - function addHTMLImage($file, $c_type='application/octet-stream', $name = '', $isfilename = true, $contentid = '') - { - $filedata = ($isfilename === true) ? $this->_file2str($file) : $file; - if ($isfilename === true) { - $filename = ($name == '' ? $file : $name); - } - else { - $filename = $name; - } - - if (PEAR::isError($filedata)) { - return $filedata; - } - - if ($contentid == '') { - $contentid = md5(uniqid(time())); - } - - $this->_html_images[] = array( - 'body' => $filedata, - 'name' => $filename, - 'c_type' => $c_type, - 'cid' => $contentid - ); - - return true; - } - - - /** - * returns the HTML body portion of the message - * @return string HTML body of the message - * @access public - */ - function getHTMLBody() - { - return $this->_htmlbody; - } - - - /** - * Encodes a header as per RFC2047 - * - * @param array $input The header data to encode - * @param array $params Extra build parameters - * @return array Encoded data - * @access private - * @override - */ - function _encodeHeaders($input, $params = array()) - { - $maxlen = 73; - $params += $this->_build_params; - - foreach ($input as $hdr_name => $hdr_value) - { - // if header contains e-mail addresses - if (preg_match('/\s<.+@[a-z0-9\-\.]+\.[a-z]+>/U', $hdr_value)) { - $chunks = rcube_explode_quoted_string(',', $hdr_value); - } - else { - $chunks = array($hdr_value); - } - - $hdr_value = ''; - $line_len = 0; - - foreach ($chunks as $i => $value) { - $value = trim($value); - - //This header contains non ASCII chars and should be encoded. - if (preg_match('/[\x80-\xFF]{1}/', $value)) { - $suffix = ''; - // Don't encode e-mail address - if (preg_match('/(.+)\s(<.+@[a-z0-9\-\.]+>)$/Ui', $value, $matches)) { - $value = $matches[1]; - $suffix = ' '.$matches[2]; - } - - switch ($params['head_encoding']) { - case 'base64': - // Base64 encoding has been selected. - $mode = 'B'; - $encoded = base64_encode($value); - break; - - case 'quoted-printable': - default: - // quoted-printable encoding has been selected - $mode = 'Q'; - // replace ?, =, _ and spaces - $encoded = str_replace(array('=','_','?',' '), array('=3D','=5F','=3F','_'), $value); - $encoded = preg_replace('/([\x80-\xFF])/e', "'='.sprintf('%02X', ord('\\1'))", $encoded); - } - - $value = '=?' . $params['head_charset'] . '?' . $mode . '?' . $encoded . '?=' . $suffix; - } - - // add chunk to output string by regarding the header maxlen - $len = strlen($value); - if ($i == 0 || $line_len + $len < $maxlen) { - $hdr_value .= ($i>0?', ':'') . $value; - $line_len += $len + ($i>0?2:0); - } - else { - $hdr_value .= ($i>0?', ':'') . "\n " . $value; - $line_len = $len; - } - } - - $input[$hdr_name] = wordwrap($hdr_value, 990, "\n", true); // hard limit header length - } - - return $input; - } - - - /** - * Provides caching of body of constructed MIME Message to avoid - * duplicate construction of message and damage of MIME headers - * - * @return string The mime content - * @access public - * @override - */ - public function &get($build_params = null) - { - if(empty($this->mime_content)) - $this->mime_content = parent::get($build_params); - return $this->mime_content; - } - -} - diff --git a/program/include/rcube_smtp.php b/program/include/rcube_smtp.php index 92534688d..299126267 100644 --- a/program/include/rcube_smtp.php +++ b/program/include/rcube_smtp.php @@ -141,7 +141,8 @@ class rcube_smtp { * Either as an associative array or a finally * formatted string * - * @param string The full text of the message body, including any Mime parts, etc. + * @param mixed The full text of the message body, including any Mime parts + * or file handle * * @return bool Returns true on success, or false on error */ @@ -206,17 +207,24 @@ class rcube_smtp { } } - // Concatenate headers and body so it can be passed by reference to SMTP_CONN->data - // so preg_replace in SMTP_CONN->quotedata will store a reference instead of a copy. - // We are still forced to make another copy here for a couple ticks so we don't really - // get to save a copy in the method call. - $data = $text_headers . "\r\n" . $body; + if (is_resource($body)) + { + // file handle + $data = $body; + $text_headers = preg_replace('/[\r\n]+$/', '', $text_headers); + } else { + // Concatenate headers and body so it can be passed by reference to SMTP_CONN->data + // so preg_replace in SMTP_CONN->quotedata will store a reference instead of a copy. + // We are still forced to make another copy here for a couple ticks so we don't really + // get to save a copy in the method call. + $data = $text_headers . "\r\n" . $body; + + // unset old vars to save data and so we can pass into SMTP_CONN->data by reference. + unset($text_headers, $body); + } - // unset old vars to save data and so we can pass into SMTP_CONN->data by reference. - unset($text_headers, $body); - // Send the message's headers and the body as SMTP data. - if (PEAR::isError($result = $this->conn->data($data))) + if (PEAR::isError($result = $this->conn->data($data, $text_headers))) { $this->error = array('label' => 'smtperror', 'vars' => array('msg' => $result->getMessage())); $this->response[] .= "Failed to send data"; -- cgit v1.2.3