mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Activated search subfolders as request by #154
This commit is contained in:
parent
b1038667ee
commit
6c797c34f8
51 changed files with 1024 additions and 874 deletions
|
|
@ -840,7 +840,7 @@ class AppUser extends AbstractApp {
|
||||||
if (getFolderInboxName() !== cF) {
|
if (getFolderInboxName() !== cF) {
|
||||||
this.folderInformation(cF);
|
this.folderInformation(cF);
|
||||||
}
|
}
|
||||||
FolderUserStore.listStatusSupported() || this.folderInformationMultiply(true);
|
FolderUserStore.hasCapability('LIST-STATUS') || this.folderInformationMultiply(true);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
setTimeout(() => Remote.appDelayStart(()=>0), 35000);
|
setTimeout(() => Remote.appDelayStart(()=>0), 35000);
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,11 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
||||||
super();
|
super();
|
||||||
this.CountRec
|
this.CountRec
|
||||||
this.FoldersHash
|
this.FoldersHash
|
||||||
this.IsMetadataSupported
|
|
||||||
this.IsThreadsSupported
|
this.IsThreadsSupported
|
||||||
this.IsSortSupported
|
|
||||||
this.IsExtendedSupported
|
|
||||||
this.Namespace;
|
this.Namespace;
|
||||||
this.Optimized
|
this.Optimized
|
||||||
this.SystemFolders
|
this.SystemFolders
|
||||||
|
this.Capabilities
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -146,11 +144,9 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
||||||
AppUserStore.threadsAllowed(!!(Settings.app('useImapThread') && this.IsThreadsSupported));
|
AppUserStore.threadsAllowed(!!(Settings.app('useImapThread') && this.IsThreadsSupported));
|
||||||
|
|
||||||
FolderUserStore.folderListOptimized(!!this.Optimized);
|
FolderUserStore.folderListOptimized(!!this.Optimized);
|
||||||
FolderUserStore.sortSupported(!!this.IsSortSupported);
|
|
||||||
FolderUserStore.metadataSupported(!!this.IsMetadataSupported);
|
|
||||||
FolderUserStore.listStatusSupported(!!this.IsListStatusSupported);
|
|
||||||
FolderUserStore.quotaUsage(this.quotaUsage);
|
FolderUserStore.quotaUsage(this.quotaUsage);
|
||||||
FolderUserStore.quotaLimit(this.quotaLimit);
|
FolderUserStore.quotaLimit(this.quotaLimit);
|
||||||
|
FolderUserStore.capabilities(this.Capabilities);
|
||||||
|
|
||||||
FolderUserStore.sentFolder(normalizeFolder(SettingsGet('SentFolder')));
|
FolderUserStore.sentFolder(normalizeFolder(SettingsGet('SentFolder')));
|
||||||
FolderUserStore.draftFolder(normalizeFolder(SettingsGet('DraftFolder')));
|
FolderUserStore.draftFolder(normalizeFolder(SettingsGet('DraftFolder')));
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ const folderForDeletion = ko.observable(null).deleteAccessHelper();
|
||||||
|
|
||||||
export class FoldersUserSettings /*extends AbstractViewSettings*/ {
|
export class FoldersUserSettings /*extends AbstractViewSettings*/ {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.showKolab = Settings.capa(Capa.Kolab) && FolderUserStore.metadataSupported();
|
this.showKolab = ko.computed(() => FolderUserStore.hasCapability('METADATA') && Settings.capa(Capa.Kolab));
|
||||||
this.defaultOptionsAfterRender = defaultOptionsAfterRender;
|
this.defaultOptionsAfterRender = defaultOptionsAfterRender;
|
||||||
this.kolabTypeOptions = ko.observableArray();
|
this.kolabTypeOptions = ko.observableArray();
|
||||||
let i18nFilter = key => i18n('SETTINGS_FOLDERS/TYPE_' + key);
|
let i18nFilter = key => i18n('SETTINGS_FOLDERS/TYPE_' + key);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ import { Settings, SettingsGet } from 'Common/Globals';
|
||||||
|
|
||||||
export const FolderUserStore = new class {
|
export const FolderUserStore = new class {
|
||||||
constructor() {
|
constructor() {
|
||||||
addObservablesTo(this, {
|
const self = this;
|
||||||
|
addObservablesTo(self, {
|
||||||
/**
|
/**
|
||||||
* To use "checkable" option in /#/settings/folders
|
* To use "checkable" option in /#/settings/folders
|
||||||
* When true, getNextFolderNames only lists system and "checkable" folders
|
* When true, getNextFolderNames only lists system and "checkable" folders
|
||||||
|
|
@ -19,12 +20,6 @@ export const FolderUserStore = new class {
|
||||||
*/
|
*/
|
||||||
displaySpecSetting: false,
|
displaySpecSetting: false,
|
||||||
|
|
||||||
/**
|
|
||||||
* If the IMAP server supports SORT, METADATA
|
|
||||||
*/
|
|
||||||
sortSupported: false,
|
|
||||||
metadataSupported: false,
|
|
||||||
listStatusSupported: false,
|
|
||||||
// sortMode: '',
|
// sortMode: '',
|
||||||
|
|
||||||
quotaLimit: 0,
|
quotaLimit: 0,
|
||||||
|
|
@ -47,40 +42,42 @@ export const FolderUserStore = new class {
|
||||||
foldersInboxUnreadCount: 0
|
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 : ''),
|
currentFolderFullNameRaw: () => (self.currentFolder() ? self.currentFolder().fullNameRaw : ''),
|
||||||
currentFolderFullNameHash: () => (this.currentFolder() ? this.currentFolder().fullNameHash : ''),
|
|
||||||
|
currentFolderFullName: () => (self.currentFolder() ? self.currentFolder().fullName : ''),
|
||||||
|
currentFolderFullNameHash: () => (self.currentFolder() ? self.currentFolder().fullNameHash : ''),
|
||||||
|
|
||||||
foldersChanging: () =>
|
foldersChanging: () =>
|
||||||
this.foldersLoading() | this.foldersCreating() | this.foldersDeleting() | this.foldersRenaming(),
|
self.foldersLoading() | self.foldersCreating() | self.foldersDeleting() | self.foldersRenaming(),
|
||||||
|
|
||||||
folderListSystemNames: () => {
|
folderListSystemNames: () => {
|
||||||
const list = [getFolderInboxName()],
|
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));
|
others.forEach(name => name && UNUSED_OPTION_VALUE !== name && list.push(name));
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
},
|
},
|
||||||
|
|
||||||
folderListSystem: () =>
|
folderListSystem: () =>
|
||||||
this.folderListSystemNames().map(name => getFolderFromCacheList(name)).filter(v => v)
|
self.folderListSystemNames().map(name => getFolderFromCacheList(name)).filter(v => v)
|
||||||
});
|
});
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -93,13 +90,13 @@ export const FolderUserStore = new class {
|
||||||
folder && folder.type(type);
|
folder && folder.type(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.sentFolder.subscribe(fRemoveSystemFolderType(this.sentFolder), this, 'beforeChange');
|
self.sentFolder.subscribe(fRemoveSystemFolderType(self.sentFolder), self, 'beforeChange');
|
||||||
this.draftFolder.subscribe(fRemoveSystemFolderType(this.draftFolder), this, 'beforeChange');
|
self.draftFolder.subscribe(fRemoveSystemFolderType(self.draftFolder), self, 'beforeChange');
|
||||||
this.spamFolder.subscribe(fRemoveSystemFolderType(this.spamFolder), this, 'beforeChange');
|
self.spamFolder.subscribe(fRemoveSystemFolderType(self.spamFolder), self, 'beforeChange');
|
||||||
this.trashFolder.subscribe(fRemoveSystemFolderType(this.trashFolder), this, 'beforeChange');
|
self.trashFolder.subscribe(fRemoveSystemFolderType(self.trashFolder), self, 'beforeChange');
|
||||||
this.archiveFolder.subscribe(fRemoveSystemFolderType(this.archiveFolder), this, 'beforeChange');
|
self.archiveFolder.subscribe(fRemoveSystemFolderType(self.archiveFolder), self, 'beforeChange');
|
||||||
|
|
||||||
addSubscribablesTo(this, {
|
addSubscribablesTo(self, {
|
||||||
sentFolder: fSetSystemFolderType(FolderType.Sent),
|
sentFolder: fSetSystemFolderType(FolderType.Sent),
|
||||||
draftFolder: fSetSystemFolderType(FolderType.Drafts),
|
draftFolder: fSetSystemFolderType(FolderType.Drafts),
|
||||||
spamFolder: fSetSystemFolderType(FolderType.Spam),
|
spamFolder: fSetSystemFolderType(FolderType.Spam),
|
||||||
|
|
@ -107,12 +104,19 @@ export const FolderUserStore = new class {
|
||||||
archiveFolder: fSetSystemFolderType(FolderType.Archive)
|
archiveFolder: fSetSystemFolderType(FolderType.Archive)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.quotaPercentage = ko.computed(() => {
|
self.quotaPercentage = ko.computed(() => {
|
||||||
const quota = this.quotaLimit(), usage = this.quotaUsage();
|
const quota = self.quotaLimit(), usage = self.quotaUsage();
|
||||||
return 0 < quota ? Math.ceil((usage / quota) * 100) : 0;
|
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}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { MessageUserStore } from 'Stores/User/Message';
|
||||||
|
|
||||||
import { decorateKoCommands } from 'Knoin/Knoin';
|
import { decorateKoCommands } from 'Knoin/Knoin';
|
||||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||||
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
|
|
||||||
class AdvancedSearchPopupView extends AbstractViewPopup {
|
class AdvancedSearchPopupView extends AbstractViewPopup {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -17,12 +18,15 @@ class AdvancedSearchPopupView extends AbstractViewPopup {
|
||||||
subject: '',
|
subject: '',
|
||||||
text: '',
|
text: '',
|
||||||
selectedDateValue: -1,
|
selectedDateValue: -1,
|
||||||
|
selectedTreeValue: '',
|
||||||
|
|
||||||
hasAttachment: false,
|
hasAttachment: false,
|
||||||
starred: false,
|
starred: false,
|
||||||
unseen: false
|
unseen: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.showMultisearch = ko.computed(() => FolderUserStore.hasCapability('MULTISEARCH'));
|
||||||
|
|
||||||
let prefix = 'SEARCH/LABEL_ADV_DATE_';
|
let prefix = 'SEARCH/LABEL_ADV_DATE_';
|
||||||
this.selectedDates = ko.computed(() => {
|
this.selectedDates = ko.computed(() => {
|
||||||
translatorTrigger();
|
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, {
|
decorateKoCommands(this, {
|
||||||
searchCommand: 1
|
searchCommand: 1
|
||||||
});
|
});
|
||||||
|
|
@ -69,65 +83,54 @@ class AdvancedSearchPopupView extends AbstractViewPopup {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSearchStringValue(value) {
|
|
||||||
if (value.includes(' ')) {
|
|
||||||
value = '"' + value + '"';
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildSearchString() {
|
buildSearchString() {
|
||||||
const result = [],
|
const
|
||||||
from_ = this.from().trim(),
|
result = new FormData();
|
||||||
to = this.to().trim(),
|
|
||||||
subject = this.subject().trim(),
|
|
||||||
text = this.text().trim(),
|
|
||||||
isPart = [],
|
|
||||||
hasPart = [];
|
|
||||||
|
|
||||||
if (from_) {
|
let value = this.from().trim();
|
||||||
result.push('from:' + this.buildSearchStringValue(from_));
|
if (value) {
|
||||||
|
result.set('from', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to) {
|
value = this.to().trim();
|
||||||
result.push('to:' + this.buildSearchStringValue(to));
|
if (value) {
|
||||||
|
result.set('to', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subject) {
|
value = this.subject().trim();
|
||||||
result.push('subject:' + this.buildSearchStringValue(subject));
|
if (value) {
|
||||||
|
result.set('subject', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasAttachment()) {
|
if (this.hasAttachment()) {
|
||||||
hasPart.push('attachment');
|
result.set('has', 'attachment');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.unseen()) {
|
if (this.unseen()) {
|
||||||
isPart.push('unseen');
|
result.set('is[]', 'unseen');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.starred()) {
|
if (this.starred()) {
|
||||||
isPart.push('flagged');
|
result.set('is[]', 'flagged');
|
||||||
}
|
|
||||||
|
|
||||||
if (hasPart.length) {
|
|
||||||
result.push('has:' + hasPart.join(','));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPart.length) {
|
|
||||||
result.push('is:' + isPart.join(','));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 < this.selectedDateValue()) {
|
if (-1 < this.selectedDateValue()) {
|
||||||
let d = new Date();
|
let d = new Date();
|
||||||
d.setDate(d.getDate() - this.selectedDateValue());
|
d.setDate(d.getDate() - this.selectedDateValue());
|
||||||
result.push('date:' + d.format('Y.m.d') + '/');
|
result.set('date', d.format('Y.m.d') + '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text) {
|
value = this.selectedTreeValue();
|
||||||
result.push('text:' + this.buildSearchStringValue(text));
|
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() {
|
clearPopup() {
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,9 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
|
|
||||||
this.messageList = MessageUserStore.list;
|
this.messageList = MessageUserStore.list;
|
||||||
|
|
||||||
this.sortSupported = FolderUserStore.sortSupported;
|
this.sortSupported = ko.computed(() =>
|
||||||
|
FolderUserStore.hasCapability('SORT') | FolderUserStore.hasCapability('ESORT')
|
||||||
|
);
|
||||||
|
|
||||||
this.composeInEdit = AppUserStore.composeInEdit;
|
this.composeInEdit = AppUserStore.composeInEdit;
|
||||||
this.leftPanelDisabled = leftPanelDisabled;
|
this.leftPanelDisabled = leftPanelDisabled;
|
||||||
|
|
|
||||||
|
|
@ -452,7 +452,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
||||||
if ($this->IsSupported('ESEARCH')) {
|
if ($this->IsSupported('ESEARCH')) {
|
||||||
$aResult = $oFolderInfo->getStatusItems();
|
$aResult = $oFolderInfo->getStatusItems();
|
||||||
// SELECT or EXAMINE command then UNSEEN is the message sequence number of the first unseen message
|
// 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;
|
return $aResult;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
@ -778,10 +778,6 @@ class ImapClient extends \MailSo\Net\NetClient
|
||||||
*/
|
*/
|
||||||
public function MessageSimpleSort(array $aSortTypes, string $sSearchCriterias = 'ALL', bool $bReturnUid = true) : array
|
public function MessageSimpleSort(array $aSortTypes, string $sSearchCriterias = 'ALL', bool $bReturnUid = true) : array
|
||||||
{
|
{
|
||||||
$sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
|
|
||||||
$sSearchCriterias = !\strlen(\trim($sSearchCriterias)) || '*' === $sSearchCriterias
|
|
||||||
? 'ALL' : $sSearchCriterias;
|
|
||||||
|
|
||||||
if (!$aSortTypes)
|
if (!$aSortTypes)
|
||||||
{
|
{
|
||||||
$this->writeLogException(
|
$this->writeLogException(
|
||||||
|
|
@ -795,6 +791,10 @@ class ImapClient extends \MailSo\Net\NetClient
|
||||||
\MailSo\Log\Enumerations\Type::ERROR, true);
|
\MailSo\Log\Enumerations\Type::ERROR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
|
||||||
|
$sSearchCriterias = !\strlen(\trim($sSearchCriterias)) || '*' === $sSearchCriterias
|
||||||
|
? 'ALL' : $sSearchCriterias;
|
||||||
|
|
||||||
$aRequest = array();
|
$aRequest = array();
|
||||||
$aRequest[] = $aSortTypes;
|
$aRequest[] = $aSortTypes;
|
||||||
$aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
|
$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\Net\Exceptions\Exception
|
||||||
* @throws \MailSo\Imap\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 ' : '';
|
$oESearch = new Requests\ESEARCH($this);
|
||||||
$sSearchCriterias = !\strlen($sSearchCriterias) || '*' === $sSearchCriterias
|
$oESearch->sCriterias = $sSearchCriterias;
|
||||||
? 'ALL' : $sSearchCriterias;
|
$oESearch->aReturn = $aSearchReturn;
|
||||||
|
$oESearch->bUid = $bReturnUid;
|
||||||
$sCmd = $bSort ? 'SORT': 'SEARCH';
|
$oESearch->sLimit = $sLimit;
|
||||||
if ($bSort && (!$aSortTypes || !$this->IsSupported('SORT')))
|
$oESearch->sCharset = $sCharset;
|
||||||
{
|
return $oESearch->SendRequestGetResponse()
|
||||||
$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)
|
|
||||||
->getSimpleESearchOrESortResult($this->getCurrentTag(), $bReturnUid);
|
->getSimpleESearchOrESortResult($this->getCurrentTag(), $bReturnUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -885,19 +828,16 @@ class ImapClient extends \MailSo\Net\NetClient
|
||||||
* @throws \MailSo\Net\Exceptions\Exception
|
* @throws \MailSo\Net\Exceptions\Exception
|
||||||
* @throws \MailSo\Imap\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);
|
$oSort = new Requests\SORT($this);
|
||||||
}
|
$oSort->sCriterias = $sSearchCriterias;
|
||||||
|
$oSort->aReturn = $aSearchReturn ?: ['ALL'];
|
||||||
/**
|
$oSort->bUid = $bReturnUid;
|
||||||
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
|
$oSort->sLimit = $sLimit;
|
||||||
* @throws \MailSo\Net\Exceptions\Exception
|
$oSort->aSortTypes = $aSortTypes;
|
||||||
* @throws \MailSo\Imap\Exceptions\Exception
|
return $oSort->SendRequestGetResponse()
|
||||||
*/
|
->getSimpleESearchOrESortResult($this->getCurrentTag(), $bReturnUid);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -227,7 +227,7 @@ class ResponseCollection extends \MailSo\Base\Collection
|
||||||
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
||||||
&& ($sStatus === $oResponse->StatusOrIndex || $iOffset)
|
&& ($sStatus === $oResponse->StatusOrIndex || $iOffset)
|
||||||
&& \is_array($oResponse->ResponseList)
|
&& \is_array($oResponse->ResponseList)
|
||||||
&& 2 < count($oResponse->ResponseList))
|
&& 2 < \count($oResponse->ResponseList))
|
||||||
{
|
{
|
||||||
$iLen = \count($oResponse->ResponseList);
|
$iLen = \count($oResponse->ResponseList);
|
||||||
for ($iIndex = 2 + $iOffset; $iIndex < $iLen; ++$iIndex) {
|
for ($iIndex = 2 + $iOffset; $iIndex < $iLen; ++$iIndex) {
|
||||||
|
|
@ -270,12 +270,13 @@ class ResponseCollection extends \MailSo\Base\Collection
|
||||||
$iLen = \count($oResponse->ResponseList);
|
$iLen = \count($oResponse->ResponseList);
|
||||||
for ($iIndex = 2 + $iOffset; $iIndex < $iLen; ++$iIndex) {
|
for ($iIndex = 2 + $iOffset; $iIndex < $iLen; ++$iIndex) {
|
||||||
$aNewValue = $this->validateThreadItem($oResponse->ResponseList[$iIndex]);
|
$aNewValue = $this->validateThreadItem($oResponse->ResponseList[$iIndex]);
|
||||||
if (false !== $aNewValue) {
|
if (\is_array($aNewValue)) {
|
||||||
$aReturn[] = $aNewValue;
|
$aReturn[] = $aNewValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $aReturn;
|
return $aReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -374,27 +375,24 @@ class ResponseCollection extends \MailSo\Base\Collection
|
||||||
$aResult = array();
|
$aResult = array();
|
||||||
foreach ($this as $oResponse) {
|
foreach ($this as $oResponse) {
|
||||||
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
||||||
&& ('ESEARCH' === $oResponse->StatusOrIndex || 'ESORT' === $oResponse->StatusOrIndex)
|
&& ('ESEARCH' === $oResponse->StatusOrIndex || 'SORT' === $oResponse->StatusOrIndex)
|
||||||
&& \is_array($oResponse->ResponseList)
|
&& \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]
|
&& '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;
|
$i = \count($oResponse->ResponseList) - 1;
|
||||||
foreach ($oResponse->ResponseList as $iIndex => $mItem) {
|
while (3 < --$i) {
|
||||||
if ($iIndex >= $iStart) {
|
$sItem = $oResponse->ResponseList[$i];
|
||||||
switch ($mItem)
|
switch ($sItem)
|
||||||
{
|
{
|
||||||
case 'ALL':
|
case 'ALL':
|
||||||
case 'MAX':
|
case 'MAX':
|
||||||
case 'MIN':
|
case 'MIN':
|
||||||
case 'COUNT':
|
case 'COUNT':
|
||||||
if (isset($oResponse->ResponseList[$iIndex + 1])) {
|
$aResult[$sItem] = $oResponse->ResponseList[$i + 1];
|
||||||
$aResult[$mItem] = $oResponse->ResponseList[$iIndex + 1];
|
break;
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
449
snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php
Normal file
449
snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,26 +27,11 @@ class FolderCollection extends \MailSo\Base\Collection
|
||||||
*/
|
*/
|
||||||
public $FoldersHash = '';
|
public $FoldersHash = '';
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $IsMetadataSupported = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public $IsThreadsSupported = false;
|
public $IsThreadsSupported = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $IsSortSupported = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $IsListStatusSupported = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
|
|
@ -59,6 +44,7 @@ class FolderCollection extends \MailSo\Base\Collection
|
||||||
|
|
||||||
public $quotaUsage = 0;
|
public $quotaUsage = 0;
|
||||||
public $quotaLimit = 0;
|
public $quotaLimit = 0;
|
||||||
|
public $capabilities = array();
|
||||||
|
|
||||||
public function append($oFolder, bool $bToTop = false) : void
|
public function append($oFolder, bool $bToTop = false) : void
|
||||||
{
|
{
|
||||||
|
|
@ -148,15 +134,13 @@ class FolderCollection extends \MailSo\Base\Collection
|
||||||
return \array_merge(parent::jsonSerialize(), array(
|
return \array_merge(parent::jsonSerialize(), array(
|
||||||
'Namespace' => $this->GetNamespace(),
|
'Namespace' => $this->GetNamespace(),
|
||||||
'FoldersHash' => $this->FoldersHash ?: '',
|
'FoldersHash' => $this->FoldersHash ?: '',
|
||||||
'IsMetadataSupported' => $this->IsMetadataSupported,
|
|
||||||
'IsThreadsSupported' => $this->IsThreadsSupported,
|
'IsThreadsSupported' => $this->IsThreadsSupported,
|
||||||
'IsSortSupported' => $this->IsSortSupported,
|
|
||||||
'IsListStatusSupported' => $this->IsListStatusSupported,
|
|
||||||
'quotaUsage' => $this->quotaUsage,
|
'quotaUsage' => $this->quotaUsage,
|
||||||
'quotaLimit' => $this->quotaLimit,
|
'quotaLimit' => $this->quotaLimit,
|
||||||
'Optimized' => $this->Optimized,
|
'Optimized' => $this->Optimized,
|
||||||
'CountRec' => $this->CountRec(),
|
'CountRec' => $this->CountRec(),
|
||||||
'SystemFolders' => empty($this->SystemFolders) ? null : $this->SystemFolders
|
'SystemFolders' => empty($this->SystemFolders) ? null : $this->SystemFolders,
|
||||||
|
'Capabilities' => \array_values($this->capabilities)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -640,6 +640,8 @@ class MailClient
|
||||||
{
|
{
|
||||||
$aFlags = array();
|
$aFlags = array();
|
||||||
|
|
||||||
|
list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq, $iAppendLimit, $sMailboxId) = $this->initFolderValues($sFolderName);
|
||||||
|
|
||||||
if (\count($aUids))
|
if (\count($aUids))
|
||||||
{
|
{
|
||||||
$this->oImapClient->FolderSelect($sFolderName);
|
$this->oImapClient->FolderSelect($sFolderName);
|
||||||
|
|
@ -661,16 +663,14 @@ class MailClient
|
||||||
'IsFlagged' => \in_array('\\flagged', $aLowerFlags),
|
'IsFlagged' => \in_array('\\flagged', $aLowerFlags),
|
||||||
'IsAnswered' => \in_array('\\answered', $aLowerFlags),
|
'IsAnswered' => \in_array('\\answered', $aLowerFlags),
|
||||||
'IsDeleted' => \in_array('\\deleted', $aLowerFlags),
|
'IsDeleted' => \in_array('\\deleted', $aLowerFlags),
|
||||||
'IsForwarded' => \in_array(\strtolower('$Forwarded'), $aLowerFlags) || ($sForwardedFlag && \in_array(\strtolower($sForwardedFlag), $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)),
|
'IsReadReceipt' => \in_array(\strtolower('$MDNSent'), $aLowerFlags)/* || ($sReadReceiptFlag && \in_array(\strtolower($sReadReceiptFlag), $aLowerFlags))*/,
|
||||||
'IsJunk' => !\in_array(\strtolower('$NonJunk'), $aLowerFlags) && \in_array(\strtolower('$Junk'), $aLowerFlags),
|
'IsJunk' => !\in_array(\strtolower('$NonJunk'), $aLowerFlags) && \in_array(\strtolower('$Junk'), $aLowerFlags),
|
||||||
'IsPhishing' => \in_array(\strtolower('$Phishing'), $aLowerFlags)
|
'IsPhishing' => \in_array(\strtolower('$Phishing'), $aLowerFlags)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq, $iAppendLimit, $sMailboxId) = $this->initFolderValues($sFolderName);
|
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'Folder' => $sFolderName,
|
'Folder' => $sFolderName,
|
||||||
'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUidNext, $iHighestModSeq),
|
'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUidNext, $iHighestModSeq),
|
||||||
|
|
@ -714,470 +714,12 @@ class MailClient
|
||||||
return 0 < $iResult ? $iResult : 0;
|
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\Base\Exceptions\InvalidArgumentException
|
||||||
* @throws \MailSo\Net\Exceptions\Exception
|
* @throws \MailSo\Net\Exceptions\Exception
|
||||||
* @throws \MailSo\Imap\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;
|
$iThreadLimit = \MailSo\Config::$LargeThreadLimit;
|
||||||
|
|
||||||
|
|
@ -1222,11 +764,6 @@ class MailClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($bCacheOnly)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->oImapClient->FolderExamine($sFolderName);
|
$this->oImapClient->FolderExamine($sFolderName);
|
||||||
|
|
||||||
$aThreadUids = array();
|
$aThreadUids = array();
|
||||||
|
|
@ -1237,117 +774,16 @@ class MailClient
|
||||||
catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
|
catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
|
||||||
{
|
{
|
||||||
unset($oException);
|
unset($oException);
|
||||||
$aThreadUids = array();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flatten to single levels
|
||||||
$aResult = array();
|
$aResult = array();
|
||||||
$aCompiledThreads = $this->compileThreadArray($aThreadUids);
|
foreach ($aThreadUids as $mItem) {
|
||||||
|
$aMap = [];
|
||||||
foreach ($aCompiledThreads as $mData)
|
\array_walk_recursive($mItem, function($a) use (&$aMap) { $aMap[] = $a; });
|
||||||
{
|
$aResult[] = $aMap;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$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))
|
if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey))
|
||||||
{
|
{
|
||||||
$oCacher->Set($sSerializedHashKey, \json_encode(array(
|
$oCacher->Set($sSerializedHashKey, \json_encode(array(
|
||||||
|
|
@ -1423,7 +859,7 @@ class MailClient
|
||||||
* @throws \MailSo\Imap\Exceptions\Exception
|
* @throws \MailSo\Imap\Exceptions\Exception
|
||||||
*/
|
*/
|
||||||
public function GetUids(?\MailSo\Cache\CacheClient $oCacher, string $sSearch,
|
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
|
bool $bUseSortIfSupported = false, string $sSort = '') : array
|
||||||
{
|
{
|
||||||
/* TODO: Validate $sSort
|
/* TODO: Validate $sSort
|
||||||
|
|
@ -1476,17 +912,16 @@ class MailClient
|
||||||
|
|
||||||
$bUseSortIfSupported = $bUseSortIfSupported && !\strlen($sSearch) && $this->oImapClient->IsSupported('SORT');
|
$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())
|
if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited())
|
||||||
{
|
{
|
||||||
$sSerializedHash = 'GetUids/'.
|
$sSerializedHash = 'GetUids/'.
|
||||||
($bUseSortIfSupported ? 'S' . $sSort : 'N').'/'.
|
($bUseSortIfSupported ? 'S' . $sSort : 'N').'/'.
|
||||||
$this->GenerateImapClientHash().'/'.
|
$this->GenerateImapClientHash().'/'.
|
||||||
$sFolderName.'/'.$sSearchCriterias;
|
$sFolderName.'/'.$sSearchCriterias;
|
||||||
|
|
||||||
$sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
|
$sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
|
||||||
|
|
||||||
$sSerialized = $oCacher->Get($sSerializedHash);
|
// $sSerialized = $oCacher->Get($sSerializedHash);
|
||||||
if (!empty($sSerialized))
|
if (!empty($sSerialized))
|
||||||
{
|
{
|
||||||
$aSerialized = \json_decode($sSerialized, true);
|
$aSerialized = \json_decode($sSerialized, true);
|
||||||
|
|
@ -1508,10 +943,15 @@ class MailClient
|
||||||
|
|
||||||
if (!\is_array($aResultUids))
|
if (!\is_array($aResultUids))
|
||||||
{
|
{
|
||||||
$aResultUids = $bUseSortIfSupported ?
|
if ($bUseSortIfSupported) {
|
||||||
$this->oImapClient->MessageSimpleSort(array($sSort ?: 'REVERSE DATE'), $sSearchCriterias, true) :
|
// $this->oImapClient->IsSupported('ESORT')
|
||||||
$this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8')
|
// $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))
|
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\Base\Exceptions\InvalidArgumentException
|
||||||
* @throws \MailSo\Net\Exceptions\Exception
|
* @throws \MailSo\Net\Exceptions\Exception
|
||||||
* @throws \MailSo\Imap\Exceptions\Exception
|
* @throws \MailSo\Imap\Exceptions\Exception
|
||||||
|
|
@ -1538,17 +979,17 @@ class MailClient
|
||||||
public function MessageList(string $sFolderName, int $iOffset = 0, int $iLimit = 10,
|
public function MessageList(string $sFolderName, int $iOffset = 0, int $iLimit = 10,
|
||||||
string $sSearch = '', int $iPrevUidNext = 0, ?\MailSo\Cache\CacheClient $oCacher = null,
|
string $sSearch = '', int $iPrevUidNext = 0, ?\MailSo\Cache\CacheClient $oCacher = null,
|
||||||
bool $bUseSortIfSupported = false, bool $bUseThreadSortIfSupported = false,
|
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) ||
|
if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) ||
|
||||||
!\MailSo\Base\Validator::RangeInt($iLimit, 0, 999))
|
!\MailSo\Base\Validator::RangeInt($iLimit, 0, 999))
|
||||||
{
|
{
|
||||||
throw new \MailSo\Base\Exceptions\InvalidArgumentException;
|
throw new \MailSo\Base\Exceptions\InvalidArgumentException;
|
||||||
}
|
}
|
||||||
|
|
||||||
$bUseFilter = '' !== $sFilter;
|
$sSearch = \trim($sSearch);
|
||||||
|
|
||||||
|
list($iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($sFolderName);
|
||||||
|
|
||||||
$this->oImapClient->FolderSelect($sFolderName);
|
$this->oImapClient->FolderSelect($sFolderName);
|
||||||
|
|
||||||
|
|
@ -1561,7 +1002,6 @@ class MailClient
|
||||||
$oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter;
|
$oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter;
|
||||||
|
|
||||||
$aUids = array();
|
$aUids = array();
|
||||||
$mAllSortedUids = null;
|
|
||||||
$mAllThreads = null;
|
$mAllThreads = null;
|
||||||
|
|
||||||
$bUseSortIfSupported = $bUseSortIfSupported && $this->oImapClient->IsSupported('SORT');
|
$bUseSortIfSupported = $bUseSortIfSupported && $this->oImapClient->IsSupported('SORT');
|
||||||
|
|
@ -1579,13 +1019,6 @@ class MailClient
|
||||||
$oCacher = null;
|
$oCacher = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($sFolderName);
|
|
||||||
|
|
||||||
if ($bUseFilter)
|
|
||||||
{
|
|
||||||
$iMessageUnseenCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oMessageCollection->FolderHash = $this->GenerateFolderHash(
|
$oMessageCollection->FolderHash = $this->GenerateFolderHash(
|
||||||
$sFolderName, $iMessageRealCount, $iUidNext, $iHighestModSeq);
|
$sFolderName, $iMessageRealCount, $iUidNext, $iHighestModSeq);
|
||||||
|
|
||||||
|
|
@ -1609,55 +1042,36 @@ class MailClient
|
||||||
|
|
||||||
if (0 < $iMessageRealCount && !$bMessageListOptimization)
|
if (0 < $iMessageRealCount && !$bMessageListOptimization)
|
||||||
{
|
{
|
||||||
$mAllSortedUids = $this->GetUids($oCacher, '', $sFilter,
|
$aUids = $this->GetUids($oCacher, '',
|
||||||
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported, $sSort);
|
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported, $sSort);
|
||||||
|
|
||||||
$mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap(
|
$mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap(
|
||||||
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null;
|
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $oCacher) : null;
|
||||||
|
|
||||||
if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads))
|
if ($bUseThreadSortIfSupported && $mAllThreads) {
|
||||||
{
|
if (0 < $iThreadUid)
|
||||||
$iResultRootUid = 0;
|
|
||||||
|
|
||||||
if (isset($mAllThreads[$iThreadUid]))
|
|
||||||
{
|
{
|
||||||
$iResultRootUid = $iThreadUid;
|
// Only show the selected thread messages
|
||||||
if (\is_array($mAllThreads[$iThreadUid]))
|
foreach ($mAllThreads as $aMap) {
|
||||||
{
|
if (\in_array($iThreadUid, $aMap)) {
|
||||||
$aUids = $mAllThreads[$iThreadUid];
|
$aUids = \array_intersect($aUids, $aMap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach ($mAllThreads as $iRootUid => $mSubUids)
|
// $aUids = \array_diff($aUids, $mAllThreads);
|
||||||
{
|
|
||||||
if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids))
|
|
||||||
{
|
|
||||||
$iResultRootUid = $iRootUid;
|
|
||||||
$aUids = $mSubUids;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids))
|
|
||||||
{
|
|
||||||
\array_unshift($aUids, $iResultRootUid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ($bUseThreadSortIfSupported && \is_array($mAllThreads))
|
|
||||||
{
|
|
||||||
$aUids = \array_keys($mAllThreads);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$bUseThreadSortIfSupported = false;
|
$bUseThreadSortIfSupported = false;
|
||||||
$aUids = $mAllSortedUids;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\strlen($sSearch) && \is_array($aUids))
|
if (\strlen($sSearch) && \is_array($aUids))
|
||||||
{
|
{
|
||||||
$aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter,
|
$aSearchedUids = $this->GetUids($oCacher, $sSearch,
|
||||||
$oMessageCollection->FolderName, $oMessageCollection->FolderHash);
|
$oMessageCollection->FolderName, $oMessageCollection->FolderHash);
|
||||||
|
|
||||||
if (\count($aSearchedUids))
|
if (\count($aSearchedUids))
|
||||||
|
|
@ -1719,9 +1133,9 @@ class MailClient
|
||||||
$oMessageCollection->MessageCount = $iMessageRealCount;
|
$oMessageCollection->MessageCount = $iMessageRealCount;
|
||||||
$oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
|
$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);
|
$oMessageCollection->FolderName, $oMessageCollection->FolderHash);
|
||||||
|
|
||||||
if (\count($aUids))
|
if (\count($aUids))
|
||||||
|
|
@ -1742,7 +1156,7 @@ class MailClient
|
||||||
|
|
||||||
if (1 < $iMessageRealCount)
|
if (1 < $iMessageRealCount)
|
||||||
{
|
{
|
||||||
$aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit);
|
$aRequestIndexes = \array_slice(\array_reverse(\range(1, $iMessageRealCount)), $iOffset, $iLimit);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1798,8 +1212,12 @@ class MailClient
|
||||||
|
|
||||||
public function Folders(string $sParent, string $sListPattern, bool $bUseListSubscribeStatus, int $iOptimizationLimit, bool $bUseListStatus) : ?FolderCollection
|
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;
|
$aImapSubscribedFoldersHelper = null;
|
||||||
if ($this->oImapClient->IsSupported('LIST-EXTENDED')) {
|
if (\in_array('LIST-EXTENDED', $aCapabilities)) {
|
||||||
$bUseListSubscribeStatus = false;
|
$bUseListSubscribeStatus = false;
|
||||||
} else if ($bUseListSubscribeStatus) {
|
} else if ($bUseListSubscribeStatus) {
|
||||||
//\error_log('RFC5258 not supported, using LSUB');
|
//\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
|
$aFolders = $bUseListStatus
|
||||||
? $this->oImapClient->FolderStatusList($sParent, $sListPattern)
|
? $this->oImapClient->FolderStatusList($sParent, $sListPattern)
|
||||||
|
|
@ -1828,11 +1252,9 @@ class MailClient
|
||||||
}
|
}
|
||||||
|
|
||||||
$oFolderCollection = new FolderCollection;
|
$oFolderCollection = new FolderCollection;
|
||||||
$oFolderCollection->IsMetadataSupported = $this->oImapClient->IsSupported('METADATA');
|
|
||||||
$oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported();
|
$oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported();
|
||||||
$oFolderCollection->IsSortSupported = $this->oImapClient->IsSupported('SORT');
|
|
||||||
$oFolderCollection->IsListStatusSupported = $bUseListStatus;
|
|
||||||
$oFolderCollection->Optimized = 10 < $iOptimizationLimit && \count($aFolders) > $iOptimizationLimit;
|
$oFolderCollection->Optimized = 10 < $iOptimizationLimit && \count($aFolders) > $iOptimizationLimit;
|
||||||
|
$oFolderCollection->capabilities = $aCapabilities;
|
||||||
|
|
||||||
$sINBOX = 'INBOX';
|
$sINBOX = 'INBOX';
|
||||||
$aSortedByLenImapFolders = array();
|
$aSortedByLenImapFolders = array();
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ trait Folders
|
||||||
try {
|
try {
|
||||||
$aQuota = $this->MailClient()->Quota();
|
$aQuota = $this->MailClient()->Quota();
|
||||||
// $aQuota = $this->MailClient()->QuotaRoot();
|
// $aQuota = $this->MailClient()->QuotaRoot();
|
||||||
$oFolderCollection->quotaUsage = $aQuota[0] * 1024;
|
$oFolderCollection->quotaUsage = $aQuota ? $aQuota[0] * 1024 : null;
|
||||||
$oFolderCollection->quotaLimit = $aQuota[1] * 1024;
|
$oFolderCollection->quotaLimit = $aQuota ? $aQuota[1] * 1024 : null;
|
||||||
} catch (\Throwable $oException) {
|
} catch (\Throwable $oException) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +57,12 @@ trait Folders
|
||||||
$this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders);
|
$this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders);
|
||||||
$oFolderCollection->SystemFolders = $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))
|
if ($this->Config()->Get('labs', 'autocreate_system_folders', true))
|
||||||
{
|
{
|
||||||
$bDoItAgain = false;
|
$bDoItAgain = false;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ trait Messages
|
||||||
|
|
||||||
$sRawKey = $this->GetActionParam('RawKey', '');
|
$sRawKey = $this->GetActionParam('RawKey', '');
|
||||||
$aValues = $this->getDecodedClientRawKeyValue($sRawKey, 10);
|
$aValues = $this->getDecodedClientRawKeyValue($sRawKey, 10);
|
||||||
|
|
||||||
if ($aValues && 7 < \count($aValues))
|
if ($aValues && 7 < \count($aValues))
|
||||||
{
|
{
|
||||||
$sFolder = (string) $aValues[2];
|
$sFolder = (string) $aValues[2];
|
||||||
|
|
@ -63,7 +62,7 @@ trait Messages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 === strlen($sFolder))
|
if (!\strlen($sFolder))
|
||||||
{
|
{
|
||||||
throw new ClientException(Notifications::CantGetMessageList);
|
throw new ClientException(Notifications::CantGetMessageList);
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +82,6 @@ trait Messages
|
||||||
!!$this->Config()->Get('labs', 'use_imap_sort', true),
|
!!$this->Config()->Get('labs', 'use_imap_sort', true),
|
||||||
$bUseThreads,
|
$bUseThreads,
|
||||||
$iThreadUid,
|
$iThreadUid,
|
||||||
'',
|
|
||||||
$sSort
|
$sSort
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +106,7 @@ trait Messages
|
||||||
$iMessageUid = $this->GetActionParam('MessageUid', 0);
|
$iMessageUid = $this->GetActionParam('MessageUid', 0);
|
||||||
|
|
||||||
$sDraftFolder = $this->GetActionParam('SaveFolder', '');
|
$sDraftFolder = $this->GetActionParam('SaveFolder', '');
|
||||||
if (0 === strlen($sDraftFolder))
|
if (!\strlen($sDraftFolder))
|
||||||
{
|
{
|
||||||
throw new ClientException(Notifications::UnknownError);
|
throw new ClientException(Notifications::UnknownError);
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +142,7 @@ trait Messages
|
||||||
|
|
||||||
$mResult = true;
|
$mResult = true;
|
||||||
|
|
||||||
if (0 < strlen($sMessageFolder) && 0 < $iMessageUid)
|
if (\strlen($sMessageFolder) && 0 < $iMessageUid)
|
||||||
{
|
{
|
||||||
$this->MailClient()->MessageDelete($sMessageFolder, array($iMessageUid), true, true);
|
$this->MailClient()->MessageDelete($sMessageFolder, array($iMessageUid), true, true);
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +207,7 @@ trait Messages
|
||||||
break;
|
break;
|
||||||
case 'forward':
|
case 'forward':
|
||||||
$sForwardedFlag = $this->Config()->Get('labs', 'imap_forwarded_flag', '');
|
$sForwardedFlag = $this->Config()->Get('labs', 'imap_forwarded_flag', '');
|
||||||
if (0 < strlen($sForwardedFlag))
|
if (\strlen($sForwardedFlag))
|
||||||
{
|
{
|
||||||
$this->MailClient()->MessageSetFlag($sDraftInfoFolder, array($sDraftInfoUid), true,
|
$this->MailClient()->MessageSetFlag($sDraftInfoFolder, array($sDraftInfoUid), true,
|
||||||
$sForwardedFlag, true);
|
$sForwardedFlag, true);
|
||||||
|
|
@ -223,7 +221,7 @@ trait Messages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 < \strlen($sSentFolder))
|
if (\strlen($sSentFolder))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -277,7 +275,7 @@ trait Messages
|
||||||
|
|
||||||
$this->deleteMessageAttachmnets($oAccount);
|
$this->deleteMessageAttachmnets($oAccount);
|
||||||
|
|
||||||
if (0 < \strlen($sDraftFolder) && 0 < $iDraftUid)
|
if (\strlen($sDraftFolder) && 0 < $iDraftUid)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -377,7 +375,7 @@ trait Messages
|
||||||
|
|
||||||
$this->Cacher($oAccount)->Set(\RainLoop\KeyPathHelper::ReadReceiptCache($oAccount->Email(), $sFolderFullName, $iUid), '1');
|
$this->Cacher($oAccount)->Set(\RainLoop\KeyPathHelper::ReadReceiptCache($oAccount->Email(), $sFolderFullName, $iUid), '1');
|
||||||
|
|
||||||
if (0 < \strlen($sFolderFullName) && 0 < $iUid)
|
if (\strlen($sFolderFullName) && 0 < $iUid)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -1044,12 +1042,12 @@ trait Messages
|
||||||
$oMessage->SetDraftInfo($aDraftInfo[0], $aDraftInfo[1], $aDraftInfo[2]);
|
$oMessage->SetDraftInfo($aDraftInfo[0], $aDraftInfo[1], $aDraftInfo[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 < \strlen($sInReplyTo))
|
if (\strlen($sInReplyTo))
|
||||||
{
|
{
|
||||||
$oMessage->SetInReplyTo($sInReplyTo);
|
$oMessage->SetInReplyTo($sInReplyTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 < \strlen($sReferences))
|
if (\strlen($sReferences))
|
||||||
{
|
{
|
||||||
$oMessage->SetReferences($sReferences);
|
$oMessage->SetReferences($sReferences);
|
||||||
}
|
}
|
||||||
|
|
@ -1064,7 +1062,7 @@ trait Messages
|
||||||
$this->Plugins()->RunHook($bTextIsHtml ? 'filter.message-html' : 'filter.message-plain',
|
$this->Plugins()->RunHook($bTextIsHtml ? 'filter.message-html' : 'filter.message-plain',
|
||||||
array($oAccount, $oMessage, &$sTextToAdd));
|
array($oAccount, $oMessage, &$sTextToAdd));
|
||||||
|
|
||||||
if ($bTextIsHtml && 0 < \strlen($sTextToAdd))
|
if ($bTextIsHtml && \strlen($sTextToAdd))
|
||||||
{
|
{
|
||||||
$sTextConverted = \MailSo\Base\HtmlUtils::ConvertHtmlToPlain($sTextToAdd);
|
$sTextConverted = \MailSo\Base\HtmlUtils::ConvertHtmlToPlain($sTextToAdd);
|
||||||
$this->Plugins()->RunHook('filter.message-plain', array($oAccount, $oMessage, &$sTextConverted));
|
$this->Plugins()->RunHook('filter.message-plain', array($oAccount, $oMessage, &$sTextConverted));
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "منذ شهر",
|
"LABEL_ADV_DATE_MONTH": "منذ شهر",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "منذ 3 أشهر",
|
"LABEL_ADV_DATE_3_MONTHS": "منذ 3 أشهر",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "منذ 6 أشهر",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "إعداد افتراضي لوضع ملء الشاشة",
|
"FULLSCREEN": "إعداد افتراضي لوضع ملء الشاشة",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "До 1 месец",
|
"LABEL_ADV_DATE_MONTH": "До 1 месец",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "До 3 месеца",
|
"LABEL_ADV_DATE_3_MONTHS": "До 3 месеца",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "До 6 месеца",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "На цял екран",
|
"FULLSCREEN": "На цял екран",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Ne starší než měsíc",
|
"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_3_MONTHS": "Ne starší než 3 měsíce",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Ne starší než 6 měsíců",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Celá obrazovka",
|
"FULLSCREEN": "Celá obrazovka",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Nyere end 1 måned",
|
"LABEL_ADV_DATE_MONTH": "Nyere end 1 måned",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Nyere end 3 måneder",
|
"LABEL_ADV_DATE_3_MONTHS": "Nyere end 3 måneder",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Nyere end 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Fuld skærm",
|
"FULLSCREEN": "Fuld skærm",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Nicht älter als 1 Monat",
|
"LABEL_ADV_DATE_MONTH": "Nicht älter als 1 Monat",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Nicht älter als 3 Monate",
|
"LABEL_ADV_DATE_3_MONTHS": "Nicht älter als 3 Monate",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Nicht älter als 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Vollbild umschalten",
|
"FULLSCREEN": "Vollbild umschalten",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Έως 1 μήνα πριν",
|
"LABEL_ADV_DATE_MONTH": "Έως 1 μήνα πριν",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Έως 3 μήνες πριν",
|
"LABEL_ADV_DATE_3_MONTHS": "Έως 3 μήνες πριν",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Έως 6 μήνες πριν",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Ενναλαγή πλήρους οθόνης",
|
"FULLSCREEN": "Ενναλαγή πλήρους οθόνης",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Up to 1 month old",
|
"LABEL_ADV_DATE_MONTH": "Up to 1 month old",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Up to 3 months old",
|
"LABEL_ADV_DATE_3_MONTHS": "Up to 3 months old",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Up to 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Toggle fullscreen",
|
"FULLSCREEN": "Toggle fullscreen",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Hasta 1 mes de antigüedad",
|
"LABEL_ADV_DATE_MONTH": "Hasta 1 mes de antigüedad",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Hasta 3 meses 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_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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Cambiar a pantalla completa",
|
"FULLSCREEN": "Cambiar a pantalla completa",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Kuni 1 kuu vanune",
|
"LABEL_ADV_DATE_MONTH": "Kuni 1 kuu vanune",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Kuni 3 kuu vanune ",
|
"LABEL_ADV_DATE_3_MONTHS": "Kuni 3 kuu vanune ",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Kuni 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Täisekraan sisse\/välja",
|
"FULLSCREEN": "Täisekraan sisse\/välja",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "تا 1 ماه گذشته",
|
"LABEL_ADV_DATE_MONTH": "تا 1 ماه گذشته",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "تا 3 ماه گذشته",
|
"LABEL_ADV_DATE_3_MONTHS": "تا 3 ماه گذشته",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "تا 6 ماه گذشته",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "ضامن تمام صفحه",
|
"FULLSCREEN": "ضامن تمام صفحه",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "1 kk ajalta",
|
"LABEL_ADV_DATE_MONTH": "1 kk ajalta",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "3 kk ajalta",
|
"LABEL_ADV_DATE_3_MONTHS": "3 kk ajalta",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Koko ruutu",
|
"FULLSCREEN": "Koko ruutu",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Jusqu'à 1 mois",
|
"LABEL_ADV_DATE_MONTH": "Jusqu'à 1 mois",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Jusqu'à 3 mois",
|
"LABEL_ADV_DATE_3_MONTHS": "Jusqu'à 3 mois",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Jusqu'à 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Basculer en plein écran",
|
"FULLSCREEN": "Basculer en plein écran",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Legfeljebb 1 hónapos",
|
"LABEL_ADV_DATE_MONTH": "Legfeljebb 1 hónapos",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Legfeljebb 3 hónapos",
|
"LABEL_ADV_DATE_3_MONTHS": "Legfeljebb 3 hónapos",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Legfeljebb 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Teljes képernyő váltása",
|
"FULLSCREEN": "Teljes képernyő váltása",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Lebih dari 1 bulan lalu",
|
"LABEL_ADV_DATE_MONTH": "Lebih dari 1 bulan lalu",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Lebih dari 3 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_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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Beralih ke layar penuh",
|
"FULLSCREEN": "Beralih ke layar penuh",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Allt að mánaðar gömlu",
|
"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_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_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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Víxla heilskjá af\/á",
|
"FULLSCREEN": "Víxla heilskjá af\/á",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Meno di un mese fa",
|
"LABEL_ADV_DATE_MONTH": "Meno di un mese fa",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Meno di 3 mesi fa",
|
"LABEL_ADV_DATE_3_MONTHS": "Meno di 3 mesi fa",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Meno di 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Passa a schermo intero",
|
"FULLSCREEN": "Passa a schermo intero",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "1ヶ月前まで",
|
"LABEL_ADV_DATE_MONTH": "1ヶ月前まで",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "3ヶ月前まで",
|
"LABEL_ADV_DATE_3_MONTHS": "3ヶ月前まで",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "6ヶ月前まで",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "フルスクリーン",
|
"FULLSCREEN": "フルスクリーン",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "1개월 이내",
|
"LABEL_ADV_DATE_MONTH": "1개월 이내",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "3개월 이내",
|
"LABEL_ADV_DATE_3_MONTHS": "3개월 이내",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "6개월 이내",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "전체화면으로 보기",
|
"FULLSCREEN": "전체화면으로 보기",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Nesenesni kaip 1 mėnesio",
|
"LABEL_ADV_DATE_MONTH": "Nesenesni kaip 1 mėnesio",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Nesenesni kaip 3 mėnesių",
|
"LABEL_ADV_DATE_3_MONTHS": "Nesenesni kaip 3 mėnesių",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Nesenesni kaip 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Perjungti viso ekrano režimą",
|
"FULLSCREEN": "Perjungti viso ekrano režimą",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Līdz 1 mēnesi vecs",
|
"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_3_MONTHS": "Līdz 3 mēnešus vecs",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Līdz 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Toggle fullscreen",
|
"FULLSCREEN": "Toggle fullscreen",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Inntil 1 måned gamle",
|
"LABEL_ADV_DATE_MONTH": "Inntil 1 måned gamle",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Inntil 3 måneder gamle",
|
"LABEL_ADV_DATE_3_MONTHS": "Inntil 3 måneder gamle",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Inntil 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Toggle fullscreen",
|
"FULLSCREEN": "Toggle fullscreen",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Tot 1 maand oud",
|
"LABEL_ADV_DATE_MONTH": "Tot 1 maand oud",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Tot 3 maanden oud",
|
"LABEL_ADV_DATE_3_MONTHS": "Tot 3 maanden oud",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Tot 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Schakel volledig scherm in\/uit",
|
"FULLSCREEN": "Schakel volledig scherm in\/uit",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "do miesiąca",
|
"LABEL_ADV_DATE_MONTH": "do miesiąca",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "do 3 miesięcy",
|
"LABEL_ADV_DATE_3_MONTHS": "do 3 miesięcy",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "do 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Pełny ekran",
|
"FULLSCREEN": "Pełny ekran",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Até 1 mês atrás",
|
"LABEL_ADV_DATE_MONTH": "Até 1 mês atrás",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Até 3 meses 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_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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Em tela cheia",
|
"FULLSCREEN": "Em tela cheia",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Até 1 mês atrás",
|
"LABEL_ADV_DATE_MONTH": "Até 1 mês atrás",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Até 3 meses 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_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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Alternar ecrã-inteiro",
|
"FULLSCREEN": "Alternar ecrã-inteiro",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "în această lună",
|
"LABEL_ADV_DATE_MONTH": "în această lună",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "3 luni",
|
"LABEL_ADV_DATE_3_MONTHS": "3 luni",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Toggle fullscreen",
|
"FULLSCREEN": "Toggle fullscreen",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "За месяц",
|
"LABEL_ADV_DATE_MONTH": "За месяц",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "За 3 месяца",
|
"LABEL_ADV_DATE_3_MONTHS": "За 3 месяца",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "За полгода",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Полный экран",
|
"FULLSCREEN": "Полный экран",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Nie staršie ako mesiac",
|
"LABEL_ADV_DATE_MONTH": "Nie staršie ako mesiac",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Nie staršie ako 3 mesiace",
|
"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_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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Prepnúť na celú obrazovku",
|
"FULLSCREEN": "Prepnúť na celú obrazovku",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Do 1 meseca nazaj",
|
"LABEL_ADV_DATE_MONTH": "Do 1 meseca nazaj",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Do 3 mesecev nazaj",
|
"LABEL_ADV_DATE_3_MONTHS": "Do 3 mesecev nazaj",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "Do 6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Preklopi celozaslonski pogled",
|
"FULLSCREEN": "Preklopi celozaslonski pogled",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "Upp till 1 månad gammalt",
|
"LABEL_ADV_DATE_MONTH": "Upp till 1 månad gammalt",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "Upp till 3 månader 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_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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Växla fullskärmsläge",
|
"FULLSCREEN": "Växla fullskärmsläge",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "1 ay önceki",
|
"LABEL_ADV_DATE_MONTH": "1 ay önceki",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "3 ay önceki",
|
"LABEL_ADV_DATE_3_MONTHS": "3 ay önceki",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "6 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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Toggle fullscreen",
|
"FULLSCREEN": "Toggle fullscreen",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "За місяць",
|
"LABEL_ADV_DATE_MONTH": "За місяць",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "За 3 місяці",
|
"LABEL_ADV_DATE_3_MONTHS": "За 3 місяці",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "За півроку",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Toggle fullscreen",
|
"FULLSCREEN": "Toggle fullscreen",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "1个月以内",
|
"LABEL_ADV_DATE_MONTH": "1个月以内",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "3个月以内",
|
"LABEL_ADV_DATE_3_MONTHS": "3个月以内",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "半年以内",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "切换全屏",
|
"FULLSCREEN": "切换全屏",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@
|
||||||
"LABEL_ADV_DATE_MONTH": "1月以內",
|
"LABEL_ADV_DATE_MONTH": "1月以內",
|
||||||
"LABEL_ADV_DATE_3_MONTHS": "3月以內",
|
"LABEL_ADV_DATE_3_MONTHS": "3月以內",
|
||||||
"LABEL_ADV_DATE_6_MONTHS": "半年以內",
|
"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": {
|
"PREVIEW_POPUP": {
|
||||||
"FULLSCREEN": "Toggle fullscreen",
|
"FULLSCREEN": "Toggle fullscreen",
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,20 @@
|
||||||
}
|
}
|
||||||
}"></div>
|
}"></div>
|
||||||
</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">
|
<div class="control-group">
|
||||||
<label class="control-label">
|
<label class="control-label">
|
||||||
</label>
|
</label>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue