PageRenderTime 65ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/phpmailer/class.smtp.php

https://bitbucket.org/synergylearning/campusconnect
PHP | 943 lines | 472 code | 81 blank | 390 comment | 66 complexity | ac45a086cec82caa4a8ac058b93df0df MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, LGPL-2.1, Apache-2.0, BSD-3-Clause, AGPL-3.0
  1. <?php
  2. /**
  3. * PHPMailer RFC821 SMTP email transport class.
  4. * Version 5.2.7
  5. * PHP version 5.0.0
  6. * @category PHP
  7. * @package PHPMailer
  8. * @link https://github.com/PHPMailer/PHPMailer/
  9. * @author Marcus Bointon (coolbru) <phpmailer@synchromedia.co.uk>
  10. * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
  11. * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
  12. * @copyright 2013 Marcus Bointon
  13. * @copyright 2004 - 2008 Andy Prevost
  14. * @copyright 2010 - 2012 Jim Jagielski
  15. * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
  16. */
  17. /**
  18. * PHPMailer RFC821 SMTP email transport class.
  19. *
  20. * Implements RFC 821 SMTP commands
  21. * and provides some utility methods for sending mail to an SMTP server.
  22. *
  23. * PHP Version 5.0.0
  24. *
  25. * @category PHP
  26. * @package PHPMailer
  27. * @link https://github.com/PHPMailer/PHPMailer/blob/master/class.smtp.php
  28. * @author Chris Ryan <unknown@example.com>
  29. * @author Marcus Bointon <phpmailer@synchromedia.co.uk>
  30. * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
  31. */
  32. class SMTP
  33. {
  34. /**
  35. * The PHPMailer SMTP Version number.
  36. */
  37. const VERSION = '5.2.7';
  38. /**
  39. * SMTP line break constant.
  40. */
  41. const CRLF = "\r\n";
  42. /**
  43. * The SMTP port to use if one is not specified.
  44. */
  45. const DEFAULT_SMTP_PORT = 25;
  46. /**
  47. * The PHPMailer SMTP Version number.
  48. * @type string
  49. * @deprecated This should be a constant
  50. * @see SMTP::VERSION
  51. */
  52. public $Version = '5.2.7';
  53. /**
  54. * SMTP server port number.
  55. * @type int
  56. * @deprecated This is only ever ued as default value, so should be a constant
  57. * @see SMTP::DEFAULT_SMTP_PORT
  58. */
  59. public $SMTP_PORT = 25;
  60. /**
  61. * SMTP reply line ending
  62. * @type string
  63. * @deprecated Use the class constant instead
  64. * @see SMTP::CRLF
  65. */
  66. public $CRLF = "\r\n";
  67. /**
  68. * Debug output level.
  69. * Options: 0 for no output, 1 for commands, 2 for data and commands
  70. * @type int
  71. */
  72. public $do_debug = 0;
  73. /**
  74. * The function/method to use for debugging output.
  75. * Options: 'echo', 'html' or 'error_log'
  76. * @type string
  77. */
  78. public $Debugoutput = 'echo';
  79. /**
  80. * Whether to use VERP.
  81. * @type bool
  82. */
  83. public $do_verp = false;
  84. /**
  85. * The SMTP timeout value for reads, in seconds.
  86. * @type int
  87. */
  88. public $Timeout = 15;
  89. /**
  90. * The SMTP timelimit value for reads, in seconds.
  91. * @type int
  92. */
  93. public $Timelimit = 30;
  94. /**
  95. * The socket for the server connection.
  96. * @type resource
  97. */
  98. protected $smtp_conn;
  99. /**
  100. * Error message, if any, for the last call.
  101. * @type string
  102. */
  103. protected $error = '';
  104. /**
  105. * The reply the server sent to us for HELO.
  106. * @type string
  107. */
  108. protected $helo_rply = '';
  109. /**
  110. * The most recent reply received from the server.
  111. * @type string
  112. */
  113. protected $last_reply = '';
  114. /**
  115. * Constructor.
  116. * @access public
  117. */
  118. public function __construct()
  119. {
  120. $this->smtp_conn = 0;
  121. $this->error = null;
  122. $this->helo_rply = null;
  123. $this->do_debug = 0;
  124. }
  125. /**
  126. * Output debugging info via a user-selected method.
  127. * @param string $str Debug string to output
  128. * @return void
  129. */
  130. protected function edebug($str)
  131. {
  132. switch ($this->Debugoutput) {
  133. case 'error_log':
  134. //Don't output, just log
  135. error_log($str);
  136. break;
  137. case 'html':
  138. //Cleans up output a bit for a better looking, HTML-safe output
  139. echo htmlentities(
  140. preg_replace('/[\r\n]+/', '', $str),
  141. ENT_QUOTES,
  142. 'UTF-8'
  143. )
  144. . "<br>\n";
  145. break;
  146. case 'echo':
  147. default:
  148. //Just echoes whatever was received
  149. echo $str;
  150. }
  151. }
  152. /**
  153. * Connect to an SMTP server.
  154. * @param string $host SMTP server IP or host name
  155. * @param int $port The port number to connect to
  156. * @param int $timeout How long to wait for the connection to open
  157. * @param array $options An array of options for stream_context_create()
  158. * @access public
  159. * @return bool
  160. */
  161. public function connect($host, $port = null, $timeout = 30, $options = array())
  162. {
  163. // Clear errors to avoid confusion
  164. $this->error = null;
  165. // Make sure we are __not__ connected
  166. if ($this->connected()) {
  167. // Already connected, generate error
  168. $this->error = array('error' => 'Already connected to a server');
  169. return false;
  170. }
  171. if (empty($port)) {
  172. $port = self::DEFAULT_SMTP_PORT;
  173. }
  174. // Connect to the SMTP server
  175. $errno = 0;
  176. $errstr = '';
  177. $socket_context = stream_context_create($options);
  178. //Suppress errors; connection failures are handled at a higher level
  179. $this->smtp_conn = @stream_socket_client(
  180. $host . ":" . $port,
  181. $errno,
  182. $errstr,
  183. $timeout,
  184. STREAM_CLIENT_CONNECT,
  185. $socket_context
  186. );
  187. // Verify we connected properly
  188. if (empty($this->smtp_conn)) {
  189. $this->error = array(
  190. 'error' => 'Failed to connect to server',
  191. 'errno' => $errno,
  192. 'errstr' => $errstr
  193. );
  194. if ($this->do_debug >= 1) {
  195. $this->edebug(
  196. 'SMTP -> ERROR: ' . $this->error['error']
  197. . ": $errstr ($errno)"
  198. );
  199. }
  200. return false;
  201. }
  202. // SMTP server can take longer to respond, give longer timeout for first read
  203. // Windows does not have support for this timeout function
  204. if (substr(PHP_OS, 0, 3) != 'WIN') {
  205. $max = ini_get('max_execution_time');
  206. if ($max != 0 && $timeout > $max) { // Don't bother if unlimited
  207. @set_time_limit($timeout);
  208. }
  209. stream_set_timeout($this->smtp_conn, $timeout, 0);
  210. }
  211. // Get any announcement
  212. $announce = $this->get_lines();
  213. if ($this->do_debug >= 2) {
  214. $this->edebug('SMTP -> FROM SERVER:' . $announce);
  215. }
  216. return true;
  217. }
  218. /**
  219. * Initiate a TLS (encrypted) session.
  220. * @access public
  221. * @return bool
  222. */
  223. public function startTLS()
  224. {
  225. if (!$this->sendCommand("STARTTLS", "STARTTLS", 220)) {
  226. return false;
  227. }
  228. // Begin encrypted connection
  229. if (!stream_socket_enable_crypto(
  230. $this->smtp_conn,
  231. true,
  232. STREAM_CRYPTO_METHOD_TLS_CLIENT
  233. )
  234. ) {
  235. return false;
  236. }
  237. return true;
  238. }
  239. /**
  240. * Perform SMTP authentication.
  241. * Must be run after hello().
  242. * @see hello()
  243. * @param string $username The user name
  244. * @param string $password The password
  245. * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5)
  246. * @param string $realm The auth realm for NTLM
  247. * @param string $workstation The auth workstation for NTLM
  248. * @access public
  249. * @return bool True if successfully authenticated.
  250. */
  251. public function authenticate(
  252. $username,
  253. $password,
  254. $authtype = 'LOGIN',
  255. $realm = '',
  256. $workstation = ''
  257. ) {
  258. if (empty($authtype)) {
  259. $authtype = 'LOGIN';
  260. }
  261. switch ($authtype) {
  262. case 'PLAIN':
  263. // Start authentication
  264. if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
  265. return false;
  266. }
  267. // Send encoded username and password
  268. if (!$this->sendCommand(
  269. 'User & Password',
  270. base64_encode("\0" . $username . "\0" . $password),
  271. 235
  272. )
  273. ) {
  274. return false;
  275. }
  276. break;
  277. case 'LOGIN':
  278. // Start authentication
  279. if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
  280. return false;
  281. }
  282. if (!$this->sendCommand("Username", base64_encode($username), 334)) {
  283. return false;
  284. }
  285. if (!$this->sendCommand("Password", base64_encode($password), 235)) {
  286. return false;
  287. }
  288. break;
  289. case 'NTLM':
  290. /*
  291. * ntlm_sasl_client.php
  292. * Bundled with Permission
  293. *
  294. * How to telnet in windows:
  295. * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
  296. * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
  297. */
  298. require_once 'extras/ntlm_sasl_client.php';
  299. $temp = new stdClass();
  300. $ntlm_client = new ntlm_sasl_client_class;
  301. //Check that functions are available
  302. if (!$ntlm_client->Initialize($temp)) {
  303. $this->error = array('error' => $temp->error);
  304. if ($this->do_debug >= 1) {
  305. $this->edebug(
  306. 'You need to enable some modules in your php.ini file: '
  307. . $this->error['error']
  308. );
  309. }
  310. return false;
  311. }
  312. //msg1
  313. $msg1 = $ntlm_client->TypeMsg1($realm, $workstation); //msg1
  314. if (!$this->sendCommand(
  315. 'AUTH NTLM',
  316. 'AUTH NTLM ' . base64_encode($msg1),
  317. 334
  318. )
  319. ) {
  320. return false;
  321. }
  322. //Though 0 based, there is a white space after the 3 digit number
  323. //msg2
  324. $challenge = substr($this->last_reply, 3);
  325. $challenge = base64_decode($challenge);
  326. $ntlm_res = $ntlm_client->NTLMResponse(
  327. substr($challenge, 24, 8),
  328. $password
  329. );
  330. //msg3
  331. $msg3 = $ntlm_client->TypeMsg3(
  332. $ntlm_res,
  333. $username,
  334. $realm,
  335. $workstation
  336. );
  337. // send encoded username
  338. return $this->sendCommand('Username', base64_encode($msg3), 235);
  339. break;
  340. case 'CRAM-MD5':
  341. // Start authentication
  342. if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
  343. return false;
  344. }
  345. // Get the challenge
  346. $challenge = base64_decode(substr($this->last_reply, 4));
  347. // Build the response
  348. $response = $username . ' ' . $this->hmac($challenge, $password);
  349. // send encoded credentials
  350. return $this->sendCommand('Username', base64_encode($response), 235);
  351. break;
  352. }
  353. return true;
  354. }
  355. /**
  356. * Calculate an MD5 HMAC hash.
  357. * Works like hash_hmac('md5', $data, $key)
  358. * in case that function is not available
  359. * @param string $data The data to hash
  360. * @param string $key The key to hash with
  361. * @access protected
  362. * @return string
  363. */
  364. protected function hmac($data, $key)
  365. {
  366. if (function_exists('hash_hmac')) {
  367. return hash_hmac('md5', $data, $key);
  368. }
  369. // The following borrowed from
  370. // http://php.net/manual/en/function.mhash.php#27225
  371. // RFC 2104 HMAC implementation for php.
  372. // Creates an md5 HMAC.
  373. // Eliminates the need to install mhash to compute a HMAC
  374. // Hacked by Lance Rushing
  375. $b = 64; // byte length for md5
  376. if (strlen($key) > $b) {
  377. $key = pack('H*', md5($key));
  378. }
  379. $key = str_pad($key, $b, chr(0x00));
  380. $ipad = str_pad('', $b, chr(0x36));
  381. $opad = str_pad('', $b, chr(0x5c));
  382. $k_ipad = $key ^ $ipad;
  383. $k_opad = $key ^ $opad;
  384. return md5($k_opad . pack('H*', md5($k_ipad . $data)));
  385. }
  386. /**
  387. * Check connection state.
  388. * @access public
  389. * @return bool True if connected.
  390. */
  391. public function connected()
  392. {
  393. if (!empty($this->smtp_conn)) {
  394. $sock_status = stream_get_meta_data($this->smtp_conn);
  395. if ($sock_status['eof']) {
  396. // the socket is valid but we are not connected
  397. if ($this->do_debug >= 1) {
  398. $this->edebug(
  399. 'SMTP -> NOTICE: EOF caught while checking if connected'
  400. );
  401. }
  402. $this->close();
  403. return false;
  404. }
  405. return true; // everything looks good
  406. }
  407. return false;
  408. }
  409. /**
  410. * Close the socket and clean up the state of the class.
  411. * Don't use this function without first trying to use QUIT.
  412. * @see quit()
  413. * @access public
  414. * @return void
  415. */
  416. public function close()
  417. {
  418. $this->error = null; // so there is no confusion
  419. $this->helo_rply = null;
  420. if (!empty($this->smtp_conn)) {
  421. // close the connection and cleanup
  422. fclose($this->smtp_conn);
  423. $this->smtp_conn = 0;
  424. }
  425. }
  426. /**
  427. * Send an SMTP DATA command.
  428. * Issues a data command and sends the msg_data to the server,
  429. * finializing the mail transaction. $msg_data is the message
  430. * that is to be send with the headers. Each header needs to be
  431. * on a single line followed by a <CRLF> with the message headers
  432. * and the message body being separated by and additional <CRLF>.
  433. * Implements rfc 821: DATA <CRLF>
  434. * @param string $msg_data Message data to send
  435. * @access public
  436. * @return bool
  437. */
  438. public function data($msg_data)
  439. {
  440. if (!$this->sendCommand('DATA', 'DATA', 354)) {
  441. return false;
  442. }
  443. /* The server is ready to accept data!
  444. * according to rfc821 we should not send more than 1000
  445. * including the CRLF
  446. * characters on a single line so we will break the data up
  447. * into lines by \r and/or \n then if needed we will break
  448. * each of those into smaller lines to fit within the limit.
  449. * in addition we will be looking for lines that start with
  450. * a period '.' and append and additional period '.' to that
  451. * line. NOTE: this does not count towards limit.
  452. */
  453. // Normalize the line breaks before exploding
  454. $msg_data = str_replace("\r\n", "\n", $msg_data);
  455. $msg_data = str_replace("\r", "\n", $msg_data);
  456. $lines = explode("\n", $msg_data);
  457. /* We need to find a good way to determine if headers are
  458. * in the msg_data or if it is a straight msg body
  459. * currently I am assuming rfc822 definitions of msg headers
  460. * and if the first field of the first line (':' separated)
  461. * does not contain a space then it _should_ be a header
  462. * and we can process all lines before a blank "" line as
  463. * headers.
  464. */
  465. $field = substr($lines[0], 0, strpos($lines[0], ':'));
  466. $in_headers = false;
  467. if (!empty($field) && !strstr($field, ' ')) {
  468. $in_headers = true;
  469. }
  470. //RFC 2822 section 2.1.1 limit
  471. $max_line_length = 998;
  472. foreach ($lines as $line) {
  473. $lines_out = null;
  474. if ($line == '' && $in_headers) {
  475. $in_headers = false;
  476. }
  477. // ok we need to break this line up into several smaller lines
  478. while (strlen($line) > $max_line_length) {
  479. $pos = strrpos(substr($line, 0, $max_line_length), ' ');
  480. // Patch to fix DOS attack
  481. if (!$pos) {
  482. $pos = $max_line_length - 1;
  483. $lines_out[] = substr($line, 0, $pos);
  484. $line = substr($line, $pos);
  485. } else {
  486. $lines_out[] = substr($line, 0, $pos);
  487. $line = substr($line, $pos + 1);
  488. }
  489. /* If processing headers add a LWSP-char to the front of new line
  490. * rfc822 on long msg headers
  491. */
  492. if ($in_headers) {
  493. $line = "\t" . $line;
  494. }
  495. }
  496. $lines_out[] = $line;
  497. // send the lines to the server
  498. while (list(, $line_out) = @each($lines_out)) {
  499. if (strlen($line_out) > 0) {
  500. if (substr($line_out, 0, 1) == '.') {
  501. $line_out = '.' . $line_out;
  502. }
  503. }
  504. $this->client_send($line_out . self::CRLF);
  505. }
  506. }
  507. // Message data has been sent, complete the command
  508. return $this->sendCommand('DATA END', '.', 250);
  509. }
  510. /**
  511. * Send an SMTP HELO or EHLO command.
  512. * Used to identify the sending server to the receiving server.
  513. * This makes sure that client and server are in a known state.
  514. * Implements from RFC 821: HELO <SP> <domain> <CRLF>
  515. * and RFC 2821 EHLO.
  516. * @param string $host The host name or IP to connect to
  517. * @access public
  518. * @return bool
  519. */
  520. public function hello($host = '')
  521. {
  522. // Try extended hello first (RFC 2821)
  523. if (!$this->sendHello('EHLO', $host)) {
  524. if (!$this->sendHello('HELO', $host)) {
  525. return false;
  526. }
  527. }
  528. return true;
  529. }
  530. /**
  531. * Send an SMTP HELO or EHLO command.
  532. * Low-level implementation used by hello()
  533. * @see hello()
  534. * @param string $hello The HELO string
  535. * @param string $host The hostname to say we are
  536. * @access protected
  537. * @return bool
  538. */
  539. protected function sendHello($hello, $host)
  540. {
  541. $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250);
  542. $this->helo_rply = $this->last_reply;
  543. return $noerror;
  544. }
  545. /**
  546. * Send an SMTP MAIL command.
  547. * Starts a mail transaction from the email address specified in
  548. * $from. Returns true if successful or false otherwise. If True
  549. * the mail transaction is started and then one or more recipient
  550. * commands may be called followed by a data command.
  551. * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
  552. * @param string $from Source address of this message
  553. * @access public
  554. * @return bool
  555. */
  556. public function mail($from)
  557. {
  558. $useVerp = ($this->do_verp ? ' XVERP' : '');
  559. return $this->sendCommand(
  560. 'MAIL FROM',
  561. 'MAIL FROM:<' . $from . '>' . $useVerp,
  562. 250
  563. );
  564. }
  565. /**
  566. * Send an SMTP QUIT command.
  567. * Closes the socket if there is no error or the $close_on_error argument is true.
  568. * Implements from rfc 821: QUIT <CRLF>
  569. * @param bool $close_on_error Should the connection close if an error occurs?
  570. * @access public
  571. * @return bool
  572. */
  573. public function quit($close_on_error = true)
  574. {
  575. $noerror = $this->sendCommand('QUIT', 'QUIT', 221);
  576. $e = $this->error; //Save any error
  577. if ($noerror or $close_on_error) {
  578. $this->close();
  579. $this->error = $e; //Restore any error from the quit command
  580. }
  581. return $noerror;
  582. }
  583. /**
  584. * Send an SMTP RCPT command.
  585. * Sets the TO argument to $to.
  586. * Returns true if the recipient was accepted false if it was rejected.
  587. * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
  588. * @param string $to The address the message is being sent to
  589. * @access public
  590. * @return bool
  591. */
  592. public function recipient($to)
  593. {
  594. return $this->sendCommand(
  595. 'RCPT TO ',
  596. 'RCPT TO:<' . $to . '>',
  597. array(250, 251)
  598. );
  599. }
  600. /**
  601. * Send an SMTP RSET command.
  602. * Abort any transaction that is currently in progress.
  603. * Implements rfc 821: RSET <CRLF>
  604. * @access public
  605. * @return bool True on success.
  606. */
  607. public function reset()
  608. {
  609. return $this->sendCommand('RSET', 'RSET', 250);
  610. }
  611. /**
  612. * Send a command to an SMTP server and check its return code.
  613. * @param string $command The command name - not sent to the server
  614. * @param string $commandstring The actual command to send
  615. * @param int|array $expect One or more expected integer success codes
  616. * @access protected
  617. * @return bool True on success.
  618. */
  619. protected function sendCommand($command, $commandstring, $expect)
  620. {
  621. if (!$this->connected()) {
  622. $this->error = array(
  623. "error" => "Called $command without being connected"
  624. );
  625. return false;
  626. }
  627. $this->client_send($commandstring . self::CRLF);
  628. $reply = $this->get_lines();
  629. $code = substr($reply, 0, 3);
  630. if ($this->do_debug >= 2) {
  631. $this->edebug('SMTP -> FROM SERVER:' . $reply);
  632. }
  633. if (!in_array($code, (array)$expect)) {
  634. $this->last_reply = null;
  635. $this->error = array(
  636. "error" => "$command command failed",
  637. "smtp_code" => $code,
  638. "detail" => substr($reply, 4)
  639. );
  640. if ($this->do_debug >= 1) {
  641. $this->edebug(
  642. 'SMTP -> ERROR: ' . $this->error['error'] . ': ' . $reply
  643. );
  644. }
  645. return false;
  646. }
  647. $this->last_reply = $reply;
  648. $this->error = null;
  649. return true;
  650. }
  651. /**
  652. * Send an SMTP SAML command.
  653. * Starts a mail transaction from the email address specified in $from.
  654. * Returns true if successful or false otherwise. If True
  655. * the mail transaction is started and then one or more recipient
  656. * commands may be called followed by a data command. This command
  657. * will send the message to the users terminal if they are logged
  658. * in and send them an email.
  659. * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
  660. * @param string $from The address the message is from
  661. * @access public
  662. * @return bool
  663. */
  664. public function sendAndMail($from)
  665. {
  666. return $this->sendCommand("SAML", "SAML FROM:$from", 250);
  667. }
  668. /**
  669. * Send an SMTP VRFY command.
  670. * @param string $name The name to verify
  671. * @access public
  672. * @return bool
  673. */
  674. public function verify($name)
  675. {
  676. return $this->sendCommand("VRFY", "VRFY $name", array(250, 251));
  677. }
  678. /**
  679. * Send an SMTP NOOP command.
  680. * Used to keep keep-alives alive, doesn't actually do anything
  681. * @access public
  682. * @return bool
  683. */
  684. public function noop()
  685. {
  686. return $this->sendCommand("NOOP", "NOOP", 250);
  687. }
  688. /**
  689. * Send an SMTP TURN command.
  690. * This is an optional command for SMTP that this class does not support.
  691. * This method is here to make the RFC821 Definition
  692. * complete for this class and __may__ be implemented in future
  693. * Implements from rfc 821: TURN <CRLF>
  694. * @access public
  695. * @return bool
  696. */
  697. public function turn()
  698. {
  699. $this->error = array(
  700. 'error' => 'The SMTP TURN command is not implemented'
  701. );
  702. if ($this->do_debug >= 1) {
  703. $this->edebug('SMTP -> NOTICE: ' . $this->error['error']);
  704. }
  705. return false;
  706. }
  707. /**
  708. * Send raw data to the server.
  709. * @param string $data The data to send
  710. * @access public
  711. * @return int|bool The number of bytes sent to the server or FALSE on error
  712. */
  713. public function client_send($data)
  714. {
  715. if ($this->do_debug >= 1) {
  716. $this->edebug("CLIENT -> SMTP: $data");
  717. }
  718. return fwrite($this->smtp_conn, $data);
  719. }
  720. /**
  721. * Get the latest error.
  722. * @access public
  723. * @return array
  724. */
  725. public function getError()
  726. {
  727. return $this->error;
  728. }
  729. /**
  730. * Get the last reply from the server.
  731. * @access public
  732. * @return string
  733. */
  734. public function getLastReply()
  735. {
  736. return $this->last_reply;
  737. }
  738. /**
  739. * Read the SMTP server's response.
  740. * Either before eof or socket timeout occurs on the operation.
  741. * With SMTP we can tell if we have more lines to read if the
  742. * 4th character is '-' symbol. If it is a space then we don't
  743. * need to read anything else.
  744. * @access protected
  745. * @return string
  746. */
  747. protected function get_lines()
  748. {
  749. $data = '';
  750. $endtime = 0;
  751. // If the connection is bad, give up now
  752. if (!is_resource($this->smtp_conn)) {
  753. return $data;
  754. }
  755. stream_set_timeout($this->smtp_conn, $this->Timeout);
  756. if ($this->Timelimit > 0) {
  757. $endtime = time() + $this->Timelimit;
  758. }
  759. while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
  760. $str = @fgets($this->smtp_conn, 515);
  761. if ($this->do_debug >= 4) {
  762. $this->edebug("SMTP -> get_lines(): \$data was \"$data\"");
  763. $this->edebug("SMTP -> get_lines(): \$str is \"$str\"");
  764. }
  765. $data .= $str;
  766. if ($this->do_debug >= 4) {
  767. $this->edebug("SMTP -> get_lines(): \$data is \"$data\"");
  768. }
  769. // if 4th character is a space, we are done reading, break the loop
  770. if (substr($str, 3, 1) == ' ') {
  771. break;
  772. }
  773. // Timed-out? Log and break
  774. $info = stream_get_meta_data($this->smtp_conn);
  775. if ($info['timed_out']) {
  776. if ($this->do_debug >= 4) {
  777. $this->edebug(
  778. 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)'
  779. );
  780. }
  781. break;
  782. }
  783. // Now check if reads took too long
  784. if ($endtime) {
  785. if (time() > $endtime) {
  786. if ($this->do_debug >= 4) {
  787. $this->edebug(
  788. 'SMTP -> get_lines(): timelimit reached ('
  789. . $this->Timelimit . ' sec)'
  790. );
  791. }
  792. break;
  793. }
  794. }
  795. }
  796. return $data;
  797. }
  798. /**
  799. * Enable or disable VERP address generation.
  800. * @param bool $enabled
  801. */
  802. public function setVerp($enabled = false)
  803. {
  804. $this->do_verp = $enabled;
  805. }
  806. /**
  807. * Get VERP address generation mode.
  808. * @return bool
  809. */
  810. public function getVerp()
  811. {
  812. return $this->do_verp;
  813. }
  814. /**
  815. * Set debug output method.
  816. * @param string $method The function/method to use for debugging output.
  817. */
  818. public function setDebugOutput($method = 'echo')
  819. {
  820. $this->Debugoutput = $method;
  821. }
  822. /**
  823. * Get debug output method.
  824. * @return string
  825. */
  826. public function getDebugOutput()
  827. {
  828. return $this->Debugoutput;
  829. }
  830. /**
  831. * Set debug output level.
  832. * @param int $level
  833. */
  834. public function setDebugLevel($level = 0)
  835. {
  836. $this->do_debug = $level;
  837. }
  838. /**
  839. * Get debug output level.
  840. * @return int
  841. */
  842. public function getDebugLevel()
  843. {
  844. return $this->do_debug;
  845. }
  846. /**
  847. * Set SMTP timeout.
  848. * @param int $timeout
  849. */
  850. public function setTimeout($timeout = 0)
  851. {
  852. $this->Timeout = $timeout;
  853. }
  854. /**
  855. * Get SMTP timeout.
  856. * @return int
  857. */
  858. public function getTimeout()
  859. {
  860. return $this->Timeout;
  861. }
  862. }