<commit_before><?php
// Copyright (C) 2010-2016 Combodo SARL
//
//   This file is part of iTop.
//
//   iTop is free software; you can redistribute it and/or modify	
//   it under the terms of the GNU Affero General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
//
//   iTop is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU Affero General Public License for more details.
//
//   You should have received a copy of the GNU Affero General Public License
//   along with iTop. If not, see <http://www.gnu.org/licenses/>


/**
 * Send an email (abstraction for synchronous/asynchronous modes)
 *
 * @copyright   Copyright (C) 2010-2016 Combodo SARL
 * @license     http://opensource.org/licenses/AGPL-3.0
 */

require_once(APPROOT.'/lib/swiftmailer/lib/swift_required.php');

Swift_Preferences::getInstance()->setCharset('UTF-8');


define ('EMAIL_SEND_OK', 0);
define ('EMAIL_SEND_PENDING', 1);
define ('EMAIL_SEND_ERROR', 2);

class EMail
{
	// Serialization formats
	const ORIGINAL_FORMAT = 1; // Original format, consisting in serializing the whole object, inculding the Swift Mailer's object.
							   // Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string
	const FORMAT_V2 = 2; // New format, only the raw data are serialized (base64 encoded if needed)
	
	protected static $m_oConfig = null;
	protected $m_aData; // For storing data to serialize

	public function LoadConfig($sConfigFile = ITOP_DEFAULT_CONFIG_FILE)
	{
		if (is_null(self::$m_oConfig))
		{
			self::$m_oConfig = new Config($sConfigFile);
		}
	}

	protected $m_oMessage;

	public function __construct()
	{
		$this->m_aData = array();
		$this->m_oMessage = Swift_Message::newInstance();
	}

	/**
	 * Custom serialization method
	 * No longer use the brute force "serialize" method since
	 * 1) It does not work with binary attachments (since they cannot be stored in a UTF-8 text field)
	 * 2) The size tends to be quite big (sometimes ten times the size of the email)
	 */
	public function SerializeV2()
	{
		return serialize($this->m_aData);
	}
	
	/**
	 * Custom de-serialization method
	 * @param string $sSerializedMessage The serialized representation of the message
	 */
	static public function UnSerializeV2($sSerializedMessage)
	{
		$aData = unserialize($sSerializedMessage);
		$oMessage = new Email();
		
		if (array_key_exists('body', $aData))
		{
			$oMessage->SetBody($aData['body']['body'], $aData['body']['mimeType']);
		}
		if (array_key_exists('message_id', $aData))
		{
			$oMessage->SetMessageId($aData['message_id']);
		}
		if (array_key_exists('bcc', $aData))
		{
			$oMessage->SetRecipientBCC($aData['bcc']);
		}
		if (array_key_exists('cc', $aData))
		{
			$oMessage->SetRecipientCC($aData['cc']);
		}
		if (array_key_exists('from', $aData))
		{
			$oMessage->SetRecipientFrom($aData['from']['address'], $aData['from']['label']);
		}
		if (array_key_exists('reply_to', $aData))
		{
			$oMessage->SetRecipientReplyTo($aData['reply_to']);
		}
		if (array_key_exists('to', $aData))
		{
			$oMessage->SetRecipientTO($aData['to']);
		}
		if (array_key_exists('subject', $aData))
		{
			$oMessage->SetSubject($aData['subject']);
		}
		
		
		if (array_key_exists('headers', $aData))
		{
			foreach($aData['headers'] as $sKey => $sValue)
			{
				$oMessage->AddToHeader($sKey, $sValue);
			}
		}
		if (array_key_exists('parts', $aData))
		{
			foreach($aData['parts'] as $aPart)
			{
				$oMessage->AddPart($aPart['text'], $aPart['mimeType']);
			}
		}
		if (array_key_exists('attachments', $aData))
		{
			foreach($aData['attachments'] as $aAttachment)
			{
				$oMessage->AddAttachment(base64_decode($aAttachment['data']), $aAttachment['filename'], $aAttachment['mimeType']);
			}
		}
		return $oMessage;
	}
	
  	protected function SendAsynchronous(&$aIssues, $oLog = null)
	{
		try
		{
			AsyncSendEmail::AddToQueue($this, $oLog);
		}
		catch(Exception $e)
		{
			$aIssues = array($e->GetMessage());
			return EMAIL_SEND_ERROR;
		}
		$aIssues = array();
		return EMAIL_SEND_PENDING;
	}

