From bffca14d964091b3256868bc42bcb9417a72629b Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Tue, 19 Jan 2016 03:37:29 -0500
Subject: [PATCH] Exit when imagecreatetruecolor() fails

---
 program/lib/Roundcube/rcube_imap_cache.php |  355 +++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 201 insertions(+), 154 deletions(-)

diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php
index 33e45c3..a402c18 100644
--- a/program/lib/Roundcube/rcube_imap_cache.php
+++ b/program/lib/Roundcube/rcube_imap_cache.php
@@ -1,6 +1,6 @@
 <?php
 
-/*
+/**
  +-----------------------------------------------------------------------+
  | This file is part of the Roundcube Webmail client                     |
  | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
@@ -27,6 +27,9 @@
  */
 class rcube_imap_cache
 {
+    const MODE_INDEX   = 1;
+    const MODE_MESSAGE = 2;
+
     /**
      * Instance of rcube_imap
      *
@@ -56,6 +59,13 @@
     private $ttl;
 
     /**
+     * Maximum cached message size
+     *
+     * @var int
+     */
+    private $threshold;
+
+    /**
      * Internal (in-memory) cache
      *
      * @var array
@@ -63,6 +73,7 @@
     private $icache = array();
 
     private $skip_deleted = false;
+    private $mode;
 
     /**
      * List of known flags. Thanks to this we can handle flag changes
@@ -96,9 +107,9 @@
      * @param int        $userid       User identifier
      * @param bool       $skip_deleted skip_deleted flag
      * @param string     $ttl          Expiration time of memcache/apc items
-     *
+     * @param int        $threshold    Maximum cached message size
      */
-    function __construct($db, $imap, $userid, $skip_deleted, $ttl=0)
+    function __construct($db, $imap, $userid, $skip_deleted, $ttl=0, $threshold=0)
     {
         // convert ttl string to seconds
         $ttl = get_offset_sec($ttl);
@@ -109,8 +120,16 @@
         $this->userid       = $userid;
         $this->skip_deleted = $skip_deleted;
         $this->ttl          = $ttl;
-    }
+        $this->threshold    = $threshold;
 
+        // cache all possible information by default
+        $this->mode = self::MODE_INDEX | self::MODE_MESSAGE;
+
+        // database tables
+        $this->index_table    = $db->table_name('cache_index', true);
+        $this->thread_table   = $db->table_name('cache_thread', true);
+        $this->messages_table = $db->table_name('cache_messages', true);
+    }
 
     /**
      * Cleanup actions (on shutdown).
@@ -121,6 +140,15 @@
         $this->icache = null;
     }
 
+    /**
+     * Set cache mode
+     *
+     * @param int $mode Cache mode
+     */
+    public function set_mode($mode)
+    {
+        $this->mode = $mode;
+    }
 
     /**
      * Return (sorted) messages index (UIDs).
@@ -144,7 +172,7 @@
         // Seek in internal cache
         if (array_key_exists('index', $this->icache[$mailbox])) {
             // The index was fetched from database already, but not validated yet
-            if (!array_key_exists('object', $this->icache[$mailbox]['index'])) {
+            if (empty($this->icache[$mailbox]['index']['validated'])) {
                 $index = $this->icache[$mailbox]['index'];
             }
             // We've got a valid index
@@ -221,6 +249,7 @@
         }
 
         $this->icache[$mailbox]['index'] = array(
+            'validated'  => true,
             'object'     => $data,
             'sort_field' => $sort_field,
             'modseq'     => !empty($index['modseq']) ? $index['modseq'] : $mbox_data['HIGHESTMODSEQ']
@@ -228,7 +257,6 @@
 
         return $data;
     }
-
 
     /**
      * Return messages thread.
@@ -285,7 +313,6 @@
         return $index['object'];
     }
 
-
     /**
      * Returns list of messages (headers). See rcube_imap::fetch_headers().
      *
@@ -300,38 +327,46 @@
             return array();
         }
 
-        // Fetch messages from cache
-        $sql_result = $this->db->query(
-            "SELECT uid, data, flags"
-            ." FROM ".$this->db->table_name('cache_messages')
-            ." WHERE user_id = ?"
-                ." AND mailbox = ?"
-                ." AND uid IN (".$this->db->array2list($msgs, 'integer').")",
-            $this->userid, $mailbox);
-
-        $msgs   = array_flip($msgs);
         $result = array();
 
-        while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
-            $uid          = intval($sql_arr['uid']);
-            $result[$uid] = $this->build_message($sql_arr);
+        if ($this->mode & self::MODE_MESSAGE) {
+            // Fetch messages from cache
+            $sql_result = $this->db->query(
+                "SELECT `uid`, `data`, `flags`"
+                ." FROM {$this->messages_table}"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?"
+                    ." AND `uid` IN (".$this->db->array2list($msgs, 'integer').")",
+                $this->userid, $mailbox);
 
-            if (!empty($result[$uid])) {
-                // save memory, we don't need message body here (?)
-                $result[$uid]->body = null;
+            $msgs = array_flip($msgs);
 
-                unset($msgs[$uid]);
+            while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
+                $uid          = intval($sql_arr['uid']);
+                $result[$uid] = $this->build_message($sql_arr);
+
+                if (!empty($result[$uid])) {
+                    // save memory, we don't need message body here (?)
+                    $result[$uid]->body = null;
+
+                    unset($msgs[$uid]);
+                }
             }
+
+            $msgs = array_flip($msgs);
         }
 
         // Fetch not found messages from IMAP server
         if (!empty($msgs)) {
-            $messages = $this->imap->fetch_headers($mailbox, array_keys($msgs), false, true);
+            $messages = $this->imap->fetch_headers($mailbox, $msgs, false, true);
 
             // Insert to DB and add to result list
             if (!empty($messages)) {
                 foreach ($messages as $msg) {
-                    $this->add_message($mailbox, $msg, !array_key_exists($msg->uid, $result));
+                    if ($this->mode & self::MODE_MESSAGE) {
+                        $this->add_message($mailbox, $msg, !array_key_exists($msg->uid, $result));
+                    }
+
                     $result[$msg->uid] = $msg;
                 }
             }
@@ -339,7 +374,6 @@
 
         return $result;
     }
-
 
     /**
      * Returns message data.
@@ -362,23 +396,29 @@
             return $this->icache['__message']['object'];
         }
 
-        $sql_result = $this->db->query(
-            "SELECT flags, data"
-            ." FROM ".$this->db->table_name('cache_messages')
-            ." WHERE user_id = ?"
-                ." AND mailbox = ?"
-                ." AND uid = ?",
-                $this->userid, $mailbox, (int)$uid);
+        if ($this->mode & self::MODE_MESSAGE) {
+            $sql_result = $this->db->query(
+                "SELECT `flags`, `data`"
+                ." FROM {$this->messages_table}"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?"
+                    ." AND `uid` = ?",
+                    $this->userid, $mailbox, (int)$uid);
 
-        if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
-            $message = $this->build_message($sql_arr);
-            $found   = true;
+            if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
+                $message = $this->build_message($sql_arr);
+                $found   = true;
+            }
         }
 
         // Get the message from IMAP server
         if (empty($message) && $update) {
             $message = $this->imap->get_message_headers($uid, $mailbox, true);
             // cache will be updated in close(), see below
+        }
+
+        if (!($this->mode & self::MODE_MESSAGE)) {
+            return $message;
         }
 
         // Save the message in internal cache, will be written to DB in close()
@@ -402,7 +442,6 @@
         return $message;
     }
 
-
     /**
      * Saves the message in cache.
      *
@@ -413,6 +452,10 @@
     function add_message($mailbox, $message, $force = false)
     {
         if (!is_object($message) || empty($message->uid)) {
+            return;
+        }
+
+        if (!($this->mode & self::MODE_MESSAGE)) {
             return;
         }
 
@@ -434,11 +477,11 @@
         // here will work as select, assume row exist if affected_rows=0)
         if (!$force) {
             $res = $this->db->query(
-                "UPDATE ".$this->db->table_name('cache_messages')
-                ." SET flags = ?, data = ?, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
-                ." WHERE user_id = ?"
-                    ." AND mailbox = ?"
-                    ." AND uid = ?",
+                "UPDATE {$this->messages_table}"
+                ." SET `flags` = ?, `data` = ?, `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?"
+                    ." AND `uid` = ?",
                 $flags, $msg, $this->userid, $mailbox, (int) $message->uid);
 
             if ($this->db->affected_rows($res)) {
@@ -450,8 +493,8 @@
 
         // insert new record
         $res = $this->db->query(
-            "INSERT INTO ".$this->db->table_name('cache_messages')
-            ." (user_id, mailbox, uid, flags, expires, data)"
+            "INSERT INTO {$this->messages_table}"
+            ." (`user_id`, `mailbox`, `uid`, `flags`, `expires`, `data`)"
             ." VALUES (?, ?, ?, ?, ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?)",
             $this->userid, $mailbox, (int) $message->uid, $flags, $msg);
 
@@ -459,18 +502,17 @@
         // thanks to ignore_key_errors "duplicate row" errors will be ignored
         if ($force && !$res && !$this->db->is_error($res)) {
             $this->db->query(
-                "UPDATE ".$this->db->table_name('cache_messages')
-                ." SET expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
-                    .", flags = ?, data = ?"
-                ." WHERE user_id = ?"
-                    ." AND mailbox = ?"
-                    ." AND uid = ?",
+                "UPDATE {$this->messages_table}"
+                ." SET `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
+                    .", `flags` = ?, `data` = ?"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?"
+                    ." AND `uid` = ?",
                 $flags, $msg, $this->userid, $mailbox, (int) $message->uid);
         }
 
         $this->db->set_option('ignore_key_errors', false);
     }
-
 
     /**
      * Sets the flag for specified message.
@@ -484,6 +526,10 @@
     function change_flag($mailbox, $uids, $flag, $enabled = false)
     {
         if (empty($uids)) {
+            return;
+        }
+
+        if (!($this->mode & self::MODE_MESSAGE)) {
             return;
         }
 
@@ -507,17 +553,18 @@
             }
         }
 
+        $binary_check = $this->db->db_provider == 'oracle' ? "BITAND(`flags`, %d)" : "(`flags` & %d)";
+
         $this->db->query(
-            "UPDATE ".$this->db->table_name('cache_messages')
-            ." SET expires = ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
-            .", flags = flags ".($enabled ? "+ $idx" : "- $idx")
-            ." WHERE user_id = ?"
-                ." AND mailbox = ?"
-                .(!empty($uids) ? " AND uid IN (".$this->db->array2list($uids, 'integer').")" : "")
-                ." AND (flags & $idx) ".($enabled ? "= 0" : "= $idx"),
+            "UPDATE {$this->messages_table}"
+            ." SET `expires` = ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
+            .", `flags` = `flags` ".($enabled ? "+ $idx" : "- $idx")
+            ." WHERE `user_id` = ?"
+                ." AND `mailbox` = ?"
+                .(!empty($uids) ? " AND `uid` IN (".$this->db->array2list($uids, 'integer').")" : "")
+                ." AND " . sprintf($binary_check, $idx) . ($enabled ? " = 0" : " = $idx"),
             $this->userid, $mailbox);
     }
-
 
     /**
      * Removes message(s) from cache.
@@ -527,10 +574,14 @@
      */
     function remove_message($mailbox = null, $uids = null)
     {
+        if (!($this->mode & self::MODE_MESSAGE)) {
+            return;
+        }
+
         if (!strlen($mailbox)) {
             $this->db->query(
-                "DELETE FROM ".$this->db->table_name('cache_messages')
-                ." WHERE user_id = ?",
+                "DELETE FROM {$this->messages_table}"
+                ." WHERE `user_id` = ?",
                 $this->userid);
         }
         else {
@@ -543,14 +594,13 @@
             }
 
             $this->db->query(
-                "DELETE FROM ".$this->db->table_name('cache_messages')
-                ." WHERE user_id = ?"
-                    ." AND mailbox = ?"
-                    .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""),
+                "DELETE FROM {$this->messages_table}"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?"
+                    .($uids !== null ? " AND `uid` IN (".$this->db->array2list((array)$uids, 'integer').")" : ""),
                 $this->userid, $mailbox);
         }
     }
