use_queue = (!$config['email_package_size']) ? false : $use_queue;
		$this->subject = '';
		// Determine EOL character (\n for UNIX, \r\n for Windows and \r for Mac)
		$this->eol = (!defined('PHP_EOL')) ? (($eol = strtolower(substr(PHP_OS, 0, 3))) == 'win') ? "\r\n" : (($eol == 'mac') ? "\r" : "\n") : PHP_EOL;
		$this->eol = (!$this->eol) ? "\n" : $this->eol;
	}
	/**
	* Resets all the data (address, template file, etc etc) to default
	*/
	function reset()
	{
		$this->addresses = $this->extra_headers = array();
		$this->msg = $this->replyto = $this->from = '';
		$this->mail_priority = MAIL_NORMAL_PRIORITY;
	}
	/**
	* Set addresses for to/im as available
	*
	* @param array $user User row
	*/
	function set_addresses($user)
	{
		if (isset($user['user_email']) && $user['user_email'])
		{
			$this->to($user['user_email'], (isset($user['username']) ? $user['username'] : ''));
		}
		if (isset($user['user_jabber']) && $user['user_jabber'])
		{
			$this->im($user['user_jabber'], (isset($user['username']) ? $user['username'] : ''));
		}
	}
	/**
	* Sets an email address to send to
	*/
	function to($address, $realname = '')
	{
		global $config;
		if (!trim($address))
		{
			return;
		}
		$pos = isset($this->addresses['to']) ? sizeof($this->addresses['to']) : 0;
		$this->addresses['to'][$pos]['email'] = trim($address);
		// If empty sendmail_path on windows, PHP changes the to line
		if (!$config['smtp_delivery'] && DIRECTORY_SEPARATOR == '\\')
		{
			$this->addresses['to'][$pos]['name'] = '';
		}
		else
		{
			$this->addresses['to'][$pos]['name'] = trim($realname);
		}
	}
	/**
	* Sets an cc address to send to
	*/
	function cc($address, $realname = '')
	{
		if (!trim($address))
		{
			return;
		}
		$pos = isset($this->addresses['cc']) ? sizeof($this->addresses['cc']) : 0;
		$this->addresses['cc'][$pos]['email'] = trim($address);
		$this->addresses['cc'][$pos]['name'] = trim($realname);
	}
	/**
	* Sets an bcc address to send to
	*/
	function bcc($address, $realname = '')
	{
		if (!trim($address))
		{
			return;
		}
		$pos = isset($this->addresses['bcc']) ? sizeof($this->addresses['bcc']) : 0;
		$this->addresses['bcc'][$pos]['email'] = trim($address);
		$this->addresses['bcc'][$pos]['name'] = trim($realname);
	}
	/**
	* Sets a im contact to send to
	*/
	function im($address, $realname = '')
	{
		// IM-Addresses could be empty
		if (!trim($address))
		{
			return;
		}
		$pos = isset($this->addresses['im']) ? sizeof($this->addresses['im']) : 0;
		$this->addresses['im'][$pos]['uid'] = trim($address);
		$this->addresses['im'][$pos]['name'] = trim($realname);
	}
	/**
	* Set the reply to address
	*/
	function replyto($address)
	{
		$this->replyto = trim($address);
	}
	/**
	* Set the from address
	*/
	function from($address)
	{
		$this->from = trim($address);
	}
	/**
	* set up subject for mail
	*/
	function subject($subject = '')
	{
		$this->subject = trim($subject);
	}
	/**
	* set up extra mail headers
	*/
	function headers($headers)
	{
		$this->extra_headers[] = trim($headers);
	}
	/**
	* Adds X-AntiAbuse headers
	*
	* @param array $config		Configuration array
	* @param user $user			A user object
	*
	* @return null
	*/
	function anti_abuse_headers($config, $user)
	{
		$this->headers('X-AntiAbuse: Board servername - ' . mail_encode($config['server_name']));
		$this->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']);
		$this->headers('X-AntiAbuse: Username - ' . mail_encode($user->data['username']));
		$this->headers('X-AntiAbuse: User IP - ' . $user->ip);
	}
	/**
	* Set the email priority
	*/
	function set_mail_priority($priority = MAIL_NORMAL_PRIORITY)
	{
		$this->mail_priority = $priority;
	}
	/**
	* Set email template to use
	*/
	function template($template_file, $template_lang = '', $template_path = '')
	{
		global $config, $phpbb_root_path, $phpEx, $user, $phpbb_extension_manager;
		$this->setup_template();
		if (!trim($template_file))
		{
			trigger_error('No template file for emailing set.', E_USER_ERROR);
		}
		if (!trim($template_lang))
		{
			// fall back to board default language if the user's language is
			// missing $template_file.  If this does not exist either,
			// $this->template->set_filenames will do a trigger_error
			$template_lang = basename($config['default_lang']);
		}
		if ($template_path)
		{
			$template_paths = array(
				$template_path,
			);
		}
		else
		{
			$template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
			$template_path .= $template_lang . '/email';
			$template_paths = array(
				$template_path,
			);
			// we can only specify default language fallback when the path is not a custom one for which we
			// do not know the default language alternative
			if ($template_lang !== basename($config['default_lang']))
			{
				$fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
				$fallback_template_path .= basename($config['default_lang']) . '/email';
				$template_paths[] = $fallback_template_path;
			}
		}
		$this->set_template_paths($template_lang . '_email', $template_paths);
		$this->template->set_filenames(array(
			'body'		=> $template_file . '.txt',
		));
		return true;
	}
	/**
	* assign variables to email template
	*/
	function assign_vars($vars)
	{
		$this->setup_template();
		$this->template->assign_vars($vars);
	}
	function assign_block_vars($blockname, $vars)
	{
		$this->setup_template();
		$this->template->assign_block_vars($blockname, $vars);
	}
	/**
	* Send the mail out to the recipients set previously in var $this->addresses
	*/
	function send($method = NOTIFY_EMAIL, $break = false)
	{
		global $config, $user;
		// We add some standard variables we always use, no need to specify them always
		$this->assign_vars(array(
			'U_BOARD'	=> generate_board_url(),
			'EMAIL_SIG'	=> str_replace('
', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])),
			'SITENAME'	=> htmlspecialchars_decode($config['sitename']),
		));
		// Parse message through template
		$this->msg = trim($this->template->assign_display('body'));
		// Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding
		$this->msg = str_replace("\r\n", "\n", $this->msg);
		// We now try and pull a subject from the email body ... if it exists,
		// do this here because the subject may contain a variable
		$drop_header = '';
		$match = array();
		if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match))
		{
			$this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
			$drop_header .= '[\r\n]*?' . preg_quote($match[1], '#');
		}
		else
		{
			$this->subject = (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
		}
		if ($drop_header)
		{
			$this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg));
		}
		if ($break)
		{
			return true;
		}
		switch ($method)
		{
			case NOTIFY_EMAIL:
				$result = $this->msg_email();
			break;
			case NOTIFY_IM:
				$result = $this->msg_jabber();
			break;
			case NOTIFY_BOTH:
				$result = $this->msg_email();
				$this->msg_jabber();
			break;
		}
		$this->reset();
		return $result;
	}
	/**
	* Add error message to log
	*/
	function error($type, $msg)
	{
		global $user, $phpEx, $phpbb_root_path, $config, $request;
		// Session doesn't exist, create it
		if (!isset($user->session_id) || $user->session_id === '')
		{
			$user->session_begin();
		}
		$calling_page = htmlspecialchars_decode($request->server('PHP_SELF'));
		$message = '';
		switch ($type)
		{
			case 'EMAIL':
				$message = 'EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/' . $config['email_function_name'] . '()') . '';
			break;
			default:
				$message = "$type";
			break;
		}
		$message .= '
