Thomas Bruederli
2014-06-05 99cdca46b7bcc46fe6affd9e9f9f60a546b2e5b8
program/steps/mail/compose.inc
@@ -62,36 +62,6 @@
    rcmail_process_compose_params($COMPOSE);
    // add attachments listed by message_compose hook
    if (is_array($plugin['attachments'])) {
        foreach ($plugin['attachments'] as $attach) {
            // we have structured data
            if (is_array($attach)) {
                $attachment = $attach;
            }
            // only a file path is given
            else {
                $filename   = basename($attach);
                $attachment = array(
                    'group'    => $COMPOSE_ID,
                    'name'     => $filename,
                    'mimetype' => rcube_mime::file_content_type($attach, $filename),
                    'path'     => $attach,
                );
            }
            // save attachment if valid
            if (($attachment['data'] && $attachment['name']) || ($attachment['path'] && file_exists($attachment['path']))) {
                $attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment);
            }
            if ($attachment['status'] && !$attachment['abort']) {
                unset($attachment['data'], $attachment['status'], $attachment['abort']);
                $COMPOSE['attachments'][$attachment['id']] = $attachment;
            }
        }
    }
    // check if folder for saving sent messages exists and is subscribed (#1486802)
    if ($sent_folder = $COMPOSE['param']['sent_mbox']) {
        rcmail_check_sent_folder($sent_folder, true);
@@ -111,7 +81,8 @@
    'nobodywarning', 'notsentwarning', 'notuploadedwarning', 'savingmessage', 'sendingmessage', 
    'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany',
    'fileuploaderror', 'sendmessage', 'savenewresponse', 'responsename', 'responsetext', 'save',
    'savingresponse', 'restoresavedcomposedata', 'restoremessage', 'delete', 'restore', 'ignore');
    'savingresponse', 'restoresavedcomposedata', 'restoremessage', 'delete', 'restore', 'ignore',
    'selectimportfile');
$OUTPUT->set_pagetitle($RCMAIL->gettext('compose'));
@@ -121,10 +92,13 @@
$OUTPUT->set_env('top_posting', intval($RCMAIL->config->get('reply_mode')) > 0);
$OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ',')));
$drafts_mbox     = $RCMAIL->config->get('drafts_mbox');
$config_show_sig = $RCMAIL->config->get('show_sig', 1);
// add config parameters to client script
if (!empty($CONFIG['drafts_mbox'])) {
    $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']);
    $OUTPUT->set_env('draft_autosave', $CONFIG['draft_autosave']);
if (strlen($drafts_mbox)) {
    $OUTPUT->set_env('drafts_mailbox', $drafts_mbox);
    $OUTPUT->set_env('draft_autosave', $RCMAIL->config->get('draft_autosave'));
}
// default font for HTML editor
@@ -142,7 +116,7 @@
if ($msg_uid = $COMPOSE['param']['draft_uid']) {
    $compose_mode = RCUBE_COMPOSE_DRAFT;
    $OUTPUT->set_env('draft_id', $msg_uid);
    $RCMAIL->storage->set_folder($CONFIG['drafts_mbox']);
    $RCMAIL->storage->set_folder($drafts_mbox);
}
else if ($msg_uid = $COMPOSE['param']['reply_uid']) {
    $compose_mode = RCUBE_COMPOSE_REPLY;
@@ -159,7 +133,6 @@
$COMPOSE['mode'] = $compose_mode;
$OUTPUT->set_env('compose_mode', $compose_mode);
$config_show_sig = $RCMAIL->config->get('show_sig', 1);
if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) {
    // don't add signature in draft/edit mode, we'll also not remove the old-one
    // but only on page display, later we should be able to change identity/sig (#1489229)
@@ -186,7 +159,9 @@
        $RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$msg_uid]);
    }
    else {
        $prefer_html = $CONFIG['prefer_html'] || $CONFIG['htmleditor'] || $compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT;
        $prefer_html = $RCMAIL->config->get('prefer_html') || $RCMAIL->config->get('htmleditor')
            || $compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT;
        $RCMAIL->config->set('prefer_html', $prefer_html);
    }
@@ -204,14 +179,20 @@
    if (!$MESSAGE->headers) {
        // error
    }
    else if ($compose_mode == RCUBE_COMPOSE_REPLY) {
        $COMPOSE['reply_uid']   = $msg_uid;
    else if ($compose_mode == RCUBE_COMPOSE_FORWARD || $compose_mode == RCUBE_COMPOSE_REPLY) {
        if ($compose_mode == RCUBE_COMPOSE_REPLY) {
            $COMPOSE['reply_uid'] = $msg_uid;
            if (!empty($COMPOSE['param']['all'])) {
                $MESSAGE->reply_all = $COMPOSE['param']['all'];
            }
        }
        else {
            $COMPOSE['forward_uid'] = $msg_uid;
        }
        $COMPOSE['reply_msgid'] = $MESSAGE->headers->messageID;
        $COMPOSE['references']  = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID);
        if (!empty($COMPOSE['param']['all'])) {
            $MESSAGE->reply_all = $COMPOSE['param']['all'];
        }
        // Save the sent message in the same folder of the message being replied to
        if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $COMPOSE['mailbox'])
@@ -267,6 +248,10 @@
    }
}
if (!empty($COMPOSE['reply_msgid'])) {
    $OUTPUT->set_env('reply_msgid', $COMPOSE['reply_msgid']);
}
$MESSAGE->compose = array();
// get user's identities
@@ -290,6 +275,7 @@
$a_recipients = array();
$parts        = array('to', 'cc', 'bcc', 'replyto', 'followupto');
$separator    = trim($RCMAIL->config->get('recipients_separator', ',')) . ' ';
$from_email   = @mb_strtolower($MESSAGE->compose['from_email']);
foreach ($parts as $header) {
    $fvalue        = '';
@@ -387,21 +373,20 @@
                continue;
            }
            $mailto = format_email(rcube_utils::idn_to_utf8($addr_part['mailto']));
            // According to RFC5321 local part of email address is case-sensitive
            // however, here it is better to compare addresses in case-insensitive manner
            $mailto    = format_email(rcube_utils::idn_to_utf8($addr_part['mailto']));
            $mailto_lc = mb_strtolower($addr_part['mailto']);
            if (!in_array($mailto, $a_recipients)
                && ($header == 'to'
                    || $compose_mode != RCUBE_COMPOSE_REPLY
                    || empty($MESSAGE->compose['from_email'])
                    || $mailto != $MESSAGE->compose['from_email'])
            if (($header == 'to' || $compose_mode != RCUBE_COMPOSE_REPLY || $mailto_lc != $from_email)
                && !in_array($mailto_lc, $a_recipients)
            ) {
                if ($addr_part['name'] && $addr_part['mailto'] != $addr_part['name'])
                    $string = format_email_recipient($mailto, $addr_part['name']);
                else
                    $string = $mailto;
                if ($addr_part['name'] && $mailto != $addr_part['name']) {
                    $mailto = format_email_recipient($mailto, $addr_part['name']);
                }
                $fvalue[]       = $string;
                $a_recipients[] = $addr_part['mailto'];
                $fvalue[]       = $mailto;
                $a_recipients[] = $mailto_lc;
            }
        }
@@ -478,6 +463,11 @@
        }
    }
    // resolve _forward_uid=* to an absolute list of messages from a search result
    if ($COMPOSE['param']['forward_uid'] == '*' && is_object($_SESSION['search'][1])) {
        $COMPOSE['param']['forward_uid'] = $_SESSION['search'][1]->get();
    }
    // clean HTML message body which can be submitted by URL
    if (!empty($COMPOSE['param']['body'])) {
        $COMPOSE['param']['body'] = rcmail_wash_html($COMPOSE['param']['body'], array('safe' => false, 'inline_html' => true), array());
@@ -491,6 +481,36 @@
    // pipe compose parameters thru plugins
    $plugin = $RCMAIL->plugins->exec_hook('message_compose', $COMPOSE);
    $COMPOSE['param'] = array_merge($COMPOSE['param'], $plugin['param']);
    // add attachments listed by message_compose hook
    if (is_array($plugin['attachments'])) {
        foreach ($plugin['attachments'] as $attach) {
            // we have structured data
            if (is_array($attach)) {
                $attachment = $attach + array('group' => $COMPOSE_ID);
            }
            // only a file path is given
            else {
                $filename   = basename($attach);
                $attachment = array(
                    'group'    => $COMPOSE_ID,
                    'name'     => $filename,
                    'mimetype' => rcube_mime::file_content_type($attach, $filename),
                    'path'     => $attach,
                );
            }
            // save attachment if valid
            if (($attachment['data'] && $attachment['name']) || ($attachment['path'] && file_exists($attachment['path']))) {
                $attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment);
            }
            if ($attachment['status'] && !$attachment['abort']) {
                unset($attachment['data'], $attachment['status'], $attachment['abort']);
                $COMPOSE['attachments'][$attachment['id']] = $attachment;
            }
        }
    }
}
function rcmail_compose_headers($attrib)
@@ -591,7 +611,7 @@
                $text = $html = $sql_arr['signature'];
                if ($sql_arr['html_signature']) {
                    $h2t  = new rcube_html2text($sql_arr['signature'], false, false);
                    $h2t  = new rcube_html2text($sql_arr['signature'], false, true);
                    $text = trim($h2t->get_text());
                }
                else {
@@ -604,7 +624,8 @@
                }
                if (!$sql_arr['html_signature']) {
                    $html = "<pre>" . $html . "</pre>";
                    $t2h  = new rcube_text2html($sql_arr['signature'], false);
                    $html = $t2h->get_html();
                }
                $a_signatures[$identity_id]['text'] = $text;
