mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Merge branch 'master' of https://github.com/cm-schl/snappymail
This commit is contained in:
commit
f10f93fd8f
18 changed files with 137 additions and 128 deletions
|
|
@ -62,7 +62,7 @@ export const
|
||||||
* @returns {?FolderModel}
|
* @returns {?FolderModel}
|
||||||
*/
|
*/
|
||||||
getFolderFromCacheList = folderFullName =>
|
getFolderFromCacheList = folderFullName =>
|
||||||
FOLDERS_CACHE[folderFullName] ? FOLDERS_CACHE[folderFullName] : null,
|
FOLDERS_CACHE[folderFullName] || null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullName
|
* @param {string} folderFullName
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
import { getNotification } from 'Common/Translator';
|
import { getNotification } from 'Common/Translator';
|
||||||
import { Settings, } from 'Common/Globals';
|
import { Settings } from 'Common/Globals';
|
||||||
import { serverRequest } from 'Common/Links';
|
import { serverRequest } from 'Common/Links';
|
||||||
|
|
||||||
import Remote from 'Remote/User/Fetch';
|
import Remote from 'Remote/User/Fetch';
|
||||||
|
|
@ -27,37 +27,6 @@ sortFolders = folders => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {?Function} fCallback
|
|
||||||
* @param {string} folder
|
|
||||||
* @param {Array=} list = []
|
|
||||||
*/
|
|
||||||
fetchFolderInformation = (fCallback, folder, list = []) => {
|
|
||||||
let fetch = !arrayLength(list);
|
|
||||||
const uids = [],
|
|
||||||
folderFromCache = getFolderFromCacheList(folder);
|
|
||||||
|
|
||||||
if (!fetch) {
|
|
||||||
list.forEach(messageListItem => {
|
|
||||||
MessageFlagsCache.getFor(folder, messageListItem.uid) || uids.push(messageListItem.uid);
|
|
||||||
messageListItem.threads.forEach(uid => {
|
|
||||||
MessageFlagsCache.getFor(folder, uid) || uids.push(uid);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
fetch = uids.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fetch) {
|
|
||||||
Remote.request('FolderInformation', fCallback, {
|
|
||||||
Folder: folder,
|
|
||||||
FlagsUids: uids,
|
|
||||||
UidNext: folderFromCache?.uidNext || 0 // Used to check for new messages
|
|
||||||
});
|
|
||||||
} else if (SettingsUserStore.useThreads()) {
|
|
||||||
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array=} aDisabled
|
* @param {Array=} aDisabled
|
||||||
* @param {Array=} aHeaderLines
|
* @param {Array=} aHeaderLines
|
||||||
|
|
@ -127,8 +96,22 @@ refreshFoldersInterval = 300000,
|
||||||
*/
|
*/
|
||||||
folderInformation = (folder, list) => {
|
folderInformation = (folder, list) => {
|
||||||
if (folder?.trim()) {
|
if (folder?.trim()) {
|
||||||
fetchFolderInformation(
|
let fetch = !arrayLength(list);
|
||||||
(iError, data) => {
|
const uids = [],
|
||||||
|
folderFromCache = getFolderFromCacheList(folder);
|
||||||
|
|
||||||
|
if (!fetch) {
|
||||||
|
list.forEach(messageListItem => {
|
||||||
|
MessageFlagsCache.getFor(folder, messageListItem.uid) || uids.push(messageListItem.uid);
|
||||||
|
messageListItem.threads.forEach(uid => {
|
||||||
|
MessageFlagsCache.getFor(folder, uid) || uids.push(uid);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
fetch = uids.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fetch) {
|
||||||
|
Remote.request('FolderInformation', (iError, data) => {
|
||||||
if (!iError && data.Result) {
|
if (!iError && data.Result) {
|
||||||
const result = data.Result,
|
const result = data.Result,
|
||||||
folderFromCache = getFolderFromCacheList(result.Folder);
|
folderFromCache = getFolderFromCacheList(result.Folder);
|
||||||
|
|
@ -159,15 +142,20 @@ folderInformation = (folder, list) => {
|
||||||
if (folderFromCache.fullName === FolderUserStore.currentFolderFullName()) {
|
if (folderFromCache.fullName === FolderUserStore.currentFolderFullName()) {
|
||||||
MessagelistUserStore.reload();
|
MessagelistUserStore.reload();
|
||||||
} else if (getFolderInboxName() === folderFromCache.fullName) {
|
} else if (getFolderInboxName() === folderFromCache.fullName) {
|
||||||
Remote.messageList(null, {Folder: getFolderInboxName()}, true);
|
// Remote.messageList(null, {folder: getFolderFromCacheList(getFolderInboxName())}, true);
|
||||||
|
Remote.messageList(null, {folder: getFolderInboxName()}, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}, {
|
||||||
folder,
|
Folder: folder,
|
||||||
list
|
FlagsUids: uids,
|
||||||
);
|
UidNext: folderFromCache?.uidNext || 0 // Used to check for new messages
|
||||||
|
});
|
||||||
|
} else if (SettingsUserStore.useThreads()) {
|
||||||
|
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,11 +130,6 @@ export class AbstractFetchRemote
|
||||||
sGetAdd ? null : (params || {}),
|
sGetAdd ? null : (params || {}),
|
||||||
undefined === iTimeout ? 30000 : pInt(iTimeout),
|
undefined === iTimeout ? 30000 : pInt(iTimeout),
|
||||||
data => {
|
data => {
|
||||||
let cached = false;
|
|
||||||
if (data?.Time) {
|
|
||||||
cached = pInt(data.Time) > Date.now() - start;
|
|
||||||
}
|
|
||||||
|
|
||||||
let iError = 0;
|
let iError = 0;
|
||||||
if (sAction && oRequests[sAction]) {
|
if (sAction && oRequests[sAction]) {
|
||||||
abort(sAction, 0, 1);
|
abort(sAction, 0, 1);
|
||||||
|
|
@ -157,9 +152,12 @@ export class AbstractFetchRemote
|
||||||
fCallback && fCallback(
|
fCallback && fCallback(
|
||||||
iError,
|
iError,
|
||||||
data,
|
data,
|
||||||
cached,
|
/**
|
||||||
sAction,
|
* Responses like "304 Not Modified" are returned as "200 OK"
|
||||||
params
|
* This is an attempt to detect if the request comes from cache.
|
||||||
|
* But when client has wrong date/time, it will fail.
|
||||||
|
*/
|
||||||
|
data?.epoch && data.epoch < Math.floor(start / 1000) - 60
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -203,8 +201,8 @@ export class AbstractFetchRemote
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
let isCached = false, type = '';
|
let isCached = false, type = '';
|
||||||
if (data?.Time) {
|
if (data?.epoch) {
|
||||||
isCached = pInt(data.Time) > microtime() - start;
|
isCached = data.epoch > microtime() - start;
|
||||||
}
|
}
|
||||||
// backward capability
|
// backward capability
|
||||||
switch (true) {
|
switch (true) {
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
||||||
*/
|
*/
|
||||||
messageList(fCallback, params, bSilent = false) {
|
messageList(fCallback, params, bSilent = false) {
|
||||||
const
|
const
|
||||||
sFolderFullName = pString(params.Folder),
|
// folder = getFolderFromCacheList(params.folder.fullName),
|
||||||
folder = getFolderFromCacheList(sFolderFullName),
|
folder = getFolderFromCacheList(params.folder),
|
||||||
folderHash = folder?.hash || '';
|
folderHash = folder?.hash || '';
|
||||||
|
|
||||||
params = Object.assign({
|
params = Object.assign({
|
||||||
|
|
@ -31,10 +31,8 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
||||||
limit: SettingsUserStore.messagesPerPage(),
|
limit: SettingsUserStore.messagesPerPage(),
|
||||||
search: '',
|
search: '',
|
||||||
uidNext: folder?.uidNext || 0, // Used to check for new messages
|
uidNext: folder?.uidNext || 0, // Used to check for new messages
|
||||||
sort: FolderUserStore.sortMode(),
|
sort: FolderUserStore.sortMode()
|
||||||
Hash: folderHash + SettingsGet('AccountHash')
|
|
||||||
}, params);
|
}, params);
|
||||||
params.Folder = sFolderFullName;
|
|
||||||
if (AppUserStore.threadsAllowed() && SettingsUserStore.useThreads()) {
|
if (AppUserStore.threadsAllowed() && SettingsUserStore.useThreads()) {
|
||||||
params.useThreads = 1;
|
params.useThreads = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -42,12 +40,9 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
||||||
}
|
}
|
||||||
|
|
||||||
let sGetAdd = '';
|
let sGetAdd = '';
|
||||||
|
if (folderHash) {
|
||||||
if (folderHash && (!params.search || !params.search.includes('is:'))) {
|
params.hash = folderHash + '-' + SettingsGet('AccountHash');
|
||||||
sGetAdd = 'MessageList/' +
|
sGetAdd = 'MessageList/' + SUB_QUERY_PREFIX + '/' + b64EncodeJSONSafe(params);
|
||||||
SUB_QUERY_PREFIX +
|
|
||||||
'/' +
|
|
||||||
b64EncodeJSONSafe(params);
|
|
||||||
params = {};
|
params = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,8 @@ MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrentFolderCach
|
||||||
MessagelistUserStore.loading(false);
|
MessagelistUserStore.loading(false);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Folder: FolderUserStore.currentFolderFullName(),
|
// folder: FolderUserStore.currentFolder() ? self.currentFolder().fullName : ''),
|
||||||
|
folder: FolderUserStore.currentFolderFullName(),
|
||||||
offset: iOffset,
|
offset: iOffset,
|
||||||
limit: SettingsUserStore.messagesPerPage(),
|
limit: SettingsUserStore.messagesPerPage(),
|
||||||
search: MessagelistUserStore.listSearch(),
|
search: MessagelistUserStore.listSearch(),
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ dialog:not(.animate) {
|
||||||
*/
|
*/
|
||||||
.rl-mobile dialog {
|
.rl-mobile dialog {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-height: calc(100vh - 86px);
|
/* max-height: calc(100vh - 86px);*/
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,15 @@ export class DomainPopupView extends AbstractViewPopup {
|
||||||
createOrAddCommand() {
|
createOrAddCommand() {
|
||||||
this.saving(true);
|
this.saving(true);
|
||||||
Remote.request('AdminDomainSave',
|
Remote.request('AdminDomainSave',
|
||||||
this.onDomainCreateOrSaveResponse.bind(this),
|
iError => {
|
||||||
|
this.saving(false);
|
||||||
|
if (iError) {
|
||||||
|
this.savingError(getNotification(iError));
|
||||||
|
} else {
|
||||||
|
DomainAdminStore.fetch();
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
Object.assign(domainToParams(this), {
|
Object.assign(domainToParams(this), {
|
||||||
Create: this.edit() ? 0 : 1
|
Create: this.edit() ? 0 : 1
|
||||||
})
|
})
|
||||||
|
|
@ -263,16 +271,6 @@ export class DomainPopupView extends AbstractViewPopup {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onDomainCreateOrSaveResponse(iError) {
|
|
||||||
this.saving(false);
|
|
||||||
if (iError) {
|
|
||||||
this.savingError(getNotification(iError));
|
|
||||||
} else {
|
|
||||||
DomainAdminStore.fetch();
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearTesting() {
|
clearTesting() {
|
||||||
this.testing(false);
|
this.testing(false);
|
||||||
this.testingDone(false);
|
this.testingDone(false);
|
||||||
|
|
|
||||||
24
dev/sieve.js
24
dev/sieve.js
|
|
@ -55,13 +55,11 @@ window.Sieve = {
|
||||||
deleteScript: script => {
|
deleteScript: script => {
|
||||||
serverError(false);
|
serverError(false);
|
||||||
Remote.request('FiltersScriptDelete',
|
Remote.request('FiltersScriptDelete',
|
||||||
(iError, data) => {
|
(iError, data) =>
|
||||||
if (iError) {
|
iError
|
||||||
setError(data?.ErrorMessageAdditional || getNotification(iError));
|
? setError(data?.ErrorMessageAdditional || getNotification(iError))
|
||||||
} else {
|
: scripts.remove(script)
|
||||||
scripts.remove(script);
|
,
|
||||||
}
|
|
||||||
},
|
|
||||||
{name:script.name()}
|
{name:script.name()}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -69,13 +67,11 @@ window.Sieve = {
|
||||||
setActiveScript(name) {
|
setActiveScript(name) {
|
||||||
serverError(false);
|
serverError(false);
|
||||||
Remote.request('FiltersScriptActivate',
|
Remote.request('FiltersScriptActivate',
|
||||||
(iError, data) => {
|
(iError, data) =>
|
||||||
if (iError) {
|
iError
|
||||||
setError(data?.ErrorMessageAdditional || iError)
|
? setError(data?.ErrorMessageAdditional || iError)
|
||||||
} else {
|
: scripts.forEach(script => script.active(script.name() === name))
|
||||||
scripts.forEach(script => script.active(script.name() === name));
|
,
|
||||||
}
|
|
||||||
},
|
|
||||||
{name:name}
|
{name:name}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
NAME = 'reCaptcha',
|
NAME = 'reCaptcha',
|
||||||
AUTHOR = 'SnappyMail',
|
AUTHOR = 'SnappyMail',
|
||||||
URL = 'https://snappymail.eu/',
|
URL = 'https://snappymail.eu/',
|
||||||
VERSION = '2.13',
|
VERSION = '2.14',
|
||||||
RELEASE = '2022-12-08',
|
RELEASE = '2023-01-11',
|
||||||
REQUIRED = '2.23',
|
REQUIRED = '2.23',
|
||||||
CATEGORY = 'General',
|
CATEGORY = 'General',
|
||||||
LICENSE = 'MIT',
|
LICENSE = 'MIT',
|
||||||
|
|
@ -141,10 +141,12 @@ class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
|
|
||||||
public function ContentSecurityPolicy(\SnappyMail\HTTP\CSP $CSP)
|
public function ContentSecurityPolicy(\SnappyMail\HTTP\CSP $CSP)
|
||||||
{
|
{
|
||||||
$CSP->script[] = 'https://www.google.com/recaptcha/';
|
// $CSP->script[] = 'https://www.google.com/recaptcha/';
|
||||||
$CSP->script[] = 'https://www.gstatic.com/recaptcha/';
|
$CSP->script[] = 'https://www.gstatic.com/recaptcha/';
|
||||||
$CSP->frame[] = 'https://www.google.com/recaptcha/';
|
$CSP->script[] = 'https://www.recaptcha.net/recaptcha/';
|
||||||
$CSP->frame[] = 'https://recaptcha.google.com/recaptcha/';
|
// $CSP->frame[] = 'https://www.google.com/recaptcha/';
|
||||||
|
// $CSP->frame[] = 'https://recaptcha.google.com/recaptcha/';
|
||||||
|
$CSP->frame[] = 'https://www.recaptcha.net/recaptcha/';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -582,11 +582,11 @@ class MailClient
|
||||||
$sSerializedHash = '';
|
$sSerializedHash = '';
|
||||||
$sSerializedLog = '';
|
$sSerializedLog = '';
|
||||||
if ($bUseCacheAfterSearch) {
|
if ($bUseCacheAfterSearch) {
|
||||||
$sSerializedHash = 'GetUids/'.
|
$sSerializedHash = 'Get'
|
||||||
($bUseSort ? 'S' . $sSort : 'N').'/'.
|
. ($bReturnUid ? 'UIDS/' : 'IDS/')
|
||||||
$this->oImapClient->Hash().'/'.
|
. ($bUseSort ? 'S' . $sSort : 'N')
|
||||||
$sFolderName.'/'.$sSearchCriterias;
|
. "/{$this->oImapClient->Hash()}/{$sFolderName}/{$sSearchCriterias}";
|
||||||
$sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
|
$sSerializedLog = "\"{$sFolderName}\" / {$sSort} / {$sSearchCriterias}";
|
||||||
|
|
||||||
$sSerialized = $oCacher->Get($sSerializedHash);
|
$sSerialized = $oCacher->Get($sSerializedHash);
|
||||||
if (!empty($sSerialized)) {
|
if (!empty($sSerialized)) {
|
||||||
|
|
@ -596,11 +596,9 @@ class MailClient
|
||||||
\is_array($aSerialized['Uids'])
|
\is_array($aSerialized['Uids'])
|
||||||
) {
|
) {
|
||||||
if ($this->oLogger) {
|
if ($this->oLogger) {
|
||||||
$this->oLogger->Write('Get Serialized UIDS from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']');
|
$this->oLogger->Write('Get Serialized '.($bReturnUid?'UIDS':'IDS').' from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']');
|
||||||
}
|
|
||||||
if (\is_array($aSerialized['Uids'])) {
|
|
||||||
return $aSerialized['Uids'];
|
|
||||||
}
|
}
|
||||||
|
return $aSerialized['Uids'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -631,7 +629,7 @@ class MailClient
|
||||||
)));
|
)));
|
||||||
|
|
||||||
if ($this->oLogger) {
|
if ($this->oLogger) {
|
||||||
$this->oLogger->Write('Save Serialized UIDS to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']');
|
$this->oLogger->Write('Save Serialized '.($bReturnUid?'UIDS':'IDS').' to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,4 +51,18 @@ class MessageListParams
|
||||||
// 0 > $oParams->iLimit
|
// 0 > $oParams->iLimit
|
||||||
// 999 < $oParams->iLimit
|
// 999 < $oParams->iLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hash() : string
|
||||||
|
{
|
||||||
|
return \md5(\implode('-', [
|
||||||
|
$this->sFolderName,
|
||||||
|
$this->iOffset,
|
||||||
|
$this->iLimit,
|
||||||
|
$this->bHideDeleted ? '1' : '0',
|
||||||
|
$this->sSearch,
|
||||||
|
$this->bUseSort ? $this->sSort : '',
|
||||||
|
$this->bUseThreads ? $this->iThreadUid : '',
|
||||||
|
$this->iPrevUidNext
|
||||||
|
]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ class Header
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.rfc-editor.org/rfc/rfc2822#section-2.1.1
|
// https://www.rfc-editor.org/rfc/rfc2822#section-2.1.1
|
||||||
return \wordwrap($this->NameWithDelimitrom() . $sValue, 78, "\r\n ");
|
return \wordwrap($this->NameWithDelimitrom() . $sResult, 78, "\r\n ");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function IsSubject() : bool
|
public function IsSubject() : bool
|
||||||
|
|
|
||||||
|
|
@ -408,6 +408,12 @@ class Actions
|
||||||
return $this->oMailClient;
|
return $this->oMailClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function ImapClient(): \MailSo\Imap\ImapClient
|
||||||
|
{
|
||||||
|
// $this->initMailClientConnection();
|
||||||
|
return $this->MailClient()->ImapClient();
|
||||||
|
}
|
||||||
|
|
||||||
// Stores data in AdditionalAccount else MainAccount
|
// Stores data in AdditionalAccount else MainAccount
|
||||||
public function LocalStorageProvider(): Providers\Storage
|
public function LocalStorageProvider(): Providers\Storage
|
||||||
{
|
{
|
||||||
|
|
@ -590,7 +596,7 @@ class Actions
|
||||||
{
|
{
|
||||||
$sLine = $this->oConfig->Get('logs', 'auth_logging_format', '');
|
$sLine = $this->oConfig->Get('logs', 'auth_logging_format', '');
|
||||||
if (!empty($sLine)) {
|
if (!empty($sLine)) {
|
||||||
$this->LoggerAuth()->Write($this->compileLogParams($sLine, $oAccount, false, $aAdditionalParams));
|
$this->LoggerAuth()->Write($this->compileLogParams($sLine, $oAccount, false, $aAdditionalParams), \LOG_WARNING);
|
||||||
}
|
}
|
||||||
if (($this->oConfig->Get('logs', 'auth_logging', false) || $this->oConfig->Get('logs', 'auth_syslog', false))
|
if (($this->oConfig->Get('logs', 'auth_logging', false) || $this->oConfig->Get('logs', 'auth_syslog', false))
|
||||||
&& \openlog('snappymail', 0, \LOG_AUTHPRIV)) {
|
&& \openlog('snappymail', 0, \LOG_AUTHPRIV)) {
|
||||||
|
|
@ -1066,9 +1072,9 @@ class Actions
|
||||||
return \md5($sKey . $this->oConfig->Get('cache', 'index', ''));
|
return \md5($sKey . $this->oConfig->Get('cache', 'index', ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function cacheByKey(string $sKey, bool $bForce = false): bool
|
public function cacheByKey(string $sKey): bool
|
||||||
{
|
{
|
||||||
if ($sKey && ($bForce || ($this->oConfig->Get('cache', 'enable', true) && $this->oConfig->Get('cache', 'http', true)))) {
|
if ($sKey && $this->oConfig->Get('cache', 'enable', true) && $this->oConfig->Get('cache', 'http', true)) {
|
||||||
\MailSo\Base\Http::ServerUseCache(
|
\MailSo\Base\Http::ServerUseCache(
|
||||||
$this->etag($sKey),
|
$this->etag($sKey),
|
||||||
1382478804,
|
1382478804,
|
||||||
|
|
@ -1080,11 +1086,11 @@ class Actions
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function verifyCacheByKey(string $sKey, bool $bForce = false): void
|
public function verifyCacheByKey(string $sKey): void
|
||||||
{
|
{
|
||||||
if ($sKey && ($bForce || ($this->oConfig->Get('cache', 'enable', true) && $this->oConfig->Get('cache', 'http', true)))) {
|
if ($sKey && $this->oConfig->Get('cache', 'enable', true) && $this->oConfig->Get('cache', 'http', true)) {
|
||||||
\MailSo\Base\Http::checkETag($this->etag($sKey));
|
\MailSo\Base\Http::checkETag($this->etag($sKey));
|
||||||
// $this->cacheByKey($sKey, $bForce);
|
// \MailSo\Base\Http::checkLastModified(1382478804);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace RainLoop\Actions;
|
||||||
|
|
||||||
use RainLoop\Enumerations\PluginPropertyType;
|
use RainLoop\Enumerations\PluginPropertyType;
|
||||||
use RainLoop\Exceptions\ClientException;
|
use RainLoop\Exceptions\ClientException;
|
||||||
|
use RainLoop\Notifications;
|
||||||
|
|
||||||
trait AdminExtensions
|
trait AdminExtensions
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,12 @@ trait Messages
|
||||||
$oParams = new \MailSo\Mail\MessageListParams;
|
$oParams = new \MailSo\Mail\MessageListParams;
|
||||||
|
|
||||||
$sRawKey = $this->GetActionParam('RawKey', '');
|
$sRawKey = $this->GetActionParam('RawKey', '');
|
||||||
$aValues = \json_decode(\MailSo\Base\Utils::UrlSafeBase64Decode($sRawKey), true);
|
$aValues = $sRawKey ? \json_decode(\MailSo\Base\Utils::UrlSafeBase64Decode($sRawKey), true) : null;
|
||||||
|
$sHash = '';
|
||||||
if ($aValues && 6 < \count($aValues)) {
|
if ($aValues && 6 < \count($aValues)) {
|
||||||
$this->verifyCacheByKey($sRawKey);
|
// GET
|
||||||
|
$sHash = (string) $aValues['hash'];
|
||||||
// $oParams->sHash = (string) $aValues['Hash'];
|
$oParams->sFolderName = (string) $aValues['folder'];
|
||||||
$oParams->sFolderName = (string) $aValues['Folder'];
|
|
||||||
$oParams->iLimit = $aValues['limit'];
|
$oParams->iLimit = $aValues['limit'];
|
||||||
$oParams->iOffset = $aValues['offset'];
|
$oParams->iOffset = $aValues['offset'];
|
||||||
$oParams->sSearch = (string) $aValues['search'];
|
$oParams->sSearch = (string) $aValues['search'];
|
||||||
|
|
@ -42,7 +42,8 @@ trait Messages
|
||||||
$oParams->iThreadUid = $aValues['threadUid'];
|
$oParams->iThreadUid = $aValues['threadUid'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$oParams->sFolderName = $this->GetActionParam('Folder', '');
|
// POST
|
||||||
|
$oParams->sFolderName = $this->GetActionParam('folder', '');
|
||||||
$oParams->iOffset = $this->GetActionParam('offset', 0);
|
$oParams->iOffset = $this->GetActionParam('offset', 0);
|
||||||
$oParams->iLimit = $this->GetActionParam('limit', 10);
|
$oParams->iLimit = $this->GetActionParam('limit', 10);
|
||||||
$oParams->sSearch = $this->GetActionParam('search', '');
|
$oParams->sSearch = $this->GetActionParam('search', '');
|
||||||
|
|
@ -60,6 +61,16 @@ trait Messages
|
||||||
|
|
||||||
$oAccount = $this->initMailClientConnection();
|
$oAccount = $this->initMailClientConnection();
|
||||||
|
|
||||||
|
if ($sHash) {
|
||||||
|
$oInfo = $this->ImapClient()->FolderStatusAndSelect($oParams->sFolderName);
|
||||||
|
$aRequestHash = \explode('-', $sHash);
|
||||||
|
$sFolderHash = $oInfo->getHash($this->ImapClient()->Hash());
|
||||||
|
$sHash = $oParams->hash() . '-' . $sFolderHash;
|
||||||
|
if ($aRequestHash[0] == $sFolderHash) {
|
||||||
|
$this->verifyCacheByKey($sHash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!$this->Config()->Get('imap', 'use_thread', true)) {
|
if (!$this->Config()->Get('imap', 'use_thread', true)) {
|
||||||
|
|
@ -75,17 +86,15 @@ trait Messages
|
||||||
}
|
}
|
||||||
|
|
||||||
$oMessageList = $this->MailClient()->MessageList($oParams);
|
$oMessageList = $this->MailClient()->MessageList($oParams);
|
||||||
|
if ($sHash) {
|
||||||
|
$this->cacheByKey($sHash);
|
||||||
|
}
|
||||||
|
return $this->DefaultResponse($oMessageList);
|
||||||
}
|
}
|
||||||
catch (\Throwable $oException)
|
catch (\Throwable $oException)
|
||||||
{
|
{
|
||||||
throw new ClientException(Notifications::CantGetMessageList, $oException);
|
throw new ClientException(Notifications::CantGetMessageList, $oException);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oMessageList) {
|
|
||||||
$this->cacheByKey($sRawKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->DefaultResponse($oMessageList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DoSaveMessage() : array
|
public function DoSaveMessage() : array
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace RainLoop\Plugins;
|
namespace RainLoop\Plugins;
|
||||||
|
|
||||||
use \RainLoop\Enumerations\PluginPropertyType;
|
use RainLoop\Enumerations\PluginPropertyType;
|
||||||
|
|
||||||
class Property implements \JsonSerializable
|
class Property implements \JsonSerializable
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace RainLoop\Providers\AddressBook\Classes;
|
namespace RainLoop\Providers\AddressBook\Classes;
|
||||||
|
|
||||||
use \Sabre\VObject\Component\VCard;
|
use Sabre\VObject\Component\VCard;
|
||||||
|
|
||||||
class Contact implements \JsonSerializable
|
class Contact implements \JsonSerializable
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -160,14 +160,17 @@ class ServiceActions
|
||||||
|
|
||||||
$aResponse['Action'] = $sAction ?: 'Unknown';
|
$aResponse['Action'] = $sAction ?: 'Unknown';
|
||||||
|
|
||||||
if (\is_array($aResponse)) {
|
|
||||||
$aResponse['Time'] = (int) ((\microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!\headers_sent()) {
|
if (!\headers_sent()) {
|
||||||
\header('Content-Type: application/json; charset=utf-8');
|
\header('Content-Type: application/json; charset=utf-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (\is_array($aResponse)) {
|
||||||
|
$aResponse['epoch'] = \time();
|
||||||
|
// if ($this->Config()->Get('debug', 'enable', false)) {
|
||||||
|
// $aResponse['rtime'] = \round(\microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], 3);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
$sResult = Utils::jsonEncode($aResponse);
|
$sResult = Utils::jsonEncode($aResponse);
|
||||||
|
|
||||||
$sObResult = \ob_get_clean();
|
$sObResult = \ob_get_clean();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue