Exemple #1
0
 /**
  * Render the part based on the view mode.
  *
  * @param boolean $inline  True if viewing inline.
  *
  * @return array  See parent::render().
  */
 protected function _IMPrender($inline)
 {
     /* RFC 1740 [4]: There are two parts to an appledouble message:
      *   (1) application/applefile
      *   (2) Data embedded in the Mac file
      * Since the resource fork is not very useful to us, only provide a
      * means to download. */
     /* Display the resource fork download link. */
     $iterator = $this->_mimepart->partIterator();
     $iterator->rewind();
     $mime_id = $iterator->current()->getMimeId();
     $iterator->next();
     $applefile_id = $iterator->current()->getMimeId();
     $id_ob = new Horde_Mime_Id($applefile_id);
     $data_id = $id_ob->idArithmetic($id_ob::ID_NEXT);
     $applefile_part = $this->_mimepart[$applefile_id];
     $data_part = $this->_mimepart[$data_id];
     $data_name = $this->getConfigParam('imp_contents')->getPartName($data_part);
     $status = new IMP_Mime_Status($this->_mimepart, array(sprintf(_("This message contains a Macintosh file (named \"%s\")."), $data_name), $this->getConfigParam('imp_contents')->linkViewJS($applefile_part, 'download_attach', "Download the Macintosh resource fork.")));
     $status->icon('mime/apple.png', _("Macintosh File"));
     /* For inline viewing, attempt to display the data inline. */
     $ret = array();
     if ($inline && ($disp = $this->getConfigParam('imp_contents')->canDisplay($data_part, IMP_Contents::RENDER_INLINE | IMP_Contents::RENDER_INFO))) {
         $ret = $this->getConfigParam('imp_contents')->renderMIMEPart($data_id, $disp);
     }
     foreach ($iterator as $ob) {
         $id = $ob->getMimeId();
         if (!isset($ret[$id]) && strcmp($id, $data_id) !== 0) {
             $ret[$id] = strcmp($id, $mime_id) === 0 ? array('data' => '', 'status' => $status, 'type' => 'text/html; charset=' . $this->getConfigParam('charset'), 'wrap' => 'mimePartWrap') : null;
         }
     }
     return $ret;
 }
Exemple #2
0
 /**
  * @dataProvider isChildProvider
  */
 public function testIsChild($base, $id, $expected)
 {
     $id_ob = new Horde_Mime_Id($base);
     if ($expected) {
         $this->assertTrue($id_ob->isChild($id));
     } else {
         $this->assertFalse($id_ob->isChild($id));
     }
 }
Exemple #3
0
 /**
  * Find a MIME type in parent parts.
  *
  * @param string $id    The MIME ID to begin the search at.
  * @param string $type  The MIME type to search for.
  *
  * @return mixed  Either the requested MIME part, or null if not found.
  */
 public function findMimeType($id, $type)
 {
     $id_ob = new Horde_Mime_Id($id);
     while (($id_ob->id = $id_ob->idArithmetic($id_ob::ID_UP)) !== null) {
         if (($part = $this->getMimePart($id_ob->id, array('nocontents' => true))) && $part->getType() == $type) {
             return $part;
         }
     }
     return null;
 }
Exemple #4
0
 /**
  * Render out the currently set contents.
  *
  * @param boolean $inline  Are we viewing inline?
  *
  * @return array  See self::render().
  */
 protected function _IMPrender($inline)
 {
     $related_id = $this->_mimepart->getMimeId();
     $used = array($related_id);
     if (!($id = $this->_init($inline))) {
         return array();
     }
     $render = $this->getConfigParam('imp_contents')->renderMIMEPart($id, $inline ? IMP_Contents::RENDER_INLINE : IMP_Contents::RENDER_FULL);
     if (!$inline) {
         foreach (array_keys($render) as $key) {
             if (!is_null($render[$key])) {
                 return array($related_id => $render[$key]);
             }
         }
         return null;
     }
     $data_id = null;
     $ret = array();
     foreach ($this->_mimepart->partIterator(false) as $val) {
         $ret[$val->getMimeId()] = null;
     }
     foreach (array_keys($render) as $val) {
         $ret[$val] = $render[$val];
         if ($ret[$val]) {
             $data_id = $val;
         }
     }
     if (!is_null($data_id)) {
         $this->_mimepart->setMetadata('viewable_part', $data_id);
         /* We want the inline display to show multipart/related vs. the
          * viewable MIME part.  This is because a multipart/related part
          * is not downloadable and clicking on the MIME part may not
          * produce the desired result in the full display (i.e. HTML parts
          * with related images). */
         if (strcmp($data_id, $related_id) !== 0) {
             $ret[$related_id] = $ret[$data_id];
             $ret[$data_id] = null;
         }
     }
     /* Fix for broken messages that don't refer to a related CID part
      * within the base part. */
     if ($cids_used = $this->_mimepart->getMetadata('related_cids_used')) {
         $used = array_merge($used, $cids_used);
     }
     $id_ob = new Horde_Mime_Id($id);
     foreach (array_diff(array_keys($ret), $used) as $val) {
         if (strcmp($val, $id) !== 0 && !$id_ob->isChild($val)) {
             $summary = $this->getConfigParam('imp_contents')->getSummary($val, IMP_Contents::SUMMARY_SIZE | IMP_Contents::SUMMARY_ICON | IMP_Contents::SUMMARY_DESCRIP_LINK | IMP_Contents::SUMMARY_DOWNLOAD);
             $status = new IMP_Mime_Status_RenderIssue($this->_mimepart, array(_("This part contains an attachment that can not be displayed within this part:"), implode(' ', array($summary['icon'], $summary['description'], $summary['size'], $summary['download']))));
             $status->action($status::WARNING);
             if (isset($ret[$related_id]['status'])) {
                 if (!is_array($ret[$related_id]['status'])) {
                     $ret[$related_id]['status'] = array($ret[$related_id]['status']);
                 }
             } else {
                 $ret[$related_id]['status'] = array();
             }
             $ret[$related_id]['status'][] = $status;
         }
     }
     return $ret;
 }
