From 3ff8cc2bc83c57010bbfe64efa76b70203857650 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Mon, 26 Nov 2012 04:45:21 -0500 Subject: [PATCH] RCMAIL_VERSION -> RCUBE_VERSION --- program/steps/mail/compose.inc | 468 +++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 330 insertions(+), 138 deletions(-) diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 76ff31d..92ec88f 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -5,8 +5,11 @@ | program/steps/mail/compose.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2011, The Roundcube Dev Team | - | Licensed under the GNU GPL | + | 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. | + | See the README file for a full license statement. | | | | PURPOSE: | | Compose a new mail message with all headers and attachments | @@ -14,9 +17,6 @@ +-----------------------------------------------------------------------+ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - - $Id$ - */ // define constants for message compose mode @@ -26,7 +26,6 @@ define('RCUBE_COMPOSE_EDIT', 0x0109); $MESSAGE_FORM = null; -$MESSAGE = null; $COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GET); $COMPOSE = null; @@ -56,7 +55,7 @@ $_SESSION['compose_data_'.$COMPOSE_ID] = array( 'id' => $COMPOSE_ID, 'param' => request2param(RCUBE_INPUT_GET), - 'mailbox' => $RCMAIL->imap->get_mailbox_name(), + 'mailbox' => $RCMAIL->storage->get_folder(), ); $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; @@ -116,7 +115,11 @@ } // redirect to a unique URL with all parameters stored in session - $OUTPUT->redirect(array('_action' => 'compose', '_id' => $COMPOSE['id'])); + $OUTPUT->redirect(array( + '_action' => 'compose', + '_id' => $COMPOSE['id'], + '_search' => $_REQUEST['_search'], + )); } @@ -127,6 +130,7 @@ 'fileuploaderror', 'sendmessage'); $OUTPUT->set_env('compose_id', $COMPOSE['id']); +$OUTPUT->set_pagetitle(rcube_label('compose')); // add config parameters to client script if (!empty($CONFIG['drafts_mbox'])) { @@ -134,13 +138,10 @@ $OUTPUT->set_env('draft_autosave', $CONFIG['draft_autosave']); } // set current mailbox in client environment -$OUTPUT->set_env('mailbox', $RCMAIL->imap->get_mailbox_name()); +$OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder()); $OUTPUT->set_env('sig_above', $RCMAIL->config->get('sig_above', false)); -$OUTPUT->set_env('top_posting', $RCMAIL->config->get('top_posting', false)); +$OUTPUT->set_env('top_posting', intval($RCMAIL->config->get('reply_mode')) > 0); $OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); - -// use jquery UI for showing prompt() dialogs -$RCMAIL->plugins->load_plugin('jqueryui'); // default font for HTML editor $font = rcube_fontdefs($RCMAIL->config->get('default_font', 'Verdana')); @@ -150,7 +151,7 @@ // get reference message and set compose mode if ($msg_uid = $COMPOSE['param']['draft_uid']) { - $RCMAIL->imap->set_mailbox($CONFIG['drafts_mbox']); + $RCMAIL->storage->set_folder($CONFIG['drafts_mbox']); $compose_mode = RCUBE_COMPOSE_DRAFT; } else if ($msg_uid = $COMPOSE['param']['reply_uid']) @@ -181,11 +182,11 @@ $MESSAGE = new rcube_message($msg_uid); // make sure message is marked as read - if ($MESSAGE && $MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN'])) - $RCMAIL->imap->set_flag($msg_uid, 'SEEN'); + if ($MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN'])) + $RCMAIL->storage->set_flag($msg_uid, 'SEEN'); if (!empty($MESSAGE->headers->charset)) - $RCMAIL->imap->set_charset($MESSAGE->headers->charset); + $RCMAIL->storage->set_charset($MESSAGE->headers->charset); if ($compose_mode == RCUBE_COMPOSE_REPLY) { @@ -241,6 +242,9 @@ $MESSAGE->forward_attachment = true; } } +else { + $MESSAGE = new stdClass(); +} $MESSAGE->compose = array(); @@ -249,7 +253,8 @@ if (count($MESSAGE->identities)) { foreach ($MESSAGE->identities as $idx => $ident) { - $email = mb_strtolower(rcube_idn_to_utf8($ident['email'])); + $ident['email'] = format_email($ident['email']); + $email = format_email(rcube_idn_to_utf8($ident['email'])); $MESSAGE->identities[$idx]['email_ascii'] = $ident['email']; $MESSAGE->identities[$idx]['ident'] = format_email_recipient($ident['email'], $ident['name']); @@ -271,19 +276,19 @@ // extract all recipients of the reply-message if (is_object($MESSAGE->headers) && in_array($compose_mode, array(RCUBE_COMPOSE_REPLY, RCUBE_COMPOSE_FORWARD))) { - $a_to = $RCMAIL->imap->decode_address_list($MESSAGE->headers->to); + $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_recipients[] = format_email($addr['mailto']); $a_names[] = $addr['name']; } } if (!empty($MESSAGE->headers->cc)) { - $a_cc = $RCMAIL->imap->decode_address_list($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_recipients[] = format_email($addr['mailto']); $a_names[] = $addr['name']; } } @@ -291,16 +296,12 @@ } $from_idx = null; - $default_identity = null; + $found_idx = null; + $default_identity = 0; // default identity is always first on the list $return_path = $MESSAGE->headers->others['return-path']; // Select identity foreach ($MESSAGE->identities as $idx => $ident) { - // save default identity ID - if ($ident['standard']) { - $default_identity = $idx; - } - // use From header if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { if ($MESSAGE->headers->from == $ident['ident']) { @@ -315,11 +316,20 @@ } // use replied message recipients else if (($found = array_search($ident['email_ascii'], $a_recipients)) !== false) { - // match identity name, prefer default identity - if ($from_idx === null || ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name'])) { + 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 amtches, get first found address (identity) + if ($from_idx === null) { + $from_idx = $found_idx; } // Fallback using Return-Path @@ -332,12 +342,7 @@ } } - // Still no ID, use default/first identity - if ($from_idx === null) { - $from_idx = $default_identity !== null ? $default_identity : key(reset($MESSAGE->identities)); - } - - $ident = $MESSAGE->identities[$from_idx]; + $ident = $MESSAGE->identities[$from_idx !== null ? $from_idx : $default_identity]; $from_id = $ident['identity_id']; $MESSAGE->compose['from_email'] = $ident['email']; @@ -408,11 +413,11 @@ else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { // get drafted headers if ($header=='to' && !empty($MESSAGE->headers->to)) - $fvalue = $MESSAGE->get_header('to'); + $fvalue = $MESSAGE->get_header('to', true); else if ($header=='cc' && !empty($MESSAGE->headers->cc)) - $fvalue = $MESSAGE->get_header('cc'); + $fvalue = $MESSAGE->get_header('cc', true); else if ($header=='bcc' && !empty($MESSAGE->headers->bcc)) - $fvalue = $MESSAGE->get_header('bcc'); + $fvalue = $MESSAGE->get_header('bcc', true); else if ($header=='replyto' && !empty($MESSAGE->headers->others['mail-reply-to'])) $fvalue = $MESSAGE->get_header('mail-reply-to'); else if ($header=='replyto' && !empty($MESSAGE->headers->replyto)) @@ -423,14 +428,14 @@ // split recipients and put them back together in a unique way if (!empty($fvalue) && in_array($header, array('to', 'cc', 'bcc'))) { - $to_addresses = $RCMAIL->imap->decode_address_list($fvalue, null, $decode_header); + $to_addresses = rcube_mime::decode_address_list($fvalue, null, $decode_header, $MESSAGE->headers->charset); $fvalue = array(); foreach ($to_addresses as $addr_part) { if (empty($addr_part['mailto'])) continue; - $mailto = mb_strtolower(rcube_idn_to_utf8($addr_part['mailto'])); + $mailto = format_email(rcube_idn_to_utf8($addr_part['mailto'])); if (!in_array($mailto, $a_recipients) && ($header == 'to' || empty($MESSAGE->compose['from_email']) || $mailto != $MESSAGE->compose['from_email']) @@ -526,7 +531,7 @@ function rcmail_compose_header_from($attrib) { - global $MESSAGE, $OUTPUT; + global $MESSAGE, $OUTPUT, $RCMAIL, $compose_mode; // pass the following attributes to the form class $field_attrib = array('name' => '_from'); @@ -537,6 +542,8 @@ if (count($MESSAGE->identities)) { $a_signatures = array(); + $separator = $RCMAIL->config->get('sig_above') + && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- '; $field_attrib['onchange'] = JS_OBJECT_NAME.".change_identity(this)"; $select_from = new html_select($field_attrib); @@ -550,13 +557,27 @@ // add signature to array if (!empty($sql_arr['signature']) && empty($COMPOSE['param']['nosig'])) { - $a_signatures[$identity_id]['text'] = $sql_arr['signature']; - $a_signatures[$identity_id]['is_html'] = ($sql_arr['html_signature'] == 1) ? true : false; - if ($a_signatures[$identity_id]['is_html']) - { - $h2t = new html2text($a_signatures[$identity_id]['text'], false, false); - $a_signatures[$identity_id]['plain_text'] = trim($h2t->get_text()); + $text = $html = $sql_arr['signature']; + + if ($sql_arr['html_signature']) { + $h2t = new html2text($sql_arr['signature'], false, false); + $text = trim($h2t->get_text()); } + else { + $html = htmlentities($html, ENT_NOQUOTES, RCMAIL_CHARSET); + } + + if (!preg_match('/^--[ -]\r?\n/m', $text)) { + $text = $separator . "\n" . $text; + $html = $separator . "<br>" . $html; + } + + if (!$sql_arr['html_signature']) { + $html = "<pre>" . $html . "</pre>"; + } + + $a_signatures[$identity_id]['text'] = $text; + $a_signatures[$identity_id]['html'] = $html; } } @@ -586,13 +607,19 @@ $html_editor = intval($RCMAIL->config->get('htmleditor')); - if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { - $useHtml = $MESSAGE->has_html_part(); + if (isset($_POST['_is_html'])) { + $useHtml = !empty($_POST['_is_html']); + } + else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { + $useHtml = $MESSAGE->has_html_part(false, true); } else if ($compose_mode == RCUBE_COMPOSE_REPLY) { - $useHtml = ($html_editor == 1 || ($html_editor == 2 && $MESSAGE->has_html_part())); + $useHtml = ($html_editor == 1 || ($html_editor >= 2 && $MESSAGE->has_html_part(false, true))); } - else { // RCUBE_COMPOSE_FORWARD or NEW + else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { + $useHtml = ($html_editor == 1 || ($html_editor == 3 && $MESSAGE->has_html_part(false, true))); + } + else { $useHtml = ($html_editor == 1); } @@ -621,41 +648,23 @@ rcmail_write_forward_attachment($MESSAGE); } // reply/edit/draft/forward - else if ($compose_mode) { - $has_html_part = $MESSAGE->has_html_part(); + else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || $RCMAIL->config->get('reply_mode') != -1)) { $isHtml = rcmail_compose_editor_mode(); - if ($isHtml) { - if ($has_html_part) { - $body = $MESSAGE->first_html_part(); - } - else { - $body = $MESSAGE->first_text_part(); - // try to remove the signature - if ($RCMAIL->config->get('strip_existing_sig', true)) - $body = rcmail_remove_signature($body); - // add HTML formatting - $body = rcmail_plain_body($body); - if ($body) - $body = '<pre>' . $body . '</pre>'; + if (!empty($MESSAGE->parts)) { + foreach ($MESSAGE->parts as $part) { + // skip no-content and attachment parts (#1488557) + if ($part->type != 'content' || !$part->size || $MESSAGE->is_attachment($part)) { + continue; + } + + if ($part_body = rcmail_compose_part_body($part, $isHtml)) { + $body .= ($body ? ($isHtml ? '<br/>' : "\n") : '') . $part_body; + } } } else { - if ($has_html_part) { - // use html part if it has been used for message (pre)viewing - // decrease line length for quoting - $len = $compose_mode == RCUBE_COMPOSE_REPLY ? $LINE_LENGTH-2 : $LINE_LENGTH; - $txt = new html2text($MESSAGE->first_html_part(), false, true, $len); - $body = $txt->get_text(); - } - else { - $body = $MESSAGE->first_text_part($part); - if ($body && $part && $part->ctype_secondary == 'plain' - && $part->ctype_parameters['format'] == 'flowed' - ) { - $body = rcube_message::unfold_flowed($body); - } - } + $body = rcmail_compose_part_body($MESSAGE, $isHtml); } // compose reply-body @@ -678,18 +687,96 @@ unset($plugin); // add blocked.gif attachment (#1486516) - if ($isHtml && preg_match('#<img src="\./program/blocked\.gif"#', $body)) { - if ($attachment = rcmail_save_image('program/blocked.gif', 'image/gif')) { + if ($isHtml && preg_match('#<img src="\./program/resources/blocked\.gif"#', $body)) { + if ($attachment = rcmail_save_image('program/resources/blocked.gif', 'image/gif')) { $COMPOSE['attachments'][$attachment['id']] = $attachment; - $body = preg_replace('#\./program/blocked\.gif#', - $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id'], - $body); + $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', + $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); + $body = preg_replace('#\./program/resources/blocked\.gif#', $url, $body); } } $HTML_MODE = $isHtml; return $body; +} + +function rcmail_compose_part_body($part, $isHtml = false) +{ + global $RCMAIL, $MESSAGE, $compose_mode; + + // Check if we have enough memory to handle the message in it + // #1487424: we need up to 10x more memory than the body + if (!rcmail_mem_check($part->size * 10)) { + return ''; + } + + if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset'])) { + $part->ctype_parameters['charset'] = $MESSAGE->headers->charset; + } + + // fetch part if not available + if (!isset($part->body)) { + $part->body = $MESSAGE->get_part_content($part->mime_id); + } + + // message is cached but not exists (#1485443), or other error + if ($part->body === false) { + return ''; + } + + $body = $part->body; + + if ($isHtml) { + if ($part->ctype_secondary == 'html') { + } + else if ($part->ctype_secondary == 'enriched') { + require_once(INSTALL_PATH . 'program/lib/enriched.inc'); + $body = enriched_to_html($body); + } + else { + // try to remove the signature + if ($RCMAIL->config->get('strip_existing_sig', true)) { + $body = rcmail_remove_signature($body); + } + // add HTML formatting + $body = rcmail_plain_body($body); + if ($body) { + $body = '<pre>' . $body . '</pre>'; + } + } + } + else { + if ($part->ctype_secondary == 'enriched') { + require_once(INSTALL_PATH . 'program/lib/enriched.inc'); + $body = enriched_to_html($body); + $part->ctype_secondary = 'html'; + } + + if ($part->ctype_secondary == 'html') { + // use html part if it has been used for message (pre)viewing + // decrease line length for quoting + $len = $compose_mode == RCUBE_COMPOSE_REPLY ? $LINE_LENGTH-2 : $LINE_LENGTH; + $txt = new html2text($body, false, true, $len); + $body = $txt->get_text(); + } + else if ($part->ctype_secondary == 'enriched') { + require_once(INSTALL_PATH . 'program/lib/enriched.inc'); + $body = enriched_to_html($body); + } + else { + if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { + $body = rcube_mime::unfold_flowed($body); + } + + // try to remove the signature + if ($RCMAIL->config->get('strip_existing_sig', true)) { + $body = rcmail_remove_signature($body); + } + } + } + + return $body; } function rcmail_compose_body($attrib) @@ -719,7 +806,9 @@ // If desired, set this textarea to be editable by TinyMCE if ($isHtml) { + $MESSAGE_BODY = htmlentities($MESSAGE_BODY, ENT_NOQUOTES, RCMAIL_CHARSET); $attrib['class'] = 'mce_editor'; + $attrib['is_escaped'] = true; $textarea = new html_textarea($attrib); $out .= $textarea->show($MESSAGE_BODY); } @@ -739,14 +828,14 @@ // include HTML editor rcube_html_editor(); - // include GoogieSpell + // Set language list if (!empty($CONFIG['enable_spellcheck'])) { $engine = $RCMAIL->config->get('spellcheck_engine','googie'); $dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary'); $spellcheck_langs = (array) $RCMAIL->config->get('spellcheck_languages', array('da'=>'Dansk', 'de'=>'Deutsch', 'en' => 'English', 'es'=>'Español', 'fr'=>'Français', 'it'=>'Italiano', 'nl'=>'Nederlands', 'pl'=>'Polski', - 'pt'=>'Português', 'fi'=>'Suomi', 'sv'=>'Svenska')); + 'pt'=>'Português', 'ru'=>'Русский', 'fi'=>'Suomi', 'sv'=>'Svenska')); // googie works only with two-letter codes if ($engine == 'googie') { @@ -768,14 +857,18 @@ if (!$spellcheck_langs[$lang]) $lang = 'en'; + $OUTPUT->set_env('spell_langs', $spellcheck_langs); + $OUTPUT->set_env('spell_lang', $lang); + $editor_lang_set = array(); foreach ($spellcheck_langs as $key => $name) { $editor_lang_set[] = ($key == $lang ? '+' : '') . JQ($name).'='.JQ($key); } + // include GoogieSpell $OUTPUT->include_script('googiespell.js'); $OUTPUT->add_script(sprintf( - "var googie = new GoogieSpell('\$__skin_path/images/googiespell/','?_task=utils&_action=spell&lang=', %s);\n". + "var googie = new GoogieSpell('%s/images/googiespell/','%s&lang=', %s);\n". "googie.lang_chck_spell = \"%s\";\n". "googie.lang_rsm_edt = \"%s\";\n". "googie.lang_close = \"%s\";\n". @@ -784,9 +877,11 @@ "googie.lang_learn_word = \"%s\";\n". "googie.setLanguages(%s);\n". "googie.setCurrentLanguage('%s');\n". - "googie.setSpellContainer('spellcheck-control');\n". + "googie.setDecoration(false);\n". "googie.decorateTextarea('%s');\n". "%s.set_env('spellcheck', googie);", + $RCMAIL->output->get_skin_path(), + $RCMAIL->url(array('_task' => 'utils', '_action' => 'spell', '_remote' => 1)), !empty($dictionary) ? 'true' : 'false', JQ(Q(rcube_label('checkspelling'))), JQ(Q(rcube_label('resumeediting'))), @@ -803,7 +898,7 @@ $OUTPUT->set_env('spellcheck_langs', join(',', $editor_lang_set)); } - $out .= "\n".'<iframe name="savetarget" src="program/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;"></iframe>'; return $out; } @@ -814,7 +909,7 @@ global $RCMAIL, $MESSAGE, $LINE_LENGTH; // build reply prefix - $from = array_pop($RCMAIL->imap->decode_address_list($MESSAGE->get_header('from'), 1, false)); + $from = array_pop(rcube_mime::decode_address_list($MESSAGE->get_header('from'), 1, false, $MESSAGE->headers->charset)); $prefix = rcube_label(array( 'name' => 'mailreplyintro', 'vars' => array( @@ -825,19 +920,17 @@ if (!$bodyIsHtml) { $body = preg_replace('/\r?\n/', "\n", $body); - - // try to remove the signature - if ($RCMAIL->config->get('strip_existing_sig', true)) - $body = rcmail_remove_signature($body); + $body = trim($body, "\n"); // soft-wrap and quote message text - $body = rcmail_wrap_and_quote(rtrim($body, "\n"), $LINE_LENGTH); + $body = rcmail_wrap_and_quote($body, $LINE_LENGTH); $prefix .= "\n"; $suffix = ''; - if ($RCMAIL->config->get('top_posting')) + if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting $prefix = "\n\n\n" . $prefix; + } } else { // save inline images to files @@ -851,7 +944,7 @@ $prefix = '<p>' . Q($prefix) . "</p>\n"; $prefix .= '<blockquote>'; - if ($RCMAIL->config->get('top_posting')) { + if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting $prefix = '<br>' . $prefix; $suffix = '</blockquote>'; } @@ -875,8 +968,7 @@ $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); $charset = $RCMAIL->output->get_charset(); - if (!$bodyIsHtml) - { + if (!$bodyIsHtml) { $prefix = "\n\n\n-------- " . rcube_label('originalmessage') . " --------\n"; $prefix .= rcube_label('subject') . ': ' . $MESSAGE->subject . "\n"; $prefix .= rcube_label('date') . ': ' . $date . "\n"; @@ -889,9 +981,9 @@ $prefix .= rcube_label('replyto') . ': ' . $MESSAGE->get_header('replyto') . "\n"; $prefix .= "\n"; + $body = trim($body, "\r\n"); } - else - { + else { // set is_safe flag (we need this for html body washing) rcmail_check_safe($MESSAGE); // clean up html tags @@ -906,18 +998,18 @@ "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", rcube_label('subject'), Q($MESSAGE->subject), rcube_label('date'), Q($date), - rcube_label('from'), htmlspecialchars(Q($MESSAGE->get_header('from'), 'replace'), ENT_COMPAT, $charset), - rcube_label('to'), htmlspecialchars(Q($MESSAGE->get_header('to'), 'replace'), ENT_COMPAT, $charset)); + rcube_label('from'), Q($MESSAGE->get_header('from'), 'replace'), + rcube_label('to'), Q($MESSAGE->get_header('to'), 'replace')); if ($MESSAGE->headers->cc) $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", rcube_label('cc'), - htmlspecialchars(Q($MESSAGE->get_header('cc'), 'replace'), ENT_COMPAT, $charset)); + Q($MESSAGE->get_header('cc'), 'replace')); if ($MESSAGE->headers->replyto && $MESSAGE->headers->replyto != $MESSAGE->headers->from) $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", rcube_label('replyto'), - htmlspecialchars(Q($MESSAGE->get_header('replyto'), 'replace'), ENT_COMPAT, $charset)); + Q($MESSAGE->get_header('replyto'), 'replace')); $prefix .= "</tbody></table><br>"; } @@ -953,7 +1045,8 @@ { global $RCMAIL; - $len = strlen($body); + $body = str_replace("\r\n", "\n", $body); + $len = strlen($body); $sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15); while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) { @@ -972,15 +1065,23 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) { - global $RCMAIL, $COMPOSE; + global $RCMAIL, $COMPOSE, $compose_mode; $cid_map = $messages = array(); foreach ((array)$message->mime_parts as $pid => $part) { - if (($part->ctype_primary != 'message' || !$bodyIsHtml) && $part->ctype_primary != 'multipart' && - ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) - && $part->mimetype != 'application/ms-tnef' - ) { + if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) { + if ($part->ctype_primary == 'message' || $part->ctype_primary == 'multipart') { + continue; + } + if ($part->mimetype == 'application/ms-tnef') { + continue; + } + // skip inline images when forwarding in plain text + if ($part->content_id && !$bodyIsHtml && $compose_mode == RCUBE_COMPOSE_FORWARD) { + continue; + } + $skip = false; if ($part->mimetype == 'message/rfc822') { $messages[] = $part->mime_id; @@ -996,7 +1097,8 @@ if (!$skip && ($attachment = rcmail_save_attachment($message, $pid))) { $COMPOSE['attachments'][$attachment['id']] = $attachment; if ($bodyIsHtml && ($part->content_id || $part->content_location)) { - $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id']; + $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', + $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); if ($part->content_id) $cid_map['cid:'.$part->content_id] = $url; else @@ -1021,7 +1123,8 @@ if (($part->content_id || $part->content_location) && $part->filename) { if ($attachment = rcmail_save_attachment($message, $pid)) { $COMPOSE['attachments'][$attachment['id']] = $attachment; - $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id']; + $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', + $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); if ($part->content_id) $cid_map['cid:'.$part->content_id] = $url; else @@ -1054,12 +1157,12 @@ $temp_dir = unslashify($RCMAIL->config->get('temp_dir')); $path = tempnam($temp_dir, 'rcmAttmnt'); if ($fp = fopen($path, 'w')) { - $RCMAIL->imap->get_raw_body($message->uid, $fp); + $RCMAIL->storage->get_raw_body($message->uid, $fp); fclose($fp); } else return false; } else { - $data = $RCMAIL->imap->get_raw_body($message->uid); + $data = $RCMAIL->storage->get_raw_body($message->uid); } $attachment = array( @@ -1108,10 +1211,22 @@ $data = $message->get_part_content($pid); } + $mimetype = $part->ctype_primary . '/' . $part->ctype_secondary; + $filename = $part->filename; + if (!strlen($filename)) { + if ($mimetype == 'text/html') { + $filename = rcube_label('htmlmessage'); + } + else { + $filename = 'Part_'.$pid; + } + $filename .= '.' . $part->ctype_secondary; + } + $attachment = array( 'group' => $COMPOSE['id'], - 'name' => $part->filename ? $part->filename : 'Part_'.$pid.'.'.$part->ctype_secondary, - 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, + 'name' => $filename, + 'mimetype' => $mimetype, 'content_id' => $part->content_id, 'data' => $data, 'path' => $path, @@ -1244,7 +1359,7 @@ 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", JS_OBJECT_NAME, $id), 'class' => 'delete'), $button) . Q($a_prop['name'])); - + $jslist['rcmfile'.$id] = array('name' => $a_prop['name'], 'complete' => true, 'mimetype' => $a_prop['mimetype']); } } @@ -1258,14 +1373,14 @@ $OUTPUT->set_env('attachments', $jslist); $OUTPUT->add_gui_object('attachmentlist', $attrib['id']); - + return html::tag('ul', $attrib, $out, html::$common_attrib); } function rcmail_compose_attachment_form($attrib) { - global $RCMAIL, $OUTPUT; + global $OUTPUT; // set defaults $attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes'); @@ -1276,7 +1391,7 @@ $button = new html_inputfield(array('type' => 'button')); $out = html::div($attrib, - $OUTPUT->form_tag(array('name' => 'uploadform', 'method' => 'post', 'enctype' => 'multipart/form-data'), + $OUTPUT->form_tag(array('id' => $attrib['id'].'Frm', 'name' => 'uploadform', 'method' => 'post', 'enctype' => 'multipart/form-data'), html::div(null, rcmail_compose_attachment_field(array('size' => $attrib['attachmentfieldsize']))) . html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) . (get_boolean($attrib['buttons']) ? html::div('buttons', @@ -1286,7 +1401,7 @@ ) ); - $OUTPUT->add_gui_object('uploadform', $attrib['id']); + $OUTPUT->add_gui_object('uploadform', $attrib['id'].'Frm'); return $out; } @@ -1305,7 +1420,7 @@ function rcmail_priority_selector($attrib) { global $MESSAGE; - + list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); @@ -1342,13 +1457,15 @@ unset($attrib['form']); if (!isset($attrib['id'])) - $attrib['id'] = 'receipt'; + $attrib['id'] = 'receipt'; $attrib['name'] = '_receipt'; $attrib['value'] = '1'; $checkbox = new html_checkbox($attrib); - if ($MESSAGE && in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) + if (isset($_POST['_receipt'])) + $mdn_default = $_POST['_receipt']; + else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) $mdn_default = (bool) $MESSAGE->headers->mdn_to; else $mdn_default = $RCMAIL->config->get('mdn_default'); @@ -1375,8 +1492,13 @@ $attrib['value'] = '1'; $checkbox = new html_checkbox($attrib); + if (isset($_POST['_dsn'])) + $dsn_value = $_POST['_dsn']; + else + $dsn_value = $RCMAIL->config->get('dsn_default'); + $out = $form_start ? "$form_start\n" : ''; - $out .= $checkbox->show($RCMAIL->config->get('dsn_default')); + $out .= $checkbox->show($dsn_value); $out .= $form_end ? "\n$form_end" : ''; return $out; @@ -1385,8 +1507,6 @@ function rcmail_editor_selector($attrib) { - global $CONFIG, $MESSAGE, $compose_mode; - // determine whether HTML or plain text should be checked $useHtml = rcmail_compose_editor_mode(); @@ -1425,7 +1545,7 @@ 'folder_filter' => 'mail', 'folder_rights' => 'w', ))); - return $select->show($COMPOSE['param']['sent_mbox'], $attrib); + return $select->show(isset($_POST['_store_target']) ? $_POST['_store_target'] : $COMPOSE['param']['sent_mbox'], $attrib); } @@ -1433,16 +1553,21 @@ { global $RCMAIL; - if ($RCMAIL->imap->mailbox_exists($folder, true)) { + // we'll not save the message, so it doesn't matter + if ($RCMAIL->config->get('no_save_sent_messages')) { + return true; + } + + if ($RCMAIL->storage->folder_exists($folder, true)) { return true; } // folder may exist but isn't subscribed (#1485241) if ($create) { - if (!$RCMAIL->imap->mailbox_exists($folder)) - return $RCMAIL->imap->create_mailbox($folder, true); + if (!$RCMAIL->storage->folder_exists($folder)) + return $RCMAIL->storage->create_folder($folder, true); else - return $RCMAIL->imap->subscribe($folder); + return $RCMAIL->storage->subscribe($folder); } return false; @@ -1459,6 +1584,7 @@ $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $RCMAIL->task)); $hiddenfields->add(array('name' => '_action', 'value' => 'send')); $hiddenfields->add(array('name' => '_id', 'value' => $COMPOSE['id'])); + $hiddenfields->add(array('name' => '_attachments')); $form_start = empty($attrib['form']) ? $RCMAIL->output->form_tag(array('name' => "form", 'method' => "post")) : ''; $form_start .= $hiddenfields->show(); @@ -1476,6 +1602,71 @@ } +function rcmail_addressbook_list($attrib = array()) +{ + global $RCMAIL, $OUTPUT; + + $attrib += array('id' => 'rcmdirectorylist'); + + $out = ''; + $line_templ = html::tag('li', array( + 'id' => 'rcmli%s', 'class' => '%s'), + html::a(array('href' => '#list', + 'rel' => '%s', + 'onclick' => "return ".JS_OBJECT_NAME.".command('list-adresses','%s',this)"), '%s')); + + foreach ($RCMAIL->get_address_sources(false, true) as $j => $source) { + $id = strval(strlen($source['id']) ? $source['id'] : $j); + $js_id = JQ($id); + + // set class name(s) + $class_name = 'addressbook'; + if ($source['class_name']) + $class_name .= ' ' . $source['class_name']; + + $out .= sprintf($line_templ, + html_identifier($id), + $class_name, + $source['id'], + $js_id, (!empty($source['name']) ? $source['name'] : $id)); + } + + $OUTPUT->add_gui_object('addressbookslist', $attrib['id']); + + return html::tag('ul', $attrib, $out, html::$common_attrib); +} + +// return the contacts list as HTML table +function rcmail_contacts_list($attrib = array()) +{ + global $OUTPUT; + + $attrib += array('id' => 'rcmAddressList'); + + // set client env + $OUTPUT->add_gui_object('contactslist', $attrib['id']); + $OUTPUT->set_env('pagecount', 0); + $OUTPUT->set_env('current_page', 0); + $OUTPUT->include_script('list.js'); + + return rcube_table_output($attrib, array(), array('name'), 'ID'); +} + + +/** + * Register a certain container as active area to drop files onto + */ +function compose_file_drop_area($attrib) +{ + global $OUTPUT; + + if ($attrib['id']) { + $OUTPUT->add_gui_object('filedrop', $attrib['id']); + $OUTPUT->set_env('filedrop', array('action' => 'upload', 'fieldname' => '_attachments')); + } +} + + // register UI objects $OUTPUT->add_handlers(array( 'composeheaders' => 'rcmail_compose_headers', @@ -1484,13 +1675,14 @@ 'composeattachmentlist' => 'rcmail_compose_attachment_list', 'composeattachmentform' => 'rcmail_compose_attachment_form', 'composeattachment' => 'rcmail_compose_attachment_field', + 'filedroparea' => 'compose_file_drop_area', 'priorityselector' => 'rcmail_priority_selector', 'editorselector' => 'rcmail_editor_selector', 'receiptcheckbox' => 'rcmail_receipt_checkbox', 'dsncheckbox' => 'rcmail_dsn_checkbox', 'storetarget' => 'rcmail_store_target_selection', + 'addressbooks' => 'rcmail_addressbook_list', + 'addresslist' => 'rcmail_contacts_list', )); $OUTPUT->send('compose'); - - -- Gitblit v1.9.1