Thomas Bruederli
2014-06-04 3412e50b54e3daac8745234e21ab6e72be0ed165
program/lib/Roundcube/rcube_imap.php
@@ -955,35 +955,56 @@
            $sort_field = $this->sort_field;
            $search_set = $this->search_set;
            $this->sort_field = null;
            $this->page_size = 1000;  // fetch up to 1000 matching messages per folder
            $this->threading = false;
            $a_msg_headers = array();
            foreach ($search_set->sets as $resultset) {
                if (!$resultset->is_empty()) {
                    $this->search_set = $resultset;
                    $this->search_threads = $resultset instanceof rcube_result_thread;
                    $a_msg_headers = array_merge($a_msg_headers, $this->list_search_messages($resultset->get_parameters('MAILBOX'), 1));
                }
            }
            // do sorting and paging
            // prepare paging
            $cnt   = $search_set->count();
            $from  = ($page-1) * $page_size;
            $to    = $from + $page_size;
            $slice_length = min($page_size, $cnt - $from);
            // sort headers
            if (!$this->threading && !empty($a_msg_headers)) {
                $a_msg_headers = $this->conn->sortHeaders($a_msg_headers, $sort_field, $this->sort_order);
            // fetch resultset headers, sort and slice them
            if (!empty($sort_field)) {
                $this->sort_field = null;
                $this->page_size = 1000;  // fetch up to 1000 matching messages per folder
                $this->threading = false;
                $a_msg_headers = array();
                foreach ($search_set->sets as $resultset) {
                    if (!$resultset->is_empty()) {
                        $this->search_set = $resultset;
                        $this->search_threads = $resultset instanceof rcube_result_thread;
                        $a_msg_headers = array_merge($a_msg_headers, $this->list_search_messages($resultset->get_parameters('MAILBOX'), 1));
                    }
                }
                // sort headers
                if (!empty($a_msg_headers)) {
                    $a_msg_headers = $this->conn->sortHeaders($a_msg_headers, $sort_field, $this->sort_order);
                }
                // store (sorted) message index
                $search_set->set_message_index($a_msg_headers, $sort_field, $this->sort_order);
                // only return the requested part of the set
                $a_msg_headers = array_slice(array_values($a_msg_headers), $from, $slice_length);
            }
            else {
                if ($this->sort_order != $search_set->get_parameters('ORDER')) {
                    $search_set->revert();
                }
            // store (sorted) message index
            $search_set->set_message_index($a_msg_headers, $sort_field, $this->sort_order);
                // slice resultset first...
                $fetch = array();
                foreach (array_slice($search_set->get(), $from, $slice_length) as $msg_id) {
                    list($uid, $folder) = explode('-', $msg_id, 2);
                    $fetch[$folder][] = $uid;
                }
            // only return the requested part of the set
            $slice_length  = min($page_size, $cnt - $from);
            $a_msg_headers = array_slice(array_values($a_msg_headers), $from, $slice_length);
                // ... and fetch the requested set of headers
                $a_msg_headers = array();
                foreach ($fetch as $folder => $a_index) {
                    $a_msg_headers = array_merge($a_msg_headers, array_values($this->fetch_headers($folder, $a_index)));
                }
            }
            if ($slice) {
                $a_msg_headers = array_slice($a_msg_headers, -$slice, $slice);
@@ -1471,17 +1492,13 @@
     * @param  string  $str        Search criteria
     * @param  string  $charset    Search charset
     * @param  string  $sort_field Header field to sort by
     *
     * @return rcube_result_index  Search result object
     * @todo: Search criteria should be provided in non-IMAP format, eg. array
     */
    public function search($folder='', $str='ALL', $charset=NULL, $sort_field=NULL)
    {
        if (!$str) {
            $str = 'ALL';
        }
        if (empty($folder)) {
            $folder = $this->folder;
        }
        // multi-folder search
@@ -1496,6 +1513,16 @@
            $this->threading = false;
            $searcher = new rcube_imap_search($this->options, $this->conn);
            // set limit to not exceed the client's request timeout
            $searcher->set_timelimit(60);
            // continue existing incomplete search
            if (!empty($this->search_set) && $this->search_set->incomplete && $str == $this->search_string) {
                $searcher->set_results($this->search_set);
            }
            // execute the search
            $results = $searcher->exec(
                $folder,
                $str,
@@ -1506,11 +1533,16 @@
        }
        else {
            $folder = is_array($folder) ? $folder[0] : $folder;
            if (!strlen($folder)) {
                $folder = $this->folder;
            }
            $results = $this->search_index($folder, $str, $charset, $sort_field);
        }
        $this->set_search_set(array($str, $results, $charset, $sort_field,
            $this->threading || $this->search_sorted ? true : false));
        return $results;
    }
@@ -1524,19 +1556,26 @@
     */
    public function search_once($folder = null, $str = 'ALL')
    {
        if (!$str) {
            $str = 'ALL';
        }
        if (!strlen($folder)) {
            $folder = $this->folder;
        }
        if (!$this->check_connection()) {
            return new rcube_result_index();
        }
        $index = $this->conn->search($folder, $str, true);
        if (!$str) {
            $str = 'ALL';
        }
        // multi-folder search
        if (is_array($folder) && count($folder) > 1) {
            $searcher = new rcube_imap_search($this->options, $this->conn);
            $index = $searcher->exec($folder, $str, $this->default_charset);
        }
        else {
            $folder = is_array($folder) ? $folder[0] : $folder;
            if (!strlen($folder)) {
                $folder = $this->folder;
            }
            $index = $this->conn->search($folder, $str, true);
        }
        return $index;
    }
@@ -1664,11 +1703,28 @@
    public function refresh_search()
    {
        if (!empty($this->search_string)) {
            // FIXME: make this work with saved multi-folder searches
            $this->search('', $this->search_string, $this->search_charset, $this->search_sort_field);
            $this->search(
                is_object($this->search_set) ? $this->search_set->get_parameters('MAILBOX') : '',
                $this->search_string,
                $this->search_charset,
                $this->search_sort_field
            );
        }
        return $this->get_search_set();
    }
    /**
     * Flag certain result subsets as 'incomplete'.
     * For subsequent refresh_search() calls to only refresh the updated parts.
     */
    protected function set_search_dirty($folder)
    {
        if ($this->search_set && is_a($this->search_set, 'rcube_result_multifolder')) {
            if ($subset = $this->search_set->get_set($folder)) {
                $subset->incomplete = $this->search_set->incomplete = true;
            }
        }
    }
@@ -1683,13 +1739,13 @@
     */
    public function get_message_headers($uid, $folder = null, $force = false)
    {
        if (!strlen($folder)) {
            $folder = $this->folder;
        // decode combined UID-folder identifier
        if (preg_match('/^\d+-.+/', $uid)) {
            list($uid, $folder) = explode('-', $uid, 2);
        }
        // decode combined UID-folder identifier
        if (preg_match('/^\d+-[^,]+$/', $uid)) {
            list($uid, $folder) = explode('-', $uid);
        if (!strlen($folder)) {
            $folder = $this->folder;
        }
        // get cached headers
@@ -1702,6 +1758,9 @@
        else {
            $headers = $this->conn->fetchHeader(
                $folder, $uid, true, true, $this->get_fetch_headers());
            if (is_object($headers))
                $headers->folder = $folder;
        }
        return $headers;
@@ -1724,8 +1783,8 @@
        }
        // decode combined UID-folder identifier
        if (preg_match('/^\d+-[^,]+$/', $uid)) {
            list($uid, $folder) = explode('-', $uid);
        if (preg_match('/^\d+-.+/', $uid)) {
            list($uid, $folder) = explode('-', $uid, 2);
        }
        // Check internal cache
@@ -2374,6 +2433,8 @@
                    $this->clear_message_cache($folder, $all_mode ? null : explode(',', $uids));
                }
            }
            $this->set_search_dirty($folder);
        }
        return $result;
@@ -2421,6 +2482,17 @@
        if ($saved) {
            // increase messagecount of the target folder
            $this->set_messagecount($folder, 'ALL', 1);
            rcube::get_instance()->plugins->exec_hook('message_saved', array(
                    'folder'  => $folder,
                    'message' => $message,
                    'headers' => $headers,
                    'is_file' => $is_file,
                    'flags'   => $flags,
                    'date'    => $date,
                    'binary'  => $binary,
                    'result'  => $saved,
            ));
        }
        return $saved;
@@ -2472,6 +2544,9 @@
        if ($moved) {
            $this->clear_messagecount($from_mbox);
            $this->clear_messagecount($to_mbox);
            $this->set_search_dirty($from_mbox);
            $this->set_search_dirty($to_mbox);
        }
        // moving failed
        else if ($to_trash && $config->get('delete_always', false)) {
@@ -2488,7 +2563,7 @@
                if ($this->search_threads || $all_mode) {
                    $this->refresh_search();
                }
                else {
                else if (!$this->search_set->incomplete) {
                    $this->search_set->filter(explode(',', $uids), $this->folder);
                }
            }
@@ -2576,13 +2651,15 @@
            // unset threads internal cache
            unset($this->icache['threads']);
            $this->set_search_dirty($folder);
            // remove message ids from search set
            if ($this->search_set && $folder == $this->folder) {
                // threads are too complicated to just remove messages from set
                if ($this->search_threads || $all_mode) {
                    $this->refresh_search();
                }
                else {
                else if (!$this->search_set->incomplete) {
                    $this->search_set->filter(explode(',', $uids));
                }
            }