mirror of
https://github.com/roundcube/roundcubemail.git
synced 2026-03-05 15:54:03 +01:00
Now instead of <pre> we use <div class="pre"> styled with monospace font. We replace whitespace characters with non-breaking spaces where needed. I.e. plain text is always unwrappable, until it uses format=flowed, in such a case only flowed paragraphs are wrappable. Also conversion of text to HTML in compose editor was modified in the same way.
1877 lines
65 KiB
PHP
1877 lines
65 KiB
PHP
<?php
|
|
|
|
/*
|
|
+-----------------------------------------------------------------------+
|
|
| program/steps/mail/compose.inc |
|
|
| |
|
|
| This file is part of the Roundcube Webmail client |
|
|
| Copyright (C) 2005-2013, 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 |
|
|
| |
|
|
+-----------------------------------------------------------------------+
|
|
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
|
+-----------------------------------------------------------------------+
|
|
*/
|
|
|
|
// define constants for message compose mode
|
|
define('RCUBE_COMPOSE_REPLY', 'reply');
|
|
define('RCUBE_COMPOSE_FORWARD', 'forward');
|
|
define('RCUBE_COMPOSE_DRAFT', 'draft');
|
|
define('RCUBE_COMPOSE_EDIT', 'edit');
|
|
|
|
$MESSAGE_FORM = null;
|
|
$COMPOSE_ID = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GET);
|
|
$COMPOSE = null;
|
|
|
|
if ($COMPOSE_ID && $_SESSION['compose_data_'.$COMPOSE_ID])
|
|
$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID];
|
|
|
|
// give replicated session storage some time to synchronize
|
|
$retries = 0;
|
|
while ($COMPOSE_ID && !is_array($COMPOSE) && $RCMAIL->db->is_replicated() && $retries++ < 5) {
|
|
usleep(500000);
|
|
$RCMAIL->session->reload();
|
|
if ($_SESSION['compose_data_'.$COMPOSE_ID]) {
|
|
$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID];
|
|
}
|
|
}
|
|
|
|
// Nothing below is called during message composition, only at "new/forward/reply/draft" initialization or
|
|
// if a compose-ID is given (i.e. when the compose step is opened in a new window/tab).
|
|
if (!is_array($COMPOSE)) {
|
|
// Infinite redirect prevention in case of broken session (#1487028)
|
|
if ($COMPOSE_ID) {
|
|
rcube::raise_error(array('code' => 500, 'type' => 'php',
|
|
'file' => __FILE__, 'line' => __LINE__,
|
|
'message' => "Invalid compose ID"), true, true);
|
|
}
|
|
|
|
$COMPOSE_ID = uniqid(mt_rand());
|
|
$_SESSION['compose_data_'.$COMPOSE_ID] = array(
|
|
'id' => $COMPOSE_ID,
|
|
'param' => rcube_utils::request2param(rcube_utils::INPUT_GET, 'task|action', true),
|
|
'mailbox' => $RCMAIL->storage->get_folder(),
|
|
);
|
|
$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID];
|
|
|
|
rcmail_process_compose_params($COMPOSE);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// redirect to a unique URL with all parameters stored in session
|
|
$OUTPUT->redirect(array(
|
|
'_action' => 'compose',
|
|
'_id' => $COMPOSE['id'],
|
|
'_search' => $_REQUEST['_search'],
|
|
));
|
|
}
|
|
|
|
|
|
// add some labels to client
|
|
$OUTPUT->add_label('nosubject', 'nosenderwarning', 'norecipientwarning', 'nosubjectwarning', 'cancel',
|
|
'nobodywarning', 'notsentwarning', 'notuploadedwarning', 'savingmessage', 'sendingmessage',
|
|
'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany',
|
|
'fileuploaderror', 'sendmessage', 'savenewresponse', 'responsename', 'responsetext', 'save',
|
|
'savingresponse', 'restoresavedcomposedata', 'restoremessage', 'delete', 'restore', 'ignore',
|
|
'selectimportfile');
|
|
|
|
$OUTPUT->set_pagetitle($RCMAIL->gettext('compose'));
|
|
|
|
$OUTPUT->set_env('compose_id', $COMPOSE['id']);
|
|
$OUTPUT->set_env('session_id', session_id());
|
|
$OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder());
|
|
$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 (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
|
|
$font = rcmail::font_defs($RCMAIL->config->get('default_font'));
|
|
if ($font && !is_array($font)) {
|
|
$OUTPUT->set_env('default_font', $font);
|
|
}
|
|
|
|
// default font size for HTML editor
|
|
if ($font_size = $RCMAIL->config->get('default_font_size')) {
|
|
$OUTPUT->set_env('default_font_size', $font_size);
|
|
}
|
|
|
|
// get reference message and set compose mode
|
|
if ($msg_uid = $COMPOSE['param']['draft_uid']) {
|
|
$compose_mode = RCUBE_COMPOSE_DRAFT;
|
|
$OUTPUT->set_env('draft_id', $msg_uid);
|
|
$RCMAIL->storage->set_folder($drafts_mbox);
|
|
}
|
|
else if ($msg_uid = $COMPOSE['param']['reply_uid']) {
|
|
$compose_mode = RCUBE_COMPOSE_REPLY;
|
|
}
|
|
else if ($msg_uid = $COMPOSE['param']['forward_uid']) {
|
|
$compose_mode = RCUBE_COMPOSE_FORWARD;
|
|
$COMPOSE['forward_uid'] = $msg_uid;
|
|
$COMPOSE['as_attachment'] = !empty($COMPOSE['param']['attachment']);
|
|
}
|
|
else if ($msg_uid = $COMPOSE['param']['uid']) {
|
|
$compose_mode = RCUBE_COMPOSE_EDIT;
|
|
}
|
|
|
|
$COMPOSE['mode'] = $compose_mode;
|
|
$OUTPUT->set_env('compose_mode', $compose_mode);
|
|
|
|
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)
|
|
if ($config_show_sig == 1 || $config_show_sig == 2) {
|
|
$OUTPUT->set_env('show_sig_later', true);
|
|
}
|
|
}
|
|
else if ($config_show_sig == 1)
|
|
$OUTPUT->set_env('show_sig', true);
|
|
else if ($config_show_sig == 2 && empty($compose_mode))
|
|
$OUTPUT->set_env('show_sig', true);
|
|
else if ($config_show_sig == 3 && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD))
|
|
$OUTPUT->set_env('show_sig', true);
|
|
|
|
// set line length for body wrapping
|
|
$LINE_LENGTH = $RCMAIL->config->get('line_length', 72);
|
|
|
|
if (!empty($msg_uid) && empty($COMPOSE['as_attachment'])) {
|
|
$mbox_name = $RCMAIL->storage->get_folder();
|
|
|
|
// set format before rcube_message construction
|
|
// use the same format as for the message view
|
|
if (isset($_SESSION['msg_formats'][$mbox_name.':'.$msg_uid])) {
|
|
$RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$msg_uid]);
|
|
}
|
|
else {
|
|
$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);
|
|
}
|
|
|
|
$MESSAGE = new rcube_message($msg_uid);
|
|
|
|
// make sure message is marked as read
|
|
if ($MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN'])) {
|
|
$RCMAIL->storage->set_flag($msg_uid, 'SEEN');
|
|
}
|
|
|
|
if (!empty($MESSAGE->headers->charset)) {
|
|
$RCMAIL->storage->set_charset($MESSAGE->headers->charset);
|
|
}
|
|
|
|
if (!$MESSAGE->headers) {
|
|
// error
|
|
}
|
|
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);
|
|
|
|
// 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'])
|
|
&& rcmail_check_sent_folder($sent_folder, false)
|
|
) {
|
|
$COMPOSE['param']['sent_mbox'] = $sent_folder;
|
|
}
|
|
}
|
|
else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
|
|
if ($compose_mode == RCUBE_COMPOSE_DRAFT) {
|
|
if ($draft_info = $MESSAGE->headers->get('x-draft-info')) {
|
|
// get reply_uid/forward_uid to flag the original message when sending
|
|
$info = rcmail_draftinfo_decode($draft_info);
|
|
|
|
if ($info['type'] == 'reply')
|
|
$COMPOSE['reply_uid'] = $info['uid'];
|
|
else if ($info['type'] == 'forward')
|
|
$COMPOSE['forward_uid'] = $info['uid'];
|
|
|
|
$COMPOSE['mailbox'] = $info['folder'];
|
|
|
|
// Save the sent message in the same folder of the message being replied to
|
|
if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $info['folder'])
|
|
&& rcmail_check_sent_folder($sent_folder, false)
|
|
) {
|
|
$COMPOSE['param']['sent_mbox'] = $sent_folder;
|
|
}
|
|
}
|
|
|
|
$COMPOSE['param']['message-id'] = $MESSAGE->headers->get('message-id');
|
|
|
|
// use message UID as draft_id
|
|
$OUTPUT->set_env('draft_id', $msg_uid);
|
|
}
|
|
|
|
if ($in_reply_to = $MESSAGE->headers->get('in-reply-to')) {
|
|
$COMPOSE['reply_msgid'] = '<' . $in_reply_to . '>';
|
|
}
|
|
|
|
$COMPOSE['references'] = $MESSAGE->headers->references;
|
|
}
|
|
}
|
|
else {
|
|
$MESSAGE = new stdClass();
|
|
|
|
// apply mailto: URL parameters
|
|
if (!empty($COMPOSE['param']['in-reply-to'])) {
|
|
$COMPOSE['reply_msgid'] = '<' . $COMPOSE['param']['in-reply-to'] . '>';
|
|
}
|
|
|
|
if (!empty($COMPOSE['param']['references'])) {
|
|
$COMPOSE['references'] = $COMPOSE['param']['references'];
|
|
}
|
|
}
|
|
|
|
if (!empty($COMPOSE['reply_msgid'])) {
|
|
$OUTPUT->set_env('reply_msgid', $COMPOSE['reply_msgid']);
|
|
}
|
|
|
|
$MESSAGE->compose = array();
|
|
|
|
// get user's identities
|
|
$MESSAGE->identities = $RCMAIL->user->list_identities(null, true);
|
|
|
|
// Set From field value
|
|
if (!empty($_POST['_from'])) {
|
|
$MESSAGE->compose['from'] = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST);
|
|
}
|
|
else if (!empty($COMPOSE['param']['from'])) {
|
|
$MESSAGE->compose['from'] = $COMPOSE['param']['from'];
|
|
}
|
|
else if (count($MESSAGE->identities)) {
|
|
$ident = rcmail_identity_select($MESSAGE, $MESSAGE->identities, $compose_mode);
|
|
|
|
$MESSAGE->compose['from_email'] = $ident['email'];
|
|
$MESSAGE->compose['from'] = $ident['identity_id'];
|
|
}
|
|
|
|
// Set other headers
|
|
$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 = '';
|
|
$decode_header = true;
|
|
|
|
// we have a set of recipients stored is session
|
|
if ($header == 'to' && ($mailto_id = $COMPOSE['param']['mailto'])
|
|
&& $_SESSION['mailto'][$mailto_id]
|
|
) {
|
|
$fvalue = urldecode($_SESSION['mailto'][$mailto_id]);
|
|
$decode_header = false;
|
|
|
|
// make session to not grow up too much
|
|
unset($_SESSION['mailto'][$mailto_id]);
|
|
$COMPOSE['param']['to'] = $fvalue;
|
|
}
|
|
else if (!empty($_POST['_'.$header])) {
|
|
$fvalue = rcube_utils::get_input_value('_'.$header, rcube_utils::INPUT_POST, TRUE);
|
|
}
|
|
else if (!empty($COMPOSE['param'][$header])) {
|
|
$fvalue = $COMPOSE['param'][$header];
|
|
}
|
|
else if ($compose_mode == RCUBE_COMPOSE_REPLY) {
|
|
// get recipent address(es) out of the message headers
|
|
if ($header == 'to') {
|
|
$mailfollowup = $MESSAGE->headers->others['mail-followup-to'];
|
|
$mailreplyto = $MESSAGE->headers->others['mail-reply-to'];
|
|
|
|
// Reply to mailing list...
|
|
if ($MESSAGE->reply_all == 'list' && $mailfollowup)
|
|
$fvalue = $mailfollowup;
|
|
else if ($MESSAGE->reply_all == 'list'
|
|
&& preg_match('/<mailto:([^>]+)>/i', $MESSAGE->headers->others['list-post'], $m))
|
|
$fvalue = $m[1];
|
|
// Reply to...
|
|
else if ($MESSAGE->reply_all && $mailfollowup)
|
|
$fvalue = $mailfollowup;
|
|
else if ($mailreplyto)
|
|
$fvalue = $mailreplyto;
|
|
else if (!empty($MESSAGE->headers->replyto))
|
|
$fvalue = $MESSAGE->headers->replyto;
|
|
else if (!empty($MESSAGE->headers->from))
|
|
$fvalue = $MESSAGE->headers->from;
|
|
|
|
// Reply to message sent by yourself (#1487074, #1489230)
|
|
if (!empty($ident) && in_array($ident['ident'], array($fvalue, $MESSAGE->headers->from))) {
|
|
$fvalue = $MESSAGE->headers->to;
|
|
}
|
|
}
|
|
// add recipient of original message if reply to all
|
|
else if ($header == 'cc' && !empty($MESSAGE->reply_all) && $MESSAGE->reply_all != 'list') {
|
|
if ($v = $MESSAGE->headers->to)
|
|
$fvalue .= $v;
|
|
if ($v = $MESSAGE->headers->cc)
|
|
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
|
|
// Use Sender header (#1489011)
|
|
if (($v = $MESSAGE->headers->get('Sender', false)) && strpos($v, '-bounces@') === false)
|
|
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
|
|
|
|
// When To: and Reply-To: are the same we add From: address to the list (#1489037)
|
|
if ($v = $MESSAGE->headers->from) {
|
|
$from = rcube_mime::decode_address_list($v, null, false, $MESSAGE->headers->charset, true);
|
|
$to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $MESSAGE->headers->charset, true);
|
|
$replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $MESSAGE->headers->charset, true);
|
|
|
|
if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) {
|
|
$fvalue .= (!empty($fvalue) ? $separator : '') . $v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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', true);
|
|
else if ($header=='cc' && !empty($MESSAGE->headers->cc))
|
|
$fvalue = $MESSAGE->get_header('cc', true);
|
|
else if ($header=='bcc' && !empty($MESSAGE->headers->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))
|
|
$fvalue = $MESSAGE->get_header('reply-to');
|
|
else if ($header=='followupto' && !empty($MESSAGE->headers->others['mail-followup-to']))
|
|
$fvalue = $MESSAGE->get_header('mail-followup-to');
|
|
}
|
|
|
|
// split recipients and put them back together in a unique way
|
|
if (!empty($fvalue) && in_array($header, array('to', 'cc', 'bcc'))) {
|
|
$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;
|
|
}
|
|
|
|
// 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 (($header == 'to' || $compose_mode != RCUBE_COMPOSE_REPLY || $mailto_lc != $from_email)
|
|
&& !in_array($mailto_lc, $a_recipients)
|
|
) {
|
|
if ($addr_part['name'] && $mailto != $addr_part['name']) {
|
|
$mailto = format_email_recipient($mailto, $addr_part['name']);
|
|
}
|
|
|
|
$fvalue[] = $mailto;
|
|
$a_recipients[] = $mailto_lc;
|
|
}
|
|
}
|
|
|
|
$fvalue = implode($separator, $fvalue);
|
|
}
|
|
|
|
$MESSAGE->compose[$header] = $fvalue;
|
|
}
|
|
unset($a_recipients);
|
|
|
|
// process $MESSAGE body/attachments, set $MESSAGE_BODY/$HTML_MODE vars and some session data
|
|
$MESSAGE_BODY = rcmail_prepare_message_body();
|
|
|
|
|
|
// register UI objects
|
|
$OUTPUT->add_handlers(array(
|
|
'composeheaders' => 'rcmail_compose_headers',
|
|
'composesubject' => 'rcmail_compose_subject',
|
|
'composebody' => 'rcmail_compose_body',
|
|
'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',
|
|
'responseslist' => 'rcmail_compose_responses_list',
|
|
));
|
|
|
|
$OUTPUT->send('compose');
|
|
|
|
|
|
/****** compose mode functions ********/
|
|
|
|
// process compose request parameters
|
|
function rcmail_process_compose_params(&$COMPOSE)
|
|
{
|
|
if ($COMPOSE['param']['to']) {
|
|
$mailto = explode('?', $COMPOSE['param']['to'], 2);
|
|
|
|
// #1486037: remove "mailto:" prefix
|
|
$COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $mailto[0]);
|
|
|
|
// Supported case-insensitive tokens in mailto URL
|
|
$url_tokens = array('to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'body');
|
|
|
|
if (!empty($mailto[1])) {
|
|
parse_str($mailto[1], $query);
|
|
foreach ($query as $f => $val) {
|
|
if (($key = array_search(strtolower($f), $url_tokens)) !== false) {
|
|
$f = $url_tokens[$key];
|
|
}
|
|
|
|
// merge mailto: addresses with addresses from 'to' parameter
|
|
if ($f == 'to' && !empty($COMPOSE['param']['to'])) {
|
|
$to_addresses = rcube_mime::decode_address_list($COMPOSE['param']['to'], null, true, null, true);
|
|
$add_addresses = rcube_mime::decode_address_list($val, null, true);
|
|
|
|
foreach ($add_addresses as $addr) {
|
|
if (!in_array($addr['mailto'], $to_addresses)) {
|
|
$to_addresses[] = $addr['mailto'];
|
|
$COMPOSE['param']['to'] = (!empty($to_addresses) ? ', ' : '') . $addr['string'];
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$COMPOSE['param'][$f] = $val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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());
|
|
}
|
|
|
|
$RCMAIL = rcmail::get_instance();
|
|
|
|
// select folder where to save the sent message
|
|
$COMPOSE['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox');
|
|
|
|
// 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)
|
|
{
|
|
global $RCMAIL, $MESSAGE;
|
|
|
|
list($form_start,) = get_form_tags($attrib);
|
|
|
|
$out = '';
|
|
$part = strtolower($attrib['part']);
|
|
|
|
switch ($part) {
|
|
case 'from':
|
|
return $form_start . rcmail_compose_header_from($attrib);
|
|
|
|
case 'to':
|
|
case 'cc':
|
|
case 'bcc':
|
|
$fname = '_' . $part;
|
|
$header = $param = $part;
|
|
|
|
$allow_attrib = array('id', 'class', 'style', 'cols', 'rows', 'tabindex');
|
|
$field_type = 'html_textarea';
|
|
break;
|
|
|
|
case 'replyto':
|
|
case 'reply-to':
|
|
$fname = '_replyto';
|
|
$param = 'replyto';
|
|
$header = 'reply-to';
|
|
|
|
case 'followupto':
|
|
case 'followup-to':
|
|
if (!$fname) {
|
|
$fname = '_followupto';
|
|
$param = 'followupto';
|
|
$header = 'mail-followup-to';
|
|
}
|
|
|
|
$allow_attrib = array('id', 'class', 'style', 'size', 'tabindex');
|
|
$field_type = 'html_inputfield';
|
|
break;
|
|
}
|
|
|
|
if ($fname && $field_type) {
|
|
// pass the following attributes to the form class
|
|
$field_attrib = array('name' => $fname, 'spellcheck' => 'false');
|
|
foreach ($attrib as $attr => $value) {
|
|
if (in_array($attr, $allow_attrib)) {
|
|
$field_attrib[$attr] = $value;
|
|
}
|
|
}
|
|
|
|
// create teaxtarea object
|
|
$input = new $field_type($field_attrib);
|
|
$out = $input->show($MESSAGE->compose[$param]);
|
|
}
|
|
|
|
if ($form_start) {
|
|
$out = $form_start . $out;
|
|
}
|
|
|
|
// configure autocompletion
|
|
$RCMAIL->autocomplete_init();
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
function rcmail_compose_header_from($attrib)
|
|
{
|
|
global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode;
|
|
|
|
// pass the following attributes to the form class
|
|
$field_attrib = array('name' => '_from');
|
|
foreach ($attrib as $attr => $value) {
|
|
if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex'))) {
|
|
$field_attrib[$attr] = $value;
|
|
}
|
|
}
|
|
|
|
if (count($MESSAGE->identities)) {
|
|
$a_signatures = array();
|
|
$identities = array();
|
|
$separator = intval($RCMAIL->config->get('reply_mode')) > 0
|
|
&& ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- ';
|
|
|
|
$field_attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.".change_identity(this)";
|
|
$select_from = new html_select($field_attrib);
|
|
|
|
// create SELECT element
|
|
foreach ($MESSAGE->identities as $sql_arr) {
|
|
$identity_id = $sql_arr['identity_id'];
|
|
$select_from->add(format_email_recipient($sql_arr['email'], $sql_arr['name']), $identity_id);
|
|
|
|
// add signature to array
|
|
if (!empty($sql_arr['signature']) && empty($COMPOSE['param']['nosig'])) {
|
|
$text = $html = $sql_arr['signature'];
|
|
|
|
if ($sql_arr['html_signature']) {
|
|
$h2t = new rcube_html2text($sql_arr['signature'], false, false);
|
|
$text = trim($h2t->get_text());
|
|
}
|
|
else {
|
|
$html = htmlentities($html, ENT_NOQUOTES, RCUBE_CHARSET);
|
|
}
|
|
|
|
if (!preg_match('/^--[ -]\r?\n/m', $text)) {
|
|
$text = $separator . "\n" . $text;
|
|
$html = $separator . "<br>" . $html;
|
|
}
|
|
|
|
if (!$sql_arr['html_signature']) {
|
|
$t2h = new rcube_text2html($sql_arr['signature'], false);
|
|
$html = $t2h->get_html();
|
|
}
|
|
|
|
$a_signatures[$identity_id]['text'] = $text;
|
|
$a_signatures[$identity_id]['html'] = $html;
|
|
}
|
|
|
|
// add bcc and reply-to
|
|
if (!empty($sql_arr['reply-to'])) {
|
|
$identities[$identity_id]['replyto'] = $sql_arr['reply-to'];
|
|
}
|
|
if (!empty($sql_arr['bcc'])) {
|
|
$identities[$identity_id]['bcc'] = $sql_arr['bcc'];
|
|
}
|
|
}
|
|
|
|
$out = $select_from->show($MESSAGE->compose['from']);
|
|
|
|
// add signatures to client
|
|
$OUTPUT->set_env('signatures', $a_signatures);
|
|
$OUTPUT->set_env('identities', $identities);
|
|
}
|
|
// no identities, display text input field
|
|
else {
|
|
$field_attrib['class'] = 'from_address';
|
|
$input_from = new html_inputfield($field_attrib);
|
|
$out = $input_from->show($MESSAGE->compose['from']);
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
function rcmail_compose_editor_mode()
|
|
{
|
|
global $RCMAIL, $compose_mode;
|
|
static $useHtml;
|
|
|
|
if ($useHtml !== null) {
|
|
return $useHtml;
|
|
}
|
|
|
|
$html_editor = intval($RCMAIL->config->get('htmleditor'));
|
|
|
|
if (isset($_POST['_is_html'])) {
|
|
$useHtml = !empty($_POST['_is_html']);
|
|
}
|
|
else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
|
|
$useHtml = rcmail_message_is_html();
|
|
}
|
|
else if ($compose_mode == RCUBE_COMPOSE_REPLY) {
|
|
$useHtml = ($html_editor == 1 || ($html_editor >= 2 && rcmail_message_is_html()));
|
|
}
|
|
else if ($compose_mode == RCUBE_COMPOSE_FORWARD) {
|
|
$useHtml = ($html_editor == 1 || ($html_editor == 3 && rcmail_message_is_html()));
|
|
}
|
|
else {
|
|
$useHtml = ($html_editor == 1);
|
|
}
|
|
|
|
return $useHtml;
|
|
}
|
|
|
|
function rcmail_message_is_html()
|
|
{
|
|
global $RCMAIL, $MESSAGE;
|
|
|
|
return $RCMAIL->config->get('prefer_html') && ($MESSAGE instanceof rcube_message) && $MESSAGE->has_html_part(true);
|
|
}
|
|
|
|
function rcmail_prepare_message_body()
|
|
{
|
|
global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE;
|
|
|
|
// use posted message body
|
|
if (!empty($_POST['_message'])) {
|
|
$body = rcube_utils::get_input_value('_message', rcube_utils::INPUT_POST, true);
|
|
$isHtml = (bool) rcube_utils::get_input_value('_is_html', rcube_utils::INPUT_POST);
|
|
}
|
|
else if ($COMPOSE['param']['body']) {
|
|
$body = $COMPOSE['param']['body'];
|
|
$isHtml = (bool) $COMPOSE['param']['html'];
|
|
}
|
|
// forward as attachment
|
|
else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $COMPOSE['as_attachment']) {
|
|
$isHtml = rcmail_compose_editor_mode();
|
|
$body = '';
|
|
|
|
rcmail_write_forward_attachments();
|
|
}
|
|
// reply/edit/draft/forward
|
|
else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || intval($RCMAIL->config->get('reply_mode')) != -1)) {
|
|
$isHtml = rcmail_compose_editor_mode();
|
|
$messages = array();
|
|
|
|
if (!empty($MESSAGE->parts)) {
|
|
// collect IDs of message/rfc822 parts
|
|
if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) {
|
|
foreach ($MESSAGE->attachments as $part) {
|
|
if ($part->mimetype == 'message/rfc822') {
|
|
$messages[] = $part->mime_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($MESSAGE->parts as $part) {
|
|
// skip no-content and attachment parts (#1488557)
|
|
if ($part->type != 'content' || !$part->size || $MESSAGE->is_attachment($part)) {
|
|
continue;
|
|
}
|
|
|
|
// skip all content parts inside the message/rfc822 part in DRAFT/EDIT mode
|
|
foreach ($messages as $mimeid) {
|
|
if (strpos($part->mime_id, $mimeid . '.') === 0) {
|
|
continue 2;
|
|
}
|
|
}
|
|
|
|
if ($part_body = rcmail_compose_part_body($part, $isHtml)) {
|
|
$body .= ($body ? ($isHtml ? '<br/>' : "\n") : '') . $part_body;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$body = rcmail_compose_part_body($MESSAGE, $isHtml);
|
|
}
|
|
|
|
// compose reply-body
|
|
if ($compose_mode == RCUBE_COMPOSE_REPLY)
|
|
$body = rcmail_create_reply_body($body, $isHtml);
|
|
// forward message body inline
|
|
else if ($compose_mode == RCUBE_COMPOSE_FORWARD)
|
|
$body = rcmail_create_forward_body($body, $isHtml);
|
|
// load draft message body
|
|
else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT)
|
|
$body = rcmail_create_draft_body($body, $isHtml);
|
|
}
|
|
else { // new message
|
|
$isHtml = rcmail_compose_editor_mode();
|
|
}
|
|
|
|
$plugin = $RCMAIL->plugins->exec_hook('message_compose_body',
|
|
array('body' => $body, 'html' => $isHtml, 'mode' => $compose_mode));
|
|
|
|
$body = $plugin['body'];
|
|
unset($plugin);
|
|
|
|
// add blocked.gif attachment (#1486516)
|
|
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;
|
|
$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, $LINE_LENGTH, $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 (!rcube_utils::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') {
|
|
$body = rcube_enriched::to_html($body);
|
|
}
|
|
else {
|
|
// try to remove the signature
|
|
if ($compose_mode != RCUBE_COMPOSE_DRAFT && $compose_mode != RCUBE_COMPOSE_EDIT) {
|
|
if ($RCMAIL->config->get('strip_existing_sig', true)) {
|
|
$body = rcmail_remove_signature($body);
|
|
}
|
|
}
|
|
|
|
// add HTML formatting
|
|
$body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed');
|
|
}
|
|
}
|
|
else {
|
|
if ($part->ctype_secondary == 'enriched') {
|
|
$body = rcube_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 rcube_html2text($body, false, true, $len);
|
|
$body = $txt->get_text();
|
|
}
|
|
else {
|
|
if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') {
|
|
$body = rcube_mime::unfold_flowed($body);
|
|
}
|
|
|
|
// try to remove the signature
|
|
if ($compose_mode != RCUBE_COMPOSE_DRAFT && $compose_mode != RCUBE_COMPOSE_EDIT) {
|
|
if ($RCMAIL->config->get('strip_existing_sig', true)) {
|
|
$body = rcmail_remove_signature($body);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $body;
|
|
}
|
|
|
|
function rcmail_compose_body($attrib)
|
|
{
|
|
global $RCMAIL, $OUTPUT, $HTML_MODE, $MESSAGE_BODY;
|
|
|
|
list($form_start, $form_end) = get_form_tags($attrib);
|
|
unset($attrib['form']);
|
|
|
|
if (empty($attrib['id']))
|
|
$attrib['id'] = 'rcmComposeBody';
|
|
|
|
$attrib['name'] = '_message';
|
|
|
|
$isHtml = $HTML_MODE;
|
|
|
|
$out = $form_start ? "$form_start\n" : '';
|
|
|
|
$saveid = new html_hiddenfield(array('name' => '_draft_saveid', 'value' => $RCMAIL->output->get_env('draft_id')));
|
|
$out .= $saveid->show();
|
|
|
|
$drafttoggle = new html_hiddenfield(array('name' => '_draft', 'value' => 'yes'));
|
|
$out .= $drafttoggle->show();
|
|
|
|
$msgtype = new html_hiddenfield(array('name' => '_is_html', 'value' => ($isHtml ? "1" : "0")));
|
|
$out .= $msgtype->show();
|
|
|
|
$framed = new html_hiddenfield(array('name' => '_framed', 'value' => '1'));
|
|
$out .= $framed->show();
|
|
|
|
// If desired, set this textarea to be editable by TinyMCE
|
|
if ($isHtml) {
|
|
$MESSAGE_BODY = htmlentities($MESSAGE_BODY, ENT_NOQUOTES, RCUBE_CHARSET);
|
|
$attrib['class'] = 'mce_editor';
|
|
$attrib['is_escaped'] = true;
|
|
$textarea = new html_textarea($attrib);
|
|
$out .= $textarea->show($MESSAGE_BODY);
|
|
}
|
|
else {
|
|
$textarea = new html_textarea($attrib);
|
|
$out .= $textarea->show('');
|
|
|
|
// quote plain text, inject into textarea
|
|
$table = get_html_translation_table(HTML_SPECIALCHARS);
|
|
$MESSAGE_BODY = strtr($MESSAGE_BODY, $table);
|
|
$out = substr($out, 0, -11) . $MESSAGE_BODY . '</textarea>';
|
|
}
|
|
|
|
$out .= $form_end ? "\n$form_end" : '';
|
|
|
|
$OUTPUT->set_env('composebody', $attrib['id']);
|
|
|
|
// include HTML editor
|
|
$RCMAIL->html_editor();
|
|
|
|
// Set language list
|
|
if ($RCMAIL->config->get('enable_spellcheck')) {
|
|
$engine = new rcube_spellchecker();
|
|
$dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary');
|
|
$spellcheck_langs = $engine->languages();
|
|
$lang = $_SESSION['language'];
|
|
|
|
// if not found in the list, try with two-letter code
|
|
if (!$spellcheck_langs[$lang]) {
|
|
$lang = strtolower(substr($lang, 0, 2));
|
|
}
|
|
|
|
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 ? '+' : '') . rcube::JQ($name).'='.rcube::JQ($key);
|
|
}
|
|
|
|
// include GoogieSpell
|
|
$OUTPUT->include_script('googiespell.js');
|
|
$OUTPUT->add_script(sprintf(
|
|
"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".
|
|
"googie.lang_revert = \"%s\";\n".
|
|
"googie.lang_no_error_found = \"%s\";\n".
|
|
"googie.lang_learn_word = \"%s\";\n".
|
|
"googie.setLanguages(%s);\n".
|
|
"googie.setCurrentLanguage('%s');\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',
|
|
rcube::JQ(rcube::Q($RCMAIL->gettext('checkspelling'))),
|
|
rcube::JQ(rcube::Q($RCMAIL->gettext('resumeediting'))),
|
|
rcube::JQ(rcube::Q($RCMAIL->gettext('close'))),
|
|
rcube::JQ(rcube::Q($RCMAIL->gettext('revertto'))),
|
|
rcube::JQ(rcube::Q($RCMAIL->gettext('nospellerrors'))),
|
|
rcube::JQ(rcube::Q($RCMAIL->gettext('addtodict'))),
|
|
rcube_output::json_serialize($spellcheck_langs),
|
|
$lang,
|
|
$attrib['id'],
|
|
rcmail_output::JS_OBJECT_NAME), '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>';
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
function rcmail_create_reply_body($body, $bodyIsHtml)
|
|
{
|
|
global $RCMAIL, $MESSAGE, $LINE_LENGTH;
|
|
|
|
// build reply prefix
|
|
$from = array_pop(rcube_mime::decode_address_list($MESSAGE->get_header('from'), 1, false, $MESSAGE->headers->charset));
|
|
$prefix = $RCMAIL->gettext(array(
|
|
'name' => 'mailreplyintro',
|
|
'vars' => array(
|
|
'date' => $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')),
|
|
'sender' => $from['name'] ? $from['name'] : rcube_utils::idn_to_utf8($from['mailto']),
|
|
)
|
|
));
|
|
|
|
if (!$bodyIsHtml) {
|
|
$body = preg_replace('/\r?\n/', "\n", $body);
|
|
$body = trim($body, "\n");
|
|
|
|
// soft-wrap and quote message text
|
|
$body = rcmail_wrap_and_quote($body, $LINE_LENGTH);
|
|
|
|
$prefix .= "\n";
|
|
$suffix = '';
|
|
|
|
if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting
|
|
$prefix = "\n\n\n" . $prefix;
|
|
}
|
|
}
|
|
else {
|
|
// save inline images to files
|
|
$cid_map = rcmail_write_inline_attachments($MESSAGE);
|
|
// set is_safe flag (we need this for html body washing)
|
|
rcmail_check_safe($MESSAGE);
|
|
// clean up html tags
|
|
$body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map);
|
|
|
|
// build reply (quote content)
|
|
$prefix = '<p>' . rcube::Q($prefix) . "</p>\n";
|
|
$prefix .= '<blockquote>';
|
|
|
|
if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting
|
|
$prefix = '<br>' . $prefix;
|
|
$suffix = '</blockquote>';
|
|
}
|
|
else {
|
|
$suffix = '</blockquote><p></p>';
|
|
}
|
|
}
|
|
|
|
return $prefix . $body . $suffix;
|
|
}
|
|
|
|
|
|
function rcmail_create_forward_body($body, $bodyIsHtml)
|
|
{
|
|
global $RCMAIL, $MESSAGE, $COMPOSE;
|
|
|
|
// add attachments
|
|
if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) {
|
|
$cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
|
|
}
|
|
|
|
$date = $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long'));
|
|
|
|
if (!$bodyIsHtml) {
|
|
$prefix = "\n\n\n-------- " . $RCMAIL->gettext('originalmessage') . " --------\n";
|
|
$prefix .= $RCMAIL->gettext('subject') . ': ' . $MESSAGE->subject . "\n";
|
|
$prefix .= $RCMAIL->gettext('date') . ': ' . $date . "\n";
|
|
$prefix .= $RCMAIL->gettext('from') . ': ' . $MESSAGE->get_header('from') . "\n";
|
|
$prefix .= $RCMAIL->gettext('to') . ': ' . $MESSAGE->get_header('to') . "\n";
|
|
|
|
if ($cc = $MESSAGE->headers->get('cc')) {
|
|
$prefix .= $RCMAIL->gettext('cc') . ': ' . $cc . "\n";
|
|
}
|
|
if (($replyto = $MESSAGE->headers->get('reply-to')) && $replyto != $MESSAGE->get_header('from')) {
|
|
$prefix .= $RCMAIL->gettext('replyto') . ': ' . $replyto . "\n";
|
|
}
|
|
|
|
$prefix .= "\n";
|
|
$body = trim($body, "\r\n");
|
|
}
|
|
else {
|
|
// set is_safe flag (we need this for html body washing)
|
|
rcmail_check_safe($MESSAGE);
|
|
|
|
// clean up html tags
|
|
$body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map);
|
|
|
|
$prefix = sprintf(
|
|
"<br /><p>-------- " . $RCMAIL->gettext('originalmessage') . " --------</p>" .
|
|
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody>" .
|
|
"<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" .
|
|
"<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" .
|
|
"<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" .
|
|
"<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>",
|
|
$RCMAIL->gettext('subject'), rcube::Q($MESSAGE->subject),
|
|
$RCMAIL->gettext('date'), rcube::Q($date),
|
|
$RCMAIL->gettext('from'), rcube::Q($MESSAGE->get_header('from'), 'replace'),
|
|
$RCMAIL->gettext('to'), rcube::Q($MESSAGE->get_header('to'), 'replace'));
|
|
|
|
if ($cc = $MESSAGE->headers->get('cc'))
|
|
$prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>",
|
|
$RCMAIL->gettext('cc'), rcube::Q($cc, 'replace'));
|
|
|
|
if (($replyto = $MESSAGE->headers->get('reply-to')) && $replyto != $MESSAGE->get_header('from'))
|
|
$prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>",
|
|
$RCMAIL->gettext('replyto'), rcube::Q($replyto, 'replace'));
|
|
|
|
$prefix .= "</tbody></table><br>";
|
|
}
|
|
|
|
return $prefix . $body;
|
|
}
|
|
|
|
|
|
function rcmail_create_draft_body($body, $bodyIsHtml)
|
|
{
|
|
global $MESSAGE, $COMPOSE;
|
|
|
|
// add attachments
|
|
// sizeof($MESSAGE->mime_parts can be 1 - e.g. attachment, but no text!
|
|
if (empty($COMPOSE['forward_attachments'])
|
|
&& is_array($MESSAGE->mime_parts)
|
|
&& count($MESSAGE->mime_parts) > 0
|
|
) {
|
|
$cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml);
|
|
}
|
|
|
|
// clean up HTML tags - XSS prevention (#1489251)
|
|
if ($bodyIsHtml) {
|
|
$body = rcmail_wash_html($body, array('safe' => 1), $cid_map);
|
|
|
|
// remove comments (produced by washtml)
|
|
$body = preg_replace('/<!--[^>]+-->/', '', $body);
|
|
|
|
// replace cid with href in inline images links
|
|
if (!empty($cid_map)) {
|
|
$body = str_replace(array_keys($cid_map), array_values($cid_map), $body);
|
|
}
|
|
}
|
|
|
|
return $body;
|
|
}
|
|
|
|
|
|
function rcmail_remove_signature($body)
|
|
{
|
|
global $RCMAIL;
|
|
|
|
$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) {
|
|
if ($sp == 0 || $body[$sp-1] == "\n") {
|
|
// do not touch blocks with more that X lines
|
|
if (substr_count($body, "\n", $sp) < $sig_max_lines) {
|
|
$body = substr($body, 0, max(0, $sp-1));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $body;
|
|
}
|
|
|
|
|
|
function rcmail_write_compose_attachments(&$message, $bodyIsHtml)
|
|
{
|
|
global $RCMAIL, $COMPOSE, $compose_mode;
|
|
|
|
$loaded_attachments = array();
|
|
foreach ((array)$COMPOSE['attachments'] as $attachment) {
|
|
$loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment;
|
|
}
|
|
|
|
$cid_map = array();
|
|
$messages = array();
|
|
|
|
foreach ((array)$message->mime_parts as $pid => $part) {
|
|
if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) {
|
|
// skip parts that aren't valid attachments
|
|
if ($part->ctype_primary == 'multipart' || $part->mimetype == 'application/ms-tnef') {
|
|
continue;
|
|
}
|
|
|
|
// skip message attachments in reply mode
|
|
if ($part->ctype_primary == 'message' && $compose_mode == RCUBE_COMPOSE_REPLY) {
|
|
continue;
|
|
}
|
|
|
|
// skip inline images when forwarding in text mode
|
|
if ($part->content_id && $part->disposition == 'inline' && !$bodyIsHtml && $compose_mode == RCUBE_COMPOSE_FORWARD) {
|
|
continue;
|
|
}
|
|
|
|
// skip message/rfc822 attachments on forwards (#1489214)
|
|
// Thunderbird when forwarding in inline mode displays such attachments
|
|
// and skips any attachments from inside of such part, this however
|
|
// skipped e.g. images used in HTML body or other attachments. So,
|
|
// better to skip .eml attachments but not their content (included files).
|
|
if ($part->mimetype == 'message/rfc822') {
|
|
if ($compose_mode == RCUBE_COMPOSE_FORWARD) {
|
|
continue;
|
|
}
|
|
$messages[] = $part->mime_id;
|
|
}
|
|
else if ($compose_mode != RCUBE_COMPOSE_FORWARD) {
|
|
// skip attachments included in message/rfc822 attachment (#1486487)
|
|
foreach ($messages as $mimeid) {
|
|
if (strpos($part->mime_id, $mimeid . '.') === 0) {
|
|
continue 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (($attachment = $loaded_attachments[rcmail_attachment_name($part) . $part->mimetype])
|
|
|| ($attachment = rcmail_save_attachment($message, $pid))
|
|
) {
|
|
$COMPOSE['attachments'][$attachment['id']] = $attachment;
|
|
|
|
if ($bodyIsHtml && ($part->content_id || $part->content_location)) {
|
|
$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
|
|
$cid_map[$part->content_location] = $url;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$COMPOSE['forward_attachments'] = true;
|
|
|
|
return $cid_map;
|
|
}
|
|
|
|
|
|
function rcmail_write_inline_attachments(&$message)
|
|
{
|
|
global $RCMAIL, $COMPOSE;
|
|
|
|
$cid_map = array();
|
|
foreach ((array)$message->mime_parts as $pid => $part) {
|
|
if (($part->content_id || $part->content_location) && $part->filename) {
|
|
if ($attachment = rcmail_save_attachment($message, $pid)) {
|
|
$COMPOSE['attachments'][$attachment['id']] = $attachment;
|
|
$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
|
|
$cid_map[$part->content_location] = $url;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $cid_map;
|
|
}
|
|
|
|
// Creates attachment(s) from the forwarded message(s)
|
|
function rcmail_write_forward_attachments()
|
|
{
|
|
global $RCMAIL, $COMPOSE, $MESSAGE;
|
|
|
|
$storage = $RCMAIL->get_storage();
|
|
$names = array();
|
|
$refs = array();
|
|
|
|
$loaded_attachments = array();
|
|
foreach ((array)$COMPOSE['attachments'] as $attachment) {
|
|
$loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment;
|
|
}
|
|
|
|
if ($COMPOSE['forward_uid'] == '*') {
|
|
$index = $storage->index(null, rcmail_sort_column(), rcmail_sort_order());
|
|
$COMPOSE['forward_uid'] = $index->get();
|
|
}
|
|
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']);
|
|
}
|
|
|
|
foreach ((array)$COMPOSE['forward_uid'] as $uid) {
|
|
$message = new rcube_message($uid);
|
|
|
|
if (empty($message->headers)) {
|
|
continue;
|
|
}
|
|
|
|
if (!empty($message->headers->charset)) {
|
|
$storage->set_charset($message->headers->charset);
|
|
}
|
|
|
|
if (empty($MESSAGE->subject)) {
|
|
$MESSAGE->subject = $message->subject;
|
|
}
|
|
|
|
// generate (unique) attachment name
|
|
$name = strlen($message->subject) ? mb_substr($message->subject, 0, 64) : 'message_rfc822';
|
|
if (!empty($names[$name])) {
|
|
$names[$name]++;
|
|
$name .= '_' . $names[$name];
|
|
}
|
|
$names[$name] = 1;
|
|
$name .= '.eml';
|
|
|
|
$data = $path = null;
|
|
|
|
if (!empty($loaded_attachments[$name . 'message/rfc822'])) {
|
|
continue;
|
|
}
|
|
|
|
// don't load too big attachments into memory
|
|
if (!rcube_utils::mem_check($message->size)) {
|
|
$temp_dir = unslashify($RCMAIL->config->get('temp_dir'));
|
|
$path = tempnam($temp_dir, 'rcmAttmnt');
|
|
if ($fp = fopen($path, 'w')) {
|
|
$storage->get_raw_body($message->uid, $fp);
|
|
fclose($fp);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
$data = $storage->get_raw_body($message->uid);
|
|
$curr_mem += $message->size;
|
|
}
|
|
|
|
$attachment = array(
|
|
'group' => $COMPOSE['id'],
|
|
'name' => $name,
|
|
'mimetype' => 'message/rfc822',
|
|
'data' => $data,
|
|
'path' => $path,
|
|
'size' => $path ? filesize($path) : strlen($data),
|
|
);
|
|
|
|
$attachment = $RCMAIL->plugins->exec_hook('attachment_save', $attachment);
|
|
|
|
if ($attachment['status']) {
|
|
unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']);
|
|
$COMPOSE['attachments'][$attachment['id']] = $attachment;
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
function rcmail_save_attachment(&$message, $pid)
|
|
{
|
|
global $COMPOSE;
|
|
|
|
$rcmail = rcmail::get_instance();
|
|
$part = $message->mime_parts[$pid];
|
|
$data = $path = null;
|
|
|
|
// don't load too big attachments into memory
|
|
if (!rcube_utils::mem_check($part->size)) {
|
|
$temp_dir = unslashify($rcmail->config->get('temp_dir'));
|
|
$path = tempnam($temp_dir, 'rcmAttmnt');
|
|
|
|
if ($fp = fopen($path, 'w')) {
|
|
$message->get_part_content($pid, $fp, true, 0, false);
|
|
fclose($fp);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
$data = $message->get_part_content($pid, null, true, 0, false);
|
|
}
|
|
|
|
$mimetype = $part->ctype_primary . '/' . $part->ctype_secondary;
|
|
$filename = rcmail_attachment_name($part);
|
|
|
|
$attachment = array(
|
|
'group' => $COMPOSE['id'],
|
|
'name' => $filename,
|
|
'mimetype' => $mimetype,
|
|
'content_id' => $part->content_id,
|
|
'data' => $data,
|
|
'path' => $path,
|
|
'size' => $path ? filesize($path) : strlen($data),
|
|
);
|
|
|
|
$attachment = $rcmail->plugins->exec_hook('attachment_save', $attachment);
|
|
|
|
if ($attachment['status']) {
|
|
unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']);
|
|
return $attachment;
|
|
}
|
|
else if ($path) {
|
|
@unlink($path);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function rcmail_save_image($path, $mimetype='')
|
|
{
|
|
global $COMPOSE;
|
|
|
|
// handle attachments in memory
|
|
$data = file_get_contents($path);
|
|
$name = rcmail_basename($path);
|
|
|
|
$attachment = array(
|
|
'group' => $COMPOSE['id'],
|
|
'name' => $name,
|
|
'mimetype' => $mimetype ? $mimetype : rcube_mime::file_content_type($path, $name),
|
|
'data' => $data,
|
|
'size' => strlen($data),
|
|
);
|
|
|
|
$attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment);
|
|
|
|
if ($attachment['status']) {
|
|
unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']);
|
|
return $attachment;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function rcmail_basename($filename)
|
|
{
|
|
// basename() is not unicode safe and locale dependent
|
|
if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) {
|
|
return preg_replace('/^.*[\\\\\\/]/', '', $filename);
|
|
}
|
|
else {
|
|
return preg_replace('/^.*[\/]/', '', $filename);
|
|
}
|
|
}
|
|
|
|
function rcmail_compose_subject($attrib)
|
|
{
|
|
global $MESSAGE, $COMPOSE, $compose_mode;
|
|
|
|
list($form_start, $form_end) = get_form_tags($attrib);
|
|
unset($attrib['form']);
|
|
|
|
$attrib['name'] = '_subject';
|
|
$attrib['spellcheck'] = 'true';
|
|
|
|
$textfield = new html_inputfield($attrib);
|
|
$subject = '';
|
|
|
|
// use subject from post
|
|
if (isset($_POST['_subject'])) {
|
|
$subject = rcube_utils::get_input_value('_subject', rcube_utils::INPUT_POST, TRUE);
|
|
}
|
|
// create a reply-subject
|
|
else if ($compose_mode == RCUBE_COMPOSE_REPLY) {
|
|
if (preg_match('/^re:/i', $MESSAGE->subject))
|
|
$subject = $MESSAGE->subject;
|
|
else
|
|
$subject = 'Re: '.$MESSAGE->subject;
|
|
}
|
|
// create a forward-subject
|
|
else if ($compose_mode == RCUBE_COMPOSE_FORWARD) {
|
|
if (preg_match('/^fwd:/i', $MESSAGE->subject))
|
|
$subject = $MESSAGE->subject;
|
|
else
|
|
$subject = 'Fwd: '.$MESSAGE->subject;
|
|
}
|
|
// creeate a draft-subject
|
|
else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) {
|
|
$subject = $MESSAGE->subject;
|
|
}
|
|
else if (!empty($COMPOSE['param']['subject'])) {
|
|
$subject = $COMPOSE['param']['subject'];
|
|
}
|
|
|
|
$out = $form_start ? "$form_start\n" : '';
|
|
$out .= $textfield->show($subject);
|
|
$out .= $form_end ? "\n$form_end" : '';
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
function rcmail_compose_attachment_list($attrib)
|
|
{
|
|
global $RCMAIL, $OUTPUT, $COMPOSE;
|
|
|
|
// add ID if not given
|
|
if (!$attrib['id'])
|
|
$attrib['id'] = 'rcmAttachmentList';
|
|
|
|
$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' => $skin_path . $attrib['deleteicon'],
|
|
'alt' => $RCMAIL->gettext('delete')
|
|
));
|
|
}
|
|
else if (rcube_utils::get_boolean($attrib['textbuttons'])) {
|
|
$button = rcube::Q($RCMAIL->gettext('delete'));
|
|
}
|
|
|
|
foreach ($COMPOSE['attachments'] as $id => $a_prop) {
|
|
if (empty($a_prop)) {
|
|
continue;
|
|
}
|
|
|
|
$out .= html::tag('li', array(
|
|
'id' => 'rcmfile'.$id,
|
|
'class' => rcube_utils::file2class($a_prop['mimetype'], $a_prop['name']),
|
|
'onmouseover' => "rcube_webmail.long_subject_title_ex(this, 0)",
|
|
),
|
|
html::a(array(
|
|
'href' => "#delete",
|
|
'title' => $RCMAIL->gettext('delete'),
|
|
'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id),
|
|
'class' => 'delete'
|
|
),
|
|
$button
|
|
) . rcube::Q($a_prop['name'])
|
|
);
|
|
|
|
$jslist['rcmfile'.$id] = array(
|
|
'name' => $a_prop['name'],
|
|
'complete' => true,
|
|
'mimetype' => $a_prop['mimetype']
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($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', $skin_path . $attrib['cancelicon']);
|
|
if ($attrib['loadingicon'])
|
|
$OUTPUT->set_env('loadingicon', $skin_path . $attrib['loadingicon']);
|
|
|
|
$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 $OUTPUT, $RCMAIL;
|
|
|
|
// set defaults
|
|
$attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes');
|
|
|
|
// Get filesize, enable upload progress bar
|
|
$max_filesize = $RCMAIL->upload_init();
|
|
|
|
$button = new html_inputfield(array('type' => 'button'));
|
|
$content = html::div(null, rcmail_compose_attachment_field())
|
|
. html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))));
|
|
|
|
if (rcube_utils::get_boolean($attrib['buttons'])) {
|
|
$content .= html::div('buttons',
|
|
$button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' .
|
|
$button->show($RCMAIL->gettext('upload'), array('class' => 'button mainaction', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".command('send-attachment', this.form)"))
|
|
);
|
|
}
|
|
|
|
$out = html::div($attrib, $OUTPUT->form_tag(array(
|
|
'id' => $attrib['id'] . 'Frm',
|
|
'name' => 'uploadform',
|
|
'method' => 'post',
|
|
'enctype' => 'multipart/form-data'
|
|
), $content
|
|
));
|
|
|
|
$OUTPUT->add_gui_object('uploadform', $attrib['id'] . 'Frm');
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
function rcmail_compose_attachment_field($attrib = array())
|
|
{
|
|
$attrib['type'] = 'file';
|
|
$attrib['name'] = '_attachments[]';
|
|
$attrib['multiple'] = 'multiple';
|
|
|
|
$field = new html_inputfield($attrib);
|
|
|
|
return $field->show();
|
|
}
|
|
|
|
|
|
function rcmail_priority_selector($attrib)
|
|
{
|
|
global $RCMAIL, $MESSAGE;
|
|
|
|
list($form_start, $form_end) = get_form_tags($attrib);
|
|
unset($attrib['form']);
|
|
|
|
$attrib['name'] = '_priority';
|
|
$prio_list = array(
|
|
$RCMAIL->gettext('lowest') => 5,
|
|
$RCMAIL->gettext('low') => 4,
|
|
$RCMAIL->gettext('normal') => 0,
|
|
$RCMAIL->gettext('high') => 2,
|
|
$RCMAIL->gettext('highest') => 1,
|
|
);
|
|
|
|
$selector = new html_select($attrib);
|
|
$selector->add(array_keys($prio_list), array_values($prio_list));
|
|
|
|
if (isset($_POST['_priority']))
|
|
$sel = $_POST['_priority'];
|
|
else if (isset($MESSAGE->headers->priority) && intval($MESSAGE->headers->priority) != 3)
|
|
$sel = $MESSAGE->headers->priority;
|
|
else
|
|
$sel = 0;
|
|
|
|
$out = $form_start ? "$form_start\n" : '';
|
|
$out .= $selector->show((int) $sel);
|
|
$out .= $form_end ? "\n$form_end" : '';
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
function rcmail_receipt_checkbox($attrib)
|
|
{
|
|
global $RCMAIL, $MESSAGE, $compose_mode;
|
|
|
|
list($form_start, $form_end) = get_form_tags($attrib);
|
|
unset($attrib['form']);
|
|
|
|
if (!isset($attrib['id']))
|
|
$attrib['id'] = 'receipt';
|
|
|
|
$attrib['name'] = '_receipt';
|
|
$attrib['value'] = '1';
|
|
|
|
$checkbox = new html_checkbox($attrib);
|
|
|
|
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');
|
|
|
|
$out = $form_start ? "$form_start\n" : '';
|
|
$out .= $checkbox->show($mdn_default);
|
|
$out .= $form_end ? "\n$form_end" : '';
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
function rcmail_dsn_checkbox($attrib)
|
|
{
|
|
global $RCMAIL;
|
|
|
|
list($form_start, $form_end) = get_form_tags($attrib);
|
|
unset($attrib['form']);
|
|
|
|
if (!isset($attrib['id']))
|
|
$attrib['id'] = 'dsn';
|
|
|
|
$attrib['name'] = '_dsn';
|
|
$attrib['value'] = '1';
|
|
|
|
$checkbox = new html_checkbox($attrib);
|
|
|
|
if (isset($_POST['_dsn']))
|
|
$dsn_value = (int) $_POST['_dsn'];
|
|
else
|
|
$dsn_value = $RCMAIL->config->get('dsn_default');
|
|
|
|
$out = $form_start ? "$form_start\n" : '';
|
|
$out .= $checkbox->show($dsn_value);
|
|
$out .= $form_end ? "\n$form_end" : '';
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
function rcmail_editor_selector($attrib)
|
|
{
|
|
global $RCMAIL;
|
|
|
|
// determine whether HTML or plain text should be checked
|
|
$useHtml = rcmail_compose_editor_mode();
|
|
|
|
if (empty($attrib['editorid']))
|
|
$attrib['editorid'] = 'rcmComposeBody';
|
|
|
|
if (empty($attrib['name']))
|
|
$attrib['name'] = 'editorSelect';
|
|
|
|
$attrib['onchange'] = "return rcmail_toggle_editor(this, '".$attrib['editorid']."', '_is_html')";
|
|
|
|
$select = new html_select($attrib);
|
|
|
|
$select->add(rcube::Q($RCMAIL->gettext('htmltoggle')), 'html');
|
|
$select->add(rcube::Q($RCMAIL->gettext('plaintoggle')), 'plain');
|
|
|
|
return $select->show($useHtml ? 'html' : 'plain');
|
|
}
|
|
|
|
|
|
function rcmail_store_target_selection($attrib)
|
|
{
|
|
global $COMPOSE, $RCMAIL;
|
|
|
|
$attrib['name'] = '_store_target';
|
|
$select = $RCMAIL->folder_selector(array_merge($attrib, array(
|
|
'noselection' => '- ' . $RCMAIL->gettext('dontsave') . ' -',
|
|
'folder_filter' => 'mail',
|
|
'folder_rights' => 'w',
|
|
)));
|
|
|
|
return $select->show(isset($_POST['_store_target']) ? $_POST['_store_target'] : $COMPOSE['param']['sent_mbox'], $attrib);
|
|
}
|
|
|
|
|
|
function rcmail_check_sent_folder($folder, $create=false)
|
|
{
|
|
global $RCMAIL;
|
|
|
|
// 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->storage->folder_exists($folder))
|
|
return $RCMAIL->storage->create_folder($folder, true);
|
|
else
|
|
return $RCMAIL->storage->subscribe($folder);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
function get_form_tags($attrib)
|
|
{
|
|
global $RCMAIL, $MESSAGE_FORM, $COMPOSE;
|
|
|
|
$form_start = '';
|
|
if (!$MESSAGE_FORM) {
|
|
$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();
|
|
}
|
|
|
|
$form_end = ($MESSAGE_FORM && !strlen($attrib['form'])) ? '</form>' : '';
|
|
$form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
|
|
|
|
if (!$MESSAGE_FORM)
|
|
$RCMAIL->output->add_gui_object('messageform', $form_name);
|
|
|
|
$MESSAGE_FORM = $form_name;
|
|
|
|
return array($form_start, $form_end);
|
|
}
|
|
|
|
|
|
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 ".rcmail_output::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 = rcube::JQ($id);
|
|
|
|
// set class name(s)
|
|
$class_name = 'addressbook';
|
|
if ($source['class_name'])
|
|
$class_name .= ' ' . $source['class_name'];
|
|
|
|
$out .= sprintf($line_templ,
|
|
rcube_utils::html_identifier($id,true),
|
|
$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 $RCMAIL, $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 $RCMAIL->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'));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
function rcmail_compose_responses_list($attrib)
|
|
{
|
|
global $RCMAIL, $OUTPUT;
|
|
|
|
$attrib += array('id' => 'rcmresponseslist', 'tagname' => 'ul', 'cols' => 1);
|
|
|
|
$jsenv = array();
|
|
$list = new html_table($attrib);
|
|
foreach ($RCMAIL->get_compose_responses(true) as $response) {
|
|
$key = $response['key'];
|
|
$item = html::a(array(
|
|
'href '=> '#'.urlencode($response['name']),
|
|
'class' => rtrim('insertresponse ' . $attrib['itemclass']),
|
|
'unselectable' => 'on',
|
|
'rel' => $key,
|
|
), rcube::Q($response['name']));
|
|
|
|
$jsenv[$key] = $response;
|
|
$list->add(array(), $item);
|
|
}
|
|
|
|
// set client env
|
|
$OUTPUT->set_env('textresponses', $jsenv);
|
|
$OUTPUT->add_gui_object('responseslist', $attrib['id']);
|
|
|
|
return $list->show();
|
|
}
|