/** * 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); }