diff --git a/dev/Common/Html.js b/dev/Common/Html.js index 4df4538e9..8079a01c3 100644 --- a/dev/Common/Html.js +++ b/dev/Common/Html.js @@ -241,7 +241,7 @@ export const )) { skipStyle = true; setAttribute('style', 'display:none'); - setAttribute('data-x-hidden-src', value); + setAttribute('data-x-src-hidden', value); } else if ((attachment = findLocationByCid(value))) { @@ -253,7 +253,9 @@ export const } else if ('cid:' === value.slice(0, 4)) { - attachment = findAttachmentByCid(value.slice(4)); + value = value.slice(4); + setAttribute('data-x-src-cid', value); + attachment = findAttachmentByCid(value); if (attachment && attachment.download) { oElement.src = attachment.linkPreview(); attachment.isInline(true); @@ -267,16 +269,16 @@ export const } else if ('data:image/' === value.slice(0, 11)) { - setAttribute('src', value); + oElement.src = value; } else { - setAttribute('data-x-broken-src', value); + setAttribute('data-x-src-broken', value); } } else { - setAttribute('data-x-broken-src', value); + setAttribute('data-x-src-broken', value); } } diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index 60be08570..e192d7e2a 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -20,7 +20,7 @@ import { folderInformation, messagesDeleteHelper } from 'Common/Folders'; import { serverRequest } from 'Common/Links'; import { i18n, getNotification, getUploadErrorDescByCode, timestampToString } from 'Common/Translator'; import { MessageFlagsCache, setFolderHash } from 'Common/Cache'; -import { Settings, SettingsCapa, SettingsGet, elementById, addShortcut } from 'Common/Globals'; +import { Settings, SettingsCapa, SettingsGet, elementById, addShortcut, createElement } from 'Common/Globals'; //import { exitFullscreen, isFullscreen, toggleFullscreen } from 'Common/Fullscreen'; import { AppUserStore } from 'Stores/User/App'; @@ -50,9 +50,13 @@ import { ThemeStore } from 'Stores/Theme'; let alreadyFullscreen; */ +let oLastMessage; + const ScopeCompose = 'Compose', + tpl = createElement('template'), + base64_encode = text => btoa(unescape(encodeURIComponent(text))).match(/.{1,76}/g).join('\r\n'), email = new EmailModel(), @@ -226,7 +230,6 @@ export class ComposePopupView extends AbstractViewPopup { } }; - this.oLastMessage = null; this.oEditor = null; this.aDraftInfo = null; this.sInReplyTo = ''; @@ -828,7 +831,7 @@ export class ComposePopupView extends AbstractViewPopup { this.editor(editor => { let signature = identity.signature() || '', isHtml = ':HTML:' === signature.slice(0, 6), - fromLine = this.oLastMessage ? emailArrayToStringLineHelper(this.oLastMessage.from, true) : ''; + fromLine = oLastMessage ? emailArrayToStringLineHelper(oLastMessage.from, true) : ''; if (fromLine) { signature = signature.replace(/{{FROM-FULL}}/g, fromLine); if (!fromLine.includes(' ') && 0 < fromLine.indexOf('@')) { @@ -909,24 +912,20 @@ export class ComposePopupView extends AbstractViewPopup { sText = '', identity = null, aDraftInfo = null, - message = null; + message = 1 === arrayLength(oMessageOrArray) + ? oMessageOrArray[0] + : (isArray(oMessageOrArray) ? null : oMessageOrArray); - const excludeEmail = {}, + const +// excludeEmail = new Set(), + excludeEmail = {}, mEmail = AccountUserStore.email(), lineComposeType = sType || ComposeType.Empty; - if (oMessageOrArray) { - message = - 1 === arrayLength(oMessageOrArray) - ? oMessageOrArray[0] - : isArray(oMessageOrArray) - ? null - : oMessageOrArray; - } + oLastMessage = message; - this.oLastMessage = message; - - if (null !== mEmail) { + if (mEmail) { +// excludeEmail.add(mEmail); excludeEmail[mEmail] = true; } @@ -934,6 +933,7 @@ export class ComposePopupView extends AbstractViewPopup { identity = findIdentityByMessage(lineComposeType, message); if (identity) { +// excludeEmail.add(identity.email()); excludeEmail[identity.email()] = true; } @@ -1030,9 +1030,15 @@ export class ComposePopupView extends AbstractViewPopup { // no default } - sText = message.bodyAsHTML().replace(/]+>/g, '').replace(/]+><\/a>/g, ''); let encrypted; + // https://github.com/the-djmaze/snappymail/issues/491 + tpl.innerHTML = message.bodyAsHTML(); + tpl.content.querySelectorAll('img').forEach(img => + img.dataset.xSrcCid || img.dataset.xSrc || img.replaceWith(img.alt || img.title) + ); + sText = tpl.innerHTML.trim(); + switch (lineComposeType) { case ComposeType.Reply: case ComposeType.ReplyAll: @@ -1068,6 +1074,7 @@ export class ComposePopupView extends AbstractViewPopup { case ComposeType.ForwardAsAttachment: sText = ''; break; + default: encrypted = PgpUserStore.isEncrypted(sText); if (encrypted) { @@ -1131,7 +1138,8 @@ export class ComposePopupView extends AbstractViewPopup { this.setFocusInPopup(); } - const downloads = this.getAttachmentsDownloadsForUpload(); + // item.CID item.isInline item.isLinked + const downloads = this.attachments.filter(item => item && !item.tempName()).map(item => item.id); if (arrayLength(downloads)) { Remote.request('MessageUploadAttachments', (iError, oData) => { @@ -1402,35 +1410,22 @@ export class ComposePopupView extends AbstractViewPopup { if (message) { if (ComposeType.ForwardAsAttachment === type) { this.addMessageAsAttachment(message); - } else { + } else if ([ + ComposeType.Reply, ComposeType.ReplyAll, + ComposeType.Forward, ComposeType.Draft, ComposeType.EditAsNew + ].includes(type)) { message.attachments.forEach(item => { - let add = false; - switch (type) { - case ComposeType.Reply: - case ComposeType.ReplyAll: - break; - - case ComposeType.Forward: - case ComposeType.Draft: - case ComposeType.EditAsNew: - add = true; - break; - // no default - } - - if (add) { - const attachment = new ComposeAttachmentModel( - item.download, - item.fileName, - item.estimatedSize, - item.isInline(), - item.isLinked(), - item.cid, - item.contentLocation - ); - attachment.fromMessage = true; - this.addAttachment(attachment); - } + const attachment = new ComposeAttachmentModel( + item.download, + item.fileName, + item.estimatedSize, + item.isInline(), + item.isLinked(), + item.cid, + item.contentLocation + ); + attachment.fromMessage = true; + this.addAttachment(attachment); }); } } @@ -1504,15 +1499,6 @@ export class ComposePopupView extends AbstractViewPopup { this.dropMailvelope(); } - /** - * @returns {Array} - */ - getAttachmentsDownloadsForUpload() { - return this.attachments.filter(item => item && !item.tempName()).map( - item => item.id - ); - } - mailvelopeArea() { if (!this.mailvelope) { /** diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php b/snappymail/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php index 742782f9d..c4e67a674 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php @@ -107,6 +107,8 @@ abstract class HtmlUtils $aRemove = array(); + $sIdRight = \md5(\microtime()); + $aNodes = $oBody->getElementsByTagName('*'); foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) { @@ -114,56 +116,30 @@ abstract class HtmlUtils if (\in_array($sTagNameLower, $aRemoveTags)) { - $aRemove[] = @$oElement; + $aRemove[] = $oElement; continue; } - if ($oElement->hasAttribute('data-x-src-cid')) - { + // images + if ($oElement->hasAttribute('data-x-src-broken') || $oElement->hasAttribute('data-x-src-hidden')) { + $aRemove[] = $oElement; + continue; + } + if ($oElement->hasAttribute('data-x-src-cid')) { $sCid = $oElement->getAttribute('data-x-src-cid'); $oElement->removeAttribute('data-x-src-cid'); - - if (!empty($sCid)) - { + if (!empty($sCid)) { $aFoundCids[] = $sCid; - - @$oElement->removeAttribute('src'); $oElement->setAttribute('src', 'cid:'.$sCid); } } - - if ($oElement->hasAttribute('data-x-src-location')) - { - $sSrc = $oElement->getAttribute('data-x-src-location'); - $oElement->removeAttribute('data-x-src-location'); - - if (!empty($sSrc)) - { - $aFoundContentLocationUrls[] = $sSrc; - - @$oElement->removeAttribute('src'); - $oElement->setAttribute('src', $sSrc); - } - } - - if ($oElement->hasAttribute('data-x-broken-src')) - { - $oElement->setAttribute('src', $oElement->getAttribute('data-x-broken-src')); - $oElement->removeAttribute('data-x-broken-src'); - } - - if ($oElement->hasAttribute('data-x-src')) - { + if ($oElement->hasAttribute('data-x-src')) { $oElement->setAttribute('src', $oElement->getAttribute('data-x-src')); $oElement->removeAttribute('data-x-src'); } // style attribute images $aCid = array(); - if ($oElement->hasAttribute('data-x-style-cid')) { - $aCid = \json_decode($oElement->getAttribute('data-x-style-cid'), true); - $oElement->removeAttribute('data-x-style-cid'); - } if ($oElement->hasAttribute('data-x-style-url')) { $aCid = \array_merge($aCid, \json_decode($oElement->getAttribute('data-x-style-url'), true)); $oElement->removeAttribute('data-x-style-url'); @@ -205,7 +181,7 @@ abstract class HtmlUtils $sSrc = $oElement->getAttribute('src'); if ('data:image/' === \strtolower(\substr($sSrc, 0, 11))) { - $sHash = \md5($sSrc); + $sHash = \md5($sSrc) . '@' . $sIdRight; $aFoundDataURL[$sHash] = $sSrc; $oElement->setAttribute('src', 'cid:'.$sHash);