Example #1
0
 /**
  * Format flowed text for HTML output.
  *
  * @param string $text    The text to format.
  * @param boolean $delsp  Was text created with DelSp formatting?
  *
  * @return string  The formatted text.
  */
 protected function _formatFlowed($text, $delsp = null)
 {
     $flowed = new Horde_Text_Flowed($text, $this->_mimepart->getCharset());
     $flowed->setMaxLength(0);
     if (!is_null($delsp)) {
         $flowed->setDelSp($delsp);
     }
     return $flowed->toFixed();
 }
Example #2
0
    public function testFlowedWrap()
    {
        $text = <<<EOT
>this is a long line this is a long line this is a long line this is a long line this is a long line this is a long line
this is a long line this is a long line this is a long line this is a long line this is a long line this is a long line
EOT;
        $expected = <<<EOT
> this is a long line this is a long line this is a long line this is a 
> long line this is a long line this is a long line
this is a long line this is a long line this is a long line this is a long line this is a long line this is a long line

EOT;
        $flowed = new Horde_Text_Flowed($text);
        $flowed->setMaxLength(70);
        $this->assertEquals($expected, $flowed->toFlowed(false, array('nowrap' => true)));
    }
Example #3
0
    public function testBug10431()
    {
        $text = 'Das könnte zum Beispiel so aussehen, dass wir bei entsprechenden Anfragen diese an eine Kontaktperson bei Euch weiterleiten. Oder Ihr schnürt ein entsprechendes Paket, dass wir in unseren Angeboten mit anführen. Bei erfolgreicher Vermittlung bekämen wir eine Vermittlungsgebühr.
Wir ständen dann weiterhin für 3rd-Level-Support zur Verfügung, d.h. für alle Anfragen des Kunden bzgl. Horde, die nicht zum Tagesgeschäft gehören.';
        $text = Horde_String::convertCharset($text, 'UTF-8', 'ISO-8859-1');
        $textBody = new Horde_Mime_Part();
        $textBody->setType('text/plain');
        $textBody->setCharset('ISO-8859-1');
        $flowed = new Horde_Text_Flowed($text, 'ISO-8859-1');
        $flowed->setDelSp(true);
        $textBody->setContents($flowed->toFlowed());
        $flowed_txt = $textBody->toString(array('headers' => false));
        $textBody2 = new Horde_Mime_Part();
        $textBody2->setType('text/plain');
        $textBody2->setCharset('ISO-8859-1');
        $textBody2->setContents($flowed_txt, array('encoding' => 'quoted-printable'));
        $flowed2 = new Horde_Text_Flowed($textBody2->getContents(), 'ISO-8859-1');
        $flowed2->setMaxLength(0);
        $flowed2->setDelSp(true);
        $this->assertEquals($text, trim($flowed2->toFixed()));
    }
