diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/ResponseParser.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/ResponseParser.php index 133e49ea3..172b9e401 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/ResponseParser.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/ResponseParser.php @@ -87,39 +87,31 @@ trait ResponseParser $sAtomBuilder = $bTreatAsAtom ? '' : null; $aList = array(); - if ($bRoot) - { + if ($bRoot) { $aList =& $oImapResponse->ResponseList; } - while (true) - { - if ($this->bNeedNext) - { - /** - * $this->sResponseBuffer is a single fgets() that ends with \r\n - */ + $sResponseBuffer = ''; + + while (true) { + if ($this->bNeedNext) { $iPos = 0; - $this->getNextBuffer(); + $sResponseBuffer = $this->getNextBuffer(); $this->iResponseBufParsedPos = $iPos; $this->bNeedNext = false; } $sChar = null; - if ($bIsGotoDefault) - { + if ($bIsGotoDefault) { $bIsGotoDefault = false; - } - else - { - $iBufferEndIndex = \strlen($this->sResponseBuffer) - 3; + } else { + $iBufferEndIndex = \strlen($sResponseBuffer) - 3; - if ($iPos > $iBufferEndIndex) - { + if ($iPos > $iBufferEndIndex) { break; } - $sChar = $this->sResponseBuffer[$iPos]; + $sChar = $sResponseBuffer[$iPos]; } switch ($sChar) @@ -167,13 +159,13 @@ trait ResponseParser continue 2; case '~': // literal8 - if ('{' !== $this->sResponseBuffer[++$iPos]) { + if ('{' !== $sResponseBuffer[++$iPos]) { break; } case '{': - $iLength = \strspn($this->sResponseBuffer, '0123456789', $iPos + 1); - if ($iLength && "}\r\n" === \substr($this->sResponseBuffer, $iPos + 1 + $iLength, 3)) { - $iLiteralLen = (int) \substr($this->sResponseBuffer, $iPos + 1, $iLength); + $iLength = \strspn($sResponseBuffer, '0123456789', $iPos + 1); + if ($iLength && "}\r\n" === \substr($sResponseBuffer, $iPos + 1 + $iLength, 3)) { + $iLiteralLen = (int) \substr($sResponseBuffer, $iPos + 1, $iLength); $iPos += 4 + $iLength; if ($this->partialResponseLiteralCallbacks($sParentToken, $sPreviousAtomUpperCase, $iLiteralLen)) { @@ -217,13 +209,13 @@ trait ResponseParser $iPos = $iBufferEndIndex; break; } - $iLength = \strcspn($this->sResponseBuffer, "\r\n\\\"", $iOffset); - $sSpecial = $this->sResponseBuffer[$iOffset + $iLength]; + $iLength = \strcspn($sResponseBuffer, "\r\n\\\"", $iOffset); + $sSpecial = $sResponseBuffer[$iOffset + $iLength]; switch ($sSpecial) { case '\\': // 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 break 2; } @@ -232,9 +224,9 @@ trait ResponseParser case '"': if ($bTreatAsAtom) { - $sAtomBuilder .= \stripslashes(\substr($this->sResponseBuffer, $iPos, $iOffset + $iLength - $iPos + 1)); + $sAtomBuilder .= \stripslashes(\substr($sResponseBuffer, $iPos, $iOffset + $iLength - $iPos + 1)); } 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; break 2; @@ -242,7 +234,7 @@ trait ResponseParser default: case "\r": 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 break 2; } @@ -253,29 +245,26 @@ trait ResponseParser default: $iCharBlockStartPos = $iPos; - if ($bRoot && $oImapResponse->IsStatusResponse) - { + if ($bRoot && $oImapResponse->IsStatusResponse) { $iPos = $iBufferEndIndex; if ($iPos > $iCharBlockStartPos) { - $iCharBlockStartPos += \strspn($this->sResponseBuffer, ' ', $iCharBlockStartPos, $iPos - $iCharBlockStartPos); + $iCharBlockStartPos += \strspn($sResponseBuffer, ' ', $iCharBlockStartPos, $iPos - $iCharBlockStartPos); } } - while ($iPos <= $iBufferEndIndex) - { - $sCharDef = $this->sResponseBuffer[$iPos]; + while ($iPos <= $iBufferEndIndex) { + $sCharDef = $sResponseBuffer[$iPos]; switch (true) { case $bRoot && ('[' === $sCharDef || ']' === $sCharDef) && static::skipSquareBracketParse($oImapResponse): ++$iPos; break; case '[' === $sCharDef: - if (null === $sAtomBuilder) - { + if (null === $sAtomBuilder) { $sAtomBuilder = ''; } - $sAtomBuilder .= \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1); + $sAtomBuilder .= \substr($sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1); $this->iResponseBufParsedPos = ++$iPos; @@ -301,33 +290,25 @@ trait ResponseParser } } - if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder) - { - $sLastCharBlock = \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos); - if (null === $sAtomBuilder) - { + if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder) { + $sLastCharBlock = \substr($sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos); + if (null === $sAtomBuilder) { $aList[] = 'NIL' === $sLastCharBlock ? null : $sLastCharBlock; $sPreviousAtomUpperCase = \strtoupper($sLastCharBlock); - } - else - { + } else { $sAtomBuilder .= $sLastCharBlock; - if (!$bTreatAsAtom) - { + if (!$bTreatAsAtom) { $aList[] = $sAtomBuilder; $sPreviousAtomUpperCase = \strtoupper($sAtomBuilder); $sAtomBuilder = null; } } - if ($bRoot) - { - if (!isset($oImapResponse->Tag) && 1 === \count($aList)) - { + if ($bRoot) { + if (!isset($oImapResponse->Tag) && 1 === \count($aList)) { $oImapResponse->setTag($aList[0]); - if ($this->getCurrentTag() === $oImapResponse->Tag) - { + if ($this->getCurrentTag() === $oImapResponse->Tag) { $oImapResponse->ResponseType = ResponseType::TAGGED; } } @@ -372,8 +353,7 @@ trait ResponseParser $iLiteralSize = \strlen($sLiteral); if ($iLiteralLen !== $iLiteralSize) { - $this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '. - $iLiteralLen.'" bytes', \LOG_WARNING); + $this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '.$iLiteralLen.'" bytes', \LOG_WARNING); } return $sLiteral; } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php index 663efbe72..08af152f9 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php @@ -28,8 +28,6 @@ abstract class NetClient private string $sConnectedHost = ''; - protected string $sResponseBuffer = ''; - private bool $ssl = false; private int $iConnectTimeOut = 10; @@ -260,25 +258,25 @@ abstract class NetClient * @throws \MailSo\Net\Exceptions\SocketConnectionDoesNotAvailableException * @throws \MailSo\Net\Exceptions\SocketReadException */ - protected function getNextBuffer(?int $iReadLen = null) : void + protected function getNextBuffer(?int $iReadLen = null) : ?string { if (null === $iReadLen) { - $this->sResponseBuffer = \fgets($this->rConnect); + $sResponseBuffer = \fgets($this->rConnect); } else { - $this->sResponseBuffer = ''; + $sResponseBuffer = ''; $iRead = $iReadLen; while (0 < $iRead) { $sAddRead = \fread($this->rConnect, $iRead); if (false === $sAddRead) { - $this->sResponseBuffer = false; + $sResponseBuffer = false; break; } - $this->sResponseBuffer .= $sAddRead; + $sResponseBuffer .= $sAddRead; $iRead -= \strlen($sAddRead); } } - if (false === $this->sResponseBuffer) { + if (false === $sResponseBuffer) { $this->IsConnected(true); $this->bUnreadBuffer = true; $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->writeLogException(new Exceptions\SocketReadException, \LOG_ERR); } - } else { - $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); - } + return null; } + + $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; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/SieveClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/SieveClient.php index b0077a5cb..a68ab016e 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/SieveClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/SieveClient.php @@ -32,21 +32,11 @@ class SieveClient extends \MailSo\Net\NetClient 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 { return $this->aModules; } - public function IsAuthSupported(string $sAuth) : bool - { - return $this->hasCapability('SASL') && \in_array(\strtoupper($sAuth), $this->aAuth); - } - /** * @throws \InvalidArgumentException * @throws \MailSo\RuntimeException @@ -58,7 +48,6 @@ class SieveClient extends \MailSo\Net\NetClient parent::Connect($oSettings); $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); $this->parseStartupResponse($aResponse); if (ConnectionSecurityType::STARTTLS === $this->Settings->type @@ -73,7 +62,6 @@ class SieveClient extends \MailSo\Net\NetClient $this->sendRequestWithCheck('STARTTLS'); $this->EnableCrypto(); $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); $this->parseStartupResponse($aResponse); } else { $this->writeLogException( @@ -98,10 +86,12 @@ class SieveClient extends \MailSo\Net\NetClient } $type = ''; - foreach ($oSettings->SASLMechanisms as $sasl_type) { - if ($this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) { - $type = $sasl_type; - break; + if ($this->hasCapability('SASL')) { + foreach ($oSettings->SASLMechanisms as $sasl_type) { + if (\in_array(\strtoupper($sasl_type), $this->aAuth) && \SnappyMail\SASL::isSupported($sasl_type)) { + $type = $sasl_type; + break; + } } } if (!$type) { @@ -143,7 +133,6 @@ class SieveClient extends \MailSo\Net\NetClient } $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); $this->parseStartupResponse($aResponse); $bAuth = true; } @@ -160,7 +149,6 @@ class SieveClient extends \MailSo\Net\NetClient $this->sendRaw($sPassword); $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); $this->parseStartupResponse($aResponse); $bAuth = true; } @@ -201,12 +189,11 @@ class SieveClient extends \MailSo\Net\NetClient { $this->sendRequest('LISTSCRIPTS'); $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); $aResult = array(); foreach ($aResponse as $sLine) { $aTokens = $this->parseLine($sLine); 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'); $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); $this->parseStartupResponse($aResponse); return $this->aCapa; @@ -247,9 +233,9 @@ class SieveClient extends \MailSo\Net\NetClient */ public function GetScript(string $sScriptName) : string { + $sScriptName = \addcslashes($sScriptName, '"\\'); $this->sendRequest('GETSCRIPT "'.$sScriptName.'"'); $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); $sScript = ''; if (\count($aResponse)) { @@ -274,6 +260,7 @@ class SieveClient extends \MailSo\Net\NetClient */ public function PutScript(string $sScriptName, string $sScriptSource) : self { + $sScriptName = \addcslashes($sScriptName, '"\\'); $sScriptSource = \preg_replace('/\r?\n/', "\r\n", $sScriptSource); $this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.\strlen($sScriptSource).'+}'); $this->sendRequestWithCheck($sScriptSource); @@ -302,6 +289,7 @@ class SieveClient extends \MailSo\Net\NetClient */ public function SetActiveScript(string $sScriptName) : self { + $sScriptName = \addcslashes($sScriptName, '"\\'); $this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"'); return $this; @@ -314,6 +302,7 @@ class SieveClient extends \MailSo\Net\NetClient */ public function DeleteScript(string $sScriptName) : self { + $sScriptName = \addcslashes($sScriptName, '"\\'); $this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"'); return $this; @@ -326,6 +315,8 @@ class SieveClient extends \MailSo\Net\NetClient */ public function RenameScript(string $sOldName, string $sNewName) : self { + $sOldName = \addcslashes($sOldName, '"\\'); + $sNewName = \addcslashes($sNewName, '"\\'); $this->sendRequestWithCheck('RENAMESCRIPT "'.$sOldName.'" "'.$sNewName.'"'); return $this; @@ -333,26 +324,13 @@ class SieveClient extends \MailSo\Net\NetClient private function parseLine(string $sLine) : ?array { - if (false === $sLine || null === $sLine || \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) { - return null; - } - - $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; - } + if (!\in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) { + $aResult = array(); + if (\preg_match_all('/(?:(?:"((?:\\\\"|[^"])*)"))/', $sLine, $aResult)) { + return \array_map('stripcslashes', $aResult[1]); } } - - return isset($aResult[0]) ? $aResult : null; + return null; } /** @@ -364,10 +342,7 @@ class SieveClient extends \MailSo\Net\NetClient { foreach ($aResponse as $sLine) { $aTokens = $this->parseLine($sLine); - - if (false === $aTokens || !isset($aTokens[0]) || - \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) - { + if (empty($aTokens[0]) || \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) { continue; } @@ -411,7 +386,7 @@ class SieveClient extends \MailSo\Net\NetClient private function sendRequestWithCheck(string $sRequest) : void { $this->sendRequest($sRequest); - $this->validateResponse($this->parseResponse()); + $this->parseResponse(); } private function parseResponse() : array @@ -419,22 +394,21 @@ class SieveClient extends \MailSo\Net\NetClient $aResult = array(); do { - $this->getNextBuffer(); - $sLine = $this->sResponseBuffer; - if (false === $sLine) { + $sResponseBuffer = $this->getNextBuffer(); + if (null === $sResponseBuffer) { break; } - $bEnd = \in_array(\substr($sLine, 0, 2), array('OK', 'NO')); + $bEnd = \in_array(\substr($sResponseBuffer, 0, 2), array('OK', 'NO')); // convertEndOfLine - $sLine = \trim($sLine); + $sLine = \trim($sResponseBuffer); if ('}' === \substr($sLine, -1)) { $iPos = \strrpos($sLine, '{'); if (false !== $iPos) { $iLen = \intval(\substr($sLine, $iPos + 1, -1)); if (0 < $iLen) { - $this->getNextBuffer($iLen); - if (\strlen($this->sResponseBuffer) === $iLen) { - $sLine = \trim(\substr_replace($sLine, $this->sResponseBuffer, $iPos)); + $sResponseBuffer = $this->getNextBuffer($iLen); + if (\strlen($sResponseBuffer) === $iLen) { + $sLine = \trim(\substr_replace($sLine, $sResponseBuffer, $iPos)); } } } @@ -446,17 +420,11 @@ class SieveClient extends \MailSo\Net\NetClient } while (true); - return $aResult; - } - - /** - * @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); + if (!$aResult || 'OK' !== \substr($aResult[\array_key_last($aResult)], 0, 2)) { + $this->writeLogException(new \MailSo\Sieve\Exceptions\NegativeResponseException($aResult), \LOG_WARNING); } + + return $aResult; } public function getLogName() : string diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php index ffd1b297a..1bee407c6 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php @@ -41,11 +41,6 @@ class SmtpClient extends \MailSo\Net\NetClient return \in_array(\strtoupper($sCapa), $this->aCapa); } - public function IsAuthSupported(string $sAuth) : bool - { - return \in_array(\strtoupper($sAuth), $this->aAuthTypes); - } - public function maxSize() : int { return $this->iSizeCapaValue; @@ -118,7 +113,7 @@ class SmtpClient extends \MailSo\Net\NetClient $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; break; } @@ -486,18 +481,16 @@ class SmtpClient extends \MailSo\Net\NetClient */ private function validateResponse($mExpectCode, string $sErrorPrefix = '') : void { - if (!\is_array($mExpectCode)) { - $mExpectCode = array((int) $mExpectCode); - } else { - $mExpectCode = \array_map('intval', $mExpectCode); - } + $mExpectCode = \is_array($mExpectCode) + ? \array_map('intval', $mExpectCode) + : array((int) $mExpectCode); $aParts = array('', '', ''); $this->aResults = array(); do { - $this->getNextBuffer(); - $aParts = \preg_split('/([\s\-]+)/', $this->sResponseBuffer, 2, PREG_SPLIT_DELIM_CAPTURE); + $sResponse = $this->getNextBuffer(); + $aParts = \preg_split('/([\s\-]+)/', $sResponse, 2, PREG_SPLIT_DELIM_CAPTURE); if (3 === \count($aParts) && \is_numeric($aParts[0])) { 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, ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim( (\count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : ''). - $this->sResponseBuffer)), \LOG_ERR); + $sResponse)), \LOG_ERR); } } else { $this->writeLogException( new Exceptions\ResponseException($this->aResults, ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim( (\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)); }