diff -rcp -x .svn roundcubemail-threading-20090225-6/config/main.inc.php.dist roundcubemail/config/main.inc.php.dist *** roundcubemail-threading-20090225-6/config/main.inc.php.dist 2009-02-25 21:54:38.000000000 +0000 --- roundcubemail/config/main.inc.php.dist 2009-03-16 13:37:05.000000000 +0000 *************** $rcmail_config['imap_auth_type'] = null; *** 70,75 **** --- 70,80 ---- $rcmail_config['imap_root'] = null; $rcmail_config['imap_delimiter'] = null; + // The default IMAP message THREAD retrieval algorithm. + // A common one for threading would be REFERENCES. + // Make sure that your IMAP server supports this! + $rcmail_config['imap_thread_algorithm'] = 'REFERENCES'; + // Automatically add this domain to user names for login // Only for IMAP servers that require full e-mail addresses for login // Specify an array with 'host' => 'domain' values to support multiple hosts *************** $rcmail_config['max_pagesize'] = 200; *** 315,321 **** $rcmail_config['mime_magic'] = '/usr/share/misc/magic'; // default sort col ! $rcmail_config['message_sort_col'] = 'date'; // default sort order $rcmail_config['message_sort_order'] = 'DESC'; --- 320,326 ---- $rcmail_config['mime_magic'] = '/usr/share/misc/magic'; // default sort col ! $rcmail_config['message_sort_col'] = 'default'; // default sort order $rcmail_config['message_sort_order'] = 'DESC'; diff -rcp -x .svn roundcubemail-threading-20090225-6/program/include/rcube_imap.php roundcubemail/program/include/rcube_imap.php *** roundcubemail-threading-20090225-6/program/include/rcube_imap.php 2009-02-25 22:17:17.000000000 +0000 --- roundcubemail/program/include/rcube_imap.php 2009-03-17 14:54:08.000000000 +0000 *************** class rcube_imap *** 483,489 **** if (!$force && is_array($a_mailbox_cache[$mailbox]) && isset($a_mailbox_cache[$mailbox][$mode])) return $a_mailbox_cache[$mailbox][$mode]; ! if ($this->get_capability('thread=references') && $mode == 'THREADS') $count = $this->_threadcount($mailbox); --- 483,489 ---- if (!$force && is_array($a_mailbox_cache[$mailbox]) && isset($a_mailbox_cache[$mailbox][$mode])) return $a_mailbox_cache[$mailbox][$mode]; ! if ($this->get_capability('thread='.rcmail::get_instance()->config->get('imap_thread_algorithm')) && $mode == 'THREADS') $count = $this->_threadcount($mailbox); *************** class rcube_imap *** 545,551 **** if ($sql_arr = $this->db->fetch_array($sql_result)) return $sql_arr[0]; } ! list ($thread_tree, $msg_depth, $has_children) = iil_C_Thread($this->conn, $mailbox, 'REFERENCES', 'ALL'); $this->update_thread_cache($mailbox, $thread_tree, $msg_depth, $has_children); return count($thread_tree); } --- 545,551 ---- if ($sql_arr = $this->db->fetch_array($sql_result)) return $sql_arr[0]; } ! list ($thread_tree, $msg_depth, $has_children) = iil_C_Thread($this->conn, $mailbox, rcmail::get_instance()->config->get('imap_thread_algorithm'), 'ALL'); $this->update_thread_cache($mailbox, $thread_tree, $msg_depth, $has_children); return count($thread_tree); } *************** class rcube_imap *** 585,591 **** $this->_set_sort_order($sort_field, $sort_order); ! $message_threading = $this->get_capability('thread=references') && rcmail::get_instance()->imap->threading; $max = $this->_messagecount($mailbox, $message_threading ? 'THREADS' : 'ALL'); --- 585,591 ---- $this->_set_sort_order($sort_field, $sort_order); ! $message_threading = $this->get_capability('thread='.rcmail::get_instance()->config->get('imap_thread_algorithm')) && rcmail::get_instance()->imap->threading; $max = $this->_messagecount($mailbox, $message_threading ? 'THREADS' : 'ALL'); *************** class rcube_imap *** 620,653 **** $msg_depth = $this->cache['__threads']['depth']; $has_children = $this->cache['__threads']['has_children']; } else { ! list ($thread_tree, $msg_depth, $has_children) = iil_C_Thread($this->conn, $mailbox, 'REFERENCES', 'ALL'); } $this->update_thread_cache($mailbox, $thread_tree, $msg_depth, $has_children); // the keys of thread_tree are the thread roots $roots = array_keys($thread_tree); } ! if ($this->get_capability('sort') && ($sort_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''))) { ! if ($this->sort_order == 'DESC') ! $sort_index = array_reverse($sort_index); ! } else { ! if ($this->sort_order == 'DESC') ! $msg_index = range($max, 1); ! else ! $msg_index = range(1, $max); } - - // sort the roots according to the order defined by $sort_index - $sorter = new rcube_thread_root_sorter(); - $sorter->set_sequence_numbers($sort_index); - $sorter->sort_threads($roots); // get the roots for this page ! $roots = array_slice($roots, $begin, $end - $begin); } if ($thread_cache_status > 0) { ! // get the children of $roots from the cache $threads = $this->get_thread_cache_threads($mailbox, $roots); $msg_index = array (); $msg_depth = array (); --- 620,651 ---- $msg_depth = $this->cache['__threads']['depth']; $has_children = $this->cache['__threads']['has_children']; } else { ! list ($thread_tree, $msg_depth, $has_children) = iil_C_Thread($this->conn, $mailbox, rcmail::get_instance()->config->get('imap_thread_algorithm'), 'ALL'); } $this->update_thread_cache($mailbox, $thread_tree, $msg_depth, $has_children); // the keys of thread_tree are the thread roots $roots = array_keys($thread_tree); } ! if ($this->sort_field != 'default' && ! $this->get_capability('sort') && ($sort_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''))) { ! // sort the roots according to the order defined by $sort_index ! $sorter = new rcube_thread_root_sorter(); ! $sorter->set_sequence_numbers($sort_index); ! $sorter->sort_threads($roots); } // get the roots for this page ! if ($this->sort_order == 'DESC') { ! $roots = array_slice($roots, $max - $end, $end - $begin); ! $roots = array_reverse($roots); ! } else { ! $roots = array_slice($roots, $begin, $end - $begin); ! } } if ($thread_cache_status > 0) { ! // get the children of $roots from the cache $threads = $this->get_thread_cache_threads($mailbox, $roots); $msg_index = array (); $msg_depth = array (); *************** class rcube_imap *** 669,681 **** } } } else { // no threading ! if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''))) { ! if ($this->sort_order == 'DESC') $msg_index = array_reverse($msg_index); ! $msg_index = array_slice($msg_index, $begin, $end - $begin); } else { if ($this->sort_order == 'DESC') ! $msg_index = range($end, $begin + 1); else $msg_index = range($begin + 1, $end); } --- 667,683 ---- } } } else { // no threading ! if ($this->sort_field != 'default' && ! $this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''))) { ! if ($this->sort_order == 'DESC') { ! $msg_index = array_slice($msg_index, $max - $end, $end - $begin); $msg_index = array_reverse($msg_index); ! } else { ! $msg_index = array_slice($msg_index, $begin, $end - $begin); ! } } else { if ($this->sort_order == 'DESC') ! $msg_index = range($max - $begin, $max - $end + 1); else $msg_index = range($begin + 1, $end); } *************** class rcube_imap *** 694,699 **** --- 696,703 ---- $deleted_count = $this->_fetch_headers($mailbox, $msgs, $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 + if ($message_threading) + $max = $this->_messagecount($mailbox, 'ALL'); $this->clear_message_cache($cache_key, $max + 1); } *************** class rcube_imap *** 957,963 **** // fetch complete message index $msg_count = $this->_messagecount($mailbox); ! if ($this->get_capability('sort') && ($a_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, ''))) { if ($this->sort_order == 'DESC') $a_index = array_reverse($a_index); --- 961,968 ---- // fetch complete message index $msg_count = $this->_messagecount($mailbox); ! if ($this->sort_field != 'default' && ! $this->get_capability('sort') && ($a_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, ''))) { if ($this->sort_order == 'DESC') $a_index = array_reverse($a_index); *************** class rcube_imap *** 1088,1094 **** */ function _search_index($mailbox, $criteria='ALL', $charset=NULL, $sort_field=NULL) { ! if ($sort_field && $this->get_capability('sort')) { $charset = $charset ? $charset : $this->default_charset; $a_messages = iil_C_Sort($this->conn, $mailbox, $sort_field, $criteria, FALSE, $charset); --- 1094,1100 ---- */ function _search_index($mailbox, $criteria='ALL', $charset=NULL, $sort_field=NULL) { ! if ($sort_field && $sort_field != 'default' && $this->get_capability('sort')) { $charset = $charset ? $charset : $this->default_charset; $a_messages = iil_C_Sort($this->conn, $mailbox, $sort_field, $criteria, FALSE, $charset); *************** class rcube_imap *** 2670,2675 **** --- 2676,2683 ---- if ($this->thread_caching_enabled && $this->caching_enabled && !isset ($this->cache[$cache_key])) { $this->cache[$cache_key] = array (); + if ($sort_field == 'default') + $sort_field = 'thread_id'; $sql_result = $this->db->limitquery("SELECT threads.idx FROM " . get_table_name('threads') . " diff -rcp -x .svn roundcubemail-threading-20090225-6/program/js/app.js roundcubemail/program/js/app.js *** roundcubemail-threading-20090225-6/program/js/app.js 2009-02-25 21:16:30.000000000 +0000 --- roundcubemail/program/js/app.js 2009-03-16 17:29:05.000000000 +0000 *************** function rcube_webmail() *** 574,579 **** --- 574,594 ---- var sort_order = a_sort[1] ? a_sort[1].toUpperCase() : null; var header; + // date column cycles between date and default + if (sort_col == 'date') + { + if (this.env.sort_col=='date' && this.env.sort_order=='ASC') + { + sort_col = 'default'; + sort_order = 'DESC'; + } + else if (this.env.sort_col=='default' && this.env.sort_order=='DESC') + { + sort_col = 'date'; + sort_order = 'DESC'; + } + } + // no sort order specified: toggle if (sort_order==null) { diff -rcp -x .svn roundcubemail-threading-20090225-6/program/lib/imap.inc roundcubemail/program/lib/imap.inc *** roundcubemail-threading-20090225-6/program/lib/imap.inc 2009-02-25 22:17:31.000000000 +0000 --- roundcubemail/program/lib/imap.inc 2009-03-17 14:42:36.000000000 +0000 *************** function iil_C_ID2UID(&$conn, $folder, $ *** 2139,2170 **** return $result; } ! function iil_ParseThread($str, $root, $parent, $depth, &$depthmap, &$haschildren) { $node = array(); ! if (strlen($str) == 0) ! return $node; ! if (substr($str, 0, 1) != '(') { ! $p = split('[^0-9]', $str, 2); ! $msg = $p[0]; ! $str = $p[1]; if (is_null($root)) $root = $msg; $depthmap[$msg] = $depth; $haschildren[$msg] = false; if (!is_null($parent)) $haschildren[$parent] = true; ! $node[$msg] = iil_ParseThread($str, $root, $msg, $depth + 1, $depthmap, $haschildren); } else { ! $off = 0; ! $len = strlen($str); ! while ($off < $len) { $start = $off; $off++; $n = 1; while ($n > 0) { $p = strpos($str, ')', $off); if ($p === false) { ! error_log("Can't parse (".substr($str, $off).") - mismatched brackets"); return $node; } $p1 = strpos($str, '(', $off); --- 2149,2186 ---- return $result; } ! // Don't be tempted to change $str to pass by reference to speed this up - it will slow it down by about ! // 7 times instead :-) See comments on http://uk2.php.net/references and this article: ! // http://derickrethans.nl/files/phparch-php-variables-article.pdf ! function iil_ParseThread($str, $begin, $end, $root, $parent, $depth, &$depthmap, &$haschildren) { $node = array(); ! if ($str[$begin] != '(') { ! $stop = $begin + strspn($str, "1234567890", $begin, $end - $begin); ! $msg = substr($str, $begin, $stop - $begin); ! if ($msg == 0) ! return $node; if (is_null($root)) $root = $msg; $depthmap[$msg] = $depth; $haschildren[$msg] = false; if (!is_null($parent)) $haschildren[$parent] = true; ! if ($stop + 1 < $end) ! $node[$msg] = iil_ParseThread($str, $stop + 1, $end, $root, $msg, $depth + 1, $depthmap, $haschildren); ! else ! $node[$msg] = array(); } else { ! $off = $begin; ! while ($off < $end) { $start = $off; $off++; $n = 1; while ($n > 0) { $p = strpos($str, ')', $off); if ($p === false) { ! error_log('Mismatched brackets parsing IMAP THREAD response:'); ! error_log(substr($str, ($begin < 10)?0:($begin - 10), $end - $begin + 20)); ! error_log(str_repeat(' ', $off - (($begin < 10)?0:($begin - 10)))); return $node; } $p1 = strpos($str, '(', $off); *************** function iil_ParseThread($str, $root, $p *** 2176,2183 **** $n--; } } ! $s = substr($str, $start + 1, $off - $start - 2); ! $node += iil_ParseThread($s, $root, $parent, $depth, $depthmap, $haschildren); } } --- 2190,2198 ---- $n--; } } ! $node += iil_ParseThread($str, $start + 1, $off - 1, $root, $parent, $depth, $depthmap, $haschildren); } } *************** function iil_C_Thread(&$conn, $folder, $ *** 2195,2201 **** $str = trim(substr($line, 8)); $depthmap = array(); $haschildren = array(); ! $tree = iil_ParseThread($str, null, null, 1, $depthmap, $haschildren); } } while (!iil_StartsWith($line, 'thrd1', true)); --- 2208,2216 ---- $str = trim(substr($line, 8)); $depthmap = array(); $haschildren = array(); ! $tree = iil_ParseThread($str, 0, strlen($str), null, null, 1, $depthmap, $haschildren); } } while (!iil_StartsWith($line, 'thrd1', true));