alecpl
2010-09-11 cb3dfdfedef18381a30fd9b80c9f7120af1031a4
program/steps/mail/func.inc
@@ -626,6 +626,21 @@
  );
  $html = preg_replace($html_search, $html_replace, $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) {
    $errstr = "Could not clean up HTML message! PCRE Error: $preg_error.";
    if ($preg_error == PREG_BACKTRACK_LIMIT_ERROR)
      $errstr .= " Consider raising pcre.backtrack_limit!";
    if ($preg_error == PREG_RECURSION_LIMIT_ERROR)
      $errstr .= " Consider raising pcre.recursion_limit!";
    raise_error(array('code' => 600, 'type' => 'php',
        'line' => __LINE__, 'file' => __FILE__,
        'message' => $errstr), true, false);
    return '';
  }
  // fix (unknown/malformed) HTML tags before "wash"
  $html = preg_replace_callback('/(<[\/]*)([^\s>]+)/', 'rcmail_html_tag_callback', $html);
@@ -929,7 +944,7 @@
 */
function rcmail_message_body($attrib)
  {
  global $CONFIG, $OUTPUT, $MESSAGE, $IMAP, $REMOTE_OBJECTS;
  global $CONFIG, $OUTPUT, $MESSAGE, $IMAP, $RCMAIL, $REMOTE_OBJECTS;
  if (!is_array($MESSAGE->parts) && empty($MESSAGE->body))
    return '';
@@ -965,22 +980,41 @@
          rcmail_message_error($MESSAGE->uid);
        }
        $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array(
          'part' => $part, 'prefix' => ''));
        // re-format format=flowed content
        if ($part->ctype_secondary == "plain" && $part->ctype_parameters['format'] == "flowed")
          $part->body = rcube_message::unfold_flowed($part->body);
        $body = rcmail_print_body($part, array('safe' => $safe_mode, 'plain' => !$CONFIG['prefer_html']));
        if ($part->ctype_secondary == 'html')
          $out .= html::div('message-htmlpart', rcmail_html4inline($body, $attrib['id'], 'div.rcmBody'));
        if ($part->ctype_secondary == 'html') {
          $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs);
          $div_attr = array('class' => 'message-htmlpart');
          $style = array();
          if (!empty($attrs)) {
            foreach ($attrs as $a_idx => $a_val)
              $style[] = $a_idx . ': ' . $a_val;
            if (!empty($style))
              $div_attr['style'] = implode('; ', $style);
          }
          $out .= html::div($div_attr, $plugin['prefix'] . $body);
        }
        else
          $out .= html::div('message-part', $body);
          $out .= html::div('message-part', $plugin['prefix'] . $body);
        }
      }
    }
  else
    $out .= html::div('message-part', html::tag('pre', array(),
  else {
    $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array(
      'part' => $MESSAGE, 'prefix' => ''));
    $out .= html::div('message-part', $plugin['prefix'] . html::tag('pre', array(),
      rcmail_plain_body(Q($MESSAGE->body, 'strict', false))));
    }
  $ctype_primary = strtolower($MESSAGE->structure->ctype_primary);
  $ctype_secondary = strtolower($MESSAGE->structure->ctype_secondary);
@@ -988,11 +1022,16 @@
  // list images after mail body
  if ($CONFIG['inline_images']
      && $ctype_primary == 'multipart'
      && !empty($MESSAGE->attachments)
      && !strstr($message_body, '<html'))
      && !empty($MESSAGE->attachments))
    {
    foreach ($MESSAGE->attachments as $attach_prop) {
      if (strpos($attach_prop->mimetype, 'image/') === 0) {
      // Content-Type: image/*...
      if (preg_match('/^image\//i', $attach_prop->mimetype) ||
        // ...or known file extension: many clients are using application/octet-stream
        ($attach_prop->filename &&
          preg_match('/^application\/octet-stream$/i', $attach_prop->mimetype) &&
          preg_match('/\.(jpg|jpeg|png|gif|bmp)$/i', $attach_prop->filename))
      ) {
        $out .= html::tag('hr') . html::p(array('align' => "center"),
          html::img(array(
            'src' => $MESSAGE->get_part_url($attach_prop->mime_id),
@@ -1031,30 +1070,32 @@
/**
 * modify a HTML message that it can be displayed inside a HTML page
 */
function rcmail_html4inline($body, $container_id, $body_id='')
  {
function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null)
{
  $last_style_pos = 0;
  $body_lc = strtolower($body);
  $cont_id = $container_id.($body_id ? ' div.'.$body_id : '');
  // find STYLE tags
  while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos)))
    {
  {
    $pos = strpos($body_lc, '>', $pos)+1;
    // replace all css definitions with #container [def]
    $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id.($body_id ? ' '.$body_id : ''));
    $styles = rcmail_mod_css_styles(
      substr($body, $pos, $pos2-$pos), $cont_id);
    $body = substr($body, 0, $pos) . $styles . substr($body, $pos2);
    $body_lc = strtolower($body);
    $last_style_pos = $pos2;
    }
  }
  // modify HTML links to open a new window if clicked
  $GLOBALS['rcmail_html_container_id'] = $container_id;
  $body = preg_replace_callback('/<(a|link)\s+([^>]+)>/Ui', 'rcmail_alter_html_link', $body);
  unset($GLOBALS['rcmail_html_container_id']);
  $out = preg_replace(array(
  $body = preg_replace(array(
      // add comments arround html and other tags
      '/(<!DOCTYPE[^>]*>)/i',
      '/(<\?xml[^>]*>)/i',
@@ -1078,18 +1119,48 @@
      '<!--\\1-->',
      '&lt;?',
      '?&gt;',
      '<div class="rcmBody"\\1>',
      '<div class="'.$body_id.'"\\1>',
      '</div>',
      ),
    $body);
  $attributes = array();
  // Handle body attributes that doesn't play nicely with div elements
  if (preg_match('/<div class="' . preg_quote($body_id, '/') . '" ([^>]+)/', $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)) {
      $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)) {
      $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);
    // handle body styles related to background image
    if ($attributes['background-image']) {
      // get body style
      if (preg_match('/#'.preg_quote($cont_id, '/').'\s+\{([^}]+)}/i', $body, $m)) {
        // get background related style
        if (preg_match_all('/(background-position|background-repeat)\s*:\s*([^;]+);/i', $m[1], $ma, PREG_SET_ORDER)) {
          foreach ($ma as $style)
            $attributes[$style[1]] = $style[2];
        }
      }
    }
  }
  // make sure there's 'rcmBody' div, we need it for proper css modification
  // its name is hardcoded in rcmail_message_body() also
  if (!preg_match('/<div class="rcmBody"/', $out))
    $out = '<div class="rcmBody">' . $out . '</div>';
  else
    $body = '<div class="' . $body_id . '">' . $body . '</div>';
  return $out;
  }
  return $body;
}
/**
@@ -1310,7 +1381,7 @@
    return;
  $rcmail = rcmail::get_instance();
  $rcmail->plugins->exec_hook('cleanup_attachments',array());
  $rcmail->plugins->exec_hook('attachments_cleanup', array());
  $rcmail->session->remove('compose');
  }
@@ -1429,6 +1500,14 @@
    // remove MDN headers after sending
    unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']);
    // get all recipients
    if ($headers['Cc'])
      $mailto .= $headers['Cc'];
    if ($headers['Bcc'])
      $mailto .= $headers['Bcc'];
    if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m))
      $mailto = implode(', ', array_unique($m[1]));
    if ($CONFIG['smtp_log']) {
      write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s",
        $RCMAIL->user->get_username(),
@@ -1478,7 +1557,7 @@
      'From' => $sender,
      'To'   => $message->headers->mdn_to,
      'Subject' => rcube_label('receiptread') . ': ' . $message->subject,
      'Message-ID' => sprintf('<%s@%s>', md5(uniqid('rcmail'.mt_rand(),true)), $RCMAIL->config->mail_domain($_SESSION['imap_host'])),
      'Message-ID' => rcmail_gen_message_id(),
      'X-Sender' => $identity['email'],
      'References' => trim($message->headers->references . ' ' . $message->headers->messageID),
    );
@@ -1519,6 +1598,29 @@
  return false;
}
// Returns unique Message-ID
function rcmail_gen_message_id()
{
  global $RCMAIL;
  $local_part  = md5(uniqid('rcmail'.mt_rand(),true));
  $domain_part = $RCMAIL->user->get_username('domain');
  // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924)
  if (!preg_match('/\.[a-z]+$/i', $domain_part)) {
    if (($host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']))
      && preg_match('/\.[a-z]+$/i', $host)) {
        $domain_part = $host;
    }
    else if (($host = preg_replace('/:[0-9]+$/', '', $_SERVER['SERVER_NAME']))
      && preg_match('/\.[a-z]+$/i', $host)) {
        $domain_part = $host;
    }
  }
  return sprintf('<%s@%s>', $local_part, $domain_part);
}
// Returns RFC2822 formatted current date in user's timezone
function rcmail_user_date()
{
@@ -1536,7 +1638,8 @@
  $date = time() + $tz * 60 * 60;
  $date = gmdate('r', $date);
  $date = preg_replace('/[+-][0-9]{4}$/', sprintf('%+05d', $tz * 100), $date);
  $tz   = sprintf('%+05d', intval($tz) * 100 + ($tz - intval($tz)) * 60);
  $date = preg_replace('/[+-][0-9]{4}$/', $tz, $date);
  return $date;
}