Пример #1
0
 /**
  * Executes any code necessary after applying the filter patterns.
  *
  * @param string $text  The text after the filtering.
  *
  * @return string|Horde_Domhtml  The modified text or a Domhtml object if
  *                               the 'return_dom' parameter is set.
  * @throws Exception
  */
 public function postProcess($text)
 {
     $dom = new Horde_Domhtml($text, $this->_params['charset']);
     foreach ($dom as $node) {
         $this->_node($node);
     }
     if ($this->_params['noprefetch']) {
         $meta = $dom->dom->createElement('meta');
         $meta->setAttribute('http-equiv', 'x-dns-prefetch-control');
         $meta->setAttribute('value-equiv', 'off');
         $head = $dom->getHead();
         $head->appendChild($meta);
     }
     if ($this->_params['return_dom']) {
         return $dom;
     }
     return $this->_params['return_document'] ? $dom->returnHtml() : $dom->returnBody();
 }
Пример #2
0
 /**
  * Executes any code necessary after applying the filter patterns.
  *
  * @param string $text  The text after the filtering.
  *
  * @return string  The modified text.
  */
 public function postProcess($text)
 {
     // We cannot find those elements via DOM because HTML doesn't know
     // about namespaces.
     $text = str_replace('<o:p>&nbsp;</o:p>', '', $text);
     try {
         $dom = new Horde_Domhtml($text, $this->_params['charset']);
     } catch (Exception $e) {
         return $text;
     }
     // Replace all <p> elements of class "MsoNormal" with <br> elements,
     // unless they contain other classes. Then replace with <div> elements.
     foreach ($dom as $child) {
         if ($child instanceof DOMElement && Horde_String::lower($child->tagName) == 'p') {
         }
         if (!$child instanceof DOMElement || Horde_String::lower($child->tagName) != 'p' || !($css = $child->getAttribute('class')) || strpos($css, 'MsoNormal') === false) {
             continue;
         }
         $css = trim(str_replace('MsoNormal', '', $css));
         if (strlen($css)) {
             $div = $dom->dom->createElement('div');
             $div->setAttribute('class', $css);
             foreach ($child->childNodes as $subchild) {
                 $div->appendChild($subchild);
             }
             $child->parentNode->insertBefore($div, $child);
         } elseif (strlen(preg_replace('/^\\s*(.*)\\s*$/u', '$1', $child->textContent))) {
             while ($child->hasChildNodes()) {
                 $tomove = $child->removeChild($child->firstChild);
                 $child->parentNode->insertBefore($tomove, $child);
             }
             $child->parentNode->insertBefore($dom->dom->createElement('br'), $child);
         }
         $child->parentNode->removeChild($child);
     }
     return $dom->returnHtml(array('charset' => $this->_params['charset']));
 }
Пример #3
0
 public function testReturnHtmlMetaCharset()
 {
     $dom = new Horde_Domhtml('<html><body><div>foo</div></body></html>', 'UTF-8');
     $this->assertRegExp('/"text\\/html; charset=utf-8"/', $dom->returnHtml(array('metacharset' => true)));
 }
Пример #4
0
 /**
  */
 protected function _addIdentityJs()
 {
     global $injector, $page_output;
     $identities = array();
     $identity = $injector->getInstance('IMP_Identity');
     $sigs = $identity->hasSignature(true);
     foreach (array_keys(iterator_to_array($identity)) as $ident) {
         $sm = $identity->getValue(IMP_Mailbox::MBOX_SENT, $ident);
         $entry = array('sm_name' => $sm ? $sm->form_to : '', 'sm_save' => (bool) $identity->saveSentmail($ident), 'sm_title' => $sm ? $sm->display_notranslate : '', 'sm_display' => $sm ? $sm->display_html : '', 'bcc' => strval($identity->getBccAddresses($ident)));
         if ($sigs) {
             $sig = $identity->getSignature('text', $ident);
             $html_sig = $identity->getSignature('html', $ident);
             if (!strlen($html_sig) && strlen($sig)) {
                 $html_sig = IMP_Compose::text2html($sig);
             }
             $sig_dom = new Horde_Domhtml($html_sig, 'UTF-8');
             $html_sig = '';
             foreach ($sig_dom->getBody()->childNodes as $child) {
                 $html_sig .= $sig_dom->dom->saveXml($child);
             }
             $entry['sig'] = trim($sig);
             $entry['hsig'] = $html_sig;
         }
         $identities[] = $entry;
     }
     $page_output->addInlineJsVars(array('ImpCompose.identities' => $identities));
 }
