Returns the decoded body part size for a MIME ID.
public bodyPartSize ( string $id ) | ||
$id | string | The MIME ID to obtain the decoded body part size for. |
/** * Fetch data from the IMAP client. * * @param array $params Parameter array. * - html_id (string) The MIME id of the HTML part, if any. * - text_id (string) The MIME id of the plain part, if any. * * @return Horde_Imap_Client_Data_Fetch The results. */ protected function _fetchData(array $params) { $query = new Horde_Imap_Client_Fetch_Query(); $query_opts = array('decode' => true, 'peek' => true); // Get body information if ($this->_version >= Horde_ActiveSync::VERSION_TWELVE) { if (!empty($params['html_id'])) { $query->bodyPartSize($params['html_id']); $query->bodyPart($params['html_id'], $query_opts); } if (!empty($params['text_id'])) { $query->bodyPart($params['text_id'], $query_opts); $query->bodyPartSize($params['text_id']); } } else { // EAS 2.5 Plaintext body $query->bodyPart($params['text_id'], $query_opts); $query->bodyPartSize($params['text_id']); } try { $fetch_ret = $this->_imap->fetch($this->_mbox, $query, array('ids' => new Horde_Imap_Client_Ids(array($this->_uid)))); } catch (Horde_Imap_Client_Exception $e) { throw new Horde_ActiveSync_Exception($e); } if (!($data = $fetch_ret->first())) { throw new Horde_Exception_NotFound(sprintf('Could not load message %s from server.', $this->_uid)); } return $data; }
/** * Process a message again to add body and attachment data. * * @param \Horde_Imap_Client_Data_Fetch $basemessagedata The structure and part of the message body * @param string|\Horde_Imap_Client_Ids $messageid The Hore message Uid * @return \stdClass The current value of the messagedata */ private function process_message_data_body(\Horde_Imap_Client_Data_Fetch $basemessagedata, $messageid) { global $CFG; // Get the current mailbox. $mailbox = $this->get_mailbox(); // We need the structure at various points below. $structure = $basemessagedata->getStructure(); // Now fetch the rest of the message content. $query = new \Horde_Imap_Client_Fetch_Query(); $query->fullText(); // Fetch all of the message parts too. $typemap = $structure->contentTypeMap(); foreach ($typemap as $part => $type) { // The body of the part - attempt to decode it on the server. $query->bodyPart($part, array('decode' => true, 'peek' => true)); $query->bodyPartSize($part); } $messagedata = $this->client->fetch($mailbox, $query, array('ids' => $messageid))->first(); // Store the data for this message. $contentplain = ''; $contenthtml = ''; $attachments = array('inline' => array(), 'attachment' => array()); $plainpartid = $structure->findBody('plain'); $htmlpartid = $structure->findBody('html'); foreach ($typemap as $part => $type) { // Get the message data from the body part, and combine it with the structure to give a fully-formed output. $stream = $messagedata->getBodyPart($part, true); $partdata = $structure->getPart($part); $partdata->setContents($stream, array('usestream' => true)); if ($part === $plainpartid) { $contentplain = $this->process_message_part_body($messagedata, $partdata, $part); } else { if ($part === $htmlpartid) { $contenthtml = $this->process_message_part_body($messagedata, $partdata, $part); } else { if ($filename = $partdata->getName($part)) { if ($attachment = $this->process_message_part_attachment($messagedata, $partdata, $part, $filename)) { // The disposition should be one of 'attachment', 'inline'. // If an empty string is provided, default to 'attachment'. $disposition = $partdata->getDisposition(); $disposition = $disposition == 'inline' ? 'inline' : 'attachment'; $attachments[$disposition][] = $attachment; } } } } // We don't handle any of the other MIME content at this stage. } // The message ID should always be in the first part. $this->currentmessagedata->plain = $contentplain; $this->currentmessagedata->html = $contenthtml; $this->currentmessagedata->attachments = $attachments; return $this->currentmessagedata; }
/** * @param \Horde_Mime_Part $p * @param int $partNo * @return string * @throws DoesNotExistException * @throws \Exception */ private function loadBodyData($p, $partNo) { // DECODE DATA $fetch_query = new \Horde_Imap_Client_Fetch_Query(); $ids = new \Horde_Imap_Client_Ids($this->messageId); $fetch_query->bodyPart($partNo, ['peek' => true]); $fetch_query->bodyPartSize($partNo); $fetch_query->mimeHeader($partNo, ['peek' => true]); $headers = $this->conn->fetch($this->mailBox, $fetch_query, ['ids' => $ids]); /** @var $fetch \Horde_Imap_Client_Data_Fetch */ $fetch = $headers[$this->messageId]; if (is_null($fetch)) { throw new DoesNotExistException("Mail body for this mail({$this->messageId}) could not be loaded"); } $mimeHeaders = $fetch->getMimeHeader($partNo, Horde_Imap_Client_Data_Fetch::HEADER_PARSE); if ($enc = $mimeHeaders->getValue('content-transfer-encoding')) { $p->setTransferEncoding($enc); } $data = $fetch->getBodyPart($partNo); $p->setContents($data); $data = $p->getContents(); $data = iconv($p->getCharset(), 'utf-8//IGNORE', $data); return $data; }
/** * @depends testOptimizedSearches */ public function testComplexFetch() { // Fetching message information from complex MIME message. $complex_fetch = new Horde_Imap_Client_Fetch_Query(); $complex_fetch->fullText(array('length' => 100, 'peek' => true)); // Header of entire message $complex_fetch->headerText(array('length' => 100, 'peek' => true)); // Header of message/rfc822 part $complex_fetch->headerText(array('id' => 2, 'length' => 100, 'peek' => true)); // Body text of entire message $complex_fetch->bodyText(array('length' => 100, 'peek' => true)); // Body text of message/rfc822 part $complex_fetch->bodyText(array('id' => 2, 'length' => 100, 'peek' => true)); // MIME Header of multipart/alternative part $complex_fetch->mimeHeader('1', array('length' => 100, 'peek' => true)); // MIME Header of text/plain part embedded in message/rfc822 part $complex_fetch->mimeHeader('2.1', array('length' => 100, 'peek' => true)); // Body text of multipart/alternative part $complex_fetch->bodyPart('1', array('length' => 100, 'peek' => true)); // Body text of image/png part embedded in message/rfc822 part // Try to do server-side decoding, if available $complex_fetch->mimeHeader('2.2', array('decode' => true, 'length' => 100, 'peek' => true)); // If supported, return decoded body part size $complex_fetch->bodyPartSize('2.2'); // Select message-id header from base message header $complex_fetch->headers('headersearch1', array('message-id'), array('length' => 100, 'peek' => true)); // Select everything but message-id header from message/rfc822 header $complex_fetch->headers('headersearch2', array('message-id'), array('id' => '2', 'length' => 100, 'notsearch' => true, 'peek' => true)); $complex_fetch->structure(); $complex_fetch->flags(); $complex_fetch->imapDate(); $complex_fetch->size(); $complex_fetch->uid(); if (self::$live->capability->query('CONDSTORE')) { $complex_fetch->modseq(); } try { $res = self::$live->fetch(self::$test_mbox, $complex_fetch, array('ids' => new Horde_Imap_Client_Ids(3, true))); } catch (Horde_Imap_Client_Exception $e) { if ($e->getCode() === $e::MBOXNOMODSEQ) { $this->markTestSkipped('Mailbox does not support MODSEQ.'); } throw $e; } $this->assertInstanceOf('Horde_Imap_Client_Fetch_Results', $res); $this->assertEquals(1, count($res)); $this->assertEquals('Message-ID: <*****@*****.**>', trim($res[3]->getHeaders('headersearch1'))); /* Return stream instead. */ $this->assertInternalType('resource', $res[3]->getHeaders('headersearch1', Horde_Imap_Client_Data_Fetch::HEADER_STREAM)); /* Parse headers instead. */ $this->assertInstanceOf('Horde_Mime_Headers', $res[3]->getHeaders('headersearch1', Horde_Imap_Client_Data_Fetch::HEADER_PARSE)); }
/** * Returns the main text body of the message suitable for sending over * EAS response. * * @param array $options An options array containgin: * - bodyprefs: (array) Bodypref settings * DEFAULT: none (No bodyprefs used). * - mimesupport: (integer) Indicates if MIME is supported or not. * Possible values: 0 - Not supported 1 - Only S/MIME or * 2 - All MIME. * DEFAULT: 0 (No MIME support) * - protocolversion: (float) The EAS protocol we are supporting. * DEFAULT 2.5 * * @return array An array of one or both of 'plain' and 'html' content. * * @throws Horde_ActiveSync_Exception, Horde_Exception_NotFound */ public function getMessageBodyData(array $options = array()) { $version = empty($options['protocolversion']) ? Horde_ActiveSync::VERSION_TWOFIVE : $options['protocolversion']; // Look for the parts we need. We try to detect and fetch only the parts // we need, while ensuring we have something to return. So, e.g., if we // don't have BODYPREF_TYPE_HTML, we only request plain text, but if we // can't find plain text but we have a html body, fetch that anyway. $text_id = $this->_message->findBody('plain'); $html_id = $this->_message->findBody('html'); // Deduce which part(s) we need to request. $want_html_text = $version >= Horde_ActiveSync::VERSION_TWELVE && (!empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]) || !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME])); $want_plain_text = $version == Horde_ActiveSync::VERSION_TWOFIVE || empty($options['bodyprefs']) || !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]) || !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_RTF]) || !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME]) || $want_html_text && empty($html_id); $want_html_as_plain = false; if (!empty($text_id) && $want_plain_text) { $text_body_part = $this->_message->getPart($text_id); $charset = $text_body_part->getCharset(); } elseif ($want_plain_text && !empty($html_id) && empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME])) { $want_html_text = true; $want_html_as_plain = true; } if (!empty($html_id) && $want_html_text) { $html_body_part = $this->_message->getPart($html_id); $html_charset = $html_body_part->getCharset(); } // Sanity check the truncation stuff if (empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]) && !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]) && $want_plain_text && $want_html_text) { // We only have HTML truncation data, requested HTML body but only // have plaintext. $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN] = $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]; } $query = new Horde_Imap_Client_Fetch_Query(); $query_opts = array('decode' => true, 'peek' => true); // Get body information if ($version >= Horde_ActiveSync::VERSION_TWELVE) { if (!empty($html_id)) { $query->bodyPartSize($html_id); $query->bodyPart($html_id, $query_opts); } if (!empty($text_id)) { $query->bodyPart($text_id, $query_opts); $query->bodyPartSize($text_id); } } else { // EAS 2.5 Plaintext body $query->bodyPart($text_id, $query_opts); $query->bodyPartSize($text_id); } try { $fetch_ret = $this->_imap->fetch($this->_mbox, $query, array('ids' => new Horde_Imap_Client_Ids(array($this->_uid)))); } catch (Horde_Imap_Client_Exception $e) { throw new Horde_ActiveSync_Exception($e); } if (!($data = $fetch_ret->first())) { throw new Horde_Exception_NotFound(sprintf('Could not load message %s from server.', $this->_uid)); } $return = array(); if (!empty($text_id) && $want_plain_text) { $text = $data->getBodyPart($text_id); if (!$data->getBodyPartDecode($text_id)) { $text_body_part->setContents($text); $text = $text_body_part->getContents(); } $text_size = !is_null($data->getBodyPartSize($text_id)) ? $data->getBodyPartSize($text_id) : Horde_String::length($text); if (!empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'])) { // EAS >= 12.0 truncation $text = Horde_String::substr($text, 0, $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'], $charset); } $truncated = $text_size > Horde_String::length($text); if ($version >= Horde_ActiveSync::VERSION_TWELVE && $truncated && !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['allornone'])) { $text = ''; } $return['plain'] = array('charset' => $charset, 'body' => $text, 'truncated' => $truncated, 'size' => $text_size); } if (!empty($html_id) && $want_html_text) { $html = $data->getBodyPart($html_id); if (!$data->getBodyPartDecode($html_id)) { $html_body_part->setContents($html); $html = $html_body_part->getContents(); } // Size of the original HTML part. $html_size = !is_null($data->getBodyPartSize($html_id)) ? $data->getBodyPartSize($html_id) : Horde_String::length($html); if (!empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize'])) { $html = Horde_String::substr($html, 0, $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]['truncationsize'], $html_charset); } elseif ($want_html_as_plain) { $html = Horde_Text_Filter::filter($html, 'Html2text', array('charset' => $html_charset)); // Get the new size, since it probably changed. $html_size = Horde_String::length($html); if (!empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'])) { // EAS >= 12.0 truncation $html = Horde_String::substr($html, 0, $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN]['truncationsize'], $html_charset); } } // Was the part truncated? $truncated = $html_size > Horde_String::length($html); if ($want_html_as_plain) { $return['plain'] = array('charset' => $html_charset, 'body' => $html, 'truncated' => $truncated, 'size' => $html_size); } if ($version >= Horde_ActiveSync::VERSION_TWELVE && !($truncated && !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]['allornone']))) { $return['html'] = array('charset' => $html_charset, 'body' => $html, 'estimated_size' => $html_size, 'truncated' => $truncated); } } return $return; }