From 187833dff94146a9b176a1ca4a5c9996809fd4a7 Mon Sep 17 00:00:00 2001 From: alecpl <alec@alec.pl> Date: Thu, 02 Jun 2011 08:36:32 -0400 Subject: [PATCH] - Apply fixes from trunk --- program/steps/mail/func.inc | 149 ++++++++++++++++++++++++++++--------------------- 1 files changed, 84 insertions(+), 65 deletions(-) diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index d4e250b..d738322 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -22,11 +22,11 @@ // setup some global vars used by mail steps $SENT_MBOX = $RCMAIL->config->get('sent_mbox'); $DRAFTS_MBOX = $RCMAIL->config->get('drafts_mbox'); -$SEARCH_MODS_DEFAULT = array('*' => array('subject'=>1, 'from'=>1), $SENT_MBOX => array('subject'=>1, 'to'=>1), $DRAFTS_MBOX => array('subject'=>1, 'to'=>1)); - -// Simplified for IDN in Unicode -//$EMAIL_ADDRESS_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9][a-z0-9\-\.]*\\.[a-z]{2,5})'; -$EMAIL_ADDRESS_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.[a-z]{2,5})'; +$SEARCH_MODS_DEFAULT = array( + '*' => array('subject'=>1, 'from'=>1), + $SENT_MBOX => array('subject'=>1, 'to'=>1), + $DRAFTS_MBOX => array('subject'=>1, 'to'=>1) +); // actions that do not require imap connection here $NOIMAP_ACTIONS = array('addcontact', 'autocomplete', 'upload', 'display-attachment', 'remove-attachment', 'get'); @@ -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); } @@ -579,7 +575,7 @@ '', '<html>', ); - $html = preg_replace($html_search, $html_replace, $html); + $html = preg_replace($html_search, $html_replace, trim($html)); // PCRE errors handling (#1486856), should we use something like for every preg_* use? if ($html === null && ($preg_error = preg_last_error()) != PREG_NO_ERROR) { @@ -611,6 +607,7 @@ $html = '<head></head>'. $html; $html = substr_replace($html, '<meta http-equiv="Content-Type" content="text/html; charset='.RCMAIL_CHARSET.'" />', intval(stripos($html, '<head>')+6), 0); } + // turn relative into absolute urls $html = rcmail_resolve_base($html); @@ -669,7 +666,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']) { @@ -702,7 +700,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']); } @@ -728,71 +727,74 @@ $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; } - $body = join("\n", $a_lines); + $body = join("\n", $body); // quote plain text (don't use Q() here, to display entities "as is") $table = get_html_translation_table(HTML_SPECIALCHARS); @@ -831,10 +833,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; } @@ -944,16 +946,25 @@ $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); +} /** @@ -1076,8 +1087,8 @@ $replacer = new rcube_base_replacer($regs[2]); // replace all relative paths - $body = preg_replace_callback('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Ui', array($replacer, 'callback'), $body); - $body = preg_replace_callback('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Ui', array($replacer, 'callback'), $body); + $body = preg_replace_callback('/(src|background|href)=(["\']?)([^"\'\s]+)(\2|\s|>)/Ui', array($replacer, 'callback'), $body); + $body = preg_replace_callback('/(url\s*\()(["\']?)([^"\'\)\s]+)(\2)\)/Ui', array($replacer, 'callback'), $body); } return $body; @@ -1187,23 +1198,30 @@ */ function rcmail_alter_html_link($matches) { - global $EMAIL_ADDRESS_PATTERN; + global $RCMAIL; + + // Support unicode/punycode in top-level domain part + $EMAIL_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))'; $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)) { + else if (preg_match('/^mailto:'.$EMAIL_PATTERN.'(\?[^"\'>]+)?/i', $attrib['href'], $mailto)) { $attrib['href'] = $mailto[0]; $attrib['onclick'] = sprintf( "return %s.command('compose','%s',this)", JS_OBJECT_NAME, - JQ($mailto[1].$mailto[2])); + JQ($mailto[1].$mailto[3])); } else if (!empty($attrib['href']) && $attrib['href'][0] != '#') { $attrib['target'] = '_blank'; @@ -1243,10 +1261,10 @@ // 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); @@ -1753,6 +1771,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', -- Gitblit v1.9.1