From 3d8b54edf74792e3996d861a6a30c41d82976261 Mon Sep 17 00:00:00 2001 From: thomascube <thomas@roundcube.net> Date: Tue, 12 Apr 2011 14:05:36 -0400 Subject: [PATCH] Keep all submitted data if contact form validation fails (#1487865) --- program/steps/mail/func.inc | 278 ++++++++++++++++++++++++++++--------------------------- 1 files changed, 140 insertions(+), 138 deletions(-) diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 1237c92..33e29a7 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -5,7 +5,7 @@ | program/steps/mail/func.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, Roundcube Dev. - Switzerland | + | Copyright (C) 2005-2010, The Roundcube Dev Team | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -46,7 +46,7 @@ } // set imap properties and session vars -if ($mbox = get_input_value('_mbox', RCUBE_INPUT_GPC)) +if (strlen(trim($mbox = get_input_value('_mbox', RCUBE_INPUT_GPC, true)))) $IMAP->set_mailbox(($_SESSION['mbox'] = $mbox)); else if ($IMAP) $_SESSION['mbox'] = $IMAP->get_mailbox_name(); @@ -56,9 +56,9 @@ // set default sort col/order to session if (!isset($_SESSION['sort_col'])) - $_SESSION['sort_col'] = $CONFIG['message_sort_col']; + $_SESSION['sort_col'] = !empty($CONFIG['message_sort_col']) ? $CONFIG['message_sort_col'] : ''; if (!isset($_SESSION['sort_order'])) - $_SESSION['sort_order'] = $CONFIG['message_sort_order']; + $_SESSION['sort_order'] = strtoupper($CONFIG['message_sort_order']) == 'ASC' ? 'ASC' : 'DESC'; // set threads mode $a_threading = $RCMAIL->config->get('message_threading', array()); @@ -102,14 +102,10 @@ // set current mailbox and some other vars in client environment $OUTPUT->set_env('mailbox', $mbox_name); $OUTPUT->set_env('pagesize', $IMAP->page_size); - $OUTPUT->set_env('quota', $IMAP->get_capability('quota')); + $OUTPUT->set_env('quota', $IMAP->get_capability('QUOTA')); $OUTPUT->set_env('delimiter', $IMAP->get_hierarchy_delimiter()); $OUTPUT->set_env('threading', (bool) $IMAP->threading); - $OUTPUT->set_env('threads', $IMAP->threading - || $IMAP->get_capability('thread=references') - || $IMAP->get_capability('thread=orderedsubject') - || $IMAP->get_capability('thread=refs') - ); + $OUTPUT->set_env('threads', $IMAP->threading || $IMAP->get_capability('THREAD')); if ($CONFIG['flag_for_deletion']) $OUTPUT->set_env('flag_for_deletion', true); @@ -277,7 +273,7 @@ if (in_array($col, array('from', 'to', 'cc', 'replyto'))) $cont = Q(rcmail_address_string($header->$col, 3), 'show'); else if ($col=='subject') { - $cont = abbreviate_string(trim($IMAP->decode_header($header->$col)), 160); + $cont = trim($IMAP->decode_header($header->$col)); if (!$cont) $cont = rcube_label('nosubject'); $cont = Q($cont); } @@ -436,65 +432,6 @@ } -function rcmail_quota_display($attrib) - { - global $OUTPUT; - - if (!$attrib['id']) - $attrib['id'] = 'rcmquotadisplay'; - - if(isset($attrib['display'])) - $_SESSION['quota_display'] = $attrib['display']; - - $OUTPUT->add_gui_object('quotadisplay', $attrib['id']); - - $quota = rcmail_quota_content($attrib); - - $OUTPUT->add_script('$(document).ready(function(){ - rcmail.set_quota('.json_serialize($quota).')});', 'foot'); - - return html::span($attrib, ''); - } - - -function rcmail_quota_content($attrib=NULL) - { - global $COMM_PATH, $RCMAIL; - - $quota = $RCMAIL->imap->get_quota(); - $quota = $RCMAIL->plugins->exec_hook('quota', $quota); - - $quota_result = (array) $quota; - $quota_result['type'] = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : ''; - - if (!$quota['total'] && $RCMAIL->config->get('quota_zero_as_unlimited')) { - $quota_result['title'] = rcube_label('unlimited'); - $quota_result['percent'] = 0; - } - else if ($quota['total']) { - if (!isset($quota['percent'])) - $quota_result['percent'] = min(100, round(($quota['used']/max(1,$quota['total']))*100)); - - $title = sprintf('%s / %s (%.0f%%)', - show_bytes($quota['used'] * 1024), show_bytes($quota['total'] * 1024), - $quota_result['percent']); - - $quota_result['title'] = $title; - - if ($attrib['width']) - $quota_result['width'] = $attrib['width']; - if ($attrib['height']) - $quota_result['height'] = $attrib['height']; - } - else { - $quota_result['title'] = rcube_label('unknown'); - $quota_result['percent'] = 0; - } - - return $quota_result; - } - - function rcmail_get_messagecount_text($count=NULL, $page=NULL) { global $RCMAIL, $IMAP; @@ -545,7 +482,7 @@ { global $RCMAIL; - $old_unseen = $_SESSION['unseen_count'][$mbox_name]; + $old_unseen = rcmail_get_unseen_count($mbox_name); if ($count === null) $unseen = $RCMAIL->imap->messagecount($mbox_name, 'UNSEEN', $force); @@ -555,10 +492,30 @@ if ($unseen != $old_unseen || ($mbox_name == 'INBOX')) $RCMAIL->output->command('set_unread_count', $mbox_name, $unseen, ($mbox_name == 'INBOX')); - // @TODO: this data is doubled (session and cache tables) if caching is enabled - $_SESSION['unseen_count'][$mbox_name] = $unseen; + rcmail_set_unseen_count($mbox_name, $unseen); return $unseen; +} + + +function rcmail_set_unseen_count($mbox_name, $count) +{ + // @TODO: this data is doubled (session and cache tables) if caching is enabled + + // Make sure we have an array here (#1487066) + if (!is_array($_SESSION['unseen_count'])) + $_SESSION['unseen_count'] = array(); + + $_SESSION['unseen_count'][$mbox_name] = $count; +} + + +function rcmail_get_unseen_count($mbox_name) +{ + if (is_array($_SESSION['unseen_count']) && array_key_exists($mbox_name, $_SESSION['unseen_count'])) + return $_SESSION['unseen_count'][$mbox_name]; + else + return null; } @@ -708,7 +665,8 @@ // trigger plugin hook $data = $RCMAIL->plugins->exec_hook('message_part_before', - array('type' => $part->ctype_secondary, 'body' => $part->body) + $p + array('safe' => false, 'plain' => false, 'inline_html' => true)); + array('type' => $part->ctype_secondary, 'body' => $part->body, 'id' => $part->mime_id) + + $p + array('safe' => false, 'plain' => false, 'inline_html' => true)); // convert html to text/plain if ($data['type'] == 'html' && $data['plain']) { @@ -741,7 +699,8 @@ $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed'); // allow post-processing of the message body - $data = $RCMAIL->plugins->exec_hook('message_part_after', array('type' => $part->ctype_secondary, 'body' => $body) + $data); + $data = $RCMAIL->plugins->exec_hook('message_part_after', + array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id) + $data); return $data['type'] == 'html' ? $data['body'] : html::tag('pre', array(), $data['body']); } @@ -767,72 +726,79 @@ $body = preg_replace_callback($replacer->mailto_pattern, array($replacer, 'mailto_callback'), $body); // split body into single lines - $a_lines = preg_split('/\r?\n/', $body); + $body = preg_split('/\r?\n/', $body); $quote_level = 0; $last = -1; // find/mark quoted lines... - for ($n=0, $cnt=count($a_lines); $n < $cnt; $n++) { - if ($a_lines[$n][0] == '>' && preg_match('/^(>+\s*)+/', $a_lines[$n], $regs)) { + for ($n=0, $cnt=count($body); $n < $cnt; $n++) { + if ($body[$n][0] == '>' && preg_match('/^(>+\s*)+/', $body[$n], $regs)) { $q = strlen(preg_replace('/\s/', '', $regs[0])); - $a_lines[$n] = substr($a_lines[$n], strlen($regs[0])); + $body[$n] = substr($body[$n], strlen($regs[0])); - if ($q > $quote_level) - $a_lines[$n] = $replacer->get_replacement($replacer->add( - str_repeat('<blockquote>', $q - $quote_level))) . $a_lines[$n]; - else if ($q < $quote_level) - $a_lines[$n] = $replacer->get_replacement($replacer->add( - str_repeat('</blockquote>', $quote_level - $q))) . $a_lines[$n]; + if ($q > $quote_level) { + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('<blockquote>', $q - $quote_level))) . $body[$n]; + } + else if ($q < $quote_level) { + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level - $q))) . $body[$n]; + } else if ($flowed) { // previous line is flowed - if (isset($a_lines[$last]) && $a_lines[$n] - && $a_lines[$last][strlen($a_lines[$last])-1] == ' ') { + if (isset($body[$last]) && $body[$n] + && $body[$last][strlen($body[$last])-1] == ' ') { // merge lines - $a_lines[$last] .= $a_lines[$n]; - unset($a_lines[$n]); + $body[$last] .= $body[$n]; + unset($body[$n]); } - else + else { $last = $n; + } } } else { $q = 0; if ($flowed) { // sig separator - line is fixed - if ($a_lines[$n] == '-- ') { - $last = $n; + if ($body[$n] == '-- ') { + $last = $last_sig = $n; } else { // remove space-stuffing - if ($a_lines[$n][0] == ' ') - $a_lines[$n] = substr($a_lines[$n], 1); + if ($body[$n][0] == ' ') + $body[$n] = substr($body[$n], 1); // previous line is flowed? - if (isset($a_lines[$last]) && $a_lines[$n] - && $a_lines[$last] != '-- ' - && $a_lines[$last][strlen($a_lines[$last])-1] == ' ' + if (isset($body[$last]) && $body[$n] + && $last != $last_sig + && $body[$last][strlen($body[$last])-1] == ' ' ) { - $a_lines[$last] .= $a_lines[$n]; - unset($a_lines[$n]); + $body[$last] .= $body[$n]; + unset($body[$n]); } else { $last = $n; } } if ($quote_level > 0) - $a_lines[$last] = $replacer->get_replacement($replacer->add( - str_repeat('</blockquote>', $quote_level))) . $a_lines[$last]; + $body[$last] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level))) . $body[$last]; } else if ($quote_level > 0) - $a_lines[$n] = $replacer->get_replacement($replacer->add( - str_repeat('</blockquote>', $quote_level))) . $a_lines[$n]; + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level))) . $body[$n]; } $quote_level = $q; } - // quote plain text - $body = Q(join("\n", $a_lines), 'dummy', false); + $body = join("\n", $body); + + // quote plain text (don't use Q() here, to display entities "as is") + $table = get_html_translation_table(HTML_SPECIALCHARS); + unset($table['?']); + $body = strtr($body, $table); // colorize signature (up to <sig_max_lines> lines) $len = strlen($body); @@ -866,10 +832,10 @@ case 'style': // decode all escaped entities and reduce to ascii strings - $stripped = preg_replace('/[^a-zA-Z\(:]/', '', rcmail_xss_entity_decode($content)); + $stripped = preg_replace('/[^a-zA-Z\(:;]/', '', rcmail_xss_entity_decode($content)); // now check for evil strings like expression, behavior or url() - if (!preg_match('/expression|behavior|url\(|import/', $stripped)) { + if (!preg_match('/expression|behavior|url\(|import[^a]/', $stripped)) { $out = html::tag('style', array('type' => 'text/css'), $content); break; } @@ -962,29 +928,42 @@ else $header_value = trim($IMAP->decode_header($value)); - $output_headers[$hkey] = array('title' => rcube_label($hkey), 'value' => $header_value, 'raw' => $value); + $output_headers[$hkey] = array( + 'title' => rcube_label(preg_replace('/(^mail-|-)/', '', $hkey)), + 'value' => $header_value, 'raw' => $value + ); } - $plugin = $RCMAIL->plugins->exec_hook('message_headers_output', array('output' => $output_headers, 'headers' => $MESSAGE->headers)); + $plugin = $RCMAIL->plugins->exec_hook('message_headers_output', + array('output' => $output_headers, 'headers' => $MESSAGE->headers)); // compose html table $table = new html_table(array('cols' => 2)); foreach ($plugin['output'] as $hkey => $row) { $table->add(array('class' => 'header-title'), Q($row['title'])); - $table->add(array('class' => $hkey, 'width' => "90%"), Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show'))); + $table->add(array('class' => 'header '.$hkey), Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show'))); } - // all headers division - $table->add(array('colspan' => 2, 'class' => "more-headers show-headers", 'onclick' => "return ".JS_OBJECT_NAME.".command('load-headers','',this)"), ''); - $table->add_row(array('id' => "all-headers")); - $table->add(array('colspan' => 2, 'class' => "all"), html::div(array('id' => 'headers-source'), '')); + return $table->show($attrib); +} + + +/** + * return block to show full message headers + */ +function rcmail_message_full_headers($attrib, $headers=NULL) +{ + global $OUTPUT; + + $html = html::div(array('class' => "more-headers show-headers", 'onclick' => "return ".JS_OBJECT_NAME.".command('load-headers','',this)"), ''); + $html .= html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'), html::div(array('id' => 'headers-source'), '')); $OUTPUT->add_gui_object('all_headers_row', 'all-headers'); $OUTPUT->add_gui_object('all_headers_box', 'headers-source'); - - return $table->show($attrib); - } + + return html::div($attrib, $html); +} /** @@ -1174,20 +1153,22 @@ $attributes = array(); // Handle body attributes that doesn't play nicely with div elements - if (preg_match('/<div class="' . preg_quote($body_id, '/') . '" ([^>]+)/', $body, $m)) { + $regexp = '/<div class="' . preg_quote($body_id, '/') . '"([^>]*)/'; + if (preg_match($regexp, $body, $m)) { $attrs = $m[0]; // Get bgcolor, we'll set it as background-color of the message container - if (preg_match('/bgcolor=["\']*([a-z0-9#]+)["\']*/', $attrs, $mb)) { + if ($m[1] && preg_match('/bgcolor=["\']*([a-z0-9#]+)["\']*/', $attrs, $mb)) { $attributes['background-color'] = $mb[1]; $attrs = preg_replace('/bgcolor=["\']*([a-z0-9#]+)["\']*/', '', $attrs); } // Get background, we'll set it as background-image of the message container - if (preg_match('/background=["\']*([^"\'>\s]+)["\']*/', $attrs, $mb)) { + if ($m[1] && preg_match('/background=["\']*([^"\'>\s]+)["\']*/', $attrs, $mb)) { $attributes['background-image'] = 'url('.$mb[1].')'; $attrs = preg_replace('/background=["\']*([^"\'>\s]+)["\']*/', '', $attrs); } - if (!empty($attributes)) - $body = preg_replace('/<div class="' . preg_quote($body_id, '/') . '" [^>]+/', rtrim($attrs), $body, 1); + if (!empty($attributes)) { + $body = preg_replace($regexp, rtrim($attrs), $body, 1); + } // handle body styles related to background image if ($attributes['background-image']) { @@ -1203,8 +1184,9 @@ } // make sure there's 'rcmBody' div, we need it for proper css modification // its name is hardcoded in rcmail_message_body() also - else + else { $body = '<div class="' . $body_id . '">' . $body . '</div>'; + } return $body; } @@ -1215,15 +1197,19 @@ */ function rcmail_alter_html_link($matches) { - global $EMAIL_ADDRESS_PATTERN; + global $RCMAIL, $EMAIL_ADDRESS_PATTERN; $tag = $matches[1]; $attrib = parse_attrib_string($matches[2]); $end = '>'; + // Remove non-printable characters in URL (#1487805) + $attrib['href'] = preg_replace('/[\x00-\x1F]/', '', $attrib['href']); + if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href'])) { - $attrib['href'] = "?_task=utils&_action=modcss&u=" . urlencode($attrib['href']) - . "&c=" . urlencode($GLOBALS['rcmail_html_container_id']); + $tempurl = 'tmp-' . md5($attrib['href']) . '.css'; + $_SESSION['modcssurls'][$tempurl] = $attrib['href']; + $attrib['href'] = $RCMAIL->url(array('task' => 'utils', 'action' => 'modcss', 'u' => $tempurl, 'c' => $GLOBALS['rcmail_html_container_id'])); $end = ' />'; } else if (preg_match('/^mailto:'.$EMAIL_ADDRESS_PATTERN.'(\?[^"\'>]+)?/i', $attrib['href'], $mailto)) { @@ -1271,17 +1257,17 @@ // IDNA ASCII to Unicode if ($name == $mailto) - $name = idn_to_utf8($name); + $name = rcube_idn_to_utf8($name); if ($string == $mailto) - $string = idn_to_utf8($string); - $mailto = idn_to_utf8($mailto); + $string = rcube_idn_to_utf8($string); + $mailto = rcube_idn_to_utf8($mailto); if ($PRINT_MODE) { $out .= sprintf('%s <%s>', Q($name), $mailto); } else if (check_email($part['mailto'], false)) { if ($linked) { - $out .= html::a(array( + $address = html::a(array( 'href' => 'mailto:'.$mailto, 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)), 'title' => $mailto, @@ -1290,12 +1276,12 @@ Q($name ? $name : $mailto)); } else { - $out .= html::span(array('title' => $mailto, 'class' => "rcmContactAddress"), + $address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"), Q($name ? $name : $mailto)); } if ($addicon && $got_writable_abook) { - $out .= ' ' . html::a(array( + $address = html::span(null, $address . html::a(array( 'href' => "#add", 'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, urlencode($string)), 'title' => rcube_label('addtoaddressbook'), @@ -1303,8 +1289,9 @@ html::img(array( 'src' => $CONFIG['skin_path'] . $addicon, 'alt' => "Add contact", - ))); + )))); } + $out .= $address; } else { if ($name) @@ -1435,14 +1422,14 @@ /** * clear message composing settings */ -function rcmail_compose_cleanup() +function rcmail_compose_cleanup($id) { - if (!isset($_SESSION['compose'])) + if (!isset($_SESSION['compose_data'][$id])) return; $rcmail = rcmail::get_instance(); - $rcmail->plugins->exec_hook('attachments_cleanup', array()); - $rcmail->session->remove('compose'); + $rcmail->plugins->exec_hook('attachments_cleanup', array('group' => $id)); + unset($_SESSION['compose_data'][$id]); } @@ -1540,6 +1527,7 @@ $delim = $RCMAIL->config->header_delimiter(); $to = $headers_enc['To']; $subject = $headers_enc['Subject']; + $header_str = rtrim($header_str); if ($delim != "\r\n") { $header_str = str_replace("\r\n", $delim, $header_str); @@ -1780,6 +1768,7 @@ 'quotadisplay' => 'rcmail_quota_display', 'mailboxname' => 'rcmail_mailbox_name_display', 'messageheaders' => 'rcmail_message_headers', + 'messagefullheaders' => 'rcmail_message_full_headers', 'messagebody' => 'rcmail_message_body', 'messagecontentframe' => 'rcmail_messagecontent_frame', 'messagepartframe' => 'rcmail_message_part_frame', @@ -1788,4 +1777,17 @@ 'searchform' => array($OUTPUT, 'search_form'), )); - +// register action aliases +$RCMAIL->register_action_map(array( + 'preview' => 'show.inc', + 'print' => 'show.inc', + 'moveto' => 'move_del.inc', + 'delete' => 'move_del.inc', + 'send' => 'sendmail.inc', + 'expunge' => 'folders.inc', + 'purge' => 'folders.inc', + 'remove-attachment' => 'attachments.inc', + 'display-attachment' => 'attachments.inc', + 'upload' => 'attachments.inc', + 'group-expand' => 'autocomplete.inc', +)); -- Gitblit v1.9.1