mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Improved IMAP sort/search/thread command handling
This commit is contained in:
parent
93ced6f5f0
commit
0055eb6016
7 changed files with 285 additions and 166 deletions
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue