/**
	* ActionJob
	* This actually processes the autoresponder job and sends it out.
	* It makes sure the autoresponder queue is present (if not, returns false)
	* It makes sure the autoresponder exists and is active (if not, returns false)
	* It makes sure the autoresponder has some content (if not, returns false)
	* Once that is done, it removes any newly banned subscribers
	* Then removes any newly unsubscribe recipients
	* It makes sure the recipient is valid, is on the list and matches the criteria set by the autoresponder
	* Then it gets to work, constructing the email to get sent to the final recipient
	* Once all recipients for this queue have been looked at, it will "UnProcess" the queue to make everyone active again so next time the job runs, it can start all over again.
	* The only recipients that are treated this way are the ones who are before the autoresponder's "hours after subscription" timeframe.
	*
	* @param Int $queueid The queue to process.
	*
	* @see IsQueue
	* @see Autoresponders_API::Load
	* @see Autoresponders_API::Active
	* @see SendStudio_Functions::GetAttachments
	* @see Lists_API::Load
	* @see RemoveBannedEmails
	* @see RemoveUnsubscribedEmails
	* @see Email_API
	* @see FetchFromQueue
	* @see Subscribers_API::LoadSubscriberList
	* @see RemoveFromQueue
	* @see MarkAsProcessed
	* @see MatchCriteria
	*
	* @return Boolean Returns false if the queue can't be processed for any reason, otherwise it gets processed and returns true.
	*/
	function ActionJob($queueid=0, $jobid=0)
	{
		$queueid = (int)$queueid;
		if (!$this->IsQueue($queueid, 'autoresponder')) {
			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "queueid (" . $queueid . ") is not valid" . "\n", 3, $this->LogFile);
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "Returning" . "\n", 3, $this->LogFile);
			}
			return false;
		}

		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "found queueid (" . $queueid . ")" . "\n", 3, $this->LogFile);
		}

		$query = "SELECT autoresponderid FROM " . SENDSTUDIO_TABLEPREFIX . "autoresponders WHERE queueid='" . $queueid . "'";
		$result = $this->Db->Query($query);
		if (!$result) {
			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "unable to find autoresponder for queue" . "\n", 3, $this->LogFile);
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "Returning" . "\n", 3, $this->LogFile);
			}
			return false;
		}

		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "got autoresponder result" . "\n", 3, $this->LogFile);
		}

		$row = $this->Db->Fetch($result);
		if (empty($row)) {
			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "unable to find autoresponder" . "\n", 3, $this->LogFile);
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "Returning" . "\n", 3, $this->LogFile);
			}
			return false;
		}

		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "found autoresponder (" . $row['autoresponderid'] . ")" . "\n", 3, $this->LogFile);
		}

		$this->autoresponder_api->Load($row['autoresponderid']);
		if ($this->autoresponder_api->autoresponderid <= 0) {
			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "unable to find autoresponder" . "\n", 3, $this->LogFile);
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "Returning" . "\n", 3, $this->LogFile);
			}
			return false;
		}

		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "loaded autoresponder (" . $row['autoresponderid'] . ")" . "\n", 3, $this->LogFile);
		}

		// if the autoresponder isn't active, don't do anything.
		if (!$this->autoresponder_api->Active()) {
			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "autoresponder not active" . "\n", 3, $this->LogFile);
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "Returning" . "\n", 3, $this->LogFile);
			}
			return false;
		}

		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "autoresponder is active" . "\n", 3, $this->LogFile);
		}

		// if the autoresponder is empty, don't do anything.
		if (empty($this->autoresponder_api->textbody) && empty($this->autoresponder_api->htmlbody)) {
			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "autoresponder bodies are empty" . "\n", 3, $this->LogFile);
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "Returning" . "\n", 3, $this->LogFile);
			}
			return false;
		}

		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "autoresponder has text &/or html body" . "\n", 3, $this->LogFile);
		}

		$this->autoresponder['Attachments'] = SendStudio_Functions::GetAttachments('autoresponders', $this->autoresponder_api->Get('autoresponderid'), true);

		$this->listid = $this->autoresponder_api->Get('listid');

		$this->Lists_API->Load($this->listid);
		$listname = $this->Lists_API->Get('name');

		$search_criteria = $this->autoresponder_api->Get('searchcriteria');

		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "search_criteria: " . array_contents($search_criteria) . "\n", 3, $this->LogFile);
		}

		if (SENDSTUDIO_DATABASE_TYPE == 'pgsql') {
			$this->Db->OptimizeTable(SENDSTUDIO_TABLEPREFIX . "queues");
		}

		// double check there are no duplicates in the autoresponder queue.
		$this->RemoveDuplicatesInQueue($queueid, 'autoresponder', $this->listid);

		// remove any that have been newly banned.
		$this->RemoveBannedEmails($this->listid, $queueid, 'autoresponder');

		// remove any that have unsubscribed.
		$this->RemoveUnsubscribedEmails($this->listid, $queueid, 'autoresponder');

		if (SENDSTUDIO_DATABASE_TYPE == 'pgsql') {
			$this->Db->OptimizeTable(SENDSTUDIO_TABLEPREFIX . "queues");
		}

		$this->Email_API->ForgetEmail();

		$this->Email_API->Set('statid', $this->statid);
		$this->Email_API->Set('listids', array($this->listid));

		$this->Email_API->SetSmtp(SENDSTUDIO_SMTP_SERVER, SENDSTUDIO_SMTP_USERNAME, @base64_decode(SENDSTUDIO_SMTP_PASSWORD), SENDSTUDIO_SMTP_PORT);

		if ($this->user->smtpserver) {
			$this->Email_API->SetSmtp($this->user->smtpserver, $this->user->smtpusername, $this->user->smtppassword, $this->user->smtpport);
		}

		if (is_null($this->userpause)) {
			$pause = $pausetime = 0;
			if ($this->user->perhour > 0) {
				$pause = $this->user->perhour;
			}

			// in case the system rate is less than the user rate, lower it.
			if (SENDSTUDIO_MAXHOURLYRATE > 0) {
				if ($pause == 0) {
					$pause = SENDSTUDIO_MAXHOURLYRATE;
				} else {
					$pause = min($pause, SENDSTUDIO_MAXHOURLYRATE);
				}
			}

			if ($pause > 0) {
				$pausetime = 3600 / $pause;
			}
			$this->userpause = $pausetime;
			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "userpause is set to " . $this->userpause . "\n", 3, $this->LogFile);
			}
		}

		if ($this->autoresponder_api->Get('tracklinks')) {
			$this->Email_API->TrackLinks(true);
		}

		if ($this->autoresponder_api->Get('trackopens')) {
			$this->Email_API->TrackOpens(true);
		}

		if (SENDSTUDIO_FORCE_UNSUBLINK) {
			$this->Email_API->ForceLinkChecks(true);
		}

		$this->Email_API->Set('CharSet', $this->autoresponder_api->Get('charset'));

		if (!SENDSTUDIO_SAFE_MODE) {
			$this->Email_API->Set('imagedir', TEMP_DIRECTORY . '/autoresponder.' . $queueid);
		} else {
			$this->Email_API->Set('imagedir', TEMP_DIRECTORY . '/autoresponder');
		}

		// clear out the attachments just to be safe.
		$this->Email_API->ClearAttachments();

		if ($this->autoresponder['Attachments']) {
			$path = $this->autoresponder['Attachments']['path'];
			$files = $this->autoresponder['Attachments']['filelist'];
			foreach ($files as $p => $file) {
				$this->Email_API->AddAttachment($path . '/' . $file);
			}
		}

		$this->Email_API->Set('Subject', $this->autoresponder_api->Get('subject'));

		$this->Email_API->Set('FromName', $this->autoresponder_api->Get('sendfromname'));
		$this->Email_API->Set('FromAddress', $this->autoresponder_api->Get('sendfromemail'));
		$this->Email_API->Set('ReplyTo', $this->autoresponder_api->Get('replytoemail'));
		$this->Email_API->Set('BounceAddress', $this->autoresponder_api->Get('bounceemail'));

		$this->Email_API->Set('EmbedImages', $this->autoresponder_api->Get('embedimages'));

		$auto_format = $this->autoresponder_api->Get('format');

		$this->Email_API->Set('Multipart', false);

		if ($auto_format == 'b' || $auto_format == 't') {
			if ($this->autoresponder_api->GetBody('text')) {
				$this->Email_API->AddBody('text', $this->autoresponder_api->GetBody('text'));
				$this->Email_API->AppendBody('text', $this->user->Get('textfooter'));
				$this->Email_API->AppendBody('text', stripslashes(SENDSTUDIO_TEXTFOOTER));
			}
		}

		if ($auto_format == 'b' || $auto_format == 'h') {
			if ($this->autoresponder_api->GetBody('html')) {
				$this->Email_API->AddBody('html', $this->autoresponder_api->GetBody('html'));
				$this->Email_API->AppendBody('html', $this->user->Get('htmlfooter'));
				$this->Email_API->AppendBody('html', stripslashes(SENDSTUDIO_HTMLFOOTER));
			}
		}

		if ($auto_format == 'b' && $this->autoresponder_api->Get('multipart')) {
			if ($this->autoresponder_api->GetBody('text') && $this->autoresponder_api->GetBody('html')) {
				$sent_format = 'm';
				$this->Email_API->Set('Multipart', true);
			} else {
				$this->Email_API->Set('Multipart', false);
			}
		}

		$custom_fields_to_replace = $this->Email_API->GetCustomFields();

		$personalize_customfields = array();

		$firstname_field = $this->autoresponder_api->Get('to_firstname');
		if ($firstname_field) {
			$personalize_customfields[] = $firstname_field;
		}

		$lastname_field = $this->autoresponder_api->Get('to_lastname');
		if ($lastname_field) {
			$personalize_customfields[] = $lastname_field;
		}

		$personalize_customfields = array_unique($personalize_customfields);

		// Current available credit returns TRUE if credit is unlimited
		$credit_available = true;

		if (SENDSTUDIO_CREDIT_INCLUDE_AUTORESPONDERS) {
			$credit_available = API_USERS::creditAvailableTotal($this->autoresponder_api->Get('ownerid'));
		}

		$credit_used = 0;
		$emails_sent = 0;
		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "checking queue for deleted recipients" . "\n", 3, $this->LogFile);
		}		
		$recipient_to_check = array();
		$query = "SELECT recipient FROM " . SENDSTUDIO_TABLEPREFIX . "queues WHERE queueid={$queueid}";
		$result = $this->Db->Query($query);
		if (!$result) {
			trigger_error(mysql_error());
			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . mysql_error() . "\n", 3, $this->LogFile);
			}
		}
		while ($row = $this->Db->Fetch($result)) {
			$recipient_to_check[] = $row['recipient'];
		}

		foreach($recipient_to_check as $val)
		{
			$query = "SELECT COUNT(subscriberid) FROM " . SENDSTUDIO_TABLEPREFIX . "list_subscribers WHERE subscriberid={$val}";
			$exist = $this->Db->FetchOne($query);
			if((int)$exist == 0){
				if ($this->Debug) {
					error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "subscriber id {$val} no longer exists" . "\n", 3, $this->LogFile);
				}
				$this->SaveAutoresponderSentStatus(false, $this->autoresponder_api->Get('autoresponderid'), $val, 'doesntexist');
				$this->MarkAsSent($queueid, $val);

			}
			
		}
		if ($this->Debug) {
			error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "fetching autoresponder recipients" . "\n", 3, $this->LogFile);
		}
		while ($recipients = $this->FetchFromQueue($queueid, 'autoresponder', 1, 500, $this->autoresponder_api->Get('hoursaftersubscription'))) {
			if (empty($recipients)) {
				if ($this->Debug) {
					error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "no more recipients" . "\n", 3, $this->LogFile);
				}

				break;
			}

			if ($this->Debug) {
				error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "found " . sizeof($recipients) . " recipients" . "\n", 3, $this->LogFile);
			}

			
            		$tempCustomField = $this->SetupDynamicContentFields($recipients, $this->listid, true);
            		$custom_fields_to_replace = array_unique(array_merge($tempCustomField, $custom_fields_to_replace));
			$all_customfields = $this->SetupCustomFields($this->listid, $custom_fields_to_replace, $recipients, $personalize_customfields);

			foreach ($recipients as $p => $recipientid) {
				$subscriberinfo = $this->Subscriber_API->LoadSubscriberList($recipientid, $this->listid, true, false, false);

				if ($this->Debug) {
					error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "recipientid: " . $recipientid . "; subscriberinfo: " . array_contents($subscriberinfo) . "\n", 3, $this->LogFile);
				}

				// if they don't match the search criteria, remember it for later and don't sent it.
				if (empty($subscriberinfo) || !isset($subscriberinfo['subscribedate'])) {
					if ($this->Debug) {
						error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "recipientid: " . $recipientid . "; subscriber info is empty or date is not set" . "\n", 3, $this->LogFile);
					}

					$this->SaveAutoresponderSentStatus(false, $this->autoresponder_api->Get('autoresponderid'), $recipientid, 'unsubscribed');


					$this->MarkAsSent($queueid, $recipientid);
					continue;
				}

				if ($this->Debug) {
					error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "recipientid: " . $recipientid . " has email address " . $subscriberinfo['emailaddress'] . "\n", 3, $this->LogFile);
				}

				// work out how long they have been subscribed for.
				$hours_subscribed = floor(($this->currenttime - $subscriberinfo['subscribedate']) / 3600);

				if ($this->Debug) {
					error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "recipientid: " . $recipientid . " subscribed for " . $hours_subscribed . "\n", 3, $this->LogFile);
				}

				// not long enough? Go to the next one.
				if ($hours_subscribed < $this->autoresponder_api->Get('hoursaftersubscription')) {
					if ($this->Debug) {
						error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "recipientid: " . $recipientid . "; not time to send the autoresponder yet (subscribed for " . $hours_subscribed . "; hours set to: " . $this->autoresponder_api->Get('hoursaftersubscription') . ")" . "\n", 3, $this->LogFile);
					}
					$this->MarkAsProcessed($queueid, 'autoresponder', $recipientid);
					continue;
				}

				if ($this->Debug) {
					error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "recipientid: " . $recipientid . " has been subscribed for long enough" . "\n", 3, $this->LogFile);
				}

				// if they don't match the search criteria, remember it for later and don't send it.
				if (!$this->MatchCriteria($search_criteria, $recipientid)) {
					$this->SaveAutoresponderSentStatus(false, $this->autoresponder_api->Get('autoresponderid'), $recipientid, 'search_criteria');
					if ($this->Debug) {
						error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "recipientid: " . $recipientid . "; dont meet search criteria (" . array_contents($search_criteria) . ")" . "\n", 3, $this->LogFile);
					}
					$this->MarkAsSent($queueid, $recipientid);
					continue;
				}

				if ($this->Debug) {
					error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "does meet search criteria" . "\n", 3, $this->LogFile);
				}

				// If user don't have enough credit, discard queue record
				if ($credit_available !== true && ($credit_available <= 0 || $credit_available <= $credit_used)) {
					if ($this->Debug) {
						error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\tUser (userid: {$this->autoresponder->ownerid}) does not have enough credit... Will remove subscriber (id: {$recipientid}) from queue table.\n", 3, $this->LogFile);
					}

					$this->SaveAutoresponderSentStatus(false, $this->autoresponder_api->Get('autoresponderid'), $recipientid, 'icredit');

					$this->MarkAsSent($queueid, $recipientid);
					continue;
				}

				$this->Email_API->ClearRecipients();

				$subscriberinfo['ipaddress'] = $subscriberinfo['confirmip'];
				if (!$subscriberinfo['ipaddress']) {
					$subscriberinfo['ipaddress'] = $subscriberinfo['requestip'];
				}
				if (!$subscriberinfo['ipaddress']) {
					$subscriberinfo['ipaddress'] = '';
				}

				$subscriberinfo['CustomFields'] = array();

				if (!empty($all_customfields) && isset($all_customfields[$recipientid])) {
					$subscriberinfo['CustomFields'] = $all_customfields[$recipientid];
				} else {
					/**
					* If the subscriber has no custom fields coming from the database, then set up blank placeholders.
					* If they have no custom fields in the database, they have no records in the 'all_customfields' array - so we need to fill it up with blank entries.
					*/
					foreach ($custom_fields_to_replace as $fieldid => $fieldname) {
						$subscriberinfo['CustomFields'][] = array(
							'fieldid' => $fieldid,
							'fieldname' => $fieldname,
							'fieldtype' => 'text',
							'defaultvalue' => '',
							'fieldsettings' => '',
							'subscriberid' => $recipientid,
							'data' => ''
						);
					}
				}

				$name = false;

				$firstname_field = $this->autoresponder_api->Get('to_firstname');
				if ($firstname_field) {
					foreach ($subscriberinfo['CustomFields'] as $p => $details) {
						if ($details['fieldid'] == $firstname_field && $details['data'] != '') {
							$name = $details['data'];
							break;
						}
					}
				}

				$lastname_field = $this->autoresponder_api->Get('to_lastname');
				if ($lastname_field) {
					foreach ($subscriberinfo['CustomFields'] as $p => $details) {
						if ($details['fieldid'] == $lastname_field && $details['data'] != '') {
							$name .= ' ' . $details['data'];
							break;
						}
					}
				}

				$this->Email_API->AddRecipient($subscriberinfo['emailaddress'], $name, $subscriberinfo['format'], $subscriberinfo['subscriberid']);

				$subscriberinfo['listid'] = $this->listid;
				$subscriberinfo['listname'] = $listname;
				$subscriberinfo['autoresponder'] = $this->autoresponder_api->Get('autoresponderid');
				$subscriberinfo['statid'] = $this->statid;

				$subscriberinfo['companyname'] = $this->Lists_API->Get('companyname');
				$subscriberinfo['companyaddress'] = $this->Lists_API->Get('companyaddress');
				$subscriberinfo['companyphone'] = $this->Lists_API->Get('companyphone');

				$this->Email_API->AddCustomFieldInfo($subscriberinfo['emailaddress'], $subscriberinfo);
				$this->Email_API->AddDynamicContentInfo($this->dynamic_content_replacement);

				$mail_result = $this->Email_API->Send(true, true);

				if ($this->Debug) {
					error_log(time() . "\t" . __FILE__ . "\t" . __LINE__ . "\t" . "recipientid: " . $recipientid . "; mail result: " . array_contents($mail_result) . "\n", 3, $this->LogFile);
				}

				if (!$this->Email_API->Get('Multipart')) {
					$sent_format = $subscriberinfo['format'];
				}

				$last_sent_error = false;
				if ($mail_result['success'] > 0) {
					$this->Stats_API->UpdateRecipient($this->statid, $sent_format, 'a');
					$this->SaveAutoresponderSentStatus(true, $this->autoresponder_api->Get('autoresponderid'), $recipientid);
				} else {
					$last_sent_error = true;
					$error_reason = 'mail_error';
					reset($mail_result['fail']);
					$error = current($mail_result['fail']);
					if ($error[1] == 'BlankEmail') {
						$error_reason = 'blankemail_' . $sent_format;
					}
					$this->SaveAutoresponderSentStatus(false, $this->autoresponder_api->Get('autoresponderid'), $recipientid, $error_reason);
				}

				/**
				* Trigger Event
				*/
					$tempEventData = new EventData_IEM_JOBSAUTORESPONDERAPI_ACTIONJOB();
					$tempEventData->emailsent = ($mail_result['success'] > 0);
					$tempEventData->subscriberinfo = &$subscriberinfo;
					$tempEventData->autoresponder = &$this->autoresponder_api;
					$tempEventData->trigger();
					unset($tempEventData);
				/**
				* ------
				*/

				$emails_sent++;

				$this->MarkAsSent($queueid, $recipientid);

				/**
				 * Work out whether we need to update the job 'lastupdatetime'
				 * - If we pause between each email, we should update it
				 * - If we are not pausing between each email, we should update it every 10 emails
				*/
				$update_job_time = false;
				if ($this->userpause > 0) {
					$update_job_time = true;
				} else {
					if (($emails_sent % 10) == 0) {
						$update_job_time = true;
					}
				}

				if ($update_job_time) {
					$timenow = $this->GetServerTime();
					$query = "UPDATE [|PREFIX|]jobs SET lastupdatetime = {$timenow} WHERE jobid = {$jobid}";
					$update_job_result = $this->Db->Query($query);

					$emails_sent = 0;
				}

				// ----- Record credit usage every 100 emails sent when there aren't any sending error
					if (!$last_sent_error && $credit_available !== true) {
						++$credit_used;
						if ($credit_used >= 100) {
							$ownerid = $this->autoresponder_api->Get('ownerid');
							$status = API_USERS::creditUse($ownerid, API_USERS::CREDIT_USAGETYPE_SENDAUTORESPONDER, $credit_used, $jobid, $this->statid);
							if (!$status) {
								trigger_error(__CLASS__ . '::' . __METHOD__ . " -- Cannot record usage -- userid = {$ownerid}, credit_used = {$credit_used}, job_id = {$jobid}, stat_id = {$this->statid}", E_USER_NOTICE);
								return false;
							}

							$credit_used = 0;
						}
					}
				// -----

				// do we need to pause between each email?
				if ($this->userpause > 0) {
					if ($this->userpause > 0 && $this->userpause < 1) {
						$p = ceil($this->userpause * 1000000);
						usleep($p);
					} else {
						$p = ceil($this->userpause);
						sleep($p);
					}
				} // end if we need to pause.
			} // end foreach recipient
		} // end while loop (to go through each subscriber in the queue).

		// ----- If there are leftover credits that haven't been recorded, then record it here
			if ($credit_available !== true && $credit_used > 0) {
				$ownerid = $this->autoresponder_api->Get('ownerid');
				$status = API_USERS::creditUse($ownerid, API_USERS::CREDIT_USAGETYPE_SENDAUTORESPONDER, $credit_used, $jobid, $this->statid);
				if (!$status) {
					trigger_error(__CLASS__ . '::' . __METHOD__ . " -- Cannot record usage -- userid = {$ownerid}, credit_used = {$credit_used}, job_id = {$jobid}, stat_id = {$this->statid}", E_USER_NOTICE);
					return false;
				}
			}
		// -----

		$this->Email_API->CleanupImages();

		// logout of the smtp server. the email class handles whether it's actually using an smtp server or not.
		$this->Email_API->SMTP_Logout();

		// reset the 'pause' counter.
		$this->userpause = null;
		return true;
	}
	/**
	 * ProcessJob
	 *
	 * This function will process all records in the queues that are related to the trigger emails.
	 * The queues only hold record of trigger emails that is ready to be sent out in the next 24 hours.
	 * Another process will take care populating the queue table.
	 *
	 * @return Boolean Returns TRUE if successful, FALSE otherwise
	 *
	 * @see Jobs_TriggerEmails_API::ProcessPopulateJob()
	 * @uses SENDSTUDIO_TABLEPREFIX
	 * @uses Jobs_TriggerEmails_API::RECORDS_PER_PROCESS
	 * @uses Jobs_TriggerEmails_API::_log()
	 * @uses Jobs_TriggerEmails_API::_cacheTriggerRecordClean()
	 * @uses Db::Query()
	 * @uses Db::GetError()
	 * @uses Db::Fetch()
	 * @uses Db::FreeResult()
	 * @uses Jobs_TriggerEmails_API::_cacheTriggerRecordGet()
	 * @uses Jobs_TriggerEmails_API::_cacheNewsletterGet()
	 * @uses Jobs_TriggerEmails_API::_send()
	 * @uses Jobs_TriggerEmails_API::UpdateJob()
	 * @uses Jobs_TriggerEmails_API::_markQueueRecordAsProcessed()
	 */
	public function ProcessJob()
	{
		$last_owner_id = null;
		$last_stat_id = null;
		$last_job_id = null;

		$current_available_credit = null;
		$credit_used = 0;

		$this->_log('Start processing Send Job');

		// Clean up old caches
		$this->_cacheTriggerRecordClean();

		// ----- Setup Stats API if it's not already available
			if (is_null($this->_statsAPIObject)) {
				require_once dirname(__FILE__) . '/stats.php';
				$this->_statsAPIObject = new Stats_API();
			}
		// -----

		$queues = array();
		do {
			// ----- Get all triggeremail queues that is due to be sent out
				$now = date('Y-m-d H:i:s', time());
				$limit = self::RECORDS_PER_PROCESS;

				$query = "
					SELECT *
					FROM [|PREFIX|]queues
					WHERE
						queuetype='triggeremail'
						AND processed='0'
						AND processtime <= '{$now}'
					ORDER BY queueid, processtime ASC
					LIMIT {$limit}
				";

				$resQueue = $this->Db->Query($query);
				if (!$resQueue) {
					list($msg, $errno) = $this->Db->GetError();
					$this->_log('Cannot get queues: ' . $msg);
					trigger_error($msg, $errno);
					return false;
				}

				$queues = array();
				while (($row = $this->Db->Fetch($resQueue))) {
					array_push($queues, $row);
				}

				$this->Db->FreeResult($resQueue);
			// -----


			// If nothing to be done in the queues, then get out from the loop
			if (empty($queues)) {
				break;
			}


			// ----- Loop against the queue to process the triggers
				foreach ($queues as $queue) {
					$doactions = true;
					$error = false;
					$queueid = $queue['queueid'];
					$recipientid = $queue['recipient'];

					// Get trigger record, if there is an error fetching the trigger it will NOT send the trigger
					$trigger = $this->_cacheTriggerRecordGet($queueid);
					if ($trigger === false) {
						$error = true;
						$doactions = false;
						$this->_log('Cannot get trigger record for queueid: ' . $queueid);
					}

					// Update credit related procedure
					if (is_null($last_owner_id)) {
						$last_owner_id = $trigger['ownerid'];
						$last_stat_id = $trigger['statid'];
						$last_job_id = $trigger['jobid'];

						// Current available credit returns TRUE if credit is unlimited
						$current_available_credit = true;
						if (SENDSTUDIO_CREDIT_INCLUDE_TRIGGERS) {
							$current_available_credit = API_USERS::creditAvailableTotal($trigger['ownerid']);
						}
					}

					// Check if trigger is active
					if (!$trigger['active']) {
						$error = true;
						$this->_log('Trigger is marked as INACTIVE');
					}

					// Have trigger exceeded it's running interval for this subscriber?
					// Or trigger has recently been actioned on.
					if (!$error && !$this->_checkInterval($trigger, $recipientid)) {
						$doactions = false;
						$this->_log('Do not proceed with trigger actions, as action interval has been exceeded for this subscriber.');
					}

					// ----- Check whether the recipient exists or not
						$status = $this->Db->Query("SELECT subscriberid FROM [|PREFIX|]list_subscribers WHERE subscriberid = {$recipientid}");
						if (!$status) {
							$this->_log('Cannot check database for particular subscriber');
							return false;
						}

						$row = $this->Db->Fetch($status);
						$this->Db->FreeResult($status);

						if (empty($row)) {
							$doactions = false;
							$this->_log('Do not proceed with trigger actions... no subscribers found');
						}
					// -----

					if ($doactions && !$error) {
						if (!empty($trigger) && isset($trigger['triggeractions']) && is_array($trigger['triggeractions'])) {
							if (array_key_exists('send', $trigger['triggeractions'])) {
								// Send only when credit is available
								if (($current_available_credit === true) || ($current_available_credit > 0 && $current_available_credit > $credit_used)) {
									$status = $this->_ProcessJob_Send($queue, $trigger, $recipientid);
									if ($status['halt']) {
										return false;
									}
									if ($status['error']) {
										$error = true;
									}
								} else {
									$rs = $this->Db->Query("SELECT emailaddress FROM [|PREFIX|]list_subscribers WHERE subscriberid = {$recipientid}");
									$emailaddress = $this->Db->FetchOne($rs, 'emailaddress');

									// Log failed sending
									$this->RecordLogActions($trigger['triggeremailsid'], $recipientid, 'send_failed', $emailaddress);
									trigger_error('Insuficient credits! Cannot send newsletter with queueid:' . $queue['queueid'] . ', and recipient:' . $recipientid);
									$error = true;
								}


								// ----- Record sending so that it counted towards credit usage
									// Increment credit use
									if (!$error) {
										++$credit_used;
									}

									// Record usage whenever the statid changed
									// NOTE: Each trigger is assigned a different statid and jobid
									if ($last_stat_id != $trigger['statid']) {
										if ($current_available_credit !== true) {
											$status = API_USERS::creditUse($last_owner_id, API_USERS::CREDIT_USAGETYPE_SENDTRIGGER, $credit_used, $last_job_id, $last_stat_id);
											if (!$status) {
												$this->_log("Cannot record usage -- userid = {$last_owner_id}, credit_used = {$credit_used}, job_id = {$last_job_id}, stat_id = {$last_stat_id}");
												return false;
											}
										}

										$last_owner_id = $trigger['ownerid'];
										$last_stat_id = $trigger['statid'];
										$last_job_id = $trigger['jobid'];

										$current_available_credit = true;
										if (SENDSTUDIO_CREDIT_INCLUDE_TRIGGERS) {
											$current_available_credit = API_USERS::creditAvailableTotal($trigger['ownerid']);
										}

										$credit_used = 0;
									}
								// -----
							}

							if (array_key_exists('addlist', $trigger['triggeractions'])) {
								$status = $this->_ProcessJob_AddList($queue, $trigger, $recipientid);
								if ($status['halt']) {
									return false;
								}
								if ($status['error']) {
									$error = true;
								}
							}

							if (array_key_exists('removelist', $trigger['triggeractions'])) {
								$status = $this->_ProcessJob_RemoveList($queue, $trigger, $recipientid);
								if ($status['halt']) {
									return false;
								}
								if ($status['error']) {
									$error = true;
								}
							}
						}
					}

					// Update log statistics if "removelist" is not enabled, otherwise it will be a wasteful exercise
					if ($doactions) {
						// Record summary
						if (!$this->RecordLogSummary($trigger['triggeremailsid'], $recipientid)) {
							$this->_log('Cannot write log summary to the database... exitting');
							return false;
						}
					}

					// update lastupdatedtime so we can track what's going on.
					// This is used so we can see if the server has crashed or the cron job has been stopped in mid-send.
					if (!$this->UpdateJob('triggeremails_send', 'i', time())) {
						$this->_log('Cannot update job... Exitting');
						return false;
					}

					// Mark queue record as processed, if cannot mark queue as processed, terminate
					if (!$this->_markQueueRecordAsProcessed($queueid, $recipientid)) {
						$this->_log('Cannot mark queue record qith queueueid:' . $queueid . ', and recipient:' . $recipientid . ' as processed');
						return false;
					}
				}
			// -----


			// ----- Clean up queue
				$status = $this->Db->Query("DELETE FROM [|PREFIX|]queues WHERE queuetype='triggeremail' AND processed='1'");
				if (!$status) {
					list($msg, $errno) = $this->Db->GetError();
					$this->_log('Cannot cleanup queue: ' . $msg);
					trigger_error($msg, $errno);
					return false;
				}
			// -----
		} while (!empty($queues));

		// ----- If there are leftover credits that haven't been recorded, then record it here
			if ($credit_used > 0) {
				$status = API_USERS::creditUse($last_owner_id, API_USERS::CREDIT_USAGETYPE_SENDTRIGGER, $credit_used, $last_job_id, $last_stat_id);
				if (!$status) {
					$this->_log("Cannot record usage -- userid = {$last_owner_id}, credit_used = {$credit_used}, job_id = {$last_job_id}, stat_id = {$last_stat_id}");
					return false;
				}
			}
		// -----

		return true;
	}