Better mail message handling

* Cleanup HTML parsing
* Drop useless Microsoft 'Sensitivity' MIME Header
* Revamp Flags handling
This commit is contained in:
djmaze 2021-12-06 16:08:58 +01:00
parent ddbcb4bfa4
commit d734a3e415
17 changed files with 175 additions and 478 deletions

View file

@ -507,14 +507,8 @@ class AppUser extends AbstractApp {
}
if (result.Flags.length) {
result.Flags.forEach(flags =>
MessageFlagsCache.storeByFolderAndUid(folderFromCache.fullName, flags.Uid.toString(), [
!!flags.IsUnseen,
!!flags.IsFlagged,
!!flags.IsAnswered,
!!flags.IsForwarded,
!!flags.IsReadReceipt
])
result.Flags.forEach(message =>
MessageFlagsCache.storeByFolderAndUid(folderFromCache.fullName, message.Uid.toString(), message.Flags)
);
this.reloadFlagsCurrentMessageListAndMessageFromCache();

View file

@ -1,5 +1,5 @@
import { MessageSetAction } from 'Common/EnumsUser';
import { arrayLength, pInt } from 'Common/Utils';
import { isArray, pInt } from 'Common/Utils';
let FOLDERS_CACHE = {},
FOLDERS_NAME_CACHE = {},
@ -176,16 +176,8 @@ export class MessageFlagsCache
const uid = message.uid,
flags = this.getFor(message.folder, uid);
if (flags && flags.length) {
message.isFlagged(!!flags[1]);
if (!message.isSimpleMessage) {
message.isUnseen(!!flags[0]);
message.isAnswered(!!flags[2]);
message.isForwarded(!!flags[3]);
message.isReadReceipt(!!flags[4]);
message.isDeleted(!!flags[5]);
}
if (isArray(flags)) {
message.flags(flags);
}
if (message.threads.length) {
@ -216,14 +208,7 @@ export class MessageFlagsCache
*/
static store(message) {
if (message) {
this.setFor(message.folder, message.uid, [
message.isUnseen(),
message.isFlagged(),
message.isAnswered(),
message.isForwarded(),
message.isReadReceipt(),
message.isDeleted()
]);
this.setFor(message.folder, message.uid, message.flags());
}
}
@ -233,7 +218,7 @@ export class MessageFlagsCache
* @param {Array} flags
*/
static storeByFolderAndUid(folder, uid, flags) {
if (arrayLength(flags)) {
if (isArray(flags)) {
this.setFor(folder, uid, flags);
}
}
@ -245,30 +230,34 @@ export class MessageFlagsCache
*/
static storeBySetAction(folder, uid, setAction) {
let unread = 0;
const flags = this.getFor(folder, uid);
const flags = this.getFor(folder, uid),
remove = item => {
const index = flags.indexOf(item);
if (index > -1) {
flags.splice(index, 1);
}
};
if (arrayLength(flags)) {
if (flags[0]) {
unread = 1;
}
if (isArray(flags)) {
unread = flags.includes('\\seen') ? 0 : 1;
switch (setAction) {
case MessageSetAction.SetSeen:
flags[0] = false;
flags.push('\\seen');
break;
case MessageSetAction.UnsetSeen:
flags[0] = true;
remove('\\seen');
break;
case MessageSetAction.SetFlag:
flags[1] = true;
flags.push('\\flagged');
break;
case MessageSetAction.UnsetFlag:
flags[1] = false;
remove('\\flagged');
break;
// no default
}
this.setFor(folder, uid, flags);
this.setFor(folder, uid, flags.unique());
}
return unread;

View file

@ -56,12 +56,6 @@ export class MessageModel extends AbstractModel {
senderClearEmailsString: '',
deleted: false,
isDeleted: false,
isUnseen: false,
isFlagged: false,
isAnswered: false,
isForwarded: false,
isReadReceipt: false,
focused: false,
selected: false,
@ -86,11 +80,21 @@ export class MessageModel extends AbstractModel {
this.attachmentsSpecData = ko.observableArray();
this.threads = ko.observableArray();
this.unsubsribeLinks = ko.observableArray();
this.flags = ko.observableArray();
this.addComputables({
attachmentIconClass: () => FileInfo.getCombinedIconClass(this.hasAttachments() ? this.attachmentsSpecData() : []),
threadsLen: () => this.threads().length,
isImportant: () => MessagePriority.High === this.priority(),
isDeleted: () => this.flags().includes('\\deleted'),
isUnseen: () => !this.flags().includes('\\seen') /* || this.flags().includes('\\unseen')*/,
isFlagged: () => this.flags().includes('\\flagged'),
isAnswered: () => this.flags().includes('\\answered'),
isForwarded: () => this.flags().includes('$forwarded'),
isReadReceipt: () => this.flags().includes('$mdnsent')
// isJunk: () => this.flags().includes('$junk') && !this.flags().includes('$nonjunk'),
// isPhishing: () => this.flags().includes('$phishing')
});
}
@ -129,12 +133,6 @@ export class MessageModel extends AbstractModel {
this.senderClearEmailsString('');
this.deleted(false);
this.isDeleted(false);
this.isUnseen(false);
this.isFlagged(false);
this.isAnswered(false);
this.isForwarded(false);
this.isReadReceipt(false);
this.selected(false);
this.checked(false);
@ -192,8 +190,8 @@ export class MessageModel extends AbstractModel {
json.Priority = MessagePriority.Normal;
}
if (super.revivePropertiesFromJson(json)) {
// this.foundedCIDs = isArray(json.FoundedCIDs) ? json.FoundedCIDs : [];
// this.attachments(AttachmentCollectionModel.reviveFromJson(json.Attachments, this.foundedCIDs));
// this.foundCIDs = isArray(json.FoundCIDs) ? json.FoundCIDs : [];
// this.attachments(AttachmentCollectionModel.reviveFromJson(json.Attachments, this.foundCIDs));
this.computeSenderEmail();
}
@ -436,12 +434,7 @@ export class MessageModel extends AbstractModel {
this.deliveredTo = message.deliveredTo;
this.unsubsribeLinks(message.unsubsribeLinks);
this.isUnseen(message.isUnseen());
this.isFlagged(message.isFlagged());
this.isAnswered(message.isAnswered());
this.isForwarded(message.isForwarded());
this.isReadReceipt(message.isReadReceipt());
this.isDeleted(message.isDeleted());
this.flags(message.flags());
this.priority(message.priority());

View file

@ -159,8 +159,8 @@ class RemoteUserFetch extends AbstractFetchRemote {
* @param {boolean} bSetSeen
* @param {Array} aThreadUids = null
*/
messageSetSeenToAll(fCallback, sFolderFullName, bSetSeen, aThreadUids = null) {
this.request('MessageSetSeenToAll', fCallback, {
messageSetSeenToAll(sFolderFullName, bSetSeen, aThreadUids = null) {
this.request('MessageSetSeenToAll', null, {
Folder: sFolderFullName,
SetAction: bSetSeen ? 1 : 0,
ThreadUids: aThreadUids ? aThreadUids.join(',') : ''

View file

@ -453,16 +453,11 @@ export const MessageUserStore = new class {
if (message && message.uid == json.Uid) {
oMessage || this.messageError('');
/*
if (cached) {
delete json.IsSeen;
delete json.IsFlagged;
delete json.IsAnswered;
delete json.IsForwarded;
delete json.IsReadReceipt;
delete json.IsDeleted;
delete json.Flags;
}
*/
message.revivePropertiesFromJson(json);
addRequestedMessage(message.folder, message.uid);

View file

@ -452,75 +452,6 @@ export class MailMessageList extends AbstractViewRight {
rl.app.messageListAction(sFolderFullName, iSetAction, aMessages);
}
/**
* @param {string} sFolderFullName
* @param {number} iSetAction
* @param {number} iThreadUid = ''
* @returns {void}
*/
setActionForAll(sFolderFullName, iSetAction, iThreadUid = 0) {
if (sFolderFullName) {
let cnt = 0;
const uids = [];
let folder = getFolderFromCacheList(sFolderFullName);
if (folder) {
switch (iSetAction) {
case MessageSetAction.SetSeen:
MessageUserStore.list.forEach(message => {
if (message.isUnseen()) {
++cnt;
}
message.isUnseen(false);
uids.push(message.uid);
});
if (iThreadUid) {
folder.messageCountUnread(folder.messageCountUnread() - cnt);
if (0 > folder.messageCountUnread()) {
folder.messageCountUnread(0);
}
} else {
folder.messageCountUnread(0);
}
MessageFlagsCache.clearFolder(sFolderFullName);
Remote.messageSetSeenToAll(null, sFolderFullName, true, iThreadUid ? uids : null);
break;
case MessageSetAction.UnsetSeen:
MessageUserStore.list.forEach(message => {
if (!message.isUnseen()) {
++cnt;
}
message.isUnseen(true);
uids.push(message.uid);
});
if (iThreadUid) {
folder.messageCountUnread(folder.messageCountUnread() + cnt);
if (folder.messageCountAll() < folder.messageCountUnread()) {
folder.messageCountUnread(folder.messageCountAll());
}
} else {
folder.messageCountUnread(folder.messageCountAll());
}
MessageFlagsCache.clearFolder(sFolderFullName);
Remote.messageSetSeenToAll(null, sFolderFullName, false, iThreadUid ? uids : null);
break;
// no default
}
rl.app.reloadFlagsCurrentMessageListAndMessageFromCache();
}
}
}
listSetSeen() {
this.setAction(
FolderUserStore.currentFolderFullName(),
@ -530,11 +461,37 @@ export class MailMessageList extends AbstractViewRight {
}
listSetAllSeen() {
this.setActionForAll(
FolderUserStore.currentFolderFullName(),
MessageSetAction.SetSeen,
MessageUserStore.listEndThreadUid()
);
let sFolderFullName = FolderUserStore.currentFolderFullName(),
iThreadUid = MessageUserStore.listEndThreadUid();
if (sFolderFullName) {
let cnt = 0;
const uids = [];
let folder = getFolderFromCacheList(sFolderFullName);
if (folder) {
MessageUserStore.list.forEach(message => {
if (message.isUnseen()) {
++cnt;
}
message.flags.push('\\seen');
// message.flags.valueHasMutated();
uids.push(message.uid);
});
if (iThreadUid) {
folder.messageCountUnread(Math.max(0, folder.messageCountUnread() - cnt));
} else {
folder.messageCountUnread(0);
}
MessageFlagsCache.clearFolder(sFolderFullName);
Remote.messageSetSeenToAll(sFolderFullName, true, iThreadUid ? uids : null);
rl.app.reloadFlagsCurrentMessageListAndMessageFromCache();
}
}
}
listUnsetSeen() {

View file

@ -606,7 +606,8 @@ export class MailMessageView extends AbstractViewRight {
Text: i18n('READ_RECEIPT/BODY', { 'READ-RECEIPT': AccountUserStore.email() })
});
oMessage.isReadReceipt(true);
oMessage.flags.push('$mdnsent');
// oMessage.flags.valueHasMutated();
MessageFlagsCache.store(oMessage);

View file

@ -19,20 +19,17 @@ abstract class HtmlUtils
{
static $KOS = '@@_KOS_@@';
public static function GetElementAttributesAsArray(?\DOMElement $oElement) : array
private static function GetElementAttributesAsArray(?\DOMElement $oElement) : array
{
$aResult = array();
if ($oElement)
if ($oElement && $oElement->hasAttributes() && isset($oElement->attributes) && $oElement->attributes)
{
if ($oElement->hasAttributes() && isset($oElement->attributes) && $oElement->attributes)
foreach ($oElement->attributes as $oAttr)
{
foreach ($oElement->attributes as $oAttr)
if ($oAttr && !empty($oAttr->nodeName))
{
if ($oAttr && !empty($oAttr->nodeName))
{
$sAttrName = \trim(\strtolower($oAttr->nodeName));
$aResult[$sAttrName] = $oAttr->nodeValue;
}
$sAttrName = \trim(\strtolower($oAttr->nodeName));
$aResult[$sAttrName] = $oAttr->nodeValue;
}
}
}
@ -40,7 +37,7 @@ abstract class HtmlUtils
return $aResult;
}
public static function GetDomFromText(string $sText) : \DOMDocument
private static function GetDomFromText(string $sText) : \DOMDocument
{
$bState = true;
if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_use_internal_errors'))
@ -107,7 +104,7 @@ abstract class HtmlUtils
return \trim($sResult);
}
public static function GetTextFromDom(\DOMDocument $oDom, bool $bWrapByFakeHtmlAndBodyDiv = true) : string
private static function GetTextFromDom(\DOMDocument $oDom, bool $bWrapByFakeHtmlAndBodyDiv = true) : string
{
$sResult = '';
@ -151,7 +148,7 @@ abstract class HtmlUtils
return $sResult;
}
public static function ClearBodyAndHtmlTag(string $sHtml, string &$sHtmlAttrs = '', string &$sBodyAttrs = '') : string
private static function ClearBodyAndHtmlTag(string $sHtml, string &$sHtmlAttrs = '', string &$sBodyAttrs = '') : string
{
$aMatch = array();
if (\preg_match('/<html([^>]+)>/im', $sHtml, $aMatch) && !empty($aMatch[1]))
@ -166,7 +163,7 @@ abstract class HtmlUtils
}
// $sHtml = \preg_replace('/^.*<body([^>]*)>/si', '', $sHtml);
$sHtml = \preg_replace('/<\/?(head|body|html|meta)(\\s[^>]*)?>/si', '', $sHtml);
$sHtml = \preg_replace('/<\/?(head|body|html)(\\s[^>]*)?>/si', '', $sHtml);
$sHtmlAttrs = \preg_replace('/xmlns:[a-z]="[^"]*"/i', '', $sHtmlAttrs);
$sHtmlAttrs = \preg_replace('/xmlns:[a-z]=\'[^\']*\'/i', '', $sHtmlAttrs);
@ -181,7 +178,7 @@ abstract class HtmlUtils
return $sHtml;
}
public static function FixSchemas(string $sHtml, bool $bClearEmpty = true) : string
private static function FixSchemas(string $sHtml, bool $bClearEmpty = true) : string
{
if ($bClearEmpty)
{
@ -194,7 +191,7 @@ abstract class HtmlUtils
return $sHtml;
}
public static function ClearFastTags(string $sHtml) : string
private static function ClearFastTags(string $sHtml) : string
{
return \preg_replace(array(
'/<p[^>]*><\/p>/i',
@ -203,7 +200,7 @@ abstract class HtmlUtils
), '', $sHtml);
}
public static function ClearComments(\DOMDocument $oDom) : void
private static function ClearComments(\DOMDocument $oDom) : void
{
$aRemove = array();
@ -228,7 +225,7 @@ abstract class HtmlUtils
}
}
public static function ClearTags(\DOMDocument $oDom, bool $bClearStyleAndHead = true) : void
private static function ClearTags(\DOMDocument $oDom, bool $bClearStyleAndHead = true) : void
{
$aRemoveTags = array(
'svg', 'link', 'base', 'meta', 'title', 'x-script', 'script', 'bgsound', 'keygen', 'source',
@ -274,18 +271,13 @@ abstract class HtmlUtils
/**
* @param callback|null $fAdditionalExternalFilter = null
*/
public static function ClearStyle(string $sStyle, \DOMElement $oElement, bool &$bHasExternals, array &$aFoundCIDs,
array $aContentLocationUrls, array &$aFoundedContentLocationUrls, bool $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null)
private static function ClearStyle(string $sStyle, \DOMElement $oElement, bool &$bHasExternals,
array &$aFoundCIDs, array $aContentLocationUrls, array &$aFoundContentLocationUrls, callable $fAdditionalExternalFilter = null)
{
$sStyle = \trim($sStyle, " \n\r\t\v\0;");
$aOutStyles = array();
$aStyles = \explode(';', $sStyle);
if ($fAdditionalExternalFilter && !\is_callable($fAdditionalExternalFilter))
{
$fAdditionalExternalFilter = null;
}
$aMatch = array();
foreach ($aStyles as $sStyleItem)
{
@ -346,32 +338,29 @@ abstract class HtmlUtils
if (\preg_match('/http[s]?:\/\//i', $sUrl) || '//' === \substr($sUrl, 0, 2))
{
$bHasExternals = true;
if (!$bDoNotReplaceExternalUrl)
if (\in_array($sName, array('background-image', 'list-style-image', 'content')))
{
if (\in_array($sName, array('background-image', 'list-style-image', 'content')))
$sStyleItem = '';
}
$sTemp = '';
if ($oElement->hasAttribute('data-x-style-url'))
{
$sTemp = \trim($oElement->getAttribute('data-x-style-url'));
}
$sTemp = empty($sTemp) ? '' : (';' === \substr($sTemp, -1) ? $sTemp.' ' : $sTemp.'; ');
$oElement->setAttribute('data-x-style-url', \trim($sTemp.
('background' === $sName ? 'background-image' : $sName).': '.$sFullUrl, ' ;'));
if ($fAdditionalExternalFilter)
{
$sAdditionalResult = $fAdditionalExternalFilter($sUrl);
if (\strlen($sAdditionalResult))
{
$sStyleItem = '';
}
$sTemp = '';
if ($oElement->hasAttribute('data-x-style-url'))
{
$sTemp = \trim($oElement->getAttribute('data-x-style-url'));
}
$sTemp = empty($sTemp) ? '' : (';' === \substr($sTemp, -1) ? $sTemp.' ' : $sTemp.'; ');
$oElement->setAttribute('data-x-style-url', \trim($sTemp.
('background' === $sName ? 'background-image' : $sName).': '.$sFullUrl, ' ;'));
if ($fAdditionalExternalFilter)
{
$sAdditionalResult = $fAdditionalExternalFilter($sUrl);
if (\strlen($sAdditionalResult))
{
$oElement->setAttribute('data-x-additional-style-url',
('background' === $sName ? 'background-image' : $sName).': url('.$sAdditionalResult.')');
}
$oElement->setAttribute('data-x-additional-style-url',
('background' === $sName ? 'background-image' : $sName).': url('.$sAdditionalResult.')');
}
}
}
@ -401,104 +390,12 @@ abstract class HtmlUtils
return \implode(';', $aOutStyles);
}
public static function FindLinksInDOM(\DOMDocument $oDom) : void
{
$aNodes = $oDom->getElementsByTagName('*');
foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement)
{
$sTagNameLower = \strtolower($oElement->tagName);
$sParentTagNameLower = isset($oElement->parentNode) && isset($oElement->parentNode->tagName) ?
\strtolower($oElement->parentNode->tagName) : '';
if (!\in_array($sTagNameLower, array('html', 'meta', 'head', 'style', 'script', 'img', 'button', 'input', 'textarea', 'a')) &&
'a' !== $sParentTagNameLower && $oElement->childNodes && 0 < $oElement->childNodes->length)
{
$oSubItem = null;
$aTextNodes = array();
$iIndex = $oElement->childNodes->length - 1;
while ($iIndex > -1)
{
$oSubItem = $oElement->childNodes->item($iIndex);
if ($oSubItem && XML_TEXT_NODE === $oSubItem->nodeType)
{
$aTextNodes[] = $oSubItem;
}
$iIndex--;
}
unset($oSubItem);
foreach ($aTextNodes as $oTextNode)
{
if ($oTextNode && \strlen($oTextNode->wholeText)/* && \preg_match('/http[s]?:\/\//i', $oTextNode->wholeText)*/)
{
$sText = (new \MailSo\Base\LinkFinder)
->Text($oTextNode->wholeText)
->UseDefaultWrappers(true)
->CompileText()
;
$oSubDom = static::GetDomFromText($sText);
if ($oSubDom)
{
$oBodyNodes = $oSubDom->getElementsByTagName('body');
if ($oBodyNodes && 0 < $oBodyNodes->length)
{
$oBodyChildNodes = $oBodyNodes->item(0)->childNodes;
if ($oBodyChildNodes && $oBodyChildNodes->length)
{
for ($iIndex = 0, $iLen = $oBodyChildNodes->length; $iIndex < $iLen; $iIndex++)
{
$oSubItem = $oBodyChildNodes->item($iIndex);
if ($oSubItem)
{
if (XML_ELEMENT_NODE === $oSubItem->nodeType &&
'a' === \strtolower($oSubItem->tagName))
{
$oLink = $oDom->createElement('a',
\str_replace(':', static::$KOS, \htmlspecialchars($oSubItem->nodeValue)));
$sHref = $oSubItem->getAttribute('href');
if ($sHref)
{
$oLink->setAttribute('href', $sHref);
}
$oElement->insertBefore($oLink, $oTextNode);
}
else
{
$oElement->insertBefore($oDom->importNode($oSubItem), $oTextNode);
}
}
}
$oElement->removeChild($oTextNode);
}
}
unset($oBodyNodes);
}
unset($oSubDom, $sText);
}
}
}
}
unset($aNodes);
}
/**
* @param callback|null $fAdditionalExternalFilter = null
* @param callback|null $fAdditionalDomReader = null
* Clears the MailSo\Mail\Message Html for viewing
*/
public static function ClearHtml(string $sHtml, bool &$bHasExternals = false, array &$aFoundCIDs = array(),
array $aContentLocationUrls = array(), array &$aFoundedContentLocationUrls = array(),
bool $bDoNotReplaceExternalUrl = false, bool $bFindLinksInHtml = false,
$fAdditionalExternalFilter = null, $fAdditionalDomReader = false,
bool $bTryToDetectHiddenImages = false, bool $bWrapByFakeHtmlAndBodyDiv = true)
array $aContentLocationUrls = array(), array &$aFoundContentLocationUrls = array(),
callable $fAdditionalExternalFilter = null, bool $bTryToDetectHiddenImages = false)
{
$sResult = '';
@ -514,11 +411,6 @@ abstract class HtmlUtils
$fAdditionalExternalFilter = null;
}
if ($fAdditionalDomReader && !\is_callable($fAdditionalDomReader))
{
$fAdditionalDomReader = null;
}
$bHasExternals = false;
// Dom Part
@ -530,22 +422,6 @@ abstract class HtmlUtils
return '';
}
if ($fAdditionalDomReader)
{
$oResDom = $fAdditionalDomReader($oDom);
if ($oResDom)
{
$oDom = $oResDom;
}
unset($oResDom);
}
if ($bFindLinksInHtml)
{
static::FindLinksInDOM($oDom);
}
static::ClearComments($oDom);
static::ClearTags($oDom);
@ -764,7 +640,7 @@ abstract class HtmlUtils
if (\in_array($sSrc, $aContentLocationUrls))
{
$oElement->setAttribute('data-x-src-location', $sSrc);
$aFoundedContentLocationUrls[] = $sSrc;
$aFoundContentLocationUrls[] = $sSrc;
}
else if ('cid:' === \strtolower(\substr($sSrc, 0, 4)))
{
@ -775,20 +651,13 @@ abstract class HtmlUtils
{
if (\preg_match('/^http[s]?:\/\//i', $sSrc) || '//' === \substr($sSrc, 0, 2))
{
if ($bDoNotReplaceExternalUrl)
$oElement->setAttribute('data-x-src', $sSrc);
if ($fAdditionalExternalFilter)
{
$oElement->setAttribute('src', $sSrc);
}
else
{
$oElement->setAttribute('data-x-src', $sSrc);
if ($fAdditionalExternalFilter)
$sCallResult = $fAdditionalExternalFilter($sSrc);
if (\strlen($sCallResult))
{
$sCallResult = $fAdditionalExternalFilter($sSrc);
if (\strlen($sCallResult))
{
$oElement->setAttribute('data-x-additional-src', $sCallResult);
}
$oElement->setAttribute('data-x-additional-src', $sCallResult);
}
}
@ -833,7 +702,7 @@ abstract class HtmlUtils
{
$oElement->setAttribute('style',
static::ClearStyle($sStyles, $oElement, $bHasExternals,
$aFoundCIDs, $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter));
$aFoundCIDs, $aContentLocationUrls, $aFoundContentLocationUrls, $fAdditionalExternalFilter));
}
if (\MailSo\Config::$HtmlStrictDebug && \count($aRemovedAttrs))
@ -849,13 +718,16 @@ abstract class HtmlUtils
}
}
$sResult = static::GetTextFromDom($oDom, $bWrapByFakeHtmlAndBodyDiv);
$sResult = static::GetTextFromDom($oDom, true);
unset($oDom);
return $sResult;
}
public static function BuildHtml(string $sHtml, array &$aFoundCids = array(), &$mFoundDataURL = null, array &$aFoundedContentLocationUrls = array()) : string
/**
* Used by DoSaveMessage() and DoSendMessage()
*/
public static function BuildHtml(string $sHtml, array &$aFoundCids = array(), &$mFoundDataURL = null, array &$aFoundContentLocationUrls = array()) : string
{
$oDom = static::GetDomFromText($sHtml);
@ -888,7 +760,7 @@ abstract class HtmlUtils
if (!empty($sSrc))
{
$aFoundedContentLocationUrls[] = $sSrc;
$aFoundContentLocationUrls[] = $sSrc;
@$oElement->removeAttribute('src');
$oElement->setAttribute('src', $sSrc);

View file

@ -108,7 +108,6 @@ class MailClient
\MailSo\Mime\Enumerations\Header::REFERENCES,
\MailSo\Mime\Enumerations\Header::DATE,
\MailSo\Mime\Enumerations\Header::SUBJECT,
\MailSo\Mime\Enumerations\Header::SENSITIVITY,
\MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY,
\MailSo\Mime\Enumerations\Header::IMPORTANCE,
\MailSo\Mime\Enumerations\Header::X_PRIORITY,
@ -663,15 +662,7 @@ class MailClient
$aLowerFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS));
$aFlags[] = array(
'Uid' => $iUid,
'IsUnseen' => \in_array('\\unseen', $aLowerFlags) || !\in_array('\\seen', $aLowerFlags),
'IsSeen' => \in_array('\\seen', $aLowerFlags),
'IsFlagged' => \in_array('\\flagged', $aLowerFlags),
'IsAnswered' => \in_array('\\answered', $aLowerFlags),
'IsDeleted' => \in_array('\\deleted', $aLowerFlags),
'IsForwarded' => \in_array(\strtolower('$Forwarded'), $aLowerFlags)/* || ($sForwardedFlag && \in_array(\strtolower($sForwardedFlag), $aLowerFlags))*/,
'IsReadReceipt' => \in_array(\strtolower('$MDNSent'), $aLowerFlags)/* || ($sReadReceiptFlag && \in_array(\strtolower($sReadReceiptFlag), $aLowerFlags))*/,
'IsJunk' => !\in_array(\strtolower('$NonJunk'), $aLowerFlags) && \in_array(\strtolower('$Junk'), $aLowerFlags),
'IsPhishing' => \in_array(\strtolower('$Phishing'), $aLowerFlags)
'Flags' => $aLowerFlags
);
}
}

View file

@ -64,7 +64,6 @@ class Message implements \JsonSerializable
/**
* @var int
*/
$iSensitivity,
$iPriority,
$sDeliveryReceipt = '',
@ -84,7 +83,6 @@ class Message implements \JsonSerializable
function __construct()
{
$this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::NOTHING;
$this->iPriority = \MailSo\Mime\Enumerations\MessagePriority::NORMAL;
}
@ -203,11 +201,6 @@ class Message implements \JsonSerializable
return $this->oFrom;
}
public function Sensitivity() : int
{
return $this->iSensitivity;
}
public function Priority() : int
{
return $this->iPriority;
@ -367,22 +360,6 @@ class Message implements \JsonSerializable
$this->sHeaderDate = $sHeaderDate;
$this->iHeaderTimeStampInUTC = \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($sHeaderDate);
// Sensitivity
$this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::NOTHING;
$sSensitivity = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SENSITIVITY);
switch (\strtolower($sSensitivity))
{
case 'personal':
$this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::PERSONAL;
break;
case 'private':
$this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::PRIVATE_;
break;
case 'company-confidential':
$this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::CONFIDENTIAL;
break;
}
// Priority
$this->iPriority = \MailSo\Mime\Enumerations\MessagePriority::NORMAL;
$sPriority = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY);
@ -674,23 +651,13 @@ class Message implements \JsonSerializable
'Priority' => $this->iPriority,
'Threads' => $this->aThreads,
'Sensitivity' => $this->iSensitivity,
'UnsubsribeLinks' => $this->aUnsubsribeLinks,
'ReadReceipt' => '',
'HasAttachments' => $this->oAttachments && 0 < $this->oAttachments->count(),
'AttachmentsSpecData' => $this->oAttachments ? $this->oAttachments->SpecData() : array(),
// Flags
'IsUnseen' => \in_array('\\unseen', $this->aFlagsLowerCase) || !\in_array('\\seen', $this->aFlagsLowerCase),
'IsSeen' => \in_array('\\seen', $this->aFlagsLowerCase),
'IsFlagged' => \in_array('\\flagged', $this->aFlagsLowerCase),
'IsAnswered' => \in_array('\\answered', $this->aFlagsLowerCase),
'IsDeleted' => \in_array('\\deleted', $this->aFlagsLowerCase),
'IsForwarded' => \in_array(\strtolower('$Forwarded'), $this->aFlagsLowerCase),
'IsReadReceipt' => \in_array(\strtolower('$MDNSent'), $this->aFlagsLowerCase),
'IsJunk' => !\in_array(\strtolower('$NonJunk'), $this->aFlagsLowerCase) && \in_array(\strtolower('$Junk'), $this->aFlagsLowerCase),
'IsPhishing' => \in_array(\strtolower('$Phishing'), $this->aFlagsLowerCase)
'Flags' => $this->aFlagsLowerCase
);
}
}

View file

@ -46,8 +46,6 @@ abstract class Header
CONTENT_ID = 'Content-ID',
CONTENT_LOCATION = 'Content-Location',
SENSITIVITY = 'Sensitivity',
RECEIVED_SPF = 'Received-SPF',
AUTHENTICATION_RESULTS = 'Authentication-Results',
X_DKIM_AUTHENTICATION_RESULTS = 'X-DKIM-Authentication-Results',

View file

@ -1,25 +0,0 @@
<?php
/*
* This file is part of MailSo.
*
* (c) 2014 Usenko Timur
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace MailSo\Mime\Enumerations;
/**
* @category MailSo
* @package Mime
* @subpackage Enumerations
*/
abstract class Sensitivity
{
const NOTHING = 0;
const CONFIDENTIAL = 1;
const PRIVATE_ = 2;
const PERSONAL = 3;
}

View file

@ -228,30 +228,6 @@ class Message
return $this;
}
public function SetSensitivity(int $iValue) : self
{
$sResult = '';
switch ($iValue)
{
case Enumerations\Sensitivity::CONFIDENTIAL:
$sResult = 'Company-Confidential';
break;
case Enumerations\Sensitivity::PERSONAL:
$sResult = 'Personal';
break;
case Enumerations\Sensitivity::PRIVATE_:
$sResult = 'Private';
break;
}
if (\strlen($sResult))
{
$this->aHeadersValue[Enumerations\Header::SENSITIVITY] = $sResult;
}
return $this;
}
public function SetXMailer(string $sXMailer) : self
{
$this->aHeadersValue[Enumerations\Header::X_MAILER] = $sXMailer;

View file

@ -1015,12 +1015,12 @@ trait Messages
$oMessage->SetReferences($sReferences);
}
$aFoundedCids = array();
$aFoundCids = array();
$mFoundDataURL = array();
$aFoundedContentLocationUrls = array();
$aFoundContentLocationUrls = array();
$sTextToAdd = $bTextIsHtml ?
\MailSo\Base\HtmlUtils::BuildHtml($sText, $aFoundedCids, $mFoundDataURL, $aFoundedContentLocationUrls) : $sText;
\MailSo\Base\HtmlUtils::BuildHtml($sText, $aFoundCids, $mFoundDataURL, $aFoundContentLocationUrls) : $sText;
$this->Plugins()->RunHook($bTextIsHtml ? 'filter.message-html' : 'filter.message-plain',
array($oAccount, $oMessage, &$sTextToAdd));
@ -1050,7 +1050,7 @@ trait Messages
$oMessage->Attachments()->append(
new \MailSo\Mime\Attachment($rResource, $sFileName, $iFileSize, $bIsInline,
\in_array(trim(trim($sCID), '<>'), $aFoundedCids),
\in_array(trim(trim($sCID), '<>'), $aFoundCids),
$sCID, array(), $sContentLocation
)
);

View file

@ -150,7 +150,6 @@ trait Response
*
* @return mixed
*/
private $oAccount = null;
private $aCheckableFolder = null;
private function responseObject($mResponse, string $sParent = '', array $aParameters = array())
{
@ -176,10 +175,7 @@ trait Response
{
$mResult = $mResponse->jsonSerialize();
if (null === $this->oAccount) {
$this->oAccount = $this->getAccountFromToken(false);
}
$oAccount = $this->oAccount;
$oAccount = $this->getAccountFromToken();
if (!$mResult['DateTimeStampInUTC'] || !!$this->Config()->Get('labs', 'date_from_headers', false)) {
$iDateTimeStampInUTC = $mResponse->HeaderTimeStampInUTC();
@ -204,21 +200,20 @@ trait Response
'FileName' => (\strlen($sSubject) ? \MailSo\Base\Utils::ClearXss($sSubject) : 'message-'.$mResult['Uid']) . '.eml'
));
$sForwardedFlag = $this->Config()->Get('labs', 'imap_forwarded_flag', '');
$sReadReceiptFlag = $this->Config()->Get('labs', 'imap_read_receipt_flag', '');
$aFlags = $mResponse->FlagsLowerCase();
$mResult['IsForwarded'] = \strlen($sForwardedFlag) && \in_array(\strtolower($sForwardedFlag), $aFlags);
$mResult['IsReadReceipt'] = \strlen($sReadReceiptFlag) && \in_array(\strtolower($sReadReceiptFlag), $aFlags);
$sForwardedFlag = \strtolower($this->Config()->Get('labs', 'imap_forwarded_flag', ''));
$sReadReceiptFlag = \strtolower($this->Config()->Get('labs', 'imap_read_receipt_flag', ''));
\strlen($sForwardedFlag) && \in_array($sForwardedFlag, $mResult['Flags']) && \array_push($mResult['Flags'], '$forwarded');
\strlen($sReadReceiptFlag) && \in_array($sReadReceiptFlag, $mResult['Flags']) && \array_push($mResult['Flags'], '$mdnsent');
$mResult['Flags'] = \array_unique($mResult['Flags']);
if ('Message' === $sParent)
{
$oAttachments = /* @var \MailSo\Mail\AttachmentCollection */ $mResponse->Attachments();
$bHasExternals = false;
$mFoundedCIDs = array();
$mFoundCIDs = array();
$aContentLocationUrls = array();
$mFoundedContentLocationUrls = array();
$mFoundContentLocationUrls = array();
if ($oAttachments && 0 < $oAttachments->count())
{
@ -265,8 +260,8 @@ trait Response
}, $sHtml);
$mResult['Html'] = \strlen($sHtml) ? \MailSo\Base\HtmlUtils::ClearHtml(
$sHtml, $bHasExternals, $mFoundedCIDs, $aContentLocationUrls, $mFoundedContentLocationUrls, false, false,
$fAdditionalExternalFilter, null, !!$this->Config()->Get('labs', 'try_to_detect_hidden_images', false)
$sHtml, $bHasExternals, $mFoundCIDs, $aContentLocationUrls, $mFoundContentLocationUrls,
$fAdditionalExternalFilter, !!$this->Config()->Get('labs', 'try_to_detect_hidden_images', false)
) : '';
$mResult['ExternalProxy'] = null !== $fAdditionalExternalFilter;
@ -274,26 +269,25 @@ trait Response
$mResult['Plain'] = $sPlain;
// $mResult['Plain'] = \strlen($sPlain) ? \MailSo\Base\HtmlUtils::ConvertPlainToHtml($sPlain) : '';
$mResult['TextHash'] = \md5($mResult['Html'].$mResult['Plain']);
$mResult['isPgpSigned'] = $mResponse->isPgpSigned();
$mResult['isPgpEncrypted'] = $mResponse->isPgpEncrypted();
$mResult['PgpSignature'] = $mResponse->PgpSignature();
$mResult['PgpSignatureMicAlg'] = $mResponse->PgpSignatureMicAlg();
// $mResult['PgpSignature'] = $mResponse->PgpSignature();
// $mResult['PgpSignatureMicAlg'] = $mResponse->PgpSignatureMicAlg();
unset($sHtml, $sPlain);
$mResult['HasExternals'] = $bHasExternals;
$mResult['HasInternals'] = (\is_array($mFoundedCIDs) && \count($mFoundedCIDs)) ||
(\is_array($mFoundedContentLocationUrls) && \count($mFoundedContentLocationUrls));
$mResult['FoundedCIDs'] = $mFoundedCIDs;
$mResult['HasInternals'] = (\is_array($mFoundCIDs) && \count($mFoundCIDs)) ||
(\is_array($mFoundContentLocationUrls) && \count($mFoundContentLocationUrls));
// $mResult['FoundCIDs'] = $mFoundCIDs;
$mResult['Attachments'] = $this->responseObject($oAttachments, $sParent, \array_merge($aParameters, array(
'FoundedCIDs' => $mFoundedCIDs,
'FoundedContentLocationUrls' => $mFoundedContentLocationUrls
'FoundCIDs' => $mFoundCIDs,
'FoundContentLocationUrls' => $mFoundContentLocationUrls
)));
$mResult['ReadReceipt'] = $mResponse->ReadReceipt();
if (\strlen($mResult['ReadReceipt']) && !$mResult['IsReadReceipt'])
if (\strlen($mResult['ReadReceipt']) && !\in_array('$forwarded', $mResult['Flags']))
{
if (\strlen($mResult['ReadReceipt']))
{
@ -322,36 +316,34 @@ trait Response
{
$mResult = $mResponse->jsonSerialize();
if (null === $this->oAccount) {
$this->oAccount = $this->getAccountFromToken(false);
}
$oAccount = $this->getAccountFromToken();
$mFoundedCIDs = isset($aParameters['FoundedCIDs']) && \is_array($aParameters['FoundedCIDs']) &&
\count($aParameters['FoundedCIDs']) ?
$aParameters['FoundedCIDs'] : null;
$mFoundCIDs = isset($aParameters['FoundCIDs']) && \is_array($aParameters['FoundCIDs']) &&
\count($aParameters['FoundCIDs']) ?
$aParameters['FoundCIDs'] : null;
$mFoundedContentLocationUrls = isset($aParameters['FoundedContentLocationUrls']) &&
\is_array($aParameters['FoundedContentLocationUrls']) &&
\count($aParameters['FoundedContentLocationUrls']) ?
$aParameters['FoundedContentLocationUrls'] : null;
$mFoundContentLocationUrls = isset($aParameters['FoundContentLocationUrls']) &&
\is_array($aParameters['FoundContentLocationUrls']) &&
\count($aParameters['FoundContentLocationUrls']) ?
$aParameters['FoundContentLocationUrls'] : null;
if ($mFoundedCIDs || $mFoundedContentLocationUrls)
if ($mFoundCIDs || $mFoundContentLocationUrls)
{
$mFoundedCIDs = \array_merge($mFoundedCIDs ? $mFoundedCIDs : array(),
$mFoundedContentLocationUrls ? $mFoundedContentLocationUrls : array());
$mFoundCIDs = \array_merge($mFoundCIDs ? $mFoundCIDs : array(),
$mFoundContentLocationUrls ? $mFoundContentLocationUrls : array());
$mFoundedCIDs = \count($mFoundedCIDs) ? $mFoundedCIDs : null;
$mFoundCIDs = \count($mFoundCIDs) ? $mFoundCIDs : null;
}
$mResult['IsLinked'] = ($mFoundedCIDs && \in_array(\trim(\trim($mResponse->Cid()), '<>'), $mFoundedCIDs))
|| ($mFoundedContentLocationUrls && \in_array(\trim($mResponse->ContentLocation()), $mFoundedContentLocationUrls));
$mResult['IsLinked'] = ($mFoundCIDs && \in_array(\trim(\trim($mResponse->Cid()), '<>'), $mFoundCIDs))
|| ($mFoundContentLocationUrls && \in_array(\trim($mResponse->ContentLocation()), $mFoundContentLocationUrls));
$mResult['Framed'] = $this->isFileHasFramedPreview($mResult['FileName']);
$mResult['IsThumbnail'] = $this->GetCapa(false, Capa::ATTACHMENT_THUMBNAILS) && $this->isFileHasThumbnail($mResult['FileName']);
$mResult['Download'] = Utils::EncodeKeyValuesQ(array(
'V' => APP_VERSION,
'Account' => $this->oAccount ? \md5($this->oAccount->Hash()) : '',
'Account' => $oAccount ? \md5($oAccount->Hash()) : '',
'Folder' => $mResult['Folder'],
'Uid' => $mResult['Uid'],
'MimeIndex' => $mResult['MimeIndex'],
@ -379,12 +371,9 @@ trait Response
if (null === $this->aCheckableFolder)
{
if (null === $this->oAccount) {
$this->oAccount = $this->getAccountFromToken(false);
}
$aCheckable = \json_decode(
$this->SettingsProvider(true)
->Load($this->oAccount)
->Load($this->getAccountFromToken())
->GetConf('CheckableFolder', '[]')
);
$this->aCheckableFolder = \is_array($aCheckable) ? $aCheckable : array();

View file

@ -4,9 +4,9 @@ namespace RainLoop\Plugins;
class Helper
{
static public function ValidateWildcardValues(string $sString, string $sWildcardValues, string &$sFoundedValue = null) : bool
static public function ValidateWildcardValues(string $sString, string $sWildcardValues, string &$sFoundValue = null) : bool
{
$sFoundedValue = '';
$sFoundValue = '';
$sString = \trim($sString);
if ('' === $sString)
@ -22,7 +22,7 @@ class Helper
if ('*' === $sWildcardValues)
{
$sFoundedValue = '*';
$sFoundValue = '*';
return true;
}
@ -35,7 +35,7 @@ class Helper
{
if ($sString === $sItem)
{
$sFoundedValue = $sItem;
$sFoundValue = $sItem;
return true;
}
}
@ -48,7 +48,7 @@ class Helper
if (\preg_match('/'.\implode('.*', $aItem).'/', $sString))
{
$sFoundedValue = $sItem;
$sFoundValue = $sItem;
return true;
}
}

View file

@ -91,7 +91,7 @@ class DefaultDomain implements \RainLoop\Providers\Domain\DomainAdminInterface
$mResult = null;
$sDisabled = '';
$sFoundedValue = '';
$sFoundValue = '';
$sRealFileName = $this->codeFileName($sName);
@ -137,11 +137,11 @@ class DefaultDomain implements \RainLoop\Providers\Domain\DomainAdminInterface
if (\strlen($sNames))
{
if (\RainLoop\Plugins\Helper::ValidateWildcardValues(
\MailSo\Base\Utils::IdnToUtf8($sName, true), $sNames, $sFoundedValue) && \strlen($sFoundedValue))
\MailSo\Base\Utils::IdnToUtf8($sName, true), $sNames, $sFoundValue) && \strlen($sFoundValue))
{
if (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.$sFoundedValue.','))
if (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.$sFoundValue.','))
{
$mResult = $this->Load($sFoundedValue, false);
$mResult = $this->Load($sFoundValue, false);
}
}
}