From 1bdd70570a98c75aae787f90e057b8cb4d9ae321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean=20Charles=20Del=C3=A9pine?= Date: Sat, 1 Aug 2026 14:33:03 +0200 Subject: [PATCH] feat(imp): add "block remote images only" mode to image replacement preference Add a third option to the image_replacement preference (value 2) that shows inline (cid:) images while blocking remote ones. Update the HTML MIME viewer to skip blocking for already-resolved cid: images in this mode, display a distinct notification for remote image blocking, and update the English help text accordingly. --- config/prefs.php | 15 ++++++++++----- lib/Mime/Viewer/Html.php | 30 +++++++++++++++++++++++++++--- locale/en/help.xml | 5 ++++- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/config/prefs.php b/config/prefs.php index 797604699..b0d5a29ff 100644 --- a/config/prefs.php +++ b/config/prefs.php @@ -1013,12 +1013,17 @@ }, ]; -$_prefs['image_replacement'] = [ - 'value' => 1, - 'type' => 'checkbox', - 'desc' => _("Block images in messages unless they are specifically requested to be loaded?"), +$_prefs['image_replacement'] = array( + 'value' => 2, + 'type' => 'enum', + 'enum' => array( + 0 => _("Show all images"), + 1 => _("Block all images in messages unless they are specifically requested to be loaded?"), + 2 => _("Show inline images, block remote images"), + ), + 'desc' => _("How should images in HTML messages be handled?"), 'help' => 'prefs-image_replacement', -]; +); $_prefs['image_replacement_manage'] = [ 'type' => 'special', diff --git a/lib/Mime/Viewer/Html.php b/lib/Mime/Viewer/Html.php index e6bcd84f0..70b2bd08e 100644 --- a/lib/Mime/Viewer/Html.php +++ b/lib/Mime/Viewer/Html.php @@ -146,6 +146,7 @@ protected function _IMPrender($inline) 'imgblock' => false, 'imgbroken' => false, 'inline' => $inline, + 'remoteblock' => false, 'style' => [], ]; } @@ -231,8 +232,13 @@ protected function _IMPrender($inline) $link = $text = null; if ($this->_imptmp['imgblock']) { - $text = _('Images have been blocked in this message part.'); - $link = _('Show Images?'); + if ($this->_imptmp['remoteblock']) { + $text = _('Remote images have been blocked in this message part.'); + $link = _('Load Remote Images?'); + } else { + $text = _('Images have been blocked in this message part.'); + $link = _('Show Images?'); + } } elseif ($this->_imptmp['cssblock']) { $text = _('Message styling has been suppressed in this message part since the style data lives on a remote server.'); $link = _('Load Styling?'); @@ -372,6 +378,7 @@ protected function _node($doc, $node) $val = $node->getAttribute('src'); /* Multipart/related. */ + $is_cid = false; if (($tag == 'img') && ($id = $this->_cidSearch($val))) { $val = $this->getConfigParam('imp_contents')->urlView(null, 'view_attach', ['params' => [ 'ctype' => 'image/*', @@ -381,7 +388,7 @@ protected function _node($doc, $node) } /* Block images.*/ - if ($this->_imgBlock()) { + if ($this->_imgBlock() && !($is_cid && $this->_isRemoteBlock())) { if (Horde_Url_Data::isData($val)) { $url = new Horde_Url_Data($val); } else { @@ -401,6 +408,9 @@ protected function _node($doc, $node) $node->setAttribute(self::IMGBLOCK, $url); $node->setAttribute('src', $this->_imgBlockImg()); $this->_imptmp['imgblock'] = true; + if ($this->_isRemoteBlock()) { + $this->_imptmp['remoteblock'] = true; + } } else { $node->parentNode->removeChild($node); $this->_imptmp['imgbroken'] = true; @@ -636,6 +646,9 @@ protected function _styleCallback($matches) } else { $this->_imptmp['node']->setAttribute(self::IMGBLOCK, $matches[2]); $this->_imptmp['imgblock'] = true; + if ($this->_isRemoteBlock()) { + $this->_imptmp['remoteblock'] = true; + } $replace = $this->_imgBlockImg(); } return $matches[1] . $replace . $matches[3]; @@ -700,4 +713,15 @@ protected function _imgBlockImg() return $this->_imptmp['blockimg']; } + /** + * Are we in "block remote images only" mode? + * + * @return boolean True if only remote images are blocked. + */ + protected function _isRemoteBlock() + { + global $prefs; + + return ($prefs->getValue('image_replacement') == 2); + } } diff --git a/locale/en/help.xml b/locale/en/help.xml index a26247486..c57348bd6 100644 --- a/locale/en/help.xml +++ b/locale/en/help.xml @@ -571,7 +571,10 @@ Message: Preferences: Image Replacement - For messages displayed inline (i.e. on the message view page), should all image tags be blocked until you specifically decide to view those images? Note that, if explicitly viewing the attachment, images will always be displayed. + For messages displayed inline (i.e. on the message view page), controls how images embedded in HTML messages are handled: show all images (including remote ones, which may be used by senders to track whether you have read a message); show only images attached directly to the message while blocking those loaded from remote servers (recommended); or block all images until you specifically decide to view them. + + + In all blocking modes, a notification appears allowing you to unblock images on a per-message basis, or to permanently allow images from a given sender. Note that, if explicitly viewing the attachment, images will always be displayed.