-
 
     /**
      * Clears index cache.
@@ -565,18 +615,18 @@
         // otherwise use 'valid' flag to not loose HIGHESTMODSEQ value
         if ($remove) {
             $this->db->query(
-                "DELETE FROM ".$this->db->table_name('cache_index')
-                ." WHERE user_id = ?"
-                    .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""),
+                "DELETE FROM {$this->index_table}"
+                ." WHERE `user_id` = ?"
+                    .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
                 $this->userid
             );
         }
         else {
             $this->db->query(
-                "UPDATE ".$this->db->table_name('cache_index')
-                ." SET valid = 0"
-                ." WHERE user_id = ?"
-                    .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""),
+                "UPDATE {$this->index_table}"
+                ." SET `valid` = 0"
+                ." WHERE `user_id` = ?"
+                    .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
                 $this->userid
             );
         }
@@ -591,7 +641,6 @@
         }
     }
 
-
     /**
      * Clears thread cache.
      *
@@ -600,9 +649,9 @@
     function remove_thread($mailbox = null)
     {
         $this->db->query(
-            "DELETE FROM ".$this->db->table_name('cache_thread')
-            ." WHERE user_id = ?"
-                .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""),
+            "DELETE FROM {$this->thread_table}"
+            ." WHERE `user_id` = ?"
+                .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
             $this->userid
         );
 
@@ -615,7 +664,6 @@
             $this->icache = array();
         }
     }
-
 
     /**
      * Clears the cache.
@@ -630,7 +678,6 @@
         $this->remove_message($mailbox, $uids);
     }
 
-
     /**
      * Delete expired cache entries
      */
