Added feature #15998: Create a new API to send mails based on SwiftMailer to replace...
[Packages/TYPO3.CMS.git] / typo3 / contrib / swiftmailer / classes / Swift / Transport / EsmtpTransport.php
1 <?php
2
3 /*
4 * This file is part of SwiftMailer.
5 * (c) 2004-2009 Chris Corbyn
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11 //@require 'Swift/Transport/AbstractSmtpTransport.php';
12 //@require 'Swift/Transport/EsmtpHandler.php';
13 //@require 'Swift/Transport/IoBuffer.php';
14 //@require 'Swift/Transport/SmtpAgent.php';
15 //@require 'Swift/TransportException.php';
16 //@require 'Swift/Mime/Message.php';
17 //@require 'Swift/Events/EventDispatcher.php';
18
19 /**
20 * Sends Messages over SMTP with ESMTP support.
21 * @package Swift
22 * @subpackage Transport
23 * @author Chris Corbyn
24 */
25 class Swift_Transport_EsmtpTransport
26 extends Swift_Transport_AbstractSmtpTransport
27 implements Swift_Transport_SmtpAgent
28 {
29
30 /**
31 * ESMTP extension handlers.
32 * @var Swift_Transport_EsmtpHandler[]
33 * @access private
34 */
35 private $_handlers = array();
36
37 /**
38 * ESMTP capabilities.
39 * @var string[]
40 * @access private
41 */
42 private $_capabilities = array();
43
44 /**
45 * Connection buffer parameters.
46 * @var array
47 * @access protected
48 */
49 private $_params = array(
50 'protocol' => 'tcp',
51 'host' => 'localhost',
52 'port' => 25,
53 'timeout' => 30,
54 'blocking' => 1,
55 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET
56 );
57
58 /**
59 * Creates a new EsmtpTransport using the given I/O buffer.
60 * @param Swift_Transport_IoBuffer $buf
61 * @param Swift_Transport_EsmtpHandler[] $extensionHandlers
62 * @param Swift_Events_EventDispatcher $dispatcher
63 */
64 public function __construct(Swift_Transport_IoBuffer $buf,
65 array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher)
66 {
67 parent::__construct($buf, $dispatcher);
68 $this->setExtensionHandlers($extensionHandlers);
69 }
70
71 /**
72 * Set the host to connect to.
73 * @param string $host
74 */
75 public function setHost($host)
76 {
77 $this->_params['host'] = $host;
78 return $this;
79 }
80
81 /**
82 * Get the host to connect to.
83 * @return string
84 */
85 public function getHost()
86 {
87 return $this->_params['host'];
88 }
89
90 /**
91 * Set the port to connect to.
92 * @param int $port
93 */
94 public function setPort($port)
95 {
96 $this->_params['port'] = (int) $port;
97 return $this;
98 }
99
100 /**
101 * Get the port to connect to.
102 * @return int
103 */
104 public function getPort()
105 {
106 return $this->_params['port'];
107 }
108
109 /**
110 * Set the connection timeout.
111 * @param int $timeout seconds
112 */
113 public function setTimeout($timeout)
114 {
115 $this->_params['timeout'] = (int) $timeout;
116 return $this;
117 }
118
119 /**
120 * Get the connection timeout.
121 * @return int
122 */
123 public function getTimeout()
124 {
125 return $this->_params['timeout'];
126 }
127
128 /**
129 * Set the encryption type (tls or ssl)
130 * @param string $encryption
131 */
132 public function setEncryption($enc)
133 {
134 $this->_params['protocol'] = $enc;
135 return $this;
136 }
137
138 /**
139 * Get the encryption type.
140 * @return string
141 */
142 public function getEncryption()
143 {
144 return $this->_params['protocol'];
145 }
146
147 /**
148 * Set ESMTP extension handlers.
149 * @param Swift_Transport_EsmtpHandler[] $handlers
150 */
151 public function setExtensionHandlers(array $handlers)
152 {
153 $assoc = array();
154 foreach ($handlers as $handler)
155 {
156 $assoc[$handler->getHandledKeyword()] = $handler;
157 }
158 uasort($assoc, array($this, '_sortHandlers'));
159 $this->_handlers = $assoc;
160 $this->_setHandlerParams();
161 return $this;
162 }
163
164 /**
165 * Get ESMTP extension handlers.
166 * @return Swift_Transport_EsmtpHandler[]
167 */
168 public function getExtensionHandlers()
169 {
170 return array_values($this->_handlers);
171 }
172
173 /**
174 * Run a command against the buffer, expecting the given response codes.
175 * If no response codes are given, the response will not be validated.
176 * If codes are given, an exception will be thrown on an invalid response.
177 * @param string $command
178 * @param int[] $codes
179 * @param string[] &$failures
180 * @return string
181 */
182 public function executeCommand($command, $codes = array(), &$failures = null)
183 {
184 $failures = (array) $failures;
185 $stopSignal = false;
186 $response = null;
187 foreach ($this->_getActiveHandlers() as $handler)
188 {
189 $response = $handler->onCommand(
190 $this, $command, $codes, $failures, $stopSignal
191 );
192 if ($stopSignal)
193 {
194 return $response;
195 }
196 }
197 return parent::executeCommand($command, $codes, $failures);
198 }
199
200 // -- Mixin invocation code
201
202 /** Mixin handling method for ESMTP handlers */
203 public function __call($method, $args)
204 {
205 foreach ($this->_handlers as $handler)
206 {
207 if (in_array(strtolower($method),
208 array_map('strtolower', (array) $handler->exposeMixinMethods())
209 ))
210 {
211 $return = call_user_func_array(array($handler, $method), $args);
212 //Allow fluid method calls
213 if (is_null($return) && substr($method, 0, 3) == 'set')
214 {
215 return $this;
216 }
217 else
218 {
219 return $return;
220 }
221 }
222 }
223 trigger_error('Call to undefined method ' . $method, E_USER_ERROR);
224 }
225
226 // -- Protected methods
227
228 /** Get the params to initialize the buffer */
229 protected function _getBufferParams()
230 {
231 return $this->_params;
232 }
233
234 /** Overridden to perform EHLO instead */
235 protected function _doHeloCommand()
236 {
237 try
238 {
239 $response = $this->executeCommand(
240 sprintf("EHLO %s\r\n", $this->_domain), array(250)
241 );
242 }
243 catch (Swift_TransportException $e)
244 {
245 return parent::_doHeloCommand();
246 }
247
248 $this->_capabilities = $this->_getCapabilities($response);
249 $this->_setHandlerParams();
250 foreach ($this->_getActiveHandlers() as $handler)
251 {
252 $handler->afterEhlo($this);
253 }
254 }
255
256 /** Overridden to add Extension support */
257 protected function _doMailFromCommand($address)
258 {
259 $handlers = $this->_getActiveHandlers();
260 $params = array();
261 foreach ($handlers as $handler)
262 {
263 $params = array_merge($params, (array) $handler->getMailParams());
264 }
265 $paramStr = !empty($params) ? ' ' . implode(' ', $params) : '';
266 $this->executeCommand(
267 sprintf("MAIL FROM: <%s>%s\r\n", $address, $paramStr), array(250)
268 );
269 }
270
271 /** Overridden to add Extension support */
272 protected function _doRcptToCommand($address)
273 {
274 $handlers = $this->_getActiveHandlers();
275 $params = array();
276 foreach ($handlers as $handler)
277 {
278 $params = array_merge($params, (array) $handler->getRcptParams());
279 }
280 $paramStr = !empty($params) ? ' ' . implode(' ', $params) : '';
281 $this->executeCommand(
282 sprintf("RCPT TO: <%s>%s\r\n", $address, $paramStr), array(250, 251, 252)
283 );
284 }
285
286 // -- Private methods
287
288 /** Determine ESMTP capabilities by function group */
289 private function _getCapabilities($ehloResponse)
290 {
291 $capabilities = array();
292 $ehloResponse = trim($ehloResponse);
293 $lines = explode("\r\n", $ehloResponse);
294 array_shift($lines);
295 foreach ($lines as $line)
296 {
297 if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches))
298 {
299 $keyword = strtoupper($matches[1]);
300 $paramStr = strtoupper(ltrim($matches[2], ' ='));
301 $params = !empty($paramStr) ? explode(' ', $paramStr) : array();
302 $capabilities[$keyword] = $params;
303 }
304 }
305 return $capabilities;
306 }
307
308 /** Set parameters which are used by each extension handler */
309 private function _setHandlerParams()
310 {
311 foreach ($this->_handlers as $keyword => $handler)
312 {
313 if (array_key_exists($keyword, $this->_capabilities))
314 {
315 $handler->setKeywordParams($this->_capabilities[$keyword]);
316 }
317 }
318 }
319
320 /** Get ESMTP handlers which are currently ok to use */
321 private function _getActiveHandlers()
322 {
323 $handlers = array();
324 foreach ($this->_handlers as $keyword => $handler)
325 {
326 if (array_key_exists($keyword, $this->_capabilities))
327 {
328 $handlers[] = $handler;
329 }
330 }
331 return $handlers;
332 }
333
334 /** Custom sort for extension handler ordering */
335 private function _sortHandlers($a, $b)
336 {
337 return $a->getPriorityOver($b->getHandledKeyword());
338 }
339
340 }