Skip to content

Commit

Permalink
Add support for RFC 5464 regarding issue #152 Kolab
Browse files Browse the repository at this point in the history
  • Loading branch information
djmaze committed Oct 12, 2021
1 parent 33f42cc commit 73eb89b
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 3 deletions.
21 changes: 21 additions & 0 deletions snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ class Folder
*/
private $aExtended = array();

/**
* RFC 5464
*/
private $aMetadata = array();

/**
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
*/
Expand Down Expand Up @@ -139,4 +144,20 @@ public function GetExtended(string $sName)
{
return isset($this->aExtended[$sName]) ? $this->aExtended[$sName] : null;
}

/**
* @param mixed $mData
*/
public function SetMetadata(string $sName, string $sData) : void
{
$this->aMetadata[$sName] = $sData;
}

/**
* @return mixed
*/
public function GetMetadata(string $sName) : ?string
{
return isset($this->aMetadata[$sName]) ? $this->aMetadata[$sName] : null;
}
}
102 changes: 99 additions & 3 deletions snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ public function Capability() : ?array
* URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED
* I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH
* LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY STATUS=SIZE LITERAL+ NOTIFY SPECIAL-USE
* STARTTLS AUTH= LOGIN LOGINDISABLED QUOTA
* METADATA METADATA-SERVER
*
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
Expand Down Expand Up @@ -463,7 +465,18 @@ private function specificFolderList(bool $bIsSubscribeList, string $sParentFolde
$bUseListStatus = false;
}

return $this->SendRequestGetResponse($sCmd, $aParameters)->getFoldersResult($sCmd, $bUseListStatus);
$aReturn = $this->SendRequestGetResponse($sCmd, $aParameters)->getFoldersResult($sCmd, $bUseListStatus);

// RFC 5464
if ($this->IsSupported('METADATA')) {
foreach ($aReturn as $oFolder) {
foreach ($this->FolderGetMetadata($oFolder->FullNameRaw(), ['/shared', '/private'], ['DEPTH'=>'infinity']) as $key => $value) {
$oFolder->SetMetadata($key, $value);
}
}
}

return $aReturn;
}

/**
Expand Down Expand Up @@ -1717,13 +1730,96 @@ private function getCurrentTag() : string
return self::TAG_PREFIX.$this->iTagCount;
}

public function EscapeString(string $sStringForEscape) : string
public function EscapeString(?string $sStringForEscape) : string
{
return '"'.\str_replace(array('\\', '"'), array('\\\\', '\\"'), $sStringForEscape).'"';
if (null === $sStringForEscape) {
return 'NIL';
}
/*
// literal-string
if (\preg_match('/[\r\n\x00\x80-\xFF]/', $sStringForEscape)) {
return \sprintf("{%d}\r\n%s", \strlen($sStringForEscape), $sStringForEscape);
}
*/
// quoted-string
return '"' . \addcslashes($sStringForEscape, '\\"') . '"';
}

protected function getLogName() : string
{
return 'IMAP';
}

/**
* RFC 5464
*/

const
ADMIN_SHARED = '/shared/admin', // Server
COMMENT_SHARED = '/shared/comment', // Server & Mailbox
COMMENT_PRIVATE = '/private/comment', // Mailbox
// RFC 6154
SPECIALUSE_PRIVATE = '/private/specialuse',
// Kolab
KOLAB_CTYPE_KEY_SHARED = '/shared/vendor/kolab/folder-type',
KOLAB_CTYPE_KEY_PRIVATE = '/private/vendor/kolab/folder-type',
KOLAB_COLOR_KEY_SHARED = '/shared/vendor/kolab/color',
KOLAB_COLOR_KEY_PRIVATE = '/private/vendor/kolab/color',
KOLAB_NAME_KEY_SHARED = '/shared/vendor/kolab/displayname',
KOLAB_NAME_KEY_PRIVATE = '/private/vendor/kolab/displayname',
KOLAB_UID_KEY_SHARED = '/shared/vendor/kolab/uniqueid',
CYRUS_UID_KEY_SHARED = '/shared/vendor/cmu/cyrus-imapd/uniqueid';

public function FolderGetMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array
{
if (!$this->IsSupported('METADATA') && !(!\strlen($sFolderName) && $this->IsSupported('METADATA-SERVER'))) {
return [];
}

$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 FolderSetMetadata(string $sFolderName, array $aEntries)
{
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) . ')';

$result = $this->SendRequestGetResponse('SETMETADATA', $arguments);
}

public function FolderDeleteMetadata($sFolderName, array $aEntries)
{
$this->SetMetadata($sFolderName, \array_fill_keys(\array_keys($aEntries), null));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,25 @@ private function getArrayNameToStringName($mName) : string
return '';
}

public function getFolderMetadataResult() : array
{
$aReturn = array();
foreach ($this 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) {
$value = $oResponse->ResponseList[3][$i+1];
$aReturn[$oResponse->ResponseList[3][$i]] = ('NIL' === $value) ? null : $value;
}
}
}
return $aReturn;
}

public function getFoldersResult(string $sStatus, bool $bUseListStatus = false) : array
{
$aReturn = array();
Expand Down

0 comments on commit 73eb89b

Please sign in to comment.