/** * Send a redirect (a/k/a resent) message. See RFC 5322 [3.6.6]. * * @param mixed $to The addresses to redirect to. * @param boolean $log Whether to log the resending in the history and * sentmail log. * * @return array An object with the following properties for each * redirected message: * - contents: (IMP_Contents) The contents object. * - headers: (Horde_Mime_Headers) The header object. * - mbox: (IMP_Mailbox) Mailbox of the message. * - uid: (string) UID of the message. * * @throws IMP_Compose_Exception */ public function sendRedirectMessage($to, $log = true) { global $injector, $registry; $recip = $this->recipientList(array('to' => $to)); $identity = $injector->getInstance('IMP_Identity'); $from_addr = $identity->getFromAddress(); $out = array(); foreach ($this->getMetadata('redirect_indices') as $val) { foreach ($val->uids as $val2) { try { $contents = $injector->getInstance('IMP_Factory_Contents')->create($val->mbox->getIndicesOb($val2)); } catch (IMP_Exception $e) { throw new IMP_Compose_Exception(_("Error when redirecting message.")); } $headers = $contents->getHeader(); /* We need to set the Return-Path header to the current user - * see RFC 2821 [4.4]. */ $headers->removeHeader('return-path'); $headers->addHeader('Return-Path', $from_addr); /* Generate the 'Resent' headers (RFC 5322 [3.6.6]). These * headers are prepended to the message. */ $resent_headers = new Horde_Mime_Headers(); $resent_headers->addHeader('Resent-Date', date('r')); $resent_headers->addHeader('Resent-From', $from_addr); $resent_headers->addHeader('Resent-To', $recip['header']['to']); $resent_headers->addHeader('Resent-Message-ID', Horde_Mime::generateMessageId()); $header_text = trim($resent_headers->toString(array('encode' => 'UTF-8'))) . "\n" . trim($contents->getHeader(IMP_Contents::HEADER_TEXT)); $this->_prepSendMessageAssert($recip['list']); $to = $this->_prepSendMessage($recip['list']); $hdr_array = $headers->toArray(array('charset' => 'UTF-8')); $hdr_array['_raw'] = $header_text; try { $injector->getInstance('IMP_Mail')->send($to, $hdr_array, $contents->getBody()); } catch (Horde_Mail_Exception $e) { $e2 = new IMP_Compose_Exception($e); if (($prev = $e->getPrevious()) && $prev instanceof Horde_Smtp_Exception) { Horde::log(sprintf("SMTP Error: %s (%u; %s)", $prev->raw_msg, $prev->getCode(), $prev->getEnhancedSmtpCode() ?: 'N/A'), 'ERR'); $e2->logged = true; } throw $e2; } $recipients = strval($recip['list']); Horde::log(sprintf("%s Redirected message sent to %s from %s", $_SERVER['REMOTE_ADDR'], $recipients, $registry->getAuth()), 'INFO'); if ($log) { /* Store history information. */ $msg_id = new Horde_Mail_Rfc822_Identification($headers->getValue('message-id')); $injector->getInstance('IMP_Maillog')->log(new IMP_Maillog_Message(reset($msg_id->ids)), new IMP_Maillog_Log_Redirect($recipients)); $injector->getInstance('IMP_Sentmail')->log(IMP_Sentmail::REDIRECT, reset($msg_id->ids), $recipients); } $tmp = new stdClass(); $tmp->contents = $contents; $tmp->headers = $headers; $tmp->mbox = $val->mbox; $tmp->uid = $val2; $out[] = $tmp; } } return $out; }
/** * Generate the 'Message-ID' header. */ public function addMessageIdHeader() { $this->addHeader('Message-ID', Horde_Mime::generateMessageId()); }
/** * Sends email notifications to a list of recipients. * * We do some ugly work in here to make sure that no one gets comments * mailed to them that they shouldn't see (because of group permissions). * * @param array $opts Option hash with notification information. * Possible values: * - ticket: (Whups_Ticket) A ticket. If not set, * this is assumed to be a reminder * message. * - recipients: (array|string) The list of recipients, * with user names as keys and user roles * as values. * - subject: (string) The email subject. * - view: (Horde_View) The view object for the * message text. * - template: (string) The template file for the * message text. * - from: (string) The email sender. * - new: (boolean, optional) Whether the passed * ticket was just created. */ public function mail(array $opts) { global $conf, $registry, $prefs; $opts = array_merge(array('ticket' => false, 'new' => false), $opts); /* Set up recipients and message headers. */ $mail = new Horde_Mime_Mail(array('X-Whups-Generated' => 1, 'User-Agent' => 'Whups ' . $registry->getVersion(), 'Precedence' => 'bulk', 'Auto-Submitted' => $opts['ticket'] ? 'auto-replied' : 'auto-generated')); $mail_always = null; if ($opts['ticket'] && !empty($conf['mail']['always_copy'])) { $mail_always = $conf['mail']['always_copy']; if (strpos($mail_always, '<@>') !== false) { try { $mail_always = str_replace('<@>', $opts['ticket']->get('queue_name'), $mail_always); } catch (Whups_Exception $e) { $mail_always = null; } } if ($mail_always && !isset($opts['recipients'][$mail_always])) { $opts['recipients'][$mail_always] = 'always'; } } if ($opts['ticket'] && ($queue = $this->getQueue($opts['ticket']->get('queue'))) && !empty($queue['email'])) { $mail->addHeader('From', $queue['email']); } elseif (!empty($conf['mail']['from_addr'])) { $mail->addHeader('From', $conf['mail']['from_addr']); } else { $mail->addHeader('From', Whups::formatUser($opts['from'])); } if (!empty($conf['mail']['return_path'])) { $mail->addHeader('Return-Path', $conf['mail']['return_path']); } if ($opts['ticket']) { $opts['subject'] = '[' . $registry->get('name') . ' #' . $opts['ticket']->getId() . '] ' . $opts['subject']; } $mail->addHeader('Subject', $opts['subject']); /* Get our array of comments, sorted in the appropriate order. */ if ($opts['ticket']) { $comments = $this->getHistory($opts['ticket']->getId()); if ($conf['mail']['commenthistory'] == 'new' && count($comments)) { $comments = array_pop($comments); $comments = array($comments); } elseif ($conf['mail']['commenthistory'] != 'chronological') { $comments = array_reverse($comments); } } else { $comments = array(); } /* Don't notify any email address more than once. */ $seen_email_addresses = array(); /* Get VFS handle for attachments. */ if ($opts['ticket']) { $vfs = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Vfs')->create(); try { $attachments = Whups::getAttachments($opts['ticket']->getId()); } catch (Whups_Exception $e) { $attachments = array(); Horde::log($e); } } $from = Whups::getUserAttributes($opts['from']); foreach ($opts['recipients'] as $user => $role) { /* Make sure to check permissions as a guest for the 'always_copy' * address, and as the recipient for all others. */ $to = $full_name = ''; if (!empty($mail_always) && $user == $mail_always) { $details = null; $mycomments = Whups::permissionsFilter($comments, 'comment', Horde_Perms::READ, ''); $to = $mail_always; } else { $details = Whups::getUserAttributes($user); if (!empty($details['email'])) { $to = Whups::formatUser($details); $mycomments = Whups::permissionsFilter($comments, 'comment', Horde_Perms::READ, $details['user']); } $full_name = $details['name']; } /* We may have no recipients due to users excluding themselves * from self notifies. */ if (!$to) { continue; } if ($details && $details['type'] == 'user') { $user_prefs = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Prefs')->create('whups', array('user' => $details['user'])); if ($from['type'] == 'user' && $details['user'] == $from['user'] && $user_prefs->getValue('email_others_only')) { continue; } } if ($opts['ticket']) { /* Add attachments. */ $attachmentAdded = false; if (empty($GLOBALS['conf']['mail']['link_attach'])) { /* We need to remove all attachments because the attachment * list is potentially limited by permissions. */ $mail->clearParts(); foreach ($mycomments as $comment) { foreach ($comment['changes'] as $change) { if ($change['type'] != 'attachment') { continue; } foreach ($attachments as $attachment) { if ($attachment['name'] != $change['value']) { continue; } if (!isset($attachment['part'])) { $attachment['part'] = new Horde_Mime_Part(); $attachment['part']->setType(Horde_Mime_Magic::filenameToMime($change['value'], false)); $attachment['part']->setDisposition('attachment'); $attachment['part']->setContents($vfs->read(Whups::VFS_ATTACH_PATH . '/' . $opts['ticket']->getId(), $change['value'])); $attachment['part']->setName($change['value']); } $mail->addMimePart($attachment['part']); $attachmentAdded = true; break; } } } } $formattedComment = $this->formatComments($mycomments, $opts['ticket']->getId()); if (!$attachmentAdded && !strlen(trim($formattedComment)) && $details && $details['type'] == 'user' && $user_prefs->getValue('email_comments_only')) { continue; } $opts['view']->comment = $formattedComment; } $addr_ob = new Horde_Mail_Rfc822_Address($to); if ($addr_ob->valid) { $bare_address = $addr_ob->bare_address; if (!empty($seen_email_addresses[$bare_address])) { continue; } $seen_email_addresses[$bare_address] = true; if (empty($full_name) && !is_null($addr_ob->personal)) { $full_name = $addr_ob->personal; } } // Use email address as fallback. if (empty($full_name)) { $full_name = $to; } $opts['view']->full_name = $full_name; $opts['view']->role = $role; $body = $opts['view']->render($opts['template']); if (!strlen(trim($body))) { continue; } $mail->setBody($body); $mail->addHeader('Message-ID', Horde_Mime::generateMessageId()); if ($opts['ticket']) { $message_id = '<whups-' . $opts['ticket']->getId() . '-' . md5($user) . '@' . $conf['server']['name'] . '>'; if ($opts['new']) { $mail->addHeader('Message-ID', $message_id); } else { $mail->addHeader('In-Reply-To', $message_id); $mail->addHeader('References', $message_id); } } $mail->clearRecipients(); $mail->addHeader('To', $to); try { $mail->send($GLOBALS['injector']->getInstance('Horde_Mail'), true); $entry = sprintf('%s Message sent to %s from "%s"', $_SERVER['REMOTE_ADDR'], $to, $GLOBALS['registry']->getAuth()); Horde::log($entry, 'INFO'); } catch (Horde_Mime_Exception $e) { Horde::log($e, 'ERR'); } } }