<?php
/**
* @version	$Id: email_messages_event_handler.php 12734 2009-10-20 19:28:11Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class EmailMessagesEventHandler extends kDBEventHandler
	{

		/**
		 * Replace id passed with id of email message
		 *
		 * @param kEvent $event
		 */
		function getPassedID(&$event)
		{
			$event->setEventParam('raise_warnings', 0);

			$parent = parent::getPassedID($event);
			if ($parent) {
				return $parent;
			}

			$email_event_id = (int)$this->getEmailEventId();
			$object =& $event->getObject();

			$parent_info = $object->getLinkedInfo();

			$sql = 'SELECT '.$object->IDField.'
					FROM '.$object->TableName.'
					WHERE ('.$parent_info['ForeignKey'].' = '.$parent_info['ParentId'].') AND (EventId = '.$email_event_id.')';

			return (int)$this->Conn->GetOne($sql);
		}

		function getEmailEventId()
		{
			return parent::getPassedID( new kEvent('emailevents:OnDummy') );
		}

		/**
		 * Apply any custom changes to list's sql query
		 *
		 * @param kEvent $event
		 * @access protected
		 * @see OnListBuild
		 */
		function SetCustomQuery(&$event)
		{
			$object =& $event->getObject();
			/* @var $object kDBList */

			if ($event->Special == 'module') {
				$module = $this->Application->GetVar('module');
				$object->addFilter('module_filter', 'Module = ' . $this->Conn->qstr($module));
			}

			if (($event->Special == 'st') && !$this->Application->isDebugMode()) {
				$object->addFilter('enabled_filter', TABLE_PREFIX . 'Events.Enabled <> ' . STATUS_DISABLED);
			}
		}

		/**
		 * If loading empty item, then set parent id
		 *
		 * @param kEvent $event
		 */
		function OnBeforeItemLoad(&$event)
		{
			if (!$event->getEventParam('id')) {
				$this->OnNew($event);

				$event->status = erFATAL;
			}
		}

		/**
		 * Sets event id
		 *
		 * @param kEvent $event
		 */
		function OnNew(&$event)
		{
			parent::OnNew($event);

			$object =& $event->getObject();
			/* @var $object kDBItem */

			$object->SetDBField('EventId', $this->getEmailEventId());
			$object->SetDBField('Headers', $this->Application->ConfigValue('Smtp_DefaultHeaders') );
		}

		/**
		 * Parse message template (split into header, subject & body)
		 *
		 * @param kEvent $event
		 */
		function OnAfterItemLoad(&$event)
		{
			$object =& $event->getObject();
			/* @var $object kDBItem */
			
			$email_message_helper =& $this->Application->recallObject('EmailMessageHelper');
			/* @var $email_message_helper EmailMessageHelper */
			
			$fields_hash = $email_message_helper->parseTemplate( $object->GetDBField('Template') );
			
			$object->SetDBFieldsFromHash($fields_hash);
		}

		/**
		 * Merge body+subject+headers into message template
		 *
		 * @param kEvent $event
		 */
		function OnBeforeItemUpdate(&$event)
		{
			$this->parseVirtualFields($event);
		}

		/**
		 * Merge body+subject+headers into message template
		 *
		 * @param kEvent $event
		 */
		function OnBeforeItemCreate(&$event)
		{
			$this->parseVirtualFields($event);
		}

		/**
		 * Enabled/disables actual email event
		 *
		 * @param kEvent $event
		 */
		function OnAfterItemUpdate(&$event)
		{
			parent::OnAfterItemUpdate($event);

			$object =& $event->getObject();
			/* @var $object kDBItem */

			if ($object->GetDBField('Enabled') != $object->GetOriginalField('Enabled')) {
				$email_event =& $this->Application->recallObject('emailevents.-item', null, Array ('skip_autoload' => true));
				/* @var $email_event kDBItem */

				$email_event->Load( $object->GetDBField('EventId') );
				if ($email_event->isLoaded()) {
					$email_event->SetDBField('Enabled', $object->GetDBField('Enabled'));
					$email_event->Update();
				}
			}
		}

		/**
		 * Merge body+subject+headers into message template
		 *
		 * @param kEvent $event
		 */
		function parseVirtualFields(&$event)
		{
			$object =& $event->getObject();
			if( $object->GetDBField('Headers') || $object->GetDBField('Subject') || $object->GetDBField('Body') )
			{
				$ret = $object->GetDBField('Headers');
				if($ret) $ret .= "\n";

				$ret = $this->removeTrailingCRLF($ret);
				$ret .= 'Subject: '.$object->GetDBField('Subject')."\n\n";
				$ret .= $object->GetDBField('Body');
				$object->SetDBField('Template', $ret);
			}
		}

		/**
		 * Remove trailing CR/LF chars from string
		 *
		 * @param string $string
		 * @return string
		 */
		function removeTrailingCRLF($string)
		{
			return preg_replace('/(\n|\r)+/',"\\1",$string);
		}

		/**
		 * Prepares selected user(-s) or group(-s) for message sending
		 *
		 * @param kEvent $event
		 */
		function OnPrepareMassRecipients(&$event)
		{
			$object =& $event->getObject( Array('skip_autoload' => true) );
			/* @var $object kDBItem */

			$object->Clear(0);

			$event->redirect = false;

			$this->Application->RemoveVar('recipient_ids');
			$this->Application->RemoveVar('recipient_type');

			$this->saveMassRecipients('u');
			$this->saveMassRecipients('g', 'total');
		}

		function saveMassRecipients($prefix, $special = '')
		{
			$recipients = $this->Application->GetVar(rtrim($prefix.'_'.$special, '_'));
			if ($recipients) {
				$this->Application->StoreVar('recipient_ids', implode(',', array_keys($recipients)));
				$this->Application->StoreVar('recipient_type', $prefix);
			}
		}

		/**
		 * Sends mass mail
		 *
		 * @param kEvent $event
		 */
		function OnMassMail(&$event)
		{
			$object =& $event->getObject( Array('skip_autoload' => true) );
			/* @var $object kDBItem */

			$object->setRequired('MassSubject', true);

			$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
			if ($items_info) {
				list($id, $field_values) = each($items_info);
				$object->SetFieldsFromHash($field_values);
			}

			if (!$object->Validate()) {
				$event->redirect = false;
				$event->status = erFAIL;
				$object->setID($id);
				return ;
			}

			$fields_hash = $object->GetFieldValues();
			list ($fields_hash['FromEmail'], $fields_hash['FromName']) = $this->getSenderData();

			if ($fields_hash['MassAttachment']) {
				$field_options = $object->GetFieldOptions('MassAttachment');
				$fields_hash['MassAttachment'] = $field_options['upload_dir'].$fields_hash['MassAttachment'];
			}

			$this->Application->RemoveVar('email_prepare_progress');
			$this->Application->StoreVar('email_prepare_fields', serialize($fields_hash));

			$event->redirect = 'emails/prepare_queue';
		}

		/**
		 * Generates email queue using progress bar
		 *
		 * @param kEvent $event
		 * @todo Move to MailingList
		 */
		function OnPrepareEmailQueue(&$event)
		{
			$prepare_count = $this->Application->ConfigValue('MailingListQueuePerStep');
			if ($prepare_count === false) {
				// 10 recipients per script run (if none defined in config)
				$prepare_count = 10;
			}

			$email_prepare_progress = $this->Application->RecallVar('email_prepare_progress');
			if ($email_prepare_progress === false) {
				$emails_prepared = 0;
				$total_emails = $this->getRecipientEmails(true);
				$this->Application->StoreVar('email_prepare_progress', $emails_prepared.':'.$total_emails);
			}
			else {
				list ($emails_prepared, $total_emails) = explode(':', $email_prepare_progress);
			}

			$recipient_emails = $this->getRecipientEmails(false, $emails_prepared.','.$prepare_count);
			$recipient_email_count = count($recipient_emails);

			if (!$recipient_email_count) {
				// no recipients left to prepare
				$this->finalizeQueuePreparing($fields_hash['MassAttachment']);
			}

			$fields_hash = unserialize($this->Application->RecallVar('email_prepare_fields'));

			$esender =& $this->Application->recallObject('EmailSender');
			/* @var $esender kEmailSendingHelper */

			// 1. set headers same for all emails
			$esender->SetFrom($fields_hash['FromEmail'], $fields_hash['FromName']);
			$esender->SetSubject($fields_hash['MassSubject']);
			$esender->SetBody($fields_hash['MassHtmlMessage'], $fields_hash['MassTextMessage']);

	    	// 2. add attachment if any
			if ($fields_hash['MassAttachment']) {
				$esender->AddAttachment(FULL_PATH.$fields_hash['MassAttachment']);
			}

			foreach ($recipient_emails as $recipient_email) {
				// 3. set recipient specific fields
				$esender->SetTo($recipient_email, $recipient_email);
				$esender->Deliver(null, false, false);

				// 4. write to log
				$log_fields_hash = Array (
					'fromuser'	=>	$fields_hash['FromName'],
					'addressto'	=>	$recipient_email,
					'subject'	=>	$fields_hash['MassSubject'],
					'timestamp'	=>	adodb_mktime(),
					'event'		=>	'',
				);

				$this->Conn->doInsert($log_fields_hash, TABLE_PREFIX.'EmailLog');
			}

			$emails_prepared += $recipient_email_count;
			if ($emails_prepared >= $total_emails) {
				$this->finalizeQueuePreparing($fields_hash['MassAttachment']);
			}

			$this->Application->StoreVar('email_prepare_progress', $emails_prepared.':'.$total_emails);
			$event->status = erSTOP;
			echo ($emails_prepared / $total_emails) * 100;
		}

		function finalizeQueuePreparing($attachment_file = null)
		{
			// variables from users/groups grid
			$this->Application->RemoveVar('recipient_ids');
			$this->Application->RemoveVar('recipient_type');

			if ($attachment_file) {
				unlink(FULL_PATH.$attachment_file);
			}

			// variables from email preparing process
//			$this->Application->RemoveVar('email_prepare_progress');
//			$this->Application->RemoveVar('email_prepare_fields');

			// variables from email delivering process (not yet executed)
			$this->Application->RemoveVar('email_queue_progress');

			$this->Application->Redirect($this->Application->GetVar('finish_template'));
		}

		function getRecipientEmails($for_counting = false, $limit = null)
		{
			$recipient_type = $this->Application->RecallVar('recipient_type');
			$recipient_ids = $this->Application->RecallVar('recipient_ids');

			if (!$recipient_ids) {
				return $for_counting ? 0 : Array ();
			}

			if ($recipient_type == 'u') {
				$sql = 'SELECT '.($for_counting ? 'COUNT(*)' : 'Email').'
						FROM '.TABLE_PREFIX.'PortalUser
						WHERE PortalUserId IN ('.$recipient_ids.')';
			}
			else {
				$sql = 'SELECT '.($for_counting ? 'COUNT(*)' : 'u.Email').'
						FROM '.TABLE_PREFIX.'UserGroup ug
						LEFT JOIN '.TABLE_PREFIX.'PortalUser u ON ug.PortalUserId = u.PortalUserId
						WHERE ug.GroupId IN ('.$recipient_ids.')';
			}

			if ($for_counting) {
				return $this->Conn->GetOne($sql);
			}

			if (isset($limit)) {
				$sql .= ' LIMIT '.$limit;
			}

			return $this->Conn->GetCol($sql);
		}

		/**
		 * Returns mass mail sender name & email
		 *
		 * @return Array
		 */
		function getSenderData()
		{
			$user =& $this->Application->recallObject('u.current');
			/* @var $user UsersItem */

			if ($user->GetID() > 0) {
				$email_address = $user->GetDBField('Email');
				$name = $user->GetDBField('FirstName').' '.$user->GetDBField('LastName');
			}
			else {
				$email_address = $this->Application->ConfigValue('Smtp_AdminMailFrom');
				$name = strip_tags( $this->Application->ConfigValue('Site_Name') );
			}

			return Array ($email_address, $name);
		}
	}