From ef595a10e03a0f8f4eae50e7302de4eb8f47b1ae Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Thu, 16 Apr 2015 04:56:38 -0400 Subject: [PATCH] Add option to place signature at bottom of the quoted text even in top-posting mode [sig_below] --- program/steps/mail/compose.inc | 190 +++++++++++++++++++++++++++-------------------- 1 files changed, 110 insertions(+), 80 deletions(-) diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 22ebaed..5009c52 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -53,13 +53,14 @@ } $COMPOSE_ID = uniqid(mt_rand()); + $params = rcube_utils::request2param(rcube_utils::INPUT_GET, 'task|action', true); + $_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(), + 'param' => $params, + 'mailbox' => $params['mbox'] ?: $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) @@ -80,9 +81,9 @@ $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', + 'fileuploaderror', 'sendmessage', 'newresponse', 'responsename', 'responsetext', 'save', 'savingresponse', 'restoresavedcomposedata', 'restoremessage', 'delete', 'restore', 'ignore', - 'selectimportfile'); + 'selectimportfile', 'messageissent'); $OUTPUT->set_pagetitle($RCMAIL->gettext('compose')); @@ -90,7 +91,10 @@ $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('sig_below', $RCMAIL->config->get('sig_below')); $OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); +$OUTPUT->set_env('save_localstorage', (bool)$RCMAIL->config->get('compose_save_localstorage')); +$OUTPUT->set_env('is_sent', false); $drafts_mbox = $RCMAIL->config->get('drafts_mbox'); $config_show_sig = $RCMAIL->config->get('show_sig', 1); @@ -130,8 +134,10 @@ $compose_mode = RCUBE_COMPOSE_EDIT; } -$COMPOSE['mode'] = $compose_mode; -$OUTPUT->set_env('compose_mode', $compose_mode); +if ($compose_mode) { + $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 @@ -280,6 +286,7 @@ foreach ($parts as $header) { $fvalue = ''; $decode_header = true; + $charset = $MESSAGE->headers->charset; // we have a set of recipients stored is session if ($header == 'to' && ($mailto_id = $COMPOSE['param']['mailto']) @@ -287,16 +294,19 @@ ) { $fvalue = urldecode($_SESSION['mailto'][$mailto_id]); $decode_header = false; + $charset = $RCMAIL->output->charset; // 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); + $fvalue = rcube_utils::get_input_value('_'.$header, rcube_utils::INPUT_POST, TRUE); + $charset = $RCMAIL->output->charset; } else if (!empty($COMPOSE['param'][$header])) { - $fvalue = $COMPOSE['param'][$header]; + $fvalue = $COMPOSE['param'][$header]; + $charset = $RCMAIL->output->charset; } else if ($compose_mode == RCUBE_COMPOSE_REPLY) { // get recipent address(es) out of the message headers @@ -315,13 +325,18 @@ $fvalue = $mailfollowup; else if ($mailreplyto) $fvalue = $mailreplyto; - else if (!empty($MESSAGE->headers->replyto)) - $fvalue = $MESSAGE->headers->replyto; + else if (!empty($MESSAGE->headers->replyto)) { + $fvalue = $MESSAGE->headers->replyto; + $replyto = true; + } 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))) { + // Reply-To address need to be unset (#1490233) + if (!empty($ident) && empty($replyto) + && in_array($ident['ident'], array($fvalue, $MESSAGE->headers->from)) + ) { $fvalue = $MESSAGE->headers->to; } } @@ -337,9 +352,9 @@ // 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); + $from = rcube_mime::decode_address_list($v, null, false, $charset, true); + $to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $charset, true); + $replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $charset, true); if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) { $fvalue .= (!empty($fvalue) ? $separator : '') . $v; @@ -365,7 +380,7 @@ // 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); + $to_addresses = rcube_mime::decode_address_list($fvalue, null, $decode_header, $charset); $fvalue = array(); foreach ($to_addresses as $addr_part) { @@ -412,7 +427,8 @@ 'filedroparea' => 'compose_file_drop_area', 'priorityselector' => 'rcmail_priority_selector', 'editorselector' => 'rcmail_editor_selector', - 'receiptcheckbox' => 'rcmail_receipt_checkbox', + 'receiptcheckbox' => 'rcmail_mdn_checkbox', // deprecated + 'mdncheckbox' => 'rcmail_mdn_checkbox', 'dsncheckbox' => 'rcmail_dsn_checkbox', 'storetarget' => 'rcmail_store_target_selection', 'addressbooks' => 'rcmail_addressbook_list', @@ -433,6 +449,8 @@ // #1486037: remove "mailto:" prefix $COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $mailto[0]); + // #1490346: decode the recipient address + $COMPOSE['param']['to'] = urldecode($COMPOSE['param']['to']); // Supported case-insensitive tokens in mailto URL $url_tokens = array('to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'body'); @@ -487,7 +505,7 @@ foreach ($plugin['attachments'] as $attach) { // we have structured data if (is_array($attach)) { - $attachment = $attach; + $attachment = $attach + array('group' => $COMPOSE_ID); } // only a file path is given else { @@ -595,8 +613,10 @@ 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) ? '---' : '-- '; + $top_posting = intval($RCMAIL->config->get('reply_mode')) > 0 + && !$RCMAIL->config->get('sig_below') + && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD); + $separator = $top_posting ? '---' : '-- '; $field_attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.".change_identity(this)"; $select_from = new html_select($field_attrib); @@ -611,20 +631,17 @@ $text = $html = $sql_arr['signature']; if ($sql_arr['html_signature']) { - $h2t = new rcube_html2text($sql_arr['signature'], false, false); + $h2t = new rcube_html2text($html, false, true); $text = trim($h2t->get_text()); } else { - $html = htmlentities($html, ENT_NOQUOTES, RCUBE_CHARSET); + $t2h = new rcube_text2html($text, false); + $html = $t2h->get_html(); } 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; @@ -772,12 +789,13 @@ 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')) { + if ($isHtml && preg_match('#<img src="program/resources/blocked\.gif"#', $body)) { + $content = $RCMAIL->get_resource_content('blocked.gif'); + if ($content && ($attachment = rcmail_save_image('blocked.gif', 'image/gif', $content))) { $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); + $body = preg_replace('#program/resources/blocked\.gif#', $url, $body); } } @@ -796,21 +814,13 @@ 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); - } + $body = $MESSAGE->get_part_body($part->mime_id, true); // message is cached but not exists (#1485443), or other error - if ($part->body === false) { + if ($body === false) { return ''; } - - $body = $part->body; if ($isHtml) { if ($part->ctype_secondary == 'html') { @@ -826,15 +836,8 @@ } } - if ($part->ctype_parameters['format'] == 'flowed') { - $body = rcube_mime::unfold_flowed($body); - } - // add HTML formatting - $body = rcmail_plain_body($body); - if ($body) { - $body = '<pre>' . $body . '</pre>'; - } + $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed'); } } else { @@ -957,9 +960,8 @@ "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(), + "googie.decorateTextarea('%s');\n", + $RCMAIL->output->asset_url($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'))), @@ -970,14 +972,13 @@ rcube::JQ(rcube::Q($RCMAIL->gettext('addtodict'))), rcube_output::json_serialize($spellcheck_langs), $lang, - $attrib['id'], - rcmail_output::JS_OBJECT_NAME), 'foot'); + $attrib['id']), 'foot'); $OUTPUT->add_label('checking'); $OUTPUT->set_env('spellcheck_langs', join(',', $editor_lang_set)); } - $out .= "\n".'<iframe name="savetarget" src="program/resources/blank.gif" style="width:0;height:0;border:none;visibility:hidden;"></iframe>'; + $out .= "\n".'<iframe name="savetarget" src="program/resources/blank.gif" style="width:0;height:0;border:none;visibility:hidden;" aria-hidden="true"></iframe>'; return $out; } @@ -997,6 +998,8 @@ ) )); + $reply_mode = intval($RCMAIL->config->get('reply_mode')); + if (!$bodyIsHtml) { $body = preg_replace('/\r?\n/', "\n", $body); $body = trim($body, "\n"); @@ -1005,10 +1008,13 @@ $body = rcmail_wrap_and_quote($body, $LINE_LENGTH); $prefix .= "\n"; - $suffix = ''; - if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting + if ($reply_mode > 0) { // top-posting $prefix = "\n\n\n" . $prefix; + $suffix = ''; + } + else { + $suffix = "\n"; } } else { @@ -1023,7 +1029,7 @@ $prefix = '<p>' . rcube::Q($prefix) . "</p>\n"; $prefix .= '<blockquote>'; - if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting + if ($reply_mode > 0) { // top-posting $prefix = '<br>' . $prefix; $suffix = '</blockquote>'; } @@ -1315,7 +1321,6 @@ } else { $data = $storage->get_raw_body($message->uid); - $curr_mem += $message->size; } $attachment = array( @@ -1366,7 +1371,7 @@ $path = tempnam($temp_dir, 'rcmAttmnt'); if ($fp = fopen($path, 'w')) { - $message->get_part_content($pid, $fp, true, 0, false); + $message->get_part_body($pid, false, 0, $fp); fclose($fp); } else { @@ -1374,7 +1379,7 @@ } } else { - $data = $message->get_part_content($pid, null, true, 0, false); + $data = $message->get_part_body($pid); } $mimetype = $part->ctype_primary . '/' . $part->ctype_secondary; @@ -1388,6 +1393,7 @@ 'data' => $data, 'path' => $path, 'size' => $path ? filesize($path) : strlen($data), + 'charset' => $part->charset, ); $attachment = $rcmail->plugins->exec_hook('attachment_save', $attachment); @@ -1403,18 +1409,31 @@ return false; } -function rcmail_save_image($path, $mimetype='') +function rcmail_save_image($path, $mimetype = '', $data = null) { global $COMPOSE; // handle attachments in memory - $data = file_get_contents($path); + if (empty($data)) { + $data = file_get_contents($path); + $is_file = true; + } + $name = rcmail_basename($path); + + if (empty($mimetype)) { + if ($is_file) { + $mimetype = rcube_mime::file_content_type($path, $name); + } + else { + $mimetype = rcube_mime::file_content_type($data, $name, 'application/octet-stream', true); + } + } $attachment = array( 'group' => $COMPOSE['id'], 'name' => $name, - 'mimetype' => $mimetype ? $mimetype : rcube_mime::file_content_type($path, $name), + 'mimetype' => $mimetype, 'data' => $data, 'size' => strlen($data), ); @@ -1457,12 +1476,18 @@ if (isset($_POST['_subject'])) { $subject = rcube_utils::get_input_value('_subject', rcube_utils::INPUT_POST, TRUE); } + else if (!empty($COMPOSE['param']['subject'])) { + $subject = $COMPOSE['param']['subject']; + } // 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; + + // replace (was: ...) (#1489375) + $subject = preg_replace('/\s*\([wW]as:[^\)]+\)\s*$/', '', $subject); } // create a forward-subject else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { @@ -1474,9 +1499,6 @@ // 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" : ''; @@ -1495,15 +1517,14 @@ if (!$attrib['id']) $attrib['id'] = 'rcmAttachmentList'; - $out = "\n"; - $jslist = array(); - $button = ''; - $skin_path = $RCMAIL->config->get('skin_path'); + $out = "\n"; + $jslist = array(); + $button = ''; if (is_array($COMPOSE['attachments'])) { if ($attrib['deleteicon']) { $button = html::img(array( - 'src' => $skin_path . $attrib['deleteicon'], + 'src' => $RCMAIL->output->abs_url($attrib['deleteicon'], true), 'alt' => $RCMAIL->gettext('delete') )); } @@ -1525,7 +1546,9 @@ 'href' => "#delete", 'title' => $RCMAIL->gettext('delete'), 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id), - 'class' => 'delete' + 'class' => 'delete', + 'tabindex' => $attrib['tabindex'] ?: '0', + 'aria-label' => $RCMAIL->gettext('delete') . ' ' . $a_prop['name'], ), $button ) . rcube::Q($a_prop['name']) @@ -1540,16 +1563,22 @@ } if ($attrib['deleteicon']) - $COMPOSE['deleteicon'] = $skin_path . $attrib['deleteicon']; + $COMPOSE['deleteicon'] = $RCMAIL->output->abs_url($attrib['deleteicon'], true); else if (rcube_utils::get_boolean($attrib['textbuttons'])) $COMPOSE['textbuttons'] = true; if ($attrib['cancelicon']) - $OUTPUT->set_env('cancelicon', $skin_path . $attrib['cancelicon']); + $OUTPUT->set_env('cancelicon', $RCMAIL->output->abs_url($attrib['cancelicon'], true)); if ($attrib['loadingicon']) - $OUTPUT->set_env('loadingicon', $skin_path . $attrib['loadingicon']); + $OUTPUT->set_env('loadingicon', $RCMAIL->output->abs_url($attrib['loadingicon'], true)); $OUTPUT->set_env('attachments', $jslist); $OUTPUT->add_gui_object('attachmentlist', $attrib['id']); + + // put tabindex value into data-tabindex attribute + if (isset($attrib['tabindex'])) { + $attrib['data-tabindex'] = $attrib['tabindex']; + unset($attrib['tabindex']); + } return html::tag('ul', $attrib, $out, html::$common_attrib); } @@ -1636,7 +1665,7 @@ } -function rcmail_receipt_checkbox($attrib) +function rcmail_mdn_checkbox($attrib) { global $RCMAIL, $MESSAGE, $compose_mode; @@ -1646,13 +1675,13 @@ if (!isset($attrib['id'])) $attrib['id'] = 'receipt'; - $attrib['name'] = '_receipt'; + $attrib['name'] = '_mdn'; $attrib['value'] = '1'; $checkbox = new html_checkbox($attrib); - if (isset($_POST['_receipt'])) - $mdn_default = $_POST['_receipt']; + if (isset($_POST['_mdn'])) + $mdn_default = $_POST['_mdn']; else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) $mdn_default = (bool) $MESSAGE->headers->mdn_to; else @@ -1707,7 +1736,7 @@ if (empty($attrib['name'])) $attrib['name'] = 'editorSelect'; - $attrib['onchange'] = "return rcmail_toggle_editor(this, '".$attrib['editorid']."', '_is_html')"; + $attrib['onchange'] = "return rcmail.command('toggle-editor', {id: '".$attrib['editorid']."', html: this.value == 'html'}, '', event)"; $select = new html_select($attrib); @@ -1864,9 +1893,10 @@ foreach ($RCMAIL->get_compose_responses(true) as $response) { $key = $response['key']; $item = html::a(array( - 'href '=> '#'.urlencode($response['name']), + 'href' => '#'.urlencode($response['name']), 'class' => rtrim('insertresponse ' . $attrib['itemclass']), 'unselectable' => 'on', + 'tabindex' => '0', 'rel' => $key, ), rcube::Q($response['name'])); -- Gitblit v1.9.1