Exemple #5
0
 /**
  * Generates HTML output for 'multipart/signed' MIME parts.
  *
  * @return string  The HTML output.
  */
 protected function _outputPGPSigned()
 {
     global $injector, $prefs, $session;
     $iterator = $this->_mimepart->partIterator();
     $iterator->rewind();
     $base_id = $iterator->current()->getMimeId();
     $iterator->next();
     $signed_id = $iterator->current()->getMimeId();
     $id_ob = new Horde_Mime_Id($signed_id);
     $sig_id = $id_ob->idArithmetic($id_ob::ID_NEXT);
     if (!IMP_Pgp::enabled()) {
         return array($sig_id => null);
     }
     $status = new IMP_Mime_Status($this->_mimepart);
     $status->addText(_("The data in this part has been digitally signed via PGP."));
     $status->icon('mime/encryption.png', 'PGP');
     $ret = array($base_id => array('data' => '', 'nosummary' => true, 'status' => array($status), 'type' => 'text/html; charset=' . $this->getConfigParam('charset'), 'wrap' => 'mimePartWrap'), $sig_id => null);
     if ($prefs->getValue('pgp_verify') || $injector->getInstance('Horde_Variables')->pgp_verify_msg) {
         $imp_contents = $this->getConfigParam('imp_contents');
         $sig_part = $imp_contents->getMimePart($sig_id);
         $status2 = new IMP_Mime_Status($this->_mimepart);
         if (!$sig_part) {
             $status2->action(IMP_Mime_Status::ERROR);
             $sig_text = _("This digitally signed message is broken.");
             $ret[$base_id]['wrap'] = 'mimePartWrapInvalid';
         } else {
             /* Close session, since this may be a long-running
              * operation. */
             $session->close();
             try {
                 $imp_pgp = $injector->getInstance('IMP_Pgp');
                 if ($sig_raw = $sig_part->getMetadata(Horde_Crypt_Pgp_Parse::SIG_RAW)) {
                     $sig_result = $imp_pgp->verifySignature($sig_raw, $this->_getSender()->bare_address, null, $sig_part->getMetadata(Horde_Crypt_Pgp_Parse::SIG_CHARSET));
                 } else {
                     $stream = $imp_contents->isEmbedded($signed_id) ? $this->_mimepart->getMetadata(self::PGP_SIGN_ENC) : $imp_contents->getBodyPart($signed_id, array('mimeheaders' => true, 'stream' => true))->data;
                     rewind($stream);
                     stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol');
                     $filter = stream_filter_append($stream, 'horde_eol', STREAM_FILTER_READ, array('eol' => Horde_Mime_Part::RFC_EOL));
                     $sig_result = $imp_pgp->verifySignature(stream_get_contents($stream), $this->_getSender()->bare_address, $sig_part->getContents());
                     stream_filter_remove($filter);
                 }
                 $status2->action(IMP_Mime_Status::SUCCESS);
                 $sig_text = $sig_result->message;
                 $ret[$base_id]['wrap'] = 'mimePartWrapValid';
             } catch (Horde_Exception $e) {
                 $status2->action(IMP_Mime_Status::ERROR);
                 $sig_text = $e->getMessage();
                 $ret[$base_id]['wrap'] = 'mimePartWrapInvalid';
             }
         }
         $status2->addText($this->_textFilter($sig_text, 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::NOHTML)));
         $ret[$base_id]['status'][] = $status2;
     } else {
         $status->addMimeAction('pgpVerifyMsg', _("Click to verify the message."));
     }
     return $ret;
 }
