summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralecpl <alec@alec.pl>2009-02-18 19:15:36 +0000
committeralecpl <alec@alec.pl>2009-02-18 19:15:36 +0000
commitec603f7da6e0dcae398169efe03b52d199427d11 (patch)
treec35b4a549989c7ba6a22d42d195db6cfceea84e0
parentf9a4bc4dfa2ef6f8b74f32afb61f2e43d26781e2 (diff)
- Fix html body washing on reply/forward + fix attachments handling (#1485676)
-rw-r--r--CHANGELOG4
-rw-r--r--program/steps/mail/compose.inc81
-rw-r--r--program/steps/mail/func.inc187
-rw-r--r--program/steps/mail/show.inc18
4 files changed, 174 insertions, 116 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 825fbb2f0..0f817752b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,10 @@
CHANGELOG RoundCube Webmail
---------------------------
+2009/02/18 (alec)
+----------
+- Fix html body washing on reply/forward + fix attachments handling (#1485676)
+
2009/02/13 (alec)
----------
- Fix multiple recipients input parsing (#1485733)
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index 7dfa967cd..1b83b1ed4 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -381,16 +381,6 @@ function rcmail_compose_body($attrib)
// load draft message body
else if ($compose_mode == RCUBE_COMPOSE_DRAFT)
$body = rcmail_create_draft_body($body, $isHtml);
-
- if ($isHtml) {
- // replace cid with href in inline images links
- foreach ((array)$_SESSION['compose']['attachments'] as $pid => $attachment) {
- if ($attachment['content_id']) {
- $body = str_replace('cid:'. $attachment['content_id'],
- $OUTPUT->app->comm_path.'&_action=display-attachment&_file=rcmfile'.$pid, $body);
- }
- }
- }
}
else if (!empty($_SESSION['compose']['param']['_body']))
{
@@ -506,13 +496,19 @@ function rcmail_create_reply_body($body, $bodyIsHtml)
}
else
{
+ // save inline images to files
+ $cid_map = rcmail_write_inline_attachments($MESSAGE);
+ // set is_safe flag (we need this for html body washing)
+ rcmail_check_safe($MESSAGE);
+ // clean up html tags
+ $body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map);
+
+ // build reply (quote content)
$prefix = sprintf("On %s, %s wrote:<br />\n",
$MESSAGE->headers->date,
htmlspecialchars(Q($MESSAGE->get_header('from'), 'replace'), ENT_COMPAT, $OUTPUT->get_charset()));
$prefix .= '<blockquote type="cite" style="padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px; width:100%">';
$suffix = "</blockquote><p></p>";
-
- rcmail_write_inline_attachments($MESSAGE);
}
return $prefix.$body.$suffix;
@@ -523,6 +519,10 @@ function rcmail_create_forward_body($body, $bodyIsHtml)
{
global $IMAP, $MESSAGE, $OUTPUT;
+ // add attachments
+ if (!isset($_SESSION['compose']['forward_attachments']) && is_array($MESSAGE->mime_parts))
+ $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
+
if (!$bodyIsHtml)
{
$prefix = "\n\n\n-------- Original Message --------\n";
@@ -536,6 +536,11 @@ function rcmail_create_forward_body($body, $bodyIsHtml)
}
else
{
+ // set is_safe flag (we need this for html body washing)
+ rcmail_check_safe($MESSAGE);
+ // clean up html tags
+ $body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map);
+
$prefix = sprintf(
"<br><br>-------- Original Message --------" .
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody>" .
@@ -554,10 +559,6 @@ function rcmail_create_forward_body($body, $bodyIsHtml)
$prefix .= "</tbody></table><br>";
}
-
- // add attachments
- if (!isset($_SESSION['compose']['forward_attachments']) && is_array($MESSAGE->mime_parts))
- rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
return $prefix.$body;
}
@@ -565,7 +566,7 @@ function rcmail_create_forward_body($body, $bodyIsHtml)
function rcmail_create_draft_body($body, $bodyIsHtml)
{
- global $MESSAGE;
+ global $MESSAGE, $OUTPUT;
/**
* add attachments
@@ -574,39 +575,67 @@ function rcmail_create_draft_body($body, $bodyIsHtml)
if (!isset($_SESSION['compose']['forward_attachments'])
&& is_array($MESSAGE->mime_parts)
&& count($MESSAGE->mime_parts) > 0)
- rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
+ {
+ $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
+ // replace cid with href in inline images links
+ if ($cid_map)
+ $body = str_replace(array_keys($cid_map), array_values($cid_map), $body);
+ }
+
return $body;
}
function rcmail_write_compose_attachments(&$message, $bodyIsHtml)
{
+ global $OUTPUT;
+
+ $cid_map = array();
+ $id = 0;
+
foreach ((array)$message->mime_parts as $pid => $part)
{
if (($part->ctype_primary != 'message' || !$bodyIsHtml) &&
($part->disposition=='attachment' || $part->disposition=='inline' || $part->headers['content-id']
|| (empty($part->disposition) && $part->filename)))
{
- if ($attachment = rcmail_save_attachment($message, $pid))
- $_SESSION['compose']['attachments'][] = $attachment;
+ if ($attachment = rcmail_save_attachment($message, $pid)) {
+ $_SESSION['compose']['attachments'][$id] = $attachment;
+ if ($bodyIsHtml && $part->filename && $part->content_id) {
+ $cid_map['cid:'.$part->content_id] =
+ $OUTPUT->app->comm_path.'&_action=display-attachment&_file=rcmfile'.$id;
+ }
+ $id++;
+ }
}
}
$_SESSION['compose']['forward_attachments'] = true;
+
+ return $cid_map;
}
function rcmail_write_inline_attachments(&$message)
{
- foreach ((array)$message->mime_parts as $pid => $part)
- {
- if ($part->content_id && $part->filename)
- {
- if ($attachment = rcmail_save_attachment($message, $pid))
- $_SESSION['compose']['attachments'][] = $attachment;
+ global $OUTPUT;
+
+ $cid_map = array();
+ $id = 0;
+
+ foreach ((array)$message->mime_parts as $pid => $part) {
+ if ($part->content_id && $part->filename) {
+ if ($attachment = rcmail_save_attachment($message, $pid)) {
+ $_SESSION['compose']['attachments'][$id] = $attachment;
+ $cid_map['cid:'.$part->content_id] =
+ $OUTPUT->app->comm_path.'&_action=display-attachment&_file=rcmfile'.$id;
+ $id++;
+ }
}
}
+
+ return $cid_map;
}
function rcmail_save_attachment(&$message, $pid)
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index f54d4facd..2e85a4097 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -19,7 +19,6 @@
*/
-require_once('lib/enriched.inc');
require_once('include/rcube_smtp.inc');
$EMAIL_ADDRESS_PATTERN = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/i';
@@ -611,22 +610,128 @@ function rcmail_get_mailbox_name_text()
return rcmail_localize_foldername($RCMAIL->imap->get_mailbox_name());
}
+/**
+ * Sets message is_safe flag according to 'show_images' option value
+ *
+ * @param object rcube_message Message
+ */
+function rcmail_check_safe(&$message)
+{
+ global $RCMAIL;
+
+ $show_images = $RCMAIL->config->get('show_images');
+ if (!$message->is_safe
+ && !empty($show_images)
+ && $message->has_html_part())
+ {
+ switch($show_images) {
+ case '1': // known senders only
+ $CONTACTS = new rcube_contacts($DB, $_SESSION['user_id']);
+ if ($CONTACTS->search('email', $message->sender['mailto'], true, false)->count) {
+ $message->set_safe(true);
+ }
+ break;
+ case '2': // always
+ $message->set_safe(true);
+ break;
+ }
+ }
+}
+
+/**
+ * Cleans up the given message HTML Body (for displaying)
+ *
+ * @param string HTML
+ * @param array Display parameters
+ * @param array CID map replaces (inline images)
+ * @return string Clean HTML
+ */
+function rcmail_wash_html($html, $p = array(), $cid_replaces)
+{
+ global $REMOTE_OBJECTS;
+
+ $p += array('safe' => false, 'inline_html' => true);
+
+ // special replacements (not properly handled by washtml class)
+ $html_search = array(
+ '/(<\/nobr>)(\s+)(<nobr>)/i', // space(s) between <NOBR>
+ '/(<[\/]*st1:[^>]+>)/i', // Microsoft's Smart Tags <ST1>
+ '/<\/?rte_text>/i', // Rich Text Editor tags (#1485647)
+ '/<title>.*<\/title>/i', // PHP bug #32547 workaround: remove title tag
+ '/<html[^>]*>/im', // malformed html: remove html tags (#1485139)
+ '/<\/html>/i', // malformed html: remove html tags (#1485139)
+ '/^[\xFE\xFF\xBB\xBF\x00]+((?:<\!doctype|\<html))/im', // remove byte-order mark (only outlook?)
+ );
+ $html_replace = array(
+ '\\1'.' &nbsp; '.'\\3',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '\\1',
+ );
+ $html = preg_replace($html_search, $html_replace, $html);
+
+ // charset was converted to UTF-8 in rcube_imap::get_message_part() -> change charset specification in HTML accordingly
+ $charset_pattern = '/(\s+content=[\'"]?\w+\/\w+;\s*charset)=([a-z0-9-_]+)/i';
+ if (preg_match($charset_pattern, $html)) {
+ $html = preg_replace($charset_pattern, '\\1='.RCMAIL_CHARSET, $html);
+ }
+ else {
+ // add head for malformed messages, washtml cannot work without that
+ if (!preg_match('/<head[^>]*>(.*)<\/head>/Uims', $html))
+ $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);
+
+ // clean HTML with washhtml by Frederic Motte
+ $wash_opts = array(
+ 'show_washed' => false,
+ 'allow_remote' => $p['safe'],
+ 'blocked_src' => "./program/blocked.gif",
+ 'charset' => RCMAIL_CHARSET,
+ 'cid_map' => $cid_replaces,
+ 'html_elements' => array('body'),
+ );
+
+ if (!$p['inline_html']) {
+ $wash_opts['html_elements'] = array('html','head','title','body');
+ }
+ if ($p['safe']) {
+ $wash_opts['html_elements'][] = 'link';
+ $wash_opts['html_attribs'] = array('rel','type');
+ }
+
+ $washer = new washtml($wash_opts);
+ $washer->add_callback('form', 'rcmail_washtml_callback');
+
+ if ($p['safe']) { // allow CSS styles, will be sanitized by rcmail_washtml_callback()
+ $washer->add_callback('style', 'rcmail_washtml_callback');
+ }
+
+ $html = $washer->wash($html);
+ $REMOTE_OBJECTS = $washer->extlinks;
+
+ return $html;
+}
+
/**
* Convert the given message part to proper HTML
* which can be displayed the message view
*
* @param object rcube_message_part Message part
- * @param bool True if external objects (ie. images ) are allowed
- * @param bool True if part should be converted to plaintext
+ * @param array Display parameters array
* @return string Formatted HTML string
*/
function rcmail_print_body($part, $p = array())
{
- global $REMOTE_OBJECTS;
-
$p += array('safe' => false, 'plain' => false, 'inline_html' => true);
-
+
// convert html to text/plain
if ($part->ctype_secondary == 'html' && $p['plain']) {
$txt = new html2text($part->body, false, true);
@@ -635,77 +740,12 @@ function rcmail_print_body($part, $p = array())
}
// text/html
else if ($part->ctype_secondary == 'html') {
- $html = $part->body;
-
- // special replacements (not properly handled by washtml class)
- $html_search = array(
- '/(<\/nobr>)(\s+)(<nobr>)/i', // space(s) between <NOBR>
- '/(<[\/]*st1:[^>]+>)/i', // Microsoft's Smart Tags <ST1>
- '/<\/?rte_text>/i', // Rich Text Editor tags (#1485647)
- '/<title>.*<\/title>/i', // PHP bug #32547 workaround: remove title tag
- '/<html[^>]*>/im', // malformed html: remove html tags (#1485139)
- '/<\/html>/i', // malformed html: remove html tags (#1485139)
- '/^[\xFE\xFF\xBB\xBF\x00]+((?:<\!doctype|\<html))/im', // remove byte-order mark (only outlook?)
- );
- $html_replace = array(
- '\\1'.' &nbsp; '.'\\3',
- '',
- '',
- '',
- '',
- '',
- '\\1',
- );
- $html = preg_replace($html_search, $html_replace, $html);
-
- // charset was converted to UTF-8 in rcube_imap::get_message_part() -> change charset specification in HTML accordingly
- $charset_pattern = '/(\s+content=[\'"]?\w+\/\w+;\s*charset)=([a-z0-9-_]+)/i';
- if (preg_match($charset_pattern, $html)) {
- $html = preg_replace($charset_pattern, '\\1='.RCMAIL_CHARSET, $html);
- }
- else {
- // add head for malformed messages, washtml cannot work without that
- if (!preg_match('/<head[^>]*>(.*)<\/head>/Uims', $html))
- $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);
-
- // clean HTML with washhtml by Frederic Motte
- $wash_opts = array(
- 'show_washed' => false,
- 'allow_remote' => $p['safe'],
- 'blocked_src' => "./program/blocked.gif",
- 'charset' => RCMAIL_CHARSET,
- 'cid_map' => $part->replaces,
- 'html_elements' => array('body'),
- );
-
- if (!$p['inline_html']) {
- $wash_opts['html_elements'] = array('html','head','title','body');
- }
- if ($p['safe']) {
- $wash_opts['html_elements'][] = 'link';
- $wash_opts['html_attribs'] = array('rel','type');
- }
-
- $washer = new washtml($wash_opts);
- $washer->add_callback('form', 'rcmail_washtml_callback');
-
- if ($p['safe']) { // allow CSS styles, will be sanitized by rcmail_washtml_callback()
- $washer->add_callback('style', 'rcmail_washtml_callback');
- }
-
- $body = $washer->wash($html);
- $REMOTE_OBJECTS = $washer->extlinks;
-
- return $body;
+ return rcmail_wash_html($part->body, $p, $part->replaces);
}
// text/enriched
else if ($part->ctype_secondary=='enriched') {
$part->ctype_secondary = 'html';
+ require_once('lib/enriched.inc');
return Q(enriched_to_html($part->body), 'show');
}
else
@@ -757,6 +797,7 @@ function rcmail_print_body($part, $p = array())
return html::tag('pre', array(), $body);
}
+
/**
* add a string to the replacement array and return a replacement string
*/
diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc
index 7ae0ae000..fd31fa91c 100644
--- a/program/steps/mail/show.inc
+++ b/program/steps/mail/show.inc
@@ -43,23 +43,7 @@ if ($_GET['_uid']) {
$mbox_name = $IMAP->get_mailbox_name();
// show images?
- $show_images = $RCMAIL->config->get('show_images');
- if(!$MESSAGE->is_safe
- && !empty($show_images)
- && $MESSAGE->has_html_part())
- {
- switch($show_images) {
- case '1': // known senders only
- $CONTACTS = new rcube_contacts($DB, $_SESSION['user_id']);
- if ($CONTACTS->search('email', $MESSAGE->sender['mailto'], true, false)->count) {
- $MESSAGE->set_safe(true);
- }
- break;
- case '2': // always
- $MESSAGE->set_safe(true);
- break;
- }
- }
+ rcmail_check_safe($MESSAGE);
// calculate Etag for this request
$etag = md5($MESSAGE->uid.$mbox_name.session_id()