Merge branch 'master' of github.com:roundcube/roundcubemail
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Search across multiple folders (#1485234) |
| | | - Improve UI integration of ACL settings |
| | | - Drop support for PHP < 5.3.7 |
| | | - Set In-Reply-To and References for forwarded messages (#1489593) |
| | |
| | | */ |
| | | public function download_folder() |
| | | { |
| | | @set_time_limit(0); |
| | | |
| | | $imap = rcmail::get_instance()->get_storage(); |
| | | $mbox_name = $imap->get_folder(); |
| | | |
| | |
| | | $_uid = $uids ?: rcube_utils::get_input_value('_uid', RCUBE_INPUT_GPC); |
| | | $_mbox = $mbox ?: (string)rcube_utils::get_input_value('_mbox', RCUBE_INPUT_GPC); |
| | | |
| | | if (is_array($uid)) { |
| | | return $uid; |
| | | // already a hash array |
| | | if (is_array($_uid) && !isset($_uid[0])) { |
| | | return $_uid; |
| | | } |
| | | |
| | | $result = array(); |
| | |
| | | } |
| | | } |
| | | else { |
| | | if (is_string($_uid)) |
| | | $_uid = explode(',', $_uid); |
| | | |
| | | // create a per-folder UIDs array |
| | | foreach (explode(',', $_uid) as $uid) { |
| | | foreach ((array)$_uid as $uid) { |
| | | list($uid, $mbox) = explode('-', $uid, 2); |
| | | if (empty($mbox)) |
| | | $mbox = $_mbox; |
| | |
| | | | Roundcube Webmail Client Script | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2013, The Roundcube Dev Team | |
| | | | Copyright (C) 2011-2013, Kolab Systems AG | |
| | | | Copyright (C) 2005-2014, The Roundcube Dev Team | |
| | | | Copyright (C) 2011-2014, Kolab Systems AG | |
| | | | | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | |
| | | this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return p.click_on_list(e); }; |
| | | |
| | | this.enable_command('toggle_status', 'toggle_flag', 'sort', true); |
| | | this.enable_command('set-listmode', this.env.threads && !this.env.search_request); |
| | | this.enable_command('set-listmode', this.env.threads && !this.is_multifolder_listing()); |
| | | |
| | | // load messages |
| | | this.command('list'); |
| | |
| | | break; |
| | | |
| | | case 'list': |
| | | // re-send for the selected folder |
| | | // re-send search query for the selected folder |
| | | if (props && props != '' && this.env.search_request && this.gui_objects.qsearchbox.value) { |
| | | var oldmbox = this.env.search_scope == 'all' ? '*' : this.env.mailbox; |
| | | this.env.search_mods[props] = this.env.search_mods[oldmbox]; // copy search mods from active search |
| | |
| | | case 'forward': |
| | | var uids = this.env.uid ? [this.env.uid] : (this.message_list ? this.message_list.get_selection() : []); |
| | | if (uids.length) { |
| | | url = { _forward_uid: this.uids_to_list(uids), _mbox: this.env.mailbox }; |
| | | url = { _forward_uid: this.uids_to_list(uids), _mbox: this.env.mailbox, _search: this.env.search_request }; |
| | | if (command == 'forward-attachment' || (!props && this.env.forward_attachment) || uids.length > 1) |
| | | url._attachment = 1; |
| | | this.open_compose_step(url); |
| | |
| | | { |
| | | switch (this.task) { |
| | | case 'mail': |
| | | return (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual) ? 1 : 0; |
| | | return (this.env.mailboxes[id] |
| | | && !this.env.mailboxes[id].virtual |
| | | && (this.env.mailboxes[id].id != this.env.mailbox || this.is_multifolder_listing())) ? 1 : 0; |
| | | |
| | | case 'settings': |
| | | return id != this.env.mailbox ? 1 : 0; |
| | |
| | | this.http_request('search', this.search_params(false, filter), lock); |
| | | }; |
| | | |
| | | // reload the current message listing |
| | | this.refresh_list = function() |
| | | { |
| | | this.list_mailbox(this.env.mailbox, this.env.current_page || 1, null, { _clear:1 }, true); |
| | | if (this.message_list) |
| | | this.message_list.clear_selection(); |
| | | }; |
| | | |
| | | // list messages of a specific mailbox |
| | | this.list_mailbox = function(mbox, page, sort, url) |
| | | this.list_mailbox = function(mbox, page, sort, url, update_only) |
| | | { |
| | | var win, target = window; |
| | | |
| | |
| | | this.select_all_mode = false; |
| | | } |
| | | |
| | | if (!update_only) { |
| | | // unselect selected messages and clear the list and message data |
| | | this.clear_message_list(); |
| | | |
| | |
| | | this.select_folder(mbox, '', true); |
| | | this.unmark_folder(mbox, 'recent', '', true); |
| | | this.env.mailbox = mbox; |
| | | } |
| | | |
| | | // load message list remotely |
| | | if (this.gui_objects.messagelist) { |
| | |
| | | }; |
| | | |
| | | // send remote request to load message list |
| | | this.list_mailbox_remote = function(mbox, page, post_data) |
| | | this.list_mailbox_remote = function(mbox, page, url) |
| | | { |
| | | // clear message list first |
| | | this.message_list.clear(); |
| | | |
| | | var lock = this.set_busy(true, 'loading'); |
| | | |
| | | if (typeof post_data != 'object') |
| | | post_data = {}; |
| | | post_data._mbox = mbox; |
| | | if (typeof url != 'object') |
| | | url = {}; |
| | | url._mbox = mbox; |
| | | if (page) |
| | | post_data._page = page; |
| | | url._page = page; |
| | | |
| | | this.http_request('list', post_data, lock); |
| | | this.http_request('list', url, lock); |
| | | }; |
| | | |
| | | // removes messages that doesn't exists from list selection array |
| | |
| | | return this.folder_selector(obj, function(folder) { ref.command('move', folder); }); |
| | | |
| | | // exit if current or no mailbox specified |
| | | if (!mbox || (mbox == this.env.mailbox && (!this.env.search_request || this.env.search_scope == 'base'))) |
| | | if (!mbox || (mbox == this.env.mailbox && !this.is_multifolder_listing())) |
| | | return; |
| | | |
| | | var lock = false, post_data = this.selection_post_data({_target_mbox: mbox}); |
| | |
| | | // @private |
| | | this._with_selected_messages = function(action, post_data, lock) |
| | | { |
| | | var count = 0, msg; |
| | | var count = 0, msg, |
| | | remove = (action == 'delete' || !this.is_multifolder_listing()); |
| | | |
| | | // update the list (remove rows, clear selection) |
| | | if (this.message_list) { |
| | |
| | | roots.push(root); |
| | | } |
| | | } |
| | | if (remove) |
| | | this.message_list.remove_row(id, (this.env.display_next && n == selection.length-1)); |
| | | } |
| | | // make sure there are no selected rows |
| | | if (!this.env.display_next) |
| | | if (!this.env.display_next && remove) |
| | | this.message_list.clear_selection(); |
| | | // update thread tree icons |
| | | for (n=0, len=roots.length; n<len; n++) { |
| | |
| | | if (count < 0) |
| | | post_data._count = (count*-1); |
| | | // remove threads from the end of the list |
| | | else if (count > 0) |
| | | else if (count > 0 && remove) |
| | | this.delete_excessive_thread_rows(); |
| | | |
| | | if (!remove) |
| | | post_data._refresh = 1; |
| | | |
| | | if (!lock) { |
| | | msg = action == 'move' ? 'movingmessage' : 'deletingmessage'; |
| | |
| | | var icn_src, uid, i, len, |
| | | rows = this.message_list ? this.message_list.rows : {}; |
| | | |
| | | if (typeof uids == 'string') |
| | | uids = String(uids).split(','); |
| | | |
| | | for (i=0, len=uids.length; i<len; i++) { |
| | |
| | | // with select_all mode checking |
| | | this.uids_to_list = function(uids) |
| | | { |
| | | return this.select_all_mode ? '*' : uids.join(','); |
| | | return this.select_all_mode ? '*' : (uids.length <= 1 ? uids.join(',') : uids); |
| | | }; |
| | | |
| | | // Sets title of the delete button |
| | |
| | | |
| | | this.env.search_mods[mbox] = mods; |
| | | }; |
| | | |
| | | this.is_multifolder_listing = function() |
| | | { |
| | | return typeof this.env.multifolder_listing != 'undefined' ? this.env.multifolder_listing : |
| | | (this.env.search_request && (this.env.search_scope || 'base') != 'base'); |
| | | } |
| | | |
| | | this.sent_successfully = function(type, msg, folders) |
| | | { |
| | |
| | | this.enable_command('expunge', this.env.exists); |
| | | this.enable_command('purge', this.purge_mailbox_test()); |
| | | this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount); |
| | | this.enable_command('set-listmode', this.env.threads && !this.is_multifolder_listing()); |
| | | |
| | | if ((response.action == 'list' || response.action == 'search') && this.message_list) { |
| | | this.msglist_select(this.message_list); |
| | |
| | | |
| | | // ignore not allowed attributes |
| | | if (!empty($allowed)) { |
| | | $is_data_attr = substr_compare($key, 'data-', 0, 5) === 0; |
| | | $is_data_attr = @substr_compare($key, 'data-', 0, 5) === 0; |
| | | if (!isset($allowed_f[$key]) && (!$is_data_attr || !isset($allowed_f['data-*']))) { |
| | | continue; |
| | | } |
| | |
| | | $a_msg_headers = array_slice(array_values($a_msg_headers), $from, $slice_length); |
| | | } |
| | | else { |
| | | if ($this->sort_order != $search_set->get_parameters('ORDER')) { |
| | | $search_set->revert(); |
| | | } |
| | | |
| | | // slice resultset first... |
| | | $fetch = array(); |
| | | foreach (array_slice($search_set->get(), $from, $slice_length) as $msg_id) { |
| | |
| | | } |
| | | |
| | | // decode combined UID-folder identifier |
| | | if (preg_match('/^\d+-[^,]+$/', $uid)) { |
| | | if (preg_match('/^\d+-.+/', $uid)) { |
| | | list($uid, $folder) = explode('-', $uid, 2); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // decode combined UID-folder identifier |
| | | if (preg_match('/^\d+-[^,]+$/', $uid)) { |
| | | if (preg_match('/^\d+-.+/', $uid)) { |
| | | list($uid, $folder) = explode('-', $uid, 2); |
| | | } |
| | | |
| | |
| | | if (empty($this->prop['groups']['scope'])) |
| | | $this->prop['groups']['scope'] = 'sub'; |
| | | // extend group objectclass => member attribute mapping |
| | | if (!empty($this->prop['groups']['event-panel-summary'])) |
| | | $this->group_types = array_merge($this->group_types, $this->prop['groups']['event-panel-summary']); |
| | | if (!empty($this->prop['groups']['class_member_attr'])) |
| | | $this->group_types = array_merge($this->group_types, $this->prop['groups']['class_member_attr']); |
| | | |
| | | // add group name attrib to the list of attributes to be fetched |
| | | $fetch_attributes[] = $this->prop['groups']['name_attr']; |
| | |
| | | // replace placeholders in filter settings |
| | | if (!empty($this->prop['filter'])) |
| | | $this->prop['filter'] = strtr($this->prop['filter'], $replaces); |
| | | if (!empty($this->prop['groups']['filter'])) |
| | | $this->prop['groups']['filter'] = strtr($this->prop['groups']['filter'], $replaces); |
| | | if (!empty($this->prop['groups']['member_filter'])) |
| | | $this->prop['groups']['member_filter'] = strtr($this->prop['groups']['member_filter'], $replaces); |
| | | |
| | | foreach (array('base_dn','filter','member_filter') as $k) { |
| | | if (!empty($this->prop['groups'][$k])) |
| | | $this->prop['groups'][$k] = strtr($this->prop['groups'][$k], $replaces); |
| | | } |
| | | |
| | | if (!empty($this->prop['group_filters'])) { |
| | | foreach ($this->prop['group_filters'] as $i => $gf) { |
| | |
| | | function __construct($uid, $folder = null) |
| | | { |
| | | // decode combined UID-folder identifier |
| | | if (preg_match('/^\d+-[^,]+$/', $uid)) { |
| | | if (preg_match('/^\d+-.+/', $uid)) { |
| | | list($uid, $folder) = explode('-', $uid, 2); |
| | | } |
| | | |
| | |
| | | public function revert() |
| | | { |
| | | $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC'; |
| | | $this->index = array(); |
| | | |
| | | // revert order in all sub-sets |
| | | foreach ($this->sets as $set) { |
| | | if ($this->order != $set->get_parameters('ORDER')) { |
| | | $set->revert(); |
| | | } |
| | | $folder = $set->get_parameters('MAILBOX'); |
| | | $index = array_map(function($uid) use ($folder) { return $uid . '-' . $folder; }, $set->get()); |
| | | $this->index = array_merge($this->index, $index); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // resolve _forward_uid=* to an absolute list of messages from a search result |
| | | if ($COMPOSE['param']['forward_uid'] == '*' && is_object($_SESSION['search'][1])) { |
| | | $COMPOSE['param']['forward_uid'] = $_SESSION['search'][1]->get(); |
| | | } |
| | | |
| | | // clean HTML message body which can be submitted by URL |
| | | if (!empty($COMPOSE['param']['body'])) { |
| | | $COMPOSE['param']['body'] = rcmail_wash_html($COMPOSE['param']['body'], array('safe' => false, 'inline_html' => true), array()); |
| | |
| | | $index = $storage->index(null, rcmail_sort_column(), rcmail_sort_order()); |
| | | $COMPOSE['forward_uid'] = $index->get(); |
| | | } |
| | | else if (strpos($COMPOSE['forward_uid'], ':')) { |
| | | else if (!is_array($COMPOSE['forward_uid']) && strpos($COMPOSE['forward_uid'], ':')) { |
| | | $COMPOSE['forward_uid'] = rcube_imap_generic::uncompressMessageSet($COMPOSE['forward_uid']); |
| | | } |
| | | else { |
| | | else if (is_string($COMPOSE['forward_uid'])) { |
| | | $COMPOSE['forward_uid'] = explode(',', $COMPOSE['forward_uid']); |
| | | } |
| | | |
| | |
| | | | program/steps/mail/copy.inc | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2013, 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. | |
| | |
| | | $target = rcube_utils::get_input_value('_target_mbox', rcube_utils::INPUT_POST, true); |
| | | |
| | | foreach (rcmail::get_uids() as $mbox => $uids) { |
| | | if ($mbox == $target) |
| | | $copied++; |
| | | else |
| | | $copied += (int)$RCMAIL->storage->copy_message($uids, $target, $mbox); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // remove mbox part from _uid |
| | | if (($_uid = get_input_value('_uid', RCUBE_INPUT_GPC)) && preg_match('/^\d+-[^,]+$/', $_uid)) { |
| | | if (($_uid = rcube_utils::get_input_value('_uid', RCUBE_INPUT_GPC)) && !is_array($_uid) && preg_match('/^\d+-.+/', $_uid)) { |
| | | list($_uid, $mbox) = explode('-', $_uid, 2); |
| | | if (isset($_GET['_uid'])) $_GET['_uid'] = $_uid; |
| | | if (isset($_POST['_uid'])) $_POST['_uid'] = $_uid; |
| | |
| | | $OUTPUT->command('select_folder', ''); |
| | | } |
| | | |
| | | $OUTPUT->set_env('multifolder_listing', $multifolder); |
| | | |
| | | if (empty($a_headers)) { |
| | | return; |
| | | } |
| | |
| | | $OUTPUT->set_env('exists', $exists); |
| | | $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name); |
| | | |
| | | // remove old message rows if commanded by the client |
| | | if (!empty($_REQUEST['_clear'])) { |
| | | $OUTPUT->command('clear_message_list'); |
| | | } |
| | | |
| | | // add message rows |
| | | rcmail_js_message_list($a_headers, false, $cols); |
| | | |
| | |
| | | |
| | | if ($flag == 'DELETED' && $read_deleted && !empty($_POST['_ruid'])) { |
| | | $ruids = rcube_utils::get_input_value('_ruid', rcube_utils::INPUT_POST); |
| | | $read = $RCMAIL->storage->set_flag($ruids, 'SEEN'); |
| | | foreach (rcmail::get_uids($ruids) as $mbox => $uids) { |
| | | $read += (int)$RCMAIL->storage->set_flag($uids, 'SEEN', $mbox); |
| | | } |
| | | |
| | | if ($read && !$skip_deleted) { |
| | | $OUTPUT->command('flag_deleted_as_read', $ruids); |
| | |
| | | $OUTPUT->show_message('messagemoved', 'confirmation'); |
| | | } |
| | | |
| | | if (!empty($_POST['_refresh'])) { |
| | | // FIXME: send updated message rows instead of releading the entire list |
| | | $OUTPUT->command('refresh_list'); |
| | | } |
| | | else { |
| | | $addrows = true; |
| | | } |
| | | } |
| | | // delete messages |
| | | else if ($RCMAIL->action=='delete' && !empty($_POST['_uid'])) { |
| | | foreach (rcmail::get_uids() as $mbox => $uids) { |