1: <?php
2: /**
3: * The IMP_Mime_Viewer_Alternative class renders out messages from
4: * multipart/alternative content types (RFC 2046 [5.1.4]).
5: *
6: * Copyright 2002-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 Michael Slusarz <slusarz@horde.org>
12: * @category Horde
13: * @license http://www.horde.org/licenses/gpl GPL
14: * @package IMP
15: */
16: class IMP_Mime_Viewer_Alternative extends Horde_Mime_Viewer_Base
17: {
18: /**
19: * This driver's display capabilities.
20: *
21: * @var array
22: */
23: protected $_capability = array(
24: 'full' => true,
25: 'info' => false,
26: 'inline' => true,
27: 'raw' => false
28: );
29:
30: /**
31: * Return the full rendered version of the Horde_Mime_Part object.
32: *
33: * @return array See parent::render().
34: */
35: protected function _render()
36: {
37: return $this->_IMPrender(false);
38: }
39:
40: /**
41: * Return the rendered inline version of the Horde_Mime_Part object.
42: *
43: * @return array See parent::render().
44: */
45: protected function _renderInline()
46: {
47: return $this->_IMPrender(true);
48: }
49:
50: /**
51: * Render out the currently set contents.
52: *
53: * @param boolean $inline Are we viewing inline?
54: * @param boolean $prefer_plain Prefer text/plain part over all others.
55: *
56: * @return array See parent::render().
57: */
58: protected function _IMPrender($inline, $prefer_plain = null)
59: {
60: $base_id = $this->_mimepart->getMimeId();
61: $subparts = $this->_mimepart->contentTypeMap();
62:
63: $base_ids = $display_ids = $ret = array();
64:
65: if (is_null($prefer_plain) &&
66: ($GLOBALS['prefs']->getValue('alternative_display') == 'text')) {
67: $prefer_plain = true;
68: }
69:
70: /* Look for a displayable part. RFC: show the LAST choice that can be
71: * displayed inline. If an alternative is itself a multipart, the user
72: * agent is allowed to show that alternative, an earlier alternative,
73: * or both. If we find a multipart alternative that contains at least
74: * one viewable part, we will display all viewable subparts of that
75: * alternative. */
76: $imp_contents = $this->getConfigParam('imp_contents');
77: foreach ($subparts as $mime_id => $type) {
78: $ret[$mime_id] = null;
79: if ((strcmp($base_id, $mime_id) !== 0) &&
80: $imp_contents->canDisplay($mime_id, $inline ? IMP_Contents::RENDER_INLINE : IMP_Contents::RENDER_FULL) &&
81: /* Show HTML if $prefer_plain is false-y or if
82: * alternative_display is not 'html'. */
83: (!$prefer_plain ||
84: (($type != 'text/html') &&
85: (strpos($type, 'text/') === 0)))) {
86: $display_ids[strval($mime_id)] = true;
87: }
88: }
89:
90: /* If we found no IDs, return now. */
91: if (empty($display_ids)) {
92: if ($prefer_plain && (IMP::getViewMode() == 'mimp')) {
93: return $this->_IMPRender($inline, false);
94: }
95:
96: $ret[$base_id] = array(
97: 'data' => '',
98: 'status' => new IMP_Mime_Status(
99: _("There are no alternative parts that can be displayed inline.")
100: ),
101: 'type' => 'text/html; charset=' . $this->getConfigParam('charset')
102: );
103: return $ret;
104: }
105:
106: /* If the last viewable message exists in a subpart, back up to the
107: * base multipart and display all viewable parts in that multipart.
108: * Else, display the single part. */
109: end($display_ids);
110: $curr_id = key($display_ids);
111: while (!is_null($curr_id) && (strcmp($base_id, $curr_id) !== 0)) {
112: if (isset($subparts[$curr_id])) {
113: $disp_id = $curr_id;
114: }
115: $curr_id = Horde_Mime::mimeIdArithmetic($curr_id, 'up');
116: }
117:
118: /* At this point, $ret contains stubs for all parts living in the base
119: * alternative part.
120: * Go through all subparts of displayable part and make sure all parts
121: * are rendered. Parts not rendered will be marked as not being
122: * handled by this viewer (Bug #9365). */
123: $render_part = $this->_mimepart->getPart($disp_id);
124: $need_render = $subparts = $render_part->contentTypeMap();
125:
126: foreach (array_keys($subparts) as $val) {
127: if (isset($display_ids[$val]) && isset($need_render[$val])) {
128: $render = $this->getConfigParam('imp_contents')->renderMIMEPart($val, $inline ? IMP_Contents::RENDER_INLINE : IMP_Contents::RENDER_FULL);
129:
130: foreach (array_keys($render) as $id) {
131: unset($need_render[$id]);
132:
133: if (!$inline) {
134: if (!is_null($render[$id])) {
135: return array($base_id => $render[$id]);
136: }
137: } else {
138: $ret[$id] = $render[$id];
139: }
140: }
141: }
142: }
143:
144: unset($need_render[$disp_id]);
145: foreach (array_keys($need_render) as $val) {
146: unset($ret[$val]);
147: }
148:
149: return $inline
150: ? $ret
151: : null;
152: }
153:
154: }
155: