PageRenderTime 38ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/class-smtp.php

https://gitlab.com/Gashler/dp
PHP | 1003 lines | 530 code | 125 blank | 348 comment | 120 complexity | 817712d3132067a4105222e1938e4534 MD5 | raw file
  1. <?php
  2. /*~ class.smtp.php
  3. .---------------------------------------------------------------------------.
  4. | Software: PHPMailer - PHP email class |
  5. | Version: 5.2.4 |
  6. | Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
  7. | ------------------------------------------------------------------------- |
  8. | Admin: Jim Jagielski (project admininistrator) |
  9. | Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
  10. | : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
  11. | : Jim Jagielski (jimjag) jimjag@gmail.com |
  12. | Founder: Brent R. Matzelle (original founder) |
  13. | Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
  14. | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
  15. | Copyright (c) 2001-2003, Brent R. Matzelle |
  16. | ------------------------------------------------------------------------- |
  17. | License: Distributed under the Lesser General Public License (LGPL) |
  18. | http://www.gnu.org/copyleft/lesser.html |
  19. | This program is distributed in the hope that it will be useful - WITHOUT |
  20. | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
  21. | FITNESS FOR A PARTICULAR PURPOSE. |
  22. '---------------------------------------------------------------------------'
  23. */
  24. /**
  25. * PHPMailer - PHP SMTP email transport class
  26. * NOTE: Designed for use with PHP version 5 and up
  27. * @package PHPMailer
  28. * @author Andy Prevost
  29. * @author Marcus Bointon
  30. * @copyright 2004 - 2008 Andy Prevost
  31. * @author Jim Jagielski
  32. * @copyright 2010 - 2012 Jim Jagielski
  33. * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
  34. */
  35. /**
  36. * PHP RFC821 SMTP client
  37. *
  38. * Implements all the RFC 821 SMTP commands except TURN which will always return a not implemented error.
  39. * SMTP also provides some utility methods for sending mail to an SMTP server.
  40. * @author Chris Ryan
  41. * @package PHPMailer
  42. */
  43. class SMTP {
  44. /**
  45. * SMTP server port
  46. * @var int
  47. */
  48. public $SMTP_PORT = 25;
  49. /**
  50. * SMTP reply line ending (don't change)
  51. * @var string
  52. */
  53. public $CRLF = "\r\n";
  54. /**
  55. * Sets whether debugging is turned on
  56. * @var bool
  57. */
  58. public $do_debug; // the level of debug to perform
  59. /**
  60. * Sets the function/method to use for debugging output.
  61. * Right now we only honor "echo" or "error_log"
  62. * @var string
  63. */
  64. public $Debugoutput = "echo";
  65. /**
  66. * Sets VERP use on/off (default is off)
  67. * @var bool
  68. */
  69. public $do_verp = false;
  70. /**
  71. * Sets the SMTP timeout value for reads, in seconds
  72. * @var int
  73. */
  74. public $Timeout = 15;
  75. /**
  76. * Sets the SMTP timelimit value for reads, in seconds
  77. * @var int
  78. */
  79. public $Timelimit = 30;
  80. /**
  81. * Sets the SMTP PHPMailer Version number
  82. * @var string
  83. */
  84. public $Version = '5.2.4';
  85. /////////////////////////////////////////////////
  86. // PROPERTIES, PRIVATE AND PROTECTED
  87. /////////////////////////////////////////////////
  88. /**
  89. * @var resource The socket to the server
  90. */
  91. private $smtp_conn;
  92. /**
  93. * @var string Error message, if any, for the last call
  94. */
  95. private $error;
  96. /**
  97. * @var string The reply the server sent to us for HELO
  98. */
  99. private $helo_rply;
  100. /**
  101. * Outputs debugging info via user-defined method
  102. * @param string $str
  103. */
  104. private function edebug($str) {
  105. if ($this->Debugoutput == "error_log") {
  106. error_log($str);
  107. } else {
  108. echo $str;
  109. }
  110. }
  111. /**
  112. * Initialize the class so that the data is in a known state.
  113. * @access public
  114. * @return SMTP
  115. */
  116. public function __construct() {
  117. $this->smtp_conn = 0;
  118. $this->error = null;
  119. $this->helo_rply = null;
  120. $this->do_debug = 0;
  121. }
  122. /////////////////////////////////////////////////
  123. // CONNECTION FUNCTIONS
  124. /////////////////////////////////////////////////
  125. /**
  126. * Connect to the server specified on the port specified.
  127. * If the port is not specified use the default SMTP_PORT.
  128. * If tval is specified then a connection will try and be
  129. * established with the server for that number of seconds.
  130. * If tval is not specified the default is 30 seconds to
  131. * try on the connection.
  132. *
  133. * SMTP CODE SUCCESS: 220
  134. * SMTP CODE FAILURE: 421
  135. * @access public
  136. * @param string $host
  137. * @param int $port
  138. * @param int $tval
  139. * @return bool
  140. */
  141. public function Connect($host, $port = 0, $tval = 30) {
  142. // set the error val to null so there is no confusion
  143. $this->error = null;
  144. // make sure we are __not__ connected
  145. if($this->connected()) {
  146. // already connected, generate error
  147. $this->error = array("error" => "Already connected to a server");
  148. return false;
  149. }
  150. if(empty($port)) {
  151. $port = $this->SMTP_PORT;
  152. }
  153. // connect to the smtp server
  154. $this->smtp_conn = @fsockopen($host, // the host of the server
  155. $port, // the port to use
  156. $errno, // error number if any
  157. $errstr, // error message if any
  158. $tval); // give up after ? secs
  159. // verify we connected properly
  160. if(empty($this->smtp_conn)) {
  161. $this->error = array("error" => "Failed to connect to server",
  162. "errno" => $errno,
  163. "errstr" => $errstr);
  164. if($this->do_debug >= 1) {
  165. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />');
  166. }
  167. return false;
  168. }
  169. // SMTP server can take longer to respond, give longer timeout for first read
  170. // Windows does not have support for this timeout function
  171. if(substr(PHP_OS, 0, 3) != "WIN") {
  172. $max = ini_get('max_execution_time');
  173. if ($max != 0 && $tval > $max) { // don't bother if unlimited
  174. @set_time_limit($tval);
  175. }
  176. stream_set_timeout($this->smtp_conn, $tval, 0);
  177. }
  178. // get any announcement
  179. $announce = $this->get_lines();
  180. if($this->do_debug >= 2) {
  181. $this->edebug("SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />');
  182. }
  183. return true;
  184. }
  185. /**
  186. * Initiate a TLS communication with the server.
  187. *
  188. * SMTP CODE 220 Ready to start TLS
  189. * SMTP CODE 501 Syntax error (no parameters allowed)
  190. * SMTP CODE 454 TLS not available due to temporary reason
  191. * @access public
  192. * @return bool success
  193. */
  194. public function StartTLS() {
  195. $this->error = null; # to avoid confusion
  196. if(!$this->connected()) {
  197. $this->error = array("error" => "Called StartTLS() without being connected");
  198. return false;
  199. }
  200. fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
  201. $rply = $this->get_lines();
  202. $code = substr($rply,0,3);
  203. if($this->do_debug >= 2) {
  204. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  205. }
  206. if($code != 220) {
  207. $this->error =
  208. array("error" => "STARTTLS not accepted from server",
  209. "smtp_code" => $code,
  210. "smtp_msg" => substr($rply,4));
  211. if($this->do_debug >= 1) {
  212. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  213. }
  214. return false;
  215. }
  216. // Begin encrypted connection
  217. if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
  218. return false;
  219. }
  220. return true;
  221. }
  222. /**
  223. * Performs SMTP authentication. Must be run after running the
  224. * Hello() method. Returns true if successfully authenticated.
  225. * @access public
  226. * @param string $username
  227. * @param string $password
  228. * @param string $authtype
  229. * @param string $realm
  230. * @param string $workstation
  231. * @return bool
  232. */
  233. public function Authenticate($username, $password, $authtype='LOGIN', $realm='', $workstation='') {
  234. if (empty($authtype)) {
  235. $authtype = 'LOGIN';
  236. }
  237. switch ($authtype) {
  238. case 'PLAIN':
  239. // Start authentication
  240. fputs($this->smtp_conn,"AUTH PLAIN" . $this->CRLF);
  241. $rply = $this->get_lines();
  242. $code = substr($rply,0,3);
  243. if($code != 334) {
  244. $this->error =
  245. array("error" => "AUTH not accepted from server",
  246. "smtp_code" => $code,
  247. "smtp_msg" => substr($rply,4));
  248. if($this->do_debug >= 1) {
  249. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  250. }
  251. return false;
  252. }
  253. // Send encoded username and password
  254. fputs($this->smtp_conn, base64_encode("\0".$username."\0".$password) . $this->CRLF);
  255. $rply = $this->get_lines();
  256. $code = substr($rply,0,3);
  257. if($code != 235) {
  258. $this->error =
  259. array("error" => "Authentication not accepted from server",
  260. "smtp_code" => $code,
  261. "smtp_msg" => substr($rply,4));
  262. if($this->do_debug >= 1) {
  263. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  264. }
  265. return false;
  266. }
  267. break;
  268. case 'LOGIN':
  269. // Start authentication
  270. fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
  271. $rply = $this->get_lines();
  272. $code = substr($rply,0,3);
  273. if($code != 334) {
  274. $this->error =
  275. array("error" => "AUTH not accepted from server",
  276. "smtp_code" => $code,
  277. "smtp_msg" => substr($rply,4));
  278. if($this->do_debug >= 1) {
  279. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  280. }
  281. return false;
  282. }
  283. // Send encoded username
  284. fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
  285. $rply = $this->get_lines();
  286. $code = substr($rply,0,3);
  287. if($code != 334) {
  288. $this->error =
  289. array("error" => "Username not accepted from server",
  290. "smtp_code" => $code,
  291. "smtp_msg" => substr($rply,4));
  292. if($this->do_debug >= 1) {
  293. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  294. }
  295. return false;
  296. }
  297. // Send encoded password
  298. fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
  299. $rply = $this->get_lines();
  300. $code = substr($rply,0,3);
  301. if($code != 235) {
  302. $this->error =
  303. array("error" => "Password not accepted from server",
  304. "smtp_code" => $code,
  305. "smtp_msg" => substr($rply,4));
  306. if($this->do_debug >= 1) {
  307. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  308. }
  309. return false;
  310. }
  311. break;
  312. case 'NTLM':
  313. /*
  314. * ntlm_sasl_client.php
  315. ** Bundled with Permission
  316. **
  317. ** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
  318. ** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
  319. */
  320. require_once('ntlm_sasl_client.php');
  321. $temp = new stdClass();
  322. $ntlm_client = new ntlm_sasl_client_class;
  323. if(! $ntlm_client->Initialize($temp)){//let's test if every function its available
  324. $this->error = array("error" => $temp->error);
  325. if($this->do_debug >= 1) {
  326. $this->edebug("You need to enable some modules in your php.ini file: " . $this->error["error"] . $this->CRLF);
  327. }
  328. return false;
  329. }
  330. $msg1 = $ntlm_client->TypeMsg1($realm, $workstation);//msg1
  331. fputs($this->smtp_conn,"AUTH NTLM " . base64_encode($msg1) . $this->CRLF);
  332. $rply = $this->get_lines();
  333. $code = substr($rply,0,3);
  334. if($code != 334) {
  335. $this->error =
  336. array("error" => "AUTH not accepted from server",
  337. "smtp_code" => $code,
  338. "smtp_msg" => substr($rply,4));
  339. if($this->do_debug >= 1) {
  340. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF);
  341. }
  342. return false;
  343. }
  344. $challange = substr($rply,3);//though 0 based, there is a white space after the 3 digit number....//msg2
  345. $challange = base64_decode($challange);
  346. $ntlm_res = $ntlm_client->NTLMResponse(substr($challange,24,8),$password);
  347. $msg3 = $ntlm_client->TypeMsg3($ntlm_res,$username,$realm,$workstation);//msg3
  348. // Send encoded username
  349. fputs($this->smtp_conn, base64_encode($msg3) . $this->CRLF);
  350. $rply = $this->get_lines();
  351. $code = substr($rply,0,3);
  352. if($code != 235) {
  353. $this->error =
  354. array("error" => "Could not authenticate",
  355. "smtp_code" => $code,
  356. "smtp_msg" => substr($rply,4));
  357. if($this->do_debug >= 1) {
  358. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF);
  359. }
  360. return false;
  361. }
  362. break;
  363. }
  364. return true;
  365. }
  366. /**
  367. * Returns true if connected to a server otherwise false
  368. * @access public
  369. * @return bool
  370. */
  371. public function Connected() {
  372. if(!empty($this->smtp_conn)) {
  373. $sock_status = socket_get_status($this->smtp_conn);
  374. if($sock_status["eof"]) {
  375. // the socket is valid but we are not connected
  376. if($this->do_debug >= 1) {
  377. $this->edebug("SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected");
  378. }
  379. $this->Close();
  380. return false;
  381. }
  382. return true; // everything looks good
  383. }
  384. return false;
  385. }
  386. /**
  387. * Closes the socket and cleans up the state of the class.
  388. * It is not considered good to use this function without
  389. * first trying to use QUIT.
  390. * @access public
  391. * @return void
  392. */
  393. public function Close() {
  394. $this->error = null; // so there is no confusion
  395. $this->helo_rply = null;
  396. if(!empty($this->smtp_conn)) {
  397. // close the connection and cleanup
  398. fclose($this->smtp_conn);
  399. $this->smtp_conn = 0;
  400. }
  401. }
  402. /////////////////////////////////////////////////
  403. // SMTP COMMANDS
  404. /////////////////////////////////////////////////
  405. /**
  406. * Issues a data command and sends the msg_data to the server
  407. * finializing the mail transaction. $msg_data is the message
  408. * that is to be send with the headers. Each header needs to be
  409. * on a single line followed by a <CRLF> with the message headers
  410. * and the message body being seperated by and additional <CRLF>.
  411. *
  412. * Implements rfc 821: DATA <CRLF>
  413. *
  414. * SMTP CODE INTERMEDIATE: 354
  415. * [data]
  416. * <CRLF>.<CRLF>
  417. * SMTP CODE SUCCESS: 250
  418. * SMTP CODE FAILURE: 552,554,451,452
  419. * SMTP CODE FAILURE: 451,554
  420. * SMTP CODE ERROR : 500,501,503,421
  421. * @access public
  422. * @param string $msg_data
  423. * @return bool
  424. */
  425. public function Data($msg_data) {
  426. $this->error = null; // so no confusion is caused
  427. if(!$this->connected()) {
  428. $this->error = array(
  429. "error" => "Called Data() without being connected");
  430. return false;
  431. }
  432. fputs($this->smtp_conn,"DATA" . $this->CRLF);
  433. $rply = $this->get_lines();
  434. $code = substr($rply,0,3);
  435. if($this->do_debug >= 2) {
  436. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  437. }
  438. if($code != 354) {
  439. $this->error =
  440. array("error" => "DATA command not accepted from server",
  441. "smtp_code" => $code,
  442. "smtp_msg" => substr($rply,4));
  443. if($this->do_debug >= 1) {
  444. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  445. }
  446. return false;
  447. }
  448. /* the server is ready to accept data!
  449. * according to rfc 821 we should not send more than 1000
  450. * including the CRLF
  451. * characters on a single line so we will break the data up
  452. * into lines by \r and/or \n then if needed we will break
  453. * each of those into smaller lines to fit within the limit.
  454. * in addition we will be looking for lines that start with
  455. * a period '.' and append and additional period '.' to that
  456. * line. NOTE: this does not count towards limit.
  457. */
  458. // normalize the line breaks so we know the explode works
  459. $msg_data = str_replace("\r\n","\n",$msg_data);
  460. $msg_data = str_replace("\r","\n",$msg_data);
  461. $lines = explode("\n",$msg_data);
  462. /* we need to find a good way to determine is headers are
  463. * in the msg_data or if it is a straight msg body
  464. * currently I am assuming rfc 822 definitions of msg headers
  465. * and if the first field of the first line (':' sperated)
  466. * does not contain a space then it _should_ be a header
  467. * and we can process all lines before a blank "" line as
  468. * headers.
  469. */
  470. $field = substr($lines[0],0,strpos($lines[0],":"));
  471. $in_headers = false;
  472. if(!empty($field) && !strstr($field," ")) {
  473. $in_headers = true;
  474. }
  475. $max_line_length = 998; // used below; set here for ease in change
  476. while(list(,$line) = @each($lines)) {
  477. $lines_out = null;
  478. if($line == "" && $in_headers) {
  479. $in_headers = false;
  480. }
  481. // ok we need to break this line up into several smaller lines
  482. while(strlen($line) > $max_line_length) {
  483. $pos = strrpos(substr($line,0,$max_line_length)," ");
  484. // Patch to fix DOS attack
  485. if(!$pos) {
  486. $pos = $max_line_length - 1;
  487. $lines_out[] = substr($line,0,$pos);
  488. $line = substr($line,$pos);
  489. } else {
  490. $lines_out[] = substr($line,0,$pos);
  491. $line = substr($line,$pos + 1);
  492. }
  493. /* if processing headers add a LWSP-char to the front of new line
  494. * rfc 822 on long msg headers
  495. */
  496. if($in_headers) {
  497. $line = "\t" . $line;
  498. }
  499. }
  500. $lines_out[] = $line;
  501. // send the lines to the server
  502. while(list(,$line_out) = @each($lines_out)) {
  503. if(strlen($line_out) > 0)
  504. {
  505. if(substr($line_out, 0, 1) == ".") {
  506. $line_out = "." . $line_out;
  507. }
  508. }
  509. fputs($this->smtp_conn,$line_out . $this->CRLF);
  510. }
  511. }
  512. // message data has been sent
  513. fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
  514. $rply = $this->get_lines();
  515. $code = substr($rply,0,3);
  516. if($this->do_debug >= 2) {
  517. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  518. }
  519. if($code != 250) {
  520. $this->error =
  521. array("error" => "DATA not accepted from server",
  522. "smtp_code" => $code,
  523. "smtp_msg" => substr($rply,4));
  524. if($this->do_debug >= 1) {
  525. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  526. }
  527. return false;
  528. }
  529. return true;
  530. }
  531. /**
  532. * Sends the HELO command to the smtp server.
  533. * This makes sure that we and the server are in
  534. * the same known state.
  535. *
  536. * Implements from rfc 821: HELO <SP> <domain> <CRLF>
  537. *
  538. * SMTP CODE SUCCESS: 250
  539. * SMTP CODE ERROR : 500, 501, 504, 421
  540. * @access public
  541. * @param string $host
  542. * @return bool
  543. */
  544. public function Hello($host = '') {
  545. $this->error = null; // so no confusion is caused
  546. if(!$this->connected()) {
  547. $this->error = array(
  548. "error" => "Called Hello() without being connected");
  549. return false;
  550. }
  551. // if hostname for HELO was not specified send default
  552. if(empty($host)) {
  553. // determine appropriate default to send to server
  554. $host = "localhost";
  555. }
  556. // Send extended hello first (RFC 2821)
  557. if(!$this->SendHello("EHLO", $host)) {
  558. if(!$this->SendHello("HELO", $host)) {
  559. return false;
  560. }
  561. }
  562. return true;
  563. }
  564. /**
  565. * Sends a HELO/EHLO command.
  566. * @access private
  567. * @param string $hello
  568. * @param string $host
  569. * @return bool
  570. */
  571. private function SendHello($hello, $host) {
  572. fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
  573. $rply = $this->get_lines();
  574. $code = substr($rply,0,3);
  575. if($this->do_debug >= 2) {
  576. $this->edebug("SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />');
  577. }
  578. if($code != 250) {
  579. $this->error =
  580. array("error" => $hello . " not accepted from server",
  581. "smtp_code" => $code,
  582. "smtp_msg" => substr($rply,4));
  583. if($this->do_debug >= 1) {
  584. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  585. }
  586. return false;
  587. }
  588. $this->helo_rply = $rply;
  589. return true;
  590. }
  591. /**
  592. * Starts a mail transaction from the email address specified in
  593. * $from. Returns true if successful or false otherwise. If True
  594. * the mail transaction is started and then one or more Recipient
  595. * commands may be called followed by a Data command.
  596. *
  597. * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
  598. *
  599. * SMTP CODE SUCCESS: 250
  600. * SMTP CODE SUCCESS: 552,451,452
  601. * SMTP CODE SUCCESS: 500,501,421
  602. * @access public
  603. * @param string $from
  604. * @return bool
  605. */
  606. public function Mail($from) {
  607. $this->error = null; // so no confusion is caused
  608. if(!$this->connected()) {
  609. $this->error = array(
  610. "error" => "Called Mail() without being connected");
  611. return false;
  612. }
  613. $useVerp = ($this->do_verp ? " XVERP" : "");
  614. fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
  615. $rply = $this->get_lines();
  616. $code = substr($rply,0,3);
  617. if($this->do_debug >= 2) {
  618. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  619. }
  620. if($code != 250) {
  621. $this->error =
  622. array("error" => "MAIL not accepted from server",
  623. "smtp_code" => $code,
  624. "smtp_msg" => substr($rply,4));
  625. if($this->do_debug >= 1) {
  626. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  627. }
  628. return false;
  629. }
  630. return true;
  631. }
  632. /**
  633. * Sends the quit command to the server and then closes the socket
  634. * if there is no error or the $close_on_error argument is true.
  635. *
  636. * Implements from rfc 821: QUIT <CRLF>
  637. *
  638. * SMTP CODE SUCCESS: 221
  639. * SMTP CODE ERROR : 500
  640. * @access public
  641. * @param bool $close_on_error
  642. * @return bool
  643. */
  644. public function Quit($close_on_error = true) {
  645. $this->error = null; // so there is no confusion
  646. if(!$this->connected()) {
  647. $this->error = array(
  648. "error" => "Called Quit() without being connected");
  649. return false;
  650. }
  651. // send the quit command to the server
  652. fputs($this->smtp_conn,"quit" . $this->CRLF);
  653. // get any good-bye messages
  654. $byemsg = $this->get_lines();
  655. if($this->do_debug >= 2) {
  656. $this->edebug("SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />');
  657. }
  658. $rval = true;
  659. $e = null;
  660. $code = substr($byemsg,0,3);
  661. if($code != 221) {
  662. // use e as a tmp var cause Close will overwrite $this->error
  663. $e = array("error" => "SMTP server rejected quit command",
  664. "smtp_code" => $code,
  665. "smtp_rply" => substr($byemsg,4));
  666. $rval = false;
  667. if($this->do_debug >= 1) {
  668. $this->edebug("SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />');
  669. }
  670. }
  671. if(empty($e) || $close_on_error) {
  672. $this->Close();
  673. }
  674. return $rval;
  675. }
  676. /**
  677. * Sends the command RCPT to the SMTP server with the TO: argument of $to.
  678. * Returns true if the recipient was accepted false if it was rejected.
  679. *
  680. * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
  681. *
  682. * SMTP CODE SUCCESS: 250,251
  683. * SMTP CODE FAILURE: 550,551,552,553,450,451,452
  684. * SMTP CODE ERROR : 500,501,503,421
  685. * @access public
  686. * @param string $to
  687. * @return bool
  688. */
  689. public function Recipient($to) {
  690. $this->error = null; // so no confusion is caused
  691. if(!$this->connected()) {
  692. $this->error = array(
  693. "error" => "Called Recipient() without being connected");
  694. return false;
  695. }
  696. fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
  697. $rply = $this->get_lines();
  698. $code = substr($rply,0,3);
  699. if($this->do_debug >= 2) {
  700. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  701. }
  702. if($code != 250 && $code != 251) {
  703. $this->error =
  704. array("error" => "RCPT not accepted from server",
  705. "smtp_code" => $code,
  706. "smtp_msg" => substr($rply,4));
  707. if($this->do_debug >= 1) {
  708. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  709. }
  710. return false;
  711. }
  712. return true;
  713. }
  714. /**
  715. * Sends the RSET command to abort and transaction that is
  716. * currently in progress. Returns true if successful false
  717. * otherwise.
  718. *
  719. * Implements rfc 821: RSET <CRLF>
  720. *
  721. * SMTP CODE SUCCESS: 250
  722. * SMTP CODE ERROR : 500,501,504,421
  723. * @access public
  724. * @return bool
  725. */
  726. public function Reset() {
  727. $this->error = null; // so no confusion is caused
  728. if(!$this->connected()) {
  729. $this->error = array(
  730. "error" => "Called Reset() without being connected");
  731. return false;
  732. }
  733. fputs($this->smtp_conn,"RSET" . $this->CRLF);
  734. $rply = $this->get_lines();
  735. $code = substr($rply,0,3);
  736. if($this->do_debug >= 2) {
  737. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  738. }
  739. if($code != 250) {
  740. $this->error =
  741. array("error" => "RSET failed",
  742. "smtp_code" => $code,
  743. "smtp_msg" => substr($rply,4));
  744. if($this->do_debug >= 1) {
  745. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  746. }
  747. return false;
  748. }
  749. return true;
  750. }
  751. /**
  752. * Starts a mail transaction from the email address specified in
  753. * $from. Returns true if successful or false otherwise. If True
  754. * the mail transaction is started and then one or more Recipient
  755. * commands may be called followed by a Data command. This command
  756. * will send the message to the users terminal if they are logged
  757. * in and send them an email.
  758. *
  759. * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
  760. *
  761. * SMTP CODE SUCCESS: 250
  762. * SMTP CODE SUCCESS: 552,451,452
  763. * SMTP CODE SUCCESS: 500,501,502,421
  764. * @access public
  765. * @param string $from
  766. * @return bool
  767. */
  768. public function SendAndMail($from) {
  769. $this->error = null; // so no confusion is caused
  770. if(!$this->connected()) {
  771. $this->error = array(
  772. "error" => "Called SendAndMail() without being connected");
  773. return false;
  774. }
  775. fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
  776. $rply = $this->get_lines();
  777. $code = substr($rply,0,3);
  778. if($this->do_debug >= 2) {
  779. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  780. }
  781. if($code != 250) {
  782. $this->error =
  783. array("error" => "SAML not accepted from server",
  784. "smtp_code" => $code,
  785. "smtp_msg" => substr($rply,4));
  786. if($this->do_debug >= 1) {
  787. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  788. }
  789. return false;
  790. }
  791. return true;
  792. }
  793. /**
  794. * This is an optional command for SMTP that this class does not
  795. * support. This method is here to make the RFC821 Definition
  796. * complete for this class and __may__ be implimented in the future
  797. *
  798. * Implements from rfc 821: TURN <CRLF>
  799. *
  800. * SMTP CODE SUCCESS: 250
  801. * SMTP CODE FAILURE: 502
  802. * SMTP CODE ERROR : 500, 503
  803. * @access public
  804. * @return bool
  805. */
  806. public function Turn() {
  807. $this->error = array("error" => "This method, TURN, of the SMTP ".
  808. "is not implemented");
  809. if($this->do_debug >= 1) {
  810. $this->edebug("SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />');
  811. }
  812. return false;
  813. }
  814. /**
  815. * Get the current error
  816. * @access public
  817. * @return array
  818. */
  819. public function getError() {
  820. return $this->error;
  821. }
  822. /////////////////////////////////////////////////
  823. // INTERNAL FUNCTIONS
  824. /////////////////////////////////////////////////
  825. /**
  826. * Read in as many lines as possible
  827. * either before eof or socket timeout occurs on the operation.
  828. * With SMTP we can tell if we have more lines to read if the
  829. * 4th character is '-' symbol. If it is a space then we don't
  830. * need to read anything else.
  831. * @access private
  832. * @return string
  833. */
  834. private function get_lines() {
  835. $data = "";
  836. $endtime = 0;
  837. /* If for some reason the fp is bad, don't inf loop */
  838. if (!is_resource($this->smtp_conn)) {
  839. return $data;
  840. }
  841. stream_set_timeout($this->smtp_conn, $this->Timeout);
  842. if ($this->Timelimit > 0) {
  843. $endtime = time() + $this->Timelimit;
  844. }
  845. while(is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
  846. $str = @fgets($this->smtp_conn,515);
  847. if($this->do_debug >= 4) {
  848. $this->edebug("SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />');
  849. $this->edebug("SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />');
  850. }
  851. $data .= $str;
  852. if($this->do_debug >= 4) {
  853. $this->edebug("SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />');
  854. }
  855. // if 4th character is a space, we are done reading, break the loop
  856. if(substr($str,3,1) == " ") { break; }
  857. // Timed-out? Log and break
  858. $info = stream_get_meta_data($this->smtp_conn);
  859. if ($info['timed_out']) {
  860. if($this->do_debug >= 4) {
  861. $this->edebug("SMTP -> get_lines(): timed-out (" . $this->Timeout . " seconds) <br />");
  862. }
  863. break;
  864. }
  865. // Now check if reads took too long
  866. if ($endtime) {
  867. if (time() > $endtime) {
  868. if($this->do_debug >= 4) {
  869. $this->edebug("SMTP -> get_lines(): timelimit reached (" . $this->Timelimit . " seconds) <br />");
  870. }
  871. break;
  872. }
  873. }
  874. }
  875. return $data;
  876. }
  877. }
  878. ?>