Better fix for #1 and RainLoop#2081

The RainLoop skipSquareBracketParse wasn't perfect either
This commit is contained in:
djmaze 2021-11-04 10:28:51 +01:00
parent 2cf2b1ee75
commit 60b0fb4b35
2 changed files with 33 additions and 66 deletions

View file

@ -88,34 +88,6 @@ class ResponseCollection extends \MailSo\Base\Collection
return $aReturn; return $aReturn;
} }
/**
* @param array|string $mName
*/
private function getArrayNameToStringName($mName) : string
{
if (\is_string($mName))
{
return $mName;
}
if (\is_array($mName))
{
if (0 === \count($mName))
{
return '[]';
}
foreach ($mName as &$mSubName)
{
$mSubName = "[{$this->getArrayNameToStringName($mSubName)}]";
}
return \implode('', $mName);
}
return '';
}
public function getFolderMetadataResult() : array public function getFolderMetadataResult() : array
{ {
$aReturn = array(); $aReturn = array();
@ -154,21 +126,10 @@ class ResponseCollection extends \MailSo\Base\Collection
} }
$aReturn[$sFullNameRaw]->setStatusFromResponse($oResponse); $aReturn[$sFullNameRaw]->setStatusFromResponse($oResponse);
} }
else if ($sStatus === $oResponse->StatusOrIndex && 5 <= count($oResponse->ResponseList)) { else if ($sStatus === $oResponse->StatusOrIndex && 5 == \count($oResponse->ResponseList)) {
try try
{ {
/** $sFullNameRaw = $oResponse->ResponseList[4];
* A bug in the parser converts folder names that start with '[' into arrays,
* and subfolders are in $oResponse->ResponseList[5+]
* https://github.com/the-djmaze/snappymail/issues/1
* https://github.com/the-djmaze/snappymail/issues/70
*/
$aFullNameRawList = \array_slice($oResponse->ResponseList, 4);
foreach ($aFullNameRawList as &$sName) {
$sName = $this->getArrayNameToStringName($sName);
}
$sFullNameRaw = \implode('', $aFullNameRawList);
/** /**
* $oResponse->ResponseList[0] = * * $oResponse->ResponseList[0] = *

View file

@ -42,15 +42,23 @@ trait ResponseParser
return $oResponse; return $oResponse;
} }
private function skipBracketParse(?Response $oImapResponse) : bool /**
* A bug in the parser converts folder names that start with '[' into arrays.
* https://github.com/the-djmaze/snappymail/issues/1
* https://github.com/the-djmaze/snappymail/issues/70
* The fix RainLoop implemented isn't correct either.
* This one should as RFC 3501 only mentions:
*
* Status responses are OK, NO, BAD, PREAUTH and BYE.
*
* Status responses MAY include an OPTIONAL "response code". A response
* code consists of data inside square brackets in the form of an atom,
* possibly followed by a space and arguments.
*/
private function skipSquareBracketParse(?Response $oImapResponse) : bool
{ {
return $oImapResponse && return $oImapResponse
$oImapResponse->ResponseType === ResponseType::UNTAGGED && && !($oImapResponse->IsStatusResponse && 2 < \count($oImapResponse->ResponseList));
(
($oImapResponse->StatusOrIndex === 'STATUS' && 2 === \count($oImapResponse->ResponseList)) ||
($oImapResponse->StatusOrIndex === 'LIST' && 4 === \count($oImapResponse->ResponseList)) ||
($oImapResponse->StatusOrIndex === 'LSUB' && 4 === \count($oImapResponse->ResponseList))
);
} }
/** /**
@ -234,18 +242,16 @@ trait ResponseParser
switch (true) switch (true)
{ {
case ']' === $sChar: case ']' === $sChar:
case ')' === $sChar: if ($this->skipSquareBracketParse($oImapResponse)) {
if ($this->skipBracketParse($oImapResponse))
{
$bIsGotoDefault = true; $bIsGotoDefault = true;
$bIsGotoNotAtomBracket = false; $bIsGotoNotAtomBracket = false;
break 2;
} }
else case ')' === $sChar:
{
++$iPos; ++$iPos;
$sPreviousAtomUpperCase = null; $sPreviousAtomUpperCase = null;
}
break 2; break 2;
case ' ' === $sChar: case ' ' === $sChar:
if ($bTreatAsAtom) if ($bTreatAsAtom)
{ {
@ -253,7 +259,13 @@ trait ResponseParser
} }
++$iPos; ++$iPos;
break; break;
case '[' === $sChar: case '[' === $sChar:
if ($this->skipSquareBracketParse($oImapResponse)) {
$bIsGotoDefault = true;
$bIsGotoNotAtomBracket = false;
break;
}
case '(' === $sChar: case '(' === $sChar:
$sOpenBracket = $sChar; $sOpenBracket = $sChar;
$sClosingBracket = '[' === $sChar ? ']' : ')'; $sClosingBracket = '[' === $sChar ? ']' : ')';
@ -263,19 +275,13 @@ trait ResponseParser
$bIsGotoAtomBracket = true; $bIsGotoAtomBracket = true;
$this->iResponseBufParsedPos = ++$iPos; $this->iResponseBufParsedPos = ++$iPos;
} }
else if ($this->skipBracketParse($oImapResponse))
{
$sOpenBracket = '';
$sClosingBracket = '';
$bIsGotoDefault = true;
$bIsGotoNotAtomBracket = false;
}
else else
{ {
$bIsGotoNotAtomBracket = true; $bIsGotoNotAtomBracket = true;
$this->iResponseBufParsedPos = ++$iPos; $this->iResponseBufParsedPos = ++$iPos;
} }
break; break;
case '{' === $sChar: case '{' === $sChar:
$bIsLiteralParsed = false; $bIsLiteralParsed = false;
$mLiteralEndPos = \strpos($this->sResponseBuffer, '}', $iPos); $mLiteralEndPos = \strpos($this->sResponseBuffer, '}', $iPos);
@ -297,6 +303,7 @@ trait ResponseParser
} }
$sPreviousAtomUpperCase = null; $sPreviousAtomUpperCase = null;
break; break;
case '"' === $sChar: case '"' === $sChar:
$bIsQuotedParsed = false; $bIsQuotedParsed = false;
while (true) while (true)
@ -402,8 +409,7 @@ trait ResponseParser
$sCharDef = $this->sResponseBuffer[$iPos]; $sCharDef = $this->sResponseBuffer[$iPos];
switch (true) switch (true)
{ {
case ('[' === $sCharDef || ']' === $sCharDef || '(' === $sCharDef || ')' === $sCharDef) && case ('[' === $sCharDef || ']' === $sCharDef) && $this->skipSquareBracketParse($oImapResponse):
$this->skipBracketParse($oImapResponse):
++$iPos; ++$iPos;
break; break;
case '[' === $sCharDef: case '[' === $sCharDef: