mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Dovecot supports
This commit is contained in:
parent
4fdfd54f87
commit
796b10dc14
4 changed files with 99 additions and 41 deletions
|
|
@ -20,6 +20,40 @@ namespace MailSo\Imap\Commands;
|
||||||
trait Metadata
|
trait Metadata
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dovecot 2.2+ supports fetching all METADATA at once (wildcard).
|
||||||
|
* RFC 5464 doesn't specify this, but its earlier draft did, and Kolab uses it.
|
||||||
|
*/
|
||||||
|
public function getAllMetadata() : array
|
||||||
|
{
|
||||||
|
$aReturn = array();
|
||||||
|
try {
|
||||||
|
$arguments = [
|
||||||
|
'(DEPTH infinity)',
|
||||||
|
$this->EscapeString('*')
|
||||||
|
];
|
||||||
|
$arguments[] = '(' . \implode(' ', \array_map([$this, 'EscapeString'], ['/shared', '/private'])) . ')';
|
||||||
|
$oResult = $this->SendRequestGetResponse('GETMETADATA', $arguments);
|
||||||
|
foreach ($oResult as $oResponse) {
|
||||||
|
if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
||||||
|
&& 4 === \count($oResponse->ResponseList)
|
||||||
|
&& 'METADATA' === $oResponse->ResponseList[1]
|
||||||
|
&& \is_array($oResponse->ResponseList[3]))
|
||||||
|
{
|
||||||
|
$aMetadata = array();
|
||||||
|
$c = \count($oResponse->ResponseList[3]);
|
||||||
|
for ($i = 0; $i < $c; $i += 2) {
|
||||||
|
$aMetadata[$oResponse->ResponseList[3][$i]] = $oResponse->ResponseList[3][$i+1];
|
||||||
|
}
|
||||||
|
$aReturn[$oResponse->ResponseList[2]] = $aMetadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
//\error_log($e->getMessage());
|
||||||
|
}
|
||||||
|
return $aReturn;
|
||||||
|
}
|
||||||
|
|
||||||
public function getMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array
|
public function getMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array
|
||||||
{
|
{
|
||||||
$arguments = [];
|
$arguments = [];
|
||||||
|
|
@ -44,7 +78,23 @@ trait Metadata
|
||||||
$arguments[] = $this->EscapeString($sFolderName);
|
$arguments[] = $this->EscapeString($sFolderName);
|
||||||
|
|
||||||
$arguments[] = '(' . \implode(' ', \array_map([$this, 'EscapeString'], $aEntries)) . ')';
|
$arguments[] = '(' . \implode(' ', \array_map([$this, 'EscapeString'], $aEntries)) . ')';
|
||||||
return $this->SendRequestGetResponse('GETMETADATA', $arguments)->getFolderMetadataResult();
|
|
||||||
|
$oResult = $this->SendRequestGetResponse('GETMETADATA', $arguments);
|
||||||
|
|
||||||
|
$aReturn = array();
|
||||||
|
foreach ($oResult as $oResponse) {
|
||||||
|
if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
||||||
|
&& 4 === \count($oResponse->ResponseList)
|
||||||
|
&& 'METADATA' === $oResponse->ResponseList[1]
|
||||||
|
&& \is_array($oResponse->ResponseList[3]))
|
||||||
|
{
|
||||||
|
$c = \count($oResponse->ResponseList[3]);
|
||||||
|
for ($i = 0; $i < $c; $i += 2) {
|
||||||
|
$aReturn[$oResponse->ResponseList[3][$i]] = $oResponse->ResponseList[3][$i+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $aReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ServerGetMetadata(array $aEntries, array $aOptions = []) : array
|
public function ServerGetMetadata(array $aEntries, array $aOptions = []) : array
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,11 @@ class Folder
|
||||||
$this->aMetadata[$sName] = $sData;
|
$this->aMetadata[$sName] = $sData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function SetAllMetadata(array $aMetadata) : void
|
||||||
|
{
|
||||||
|
$this->aMetadata = $aMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -534,38 +534,33 @@ class ImapClient extends \MailSo\Net\NetClient
|
||||||
$this->SendRequest($sCmd, $aParameters);
|
$this->SendRequest($sCmd, $aParameters);
|
||||||
$bPassthru = false;
|
$bPassthru = false;
|
||||||
if ($bPassthru) {
|
if ($bPassthru) {
|
||||||
// TODO: passthru to parse response in JavaScript
|
$this->streamResponse();
|
||||||
// This will reduce CPU time on server and moves it to the client
|
|
||||||
// And can be used with the new JavaScript AbstractFetchRemote.streamPerLine(fCallback, sGetAdd)
|
|
||||||
if (\is_resource($this->ConnectionResource())) {
|
|
||||||
\SnappyMail\HTTP\Stream::start();
|
|
||||||
$sEndTag = $this->getCurrentTag();
|
|
||||||
$sLine = \fgets($this->ConnectionResource());
|
|
||||||
do {
|
|
||||||
echo $sLine;
|
|
||||||
if (0 === \strpos($sLine, $sEndTag)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$sLine = \fgets($this->ConnectionResource());
|
|
||||||
} while (\strlen($sLine));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$aReturn = $this->getResponse()->getFoldersResult($sCmd);
|
$aReturn = $this->getResponse()->getFoldersResult($sCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RFC 5464
|
// RFC 5464
|
||||||
if (!$bIsSubscribeList && $this->IsSupported('METADATA')) {
|
if (!$bIsSubscribeList && $this->IsSupported('METADATA')) {
|
||||||
|
// Dovecot supports fetching all METADATA at once
|
||||||
|
$aMetadata = $this->getAllMetadata();
|
||||||
|
if ($aMetadata) {
|
||||||
|
foreach ($aReturn as $oFolder) {
|
||||||
|
if (isset($aMetadata[$oFolder->FullNameRaw()])) {
|
||||||
|
$oFolder->SetAllMetadata($aMetadata[$oFolder->FullNameRaw()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
foreach ($aReturn as $oFolder) {
|
foreach ($aReturn as $oFolder) {
|
||||||
try {
|
try {
|
||||||
foreach ($this->getMetadata($oFolder->FullNameRaw(), ['/shared', '/private'], ['DEPTH'=>'infinity']) as $key => $value) {
|
$oFolder->SetAllMetadata(
|
||||||
$oFolder->SetMetadata($key, $value);
|
$this->getMetadata($oFolder->FullNameRaw(), ['/shared', '/private'], ['DEPTH'=>'infinity'])
|
||||||
}
|
);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $aReturn;
|
return $aReturn;
|
||||||
}
|
}
|
||||||
|
|
@ -1099,10 +1094,36 @@ class ImapClient extends \MailSo\Net\NetClient
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* TODO: passthru to parse response in JavaScript
|
||||||
|
* This will reduce CPU time on server and moves it to the client
|
||||||
|
* And can be used with the new JavaScript AbstractFetchRemote.streamPerLine(fCallback, sGetAdd)
|
||||||
|
*
|
||||||
* @throws \MailSo\Imap\Exceptions\ResponseNotFoundException
|
* @throws \MailSo\Imap\Exceptions\ResponseNotFoundException
|
||||||
* @throws \MailSo\Imap\Exceptions\InvalidResponseException
|
* @throws \MailSo\Imap\Exceptions\InvalidResponseException
|
||||||
* @throws \MailSo\Imap\Exceptions\NegativeResponseException
|
* @throws \MailSo\Imap\Exceptions\NegativeResponseException
|
||||||
*/
|
*/
|
||||||
|
private function streamResponse(string $sEndTag = null) : void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (\is_resource($this->ConnectionResource())) {
|
||||||
|
\SnappyMail\HTTP\Stream::start();
|
||||||
|
$sEndTag = $sEndTag ?: $this->getCurrentTag();
|
||||||
|
$sLine = \fgets($this->ConnectionResource());
|
||||||
|
do {
|
||||||
|
echo $sLine;
|
||||||
|
if (0 === \strpos($sLine, $sEndTag)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$sLine = \fgets($this->ConnectionResource());
|
||||||
|
} while (\strlen($sLine));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->writeLogException($e, \MailSo\Log\Enumerations\Type::WARNING);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function getResponse(string $sEndTag = null) : ResponseCollection
|
private function getResponse(string $sEndTag = null) : ResponseCollection
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -88,24 +88,6 @@ class ResponseCollection extends \MailSo\Base\Collection
|
||||||
return $aReturn;
|
return $aReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFolderMetadataResult() : array
|
|
||||||
{
|
|
||||||
$aReturn = array();
|
|
||||||
foreach ($this as $oResponse) {
|
|
||||||
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
|
||||||
&& 4 === \count($oResponse->ResponseList)
|
|
||||||
&& 'METADATA' === $oResponse->ResponseList[1]
|
|
||||||
&& \is_array($oResponse->ResponseList[3]))
|
|
||||||
{
|
|
||||||
$c = \count($oResponse->ResponseList[3]);
|
|
||||||
for ($i = 0; $i < $c; $i += 2) {
|
|
||||||
$aReturn[$oResponse->ResponseList[3][$i]] = $oResponse->ResponseList[3][$i+1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $aReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFoldersResult(string $sStatus) : array
|
public function getFoldersResult(string $sStatus) : array
|
||||||
{
|
{
|
||||||
$aReturn = array();
|
$aReturn = array();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue