<?php //$Id$
//Copyright (c) 2012-2015 Pierre Pronchery <khorben@defora.org>
//This file is part of DeforaOS Web DaPortal
//
//This program 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, version 3 of the License.
//
//This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.



namespace DaPortal;

use \Engine;
use \Mail_Mime;


@include_once('Mail.php');
@include_once('Mail/mime.php');


//Mail
class Mail
{
	//public
	//methods
	//static
	//useful
	//Mail::send
	static public function send(Engine $engine, $from, $to, $subject, $page,
			$headers = FALSE, $attachments = FALSE)
	{
		global $config;

		//obtain the sender
		if($from === FALSE)
			$from = $config->get('defaults::email', 'from');
		if($from === FALSE && isset($_SERVER['SERVER_ADMIN']))
			$from = $_SERVER['SERVER_ADMIN'];
		if($from === FALSE)
		{
			$pw = posix_getpwuid(posix_getuid());
			$from = $pw['name'];
		}
		//verify the parameters
		$error = 'Could not send e-mail (invalid parameters)';
		if(strpos($from, "\n") !== FALSE
				|| strpos($subject, "\n") !== FALSE)
			return $engine->log(LOG_ERR, $error);
		//verify the headers
		if(!is_array($headers))
			$headers = array();
		foreach($headers as $h => $v)
			if(strpos($h, "\n") !== FALSE
					|| strpos($v, "\n") !== FALSE)
				return $engine->log(LOG_ERR, $error);
		//obtain the charset
		if(($charset = $config->get('defaults', 'charset')) === FALSE)
			$charset = 'UTF-8';
		else
			$charset = strtoupper($charset);
		$headers['Content-Type'] = "text/plain; charset=$charset\n";
		//prepare the message
		if(($page = static::render($engine, $page, $headers,
				$attachments)) === FALSE)
			return FALSE;
		//send to each desired recipient
		if(is_array($to))
		{
			$ret = TRUE;
			foreach($to as $t)
				if(static::_sendTo($engine, $from, $t, $subject,
						$page, $headers, $attachments)
						=== FALSE)
					$ret = FALSE;
			return $ret;
		}
		return static::_sendTo($engine, $from, $to, $subject, $page,
				$headers, $attachments);
	}

	static protected function _sendTo(Engine $engine, $from, $to, $subject,
			$page, $headers, $attachments)
	{
		//verify the recipient
		$error = 'Could not send e-mail (invalid recipient)';
		if(strpos($to, "\n") !== FALSE)
			return $engine->log(LOG_ERR, $error);
		//assemble the headers
		$hdr = "From: $from\n";
		foreach($headers as $h => $v)
			$hdr .= "$h: $v\n";
		//send the message
		$error = 'Could not send e-mail';
		if(mail($to, $subject, $page, $hdr) === FALSE)
			return $engine->log(LOG_ERR, $error);
		$engine->log(LOG_DEBUG, 'e-mail sent to '.$to);
		return TRUE;
	}


	//protected
	//methods
	//static
	//useful
	//Mail::pageToHTML
	static protected function pageToHTML(Engine $engine, $page)
	{
		if($page instanceof \PageElement)
		{
			if(($format = \Format::attachDefault($engine,
					'text/html')) === FALSE)
				return FALSE;
			$format = clone $format;
			$format->set('standalone', TRUE);
			ob_start();
			$format->render($engine, $page);
			$str = ob_get_contents();
			ob_end_clean();
			return $str;
		}
		else if(is_string($page) && substr($page, 0, 1) == '<')
			//XXX assumes HTML
			return $page;
		return FALSE;
	}


	//Mail::pageToText
	static protected function pageToText(Engine $engine, $page)
	{
		if($page instanceof \PageElement)
		{
			if(($format = \Format::attachDefault($engine,
					'text/plain')) === FALSE)
				return FALSE;
			$format = clone $format;
			$format->set('wrap', 72);
			ob_start();
			$format->render($engine, $page);
			$str = ob_get_contents();
			ob_end_clean();
			return $str;
		}
		else if(is_string($page) && substr($page, 0, 1) == '<')
			//XXX assumes HTML
			return 'This e-mail message requires an HTML viewer.';
		return $page;
	}


