From 481cb9ffcf2443f95b77f99936e8edba5050b378 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 20 Jun 2013 14:22:25 +0200 Subject: [PATCH] Fix memory calculation when deciding if memory or file should be used for saved message. Handle saved message parts with file pointers for better performance (one temp file creation is skipped) --- plugins/libkolab/lib/kolab_storage_folder.php | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php index 702b6214..9d7042fe 100644 --- a/plugins/libkolab/lib/kolab_storage_folder.php +++ b/plugins/libkolab/lib/kolab_storage_folder.php @@ -688,13 +688,7 @@ class kolab_storage_folder $object['_mailbox'] = $this->name; } - if (is_array($raw_msg)) { - $result = $this->imap->save_message($this->name, $raw_msg[0], $raw_msg[1], true, null, null, $binary); - @unlink($raw_msg[0]); - } - else { - $result = $this->imap->save_message($this->name, $raw_msg, null, false, null, null, $binary); - } + $result = $this->imap->save_message($this->name, $raw_msg, null, false, null, null, $binary); // delete old message if ($result && !empty($object['_msguid']) && !empty($object['_mailbox'])) { @@ -861,6 +855,10 @@ class kolab_storage_folder /** * Creates source of the configuration object message * + * @param array $object The array that holds the data of the object. + * @param string $type The type of the kolab object. + * @param bool $binary Enables use of binary encoding of attachment(s) + * * @return mixed Message as string or array with two elements * (one for message file path, second for message headers) */ @@ -891,6 +889,7 @@ class kolab_storage_folder $mime = new Mail_mime("\r\n"); $rcmail = rcube::get_instance(); $headers = array(); + $files = array(); $part_id = 1; $encoding = $binary ? 'binary' : 'base64'; @@ -914,8 +913,9 @@ class kolab_storage_folder $memory += $attachment['size']; } - // 1.33 is for base64, we need at least 2x more memory than the message size - if ($memory * ($binary ? 1 : 1.33) * 2 > $mem_limit) { + // 1.33 is for base64, we need at least 4x more memory than the message size + if ($memory * ($binary ? 1 : 1.33) * 4 > $mem_limit) { + $marker = '%%%~~~' . md5(microtime(true) . $memory) . '~~~%%%'; $is_file = true; $temp_dir = unslashify($rcmail->config->get('temp_dir')); $mime->setParam('delay_file_io', true); @@ -969,14 +969,42 @@ class kolab_storage_folder $part_id++; } else if (!empty($att['path'])) { - $mime->addAttachment($att['path'], $att['mimetype'], $name, true, $encoding, 'attachment', '', '', '', null, null, '', RCUBE_CHARSET, $headers); + // To store binary files we can use faster method + // without writting full message content to a temporary file but + // directly to IMAP, see rcube_imap_generic::append(). + if ($is_file && $binary) { + $files[] = fopen($att['path'], 'r'); + $mime->addAttachment($marker, $att['mimetype'], $name, false, $encoding, 'attachment', '', '', '', null, null, '', RCUBE_CHARSET, $headers); + } + else { + $mime->addAttachment($att['path'], $att['mimetype'], $name, true, $encoding, 'attachment', '', '', '', null, null, '', RCUBE_CHARSET, $headers); + } $part_id++; } $object['_attachments'][$key]['id'] = $part_id; } - if ($is_file) { + if (!$is_file || !empty($files)) { + $message = $mime->getMessage(); + } + + // parse message and build message array with + // attachment file pointers in place of file markers + if (!empty($files)) { + $message = explode($marker, $message); + $tmp = array(); + + foreach ($message as $msg_part) { + $tmp[] = $msg_part; + if ($file = array_shift($files)) { + $tmp[] = $file; + } + } + $message = $tmp; + } + // write complete message body into temp file + else if ($is_file) { // use common temp dir $body_file = tempnam($temp_dir, 'rcmMsg'); @@ -988,11 +1016,10 @@ class kolab_storage_folder return false; } - return array($body_file, $mime->txtHeaders()); - } - else { - return $mime->getMessage(); + $message = array(trim($mime->txtHeaders()) . "\r\n\r\n", fopen($body_file, 'r')); } + + return $message; }