Overview

Packages

  • IMP
  • None

Classes

  • IMP
  • IMP_Ajax_Application
  • IMP_Ajax_Imple_ContactAutoCompleter
  • IMP_Ajax_Imple_PassphraseDialog
  • IMP_Ajax_Queue
  • IMP_Api
  • IMP_Auth
  • IMP_Block_Newmail
  • IMP_Block_Summary
  • IMP_Compose
  • IMP_Compose_Exception
  • IMP_Compose_Stationery
  • IMP_Contents
  • IMP_Crypt_Pgp
  • IMP_Crypt_Smime
  • IMP_Dimp
  • IMP_Exception
  • IMP_Factory_AuthImap
  • IMP_Factory_Compose
  • IMP_Factory_Contents
  • IMP_Factory_Flags
  • IMP_Factory_Identity
  • IMP_Factory_Imap
  • IMP_Factory_Imaptree
  • IMP_Factory_Mail
  • IMP_Factory_Mailbox
  • IMP_Factory_MailboxList
  • IMP_Factory_MimeViewer
  • IMP_Factory_Pgp
  • IMP_Factory_Quota
  • IMP_Factory_Search
  • IMP_Factory_Sentmail
  • IMP_Factory_Smime
  • IMP_Filter
  • IMP_Flag_Base
  • IMP_Flag_Imap
  • IMP_Flag_Imap_Answered
  • IMP_Flag_Imap_Deleted
  • IMP_Flag_Imap_Draft
  • IMP_Flag_Imap_Flagged
  • IMP_Flag_Imap_Forwarded
  • IMP_Flag_Imap_Junk
  • IMP_Flag_Imap_NotJunk
  • IMP_Flag_Imap_Seen
  • IMP_Flag_System_Attachment
  • IMP_Flag_System_Encrypted
  • IMP_Flag_System_HighPriority
  • IMP_Flag_System_List
  • IMP_Flag_System_LowPriority
  • IMP_Flag_System_Match_Address
  • IMP_Flag_System_Match_Flag
  • IMP_Flag_System_Match_Header
  • IMP_Flag_System_Personal
  • IMP_Flag_System_Signed
  • IMP_Flag_System_Unseen
  • IMP_Flag_User
  • IMP_Flags
  • IMP_Imap
  • IMP_Imap_Acl
  • IMP_Imap_Exception
  • IMP_Imap_PermanentFlags
  • IMP_Imap_Thread
  • IMP_Imap_Tree
  • IMP_Indices
  • IMP_Indices_Form
  • IMP_LoginTasks_SystemTask_GarbageCollection
  • IMP_LoginTasks_SystemTask_Upgrade
  • IMP_LoginTasks_SystemTask_UpgradeAuth
  • IMP_LoginTasks_Task_Autocreate
  • IMP_LoginTasks_Task_DeleteAttachmentsMonthly
  • IMP_LoginTasks_Task_DeleteSentmailMonthly
  • IMP_LoginTasks_Task_FilterOnLogin
  • IMP_LoginTasks_Task_PurgeSentmail
  • IMP_LoginTasks_Task_PurgeSpam
  • IMP_LoginTasks_Task_PurgeTrash
  • IMP_LoginTasks_Task_RecoverDraft
  • IMP_LoginTasks_Task_RenameSentmailMonthly
  • IMP_Mailbox
  • IMP_Mailbox_List
  • IMP_Mailbox_List_Track
  • IMP_Maillog
  • IMP_Menu_Dimp
  • IMP_Message
  • IMP_Mime_Status
  • IMP_Mime_Viewer_Alternative
  • IMP_Mime_Viewer_Appledouble
  • IMP_Mime_Viewer_Audio
  • IMP_Mime_Viewer_Enriched
  • IMP_Mime_Viewer_Externalbody
  • IMP_Mime_Viewer_Html
  • IMP_Mime_Viewer_Images
  • IMP_Mime_Viewer_Itip
  • IMP_Mime_Viewer_Mdn
  • IMP_Mime_Viewer_Partial
  • IMP_Mime_Viewer_Pdf
  • IMP_Mime_Viewer_Pgp
  • IMP_Mime_Viewer_Plain
  • IMP_Mime_Viewer_Related
  • IMP_Mime_Viewer_Rfc822
  • IMP_Mime_Viewer_Smil
  • IMP_Mime_Viewer_Smime
  • IMP_Mime_Viewer_Status
  • IMP_Mime_Viewer_Vcard
  • IMP_Mime_Viewer_Video
  • IMP_Mime_Viewer_Zip
  • IMP_Notification_Event_Status
  • IMP_Notification_Handler_Decorator_ImapAlerts
  • IMP_Notification_Handler_Decorator_NewmailNotify
  • IMP_Notification_Listener_AjaxStatus
  • Imp_Prefs_Identity
  • IMP_Prefs_Ui
  • IMP_Quota
  • IMP_Quota_Base
  • IMP_Quota_Command
  • IMP_Quota_Hook
  • IMP_Quota_Imap
  • IMP_Quota_Maildir
  • IMP_Quota_Mdaemon
  • IMP_Quota_Mercury32
  • IMP_Quota_Null
  • IMP_Quota_Sql
  • IMP_Search
  • IMP_Search_Element
  • IMP_Search_Element_Attachment
  • IMP_Search_Element_Autogenerated
  • IMP_Search_Element_Bulk
  • IMP_Search_Element_Contacts
  • IMP_Search_Element_Date
  • IMP_Search_Element_Flag
  • IMP_Search_Element_Header
  • IMP_Search_Element_Mailinglist
  • IMP_Search_Element_Or
  • IMP_Search_Element_Personal
  • IMP_Search_Element_Recipient
  • IMP_Search_Element_Size
  • IMP_Search_Element_Text
  • IMP_Search_Element_Within
  • IMP_Search_Filter
  • IMP_Search_Filter_Attachment
  • IMP_Search_Filter_Autogenerated
  • IMP_Search_Filter_Builtin
  • IMP_Search_Filter_Bulk
  • IMP_Search_Filter_Contacts
  • IMP_Search_Filter_Mailinglist
  • IMP_Search_Filter_Personal
  • IMP_Search_Query
  • IMP_Search_Vfolder
  • IMP_Search_Vfolder_Builtin
  • IMP_Search_Vfolder_Vinbox
  • IMP_Search_Vfolder_Vtrash
  • IMP_Sentmail
  • IMP_Sentmail_Base
  • IMP_Sentmail_Null
  • IMP_Sentmail_Sql
  • IMP_Spam
  • IMP_Test
  • IMP_Tree_Flist
  • IMP_Tree_Jquerymobile
  • IMP_Tree_Simplehtml
  • IMP_Ui_Compose
  • IMP_Ui_Editor
  • IMP_Ui_Folder
  • IMP_Ui_Headers
  • IMP_Ui_Imageview
  • IMP_Ui_Mailbox
  • IMP_Ui_Message
  • IMP_Ui_Mimp
  • IMP_Ui_Search
  • IMP_Views_Compose
  • IMP_Views_ListMessages
  • IMP_Views_ShowMessage
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The IMP_Mime_Viewer_Html class renders out HTML text with an effort
  4:  * to remove potentially malicious code.
  5:  *
  6:  * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
  7:  *
  8:  * See the enclosed file COPYING for license information (GPL). If you
  9:  * did not receive this file, see http://www.horde.org/licenses/gpl.
 10:  *
 11:  * @author   Anil Madhavapeddy <anil@recoil.org>
 12:  * @author   Jon Parise <jon@horde.org>
 13:  * @author   Michael Slusarz <slusarz@horde.org>
 14:  * @category Horde
 15:  * @license  http://www.horde.org/licenses/gpl GPL
 16:  * @package  IMP
 17:  */
 18: class IMP_Mime_Viewer_Html extends Horde_Mime_Viewer_Html
 19: {
 20:     const CSS_BG_PREG = '/(background(?:-image)?:[^;\}]*(?:url\(["\']?))(.*?)((?:["\']?\)))/i';
 21: 
 22:     /**
 23:      * Temp array for storing data when parsing the HTML document.
 24:      *
 25:      * @var array
 26:      */
 27:     protected $_imptmp = array();
 28: 
 29:     /**
 30:      * This driver's display capabilities.
 31:      *
 32:      * @var array
 33:      */
 34:     protected $_capability = array(
 35:         'full' => true,
 36:         'info' => true,
 37:         'inline' => true,
 38:         'raw' => false
 39:     );
 40: 
 41:     /**
 42:      * Return the full rendered version of the Horde_Mime_Part object.
 43:      *
 44:      * @return array  See parent::render().
 45:      */
 46:     protected function _render()
 47:     {
 48:         return array(
 49:             $this->_mimepart->getMimeId() => $this->_IMPrender(false)
 50:         );
 51:     }
 52: 
 53:     /**
 54:      * Return the rendered inline version of the Horde_Mime_Part object.
 55:      *
 56:      * @return array  See parent::render().
 57:      */
 58:     protected function _renderInline()
 59:     {
 60:         $data = $this->_IMPrender(true);
 61: 
 62:         if (!is_null($this->_imptmp)) {
 63:             $uid = strval(new Horde_Support_Randomid());
 64: 
 65:             Horde::addScriptFile('imp.js', 'imp');
 66: 
 67:             $data['js'] = array('IMP_JS.iframeInject("' . $uid . '", ' . Horde_Serialize::serialize($data['data'], Horde_Serialize::JSON, $this->_mimepart->getCharset()) . ')');
 68:             $data['data'] = '<div>' . _("Loading...") . '</div><iframe class="htmlMsgData" id="' . $uid . '" src="javascript:false" frameborder="0" style="display:none"></iframe>';
 69:             $data['type'] = 'text/html; charset=UTF-8';
 70:         }
 71: 
 72:         return array(
 73:             $this->_mimepart->getMimeId() => $data
 74:         );
 75:     }
 76: 
 77:     /**
 78:      * Return the rendered information about the Horde_Mime_Part object.
 79:      *
 80:      * @return array  See parent::render().
 81:      */
 82:     protected function _renderInfo()
 83:     {
 84:         if ($this->canRender('inline') ||
 85:             ($this->_mimepart->getDisposition() == 'attachment')) {
 86:             return array();
 87:         }
 88: 
 89:         $status = new IMP_Mime_Status(array(
 90:             _("This message part contains HTML data, but inline HTML display is disabled."),
 91:             $this->getConfigParam('imp_contents')->linkViewJS($this->_mimepart, 'view_attach', _("View HTML data in new window.")),
 92:             $this->getConfigParam('imp_contents')->linkViewJS($this->_mimepart, 'view_attach', _("Convert HTML data to plain text and view in new window."), array('params' => array('convert_text' => 1)))
 93:         ));
 94:         $status->icon('mime/html.png');
 95: 
 96:         return array(
 97:             $this->_mimepart->getMimeId() => array(
 98:                 'data' => '',
 99:                 'status' => $status,
100:                 'type' => 'text/html; charset=' . $this->getConfigParam('charset')
101:             )
102:         );
103:     }
104: 
105:     /**
106:      * Render out the currently set contents.
107:      *
108:      * @param boolean $inline  Are we viewing inline?
109:      *
110:      * @return array  Two elements: html and status.
111:      */
112:     protected function _IMPrender($inline)
113:     {
114:         $data = $this->_mimepart->getContents();
115: 
116:         /* Don't do IMP DOM processing if in mimp mode or converting to
117:          * text. */
118:         if ((IMP::getViewMode() == 'mimp') ||
119:             (!$inline && Horde_Util::getFormData('convert_text'))) {
120:             $this->_imptmp = null;
121:         } else {
122:             if ($inline) {
123:                 $imgview = new IMP_Ui_Imageview();
124:                 $blockimg = !$imgview->showInlineImage($this->getConfigParam('imp_contents'));
125:             } else {
126:                 $blockimg = false;
127:             }
128: 
129:             $this->_imptmp = array(
130:                 'blockimg' => null,
131:                 'cid' => null,
132:                 'cid_used' => array(),
133:                 'cssblock' => false,
134:                 'img' => $blockimg,
135:                 'imgblock' => false,
136:                 'inline' => $inline,
137:                 'style' => array(),
138:                 'target' => strval(new Horde_Support_Randomid())
139:             );
140: 
141:             /* Image filtering. */
142:             if ($this->_imptmp['img']) {
143:                 $this->_imptmp['blockimg'] = Horde::url(Horde_Themes::img('spacer_red.png'), true, array('append_session' => -1));
144:             }
145: 
146:             /* Search for inlined data that we can display (multipart/related
147:              * parts) - see RFC 2392. */
148:             $this->_imptmp['cid'] = array();
149:             if (($related_part = $this->getConfigParam('imp_contents')->findMimeType($this->_mimepart->getMimeId(), 'multipart/related')) &&
150:                 ($related_cids = $related_part->getMetadata('related_cids'))) {
151:                 $cid_replace = array();
152: 
153:                 foreach ($related_cids as $mime_id => $cid) {
154:                     if ($cid = trim($cid, '<>')) {
155:                         $cid_replace['cid:' . $cid] = $mime_id;
156:                     }
157:                 }
158: 
159:                 if (!empty($cid_replace)) {
160:                     $this->_imptmp['cid'] = $cid_replace;
161:                 }
162:             }
163:         }
164: 
165:         /* Sanitize the HTML. */
166:         $data = $this->_cleanHTML($data, array(
167:             'noprefetch' => ($inline && (IMP::getViewMode() != 'mimp')),
168:             'phishing' => $inline
169:         ));
170: 
171:         $status = array();
172:         if ($this->_phishWarn) {
173:             $status[] = new IMP_Mime_Status(array(
174:                 sprintf(_("%s: This message may not be from whom it claims to be. Beware of following any links in it or of providing the sender with any personal information."), _("Warning")),
175:                 _("The links that caused this warning have this background color:") . ' <span style="' . $this->_phishCss . '">' . _("EXAMPLE") . '</span>'
176:             ));
177:         }
178: 
179:         /* We are done processing if in mimp mode, or we are converting to
180:          * text. */
181:         if (is_null($this->_imptmp)) {
182:             $data = $this->_textFilter($data, 'Html2text', array(
183:                 'wrap' => false
184:             ));
185: 
186:             // Filter bad language.
187:             return array(
188:                 'data' => IMP::filterText($data),
189:                 'type' => 'text/plain; charset=' . $this->getConfigParam('charset')
190:             );
191:         }
192: 
193:         if ($this->_imptmp['imgblock']) {
194:             $tmp = new IMP_Mime_Status(array(
195:                 _("Images have been blocked in this message part."),
196:                 Horde::link('#', '', 'unblockImageLink') . _("Show Images?") . '</a>'
197:             ));
198:             $tmp->icon('mime/image.png');
199:             $status[] = $tmp;
200:         } elseif ($this->_imptmp['cssblock']) {
201:             /* This is a bit less intuitive for end users, so hide within
202:              * image blocking if possible. */
203:             $tmp = new IMP_Mime_Status(array(
204:                 _("Message styling has been suppressed in this message part since the style data lives on a remote server."),
205:                 Horde::link('#', '', 'unblockImageLink') . _("Load Styling?") . '</a>'
206:             ));
207:             $tmp->icon('mime/image.png');
208:             $status[] = $tmp;
209:         }
210: 
211:         $filters = array();
212:         if ($GLOBALS['prefs']->getValue('emoticons')) {
213:             $filters['emoticons'] = array(
214:                 'entities' => true
215:             );
216:         }
217: 
218:         if ($inline) {
219:             $filters['emails'] = array(
220:                 'callback' => array($this, 'emailsCallback')
221:             );
222:         }
223: 
224:         if (!empty($filters)) {
225:             $data = $this->_textFilter($data, array_keys($filters), array_values($filters));
226:         }
227: 
228:         /* Filter bad language. */
229:         $data = IMP::filterText($data);
230: 
231:         /* Add used CID information. */
232:         if (!empty($this->_imptmp['cid'])) {
233:             $related_part->setMetadata('related_cids_used', $this->_imptmp['cid_used']);
234:         }
235: 
236:         return array(
237:             'data' => $data,
238:             'status' => $status,
239:             'type' => $this->_mimepart->getType(true)
240:         );
241:     }
242: 
243:     /**
244:      * Determine whether the sender appears in an available addressbook.
245:      *
246:      * @return boolean  Does the sender appear in an addressbook?
247:      */
248:     protected function _inAddressBook()
249:     {
250:         if (!$this->getConfigParam('imp_contents')) {
251:             return false;
252:         }
253: 
254:         $from = Horde_Mime_Address::bareAddress($this->getConfigParam('imp_contents')->getHeader()->getValue('from'));
255: 
256:         if ($GLOBALS['prefs']->getValue('html_image_addrbook') &&
257:             $GLOBALS['registry']->hasMethod('contacts/getField')) {
258:             $params = IMP::getAddressbookSearchParams();
259:             try {
260:                 if ($GLOBALS['registry']->call('contacts/getField', array($from, '__key', $params['sources'], true, true))) {
261:                     return true;
262:                 }
263:             } catch (Horde_Exception $e) {}
264:         }
265: 
266:         /* Check admin defined e-mail list. */
267:         $safe_addrs = $this->getConfigParam('safe_addrs');
268:         return (!empty($safe_addrs) && in_array($from, $safe_addrs));
269:     }
270: 
271:     /**
272:      * Process emails text filter callback.
273:      *
274:      * @param array $args   List of arguments to pass to the compose script.
275:      * @param array $extra  Hash of extra, non-standard arguments to pass to
276:      *                      compose script.
277:      *
278:      * @return Horde_Url  The link to the message composition script.
279:      */
280:     public function emailsCallback($args, $extra)
281:     {
282:         return IMP::composeLink($args, $extra, true);
283:     }
284: 
285:     /**
286:      */
287:     protected function _node($doc, $node)
288:     {
289:         parent::_node($doc, $node);
290: 
291:         if ($doc == $node) {
292:             /* Sanitize and optimize style tags. */
293:             if ($this->_imptmp && !empty($this->_imptmp['style'])) {
294:                 // Csstidy may not be available.
295:                 try {
296:                     $style = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter(implode("\n", $this->_imptmp['style']), 'csstidy', array(
297:                         'ob' => true,
298:                         'preserve_css' => false
299:                     ));
300: 
301:                     $blocked = array();
302:                     foreach ($style->import as $val) {
303:                         $blocked[] = '@import "' . $val . '";';
304:                     }
305:                     $style->import = array();
306: 
307:                     foreach ($style->css as $key => $val) {
308:                         foreach ($val as $key2 => $val2) {
309:                             foreach ($val2 as $key3 => $val3) {
310:                                 foreach ($val3['p'] as $key4 => $val4) {
311:                                     if (preg_match('/^\s*url\(["\']?.*?["\']?\)/i', $val4)) {
312:                                         $blocked[] = $key2 . '{' . $key3 . ':' . $val4 . ';}';
313:                                         unset($style->css[$key][$key2][$key3]['p'][$key4]);
314:                                     }
315:                                 }
316:                             }
317:                         }
318:                     }
319: 
320:                     $css_text = $style->print->plain();
321: 
322:                     if ($css_text || !empty($blocked)) {
323:                         // Gets the HEAD element or creates one if it doesn't
324:                         // exist.
325:                         $head = $doc->getElementsByTagName('head');
326:                         if ($head->length) {
327:                             $headelt = $head->item(0);
328:                         } else {
329:                             $headelt = $doc->createElement('head');
330:                             $doc->appendChild($headelt);
331:                         }
332:                     }
333: 
334:                     if ($css_text) {
335:                         $style_elt = $doc->createElement('style', $css_text);
336:                         $style_elt->setAttribute('type', 'text/css');
337:                         $headelt->appendChild($style_elt);
338:                     }
339: 
340:                     /* Store all the blocked CSS in a bogus style element in
341:                      * the HTML output - then we simply need to change the
342:                      * type attribute to text/css, and the browser should
343:                      * load the definitions on-demand. */
344:                     if (!empty($blocked)) {
345:                         $block_elt = $doc->createElement('style', implode('', $blocked));
346:                         $block_elt->setAttribute('type', 'text/x-imp-cssblocked');
347:                         $headelt->appendChild($block_elt);
348:                     }
349:                 } catch (Horde_Exception $e) {}
350:             }
351:         }
352:     }
353: 
354:     /**
355:      * Process DOM node (callback).
356:      *
357:      * @param DOMDocument $doc  Document node.
358:      * @param DOMNode $node     Node.
359:      */
360:     protected function _nodeCallback($doc, $node)
361:     {
362:         if (is_null($this->_imptmp)) {
363:             return;
364:         }
365: 
366:         if ($node instanceof DOMElement) {
367:             $tag = Horde_String::lower($node->tagName);
368: 
369:             switch ($tag) {
370:             case 'a':
371:             case 'area':
372:                 /* Convert links to open in new windows. Ignore
373:                  * mailto: links and links that already have a target. */
374:                 if ($node->hasAttribute('href')) {
375:                     $url = parse_url($node->getAttribute('href'));
376:                     if (isset($url['scheme']) && ($url['scheme'] == 'mailto')) {
377:                         /* We don't include Horde.popup() in IFRAME, so need
378:                          * to use 'simple' links. */
379:                         $node->setAttribute('href', IMP::composeLink($node->getAttribute('href'), array(), true));
380:                         $node->removeAttribute('target');
381:                     } elseif ($this->_imptmp['inline'] &&
382:                               isset($url['fragment']) &&
383:                               empty($url['path']) &&
384:                               $GLOBALS['browser']->isBrowser('mozilla')) {
385:                         /* See Bug #8695: internal anchors are broken in
386:                          * Mozilla. */
387:                         $node->removeAttribute('href');
388:                     } elseif (!$node->hasAttribute('target') ||
389:                               Horde_String::lower($node->getAttribute('target')) == '_self') {
390:                         $node->setAttribute('target', $this->_imptmp['target']);
391:                     }
392:                 }
393:                 break;
394: 
395:             case 'img':
396:             case 'input':
397:                 if ($this->_imptmp && $node->hasAttribute('src')) {
398:                     $val = $node->getAttribute('src');
399: 
400:                     /* Multipart/related. */
401:                     if (($tag == 'img') &&
402:                         isset($this->_imptmp['cid'][$val])) {
403:                         $this->_imptmp['cid_used'][] = $this->_imptmp['cid'][$val];
404:                         $val = $this->getConfigParam('imp_contents')->urlView(null, 'view_attach', array('params' => array(
405:                             'ctype' => 'image/*',
406:                             'id' => $this->_imptmp['cid'][$val],
407:                             'imp_img_view' => 'data'
408:                         )));
409:                         $node->setAttribute('src', $val);
410:                     }
411: 
412:                     /* Block images.*/
413:                     if ($this->_imptmp['img']) {
414:                         $node->setAttribute('htmlimgblocked', $val);
415:                         $node->setAttribute('src', $this->_imptmp['blockimg']);
416:                         $this->_imptmp['imgblock'] = true;
417:                     }
418:                 }
419:                 break;
420: 
421:             case 'link':
422:                 /* Block all link tags that reference foreign URLs, other than
423:                  * CSS. There's no inherently wrong with linking to a foreign
424:                  * CSS file other than privacy concerns. Therefore, block
425:                  * linking until requested by the user. */
426:                 $delete_link = true;
427: 
428:                 switch (Horde_String::lower($node->getAttribute('type'))) {
429:                 case 'text/css':
430:                     if ($this->_imptmp && $node->hasAttribute('href')) {
431:                         $tmp = $node->getAttribute('href');
432: 
433:                         if (isset($this->_imptmp['cid'][$tmp])) {
434:                             $this->_imptmp['style'][] = $this->getConfigParam('imp_contents')->getMIMEPart($this->_imptmp['cid'][$tmp])->getContents();
435:                         } else {
436:                             $node->setAttribute('htmlcssblocked', $node->getAttribute('href'));
437:                             $node->removeAttribute('href');
438:                             $this->_imptmp['cssblock'] = true;
439:                             $delete_link = false;
440:                         }
441:                     }
442:                     break;
443:                 }
444: 
445:                 if ($delete_link &&
446:                     $node->hasAttribute('href') &&
447:                     $node->parentNode) {
448:                     $node->parentNode->removeChild($node);
449:                 }
450:                 break;
451: 
452:             case 'style':
453:                 switch (Horde_String::lower($node->getAttribute('type'))) {
454:                 case 'text/css':
455:                     if ($this->_imptmp) {
456:                         $this->_imptmp['style'][] = $node->nodeValue;
457:                     }
458:                     $node->parentNode->removeChild($node);
459:                     break;
460:                 }
461:                 break;
462: 
463:             case 'table':
464:                 /* If displaying inline (in IFRAME), tables with 100%
465:                  * height seems to confuse many browsers re: the
466:                  * iframe internal height. */
467:                 if ($this->_imptmp['inline'] &&
468:                     $node->hasAttribute('height') &&
469:                     ($node->getAttribute('height') == '100%')) {
470:                     $node->removeAttribute('height');
471:                 }
472: 
473:                 // Fall-through
474: 
475:             case 'body':
476:             case 'td':
477:                 if ($this->_imptmp &&
478:                     $node->hasAttribute('background')) {
479:                     $val = $node->getAttribute('background');
480: 
481:                     /* Multipart/related. */
482:                     if (isset($this->_imptmp['cid'][$val])) {
483:                         $this->_imptmp['cid_used'][] = $this->_imptmp['cid'][$val];
484:                         $val = $this->getConfigParam('imp_contents')->urlView(null, 'view_attach', array('params' => array(
485:                             'id' => $this->_imptmp['cid'][$val],
486:                             'imp_img_view' => 'data'
487:                         )));
488:                         $node->setAttribute('background', $val);
489:                     }
490: 
491:                     /* Block images.*/
492:                     if ($this->_imptmp['img']) {
493:                         $node->setAttribute('htmlimgblocked', $val);
494:                         $node->setAttribute('background', $this->_imptmp['blockimg']);
495:                         $this->_imptmp['imgblock'] = true;
496:                     }
497:                 }
498:                 break;
499:             }
500: 
501: 
502:             if (!is_null($this->_imptmp)) {
503:                 $remove = array();
504:                 foreach ($node->attributes as $val) {
505:                     /* Catch random mailto: strings in attributes that will
506:                      * cause problems with e-mail linking. */
507:                     if (stripos($val->value, 'mailto:') === 0) {
508:                         $remove[] = $val->name;
509:                     }
510:                 }
511: 
512:                 foreach ($remove as $val) {
513:                     $node->removeAttribute($val);
514:                 }
515: 
516:                 if ($node->hasAttribute('style')) {
517:                     if (strpos($node->getAttribute('style'), 'content:') !== false) {
518:                         // TODO: Figure out way to unblock?
519:                         $node->removeAttribute('style');
520:                     } elseif ($this->_imptmp['img'] || $this->_imptmp['cid']) {
521:                         $this->_imptmp['node'] = $node;
522:                         $style = preg_replace_callback(self::CSS_BG_PREG, array($this, '_styleCallback'), $node->getAttribute('style'), -1, $matches);
523:                         if ($matches) {
524:                             $node->setAttribute('style', $style);
525:                         }
526:                     }
527:                 }
528:             }
529:         }
530:     }
531: 
532:     /**
533:      * preg_replace_callback() callback for style/background matching of
534:      * images.
535:      *
536:      * @param array $matches  The list of matches.
537:      *
538:      * @return string  The replacement image string.
539:      */
540:     protected function _styleCallback($matches)
541:     {
542:         if (isset($this->_imptmp['cid'][$matches[2]])) {
543:             $replace = $this->getConfigParam('imp_contents')->urlView(null, 'view_attach', array('params' => array(
544:                 'id' => $this->_imptmp['cid'][$matches[2]],
545:                 'imp_img_view' => 'data'
546:             )));
547:             $this->_imptmp['cid_used'][] = $this->_imptmp['cid'][$matches[2]];
548:         } else {
549:             $this->_imptmp['node']->setAttribute('htmlimgblocked', $matches[2]);
550:             $this->_imptmp['imgblock'] = true;
551:             $replace = $this->_imptmp['blockimg'];
552:         }
553:         return $matches[1] . $replace . $matches[3];
554:     }
555: 
556: }
557: 
API documentation generated by ApiGen