Example #4
0
 /**
  * Process DOM node.
  *
  * @param DOMDocument $doc  Document node.
  * @param DOMElement $node  Element node.
  *
  * @return string  The plaintext representation.
  */
 protected function _node($doc, $node)
 {
     $out = '';
     if (!empty($this->_params['nestingLimit']) && $this->_nestingLevel > $this->_params['nestingLimit']) {
         $this->_nestingLevel--;
         return;
     }
     $this->_nestingLevel++;
     if ($node->hasChildNodes()) {
         foreach ($node->childNodes as $child) {
             if ($this->_params['callback'] && ($txt = call_user_func($this->_params['callback'], $doc, $child)) !== null) {
                 $out .= $txt;
                 continue;
             }
             if ($child instanceof DOMElement) {
                 switch (Horde_String::lower($child->tagName)) {
                     case 'h1':
                     case 'h2':
                     case 'h3':
                         $out .= "\n\n" . strtoupper($this->_node($doc, $child)) . "\n\n";
                         break;
                     case 'h4':
                     case 'h5':
                     case 'h6':
                         $out .= "\n\n" . ucwords($this->_node($doc, $child)) . "\n\n";
                         break;
                     case 'b':
                     case 'strong':
                         $out .= strtoupper($this->_node($doc, $child));
                         break;
                     case 'u':
                         $out .= '_' . $this->_node($doc, $child) . '_';
                         break;
                     case 'em':
                     case 'i':
                         $out .= '/' . $this->_node($doc, $child) . '/';
                         break;
                     case 'hr':
                         $out .= "\n-------------------------\n";
                         break;
                     case 'ol':
                     case 'ul':
                     case 'dl':
                         ++$this->_indent;
                         $out .= "\n" . $this->_node($doc, $child) . "\n";
                         --$this->_indent;
                         break;
                     case 'p':
                         if ($tmp = $this->_node($doc, $child)) {
                             if (!strspn(substr($out, -2), "\n")) {
                                 $out .= "\n";
                             }
                             if (strlen(trim($tmp))) {
                                 $out .= $tmp . "\n";
                             }
                         }
                         break;
                     case 'table':
                         if ($tmp = $this->_node($doc, $child)) {
                             $out .= "\n\n" . $tmp . "\n\n";
                         }
                         break;
                     case 'tr':
                         $out .= "\n  " . trim($this->_node($doc, $child));
                         break;
                     case 'th':
                         $out .= strtoupper($this->_node($doc, $child)) . " \t";
                         break;
                     case 'td':
                         $out .= $this->_node($doc, $child) . " \t";
                         break;
                     case 'li':
                     case 'dd':
                     case 'dt':
                         $out .= "\n" . str_repeat('  ', $this->_indent) . '* ' . $this->_node($doc, $child);
                         break;
                     case 'a':
                         $out .= $this->_node($doc, $child) . $this->_buildLinkList($doc, $child);
                         break;
                     case 'blockquote':
                         $tmp = trim(preg_replace('/\\s*\\n{3,}/', "\n\n", $this->_node($doc, $child)));
                         if (class_exists('Horde_Text_Flowed')) {
                             $flowed = new Horde_Text_Flowed($tmp, $this->_params['charset']);
                             $flowed->setMaxLength($this->_params['width']);
                             $flowed->setOptLength($this->_params['width']);
                             $tmp = $flowed->toFlowed(true);
                         }
                         if (!strspn(substr($out, -1), " \r\n\t")) {
                             $out .= "\n";
                         }
                         $out .= "\n" . rtrim($tmp) . "\n\n";
                         break;
                     case 'div':
                         $out .= $this->_node($doc, $child) . "\n";
                         break;
                     case 'br':
                         $out .= "\n";
                         break;
                     default:
                         $out .= $this->_node($doc, $child);
                         break;
                 }
             } elseif ($child instanceof DOMText) {
                 $tmp = $child->textContent;
                 $out .= strspn(substr($out, -1), " \r\n\t") ? ltrim($child->textContent) : $child->textContent;
             }
         }
     }
     if (!empty($this->_params['nestingLimit'])) {
         $this->_nestingLevel--;
     }
     return $out;
 }
Example #5
0
 /**
  * Return the body text of the original email from a smart request.
  *
  * @param array $body_data       The body data array of the source msg.
  * @param Horde_Mime_Part $part  The body mime part of the email to send.
  * @param boolean $html          Do we want an html body?
  * @param boolean $flow          Should the body be flowed?
  *
  * @return string  The properly formatted/flowed message body.
  */
 protected function _msgBody(array $body_data, Horde_Mime_Part $part, $html, $flow = false)
 {
     $subtype = $html == true ? 'html' : 'plain';
     $msg = Horde_String::convertCharset($body_data[$subtype]['body'], $body_data[$subtype]['charset'], 'UTF-8');
     trim($msg);
     if (!$html) {
         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 not flowed, remove padding at eol
             $msg = preg_replace("/\\s*\n/U", "\n", $msg);
         }
         if ($flow) {
             $flowed = new Horde_Text_Flowed($msg, 'UTF-8');
             $msg = $flowed->toFlowed(true);
         }
     }
     return $msg;
 }
Example #6
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);
 }
Example #7
0
File: Mail.php Project: horde/horde
 /**
  * Return the body text of the original email from a smart request.
  *
  * @param array $body_data       The body data array of the source msg.
  * @param Horde_Mime_Part $part  The body mime part of the email to send.
  * @param boolean $html          Do we want an html body?
  * @param boolean $flow          Should the body be flowed?
  *
  * @return string  The properly formatted/flowed message body.
  */
 protected function _msgBody(array $body_data, Horde_Mime_Part $part, $html, $flow = false)
 {
     $subtype = $html == true ? 'html' : 'plain';
     $msg = Horde_String::convertCharset((string) $body_data[$subtype]['body'], $body_data[$subtype]['charset'], 'UTF-8');
     if (!$html) {
         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 not flowed, remove padding at eol
             $msg = preg_replace("/\\s*\n/U", "\n", $msg);
         }
         if ($flow) {
             $flowed = new Horde_Text_Flowed($msg, 'UTF-8');
             $msg = $flowed->toFlowed(true);
         }
     } else {
         // This filter requires the tidy extenstion.
         if (Horde_Util::extensionExists('tidy')) {
             return Horde_Text_Filter::filter($msg, 'Cleanhtml', array('body_only' => true));
         } else {
             // If no tidy, use Horde_Dom.
             $dom = new Horde_Domhtml($msg, 'UTF-8');
             return $dom->returnBody();
         }
     }
     return $msg;
 }