snappymail/rainloop/v/1.3.6.461/app/libraries/MailSo/Sieve/ManageSieveClient.php
RainLoop Team 486aedb57b v1.3.6.461
2013-10-29 04:54:17 +04:00

629 lines
14 KiB
PHP

<?php
namespace MailSo\Sieve;
/**
* @category MailSo
* @package Sieve
*/
class ManageSieveClient extends \MailSo\Net\NetClient
{
/**
* @var bool
*/
private $bIsLoggined;
/**
* @var array
*/
private $aCapa;
/**
* @var int
*/
private $iRequestTime;
/**
* @access protected
*/
protected function __construct()
{
parent::__construct();
$this->bIsLoggined = false;
$this->iRequestTime = 0;
$this->aCapa = array();
$this->aModules = array();
}
/**
* @return \MailSo\Sieve\ManageSieveClient
*/
public static function NewInstance()
{
return new self();
}
/**
* @param string $sCapa
*
* @return bool
*/
public function IsSupported($sCapa)
{
return isset($this->aCapa[\strtoupper($sCapa)]);
}
/**
* @param string $sModule
*
* @return bool
*/
public function IsModuleSupported($sModule)
{
return $this->IsSupported('SIEVE') && \in_array(\strtoupper($sModule), $this->aModules);
}
/**
* @param string $sAuth
*
* @return bool
*/
public function IsAuthSupported($sAuth)
{
return $this->IsSupported('SASL') && \in_array(\strtoupper($sAuth), $this->aAuth);
}
/**
* @param string $sServerName
* @param int $iPort
* @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
*
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Sieve\Exceptions\ResponseException
*/
public function Connect($sServerName, $iPort,
$iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT)
{
$this->iRequestTime = microtime(true);
parent::Connect($sServerName, $iPort, $iSecurityType);
$mResponse = $this->parseResponse();
$this->validateResponse($mResponse);
$this->parseStartupResponse($mResponse);
if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
$this->IsSupported('STARTTLS'), $this->iSecurityType))
{
$this->sendRequestWithCheck('STARTTLS');
if (!@stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_TLS_CLIENT))
{
$this->writeLogException(
new \MailSo\Sieve\Exceptions\RuntimeException('Cannot enable STARTTLS'),
\MailSo\Log\Enumerations\Type::ERROR, true);
}
$mResponse = $this->parseResponse();
$this->validateResponse($mResponse);
$this->parseStartupResponse($mResponse);
}
else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
{
$this->writeLogException(
new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
\MailSo\Log\Enumerations\Type::ERROR, true);
}
return $this;
}
/**
* @param string $sLogin
* @param string $sPassword
* @param string $sLoginAuthKey = ''
*
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Sieve\Exceptions\LoginException
*/
public function Login($sLogin, $sPassword, $sLoginAuthKey = '')
{
if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) ||
!\MailSo\Base\Validator::NotEmptyString($sPassword, true))
{
$this->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException(),
\MailSo\Log\Enumerations\Type::ERROR, true);
}
if ($this->IsSupported('SASL'))
{
$bAuth = false;
try
{
if ($this->IsAuthSupported('PLAIN'))
{
$sAuth = base64_encode($sLoginAuthKey."\0".$sLogin."\0".$sPassword);
$this->sendRequest('AUTHENTICATE "PLAIN" {'.strlen($sAuth).'+}');
$this->sendRequest($sAuth);
$mResponse = $this->parseResponse();
$this->validateResponse($mResponse);
$this->parseStartupResponse($mResponse);
$bAuth = true;
}
else if ($this->IsAuthSupported('LOGIN'))
{
$sLogin = base64_encode($sLogin);
$sPassword = base64_encode($sPassword);
$this->sendRequest('AUTHENTICATE "LOGIN"');
$this->sendRequest('{'.strlen($sLogin).'+}');
$this->sendRequest($sLogin);
$this->sendRequest('{'.strlen($sPassword).'+}');
$this->sendRequest($sPassword);
$mResponse = $this->parseResponse();
$this->validateResponse($mResponse);
$this->parseStartupResponse($mResponse);
$bAuth = true;
}
}
catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException)
{
$this->writeLogException(
new \MailSo\Sieve\Exceptions\LoginBadCredentialsException(
$oException->GetResponses(), '', 0, $oException),
\MailSo\Log\Enumerations\Type::ERROR, true);
}
if (!$bAuth)
{
$this->writeLogException(
new \MailSo\Sieve\Exceptions\LoginBadMethodException(),
\MailSo\Log\Enumerations\Type::ERROR, true);
}
}
else
{
$this->writeLogException(
new \MailSo\Sieve\Exceptions\LoginException(),
\MailSo\Log\Enumerations\Type::ERROR, true);
}
$this->bIsLoggined = true;
return $this;
}
/**
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function Logout()
{
if ($this->bIsLoggined)
{
$this->sendRequestWithCheck('LOGOUT');
$this->bIsLoggined = false;
}
return $this;
}
/**
* @return array
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function ListScripts()
{
$this->sendRequest('LISTSCRIPTS');
$mResponse = $this->parseResponse();
$this->validateResponse($mResponse);
$aResult = array();
if (is_array($mResponse))
{
foreach ($mResponse as $sLine)
{
$aTokens = $this->parseLine($sLine);
if (false === $aTokens)
{
continue;
}
$aResult[$aTokens[0]] = 'ACTIVE' === substr($sLine, -6);
}
}
return $aResult;
}
/**
* @return array
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function Capability()
{
$this->sendRequest('CAPABILITY');
$mResponse = $this->parseResponse();
$this->validateResponse($mResponse);
$this->parseStartupResponse($mResponse);
return $this->aCapa;
}
/**
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function Noop()
{
$this->sendRequestWithCheck('NOOP');
return $this;
}
/**
* @param string $sScriptName
*
* @return string
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function GetScript($sScriptName)
{
$this->sendRequest('GETSCRIPT "'.$sScriptName.'"');
$mResponse = $this->parseResponse();
$this->validateResponse($mResponse);
$sScript = '';
if (is_array($mResponse) && 0 < count($mResponse))
{
if ('{' === $mResponse[0]{0})
{
array_shift($mResponse);
}
if (\in_array(\substr($mResponse[\count($mResponse) - 1], 0, 2), array('OK', 'NO')))
{
array_pop($mResponse);
}
$sScript = \implode("\n", $mResponse);
}
return $sScript;
}
/**
* @param string $sScriptName
* @param string $sScriptSource
*
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function PutScript($sScriptName, $sScriptSource)
{
$sScriptSource = stripslashes($sScriptSource);
$this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.strlen($sScriptSource).'+}');
$this->sendRequestWithCheck($sScriptSource);
return $this;
}
/**
* @param string $sScriptSource
*
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function CheckScript($sScriptSource)
{
$sScriptSource = stripslashes($sScriptSource);
$this->sendRequest('CHECKSCRIPT {'.strlen($sScriptSource).'+}');
$this->sendRequestWithCheck($sScriptSource);
return $this;
}
/**
* @param string $sScriptName
*
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function SetActiveScript($sScriptName)
{
$this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"');
return $this;
}
/**
* @param string $sScriptName
*
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function DeleteScript($sScriptName)
{
$this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"');
return $this;
}
/**
* @return string
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function GetActiveScriptName()
{
$aList = $this->ListScripts();
if (is_array($aList) && 0 < count($aList))
{
foreach ($aList as $sName => $bIsActive)
{
if ($bIsActive)
{
return $sName;
}
}
}
return '';
}
/**
* @param string $sScriptName
*
* @return bool
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
public function IsActiveScript($sScriptName)
{
return $sScriptName === $this->GetActiveScriptName();
}
/**
* @param string $sLine
* @return array|false
*/
private function parseLine($sLine)
{
if (false === $sLine || null === $sLine || \in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
{
return false;
}
$iStart = -1;
$iIndex = 0;
$aResult = false;
for ($iPos = 0; $iPos < \strlen($sLine); $iPos++)
{
if ('"' === $sLine[$iPos] && '\\' !== $sLine[$iPos])
{
if (-1 === $iStart)
{
$iStart = $iPos;
}
else
{
$aResult = \is_array($aResult) ? $aResult : array();
$aResult[$iIndex++] = \substr($sLine, $iStart + 1, $iPos - $iStart - 1);
$iStart = -1;
}
}
}
return \is_array($aResult) && isset($aResult[0]) ? $aResult : false;
}
/**
* @param string $sCommand
*
* @return void
*
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Net\Exceptions\Exception
*/
private function parseStartupResponse($mResponse)
{
foreach ($mResponse as $sLine)
{
$aTokens = $this->parseLine($sLine);
if (false === $aTokens || !isset($aTokens[0]) ||
\in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
{
continue;
}
$sToken = \strtoupper($aTokens[0]);
$this->aCapa[$sToken] = isset($aTokens[1]) ? $aTokens[1] : '';
if (isset($aTokens[1]))
{
switch ($sToken) {
case 'SASL':
$this->aAuth = \explode(' ', \strtoupper($aTokens[1]));
break;
case 'SIEVE':
$this->aModules = \explode(' ', \strtoupper($aTokens[1]));
break;
}
}
}
}
/**
* @param string $sRequest
*
* @return void
*
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Net\Exceptions\Exception
*/
private function sendRequest($sRequest)
{
if (!\MailSo\Base\Validator::NotEmptyString($sRequest, true))
{
$this->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException(),
\MailSo\Log\Enumerations\Type::ERROR, true);
}
$this->IsConnected(true);
$sRequest = \trim($sRequest);
$this->sendRaw($sRequest);
}
/**
* @param string $sRequest
*
* @return void
*
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
private function sendRequestWithCheck($sRequest)
{
$this->sendRequest($sRequest);
$this->validateResponse($this->parseResponse());
}
/**
* @param string $sLine
*
* @return string
*/
private function convertEndOfLine($sLine)
{
$sLine = \trim($sLine);
if ('}' === \substr($sLine, -1))
{
$iPos = \strrpos($sLine, '{');
if (false !== $iPos)
{
$sSunLine = \substr($sLine, $iPos + 1, -1);
if (\is_numeric($sSunLine) && 0 < (int) $sSunLine)
{
$iLen = (int) $sSunLine;
$this->getNextBuffer($iLen, true);
if (strlen($this->sResponseBuffer) === $iLen)
{
$sLine = \trim(\substr_replace($sLine, $this->sResponseBuffer, $iPos));
}
}
}
}
return $sLine;
}
/**
* @return array|bool
*/
private function parseResponse()
{
$this->iRequestTime = \microtime(true);
$aResult = array();
do
{
$this->getNextBuffer();
$sLine = $this->sResponseBuffer;
if (false === $sLine)
{
break;
}
else if (\in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
{
$aResult[] = $this->convertEndOfLine($sLine);
break;
}
else
{
$aResult[] = $this->convertEndOfLine($sLine);
}
}
while (true);
$this->writeLog((\microtime(true) - $this->iRequestTime),
\MailSo\Log\Enumerations\Type::TIME);
return $aResult;
}
/**
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
*/
private function validateResponse($aResponse)
{
if (!\is_array($aResponse) || 0 === \count($aResponse) ||
'OK' !== \substr($aResponse[\count($aResponse) - 1], 0, 2))
{
$this->writeLogException(
new \MailSo\Sieve\Exceptions\NegativeResponseException(),
\MailSo\Log\Enumerations\Type::WARNING, true);
}
}
/**
* @return string
*/
protected function getLogName()
{
return 'MANAGE-SIEVE';
}
/**
* @param \MailSo\Log\Logger $oLogger
*
* @return \MailSo\Sieve\ManageSieveClient
*
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
*/
public function SetLogger($oLogger)
{
parent::SetLogger($oLogger);
return $this;
}
}