From 603e048f7307e260bf0f064ed73700d6723a0e5c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 13 Jun 2013 11:07:35 +0200 Subject: [PATCH] Fix thread cache syncronization/validation (#1489028) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_imap.php | 63 +++++++++++++--------- program/lib/Roundcube/rcube_imap_cache.php | 48 ++++++++++------- 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 23085d4f7..0b9712639 100644 --- a/CHANGELOG +++ b/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) diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index 73158c388..3ca8a07c9 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -619,7 +619,7 @@ class rcube_imap extends rcube_storage } if ($mode == 'THREADS') { - $res = $this->fetch_threads($folder, $force); + $res = $this->threads($folder); $count = $res->count(); if ($status) { @@ -649,11 +649,11 @@ class rcube_imap extends rcube_storage $keys[] = 'ALL'; } if ($status) { - $keys[] = 'MAX'; + $keys[] = 'MAX'; } } - // @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 @@ class rcube_imap extends rcube_storage $threads = $mcache->get_thread($folder); } else { - $threads = $this->fetch_threads($folder); + $threads = $this->threads($folder); } return $this->fetch_thread_headers($folder, $threads, $page, $slice); @@ -793,14 +793,13 @@ class rcube_imap extends rcube_storage /** * Method for fetching threads data * - * @param string $folder Folder name - * @param bool $force Use IMAP server, no cache + * @param string $folder Folder name * * @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 @@ class rcube_imap extends rcube_storage } } + // 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 @@ class rcube_imap extends rcube_storage * @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 @@ class rcube_imap extends rcube_storage * @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 @@ class rcube_imap extends rcube_storage } 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,9 +1331,10 @@ class rcube_imap extends rcube_storage /** - * 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 + * @param rcube_result_thread $threads Threads result set */ protected function sort_threads($threads) { @@ -1337,7 +1348,7 @@ class rcube_imap extends rcube_storage 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 @@ class rcube_imap extends rcube_storage 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) diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php index e2fd2a98b..a505d121a 100644 --- a/program/lib/Roundcube/rcube_imap_cache.php +++ b/program/lib/Roundcube/rcube_imap_cache.php @@ -234,9 +234,7 @@ class rcube_imap_cache * Return messages thread. * 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) + * @param string $mailbox Folder name * * @return array Messages threaded index */ @@ -275,19 +273,11 @@ class rcube_imap_cache 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 @@ class rcube_imap_cache } } - // 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 @@ class rcube_imap_cache 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.