Aleksander Machniak
2013-06-13 603e048f7307e260bf0f064ed73700d6723a0e5c
Fix thread cache syncronization/validation (#1489028)
3 files modified
104 ■■■■■ changed files
CHANGELOG 1 ●●●● patch | view | raw | blame | history
program/lib/Roundcube/rcube_imap.php 57 ●●●●● patch | view | raw | blame | history
program/lib/Roundcube/rcube_imap_cache.php 46 ●●●●● patch | view | raw | blame | history
CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
- Fix thread cache syncronization/validation (#1489028)
- Fix default sorting of threaded list when THREAD=REFS isn't supported
- Fix list mode switch to 'List' after saving list settings in Larry skin (#1489164)
- Fix error when there's no writeable addressbook source (#1489162)
program/lib/Roundcube/rcube_imap.php
@@ -619,7 +619,7 @@
        }
        if ($mode == 'THREADS') {
            $res   = $this->fetch_threads($folder, $force);
            $res   = $this->threads($folder);
            $count = $res->count();
            if ($status) {
@@ -653,7 +653,7 @@
                }
            }
            // @TODO: if $force==false && $mode == 'ALL' we could try to use cache index here
            // @TODO: if $mode == 'ALL' we could try to use cache index here
            // get message count using (E)SEARCH
            // not very performant but more precise (using UNDELETED)
@@ -784,7 +784,7 @@
            $threads = $mcache->get_thread($folder);
        }
        else {
            $threads = $this->fetch_threads($folder);
            $threads = $this->threads($folder);
        }
        return $this->fetch_thread_headers($folder, $threads, $page, $slice);
@@ -794,13 +794,12 @@
     * Method for fetching threads data
     *
     * @param  string $folder  Folder name
     * @param  bool   $force   Use IMAP server, no cache
     *
     * @return rcube_imap_thread Thread data object
     */
    function fetch_threads($folder, $force = false)
    function threads($folder)
    {
        if (!$force && ($mcache = $this->get_mcache_engine())) {
        if ($mcache = $this->get_mcache_engine()) {
            // don't store in self's internal cache, cache has it's own internal cache
            return $mcache->get_thread($folder);
        }
@@ -811,16 +810,30 @@
            }
        }
        // get all threads
        $result = $this->threads_direct($folder);
        // add to internal (fast) cache
        return $this->icache['threads'] = $result;
    }
    /**
     * Method for direct fetching of threads data
     *
     * @param  string $folder Folder name
     *
     * @return rcube_imap_thread Thread data object
     */
    function threads_direct($folder)
    {
        if (!$this->check_connection()) {
            return new rcube_result_thread();
        }
        // get all threads
        $result = $this->conn->thread($folder, $this->threading,
        return $this->conn->thread($folder, $this->threading,
            $this->options['skip_deleted'] ? 'UNDELETED' : '', true);
        // add to internal (fast) cache
        return $this->icache['threads'] = $result;
    }
@@ -1175,12 +1188,13 @@
     * @param string $folder     Folder to get index from
     * @param string $sort_field Sort column
     * @param string $sort_order Sort order [ASC, DESC]
     * @param bool   $no_threads Get not threaded index
     *
     * @return rcube_result_index|rcube_result_thread List of messages (UIDs)
     */
    public function index($folder = '', $sort_field = NULL, $sort_order = NULL)
    public function index($folder = '', $sort_field = NULL, $sort_order = NULL, $no_threads = false)
    {
        if ($this->threading) {
        if (!$no_threads && $this->threading) {
            return $this->thread_index($folder, $sort_field, $sort_order);
        }
@@ -1239,17 +1253,13 @@
     * @param string $folder     Folder to get index from
     * @param string $sort_field Sort column
     * @param string $sort_order Sort order [ASC, DESC]
     * @param bool   $skip_cache Disables cache usage
     *
     * @return rcube_result_index Sorted list of message UIDs
     */
    public function index_direct($folder, $sort_field = null, $sort_order = null, $skip_cache = true)
    public function index_direct($folder, $sort_field = null, $sort_order = null)
    {
        if (!$skip_cache && ($mcache = $this->get_mcache_engine())) {
            $index = $mcache->get_index($folder, $sort_field, $sort_order);
        }
        // use message index sort as default sorting
        else if (!$sort_field) {
        if (!$sort_field) {
            // use search result from count() if possible
            if ($this->options['skip_deleted'] && !empty($this->icache['undeleted_idx'])
                && $this->icache['undeleted_idx']->get_parameters('ALL') !== null
@@ -1310,7 +1320,7 @@
        }
        else {
            // get all threads (default sort order)
            $threads = $this->fetch_threads($folder);
            $threads = $this->threads($folder);
        }
        $this->set_sort_order($sort_field, $sort_order);
@@ -1321,7 +1331,8 @@
    /**
     * Sort threaded result, using THREAD=REFS method
     * Sort threaded result, using THREAD=REFS method if available.
     * If not, use any method and re-sort the result in THREAD=REFS way.
     *
     * @param rcube_result_thread $threads  Threads result set
     */
@@ -1337,7 +1348,7 @@
        if ($this->get_capability('THREAD') != 'REFS') {
            $sortby = $this->sort_field ? $this->sort_field : 'date';
            $index  = $this->index_direct($this->folder, $sortby, $this->sort_order, false);
            $index  = $this->index($this->folder, $sortby, $this->sort_order, true);
            if (!$index->is_empty()) {
                $threads->sort($index);
@@ -4092,9 +4103,9 @@
        return $this->index($folder, $sort_field, $sort_order);
    }
    public function message_index_direct($folder, $sort_field = null, $sort_order = null, $skip_cache = true)
    public function message_index_direct($folder, $sort_field = null, $sort_order = null)
    {
        return $this->index_direct($folder, $sort_field, $sort_order, $skip_cache);
        return $this->index_direct($folder, $sort_field, $sort_order);
    }
    public function list_mailboxes($root='', $name='*', $filter=null, $rights=null, $skip_sort=false)
program/lib/Roundcube/rcube_imap_cache.php
@@ -235,8 +235,6 @@
     * If threaded index doesn't exist or is invalid, will be updated.
     *
     * @param string  $mailbox     Folder name
     * @param string  $sort_field  Sorting column
     * @param string  $sort_order  Sorting order (ASC|DESC)
     *
     * @return array Messages threaded index
     */
@@ -275,19 +273,11 @@
        if ($index === null) {
            // Get mailbox data (UIDVALIDITY, counters, etc.) for status check
            $mbox_data = $this->imap->folder_data($mailbox);
            if ($mbox_data['EXISTS']) {
                // get all threads (default sort order)
                $threads = $this->imap->fetch_threads($mailbox, true);
            }
            else {
                $threads = new rcube_result_thread($mailbox, '* THREAD');
            }
            $index['object'] = $threads;
            // Get THREADS result
            $index['object'] = $this->get_thread_data($mailbox, $mbox_data);
            // insert/update
            $this->add_thread_row($mailbox, $threads, $mbox_data, $exists);
            $this->add_thread_row($mailbox, $index['object'], $mbox_data, $exists);
        }
        $this->icache[$mailbox]['thread'] = $index;
@@ -1106,17 +1096,18 @@
            }
        }
        // Invalidate thread index (?)
        if (!$index['valid']) {
            $this->remove_thread($mailbox);
        }
        $sort_field = $index['sort_field'];
        $sort_order = $index['object']->get_parameters('ORDER');
        $exists     = true;
        // Validate index
        if (!$this->validate($mailbox, $index, $exists)) {
            // Invalidate (remove) thread index
            // if $exists=false it was already removed in validate()
            if ($exists) {
                $this->remove_thread($mailbox);
            }
            // Update index
            $data = $this->get_index_data($mailbox, $sort_field, $sort_order, $mbox_data);
        }
@@ -1224,6 +1215,25 @@
        return $index;
    }
    /**
     * Fetches thread data from IMAP server
     */
    private function get_thread_data($mailbox, $mbox_data = array())
    {
        if (empty($mbox_data)) {
            $mbox_data = $this->imap->folder_data($mailbox);
        }
        if ($mbox_data['EXISTS']) {
            // get all threads (default sort order)
            return $this->imap->threads_direct($mailbox);
        }
        return new rcube_result_thread($mailbox, '* THREAD');
    }
}
// for backward compat.