Exemple #6
0
 /**
  * Generate inline message display.
  *
  * @param array $options  Options:
  *   - mask: (integer) The mask needed for a getSummary() call.
  *   - mimeid: (string) Restrict output to this MIME ID (and children).
  *
  * @return array  See getInlineOutput().
  */
 protected function _getInlineOutput(array $options)
 {
     global $prefs, $registry;
     $atc_parts = $display_ids = $i = $metadata = $msgtext = $wrap_ids = array();
     $text_out = '';
     $view = $registry->getView();
     $contents_mask = isset($options['mask']) ? $options['mask'] : 0;
     $mimeid_filter = isset($options['mimeid']) ? new Horde_Mime_Id($options['mimeid']) : null;
     $show_parts = $prefs->getValue('parts_display');
     foreach ($this->contents->getMIMEMessage()->partIterator() as $part) {
         $mime_id = $part->getMimeId();
         $i[] = $mime_id;
         if (isset($display_ids[$mime_id]) || isset($atc_parts[$mime_id])) {
             continue;
         }
         if ($mimeid_filter && (strval($mimeid_filter) != $mime_id && !$mimeid_filter->isChild($mime_id))) {
             continue;
         }
         if (!($render_mode = $this->contents->canDisplay($mime_id, IMP_Contents::RENDER_INLINE_AUTO))) {
             if (IMP_Mime_Attachment::isAttachment($part)) {
                 if ($show_parts == 'atc') {
                     $atc_parts[$mime_id] = 1;
                 }
                 if ($contents_mask) {
                     $msgtext[$mime_id] = array('text' => $this->_formatSummary($this->contents->getSummary($mime_id, $contents_mask), true));
                 }
             }
             continue;
         }
         $render_part = $this->contents->renderMIMEPart($mime_id, $render_mode);
         if ($show_parts == 'atc' && IMP_Mime_Attachment::isAttachment($part) && (empty($render_part) || !($render_mode & IMP_Contents::RENDER_INLINE))) {
             $atc_parts[$mime_id] = 1;
         }
         if (empty($render_part)) {
             if ($contents_mask && IMP_Mime_Attachment::isAttachment($part)) {
                 $msgtext[$mime_id] = array('text' => $this->_formatSummary($this->contents->getSummary($mime_id, $contents_mask), true));
             }
             continue;
         }
         reset($render_part);
         while (list($id, $info) = each($render_part)) {
             $display_ids[$id] = 1;
             if (empty($info)) {
                 continue;
             }
             $part_text = $contents_mask && empty($info['nosummary']) ? $this->_formatSummary($this->contents->getSummary($id, $contents_mask), !empty($info['attach'])) : '';
             if (empty($info['attach'])) {
                 if (isset($info['status'])) {
                     if (!is_array($info['status'])) {
                         $info['status'] = array($info['status']);
                     }
                     $render_issues = array();
                     foreach ($info['status'] as $val) {
                         if (in_array($view, $val->views)) {
                             if ($val instanceof IMP_Mime_Status_RenderIssue) {
                                 $render_issues[] = $val;
                             } else {
                                 $part_text .= strval($val);
                             }
                         }
                     }
                     if (!empty($render_issues)) {
                         $render_issues_ob = new IMP_Mime_Status_RenderIssue_Display();
                         $render_issues_ob->addIssues($render_issues);
                         $part_text .= strval($render_issues_ob);
                     }
                 }
                 $part_text .= '<div class="mimePartData">' . $info['data'] . '</div>';
             } elseif ($show_parts == 'atc') {
                 $atc_parts[$id] = 1;
             }
             $msgtext[$id] = array('text' => $part_text, 'wrap' => empty($info['wrap']) ? null : $info['wrap']);
             if (isset($info['metadata'])) {
                 /* Format: array(identifier, ...[data]...) */
                 $metadata = array_merge($metadata, $info['metadata']);
             }
         }
     }
     if (!empty($msgtext)) {
         uksort($msgtext, 'strnatcmp');
     }
     reset($msgtext);
     while (list($id, $part) = each($msgtext)) {
         while (!empty($wrap_ids)) {
             $id_ob = new Horde_Mime_Id(end($wrap_ids));
             if ($id_ob->isChild($id)) {
                 break;
             }
             array_pop($wrap_ids);
             $text_out .= '</div>';
         }
         if (!empty($part['wrap'])) {
             $text_out .= '<div class="' . $part['wrap'] . '" impcontentsmimeid="' . $id . '">';
             $wrap_ids[] = $id;
         }
         $text_out .= '<div class="mimePartBase"' . (empty($part['wrap']) ? ' impcontentsmimeid="' . $id . '"' : '') . '>' . $part['text'] . '</div>';
     }
     $text_out .= str_repeat('</div>', count($wrap_ids));
     if (!strlen($text_out)) {
         $text_out = strval(new IMP_Mime_Status(null, _("There are no parts that can be shown inline.")));
     }
     $atc_parts = $show_parts == 'all' ? $i : array_keys($atc_parts);
     return array('atc_parts' => $atc_parts, 'display_ids' => array_keys($display_ids), 'metadata' => $metadata, 'msgtext' => $text_out, 'one_part' => count($i) === 1);
 }
