Browse Source

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 :)

stekkel 22 years ago
parent
commit
5a36559d1b
2 changed files with 102 additions and 16 deletions
  1. 68 7
      functions/imap_general.php
  2. 34 9
      functions/mime.php

+ 68 - 7
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

+ 34 - 9
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;