summaryrefslogtreecommitdiff
path: root/program/lib/Roundcube/rcube_imap.php
diff options
context:
space:
mode:
Diffstat (limited to 'program/lib/Roundcube/rcube_imap.php')
-rw-r--r--program/lib/Roundcube/rcube_imap.php175
1 files changed, 94 insertions, 81 deletions
diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php
index 74c1f5324..3ca8a07c9 100644
--- a/program/lib/Roundcube/rcube_imap.php
+++ b/program/lib/Roundcube/rcube_imap.php
@@ -308,14 +308,7 @@ class rcube_imap extends rcube_storage
*/
public function set_folder($folder)
{
- if ($this->folder == $folder) {
- return;
- }
-
$this->folder = $folder;
-
- // clear messagecount cache for this folder
- $this->clear_messagecount($folder);
}
@@ -626,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) {
@@ -656,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)
@@ -791,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);
@@ -800,32 +793,47 @@ 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);
}
- if (empty($this->icache['threads'])) {
- if (!$this->check_connection()) {
- return new rcube_result_thread();
+ if (!empty($this->icache['threads'])) {
+ if ($this->icache['threads']->get_parameters('MAILBOX') == $folder) {
+ return $this->icache['threads'];
}
+ }
+
+ // get all threads
+ $result = $this->threads_direct($folder);
+
+ // add to internal (fast) cache
+ return $this->icache['threads'] = $result;
+ }
- // get all threads
- $result = $this->conn->thread($folder, $this->threading,
- $this->options['skip_deleted'] ? 'UNDELETED' : '', true);
- // add to internal (fast) cache
- $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();
}
- return $this->icache['threads'];
+ // get all threads
+ return $this->conn->thread($folder, $this->threading,
+ $this->options['skip_deleted'] ? 'UNDELETED' : '', true);
}
@@ -981,7 +989,7 @@ class rcube_imap extends rcube_storage
// use memory less expensive (and quick) method for big result set
$index = clone $this->index('', $this->sort_field, $this->sort_order);
// get messages uids for one page...
- $index->slice($start_msg, min($cnt-$from, $this->page_size));
+ $index->slice($from, min($cnt-$from, $this->page_size));
if ($slice) {
$index->slice(-$slice, $slice);
@@ -1096,16 +1104,17 @@ class rcube_imap extends rcube_storage
/**
- * Returns current status of folder
+ * Returns current status of a folder (compared to the last time use)
*
* We compare the maximum UID to determine the number of
* new messages because the RECENT flag is not reliable.
*
* @param string $folder Folder name
+ * @param array $diff Difference data
*
- * @return int Folder status
+ * @return int Folder status
*/
- public function folder_status($folder = null)
+ public function folder_status($folder = null, &$diff = array())
{
if (!strlen($folder)) {
$folder = $this->folder;
@@ -1126,6 +1135,9 @@ class rcube_imap extends rcube_storage
// got new messages
if ($new['maxuid'] > $old['maxuid']) {
$result += 1;
+ // get new message UIDs range, that can be used for example
+ // to get the data of these messages
+ $diff['new'] = ($old['maxuid'] + 1 < $new['maxuid'] ? ($old['maxuid']+1).':' : '') . $new['maxuid'];
}
// some messages has been deleted
if ($new['cnt'] < $old['cnt']) {
@@ -1176,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);
}
@@ -1240,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
@@ -1311,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);
@@ -1322,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)
{
@@ -1336,17 +1346,16 @@ class rcube_imap extends rcube_storage
// 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->get_capability('THREAD') != 'REFS') {
+ $sortby = $this->sort_field ? $this->sort_field : 'date';
+ $index = $this->index($this->folder, $sortby, $this->sort_order, 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();
}
}
@@ -1419,8 +1428,6 @@ class rcube_imap extends rcube_storage
*/
protected function search_index($folder, $criteria='ALL', $charset=NULL, $sort_field=NULL)
{
- $orig_criteria = $criteria;
-
if (!$this->check_connection()) {
if ($this->threading) {
return new rcube_result_thread();
@@ -1634,9 +1641,15 @@ class rcube_imap extends rcube_storage
// Example of structure for malformed MIME message:
// ("text" "plain" NIL NIL NIL "7bit" 2154 70 NIL NIL NIL)
if ($headers->ctype && !is_array($structure[0]) && $headers->ctype != 'text/plain'
- && strtolower($structure[0].'/'.$structure[1]) == 'text/plain') {
+ && strtolower($structure[0].'/'.$structure[1]) == 'text/plain'
+ ) {
+ // A special known case "Content-type: text" (#1488968)
+ if ($headers->ctype == 'text') {
+ $structure[1] = 'plain';
+ $headers->ctype = 'text/plain';
+ }
// we can handle single-part messages, by simple fix in structure (#1486898)
- if (preg_match('/^(text|application)\/(.*)/', $headers->ctype, $m)) {
+ else if (preg_match('/^(text|application)\/(.*)/', $headers->ctype, $m)) {
$structure[0] = $m[1];
$structure[1] = $m[2];
}
@@ -1660,11 +1673,21 @@ class rcube_imap extends rcube_storage
$struct = $this->structure_part($structure, 0, '', $headers);
}
- // don't trust given content-type
- if (empty($struct->parts) && !empty($headers->ctype)) {
- $struct->mime_id = '1';
- $struct->mimetype = strtolower($headers->ctype);
- list($struct->ctype_primary, $struct->ctype_secondary) = explode('/', $struct->mimetype);
+ // some workarounds on simple messages...
+ if (empty($struct->parts)) {
+ // ...don't trust given content-type
+ if (!empty($headers->ctype)) {
+ $struct->mime_id = '1';
+ $struct->mimetype = strtolower($headers->ctype);
+ list($struct->ctype_primary, $struct->ctype_secondary) = explode('/', $struct->mimetype);
+ }
+
+ // ...and charset (there's a case described in #1488968 where invalid content-type
+ // results in invalid charset in BODYSTRUCTURE)
+ if (!empty($headers->charset) && $headers->charset != $struct->ctype_parameters['charset']) {
+ $struct->charset = $headers->charset;
+ $struct->ctype_parameters['charset'] = $headers->charset;
+ }
}
$headers->structure = $struct;
@@ -2317,10 +2340,7 @@ class rcube_imap extends rcube_storage
// move messages
$moved = $this->conn->move($uids, $from_mbox, $to_mbox);
- // send expunge command in order to have the moved message
- // really deleted from the source folder
if ($moved) {
- $this->expunge_message($uids, $from_mbox, false);
$this->clear_messagecount($from_mbox);
$this->clear_messagecount($to_mbox);
}
@@ -2710,7 +2730,7 @@ class rcube_imap extends rcube_storage
// filter folders list according to rights requirements
if ($rights && $this->get_capability('ACL')) {
- $a_folders = $this->filter_rights($a_folders, $rights);
+ $a_mboxes = $this->filter_rights($a_mboxes, $rights);
}
// filter folders and sort them
@@ -2766,7 +2786,6 @@ class rcube_imap extends rcube_storage
*/
private function list_folders_update(&$result, $type = null)
{
- $delim = $this->get_hierarchy_delimiter();
$namespace = $this->get_namespace();
$search = array();
@@ -3355,7 +3374,6 @@ class rcube_imap extends rcube_storage
{
if (!empty($this->options['fetch_headers'])) {
$headers = explode(' ', $this->options['fetch_headers']);
- $headers = array_map('strtoupper', $headers);
}
else {
$headers = array();
@@ -3365,7 +3383,7 @@ class rcube_imap extends rcube_storage
$headers = array_merge($headers, $this->all_headers);
}
- return implode(' ', array_unique($headers));
+ return $headers;
}
@@ -3678,7 +3696,7 @@ class rcube_imap extends rcube_storage
{
if ($this->caching && !$this->cache) {
$rcube = rcube::get_instance();
- $ttl = $rcube->config->get('message_cache_lifetime', '10d');
+ $ttl = $rcube->config->get('imap_cache_ttl', '10d');
$this->cache = $rcube->get_cache('IMAP', $this->caching, $ttl);
}
@@ -3726,21 +3744,6 @@ class rcube_imap extends rcube_storage
}
}
- /**
- * Delete outdated cache entries
- */
- public function expunge_cache()
- {
- if ($this->mcache) {
- $ttl = rcube::get_instance()->config->get('message_cache_lifetime', '10d');
- $this->mcache->expunge($ttl);
- }
-
- if ($this->cache) {
- $this->cache->expunge();
- }
- }
-
/* --------------------------------
* message caching methods
@@ -3774,8 +3777,9 @@ class rcube_imap extends rcube_storage
if ($this->messages_caching && !$this->mcache) {
$rcube = rcube::get_instance();
if (($dbh = $rcube->get_dbh()) && ($userid = $rcube->get_user_id())) {
+ $ttl = $rcube->config->get('messages_cache_ttl', '10d');
$this->mcache = new rcube_imap_cache(
- $dbh, $this, $userid, $this->options['skip_deleted']);
+ $dbh, $this, $userid, $this->options['skip_deleted'], $ttl);
}
}
@@ -3797,6 +3801,15 @@ class rcube_imap extends rcube_storage
}
+ /**
+ * Delete outdated cache entries
+ */
+ function cache_gc()
+ {
+ rcube_imap_cache::gc();
+ }
+
+
/* --------------------------------
* protected methods
* --------------------------------*/
@@ -3830,7 +3843,7 @@ class rcube_imap extends rcube_storage
$delimiter = $this->get_hierarchy_delimiter();
// find default folders and skip folders starting with '.'
- foreach ($a_folders as $i => $folder) {
+ foreach ($a_folders as $folder) {
if ($folder[0] == '.') {
continue;
}
@@ -4090,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)