From 73499db1c70f7cb956b6bc098de33d356a759d25 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 15 May 2015 14:00:37 +0000 Subject: [PATCH] WIP mail inline image - Define static methods for resolving inline images from CID, based on types - Fix not showing inline images on reply --- mail/inc/class.mail_compose.inc.php | 3 +- mail/inc/class.mail_ui.inc.php | 259 +++++++++++++--------------- 2 files changed, 123 insertions(+), 139 deletions(-) diff --git a/mail/inc/class.mail_compose.inc.php b/mail/inc/class.mail_compose.inc.php index 512707ca28..90e7ee555a 100644 --- a/mail/inc/class.mail_compose.inc.php +++ b/mail/inc/class.mail_compose.inc.php @@ -2081,6 +2081,7 @@ class mail_compose } $this->sessionData['body'] .= '
'; + $this->sessionData['body'] = mail_ui::resolve_inline_images($this->sessionData['body'], $_folder, $_uid, $_partID, 'html'); } else { //$this->sessionData['body'] = @htmlspecialchars(lang("on")." ".$headers['DATE']." ".$mail_bo->decode_header($fromAddress), ENT_QUOTES) . " ".lang("wrote").":\r\n"; // take care the way the ReplyHeader is created here, is used later on in uicompose::compose, in case you force replys to be HTML (prefs) @@ -2100,7 +2101,7 @@ class mail_compose if ($bodyParts[$i]['charSet']===false) $bodyParts[$i]['charSet'] = mail_bo::detect_encoding($bodyParts[$i]['body']); $newBody = translation::convert($bodyParts[$i]['body'], $bodyParts[$i]['charSet']); #error_log( "GetReplyData (Plain) CharSet:".mb_detect_encoding($bodyParts[$i]['body'] . 'a' , strtoupper($bodyParts[$i]['charSet']).','.strtoupper($this->displayCharset).',UTF-8, ISO-8859-1')); - + $newBody = mail_ui::resolve_inline_images($newBody, $_folder, $_uid, $_partID, 'plain'); $this->sessionData['body'] .= "\r\n"; // create body new, with good line breaks and indention foreach(explode("\n",$newBody) as $value) { diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 60927f5319..f4182bf3e3 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -3013,7 +3013,7 @@ class mail_ui // create links for inline images if ($modifyURI) { - $newBody = preg_replace_callback("/\[cid:(.*)\]/iU",array($this,'image_callback_plain'),$newBody); + $newBody = self::resolve_inline_images($newBody, $this->mailbox, $this->uid, $this->partID, 'plain'); } //TODO:$newBody = $this->highlightQuotes($newBody); @@ -3064,9 +3064,7 @@ class mail_ui // create links for inline images if ($modifyURI) { - $newBody = preg_replace_callback("/src=(\"|\')cid:(.*)(\"|\')/iU",array($this,'image_callback'),$newBody); - $newBody = preg_replace_callback("/url\(cid:(.*)\);/iU",array($this,'image_callback_url'),$newBody); - $newBody = preg_replace_callback("/background=(\"|\')cid:(.*)(\"|\')/iU",array($this,'image_callback_background'),$newBody); + $newBody = self::resolve_inline_images ($newBody, $this->mailbox, $this->uid, $this->partID); } // email addresses / mailto links get now activated on client-side } @@ -3082,161 +3080,146 @@ class mail_ui return $body; } - + /** - * preg_replace callback to replace image cid url's + * Resolve inline images from CID to proper url * - * @param array $matches matches from preg_replace("/src=(\"|\')cid:(.*)(\"|\')/iU",...) - * @return string src attribute to replace + * @param string $_body message content + * @param string $_mailbox mail folder + * @param string $_uid uid + * @param string $_partID part id + * @param string $_messageType = 'html', message type is either html or plain + * @return string message body including all CID images replaced */ - function image_callback($matches) + public static function resolve_inline_images ($_body,$_mailbox, $_uid, $_partID, $_messageType = 'html') { - static $cache = array(); // some caching, if mails containing the same image multiple times - - $linkData = array ( - 'menuaction' => 'mail.mail_ui.displayImage', - 'uid' => $this->uid, - 'mailbox' => base64_encode($this->mailbox), - 'cid' => base64_encode($matches[2]), - 'partID' => $this->partID, - ); - $imageURL = egw::link('/index.php', $linkData); - - // to test without data uris, comment the if close incl. it's body - if (html::$user_agent != 'msie' || html::$ua_version >= 8) + if ($_messageType === 'plain') { - if (!isset($cache[$imageURL])) - { - $attachment = $this->mail_bo->getAttachmentByCID($this->uid, $matches[2], $this->partID); - - // only use data uri for "smaller" images, as otherwise the first display of the mail takes to long - if (($attachment instanceof Horde_Mime_Part) && $attachment->getBytes() < 8192) // msie=8 allows max 32k data uris - { - $this->mail_bo->fetchPartContents($this->uid, $attachment); - $cache[$imageURL] = 'data:'.$attachment->getType().';base64,'.base64_encode($attachment->getContents()); - } - else - { - $cache[$imageURL] = $imageURL; - } - } - $imageURL = $cache[$imageURL]; + return self::resolve_inline_image_byType($_body, $_mailbox, $_uid, $_partID, 'plain'); + } + else + { + foreach(array('src','url','background') as $type) + { + $_body = self::resolve_inline_image_byType($_body, $_mailbox, $_uid, $_partID, $type); + } + return $_body; } - return 'src="'.$imageURL.'"'; } - + /** - * preg_replace callback to replace image cid url's + * Replace CID with proper type of content understandable by browser * - * @param array $matches matches from preg_replace("/src=(\"|\')cid:(.*)(\"|\')/iU",...) - * @return string src attribute to replace + * @param type $_body content of message + * @param type $_mailbox mail box + * @param type $_uid uid + * @param type $_partID part id + * @param type $_type = 'src' type of inline image that needs to be resolved and replaced + * - types: {plain|src|url|background} + * @return string returns body content including all CID replacements */ - function image_callback_plain($matches) + public static function resolve_inline_image_byType ($_body,$_mailbox, $_uid, $_partID, $_type ='src') { - static $cache = array(); // some caching, if mails containing the same image multiple times - //error_log(__METHOD__.__LINE__.array2string($matches)); - $linkData = array ( - 'menuaction' => 'mail.mail_ui.displayImage', - 'uid' => $this->uid, - 'mailbox' => base64_encode($this->mailbox), - 'cid' => base64_encode($matches[1]), - 'partID' => $this->partID, - ); - $imageURL = egw::link('/index.php', $linkData); - - // to test without data uris, comment the if close incl. it's body - if (html::$user_agent != 'msie' || html::$ua_version >= 8) + /** + * Callback for preg_replace_callback function + * returns matched CID replacement string based on given type + * @param array $matches + * @param string $_mailbox + * @param string $_uid + * @param string $_partID + * @param string $_type + * @return string|boolean returns the replace + */ + $replace_callback = function ($matches) use ($_mailbox,$_uid, $_partID, $_type) { - if (!isset($cache[$imageURL])) + if (!$_type) return false; + $CID = ''; + // Build up matches according to selected type + switch ($_type) { - $attachment = $this->mail_bo->getAttachmentByCID($this->uid, $matches[1], $this->partID); + case "plain": + $CID = $matches[1]; + break; + case "src": + $CID = $matches[2]; + break; + case "url": + $CID = $matches[1]; + break; + case "background": + $CID = $matches[2]; + break; + } - // only use data uri for "smaller" images, as otherwise the first display of the mail takes to long - if (($attachment instanceof Horde_Mime_Part) && bytes($attachment->getBytes()) < 8192) // msie=8 allows max 32k data uris + static $cache = array(); // some caching, if mails containing the same image multiple times + + if (is_array($matches) && $CID) + { + $linkData = array ( + 'menuaction' => 'mail.mail_ui.displayImage', + 'uid' => $_uid, + 'mailbox' => base64_encode($_mailbox), + 'cid' => base64_encode($CID), + 'partID' => $_partID, + ); + $imageURL = egw::link('/index.php', $linkData); + // to test without data uris, comment the if close incl. it's body + if (html::$user_agent != 'msie' || html::$ua_version >= 8) { - $this->mail_bo->fetchPartContents($this->uid, $attachment); - $cache[$imageURL] = 'data:'.$attachment->getType().';base64,'.base64_encode($attachment->getContents()); + if (!isset($cache[$imageURL])) + { + if ($_type !="background") + { + $bo = emailadmin_imapbase::getInstance(false, self::$icServerID); + $attachment = $bo->getAttachmentByCID($_uid, $CID, $_partID); + + // only use data uri for "smaller" images, as otherwise the first display of the mail takes to long + if (($attachment instanceof Horde_Mime_Part) && $attachment->getBytes() < 8192) // msie=8 allows max 32k data uris + { + $bo->fetchPartContents($_uid, $attachment); + $cache[$imageURL] = 'data:'.$attachment->getType().';base64,'.base64_encode($attachment->getContents()); + } + else + { + $cache[$imageURL] = $imageURL; + } + } + else + { + $cache[$imageURL] = $imageURL; + } + } + $imageURL = $cache[$imageURL]; } - else + + // Decides the final result of replacement according to the type + switch ($_type) { - $cache[$imageURL] = $imageURL; + case "plain": + return ''; + case "src": + return 'src="'.$imageURL.'"'; + case "url": + return 'url('.$imageURL.');'; + case "background": + return 'background="'.$imageURL.'"'; } } - $imageURL = $cache[$imageURL]; - } - return ''; - } - - /** - * preg_replace callback to replace image cid url's - * - * @param array $matches matches from preg_replace("/src=(\"|\')cid:(.*)(\"|\')/iU",...) - * @return string src attribute to replace - */ - function image_callback_url($matches) - { - static $cache = array(); // some caching, if mails containing the same image multiple times - //error_log(__METHOD__.__LINE__.array2string($matches)); - $linkData = array ( - 'menuaction' => 'mail.mail_ui.displayImage', - 'uid' => $this->uid, - 'mailbox' => base64_encode($this->mailbox), - 'cid' => base64_encode($matches[1]), - 'partID' => $this->partID, - ); - $imageURL = egw::link('/index.php', $linkData); - - // to test without data uris, comment the if close incl. it's body - if (html::$user_agent != 'msie' || html::$ua_version >= 8) + return false; + }; + + // return new body content base on chosen type + switch($_type) { - if (!isset($cache[$imageURL])) - { - $attachment = $this->mail_bo->getAttachmentByCID($this->uid, $matches[1], $this->partID); - - // only use data uri for "smaller" images, as otherwise the first display of the mail takes to long - if (($attachment instanceof Horde_Mime_Part) && $attachment->getBytes() < 8192) // msie=8 allows max 32k data uris - { - $this->mail_bo->fetchPartContents($this->uid, $attachment); - $cache[$imageURL] = 'data:'.$attachment->getType().';base64,'.base64_encode($attachment->getContents()); - } - else - { - $cache[$imageURL] = $imageURL; - } - } - $imageURL = $cache[$imageURL]; + case"plain": + return preg_replace_callback("/\[cid:(.*)\]/iU",$replace_callback,$_body); + case "src": + return preg_replace_callback("/src=(\"|\')cid:(.*)(\"|\')/iU",$replace_callback,$_body); + case "url": + return preg_replace_callback("/url\(cid:(.*)\);/iU",$replace_callback,$_body); + case "background": + return preg_replace_callback("/background=(\"|\')cid:(.*)(\"|\')/iU",$replace_callback,$_body); } - return 'url('.$imageURL.');'; - } - - /** - * preg_replace callback to replace image cid url's - * - * @param array $matches matches from preg_replace("/src=(\"|\')cid:(.*)(\"|\')/iU",...) - * @return string src attribute to replace - */ - function image_callback_background($matches) - { - static $cache = array(); // some caching, if mails containing the same image multiple times - $linkData = array ( - 'menuaction' => 'mail.mail_ui.displayImage', - 'uid' => $this->uid, - 'mailbox' => base64_encode($this->mailbox), - 'cid' => base64_encode($matches[2]), - 'partID' => $this->partID, - ); - $imageURL = egw::link('/index.php', $linkData); - - // to test without data uris, comment the if close incl. it's body - if (html::$user_agent != 'msie' || html::$ua_version >= 8) - { - if (!isset($cache[$imageURL])) - { - $cache[$imageURL] = $imageURL; - } - $imageURL = $cache[$imageURL]; - } - return 'background="'.$imageURL.'"'; } /**