	protected function SendSynchronous(&$aIssues, $oLog = null)
	{
		// If the body of the message is in HTML, embed all images based on attachments
		$this->EmbedInlineImages();
		
		$this->LoadConfig();

		$sTransport = self::$m_oConfig->Get('email_transport');
		switch ($sTransport)
		{
		case 'SMTP':
			$sHost = self::$m_oConfig->Get('email_transport_smtp.host');
			$sPort = self::$m_oConfig->Get('email_transport_smtp.port');
			$sEncryption = self::$m_oConfig->Get('email_transport_smtp.encryption');
			$sUserName = self::$m_oConfig->Get('email_transport_smtp.username');
			$sPassword = self::$m_oConfig->Get('email_transport_smtp.password');

			$oTransport = Swift_SmtpTransport::newInstance($sHost, $sPort, $sEncryption);
			if (strlen($sUserName) > 0)
			{
				$oTransport->setUsername($sUserName);
				$oTransport->setPassword($sPassword);
			}
			break;

		case 'Null':
			$oTransport = Swift_NullTransport::newInstance();
			break;
		
		case 'LogFile':
			$oTransport = Swift_LogFileTransport::newInstance();
			$oTransport->setLogFile(APPROOT.'log/mail.log');
			break;
			
		case 'PHPMail':
		default:
			$oTransport = Swift_MailTransport::newInstance();
		}

		$oMailer = Swift_Mailer::newInstance($oTransport);

		$aFailedRecipients = array();
		$this->m_oMessage->setMaxLineLength(0);
IssueLog::Info(__METHOD__.' '.$this->m_oMessage->getMaxLineLength());
IssueLog::Info(__METHOD__.' '.$this->m_oMessage->toString());
		$iSent = $oMailer->send($this->m_oMessage, $aFailedRecipients);
		if ($iSent === 0)
		{
			// Beware: it seems that $aFailedRecipients sometimes contains the recipients that actually received the message !!!
			IssueLog::Warning('Email sending failed: Some recipients were invalid, aFailedRecipients contains: '.implode(', ', $aFailedRecipients));
			$aIssues = array('Some recipients were invalid.');
			return EMAIL_SEND_ERROR;
		}
		else
		{
			$aIssues = array();
			return EMAIL_SEND_OK;
		}
	}
	
	/**
	 * Reprocess the body of the message (if it is an HTML message)
	 * to replace the URL of images based on attachments by a link<commit_msg>#1323 error.log polluted with the contents of each email sent (transport = PHPMail)<commit_after><?php
// Copyright (C) 2010-2016 Combodo SARL
//
//   This file is part of iTop.
//
//   iTop is free software; you can redistribute it and/or modify	
//   it under the terms of the GNU Affero General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
//
//   iTop is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU Affero General Public License for more details.
//
//   You should have received a copy of the GNU Affero General Public License
//   along with iTop. If not, see <http://www.gnu.org/licenses/>


/**
 * Send an email (abstraction for synchronous/asynchronous modes)
 *
 * @copyright   Copyright (C) 2010-2016 Combodo SARL
 * @license     http://opensource.org/licenses/AGPL-3.0
 */

require_once(APPROOT.'/lib/swiftmailer/lib/swift_required.php');

Swift_Preferences::getInstance()->setCharset('UTF-8');


define ('EMAIL_SEND_OK', 0);
define ('EMAIL_SEND_PENDING', 1);
define ('EMAIL_SEND_ERROR', 2);

class EMail
{
	// Serialization formats
	const ORIGINAL_FORMAT = 1; // Original format, consisting in serializing the whole object, inculding the Swift Mailer's object.
							   // Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string
	const FORMAT_V2 = 2; // New format, only the raw data are serialized (base64 encoded if needed)
	
	protected static $m_oConfig = null;
	protected $m_aData; // For storing data to serialize

	public function LoadConfig($sConfigFile = ITOP_DEFAULT_CONFIG_FILE)
	{
		if (is_null(self::$m_oConfig))
		{
			self::$m_oConfig = new Config($sConfigFile);
		}
	}

	protected $m_oMessage;

	public function __construct()
	{
		$this->m_aData = array();
		$this->m_oMessage = Swift_Message::newInstance();
	}

	/**
	 * Custom serialization method
	 * No longer use the brute force "serialize" method since
	 * 1) It does not work with binary attachments (since they cannot be stored in a UTF-8 text field)
	 * 2) The size tends to be quite big (sometimes ten times the size of the email)
	 */
	public function SerializeV2()
	{
		return serialize($this->m_aData);
	}
	
	/**
	 * Custom de-serialization method
	 * @param string $sSerializedMessage The serialized representation of the message
	 */
	static public function UnSerializeV2($sSerializedMessage)
	{
		$aData = unserialize($sSerializedMessage);
		$oMessage = new Email();
		
		if (array_key_exists('body', $aData))
		{
			$oMessage->SetBody($aData['body']['body'], $aData['body']['mimeType']);
		}
		if (array_key_exists('message_id', $aData))
		{
			$oMessage->SetMessageId($aData['message_id']);
		}
		if (array_key_exists('bcc', $aData))
		{
			$oMessage->SetRecipientBCC($aData['bcc']);
		}
		if (array_key_exists('cc', $aData))
		{
			$oMessage->SetRecipientCC($aData['cc']);
		}
		if (array_key_exists('from', $aData))
		{
			$oMessage->SetRecipientFrom($aData['from']['address'], $aData['from']['label']);
		}
		if (array_key_exists('reply_to', $aData))
		{
			$oMessage->SetRecipientReplyTo($aData['reply_to']);
		}
		if (array_key_exists('to', $aData))
		{
			$oMessage->SetRecipientTO($aData['to']);
		}
		if (array_key_exists('subject', $aData))
		{
			$oMessage->SetSubject($aData['subject']);
		}
		
		
		if (array_key_exists('headers', $aData))
		{
			foreach($aData['headers'] as $sKey => $sValue)
			{
				$oMessage->AddToHeader($sKey, $sValue);
			}
		}
		if (array_key_exists('parts', $aData))
		{
			foreach($aData['parts'] as $aPart)
			{
				$oMessage->AddPart($aPart['text'], $aPart['mimeType']);
			}
		}
		if (array_key_exists('attachments', $aData))
		{
			foreach($aData['attachments'] as $aAttachment)
			{
				$oMessage->AddAttachment(base64_decode($aAttachment['data']), $aAttachment['filename'], $aAttachment['mimeType']);
			}
		}
		return $oMessage;
	}
	
  	protected function SendAsynchronous(&$aIssues, $oLog = null)
	{
		try
		{
			AsyncSendEmail::AddToQueue($this, $oLog);
		}
		catch(Exception $e)
		{
			$aIssues = array($e->GetMessage());
			return EMAIL_SEND_ERROR;
		}
		$aIssues = array();
		return EMAIL_SEND_PENDING;
	}

	protected function SendSynchronous(&$aIssues, $oLog = null)
	{
		// If the body of the message is in HTML, embed all images based on attachments
		$this->EmbedInlineImages();
		
		$this->LoadConfig();

		$sTransport = self::$m_oConfig->Get('email_transport');
		switch ($sTransport)
		{
		case 'SMTP':
			$sHost = self::$m_oConfig->Get('email_transport_smtp.host');
			$sPort = self::$m_oConfig->Get('email_transport_smtp.port');
			$sEncryption = self::$m_oConfig->Get('email_transport_smtp.encryption');
			$sUserName = self::$m_oConfig->Get('email_transport_smtp.username');
			$sPassword = self::$m_oConfig->Get('email_transport_smtp.password');

			$oTransport = Swift_SmtpTransport::newInstance($sHost, $sPort, $sEncryption);
			if (strlen($sUserName) > 0)
			{
				$oTransport->setUsername($sUserName);
				$oTransport->setPassword($sPassword);
			}
			break;

		case 'Null':
			$oTransport = Swift_NullTransport::newInstance();
			break;
		
		case 'LogFile':
			$oTransport = Swift_LogFileTransport::newInstance();
			$oTransport->setLogFile(APPROOT.'log/mail.log');
			break;
			
		case 'PHPMail':
		default:
			$oTransport = Swift_MailTransport::newInstance();
		}

		$oMailer = Swift_Mailer::newInstance($oTransport);

		$aFailedRecipients = array();
		$this->m_oMessage->setMaxLineLength(0);
		$iSent = $oMailer->send($this->m_oMessage, $aFailedRecipients);
		if ($iSent === 0)
		{
			// Beware: it seems that $aFailedRecipients sometimes contains the recipients that actually received the message !!!
			IssueLog::Warning('Email sending failed: Some recipients were invalid, aFailedRecipients contains: '.implode(', ', $aFailedRecipients));
			$aIssues = array('Some recipients were invalid.');
			return EMAIL_SEND_ERROR;
		}
		else
		{
			$aIssues = array();
			return EMAIL_SEND_OK;
		}
	}
	
	/**
	 * Reprocess the body of the message (if it is an HTML message)
	 * to replace the URL of images based on attachments by a link
{'fraction_non_alphanumeric': 0.1433428209993675, 'fraction_numerical': 0.006483238456672992, 'mean_word_length': 4.244195688225539, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2192739', 'n_tokens_mistral': 4750, 'n_tokens_neox': 4199, 'n_words': 1030}