mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-06 16:07:03 +03:00
Bugfix: SieveClient quoted string parsing
Redesign NetClient::getNextBuffer() to return string
This commit is contained in:
parent
2a86ab5753
commit
8b65b6ee7c
4 changed files with 94 additions and 152 deletions
|
|
@ -87,39 +87,31 @@ trait ResponseParser
|
||||||
|
|
||||||
$sAtomBuilder = $bTreatAsAtom ? '' : null;
|
$sAtomBuilder = $bTreatAsAtom ? '' : null;
|
||||||
$aList = array();
|
$aList = array();
|
||||||
if ($bRoot)
|
if ($bRoot) {
|
||||||
{
|
|
||||||
$aList =& $oImapResponse->ResponseList;
|
$aList =& $oImapResponse->ResponseList;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
$sResponseBuffer = '';
|
||||||
{
|
|
||||||
if ($this->bNeedNext)
|
while (true) {
|
||||||
{
|
if ($this->bNeedNext) {
|
||||||
/**
|
|
||||||
* $this->sResponseBuffer is a single fgets() that ends with \r\n
|
|
||||||
*/
|
|
||||||
$iPos = 0;
|
$iPos = 0;
|
||||||
$this->getNextBuffer();
|
$sResponseBuffer = $this->getNextBuffer();
|
||||||
$this->iResponseBufParsedPos = $iPos;
|
$this->iResponseBufParsedPos = $iPos;
|
||||||
$this->bNeedNext = false;
|
$this->bNeedNext = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sChar = null;
|
$sChar = null;
|
||||||
if ($bIsGotoDefault)
|
if ($bIsGotoDefault) {
|
||||||
{
|
|
||||||
$bIsGotoDefault = false;
|
$bIsGotoDefault = false;
|
||||||
}
|
} else {
|
||||||
else
|
$iBufferEndIndex = \strlen($sResponseBuffer) - 3;
|
||||||
{
|
|
||||||
$iBufferEndIndex = \strlen($this->sResponseBuffer) - 3;
|
|
||||||
|
|
||||||
if ($iPos > $iBufferEndIndex)
|
if ($iPos > $iBufferEndIndex) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sChar = $this->sResponseBuffer[$iPos];
|
$sChar = $sResponseBuffer[$iPos];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($sChar)
|
switch ($sChar)
|
||||||
|
|
@ -167,13 +159,13 @@ trait ResponseParser
|
||||||
continue 2;
|
continue 2;
|
||||||
|
|
||||||
case '~': // literal8
|
case '~': // literal8
|
||||||
if ('{' !== $this->sResponseBuffer[++$iPos]) {
|
if ('{' !== $sResponseBuffer[++$iPos]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '{':
|
case '{':
|
||||||
$iLength = \strspn($this->sResponseBuffer, '0123456789', $iPos + 1);
|
$iLength = \strspn($sResponseBuffer, '0123456789', $iPos + 1);
|
||||||
if ($iLength && "}\r\n" === \substr($this->sResponseBuffer, $iPos + 1 + $iLength, 3)) {
|
if ($iLength && "}\r\n" === \substr($sResponseBuffer, $iPos + 1 + $iLength, 3)) {
|
||||||
$iLiteralLen = (int) \substr($this->sResponseBuffer, $iPos + 1, $iLength);
|
$iLiteralLen = (int) \substr($sResponseBuffer, $iPos + 1, $iLength);
|
||||||
$iPos += 4 + $iLength;
|
$iPos += 4 + $iLength;
|
||||||
|
|
||||||
if ($this->partialResponseLiteralCallbacks($sParentToken, $sPreviousAtomUpperCase, $iLiteralLen)) {
|
if ($this->partialResponseLiteralCallbacks($sParentToken, $sPreviousAtomUpperCase, $iLiteralLen)) {
|
||||||
|
|
@ -217,13 +209,13 @@ trait ResponseParser
|
||||||
$iPos = $iBufferEndIndex;
|
$iPos = $iBufferEndIndex;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$iLength = \strcspn($this->sResponseBuffer, "\r\n\\\"", $iOffset);
|
$iLength = \strcspn($sResponseBuffer, "\r\n\\\"", $iOffset);
|
||||||
$sSpecial = $this->sResponseBuffer[$iOffset + $iLength];
|
$sSpecial = $sResponseBuffer[$iOffset + $iLength];
|
||||||
switch ($sSpecial)
|
switch ($sSpecial)
|
||||||
{
|
{
|
||||||
case '\\':
|
case '\\':
|
||||||
// Is escaped character \ or "?
|
// Is escaped character \ or "?
|
||||||
if (!\in_array($this->sResponseBuffer[$iOffset + $iLength + 1], ['\\','"'])) {
|
if (!\in_array($sResponseBuffer[$iOffset + $iLength + 1], ['\\','"'])) {
|
||||||
// No, not allowed in quoted string
|
// No, not allowed in quoted string
|
||||||
break 2;
|
break 2;
|
||||||
}
|
}
|
||||||
|
|
@ -232,9 +224,9 @@ trait ResponseParser
|
||||||
|
|
||||||
case '"':
|
case '"':
|
||||||
if ($bTreatAsAtom) {
|
if ($bTreatAsAtom) {
|
||||||
$sAtomBuilder .= \stripslashes(\substr($this->sResponseBuffer, $iPos, $iOffset + $iLength - $iPos + 1));
|
$sAtomBuilder .= \stripslashes(\substr($sResponseBuffer, $iPos, $iOffset + $iLength - $iPos + 1));
|
||||||
} else {
|
} else {
|
||||||
$aList[] = \stripslashes(\substr($this->sResponseBuffer, $iPos + 1, $iOffset + $iLength - $iPos - 1));
|
$aList[] = \stripslashes(\substr($sResponseBuffer, $iPos + 1, $iOffset + $iLength - $iPos - 1));
|
||||||
}
|
}
|
||||||
$iPos = $iOffset + $iLength + 1;
|
$iPos = $iOffset + $iLength + 1;
|
||||||
break 2;
|
break 2;
|
||||||
|
|
@ -242,7 +234,7 @@ trait ResponseParser
|
||||||
default:
|
default:
|
||||||
case "\r":
|
case "\r":
|
||||||
case "\n":
|
case "\n":
|
||||||
\SnappyMail\Log::notice('IMAP', 'Invalid char in quoted string: "' . \substr($this->sResponseBuffer, $iPos, $iOffset + $iLength - $iPos) . '"');
|
\SnappyMail\Log::notice('IMAP', 'Invalid char in quoted string: "' . \substr($sResponseBuffer, $iPos, $iOffset + $iLength - $iPos) . '"');
|
||||||
// Not allowed in quoted string
|
// Not allowed in quoted string
|
||||||
break 2;
|
break 2;
|
||||||
}
|
}
|
||||||
|
|
@ -253,29 +245,26 @@ trait ResponseParser
|
||||||
default:
|
default:
|
||||||
$iCharBlockStartPos = $iPos;
|
$iCharBlockStartPos = $iPos;
|
||||||
|
|
||||||
if ($bRoot && $oImapResponse->IsStatusResponse)
|
if ($bRoot && $oImapResponse->IsStatusResponse) {
|
||||||
{
|
|
||||||
$iPos = $iBufferEndIndex;
|
$iPos = $iBufferEndIndex;
|
||||||
if ($iPos > $iCharBlockStartPos) {
|
if ($iPos > $iCharBlockStartPos) {
|
||||||
$iCharBlockStartPos += \strspn($this->sResponseBuffer, ' ', $iCharBlockStartPos, $iPos - $iCharBlockStartPos);
|
$iCharBlockStartPos += \strspn($sResponseBuffer, ' ', $iCharBlockStartPos, $iPos - $iCharBlockStartPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($iPos <= $iBufferEndIndex)
|
while ($iPos <= $iBufferEndIndex) {
|
||||||
{
|
$sCharDef = $sResponseBuffer[$iPos];
|
||||||
$sCharDef = $this->sResponseBuffer[$iPos];
|
|
||||||
switch (true)
|
switch (true)
|
||||||
{
|
{
|
||||||
case $bRoot && ('[' === $sCharDef || ']' === $sCharDef) && static::skipSquareBracketParse($oImapResponse):
|
case $bRoot && ('[' === $sCharDef || ']' === $sCharDef) && static::skipSquareBracketParse($oImapResponse):
|
||||||
++$iPos;
|
++$iPos;
|
||||||
break;
|
break;
|
||||||
case '[' === $sCharDef:
|
case '[' === $sCharDef:
|
||||||
if (null === $sAtomBuilder)
|
if (null === $sAtomBuilder) {
|
||||||
{
|
|
||||||
$sAtomBuilder = '';
|
$sAtomBuilder = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$sAtomBuilder .= \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1);
|
$sAtomBuilder .= \substr($sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1);
|
||||||
|
|
||||||
$this->iResponseBufParsedPos = ++$iPos;
|
$this->iResponseBufParsedPos = ++$iPos;
|
||||||
|
|
||||||
|
|
@ -301,33 +290,25 @@ trait ResponseParser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder)
|
if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder) {
|
||||||
{
|
$sLastCharBlock = \substr($sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos);
|
||||||
$sLastCharBlock = \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos);
|
if (null === $sAtomBuilder) {
|
||||||
if (null === $sAtomBuilder)
|
|
||||||
{
|
|
||||||
$aList[] = 'NIL' === $sLastCharBlock ? null : $sLastCharBlock;
|
$aList[] = 'NIL' === $sLastCharBlock ? null : $sLastCharBlock;
|
||||||
$sPreviousAtomUpperCase = \strtoupper($sLastCharBlock);
|
$sPreviousAtomUpperCase = \strtoupper($sLastCharBlock);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$sAtomBuilder .= $sLastCharBlock;
|
$sAtomBuilder .= $sLastCharBlock;
|
||||||
|
|
||||||
if (!$bTreatAsAtom)
|
if (!$bTreatAsAtom) {
|
||||||
{
|
|
||||||
$aList[] = $sAtomBuilder;
|
$aList[] = $sAtomBuilder;
|
||||||
$sPreviousAtomUpperCase = \strtoupper($sAtomBuilder);
|
$sPreviousAtomUpperCase = \strtoupper($sAtomBuilder);
|
||||||
$sAtomBuilder = null;
|
$sAtomBuilder = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($bRoot)
|
if ($bRoot) {
|
||||||
{
|
if (!isset($oImapResponse->Tag) && 1 === \count($aList)) {
|
||||||
if (!isset($oImapResponse->Tag) && 1 === \count($aList))
|
|
||||||
{
|
|
||||||
$oImapResponse->setTag($aList[0]);
|
$oImapResponse->setTag($aList[0]);
|
||||||
if ($this->getCurrentTag() === $oImapResponse->Tag)
|
if ($this->getCurrentTag() === $oImapResponse->Tag) {
|
||||||
{
|
|
||||||
$oImapResponse->ResponseType = ResponseType::TAGGED;
|
$oImapResponse->ResponseType = ResponseType::TAGGED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -372,8 +353,7 @@ trait ResponseParser
|
||||||
|
|
||||||
$iLiteralSize = \strlen($sLiteral);
|
$iLiteralSize = \strlen($sLiteral);
|
||||||
if ($iLiteralLen !== $iLiteralSize) {
|
if ($iLiteralLen !== $iLiteralSize) {
|
||||||
$this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '.
|
$this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '.$iLiteralLen.'" bytes', \LOG_WARNING);
|
||||||
$iLiteralLen.'" bytes', \LOG_WARNING);
|
|
||||||
}
|
}
|
||||||
return $sLiteral;
|
return $sLiteral;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ abstract class NetClient
|
||||||
|
|
||||||
private string $sConnectedHost = '';
|
private string $sConnectedHost = '';
|
||||||
|
|
||||||
protected string $sResponseBuffer = '';
|
|
||||||
|
|
||||||
private bool $ssl = false;
|
private bool $ssl = false;
|
||||||
|
|
||||||
private int $iConnectTimeOut = 10;
|
private int $iConnectTimeOut = 10;
|
||||||
|
|
@ -260,25 +258,25 @@ abstract class NetClient
|
||||||
* @throws \MailSo\Net\Exceptions\SocketConnectionDoesNotAvailableException
|
* @throws \MailSo\Net\Exceptions\SocketConnectionDoesNotAvailableException
|
||||||
* @throws \MailSo\Net\Exceptions\SocketReadException
|
* @throws \MailSo\Net\Exceptions\SocketReadException
|
||||||
*/
|
*/
|
||||||
protected function getNextBuffer(?int $iReadLen = null) : void
|
protected function getNextBuffer(?int $iReadLen = null) : ?string
|
||||||
{
|
{
|
||||||
if (null === $iReadLen) {
|
if (null === $iReadLen) {
|
||||||
$this->sResponseBuffer = \fgets($this->rConnect);
|
$sResponseBuffer = \fgets($this->rConnect);
|
||||||
} else {
|
} else {
|
||||||
$this->sResponseBuffer = '';
|
$sResponseBuffer = '';
|
||||||
$iRead = $iReadLen;
|
$iRead = $iReadLen;
|
||||||
while (0 < $iRead) {
|
while (0 < $iRead) {
|
||||||
$sAddRead = \fread($this->rConnect, $iRead);
|
$sAddRead = \fread($this->rConnect, $iRead);
|
||||||
if (false === $sAddRead) {
|
if (false === $sAddRead) {
|
||||||
$this->sResponseBuffer = false;
|
$sResponseBuffer = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$this->sResponseBuffer .= $sAddRead;
|
$sResponseBuffer .= $sAddRead;
|
||||||
$iRead -= \strlen($sAddRead);
|
$iRead -= \strlen($sAddRead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false === $this->sResponseBuffer) {
|
if (false === $sResponseBuffer) {
|
||||||
$this->IsConnected(true);
|
$this->IsConnected(true);
|
||||||
$this->bUnreadBuffer = true;
|
$this->bUnreadBuffer = true;
|
||||||
$aSocketStatus = \stream_get_meta_data($this->rConnect);
|
$aSocketStatus = \stream_get_meta_data($this->rConnect);
|
||||||
|
|
@ -288,16 +286,19 @@ abstract class NetClient
|
||||||
$this->writeLog('Stream Meta: '.\print_r($aSocketStatus, true), \LOG_ERR);
|
$this->writeLog('Stream Meta: '.\print_r($aSocketStatus, true), \LOG_ERR);
|
||||||
$this->writeLogException(new Exceptions\SocketReadException, \LOG_ERR);
|
$this->writeLogException(new Exceptions\SocketReadException, \LOG_ERR);
|
||||||
}
|
}
|
||||||
} else {
|
return null;
|
||||||
$iReadBytes = \strlen($this->sResponseBuffer);
|
|
||||||
// $iReadLen && $this->writeLog('Received '.$iReadBytes.'/'.$iReadLen.' bytes.');
|
|
||||||
$iLimit = 5000; // 5KB
|
|
||||||
if ($iLimit < $iReadBytes) {
|
|
||||||
$this->writeLogWithCrlf('[cutted:'.$iReadBytes.'] < '.\substr($this->sResponseBuffer, 0, $iLimit).'...');
|
|
||||||
} else {
|
|
||||||
$this->writeLogWithCrlf('< '.$this->sResponseBuffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$iReadBytes = \strlen($sResponseBuffer);
|
||||||
|
// $iReadLen && $this->writeLog('Received '.$iReadBytes.'/'.$iReadLen.' bytes.');
|
||||||
|
$iLimit = 5000; // 5KB
|
||||||
|
if ($iLimit < $iReadBytes) {
|
||||||
|
$this->writeLogWithCrlf('[cutted:'.$iReadBytes.'] < '.\substr($sResponseBuffer, 0, $iLimit).'...');
|
||||||
|
} else {
|
||||||
|
$this->writeLogWithCrlf('< '.$sResponseBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sResponseBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract function getLogName() : string;
|
abstract function getLogName() : string;
|
||||||
|
|
|
||||||
|
|
@ -32,21 +32,11 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
return isset($this->aCapa[\strtoupper($sCapa)]);
|
return isset($this->aCapa[\strtoupper($sCapa)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function IsModuleSupported(string $sModule) : bool
|
|
||||||
{
|
|
||||||
return $this->hasCapability('SIEVE') && \in_array(\strtolower(\trim($sModule)), $this->aModules);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function Modules() : array
|
public function Modules() : array
|
||||||
{
|
{
|
||||||
return $this->aModules;
|
return $this->aModules;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function IsAuthSupported(string $sAuth) : bool
|
|
||||||
{
|
|
||||||
return $this->hasCapability('SASL') && \in_array(\strtoupper($sAuth), $this->aAuth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
* @throws \MailSo\RuntimeException
|
* @throws \MailSo\RuntimeException
|
||||||
|
|
@ -58,7 +48,6 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
parent::Connect($oSettings);
|
parent::Connect($oSettings);
|
||||||
|
|
||||||
$aResponse = $this->parseResponse();
|
$aResponse = $this->parseResponse();
|
||||||
$this->validateResponse($aResponse);
|
|
||||||
$this->parseStartupResponse($aResponse);
|
$this->parseStartupResponse($aResponse);
|
||||||
|
|
||||||
if (ConnectionSecurityType::STARTTLS === $this->Settings->type
|
if (ConnectionSecurityType::STARTTLS === $this->Settings->type
|
||||||
|
|
@ -73,7 +62,6 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
$this->sendRequestWithCheck('STARTTLS');
|
$this->sendRequestWithCheck('STARTTLS');
|
||||||
$this->EnableCrypto();
|
$this->EnableCrypto();
|
||||||
$aResponse = $this->parseResponse();
|
$aResponse = $this->parseResponse();
|
||||||
$this->validateResponse($aResponse);
|
|
||||||
$this->parseStartupResponse($aResponse);
|
$this->parseStartupResponse($aResponse);
|
||||||
} else {
|
} else {
|
||||||
$this->writeLogException(
|
$this->writeLogException(
|
||||||
|
|
@ -98,10 +86,12 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = '';
|
$type = '';
|
||||||
foreach ($oSettings->SASLMechanisms as $sasl_type) {
|
if ($this->hasCapability('SASL')) {
|
||||||
if ($this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) {
|
foreach ($oSettings->SASLMechanisms as $sasl_type) {
|
||||||
$type = $sasl_type;
|
if (\in_array(\strtoupper($sasl_type), $this->aAuth) && \SnappyMail\SASL::isSupported($sasl_type)) {
|
||||||
break;
|
$type = $sasl_type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$type) {
|
if (!$type) {
|
||||||
|
|
@ -143,7 +133,6 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
}
|
}
|
||||||
|
|
||||||
$aResponse = $this->parseResponse();
|
$aResponse = $this->parseResponse();
|
||||||
$this->validateResponse($aResponse);
|
|
||||||
$this->parseStartupResponse($aResponse);
|
$this->parseStartupResponse($aResponse);
|
||||||
$bAuth = true;
|
$bAuth = true;
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +149,6 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
$this->sendRaw($sPassword);
|
$this->sendRaw($sPassword);
|
||||||
|
|
||||||
$aResponse = $this->parseResponse();
|
$aResponse = $this->parseResponse();
|
||||||
$this->validateResponse($aResponse);
|
|
||||||
$this->parseStartupResponse($aResponse);
|
$this->parseStartupResponse($aResponse);
|
||||||
$bAuth = true;
|
$bAuth = true;
|
||||||
}
|
}
|
||||||
|
|
@ -201,12 +189,11 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
{
|
{
|
||||||
$this->sendRequest('LISTSCRIPTS');
|
$this->sendRequest('LISTSCRIPTS');
|
||||||
$aResponse = $this->parseResponse();
|
$aResponse = $this->parseResponse();
|
||||||
$this->validateResponse($aResponse);
|
|
||||||
$aResult = array();
|
$aResult = array();
|
||||||
foreach ($aResponse as $sLine) {
|
foreach ($aResponse as $sLine) {
|
||||||
$aTokens = $this->parseLine($sLine);
|
$aTokens = $this->parseLine($sLine);
|
||||||
if ($aTokens) {
|
if ($aTokens) {
|
||||||
$aResult[$aTokens[0]] = 'ACTIVE' === substr($sLine, -6);
|
$aResult[$aTokens[0]] = 'ACTIVE' === \substr($sLine, -6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,7 +209,6 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
{
|
{
|
||||||
$this->sendRequest('CAPABILITY');
|
$this->sendRequest('CAPABILITY');
|
||||||
$aResponse = $this->parseResponse();
|
$aResponse = $this->parseResponse();
|
||||||
$this->validateResponse($aResponse);
|
|
||||||
$this->parseStartupResponse($aResponse);
|
$this->parseStartupResponse($aResponse);
|
||||||
|
|
||||||
return $this->aCapa;
|
return $this->aCapa;
|
||||||
|
|
@ -247,9 +233,9 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
*/
|
*/
|
||||||
public function GetScript(string $sScriptName) : string
|
public function GetScript(string $sScriptName) : string
|
||||||
{
|
{
|
||||||
|
$sScriptName = \addcslashes($sScriptName, '"\\');
|
||||||
$this->sendRequest('GETSCRIPT "'.$sScriptName.'"');
|
$this->sendRequest('GETSCRIPT "'.$sScriptName.'"');
|
||||||
$aResponse = $this->parseResponse();
|
$aResponse = $this->parseResponse();
|
||||||
$this->validateResponse($aResponse);
|
|
||||||
|
|
||||||
$sScript = '';
|
$sScript = '';
|
||||||
if (\count($aResponse)) {
|
if (\count($aResponse)) {
|
||||||
|
|
@ -274,6 +260,7 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
*/
|
*/
|
||||||
public function PutScript(string $sScriptName, string $sScriptSource) : self
|
public function PutScript(string $sScriptName, string $sScriptSource) : self
|
||||||
{
|
{
|
||||||
|
$sScriptName = \addcslashes($sScriptName, '"\\');
|
||||||
$sScriptSource = \preg_replace('/\r?\n/', "\r\n", $sScriptSource);
|
$sScriptSource = \preg_replace('/\r?\n/', "\r\n", $sScriptSource);
|
||||||
$this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.\strlen($sScriptSource).'+}');
|
$this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.\strlen($sScriptSource).'+}');
|
||||||
$this->sendRequestWithCheck($sScriptSource);
|
$this->sendRequestWithCheck($sScriptSource);
|
||||||
|
|
@ -302,6 +289,7 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
*/
|
*/
|
||||||
public function SetActiveScript(string $sScriptName) : self
|
public function SetActiveScript(string $sScriptName) : self
|
||||||
{
|
{
|
||||||
|
$sScriptName = \addcslashes($sScriptName, '"\\');
|
||||||
$this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"');
|
$this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
@ -314,6 +302,7 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
*/
|
*/
|
||||||
public function DeleteScript(string $sScriptName) : self
|
public function DeleteScript(string $sScriptName) : self
|
||||||
{
|
{
|
||||||
|
$sScriptName = \addcslashes($sScriptName, '"\\');
|
||||||
$this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"');
|
$this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
@ -326,6 +315,8 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
*/
|
*/
|
||||||
public function RenameScript(string $sOldName, string $sNewName) : self
|
public function RenameScript(string $sOldName, string $sNewName) : self
|
||||||
{
|
{
|
||||||
|
$sOldName = \addcslashes($sOldName, '"\\');
|
||||||
|
$sNewName = \addcslashes($sNewName, '"\\');
|
||||||
$this->sendRequestWithCheck('RENAMESCRIPT "'.$sOldName.'" "'.$sNewName.'"');
|
$this->sendRequestWithCheck('RENAMESCRIPT "'.$sOldName.'" "'.$sNewName.'"');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
@ -333,26 +324,13 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
|
|
||||||
private function parseLine(string $sLine) : ?array
|
private function parseLine(string $sLine) : ?array
|
||||||
{
|
{
|
||||||
if (false === $sLine || null === $sLine || \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) {
|
if (!\in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) {
|
||||||
return null;
|
$aResult = array();
|
||||||
}
|
if (\preg_match_all('/(?:(?:"((?:\\\\"|[^"])*)"))/', $sLine, $aResult)) {
|
||||||
|
return \array_map('stripcslashes', $aResult[1]);
|
||||||
$iStart = -1;
|
|
||||||
$iIndex = 0;
|
|
||||||
$aResult = array();
|
|
||||||
|
|
||||||
for ($iPos = 0; $iPos < \strlen($sLine); ++$iPos) {
|
|
||||||
if ('"' === $sLine[$iPos] && '\\' !== $sLine[$iPos]) {
|
|
||||||
if (-1 === $iStart) {
|
|
||||||
$iStart = $iPos;
|
|
||||||
} else {
|
|
||||||
$aResult[$iIndex++] = \substr($sLine, $iStart + 1, $iPos - $iStart - 1);
|
|
||||||
$iStart = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
return isset($aResult[0]) ? $aResult : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -364,10 +342,7 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
{
|
{
|
||||||
foreach ($aResponse as $sLine) {
|
foreach ($aResponse as $sLine) {
|
||||||
$aTokens = $this->parseLine($sLine);
|
$aTokens = $this->parseLine($sLine);
|
||||||
|
if (empty($aTokens[0]) || \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) {
|
||||||
if (false === $aTokens || !isset($aTokens[0]) ||
|
|
||||||
\in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -411,7 +386,7 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
private function sendRequestWithCheck(string $sRequest) : void
|
private function sendRequestWithCheck(string $sRequest) : void
|
||||||
{
|
{
|
||||||
$this->sendRequest($sRequest);
|
$this->sendRequest($sRequest);
|
||||||
$this->validateResponse($this->parseResponse());
|
$this->parseResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseResponse() : array
|
private function parseResponse() : array
|
||||||
|
|
@ -419,22 +394,21 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
$aResult = array();
|
$aResult = array();
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
$this->getNextBuffer();
|
$sResponseBuffer = $this->getNextBuffer();
|
||||||
$sLine = $this->sResponseBuffer;
|
if (null === $sResponseBuffer) {
|
||||||
if (false === $sLine) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$bEnd = \in_array(\substr($sLine, 0, 2), array('OK', 'NO'));
|
$bEnd = \in_array(\substr($sResponseBuffer, 0, 2), array('OK', 'NO'));
|
||||||
// convertEndOfLine
|
// convertEndOfLine
|
||||||
$sLine = \trim($sLine);
|
$sLine = \trim($sResponseBuffer);
|
||||||
if ('}' === \substr($sLine, -1)) {
|
if ('}' === \substr($sLine, -1)) {
|
||||||
$iPos = \strrpos($sLine, '{');
|
$iPos = \strrpos($sLine, '{');
|
||||||
if (false !== $iPos) {
|
if (false !== $iPos) {
|
||||||
$iLen = \intval(\substr($sLine, $iPos + 1, -1));
|
$iLen = \intval(\substr($sLine, $iPos + 1, -1));
|
||||||
if (0 < $iLen) {
|
if (0 < $iLen) {
|
||||||
$this->getNextBuffer($iLen);
|
$sResponseBuffer = $this->getNextBuffer($iLen);
|
||||||
if (\strlen($this->sResponseBuffer) === $iLen) {
|
if (\strlen($sResponseBuffer) === $iLen) {
|
||||||
$sLine = \trim(\substr_replace($sLine, $this->sResponseBuffer, $iPos));
|
$sLine = \trim(\substr_replace($sLine, $sResponseBuffer, $iPos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -446,17 +420,11 @@ class SieveClient extends \MailSo\Net\NetClient
|
||||||
}
|
}
|
||||||
while (true);
|
while (true);
|
||||||
|
|
||||||
return $aResult;
|
if (!$aResult || 'OK' !== \substr($aResult[\array_key_last($aResult)], 0, 2)) {
|
||||||
}
|
$this->writeLogException(new \MailSo\Sieve\Exceptions\NegativeResponseException($aResult), \LOG_WARNING);
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
|
|
||||||
*/
|
|
||||||
private function validateResponse(array $aResponse)
|
|
||||||
{
|
|
||||||
if (!$aResponse || 'OK' !== \substr($aResponse[\count($aResponse) - 1], 0, 2)) {
|
|
||||||
$this->writeLogException(new \MailSo\Sieve\Exceptions\NegativeResponseException($aResponse), \LOG_WARNING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $aResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLogName() : string
|
public function getLogName() : string
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,6 @@ class SmtpClient extends \MailSo\Net\NetClient
|
||||||
return \in_array(\strtoupper($sCapa), $this->aCapa);
|
return \in_array(\strtoupper($sCapa), $this->aCapa);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function IsAuthSupported(string $sAuth) : bool
|
|
||||||
{
|
|
||||||
return \in_array(\strtoupper($sAuth), $this->aAuthTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function maxSize() : int
|
public function maxSize() : int
|
||||||
{
|
{
|
||||||
return $this->iSizeCapaValue;
|
return $this->iSizeCapaValue;
|
||||||
|
|
@ -118,7 +113,7 @@ class SmtpClient extends \MailSo\Net\NetClient
|
||||||
|
|
||||||
$type = '';
|
$type = '';
|
||||||
foreach ($oSettings->SASLMechanisms as $sasl_type) {
|
foreach ($oSettings->SASLMechanisms as $sasl_type) {
|
||||||
if ($this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) {
|
if (\in_array(\strtoupper($sasl_type), $this->aAuthTypes) && \SnappyMail\SASL::isSupported($sasl_type)) {
|
||||||
$type = $sasl_type;
|
$type = $sasl_type;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -486,18 +481,16 @@ class SmtpClient extends \MailSo\Net\NetClient
|
||||||
*/
|
*/
|
||||||
private function validateResponse($mExpectCode, string $sErrorPrefix = '') : void
|
private function validateResponse($mExpectCode, string $sErrorPrefix = '') : void
|
||||||
{
|
{
|
||||||
if (!\is_array($mExpectCode)) {
|
$mExpectCode = \is_array($mExpectCode)
|
||||||
$mExpectCode = array((int) $mExpectCode);
|
? \array_map('intval', $mExpectCode)
|
||||||
} else {
|
: array((int) $mExpectCode);
|
||||||
$mExpectCode = \array_map('intval', $mExpectCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
$aParts = array('', '', '');
|
$aParts = array('', '', '');
|
||||||
$this->aResults = array();
|
$this->aResults = array();
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
$this->getNextBuffer();
|
$sResponse = $this->getNextBuffer();
|
||||||
$aParts = \preg_split('/([\s\-]+)/', $this->sResponseBuffer, 2, PREG_SPLIT_DELIM_CAPTURE);
|
$aParts = \preg_split('/([\s\-]+)/', $sResponse, 2, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
|
||||||
if (3 === \count($aParts) && \is_numeric($aParts[0])) {
|
if (3 === \count($aParts) && \is_numeric($aParts[0])) {
|
||||||
if ('-' !== \substr($aParts[1], 0, 1) && !\in_array((int) $aParts[0], $mExpectCode)) {
|
if ('-' !== \substr($aParts[1], 0, 1) && !\in_array((int) $aParts[0], $mExpectCode)) {
|
||||||
|
|
@ -505,17 +498,17 @@ class SmtpClient extends \MailSo\Net\NetClient
|
||||||
new Exceptions\NegativeResponseException($this->aResults,
|
new Exceptions\NegativeResponseException($this->aResults,
|
||||||
('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
|
('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
|
||||||
(\count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
|
(\count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
|
||||||
$this->sResponseBuffer)), \LOG_ERR);
|
$sResponse)), \LOG_ERR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->writeLogException(
|
$this->writeLogException(
|
||||||
new Exceptions\ResponseException($this->aResults,
|
new Exceptions\ResponseException($this->aResults,
|
||||||
('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
|
('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
|
||||||
(\count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
|
(\count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
|
||||||
$this->sResponseBuffer)), \LOG_ERR);
|
$sResponse)), \LOG_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->aResults[] = $this->sResponseBuffer;
|
$this->aResults[] = $sResponse;
|
||||||
}
|
}
|
||||||
while ('-' === \substr($aParts[1], 0, 1));
|
while ('-' === \substr($aParts[1], 0, 1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue