*/
class IMP_Contents
{
+ /* Mask entries for getSummary(). */
+ const SUMMARY_RENDER = 1;
+ const SUMMARY_BYTES = 2;
+ const SUMMARY_SIZE = 4;
+ const SUMMARY_ICON = 8;
+ const SUMMARY_DESCRIP_LINK = 16;
+ const SUMMARY_DESCRIP_NOLINK = 32;
+ const SUMMARY_DOWNLOAD = 64;
+ const SUMMARY_DOWNLOAD_ZIP = 128;
+ const SUMMARY_IMAGE_SAVE = 256;
+ const SUMMARY_STRIP_LINK = 512;
+ const SUMMARY_DOWNLOAD_ALL = 1024;
+
/**
* The IMAP index of the message.
*
/**
* Get message summary info.
*
- * @param array $options Additional options:
+ * @param integer $mask A mask of information to return:
* <pre>
- * 'show_links' - (boolean)
- * 'strip' - (boolean)
+ * IMP_Contents::SUMMARY_ICON
* </pre>
*
* @return array The following fields:
* 'type' - (string) The MIME type.
* </pre>
*/
- public function getSummary($options = array())
+ public function getSummary($mask = 0)
{
- $msg = array(
+ $last_id = null;
+ $info = array(
'download_all' => array(),
- 'has_download_link' => false,
- 'has_img_save' => false,
- 'has_strip' => false,
- 'has_zip' => false,
+ 'has' => array(),
+ 'render' => array()
);
- $ret = array();
- $slinks = !empty($options['show_links']);
+ $parts = array();
+
+ // TODO: build message (any embedded message added to structure)
+ $mime_message = $this->_message;
+
+ // Cache some settings before we enter the loop.
+ $download_zip = (($mask & self::SUMMARY_DOWNLOAD_ZIP) && Util::extensionExists('zlib'));
+ if ($download_zip) {
+ $zip_img = Horde::img('compressed.png', _("Download in .zip Format"), null, $GLOBALS['registry']->getImageDir('horde') . '/mime');
+ }
- foreach ($this->_message->contentTypeMap() as $mime_id => $mime_type) {
- if ($slinks &&
- in_array($mime_type, array('application/octet-stream', 'application/base64'))) {
+ if (($mask && self::SUMMARY_IMAGE_SAVE) &&
+ $GLOBALS['registry']->hasMethod('images/selectGalleries') &&
+ ($image_app = $GLOBALS['registry']->hasMethod('images/saveImage'))) {
+ $image_img = '<img src="' . $GLOBALS['registry']->get('icon', $image_app) . '" alt="' . _("Save Image in Gallery") . '" title="' . _("Save Image in Gallery") . '" />';
+ } else {
+ $image_img = null;
+ }
+
+ if ($mask && self::SUMMARY_STRIP_LINK) {
+ $message_token = IMP::getRequestToken('imp.impcontents');
+ }
+
+ foreach ($mime_message->contentTypeMap() as $mime_id => $mime_type) {
+ $parts[$mime_id] = array(
+ 'bytes' => null,
+ 'download' => null,
+ 'download_zip' => null,
+ 'id' => $mime_id,
+ 'img_save' => null,
+ 'render_info' => false,
+ 'render_inline' => false,
+ 'size' => null,
+ 'strip' => null
+ );
+ $part = &$parts[$mime_id];
+
+ $mime_part = $this->getMIMEPart($mime_id, array('nocontents' => true, 'nodecode' => true));
+
+ /* If this is an attachment that has no specific MIME type info,
+ * see if we can guess a rendering type. */
+ $param_array = array();
+ if (in_array($mime_type, array('application/octet-stream', 'application/base64'))) {
$mime_type = Horde_Mime_Magic::filenameToMIME($mime_part->getName());
$param_array['ctype'] = $mime_type;
- } else {
- $param_array = array();
+ }
+ $part['type'] = $mime_type;
+
+ /* Determine if part can be viewed inline or has viewable info. */
+ if (($mask & self::SUMMARY_RENDER) &&
+ (is_null($last_id) ||
+ (($last_id !== 0) &&
+ (strpos($mime_id, $last_id) !== 0)))) {
+ $last_id = null;
+ $viewer = Horde_Mime_Viewer::factory($mime_type);
+
+ if ($viewer->canDisplayInline() &&
+ ($mime_part->getDisposition() == 'inline')) {
+ $part['render_inline'] = true;
+ $info['render'][$mime_id] = 'inline';
+ $last_id = $mime_id;
+ } elseif (is_null($last_id) && $viewer->canDisplayInfo()) {
+ // TODO - Need way to show info while allowing display of
+ // subparts.
+ $part['render_info'] = true;
+ $info['render'][$mime_id] = 'info';
+ $last_id = $mime_id;
+ }
}
- $mime_part = $this->getMIMEPart($mime_id, array('nocontents' => true, 'nodecode' => true));
+ /* Get bytes/size information. */
+ if (($mask & self::SUMMARY_BYTES) ||
+ $download_zip ||
+ ($mask & self::SUMMARY_SIZE)) {
+ $part['bytes'] = $mime_part->getBytes();
+
+ if ($part['bytes'] &&
+ ($mime_part->getCurrentEncoding() == 'base64')) {
+ /* From RFC 2045 [6.8]: "...the encoded data are
+ * consistently only about 33 percent larger than the
+ * unencoded data." Thus, adding 33% to the byte size is
+ * a good estimate for our purposes. */
+ $size = number_format(max((($part['bytes'] * 0.75) / 1024), 1));
+ } else {
+ $size = $mime_part->getSize(true);
+ }
+ $part['size'] = ($size > 1024)
+ ? sprintf(_("%s MB"), number_format(max(($size / 1024), 1)))
+ : sprintf(_("%s KB"), $size);
+ }
- $bytes = $mime_part->getBytes();
- $icon = Horde::img(Horde_Mime_Viewer::getIcon($mime_type), '', array('title' => $mime_type));
+ /* Get part's icon. */
+ $part['icon'] = ($mask & self::SUMMARY_ICON) ? Horde::img(Horde_Mime_Viewer::getIcon($mime_type), '', array('title' => $mime_type)) : null;
+ /* Get part's description. */
$description = $mime_part->getDescription(true);
if (empty($description)) {
$description = _("unnamed");
}
- if ($slinks) {
- $descrip = $this->linkViewJS($mime_part, 'view_attach', htmlspecialchars($description), array('jstext' => sprintf(_("View %s [%s]"), $description, $mime_type), 'params' => $param_array));
- } else {
- $descrip = htmlspecialchars($description);
+ if ($mask & self::SUMMARY_DESCRIP_LINK) {
+ $part['description'] = $this->linkViewJS($mime_part, 'view_attach', htmlspecialchars($description), array('jstext' => sprintf(_("View %s [%s]"), $description, $mime_type), 'params' => $param_array));
+ } elseif ($mask & self::SUMMARY_DESCRIP_NOLINK) {
+ $part['description'] = htmlspecialchars($description);
}
- if (!empty($bytes) &&
- ($mime_part->getCurrentEncoding() == 'base64')) {
- /* From RFC 2045 [6.8]: "...the encoded data are consistently
- * only about 33 percent larger than the unencoded data." */
- $size = number_format(max((($bytes * 0.75) / 1024), 1));
- } else {
- $size = $mime_part->getSize(true);
- }
- $size = ($size > 1024)
- ? sprintf(_("%s MB"), number_format(max(($size / 1024), 1)))
- : sprintf(_("%s KB"), $size);
-
/* Download column. */
- if ($slinks && $bytes) {
- $download_link = $this->linkView($mime_part, 'download_attach', '', array('class' => 'download', 'dload' => true, 'jstext' => sprintf(_("Download %s"), $description)));
- $msg['has_download_link'] = true;
- } else {
- $download_link = null;
+ if (($mask & self::SUMMARY_DOWNLOAD) &&
+ (is_null($part['bytes']) || $part['bytes'])) {
+ $part['download'] = $this->linkView($mime_part, 'download_attach', '', array('class' => 'download', 'dload' => true, 'jstext' => sprintf(_("Download %s"), $description)));
+ $info['has']['download'] = true;
}
/* Display the compressed download link only if size is greater
* than 200 KB. */
- if ($slinks &&
- ($mime_part->getBytes() > 204800) &&
- Util::extensionExists('zlib') &&
+ if ($download_zip &&
+ ($part['bytes'] > 204800) &&
!in_array($mime_type, array('application/zip', 'application/x-zip-compressed'))) {
- $zip = $this->linkView($mime_part, 'download_attach', Horde::img('compressed.png', _("Download in .zip Format"), null, $GLOBALS['registry']->getImageDir('horde') . '/mime'), array('dload' => true, 'jstext' => sprintf(_("Download %s in .zip Format"), $mime_part->getDescription(true)), 'params' => array('zip' => 1)));
- $msg['has_zip'] = true;
- } else {
- $zip = null;
+ $part['download_zip'] = $this->linkView($mime_part, 'download_attach', $zip_img, array('dload' => true, 'jstext' => sprintf(_("Download %s in .zip Format"), $mime_part->getDescription(true)), 'params' => array('zip' => 1)));
+ $info['has']['download_zip'] = true;
}
/* Display the image save link if the required registry calls are
* present. */
- if ($slinks &&
- ($mime_part->getPrimaryType() == 'image') &&
- $GLOBALS['registry']->hasMethod('images/selectGalleries') &&
- ($image_app = $GLOBALS['registry']->hasMethod('images/saveImage'))) {
- if (!$msg['has_img_save']) {
+ if (!is_null($image_img) &&
+ ($mime_part->getPrimaryType() == 'image')) {
+ if (empty($info['has']['img_save'])) {
Horde::addScriptFile('prototype.js', 'horde', true);
Horde::addScriptFile('popup.js', 'imp', true);
- $msg['has_img_save'] = true;
+ $info['has']['img_save'] = true;
}
- $img_save = Horde::link('#', _("Save Image in Gallery"), null, null, IMP::popupIMPString('saveimage.php', array('index' => ($this->_index . IMP::IDX_SEP . $this->_mailbox), 'id' => $mime_id), 450, 200) . "return false;") . '<img src="' . $GLOBALS['registry']->get('icon', $image_app) . '" alt="' . _("Save Image in Gallery") . '" title="' . _("Save Image in Gallery") . '" /></a>';
- } else {
- $img_save = null;
+ $part['img_save'] = Horde::link('#', _("Save Image in Gallery"), null, null, IMP::popupIMPString('saveimage.php', array('index' => ($this->_index . IMP::IDX_SEP . $this->_mailbox), 'id' => $mime_id), 450, 200) . "return false;") . $image_img . '</a>';
}
/* Strip the Attachment? */
- if ($slinks && !empty($options['strip'])) {
- // TODO: No stripping of RFC822 part.
+ if ($mask && self::SUMMARY_STRIP_LINK) {
+ // TODO: No stripping of RFC 822 parts.
$url = Util::removeParameter(Horde::selfUrl(true), array('actionID', 'imapid', 'index'));
- $url = Util::addParameter($url, array('actionID' => 'strip_attachment', 'imapid' => $mime_id, 'index' => $this->_index, 'message_token' => $options['message_token']));
- $strip = Horde::link($url, _("Strip Attachment"), null, null, "return window.confirm('" . addslashes(_("Are you sure you wish to PERMANENTLY delete this attachment?")) . "');") . Horde::img('delete.png', _("Strip Attachment"), null, $GLOBALS['registry']->getImageDir('horde')) . '</a>';
- $msg['has_strip'] = true;
- } else {
- $strip = null;
- }
-
- if ($download = $this->isDownloadable($mime_part)) {
- $msg['download_all'][] = $mime_id;
- }
-
- $ret[$mime_id] = array(
- 'description' => $descrip,
- 'download' => $download,
- 'download_link' => $download_link,
- 'icon' => $icon,
- 'id' => $mime_id,
- 'img_save' => $img_save,
- 'size' => $size,
- 'strip' => $strip,
- 'type' => $mime_type,
- 'zip' => $zip
- );
- }
-
- return array('message' => $msg, 'parts' => $ret);
- }
-
- /**
- * Get the viewable inline parts.
- *
- * @return array TODO
- */
- public function getInlineParts()
- {
- $ret = array();
- $last_id = null;
-
- foreach ($this->_message->contentTypeMap() as $mime_id => $mime_type) {
- if (!is_null($last_id) &&
- (($last_id === 0) ||
- (strpos($mime_id, $last_id) === 0))) {
- continue;
+ $url = Util::addParameter($url, array('actionID' => 'strip_attachment', 'imapid' => $mime_id, 'index' => $this->_index, 'message_token' => $message_token));
+ $part['strip'] = Horde::link($url, _("Strip Attachment"), null, null, "return window.confirm('" . addslashes(_("Are you sure you wish to PERMANENTLY delete this attachment?")) . "');") . Horde::img('delete.png', _("Strip Attachment"), null, $GLOBALS['registry']->getImageDir('horde')) . '</a>';
+ $info['has']['strip'] = true;
}
- $last_id = null;
- $viewer = Horde_Mime_Viewer::factory($mime_type);
-
- if ($viewer->canDisplayInline()) {
- $mime_part = $this->getMIMEPart($mime_id, array('nocontents' => true, 'nodecode' => true));
- if ($mime_part->getDisposition() == 'inline') {
- $res = $this->renderMIMEPart($mime_id, array('format' => 'inline'));
- $ret[$mime_id] = $res['data'];
- $last_id = $mime_id;
+ if ($mask && self::SUMMARY_DOWNLOAD_ALL) {
+ if ($download = $this->isDownloadable($mime_part)) {
+ $info['download_all'][] = $mime_id;
}
}
-
- if (is_null($last_id) && $viewer->canDisplayInfo()) {
- $res = $this->renderMIMEPart($mime_id, array('format' => 'info'));
- $ret[$mime_id] = $res['data'];
- $last_id = $mime_id;
- }
}
- return $ret;
+ return array('info' => $info, 'parts' => $parts);
}
/**
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_alternative class renders out messages from
- * multipart/alternative content types (RFC 2046 [5.1.4]).
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_alternative extends Horde_Mime_Viewer_Driver
-{
- /**
- * The content-type of the preferred part.
- * Default: application/octet-stream
- *
- * @var string
- */
- protected $_contentType = 'application/octet-stream';
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- $display_id = null;
- $summaryList = array();
- $text = '';
-
- /* Look for a displayable part.
- * RFC 2046: We show the LAST choice that can be displayed inline. */
- $partList = $this->mime_part->getParts();
- foreach ($partList as $part) {
- if ($contents->canDisplayInline($part)) {
- $text = $contents->renderMIMEPart($part);
- $this->_contentType = $part->getType();
- $display_id = $part->getMIMEId();
- }
- }
-
- /* Show links to alternative parts. */
- if (($text === null) || (count($partList) > 1)) {
- if ($text === null) {
- $text = '<em>' . _("There are no alternative parts that can be displayed.") . '</em>';
- }
-
- /* Generate the list of summaries to use. */
- foreach ($partList as $part) {
- $id = $part->getMIMEId();
- if ($id && $id != $display_id) {
- $summary = $contents->partSummary($part);
- /* We don't want to show the MIME ID for alt parts. */
- if (!empty($summary)) {
- array_splice($summary, 1, 1);
- $summaryList[] = $summary;
- }
- }
- }
-
- /* Make sure there is at least one summary before showing the
- * alternative parts. */
- $alternative_display = $GLOBALS['prefs']->getValue('alternative_display');
- if (!empty($summaryList) &&
- !$this->viewAsAttachment() &&
- $alternative_display != 'none') {
- $status_array = array();
- $status = _("Alternative parts for this section:");
- if ($contents->showSummaryLinks()) {
- require_once 'Horde/Help.php';
- $status .= ' ' . Help::link('imp', 'alternative-msg');
- }
- $status_array[] = $status;
- $status = '<table border="0" cellspacing="1" cellpadding="1">';
- foreach ($summaryList as $summary) {
- $status .= '<tr valign="middle">';
- foreach ($summary as $val) {
- if (!empty($val)) {
- $status .= "<td>$val </td>\n";
- }
- }
- $status .= "</tr>\n";
- }
- $status .= '</table>';
- $status_array[] = $status;
- $status_msg = $this->formatStatusMsg($status_array, Horde::img('mime/binary.png', _("Multipart/alternative"), null, $GLOBALS['registry']->getImageDir('horde')), false);
- switch ($alternative_display) {
- case 'above':
- $text = $status_msg . $text;
- break;
-
- case 'below':
- $text .= $status_msg;
- break;
- }
- }
- }
-
- /* Remove attachment information for the displayed part if we
- * can. */
- if (is_callable(array($contents, 'removeAtcEntry'))) {
- $contents->removeAtcEntry($this->mime_part->getMIMEId());
- }
-
- return $text;
- }
-
- /**
- * Return the content-type.
- *
- * @return string The content-type of the message.
- * Returns 'application/octet-stream' until actual
- * content type of the message can be determined.
- */
- public function getType()
- {
- return $this->_contentType;
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_appledouble class handles multipart/appledouble
- * messages conforming to RFC 1740.
- *
- * Copyright 2003-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_appledouble extends Horde_Mime_Viewer_Driver
-{
- /**
- * Force viewing of a part inline, regardless of the Content-Disposition
- * of the MIME Part.
- *
- * @var boolean
- */
- protected $_forceinline = true;
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- $contents = &$params[0];
- $text = '';
-
- /* RFC 1740 [4]: There are two parts to an appledouble message:
- (1) application/applefile
- (2) Data embedded in the Mac file */
-
- /* Display the macintosh download link. */
- $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(1));
- if ($part) {
- $status = array(
- _("This message contains a Macintosh file."),
- sprintf(_("The Macintosh resource fork can be downloaded %s."), $contents->linkViewJS($part, 'download_attach', _("HERE"), _("The Macintosh resource fork"))),
- _("The contents of the Macintosh file are below.")
- );
- $text .= $this->formatStatusMsg($status, Horde::img('apple.png', _("Macintosh File")), false);
- }
-
- /* Display the content of the file. */
- $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(2));
- if ($part) {
- $mime_message = Horde_Mime_Message::convertMIMEPart($part);
- $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$contents));
- $mc->buildMessage();
- $text .= '<table cellspacing="0">' . $mc->getMessage(true) . '</table>';
- }
-
- return $text;
- }
-
- /**
- * Return the content-type.
- *
- * @return string The content-type of the message.
- */
- public function getType()
- {
- return 'text/html; charset=' . NLS::getCharset();
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_enriched class renders out plain text from
- * enriched content tags, ala RFC 1896
- *
- * Copyright 2001-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Eric Rostetter <eric.rostetter@physics.utexas.edu>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_enriched extends Horde_Mime_Viewer_enriched
-{
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- global $prefs;
-
- if (($text = $this->mime_part->getContents()) === false) {
- return $this->formatPartError(_("There was an error displaying this message part"));
- }
-
- if (trim($text) == '') {
- return $text;
- }
-
- $text = parent::render();
-
- // Highlight quoted parts of an email.
- if ($prefs->getValue('highlight_text')) {
- $text = implode("\n", preg_replace('|^(\s*>.+)$|', '<span class="quoted1">\1</span>', explode("\n", $text)));
- $indent = 1;
- while (preg_match('|>(\s?>){' . $indent . '}|', $text)) {
- $text = implode("\n", preg_replace('|^<span class="quoted' . ((($indent - 1) % 5) + 1) . '">(\s*>(\s?>){' . $indent . '}.+)$|', '<span class="quoted' . (($indent % 5) + 1) . '">\1', explode("\n", $text)));
- $indent++;
- }
- }
-
- // Dim signatures.
- if ($prefs->getValue('dim_signature')) {
- $parts = preg_split('|(\n--\s*\n)|', $text, 2, PREG_SPLIT_DELIM_CAPTURE);
- $text = array_shift($parts);
- if (count($parts)) {
- $text .= '<span class="signature">' . $parts[0] .
- preg_replace('|class="[^"]+"|', 'class="signature-fixed"', $parts[1]) .
- '</span>';
- }
- }
-
- // Filter bad language.
- $text = IMP::filterText($text);
-
- return $text;
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_html class renders out HTML text with an effort
- * to remove potentially malicious code.
- *
- * Copyright 1999-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Anil Madhavapeddy <anil@recoil.org>
- * @author Jon Parise <jon@horde.org>
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_html extends Horde_Mime_Viewer_html
-{
- /**
- * Cached block image.
- *
- * @var string
- */
- protected $_blockimg = null;
-
- /**
- * The regular expression to catch any tags and attributes that load
- * external images.
- *
- * @var string
- */
- protected $_img_regex = '/
- # match 1
- (
- # <img> tags
- <img[^>]+src=
- # <input> tags
- |<input[^>]*src=
- # "background" attributes
- |<body[^>]*background=|<td[^>]*background=|<table[^>]*background=
- # "style" attributes; match 2; quotes: match 3
- |(style=\s*("|\')?[^>]*background(?:-image)?:(?(3)[^"\']|[^>])*?url\s*\()
- )
- # whitespace
- \s*
- # opening quotes, parenthesis; match 4
- ("|\')?
- # the image url; match 5
- ((?(2)
- # matched a "style" attribute
- (?(4)[^"\')>]*|[^\s)>]*)
- # did not match a "style" attribute
- |(?(4)[^"\'>]*|[^\s>]*)
- ))
- # closing quotes
- (?(4)\\4)
- # matched a "style" attribute?
- (?(2)
- # closing parenthesis
- \s*\)
- # remainder of the "style" attribute; match 5
- ((?(3)[^"\'>]*|[^\s>]*))
- )
- /isx';
-
- /**
- * TODO
- */
- protected function _render()
- {
- $render = $this->_IMPrender(false);
-
- return array(
- 'data' => $render['html'],
- 'status' => $render['status'],
- 'type' => $this->_mimepart->getType(true)
- );
- }
-
- /**
- * TODO
- */
- protected function _renderInline()
- {
- $render = $this->_IMPrender(true);
-
- return array(
- 'data' => $render['html'],
- 'status' => $render['status']
- );
- }
-
- /**
- * Render out the currently set contents.
- *
- * @param boolean $inline Are we viewing inline?
- *
- * @return array Two elements: html and status.
- */
- protected function _IMPrender($inline)
- {
- $data = $this->_mimepart->getContents();
- $charset = NLS::getCharset();
- $msg_charset = $this->_mimepart->getCharset();
-
- if ($inline) {
- $data = String::convertCharset($data, $msg_charset);
- $msg_charset = $charset;
- }
-
- /* Run tidy on the HTML. */
- if ($this->getConfigParam('tidy') &&
- ($tidy_config = IMP::getTidyConfig(String::length($data)))) {
- if ($msg_charset == 'us-ascii') {
- $tidy = tidy_parse_string($data, $tidy_config, 'ascii');
- $tidy->cleanRepair();
- $data = tidy_get_output($tidy);
- } else {
- $tidy = tidy_parse_string(String::convertCharset($data, $msg_charset, 'UTF-8'), $tidy_config, 'utf8');
- $tidy->cleanRepair();
- $data = String::convertCharset(tidy_get_output($tidy), 'UTF-8', $msg_charset);
- }
- }
-
- /* Sanitize the HTML. */
- $cleanhtml = $this->_cleanHTML($data, $inline);
- $data = $cleanhtml['html'];
-
- /* Reset absolutely positioned elements. */
- if ($inline) {
- $data = preg_replace('/(style\s*=\s*)(["\'])?([^>"\']*)position\s*:\s*absolute([^>"\']*)\2/i', '$1"$3$4"', $data);
- }
-
- /* Search for inlined images that we can display. */
- // TODO
- $related = $this->_mimepart->getInformation('related_part');
- if ($related !== false) {
- $relatedPart = $this->_params['contents']->getMIMEPart($related);
- foreach ($relatedPart->getCIDList() as $ref => $id) {
- $id = trim($id, '<>');
- $cid_part = $this->_params['contents']->getDecodedMIMEPart($ref);
- $data = str_replace("cid:$id", $this->_params['contents']->urlView($cid_part, 'view_attach'), $data);
- }
- }
-
- /* Convert links to open in new windows. First we hide all
- * mailto: links, links that have an "#xyz" anchor and ignore
- * all links that already have a target. */
- $data = preg_replace(
- array('/<a\s([^>]*\s*href=["\']?(#|mailto:))/i',
- '/<a\s([^>]*)\s*target=["\']?[^>"\'\s]*["\']?/i',
- '/<a\s/i',
- '/<area\s([^>]*\s*href=["\']?(#|mailto:))/i',
- '/<area\s([^>]*)\s*target=["\']?[^>"\'\s]*["\']?/i',
- '/<area\s/i',
- "/\x01/",
- "/\x02/"),
- array("<\x01\\1",
- "<\x01 \\1 target=\"_blank\"",
- '<a target="_blank" ',
- "<\x02\\1",
- "<\x02 \\1 target=\"_blank\"",
- '<area target="_blank" ',
- 'a ',
- 'area '),
- $data);
-
- /* Turn mailto: links into our own compose links. */
- if ($inline && $GLOBALS['registry']->hasMethod('mail/compose')) {
- $data = preg_replace_callback('/href\s*=\s*(["\'])?mailto:((?(1)[^\1]*?|[^\s>]+))(?(1)\1|)/i', array($this, '_mailtoCallback'), $data);
- }
-
- /* Filter bad language. */
- $data = IMP::filterText($data);
-
- if ($inline) {
- /* Put div around message. */
- $data = '<div id="html-message">' . $data . '</div>';
- }
-
- /* Only display images if specifically allowed by user. */
- $msg = $script = '';
- if (!IMP::printMode() &&
- $GLOBALS['prefs']->getValue('html_image_replacement') &&
- preg_match($this->_img_regex, $data)) {
- /* Make sure the URL parameters are correct for the current
- * message. */
- $url = Util::removeParameter(Horde::selfUrl(true), array('index'));
- if ($inline) {
- $url = Util::removeParameter($url, array('actionID'));
- }
- $url = Util::addParameter($url, 'index', $this->_params['contents']->getMessageIndex());
-
- $view_img = Util::getFormData('view_html_images');
- $addr_check = ($GLOBALS['prefs']->getValue('html_image_addrbook') && $this->_inAddressBook());
-
- if (!$view_img && !$addr_check) {
- $script = Util::bufferOutput(array('Horde', 'addScriptFile'), 'prototype.js', 'horde', true) .
- Util::bufferOutput(array('Horde', 'addScriptFile'), 'unblockImages.js', 'imp', true);
-
- $url = Util::addParameter($url, 'view_html_images', 1);
- $attributes = $inline ? array() : array('style' => 'color:blue');
- $msg = Horde::img('mime/image.png') . ' ' . String::convertCharset(_("Images have been blocked to protect your privacy."), $charset, $msg_charset) . ' ' . Horde::link($url, '', '', '', 'return IMP.unblockImages(' . (!$inline ? 'document.body' : '$(\'html-message\')') . ', \'block-images\');', '', '', $attributes) . String::convertCharset(_("Show Images?"), $charset, $msg_charset) . '</a>';
- $data = preg_replace_callback($this->_img_regex, array($this, '_blockImages'), $data);
- if (!$inline) {
- $msg = '<span style="background:#fff;color:#000">' . nl2br($msg) . '</span><br />';
- }
- $msg = '<span id="block-images">' . $msg . '</span>';
- }
- }
-
- /* If we are viewing inline, give option to view in separate window. */
- if ($inline && $this->getConfigParam('external')) {
- $cleanhtml['status'][] = array(
- 'data' => $this->_params['contents']->linkViewJS($this->mime_part, 'view_attach', _("Show this HTML in a new window?")),
- 'type' => 'info'
- );
- }
-
- return array(
- 'html' => $data,
- 'status' => $cleanhtml['status']
- );
- }
-
- /**
- * TODO
- */
- protected function _mailtoCallback($m)
- {
- return 'href="' . $GLOBALS['registry']->call('mail/compose', array(String::convertCharset(html_entity_decode($m[2]), 'ISO-8859-1', NLS::getCharset()))) . '"';
- }
-
- /**
- * Called from the image-blocking regexp to construct the new image tags.
- *
- * @param array $matches
- *
- * @return string The new image tag.
- */
- protected function _blockImages($matches)
- {
- if (is_null($this->_blockimg)) {
- $this->_blockimg = Horde::url($GLOBALS['registry']->getImageDir('imp') . '/spacer_red.png', false, -1);
- }
-
- return empty($matches[2])
- ? $matches[1] . '"' . $this->_blockimg . '" blocked="' . rawurlencode(str_replace('&', '&', trim($matches[5], '\'" '))) . '"'
- : $matches[1] . "'" . $this->_blockimg . '\')' . $matches[6] . '" blocked="' . rawurlencode(str_replace('&', '&', trim($matches[5], '\'" ')));
- }
-
- /**
- * Determine whether the sender appears in an available addressbook.
- *
- * @return boolean Does the sender appear in an addressbook?
- */
- protected function _inAddressBook()
- {
- /* If we don't have a contacts provider available, give up. */
- if (!$GLOBALS['registry']->hasMethod('contacts/getField')) {
- return false;
- }
-
- $params = IMP_Compose::getAddressSearchParams();
-
- // TODO
- // get mime_message.
-
- /* Try to get back a result from the search. */
- $result = $GLOBALS['registry']->call('contacts/getField', array($base_ob->getFromAddress(), '__key', $params['sources'], false, true));
-
- return is_a($result, 'PEAR_Error')
- ? false
- : (count($result) > 0);
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_images class allows images to be displayed
- * inline in a message.
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_images extends Horde_Mime_Viewer_images
-{
- /**
- * The content-type of the generated data.
- *
- * @var string
- */
- protected $_contentType;
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered information.
- */
- public function render($params)
- {
- $contents = $params[0];
-
- global $browser;
-
- /* If calling page is asking us to output data, do that without any
- * further delay and exit. */
- if (Util::getFormData('img_data')) {
- return parent::render();
- }
-
- /* Convert the image to browser-viewable format and display. */
- if (Util::getFormData('images_view_convert')) {
- return $this->_viewConvert();
- }
-
- /* Create the thumbnail and display. */
- if (Util::getFormData('images_view_thumbnail')) {
- return $this->_viewConvert(true);
- }
-
- if (Util::getFormData('images_load_convert')) {
- return $this->_popupImageWindow();
- }
-
- if ($this->viewAsAttachment()) {
- if (!$browser->hasFeature('javascript')) {
- /* If the browser doesn't support javascript then simply
- render the image data. */
- return parent::render();
- } elseif ($browser->isViewable(parent::getType())) {
- /* The browser can display the image type directly - just
- output the javascript code to render the auto resize popup
- image window. */
- return $this->_popupImageWindow();
- }
- }
-
- if ($browser->isViewable($this->mime_part->getType())) {
- /* If we are viewing inline, and the browser can handle the image
- type directly, output an <img> tag to load the image. */
- $alt = $this->mime_part->getName(false, true);
- return Horde::img($contents->urlView($this->mime_part, 'view_attach'), $alt, null, '');
- } else {
- /* If we have made it this far, than the browser cannot view this
- image inline. Inform the user of this and, possibly, ask user
- if we should convert to another image type. */
- $msg = _("Your browser does not support inline display of this image type.");
-
- if ($this->viewAsAttachment()) {
- $msg .= '<br />' . sprintf(_("Click %s to download the image."), $contents->linkView($this->mime_part, 'download_attach', _("HERE"), array('viewparams' => array('img_data' => 1)), true));
- }
-
- /* See if we can convert to an inline browser viewable form. */
- $img = $this->_getHordeImageOb(false);
- if ($img && $browser->isViewable($img->getContentType())) {
- if ($this->viewAsAttachment()) {
- $convert_link = Horde::link($contents->urlView($this->mime_part, 'view_attach', array('images_load_convert' => 1))) . _("HERE") . '</a>';
- } else {
- $convert_link = $contents->linkViewJS($this->mime_part, 'view_attach', _("HERE"), null, null, array('images_load_convert' => 1));
- }
- $msg .= '<br />' . sprintf(_("Click %s to convert the image file into a format your browser can view."), $convert_link);
- }
-
- $this->_contentType = 'text/html; charset=' . NLS::getCharset();
- return $this->formatStatusMsg($msg);
- }
- }
-
- /**
- * Return the content-type
- *
- * @return string The content-type of the output.
- */
- public function getType()
- {
- return ($this->_contentType) ? $this->_contentType : parent::getType();
- }
-
- /**
- * Render out attachment information.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function renderAttachmentInfo($params)
- {
- $contents = &$params[0];
-
- /* Display the thumbnail link only if we show thumbs for all images or
- if image is over 50 KB. */
- if (!$this->getConfigParam('allthumbs') &&
- ($this->mime_part->getBytes() < 51200)) {
- return '';
- }
-
- if (is_a($contents, 'IMP_Contents')) {
- $this->mime_part = &$contents->getDecodedMIMEPart($this->mime_part->getMIMEId(), true);
- }
-
- /* Check to see if convert utility is available. */
- if (!$this->_getHordeImageOb(false)) {
- return '';
- }
-
- $status = array(
- sprintf(_("An image named %s is attached to this message. A thumbnail is below."),
- $this->mime_part->getName(true)),
- );
-
- if (!$GLOBALS['browser']->hasFeature('javascript')) {
- $status[] = Horde::link($contents->urlView($this->mime_part,
- 'view_attach')) .
- Horde::img($contents->urlView($this->mime_part,
- 'view_attach', array('images_view_thumbnail' => 1), false),
- _("View Attachment"), null, '') . '</a>';
- } else {
- $status[] = $contents->linkViewJS($this->mime_part, 'view_attach',
- Horde::img($contents->urlView($this->mime_part,
- 'view_attach', array('images_view_thumbnail' => 1),
- false), _("View Attachment"), null, ''), null, null,
- null);
- }
-
- return $this->formatStatusMsg($status, Horde::img('mime/image.png',
- _("Thumbnail of attached image"), null, $GLOBALS['registry']->getImageDir('horde')), false);
- }
-
- /**
- * Generate the HTML output for the JS auto-resize view window.
- *
- * @return string The HTML output.
- */
- protected function _popupImageWindow()
- {
- $params = $remove_params = array();
- if (Util::getFormData('images_load_convert')) {
- $params['images_view_convert'] = 1;
- $remove_params[] = 'images_load_convert';
- } else {
- $params['img_data'] = 1;
- }
- $self_url = Util::addParameter(Util::removeParameter(Horde::selfUrl(true), $remove_params), $params);
- $title = MIME::decode($this->mime_part->getName(false, true));
- $this->_contentType = 'text/html; charset=' . NLS::getCharset();
- return parent::_popupImageWindow($self_url, $title);
- }
-
- /**
- * View thumbnail sized image.
- *
- * @param boolean $thumb View thumbnail size?
- *
- * @return string The image data.
- */
- protected function _viewConvert($thumb = false)
- {
- $mime = $this->mime_part;
- $img = $this->_getHordeImageOb();
-
- if ($img) {
- if ($thumb) {
- $img->resize(96, 96, true);
- }
- $type = $img->getContentType();
- $data = $img->raw(true);
- }
-
- if (!$img || !$data) {
- $type = 'image/png';
- $data = file_get_contents(IMP_BASE . '/themes/graphics/mini-error.png');
- }
-
- $mime->setType($type);
- $this->_contentType = $type;
- $mime->setContents($data);
-
- return $mime->getContents();
- }
-
- /**
- * Return a Horde_Image object.
- *
- * @param boolean $load Whether to load the image data.
- *
- * @return Horde_Image The requested object.
- */
- protected function _getHordeImageOb($load = true)
- {
- include_once 'Horde/Image.php';
- $params = array('temp' => Horde::getTempdir());
- if (!empty($GLOBALS['conf']['image']['convert'])) {
- $img = &Horde_Image::singleton('im', $params);
- } elseif (Util::extensionExists('gd')) {
- $img = &Horde_Image::singleton('gd', $params);
- } else {
- return false;
- }
-
- if (is_a($img, 'PEAR_Error')) {
- return false;
- }
-
- if ($load) {
- $ret = $img->loadString(1, $this->mime_part->getContents());
- if (is_a($ret, 'PEAR_Error')) {
- return false;
- }
- }
-
- return $img;
- }
-
- /**
- * Can this driver render the the data inline?
- *
- * @return boolean True if the driver can display inline.
- */
- public function canDisplayInline()
- {
- /* Only display the image inline if the configuration parameter is set,
- the browser can actually display it, and the size of the image is
- small. */
- global $browser;
- if (($this->getConfigParam('inline')) && ($browser->isViewable($this->mime_part->getType())) &&
- ($this->mime_part->getBytes() < 51200)) {
- return true;
- } else {
- return false;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_HordeMIME_Viewer_itip class displays vCalendar/iCalendar data
- * and provides an option to import the data into a calendar source,
- * if one is available.
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @author Mike Cochrane <mike@graftonhall.co.nz>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_itip extends Horde_Mime_Viewer_Driver
-{
- /**
- * Force viewing of a part inline, regardless of the Content-Disposition
- * of the MIME Part.
- *
- * @var boolean
- */
- protected $_forceinline = true;
-
- /**
- * The messages to output to the user.
- *
- * @var array
- */
- protected $_msgs = array();
-
- /**
- * The method as marked in either the iCal structure or message header.
- *
- * @var string
- */
- protected $_method = 'PUBLISH';
-
- /**
- * The headers of the message.
- *
- * @var string
- */
- protected $_headers;
-
- /**
- * Render out the currently set iCalendar contents.
- *
- * @param array $params Any parameters the Viewer may need.
- *
- * @return string The rendered contents.
- */
- public function render($params = array())
- {
- global $registry;
-
- // Extract the data.
- $data = $this->mime_part->getContents();
- if (empty($this->_headers) && is_a($params[0], 'IMP_Contents')) {
- $this->_headers = $params[0]->getHeaderOb();
- }
-
- // Parse the iCal file.
- $vCal = new Horde_iCalendar();
- if (!$vCal->parsevCalendar($data, 'VCALENDAR', $this->mime_part->getCharset())) {
- return '<h1>' . _("The calendar data is invalid") . '</h1>' .
- '<pre>' . htmlspecialchars($data) . '</pre>';
- }
-
- // Check if we got vcard data with the wrong vcalendar mime type.
- $c = $vCal->getComponentClasses();
- if (count($c) == 1 && !empty($c['horde_icalendar_vcard'])) {
- $vcard_renderer = &Horde_Mime_Viewer::factory($this->mime_part, 'text/x-vcard');
- return $vcard_renderer->render($params);
- }
-
- // Get the method type.
- $this->_method = $vCal->getAttribute('METHOD');
- if (is_a($this->_method, 'PEAR_Error')) {
- $this->_method = '';
- }
-
- // Get the iCalendar file components.
- $components = $vCal->getComponents();
-
- // Handle the action requests.
- $actions = Util::getFormData('action', array());
- foreach ($actions as $key => $action) {
- $this->_msgs[$key] = array();
- switch ($action) {
- case 'delete':
- // vEvent cancellation.
- if ($registry->hasMethod('calendar/delete')) {
- $guid = $components[$key]->getAttribute('UID');
- $event = $registry->call('calendar/delete', array('guid' => $guid));
- if (is_a($event, 'PEAR_Error')) {
- $this->_msgs[$key][] = array('error', _("There was an error deleting the event:") . ' ' . $event->getMessage());
- } else {
- $this->_msgs[$key][] = array('success', _("Event successfully deleted."));
- }
- } else {
- $this->_msgs[$key][] = array('warning', _("This action is not supported."));
- }
- break;
-
- case 'update':
- // vEvent reply.
- if ($registry->hasMethod('calendar/updateAttendee')) {
- $event = $registry->call('calendar/updateAttendee', array('response' => $components[$key], 'sender' => $params[0]->getFromAddress()));
- if (is_a($event, 'PEAR_Error')) {
- $this->_msgs[$key][] = array('error', _("There was an error updating the event:") . ' ' . $event->getMessage());
- } else {
- $this->_msgs[$key][] = array('success', _("Respondent Status Updated."));
- }
- } else {
- $this->_msgs[$key][] = array('warning', _("This action is not supported."));
- }
- break;
-
- case 'import':
- case 'accept-import':
- // vFreebusy reply.
- // vFreebusy publish.
- // vEvent request.
- // vEvent publish.
- // vTodo publish.
- // vJournal publish.
- switch ($components[$key]->getType()) {
- case 'vEvent':
- $handled = false;
- $guid = $components[$key]->getAttribute('UID');
- // Check if this is an update.
- if ($registry->hasMethod('calendar/export') &&
- !is_a($registry->call('calendar/export', array($guid, 'text/calendar')), 'PEAR_Error')) {
- // Update in Kronolith.
- if ($registry->hasMethod('calendar/replace')) {
- $handled = true;
- $result = $registry->call('calendar/replace', array('uid' => $guid, 'content' => $components[$key], 'contentType' => $this->mime_part->getType()));
- if (is_a($result, 'PEAR_Error')) {
- $this->_msgs[$key][] = array('error', _("There was an error updating the event:") . ' ' . $result->getMessage());
- } else {
- $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
- $this->_msgs[$key][] = array('success', _("The event was updated in your calendar.") .
- ' ' . Horde::link($url, _("View event"), null, '_blank') . Horde::img('mime/icalendar.png', _("View event"), null, $registry->getImageDir('horde')) . '</a>');
- }
- }
- } else {
- // Import into Kronolith.
- if ($registry->hasMethod('calendar/import')) {
- $handled = true;
- $guid = $registry->call('calendar/import', array('content' => $components[$key], 'contentType' => $this->mime_part->getType()));
- if (is_a($guid, 'PEAR_Error')) {
- $this->_msgs[$key][] = array('error', _("There was an error importing the event:") . ' ' . $guid->getMessage());
- } else {
- $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
- $this->_msgs[$key][] = array('success', _("The event was added to your calendar.") .
- ' ' . Horde::link($url, _("View event"), null, '_blank') . Horde::img('mime/icalendar.png', _("View event"), null, $registry->getImageDir('horde')) . '</a>');
- }
- }
- }
- if (!$handled) {
- $this->_msgs[$key][] = array('warning', _("This action is not supported."));
- }
- break;
-
- case 'vFreebusy':
- // Import into Kronolith.
- if ($registry->hasMethod('calendar/import_vfreebusy')) {
- $res = $registry->call('calendar/import_vfreebusy', array($components[$key]));
- if (is_a($res, 'PEAR_Error')) {
- $this->_msgs[$key][] = array('error', _("There was an error importing user's free/busy information:") . ' ' . $res->getMessage());
- } else {
- $this->_msgs[$key][] = array('success', _("The user's free/busy information was sucessfully stored."));
- }
- } else {
- $this->_msgs[$key][] = array('warning', _("This action is not supported."));
- }
- break;
-
- case 'vTodo':
- // Import into Nag.
- if ($registry->hasMethod('tasks/import')) {
- $guid = $registry->call('tasks/import', array($components[$key], $this->mime_part->getType()));
- if (is_a($guid, 'PEAR_Error')) {
- $this->_msgs[$key][] = array('error', _("There was an error importing the task:") . ' ' . $guid->getMessage());
- } else {
- $url = Horde::url($registry->link('tasks/show', array('uid' => $guid)));
- $this->_msgs[$key][] = array('success', _("The task has been added to your tasklist.") .
- ' ' . Horde::link($url, _("View task"), null, '_blank') . Horde::img('mime/icalendar.png', _("View task"), null, $registry->getImageDir('horde')) . '</a>');
- }
- } else {
- $this->_msgs[$key][] = array('warning', _("This action is not supported."));
- }
- break;
-
- case 'vJournal':
- default:
- $this->_msgs[$key][] = array('warning', _("This action is not yet implemented."));
- }
-
- if ($action != 'accept-import') {
- break;
- }
-
- case 'accept':
- case 'accept-import':
- case 'deny':
- case 'tentative':
- // vEvent request.
- if (isset($components[$key]) &&
- $components[$key]->getType() == 'vEvent') {
- $vEvent = $components[$key];
-
- // Get the organizer details.
- $organizer = $vEvent->getAttribute('ORGANIZER');
- if (is_a($organizer, 'PEAR_Error')) {
- break;
- }
- $organizer = parse_url($organizer);
- $organizerEmail = $organizer['path'];
- $organizer = $vEvent->getAttribute('ORGANIZER', true);
- $organizerName = isset($organizer['cn']) ? $organizer['cn'] : '';
-
- require_once 'Horde/Identity.php';
-
- // Build the reply.
- $vCal = new Horde_iCalendar();
- $vCal->setAttribute('PRODID', '-//The Horde Project//' . HORDE_AGENT_HEADER . '//EN');
- $vCal->setAttribute('METHOD', 'REPLY');
-
- $vEvent_reply = &Horde_iCalendar::newComponent('vevent', $vCal);
- $vEvent_reply->setAttribute('UID', $vEvent->getAttribute('UID'));
- if (!is_a($vEvent->getAttribute('SUMMARY'), 'PEAR_error')) {
- $vEvent_reply->setAttribute('SUMMARY', $vEvent->getAttribute('SUMMARY'));
- }
- if (!is_a($vEvent->getAttribute('DESCRIPTION'), 'PEAR_error')) {
- $vEvent_reply->setAttribute('DESCRIPTION', $vEvent->getAttribute('DESCRIPTION'));
- }
- $dtstart = $vEvent->getAttribute('DTSTART', true);
- $vEvent_reply->setAttribute('DTSTART', $vEvent->getAttribute('DTSTART'), array_pop($dtstart));
- if (!is_a($vEvent->getAttribute('DTEND'), 'PEAR_error')) {
- $dtend = $vEvent->getAttribute('DTEND', true);
- $vEvent_reply->setAttribute('DTEND', $vEvent->getAttribute('DTEND'), array_pop($dtend));
- } else {
- $duration = $vEvent->getAttribute('DURATION', true);
- $vEvent_reply->setAttribute('DURATION', $vEvent->getAttribute('DURATION'), array_pop($duration));
- }
- if (!is_a($vEvent->getAttribute('SEQUENCE'), 'PEAR_error')) {
- $vEvent_reply->setAttribute('SEQUENCE', $vEvent->getAttribute('SEQUENCE'));
- }
- $vEvent_reply->setAttribute('ORGANIZER', $vEvent->getAttribute('ORGANIZER'), array_pop($organizer));
-
- // Find out who we are and update status.
- $identity = &Identity::singleton(array('imp', 'imp'));
- $attendees = $vEvent->getAttribute('ATTENDEE');
- if (!is_array($attendees)) {
- $attendees = array($attendees);
- }
- foreach ($attendees as $attendee) {
- $attendee = preg_replace('/mailto:/i', '', $attendee);
- if (!is_null($id = $identity->getMatchingIdentity($attendee))) {
- $identity->setDefault($id);
- break;
- }
- }
- $name = $email = $identity->getFromAddress();
- $params = array();
- $cn = $identity->getValue('fullname');
- if (!empty($cn)) {
- $name = $params['CN'] = $cn;
- }
-
- switch ($action) {
- case 'accept':
- case 'accept-import':
- $message = sprintf(_("%s has accepted."), $name);
- $subject = _("Accepted: ") . $vEvent->getAttribute('SUMMARY');
- $params['PARTSTAT'] = 'ACCEPTED';
- break;
-
- case 'deny':
- $message = sprintf(_("%s has declined."), $name);
- $subject = _("Declined: ") . $vEvent->getAttribute('SUMMARY');
- $params['PARTSTAT'] = 'DECLINED';
- break;
-
- case 'tentative':
- $message = sprintf(_("%s has tentatively accepted."), $name);
- $subject = _("Tentative: ") . $vEvent->getAttribute('SUMMARY');
- $params['PARTSTAT'] = 'TENTATIVE';
- break;
- }
-
- $vEvent_reply->setAttribute('ATTENDEE', 'mailto:' . $email, $params);
- $vCal->addComponent($vEvent_reply);
-
- $mime = new Horde_Mime_Part('multipart/alternative');
- $body = new Horde_Mime_Part('text/plain',
- String::wrap($message, 76, "\n"),
- NLS::getCharset());
-
- $ics = new Horde_Mime_Part('text/calendar', $vCal->exportvCalendar());
- $ics->setName('event-reply.ics');
- $ics->setContentTypeParameter('METHOD', 'REPLY');
- $ics->setCharset(NLS::getCharset());
-
- $mime->addPart($body);
- $mime->addPart($ics);
- $mime = &Horde_Mime_Message::convertMimePart($mime);
-
- // Build the reply headers.
- $msg_headers = new Horde_Mime_Headers();
- $msg_headers->addReceivedHeader();
- $msg_headers->addMessageIdHeader();
- $msg_headers->addHeader('Date', date('r'));
- $msg_headers->addHeader('From', $email);
- $msg_headers->addHeader('To', $organizerEmail);
-
- $identity->setDefault(Util::getFormData('identity'));
- $replyto = $identity->getValue('replyto_addr');
- if (!empty($replyto) && ($replyto != $email)) {
- $msg_headers->addHeader('Reply-to', $replyto);
- }
- $msg_headers->addHeader('Subject', Horde_Mime::encode($subject, NLS::getCharset()));
-
- // Send the reply.
- $status = $mime->send($organizerEmail, $msg_headers,
- $GLOBALS['conf']['mailer']['type'],
- $GLOBALS['conf']['mailer']['params']);
- if (is_a($status, 'PEAR_Error')) {
- $this->_msgs[$key][] = array('error', sprintf(_("Error sending reply: %s."), $status->getMessage()));
- } else {
- $this->_msgs[$key][] = array('success', _("Reply Sent."));
- }
- } else {
- $this->_msgs[$key][] = array('warning', _("This action is not supported."));
- }
- break;
-
- case 'send':
- // vEvent refresh.
- if (isset($components[$key]) &&
- $components[$key]->getType() == 'vEvent') {
- $vEvent = $components[$key];
- }
-
- // vTodo refresh.
- case 'reply':
- case 'reply2m':
- // vfreebusy request.
- if (isset($components[$key]) &&
- $components[$key]->getType() == 'vFreebusy') {
- $vFb = $components[$key];
-
- // Get the organizer details.
- $organizer = $vFb->getAttribute('ORGANIZER');
- if (is_a($organizer, 'PEAR_Error')) {
- break;
- }
- $organizer = parse_url($organizer);
- $organizerEmail = $organizer['path'];
- $organizer = $vFb->getAttribute('ORGANIZER', true);
- $organizerName = isset($organizer['cn']) ? $organizer['cn'] : '';
-
- if ($action == 'reply2m') {
- $startStamp = time();
- $endStamp = $startStamp + (60 * 24 * 3600);
- } else {
- $startStamp = $vFb->getAttribute('DTSTART');
- if (is_a($startStamp, 'PEAR_Error')) {
- $startStamp = time();
- }
- $endStamp = $vFb->getAttribute('DTEND');
- if (is_a($endStamp, 'PEAR_Error')) {
- $duration = $vFb->getAttribute('DURATION');
- if (is_a($duration, 'PEAR_Error')) {
- $endStamp = $startStamp + (60 * 24 * 3600);
- } else {
- $endStamp = $startStamp + $duration;
- }
- }
- }
- $vfb_reply = $registry->call('calendar/getFreeBusy',
- array('startStamp' => $startStamp,
- 'endStamp' => $endStamp));
- require_once 'Horde/Identity.php';
-
- // Find out who we are and update status.
- $identity = &Identity::singleton();
- $email = $identity->getFromAddress();
-
- // Build the reply.
- $vCal = new Horde_iCalendar();
- $vCal->setAttribute('PRODID', '-//The Horde Project//' . HORDE_AGENT_HEADER . '//EN');
- $vCal->setAttribute('METHOD', 'REPLY');
- $vCal->addComponent($vfb_reply);
-
- $mime = new Horde_Mime_Message();
- $message = _("Attached is a reply to a calendar request you sent.");
- $body = new Horde_Mime_Part('text/plain',
- String::wrap($message, 76, "\n"),
- NLS::getCharset());
-
- $ics = new Horde_Mime_Part('text/calendar', $vCal->exportvCalendar());
- $ics->setName('icalendar.ics');
- $ics->setContentTypeParameter('METHOD', 'REPLY');
- $ics->setCharset(NLS::getCharset());
-
- $mime->addPart($body);
- $mime->addPart($ics);
-
- // Build the reply headers.
- $msg_headers = new Horde_Mime_Headers();
- $msg_headers->addReceivedHeader();
- $msg_headers->addMessageIdHeader();
- $msg_headers->addHeader('Date', date('r'));
- $msg_headers->addHeader('From', $email);
- $msg_headers->addHeader('To', $organizerEmail);
-
- $identity->setDefault(Util::getFormData('identity'));
- $replyto = $identity->getValue('replyto_addr');
- if (!empty($replyto) && ($replyto != $email)) {
- $msg_headers->addHeader('Reply-to', $replyto);
- }
- $msg_headers->addHeader('Subject', Horde_Mime::encode(_("Free/Busy Request Response"), NLS::getCharset()));
-
- // Send the reply.
- $status = $mime->send($organizerEmail, $msg_headers,
- $GLOBALS['conf']['mailer']['type'],
- $GLOBALS['conf']['mailer']['params']);
- if (is_a($status, 'PEAR_Error')) {
- $this->_msgs[$key][] = array('error', sprintf(_("Error sending reply: %s."), $status->getMessage()));
- } else {
- $this->_msgs[$key][] = array('success', _("Reply Sent."));
- }
- } else {
- $this->_msgs[$key][] = array('warning', _("Invalid Action selected for this component."));
- }
- break;
-
- case 'nosup':
- // vFreebusy request.
- default:
- $this->_msgs[$key][] = array('warning', _("This action is not yet implemented."));
- break;
- }
- }
-
- // Create the HTML to display the iCal file.
- $html = '';
- if ($this->viewAsAttachment()) {
- $html .= Util::bufferOutput('require', $registry->get('templates', 'horde') . '/common-header.inc');
- }
- if ($_SESSION['imp']['viewmode'] == 'imp') {
- $html .= '<form method="post" name="iCal" action="' . Horde::selfUrl(true) . '">';
- }
-
- foreach ($components as $key => $component) {
- switch ($component->getType()) {
- case 'vEvent':
- $html .= $this->_vEvent($component, $key);
- break;
-
- case 'vTodo':
- $html .= $this->_vTodo($component, $key);
- break;
-
- case 'vTimeZone':
- // Ignore them.
- break;
-
- case 'vFreebusy':
- $html .= $this->_vFreebusy($component, $key);
- break;
-
- // @todo: handle stray vcards here as well.
- default:
- $html .= sprintf(_("Unhandled component of type: %s"), $component->getType());
- }
- }
-
- // Need to work out if we are inline and actually need this.
- if ($_SESSION['imp']['viewmode'] == 'imp') {
- $html .= '</form>';
- }
- if ($this->viewAsAttachment()) {
- $html .= Util::bufferOutput('require', $registry->get('templates', 'horde') . '/common-footer.inc');
- }
-
- return $html;
- }
-
- /**
- * Return text/html as the content-type.
- *
- * @return string "text/html" constant
- */
- public function getType()
- {
- return 'text/html; charset=' . NLS::getCharset();
- }
-
- /**
- * Return the html for a vFreebusy.
- */
- protected function _vFreebusy($vfb, $id)
- {
- global $registry, $prefs;
-
- $html = '';
- $desc = '';
- $sender = $vfb->getName();
- switch ($this->_method) {
- case 'PUBLISH':
- $desc = _("%s has sent you free/busy information.");
- break;
-
- case 'REQUEST':
- $sender = $this->_headers->getValue('From');
- $desc = _("%s requests your free/busy information.");
- break;
-
- case 'REPLY':
- $desc = _("%s has replied to a free/busy request.");
- break;
- }
-
- $html .= '<h1 class="header">' . sprintf($desc, $sender) . '</h1>';
-
- if ($this->_msgs) {
- foreach ($this->_msgs[$id] as $msg) {
- $html .= '<p class="notice">' . Horde::img('alerts/' . $msg[0] . '.png', '', null, $registry->getImageDir('horde')) . $msg[1] . '</p>';
- }
- }
-
- $start = $vfb->getAttribute('DTSTART');
- if (!is_a($start, 'PEAR_Error')) {
- if (is_array($start)) {
- $html .= '<p><strong>' . _("Start") . ':</strong> ' . strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $start['month'], $start['mday'], $start['year'])) . '</p>';
- } else {
- $html .= '<p><strong>' . _("Start") . ':</strong> ' . strftime($prefs->getValue('date_format'), $start) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $start) . '</p>';
- }
- }
-
- $end = $vfb->getAttribute('DTEND');
- if (!is_a($end, 'PEAR_Error')) {
- if (is_array($end)) {
- $html .= '<p><strong>' . _("End") . ':</strong> ' . strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $end['month'], $end['mday'], $end['year'])) . '</p>';
- } else {
- $html .= '<p><strong>' . _("End") . ':</strong> ' . strftime($prefs->getValue('date_format'), $end) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $end) . '</p>';
- }
- }
-
- if ($_SESSION['imp']['viewmode'] != 'imp') {
- return $html;
- }
-
- $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
- '<select name="action[' . $id . ']">';
-
- switch ($this->_method) {
- case 'PUBLISH':
- if ($registry->hasMethod('calendar/import_vfreebusy')) {
- $html .= '<option value="import">' . _("Remember the free/busy information.") . '</option>';
- } else {
- $html .= '<option value="nosup">' . _("Reply with Not Supported Message") . '</option>';
- }
- break;
-
- case 'REQUEST':
- if ($registry->hasMethod('calendar/getFreeBusy')) {
- $html .= '<option value="reply">' . _("Reply with requested free/busy information.") . '</option>' .
- '<option value="reply2m">' . _("Reply with free/busy for next 2 months.") . '</option>';
- } else {
- $html .= '<option value="nosup">' . _("Reply with Not Supported Message") . '</option>';
- }
-
- $html .= '<option value="deny">' . _("Deny request for free/busy information") . '</option>';
- break;
-
- case 'REPLY':
- if ($registry->hasMethod('calendar/import_vfreebusy')) {
- $html .= '<option value="import">' . _("Remember the free/busy information.") . '</option>';
- } else {
- $html .= '<option value="nosup">' . _("Reply with Not Supported Message") . '</option>';
- }
- break;
- }
-
- return $html . '</select> <input type="submit" class="button" value="' . _("Go") . '/>';
- }
-
- /**
- * Return the html for a vEvent.
- */
- protected function _vEvent($vevent, $id)
- {
- global $registry, $prefs;
-
- $html = '';
- $desc = '';
- $sender = $vevent->organizerName();
- $options = array();
-
- $attendees = $vevent->getAttribute('ATTENDEE');
- if (!is_a($attendees, 'PEAR_Error') &&
- !empty($attendees) &&
- !is_array($attendees)) {
- $attendees = array($attendees);
- }
- $attendee_params = $vevent->getAttribute('ATTENDEE', true);
-
- switch ($this->_method) {
- case 'PUBLISH':
- $desc = _("%s wishes to make you aware of \"%s\".");
- if ($registry->hasMethod('calendar/import')) {
- $options[] = '<option value="import">' . _("Add this to my calendar") . '</option>';
- }
- break;
-
- case 'REQUEST':
- // Check if this is an update.
- if ($registry->hasMethod('calendar/export') &&
- !is_a($registry->call('calendar/export', array($vevent->getAttribute('UID'), 'text/calendar')), 'PEAR_Error')) {
- $is_update = true;
- $desc = _("%s wants to notify you about changes of \"%s\".");
- } else {
- $is_update = false;
-
- // Check that you are one of the attendees here.
- $is_attendee = false;
- if (!is_a($attendees, 'PEAR_Error') && !empty($attendees)) {
- require_once 'Horde/Identity.php';
- $identity = &Identity::singleton(array('imp', 'imp'));
- for ($i = 0, $c = count($attendees); $i < $c; ++$i) {
- $attendee = parse_url($attendees[$i]);
- if (!empty($attendee['path']) &&
- $identity->hasAddress($attendee['path'])) {
- $is_attendee = true;
- break;
- }
- }
- }
-
- $desc = $is_attendee
- ? _("%s requests your presence at \"%s\".")
- : _("%s wishes to make you aware of \"%s\".");
- }
- if ($is_update && $registry->hasMethod('calendar/replace')) {
- $options[] = '<option value="accept-import">' . _("Accept and update in my calendar") . '</option>';
- $options[] = '<option value="import">' . _("Update in my calendar") . '</option>';
- } elseif ($registry->hasMethod('calendar/import')) {
- $options[] = '<option value="accept-import">' . _("Accept and add to my calendar") . '</option>';
- $options[] = '<option value="import">' . _("Add to my calendar") . '</option>';
- }
- $options[] = '<option value="accept">' . _("Accept request") . '</option>';
- $options[] = '<option value="tentative">' . _("Tentatively Accept request") . '</option>';
- $options[] = '<option value="deny">' . _("Deny request") . '</option>';
- // $options[] = '<option value="delegate">' . _("Delegate position") . '</option>';
- break;
-
- case 'ADD':
- $desc = _("%s wishes to ammend \"%s\".");
- if ($registry->hasMethod('calendar/import')) {
- $options[] = '<option value="import">' . _("Update this event on my calendar") . '</option>';
- }
- break;
-
- case 'REFRESH':
- $desc = _("%s wishes to receive the latest information about \"%s\".");
- $options[] = '<option value="send">' . _("Send Latest Information") . '</option>';
- break;
-
- case 'REPLY':
- $desc = _("%s has replied to the invitation to \"%s\".");
- $sender = $this->_headers->getValue('From');
- if ($registry->hasMethod('calendar/updateAttendee')) {
- $options[] = '<option value="update">' . _("Update respondent status") . '</option>';
- }
- break;
-
- case 'CANCEL':
- if (is_a($instance = $vevent->getAttribute('RECURRENCE-ID'), 'PEAR_Error')) {
- $desc = _("%s has cancelled \"%s\".");
- if ($registry->hasMethod('calendar/delete')) {
- $options[] = '<option value="delete">' . _("Delete from my calendar") . '</option>';
- }
- } else {
- $desc = _("%s has cancelled an instance of the recurring \"%s\".");
- if ($registry->hasMethod('calendar/replace')) {
- $options[] = '<option value="import">' . _("Update in my calendar") . '</option>';
- }
- }
- break;
- }
-
- $summary = $vevent->getAttribute('SUMMARY');
- if (is_a($summary, 'PEAR_Error')) {
- $desc = sprintf($desc, htmlspecialchars($sender), _("Unknown Meeting"));
- } else {
- $desc = sprintf($desc, htmlspecialchars($sender), htmlspecialchars($summary));
- }
-
- $html .= '<h2 class="header">' . $desc . '</h2>';
-
- if ($this->_msgs) {
- foreach ($this->_msgs[$id] as $msg) {
- $html .= '<p class="notice">' . Horde::img('alerts/' . $msg[0] . '.png', '', null, $registry->getImageDir('horde')) . $msg[1] . '</p>';
- }
- }
-
- $start = $vevent->getAttribute('DTSTART');
- if (!is_a($start, 'PEAR_Error')) {
- if (is_array($start)) {
- $html .= '<p><strong>' . _("Start") . ':</strong> ' . strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $start['month'], $start['mday'], $start['year'])) . '</p>';
- } else {
- $html .= '<p><strong>' . _("Start") . ':</strong> ' . strftime($prefs->getValue('date_format'), $start) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $start) . '</p>';
- }
- }
-
- $end = $vevent->getAttribute('DTEND');
- if (!is_a($end, 'PEAR_Error')) {
- if (is_array($end)) {
- $html .= '<p><strong>' . _("End") . ':</strong> ' . strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $end['month'], $end['mday'], $end['year'])) . '</p>';
- } else {
- $html .= '<p><strong>' . _("End") . ':</strong> ' . strftime($prefs->getValue('date_format'), $end) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $end) . '</p>';
- }
- }
-
- $sum = $vevent->getAttribute('SUMMARY');
- if (!is_a($sum, 'PEAR_Error')) {
- $html .= '<p><strong>' . _("Summary") . ':</strong> ' . htmlspecialchars($sum) . '</p>';
- } else {
- $html .= '<p><strong>' . _("Summary") . ':</strong> <em>' . _("None") . '</em></p>';
- }
-
- $desc = $vevent->getAttribute('DESCRIPTION');
- if (!is_a($desc, 'PEAR_Error')) {
- $html .= '<p><strong>' . _("Description") . ':</strong> ' . nl2br(htmlspecialchars($desc)) . '</p>';
- }
-
- $loc = $vevent->getAttribute('LOCATION');
- if (!is_a($loc, 'PEAR_Error')) {
- $html .= '<p><strong>' . _("Location") . ':</strong> ' . htmlspecialchars($loc) . '</p>';
- }
-
- if (!is_a($attendees, 'PEAR_Error') && !empty($attendees)) {
- $html .= '<h2 class="smallheader">' . _("Attendees") . '</h2>';
-
- $html .= '<table><thead class="leftAlign"><tr><th>' . _("Name") . '</th><th>' . _("Role") . '</th><th>' . _("Status") . '</th></tr></thead><tbody>';
- foreach ($attendees as $key => $attendee) {
- $attendee = parse_url($attendee);
- $attendee = empty($attendee['path']) ? _("Unknown") : $attendee['path'];
-
- if (!empty($attendee_params[$key]['CN'])) {
- $attendee = $attendee_params[$key]['CN'];
- }
-
- $role = _("Required Participant");
- if (isset($attendee_params[$key]['ROLE'])) {
- switch ($attendee_params[$key]['ROLE']) {
- case 'CHAIR':
- $role = _("Chair Person");
- break;
-
- case 'OPT-PARTICIPANT':
- $role = _("Optional Participant");
- break;
-
- case 'NON-PARTICIPANT':
- $role = _("Non Participant");
- break;
-
- case 'REQ-PARTICIPANT':
- default:
- // Already set above.
- break;
- }
- }
-
- $status = _("Awaiting Response");
- if (isset($attendee_params[$key]['PARTSTAT'])) {
- $status = $this->_partstatToString($attendee_params[$key]['PARTSTAT'], $status);
- }
-
- $html .= '<tr><td>' . htmlspecialchars($attendee) . '</td><td>' . htmlspecialchars($role) . '</td><td>' . htmlspecialchars($status) . '</td></tr>';
- }
- $html .= '</tbody></table>';
- }
-
- if ($_SESSION['imp']['viewmode'] != 'imp') {
- return $html;
- }
-
- if ($options) {
- $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
- '<label for="action_' . $id . '" class="hidden">' . _("Actions") . '</label>' .
- '<select id="action_' . $id . '" name="action[' . $id . ']">' .
- implode("\n", $options) .
- '</select> <input type="submit" class="button" value="' . _("Go") . '" />';
- }
-
- return $html;
- }
-
- /**
- * Returns the html for a vEvent.
- *
- * @todo IMP 5: move organizerName() from Horde_iCalendar_vevent to
- * Horde_iCalendar
- */
- protected function _vTodo($vtodo, $id)
- {
- global $registry, $prefs;
-
- $html = '';
- $desc = '';
- $options = array();
-
- $organizer = $vtodo->getAttribute('ORGANIZER', true);
- if (is_a($organizer, 'PEAR_Error')) {
- $sender = _("An unknown person");
- } else {
- if (isset($organizer[0]['CN'])) {
- $sender = $organizer[0]['CN'];
- } else {
- $organizer = parse_url($vtodo->getAttribute('ORGANIZER'));
- $sender = $organizer['path'];
- }
- }
-
- switch ($this->_method) {
- case 'PUBLISH':
- $desc = _("%s wishes to make you aware of \"%s\".");
- if ($registry->hasMethod('tasks/import')) {
- $options[] = '<option value="import">' . _("Add this to my tasklist") . '</option>';
- }
- break;
- }
-
- $summary = $vtodo->getAttribute('SUMMARY');
- if (is_a($summary, 'PEAR_Error')) {
- $desc = sprintf($desc, htmlspecialchars($sender), _("Unknown Task"));
- } else {
- $desc = sprintf($desc, htmlspecialchars($sender), htmlspecialchars($summary));
- }
-
- $html .= '<h2 class="header">' . $desc . '</h2>';
-
- if ($this->_msgs) {
- foreach ($this->_msgs[$id] as $msg) {
- $html .= '<p class="notice">' . Horde::img('alerts/' . $msg[0] . '.png', '', null, $registry->getImageDir('horde')) . $msg[1] . '</p>';
- }
- }
-
- $priority = $vtodo->getAttribute('PRIORITY');
- if (!is_a($priority, 'PEAR_Error')) {
- $html .= '<p><strong>' . _("Priority") . ':</strong> ' . (int)$priority . '</p>';
- }
-
- $sum = $vtodo->getAttribute('SUMMARY');
- if (!is_a($sum, 'PEAR_Error')) {
- $html .= '<p><strong>' . _("Summary") . ':</strong> ' . htmlspecialchars($sum) . '</p>';
- } else {
- $html .= '<p><strong>' . _("Summary") . ':</strong> <em>' . _("None") . '</em></p>';
- }
-
- $desc = $vtodo->getAttribute('DESCRIPTION');
- if (!is_a($desc, 'PEAR_Error')) {
- $html .= '<p><strong>' . _("Description") . ':</strong> ' . nl2br(htmlspecialchars($desc)) . '</p>';
- }
-
- $attendees = $vtodo->getAttribute('ATTENDEE');
- $params = $vtodo->getAttribute('ATTENDEE', true);
-
- if (!is_a($attendees, 'PEAR_Error') && !empty($attendees)) {
- $html .= '<h2 class="smallheader">' . _("Attendees") . '</h2>';
- if (!is_array($attendees)) {
- $attendees = array($attendees);
- }
-
- $html .= '<table><thead class="leftAlign"><tr><th>' . _("Name") . '</th><th>' . _("Role") . '</th><th>' . _("Status") . '</th></tr></thead><tbody>';
- foreach ($attendees as $key => $attendee) {
- $attendee = parse_url($attendee);
- $attendee = $attendee['path'];
-
- if (isset($params[$key]['CN'])) {
- $attendee = $params[$key]['CN'];
- }
-
- $role = _("Required Participant");
- if (isset($params[$key]['ROLE'])) {
- switch ($params[$key]['ROLE']) {
- case 'CHAIR':
- $role = _("Chair Person");
- break;
-
- case 'OPT-PARTICIPANT':
- $role = _("Optional Participant");
- break;
-
- case 'NON-PARTICIPANT':
- $role = _("Non Participant");
- break;
-
- case 'REQ-PARTICIPANT':
- default:
- // Already set above.
- break;
- }
- }
-
- $status = _("Awaiting Response");
- if (isset($params[$key]['PARTSTAT'])) {
- $status = $this->_partstatToString($params[$key]['PARTSTAT'], $status);
- }
-
- $html .= '<tr><td>' . htmlspecialchars($attendee) . '</td><td>' . htmlspecialchars($role) . '</td><td>' . htmlspecialchars($status) . '</td></tr>';
- }
- $html .= '</tbody></table>';
- }
-
- if ($_SESSION['imp']['viewmode'] != 'imp') {
- return $html;
- }
-
- if ($options) {
- $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
- '<select name="action[' . $id . ']">' .
- implode("\n", $options) .
- '</select> <input type="submit" class="button" value="' . _("Go") . '" />';
- }
-
- return $html;
- }
-
- /**
- * Translate the Participation status to string.
- *
- * @param string $value The value of PARTSTAT.
- * @param string $default The value to return as default.
- *
- * @return string The translated string.
- */
- protected function _partstatToString($value, $default = null)
- {
- switch ($value) {
- case 'ACCEPTED':
- return _("Accepted");
- break;
-
- case 'DECLINED':
- return _("Declined");
- break;
-
- case 'TENTATIVE':
- return _("Tentatively Accepted");
- break;
-
- case 'DELEGATED':
- return _("Delegated");
- break;
-
- case 'COMPLETED':
- return _("Completed");
- break;
-
- case 'IN-PROCESS':
- return _("In Process");
- break;
-
- case 'NEEDS-ACTION':
- default:
- return is_null($default) ? _("Needs Action") : $default;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_notification class handles multipart/report
- * messages that refer to mail notification messages (RFC 2298).
- *
- * Copyright 2003-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_notification extends Horde_Mime_Viewer_Driver
-{
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- /* If this is a straight message/disposition-notification part, just
- output the text. */
- if ($this->mime_part->getType() == 'message/disposition-notification') {
- $part = new MIME_Part('text/plain');
- $part->setContents($this->mime_part->getContents());
- return '<pre>' . htmlspecialchars($contents->renderMIMEPart($part)) . '</pre>';
- }
-
- global $registry;
-
- /* RFC 2298 [3]: There are three parts to a delivery status
- multipart/report message:
- (1) Human readable message
- (2) Machine parsable body part (message/disposition-notification)
- (3) Original message (optional) */
-
- /* Print the human readable message. */
- $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(1));
- $status = array(
- _("A message you have sent has resulted in a return notification from the recipient."),
- _("The mail server generated the following informational message:")
- );
- $statusimg = Horde::img('alerts/message.png', _("Attention"), 'height="16" width="16"', $registry->getImageDir('horde'));
- $text = $this->formatStatusMsg($status, $statusimg) .
- '<blockquote>' . $contents->renderMIMEPart($part) . '</blockquote>' . "\n";
-
- /* Display a link to more detailed message. */
- $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(2));
- if ($part) {
- $statusimg = Horde::img('info_icon.png', _("Info"), 'height="16" width="16"', $registry->getImageDir('horde'));
- $status = array(sprintf(_("Additional information can be viewed %s."), $contents->linkViewJS($part, 'view_attach', _("HERE"), _("Additional information details"))));
- }
-
- /* Display a link to the sent message. Try to download the text of
- the message/rfc822 part first, if it exists. */
- if (($part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId('3.0'))) ||
- ($part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(3)))) {
- $status[] = sprintf(_("The text of the sent message can be viewed %s."), $contents->linkViewJS($part, 'view_attach', _("HERE"), _("The text of the sent message")));
- }
-
- $text .= $this->formatStatusMsg($status, $statusimg, false);
-
- return $text;
- }
-
- /**
- * Return the content-type.
- *
- * @return string The content-type of the message.
- */
- public function getType()
- {
- return 'text/html; charset=' . NLS::getCharset();
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_partial class allows multipart/partial messages
- * to be displayed (RFC 2046 [5.2.2]).
- *
- * Copyright 2003-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_partial extends Horde_Mime_Viewer_Driver
-{
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- $base_ob = &$contents->getBaseObjectPtr();
- $curr_index = $base_ob->getMessageIndex();
- $id = $this->mime_part->getContentTypeParameter('id');
- $parts = array();
-
- /* Perform the search to find the other parts of the message. */
- $query = new Horde_Imap_Client_Search_Query();
- $query->header('Content-Type', $id);
-
- $indices = $GLOBALS['imp_search']->runSearchQuery($query, $GLOBALS['imp_mbox']['thismailbox']);
-
- /* If not able to find the other parts of the message, print error. */
- if (count($indices) != $this->mime_part->getContentTypeParameter('total')) {
- return $this->formatStatusMsg(sprintf(_("Cannot display - found only %s of %s parts of this message in the current mailbox."), count($indices), $this->mime_part->getContentTypeParameter('total')));
- }
-
- /* Get the contents of each of the parts. */
- foreach ($indices as $val) {
- /* No need to fetch the current part again. */
- if ($val == $curr_index) {
- $parts[$this->mime_part->getContentTypeParameter('number')] = $this->mime_part->getContents();
- } else {
- $imp_contents = &IMP_Contents::singleton($val . IMP::IDX_SEP . $GLOBALS['imp_mbox']['thismailbox']);
- $part = &$imp_contents->getMIMEPart(0);
- $parts[$part->getContentTypeParameter('number')] = $imp_contents->getBody();
- }
- }
-
- /* Sort the parts in numerical order. */
- ksort($parts, SORT_NUMERIC);
-
- /* Combine the parts and render the underlying data. */
- $mime_message = &MIME_Message::parseMessage(implode('', $parts));
- $mc = new MIME_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$contents));
- $mc->buildMessage();
-
- return '<table>' . $mc->getMessage(true) . '</table>';
- }
-
- /**
- * Return the content-type of the rendered output.
- *
- * @return string The content-type of the output.
- */
- public function getType()
- {
- return 'text/html; charset=' . NLS::getCharset();
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_pdf class enables generation of thumbnails for
- * PDF attachments.
- *
- * Copyright 2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime_Viewer
- */
-class IMP_Horde_Mime_Viewer_pdf extends Horde_Mime_Viewer_Driver
-{
- /**
- * The content-type of the generated data.
- *
- * @var string
- */
- protected $_contentType;
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered information.
- */
- public function render($params)
- {
- /* Create the thumbnail and display. */
- if (Util::getFormData('images_view_thumbnail')) {
- $mime = $this->mime_part;
- $img = $this->_getHordeImageOb();
-
- if ($img) {
- $img->resize(96, 96, true);
- $type = $img->getContentType();
- $data = $img->raw(true);
- }
-
- if (!$img || !$data) {
- $type = 'image/png';
- $data = file_get_contents(IMP_BASE . '/themes/graphics/mini-error.png');
- }
-
- $mime->setType($type);
- $this->_contentType = $type;
- $mime->setContents($data);
-
- return $mime->getContents();
- }
-
- return parent::render($params);
- }
-
- /**
- * Render out attachment information.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function renderAttachmentInfo($params)
- {
- $contents = &$params[0];
-
- if (is_a($contents, 'IMP_Contents')) {
- $this->mime_part = &$contents->getDecodedMIMEPart($this->mime_part->getMIMEId(), true);
- }
-
- /* Check to see if convert utility is available. */
- if (!$this->_getHordeImageOb(false)) {
- return '';
- }
-
- $status = array(
- sprintf(_("A PDF file named %s is attached to this message. A thumbnail is below."),
- $this->mime_part->getName(true)),
- );
-
- if (!$GLOBALS['browser']->hasFeature('javascript')) {
- $status[] = Horde::link($contents->urlView($this->mime_part,
- 'view_attach')) .
- Horde::img($contents->urlView($this->mime_part,
- 'view_attach', array('images_view_thumbnail' => 1), false),
- _("View Attachment"), null, '') . '</a>';
- } else {
- $status[] = $contents->linkViewJS($this->mime_part, 'view_attach',
- Horde::img($contents->urlView($this->mime_part,
- 'view_attach', array('images_view_thumbnail' => 1),
- false), _("View Attachment"), null, ''), null, null,
- null);
- }
-
- return $this->formatStatusMsg($status, Horde::img('mime/image.png',
- _("Thumbnail of attached PDF file"), null, $GLOBALS['registry']->getImageDir('horde')), false);
- }
-
- /**
- * Return a Horde_Image object.
- *
- * @param boolean $load Whether to load the image data.
- *
- * @return Horde_Image The requested object.
- */
- protected function _getHordeImageOb($load = true)
- {
- if (empty($GLOBALS['conf']['image']['convert'])) {
- return false;
- }
-
- include_once 'Horde/Image.php';
- $img = &Horde_Image::singleton('im', array('temp' => Horde::getTempdir()));
- if (is_a($img, 'PEAR_Error')) {
- return false;
- }
-
- if ($load) {
- $ret = $img->loadString(1, $this->mime_part->getContents());
- if (is_a($ret, 'PEAR_Error')) {
- return false;
- }
- }
-
- return $img;
- }
-
- /**
- * Return the content-type
- *
- * @return string The content-type of the output.
- */
- public function getType()
- {
- return ($this->_contentType) ? $this->_contentType : parent::getType();
- }
-}
+++ /dev/null
-<?php
-
-require_once IMP_BASE . '/lib/Crypt/PGP.php';
-
-/**
- * The IMP_Horde_Mime_Viewer_pgp class allows viewing/decrypting of PGP
- * formatted messages. This class implements RFC 3156.
- *
- * This class handles the following MIME types:
- * application/pgp-encryption
- * application/pgp-keys
- * application/pgp-signature
- *
- * This class may add the following parameters to the URL:
- * 'pgp_verify_msg' -- Do verification of PGP signed data.
- * 'rawpgpkey' -- Display the PGP Public Key in raw, text format
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_pgp extends Horde_Mime_Viewer_Driver
-{
- /**
- * IMP_PGP object.
- *
- * @var IMP_PGP
- */
- protected $_imp_pgp;
-
- /**
- * The address of the sender.
- *
- * @var string
- */
- protected $_address;
-
- /**
- * Pointer to the MIME_Contents item.
- *
- * @var MIME_Contents
- */
- protected $_contents = null;
-
- /**
- * Classwide cache for icons for status messages.
- *
- * @var string
- */
- protected $_icon = null;
-
- /**
- * Classwide cache for status messages.
- *
- * @var array
- */
- protected $_status = array();
-
- /**
- * The MIME content-type of this part.
- *
- * @var string
- */
- protected $_type = 'text/html';
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- global $conf, $prefs;
-
- /* Set the MIME_Contents class variable. */
- $this->_contents = &$params[0];
-
- $msg = '';
-
- if (empty($this->_imp_pgp) && !empty($conf['utils']['gnupg'])) {
- $this->_imp_pgp = new IMP_PGP();
- }
-
- /* Determine the address of the sender. */
- if (empty($this->_address)) {
- $base_ob = &$this->_contents->getBaseObjectPtr();
- $this->_address = $base_ob->getFromAddress();
- }
-
- /* We need to insert JavaScript code now if PGP support is active. */
- if (!empty($conf['utils']['gnupg']) &&
- $prefs->getValue('use_pgp') &&
- !Util::getFormData('rawpgpkey')) {
- $msg = Util::bufferOutput(array('Horde', 'addScriptFile'), 'prototype.js', 'horde', true);
- $msg .= Util::bufferOutput(array('Horde', 'addScriptFile'), 'popup.js', 'imp', true);
- }
-
- /* For RFC 2015/3156, there are 3 types of messages:
- + multipart/encrypted
- + multipart/signed
- + application/pgp-keys */
- switch ($this->mime_part->getType()) {
- case 'application/pgp-keys':
- $msg .= $this->_outputPGPKey();
- break;
-
- case 'multipart/signed':
- case 'application/pgp-signature':
- $msg .= $this->_outputPGPSigned();
- break;
-
- case 'multipart/encrypted':
- case 'application/pgp-encrypted':
- $msg .= $this->_outputPGPEncrypted();
- break;
- }
-
- return $msg;
- }
-
- /**
- * Return the content-type of the output.
- *
- * @return string The MIME content type of the output.
- */
- public function getType()
- {
- return $this->_type;
- }
-
- /**
- * Generates HTML output for 'application/pgp-keys' MIME_Parts.
- *
- * @return string The HTML output.
- */
- protected function _outputPGPKey()
- {
- global $conf, $prefs;
-
- $mime = &$this->mime_part;
- $part = $this->_contents->getDecodedMIMEPart($mime->getMIMEId());
-
- if (empty($conf['utils']['gnupg'])) {
- $text = '<pre>' . $part->getContents() . '</pre>';
- } elseif (Util::getFormData('rawpgpkey')) {
- $text = $part->getContents();
- $this->_type = 'text/plain';
- } else {
- require_once 'Horde/Text.php';
-
- $pgp_key = $mime->getContents();
-
- /* Initialize status message. */
- $this->_initStatus($this->getIcon($mime->getType()), _("PGP"));
- $msg = _("This PGP Public Key was attached to the message.");
- if ($prefs->getValue('use_pgp') &&
- $GLOBALS['registry']->hasMethod('contacts/addField') &&
- $prefs->getValue('add_source')) {
- $msg .= ' ' . Horde::link('#', '', '', '', $this->_imp_pgp->savePublicKeyURL($mime) . ' return false;') . _("[Save the key to your Address book]") . '</a>';
- }
- $this->_status[] = $msg . ' ' . $this->_contents->linkViewJS($part, 'view_attach', _("[View the raw key]"), '', null, array('rawpgpkey' => 1));
-
- $text = $this->_outputStatus(false) .
- '<span class="fixed">' . nl2br(str_replace(' ', ' ', $this->_imp_pgp->pgpPrettyKey($pgp_key))) . '</span>';
- }
-
- return $text;
- }
-
- /**
- * Generates HTML output for 'multipart/signed' and
- * 'application/pgp-signature' MIME_Parts.
- *
- * @return string The HTML output.
- */
- protected function _outputPGPSigned()
- {
- global $conf, $prefs;
-
- $active = ($prefs->getValue('use_pgp') && !empty($conf['utils']['gnupg']));
- $mime = &$this->mime_part;
- $mimetype = $mime->getType();
- $text = '';
-
- $signenc = $mime->getInformation('pgp_signenc');
- if (!$active) {
- if ($signenc) {
- $this->_status[] = _("The message below has been digitally signed and encrypted with PGP, but the signature cannot be verified.");
- } else {
- $this->_status[] = _("The message below has been digitally signed with PGP, but the signature cannot be verified.");
- }
- } else {
- if ($signenc) {
- $this->_status[] = _("The message below has been digitally signed and encrypted with PGP.");
- } else {
- $this->_status[] = _("The message below has been digitally signed with PGP.");
- }
- }
-
- $this->_initStatus($this->getIcon($mimetype), _("PGP"));
-
- /* Store PGP results in $sig_result; store text in $data. */
- $sig_result = null;
- if ($mimetype == 'multipart/signed') {
- /* If the MIME ID is 0, we need to store the body of the message
- in the MIME_Part object. */
- if (!$signenc) {
- if (($mimeID = $mime->getMIMEId())) {
- $mime->setContents($this->_contents->getBodyPart($mimeID));
- } else {
- $mime->setContents($this->_contents->getBody());
- }
- $mime->splitContents();
- }
-
- /* Data that is signed appears in the first MIME subpart. */
- $subpart = $mime->getPart($mime->getRelativeMIMEId(1));
- $signature_data = rtrim($subpart->getCanonicalContents(), "\r");
-
- $mime_message = Horde_Mime_Message::parseMessage($signature_data);
-
- /* The PGP signature appears in the second MIME subpart. */
- $subpart = $mime->getPart($mime->getRelativeMIMEId(2));
- if ($subpart && $subpart->getType() == 'application/pgp-signature') {
- if ($active) {
- if ($GLOBALS['prefs']->getValue('pgp_verify') ||
- Util::getFormData('pgp_verify_msg')) {
- $subpart->transferDecodeContents();
- $sig_result = $this->_imp_pgp->verifySignature($signature_data, $this->_address, $subpart->getContents());
- } elseif (isset($_SESSION['imp']['viewmode']) &&
- ($_SESSION['imp']['viewmode'] == 'imp')) {
- // TODO: Fix to work with DIMP
- $base_ob = &$this->_contents->getBaseObjectPtr();
- $this->_status[] = Horde::link(Util::addParameter(IMP::generateIMPUrl(Horde::selfUrl(), $GLOBALS['imp_mbox']['mailbox'], $GLOBALS['imp_mbox']['index'], $GLOBALS['imp_mbox']['thismailbox']), 'pgp_verify_msg', 1)) . _("Click HERE to verify the message.") . '</a>';
- }
- }
- } else {
- $this->_status[] = _("The message below does not appear to be in the correct PGP format (according to RFC 2015).");
- }
- } elseif ($mimetype == 'application/pgp-signature') {
- /* Get the signed message to output. */
- $mime_message = new Horde_Mime_Message();
- $mime_message->setType('text/plain');
- $mime->transferDecodeContents();
-
- if (empty($this->_imp_pgp)) {
- $mime_message->setContents($mime->getContents());
- } else {
- $mime_message->setContents($this->_imp_pgp->getSignedMessage($mime));
- }
-
- /* Pass the signed text straight through to PGP program */
- if ($active) {
- if ($GLOBALS['prefs']->getValue('pgp_verify') ||
- Util::getFormData('pgp_verify_msg')) {
- $sig_result = $this->_imp_pgp->verifySignature($mime->getContents(), $this->_address);
- } elseif (isset($_SESSION['imp']['viewmode']) &&
- ($_SESSION['imp']['viewmode'] == 'imp')) {
- // TODO: Fix to work with DIMP
- $this->_status[] = Horde::link(Util::addParameter(Horde::selfUrl(true), 'pgp_verify_msg', 1)) . _("Click HERE to verify the message.") . '</a>';
- }
- }
- }
-
- $text = $this->_outputStatus();
-
- if ($sig_result !== null) {
- $text .= $this->_outputPGPSignatureTest($sig_result);
- }
-
- /* We need to stick the output into a MIME_Contents object. */
- $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$this->_contents));
- $mc->buildMessage();
-
- return $text . '<table cellspacing="0">' . $mc->getMessage(true) . '</table>';
- }
-
- /**
- * Generates HTML output for 'multipart/encrypted' and
- * 'application/pgp-encrypted' MIME_Parts.
- *
- * @return string The HTML output.
- */
- protected function _outputPGPEncrypted()
- {
- global $conf, $prefs;
-
- $mime = &$this->mime_part;
- $mimetype = $mime->getType();
- $text = '';
-
- $this->_initStatus($this->getIcon($mimetype), _("PGP"));
-
- /* Print out message now if PGP is not active. */
- if (empty($conf['utils']['gnupg']) || !$prefs->getValue('use_pgp')) {
- $this->_status[] = _("The message below has been encrypted with PGP, however, PGP support is disabled so the message cannot be decrypted.");
- return $this->_outputStatus();
- }
-
- if ($mimetype == 'multipart/encrypted') {
- /* PGP control information appears in the first MIME subpart. We
- don't currently need to do anything with this information. The
- encrypted data appears in the second MIME subpart. */
- $subpart = $mime->getPart($mime->getRelativeMIMEId(2));
- if (!$subpart) {
- return $text;
- }
- $encrypted_data = $this->_contents->getBodyPart($subpart->getMIMEId());
- } elseif ($mimetype == 'application/pgp-encrypted') {
- $encrypted_data = $mime->getContents();
- } else {
- return $text;
- }
-
- /* Check if this is a literal compressed message. */
- $info = $this->_imp_pgp->pgpPacketInformation($encrypted_data);
- $literal = !empty($info['literal']);
-
- /* Check if this a symmetrically encrypted message. */
- $symmetric = $this->_imp_pgp->encryptedSymmetrically($encrypted_data);
-
- if ($symmetric && !$this->_imp_pgp->getSymmetricPassphrase()) {
- if (isset($_SESSION['imp']['viewmode']) &&
- ($_SESSION['imp']['viewmode'] == 'imp')) {
- // TODO: Fix to work with DIMP
- /* Ask for the correct passphrase if this is encrypted
- * symmetrically. */
- $url = $this->_imp_pgp->getJSOpenWinCode('open_symmetric_passphrase_dialog');
- $this->_status[] = Horde::link('#', _("The message below has been encrypted with PGP. You must enter the passphrase that was used to encrypt this message."), null, null, $url . ' return false;') . _("You must enter the passphrase that was used to encrypt this message.") . '</a>';
- $text .= $this->_outputStatus() .
- Util::bufferOutput(array('IMP', 'addInlineScript'), $url);
- }
- } elseif (!$literal && !$symmetric &&
- !$this->_imp_pgp->getPersonalPrivateKey()) {
- /* Output if there is no personal private key to decrypt with. */
- $this->_status[] = _("The message below has been encrypted with PGP, however, no personal private key exists so the message cannot be decrypted.");
- return $this->_outputStatus();
- } elseif (!$literal && !$symmetric &&
- !$this->_imp_pgp->getPassphrase()) {
- if (isset($_SESSION['imp']['viewmode']) &&
- ($_SESSION['imp']['viewmode'] == 'imp')) {
- // TODO: Fix to work with DIMP
- /* Ask for the private key's passphrase if this is encrypted
- * asymmetrically. */
- $url = $this->_imp_pgp->getJSOpenWinCode('open_passphrase_dialog');
- $this->_status[] = Horde::link('#', _("The message below has been encrypted with PGP. You must enter the passphrase for your PGP private key before it can be decrypted."), null, null, $url . ' return false;') . _("You must enter the passphrase for your PGP private key to view this message.") . '</a>';
- $text .= $this->_outputStatus() .
- Util::bufferOutput(array('IMP', 'addInlineScript'), $url);
- }
- } else {
- /* Decrypt this message. */
- $this->_status[] = $literal ? _("The message below has been compressed with PGP.") : _("The message below has been encrypted with PGP.");
- if ($mimetype == 'multipart/encrypted') {
- if ($subpart->getType() == 'application/octet-stream') {
- $decrypted_data = $this->_imp_pgp->decryptMessage($encrypted_data, $symmetric, !$literal);
- if (is_a($decrypted_data, 'PEAR_Error')) {
- $this->_status[] = _("The message below does not appear to be a valid PGP encrypted message. Error: ") . $decrypted_data->getMessage();
- $text .= $this->_outputStatus();
- } else {
- /* We need to check if this is a signed/encrypted
- message. */
- $mime_message = Horde_Mime_Message::parseMessage($decrypted_data->message);
- if (!$mime_message) {
- require_once 'Horde/Text/Filter.php';
- $text .= $this->_signedOutput($decrypted_data->sig_result);
- $decrypted_message = String::convertCharset($decrypted_data->message, $subpart->getCharset());
- $text .= '<span class="fixed">' . Text_Filter::filter($decrypted_message, 'text2html', array('parselevel' => TEXT_HTML_SYNTAX)) . '</span>';
- } else {
- $mimetype = $mime_message->getType();
- if (($mimetype == 'multipart/signed') ||
- ($mimetype == 'application/pgp-signature')) {
- $mime_message->setInformation('pgp_signenc', true);
- $mime_message->setContents($decrypted_data->message);
- $mime_message->splitContents();
- } else {
- $text .= $this->_signedOutput($decrypted_data->sig_result);
- }
-
- /* We need to stick the output into a
- MIME_Contents object. */
- $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$this->_contents));
- $mc->buildMessage();
- if ($mime_message->getInformation('pgp_signenc')) {
- $text .= $mc->getMessage(true);
- } else {
- $text .= '<table cellspacing="0">' . $mc->getMessage(true) . '</table>';
- }
- }
- }
- } else {
- $this->_status[] = _("The message below does not appear to be in the correct PGP format (according to RFC 2015).");
- $text .= $this->_outputStatus();
- }
- } elseif ($mimetype == 'application/pgp-encrypted') {
- $decrypted_data = $this->_imp_pgp->decryptMessage($encrypted_data, $symmetric, !$literal);
- if (is_a($decrypted_data, 'PEAR_Error')) {
- $decrypted_message = $decrypted_data->getMessage();
- $text .= $this->_outputStatus();
- } else {
- $text .= $this->_signedOutput($decrypted_data->sig_result);
- $decrypted_message = String::convertCharset($decrypted_data->message, $mime->getCharset());
- }
-
- require_once 'Horde/Text/Filter.php';
- $text .= '<span class="fixed">' . Text_Filter::filter($decrypted_message, 'text2html', array('parselevel' => TEXT_HTML_SYNTAX)) . '</span>';
- }
- }
- $this->_imp_pgp->unsetSymmetricPassphrase();
-
- return $text;
- }
-
- /**
- * Generates HTML output for the PGP signature test.
- *
- * @param string $result Result string of the PGP output concerning the
- * signature test.
- *
- * @return string The HTML output.
- */
- protected function _outputPGPSignatureTest($result)
- {
- $text = '';
-
- if (is_a($result, 'PEAR_Error')) {
- $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/error.png', _("Error"));
- $result = $result->getMessage();
- } else {
- $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/success.png', _("Success"));
- /* This message has been verified but there was no output from the
- PGP program. */
- if (empty($result)) {
- $result = _("The message below has been verified.");
- }
- }
-
- require_once 'Horde/Text/Filter.php';
- $this->_status[] = Text_Filter::filter($result, 'text2html', array('parselevel' => TEXT_HTML_NOHTML));
-
- return $this->_outputStatus();
- }
-
- /**
- * Output signed message status.
- *
- * @param string $result The signature result.
- *
- * @return string HTML output.
- */
- protected function _signedOutput($result)
- {
- if (!empty($result)) {
- return $this->_outputPGPSignatureTest($result);
- } else {
- return $this->_outputStatus();
- }
- }
-
- /* Various formatting helper functions */
- protected function _initStatus($src, $alt = '')
- {
- if ($this->_icon === null) {
- $this->_icon = Horde::img($src, $alt, 'height="16" width="16"', '');
- }
- }
-
- protected function _outputStatus($printable = true)
- {
- $output = '';
- if (!empty($this->_status)) {
- $output = $this->formatStatusMsg($this->_status, $this->_icon, $printable);
- }
- $this->_icon = null;
- $this->_status = array();
- return $output;
- }
-}
+++ /dev/null
-<?php
-
-require_once IMP_BASE . '/lib/Crypt/SMIME.php';
-
-/**
- * The IMP_Horde_Mime_Viewer_pkcs7 class allows viewing/decrypting of S/MIME
- * messages.
- * This class implements parts of RFC 2630, RFC 2632, and RFC 2633.
- *
- * This class handles the following MIME types:
- * application/pkcs7-mime
- * application/pkcs7-signature
- * application/x-pkcs7-mime
- * application/x-pkcs7-signature
- *
- * This class may add the following parameters to the URL:
- * 'smime_verify_msg' -- Do verification of S/MIME signed data.
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Mike Cochrane <mike@graftonhall.co.nz>
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime_Viewer
- */
-class IMP_Horde_Mime_Viewer_pkcs7 extends Horde_Mime_Viewer_Driver
-{
- /**
- * IMP_SMIME object.
- *
- * @var IMP_SMIME
- */
- protected $_impSmime;
-
- /**
- * Classwide cache for icons for status messages.
- *
- * @var string
- */
- protected $_icon = null;
-
- /**
- * Pointer to the IMP_Contents item.
- *
- * @var IMP_Contents
- */
- protected $_contents = null;
-
- /**
- * Classwide cache for status messages.
- *
- * @var array
- */
- protected $_status = array();
-
- /**
- * The MIME_Headers object for the message data.
- *
- * @var MIME_Headers
- */
- protected $_headers;
-
- /**
- * Some mailers set S/MIME messages to always be attachments. However,
- * most of the time S/MIME is used to secure the contents of the message,
- * so displaying as an attachment makes no sense. Therefore, force
- * viewing inline (or at least let Horde_Mime_Viewer/IMP_Contents make the
- * determination on whether the data can be viewed inline or not).
- *
- * @var boolean
- */
- protected $_forceinline = true;
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a IMP_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- /* Set the IMP_Contents class variable. */
- $this->_contents = &$params[0];
-
- $msg = '';
-
- if (empty($this->_impSmime)) {
- $this->_impSmime = new IMP_SMIME();
- }
-
- /* Check to see if S/MIME support is available. */
- $openssl_check = $this->_impSmime->checkForOpenSSL();
- if ($GLOBALS['prefs']->getValue('use_smime') &&
- !is_a($openssl_check, 'PEAR_Error')) {
- /* We need to insert JavaScript code now if S/MIME support is
- active. */
- $msg = Util::bufferOutput(array('Horde', 'addScriptFile'), 'prototype.js', 'horde', true);
- $msg .= Util::bufferOutput(array('Horde', 'addScriptFile'), 'popup.js', 'imp', true);
- }
-
- /* Get the type of message now. */
- $type = $this->_getSMIMEType();
- switch ($type) {
- case 'signed':
- $msg .= $this->_outputSMIMESigned();
- break;
-
- case 'encrypted':
- $msg .= $this->_outputSMIMEEncrypted();
- break;
- }
-
- return $msg;
- }
-
- /**
- * Generates HTML output for the S/MIME key in
- * 'application/pkcs7-signature' MIME_Parts.
- *
- * @return string The HTML output.
- */
- protected function _outputSMIMEKey()
- {
- if (!$GLOBALS['prefs']->getValue('use_smime')) {
- return _("S/MIME support is not enabled.");
- } else {
- $mime = &$this->mime_part;
- $signenc = $mime->getInformation('smime_signenc');
- $raw_text = $this->_getRawSMIMEText();
- if ($signenc && $mime->getInformation('smime_from')) {
- $smime_from = $mime->getInformation('smime_from');
- $raw_text = "From: $smime_from\n" . $raw_text;
- }
- $sig_result = $this->_impSmime->verifySignature($raw_text);
- return $this->_impSmime->certToHTML($sig_result->cert);
- }
- }
-
- /**
- * Generates HTML output for 'multipart/signed',
- * 'application/pkcs7-signature' and
- * 'application/x-pkcs7-signature' MIME_Parts.
- *
- * @return string The HTML output.
- */
- protected function _outputSMIMESigned()
- {
- if (Util::getFormData('viewkey')) {
- return $this->_outputSMIMEKey();
- }
-
- $cert = $text = '';
- $mime = &$this->mime_part;
- $mimetype = $mime->getType();
- $active = $GLOBALS['prefs']->getValue('use_smime');
-
- $signenc = $mime->getInformation('smime_signenc');
- if ($signenc) {
- $this->_status[] = _("This message has been encrypted via S/MIME.");
- }
-
- $this->_initStatus($this->getIcon($mimetype), _("S/MIME"));
- $this->_status[] = _("This message has been digitally signed via S/MIME.");
-
- if (!$active) {
- $this->_status[] = _("S/MIME support is not enabled so the digital signature is unable to be verified.");
- }
-
- /* Store S/MIME results in $sig_result. */
- $sig_result = null;
- if ($mimetype == 'multipart/signed') {
- if (!$signenc) {
- if (($mimeID = $mime->getMIMEId())) {
- $mime->setContents($this->_contents->getBodyPart($mimeID));
- } else {
- $mime->setContents($this->_contents->getBody());
- }
- $mime->splitContents();
- }
-
- /* Data that is signed appears in the first MIME subpart. */
- $signed_part = $mime->getPart($mime->getRelativeMIMEId(1));
- $signed_data = rtrim($signed_part->getCanonicalContents(), "\r");
- $mime_message = Horde_Mime_Message::parseMessage($signed_data);
-
- /* The S/MIME signature appears in the second MIME subpart. */
- $subpart = $mime->getPart($mime->getRelativeMIMEId(2));
- if (!$subpart ||
- !in_array($subpart->getType(), array('application/pkcs7-signature', 'application/x-pkcs7-signature'))) {
- $this->_status[] = _("This message does not appear to be in the correct S/MIME format.");
- }
- } elseif (!$active) {
- $this->_status[] = _("S/MIME support is not enabled so the contents of this signed message cannot be displayed.");
- }
-
- if ($active) {
- $raw_text = $this->_getRawSMIMEText();
- if ($signenc && $mime->getInformation('smime_from')) {
- $smime_from = $mime->getInformation('smime_from');
- $raw_text = "From: $smime_from\n" . $raw_text;
- }
-
- if ($GLOBALS['prefs']->getValue('smime_verify') ||
- Util::getFormData('smime_verify_msg')) {
- $sig_result = $this->_impSmime->verifySignature($raw_text);
- } elseif (isset($_SESSION['imp']['viewmode']) &&
- ($_SESSION['imp']['viewmode'] == 'imp')) {
- // TODO: Fix to work with DIMP
- $this->_status[] = Horde::link(Util::addParameter(Horde::selfUrl(true), 'smime_verify_msg', 1)) . _("Click HERE to verify the message.") . '</a>';
- }
-
- if (!isset($subpart)) {
- $msg_data = $this->_impSmime->extractSignedContents($raw_text);
- if (is_a($msg_data, 'PEAR_Error')) {
- $this->_status[] = $msg_data->getMessage();
- $mime_message = $mime;
- } else {
- $mime_message = Horde_Mime_Message::parseMessage($msg_data);
- }
- }
-
- $text = $this->_outputStatus();
- if ($sig_result !== null) {
- $text .= $this->_outputSMIMESignatureTest($sig_result->result, $sig_result->email);
- if (!empty($sig_result->cert)) {
- $cert_details = $this->_impSmime->parseCert($sig_result->cert);
- if (isset($cert_details['certificate']['subject']['CommonName'])) {
- $subject = $cert_details['certificate']['subject']['CommonName'];
- } elseif (isset($cert_details['certificate']['subject']['Email'])) {
- $subject = $cert_details['certificate']['subject']['Email'];
- } elseif (isset($sig_result->email)) {
- $subject = $sig_result->email;
- } elseif (isset($smime_from)) {
- $subject = $smime_from;
- } elseif (($from = $this->_headers->getValue('from'))) {
- $subject = $from;
- } else {
- $subject = null;
- }
- if (isset($subpart) &&
- !empty($subject) &&
- $GLOBALS['registry']->hasMethod('contacts/addField') &&
- $GLOBALS['prefs']->getValue('add_source')) {
- $this->_status[] = sprintf(_("The S/MIME certificate of %s: "), @htmlspecialchars($subject, ENT_COMPAT, NLS::getCharset())) .
- $this->_contents->linkViewJS($subpart, 'view_attach', _("View"), '', null, array('viewkey' => 1)) . '/' .
- Horde::link('#', '', null, null, $this->_impSmime->savePublicKeyURL($sig_result->cert) . ' return false;') . _("Save in your Address Book") . '</a>';
- $text .= $this->_outputStatus();
- }
- }
- }
- }
-
- if (isset($mime_message)) {
- /* We need to stick the output into a IMP_Contents object. */
- $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$this->_contents));
- $mc->buildMessage();
-
- $text .= '<table cellpadding="0" cellspacing="0">' . $mc->getMessage(true) . '</table>';
- } else {
- $text = $this->_outputStatus();
- }
-
- return $text;
- }
-
- /**
- * Generates HTML output for 'multipart/encrypted',
- * 'application/pkcs7-mime' and
- * 'application/x-pkcs7-mime' MIME_Parts.
- *
- * @return string The HTML output.
- */
- protected function _outputSMIMEEncrypted()
- {
- $active = $GLOBALS['prefs']->getValue('use_smime');
- $mime = &$this->mime_part;
- $mimetype = $mime->getType();
- $msg = '';
-
- $this->_initStatus($this->getIcon($mime->getType()), _("S/MIME"));
- $this->_status[] = _("This message has been encrypted via S/MIME.");
-
- if (!$active) {
- $this->_status[] = _("S/MIME support is not currently enabled so the message is unable to be decrypted.");
- return $this->_outputStatus();
- }
-
- if (!$this->_impSmime->getPersonalPrivateKey()) {
- $this->_status[] = _("No personal private key exists so the message is unable to be decrypted.");
- return $this->_outputStatus();
- }
-
- /* Make sure we have a passphrase. */
- $passphrase = $this->_impSmime->getPassphrase();
- if ($passphrase === false) {
- if (isset($_SESSION['imp']['viewmode']) &&
- ($_SESSION['imp']['viewmode'] == 'imp')) {
- // TODO: Fix to work with DIMP
- $url = $this->_impSmime->getJSOpenWinCode('open_passphrase_dialog');
- $this->_status[] = Horde::link('#', _("You must enter the passphrase for your S/MIME private key to view this message"), null, null, $url . ' return false;') . '<em>' . _("You must enter the passphrase for your S/MIME private key to view this message") . '</em></a>.';
- $msg .= $this->_outputStatus() .
- '<script type="text/javascript">' . $url . ';</script>';
- }
- return $msg;
- }
-
- $raw_text = $this->_getRawSMIMEText();
- $decrypted_data = $this->_impSmime->decryptMessage($raw_text);
-
- if (is_a($decrypted_data, 'PEAR_Error')) {
- $this->_status[] = $decrypted_data->getMessage();
- return $this->_outputStatus();
- }
-
- /* We need to check if this is a signed/encrypted message. */
- $mime_message = Horde_Mime_Message::parseMessage($decrypted_data);
- if ($mime_message) {
- /* Check for signed and encoded data. */
- if (in_array($mime_message->getType(), array('multipart/signed', 'application/pkcs7-mime', 'application/x-pkcs7-mime'))) {
- $mime_message->setContents($decrypted_data);
- $mime_message->splitContents();
- $mime_message->setInformation('smime_signenc', true);
- if (($from = $this->_headers->getValue('from'))) {
- $mime_message->setInformation('smime_from', $from);
- }
- } else {
- $msg .= $this->_outputStatus();
- }
-
- /* We need to stick the output into a IMP_Contents object. */
- $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$this->_contents));
- $mc->buildMessage();
- $msg .= '<table cellpadding="0" cellspacing="0">' . $mc->getMessage(true) . '</table>';
- } else {
- require_once 'Horde/Text/Filter.php';
- $msg .= $this->_outputStatus() .
- '<span class="fixed">' . Text_Filter::filter($decrypted_data, 'text2html', array('parselevel' => TEXT_HTML_SYNTAX)) . '</span>';
- }
-
- return $msg;
- }
-
- /**
- * Return text/html as the content-type.
- *
- * @return string "text/html" constant.
- */
- public function getType()
- {
- return 'text/html; charset=' . NLS::getCharset();
- }
-
- /**
- * Get the headers of the S/MIME message.
- */
- protected function _getRawSMIMEText()
- {
- $mime = &$this->mime_part;
-
- $mime->setContents($this->_contents->getBody());
- if (is_a($this->_contents, 'IMP_Contents') &&
- (($mime->getMIMEId() == 0) ||
- ($mime->splitContents() == false))) {
- $this->_headers = $this->_contents->getHeaderOb();
- return $this->_contents->fullMessageText();
- } else {
- $header_text = $mime->getCanonicalContents();
- $header_text = substr($header_text, 0, strpos($header_text, "\r\n\r\n"));
- $this->_headers = MIME_Headers::parseHeaders($header_text);
-
- $mime_headers = new MIME_Headers();
- foreach (array('Content-Type', 'From', 'To') as $val) {
- $tmp = $this->_headers->getValue($val);
- if (!empty($tmp)) {
- $mime_headers->addHeader($val, $tmp);
- }
- }
-
- return $mime_headers->toString() . $mime->toCanonicalString();
- }
- }
-
- /* Various formatting helper functions. */
- protected function _initStatus($src, $alt = '')
- {
- if ($this->_icon === null) {
- $this->_icon = Horde::img($src, $alt, 'height="16" width="16"', '');
- }
- }
-
- protected function _outputStatus()
- {
- $output = '';
- if (!empty($this->_status)) {
- $output = $this->formatStatusMsg($this->_status, $this->_icon);
- }
- $this->_icon = null;
- $this->_status = array();
- return $output;
- }
-
- /**
- * Generates HTML output for the S/MIME signature test.
- *
- * @param string $result Result string of the S/MIME output concerning
- * the signature test.
- * @param string $email The email of the sender.
- *
- * @return string The HTML output.
- */
- protected function _outputSMIMESignatureTest($result, $email)
- {
- $text = '';
-
- if (is_a($result, 'PEAR_Error')) {
- if ($result->getCode() == 'horde.warning') {
- $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/warning.png', _("Warning"));
- } else {
- $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/error.png', _("Error"));
- }
- $result = $result->getMessage();
- } else {
- $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/success.png', _("Success"));
- /* This message has been verified but there was no output
- from the PGP program. */
- if (empty($result) || ($result === true)) {
- $email = (is_array($email)) ? implode(', ', $email): $email;
- $result = sprintf(_("The message has been verified. Sender: %s."), htmlspecialchars($email));
- }
- }
-
- require_once 'Horde/Text/Filter.php';
-
- $this->_status[] = Text_Filter::filter($result, 'text2html', array('parselevel' => TEXT_HTML_NOHTML));
-
- return $this->_outputStatus();
- }
-
- /**
- * Render out attachment information.
- *
- * @param array $params An array with a reference to a IMP_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function renderAttachmentInfo($params)
- {
- $this->_contents = &$params[0];
-
- $type = $this->_getSMIMEType();
- switch ($type) {
- case 'signed':
- $this->_status[] = _("This message contains an attachment that has been digitally signed via S/MIME.");
- break;
-
- case 'encrypted':
- $this->_status[] = _("This message contains an attachment that has been encrypted via S/MIME.");
- break;
- }
-
- $this->_status[] = sprintf(_("Click %s to view the attachment in a separate window."), $this->_contents->linkViewJS($this->mime_part, 'view_attach', _("HERE"), _("View attachment in a separate window")));
- $this->_initStatus($this->getIcon($this->mime_part->getType()), _("S/MIME"));
- return $this->_outputStatus();
- }
-
- /**
- * Deterimne the S/MIME type of the message.
- *
- * @return string Either 'encrypted' or 'signed'.
- */
- protected function _getSMIMEType()
- {
- $type = $this->mime_part->getType();
- if (in_array($type, array('application/pkcs7-mime', 'application/x-pkcs7-mime'))) {
- $smime_type = $this->mime_part->getContentTypeParameter('smime-type');
- if ($smime_type == 'signed-data') {
- return 'signed';
- } elseif (!$smime_type || ($smime_type == 'enveloped-data')) {
- return 'encrypted';
- }
- }
-
- switch ($type) {
- case 'multipart/signed':
- case 'application/pkcs7-signature':
- case 'application/x-pkcs7-signature':
- return 'signed';
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_plain class renders out text/plain MIME parts
- * with URLs made into hyperlinks.
- *
- * Copyright 1999-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Anil Madhavapeddy <anil@recoil.org>
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime_Viewer
- */
-class IMP_Horde_Mime_Viewer_plain extends Horde_Mime_Viewer_plain
-{
- /**
- * TODO
- */
- protected function _renderInline()
- {
- global $conf, $prefs;
-
- // Trim extra whitespace in the text.
- $text = rtrim($this->_mimepart->getContents());
- if ($text == '') {
- return array(
- 'data' => '',
- 'status' => array()
- );
- }
-
- // If requested, scan the message for PGP data.
- if (!empty($conf['utils']['gnupg']) &&
- $prefs->getValue('pgp_scan_body') &&
- preg_match('/-----BEGIN PGP ([^-]+)-----/', $text)) {
- require_once IMP_BASE . '/lib/Crypt/PGP.php';
- $imp_pgp = new IMP_PGP();
- if (($out = $imp_pgp->parseMessageOutput($this->_mimepart, $this->_params['contents']))) {
- return array(
- 'data' => $out,
- 'status' => array()
- );
- }
- }
-
- // Check for 'flowed' text data.
- if ($this->_mimepart->getContentTypeParameter('format') == 'flowed') {
- $text = $this->_formatFlowed($text, $this->_mimepart->getContentTypeParameter('delsp'));
- } else {
- /* A "From" located at the beginning of a line in the body text
- * will be escaped with a '>' by the IMAP server. Remove this
- * escape character or else the line will display as being
- * quoted. Flowed conversion would have already taken care of this
- * for us. */
- $text = preg_replace('/(\n+)> ?From(\s+)/', "$1From$2", $text);
- }
-
- // Build filter stack. Starts with HTML markup and tab expansion.
- require_once 'Horde/Text/Filter.php';
- $filters = array(
- 'text2html' => array(
- 'parselevel' => TEXT_HTML_MICRO,
- 'charset' => $this->_mimepart->getCharset()
- ),
- 'tabs2spaces' => array()
- );
-
- // Highlight quoted parts of an email.
- if ($prefs->getValue('highlight_text')) {
- $show = $prefs->getValue('show_quoteblocks');
- $hideBlocks = ($show == 'hidden') ||
- (($show == 'thread') && (basename(Horde::selfUrl()) == 'thread.php'));
- if (!$hideBlocks && in_array($show, array('list', 'listthread'))) {
- $header = $this->_params['contents']->getHeaderOb();
- $imp_ui = new IMP_UI_Message();
- $list_info = $imp_ui->getListInformation($header);
- $hideBlocks = $list_info['exists'];
- }
- $filters['highlightquotes'] = array('hideBlocks' => $hideBlocks);
- }
-
- // Highlight simple markup of an email.
- if ($prefs->getValue('highlight_simple_markup')) {
- $filters['simplemarkup'] = array();
- }
-
- // Dim signatures.
- if ($prefs->getValue('dim_signature')) {
- $filters['dimsignature'] = array();
- }
-
- // Filter bad language.
- if ($prefs->getValue('filtering')) {
- $filters['words'] = array(
- 'words_file' => $conf['msgsettings']['filtering']['words'],
- 'replacement' => $conf['msgsettings']['filtering']['replacement']
- );
- }
-
- // Run filters.
- $text = Text_Filter::filter($text, array_keys($filters), array_values($filters));
-
- // Wordwrap.
- $text = str_replace(array(' ', "\n "), array(' ', "\n "), $text);
- if (!strncmp($text, ' ', 1)) {
- $text = ' ' . substr($text, 1);
- }
-
- return array(
- 'data' => '<div class="fixed leftAlign">' . "\n" . $text . '</div>',
- 'status' => array()
- );
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_related class handles multipart/related messages
- * as defined by RFC 2387.
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_related extends Horde_Mime_Viewer_Driver
-{
- /**
- * The character set of the rendered HTML part.
- *
- * @var string
- */
- protected $_charset = null;
-
- /**
- * The mime type of the message part that has been chosen to be displayed.
- *
- * @var string
- */
- protected $_viewerType = 'text/html';
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- /* Look at the 'start' parameter to determine which part to start
- with. If no 'start' parameter, use the first part.
- RFC 2387 [3.1] */
- if ($this->mime_part->getContentTypeParameter('start') &&
- ($key = array_search($this->mime_part->getContentTypeParameter('start'), $this->mime_part->getCIDList()))) {
- if (($pos = strrpos($key, '.'))) {
- $id = substr($key, $pos + 1);
- } else {
- $id = $key;
- }
- } else {
- $id = 1;
- }
- $start = $this->mime_part->getPart($this->mime_part->getRelativeMimeID($id));
-
- /* Only display if the start part (normally text/html) can be displayed
- inline -OR- we are viewing this part as an attachment. */
- if ($contents->canDisplayInline($start) ||
- $this->viewAsAttachment()) {
- $text = $contents->renderMIMEPart($start);
- $this->_viewerType = $contents->getMIMEViewerType($start);
- $this->_charset = $start->getCharset();
- } else {
- $text = '';
- }
-
- return $text;
- }
-
- /**
- * Render out attachment information.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function renderAttachmentInfo($params)
- {
- $contents = &$params[0];
-
- $msg = sprintf(_("Click %s to view this multipart/related part in a separate window."), $contents->linkViewJS($this->mime_part, 'view_attach', _("HERE"), _("View content in a separate window")));
- return $this->formatStatusMsg($msg, Horde::img('mime/html.png', _("HTML")), false);
- }
-
- /**
- * Return the content-type.
- *
- * @return string The content-type of the message.
- */
- public function getType()
- {
- return $this->_viewerType . '; charset=' . $this->getCharset();
- }
-
- /**
- * Returns the character set used for the Viewer.
- *
- * @return string The character set used by this Viewer.
- */
- public function getCharset()
- {
- return ($this->_charset === null) ? NLS::getCharset() : $this->_charset;
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_rfc822 class renders out messages from
- * message/rfc822 content types.
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_rfc822 extends Horde_Mime_Viewer_rfc822
-{
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- /* Get the entire body part of the message/rfc822 contents. */
- if (!$this->mime_part->getInformation('imp_contents_set') &&
- is_a($contents, 'IMP_Contents') &&
- $this->mime_part->getMIMEId()) {
- $this->mime_part = &$contents->getDecodedMIMEPart($this->mime_part->getMIMEId(), true);
- }
-
- return parent::render();
- }
-
- /**
- * Render out attachment information.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function renderAttachmentInfo($params)
- {
- $contents = &$params[0];
-
- if (is_a($contents, 'IMP_Contents') &&
- !$this->mime_part->getContents()) {
- $id = $this->mime_part->getMIMEId();
- $hdr_id = substr($id, -2);
- if ($hdr_id != '.0') {
- $id .= '.0';
- }
- $this->mime_part = &$contents->getDecodedMIMEPart($id);
- }
-
- return parent::renderAttachmentInfo();
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_smil renders SMIL documents to very basic HTML.
- *
- * Copyright 2006-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Jan Schneider <jan@horde.org>
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_smil extends Horde_Mime_Viewer_smil
-{
- /**
- * The MIME_Contents object, needed for the _callback() function.
- *
- * @var MIME_Contents
- */
- protected $_contents;
-
- /**
- * The list of related parts to the current part.
- *
- * @var array
- */
- protected $_related = null;
-
- /**
- * Renders out the contents.
- *
- * @param array $params Any parameters the Viewer may need.
- *
- * @return string The rendered contents.
- */
- public function render($params)
- {
- $this->_contents = &$params[0];
- return parent::render($params);
- }
-
- /**
- * User-defined function callback for start elements.
- *
- * @param object $parser Handle to the parser instance.
- * @param string $name The name of this XML element.
- * @param array $attrs List of this element's attributes.
- */
- protected function _startElement($parser, $name, $attrs)
- {
- switch ($name) {
- case 'IMG':
- if (isset($attrs['SRC'])) {
- $rp = $this->_getRelatedLink($attrs['SRC']);
- if ($rp !== false) {
- $this->_content .= '<img src="' . $this->_contents->urlView($rp, 'view_attach') . '" alt="" /><br />';
- }
- }
- break;
-
- case 'TEXT':
- if (isset($attrs['SRC'])) {
- $rp = $this->_getRelatedLink($attrs['SRC']);
- if ($rp !== false) {
- $this->_content .= htmlspecialchars($rp->getContents()) . '<br />';
- }
- }
- break;
- }
- }
-
- /**
- * Get related parts.
- *
- * @param string $cid The CID to search for.
- *
- * @return mixed Either the related MIME_Part or false.
- */
- protected function _getRelatedLink($cid)
- {
- if ($this->_related === null) {
- $this->_related = false;
- $related = $this->mime_part->getInformation('related_part');
- if ($related !== false) {
- $relatedPart = $this->_contents->getMIMEPart($related);
- $this->_related = $relatedPart->getCIDList();
- }
- }
-
- if ($this->_related) {
- $key = array_search('<' . $cid . '>', $this->_related);
- if ($key !== false) {
- $cid_part = $this->_contents->getDecodedMIMEPart($key);
- return $cid_part;
- }
- }
-
- return false;
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_status class handles multipart/report messages
- * that refer to mail system administrative messages (RFC 3464).
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_status extends Horde_Mime_Viewer_Driver
-{
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- /* If this is a straight message/delivery-status part, just output
- the text. */
- if ($this->mime_part->getType() == 'message/delivery-status') {
- $part = new Horde_Mime_Part('text/plain');
- $part->setContents($this->mime_part->getContents());
- return '<pre>' . $contents->renderMIMEPart($part) . '</pre>';
- }
-
- global $registry;
-
- /* RFC 3464 [2]: There are three parts to a delivery status
- multipart/report message:
- (1) Human readable message
- (2) Machine parsable body part (message/delivery-status)
- (3) Returned message (optional)
-
- Information on the message status is found in the 'Action' field
- located in part #2 (RFC 2464 [2.3.3]). It can be either 'failed',
- 'delayed', 'delivered', 'relayed', or 'expanded'. */
- $action = null;
- $part2 = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(2));
- if (empty($part2)) {
- return $this->_errorMsg($contents);
- }
-
- foreach (explode("\n", $part2->getContents()) as $line) {
- if (strstr($line, 'Action:') !== false) {
- $pos = strpos($line, ':') + 1;
- $action = strtolower(trim(substr($line, $pos)));
- break;
- }
- }
- if (strpos($action, ' ') !== false) {
- $action = substr($action, 0, strpos($action, ' '));
- }
-
- /* Get the correct text strings for the action type. */
- switch ($action) {
- case 'failed':
- case 'delayed':
- $graphic = 'alerts/error.png';
- $alt = _("Error");
- $msg = array(
- _("ERROR: Your message could not be delivered."),
- _("The mail server generated the following error message:")
- );
- $detail_msg = _("Additional message error details can be viewed %s.");
- $detail_msg_status = _("Additional message error details");
- $msg_link = _("The text of the returned message can be viewed %s.");
- $msg_link_status = _("The text of the returned message");
- break;
-
- case 'delivered':
- case 'expanded':
- case 'relayed':
- $graphic = 'alerts/success.png';
- $alt = _("Success");
- $msg = array(
- _("Your message was successfully delivered."),
- _("The mail server generated the following message:")
- );
- $detail_msg = _("Additional message details can be viewed %s.");
- $detail_msg_status = _("Additional message details");
- $msg_link = _("The text of the message can be viewed %s.");
- $msg_link_status = _("The text of the message");
- break;
-
- default:
- $graphic = '';
- $alt = '';
- $msg = '';
- $detail_msg = '';
- $detail_msg_status = '';
- $msg_link = '';
- $msg_link_status = '';
- }
-
- /* Print the human readable message. */
- $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(1));
- if (empty($part)) {
- return $this->_errorMsg($contents);
- }
-
- $statusimg = Horde::img($graphic, $alt, 'height="16" width="16"', $registry->getImageDir('horde'));
- $text = $this->formatStatusMsg($msg, $statusimg);
- $text .= '<blockquote>' . $contents->renderMIMEPart($part) . '</blockquote>' . "\n";
-
- /* Display a link to more detailed error message. */
- $detailed_msg = array(
- sprintf($detail_msg, $contents->linkViewJS($part2, 'view_attach', _("HERE"), $detail_msg_status))
- );
-
- /* Display a link to the returned message. Try to download the
- text of the message/rfc822 part first, if it exists.
- TODO: Retrieving by part ID 3.0 is deprecated. Remove this once
- Horde 4.0 is released. */
- if (($part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(3))) ||
- ($part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId('3.0')))) {
- $detailed_msg[] = sprintf($msg_link, $contents->linkViewJS($part, 'view_attach', _("HERE"), $msg_link_status, null, array('ctype' => 'message/rfc822')));
- }
-
- $infoimg = Horde::img('info_icon.png', _("Info"), 'height="16" width="16"', $registry->getImageDir('horde'));
- $text .= $this->formatStatusMsg($detailed_msg, $infoimg, false);
-
- return $text;
- }
-
-
- /**
- * Return the content-type.
- *
- * @return string The content-type of the message.
- */
- public function getType()
- {
- return 'text/html; charset=' . NLS::getCharset();
- }
-
- /**
- * Returns an error string for a malformed RFC 3464 message.
- *
- * @param MIME_Contents &$contents The MIME_Contents object for this
- * message.
- *
- * @return string The error message string.
- */
- protected function _errorMsg(&$contents)
- {
- $err_msg = array(
- _("This message contains mail delivery status information, but the format of this message is unknown."),
- _("Below is the raw text of the status information message.")
- );
- $img = Horde::img('alerts/error.png', _("Error"), 'height="16" width="16"', $GLOBALS['registry']->getImageDir('horde'));
-
- $text = $this->formatStatusMsg($err_msg, $img);
-
- /* There is currently no BC way to obtain all parts from a message
- * and display the summary of each part. So instead, display the
- * entire raw contents of the message. See Bug 3757. */
- $text .= '<pre>';
- if (is_a($contents, 'IMP_Contents')) {
- $contents->rebuildMessage();
- $message = $contents->getMIMEMessage();
- $text .= $contents->toString($message, true);
- } else {
- $text .= htmlspecialchars($this->mime_part->getContents());
- }
-
- return $text . '</pre>';
- }
-
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_tnef class allows MS-TNEF attachments to be
- * displayed.
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_tnef extends Horde_Mime_Viewer_tnef
-{
- /**
- * The contentType of the attachment.
- *
- * @var string
- */
- protected $_contentType = 'application/octet-stream';
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string Either the list of tnef files or the data of an
- * individual tnef file.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- $text = '';
-
- /* Get the data from the attachment. */
- $tnefData = $this->_getSubparts();
-
- /* Display the requested file. Its position in the $tnefData
- array can be found in 'tnef_attachment'. */
- if (Util::getFormData('tnef_attachment')) {
- $tnefKey = Util::getFormData('tnef_attachment') - 1;
- /* Verify that the requested file exists. */
- if (isset($tnefData[$tnefKey])) {
- $text = $tnefData[$tnefKey]['stream'];
- if (empty($text)) {
- $text = $this->formatStatusMsg(_("Could not extract the requested file from the MS-TNEF attachment."));
- } else {
- $this->mime_part->setName($tnefData[$tnefKey]['name']);
- $this->mime_part->setType($tnefData[$tnefKey]['type'] . '/' . $tnefData[$tnefKey]['subtype']);
- }
- } else {
- $text = $this->formatStatusMsg(_("The requested file does not exist in the MS-TNEF attachment."));
- }
- } else {
- $text = $this->renderAttachmentInfo(array($params[0]));
- }
-
- return $text;
- }
-
- /**
- * Render out TNEF attachment information.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string The rendered text in HTML.
- */
- public function renderAttachmentInfo($params)
- {
- $contents = &$params[0];
-
- $text = '';
-
- /* Make sure the contents are in the MIME_Part object. */
- if (!$this->mime_part->getContents()) {
- $this->mime_part->setContents($contents->getBodyPart($this->mime_part->getMIMEId()));
- }
-
- /* Get the data from the attachment. */
- $tnefData = $this->_getSubparts();
-
- if (!count($tnefData)) {
- $text = $this->formatStatusMsg(_("No attachments found."));
- } else {
- $text = $this->formatStatusMsg(_("The following files were attached to this part:")) . '<br />';
- foreach ($tnefData as $key => $data) {
- $temp_part = $this->mime_part;
- $temp_part->setName($data['name']);
- $temp_part->setDescription($data['name']);
-
- /* Short-circuit MIME-type guessing for winmail.dat parts;
- we're showing enough entries for them already. */
- $type = $data['type'] . '/' . $data['subtype'];
- if (($type == 'application/octet-stream') ||
- ($type == 'application/base64')) {
- $type = Horde_Mime_Magic::filenameToMIME($data['name']);
- }
- $temp_part->setType($type);
-
- $link = $contents->linkView($temp_part, 'view_attach', htmlspecialchars($data['name']), array('jstext' => sprintf(_("View %s"), $data['name']), 'viewparams' => array('tnef_attachment' => ($key + 1))));
- $text .= _("Attached File:") . ' ' . $link . ' (' . $data['type'] . '/' . $data['subtype'] . ")<br />\n";
- }
- }
-
- return $text;
- }
-
- /**
- * List any embedded attachments in the TNEF part.
- *
- * @return array An array of any embedded attachments.
- */
- protected function _getSubparts()
- {
- $tnef = &Horde_Compress::singleton('tnef');
- return $tnef->decompress($this->mime_part->transferDecode());
- }
-
- /**
- * Return the content-type.
- *
- * @return string The content-type of the output.
- */
- public function getType()
- {
- if (Util::getFormData('tnef_attachment')) {
- return $this->_contentType;
- } else {
- return 'text/html; charset=' . NLS::getCharset();
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_zip class renders out the contents of ZIP files
- * in HTML format and allows downloading of extractable files.
- *
- * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Mike Cochrane <mike@graftonhall.co.nz>
- * @author Michael Slusarz <slusarz@horde.org>
- * @package Horde_Mime
- */
-class IMP_Horde_Mime_Viewer_zip extends Horde_Mime_Viewer_zip
-{
- /**
- * The IMP_Contents object, needed for the _callback() function.
- *
- * @var IMP_Contents
- */
- protected $_contents;
-
- /**
- * Render out the currently set contents.
- *
- * @param array $params An array with a reference to a MIME_Contents
- * object.
- *
- * @return string Either the list of zip files or the data of an
- * individual zip file.
- */
- public function render($params)
- {
- $contents = &$params[0];
-
- $data = $this->mime_part->getContents();
- $text = '';
-
- /* Send the requested file. Its position in the zip archive is located
- * in 'zip_attachment'. */
- if (Util::getFormData('zip_attachment')) {
- $zip = &Horde_Compress::singleton('zip');
- $fileKey = Util::getFormData('zip_attachment') - 1;
- $zipInfo = $zip->decompress(
- $data, array('action' => HORDE_COMPRESS_ZIP_LIST));
- /* Verify that the requested file exists. */
- if (isset($zipInfo[$fileKey])) {
- $text = $zip->decompress(
- $data,
- array('action' => HORDE_COMPRESS_ZIP_DATA,
- 'info' => &$zipInfo,
- 'key' => $fileKey));
- if (empty($text)) {
- $text = '<pre>' . _("Could not extract the requested file from the Zip archive.") . '</pre>';
- } else {
- $this->mime_part->setType('application/octet-stream');
- $this->mime_part->setName(basename($zipInfo[$fileKey]['name']));
- }
- } else {
- $text = '<pre>' . _("The requested file does not exist in the Zip attachment.") . '</pre>';
- }
- } else {
- $this->_contents = $contents;
- $text = parent::_render($data, array($this, '_callback'));
- }
-
- return $text;
- }
-
- /**
- * The function to use as a callback to parent::_render().
- *
- * @param integer $key The position of the file in the zip archive.
- * @param array $val The information array for the archived file.
- *
- * @return string The content-type of the output.
- */
- protected function _callback($key, $val)
- {
- $name = preg_replace('/( )+$/', '', $val['name']);
- if (!empty($val['size']) && (strstr($val['attr'], 'D') === false) &&
- ((($val['method'] == 0x8) && Util::extensionExists('zlib')) ||
- ($val['method'] == 0x0))) {
- $old_name = $this->mime_part->getName();
- $this->mime_part->setName(basename($name));
- $val['name'] = str_replace(
- $name,
- $this->_contents->linkView(
- $this->mime_part, 'download_render', $name,
- array('jstext' => sprintf(_("View %s"),
- str_replace(' ', ' ', $name)),
- 'class' => 'fixed',
- 'viewparams' => array(
- 'ctype' => 'application/zip',
- 'zip_attachment' => (urlencode($key) + 1)))),
- $val['name']);
- $this->mime_part->setName($old_name);
- }
-
- return $val;
- }
-}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_alternative class renders out messages from
+ * multipart/alternative content types (RFC 2046 [5.1.4]).
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_alternative extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * The content-type of the preferred part.
+ * Default: application/octet-stream
+ *
+ * @var string
+ */
+ protected $_contentType = 'application/octet-stream';
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ $display_id = null;
+ $summaryList = array();
+ $text = '';
+
+ /* Look for a displayable part.
+ * RFC 2046: We show the LAST choice that can be displayed inline. */
+ $partList = $this->mime_part->getParts();
+ foreach ($partList as $part) {
+ if ($contents->canDisplayInline($part)) {
+ $text = $contents->renderMIMEPart($part);
+ $this->_contentType = $part->getType();
+ $display_id = $part->getMIMEId();
+ }
+ }
+
+ /* Show links to alternative parts. */
+ if (($text === null) || (count($partList) > 1)) {
+ if ($text === null) {
+ $text = '<em>' . _("There are no alternative parts that can be displayed.") . '</em>';
+ }
+
+ /* Generate the list of summaries to use. */
+ foreach ($partList as $part) {
+ $id = $part->getMIMEId();
+ if ($id && $id != $display_id) {
+ $summary = $contents->partSummary($part);
+ /* We don't want to show the MIME ID for alt parts. */
+ if (!empty($summary)) {
+ array_splice($summary, 1, 1);
+ $summaryList[] = $summary;
+ }
+ }
+ }
+
+ /* Make sure there is at least one summary before showing the
+ * alternative parts. */
+ $alternative_display = $GLOBALS['prefs']->getValue('alternative_display');
+ if (!empty($summaryList) &&
+ !$this->viewAsAttachment() &&
+ $alternative_display != 'none') {
+ $status_array = array();
+ $status = _("Alternative parts for this section:");
+ if ($contents->showSummaryLinks()) {
+ require_once 'Horde/Help.php';
+ $status .= ' ' . Help::link('imp', 'alternative-msg');
+ }
+ $status_array[] = $status;
+ $status = '<table border="0" cellspacing="1" cellpadding="1">';
+ foreach ($summaryList as $summary) {
+ $status .= '<tr valign="middle">';
+ foreach ($summary as $val) {
+ if (!empty($val)) {
+ $status .= "<td>$val </td>\n";
+ }
+ }
+ $status .= "</tr>\n";
+ }
+ $status .= '</table>';
+ $status_array[] = $status;
+ $status_msg = $this->formatStatusMsg($status_array, Horde::img('mime/binary.png', _("Multipart/alternative"), null, $GLOBALS['registry']->getImageDir('horde')), false);
+ switch ($alternative_display) {
+ case 'above':
+ $text = $status_msg . $text;
+ break;
+
+ case 'below':
+ $text .= $status_msg;
+ break;
+ }
+ }
+ }
+
+ /* Remove attachment information for the displayed part if we
+ * can. */
+ if (is_callable(array($contents, 'removeAtcEntry'))) {
+ $contents->removeAtcEntry($this->mime_part->getMIMEId());
+ }
+
+ return $text;
+ }
+
+ /**
+ * Return the content-type.
+ *
+ * @return string The content-type of the message.
+ * Returns 'application/octet-stream' until actual
+ * content type of the message can be determined.
+ */
+ public function getType()
+ {
+ return $this->_contentType;
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_appledouble class handles multipart/appledouble
+ * messages conforming to RFC 1740.
+ *
+ * Copyright 2003-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_appledouble extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * Force viewing of a part inline, regardless of the Content-Disposition
+ * of the MIME Part.
+ *
+ * @var boolean
+ */
+ protected $_forceinline = true;
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+ $text = '';
+
+ /* RFC 1740 [4]: There are two parts to an appledouble message:
+ (1) application/applefile
+ (2) Data embedded in the Mac file */
+
+ /* Display the macintosh download link. */
+ $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(1));
+ if ($part) {
+ $status = array(
+ _("This message contains a Macintosh file."),
+ sprintf(_("The Macintosh resource fork can be downloaded %s."), $contents->linkViewJS($part, 'download_attach', _("HERE"), _("The Macintosh resource fork"))),
+ _("The contents of the Macintosh file are below.")
+ );
+ $text .= $this->formatStatusMsg($status, Horde::img('apple.png', _("Macintosh File")), false);
+ }
+
+ /* Display the content of the file. */
+ $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(2));
+ if ($part) {
+ $mime_message = Horde_Mime_Message::convertMIMEPart($part);
+ $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$contents));
+ $mc->buildMessage();
+ $text .= '<table cellspacing="0">' . $mc->getMessage(true) . '</table>';
+ }
+
+ return $text;
+ }
+
+ /**
+ * Return the content-type.
+ *
+ * @return string The content-type of the message.
+ */
+ public function getType()
+ {
+ return 'text/html; charset=' . NLS::getCharset();
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_enriched class renders out plain text from
+ * enriched content tags, ala RFC 1896
+ *
+ * Copyright 2001-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Eric Rostetter <eric.rostetter@physics.utexas.edu>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_enriched extends Horde_Mime_Viewer_enriched
+{
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ global $prefs;
+
+ if (($text = $this->mime_part->getContents()) === false) {
+ return $this->formatPartError(_("There was an error displaying this message part"));
+ }
+
+ if (trim($text) == '') {
+ return $text;
+ }
+
+ $text = parent::render();
+
+ // Highlight quoted parts of an email.
+ if ($prefs->getValue('highlight_text')) {
+ $text = implode("\n", preg_replace('|^(\s*>.+)$|', '<span class="quoted1">\1</span>', explode("\n", $text)));
+ $indent = 1;
+ while (preg_match('|>(\s?>){' . $indent . '}|', $text)) {
+ $text = implode("\n", preg_replace('|^<span class="quoted' . ((($indent - 1) % 5) + 1) . '">(\s*>(\s?>){' . $indent . '}.+)$|', '<span class="quoted' . (($indent % 5) + 1) . '">\1', explode("\n", $text)));
+ $indent++;
+ }
+ }
+
+ // Dim signatures.
+ if ($prefs->getValue('dim_signature')) {
+ $parts = preg_split('|(\n--\s*\n)|', $text, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $text = array_shift($parts);
+ if (count($parts)) {
+ $text .= '<span class="signature">' . $parts[0] .
+ preg_replace('|class="[^"]+"|', 'class="signature-fixed"', $parts[1]) .
+ '</span>';
+ }
+ }
+
+ // Filter bad language.
+ $text = IMP::filterText($text);
+
+ return $text;
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_html class renders out HTML text with an effort
+ * to remove potentially malicious code.
+ *
+ * Copyright 1999-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Jon Parise <jon@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_html extends Horde_Mime_Viewer_html
+{
+ /**
+ * Cached block image.
+ *
+ * @var string
+ */
+ protected $_blockimg = null;
+
+ /**
+ * The regular expression to catch any tags and attributes that load
+ * external images.
+ *
+ * @var string
+ */
+ protected $_img_regex = '/
+ # match 1
+ (
+ # <img> tags
+ <img[^>]+src=
+ # <input> tags
+ |<input[^>]*src=
+ # "background" attributes
+ |<body[^>]*background=|<td[^>]*background=|<table[^>]*background=
+ # "style" attributes; match 2; quotes: match 3
+ |(style=\s*("|\')?[^>]*background(?:-image)?:(?(3)[^"\']|[^>])*?url\s*\()
+ )
+ # whitespace
+ \s*
+ # opening quotes, parenthesis; match 4
+ ("|\')?
+ # the image url; match 5
+ ((?(2)
+ # matched a "style" attribute
+ (?(4)[^"\')>]*|[^\s)>]*)
+ # did not match a "style" attribute
+ |(?(4)[^"\'>]*|[^\s>]*)
+ ))
+ # closing quotes
+ (?(4)\\4)
+ # matched a "style" attribute?
+ (?(2)
+ # closing parenthesis
+ \s*\)
+ # remainder of the "style" attribute; match 5
+ ((?(3)[^"\'>]*|[^\s>]*))
+ )
+ /isx';
+
+ /**
+ * TODO
+ */
+ protected function _render()
+ {
+ $render = $this->_IMPrender(false);
+
+ return array(
+ 'data' => $render['html'],
+ 'status' => $render['status'],
+ 'type' => $this->_mimepart->getType(true)
+ );
+ }
+
+ /**
+ * TODO
+ */
+ protected function _renderInline()
+ {
+ $render = $this->_IMPrender(true);
+
+ return array(
+ 'data' => $render['html'],
+ 'status' => $render['status']
+ );
+ }
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param boolean $inline Are we viewing inline?
+ *
+ * @return array Two elements: html and status.
+ */
+ protected function _IMPrender($inline)
+ {
+ $data = $this->_mimepart->getContents();
+ $charset = NLS::getCharset();
+ $msg_charset = $this->_mimepart->getCharset();
+
+ if ($inline) {
+ $data = String::convertCharset($data, $msg_charset);
+ $msg_charset = $charset;
+ }
+
+ /* Run tidy on the HTML. */
+ if ($this->getConfigParam('tidy') &&
+ ($tidy_config = IMP::getTidyConfig(String::length($data)))) {
+ if ($msg_charset == 'us-ascii') {
+ $tidy = tidy_parse_string($data, $tidy_config, 'ascii');
+ $tidy->cleanRepair();
+ $data = tidy_get_output($tidy);
+ } else {
+ $tidy = tidy_parse_string(String::convertCharset($data, $msg_charset, 'UTF-8'), $tidy_config, 'utf8');
+ $tidy->cleanRepair();
+ $data = String::convertCharset(tidy_get_output($tidy), 'UTF-8', $msg_charset);
+ }
+ }
+
+ /* Sanitize the HTML. */
+ $cleanhtml = $this->_cleanHTML($data, $inline);
+ $data = $cleanhtml['html'];
+
+ /* Reset absolutely positioned elements. */
+ if ($inline) {
+ $data = preg_replace('/(style\s*=\s*)(["\'])?([^>"\']*)position\s*:\s*absolute([^>"\']*)\2/i', '$1"$3$4"', $data);
+ }
+
+ /* Search for inlined images that we can display. */
+ // TODO
+ $related = $this->_mimepart->getInformation('related_part');
+ if ($related !== false) {
+ $relatedPart = $this->_params['contents']->getMIMEPart($related);
+ foreach ($relatedPart->getCIDList() as $ref => $id) {
+ $id = trim($id, '<>');
+ $cid_part = $this->_params['contents']->getDecodedMIMEPart($ref);
+ $data = str_replace("cid:$id", $this->_params['contents']->urlView($cid_part, 'view_attach'), $data);
+ }
+ }
+
+ /* Convert links to open in new windows. First we hide all
+ * mailto: links, links that have an "#xyz" anchor and ignore
+ * all links that already have a target. */
+ $data = preg_replace(
+ array('/<a\s([^>]*\s*href=["\']?(#|mailto:))/i',
+ '/<a\s([^>]*)\s*target=["\']?[^>"\'\s]*["\']?/i',
+ '/<a\s/i',
+ '/<area\s([^>]*\s*href=["\']?(#|mailto:))/i',
+ '/<area\s([^>]*)\s*target=["\']?[^>"\'\s]*["\']?/i',
+ '/<area\s/i',
+ "/\x01/",
+ "/\x02/"),
+ array("<\x01\\1",
+ "<\x01 \\1 target=\"_blank\"",
+ '<a target="_blank" ',
+ "<\x02\\1",
+ "<\x02 \\1 target=\"_blank\"",
+ '<area target="_blank" ',
+ 'a ',
+ 'area '),
+ $data);
+
+ /* Turn mailto: links into our own compose links. */
+ if ($inline && $GLOBALS['registry']->hasMethod('mail/compose')) {
+ $data = preg_replace_callback('/href\s*=\s*(["\'])?mailto:((?(1)[^\1]*?|[^\s>]+))(?(1)\1|)/i', array($this, '_mailtoCallback'), $data);
+ }
+
+ /* Filter bad language. */
+ $data = IMP::filterText($data);
+
+ if ($inline) {
+ /* Put div around message. */
+ $data = '<div id="html-message">' . $data . '</div>';
+ }
+
+ /* Only display images if specifically allowed by user. */
+ $msg = $script = '';
+ if (!IMP::printMode() &&
+ $GLOBALS['prefs']->getValue('html_image_replacement') &&
+ preg_match($this->_img_regex, $data)) {
+ /* Make sure the URL parameters are correct for the current
+ * message. */
+ $url = Util::removeParameter(Horde::selfUrl(true), array('index'));
+ if ($inline) {
+ $url = Util::removeParameter($url, array('actionID'));
+ }
+ $url = Util::addParameter($url, 'index', $this->_params['contents']->getMessageIndex());
+
+ $view_img = Util::getFormData('view_html_images');
+ $addr_check = ($GLOBALS['prefs']->getValue('html_image_addrbook') && $this->_inAddressBook());
+
+ if (!$view_img && !$addr_check) {
+ $script = Util::bufferOutput(array('Horde', 'addScriptFile'), 'prototype.js', 'horde', true) .
+ Util::bufferOutput(array('Horde', 'addScriptFile'), 'unblockImages.js', 'imp', true);
+
+ $url = Util::addParameter($url, 'view_html_images', 1);
+ $attributes = $inline ? array() : array('style' => 'color:blue');
+ $msg = Horde::img('mime/image.png') . ' ' . String::convertCharset(_("Images have been blocked to protect your privacy."), $charset, $msg_charset) . ' ' . Horde::link($url, '', '', '', 'return IMP.unblockImages(' . (!$inline ? 'document.body' : '$(\'html-message\')') . ', \'block-images\');', '', '', $attributes) . String::convertCharset(_("Show Images?"), $charset, $msg_charset) . '</a>';
+ $data = preg_replace_callback($this->_img_regex, array($this, '_blockImages'), $data);
+ if (!$inline) {
+ $msg = '<span style="background:#fff;color:#000">' . nl2br($msg) . '</span><br />';
+ }
+ $msg = '<span id="block-images">' . $msg . '</span>';
+ }
+ }
+
+ /* If we are viewing inline, give option to view in separate window. */
+ if ($inline && $this->getConfigParam('external')) {
+ $cleanhtml['status'][] = array(
+ 'data' => $this->_params['contents']->linkViewJS($this->mime_part, 'view_attach', _("Show this HTML in a new window?")),
+ 'type' => 'info'
+ );
+ }
+
+ return array(
+ 'html' => $data,
+ 'status' => $cleanhtml['status']
+ );
+ }
+
+ /**
+ * TODO
+ */
+ protected function _mailtoCallback($m)
+ {
+ return 'href="' . $GLOBALS['registry']->call('mail/compose', array(String::convertCharset(html_entity_decode($m[2]), 'ISO-8859-1', NLS::getCharset()))) . '"';
+ }
+
+ /**
+ * Called from the image-blocking regexp to construct the new image tags.
+ *
+ * @param array $matches
+ *
+ * @return string The new image tag.
+ */
+ protected function _blockImages($matches)
+ {
+ if (is_null($this->_blockimg)) {
+ $this->_blockimg = Horde::url($GLOBALS['registry']->getImageDir('imp') . '/spacer_red.png', false, -1);
+ }
+
+ return empty($matches[2])
+ ? $matches[1] . '"' . $this->_blockimg . '" blocked="' . rawurlencode(str_replace('&', '&', trim($matches[5], '\'" '))) . '"'
+ : $matches[1] . "'" . $this->_blockimg . '\')' . $matches[6] . '" blocked="' . rawurlencode(str_replace('&', '&', trim($matches[5], '\'" ')));
+ }
+
+ /**
+ * Determine whether the sender appears in an available addressbook.
+ *
+ * @return boolean Does the sender appear in an addressbook?
+ */
+ protected function _inAddressBook()
+ {
+ /* If we don't have a contacts provider available, give up. */
+ if (!$GLOBALS['registry']->hasMethod('contacts/getField')) {
+ return false;
+ }
+
+ $params = IMP_Compose::getAddressSearchParams();
+
+ // TODO
+ // get mime_message.
+
+ /* Try to get back a result from the search. */
+ $result = $GLOBALS['registry']->call('contacts/getField', array($base_ob->getFromAddress(), '__key', $params['sources'], false, true));
+
+ return is_a($result, 'PEAR_Error')
+ ? false
+ : (count($result) > 0);
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_images class allows images to be displayed
+ * inline in a message.
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_images extends Horde_Mime_Viewer_images
+{
+ /**
+ * The content-type of the generated data.
+ *
+ * @var string
+ */
+ protected $_contentType;
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered information.
+ */
+ public function render($params)
+ {
+ $contents = $params[0];
+
+ global $browser;
+
+ /* If calling page is asking us to output data, do that without any
+ * further delay and exit. */
+ if (Util::getFormData('img_data')) {
+ return parent::render();
+ }
+
+ /* Convert the image to browser-viewable format and display. */
+ if (Util::getFormData('images_view_convert')) {
+ return $this->_viewConvert();
+ }
+
+ /* Create the thumbnail and display. */
+ if (Util::getFormData('images_view_thumbnail')) {
+ return $this->_viewConvert(true);
+ }
+
+ if (Util::getFormData('images_load_convert')) {
+ return $this->_popupImageWindow();
+ }
+
+ if ($this->viewAsAttachment()) {
+ if (!$browser->hasFeature('javascript')) {
+ /* If the browser doesn't support javascript then simply
+ render the image data. */
+ return parent::render();
+ } elseif ($browser->isViewable(parent::getType())) {
+ /* The browser can display the image type directly - just
+ output the javascript code to render the auto resize popup
+ image window. */
+ return $this->_popupImageWindow();
+ }
+ }
+
+ if ($browser->isViewable($this->mime_part->getType())) {
+ /* If we are viewing inline, and the browser can handle the image
+ type directly, output an <img> tag to load the image. */
+ $alt = $this->mime_part->getName(false, true);
+ return Horde::img($contents->urlView($this->mime_part, 'view_attach'), $alt, null, '');
+ } else {
+ /* If we have made it this far, than the browser cannot view this
+ image inline. Inform the user of this and, possibly, ask user
+ if we should convert to another image type. */
+ $msg = _("Your browser does not support inline display of this image type.");
+
+ if ($this->viewAsAttachment()) {
+ $msg .= '<br />' . sprintf(_("Click %s to download the image."), $contents->linkView($this->mime_part, 'download_attach', _("HERE"), array('viewparams' => array('img_data' => 1)), true));
+ }
+
+ /* See if we can convert to an inline browser viewable form. */
+ $img = $this->_getHordeImageOb(false);
+ if ($img && $browser->isViewable($img->getContentType())) {
+ if ($this->viewAsAttachment()) {
+ $convert_link = Horde::link($contents->urlView($this->mime_part, 'view_attach', array('images_load_convert' => 1))) . _("HERE") . '</a>';
+ } else {
+ $convert_link = $contents->linkViewJS($this->mime_part, 'view_attach', _("HERE"), null, null, array('images_load_convert' => 1));
+ }
+ $msg .= '<br />' . sprintf(_("Click %s to convert the image file into a format your browser can view."), $convert_link);
+ }
+
+ $this->_contentType = 'text/html; charset=' . NLS::getCharset();
+ return $this->formatStatusMsg($msg);
+ }
+ }
+
+ /**
+ * Return the content-type
+ *
+ * @return string The content-type of the output.
+ */
+ public function getType()
+ {
+ return ($this->_contentType) ? $this->_contentType : parent::getType();
+ }
+
+ /**
+ * Render out attachment information.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function renderAttachmentInfo($params)
+ {
+ $contents = &$params[0];
+
+ /* Display the thumbnail link only if we show thumbs for all images or
+ if image is over 50 KB. */
+ if (!$this->getConfigParam('allthumbs') &&
+ ($this->mime_part->getBytes() < 51200)) {
+ return '';
+ }
+
+ if (is_a($contents, 'IMP_Contents')) {
+ $this->mime_part = &$contents->getDecodedMIMEPart($this->mime_part->getMIMEId(), true);
+ }
+
+ /* Check to see if convert utility is available. */
+ if (!$this->_getHordeImageOb(false)) {
+ return '';
+ }
+
+ $status = array(
+ sprintf(_("An image named %s is attached to this message. A thumbnail is below."),
+ $this->mime_part->getName(true)),
+ );
+
+ if (!$GLOBALS['browser']->hasFeature('javascript')) {
+ $status[] = Horde::link($contents->urlView($this->mime_part,
+ 'view_attach')) .
+ Horde::img($contents->urlView($this->mime_part,
+ 'view_attach', array('images_view_thumbnail' => 1), false),
+ _("View Attachment"), null, '') . '</a>';
+ } else {
+ $status[] = $contents->linkViewJS($this->mime_part, 'view_attach',
+ Horde::img($contents->urlView($this->mime_part,
+ 'view_attach', array('images_view_thumbnail' => 1),
+ false), _("View Attachment"), null, ''), null, null,
+ null);
+ }
+
+ return $this->formatStatusMsg($status, Horde::img('mime/image.png',
+ _("Thumbnail of attached image"), null, $GLOBALS['registry']->getImageDir('horde')), false);
+ }
+
+ /**
+ * Generate the HTML output for the JS auto-resize view window.
+ *
+ * @return string The HTML output.
+ */
+ protected function _popupImageWindow()
+ {
+ $params = $remove_params = array();
+ if (Util::getFormData('images_load_convert')) {
+ $params['images_view_convert'] = 1;
+ $remove_params[] = 'images_load_convert';
+ } else {
+ $params['img_data'] = 1;
+ }
+ $self_url = Util::addParameter(Util::removeParameter(Horde::selfUrl(true), $remove_params), $params);
+ $title = MIME::decode($this->mime_part->getName(false, true));
+ $this->_contentType = 'text/html; charset=' . NLS::getCharset();
+ return parent::_popupImageWindow($self_url, $title);
+ }
+
+ /**
+ * View thumbnail sized image.
+ *
+ * @param boolean $thumb View thumbnail size?
+ *
+ * @return string The image data.
+ */
+ protected function _viewConvert($thumb = false)
+ {
+ $mime = $this->mime_part;
+ $img = $this->_getHordeImageOb();
+
+ if ($img) {
+ if ($thumb) {
+ $img->resize(96, 96, true);
+ }
+ $type = $img->getContentType();
+ $data = $img->raw(true);
+ }
+
+ if (!$img || !$data) {
+ $type = 'image/png';
+ $data = file_get_contents(IMP_BASE . '/themes/graphics/mini-error.png');
+ }
+
+ $mime->setType($type);
+ $this->_contentType = $type;
+ $mime->setContents($data);
+
+ return $mime->getContents();
+ }
+
+ /**
+ * Return a Horde_Image object.
+ *
+ * @param boolean $load Whether to load the image data.
+ *
+ * @return Horde_Image The requested object.
+ */
+ protected function _getHordeImageOb($load = true)
+ {
+ include_once 'Horde/Image.php';
+ $params = array('temp' => Horde::getTempdir());
+ if (!empty($GLOBALS['conf']['image']['convert'])) {
+ $img = &Horde_Image::singleton('im', $params);
+ } elseif (Util::extensionExists('gd')) {
+ $img = &Horde_Image::singleton('gd', $params);
+ } else {
+ return false;
+ }
+
+ if (is_a($img, 'PEAR_Error')) {
+ return false;
+ }
+
+ if ($load) {
+ $ret = $img->loadString(1, $this->mime_part->getContents());
+ if (is_a($ret, 'PEAR_Error')) {
+ return false;
+ }
+ }
+
+ return $img;
+ }
+
+ /**
+ * Can this driver render the the data inline?
+ *
+ * @return boolean True if the driver can display inline.
+ */
+ public function canDisplayInline()
+ {
+ /* Only display the image inline if the configuration parameter is set,
+ the browser can actually display it, and the size of the image is
+ small. */
+ global $browser;
+ if (($this->getConfigParam('inline')) && ($browser->isViewable($this->mime_part->getType())) &&
+ ($this->mime_part->getBytes() < 51200)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_HordeMIME_Viewer_itip class displays vCalendar/iCalendar data
+ * and provides an option to import the data into a calendar source,
+ * if one is available.
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Cochrane <mike@graftonhall.co.nz>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_itip extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * Force viewing of a part inline, regardless of the Content-Disposition
+ * of the MIME Part.
+ *
+ * @var boolean
+ */
+ protected $_forceinline = true;
+
+ /**
+ * The messages to output to the user.
+ *
+ * @var array
+ */
+ protected $_msgs = array();
+
+ /**
+ * The method as marked in either the iCal structure or message header.
+ *
+ * @var string
+ */
+ protected $_method = 'PUBLISH';
+
+ /**
+ * The headers of the message.
+ *
+ * @var string
+ */
+ protected $_headers;
+
+ /**
+ * Render out the currently set iCalendar contents.
+ *
+ * @param array $params Any parameters the Viewer may need.
+ *
+ * @return string The rendered contents.
+ */
+ public function render($params = array())
+ {
+ global $registry;
+
+ // Extract the data.
+ $data = $this->mime_part->getContents();
+ if (empty($this->_headers) && is_a($params[0], 'IMP_Contents')) {
+ $this->_headers = $params[0]->getHeaderOb();
+ }
+
+ // Parse the iCal file.
+ $vCal = new Horde_iCalendar();
+ if (!$vCal->parsevCalendar($data, 'VCALENDAR', $this->mime_part->getCharset())) {
+ return '<h1>' . _("The calendar data is invalid") . '</h1>' .
+ '<pre>' . htmlspecialchars($data) . '</pre>';
+ }
+
+ // Check if we got vcard data with the wrong vcalendar mime type.
+ $c = $vCal->getComponentClasses();
+ if (count($c) == 1 && !empty($c['horde_icalendar_vcard'])) {
+ $vcard_renderer = &Horde_Mime_Viewer::factory($this->mime_part, 'text/x-vcard');
+ return $vcard_renderer->render($params);
+ }
+
+ // Get the method type.
+ $this->_method = $vCal->getAttribute('METHOD');
+ if (is_a($this->_method, 'PEAR_Error')) {
+ $this->_method = '';
+ }
+
+ // Get the iCalendar file components.
+ $components = $vCal->getComponents();
+
+ // Handle the action requests.
+ $actions = Util::getFormData('action', array());
+ foreach ($actions as $key => $action) {
+ $this->_msgs[$key] = array();
+ switch ($action) {
+ case 'delete':
+ // vEvent cancellation.
+ if ($registry->hasMethod('calendar/delete')) {
+ $guid = $components[$key]->getAttribute('UID');
+ $event = $registry->call('calendar/delete', array('guid' => $guid));
+ if (is_a($event, 'PEAR_Error')) {
+ $this->_msgs[$key][] = array('error', _("There was an error deleting the event:") . ' ' . $event->getMessage());
+ } else {
+ $this->_msgs[$key][] = array('success', _("Event successfully deleted."));
+ }
+ } else {
+ $this->_msgs[$key][] = array('warning', _("This action is not supported."));
+ }
+ break;
+
+ case 'update':
+ // vEvent reply.
+ if ($registry->hasMethod('calendar/updateAttendee')) {
+ $event = $registry->call('calendar/updateAttendee', array('response' => $components[$key], 'sender' => $params[0]->getFromAddress()));
+ if (is_a($event, 'PEAR_Error')) {
+ $this->_msgs[$key][] = array('error', _("There was an error updating the event:") . ' ' . $event->getMessage());
+ } else {
+ $this->_msgs[$key][] = array('success', _("Respondent Status Updated."));
+ }
+ } else {
+ $this->_msgs[$key][] = array('warning', _("This action is not supported."));
+ }
+ break;
+
+ case 'import':
+ case 'accept-import':
+ // vFreebusy reply.
+ // vFreebusy publish.
+ // vEvent request.
+ // vEvent publish.
+ // vTodo publish.
+ // vJournal publish.
+ switch ($components[$key]->getType()) {
+ case 'vEvent':
+ $handled = false;
+ $guid = $components[$key]->getAttribute('UID');
+ // Check if this is an update.
+ if ($registry->hasMethod('calendar/export') &&
+ !is_a($registry->call('calendar/export', array($guid, 'text/calendar')), 'PEAR_Error')) {
+ // Update in Kronolith.
+ if ($registry->hasMethod('calendar/replace')) {
+ $handled = true;
+ $result = $registry->call('calendar/replace', array('uid' => $guid, 'content' => $components[$key], 'contentType' => $this->mime_part->getType()));
+ if (is_a($result, 'PEAR_Error')) {
+ $this->_msgs[$key][] = array('error', _("There was an error updating the event:") . ' ' . $result->getMessage());
+ } else {
+ $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
+ $this->_msgs[$key][] = array('success', _("The event was updated in your calendar.") .
+ ' ' . Horde::link($url, _("View event"), null, '_blank') . Horde::img('mime/icalendar.png', _("View event"), null, $registry->getImageDir('horde')) . '</a>');
+ }
+ }
+ } else {
+ // Import into Kronolith.
+ if ($registry->hasMethod('calendar/import')) {
+ $handled = true;
+ $guid = $registry->call('calendar/import', array('content' => $components[$key], 'contentType' => $this->mime_part->getType()));
+ if (is_a($guid, 'PEAR_Error')) {
+ $this->_msgs[$key][] = array('error', _("There was an error importing the event:") . ' ' . $guid->getMessage());
+ } else {
+ $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
+ $this->_msgs[$key][] = array('success', _("The event was added to your calendar.") .
+ ' ' . Horde::link($url, _("View event"), null, '_blank') . Horde::img('mime/icalendar.png', _("View event"), null, $registry->getImageDir('horde')) . '</a>');
+ }
+ }
+ }
+ if (!$handled) {
+ $this->_msgs[$key][] = array('warning', _("This action is not supported."));
+ }
+ break;
+
+ case 'vFreebusy':
+ // Import into Kronolith.
+ if ($registry->hasMethod('calendar/import_vfreebusy')) {
+ $res = $registry->call('calendar/import_vfreebusy', array($components[$key]));
+ if (is_a($res, 'PEAR_Error')) {
+ $this->_msgs[$key][] = array('error', _("There was an error importing user's free/busy information:") . ' ' . $res->getMessage());
+ } else {
+ $this->_msgs[$key][] = array('success', _("The user's free/busy information was sucessfully stored."));
+ }
+ } else {
+ $this->_msgs[$key][] = array('warning', _("This action is not supported."));
+ }
+ break;
+
+ case 'vTodo':
+ // Import into Nag.
+ if ($registry->hasMethod('tasks/import')) {
+ $guid = $registry->call('tasks/import', array($components[$key], $this->mime_part->getType()));
+ if (is_a($guid, 'PEAR_Error')) {
+ $this->_msgs[$key][] = array('error', _("There was an error importing the task:") . ' ' . $guid->getMessage());
+ } else {
+ $url = Horde::url($registry->link('tasks/show', array('uid' => $guid)));
+ $this->_msgs[$key][] = array('success', _("The task has been added to your tasklist.") .
+ ' ' . Horde::link($url, _("View task"), null, '_blank') . Horde::img('mime/icalendar.png', _("View task"), null, $registry->getImageDir('horde')) . '</a>');
+ }
+ } else {
+ $this->_msgs[$key][] = array('warning', _("This action is not supported."));
+ }
+ break;
+
+ case 'vJournal':
+ default:
+ $this->_msgs[$key][] = array('warning', _("This action is not yet implemented."));
+ }
+
+ if ($action != 'accept-import') {
+ break;
+ }
+
+ case 'accept':
+ case 'accept-import':
+ case 'deny':
+ case 'tentative':
+ // vEvent request.
+ if (isset($components[$key]) &&
+ $components[$key]->getType() == 'vEvent') {
+ $vEvent = $components[$key];
+
+ // Get the organizer details.
+ $organizer = $vEvent->getAttribute('ORGANIZER');
+ if (is_a($organizer, 'PEAR_Error')) {
+ break;
+ }
+ $organizer = parse_url($organizer);
+ $organizerEmail = $organizer['path'];
+ $organizer = $vEvent->getAttribute('ORGANIZER', true);
+ $organizerName = isset($organizer['cn']) ? $organizer['cn'] : '';
+
+ require_once 'Horde/Identity.php';
+
+ // Build the reply.
+ $vCal = new Horde_iCalendar();
+ $vCal->setAttribute('PRODID', '-//The Horde Project//' . HORDE_AGENT_HEADER . '//EN');
+ $vCal->setAttribute('METHOD', 'REPLY');
+
+ $vEvent_reply = &Horde_iCalendar::newComponent('vevent', $vCal);
+ $vEvent_reply->setAttribute('UID', $vEvent->getAttribute('UID'));
+ if (!is_a($vEvent->getAttribute('SUMMARY'), 'PEAR_error')) {
+ $vEvent_reply->setAttribute('SUMMARY', $vEvent->getAttribute('SUMMARY'));
+ }
+ if (!is_a($vEvent->getAttribute('DESCRIPTION'), 'PEAR_error')) {
+ $vEvent_reply->setAttribute('DESCRIPTION', $vEvent->getAttribute('DESCRIPTION'));
+ }
+ $dtstart = $vEvent->getAttribute('DTSTART', true);
+ $vEvent_reply->setAttribute('DTSTART', $vEvent->getAttribute('DTSTART'), array_pop($dtstart));
+ if (!is_a($vEvent->getAttribute('DTEND'), 'PEAR_error')) {
+ $dtend = $vEvent->getAttribute('DTEND', true);
+ $vEvent_reply->setAttribute('DTEND', $vEvent->getAttribute('DTEND'), array_pop($dtend));
+ } else {
+ $duration = $vEvent->getAttribute('DURATION', true);
+ $vEvent_reply->setAttribute('DURATION', $vEvent->getAttribute('DURATION'), array_pop($duration));
+ }
+ if (!is_a($vEvent->getAttribute('SEQUENCE'), 'PEAR_error')) {
+ $vEvent_reply->setAttribute('SEQUENCE', $vEvent->getAttribute('SEQUENCE'));
+ }
+ $vEvent_reply->setAttribute('ORGANIZER', $vEvent->getAttribute('ORGANIZER'), array_pop($organizer));
+
+ // Find out who we are and update status.
+ $identity = &Identity::singleton(array('imp', 'imp'));
+ $attendees = $vEvent->getAttribute('ATTENDEE');
+ if (!is_array($attendees)) {
+ $attendees = array($attendees);
+ }
+ foreach ($attendees as $attendee) {
+ $attendee = preg_replace('/mailto:/i', '', $attendee);
+ if (!is_null($id = $identity->getMatchingIdentity($attendee))) {
+ $identity->setDefault($id);
+ break;
+ }
+ }
+ $name = $email = $identity->getFromAddress();
+ $params = array();
+ $cn = $identity->getValue('fullname');
+ if (!empty($cn)) {
+ $name = $params['CN'] = $cn;
+ }
+
+ switch ($action) {
+ case 'accept':
+ case 'accept-import':
+ $message = sprintf(_("%s has accepted."), $name);
+ $subject = _("Accepted: ") . $vEvent->getAttribute('SUMMARY');
+ $params['PARTSTAT'] = 'ACCEPTED';
+ break;
+
+ case 'deny':
+ $message = sprintf(_("%s has declined."), $name);
+ $subject = _("Declined: ") . $vEvent->getAttribute('SUMMARY');
+ $params['PARTSTAT'] = 'DECLINED';
+ break;
+
+ case 'tentative':
+ $message = sprintf(_("%s has tentatively accepted."), $name);
+ $subject = _("Tentative: ") . $vEvent->getAttribute('SUMMARY');
+ $params['PARTSTAT'] = 'TENTATIVE';
+ break;
+ }
+
+ $vEvent_reply->setAttribute('ATTENDEE', 'mailto:' . $email, $params);
+ $vCal->addComponent($vEvent_reply);
+
+ $mime = new Horde_Mime_Part('multipart/alternative');
+ $body = new Horde_Mime_Part('text/plain',
+ String::wrap($message, 76, "\n"),
+ NLS::getCharset());
+
+ $ics = new Horde_Mime_Part('text/calendar', $vCal->exportvCalendar());
+ $ics->setName('event-reply.ics');
+ $ics->setContentTypeParameter('METHOD', 'REPLY');
+ $ics->setCharset(NLS::getCharset());
+
+ $mime->addPart($body);
+ $mime->addPart($ics);
+ $mime = &Horde_Mime_Message::convertMimePart($mime);
+
+ // Build the reply headers.
+ $msg_headers = new Horde_Mime_Headers();
+ $msg_headers->addReceivedHeader();
+ $msg_headers->addMessageIdHeader();
+ $msg_headers->addHeader('Date', date('r'));
+ $msg_headers->addHeader('From', $email);
+ $msg_headers->addHeader('To', $organizerEmail);
+
+ $identity->setDefault(Util::getFormData('identity'));
+ $replyto = $identity->getValue('replyto_addr');
+ if (!empty($replyto) && ($replyto != $email)) {
+ $msg_headers->addHeader('Reply-to', $replyto);
+ }
+ $msg_headers->addHeader('Subject', Horde_Mime::encode($subject, NLS::getCharset()));
+
+ // Send the reply.
+ $status = $mime->send($organizerEmail, $msg_headers,
+ $GLOBALS['conf']['mailer']['type'],
+ $GLOBALS['conf']['mailer']['params']);
+ if (is_a($status, 'PEAR_Error')) {
+ $this->_msgs[$key][] = array('error', sprintf(_("Error sending reply: %s."), $status->getMessage()));
+ } else {
+ $this->_msgs[$key][] = array('success', _("Reply Sent."));
+ }
+ } else {
+ $this->_msgs[$key][] = array('warning', _("This action is not supported."));
+ }
+ break;
+
+ case 'send':
+ // vEvent refresh.
+ if (isset($components[$key]) &&
+ $components[$key]->getType() == 'vEvent') {
+ $vEvent = $components[$key];
+ }
+
+ // vTodo refresh.
+ case 'reply':
+ case 'reply2m':
+ // vfreebusy request.
+ if (isset($components[$key]) &&
+ $components[$key]->getType() == 'vFreebusy') {
+ $vFb = $components[$key];
+
+ // Get the organizer details.
+ $organizer = $vFb->getAttribute('ORGANIZER');
+ if (is_a($organizer, 'PEAR_Error')) {
+ break;
+ }
+ $organizer = parse_url($organizer);
+ $organizerEmail = $organizer['path'];
+ $organizer = $vFb->getAttribute('ORGANIZER', true);
+ $organizerName = isset($organizer['cn']) ? $organizer['cn'] : '';
+
+ if ($action == 'reply2m') {
+ $startStamp = time();
+ $endStamp = $startStamp + (60 * 24 * 3600);
+ } else {
+ $startStamp = $vFb->getAttribute('DTSTART');
+ if (is_a($startStamp, 'PEAR_Error')) {
+ $startStamp = time();
+ }
+ $endStamp = $vFb->getAttribute('DTEND');
+ if (is_a($endStamp, 'PEAR_Error')) {
+ $duration = $vFb->getAttribute('DURATION');
+ if (is_a($duration, 'PEAR_Error')) {
+ $endStamp = $startStamp + (60 * 24 * 3600);
+ } else {
+ $endStamp = $startStamp + $duration;
+ }
+ }
+ }
+ $vfb_reply = $registry->call('calendar/getFreeBusy',
+ array('startStamp' => $startStamp,
+ 'endStamp' => $endStamp));
+ require_once 'Horde/Identity.php';
+
+ // Find out who we are and update status.
+ $identity = &Identity::singleton();
+ $email = $identity->getFromAddress();
+
+ // Build the reply.
+ $vCal = new Horde_iCalendar();
+ $vCal->setAttribute('PRODID', '-//The Horde Project//' . HORDE_AGENT_HEADER . '//EN');
+ $vCal->setAttribute('METHOD', 'REPLY');
+ $vCal->addComponent($vfb_reply);
+
+ $mime = new Horde_Mime_Message();
+ $message = _("Attached is a reply to a calendar request you sent.");
+ $body = new Horde_Mime_Part('text/plain',
+ String::wrap($message, 76, "\n"),
+ NLS::getCharset());
+
+ $ics = new Horde_Mime_Part('text/calendar', $vCal->exportvCalendar());
+ $ics->setName('icalendar.ics');
+ $ics->setContentTypeParameter('METHOD', 'REPLY');
+ $ics->setCharset(NLS::getCharset());
+
+ $mime->addPart($body);
+ $mime->addPart($ics);
+
+ // Build the reply headers.
+ $msg_headers = new Horde_Mime_Headers();
+ $msg_headers->addReceivedHeader();
+ $msg_headers->addMessageIdHeader();
+ $msg_headers->addHeader('Date', date('r'));
+ $msg_headers->addHeader('From', $email);
+ $msg_headers->addHeader('To', $organizerEmail);
+
+ $identity->setDefault(Util::getFormData('identity'));
+ $replyto = $identity->getValue('replyto_addr');
+ if (!empty($replyto) && ($replyto != $email)) {
+ $msg_headers->addHeader('Reply-to', $replyto);
+ }
+ $msg_headers->addHeader('Subject', Horde_Mime::encode(_("Free/Busy Request Response"), NLS::getCharset()));
+
+ // Send the reply.
+ $status = $mime->send($organizerEmail, $msg_headers,
+ $GLOBALS['conf']['mailer']['type'],
+ $GLOBALS['conf']['mailer']['params']);
+ if (is_a($status, 'PEAR_Error')) {
+ $this->_msgs[$key][] = array('error', sprintf(_("Error sending reply: %s."), $status->getMessage()));
+ } else {
+ $this->_msgs[$key][] = array('success', _("Reply Sent."));
+ }
+ } else {
+ $this->_msgs[$key][] = array('warning', _("Invalid Action selected for this component."));
+ }
+ break;
+
+ case 'nosup':
+ // vFreebusy request.
+ default:
+ $this->_msgs[$key][] = array('warning', _("This action is not yet implemented."));
+ break;
+ }
+ }
+
+ // Create the HTML to display the iCal file.
+ $html = '';
+ if ($this->viewAsAttachment()) {
+ $html .= Util::bufferOutput('require', $registry->get('templates', 'horde') . '/common-header.inc');
+ }
+ if ($_SESSION['imp']['viewmode'] == 'imp') {
+ $html .= '<form method="post" name="iCal" action="' . Horde::selfUrl(true) . '">';
+ }
+
+ foreach ($components as $key => $component) {
+ switch ($component->getType()) {
+ case 'vEvent':
+ $html .= $this->_vEvent($component, $key);
+ break;
+
+ case 'vTodo':
+ $html .= $this->_vTodo($component, $key);
+ break;
+
+ case 'vTimeZone':
+ // Ignore them.
+ break;
+
+ case 'vFreebusy':
+ $html .= $this->_vFreebusy($component, $key);
+ break;
+
+ // @todo: handle stray vcards here as well.
+ default:
+ $html .= sprintf(_("Unhandled component of type: %s"), $component->getType());
+ }
+ }
+
+ // Need to work out if we are inline and actually need this.
+ if ($_SESSION['imp']['viewmode'] == 'imp') {
+ $html .= '</form>';
+ }
+ if ($this->viewAsAttachment()) {
+ $html .= Util::bufferOutput('require', $registry->get('templates', 'horde') . '/common-footer.inc');
+ }
+
+ return $html;
+ }
+
+ /**
+ * Return text/html as the content-type.
+ *
+ * @return string "text/html" constant
+ */
+ public function getType()
+ {
+ return 'text/html; charset=' . NLS::getCharset();
+ }
+
+ /**
+ * Return the html for a vFreebusy.
+ */
+ protected function _vFreebusy($vfb, $id)
+ {
+ global $registry, $prefs;
+
+ $html = '';
+ $desc = '';
+ $sender = $vfb->getName();
+ switch ($this->_method) {
+ case 'PUBLISH':
+ $desc = _("%s has sent you free/busy information.");
+ break;
+
+ case 'REQUEST':
+ $sender = $this->_headers->getValue('From');
+ $desc = _("%s requests your free/busy information.");
+ break;
+
+ case 'REPLY':
+ $desc = _("%s has replied to a free/busy request.");
+ break;
+ }
+
+ $html .= '<h1 class="header">' . sprintf($desc, $sender) . '</h1>';
+
+ if ($this->_msgs) {
+ foreach ($this->_msgs[$id] as $msg) {
+ $html .= '<p class="notice">' . Horde::img('alerts/' . $msg[0] . '.png', '', null, $registry->getImageDir('horde')) . $msg[1] . '</p>';
+ }
+ }
+
+ $start = $vfb->getAttribute('DTSTART');
+ if (!is_a($start, 'PEAR_Error')) {
+ if (is_array($start)) {
+ $html .= '<p><strong>' . _("Start") . ':</strong> ' . strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $start['month'], $start['mday'], $start['year'])) . '</p>';
+ } else {
+ $html .= '<p><strong>' . _("Start") . ':</strong> ' . strftime($prefs->getValue('date_format'), $start) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $start) . '</p>';
+ }
+ }
+
+ $end = $vfb->getAttribute('DTEND');
+ if (!is_a($end, 'PEAR_Error')) {
+ if (is_array($end)) {
+ $html .= '<p><strong>' . _("End") . ':</strong> ' . strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $end['month'], $end['mday'], $end['year'])) . '</p>';
+ } else {
+ $html .= '<p><strong>' . _("End") . ':</strong> ' . strftime($prefs->getValue('date_format'), $end) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $end) . '</p>';
+ }
+ }
+
+ if ($_SESSION['imp']['viewmode'] != 'imp') {
+ return $html;
+ }
+
+ $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
+ '<select name="action[' . $id . ']">';
+
+ switch ($this->_method) {
+ case 'PUBLISH':
+ if ($registry->hasMethod('calendar/import_vfreebusy')) {
+ $html .= '<option value="import">' . _("Remember the free/busy information.") . '</option>';
+ } else {
+ $html .= '<option value="nosup">' . _("Reply with Not Supported Message") . '</option>';
+ }
+ break;
+
+ case 'REQUEST':
+ if ($registry->hasMethod('calendar/getFreeBusy')) {
+ $html .= '<option value="reply">' . _("Reply with requested free/busy information.") . '</option>' .
+ '<option value="reply2m">' . _("Reply with free/busy for next 2 months.") . '</option>';
+ } else {
+ $html .= '<option value="nosup">' . _("Reply with Not Supported Message") . '</option>';
+ }
+
+ $html .= '<option value="deny">' . _("Deny request for free/busy information") . '</option>';
+ break;
+
+ case 'REPLY':
+ if ($registry->hasMethod('calendar/import_vfreebusy')) {
+ $html .= '<option value="import">' . _("Remember the free/busy information.") . '</option>';
+ } else {
+ $html .= '<option value="nosup">' . _("Reply with Not Supported Message") . '</option>';
+ }
+ break;
+ }
+
+ return $html . '</select> <input type="submit" class="button" value="' . _("Go") . '/>';
+ }
+
+ /**
+ * Return the html for a vEvent.
+ */
+ protected function _vEvent($vevent, $id)
+ {
+ global $registry, $prefs;
+
+ $html = '';
+ $desc = '';
+ $sender = $vevent->organizerName();
+ $options = array();
+
+ $attendees = $vevent->getAttribute('ATTENDEE');
+ if (!is_a($attendees, 'PEAR_Error') &&
+ !empty($attendees) &&
+ !is_array($attendees)) {
+ $attendees = array($attendees);
+ }
+ $attendee_params = $vevent->getAttribute('ATTENDEE', true);
+
+ switch ($this->_method) {
+ case 'PUBLISH':
+ $desc = _("%s wishes to make you aware of \"%s\".");
+ if ($registry->hasMethod('calendar/import')) {
+ $options[] = '<option value="import">' . _("Add this to my calendar") . '</option>';
+ }
+ break;
+
+ case 'REQUEST':
+ // Check if this is an update.
+ if ($registry->hasMethod('calendar/export') &&
+ !is_a($registry->call('calendar/export', array($vevent->getAttribute('UID'), 'text/calendar')), 'PEAR_Error')) {
+ $is_update = true;
+ $desc = _("%s wants to notify you about changes of \"%s\".");
+ } else {
+ $is_update = false;
+
+ // Check that you are one of the attendees here.
+ $is_attendee = false;
+ if (!is_a($attendees, 'PEAR_Error') && !empty($attendees)) {
+ require_once 'Horde/Identity.php';
+ $identity = &Identity::singleton(array('imp', 'imp'));
+ for ($i = 0, $c = count($attendees); $i < $c; ++$i) {
+ $attendee = parse_url($attendees[$i]);
+ if (!empty($attendee['path']) &&
+ $identity->hasAddress($attendee['path'])) {
+ $is_attendee = true;
+ break;
+ }
+ }
+ }
+
+ $desc = $is_attendee
+ ? _("%s requests your presence at \"%s\".")
+ : _("%s wishes to make you aware of \"%s\".");
+ }
+ if ($is_update && $registry->hasMethod('calendar/replace')) {
+ $options[] = '<option value="accept-import">' . _("Accept and update in my calendar") . '</option>';
+ $options[] = '<option value="import">' . _("Update in my calendar") . '</option>';
+ } elseif ($registry->hasMethod('calendar/import')) {
+ $options[] = '<option value="accept-import">' . _("Accept and add to my calendar") . '</option>';
+ $options[] = '<option value="import">' . _("Add to my calendar") . '</option>';
+ }
+ $options[] = '<option value="accept">' . _("Accept request") . '</option>';
+ $options[] = '<option value="tentative">' . _("Tentatively Accept request") . '</option>';
+ $options[] = '<option value="deny">' . _("Deny request") . '</option>';
+ // $options[] = '<option value="delegate">' . _("Delegate position") . '</option>';
+ break;
+
+ case 'ADD':
+ $desc = _("%s wishes to ammend \"%s\".");
+ if ($registry->hasMethod('calendar/import')) {
+ $options[] = '<option value="import">' . _("Update this event on my calendar") . '</option>';
+ }
+ break;
+
+ case 'REFRESH':
+ $desc = _("%s wishes to receive the latest information about \"%s\".");
+ $options[] = '<option value="send">' . _("Send Latest Information") . '</option>';
+ break;
+
+ case 'REPLY':
+ $desc = _("%s has replied to the invitation to \"%s\".");
+ $sender = $this->_headers->getValue('From');
+ if ($registry->hasMethod('calendar/updateAttendee')) {
+ $options[] = '<option value="update">' . _("Update respondent status") . '</option>';
+ }
+ break;
+
+ case 'CANCEL':
+ if (is_a($instance = $vevent->getAttribute('RECURRENCE-ID'), 'PEAR_Error')) {
+ $desc = _("%s has cancelled \"%s\".");
+ if ($registry->hasMethod('calendar/delete')) {
+ $options[] = '<option value="delete">' . _("Delete from my calendar") . '</option>';
+ }
+ } else {
+ $desc = _("%s has cancelled an instance of the recurring \"%s\".");
+ if ($registry->hasMethod('calendar/replace')) {
+ $options[] = '<option value="import">' . _("Update in my calendar") . '</option>';
+ }
+ }
+ break;
+ }
+
+ $summary = $vevent->getAttribute('SUMMARY');
+ if (is_a($summary, 'PEAR_Error')) {
+ $desc = sprintf($desc, htmlspecialchars($sender), _("Unknown Meeting"));
+ } else {
+ $desc = sprintf($desc, htmlspecialchars($sender), htmlspecialchars($summary));
+ }
+
+ $html .= '<h2 class="header">' . $desc . '</h2>';
+
+ if ($this->_msgs) {
+ foreach ($this->_msgs[$id] as $msg) {
+ $html .= '<p class="notice">' . Horde::img('alerts/' . $msg[0] . '.png', '', null, $registry->getImageDir('horde')) . $msg[1] . '</p>';
+ }
+ }
+
+ $start = $vevent->getAttribute('DTSTART');
+ if (!is_a($start, 'PEAR_Error')) {
+ if (is_array($start)) {
+ $html .= '<p><strong>' . _("Start") . ':</strong> ' . strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $start['month'], $start['mday'], $start['year'])) . '</p>';
+ } else {
+ $html .= '<p><strong>' . _("Start") . ':</strong> ' . strftime($prefs->getValue('date_format'), $start) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $start) . '</p>';
+ }
+ }
+
+ $end = $vevent->getAttribute('DTEND');
+ if (!is_a($end, 'PEAR_Error')) {
+ if (is_array($end)) {
+ $html .= '<p><strong>' . _("End") . ':</strong> ' . strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $end['month'], $end['mday'], $end['year'])) . '</p>';
+ } else {
+ $html .= '<p><strong>' . _("End") . ':</strong> ' . strftime($prefs->getValue('date_format'), $end) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $end) . '</p>';
+ }
+ }
+
+ $sum = $vevent->getAttribute('SUMMARY');
+ if (!is_a($sum, 'PEAR_Error')) {
+ $html .= '<p><strong>' . _("Summary") . ':</strong> ' . htmlspecialchars($sum) . '</p>';
+ } else {
+ $html .= '<p><strong>' . _("Summary") . ':</strong> <em>' . _("None") . '</em></p>';
+ }
+
+ $desc = $vevent->getAttribute('DESCRIPTION');
+ if (!is_a($desc, 'PEAR_Error')) {
+ $html .= '<p><strong>' . _("Description") . ':</strong> ' . nl2br(htmlspecialchars($desc)) . '</p>';
+ }
+
+ $loc = $vevent->getAttribute('LOCATION');
+ if (!is_a($loc, 'PEAR_Error')) {
+ $html .= '<p><strong>' . _("Location") . ':</strong> ' . htmlspecialchars($loc) . '</p>';
+ }
+
+ if (!is_a($attendees, 'PEAR_Error') && !empty($attendees)) {
+ $html .= '<h2 class="smallheader">' . _("Attendees") . '</h2>';
+
+ $html .= '<table><thead class="leftAlign"><tr><th>' . _("Name") . '</th><th>' . _("Role") . '</th><th>' . _("Status") . '</th></tr></thead><tbody>';
+ foreach ($attendees as $key => $attendee) {
+ $attendee = parse_url($attendee);
+ $attendee = empty($attendee['path']) ? _("Unknown") : $attendee['path'];
+
+ if (!empty($attendee_params[$key]['CN'])) {
+ $attendee = $attendee_params[$key]['CN'];
+ }
+
+ $role = _("Required Participant");
+ if (isset($attendee_params[$key]['ROLE'])) {
+ switch ($attendee_params[$key]['ROLE']) {
+ case 'CHAIR':
+ $role = _("Chair Person");
+ break;
+
+ case 'OPT-PARTICIPANT':
+ $role = _("Optional Participant");
+ break;
+
+ case 'NON-PARTICIPANT':
+ $role = _("Non Participant");
+ break;
+
+ case 'REQ-PARTICIPANT':
+ default:
+ // Already set above.
+ break;
+ }
+ }
+
+ $status = _("Awaiting Response");
+ if (isset($attendee_params[$key]['PARTSTAT'])) {
+ $status = $this->_partstatToString($attendee_params[$key]['PARTSTAT'], $status);
+ }
+
+ $html .= '<tr><td>' . htmlspecialchars($attendee) . '</td><td>' . htmlspecialchars($role) . '</td><td>' . htmlspecialchars($status) . '</td></tr>';
+ }
+ $html .= '</tbody></table>';
+ }
+
+ if ($_SESSION['imp']['viewmode'] != 'imp') {
+ return $html;
+ }
+
+ if ($options) {
+ $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
+ '<label for="action_' . $id . '" class="hidden">' . _("Actions") . '</label>' .
+ '<select id="action_' . $id . '" name="action[' . $id . ']">' .
+ implode("\n", $options) .
+ '</select> <input type="submit" class="button" value="' . _("Go") . '" />';
+ }
+
+ return $html;
+ }
+
+ /**
+ * Returns the html for a vEvent.
+ *
+ * @todo IMP 5: move organizerName() from Horde_iCalendar_vevent to
+ * Horde_iCalendar
+ */
+ protected function _vTodo($vtodo, $id)
+ {
+ global $registry, $prefs;
+
+ $html = '';
+ $desc = '';
+ $options = array();
+
+ $organizer = $vtodo->getAttribute('ORGANIZER', true);
+ if (is_a($organizer, 'PEAR_Error')) {
+ $sender = _("An unknown person");
+ } else {
+ if (isset($organizer[0]['CN'])) {
+ $sender = $organizer[0]['CN'];
+ } else {
+ $organizer = parse_url($vtodo->getAttribute('ORGANIZER'));
+ $sender = $organizer['path'];
+ }
+ }
+
+ switch ($this->_method) {
+ case 'PUBLISH':
+ $desc = _("%s wishes to make you aware of \"%s\".");
+ if ($registry->hasMethod('tasks/import')) {
+ $options[] = '<option value="import">' . _("Add this to my tasklist") . '</option>';
+ }
+ break;
+ }
+
+ $summary = $vtodo->getAttribute('SUMMARY');
+ if (is_a($summary, 'PEAR_Error')) {
+ $desc = sprintf($desc, htmlspecialchars($sender), _("Unknown Task"));
+ } else {
+ $desc = sprintf($desc, htmlspecialchars($sender), htmlspecialchars($summary));
+ }
+
+ $html .= '<h2 class="header">' . $desc . '</h2>';
+
+ if ($this->_msgs) {
+ foreach ($this->_msgs[$id] as $msg) {
+ $html .= '<p class="notice">' . Horde::img('alerts/' . $msg[0] . '.png', '', null, $registry->getImageDir('horde')) . $msg[1] . '</p>';
+ }
+ }
+
+ $priority = $vtodo->getAttribute('PRIORITY');
+ if (!is_a($priority, 'PEAR_Error')) {
+ $html .= '<p><strong>' . _("Priority") . ':</strong> ' . (int)$priority . '</p>';
+ }
+
+ $sum = $vtodo->getAttribute('SUMMARY');
+ if (!is_a($sum, 'PEAR_Error')) {
+ $html .= '<p><strong>' . _("Summary") . ':</strong> ' . htmlspecialchars($sum) . '</p>';
+ } else {
+ $html .= '<p><strong>' . _("Summary") . ':</strong> <em>' . _("None") . '</em></p>';
+ }
+
+ $desc = $vtodo->getAttribute('DESCRIPTION');
+ if (!is_a($desc, 'PEAR_Error')) {
+ $html .= '<p><strong>' . _("Description") . ':</strong> ' . nl2br(htmlspecialchars($desc)) . '</p>';
+ }
+
+ $attendees = $vtodo->getAttribute('ATTENDEE');
+ $params = $vtodo->getAttribute('ATTENDEE', true);
+
+ if (!is_a($attendees, 'PEAR_Error') && !empty($attendees)) {
+ $html .= '<h2 class="smallheader">' . _("Attendees") . '</h2>';
+ if (!is_array($attendees)) {
+ $attendees = array($attendees);
+ }
+
+ $html .= '<table><thead class="leftAlign"><tr><th>' . _("Name") . '</th><th>' . _("Role") . '</th><th>' . _("Status") . '</th></tr></thead><tbody>';
+ foreach ($attendees as $key => $attendee) {
+ $attendee = parse_url($attendee);
+ $attendee = $attendee['path'];
+
+ if (isset($params[$key]['CN'])) {
+ $attendee = $params[$key]['CN'];
+ }
+
+ $role = _("Required Participant");
+ if (isset($params[$key]['ROLE'])) {
+ switch ($params[$key]['ROLE']) {
+ case 'CHAIR':
+ $role = _("Chair Person");
+ break;
+
+ case 'OPT-PARTICIPANT':
+ $role = _("Optional Participant");
+ break;
+
+ case 'NON-PARTICIPANT':
+ $role = _("Non Participant");
+ break;
+
+ case 'REQ-PARTICIPANT':
+ default:
+ // Already set above.
+ break;
+ }
+ }
+
+ $status = _("Awaiting Response");
+ if (isset($params[$key]['PARTSTAT'])) {
+ $status = $this->_partstatToString($params[$key]['PARTSTAT'], $status);
+ }
+
+ $html .= '<tr><td>' . htmlspecialchars($attendee) . '</td><td>' . htmlspecialchars($role) . '</td><td>' . htmlspecialchars($status) . '</td></tr>';
+ }
+ $html .= '</tbody></table>';
+ }
+
+ if ($_SESSION['imp']['viewmode'] != 'imp') {
+ return $html;
+ }
+
+ if ($options) {
+ $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
+ '<select name="action[' . $id . ']">' .
+ implode("\n", $options) .
+ '</select> <input type="submit" class="button" value="' . _("Go") . '" />';
+ }
+
+ return $html;
+ }
+
+ /**
+ * Translate the Participation status to string.
+ *
+ * @param string $value The value of PARTSTAT.
+ * @param string $default The value to return as default.
+ *
+ * @return string The translated string.
+ */
+ protected function _partstatToString($value, $default = null)
+ {
+ switch ($value) {
+ case 'ACCEPTED':
+ return _("Accepted");
+ break;
+
+ case 'DECLINED':
+ return _("Declined");
+ break;
+
+ case 'TENTATIVE':
+ return _("Tentatively Accepted");
+ break;
+
+ case 'DELEGATED':
+ return _("Delegated");
+ break;
+
+ case 'COMPLETED':
+ return _("Completed");
+ break;
+
+ case 'IN-PROCESS':
+ return _("In Process");
+ break;
+
+ case 'NEEDS-ACTION':
+ default:
+ return is_null($default) ? _("Needs Action") : $default;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_notification class handles multipart/report
+ * messages that refer to mail notification messages (RFC 2298).
+ *
+ * Copyright 2003-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_notification extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ /* If this is a straight message/disposition-notification part, just
+ output the text. */
+ if ($this->mime_part->getType() == 'message/disposition-notification') {
+ $part = new MIME_Part('text/plain');
+ $part->setContents($this->mime_part->getContents());
+ return '<pre>' . htmlspecialchars($contents->renderMIMEPart($part)) . '</pre>';
+ }
+
+ global $registry;
+
+ /* RFC 2298 [3]: There are three parts to a delivery status
+ multipart/report message:
+ (1) Human readable message
+ (2) Machine parsable body part (message/disposition-notification)
+ (3) Original message (optional) */
+
+ /* Print the human readable message. */
+ $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(1));
+ $status = array(
+ _("A message you have sent has resulted in a return notification from the recipient."),
+ _("The mail server generated the following informational message:")
+ );
+ $statusimg = Horde::img('alerts/message.png', _("Attention"), 'height="16" width="16"', $registry->getImageDir('horde'));
+ $text = $this->formatStatusMsg($status, $statusimg) .
+ '<blockquote>' . $contents->renderMIMEPart($part) . '</blockquote>' . "\n";
+
+ /* Display a link to more detailed message. */
+ $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(2));
+ if ($part) {
+ $statusimg = Horde::img('info_icon.png', _("Info"), 'height="16" width="16"', $registry->getImageDir('horde'));
+ $status = array(sprintf(_("Additional information can be viewed %s."), $contents->linkViewJS($part, 'view_attach', _("HERE"), _("Additional information details"))));
+ }
+
+ /* Display a link to the sent message. Try to download the text of
+ the message/rfc822 part first, if it exists. */
+ if (($part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId('3.0'))) ||
+ ($part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(3)))) {
+ $status[] = sprintf(_("The text of the sent message can be viewed %s."), $contents->linkViewJS($part, 'view_attach', _("HERE"), _("The text of the sent message")));
+ }
+
+ $text .= $this->formatStatusMsg($status, $statusimg, false);
+
+ return $text;
+ }
+
+ /**
+ * Return the content-type.
+ *
+ * @return string The content-type of the message.
+ */
+ public function getType()
+ {
+ return 'text/html; charset=' . NLS::getCharset();
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_partial class allows multipart/partial messages
+ * to be displayed (RFC 2046 [5.2.2]).
+ *
+ * Copyright 2003-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_partial extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ $base_ob = &$contents->getBaseObjectPtr();
+ $curr_index = $base_ob->getMessageIndex();
+ $id = $this->mime_part->getContentTypeParameter('id');
+ $parts = array();
+
+ /* Perform the search to find the other parts of the message. */
+ $query = new Horde_Imap_Client_Search_Query();
+ $query->header('Content-Type', $id);
+
+ $indices = $GLOBALS['imp_search']->runSearchQuery($query, $GLOBALS['imp_mbox']['thismailbox']);
+
+ /* If not able to find the other parts of the message, print error. */
+ if (count($indices) != $this->mime_part->getContentTypeParameter('total')) {
+ return $this->formatStatusMsg(sprintf(_("Cannot display - found only %s of %s parts of this message in the current mailbox."), count($indices), $this->mime_part->getContentTypeParameter('total')));
+ }
+
+ /* Get the contents of each of the parts. */
+ foreach ($indices as $val) {
+ /* No need to fetch the current part again. */
+ if ($val == $curr_index) {
+ $parts[$this->mime_part->getContentTypeParameter('number')] = $this->mime_part->getContents();
+ } else {
+ $imp_contents = &IMP_Contents::singleton($val . IMP::IDX_SEP . $GLOBALS['imp_mbox']['thismailbox']);
+ $part = &$imp_contents->getMIMEPart(0);
+ $parts[$part->getContentTypeParameter('number')] = $imp_contents->getBody();
+ }
+ }
+
+ /* Sort the parts in numerical order. */
+ ksort($parts, SORT_NUMERIC);
+
+ /* Combine the parts and render the underlying data. */
+ $mime_message = &MIME_Message::parseMessage(implode('', $parts));
+ $mc = new MIME_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$contents));
+ $mc->buildMessage();
+
+ return '<table>' . $mc->getMessage(true) . '</table>';
+ }
+
+ /**
+ * Return the content-type of the rendered output.
+ *
+ * @return string The content-type of the output.
+ */
+ public function getType()
+ {
+ return 'text/html; charset=' . NLS::getCharset();
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_pdf class enables generation of thumbnails for
+ * PDF attachments.
+ *
+ * Copyright 2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime_Viewer
+ */
+class IMP_Horde_Mime_Viewer_pdf extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * The content-type of the generated data.
+ *
+ * @var string
+ */
+ protected $_contentType;
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered information.
+ */
+ public function render($params)
+ {
+ /* Create the thumbnail and display. */
+ if (Util::getFormData('images_view_thumbnail')) {
+ $mime = $this->mime_part;
+ $img = $this->_getHordeImageOb();
+
+ if ($img) {
+ $img->resize(96, 96, true);
+ $type = $img->getContentType();
+ $data = $img->raw(true);
+ }
+
+ if (!$img || !$data) {
+ $type = 'image/png';
+ $data = file_get_contents(IMP_BASE . '/themes/graphics/mini-error.png');
+ }
+
+ $mime->setType($type);
+ $this->_contentType = $type;
+ $mime->setContents($data);
+
+ return $mime->getContents();
+ }
+
+ return parent::render($params);
+ }
+
+ /**
+ * Render out attachment information.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function renderAttachmentInfo($params)
+ {
+ $contents = &$params[0];
+
+ if (is_a($contents, 'IMP_Contents')) {
+ $this->mime_part = &$contents->getDecodedMIMEPart($this->mime_part->getMIMEId(), true);
+ }
+
+ /* Check to see if convert utility is available. */
+ if (!$this->_getHordeImageOb(false)) {
+ return '';
+ }
+
+ $status = array(
+ sprintf(_("A PDF file named %s is attached to this message. A thumbnail is below."),
+ $this->mime_part->getName(true)),
+ );
+
+ if (!$GLOBALS['browser']->hasFeature('javascript')) {
+ $status[] = Horde::link($contents->urlView($this->mime_part,
+ 'view_attach')) .
+ Horde::img($contents->urlView($this->mime_part,
+ 'view_attach', array('images_view_thumbnail' => 1), false),
+ _("View Attachment"), null, '') . '</a>';
+ } else {
+ $status[] = $contents->linkViewJS($this->mime_part, 'view_attach',
+ Horde::img($contents->urlView($this->mime_part,
+ 'view_attach', array('images_view_thumbnail' => 1),
+ false), _("View Attachment"), null, ''), null, null,
+ null);
+ }
+
+ return $this->formatStatusMsg($status, Horde::img('mime/image.png',
+ _("Thumbnail of attached PDF file"), null, $GLOBALS['registry']->getImageDir('horde')), false);
+ }
+
+ /**
+ * Return a Horde_Image object.
+ *
+ * @param boolean $load Whether to load the image data.
+ *
+ * @return Horde_Image The requested object.
+ */
+ protected function _getHordeImageOb($load = true)
+ {
+ if (empty($GLOBALS['conf']['image']['convert'])) {
+ return false;
+ }
+
+ include_once 'Horde/Image.php';
+ $img = &Horde_Image::singleton('im', array('temp' => Horde::getTempdir()));
+ if (is_a($img, 'PEAR_Error')) {
+ return false;
+ }
+
+ if ($load) {
+ $ret = $img->loadString(1, $this->mime_part->getContents());
+ if (is_a($ret, 'PEAR_Error')) {
+ return false;
+ }
+ }
+
+ return $img;
+ }
+
+ /**
+ * Return the content-type
+ *
+ * @return string The content-type of the output.
+ */
+ public function getType()
+ {
+ return ($this->_contentType) ? $this->_contentType : parent::getType();
+ }
+}
--- /dev/null
+<?php
+
+require_once IMP_BASE . '/lib/Crypt/PGP.php';
+
+/**
+ * The IMP_Horde_Mime_Viewer_pgp class allows viewing/decrypting of PGP
+ * formatted messages. This class implements RFC 3156.
+ *
+ * This class handles the following MIME types:
+ * application/pgp-encryption
+ * application/pgp-keys
+ * application/pgp-signature
+ *
+ * This class may add the following parameters to the URL:
+ * 'pgp_verify_msg' -- Do verification of PGP signed data.
+ * 'rawpgpkey' -- Display the PGP Public Key in raw, text format
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_pgp extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * IMP_PGP object.
+ *
+ * @var IMP_PGP
+ */
+ protected $_imp_pgp;
+
+ /**
+ * The address of the sender.
+ *
+ * @var string
+ */
+ protected $_address;
+
+ /**
+ * Pointer to the MIME_Contents item.
+ *
+ * @var MIME_Contents
+ */
+ protected $_contents = null;
+
+ /**
+ * Classwide cache for icons for status messages.
+ *
+ * @var string
+ */
+ protected $_icon = null;
+
+ /**
+ * Classwide cache for status messages.
+ *
+ * @var array
+ */
+ protected $_status = array();
+
+ /**
+ * The MIME content-type of this part.
+ *
+ * @var string
+ */
+ protected $_type = 'text/html';
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ global $conf, $prefs;
+
+ /* Set the MIME_Contents class variable. */
+ $this->_contents = &$params[0];
+
+ $msg = '';
+
+ if (empty($this->_imp_pgp) && !empty($conf['utils']['gnupg'])) {
+ $this->_imp_pgp = new IMP_PGP();
+ }
+
+ /* Determine the address of the sender. */
+ if (empty($this->_address)) {
+ $base_ob = &$this->_contents->getBaseObjectPtr();
+ $this->_address = $base_ob->getFromAddress();
+ }
+
+ /* We need to insert JavaScript code now if PGP support is active. */
+ if (!empty($conf['utils']['gnupg']) &&
+ $prefs->getValue('use_pgp') &&
+ !Util::getFormData('rawpgpkey')) {
+ $msg = Util::bufferOutput(array('Horde', 'addScriptFile'), 'prototype.js', 'horde', true);
+ $msg .= Util::bufferOutput(array('Horde', 'addScriptFile'), 'popup.js', 'imp', true);
+ }
+
+ /* For RFC 2015/3156, there are 3 types of messages:
+ + multipart/encrypted
+ + multipart/signed
+ + application/pgp-keys */
+ switch ($this->mime_part->getType()) {
+ case 'application/pgp-keys':
+ $msg .= $this->_outputPGPKey();
+ break;
+
+ case 'multipart/signed':
+ case 'application/pgp-signature':
+ $msg .= $this->_outputPGPSigned();
+ break;
+
+ case 'multipart/encrypted':
+ case 'application/pgp-encrypted':
+ $msg .= $this->_outputPGPEncrypted();
+ break;
+ }
+
+ return $msg;
+ }
+
+ /**
+ * Return the content-type of the output.
+ *
+ * @return string The MIME content type of the output.
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Generates HTML output for 'application/pgp-keys' MIME_Parts.
+ *
+ * @return string The HTML output.
+ */
+ protected function _outputPGPKey()
+ {
+ global $conf, $prefs;
+
+ $mime = &$this->mime_part;
+ $part = $this->_contents->getDecodedMIMEPart($mime->getMIMEId());
+
+ if (empty($conf['utils']['gnupg'])) {
+ $text = '<pre>' . $part->getContents() . '</pre>';
+ } elseif (Util::getFormData('rawpgpkey')) {
+ $text = $part->getContents();
+ $this->_type = 'text/plain';
+ } else {
+ require_once 'Horde/Text.php';
+
+ $pgp_key = $mime->getContents();
+
+ /* Initialize status message. */
+ $this->_initStatus($this->getIcon($mime->getType()), _("PGP"));
+ $msg = _("This PGP Public Key was attached to the message.");
+ if ($prefs->getValue('use_pgp') &&
+ $GLOBALS['registry']->hasMethod('contacts/addField') &&
+ $prefs->getValue('add_source')) {
+ $msg .= ' ' . Horde::link('#', '', '', '', $this->_imp_pgp->savePublicKeyURL($mime) . ' return false;') . _("[Save the key to your Address book]") . '</a>';
+ }
+ $this->_status[] = $msg . ' ' . $this->_contents->linkViewJS($part, 'view_attach', _("[View the raw key]"), '', null, array('rawpgpkey' => 1));
+
+ $text = $this->_outputStatus(false) .
+ '<span class="fixed">' . nl2br(str_replace(' ', ' ', $this->_imp_pgp->pgpPrettyKey($pgp_key))) . '</span>';
+ }
+
+ return $text;
+ }
+
+ /**
+ * Generates HTML output for 'multipart/signed' and
+ * 'application/pgp-signature' MIME_Parts.
+ *
+ * @return string The HTML output.
+ */
+ protected function _outputPGPSigned()
+ {
+ global $conf, $prefs;
+
+ $active = ($prefs->getValue('use_pgp') && !empty($conf['utils']['gnupg']));
+ $mime = &$this->mime_part;
+ $mimetype = $mime->getType();
+ $text = '';
+
+ $signenc = $mime->getInformation('pgp_signenc');
+ if (!$active) {
+ if ($signenc) {
+ $this->_status[] = _("The message below has been digitally signed and encrypted with PGP, but the signature cannot be verified.");
+ } else {
+ $this->_status[] = _("The message below has been digitally signed with PGP, but the signature cannot be verified.");
+ }
+ } else {
+ if ($signenc) {
+ $this->_status[] = _("The message below has been digitally signed and encrypted with PGP.");
+ } else {
+ $this->_status[] = _("The message below has been digitally signed with PGP.");
+ }
+ }
+
+ $this->_initStatus($this->getIcon($mimetype), _("PGP"));
+
+ /* Store PGP results in $sig_result; store text in $data. */
+ $sig_result = null;
+ if ($mimetype == 'multipart/signed') {
+ /* If the MIME ID is 0, we need to store the body of the message
+ in the MIME_Part object. */
+ if (!$signenc) {
+ if (($mimeID = $mime->getMIMEId())) {
+ $mime->setContents($this->_contents->getBodyPart($mimeID));
+ } else {
+ $mime->setContents($this->_contents->getBody());
+ }
+ $mime->splitContents();
+ }
+
+ /* Data that is signed appears in the first MIME subpart. */
+ $subpart = $mime->getPart($mime->getRelativeMIMEId(1));
+ $signature_data = rtrim($subpart->getCanonicalContents(), "\r");
+
+ $mime_message = Horde_Mime_Message::parseMessage($signature_data);
+
+ /* The PGP signature appears in the second MIME subpart. */
+ $subpart = $mime->getPart($mime->getRelativeMIMEId(2));
+ if ($subpart && $subpart->getType() == 'application/pgp-signature') {
+ if ($active) {
+ if ($GLOBALS['prefs']->getValue('pgp_verify') ||
+ Util::getFormData('pgp_verify_msg')) {
+ $subpart->transferDecodeContents();
+ $sig_result = $this->_imp_pgp->verifySignature($signature_data, $this->_address, $subpart->getContents());
+ } elseif (isset($_SESSION['imp']['viewmode']) &&
+ ($_SESSION['imp']['viewmode'] == 'imp')) {
+ // TODO: Fix to work with DIMP
+ $base_ob = &$this->_contents->getBaseObjectPtr();
+ $this->_status[] = Horde::link(Util::addParameter(IMP::generateIMPUrl(Horde::selfUrl(), $GLOBALS['imp_mbox']['mailbox'], $GLOBALS['imp_mbox']['index'], $GLOBALS['imp_mbox']['thismailbox']), 'pgp_verify_msg', 1)) . _("Click HERE to verify the message.") . '</a>';
+ }
+ }
+ } else {
+ $this->_status[] = _("The message below does not appear to be in the correct PGP format (according to RFC 2015).");
+ }
+ } elseif ($mimetype == 'application/pgp-signature') {
+ /* Get the signed message to output. */
+ $mime_message = new Horde_Mime_Message();
+ $mime_message->setType('text/plain');
+ $mime->transferDecodeContents();
+
+ if (empty($this->_imp_pgp)) {
+ $mime_message->setContents($mime->getContents());
+ } else {
+ $mime_message->setContents($this->_imp_pgp->getSignedMessage($mime));
+ }
+
+ /* Pass the signed text straight through to PGP program */
+ if ($active) {
+ if ($GLOBALS['prefs']->getValue('pgp_verify') ||
+ Util::getFormData('pgp_verify_msg')) {
+ $sig_result = $this->_imp_pgp->verifySignature($mime->getContents(), $this->_address);
+ } elseif (isset($_SESSION['imp']['viewmode']) &&
+ ($_SESSION['imp']['viewmode'] == 'imp')) {
+ // TODO: Fix to work with DIMP
+ $this->_status[] = Horde::link(Util::addParameter(Horde::selfUrl(true), 'pgp_verify_msg', 1)) . _("Click HERE to verify the message.") . '</a>';
+ }
+ }
+ }
+
+ $text = $this->_outputStatus();
+
+ if ($sig_result !== null) {
+ $text .= $this->_outputPGPSignatureTest($sig_result);
+ }
+
+ /* We need to stick the output into a MIME_Contents object. */
+ $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$this->_contents));
+ $mc->buildMessage();
+
+ return $text . '<table cellspacing="0">' . $mc->getMessage(true) . '</table>';
+ }
+
+ /**
+ * Generates HTML output for 'multipart/encrypted' and
+ * 'application/pgp-encrypted' MIME_Parts.
+ *
+ * @return string The HTML output.
+ */
+ protected function _outputPGPEncrypted()
+ {
+ global $conf, $prefs;
+
+ $mime = &$this->mime_part;
+ $mimetype = $mime->getType();
+ $text = '';
+
+ $this->_initStatus($this->getIcon($mimetype), _("PGP"));
+
+ /* Print out message now if PGP is not active. */
+ if (empty($conf['utils']['gnupg']) || !$prefs->getValue('use_pgp')) {
+ $this->_status[] = _("The message below has been encrypted with PGP, however, PGP support is disabled so the message cannot be decrypted.");
+ return $this->_outputStatus();
+ }
+
+ if ($mimetype == 'multipart/encrypted') {
+ /* PGP control information appears in the first MIME subpart. We
+ don't currently need to do anything with this information. The
+ encrypted data appears in the second MIME subpart. */
+ $subpart = $mime->getPart($mime->getRelativeMIMEId(2));
+ if (!$subpart) {
+ return $text;
+ }
+ $encrypted_data = $this->_contents->getBodyPart($subpart->getMIMEId());
+ } elseif ($mimetype == 'application/pgp-encrypted') {
+ $encrypted_data = $mime->getContents();
+ } else {
+ return $text;
+ }
+
+ /* Check if this is a literal compressed message. */
+ $info = $this->_imp_pgp->pgpPacketInformation($encrypted_data);
+ $literal = !empty($info['literal']);
+
+ /* Check if this a symmetrically encrypted message. */
+ $symmetric = $this->_imp_pgp->encryptedSymmetrically($encrypted_data);
+
+ if ($symmetric && !$this->_imp_pgp->getSymmetricPassphrase()) {
+ if (isset($_SESSION['imp']['viewmode']) &&
+ ($_SESSION['imp']['viewmode'] == 'imp')) {
+ // TODO: Fix to work with DIMP
+ /* Ask for the correct passphrase if this is encrypted
+ * symmetrically. */
+ $url = $this->_imp_pgp->getJSOpenWinCode('open_symmetric_passphrase_dialog');
+ $this->_status[] = Horde::link('#', _("The message below has been encrypted with PGP. You must enter the passphrase that was used to encrypt this message."), null, null, $url . ' return false;') . _("You must enter the passphrase that was used to encrypt this message.") . '</a>';
+ $text .= $this->_outputStatus() .
+ Util::bufferOutput(array('IMP', 'addInlineScript'), $url);
+ }
+ } elseif (!$literal && !$symmetric &&
+ !$this->_imp_pgp->getPersonalPrivateKey()) {
+ /* Output if there is no personal private key to decrypt with. */
+ $this->_status[] = _("The message below has been encrypted with PGP, however, no personal private key exists so the message cannot be decrypted.");
+ return $this->_outputStatus();
+ } elseif (!$literal && !$symmetric &&
+ !$this->_imp_pgp->getPassphrase()) {
+ if (isset($_SESSION['imp']['viewmode']) &&
+ ($_SESSION['imp']['viewmode'] == 'imp')) {
+ // TODO: Fix to work with DIMP
+ /* Ask for the private key's passphrase if this is encrypted
+ * asymmetrically. */
+ $url = $this->_imp_pgp->getJSOpenWinCode('open_passphrase_dialog');
+ $this->_status[] = Horde::link('#', _("The message below has been encrypted with PGP. You must enter the passphrase for your PGP private key before it can be decrypted."), null, null, $url . ' return false;') . _("You must enter the passphrase for your PGP private key to view this message.") . '</a>';
+ $text .= $this->_outputStatus() .
+ Util::bufferOutput(array('IMP', 'addInlineScript'), $url);
+ }
+ } else {
+ /* Decrypt this message. */
+ $this->_status[] = $literal ? _("The message below has been compressed with PGP.") : _("The message below has been encrypted with PGP.");
+ if ($mimetype == 'multipart/encrypted') {
+ if ($subpart->getType() == 'application/octet-stream') {
+ $decrypted_data = $this->_imp_pgp->decryptMessage($encrypted_data, $symmetric, !$literal);
+ if (is_a($decrypted_data, 'PEAR_Error')) {
+ $this->_status[] = _("The message below does not appear to be a valid PGP encrypted message. Error: ") . $decrypted_data->getMessage();
+ $text .= $this->_outputStatus();
+ } else {
+ /* We need to check if this is a signed/encrypted
+ message. */
+ $mime_message = Horde_Mime_Message::parseMessage($decrypted_data->message);
+ if (!$mime_message) {
+ require_once 'Horde/Text/Filter.php';
+ $text .= $this->_signedOutput($decrypted_data->sig_result);
+ $decrypted_message = String::convertCharset($decrypted_data->message, $subpart->getCharset());
+ $text .= '<span class="fixed">' . Text_Filter::filter($decrypted_message, 'text2html', array('parselevel' => TEXT_HTML_SYNTAX)) . '</span>';
+ } else {
+ $mimetype = $mime_message->getType();
+ if (($mimetype == 'multipart/signed') ||
+ ($mimetype == 'application/pgp-signature')) {
+ $mime_message->setInformation('pgp_signenc', true);
+ $mime_message->setContents($decrypted_data->message);
+ $mime_message->splitContents();
+ } else {
+ $text .= $this->_signedOutput($decrypted_data->sig_result);
+ }
+
+ /* We need to stick the output into a
+ MIME_Contents object. */
+ $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$this->_contents));
+ $mc->buildMessage();
+ if ($mime_message->getInformation('pgp_signenc')) {
+ $text .= $mc->getMessage(true);
+ } else {
+ $text .= '<table cellspacing="0">' . $mc->getMessage(true) . '</table>';
+ }
+ }
+ }
+ } else {
+ $this->_status[] = _("The message below does not appear to be in the correct PGP format (according to RFC 2015).");
+ $text .= $this->_outputStatus();
+ }
+ } elseif ($mimetype == 'application/pgp-encrypted') {
+ $decrypted_data = $this->_imp_pgp->decryptMessage($encrypted_data, $symmetric, !$literal);
+ if (is_a($decrypted_data, 'PEAR_Error')) {
+ $decrypted_message = $decrypted_data->getMessage();
+ $text .= $this->_outputStatus();
+ } else {
+ $text .= $this->_signedOutput($decrypted_data->sig_result);
+ $decrypted_message = String::convertCharset($decrypted_data->message, $mime->getCharset());
+ }
+
+ require_once 'Horde/Text/Filter.php';
+ $text .= '<span class="fixed">' . Text_Filter::filter($decrypted_message, 'text2html', array('parselevel' => TEXT_HTML_SYNTAX)) . '</span>';
+ }
+ }
+ $this->_imp_pgp->unsetSymmetricPassphrase();
+
+ return $text;
+ }
+
+ /**
+ * Generates HTML output for the PGP signature test.
+ *
+ * @param string $result Result string of the PGP output concerning the
+ * signature test.
+ *
+ * @return string The HTML output.
+ */
+ protected function _outputPGPSignatureTest($result)
+ {
+ $text = '';
+
+ if (is_a($result, 'PEAR_Error')) {
+ $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/error.png', _("Error"));
+ $result = $result->getMessage();
+ } else {
+ $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/success.png', _("Success"));
+ /* This message has been verified but there was no output from the
+ PGP program. */
+ if (empty($result)) {
+ $result = _("The message below has been verified.");
+ }
+ }
+
+ require_once 'Horde/Text/Filter.php';
+ $this->_status[] = Text_Filter::filter($result, 'text2html', array('parselevel' => TEXT_HTML_NOHTML));
+
+ return $this->_outputStatus();
+ }
+
+ /**
+ * Output signed message status.
+ *
+ * @param string $result The signature result.
+ *
+ * @return string HTML output.
+ */
+ protected function _signedOutput($result)
+ {
+ if (!empty($result)) {
+ return $this->_outputPGPSignatureTest($result);
+ } else {
+ return $this->_outputStatus();
+ }
+ }
+
+ /* Various formatting helper functions */
+ protected function _initStatus($src, $alt = '')
+ {
+ if ($this->_icon === null) {
+ $this->_icon = Horde::img($src, $alt, 'height="16" width="16"', '');
+ }
+ }
+
+ protected function _outputStatus($printable = true)
+ {
+ $output = '';
+ if (!empty($this->_status)) {
+ $output = $this->formatStatusMsg($this->_status, $this->_icon, $printable);
+ }
+ $this->_icon = null;
+ $this->_status = array();
+ return $output;
+ }
+}
--- /dev/null
+<?php
+
+require_once IMP_BASE . '/lib/Crypt/SMIME.php';
+
+/**
+ * The IMP_Horde_Mime_Viewer_pkcs7 class allows viewing/decrypting of S/MIME
+ * messages.
+ * This class implements parts of RFC 2630, RFC 2632, and RFC 2633.
+ *
+ * This class handles the following MIME types:
+ * application/pkcs7-mime
+ * application/pkcs7-signature
+ * application/x-pkcs7-mime
+ * application/x-pkcs7-signature
+ *
+ * This class may add the following parameters to the URL:
+ * 'smime_verify_msg' -- Do verification of S/MIME signed data.
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Mike Cochrane <mike@graftonhall.co.nz>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime_Viewer
+ */
+class IMP_Horde_Mime_Viewer_pkcs7 extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * IMP_SMIME object.
+ *
+ * @var IMP_SMIME
+ */
+ protected $_impSmime;
+
+ /**
+ * Classwide cache for icons for status messages.
+ *
+ * @var string
+ */
+ protected $_icon = null;
+
+ /**
+ * Pointer to the IMP_Contents item.
+ *
+ * @var IMP_Contents
+ */
+ protected $_contents = null;
+
+ /**
+ * Classwide cache for status messages.
+ *
+ * @var array
+ */
+ protected $_status = array();
+
+ /**
+ * The MIME_Headers object for the message data.
+ *
+ * @var MIME_Headers
+ */
+ protected $_headers;
+
+ /**
+ * Some mailers set S/MIME messages to always be attachments. However,
+ * most of the time S/MIME is used to secure the contents of the message,
+ * so displaying as an attachment makes no sense. Therefore, force
+ * viewing inline (or at least let Horde_Mime_Viewer/IMP_Contents make the
+ * determination on whether the data can be viewed inline or not).
+ *
+ * @var boolean
+ */
+ protected $_forceinline = true;
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a IMP_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ /* Set the IMP_Contents class variable. */
+ $this->_contents = &$params[0];
+
+ $msg = '';
+
+ if (empty($this->_impSmime)) {
+ $this->_impSmime = new IMP_SMIME();
+ }
+
+ /* Check to see if S/MIME support is available. */
+ $openssl_check = $this->_impSmime->checkForOpenSSL();
+ if ($GLOBALS['prefs']->getValue('use_smime') &&
+ !is_a($openssl_check, 'PEAR_Error')) {
+ /* We need to insert JavaScript code now if S/MIME support is
+ active. */
+ $msg = Util::bufferOutput(array('Horde', 'addScriptFile'), 'prototype.js', 'horde', true);
+ $msg .= Util::bufferOutput(array('Horde', 'addScriptFile'), 'popup.js', 'imp', true);
+ }
+
+ /* Get the type of message now. */
+ $type = $this->_getSMIMEType();
+ switch ($type) {
+ case 'signed':
+ $msg .= $this->_outputSMIMESigned();
+ break;
+
+ case 'encrypted':
+ $msg .= $this->_outputSMIMEEncrypted();
+ break;
+ }
+
+ return $msg;
+ }
+
+ /**
+ * Generates HTML output for the S/MIME key in
+ * 'application/pkcs7-signature' MIME_Parts.
+ *
+ * @return string The HTML output.
+ */
+ protected function _outputSMIMEKey()
+ {
+ if (!$GLOBALS['prefs']->getValue('use_smime')) {
+ return _("S/MIME support is not enabled.");
+ } else {
+ $mime = &$this->mime_part;
+ $signenc = $mime->getInformation('smime_signenc');
+ $raw_text = $this->_getRawSMIMEText();
+ if ($signenc && $mime->getInformation('smime_from')) {
+ $smime_from = $mime->getInformation('smime_from');
+ $raw_text = "From: $smime_from\n" . $raw_text;
+ }
+ $sig_result = $this->_impSmime->verifySignature($raw_text);
+ return $this->_impSmime->certToHTML($sig_result->cert);
+ }
+ }
+
+ /**
+ * Generates HTML output for 'multipart/signed',
+ * 'application/pkcs7-signature' and
+ * 'application/x-pkcs7-signature' MIME_Parts.
+ *
+ * @return string The HTML output.
+ */
+ protected function _outputSMIMESigned()
+ {
+ if (Util::getFormData('viewkey')) {
+ return $this->_outputSMIMEKey();
+ }
+
+ $cert = $text = '';
+ $mime = &$this->mime_part;
+ $mimetype = $mime->getType();
+ $active = $GLOBALS['prefs']->getValue('use_smime');
+
+ $signenc = $mime->getInformation('smime_signenc');
+ if ($signenc) {
+ $this->_status[] = _("This message has been encrypted via S/MIME.");
+ }
+
+ $this->_initStatus($this->getIcon($mimetype), _("S/MIME"));
+ $this->_status[] = _("This message has been digitally signed via S/MIME.");
+
+ if (!$active) {
+ $this->_status[] = _("S/MIME support is not enabled so the digital signature is unable to be verified.");
+ }
+
+ /* Store S/MIME results in $sig_result. */
+ $sig_result = null;
+ if ($mimetype == 'multipart/signed') {
+ if (!$signenc) {
+ if (($mimeID = $mime->getMIMEId())) {
+ $mime->setContents($this->_contents->getBodyPart($mimeID));
+ } else {
+ $mime->setContents($this->_contents->getBody());
+ }
+ $mime->splitContents();
+ }
+
+ /* Data that is signed appears in the first MIME subpart. */
+ $signed_part = $mime->getPart($mime->getRelativeMIMEId(1));
+ $signed_data = rtrim($signed_part->getCanonicalContents(), "\r");
+ $mime_message = Horde_Mime_Message::parseMessage($signed_data);
+
+ /* The S/MIME signature appears in the second MIME subpart. */
+ $subpart = $mime->getPart($mime->getRelativeMIMEId(2));
+ if (!$subpart ||
+ !in_array($subpart->getType(), array('application/pkcs7-signature', 'application/x-pkcs7-signature'))) {
+ $this->_status[] = _("This message does not appear to be in the correct S/MIME format.");
+ }
+ } elseif (!$active) {
+ $this->_status[] = _("S/MIME support is not enabled so the contents of this signed message cannot be displayed.");
+ }
+
+ if ($active) {
+ $raw_text = $this->_getRawSMIMEText();
+ if ($signenc && $mime->getInformation('smime_from')) {
+ $smime_from = $mime->getInformation('smime_from');
+ $raw_text = "From: $smime_from\n" . $raw_text;
+ }
+
+ if ($GLOBALS['prefs']->getValue('smime_verify') ||
+ Util::getFormData('smime_verify_msg')) {
+ $sig_result = $this->_impSmime->verifySignature($raw_text);
+ } elseif (isset($_SESSION['imp']['viewmode']) &&
+ ($_SESSION['imp']['viewmode'] == 'imp')) {
+ // TODO: Fix to work with DIMP
+ $this->_status[] = Horde::link(Util::addParameter(Horde::selfUrl(true), 'smime_verify_msg', 1)) . _("Click HERE to verify the message.") . '</a>';
+ }
+
+ if (!isset($subpart)) {
+ $msg_data = $this->_impSmime->extractSignedContents($raw_text);
+ if (is_a($msg_data, 'PEAR_Error')) {
+ $this->_status[] = $msg_data->getMessage();
+ $mime_message = $mime;
+ } else {
+ $mime_message = Horde_Mime_Message::parseMessage($msg_data);
+ }
+ }
+
+ $text = $this->_outputStatus();
+ if ($sig_result !== null) {
+ $text .= $this->_outputSMIMESignatureTest($sig_result->result, $sig_result->email);
+ if (!empty($sig_result->cert)) {
+ $cert_details = $this->_impSmime->parseCert($sig_result->cert);
+ if (isset($cert_details['certificate']['subject']['CommonName'])) {
+ $subject = $cert_details['certificate']['subject']['CommonName'];
+ } elseif (isset($cert_details['certificate']['subject']['Email'])) {
+ $subject = $cert_details['certificate']['subject']['Email'];
+ } elseif (isset($sig_result->email)) {
+ $subject = $sig_result->email;
+ } elseif (isset($smime_from)) {
+ $subject = $smime_from;
+ } elseif (($from = $this->_headers->getValue('from'))) {
+ $subject = $from;
+ } else {
+ $subject = null;
+ }
+ if (isset($subpart) &&
+ !empty($subject) &&
+ $GLOBALS['registry']->hasMethod('contacts/addField') &&
+ $GLOBALS['prefs']->getValue('add_source')) {
+ $this->_status[] = sprintf(_("The S/MIME certificate of %s: "), @htmlspecialchars($subject, ENT_COMPAT, NLS::getCharset())) .
+ $this->_contents->linkViewJS($subpart, 'view_attach', _("View"), '', null, array('viewkey' => 1)) . '/' .
+ Horde::link('#', '', null, null, $this->_impSmime->savePublicKeyURL($sig_result->cert) . ' return false;') . _("Save in your Address Book") . '</a>';
+ $text .= $this->_outputStatus();
+ }
+ }
+ }
+ }
+
+ if (isset($mime_message)) {
+ /* We need to stick the output into a IMP_Contents object. */
+ $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$this->_contents));
+ $mc->buildMessage();
+
+ $text .= '<table cellpadding="0" cellspacing="0">' . $mc->getMessage(true) . '</table>';
+ } else {
+ $text = $this->_outputStatus();
+ }
+
+ return $text;
+ }
+
+ /**
+ * Generates HTML output for 'multipart/encrypted',
+ * 'application/pkcs7-mime' and
+ * 'application/x-pkcs7-mime' MIME_Parts.
+ *
+ * @return string The HTML output.
+ */
+ protected function _outputSMIMEEncrypted()
+ {
+ $active = $GLOBALS['prefs']->getValue('use_smime');
+ $mime = &$this->mime_part;
+ $mimetype = $mime->getType();
+ $msg = '';
+
+ $this->_initStatus($this->getIcon($mime->getType()), _("S/MIME"));
+ $this->_status[] = _("This message has been encrypted via S/MIME.");
+
+ if (!$active) {
+ $this->_status[] = _("S/MIME support is not currently enabled so the message is unable to be decrypted.");
+ return $this->_outputStatus();
+ }
+
+ if (!$this->_impSmime->getPersonalPrivateKey()) {
+ $this->_status[] = _("No personal private key exists so the message is unable to be decrypted.");
+ return $this->_outputStatus();
+ }
+
+ /* Make sure we have a passphrase. */
+ $passphrase = $this->_impSmime->getPassphrase();
+ if ($passphrase === false) {
+ if (isset($_SESSION['imp']['viewmode']) &&
+ ($_SESSION['imp']['viewmode'] == 'imp')) {
+ // TODO: Fix to work with DIMP
+ $url = $this->_impSmime->getJSOpenWinCode('open_passphrase_dialog');
+ $this->_status[] = Horde::link('#', _("You must enter the passphrase for your S/MIME private key to view this message"), null, null, $url . ' return false;') . '<em>' . _("You must enter the passphrase for your S/MIME private key to view this message") . '</em></a>.';
+ $msg .= $this->_outputStatus() .
+ '<script type="text/javascript">' . $url . ';</script>';
+ }
+ return $msg;
+ }
+
+ $raw_text = $this->_getRawSMIMEText();
+ $decrypted_data = $this->_impSmime->decryptMessage($raw_text);
+
+ if (is_a($decrypted_data, 'PEAR_Error')) {
+ $this->_status[] = $decrypted_data->getMessage();
+ return $this->_outputStatus();
+ }
+
+ /* We need to check if this is a signed/encrypted message. */
+ $mime_message = Horde_Mime_Message::parseMessage($decrypted_data);
+ if ($mime_message) {
+ /* Check for signed and encoded data. */
+ if (in_array($mime_message->getType(), array('multipart/signed', 'application/pkcs7-mime', 'application/x-pkcs7-mime'))) {
+ $mime_message->setContents($decrypted_data);
+ $mime_message->splitContents();
+ $mime_message->setInformation('smime_signenc', true);
+ if (($from = $this->_headers->getValue('from'))) {
+ $mime_message->setInformation('smime_from', $from);
+ }
+ } else {
+ $msg .= $this->_outputStatus();
+ }
+
+ /* We need to stick the output into a IMP_Contents object. */
+ $mc = new IMP_Contents($mime_message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$this->_contents));
+ $mc->buildMessage();
+ $msg .= '<table cellpadding="0" cellspacing="0">' . $mc->getMessage(true) . '</table>';
+ } else {
+ require_once 'Horde/Text/Filter.php';
+ $msg .= $this->_outputStatus() .
+ '<span class="fixed">' . Text_Filter::filter($decrypted_data, 'text2html', array('parselevel' => TEXT_HTML_SYNTAX)) . '</span>';
+ }
+
+ return $msg;
+ }
+
+ /**
+ * Return text/html as the content-type.
+ *
+ * @return string "text/html" constant.
+ */
+ public function getType()
+ {
+ return 'text/html; charset=' . NLS::getCharset();
+ }
+
+ /**
+ * Get the headers of the S/MIME message.
+ */
+ protected function _getRawSMIMEText()
+ {
+ $mime = &$this->mime_part;
+
+ $mime->setContents($this->_contents->getBody());
+ if (is_a($this->_contents, 'IMP_Contents') &&
+ (($mime->getMIMEId() == 0) ||
+ ($mime->splitContents() == false))) {
+ $this->_headers = $this->_contents->getHeaderOb();
+ return $this->_contents->fullMessageText();
+ } else {
+ $header_text = $mime->getCanonicalContents();
+ $header_text = substr($header_text, 0, strpos($header_text, "\r\n\r\n"));
+ $this->_headers = MIME_Headers::parseHeaders($header_text);
+
+ $mime_headers = new MIME_Headers();
+ foreach (array('Content-Type', 'From', 'To') as $val) {
+ $tmp = $this->_headers->getValue($val);
+ if (!empty($tmp)) {
+ $mime_headers->addHeader($val, $tmp);
+ }
+ }
+
+ return $mime_headers->toString() . $mime->toCanonicalString();
+ }
+ }
+
+ /* Various formatting helper functions. */
+ protected function _initStatus($src, $alt = '')
+ {
+ if ($this->_icon === null) {
+ $this->_icon = Horde::img($src, $alt, 'height="16" width="16"', '');
+ }
+ }
+
+ protected function _outputStatus()
+ {
+ $output = '';
+ if (!empty($this->_status)) {
+ $output = $this->formatStatusMsg($this->_status, $this->_icon);
+ }
+ $this->_icon = null;
+ $this->_status = array();
+ return $output;
+ }
+
+ /**
+ * Generates HTML output for the S/MIME signature test.
+ *
+ * @param string $result Result string of the S/MIME output concerning
+ * the signature test.
+ * @param string $email The email of the sender.
+ *
+ * @return string The HTML output.
+ */
+ protected function _outputSMIMESignatureTest($result, $email)
+ {
+ $text = '';
+
+ if (is_a($result, 'PEAR_Error')) {
+ if ($result->getCode() == 'horde.warning') {
+ $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/warning.png', _("Warning"));
+ } else {
+ $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/error.png', _("Error"));
+ }
+ $result = $result->getMessage();
+ } else {
+ $this->_initStatus($GLOBALS['registry']->getImageDir('horde') . '/alerts/success.png', _("Success"));
+ /* This message has been verified but there was no output
+ from the PGP program. */
+ if (empty($result) || ($result === true)) {
+ $email = (is_array($email)) ? implode(', ', $email): $email;
+ $result = sprintf(_("The message has been verified. Sender: %s."), htmlspecialchars($email));
+ }
+ }
+
+ require_once 'Horde/Text/Filter.php';
+
+ $this->_status[] = Text_Filter::filter($result, 'text2html', array('parselevel' => TEXT_HTML_NOHTML));
+
+ return $this->_outputStatus();
+ }
+
+ /**
+ * Render out attachment information.
+ *
+ * @param array $params An array with a reference to a IMP_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function renderAttachmentInfo($params)
+ {
+ $this->_contents = &$params[0];
+
+ $type = $this->_getSMIMEType();
+ switch ($type) {
+ case 'signed':
+ $this->_status[] = _("This message contains an attachment that has been digitally signed via S/MIME.");
+ break;
+
+ case 'encrypted':
+ $this->_status[] = _("This message contains an attachment that has been encrypted via S/MIME.");
+ break;
+ }
+
+ $this->_status[] = sprintf(_("Click %s to view the attachment in a separate window."), $this->_contents->linkViewJS($this->mime_part, 'view_attach', _("HERE"), _("View attachment in a separate window")));
+ $this->_initStatus($this->getIcon($this->mime_part->getType()), _("S/MIME"));
+ return $this->_outputStatus();
+ }
+
+ /**
+ * Deterimne the S/MIME type of the message.
+ *
+ * @return string Either 'encrypted' or 'signed'.
+ */
+ protected function _getSMIMEType()
+ {
+ $type = $this->mime_part->getType();
+ if (in_array($type, array('application/pkcs7-mime', 'application/x-pkcs7-mime'))) {
+ $smime_type = $this->mime_part->getContentTypeParameter('smime-type');
+ if ($smime_type == 'signed-data') {
+ return 'signed';
+ } elseif (!$smime_type || ($smime_type == 'enveloped-data')) {
+ return 'encrypted';
+ }
+ }
+
+ switch ($type) {
+ case 'multipart/signed':
+ case 'application/pkcs7-signature':
+ case 'application/x-pkcs7-signature':
+ return 'signed';
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_plain class renders out text/plain MIME parts
+ * with URLs made into hyperlinks.
+ *
+ * Copyright 1999-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime_Viewer
+ */
+class IMP_Horde_Mime_Viewer_plain extends Horde_Mime_Viewer_plain
+{
+ /**
+ * TODO
+ */
+ protected function _renderInline()
+ {
+ global $conf, $prefs;
+
+ // Trim extra whitespace in the text.
+ $text = rtrim($this->_mimepart->getContents());
+ if ($text == '') {
+ return array(
+ 'data' => '',
+ 'status' => array()
+ );
+ }
+
+ // If requested, scan the message for PGP data.
+ if (!empty($conf['utils']['gnupg']) &&
+ $prefs->getValue('pgp_scan_body') &&
+ preg_match('/-----BEGIN PGP ([^-]+)-----/', $text)) {
+ require_once IMP_BASE . '/lib/Crypt/PGP.php';
+ $imp_pgp = new IMP_PGP();
+ if (($out = $imp_pgp->parseMessageOutput($this->_mimepart, $this->_params['contents']))) {
+ return array(
+ 'data' => $out,
+ 'status' => array()
+ );
+ }
+ }
+
+ // Check for 'flowed' text data.
+ if ($this->_mimepart->getContentTypeParameter('format') == 'flowed') {
+ $text = $this->_formatFlowed($text, $this->_mimepart->getContentTypeParameter('delsp'));
+ } else {
+ /* A "From" located at the beginning of a line in the body text
+ * will be escaped with a '>' by the IMAP server. Remove this
+ * escape character or else the line will display as being
+ * quoted. Flowed conversion would have already taken care of this
+ * for us. */
+ $text = preg_replace('/(\n+)> ?From(\s+)/', "$1From$2", $text);
+ }
+
+ // Build filter stack. Starts with HTML markup and tab expansion.
+ require_once 'Horde/Text/Filter.php';
+ $filters = array(
+ 'text2html' => array(
+ 'parselevel' => TEXT_HTML_MICRO,
+ 'charset' => $this->_mimepart->getCharset()
+ ),
+ 'tabs2spaces' => array()
+ );
+
+ // Highlight quoted parts of an email.
+ if ($prefs->getValue('highlight_text')) {
+ $show = $prefs->getValue('show_quoteblocks');
+ $hideBlocks = ($show == 'hidden') ||
+ (($show == 'thread') && (basename(Horde::selfUrl()) == 'thread.php'));
+ if (!$hideBlocks && in_array($show, array('list', 'listthread'))) {
+ $header = $this->_params['contents']->getHeaderOb();
+ $imp_ui = new IMP_UI_Message();
+ $list_info = $imp_ui->getListInformation($header);
+ $hideBlocks = $list_info['exists'];
+ }
+ $filters['highlightquotes'] = array('hideBlocks' => $hideBlocks);
+ }
+
+ // Highlight simple markup of an email.
+ if ($prefs->getValue('highlight_simple_markup')) {
+ $filters['simplemarkup'] = array();
+ }
+
+ // Dim signatures.
+ if ($prefs->getValue('dim_signature')) {
+ $filters['dimsignature'] = array();
+ }
+
+ // Filter bad language.
+ if ($prefs->getValue('filtering')) {
+ $filters['words'] = array(
+ 'words_file' => $conf['msgsettings']['filtering']['words'],
+ 'replacement' => $conf['msgsettings']['filtering']['replacement']
+ );
+ }
+
+ // Run filters.
+ $text = Text_Filter::filter($text, array_keys($filters), array_values($filters));
+
+ // Wordwrap.
+ $text = str_replace(array(' ', "\n "), array(' ', "\n "), $text);
+ if (!strncmp($text, ' ', 1)) {
+ $text = ' ' . substr($text, 1);
+ }
+
+ return array(
+ 'data' => '<div class="fixed leftAlign">' . "\n" . $text . '</div>',
+ 'status' => array()
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_related class handles multipart/related messages
+ * as defined by RFC 2387.
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_related extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * The character set of the rendered HTML part.
+ *
+ * @var string
+ */
+ protected $_charset = null;
+
+ /**
+ * The mime type of the message part that has been chosen to be displayed.
+ *
+ * @var string
+ */
+ protected $_viewerType = 'text/html';
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ /* Look at the 'start' parameter to determine which part to start
+ with. If no 'start' parameter, use the first part.
+ RFC 2387 [3.1] */
+ if ($this->mime_part->getContentTypeParameter('start') &&
+ ($key = array_search($this->mime_part->getContentTypeParameter('start'), $this->mime_part->getCIDList()))) {
+ if (($pos = strrpos($key, '.'))) {
+ $id = substr($key, $pos + 1);
+ } else {
+ $id = $key;
+ }
+ } else {
+ $id = 1;
+ }
+ $start = $this->mime_part->getPart($this->mime_part->getRelativeMimeID($id));
+
+ /* Only display if the start part (normally text/html) can be displayed
+ inline -OR- we are viewing this part as an attachment. */
+ if ($contents->canDisplayInline($start) ||
+ $this->viewAsAttachment()) {
+ $text = $contents->renderMIMEPart($start);
+ $this->_viewerType = $contents->getMIMEViewerType($start);
+ $this->_charset = $start->getCharset();
+ } else {
+ $text = '';
+ }
+
+ return $text;
+ }
+
+ /**
+ * Render out attachment information.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function renderAttachmentInfo($params)
+ {
+ $contents = &$params[0];
+
+ $msg = sprintf(_("Click %s to view this multipart/related part in a separate window."), $contents->linkViewJS($this->mime_part, 'view_attach', _("HERE"), _("View content in a separate window")));
+ return $this->formatStatusMsg($msg, Horde::img('mime/html.png', _("HTML")), false);
+ }
+
+ /**
+ * Return the content-type.
+ *
+ * @return string The content-type of the message.
+ */
+ public function getType()
+ {
+ return $this->_viewerType . '; charset=' . $this->getCharset();
+ }
+
+ /**
+ * Returns the character set used for the Viewer.
+ *
+ * @return string The character set used by this Viewer.
+ */
+ public function getCharset()
+ {
+ return ($this->_charset === null) ? NLS::getCharset() : $this->_charset;
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_rfc822 class renders out messages from
+ * message/rfc822 content types.
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_rfc822 extends Horde_Mime_Viewer_rfc822
+{
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ /* Get the entire body part of the message/rfc822 contents. */
+ if (!$this->mime_part->getInformation('imp_contents_set') &&
+ is_a($contents, 'IMP_Contents') &&
+ $this->mime_part->getMIMEId()) {
+ $this->mime_part = &$contents->getDecodedMIMEPart($this->mime_part->getMIMEId(), true);
+ }
+
+ return parent::render();
+ }
+
+ /**
+ * Render out attachment information.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function renderAttachmentInfo($params)
+ {
+ $contents = &$params[0];
+
+ if (is_a($contents, 'IMP_Contents') &&
+ !$this->mime_part->getContents()) {
+ $id = $this->mime_part->getMIMEId();
+ $hdr_id = substr($id, -2);
+ if ($hdr_id != '.0') {
+ $id .= '.0';
+ }
+ $this->mime_part = &$contents->getDecodedMIMEPart($id);
+ }
+
+ return parent::renderAttachmentInfo();
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_smil renders SMIL documents to very basic HTML.
+ *
+ * Copyright 2006-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Jan Schneider <jan@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_smil extends Horde_Mime_Viewer_smil
+{
+ /**
+ * The MIME_Contents object, needed for the _callback() function.
+ *
+ * @var MIME_Contents
+ */
+ protected $_contents;
+
+ /**
+ * The list of related parts to the current part.
+ *
+ * @var array
+ */
+ protected $_related = null;
+
+ /**
+ * Renders out the contents.
+ *
+ * @param array $params Any parameters the Viewer may need.
+ *
+ * @return string The rendered contents.
+ */
+ public function render($params)
+ {
+ $this->_contents = &$params[0];
+ return parent::render($params);
+ }
+
+ /**
+ * User-defined function callback for start elements.
+ *
+ * @param object $parser Handle to the parser instance.
+ * @param string $name The name of this XML element.
+ * @param array $attrs List of this element's attributes.
+ */
+ protected function _startElement($parser, $name, $attrs)
+ {
+ switch ($name) {
+ case 'IMG':
+ if (isset($attrs['SRC'])) {
+ $rp = $this->_getRelatedLink($attrs['SRC']);
+ if ($rp !== false) {
+ $this->_content .= '<img src="' . $this->_contents->urlView($rp, 'view_attach') . '" alt="" /><br />';
+ }
+ }
+ break;
+
+ case 'TEXT':
+ if (isset($attrs['SRC'])) {
+ $rp = $this->_getRelatedLink($attrs['SRC']);
+ if ($rp !== false) {
+ $this->_content .= htmlspecialchars($rp->getContents()) . '<br />';
+ }
+ }
+ break;
+ }
+ }
+
+ /**
+ * Get related parts.
+ *
+ * @param string $cid The CID to search for.
+ *
+ * @return mixed Either the related MIME_Part or false.
+ */
+ protected function _getRelatedLink($cid)
+ {
+ if ($this->_related === null) {
+ $this->_related = false;
+ $related = $this->mime_part->getInformation('related_part');
+ if ($related !== false) {
+ $relatedPart = $this->_contents->getMIMEPart($related);
+ $this->_related = $relatedPart->getCIDList();
+ }
+ }
+
+ if ($this->_related) {
+ $key = array_search('<' . $cid . '>', $this->_related);
+ if ($key !== false) {
+ $cid_part = $this->_contents->getDecodedMIMEPart($key);
+ return $cid_part;
+ }
+ }
+
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_status class handles multipart/report messages
+ * that refer to mail system administrative messages (RFC 3464).
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_status extends Horde_Mime_Viewer_Driver
+{
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ /* If this is a straight message/delivery-status part, just output
+ the text. */
+ if ($this->mime_part->getType() == 'message/delivery-status') {
+ $part = new Horde_Mime_Part('text/plain');
+ $part->setContents($this->mime_part->getContents());
+ return '<pre>' . $contents->renderMIMEPart($part) . '</pre>';
+ }
+
+ global $registry;
+
+ /* RFC 3464 [2]: There are three parts to a delivery status
+ multipart/report message:
+ (1) Human readable message
+ (2) Machine parsable body part (message/delivery-status)
+ (3) Returned message (optional)
+
+ Information on the message status is found in the 'Action' field
+ located in part #2 (RFC 2464 [2.3.3]). It can be either 'failed',
+ 'delayed', 'delivered', 'relayed', or 'expanded'. */
+ $action = null;
+ $part2 = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(2));
+ if (empty($part2)) {
+ return $this->_errorMsg($contents);
+ }
+
+ foreach (explode("\n", $part2->getContents()) as $line) {
+ if (strstr($line, 'Action:') !== false) {
+ $pos = strpos($line, ':') + 1;
+ $action = strtolower(trim(substr($line, $pos)));
+ break;
+ }
+ }
+ if (strpos($action, ' ') !== false) {
+ $action = substr($action, 0, strpos($action, ' '));
+ }
+
+ /* Get the correct text strings for the action type. */
+ switch ($action) {
+ case 'failed':
+ case 'delayed':
+ $graphic = 'alerts/error.png';
+ $alt = _("Error");
+ $msg = array(
+ _("ERROR: Your message could not be delivered."),
+ _("The mail server generated the following error message:")
+ );
+ $detail_msg = _("Additional message error details can be viewed %s.");
+ $detail_msg_status = _("Additional message error details");
+ $msg_link = _("The text of the returned message can be viewed %s.");
+ $msg_link_status = _("The text of the returned message");
+ break;
+
+ case 'delivered':
+ case 'expanded':
+ case 'relayed':
+ $graphic = 'alerts/success.png';
+ $alt = _("Success");
+ $msg = array(
+ _("Your message was successfully delivered."),
+ _("The mail server generated the following message:")
+ );
+ $detail_msg = _("Additional message details can be viewed %s.");
+ $detail_msg_status = _("Additional message details");
+ $msg_link = _("The text of the message can be viewed %s.");
+ $msg_link_status = _("The text of the message");
+ break;
+
+ default:
+ $graphic = '';
+ $alt = '';
+ $msg = '';
+ $detail_msg = '';
+ $detail_msg_status = '';
+ $msg_link = '';
+ $msg_link_status = '';
+ }
+
+ /* Print the human readable message. */
+ $part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(1));
+ if (empty($part)) {
+ return $this->_errorMsg($contents);
+ }
+
+ $statusimg = Horde::img($graphic, $alt, 'height="16" width="16"', $registry->getImageDir('horde'));
+ $text = $this->formatStatusMsg($msg, $statusimg);
+ $text .= '<blockquote>' . $contents->renderMIMEPart($part) . '</blockquote>' . "\n";
+
+ /* Display a link to more detailed error message. */
+ $detailed_msg = array(
+ sprintf($detail_msg, $contents->linkViewJS($part2, 'view_attach', _("HERE"), $detail_msg_status))
+ );
+
+ /* Display a link to the returned message. Try to download the
+ text of the message/rfc822 part first, if it exists.
+ TODO: Retrieving by part ID 3.0 is deprecated. Remove this once
+ Horde 4.0 is released. */
+ if (($part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId(3))) ||
+ ($part = $contents->getDecodedMIMEPart($this->mime_part->getRelativeMIMEId('3.0')))) {
+ $detailed_msg[] = sprintf($msg_link, $contents->linkViewJS($part, 'view_attach', _("HERE"), $msg_link_status, null, array('ctype' => 'message/rfc822')));
+ }
+
+ $infoimg = Horde::img('info_icon.png', _("Info"), 'height="16" width="16"', $registry->getImageDir('horde'));
+ $text .= $this->formatStatusMsg($detailed_msg, $infoimg, false);
+
+ return $text;
+ }
+
+
+ /**
+ * Return the content-type.
+ *
+ * @return string The content-type of the message.
+ */
+ public function getType()
+ {
+ return 'text/html; charset=' . NLS::getCharset();
+ }
+
+ /**
+ * Returns an error string for a malformed RFC 3464 message.
+ *
+ * @param MIME_Contents &$contents The MIME_Contents object for this
+ * message.
+ *
+ * @return string The error message string.
+ */
+ protected function _errorMsg(&$contents)
+ {
+ $err_msg = array(
+ _("This message contains mail delivery status information, but the format of this message is unknown."),
+ _("Below is the raw text of the status information message.")
+ );
+ $img = Horde::img('alerts/error.png', _("Error"), 'height="16" width="16"', $GLOBALS['registry']->getImageDir('horde'));
+
+ $text = $this->formatStatusMsg($err_msg, $img);
+
+ /* There is currently no BC way to obtain all parts from a message
+ * and display the summary of each part. So instead, display the
+ * entire raw contents of the message. See Bug 3757. */
+ $text .= '<pre>';
+ if (is_a($contents, 'IMP_Contents')) {
+ $contents->rebuildMessage();
+ $message = $contents->getMIMEMessage();
+ $text .= $contents->toString($message, true);
+ } else {
+ $text .= htmlspecialchars($this->mime_part->getContents());
+ }
+
+ return $text . '</pre>';
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_tnef class allows MS-TNEF attachments to be
+ * displayed.
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_tnef extends Horde_Mime_Viewer_tnef
+{
+ /**
+ * The contentType of the attachment.
+ *
+ * @var string
+ */
+ protected $_contentType = 'application/octet-stream';
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string Either the list of tnef files or the data of an
+ * individual tnef file.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ $text = '';
+
+ /* Get the data from the attachment. */
+ $tnefData = $this->_getSubparts();
+
+ /* Display the requested file. Its position in the $tnefData
+ array can be found in 'tnef_attachment'. */
+ if (Util::getFormData('tnef_attachment')) {
+ $tnefKey = Util::getFormData('tnef_attachment') - 1;
+ /* Verify that the requested file exists. */
+ if (isset($tnefData[$tnefKey])) {
+ $text = $tnefData[$tnefKey]['stream'];
+ if (empty($text)) {
+ $text = $this->formatStatusMsg(_("Could not extract the requested file from the MS-TNEF attachment."));
+ } else {
+ $this->mime_part->setName($tnefData[$tnefKey]['name']);
+ $this->mime_part->setType($tnefData[$tnefKey]['type'] . '/' . $tnefData[$tnefKey]['subtype']);
+ }
+ } else {
+ $text = $this->formatStatusMsg(_("The requested file does not exist in the MS-TNEF attachment."));
+ }
+ } else {
+ $text = $this->renderAttachmentInfo(array($params[0]));
+ }
+
+ return $text;
+ }
+
+ /**
+ * Render out TNEF attachment information.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string The rendered text in HTML.
+ */
+ public function renderAttachmentInfo($params)
+ {
+ $contents = &$params[0];
+
+ $text = '';
+
+ /* Make sure the contents are in the MIME_Part object. */
+ if (!$this->mime_part->getContents()) {
+ $this->mime_part->setContents($contents->getBodyPart($this->mime_part->getMIMEId()));
+ }
+
+ /* Get the data from the attachment. */
+ $tnefData = $this->_getSubparts();
+
+ if (!count($tnefData)) {
+ $text = $this->formatStatusMsg(_("No attachments found."));
+ } else {
+ $text = $this->formatStatusMsg(_("The following files were attached to this part:")) . '<br />';
+ foreach ($tnefData as $key => $data) {
+ $temp_part = $this->mime_part;
+ $temp_part->setName($data['name']);
+ $temp_part->setDescription($data['name']);
+
+ /* Short-circuit MIME-type guessing for winmail.dat parts;
+ we're showing enough entries for them already. */
+ $type = $data['type'] . '/' . $data['subtype'];
+ if (($type == 'application/octet-stream') ||
+ ($type == 'application/base64')) {
+ $type = Horde_Mime_Magic::filenameToMIME($data['name']);
+ }
+ $temp_part->setType($type);
+
+ $link = $contents->linkView($temp_part, 'view_attach', htmlspecialchars($data['name']), array('jstext' => sprintf(_("View %s"), $data['name']), 'viewparams' => array('tnef_attachment' => ($key + 1))));
+ $text .= _("Attached File:") . ' ' . $link . ' (' . $data['type'] . '/' . $data['subtype'] . ")<br />\n";
+ }
+ }
+
+ return $text;
+ }
+
+ /**
+ * List any embedded attachments in the TNEF part.
+ *
+ * @return array An array of any embedded attachments.
+ */
+ protected function _getSubparts()
+ {
+ $tnef = &Horde_Compress::singleton('tnef');
+ return $tnef->decompress($this->mime_part->transferDecode());
+ }
+
+ /**
+ * Return the content-type.
+ *
+ * @return string The content-type of the output.
+ */
+ public function getType()
+ {
+ if (Util::getFormData('tnef_attachment')) {
+ return $this->_contentType;
+ } else {
+ return 'text/html; charset=' . NLS::getCharset();
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_zip class renders out the contents of ZIP files
+ * in HTML format and allows downloading of extractable files.
+ *
+ * Copyright 2002-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Mike Cochrane <mike@graftonhall.co.nz>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Mime
+ */
+class IMP_Horde_Mime_Viewer_zip extends Horde_Mime_Viewer_zip
+{
+ /**
+ * The IMP_Contents object, needed for the _callback() function.
+ *
+ * @var IMP_Contents
+ */
+ protected $_contents;
+
+ /**
+ * Render out the currently set contents.
+ *
+ * @param array $params An array with a reference to a MIME_Contents
+ * object.
+ *
+ * @return string Either the list of zip files or the data of an
+ * individual zip file.
+ */
+ public function render($params)
+ {
+ $contents = &$params[0];
+
+ $data = $this->mime_part->getContents();
+ $text = '';
+
+ /* Send the requested file. Its position in the zip archive is located
+ * in 'zip_attachment'. */
+ if (Util::getFormData('zip_attachment')) {
+ $zip = &Horde_Compress::singleton('zip');
+ $fileKey = Util::getFormData('zip_attachment') - 1;
+ $zipInfo = $zip->decompress(
+ $data, array('action' => HORDE_COMPRESS_ZIP_LIST));
+ /* Verify that the requested file exists. */
+ if (isset($zipInfo[$fileKey])) {
+ $text = $zip->decompress(
+ $data,
+ array('action' => HORDE_COMPRESS_ZIP_DATA,
+ 'info' => &$zipInfo,
+ 'key' => $fileKey));
+ if (empty($text)) {
+ $text = '<pre>' . _("Could not extract the requested file from the Zip archive.") . '</pre>';
+ } else {
+ $this->mime_part->setType('application/octet-stream');
+ $this->mime_part->setName(basename($zipInfo[$fileKey]['name']));
+ }
+ } else {
+ $text = '<pre>' . _("The requested file does not exist in the Zip attachment.") . '</pre>';
+ }
+ } else {
+ $this->_contents = $contents;
+ $text = parent::_render($data, array($this, '_callback'));
+ }
+
+ return $text;
+ }
+
+ /**
+ * The function to use as a callback to parent::_render().
+ *
+ * @param integer $key The position of the file in the zip archive.
+ * @param array $val The information array for the archived file.
+ *
+ * @return string The content-type of the output.
+ */
+ protected function _callback($key, $val)
+ {
+ $name = preg_replace('/( )+$/', '', $val['name']);
+ if (!empty($val['size']) && (strstr($val['attr'], 'D') === false) &&
+ ((($val['method'] == 0x8) && Util::extensionExists('zlib')) ||
+ ($val['method'] == 0x0))) {
+ $old_name = $this->mime_part->getName();
+ $this->mime_part->setName(basename($name));
+ $val['name'] = str_replace(
+ $name,
+ $this->_contents->linkView(
+ $this->mime_part, 'download_render', $name,
+ array('jstext' => sprintf(_("View %s"),
+ str_replace(' ', ' ', $name)),
+ 'class' => 'fixed',
+ 'viewparams' => array(
+ 'ctype' => 'application/zip',
+ 'zip_attachment' => (urlencode($key) + 1)))),
+ $val['name']);
+ $this->mime_part->setName($old_name);
+ }
+
+ return $val;
+ }
+}
$mime_headers = $fetch_ret[$index]['headertext'][0];
$use_pop = ($_SESSION['imp']['protocol'] == 'pop');
-/* Parse MIME info and create the body of the message. */
+/* Parse the message. */
$imp_contents = &IMP_Contents::singleton($index . IMP::IDX_SEP . $mailbox_name);
if (is_a($imp_contents, 'PEAR_Error')) {
_returnToMailbox(null, 'message_missing');
require IMP_BASE . '/mailbox.php';
exit;
}
-$summary = $imp_contents->getSummary(array(
- 'message_token' => $message_token,
- 'show_links' => !$printer_friendly,
- 'strip' => !$readonly && $prefs->getValue('strip_attachments')
-));
-$inline_parts = $imp_contents->getInlineParts();
+
+$contents_mask = IMP_Contents::SUMMARY_RENDER |
+ IMP_Contents::SUMMARY_BYTES |
+ IMP_Contents::SUMMARY_SIZE |
+ IMP_Contents::SUMMARY_ICON;
+if ($printer_friendly) {
+ $contents_mask |= IMP_Contents::SUMMARY_DESCRIP_NOLINK;
+} else {
+ $contents_mask |= IMP_Contents::SUMMARY_DESCRIP_LINK |
+ IMP_Contents::SUMMARY_DOWNLOAD |
+ IMP_Contents::SUMMARY_DOWNLOAD_ZIP |
+ IMP_Contents::SUMMARY_IMAGE_SAVE |
+ IMP_Contents::SUMMARY_DOWNLOAD_ALL;
+ if (!$readonly && $prefs->getValue('strip_attachments')) {
+ $contents_mask |= IMP_Contents::SUMMARY_STRIP_LINK;
+ }
+}
+
+$summary = $imp_contents->getSummary($contents_mask);
/* Get the title/mailbox label of the mailbox page. */
$page_label = IMP::getLabel($imp_mbox['mailbox']);