From 93adce7abfcfc3c8cec06566f0b5cb85d4f0dc49 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Fri, 06 Sep 2013 03:13:24 -0400
Subject: [PATCH] Make identities matching case insensitive (#1485480)

---
 program/steps/mail/func.inc |  393 +++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 274 insertions(+), 119 deletions(-)

diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 47d1a48..8de76c3 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, The Roundcube Dev Team                       |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
  |                                                                       |
  | Licensed under the GNU General Public License version 3 or            |
  | any later version with exceptions for skins & plugins.                |
@@ -471,7 +471,7 @@
     $OUTPUT->set_env('contentframe', $attrib['id']);
   $OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/resources/blank.gif');
 
-  return html::iframe($attrib);
+  return $OUTPUT->frame($attrib, true);
 }
 
 
@@ -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';
   }
@@ -751,9 +715,9 @@
   }
   // text/enriched
   else if ($data['type'] == 'enriched') {
+    $body = rcube_enriched::to_html($data['body']);
+    $body = rcmail_wash_html($body, $data, $part->replaces);
     $part->ctype_secondary = 'html';
-    require_once(INSTALL_PATH . 'program/lib/enriched.inc');
-    $body = Q(enriched_to_html($data['body']), 'show');
   }
   else {
     // assert plaintext
@@ -789,7 +753,7 @@
   global $RCMAIL;
 
   // make links and email-addresses clickable
-  $replacer = new rcube_string_replacer;
+  $replacer = new rcmail_string_replacer;
 
   // search for patterns like links and e-mail addresses and replace with tokens
   $body = $replacer->replace($body);
@@ -801,17 +765,19 @@
 
   // find/mark quoted lines...
   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]));
