More MIME->Mime fixes. More work on render API.
authorMichael M Slusarz <slusarz@curecanti.org>
Mon, 10 Nov 2008 21:46:37 +0000 (14:46 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Mon, 10 Nov 2008 21:46:37 +0000 (14:46 -0700)
Rendering API is starting to solidify. Give calling code full control
over the information to parse. Determine inline/info rendering status
when obtaining summary information.

38 files changed:
imp/lib/Contents.php
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/notification.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/pkcs7.php [deleted file]
imp/lib/MIME/Viewer/plain.php [deleted file]
imp/lib/MIME/Viewer/related.php [deleted file]
imp/lib/MIME/Viewer/rfc822.php [deleted file]
imp/lib/MIME/Viewer/smil.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]
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/notification.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/pkcs7.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/rfc822.php [new file with mode: 0644]
imp/lib/Mime/Viewer/smil.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/message.php

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