Index: trunk/core/kernel/utility/email_send.php =================================================================== diff -u -N --- trunk/core/kernel/utility/email_send.php (revision 8402) +++ trunk/core/kernel/utility/email_send.php (revision 0) @@ -1,1968 +0,0 @@ -guessOptions = Array ( - 'attachments' => Array(), - 'inline_attachments' => Array (), - 'text_part' => false, - 'html_part' => false, - ); - - // read SMTP server connection params from config - $smtp_mapping = Array ('server' => 'Smtp_Server', 'port' => 'Smtp_Port'); - if ($this->Application->ConfigValue('Smtp_Authenticate')) { - $smtp_mapping['username'] = 'Smtp_User'; - $smtp_mapping['password'] = 'Smtp_Pass'; - } - - foreach ($smtp_mapping as $smtp_name => $config_name) { - $this->smtpParams[$smtp_name] = $this->Application->ConfigValue($config_name); - } - $this->smtpParams['use_auth'] = isset($this->smtpParams['username']) ? true : false; - $this->smtpParams['localhost'] = 'localhost'; // The value to give when sending EHLO or HELO. - - $this->sendMethod = $this->smtpParams['server'] && $this->smtpParams['port'] ? 'SMTP' : 'Mail'; - - if ($this->sendMethod == 'SMTP') { - // create connection object if we will use SMTP - $this->smtpSocket =& $this->Application->makeClass('Socket'); - } - - $this->SetCharset(null, true); - } - - - /** - * Returns new message id header by sender's email address - * - * @param string $email_address email address - * @return string - */ - function GenerateMessageID($email_address) - { - list ($micros, $seconds) = explode(' ', microtime()); - list ($user, $domain) = explode('@', $email_address, 2); - - $message_id = strftime('%Y%m%d%H%M%S', $seconds).substr($micros, 1, 5).'.'.preg_replace('/[^A-Za-z]+/', '-', $user).'@'.$domain; - - $this->SetHeader('Message-ID', '<'.$message_id.'>'); - } - - /** - * Returns extension of given filename - * - * @param string $filename - * @return string - */ - function GetFilenameExtension($filename) - { - $last_dot = strrpos($filename, '.'); - return $last_dot !== false ? substr($filename, $last_dot + 1) : ''; - } - - /** - * Creates boundary for part by number (only if it's missing) - * - * @param int $part_number - * - */ - - function CreatePartBoundary($part_number) - { - $part =& $this->parts[$part_number]; - if (!isset($part['BOUNDARY'])) { - $part['BOUNDARY'] = md5(uniqid($part_number.time())); - - } - } - - /** - * Returns ready to use headers associative array of any message part by it's number - * - * @param int $part_number - * @return Array - */ - function GetPartHeaders($part_number) - { - $part =& $this->parts[$part_number]; - - if (!isset($part['Content-Type'])) { - return $this->SetError('MISSING_CONTENT_TYPE'); - } - - $full_type = strtolower($part['Content-Type']); - list ($type, $sub_type) = explode('/', $full_type); - - $headers['Content-Type'] = $full_type; - switch ($type) { - case 'text': - case 'image': - case 'audio': - case 'video': - case 'application': - case 'message': - // 1. update content-type header - if (isset($part['CHARSET'])) { - $headers['Content-Type'] .= '; charset='.$part['CHARSET']; - } - if (isset($part['NAME'])) { - $headers['Content-Type'] .= '; name="'.$part['NAME'].'"'; - } - - // 2. set content-transfer-encoding header - if (isset($part['Content-Transfer-Encoding'])) { - $headers['Content-Transfer-Encoding'] = $part['Content-Transfer-Encoding']; - } - - // 3. set content-disposition header - if (isset($part['DISPOSITION']) && $part['DISPOSITION']) { - $headers['Content-Disposition'] = $part['DISPOSITION']; - if (isset($part['NAME'])) { - $headers['Content-Disposition'] .= '; filename="'.$part['NAME'].'"'; - } - } - break; - - case 'multipart': - switch ($sub_type) { - case 'alternative': - case 'related': - case 'mixed': - case 'parallel': - $this->CreatePartBoundary($part_number); - $headers['Content-Type'] .= '; boundary="'.$part['BOUNDARY'].'"'; - break; - - default: - return $this->SetError('INVALID_MULTIPART_SUBTYPE', Array($sub_type)); - } - break; - - default: - return $this->SetError('INVALID_CONTENT_TYPE', Array($full_type)); - } - - // set content-id if any - if (isset($part['Content-ID'])) { - $headers['Content-ID'] = '<'.$part['Content-ID'].'>'; - } - - return $headers; - } - - function GetPartBody($part_number) - { - $part =& $this->parts[$part_number]; - - if (!isset($part['Content-Type'])) { - return $this->SetError('MISSING_CONTENT_TYPE'); - } - - $full_type = strtolower($part['Content-Type']); - list ($type, $sub_type) = explode('/', $full_type); - - $body = ''; - switch ($type) { - // compose text/binary content - case 'text': - case 'image': - case 'audio': - case 'video': - case 'application': - case 'message': - // 1. get content of part - if (isset($part['FILENAME'])) { - // content provided via absolute path to content containing file - $filename = $part['FILENAME']; - $file_size = filesize($filename); - - $body = file_get_contents($filename); - if ($body === false) { - return $this->SetError('FILE_PART_OPEN_ERROR', Array($filename)); - } - - $actual_size = strlen($body); - if (($file_size === false || $actual_size > $file_size) && get_magic_quotes_runtime()) { - $body = stripslashes($body); - } - - if ($file_size !== false && $actual_size != $file_size) { - return $this->SetError('FILE_PART_DATA_ERROR', Array($filename)); - } - } - else { - // content provided directly as one of part keys - if (!isset($part['DATA'])) { - return $this->SetError('FILE_PART_DATA_MISSING'); - } - $body =& $part['DATA']; - } - - // 2. get part transfer encoding - $encoding = isset($part['Content-Transfer-Encoding']) ? strtolower($part['Content-Transfer-Encoding']) : ''; - if (!in_array($encoding, Array ('', 'base64', 'quoted-printable', '7bit'))) { - return $this->SetError('INVALID_ENCODING', Array($encoding)); - } - - if ($encoding == 'base64') { - // split base64 encoded text by 76 symbols at line (MIME requirement) - $body = chunk_split( base64_encode($body) ); - } - break; - - case 'multipart': - // compose multipart message - switch ($sub_type) { - case 'alternative': - case 'related': - case 'mixed': - case 'parallel': - $this->CreatePartBoundary($part_number); - $boundary = $this->line_break.'--'.$part['BOUNDARY']; - - foreach ($part['PARTS'] as $multipart_number) { - $body .= $boundary.$this->line_break; - $part_headers = $this->GetPartHeaders($multipart_number); - if ($part_headers === false) { - // some of sub-part headers were invalid - return false; - } - - foreach ($part_headers as $header_name => $header_value) { - $body .= $header_name.': '.$header_value.$this->line_break; - } - - $part_body = $this->GetPartBody($multipart_number); - if ($part_body === false) { - // part body was invalid - return false; - } - - $body .= $this->line_break.$part_body; - } - $body .= $boundary.'--'.$this->line_break; - break; - - default: - return $this->SetError('INVALID_MULTIPART_SUBTYPE', Array($sub_type)); - } - break; - default: - return $this->SetError('INVALID_CONTENT_TYPE', Array($full_type)); - } - - return $body; - } - - /** - * Applies quoted-printable encoding to specified text - * - * @param string $text - * @param string $header_charset - * @param int $break_lines - * @return unknown - */ - function QuotedPrintableEncode($text, $header_charset = '', $break_lines = 1) - { - $ln = strlen($text); - $h = strlen($header_charset) > 0; - if ($h) { - $s = Array ( - '=' => 1, - '?' => 1, - '_' => 1, - '(' => 1, - ')' => 1, - '<' => 1, - '>' => 1, - '@' => 1, - ',' => 1, - ';' => 1, - '"' => 1, - '\\' => 1, - /* - '/' => 1, - '[' => 1, - ']' => 1, - ':' => 1, - '.' => 1, - */ - ); - - $b = $space = $break_lines = 0; - for ($i = 0; $i < $ln; $i++) { - if (isset($s[$text[$i]])) { - $b = 1; - break; - } - - switch ($o = ord($text[$i])) { - case 9: - case 32: - $space = $i + 1; - $b = 1; - break 2; - case 10: - case 13: - break 2; - default: - if ($o < 32 || $o > 127) { - $b = 1; - break 2; - } - } - } - - if($i == $ln) { - return $text; - } - - if ($space > 0) { - return substr($text, 0, $space).($space < $ln ? $this->QuotedPrintableEncode(substr($text, $space), $header_charset, 0) : ''); - } - } - - for ($w = $e = '', $n = 0, $l = 0, $i = 0; $i < $ln; $i++) { - $c = $text[$i]; - $o = ord($c); - $en = 0; - switch ($o) { - case 9: - case 32: - if (!$h) { - $w = $c; - $c = ''; - } - else { - if ($b) { - if ($o == 32) { - $c = '_'; - } - else { - $en = 1; - } - } - } - break; - case 10: - case 13: - if (strlen($w)) { - if ($break_lines && $l + 3 > 75) { - $e .= '='.$this->line_break; - $l = 0; - } - - $e .= sprintf('=%02X', ord($w)); - $l += 3; - $w = ''; - } - - $e .= $c; - if ($h) { - $e .= "\t"; - } - $l = 0; - continue 2; - case 46: - case 70: - case 102: - $en = (!$h && ($l == 0 || $l + 1 > 75)); - break; - default: - if ($o > 127 || $o < 32 || !strcmp($c, '=')) { - $en = 1; - } - elseif ($h && isset($s[$c])) { - $en = 1; - } - break; - } - - if (strlen($w)) { - if ($break_lines && $l + 1 > 75) { - $e .= '='.$this->line_break; - $l = 0; - } - $e .= $w; - $l++; - $w = ''; - } - - if (strlen($c)) { - if ($en) { - $c = sprintf('=%02X', $o); - $el = 3; - $n = 1; - $b = 1; - } - else { - $el = 1; - } - if ($break_lines && $l + $el > 75) { - $e .= '='.$this->line_break; - $l = 0; - } - $e .= $c; - $l += $el; - } - } - if (strlen($w)) { - if ($break_lines && $l + 3 > 75) { - $e .= '='.$this->line_break; - } - $e .= sprintf('=%02X', ord($w)); - } - - return $h && $n ? '=?'.$header_charset.'?q?'.$e.'?=' : $e; - } - - /** - * Sets message header + encodes is by quoted-printable using charset specified - * - * @param string $name - * @param string $value - * @param string $encoding_charset - */ - function SetHeader($name, $value, $encoding_charset = '') - { - if ($encoding_charset) { - // actually for headers base64 method may give shorter result - $value = $this->QuotedPrintableEncode($value, $encoding_charset); - } - - $this->headers[$name] = $value; - } - - /** - * Sets header + automatically encodes it using default charset - * - * @param string $name - * @param string $value - */ - function SetEncodedHeader($name, $value) - { - $this->SetHeader($name, $value, $this->charset); - } - - /** - * Sets header which value is email and username +autoencode - * - * @param string $header - * @param string $address - * @param string $name - */ - function SetEncodedEmailHeader($header, $address, $name) - { - $this->SetHeader($header, $this->QuotedPrintableEncode($name, $this->charset).' <'.$address.'>'); - } - - function SetMultipleEncodedEmailHeader($header, $addresses) - { - $value = ''; - foreach ($addresses as $name => $address) { - $value .= $this->QuotedPrintableEncode($name, $this->charset).' <'.$address.'>, '; - } - $value = preg_replace('/(.*),$/', '\\1', $value); - - $this->SetHeader($header, $value); - } - - - /** - * Adds new part to message and returns it's number - * - * @param Array $part_definition - * @param int $part_number number of new part - * @return int - */ - function AddPart(&$part_definition, $part_number = false) - { - $part_number = $part_number !== false ? $part_number : count($this->parts); - $this->parts[$part_number] =& $part_definition; - return $part_number; - } - - /** - * Returns text version of HTML document - * - * @param string $html - * @return string - */ - function ConvertToText($html) - { - $search = Array ( - "'(<\/td>.*)[\r\n]+(.*