@@ -806,15 +827,8 @@
                }
            }
            if ($part->ctype_parameters['format'] == 'flowed') {
                $body = rcube_mime::unfold_flowed($body);
            }
            // add HTML formatting
            $body = rcmail_plain_body($body);
            if ($body) {
                $body = '<pre>' . $body . '</pre>';
            }
            $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed');
        }
    }
    else {
@@ -849,7 +863,7 @@
function rcmail_compose_body($attrib)
{
    global $RCMAIL, $CONFIG, $OUTPUT, $HTML_MODE, $MESSAGE_BODY;
    global $RCMAIL, $OUTPUT, $HTML_MODE, $MESSAGE_BODY;
    list($form_start, $form_end) = get_form_tags($attrib);
    unset($attrib['form']);
@@ -901,7 +915,7 @@
    $RCMAIL->html_editor();
    // Set language list
    if (!empty($CONFIG['enable_spellcheck'])) {
    if ($RCMAIL->config->get('enable_spellcheck')) {
        $engine           = new rcube_spellchecker();
        $dictionary       = (bool) $RCMAIL->config->get('spellcheck_dictionary');
        $spellcheck_langs = $engine->languages();
@@ -937,8 +951,7 @@
            "googie.setLanguages(%s);\n".
            "googie.setCurrentLanguage('%s');\n".
            "googie.setDecoration(false);\n".
            "googie.decorateTextarea('%s');\n".
            "%s.set_env('spellcheck', googie);",
            "googie.decorateTextarea('%s');\n",
            $RCMAIL->output->get_skin_path(),
            $RCMAIL->url(array('_task' => 'utils', '_action' => 'spell', '_remote' => 1)),
                !empty($dictionary) ? 'true' : 'false',
@@ -950,14 +963,13 @@
            rcube::JQ(rcube::Q($RCMAIL->gettext('addtodict'))),
            rcube_output::json_serialize($spellcheck_langs),
            $lang,
            $attrib['id'],
            rcmail_output::JS_OBJECT_NAME), 'foot');
            $attrib['id']), 'foot');
        $OUTPUT->add_label('checking');
        $OUTPUT->set_env('spellcheck_langs', join(',', $editor_lang_set));
    }
    $out .= "\n".'<iframe name="savetarget" src="program/resources/blank.gif" style="width:0;height:0;border:none;visibility:hidden;"></iframe>';
    $out .= "\n".'<iframe name="savetarget" src="program/resources/blank.gif" style="width:0;height:0;border:none;visibility:hidden;" aria-hidden="true"></iframe>';
    return $out;
}
@@ -1233,6 +1245,7 @@
    $storage = $RCMAIL->get_storage();
    $names   = array();
    $refs    = array();
    $loaded_attachments = array();
    foreach ((array)$COMPOSE['attachments'] as $attachment) {
@@ -1243,7 +1256,10 @@
        $index = $storage->index(null, rcmail_sort_column(), rcmail_sort_order());
        $COMPOSE['forward_uid'] = $index->get();
    }
    else {
    else if (!is_array($COMPOSE['forward_uid']) && strpos($COMPOSE['forward_uid'], ':')) {
        $COMPOSE['forward_uid'] = rcube_imap_generic::uncompressMessageSet($COMPOSE['forward_uid']);
    }
    else if (is_string($COMPOSE['forward_uid'])) {
        $COMPOSE['forward_uid'] = explode(',', $COMPOSE['forward_uid']);
    }
@@ -1312,6 +1328,18 @@
        else if ($path) {
            @unlink($path);
        }
        if ($message->headers->messageID) {
            $refs[] = $message->headers->messageID;
        }
    }
    // set In-Reply-To and References headers
    if (count($refs) == 1) {
        $COMPOSE['reply_msgid'] = $refs[0];
    }
    if (!empty($refs)) {
        $COMPOSE['references'] = implode(' ', $refs);
    }
}
@@ -1427,6 +1455,9 @@
            $subject = $MESSAGE->subject;
        else
            $subject = 'Re: '.$MESSAGE->subject;
        // replace (was: ...) (#1489375)
        $subject = preg_replace('/\s*\([wW]as:[^\)]+\)\s*$/', '', $subject);
    }
    // create a forward-subject
    else if ($compose_mode == RCUBE_COMPOSE_FORWARD) {
@@ -1453,20 +1484,21 @@
function rcmail_compose_attachment_list($attrib)
{
    global $RCMAIL, $OUTPUT, $CONFIG, $COMPOSE;
    global $RCMAIL, $OUTPUT, $COMPOSE;
    // add ID if not given
    if (!$attrib['id'])
        $attrib['id'] = 'rcmAttachmentList';
    $out    = "\n";
    $jslist = array();
    $button = '';
    $out       = "\n";
    $jslist    = array();
    $button    = '';
    $skin_path = $RCMAIL->config->get('skin_path');
    if (is_array($COMPOSE['attachments'])) {
        if ($attrib['deleteicon']) {
            $button = html::img(array(
                'src' => $CONFIG['skin_path'] . $attrib['deleteicon'],
                'src' => $skin_path . $attrib['deleteicon'],
                'alt' => $RCMAIL->gettext('delete')
            ));
        }
@@ -1503,13 +1535,13 @@
    }
    if ($attrib['deleteicon'])
        $COMPOSE['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon'];
        $COMPOSE['deleteicon'] = $skin_path . $attrib['deleteicon'];
    else if (rcube_utils::get_boolean($attrib['textbuttons']))
        $COMPOSE['textbuttons'] = true;
    if ($attrib['cancelicon'])
        $OUTPUT->set_env('cancelicon', $CONFIG['skin_path'] . $attrib['cancelicon']);
        $OUTPUT->set_env('cancelicon', $skin_path . $attrib['cancelicon']);
    if ($attrib['loadingicon'])
        $OUTPUT->set_env('loadingicon', $CONFIG['skin_path'] . $attrib['loadingicon']);
        $OUTPUT->set_env('loadingicon', $skin_path . $attrib['loadingicon']);
    $OUTPUT->set_env('attachments', $jslist);
    $OUTPUT->add_gui_object('attachmentlist', $attrib['id']);
@@ -1670,7 +1702,7 @@
    if (empty($attrib['name']))
        $attrib['name'] = 'editorSelect';
    $attrib['onchange'] = "return rcmail_toggle_editor(this, '".$attrib['editorid']."', '_is_html')";
    $attrib['onchange'] = "return rcmail.command('toggle-editor', {id: '".$attrib['editorid']."', html: this.value == 'html'}, '', event)";
    $select = new html_select($attrib);
@@ -1827,9 +1859,10 @@
    foreach ($RCMAIL->get_compose_responses(true) as $response) {
        $key = $response['key'];
        $item = html::a(array(
            'href '=> '#'.urlencode($response['name']),
            'href' => '#'.urlencode($response['name']),
            'class' => rtrim('insertresponse ' . $attrib['itemclass']),
            'unselectable' => 'on',
            'tabindex' => '0',
            'rel' => $key,
        ), rcube::Q($response['name']));