TYPO3 API  SVNRelease
EsmtpTransport.php
Go to the documentation of this file.
00001 <?php
00002 
00003 /*
00004  * This file is part of SwiftMailer.
00005  * (c) 2004-2009 Chris Corbyn
00006  *
00007  * For the full copyright and license information, please view the LICENSE
00008  * file that was distributed with this source code.
00009  */
00010 
00011 //@require 'Swift/Transport/AbstractSmtpTransport.php';
00012 //@require 'Swift/Transport/EsmtpHandler.php';
00013 //@require 'Swift/Transport/IoBuffer.php';
00014 //@require 'Swift/Transport/SmtpAgent.php';
00015 //@require 'Swift/TransportException.php';
00016 //@require 'Swift/Mime/Message.php';
00017 //@require 'Swift/Events/EventDispatcher.php';
00018 
00019 /**
00020  * Sends Messages over SMTP with ESMTP support.
00021  * @package Swift
00022  * @subpackage Transport
00023  * @author Chris Corbyn
00024  */
00025 class Swift_Transport_EsmtpTransport
00026   extends Swift_Transport_AbstractSmtpTransport
00027   implements Swift_Transport_SmtpAgent
00028 {
00029 
00030   /**
00031    * ESMTP extension handlers.
00032    * @var Swift_Transport_EsmtpHandler[]
00033    * @access private
00034    */
00035   private $_handlers = array();
00036 
00037   /**
00038    * ESMTP capabilities.
00039    * @var string[]
00040    * @access private
00041    */
00042   private $_capabilities = array();
00043 
00044   /**
00045    * Connection buffer parameters.
00046    * @var array
00047    * @access protected
00048    */
00049   private $_params = array(
00050     'protocol' => 'tcp',
00051     'host' => 'localhost',
00052     'port' => 25,
00053     'timeout' => 30,
00054     'blocking' => 1,
00055     'type' => Swift_Transport_IoBuffer::TYPE_SOCKET
00056     );
00057 
00058   /**
00059    * Creates a new EsmtpTransport using the given I/O buffer.
00060    * @param Swift_Transport_IoBuffer $buf
00061    * @param Swift_Transport_EsmtpHandler[] $extensionHandlers
00062    * @param Swift_Events_EventDispatcher $dispatcher
00063    */
00064   public function __construct(Swift_Transport_IoBuffer $buf,
00065     array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher)
00066   {
00067     parent::__construct($buf, $dispatcher);
00068     $this->setExtensionHandlers($extensionHandlers);
00069   }
00070 
00071   /**
00072    * Set the host to connect to.
00073    * @param string $host
00074    */
00075   public function setHost($host)
00076   {
00077     $this->_params['host'] = $host;
00078     return $this;
00079   }
00080 
00081   /**
00082    * Get the host to connect to.
00083    * @return string
00084    */
00085   public function getHost()
00086   {
00087     return $this->_params['host'];
00088   }
00089 
00090   /**
00091    * Set the port to connect to.
00092    * @param int $port
00093    */
00094   public function setPort($port)
00095   {
00096     $this->_params['port'] = (int) $port;
00097     return $this;
00098   }
00099 
00100   /**
00101    * Get the port to connect to.
00102    * @return int
00103    */
00104   public function getPort()
00105   {
00106     return $this->_params['port'];
00107   }
00108 
00109   /**
00110    * Set the connection timeout.
00111    * @param int $timeout seconds
00112    */
00113   public function setTimeout($timeout)
00114   {
00115     $this->_params['timeout'] = (int) $timeout;
00116     return $this;
00117   }
00118 
00119   /**
00120    * Get the connection timeout.
00121    * @return int
00122    */
00123   public function getTimeout()
00124   {
00125     return $this->_params['timeout'];
00126   }
00127 
00128   /**
00129    * Set the encryption type (tls or ssl)
00130    * @param string $encryption
00131    */
00132   public function setEncryption($enc)
00133   {
00134     $this->_params['protocol'] = $enc;
00135     return $this;
00136   }
00137 
00138   /**
00139    * Get the encryption type.
00140    * @return string
00141    */
00142   public function getEncryption()
00143   {
00144     return $this->_params['protocol'];
00145   }
00146 
00147   /**
00148    * Set ESMTP extension handlers.
00149    * @param Swift_Transport_EsmtpHandler[] $handlers
00150    */
00151   public function setExtensionHandlers(array $handlers)
00152   {
00153     $assoc = array();
00154     foreach ($handlers as $handler)
00155     {
00156       $assoc[$handler->getHandledKeyword()] = $handler;
00157     }
00158     uasort($assoc, array($this, '_sortHandlers'));
00159     $this->_handlers = $assoc;
00160     $this->_setHandlerParams();
00161     return $this;
00162   }
00163 
00164   /**
00165    * Get ESMTP extension handlers.
00166    * @return Swift_Transport_EsmtpHandler[]
00167    */
00168   public function getExtensionHandlers()
00169   {
00170     return array_values($this->_handlers);
00171   }
00172 
00173   /**
00174    * Run a command against the buffer, expecting the given response codes.
00175    * If no response codes are given, the response will not be validated.
00176    * If codes are given, an exception will be thrown on an invalid response.
00177    * @param string $command
00178    * @param int[] $codes
00179    * @param string[] &$failures
00180    * @return string
00181    */
00182   public function executeCommand($command, $codes = array(), &$failures = null)
00183   {
00184     $failures = (array) $failures;
00185     $stopSignal = false;
00186     $response = null;
00187     foreach ($this->_getActiveHandlers() as $handler)
00188     {
00189       $response = $handler->onCommand(
00190         $this, $command, $codes, $failures, $stopSignal
00191         );
00192       if ($stopSignal)
00193       {
00194         return $response;
00195       }
00196     }
00197     return parent::executeCommand($command, $codes, $failures);
00198   }
00199 
00200   // -- Mixin invocation code
00201 
00202   /** Mixin handling method for ESMTP handlers */
00203   public function __call($method, $args)
00204   {
00205     foreach ($this->_handlers as $handler)
00206     {
00207       if (in_array(strtolower($method),
00208         array_map('strtolower', (array) $handler->exposeMixinMethods())
00209         ))
00210       {
00211         $return = call_user_func_array(array($handler, $method), $args);
00212         //Allow fluid method calls
00213         if (is_null($return) && substr($method, 0, 3) == 'set')
00214         {
00215           return $this;
00216         }
00217         else
00218         {
00219           return $return;
00220         }
00221       }
00222     }
00223     trigger_error('Call to undefined method ' . $method, E_USER_ERROR);
00224   }
00225 
00226   // -- Protected methods
00227 
00228   /** Get the params to initialize the buffer */
00229   protected function _getBufferParams()
00230   {
00231     return $this->_params;
00232   }
00233 
00234   /** Overridden to perform EHLO instead */
00235   protected function _doHeloCommand()
00236   {
00237     try
00238     {
00239       $response = $this->executeCommand(
00240         sprintf("EHLO %s\r\n", $this->_domain), array(250)
00241         );
00242     }
00243     catch (Swift_TransportException $e)
00244     {
00245       return parent::_doHeloCommand();
00246     }
00247 
00248     $this->_capabilities = $this->_getCapabilities($response);
00249     $this->_setHandlerParams();
00250     foreach ($this->_getActiveHandlers() as $handler)
00251     {
00252       $handler->afterEhlo($this);
00253     }
00254   }
00255 
00256   /** Overridden to add Extension support */
00257   protected function _doMailFromCommand($address)
00258   {
00259     $handlers = $this->_getActiveHandlers();
00260     $params = array();
00261     foreach ($handlers as $handler)
00262     {
00263       $params = array_merge($params, (array) $handler->getMailParams());
00264     }
00265     $paramStr = !empty($params) ? ' ' . implode(' ', $params) : '';
00266     $this->executeCommand(
00267       sprintf("MAIL FROM: <%s>%s\r\n", $address, $paramStr), array(250)
00268       );
00269   }
00270 
00271   /** Overridden to add Extension support */
00272   protected function _doRcptToCommand($address)
00273   {
00274     $handlers = $this->_getActiveHandlers();
00275     $params = array();
00276     foreach ($handlers as $handler)
00277     {
00278       $params = array_merge($params, (array) $handler->getRcptParams());
00279     }
00280     $paramStr = !empty($params) ? ' ' . implode(' ', $params) : '';
00281     $this->executeCommand(
00282       sprintf("RCPT TO: <%s>%s\r\n", $address, $paramStr), array(250, 251, 252)
00283       );
00284   }
00285 
00286   // -- Private methods
00287 
00288   /** Determine ESMTP capabilities by function group */
00289   private function _getCapabilities($ehloResponse)
00290   {
00291     $capabilities = array();
00292     $ehloResponse = trim($ehloResponse);
00293     $lines = explode("\r\n", $ehloResponse);
00294     array_shift($lines);
00295     foreach ($lines as $line)
00296     {
00297       if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches))
00298       {
00299         $keyword = strtoupper($matches[1]);
00300         $paramStr = strtoupper(ltrim($matches[2], ' ='));
00301         $params = !empty($paramStr) ? explode(' ', $paramStr) : array();
00302         $capabilities[$keyword] = $params;
00303       }
00304     }
00305     return $capabilities;
00306   }
00307 
00308   /** Set parameters which are used by each extension handler */
00309   private function _setHandlerParams()
00310   {
00311     foreach ($this->_handlers as $keyword => $handler)
00312     {
00313       if (array_key_exists($keyword, $this->_capabilities))
00314       {
00315         $handler->setKeywordParams($this->_capabilities[$keyword]);
00316       }
00317     }
00318   }
00319 
00320   /** Get ESMTP handlers which are currently ok to use */
00321   private function _getActiveHandlers()
00322   {
00323     $handlers = array();
00324     foreach ($this->_handlers as $keyword => $handler)
00325     {
00326       if (array_key_exists($keyword, $this->_capabilities))
00327       {
00328         $handlers[] = $handler;
00329       }
00330     }
00331     return $handlers;
00332   }
00333 
00334   /** Custom sort for extension handler ordering */
00335   private function _sortHandlers($a, $b)
00336   {
00337     return $a->getPriorityOver($b->getHandledKeyword());
00338   }
00339 
00340 }