@@ -638,17 +685,17 @@
     {
         $rcube = rcube::get_instance();
         $db    = $rcube->get_dbh();
+        $now   = $db->now();
 
-        $db->query("DELETE FROM ".$db->table_name('cache_messages')
-              ." WHERE expires < " . $db->now());
+        $db->query("DELETE FROM " . $db->table_name('cache_messages', true)
+              ." WHERE `expires` < $now");
 
-        $db->query("DELETE FROM ".$db->table_name('cache_index')
-              ." WHERE expires < " . $db->now());
+        $db->query("DELETE FROM " . $db->table_name('cache_index', true)
+              ." WHERE `expires` < $now");
 
-        $db->query("DELETE FROM ".$db->table_name('cache_thread')
-              ." WHERE expires < " . $db->now());
+        $db->query("DELETE FROM ".$db->table_name('cache_thread', true)
+              ." WHERE `expires` < $now");
     }
-
 
     /**
      * Fetches index data from database
@@ -657,10 +704,10 @@
     {
         // Get index from DB
         $sql_result = $this->db->query(
-            "SELECT data, valid"
-            ." FROM ".$this->db->table_name('cache_index')
-            ." WHERE user_id = ?"
-                ." AND mailbox = ?",
+            "SELECT `data`, `valid`"
+            ." FROM {$this->index_table}"
+            ." WHERE `user_id` = ?"
+                ." AND `mailbox` = ?",
             $this->userid, $mailbox);
 
         if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@@ -686,7 +733,6 @@
         return null;
     }
 
-
     /**
      * Fetches thread data from database
      */