Exemple #7
0
 /**
  * @deprecated  Use Horde_Mime_Id instead.
  */
 public static function isChild($base, $id)
 {
     $id_ob = new Horde_Mime_Id($base);
     return $id_ob->isChild($id);
 }
Exemple #8
0
 /**
  * Return the rendered information about the Horde_Mime_Part object.
  *
  * @return array  See parent::render().
  */
 protected function _renderInfo()
 {
     $imp_contents = $this->getConfigParam('imp_contents');
     $machine = $original = null;
     $ret = array();
     switch ($this->_mimepart->getType()) {
         case 'message/disposition-notification':
             /* Outlook can send a disposition-notification without the
              * RFC-required multipart/report wrapper. */
             $machine = $imp_contents->getMimePart($this->_mimepart->getMimeId());
             break;
         case 'multipart/report':
             /* RFC 3798 [3]: There are three parts to a delivery status
              * multipart/report message:
              *   (1) Human readable message
              *   (2) Machine parsable body part
              *       [message/disposition-notification]
              *   (3) Original message (optional) */
             $iterator = $this->_mimepart->partIterator(false);
             $iterator->rewind();
             if (!($curr = $iterator->current())) {
                 break;
             }
             $part1_id = $curr->getMimeId();
             $id_ob = new Horde_Mime_Id($part1_id);
             /* Technical details. */
             $id_ob->id = $id_ob->idArithmetic($id_ob::ID_NEXT);
             $ret[$id_ob->id] = null;
             $machine = $imp_contents->getMimePart($id_ob->id);
             /* Original sent message. */
             $original = $imp_contents->getMimePart($id_ob->idArithmetic($id_ob::ID_NEXT));
             if ($original) {
                 foreach ($this->_mimepart->partIterator() as $val) {
                     $ret[$val->getMimeId()] = null;
                 }
                 /* Allow the human readable part to be displayed
                  * separately. */
                 unset($ret[$part1_id]);
             }
             break;
         default:
             return array($this->_mimepart->getMimeId() => null);
     }
     $mdn_status = array(_("A message you have sent has resulted in a return notification from the recipient."));
     if ($machine) {
         $parse = Horde_Mime_Headers::parseHeaders(preg_replace('/\\n{2,}/', "\n", strtr($machine->getContents(), "\r", "\n")));
         if (isset($parse['Final-Recipient'])) {
             list(, $recip) = explode(';', $parse['Final-Recipient']->value_single);
             if ($recip) {
                 $mdn_status[] = sprintf(_("Recipient: %s"), trim($recip));
             }
         }
         if (isset($parse['Disposition'])) {
             list($modes, $type) = explode(';', $parse['Disposition']->value_single);
             list($action, $sent) = explode('/', $modes);
             switch (trim(Horde_String::lower($type))) {
                 case 'displayed':
                     $mdn_status[] = _("The message has been displayed to the recipient.");
                     break;
                 case 'deleted':
                     $mdn_status[] = _("The message has been deleted by the recipient; it is unknown whether they viewed the message.");
                     break;
             }
             switch (trim(Horde_String::lower($action))) {
                 case 'manual-action':
                     // NOOP
                     break;
                 case 'automatic-action':
                     // NOOP
                     break;
             }
             switch (trim(Horde_String::lower($sent))) {
                 case 'mdn-sent-manually':
                     $mdn_status[] = _("This notification was explicitly sent by the recipient.");
                     break;
                 case 'mdn-sent-automatically':
                     // NOOP
                     break;
             }
         }
     }
     $status = new IMP_Mime_Status($this->_mimepart, $mdn_status);
     $status->icon('info_icon.png', _("Info"));
     if ($original) {
         $status->addText($imp_contents->linkViewJS($original, 'view_attach', _("View the text of the original sent message."), array('params' => array('ctype' => 'message/rfc822', 'mode' => IMP_Contents::RENDER_FULL))));
     }
     $ret[$this->_mimepart->getMimeId()] = array('data' => '', 'status' => $status, 'type' => 'text/html; charset=' . $this->getConfigParam('charset'), 'wrap' => 'mimePartWrap');
     return $ret;
 }
