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