From aa370627b211a51dc46891cfa4b6e3d2ef3e52db Mon Sep 17 00:00:00 2001 From: mcramer <m.cramer@pixcept.de> Date: Tue, 16 Jul 2013 10:45:17 -0400 Subject: [PATCH] - Fixed FS#2924 - the month will not set automatically in the autoresponder by click now Along with this fixed some display problems with the combo boxes introduced in 3.0.5. Some fields were not correctly displayed with the predefined values if value and text of the underlying option element differ. --- interface/lib/classes/ispcmail.inc.php | 212 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 190 insertions(+), 22 deletions(-) diff --git a/interface/lib/classes/ispcmail.inc.php b/interface/lib/classes/ispcmail.inc.php index f452c54..d49af96 100644 --- a/interface/lib/classes/ispcmail.inc.php +++ b/interface/lib/classes/ispcmail.inc.php @@ -54,6 +54,8 @@ private $mime_boundary; private $body = ''; private $_mail_sender = ''; + private $_sent_mails = 0; + private $user_agent = 'ISPConfig/3 (Mailer Class)'; /**#@-*/ /** @@ -95,6 +97,26 @@ * If you want to use tls/ssl specify it here */ private $smtp_crypt = ''; // tls or ssl + /** + * How many mails should be sent via one single smtp connection + */ + private $smtp_max_mails = 20; + /** + * Should the mail be signed + */ + private $sign_email = false; + /** + * The cert and key to use for email signing + */ + private $sign_key = ''; + private $sign_key_pass = ''; + private $sign_cert = ''; + private $sign_bundle = ''; + private $_is_signed = false; + /** + * get disposition notification + */ + private $notification = false; /**#@-*/ public function __construct($options = array()) { @@ -105,7 +127,8 @@ $this->attachments = array(); $this->headers['MIME-Version'] = '1.0'; - $this->setOptions($options); + $this->headers['User-Agent'] = $this->user_agent; + if(is_array($options) && count($options) > 0) $this->setOptions($options); } public function __destruct() { @@ -138,6 +161,10 @@ case 'smtp_pass': $this->smtp_pass = $value; break; + case 'smtp_max_mails': + $this->smtp_max_mails = intval($value); + if($this->smtp_max_mails < 1) $this->smtp_max_mails = 1; + break; case 'use_smtp': $this->use_smtp = ($value == true ? true : false); if($value == true) $this->_crlf = "\r\n"; @@ -146,14 +173,36 @@ if($value != 'ssl' && $value != 'tls') $value = ''; $this->smtp_crypt = $value; break; + case 'sign_email': + $this->sign_email = ($value == true ? true : false); + break; + case 'sign_key': + $this->sign_key = $value; + break; + case 'sign_key_pass': + $this->sign_key_pass = $value; + break; + case 'sign_cert': + $this->sign_cert = $value; + break; + case 'sign_bundle': + $this->sign_bundle = $value; + break; case 'mail_charset': $this->mail_charset = $value; + break; + case 'notify': + $this->notification = ($value == true ? true : false); break; } } + /** Detect the helo string if none given + * + */ private function detectHelo() { - if(isset($_SERVER['SERVER_NAME'])) $this->smtp_helo = $_SERVER['SERVER_NAME']; + if(isset($_SERVER['HTTP_HOST'])) $this->smtp_helo = $_SERVER['HTTP_HOST']; + elseif(isset($_SERVER['SERVER_NAME'])) $this->smtp_helo = $_SERVER['SERVER_NAME']; else $this->smtp_helo = php_uname('n'); if($this->smtp_helo == '') $this->smtp_helo = 'localhost'; } @@ -211,6 +260,9 @@ * @param string $value value to set in header field */ public function setHeader($header, $value) { + if(strtolower($header) == 'bcc') $header = 'Bcc'; + elseif(strtolower($header) == 'cc') $header = 'Cc'; + elseif(strtolower($header) == 'from') $header = 'From'; $this->headers["$header"] = $value; } @@ -224,7 +276,10 @@ * @return string header value */ public function getHeader($header) { - return $this->headers["$header"]; + if(strtolower($header) == 'bcc') $header = 'Bcc'; + elseif(strtolower($header) == 'cc') $header = 'Cc'; + elseif(strtolower($header) == 'from') $header = 'From'; + return (isset($this->headers["$header"]) ? $this->headers["$header"] : ''); } /** @@ -359,23 +414,30 @@ $this->body = "This is a multi-part message in MIME format.\n\n"; if($text) { - $this->body .= "--{$this->mime_boundary}\n" . + /*$this->body .= "--{$this->mime_boundary}\n" . "Content-Type:text/plain; charset=\"" . strtolower($this->mail_charset) . "\"\n" . - "Content-Transfer-Encoding: 7bit\n\n" . $this->text_part . "\n\n"; - } + "Content-Transfer-Encoding: 7bit\n\n" . $this->text_part . "\n\n";*/ + $this->body .= "--{$this->mime_boundary}\n" . + "Content-Type:text/plain; charset=\"UTF-8\"\n" . + "Content-Transfer-Encoding: 8bit\n\n" . $this->text_part . "\n\n"; + } if($html) { - $this->body .= "--{$this->mime_boundary}\n" . + /*$this->body .= "--{$this->mime_boundary}\n" . "Content-Type:text/html; charset=\"" . strtolower($this->mail_charset) . "\"\n" . - "Content-Transfer-Encoding: 7bit\n\n" . $this->html_part . "\n\n"; - } + "Content-Transfer-Encoding: 7bit\n\n" . $this->html_part . "\n\n";*/ + $this->body .= "--{$this->mime_boundary}\n" . + "Content-Type:text/html; charset=\"UTF-8\"\n" . + "Content-Transfer-Encoding: 8bit\n\n" . $this->html_part . "\n\n"; + } if($attach) { foreach($this->attachments as $att) { $this->body .= "--{$this->mime_boundary}\n" . "Content-Type: " . $att['type'] . ";\n" . " name=\"" . $att['filename'] . "\"\n" . - "Content-Transfer-Encoding: base64\n\n" . + "Content-Transfer-Encoding: base64\n" . + "Content-Disposition: attachment;\n\n" . chunk_split(base64_encode($att['content'])) . "\n\n"; } } @@ -388,7 +450,7 @@ if (isset($this->body)) { // Add message ID header - $message_id = sprintf('<%s.%s@%s>', base_convert(time(), 10, 36), base_convert(rand(), 10, 36), !empty($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']); + $message_id = sprintf('<%s.%s@%s>', base_convert(time(), 10, 36), base_convert(rand(), 10, 36), $this->smtp_helo != '' ? $this->smtp_helo : $this->detectHelo()); $this->headers['Message-ID'] = $message_id; return true; } else { @@ -397,16 +459,79 @@ } /** + * Function to sign an email body + */ + private function sign() { + if($this->sign_email == false || $this->sign_key == '' || $this->sign_cert == '') return false; + if(function_exists('openssl_pkcs7_sign') == false) return false; + + $tmpin = tempnam(sys_get_temp_dir(), 'sign'); + $tmpout = tempnam(sys_get_temp_dir(), 'sign'); + if(!file_exists($tmpin) || !is_writable($tmpin)) return false; + + file_put_contents($tmpin, 'Content-Type: ' . $this->getHeader('Content-Type') . "\n\n" . $this->body); + $tmpf_key = tempnam(sys_get_temp_dir(), 'sign'); + file_put_contents($tmpf_key, $this->sign_key); + $tmpf_cert = tempnam(sys_get_temp_dir(), 'sign'); + file_put_contents($tmpf_cert, $this->sign_cert); + if($this->sign_bundle != '') { + $tmpf_bundle = tempnam(sys_get_temp_dir(), 'sign'); + file_put_contents($tmpf_bundle, $this->sign_bundle); + openssl_pkcs7_sign($tmpin, $tmpout, 'file://' . realpath($tmpf_cert), array('file://' . realpath($tmpf_key), $this->sign_key_pass), array(), PKCS7_DETACHED, realpath($tmpf_bundle)); + } else { + openssl_pkcs7_sign($tmpin, $tmpout, 'file://' . realpath($tmpf_cert), array('file://' . realpath($tmpf_key), $this->sign_key_pass), array()); + } + unlink($tmpin); + unlink($tmpf_cert); + unlink($tmpf_key); + if(file_exists($tmpf_bundle)) unlink($tmpf_bundle); + + if(!file_exists($tmpout) || !is_readable($tmpout)) return false; + $this->body = file_get_contents($tmpout); + unlink($tmpout); + + unset($this->headers['Content-Type']); + unset($this->headers['MIME-Version']); + + $this->_is_signed = true; + } + + private function _char_to_hex($matches) { + return '=' . strtoupper(dechex(ord($matches[1]))); + } + + /** * Function to encode a header if necessary * according to RFC2047 * @access private */ private function _encodeHeader($input, $charset = 'ISO-8859-1') { - preg_match_all('/(\s?\w*[\x80-\xFF]+\w*\s?)/', $input, $matches); - foreach ($matches[1] as $value) { - $replacement = preg_replace('/([\x20\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value); - $input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input); - } + preg_match_all('/(\s?\w*[\x80-\xFF]+\w*\s?)/', $input, $matches); + foreach ($matches[1] as $value) { + $replacement = preg_replace_callback('/([\x20\x80-\xFF])/', array($this, '_char_to_hex'), $value); + $input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input); + } + + return $input; + } + + /** + * Function to encode the subject if necessary + * according to RFC2047 + * @access private + */ + private function _encodeSubject($input, $charset = 'ISO-8859-1') { + /* + if($charset == 'UTF-8' && function_exists('imap_8bit')) { + $input = "=?utf-8?Q?" . imap_8bit($input) . "?="; + } else { + preg_match_all('/(\s?\w*[\x80-\xFF]+\w*\s?)/', $input, $matches); + foreach ($matches[1] as $value) { + $replacement = preg_replace('/([\x20\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value); + $input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input); + } + }*/ + $input='=?UTF-8?B?'.base64_encode($input).'?='; return $input; } @@ -473,23 +598,30 @@ public function send($recipients) { if(!is_array($recipients)) $recipients = array($recipients); + if($this->use_smtp == true) $this->_crlf = "\r\n"; + else $this->_crlf = "\n"; + $this->create(); + if($this->sign_email == true) $this->sign(); $subject = ''; if (!empty($this->headers['Subject'])) { //$subject = $this->_encodeHeader($this->headers['Subject'], $this->mail_charset); $subject = $this->headers['Subject']; - $enc_subject = $this->_encodeHeader($subject, $this->mail_charset); + //$enc_subject = $this->_encodeHeader($subject, $this->mail_charset); + $enc_subject = $this->_encodeSubject($subject, $this->mail_charset); unset($this->headers['Subject']); } + + if($this->notification == true) $this->setHeader('Disposition-Notification-To', $this->getHeader('From')); unset($this->headers['To']); // always reset the To header to prevent from sending to multiple users at once $this->headers['Date'] = date('r'); //date('D, d M Y H:i:s O'); // Get flat representation of headers foreach ($this->headers as $name => $value) { - if(strtolower($name) == 'to') continue; // never add the To header + if(strtolower($name) == 'to' || strtolower($name) == 'cc' || strtolower($name) == 'bcc') continue; // never add the To header $headers[] = $name . ': ' . $this->_encodeHeader($value, $this->mail_charset); } @@ -499,6 +631,15 @@ if(!$result) return false; } foreach($recipients as $recipname => $recip) { + if($this->_sent_mails >= $this->smtp_max_mails) { + // close connection to smtp and reconnect + $this->_sent_mails = 0; + $this->_smtp_close(); + $result = $this->_smtp_login(); + if(!$result) return false; + } + $this->_sent_mails += 1; + $recipname = trim(str_replace('"', '', $recipname)); $recip = $this->_encodeHeader($recip, $this->mail_charset); $recipname = $this->_encodeHeader($recipname, $this->mail_charset); @@ -519,9 +660,11 @@ if($recipname && !is_numeric($recipname)) $this->setHeader('To', $recipname . ' <' . $recip . '>'); else $this->setHeader('To', $recip); - - $mail_content = 'To: ' . $this->getHeader('To') . $this->_crlf . 'Subject: ' . $enc_subject . $this->_crlf; - $mail_content .= implode($this->_crlf, $headers) . $this->_crlf . $this->_crlf . $this->body; + $mail_content = 'Subject: ' . $enc_subject . $this->_crlf; + $mail_content .= 'To: ' . $this->getHeader('To') . $this->_crlf; + if($this->getHeader('Bcc') != '') $mail_content .= 'Bcc: ' . $this->_encodeHeader($this->getHeader('Bcc'), $this->mail_charset) . $this->_crlf; + if($this->getHeader('Cc') != '') $mail_content .= 'Cc: ' . $this->_encodeHeader($this->getHeader('Cc'), $this->mail_charset) . $this->_crlf; + $mail_content .= implode($this->_crlf, $headers) . $this->_crlf . ($this->_is_signed == false ? $this->_crlf : '') . $this->body; fputs($this->_smtp_conn, $mail_content . $this->_crlf . '.' . $this->_crlf); $response = fgets($this->_smtp_conn, 515); @@ -530,6 +673,8 @@ $result = true; } } else { + if($this->getHeader('Bcc') != '') $headers[] = 'Bcc: ' . $this->_encodeHeader($this->getHeader('Bcc'), $this->mail_charset); + if($this->getHeader('Cc') != '') $headers[] = 'Cc: ' . $this->_encodeHeader($this->getHeader('Cc'), $this->mail_charset); $rec_string = ''; foreach($recipients as $recipname => $recip) { $recipname = trim(str_replace('"', '', $recipname)); @@ -539,7 +684,8 @@ else $rec_string .= $recip; } $to = $this->_encodeHeader($rec_string, $this->mail_charset); - $result = mail($to, $subject, $this->body, implode($this->_crlf, $headers)); + //$result = mail($to, $subject, $this->body, implode($this->_crlf, $headers)); + $result = mail($to, $enc_subject, $this->body, implode($this->_crlf, $headers)); } // Reset the subject in case mail is resent @@ -560,6 +706,28 @@ */ public function finish() { if($this->use_smtp == true) $this->_smtp_close(); + + $rand = md5(microtime()); + $this->mime_boundary = '==Multipart_Boundary_x' . $rand . 'x'; + + $this->headers = array(); + $this->attachments = array(); + $this->text_part = ''; + $this->html_part = ''; + + $this->headers['MIME-Version'] = '1.0'; + $this->headers['User-Agent'] = $this->user_agent; + + $this->smtp_helo = ''; + $this->smtp_host = ''; + $this->smtp_port = ''; + $this->smtp_user = ''; + $this->smtp_pass = ''; + $this->use_smtp = false; + $this->smtp_crypt = false; + $this->mail_charset = 'UTF-8'; + $this->_sent_mails = 0; + return; } } -- Gitblit v1.9.1