Пример #5
0
 /**
  * Create the base Horde_Mime_Part for sending.
  *
  * @param string $body                Message body.
  * @param array $options              Additional options:
  *   - html: (boolean) Is this a HTML message?
  *   - identity: (IMP_Prefs_Identity) Identity of the sender.
  *   - nofinal: (boolean) This is not a message which will be sent out.
  *   - noattach: (boolean) Don't add attachment information.
  *   - pgp_attach_pubkey: (boolean) Attach the user's PGP public key?
  *   - recip: (Horde_Mail_Rfc822_List) The recipient list.
  *   - signature: (IMP_Prefs_Identity|string) If set, add the signature to
  *                the message.
  *   - vcard_attach: (string) If set, attach user's vcard to message.
  *
  * @return Horde_Mime_Part  The base MIME part.
  *
  * @throws Horde_Exception
  * @throws IMP_Compose_Exception
  */
 protected function _createMimeMessage($body, array $options = array())
 {
     global $injector, $prefs, $registry;
     /* Get body text. */
     if (empty($options['html'])) {
         $body_html = null;
     } else {
         $tfilter = $injector->getInstance('Horde_Core_Factory_TextFilter');
         $body_html = $tfilter->filter($body, 'Xss', array('return_dom' => true, 'strip_style_attributes' => false));
         $body_html_body = $body_html->getBody();
         $body = $tfilter->filter($body_html->returnHtml(), 'Html2text', array('wrap' => false));
     }
     $hooks = $injector->getInstance('Horde_Core_Hooks');
     /* We need to do the attachment check before any of the body text
      * has been altered. */
     if (!count($this) && !$this->getMetadata('attach_body_check')) {
         $this->_setMetadata('attach_body_check', true);
         try {
             $check = $hooks->callHook('attach_body_check', 'imp', array($body));
         } catch (Horde_Exception_HookNotSet $e) {
             $check = array();
         }
         if (!empty($check) && preg_match('/\\b(' . implode('|', array_map('preg_quote', $check, array_fill(0, count($check), '/'))) . ')\\b/i', $body, $matches)) {
             throw IMP_Compose_Exception::createAndLog('DEBUG', sprintf(_("Found the word %s in the message text although there are no files attached to the message. Did you forget to attach a file? (This check will not be performed again for this message.)"), $matches[0]));
         }
     }
     /* Add signature data. */
     if (!empty($options['signature'])) {
         if (is_string($options['signature'])) {
             if (empty($options['html'])) {
                 $body .= "\n\n" . trim($options['signature']);
             } else {
                 $html_sig = trim($options['signature']);
                 $body .= "\n" . $tfilter->filter($html_sig, 'Html2text');
             }
         } else {
             $sig = $options['signature']->getSignature('text');
             $body .= $sig;
             if (!empty($options['html'])) {
                 $html_sig = $options['signature']->getSignature('html');
                 if (!strlen($html_sig) && strlen($sig)) {
                     $html_sig = $this->text2html($sig);
                 }
             }
         }
         if (!empty($options['html'])) {
             try {
                 $sig_ob = new IMP_Compose_HtmlSignature($html_sig);
             } catch (IMP_Exception $e) {
                 throw new IMP_Compose_Exception($e);
             }
             foreach ($sig_ob->dom->getBody()->childNodes as $child) {
                 $body_html_body->appendChild($body_html->dom->importNode($child, true));
             }
         }
     }
     /* Add linked attachments. */
     if (empty($options['nofinal'])) {
         $this->_linkAttachments($body, $body_html);
     }
     /* Get trailer text (if any). */
     if (empty($options['nofinal']) && !empty($options['recip'])) {
         try {
             $trailer = $hooks->callHook('trailer', 'imp', array(false, $options['identity'], $options['recip']));
             $html_trailer = $hooks->callHook('trailer', 'imp', array(true, $options['identity'], $options['recip']));
         } catch (Horde_Exception_HookNotSet $e) {
             $trailer = $html_trailer = null;
         }
         $body .= strval($trailer);
         if (!empty($options['html'])) {
             if (is_null($html_trailer) && strlen($trailer)) {
                 $html_trailer = $this->text2html($trailer);
             }
             if (strlen($html_trailer)) {
                 $t_dom = new Horde_Domhtml($html_trailer, 'UTF-8');
                 foreach ($t_dom->getBody()->childNodes as $child) {
                     $body_html_body->appendChild($body_html->dom->importNode($child, true));
                 }
             }
         }
     }
     /* Convert text to sending charset. HTML text will be converted
      * via Horde_Domhtml. */
     $body = Horde_String::convertCharset($body, 'UTF-8', $this->charset);
     /* Set up the body part now. */
     $textBody = new Horde_Mime_Part();
     $textBody->setType('text/plain');
     $textBody->setCharset($this->charset);
     $textBody->setDisposition('inline');
     /* Send in flowed format. */
     $flowed = new Horde_Text_Flowed($body, $this->charset);
     $flowed->setDelSp(true);
     $textBody->setContentTypeParameter('format', 'flowed');
     $textBody->setContentTypeParameter('DelSp', 'Yes');
     $text_contents = $flowed->toFlowed();
     $textBody->setContents($text_contents);
     /* Determine whether or not to send a multipart/alternative
      * message with an HTML part. */
     if (!empty($options['html'])) {
         $htmlBody = new Horde_Mime_Part();
         $htmlBody->setType('text/html');
         $htmlBody->setCharset($this->charset);
         $htmlBody->setDisposition('inline');
         $htmlBody->setDescription(Horde_String::convertCharset(_("HTML Message"), 'UTF-8', $this->charset));
         /* Add default font CSS information here. */
         $styles = array();
         if ($font_family = $prefs->getValue('compose_html_font_family')) {
             $styles[] = 'font-family:' . $font_family;
         }
         if ($font_size = intval($prefs->getValue('compose_html_font_size'))) {
             $styles[] = 'font-size:' . $font_size . 'px';
         }
         if (!empty($styles)) {
             $body_html_body->setAttribute('style', implode(';', $styles));
         }
         if (empty($options['nofinal'])) {
             $this->_cleanHtmlOutput($body_html);
         }
         $to_add = $this->_convertToRelated($body_html, $htmlBody);
         /* Now, all parts referred to in the HTML data have been added
          * to the attachment list. Convert to multipart/related if
          * this is the case. Exception: if text representation is empty,
          * just send HTML part. */
         if (strlen(trim($text_contents))) {
             $textpart = new Horde_Mime_Part();
             $textpart->setType('multipart/alternative');
             $textpart[] = $textBody;
             $textpart[] = $to_add;
             $textpart->setHeaderCharset($this->charset);
             $textBody->setDescription(Horde_String::convertCharset(_("Plaintext Message"), 'UTF-8', $this->charset));
         } else {
             $textpart = $to_add;
         }
         $htmlBody->setContents($tfilter->filter($body_html->returnHtml(array('charset' => $this->charset, 'metacharset' => true)), 'Cleanhtml', array('charset' => $this->charset)));
         $base = $textpart;
     } else {
         $base = $textpart = strlen(trim($text_contents)) ? $textBody : null;
     }
     /* Add attachments. */
     if (empty($options['noattach'])) {
         $parts = array();
         foreach ($this as $val) {
             if (!$val->related && !$val->linked) {
                 $parts[] = $val->getPart(true);
             }
         }
         if (!empty($options['pgp_attach_pubkey'])) {
             $parts[] = $injector->getInstance('IMP_Crypt_Pgp')->publicKeyMIMEPart();
         }
         if (!empty($options['vcard_attach'])) {
             try {
                 $vpart = new Horde_Mime_Part();
                 $vpart->setType('text/x-vcard');
                 $vpart->setCharset('UTF-8');
                 $vpart->setContents($registry->call('contacts/ownVCard'));
                 $vpart->setName($options['vcard_attach']);
                 $parts[] = $vpart;
             } catch (Horde_Exception $e) {
                 throw new IMP_Compose_Exception(sprintf(_("Can't attach contact information: %s"), $e->getMessage()));
             }
         }
         if (!empty($parts)) {
             if (is_null($base) && count($parts) === 1) {
                 /* If this is a single attachment with no text, the
                  * attachment IS the message. */
                 $base = reset($parts);
             } else {
                 $base = new Horde_Mime_Part();
                 $base->setType('multipart/mixed');
                 if (!is_null($textpart)) {
                     $base[] = $textpart;
                 }
                 foreach ($parts as $val) {
                     $base[] = $val;
                 }
             }
         }
     }
     /* If we reach this far with no base, we are sending a blank message.
      * Assume this is what the user wants. */
     if (is_null($base)) {
         $base = $textBody;
     }
     /* Flag this as the base part and rebuild MIME IDs. */
     $base->isBasePart(true);
     $base->buildMimeIds();
     return $base;
 }
