You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
7.9 KiB
PHP
251 lines
7.9 KiB
PHP
<?php
|
|
|
|
/**
|
|
+-----------------------------------------------------------------------+
|
|
| program/steps/mail/bounce.inc |
|
|
| |
|
|
| This file is part of the Roundcube Webmail client |
|
|
| Copyright (C) 2005-2017, 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: |
|
|
| Bounce/resend an email message |
|
|
+-----------------------------------------------------------------------+
|
|
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
|
| Author: Aleksander Machniak <alec@alec.pl> |
|
|
+-----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/**
|
|
* Mail_mime wrapper to handle mail bounce
|
|
*
|
|
* @FIXME: For some reason this class definition
|
|
* cannot be put at the end of the file
|
|
*/
|
|
class rcmail_bounce_mail extends Mail_mime
|
|
{
|
|
/**
|
|
* Constructor function
|
|
*/
|
|
public function __construct($params = array())
|
|
{
|
|
// To make the code simpler always use delay_file_io=true
|
|
$params['delay_file_io'] = true;
|
|
$params['eol'] = "\r\n";
|
|
|
|
parent::__construct($params);
|
|
}
|
|
|
|
/**
|
|
* Returns/Sets message headers
|
|
*/
|
|
public function headers($headers = array(), $overwrite = false, $skip_content = false)
|
|
{
|
|
// headers() wrapper that returns Resent-Cc, Resent-Bcc instead of Cc,Bcc
|
|
// it's also called to re-add Resent-Bcc after it has been sent (to store in Sent)
|
|
|
|
if (array_key_exists('Bcc', $headers)) {
|
|
$this->build_params['bounce_headers']['Resent-Bcc'] = $headers['Bcc'];
|
|
}
|
|
|
|
foreach ($this->build_params['bounce_headers'] as $key => $val) {
|
|
$headers[str_replace('Resent-', '', $key)] = $val;
|
|
}
|
|
|
|
return $headers;
|
|
}
|
|
|
|
/**
|
|
* Returns all message headers as string
|
|
*/
|
|
public function txtHeaders($headers = array(), $overwrite = false, $skip_content = false)
|
|
{
|
|
// i.e. add Resent-* headers on top of the original message head
|
|
$this->init_message();
|
|
|
|
$result = array();
|
|
|
|
foreach ($this->build_params['bounce_headers'] as $name => $value) {
|
|
$key = str_replace('Resent-', '', $name);
|
|
|
|
// txtHeaders() can be used to unset Bcc header
|
|
if (array_key_exists($key, $headers)) {
|
|
$value = $headers[$key];
|
|
$this->build_params['bounce_headers']['Resent-'.$key] = $value;
|
|
}
|
|
|
|
if ($value) {
|
|
$result[] = "$name: $value";
|
|
}
|
|
}
|
|
|
|
$result = implode($this->build_params['eol'], $result);
|
|
|
|
if (strlen($this->bounce_head)) {
|
|
$result .= $this->build_params['eol'] . $this->bounce_head;
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Save the message body to a file (if delay_file_io=true)
|
|
*/
|
|
public function saveMessageBody($file, $params = null)
|
|
{
|
|
$this->init_message();
|
|
|
|
// this will be called only once, so let just move the file
|
|
rename($this->bounce_body, $file);
|
|
|
|
$this->bounce_head = null;
|
|
}
|
|
|
|
protected function init_message()
|
|
{
|
|
if ($this->bounce_head !== null) {
|
|
return;
|
|
}
|
|
|
|
$rcmail = rcmail::get_instance();
|
|
$storage = $rcmail->get_storage();
|
|
$message = $this->build_params['bounce_message'];
|
|
$temp_dir = unslashify($rcmail->config->get('temp_dir'));
|
|
$path = tempnam($temp_dir, 'rcmBounce');
|
|
|
|
// We'll write the body to the file and the headers to a variable
|
|
if ($fp = fopen($path, 'w')) {
|
|
stream_filter_register('bounce_source', 'rcmail_bounce_stream_filter');
|
|
stream_filter_append($fp, 'bounce_source');
|
|
|
|
// message part
|
|
if ($message->context) {
|
|
$message->get_part_body($message->context, false, 0, $fp);
|
|
}
|
|
// complete message
|
|
else {
|
|
$storage->set_folder($message->folder);
|
|
$storage->get_raw_body($message->uid, $fp);
|
|
}
|
|
|
|
fclose($fp);
|
|
|
|
$this->bounce_head = rcmail_bounce_stream_filter::$headers;
|
|
$this->bounce_body = $path;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stream filter to remove message headers from the streamed
|
|
* message source (and store them in a variable)
|
|
*/
|
|
class rcmail_bounce_stream_filter extends php_user_filter
|
|
{
|
|
public static $headers;
|
|
|
|
protected $in_body = false;
|
|
|
|
public function onCreate()
|
|
{
|
|
self::$headers = '';
|
|
}
|
|
|
|
public function filter($in, $out, &$consumed, $closing)
|
|
{
|
|
while ($bucket = stream_bucket_make_writeable($in)) {
|
|
if (!$this->in_body) {
|
|
self::$headers .= $bucket->data;
|
|
if (($pos = strpos(self::$headers, "\r\n\r\n")) === false) {
|
|
continue;
|
|
}
|
|
|
|
$bucket->data = substr(self::$headers, $pos + 4);
|
|
$bucket->datalen = strlen($bucket->data);
|
|
|
|
self::$headers = substr(self::$headers, 0, $pos);
|
|
$this->in_body = true;
|
|
}
|
|
|
|
$consumed += $bucket->datalen;
|
|
stream_bucket_append($out, $bucket);
|
|
}
|
|
|
|
return PSFS_PASS_ON;
|
|
}
|
|
}
|
|
|
|
|
|
$msg_uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GP);
|
|
$msg_folder = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GP, true);
|
|
$MESSAGE = new rcube_message($msg_uid, $msg_folder);
|
|
|
|
if (!$MESSAGE->headers) {
|
|
$OUTPUT->show_message('messageopenerror', 'error');
|
|
$OUTPUT->send('iframe');
|
|
}
|
|
|
|
// Display Bounce form
|
|
if (empty($_POST)) {
|
|
if (!empty($MESSAGE->headers->charset)) {
|
|
$RCMAIL->storage->set_charset($MESSAGE->headers->charset);
|
|
}
|
|
|
|
// Initialize helper class to build the UI
|
|
$SENDMAIL = new rcmail_sendmail(
|
|
array('mode' => rcmail_sendmail::MODE_FORWARD),
|
|
array('message' => $MESSAGE)
|
|
);
|
|
|
|
$OUTPUT->set_env('mailbox', $msg_folder);
|
|
$OUTPUT->set_env('uid', $msg_uid);
|
|
|
|
$OUTPUT->send('bounce');
|
|
}
|
|
|
|
// Initialize helper class to send the message
|
|
$SENDMAIL = new rcmail_sendmail(array('mode' => rcmail_sendmail::MODE_FORWARD), array(
|
|
'sendmail' => true,
|
|
'error_handler' => function() use ($OUTPUT) {
|
|
call_user_func_array(array($OUTPUT, 'show_message'), func_get_args());
|
|
$OUTPUT->send('iframe');
|
|
}
|
|
));
|
|
|
|
// Handle the form input
|
|
$input_headers = $SENDMAIL->headers_input();
|
|
|
|
// Set Resent-* headers, these will be added on top of the bounced message
|
|
$headers = array_filter(array(
|
|
// 'Received' => $input_headers['Received'],
|
|
'Resent-From' => $input_headers['From'],
|
|
'Resent-To' => $input_headers['To'],
|
|
'Resent-Cc' => $input_headers['Cc'],
|
|
'Resent-Bcc' => $input_headers['Bcc'],
|
|
'Resent-Date' => $input_headers['Date'],
|
|
'Resent-Message-ID' => $input_headers['Message-ID'],
|
|
));
|
|
|
|
// Create the bounce message
|
|
$BOUNCE = new rcmail_bounce_mail(array(
|
|
'bounce_message' => $MESSAGE,
|
|
'bounce_headers' => $headers,
|
|
));
|
|
|
|
// Send the bounce message
|
|
$SENDMAIL->deliver_message($BOUNCE);
|
|
|
|
// Save in Sent (if requested)
|
|
$saved = $SENDMAIL->save_message($BOUNCE);
|
|
|
|
if (!$saved && strlen($SENDMAIL->options['store_target'])) {
|
|
$RCMAIL->display_server_error('errorsaving');
|
|
}
|
|
|
|
$OUTPUT->show_message('messagesent', 'confirmation', null, false);
|
|
|
|
$OUTPUT->send('iframe');
|