<?php
// $Id: xoopsmailer.php,v 1.1 2004/07/11 10:27:18 Farsus Exp $
// -------------------------------------------------------------------------//
//			                 RUNCMS                                         //
//                                                                          //
//	 reliable - Unique - Nocost &  Simplicity & ease off use                //
//                       < http://www.runcms.org >                          //
// -------------------------------------------------------------------------//
// Original Author: Kazumi Ono
// Author Website : http://www.mywebaddons.com/ , http://www.myweb.ne.jp
// License Type   : GPL: See /manual/LICENSES/GPL.txt
// ------------------------------------------------------------------------- //

if (!defined("XOOPS_XOOPSMAILER_INCLUDED")) {
	define("XOOPS_XOOPSMAILER_INCLUDED", 1);

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
class XoopsMailer {

	var $fromEmail;
	var $fromName;
	var $toUsers;
	var $toEmails;
	var $subject;
	var $body;
	var $errors;
	var $success;
	var $isMail;
	var $isPM;
	var $assignedTags;
	var $template;
	var $templatedir;
	var $useToggle;
	var $type;

	function XoopsMailer() {
		$this->reset();
	}


//---------------------------------------------------------------------------------------//
/**
* reset all properties to default
*/
function reset() {
	$this->fromEmail    = '';
	$this->fromName     = '';
	$this->toUsers      = array();
	$this->toEmails     = array();
	$this->headers      = array();
	$this->subject      = '';
	$this->body         = '';
	$this->errors       = array();
	$this->success      = array();
	$this->isMail       = false;
	$this->isPM         = false;
	$this->assignedTags = array();
	$this->template     = '';
	$this->templatedir  = '';
	$this->isToggle     = false;
	$this->type         = 'plain';
	$this->boundary     = '----'.md5(uniqid(mt_rand(), TRUE));
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function assign($tag, $value=NULL) {

if ( is_array($tag) ) {
	foreach ($tag as $k => $v) {
		$this->assign($k, $v);
	}
	} else {
		if ( !empty($tag) && isset($value) ) {
			$tag = strtoupper(trim($tag));
				if ( substr($tag, 0, 2) != 'X_' ) {
					$this->assignedTags[$tag] = $value;
				}
		}
	}
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function attachFile($file, $type='application/x-unknown-content-type', $disposition='attachment') {

if ( empty($type) ) {
	$type = 'application/x-unknown-content-type';
}

if ( preg_match("'(audio|application|image|video)/'i", $type) ) {
	$mode = 'b';
}

if ($fp = @fopen($file, 'r'.$mode)) {
	$attachment = fread($fp, filesize($file));
	fclose($fp);
}

if ($attachment) {
	if ($disposition != 'inline') { $disposition = 'attachment'; }
	$this->attachments[] = '--'.$this->boundary;
	$this->attachments[] = 'Content-Type: '.$type.'; name="'.basename($file).'"';
	$this->attachments[] = 'Content-Transfer-Encoding: base64';
	$this->attachments[] = 'Content-Disposition: '.$disposition.'; filename="'.basename($file).'"'."\n";
	$this->attachments[] = chunk_split(base64_encode($attachment));
	return(TRUE);
}

return(FALSE);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setTemplateDir($value) {

if ( @is_dir($value) ) {
	if (substr($value, -1) == '/') {
		$value = substr($value, 0, -1);
	}
	$this->templatedir = $value;
	}
}

//---------------------------------------------------------------------------------------//
/**
* Sets path to the root of the module containing the template
* Do NOT set the path to the language dir
* Templates are always in <path>/language/(lang)/mail_template/<files>
*
* @param string $value full path to directory
*/
function setTemplate($value) {
	$this->template = $value;
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setFromEmail($value) {
	$this->fromEmail = trim($value);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setFromName($value) {
	$this->fromName = trim($value);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setSubject($value) {
	$this->subject = trim($value);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setBody($value) {
	$this->body = trim($value);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function useMail() {
	$this->isMail = true;
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function usePM() {
	$this->isPM = true;
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function useToggle($value=false) {
	$this->useToggle = ($value == false) ? false : true;
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setToEmails($email) {

if (!is_array($email) && preg_match('#(,|;| )#', $email)) {
	$email = preg_split('#(,|;| )#', $email);
}

if ( !is_array($email) ) {
	$email = trim($email);
	if ( checkEmail($email) ) {
		array_push($this->toEmails, $email);
	}
	} else {
		foreach ($email as $e) {
			$this->setToEmails($e);
		}
	}

$this->toEmails = array_unique($this->toEmails);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setToUsers($user) {

if ( !is_array($user) ) {
	if ( get_class($user) == 'xoopsuser' ) {
		array_push($this->toUsers, $user->getVar('uid'));
		} elseif ( XoopsUser::getUnameFromId($user) ) {
			array_push($this->toUsers, $user);
		}
	} else {
		foreach ($user as $u) {
			$this->setToUsers($u);
		}
	}

$this->toUsers = array_unique($this->toUsers);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setToGroups($group) {

if ( !is_array($group) ) {
	if ( get_class($group) != 'xoopsgroup' ) {
		$group = new XoopsGroup($group);
	}
	$this->setToUsers($group->getMembers());
	} else {
		foreach ($group as $g) {
			$this->setToGroups($g);
		}
	}
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setType($type='text/plain') {
	$this->addHeader('Content-Type:', $type);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setPriority($priority=3) {

switch($priority) {
	case 1:
		$this->addHeader('X-Priority:', '1 (Highest)');
		break;

	case 2:
		$this->addHeader('X-Priority:', '2 (High)');
		break;

	case 3:
		$this->addHeader('X-Priority:', '3 (Normal)');
		break;

	case 4:
		$this->addHeader('X-Priority:', '4 (Low)');
		break;

	case 5:
		$this->addHeader('X-Priority:', '5 (Lowest)');
		break;
	}
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function setReciept($email='') {
	$email = checkEmail($email) ? $email : $this->fromEmail;
	$this->addHeader('Disposition-Notification-To:', $email);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function addHeader($type, $value) {

$type = trim($type);

if (substr($type, -1) != ':') {
	$type .= ':';
}

$this->headers[$type] = trim($value);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function removeHeader($value) {

$value = trim($value);

if (substr($value, -1) != ':') {
	$value .= ':';
}

unset($this->headers[$value]);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function getHeaders() {

foreach ($this->headers as $key => $value) {
	if (substr($key, -1) != ':') {
		$key .= ':';
	}
	$header[] = trim($key).''.trim($value);
}

return join("\n", $header);
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function send() {
global $xoopsUser, $xoopsConfig, $meta;

if ( $this->toggle(4) ) {
	return;
}

if ( !empty($this->template) ) {

	if ( !empty($this->templatedir) ) {
		if ( @file_exists($this->templatedir.'/language/'.$xoopsConfig['language'].'/mail_template/'.$this->template) ) {
			$path = $this->templatedir.'/language/'.$xoopsConfig['language'].'/mail_template/'.$this->template;
			} elseif( @file_exists($this->templatedir.'/language/english/mail_template/'.$this->template) ) {
			$path = $this->templatedir.'/language/english/mail_template/'.$this->template;
			} else {
			$this->errors[] = sprintf(_XM_FAILOPTPL, $this->templatedir.$this->template);
			return false;
		}
		} else {
			if ( @file_exists(XOOPS_ROOT_PATH.'/language/'.$xoopsConfig['language'].'/mail_template/'.$this->template) ) {
				$path = XOOPS_ROOT_PATH.'/language/'.$xoopsConfig['language'].'/mail_template/'.$this->template;
				} elseif ( @file_exists(XOOPS_ROOT_PATH.'/language/english/mail_template/'.$this->template) ) {
				$path = XOOPS_ROOT_PATH.'/language/english/mail_template/'.$this->template;
				} else {
				$this->errors[] = sprintf(_XM_FAILOPTPL, $this->templatedir.$this->template);
				return false;
			}
		}

	if ($fp = @fopen($path, 'r')) {
		$this->setBody(fread($fp, filesize($path)));
		fclose($fp);
		if ( stristr($this->body, '{X_ISHTML}') ) {
			$this->body = str_replace('{X_ISHTML}', '', $this->body);
			$this->setType('text/html');
		}
		} else {
			$this->errors[] = sprintf(_XM_FAILOPTPL, $path);
			return false;
		}
	} elseif ( empty($this->body) ) {
		$this->errors[] = _XM_MSGBODY;
		return false;
	}

// replace tags with actual values
foreach ( $this->assignedTags as $k => $v ) {
	$this->body = str_replace("{".$k."}", $v, $this->body);
}

$this->body = str_replace("\r\n", "\n"  , $this->body);
$this->body = str_replace("\r"  , "\n"  , $this->body);

if ($this->isMail || $this->toEmails) {
	if ( empty($this->fromName) && $xoopsUser ) {
		$this->setFromName($xoopsUser->uname());
		} elseif ( empty($this->fromName) ) {
			$this->setFromName($meta['title']);
		}

	if ( empty($this->fromEmail) && $xoopsUser ) {
		$this->setFromEmail($xoopsUser->email());
		} elseif ( empty($this->fromEmail) ) {
			$this->setFromEmail($xoopsConfig['adminmail']);
		}

	$this->addHeader('From:', $this->fromEmail);
	$this->addHeader('Reply-To:', $this->fromEmail);
	$this->addHeader('Return-Path:', $this->fromEmail);
	$this->addHeader('Error-To:', $this->fromEmail);
	$this->addHeader('Return-Errors-To:', $this->fromEmail);
	$this->addHeader('X-Mailer:', XOOPS_VERSION);

	if ( !empty($this->attachments) ) {
		$body = "\n".'--'.$this->boundary."\n";
		if ( isset($this->headers['Content-Type:']) ) {
			$body .= 'Content-Type: '.$this->headers['Content-Type:']."\n\n";
			} else {
				$body .= 'Content-Type: text/plain'."\n\n";
			}
		$body       .= $this->body."\n\n";
		$body       .= join("\n", $this->attachments);
		$body       .= '--'.$this->boundary.'--';
		$this->body  = $body;
		$this->addHeader('Content-Type:', 'multipart/mixed; boundary="'.$this->boundary.'"');
	}

// RFC 822 compliency :: need to test header/attachments
$this->body = str_replace("\n", "\r\n", trim($this->body));
}


$headers = $this->getHeaders();

/*
echo "<pre>".$headers."</pre>";
exit();
*/

// send mail to specified mail addresses, if any
foreach ($this->toEmails as $mailaddr) {
	if ( !$this->sendMail($mailaddr, $this->subject, $this->body, $headers) ) {
		$this->errors[] = sprintf(_XM_SENDMAILNG, $mailaddr);
		} else {
			$this->success[] = sprintf(_XM_MAILGOOD, $mailaddr);
		}
}

// send message to specified users, if any
foreach ($this->toUsers as $uid) {
	$user = new XoopsUser($uid);

	// set some user specific variables
	$subject = str_replace("{X_UNAME}", $user->getVar("uname"), $this->subject );
	$text    = str_replace("{X_UID}", $user->getVar("uid"), $this->body );
	$text    = str_replace("{X_UEMAIL}", $user->getVar("email"), $text );
	$text    = str_replace("{X_UNAME}", $user->getVar("uname"), $text );
	$text    = str_replace("{X_UACTLINK}", XOOPS_URL."/user.php?op=actv&id=".$user->getVar("uid")."&key=".$user->getVar("actkey")."", $text );

// send mail
if ($this->isMail) {
	if (
		checkEmail($user->getVar("email")) &&
		$this->sendMail($user->getVar("email"), $subject, $text, $headers)
		) {
		$this->success[] = sprintf(_XM_MAILGOOD, $user->getVar("uname"));
		} else {
			$this->errors[] = sprintf(_XM_SENDMAILNG, $user->getVar("uname"));
		}
}

// send private message
if ($this->isPM) {
	if ( !$this->sendPM($user->getVar("uid"), $subject, $text) ) {
		$this->errors[] = sprintf(_XM_SENDPMNG, $user->getVar("uname"));
		} else {
			$this->success[] = sprintf(_XM_PMGOOD, $user->getVar("uname"));
		}
}

} // END FOREACH

if ( count($this->errors) > 0 ) {
	return false;
}

return true;
} // END SEND

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function sendMail($to, $subject, $body, $headers) {
global $myts, $xoopsConfig;

$subject = trim($myts->oopsStripSlashesGPC($subject));
$body    = trim($myts->oopsStripSlashesGPC($body));
$headers = trim($myts->oopsStripSlashesGPC($headers));

if ($xoopsConfig['mail_function'] == 'email') {
	if ( !email($this->fromEmail, $to, $subject, $body, $this->fromEmail, $headers) ) {
		return false;
	}
	} else {
		if ( !mail($to, $subject, $body, $headers) ) {
			return false;
		}
	}

sleep(1);
return true;
}

//---------------------------------------------------------------------------------------//
/**
* Sends mail via SMTP using PhpSMTP (Author: Chris Ryan).
*
* @access private
* @param type $header description
* @param type $body description
* @return bool Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
*/
function sendSMTP($header, $body) {

include_once(XOOPS_ROOT_PATH."/class/mail/class.smtp.php");

$smtp = new SMTP();
$smtp->do_debug = $this->SMTPDebug;

// Try to connect to all SMTP servers
$hosts      = explode(';', $this->Host);
$index      = 0;
$connection = false;
$smtp_from  = '';
$bad_rcpt   = array();
$e          = '';

// Retry while there is no connection
while ($index < count($hosts) && $connection == false) {
	if (strstr($hosts[$index], ':')) {
		list ($host, $port) = explode(':', $hosts[$index]);
		} else {
			$host = $hosts[$index];
			$port = $this->Port;
		}

	if ($smtp->Connect($host, $port, $this->Timeout))
	$connection = true;
	//printf("%s host could not connect<br>", $hosts[$index]); //debug only
	$index++;
}

if (!$connection) {
	$this->error_handler("SMTP Error: could not connect to SMTP host server(s)");
	return false;
}

// Must perform HELO before authentication
if ($this->Helo != '')
$smtp->Hello($this->Helo);
else
$smtp->Hello($this->get_server_hostname());

// If user requests SMTP authentication
if ($this->SMTPAuth) {
	if (!$smtp->Authenticate($this->Username, $this->Password)) {
		$this->error_handler("SMTP Error: Could not authenticate");
		return false;
	}
}

if ($this->Sender == "")
$smtp_from = $this->From;
else
$smtp_from = $this->Sender;

if (!$smtp->Mail(sprintf("<%s>", $smtp_from))) {
	$e = sprintf("SMTP Error: From address [%s] failed", $smtp_from);
	$this->error_handler($e);
	return false;
}

// Attempt to send attach all recipients
for ($i = 0; $i < count($this->to); $i++) {
if (!$smtp->Recipient(sprintf("<%s>", $this->to[$i][0])))
$bad_rcpt[] = $this->to[$i][0];
}
for ($i = 0; $i < count($this->cc); $i++) {
if (!$smtp->Recipient(sprintf("<%s>", $this->cc[$i][0])))
	$bad_rcpt[] = $this->cc[$i][0];
}
for ($i = 0; $i < count($this->bcc); $i++) {
if (!$smtp->Recipient(sprintf("<%s>", $this->bcc[$i][0])))
	$bad_rcpt[] = $this->bcc[$i][0];
}

// Create error message
if (count($bad_rcpt) > 0) {
	for ($i = 0; $i < count($bad_rcpt); $i++) {
		if ($i != 0) {
			$e .= ", ";
		}
		$e .= $bad_rcpt[$i];
	}
	$e = sprintf("SMTP Error: The following recipients failed [%s]", $e);
	$this->error_handler($e);
	return false;
}

if (!$smtp->Data(sprintf("%s%s", $header, $body))) {
	$this->error_handler("SMTP Error: Data not accepted");
	return false;
}

$smtp->Quit();
$smtp->Close();

return true;
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function sendPM($uid, $subject, $body) {
global $xoopsUser;

include_once(XOOPS_ROOT_PATH."/class/xoopspm.php");

$pm = new XoopsPM();
$pm->setVar("subject"    , $subject);
$pm->setVar("msg_text"   , $body);
$pm->setVar("to_userid"  , $uid);
$pm->setVar("from_userid", $xoopsUser->getVar("uid"));

if ( !$pm->store() ) {
	return false;
}

return true;
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function getErrors($ashtml=true) {

if ( !$ashtml ) {
	return $this->errors;
	} else {
		if ( !empty($this->errors) ) {
			$ret = "<h6>"._ERROR."</h6>";
			foreach ($this->errors as $error) {
				$ret .= $error.'<br />';
				}
		} else {
			$ret = "";
		}
	return $ret;
	}
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function getSuccess($ashtml = true) {

if ( !$ashtml ) {
	return $this->success;
	} else {
		$ret = "";
			if ( !empty($this->success) ) {
				foreach ( $this->success as $suc ) {
					$ret .= $suc."<br />";
				}
			}
	return $ret;
	}
}

//---------------------------------------------------------------------------------------//
/**
* Description
*
* @param type $var description
* @return type description
*/
function toggle($trigger=5) {

$toUsers  = count($this->toUsers);
$toEmails = count($this->toEmails);

if ( ($this->useToggle == 1) && ($this->isMail || $toEmails) && (($toEmails+$toUsers) > $trigger) ) {
	$this->useToggle = 0;
	?>
	<form action="<?php echo XOOPS_URL;?>/include/mailtoggle.php" method="post" id="toggle" name="toggle" target="mailer">
	<input type="hidden" name="mail" value="<?php echo urlencode(serialize($this));?>" />
	<input type="image" class="image" src="<?php echo XOOPS_URL;?>/images/pixel.gif" />
	</form>

	<script type="text/javascript">
		mailer = window.open("", "mailer", "width=300, height=150, location=no, menubar=no, resizable=no, scrollbars=yes, status=no, titlebar=no, toolbar=no, directories=no");
		mailer.moveTo(((screen.availWidth/2)-(300/2)), ((screen.availHeight/2)-(150/2)));
		xoopsGetElementById("toggle").submit();
	</script>
	<?php
	echo "<h4>"._XM_BATCH."</h4>"._XM_LEAVE;
	return(TRUE);
	}

return(FALSE);
}

//---------------------------------------------------------------------------------------//
} // END CLASS

//---------------------------------------------------------------------------------------//
}
?>