Пример #6
0
 /**
  */
 public function printAttach($id)
 {
     global $injector, $page_output, $prefs, $registry;
     if (is_null($id) || !($render = $this->_contents->renderMIMEPart($id, IMP_Contents::RENDER_FULL))) {
         return array();
     }
     $part = reset($render);
     /* Directly render part if this is not an HTML part or it is empty. */
     if (stripos($part['type'], 'text/html') !== 0 || !strlen($part['data'])) {
         return $part;
     }
     $imp_ui_mbox = new IMP_Mailbox_Ui();
     $basic_headers = $injector->getInstance('IMP_Message_Ui')->basicHeaders();
     unset($basic_headers['bcc'], $basic_headers['reply-to']);
     $headerob = $this->_contents->getHeader();
     $d_param = Horde_Mime::decodeParam('content-type', $part['type']);
     $headers = array();
     foreach ($basic_headers as $key => $val) {
         if ($hdr_val = $headerob->getValue($key)) {
             /* Format date string. */
             if ($key == 'date') {
                 $date_ob = new IMP_Message_Date($hdr_val);
                 $hdr_val = $date_ob->format($date_ob::DATE_FORCE);
             }
             $headers[] = array('header' => $val, 'value' => $hdr_val);
         }
     }
     if ($prefs->getValue('add_printedby')) {
         $user_identity = $injector->getInstance('IMP_Identity');
         $headers[] = array('header' => _("Printed By"), 'value' => $user_identity->getFullname() ?: $registry->getAuth());
     }
     $view = new Horde_View(array('templatePath' => IMP_TEMPLATES . '/print'));
     $view->addHelper('Text');
     $view->headers = $headers;
     $header_dom = new Horde_Domhtml(Horde_String::convertCharset($view->render('headers'), 'UTF-8', $d_param['params']['charset']), $d_param['params']['charset']);
     $elt = $header_dom->dom->getElementById('headerblock');
     $elt->removeAttribute('id');
     if ($elt->hasAttribute('class')) {
         $selectors = array('body');
         foreach (explode(' ', $elt->getAttribute('class')) as $val) {
             if (strlen($val = trim($val))) {
                 $selectors[] = '.' . $val;
             }
         }
         /* Cache CSS. */
         $cache_list = array();
         $cache_ob = $injector->getInstance('Horde_Cache');
         $css_list = $page_output->css->getStylesheets();
         foreach ($css_list as $val) {
             $cache_list[] = $val['fs'];
             $cache_list[] = filemtime($val['fs']);
         }
         $cache_id = 'imp_printcss_' . hash(PHP_MINOR_VERSION >= 4 ? 'fnv132' : 'sha1', implode('|', $cache_list));
         if (($style = $cache_ob->get($cache_id, 0)) === false) {
             try {
                 $css_parser = new Horde_Css_Parser($page_output->css->loadCssFiles($page_output->css->getStylesheets()));
                 $style = '';
                 foreach ($css_parser->doc->getContents() as $val) {
                     if ($val instanceof Sabberworm\CSS\RuleSet\DeclarationBlock && array_intersect($selectors, array_map('strval', $val->getSelectors()))) {
                         $style .= implode('', array_map('strval', $val->getRules()));
                     }
                 }
                 $cache_ob->set($cache_id, $style, 86400);
             } catch (Exception $e) {
                 // Ignore CSS if it can't be parsed.
             }
         }
         if (strlen($style)) {
             $elt->setAttribute('style', ($elt->hasAttribute('style') ? rtrim($elt->getAttribute('style'), ' ;') . ';' : '') . $style);
         }
     }
     $elt->removeAttribute('class');
     /* Need to wrap headers in another DIV. */
     $newdiv = new DOMDocument();
     $div = $newdiv->createElement('div');
     $div->appendChild($newdiv->importNode($elt, true));
     $pstring = Horde_Mime::decodeParam('content-type', $part['type']);
     $doc = new Horde_Domhtml($part['data'], $pstring['params']['charset']);
     $bodyelt = $doc->dom->getElementsByTagName('body')->item(0);
     $bodyelt->insertBefore($doc->dom->importNode($div, true), $bodyelt->firstChild);
     /* Make the title the e-mail subject. */
     $headelt = $doc->getHead();
     foreach ($headelt->getElementsByTagName('title') as $node) {
         $headelt->removeChild($node);
     }
     $headelt->appendChild($doc->dom->createElement('title', htmlspecialchars($imp_ui_mbox->getSubject($headerob->getValue('subject')))));
     return array('data' => $doc->returnHtml(), 'name' => $part['name'], 'type' => $part['type']);
 }
