1<?php
2
3/**
4 * Swift Mailer mail() sending plugin
5 * Please read the LICENSE file
6 * @author Chris Corbyn <chris@w3style.co.uk>
7 * @package Swift_Connection
8 * @license GNU Lesser General Public License
9 */
10
11require_once dirname(__FILE__) . "/../ClassLoader.php";
12Swift_ClassLoader::load("Swift_Events_SendListener");
13Swift_ClassLoader::load("Swift_Events_BeforeSendListener");
14
15/**
16 * Swift mail() send plugin
17 * Sends the message using mail() when a SendEvent is fired.  Using the NativeMail connection provides stub responses to allow this to happen cleanly.
18 * @package Swift_Connection
19 * @author Chris Corbyn <chris@w3style.co.uk>
20 */
21class Swift_Plugin_MailSend implements Swift_Events_SendListener, Swift_Events_BeforeSendListener
22{
23  /**
24   * The operating system of the server
25   * @var string
26   */
27  protected $OS = null;
28  /**
29   * The return path in use here
30   * @var string
31   */
32  protected $returnPath = null;
33  /**
34   * The line ending before we intrusively change it
35   * @var string
36   */
37  protected $oldLE = "\r\n";
38  /**
39   * 5th parameter in mail().
40   * @var string
41   */
42  protected $additionalParams;
43
44  /**
45   * Constructor.
46   * @param string 5th mail() function parameter as a sprintf() formatted string where %s is the sender.
47   */
48  public function __construct($params="-oi -f %s")
49  {
50    $this->setAdditionalParams($params);
51    $this->setOS(PHP_OS);
52  }
53  /**
54   * Set the 5th mail() function parameter as a sprintf() formatted string where %s is the sender.
55   * @param string
56   */
57  public function setAdditionalParams($params)
58  {
59    $this->additionalParams = $params;
60  }
61  /**
62   * Get the 5th mail() function parameter as a sprintf() string.
63   * @return string
64   */
65  public function getAdditionalParams()
66  {
67    return $this->additionalParams;
68  }
69  /**
70   * Set the operating system string (changes behaviour with LE)
71   * @param string The operating system
72   */
73  public function setOS($os)
74  {
75    $this->OS = $os;
76  }
77  /**
78   * Get the operating system string
79   * @return string
80   */
81  public function getOS()
82  {
83    return $this->OS;
84  }
85  /**
86   * Check if this is windows or not
87   * @return boolean
88   */
89  public function isWindows()
90  {
91    return (substr($this->getOS(), 0, 3) == "WIN");
92  }
93  /**
94   * Swift's BeforeSendEvent listener.
95   * Invoked just before Swift sends a message
96   * @param Swift_Events_SendEvent The event information
97   */
98  public function beforeSendPerformed(Swift_Events_SendEvent $e)
99  {
100    $message = $e->getMessage();
101    $message->uncacheAll();
102    $this->oldLE = $message->getLE();
103    if (!$this->isWindows() && $this->oldLE != "\n") $message->setLE("\n");
104  }
105  /**
106   * Swift's SendEvent listener.
107   * Invoked when Swift sends a message
108   * @param Swift_Events_SendEvent The event information
109   * @throws Swift_ConnectionException If mail() returns false
110   */
111  public function sendPerformed(Swift_Events_SendEvent $e)
112  {
113    $message = $e->getMessage();
114    $recipients = $e->getRecipients();
115
116    $to = array();
117    foreach ($recipients->getTo() as $addr)
118    {
119      if ($this->isWindows()) $to[] = substr($addr->build(true), 1, -1);
120      else $to[] = $addr->build();
121    }
122    $to = implode(", ", $to);
123
124    $bcc_orig = $message->headers->has("Bcc") ? $message->headers->get("Bcc") : null;
125    $subject_orig = $message->headers->has("Subject") ? $message->headers->get("Subject") : null;
126    $to_orig = $message->headers->has("To") ? $message->headers->get("To") : null;
127
128    $bcc = array();
129    foreach ($recipients->getBcc() as $addr) $bcc[] = $addr->build();
130    if (!empty($bcc)) $message->headers->set("Bcc", $bcc);
131    $bcc = null;
132
133    $body_data = $message->buildData();
134    $message_body = $body_data->readFull();
135
136    $subject_enc = $message->headers->has("Subject") ? $message->headers->getEncoded("Subject") : "";
137
138    $message->headers->set("To", null);
139    $message->headers->set("Subject", null);
140
141    $sender = $e->getSender();
142    $this->returnPath = $sender->build();
143    if ($message->headers->has("Return-Path")) $this->returnPath = $message->headers->get("Return-Path");
144    if (preg_match("~<([^>]+)>[^>]*\$~", $this->returnPath, $matches)) $this->returnPath = $matches[1];
145
146    $this->doMail($to, $subject_enc, $message_body, $message->headers, sprintf($this->getAdditionalParams(), $this->returnPath));
147    $message->setLE($this->oldLE);
148    $message->headers->set("To", $to_orig);
149    $message->headers->set("Subject", $subject_orig);
150    $message->headers->set("Bcc", $bcc_orig);
151  }
152
153  public function doMail($to, $subject, $message, $headers, $params)
154  {
155    $original_from = @ini_get("sendmail_from");
156    @ini_set("sendmail_from", $this->returnPath);
157
158    $headers = $headers->build();
159
160    if (!ini_get("safe_mode")) $success = mail($to, $subject, $message, $headers, $params);
161    else $success = mail($to, $subject, $message, $headers);
162
163    if (!$success)
164    {
165      @ini_set("sendmail_from", $original_from);
166      throw new Swift_ConnectionException("Sending failed using mail() as PHP's default mail() function returned boolean FALSE.");
167    }
168    @ini_set("sendmail_from", $original_from);
169  }
170}
171