Activated search subfolders as request by #154

This commit is contained in:
djmaze 2021-11-03 02:28:01 +01:00
parent b1038667ee
commit 6c797c34f8
51 changed files with 1024 additions and 874 deletions

View file

@ -840,7 +840,7 @@ class AppUser extends AbstractApp {
if (getFolderInboxName() !== cF) {
this.folderInformation(cF);
}
FolderUserStore.listStatusSupported() || this.folderInformationMultiply(true);
FolderUserStore.hasCapability('LIST-STATUS') || this.folderInformationMultiply(true);
}, 1000);
setTimeout(() => Remote.appDelayStart(()=>0), 35000);

View file

@ -37,13 +37,11 @@ export class FolderCollectionModel extends AbstractCollectionModel
super();
this.CountRec
this.FoldersHash
this.IsMetadataSupported
this.IsThreadsSupported
this.IsSortSupported
this.IsExtendedSupported
this.Namespace;
this.Optimized
this.SystemFolders
this.Capabilities
}
*/
@ -146,11 +144,9 @@ export class FolderCollectionModel extends AbstractCollectionModel
AppUserStore.threadsAllowed(!!(Settings.app('useImapThread') && this.IsThreadsSupported));
FolderUserStore.folderListOptimized(!!this.Optimized);
FolderUserStore.sortSupported(!!this.IsSortSupported);
FolderUserStore.metadataSupported(!!this.IsMetadataSupported);
FolderUserStore.listStatusSupported(!!this.IsListStatusSupported);
FolderUserStore.quotaUsage(this.quotaUsage);
FolderUserStore.quotaLimit(this.quotaLimit);
FolderUserStore.capabilities(this.Capabilities);
FolderUserStore.sentFolder(normalizeFolder(SettingsGet('SentFolder')));
FolderUserStore.draftFolder(normalizeFolder(SettingsGet('DraftFolder')));

View file