Пример #7
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((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;
 }
Пример #8
0
 /**
  * Create the base Horde_Mime_Part for sending.
  *
  * @param Horde_Mail_Rfc822_List $to  The recipient list.
  * @param string $body                Message body.
  * @param array $options              Additional options:
  *   - encrypt: (integer) The encryption flag.
  *   - from: (Horde_Mail_Rfc822_Address) The outgoing from address (only
  *           needed for multiple PGP encryption).
  *   - html: (boolean) Is this a HTML message?
  *   - identity: (IMP_Prefs_Identity) Identity of the sender.
  *   - nofinal: (boolean) This is not a message which will be sent out.
  *   - noattach: (boolean) Don't add attachment information.
  *   - pgp_attach_pubkey: (boolean) Attach the user's PGP public key?
  *   - signature: (IMP_Prefs_Identity|string) If set, add the signature to
  *                the message.
  *   - vcard_attach: (string) If set, attach user's vcard to message.
  *
  * @return Horde_Mime_Part  The MIME message to send.
  *
  * @throws Horde_Exception
  * @throws IMP_Compose_Exception
  */
 protected function _createMimeMessage(Horde_Mail_Rfc822_List $to, $body, array $options = array())
 {
     global $conf, $injector, $prefs, $registry;
     /* Get body text. */
     if (empty($options['html'])) {
         $body_html = null;
     } else {
         $tfilter = $injector->getInstance('Horde_Core_Factory_TextFilter');
         $body_html = $tfilter->filter($body, 'Xss', array('return_dom' => true, 'strip_style_attributes' => false));
         $body_html_body = $body_html->getBody();
         $body = $tfilter->filter($body_html->returnHtml(), 'Html2text', array('wrap' => false));
     }
     $hooks = $injector->getInstance('Horde_Core_Hooks');
     /* We need to do the attachment check before any of the body text
      * has been altered. */
     if (!count($this) && !$this->getMetadata('attach_body_check')) {
         $this->_setMetadata('attach_body_check', true);
         try {
             $check = $hooks->callHook('attach_body_check', 'imp', array($body));
         } catch (Horde_Exception_HookNotSet $e) {
             $check = array();
         }
         if (!empty($check) && preg_match('/\\b(' . implode('|', array_map('preg_quote', $check)) . ')\\b/i', $body, $matches)) {
             throw IMP_Compose_Exception::createAndLog('DEBUG', sprintf(_("Found the word %s in the message text although there are no files attached to the message. Did you forget to attach a file? (This check will not be performed again for this message.)"), $matches[0]));
         }
     }
     /* Add signature data. */
     if (!empty($options['signature'])) {
         if (is_string($options['signature'])) {
             if (empty($options['html'])) {
                 $body .= "\n\n" . trim($options['signature']);
             } else {
                 $html_sig = trim($options['signature']);
                 $body .= "\n" . $tfilter->filter($html_sig, 'Html2text');
             }
         } else {
             $sig = $options['signature']->getSignature('text');
             $body .= $sig;
             if (!empty($options['html'])) {
                 $html_sig = $options['signature']->getSignature('html');
                 if (!strlen($html_sig) && strlen($sig)) {
                     $html_sig = $this->text2html($sig);
                 }
             }
         }
         if (!empty($options['html'])) {
             try {
                 $sig_ob = new IMP_Compose_HtmlSignature($html_sig);
             } catch (IMP_Exception $e) {
                 throw new IMP_Compose_Exception($e);
             }
             foreach ($sig_ob->dom->getBody()->childNodes as $child) {
                 $body_html_body->appendChild($body_html->dom->importNode($child, true));
             }
         }
     }
     /* Add linked attachments. */
     if (empty($options['nofinal'])) {
         $this->_linkAttachments($body, $body_html);
     }
     /* Get trailer text (if any). */
     if (empty($options['nofinal'])) {
         try {
             $trailer = $hooks->callHook('trailer', 'imp', array(false, $options['identity'], $to));
             $html_trailer = $hooks->callHook('trailer', 'imp', array(true, $options['identity'], $to));
         } catch (Horde_Exception_HookNotSet $e) {
             $trailer = $html_trailer = null;
         }
         $body .= strval($trailer);
         if (!empty($options['html'])) {
             if (is_null($html_trailer) && strlen($trailer)) {
                 $html_trailer = $this->text2html($trailer);
             }
             if (strlen($html_trailer)) {
                 $t_dom = new Horde_Domhtml($html_trailer, 'UTF-8');
                 foreach ($t_dom->getBody()->childNodes as $child) {
                     $body_html_body->appendChild($body_html->dom->importNode($child, true));
                 }
             }
         }
     }
     /* Convert text to sending charset. HTML text will be converted
      * via Horde_Domhtml. */
     $body = Horde_String::convertCharset($body, 'UTF-8', $this->charset);
     /* Set up the body part now. */
     $textBody = new Horde_Mime_Part();
     $textBody->setType('text/plain');
     $textBody->setCharset($this->charset);
     $textBody->setDisposition('inline');
     /* Send in flowed format. */
     $flowed = new Horde_Text_Flowed($body, $this->charset);
     $flowed->setDelSp(true);
     $textBody->setContentTypeParameter('format', 'flowed');
     $textBody->setContentTypeParameter('DelSp', 'Yes');
     $text_contents = $flowed->toFlowed();
     $textBody->setContents($text_contents);
     /* Determine whether or not to send a multipart/alternative
      * message with an HTML part. */
     if (!empty($options['html'])) {
         $htmlBody = new Horde_Mime_Part();
         $htmlBody->setType('text/html');
         $htmlBody->setCharset($this->charset);
         $htmlBody->setDisposition('inline');
         $htmlBody->setDescription(Horde_String::convertCharset(_("HTML Message"), 'UTF-8', $this->charset));
         /* Add default font CSS information here. */
         $styles = array();
         if ($font_family = $prefs->getValue('compose_html_font_family')) {
             $styles[] = 'font-family:' . $font_family;
         }
         if ($font_size = intval($prefs->getValue('compose_html_font_size'))) {
             $styles[] = 'font-size:' . $font_size . 'px';
         }
         if (!empty($styles)) {
             $body_html_body->setAttribute('style', implode(';', $styles));
         }
         if (empty($options['nofinal'])) {
             $this->_cleanHtmlOutput($body_html);
         }
         $to_add = $this->_convertToRelated($body_html, $htmlBody);
         /* Now, all parts referred to in the HTML data have been added
          * to the attachment list. Convert to multipart/related if
          * this is the case. Exception: if text representation is empty,
          * just send HTML part. */
         if (strlen(trim($text_contents))) {
             $textpart = new Horde_Mime_Part();
             $textpart->setType('multipart/alternative');
             $textpart->addPart($textBody);
             $textpart->addPart($to_add);
             $textpart->setHeaderCharset($this->charset);
             $textBody->setDescription(Horde_String::convertCharset(_("Plaintext Message"), 'UTF-8', $this->charset));
         } else {
             $textpart = $to_add;
         }
         $htmlBody->setContents($tfilter->filter($body_html->returnHtml(array('charset' => $this->charset, 'metacharset' => true)), 'Cleanhtml', array('charset' => $this->charset)));
     } else {
         $textpart = $textBody;
     }
     /* Add attachments. */
     $base = $textpart;
     if (empty($options['noattach'])) {
         $parts = array();
         foreach ($this as $val) {
             if (!$val->related && !$val->linked) {
                 $parts[] = $val->getPart(true);
             }
         }
         if (!empty($options['pgp_attach_pubkey'])) {
             $parts[] = $injector->getInstance('IMP_Crypt_Pgp')->publicKeyMIMEPart();
         }
         if (!empty($options['vcard_attach'])) {
             try {
                 $vpart = new Horde_Mime_Part();
                 $vpart->setType('text/x-vcard');
                 $vpart->setCharset('UTF-8');
                 $vpart->setContents($registry->call('contacts/ownVCard'));
                 $vpart->setName($options['vcard_attach']);
                 $parts[] = $vpart;
             } catch (Horde_Exception $e) {
                 throw new IMP_Compose_Exception(sprintf(_("Can't attach contact information: %s"), $e->getMessage()));
             }
         }
         if (!empty($parts)) {
             $base = new Horde_Mime_Part();
             $base->setType('multipart/mixed');
             $base->addPart($textpart);
             foreach ($parts as $val) {
                 $base->addPart($val);
             }
         }
     }
     /* Set up the base message now. */
     $encrypt = empty($options['encrypt']) ? IMP::ENCRYPT_NONE : $options['encrypt'];
     if ($prefs->getValue('use_pgp') && !empty($conf['gnupg']['path']) && in_array($encrypt, array(IMP_Crypt_Pgp::ENCRYPT, IMP_Crypt_Pgp::SIGN, IMP_Crypt_Pgp::SIGNENC, IMP_Crypt_Pgp::SYM_ENCRYPT, IMP_Crypt_Pgp::SYM_SIGNENC))) {
         $imp_pgp = $injector->getInstance('IMP_Crypt_Pgp');
         $symmetric_passphrase = null;
         switch ($encrypt) {
             case IMP_Crypt_Pgp::SIGN:
             case IMP_Crypt_Pgp::SIGNENC:
             case IMP_Crypt_Pgp::SYM_SIGNENC:
                 /* Check to see if we have the user's passphrase yet. */
                 $passphrase = $imp_pgp->getPassphrase('personal');
                 if (empty($passphrase)) {
                     $e = new IMP_Compose_Exception(_("PGP: Need passphrase for personal private key."));
                     $e->encrypt = 'pgp_passphrase_dialog';
                     throw $e;
                 }
                 break;
             case IMP_Crypt_Pgp::SYM_ENCRYPT:
             case IMP_Crypt_Pgp::SYM_SIGNENC:
                 /* Check to see if we have the user's symmetric passphrase
                  * yet. */
                 $symmetric_passphrase = $imp_pgp->getPassphrase('symmetric', 'imp_compose_' . $this->_cacheid);
                 if (empty($symmetric_passphrase)) {
                     $e = new IMP_Compose_Exception(_("PGP: Need passphrase to encrypt your message with."));
                     $e->encrypt = 'pgp_symmetric_passphrase_dialog';
                     throw $e;
                 }
                 break;
         }
         /* Do the encryption/signing requested. */
         try {
             switch ($encrypt) {
                 case IMP_Crypt_Pgp::SIGN:
                     $base = $imp_pgp->impSignMimePart($base);
                     $this->_setMetadata('encrypt_sign', true);
                     break;
                 case IMP_Crypt_Pgp::ENCRYPT:
                 case IMP_Crypt_Pgp::SYM_ENCRYPT:
                     $to_list = clone $to;
                     if (count($options['from'])) {
                         $to_list->add($options['from']);
                     }
                     $base = $imp_pgp->IMPencryptMIMEPart($base, $to_list, $encrypt == IMP_Crypt_Pgp::SYM_ENCRYPT ? $symmetric_passphrase : null);
                     break;
                 case IMP_Crypt_Pgp::SIGNENC:
                 case IMP_Crypt_Pgp::SYM_SIGNENC:
                     $to_list = clone $to;
                     if (count($options['from'])) {
                         $to_list->add($options['from']);
                     }
                     $base = $imp_pgp->IMPsignAndEncryptMIMEPart($base, $to_list, $encrypt == IMP_Crypt_Pgp::SYM_SIGNENC ? $symmetric_passphrase : null);
                     break;
             }
         } catch (Horde_Exception $e) {
             throw new IMP_Compose_Exception(_("PGP Error: ") . $e->getMessage(), $e->getCode());
         }
     } elseif ($prefs->getValue('use_smime') && in_array($encrypt, array(IMP_Crypt_Smime::ENCRYPT, IMP_Crypt_Smime::SIGN, IMP_Crypt_Smime::SIGNENC))) {
         $imp_smime = $injector->getInstance('IMP_Crypt_Smime');
         /* Check to see if we have the user's passphrase yet. */
         if (in_array($encrypt, array(IMP_Crypt_Smime::SIGN, IMP_Crypt_Smime::SIGNENC))) {
             $passphrase = $imp_smime->getPassphrase();
             if ($passphrase === false) {
                 $e = new IMP_Compose_Exception(_("S/MIME Error: Need passphrase for personal private key."));
                 $e->encrypt = 'smime_passphrase_dialog';
                 throw $e;
             }
         }
         /* Do the encryption/signing requested. */
         try {
             switch ($encrypt) {
                 case IMP_Crypt_Smime::SIGN:
                     $base = $imp_smime->IMPsignMIMEPart($base);
                     $this->_setMetadata('encrypt_sign', true);
                     break;
                 case IMP_Crypt_Smime::ENCRYPT:
                     $base = $imp_smime->IMPencryptMIMEPart($base, $to[0]);
                     break;
                 case IMP_Crypt_Smime::SIGNENC:
                     $base = $imp_smime->IMPsignAndEncryptMIMEPart($base, $to[0]);
                     break;
             }
         } catch (Horde_Exception $e) {
             throw new IMP_Compose_Exception(_("S/MIME Error: ") . $e->getMessage(), $e->getCode());
         }
     }
     /* Flag this as the base part and rebuild MIME IDs. */
     $base->isBasePart(true);
     $base->buildMimeIds();
     return $base;
 }