Aleksander Machniak
2013-07-10 bd284693027196517545616883d5cc43a3f0d39e
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) {
@@ -649,11 +649,11 @@
                    $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 @@
            $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 @@
    /**
     * 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 @@
            }
        }
        // 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,15 @@
     * @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
     * @param bool   $no_search  Get index not limited to search result (optionally)
     *
     * @return rcube_result_index|rcube_result_thread List of messages (UIDs)
     */
    public function index($folder = '', $sort_field = NULL, $sort_order = NULL)
    {
        if ($this->threading) {
    public function index($folder = '', $sort_field = NULL, $sort_order = NULL,
        $no_threads = false, $no_search = false
    ) {
        if (!$no_threads && $this->threading) {
            return $this->thread_index($folder, $sort_field, $sort_order);
        }
@@ -1192,43 +1208,50 @@
        // we have a saved search result, get index from there
        if ($this->search_string) {
            if ($this->search_threads) {
                $this->search($folder, $this->search_string, $this->search_charset, $this->sort_field);
            if ($this->search_set->is_empty()) {
                return new rcube_result_index($folder, '* SORT');
            }
            // use message index sort as default sorting
            if (!$this->sort_field || $this->search_sorted) {
                if ($this->sort_field && $this->search_sort_field != $this->sort_field) {
                    $this->search($folder, $this->search_string, $this->search_charset, $this->sort_field);
                }
            // search result is an index with the same sorting?
            if (($this->search_set instanceof rcube_result_index)
                && ((!$this->sort_field && !$this->search_sorted) ||
                    ($this->search_sorted && $this->search_sort_field == $this->sort_field))
            ) {
                $index = $this->search_set;
            }
            else if (!$this->check_connection()) {
                return new rcube_result_index();
            }
            else {
                $index = $this->conn->index($folder, $this->search_set->get(),
                    $this->sort_field, $this->options['skip_deleted'], true, true);
            // $no_search is enabled when we are not interested in
            // fetching index for search result, e.g. to sort
            // threaded search result we can use full mailbox index.
            // This makes possible to use index from cache
            else if (!$no_search) {
                if (!$this->sort_field) {
                    // No sorting needed, just build index from the search result
                    // @TODO: do we need to sort by UID here?
                    $search = $this->search_set->get_compressed();
                    $index  = new rcube_result_index($folder, '* ESEARCH ALL ' . $search);
                }
                else {
                    $index = $this->index_direct($folder, $this->search_charset,
                        $this->sort_field, $this->search_set);
                }
            }
            if ($this->sort_order != $index->get_parameters('ORDER')) {
                $index->revert();
            }
            if (isset($index)) {
                if ($this->sort_order != $index->get_parameters('ORDER')) {
                    $index->revert();
                }
            return $index;
                return $index;
            }
        }
        // check local cache
        if ($mcache = $this->get_mcache_engine()) {
            $index = $mcache->get_index($folder, $this->sort_field, $this->sort_order);
        }
        // fetch from IMAP server
        else {
            $index = $this->index_direct(
                $folder, $this->sort_field, $this->sort_order);
            return $mcache->get_index($folder, $this->sort_field, $this->sort_order);
        }
        return $index;
        // fetch from IMAP server
        return $this->index_direct($folder, $this->sort_field, $this->sort_order);
    }
@@ -1236,22 +1259,24 @@
     * Return sorted list of message UIDs ignoring current search settings.
     * Doesn't uses cache by default.
     *
     * @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
     * @param string         $folder     Folder to get index from
     * @param string         $sort_field Sort column
     * @param string         $sort_order Sort order [ASC, DESC]
     * @param rcube_result_* $search     Optional messages set to limit the result
     *
     * @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, $search = null)
    {
        if (!$skip_cache && ($mcache = $this->get_mcache_engine())) {
            $index = $mcache->get_index($folder, $sort_field, $sort_order);
        if (!empty($search)) {
            $search = $this->search_set->get_compressed();
        }
        // 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'])
            if (empty($search) && $this->options['skip_deleted']
                && !empty($this->icache['undeleted_idx'])
                && $this->icache['undeleted_idx']->get_parameters('ALL') !== null
                && $this->icache['undeleted_idx']->get_parameters('MAILBOX') == $folder
            ) {
@@ -1261,8 +1286,12 @@
                return new rcube_result_index();
            }
            else {
                $index = $this->conn->search($folder,
                    'ALL' .($this->options['skip_deleted'] ? ' UNDELETED' : ''), true);
                $query = $this->options['skip_deleted'] ? 'UNDELETED' : '';
                if ($search) {
                    $query = trim($query . ' UID ' . $search);
                }
                $index = $this->conn->search($folder, $query, true);
            }
        }
        else if (!$this->check_connection()) {
@@ -1271,13 +1300,18 @@
        // fetch complete message index
        else {
            if ($this->get_capability('SORT')) {
                $index = $this->conn->sort($folder, $sort_field,
                    $this->options['skip_deleted'] ? 'UNDELETED' : '', true);
                $query = $this->options['skip_deleted'] ? 'UNDELETED' : '';
                if ($search) {
                    $query = trim($query . ' UID ' . $search);
                }
                $index = $this->conn->sort($folder, $sort_field, $query, true);
            }
            if (empty($index) || $index->is_error()) {
                $index = $this->conn->index($folder, "1:*", $sort_field,
                    $this->options['skip_deleted'], false, true);
                $index = $this->conn->index($folder, $search ? $search : "1:*",
                    $sort_field, $this->options['skip_deleted'],
                    $search ? true : false, true);
            }
        }
@@ -1310,7 +1344,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,9 +1355,10 @@
    /**
     * 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)
    {
@@ -1335,17 +1370,16 @@
        // THREAD=REFERENCES:     sorting by sent date of root message
        // THREAD=REFS:           sorting by the most recent date in each thread
        if ($this->sort_field && ($this->sort_field != 'date' || $this->get_capability('THREAD') != 'REFS')) {
            $index = $this->index_direct($this->folder, $this->sort_field, $this->sort_order, false);
        if ($this->threading != 'REFS' || ($this->sort_field && $this->sort_field != 'date')) {
            $sortby = $this->sort_field ? $this->sort_field : 'date';
            $index  = $this->index($this->folder, $sortby, $this->sort_order, true, true);
            if (!$index->is_empty()) {
                $threads->sort($index);
            }
        }
        else {
            if ($this->sort_order != $threads->get_parameters('ORDER')) {
                $threads->revert();
            }
        else if ($this->sort_order != $threads->get_parameters('ORDER')) {
            $threads->revert();
        }
    }
@@ -2233,13 +2267,14 @@
    /**
     * Append a mail message (source) to a specific folder
     *
     * @param string  $folder  Target folder
     * @param string  $message The message source string or filename
     * @param string  $headers Headers string if $message contains only the body
     * @param boolean $is_file True if $message is a filename
     * @param array   $flags   Message flags
     * @param mixed   $date    Message internal date
     * @param bool    $binary  Enables BINARY append
     * @param string       $folder  Target folder
     * @param string|array $message The message source string or filename
     *                              or array (of strings and file pointers)
     * @param string       $headers Headers string if $message contains only the body
     * @param boolean      $is_file True if $message is a filename
     * @param array        $flags   Message flags
     * @param mixed        $date    Message internal date
     * @param bool         $binary  Enables BINARY append
     *
     * @return int|bool Appended message UID or True on success, False on error
     */
@@ -2632,7 +2667,6 @@
        if ($list_extended) {
            // unsubscribe non-existent folders, remove from the list
            // we can do this only when LIST response is available
            if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) {
                foreach ($a_folders as $idx => $folder) {
                    if (($opts = $this->conn->data['LIST'][$folder])
@@ -2645,19 +2679,14 @@
            }
        }
        else {
            // unsubscribe non-existent folders, remove them from the list,
            // we can do this only when LIST response is available
            if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) {
                foreach ($a_folders as $idx => $folder) {
                    if (!isset($this->conn->data['LIST'][$folder])
                        || in_array('\\Noselect', $this->conn->data['LIST'][$folder])
                    ) {
                        // Some servers returns \Noselect for existing folders
                        if (!$this->folder_exists($folder)) {
                            $this->conn->unsubscribe($folder);
                            unset($a_folders[$idx]);
                        }
                    }
            // unsubscribe non-existent folders, remove them from the list
            if (is_array($a_folders) && !empty($a_folders) && $name == '*') {
                $existing    = $this->list_folders($root, $name);
                $nonexisting = array_diff($a_folders, $existing);
                $a_folders   = array_diff($a_folders, $nonexisting);
                foreach ($nonexisting as $folder) {
                    $this->conn->unsubscribe($folder);
                }
            }
        }
@@ -4093,9 +4122,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)