	//Mail::render
	static protected function render(Engine $engine, $page, &$headers,
			$attachments = FALSE)
	{
		$class = 'Mail_Mime';

		if(($text = static::pageToText($engine, $page)) === FALSE)
			return FALSE;
		if(!class_exists($class))
		{
			$engine->log(LOG_WARNING, $class.': Class not found');
			return $text;
		}
		$mime = new $class(array('eol' => "\n",
			'text_charset' => 'UTF-8',
			'html_charset' => 'UTF-8'));
		static::_renderBody($engine, $mime, $text, $page);
		static::_renderAttachments($engine, $mime, $attachments);
		$ret = $mime->get();
		//XXX for Mail_Mime < 1.6.0 call get() before headers()
		static::_renderHeaders($mime, $headers);
		return $ret;
	}

	static protected function _renderAttachments(Engine $engine,
			Mail_Mime $mime, $attachments)
	{
		//attachments
		if(!is_array($attachments))
			$attachments = array();
		foreach($attachments as $filename => $data)
		{
			if(!is_string($filename) || !is_string($data))
				continue;
			$type = \Mime::getType($engine, $filename,
					'application/octet-stream');
			if(($e = $mime->addAttachment($data, $type, $filename,
					FALSE)) !== TRUE)
				$engine->log(LOG_ERR, $e->getMessage());
		}
	}

	static protected function _renderBody(Engine $engine, Mail_Mime $mime,
			$text, $page = FALSE)
	{
		//plain text content
		$mime->setTXTBody($text);
		//HTML contents
		if($page !== FALSE
				&& ($html = static::pageToHTML($engine,
					$page)) !== FALSE)
			static::_renderBodyHtml($engine, $mime, $html);
	}

	static protected function _renderBodyHtml(Engine $engine,
			Mail_Mime $mime, $html)
	{
		$jpeg = 'image/jpeg;base64,';
		$png = 'image/png;base64,';

		$xml = new \DOMDocument('1.0', 'UTF-8');
		if(version_compare(PHP_VERSION, '5.4.0') < 0)
		{
			//XXX for PHP < 5.4
			if($xml->loadHTML($html) === FALSE)
				return $engine->log(LOG_ERR,
						'Could not set the HTML body');
		}
		else if($xml->loadHTML($html, LIBXML_NOENT | LIBXML_NONET)
				=== FALSE)
			return $engine->log(LOG_ERR,
					'Could not set the HTML body');
		//convert in-line images for compatibility
		$images = $xml->getElementsByTagName('img');
		foreach($images as $img)
		{
			if(($a = $img->getAttribute('src')) === FALSE)
				continue;
			if(strncmp($a, 'data:', 5) != 0)
				continue;
			$a = substr($a, 5);
			if(strncmp($a, $jpeg, strlen($jpeg)) == 0)
			{
				$a = substr($a, strlen($jpeg));
				$a = base64_decode($a);
				static::_renderBodyHtmlImage($mime,
						$img, 'image/jpeg', $a);
			}
			else if(strncmp($a, $png, strlen($png)) == 0)
			{
				$a = substr($a, strlen($png));
				$a = base64_decode($a);
				static::_renderBodyHtmlImage($mime,
						$img, 'image/png', $a);
			}
		}
		if(($h = $xml->saveHTML()) !== FALSE)
			$html = $h;
		$mime->setHTMLBody($html);
		return TRUE;
	}

	static protected function _renderBodyHtmlImage(Mail_Mime $mime, $img,
			$type, $data)
	{
		$filename = uniqid();
		if($mime->addHTMLImage($data, 'image/jpeg', $filename, FALSE))
			$img->setAttribute('src', $filename);
	}

	static protected function _renderHeaders(Mail_Mime $mime, &$headers)
	{
		$hdrs = $mime->headers(array());
		foreach($hdrs as $h => $v)
			$headers[$h] = $v;
	}
}

?>
