Example #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;
 }
Example #2
0
 /**
  * @dataProvider idArithmeticProvider
  */
 public function testIdArithmetic($id, $action, $opts, $expected)
 {
     $id_ob = new Horde_Mime_Id($id);
     $this->assertEquals($expected, $id_ob->idArithmetic($action, $opts));
 }
Example #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;
 }
Example #4
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;
 }
Example #5
0
 /**
  * @deprecated  Use Horde_Mime_Id instead.
  */
 public static function mimeIdArithmetic($id, $action, $options = array())
 {
     $id_ob = new Horde_Mime_Id($id);
     switch ($action) {
         case 'down':
             $action = $id_ob::ID_DOWN;
             break;
         case 'next':
             $action = $id_ob::ID_NEXT;
             break;
         case 'prev':
             $action = $id_ob::ID_PREV;
             break;
         case 'up':
             $action = $id_ob::ID_UP;
             break;
     }
     return $id_ob->idArithmetic($action, $options);
 }
Example #6
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;
 }
Example #7
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;
 }
Example #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 = $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;
 }
Example #9
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;
 }