From 2baeac116abef9d5bcb748c687577d16dce868a0 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 16 Jan 2014 14:17:08 +0100 Subject: Fix sorting and paging in cross-folder searches --- program/steps/mail/list.inc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'program/steps/mail/list.inc') diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index 277564c38..4b2a955b7 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -75,6 +75,22 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search']) && $_SESSION['search_request'] == $_REQUEST['_search'] ) { $_SESSION['search'] = $RCMAIL->storage->get_search_set(); + + // multi-folder search + if ($_SESSION['search'][1]->multi) { + if (empty($cols)) + $cols = $_SESSION['list_attrib']['columns'] ? $_SESSION['list_attrib']['columns'] : (array)$CONFIG['list_cols']; + if (!in_array('folder', $cols)) + $cols[] = 'folder'; // Add 'folder' column to list + + // make message UIDs unique by appending the folder name + foreach ($a_headers as $i => $header) { + $header->uid .= '-'.$header->folder; + $header->flags['skip_mbox_check'] = true; + if ($header->parent_uid) + $header->parent_uid .= '-'.$header->folder; + } + } } // remove old search data else if (empty($_REQUEST['_search']) && isset($_SESSION['search'])) { -- cgit v1.2.3 From 2c33c7e38bc767330b4eebdc9e4d234caca72966 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 16 Jan 2014 15:41:19 +0100 Subject: Make message pagenav (prev/next) work with sorted multi-folder search results --- program/js/app.js | 3 +- program/lib/Roundcube/rcube_imap.php | 10 +++++- program/lib/Roundcube/rcube_result_multifolder.php | 40 +++++++++++++++++++--- program/steps/mail/func.inc | 4 ++- program/steps/mail/list.inc | 2 ++ program/steps/mail/search.inc | 8 ++--- 6 files changed, 56 insertions(+), 11 deletions(-) (limited to 'program/steps/mail/list.inc') diff --git a/program/js/app.js b/program/js/app.js index 2717e35d5..5eae82351 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -696,6 +696,7 @@ function rcube_webmail() break; case 'list': + // TODO: don't reset search but re-send for the new folder if (props && props != '') this.reset_qsearch(); if (this.env.action == 'compose' && this.env.extwin) @@ -1620,7 +1621,7 @@ function rcube_webmail() var uid = list.get_single_selection(); - if (uid && this.env.mailbox == this.env.drafts_mailbox) + if (uid && (this.env.messages[uid].mbox || this.env.mailbox) == this.env.drafts_mailbox) this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox }); else if (uid) this.show_message(uid, false, false); diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index e265946f2..847bcfa70 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -973,6 +973,9 @@ class rcube_imap extends rcube_storage $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 $slice_length = min($page_size, $cnt - ($to > $cnt ? $from : $to)); $a_msg_headers = array_slice(array_values($a_msg_headers), $from, $slice_length); @@ -1279,8 +1282,13 @@ class rcube_imap extends rcube_storage return new rcube_result_index($folder, '* SORT'); } + if ($this->search_set instanceof rcube_result_multifolder) { + $index = $this->search_set; + $index->folder = $folder; + // TODO: handle changed sorting + } // search result is an index with the same sorting? - if (($this->search_set instanceof rcube_result_index) + else if (($this->search_set instanceof rcube_result_index) && ((!$this->sort_field && !$this->search_sorted) || ($this->search_sorted && $this->search_sort_field == $this->sort_field)) ) { diff --git a/program/lib/Roundcube/rcube_result_multifolder.php b/program/lib/Roundcube/rcube_result_multifolder.php index 8d7ae5de8..277a6d1ea 100644 --- a/program/lib/Roundcube/rcube_result_multifolder.php +++ b/program/lib/Roundcube/rcube_result_multifolder.php @@ -28,8 +28,11 @@ class rcube_result_multifolder { public $multi = true; public $sets = array(); + public $folder; protected $meta = array(); + protected $index = array(); + protected $sorting; protected $order = 'ASC'; @@ -53,6 +56,19 @@ class rcube_result_multifolder $this->meta['count'] += $result->count(); } + /** + * Store a global index of (sorted) message UIDs + */ + public function set_message_index($headers, $sort_field, $sort_order) + { + $this->index = array(); + foreach ($headers as $header) { + $this->index[] = $header->uid . '-' . $header->folder; + } + + $this->sorting = $sort_field; + $this->order = $sort_order; + } /** * Checks the result from IMAP command @@ -119,7 +135,10 @@ class rcube_result_multifolder */ public function exists($msgid, $get_index = false) { - return false; + if (!empty($this->folder)) { + $msgid .= '-' . $this->folder; + } + return array_search($msgid, $this->index); } @@ -157,7 +176,7 @@ class rcube_result_multifolder */ public function get() { - return array(); + return $this->index; } @@ -179,9 +198,13 @@ class rcube_result_multifolder * * @return int Element value */ - public function get_element($index) + public function get_element($idx) { - return null; + switch ($idx) { + case 'FIRST': return $this->index[0]; + case 'LAST': return end($this->index); + default: return $this->index[$idx]; + } } @@ -195,6 +218,15 @@ class rcube_result_multifolder */ public function get_parameters($param=null) { + $params = array( + 'SORT' => $this->sorting, + 'ORDER' => $this->order, + ); + + if ($param !== null) { + return $params[$param]; + } + return $params; } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 3848ec540..45d4242f9 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -76,9 +76,11 @@ if (($_uid = get_input_value('_uid', RCUBE_INPUT_GPC)) && preg_match('/^\d+-[^, $_REQUEST['_uid'] = $_uid; unset($_uid); - if (empty($_REQUEST['_mbox']) && !empty($mbox)) { + // override mbox + if (!empty($mbox)) { $_GET['_mbox'] = $mbox; $_POST['_mbox'] = $mbox; + $RCMAIL->storage->set_folder(($_SESSION['mbox'] = $mbox)); } } diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index 4b2a955b7..a77d60f32 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -90,6 +90,8 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search']) if ($header->parent_uid) $header->parent_uid .= '-'.$header->folder; } + + $OUTPUT->command('select_folder', ''); } } // remove old search data diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc index 5ce9fe6e2..b45cdc0de 100644 --- a/program/steps/mail/search.inc +++ b/program/steps/mail/search.inc @@ -114,6 +114,10 @@ if ($search_str) { $RCMAIL->storage->search($mboxes, $search_str, $imap_charset, $sort_column); } +// Get the headers +$result_h = $RCMAIL->storage->list_messages($mbox, 1, $sort_column, rcmail_sort_order()); +$count = $RCMAIL->storage->count($mbox, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'); + // save search results in session if (!is_array($_SESSION['search'])) { $_SESSION['search'] = array(); @@ -125,10 +129,6 @@ if ($search_str) { } $_SESSION['search_request'] = $search_request; -// Get the headers -$result_h = $RCMAIL->storage->list_messages($mbox, 1, $sort_column, rcmail_sort_order()); -$count = $RCMAIL->storage->count($mbox, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'); - // Add 'folder' column to list if ($_SESSION['search'][1]->multi) { $a_show_cols = $_SESSION['list_attrib']['columns'] ? $_SESSION['list_attrib']['columns'] : (array)$CONFIG['list_cols']; -- cgit v1.2.3 From 19262e6eab19951393154d8e52fe141c63b5cd5d Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Mon, 20 Jan 2014 15:53:28 +0100 Subject: Code cleanup: remove duplicated code, don't trigger multi-folder search on simple filter requests --- program/js/app.js | 2 +- program/steps/mail/func.inc | 24 +++++++++++++++++++++--- program/steps/mail/list.inc | 22 +++------------------- program/steps/mail/search.inc | 39 +++++++++++---------------------------- 4 files changed, 36 insertions(+), 51 deletions(-) (limited to 'program/steps/mail/list.inc') diff --git a/program/js/app.js b/program/js/app.js index e276f6f96..675372107 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -6422,7 +6422,7 @@ function rcube_webmail() this.env.status_col = n; if (list) { - list.hide_column('folder', !(this.env.search_request || this.env.search_id)); + list.hide_column('folder', !(this.env.search_request || this.env.search_id) || this.env.search_scope == 'base'); list.init_header(); } }; diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index fd321e294..3487ec73f 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -363,7 +363,7 @@ function rcmail_message_list($attrib) /** * return javascript commands to add rows to the message list */ -function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null) +function rcmail_js_message_list($a_headers, $insert_top=false, $a_show_cols=null) { global $RCMAIL, $OUTPUT; @@ -382,6 +382,14 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null $head_replace = true; } + // add 'folder' column to list on multi-folder searches + $search_set = $RCMAIL->storage->get_search_set(); + $multifolder = $search_set && $search_set[1]->multi; + if ($multifolder && !in_array('folder', $a_show_cols)) { + $a_show_cols[] = 'folder'; + $head_replace = true; + } + $mbox = $RCMAIL->storage->get_folder(); // make sure 'threads' and 'subject' columns are present @@ -390,8 +398,6 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null if (!in_array('threads', $a_show_cols)) array_unshift($a_show_cols, 'threads'); - $_SESSION['list_attrib']['columns'] = $a_show_cols; - // Make sure there are no duplicated columns (#1486999) $a_show_cols = array_unique($a_show_cols); @@ -412,6 +418,10 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null $OUTPUT->command('set_message_coltypes', $a_show_cols, $thead, $smart_col); + if ($multifolder) { + $OUTPUT->command('select_folder', ''); + } + if (empty($a_headers)) { return; } @@ -428,6 +438,14 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null if (empty($header)) continue; + // make message UIDs unique by appending the folder name + if ($multifolder) { + $header->uid .= '-'.$header->folder; + $header->flags['skip_mbox_check'] = true; + if ($header->parent_uid) + $header->parent_uid .= '-'.$header->folder; + } + $a_msg_cols = array(); $a_msg_flags = array(); diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index a77d60f32..18f771d8b 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -42,6 +42,7 @@ if ($sort = rcube_utils::get_input_value('_sort', rcube_utils::INPUT_GET)) { // is there a set of columns for this request? if ($cols = rcube_utils::get_input_value('_cols', rcube_utils::INPUT_GET)) { + $_SESSION['list_attrib']['columns'] = $cols; if (!in_array('list_cols', $dont_override)) { $save_arr['list_cols'] = explode(',', $cols); } @@ -75,24 +76,6 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search']) && $_SESSION['search_request'] == $_REQUEST['_search'] ) { $_SESSION['search'] = $RCMAIL->storage->get_search_set(); - - // multi-folder search - if ($_SESSION['search'][1]->multi) { - if (empty($cols)) - $cols = $_SESSION['list_attrib']['columns'] ? $_SESSION['list_attrib']['columns'] : (array)$CONFIG['list_cols']; - if (!in_array('folder', $cols)) - $cols[] = 'folder'; // Add 'folder' column to list - - // make message UIDs unique by appending the folder name - foreach ($a_headers as $i => $header) { - $header->uid .= '-'.$header->folder; - $header->flags['skip_mbox_check'] = true; - if ($header->parent_uid) - $header->parent_uid .= '-'.$header->folder; - } - - $OUTPUT->command('select_folder', ''); - } } // remove old search data else if (empty($_REQUEST['_search']) && isset($_SESSION['search'])) { @@ -119,7 +102,8 @@ $OUTPUT->set_env('exists', $exists); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name); // add message rows -rcmail_js_message_list($a_headers, FALSE, $cols); +rcmail_js_message_list($a_headers, false, $cols); + if (isset($a_headers) && count($a_headers)) { if ($search_request) { $OUTPUT->show_message('searchsuccessful', 'confirmation', array('nr' => $count)); diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc index e13bc2ce5..e17552f7d 100644 --- a/program/steps/mail/search.inc +++ b/program/steps/mail/search.inc @@ -104,21 +104,21 @@ if (!empty($subject)) { foreach ($subject as $sub) { $search_str .= ' ' . $sub . ' ' . rcube_imap_generic::escape($search); } + + // search all, current or subfolders folders + if ($scope == 'all') { + $mboxes = $RCMAIL->storage->list_folders_subscribed('', '*', 'mail'); + } + else if ($scope == 'sub') { + $mboxes = $RCMAIL->storage->list_folders_subscribed($mbox, '*', 'mail'); + if ($mbox != 'INBOX' && $mboxes[0] == 'INBOX') + array_shift($mboxes); + } } $search_str = trim($search_str); $sort_column = rcmail_sort_column(); -// search all, current or subfolders folders -if ($scope == 'all') { - $mboxes = $RCMAIL->storage->list_folders_subscribed('', '*', 'mail'); -} -else if ($scope == 'sub') { - $mboxes = $RCMAIL->storage->list_folders_subscribed($mbox, '*', 'mail'); - if ($mbox != 'INBOX' && $mboxes[0] == 'INBOX') - array_shift($mboxes); -} - // execute IMAP search if ($search_str) { $RCMAIL->storage->search($mboxes, $search_str, $imap_charset, $sort_column); @@ -140,26 +140,9 @@ if ($search_str) { $_SESSION['search_request'] = $search_request; $_SESSION['search_scope'] = $scope; -// Add 'folder' column to list -if ($_SESSION['search'][1]->multi) { - $a_show_cols = $_SESSION['list_attrib']['columns'] ? $_SESSION['list_attrib']['columns'] : (array)$CONFIG['list_cols']; - if (!in_array('folder', $a_show_cols)) - $a_show_cols[] = 'folder'; - - // make message UIDs unique by appending the folder name - foreach ($result_h as $i => $header) { - $header->uid .= '-'.$header->folder; - $header->flags['skip_mbox_check'] = true; - if ($header->parent_uid) - $header->parent_uid .= '-'.$header->folder; - } - - $OUTPUT->command('select_folder', ''); -} - // Make sure we got the headers if (!empty($result_h)) { - rcmail_js_message_list($result_h, false, $a_show_cols); + rcmail_js_message_list($result_h, false); if ($search_str) { $OUTPUT->show_message('searchsuccessful', 'confirmation', array('nr' => $RCMAIL->storage->count(NULL, 'ALL'))); } -- cgit v1.2.3 From b95033e45a7dbc4b425bb6745facd6edb4af1edc Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Mon, 7 Apr 2014 10:25:15 +0200 Subject: Save list columns as array in session --- program/steps/mail/list.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'program/steps/mail/list.inc') diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index 18f771d8b..a8fc9eb8a 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -5,7 +5,7 @@ | program/steps/mail/list.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2007, The Roundcube Dev Team | + | Copyright (C) 2005-2014, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -42,7 +42,7 @@ if ($sort = rcube_utils::get_input_value('_sort', rcube_utils::INPUT_GET)) { // is there a set of columns for this request? if ($cols = rcube_utils::get_input_value('_cols', rcube_utils::INPUT_GET)) { - $_SESSION['list_attrib']['columns'] = $cols; + $_SESSION['list_attrib']['columns'] = explode(',', $cols); if (!in_array('list_cols', $dont_override)) { $save_arr['list_cols'] = explode(',', $cols); } -- cgit v1.2.3