429 lines
12 KiB
PHP
429 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Copyright 2012-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information (GPL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/gpl.
|
|
*
|
|
* @category Horde
|
|
* @copyright 2012-2017 Horde LLC
|
|
* @license http://www.horde.org/licenses/gpl GPL
|
|
* @package IMP
|
|
*/
|
|
|
|
/**
|
|
* Provides logic to format message content for delivery to the browser.
|
|
*
|
|
* @author Michael Slusarz <slusarz@horde.org>
|
|
* @category Horde
|
|
* @copyright 2012-2017 Horde LLC
|
|
* @license http://www.horde.org/licenses/gpl GPL
|
|
* @package IMP
|
|
*/
|
|
class IMP_Contents_View
|
|
{
|
|
const VIEW_TOKEN_PARAM = 'view_token';
|
|
|
|
/**
|
|
* @var IMP_Contents
|
|
*/
|
|
protected $_contents;
|
|
|
|
/**
|
|
* @param IMP_Indices $indices
|
|
*/
|
|
public function __construct(IMP_Indices $indices)
|
|
{
|
|
try {
|
|
$this->_contents = $GLOBALS['injector']->getInstance('IMP_Factory_Contents')->create($indices);
|
|
} catch (Exception $e) {
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function downloadAll()
|
|
{
|
|
global $page_output, $session;
|
|
|
|
$headers = $this->_contents->getHeader();
|
|
$zipfile = trim(preg_replace('/[^\pL\pN\-+_. ]/u', '_', $headers->getValue('subject')), ' _');
|
|
if (empty($zipfile)) {
|
|
$zipfile = _("attachments.zip");
|
|
} else {
|
|
$zipfile .= '.zip';
|
|
}
|
|
|
|
$page_output->disableCompression();
|
|
$session->close();
|
|
|
|
$tosave = array();
|
|
foreach ($this->_contents->downloadAllList() as $val) {
|
|
$mime = $this->_getRawDownloadPart($val);
|
|
if ($name = $mime->getName(true)) {
|
|
$name = preg_replace('/[\x00-\x1f]+/', '', $name);
|
|
} else {
|
|
$name = sprintf(_("part %s"), $val);
|
|
}
|
|
$tosave[] = array(
|
|
'data' => $mime->getContents(array('stream' => true)),
|
|
'name' => $name
|
|
);
|
|
}
|
|
|
|
if (empty($tosave)) {
|
|
return array();
|
|
}
|
|
|
|
return array(
|
|
'data' => Horde_Compress::factory('Zip')->compress($tosave, array(
|
|
'stream' => true
|
|
)),
|
|
'name' => $zipfile,
|
|
'type' => 'application/zip'
|
|
);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function downloadAttach($id, $zip = false)
|
|
{
|
|
global $page_output, $session;
|
|
|
|
$session->close();
|
|
|
|
if (!($mime = $this->_getRawDownloadPart($id))) {
|
|
return array();
|
|
}
|
|
|
|
if (!($name = $this->_contents->getPartName($mime))) {
|
|
$name = '';
|
|
}
|
|
|
|
/* Compress output? */
|
|
if ($zip) {
|
|
$data = Horde_Compress::factory('Zip')->compress(array(
|
|
array(
|
|
'data' => $mime->getContents(),
|
|
'name' => preg_replace('/[\x00-\x1f]+/', '', $name)
|
|
)
|
|
), array(
|
|
'stream' => true
|
|
));
|
|
$name .= '.zip';
|
|
$type = 'application/zip';
|
|
|
|
$page_output->disableCompression();
|
|
} else {
|
|
$data = $mime->getContents(array('stream' => true));
|
|
$type = $mime->getType(true);
|
|
}
|
|
|
|
return array(
|
|
'data' => $data,
|
|
'name' => $name,
|
|
'type' => $type
|
|
);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function downloadRender($id, $mode, $ctype = null)
|
|
{
|
|
global $session;
|
|
|
|
$session->close();
|
|
|
|
$render = $this->_contents->renderMIMEPart(
|
|
$id,
|
|
$mode,
|
|
array(
|
|
'type' => $ctype
|
|
)
|
|
);
|
|
return reset($render);
|
|
}
|
|
|
|
/**
|
|
* @throws IMP_Exception
|
|
*/
|
|
public function viewAttach($id, $mode, $autodetect = false, $ctype = null)
|
|
{
|
|
global $session;
|
|
|
|
$session->close();
|
|
|
|
$render = $this->_contents->renderMIMEPart(
|
|
$id,
|
|
$mode,
|
|
array(
|
|
'autodetect' => $autodetect,
|
|
'type' => $ctype
|
|
)
|
|
);
|
|
|
|
if (!empty($render)) {
|
|
return reset($render);
|
|
} elseif ($autodetect) {
|
|
$e = new IMP_Exception(_("Could not auto-determine data type."));
|
|
$e->logged = true;
|
|
throw $e;
|
|
}
|
|
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function viewSource()
|
|
{
|
|
global $session;
|
|
|
|
$session->close();
|
|
|
|
$charset = $this->_contents->getMIMEMessage()->getCharset();
|
|
|
|
return array(
|
|
'data' => $this->_contents->fullMessageText(array(
|
|
'stream' => true
|
|
)),
|
|
'name' => _("Message Source"),
|
|
'type' => 'text/plain; charset=' . (is_null($charset) ? 'UTF-8' : $charset)
|
|
);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function saveMessage()
|
|
{
|
|
global $session;
|
|
|
|
$session->close();
|
|
|
|
$name = ($subject = $this->_contents->getHeader()->getValue('subject'))
|
|
? trim(preg_replace('/[^\pL\pN\-+_. ]/u', '_', $subject), ' _')
|
|
: 'saved_message';
|
|
|
|
return array(
|
|
'data' => $this->_contents->fullMessageText(array(
|
|
'stream' => true
|
|
)),
|
|
'name' => $name . '.eml',
|
|
'type' => 'message/rfc822'
|
|
);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function printAttach($id)
|
|
{
|
|
global $injector, $page_output, $prefs, $registry;
|
|
|
|
if (is_null($id) ||
|
|
!($render = $this->_contents->renderMIMEPart($id, IMP_Contents::RENDER_FULL))) {
|
|
return array();
|
|
}
|
|
|
|
$part = reset($render);
|
|
|
|
/* Directly render part if this is not an HTML part or it is empty. */
|
|
if (stripos($part['type'], 'text/html') !== 0 || !strlen($part['data'])) {
|
|
return $part;
|
|
}
|
|
|
|
$imp_ui_mbox = new IMP_Mailbox_Ui();
|
|
$basic_headers = $injector->getInstance('IMP_Message_Ui')->basicHeaders();
|
|
unset($basic_headers['bcc'], $basic_headers['reply-to']);
|
|
$headerob = $this->_contents->getHeader();
|
|
|
|
$d_param = Horde_Mime::decodeParam('content-type', $part['type']);
|
|
|
|
$headers = array();
|
|
foreach ($basic_headers as $key => $val) {
|
|
if ($hdr_val = $headerob->getValue($key)) {
|
|
/* Format date string. */
|
|
if ($key == 'date') {
|
|
$registry->setTimeZone();
|
|
$hdr_val = $imp_ui_mbox->getDate($hdr_val, $imp_ui_mbox::DATE_FORCE | $imp_ui_mbox::DATE_FULL);
|
|
}
|
|
|
|
$headers[] = array(
|
|
'header' => $val,
|
|
'value' => $hdr_val
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($prefs->getValue('add_printedby')) {
|
|
$user_identity = $injector->getInstance('IMP_Identity');
|
|
$headers[] = array(
|
|
'header' => _("Printed By"),
|
|
'value' => $user_identity->getFullname() ? $user_identity->getFullname() : $registry->getAuth()
|
|
);
|
|
}
|
|
|
|
$view = new Horde_View(array(
|
|
'templatePath' => IMP_TEMPLATES . '/print'
|
|
));
|
|
$view->addHelper('Text');
|
|
|
|
$view->headers = $headers;
|
|
|
|
$header_dom = new Horde_Domhtml(Horde_String::convertCharset($view->render('headers'), 'UTF-8', $d_param['params']['charset']), $d_param['params']['charset']);
|
|
$elt = $header_dom->dom->getElementById('headerblock');
|
|
$elt->removeAttribute('id');
|
|
|
|
if ($elt->hasAttribute('class')) {
|
|
$selectors = array('body');
|
|
foreach (explode(' ', $elt->getAttribute('class')) as $val) {
|
|
if (strlen($val = trim($val))) {
|
|
$selectors[] = '.' . $val;
|
|
}
|
|
}
|
|
|
|
/* Cache CSS. */
|
|
$cache_list = array();
|
|
$cache_ob = $injector->getInstance('Horde_Cache');
|
|
|
|
$css_list = $page_output->css->getStylesheets();
|
|
foreach ($css_list as $val) {
|
|
$cache_list[] = $val['fs'];
|
|
$cache_list[] = filemtime($val['fs']);
|
|
}
|
|
$cache_id = 'imp_printcss_' . hash(
|
|
(PHP_MINOR_VERSION >= 4) ? 'fnv132' : 'sha1',
|
|
implode('|', $cache_list)
|
|
);
|
|
|
|
if (($style = $cache_ob->get($cache_id, 0)) === false) {
|
|
try {
|
|
$css_parser = new Horde_Css_Parser(
|
|
$page_output->css->loadCssFiles(
|
|
$page_output->css->getStylesheets()
|
|
)
|
|
);
|
|
|
|
$style = '';
|
|
|
|
foreach ($css_parser->doc->getContents() as $val) {
|
|
if (($val instanceof Sabberworm\CSS\RuleSet\DeclarationBlock) &&
|
|
array_intersect($selectors, array_map('strval', $val->getSelectors()))) {
|
|
$style .= implode('', array_map('strval', $val->getRules()));
|
|
}
|
|
}
|
|
|
|
$cache_ob->set($cache_id, $style, 86400);
|
|
} catch (Exception $e) {
|
|
// Ignore CSS if it can't be parsed.
|
|
}
|
|
}
|
|
|
|
if (strlen($style)) {
|
|
$elt->setAttribute('style', ($elt->hasAttribute('style') ? rtrim($elt->getAttribute('style'), ' ;') . ';' : '') . $style);
|
|
}
|
|
}
|
|
|
|
$elt->removeAttribute('class');
|
|
|
|
/* Need to wrap headers in another DIV. */
|
|
$newdiv = new DOMDocument();
|
|
$div = $newdiv->createElement('div');
|
|
$div->appendChild($newdiv->importNode($elt, true));
|
|
|
|
$pstring = Horde_Mime::decodeParam('content-type', $part['type']);
|
|
|
|
$doc = new Horde_Domhtml($part['data'], $pstring['params']['charset']);
|
|
|
|
$bodyelt = $doc->dom->getElementsByTagName('body')->item(0);
|
|
$bodyelt->insertBefore($doc->dom->importNode($div, true), $bodyelt->firstChild);
|
|
|
|
/* Make the title the e-mail subject. */
|
|
$headelt = $doc->getHead();
|
|
foreach ($headelt->getElementsByTagName('title') as $node) {
|
|
$headelt->removeChild($node);
|
|
}
|
|
$headelt->appendChild($doc->dom->createElement('title', htmlspecialchars($imp_ui_mbox->getSubject($headerob->getValue('subject')))));
|
|
|
|
return array(
|
|
'data' => $doc->returnHtml(),
|
|
'name' => $part['name'],
|
|
'type' => $part['type']
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check for a download token.
|
|
*
|
|
* @param Horde_Variables $vars Form variables.
|
|
*
|
|
* @throws Horde_Exception Exception on incorrect token.
|
|
*/
|
|
public function checkToken(Horde_Variables $vars)
|
|
{
|
|
$GLOBALS['session']->checkToken($vars->get(self::VIEW_TOKEN_PARAM));
|
|
}
|
|
|
|
/* Static methods. */
|
|
|
|
/**
|
|
* Returns a URL to be used for downloading data.
|
|
* IMP adds token data, since the data displayed is coming from a remote
|
|
* source.
|
|
*
|
|
* @see Horde_Registry#downloadUrl()
|
|
*
|
|
* @param string $filename The filename of the download data.
|
|
* @param array $params Additional URL parameters needed.
|
|
*
|
|
* @return Horde_Url The download URL.
|
|
*/
|
|
static public function downloadUrl($filename, array $params = array())
|
|
{
|
|
global $registry;
|
|
|
|
return $registry->downloadUrl($filename, self::addToken($params));
|
|
}
|
|
|
|
/**
|
|
* Adds the view token to a parameter list.
|
|
*
|
|
* @param array $params URL parameters.
|
|
*
|
|
* @return array Parameter list with token added.
|
|
*/
|
|
static public function addToken(array $params = array())
|
|
{
|
|
global $session;
|
|
|
|
$params[self::VIEW_TOKEN_PARAM] = $session->getToken();
|
|
|
|
return $params;
|
|
}
|
|
|
|
/* Internal methods. */
|
|
|
|
/**
|
|
* Get a MIME Part for use in creating download.
|
|
*
|
|
* @param string $id MIME ID.
|
|
*
|
|
* @return Horde_Mime_Part MIME part.
|
|
*/
|
|
protected function _getRawDownloadPart($id)
|
|
{
|
|
$mime = $this->_contents->getMIMEPart($id);
|
|
|
|
if ($this->_contents->canDisplay($id, IMP_Contents::RENDER_RAW)) {
|
|
$render = $this->_contents->renderMIMEPart($id, IMP_Contents::RENDER_RAW);
|
|
$part = reset($render);
|
|
$mime->setContents($part['data'], array(
|
|
'encoding' => 'binary'
|
|
));
|
|
}
|
|
|
|
return $mime;
|
|
}
|
|
|
|
}
|