Aleksander Machniak
2013-05-14 05b5f969d5c10850291ae413b89461ca1f6bcc5d
program/steps/mail/func.inc
@@ -628,39 +628,6 @@
  $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>
    '/<title[^>]*>[^<]*<\/title>/i',   // PHP bug #32547 workaround: remove title tag
    '/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/',   // byte-order mark (only outlook?)
    '/<html\s[^>]+>/i',         // washtml/DOMDocument cannot handle xml namespaces
  );
  $html_replace = array(
    '\\1'.' &nbsp; '.'\\3',
    '',
    '',
    '<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) {
    $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' => 620, '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);
  // charset was converted to UTF-8 in rcube_storage::get_message_part(),
  // change/add charset specification in HTML accordingly,
  // washtml cannot work without that
@@ -673,9 +640,6 @@
  if (!$rcount) {
    $html = '<head>' . $meta . '</head>' . $html;
  }
  // turn relative into absolute urls
  $html = rcmail_resolve_base($html);
  // clean HTML with washhtml by Frederic Motte
  $wash_opts = array(
@@ -702,7 +666,7 @@
    $wash_opts['html_attribs'] = $p['html_attribs'];
  // initialize HTML washer
  $washer = new washtml($wash_opts);
  $washer = new rcube_washtml($wash_opts);
  if (!$p['skip_washer_form_callback'])
    $washer->add_callback('form', 'rcmail_washtml_callback');
@@ -740,7 +704,7 @@
  // convert html to text/plain
  if ($data['type'] == 'html' && $data['plain']) {
    $txt = new html2text($data['body'], false, true);
    $txt = new rcube_html2text($data['body'], false, true);
    $body = $txt->get_text();
    $part->ctype_secondary = 'plain';
  }
@@ -808,10 +772,12 @@
      if ($q > $quote_level) {
        $body[$n] = $replacer->get_replacement($replacer->add(
          str_repeat('<blockquote>', $q - $quote_level))) . $body[$n];
        $last = $n;
      }
      else if ($q < $quote_level) {
        $body[$n] = $replacer->get_replacement($replacer->add(
          str_repeat('</blockquote>', $quote_level - $q))) . $body[$n];
        $last = $n;
      }
      else if ($flowed) {
        // previous line is flowed
@@ -921,26 +887,10 @@
/**
 * Callback function for HTML tags fixing
 */
function rcmail_html_tag_callback($matches)
{
  $tagname = $matches[2];
  $tagname = preg_replace(array(
    '/:.*$/',         // Microsoft's Smart Tags <st1:xxxx>
    '/[^a-z0-9_\[\]\!-]/i',   // forbidden characters
    ), '', $tagname);
  return $matches[1].$tagname;
}
/**
 * return table with message headers
 */
function rcmail_message_headers($attrib, $headers=null)
  {
{
  global $OUTPUT, $MESSAGE, $PRINT_MODE, $RCMAIL;
  static $sa_attrib;
@@ -967,7 +917,7 @@
  }
  // show these headers
  $standard_headers = array('subject', 'from', 'to', 'cc', 'bcc', 'replyto',
  $standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto',
    'mail-reply-to', 'mail-followup-to', 'date', 'priority');
  $exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array();
  $output_headers = array();
@@ -1012,6 +962,14 @@
      if ($headers['mail-replyto'] != $headers['reply-to']
        && $headers['reply-to'] != $headers['from']
      ) {
        $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title);
        $ishtml = true;
      }
      else
        continue;
    }
    else if ($hkey == 'sender') {
      if ($headers['sender'] != $headers['from']) {
        $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title);
        $ishtml = true;
      }
@@ -1123,9 +1081,9 @@
        $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers));
      }
      else if ($part->type == 'content') {
        // unsapported
        // unsupported (e.g. encrypted)
        if ($part->realtype) {
          if ($part->realtype == 'multipart/encrypted') {
          if ($part->realtype == 'multipart/encrypted' || $part->realtype == 'application/pkcs7-mime') {
            $out .= html::span('part-notice', rcube_label('encryptedmessage'));
          }
          continue;
@@ -1231,7 +1189,7 @@
             html::a($show_link + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)),
               html::img(array(
                'class' => 'image-thumbnail',
                'src'   => $MESSAGE->get_part_url($attach_prop->mime_id, true) . '&_thumb=1',
                'src'   => $MESSAGE->get_part_url($attach_prop->mime_id, 'image') . '&_thumb=1',
                'title' => $attach_prop->filename,
                'alt'   => $attach_prop->filename,
                'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size),
@@ -1251,7 +1209,7 @@
            html::tag('legend', 'image-filename', Q($attach_prop->filename)) .
            html::p(array('align' => "center"),
              html::img(array(
                'src'   => $MESSAGE->get_part_url($attach_prop->mime_id, true),
                'src'   => $MESSAGE->get_part_url($attach_prop->mime_id, 'image'),
                'title' => $attach_prop->filename,
                'alt'   => $attach_prop->filename,
              )))
@@ -1282,7 +1240,7 @@
  // Content-Type: image/*...
  if (preg_match($mime_regex, $part->mimetype)) {
    return $part->mimetype;
    return rcmail_fix_mimetype($part->mimetype);
  }
  // Many clients use application/octet-stream, we'll detect mimetype
@@ -1309,20 +1267,6 @@
  ) {
    return $types[$extension];
  }
}
/**
 * Convert all relative URLs according to a <base> in HTML
 */
function rcmail_resolve_base($body)
{
  // check for <base href=...>
  if (preg_match('!(<base.*href=["\']?)([hftps]{3,5}://[a-z0-9/.%-]+)!i', $body, $regs)) {
    $replacer = new rcube_base_replacer($regs[2]);
    $body     = $replacer->replace($body);
  }
  return $body;
}
@@ -1497,6 +1441,12 @@
    $name   = $part['name'];
    $mailto = $part['mailto'];
    $string = $part['string'];
    $valid  = check_email($mailto, false);
    // phishing email prevention (#1488981), e.g. "valid@email.addr <phishing@email.addr>"
    if ($name && $valid && $name != $mailto && strpos($name, '@')) {
      $name = '';
    }
    // IDNA ASCII to Unicode
    if ($name == $mailto)
@@ -1510,7 +1460,7 @@
      // for printing we display all addresses
      continue;
    }
    else if (check_email($part['mailto'], false)) {
    else if ($valid) {
      if ($linked) {
        $address = html::a(array(
            'href' => 'mailto:'.$mailto,
@@ -1528,7 +1478,7 @@
      if ($addicon && $_SESSION['writeable_abook']) {
        $address .= html::a(array(
            'href' => "#add",
            'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, $string),
            'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, JQ($string)),
            'title' => rcube_label('addtoaddressbook'),
            'class' => 'rcmaddcontact',
          ),
@@ -1543,7 +1493,7 @@
      if ($name)
        $address .= Q($name);
      if ($mailto)
        $address .= (strlen($address) ? ' ' : '') . sprintf('&lt;%s&gt;', Q($mailto));
        $address = trim($address . ' ' . Q($name ? sprintf('<%s>', $mailto) : $mailto));
    }
    $address = html::span('adr', $address);
@@ -1656,10 +1606,7 @@
  $part  = $MESSAGE->mime_parts[$part];
  $table = new html_table(array('cols' => 3));
  $filename = $part->filename;
  if (empty($filename) && $attach_prop->mimetype == 'text/html') {
    $filename = rcube_label('htmlmessage');
  }
  $filename = rcmail_attachment_name($part);
  if (!empty($filename)) {
    $table->add('title', Q(rcube_label('filename')));
@@ -1672,7 +1619,6 @@
  return $table->show($attrib);
}
function rcmail_message_part_frame($attrib)
@@ -1749,6 +1695,9 @@
    if ($agent = $RCMAIL->config->get('useragent'))
      $headers['User-Agent'] = $agent;
    if ($RCMAIL->config->get('mdn_use_from'))
      $options['mdn_use_from'] = true;
    $body = rcube_label("yourmessage") . "\r\n\r\n" .
      "\t" . rcube_label("to") . ': ' . rcube_mime::decode_mime_string($message->headers->to, $message->headers->charset) . "\r\n" .
      "\t" . rcube_label("subject") . ': ' . $message->subject . "\r\n" .
@@ -1770,7 +1719,7 @@
    $compose->setTXTBody(rc_wordwrap($body, 75, "\r\n"));
    $compose->addAttachment($report, 'message/disposition-notification', 'MDNPart2.txt', false, '7bit', 'inline');
    $sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file);
    $sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options);
    if ($sent)
    {
@@ -1891,10 +1840,44 @@
  // application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608
  if (preg_match('/^application\/pdf.+/', $name))
    $name = 'application/pdf';
  // treat image/pjpeg (image/pjpg, image/jpg) as image/jpeg (#1489097)
  else if (preg_match('/^image\/p?jpe?g$/', $name))
    $name = 'image/jpeg';
  return $name;
}
// return attachment filename, handle empty filename case
function rcmail_attachment_name($attachment, $display = false)
{
    $filename = $attachment->filename;
    if ($filename === null || $filename === '') {
        if ($attachment->mimetype == 'text/html') {
            $filename = rcube_label('htmlmessage');
        }
        else {
            $ext      = (array) rcube_mime::get_mime_extensions($attachment->mimetype);
            $ext      = array_shift($ext);
            $filename = rcube_label('messagepart') . ' ' . $attachment->mime_id;
            if ($ext) {
                $filename .= '.' . $ext;
            }
        }
    }
    $filename = preg_replace('[\r\n]', '', $filename);
    // Display smart names for some known mimetypes
    if ($display) {
        if (preg_match('/application\/(pgp|pkcs7)-signature/i', $attachment->mimetype)) {
            $filename = rcube_label('digitalsig');
        }
    }
    return $filename;
}
function rcmail_search_filter($attrib)
{
  global $OUTPUT, $CONFIG;