Author: Jan Schneider (jan@horde.org)
Author: Chuck Hagenbuch (chuck@horde.org)
Inheritance: extends Horde_Core_Prefs_Identity
Exemple #1
0
 /**
  * Builds and sends a MIME message.
  *
  * @param string $body                  The message body.
  * @param array $header                 List of message headers.
  * @param IMP_Prefs_Identity $identity  The Identity object for the sender
  *                                      of this message.
  * @param array $opts                   An array of options w/the
  *                                      following keys:
  *  - encrypt: (integer) A flag whether to encrypt or sign the message.
  *            One of:
  *    - IMP_Pgp::ENCRYPT</li>
  *    - IMP_Pgp::SIGNENC</li>
  *    - IMP_Smime::ENCRYPT</li>
  *    - IMP_Smime::SIGNENC</li>
  *  - html: (boolean) Whether this is an HTML message.
  *          DEFAULT: false
  *  - pgp_attach_pubkey: (boolean) Attach the user's PGP public key to the
  *                       message?
  *  - priority: (string) The message priority ('high', 'normal', 'low').
  *  - save_sent: (boolean) Save sent mail?
  *  - sent_mail: (IMP_Mailbox) The sent-mail mailbox (UTF-8).
  *  - strip_attachments: (bool) Strip attachments from the message?
  *  - signature: (string) The message signature.
  *  - readreceipt: (boolean) Add return receipt headers?
  *  - useragent: (string) The User-Agent string to use.
  *  - vcard_attach: (string) Attach the user's vCard (value is name to
  *                  display as vcard filename).
  *
  * @throws Horde_Exception
  * @throws IMP_Compose_Exception
  * @throws IMP_Compose_Exception_Address
  * @throws IMP_Exception
  */
 public function buildAndSendMessage($body, $header, IMP_Prefs_Identity $identity, array $opts = array())
 {
     global $injector, $prefs, $registry, $session;
     /* Set up defaults. */
     $opts = array_merge(array('encrypt' => IMP::ENCRYPT_NONE), $opts);
     /* Check body size of message. */
     $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
     if (!$imp_imap->accessCompose(IMP_Imap::ACCESS_COMPOSE_BODYSIZE, strlen($body))) {
         Horde::permissionDeniedError('imp', 'max_bodysize');
         throw new IMP_Compose_Exception(sprintf(_("Your message body has exceeded the limit by body size by %d characters."), strlen($body) - $imp_imap->max_compose_bodysize));
     }
     /* We need at least one recipient. */
     $recip = $this->recipientList($header);
     if (!count($recip['list'])) {
         if ($recip['has_input']) {
             throw new IMP_Compose_Exception(_("Invalid e-mail address."));
         }
         throw new IMP_Compose_Exception(_("Need at least one message recipient."));
     }
     /* Recipient checks. */
     $this->_prepSendMessageAssert($recip['list']);
     /* Check for correct identity usage. */
     if (!$this->getMetadata('identity_check') && count($recip['list']) === 1) {
         $identity_search = $identity->getMatchingIdentity($recip['list'], false);
         if (!is_null($identity_search) && $identity->getDefault() != $identity_search) {
             $this->_setMetadata('identity_check', true);
             $e = new IMP_Compose_Exception(_("Recipient address does not match the currently selected identity."));
             $e->tied_identity = $identity_search;
             throw $e;
         }
     }
     /* Initalize a header object for the outgoing message. */
     $headers = $this->_prepareHeaders($header, $opts);
     /* Add a Received header for the hop from browser to server. */
     $headers->addHeaderOb(Horde_Core_Mime_Headers_Received::createHordeHop());
     /* Add the 'User-Agent' header. */
     $headers->addHeaderOb(new Horde_Mime_Headers_UserAgent(null, empty($opts['useragent']) ? 'Internet Messaging Program (IMP) ' . $registry->getVersion() : $opts['useragent']));
     /* Add preferred reply language(s). */
     if ($lang = @unserialize($prefs->getValue('reply_lang'))) {
         $headers->addHeader('Accept-Language', implode(',', $lang));
     }
     $message = $this->_createMimeMessage($body, array('html' => !empty($opts['html']), 'identity' => $identity, 'pgp_attach_pubkey' => !empty($opts['pgp_attach_pubkey']) && $prefs->getValue('use_pgp') && $prefs->getValue('pgp_public_key'), 'recip' => $recip['list'], 'signature' => is_null($opts['signature']) ? $identity : $opts['signature'], 'vcard_attach' => !empty($opts['vcard_attach']) && $registry->hasMethod('contacts/ownVCard') ? (strlen($opts['vcard_attach']) ? $opts['vcard_attach'] : 'vcard') . '.vcf' : null));
     /* Pass to hook to allow alteration of message details. */
     try {
         $injector->getInstance('Horde_Core_Hooks')->callHook('pre_sent', 'imp', array($message, $headers, $this));
         /* Re-parse headers to determine up-to-date recipient list. */
         $tmp_recip = array();
         foreach (array('to', 'cc', 'bcc') as $val) {
             if ($tmp_hdr = $headers[$val]) {
                 $tmp_recip[$val] = $tmp_hdr->getAddressList(true);
             }
         }
         $recip = $this->recipientList($tmp_recip);
     } catch (Horde_Exception_HookNotSet $e) {
     }
     /* Get from address. Done after pre_sent hook since from address could
      * be changed by hook. */
     $from = $headers['from']->getAddressList(true)->first();
     if (is_null($from->host)) {
         $from->host = $imp_imap->config->maildomain;
     }
     /* Add Reply-To header. Done after pre_sent hook since from address
      * could be change by hook and/or Reply-To was set by hook. */
     if (!empty($header['replyto']) && $header['replyto'] != $from->bare_address && !isset($headers['reply-to'])) {
         $headers->addHeader('Reply-To', $header['replyto']);
     }
     $message = $this->_encryptMessage($message, $opts['encrypt'], $recip['list'], $from);
     /* Send the messages out now. */
     try {
         $this->sendMessage($recip['list'], $headers, $message);
         /* Store history information. Even if history is inactive, this
          * will provide Message ID of message. */
         $msgid = $this->_logSentmail($headers, $recip['list'], true);
     } catch (IMP_Compose_Exception_Address $e) {
         throw $e;
     } catch (IMP_Compose_Exception $e) {
         /* Unsuccessful send. */
         if ($e->log()) {
             $this->_logSentmail($headers, $recip['list'], false);
         }
         throw new IMP_Compose_Exception(sprintf(_("There was an error sending your message: %s"), $e->getMessage()));
     }
     if ($this->_replytype) {
         /* Log the reply. */
         if ($indices = $this->getMetadata('indices')) {
             $log_data = array('msgid' => $msgid);
             switch ($this->_replytype) {
                 case self::FORWARD:
                 case self::FORWARD_ATTACH:
                 case self::FORWARD_BODY:
                 case self::FORWARD_BOTH:
                     $ob = 'IMP_Maillog_Log_Forward';
                     $log_data['recipients'] = strval($recip['list']);
                     break;
                 case self::REPLY:
                 case self::REPLY_SENDER:
                     $ob = 'IMP_Maillog_Log_Reply';
                     break;
                 case IMP_Compose::REPLY_ALL:
                     $ob = 'IMP_Maillog_Log_Replyall';
                     break;
                 case IMP_Compose::REPLY_LIST:
                     $ob = 'IMP_Maillog_Log_Replylist';
                     break;
             }
             $log = new $ob($log_data);
             $log_msgs = array();
             foreach ($indices as $val) {
                 foreach ($val->uids as $val2) {
                     $log_msgs[] = new IMP_Maillog_Message(new IMP_Indices($val->mbox, $val2));
                 }
             }
             $injector->getInstance('IMP_Maillog')->log($log_msgs, $log);
         }
         $reply_uid = new IMP_Indices($this);
         switch ($this->replyType(true)) {
             case self::FORWARD:
                 /* Set the Forwarded flag, if possible, in the mailbox.
                  * See RFC 5550 [5.9] */
                 $reply_uid->flag(array(Horde_Imap_Client::FLAG_FORWARDED));
                 break;
             case self::REPLY:
                 /* Make sure to set the IMAP reply flag and unset any
                  * 'flagged' flag. */
                 $reply_uid->flag(array(Horde_Imap_Client::FLAG_ANSWERED), array(Horde_Imap_Client::FLAG_FLAGGED));
                 break;
         }
     }
     Horde::log(sprintf("Message sent to %s from %s (%s)", strval($recip['list']), $registry->getAuth(), $session->get('horde', 'auth/remoteAddr')), 'INFO');
     /* Save message to the sent mail mailbox. */
     $this->_saveToSentMail($headers, $message, $recip['list'], $opts);
     /* Delete the attachment data. */
     $this->deleteAllAttachments();
     /* Save recipients to address book? */
     $this->_saveRecipients($recip['list']);
     /* Call post-sent hook. */
     try {
         $injector->getInstance('Horde_Core_Hooks')->callHook('post_sent', 'imp', array($message, $headers));
     } catch (Horde_Exception_HookNotSet $e) {
     }
 }
Exemple #2
0
 /**
  * Builds and sends a MIME message.
  *
  * @param string $body                  The message body.
  * @param array $header                 List of message headers.
  * @param IMP_Prefs_Identity $identity  The Identity object for the sender
  *                                      of this message.
  * @param array $opts                   An array of options w/the
  *                                      following keys:
  *  - encrypt: (integer) A flag whether to encrypt or sign the message.
  *            One of:
  *    - IMP_Crypt_Pgp::ENCRYPT</li>
  *    - IMP_Crypt_Pgp::SIGNENC</li>
  *    - IMP_Crypt_Smime::ENCRYPT</li>
  *    - IMP_Crypt_Smime::SIGNENC</li>
  *  - html: (boolean) Whether this is an HTML message.
  *          DEFAULT: false
  *  - pgp_attach_pubkey: (boolean) Attach the user's PGP public key to the
  *                       message?
  *  - priority: (string) The message priority ('high', 'normal', 'low').
  *  - save_sent: (boolean) Save sent mail?
  *  - sent_mail: (IMP_Mailbox) The sent-mail mailbox (UTF-8).
  *  - strip_attachments: (bool) Strip attachments from the message?
  *  - signature: (string) The message signature.
  *  - readreceipt: (boolean) Add return receipt headers?
  *  - useragent: (string) The User-Agent string to use.
  *  - vcard_attach: (string) Attach the user's vCard (value is name to
  *                  display as vcard filename).
  *
  * @throws Horde_Exception
  * @throws IMP_Compose_Exception
  * @throws IMP_Compose_Exception_Address
  * @throws IMP_Exception
  */
 public function buildAndSendMessage($body, $header, IMP_Prefs_Identity $identity, array $opts = array())
 {
     global $conf, $injector, $notification, $prefs, $registry, $session;
     /* We need at least one recipient & RFC 2822 requires that no 8-bit
      * characters can be in the address fields. */
     $recip = $this->recipientList($header);
     if (!count($recip['list'])) {
         if ($recip['has_input']) {
             throw new IMP_Compose_Exception(_("Invalid e-mail address."));
         }
         throw new IMP_Compose_Exception(_("Need at least one message recipient."));
     }
     $header = array_merge($header, $recip['header']);
     /* Check for correct identity usage. */
     if (!$this->getMetadata('identity_check') && count($recip['list']) === 1) {
         $identity_search = $identity->getMatchingIdentity($recip['list'], false);
         if (!is_null($identity_search) && $identity->getDefault() != $identity_search) {
             $this->_setMetadata('identity_check', true);
             $e = new IMP_Compose_Exception(_("Recipient address does not match the currently selected identity."));
             $e->tied_identity = $identity_search;
             throw $e;
         }
     }
     /* Check body size of message. */
     $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
     if (!$imp_imap->accessCompose(IMP_Imap::ACCESS_COMPOSE_BODYSIZE, strlen($body))) {
         Horde::permissionDeniedError('imp', 'max_bodysize');
         throw new IMP_Compose_Exception(sprintf(_("Your message body has exceeded the limit by body size by %d characters."), strlen($body) - $imp_imap->max_compose_bodysize));
     }
     $from = new Horde_Mail_Rfc822_Address($header['from']);
     if (is_null($from->host)) {
         $from->host = $imp_imap->config->maildomain;
     }
     /* Prepare the array of messages to send out.  May be more
      * than one if we are encrypting for multiple recipients or
      * are storing an encrypted message locally. */
     $encrypt = empty($opts['encrypt']) ? 0 : $opts['encrypt'];
     $send_msgs = array();
     $msg_options = array('encrypt' => $encrypt, 'html' => !empty($opts['html']), 'identity' => $identity, 'pgp_attach_pubkey' => !empty($opts['pgp_attach_pubkey']) && $prefs->getValue('use_pgp') && $prefs->getValue('pgp_public_key'), 'signature' => is_null($opts['signature']) ? $identity : $opts['signature'], 'vcard_attach' => !empty($opts['vcard_attach']) && $registry->hasMethod('contacts/ownVCard') ? (strlen($opts['vcard_attach']) ? $opts['vcard_attach'] : 'vcard') . '.vcf' : null);
     /* Must encrypt & send the message one recipient at a time. */
     if ($prefs->getValue('use_smime') && in_array($encrypt, array(IMP_Crypt_Smime::ENCRYPT, IMP_Crypt_Smime::SIGNENC))) {
         foreach ($recip['list'] as $val) {
             $list_ob = new Horde_Mail_Rfc822_List($val);
             $send_msgs[] = array('base' => $this->_createMimeMessage($list_ob, $body, $msg_options), 'recipients' => $list_ob);
         }
         /* Must target the encryption for the sender before saving message
          * in sent-mail. */
         $save_msg = $this->_createMimeMessage(IMP::parseAddressList($header['from']), $body, $msg_options);
     } else {
         /* Can send in clear-text all at once, or PGP can encrypt
          * multiple addresses in the same message. */
         $msg_options['from'] = $from;
         $save_msg = $this->_createMimeMessage($recip['list'], $body, $msg_options);
         $send_msgs[] = array('base' => $save_msg, 'recipients' => $recip['list']);
     }
     /* Initalize a header object for the outgoing message. */
     $headers = $this->_prepareHeaders($header, $opts);
     /* Add a Received header for the hop from browser to server. */
     $headers->addReceivedHeader(array('dns' => $injector->getInstance('Net_DNS2_Resolver'), 'server' => $conf['server']['name']));
     /* Add Reply-To header. */
     if (!empty($header['replyto']) && $header['replyto'] != $from->bare_address) {
         $headers->addHeader('Reply-to', $header['replyto']);
     }
     /* Add the 'User-Agent' header. */
     if (empty($opts['useragent'])) {
         $headers->setUserAgent('Internet Messaging Program (IMP) ' . $registry->getVersion());
     } else {
         $headers->setUserAgent($opts['useragent']);
     }
     $headers->addUserAgentHeader();
     /* Add preferred reply language(s). */
     if ($lang = @unserialize($prefs->getValue('reply_lang'))) {
         $headers->addHeader('Accept-Language', implode(',', $lang));
     }
     /* Send the messages out now. */
     $sentmail = $injector->getInstance('IMP_Sentmail');
     foreach ($send_msgs as $val) {
         switch (intval($this->replyType(true))) {
             case self::REPLY:
                 $senttype = IMP_Sentmail::REPLY;
                 break;
             case self::FORWARD:
                 $senttype = IMP_Sentmail::FORWARD;
                 break;
             case self::REDIRECT:
                 $senttype = IMP_Sentmail::REDIRECT;
                 break;
             default:
                 $senttype = IMP_Sentmail::NEWMSG;
                 break;
         }
         try {
             $this->_prepSendMessageAssert($val['recipients'], $headers, $val['base']);
             $this->sendMessage($val['recipients'], $headers, $val['base']);
             /* Store history information. */
             $msg_id = new Horde_Mail_Rfc822_Identification($headers->getValue('message-id'));
             $sentmail->log($senttype, reset($msg_id->ids), $val['recipients'], true);
         } catch (IMP_Compose_Exception_Address $e) {
             throw $e;
         } catch (IMP_Compose_Exception $e) {
             /* Unsuccessful send. */
             if ($e->log()) {
                 $msg_id = new Horde_Mail_Rfc822_Identification($headers->getValue('message-id'));
                 $sentmail->log($senttype, reset($msg_id->ids), $val['recipients'], false);
             }
             throw new IMP_Compose_Exception(sprintf(_("There was an error sending your message: %s"), $e->getMessage()));
         }
     }
     $recipients = strval($recip['list']);
     if ($this->_replytype) {
         /* Log the reply. */
         if ($indices = $this->getMetadata('indices')) {
             switch ($this->_replytype) {
                 case self::FORWARD:
                 case self::FORWARD_ATTACH:
                 case self::FORWARD_BODY:
                 case self::FORWARD_BOTH:
                     $log = new IMP_Maillog_Log_Forward($recipients);
                     break;
                 case self::REPLY:
                 case self::REPLY_SENDER:
                     $log = new IMP_Maillog_Log_Reply();
                     break;
                 case IMP_Compose::REPLY_ALL:
                     $log = new IMP_Maillog_Log_Replyall();
                     break;
                 case IMP_Compose::REPLY_LIST:
                     $log = new IMP_Maillog_Log_Replylist();
                     break;
             }
             $log_msgs = array();
             foreach ($indices as $val) {
                 foreach ($val->uids as $val2) {
                     $log_msgs[] = new IMP_Maillog_Message(new IMP_Indices($val->mbox, $val2));
                 }
             }
             $injector->getInstance('IMP_Maillog')->log($log_msgs, $log);
         }
         $imp_message = $injector->getInstance('IMP_Message');
         $reply_uid = new IMP_Indices($this);
         switch ($this->replyType(true)) {
             case self::FORWARD:
                 /* Set the Forwarded flag, if possible, in the mailbox.
                  * See RFC 5550 [5.9] */
                 $imp_message->flag(array('add' => array(Horde_Imap_Client::FLAG_FORWARDED)), $reply_uid);
                 break;
             case self::REPLY:
                 /* Make sure to set the IMAP reply flag and unset any
                  * 'flagged' flag. */
                 $imp_message->flag(array('add' => array(Horde_Imap_Client::FLAG_ANSWERED), 'remove' => array(Horde_Imap_Client::FLAG_FLAGGED)), $reply_uid);
                 break;
         }
     }
     Horde::log(sprintf("Message sent to %s from %s (%s)", $recipients, $registry->getAuth(), $session->get('horde', 'auth/remoteAddr')), 'INFO');
     /* Should we save this message in the sent mail mailbox? */
     if (!empty($opts['sent_mail']) && (!$prefs->isLocked('save_sent_mail') && !empty($opts['save_sent']) || $prefs->isLocked('save_sent_mail') && $prefs->getValue('save_sent_mail'))) {
         /* Keep Bcc: headers on saved messages. */
         if (count($header['bcc'])) {
             $headers->addHeader('Bcc', $header['bcc']);
         }
         /* Strip attachments if requested. */
         if (!empty($opts['strip_attachments'])) {
             $save_msg->buildMimeIds();
             /* Don't strip any part if this is a text message with both
              * plaintext and HTML representation. */
             if ($save_msg->getType() != 'multipart/alternative') {
                 for ($i = 2;; ++$i) {
                     if (!($oldPart = $save_msg->getPart($i))) {
                         break;
                     }
                     $replace_part = new Horde_Mime_Part();
                     $replace_part->setType('text/plain');
                     $replace_part->setCharset($this->charset);
                     $replace_part->setLanguage($GLOBALS['language']);
                     $replace_part->setContents('[' . _("Attachment stripped: Original attachment type") . ': "' . $oldPart->getType() . '", ' . _("name") . ': "' . $oldPart->getName(true) . '"]');
                     $save_msg->alterPart($i, $replace_part);
                 }
             }
         }
         /* Generate the message string. */
         $fcc = $save_msg->toString(array('defserver' => $imp_imap->config->maildomain, 'headers' => $headers, 'stream' => true));
         /* Make sure sent mailbox is created. */
         $sent_mail = IMP_Mailbox::get($opts['sent_mail']);
         $sent_mail->create();
         $flags = array(Horde_Imap_Client::FLAG_SEEN, Horde_Imap_Client::FLAG_MDNSENT);
         try {
             $imp_imap->append($sent_mail, array(array('data' => $fcc, 'flags' => $flags)));
         } catch (IMP_Imap_Exception $e) {
             $notification->push(sprintf(_("Message sent successfully, but not saved to %s."), $sent_mail->display));
         }
     }
     /* Delete the attachment data. */
     $this->deleteAllAttachments();
     /* Save recipients to address book? */
     $this->_saveRecipients($recip['list']);
     /* Call post-sent hook. */
     try {
         $injector->getInstance('Horde_Core_Hooks')->callHook('post_sent', 'imp', array($save_msg['msg'], $headers));
     } catch (Horde_Exception_HookNotSet $e) {
     }
 }