Rename Mime drivers
authorMichael M Slusarz <slusarz@curecanti.org>
Tue, 10 Mar 2009 21:59:41 +0000 (15:59 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Tue, 10 Mar 2009 21:59:41 +0000 (15:59 -0600)
34 files changed:
imp/lib/Mime/Viewer/Alternative.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Appledouble.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Enriched.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Html.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Images.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Itip.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Mdn.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Partial.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Pdf.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Pgp.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Plain.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Related.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Smil.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Smime.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Status.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Tnef.php [new file with mode: 0644]
imp/lib/Mime/Viewer/Zip.php [new file with mode: 0644]
imp/lib/Mime/Viewer/alternative.php [deleted file]
imp/lib/Mime/Viewer/appledouble.php [deleted file]
imp/lib/Mime/Viewer/enriched.php [deleted file]
imp/lib/Mime/Viewer/html.php [deleted file]
imp/lib/Mime/Viewer/images.php [deleted file]
imp/lib/Mime/Viewer/itip.php [deleted file]
imp/lib/Mime/Viewer/mdn.php [deleted file]
imp/lib/Mime/Viewer/partial.php [deleted file]
imp/lib/Mime/Viewer/pdf.php [deleted file]
imp/lib/Mime/Viewer/pgp.php [deleted file]
imp/lib/Mime/Viewer/plain.php [deleted file]
imp/lib/Mime/Viewer/related.php [deleted file]
imp/lib/Mime/Viewer/smil.php [deleted file]
imp/lib/Mime/Viewer/smime.php [deleted file]
imp/lib/Mime/Viewer/status.php [deleted file]
imp/lib/Mime/Viewer/tnef.php [deleted file]
imp/lib/Mime/Viewer/zip.php [deleted file]

diff --git a/imp/lib/Mime/Viewer/Alternative.php b/imp/lib/Mime/Viewer/Alternative.php
new file mode 100644 (file)
index 0000000..e62860a
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Alternative class renders out messages from
+ * multipart/alternative content types (RFC 2046 [5.1.4]).
+ *
+ * Copyright 2002-2009 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
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => true,
+        'full' => false,
+        'info' => false,
+        'inline' => true,
+    );
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        $base_id = $this->_mimepart->getMimeId();
+        $subparts = $this->_mimepart->contentTypeMap();
+
+        $base_ids = $display_ids = $ret = array();
+
+        /* Look for a displayable part. RFC: show the LAST choice that can be
+         * displayed inline. If an alternative is itself a multipart, the user
+         * agent is allowed to show that alternative, an earlier alternative,
+         * or both. If we find a multipart alternative that contains at least
+         * one viewable part, we will display all viewable subparts of that
+         * alternative. */
+        foreach (array_keys($subparts) as $mime_id) {
+            $ret[$mime_id] = null;
+            if ((strcmp($base_id, $mime_id) !== 0) &&
+                $this->_params['contents']->canDisplay($mime_id, IMP_Contents::RENDER_INLINE)) {
+                $display_ids[strval($mime_id)] = true;
+            }
+        }
+
+        /* If we found no IDs, return now. */
+        if (empty($display_ids)) {
+            $ret[$base_id] = array(
+                'data' => '',
+                'status' => array(
+                    array(
+                        'text' => array(_("There are no alternative parts that can be displayed inline.")),
+                        'type' => 'info'
+                    )
+                ),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            );
+            return $ret;
+        }
+
+        /* If the last viewable message exists in a subpart, back up to the
+         * base multipart and display all viewable parts in that multipart.
+         * Else, display the single part. */
+        end($display_ids);
+        $curr_id = key($display_ids);
+        while (!is_null($curr_id) && (strcmp($base_id, $curr_id) !== 0)) {
+            if (isset($subparts[$curr_id])) {
+                $disp_id = $curr_id;
+            }
+            $curr_id = Horde_Mime::mimeIdArithmetic($curr_id, 'up');
+        }
+
+        /* Now grab all keys under this ID. */
+        $render_part = $this->_mimepart->getPart($disp_id);
+        foreach (array_keys($render_part->contentTypeMap()) as $val) {
+            if (isset($display_ids[$val])) {
+                $render = $this->_params['contents']->renderMIMEPart($val, IMP_Contents::RENDER_INLINE, array('params' => $this->_params));
+                foreach (array_keys($render) as $id) {
+                    $ret[$id] = $render[$id];
+                    unset($display_ids[$id]);
+                }
+            }
+        }
+
+        return $ret;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Appledouble.php b/imp/lib/Mime/Viewer/Appledouble.php
new file mode 100644 (file)
index 0000000..19f1eb2
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Appledouble class handles multipart/appledouble
+ * messages conforming to RFC 1740.
+ *
+ * Copyright 2003-2009 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
+{
+    /**
+     * This driver's capabilities.
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => true,
+        'full' => false,
+        'info' => true,
+        'inline' => true
+    );
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        return $this->_IMPrender(true);
+    }
+
+    /**
+     * Return the rendered information about the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInfo()
+    {
+        return $this->_IMPrender(false);
+    }
+
+    /**
+     * Render the part based on the view mode.
+     *
+     * @param boolean $inline  True if viewing inline.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _IMPrender($inline)
+    {
+        /* RFC 1740 [4]: There are two parts to an appledouble message:
+         *   (1) application/applefile
+         *   (2) Data embedded in the Mac file
+         * Since the resource fork is not very useful to us, only provide a
+         * means to download. */
+
+        /* Display the resource fork download link. */
+        $mime_id = $this->_mimepart->getMimeId();
+        $parts_list = array_keys($this->_mimepart->contentTypeMap());
+        reset($parts_list);
+        $applefile_id = next($parts_list);
+        $data_id = Horde_Mime::mimeIdArithmetic($applefile_id, 'next');
+
+        $applefile_part = $this->_mimepart->getPart($applefile_id);
+        $data_part = $this->_mimepart->getPart($data_id);
+
+        $data_name = $data_part->getName(true);
+        if (empty($data_name)) {
+            $data_name = _("unnamed");
+        }
+
+        $status = array(
+            'icon' => Horde::img('apple.png', _("Macintosh File")),
+            'text' => array(
+                sprintf(_("This message contains a Macintosh file (named \"%s\")."), $data_name),
+                sprintf(_("The Macintosh resource fork can be downloaded %s."), $this->_params['contents']->linkViewJS($applefile_part, 'download_attach', _("HERE"), array('jstext' => _("The Macintosh resource fork"))))
+            )
+        );
+
+        /* For inline viewing, attempt to display the data inline. */
+        $ret = array();
+        if ($inline && (($disp = $this->_params['contents']->canDisplay($data_part, IMP_Contents::RENDER_INLINE | IMP_Contents::RENDER_INFO)))) {
+            $ret = $this->_params['contents']->renderMIMEPart($data_id, $disp, array('params' => $this->_params));
+            $status['text'][] = _("The contents of the Macintosh file are below.");
+        } else {
+            $status['text'][] = sprintf(_("The contents of the Macintosh file can be downloaded %s."), $this->_params['contents']->linkViewJS($data_part, 'download_attach', _("HERE"), array('jstext' => _("The Macintosh file"))));
+        }
+
+        foreach ($parts_list as $val) {
+            if (!isset($ret[$val]) && (strcmp($val, $data_id) !== 0)) {
+                $ret[$val] = (strcmp($val, $mime_id) === 0)
+                    ? array(
+                          'data' => '',
+                          'status' => array($status),
+                          'type' => 'text/html; charset=' . NLS::getCharset()
+                      )
+                    : null;
+            }
+        }
+
+        ksort($ret);
+
+        return $ret;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Enriched.php b/imp/lib/Mime/Viewer/Enriched.php
new file mode 100644 (file)
index 0000000..ca3413b
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Enriched class renders out plain text from
+ * enriched content tags, ala RFC 1896
+ *
+ * Copyright 2001-2009 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
+{
+    /**
+     * Return the full rendered version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _render()
+    {
+        $ret = parent::_render();
+        if (!empty($ret)) {
+            reset($ret);
+            $ret[key($ret)]['data'] = $this->_IMPformat($ret[key($ret)]['data']);
+        }
+        return $ret;
+    }
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        $ret = parent::_renderInline();
+        if (!empty($ret)) {
+            reset($ret);
+            $ret[key($ret)]['data'] = $this->_IMPformat($ret[key($ret)]['data']);
+        }
+        return $ret;
+    }
+
+    /**
+     * Format output text with IMP additions.
+     *
+     * @param string $text  The HTML text.
+     *
+     * @return string  The text with extra IMP formatting applied.
+     */
+    protected function _IMPformat($text)
+    {
+        // Highlight quoted parts of an email.
+        if ($GLOBALS['prefs']->getValue('highlight_text')) {
+            $text = implode("\n", preg_replace('|^(\s*&gt;.+)$|', '<span class="quoted1">\1</span>', explode("\n", $text)));
+            $indent = 1;
+            while (preg_match('|&gt;(\s?&gt;){' . $indent . '}|', $text)) {
+                $text = implode("\n", preg_replace('|^<span class="quoted' . ((($indent - 1) % 5) + 1) . '">(\s*&gt;(\s?&gt;){' . $indent . '}.+)$|', '<span class="quoted' . (($indent % 5) + 1) . '">\1', explode("\n", $text)));
+                ++$indent;
+            }
+        }
+
+        // Dim signatures.
+        if ($GLOBALS['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.
+        return IMP::filterText($text);
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Html.php b/imp/lib/Mime/Viewer/Html.php
new file mode 100644 (file)
index 0000000..69000c6
--- /dev/null
@@ -0,0 +1,290 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Html class renders out HTML text with an effort
+ * to remove potentially malicious code.
+ *
+ * Copyright 1999-2009 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';
+
+    /**
+     * Return the full rendered version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _render()
+    {
+        $render = $this->_IMPrender(false);
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => $render['html'],
+                'status' => $render['status'],
+                'type' => $this->_mimepart->getType(true)
+            )
+        );
+    }
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        $render = $this->_IMPrender(true);
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => $render['html'],
+                'status' => $render['status'],
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+    }
+
+    /**
+     * 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'];
+
+        /* We are done processing if in mimp mode. */
+        if ($_SESSION['imp']['view'] == 'mimp') {
+            require_once 'Horde/Text/Filter.php';
+            $data = Text_Filter::filter($data, 'html2text');
+
+            // Filter bad language.
+            return array('html' => IMP::filterText($data), 'status' => array());
+        }
+
+        /* 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 links that we can display (multipart/related
+         * parts). */
+        if (isset($this->_params['related_id'])) {
+            $cid_replace = array();
+
+            foreach ($this->_params['related_cids'] as $mime_id => $cid) {
+                $cid = trim($cid, '<>');
+                if ($cid) {
+                    $cid_part = $this->_params['contents']->getMIMEPart($mime_id);
+                    $cid_replace['cid:' . $cid] = $this->_params['contents']->urlView($cid_part, 'view_attach', array('params' => array('img_data' => 1)));
+                }
+            }
+
+            if (!empty($cid_replace)) {
+                $data = str_replace(array_keys($cid_replace), array_values($cid_replace), $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 class="htmlMessage">' . $data . '</div>';
+        }
+
+        /* Only display images if specifically allowed by user. */
+        if ($inline &&
+            !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(IMP::selfUrl(), array('actionID', 'index'));
+            $url = Util::addParameter($url, 'index', $this->_params['contents']->getIndex());
+
+            $view_img = Util::getFormData('view_html_images');
+            $addr_check = ($GLOBALS['prefs']->getValue('html_image_addrbook') && $this->_inAddressBook());
+
+            if (!$view_img && !$addr_check) {
+                $data .= Util::bufferOutput(array('Horde', 'addScriptFile'), 'prototype.js', 'horde', true) .
+                    Util::bufferOutput(array('Horde', 'addScriptFile'), 'imp.js', 'imp', true);
+
+                // Unblock javascript code in js/src/imp.js
+                $cleanhtml['status'][] = array(
+                    'icon' => Horde::img('mime/image.png'),
+                    'text' => array(
+                        String::convertCharset(_("Images have been blocked to protect your privacy."), $charset, $msg_charset),
+                        Horde::link(Util::addParameter($url, 'view_html_images', 1), '', 'unblockImageLink') . String::convertCharset(_("Show Images?"), $charset, $msg_charset) . '</a>'
+                    )
+                );
+
+                $data = preg_replace_callback($this->_img_regex, array($this, '_blockImages'), $data);
+            }
+        }
+
+        require_once 'Horde/Text/Filter.php';
+        if ($GLOBALS['prefs']->getValue('emoticons')) {
+            $data = Text_Filter::filter($data, array('emoticons'), array(array('emoticons' => true)));
+        }
+
+        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('&amp;', '&', trim($matches[5], '\'" '))) . '"'
+            : $matches[1] . "'" . $this->_blockimg . '\')' . $matches[6] . '" blocked="' . rawurlencode(str_replace('&amp;', '&', 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();
+        $headers = $this->_params['contents']->getHeaderOb();
+
+        /* Try to get back a result from the search. */
+        $res = $GLOBALS['registry']->call('contacts/getField', array(Horde_Mime_Address::bareAddress($headers->getValue('from')), '__key', $params['sources'], false, true));
+        return is_a($res, 'PEAR_Error') ? false : count($res);
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Images.php b/imp/lib/Mime/Viewer/Images.php
new file mode 100644 (file)
index 0000000..21f7cf6
--- /dev/null
@@ -0,0 +1,282 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Images class allows display of images attached
+ * to a message.
+ *
+ * Copyright 2002-2009 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
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => false,
+        'full' => true,
+        'info' => true,
+        'inline' => true
+    );
+
+    /**
+     * Return the full rendered version of the Horde_Mime_Part object.
+     *
+     * URL parameters used by this function:
+     * <pre>
+     * 'imp_img_view' - (string) One of the following:
+     *   'data' - Output the image directly.
+     *   'load_convert' - TODO
+     *   'view_convert' - TODO
+     *   'view_thumbnail' - TODO
+     * </pre>
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _render()
+    {
+        switch (Util::getFormData('imp_img_view')) {
+        case 'data':
+            /* If calling page is asking us to output data, do that without
+             * any further delay and exit. */
+            return parent::_render();
+
+        case 'view_convert':
+            /* Convert the image to browser-viewable format and display. */
+            return $this->_viewConvert(false);
+
+        case 'view_thumbnail':
+            /* Create the thumbnail and display. */
+            return $this->_viewConvert(true);
+
+        case 'load_convert':
+            /* The browser can display the image type directly - output the JS
+             * code to render the auto resize popup image window. */
+            return $this->_popupImageWindow();
+        }
+
+        return parent::_render();
+    }
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        /* Only display the image inline if the browser can display it and the
+         * size of the image is below the config value. */
+        if ($GLOBALS['browser']->isViewable($this->_getType())) {
+            if (isset($this->_conf['inlinesize']) &&
+                ($this->_mimepart->getBytes() < $this->_conf['inlinesize'])) {
+                /* Viewing inline, and the browser can handle the image type
+                 * directly. So output an <img> tag to load the image. */
+                return array(
+                    $this->_mimepart->getMimeId() => array(
+                        'data' => Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('imp_img_view' => 'data'))), $this->_mimepart->getName(true), null, ''),
+                        'status' => array(),
+                        'type' => 'text/html; charset=' . NLS::getCharset()
+                    )
+                );
+            } else {
+                return $this->_renderInfo();
+            }
+        }
+
+        /* The browser cannot view this image. Inform the user of this and
+         * ask user if we should convert to another image type. */
+        $status = array(_("Your browser does not support inline display of this image type."));
+
+        /* See if we can convert to an inline browser viewable form. */
+        if ($GLOBALS['browser']->hasFeature('javascript')) {
+            $img = $this->_getHordeImageOb(false);
+            if ($img &&
+                $GLOBALS['browser']->isViewable($img->getContentType())) {
+                $convert_link = $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("HERE"), array('params' => array('imp_img_view' => 'load_convert')));
+                $status[] = sprintf(_("Click %s to convert the image file into a format your browser can attempt to view."), $convert_link);
+            }
+        }
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => '',
+                'status' => array(
+                    array(
+                        'text' => $status
+                    )
+                ),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+    }
+
+    /**
+     * Return the rendered information about the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInfo()
+    {
+        /* Display the thumbnail link only if we show thumbs for all images or
+         * if image is over 50 KB. Also, check to see if convert utility is
+         * available. */
+        if ((!$this->getConfigParam('allthumbs') &&
+             ($this->_mimepart->getBytes() < 51200)) ||
+            !$this->_getHordeImageOb(false)) {
+            return array();
+        }
+
+        $status = array(sprintf(_("An image named %s is attached to this message. A thumbnail is below."), $this->_mimepart->getName(true)));
+
+        if ($GLOBALS['browser']->hasFeature('javascript')) {
+            $status[] = $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('imp_img_view' => 'view_thumbnail')), false), _("View Attachment"), null, ''), null, null, null);
+        } else {
+            $status[] = Horde::link($this->_params['contents']->urlView($this->_mimepart, 'view_attach')) . Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('imp_img_view' => 'view_thumbnail')), false), _("View Attachment"), null, '') . '</a>';
+        }
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => '',
+                'status' => array(
+                    array(
+                        'icon' => Horde::img('mime/image.png', _("Thumbnail of attached image")),
+                        'text' => $status
+                    )
+                ),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+    }
+
+    /**
+     * Generate the HTML output for the JS auto-resize view window.
+     *
+     * @return string  The HTML output.
+     */
+    protected function _popupImageWindow()
+    {
+        $self_url = Util::addParameter(IMP::selfUrl(), array('imp_img_view' => ((Util::getFormData('imp_img_view') == 'load_convert') ? 'view_convert' : 'data')));
+        $title = $this->_mimepart->getName(true);
+
+        $str = <<<EOD
+<html>
+<head>
+<title>$title</title>
+<style type="text/css"><!-- body { margin:0px; padding:0px; } --></style>
+EOD;
+
+        /* Only use javascript if we are using a DOM capable browser. */
+        if ($GLOBALS['browser']->getFeature('dom')) {
+            /* Javascript display. */
+            $loading = _("Loading...");
+            $str .= <<<EOD
+<script type="text/javascript">
+function resizeWindow()
+{
+
+    var h, img = document.getElementById('disp_image'), w;
+    document.getElementById('splash').style.display = 'none';
+    img.style.display = 'block';
+    window.moveTo(0, 0);
+    h = img.height - (self.innerHeight ? self.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight));
+    w = img.width - (self.innerWidth ? self.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth));
+    window.resizeBy(w, h);
+    self.focus();
+}
+</script></head>
+<body onload="resizeWindow();"><span id="splash" style="color:gray;font-family:sans-serif;padding:2px;">$loading</span><img id="disp_image" style="display:none;" src="$self_url" /></body></html>
+EOD;
+        } else {
+            /* Non-javascript display. */
+            $img_txt = _("Image");
+            $str .= <<<EOD
+</head>
+<body bgcolor="#ffffff">
+<img border="0" src="$self_url" alt="$img_txt" />
+</body>
+</html>
+EOD;
+        }
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => $str,
+                'status' => array(),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+    }
+
+    /**
+     * Convert image.
+     *
+     * @param boolean $thumb  View image in thumbnail size?
+     *
+     * @return string  The image data.
+     */
+    protected function _viewConvert($thumb)
+    {
+        $img = $this->_getHordeImageOb(true);
+
+        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');
+        }
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => $data,
+                'status' => array(),
+                'type' => $type
+            )
+        );
+    }
+
+    /**
+     * Return a Horde_Image object.
+     *
+     * @param boolean $load  Whether to load the image data.
+     *
+     * @return mixed  The Horde_Image object, or false on error.
+     */
+    protected function _getHordeImageOb($load)
+    {
+        $img = null;
+        $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);
+        }
+
+        if (!$img || is_a($img, 'PEAR_Error')) {
+            return false;
+        }
+
+        if ($load) {
+            $ret = $img->loadString(1, $this->_mimepart->getContents());
+            if (is_a($ret, 'PEAR_Error')) {
+                return false;
+            }
+        }
+
+        return $img;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Itip.php b/imp/lib/Mime/Viewer/Itip.php
new file mode 100644 (file)
index 0000000..0a1fb15
--- /dev/null
@@ -0,0 +1,967 @@
+<?php
+/**
+ * The IMP_Horde_Mime_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-2009 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
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => false,
+        'full' => true,
+        'info' => false,
+        'inline' => true
+    );
+
+    /**
+     * Return the full rendered version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _render()
+    {
+        $ret = $this->_renderInline();
+        if (!empty($ret)) {
+            reset($ret);
+            $ret[key($ret)]['data'] = Util::bufferOutput('include', $GLOBALS['registry']->get('templates', 'horde') . '/common-header.inc') .
+                $ret[key($ret)]['data'] .
+                Util::bufferOutput('include', $GLOBALS['registry']->get('templates', 'horde') . '/common-footer.inc');
+        }
+        return $ret;
+    }
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * URL parameters used by this function:
+     * <pre>
+     * 'identity' - (integer) TODO
+     * 'itip_action' - (array) TODO
+     * </pre>
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        global $registry;
+
+        $charset = NLS::getCharset();
+        $data = $this->_mimepart->getContents();
+        $mime_id = $this->_mimepart->getMimeId();
+
+        // Parse the iCal file.
+        $vCal = new Horde_iCalendar();
+        if (!$vCal->parsevCalendar($data, 'VCALENDAR', $this->_mimepart->getCharset())) {
+            return array(
+                $mime_id => array(
+                    'data' => '<h1>' . _("The calendar data is invalid") . '</h1>' . '<pre>' . htmlspecialchars($data) . '</pre>',
+                    'status' => array(),
+                    'type' => 'text/html; charset=' . $charset
+                )
+            );
+        }
+
+        // Check if we got vcard data with the wrong vcalendar mime type.
+        $c = $vCal->getComponentClasses();
+        if ((count($c) == 1) && !empty($c['horde_icalendar_vcard'])) {
+            return $this->_params['contents']->renderMIMEPart($mime_id, IMP_Contents::RENDER_INLINE, array('type' => 'text/x-vcard'));
+        }
+
+        // Get the method type.
+        $method = $vCal->getAttribute('METHOD');
+        if (is_a($method, 'PEAR_Error')) {
+            $method = '';
+        }
+
+        // Get the iCalendar file components.
+        $components = $vCal->getComponents();
+        $msgs = array();
+
+        // Handle the action requests.
+        $actions = Util::getFormData('itip_action', array());
+        foreach ($actions as $key => $action) {
+            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')) {
+                        $msgs[] = array('error', _("There was an error deleting the event:") . ' ' . $event->getMessage());
+                    } else {
+                        $msgs[] = array('success', _("Event successfully deleted."));
+                    }
+                } else {
+                    $msgs[] = 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')) {
+                        $msgs[] = array('error', _("There was an error updating the event:") . ' ' . $event->getMessage());
+                    } else {
+                        $msgs[] = array('success', _("Respondent Status Updated."));
+                    }
+                } else {
+                    $msgs[] = 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')) {
+                        // Try to update in calendar.
+                        if ($registry->hasMethod('calendar/replace')) {
+                            $result = $registry->call('calendar/replace', array('uid' => $guid, 'content' => $components[$key], 'contentType' => $this->mime_part->getType()));
+                            if (is_a($result, 'PEAR_Error')) {
+                                // Could be a missing permission.
+                                $msgs[] = array('warning', _("There was an error updating the event:") . ' ' . $result->getMessage() . '. ' . _("Trying to import the event instead."));
+                            } else {
+                                $handled = true;
+                                $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
+                                $msgs[] = array('success', _("The event was updated in your calendar.") .
+                                                             '&nbsp;' . Horde::link($url, _("View event"), null, '_blank') . Horde::img('mime/icalendar.png', _("View event"), null, $registry->getImageDir('horde')) . '</a>');
+                            }
+                        }
+                    }
+                    if (!$handled && $registry->hasMethod('calendar/import')) {
+                        // Import into calendar.
+                        $handled = true;
+                        $guid = $registry->call('calendar/import', array('content' => $components[$key], 'contentType' => $this->mime_part->getType()));
+                        if (is_a($guid, 'PEAR_Error')) {
+                            $msgs[] = array('error', _("There was an error importing the event:") . ' ' . $guid->getMessage());
+                        } else {
+                            $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
+                            $msgs[] = array('success', _("The event was added to your calendar.") .
+                                            '&nbsp;' . Horde::link($url, _("View event"), null, '_blank') . Horde::img('mime/icalendar.png', _("View event"), null, $registry->getImageDir('horde')) . '</a>');
+                        }
+                    }
+                    if (!$handled) {
+                        $msgs[] = 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')) {
+                            $msgs[] = array('error', _("There was an error importing user's free/busy information:") . ' ' . $res->getMessage());
+                        } else {
+                            $msgs[] = array('success', _("The user's free/busy information was sucessfully stored."));
+                        }
+                    } else {
+                        $msgs[] = 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')) {
+                            $msgs[] = array('error', _("There was an error importing the task:") . ' ' . $guid->getMessage());
+                        } else {
+                            $url = Horde::url($registry->link('tasks/show', array('uid' => $guid)));
+                            $msgs[] = array('success', _("The task has been added to your tasklist.") .
+                                                         '&nbsp;' . Horde::link($url, _("View task"), null, '_blank') . Horde::img('mime/icalendar.png', _("View task"), null, $registry->getImageDir('horde')) . '</a>');
+                        }
+                    } else {
+                        $msgs[] = array('warning', _("This action is not supported."));
+                    }
+                    break;
+
+                case 'vJournal':
+                default:
+                    $msgs[] = 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();
+                    $mime->setType('multipart/alternative');
+
+                    $body = new Horde_Mime_Part();
+                    $body->setType('text/plain');
+                    $body->setCharset($charset);
+                    $body->setContents(String::wrap($message, 76, "\n"));
+
+                    $ics = new Horde_Mime_Part();
+                    $ics->setType('text/calendar');
+                    $ics->setCharset($charset);
+                    $ics->setContents($vCal->exportvCalendar());
+                    $ics->setName('event-reply.ics');
+                    $ics->setContentTypeParameter('METHOD', 'REPLY');
+
+                    $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($subject, $charset));
+
+                    // Send the reply.
+                    $mail_driver = IMP_Compose::getMailDriver();
+                    try {
+                        $mime->send($organizerEmail, $msg_headers,
+                                    $mail_driver['driver'],
+                                    $mail_driver['params']);
+                        $msgs[] = array('success', _("Reply Sent."));
+                    } catch (Horde_Mime_Exception $e) {
+                        $msgs[] = array('error', sprintf(_("Error sending reply: %s."), $e->getMessage()));
+                    }
+                } else {
+                    $msgs[] = 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);
+
+                    $message = _("Attached is a reply to a calendar request you sent.");
+                    $body = new Horde_Mime_Part('text/plain',
+                                          String::wrap($message, 76, "\n"),
+                                          $charset);
+
+                    $ics = new Horde_Mime_Part('text/calendar', $vCal->exportvCalendar());
+                    $ics->setName('icalendar.ics');
+                    $ics->setContentTypeParameter('METHOD', 'REPLY');
+                    $ics->setCharset($charset);
+
+                    $mime = new Horde_Mime_Part();
+                    $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"), $charset));
+
+                    // Send the reply.
+                    $mail_driver = IMP_Compose::getMailDriver();
+                    try {
+                        $mime->send($organizerEmail, $msg_headers,
+                                    $mail_driver['driver'],
+                                    $mail_driver['params']);
+                        $msgs[] = array('success', _("Reply Sent."));
+                    } catch (Horde_Mime_Exception $e) {
+                        $msgs[] = array('error', sprintf(_("Error sending reply: %s."), $e->getMessage()));
+                    }
+                } else {
+                    $msgs[] = array('warning', _("Invalid Action selected for this component."));
+                }
+                break;
+
+            case 'nosup':
+                // vFreebusy request.
+            default:
+                $msgs[] = array('warning', _("This action is not yet implemented."));
+                break;
+            }
+        }
+
+        // Create the HTML to display the iCal file.
+        $html = '';
+        if ($_SESSION['imp']['view'] == 'imp') {
+            $html .= '<form method="post" name="iCal" action="' . (IMP::selfUrl()) . '">';
+        }
+
+        foreach ($components as $key => $component) {
+            switch ($component->getType()) {
+            case 'vEvent':
+                $html .= $this->_vEvent($component, $key, $method, $msgs);
+                break;
+
+            case 'vTodo':
+                $html .= $this->_vTodo($component, $key, $method, $msgs);
+                break;
+
+            case 'vTimeZone':
+                // Ignore them.
+                break;
+
+            case 'vFreebusy':
+                $html .= $this->_vFreebusy($component, $key, $method, $msgs);
+                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']['view'] == 'imp') {
+            $html .= '</form>';
+        }
+
+        return array(
+            $mime_id = array(
+                'data' => $html,
+                'status' => array(),
+                'type' => 'text/html; charset=' . $charset
+            )
+        );
+    }
+
+    /**
+     * Return the html for a vFreebusy.
+     */
+    protected function _vFreebusy($vfb, $id, $method, $msgs)
+    {
+        global $registry, $prefs;
+
+        $desc = $html = '';
+        $sender = $vfb->getName();
+
+        switch ($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>';
+
+        foreach ($msgs 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']['view'] != 'imp') {
+            return $html;
+        }
+
+        $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
+            '<select name="itip_action[' . $id . ']">';
+
+        switch ($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, $method, $msgs)
+    {
+        global $registry, $prefs;
+
+        $desc = $html = '';
+        $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 ($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>';
+
+        foreach ($msgs 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']['view'] != 'imp') {
+            return $html;
+        }
+
+        if ($options) {
+            $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
+                '<label for="action_' . $id . '" class="hidden">' . _("Actions") . '</label>' .
+                '<select id="action_' . $id . '" name="itip_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, $method, $msgs)
+    {
+        global $registry, $prefs;
+
+        $desc = $html = '';
+        $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 ($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>';
+
+        foreach ($msgs 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']['view'] != 'imp') {
+            return $html;
+        }
+
+        if ($options) {
+            $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
+                '<select name="itip_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");
+
+        case 'DECLINED':
+            return _("Declined");
+
+        case 'TENTATIVE':
+            return _("Tentatively Accepted");
+
+        case 'DELEGATED':
+            return _("Delegated");
+
+        case 'COMPLETED':
+            return _("Completed");
+
+        case 'IN-PROCESS':
+            return _("In Process");
+
+        case 'NEEDS-ACTION':
+        default:
+            return is_null($default) ? _("Needs Action") : $default;
+        }
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Mdn.php b/imp/lib/Mime/Viewer/Mdn.php
new file mode 100644 (file)
index 0000000..5755bfb
--- /dev/null
@@ -0,0 +1,105 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Mdn class handles multipart/report messages that
+ * that refer to message disposition notification (MDN) messages (RFC 3798).
+ *
+ * Copyright 2003-2009 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_Mdn extends Horde_Mime_Viewer_Driver
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => true,
+        'full' => false,
+        'info' => true,
+        'inline' => true,
+    );
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        /* If this is a straight message/disposition-notification part, just
+         * output the text. */
+        if ($this->_mimepart->getType() == 'message/disposition-notification') {
+            return $this->_params['contents']->renderMIMEPart($this->_mimepart->getMIMEId(), IMP_Contents::RENDER_FULL, array('type' => 'text/plain', 'params' => $this->_params));
+        }
+
+        return $this->_renderInfo();
+    }
+
+    /**
+     * Return the rendered information about the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInfo()
+    {
+        $mdn_id = $this->_mimepart->getMimeId();
+        $parts = array_keys($this->_mimepart->contentTypeMap());
+
+        $status = array(
+            array(
+                'icon' => Horde::img('info_icon.png', _("Info"), null, $GLOBALS['registry']->getImageDir('horde')),
+                'text' => array(_("A message you have sent has resulted in a return notification from the recipient."))
+            )
+        );
+
+        /* RFC 3798 [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. */
+        reset($parts);
+        $curr_id = $first_id = next($parts);
+        $first_part = $this->_params['contents']->renderMIMEPart($curr_id, IMP_Contents::RENDER_INLINE_AUTO, array('params' => $this->_params));
+
+        /* Display a link to more detailed message. */
+        $curr_id = Horde_Mime::mimeIdArithmetic($curr_id, 'next');
+        $part = $this->_params['contents']->getMIMEPart($curr_id);
+        if ($part) {
+            $status[0]['text'][] = sprintf(_("Additional information can be viewed %s."), $this->_params['contents']->linkViewJS($part, 'view_attach', _("HERE"), array('jstext' => _("Additional information details"), 'params' => array('mode' => IMP_Contents::RENDER_INLINE))));
+        }
+
+        /* Display a link to the sent message. Try to download the text of
+           the message/rfc822 part first, if it exists. */
+        $curr_id = Horde_Mime::mimeIdArithmetic($curr_id, 'next');
+        $part = $this->_params['contents']->getMIMEPart($curr_id);
+        if ($part) {
+            $status[0]['text'][] = sprintf(_("The text of the sent message can be viewed %s."), $this->_params['contents']->linkViewJS($part, 'view_attach', _("HERE"), array('jstext' => _("The text of the sent message"))));
+        }
+
+        if (empty($first_part)) {
+            $data = '';
+        } else {
+            $status[0]['text'][] = _("The mail server generated the following informational message:");
+            $status = array_merge($status, $first_part[$first_id]['status']);
+            $data = $first_part[$first_id]['data'];
+        }
+
+        $ret = array_combine($parts, array_fill(0, count($parts), null));
+        $ret[$mdn_id] = array(
+            'data' => $data,
+            'status' => $status,
+            'type' => 'text/html; charset=' . NLS::getCharset()
+        );
+
+        return $ret;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Partial.php b/imp/lib/Mime/Viewer/Partial.php
new file mode 100644 (file)
index 0000000..4572198
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Partial class allows message/partial messages
+ * to be displayed (RFC 2046 [5.2.2]).
+ *
+ * Copyright 2003-2009 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
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => true,
+        'forceinline' => true,
+        'full' => false,
+        'info' => false,
+        'inline' => false,
+    );
+
+    /**
+     * If this MIME part can contain embedded MIME parts, and those embedded
+     * MIME parts exist, return a list of MIME parts that contain the embedded
+     * MIME part information.
+     *
+     * @return array  An array of Horde_Mime_Part objects, with the key as
+     *                the ID, or null if no embedded MIME parts exist.
+     */
+    protected function _getEmbeddedMimeParts()
+    {
+        $id = $this->_mimepart->getContentTypeParameter('id');
+        $number = $this->_mimepart->getContentTypeParameter('number');
+        $total = $this->_mimepart->getContentTypeParameter('total');
+
+        if (is_null($id) || is_null($number) || is_null($total)) {
+            return null;
+        }
+
+        $mbox = $this->_params['contents']->getMailbox();
+
+        /* Perform the search to find the other parts of the message. */
+        $query = new Horde_Imap_Client_Search_Query();
+        $query->headerText('Content-Type', $id);
+        $indices = $GLOBALS['imp_search']->runSearchQuery($query, $mbox);
+
+        /* If not able to find the other parts of the message, print error. */
+        if (count($indices) != $total) {
+            $mime_part = new Horde_Mime_Part();
+            $mime_part->setType('text/plain');
+            $mime_part->setCharset(NLS::getCharset());
+            $mime_part->setContents(sprintf(_("[Cannot display message - found only %s of %s parts of this message in the current mailbox.]"), count($indices), $total));
+            return array($this->_mimepart->getMimeId() => $mime_part);
+        }
+
+        /* Get the contents of each of the parts. */
+        $parts = array();
+        foreach ($indices as $val) {
+            /* No need to fetch the current part again. */
+            if ($val == $number) {
+                $parts[$number] = $this->_mimepart->getContents();
+            } else {
+                $ic = &IMP_Contents::singleton($val . IMP::IDX_SEP . $mbox);
+                $parts[$ic->getMIMEMessage()->getContentTypeParameter('number')] = $ic->getBody();
+            }
+        }
+
+        /* Sort the parts in numerical order. */
+        ksort($parts, SORT_NUMERIC);
+
+        /* Combine the parts. */
+        $mime_part = Horde_Mime_Part::parseMessage(implode('', $parts));
+        return ($mime_part === false)
+            ? null
+            : array($this->_mimepart->getMimeId() => $mime_part);
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Pdf.php b/imp/lib/Mime/Viewer/Pdf.php
new file mode 100644 (file)
index 0000000..a2e9a74
--- /dev/null
@@ -0,0 +1,131 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Pdf class enables generation of thumbnails for
+ * PDF attachments.
+ *
+ * Copyright 2008-2009 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_Pdf
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => false,
+        'full' => true,
+        'info' => true,
+        'inline' => false
+    );
+
+    /**
+     * Return the full rendered version of the Horde_Mime_Part object.
+     *
+     * URL parameters used by this function:
+     * <pre>
+     * 'pdf_view_thumbnail' - (boolean) Output the thumbnail info.
+     * </pre>
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _render()
+    {
+        /* Create the thumbnail and display. */
+        if (!Util::getFormData('pdf_view_thumbnail')) {
+            return parent::_render();
+        }
+
+        $img = $this->_getHordeImageOb(true);
+
+        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');
+        }
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => $data,
+                'status' => array(),
+                'type' => $type
+            )
+        );
+    }
+
+    /**
+     * Return the rendered information about the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInfo()
+    {
+        /* Check to see if convert utility is available. */
+        if (!$this->_getHordeImageOb(false)) {
+            return array();
+        }
+
+        $status = array(
+            sprintf(_("A PDF file named %s is attached to this message. A thumbnail is below."), $this->_mimepart->getName(true)),
+        );
+
+        if ($GLOBALS['browser']->hasFeature('javascript')) {
+            $status[] = $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('pdf_view_thumbnail' => 1)), false), _("View Attachment"), null, ''), null, null, null);
+        } else {
+            $status[] = Horde::link($this->_params['contents']->urlView($this->_mimepart, 'view_attach')) . Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('pdf_view_thumbnail' => 1)), false), _("View Attachment"), null, '') . '</a>';
+        }
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => '',
+                'status' => array(
+                    array(
+                        'icon' => Horde::img('mime/image.png', _("Thumbnail of attached PDF file")),
+                        'text' => $status
+                    )
+                ),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+    }
+
+    /**
+     * Return a Horde_Image object.
+     *
+     * @param boolean $load  Whether to load the image data.
+     *
+     * @return mixed  The Hore_Image object, or false on error.
+     */
+    protected function _getHordeImageOb($load)
+    {
+        if (empty($GLOBALS['conf']['image']['convert'])) {
+            return false;
+        }
+
+        $img = &Horde_Image::singleton('im', array('temp' => Horde::getTempdir()));
+        if (is_a($img, 'PEAR_Error')) {
+            return false;
+        }
+
+        if ($load) {
+            $ret = $img->loadString(1, $this->_mimepart->getContents());
+            if (is_a($ret, 'PEAR_Error')) {
+                return false;
+            }
+        }
+
+        return $img;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Pgp.php b/imp/lib/Mime/Viewer/Pgp.php
new file mode 100644 (file)
index 0000000..d5e78fd
--- /dev/null
@@ -0,0 +1,408 @@
+<?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 (in multipart/encrypted part)
+ *   application/pgp-keys
+ *   application/pgp-signature (in multipart/signed part)
+ *
+ * This class may add the following parameters to the URL:
+ *   'pgp_verify_msg' - (boolean) Do verification of PGP signed data.
+ *   'rawpgpkey' - (boolean) Display the PGP Public Key in raw, text format
+ *
+ * Copyright 2002-2009 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
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => true,
+        'forceinline' => true,
+        'full' => false,
+        'info' => false,
+        'inline' => true
+    );
+
+    /**
+     * IMP_Crypt_Pgp object.
+     *
+     * @var IMP_Crypt_Pgp
+     */
+    protected $_imppgp;
+
+    /**
+     * The address of the sender.
+     *
+     * @var string
+     */
+    protected $_address = null;
+
+    /**
+     * Cache for inline data.
+     *
+     * @var array
+     */
+    static protected $_inlinecache = array();
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        if (empty($this->_imppgp) &&
+            !empty($GLOBALS['conf']['utils']['gnupg'])) {
+            $this->_imppgp = Horde_Crypt::singleton(array('IMP', 'Pgp'));
+        }
+
+        if (Util::getFormData('rawpgpkey')) {
+            return array(
+                $this->_mimepart->getMimeId() => array(
+                    'data' => $this->_mimepart->getContents(),
+                    'status' => array(),
+                    'type' => 'text/plain; charset=' . $this->_mimepart->getCharset()
+                )
+            );
+        }
+
+        /* Determine the address of the sender. */
+        if (is_null($this->_address)) {
+            $headers = $this->_params['contents']->getHeaderOb();
+            $this->_address = Horde_Mime_Address::bareAddress($headers->getValue('from'));
+        }
+
+        switch ($this->_mimepart->getType()) {
+        case 'application/pgp-keys':
+            return $this->_outputPGPKey();
+
+        case 'multipart/signed':
+            return $this->_outputPGPSigned();
+
+        case 'multipart/encrypted':
+            return $this->_outputPGPEncrypted();
+
+        case 'application/pgp-encrypted':
+        case 'application/pgp-signature':
+        default:
+            return array();
+        }
+    }
+
+    /**
+     * If this MIME part can contain embedded MIME parts, and those embedded
+     * MIME parts exist, return an altered version of the Horde_Mime_Part that
+     * contains the embedded MIME part information.
+     *
+     * @return mixed  A Horde_Mime_Part with the embedded MIME part information
+     *                or null if no embedded MIME parts exist.
+     */
+    protected function _getEmbeddedMimeParts()
+    {
+        if ($this->_mimepart->getType() != 'multipart/encrypted') {
+            return null;
+        }
+
+        $partlist = array_keys($this->_mimepart->contentTypeMap());
+        $base_id = reset($partlist);
+        $version_id = next($partlist);
+        $data_id = Horde_Mime::mimeIdArithmetic($version_id, 'next');
+
+        /* Initialize inline data. */
+        $resymmetric = isset(self::$_inlinecache[$base_id]);
+        self::$_inlinecache[$base_id] = array(
+            $base_id => array(
+                'data' => '',
+                'status' => array(
+                    array(
+                        'icon' => Horde::img('mime/encryption.png', 'PGP'),
+                        'text' => $resymmetric ? self::$_inlinecache[$base_id][$base_id]['status'][0]['text'] : array()
+                    )
+                ),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            ),
+            $version_id => null,
+            $data_id => null
+        );
+        $status = &self::$_inlinecache[$base_id][$base_id]['status'][0]['text'];
+
+        /* Is PGP active? */
+        if (empty($GLOBALS['conf']['utils']['gnupg']) ||
+            !$GLOBALS['prefs']->getValue('use_pgp')) {
+            $status[] = _("The message below has been encrypted via PGP, however, PGP support is disabled so the message cannot be decrypted.");
+            return null;
+        }
+
+        if (empty($this->_imppgp)) {
+            $this->_imppgp = Horde_Crypt::singleton(array('IMP', 'Pgp'));
+        }
+
+        /* PGP version 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. */
+        $encrypted_part = $this->_params['contents']->getMIMEPart($data_id);
+        $encrypted_data = $encrypted_part->getContents();
+
+        $symmetric_pass = $personal_pass = null;
+
+        /* Check if this a symmetrically encrypted message. */
+        try {
+            $symmetric = $this->_imppgp->encryptedSymmetrically($encrypted_data);
+            if ($symmetric) {
+                $symmetric_id = $this->_getSymmetricID();
+                $symmetric_pass = $this->_imppgp->getPassphrase('symmetric', $symmetric_id);
+
+                if (is_null($symmetric_pass)) {
+                    $js_action = '';
+                    if (!$resymmetric) {
+                        $status[] = _("The message has been encrypted via PGP.");
+                    }
+
+                    switch ($_SESSION['imp']['view']) {
+                    case 'dimp':
+                        $js_action = 'DimpCore.reloadMessage({});';
+                        // Fall through
+
+                    case 'imp':
+                        /* Ask for the correct passphrase if this is encrypted
+                         * symmetrically. */
+                        $status[] = Horde::link('#', '', '', '', IMP::passphraseDialogJS('PGPSymmetric', $js_action, array('symmetricid' => $symmetric_id)) . ';return false;') . _("You must enter the passphrase used to encrypt this message to view it.") . '</a>';
+                        break;
+                    }
+                    return null;
+                }
+            }
+        } catch (Horde_Exception $e) {
+            Horde::logMessage($e, __FILE__, __LINE__);
+            unset(self::$_inlinecache[$base_id]);
+            return null;
+        }
+
+        /* Check if this is a literal compressed message. */
+        try {
+            $info = $this->_imppgp->pgpPacketInformation($encrypted_data);
+        } catch (Horde_Exception $e) {
+            Horde::logMessage($e, __FILE__, __LINE__);
+            unset(self::$_inlinecache[$base_id]);
+            return null;
+        }
+        $literal = !empty($info['literal']);
+
+        if ($literal) {
+            $status[] = _("The message below has been compressed via PGP.");
+        } else {
+            $status[] = _("The message below has been encrypted via PGP.");
+            if (!$symmetric) {
+                if (!$this->_imppgp->getPersonalPrivateKey()) {
+                    /* Output if there is no personal private key to decrypt
+                     * with. */
+                    $status[] = _("The message below has been encrypted via PGP, however, no personal private key exists so the message cannot be decrypted.");
+                    return null;
+                } else {
+                    $personal_pass = $this->_imppgp->getPassphrase('personal');
+
+                    if (is_null($personal_pass)) {
+                        $js_action = '';
+                        $status[] = _("The message has been encrypted via PGP.");
+
+                        switch ($_SESSION['imp']['view']) {
+                        case 'dimp':
+                            $js_action = 'DimpCore.reloadMessage({});';
+                            // Fall through
+
+                        case 'imp':
+                            /* Ask for the private key's passphrase if this is
+                             * encrypted asymmetrically. */
+                            $status[] = Horde::link('#', '', '', '', IMP::passphraseDialogJS('PGPPersonal', $js_action) . ';return false;') . _("You must enter the passphrase for your PGP private key to view this message.") . '</a>';
+                            break;
+                        }
+                        return null;
+                    }
+                }
+            }
+        }
+
+        try {
+            if (!is_null($symmetric_pass)) {
+                $decrypted_data = $this->_imppgp->decryptMessage($encrypted_data, 'symmetric', $symmetric_pass);
+            } elseif (!is_null($personal_pass)) {
+                $decrypted_data = $this->_imppgp->decryptMessage($encrypted_data, 'personal', $personal_pass);
+            } else {
+                $decrypted_data = $this->_imppgp->decryptMessage($encrypted_data, 'literal');
+            }
+        } catch (Horde_Exception $e) {
+            $status[] = _("The message below does not appear to be a valid PGP encrypted message. Error: ") . $e->getMessage();
+            if (!is_null($symmetric_pass)) {
+                $this->_imppgp->unsetPassphrase('symmetric', $this->_getSymmetricID());
+                return $this->_getEmbeddedMimeParts();
+            }
+            return null;
+        }
+
+        unset(self::$_inlinecache[$base_id][$data_id]);
+
+        $msg = Horde_Mime_Part::parseMessage($decrypted_data->message);
+        $msg->buildMimeIds($data_id);
+
+        return array($data_id => $msg);
+    }
+
+    /**
+     * Generates output for 'application/pgp-keys' MIME_Parts.
+     *
+     * @return string  The HTML output.
+     */
+    protected function _outputPGPKey()
+    {
+        /* Initialize status message. */
+        $status = array(
+            'icon' => Horde::img('mime/encryption.png', 'PGP'),
+            'text' => array(
+                _("A PGP Public Key was attached to the message.")
+            )
+        );
+
+        $mime_id = $this->_mimepart->getMimeId();
+
+        if ($GLOBALS['prefs']->getValue('use_pgp') &&
+            $GLOBALS['prefs']->getValue('add_source') &&
+            $GLOBALS['registry']->hasMethod('contacts/addField')) {
+            $status['text'][] = Horde::link('#', '', '', '', $this->_imppgp->savePublicKeyURL($this->_params['contents']->getMailbox(), $this->_params['contents']->getIndex(), $mime_id) . 'return false;') . _("[Save the key to your Address book]") . '</a>';
+        }
+        $status['text'][] = $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("View the raw text of the Public Key."), array('params' => array('mode' => IMP_Contents::RENDER_INLINE, 'rawpgpkey' => 1)));
+
+        try {
+            $data = '<span class="fixed">' . nl2br(str_replace(' ', '&nbsp;', $this->_imppgp->pgpPrettyKey($this->_mimepart->getContents()))) . '</span>';
+        } catch (Horde_Exception $e) {
+            $data = $e->getMessage();
+        }
+
+        return array(
+            $mime_id => array(
+                'data' => $data,
+                'status' => array($status),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+    }
+
+    /**
+     * Generates HTML output for 'multipart/signed' MIME parts.
+     *
+     * @return string  The HTML output.
+     */
+    protected function _outputPGPSigned()
+    {
+        $partlist = array_keys($this->_mimepart->contentTypeMap());
+        $base_id = reset($partlist);
+        $signed_id = next($partlist);
+        $sig_id = Horde_Mime::mimeIdArithmetic($signed_id, 'next');
+
+        $ret = array(
+            $base_id => array(
+                'data' => '',
+                'status' => array(
+                    array(
+                        'icon' => Horde::img('mime/encryption.png', 'PGP'),
+                        'text' => array()
+                    )
+                ),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            ),
+            $sig_id => null
+        );
+        $status = &$ret[$base_id]['status'][0]['text'];
+
+        if (!$GLOBALS['prefs']->getValue('use_pgp') ||
+            empty($GLOBALS['conf']['utils']['gnupg'])) {
+            /* If PGP not active, hide signature data and output status
+             * information. */
+            $status[] = _("The message below has been digitally signed via PGP, but the signature cannot be verified.");
+            return $ret;
+        }
+
+        $status[] = _("The message below has been digitally signed via PGP.");
+
+        if ($GLOBALS['prefs']->getValue('pgp_verify') ||
+            Util::getFormData('pgp_verify_msg')) {
+            $signed_data = $GLOBALS['imp_imap']->utils->removeBareNewlines($this->_params['contents']->getBodyPart($signed_id, array('mimeheaders' => true)));
+            $sig_part = $this->_params['contents']->getMIMEPart($sig_id);
+
+            /* Check for the 'x-imp-pgp-signature' param. This is set by the
+             * plain driver when parsing PGP armor text. */
+            $graphicsdir = $GLOBALS['registry']->getImageDir('horde');
+            try {
+                $sig_result = $sig_part->getContentTypeParameter('x-imp-pgp-signature')
+                    ? $this->_imppgp->verifySignature($signed_data, $this->_address)
+                    : $this->_imppgp->verifySignature($signed_data, $this->_address, $sig_part->getContents());
+
+                if ($sig_result->result) {
+                    $icon = Horde::img('alerts/success.png', _("Success"), null, $graphicsdir);
+                    $sig_text = $sig_result->message;
+                } else {
+                    $icon = Horde::img('alerts/warning.png', _("Warning"), null, $graphicsdir);
+                   $sig_text = _("The signature could not be checked because the sender's key could not be found.");
+                }
+            } catch (Horde_Exception $e) {
+                $icon = Horde::img('alerts/error.png', _("Error"), null, $graphicsdir);
+                $sig_text = $e->getMessage();
+            }
+
+            require_once 'Horde/Text/Filter.php';
+            $ret[$base_id]['status'][] = array(
+                'icon' => $icon,
+                'text' => array(
+                    Text_Filter::filter($sig_text, 'text2html', array('parselevel' => TEXT_HTML_NOHTML))
+                )
+            );
+        } else {
+            switch ($_SESSION['imp']['view']) {
+            case 'imp':
+                $status[] = Horde::link(Util::addParameter(IMP::selfUrl(), array('pgp_verify_msg' => 1))) . _("Click HERE to verify the message.") . '</a>';
+                break;
+
+            case 'dimp':
+                $status[] = Horde::link('#', '', 'pgpVerifyMsg') . _("Click HERE to verify the message.") . '</a>';
+                break;
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Generates HTML output for 'multipart/encrypted' MIME parts.
+     *
+     * @return string  The HTML output.
+     */
+    protected function _outputPGPEncrypted()
+    {
+        $id = $this->_mimepart->getMimeId();
+        return isset(self::$_inlinecache[$id])
+            ? self::$_inlinecache[$id]
+            : array();
+    }
+
+    /**
+     * Generates the symmetric ID for this message.
+     *
+     * @return string  Symmetric ID.
+     */
+    protected function _getSymmetricID()
+    {
+        return $this->_imppgp->getSymmetricID($this->_params['contents']->getMailbox(), $this->_params['contents']->getIndex(), $this->_mimepart->getMimeId());
+    }
+
+}
diff --git a/imp/lib/Mime/Viewer/Plain.php b/imp/lib/Mime/Viewer/Plain.php
new file mode 100644 (file)
index 0000000..4c83cd0
--- /dev/null
@@ -0,0 +1,293 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Plain class renders out text/plain MIME parts
+ * with URLs made into hyperlinks.
+ *
+ * Copyright 1999-2009 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
+{
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        global $conf, $prefs;
+
+        $mime_id = $this->_mimepart->getMimeId();
+        $type = 'text/html; charset=' . NLS::getCharset();
+
+        // Trim extra whitespace in the text.
+        $text = trim($this->_mimepart->getContents());
+        if ($text == '') {
+            return array(
+                $mime_id => array(
+                    'data' => '',
+                    'status' => array(),
+                    'type' => $type
+                )
+            );
+        }
+
+        // Convert to the local charset.
+        $text = String::convertCharset($text, $this->_mimepart->getCharset());
+
+        // 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);
+        }
+
+        $text = IMP::filterText($text);
+
+        /* Done processing if in mimp mode. */
+        if ($_SESSION['imp']['view'] == 'mimp') {
+            return array(
+                $mime_id => array(
+                    'data' => $text,
+                    'status' => array(),
+                    'type' => $type
+                )
+            );
+        }
+
+        // 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' => NLS::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, 'outputJS' => false);
+        }
+
+        // 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();
+        }
+
+        if ($prefs->getValue('emoticons')) {
+            $filters['emoticons'] = array('entities' => true);
+        }
+
+        // Run filters.
+        $text = Text_Filter::filter($text, array_keys($filters), array_values($filters));
+
+        // Wordwrap.
+        $text = str_replace(array('  ', "\n "), array(' &nbsp;', "\n&nbsp;"), $text);
+        if (!strncmp($text, ' ', 1)) {
+            $text = '&nbsp;' . substr($text, 1);
+        }
+
+        return array(
+            $mime_id => array(
+                'data' => '<div class="fixed leftAlign">' . "\n" . $text . '</div>',
+                'status' => array(),
+                'type' => $type
+            )
+        );
+    }
+
+    /**
+     * Does this MIME part possibly contain embedded MIME parts?
+     *
+     * @return boolean  True if this driver supports parsing embedded MIME
+     *                  parts.
+     */
+    public function embeddedMimeParts()
+    {
+        return (!empty($GLOBALS['conf']['utils']['gnupg']) && $GLOBALS['prefs']->getValue('pgp_scan_body')) || $this->getConfigParam('uudecode');
+    }
+
+    /**
+     * If this MIME part can contain embedded MIME parts, and those embedded
+     * MIME parts exist, return a list of MIME parts that contain the embedded
+     * MIME part information.
+     *
+     * @return mixed  An array of Horde_Mime_Part objects, with the key as
+     *                the ID, or null if no embedded MIME parts exist.
+     */
+    public function getEmbeddedMimeParts()
+    {
+        $ret = null;
+
+        if (!empty($GLOBALS['conf']['utils']['gnupg']) &&
+            $GLOBALS['prefs']->getValue('pgp_scan_body')) {
+            $ret = $this->_parsePGP();
+        }
+
+        if (is_null($ret) && $this->getConfigParam('uudecode')) {
+            $ret = $this->_parseUUencode();
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Scan text for armored PGP blocks and, if they exist, convert the part
+     * to the embedded MIME representation.
+     *
+     * @return mixed  See self::_getEmbeddedMimeParts().
+     */
+    protected function _parsePGP()
+    {
+        /* Avoid infinite loop. */
+        $imp_pgp = Horde_Crypt::singleton(array('IMP', 'Pgp'));
+        $parts = $imp_pgp->parsePGPData($this->_mimepart->getContents());
+        if (empty($parts) ||
+            ((count($parts) == 1) &&
+             ($parts[0]['type'] == Horde_Crypt_Pgp::ARMOR_TEXT))) {
+            return null;
+        }
+
+        $new_part = new Horde_Mime_Part();
+        $new_part->setType('multipart/mixed');
+        $charset = $this->_mimepart->getCharset();
+        $mime_id = $this->_mimepart->getMimeId();
+
+        while (list(,$val) = each($parts)) {
+            switch ($val['type']) {
+            case Horde_Crypt_Pgp::ARMOR_TEXT:
+                $part = new Horde_Mime_Part();
+                $part->setType('text/plain');
+                $part->setCharset($charset);
+                $part->setContents(implode("\n", $val['data']));
+                $new_part->addPart($part);
+                break;
+
+            case Horde_Crypt_Pgp::ARMOR_PUBLIC_KEY:
+                $part = new Horde_Mime_Part();
+                $part->setType('application/pgp-keys');
+                $part->setContents(implode("\n", $val['data']));
+                $new_part->addPart($part);
+                break;
+
+            case Horde_Crypt_Pgp::ARMOR_MESSAGE:
+                $part = new Horde_Mime_Part();
+                $part->setType('multipart/signed');
+                // TODO: add micalg parameter
+                $part->setContentTypeParameter('protocol', 'application/pgp-encrypted');
+
+                $part1 = new Horde_Mime_Part();
+                $part1->setType('application/pgp-encrypted');
+                $part1->setContents("Version: 1\n");
+
+                $part2 = new Horde_Mime_Part();
+                $part2->setType('application/octet-stream');
+                $part2->setContents($message_encrypt);
+                $part2->setDisposition('inline');
+
+                $part->addPart($part1);
+                $part->addPart($part2);
+
+                $new_part->addPart($part);
+                break;
+
+            case Horde_Crypt_Pgp::ARMOR_SIGNED_MESSAGE:
+                if (($sig = current($parts)) &&
+                    ($sig['type'] == Horde_Crypt_Pgp::ARMOR_SIGNATURE)) {
+                    $part = new Horde_Mime_Part();
+                    $part->setType('multipart/signed');
+                    // TODO: add micalg parameter
+                    $part->setContentTypeParameter('protocol', 'application/pgp-signature');
+
+                    $part1 = new Horde_Mime_Part();
+                    $part1->setType('text/plain');
+                    $part1->setCharset($charset);
+
+                    $part1_data = implode("\n", $val['data']);
+                    $part1->setContents(substr($part1_data, strpos($part1_data, "\n\n") + 2));
+
+                    $part2 = new Horde_Mime_Part();
+                    $part2->setType('application/x-imp-pgp-signature');
+                    $part2->setContents(String::convertCharset(implode("\n", $val['data']) . "\n" . implode("\n", $sig['data']), $charset));
+
+                    $part->addPart($part1);
+                    $part->addPart($part2);
+                    $new_part->addPart($part);
+
+                    next($parts);
+                }
+            }
+        }
+
+        $new_part->buildMimeIds($mime_id);
+
+        return array($mime_id => $new_part);
+    }
+
+    /**
+     * Scan text for UUencode data an, if it exists, convert the part to the
+     * embedded MIME representation.
+     *
+     * @return mixed  See self::_getEmbeddedMimeParts().
+     */
+    protected function _parseUUencode()
+    {
+        $text = String::convertCharset($this->_mimepart->getContents(), $this->_mimepart->getCharset());
+
+        /* Don't want to use convert_uudecode() here as there may be multiple
+         * files residing in the text. */
+        $files = &Mail_mimeDecode::uudecode($text);
+        if (empty($files)) {
+            return null;
+        }
+
+        $new_part = new Horde_Mime_Part();
+        $new_part->setType('multipart/mixed');
+        $mime_id = $this->_mimepart->getMimeId();
+
+        $text_part = new Horde_Mime_Part();
+        $text_part->setType('text/plain');
+        $text_part->setCharset(NLS::getCharset());
+        $text_part->setContents(preg_replace("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", "\n", $text));
+        $new_part->addPart($text_part);
+
+        reset($files);
+        while (list(,$file) = each($files)) {
+            $uupart = new Horde_Mime_Part();
+            $uupart->setType('application/octet-stream');
+            $uupart->setContents($file['filedata']);
+            $uupart->setName(strip_tags($file['filename']));
+            $new_part->addPart($uupart);
+        }
+
+        $new_part->buildMimeIds($mime_id);
+
+        return array($mime_id => $new_part);
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Related.php b/imp/lib/Mime/Viewer/Related.php
new file mode 100644 (file)
index 0000000..4a491a0
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Related class handles multipart/related
+ * (RFC 2387) messages.
+ *
+ * Copyright 2002-2009 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
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => true,
+        'full' => true,
+        'info' => false,
+        'inline' => true,
+    );
+
+    /**
+     * Return the full rendered version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _render()
+    {
+        return $this->_IMPrender(false);
+    }
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        return $this->_IMPrender(true);
+    }
+
+    /**
+     * Render out the currently set contents.
+     *
+     * @param boolean $inline  Are we viewing inline?
+     *
+     * @return array  See self::render().
+     */
+    protected function _IMPrender($inline)
+    {
+        $ids = array_keys($this->_mimepart->contentTypeMap());
+        $related_id = $this->_mimepart->getMimeId();
+
+        $cids = $ret = array();
+        $id = null;
+
+        /* Build a list of parts -> CIDs. */
+        foreach ($ids as $val) {
+            $ret[$val] = null;
+            if (strcmp($related_id, $val) !== 0) {
+                $part = $this->_mimepart->getPart($val);
+                $cids[$val] = $part->getContentId();
+            }
+        }
+
+        /* Look at the 'start' parameter to determine which part to start
+         * with. If no 'start' parameter, use the first part. RFC 2387
+         * [3.1] */
+        $start = $this->_mimepart->getContentTypeParameter('start');
+        if (!empty($start)) {
+            $id = array_search($id, $cids);
+        }
+
+        if (empty($id)) {
+            reset($ids);
+            $id = next($ids);
+        }
+
+        /* Only display if the start part (normally text/html) can be
+         * displayed inline -OR- we are viewing this part as an attachment. */
+        if ($inline &&
+            !$this->_params['contents']->canDisplay($id, IMP_Contents::RENDER_INLINE)) {
+            return array();
+        }
+
+
+        $render = $this->_params['contents']->renderMIMEPart($id, $inline ? IMP_Contents::RENDER_INLINE : IMP_Contents::RENDER_FULL, array('params' => array_merge($this->_params, array('related_id' => $id, 'related_cids' => $cids))));
+
+        if (!$inline) {
+            return $render;
+        }
+
+        foreach (array_keys($render) as $val) {
+            $ret[$val] = $render[$val];
+        }
+
+        return $ret;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Smil.php b/imp/lib/Mime/Viewer/Smil.php
new file mode 100644 (file)
index 0000000..5abd83f
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Smil renders SMIL documents to very basic HTML.
+ *
+ * Copyright 2006-2009 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
+{
+    /**
+     * 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'])) !== false)) {
+                $this->_content .= '<img src="' . $this->_params['contents']->urlView($rp, 'view_attach') . '" alt="" /><br />';
+            }
+            break;
+
+        case 'TEXT':
+            if (isset($attrs['SRC']) &&
+                (($rp = $this->_getRelatedLink($attrs['SRC'])) !== 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 (isset($this->_params['related_id']) &&
+            (($key = array_search(trim($cid, '<>', $this->_params['related_cids']))) !== false)) {
+            return $this->_param['contents']->getMIMEPart($key);
+        }
+
+        return false;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Smime.php b/imp/lib/Mime/Viewer/Smime.php
new file mode 100644 (file)
index 0000000..448cd5e
--- /dev/null
@@ -0,0 +1,331 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Smime 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/x-pkcs7-mime
+ *   application/pkcs7-signature (in multipart/signed part)
+ *   application/x-pkcs7-signature (in multipart/signed part)
+ *
+ * This class may add the following parameters to the URL:
+ *   'smime_verify_msg' - (boolean) Do verification of S.
+ *   'view_smime_key' - (boolean) Display the S/MIME Key.
+ *
+ * Copyright 2002-2009 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_Smime extends Horde_Mime_Viewer_Driver
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => true,
+        'forceinline' => true,
+        'full' => false,
+        'info' => false,
+        'inline' => true
+    );
+
+    /**
+     * IMP_Crypt_Smime object.
+     *
+     * @var IMP_Crypt_Smime
+     */
+    protected $_impsmime = null;
+
+    /**
+     * Cache for inline data.
+     *
+     * @var array
+     */
+    static protected $_inlinecache = array();
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        /* Check to see if S/MIME support is available. */
+        $this->_initSMIME();
+
+        if (Util::getFormData('view_smime_key')) {
+            return $this->_outputSMIMEKey();
+        }
+
+        if (is_null($this->_impsmime)) {
+            $this->_impsmime = false;
+        } else {
+            /* We need to insert JavaScript code now if S/MIME support is
+             * active. */
+            Horde::addScriptFile('prototype.js', 'horde', true);
+            Horde::addScriptFile('imp.js', 'imp', true);
+        }
+
+        switch ($this->_mimepart->getType()) {
+        case 'multipart/signed':
+            return $this->_outputSMIMESigned();
+
+        case 'application/pkcs7-mime':
+        case 'application/x-pkcs7-mime':
+            return $this->_outputSMIMEEncrypted();
+        }
+    }
+
+    /**
+     * If this MIME part can contain embedded MIME parts, and those embedded
+     * MIME parts exist, return an altered version of the Horde_Mime_Part that
+     * contains the embedded MIME part information.
+     *
+     * @return mixed  A Horde_Mime_Part with the embedded MIME part information
+     *                or null if no embedded MIME parts exist.
+     */
+    protected function _getEmbeddedMimeParts()
+    {
+        if (!in_array($this->_mimepart->getType(), array('application/pkcs7-mime', 'application/x-pkcs7-mime'))) {
+            return null;
+        }
+
+        // 'smime-type' must be empty or 'enveloped-data'
+        $smime_type = $this->_mimepart->getContentTypeParameter('smime-type');
+        if ($smime_type == 'signed-data') {
+            // TODO
+            return null;
+        }
+
+        $base_id = $this->_mimepart->getMimeId();
+
+        /* Initialize inline data. */
+        self::$_inlinecache[$base_id] = array(
+            $base_id => array(
+                'data' => '',
+                'status' => array(
+                    array(
+                        'icon' => Horde::img('mime/encryption.png', 'S/MIME'),
+                        'text' => array(_("This message has been encrypted via S/MIME."))
+                    )
+                ),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+        $status = &self::$_inlinecache[$base_id][$base_id]['status'][0]['text'];
+
+        /* Is PGP active? */
+        $this->_initSMIME();
+        if (empty($this->_impsmime)) {
+            $status[] = _("S/MIME support is not currently enabled so the message is unable to be decrypted.");
+            return null;
+        }
+
+        if (!$this->_impsmime->getPersonalPrivateKey()) {
+            $status[] = _("No personal private key exists so the message is unable to be decrypted.");
+            return null;
+        }
+
+        /* Make sure we have a passphrase. */
+        $passphrase = $this->_impsmime->getPassphrase();
+        if ($passphrase === false) {
+            $js_action = '';
+
+            switch ($_SESSION['imp']['view'] == 'imp') {
+            case 'dimp':
+                $js_action = 'DimpCore.reloadMessage({});';
+                // Fall through
+
+            case 'imp':
+                $status[] = Horde::link('#', '', '', '', IMP::passphraseDialogJS('SMIMEPersonal', $js_action) . ';return false;') . _("You must enter the passphrase for your S/MIME private key to view this message.") . '</a>';
+                break;
+            }
+            return null;
+        }
+
+        $raw_text = $GLOBALS['imp_imap']->utils->removeBareNewlines($this->_params['contents']->getBodyPart($this->_mimepart->getMimeId(), array('mimeheaders' => true)));
+
+        try {
+            $decrypted_data = $this->_impsmime->decryptMessage($raw_text);
+        } catch (Horde_Exception $e) {
+            $status[] = $e->getMessage();
+            return null;
+        }
+
+        return array($base_id => Horde_Mime_Part::parseMessage($decrypted_data));
+    }
+
+    /**
+     * Generates HTML output for the S/MIME key.
+     *
+     * @return string  The HTML output.
+     */
+    protected function _outputSMIMEKey()
+    {
+        if (empty($this->_impsmime)) {
+            return array();
+        }
+
+        $raw_text = $GLOBALS['imp_imap']->utils->removeBareNewlines($this->_params['contents']->getBodyPart($this->_mimepart->getMimeId(), array('mimeheaders' => true)));
+
+        try {
+            $sig_result = $this->_impsmime->verifySignature($raw_text);
+        } catch (Horde_Exception $e) {}
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => $this->_impsmime->certToHTML($sig_result->cert),
+                'status' => array(),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+    }
+
+    /**
+     * Init the S/MIME Horde_Crypt object.
+     */
+    protected function _initSMIME()
+    {
+        if (is_null($this->_impsmime) &&
+            $GLOBALS['prefs']->getValue('use_smime')) {
+            try {
+                $this->_impsmime = Horde_Crypt::singleton(array('IMP', 'Smime'));
+                $this->_impsmime->checkForOpenSSL();
+            } catch (Horde_Exception $e) {
+                $this->_impsmime = null;
+            }
+        }
+    }
+
+    /**
+     * Generates HTML output for 'multipart/signed' MIME parts.
+     *
+     * @return array  TODO
+     */
+    protected function _outputSMIMESigned()
+    {
+        $partlist = array_keys($this->_mimepart->contentTypeMap());
+        $base_id = reset($partlist);
+        $sig_id = Horde_Mime::mimeIdArithmetic(next($partlist), 'next');
+
+        $ret = array(
+            $base_id => array(
+                'data' => '',
+                'status' => array(
+                    array(
+                        'icon' => Horde::img('mime/encryption.png', 'S/MIME'),
+                        'text' => array(_("This message has been digitally signed via S/MIME."))
+                    )
+                ),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            ),
+            $sig_id => null
+        );
+        $status = &$ret[$base_id]['status'][0]['text'];
+
+        if (!$GLOBALS['prefs']->getValue('use_smime')) {
+            $status[] = _("S/MIME support is not enabled so the digital signature is unable to be verified.");
+            return $ret;
+        }
+
+        $raw_text = $base_id
+            ? $this->_params['contents']->getBodyPart($base_id, array('mimeheaders' => true))
+            : $this->_params['contents']->fullMessageText();
+        $raw_text = $GLOBALS['imp_imap']->utils->removeBareNewlines($raw_text);
+
+        $sig_result = null;
+
+        if ($GLOBALS['prefs']->getValue('smime_verify') ||
+            Util::getFormData('smime_verify_msg')) {
+            try {
+                $sig_result = $this->_impsmime->verifySignature($raw_text);
+            } catch (Horde_Exception $e) {
+                $ret[$base_id]['status'][0]['icon'] = ($e->getCode() == 'horde.warning')
+                    ? Horde::img('alerts/warning.png', _("Warning"), null, $graphicsdir)
+                    : Horde::img('alerts/error.png', _("Error"), null, $graphicsdir);
+                $status[] = $e->getMessage();
+                return $ret;
+            }
+        } else {
+            switch ($_SESSION['imp']['view']) {
+            case 'imp':
+                $status[] = Horde::link(Util::addParameter(IMP::selfUrl(), 'smime_verify_msg', 1)) . _("Click HERE to verify the message.") . '</a>';
+                break;
+
+            case 'dimp':
+                $status[] = Horde::link('#', '', 'smimeVerifyMsg') . _("Click HERE to verify the message.") . '</a>';
+                break;
+            }
+            return $ret;
+        }
+
+        $subpart = $this->_params['contents']->getMIMEPart($sig_id);
+        if (!isset($subpart)) {
+            try {
+                $msg_data = $this->_impsmime->extractSignedContents($raw_text);
+                $subpart = Horde_Mime_Part::parseMessage($msg_data);
+            } catch (Horde_Exception $e) {
+                $this->_status[] = $e->getMessage();
+                $subpart = $this->_mimepart;
+            }
+        }
+
+        $graphicsdir = $GLOBALS['registry']->getImageDir('horde');
+
+        $ret[$base_id]['status'][0]['icon'] = Horde::img('alerts/success.png', _("Success"), null, $graphicsdir);
+
+        /* This message has been verified but there was no output
+         * from the PGP program. */
+        if (empty($sig_result->result) || ($sig_result->result === true)) {
+            $email = (is_array($sig_result->email))
+                ? implode(', ', $sig_result->email)
+                : $sig_result->email;
+            $status[] = sprintf(_("The message has been verified. Sender: %s."), htmlspecialchars($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;
+            } else {
+                $subject = null;
+            }
+
+            if (!empty($subject) &&
+                $GLOBALS['registry']->hasMethod('contacts/addField') &&
+                $GLOBALS['prefs']->getValue('add_source')) {
+                $status[] = sprintf(_("The S/MIME certificate of %s: "), @htmlspecialchars($subject, ENT_COMPAT, NLS::getCharset())) . $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("View"), array('params' => array('mode' => IMP_Contents::RENDER_INLINE, 'view_smime_key' => 1))) . '/' . Horde::link('#', '', null, null, $this->_impsmime->savePublicKeyURL($sig_result->cert, $this->_params['contents']->getIndex(), $sig_id) . ' return false;') . _("Save in your Address Book") . '</a>';
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Generates output for encrypted S/MIME parts.
+     *
+     * @return array  TODO
+     */
+    protected function _outputSMIMEEncrypted()
+    {
+        $id = $this->_mimepart->getMimeId();
+        return isset(self::$_inlinecache[$id])
+            ? self::$_inlinecache[$id]
+            : array();
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Status.php b/imp/lib/Mime/Viewer/Status.php
new file mode 100644 (file)
index 0000000..2516df4
--- /dev/null
@@ -0,0 +1,148 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Status class handles multipart/report messages
+ * that refer to mail system administrative messages (RFC 3464).
+ *
+ * Copyright 2002-2009 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
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => true,
+        'full' => false,
+        'info' => true,
+        'inline' => true,
+    );
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        /* If this is a straight message/disposition-notification part, just
+         * output the text. */
+        if ($this->_mimepart->getType() == 'message/delivery-status') {
+            return $this->_params['contents']->renderMIMEPart($this->_mimepart->getMIMEId(), IMP_Contents::RENDER_FULL, array('type' => 'text/plain', 'params' => $this->_params));
+        }
+
+        return $this->_renderInfo();
+    }
+
+    /**
+     * Return the rendered information about the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInfo()
+    {
+        $parts = array_keys($this->_mimepart->contentTypeMap());
+
+        reset($parts);
+        $part1_id = next($parts);
+        $part2_id = Horde_Mime::mimeIdArithmetic($part1_id, 'next');
+        $part3_id = Horde_Mime::mimeIdArithmetic($part2_id, 'next');
+
+        /* 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 3464 [2.3.3]). It can be either 'failed',
+         * 'delayed', 'delivered', 'relayed', or 'expanded'. */
+
+        /* Get the action first - it appears in the second part. */
+        $action = null;
+        $part2 = $this->_params['contents']->getMIMEPart($part2_id);
+
+        foreach (explode("\n", $part2->getContents()) as $line) {
+            if (stristr($line, 'Action:') !== false) {
+                $action = strtolower(trim(substr($line, strpos($line, ':') + 1)));
+                if (strpos($action, ' ') !== false) {
+                    $action = substr($action, 0, strpos($action, ' '));
+                }
+                break;
+            }
+        }
+
+        if (is_null($action)) {
+            return array();
+        }
+
+        /* Get the correct text strings for the action type. */
+        switch ($action) {
+        case 'failed':
+        case 'delayed':
+            $status = array(
+                array(
+                    'icon' => Horde::img('alerts/error.png', _("Error"), null, $GLOBALS['registry']->getImageDir('horde')),
+                    'text' => array(
+                        _("ERROR: Your message could not be delivered."),
+                        sprintf(_("Additional error message details can be viewed %s."), $this->_params['contents']->linkViewJS($part2, 'view_attach', _("HERE"), array('jstext' => _("Additional message details"), 'params' => array('mode' => IMP_Contents::RENDER_INLINE))))
+                    )
+                )
+            );
+            $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':
+            $status = array(
+                array(
+                    'icon' => Horde::img('alerts/success.png', _("Success"), null, $GLOBALS['registry']->getImageDir('horde')),
+                    'text' => array(
+                        _("Your message was successfully delivered."),
+                        sprintf(_("Additional message details can be viewed %s."), $this->_params['contents']->linkViewJS($part2, 'view_attach', _("HERE"), array('jstext' => _("Additional message details"), 'params' => array('mode' => IMP_Contents::RENDER_INLINE))))
+                    )
+                )
+            );
+            $msg_link = _("The text of the message can be viewed %s.");
+            $msg_link_status = _("The text of the message");
+            break;
+        }
+
+        /* Print the human readable message. */
+        $first_part = $this->_params['contents']->renderMIMEPart($part1_id, IMP_Contents::RENDER_INLINE_AUTO, array('params' => $this->_params));
+
+        /* Display a link to the returned message, if it exists. */
+        $part3 = $this->_params['contents']->getMIMEPart($part3_id);
+        if ($part3) {
+            $status[0]['text'][] = sprintf($msg_link, $this->_params['contents']->linkViewJS($part3, 'view_attach', _("HERE"), array('jstext' => $msg_link_status, 'ctype' => 'message/rfc822')));
+        }
+
+        if (empty($first_part)) {
+            $data = '';
+        } else {
+            $status[0]['text'][] = _("The mail server generated the following informational message:");
+            $status = array_merge($status, $first_part[$part1_id]['status']);
+            $data = $first_part[$part1_id]['data'];
+        }
+
+        $ret = array_combine($parts, array_fill(0, count($parts), null));
+
+        $ret[$this->_mimepart->getMimeId()] = array(
+            'data' => $data,
+            'status' => $status,
+            'type' => 'text/html; charset=' . NLS::getCharset()
+        );
+
+        return $ret;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Tnef.php b/imp/lib/Mime/Viewer/Tnef.php
new file mode 100644 (file)
index 0000000..faf68e7
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+/**
+ * The IMP_Horde_Mime_Viewer_Tnef class allows MS-TNEF attachments to be
+ * displayed.
+ *
+ * Copyright 2002-2009 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
+{
+    /**
+     * Can this driver render various views?
+     *
+     * @var boolean
+     */
+    protected $_capability = array(
+        'embedded' => false,
+        'forceinline' => true,
+        'full' => true,
+        'info' => true,
+        'inline' => false
+    );
+
+    /**
+     * Return the full rendered version of the Horde_Mime_Part object.
+     *
+     * URL parameters used by this function:
+     * <pre>
+     * 'tnef_attachment' - (integer) The TNEF attachment to download.
+     * </pre>
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _render()
+    {
+        if (!Util::getFormData('tnef_attachment')) {
+            $ret = $this->_renderInfo();
+            reset($ret);
+            $ret[key($ret)]['data'] = '<html><body>' . $ret[key($ret)]['data'] . '</body></html>';
+            return $ret;
+        }
+
+        /* Get the data from the attachment. */
+        $tnef = &Horde_Compress::singleton('tnef');
+        $tnefData = $tnef->decompress($this->_mimepart->getContents());
+
+        /* Display the requested file. Its position in the $tnefData
+         * array can be found in '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)) {
+                return array(
+                    $this->_mimepart->getMimeId() => array(
+                        'data' => $text,
+                        'name' => $tnefData[$tnefKey]['name'],
+                        'status' => array(),
+                        'type' => $tnefData[$tnefKey]['type'] . '/' . $tnefData[$tnefKey]['subtype']
+                    )
+                );
+            }
+        }
+
+        // TODO: Error reporting
+        return array();
+    }
+
+    /**
+     * Return the rendered information about the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInfo()
+    {
+        /* Get the data from the attachment. */
+        $tnef = &Horde_Compress::singleton('tnef');
+        $tnefData = $tnef->decompress($this->_mimepart->getContents());
+
+        $text = '';
+
+        if (!count($tnefData)) {
+            $status = array(
+                'text' => array(_("No attachments found."))
+            );
+        } else {
+            $status = array(
+                'text' => array(_("The following files were attached to this part:"))
+            );
+
+            reset($tnefData);
+            while (list($key, $data) = each($tnefData)) {
+                $temp_part = $this->_mimepart;
+                $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 (in_array($type, array('application/octet-stream', 'application/base64'))) {
+                    $type = Horde_Mime_Magic::filenameToMIME($data['name']);
+                }
+                $temp_part->setType($type);
+
+                $link = $this->_params['contents']->linkView($temp_part, 'view_attach', htmlspecialchars($data['name']), array('jstext' => sprintf(_("View %s"), $data['name']), 'params' => array('tnef_attachment' => $key + 1)));
+                $text .= _("Attached File:") . '&nbsp;&nbsp;' . $link . '&nbsp;&nbsp;(' . $data['type'] . '/' . $data['subtype'] . ")<br />\n";
+            }
+        }
+
+        return array(
+            $this->_mimepart->getMimeId() => array(
+                'data' => $text,
+                'status' => array($status),
+                'type' => 'text/html; charset=' . NLS::getCharset()
+            )
+        );
+    }
+}
diff --git a/imp/lib/Mime/Viewer/Zip.php b/imp/lib/Mime/Viewer/Zip.php
new file mode 100644 (file)
index 0000000..504dcd2
--- /dev/null
@@ -0,0 +1,93 @@
+<?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-2009 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
+{
+    /**
+     * Return the full rendered version of the Horde_Mime_Part object.
+     *
+     * URL parameters used by this function:
+     * <pre>
+     * 'zip_attachment' - (integer) The ZIP attachment to download.
+     * </pre>
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _render()
+    {
+        if (!Util::getFormData('zip_attachment')) {
+            $this->_callback = array(&$this, '_IMPcallback');
+            return parent::_render();
+        }
+
+        /* Send the requested file. Its position in the zip archive is located
+         * in 'zip_attachment'. */
+        $data = $this->_mimepart->getContents();
+        $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)) {
+                return array(
+                    $this->_mimepart->getMimeId() => array(
+                        'data' => $text,
+                        'name' => basename($zipInfo[$fileKey]['name']),
+                        'status' => array(),
+                        'type' => 'application/octet-stream'
+                    )
+                );
+            }
+        }
+
+        // TODO: Error reporting
+        return array();
+    }
+
+    /**
+     * Return the rendered inline version of the Horde_Mime_Part object.
+     *
+     * @return array  See Horde_Mime_Viewer_Driver::render().
+     */
+    protected function _renderInline()
+    {
+        $this->_callback = array(&$this, '_IMPcallback');
+        return parent::_renderInline();
+    }
+
+    /**
+     * The function to use as a callback to _toHTML().
+     *
+     * @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 _IMPcallback($key, $val)
+    {
+        $name = preg_replace('/(&nbsp;)+$/', '', $val['name']);
+
+        if (!empty($val['size']) && (strstr($val['attr'], 'D') === false) &&
+            ((($val['method'] == 0x8) && Util::extensionExists('zlib')) ||
+             ($val['method'] == 0x0))) {
+            $mime_part = $this->_mimepart;
+            $mime_part->setName(basename($name));
+            $val['name'] = str_replace($name, $this->_params['contents']->linkView($mime_part, 'download_render', $name, array('jstext' => sprintf(_("View %s"), str_replace('&nbsp;', ' ', $name)), 'class' => 'fixed', 'params' => array('zip_attachment' => urlencode($key) + 1))), $val['name']);
+        }
+
+        return $val;
+    }
+}
diff --git a/imp/lib/Mime/Viewer/alternative.php b/imp/lib/Mime/Viewer/alternative.php
deleted file mode 100644 (file)
index 265d8ef..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_alternative class renders out messages from
- * multipart/alternative content types (RFC 2046 [5.1.4]).
- *
- * Copyright 2002-2009 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
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => true,
-        'full' => false,
-        'info' => false,
-        'inline' => true,
-    );
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        $base_id = $this->_mimepart->getMimeId();
-        $subparts = $this->_mimepart->contentTypeMap();
-
-        $base_ids = $display_ids = $ret = array();
-
-        /* Look for a displayable part. RFC: show the LAST choice that can be
-         * displayed inline. If an alternative is itself a multipart, the user
-         * agent is allowed to show that alternative, an earlier alternative,
-         * or both. If we find a multipart alternative that contains at least
-         * one viewable part, we will display all viewable subparts of that
-         * alternative. */
-        foreach (array_keys($subparts) as $mime_id) {
-            $ret[$mime_id] = null;
-            if ((strcmp($base_id, $mime_id) !== 0) &&
-                $this->_params['contents']->canDisplay($mime_id, IMP_Contents::RENDER_INLINE)) {
-                $display_ids[strval($mime_id)] = true;
-            }
-        }
-
-        /* If we found no IDs, return now. */
-        if (empty($display_ids)) {
-            $ret[$base_id] = array(
-                'data' => '',
-                'status' => array(
-                    array(
-                        'text' => array(_("There are no alternative parts that can be displayed inline.")),
-                        'type' => 'info'
-                    )
-                ),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            );
-            return $ret;
-        }
-
-        /* If the last viewable message exists in a subpart, back up to the
-         * base multipart and display all viewable parts in that multipart.
-         * Else, display the single part. */
-        end($display_ids);
-        $curr_id = key($display_ids);
-        while (!is_null($curr_id) && (strcmp($base_id, $curr_id) !== 0)) {
-            if (isset($subparts[$curr_id])) {
-                $disp_id = $curr_id;
-            }
-            $curr_id = Horde_Mime::mimeIdArithmetic($curr_id, 'up');
-        }
-
-        /* Now grab all keys under this ID. */
-        $render_part = $this->_mimepart->getPart($disp_id);
-        foreach (array_keys($render_part->contentTypeMap()) as $val) {
-            if (isset($display_ids[$val])) {
-                $render = $this->_params['contents']->renderMIMEPart($val, IMP_Contents::RENDER_INLINE, array('params' => $this->_params));
-                foreach (array_keys($render) as $id) {
-                    $ret[$id] = $render[$id];
-                    unset($display_ids[$id]);
-                }
-            }
-        }
-
-        return $ret;
-    }
-}
diff --git a/imp/lib/Mime/Viewer/appledouble.php b/imp/lib/Mime/Viewer/appledouble.php
deleted file mode 100644 (file)
index ca8e8cc..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_appledouble class handles multipart/appledouble
- * messages conforming to RFC 1740.
- *
- * Copyright 2003-2009 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
-{
-    /**
-     * This driver's capabilities.
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => true,
-        'full' => false,
-        'info' => true,
-        'inline' => true
-    );
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        return $this->_IMPrender(true);
-    }
-
-    /**
-     * Return the rendered information about the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInfo()
-    {
-        return $this->_IMPrender(false);
-    }
-
-    /**
-     * Render the part based on the view mode.
-     *
-     * @param boolean $inline  True if viewing inline.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _IMPrender($inline)
-    {
-        /* RFC 1740 [4]: There are two parts to an appledouble message:
-         *   (1) application/applefile
-         *   (2) Data embedded in the Mac file
-         * Since the resource fork is not very useful to us, only provide a
-         * means to download. */
-
-        /* Display the resource fork download link. */
-        $mime_id = $this->_mimepart->getMimeId();
-        $parts_list = array_keys($this->_mimepart->contentTypeMap());
-        reset($parts_list);
-        $applefile_id = next($parts_list);
-        $data_id = Horde_Mime::mimeIdArithmetic($applefile_id, 'next');
-
-        $applefile_part = $this->_mimepart->getPart($applefile_id);
-        $data_part = $this->_mimepart->getPart($data_id);
-
-        $data_name = $data_part->getName(true);
-        if (empty($data_name)) {
-            $data_name = _("unnamed");
-        }
-
-        $status = array(
-            'icon' => Horde::img('apple.png', _("Macintosh File")),
-            'text' => array(
-                sprintf(_("This message contains a Macintosh file (named \"%s\")."), $data_name),
-                sprintf(_("The Macintosh resource fork can be downloaded %s."), $this->_params['contents']->linkViewJS($applefile_part, 'download_attach', _("HERE"), array('jstext' => _("The Macintosh resource fork"))))
-            )
-        );
-
-        /* For inline viewing, attempt to display the data inline. */
-        $ret = array();
-        if ($inline && (($disp = $this->_params['contents']->canDisplay($data_part, IMP_Contents::RENDER_INLINE | IMP_Contents::RENDER_INFO)))) {
-            $ret = $this->_params['contents']->renderMIMEPart($data_id, $disp, array('params' => $this->_params));
-            $status['text'][] = _("The contents of the Macintosh file are below.");
-        } else {
-            $status['text'][] = sprintf(_("The contents of the Macintosh file can be downloaded %s."), $this->_params['contents']->linkViewJS($data_part, 'download_attach', _("HERE"), array('jstext' => _("The Macintosh file"))));
-        }
-
-        foreach ($parts_list as $val) {
-            if (!isset($ret[$val]) && (strcmp($val, $data_id) !== 0)) {
-                $ret[$val] = (strcmp($val, $mime_id) === 0)
-                    ? array(
-                          'data' => '',
-                          'status' => array($status),
-                          'type' => 'text/html; charset=' . NLS::getCharset()
-                      )
-                    : null;
-            }
-        }
-
-        ksort($ret);
-
-        return $ret;
-    }
-}
diff --git a/imp/lib/Mime/Viewer/enriched.php b/imp/lib/Mime/Viewer/enriched.php
deleted file mode 100644 (file)
index 4fc1940..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_enriched class renders out plain text from
- * enriched content tags, ala RFC 1896
- *
- * Copyright 2001-2009 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
-{
-    /**
-     * Return the full rendered version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _render()
-    {
-        $ret = parent::_render();
-        if (!empty($ret)) {
-            reset($ret);
-            $ret[key($ret)]['data'] = $this->_IMPformat($ret[key($ret)]['data']);
-        }
-        return $ret;
-    }
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        $ret = parent::_renderInline();
-        if (!empty($ret)) {
-            reset($ret);
-            $ret[key($ret)]['data'] = $this->_IMPformat($ret[key($ret)]['data']);
-        }
-        return $ret;
-    }
-
-    /**
-     * Format output text with IMP additions.
-     *
-     * @param string $text  The HTML text.
-     *
-     * @return string  The text with extra IMP formatting applied.
-     */
-    protected function _IMPformat($text)
-    {
-        // Highlight quoted parts of an email.
-        if ($GLOBALS['prefs']->getValue('highlight_text')) {
-            $text = implode("\n", preg_replace('|^(\s*&gt;.+)$|', '<span class="quoted1">\1</span>', explode("\n", $text)));
-            $indent = 1;
-            while (preg_match('|&gt;(\s?&gt;){' . $indent . '}|', $text)) {
-                $text = implode("\n", preg_replace('|^<span class="quoted' . ((($indent - 1) % 5) + 1) . '">(\s*&gt;(\s?&gt;){' . $indent . '}.+)$|', '<span class="quoted' . (($indent % 5) + 1) . '">\1', explode("\n", $text)));
-                ++$indent;
-            }
-        }
-
-        // Dim signatures.
-        if ($GLOBALS['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.
-        return IMP::filterText($text);
-    }
-}
diff --git a/imp/lib/Mime/Viewer/html.php b/imp/lib/Mime/Viewer/html.php
deleted file mode 100644 (file)
index ebb72b1..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_html class renders out HTML text with an effort
- * to remove potentially malicious code.
- *
- * Copyright 1999-2009 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';
-
-    /**
-     * Return the full rendered version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _render()
-    {
-        $render = $this->_IMPrender(false);
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => $render['html'],
-                'status' => $render['status'],
-                'type' => $this->_mimepart->getType(true)
-            )
-        );
-    }
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        $render = $this->_IMPrender(true);
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => $render['html'],
-                'status' => $render['status'],
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-    }
-
-    /**
-     * 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'];
-
-        /* We are done processing if in mimp mode. */
-        if ($_SESSION['imp']['view'] == 'mimp') {
-            require_once 'Horde/Text/Filter.php';
-            $data = Text_Filter::filter($data, 'html2text');
-
-            // Filter bad language.
-            return array('html' => IMP::filterText($data), 'status' => array());
-        }
-
-        /* 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 links that we can display (multipart/related
-         * parts). */
-        if (isset($this->_params['related_id'])) {
-            $cid_replace = array();
-
-            foreach ($this->_params['related_cids'] as $mime_id => $cid) {
-                $cid = trim($cid, '<>');
-                if ($cid) {
-                    $cid_part = $this->_params['contents']->getMIMEPart($mime_id);
-                    $cid_replace['cid:' . $cid] = $this->_params['contents']->urlView($cid_part, 'view_attach', array('params' => array('img_data' => 1)));
-                }
-            }
-
-            if (!empty($cid_replace)) {
-                $data = str_replace(array_keys($cid_replace), array_values($cid_replace), $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 class="htmlMessage">' . $data . '</div>';
-        }
-
-        /* Only display images if specifically allowed by user. */
-        if ($inline &&
-            !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(IMP::selfUrl(), array('actionID', 'index'));
-            $url = Util::addParameter($url, 'index', $this->_params['contents']->getIndex());
-
-            $view_img = Util::getFormData('view_html_images');
-            $addr_check = ($GLOBALS['prefs']->getValue('html_image_addrbook') && $this->_inAddressBook());
-
-            if (!$view_img && !$addr_check) {
-                $data .= Util::bufferOutput(array('Horde', 'addScriptFile'), 'prototype.js', 'horde', true) .
-                    Util::bufferOutput(array('Horde', 'addScriptFile'), 'imp.js', 'imp', true);
-
-                // Unblock javascript code in js/src/imp.js
-                $cleanhtml['status'][] = array(
-                    'icon' => Horde::img('mime/image.png'),
-                    'text' => array(
-                        String::convertCharset(_("Images have been blocked to protect your privacy."), $charset, $msg_charset),
-                        Horde::link(Util::addParameter($url, 'view_html_images', 1), '', 'unblockImageLink') . String::convertCharset(_("Show Images?"), $charset, $msg_charset) . '</a>'
-                    )
-                );
-
-                $data = preg_replace_callback($this->_img_regex, array($this, '_blockImages'), $data);
-            }
-        }
-
-        require_once 'Horde/Text/Filter.php';
-        if ($GLOBALS['prefs']->getValue('emoticons')) {
-            $data = Text_Filter::filter($data, array('emoticons'), array(array('emoticons' => true)));
-        }
-
-        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('&amp;', '&', trim($matches[5], '\'" '))) . '"'
-            : $matches[1] . "'" . $this->_blockimg . '\')' . $matches[6] . '" blocked="' . rawurlencode(str_replace('&amp;', '&', 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();
-        $headers = $this->_params['contents']->getHeaderOb();
-
-        /* Try to get back a result from the search. */
-        $res = $GLOBALS['registry']->call('contacts/getField', array(Horde_Mime_Address::bareAddress($headers->getValue('from')), '__key', $params['sources'], false, true));
-        return is_a($res, 'PEAR_Error') ? false : count($res);
-    }
-}
diff --git a/imp/lib/Mime/Viewer/images.php b/imp/lib/Mime/Viewer/images.php
deleted file mode 100644 (file)
index 8c6816a..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_images class allows display of images attached
- * to a message.
- *
- * Copyright 2002-2009 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
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => false,
-        'full' => true,
-        'info' => true,
-        'inline' => true
-    );
-
-    /**
-     * Return the full rendered version of the Horde_Mime_Part object.
-     *
-     * URL parameters used by this function:
-     * <pre>
-     * 'imp_img_view' - (string) One of the following:
-     *   'data' - Output the image directly.
-     *   'load_convert' - TODO
-     *   'view_convert' - TODO
-     *   'view_thumbnail' - TODO
-     * </pre>
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _render()
-    {
-        switch (Util::getFormData('imp_img_view')) {
-        case 'data':
-            /* If calling page is asking us to output data, do that without
-             * any further delay and exit. */
-            return parent::_render();
-
-        case 'view_convert':
-            /* Convert the image to browser-viewable format and display. */
-            return $this->_viewConvert(false);
-
-        case 'view_thumbnail':
-            /* Create the thumbnail and display. */
-            return $this->_viewConvert(true);
-
-        case 'load_convert':
-            /* The browser can display the image type directly - output the JS
-             * code to render the auto resize popup image window. */
-            return $this->_popupImageWindow();
-        }
-
-        return parent::_render();
-    }
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        /* Only display the image inline if the browser can display it and the
-         * size of the image is below the config value. */
-        if ($GLOBALS['browser']->isViewable($this->_getType())) {
-            if (isset($this->_conf['inlinesize']) &&
-                ($this->_mimepart->getBytes() < $this->_conf['inlinesize'])) {
-                /* Viewing inline, and the browser can handle the image type
-                 * directly. So output an <img> tag to load the image. */
-                return array(
-                    $this->_mimepart->getMimeId() => array(
-                        'data' => Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('imp_img_view' => 'data'))), $this->_mimepart->getName(true), null, ''),
-                        'status' => array(),
-                        'type' => 'text/html; charset=' . NLS::getCharset()
-                    )
-                );
-            } else {
-                return $this->_renderInfo();
-            }
-        }
-
-        /* The browser cannot view this image. Inform the user of this and
-         * ask user if we should convert to another image type. */
-        $status = array(_("Your browser does not support inline display of this image type."));
-
-        /* See if we can convert to an inline browser viewable form. */
-        if ($GLOBALS['browser']->hasFeature('javascript')) {
-            $img = $this->_getHordeImageOb(false);
-            if ($img &&
-                $GLOBALS['browser']->isViewable($img->getContentType())) {
-                $convert_link = $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("HERE"), array('params' => array('imp_img_view' => 'load_convert')));
-                $status[] = sprintf(_("Click %s to convert the image file into a format your browser can attempt to view."), $convert_link);
-            }
-        }
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => '',
-                'status' => array(
-                    array(
-                        'text' => $status
-                    )
-                ),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-    }
-
-    /**
-     * Return the rendered information about the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInfo()
-    {
-        /* Display the thumbnail link only if we show thumbs for all images or
-         * if image is over 50 KB. Also, check to see if convert utility is
-         * available. */
-        if ((!$this->getConfigParam('allthumbs') &&
-             ($this->_mimepart->getBytes() < 51200)) ||
-            !$this->_getHordeImageOb(false)) {
-            return array();
-        }
-
-        $status = array(sprintf(_("An image named %s is attached to this message. A thumbnail is below."), $this->_mimepart->getName(true)));
-
-        if ($GLOBALS['browser']->hasFeature('javascript')) {
-            $status[] = $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('imp_img_view' => 'view_thumbnail')), false), _("View Attachment"), null, ''), null, null, null);
-        } else {
-            $status[] = Horde::link($this->_params['contents']->urlView($this->_mimepart, 'view_attach')) . Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('imp_img_view' => 'view_thumbnail')), false), _("View Attachment"), null, '') . '</a>';
-        }
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => '',
-                'status' => array(
-                    array(
-                        'icon' => Horde::img('mime/image.png', _("Thumbnail of attached image")),
-                        'text' => $status
-                    )
-                ),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-    }
-
-    /**
-     * Generate the HTML output for the JS auto-resize view window.
-     *
-     * @return string  The HTML output.
-     */
-    protected function _popupImageWindow()
-    {
-        $self_url = Util::addParameter(IMP::selfUrl(), array('imp_img_view' => ((Util::getFormData('imp_img_view') == 'load_convert') ? 'view_convert' : 'data')));
-        $title = $this->_mimepart->getName(true);
-
-        $str = <<<EOD
-<html>
-<head>
-<title>$title</title>
-<style type="text/css"><!-- body { margin:0px; padding:0px; } --></style>
-EOD;
-
-        /* Only use javascript if we are using a DOM capable browser. */
-        if ($GLOBALS['browser']->getFeature('dom')) {
-            /* Javascript display. */
-            $loading = _("Loading...");
-            $str .= <<<EOD
-<script type="text/javascript">
-function resizeWindow()
-{
-
-    var h, img = document.getElementById('disp_image'), w;
-    document.getElementById('splash').style.display = 'none';
-    img.style.display = 'block';
-    window.moveTo(0, 0);
-    h = img.height - (self.innerHeight ? self.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight));
-    w = img.width - (self.innerWidth ? self.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth));
-    window.resizeBy(w, h);
-    self.focus();
-}
-</script></head>
-<body onload="resizeWindow();"><span id="splash" style="color:gray;font-family:sans-serif;padding:2px;">$loading</span><img id="disp_image" style="display:none;" src="$self_url" /></body></html>
-EOD;
-        } else {
-            /* Non-javascript display. */
-            $img_txt = _("Image");
-            $str .= <<<EOD
-</head>
-<body bgcolor="#ffffff">
-<img border="0" src="$self_url" alt="$img_txt" />
-</body>
-</html>
-EOD;
-        }
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => $str,
-                'status' => array(),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-    }
-
-    /**
-     * Convert image.
-     *
-     * @param boolean $thumb  View image in thumbnail size?
-     *
-     * @return string  The image data.
-     */
-    protected function _viewConvert($thumb)
-    {
-        $img = $this->_getHordeImageOb(true);
-
-        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');
-        }
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => $data,
-                'status' => array(),
-                'type' => $type
-            )
-        );
-    }
-
-    /**
-     * Return a Horde_Image object.
-     *
-     * @param boolean $load  Whether to load the image data.
-     *
-     * @return mixed  The Horde_Image object, or false on error.
-     */
-    protected function _getHordeImageOb($load)
-    {
-        $img = null;
-        $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);
-        }
-
-        if (!$img || is_a($img, 'PEAR_Error')) {
-            return false;
-        }
-
-        if ($load) {
-            $ret = $img->loadString(1, $this->_mimepart->getContents());
-            if (is_a($ret, 'PEAR_Error')) {
-                return false;
-            }
-        }
-
-        return $img;
-    }
-}
diff --git a/imp/lib/Mime/Viewer/itip.php b/imp/lib/Mime/Viewer/itip.php
deleted file mode 100644 (file)
index ec35afb..0000000
+++ /dev/null
@@ -1,967 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_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-2009 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
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => false,
-        'full' => true,
-        'info' => false,
-        'inline' => true
-    );
-
-    /**
-     * Return the full rendered version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _render()
-    {
-        $ret = $this->_renderInline();
-        if (!empty($ret)) {
-            reset($ret);
-            $ret[key($ret)]['data'] = Util::bufferOutput('include', $GLOBALS['registry']->get('templates', 'horde') . '/common-header.inc') .
-                $ret[key($ret)]['data'] .
-                Util::bufferOutput('include', $GLOBALS['registry']->get('templates', 'horde') . '/common-footer.inc');
-        }
-        return $ret;
-    }
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * URL parameters used by this function:
-     * <pre>
-     * 'identity' - (integer) TODO
-     * 'itip_action' - (array) TODO
-     * </pre>
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        global $registry;
-
-        $charset = NLS::getCharset();
-        $data = $this->_mimepart->getContents();
-        $mime_id = $this->_mimepart->getMimeId();
-
-        // Parse the iCal file.
-        $vCal = new Horde_iCalendar();
-        if (!$vCal->parsevCalendar($data, 'VCALENDAR', $this->_mimepart->getCharset())) {
-            return array(
-                $mime_id => array(
-                    'data' => '<h1>' . _("The calendar data is invalid") . '</h1>' . '<pre>' . htmlspecialchars($data) . '</pre>',
-                    'status' => array(),
-                    'type' => 'text/html; charset=' . $charset
-                )
-            );
-        }
-
-        // Check if we got vcard data with the wrong vcalendar mime type.
-        $c = $vCal->getComponentClasses();
-        if ((count($c) == 1) && !empty($c['horde_icalendar_vcard'])) {
-            return $this->_params['contents']->renderMIMEPart($mime_id, IMP_Contents::RENDER_INLINE, array('type' => 'text/x-vcard'));
-        }
-
-        // Get the method type.
-        $method = $vCal->getAttribute('METHOD');
-        if (is_a($method, 'PEAR_Error')) {
-            $method = '';
-        }
-
-        // Get the iCalendar file components.
-        $components = $vCal->getComponents();
-        $msgs = array();
-
-        // Handle the action requests.
-        $actions = Util::getFormData('itip_action', array());
-        foreach ($actions as $key => $action) {
-            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')) {
-                        $msgs[] = array('error', _("There was an error deleting the event:") . ' ' . $event->getMessage());
-                    } else {
-                        $msgs[] = array('success', _("Event successfully deleted."));
-                    }
-                } else {
-                    $msgs[] = 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')) {
-                        $msgs[] = array('error', _("There was an error updating the event:") . ' ' . $event->getMessage());
-                    } else {
-                        $msgs[] = array('success', _("Respondent Status Updated."));
-                    }
-                } else {
-                    $msgs[] = 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')) {
-                        // Try to update in calendar.
-                        if ($registry->hasMethod('calendar/replace')) {
-                            $result = $registry->call('calendar/replace', array('uid' => $guid, 'content' => $components[$key], 'contentType' => $this->mime_part->getType()));
-                            if (is_a($result, 'PEAR_Error')) {
-                                // Could be a missing permission.
-                                $msgs[] = array('warning', _("There was an error updating the event:") . ' ' . $result->getMessage() . '. ' . _("Trying to import the event instead."));
-                            } else {
-                                $handled = true;
-                                $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
-                                $msgs[] = array('success', _("The event was updated in your calendar.") .
-                                                             '&nbsp;' . Horde::link($url, _("View event"), null, '_blank') . Horde::img('mime/icalendar.png', _("View event"), null, $registry->getImageDir('horde')) . '</a>');
-                            }
-                        }
-                    }
-                    if (!$handled && $registry->hasMethod('calendar/import')) {
-                        // Import into calendar.
-                        $handled = true;
-                        $guid = $registry->call('calendar/import', array('content' => $components[$key], 'contentType' => $this->mime_part->getType()));
-                        if (is_a($guid, 'PEAR_Error')) {
-                            $msgs[] = array('error', _("There was an error importing the event:") . ' ' . $guid->getMessage());
-                        } else {
-                            $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
-                            $msgs[] = array('success', _("The event was added to your calendar.") .
-                                            '&nbsp;' . Horde::link($url, _("View event"), null, '_blank') . Horde::img('mime/icalendar.png', _("View event"), null, $registry->getImageDir('horde')) . '</a>');
-                        }
-                    }
-                    if (!$handled) {
-                        $msgs[] = 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')) {
-                            $msgs[] = array('error', _("There was an error importing user's free/busy information:") . ' ' . $res->getMessage());
-                        } else {
-                            $msgs[] = array('success', _("The user's free/busy information was sucessfully stored."));
-                        }
-                    } else {
-                        $msgs[] = 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')) {
-                            $msgs[] = array('error', _("There was an error importing the task:") . ' ' . $guid->getMessage());
-                        } else {
-                            $url = Horde::url($registry->link('tasks/show', array('uid' => $guid)));
-                            $msgs[] = array('success', _("The task has been added to your tasklist.") .
-                                                         '&nbsp;' . Horde::link($url, _("View task"), null, '_blank') . Horde::img('mime/icalendar.png', _("View task"), null, $registry->getImageDir('horde')) . '</a>');
-                        }
-                    } else {
-                        $msgs[] = array('warning', _("This action is not supported."));
-                    }
-                    break;
-
-                case 'vJournal':
-                default:
-                    $msgs[] = 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();
-                    $mime->setType('multipart/alternative');
-
-                    $body = new Horde_Mime_Part();
-                    $body->setType('text/plain');
-                    $body->setCharset($charset);
-                    $body->setContents(String::wrap($message, 76, "\n"));
-
-                    $ics = new Horde_Mime_Part();
-                    $ics->setType('text/calendar');
-                    $ics->setCharset($charset);
-                    $ics->setContents($vCal->exportvCalendar());
-                    $ics->setName('event-reply.ics');
-                    $ics->setContentTypeParameter('METHOD', 'REPLY');
-
-                    $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($subject, $charset));
-
-                    // Send the reply.
-                    $mail_driver = IMP_Compose::getMailDriver();
-                    try {
-                        $mime->send($organizerEmail, $msg_headers,
-                                    $mail_driver['driver'],
-                                    $mail_driver['params']);
-                        $msgs[] = array('success', _("Reply Sent."));
-                    } catch (Horde_Mime_Exception $e) {
-                        $msgs[] = array('error', sprintf(_("Error sending reply: %s."), $e->getMessage()));
-                    }
-                } else {
-                    $msgs[] = 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);
-
-                    $message = _("Attached is a reply to a calendar request you sent.");
-                    $body = new Horde_Mime_Part('text/plain',
-                                          String::wrap($message, 76, "\n"),
-                                          $charset);
-
-                    $ics = new Horde_Mime_Part('text/calendar', $vCal->exportvCalendar());
-                    $ics->setName('icalendar.ics');
-                    $ics->setContentTypeParameter('METHOD', 'REPLY');
-                    $ics->setCharset($charset);
-
-                    $mime = new Horde_Mime_Part();
-                    $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"), $charset));
-
-                    // Send the reply.
-                    $mail_driver = IMP_Compose::getMailDriver();
-                    try {
-                        $mime->send($organizerEmail, $msg_headers,
-                                    $mail_driver['driver'],
-                                    $mail_driver['params']);
-                        $msgs[] = array('success', _("Reply Sent."));
-                    } catch (Horde_Mime_Exception $e) {
-                        $msgs[] = array('error', sprintf(_("Error sending reply: %s."), $e->getMessage()));
-                    }
-                } else {
-                    $msgs[] = array('warning', _("Invalid Action selected for this component."));
-                }
-                break;
-
-            case 'nosup':
-                // vFreebusy request.
-            default:
-                $msgs[] = array('warning', _("This action is not yet implemented."));
-                break;
-            }
-        }
-
-        // Create the HTML to display the iCal file.
-        $html = '';
-        if ($_SESSION['imp']['view'] == 'imp') {
-            $html .= '<form method="post" name="iCal" action="' . (IMP::selfUrl()) . '">';
-        }
-
-        foreach ($components as $key => $component) {
-            switch ($component->getType()) {
-            case 'vEvent':
-                $html .= $this->_vEvent($component, $key, $method, $msgs);
-                break;
-
-            case 'vTodo':
-                $html .= $this->_vTodo($component, $key, $method, $msgs);
-                break;
-
-            case 'vTimeZone':
-                // Ignore them.
-                break;
-
-            case 'vFreebusy':
-                $html .= $this->_vFreebusy($component, $key, $method, $msgs);
-                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']['view'] == 'imp') {
-            $html .= '</form>';
-        }
-
-        return array(
-            $mime_id = array(
-                'data' => $html,
-                'status' => array(),
-                'type' => 'text/html; charset=' . $charset
-            )
-        );
-    }
-
-    /**
-     * Return the html for a vFreebusy.
-     */
-    protected function _vFreebusy($vfb, $id, $method, $msgs)
-    {
-        global $registry, $prefs;
-
-        $desc = $html = '';
-        $sender = $vfb->getName();
-
-        switch ($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>';
-
-        foreach ($msgs 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']['view'] != 'imp') {
-            return $html;
-        }
-
-        $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
-            '<select name="itip_action[' . $id . ']">';
-
-        switch ($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, $method, $msgs)
-    {
-        global $registry, $prefs;
-
-        $desc = $html = '';
-        $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 ($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>';
-
-        foreach ($msgs 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']['view'] != 'imp') {
-            return $html;
-        }
-
-        if ($options) {
-            $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
-                '<label for="action_' . $id . '" class="hidden">' . _("Actions") . '</label>' .
-                '<select id="action_' . $id . '" name="itip_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, $method, $msgs)
-    {
-        global $registry, $prefs;
-
-        $desc = $html = '';
-        $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 ($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>';
-
-        foreach ($msgs 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']['view'] != 'imp') {
-            return $html;
-        }
-
-        if ($options) {
-            $html .= '<h2 class="smallheader">' . _("Actions") . '</h2>' .
-                '<select name="itip_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");
-
-        case 'DECLINED':
-            return _("Declined");
-
-        case 'TENTATIVE':
-            return _("Tentatively Accepted");
-
-        case 'DELEGATED':
-            return _("Delegated");
-
-        case 'COMPLETED':
-            return _("Completed");
-
-        case 'IN-PROCESS':
-            return _("In Process");
-
-        case 'NEEDS-ACTION':
-        default:
-            return is_null($default) ? _("Needs Action") : $default;
-        }
-    }
-}
diff --git a/imp/lib/Mime/Viewer/mdn.php b/imp/lib/Mime/Viewer/mdn.php
deleted file mode 100644 (file)
index e0abd25..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_mdn class handles multipart/report messages that
- * that refer to message disposition notification (MDN) messages (RFC 3798).
- *
- * Copyright 2003-2009 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_mdn extends Horde_Mime_Viewer_Driver
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => true,
-        'full' => false,
-        'info' => true,
-        'inline' => true,
-    );
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        /* If this is a straight message/disposition-notification part, just
-         * output the text. */
-        if ($this->_mimepart->getType() == 'message/disposition-notification') {
-            return $this->_params['contents']->renderMIMEPart($this->_mimepart->getMIMEId(), IMP_Contents::RENDER_FULL, array('type' => 'text/plain', 'params' => $this->_params));
-        }
-
-        return $this->_renderInfo();
-    }
-
-    /**
-     * Return the rendered information about the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInfo()
-    {
-        $mdn_id = $this->_mimepart->getMimeId();
-        $parts = array_keys($this->_mimepart->contentTypeMap());
-
-        $status = array(
-            array(
-                'icon' => Horde::img('info_icon.png', _("Info"), null, $GLOBALS['registry']->getImageDir('horde')),
-                'text' => array(_("A message you have sent has resulted in a return notification from the recipient."))
-            )
-        );
-
-        /* RFC 3798 [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. */
-        reset($parts);
-        $curr_id = $first_id = next($parts);
-        $first_part = $this->_params['contents']->renderMIMEPart($curr_id, IMP_Contents::RENDER_INLINE_AUTO, array('params' => $this->_params));
-
-        /* Display a link to more detailed message. */
-        $curr_id = Horde_Mime::mimeIdArithmetic($curr_id, 'next');
-        $part = $this->_params['contents']->getMIMEPart($curr_id);
-        if ($part) {
-            $status[0]['text'][] = sprintf(_("Additional information can be viewed %s."), $this->_params['contents']->linkViewJS($part, 'view_attach', _("HERE"), array('jstext' => _("Additional information details"), 'params' => array('mode' => IMP_Contents::RENDER_INLINE))));
-        }
-
-        /* Display a link to the sent message. Try to download the text of
-           the message/rfc822 part first, if it exists. */
-        $curr_id = Horde_Mime::mimeIdArithmetic($curr_id, 'next');
-        $part = $this->_params['contents']->getMIMEPart($curr_id);
-        if ($part) {
-            $status[0]['text'][] = sprintf(_("The text of the sent message can be viewed %s."), $this->_params['contents']->linkViewJS($part, 'view_attach', _("HERE"), array('jstext' => _("The text of the sent message"))));
-        }
-
-        if (empty($first_part)) {
-            $data = '';
-        } else {
-            $status[0]['text'][] = _("The mail server generated the following informational message:");
-            $status = array_merge($status, $first_part[$first_id]['status']);
-            $data = $first_part[$first_id]['data'];
-        }
-
-        $ret = array_combine($parts, array_fill(0, count($parts), null));
-        $ret[$mdn_id] = array(
-            'data' => $data,
-            'status' => $status,
-            'type' => 'text/html; charset=' . NLS::getCharset()
-        );
-
-        return $ret;
-    }
-}
diff --git a/imp/lib/Mime/Viewer/partial.php b/imp/lib/Mime/Viewer/partial.php
deleted file mode 100644 (file)
index 7bf2c0c..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_partial class allows message/partial messages
- * to be displayed (RFC 2046 [5.2.2]).
- *
- * Copyright 2003-2009 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
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => true,
-        'forceinline' => true,
-        'full' => false,
-        'info' => false,
-        'inline' => false,
-    );
-
-    /**
-     * If this MIME part can contain embedded MIME parts, and those embedded
-     * MIME parts exist, return a list of MIME parts that contain the embedded
-     * MIME part information.
-     *
-     * @return array  An array of Horde_Mime_Part objects, with the key as
-     *                the ID, or null if no embedded MIME parts exist.
-     */
-    protected function _getEmbeddedMimeParts()
-    {
-        $id = $this->_mimepart->getContentTypeParameter('id');
-        $number = $this->_mimepart->getContentTypeParameter('number');
-        $total = $this->_mimepart->getContentTypeParameter('total');
-
-        if (is_null($id) || is_null($number) || is_null($total)) {
-            return null;
-        }
-
-        $mbox = $this->_params['contents']->getMailbox();
-
-        /* Perform the search to find the other parts of the message. */
-        $query = new Horde_Imap_Client_Search_Query();
-        $query->headerText('Content-Type', $id);
-        $indices = $GLOBALS['imp_search']->runSearchQuery($query, $mbox);
-
-        /* If not able to find the other parts of the message, print error. */
-        if (count($indices) != $total) {
-            $mime_part = new Horde_Mime_Part();
-            $mime_part->setType('text/plain');
-            $mime_part->setCharset(NLS::getCharset());
-            $mime_part->setContents(sprintf(_("[Cannot display message - found only %s of %s parts of this message in the current mailbox.]"), count($indices), $total));
-            return array($this->_mimepart->getMimeId() => $mime_part);
-        }
-
-        /* Get the contents of each of the parts. */
-        $parts = array();
-        foreach ($indices as $val) {
-            /* No need to fetch the current part again. */
-            if ($val == $number) {
-                $parts[$number] = $this->_mimepart->getContents();
-            } else {
-                $ic = &IMP_Contents::singleton($val . IMP::IDX_SEP . $mbox);
-                $parts[$ic->getMIMEMessage()->getContentTypeParameter('number')] = $ic->getBody();
-            }
-        }
-
-        /* Sort the parts in numerical order. */
-        ksort($parts, SORT_NUMERIC);
-
-        /* Combine the parts. */
-        $mime_part = Horde_Mime_Part::parseMessage(implode('', $parts));
-        return ($mime_part === false)
-            ? null
-            : array($this->_mimepart->getMimeId() => $mime_part);
-    }
-}
diff --git a/imp/lib/Mime/Viewer/pdf.php b/imp/lib/Mime/Viewer/pdf.php
deleted file mode 100644 (file)
index 81b8dd0..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_pdf class enables generation of thumbnails for
- * PDF attachments.
- *
- * Copyright 2008-2009 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_pdf
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => false,
-        'full' => true,
-        'info' => true,
-        'inline' => false
-    );
-
-    /**
-     * Return the full rendered version of the Horde_Mime_Part object.
-     *
-     * URL parameters used by this function:
-     * <pre>
-     * 'pdf_view_thumbnail' - (boolean) Output the thumbnail info.
-     * </pre>
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _render()
-    {
-        /* Create the thumbnail and display. */
-        if (!Util::getFormData('pdf_view_thumbnail')) {
-            return parent::_render();
-        }
-
-        $img = $this->_getHordeImageOb(true);
-
-        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');
-        }
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => $data,
-                'status' => array(),
-                'type' => $type
-            )
-        );
-    }
-
-    /**
-     * Return the rendered information about the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInfo()
-    {
-        /* Check to see if convert utility is available. */
-        if (!$this->_getHordeImageOb(false)) {
-            return array();
-        }
-
-        $status = array(
-            sprintf(_("A PDF file named %s is attached to this message. A thumbnail is below."), $this->_mimepart->getName(true)),
-        );
-
-        if ($GLOBALS['browser']->hasFeature('javascript')) {
-            $status[] = $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('pdf_view_thumbnail' => 1)), false), _("View Attachment"), null, ''), null, null, null);
-        } else {
-            $status[] = Horde::link($this->_params['contents']->urlView($this->_mimepart, 'view_attach')) . Horde::img($this->_params['contents']->urlView($this->_mimepart, 'view_attach', array('params' => array('pdf_view_thumbnail' => 1)), false), _("View Attachment"), null, '') . '</a>';
-        }
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => '',
-                'status' => array(
-                    array(
-                        'icon' => Horde::img('mime/image.png', _("Thumbnail of attached PDF file")),
-                        'text' => $status
-                    )
-                ),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-    }
-
-    /**
-     * Return a Horde_Image object.
-     *
-     * @param boolean $load  Whether to load the image data.
-     *
-     * @return mixed  The Hore_Image object, or false on error.
-     */
-    protected function _getHordeImageOb($load)
-    {
-        if (empty($GLOBALS['conf']['image']['convert'])) {
-            return false;
-        }
-
-        $img = &Horde_Image::singleton('im', array('temp' => Horde::getTempdir()));
-        if (is_a($img, 'PEAR_Error')) {
-            return false;
-        }
-
-        if ($load) {
-            $ret = $img->loadString(1, $this->_mimepart->getContents());
-            if (is_a($ret, 'PEAR_Error')) {
-                return false;
-            }
-        }
-
-        return $img;
-    }
-}
diff --git a/imp/lib/Mime/Viewer/pgp.php b/imp/lib/Mime/Viewer/pgp.php
deleted file mode 100644 (file)
index 26d5f3f..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-<?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 (in multipart/encrypted part)
- *   application/pgp-keys
- *   application/pgp-signature (in multipart/signed part)
- *
- * This class may add the following parameters to the URL:
- *   'pgp_verify_msg' - (boolean) Do verification of PGP signed data.
- *   'rawpgpkey' - (boolean) Display the PGP Public Key in raw, text format
- *
- * Copyright 2002-2009 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
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => true,
-        'forceinline' => true,
-        'full' => false,
-        'info' => false,
-        'inline' => true
-    );
-
-    /**
-     * IMP_Crypt_Pgp object.
-     *
-     * @var IMP_Crypt_Pgp
-     */
-    protected $_imppgp;
-
-    /**
-     * The address of the sender.
-     *
-     * @var string
-     */
-    protected $_address = null;
-
-    /**
-     * Cache for inline data.
-     *
-     * @var array
-     */
-    static protected $_inlinecache = array();
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        if (empty($this->_imppgp) &&
-            !empty($GLOBALS['conf']['utils']['gnupg'])) {
-            $this->_imppgp = Horde_Crypt::singleton(array('IMP', 'Pgp'));
-        }
-
-        if (Util::getFormData('rawpgpkey')) {
-            return array(
-                $this->_mimepart->getMimeId() => array(
-                    'data' => $this->_mimepart->getContents(),
-                    'status' => array(),
-                    'type' => 'text/plain; charset=' . $this->_mimepart->getCharset()
-                )
-            );
-        }
-
-        /* Determine the address of the sender. */
-        if (is_null($this->_address)) {
-            $headers = $this->_params['contents']->getHeaderOb();
-            $this->_address = Horde_Mime_Address::bareAddress($headers->getValue('from'));
-        }
-
-        switch ($this->_mimepart->getType()) {
-        case 'application/pgp-keys':
-            return $this->_outputPGPKey();
-
-        case 'multipart/signed':
-            return $this->_outputPGPSigned();
-
-        case 'multipart/encrypted':
-            return $this->_outputPGPEncrypted();
-
-        case 'application/pgp-encrypted':
-        case 'application/pgp-signature':
-        default:
-            return array();
-        }
-    }
-
-    /**
-     * If this MIME part can contain embedded MIME parts, and those embedded
-     * MIME parts exist, return an altered version of the Horde_Mime_Part that
-     * contains the embedded MIME part information.
-     *
-     * @return mixed  A Horde_Mime_Part with the embedded MIME part information
-     *                or null if no embedded MIME parts exist.
-     */
-    protected function _getEmbeddedMimeParts()
-    {
-        if ($this->_mimepart->getType() != 'multipart/encrypted') {
-            return null;
-        }
-
-        $partlist = array_keys($this->_mimepart->contentTypeMap());
-        $base_id = reset($partlist);
-        $version_id = next($partlist);
-        $data_id = Horde_Mime::mimeIdArithmetic($version_id, 'next');
-
-        /* Initialize inline data. */
-        $resymmetric = isset(self::$_inlinecache[$base_id]);
-        self::$_inlinecache[$base_id] = array(
-            $base_id => array(
-                'data' => '',
-                'status' => array(
-                    array(
-                        'icon' => Horde::img('mime/encryption.png', 'PGP'),
-                        'text' => $resymmetric ? self::$_inlinecache[$base_id][$base_id]['status'][0]['text'] : array()
-                    )
-                ),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            ),
-            $version_id => null,
-            $data_id => null
-        );
-        $status = &self::$_inlinecache[$base_id][$base_id]['status'][0]['text'];
-
-        /* Is PGP active? */
-        if (empty($GLOBALS['conf']['utils']['gnupg']) ||
-            !$GLOBALS['prefs']->getValue('use_pgp')) {
-            $status[] = _("The message below has been encrypted via PGP, however, PGP support is disabled so the message cannot be decrypted.");
-            return null;
-        }
-
-        if (empty($this->_imppgp)) {
-            $this->_imppgp = Horde_Crypt::singleton(array('IMP', 'Pgp'));
-        }
-
-        /* PGP version 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. */
-        $encrypted_part = $this->_params['contents']->getMIMEPart($data_id);
-        $encrypted_data = $encrypted_part->getContents();
-
-        $symmetric_pass = $personal_pass = null;
-
-        /* Check if this a symmetrically encrypted message. */
-        try {
-            $symmetric = $this->_imppgp->encryptedSymmetrically($encrypted_data);
-            if ($symmetric) {
-                $symmetric_id = $this->_getSymmetricID();
-                $symmetric_pass = $this->_imppgp->getPassphrase('symmetric', $symmetric_id);
-
-                if (is_null($symmetric_pass)) {
-                    $js_action = '';
-                    if (!$resymmetric) {
-                        $status[] = _("The message has been encrypted via PGP.");
-                    }
-
-                    switch ($_SESSION['imp']['view']) {
-                    case 'dimp':
-                        $js_action = 'DimpCore.reloadMessage({});';
-                        // Fall through
-
-                    case 'imp':
-                        /* Ask for the correct passphrase if this is encrypted
-                         * symmetrically. */
-                        $status[] = Horde::link('#', '', '', '', IMP::passphraseDialogJS('PGPSymmetric', $js_action, array('symmetricid' => $symmetric_id)) . ';return false;') . _("You must enter the passphrase used to encrypt this message to view it.") . '</a>';
-                        break;
-                    }
-                    return null;
-                }
-            }
-        } catch (Horde_Exception $e) {
-            Horde::logMessage($e, __FILE__, __LINE__);
-            unset(self::$_inlinecache[$base_id]);
-            return null;
-        }
-
-        /* Check if this is a literal compressed message. */
-        try {
-            $info = $this->_imppgp->pgpPacketInformation($encrypted_data);
-        } catch (Horde_Exception $e) {
-            Horde::logMessage($e, __FILE__, __LINE__);
-            unset(self::$_inlinecache[$base_id]);
-            return null;
-        }
-        $literal = !empty($info['literal']);
-
-        if ($literal) {
-            $status[] = _("The message below has been compressed via PGP.");
-        } else {
-            $status[] = _("The message below has been encrypted via PGP.");
-            if (!$symmetric) {
-                if (!$this->_imppgp->getPersonalPrivateKey()) {
-                    /* Output if there is no personal private key to decrypt
-                     * with. */
-                    $status[] = _("The message below has been encrypted via PGP, however, no personal private key exists so the message cannot be decrypted.");
-                    return null;
-                } else {
-                    $personal_pass = $this->_imppgp->getPassphrase('personal');
-
-                    if (is_null($personal_pass)) {
-                        $js_action = '';
-                        $status[] = _("The message has been encrypted via PGP.");
-
-                        switch ($_SESSION['imp']['view']) {
-                        case 'dimp':
-                            $js_action = 'DimpCore.reloadMessage({});';
-                            // Fall through
-
-                        case 'imp':
-                            /* Ask for the private key's passphrase if this is
-                             * encrypted asymmetrically. */
-                            $status[] = Horde::link('#', '', '', '', IMP::passphraseDialogJS('PGPPersonal', $js_action) . ';return false;') . _("You must enter the passphrase for your PGP private key to view this message.") . '</a>';
-                            break;
-                        }
-                        return null;
-                    }
-                }
-            }
-        }
-
-        try {
-            if (!is_null($symmetric_pass)) {
-                $decrypted_data = $this->_imppgp->decryptMessage($encrypted_data, 'symmetric', $symmetric_pass);
-            } elseif (!is_null($personal_pass)) {
-                $decrypted_data = $this->_imppgp->decryptMessage($encrypted_data, 'personal', $personal_pass);
-            } else {
-                $decrypted_data = $this->_imppgp->decryptMessage($encrypted_data, 'literal');
-            }
-        } catch (Horde_Exception $e) {
-            $status[] = _("The message below does not appear to be a valid PGP encrypted message. Error: ") . $e->getMessage();
-            if (!is_null($symmetric_pass)) {
-                $this->_imppgp->unsetPassphrase('symmetric', $this->_getSymmetricID());
-                return $this->_getEmbeddedMimeParts();
-            }
-            return null;
-        }
-
-        unset(self::$_inlinecache[$base_id][$data_id]);
-
-        $msg = Horde_Mime_Part::parseMessage($decrypted_data->message);
-        $msg->buildMimeIds($data_id);
-
-        return array($data_id => $msg);
-    }
-
-    /**
-     * Generates output for 'application/pgp-keys' MIME_Parts.
-     *
-     * @return string  The HTML output.
-     */
-    protected function _outputPGPKey()
-    {
-        /* Initialize status message. */
-        $status = array(
-            'icon' => Horde::img('mime/encryption.png', 'PGP'),
-            'text' => array(
-                _("A PGP Public Key was attached to the message.")
-            )
-        );
-
-        $mime_id = $this->_mimepart->getMimeId();
-
-        if ($GLOBALS['prefs']->getValue('use_pgp') &&
-            $GLOBALS['prefs']->getValue('add_source') &&
-            $GLOBALS['registry']->hasMethod('contacts/addField')) {
-            $status['text'][] = Horde::link('#', '', '', '', $this->_imppgp->savePublicKeyURL($this->_params['contents']->getMailbox(), $this->_params['contents']->getIndex(), $mime_id) . 'return false;') . _("[Save the key to your Address book]") . '</a>';
-        }
-        $status['text'][] = $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("View the raw text of the Public Key."), array('params' => array('mode' => IMP_Contents::RENDER_INLINE, 'rawpgpkey' => 1)));
-
-        try {
-            $data = '<span class="fixed">' . nl2br(str_replace(' ', '&nbsp;', $this->_imppgp->pgpPrettyKey($this->_mimepart->getContents()))) . '</span>';
-        } catch (Horde_Exception $e) {
-            $data = $e->getMessage();
-        }
-
-        return array(
-            $mime_id => array(
-                'data' => $data,
-                'status' => array($status),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-    }
-
-    /**
-     * Generates HTML output for 'multipart/signed' MIME parts.
-     *
-     * @return string  The HTML output.
-     */
-    protected function _outputPGPSigned()
-    {
-        $partlist = array_keys($this->_mimepart->contentTypeMap());
-        $base_id = reset($partlist);
-        $signed_id = next($partlist);
-        $sig_id = Horde_Mime::mimeIdArithmetic($signed_id, 'next');
-
-        $ret = array(
-            $base_id => array(
-                'data' => '',
-                'status' => array(
-                    array(
-                        'icon' => Horde::img('mime/encryption.png', 'PGP'),
-                        'text' => array()
-                    )
-                ),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            ),
-            $sig_id => null
-        );
-        $status = &$ret[$base_id]['status'][0]['text'];
-
-        if (!$GLOBALS['prefs']->getValue('use_pgp') ||
-            empty($GLOBALS['conf']['utils']['gnupg'])) {
-            /* If PGP not active, hide signature data and output status
-             * information. */
-            $status[] = _("The message below has been digitally signed via PGP, but the signature cannot be verified.");
-            return $ret;
-        }
-
-        $status[] = _("The message below has been digitally signed via PGP.");
-
-        if ($GLOBALS['prefs']->getValue('pgp_verify') ||
-            Util::getFormData('pgp_verify_msg')) {
-            $signed_data = $GLOBALS['imp_imap']->utils->removeBareNewlines($this->_params['contents']->getBodyPart($signed_id, array('mimeheaders' => true)));
-            $sig_part = $this->_params['contents']->getMIMEPart($sig_id);
-
-            /* Check for the 'x-imp-pgp-signature' param. This is set by the
-             * plain driver when parsing PGP armor text. */
-            $graphicsdir = $GLOBALS['registry']->getImageDir('horde');
-            try {
-                $sig_result = $sig_part->getContentTypeParameter('x-imp-pgp-signature')
-                    ? $this->_imppgp->verifySignature($signed_data, $this->_address)
-                    : $this->_imppgp->verifySignature($signed_data, $this->_address, $sig_part->getContents());
-
-                if ($sig_result->result) {
-                    $icon = Horde::img('alerts/success.png', _("Success"), null, $graphicsdir);
-                    $sig_text = $sig_result->message;
-                } else {
-                    $icon = Horde::img('alerts/warning.png', _("Warning"), null, $graphicsdir);
-                   $sig_text = _("The signature could not be checked because the sender's key could not be found.");
-                }
-            } catch (Horde_Exception $e) {
-                $icon = Horde::img('alerts/error.png', _("Error"), null, $graphicsdir);
-                $sig_text = $e->getMessage();
-            }
-
-            require_once 'Horde/Text/Filter.php';
-            $ret[$base_id]['status'][] = array(
-                'icon' => $icon,
-                'text' => array(
-                    Text_Filter::filter($sig_text, 'text2html', array('parselevel' => TEXT_HTML_NOHTML))
-                )
-            );
-        } else {
-            switch ($_SESSION['imp']['view']) {
-            case 'imp':
-                $status[] = Horde::link(Util::addParameter(IMP::selfUrl(), array('pgp_verify_msg' => 1))) . _("Click HERE to verify the message.") . '</a>';
-                break;
-
-            case 'dimp':
-                $status[] = Horde::link('#', '', 'pgpVerifyMsg') . _("Click HERE to verify the message.") . '</a>';
-                break;
-            }
-        }
-
-        return $ret;
-    }
-
-    /**
-     * Generates HTML output for 'multipart/encrypted' MIME parts.
-     *
-     * @return string  The HTML output.
-     */
-    protected function _outputPGPEncrypted()
-    {
-        $id = $this->_mimepart->getMimeId();
-        return isset(self::$_inlinecache[$id])
-            ? self::$_inlinecache[$id]
-            : array();
-    }
-
-    /**
-     * Generates the symmetric ID for this message.
-     *
-     * @return string  Symmetric ID.
-     */
-    protected function _getSymmetricID()
-    {
-        return $this->_imppgp->getSymmetricID($this->_params['contents']->getMailbox(), $this->_params['contents']->getIndex(), $this->_mimepart->getMimeId());
-    }
-
-}
diff --git a/imp/lib/Mime/Viewer/plain.php b/imp/lib/Mime/Viewer/plain.php
deleted file mode 100644 (file)
index 1231362..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_plain class renders out text/plain MIME parts
- * with URLs made into hyperlinks.
- *
- * Copyright 1999-2009 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
-{
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        global $conf, $prefs;
-
-        $mime_id = $this->_mimepart->getMimeId();
-        $type = 'text/html; charset=' . NLS::getCharset();
-
-        // Trim extra whitespace in the text.
-        $text = trim($this->_mimepart->getContents());
-        if ($text == '') {
-            return array(
-                $mime_id => array(
-                    'data' => '',
-                    'status' => array(),
-                    'type' => $type
-                )
-            );
-        }
-
-        // Convert to the local charset.
-        $text = String::convertCharset($text, $this->_mimepart->getCharset());
-
-        // 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);
-        }
-
-        $text = IMP::filterText($text);
-
-        /* Done processing if in mimp mode. */
-        if ($_SESSION['imp']['view'] == 'mimp') {
-            return array(
-                $mime_id => array(
-                    'data' => $text,
-                    'status' => array(),
-                    'type' => $type
-                )
-            );
-        }
-
-        // 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' => NLS::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, 'outputJS' => false);
-        }
-
-        // 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();
-        }
-
-        if ($prefs->getValue('emoticons')) {
-            $filters['emoticons'] = array('entities' => true);
-        }
-
-        // Run filters.
-        $text = Text_Filter::filter($text, array_keys($filters), array_values($filters));
-
-        // Wordwrap.
-        $text = str_replace(array('  ', "\n "), array(' &nbsp;', "\n&nbsp;"), $text);
-        if (!strncmp($text, ' ', 1)) {
-            $text = '&nbsp;' . substr($text, 1);
-        }
-
-        return array(
-            $mime_id => array(
-                'data' => '<div class="fixed leftAlign">' . "\n" . $text . '</div>',
-                'status' => array(),
-                'type' => $type
-            )
-        );
-    }
-
-    /**
-     * Does this MIME part possibly contain embedded MIME parts?
-     *
-     * @return boolean  True if this driver supports parsing embedded MIME
-     *                  parts.
-     */
-    public function embeddedMimeParts()
-    {
-        return (!empty($GLOBALS['conf']['utils']['gnupg']) && $GLOBALS['prefs']->getValue('pgp_scan_body')) || $this->getConfigParam('uudecode');
-    }
-
-    /**
-     * If this MIME part can contain embedded MIME parts, and those embedded
-     * MIME parts exist, return a list of MIME parts that contain the embedded
-     * MIME part information.
-     *
-     * @return mixed  An array of Horde_Mime_Part objects, with the key as
-     *                the ID, or null if no embedded MIME parts exist.
-     */
-    public function getEmbeddedMimeParts()
-    {
-        $ret = null;
-
-        if (!empty($GLOBALS['conf']['utils']['gnupg']) &&
-            $GLOBALS['prefs']->getValue('pgp_scan_body')) {
-            $ret = $this->_parsePGP();
-        }
-
-        if (is_null($ret) && $this->getConfigParam('uudecode')) {
-            $ret = $this->_parseUUencode();
-        }
-
-        return $ret;
-    }
-
-    /**
-     * Scan text for armored PGP blocks and, if they exist, convert the part
-     * to the embedded MIME representation.
-     *
-     * @return mixed  See self::_getEmbeddedMimeParts().
-     */
-    protected function _parsePGP()
-    {
-        /* Avoid infinite loop. */
-        $imp_pgp = Horde_Crypt::singleton(array('IMP', 'Pgp'));
-        $parts = $imp_pgp->parsePGPData($this->_mimepart->getContents());
-        if (empty($parts) ||
-            ((count($parts) == 1) &&
-             ($parts[0]['type'] == Horde_Crypt_Pgp::ARMOR_TEXT))) {
-            return null;
-        }
-
-        $new_part = new Horde_Mime_Part();
-        $new_part->setType('multipart/mixed');
-        $charset = $this->_mimepart->getCharset();
-        $mime_id = $this->_mimepart->getMimeId();
-
-        while (list(,$val) = each($parts)) {
-            switch ($val['type']) {
-            case Horde_Crypt_Pgp::ARMOR_TEXT:
-                $part = new Horde_Mime_Part();
-                $part->setType('text/plain');
-                $part->setCharset($charset);
-                $part->setContents(implode("\n", $val['data']));
-                $new_part->addPart($part);
-                break;
-
-            case Horde_Crypt_Pgp::ARMOR_PUBLIC_KEY:
-                $part = new Horde_Mime_Part();
-                $part->setType('application/pgp-keys');
-                $part->setContents(implode("\n", $val['data']));
-                $new_part->addPart($part);
-                break;
-
-            case Horde_Crypt_Pgp::ARMOR_MESSAGE:
-                $part = new Horde_Mime_Part();
-                $part->setType('multipart/signed');
-                // TODO: add micalg parameter
-                $part->setContentTypeParameter('protocol', 'application/pgp-encrypted');
-
-                $part1 = new Horde_Mime_Part();
-                $part1->setType('application/pgp-encrypted');
-                $part1->setContents("Version: 1\n");
-
-                $part2 = new Horde_Mime_Part();
-                $part2->setType('application/octet-stream');
-                $part2->setContents($message_encrypt);
-                $part2->setDisposition('inline');
-
-                $part->addPart($part1);
-                $part->addPart($part2);
-
-                $new_part->addPart($part);
-                break;
-
-            case Horde_Crypt_Pgp::ARMOR_SIGNED_MESSAGE:
-                if (($sig = current($parts)) &&
-                    ($sig['type'] == Horde_Crypt_Pgp::ARMOR_SIGNATURE)) {
-                    $part = new Horde_Mime_Part();
-                    $part->setType('multipart/signed');
-                    // TODO: add micalg parameter
-                    $part->setContentTypeParameter('protocol', 'application/pgp-signature');
-
-                    $part1 = new Horde_Mime_Part();
-                    $part1->setType('text/plain');
-                    $part1->setCharset($charset);
-
-                    $part1_data = implode("\n", $val['data']);
-                    $part1->setContents(substr($part1_data, strpos($part1_data, "\n\n") + 2));
-
-                    $part2 = new Horde_Mime_Part();
-                    $part2->setType('application/x-imp-pgp-signature');
-                    $part2->setContents(String::convertCharset(implode("\n", $val['data']) . "\n" . implode("\n", $sig['data']), $charset));
-
-                    $part->addPart($part1);
-                    $part->addPart($part2);
-                    $new_part->addPart($part);
-
-                    next($parts);
-                }
-            }
-        }
-
-        $new_part->buildMimeIds($mime_id);
-
-        return array($mime_id => $new_part);
-    }
-
-    /**
-     * Scan text for UUencode data an, if it exists, convert the part to the
-     * embedded MIME representation.
-     *
-     * @return mixed  See self::_getEmbeddedMimeParts().
-     */
-    protected function _parseUUencode()
-    {
-        $text = String::convertCharset($this->_mimepart->getContents(), $this->_mimepart->getCharset());
-
-        /* Don't want to use convert_uudecode() here as there may be multiple
-         * files residing in the text. */
-        $files = &Mail_mimeDecode::uudecode($text);
-        if (empty($files)) {
-            return null;
-        }
-
-        $new_part = new Horde_Mime_Part();
-        $new_part->setType('multipart/mixed');
-        $mime_id = $this->_mimepart->getMimeId();
-
-        $text_part = new Horde_Mime_Part();
-        $text_part->setType('text/plain');
-        $text_part->setCharset(NLS::getCharset());
-        $text_part->setContents(preg_replace("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", "\n", $text));
-        $new_part->addPart($text_part);
-
-        reset($files);
-        while (list(,$file) = each($files)) {
-            $uupart = new Horde_Mime_Part();
-            $uupart->setType('application/octet-stream');
-            $uupart->setContents($file['filedata']);
-            $uupart->setName(strip_tags($file['filename']));
-            $new_part->addPart($uupart);
-        }
-
-        $new_part->buildMimeIds($mime_id);
-
-        return array($mime_id => $new_part);
-    }
-}
diff --git a/imp/lib/Mime/Viewer/related.php b/imp/lib/Mime/Viewer/related.php
deleted file mode 100644 (file)
index ec0be5e..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_related class handles multipart/related
- * (RFC 2387) messages.
- *
- * Copyright 2002-2009 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
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => true,
-        'full' => true,
-        'info' => false,
-        'inline' => true,
-    );
-
-    /**
-     * Return the full rendered version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _render()
-    {
-        return $this->_IMPrender(false);
-    }
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        return $this->_IMPrender(true);
-    }
-
-    /**
-     * Render out the currently set contents.
-     *
-     * @param boolean $inline  Are we viewing inline?
-     *
-     * @return array  See self::render().
-     */
-    protected function _IMPrender($inline)
-    {
-        $ids = array_keys($this->_mimepart->contentTypeMap());
-        $related_id = $this->_mimepart->getMimeId();
-
-        $cids = $ret = array();
-        $id = null;
-
-        /* Build a list of parts -> CIDs. */
-        foreach ($ids as $val) {
-            $ret[$val] = null;
-            if (strcmp($related_id, $val) !== 0) {
-                $part = $this->_mimepart->getPart($val);
-                $cids[$val] = $part->getContentId();
-            }
-        }
-
-        /* Look at the 'start' parameter to determine which part to start
-         * with. If no 'start' parameter, use the first part. RFC 2387
-         * [3.1] */
-        $start = $this->_mimepart->getContentTypeParameter('start');
-        if (!empty($start)) {
-            $id = array_search($id, $cids);
-        }
-
-        if (empty($id)) {
-            reset($ids);
-            $id = next($ids);
-        }
-
-        /* Only display if the start part (normally text/html) can be
-         * displayed inline -OR- we are viewing this part as an attachment. */
-        if ($inline &&
-            !$this->_params['contents']->canDisplay($id, IMP_Contents::RENDER_INLINE)) {
-            return array();
-        }
-
-
-        $render = $this->_params['contents']->renderMIMEPart($id, $inline ? IMP_Contents::RENDER_INLINE : IMP_Contents::RENDER_FULL, array('params' => array_merge($this->_params, array('related_id' => $id, 'related_cids' => $cids))));
-
-        if (!$inline) {
-            return $render;
-        }
-
-        foreach (array_keys($render) as $val) {
-            $ret[$val] = $render[$val];
-        }
-
-        return $ret;
-    }
-}
diff --git a/imp/lib/Mime/Viewer/smil.php b/imp/lib/Mime/Viewer/smil.php
deleted file mode 100644 (file)
index 0f90332..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_smil renders SMIL documents to very basic HTML.
- *
- * Copyright 2006-2009 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
-{
-    /**
-     * 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'])) !== false)) {
-                $this->_content .= '<img src="' . $this->_params['contents']->urlView($rp, 'view_attach') . '" alt="" /><br />';
-            }
-            break;
-
-        case 'TEXT':
-            if (isset($attrs['SRC']) &&
-                (($rp = $this->_getRelatedLink($attrs['SRC'])) !== 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 (isset($this->_params['related_id']) &&
-            (($key = array_search(trim($cid, '<>', $this->_params['related_cids']))) !== false)) {
-            return $this->_param['contents']->getMIMEPart($key);
-        }
-
-        return false;
-    }
-}
diff --git a/imp/lib/Mime/Viewer/smime.php b/imp/lib/Mime/Viewer/smime.php
deleted file mode 100644 (file)
index ff42f87..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_smime 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/x-pkcs7-mime
- *   application/pkcs7-signature (in multipart/signed part)
- *   application/x-pkcs7-signature (in multipart/signed part)
- *
- * This class may add the following parameters to the URL:
- *   'smime_verify_msg' - (boolean) Do verification of S.
- *   'view_smime_key' - (boolean) Display the S/MIME Key.
- *
- * Copyright 2002-2009 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_smime extends Horde_Mime_Viewer_Driver
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => true,
-        'forceinline' => true,
-        'full' => false,
-        'info' => false,
-        'inline' => true
-    );
-
-    /**
-     * IMP_Crypt_Smime object.
-     *
-     * @var IMP_Crypt_Smime
-     */
-    protected $_impsmime = null;
-
-    /**
-     * Cache for inline data.
-     *
-     * @var array
-     */
-    static protected $_inlinecache = array();
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        /* Check to see if S/MIME support is available. */
-        $this->_initSMIME();
-
-        if (Util::getFormData('view_smime_key')) {
-            return $this->_outputSMIMEKey();
-        }
-
-        if (is_null($this->_impsmime)) {
-            $this->_impsmime = false;
-        } else {
-            /* We need to insert JavaScript code now if S/MIME support is
-             * active. */
-            Horde::addScriptFile('prototype.js', 'horde', true);
-            Horde::addScriptFile('imp.js', 'imp', true);
-        }
-
-        switch ($this->_mimepart->getType()) {
-        case 'multipart/signed':
-            return $this->_outputSMIMESigned();
-
-        case 'application/pkcs7-mime':
-        case 'application/x-pkcs7-mime':
-            return $this->_outputSMIMEEncrypted();
-        }
-    }
-
-    /**
-     * If this MIME part can contain embedded MIME parts, and those embedded
-     * MIME parts exist, return an altered version of the Horde_Mime_Part that
-     * contains the embedded MIME part information.
-     *
-     * @return mixed  A Horde_Mime_Part with the embedded MIME part information
-     *                or null if no embedded MIME parts exist.
-     */
-    protected function _getEmbeddedMimeParts()
-    {
-        if (!in_array($this->_mimepart->getType(), array('application/pkcs7-mime', 'application/x-pkcs7-mime'))) {
-            return null;
-        }
-
-        // 'smime-type' must be empty or 'enveloped-data'
-        $smime_type = $this->_mimepart->getContentTypeParameter('smime-type');
-        if ($smime_type == 'signed-data') {
-            // TODO
-            return null;
-        }
-
-        $base_id = $this->_mimepart->getMimeId();
-
-        /* Initialize inline data. */
-        self::$_inlinecache[$base_id] = array(
-            $base_id => array(
-                'data' => '',
-                'status' => array(
-                    array(
-                        'icon' => Horde::img('mime/encryption.png', 'S/MIME'),
-                        'text' => array(_("This message has been encrypted via S/MIME."))
-                    )
-                ),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-        $status = &self::$_inlinecache[$base_id][$base_id]['status'][0]['text'];
-
-        /* Is PGP active? */
-        $this->_initSMIME();
-        if (empty($this->_impsmime)) {
-            $status[] = _("S/MIME support is not currently enabled so the message is unable to be decrypted.");
-            return null;
-        }
-
-        if (!$this->_impsmime->getPersonalPrivateKey()) {
-            $status[] = _("No personal private key exists so the message is unable to be decrypted.");
-            return null;
-        }
-
-        /* Make sure we have a passphrase. */
-        $passphrase = $this->_impsmime->getPassphrase();
-        if ($passphrase === false) {
-            $js_action = '';
-
-            switch ($_SESSION['imp']['view'] == 'imp') {
-            case 'dimp':
-                $js_action = 'DimpCore.reloadMessage({});';
-                // Fall through
-
-            case 'imp':
-                $status[] = Horde::link('#', '', '', '', IMP::passphraseDialogJS('SMIMEPersonal', $js_action) . ';return false;') . _("You must enter the passphrase for your S/MIME private key to view this message.") . '</a>';
-                break;
-            }
-            return null;
-        }
-
-        $raw_text = $GLOBALS['imp_imap']->utils->removeBareNewlines($this->_params['contents']->getBodyPart($this->_mimepart->getMimeId(), array('mimeheaders' => true)));
-
-        try {
-            $decrypted_data = $this->_impsmime->decryptMessage($raw_text);
-        } catch (Horde_Exception $e) {
-            $status[] = $e->getMessage();
-            return null;
-        }
-
-        return array($base_id => Horde_Mime_Part::parseMessage($decrypted_data));
-    }
-
-    /**
-     * Generates HTML output for the S/MIME key.
-     *
-     * @return string  The HTML output.
-     */
-    protected function _outputSMIMEKey()
-    {
-        if (empty($this->_impsmime)) {
-            return array();
-        }
-
-        $raw_text = $GLOBALS['imp_imap']->utils->removeBareNewlines($this->_params['contents']->getBodyPart($this->_mimepart->getMimeId(), array('mimeheaders' => true)));
-
-        try {
-            $sig_result = $this->_impsmime->verifySignature($raw_text);
-        } catch (Horde_Exception $e) {}
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => $this->_impsmime->certToHTML($sig_result->cert),
-                'status' => array(),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-    }
-
-    /**
-     * Init the S/MIME Horde_Crypt object.
-     */
-    protected function _initSMIME()
-    {
-        if (is_null($this->_impsmime) &&
-            $GLOBALS['prefs']->getValue('use_smime')) {
-            try {
-                $this->_impsmime = Horde_Crypt::singleton(array('IMP', 'Smime'));
-                $this->_impsmime->checkForOpenSSL();
-            } catch (Horde_Exception $e) {
-                $this->_impsmime = null;
-            }
-        }
-    }
-
-    /**
-     * Generates HTML output for 'multipart/signed' MIME parts.
-     *
-     * @return array  TODO
-     */
-    protected function _outputSMIMESigned()
-    {
-        $partlist = array_keys($this->_mimepart->contentTypeMap());
-        $base_id = reset($partlist);
-        $sig_id = Horde_Mime::mimeIdArithmetic(next($partlist), 'next');
-
-        $ret = array(
-            $base_id => array(
-                'data' => '',
-                'status' => array(
-                    array(
-                        'icon' => Horde::img('mime/encryption.png', 'S/MIME'),
-                        'text' => array(_("This message has been digitally signed via S/MIME."))
-                    )
-                ),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            ),
-            $sig_id => null
-        );
-        $status = &$ret[$base_id]['status'][0]['text'];
-
-        if (!$GLOBALS['prefs']->getValue('use_smime')) {
-            $status[] = _("S/MIME support is not enabled so the digital signature is unable to be verified.");
-            return $ret;
-        }
-
-        $raw_text = $base_id
-            ? $this->_params['contents']->getBodyPart($base_id, array('mimeheaders' => true))
-            : $this->_params['contents']->fullMessageText();
-        $raw_text = $GLOBALS['imp_imap']->utils->removeBareNewlines($raw_text);
-
-        $sig_result = null;
-
-        if ($GLOBALS['prefs']->getValue('smime_verify') ||
-            Util::getFormData('smime_verify_msg')) {
-            try {
-                $sig_result = $this->_impsmime->verifySignature($raw_text);
-            } catch (Horde_Exception $e) {
-                $ret[$base_id]['status'][0]['icon'] = ($e->getCode() == 'horde.warning')
-                    ? Horde::img('alerts/warning.png', _("Warning"), null, $graphicsdir)
-                    : Horde::img('alerts/error.png', _("Error"), null, $graphicsdir);
-                $status[] = $e->getMessage();
-                return $ret;
-            }
-        } else {
-            switch ($_SESSION['imp']['view']) {
-            case 'imp':
-                $status[] = Horde::link(Util::addParameter(IMP::selfUrl(), 'smime_verify_msg', 1)) . _("Click HERE to verify the message.") . '</a>';
-                break;
-
-            case 'dimp':
-                $status[] = Horde::link('#', '', 'smimeVerifyMsg') . _("Click HERE to verify the message.") . '</a>';
-                break;
-            }
-            return $ret;
-        }
-
-        $subpart = $this->_params['contents']->getMIMEPart($sig_id);
-        if (!isset($subpart)) {
-            try {
-                $msg_data = $this->_impsmime->extractSignedContents($raw_text);
-                $subpart = Horde_Mime_Part::parseMessage($msg_data);
-            } catch (Horde_Exception $e) {
-                $this->_status[] = $e->getMessage();
-                $subpart = $this->_mimepart;
-            }
-        }
-
-        $graphicsdir = $GLOBALS['registry']->getImageDir('horde');
-
-        $ret[$base_id]['status'][0]['icon'] = Horde::img('alerts/success.png', _("Success"), null, $graphicsdir);
-
-        /* This message has been verified but there was no output
-         * from the PGP program. */
-        if (empty($sig_result->result) || ($sig_result->result === true)) {
-            $email = (is_array($sig_result->email))
-                ? implode(', ', $sig_result->email)
-                : $sig_result->email;
-            $status[] = sprintf(_("The message has been verified. Sender: %s."), htmlspecialchars($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;
-            } else {
-                $subject = null;
-            }
-
-            if (!empty($subject) &&
-                $GLOBALS['registry']->hasMethod('contacts/addField') &&
-                $GLOBALS['prefs']->getValue('add_source')) {
-                $status[] = sprintf(_("The S/MIME certificate of %s: "), @htmlspecialchars($subject, ENT_COMPAT, NLS::getCharset())) . $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("View"), array('params' => array('mode' => IMP_Contents::RENDER_INLINE, 'view_smime_key' => 1))) . '/' . Horde::link('#', '', null, null, $this->_impsmime->savePublicKeyURL($sig_result->cert, $this->_params['contents']->getIndex(), $sig_id) . ' return false;') . _("Save in your Address Book") . '</a>';
-            }
-        }
-
-        return $ret;
-    }
-
-    /**
-     * Generates output for encrypted S/MIME parts.
-     *
-     * @return array  TODO
-     */
-    protected function _outputSMIMEEncrypted()
-    {
-        $id = $this->_mimepart->getMimeId();
-        return isset(self::$_inlinecache[$id])
-            ? self::$_inlinecache[$id]
-            : array();
-    }
-}
diff --git a/imp/lib/Mime/Viewer/status.php b/imp/lib/Mime/Viewer/status.php
deleted file mode 100644 (file)
index 99c2772..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_status class handles multipart/report messages
- * that refer to mail system administrative messages (RFC 3464).
- *
- * Copyright 2002-2009 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
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => true,
-        'full' => false,
-        'info' => true,
-        'inline' => true,
-    );
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        /* If this is a straight message/disposition-notification part, just
-         * output the text. */
-        if ($this->_mimepart->getType() == 'message/delivery-status') {
-            return $this->_params['contents']->renderMIMEPart($this->_mimepart->getMIMEId(), IMP_Contents::RENDER_FULL, array('type' => 'text/plain', 'params' => $this->_params));
-        }
-
-        return $this->_renderInfo();
-    }
-
-    /**
-     * Return the rendered information about the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInfo()
-    {
-        $parts = array_keys($this->_mimepart->contentTypeMap());
-
-        reset($parts);
-        $part1_id = next($parts);
-        $part2_id = Horde_Mime::mimeIdArithmetic($part1_id, 'next');
-        $part3_id = Horde_Mime::mimeIdArithmetic($part2_id, 'next');
-
-        /* 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 3464 [2.3.3]). It can be either 'failed',
-         * 'delayed', 'delivered', 'relayed', or 'expanded'. */
-
-        /* Get the action first - it appears in the second part. */
-        $action = null;
-        $part2 = $this->_params['contents']->getMIMEPart($part2_id);
-
-        foreach (explode("\n", $part2->getContents()) as $line) {
-            if (stristr($line, 'Action:') !== false) {
-                $action = strtolower(trim(substr($line, strpos($line, ':') + 1)));
-                if (strpos($action, ' ') !== false) {
-                    $action = substr($action, 0, strpos($action, ' '));
-                }
-                break;
-            }
-        }
-
-        if (is_null($action)) {
-            return array();
-        }
-
-        /* Get the correct text strings for the action type. */
-        switch ($action) {
-        case 'failed':
-        case 'delayed':
-            $status = array(
-                array(
-                    'icon' => Horde::img('alerts/error.png', _("Error"), null, $GLOBALS['registry']->getImageDir('horde')),
-                    'text' => array(
-                        _("ERROR: Your message could not be delivered."),
-                        sprintf(_("Additional error message details can be viewed %s."), $this->_params['contents']->linkViewJS($part2, 'view_attach', _("HERE"), array('jstext' => _("Additional message details"), 'params' => array('mode' => IMP_Contents::RENDER_INLINE))))
-                    )
-                )
-            );
-            $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':
-            $status = array(
-                array(
-                    'icon' => Horde::img('alerts/success.png', _("Success"), null, $GLOBALS['registry']->getImageDir('horde')),
-                    'text' => array(
-                        _("Your message was successfully delivered."),
-                        sprintf(_("Additional message details can be viewed %s."), $this->_params['contents']->linkViewJS($part2, 'view_attach', _("HERE"), array('jstext' => _("Additional message details"), 'params' => array('mode' => IMP_Contents::RENDER_INLINE))))
-                    )
-                )
-            );
-            $msg_link = _("The text of the message can be viewed %s.");
-            $msg_link_status = _("The text of the message");
-            break;
-        }
-
-        /* Print the human readable message. */
-        $first_part = $this->_params['contents']->renderMIMEPart($part1_id, IMP_Contents::RENDER_INLINE_AUTO, array('params' => $this->_params));
-
-        /* Display a link to the returned message, if it exists. */
-        $part3 = $this->_params['contents']->getMIMEPart($part3_id);
-        if ($part3) {
-            $status[0]['text'][] = sprintf($msg_link, $this->_params['contents']->linkViewJS($part3, 'view_attach', _("HERE"), array('jstext' => $msg_link_status, 'ctype' => 'message/rfc822')));
-        }
-
-        if (empty($first_part)) {
-            $data = '';
-        } else {
-            $status[0]['text'][] = _("The mail server generated the following informational message:");
-            $status = array_merge($status, $first_part[$part1_id]['status']);
-            $data = $first_part[$part1_id]['data'];
-        }
-
-        $ret = array_combine($parts, array_fill(0, count($parts), null));
-
-        $ret[$this->_mimepart->getMimeId()] = array(
-            'data' => $data,
-            'status' => $status,
-            'type' => 'text/html; charset=' . NLS::getCharset()
-        );
-
-        return $ret;
-    }
-}
diff --git a/imp/lib/Mime/Viewer/tnef.php b/imp/lib/Mime/Viewer/tnef.php
deleted file mode 100644 (file)
index 5405e88..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-/**
- * The IMP_Horde_Mime_Viewer_tnef class allows MS-TNEF attachments to be
- * displayed.
- *
- * Copyright 2002-2009 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
-{
-    /**
-     * Can this driver render various views?
-     *
-     * @var boolean
-     */
-    protected $_capability = array(
-        'embedded' => false,
-        'forceinline' => true,
-        'full' => true,
-        'info' => true,
-        'inline' => false
-    );
-
-    /**
-     * Return the full rendered version of the Horde_Mime_Part object.
-     *
-     * URL parameters used by this function:
-     * <pre>
-     * 'tnef_attachment' - (integer) The TNEF attachment to download.
-     * </pre>
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _render()
-    {
-        if (!Util::getFormData('tnef_attachment')) {
-            $ret = $this->_renderInfo();
-            reset($ret);
-            $ret[key($ret)]['data'] = '<html><body>' . $ret[key($ret)]['data'] . '</body></html>';
-            return $ret;
-        }
-
-        /* Get the data from the attachment. */
-        $tnef = &Horde_Compress::singleton('tnef');
-        $tnefData = $tnef->decompress($this->_mimepart->getContents());
-
-        /* Display the requested file. Its position in the $tnefData
-         * array can be found in '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)) {
-                return array(
-                    $this->_mimepart->getMimeId() => array(
-                        'data' => $text,
-                        'name' => $tnefData[$tnefKey]['name'],
-                        'status' => array(),
-                        'type' => $tnefData[$tnefKey]['type'] . '/' . $tnefData[$tnefKey]['subtype']
-                    )
-                );
-            }
-        }
-
-        // TODO: Error reporting
-        return array();
-    }
-
-    /**
-     * Return the rendered information about the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInfo()
-    {
-        /* Get the data from the attachment. */
-        $tnef = &Horde_Compress::singleton('tnef');
-        $tnefData = $tnef->decompress($this->_mimepart->getContents());
-
-        $text = '';
-
-        if (!count($tnefData)) {
-            $status = array(
-                'text' => array(_("No attachments found."))
-            );
-        } else {
-            $status = array(
-                'text' => array(_("The following files were attached to this part:"))
-            );
-
-            reset($tnefData);
-            while (list($key, $data) = each($tnefData)) {
-                $temp_part = $this->_mimepart;
-                $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 (in_array($type, array('application/octet-stream', 'application/base64'))) {
-                    $type = Horde_Mime_Magic::filenameToMIME($data['name']);
-                }
-                $temp_part->setType($type);
-
-                $link = $this->_params['contents']->linkView($temp_part, 'view_attach', htmlspecialchars($data['name']), array('jstext' => sprintf(_("View %s"), $data['name']), 'params' => array('tnef_attachment' => $key + 1)));
-                $text .= _("Attached File:") . '&nbsp;&nbsp;' . $link . '&nbsp;&nbsp;(' . $data['type'] . '/' . $data['subtype'] . ")<br />\n";
-            }
-        }
-
-        return array(
-            $this->_mimepart->getMimeId() => array(
-                'data' => $text,
-                'status' => array($status),
-                'type' => 'text/html; charset=' . NLS::getCharset()
-            )
-        );
-    }
-}
diff --git a/imp/lib/Mime/Viewer/zip.php b/imp/lib/Mime/Viewer/zip.php
deleted file mode 100644 (file)
index e7d5db1..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<?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-2009 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
-{
-    /**
-     * Return the full rendered version of the Horde_Mime_Part object.
-     *
-     * URL parameters used by this function:
-     * <pre>
-     * 'zip_attachment' - (integer) The ZIP attachment to download.
-     * </pre>
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _render()
-    {
-        if (!Util::getFormData('zip_attachment')) {
-            $this->_callback = array(&$this, '_IMPcallback');
-            return parent::_render();
-        }
-
-        /* Send the requested file. Its position in the zip archive is located
-         * in 'zip_attachment'. */
-        $data = $this->_mimepart->getContents();
-        $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)) {
-                return array(
-                    $this->_mimepart->getMimeId() => array(
-                        'data' => $text,
-                        'name' => basename($zipInfo[$fileKey]['name']),
-                        'status' => array(),
-                        'type' => 'application/octet-stream'
-                    )
-                );
-            }
-        }
-
-        // TODO: Error reporting
-        return array();
-    }
-
-    /**
-     * Return the rendered inline version of the Horde_Mime_Part object.
-     *
-     * @return array  See Horde_Mime_Viewer_Driver::render().
-     */
-    protected function _renderInline()
-    {
-        $this->_callback = array(&$this, '_IMPcallback');
-        return parent::_renderInline();
-    }
-
-    /**
-     * The function to use as a callback to _toHTML().
-     *
-     * @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 _IMPcallback($key, $val)
-    {
-        $name = preg_replace('/(&nbsp;)+$/', '', $val['name']);
-
-        if (!empty($val['size']) && (strstr($val['attr'], 'D') === false) &&
-            ((($val['method'] == 0x8) && Util::extensionExists('zlib')) ||
-             ($val['method'] == 0x0))) {
-            $mime_part = $this->_mimepart;
-            $mime_part->setName(basename($name));
-            $val['name'] = str_replace($name, $this->_params['contents']->linkView($mime_part, 'download_render', $name, array('jstext' => sprintf(_("View %s"), str_replace('&nbsp;', ' ', $name)), 'class' => 'fixed', 'params' => array('zip_attachment' => urlencode($key) + 1))), $val['name']);
-        }
-
-        return $val;
-    }
-}