Improved IMAP sort/search/thread command handling

This commit is contained in:
djmaze 2021-11-03 11:24:26 +01:00
parent 93ced6f5f0
commit 0055eb6016
7 changed files with 285 additions and 166 deletions

View file

@ -3,7 +3,7 @@
/* /*
* This file is part of MailSo. * This file is part of MailSo.
* *
* (c) 2014 Usenko Timur * (c) 2021 DJMaze
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.

View file

@ -0,0 +1,82 @@
<?php
/*
* This file is part of MailSo.
*
* (c) 2021 DJMaze
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://datatracker.ietf.org/doc/html/rfc5464
*/
namespace MailSo\Imap\Commands;
/**
* @category MailSo
* @package Imap
*/
trait Metadata
{
public function getMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array
{
$arguments = [];
if ($aOptions) {
$options = [];
$aOptions = \array_intersect_key(
\array_change_key_case($aOptions, CASE_UPPER),
['MAXSIZE' => 0, 'DEPTH' => 0]
);
if (isset($aOptions['MAXSIZE']) && 0 < \intval($aOptions['MAXSIZE'])) {
$options[] = 'MAXSIZE ' . \intval($aOptions['MAXSIZE']);
}
if (isset($aOptions['DEPTH']) && (1 == $aOptions['DEPTH'] || 'infinity' === $aOptions['DEPTH'])) {
$options[] = "DEPTH {$aOptions['DEPTH']}";
}
if ($options) {
$arguments[] = '(' . \implode(' ', $options) . ')';
}
}
$arguments[] = $this->EscapeString($sFolderName);
$arguments[] = '(' . \implode(' ', \array_map([$this, 'EscapeString'], $aEntries)) . ')';
return $this->SendRequestGetResponse('GETMETADATA', $arguments)->getFolderMetadataResult();
}
public function ServerGetMetadata(array $aEntries, array $aOptions = []) : array
{
return $this->IsSupported('METADATA-SERVER')
? $this->getMetadata('', $aEntries, $aOptions)
: [];
}
public function FolderGetMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array
{
return $this->IsSupported('METADATA')
? $this->getMetadata($sFolderName, $aEntries, $aOptions)
: [];
}
public function FolderSetMetadata(string $sFolderName, array $aEntries) : void
{
if ($this->IsSupported('METADATA')) {
if (!$aEntries) {
throw new \MailSo\Base\Exceptions\InvalidArgumentException("Wrong argument for SETMETADATA command");
}
$arguments = [$this->EscapeString($sFolderName)];
\array_walk($aEntries, function(&$v, $k){
$v = $this->EscapeString($k) . ' ' . $this->EscapeString($v);
});
$arguments[] = '(' . \implode(' ', $aEntries) . ')';
$this->SendRequestGetResponse('SETMETADATA', $arguments);
}
}
}

View file

