<?php
/*
This file is part of Thomas Bley's moregroupware webmail2/calendar2/admin2 module. (tb-mgw)

More information:
-----------------

Simple Groupware Solutions Thomas Bley
Fichtenstr. 23
Germany, 85640 Putzbrunn

Contact:
--------

info@simple-groupware.de

http://www.simple-groupware.de


Copyright 2002-2003 Thomas Bley
tb-mgw is distributed under the terms of the GNU General Public License 

tb-mgw 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.

tb-mgw 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 tb-mgw; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

// class_html_mime_mail
// Moregroupware.org

/***************************************
** Title.........: HTML Mime Mail class
** Version.......: 2.0.3
** Author........: Richard Heyes <richard@phpguru.org>
** Filename......: class.html.mime.mail.class
** Last changed..: 21 December 2001
** License.......: Free to use. If you find it useful
**                 though, feel free to buy me something
**                 from my wishlist :)
**                 http://www.amazon.co.uk/exec/obidos/wishlist/S8H2UOGMPZK6
***************************************/

require_once(WM2_INC_DIR.'mimepart.php');

class html_mime_mail{

	var $html;
	var $text;
	var $output;
	var $html_text;
	var $html_images;
	var $image_types;
	var $build_params;
	var $attachments;
	var $headers;

/***************************************
** Constructor function. Sets the headers
** if supplied.
***************************************/

	function html_mime_mail($headers = array()){

		/***************************************
        ** Make sure this is defined. This should
		** be \r\n, but due to many people having
		** trouble with that, it is by default \n
		** If you leave it as is, you will be breaking
		** quite a few standards.
        ***************************************/

		if(!defined('CRLF'))
			define('CRLF', "\n", TRUE);

		/***************************************
        ** Initialise some variables.
        ***************************************/

		$this->html_images	= array();
		$this->headers		= array();

		/***************************************
        ** If you want the auto load functionality
		** to find other image/file types, add the
		** extension and content type here.
        ***************************************/

		$this->image_types = array(
									'gif'	=> 'image/gif',
									'jpg'	=> 'image/jpeg',
									'jpeg'	=> 'image/jpeg',
									'jpe'	=> 'image/jpeg',
									'bmp'	=> 'image/bmp',
									'png'	=> 'image/png',
									'tif'	=> 'image/tiff',
									'tiff'	=> 'image/tiff',
									'swf'	=> 'application/x-shockwave-flash'
								  );

		/***************************************
        ** Set these up
        ***************************************/

		$this->build_params['html_encoding']	= 'quoted-printable';
		$this->build_params['text_encoding']	= '7bit';
		$this->build_params['html_charset']		= 'iso-8859-1';
		$this->build_params['text_charset']		= 'iso-8859-1';
		$this->build_params['text_wrap']		= 998;

		/***************************************
        ** Make sure the MIME version header is first.
        ***************************************/

		$this->headers[] = 'MIME-Version: 1.0';

		foreach($headers as $value){
			if(!empty($value))
				$this->headers[] = $value;
		}
	}

/***************************************
** This function will read a file in
** from a supplied filename and return
** it. This can then be given as the first
** argument of the the functions
** add_html_image() or add_attachment().
***************************************/

	function get_file($filename){

		$return = '';
		if($fp = fopen($filename, 'rb')){
			while(!feof($fp)){
				$return .= fread($fp, 1024);
			}
			fclose($fp);
			return $return;

		}else{
			return FALSE;
		}
	}

/***************************************
** Function for extracting images from
** html source. This function will look
** through the html code supplied by add_html()
** and find any file that ends in one of the
** extensions defined in $obj->image_types.
** If the file exists it will read it in and
** embed it, (not an attachment).
**
** Function contributed by Dan Allen
***************************************/

	function find_html_images($images_dir) {

		// Build the list of image extensions
		while(list($key,) = each($this->image_types))
			$extensions[] = $key;

		preg_match_all('/"([^"]+\.('.implode('|', $extensions).'))"/Ui', $this->html, $images);

		for($i=0; $i<count($images[1]); $i++){
			if(file_exists($images_dir.$images[1][$i])){
				$html_images[] = $images[1][$i];
				$this->html = str_replace($images[1][$i], basename($images[1][$i]), $this->html);
			}
		}

		if(!empty($html_images)){

			// If duplicate images are embedded, they may show up as attachments, so remove them.
			$html_images = array_unique($html_images);
			sort($html_images);
	
			for($i=0; $i<count($html_images); $i++){
				if($image = $this->get_file($images_dir.$html_images[$i])){
					$content_type = $this->image_types[substr($html_images[$i], strrpos($html_images[$i], '.') + 1)];
					$this->add_html_image($image, basename($html_images[$i]), $content_type);
				}
			}
		}
	}

/***************************************
** Adds plain text. Use this function
** when NOT sending html email
***************************************/

