Aleksander Machniak
2013-11-04 a8b004e8d8f040d868e4b19da9527c177be9959d
program/steps/mail/func.inc
@@ -97,6 +97,7 @@
  $OUTPUT->set_env('delimiter', $delimiter);
  $OUTPUT->set_env('threading', $threading);
  $OUTPUT->set_env('threads', $threading || $RCMAIL->storage->get_capability('THREAD'));
  $OUTPUT->set_env('reply_all_mode', (int) $RCMAIL->config->get('reply_all_mode'));
  $OUTPUT->set_env('preview_pane_mark_read', $RCMAIL->config->get('preview_pane_mark_read', 0));
  if ($RCMAIL->storage->get_capability('QUOTA')) {
    $OUTPUT->set_env('quota', true);
@@ -120,13 +121,47 @@
  if (!$OUTPUT->ajax_call)
    $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash',
      'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage',
      'copy', 'move', 'quota');
      'copy', 'move', 'quota', 'replyall', 'replylist', 'importwait');
  $pagetitle = $RCMAIL->localize_foldername($RCMAIL->storage->mod_folder($mbox_name), true);
  $pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle);
  $OUTPUT->set_pagetitle($pagetitle);
}
// register UI objects
$OUTPUT->add_handlers(array(
  'mailboxlist'         => 'rcmail_mailbox_list',
  'messages'            => 'rcmail_message_list',
  'messagecountdisplay' => 'rcmail_messagecount_display',
  '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',
  'messageimportform'   => 'rcmail_message_import_form',
  'searchfilter'        => 'rcmail_search_filter',
  'searchform'          => array($OUTPUT, 'search_form'),
));
// register action aliases
$RCMAIL->register_action_map(array(
    'refresh' => 'check_recent.inc',
    'preview' => 'show.inc',
    'print'   => 'show.inc',
    'move'    => 'move_del.inc',
    'delete'  => 'move_del.inc',
    'send'    => 'sendmail.inc',
    'expunge' => 'folders.inc',
    'purge'   => 'folders.inc',
    'remove-attachment'  => 'attachments.inc',
    'display-attachment' => 'attachments.inc',
    'upload'             => 'attachments.inc',
    'group-expand'       => 'autocomplete.inc',
));
/**
 * Returns 'to' if current folder is configured Sent or Drafts
@@ -143,7 +178,9 @@
  $sent_mbox   = $RCMAIL->config->get('sent_mbox');
  $drafts_mbox = $RCMAIL->config->get('drafts_mbox');
  if (strpos($mbox.$delim, $sent_mbox.$delim) === 0 || strpos($mbox.$delim, $drafts_mbox.$delim) === 0) {
  if ((strpos($mbox.$delim, $sent_mbox.$delim) === 0 || strpos($mbox.$delim, $drafts_mbox.$delim) === 0)
    && strtoupper($mbox) != 'INBOX'
  ) {
    return 'to';
  }
@@ -605,6 +642,8 @@
            $message->set_safe(true);
          }
        }
        $RCMAIL->plugins->exec_hook('message_check_safe', array('message' => $message));
        break;
      case 2: // always
@@ -900,7 +939,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))
@@ -1345,9 +1384,6 @@
{
  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    = strtolower($matches[1]);
  $attrib = parse_attrib_string($matches[2]);
  $end    = '>';
@@ -1362,12 +1398,36 @@
    $attrib['href'] = $RCMAIL->url(array('task' => 'utils', 'action' => 'modcss', 'u' => $tempurl, 'c' => $GLOBALS['rcmail_html_container_id']));
    $end = ' />';
  }
  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[3]));
  else if (preg_match('/^mailto:(.+)/i', $attrib['href'], $mailto)) {
    list($mailto, $url) = explode('?', html_entity_decode($mailto[1], ENT_QUOTES, 'UTF-8'), 2);
    $url       = urldecode($url);
    $mailto    = urldecode($mailto);
    $addresses = rcube_mime::decode_address_list($mailto, null, true);
    $mailto    = array();
    // do sanity checks on recipients
    foreach ($addresses as $idx => $addr) {
      if (rcube_utils::check_email($addr['mailto'], false)) {
        $addresses[$idx] = $addr['mailto'];
        $mailto[] = $addr['string'];
      }
      else {
        unset($addresses[$idx]);
      }
    }
    if (!empty($addresses)) {
      $attrib['href'] = 'mailto:' . implode(',', $addresses);
      $attrib['onclick'] = sprintf(
        "return %s.command('compose','%s',this)",
        JS_OBJECT_NAME,
        JQ(implode(',', $mailto) . ($url ? "?$url" : '')));
    }
    else {
      $attrib['href'] = '#NOP';
      $attrib['onclick'] = '';
    }
  }
  else if (empty($attrib['href']) && !$attrib['name']) {
    $attrib['href'] = './#NOP';
@@ -1432,15 +1492,13 @@
    $mailto = rcube_idn_to_utf8($mailto);
    if ($PRINT_MODE) {
      $out .= ($out ? ', ' : '') . sprintf('%s <%s>', Q($name), $mailto);
      // for printing we display all addresses
      continue;
      $address = sprintf('%s <%s>', Q($name), Q($mailto));
    }
    else if ($valid) {
      if ($linked) {
        $attrs = array(
           'href' => 'mailto:' . $mailto,
           'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)),
           'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ(format_email_recipient($mailto, $name))),
           'class' => "rcmContactAddress",
        );
@@ -1498,6 +1556,15 @@
  }
  if ($moreadrs) {
    if ($PRINT_MODE) {
      $out .= ' ' . html::a(array(
        'href' => '#more',
        'class' => 'morelink',
        'onclick' => '$(this).hide().next().show()',
      ), Q(rcube_label(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs))))) .
      html::span(array('style' => 'display:none'), join(', ', $allvalues));
    }
    else {
      $out .= ' ' . html::a(array(
          'href' => '#more',
          'class' => 'morelink',
@@ -1507,6 +1574,7 @@
            JQ($title))
        ),
        Q(rcube_label(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs)))));
    }
  }
  return $out;
@@ -1516,11 +1584,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)
@@ -1536,7 +1604,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
@@ -1576,45 +1644,6 @@
  }
  return $info;
}
function rcmail_message_part_controls($attrib)
{
  global $MESSAGE, $RCMAIL;
  $part = asciiwords(get_input_value('_part', RCUBE_INPUT_GPC));
  if (!is_object($MESSAGE) || !is_array($MESSAGE->parts) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE->mime_parts[$part])
    return '';
  $part  = $MESSAGE->mime_parts[$part];
  $table = new html_table(array('cols' => 3));
  $filename = rcmail_attachment_name($part);
  if (!empty($filename)) {
    $table->add('title', Q(rcube_label('filename')));
    $table->add('header', Q($filename));
    $table->add('download-link', html::a(array('href' => './?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING'])), Q(rcube_label('download'))));
  }
  $table->add('title', Q(rcube_label('filesize')));
  $table->add('header', Q($RCMAIL->message_part_size($part)));
  return $table->show($attrib);
}
function rcmail_message_part_frame($attrib)
{
  global $MESSAGE;
  $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' ? '_embed=' : '_preload='), $_SERVER['QUERY_STRING']);
  return html::iframe($attrib);
}
@@ -1731,7 +1760,7 @@
        $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[] = format_email($addr['mailto']);
                $a_recipients[] = strtolower($addr['mailto']);
                $a_names[]      = $addr['name'];
            }
        }
@@ -1740,35 +1769,41 @@
            $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[] = format_email($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
    // decode From: address
    $from = rcube_mime::decode_address_list($MESSAGE->headers->from, null, true, $MESSAGE->headers->charset);
    $from = array_shift($from);
    $from['mailto'] = strtolower($from['mailto']);
    $from_idx   = null;
    $found_idx  = array('to' => null, 'from' => null);
    $check_from = in_array($compose_mode, array('draft', 'edit', 'reply'));
    // Select identity
    foreach ($identities as $idx => $ident) {
        // use From header
        if (in_array($compose_mode, array('draft', 'edit'))) {
            if ($MESSAGE->headers->from == $ident['ident']) {
        // use From: header when in edit/draft or reply-to-self
        if ($check_from && $from['mailto'] == strtolower($ident['email_ascii'])) {
            // remember first matching identity address
            if ($found_idx['from'] === null) {
                $found_idx['from'] = $idx;
            }
            // match identity name
            if ($from['name'] && $ident['name'] && $from['name'] == $ident['name']) {
                $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($ident['email_ascii'], $a_recipients)) !== false) {
            if ($found_idx === null) {
                $found_idx = $idx;
        // use replied/forwarded message recipients
        else if (($found = array_search(strtolower($ident['email_ascii']), $a_recipients)) !== false) {
            // remember first matching identity address
            if ($found_idx['to'] === null) {
                $found_idx['to'] = $idx;
            }
            // match identity name
            if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) {
@@ -1778,42 +1813,42 @@
        }
    }
    // If matching by name+address doesn't found any matches, get first found address (identity)
    // If matching by name+address didn't find any matches,
    // get first found identity (address) if any
    if ($from_idx === null) {
        $from_idx = $found_idx;
        $from_idx = $found_idx['from'] !== null ? $found_idx['from'] : $found_idx['to'];
    }
    // Try Return-Path
    if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) {
        $return_path = array_map('strtolower', (array) $return_path);
        foreach ($identities as $idx => $ident) {
            if (strpos($return_path, str_replace('@', '=', $ident['email_ascii']).'@') !== false) {
                $from_idx = $idx;
                break;
            // 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 = strtolower($ident['email_ascii']);
            $ident2 = str_replace('@', '=', $ident1);
            $ident1 = '<' . $ident1 . '>';
            $ident2 = '-' . $ident2 . '@';
            foreach ($return_path as $path) {
                if ($path == $ident1 || 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;
            }
        }
    }
    // See identity_select plugin for example usage of this hook
    $plugin = rcmail::get_instance()->plugins->exec_hook('identity_select',
        array('message' => $MESSAGE, 'identities' => $identities, 'selected' => $from_idx));
    // 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;
            }
        }
    }
    $selected = $plugin['selected'];
    return $identities[$from_idx !== null ? $from_idx : $default_identity];
    // default identity is always first on the list
    return $identities[$selected !== null ? $selected : 0];
}
// Fixes some content-type names
@@ -1919,35 +1954,36 @@
  $RCMAIL->output->send('messageerror');
}
// register UI objects
$OUTPUT->add_handlers(array(
  'mailboxlist' => 'rcmail_mailbox_list',
  'messages' => 'rcmail_message_list',
  'messagecountdisplay' => 'rcmail_messagecount_display',
  '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',
  'messagepartcontrols' => 'rcmail_message_part_controls',
  'searchfilter' => 'rcmail_search_filter',
  'searchform' => array($OUTPUT, 'search_form'),
));
function rcmail_message_import_form($attrib = array())
{
  global $OUTPUT;
// register action aliases
$RCMAIL->register_action_map(array(
    'refresh' => 'check_recent.inc',
    'preview' => 'show.inc',
    'print'   => 'show.inc',
    'moveto'  => 'move_del.inc',
    'delete'  => 'move_del.inc',
    'send'    => 'sendmail.inc',
    'expunge' => 'folders.inc',
    'purge'   => 'folders.inc',
    'remove-attachment'  => 'attachments.inc',
    'display-attachment' => 'attachments.inc',
    'upload'             => 'attachments.inc',
    'group-expand'       => 'autocomplete.inc',
));
  // set defaults
  $attrib += array('id' => 'rcmImportform', 'buttons' => 'yes');
  // Get filesize, enable upload progress bar
  $max_filesize = rcube_upload_init();
  $button = new html_inputfield(array('type' => 'button'));
  $fileinput = new html_inputfield(array(
      'type' => 'file',
      'name' => '_file[]',
      'multiple' => 'multiple',
      'accept' => ".eml, .mbox, message/rfc822, text/*",
  ));
  $out = html::div($attrib,
    $OUTPUT->form_tag(array('id' => $attrib['id'].'Frm', 'method' => 'post', 'enctype' => 'multipart/form-data'),
      html::tag('input', array('type' => 'hidden', 'name' => '_unlock', 'value' => '')) .
      html::div(null, $fileinput->show()) .
      html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) .
      (get_boolean($attrib['buttons']) ? html::div('buttons',
        $button->show(rcube_label('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' .
        $button->show(rcube_label('upload'), array('class' => 'button mainaction', 'onclick' => JS_OBJECT_NAME . ".command('import-messages', this.form)"))
      ) : '')
    )
  );
  $OUTPUT->add_gui_object('importform', $attrib['id'].'Frm');
  return $out;
}