Exemple #9
0
 /**
  * Parse signed data.
  *
  * @param boolean $sig_only  Only do signature checking?
  *
  * @return mixed  See self::_getEmbeddedMimeParts().
  */
 protected function _parseSignedData($sig_only = false)
 {
     $iterator = $this->_mimepart->partIterator();
     $iterator->rewind();
     if (!($curr = $iterator->current())) {
         return null;
     }
     $base_id = $curr->getMimeId();
     $iterator->next();
     if (!($curr = $iterator->current())) {
         // application/pkcs-7-mime might be the base part.
         // See RFC 5751 3.4.2
         $data_id = $base_id;
     } else {
         $data_id = $curr->getMimeId();
     }
     $id_ob = new Horde_Mime_Id($data_id);
     $sig_id = $id_ob->idArithmetic($id_ob::ID_NEXT);
     /* Initialize inline data. */
     $status = new IMP_Mime_Status($this->_mimepart, _("The data in this part has been digitally signed via S/MIME."));
     $status->icon('mime/encryption.png', 'S/MIME');
     $cache = $this->getConfigParam('imp_contents')->getViewCache();
     $cache->smime[$base_id] = array('sig' => $sig_id, 'status' => $status, 'wrap' => 'mimePartWrap');
     if (!IMP_Smime::enabled()) {
         $status->addText(_("S/MIME support is not enabled so the digital signature is unable to be verified."));
         return null;
     }
     $imp_contents = $this->getConfigParam('imp_contents');
     $stream = $imp_contents->isEmbedded($base_id) ? $this->_mimepart->getMetadata('imp-smime-decrypt')->stream : $this->_getPartStream($base_id);
     $raw_text = $this->_mimepart->replaceEOL($stream, Horde_Mime_Part::RFC_EOL);
     $this->_initSmime();
     $sig_result = null;
     if ($GLOBALS['prefs']->getValue('smime_verify') || $GLOBALS['injector']->getInstance('Horde_Variables')->smime_verify_msg) {
         try {
             $sig_result = $this->_impsmime->verifySignature($raw_text);
             if ($sig_result->verify) {
                 $status->action(IMP_Mime_Status::SUCCESS);
             } else {
                 $status->action(IMP_Mime_Status::WARNING);
             }
             if (!is_array($sig_result->email)) {
                 $sig_result->email = array($sig_result->email);
             }
             $email = implode(', ', $sig_result->email);
             $cache->smime[$base_id]['wrap'] = 'mimePartWrapValid';
             $status->addText($sig_result->msg);
             if (!empty($sig_result->cert)) {
                 $cert = $this->_impsmime->parseCert($sig_result->cert);
                 if (isset($cert['certificate']['subject']['CommonName']) && strcasecmp($email, $cert['certificate']['subject']['CommonName']) !== 0) {
                     $email = $cert['certificate']['subject']['CommonName'] . ' (' . trim($email) . ')';
                 }
             }
             if (!empty($sig_result->cert) && isset($sig_result->email) && $GLOBALS['registry']->hasMethod('contacts/addField') && $GLOBALS['prefs']->getValue('add_source')) {
                 $status->addText(sprintf(_("Sender: %s"), $imp_contents->linkViewJS($this->_mimepart, 'view_attach', htmlspecialchars($email), array('jstext' => _("View certificate details"), 'params' => array('mode' => IMP_Contents::RENDER_INLINE, 'view_smime_key' => 1)))));
                 foreach ($sig_result->email as $single_email) {
                     try {
                         $this->_impsmime->getPublicKey($single_email);
                     } catch (Horde_Exception $e) {
                         $imple = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Imple')->create('IMP_Ajax_Imple_ImportEncryptKey', array('mime_id' => $base_id, 'muid' => strval($imp_contents->getIndicesOb()), 'type' => 'smime'));
                         $status->addText(Horde::link('#', '', '', '', '', '', '', array('id' => $imple->getDomId())) . _("Save the certificate to your Address Book.") . '</a>');
                         break;
                     }
                 }
             } elseif (strlen($email)) {
                 $status->addText(sprintf(_("Sender: %s"), htmlspecialchars($email)));
             }
         } catch (Horde_Exception $e) {
             $status->action(IMP_Mime_Status::ERROR);
             $cache->smime[$base_id]['wrap'] = 'mimePartWrapInvalid';
             $status->addText($e->getMessage());
         }
     } else {
         $status->addMimeAction('smimeVerifyMsg', _("Click to verify the data."));
     }
     if ($sig_only) {
         return;
     }
     if (!($subpart = $imp_contents->getMimePart($sig_id))) {
         try {
             $msg_data = $this->_impsmime->extractSignedContents($raw_text);
             $subpart = Horde_Mime_Part::parseMessage($msg_data, array('forcemime' => true));
         } catch (Horde_Exception $e) {
             $status->addText($e->getMessage());
             return null;
         }
     }
     return $subpart;
 }
