/** * Protected method for getting number of messages * * @param string $folder Folder name * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS] * @param boolean $force Force reading from server and update cache * @param boolean $status Enables storing folder status info (max UID/count), * required for folder_status() * @param boolean $no_search Ignore current search result * * @return int Number of messages * @see rcube_imap::count() */ protected function countmessages($folder, $mode = 'ALL', $force = false, $status = true, $no_search = false) { $mode = strtoupper($mode); // Count search set, assume search set is always up-to-date (don't check $force flag) // @TODO: this could be handled in more reliable way, e.g. a separate method // maybe in rcube_imap_search if (!$no_search && $this->search_string && $folder == $this->folder) { if ($mode == 'ALL') { return $this->search_set->count_messages(); } else { if ($mode == 'THREADS') { return $this->search_set->count(); } } } // EXISTS is a special alias for ALL, it allows to get the number // of all messages in a folder also when search is active and with // any skip_deleted setting $a_folder_cache = $this->get_cache('messagecount'); // return cached value if (!$force && is_array($a_folder_cache[$folder]) && isset($a_folder_cache[$folder][$mode])) { return $a_folder_cache[$folder][$mode]; } if (!is_array($a_folder_cache[$folder])) { $a_folder_cache[$folder] = array(); } if ($mode == 'THREADS') { $res = $this->threads($folder); $count = $res->count(); if ($status) { $msg_count = $res->count_messages(); $this->set_folder_stats($folder, 'cnt', $msg_count); $this->set_folder_stats($folder, 'maxuid', $msg_count ? $this->id2uid($msg_count, $folder) : 0); } } else { if (!$this->check_connection()) { return 0; } else { if ($mode == 'RECENT') { $count = $this->conn->countRecent($folder); } else { if ($mode != 'EXISTS' && !empty($this->options['skip_deleted'])) { $search_str = "ALL UNDELETED"; $keys = array('COUNT'); if ($mode == 'UNSEEN') { $search_str .= " UNSEEN"; } else { if ($this->messages_caching) { $keys[] = 'ALL'; } if ($status) { $keys[] = 'MAX'; } } // @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) $index = $this->conn->search($folder, $search_str, true, $keys); $count = $index->count(); if ($mode == 'ALL') { // Cache index data, will be used in index_direct() $this->icache['undeleted_idx'] = $index; if ($status) { $this->set_folder_stats($folder, 'cnt', $count); $this->set_folder_stats($folder, 'maxuid', $index->max()); } } } else { if ($mode == 'UNSEEN') { $count = $this->conn->countUnseen($folder); } else { $count = $this->conn->countMessages($folder); if ($status && $mode == 'ALL') { $this->set_folder_stats($folder, 'cnt', $count); $this->set_folder_stats($folder, 'maxuid', $count ? $this->id2uid($count, $folder) : 0); } } } } } } $a_folder_cache[$folder][$mode] = (int) $count; // write back to cache $this->update_cache('messagecount', $a_folder_cache); return (int) $count; }
/** * Private method for listing message headers * * @param string $mailbox Mailbox name * @param int $page Current page to list * @param string $sort_field Header field to sort by * @param string $sort_order Sort order [ASC|DESC] * @param int $slice Number of slice items to extract from result array * @return array Indexed array with message header objects * @access private * @see rcube_imap::list_headers */ private function _list_headers($mailbox = '', $page = NULL, $sort_field = NULL, $sort_order = NULL, $recursive = false, $slice = 0) { if (!strlen($mailbox)) { return array(); } // use saved message set if ($this->search_string && $mailbox == $this->mailbox) { return $this->_list_header_set($mailbox, $page, $sort_field, $sort_order, $slice); } if ($this->threading) { return $this->_list_thread_headers($mailbox, $page, $sort_field, $sort_order, $recursive, $slice); } $this->_set_sort_order($sort_field, $sort_order); $page = $page ? $page : $this->list_page; $cache_key = $mailbox . '.msg'; if ($this->caching_enabled) { // cache is OK, we can get messages from local cache // (assume cache is in sync when in recursive mode) if ($recursive || $this->check_cache_status($mailbox, $cache_key) > 0) { $start_msg = ($page - 1) * $this->page_size; $a_msg_headers = $this->get_message_cache($cache_key, $start_msg, $start_msg + $this->page_size, $this->sort_field, $this->sort_order); $result = array_values($a_msg_headers); if ($slice) { $result = array_slice($result, -$slice, $slice); } return $result; } else { if (!$recursive) { $this->sync_header_index($mailbox); return $this->_list_headers($mailbox, $page, $this->sort_field, $this->sort_order, true, $slice); } } } // retrieve headers from IMAP $a_msg_headers = array(); // use message index sort as default sorting (for better performance) if (!$this->sort_field) { if ($this->skip_deleted) { // @TODO: this could be cached if ($msg_index = $this->_search_index($mailbox, 'ALL UNDELETED')) { $max = max($msg_index); list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $msg_index = array_slice($msg_index, $begin, $end - $begin); } } else { if ($max = $this->conn->countMessages($mailbox)) { list($begin, $end) = $this->_get_message_range($max, $page); $msg_index = range($begin + 1, $end); } else { $msg_index = array(); } } if ($slice && $msg_index) { $msg_index = array_slice($msg_index, $this->sort_order == 'DESC' ? 0 : -$slice, $slice); } // fetch reqested headers from server if ($msg_index) { $this->_fetch_headers($mailbox, join(",", $msg_index), $a_msg_headers, $cache_key); } } else { if ($this->get_capability('SORT') && ($msg_index = $this->conn->sort($mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')) !== false) { if (!empty($msg_index)) { list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $max = max($msg_index); $msg_index = array_slice($msg_index, $begin, $end - $begin); if ($slice) { $msg_index = array_slice($msg_index, $this->sort_order == 'DESC' ? 0 : -$slice, $slice); } // fetch reqested headers from server $this->_fetch_headers($mailbox, join(',', $msg_index), $a_msg_headers, $cache_key); } } else { if ($a_index = $this->conn->fetchHeaderIndex($mailbox, "1:*", $this->sort_field, $this->skip_deleted)) { asort($a_index); // ASC $msg_index = array_keys($a_index); $max = max($msg_index); list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $msg_index = array_slice($msg_index, $begin, $end - $begin); if ($slice) { $msg_index = array_slice($msg_index, $this->sort_order == 'DESC' ? 0 : -$slice, $slice); } // fetch reqested headers from server $this->_fetch_headers($mailbox, join(",", $msg_index), $a_msg_headers, $cache_key); } } } // delete cached messages with a higher index than $max+1 // Changed $max to $max+1 to fix this bug : #1484295 $this->clear_message_cache($cache_key, $max + 1); // kick child process to sync cache // ... // return empty array if no messages found if (!is_array($a_msg_headers) || empty($a_msg_headers)) { return array(); } // use this class for message sorting $sorter = new rcube_header_sorter(); $sorter->set_sequence_numbers($msg_index); $sorter->sort_headers($a_msg_headers); if ($this->sort_order == 'DESC') { $a_msg_headers = array_reverse($a_msg_headers); } return array_values($a_msg_headers); }
/** * protected method for getting nr of messages * * @param string $folder Folder name * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT] * @param boolean $force Force reading from server and update cache * @param boolean $status Enables storing folder status info (max UID/count), * required for folder_status() * * @return int Number of messages * @see rcube_imap::count() */ protected function countmessages($folder, $mode = 'ALL', $force = false, $status = true) { $mode = strtoupper($mode); // count search set, assume search set is always up-to-date (don't check $force flag) if ($this->search_string && $folder == $this->folder && ($mode == 'ALL' || $mode == 'THREADS')) { if ($mode == 'ALL') { return $this->search_set->count_messages(); } else { return $this->search_set->count(); } } $a_folder_cache = $this->get_cache('messagecount'); // return cached value if (!$force && is_array($a_folder_cache[$folder]) && isset($a_folder_cache[$folder][$mode])) { return $a_folder_cache[$folder][$mode]; } if (!is_array($a_folder_cache[$folder])) { $a_folder_cache[$folder] = array(); } if ($mode == 'THREADS') { $res = $this->fetch_threads($folder, $force); $count = $res->count(); if ($status) { $msg_count = $res->count_messages(); $this->set_folder_stats($folder, 'cnt', $msg_count); $this->set_folder_stats($folder, 'maxuid', $msg_count ? $this->id2uid($msg_count, $folder) : 0); } } else { if (!$this->check_connection()) { return 0; } else { if ($mode == 'RECENT') { $count = $this->conn->countRecent($folder); } else { if (!empty($this->options['skip_deleted'])) { $search_str = "ALL UNDELETED"; $keys = array('COUNT'); if ($mode == 'UNSEEN') { $search_str .= " UNSEEN"; } else { if ($this->messages_caching) { $keys[] = 'ALL'; } if ($status) { $keys[] = 'MAX'; } } // @TODO: if $force==false && $mode == 'ALL' we could try to use cache index here // get message count using (E)SEARCH // not very performant but more precise (using UNDELETED) $index = $this->conn->search($folder, $search_str, true, $keys); $count = $index->count(); if ($mode == 'ALL') { // Cache index data, will be used in index_direct() $this->icache['undeleted_idx'] = $index; if ($status) { $this->set_folder_stats($folder, 'cnt', $count); $this->set_folder_stats($folder, 'maxuid', $index->max()); } } } else { if ($mode == 'UNSEEN') { $count = $this->conn->countUnseen($folder); } else { $count = $this->conn->countMessages($folder); if ($status) { $this->set_folder_stats($folder, 'cnt', $count); $this->set_folder_stats($folder, 'maxuid', $count ? $this->id2uid($count, $folder) : 0); } } } } } } $a_folder_cache[$folder][$mode] = (int) $count; // write back to cache $this->update_cache('messagecount', $a_folder_cache); return (int) $count; }
/** * Private method for listing message headers * * @param string $mailbox Mailbox name * @param int $page Current page to list * @param string $sort_field Header field to sort by * @param string $sort_order Sort order [ASC|DESC] * @param int $slice Number of slice items to extract from result array * * @return array Indexed array with message header objects * @see rcube_imap::list_headers */ private function _list_headers($mailbox = '', $page = NULL, $sort_field = NULL, $sort_order = NULL, $slice = 0) { if (!strlen($mailbox)) { return array(); } // use saved message set if ($this->search_string && $mailbox == $this->mailbox) { return $this->_list_header_set($mailbox, $page, $sort_field, $sort_order, $slice); } if ($this->threading) { return $this->_list_thread_headers($mailbox, $page, $sort_field, $sort_order, $slice); } $this->_set_sort_order($sort_field, $sort_order); $page = $page ? $page : $this->list_page; // Use messages cache if ($mcache = $this->get_mcache_engine()) { $msg_index = $mcache->get_index($mailbox, $this->sort_field, $this->sort_order); if (empty($msg_index)) { return array(); } $from = ($page - 1) * $this->page_size; $to = $from + $this->page_size; $msg_index = array_values($msg_index); // UIDs $is_uid = true; $sorted = true; if ($from || $to) { $msg_index = array_slice($msg_index, $from, $to - $from); } if ($slice) { $msg_index = array_slice($msg_index, -$slice, $slice); } $a_msg_headers = $mcache->get_messages($mailbox, $msg_index); } else { if (!$this->sort_field) { if ($this->skip_deleted) { // @TODO: this could be cached if ($msg_index = $this->_search_index($mailbox, 'ALL UNDELETED')) { list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $msg_index = array_slice($msg_index, $begin, $end - $begin); } } else { if ($max = $this->conn->countMessages($mailbox)) { list($begin, $end) = $this->_get_message_range($max, $page); $msg_index = range($begin + 1, $end); } else { $msg_index = array(); } } if ($slice && $msg_index) { $msg_index = array_slice($msg_index, $this->sort_order == 'DESC' ? 0 : -$slice, $slice); } // fetch reqested headers from server if ($msg_index) { $a_msg_headers = $this->fetch_headers($mailbox, $msg_index); } } else { if ($this->get_capability('SORT') && ($msg_index = $this->conn->sort($mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '', true)) !== false) { if (!empty($msg_index)) { list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $msg_index = array_slice($msg_index, $begin, $end - $begin); $is_uid = true; if ($slice) { $msg_index = array_slice($msg_index, $this->sort_order == 'DESC' ? 0 : -$slice, $slice); } // fetch reqested headers from server $a_msg_headers = $this->fetch_headers($mailbox, $msg_index, true); } } else { if ($msg_index = $this->conn->fetchHeaderIndex($mailbox, "1:*", $this->sort_field, $this->skip_deleted)) { asort($msg_index); // ASC $msg_index = array_keys($msg_index); list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $msg_index = array_slice($msg_index, $begin, $end - $begin); if ($slice) { $msg_index = array_slice($msg_index, $this->sort_order == 'DESC' ? 0 : -$slice, $slice); } // fetch reqested headers from server $a_msg_headers = $this->fetch_headers($mailbox, $msg_index); } } } } // return empty array if no messages found if (!is_array($a_msg_headers) || empty($a_msg_headers)) { return array(); } // use this class for message sorting $sorter = new rcube_header_sorter(); $sorter->set_index($msg_index, $is_uid); $sorter->sort_headers($a_msg_headers); if ($this->sort_order == 'DESC' && !$sorted) { $a_msg_headers = array_reverse($a_msg_headers); } return array_values($a_msg_headers); }