+    if ($body[$n][0] == '>' && preg_match('/^(>+ {0,1})+/', $body[$n], $regs)) {
+      $q        = substr_count($regs[0], '>');
       $body[$n] = substr($body[$n], strlen($regs[0]));
 
       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,31 +887,15 @@
 
 
 /**
- * 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)
-  {
+function rcmail_message_headers($attrib, $headers=null)
+{
   global $OUTPUT, $MESSAGE, $PRINT_MODE, $RCMAIL;
   static $sa_attrib;
 
   // keep header table attrib
-  if (is_array($attrib) && !$sa_attrib)
+  if (is_array($attrib) && !$sa_attrib && !$attrib['valueof'])
     $sa_attrib = $attrib;
   else if (!is_array($attrib) && is_array($sa_attrib))
     $attrib = $sa_attrib;
@@ -954,11 +904,20 @@
     return FALSE;
 
   // get associative array of headers object
-  if (!$headers)
-    $headers = is_object($MESSAGE->headers) ? get_object_vars($MESSAGE->headers) : $MESSAGE->headers;
+  if (!$headers) {
+    $headers_obj = $MESSAGE->headers;
+    $headers = get_object_vars($MESSAGE->headers);
+  }
+  else if (is_object($headers)) {
+    $headers_obj = $headers;
+    $headers = get_object_vars($headers_obj);
+  }
+  else {
+    $headers_obj = rcube_message_header::from_array($headers);
+  }
 
   // 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();
@@ -970,7 +929,7 @@
       $value = $headers[$hkey];
     else if ($headers['others'][$hkey])
       $value = $headers['others'][$hkey];
-    else
+    else if (!$attrib['valueof'])
       continue;
 
     if (in_array($hkey, $exclude_headers))
@@ -1009,6 +968,14 @@
       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;
+      }
+      else
+        continue;
+    }
     else if ($hkey == 'mail-followup-to') {
       $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title);
       $ishtml = true;
@@ -1031,7 +998,7 @@
   }
 
   $plugin = $RCMAIL->plugins->exec_hook('message_headers_output',
-    array('output' => $output_headers, 'headers' => $MESSAGE->headers, 'exclude' => $exclude_headers));
+    array('output' => $output_headers, 'headers' => $headers_obj, 'exclude' => $exclude_headers));
 
   // single header value is requested
   if (!empty($attrib['valueof']))
@@ -1060,10 +1027,10 @@
     '4' => 'low',
     '5' => 'lowest',
   );
-  
+
   if ($value && $labels_map[$value])
     return rcube_label($labels_map[$value]);
-    
+
   return '';
 }
 
@@ -1110,12 +1077,13 @@
 
   if (!empty($MESSAGE->parts)) {
     foreach ($MESSAGE->parts as $i => $part) {
-      if ($part->type == 'headers')
-        $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers);
+      if ($part->type == 'headers') {
+        $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;
@@ -1138,6 +1106,15 @@
         // fetch part if not available
         if (!isset($part->body))
           $part->body = $MESSAGE->get_part_content($part->mime_id);
+
+        // extract headers from message/rfc822 parts
+        if ($part->mimetype == 'message/rfc822') {
+          $msgpart = rcube_mime::parse_message($part->body);
+          if (!empty($msgpart->headers)) {
+            $part = $msgpart;
+            $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers));
+          }
+        }
 
         // message is cached but not exists (#1485443), or other error
         if ($part->body === false) {
@@ -1186,7 +1163,10 @@
   }
 
   // list images after mail body
-  if ($CONFIG['inline_images'] && !empty($MESSAGE->attachments)) {
+  if ($RCMAIL->config->get('inline_images', true) && !empty($MESSAGE->attachments)) {
+    $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
+    $client_mimetypes = (array)$RCMAIL->config->get('client_mimetypes');
+
     foreach ($MESSAGE->attachments as $attach_prop) {
       // skip inline images
       if ($attach_prop->content_id && $attach_prop->disposition == 'inline') {
@@ -1194,13 +1174,47 @@
       }
 
       // Content-Type: image/*...
-      if (rcmail_part_image_type($attach_prop)) {
-        $out .= html::tag('hr') . html::p(array('align' => "center"),
-          html::img(array(
-            'src' => $MESSAGE->get_part_url($attach_prop->mime_id, true),
-            'title' => $attach_prop->filename,
-            'alt' => $attach_prop->filename,
-          )));
+      if ($mimetype = rcmail_part_image_type($attach_prop)) {
+        // display thumbnails
+        if ($thumbnail_size) {
+          $show_link = array(
+            'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
+            'onclick' => sprintf(
+              'return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)',
+              JS_OBJECT_NAME,
+              $attach_prop->mime_id,
+              $mimetype)
+          );
+          $out .= html::p('image-attachment',
+             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, 'image') . '&_thumb=1',
+                'title' => $attach_prop->filename,
+                'alt'   => $attach_prop->filename,
+                'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size),
+              ))
+            ) .
+            html::span('image-filename', Q($attach_prop->filename)) .
+            html::span('image-filesize', Q($RCMAIL->message_part_size($attach_prop))) .
+            html::span('attachment-links',
+              (in_array($mimetype, $client_mimetypes) ? html::a($show_link, rcube_label('showattachment')) . '&nbsp;' : '') .
+              html::a($show_link['href'] . '&_download=1', rcube_label('download'))
+            ) .
+            html::br(array('style' => 'clear:both'))
+          );
+        }
+        else {
+          $out .= html::tag('fieldset', 'image-attachment',
+            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, 'image'),
+                'title' => $attach_prop->filename,
+                'alt'   => $attach_prop->filename,
+              )))
+          );
+        }
       }
     }
   }
@@ -1226,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
@@ -1247,26 +1261,12 @@
 
   if ($part->filename
     && preg_match('/^application\/octet-stream$/i', $part->mimetype)
-    && preg_match('/\.([^.])$/i', $part->filename, $m)
+    && preg_match('/\.([^.]+)$/i', $part->filename, $m)
     && ($extension = strtolower($m[1]))
     && isset($types[$extension])
   ) {
     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;
 }
 
 
@@ -1294,7 +1294,7 @@
 
   // 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);
+  $body = preg_replace_callback('/<(a|link|area)\s+([^>]+)>/Ui', 'rcmail_alter_html_link', $body);
   unset($GLOBALS['rcmail_html_container_id']);
 
   $body = preg_replace(array(
@@ -1407,7 +1407,11 @@
     $attrib['target'] = '_blank';
   }
 
-  return "<$tag" . html::attrib_string($attrib, array('href','name','target','onclick','id','class','style','title','rel','type','media')) . $end;
+  // allowed attributes for a|link|area tags
+  $allow = array('href','name','target','onclick','id','class','style','title',
+    'rel','type','media','alt','coords','nohref','hreflang','shape');
+
+  return "<$tag" . html::attrib_string($attrib, $allow) . $end;
 }
 
 
@@ -1437,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)
@@ -1446,9 +1456,11 @@
     $mailto = rcube_idn_to_utf8($mailto);
 
     if ($PRINT_MODE) {
-      $out .= sprintf('%s &lt;%s&gt;', Q($name), $mailto);
+      $out .= ($out ? ', ' : '') . sprintf('%s &lt;%s&gt;', Q($name), $mailto);
+      // 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,
@@ -1466,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',
           ),
@@ -1481,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);
@@ -1520,11 +1532,11 @@
 /**
  * Wrap text to a given number of characters per line
  * but respect the mail quotation of replies messages (>).
- * Finally add another quotation level by prpending the lines
+ * Finally add another quotation level by prepending the lines
  * with >
  *
  * @param string Text to wrap
- * @param int The line width
+ * @param int    The line width
  * @return string The wrapped text
  */
 function rcmail_wrap_and_quote($text, $length = 72)
@@ -1540,7 +1552,7 @@
       $line = '>' . rtrim($line);
     else if (mb_strlen($line) > $max) {
       $newline = '';
-      foreach(explode("\n", rc_wordwrap($line, $length - 2)) as $l) {
+      foreach (explode("\n", rc_wordwrap($line, $length - 2)) as $l) {
         if (strlen($l))
           $newline .= '> ' . $l . "\n";
         else
@@ -1555,7 +1567,7 @@
     $out .= $line . "\n";
   }
 
-  return $out;
+  return rtrim($out, "\n");
 }
 
 
@@ -1594,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')));
@@ -1612,7 +1621,6 @@
 }
 
 
-
 function rcmail_message_part_frame($attrib)
 {
   global $MESSAGE;
@@ -1620,7 +1628,7 @@
   $part = $MESSAGE->mime_parts[asciiwords(get_input_value('_part', RCUBE_INPUT_GPC))];
   $ctype_primary = strtolower($part->ctype_primary);
 
-  $attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary=='text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']);
+  $attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary=='text' ? '_embed=' : '_preload='), $_SERVER['QUERY_STRING']);
 
   return html::iframe($attrib);
 }
