PopBeforeSmtpPlugin.php 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <?php
  2. /*
  3. * This file is part of SwiftMailer.
  4. * (c) 2004-2009 Chris Corbyn
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * Makes sure a connection to a POP3 host has been established prior to connecting to SMTP.
  11. *
  12. * @package Swift
  13. * @subpackage Plugins
  14. *
  15. * @author Chris Corbyn
  16. */
  17. class Swift_Plugins_PopBeforeSmtpPlugin implements Swift_Events_TransportChangeListener, Swift_Plugins_Pop_Pop3Connection
  18. {
  19. /** A delegate connection to use (mostly a test hook) */
  20. private $_connection;
  21. /** Hostname of the POP3 server */
  22. private $_host;
  23. /** Port number to connect on */
  24. private $_port;
  25. /** Encryption type to use (if any) */
  26. private $_crypto;
  27. /** Username to use (if any) */
  28. private $_username;
  29. /** Password to use (if any) */
  30. private $_password;
  31. /** Established connection via TCP socket */
  32. private $_socket;
  33. /** Connect timeout in seconds */
  34. private $_timeout = 10;
  35. /** SMTP Transport to bind to */
  36. private $_transport;
  37. /**
  38. * Create a new PopBeforeSmtpPlugin for $host and $port.
  39. *
  40. * @param string $host
  41. * @param int $port
  42. * @param string $cypto as "tls" or "ssl"
  43. */
  44. public function __construct($host, $port = 110, $crypto = null)
  45. {
  46. $this->_host = $host;
  47. $this->_port = $port;
  48. $this->_crypto = $crypto;
  49. }
  50. /**
  51. * Create a new PopBeforeSmtpPlugin for $host and $port.
  52. *
  53. * @param string $host
  54. * @param int $port
  55. * @param string $cypto as "tls" or "ssl"
  56. *
  57. * @return Swift_Plugins_PopBeforeSmtpPlugin
  58. */
  59. public static function newInstance($host, $port = 110, $crypto = null)
  60. {
  61. return new self($host, $port, $crypto);
  62. }
  63. /**
  64. * Set a Pop3Connection to delegate to instead of connecting directly.
  65. *
  66. * @param Swift_Plugins_Pop_Pop3Connection $connection
  67. */
  68. public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection)
  69. {
  70. $this->_connection = $connection;
  71. return $this;
  72. }
  73. /**
  74. * Bind this plugin to a specific SMTP transport instance.
  75. *
  76. * @param Swift_Transport
  77. */
  78. public function bindSmtp(Swift_Transport $smtp)
  79. {
  80. $this->_transport = $smtp;
  81. }
  82. /**
  83. * Set the connection timeout in seconds (default 10).
  84. *
  85. * @param int $timeout
  86. */
  87. public function setTimeout($timeout)
  88. {
  89. $this->_timeout = (int) $timeout;
  90. return $this;
  91. }
  92. /**
  93. * Set the username to use when connecting (if needed).
  94. *
  95. * @param string $username
  96. */
  97. public function setUsername($username)
  98. {
  99. $this->_username = $username;
  100. return $this;
  101. }
  102. /**
  103. * Set the password to use when connecting (if needed).
  104. *
  105. * @param string $password
  106. */
  107. public function setPassword($password)
  108. {
  109. $this->_password = $password;
  110. return $this;
  111. }
  112. /**
  113. * Connect to the POP3 host and authenticate.
  114. *
  115. * @throws Swift_Plugins_Pop_Pop3Exception if connection fails
  116. */
  117. public function connect()
  118. {
  119. if (isset($this->_connection)) {
  120. $this->_connection->connect();
  121. } else {
  122. if (!isset($this->_socket)) {
  123. if (!$socket = fsockopen(
  124. $this->_getHostString(), $this->_port, $errno, $errstr, $this->_timeout))
  125. {
  126. throw new Swift_Plugins_Pop_Pop3Exception(
  127. sprintf('Failed to connect to POP3 host [%s]: %s', $this->_host, $errstr)
  128. );
  129. }
  130. $this->_socket = $socket;
  131. if (false === $greeting = fgets($this->_socket)) {
  132. throw new Swift_Plugins_Pop_Pop3Exception(
  133. sprintf('Failed to connect to POP3 host [%s]', trim($greeting))
  134. );
  135. }
  136. $this->_assertOk($greeting);
  137. if ($this->_username) {
  138. $this->_command(sprintf("USER %s\r\n", $this->_username));
  139. $this->_command(sprintf("PASS %s\r\n", $this->_password));
  140. }
  141. }
  142. }
  143. }
  144. /**
  145. * Disconnect from the POP3 host.
  146. */
  147. public function disconnect()
  148. {
  149. if (isset($this->_connection)) {
  150. $this->_connection->disconnect();
  151. } else {
  152. $this->_command("QUIT\r\n");
  153. if (!fclose($this->_socket)) {
  154. throw new Swift_Plugins_Pop_Pop3Exception(
  155. sprintf('POP3 host [%s] connection could not be stopped', $this->_host)
  156. );
  157. }
  158. $this->_socket = null;
  159. }
  160. }
  161. /**
  162. * Invoked just before a Transport is started.
  163. *
  164. * @param Swift_Events_TransportChangeEvent $evt
  165. */
  166. public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt)
  167. {
  168. if (isset($this->_transport)) {
  169. if ($this->_transport !== $evt->getTransport()) {
  170. return;
  171. }
  172. }
  173. $this->connect();
  174. $this->disconnect();
  175. }
  176. /**
  177. * Not used.
  178. */
  179. public function transportStarted(Swift_Events_TransportChangeEvent $evt)
  180. {
  181. }
  182. /**
  183. * Not used.
  184. */
  185. public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt)
  186. {
  187. }
  188. /**
  189. * Not used.
  190. */
  191. public function transportStopped(Swift_Events_TransportChangeEvent $evt)
  192. {
  193. }
  194. // -- Private Methods
  195. private function _command($command)
  196. {
  197. if (!fwrite($this->_socket, $command)) {
  198. throw new Swift_Plugins_Pop_Pop3Exception(
  199. sprintf('Failed to write command [%s] to POP3 host', trim($command))
  200. );
  201. }
  202. if (false === $response = fgets($this->_socket)) {
  203. throw new Swift_Plugins_Pop_Pop3Exception(
  204. sprintf('Failed to read from POP3 host after command [%s]', trim($command))
  205. );
  206. }
  207. $this->_assertOk($response);
  208. return $response;
  209. }
  210. private function _assertOk($response)
  211. {
  212. if (substr($response, 0, 3) != '+OK') {
  213. throw new Swift_Plugins_Pop_Pop3Exception(
  214. sprintf('POP3 command failed [%s]', trim($response))
  215. );
  216. }
  217. }
  218. private function _getHostString()
  219. {
  220. $host = $this->_host;
  221. switch (strtolower($this->_crypto)) {
  222. case 'ssl':
  223. $host = 'ssl://' . $host;
  224. break;
  225. case 'tls':
  226. $host = 'tls://' . $host;
  227. break;
  228. }
  229. return $host;
  230. }
  231. }