From 7c7b74b374e2cbc848b8fff895123d26f0d9051d Mon Sep 17 00:00:00 2001 From: stekkel Date: Wed, 18 Jun 2003 18:39:12 +0000 Subject: [PATCH] DO NOT buffer base64 encoded attachments before we decode them. Instead decode them directly after we retrieved the data from the imapserver and echo te result. This will safe a lot of memmory usage :) git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@5078 7612ce4b-ef26-0410-bec9-ea0150e637f0 --- functions/imap_general.php | 75 ++++++++++++++++++++++++++++++++++---- functions/mime.php | 43 +++++++++++++++++----- 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/functions/imap_general.php b/functions/imap_general.php index dbc42968..d7109bc6 100755 --- a/functions/imap_general.php +++ b/functions/imap_general.php @@ -51,11 +51,14 @@ function sqimap_run_command_list ($imap_stream, $query, $handle_errors, &$respon } -function sqimap_run_command ($imap_stream, $query, $handle_errors, &$response, &$message, $unique_id = false) { +function sqimap_run_command ($imap_stream, $query, $handle_errors, &$response, + &$message, $unique_id = false,$filter=false, + $outputstream=false,$no_return=false) { if ($imap_stream) { $sid = sqimap_session_id($unique_id); fputs ($imap_stream, $sid . ' ' . $query . "\r\n"); - $read = sqimap_read_data ($imap_stream, $sid, $handle_errors, $response, $message, $query); + $read = sqimap_read_data ($imap_stream, $sid, $handle_errors, $response, + $message, $query,$filter,$outputstream,$no_return); return $read; } else { global $squirrelmail_language, $color; @@ -96,13 +99,69 @@ function sqimap_fgets($imap_stream) { return $results; } +function sqimap_fread($imap_stream,$iSize,$filter=false, + $outputstream=false, $no_return=false) { + if (!$filter || !$outputstream) { + $iBufferSize = $iSize; + } else { + $iBufferSize = 32768; + } + $iRet = $iSize - $iBufferSize; + $i = 0; + $results = ''; + while (($i * $iBufferSize) < $iRet) { + $sRead = fread($imap_stream,$iBufferSize); + if (!$sRead) { + $results = false; + break; + } + ++$i; + if ($filter) { + $filter($sRead); + } + if ($outputstream) { + if (is_resource($outputstream)) { + fwrite($outputstream,$sRead); + } else if ($outputstream == 'php://stdout') { + echo $sRead; + } + } + if ($no_return) { + $sRead = ''; + } + $results .= $sRead; + } + if ($results !== false) { + $sRead = fread($imap_stream,($iSize - ($i * $iBufferSize))); + if ($filter) { + $filter($sRead); + } + if ($outputstream) { + if (is_resource($outputstream)) { + fwrite($outputstream,$sRead); + } else if ($outputstream == 'php://stdout') { // FIXME + echo $sRead; + } + } + if ($no_return) { + $sRead = ''; + } + $results .= $sRead; + } + return $results; +} + + + /* * Reads the output from the IMAP stream. If handle_errors is set to true, * this will also handle all errors that are received. If it is not set, * the errors will be sent back through $response and $message */ -function sqimap_read_data_list ($imap_stream, $tag_uid, $handle_errors, &$response, &$message, $query = '') { +function sqimap_read_data_list ($imap_stream, $tag_uid, $handle_errors, + &$response, &$message, $query = '', + $filter = false, $outputstream = false, $no_return = false) { global $color, $squirrelmail_language; $read = ''; $tag_uid_a = explode(' ',trim($tag_uid)); @@ -171,7 +230,7 @@ function sqimap_read_data_list ($imap_stream, $tag_uid, $handle_errors, &$respon $j = strrpos($read,'{'); $iLit = substr($read,$j+1,-3); $fetch_data[] = $read; - $sLiteral = fread($imap_stream,$iLit); + $sLiteral = sqimap_fread($imap_stream,$iLit,$filter,$outputstream,$no_return); if ($sLiteral === false) { /* error */ break 4; /* while while switch while */ } @@ -335,9 +394,11 @@ function sqimap_read_data_list ($imap_stream, $tag_uid, $handle_errors, &$respon } } -function sqimap_read_data ($imap_stream, $tag_uid, $handle_errors, &$response, &$message, $query = '') { - $res = sqimap_read_data_list($imap_stream, $tag_uid, $handle_errors, $response, $message, $query); - +function sqimap_read_data ($imap_stream, $tag_uid, $handle_errors, + &$response, &$message, $query = '', + $filter=false,$outputstream=false,$no_return=false) { + $res = sqimap_read_data_list($imap_stream, $tag_uid, $handle_errors, + $response, $message, $query,$filter,$outputstream,$no_return); /* sqimap_read_data should be called for one response but since it just calls sqimap_read_data_list which handles multiple responses we need to check for that diff --git a/functions/mime.php b/functions/mime.php index 57ab2981..6c58f107 100644 --- a/functions/mime.php +++ b/functions/mime.php @@ -15,9 +15,9 @@ require_once(SM_PATH . 'functions/imap.php'); require_once(SM_PATH . 'functions/attachment_common.php'); -/* --------------------------------------------------------------------------------- */ -/* MIME DECODING */ -/* --------------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* MIME DECODING */ +/* -------------------------------------------------------------------------- */ /* This function gets the structure of a message and stores it in the "message" class. * It will return this object for use with all relevant header information and @@ -99,6 +99,7 @@ function mime_fetch_body($imap_stream, $id, $ent_id=1) { /* Do a bit of error correction. If we couldn't find the entity id, just guess * that it is the first one. That is usually the case anyway. */ + if (!$ent_id) { $cmd = "FETCH $id BODY[]"; } else { @@ -156,7 +157,6 @@ function mime_fetch_body($imap_stream, $id, $ent_id=1) { function mime_print_body_lines ($imap_stream, $id, $ent_id=1, $encoding) { global $uid_support; - $sid = sqimap_session_id($uid_support); /* Don't kill the connection if the browser is over a dialup * and it would take over 30 seconds to download it. * Don“t call set_time_limit in safe mode. @@ -165,14 +165,35 @@ function mime_print_body_lines ($imap_stream, $id, $ent_id=1, $encoding) { if (!ini_get('safe_mode')) { set_time_limit(0); } - if ($uid_support) { - $sid_s = substr($sid,0,strpos($sid, ' ')); + /* in case of base64 encoded attachments, do not buffer them. + Instead, echo the decoded attachment directly to screen */ + if (strtolower($encoding) == 'base64') { + if (!$ent_id) { + $query = "FETCH $id BODY[]"; + } else { + $query = "FETCH $id BODY[$ent_id]"; + } + sqimap_run_command($imap_stream,$query,true,$response,$message,$uid_support,'sqimap_base64_decode','php://stdout',true); } else { - $sid_s = $sid; + $body = mime_fetch_body ($imap_stream, $id, $ent_id); + echo decodeBody($body, $encoding); } - $body = mime_fetch_body ($imap_stream, $id, $ent_id); - echo decodeBody($body, $encoding); + /* + TODO, use the same method for quoted printable. + However, I assume that quoted printable attachments aren't that large + so the performancegain / memory usage drop will be minimal. + If we decide to add that then we need to adapt sqimap_fread because + we need to split te result on \n and fread doesn't stop at \n. That + means we also should provide $results from sqimap_fread (by ref) to + te function and set $no_return to false. The $filter function for + quoted printable should handle unsetting of $results. + */ + /* + TODO 2: find out how we write to the output stream php://stdout. fwrite + doesn't work because 'php://stdout isn't a stream. + */ + return; /* fputs ($imap_stream, "$sid FETCH $id BODY[$ent_id]\r\n"); @@ -518,6 +539,10 @@ function formatAttachments($message, $exclude_id, $mailbox, $id) { return $attachments; } +function sqimap_base64_decode(&$string) { + $string = base64_decode($string); +} + /* This function decodes the body depending on the encoding type. */ function decodeBody($body, $encoding) { global $show_html_default; -- 2.25.1