smtp.transport.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. <?php
  2. /**
  3. * @file
  4. * SMTP mail transport class for the smtp module,based on code of the phpmailer
  5. * library, customized and relicensed to GPLv2
  6. *
  7. */
  8. /*~ class.smtp.php
  9. Original release information:
  10. .---------------------------------------------------------------------------.
  11. | Software: PHPMailer - PHP email class |
  12. | Version: 5.1 |
  13. | Contact: via sourceforge.net support pages (also www.codeworxtech.com) |
  14. | Info: http://phpmailer.sourceforge.net |
  15. | Support: http://sourceforge.net/projects/phpmailer/ |
  16. | ------------------------------------------------------------------------- |
  17. | Admin: Andy Prevost (project admininistrator) |
  18. | Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
  19. | : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
  20. | Founder: Brent R. Matzelle (original founder) |
  21. | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
  22. | Copyright (c) 2001-2003, Brent R. Matzelle |
  23. | ------------------------------------------------------------------------- |
  24. | License: Distributed under the Lesser General Public License (LGPL) |
  25. | http://www.gnu.org/copyleft/lesser.html |
  26. | This program is distributed in the hope that it will be useful - WITHOUT |
  27. | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
  28. | FITNESS FOR A PARTICULAR PURPOSE. |
  29. | ------------------------------------------------------------------------- |
  30. | We offer a number of paid services (www.codeworxtech.com): |
  31. | - Web Hosting on highly optimized fast and secure servers |
  32. | - Technology Consulting |
  33. | - Oursourcing (highly qualified programmers and graphic designers) |
  34. '---------------------------------------------------------------------------'
  35. */
  36. /**
  37. * PHPMailer - PHP SMTP email transport class
  38. * NOTE: Designed for use with PHP version 5 and up
  39. * @package PHPMailer
  40. * @author Andy Prevost
  41. * @author Marcus Bointon
  42. * @copyright 2004 - 2008 Andy Prevost
  43. */
  44. /**
  45. * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
  46. * commands except TURN which will always return a not implemented
  47. * error. SMTP also provides some utility methods for sending mail
  48. * to an SMTP server.
  49. * original author: Chris Ryan
  50. */
  51. class SMTP {
  52. /**
  53. * SMTP server port
  54. * @var int
  55. */
  56. public $SMTP_PORT = 25;
  57. /**
  58. * SMTP reply line ending
  59. * @var string
  60. */
  61. public $CRLF = "\r\n";
  62. /**
  63. * Sets whether debugging is turned on
  64. * @var bool
  65. */
  66. public $do_debug; // the level of debug to perform
  67. /**
  68. * Sets VERP use on/off (default is off)
  69. * @var bool
  70. */
  71. public $do_verp = FALSE;
  72. /////////////////////////////////////////////////
  73. // PROPERTIES, PRIVATE AND PROTECTED
  74. /////////////////////////////////////////////////
  75. private $smtp_conn; // the socket to the server
  76. private $error; // error if any on the last call
  77. private $helo_rply; // the reply the server sent to us for HELO
  78. /**
  79. * Initialize the class so that the data is in a known state.
  80. * @access public
  81. * @return void
  82. */
  83. public function __construct() {
  84. $this->smtp_conn = 0;
  85. $this->error = NULL;
  86. $this->helo_rply = NULL;
  87. $this->do_debug = 0;
  88. }
  89. /////////////////////////////////////////////////
  90. // CONNECTION FUNCTIONS
  91. /////////////////////////////////////////////////
  92. /**
  93. * Connect to the server specified on the port specified.
  94. * If the port is not specified use the default SMTP_PORT.
  95. * If tval is specified then a connection will try and be
  96. * established with the server for that number of seconds.
  97. * If tval is not specified the default is 30 seconds to
  98. * try on the connection.
  99. *
  100. * SMTP CODE SUCCESS: 220
  101. * SMTP CODE FAILURE: 421
  102. * @access public
  103. * @return bool
  104. */
  105. public function Connect($host, $port = 0, $tval = 30) {
  106. // set the error val to NULL so there is no confusion
  107. $this->error = NULL;
  108. // make sure we are __not__ connected
  109. if ($this->connected()) {
  110. // already connected, generate error
  111. $this->error = array("error" => "Already connected to a server");
  112. return FALSE;
  113. }
  114. if (empty($port)) {
  115. $port = $this->SMTP_PORT;
  116. }
  117. // connect to the smtp server
  118. $this->smtp_conn = @fsockopen($host, // the host of the server
  119. $port, // the port to use
  120. $errno, // error number if any
  121. $errstr, // error message if any
  122. $tval); // give up after ? secs
  123. // verify we connected properly
  124. if (empty($this->smtp_conn)) {
  125. $this->error = array("error" => "Failed to connect to server",
  126. "errno" => $errno,
  127. "errstr" => $errstr);
  128. if ($this->do_debug >= 1) {
  129. drupal_set_message(t("SMTP -> ERROR: @error: @errstr (@errno)", array("@error" => $this->error["error"], "@errstr" => $errstr, "@errno" => $errno)));
  130. }
  131. return FALSE;
  132. }
  133. // SMTP server can take longer to respond, give longer timeout for first read
  134. // Windows does not have support for this timeout function
  135. if (substr(PHP_OS, 0, 3) != "WIN")
  136. socket_set_timeout($this->smtp_conn, $tval, 0);
  137. // get any announcement
  138. $announce = $this->get_lines();
  139. if ($this->do_debug >= 2) {
  140. drupal_set_message(t("SMTP -> FROM SERVER: @announce", array("@announce" => $announce)));
  141. }
  142. return TRUE;
  143. }
  144. /**
  145. * Initiate a TLS communication with the server.
  146. *
  147. * SMTP CODE 220 Ready to start TLS
  148. * SMTP CODE 501 Syntax error (no parameters allowed)
  149. * SMTP CODE 454 TLS not available due to temporary reason
  150. * @access public
  151. * @return bool success
  152. */
  153. public function StartTLS() {
  154. $this->error = NULL; # to avoid confusion
  155. if (!$this->connected()) {
  156. $this->error = array("error" => "Called StartTLS() without being connected");
  157. return FALSE;
  158. }
  159. fputs($this->smtp_conn, "STARTTLS" . $this->CRLF);
  160. $rply = $this->get_lines();
  161. $code = substr($rply, 0, 3);
  162. if ($this->do_debug >= 2) {
  163. drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
  164. }
  165. if ($code != 220) {
  166. $this->error =
  167. array("error" => "STARTTLS not accepted from server",
  168. "smtp_code" => $code,
  169. "smtp_msg" => substr($rply, 4));
  170. if ($this->do_debug >= 1) {
  171. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  172. }
  173. return FALSE;
  174. }
  175. // Begin encrypted connection
  176. if (!stream_socket_enable_crypto($this->smtp_conn, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
  177. return FALSE;
  178. }
  179. return TRUE;
  180. }
  181. /**
  182. * Performs SMTP authentication. Must be run after running the
  183. * Hello() method. Returns TRUE if successfully authenticated.
  184. * @access public
  185. * @return bool
  186. */
  187. public function Authenticate($username, $password) {
  188. // Start authentication
  189. fputs($this->smtp_conn, "AUTH LOGIN" . $this->CRLF);
  190. $rply = $this->get_lines();
  191. $code = substr($rply, 0, 3);
  192. if ($code != 334) {
  193. $this->error =
  194. array("error" => "AUTH not accepted from server",
  195. "smtp_code" => $code,
  196. "smtp_msg" => substr($rply, 4));
  197. if ($this->do_debug >= 1) {
  198. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  199. }
  200. return FALSE;
  201. }
  202. // Send encoded username
  203. fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
  204. $rply = $this->get_lines();
  205. $code = substr($rply, 0, 3);
  206. if ($code != 334) {
  207. $this->error =
  208. array("error" => "Username not accepted from server",
  209. "smtp_code" => $code,
  210. "smtp_msg" => substr($rply, 4));
  211. if ($this->do_debug >= 1) {
  212. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  213. }
  214. return FALSE;
  215. }
  216. // Send encoded password
  217. fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
  218. $rply = $this->get_lines();
  219. $code = substr($rply, 0, 3);
  220. if ($code != 235) {
  221. $this->error =
  222. array("error" => "Password not accepted from server",
  223. "smtp_code" => $code,
  224. "smtp_msg" => substr($rply, 4));
  225. if ($this->do_debug >= 1) {
  226. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  227. }
  228. return FALSE;
  229. }
  230. return TRUE;
  231. }
  232. /**
  233. * Returns TRUE if connected to a server otherwise FALSE
  234. * @access public
  235. * @return bool
  236. */
  237. public function Connected() {
  238. if (!empty($this->smtp_conn)) {
  239. $sock_status = socket_get_status($this->smtp_conn);
  240. if ($sock_status["eof"]) {
  241. // the socket is valid but we are not connected
  242. if ($this->do_debug >= 1) {
  243. drupal_set_message(t("SMTP -> NOTICE: EOF caught while checking if connected"));
  244. }
  245. $this->Close();
  246. return FALSE;
  247. }
  248. return TRUE; // everything looks good
  249. }
  250. return FALSE;
  251. }
  252. /**
  253. * Closes the socket and cleans up the state of the class.
  254. * It is not considered good to use this function without
  255. * first trying to use QUIT.
  256. * @access public
  257. * @return void
  258. */
  259. public function Close() {
  260. $this->error = NULL; // so there is no confusion
  261. $this->helo_rply = NULL;
  262. if (!empty($this->smtp_conn)) {
  263. // close the connection and cleanup
  264. fclose($this->smtp_conn);
  265. $this->smtp_conn = 0;
  266. }
  267. }
  268. /////////////////////////////////////////////////
  269. // SMTP COMMANDS
  270. /////////////////////////////////////////////////
  271. /**
  272. * Issues a data command and sends the msg_data to the server
  273. * finializing the mail transaction. $msg_data is the message
  274. * that is to be send with the headers. Each header needs to be
  275. * on a single line followed by a <CRLF> with the message headers
  276. * and the message body being separated by and additional <CRLF>.
  277. *
  278. * Implements rfc 821: DATA <CRLF>
  279. *
  280. * SMTP CODE INTERMEDIATE: 354
  281. * [data]
  282. * <CRLF>.<CRLF>
  283. * SMTP CODE SUCCESS: 250
  284. * SMTP CODE FAILURE: 552,554,451,452
  285. * SMTP CODE FAILURE: 451,554
  286. * SMTP CODE ERROR : 500,501,503,421
  287. * @access public
  288. * @return bool
  289. */
  290. public function Data($msg_data) {
  291. $this->error = NULL; // so no confusion is caused
  292. if (!$this->connected()) {
  293. $this->error = array(
  294. "error" => "Called Data() without being connected");
  295. return FALSE;
  296. }
  297. fputs($this->smtp_conn, "DATA" . $this->CRLF);
  298. $rply = $this->get_lines();
  299. $code = substr($rply, 0, 3);
  300. if ($this->do_debug >= 2) {
  301. drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
  302. }
  303. if ($code != 354) {
  304. $this->error =
  305. array("error" => "DATA command not accepted from server",
  306. "smtp_code" => $code,
  307. "smtp_msg" => substr($rply, 4));
  308. if ($this->do_debug >= 1) {
  309. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  310. }
  311. return FALSE;
  312. }
  313. /* the server is ready to accept data!
  314. * according to rfc 821 we should not send more than 1000
  315. * including the CRLF
  316. * characters on a single line so we will break the data up
  317. * into lines by \r and/or \n then if needed we will break
  318. * each of those into smaller lines to fit within the limit.
  319. * in addition we will be looking for lines that start with
  320. * a period '.' and append and additional period '.' to that
  321. * line. NOTE: this does not count towards limit.
  322. */
  323. // normalize the line breaks so we know the explode works
  324. $msg_data = str_replace("\r\n", "\n", $msg_data);
  325. $msg_data = str_replace("\r", "\n", $msg_data);
  326. $lines = explode("\n", $msg_data);
  327. /* we need to find a good way to determine is headers are
  328. * in the msg_data or if it is a straight msg body
  329. * currently I am assuming rfc 822 definitions of msg headers
  330. * and if the first field of the first line (':' sperated)
  331. * does not contain a space then it _should_ be a header
  332. * and we can process all lines before a blank "" line as
  333. * headers.
  334. */
  335. $field = substr($lines[0], 0, strpos($lines[0], ":"));
  336. $in_headers = FALSE;
  337. if (!empty($field) && !strstr($field, " ")) {
  338. $in_headers = TRUE;
  339. }
  340. $max_line_length = 998; // used below; set here for ease in change
  341. while (list(, $line) = @each($lines)) {
  342. $lines_out = NULL;
  343. if ($line == "" && $in_headers) {
  344. $in_headers = FALSE;
  345. }
  346. // ok we need to break this line up into several smaller lines
  347. while (strlen($line) > $max_line_length) {
  348. $pos = strrpos(substr($line, 0, $max_line_length), " ");
  349. // Patch to fix DOS attack
  350. if (!$pos) {
  351. $pos = $max_line_length - 1;
  352. $lines_out[] = substr($line, 0, $pos);
  353. $line = substr($line, $pos);
  354. }
  355. else {
  356. $lines_out[] = substr($line, 0, $pos);
  357. $line = substr($line, $pos + 1);
  358. }
  359. /* if processing headers add a LWSP-char to the front of new line
  360. * rfc 822 on long msg headers
  361. */
  362. if ($in_headers) {
  363. $line = "\t" . $line;
  364. }
  365. }
  366. $lines_out[] = $line;
  367. // send the lines to the server
  368. while (list(, $line_out) = @each($lines_out)) {
  369. if (strlen($line_out) > 0) {
  370. if (substr($line_out, 0, 1) == ".") {
  371. $line_out = "." . $line_out;
  372. }
  373. }
  374. fputs($this->smtp_conn, $line_out . $this->CRLF);
  375. }
  376. }
  377. // message data has been sent
  378. fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
  379. $rply = $this->get_lines();
  380. $code = substr($rply, 0, 3);
  381. if ($this->do_debug >= 2) {
  382. drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
  383. }
  384. if ($code != 250) {
  385. $this->error =
  386. array("error" => "DATA not accepted from server",
  387. "smtp_code" => $code,
  388. "smtp_msg" => substr($rply, 4));
  389. if ($this->do_debug >= 1) {
  390. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  391. }
  392. return FALSE;
  393. }
  394. return TRUE;
  395. }
  396. /**
  397. * Sends the HELO command to the smtp server.
  398. * This makes sure that we and the server are in
  399. * the same known state.
  400. *
  401. * Implements from rfc 821: HELO <SP> <domain> <CRLF>
  402. *
  403. * SMTP CODE SUCCESS: 250
  404. * SMTP CODE ERROR : 500, 501, 504, 421
  405. * @access public
  406. * @return bool
  407. */
  408. public function Hello($host = '') {
  409. $this->error = NULL; // so no confusion is caused
  410. if (!$this->connected()) {
  411. $this->error = array(
  412. "error" => "Called Hello() without being connected");
  413. return FALSE;
  414. }
  415. // if hostname for HELO was not specified send default
  416. if (empty($host)) {
  417. // determine appropriate default to send to server
  418. $host = "localhost";
  419. }
  420. // Send extended hello first (RFC 2821)
  421. if (!$this->SendHello("EHLO", $host)) {
  422. if (!$this->SendHello("HELO", $host)) {
  423. return FALSE;
  424. }
  425. }
  426. return TRUE;
  427. }
  428. /**
  429. * Sends a HELO/EHLO command.
  430. * @access private
  431. * @return bool
  432. */
  433. private function SendHello($hello, $host) {
  434. fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
  435. $rply = $this->get_lines();
  436. $code = substr($rply, 0, 3);
  437. if ($this->do_debug >= 2) {
  438. drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
  439. }
  440. if ($code != 250) {
  441. $this->error =
  442. array("error" => $hello . " not accepted from server",
  443. "smtp_code" => $code,
  444. "smtp_msg" => substr($rply, 4));
  445. if ($this->do_debug >= 1) {
  446. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  447. }
  448. return FALSE;
  449. }
  450. $this->helo_rply = $rply;
  451. return TRUE;
  452. }
  453. /**
  454. * Starts a mail transaction from the email address specified in
  455. * $from. Returns TRUE if successful or FALSE otherwise. If True
  456. * the mail transaction is started and then one or more Recipient
  457. * commands may be called followed by a Data command.
  458. *
  459. * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
  460. *
  461. * SMTP CODE SUCCESS: 250
  462. * SMTP CODE SUCCESS: 552,451,452
  463. * SMTP CODE SUCCESS: 500,501,421
  464. * @access public
  465. * @return bool
  466. */
  467. public function Mail($from) {
  468. $this->error = NULL; // so no confusion is caused
  469. if (!$this->connected()) {
  470. $this->error = array(
  471. "error" => "Called Mail() without being connected");
  472. return FALSE;
  473. }
  474. $useVerp = ($this->do_verp ? "XVERP" : "");
  475. fputs($this->smtp_conn, "MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
  476. $rply = $this->get_lines();
  477. $code = substr($rply, 0, 3);
  478. if ($this->do_debug >= 2) {
  479. drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
  480. }
  481. if ($code != 250) {
  482. $this->error =
  483. array("error" => "MAIL not accepted from server",
  484. "smtp_code" => $code,
  485. "smtp_msg" => substr($rply, 4));
  486. if ($this->do_debug >= 1) {
  487. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  488. }
  489. return FALSE;
  490. }
  491. return TRUE;
  492. }
  493. /**
  494. * Sends the quit command to the server and then closes the socket
  495. * if there is no error or the $close_on_error argument is TRUE.
  496. *
  497. * Implements from rfc 821: QUIT <CRLF>
  498. *
  499. * SMTP CODE SUCCESS: 221
  500. * SMTP CODE ERROR : 500
  501. * @access public
  502. * @return bool
  503. */
  504. public function Quit($close_on_error = TRUE) {
  505. $this->error = NULL; // so there is no confusion
  506. if (!$this->connected()) {
  507. $this->error = array(
  508. "error" => "Called Quit() without being connected");
  509. return FALSE;
  510. }
  511. // send the quit command to the server
  512. fputs($this->smtp_conn, "quit" . $this->CRLF);
  513. // get any good-bye messages
  514. $byemsg = $this->get_lines();
  515. if ($this->do_debug >= 2) {
  516. drupal_set_message(t("SMTP -> FROM SERVER: @byemsg", array("@rply" => $byemsg)));
  517. }
  518. $rval = TRUE;
  519. $e = NULL;
  520. $code = substr($byemsg, 0, 3);
  521. if ($code != 221) {
  522. // use e as a tmp var cause Close will overwrite $this->error
  523. $e = array("error" => "SMTP server rejected quit command",
  524. "smtp_code" => $code,
  525. "smtp_rply" => substr($byemsg, 4));
  526. $rval = FALSE;
  527. if ($this->do_debug >= 1) {
  528. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  529. }
  530. }
  531. if (empty($e) || $close_on_error) {
  532. $this->Close();
  533. }
  534. return $rval;
  535. }
  536. /**
  537. * Sends the command RCPT to the SMTP server with the TO: argument of $to.
  538. * Returns TRUE if the recipient was accepted FALSE if it was rejected.
  539. *
  540. * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
  541. *
  542. * SMTP CODE SUCCESS: 250,251
  543. * SMTP CODE FAILURE: 550,551,552,553,450,451,452
  544. * SMTP CODE ERROR : 500,501,503,421
  545. * @access public
  546. * @return bool
  547. */
  548. public function Recipient($to) {
  549. $this->error = NULL; // so no confusion is caused
  550. if (!$this->connected()) {
  551. $this->error = array(
  552. "error" => "Called Recipient() without being connected");
  553. return FALSE;
  554. }
  555. fputs($this->smtp_conn, "RCPT TO:<" . $to . ">" . $this->CRLF);
  556. $rply = $this->get_lines();
  557. $code = substr($rply, 0, 3);
  558. if ($this->do_debug >= 2) {
  559. drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
  560. }
  561. if ($code != 250 && $code != 251) {
  562. $this->error =
  563. array("error" => "RCPT not accepted from server",
  564. "smtp_code" => $code,
  565. "smtp_msg" => substr($rply, 4));
  566. if ($this->do_debug >= 1) {
  567. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  568. }
  569. return FALSE;
  570. }
  571. return TRUE;
  572. }
  573. /**
  574. * Sends the RSET command to abort and transaction that is
  575. * currently in progress. Returns TRUE if successful FALSE
  576. * otherwise.
  577. *
  578. * Implements rfc 821: RSET <CRLF>
  579. *
  580. * SMTP CODE SUCCESS: 250
  581. * SMTP CODE ERROR : 500,501,504,421
  582. * @access public
  583. * @return bool
  584. */
  585. public function Reset() {
  586. $this->error = NULL; // so no confusion is caused
  587. if (!$this->connected()) {
  588. $this->error = array(
  589. "error" => "Called Reset() without being connected");
  590. return FALSE;
  591. }
  592. fputs($this->smtp_conn, "RSET" . $this->CRLF);
  593. $rply = $this->get_lines();
  594. $code = substr($rply, 0, 3);
  595. if ($this->do_debug >= 2) {
  596. drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
  597. }
  598. if ($code != 250) {
  599. $this->error =
  600. array("error" => "RSET failed",
  601. "smtp_code" => $code,
  602. "smtp_msg" => substr($rply, 4));
  603. if ($this->do_debug >= 1) {
  604. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  605. }
  606. return FALSE;
  607. }
  608. return TRUE;
  609. }
  610. /**
  611. * Starts a mail transaction from the email address specified in
  612. * $from. Returns TRUE if successful or FALSE otherwise. If True
  613. * the mail transaction is started and then one or more Recipient
  614. * commands may be called followed by a Data command. This command
  615. * will send the message to the users terminal if they are logged
  616. * in and send them an email.
  617. *
  618. * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
  619. *
  620. * SMTP CODE SUCCESS: 250
  621. * SMTP CODE SUCCESS: 552,451,452
  622. * SMTP CODE SUCCESS: 500,501,502,421
  623. * @access public
  624. * @return bool
  625. */
  626. public function SendAndMail($from) {
  627. $this->error = NULL; // so no confusion is caused
  628. if (!$this->connected()) {
  629. $this->error = array("error" => "Called SendAndMail() without being connected");
  630. return FALSE;
  631. }
  632. fputs($this->smtp_conn, "SAML FROM:" . $from . $this->CRLF);
  633. $rply = $this->get_lines();
  634. $code = substr($rply, 0, 3);
  635. if ($this->do_debug >= 2) {
  636. drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
  637. }
  638. if ($code != 250) {
  639. $this->error =
  640. array("error" => "SAML not accepted from server",
  641. "smtp_code" => $code,
  642. "smtp_msg" => substr($rply, 4));
  643. if ($this->do_debug >= 1) {
  644. drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
  645. }
  646. return FALSE;
  647. }
  648. return TRUE;
  649. }
  650. /**
  651. * This is an optional command for SMTP that this class does not
  652. * support. This method is here to make the RFC821 Definition
  653. * complete for this class and __may__ be implemented in the future
  654. *
  655. * Implements from rfc 821: TURN <CRLF>
  656. *
  657. * SMTP CODE SUCCESS: 250
  658. * SMTP CODE FAILURE: 502
  659. * SMTP CODE ERROR : 500, 503
  660. * @access public
  661. * @return bool
  662. */
  663. public function Turn() {
  664. $this->error = array("error" => "This method, TURN, of the SMTP is not implemented");
  665. if ($this->do_debug >= 1) {
  666. drupal_set_message(t("SMTP -> NOTICE: @error", array("@error" => $this->error["error"])));
  667. }
  668. return FALSE;
  669. }
  670. /**
  671. * Get the current error
  672. * @access public
  673. * @return array
  674. */
  675. public function getError() {
  676. return $this->error;
  677. }
  678. /////////////////////////////////////////////////
  679. // INTERNAL FUNCTIONS
  680. /////////////////////////////////////////////////
  681. /**
  682. * Read in as many lines as possible
  683. * either before eof or socket timeout occurs on the operation.
  684. * With SMTP we can tell if we have more lines to read if the
  685. * 4th character is '-' symbol. If it is a space then we don't
  686. * need to read anything else.
  687. * @access private
  688. * @return string
  689. */
  690. private function get_lines() {
  691. $data = "";
  692. while ($str = @fgets($this->smtp_conn, 515)) {
  693. if ($this->do_debug >= 4) {
  694. drupal_set_message(t("SMTP -> get_lines(): \$data was \"@data\"", array("@data" => $data)));
  695. drupal_set_message(t("SMTP -> get_lines(): \$str is \"@str\"", array("@str" => $str)));
  696. }
  697. $data .= $str;
  698. if ($this->do_debug >= 4) {
  699. drupal_set_message(t("SMTP -> get_lines(): \$data was \"@data\"", array("@data" => $data)));
  700. }
  701. // if 4th character is a space, we are done reading, break the loop
  702. if (substr($str, 3, 1) == " ") {
  703. break;
  704. }
  705. }
  706. return $data;
  707. }
  708. }