public function testBodyGeneration() { $dom = new Horde_Domhtml('<div>foo</div>'); $body = $dom->getBody(); $this->assertEquals(1, $body->childNodes->length); $this->assertEquals('div', $body->childNodes->item(0)->tagName); }
/** * 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; }
/** */ 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)); }
/** * 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; }