@ -26,7 +26,7 @@ const folderForDeletion = ko.observable(null).deleteAccessHelper();
export class FoldersUserSettings /*extends AbstractViewSettings*/ {
constructor() {
this.showKolab = Settings.capa(Capa.Kolab) && FolderUserStore.metadataSupported();
this.showKolab = ko.computed(() => FolderUserStore.hasCapability('METADATA') && Settings.capa(Capa.Kolab));
this.defaultOptionsAfterRender = defaultOptionsAfterRender;
this.kolabTypeOptions = ko.observableArray();
let i18nFilter = key => i18n('SETTINGS_FOLDERS/TYPE_' + key);

View file

@ -9,7 +9,8 @@ import { Settings, SettingsGet } from 'Common/Globals';
export const FolderUserStore = new class {
constructor() {
addObservablesTo(this, {
const self = this;
addObservablesTo(self, {
/**
* To use "checkable" option in /#/settings/folders
* When true, getNextFolderNames only lists system and "checkable" folders
@ -19,12 +20,6 @@ export const FolderUserStore = new class {
*/
displaySpecSetting: false,
/**
* If the IMAP server supports SORT, METADATA
*/
sortSupported: false,
metadataSupported: false,
listStatusSupported: false,
// sortMode: '',
quotaLimit: 0,
@ -47,40 +42,42 @@ export const FolderUserStore = new class {
foldersInboxUnreadCount: 0
});
this.sortMode = ko.observable('').extend({ limitedList: Object.values(FolderSortMode) });
self.sortMode = ko.observable('').extend({ limitedList: Object.values(FolderSortMode) });
this.namespace = '';
self.namespace = '';
this.folderList = ko.observableArray();
self.folderList = ko.observableArray();
this.currentFolder = ko.observable(null).extend({ toggleSubscribeProperty: [this, 'selected'] });
self.capabilities = ko.observableArray();
this.sieveAllowFileintoInbox = !!SettingsGet('SieveAllowFileintoInbox');
self.currentFolder = ko.observable(null).extend({ toggleSubscribeProperty: [self, 'selected'] });
addComputablesTo(this, {
self.sieveAllowFileintoInbox = !!SettingsGet('SieveAllowFileintoInbox');
draftFolderNotEnabled: () => !this.draftFolder() || UNUSED_OPTION_VALUE === this.draftFolder(),
addComputablesTo(self, {
currentFolderFullNameRaw: () => (this.currentFolder() ? this.currentFolder().fullNameRaw : ''),
draftFolderNotEnabled: () => !self.draftFolder() || UNUSED_OPTION_VALUE === self.draftFolder(),
currentFolderFullName: () => (this.currentFolder() ? this.currentFolder().fullName : ''),
currentFolderFullNameHash: () => (this.currentFolder() ? this.currentFolder().fullNameHash : ''),
currentFolderFullNameRaw: () => (self.currentFolder() ? self.currentFolder().fullNameRaw : ''),
currentFolderFullName: () => (self.currentFolder() ? self.currentFolder().fullName : ''),
currentFolderFullNameHash: () => (self.currentFolder() ? self.currentFolder().fullNameHash : ''),
foldersChanging: () =>
this.foldersLoading() | this.foldersCreating() | this.foldersDeleting() | this.foldersRenaming(),
self.foldersLoading() | self.foldersCreating() | self.foldersDeleting() | self.foldersRenaming(),
folderListSystemNames: () => {
const list = [getFolderInboxName()],
others = [this.sentFolder(), this.draftFolder(), this.spamFolder(), this.trashFolder(), this.archiveFolder()];
others = [self.sentFolder(), self.draftFolder(), self.spamFolder(), self.trashFolder(), self.archiveFolder()];
this.folderList().length &&
self.folderList().length &&
others.forEach(name => name && UNUSED_OPTION_VALUE !== name && list.push(name));
return list;
},
folderListSystem: () =>
this.folderListSystemNames().map(name => getFolderFromCacheList(name)).filter(v => v)
self.folderListSystemNames().map(name => getFolderFromCacheList(name)).filter(v => v)
});
const
@ -93,13 +90,13 @@ export const FolderUserStore = new class {
folder && folder.type(type);
};
this.sentFolder.subscribe(fRemoveSystemFolderType(this.sentFolder), this, 'beforeChange');
this.draftFolder.subscribe(fRemoveSystemFolderType(this.draftFolder), this, 'beforeChange');
this.spamFolder.subscribe(fRemoveSystemFolderType(this.spamFolder), this, 'beforeChange');
this.trashFolder.subscribe(fRemoveSystemFolderType(this.trashFolder), this, 'beforeChange');
this.archiveFolder.subscribe(fRemoveSystemFolderType(this.archiveFolder), this, 'beforeChange');
self.sentFolder.subscribe(fRemoveSystemFolderType(self.sentFolder), self, 'beforeChange');
self.draftFolder.subscribe(fRemoveSystemFolderType(self.draftFolder), self, 'beforeChange');
self.spamFolder.subscribe(fRemoveSystemFolderType(self.spamFolder), self, 'beforeChange');
self.trashFolder.subscribe(fRemoveSystemFolderType(self.trashFolder), self, 'beforeChange');
self.archiveFolder.subscribe(fRemoveSystemFolderType(self.archiveFolder), self, 'beforeChange');
addSubscribablesTo(this, {
addSubscribablesTo(self, {
sentFolder: fSetSystemFolderType(FolderType.Sent),
draftFolder: fSetSystemFolderType(FolderType.Drafts),
spamFolder: fSetSystemFolderType(FolderType.Spam),
@ -107,12 +104,19 @@ export const FolderUserStore = new class {
archiveFolder: fSetSystemFolderType(FolderType.Archive)
});
this.quotaPercentage = ko.computed(() => {
const quota = this.quotaLimit(), usage = this.quotaUsage();
self.quotaPercentage = ko.computed(() => {
const quota = self.quotaLimit(), usage = self.quotaUsage();
return 0 < quota ? Math.ceil((usage / quota) * 100) : 0;
});
}
/**
* If the IMAP server supports SORT, METADATA
*/
hasCapability(name) {
return this.capabilities().includes(name);
}
/**
* @returns {Array}
*/

View file

@ -6,6 +6,7 @@ import { MessageUserStore } from 'Stores/User/Message';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { FolderUserStore } from 'Stores/User/Folder';
class AdvancedSearchPopupView extends AbstractViewPopup {
constructor() {
@ -17,12 +18,15 @@ class AdvancedSearchPopupView extends AbstractViewPopup {
subject: '',
text: '',
selectedDateValue: -1,
selectedTreeValue: '',
hasAttachment: false,
starred: false,
unseen: false
});
this.showMultisearch = ko.computed(() => FolderUserStore.hasCapability('MULTISEARCH'));
let prefix = 'SEARCH/LABEL_ADV_DATE_';
this.selectedDates = ko.computed(() => {
translatorTrigger();
@ -37,6 +41,16 @@ class AdvancedSearchPopupView extends AbstractViewPopup {
];
});
prefix = 'SEARCH/LABEL_ADV_SUBFOLDERS_';
this.selectedTree = ko.computed(() => {
translatorTrigger();
return [
{ id: '', name: i18n(prefix + 'NONE') },
{ id: 'subtree-one', name: i18n(prefix + 'SUBTREE_ONE') },
{ id: 'subtree', name: i18n(prefix + 'SUBTREE') }
];
});
decorateKoCommands(this, {
searchCommand: 1
});
@ -69,65 +83,54 @@ class AdvancedSearchPopupView extends AbstractViewPopup {
});
}
buildSearchStringValue(value) {
if (value.includes(' ')) {
value = '"' + value + '"';
}
return value;
}
buildSearchString() {
const result = [],
from_ = this.from().trim(),
to = this.to().trim(),
subject = this.subject().trim(),
text = this.text().trim(),
isPart = [],
hasPart = [];
const
result = new FormData();
if (from_) {
result.push('from:' + this.buildSearchStringValue(from_));
let value = this.from().trim();
if (value) {
result.set('from', value);
}
if (to) {
result.push('to:' + this.buildSearchStringValue(to));
value = this.to().trim();
if (value) {
result.set('to', value);
}
if (subject) {
result.push('subject:' + this.buildSearchStringValue(subject));
value = this.subject().trim();
if (value) {
result.set('subject', value);
}
if (this.hasAttachment()) {
hasPart.push('attachment');
result.set('has', 'attachment');
}
if (this.unseen()) {
isPart.push('unseen');
result.set('is[]', 'unseen');
}
if (this.starred()) {
isPart.push('flagged');
}
if (hasPart.length) {
result.push('has:' + hasPart.join(','));
}
if (isPart.length) {
result.push('is:' + isPart.join(','));
result.set('is[]', 'flagged');
}
if (-1 < this.selectedDateValue()) {
let d = new Date();
d.setDate(d.getDate() - this.selectedDateValue());
result.push('date:' + d.format('Y.m.d') + '/');
result.set('date', d.format('Y.m.d') + '/');
}
if (text) {
result.push('text:' + this.buildSearchStringValue(text));
value = this.selectedTreeValue();
if (value) {
result.set('in', value);
}
return result.join(' ').trim();
value = this.text().trim();
if (value) {
result.set('text', value);
}
return new URLSearchParams(result).toString();
}
clearPopup() {

View file

@ -64,7 +64,9 @@ export class MailMessageList extends AbstractViewRight {
this.messageList = MessageUserStore.list;
this.sortSupported = FolderUserStore.sortSupported;
this.sortSupported = ko.computed(() =>
FolderUserStore.hasCapability('SORT') | FolderUserStore.hasCapability('ESORT')
);
this.composeInEdit = AppUserStore.composeInEdit;
this.leftPanelDisabled = leftPanelDisabled;

View file

@ -452,7 +452,7 @@ class ImapClient extends \MailSo\Net\NetClient
if ($this->IsSupported('ESEARCH')) {
$aResult = $oFolderInfo->getStatusItems();
// SELECT or EXAMINE command then UNSEEN is the message sequence number of the first unseen message
$aResult['UNSEEN'] = $this->simpleESearchOrESortHelper(false, 'UNSEEN', ['COUNT'])['COUNT'];
$aResult['UNSEEN'] = $this->MessageSimpleESearch('UNSEEN', ['COUNT'])['COUNT'];
return $aResult;
}
*/
@ -778,10 +778,6 @@ class ImapClient extends \MailSo\Net\NetClient
*/
public function MessageSimpleSort(array $aSortTypes, string $sSearchCriterias = 'ALL', bool $bReturnUid = true) : array
{
$sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
$sSearchCriterias = !\strlen(\trim($sSearchCriterias)) || '*' === $sSearchCriterias
? 'ALL' : $sSearchCriterias;
if (!$aSortTypes)
{
$this->writeLogException(
@ -795,6 +791,10 @@ class ImapClient extends \MailSo\Net\NetClient
\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';
@ -811,72 +811,15 @@ class ImapClient extends \MailSo\Net\NetClient
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
private function simpleESearchOrESortHelper(bool $bSort = false, string $sSearchCriterias = 'ALL', array $aSearchOrSortReturn = null, bool $bReturnUid = true, string $sLimit = '', string $sCharset = '', array $aSortTypes = null) : array
public function MessageSimpleESearch(string $sSearchCriterias = 'ALL', array $aSearchReturn = null, bool $bReturnUid = true, string $sCharset = '', string $sLimit = '') : array
{
$sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
$sSearchCriterias = !\strlen($sSearchCriterias) || '*' === $sSearchCriterias
? 'ALL' : $sSearchCriterias;
$sCmd = $bSort ? 'SORT': 'SEARCH';
if ($bSort && (!$aSortTypes || !$this->IsSupported('SORT')))
{
$this->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException,
\MailSo\Log\Enumerations\Type::ERROR, true);
}
if (!$this->IsSupported($bSort ? 'ESORT' : 'ESEARCH'))
{
$this->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException,
\MailSo\Log\Enumerations\Type::ERROR, true);
}
if (!$aSearchOrSortReturn)
{
// ALL OR COUNT | MIN | MAX
$aSearchOrSortReturn = array('ALL');
}
$aRequest = array();
if ($bSort)
{
$aRequest[] = 'RETURN';
$aRequest[] = $aSearchOrSortReturn;
$aRequest[] = $aSortTypes;
$aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
}
else
{
/*
TODO: https://github.com/the-djmaze/snappymail/issues/154
https://datatracker.ietf.org/doc/html/rfc6237
$sCmd = 'ESEARCH';
$aReques[] = 'IN';
$aReques[] = ['mailboxes', '"folder1"', 'subtree', '"folder2"'];
$aReques[] = ['mailboxes', '"folder1"', 'subtree-one', '"folder2"'];
*/
if (\strlen($sCharset))
{
$aRequest[] = 'CHARSET';
$aRequest[] = \strtoupper($sCharset);
}
$aRequest[] = 'RETURN';
$aRequest[] = $aSearchOrSortReturn;
}
$aRequest[] = $sSearchCriterias;
if (\strlen($sLimit))
{
$aRequest[] = $sLimit;
}
return $this->SendRequestGetResponse($sCommandPrefix.$sCmd, $aRequest)
$oESearch = new Requests\ESEARCH($this);
$oESearch->sCriterias = $sSearchCriterias;
$oESearch->aReturn = $aSearchReturn;
$oESearch->bUid = $bReturnUid;
$oESearch->sLimit = $sLimit;
$oESearch->sCharset = $sCharset;
return $oESearch->SendRequestGetResponse()
->getSimpleESearchOrESortResult($this->getCurrentTag(), $bReturnUid);
}
@ -885,19 +828,16 @@ class ImapClient extends \MailSo\Net\NetClient
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
public function MessageSimpleESearch(string $sSearchCriterias = 'ALL', array $aSearchReturn = null, bool $bReturnUid = true, string $sLimit = '', string $sCharset = '') : array
public function MessageSimpleESort(array $aSortTypes, string $sSearchCriterias = 'ALL', array $aSearchReturn = ['ALL'], bool $bReturnUid = true, string $sLimit = '') : array
{
return $this->simpleESearchOrESortHelper(false, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, $sCharset);
}
/**
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
public function MessageSimpleESort(array $aSortTypes, string $sSearchCriterias = 'ALL', array $aSearchReturn = null, bool $bReturnUid = true, string $sLimit = '') : array
{
return $this->simpleESearchOrESortHelper(true, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, '', $aSortTypes);
$oSort = new Requests\SORT($this);
$oSort->sCriterias = $sSearchCriterias;
$oSort->aReturn = $aSearchReturn ?: ['ALL'];
$oSort->bUid = $bReturnUid;
$oSort->sLimit = $sLimit;
$oSort->aSortTypes = $aSortTypes;
return $oSort->SendRequestGetResponse()
->getSimpleESearchOrESortResult($this->getCurrentTag(), $bReturnUid);
}
/**

View file

@ -0,0 +1,88 @@
<?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.
*/
namespace MailSo\Imap\Requests;
/**
* @category MailSo
* @package Imap
*/
class ESEARCH extends Request
{
public
$sCriterias = 'ALL',
$aReturn = [],
$bUid = true,
$sLimit = '',
$sCharset = '',
$aMailboxes = [],
$aSubtrees = [],
$aSubtreesOne = [];
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';
$aRequest = array();
// TODO: https://github.com/the-djmaze/snappymail/issues/154
// https://datatracker.ietf.org/doc/html/rfc7377
$aFolders = [];
if ($this->aMailboxes) {
$aFolders[] = 'mailboxes';
$aFolders[] = $this->aMailboxes;
}
if ($this->aSubtrees) {
$aFolders[] = 'subtree';
$aFolders[] = $this->aSubtrees;
}
if ($this->aSubtreesOne) {
$aFolders[] = 'subtree-one';
$aFolders[] = $this->aSubtreesOne;
}
if ($aFolders && $this->oImapClient->IsSupported('MULTISEARCH')) {
$sCmd = 'ESEARCH';
$aReques[] = 'IN';
$aReques[] = $aFolders;
}
if (\strlen($this->sCharset)) {
$aRequest[] = 'CHARSET';
$aRequest[] = \strtoupper($this->sCharset);
}
$aRequest[] = 'RETURN';
if ($this->aReturn) {
$aRequest[] = $this->aReturn;
} else {
// ALL OR COUNT | MIN | MAX
$aRequest[] = array('ALL');
}
$aRequest[] = !\strlen($this->sCriterias) || '*' === $this->sCriterias
? 'ALL' : $this->sCriterias;
if (\strlen($this->sLimit)) {
$aRequest[] = $this->sLimit;
}
return $this->oImapClient->SendRequestGetResponse(
($this->bUid ? 'UID ' : '') . $sCmd,
$aRequest
);
}
}

View file

@ -0,0 +1,29 @@
<?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.
*/
namespace MailSo\Imap\Requests;
abstract class Request
{
protected
$oImapClient;
function __construct(\MailSo\Imap\ImapClient $oImapClient)
{
$this->oImapClient = $oImapClient;
}
final public function getName()
{
$name = \explode('\\', \get_class($this));
return \end($name);
}
}

View file

@ -0,0 +1,81 @@
<?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.
*/
namespace MailSo\Imap\Requests;
/**
* @category MailSo
* @package Imap
*/
class SORT extends Request
{
public
$sCriterias = 'ALL',
$bUid = true,
$sLimit = '',
$aSortTypes = [],
// rfc5267
$aReturn = [
/*
MIN
Return the message number/UID of the lowest sorted message
satisfying the search criteria.
MAX
Return the message number/UID of the highest sorted message
satisfying the search criteria.
ALL
Return all message numbers/UIDs which match the search criteria,
in the requested sort order, using a sequence-set.
COUNT
As in [ESEARCH].
*/
];
public function SendRequestGetResponse() : \MailSo\Imap\ResponseCollection
{
if (!$this->aSortTypes) {
$this->oImapClient->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException,
\MailSo\Log\Enumerations\Type::ERROR, true);
}
$aRequest = array();
if ($this->aReturn) {
if (!$this->oImapClient->IsSupported('ESORT')) {
$this->oImapClient->writeLogException(
new \MailSo\Base\Exceptions\InvalidArgumentException,
\MailSo\Log\Enumerations\Type::ERROR, true);
}
$aRequest[] = 'RETURN';
$aRequest[] = $this->aReturn;
}
$aRequest[] = $this->aSortTypes;
$sSearchCriterias = (\strlen($this->sCriterias) && '*' !== $this->sCriterias) ? $this->sCriterias : 'ALL';
$aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
$aRequest[] = $sSearchCriterias;
if (\strlen($this->sLimit)) {
$aRequest[] = $this->sLimit;
}
return $this->oImapClient->SendRequestGetResponse(
($this->bUid ? 'UID SORT' : 'SORT'),
$aRequest
);
}
}

View file

@ -227,7 +227,7 @@ class ResponseCollection extends \MailSo\Base\Collection
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
&& ($sStatus === $oResponse->StatusOrIndex || $iOffset)
&& \is_array($oResponse->ResponseList)
&& 2 < count($oResponse->ResponseList))
&& 2 < \count($oResponse->ResponseList))
{
$iLen = \count($oResponse->ResponseList);
for ($iIndex = 2 + $iOffset; $iIndex < $iLen; ++$iIndex) {
@ -270,12 +270,13 @@ class ResponseCollection extends \MailSo\Base\Collection
$iLen = \count($oResponse->ResponseList);
for ($iIndex = 2 + $iOffset; $iIndex < $iLen; ++$iIndex) {
$aNewValue = $this->validateThreadItem($oResponse->ResponseList[$iIndex]);
if (false !== $aNewValue) {
if (\is_array($aNewValue)) {
$aReturn[] = $aNewValue;
}
}
}
}
return $aReturn;
}
@ -374,27 +375,24 @@ class ResponseCollection extends \MailSo\Base\Collection
$aResult = array();
foreach ($this as $oResponse) {
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
&& ('ESEARCH' === $oResponse->StatusOrIndex || 'ESORT' === $oResponse->StatusOrIndex)
&& ('ESEARCH' === $oResponse->StatusOrIndex || 'SORT' === $oResponse->StatusOrIndex)
&& \is_array($oResponse->ResponseList)
&& isset($oResponse->ResponseList[2], $oResponse->ResponseList[2][0], $oResponse->ResponseList[2][1])
&& isset($oResponse->ResponseList[2][1])
&& 'TAG' === $oResponse->ResponseList[2][0] && $sRequestTag === $oResponse->ResponseList[2][1]
&& (!$bReturnUid || ($bReturnUid && !empty($oResponse->ResponseList[3]) && 'UID' === $oResponse->ResponseList[3]))
&& (!$bReturnUid || (!empty($oResponse->ResponseList[3]) && 'UID' === $oResponse->ResponseList[3]))
)
{
$iStart = 3;
foreach ($oResponse->ResponseList as $iIndex => $mItem) {
if ($iIndex >= $iStart) {
switch ($mItem)
{
case 'ALL':
case 'MAX':
case 'MIN':
case 'COUNT':
if (isset($oResponse->ResponseList[$iIndex + 1])) {
$aResult[$mItem] = $oResponse->ResponseList[$iIndex + 1];
}
break;
}
$i = \count($oResponse->ResponseList) - 1;
while (3 < --$i) {
$sItem = $oResponse->ResponseList[$i];
switch ($sItem)
{
case 'ALL':
case 'MAX':
case 'MIN':
case 'COUNT':
$aResult[$sItem] = $oResponse->ResponseList[$i + 1];
break;
}
}
}

View file

@ -0,0 +1,449 @@
<?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.
*/
namespace MailSo\Imap;
/**
* @category MailSo
* @package Mail
*/
class SearchCriterias
{
/**
https://datatracker.ietf.org/doc/html/rfc3501#section-6.4.4
ALL
All messages in the mailbox; the default initial key for
ANDing.
BCC <string>
Messages that contain the specified string in the envelope
structure's BCC field.
BEFORE <date>
Messages whose internal date (disregarding time and timezone)
is earlier than the specified date.
BODY <string>
Messages that contain the specified string in the body of the
message.
CC <string>
Messages that contain the specified string in the envelope
structure's CC field.
FROM <string>
Messages that contain the specified string in the envelope
structure's FROM field.
HEADER <field-name> <string>
Messages that have a header with the specified field-name (as
defined in [RFC-2822]) and that contains the specified string
in the text of the header (what comes after the colon). If the
string to search is zero-length, this matches all messages that
have a header line with the specified field-name regardless of
the contents.
KEYWORD <flag>
Messages with the specified keyword flag set.
LARGER <n>
Messages with an [RFC-2822] size larger than the specified
number of octets.
NOT <search-key>
Messages that do not match the specified search key.
ON <date>
Messages whose internal date (disregarding time and timezone)
is within the specified date.
OR <search-key1> <search-key2>
Messages that match either search key.
SENTBEFORE <date>
Messages whose [RFC-2822] Date: header (disregarding time and
timezone) is earlier than the specified date.
SENTON <date>
Messages whose [RFC-2822] Date: header (disregarding time and
timezone) is within the specified date.
SENTSINCE <date>
Messages whose [RFC-2822] Date: header (disregarding time and
timezone) is within or later than the specified date.
SINCE <date>
Messages whose internal date (disregarding time and timezone)
is within or later than the specified date.
SMALLER <n>
Messages with an [RFC-2822] size smaller than the specified
number of octets.
SUBJECT <string>
Messages that contain the specified string in the envelope
structure's SUBJECT field.
TEXT <string>
Messages that contain the specified string in the header or
body of the message.
TO <string>
Messages that contain the specified string in the envelope
structure's TO field.
UID <sequence set>
Messages with unique identifiers corresponding to the specified
unique identifier set. Sequence set ranges are permitted.
UNKEYWORD <flag>
Messages that do not have the specified keyword flag set.
FLAGGED
UNFLAGGED
SEEN
UNSEEN
ANSWERED
UNANSWERED
DELETED
UNDELETED
DRAFT
UNDRAFT
X NEW
X OLD
X RECENT
*/
public static function fromString(\MailSo\Imap\ImapClient $oImapClient, string $sFolderName, string $sSearch, int $iTimeZoneOffset = 0, bool &$bUseCache = true) : string
{
$bUseCache = true;
$iTimeFilter = 0;
$aCriteriasResult = array();
if (0 < \MailSo\Config::$MessageListDateFilter) {
$iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter;
$iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD));
}
if (\strlen(\trim($sSearch))) {
$aLines = static::parseQueryString($sSearch);
// $aLines = static::parseSearchString($sSearch);
if (!$aLines) {
$sValue = static::escapeSearchString($oImapClient, $sSearch);
if (\MailSo\Config::$MessageListFastSimpleSearch) {
$aCriteriasResult[] = 'OR OR OR';
$aCriteriasResult[] = 'FROM';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'TO';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'CC';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'SUBJECT';
$aCriteriasResult[] = $sValue;
} else {
$aCriteriasResult[] = 'TEXT';
$aCriteriasResult[] = $sValue;
}
} else {
if (isset($aLines['IN']) && $oImapClient->IsSupported('MULTISEARCH') && \in_array($aLines['IN'], ['subtree','subtree-one','mailboxes'])) {
$aCriteriasResult[] = "IN ({$aLines['IN']} \"{$sFolderName}\")";
}
if (isset($aLines['EMAIL'])) {
$sValue = static::escapeSearchString($oImapClient, $aLines['EMAIL']);
$aCriteriasResult[] = 'OR OR';
$aCriteriasResult[] = 'FROM';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'TO';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'CC';
$aCriteriasResult[] = $sValue;
unset($aLines['EMAIL']);
}
if (isset($aLines['TO'])) {
$sValue = static::escapeSearchString($oImapClient, $aLines['TO']);
$aCriteriasResult[] = 'OR';
$aCriteriasResult[] = 'TO';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'CC';
$aCriteriasResult[] = $sValue;
unset($aLines['TO']);
}
foreach ($aLines as $sName => $sRawValue) {
if ('' === \trim($sRawValue)) {
continue;
}
$sValue = static::escapeSearchString($oImapClient, $sRawValue);
switch ($sName) {
case 'FROM':
case 'SUBJECT':
$aCriteriasResult[] = $sName;
$aCriteriasResult[] = $sValue;
break;
case 'BODY':
// $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"');
$aCriteriasResult[] = 'BODY';
$aCriteriasResult[] = static::escapeSearchString($oImapClient, $sRawValue);
break;
case 'HAS':
$aValue = \explode(',', \strtolower($sRawValue));
$aValue = \array_map('trim', $aValue);
$aCompareArray = array('file', 'files', 'attachment', 'attachments');
if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) {
// Simple, is not detailed search (Sometimes doesn't work)
$aCriteriasResult[] = 'OR OR OR';
$aCriteriasResult[] = 'HEADER Content-Type application/';
$aCriteriasResult[] = 'HEADER Content-Type multipart/m';
$aCriteriasResult[] = 'HEADER Content-Type multipart/signed';
$aCriteriasResult[] = 'HEADER Content-Type multipart/report';
}
case 'IS':
$aValue = \explode(',', \strtolower($sRawValue));
if (\in_array('flagged', $aValue)) {
$aCriteriasResult[] = 'FLAGGED';
$bUseCache = false;
} else if (\in_array('unflagged', $aValue)) {
$aCriteriasResult[] = 'UNFLAGGED';
$bUseCache = false;
}
if (\in_array('seen', $aValue)) {
$aCriteriasResult[] = 'SEEN';
$bUseCache = false;
} else if (\in_array('unseen', $aValue)) {
$aCriteriasResult[] = 'UNSEEN';
$bUseCache = false;
}
break;
case 'LARGER':
case 'SMALLER':
$aCriteriasResult[] = $sName;
$aCriteriasResult[] = static::parseFriendlySize($sRawValue);
break;
case 'DATE':
$iDateStampFrom = $iDateStampTo = 0;
$sDate = $sRawValue;
$aDate = \explode('/', $sDate);
if (2 === \count($aDate)) {
if (\strlen($aDate[0])) {
$iDateStampFrom = static::parseSearchDate($aDate[0], $iTimeZoneOffset);
}
if (\strlen($aDate[1])) {
$iDateStampTo = static::parseSearchDate($aDate[1], $iTimeZoneOffset);
$iDateStampTo += 60 * 60 * 24;
}
} else {
if (\strlen($sDate)) {
$iDateStampFrom = static::parseSearchDate($sDate, $iTimeZoneOffset);
$iDateStampTo = $iDateStampFrom + 60 * 60 * 24;
}
}
if (0 < $iDateStampFrom) {
$aCriteriasResult[] = 'SINCE';
$aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ?
$iTimeFilter : $iDateStampFrom);
$iTimeFilter = 0;
}
if (0 < $iDateStampTo) {
$aCriteriasResult[] = 'BEFORE';
$aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo);
}
break;
}
}
}
}
$sCriteriasResult = \trim(\implode(' ', $aCriteriasResult));
if (0 < $iTimeFilter) {
$sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter);
}
$sCriteriasResult = \trim($sCriteriasResult);
if (\MailSo\Config::$MessageListUndeletedOnly) {
$sCriteriasResult = \trim($sCriteriasResult.' UNDELETED');
}
$sCriteriasResult = \trim($sCriteriasResult);
if (\MailSo\Config::$MessageListPermanentFilter) {
$sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter);
}
$sCriteriasResult = \trim($sCriteriasResult);
return $sCriteriasResult ?: 'ALL';
}
private static function escapeSearchString(\MailSo\Imap\ImapClient $oImapClient, string $sSearch) : string
{
return !\MailSo\Base\Utils::IsAscii($sSearch)
? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $oImapClient->EscapeString($sSearch);
}
private static function parseSearchDate(string $sDate, int $iTimeZoneOffset) : int
{
if (\strlen($sDate)) {
$oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject());
return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0;
}
return 0;
}
private static function parseFriendlySize(string $sSize) : int
{
$sSize = \preg_replace('/[^0-9KM]/', '', \strtoupper($sSize));
$iResult = \intval($sSize);
switch (\substr($sSize, -1)) {
case 'K':
$iResult *= 1024;
case 'M':
$iResult *= 1024;
}
return $iResult;
}
/**
* SnappyMail search like: 'from=foo&to=test&is[]=unseen&is[]=flagged'
*/
private static function parseQueryString(string $sSearch) : array
{
$aResult = array();
$aParams = array();
\parse_str($sSearch, $aParams);
foreach ($aParams as $sName => $mValue) {
if (\is_array($mValue)) {
$mValue = \implode(',', $mValue);
}
if (\strlen($mValue)) {
$sName = \strtoupper($sName);
if ('MAIL' === $sName) {
$sName = 'EMAIL';
} else if ('TEXT' === $sName) {
$sName = 'BODY';
} else if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName) {
$sName = 'LARGER';
} else if ('MAXSIZE' === $sName) {
$sName = 'SMALLER';
}
switch ($sName) {
case 'BODY':
case 'EMAIL':
case 'FROM':
case 'TO':
case 'SUBJECT':
case 'IS':
case 'IN':
case 'HAS':
case 'SMALLER':
case 'LARGER':
case 'DATE':
$aResult[$sName] = $mValue;
break;
}
}
}
return $aResult;
}
/**
* RainLoop search like: 'from:"foo" to:"test" is:unseen,flagged'
*/
private static function parseSearchString(string $sSearch) : array
{
$aResult = array();
$aCache = array();
$sReg = 'in|e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize';
$sSearch = \MailSo\Base\Utils::StripSpaces($sSearch);
$sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch));
$mMatch = array();
if (\preg_match_all('/".*?(?<!\\\)"/', $sSearch, $mMatch)) {
foreach ($mMatch[0] as $sItem) {
do {
$sKey = \MailSo\Base\Utils::Sha1Rand();
}
while (isset($aCache[$sKey]));
$aCache[$sKey] = \stripcslashes($sItem);
$sSearch = \str_replace($sItem, $sKey, $sSearch);
}
}
if (\preg_match_all('/\'.*?(?<!\\\)\'/', $sSearch, $mMatch)) {
foreach ($mMatch[0] as $sItem) {
do {
$sKey = \MailSo\Base\Utils::Sha1Rand();
}
while (isset($aCache[$sKey]));
$aCache[$sKey] = \stripcslashes($sItem);
$sSearch = \str_replace($sItem, $sKey, $sSearch);
}
}
if (\preg_match_all('/('.$sReg.'):([^\s]*)/i', $sSearch, $mMatch)) {
if (\is_array($mMatch[0])) {
foreach ($mMatch[0] as $sToken) {
$sSearch = \str_replace($sToken, '', $sSearch);
}
$sSearch = \MailSo\Base\Utils::StripSpaces($sSearch);
}
foreach ($mMatch[1] as $iIndex => $sName) {
if (isset($mMatch[2][$iIndex]) && \strlen($mMatch[2][$iIndex])) {
$sName = \strtoupper($sName);
if ('MAIL' === $sName) {
$sName = 'EMAIL';
} else if ('TEXT' === $sName) {
$sName = 'BODY';
} else if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName) {
$sName = 'LARGER';
} else if ('MAXSIZE' === $sName) {
$sName = 'SMALLER';
}
$aResult[$sName] = $mMatch[2][$iIndex];
}
}
}
foreach ($aResult as $sName => $sValue) {
if (isset($aCache[$sValue])) {
$aResult[$sName] = \trim($aCache[$sValue], '"\' ');
}
}
return $aResult;
}
}

View file

@ -27,26 +27,11 @@ class FolderCollection extends \MailSo\Base\Collection
*/
public $FoldersHash = '';
/**
* @var bool
*/
public $IsMetadataSupported = false;
/**
* @var bool
*/
public $IsThreadsSupported = false;
/**
* @var bool
*/
public $IsSortSupported = false;
/**
* @var bool
*/
public $IsListStatusSupported = false;
/**
* @var bool
*/
@ -59,6 +44,7 @@ class FolderCollection extends \MailSo\Base\Collection
public $quotaUsage = 0;
public $quotaLimit = 0;
public $capabilities = array();
public function append($oFolder, bool $bToTop = false) : void
{
@ -148,15 +134,13 @@ class FolderCollection extends \MailSo\Base\Collection
return \array_merge(parent::jsonSerialize(), array(
'Namespace' => $this->GetNamespace(),
'FoldersHash' => $this->FoldersHash ?: '',
'IsMetadataSupported' => $this->IsMetadataSupported,
'IsThreadsSupported' => $this->IsThreadsSupported,
'IsSortSupported' => $this->IsSortSupported,
'IsListStatusSupported' => $this->IsListStatusSupported,
'quotaUsage' => $this->quotaUsage,
'quotaLimit' => $this->quotaLimit,
'Optimized' => $this->Optimized,
'CountRec' => $this->CountRec(),
'SystemFolders' => empty($this->SystemFolders) ? null : $this->SystemFolders
'SystemFolders' => empty($this->SystemFolders) ? null : $this->SystemFolders,
'Capabilities' => \array_values($this->capabilities)
));
}
}

View file

@ -640,6 +640,8 @@ class MailClient
{
$aFlags = array();
list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq, $iAppendLimit, $sMailboxId) = $this->initFolderValues($sFolderName);
if (\count($aUids))
{
$this->oImapClient->FolderSelect($sFolderName);
@ -661,16 +663,14 @@ class MailClient
'IsFlagged' => \in_array('\\flagged', $aLowerFlags),
'IsAnswered' => \in_array('\\answered', $aLowerFlags),
'IsDeleted' => \in_array('\\deleted', $aLowerFlags),
'IsForwarded' => \in_array(\strtolower('$Forwarded'), $aLowerFlags) || ($sForwardedFlag && \in_array(\strtolower($sForwardedFlag), $aLowerFlags)),
'IsReadReceipt' => \in_array(\strtolower('$MDNSent'), $aLowerFlags) || ($sReadReceiptFlag && \in_array(\strtolower($sReadReceiptFlag), $aLowerFlags)),
'IsForwarded' => \in_array(\strtolower('$Forwarded'), $aLowerFlags)/* || ($sForwardedFlag && \in_array(\strtolower($sForwardedFlag), $aLowerFlags))*/,
'IsReadReceipt' => \in_array(\strtolower('$MDNSent'), $aLowerFlags)/* || ($sReadReceiptFlag && \in_array(\strtolower($sReadReceiptFlag), $aLowerFlags))*/,
'IsJunk' => !\in_array(\strtolower('$NonJunk'), $aLowerFlags) && \in_array(\strtolower('$Junk'), $aLowerFlags),
'IsPhishing' => \in_array(\strtolower('$Phishing'), $aLowerFlags)
);
}
}
list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq, $iAppendLimit, $sMailboxId) = $this->initFolderValues($sFolderName);
return array(
'Folder' => $sFolderName,
'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUidNext, $iHighestModSeq),
@ -714,470 +714,12 @@ class MailClient
return 0 < $iResult ? $iResult : 0;
}
private function escapeSearchString(string $sSearch) : string
{
return !\MailSo\Base\Utils::IsAscii($sSearch)
? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch);
}
private function parseSearchDate(string $sDate, int $iTimeZoneOffset) : int
{
$iResult = 0;
if (\strlen($sDate))
{
$oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject());
return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0;
}
return $iResult;
}
private function parseFriendlySize(string $sSize) : int
{
$sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize);
$iResult = 0;
$aMatch = array();
if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2]))
{
$iResult = (int) $aMatch[1];
switch (\strtoupper($aMatch[2]))
{
case 'K':
case 'KB':
$iResult *= 1024;
case 'M':
case 'MB':
$iResult *= 1024;
case 'G':
case 'GB':
$iResult *= 1024;
}
}
else
{
$iResult = (int) $sSize;
}
return $iResult;
}
private function parseSearchString(string $sSearch) : array
{
$aResult = array(
'OTHER' => ''
);
$aCache = array();
$sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize';
$sSearch = \MailSo\Base\Utils::StripSpaces($sSearch);
$sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch));
$mMatch = array();
\preg_match_all('/".*?(?<!\\\)"/', $sSearch, $mMatch);
if (\is_array($mMatch) && isset($mMatch[0]) && \is_array($mMatch[0]))
{
foreach ($mMatch[0] as $sItem)
{
do
{
$sKey = \MailSo\Base\Utils::Sha1Rand();
}
while (isset($aCache[$sKey]));
$aCache[$sKey] = \stripcslashes($sItem);
$sSearch = \str_replace($sItem, $sKey, $sSearch);
}
}
\preg_match_all('/\'.*?(?<!\\\)\'/', $sSearch, $mMatch);
if (\is_array($mMatch) && isset($mMatch[0]) && \is_array($mMatch[0]))
{
foreach ($mMatch[0] as $sItem)
{
do
{
$sKey = \MailSo\Base\Utils::Sha1Rand();
}
while (isset($aCache[$sKey]));
$aCache[$sKey] = \stripcslashes($sItem);
$sSearch = \str_replace($sItem, $sKey, $sSearch);
}
}
$mMatch = array();
\preg_match_all('/('.$sReg.'):([^\s]*)/i', $sSearch, $mMatch);
if (\is_array($mMatch) && isset($mMatch[1]) && \is_array($mMatch[1]) && \count($mMatch[1]))
{
if (\is_array($mMatch[0]))
{
foreach ($mMatch[0] as $sToken)
{
$sSearch = \str_replace($sToken, '', $sSearch);
}
$sSearch = \MailSo\Base\Utils::StripSpaces($sSearch);
}
foreach ($mMatch[1] as $iIndex => $sName)
{
if (isset($mMatch[2][$iIndex]) && \strlen($mMatch[2][$iIndex]))
{
$sName = \strtoupper($sName);
$sValue = $mMatch[2][$iIndex];
switch ($sName)
{
case 'TEXT':
case 'BODY':
case 'EMAIL':
case 'MAIL':
case 'FROM':
case 'TO':
case 'SUBJECT':
case 'IS':
case 'HAS':
case 'SIZE':
case 'SMALLER':
case 'LARGER':
case 'BIGGER':
case 'MAXSIZE':
case 'MINSIZE':
case 'DATE':
if ('MAIL' === $sName)
{
$sName = 'EMAIL';
}
if ('BODY' === $sName)
{
$sName = 'TEXT';
}
if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName)
{
$sName = 'LARGER';
}
if ('MAXSIZE' === $sName)
{
$sName = 'SMALLER';
}
$aResult[$sName] = $sValue;
break;
}
}
}
}
$aResult['OTHER'] = $sSearch;
foreach ($aResult as $sName => $sValue)
{
if (isset($aCache[$sValue]))
{
$aResult[$sName] = \trim($aCache[$sValue], '"\' ');
}
}
return $aResult;
}
private function getImapSearchCriterias(string $sSearch, string $sFilter, int $iTimeZoneOffset = 0, bool &$bUseCache = true) : string
{
$bUseCache = true;
$iTimeFilter = 0;
$aCriteriasResult = array();
if (0 < \MailSo\Config::$MessageListDateFilter)
{
$iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter;
$iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD));
}
if (\strlen(\trim($sSearch)))
{
$sResultBodyTextSearch = '';
$aLines = $this->parseSearchString($sSearch);
if (1 === \count($aLines) && isset($aLines['OTHER']))
{
$sValue = $this->escapeSearchString($aLines['OTHER']);
if (\MailSo\Config::$MessageListFastSimpleSearch)
{
$aCriteriasResult[] = 'OR OR OR';
$aCriteriasResult[] = 'FROM';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'TO';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'CC';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'SUBJECT';
$aCriteriasResult[] = $sValue;
}
else
{
$aCriteriasResult[] = 'TEXT';
$aCriteriasResult[] = $sValue;
}
}
else
{
if (isset($aLines['EMAIL']))
{
$sValue = $this->escapeSearchString($aLines['EMAIL']);
$aCriteriasResult[] = 'OR OR';
$aCriteriasResult[] = 'FROM';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'TO';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'CC';
$aCriteriasResult[] = $sValue;
unset($aLines['EMAIL']);
}
if (isset($aLines['TO']))
{
$sValue = $this->escapeSearchString($aLines['TO']);
$aCriteriasResult[] = 'OR';
$aCriteriasResult[] = 'TO';
$aCriteriasResult[] = $sValue;
$aCriteriasResult[] = 'CC';
$aCriteriasResult[] = $sValue;
unset($aLines['TO']);
}
$sMainText = '';
foreach ($aLines as $sName => $sRawValue)
{
if ('' === \trim($sRawValue))
{
continue;
}
$sValue = $this->escapeSearchString($sRawValue);
switch ($sName)
{
case 'FROM':
$aCriteriasResult[] = 'FROM';
$aCriteriasResult[] = $sValue;
break;
case 'SUBJECT':
$aCriteriasResult[] = 'SUBJECT';
$aCriteriasResult[] = $sValue;
break;
case 'OTHER':
case 'TEXT':
$sMainText .= ' '.$sRawValue;
break;
case 'HAS':
$aValue = \explode(',', \strtolower($sRawValue));
$aValue = \array_map('trim', $aValue);
$aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments');
if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
{
// Simple, is not detailed search (Sometimes doesn't work)
$aCriteriasResult[] = 'OR OR OR';
$aCriteriasResult[] = 'HEADER Content-Type application/';
$aCriteriasResult[] = 'HEADER Content-Type multipart/m';
$aCriteriasResult[] = 'HEADER Content-Type multipart/signed';
$aCriteriasResult[] = 'HEADER Content-Type multipart/report';
}
case 'IS':
$aValue = \explode(',', \strtolower($sRawValue));
$aValue = \array_map('trim', $aValue);
$aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned');
$aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned');
if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
{
$aCriteriasResult[] = 'FLAGGED';
$bUseCache = false;
}
else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
{
$aCriteriasResult[] = 'UNFLAGGED';
$bUseCache = false;
}
$aCompareArray = array('unread', 'unseen');
$aCompareArray2 = array('read', 'seen');
if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
{
$aCriteriasResult[] = 'UNSEEN';
$bUseCache = false;
}
else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
{
$aCriteriasResult[] = 'SEEN';
$bUseCache = false;
}
break;
case 'LARGER':
$aCriteriasResult[] = 'LARGER';
$aCriteriasResult[] = $this->parseFriendlySize($sRawValue);
break;
case 'SMALLER':
$aCriteriasResult[] = 'SMALLER';
$aCriteriasResult[] = $this->parseFriendlySize($sRawValue);
break;
case 'DATE':
$iDateStampFrom = $iDateStampTo = 0;
$sDate = $sRawValue;
$aDate = \explode('/', $sDate);
if (2 === \count($aDate))
{
if (\strlen($aDate[0]))
{
$iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset);
}
if (\strlen($aDate[1]))
{
$iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset);
$iDateStampTo += 60 * 60 * 24;
}
}
else
{
if (\strlen($sDate))
{
$iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset);
$iDateStampTo = $iDateStampFrom + 60 * 60 * 24;
}
}
if (0 < $iDateStampFrom)
{
$aCriteriasResult[] = 'SINCE';
$aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ?
$iTimeFilter : $iDateStampFrom);
$iTimeFilter = 0;
}
if (0 < $iDateStampTo)
{
$aCriteriasResult[] = 'BEFORE';
$aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo);
}
break;
}
}
if ('' !== \trim($sMainText))
{
$sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"');
$sResultBodyTextSearch .= ' '.$sMainText;
}
}
$sResultBodyTextSearch = \trim($sResultBodyTextSearch);
if (\strlen($sResultBodyTextSearch))
{
$aCriteriasResult[] = 'BODY';
$aCriteriasResult[] = $this->escapeSearchString($sResultBodyTextSearch);
}
}
$sCriteriasResult = \trim(\implode(' ', $aCriteriasResult));
if (0 < $iTimeFilter)
{
$sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter);
}
$sCriteriasResult = \trim($sCriteriasResult);
if (\MailSo\Config::$MessageListUndeletedOnly)
{
$sCriteriasResult = \trim($sCriteriasResult.' UNDELETED');
}
$sFilter = \trim($sFilter);
if ('' !== $sFilter)
{
$sCriteriasResult .= ' '.$sFilter;
}
$sCriteriasResult = \trim($sCriteriasResult);
if ('' !== \MailSo\Config::$MessageListPermanentFilter)
{
$sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter);
}
$sCriteriasResult = \trim($sCriteriasResult);
if ('' === $sCriteriasResult)
{
$sCriteriasResult = 'ALL';
}
return $sCriteriasResult;
}
private function threadArrayMap(array $aThreads) : array
{
$aNew = array();
foreach ($aThreads as $mItem)
{
if (!\is_array($mItem))
{
$aNew[] = $mItem;
}
else
{
$mMap = $this->threadArrayMap($mItem);
if (\count($mMap))
{
$aNew = \array_merge($aNew, $mMap);
}
}
}
return $aNew;
}
private function compileThreadArray(array $aThreads) : array
{
$aResult = array();
foreach ($aThreads as $mItem)
{
if (\is_array($mItem))
{
$aMap = $this->threadArrayMap($mItem);
if (1 < \count($aMap))
{
$aResult[] = $aMap;
}
else if (\count($aMap))
{
$aResult[] = $aMap[0];
}
}
else
{
$aResult[] = $mItem;
}
}
return $aResult;
}
/**
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
public function MessageListThreadsMap(string $sFolderName, string $sFolderHash, array $aIndexOrUids, \MailSo\Cache\CacheClient $oCacher, bool $bCacheOnly = false) : array
public function MessageListThreadsMap(string $sFolderName, string $sFolderHash, \MailSo\Cache\CacheClient $oCacher) : array
{
$iThreadLimit = \MailSo\Config::$LargeThreadLimit;
@ -1222,11 +764,6 @@ class MailClient
}
}
if ($bCacheOnly)
{
return null;
}
$this->oImapClient->FolderExamine($sFolderName);
$aThreadUids = array();
@ -1237,117 +774,16 @@ class MailClient
catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
{
unset($oException);
$aThreadUids = array();
}
// Flatten to single levels
$aResult = array();
$aCompiledThreads = $this->compileThreadArray($aThreadUids);
foreach ($aCompiledThreads as $mData)
{
if (\is_array($mData))
{
foreach ($mData as $mSubData)
{
$aResult[(int) $mSubData] =
\array_diff($mData, array((int) $mSubData));
}
}
else if (\is_int($mData) || \is_string($mData))
{
$aResult[(int) $mData] = (int) $mData;
}
foreach ($aThreadUids as $mItem) {
$aMap = [];
\array_walk_recursive($mItem, function($a) use (&$aMap) { $aMap[] = $a; });
$aResult[] = $aMap;
}
$aParentsMap = array();
foreach ($aIndexOrUids as $iUid)
{
if (isset($aResult[$iUid]) && \is_array($aResult[$iUid]))
{
foreach ($aResult[$iUid] as $iTempUid)
{
$aParentsMap[$iTempUid] = $iUid;
if (isset($aResult[$iTempUid]))
{
unset($aResult[$iTempUid]);
}
}
}
}
$aSortedThreads = array();
foreach ($aIndexOrUids as $iUid)
{
if (isset($aResult[$iUid]))
{
$aSortedThreads[$iUid] = $iUid;
}
}
foreach ($aIndexOrUids as $iUid)
{
if (!isset($aSortedThreads[$iUid]) &&
isset($aParentsMap[$iUid]) &&
isset($aSortedThreads[$aParentsMap[$iUid]]))
{
if (!\is_array($aSortedThreads[$aParentsMap[$iUid]]))
{
$aSortedThreads[$aParentsMap[$iUid]] = array();
}
$aSortedThreads[$aParentsMap[$iUid]][] = $iUid;
}
}
$aResult = $aSortedThreads;
unset($aParentsMap, $aSortedThreads);
$aTemp = array();
foreach ($aResult as $iUid => $mValue)
{
if (0 < $iThreadLimit && \is_array($mValue) && $iThreadLimit < \count($mValue))
{
$aParts = \array_chunk($mValue, $iThreadLimit);
if (0 < count($aParts))
{
foreach ($aParts as $iIndex => $aItem)
{
if (0 === $iIndex)
{
$aResult[$iUid] = $aItem;
}
else if (0 < $iIndex && \is_array($aItem))
{
$mFirst = \array_shift($aItem);
if (!empty($mFirst))
{
$aTemp[$mFirst] = \count($aItem) ? $aItem : $mFirst;
}
}
}
}
}
}
foreach ($aTemp as $iUid => $mValue)
{
$aResult[$iUid] = $mValue;
}
unset($aTemp);
$aLastResult = array();
foreach ($aIndexOrUids as $iUid)
{
if (isset($aResult[$iUid]))
{
$aLastResult[$iUid] = $aResult[$iUid];
}
}
$aResult = $aLastResult;
unset($aLastResult);
if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey))
{
$oCacher->Set($sSerializedHashKey, \json_encode(array(
@ -1423,7 +859,7 @@ class MailClient
* @throws \MailSo\Imap\Exceptions\Exception
*/
public function GetUids(?\MailSo\Cache\CacheClient $oCacher, string $sSearch,
string $sFilter, string $sFolderName, string $sFolderHash,
string $sFolderName, string $sFolderHash,
bool $bUseSortIfSupported = false, string $sSort = '') : array
{
/* TODO: Validate $sSort
@ -1476,17 +912,16 @@ class MailClient
$bUseSortIfSupported = $bUseSortIfSupported && !\strlen($sSearch) && $this->oImapClient->IsSupported('SORT');
$sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch);
$sSearchCriterias = \MailSo\Imap\SearchCriterias::fromString($this->oImapClient, $sFolderName, $sSearch, 0, $bUseCacheAfterSearch);
if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited())
{
$sSerializedHash = 'GetUids/'.
($bUseSortIfSupported ? 'S' . $sSort : 'N').'/'.
$this->GenerateImapClientHash().'/'.
$sFolderName.'/'.$sSearchCriterias;
$sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
$sSerialized = $oCacher->Get($sSerializedHash);
// $sSerialized = $oCacher->Get($sSerializedHash);
if (!empty($sSerialized))
{
$aSerialized = \json_decode($sSerialized, true);
@ -1508,10 +943,15 @@ class MailClient
if (!\is_array($aResultUids))
{
$aResultUids = $bUseSortIfSupported ?
$this->oImapClient->MessageSimpleSort(array($sSort ?: 'REVERSE DATE'), $sSearchCriterias, true) :
$this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8')
;
if ($bUseSortIfSupported) {
// $this->oImapClient->IsSupported('ESORT')
// $aResultUids = $this->oImapClient->MessageSimpleESort(array($sSort ?: 'REVERSE DATE'), $sSearchCriterias)['ALL'];
$aResultUids = $this->oImapClient->MessageSimpleSort(array($sSort ?: 'REVERSE DATE'), $sSearchCriterias);
} else {
// $this->oImapClient->IsSupported('ESEARCH')
// $aResultUids = $this->oImapClient->MessageSimpleESearch($sSearchCriterias, null, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8')
$aResultUids = $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8');
}
if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && \strlen($sSerializedHash))
{
@ -1531,6 +971,7 @@ class MailClient
}
/**
* Runs SORT/SEARCH when $sSearch is provided
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
@ -1538,17 +979,17 @@ class MailClient
public function MessageList(string $sFolderName, int $iOffset = 0, int $iLimit = 10,
string $sSearch = '', int $iPrevUidNext = 0, ?\MailSo\Cache\CacheClient $oCacher = null,
bool $bUseSortIfSupported = false, bool $bUseThreadSortIfSupported = false,
int $iThreadUid = 0, string $sFilter = '', string $sSort = '') : MessageCollection
int $iThreadUid = 0, string $sSort = '') : MessageCollection
{
$sFilter = \trim($sFilter);
$sSearch = \trim($sSearch);
if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) ||
!\MailSo\Base\Validator::RangeInt($iLimit, 0, 999))
{
throw new \MailSo\Base\Exceptions\InvalidArgumentException;
}
$bUseFilter = '' !== $sFilter;
$sSearch = \trim($sSearch);
list($iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($sFolderName);
$this->oImapClient->FolderSelect($sFolderName);
@ -1561,7 +1002,6 @@ class MailClient
$oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter;
$aUids = array();
$mAllSortedUids = null;
$mAllThreads = null;
$bUseSortIfSupported = $bUseSortIfSupported && $this->oImapClient->IsSupported('SORT');
@ -1579,13 +1019,6 @@ class MailClient
$oCacher = null;
}
list($iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($sFolderName);
if ($bUseFilter)
{
$iMessageUnseenCount = 0;
}
$oMessageCollection->FolderHash = $this->GenerateFolderHash(
$sFolderName, $iMessageRealCount, $iUidNext, $iHighestModSeq);
@ -1609,55 +1042,36 @@ class MailClient
if (0 < $iMessageRealCount && !$bMessageListOptimization)
{
$mAllSortedUids = $this->GetUids($oCacher, '', $sFilter,
$aUids = $this->GetUids($oCacher, '',
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported, $sSort);
$mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap(
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null;
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $oCacher) : null;
if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads))
{
$iResultRootUid = 0;
if (isset($mAllThreads[$iThreadUid]))
if ($bUseThreadSortIfSupported && $mAllThreads) {
if (0 < $iThreadUid)
{
$iResultRootUid = $iThreadUid;
if (\is_array($mAllThreads[$iThreadUid]))
{
$aUids = $mAllThreads[$iThreadUid];
// Only show the selected thread messages
foreach ($mAllThreads as $aMap) {
if (\in_array($iThreadUid, $aMap)) {
$aUids = \array_intersect($aUids, $aMap);
break;
}
}
}
else
{
foreach ($mAllThreads as $iRootUid => $mSubUids)
{
if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids))
{
$iResultRootUid = $iRootUid;
$aUids = $mSubUids;
continue;
}
}
// $aUids = \array_diff($aUids, $mAllThreads);
}
if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids))
{
\array_unshift($aUids, $iResultRootUid);
}
}
else if ($bUseThreadSortIfSupported && \is_array($mAllThreads))
{
$aUids = \array_keys($mAllThreads);
}
else
{
$bUseThreadSortIfSupported = false;
$aUids = $mAllSortedUids;
}
if (\strlen($sSearch) && \is_array($aUids))
{
$aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter,
$aSearchedUids = $this->GetUids($oCacher, $sSearch,
$oMessageCollection->FolderName, $oMessageCollection->FolderHash);
if (\count($aSearchedUids))
@ -1719,9 +1133,9 @@ class MailClient
$oMessageCollection->MessageCount = $iMessageRealCount;
$oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
if (\strlen($sSearch) || $bUseFilter)
if (\strlen($sSearch))
{
$aUids = $this->GetUids($oCacher, $sSearch, $sFilter,
$aUids = $this->GetUids($oCacher, $sSearch,
$oMessageCollection->FolderName, $oMessageCollection->FolderHash);
if (\count($aUids))
@ -1742,7 +1156,7 @@ class MailClient
if (1 < $iMessageRealCount)
{
$aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit);
$aRequestIndexes = \array_slice(\array_reverse(\range(1, $iMessageRealCount)), $iOffset, $iLimit);
}
else
{
@ -1798,8 +1212,12 @@ class MailClient
public function Folders(string $sParent, string $sListPattern, bool $bUseListSubscribeStatus, int $iOptimizationLimit, bool $bUseListStatus) : ?FolderCollection
{
$aCapabilities = \array_filter($this->oImapClient->Capability(), function($item){
return !\preg_match('/^(IMAP|AUTH|LOGIN|SASL)/', $item);
});
$aImapSubscribedFoldersHelper = null;
if ($this->oImapClient->IsSupported('LIST-EXTENDED')) {
if (\in_array('LIST-EXTENDED', $aCapabilities)) {
$bUseListSubscribeStatus = false;
} else if ($bUseListSubscribeStatus) {
//\error_log('RFC5258 not supported, using LSUB');
@ -1818,7 +1236,13 @@ class MailClient
}
}
$bUseListStatus = $bUseListStatus && $this->oImapClient->IsSupported('LIST-STATUS');
$bUseListStatus = $bUseListStatus && \in_array('LIST-STATUS', $aCapabilities);
if (!$bUseListStatus) {
$key = \array_search('LIST-STATUS', $aCapabilities);
if (false !== $key) {
unset($aCapabilities[$key]);
}
}
$aFolders = $bUseListStatus
? $this->oImapClient->FolderStatusList($sParent, $sListPattern)
@ -1828,11 +1252,9 @@ class MailClient
}
$oFolderCollection = new FolderCollection;
$oFolderCollection->IsMetadataSupported = $this->oImapClient->IsSupported('METADATA');
$oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported();
$oFolderCollection->IsSortSupported = $this->oImapClient->IsSupported('SORT');
$oFolderCollection->IsListStatusSupported = $bUseListStatus;
$oFolderCollection->Optimized = 10 < $iOptimizationLimit && \count($aFolders) > $iOptimizationLimit;
$oFolderCollection->capabilities = $aCapabilities;
$sINBOX = 'INBOX';
$aSortedByLenImapFolders = array();

View file

@ -24,8 +24,8 @@ trait Folders
try {
$aQuota = $this->MailClient()->Quota();
// $aQuota = $this->MailClient()->QuotaRoot();
$oFolderCollection->quotaUsage = $aQuota[0] * 1024;
$oFolderCollection->quotaLimit = $aQuota[1] * 1024;
$oFolderCollection->quotaUsage = $aQuota ? $aQuota[0] * 1024 : null;
$oFolderCollection->quotaLimit = $aQuota ? $aQuota[1] * 1024 : null;
} catch (\Throwable $oException) {
// ignore
}
@ -57,6 +57,12 @@ trait Folders
$this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders);
$oFolderCollection->SystemFolders = $aSystemFolders;
if (!$this->Config()->Get('labs', 'use_imap_sort', true)) {
$oFolderCollection->capabilities = \array_filter($oFolderCollection->capabilities, function($item){
return !\preg_match('/^E?SORT/', $item);
});
}
if ($this->Config()->Get('labs', 'autocreate_system_folders', true))
{
$bDoItAgain = false;

View file

@ -28,7 +28,6 @@ trait Messages
$sRawKey = $this->GetActionParam('RawKey', '');
$aValues = $this->getDecodedClientRawKeyValue($sRawKey, 10);
if ($aValues && 7 < \count($aValues))
{
$sFolder = (string) $aValues[2];
@ -63,7 +62,7 @@ trait Messages
}
}
if (0 === strlen($sFolder))
if (!\strlen($sFolder))
{
throw new ClientException(Notifications::CantGetMessageList);
}
@ -83,7 +82,6 @@ trait Messages
!!$this->Config()->Get('labs', 'use_imap_sort', true),
$bUseThreads,
$iThreadUid,
'',
$sSort
);
}
@ -108,7 +106,7 @@ trait Messages
$iMessageUid = $this->GetActionParam('MessageUid', 0);
$sDraftFolder = $this->GetActionParam('SaveFolder', '');
if (0 === strlen($sDraftFolder))
if (!\strlen($sDraftFolder))
{
throw new ClientException(Notifications::UnknownError);
}
@ -144,7 +142,7 @@ trait Messages
$mResult = true;
if (0 < strlen($sMessageFolder) && 0 < $iMessageUid)
if (\strlen($sMessageFolder) && 0 < $iMessageUid)
{
$this->MailClient()->MessageDelete($sMessageFolder, array($iMessageUid), true, true);
}
@ -209,7 +207,7 @@ trait Messages
break;
case 'forward':
$sForwardedFlag = $this->Config()->Get('labs', 'imap_forwarded_flag', '');
if (0 < strlen($sForwardedFlag))
if (\strlen($sForwardedFlag))
{
$this->MailClient()->MessageSetFlag($sDraftInfoFolder, array($sDraftInfoUid), true,
$sForwardedFlag, true);
@ -223,7 +221,7 @@ trait Messages
}
}
if (0 < \strlen($sSentFolder))
if (\strlen($sSentFolder))
{
try
{
@ -277,7 +275,7 @@ trait Messages
$this->deleteMessageAttachmnets($oAccount);
if (0 < \strlen($sDraftFolder) && 0 < $iDraftUid)
if (\strlen($sDraftFolder) && 0 < $iDraftUid)
{
try
{
@ -377,7 +375,7 @@ trait Messages
$this->Cacher($oAccount)->Set(\RainLoop\KeyPathHelper::ReadReceiptCache($oAccount->Email(), $sFolderFullName, $iUid), '1');
if (0 < \strlen($sFolderFullName) && 0 < $iUid)
if (\strlen($sFolderFullName) && 0 < $iUid)
{
try
{
@ -1044,12 +1042,12 @@ trait Messages
$oMessage->SetDraftInfo($aDraftInfo[0], $aDraftInfo[1], $aDraftInfo[2]);
}
if (0 < \strlen($sInReplyTo))
if (\strlen($sInReplyTo))
{
$oMessage->SetInReplyTo($sInReplyTo);
}
if (0 < \strlen($sReferences))
if (\strlen($sReferences))
{
$oMessage->SetReferences($sReferences);
}
@ -1064,7 +1062,7 @@ trait Messages
$this->Plugins()->RunHook($bTextIsHtml ? 'filter.message-html' : 'filter.message-plain',
array($oAccount, $oMessage, &$sTextToAdd));
if ($bTextIsHtml && 0 < \strlen($sTextToAdd))
if ($bTextIsHtml && \strlen($sTextToAdd))
{
$sTextConverted = \MailSo\Base\HtmlUtils::ConvertHtmlToPlain($sTextToAdd);
$this->Plugins()->RunHook('filter.message-plain', array($oAccount, $oMessage, &$sTextConverted));

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "منذ شهر",
"LABEL_ADV_DATE_3_MONTHS": "منذ 3 أشهر",
"LABEL_ADV_DATE_6_MONTHS": "منذ 6 أشهر",
"LABEL_ADV_DATE_YEAR": "منذ سنة"
"LABEL_ADV_DATE_YEAR": "منذ سنة",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "إعداد افتراضي لوضع ملء الشاشة",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "До 1 месец",
"LABEL_ADV_DATE_3_MONTHS": "До 3 месеца",
"LABEL_ADV_DATE_6_MONTHS": "До 6 месеца",
"LABEL_ADV_DATE_YEAR": "До 1 година"
"LABEL_ADV_DATE_YEAR": "До 1 година",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "На цял екран",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Ne starší než měsíc",
"LABEL_ADV_DATE_3_MONTHS": "Ne starší než 3 měsíce",
"LABEL_ADV_DATE_6_MONTHS": "Ne starší než 6 měsíců",
"LABEL_ADV_DATE_YEAR": "Ne starší než 1 rok"
"LABEL_ADV_DATE_YEAR": "Ne starší než 1 rok",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Celá obrazovka",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Nyere end 1 måned",
"LABEL_ADV_DATE_3_MONTHS": "Nyere end 3 måneder",
"LABEL_ADV_DATE_6_MONTHS": "Nyere end 6 måneder",
"LABEL_ADV_DATE_YEAR": "Nyere end 1 år"
"LABEL_ADV_DATE_YEAR": "Nyere end 1 år",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Fuld skærm",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Nicht älter als 1 Monat",
"LABEL_ADV_DATE_3_MONTHS": "Nicht älter als 3 Monate",
"LABEL_ADV_DATE_6_MONTHS": "Nicht älter als 6 Monate",
"LABEL_ADV_DATE_YEAR": "Nicht älter als 1 Jahr"
"LABEL_ADV_DATE_YEAR": "Nicht älter als 1 Jahr",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Vollbild umschalten",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Έως 1 μήνα πριν",
"LABEL_ADV_DATE_3_MONTHS": "Έως 3 μήνες πριν",
"LABEL_ADV_DATE_6_MONTHS": "Έως 6 μήνες πριν",
"LABEL_ADV_DATE_YEAR": "Έως 1 χρόνο πριν"
"LABEL_ADV_DATE_YEAR": "Έως 1 χρόνο πριν",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Ενναλαγή πλήρους οθόνης",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Up to 1 month old",
"LABEL_ADV_DATE_3_MONTHS": "Up to 3 months old",
"LABEL_ADV_DATE_6_MONTHS": "Up to 6 months old",
"LABEL_ADV_DATE_YEAR": "Up to 1 year old"
"LABEL_ADV_DATE_YEAR": "Up to 1 year old",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE" : "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE" : "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE" : "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Toggle fullscreen",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Hasta 1 mes de antigüedad",
"LABEL_ADV_DATE_3_MONTHS": "Hasta 3 meses de antigüedad",
"LABEL_ADV_DATE_6_MONTHS": "Hasta 6 meses de antigüedad",
"LABEL_ADV_DATE_YEAR": "Hasta 1 año de antigüedad"
"LABEL_ADV_DATE_YEAR": "Hasta 1 año de antigüedad",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Cambiar a pantalla completa",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Kuni 1 kuu vanune",
"LABEL_ADV_DATE_3_MONTHS": "Kuni 3 kuu vanune ",
"LABEL_ADV_DATE_6_MONTHS": "Kuni 6 kuu vanune",
"LABEL_ADV_DATE_YEAR": "Kuni 1 aasta vanune"
"LABEL_ADV_DATE_YEAR": "Kuni 1 aasta vanune",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Täisekraan sisse\/välja",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "تا 1 ماه گذشته",
"LABEL_ADV_DATE_3_MONTHS": "تا 3 ماه گذشته",
"LABEL_ADV_DATE_6_MONTHS": "تا 6 ماه گذشته",
"LABEL_ADV_DATE_YEAR": "تا 1 سال گذشته"
"LABEL_ADV_DATE_YEAR": "تا 1 سال گذشته",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "ضامن تمام صفحه",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "1 kk ajalta",
"LABEL_ADV_DATE_3_MONTHS": "3 kk ajalta",
"LABEL_ADV_DATE_6_MONTHS": "6 kk ajalta",
"LABEL_ADV_DATE_YEAR": "1 vuoden ajalta"
"LABEL_ADV_DATE_YEAR": "1 vuoden ajalta",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Koko ruutu",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Jusqu'à 1 mois",
"LABEL_ADV_DATE_3_MONTHS": "Jusqu'à 3 mois",
"LABEL_ADV_DATE_6_MONTHS": "Jusqu'à 6 mois",
"LABEL_ADV_DATE_YEAR": "Jusqu'à 1 an"
"LABEL_ADV_DATE_YEAR": "Jusqu'à 1 an",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Basculer en plein écran",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Legfeljebb 1 hónapos",
"LABEL_ADV_DATE_3_MONTHS": "Legfeljebb 3 hónapos",
"LABEL_ADV_DATE_6_MONTHS": "Legfeljebb 6 hónapos",
"LABEL_ADV_DATE_YEAR": "Legfeljebb 1 éves"
"LABEL_ADV_DATE_YEAR": "Legfeljebb 1 éves",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Teljes képernyő váltása",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Lebih dari 1 bulan lalu",
"LABEL_ADV_DATE_3_MONTHS": "Lebih dari 3 bulan lalu",
"LABEL_ADV_DATE_6_MONTHS": "Lebih dari 6 bulan lalu",
"LABEL_ADV_DATE_YEAR": "Lebih dari 1 tahun lalu"
"LABEL_ADV_DATE_YEAR": "Lebih dari 1 tahun lalu",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Beralih ke layar penuh",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Allt að mánaðar gömlu",
"LABEL_ADV_DATE_3_MONTHS": "Allt að 3 mánaða gömlu",
"LABEL_ADV_DATE_6_MONTHS": "Allt að 6 mánaða gömlu",
"LABEL_ADV_DATE_YEAR": "Allt að 1 árs gömlu"
"LABEL_ADV_DATE_YEAR": "Allt að 1 árs gömlu",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Víxla heilskjá af\/á",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Meno di un mese fa",
"LABEL_ADV_DATE_3_MONTHS": "Meno di 3 mesi fa",
"LABEL_ADV_DATE_6_MONTHS": "Meno di 6 mesi fa",
"LABEL_ADV_DATE_YEAR": "Meno di un anno fa"
"LABEL_ADV_DATE_YEAR": "Meno di un anno fa",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Passa a schermo intero",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "1ヶ月前まで",
"LABEL_ADV_DATE_3_MONTHS": "3ヶ月前まで",
"LABEL_ADV_DATE_6_MONTHS": "6ヶ月前まで",
"LABEL_ADV_DATE_YEAR": "1年前まで"
"LABEL_ADV_DATE_YEAR": "1年前まで",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "フルスクリーン",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "1개월 이내",
"LABEL_ADV_DATE_3_MONTHS": "3개월 이내",
"LABEL_ADV_DATE_6_MONTHS": "6개월 이내",
"LABEL_ADV_DATE_YEAR": "1년 이내"
"LABEL_ADV_DATE_YEAR": "1년 이내",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "전체화면으로 보기",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Nesenesni kaip 1 mėnesio",
"LABEL_ADV_DATE_3_MONTHS": "Nesenesni kaip 3 mėnesių",
"LABEL_ADV_DATE_6_MONTHS": "Nesenesni kaip 6 mėnesių",
"LABEL_ADV_DATE_YEAR": "Nesenesni kaip 1 metų"
"LABEL_ADV_DATE_YEAR": "Nesenesni kaip 1 metų",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Perjungti viso ekrano režimą",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Līdz 1 mēnesi vecs",
"LABEL_ADV_DATE_3_MONTHS": "Līdz 3 mēnešus vecs",
"LABEL_ADV_DATE_6_MONTHS": "Līdz 6 mēnešus vecs",
"LABEL_ADV_DATE_YEAR": "Līdz 1 gadu vecs"
"LABEL_ADV_DATE_YEAR": "Līdz 1 gadu vecs",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Toggle fullscreen",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Inntil 1 måned gamle",
"LABEL_ADV_DATE_3_MONTHS": "Inntil 3 måneder gamle",
"LABEL_ADV_DATE_6_MONTHS": "Inntil 6 måneder gamle",
"LABEL_ADV_DATE_YEAR": "Inntil 1 år gamle"
"LABEL_ADV_DATE_YEAR": "Inntil 1 år gamle",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Toggle fullscreen",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Tot 1 maand oud",
"LABEL_ADV_DATE_3_MONTHS": "Tot 3 maanden oud",
"LABEL_ADV_DATE_6_MONTHS": "Tot 6 maanden oud",
"LABEL_ADV_DATE_YEAR": "Tot 1 jaar oud"
"LABEL_ADV_DATE_YEAR": "Tot 1 jaar oud",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Schakel volledig scherm in\/uit",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "do miesiąca",
"LABEL_ADV_DATE_3_MONTHS": "do 3 miesięcy",
"LABEL_ADV_DATE_6_MONTHS": "do 6 miesięcy",
"LABEL_ADV_DATE_YEAR": "do roku"
"LABEL_ADV_DATE_YEAR": "do roku",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Pełny ekran",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Até 1 mês atrás",
"LABEL_ADV_DATE_3_MONTHS": "Até 3 meses atrás",
"LABEL_ADV_DATE_6_MONTHS": "Até 6 meses atrás",
"LABEL_ADV_DATE_YEAR": "Até 1 ano atrás"
"LABEL_ADV_DATE_YEAR": "Até 1 ano atrás",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Em tela cheia",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Até 1 mês atrás",
"LABEL_ADV_DATE_3_MONTHS": "Até 3 meses atrás",
"LABEL_ADV_DATE_6_MONTHS": "Até 6 meses atrás",
"LABEL_ADV_DATE_YEAR": "Até 1 ano atrás"
"LABEL_ADV_DATE_YEAR": "Até 1 ano atrás",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Alternar ecrã-inteiro",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "în această lună",
"LABEL_ADV_DATE_3_MONTHS": "3 luni",
"LABEL_ADV_DATE_6_MONTHS": "6 luni",
"LABEL_ADV_DATE_YEAR": "în acest an"
"LABEL_ADV_DATE_YEAR": "în acest an",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Toggle fullscreen",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "За месяц",
"LABEL_ADV_DATE_3_MONTHS": "За 3 месяца",
"LABEL_ADV_DATE_6_MONTHS": "За полгода",
"LABEL_ADV_DATE_YEAR": "За год"
"LABEL_ADV_DATE_YEAR": "За год",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Полный экран",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Nie staršie ako mesiac",
"LABEL_ADV_DATE_3_MONTHS": "Nie staršie ako 3 mesiace",
"LABEL_ADV_DATE_6_MONTHS": "Nie staršie ako 6 mesiacov",
"LABEL_ADV_DATE_YEAR": "Nie staršie ako 1 rok"
"LABEL_ADV_DATE_YEAR": "Nie staršie ako 1 rok",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Prepnúť na celú obrazovku",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Do 1 meseca nazaj",
"LABEL_ADV_DATE_3_MONTHS": "Do 3 mesecev nazaj",
"LABEL_ADV_DATE_6_MONTHS": "Do 6 mesecev nazaj",
"LABEL_ADV_DATE_YEAR": "Do 1 leta nazaj"
"LABEL_ADV_DATE_YEAR": "Do 1 leta nazaj",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Preklopi celozaslonski pogled",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "Upp till 1 månad gammalt",
"LABEL_ADV_DATE_3_MONTHS": "Upp till 3 månader gammalt",
"LABEL_ADV_DATE_6_MONTHS": "Upp till 6 månader gammalt",
"LABEL_ADV_DATE_YEAR": "Upp till 1 år gammalt"
"LABEL_ADV_DATE_YEAR": "Upp till 1 år gammalt",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Växla fullskärmsläge",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "1 ay önceki",
"LABEL_ADV_DATE_3_MONTHS": "3 ay önceki",
"LABEL_ADV_DATE_6_MONTHS": "6 ay önceki",
"LABEL_ADV_DATE_YEAR": "1 yıl önceki"
"LABEL_ADV_DATE_YEAR": "1 yıl önceki",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Toggle fullscreen",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "За місяць",
"LABEL_ADV_DATE_3_MONTHS": "За 3 місяці",
"LABEL_ADV_DATE_6_MONTHS": "За півроку",
"LABEL_ADV_DATE_YEAR": "За рік"
"LABEL_ADV_DATE_YEAR": "За рік",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Toggle fullscreen",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "1个月以内",
"LABEL_ADV_DATE_3_MONTHS": "3个月以内",
"LABEL_ADV_DATE_6_MONTHS": "半年以内",
"LABEL_ADV_DATE_YEAR": "1年以内"
"LABEL_ADV_DATE_YEAR": "1年以内",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "切换全屏",

View file

@ -57,7 +57,11 @@
"LABEL_ADV_DATE_MONTH": "1月以內",
"LABEL_ADV_DATE_3_MONTHS": "3月以內",
"LABEL_ADV_DATE_6_MONTHS": "半年以內",
"LABEL_ADV_DATE_YEAR": "1年以內"
"LABEL_ADV_DATE_YEAR": "1年以內",
"LABEL_ADV_SUBFOLDERS": "Subfolders",
"LABEL_ADV_SUBFOLDERS_NONE": "None",
"LABEL_ADV_SUBFOLDERS_SUBTREE": "All",
"LABEL_ADV_SUBFOLDERS_SUBTREE_ONE": "One level"
},
"PREVIEW_POPUP": {
"FULLSCREEN": "Toggle fullscreen",

View file

@ -50,6 +50,20 @@
}
}"></div>
</div>
<!-- ko if: showMultisearch -->
<div class="control-group">
<label class="control-label" data-i18n="SEARCH/LABEL_ADV_SUBFOLDERS"></label>
<div class="controls" data-bind="component: {
name: 'Select',
params: {
options: selectedTree,
value: selectedTreeValue,
optionsText: 'name',
optionsValue: 'id'
}
}"></div>
</div>
<!-- /ko -->
<div class="control-group">
<label class="control-label">
</label>