<?php // vim:ts=4:sw=4:noet
/*====================================================================== 
Copyright (C) 2006-2009, Walter Doekes
This file is part of KjwLib-php45.
 
KjwLib-php45 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 3 of the License, or 
(at your option) any later version. 

KjwLib-php45 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. 

You should have received a copy of the GNU General Public License 
along with KjwLib-php45.  If not, see <http://www.gnu.org/licenses/>. 
======================================================================*/

/**
 * Sends a simple plaintext mail, but adds a couple of important headers:
 * encoding, originating-ip (the requester), originating-site.
 * Assumes that subject and message are encoded in UTF8.
 *
 * @param $to Receiver, or receivers of the mail. Use double quotes around names!
 * @param $subject Subject of the email to be sent (encoded in US-ASCII or UTF-8).
 * @param $message Message to be sent.
 * @param $additional_headers (optional) Use an associative array! array('From'=>'"Myself" <my@self.tld>');
 * @param $additional_parameters (optional) Additional parameters to send to the program sending the mail.
 * @return Returns TRUE if the mail was successfully accepted for delivery, FALSE otherwise.
 *
 * @note Uses the KJW_MAIL_USE_LF_ONLY define to determine whether to send LF's or CRLF's (more correct, but
 *       produces double linefeeds on some systems).
 * @todo http://www.faqs.org/rfcs/rfc3676.html
 * @todo Merge with htmlMimeMail().
 */
function kjwmail_sendplain($to, $subject, $message, $additional_headers = null, $additional_parameters = '') {
	assert('$additional_headers === null || (is_array($additional_headers) && !isset($additional_headers["To"]))');

	// Clean up variables
	$addCr = defined('KJW_MAIL_USE_LF_ONLY') && !KJW_MAIL_USE_LF_ONLY;
	$host = str_replace(array("\x00", "\n", "\r", "<", ">"), '', @$_SERVER['HTTP_HOST']);
	if ($host == '')
		$host = 'localhost';
	$to = str_replace(array("\x00", "\n", "\r"), '', $to);
	$subject = kjwmail_encode_header(str_replace("\x00", '', $subject));
	$message = str_replace("\r\n", "\n", str_replace("\x00", '', $message));

	// Set standard headers
	$headers = array(
		'From' => '"' . ucfirst($host) . "\" <postmaster@$host>",
		'Content-Type' => 'text/plain; charset=UTF-8',
		'Content-Transfer-Encoding' => 'quoted-printable',
	);
	if (isset($_SERVER['REMOTE_ADDR']))
		$headers['X-Originating-IP'] = '[' . $_SERVER['REMOTE_ADDR'] . ']';
	if (isset($_SERVER['REQUEST_URI']))
		$headers['X-Originating-URL'] = 'http://' . $host . $_SERVER['REQUEST_URI'];
	if (isset($_SERVER['HTTP_REFERER']))
		$headers['X-Originating-URL-referer'] = $_SERVER['HTTP_REFERER'];
	if ($additional_headers !== null)
		$headers = array_merge($headers, $additional_headers); // Overwrite all existing keys with user supplied ones
	
	// Concatenate headers and encode headers and body
	$additional_headers = array();
	foreach ($headers as $k => $v) {
		assert('preg_match("/[A-Za-z0-9-]/", $k)');
		array_push($additional_headers, $k . ': ' . kjwmail_encode_header($v));
	}
	$message = preg_replace("/([\x80-\xff=])/e", "sprintf('=%02X',ord('$1'))", $message);
	if ($addCr) {
		$message = str_replace("\n", "\r\n", $message);
		$headers = implode("\r\n", $additional_headers);
	} else {
		$headers = implode("\n", $additional_headers);
	}

	// Send the mail
	return mail($to, $subject, $message, $headers, $additional_parameters);
}


/**
 * Encodes the string with Q-encoding if it contains characters below 0x20 or above 0x7f.
 * Does a bit of tricks to try and get the encoding correct if an email is embedded.
 * If you have '"a b c" <x@y.z>, "d e f" <u@v.w>' it will encode only "a b c" and "d e f".
 * Please make sure that you use the double quotes mentioned above. PHP or someone else might
 * include this-machine-host: 'a <b@localhost> c <x@y.z>'.
 *
 * @param $str The string to encode.
 * @return The encoded string.
 */
function kjwmail_encode_header($str) {
	$str = str_replace("\x00", '', $str);
	if (!preg_match("/[\x01-\x1f\x80-\xff]/", $str))
		return $str;
	if (strpos($str, '@') === false) // If there's no <email> in there, encode all
		return '=?UTF-8?Q?' . preg_replace("/([\x01-\x1f\x80-\xff _=?])/e", "'$1'==' '?'_':sprintf('=%02X',ord('$1'))", $str) . '?=';

	$header_parts = explode('@', $str);
	assert('sizeof($header_parts) > 1');
	
	// Do the edges
	foreach (array(0, sizeof($header_parts) - 1) as $i) {
		if ($i == 0)
			$e = strrpos($header_parts[$i], ' ');
		else
			$e = strpos($header_parts[$i], ' ');
		if ($e !== false) {
			if ($i != 0)
				++$e;
			$begin = substr($header_parts[$i], 0, $e);
			$end = substr($header_parts[$i], $e);
			if (preg_match("/[\x01-\x1f\x80-\xff]/", $begin)) {
				$begin = '=?UTF-8?Q?'
						. preg_replace("/([\x01-\x1f\x80-\xff _=?])/e", "'$1'==' '?'_':sprintf('=%02X',ord('$1'))", $begin) . '?=';
			}
			$header_parts[$i] = $begin . $end;
		}
	}

	// Do the center parts
	for ($i = 1; $i < sizeof($header_parts) - 1; ++$i) {
		$b = strpos($header_parts[$i], ' ');
		$e = strrpos($header_parts[$i], ' ');
		if ($b != $e && $b !== false) {
			++$b;
			$begin = substr($header_parts[$i], 0, $b);
			$mid = substr($header_parts[$i], $b, $e - $b);
			$end = substr($header_parts[$i], $e);
			if (preg_match("/[\x01-\x1f\x80-\xff]/", $mid)) {
				$mid = '=?UTF-8?Q?'
						. preg_replace("/([\x01-\x1f\x80-\xff _=?])/e", "'$1'==' '?'_':sprintf('=%02X',ord('$1'))", $mid) . '?=';
			}
			$header_parts[$i] = $begin . $mid . $end;
		}
	}

	// Concatenate them again
	$str = implode('@', $header_parts);
	// If we still have high ascii, leave it..
	return $str;
}