Index: t3lib/config_default.php =================================================================== --- t3lib/config_default.php (revision 9982) +++ t3lib/config_default.php (working copy) @@ -595,7 +595,7 @@ $TYPO3_CONF_VARS['SC_OPTIONS']['errors']['exceptionalErrors'] = $TYPO3_CONF_VARS['SYS']['exceptionalErrors']; // Mail sending via Swift Mailer -$TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/utility/class.t3lib_utility_mail.php']['substituteMailDelivery'][] = 'tx_t3lib_mail_hooks->sendMail'; +$TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/utility/class.t3lib_utility_mail.php']['substituteMailDelivery'][] = 't3lib_mail_SwiftMailerAdapter'; // Turn error logging on/off. if (($displayErrors = intval($TYPO3_CONF_VARS['SYS']['displayErrors'])) != '-1') { Index: t3lib/core_autoload.php =================================================================== --- t3lib/core_autoload.php (revision 9982) +++ t3lib/core_autoload.php (working copy) @@ -127,6 +127,7 @@ 't3lib_formprotection_backendformprotection' => PATH_t3lib . 'formprotection/class.t3lib_formprotection_backendformprotection.php', 't3lib_formprotection_installtoolformprotection' => PATH_t3lib . 'formprotection/class.t3lib_formprotection_installtoolformprotection.php', 't3lib_localrecordlistgettablehook' => PATH_t3lib . 'interfaces/interface.t3lib_localrecordlistgettablehook.php', + 't3lib_mail_maileradapter' => PATH_t3lib . 'interfaces/interface.t3lib_mail_maileradapter.php', 't3lib_pageselect_getpagehook' => PATH_t3lib . 'interfaces/interface.t3lib_pageselect_getpagehook.php', 't3lib_pageselect_getrecordoverlayhook' => PATH_t3lib . 'interfaces/interface.t3lib_pageselect_getrecordoverlayhook.php', 't3lib_pageselect_getpageoverlayhook' => PATH_t3lib . 'interfaces/interface.t3lib_pageselect_getpageoverlayhook.php', @@ -138,7 +139,7 @@ 't3lib_mail_mboxtransport' => PATH_t3lib . 'mail/class.t3lib_mail_mboxtransport.php', 't3lib_mail_message' => PATH_t3lib . 'mail/class.t3lib_mail_message.php', 't3lib_mail_mailer' => PATH_t3lib . 'mail/class.t3lib_mail_mailer.php', - 'tx_t3lib_mail_hooks' => PATH_t3lib . 'mail/class.tx_t3lib_mail_hooks.php', + 't3lib_mail_swiftmaileradapter' => PATH_t3lib . 'mail/class.t3lib_mail_swiftmaileradapter.php', 't3lib_matchcondition_abstract' => PATH_t3lib . 'matchcondition/class.t3lib_matchcondition_abstract.php', 't3lib_matchcondition_backend' => PATH_t3lib . 'matchcondition/class.t3lib_matchcondition_backend.php', 't3lib_matchcondition_frontend' => PATH_t3lib . 'matchcondition/class.t3lib_matchcondition_frontend.php', Index: t3lib/interfaces/interface.t3lib_mail_maileradapter.php =================================================================== --- t3lib/interfaces/interface.t3lib_mail_maileradapter.php (revision 0) +++ t3lib/interfaces/interface.t3lib_mail_maileradapter.php (revision 0) @@ -0,0 +1,52 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * A copy is found in the textfile GPL.txt and important notices to the license + * from the author is found in LICENSE.txt distributed with these scripts. + * + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Mailer Adapter interface + * + * @author Ingo Renner + * @package TYPO3 + * @subpackage t3lib + */ +interface t3lib_mail_MailerAdapter { + + /** + * Mail sending function + * + * @param string $to Mail recipient. + * @param string $subject Mail subject. + * @param string $messageBody Mail body. + * @param array $additionalHeaders Additional mail headers. + * @param array $additionalParameters Additional mailer parameters. + * @param boolean $fakeSending Whether to fake sending or not, used in Unit Tests. + * @return boolean TRUE if the mail was successfully sent, FALSE otherwise. + */ + public function mail($to, $subject, $messageBody, $additionalHeaders = NULL, $additionalParameters = NULL, $fakeSending = FALSE); + +} + +?> \ No newline at end of file Index: t3lib/mail/class.t3lib_mail_swiftmaileradapter.php =================================================================== --- t3lib/mail/class.t3lib_mail_swiftmaileradapter.php (revision 9982) +++ t3lib/mail/class.t3lib_mail_swiftmaileradapter.php (working copy) @@ -1,230 +1,340 @@ - - * All rights reserved - * - * This script is part of the TYPO3 project. The TYPO3 project is - * free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The GNU General Public License can be found at - * http://www.gnu.org/copyleft/gpl.html. - * A copy is found in the textfile GPL.txt and important notices to the license - * from the author is found in LICENSE.txt distributed with these scripts. - * - * - * This script is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This copyright notice MUST APPEAR in all copies of the script! - ***************************************************************/ - -/** - * Hook subscriber for using Swift Mailer with the t3lib_utility_mail function - * - * $Id$ - * - * @author Jigal van Hemert - * @package TYPO3 - * @subpackage t3lib - */ -class tx_t3lib_mail_hooks { - - /** @var $mailerObject t3lib_mail_Mailer */ - protected $mailerObject; - - /** @var $messageObject Swift_Message */ - protected $messageObject; - - /** @var $messageHeaders Swift_Mime_HeaderSet */ - protected $messageHeaders; - - /** - * @param array $parameters Array with keys: 'to', 'subject', 'messageBody', 'additionalHeaders', 'additionalParameters' - * @param bool $fakeSending If set fake sending a mail - * @throws t3lib_exception - * @return bool - */ - public function sendMail(array $parameters = array(), $fakeSending = FALSE) { - - // report success for fake sending - if ($fakeSending === TRUE) { - return TRUE; - } - // create mailer object - $this->mailerObject = t3lib_div::makeInstance('t3lib_mail_Mailer'); - - // create message object - $this->messageObject = Swift_Message::newInstance($parameters['subject'], $parameters['messageBody']); - $this->messageObject->setTo($parameters['to']); - // handle additional headers - $headers = t3lib_div::trimExplode(LF, $parameters['additionalHeaders'], TRUE); - $this->messageHeaders = $this->messageObject->getHeaders(); - foreach ($headers as $header) { - list($headerName, $headerValue) = t3lib_div::trimExplode(':', $header, FALSE, 2); - $this->setHeader($headerName, $headerValue); - } - // handle additional parameters (force return path) - if (preg_match('/-f\s*(\S*?)/', $parameters['additionalParameters'], $matches)) { - $this->messageObject->setReturnPath($this->unEscapeShellArg($matches[1])); - } - // handle from: - $from = $this->messageObject->getFrom(); - if (count($from) > 0) { - reset($from); - list($fromAddress, $fromName) = each($from); - } else { - $fromAddress = $this->messageObject->getReturnPath(); - $fromName = $fromAddress; - } - if (strlen($fromAddress) == 0) { - $fromAddress = 'no-reply@example.org'; - $fromName = 'TYPO3 Installation'; - } - $this->messageObject->setFrom(array($fromAddress => $fromName)); - // send mail - $result = $this->mailerObject->send($this->messageObject); - - // report success/failure - return (bool) $result; - } - - /** - * Tries to undo the action by escapeshellarg() - * - * @param $escapedString String escaped by escapeshellarg() - * @return string String with escapeshellarg() action undone as best as possible - */ - protected function unEscapeShellArg($escapedString) { - if (TYPO3_OS === 'WIN') { - // on Windows double quotes are used and % signs are replaced by spaces - if (preg_match('/^"([^"]*)"$/', trim($escapedString), $matches)) { - $result = str_replace('\"', '"', $matches[1]); - // % signs are replaced with spaces, so they can't be recovered - } - } else { - // on Unix-like systems single quotes are escaped - if (preg_match('/^\'([^' . preg_quote('\'') . ']*)\'$/', trim($escapedString), $matches)) { - $result = str_replace('\\\'', '\'', $matches[1]); - } - } - return $result; - } - - /** - * Handles setting and replacing of mail headers - * - * @param $headerName Name of header - * @param $headerValue Value of header - * @return void - */ - protected function setHeader($headerName, $headerValue) { - if ($this->messageHeaders->has($headerName)) { - $header = $this->messageHeaders->get($headerName); - $headerType = $header->getFieldType(); - switch ($headerType) { - case Swift_Mime_Header::TYPE_TEXT: - $header->setValue($headerValue); - break; - case Swift_Mime_Header::TYPE_PARAMETERIZED: - $header->setValue($headerValue); - break; - case Swift_Mime_Header::TYPE_MAILBOX: - // mailbox headers look like: - // name , othermail@example.org, ... - // pattern matches cases with and without name - // comma is added to match each item in a comma separated list - preg_match_all('/,\s*([^<]+)(<([^>]*?)>)?/', ', ' . $headerValue, $addresses, PREG_SET_ORDER); - $addressList = array(); - foreach ($addresses as $address) { - if (!$address[2]) { - // item with name found ( name ) - if (t3lib_div::validEmail($address[1])) { - $addressList[] = $address[1]; - } - } else { - // item without name found ( email@example.org ) - if (t3lib_div::validEmail($address[3])) { - $addressList[$address[3]] = $address[1]; - } - } - } - if (count($addressList) > 0) { - $header->setNameAddresses($addressList); - } - break; - case Swift_Mime_Header::TYPE_DATE: - $header->setTimeStamp(strtotime($headerValue)); - break; - case Swift_Mime_Header::TYPE_ID: - // remove '<' and '>' from ID headers - $header->setId(trim($headerValue, '<>')); - break; - case Swift_Mime_Header::TYPE_PATH: - $header->setAddress($headerValue); - break; - } - // change value - } else { - switch ($headerName) { - // mailbox headers - case 'From': - case 'To': - case 'Cc': - case 'Bcc': - case 'Reply-To': - case 'Sender': - // mailbox headers look like: - // name , othermail@example.org, ... - // pattern matches cases with and without name - // comma is added to match each item in a comma separated list - preg_match_all('/,\s*(.*?)(<([^>]*?)>)?/', ', ' . $headerValue, $addresses, PREG_SET_ORDER); - $addressList = array(); - foreach ($addresses as $address) { - if ($address[2]) { - // item with name found ( name ) - if (t3lib_div::validEmail($address[1])) { - $addressList[] = $address[1]; - } - } else { - // item without name found ( email@example.org ) - if (t3lib_div::validEmail($address[3])) { - $addressList[$address[3]] = $address[1]; - } - } - } - if (count($addressList) > 0) { - $header->addMailboxHeader($headerName, $addressList); - } - break; - // date headers - case 'Date': - $this->messageHeaders->addDateHeader($headerName, strtotime($headerValue)); - break; - // ID headers - case 'Message-ID': - // remove '<' and '>' from ID headers - $this->messageHeaders->addIdHeader($headerName, trim($headerValue, '<>')); - // path headers - case 'Return-Path': - $this->messageHeaders->addPathHeader($headerName, $headerValue); - break; - // parameterized headers - case 'Content-Type': - case 'Content-Disposition': - $this->messageHeaders->addParameterizedHeader($headerName, $headerValue); - break; - // text headers - default: - $this->messageHeaders->addTextheader($headerName, $headerValue); - break; - } - } - } -} + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * A copy is found in the textfile GPL.txt and important notices to the license + * from the author is found in LICENSE.txt distributed with these scripts. + * + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Hook subscriber for using Swift Mailer with the t3lib_utility_mail function + * + * $Id$ + * + * @author Jigal van Hemert + * @package TYPO3 + * @subpackage t3lib + */ +class t3lib_mail_SwiftMailerAdapter implements t3lib_mail_MailerAdapter { + + /** @var $mailer t3lib_mail_Mailer */ + protected $mailer; + + /** @var $message Swift_Message */ + protected $message; + + /** @var $messageHeaders Swift_Mime_HeaderSet */ + protected $messageHeaders; + + /** @var string */ + protected $boundary = ''; + + /** + * Constructor + * + * @return void + */ + public function __construct() { + // create mailer object + $this->mailer = t3lib_div::makeInstance('t3lib_mail_Mailer'); + // create message object + $this->message = Swift_Message::newInstance(); + } + + /** + * Parses parts of the mail message and sends it with the Swift Mailer functions + * + * @param string $to Email address to send the message to + * @param string $subject Subject of mail message + * @param string $messageBody Raw body (may be multipart) + * @param array $additionalHeaders Additional mail headers + * @param array $additionalParameters Extra parameters for the mail() command + * @param bool $fakeSending If set fake sending a mail + * @throws t3lib_exception + * @return bool + */ + public function mail($to, $subject, $messageBody, $additionalHeaders = NULL, $additionalParameters = NULL, $fakeSending = FALSE) { + + // report success for fake sending + if ($fakeSending === TRUE) { + return TRUE; + } + $this->message->setSubject($subject); + $this->message->setTo($to); + // handle additional headers + $headers = t3lib_div::trimExplode(LF, $additionalHeaders, TRUE); + $this->messageHeaders = $this->message->getHeaders(); + foreach ($headers as $header) { + list($headerName, $headerValue) = t3lib_div::trimExplode(':', $header, FALSE, 2); + $this->setHeader($headerName, $headerValue); + } + // handle additional parameters (force return path) + if (preg_match('/-f\s*(\S*?)/', $additionalParameters, $matches)) { + $this->message->setReturnPath($this->unescapeShellArguments($matches[1])); + } + // handle from: + $this->fixSender(); + // handle message body + $this->setBody($messageBody); + // send mail + $result = $this->mailer->send($this->message); + + // report success/failure + return (bool) $result; + } + + /** + * Tries to undo the action by escapeshellarg() + * + * @param $escapedString String escaped by escapeshellarg() + * @return string String with escapeshellarg() action undone as best as possible + */ + protected function unescapeShellArguments($escapedString) { + if (TYPO3_OS === 'WIN') { + // on Windows double quotes are used and % signs are replaced by spaces + if (preg_match('/^"([^"]*)"$/', trim($escapedString), $matches)) { + $result = str_replace('\"', '"', $matches[1]); + // % signs are replaced with spaces, so they can't be recovered + } + } else { + // on Unix-like systems single quotes are escaped + if (preg_match('/^\'([^' . preg_quote('\'') . ']*)\'$/', trim($escapedString), $matches)) { + $result = str_replace('\\\'', '\'', $matches[1]); + } + } + return $result; + } + + /** + * Handles setting and replacing of mail headers + * + * @param $headerName Name of header + * @param $headerValue Value of header + * @return void + */ + protected function setHeader($headerName, $headerValue) { + // check for boundary in headers + if (preg_match('/^boundary="(.*)"$/', $headerName, $matches) > 0) { + $this->boundary = $matches[1]; + return; + } + // process other, real headers + if ($this->messageHeaders->has($headerName)) { + $header = $this->messageHeaders->get($headerName); + $headerType = $header->getFieldType(); + switch ($headerType) { + case Swift_Mime_Header::TYPE_TEXT: + $header->setValue($headerValue); + break; + case Swift_Mime_Header::TYPE_PARAMETERIZED: + $header->setValue(rtrim($headerValue, ';')); + break; + case Swift_Mime_Header::TYPE_MAILBOX: + $addressList = $this->parseAddresses($headerValue); + if (count($addressList) > 0) { + $header->setNameAddresses($addressList); + } + break; + case Swift_Mime_Header::TYPE_DATE: + $header->setTimeStamp(strtotime($headerValue)); + break; + case Swift_Mime_Header::TYPE_ID: + // remove '<' and '>' from ID headers + $header->setId(trim($headerValue, '<>')); + break; + case Swift_Mime_Header::TYPE_PATH: + $header->setAddress($headerValue); + break; + } + // change value + } else { + switch ($headerName) { + // mailbox headers + case 'From': + case 'To': + case 'Cc': + case 'Bcc': + case 'Reply-To': + case 'Sender': + $addressList = $this->parseAddresses($headerValue); + if (count($addressList) > 0) { + $header->addMailboxHeader($headerName, $addressList); + } + break; + // date headers + case 'Date': + $this->messageHeaders->addDateHeader($headerName, strtotime($headerValue)); + break; + // ID headers + case 'Message-ID': + // remove '<' and '>' from ID headers + $this->messageHeaders->addIdHeader($headerName, trim($headerValue, '<>')); + // path headers + case 'Return-Path': + $this->messageHeaders->addPathHeader($headerName, $headerValue); + break; + // parameterized headers + case 'Content-Type': + case 'Content-Disposition': + $this->messageHeaders->addParameterizedHeader($headerName, rtrim($headerValue, ';')); + break; + // text headers + default: + $this->messageHeaders->addTextheader($headerName, $headerValue); + break; + } + } + } + + /** + * Sets body of mail message. Handles multi-part and single part messages. Encoded body parts are decoded prior to adding + * them to the message object. + * + * @param string $body Raw body, may be multi-part + * @return void + */ + protected function setBody($body) { + if ($this->boundary) { + // handle multi-part + $bodyParts = preg_split('/--' . preg_quote($this->boundary) . '(--)?/m', $body, NULL, PREG_SPLIT_NO_EMPTY); + foreach ($bodyParts as $bodyPart) { + // skip empty parts + if (trim($bodyPart) == '') { + continue; + } + // keep leading white space when exploding the text + $lines = explode(LF, $bodyPart); + // set defaults for this part + $encoding = ''; + $charset = 'utf-8'; + $contentType = 'text/plain'; + // skip intro messages + if (trim($lines[0]) == 'This is a multi-part message in MIME format.') { + continue; + } + // first line is empty leftover from splitting + array_shift($lines); + while (count($lines) > 0) { + $line = array_shift($lines); + if (preg_match('/^content-type:(.*);( charset=(.*))?$/i', $line, $matches)) { + $contentType = trim($matches[1]); + if ($matches[2]) { + $charset = trim($matches[3]); + } + } else if (preg_match('/^content-transfer-encoding:(.*)$/i', $line, $matches)) { + $encoding = trim($matches[1]); + } else if (strlen(trim($line)) == 0) { + // empty line before actual content of this part + break; + } + } + // use rest of part as body, but reverse encoding first + $bodyPart = $this->decode(implode(LF, $lines), $encoding); + $this->message->addPart($bodyPart, $contentType, $charset); + } + } else { + // Handle single body + // The headers have already been set, so use header information + $contentType = $this->message->getContentType(); + $charset = $this->message->getCharset(); + $encoding = $this->message->getEncoder(); + // reverse encoding and set body + $rawBody = $this->decode($body, $encoding); + $this->message->setBody($rawBody, $contentType, $charset); + } + } + + /** + * Reverts encoding of body text + * + * @param string $text Body text to be decoded + * @param string $encoding Encoding type to be reverted + * @return string Decoded message body + */ + protected function decode($text, $encoding) { + $result = $text; + switch ($encoding) { + case 'quoted-printable': + $result = quoted_printable_decode($text); + break; + case 'base64': + $result = base64_decode($text); + break; + } + return $result; + } + + /** + * Parses mailbox headers and turns them into an array. + * + * Mailbox headers are a comma separated list of 'name ]*?)>)?/', ', ' . $rawAddresses, $addresses, PREG_SET_ORDER); + $addressList = array(); + foreach ($addresses as $address) { + if ($address[2]) { + // item with name found ( name ) + if (t3lib_div::validEmail($address[1])) { + $addressList[] = $address[1]; + } + } else { + // item without name found ( email@example.org ) + if (t3lib_div::validEmail($address[3])) { + $addressList[$address[3]] = trim($address[1], "\n\r\t\0\x0B \""); + } + } + } + return $addressList; + } + + /** + * Makes sure there is a correct sender set. + * + * If there is no from header the returnpath will be used. If that also fails a fake address will be used to make sure + * Swift Mailer will be able to send the message. Some SMTP server will not accept mail messages without a valid sender. + * + * @return void + */ + protected function fixSender() { + $from = $this->message->getFrom(); + if (count($from) > 0) { + reset($from); + list($fromAddress, $fromName) = each($from); + } else { + $fromAddress = $this->message->getReturnPath(); + $fromName = $fromAddress; + } + if (strlen($fromAddress) == 0) { + $fromAddress = 'no-reply@example.org'; + $fromName = 'TYPO3 CMS'; + } + $this->message->setFrom(array($fromAddress => $fromName)); + } +} Index: t3lib/mail/class.tx_t3lib_mail_hooks.php =================================================================== --- t3lib/mail/class.tx_t3lib_mail_hooks.php (revision 9982) +++ t3lib/mail/class.tx_t3lib_mail_hooks.php (working copy) @@ -1,230 +0,0 @@ - - * All rights reserved - * - * This script is part of the TYPO3 project. The TYPO3 project is - * free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The GNU General Public License can be found at - * http://www.gnu.org/copyleft/gpl.html. - * A copy is found in the textfile GPL.txt and important notices to the license - * from the author is found in LICENSE.txt distributed with these scripts. - * - * - * This script is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This copyright notice MUST APPEAR in all copies of the script! - ***************************************************************/ - -/** - * Hook subscriber for using Swift Mailer with the t3lib_utility_mail function - * - * $Id$ - * - * @author Jigal van Hemert - * @package TYPO3 - * @subpackage t3lib - */ -class tx_t3lib_mail_hooks { - - /** @var $mailerObject t3lib_mail_Mailer */ - protected $mailerObject; - - /** @var $messageObject Swift_Message */ - protected $messageObject; - - /** @var $messageHeaders Swift_Mime_HeaderSet */ - protected $messageHeaders; - - /** - * @param array $parameters Array with keys: 'to', 'subject', 'messageBody', 'additionalHeaders', 'additionalParameters' - * @param bool $fakeSending If set fake sending a mail - * @throws t3lib_exception - * @return bool - */ - public function sendMail(array $parameters = array(), $fakeSending = FALSE) { - - // report success for fake sending - if ($fakeSending === TRUE) { - return TRUE; - } - // create mailer object - $this->mailerObject = t3lib_div::makeInstance('t3lib_mail_Mailer'); - - // create message object - $this->messageObject = Swift_Message::newInstance($parameters['subject'], $parameters['messageBody']); - $this->messageObject->setTo($parameters['to']); - // handle additional headers - $headers = t3lib_div::trimExplode(LF, $parameters['additionalHeaders'], TRUE); - $this->messageHeaders = $this->messageObject->getHeaders(); - foreach ($headers as $header) { - list($headerName, $headerValue) = t3lib_div::trimExplode(':', $header, FALSE, 2); - $this->setHeader($headerName, $headerValue); - } - // handle additional parameters (force return path) - if (preg_match('/-f\s*(\S*?)/', $parameters['additionalParameters'], $matches)) { - $this->messageObject->setReturnPath($this->unEscapeShellArg($matches[1])); - } - // handle from: - $from = $this->messageObject->getFrom(); - if (count($from) > 0) { - reset($from); - list($fromAddress, $fromName) = each($from); - } else { - $fromAddress = $this->messageObject->getReturnPath(); - $fromName = $fromAddress; - } - if (strlen($fromAddress) == 0) { - $fromAddress = 'no-reply@example.org'; - $fromName = 'TYPO3 Installation'; - } - $this->messageObject->setFrom(array($fromAddress => $fromName)); - // send mail - $result = $this->mailerObject->send($this->messageObject); - - // report success/failure - return (bool) $result; - } - - /** - * Tries to undo the action by escapeshellarg() - * - * @param $escapedString String escaped by escapeshellarg() - * @return string String with escapeshellarg() action undone as best as possible - */ - protected function unEscapeShellArg($escapedString) { - if (TYPO3_OS === 'WIN') { - // on Windows double quotes are used and % signs are replaced by spaces - if (preg_match('/^"([^"]*)"$/', trim($escapedString), $matches)) { - $result = str_replace('\"', '"', $matches[1]); - // % signs are replaced with spaces, so they can't be recovered - } - } else { - // on Unix-like systems single quotes are escaped - if (preg_match('/^\'([^' . preg_quote('\'') . ']*)\'$/', trim($escapedString), $matches)) { - $result = str_replace('\\\'', '\'', $matches[1]); - } - } - return $result; - } - - /** - * Handles setting and replacing of mail headers - * - * @param $headerName Name of header - * @param $headerValue Value of header - * @return void - */ - protected function setHeader($headerName, $headerValue) { - if ($this->messageHeaders->has($headerName)) { - $header = $this->messageHeaders->get($headerName); - $headerType = $header->getFieldType(); - switch ($headerType) { - case Swift_Mime_Header::TYPE_TEXT: - $header->setValue($headerValue); - break; - case Swift_Mime_Header::TYPE_PARAMETERIZED: - $header->setValue($headerValue); - break; - case Swift_Mime_Header::TYPE_MAILBOX: - // mailbox headers look like: - // name , othermail@example.org, ... - // pattern matches cases with and without name - // comma is added to match each item in a comma separated list - preg_match_all('/,\s*([^<]+)(<([^>]*?)>)?/', ', ' . $headerValue, $addresses, PREG_SET_ORDER); - $addressList = array(); - foreach ($addresses as $address) { - if (!$address[2]) { - // item with name found ( name ) - if (t3lib_div::validEmail($address[1])) { - $addressList[] = $address[1]; - } - } else { - // item without name found ( email@example.org ) - if (t3lib_div::validEmail($address[3])) { - $addressList[$address[3]] = $address[1]; - } - } - } - if (count($addressList) > 0) { - $header->setNameAddresses($addressList); - } - break; - case Swift_Mime_Header::TYPE_DATE: - $header->setTimeStamp(strtotime($headerValue)); - break; - case Swift_Mime_Header::TYPE_ID: - // remove '<' and '>' from ID headers - $header->setId(trim($headerValue, '<>')); - break; - case Swift_Mime_Header::TYPE_PATH: - $header->setAddress($headerValue); - break; - } - // change value - } else { - switch ($headerName) { - // mailbox headers - case 'From': - case 'To': - case 'Cc': - case 'Bcc': - case 'Reply-To': - case 'Sender': - // mailbox headers look like: - // name , othermail@example.org, ... - // pattern matches cases with and without name - // comma is added to match each item in a comma separated list - preg_match_all('/,\s*(.*?)(<([^>]*?)>)?/', ', ' . $headerValue, $addresses, PREG_SET_ORDER); - $addressList = array(); - foreach ($addresses as $address) { - if ($address[2]) { - // item with name found ( name ) - if (t3lib_div::validEmail($address[1])) { - $addressList[] = $address[1]; - } - } else { - // item without name found ( email@example.org ) - if (t3lib_div::validEmail($address[3])) { - $addressList[$address[3]] = $address[1]; - } - } - } - if (count($addressList) > 0) { - $header->addMailboxHeader($headerName, $addressList); - } - break; - // date headers - case 'Date': - $this->messageHeaders->addDateHeader($headerName, strtotime($headerValue)); - break; - // ID headers - case 'Message-ID': - // remove '<' and '>' from ID headers - $this->messageHeaders->addIdHeader($headerName, trim($headerValue, '<>')); - // path headers - case 'Return-Path': - $this->messageHeaders->addPathHeader($headerName, $headerValue); - break; - // parameterized headers - case 'Content-Type': - case 'Content-Disposition': - $this->messageHeaders->addParameterizedHeader($headerName, $headerValue); - break; - // text headers - default: - $this->messageHeaders->addTextheader($headerName, $headerValue); - break; - } - } - } -} Index: t3lib/utility/class.t3lib_utility_mail.php =================================================================== --- t3lib/utility/class.t3lib_utility_mail.php (revision 9982) +++ t3lib/utility/class.t3lib_utility_mail.php (working copy) @@ -62,8 +62,28 @@ 'additionalParameters' => $additionalParameters, ); $fakeThis = FALSE; - foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/utility/class.t3lib_utility_mail.php']['substituteMailDelivery'] as $hookMethod) { - $success = $success && t3lib_div::callUserFunction($hookMethod, $parameters, $fakeThis); + foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/utility/class.t3lib_utility_mail.php']['substituteMailDelivery'] as $hookSubscriber) { + $hookSubscriberContainsArrow = strpos($hookSubscriber, '->'); + + if ($hookSubscriberContainsArrow !== FALSE) { + // deprecated, remove in TYPO3 4.7 + t3lib_div::deprecationLog( + 'The usage of user function notation for the substituteMailDelivery hook is deprecated, + use the t3lib_mail_MailerAdapter interface instead.' + ); + $success = $success && t3lib_div::callUserFunction($hookSubscriber, $parameters, $fakeThis); + } else { + $mailerAdapter = t3lib_div::makeInstance($hookSubscriber); + if ($mailerAdapter instanceof t3lib_mail_MailerAdapter) { + $success = $success && $mailerAdapter->mail($to, $subject, $messageBody, $additionalHeaders, $additionalParameters, $fakeThis); + } else { + throw new RuntimeException( + $hookSubscriber . ' is not an implementation of t3lib_mail_MailerAdapter, + but must implement that interface to be used in the substituteMailDelivery hook.', + 1294062286 + ); + } + } } } else { if (t3lib_utility_PhpOptions::isSafeModeEnabled() && !is_null($additionalParameters)) {