mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-02-01 03:27:43 +08:00
Support RFC 6855 / RFC 5738 (UTF8)
This commit is contained in:
parent
c9a497eb9d
commit
299ec7faf8
25 changed files with 249 additions and 505 deletions
|
@ -299,8 +299,8 @@ class AppUser extends AbstractApp {
|
|||
}
|
||||
]);
|
||||
} else if (oMoveFolder) {
|
||||
this.messagesMoveHelper(sFromFolderFullNameRaw, oMoveFolder.fullNameRaw, aUidForRemove);
|
||||
MessageUserStore.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw);
|
||||
this.messagesMoveHelper(sFromFolderFullNameRaw, oMoveFolder.fullName, aUidForRemove);
|
||||
MessageUserStore.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,12 +317,12 @@ class AppUser extends AbstractApp {
|
|||
|
||||
if (oFromFolder && oToFolder) {
|
||||
if (undefined === bCopy ? false : !!bCopy) {
|
||||
this.messagesCopyHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove);
|
||||
this.messagesCopyHelper(oFromFolder.fullName, oToFolder.fullName, aUidForMove);
|
||||
} else {
|
||||
this.messagesMoveHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove);
|
||||
this.messagesMoveHelper(oFromFolder.fullName, oToFolder.fullName, aUidForMove);
|
||||
}
|
||||
|
||||
MessageUserStore.removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy);
|
||||
MessageUserStore.removeMessagesFromList(oFromFolder.fullName, aUidForMove, oToFolder.fullName, bCopy);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -487,12 +487,12 @@ class AppUser extends AbstractApp {
|
|||
folderFromCache.messageCountUnread(result.MessageUnseenCount);
|
||||
|
||||
if (unreadCountChange) {
|
||||
MessageFlagsCache.clearFolder(folderFromCache.fullNameRaw);
|
||||
MessageFlagsCache.clearFolder(folderFromCache.fullName);
|
||||
}
|
||||
|
||||
if (result.Flags.length) {
|
||||
result.Flags.forEach(flags =>
|
||||
MessageFlagsCache.storeByFolderAndUid(folderFromCache.fullNameRaw, flags.Uid.toString(), [
|
||||
MessageFlagsCache.storeByFolderAndUid(folderFromCache.fullName, flags.Uid.toString(), [
|
||||
!!flags.IsUnseen,
|
||||
!!flags.IsFlagged,
|
||||
!!flags.IsAnswered,
|
||||
|
@ -505,15 +505,15 @@ class AppUser extends AbstractApp {
|
|||
}
|
||||
|
||||
MessageUserStore.initUidNextAndNewMessages(
|
||||
folderFromCache.fullNameRaw,
|
||||
folderFromCache.fullName,
|
||||
result.UidNext,
|
||||
result.NewMessages
|
||||
);
|
||||
|
||||
if (!hash || unreadCountChange || result.Hash !== hash) {
|
||||
if (folderFromCache.fullNameRaw === FolderUserStore.currentFolderFullNameRaw()) {
|
||||
if (folderFromCache.fullName === FolderUserStore.currentFolderFullNameRaw()) {
|
||||
this.reloadMessageList();
|
||||
} else if (getFolderInboxName() === folderFromCache.fullNameRaw) {
|
||||
} else if (getFolderInboxName() === folderFromCache.fullName) {
|
||||
Remote.messageList(null, {Folder: getFolderInboxName()}, true);
|
||||
}
|
||||
}
|
||||
|
@ -551,17 +551,17 @@ class AppUser extends AbstractApp {
|
|||
folder.messageCountUnread(item.MessageUnseenCount);
|
||||
|
||||
if (unreadCountChange) {
|
||||
MessageFlagsCache.clearFolder(folder.fullNameRaw);
|
||||
MessageFlagsCache.clearFolder(folder.fullName);
|
||||
}
|
||||
|
||||
if (!hash || item.Hash !== hash) {
|
||||
if (folder.fullNameRaw === FolderUserStore.currentFolderFullNameRaw()) {
|
||||
if (folder.fullName === FolderUserStore.currentFolderFullNameRaw()) {
|
||||
this.reloadMessageList();
|
||||
}
|
||||
} else if (unreadCountChange
|
||||
&& folder.fullNameRaw === FolderUserStore.currentFolderFullNameRaw()
|
||||
&& folder.fullName === FolderUserStore.currentFolderFullNameRaw()
|
||||
&& MessageUserStore.list.length) {
|
||||
this.folderInformation(folder.fullNameRaw, MessageUserStore.list());
|
||||
this.folderInformation(folder.fullName, MessageUserStore.list());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -200,14 +200,14 @@ folderListOptionsBuilder = (
|
|||
folders.forEach(oItem => {
|
||||
if (showUnsubscribed || oItem.hasSubscriptions() || !oItem.exists) {
|
||||
aResult.push({
|
||||
id: oItem.fullNameRaw,
|
||||
id: oItem.fullName,
|
||||
name:
|
||||
sDeepPrefix.repeat(oItem.deep) +
|
||||
fRenameCallback(oItem),
|
||||
system: false,
|
||||
disabled: !bNoSelectSelectable && (
|
||||
!oItem.selectable() ||
|
||||
aDisabled.includes(oItem.fullNameRaw) ||
|
||||
aDisabled.includes(oItem.fullName) ||
|
||||
fDisableCallback(oItem))
|
||||
});
|
||||
}
|
||||
|
|
2
dev/External/User/ko.js
vendored
2
dev/External/User/ko.js
vendored
|
@ -145,7 +145,7 @@ ko.bindingHandlers.dropmessages = {
|
|||
if ('messages' === getDragAction(e) && ['move','copy'].includes(e.dataTransfer.effectAllowed)) {
|
||||
let data = dragData.data;
|
||||
if (folder && data && data.folder && isArray(data.uids)) {
|
||||
rl.app.moveMessagesToFolder(data.folder, data.uids, folder.fullNameRaw, data.copy && e.ctrlKey);
|
||||
rl.app.moveMessagesToFolder(data.folder, data.uids, folder.fullName, data.copy && e.ctrlKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -69,7 +69,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
}
|
||||
|
||||
return super.reviveFromJson(object, oFolder => {
|
||||
let oCacheFolder = Cache.getFolderFromCacheList(oFolder.FullNameRaw);
|
||||
let oCacheFolder = Cache.getFolderFromCacheList(oFolder.FullName);
|
||||
|
||||
if (oCacheFolder) {
|
||||
oFolder.SubFolders = FolderCollectionModel.reviveFromJson(oFolder.SubFolders);
|
||||
|
@ -79,14 +79,14 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
if (!oCacheFolder)
|
||||
return null;
|
||||
|
||||
if (1 == SystemFolders.indexOf(oFolder.FullNameRaw)) {
|
||||
if (1 == SystemFolders.indexOf(oFolder.FullName)) {
|
||||
oCacheFolder.type(FolderType.Inbox);
|
||||
Cache.setFolderInboxName(oFolder.FullNameRaw);
|
||||
Cache.setFolderInboxName(oFolder.FullName);
|
||||
}
|
||||
Cache.setFolder(oCacheFolder.fullNameHash, oFolder.FullNameRaw, oCacheFolder);
|
||||
Cache.setFolder(oCacheFolder.fullNameHash, oFolder.FullName, oCacheFolder);
|
||||
}
|
||||
|
||||
let type = SystemFolders.indexOf(oFolder.FullNameRaw);
|
||||
let type = SystemFolders.indexOf(oFolder.FullName);
|
||||
if (1 < type) {
|
||||
oCacheFolder.type(type);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
|
||||
if (oFolder.Extended) {
|
||||
if (oFolder.Extended.Hash) {
|
||||
Cache.setFolderHash(oCacheFolder.fullNameRaw, oFolder.Extended.Hash);
|
||||
Cache.setFolderHash(oCacheFolder.fullName, oFolder.Extended.Hash);
|
||||
}
|
||||
|
||||
if (null != oFolder.Extended.MessageCount) {
|
||||
|
@ -196,7 +196,6 @@ export class FolderModel extends AbstractModel {
|
|||
super();
|
||||
|
||||
this.fullName = '';
|
||||
this.fullNameRaw = '';
|
||||
this.fullNameHash = '';
|
||||
this.delimiter = '';
|
||||
this.namespace = '';
|
||||
|
@ -244,7 +243,7 @@ export class FolderModel extends AbstractModel {
|
|||
static reviveFromJson(json) {
|
||||
const folder = super.reviveFromJson(json);
|
||||
if (folder) {
|
||||
folder.deep = json.FullNameRaw.split(folder.delimiter).length - 1;
|
||||
folder.deep = json.FullName.split(folder.delimiter).length - 1;
|
||||
|
||||
let type = (folder.metadata[FolderMetadataKeys.KolabFolderType]
|
||||
|| folder.metadata[FolderMetadataKeys.KolabFolderTypeShared]
|
||||
|
|
|
@ -19,10 +19,19 @@ import { AbstractFetchRemote } from 'Remote/AbstractFetch';
|
|||
|
||||
import { FolderCollectionModel } from 'Model/FolderCollection';
|
||||
|
||||
const urlSafeJSON = data => btoa(JSON.stringify(data))
|
||||
// unescape(encodeURIComponent()) makes the UTF-16 DOMString to an UTF-8 string
|
||||
const urlSafeJSON = data => btoa(unescape(encodeURIComponent(JSON.stringify(data))))
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/, '');
|
||||
/* Withous deprecated 'unescape':
|
||||
const urlSafeJSON = data => btoa(encodeURIComponent(JSON.stringify(data)).replace(
|
||||
/%([0-9A-F]{2})/g, (match, p1) => String.fromCharCode('0x' + p1)
|
||||
))
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/, '');
|
||||
*/
|
||||
|
||||
class RemoteUserFetch extends AbstractFetchRemote {
|
||||
|
||||
|
|
|
@ -73,11 +73,11 @@ export class FoldersUserSettings /*extends AbstractViewSettings*/ {
|
|||
Local.set(ClientSideKeyName.FoldersLashHash, '');
|
||||
|
||||
rl.app.foldersPromisesActionHelper(
|
||||
Remote.folderRename(folder.fullNameRaw, nameToEdit),
|
||||
Remote.folderRename(folder.fullName, nameToEdit),
|
||||
Notification.CantRenameFolder
|
||||
);
|
||||
|
||||
removeFolderFromCacheList(folder.fullNameRaw);
|
||||
removeFolderFromCacheList(folder.fullName);
|
||||
|
||||
folder.name(nameToEdit);
|
||||
}
|
||||
|
@ -120,11 +120,11 @@ export class FoldersUserSettings /*extends AbstractViewSettings*/ {
|
|||
|
||||
// rl.app.foldersPromisesActionHelper
|
||||
Remote.abort('Folders')
|
||||
.folderDelete(folderToRemove.fullNameRaw)
|
||||
.folderDelete(folderToRemove.fullName)
|
||||
.then(
|
||||
() => {
|
||||
folderToRemove.selectable(false)
|
||||
removeFolderFromCacheList(folderToRemove.fullNameRaw);
|
||||
removeFolderFromCacheList(folderToRemove.fullName);
|
||||
FolderUserStore.folderList(FolderUserStore.folderList.filter(folder => folder !== folderToRemove));
|
||||
},
|
||||
error => {
|
||||
|
@ -143,20 +143,20 @@ export class FoldersUserSettings /*extends AbstractViewSettings*/ {
|
|||
toggleFolderKolabType(folder, event) {
|
||||
let type = event.target.value;
|
||||
// TODO: append '.default' ?
|
||||
Remote.folderSetMetadata(null, folder.fullNameRaw, FolderMetadataKeys.KolabFolderType, type);
|
||||
Remote.folderSetMetadata(null, folder.fullName, FolderMetadataKeys.KolabFolderType, type);
|
||||
folder.kolabType(type);
|
||||
}
|
||||
|
||||
toggleFolderSubscription(folder) {
|
||||
let subscribe = !folder.subscribed();
|
||||
Local.set(ClientSideKeyName.FoldersLashHash, '');
|
||||
Remote.folderSetSubscribe(null, folder.fullNameRaw, subscribe);
|
||||
Remote.folderSetSubscribe(null, folder.fullName, subscribe);
|
||||
folder.subscribed(subscribe);
|
||||
}
|
||||
|
||||
toggleFolderCheckable(folder) {
|
||||
let checkable = !folder.checkable();
|
||||
Remote.folderSetCheckable(null, folder.fullNameRaw, checkable);
|
||||
Remote.folderSetCheckable(null, folder.fullName, checkable);
|
||||
folder.checkable(checkable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ export const FolderUserStore = new class {
|
|||
|
||||
draftFolderNotEnabled: () => !self.draftFolder() || UNUSED_OPTION_VALUE === self.draftFolder(),
|
||||
|
||||
currentFolderFullNameRaw: () => (self.currentFolder() ? self.currentFolder().fullNameRaw : ''),
|
||||
currentFolderFullNameRaw: () => (self.currentFolder() ? self.currentFolder().fullName : ''),
|
||||
|
||||
currentFolderFullName: () => (self.currentFolder() ? self.currentFolder().fullName : ''),
|
||||
currentFolderFullNameHash: () => (self.currentFolder() ? self.currentFolder().fullNameHash : ''),
|
||||
|
@ -136,7 +136,7 @@ export const FolderUserStore = new class {
|
|||
timeout > folder.expires &&
|
||||
(folder.isSystemFolder() || (folder.subscribed() && (folder.checkable() || !bDisplaySpecSetting)))
|
||||
) {
|
||||
timeouts.push([folder.expires, folder.fullNameRaw]);
|
||||
timeouts.push([folder.expires, folder.fullName]);
|
||||
}
|
||||
|
||||
if (folder && folder.subFolders.length) {
|
||||
|
|
|
@ -308,7 +308,7 @@ export const MessageUserStore = new class {
|
|||
}
|
||||
|
||||
if (toFolder) {
|
||||
if (trashFolder === toFolder.fullNameRaw || spamFolder === toFolder.fullNameRaw) {
|
||||
if (trashFolder === toFolder.fullName || spamFolder === toFolder.fullName) {
|
||||
unseenCount = 0;
|
||||
}
|
||||
|
||||
|
@ -661,13 +661,13 @@ export const MessageUserStore = new class {
|
|||
if (null != collection.MessageUnseenCount) {
|
||||
if (pInt(folder.messageCountUnread()) !== pInt(collection.MessageUnseenCount)) {
|
||||
unreadCountChange = true;
|
||||
MessageFlagsCache.clearFolder(folder.fullNameRaw);
|
||||
MessageFlagsCache.clearFolder(folder.fullName);
|
||||
}
|
||||
|
||||
folder.messageCountUnread(collection.MessageUnseenCount);
|
||||
}
|
||||
|
||||
this.initUidNextAndNewMessages(folder.fullNameRaw, collection.UidNext, collection.NewMessages);
|
||||
this.initUidNextAndNewMessages(folder.fullName, collection.UidNext, collection.NewMessages);
|
||||
}
|
||||
|
||||
this.listCount(iCount);
|
||||
|
@ -688,7 +688,7 @@ export const MessageUserStore = new class {
|
|||
clearNewMessageCache();
|
||||
|
||||
if (folder && (cached || unreadCountChange || SettingsUserStore.useThreads())) {
|
||||
rl.app.folderInformation(folder.fullNameRaw, collection);
|
||||
rl.app.folderInformation(folder.fullName, collection);
|
||||
}
|
||||
} else {
|
||||
this.listCount(0);
|
||||
|
|
|
@ -52,7 +52,7 @@ class FolderClearPopupView extends AbstractViewPopup {
|
|||
folderToClear.messageCountAll(0);
|
||||
folderToClear.messageCountUnread(0);
|
||||
|
||||
setFolderHash(folderToClear.fullNameRaw, '');
|
||||
setFolderHash(folderToClear.fullName, '');
|
||||
|
||||
Remote.folderClear(iError => {
|
||||
this.clearingProcess(false);
|
||||
|
@ -62,7 +62,7 @@ class FolderClearPopupView extends AbstractViewPopup {
|
|||
rl.app.reloadMessageList(true);
|
||||
this.cancelCommand();
|
||||
}
|
||||
}, folderToClear.fullNameRaw);
|
||||
}, folderToClear.fullName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class FolderCreatePopupView extends AbstractViewPopup {
|
|||
oItem =>
|
||||
oItem ? (oItem.isSystemFolder() ? oItem.name() + ' ' + oItem.manageFolderSystemName() : oItem.name()) : '',
|
||||
FolderUserStore.namespace
|
||||
? item => FolderUserStore.namespace !== item.fullNameRaw.substr(0, FolderUserStore.namespace.length)
|
||||
? item => FolderUserStore.namespace !== item.fullName.substr(0, FolderUserStore.namespace.length)
|
||||
: null,
|
||||
true
|
||||
)
|
||||
|
|
|
@ -88,7 +88,7 @@ export class MailFolderList extends AbstractViewLeft {
|
|||
rl.app.moveMessagesToFolder(
|
||||
FolderUserStore.currentFolderFullNameRaw(),
|
||||
MessageUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
||||
folder.fullNameRaw,
|
||||
folder.fullName,
|
||||
event.ctrlKey
|
||||
);
|
||||
} else {
|
||||
|
@ -96,8 +96,8 @@ export class MailFolderList extends AbstractViewLeft {
|
|||
MessageUserStore.message(null);
|
||||
}
|
||||
|
||||
if (folder.fullNameRaw === FolderUserStore.currentFolderFullNameRaw()) {
|
||||
setFolderHash(folder.fullNameRaw, '');
|
||||
if (folder.fullName === FolderUserStore.currentFolderFullNameRaw()) {
|
||||
setFolderHash(folder.fullName, '');
|
||||
}
|
||||
|
||||
rl.route.setHash(
|
||||
|
|
|
@ -1374,239 +1374,16 @@ END;
|
|||
|
||||
public static function Utf7ModifiedToUtf8(string $sStr) : string
|
||||
{
|
||||
$aArray = array(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,62, 63,-1,-1,-1,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,
|
||||
10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
|
||||
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1);
|
||||
|
||||
$sResult = '';
|
||||
$bError = false;
|
||||
$iLen = \strlen($sStr);
|
||||
|
||||
for ($iIndex = 0; $iLen > 0; $iIndex++, $iLen--)
|
||||
{
|
||||
$sChar = $sStr[$iIndex];
|
||||
if ($sChar == '&')
|
||||
{
|
||||
$iIndex++;
|
||||
$iLen--;
|
||||
|
||||
$sChar = isset($sStr[$iIndex]) ? $sStr[$iIndex] : null;
|
||||
if ($sChar === null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ($iLen && $sChar == '-')
|
||||
{
|
||||
$sResult .= '&';
|
||||
continue;
|
||||
}
|
||||
|
||||
$iCh = 0;
|
||||
$iK = 10;
|
||||
for (; $iLen > 0; $iIndex++, $iLen--)
|
||||
{
|
||||
$sChar = $sStr[$iIndex];
|
||||
|
||||
$iB = $aArray[\ord($sChar)];
|
||||
if ((\ord($sChar) & 0x80) || $iB == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ($iK > 0)
|
||||
{
|
||||
$iCh |= $iB << $iK;
|
||||
$iK -= 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCh |= $iB >> (-$iK);
|
||||
if ($iCh < 0x80)
|
||||
{
|
||||
if (0x20 <= $iCh && $iCh < 0x7f)
|
||||
{
|
||||
return $bError;
|
||||
}
|
||||
|
||||
$sResult .= \chr($iCh);
|
||||
}
|
||||
else if ($iCh < 0x800)
|
||||
{
|
||||
$sResult .= \chr(0xc0 | ($iCh >> 6));
|
||||
$sResult .= \chr(0x80 | ($iCh & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult .= \chr(0xe0 | ($iCh >> 12));
|
||||
$sResult .= \chr(0x80 | (($iCh >> 6) & 0x3f));
|
||||
$sResult .= \chr(0x80 | ($iCh & 0x3f));
|
||||
}
|
||||
|
||||
$iCh = ($iB << (16 + $iK)) & 0xffff;
|
||||
$iK += 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (($iCh || $iK < 6) ||
|
||||
(!$iLen || $sChar != '-') ||
|
||||
($iLen > 2 && '&' === $sStr[$iIndex+1] && '-' !== $sStr[$iIndex+2]))
|
||||
{
|
||||
return $bError;
|
||||
}
|
||||
}
|
||||
else if (\ord($sChar) < 0x20 || \ord($sChar) >= 0x7f)
|
||||
{
|
||||
return $bError;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult .= $sChar;
|
||||
}
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
return \is_callable('imap_mutf7_to_utf8')
|
||||
? \imap_mutf7_to_utf8($sStr)
|
||||
: \mb_convert_encoding($sStr, 'UTF-8', 'UTF7-IMAP');
|
||||
}
|
||||
|
||||
public static function Utf8ToUtf7Modified(string $sStr) : string
|
||||
{
|
||||
$sArray = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
|
||||
'T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
|
||||
'p','q','r','s','t','u','v','w','x','y','z', '0','1','2','3','4','5','6','7','8','9','+',',');
|
||||
|
||||
$sLen = \strlen($sStr);
|
||||
$bIsB = false;
|
||||
$iIndex = $iN = 0;
|
||||
$sReturn = '';
|
||||
$bError = false;
|
||||
$iCh = $iB = $iK = 0;
|
||||
|
||||
while ($sLen)
|
||||
{
|
||||
$iC = \ord($sStr[$iIndex]);
|
||||
if ($iC < 0x80)
|
||||
{
|
||||
$iCh = $iC;
|
||||
$iN = 0;
|
||||
}
|
||||
else if ($iC < 0xc2)
|
||||
{
|
||||
return $bError;
|
||||
}
|
||||
else if ($iC < 0xe0)
|
||||
{
|
||||
$iCh = $iC & 0x1f;
|
||||
$iN = 1;
|
||||
}
|
||||
else if ($iC < 0xf0)
|
||||
{
|
||||
$iCh = $iC & 0x0f;
|
||||
$iN = 2;
|
||||
}
|
||||
else if ($iC < 0xf8)
|
||||
{
|
||||
$iCh = $iC & 0x07;
|
||||
$iN = 3;
|
||||
}
|
||||
else if ($iC < 0xfc)
|
||||
{
|
||||
$iCh = $iC & 0x03;
|
||||
$iN = 4;
|
||||
}
|
||||
else if ($iC < 0xfe)
|
||||
{
|
||||
$iCh = $iC & 0x01;
|
||||
$iN = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $bError;
|
||||
}
|
||||
|
||||
$iIndex++;
|
||||
$sLen--;
|
||||
|
||||
if ($iN > $sLen)
|
||||
{
|
||||
return $bError;
|
||||
}
|
||||
|
||||
for ($iJ = 0; $iJ < $iN; $iJ++)
|
||||
{
|
||||
$iO = \ord($sStr[$iIndex+$iJ]);
|
||||
if (($iO & 0xc0) != 0x80)
|
||||
{
|
||||
return $bError;
|
||||
}
|
||||
|
||||
$iCh = ($iCh << 6) | ($iO & 0x3f);
|
||||
}
|
||||
|
||||
if ($iN > 1 && !($iCh >> ($iN * 5 + 1)))
|
||||
{
|
||||
return $bError;
|
||||
}
|
||||
|
||||
$iIndex += $iN;
|
||||
$sLen -= $iN;
|
||||
|
||||
if ($iCh < 0x20 || $iCh >= 0x7f)
|
||||
{
|
||||
if (!$bIsB)
|
||||
{
|
||||
$sReturn .= '&';
|
||||
$bIsB = true;
|
||||
$iB = 0;
|
||||
$iK = 10;
|
||||
}
|
||||
|
||||
if ($iCh & ~0xffff)
|
||||
{
|
||||
$iCh = 0xfffe;
|
||||
}
|
||||
|
||||
$sReturn .= $sArray[($iB | $iCh >> $iK)];
|
||||
$iK -= 6;
|
||||
for (; $iK >= 0; $iK -= 6)
|
||||
{
|
||||
$sReturn .= $sArray[(($iCh >> $iK) & 0x3f)];
|
||||
}
|
||||
|
||||
$iB = ($iCh << (-$iK)) & 0x3f;
|
||||
$iK += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bIsB)
|
||||
{
|
||||
if ($iK > 10)
|
||||
{
|
||||
$sReturn .= $sArray[$iB];
|
||||
}
|
||||
$sReturn .= '-';
|
||||
$bIsB = false;
|
||||
}
|
||||
|
||||
$sReturn .= \chr($iCh);
|
||||
if ('&' === \chr($iCh))
|
||||
{
|
||||
$sReturn .= '-';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($bIsB)
|
||||
{
|
||||
if ($iK > 10)
|
||||
{
|
||||
$sReturn .= $sArray[$iB];
|
||||
}
|
||||
|
||||
$sReturn .= '-';
|
||||
}
|
||||
|
||||
return $sReturn;
|
||||
return \is_callable('imap_utf8_to_mutf7')
|
||||
? \imap_utf8_to_mutf7($sStr)
|
||||
: \mb_convert_encoding($sStr, 'UTF7-IMAP', 'UTF-8');
|
||||
}
|
||||
|
||||
public static function FunctionExistsAndEnabled($mFunctionNameOrNames) : bool
|
||||
|
|
|
@ -45,7 +45,7 @@ trait Metadata
|
|||
for ($i = 0; $i < $c; $i += 2) {
|
||||
$aMetadata[$oResponse->ResponseList[3][$i]] = $oResponse->ResponseList[3][$i+1];
|
||||
}
|
||||
$aReturn[$oResponse->ResponseList[2]] = $aMetadata;
|
||||
$aReturn[$this->toUTF8($oResponse->ResponseList[2])] = $aMetadata;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
@ -75,7 +75,7 @@ trait Metadata
|
|||
}
|
||||
}
|
||||
|
||||
$arguments[] = $this->EscapeString($sFolderName);
|
||||
$arguments[] = $this->EscapeFolderName($sFolderName);
|
||||
|
||||
$arguments[] = '(' . \implode(' ', \array_map([$this, 'EscapeString'], $aEntries)) . ')';
|
||||
|
||||
|
@ -118,7 +118,7 @@ trait Metadata
|
|||
throw new \MailSo\Base\Exceptions\InvalidArgumentException("Wrong argument for SETMETADATA command");
|
||||
}
|
||||
|
||||
$arguments = [$this->EscapeString($sFolderName)];
|
||||
$arguments = [$this->EscapeFolderName($sFolderName)];
|
||||
|
||||
\array_walk($aEntries, function(&$v, $k){
|
||||
$v = $this->EscapeString($k) . ' ' . $this->EscapeString($v);
|
||||
|
|
|
@ -29,7 +29,7 @@ trait Quota
|
|||
public function Quota(string $sRootName = '') : ?array
|
||||
{
|
||||
return $this->IsSupported('QUOTA')
|
||||
? $this->SendRequestGetResponse("GETQUOTA {$this->EscapeString($sRootName)}")->getQuotaResult()
|
||||
? $this->getQuotaResult($this->SendRequestGetResponse("GETQUOTA {$this->EscapeFolderName($sRootName)}"))
|
||||
: null;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,45 @@ trait Quota
|
|||
public function QuotaRoot(string $sFolderName = 'INBOX') : ?array
|
||||
{
|
||||
return $this->IsSupported('QUOTA')
|
||||
? $this->SendRequestGetResponse("GETQUOTAROOT {$this->EscapeString($sFolderName)}")->getQuotaResult()
|
||||
? $this->getQuotaResult($this->SendRequestGetResponse("GETQUOTAROOT {$this->EscapeFolderName($sFolderName)}"))
|
||||
: null;
|
||||
}
|
||||
|
||||
private function getQuotaResult(\MailSo\Imap\ResponseCollection $oResponseCollection) : array
|
||||
{
|
||||
$aReturn = array(0, 0);
|
||||
foreach ($oResponseCollection as $oResponse) {
|
||||
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
||||
&& 'QUOTA' === $oResponse->StatusOrIndex
|
||||
&& \is_array($oResponse->ResponseList)
|
||||
&& isset($oResponse->ResponseList[3])
|
||||
&& \is_array($oResponse->ResponseList[3])
|
||||
&& 2 < \count($oResponse->ResponseList[3])
|
||||
&& 'STORAGE' === \strtoupper($oResponse->ResponseList[3][0])
|
||||
&& \is_numeric($oResponse->ResponseList[3][1])
|
||||
&& \is_numeric($oResponse->ResponseList[3][2])
|
||||
)
|
||||
{
|
||||
$aReturn = array(
|
||||
(int) $oResponse->ResponseList[3][1],
|
||||
(int) $oResponse->ResponseList[3][2],
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
if (5 < \count($oResponse->ResponseList[3])
|
||||
&& 'MESSAGE' === \strtoupper($oResponse->ResponseList[3][3])
|
||||
&& \is_numeric($oResponse->ResponseList[3][4])
|
||||
&& \is_numeric($oResponse->ResponseList[3][5])
|
||||
)
|
||||
{
|
||||
$aReturn[2] = (int) $oResponse->ResponseList[3][4];
|
||||
$aReturn[3] = (int) $oResponse->ResponseList[3][5];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aReturn;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,12 +23,7 @@ class Folder
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sNameRaw;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sFullNameRaw;
|
||||
private $sFullName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
@ -48,15 +43,20 @@ class Folder
|
|||
/**
|
||||
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
function __construct(string $sFullNameRaw, string $sDelimiter = null, array $aFlags = array())
|
||||
function __construct(string $sFullName, string $sDelimiter = null, array $aFlags = array())
|
||||
{
|
||||
if (!\strlen($sFullNameRaw)) {
|
||||
if (!\strlen($sFullName)) {
|
||||
throw new \MailSo\Base\Exceptions\InvalidArgumentException;
|
||||
}
|
||||
$this->sFullNameRaw = $sFullNameRaw;
|
||||
|
||||
$this->sFullName = $sFullName;
|
||||
$this->setDelimiter($sDelimiter);
|
||||
$this->setFlags($aFlags);
|
||||
/*
|
||||
if (\in_array('\\noutf8', $this->aFlagsLowerCase)) {
|
||||
}
|
||||
if (\in_array('\\utf8only', $this->aFlagsLowerCase)) {
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public function setFlags(array $aFlags) : void
|
||||
|
@ -67,22 +67,21 @@ class Folder
|
|||
public function setDelimiter(?string $sDelimiter) : void
|
||||
{
|
||||
$this->sDelimiter = $sDelimiter;
|
||||
if ($sDelimiter) {
|
||||
$aNames = \explode($this->sDelimiter, $this->sFullNameRaw);
|
||||
$this->sNameRaw = \end($aNames);
|
||||
} else {
|
||||
$this->sNameRaw = $this->sFullNameRaw;
|
||||
}
|
||||
|
||||
public function Name() : string
|
||||
{
|
||||
$sNameRaw = $this->sFullName;
|
||||
if ($this->sDelimiter) {
|
||||
$aNames = \explode($this->sDelimiter, $sNameRaw);
|
||||
return \end($aNames);
|
||||
}
|
||||
return $sNameRaw;
|
||||
}
|
||||
|
||||
public function NameRaw() : string
|
||||
public function FullName() : string
|
||||
{
|
||||
return $this->sNameRaw;
|
||||
}
|
||||
|
||||
public function FullNameRaw() : string
|
||||
{
|
||||
return $this->sFullNameRaw;
|
||||
return $this->sFullName;
|
||||
}
|
||||
|
||||
public function Delimiter() : ?string
|
||||
|
@ -102,7 +101,7 @@ class Folder
|
|||
|
||||
public function IsInbox() : bool
|
||||
{
|
||||
return 'INBOX' === \strtoupper($this->sFullNameRaw) || \in_array('\\inbox', $this->aFlagsLowerCase);
|
||||
return 'INBOX' === \strtoupper($this->sFullName) || \in_array('\\inbox', $this->aFlagsLowerCase);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,6 +66,11 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
*/
|
||||
public $__FORCE_SELECT_ON_EXAMINE__ = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $UTF8 = false;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
\ini_set('xdebug.max_nesting_level', 500);
|
||||
|
@ -248,11 +253,12 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
if ($this->IsSupported('IMAP4rev2')) {
|
||||
$this->SendRequestGetResponse('ENABLE', array('IMAP4rev1'));
|
||||
}
|
||||
// TODO: RFC 6855
|
||||
if ($this->IsSupported('UTF8=ONLY')) {
|
||||
*/
|
||||
// RFC 6855 || RFC 5738
|
||||
$this->UTF8 = $this->IsSupported('UTF8=ONLY') || $this->IsSupported('UTF8=ACCEPT');
|
||||
if ($this->UTF8) {
|
||||
$this->SendRequestGetResponse('ENABLE', array('UTF8=ACCEPT'));
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch (Exceptions\NegativeResponseException $oException)
|
||||
{
|
||||
|
@ -377,7 +383,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
public function FolderCreate(string $sFolderName) : self
|
||||
{
|
||||
$this->SendRequestGetResponse('CREATE',
|
||||
array($this->EscapeString($sFolderName)));
|
||||
array($this->EscapeFolderName($sFolderName)));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -391,7 +397,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
// Uncomment will work issue #124 ?
|
||||
// $this->selectOrExamineFolder($sFolderName, true);
|
||||
$this->SendRequestGetResponse('DELETE',
|
||||
array($this->EscapeString($sFolderName)));
|
||||
array($this->EscapeFolderName($sFolderName)));
|
||||
// $this->FolderCheck();
|
||||
// $this->FolderUnSelect();
|
||||
return $this;
|
||||
|
@ -405,7 +411,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
public function FolderSubscribe(string $sFolderName) : self
|
||||
{
|
||||
$this->SendRequestGetResponse('SUBSCRIBE',
|
||||
array($this->EscapeString($sFolderName)));
|
||||
array($this->EscapeFolderName($sFolderName)));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -417,7 +423,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
public function FolderUnSubscribe(string $sFolderName) : self
|
||||
{
|
||||
$this->SendRequestGetResponse('UNSUBSCRIBE',
|
||||
array($this->EscapeString($sFolderName)));
|
||||
array($this->EscapeFolderName($sFolderName)));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -429,8 +435,8 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
public function FolderRename(string $sOldFolderName, string $sNewFolderName) : self
|
||||
{
|
||||
$this->SendRequestGetResponse('RENAME', array(
|
||||
$this->EscapeString($sOldFolderName),
|
||||
$this->EscapeString($sNewFolderName)));
|
||||
$this->EscapeFolderName($sOldFolderName),
|
||||
$this->EscapeFolderName($sNewFolderName)));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -465,8 +471,14 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$bReselect = true;
|
||||
$this->FolderUnSelect();
|
||||
}
|
||||
$aResult = $this->SendRequestGetResponse('STATUS', array($this->EscapeString($sFolderName), $aStatusItems))
|
||||
->getStatusFolderInformationResult();
|
||||
|
||||
$oResponseCollection = $this->SendRequestGetResponse('STATUS', array($this->EscapeFolderName($sFolderName), $aStatusItems));
|
||||
$oInfo = new FolderInformation($sFolderName, false);
|
||||
foreach ($oResponseCollection as $oResponse) {
|
||||
$oInfo->setStatusFromResponse($oResponse);
|
||||
}
|
||||
$aResult = $oInfo->getStatusItems();
|
||||
|
||||
if ($bReselect) {
|
||||
$this->selectOrExamineFolder($sFolderName, $bWritable, false);
|
||||
}
|
||||
|
@ -502,7 +514,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
}
|
||||
}
|
||||
|
||||
$aParameters[] = $this->EscapeString($sParentFolderName);
|
||||
$aParameters[] = $this->EscapeFolderName($sParentFolderName);
|
||||
$aParameters[] = $this->EscapeString(\strlen(\trim($sListPattern)) ? $sListPattern : '*');
|
||||
|
||||
// RFC 5819
|
||||
|
@ -529,7 +541,11 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$aReturnParams[] = 'STATUS';
|
||||
$aReturnParams[] = $aL;
|
||||
}
|
||||
|
||||
/*
|
||||
if ($this->UTF8) {
|
||||
$aReturnParams[] = 'UTF8'; // 'UTF8ONLY';
|
||||
}
|
||||
*/
|
||||
if ($aReturnParams) {
|
||||
$aParameters[] = 'RETURN';
|
||||
$aParameters[] = $aReturnParams;
|
||||
|
@ -540,7 +556,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
if ($bPassthru) {
|
||||
$this->streamResponse();
|
||||
} else {
|
||||
$aReturn = $this->getResponse()->getFoldersResult($sCmd);
|
||||
$aReturn = $this->getResponse()->getFoldersResult($sCmd, $this);
|
||||
}
|
||||
|
||||
// RFC 5464
|
||||
|
@ -549,15 +565,15 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$aMetadata = $this->getAllMetadata();
|
||||
if ($aMetadata) {
|
||||
foreach ($aReturn as $oFolder) {
|
||||
if (isset($aMetadata[$oFolder->FullNameRaw()])) {
|
||||
$oFolder->SetAllMetadata($aMetadata[$oFolder->FullNameRaw()]);
|
||||
if (isset($aMetadata[$oFolder->FullName()])) {
|
||||
$oFolder->SetAllMetadata($aMetadata[$oFolder->FullName()]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($aReturn as $oFolder) {
|
||||
try {
|
||||
$oFolder->SetAllMetadata(
|
||||
$this->getMetadata($oFolder->FullNameRaw(), ['/shared', '/private'], ['DEPTH'=>'infinity'])
|
||||
$this->getMetadata($oFolder->FullName(), ['/shared', '/private'], ['DEPTH'=>'infinity'])
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
// Ignore error
|
||||
|
@ -602,7 +618,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
*/
|
||||
public function FolderHierarchyDelimiter(string $sFolderName = '') : ?string
|
||||
{
|
||||
$oResponse = $this->SendRequestGetResponse('LIST', ['""', $this->EscapeString($sFolderName)]);
|
||||
$oResponse = $this->SendRequestGetResponse('LIST', ['""', $this->EscapeFolderName($sFolderName)]);
|
||||
return ('LIST' === $oResponse[0]->ResponseList[1]) ? $oResponse[0]->ResponseList[3] : null;
|
||||
}
|
||||
|
||||
|
@ -628,18 +644,57 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
throw new \MailSo\Base\Exceptions\InvalidArgumentException;
|
||||
}
|
||||
|
||||
$aParams = array($this->EscapeString($sFolderName));
|
||||
$aSelectParams = array();
|
||||
/*
|
||||
if ($this->IsSupported('CONDSTORE')) {
|
||||
$aParams[] = ['CONDSTORE'];
|
||||
$aSelectParams[] = 'CONDSTORE';
|
||||
}
|
||||
if ($this->UTF8) {
|
||||
$aSelectParams[] = 'UTF8';
|
||||
}
|
||||
*/
|
||||
|
||||
$aParams = array(
|
||||
$this->EscapeFolderName($sFolderName)
|
||||
);
|
||||
if ($aSelectParams) {
|
||||
$aParams[] = $aSelectParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* IMAP4rev2 SELECT/EXAMINE are now required to return an untagged LIST response.
|
||||
*/
|
||||
$this->oCurrentFolderInfo = $this->SendRequestGetResponse($bIsWritable ? 'SELECT' : 'EXAMINE',
|
||||
$aParams)
|
||||
->getCurrentFolderInformation($sFolderName, $bIsWritable);
|
||||
$oResponseCollection = $this->SendRequestGetResponse($bIsWritable ? 'SELECT' : 'EXAMINE', $aParams);
|
||||
$oResult = new FolderInformation($sFolderName, $bIsWritable);
|
||||
foreach ($oResponseCollection as $oResponse) {
|
||||
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType) {
|
||||
if (!$oResult->setStatusFromResponse($oResponse)) {
|
||||
// OK untagged responses
|
||||
if (\is_array($oResponse->OptionalResponse)) {
|
||||
$key = $oResponse->OptionalResponse[0];
|
||||
if (\count($oResponse->OptionalResponse) > 1) {
|
||||
if ('PERMANENTFLAGS' === $key && \is_array($oResponse->OptionalResponse[1])) {
|
||||
$oResult->PermanentFlags = $oResponse->OptionalResponse[1];
|
||||
}
|
||||
} else if ('READ-ONLY' === $key) {
|
||||
// $oResult->IsWritable = false;
|
||||
} else if ('READ-WRITE' === $key) {
|
||||
// $oResult->IsWritable = true;
|
||||
} else if ('NOMODSEQ' === $key) {
|
||||
// https://datatracker.ietf.org/doc/html/rfc4551#section-3.1.2
|
||||
}
|
||||
}
|
||||
|
||||
// untagged responses
|
||||
else if (\count($oResponse->ResponseList) > 2
|
||||
&& 'FLAGS' === $oResponse->ResponseList[1]
|
||||
&& \is_array($oResponse->ResponseList[2])) {
|
||||
$oResult->Flags = $oResponse->ResponseList[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->oCurrentFolderInfo = $oResult;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -885,7 +940,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
}
|
||||
|
||||
$this->SendRequestGetResponse($bIndexIsUid ? 'UID COPY' : 'COPY',
|
||||
array($sIndexRange, $this->EscapeString($sToFolder)));
|
||||
array($sIndexRange, $this->EscapeFolderName($sToFolder)));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -911,7 +966,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
}
|
||||
|
||||
$this->SendRequestGetResponse($bIndexIsUid ? 'UID MOVE' : 'MOVE',
|
||||
array($sIndexRange, $this->EscapeString($sToFolder)));
|
||||
array($sIndexRange, $this->EscapeFolderName($sToFolder)));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -972,7 +1027,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
*/
|
||||
public function MessageAppendStream(string $sFolderName, $rMessageAppendStream, int $iStreamSize, array $aAppendFlags = null, int &$iUid = null, int $iDateTime = 0) : self
|
||||
{
|
||||
$aData = array($this->EscapeString($sFolderName), $aAppendFlags);
|
||||
$aData = array($this->EscapeFolderName($sFolderName), $aAppendFlags);
|
||||
if (0 < $iDateTime)
|
||||
{
|
||||
$aData[] = $this->EscapeString(\gmdate('d-M-Y H:i:s', $iDateTime).' +0000');
|
||||
|
@ -1239,4 +1294,14 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
return 'UNKNOWN';
|
||||
}
|
||||
|
||||
public function EscapeFolderName(string $sFolderName) : string
|
||||
{
|
||||
return $this->EscapeString($this->UTF8 ? $sFolderName : \MailSo\Base\Utils::Utf8ToUtf7Modified($sFolderName));
|
||||
}
|
||||
|
||||
public function toUTF8(string $sText) : string
|
||||
{
|
||||
return $this->UTF8 ? $sText : \MailSo\Base\Utils::Utf7ModifiedToUtf8($sText);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,42 +20,32 @@ class NamespaceResult
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sPersonal;
|
||||
private $sPersonal = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sPersonalDelimiter;
|
||||
private $sPersonalDelimiter = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sOtherUser;
|
||||
private $sOtherUser = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sOtherUserDelimiter;
|
||||
private $sOtherUserDelimiter = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sShared;
|
||||
private $sShared = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sSharedDelimiter;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->sPersonal = '';
|
||||
$this->sPersonalDelimiter = '';
|
||||
$this->sOtherUser = '';
|
||||
$this->sOtherUserDelimiter = '';
|
||||
$this->sShared = '';
|
||||
$this->sSharedDelimiter = '';
|
||||
}
|
||||
private $sSharedDelimiter = '';
|
||||
|
||||
public function InitByImapResponse(\MailSo\Imap\Response $oImapResponse) : self
|
||||
{
|
||||
|
@ -103,8 +93,4 @@ class NamespaceResult
|
|||
return $this->sPersonal;
|
||||
}
|
||||
|
||||
public function GetPersonalNamespaceDelimiter() : string
|
||||
{
|
||||
return $this->sPersonalDelimiter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ class ResponseCollection extends \MailSo\Base\Collection
|
|||
return $aReturn;
|
||||
}
|
||||
|
||||
public function getFoldersResult(string $sStatus) : array
|
||||
public function getFoldersResult(string $sStatus, ImapClient $oImapClient) : array
|
||||
{
|
||||
$aReturn = array();
|
||||
|
||||
|
@ -99,7 +99,7 @@ class ResponseCollection extends \MailSo\Base\Collection
|
|||
continue;
|
||||
}
|
||||
if ('STATUS' === $oResponse->StatusOrIndex && isset($oResponse->ResponseList[2])) {
|
||||
$sFullNameRaw = $oResponse->ResponseList[2];
|
||||
$sFullNameRaw = $oImapClient->toUTF8($oResponse->ResponseList[2]);
|
||||
if (!isset($aReturn[$sFullNameRaw])) {
|
||||
$aReturn[$sFullNameRaw] = new Folder($sFullNameRaw);
|
||||
}
|
||||
|
@ -108,14 +108,14 @@ class ResponseCollection extends \MailSo\Base\Collection
|
|||
else if ($sStatus === $oResponse->StatusOrIndex && 5 == \count($oResponse->ResponseList)) {
|
||||
try
|
||||
{
|
||||
$sFullNameRaw = $oResponse->ResponseList[4];
|
||||
$sFullNameRaw = $oImapClient->toUTF8($oResponse->ResponseList[4]);
|
||||
|
||||
/**
|
||||
* $oResponse->ResponseList[0] = *
|
||||
* $oResponse->ResponseList[1] = LIST (all) | LSUB (subscribed)
|
||||
* $oResponse->ResponseList[2] = Flags
|
||||
* $oResponse->ResponseList[3] = Delimiter
|
||||
* $oResponse->ResponseList[4] = FullNameRaw
|
||||
* $oResponse->ResponseList[4] = FullName
|
||||
*/
|
||||
if (!isset($aReturn[$sFullNameRaw])) {
|
||||
$oFolder = new Folder($sFullNameRaw,
|
||||
|
@ -220,45 +220,6 @@ class ResponseCollection extends \MailSo\Base\Collection
|
|||
return $aReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by selectOrExamineFolder
|
||||
*/
|
||||
public function getCurrentFolderInformation(string $sFolderName, bool $bIsWritable) : FolderInformation
|
||||
{
|
||||
$oResult = new FolderInformation($sFolderName, $bIsWritable);
|
||||
foreach ($this as $oResponse) {
|
||||
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType) {
|
||||
if (!$oResult->setStatusFromResponse($oResponse)) {
|
||||
// OK untagged responses
|
||||
if (\is_array($oResponse->OptionalResponse)) {
|
||||
$key = $oResponse->OptionalResponse[0];
|
||||
if (\count($oResponse->OptionalResponse) > 1) {
|
||||
if ('PERMANENTFLAGS' === $key && \is_array($oResponse->OptionalResponse[1])) {
|
||||
$oResult->PermanentFlags = $oResponse->OptionalResponse[1];
|
||||
}
|
||||
} else if ('READ-ONLY' === $key) {
|
||||
// $oResult->IsWritable = false;
|
||||
} else if ('READ-WRITE' === $key) {
|
||||
// $oResult->IsWritable = true;
|
||||
} else if ('NOMODSEQ' === $key) {
|
||||
// https://datatracker.ietf.org/doc/html/rfc4551#section-3.1.2
|
||||
}
|
||||
}
|
||||
|
||||
// untagged responses
|
||||
else if (\count($oResponse->ResponseList) > 2) {
|
||||
if ('FLAGS' === $oResponse->ResponseList[1] && \is_array($oResponse->ResponseList[2]))
|
||||
{
|
||||
$oResult->Flags = $oResponse->ResponseList[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $oResult;
|
||||
}
|
||||
|
||||
public function getNamespaceResult() : NamespaceResult
|
||||
{
|
||||
foreach ($this as $oResponse) {
|
||||
|
@ -273,43 +234,6 @@ class ResponseCollection extends \MailSo\Base\Collection
|
|||
throw new Exceptions\ResponseException;
|
||||
}
|
||||
|
||||
public function getQuotaResult() : array
|
||||
{
|
||||
$aReturn = array(0, 0);
|
||||
foreach ($this as $oResponse) {
|
||||
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
|
||||
&& 'QUOTA' === $oResponse->StatusOrIndex
|
||||
&& \is_array($oResponse->ResponseList)
|
||||
&& isset($oResponse->ResponseList[3])
|
||||
&& \is_array($oResponse->ResponseList[3])
|
||||
&& 2 < \count($oResponse->ResponseList[3])
|
||||
&& 'STORAGE' === \strtoupper($oResponse->ResponseList[3][0])
|
||||
&& \is_numeric($oResponse->ResponseList[3][1])
|
||||
&& \is_numeric($oResponse->ResponseList[3][2])
|
||||
)
|
||||
{
|
||||
$aReturn = array(
|
||||
(int) $oResponse->ResponseList[3][1],
|
||||
(int) $oResponse->ResponseList[3][2],
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
if (5 < \count($oResponse->ResponseList[3])
|
||||
&& 'MESSAGE' === \strtoupper($oResponse->ResponseList[3][3])
|
||||
&& \is_numeric($oResponse->ResponseList[3][4])
|
||||
&& \is_numeric($oResponse->ResponseList[3][5])
|
||||
)
|
||||
{
|
||||
$aReturn[2] = (int) $oResponse->ResponseList[3][4];
|
||||
$aReturn[3] = (int) $oResponse->ResponseList[3][5];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aReturn;
|
||||
}
|
||||
|
||||
public function getSimpleESearchOrESortResult(string $sRequestTag, bool $bReturnUid) : array
|
||||
{
|
||||
$aResult = array();
|
||||
|
@ -340,15 +264,6 @@ class ResponseCollection extends \MailSo\Base\Collection
|
|||
return $aResult;
|
||||
}
|
||||
|
||||
public function getStatusFolderInformationResult() : array
|
||||
{
|
||||
$oInfo = new FolderInformation('', false);
|
||||
foreach ($this as $oResponse) {
|
||||
$oInfo->setStatusFromResponse($oResponse);
|
||||
}
|
||||
return $oInfo->getStatusItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $mValue
|
||||
*
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
/*
|
||||
* 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.
|
||||
|
|
|
@ -112,10 +112,10 @@ trait Status
|
|||
* EXAMINE https://datatracker.ietf.org/doc/html/rfc3501#section-6.3.2
|
||||
* STATUS https://datatracker.ietf.org/doc/html/rfc3501#section-6.3.10
|
||||
*
|
||||
* getCurrentFolderInformation
|
||||
* selectOrExamineFolder
|
||||
* ResponseList[2] => EXISTS | RECENT
|
||||
* OptionalResponse[0] => UNSEEN
|
||||
* getStatusFolderInformationResult
|
||||
* FolderStatus
|
||||
* OptionalResponse[0] => HIGHESTMODSEQ
|
||||
* ResponseList[1] => STATUS
|
||||
* getFoldersResult LIST-EXTENDED
|
||||
|
|
|
@ -20,16 +20,6 @@ use MailSo\Imap\Enumerations\MetadataKeys;
|
|||
*/
|
||||
class Folder implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sParentFullNameRaw;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $iNestingLevel;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
@ -48,7 +38,7 @@ class Folder implements \JsonSerializable
|
|||
/**
|
||||
* @var \MailSo\Mail\FolderCollection
|
||||
*/
|
||||
private $oSubFolders;
|
||||
private $oSubFolders = null;
|
||||
|
||||
/**
|
||||
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
|
||||
|
@ -56,18 +46,6 @@ class Folder implements \JsonSerializable
|
|||
function __construct(\MailSo\Imap\Folder $oImapFolder, bool $bSubscribed = true, bool $bExists = true)
|
||||
{
|
||||
$this->oImapFolder = $oImapFolder;
|
||||
$this->oSubFolders = null;
|
||||
|
||||
$aNames = \explode($this->oImapFolder->Delimiter(), $this->oImapFolder->FullNameRaw());
|
||||
$this->iNestingLevel = \count($aNames);
|
||||
|
||||
$this->sParentFullNameRaw = '';
|
||||
if (1 < $this->iNestingLevel)
|
||||
{
|
||||
\array_pop($aNames);
|
||||
$this->sParentFullNameRaw = \implode($this->oImapFolder->Delimiter(), $aNames);
|
||||
}
|
||||
|
||||
$this->bSubscribed = $bSubscribed || \in_array('\\subscribed', $oImapFolder->FlagsLowerCase());
|
||||
$this->bExists = $bExists;
|
||||
}
|
||||
|
@ -84,16 +62,12 @@ class Folder implements \JsonSerializable
|
|||
|
||||
public function Name() : string
|
||||
{
|
||||
return \MailSo\Base\Utils::ConvertEncoding($this->NameRaw(),
|
||||
\MailSo\Base\Enumerations\Charset::UTF_7_IMAP,
|
||||
\MailSo\Base\Enumerations\Charset::UTF_8);
|
||||
return $this->oImapFolder->Name();
|
||||
}
|
||||
|
||||
public function FullName() : string
|
||||
{
|
||||
return \MailSo\Base\Utils::ConvertEncoding($this->FullNameRaw(),
|
||||
\MailSo\Base\Enumerations\Charset::UTF_7_IMAP,
|
||||
\MailSo\Base\Enumerations\Charset::UTF_8);
|
||||
return $this->oImapFolder->FullName();
|
||||
}
|
||||
|
||||
public function NameRaw() : string
|
||||
|
@ -101,23 +75,6 @@ class Folder implements \JsonSerializable
|
|||
return $this->oImapFolder->NameRaw();
|
||||
}
|
||||
|
||||
public function FullNameRaw() : string
|
||||
{
|
||||
return $this->oImapFolder->FullNameRaw();
|
||||
}
|
||||
|
||||
public function ParentFullName() : string
|
||||
{
|
||||
return \MailSo\Base\Utils::ConvertEncoding($this->sParentFullNameRaw,
|
||||
\MailSo\Base\Enumerations\Charset::UTF_7_IMAP,
|
||||
\MailSo\Base\Enumerations\Charset::UTF_8);
|
||||
}
|
||||
|
||||
public function ParentFullNameRaw() : string
|
||||
{
|
||||
return $this->sParentFullNameRaw;
|
||||
}
|
||||
|
||||
public function Delimiter() : string
|
||||
{
|
||||
return $this->oImapFolder->Delimiter();
|
||||
|
@ -188,7 +145,7 @@ class Folder implements \JsonSerializable
|
|||
|
||||
switch (true)
|
||||
{
|
||||
case \in_array('\\inbox', $aFlags) || 'INBOX' === \strtoupper($this->FullNameRaw()):
|
||||
case \in_array('\\inbox', $aFlags) || 'INBOX' === \strtoupper($this->FullName()):
|
||||
return FolderType::INBOX;
|
||||
|
||||
case \in_array('\\sent', $aFlags):
|
||||
|
@ -221,7 +178,7 @@ class Folder implements \JsonSerializable
|
|||
return FolderType::ALL;
|
||||
|
||||
// TODO
|
||||
// case 'Templates' === $this->FullNameRaw():
|
||||
// case 'Templates' === $this->FullName():
|
||||
// return FolderType::TEMPLATES;
|
||||
}
|
||||
|
||||
|
@ -287,7 +244,7 @@ class Folder implements \JsonSerializable
|
|||
'MessageUnseenCount' => (int) $aStatus['UNSEEN'],
|
||||
'UidNext' => (int) $aStatus['UIDNEXT'],
|
||||
// 'Hash' => $this->MailClient()->GenerateFolderHash(
|
||||
// $this->FullNameRaw(), $aStatus['MESSAGES'], $aStatus['UIDNEXT'],
|
||||
// $this->FullName(), $aStatus['MESSAGES'], $aStatus['UIDNEXT'],
|
||||
// empty($aStatus['HIGHESTMODSEQ']) ? 0 : $aStatus['HIGHESTMODSEQ'])
|
||||
);
|
||||
}
|
||||
|
@ -296,7 +253,6 @@ class Folder implements \JsonSerializable
|
|||
'@Object' => 'Object/Folder',
|
||||
'Name' => $this->Name(),
|
||||
'FullName' => $this->FullName(),
|
||||
'FullNameRaw' => $this->FullNameRaw(),
|
||||
'Delimiter' => (string) $this->Delimiter(),
|
||||
// 'HasVisibleSubFolders' => $this->HasVisibleSubFolders(),
|
||||
'Subscribed' => $this->bSubscribed,
|
||||
|
|
|
@ -57,7 +57,7 @@ class FolderCollection extends \MailSo\Base\Collection
|
|||
$mResult = null;
|
||||
foreach ($this as $oFolder)
|
||||
{
|
||||
if ($oFolder->FullNameRaw() === $sFullNameRaw)
|
||||
if ($oFolder->FullName() === $sFullNameRaw)
|
||||
{
|
||||
$mResult = $oFolder;
|
||||
break;
|
||||
|
@ -119,7 +119,7 @@ class FolderCollection extends \MailSo\Base\Collection
|
|||
{
|
||||
foreach ($this as $oItemFolder)
|
||||
{
|
||||
if (0 === \strpos($oMailFolder->FullNameRaw(), $oItemFolder->FullNameRaw().$oItemFolder->Delimiter()))
|
||||
if (0 === \strpos($oMailFolder->FullName(), $oItemFolder->FullName().$oItemFolder->Delimiter()))
|
||||
{
|
||||
$oItemFolder->SubFolders(true)->AddWithPositionSearch($oMailFolder);
|
||||
return;
|
||||
|
|
|
@ -1219,7 +1219,7 @@ class MailClient
|
|||
$aImapSubscribedFoldersHelper = array();
|
||||
foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
|
||||
{
|
||||
$aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw();
|
||||
$aImapSubscribedFoldersHelper[] = $oImapFolder->FullName();
|
||||
}
|
||||
}
|
||||
catch (\Throwable $oException)
|
||||
|
@ -1253,13 +1253,13 @@ class MailClient
|
|||
foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
|
||||
{
|
||||
$oMailFolder = new Folder($oImapFolder,
|
||||
($bUseListSubscribeStatus && (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)))
|
||||
($bUseListSubscribeStatus && (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullName(), $aImapSubscribedFoldersHelper)))
|
||||
|| $oImapFolder->IsInbox()
|
||||
);
|
||||
if ($oImapFolder->IsInbox()) {
|
||||
$sINBOX = $oMailFolder->FullNameRaw();
|
||||
$sINBOX = $oMailFolder->FullName();
|
||||
}
|
||||
$aSortedByLenImapFolders[$oMailFolder->FullNameRaw()] = $oMailFolder;
|
||||
$aSortedByLenImapFolders[$oMailFolder->FullName()] = $oMailFolder;
|
||||
}
|
||||
|
||||
// Add NonExistent folders
|
||||
|
@ -1267,7 +1267,7 @@ class MailClient
|
|||
foreach ($aSortedByLenImapFolders as /* @var $oMailFolder Folder */ $oMailFolder)
|
||||
{
|
||||
$sDelimiter = $oMailFolder->Delimiter();
|
||||
$aFolderExplode = \explode($sDelimiter, $oMailFolder->FullNameRaw());
|
||||
$aFolderExplode = \explode($sDelimiter, $oMailFolder->FullName());
|
||||
|
||||
if (1 < \count($aFolderExplode))
|
||||
{
|
||||
|
@ -1418,7 +1418,7 @@ class MailClient
|
|||
$aSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*');
|
||||
foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder)
|
||||
{
|
||||
$this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw());
|
||||
$this->oImapClient->FolderUnSubscribe($oFolder->FullName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1442,7 +1442,7 @@ class MailClient
|
|||
|
||||
foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder)
|
||||
{
|
||||
$sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw();
|
||||
$sFolderFullNameRawForResubscrine = $oFolder->FullName();
|
||||
if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw))
|
||||
{
|
||||
$sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw.
|
||||
|
|
|
@ -460,7 +460,7 @@ trait Folders
|
|||
{
|
||||
foreach ($oFolders as $oFolder)
|
||||
{
|
||||
$aResult[] = $oFolder->FullNameRaw()."|".
|
||||
$aResult[] = $oFolder->FullName()."|".
|
||||
implode("|", $oFolder->FlagsLowerCase()).($oFolder->IsSubscribed() ? '1' : '0');
|
||||
|
||||
$oSub = $oFolder->SubFolders();
|
||||
|
@ -492,7 +492,7 @@ trait Folders
|
|||
FolderType::ARCHIVE
|
||||
)))
|
||||
{
|
||||
$aResult[$iFolderType] = $oFolder->FullNameRaw();
|
||||
$aResult[$iFolderType] = $oFolder->FullName();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,7 +524,7 @@ trait Folders
|
|||
FolderType::ARCHIVE
|
||||
)))
|
||||
{
|
||||
$aResult[$iFolderType] = $oFolder->FullNameRaw();
|
||||
$aResult[$iFolderType] = $oFolder->FullName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -373,7 +373,7 @@ trait Response
|
|||
'MessageUnseenCount' => (int) $aStatus['UNSEEN'],
|
||||
'UidNext' => (int) $aStatus['UIDNEXT'],
|
||||
'Hash' => $this->MailClient()->GenerateFolderHash(
|
||||
$mResponse->FullNameRaw(), $aStatus['MESSAGES'], $aStatus['UIDNEXT'],
|
||||
$mResponse->FullName(), $aStatus['MESSAGES'], $aStatus['UIDNEXT'],
|
||||
empty($aStatus['HIGHESTMODSEQ']) ? 0 : $aStatus['HIGHESTMODSEQ'])
|
||||
);
|
||||
}
|
||||
|
@ -394,8 +394,8 @@ trait Response
|
|||
return \array_merge(
|
||||
$mResponse->jsonSerialize(),
|
||||
array(
|
||||
'FullNameHash' => $this->hashFolderFullName($mResponse->FullNameRaw(), $mResponse->FullName()),
|
||||
'Checkable' => \in_array($mResponse->FullNameRaw(), $this->aCheckableFolder),
|
||||
'FullNameHash' => $this->hashFolderFullName($mResponse->FullName(), $mResponse->FullName()),
|
||||
'Checkable' => \in_array($mResponse->FullName(), $this->aCheckableFolder),
|
||||
'Extended' => $aExtended,
|
||||
'SubFolders' => $this->responseObject($mResponse->SubFolders(), $sParent, $aParameters)
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue