Автор: Michael Slusarz (slusarz@horde.org)
Наследование: extends IMP_Exception
Пример #1
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;
 }
Пример #2
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;
 }