' . htmlspecialchars($calling_page) . '
' . $msg . '
';
		add_log('critical', 'LOG_ERROR_' . $type, $message);
	}
	/**
	* Save to queue
	*/
	function save_queue()
	{
		global $config;
		if ($config['email_package_size'] && $this->use_queue && !empty($this->queue))
		{
			$this->queue->save();
			return;
		}
	}
	/**
	* Generates a valid message id to be used in emails
	*
	* @return string message id
	*/
	function generate_message_id()
	{
		global $config;
		$domain = 'phpbb.generated';
		if ($config['server_name'])
		{
			$domain = $config['server_name'];
		}
		else if (!empty($_SERVER['SERVER_NAME']))
		{
			$domain = $_SERVER['SERVER_NAME'];
		}
		return md5(unique_id(time())) . '@' . $domain;
	}
	/**
	* Return email header
	*/
	function build_header($to, $cc, $bcc)
	{
		global $config;
		// We could use keys here, but we won't do this for 3.0.x to retain backwards compatibility
		$headers = array();
		$headers[] = 'From: ' . $this->from;
		if ($cc)
		{
			$headers[] = 'Cc: ' . $cc;
		}
		if ($bcc)
		{
			$headers[] = 'Bcc: ' . $bcc;
		}
		$headers[] = 'Reply-To: ' . $this->replyto;
		$headers[] = 'Return-Path: <' . $config['board_email'] . '>';
		$headers[] = 'Sender: <' . $config['board_email'] . '>';
		$headers[] = 'MIME-Version: 1.0';
		$headers[] = 'Message-ID: <' . $this->generate_message_id() . '>';
		$headers[] = 'Date: ' . date('r', time());
		$headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed
		$headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit
		$headers[] = 'X-Priority: ' . $this->mail_priority;
		$headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High'));
		$headers[] = 'X-Mailer: phpBB3';
		$headers[] = 'X-MimeOLE: phpBB3';
		$headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url());
		if (sizeof($this->extra_headers))
		{
			$headers = array_merge($headers, $this->extra_headers);
		}
		return $headers;
	}
	/**
	* Send out emails
	*/
	function msg_email()
	{
		global $config, $user;
		if (empty($config['email_enable']))
		{
			return false;
		}
		// Addresses to send to?
		if (empty($this->addresses) || (empty($this->addresses['to']) && empty($this->addresses['cc']) && empty($this->addresses['bcc'])))
		{
			// Send was successful. ;)
			return true;
		}
		$use_queue = false;
		if ($config['email_package_size'] && $this->use_queue)
		{
			if (empty($this->queue))
			{
				$this->queue = new queue();
				$this->queue->init('email', $config['email_package_size']);
			}
			$use_queue = true;
		}
		if (empty($this->replyto))
		{
			$this->replyto = '<' . $config['board_contact'] . '>';
		}
		if (empty($this->from))
		{
			$this->from = '<' . $config['board_contact'] . '>';
		}
		$encode_eol = ($config['smtp_delivery']) ? "\r\n" : $this->eol;
		// Build to, cc and bcc strings
		$to = $cc = $bcc = '';
		foreach ($this->addresses as $type => $address_ary)
		{
			if ($type == 'im')
			{
				continue;
			}
			foreach ($address_ary as $which_ary)
			{
				$$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']);
			}
		}
		// Build header
		$headers = $this->build_header($to, $cc, $bcc);
		// Send message ...
		if (!$use_queue)
		{
			$mail_to = ($to == '') ? 'undisclosed-recipients:;' : $to;
			$err_msg = '';
			if ($config['smtp_delivery'])
			{
				$result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $err_msg, $headers);
			}
			else
			{
				$result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, $this->eol, $err_msg);
			}
			if (!$result)
			{
				$this->error('EMAIL', $err_msg);
				return false;
			}
		}
		else
		{
			$this->queue->put('email', array(
				'to'			=> $to,
				'addresses'		=> $this->addresses,
				'subject'		=> $this->subject,
				'msg'			=> $this->msg,
				'headers'		=> $headers)
			);
		}
		return true;
	}
	/**
	* Send jabber message out
	*/
	function msg_jabber()
	{
		global $config, $db, $user, $phpbb_root_path, $phpEx;
		if (empty($config['jab_enable']) || empty($config['jab_host']) || empty($config['jab_username']) || empty($config['jab_password']))
		{
			return false;
		}
		if (empty($this->addresses['im']))
		{
			// Send was successful. ;)
			return true;
		}
		$use_queue = false;
		if ($config['jab_package_size'] && $this->use_queue)
		{
			if (empty($this->queue))
			{
				$this->queue = new queue();
				$this->queue->init('jabber', $config['jab_package_size']);
			}
			$use_queue = true;
		}
		$addresses = array();
		foreach ($this->addresses['im'] as $type => $uid_ary)
		{
			$addresses[] = $uid_ary['uid'];
		}
		$addresses = array_unique($addresses);
		if (!$use_queue)
		{
			include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
			$this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl']);
			if (!$this->jabber->connect())
			{
				$this->error('JABBER', $user->lang['ERR_JAB_CONNECT'] . '
' . $this->jabber->get_log());
				return false;
			}
			if (!$this->jabber->login())
			{
				$this->error('JABBER', $user->lang['ERR_JAB_AUTH'] . '
' . $this->jabber->get_log());
				return false;
			}
			foreach ($addresses as $address)
			{
				$this->jabber->send_message($address, $this->msg, $this->subject);
			}
			$this->jabber->disconnect();
		}
		else
		{
			$this->queue->put('jabber', array(
				'addresses'		=> $addresses,
				'subject'		=> $this->subject,
				'msg'			=> $this->msg)
			);
		}
		unset($addresses);
		return true;
	}
	/**
	* Setup template engine
	*/
	protected function setup_template()
	{
		global $config, $phpbb_path_helper, $user, $phpbb_extension_manager;
		if ($this->template instanceof \phpbb\template\template)
		{
			return;
		}
		$this->template = new \phpbb\template\twig\twig($phpbb_path_helper, $config, $user, new \phpbb\template\context(), $phpbb_extension_manager);
	}
	/**
	* Set template paths to load
	*/
	protected function set_template_paths($path_name, $paths)
	{
		$this->setup_template();
		$this->template->set_custom_style($path_name, $paths);
	}
}
/**
* handling email and jabber queue
* @package phpBB3
*/
class queue
{
	var $data = array();
	var $queue_data = array();
	var $package_size = 0;
	var $cache_file = '';
	var $eol = "\n";
	/**
	* constructor
	*/
	function queue()
	{
		global $phpEx, $phpbb_root_path;
		$this->data = array();
		$this->cache_file = "{$phpbb_root_path}cache/queue.$phpEx";
		// Determine EOL character (\n for UNIX, \r\n for Windows and \r for Mac)
		$this->eol = (!defined('PHP_EOL')) ? (($eol = strtolower(substr(PHP_OS, 0, 3))) == 'win') ? "\r\n" : (($eol == 'mac') ? "\r" : "\n") : PHP_EOL;
		$this->eol = (!$this->eol) ? "\n" : $this->eol;
	}
	/**
	* Init a queue object
	*/
	function init($object, $package_size)
	{
		$this->data[$object] = array();
		$this->data[$object]['package_size'] = $package_size;
		$this->data[$object]['data'] = array();
	}
	/**
	* Put object in queue
	*/
	function put($object, $scope)
	{
		$this->data[$object]['data'][] = $scope;
	}
	/**
	* Process queue
	* Using lock file
	*/
	function process()
	{
		global $db, $config, $phpEx, $phpbb_root_path, $user;
		$lock = new \phpbb\lock\flock($this->cache_file);
		$lock->acquire();
		// avoid races, check file existence once
		$have_cache_file = file_exists($this->cache_file);
		if (!$have_cache_file || $config['last_queue_run'] > time() - $config['queue_interval'])
		{
			if (!$have_cache_file)
			{
				set_config('last_queue_run', time(), true);
			}
			$lock->release();
			return;
		}
		set_config('last_queue_run', time(), true);
		include($this->cache_file);
		foreach ($this->queue_data as $object => $data_ary)
		{
			@set_time_limit(0);
			if (!isset($data_ary['package_size']))
			{
				$data_ary['package_size'] = 0;
			}
			$package_size = $data_ary['package_size'];
			$num_items = (!$package_size || sizeof($data_ary['data']) < $package_size) ? sizeof($data_ary['data']) : $package_size;
			/*
			* This code is commented out because it causes problems on some web hosts.
			* The core problem is rather restrictive email sending limits.
			* This code is nly useful if you have no such restrictions from the
			* web host and the package size setting is wrong.
			// If the amount of emails to be sent is way more than package_size than we need to increase it to prevent backlogs...
			if (sizeof($data_ary['data']) > $package_size * 2.5)
			{
				$num_items = sizeof($data_ary['data']);
			}
			*/
			switch ($object)
			{
				case 'email':
					// Delete the email queued objects if mailing is disabled
					if (!$config['email_enable'])
					{
						unset($this->queue_data['email']);
						continue 2;
					}
				break;
				case 'jabber':
					if (!$config['jab_enable'])
					{
						unset($this->queue_data['jabber']);
						continue 2;
					}
					include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
					$this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl']);
					if (!$this->jabber->connect())
					{
						messenger::error('JABBER', $user->lang['ERR_JAB_CONNECT']);
						continue 2;
					}
					if (!$this->jabber->login())
					{
						messenger::error('JABBER', $user->lang['ERR_JAB_AUTH']);
						continue 2;
					}
				break;
				default:
					$lock->release();
					return;
			}
			for ($i = 0; $i < $num_items; $i++)
			{
				// Make variables available...
				extract(array_shift($this->queue_data[$object]['data']));
				switch ($object)
				{
					case 'email':
						$err_msg = '';
						$to = (!$to) ? 'undisclosed-recipients:;' : $to;
						if ($config['smtp_delivery'])
						{
							$result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers);
						}
						else
						{
							$result = phpbb_mail($to, $subject, $msg, $headers, $this->eol, $err_msg);
						}
						if (!$result)
						{
							messenger::error('EMAIL', $err_msg);
							continue 2;
						}
					break;
					case 'jabber':
						foreach ($addresses as $address)
						{
							if ($this->jabber->send_message($address, $msg, $subject) === false)
							{
								messenger::error('JABBER', $this->jabber->get_log());
								continue 3;
							}
						}
					break;
				}
			}
			// No more data for this object? Unset it
			if (!sizeof($this->queue_data[$object]['data']))
			{
				unset($this->queue_data[$object]);
			}
			// Post-object processing
			switch ($object)
			{
				case 'jabber':
					// Hang about a couple of secs to ensure the messages are
					// handled, then disconnect
					$this->jabber->disconnect();
				break;
			}
		}
		if (!sizeof($this->queue_data))
		{
			@unlink($this->cache_file);
		}
		else
		{
			if ($fp = @fopen($this->cache_file, 'wb'))
			{
				fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>");
				fclose($fp);
				phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
			}
		}
		$lock->release();
	}
	/**
	* Save queue
	*/
	function save()
	{
		if (!sizeof($this->data))
		{
			return;
		}
		$lock = new \phpbb\lock\flock($this->cache_file);
		$lock->acquire();
		if (file_exists($this->cache_file))
		{
			include($this->cache_file);
			foreach ($this->queue_data as $object => $data_ary)
			{
				if (isset($this->data[$object]) && sizeof($this->data[$object]))
				{
					$this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']);
				}
				else
				{
					$this->data[$object]['data'] = $data_ary['data'];
				}
			}
		}
		if ($fp = @fopen($this->cache_file, 'w'))
		{
			fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>");
			fclose($fp);
			phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
		}
		$lock->release();
	}
}
/**
* Replacement or substitute for PHP's mail command
*/
function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false)
{
	global $config, $user;
	// Fix any bare linefeeds in the message to make it RFC821 Compliant.
	$message = preg_replace("#(?lang['NO_EMAIL_SUBJECT'])) ? $user->lang['NO_EMAIL_SUBJECT'] : 'No email subject specified';
		return false;
	}
	if (trim($message) == '')
	{
		$err_msg = (isset($user->lang['NO_EMAIL_MESSAGE'])) ? $user->lang['NO_EMAIL_MESSAGE'] : 'Email message was blank';
		return false;
	}
	$mail_rcpt = $mail_to = $mail_cc = array();
	// Build correct addresses for RCPT TO command and the client side display (TO, CC)
	if (isset($addresses['to']) && sizeof($addresses['to']))
	{
		foreach ($addresses['to'] as $which_ary)
		{
			$mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>';
			$mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>';
		}
	}
	if (isset($addresses['bcc']) && sizeof($addresses['bcc']))
	{
		foreach ($addresses['bcc'] as $which_ary)
		{
			$mail_rcpt['bcc'][] = '<' . trim($which_ary['email']) . '>';
		}
	}
	if (isset($addresses['cc']) && sizeof($addresses['cc']))
	{
		foreach ($addresses['cc'] as $which_ary)
		{
			$mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>';
			$mail_rcpt['cc'][] = '<' . trim($which_ary['email']) . '>';
		}
	}
	$smtp = new smtp_class();
	$errno = 0;
	$errstr = '';
	$smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']);
	// Ok we have error checked as much as we can to this point let's get on it already.
	if (!class_exists('\phpbb\error_collector'))
	{
		global $phpbb_root_path, $phpEx;
		include($phpbb_root_path . 'includes/error_collector.' . $phpEx);
	}
	$collector = new \phpbb\error_collector;
	$collector->install();
	$smtp->socket = fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 20);
	$collector->uninstall();
	$error_contents = $collector->format_errors();
	if (!$smtp->socket)
	{
		if ($errstr)
		{
			$errstr = utf8_convert_message($errstr);
		}
		$err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr";
		$err_msg .= ($error_contents) ? '
' . htmlspecialchars($error_contents) : '';
		return false;
	}
	// Wait for reply
	if ($err_msg = $smtp->server_parse('220', __LINE__))
	{
		$smtp->close_session($err_msg);
		return false;
	}
	// Let me in. This function handles the complete authentication process
	if ($err_msg = $smtp->log_into_server($config['smtp_host'], $config['smtp_username'], htmlspecialchars_decode($config['smtp_password']), $config['smtp_auth_method']))
	{
		$smtp->close_session($err_msg);
		return false;
	}
	// From this point onward most server response codes should be 250
	// Specify who the mail is from....
	$smtp->server_send('MAIL FROM:<' . $config['board_email'] . '>');
	if ($err_msg = $smtp->server_parse('250', __LINE__))
	{
		$smtp->close_session($err_msg);
		return false;
	}
	// Specify each user to send to and build to header.
	$to_header = implode(', ', $mail_to);
	$cc_header = implode(', ', $mail_cc);
	// Now tell the MTA to send the Message to the following people... [TO, BCC, CC]
	$rcpt = false;
	foreach ($mail_rcpt as $type => $mail_to_addresses)
	{
		foreach ($mail_to_addresses as $mail_to_address)
		{
			// Add an additional bit of error checking to the To field.
			if (preg_match('#[^ ]+\@[^ ]+#', $mail_to_address))
			{
				$smtp->server_send("RCPT TO:$mail_to_address");
				if ($err_msg = $smtp->server_parse('250', __LINE__))
				{
					// We continue... if users are not resolved we do not care
					if ($smtp->numeric_response_code != 550)
					{
						$smtp->close_session($err_msg);
						return false;
					}
				}
				else
				{
					$rcpt = true;
				}
			}
		}
	}
	// We try to send messages even if a few people do not seem to have valid email addresses, but if no one has, we have to exit here.
	if (!$rcpt)
	{
		$user->session_begin();
		$err_msg .= '
';
		$err_msg .= (isset($user->lang['INVALID_EMAIL_LOG'])) ? sprintf($user->lang['INVALID_EMAIL_LOG'], htmlspecialchars($mail_to_address)) : '' . htmlspecialchars($mail_to_address) . ' possibly an invalid email address?';
		$smtp->close_session($err_msg);
		return false;
	}
	// Ok now we tell the server we are ready to start sending data
	$smtp->server_send('DATA');
	// This is the last response code we look for until the end of the message.
	if ($err_msg = $smtp->server_parse('354', __LINE__))
	{
		$smtp->close_session($err_msg);
		return false;
	}
	// Send the Subject Line...
	$smtp->server_send("Subject: $subject");
	// Now the To Header.
	$to_header = ($to_header == '') ? 'undisclosed-recipients:;' : $to_header;
	$smtp->server_send("To: $to_header");
	// Now the CC Header.
	if ($cc_header != '')
	{
		$smtp->server_send("CC: $cc_header");
	}
	// Now any custom headers....
	if ($headers !== false)
	{
		$smtp->server_send("$headers\r\n");
	}
	// Ok now we are ready for the message...
	$smtp->server_send($message);
	// Ok the all the ingredients are mixed in let's cook this puppy...
	$smtp->server_send('.');
	if ($err_msg = $smtp->server_parse('250', __LINE__))
	{
		$smtp->close_session($err_msg);
		return false;
	}
	// Now tell the server we are done and close the socket...
	$smtp->server_send('QUIT');
	$smtp->close_session($err_msg);
	return true;
}
/**
* SMTP Class
* Auth Mechanisms originally taken from the AUTH Modules found within the PHP Extension and Application Repository (PEAR)
* See docs/AUTHORS for more details
* @package phpBB3
*/
class smtp_class
{
	var $server_response = '';
	var $socket = 0;
	protected $socket_tls = false;
	var $responses = array();
	var $commands = array();
	var $numeric_response_code = 0;
	var $backtrace = false;
	var $backtrace_log = array();
	function smtp_class()
	{
		// Always create a backtrace for admins to identify SMTP problems
		$this->backtrace = true;
		$this->backtrace_log = array();
	}
	/**
	* Add backtrace message for debugging
	*/
	function add_backtrace($message)
	{
		if ($this->backtrace)
		{
			$this->backtrace_log[] = utf8_htmlspecialchars($message);
		}
	}
	/**
	* Send command to smtp server
	*/
	function server_send($command, $private_info = false)
	{
		fputs($this->socket, $command . "\r\n");
		(!$private_info) ? $this->add_backtrace("# $command") : $this->add_backtrace('# Omitting sensitive information');
		// We could put additional code here
	}
	/**
	* We use the line to give the support people an indication at which command the error occurred
	*/
	function server_parse($response, $line)
	{
		global $user;
		$this->server_response = '';
		$this->responses = array();
		$this->numeric_response_code = 0;
		while (substr($this->server_response, 3, 1) != ' ')
		{
			if (!($this->server_response = fgets($this->socket, 256)))
			{
				return (isset($user->lang['NO_EMAIL_RESPONSE_CODE'])) ? $user->lang['NO_EMAIL_RESPONSE_CODE'] : 'Could not get mail server response codes';
			}
			$this->responses[] = substr(rtrim($this->server_response), 4);
			$this->numeric_response_code = (int) substr($this->server_response, 0, 3);
			$this->add_backtrace("LINE: $line <- {$this->server_response}");
		}
		if (!(substr($this->server_response, 0, 3) == $response))
		{
			$this->numeric_response_code = (int) substr($this->server_response, 0, 3);
			return (isset($user->lang['EMAIL_SMTP_ERROR_RESPONSE'])) ? sprintf($user->lang['EMAIL_SMTP_ERROR_RESPONSE'], $line, $this->server_response) : "Ran into problems sending Mail at Line $line. Response: $this->server_response";
		}
		return 0;
	}
	/**
	* Close session
	*/
	function close_session(&$err_msg)
	{
		fclose($this->socket);
		if ($this->backtrace)
		{
			$message = '
' . implode('
', $this->backtrace_log) . '