/**
	 * _send
	 *
	 * Send email campaign that is triggered by the "trigger email".
	 *
	 * @param Array $triggerrecord Trigger record
	 * @param Array $queuerecord Queue record
	 * @param Array $newsletter Newsletter record
	 * @return Array Returns a status result that contains the sending result, and the email address that get sent
	 */
	private function _send($triggerrecord, $queuerecord, $newsletter)
	{
		static $prevUserID = 0;
		static $prevQueueID = 0;
		static $userPause = 0;
		static $subscriberAPI = null;

		$triggerid = $triggerrecord['triggeremailsid'];
		$newsletterid = $newsletter['newsletterid'];
		$recipientid = $queuerecord['recipient'];
		$user = null;
		$email = null;
		$customfields = array();

		$return = array(
			'email'		=> '',
			'message'	=> '',
			'listid'	=> 0,
			'result'	=> false
		);

		if (is_null($subscriberAPI)) {
			$subscriberAPI = new Subscribers_API();
		}

		/**
		 * Get owner of trigger email
		 */
			$user = $this->_cacheUser($triggerrecord['ownerid']);
			if (empty($user)) {
				trigger_error('Cannot get trigger owner record', E_USER_NOTICE);
				return $return;
			}
		/**
		 * -----
		 */

		/**
		 * Get email object, and setup
		 * This will setup emails and setup everything that it needs to have according to the newsletter record.
		 */
			$email = new SS_Email_API();

			$email->Set('CharSet', SENDSTUDIO_CHARSET);
			if (!SENDSTUDIO_SAFE_MODE) {
				$email->Set('imagedir', TEMP_DIRECTORY . '/triggeremails.' . $triggerrecord['queueid']);
			} else {
				$email->Set('imagedir', TEMP_DIRECTORY . '/send');
			}

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

			$email->Set('Subject', $newsletter['subject']);

			/**
			 * Setup attachments
			 */
				$email->ClearAttachments();
				$tempAttachments = SendStudio_Functions::GetAttachments('newsletters', $newsletterid, true);
				if ($tempAttachments) {
					$path = $tempAttachments['path'];
					$files = $tempAttachments['filelist'];
					foreach ($files as $p => $file) {
						$email->AddAttachment($path . DIRECTORY_SEPARATOR . $file);
					}
				}
			/**
			 * -----
			 */

			/**
			 * Set up the contents of the newsletter and the formatting (ie. multipart/html only/text only)
			 */
				$format = $newsletter['format'];

				$email->Set('Multipart', false);

				if ($format == 'b' || $format == 't') {
					if ($newsletter['textbody']) {
						$email->AddBody('text', $newsletter['textbody']);
						$email->AppendBody('text', $user->Get('textfooter'));
						$email->AppendBody('text', stripslashes(SENDSTUDIO_TEXTFOOTER));
					}
				}

				if ($format == 'b' || $format == 'h') {
					if ($newsletter['htmlbody']) {
						$email->AddBody('html', $newsletter['htmlbody']);
						$email->AppendBody('html', $user->Get('htmlfooter'));
						$email->AppendBody('html', stripslashes(SENDSTUDIO_HTMLFOOTER));
					}
				}

				if ($format == 'b') {
					if ($newsletter['textbody'] && $newsletter['htmlbody']) {
						$email->Set('Multipart', true);
					} else {
						$email->Set('Multipart', false);
					}
				}
			/**
			 * -----
			 */

			// Setup custom fields
			$customfields = $email->GetCustomFields();

			if (!is_a($email, 'SS_Email_API')) {
				trigger_error('Cannot instantiate email object to be used to send emails', E_USER_NOTICE);
				return $return;
			}

			$email->Debug = $this->_debugMode;
		/**
		 * -----
		 */


		/**
		 * Set up email object for any headers and SMTP server details.
		 * These setup will take account of each trigger records (ie. owner and user as well as stats and other sending related headers)
		 */
			/**
			 * Calculate pause time to make sure it complies with the throttling
			 */
				$pause = $pausetime = 0;
				if ($user->perhour > 0) {
					$pause = $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;
				}
				$userPause = $pausetime;
				$this->_log('UserPause is set to ' . $pausetime);
			/**
			 * -----
			 */

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

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

			// If queue has changed since previous send, update email class for queue related information
			$email->TrackOpens((array_key_exists('trackopens', $triggerrecord['triggeractions']['send']) && $triggerrecord['triggeractions']['send']['trackopens'] == '1'));
			$email->TrackLinks((array_key_exists('tracklinks', $triggerrecord['triggeractions']['send']) && $triggerrecord['triggeractions']['send']['tracklinks'] == '1'));

			$email->Set('statid',			$triggerrecord['statid']);

			$email->Set('FromName',			$triggerrecord['triggeractions']['send']['sendfromname']);
			$email->Set('FromAddress',		$triggerrecord['triggeractions']['send']['sendfromemail']);
			$email->Set('ReplyTo',			$triggerrecord['triggeractions']['send']['replyemail']);
			$email->Set('BounceAddress',	$triggerrecord['triggeractions']['send']['bounceemail']);

			$email->Set('EmbedImages',		((array_key_exists('embedimages', $triggerrecord['triggeractions']['send'])) && $triggerrecord['triggeractions']['send']['embedimages'] == '1'));
			$email->Set('Multipart',		((array_key_exists('multipart', $triggerrecord['triggeractions']['send'])) && $triggerrecord['triggeractions']['send']['multipart'] == '1'));
		/**
		 * -----
		 */


		/**
		 * Set up recipient
		 */
			$subscriberinfo = $subscriberAPI->LoadSubscriberList($recipientid, 0, true);
            
			if (empty($subscriberinfo)) {
				trigger_error('Cannot fetch recipient details', E_USER_NOTICE);
				return $return;
			}

			$listinfo = $this->_cacheListGet($subscriberinfo['listid']);
			if (empty($listinfo)) {
                trigger_error('Unable to load recipient list details', E_USER_NOTICE);
				return $return;
			}

			// List ID for the particualar subscriber
			$email->Set('listids', $subscriberinfo['listid']);

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

			$subscriberinfo['subscriberid'] = $recipientid;
			$subscriberinfo['newsletter'] = $triggerrecord['triggeractions']['send']['newsletterid'];
			$subscriberinfo['listid'] = $subscriberinfo['listid'];
			$subscriberinfo['statid'] = $triggerrecord['statid'];
			$subscriberinfo['listname'] = $listinfo['name'];
			$subscriberinfo['companyname'] = $listinfo['companyname'];
			$subscriberinfo['companyaddress'] = $listinfo['companyaddress'];
			$subscriberinfo['companyphone'] = $listinfo['companyphone'];

			if (!isset($subscriberinfo['CustomFields']) && empty($subscriberinfo['CustomFields'])) {
				$subscriberinfo['CustomFields'] = array();

				/**
				* 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 ($customfields as $fieldid => $fieldname) {
					$subscriberinfo['CustomFields'][] = array(
						'fieldid' => $fieldid,
						'fieldname' => $fieldname,
						'fieldtype' => 'text',
						'defaultvalue' => '',
						'fieldsettings' => '',
						'subscriberid' => $recipientid,
						'data' => ''
					);
				}
			} else {
                require_once(SENDSTUDIO_API_DIRECTORY.'/customfields_date.php');
 
                foreach($subscriberinfo['CustomFields'] as $ar_key => $ar_value){
                    if($ar_value['fieldtype'] == 'date'){
                        $cfdateapi = new CustomFields_Date_API($ar_value['fieldid']);
                        $real_order = $cfdateapi->GetRealValue($ar_value['data']);
                        $subscriberinfo['CustomFields'][$ar_key]['data'] = $real_order;
                    }
                }           
			}

			// TODO refactor
				$name = '';
				$firstname_field = $triggerrecord['triggeractions']['send']['firstnamefield'];
				if ($firstname_field) {
					foreach ($subscriberinfo['CustomFields'] as $p => $details) {
						if ($details['fieldid'] == $firstname_field && $details['data'] != '') {
							$name = $details['data'];
							break;
						}
					}
				}

				$lastname_field = $triggerrecord['triggeractions']['send']['lastnamefield'];
				if ($lastname_field) {
					foreach ($subscriberinfo['CustomFields'] as $p => $details) {
						if ($details['fieldid'] == $lastname_field && $details['data'] != '') {
							$name .= ' ' . $details['data'];
							break;
						}
					}
				}

				if (trim($name) == '') {
					$name = false;
				}
			// --

	            // SetupDynamicContentFields
	            $dctEventListId = (is_array($subscriberinfo['listid']))?$subscriberinfo['listid']:array($subscriberinfo['listid']);
	            $dctEvent =new EventData_IEM_ADDON_DYNAMICCONTENTTAGS_REPLACETAGCONTENT();
	            $dctEvent->lists = $dctEventListId;
	            $dctEvent->info = array($subscriberinfo);
	            $dctEvent->trigger();
	            // --

			$email->ClearRecipients();
			$email->AddRecipient($subscriberinfo['emailaddress'], $name, $subscriberinfo['format'], $subscriberinfo['subscriberid']);
			$email->AddDynamicContentInfo($dctEvent->contentTobeReplaced);
			$email->AddCustomFieldInfo($subscriberinfo['emailaddress'], $subscriberinfo);

			$status = $email->Send(true, true);
			if (!$status['success']) {
				list($return['email'], $return['message']) = $status['fail'][0];
                trigger_error("Failed sending trigger email to {$return['email']}: {$return['message']}");
				return $return;
			}

			$return['listid'] = $subscriberinfo['listid'];
			$return['email'] = $subscriberinfo['emailaddress'];
		/**
		 * -----
		 */

		// Set previous user
		$prevUserID = $user->userid;

		// Set previous queue
		$prevQueueID = $triggerrecord['queueid'];

		$return['result'] = true;

		return $return;
	}
	/**
	* 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;
	}
	/**
	 * SetupJob
	 * This sets up the 'send job' ready to go.
	 * - It checks the "queue" is set up. If it's not, this will return false.
	 * - It loads the newsletter based on the "Newsletter" in the jobdetails array. If it's not a valid newsletter, then this will return false.
	 * - The newsletter gets stored in the newsletter array for easy access.
	 * - Loads the user object (so we can easily look at the per-hour & other sending limits).
	 * - It gets a list of attachments for the newsletter and gives them to the email class
	 * - Sets smtp details for the email class
	 * - Sets stat/listid's for the email class headers to use
	 * - Sets open/link tracking for the email class
	 * - Sets the charset for the email class
	 * - Sets up the rest of the details the email class needs (from details, bounce address, reply-to etc)
	 * - Works out the "userpause" time which is used later on to sleep for a period of time between each email sent
	 * - Gets the custom fields from the content so later on we know which fields to load for each subscriber
	 * - Works out the "to" custom fields so later on we know which fields to load for each subscriber
	 *
	 * @uses IsQueue
	 * @uses Newsletters_API::Load
	 * @uses GetUser
	 * @uses newsletter
	 * @uses SendStudio_Functions::GetAttachments
	 * @uses Email_API
	 * @uses Email_API::AddAttachment
	 * @uses Email_API::AddBody
	 * @uses Email_API::AppendBody
	 * @uses Email_API::ClearAttachments
	 * @uses Email_API::ForceLinkChecks
	 * @uses Email_API::ForgetEmail
	 * @uses Email_API::GetCustomFields
	 * @uses Email_API::Set
	 * @uses Email_API::SetSmtp
	 * @uses Email_API::TrackLinks
	 * @uses Email_API::TrackOpens
	 * @uses userpause
	 * @uses User_API::perhour
	 * @uses custom_fields_to_replace
	 * @uses to_customfields
	 *
	 * @return Boolean Returns false if the 'send queue' isn't set up already, or if the newsletter can't be loaded or doesn't exist.
	 *   Otherwise sets up the email class and other details ready for use, and returns true.
	 */
	function SetupJob($jobid=0, $queueid=0)
	{
		$is_queue = $this->IsQueue($queueid, 'send');
		
		if (!$is_queue) {
			return false;
		}

		// if we can't load the newsletter, pause it and immediately stop.
		$news_loaded = $this->Newsletters_API->Load($this->jobdetails['Newsletter']);
		
		if (!$news_loaded) {
			return false;
		}

		$this->user = GetUser($this->jobowner);
		
		$this->newsletter                = array();
		$this->newsletter['Format']      = $this->Newsletters_API->Get('format');
		$this->newsletter['Subject']     = $this->Newsletters_API->Get('subject');
		$this->newsletter['TextBody']    = $this->Newsletters_API->Get('textbody');
		$this->newsletter['HTMLBody']    = $this->Newsletters_API->Get('htmlbody');
		$this->newsletter['Attachments'] = $this->sendstudio_functions->GetAttachments('newsletters', $this->jobdetails['Newsletter'], true);

		$this->Email_API->ForgetEmail();
		$this->Email_API->SetSmtp(SENDSTUDIO_SMTP_SERVER, SENDSTUDIO_SMTP_USERNAME, @base64_decode(SENDSTUDIO_SMTP_PASSWORD), SENDSTUDIO_SMTP_PORT);
		$this->Email_API->Set('statid', $this->statid);
		$this->Email_API->Set('listids', $this->jobdetails['Lists']);

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

		if ($this->jobdetails['TrackLinks']) {
			$this->Email_API->TrackLinks(true);
		}

		if ($this->jobdetails['TrackOpens']) {
			$this->Email_API->TrackOpens(true);
		}

		$this->Email_API->Set('CharSet', $this->jobdetails['Charset']);

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

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

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

		$this->Email_API->Set('Subject', $this->newsletter['Subject']);
		$this->Email_API->Set('FromName', $this->jobdetails['SendFromName']);
		$this->Email_API->Set('FromAddress', $this->jobdetails['SendFromEmail']);
		$this->Email_API->Set('ReplyTo', $this->jobdetails['ReplyToEmail']);
		$this->Email_API->Set('BounceAddress', $this->jobdetails['BounceEmail']);
		$this->Email_API->Set('Multipart', $this->jobdetails['Multipart']);
		$this->Email_API->Set('EmbedImages', $this->jobdetails['EmbedImages']);
		$this->Email_API->Set('SentBy', $this->user->Get('userid'));

		if ($this->jobdetails['Multipart']) {
			if ($this->newsletter['TextBody'] && $this->newsletter['HTMLBody'] && $this->newsletter['Format'] == 'b') {
				$sent_format = 'm';
			} else {
				$this->Email_API->Set('Multipart', false);
			}
		}

		if ($this->newsletter['TextBody'] && in_array($this->newsletter['Format'], array('t', 'b'))) {
			$this->Email_API->AddBody('text', $this->newsletter['TextBody']);
			$this->Email_API->AppendBody('text', $this->user->Get('textfooter'));
			$this->Email_API->AppendBody('text', stripslashes(SENDSTUDIO_TEXTFOOTER));
		}

		if ($this->newsletter['HTMLBody'] && in_array($this->newsletter['Format'], array('h', 'b'))) {
			$this->Email_API->AddBody('html', $this->newsletter['HTMLBody']);
			$this->Email_API->AppendBody('html', $this->user->Get('htmlfooter'));
			$this->Email_API->AppendBody('html', stripslashes(SENDSTUDIO_HTMLFOOTER));
		}

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

		/*
		 * The following code pauses the sending depending on if userpause
		 * (undescriptive variable name) is set or if the user has gone over
		 * their hourly limit.
		 */
		if (is_null($this->userpause)) {
			$pause      = $pausetime = 0;
			$hourlyRate = $this->user->group->limit_hourlyemailsrate;
			
			/*
			 * If the hourly rate is greater than 0, set the pause time to it.
			 * 
			 * Why originally pause was set to this is logically bad and creates
			 * unclear code. This should be written differently or at least use
			 * better variable names and have been originally commented.
			 * 
			 * @todo refactor
			 */
			if ($hourlyRate > 0) {
				$pause = $hourlyRate;
			}

			// 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;
		}

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

		$to_customfields = array();

		if ($this->jobdetails['To_FirstName']) {
			$to_customfields[] = $this->jobdetails['To_FirstName'];
		}

		if ($this->jobdetails['To_LastName']) {
			$to_customfields[] = $this->jobdetails['To_LastName'];
		}

		$this->to_customfields = array_unique($to_customfields);
		
		return true;
	}