Exemple #10
0
 /**
  * Regenerates body text for use in the compose screen from IMAP data.
  *
  * @param IMP_Contents $contents  An IMP_Contents object.
  * @param array $options          Additional options:
  * <ul>
  *  <li>html: (boolean) Return text/html part, if available.</li>
  *  <li>imp_msg: (integer) If non-empty, the message data was created by
  *               IMP. Either:
  *   <ul>
  *    <li>self::COMPOSE</li>
  *    <li>self::FORWARD</li>
  *    <li>self::REPLY</li>
  *   </ul>
  *  </li>
  *  <li>replylimit: (boolean) Enforce length limits?</li>
  *  <li>toflowed: (boolean) Do flowed conversion?</li>
  * </ul>
  *
  * @return mixed  Null if bodypart not found, or array with the following
  *                keys:
  *   - charset: (string) The guessed charset to use.
  *   - flowed: (Horde_Text_Flowed) A flowed object, if the text is flowed.
  *             Otherwise, null.
  *   - id: (string) The MIME ID of the bodypart.
  *   - mode: (string) Either 'text' or 'html'.
  *   - text: (string) The body text.
  */
 protected function _getMessageText($contents, array $options = array())
 {
     global $conf, $injector, $notification, $prefs;
     $body_id = null;
     $mode = 'text';
     $options = array_merge(array('imp_msg' => self::COMPOSE), $options);
     if (!empty($options['html']) && self::canHtmlCompose() && ($body_id = $contents->findBody('html')) !== null) {
         $mime_message = $contents->getMIMEMessage();
         switch ($mime_message->getPrimaryType()) {
             case 'multipart':
                 if ($body_id != '1' && $mime_message->getSubType() == 'mixed' && ($id_ob = new Horde_Mime_Id('1')) && !$id_ob->isChild($body_id)) {
                     $body_id = null;
                 } else {
                     $mode = 'html';
                 }
                 break;
             default:
                 if (strval($body_id) != '1') {
                     $body_id = null;
                 } else {
                     $mode = 'html';
                 }
                 break;
         }
     }
     if (is_null($body_id)) {
         $body_id = $contents->findBody();
         if (is_null($body_id)) {
             return null;
         }
     }
     if (!($part = $contents->getMimePart($body_id))) {
         return null;
     }
     $type = $part->getType();
     $part_charset = $part->getCharset();
     $msg = Horde_String::convertCharset($part->getContents(), $part_charset, 'UTF-8');
     /* Enforce reply limits. */
     if (!empty($options['replylimit']) && !empty($conf['compose']['reply_limit'])) {
         $limit = $conf['compose']['reply_limit'];
         if (Horde_String::length($msg) > $limit) {
             $msg = Horde_String::substr($msg, 0, $limit) . "\n" . _("[Truncated Text]");
         }
     }
     if ($mode == 'html') {
         $dom = $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($msg, 'Xss', array('charset' => $this->charset, 'return_dom' => true, 'strip_style_attributes' => false));
         /* If we are replying to a related part, and this part refers
          * to local message parts, we need to move those parts into this
          * message (since the original message may disappear during the
          * compose process). */
         if ($related_part = $contents->findMimeType($body_id, 'multipart/related')) {
             $this->_setMetadata('related_contents', $contents);
             $related_ob = new Horde_Mime_Related($related_part);
             $related_ob->cidReplace($dom, array($this, '_getMessageTextCallback'), $part_charset);
             $this->_setMetadata('related_contents', null);
         }
         /* Convert any Data URLs to attachments. */
         $xpath = new DOMXPath($dom->dom);
         foreach ($xpath->query('//*[@src]') as $val) {
             $data_url = new Horde_Url_Data($val->getAttribute('src'));
             if (strlen($data_url->data)) {
                 $data_part = new Horde_Mime_Part();
                 $data_part->setContents($data_url->data);
                 $data_part->setType($data_url->type);
                 try {
                     $atc = $this->addAttachmentFromPart($data_part);
                     $val->setAttribute('src', $atc->viewUrl());
                     $this->addRelatedAttachment($atc, $val, 'src');
                 } catch (IMP_Compose_Exception $e) {
                     $notification->push($e, 'horde.warning');
                 }
             }
         }
         $msg = $dom->returnBody();
     } elseif ($type == 'text/html') {
         $msg = $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($msg, 'Html2text');
         $type = 'text/plain';
     }
     /* Always remove leading/trailing whitespace. The data in the
      * message body is not intended to be the exact representation of the
      * original message (use forward as message/rfc822 part for that). */
     $msg = trim($msg);
     if ($type == 'text/plain') {
         if ($prefs->getValue('reply_strip_sig') && ($pos = strrpos($msg, "\n-- ")) !== false) {
             $msg = rtrim(substr($msg, 0, $pos));
         }
         /* Remove PGP armored text. */
         $pgp = $injector->getInstance('Horde_Crypt_Pgp_Parse')->parseToPart($msg);
         if (!is_null($pgp)) {
             $msg = '';
             $pgp->buildMimeIds();
             foreach ($pgp->partIterator() as $val) {
                 if ($val->getPrimaryType() === 'text') {
                     $msg .= $val->getContents();
                 }
             }
         }
         if ($part->getContentTypeParameter('format') == 'flowed') {
             $flowed = new Horde_Text_Flowed($msg, 'UTF-8');
             if (Horde_String::lower($part->getContentTypeParameter('delsp')) == 'yes') {
                 $flowed->setDelSp(true);
             }
             $flowed->setMaxLength(0);
             $msg = $flowed->toFixed(false);
         } else {
             /* If the input is *not* in flowed format, make sure there is
              * no padding at the end of lines. */
             $msg = preg_replace("/\\s*\n/U", "\n", $msg);
         }
         if (isset($options['toflowed'])) {
             $flowed = new Horde_Text_Flowed($msg, 'UTF-8');
             $msg = $options['toflowed'] ? $flowed->toFlowed(true) : $flowed->toFlowed(false, array('nowrap' => true));
         }
     }
     if (strcasecmp($part->getCharset(), 'windows-1252') === 0) {
         $part_charset = 'ISO-8859-1';
     }
     return array('charset' => $part_charset, 'flowed' => isset($flowed) ? $flowed : null, 'id' => $body_id, 'mode' => $mode, 'text' => $msg);
 }