	function add_text($text = ''){
		$this->text = $text;
	}

/***************************************
** Adds a html part to the mail.
** Also replaces image names with
** content-id's.
***************************************/

	function add_html($html, $text = NULL, $images_dir = NULL){

		$this->html			= $html;
		$this->html_text	= $text;

		if(isset($images_dir))
			$this->find_html_images($images_dir);
	}

/***************************************
** Adds an image to the list of embedded
** images.
***************************************/

	function add_html_image($file, $name = '', $c_type='application/octet-stream'){
		$this->html_images[] = array(
										'body'   => $file,
										'name'   => $name,
										'c_type' => $c_type,
										'cid'    => md5(uniqid(time()))
									);
	}


/***************************************
** Adds a file to the list of attachments.
***************************************/

	function add_attachment($file, $name = '', $c_type='application/octet-stream', $encoding = 'base64', $dispo = 'attachment'){
		$this->attachments[] = array(
									'body'		=> $file,
									'name'		=> $name,
									'c_type'	=> $c_type,
									'encoding'	=> $encoding,
									'dispo'		=> $dispo
								  );
	}

/***************************************
** Adds a text subpart to a mime_part object
***************************************/

	function &add_text_part(&$obj, $text){

		$params['content_type'] = 'text/plain';
		$params['encoding']     = $this->build_params['text_encoding'];
		$params['charset']      = $this->build_params['text_charset'];
		if(is_object($obj)){
			return $obj->addSubpart($text, $params);
		}else{
			return new Mail_mimePart($text, $params);
		}
	}

/***************************************
** Adds a html subpart to a mime_part object
***************************************/

	function &add_html_part(&$obj){

		$params['content_type'] = 'text/html';
		$params['encoding']     = $this->build_params['html_encoding'];
		$params['charset']      = $this->build_params['html_charset'];
		if(is_object($obj)){
			return $obj->addSubpart($this->html, $params);
		}else{
			return new Mail_mimePart($this->html, $params);
		}
	}

/***************************************
** Starts a message with a mixed part
***************************************/

	function &add_mixed_part(){

		$params['content_type'] = 'multipart/mixed';
		return new Mail_mimePart('', $params);
	}

	function &add_mixed_report(){

		$params['content_type'] = 'multipart/report; report-type=disposition-notification';
		return new Mail_mimePart('', $params);
	}

/***************************************
** Adds an alternative part to a mime_part object
***************************************/

	function &add_alternative_part(&$obj){

		$params['content_type'] = 'multipart/alternative';
		if(is_object($obj)){
			return $obj->addSubpart('', $params);
		}else{
			return new Mail_mimePart('', $params);
		}
	}

/***************************************
** Adds a html subpart to a mime_part object
***************************************/

	function &add_related_part(&$obj){

		$params['content_type'] = 'multipart/related';
		if(is_object($obj)){
			return $obj->addSubpart('', $params);
		}else{
			return new Mail_mimePart('', $params);
		}
	}

/***************************************
** Adds an html image subpart to a mime_part object
***************************************/

	function &add_html_image_part(&$obj, $value){

		$params['content_type'] = $value['c_type'];
		$params['encoding']     = 'base64';
		$params['disposition']  = 'inline';
		$params['dfilename']    = $value['name'];
		$params['cid']          = $value['cid'];
		$obj->addSubpart($value['body'], $params);
	}

/***************************************
** Adds an attachment subpart to a mime_part object
***************************************/

	function &add_attachment_part(&$obj, $value){

		$params['content_type'] = $value['c_type'];
		$params['encoding']     = $value['encoding'];
		$params['disposition']  = $value['dispo'];
		if ($value['dispo']!="inline" && $value['dispo']!="") {
		$params['dfilename']    = $value['name'];
		}
		$obj->addSubpart($value['body'], $params);
	}

/***************************************
** Builds the multipart message from the
** list ($this->_parts). $params is an
** array of parameters that shape the building
** of the message. Currently supported are:
**
** $params['html_encoding'] - The type of encoding to use on html. Valid options are
**                            "7bit", "quoted-printable" or "base64" (all without quotes).
**                            7bit is EXPRESSLY NOT RECOMMENDED. Default is quoted-printable
** $params['text_encoding'] - The type of encoding to use on plain text Valid options are
**                            "7bit", "quoted-printable" or "base64" (all without quotes).
**                            Default is 7bit
** $params['text_wrap']     - The character count at which to wrap 7bit encoded data.
**                            Default this is 998.
** $params['html_charset']  - The character set to use for a html section.
**                            Default is iso-8859-1
** $params['text_charset']  - The character set to use for a text section.
**                          - Default is iso-8859-1
***************************************/

	function build_message($params = array()){

		if(count($params) > 0)
			while(list($key, $value) = each($params))
				$this->build_params[$key] = $value;

		if(!empty($this->html_images))
			foreach($this->html_images as $value)
				$this->html = str_replace($value['name'], 'cid:'.$value['cid'], $this->html);

		$null        = NULL;
		$attachments = !empty($this->attachments) ? TRUE : FALSE;
		$html_images = !empty($this->html_images) ? TRUE : FALSE;
		$html        = !empty($this->html)        ? TRUE : FALSE;
		$text        = isset($this->text)         ? TRUE : FALSE;

		switch(TRUE){
			case $text AND !$attachments:
				$message =& $this->add_text_part($null, $this->text);
				break;

			case !$text AND $attachments AND !$html:
				$message =& $this->add_mixed_part();

				for($i=0; $i<count($this->attachments); $i++)
					$this->add_attachment_part($message, $this->attachments[$i]);
				break;

			case $text AND $attachments:
			    $notification = false;
                $calendar = false;
				for($i=0; $i<count($this->attachments); $i++) {
                  if ($this->attachments[$i]["c_type"]=="text/calendar") {
                    $calendar = true;
                  }
                }
				for($i=0; $i<count($this->attachments); $i++) {
                  if ($this->attachments[$i]["c_type"]=="message/disposition-notification") {
                    $notification = true;
                  }
                }

				$message =& $this->add_mixed_part();
                if ($calendar) {
				  $message2 =& $this->add_alternative_part($message);
                  $this->add_text_part($message2, $this->text);
				  for($i=0; $i<count($this->attachments); $i++) {
				    if ($this->attachments[$i]["c_type"]=="text/calendar") {
					  $this->add_attachment_part($message2, $this->attachments[$i]);
				} else {
					  $this->add_attachment_part($message, $this->attachments[$i]);
                }
				  }
				} else {
				  if ($notification) $message =& $this->add_mixed_report();
  				    else $message =& $this->add_mixed_part();
                $this->add_text_part($message, $this->text);
				for($i=0; $i<count($this->attachments); $i++) {
                  $this->add_attachment_part($message, $this->attachments[$i]);
                }
                }
				break;
                
			case $html AND !$attachments AND !$html_images:
				if(!is_null($this->html_text)){
					$message =& $this->add_alternative_part($null);
					$this->add_text_part($message, $this->html_text);
					$this->add_html_part($message);
				}else{
					$message =& $this->add_html_part($null);
				}
				break;

			case $html AND !$attachments AND $html_images:
				if(!is_null($this->html_text)){
					$message =& $this->add_alternative_part($null);
					$this->add_text_part($message, $this->html_text);
					$related =& $this->add_related_part($message);
				}else{
					$message =& $this->add_related_part($null);
					$related =& $message;
				}
				$this->add_html_part($related);
				for($i=0; $i<count($this->html_images); $i++)
					$this->add_html_image_part($related, $this->html_images[$i]);
				break;

			case $html AND $attachments AND !$html_images:
                $calendar = false;
				for($i=0; $i<count($this->attachments); $i++) {
                  if ($this->attachments[$i]["c_type"]=="text/calendar") {
                    $calendar = true;
                  }
                }

				$message =& $this->add_mixed_part();
                if ($calendar) {
				  if(!is_null($this->html_text)){
					$alt =& $this->add_alternative_part($message);
					$this->add_text_part($alt, $this->html_text);
					$this->add_html_part($alt);
				    for($i=0; $i<count($this->attachments); $i++) {
				      if ($this->attachments[$i]["c_type"]=="text/calendar") {
					    $this->add_attachment_part($alt, $this->attachments[$i]);
					  } else {
					    $this->add_attachment_part($message, $this->attachments[$i]);
					  }
				    }
				  }else{
					$this->add_html_part($message);
				  }
				} else {
				if(!is_null($this->html_text)){
					$alt =& $this->add_alternative_part($message);
					$this->add_text_part($alt, $this->html_text);
					$this->add_html_part($alt);
				}else{
					$this->add_html_part($message);
				}
				  for($i=0; $i<count($this->attachments); $i++) {
					$this->add_attachment_part($message, $this->attachments[$i]);
				  }
                }
				break;

			case $html AND $attachments AND $html_images:
				$message =& $this->add_mixed_part();
				if(!is_null($this->html_text)){
					$alt =& $this->add_alternative_part($message);
					$this->add_text_part($alt, $this->html_text);
					$rel =& $this->add_related_part($alt);
				}else{
					$rel =& $this->add_related_part($message);
				}
				$this->add_html_part($rel);
				for($i=0; $i<count($this->html_images); $i++)
					$this->add_html_image_part($rel, $this->html_images[$i]);
				for($i=0; $i<count($this->attachments); $i++)
					$this->add_attachment_part($message, $this->attachments[$i]);
				break;

		}
		if(isset($message)){
			$output = $message->encode();
			$this->output = $output['body'];

			foreach($output['headers'] as $key => $value){
				$headers[] = $key.': '.$value;
			}

			$this->headers = array_merge($this->headers, $headers);
			return TRUE;
		}else
			return FALSE;
	}

/***************************************
** Sends the mail.
***************************************/

	function send($to_name, $to_addr, $from_name, $from_addr, $subject = '', $headers = ''){

		$to		= ($to_name != '')   ? '"'.$to_name.'" <'.$to_addr.'>' : $to_addr;
		$from	= ($from_name != '') ? '"'.$from_name.'" <'.$from_addr.'>' : $from_addr;

		if(is_string($headers))
			$headers = explode(CRLF, trim($headers));


		for($i=0; $i<count($headers); $i++){
			if(is_array($headers[$i]))
				for($j=0; $j<count($headers[$i]); $j++)
					if($headers[$i][$j] != '')
						$xtra_headers[] = $headers[$i][$j];

			if($headers[$i] != '')
				$xtra_headers[] = $headers[$i];
		}

// 		$this->output = str_replace(CRLF, '@@@<br>', $this->output);

		if(!isset($xtra_headers)) $xtra_headers = array();

	/*
			$headers = str_replace(CRLF.'.', CRLF.'..', trim(implode(CRLF, $this->headers)));
			$this->output    = str_replace(CRLF.'.', CRLF.'..', $this->output);
			$this->output    = $this->output == '.' ? '.'.$this->output : $this->output;
	*/		

		$myheaders = implode(CRLF, $this->headers).CRLF.implode(CRLF, $xtra_headers);
		return mail($to, $subject, $this->output,$myheaders);
	}

/***************************************
** Use this method to deliver using direct
** smtp connection. Relies upon the smtp
** class available from http://www.heyes-computing.net
** You probably downloaded it with this class though.
**
** bool smtp_send(
**                object The smtp object,
**                array  Parameters to pass to the smtp object
**                       See example.1.php for details.
**               )
***************************************/

	function smtp_send(&$smtp, $params = array()){

		foreach($params as $key => $value){
			switch($key){
				case 'headers':
					$headers = $value;
					break;

				case 'from':
					$send_params['from'] = $value;
					break;

				case 'recipients':
					$send_params['recipients'] = $value;
					break;
			}
		}

		$send_params['body']	= $this->output;
		$send_params['headers']	= array_merge($this->headers, $headers);

		return $smtp->send($send_params);
	}

/***************************************
** Use this method to return the email
** in message/rfc822 format. Useful for
** adding an email to another email as
** an attachment. there's a commented
** out example in example.php.
**
** string get_rfc822(string To name,
**		   string To email,
**		   string From name,
**		   string From email,
**		   [string Subject,
**		    string Extra headers])
***************************************/

	function get_rfc822($to_name, $to_addr, $from_name, $from_addr, $subject = '', $headers = ''){

		// Make up the date header as according to RFC822
		$date = 'Date: '.date('D, d M y H:i:s');

		$to   = ($to_name   != '') ? 'To: "'.$to_name.'" <'.$to_addr.'>' : 'To: '.$to_addr;
		$from = ($from_name != '') ? 'From: "'.$from_name.'" <'.$from_addr.'>' : 'From: '.$from_addr;

		if(is_string($subject))
			$subject = 'Subject: '.$subject;

		if(is_string($headers))
			$headers = explode(CRLF, trim($headers));

		for($i=0; $i<count($headers); $i++){
			if(is_array($headers[$i]))
				for($j=0; $j<count($headers[$i]); $j++)
					if($headers[$i][$j] != '')
						$xtra_headers[] = $headers[$i][$j];

			if($headers[$i] != '')
				$xtra_headers[] = $headers[$i];
		}

		if(!isset($xtra_headers))
			$xtra_headers = array();

		$headers = array_merge($this->headers, $xtra_headers);

		return $date.CRLF.$from.CRLF.$to.CRLF.$subject.CRLF.implode(CRLF, $headers).CRLF.CRLF.$this->output;
	}


} // End of class.
?>