@@ -694,10 +740,10 @@
     {
         // Get thread from DB
         $sql_result = $this->db->query(
-            "SELECT data"
-            ." FROM ".$this->db->table_name('cache_thread')
-            ." WHERE user_id = ?"
-                ." AND mailbox = ?",
+            "SELECT `data`"
+            ." FROM {$this->thread_table}"
+            ." WHERE `user_id` = ?"
+                ." AND `mailbox` = ?",
             $this->userid, $mailbox);
 
         if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@@ -720,7 +766,6 @@
         return null;
     }
 
-
     /**
      * Saves index data into database
      */
@@ -735,14 +780,16 @@
             (int) $mbox_data['UIDNEXT'],
             $modseq ? $modseq : $mbox_data['HIGHESTMODSEQ'],
         );
-        $data = implode('@', $data);
+
+        $data    = implode('@', $data);
+        $expires = $this->ttl ? $this->db->now($this->ttl) : 'NULL';
 
         if ($exists) {
             $res = $this->db->query(
-                "UPDATE ".$this->db->table_name('cache_index')
-                ." SET data = ?, valid = 1, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
-                ." WHERE user_id = ?"
-                    ." AND mailbox = ?",
+                "UPDATE {$this->index_table}"
+                ." SET `data` = ?, `valid` = 1, `expires` = $expires"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?",
                 $data, $this->userid, $mailbox);
 
             if ($this->db->affected_rows($res)) {
@@ -753,25 +800,24 @@
         $this->db->set_option('ignore_key_errors', true);
 
         $res = $this->db->query(
-            "INSERT INTO ".$this->db->table_name('cache_index')
-            ." (user_id, mailbox, valid, expires, data)"
-            ." VALUES (?, ?, 1, ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') .", ?)",
+            "INSERT INTO {$this->index_table}"
+            ." (`user_id`, `mailbox`, `valid`, `expires`, `data`)"
+            ." VALUES (?, ?, 1, $expires, ?)",
             $this->userid, $mailbox, $data);
 
         // race-condition, insert failed so try update (#1489146)
         // thanks to ignore_key_errors "duplicate row" errors will be ignored
         if (!$exists && !$res && !$this->db->is_error($res)) {
             $res = $this->db->query(
-                "UPDATE ".$this->db->table_name('cache_index')
-                ." SET data = ?, valid = 1, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
-                ." WHERE user_id = ?"
-                    ." AND mailbox = ?",
+                "UPDATE {$this->index_table}"
+                ." SET `data` = ?, `valid` = 1, `expires` = $expires"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?",
                 $data, $this->userid, $mailbox);
         }
 
         $this->db->set_option('ignore_key_errors', false);
     }