@ -778,32 +778,12 @@ class ImapClient extends \MailSo\Net\NetClient
*/ */
public function MessageSimpleSort(array $aSortTypes, string $sSearchCriterias = 'ALL', bool $bReturnUid = true) : array public function MessageSimpleSort(array $aSortTypes, string $sSearchCriterias = 'ALL', bool $bReturnUid = true) : array
{ {
if (!$aSortTypes) $oSort = new Requests\SORT($this);
{ $oSort->sCriterias = $sSearchCriterias;
$this->writeLogException( $oSort->bUid = $bReturnUid;
new \MailSo\Base\Exceptions\InvalidArgumentException, $oSort->aSortTypes = $aSortTypes;
\MailSo\Log\Enumerations\Type::ERROR, true); return $oSort->SendRequestGetResponse()
} ->getMessageSimpleSortResult($bReturnUid);
if (!$this->IsSupported('SORT'))
{
$this->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException,
\MailSo\Log\Enumerations\Type::ERROR, true);
}
$sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
$sSearchCriterias = !\strlen(\trim($sSearchCriterias)) || '*' === $sSearchCriterias
? 'ALL' : $sSearchCriterias;
$aRequest = array();
$aRequest[] = $aSortTypes;
$aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
$aRequest[] = $sSearchCriterias;
$sCmd = 'SORT';
return $this->SendRequestGetResponse($sCommandPrefix.$sCmd, $aRequest)
->getMessageSimpleSortResult($sCmd, $bReturnUid);
} }
/** /**
@ -832,10 +812,10 @@ class ImapClient extends \MailSo\Net\NetClient
{ {
$oSort = new Requests\SORT($this); $oSort = new Requests\SORT($this);
$oSort->sCriterias = $sSearchCriterias; $oSort->sCriterias = $sSearchCriterias;
$oSort->aReturn = $aSearchReturn ?: ['ALL'];
$oSort->bUid = $bReturnUid; $oSort->bUid = $bReturnUid;
$oSort->sLimit = $sLimit;
$oSort->aSortTypes = $aSortTypes; $oSort->aSortTypes = $aSortTypes;
$oSort->aReturn = $aSearchReturn ?: ['ALL'];
$oSort->sLimit = $sLimit;
return $oSort->SendRequestGetResponse() return $oSort->SendRequestGetResponse()
->getSimpleESearchOrESortResult($this->getCurrentTag(), $bReturnUid); ->getSimpleESearchOrESortResult($this->getCurrentTag(), $bReturnUid);
} }
@ -883,7 +863,7 @@ class ImapClient extends \MailSo\Net\NetClient
} }
} }
return $oResult->getMessageSimpleSearchResult($sCmd, $bReturnUid); return $oResult->getMessageSimpleSearchResult($bReturnUid);
} }
/** /**
@ -893,38 +873,12 @@ class ImapClient extends \MailSo\Net\NetClient
*/ */
public function MessageSimpleThread(string $sSearchCriterias = 'ALL', bool $bReturnUid = true, string $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8) : array public function MessageSimpleThread(string $sSearchCriterias = 'ALL', bool $bReturnUid = true, string $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8) : array
{ {
$sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; $oThread = new Requests\THREAD($this);
$sSearchCriterias = !\strlen(\trim($sSearchCriterias)) || '*' === $sSearchCriterias $oThread->sCriterias = $sSearchCriterias;
? 'ALL' : $sSearchCriterias; $oThread->sCharset = $sCharset;
$oThread->bUid = $bReturnUid;
$sThreadType = ''; return $oThread->SendRequestGetResponse()
switch (true) ->getMessageSimpleThreadResult($bReturnUid);
{
case $this->IsSupported('THREAD=REFS'):
$sThreadType = 'REFS';
break;
case $this->IsSupported('THREAD=REFERENCES'):
$sThreadType = 'REFERENCES';
break;
case $this->IsSupported('THREAD=ORDEREDSUBJECT'):
$sThreadType = 'ORDEREDSUBJECT';
break;
default:
$this->writeLogException(
new Exceptions\RuntimeException('Thread is not supported'),
\MailSo\Log\Enumerations\Type::ERROR, true);
break;
}
$aRequest = array();
$aRequest[] = $sThreadType;
$aRequest[] = \strtoupper($sCharset);
$aRequest[] = $sSearchCriterias;
$sCmd = 'THREAD';
return $this->SendRequestGetResponse($sCommandPrefix.$sCmd, $aRequest)
->getMessageSimpleThreadResult($sCmd, $bReturnUid);
} }
/** /**
@ -1248,37 +1202,6 @@ class ImapClient extends \MailSo\Net\NetClient
return 'IMAP'; return 'IMAP';
} }
/**
* RFC 5464
*/
private function getMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array
{
$arguments = [];
if ($aOptions) {
$options = [];
$aOptions = \array_intersect_key(
\array_change_key_case($aOptions, CASE_UPPER),
['MAXSIZE' => 0, 'DEPTH' => 0]
);
if (isset($aOptions['MAXSIZE']) && 0 < \intval($aOptions['MAXSIZE'])) {
$options[] = 'MAXSIZE ' . \intval($aOptions['MAXSIZE']);
}
if (isset($aOptions['DEPTH']) && (1 == $aOptions['DEPTH'] || 'infinity' === $aOptions['DEPTH'])) {
$options[] = "DEPTH {$aOptions['DEPTH']}";
}
if ($options) {
$arguments[] = '(' . \implode(' ', $options) . ')';
}
}
$arguments[] = $this->EscapeString($sFolderName);
$arguments[] = '(' . \implode(' ', \array_map([$this, 'EscapeString'], $aEntries)) . ')';
return $this->SendRequestGetResponse('GETMETADATA', $arguments)->getFolderMetadataResult();
}
/** /**
* Don't have to be logged in to call this command * Don't have to be logged in to call this command
*/ */
@ -1299,36 +1222,4 @@ class ImapClient extends \MailSo\Net\NetClient
return 'UNKNOWN'; return 'UNKNOWN';
} }
public function ServerGetMetadata(array $aEntries, array $aOptions = []) : array
{
return $this->IsSupported('METADATA-SERVER')
? $this->getMetadata('', $aEntries, $aOptions)
: [];
}
public function FolderGetMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array
{
return $this->IsSupported('METADATA')
? $this->getMetadata($sFolderName, $aEntries, $aOptions)
: [];
}
public function FolderSetMetadata(string $sFolderName, array $aEntries) : void
{
if ($this->IsSupported('METADATA')) {
if (!$aEntries) {
throw new \MailSo\Base\Exceptions\InvalidArgumentException("Wrong argument for SETMETADATA command");
}
$arguments = [$this->EscapeString($sFolderName)];
\array_walk($aEntries, function(&$v, $k){
$v = $this->EscapeString($k) . ' ' . $this->EscapeString($v);
});
$arguments[] = '(' . \implode(' ', $aEntries) . ')';
$this->SendRequestGetResponse('SETMETADATA', $arguments);
}
}
} }

