CHANGELOG
@@ -1,13 +1,16 @@ CHANGELOG Roundcube Webmail =========================== - Fix handling of signatures on draft edit (#1488798) - Fix so compacting of non-empty folder is possible also when messages list is empty (#1488858) - Allow forwarding of multiple emails (#1486854) - Fix big memory consumption of DB layer (#1488856) - Add workaround for IE<=8 bug where Content-Disposition:inline was ignored (#1488844) - Fix XSS vulnerability in vbscript: and data:text links handling (#1488850) - Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836) - Fix empty email on identities list after identity update (#1488834) - Add new identities_level: (4) one identity with possibility to edit only signature - Use Delivered-To header as a last resort for identity selection (#1488840) - Use Delivered-To and Envelope-To headers for identity selection (#1488840, #1488553) - Fix XSS vulnerability using Flash files (#1488828) - Fix absolute positioning in HTML messages (#1488819) - Fix cache (in)validation after setting \Deleted flag program/include/rcmail_output_html.php
@@ -670,7 +670,10 @@ */ public function just_parse($input) { return $this->parse_xml($input); $input = $this->parse_conditions($input); $input = $this->parse_xml($input); return $input; } program/js/app.js
@@ -224,9 +224,10 @@ this.set_button_titles(); this.env.message_commands = ['show', 'reply', 'reply-all', 'reply-list', 'forward', 'moveto', 'copy', 'delete', 'open', 'mark', 'edit', 'viewsource', 'download', 'print', 'load-attachment', 'show-headers', 'hide-headers', 'forward-attachment']; this.env.message_commands = ['show', 'reply', 'reply-all', 'reply-list', 'moveto', 'copy', 'delete', 'open', 'mark', 'edit', 'viewsource', 'print', 'load-attachment', 'show-headers', 'hide-headers', 'download', 'forward', 'forward-inline', 'forward-attachment']; if (this.env.action == 'show' || this.env.action == 'preview') { this.enable_command(this.env.message_commands, this.env.uid); @@ -650,13 +651,13 @@ break; case 'expunge': if (this.env.messagecount) if (this.env.exists) this.expunge_mailbox(this.env.mailbox); break; case 'purge': case 'empty-mailbox': if (this.env.messagecount) if (this.env.exists) this.purge_mailbox(this.env.mailbox); break; @@ -999,10 +1000,12 @@ break; case 'forward-attachment': case 'forward-inline': case 'forward': if (uid = this.get_single_uid()) { url = { _forward_uid: uid, _mbox: this.env.mailbox }; if (command == 'forward-attachment' || (!props && this.env.forward_attachment)) 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 }; if (command == 'forward-attachment' || (!props && this.env.forward_attachment) || uids.length > 1) url._attachment = 1; this.open_compose_step(url); } @@ -1526,7 +1529,7 @@ if (selected) { // Hide certain command buttons when Drafts folder is selected if (this.env.mailbox == this.env.drafts_mailbox) this.enable_command('reply', 'reply-all', 'reply-list', 'forward', 'forward-attachment', false); this.enable_command('reply', 'reply-all', 'reply-list', 'forward', 'forward-attachment', 'forward-inline', false); // Disable reply-list when List-Post header is not set else { var msg = this.env.messages[list.get_single_selection()]; @@ -1535,7 +1538,7 @@ } } // Multi-message commands this.enable_command('delete', 'moveto', 'copy', 'mark', (list.selection.length > 0 ? true : false)); this.enable_command('delete', 'moveto', 'copy', 'mark', 'forward', 'forward-attachment', list.selection.length > 0); // reset all-pages-selection if (selected || (list.selection.length && list.selection.length != list.rowcount)) @@ -2550,27 +2553,18 @@ if (mbox && typeof mbox === 'object') mbox = mbox.id; // exit if current or no mailbox specified or if selection is empty if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))) // exit if current or no mailbox specified if (!mbox || mbox == this.env.mailbox) return; var a_uids = [], n, selection, lock = this.display_message(this.get_label('copyingmessage'), 'loading'), post_data = {_mbox: this.env.mailbox, _target_mbox: mbox, _from: (this.env.action ? this.env.action : '')}; var post_data = this.selection_post_data({_target_mbox: mbox}); if (this.env.uid) a_uids[0] = this.env.uid; else { selection = this.message_list.get_selection(); for (n in selection) { a_uids.push(selection[n]); } } post_data._uid = this.uids_to_list(a_uids); // exit if selection is empty if (!post_data._uid) return; // send request to server this.http_post('copy', post_data, lock); this.http_post('copy', post_data, this.display_message(this.get_label('copyingmessage'), 'loading')); }; // move selected messages to the specified mailbox @@ -2579,12 +2573,15 @@ if (mbox && typeof mbox === 'object') mbox = mbox.id; // exit if current or no mailbox specified or if selection is empty if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))) // exit if current or no mailbox specified if (!mbox || mbox == this.env.mailbox) return; var lock = false, add_post = {_target_mbox: mbox, _from: (this.env.action ? this.env.action : '')}; var lock = false, post_data = this.selection_post_data({_target_mbox: mbox}); // exit if selection is empty if (!post_data._uid) return; // show wait message if (this.env.action == 'show') @@ -2595,7 +2592,7 @@ // Hide message command buttons until a message is selected this.enable_command(this.env.message_commands, false); this._with_selected_messages('moveto', lock, add_post); this._with_selected_messages('moveto', post_data, lock); }; // delete selected messages from the current mailbox @@ -2603,7 +2600,7 @@ { var uid, i, len, trash = this.env.trash_mailbox, list = this.message_list, selection = list ? $.merge([], list.get_selection()) : []; selection = list.get_selection(); // exit if no mailbox specified or if selection is empty if (!this.env.uid && !selection.length) @@ -2622,7 +2619,6 @@ return false; } // if there isn't a defined trash mailbox or we are in it // @TODO: we should check if defined trash mailbox exists else if (!trash || this.env.mailbox == trash) this.permanently_remove_messages(); // we're in Junk folder and delete_junk is enabled @@ -2645,32 +2641,29 @@ // delete the selected messages permanently this.permanently_remove_messages = function() { // exit if no mailbox specified or if selection is empty if (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length)) var post_data = this.selection_post_data(); // exit if selection is empty if (!post_data._uid) return; this.show_contentframe(false); this._with_selected_messages('delete', false, {_from: this.env.action ? this.env.action : ''}); this._with_selected_messages('delete', post_data); }; // Send a specifc moveto/delete request with UIDs of all selected messages // @private this._with_selected_messages = function(action, lock, post_data) this._with_selected_messages = function(action, post_data, lock) { var a_uids = [], count = 0, msg, lock; var count = 0, msg; if (typeof(post_data) != 'object') post_data = {}; if (this.env.uid) a_uids[0] = this.env.uid; else { // update the list (remove rows, clear selection) if (this.message_list) { var n, id, root, roots = [], selection = this.message_list.get_selection(); for (n=0, len=selection.length; n<len; n++) { id = selection[n]; a_uids.push(id); if (this.env.threading) { count += this.update_thread(id); @@ -2690,10 +2683,6 @@ } } // also send search request to get the right messages if (this.env.search_request) post_data._search = this.env.search_request; if (this.env.display_next && this.env.next_uid) post_data._next_uid = this.env.next_uid; @@ -2702,9 +2691,6 @@ // remove threads from the end of the list else if (count > 0) this.delete_excessive_thread_rows(); post_data._uid = this.uids_to_list(a_uids); post_data._mbox = this.env.mailbox; if (!lock) { msg = action == 'moveto' ? 'movingmessage' : 'deletingmessage'; @@ -2715,22 +2701,41 @@ this.http_post(action, post_data, lock); }; // build post data for message delete/move/copy/flag requests this.selection_post_data = function(data) { if (typeof(data) != 'object') data = {}; data._mbox = this.env.mailbox; if (!data._uid) { var uids = this.env.uid ? this.env.uid : this.message_list.get_selection(); data._uid = this.uids_to_list(uids); } if (this.env.action) data._from = this.env.action; // also send search request to get the right messages if (this.env.search_request) data._search = this.env.search_request; return data; }; // set a specific flag to one or more messages this.mark_message = function(flag, uid) { var a_uids = [], r_uids = [], len, n, id, selection, var a_uids = [], r_uids = [], len, n, id, list = this.message_list; if (uid) a_uids[0] = uid; else if (this.env.uid) a_uids[0] = this.env.uid; else if (list) { selection = list.get_selection(); for (n=0, len=selection.length; n<len; n++) { a_uids.push(selection[n]); } } else if (list) a_uids = list.get_selection(); if (!list) r_uids = a_uids; @@ -2738,12 +2743,12 @@ list.focus(); for (n=0, len=a_uids.length; n<len; n++) { id = a_uids[n]; if ((flag=='read' && list.rows[id].unread) || (flag=='unread' && !list.rows[id].unread) || (flag=='delete' && !list.rows[id].deleted) || (flag=='undelete' && list.rows[id].deleted) || (flag=='flagged' && !list.rows[id].flagged) || (flag=='unflagged' && list.rows[id].flagged)) if ((flag == 'read' && list.rows[id].unread) || (flag == 'unread' && !list.rows[id].unread) || (flag == 'delete' && !list.rows[id].deleted) || (flag == 'undelete' && list.rows[id].deleted) || (flag == 'flagged' && !list.rows[id].flagged) || (flag == 'unflagged' && list.rows[id].flagged)) { r_uids.push(id); } @@ -2774,16 +2779,12 @@ this.toggle_read_status = function(flag, a_uids) { var i, len = a_uids.length, post_data = {_uid: this.uids_to_list(a_uids), _flag: flag}, post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: flag}), lock = this.display_message(this.get_label('markingmessage'), 'loading'); // mark all message rows as read/unread for (i=0; i<len; i++) this.set_message(a_uids[i], 'unread', (flag=='unread' ? true : false)); // also send search request to get the right messages if (this.env.search_request) post_data._search = this.env.search_request; this.set_message(a_uids[i], 'unread', (flag == 'unread' ? true : false)); this.http_post('mark', post_data, lock); @@ -2795,16 +2796,12 @@ this.toggle_flagged_status = function(flag, a_uids) { var i, len = a_uids.length, post_data = {_uid: this.uids_to_list(a_uids), _flag: flag}, post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: flag}), lock = this.display_message(this.get_label('markingmessage'), 'loading'); // mark all message rows as flagged/unflagged for (i=0; i<len; i++) this.set_message(a_uids[i], 'flagged', (flag=='flagged' ? true : false)); // also send search request to get the right messages if (this.env.search_request) post_data._search = this.env.search_request; this.set_message(a_uids[i], 'flagged', (flag == 'flagged' ? true : false)); this.http_post('mark', post_data, lock); }; @@ -2843,25 +2840,20 @@ this.flag_as_undeleted = function(a_uids) { var i, len=a_uids.length, post_data = {_uid: this.uids_to_list(a_uids), _flag: 'undelete'}, var i, len = a_uids.length, post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: 'undelete'}), lock = this.display_message(this.get_label('markingmessage'), 'loading'); for (i=0; i<len; i++) this.set_message(a_uids[i], 'deleted', false); // also send search request to get the right messages if (this.env.search_request) post_data._search = this.env.search_request; this.http_post('mark', post_data, lock); return true; }; this.flag_as_deleted = function(a_uids) { var r_uids = [], post_data = {_uid: this.uids_to_list(a_uids), _flag: 'delete'}, post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: 'delete'}), lock = this.display_message(this.get_label('markingmessage'), 'loading'), rows = this.message_list ? this.message_list.rows : [], count = 0; @@ -2892,9 +2884,6 @@ this.delete_excessive_thread_rows(); } if (this.env.action) post_data._from = this.env.action; // ?? if (r_uids.length) post_data._ruid = this.uids_to_list(r_uids); @@ -2902,12 +2891,7 @@ if (this.env.skip_deleted && this.env.display_next && this.env.next_uid) post_data._next_uid = this.env.next_uid; // also send search request to get the right messages if (this.env.search_request) post_data._search = this.env.search_request; this.http_post('mark', post_data, lock); return true; }; // flag as read without mark request (called from backend) @@ -2987,7 +2971,7 @@ // test if purge command is allowed this.purge_mailbox_test = function() { return (this.env.messagecount && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox return (this.env.exists && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter)) || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter)))); }; @@ -6244,7 +6228,7 @@ case 'purge': case 'expunge': if (this.task == 'mail') { if (!this.env.messagecount) { if (!this.env.exists) { // clear preview pane content if (this.env.contentframe) this.show_contentframe(false); @@ -6264,7 +6248,8 @@ this.env.qsearch = null; case 'list': if (this.task == 'mail') { this.enable_command('show', 'expunge', 'select-all', 'select-none', (this.env.messagecount > 0)); this.enable_command('show', 'select-all', 'select-none', this.env.messagecount > 0); 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); program/lib/Roundcube/rcube_imap.php
@@ -151,7 +151,7 @@ $attempt = 0; do { $data = rcube::get_instance()->plugins->exec_hook('imap_connect', $data = rcube::get_instance()->plugins->exec_hook('storage_connect', array_merge($this->options, array('host' => $host, 'user' => $user, 'attempt' => ++$attempt))); @@ -571,7 +571,7 @@ * Get message count for a specific folder * * @param string $folder Folder name * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT] * @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() @@ -592,7 +592,7 @@ * protected method for getting nr of messages * * @param string $folder Folder name * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT] * @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() @@ -613,6 +613,10 @@ 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'); @@ -644,7 +648,7 @@ $count = $this->conn->countRecent($folder); } // use SEARCH for message counting else if (!empty($this->options['skip_deleted'])) { else if ($mode != 'EXISTS' && !empty($this->options['skip_deleted'])) { $search_str = "ALL UNDELETED"; $keys = array('COUNT'); @@ -683,8 +687,8 @@ } else { $count = $this->conn->countMessages($folder); if ($status) { $this->set_folder_stats($folder,'cnt', $count); if ($status && $mode == 'ALL') { $this->set_folder_stats($folder, 'cnt', $count); $this->set_folder_stats($folder, 'maxuid', $count ? $this->id2uid($count, $folder) : 0); } } program/lib/Roundcube/rcube_plugin_api.php
@@ -78,7 +78,8 @@ 'identity_save' => 'identity_update', // to be removed after 0.8 'imap_init' => 'storage_init', 'mailboxes_list' => 'storage_folders', 'mailboxes_list' => 'storage_folders', 'imap_connect' => 'storage_connect', ); /** program/lib/Roundcube/rcube_storage.php
@@ -65,6 +65,7 @@ 'MAIL-REPLY-TO', 'RETURN-PATH', 'DELIVERED-TO', 'ENVELOPE-TO', ); const UNKNOWN = 0; @@ -353,7 +354,7 @@ * Get messages count for a specific folder. * * @param string $folder Folder name * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT] * @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() program/steps/mail/check_recent.inc
@@ -75,13 +75,15 @@ if (!empty($_GET['_quota'])) $OUTPUT->command('set_quota', rcmail_quota_content()); $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS')); // "No-list" mode, don't get messages if (empty($_GET['_list'])) continue; // get overall message count; allow caching because rcube_storage::folder_status() did a refresh $list_mode = $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'; $all_count = $RCMAIL->storage->count(null, $list_mode, false, false); $all_count = $RCMAIL->storage->count($mbox_name, $list_mode, false, false); $page = $RCMAIL->storage->get_page(); $page_size = $RCMAIL->storage->get_pagesize(); program/steps/mail/compose.inc
@@ -151,30 +151,38 @@ // get reference message and set compose mode if ($msg_uid = $COMPOSE['param']['draft_uid']) { $RCMAIL->storage->set_folder($CONFIG['drafts_mbox']); $compose_mode = RCUBE_COMPOSE_DRAFT; $RCMAIL->storage->set_folder($CONFIG['drafts_mbox']); } else if ($msg_uid = $COMPOSE['param']['reply_uid']) else if ($msg_uid = $COMPOSE['param']['reply_uid']) { $compose_mode = RCUBE_COMPOSE_REPLY; else if ($msg_uid = $COMPOSE['param']['forward_uid']) $OUTPUT->set_env('compose_mode', 'reply'); } else if ($msg_uid = $COMPOSE['param']['forward_uid']) { $compose_mode = RCUBE_COMPOSE_FORWARD; else if ($msg_uid = $COMPOSE['param']['uid']) $OUTPUT->set_env('compose_mode', 'forward'); $COMPOSE['forward_uid'] = $msg_uid; $COMPOSE['as_attachment'] = !empty($COMPOSE['param']['attachment']); } else if ($msg_uid = $COMPOSE['param']['uid']) { $compose_mode = RCUBE_COMPOSE_EDIT; } $config_show_sig = $RCMAIL->config->get('show_sig', 1); if ($config_show_sig == 1) if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) { // don't add signature in draft/edit mode, we'll also not remove the old-one } else if ($config_show_sig == 1) $OUTPUT->set_env('show_sig', true); else if ($config_show_sig == 2 && (empty($compose_mode) || $compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT)) else if ($config_show_sig == 2 && empty($compose_mode)) $OUTPUT->set_env('show_sig', true); else if ($config_show_sig == 3 && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD)) $OUTPUT->set_env('show_sig', true); else $OUTPUT->set_env('show_sig', false); // set line length for body wrapping $LINE_LENGTH = $RCMAIL->config->get('line_length', 72); if (!empty($msg_uid)) if (!empty($msg_uid) && empty($COMPOSE['as_attachment'])) { // similar as in program/steps/mail/show.inc // re-set 'prefer_html' to have possibility to use html part for compose @@ -188,16 +196,13 @@ if (!empty($MESSAGE->headers->charset)) $RCMAIL->storage->set_charset($MESSAGE->headers->charset); if ($compose_mode == RCUBE_COMPOSE_REPLY) { if ($compose_mode == RCUBE_COMPOSE_REPLY) { $COMPOSE['reply_uid'] = $msg_uid; $COMPOSE['reply_msgid'] = $MESSAGE->headers->messageID; $COMPOSE['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID); if (!empty($COMPOSE['param']['all'])) $MESSAGE->reply_all = $COMPOSE['param']['all']; $OUTPUT->set_env('compose_mode', 'reply'); // Save the sent message in the same folder of the message being replied to if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $COMPOSE['mailbox']) @@ -206,10 +211,8 @@ $COMPOSE['param']['sent_mbox'] = $sent_folder; } } else if ($compose_mode == RCUBE_COMPOSE_DRAFT) { if ($MESSAGE->headers->others['x-draft-info']) { else if ($compose_mode == RCUBE_COMPOSE_DRAFT) { if ($MESSAGE->headers->others['x-draft-info']) { // get reply_uid/forward_uid to flag the original message when sending $info = rcmail_draftinfo_decode($MESSAGE->headers->others['x-draft-info']); @@ -232,14 +235,6 @@ $COMPOSE['reply_msgid'] = '<'.$MESSAGE->headers->in_reply_to.'>'; $COMPOSE['references'] = $MESSAGE->headers->references; } else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { $COMPOSE['forward_uid'] = $msg_uid; $OUTPUT->set_env('compose_mode', 'forward'); if (!empty($COMPOSE['param']['attachment'])) $MESSAGE->forward_attachment = true; } } else { @@ -461,6 +456,16 @@ } } // Fallback using Envelope-To if ($from_idx === null && ($envelope_to = $MESSAGE->headers->others['envelope-to'])) { foreach ($identities as $idx => $ident) { if (in_array($ident['email_ascii'], (array)$envelope_to)) { $from_idx = $idx; break; } } } return $identities[$from_idx !== null ? $from_idx : $default_identity]; } @@ -643,11 +648,11 @@ $isHtml = false; } // forward as attachment else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $MESSAGE->forward_attachment) { else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $COMPOSE['as_attachment']) { $isHtml = rcmail_compose_editor_mode(); $body = ''; if (empty($COMPOSE['attachments'])) rcmail_write_forward_attachment($MESSAGE); rcmail_write_forward_attachments(); } // reply/edit/draft/forward else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || $RCMAIL->config->get('reply_mode') != -1)) { @@ -737,8 +742,10 @@ } else { // try to remove the signature if ($RCMAIL->config->get('strip_existing_sig', true)) { $body = rcmail_remove_signature($body); if ($compose_mode != RCUBE_COMPOSE_DRAFT && $compose_mode != RCUBE_COMPOSE_EDIT) { if ($RCMAIL->config->get('strip_existing_sig', true)) { $body = rcmail_remove_signature($body); } } // add HTML formatting $body = rcmail_plain_body($body); @@ -769,8 +776,10 @@ } // try to remove the signature if ($RCMAIL->config->get('strip_existing_sig', true)) { $body = rcmail_remove_signature($body); if ($compose_mode != RCUBE_COMPOSE_DRAFT && $compose_mode != RCUBE_COMPOSE_EDIT) { if ($RCMAIL->config->get('strip_existing_sig', true)) { $body = rcmail_remove_signature($body); } } } } @@ -1135,55 +1144,86 @@ return $cid_map; } // Creates an attachment from the forwarded message function rcmail_write_forward_attachment(&$message) // Creates attachment(s) from the forwarded message(s) function rcmail_write_forward_attachments() { global $RCMAIL, $COMPOSE; global $RCMAIL, $COMPOSE, $MESSAGE; if (strlen($message->subject)) { $name = mb_substr($message->subject, 0, 64) . '.eml'; $storage = $RCMAIL->get_storage(); $mem_limit = parse_bytes(ini_get('memory_limit')); $curr_mem = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB $names = array(); if ($COMPOSE['forward_uid'] == '*') { $index = $storage->index(null, rcmail_sort_column(), rcmail_sort_order()); $COMPOSE['forward_uid'] = $index->get(); } else { $name = 'message_rfc822.eml'; $COMPOSE['forward_uid'] = explode(',', $COMPOSE['forward_uid']); } $mem_limit = parse_bytes(ini_get('memory_limit')); $curr_mem = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB $data = $path = null; foreach ((array)$COMPOSE['forward_uid'] as $uid) { $message = new rcube_message($uid); // don't load too big attachments into memory if ($mem_limit > 0 && $message->size > $mem_limit - $curr_mem) { $temp_dir = unslashify($RCMAIL->config->get('temp_dir')); $path = tempnam($temp_dir, 'rcmAttmnt'); if ($fp = fopen($path, 'w')) { $RCMAIL->storage->get_raw_body($message->uid, $fp); fclose($fp); } else return false; } else { $data = $RCMAIL->storage->get_raw_body($message->uid); if (empty($message->headers)) { continue; } if (!empty($message->headers->charset)) { $storage->set_charset($message->headers->charset); } if (empty($MESSAGE->subject)) { $MESSAGE->subject = $message->subject; } // generate (unique) attachment name $name = strlen($message->subject) ? mb_substr($message->subject, 0, 64) : 'message_rfc822'; if (!empty($names[$name])) { $names[$name]++; $name .= '_' . $names[$name]; } $names[$name] = 1; $name .= '.eml'; $data = $path = null; // don't load too big attachments into memory if ($mem_limit > 0 && $message->size > $mem_limit - $curr_mem) { $temp_dir = unslashify($RCMAIL->config->get('temp_dir')); $path = tempnam($temp_dir, 'rcmAttmnt'); if ($fp = fopen($path, 'w')) { $storage->get_raw_body($message->uid, $fp); fclose($fp); } else { return false; } } else { $data = $storage->get_raw_body($message->uid); $curr_mem += $message->size; } $attachment = array( 'group' => $COMPOSE['id'], 'name' => $name, 'mimetype' => 'message/rfc822', 'data' => $data, 'path' => $path, 'size' => $path ? filesize($path) : strlen($data), ); $attachment = $RCMAIL->plugins->exec_hook('attachment_save', $attachment); if ($attachment['status']) { unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); $COMPOSE['attachments'][$attachment['id']] = $attachment; } else if ($path) { @unlink($path); } } $attachment = array( 'group' => $COMPOSE['id'], 'name' => $name, 'mimetype' => 'message/rfc822', 'data' => $data, 'path' => $path, 'size' => $path ? filesize($path) : strlen($data), ); $attachment = $RCMAIL->plugins->exec_hook('attachment_save', $attachment); if ($attachment['status']) { unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); $COMPOSE['attachments'][$attachment['id']] = $attachment; return true; } else if ($path) { @unlink($path); } return false; } program/steps/mail/folders.inc
@@ -65,6 +65,7 @@ if (!empty($_REQUEST['_reload'])) { $OUTPUT->set_env('messagecount', 0); $OUTPUT->set_env('pagecount', 0); $OUTPUT->set_env('exists', 0); $OUTPUT->command('message_list.clear'); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text(), $mbox); $OUTPUT->command('set_unread_count', $mbox, 0); program/steps/mail/list.inc
@@ -95,6 +95,7 @@ $OUTPUT->set_env('pagecount', $pages); $OUTPUT->set_env('threading', $threading); $OUTPUT->set_env('current_page', $count ? $RCMAIL->storage->get_page() : 1); $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS')); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name); $OUTPUT->command('set_mailboxname', rcmail_get_mailbox_name_text()); program/steps/mail/move_del.inc
@@ -38,7 +38,7 @@ if (!$moved) { // send error message if ($_POST['_from'] != 'show') if ($_POST['_from'] != 'show') $OUTPUT->command('list_mailbox'); rcmail_display_server_error('errormoving'); $OUTPUT->send(); @@ -59,7 +59,7 @@ if (!$del) { // send error message if ($_POST['_from'] != 'show') if ($_POST['_from'] != 'show') $OUTPUT->command('list_mailbox'); rcmail_display_server_error('errordeleting'); $OUTPUT->send(); @@ -111,6 +111,7 @@ $OUTPUT->set_env('messagecount', $msg_count); $OUTPUT->set_env('current_page', $page); $OUTPUT->set_env('pagecount', $pages); $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox, 'EXISTS', true)); // update mailboxlist $mbox = $RCMAIL->storage->get_folder(); @@ -144,5 +145,3 @@ // send response $OUTPUT->send(); program/steps/mail/search.inc
@@ -143,5 +143,6 @@ $OUTPUT->set_env('search_request', $search_str ? $search_request : ''); $OUTPUT->set_env('messagecount', $count); $OUTPUT->set_env('pagecount', ceil($count/$RCMAIL->storage->get_pagesize())); $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS')); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count, 1), $mbox); $OUTPUT->send(); program/steps/mail/sendmail.inc
@@ -617,13 +617,12 @@ $ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914 $file = $attachment['data'] ? $attachment['data'] : $attachment['path']; // .eml attachments send inline $MAIL_MIME->addAttachment($file, $ctype, $attachment['name'], ($attachment['data'] ? false : true), ($ctype == 'message/rfc822' ? '8bit' : 'base64'), ($ctype == 'message/rfc822' ? 'inline' : 'attachment'), 'attachment', '', '', '', $CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL, $CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL, skins/classic/includes/messagetoolbar.html
@@ -27,7 +27,7 @@ <div id="forwardmenu" class="popupmenu"> <ul> <li><roundcube:button command="forward" label="forwardinline" prop="sub" classAct="forwardlink active" class="forwardlink" /></li> <li><roundcube:button command="forward-inline" label="forwardinline" prop="sub" classAct="forwardlink active" class="forwardlink" /></li> <li><roundcube:button command="forward-attachment" label="forwardattachment" prop="sub" classAct="forwardattachmentlink active" class="forwardattachmentlink" /></li> <roundcube:container name="forwardmenu" id="forwardmenu" /> </ul> skins/larry/includes/mailtoolbar.html
@@ -17,7 +17,7 @@ <div id="forwardmenu" class="popupmenu"> <ul class="toolbarmenu"> <li><roundcube:button command="forward" label="forwardinline" prop="sub" classAct="forwardlink active" class="forwardlink" /></li> <li><roundcube:button command="forward-inline" label="forwardinline" prop="sub" classAct="forwardlink active" class="forwardlink" /></li> <li><roundcube:button command="forward-attachment" label="forwardattachment" prop="sub" classAct="forwardattachmentlink active" class="forwardattachmentlink" /></li> <roundcube:container name="forwardmenu" id="forwardmenu" /> </ul>