-
 
     /**
      * Saves thread data into database
@@ -784,16 +830,16 @@
             (int) $mbox_data['UIDVALIDITY'],
             (int) $mbox_data['UIDNEXT'],
         );
-        $data = implode('@', $data);
 
-        $expires = ($this->ttl ? $this->db->now($this->ttl) : 'NULL');
+        $data    = implode('@', $data);
+        $expires = $this->ttl ? $this->db->now($this->ttl) : 'NULL';
 
         if ($exists) {
             $res = $this->db->query(
-                "UPDATE ".$this->db->table_name('cache_thread')
-                ." SET data = ?, expires = $expires"
-                ." WHERE user_id = ?"
-                    ." AND mailbox = ?",
+                "UPDATE {$this->thread_table}"
+                ." SET `data` = ?, `expires` = $expires"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?",
                 $data, $this->userid, $mailbox);
 
             if ($this->db->affected_rows($res)) {
@@ -804,8 +850,8 @@
         $this->db->set_option('ignore_key_errors', true);
 
         $res = $this->db->query(
-            "INSERT INTO ".$this->db->table_name('cache_thread')
-            ." (user_id, mailbox, expires, data)"
+            "INSERT INTO {$this->thread_table}"
+            ." (`user_id`, `mailbox`, `expires`, `data`)"
             ." VALUES (?, ?, $expires, ?)",
             $this->userid, $mailbox, $data);
 
@@ -813,16 +859,15 @@
         // thanks to ignore_key_errors "duplicate row" errors will be ignored
         if (!$exists && !$res && !$this->db->is_error($res)) {
             $this->db->query(
-                "UPDATE ".$this->db->table_name('cache_thread')
-                ." SET expires = $expires, data = ?"
-                ." WHERE user_id = ?"
-                    ." AND mailbox = ?",
+                "UPDATE {$this->thread_table}"
+                ." SET `expires` = $expires, `data` = ?"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?",
                 $data, $this->userid, $mailbox);
         }
 
         $this->db->set_option('ignore_key_errors', false);
     }
-
 
     /**
      * Checks index/thread validity
@@ -836,6 +881,8 @@
         if (empty($object)) {
             return false;
         }
+
+        $index['validated'] = true;
 
         // Get mailbox data (UIDVALIDITY, counters, etc.) for status check
         $mbox_data = $this->imap->folder_data($mailbox);
@@ -939,14 +986,13 @@
                 return false;
             }
             // ... and max UID
-            if ($object->max() != $this->imap->id2uid($mbox_data['EXISTS'], $mailbox, true)) {
+            if ($object->max() != $this->imap->id2uid($mbox_data['EXISTS'], $mailbox)) {
                 return false;
             }
         }
 
         return true;
     }
-
 
     /**
      * Synchronizes the mailbox.
@@ -1028,15 +1074,17 @@
         $removed = array();
 
         // Get known UIDs
-        $sql_result = $this->db->query(
-            "SELECT uid"
-            ." FROM ".$this->db->table_name('cache_messages')
-            ." WHERE user_id = ?"
-                ." AND mailbox = ?",
-            $this->userid, $mailbox);
+        if ($this->mode & self::MODE_MESSAGE) {
+            $sql_result = $this->db->query(
+                "SELECT `uid`"
+                ." FROM {$this->messages_table}"
+                ." WHERE `user_id` = ?"
+                    ." AND `mailbox` = ?",
+                $this->userid, $mailbox);
 
-        while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
-            $uids[] = $sql_arr['uid'];
+            while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
+                $uids[] = $sql_arr['uid'];
+            }
         }
 
         // Synchronize messages data
@@ -1067,12 +1115,12 @@
                     }
 
                     $this->db->query(
-                        "UPDATE ".$this->db->table_name('cache_messages')
-                        ." SET flags = ?, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
-                        ." WHERE user_id = ?"
-                            ." AND mailbox = ?"
-                            ." AND uid = ?"
-                            ." AND flags <> ?",
+                        "UPDATE {$this->messages_table}"
+                        ." SET `flags` = ?, `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
+                        ." WHERE `user_id` = ?"
+                            ." AND `mailbox` = ?"
+                            ." AND `uid` = ?"
+                            ." AND `flags` <> ?",
                         $flags, $this->userid, $mailbox, $uid, $flags);
                 }
             }
@@ -1122,7 +1170,6 @@
         $this->icache[$mailbox]['index']['object'] = $data;
     }
 
-
     /**
      * Converts cache row into message object.
      *
@@ -1146,7 +1193,6 @@
         return $message;
     }
 
-
     /**
      * Saves message stored in internal cache
      */
@@ -1168,17 +1214,23 @@
         }
     }
 
-
     /**
      * Prepares message object to be stored in database.
      *
      * @param rcube_message_header|rcube_message_part
      */
-    private function message_object_prepare(&$msg)
+    private function message_object_prepare(&$msg, &$size = 0)
     {
-        // Remove body too big (>25kB)
-        if ($msg->body && strlen($msg->body) > 25 * 1024) {
-            unset($msg->body);
+        // Remove body too big
+        if (isset($msg->body)) {
+            $length = strlen($msg->body);
+
+            if ($msg->body_modified || $size + $length > $this->threshold * 1024) {
+                unset($msg->body);
+            }
+            else {
+                $size += $length;
+            }
         }
 
         // Fix mimetype which might be broken by some code when message is displayed
@@ -1190,19 +1242,16 @@
 
         unset($msg->replaces);
 
-        if (is_array($msg->structure->parts)) {
-            foreach ($msg->structure->parts as $part) {
-                $this->message_object_prepare($part);
-            }
+        if (is_object($msg->structure)) {
+            $this->message_object_prepare($msg->structure, $size);
         }
 
         if (is_array($msg->parts)) {
             foreach ($msg->parts as $part) {
-                $this->message_object_prepare($part);
+                $this->message_object_prepare($part, $size);
             }
         }
     }
-
 
     /**
      * Fetches index data from IMAP server
@@ -1224,7 +1273,6 @@
         return $index;
     }
 
-
     /**
      * Fetches thread data from IMAP server
      */
@@ -1241,7 +1289,6 @@
 
         return new rcube_result_thread($mailbox, '* THREAD');
     }
-
 }
 
 // for backward compat.

--
Gitblit v1.9.1