View file

@ -12,6 +12,9 @@
namespace MailSo\Imap\Requests; namespace MailSo\Imap\Requests;
use MailSo\Imap\Exceptions\RuntimeException;
use MailSo\Log\Enumerations\Type;
/** /**
* @category MailSo * @category MailSo
* @package Imap * @package Imap
@ -20,27 +23,51 @@ class ESEARCH extends Request
{ {
public public
$sCriterias = 'ALL', $sCriterias = 'ALL',
$aReturn = [], $aReturn = [
/**
ALL
Return all message numbers/UIDs which match the search criteria,
in the requested sort order, using a sequence-set.
COUNT
As in [ESEARCH].
MAX
Return the message number/UID of the highest sorted message
satisfying the search criteria.
MIN
Return the message number/UID of the lowest sorted message
satisfying the search criteria.
PARTIAL 1:500
Return all message numbers/UIDs which match the search criteria,
in the requested sort order, using a sequence-set.
*/
],
$bUid = true, $bUid = true,
$sLimit = '', $sLimit = '',
$sCharset = '', $sCharset = '',
// https://datatracker.ietf.org/doc/html/rfc7377
$aMailboxes = [], $aMailboxes = [],
$aSubtrees = [], $aSubtrees = [],
$aSubtreesOne = []; $aSubtreesOne = [];
function __construct(\MailSo\Imap\ImapClient $oImapClient)
{
if (!$oImapClient->IsSupported('ESEARCH')) {
$oImapClient->writeLogException(
new RuntimeException('ESEARCH is not supported'),
Type::ERROR, true);
}
parent::__construct($oImapClient);
}
public function SendRequestGetResponse() : \MailSo\Imap\ResponseCollection public function SendRequestGetResponse() : \MailSo\Imap\ResponseCollection
{ {
if (!$this->oImapClient->IsSupported('ESEARCH')) {
$this->oImapClient->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException,
\MailSo\Log\Enumerations\Type::ERROR, true);
}
$sCmd = 'SEARCH'; $sCmd = 'SEARCH';
$aRequest = array(); $aRequest = array();
// TODO: https://github.com/the-djmaze/snappymail/issues/154
// https://datatracker.ietf.org/doc/html/rfc7377
$aFolders = []; $aFolders = [];
if ($this->aMailboxes) { if ($this->aMailboxes) {
$aFolders[] = 'mailboxes'; $aFolders[] = 'mailboxes';
@ -54,7 +81,12 @@ class ESEARCH extends Request
$aFolders[] = 'subtree-one'; $aFolders[] = 'subtree-one';
$aFolders[] = $this->aSubtreesOne; $aFolders[] = $this->aSubtreesOne;
} }
if ($aFolders && $this->oImapClient->IsSupported('MULTISEARCH')) { if ($aFolders) {
if (!$this->oImapClient->IsSupported('MULTISEARCH')) {
$this->oImapClient->writeLogException(
new RuntimeException('MULTISEARCH is not supported'),
Type::ERROR, true);
}
$sCmd = 'ESEARCH'; $sCmd = 'ESEARCH';
$aReques[] = 'IN'; $aReques[] = 'IN';
$aReques[] = $aFolders; $aReques[] = $aFolders;
@ -67,14 +99,22 @@ class ESEARCH extends Request
$aRequest[] = 'RETURN'; $aRequest[] = 'RETURN';
if ($this->aReturn) { if ($this->aReturn) {
// RFC 5267 checks
if (!$this->oImapClient->IsSupported('CONTEXT=SEARCH')) {
foreach ($this->aReturn as $sReturn) {
if (\preg_match('/PARTIAL|UPDATE|CONTEXT/i', $sReturn)) {
$this->oImapClient->writeLogException(
new RuntimeException('CONTEXT=SEARCH is not supported'),
Type::ERROR, true);
}
}
}
$aRequest[] = $this->aReturn; $aRequest[] = $this->aReturn;
} else { } else {
// ALL OR COUNT | MIN | MAX
$aRequest[] = array('ALL'); $aRequest[] = array('ALL');
} }
$aRequest[] = !\strlen($this->sCriterias) || '*' === $this->sCriterias $aRequest[] = (\strlen($this->sCriterias) && '*' !== $this->sCriterias) ? $this->sCriterias : 'ALL';
? 'ALL' : $this->sCriterias;
if (\strlen($this->sLimit)) { if (\strlen($this->sLimit)) {
$aRequest[] = $this->sLimit; $aRequest[] = $this->sLimit;

View file

@ -8,10 +8,16 @@
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*
* https://datatracker.ietf.org/doc/html/rfc5256
* https://datatracker.ietf.org/doc/html/rfc5957
*/ */
namespace MailSo\Imap\Requests; namespace MailSo\Imap\Requests;
use MailSo\Imap\Exceptions\RuntimeException;
use MailSo\Log\Enumerations\Type;
/** /**
* @category MailSo * @category MailSo
* @package Imap * @package Imap
@ -20,44 +26,69 @@ class SORT extends Request
{ {
public public
$sCriterias = 'ALL', $sCriterias = 'ALL',
$sCharset = '',
$bUid = true, $bUid = true,
$sLimit = '',
$aSortTypes = [], $aSortTypes = [],
$sLimit = '',
// rfc5267 // rfc5267
$aReturn = [ $aReturn = [
/* /**
MIN ALL
Return the message number/UID of the lowest sorted message Return all message numbers/UIDs which match the search criteria,
satisfying the search criteria. in the requested sort order, using a sequence-set.
MAX COUNT
Return the message number/UID of the highest sorted message As in [ESEARCH].
satisfying the search criteria.
ALL MAX
Return all message numbers/UIDs which match the search criteria, Return the message number/UID of the highest sorted message
in the requested sort order, using a sequence-set. satisfying the search criteria.
COUNT MIN
As in [ESEARCH]. Return the message number/UID of the lowest sorted message
*/ satisfying the search criteria.
PARTIAL 1:500
Return all message numbers/UIDs which match the search criteria,
in the requested sort order, using a sequence-set.
*/
]; ];
function __construct(\MailSo\Imap\ImapClient $oImapClient)
{
if (!$oImapClient->IsSupported('SORT')) {
$oImapClient->writeLogException(
new RuntimeException('SORT is not supported'),
Type::ERROR, true);
}
parent::__construct($oImapClient);
}
public function SendRequestGetResponse() : \MailSo\Imap\ResponseCollection public function SendRequestGetResponse() : \MailSo\Imap\ResponseCollection
{ {
if (!$this->aSortTypes) { if (!$this->aSortTypes) {
$this->oImapClient->writeLogException( $this->oImapClient->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException, new RuntimeException('SortTypes are missing'),
\MailSo\Log\Enumerations\Type::ERROR, true); Type::ERROR, true);
} }
$aRequest = array(); $aRequest = array();
if ($this->aReturn) { if ($this->aReturn) {
// RFC 5267 checks
if (!$this->oImapClient->IsSupported('ESORT')) { if (!$this->oImapClient->IsSupported('ESORT')) {
$this->oImapClient->writeLogException( $this->oImapClient->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException, new RuntimeException('ESORT is not supported'),
\MailSo\Log\Enumerations\Type::ERROR, true); Type::ERROR, true);
}
if (!$this->oImapClient->IsSupported('CONTEXT=SORT')) {
foreach ($this->aReturn as $sReturn) {
if (\preg_match('/PARTIAL|UPDATE|CONTEXT/i', $sReturn)) {
$this->oImapClient->writeLogException(
new RuntimeException('CONTEXT=SORT is not supported'),
Type::ERROR, true);
}
}
} }
$aRequest[] = 'RETURN'; $aRequest[] = 'RETURN';
$aRequest[] = $this->aReturn; $aRequest[] = $this->aReturn;
@ -66,7 +97,12 @@ class SORT extends Request
$aRequest[] = $this->aSortTypes; $aRequest[] = $this->aSortTypes;
$sSearchCriterias = (\strlen($this->sCriterias) && '*' !== $this->sCriterias) ? $this->sCriterias : 'ALL'; $sSearchCriterias = (\strlen($this->sCriterias) && '*' !== $this->sCriterias) ? $this->sCriterias : 'ALL';
$aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
if (!$this->sCharset) {
$this->sCharset = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
}
$aRequest[] = \strtoupper($this->sCharset);
$aRequest[] = $sSearchCriterias; $aRequest[] = $sSearchCriterias;
if (\strlen($this->sLimit)) { if (\strlen($this->sLimit)) {

View file

@ -0,0 +1,70 @@
<?php
/*
* This file is part of MailSo.
*
* (c) 2014 Usenko Timur
* (c) 2021 DJMaze
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://datatracker.ietf.org/doc/html/rfc5256
*/
namespace MailSo\Imap\Requests;
/**
* @category MailSo
* @package Imap
*/
class THREAD extends Request
{
public
$sAlgorithm = '', // ORDEREDSUBJECT or REFERENCES or REFS
$sCriterias = 'ALL',
$sCharset = '',
$bUid = true;
function __construct(\MailSo\Imap\ImapClient $oImapClient)
{
if ($oImapClient->IsSupported('THREAD=REFS')) {
$this->sAlgorithm = 'REFS';
} else if ($oImapClient->IsSupported('THREAD=REFERENCES')) {
$this->sAlgorithm = 'REFERENCES';
} else if ($oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) {
$this->sAlgorithm = 'ORDEREDSUBJECT';
} else {
$oImapClient->writeLogException(
new RuntimeException('THREAD is not supported'),
Type::ERROR, true);
}
parent::__construct($oImapClient);
}
public function SendRequestGetResponse() : \MailSo\Imap\ResponseCollection
{
if (!$this->oImapClient->IsSupported(\strtoupper("THREAD={$this->sAlgorithm}"))) {
$this->oImapClient->writeLogException(
new Exceptions\RuntimeException("THREAD={$this->sAlgorithm} is not supported"),
\MailSo\Log\Enumerations\Type::ERROR, true);
}
$aRequest = array();
$aRequest[] = $this->sAlgorithm;
$sSearchCriterias = (\strlen($this->sCriterias) && '*' !== $this->sCriterias) ? $this->sCriterias : 'ALL';
if (!$this->sCharset) {
$this->sCharset = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
}
$aRequest[] = \strtoupper($this->sCharset);
$aRequest[] = $sSearchCriterias;
return $this->oImapClient->SendRequestGetResponse(
($this->bUid ? 'UID THREAD' : 'THREAD'),
$aRequest
);
}
}

View file

@ -219,13 +219,13 @@ class ResponseCollection extends \MailSo\Base\Collection
return $aReturn; return $aReturn;
} }
public function getMessageSimpleSearchResult(string $sStatus, bool $bReturnUid) : array public function getMessageSimpleSearchResult(bool $bReturnUid) : array
{ {
$aReturn = array(); $aReturn = array();
foreach ($this as $oResponse) { foreach ($this as $oResponse) {
$iOffset = ($bReturnUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && $sStatus === $oResponse->ResponseList[2]) ? 1 : 0; $iOffset = ($bReturnUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && 'SEARCH' === $oResponse->ResponseList[2]) ? 1 : 0;
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
&& ($sStatus === $oResponse->StatusOrIndex || $iOffset) && ('SEARCH' === $oResponse->StatusOrIndex || $iOffset)
&& \is_array($oResponse->ResponseList) && \is_array($oResponse->ResponseList)
&& 2 < \count($oResponse->ResponseList)) && 2 < \count($oResponse->ResponseList))
{ {
@ -238,13 +238,13 @@ class ResponseCollection extends \MailSo\Base\Collection
return \array_reverse($aReturn); return \array_reverse($aReturn);
} }
public function getMessageSimpleSortResult(string $sStatus, bool $bReturnUid) : array public function getMessageSimpleSortResult(bool $bReturnUid) : array
{ {
$aReturn = array(); $aReturn = array();
foreach ($this as $oResponse) { foreach ($this as $oResponse) {
$iOffset = ($bReturnUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && $sStatus === $oResponse->ResponseList[2]) ? 1 : 0; $iOffset = ($bReturnUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && 'SORT' === $oResponse->ResponseList[2]) ? 1 : 0;
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
&& ($sStatus === $oResponse->StatusOrIndex || $iOffset) && ('SORT' === $oResponse->StatusOrIndex || $iOffset)
&& \is_array($oResponse->ResponseList) && \is_array($oResponse->ResponseList)
&& 2 < \count($oResponse->ResponseList)) && 2 < \count($oResponse->ResponseList))
{ {
@ -257,13 +257,13 @@ class ResponseCollection extends \MailSo\Base\Collection
return $aReturn; return $aReturn;
} }
public function getMessageSimpleThreadResult(string $sStatus, bool $bReturnUid) : array public function getMessageSimpleThreadResult(bool $bReturnUid) : array
{ {
$aReturn = array(); $aReturn = array();
foreach ($this as $oResponse) { foreach ($this as $oResponse) {
$iOffset = ($bReturnUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && $sStatus === $oResponse->ResponseList[2]) ? 1 : 0; $iOffset = ($bReturnUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && 'THREAD' === $oResponse->ResponseList[2]) ? 1 : 0;
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
&& ($sStatus === $oResponse->StatusOrIndex || $iOffset) && ('THREAD' === $oResponse->StatusOrIndex || $iOffset)
&& \is_array($oResponse->ResponseList) && \is_array($oResponse->ResponseList)
&& 2 < \count($oResponse->ResponseList)) && 2 < \count($oResponse->ResponseList))
{ {