Exemple #11
0
 /**
  * Return the rendered information about the Horde_Mime_Part object.
  *
  * @return array  See parent::render().
  */
 protected function _renderInfo()
 {
     $imp_contents = $this->getConfigParam('imp_contents');
     $machine = $original = $status = null;
     $mime_id = $this->_mimepart->getMimeId();
     $ret = array();
     switch ($this->_mimepart->getType()) {
         case 'message/delivery-status':
             $machine = $imp_contents->getMimePart($mime_id);
             break;
         case 'multipart/report':
             /* 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) */
             $iterator = $this->_mimepart->partIterator(false);
             $iterator->rewind();
             if (!($curr = $iterator->current())) {
                 break;
             }
             $part1_id = $curr->getMimeId();
             $id_ob = new Horde_Mime_Id($part1_id);
             /* Technical details. */
             $id_ob->id = $id_ob->idArithmetic($id_ob::ID_NEXT);
             $ret[$id_ob->id] = null;
             $machine = $imp_contents->getMimePart($id_ob->id);
             /* Returned message. */
             $original = $imp_contents->getMimePart($id_ob->idArithmetic($id_ob::ID_NEXT));
             if ($original) {
                 foreach ($this->_mimepart->partIterator() as $val) {
                     $ret[$val->getMimeId()] = null;
                 }
                 /* Allow the human readable part to be displayed
                  * separately. */
                 unset($ret[$part1_id]);
             }
             break;
     }
     if (!$machine) {
         return array($mime_id => null);
     }
     $parse = Horde_Mime_Headers::parseHeaders(preg_replace('/\\n{2,}/', "\n", strtr($machine->getContents(), "\r", "\n")));
     /* Information on the message status is found in the 'Action'
      * field located in part #2 (RFC 3464 [2.3.3]). */
     if (isset($parse['Action'])) {
         switch (trim($parse['Action']->value_single)) {
             case 'failed':
             case 'delayed':
                 $msg_link = _("View details of the returned message.");
                 $status_action = IMP_Mime_Status::ERROR;
                 $status_msg = _("ERROR: Your message could not be delivered.");
                 break;
             case 'delivered':
             case 'expanded':
             case 'relayed':
                 $msg_link = _("View details of the delivered message.");
                 $status_action = IMP_Mime_Status::SUCCESS;
                 $status_msg = _("Your message was successfully delivered.");
                 break;
         }
         if (isset($msg_link)) {
             $status = new IMP_Mime_Status($this->_mimepart, $status_msg);
             $status->action($status_action);
             if (isset($parse['Final-Recipient'])) {
                 list(, $recip) = explode(';', $parse['Final-Recipient']->value_single);
                 $recip_ob = new Horde_Mail_Rfc822_List($recip);
                 if (count($recip_ob)) {
                     $status->addText(sprintf(_("Recipient: %s"), $recip_ob[0]));
                 }
             }
             /* Display a link to the returned message, if it exists. */
             if ($original) {
                 $status->addText($imp_contents->linkViewJS($original, 'view_attach', $msg_link, array('params' => array('ctype' => 'message/rfc822'))));
             }
         }
     }
     $ret[$mime_id] = array_filter(array('data' => '', 'status' => $status ?: null, 'type' => 'text/html; charset=' . $this->getConfigParam('charset'), 'wrap' => 'mimePartWrap'));
     return $ret;
 }
