| | Author: Aleksander Machniak | +-----------------------------------------------------------------------+ */ // remove all scripts and act as called in frame $OUTPUT->reset(); $OUTPUT->framed = true; $COMPOSE_ID = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC); $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; // Sanity checks if (!isset($COMPOSE['id'])) { rcube::raise_error(array('code' => 500, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid compose ID"), true, false); $OUTPUT->show_message('internalerror', 'error'); $OUTPUT->send('iframe'); } $saveonly = !empty($_GET['_saveonly']); $savedraft = !empty($_POST['_draft']) && !$saveonly; $SENDMAIL = new rcmail_sendmail($COMPOSE, array( 'sendmail' => true, 'saveonly' => $saveonly, 'savedraft' => $savedraft, 'error_handler' => function() use ($OUTPUT) { call_user_func_array(array($OUTPUT, 'show_message'), func_get_args()); $OUTPUT->send('iframe'); } )); // Collect input for message headers $headers = $SENDMAIL->headers_input(); $COMPOSE['param']['message-id'] = $headers['Message-ID']; $message_id = $headers['Message-ID']; $message_charset = $SENDMAIL->options['charset']; $message_body = rcube_utils::get_input_value('_message', rcube_utils::INPUT_POST, true, $message_charset); $isHtml = (bool) rcube_utils::get_input_value('_is_html', rcube_utils::INPUT_POST); // Reset message body and attachments in Mailvelope mode if (isset($_POST['_pgpmime'])) { $pgp_mime = rcube_utils::get_input_value('_pgpmime', rcube_utils::INPUT_POST); $isHtml = false; $message_body = ''; // clear unencrypted attachments foreach ((array) $COMPOSE['attachments'] as $attach) { $RCMAIL->plugins->exec_hook('attachment_delete', $attach); } $COMPOSE['attachments'] = array(); } if ($isHtml) { $bstyle = array(); if ($font_size = $RCMAIL->config->get('default_font_size')) { $bstyle[] = 'font-size: ' . $font_size; } if ($font_family = $RCMAIL->config->get('default_font')) { $bstyle[] = 'font-family: ' . rcmail::font_defs($font_family); } // append doctype and html/body wrappers $bstyle = !empty($bstyle) ? (" style='" . implode('; ', $bstyle) . "'") : ''; $message_body = '' . '' . "\r\n" . $message_body; } if (!$savedraft) { if ($isHtml) { $b_style = 'padding: 0 0.4em; border-left: #1010ff 2px solid; margin: 0'; $pre_style = 'margin: 0; padding: 0; font-family: monospace'; $message_body = preg_replace( array( // remove empty signature div '/
( )?<\/div>[\s\r\n]*$/', // replace signature's div ID (#6073) '/ id="_rc_sig"/', // add inline css for blockquotes and container '/
/', '/
/', // convert TinyMCE's new-line sequences (#1490463) '/

 <\/p>/', ), array( '', ' id="signature"', '

', '
', '


', ), $message_body); rcube_utils::preg_error(array( 'line' => __LINE__, 'file' => __FILE__, 'message' => "Could not format HTML!" ), true); } // Check spelling before send if ($RCMAIL->config->get('spellcheck_before_send') && $RCMAIL->config->get('enable_spellcheck') && empty($COMPOSE['spell_checked']) && !empty($message_body) ) { $message_body = str_replace("\r\n", "\n", $message_body); $spellchecker = new rcube_spellchecker(rcube_utils::get_input_value('_lang', rcube_utils::INPUT_GPC)); $spell_result = $spellchecker->check($message_body, $isHtml); $COMPOSE['spell_checked'] = true; if (!$spell_result) { if ($isHtml) { $result['words'] = $spellchecker->get(); $result['dictionary'] = (bool) $RCMAIL->config->get('spellcheck_dictionary'); } else { $result = $spellchecker->get_xml(); } $OUTPUT->show_message('mispellingsfound', 'error'); $OUTPUT->command('spellcheck_resume', $result); $OUTPUT->send('iframe'); } } // generic footer for all messages if ($footer = $SENDMAIL->generic_message_footer($isHtml)) { $message_body .= "\r\n" . $footer; } } if ($isHtml) { $message_body .= "\r\n\r\n"; } // sort attachments to make sure the order is the same as in the UI (#1488423) if ($files = rcube_utils::get_input_value('_attachments', rcube_utils::INPUT_POST)) { $files = explode(',', $files); $files = array_flip($files); foreach ($files as $idx => $val) { $files[$idx] = $COMPOSE['attachments'][$idx]; unset($COMPOSE['attachments'][$idx]); } $COMPOSE['attachments'] = array_merge(array_filter($files), $COMPOSE['attachments']); } // Since we can handle big messages with disk usage, we need more time to work @set_time_limit(360); // create PEAR::Mail_mime instance, set headers, body and params $MAIL_MIME = $SENDMAIL->create_message($headers, $message_body, $isHtml, $COMPOSE['attachments']); // add stored attachments, if any if (is_array($COMPOSE['attachments'])) { foreach ($COMPOSE['attachments'] as $id => $attachment) { // This hook retrieves the attachment contents from the file storage backend $attachment = $RCMAIL->plugins->exec_hook('attachment_get', $attachment); $is_inline = false; if ($isHtml) { $dispurl = '/[\'"]\S+display-attachment\S+file=rcmfile' . preg_quote($attachment['id']) . '[\'"]/'; $message_body = $MAIL_MIME->getHTMLBody(); $is_inline = preg_match($dispurl, $message_body); } // inline image if ($is_inline) { // Mail_Mime does not support many inline attachments with the same name (#1489406) // we'll generate cid: urls here to workaround this $cid = preg_replace('/[^0-9a-zA-Z]/', '', uniqid(time(), true)); if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $SENDMAIL->options['from'], $matches)) { $cid .= $matches[1]; } else { $cid .= '@localhost'; } $message_body = preg_replace($dispurl, '"cid:' . $cid . '"', $message_body); rcube_utils::preg_error(array( 'line' => __LINE__, 'file' => __FILE__, 'message' => "Could not replace an image reference!" ), true); $MAIL_MIME->setHTMLBody($message_body); if ($attachment['data']) $MAIL_MIME->addHTMLImage($attachment['data'], $attachment['mimetype'], $attachment['name'], false, $cid); else $MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name'], true, $cid); } else { $ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914 $file = $attachment['data'] ?: $attachment['path']; $folding = (int) $RCMAIL->config->get('mime_param_folding'); $MAIL_MIME->addAttachment($file, $ctype, $attachment['name'], $attachment['data'] ? false : true, $ctype == 'message/rfc822' ? '8bit' : 'base64', 'attachment', $attachment['charset'], '', '', $folding ? 'quoted-printable' : NULL, $folding == 2 ? 'quoted-printable' : NULL, '', RCUBE_CHARSET ); } } } // compose PGP/Mime message if ($pgp_mime) { $MAIL_MIME->addAttachment(new Mail_mimePart('Version: 1', array( 'content_type' => 'application/pgp-encrypted', 'description' => 'PGP/MIME version identification', ))); $MAIL_MIME->addAttachment(new Mail_mimePart($pgp_mime, array( 'content_type' => 'application/octet-stream', 'filename' => 'encrypted.asc', 'disposition' => 'inline', ))); $MAIL_MIME->setContentType('multipart/encrypted', array('protocol' => 'application/pgp-encrypted')); $MAIL_MIME->setParam('preamble', 'This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)'); } // This hook allows to modify the message before send or save action $plugin = $RCMAIL->plugins->exec_hook('message_ready', array('message' => $MAIL_MIME)); $MAIL_MIME = $plugin['message']; // Deliver the message over SMTP if (!$savedraft && !$saveonly) { $sent = $SENDMAIL->deliver_message($MAIL_MIME); } // Save the message in Drafts/Sent $saved = $SENDMAIL->save_message($MAIL_MIME); // raise error if saving failed if (!$saved && $savedraft) { $RCMAIL->display_server_error('errorsaving'); // start the auto-save timer again $OUTPUT->command('auto_save_start'); $OUTPUT->send('iframe'); } $store_target = $SENDMAIL->options['store_target']; $store_folder = $SENDMAIL->options['store_folder']; // delete previous saved draft $drafts_mbox = $RCMAIL->config->get('drafts_mbox'); $old_id = rcube_utils::get_input_value('_draft_saveid', rcube_utils::INPUT_POST); if ($old_id && ($sent || $saved)) { $deleted = $RCMAIL->storage->delete_message($old_id, $drafts_mbox); // raise error if deletion of old draft failed if (!$deleted) { rcube::raise_error(array('code' => 800, 'type' => 'imap', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Could not delete message from $drafts_mbox"), true, false); } } if ($savedraft) { // remember new draft-uid ($saved could be an UID or true/false here) if ($saved && is_bool($saved)) { $index = $RCMAIL->storage->search_once($drafts_mbox, 'HEADER Message-ID ' . $message_id); $saved = @max($index->get()); } if ($saved) { $plugin = $RCMAIL->plugins->exec_hook('message_draftsaved', array('msgid' => $message_id, 'uid' => $saved, 'folder' => $store_target)); // display success $OUTPUT->show_message($plugin['message'] ?: 'messagesaved', 'confirmation'); // update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning $COMPOSE['param']['draft_uid'] = $plugin['uid']; $OUTPUT->command('set_draft_id', $plugin['uid']); $OUTPUT->command('compose_field_hash', true); } // start the auto-save timer again $OUTPUT->command('auto_save_start'); } else { // Collect folders which could contain the composed message, // we'll refresh the list if currently opened folder is one of them (#1490238) $folders = array(); if (!$saveonly) { if (in_array($COMPOSE['mode'], array('reply', 'forward', 'draft'))) { $folders[] = $COMPOSE['mailbox']; } if (!empty($COMPOSE['param']['draft_uid']) && $drafts_mbox) { $folders[] = $drafts_mbox; } } if ($store_folder && !$saved) { $params = $saveonly ? null : array('prefix' => true); $RCMAIL->display_server_error('errorsavingsent', null, null, $params); if ($saveonly) { $OUTPUT->send('iframe'); } $save_error = true; } else { $RCMAIL->plugins->exec_hook('attachments_cleanup', array('group' => $COMPOSE_ID)); $RCMAIL->session->remove('compose_data_' . $COMPOSE_ID); $_SESSION['last_compose_session'] = $COMPOSE_ID; $OUTPUT->command('remove_compose_data', $COMPOSE_ID); if ($store_folder) { $folders[] = $store_target; } } $msg = $RCMAIL->gettext($saveonly ? 'successfullysaved' : 'messagesent'); $OUTPUT->command('sent_successfully', 'confirmation', $msg, $folders, $save_error); } $OUTPUT->send('iframe');