diff --git a/dev/App/User.js b/dev/App/User.js index a1b35ea80..027091547 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -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); diff --git a/dev/Model/FolderCollection.js b/dev/Model/FolderCollection.js index 8542f1686..6f37b7634 100644 --- a/dev/Model/FolderCollection.js +++ b/dev/Model/FolderCollection.js @@ -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'))); diff --git a/dev/Settings/User/Folders.js b/dev/Settings/User/Folders.js index 89c6839e1..3dc3e21e3 100644 --- a/dev/Settings/User/Folders.js +++ b/dev/Settings/User/Folders.js @@ -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); diff --git a/dev/Stores/User/Folder.js b/dev/Stores/User/Folder.js index 37415632a..8b600d885 100644 --- a/dev/Stores/User/Folder.js +++ b/dev/Stores/User/Folder.js @@ -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} */ diff --git a/dev/View/Popup/AdvancedSearch.js b/dev/View/Popup/AdvancedSearch.js index 2c8cb6fa1..4fc5057ae 100644 --- a/dev/View/Popup/AdvancedSearch.js +++ b/dev/View/Popup/AdvancedSearch.js @@ -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() { diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index aee2bf1bf..f8358e7ea 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -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; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index 070e8393b..26ae8b701 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -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); } /** diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/ESEARCH.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/ESEARCH.php new file mode 100644 index 000000000..fa4cf65f1 --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/ESEARCH.php @@ -0,0 +1,88 @@ +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 + ); + } +} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/Request.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/Request.php new file mode 100644 index 000000000..ec5e11f1e --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/Request.php @@ -0,0 +1,29 @@ +oImapClient = $oImapClient; + } + + final public function getName() + { + $name = \explode('\\', \get_class($this)); + return \end($name); + } +} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/SORT.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/SORT.php new file mode 100644 index 000000000..1e4080bb2 --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/SORT.php @@ -0,0 +1,81 @@ +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 + ); + } +} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php index b5d7380a5..01d07114d 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php @@ -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; } } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php new file mode 100644 index 000000000..e21b68b39 --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php @@ -0,0 +1,449 @@ + + Messages that contain the specified string in the envelope + structure's BCC field. + + ✔ BEFORE + Messages whose internal date (disregarding time and timezone) + is earlier than the specified date. + + ✔ BODY + Messages that contain the specified string in the body of the + message. + + ✔ CC + Messages that contain the specified string in the envelope + structure's CC field. + + ✔ FROM + Messages that contain the specified string in the envelope + structure's FROM field. + + ✔ HEADER + 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 + Messages with the specified keyword flag set. + + ✔ LARGER + Messages with an [RFC-2822] size larger than the specified + number of octets. + + ☐ NOT + Messages that do not match the specified search key. + + ☐ ON + Messages whose internal date (disregarding time and timezone) + is within the specified date. + + ✔ OR + Messages that match either search key. + + ☐ SENTBEFORE + Messages whose [RFC-2822] Date: header (disregarding time and + timezone) is earlier than the specified date. + + ☐ SENTON + Messages whose [RFC-2822] Date: header (disregarding time and + timezone) is within the specified date. + + ☐ SENTSINCE + Messages whose [RFC-2822] Date: header (disregarding time and + timezone) is within or later than the specified date. + + ✔ SINCE + Messages whose internal date (disregarding time and timezone) + is within or later than the specified date. + + ✔ SMALLER + Messages with an [RFC-2822] size smaller than the specified + number of octets. + + ✔ SUBJECT + Messages that contain the specified string in the envelope + structure's SUBJECT field. + + ✔ TEXT + Messages that contain the specified string in the header or + body of the message. + + ✔ TO + Messages that contain the specified string in the envelope + structure's TO field. + + ☐ UID + Messages with unique identifiers corresponding to the specified + unique identifier set. Sequence set ranges are permitted. + + ☐ UNKEYWORD + 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('/".*?(? $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; + } +} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php index 0980b96b6..99dcacc64 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php @@ -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) )); } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php index 743d54bad..3f19f339f 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php @@ -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('/".*?(? $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(); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php index 5e17a9da0..d21334936 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php @@ -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; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php index 6b80b82ba..60d7fb558 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php @@ -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)); diff --git a/snappymail/v/0.0.0/app/localization/ar-SA/user.json b/snappymail/v/0.0.0/app/localization/ar-SA/user.json index 69a49c2e5..b7eac0427 100644 --- a/snappymail/v/0.0.0/app/localization/ar-SA/user.json +++ b/snappymail/v/0.0.0/app/localization/ar-SA/user.json @@ -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": "إعداد افتراضي لوضع ملء الشاشة", diff --git a/snappymail/v/0.0.0/app/localization/bg-BG/user.json b/snappymail/v/0.0.0/app/localization/bg-BG/user.json index 58e072623..c44f33c95 100644 --- a/snappymail/v/0.0.0/app/localization/bg-BG/user.json +++ b/snappymail/v/0.0.0/app/localization/bg-BG/user.json @@ -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": "На цял екран", diff --git a/snappymail/v/0.0.0/app/localization/cs-CZ/user.json b/snappymail/v/0.0.0/app/localization/cs-CZ/user.json index 87a3c50b7..854f09080 100644 --- a/snappymail/v/0.0.0/app/localization/cs-CZ/user.json +++ b/snappymail/v/0.0.0/app/localization/cs-CZ/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/da-DK/user.json b/snappymail/v/0.0.0/app/localization/da-DK/user.json index 5ca2ee46d..f2d201e67 100644 --- a/snappymail/v/0.0.0/app/localization/da-DK/user.json +++ b/snappymail/v/0.0.0/app/localization/da-DK/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/de-DE/user.json b/snappymail/v/0.0.0/app/localization/de-DE/user.json index bf3c73c11..238ce6eb2 100644 --- a/snappymail/v/0.0.0/app/localization/de-DE/user.json +++ b/snappymail/v/0.0.0/app/localization/de-DE/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/el-GR/user.json b/snappymail/v/0.0.0/app/localization/el-GR/user.json index 0e7666f88..1236e39e7 100644 --- a/snappymail/v/0.0.0/app/localization/el-GR/user.json +++ b/snappymail/v/0.0.0/app/localization/el-GR/user.json @@ -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": "Ενναλαγή πλήρους οθόνης", diff --git a/snappymail/v/0.0.0/app/localization/en/user.json b/snappymail/v/0.0.0/app/localization/en/user.json index 3530c502c..ee1bd3126 100644 --- a/snappymail/v/0.0.0/app/localization/en/user.json +++ b/snappymail/v/0.0.0/app/localization/en/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/es-ES/user.json b/snappymail/v/0.0.0/app/localization/es-ES/user.json index a7ea49aba..a9ecf1189 100644 --- a/snappymail/v/0.0.0/app/localization/es-ES/user.json +++ b/snappymail/v/0.0.0/app/localization/es-ES/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/et-EE/user.json b/snappymail/v/0.0.0/app/localization/et-EE/user.json index 769673c8e..14e05d9c1 100644 --- a/snappymail/v/0.0.0/app/localization/et-EE/user.json +++ b/snappymail/v/0.0.0/app/localization/et-EE/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/fa-IR/user.json b/snappymail/v/0.0.0/app/localization/fa-IR/user.json index e3423c57f..0027c7833 100644 --- a/snappymail/v/0.0.0/app/localization/fa-IR/user.json +++ b/snappymail/v/0.0.0/app/localization/fa-IR/user.json @@ -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": "ضامن تمام صفحه", diff --git a/snappymail/v/0.0.0/app/localization/fi-FI/user.json b/snappymail/v/0.0.0/app/localization/fi-FI/user.json index 537335b78..3e49f33b8 100644 --- a/snappymail/v/0.0.0/app/localization/fi-FI/user.json +++ b/snappymail/v/0.0.0/app/localization/fi-FI/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/fr-FR/user.json b/snappymail/v/0.0.0/app/localization/fr-FR/user.json index 47e132b9a..20759c86c 100644 --- a/snappymail/v/0.0.0/app/localization/fr-FR/user.json +++ b/snappymail/v/0.0.0/app/localization/fr-FR/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/hu-HU/user.json b/snappymail/v/0.0.0/app/localization/hu-HU/user.json index 6e2e09e70..3d89ab489 100644 --- a/snappymail/v/0.0.0/app/localization/hu-HU/user.json +++ b/snappymail/v/0.0.0/app/localization/hu-HU/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/id-ID/user.json b/snappymail/v/0.0.0/app/localization/id-ID/user.json index fc719ca7b..2d5dff627 100644 --- a/snappymail/v/0.0.0/app/localization/id-ID/user.json +++ b/snappymail/v/0.0.0/app/localization/id-ID/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/is-IS/user.json b/snappymail/v/0.0.0/app/localization/is-IS/user.json index 15ae7b05a..13d535ada 100644 --- a/snappymail/v/0.0.0/app/localization/is-IS/user.json +++ b/snappymail/v/0.0.0/app/localization/is-IS/user.json @@ -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\/á", diff --git a/snappymail/v/0.0.0/app/localization/it-IT/user.json b/snappymail/v/0.0.0/app/localization/it-IT/user.json index 9f33aa947..9ef5ed5fa 100644 --- a/snappymail/v/0.0.0/app/localization/it-IT/user.json +++ b/snappymail/v/0.0.0/app/localization/it-IT/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/ja-JP/user.json b/snappymail/v/0.0.0/app/localization/ja-JP/user.json index cfeae1b16..471b25d14 100644 --- a/snappymail/v/0.0.0/app/localization/ja-JP/user.json +++ b/snappymail/v/0.0.0/app/localization/ja-JP/user.json @@ -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": "フルスクリーン", diff --git a/snappymail/v/0.0.0/app/localization/ko-KR/user.json b/snappymail/v/0.0.0/app/localization/ko-KR/user.json index ee2cb2f62..a320ce283 100644 --- a/snappymail/v/0.0.0/app/localization/ko-KR/user.json +++ b/snappymail/v/0.0.0/app/localization/ko-KR/user.json @@ -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": "전체화면으로 보기", diff --git a/snappymail/v/0.0.0/app/localization/lt-LT/user.json b/snappymail/v/0.0.0/app/localization/lt-LT/user.json index 43c6b3808..a3101d5da 100644 --- a/snappymail/v/0.0.0/app/localization/lt-LT/user.json +++ b/snappymail/v/0.0.0/app/localization/lt-LT/user.json @@ -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ą", diff --git a/snappymail/v/0.0.0/app/localization/lv-LV/user.json b/snappymail/v/0.0.0/app/localization/lv-LV/user.json index 8b8a7d3ab..233566abd 100644 --- a/snappymail/v/0.0.0/app/localization/lv-LV/user.json +++ b/snappymail/v/0.0.0/app/localization/lv-LV/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/nb-NO/user.json b/snappymail/v/0.0.0/app/localization/nb-NO/user.json index 5572a3147..4cb0d81cf 100644 --- a/snappymail/v/0.0.0/app/localization/nb-NO/user.json +++ b/snappymail/v/0.0.0/app/localization/nb-NO/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/nl-NL/user.json b/snappymail/v/0.0.0/app/localization/nl-NL/user.json index 57ba98ebf..2a69299de 100644 --- a/snappymail/v/0.0.0/app/localization/nl-NL/user.json +++ b/snappymail/v/0.0.0/app/localization/nl-NL/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/pl-PL/user.json b/snappymail/v/0.0.0/app/localization/pl-PL/user.json index a5ee5b9e1..57d151a8a 100644 --- a/snappymail/v/0.0.0/app/localization/pl-PL/user.json +++ b/snappymail/v/0.0.0/app/localization/pl-PL/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/pt-BR/user.json b/snappymail/v/0.0.0/app/localization/pt-BR/user.json index 7ea11d446..3579055e9 100644 --- a/snappymail/v/0.0.0/app/localization/pt-BR/user.json +++ b/snappymail/v/0.0.0/app/localization/pt-BR/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/pt-PT/user.json b/snappymail/v/0.0.0/app/localization/pt-PT/user.json index 5df2edbfd..2a8589a55 100644 --- a/snappymail/v/0.0.0/app/localization/pt-PT/user.json +++ b/snappymail/v/0.0.0/app/localization/pt-PT/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/ro-RO/user.json b/snappymail/v/0.0.0/app/localization/ro-RO/user.json index 206dcbfea..e80cda19e 100644 --- a/snappymail/v/0.0.0/app/localization/ro-RO/user.json +++ b/snappymail/v/0.0.0/app/localization/ro-RO/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/ru-RU/user.json b/snappymail/v/0.0.0/app/localization/ru-RU/user.json index af9f978ff..f91ff38f2 100644 --- a/snappymail/v/0.0.0/app/localization/ru-RU/user.json +++ b/snappymail/v/0.0.0/app/localization/ru-RU/user.json @@ -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": "Полный экран", diff --git a/snappymail/v/0.0.0/app/localization/sk-SK/user.json b/snappymail/v/0.0.0/app/localization/sk-SK/user.json index b1cff1a65..16b392917 100644 --- a/snappymail/v/0.0.0/app/localization/sk-SK/user.json +++ b/snappymail/v/0.0.0/app/localization/sk-SK/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/sl-SI/user.json b/snappymail/v/0.0.0/app/localization/sl-SI/user.json index ef067c0db..72412d979 100644 --- a/snappymail/v/0.0.0/app/localization/sl-SI/user.json +++ b/snappymail/v/0.0.0/app/localization/sl-SI/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/sv-SE/user.json b/snappymail/v/0.0.0/app/localization/sv-SE/user.json index e1a8a30d8..2161bb550 100644 --- a/snappymail/v/0.0.0/app/localization/sv-SE/user.json +++ b/snappymail/v/0.0.0/app/localization/sv-SE/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/tr-TR/user.json b/snappymail/v/0.0.0/app/localization/tr-TR/user.json index bece1a3be..70472858b 100644 --- a/snappymail/v/0.0.0/app/localization/tr-TR/user.json +++ b/snappymail/v/0.0.0/app/localization/tr-TR/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/uk-UA/user.json b/snappymail/v/0.0.0/app/localization/uk-UA/user.json index 9aca6f85c..fc1378382 100644 --- a/snappymail/v/0.0.0/app/localization/uk-UA/user.json +++ b/snappymail/v/0.0.0/app/localization/uk-UA/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/localization/zh-CN/user.json b/snappymail/v/0.0.0/app/localization/zh-CN/user.json index c86c971d1..a24b9810a 100644 --- a/snappymail/v/0.0.0/app/localization/zh-CN/user.json +++ b/snappymail/v/0.0.0/app/localization/zh-CN/user.json @@ -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": "切换全屏", diff --git a/snappymail/v/0.0.0/app/localization/zh-TW/user.json b/snappymail/v/0.0.0/app/localization/zh-TW/user.json index 3e917b137..e6af04baa 100644 --- a/snappymail/v/0.0.0/app/localization/zh-TW/user.json +++ b/snappymail/v/0.0.0/app/localization/zh-TW/user.json @@ -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", diff --git a/snappymail/v/0.0.0/app/templates/Views/User/PopupsAdvancedSearch.html b/snappymail/v/0.0.0/app/templates/Views/User/PopupsAdvancedSearch.html index 2901a2d2a..ab5bfa201 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/PopupsAdvancedSearch.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/PopupsAdvancedSearch.html @@ -50,6 +50,20 @@ } }"> + +
+ +
+
+