Exemple #12
0
 /**
  * Render out the currently set contents.
  *
  * @param boolean $inline  Are we viewing inline?
  *
  * @return array  See parent::render().
  */
 protected function _IMPrender($inline)
 {
     $base_id = $this->_mimepart->getMimeId();
     $display_ids = $ret = array();
     $prefer_plain = $GLOBALS['prefs']->getValue('alternative_display') == 'text';
     /* Look for a displayable part. RFC: show the LAST choice that can be
      * displayed inline. If an alternative is itself a multipart, the user
      * agent is allowed to show that alternative, an earlier alternative,
      * or both. If we find a multipart alternative that contains at least
      * one viewable part, we will display all viewable subparts of that
      * alternative. */
     $imp_contents = $this->getConfigParam('imp_contents');
     foreach ($this->_mimepart->partIterator() as $val) {
         $id = $val->getMimeId();
         $ret[$id] = null;
         if (strcmp($base_id, $id) !== 0 && $imp_contents->canDisplay($id, $inline ? IMP_Contents::RENDER_INLINE : IMP_Contents::RENDER_FULL) && (!$prefer_plain || $val->getType() != 'text/html' && $val->getPrimaryType() == 'text')) {
             $display_ids[strval($id)] = true;
         }
     }
     /* If we found no IDs, return now. */
     if (empty($display_ids)) {
         $ret[$base_id] = array('data' => '', 'status' => new IMP_Mime_Status($this->_mimepart, _("There are no alternative parts that can be displayed inline.")), 'type' => 'text/html; charset=' . $this->getConfigParam('charset'));
         return $ret;
     }
     /* If the last viewable message exists in a subpart, back up to the
      * base multipart and display all viewable parts in that multipart.
      * Else, display the single part. */
     end($display_ids);
     $curr_id = key($display_ids);
     while (!is_null($curr_id) && strcmp($base_id, $curr_id) !== 0) {
         if (array_key_exists($curr_id, $ret)) {
             $disp_id = $curr_id;
         }
         $id_ob = new Horde_Mime_Id($curr_id);
         $curr_id = $id_ob->idArithmetic($id_ob::ID_UP);
     }
     /* At this point, $ret contains stubs for all parts living in the base
      * alternative part.
      * Go through all subparts of displayable part and make sure all parts
      * are rendered.  Parts not rendered will be marked as not being
      * handled by this viewer (Bug #9365). */
     $render_part = $this->_mimepart[$disp_id];
     foreach ($render_part->partIterator() as $val) {
         $id = $val->getMimeId();
         $need_render[$id] = $subparts[$id] = true;
     }
     /* Track whether there is at least one viewable (non-empty) part. */
     $viewable = false;
     $viewable_ret = $ret;
     foreach (array_keys($subparts) as $val) {
         if (isset($display_ids[$val]) && isset($need_render[$val])) {
             $render = $this->getConfigParam('imp_contents')->renderMIMEPart($val, $inline ? IMP_Contents::RENDER_INLINE : IMP_Contents::RENDER_FULL);
             foreach (array_keys($render) as $id) {
                 unset($need_render[$id]);
                 if (!$inline) {
                     if (!is_null($render[$id])) {
                         return array($base_id => $render[$id]);
                     }
                 } else {
                     $ret[$id] = $render[$id];
                     if (!is_null($ret[$id])) {
                         $viewable = true;
                     }
                 }
             }
         }
     }
     if (!$inline) {
         return null;
     }
     unset($need_render[$disp_id]);
     foreach (array_keys($need_render) as $val) {
         unset($ret[$val]);
     }
     /* If we reach this point, and have at least one subpart with no
      * viewable parts, check to see there is not a richer, non-inline
      * viewable part that exists in the message. */
     if (!$viewable) {
         $id_ob = new Horde_Mime_Id($disp_id);
         if (array_key_exists($id_ob->idArithmetic($id_ob::ID_NEXT), $viewable_ret)) {
             $ret[$disp_id] = array('data' => '', 'status' => new IMP_Mime_Status($this->_mimepart, array(_("This part contains no message contents."), _("There are no alternative parts that can be displayed inline."))), 'type' => 'text/html; charset=' . $this->getConfigParam('charset'));
         }
     }
     return $ret;
 }