@@ -1658,11 +1666,11 @@
   if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) &&
     ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*')))
   {
-    $identity = $RCMAIL->user->get_identity();
-    $sender = format_email_recipient($identity['email'], $identity['name']);
+    $identity  = rcmail_identity_select($message);
+    $sender    = format_email_recipient($identity['email'], $identity['name']);
     $recipient = array_shift(rcube_mime::decode_address_list(
       $message->headers->mdn_to, 1, true, $message->headers->charset));
-    $mailto = $recipient['mailto'];
+    $mailto    = $recipient['mailto'];
 
     $compose = new Mail_mime("\r\n");
 
@@ -1687,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" .
@@ -1708,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)
     {
@@ -1720,6 +1731,115 @@
   return false;
 }
 
+/**
+ * Detect recipient identity from specified message
+ */
+function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'reply')
+{
+    $a_recipients = array();
+    $a_names      = array();
+
+    if ($identities === null) {
+        $identities = rcmail::get_instance()->user->list_identities(null, true);
+    }
+
+    // extract all recipients of the reply-message
+    if (is_object($MESSAGE->headers) && in_array($compose_mode, array('reply', 'forward'))) {
+        $a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset);
+        foreach ($a_to as $addr) {
+            if (!empty($addr['mailto'])) {
+                $a_recipients[] = strtolower($addr['mailto']);
+                $a_names[]      = $addr['name'];
+            }
+        }
+
+        if (!empty($MESSAGE->headers->cc)) {
+            $a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset);
+            foreach ($a_cc as $addr) {
+                if (!empty($addr['mailto'])) {
+                    $a_recipients[] = strtolower($addr['mailto']);
+                    $a_names[]      = $addr['name'];
+                }
+            }
+        }
+    }
+
+    $from_idx         = null;
+    $found_idx        = null;
+    $default_identity = 0; // default identity is always first on the list
+
+    // Select identity
+    foreach ($identities as $idx => $ident) {
+        // use From header
+        if (in_array($compose_mode, array('draft', 'edit'))) {
+            if ($MESSAGE->headers->from == $ident['ident']) {
+                $from_idx = $idx;
+                break;
+            }
+        }
+        // reply to yourself
+        else if ($compose_mode == 'reply' && $MESSAGE->headers->from == $ident['ident']) {
+            $from_idx = $idx;
+            break;
+        }
+        // use replied message recipients
+        else if (($found = array_search(strtolower($ident['email_ascii']), $a_recipients)) !== false) {
+            if ($found_idx === null) {
+                $found_idx = $idx;
+            }
+            // match identity name
+            if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) {
+                $from_idx = $idx;
+                break;
+            }
+        }
+    }
+
+    // If matching by name+address doesn't found any matches, get first found address (identity)
+    if ($from_idx === null) {
+        $from_idx = $found_idx;
+    }
+
+    // Try Return-Path
+    if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) {
+        foreach ($identities as $idx => $ident) {
+            // Return-Path header contains an email address, but on some mailing list
+            // it can be e.g. <pear-dev-return-55250-local=domain.tld@lists.php.net>
+            // where local@domain.tld is the address we're looking for (#1489241)
+            $ident1 = $ident['email_ascii'];
+            $ident2 = str_replace('@', '=', $ident1);
+
+            foreach ((array)$return_path as $path) {
+                if (stripos($path, $ident1) !== false || stripos($path, $ident2)) {
+                    $from_idx = $idx;
+                    break 2;
+                }
+            }
+        }
+    }
+
+    // Fallback using Delivered-To
+    if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) {
+        foreach ($identities as $idx => $ident) {
+            if (in_array($ident['email_ascii'], (array)$delivered_to)) {
+                $from_idx = $idx;
+                break;
+            }
+        }
+    }
+
+    // Fallback using Envelope-To
+    if ($from_idx === null && ($envelope_to = $MESSAGE->headers->others['envelope-to'])) {
+        foreach ($identities as $idx => $ident) {
+            if (in_array($ident['email_ascii'], (array)$envelope_to)) {
+                $from_idx = $idx;
+                break;
+            }
+        }
+    }
+
+    return $identities[$from_idx !== null ? $from_idx : $default_identity];
+}
 
 // Fixes some content-type names
 function rcmail_fix_mimetype($name)
@@ -1728,8 +1848,42 @@
   // 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)
@@ -1806,6 +1960,7 @@
 
 // register action aliases
 $RCMAIL->register_action_map(array(
+    'refresh' => 'check_recent.inc',
     'preview' => 'show.inc',
     'print'   => 'show.inc',
     'moveto'  => 'move_del.inc',

--
Gitblit v1.9.1