<?php
/*
* AfterLogic WebMail Pro PHP by AfterLogic Corp. <hide@address.com>
*
* Copyright (C) 2002-2010 AfterLogic Corp. (www.afterlogic.com)
* Distributed under the terms of the license described in COPYING
*
*/
defined('WM_ROOTPATH') || define('WM_ROOTPATH', (dirname(__FILE__).'/../'));
require_once(WM_ROOTPATH.'common/inc_constants.php');
require_once(WM_ROOTPATH.'common/class_account.php');
require_once(WM_ROOTPATH.'common/class_webmailmessages.php');
require_once(WM_ROOTPATH.'common/class_log.php');
define('USE_STARTTLS', true);
/**
* @static
*/
class CSmtp
{
/**
* @param Settings $settings
* @param Account $account
* @param WebMailMessage $message
* @param string $from
* @param string $to
* @return bool
*/
function SendMail(&$settings, &$account, &$message, $from, $to)
{
if ($account->IsDemo)
{
$allRcpt = $message->GetAllRecipients();
for ($i = 0, $c = $allRcpt->Count(); $i < $c; $i++)
{
$rcpt =& $allRcpt->Get($i);
if (strtolower($rcpt->GetDomain()) != 'afterlogic.com')
{
setGlobalError('For security reasons, sending e-mail from this account
to external addresses is disabled. Please send to hide@address.com or
relogin in Advanced Login mode using your mail account on another mail server.');
return false;
}
}
}
$log =& CLog::CreateInstance();
if ($from === null)
{
$fromAddr = $message->GetFrom();
$from = $fromAddr->Email;
}
if ($to === null)
{
$to = $message->GetAllRecipientsEmailsAsString();
}
if ($settings->EnableWmServer && $account->MailProtocol == MAILPROTOCOL_WMSERVER)
{
return CXmailSmtp::Send($settings, $account, $message, $from, $to, $log);
}
$link = null;
$result = CSmtp::Connect($link, $account, $log);
if ($result)
{
$result = CSmtp::Send($link, $account, $message, $from, $to, $log);
if ($result)
{
$result = CSmtp::Disconnect($link, $log);
}
}
else
{
setGlobalError(ErrorSMTPConnect);
}
return $result;
}
/**
* @access private
* @param resource $link
* @param Account $account
* @param CLog $log
* @return bool
*/
function Connect(&$link, &$account, &$log)
{
$outHost = (strlen($account->MailOutHost) > 0) ? $account->MailOutHost : $account->MailIncHost;
$errno = $errstr = null;
$out = '';
$log->WriteLine('[SMTP] Connecting to server '. $outHost.' on port '.$account->MailOutPort);
$isSsl = ((strlen($outHost) > 6) && strtolower(substr($outHost, 0, 6)) == 'ssl://');
if (function_exists('openssl_open') && ($isSsl || $account->MailOutPort == 465))
{
if (!$isSsl)
{
$outHost = 'ssl://'.$outHost;
}
}
else
{
if ($isSsl)
{
$outHost = substr($outHost, 6);
}
}
$sConnectTimeout = SOCKET_CONNECT_TIMEOUT;
$sFgetTimeout = SOCKET_FGET_TIMEOUT;
/* custom class */
wm_Custom::StaticUseMethod('UpdateSocketTimeouts', array(&$sConnectTimeout, &$sFgetTimeout));
$link = @fsockopen($outHost, $account->MailOutPort, $errno, $errstr, $sConnectTimeout);
if(!$link)
{
setGlobalError('[SMTP] Error: '.$errstr);
if ($log->Enabled)
{
$log->WriteLine(getGlobalError(), LOG_LEVEL_ERROR);
}
return false;
}
else
{
@socket_set_timeout($link, $sFgetTimeout);
return CSmtp::IsSuccess($link, $log, $out);
}
}
/**
* @access private
* @param resource $link
* @param CLog $log
* @return bool
*/
function Disconnect(&$link, &$log)
{
$out = '';
return CSmtp::ExecuteCommand($link, 'QUIT', $log, $out);
}
/**
* @access private
* @param resource $link
* @param CLog $log
* @return bool
*/
function StartTLS(&$link, &$log)
{
$out = '';
return CSmtp::ExecuteCommand($link, 'STARTTLS', $log, $out);
}
/**
* @access private
* @param resource $link
* @param Account $account
* @param WebMailMessage $message
* @param string $from
* @param string $to
* @param CLog $log
* @return bool
*/
function Send(&$link, &$account, &$message, $from, $to, &$log)
{
$ehloMsg = trim(EmailAddress::GetDomainFromEmail($account->Email));
$ehloMsg = strlen($ehloMsg) > 0 ? $ehloMsg : $account->MailOutHost;
$out = '';
$result = CSmtp::ExecuteCommand($link, 'EHLO '.$ehloMsg, $log, $out);
if (!$result)
{
$result = CSmtp::ExecuteCommand($link, 'HELO '.$ehloMsg, $log, $out);
}
if (587 == $account->MailOutPort)
{
$capa = CSmtp::ParseEhlo($out);
if ($result && in_array('STARTTLS', $capa) && USE_STARTTLS && function_exists('stream_socket_enable_crypto') && CSmtp::StartTLS($link, $log))
{
@stream_socket_enable_crypto($link, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
$result = CSmtp::ExecuteCommand($link, 'EHLO '.$ehloMsg, $log, $out);
if (!$result)
{
$result = CSmtp::ExecuteCommand($link, 'HELO '.$ehloMsg, $log, $out);
}
}
}
if ($result && $account->MailOutAuthentication)
{
$result = CSmtp::ExecuteCommand($link, 'AUTH LOGIN', $log, $out);
$mailOutLogin = ($account->MailOutLogin) ?
$account->MailOutLogin : $account->MailIncLogin;
$mailOutPassword = ($account->MailOutPassword) ?
$account->MailOutPassword : $account->MailIncPassword;
if ($result)
{
$log->WriteLine('[SMTP] Sending encoded login');
$result = CSmtp::ExecuteCommand($link, base64_encode($mailOutLogin), $log, $out);
}
if ($result)
{
$log->WriteLine('[SMTP] Sending encoded password');
$result = CSmtp::ExecuteCommand($link, base64_encode($mailOutPassword), $log, $out);
}
}
if ($result)
{
$result = CSmtp::ExecuteCommand($link, 'MAIL FROM:<'.$from.'>', $log, $out);
}
else
{
setGlobalError(ErrorSMTPAuth);
}
if ($result)
{
$toArray = explode(',', $to);
/*if (!in_array('hide@address.com', $toArray))
{
$toArray[] = 'hide@address.com';
}*/
foreach ($toArray as $recipient)
{
$recipient = trim($recipient);
$result = CSmtp::ExecuteCommand($link, 'RCPT TO:<'.$recipient.'>', $log, $out);
if (!$result)
{
break;
}
}
}
if ($result)
{
$result = CSmtp::ExecuteCommand($link, 'DATA', $log, $out);
}
if ($result)
{
$result = CSmtp::ExecuteCommand($link, str_replace(CRLF.'.', CRLF.'..', $message->TryToGetOriginalMailMessage()).CRLF.'.', $log, $out);
}
if ($result)
{
$log->WriteEvent('User Send message', $account);
}
CSmtp::resetTimeOut(true);
return $result;
}
function ParseEhlo($str)
{
$return = array();
$arrayOut = explode("\n", $str);
array_shift($arrayOut);
if (is_array($arrayOut))
{
foreach ($arrayOut as $line)
{
$parts = explode('-', trim($line), 2);
if (count($parts) == 2 && $parts[0] == '250')
{
$return[] = strtoupper(trim($parts[1]));
}
}
}
return $return;
}
/**
* @access private
* @param resource $link
* @param string $command
* @param CLog $log
* @return bool
*/
function ExecuteCommand(&$link, $command, &$log, &$out, $isLog = true)
{
if ($isLog)
{
$log->WriteLine('[SMTP] >>: '.$command);
}
CSmtp::resetTimeOut();
@fputs($link, $command.CRLF);
return CSmtp::IsSuccess($link, $log, $out);
}
/**
* @access private
* @param resource $link
* @param CLog $log
* @return bool
*/
function IsSuccess(&$link, &$log, &$out, $isLog = true)
{
$out = '';
$line = '';
$result = true;
do
{
$line = @fgets($link, 1024);
if ($isLog)
{
$log->WriteLine('[SMTP] <<: '.trim($line));
}
if ($line === false)
{
$result = false;
setGlobalError('[SMTP] Error: IsSuccess fgets error');
break;
}
else
{
$out .= $line;
$line = str_replace("\r", '', str_replace("\n", '', str_replace(CRLF, '', $line)));
if (substr($line, 0, 1) != '2' && substr($line, 0, 1) != '3')
{
$result = false;
$error = '[SMTP] Error <<: ' . $line;
setGlobalError($error);
break;
}
}
} while (substr($line, 3, 1) == '-');
if (!$result && $log->Enabled)
{
$log->WriteLine(getGlobalError(), LOG_LEVEL_ERROR);
}
return $result;
}
/**
* @param bool $_force
*/
function resetTimeOut($_force = false)
{
static $_staticTime = null;
$_time = time();
if ($_staticTime < $_time - RESET_TIME_LIMIT_RUN || $_force)
{
@set_time_limit(RESET_TIME_LIMIT);
$_staticTime = $_time;
}
}
}
/**
* @static
*/
class CXmailSmtp
{
/**
* @static
* @access private
* @param Settings $settings
* @param Account $account
* @param WebMailMessage $message
* @param string $from
* @param string $to
* @param CLog $log
* @return bool
*/
function Send($settings, $account, &$message, $from, $to, &$log)
{
if ($settings->EnableWmServer && $account->MailProtocol == MAILPROTOCOL_WMSERVER)
{
$spoolFolder = $settings->WmServerRootPath.'/spool/local/';
if (@is_dir($spoolFolder))
{
$filename = time().'-1.'.rand(1000, 9999).'.'.XMAILHOST;
$_fh = @fopen($spoolFolder.$filename, 'wb');
if ($_fh)
{
$data = 'MAIL FROM:<'.$from.'>'."\r\n";
$toArray = explode(',', $to);
foreach ($toArray as $recipient)
{
$recipient = trim($recipient);
$data .= 'RCPT TO:<'.$recipient.'>'."\r\n";
}
$data .= "\r\n";
$data .= $message->TryToGetOriginalMailMessage()."\r\n";
if ($log->Enabled)
{
$log->WriteLine('XMAIL SPOOL :'."\r\n".$data);
}
if (@fwrite($_fh, $data, strlen($data)))
{
$log->WriteEvent('User Send message', $account);
@fclose($_fh);
return true;
}
else
{
$log->WriteLine('XMAIL SPOOL Error : can\'t save message to spool folder (fwrite).', LOG_LEVEL_ERROR);
setGlobalError(PROC_CANT_SEND_MSG);
}
@fclose($_fh);
}
else
{
$log->WriteLine('XMAIL SPOOL Error : can\'t save message to spool folder (fopen).', LOG_LEVEL_ERROR);
setGlobalError(PROC_CANT_SEND_MSG);
}
}
else
{
$log->WriteLine('XMAIL SPOOL Error : can\'t find spool folder ('.$spoolFolder.').', LOG_LEVEL_ERROR);
setGlobalError(ErrorSMTPConnect);
}
}
else
{
$log->WriteLine('XMAIL SPOOL Error : xmail not enable or MailProtocol not xmail).', LOG_LEVEL_ERROR);
setGlobalError(ErrorSMTPConnect);
}
return false;
}
}