Cheetah
All Classes Namespaces Files Functions Variables Pages
class.smtp.php
Go to the documentation of this file.
1 <?php
27 class SMTP
28 {
33  const VERSION = '5.2.25';
34 
39  const CRLF = "\r\n";
40 
45  const DEFAULT_SMTP_PORT = 25;
46 
51  const MAX_LINE_LENGTH = 998;
52 
56  const DEBUG_OFF = 0;
57 
61  const DEBUG_CLIENT = 1;
62 
66  const DEBUG_SERVER = 2;
67 
71  const DEBUG_CONNECTION = 3;
72 
76  const DEBUG_LOWLEVEL = 4;
77 
84  public $Version = '5.2.25';
85 
92  public $SMTP_PORT = 25;
93 
100  public $CRLF = "\r\n";
101 
113 
127  public $Debugoutput = 'echo';
128 
135  public $do_verp = false;
136 
144  public $Timeout = 300;
145 
151  public $Timelimit = 300;
152 
157  protected $smtp_transaction_id_patterns = array(
158  'exim' => '/[0-9]{3} OK id=(.*)/',
159  'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/',
160  'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
161  );
162 
168 
173  protected $smtp_conn;
174 
179  protected $error = array(
180  'error' => '',
181  'detail' => '',
182  'smtp_code' => '',
183  'smtp_code_ex' => ''
184  );
185 
191  protected $helo_rply = null;
192 
202  protected $server_caps = null;
203 
208  protected $last_reply = '';
209 
218  protected function edebug($str, $level = 0)
219  {
220  if ($level > $this->do_debug) {
221  return;
222  }
223  //Avoid clash with built-in function names
224  if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
225  call_user_func($this->Debugoutput, $str, $level);
226  return;
227  }
228  switch ($this->Debugoutput) {
229  case 'error_log':
230  //Don't output, just log
231  error_log($str);
232  break;
233  case 'html':
234  //Cleans up output a bit for a better looking, HTML-safe output
235  echo gmdate('Y-m-d H:i:s') . ' ' . htmlentities(
236  preg_replace('/[\r\n]+/', '', $str),
237  ENT_QUOTES,
238  'UTF-8'
239  ) . "<br>\n";
240  break;
241  case 'echo':
242  default:
243  //Normalize line breaks
244  $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
245  echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
246  "\n",
247  "\n \t ",
248  trim($str)
249  ) . "\n";
250  }
251  }
252 
262  public function connect($host, $port = null, $timeout = 30, $options = array())
263  {
264  static $streamok;
265  //This is enabled by default since 5.0.0 but some providers disable it
266  //Check this once and cache the result
267  if (is_null($streamok)) {
268  $streamok = function_exists('stream_socket_client');
269  }
270  // Clear errors to avoid confusion
271  $this->setError('');
272  // Make sure we are __not__ connected
273  if ($this->connected()) {
274  // Already connected, generate error
275  $this->setError('Already connected to a server');
276  return false;
277  }
278  if (empty($port)) {
279  $port = self::DEFAULT_SMTP_PORT;
280  }
281  // Connect to the SMTP server
282  $this->edebug(
283  "Connection: opening to $host:$port, timeout=$timeout, options=" .
284  var_export($options, true),
285  self::DEBUG_CONNECTION
286  );
287  $errno = 0;
288  $errstr = '';
289  if ($streamok) {
290  $socket_context = stream_context_create($options);
291  set_error_handler(array($this, 'errorHandler'));
292  $this->smtp_conn = stream_socket_client(
293  $host . ":" . $port,
294  $errno,
295  $errstr,
296  $timeout,
297  STREAM_CLIENT_CONNECT,
298  $socket_context
299  );
300  restore_error_handler();
301  } else {
302  //Fall back to fsockopen which should work in more places, but is missing some features
303  $this->edebug(
304  "Connection: stream_socket_client not available, falling back to fsockopen",
305  self::DEBUG_CONNECTION
306  );
307  set_error_handler(array($this, 'errorHandler'));
308  $this->smtp_conn = fsockopen(
309  $host,
310  $port,
311  $errno,
312  $errstr,
313  $timeout
314  );
315  restore_error_handler();
316  }
317  // Verify we connected properly
318  if (!is_resource($this->smtp_conn)) {
319  $this->setError(
320  'Failed to connect to server',
321  $errno,
322  $errstr
323  );
324  $this->edebug(
325  'SMTP ERROR: ' . $this->error['error']
326  . ": $errstr ($errno)",
327  self::DEBUG_CLIENT
328  );
329  return false;
330  }
331  $this->edebug('Connection: opened', self::DEBUG_CONNECTION);
332  // SMTP server can take longer to respond, give longer timeout for first read
333  // Windows does not have support for this timeout function
334  if (substr(PHP_OS, 0, 3) != 'WIN') {
335  $max = ini_get('max_execution_time');
336  // Don't bother if unlimited
337  if ($max != 0 && $timeout > $max) {
338  @set_time_limit($timeout);
339  }
340  stream_set_timeout($this->smtp_conn, $timeout, 0);
341  }
342  // Get any announcement
343  $announce = $this->get_lines();
344  $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
345  return true;
346  }
347 
353  public function startTLS()
354  {
355  if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
356  return false;
357  }
358 
359  //Allow the best TLS version(s) we can
360  $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
361 
362  //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
363  //so add them back in manually if we can
364  if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
365  $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
366  $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
367  }
368 
369  // Begin encrypted connection
370  set_error_handler(array($this, 'errorHandler'));
371  $crypto_ok = stream_socket_enable_crypto(
372  $this->smtp_conn,
373  true,
374  $crypto_method
375  );
376  restore_error_handler();
377  return $crypto_ok;
378  }
379 
392  public function authenticate(
393  $username,
394  $password,
395  $authtype = null,
396  $realm = '',
397  $workstation = '',
398  $OAuth = null
399  ) {
400  if (!$this->server_caps) {
401  $this->setError('Authentication is not allowed before HELO/EHLO');
402  return false;
403  }
404 
405  if (array_key_exists('EHLO', $this->server_caps)) {
406  // SMTP extensions are available; try to find a proper authentication method
407  if (!array_key_exists('AUTH', $this->server_caps)) {
408  $this->setError('Authentication is not allowed at this stage');
409  // 'at this stage' means that auth may be allowed after the stage changes
410  // e.g. after STARTTLS
411  return false;
412  }
413 
414  self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL);
415  self::edebug(
416  'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']),
417  self::DEBUG_LOWLEVEL
418  );
419 
420  if (empty($authtype)) {
421  foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN', 'NTLM', 'XOAUTH2') as $method) {
422  if (in_array($method, $this->server_caps['AUTH'])) {
423  $authtype = $method;
424  break;
425  }
426  }
427  if (empty($authtype)) {
428  $this->setError('No supported authentication methods found');
429  return false;
430  }
431  self::edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL);
432  }
433 
434  if (!in_array($authtype, $this->server_caps['AUTH'])) {
435  $this->setError("The requested authentication method \"$authtype\" is not supported by the server");
436  return false;
437  }
438  } elseif (empty($authtype)) {
439  $authtype = 'LOGIN';
440  }
441  switch ($authtype) {
442  case 'PLAIN':
443  // Start authentication
444  if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
445  return false;
446  }
447  // Send encoded username and password
448  if (!$this->sendCommand(
449  'User & Password',
450  base64_encode("\0" . $username . "\0" . $password),
451  235
452  )
453  ) {
454  return false;
455  }
456  break;
457  case 'LOGIN':
458  // Start authentication
459  if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
460  return false;
461  }
462  if (!$this->sendCommand("Username", base64_encode($username), 334)) {
463  return false;
464  }
465  if (!$this->sendCommand("Password", base64_encode($password), 235)) {
466  return false;
467  }
468  break;
469  case 'XOAUTH2':
470  //If the OAuth Instance is not set. Can be a case when PHPMailer is used
471  //instead of PHPMailerOAuth
472  if (is_null($OAuth)) {
473  return false;
474  }
475  $oauth = $OAuth->getOauth64();
476 
477  // Start authentication
478  if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
479  return false;
480  }
481  break;
482  case 'NTLM':
483  /*
484  * ntlm_sasl_client.php
485  * Bundled with Permission
486  *
487  * How to telnet in windows:
488  * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
489  * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
490  */
491  require_once 'extras/ntlm_sasl_client.php';
492  $temp = new stdClass;
493  $ntlm_client = new ntlm_sasl_client_class;
494  //Check that functions are available
495  if (!$ntlm_client->initialize($temp)) {
496  $this->setError($temp->error);
497  $this->edebug(
498  'You need to enable some modules in your php.ini file: '
499  . $this->error['error'],
500  self::DEBUG_CLIENT
501  );
502  return false;
503  }
504  //msg1
505  $msg1 = $ntlm_client->typeMsg1($realm, $workstation); //msg1
506 
507  if (!$this->sendCommand(
508  'AUTH NTLM',
509  'AUTH NTLM ' . base64_encode($msg1),
510  334
511  )
512  ) {
513  return false;
514  }
515  //Though 0 based, there is a white space after the 3 digit number
516  //msg2
517  $challenge = substr($this->last_reply, 3);
518  $challenge = base64_decode($challenge);
519  $ntlm_res = $ntlm_client->NTLMResponse(
520  substr($challenge, 24, 8),
521  $password
522  );
523  //msg3
524  $msg3 = $ntlm_client->typeMsg3(
525  $ntlm_res,
526  $username,
527  $realm,
528  $workstation
529  );
530  // send encoded username
531  return $this->sendCommand('Username', base64_encode($msg3), 235);
532  case 'CRAM-MD5':
533  // Start authentication
534  if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
535  return false;
536  }
537  // Get the challenge
538  $challenge = base64_decode(substr($this->last_reply, 4));
539 
540  // Build the response
541  $response = $username . ' ' . $this->hmac($challenge, $password);
542 
543  // send encoded credentials
544  return $this->sendCommand('Username', base64_encode($response), 235);
545  default:
546  $this->setError("Authentication method \"$authtype\" is not supported");
547  return false;
548  }
549  return true;
550  }
551 
561  protected function hmac($data, $key)
562  {
563  if (function_exists('hash_hmac')) {
564  return hash_hmac('md5', $data, $key);
565  }
566 
567  // The following borrowed from
568  // http://php.net/manual/en/function.mhash.php#27225
569 
570  // RFC 2104 HMAC implementation for php.
571  // Creates an md5 HMAC.
572  // Eliminates the need to install mhash to compute a HMAC
573  // by Lance Rushing
574 
575  $bytelen = 64; // byte length for md5
576  if (strlen($key) > $bytelen) {
577  $key = pack('H*', md5($key));
578  }
579  $key = str_pad($key, $bytelen, chr(0x00));
580  $ipad = str_pad('', $bytelen, chr(0x36));
581  $opad = str_pad('', $bytelen, chr(0x5c));
582  $k_ipad = $key ^ $ipad;
583  $k_opad = $key ^ $opad;
584 
585  return md5($k_opad . pack('H*', md5($k_ipad . $data)));
586  }
587 
593  public function connected()
594  {
595  if (is_resource($this->smtp_conn)) {
596  $sock_status = stream_get_meta_data($this->smtp_conn);
597  if ($sock_status['eof']) {
598  // The socket is valid but we are not connected
599  $this->edebug(
600  'SMTP NOTICE: EOF caught while checking if connected',
601  self::DEBUG_CLIENT
602  );
603  $this->close();
604  return false;
605  }
606  return true; // everything looks good
607  }
608  return false;
609  }
610 
618  public function close()
619  {
620  $this->setError('');
621  $this->server_caps = null;
622  $this->helo_rply = null;
623  if (is_resource($this->smtp_conn)) {
624  // close the connection and cleanup
625  fclose($this->smtp_conn);
626  $this->smtp_conn = null; //Makes for cleaner serialization
627  $this->edebug('Connection: closed', self::DEBUG_CONNECTION);
628  }
629  }
630 
643  public function data($msg_data)
644  {
645  //This will use the standard timelimit
646  if (!$this->sendCommand('DATA', 'DATA', 354)) {
647  return false;
648  }
649 
650  /* The server is ready to accept data!
651  * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF)
652  * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into
653  * smaller lines to fit within the limit.
654  * We will also look for lines that start with a '.' and prepend an additional '.'.
655  * NOTE: this does not count towards line-length limit.
656  */
657 
658  // Normalize line breaks before exploding
659  $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data));
660 
661  /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
662  * of the first line (':' separated) does not contain a space then it _should_ be a header and we will
663  * process all lines before a blank line as headers.
664  */
665 
666  $field = substr($lines[0], 0, strpos($lines[0], ':'));
667  $in_headers = false;
668  if (!empty($field) && strpos($field, ' ') === false) {
669  $in_headers = true;
670  }
671 
672  foreach ($lines as $line) {
673  $lines_out = array();
674  if ($in_headers and $line == '') {
675  $in_headers = false;
676  }
677  //Break this line up into several smaller lines if it's too long
678  //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len),
679  while (isset($line[self::MAX_LINE_LENGTH])) {
680  //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on
681  //so as to avoid breaking in the middle of a word
682  $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' ');
683  //Deliberately matches both false and 0
684  if (!$pos) {
685  //No nice break found, add a hard break
686  $pos = self::MAX_LINE_LENGTH - 1;
687  $lines_out[] = substr($line, 0, $pos);
688  $line = substr($line, $pos);
689  } else {
690  //Break at the found point
691  $lines_out[] = substr($line, 0, $pos);
692  //Move along by the amount we dealt with
693  $line = substr($line, $pos + 1);
694  }
695  //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1
696  if ($in_headers) {
697  $line = "\t" . $line;
698  }
699  }
700  $lines_out[] = $line;
701 
702  //Send the lines to the server
703  foreach ($lines_out as $line_out) {
704  //RFC2821 section 4.5.2
705  if (!empty($line_out) and $line_out[0] == '.') {
706  $line_out = '.' . $line_out;
707  }
708  $this->client_send($line_out . self::CRLF);
709  }
710  }
711 
712  //Message data has been sent, complete the command
713  //Increase timelimit for end of DATA command
714  $savetimelimit = $this->Timelimit;
715  $this->Timelimit = $this->Timelimit * 2;
716  $result = $this->sendCommand('DATA END', '.', 250);
717  $this->recordLastTransactionID();
718  //Restore timelimit
719  $this->Timelimit = $savetimelimit;
720  return $result;
721  }
722 
733  public function hello($host = '')
734  {
735  //Try extended hello first (RFC 2821)
736  return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host));
737  }
738 
748  protected function sendHello($hello, $host)
749  {
750  $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250);
751  $this->helo_rply = $this->last_reply;
752  if ($noerror) {
753  $this->parseHelloFields($hello);
754  } else {
755  $this->server_caps = null;
756  }
757  return $noerror;
758  }
759 
766  protected function parseHelloFields($type)
767  {
768  $this->server_caps = array();
769  $lines = explode("\n", $this->helo_rply);
770 
771  foreach ($lines as $n => $s) {
772  //First 4 chars contain response code followed by - or space
773  $s = trim(substr($s, 4));
774  if (empty($s)) {
775  continue;
776  }
777  $fields = explode(' ', $s);
778  if (!empty($fields)) {
779  if (!$n) {
780  $name = $type;
781  $fields = $fields[0];
782  } else {
783  $name = array_shift($fields);
784  switch ($name) {
785  case 'SIZE':
786  $fields = ($fields ? $fields[0] : 0);
787  break;
788  case 'AUTH':
789  if (!is_array($fields)) {
790  $fields = array();
791  }
792  break;
793  default:
794  $fields = true;
795  }
796  }
797  $this->server_caps[$name] = $fields;
798  }
799  }
800  }
801 
813  public function mail($from)
814  {
815  $useVerp = ($this->do_verp ? ' XVERP' : '');
816  return $this->sendCommand(
817  'MAIL FROM',
818  'MAIL FROM:<' . $from . '>' . $useVerp,
819  250
820  );
821  }
822 
831  public function quit($close_on_error = true)
832  {
833  $noerror = $this->sendCommand('QUIT', 'QUIT', 221);
834  $err = $this->error; //Save any error
835  if ($noerror or $close_on_error) {
836  $this->close();
837  $this->error = $err; //Restore any error from the quit command
838  }
839  return $noerror;
840  }
841 
851  public function recipient($address)
852  {
853  return $this->sendCommand(
854  'RCPT TO',
855  'RCPT TO:<' . $address . '>',
856  array(250, 251)
857  );
858  }
859 
867  public function reset()
868  {
869  return $this->sendCommand('RSET', 'RSET', 250);
870  }
871 
880  protected function sendCommand($command, $commandstring, $expect)
881  {
882  if (!$this->connected()) {
883  $this->setError("Called $command without being connected");
884  return false;
885  }
886  //Reject line breaks in all commands
887  if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) {
888  $this->setError("Command '$command' contained line breaks");
889  return false;
890  }
891  $this->client_send($commandstring . self::CRLF);
892 
893  $this->last_reply = $this->get_lines();
894  // Fetch SMTP code and possible error code explanation
895  $matches = array();
896  if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) {
897  $code = $matches[1];
898  $code_ex = (count($matches) > 2 ? $matches[2] : null);
899  // Cut off error code from each response line
900  $detail = preg_replace(
901  "/{$code}[ -]" .
902  ($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . "/m",
903  '',
904  $this->last_reply
905  );
906  } else {
907  // Fall back to simple parsing if regex fails
908  $code = substr($this->last_reply, 0, 3);
909  $code_ex = null;
910  $detail = substr($this->last_reply, 4);
911  }
912 
913  $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
914 
915  if (!in_array($code, (array)$expect)) {
916  $this->setError(
917  "$command command failed",
918  $detail,
919  $code,
920  $code_ex
921  );
922  $this->edebug(
923  'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply,
924  self::DEBUG_CLIENT
925  );
926  return false;
927  }
928 
929  $this->setError('');
930  return true;
931  }
932 
946  public function sendAndMail($from)
947  {
948  return $this->sendCommand('SAML', "SAML FROM:$from", 250);
949  }
950 
957  public function verify($name)
958  {
959  return $this->sendCommand('VRFY', "VRFY $name", array(250, 251));
960  }
961 
968  public function noop()
969  {
970  return $this->sendCommand('NOOP', 'NOOP', 250);
971  }
972 
982  public function turn()
983  {
984  $this->setError('The SMTP TURN command is not implemented');
985  $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT);
986  return false;
987  }
988 
995  public function client_send($data)
996  {
997  $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
998  set_error_handler(array($this, 'errorHandler'));
999  $result = fwrite($this->smtp_conn, $data);
1000  restore_error_handler();
1001  return $result;
1002  }
1003 
1009  public function getError()
1010  {
1011  return $this->error;
1012  }
1013 
1019  public function getServerExtList()
1020  {
1021  return $this->server_caps;
1022  }
1023 
1043  public function getServerExt($name)
1044  {
1045  if (!$this->server_caps) {
1046  $this->setError('No HELO/EHLO was sent');
1047  return null;
1048  }
1049 
1050  // the tight logic knot ;)
1051  if (!array_key_exists($name, $this->server_caps)) {
1052  if ($name == 'HELO') {
1053  return $this->server_caps['EHLO'];
1054  }
1055  if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) {
1056  return false;
1057  }
1058  $this->setError('HELO handshake was used. Client knows nothing about server extensions');
1059  return null;
1060  }
1061 
1062  return $this->server_caps[$name];
1063  }
1064 
1070  public function getLastReply()
1071  {
1072  return $this->last_reply;
1073  }
1074 
1084  protected function get_lines()
1085  {
1086  // If the connection is bad, give up straight away
1087  if (!is_resource($this->smtp_conn)) {
1088  return '';
1089  }
1090  $data = '';
1091  $endtime = 0;
1092  stream_set_timeout($this->smtp_conn, $this->Timeout);
1093  if ($this->Timelimit > 0) {
1094  $endtime = time() + $this->Timelimit;
1095  }
1096  while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
1097  $str = @fgets($this->smtp_conn, 515);
1098  $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
1099  $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
1100  $data .= $str;
1101  // If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
1102  // or 4th character is a space, we are done reading, break the loop,
1103  // string array access is a micro-optimisation over strlen
1104  if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) {
1105  break;
1106  }
1107  // Timed-out? Log and break
1108  $info = stream_get_meta_data($this->smtp_conn);
1109  if ($info['timed_out']) {
1110  $this->edebug(
1111  'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)',
1112  self::DEBUG_LOWLEVEL
1113  );
1114  break;
1115  }
1116  // Now check if reads took too long
1117  if ($endtime and time() > $endtime) {
1118  $this->edebug(
1119  'SMTP -> get_lines(): timelimit reached (' .
1120  $this->Timelimit . ' sec)',
1121  self::DEBUG_LOWLEVEL
1122  );
1123  break;
1124  }
1125  }
1126  return $data;
1127  }
1128 
1133  public function setVerp($enabled = false)
1134  {
1135  $this->do_verp = $enabled;
1136  }
1137 
1142  public function getVerp()
1143  {
1144  return $this->do_verp;
1145  }
1146 
1154  protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '')
1155  {
1156  $this->error = array(
1157  'error' => $message,
1158  'detail' => $detail,
1159  'smtp_code' => $smtp_code,
1160  'smtp_code_ex' => $smtp_code_ex
1161  );
1162  }
1163 
1168  public function setDebugOutput($method = 'echo')
1169  {
1170  $this->Debugoutput = $method;
1171  }
1172 
1177  public function getDebugOutput()
1178  {
1179  return $this->Debugoutput;
1180  }
1181 
1186  public function setDebugLevel($level = 0)
1187  {
1188  $this->do_debug = $level;
1189  }
1190 
1195  public function getDebugLevel()
1196  {
1197  return $this->do_debug;
1198  }
1199 
1204  public function setTimeout($timeout = 0)
1205  {
1206  $this->Timeout = $timeout;
1207  }
1208 
1213  public function getTimeout()
1214  {
1215  return $this->Timeout;
1216  }
1217 
1225  protected function errorHandler($errno, $errmsg, $errfile = '', $errline = 0)
1226  {
1227  $notice = 'Connection failed.';
1228  $this->setError(
1229  $notice,
1230  $errno,
1231  $errmsg
1232  );
1233  $this->edebug(
1234  $notice . ' Error #' . $errno . ': ' . $errmsg . " [$errfile line $errline]",
1235  self::DEBUG_CONNECTION
1236  );
1237  }
1238 
1247  protected function recordLastTransactionID()
1248  {
1249  $reply = $this->getLastReply();
1250 
1251  if (empty($reply)) {
1252  $this->last_smtp_transaction_id = null;
1253  } else {
1254  $this->last_smtp_transaction_id = false;
1255  foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
1256  if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
1257  $this->last_smtp_transaction_id = $matches[1];
1258  }
1259  }
1260  }
1261 
1263  }
1264 
1272  public function getLastTransactionID()
1273  {
1275  }
1276 }
SMTP\setVerp
setVerp($enabled=false)
Definition: class.smtp.php:1133
SMTP\setDebugOutput
setDebugOutput($method='echo')
Definition: class.smtp.php:1168
SMTP\DEBUG_SERVER
const DEBUG_SERVER
Definition: class.smtp.php:66
SMTP\MAX_LINE_LENGTH
const MAX_LINE_LENGTH
Definition: class.smtp.php:51
SMTP\getLastTransactionID
getLastTransactionID()
Definition: class.smtp.php:1272
SMTP\setError
setError($message, $detail='', $smtp_code='', $smtp_code_ex='')
Definition: class.smtp.php:1154
SMTP\$server_caps
$server_caps
Definition: class.smtp.php:202
SMTP\authenticate
authenticate( $username, $password, $authtype=null, $realm='', $workstation='', $OAuth=null)
Definition: class.smtp.php:392
SMTP\$smtp_transaction_id_patterns
$smtp_transaction_id_patterns
Definition: class.smtp.php:157
SMTP\getTimeout
getTimeout()
Definition: class.smtp.php:1213
SMTP\sendHello
sendHello($hello, $host)
Definition: class.smtp.php:748
SMTP\$helo_rply
$helo_rply
Definition: class.smtp.php:191
SMTP\verify
verify($name)
Definition: class.smtp.php:957
SMTP\DEBUG_CONNECTION
const DEBUG_CONNECTION
Definition: class.smtp.php:71
php
SMTP\get_lines
get_lines()
Definition: class.smtp.php:1084
SMTP
Definition: class.smtp.php:28
SMTP\getVerp
getVerp()
Definition: class.smtp.php:1142
SMTP\connected
connected()
Definition: class.smtp.php:593
SMTP\reset
reset()
Definition: class.smtp.php:867
SMTP\getServerExt
getServerExt($name)
Definition: class.smtp.php:1043
SMTP\mail
mail($from)
Definition: class.smtp.php:813
SMTP\$last_smtp_transaction_id
$last_smtp_transaction_id
Definition: class.smtp.php:167
SMTP\$do_debug
$do_debug
Definition: class.smtp.php:112
and
and
Definition: license.txt:18
SMTP\edebug
edebug($str, $level=0)
Definition: class.smtp.php:218
SMTP\VERSION
const VERSION
Definition: class.smtp.php:33
SMTP\hello
hello($host='')
Definition: class.smtp.php:733
SMTP\getError
getError()
Definition: class.smtp.php:1009
SMTP\turn
turn()
Definition: class.smtp.php:982
SMTP\setTimeout
setTimeout($timeout=0)
Definition: class.smtp.php:1204
SMTP\DEBUG_CLIENT
const DEBUG_CLIENT
Definition: class.smtp.php:61
SMTP\$last_reply
$last_reply
Definition: class.smtp.php:208
time
that in the case of a Adaptation or at a minimum such credit will if a credit for all contributing authors of the Adaptation or Collection then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors For the avoidance of You may only use the credit required by this Section for the purpose of attribution in the manner set out above by exercising Your rights under this You may not implicitly or explicitly assert or imply any connection sponsorship or endorsement by the Original Licensor and or Attribution as of You or Your use of the without the express prior written permission of the Original Licensor and or Attribution Parties Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable if You Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or You must not modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author s honor or reputation Licensor agrees that in those in which any exercise of the right granted in modification or other derogatory action prejudicial to the Original Author s honor and the Licensor will waive or not as this to the fullest extent permitted by the applicable national to enable You to reasonably exercise Your right under Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN LICENSOR OFFERS THE WORK AS IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE STATUTORY OR WITHOUT WARRANTIES OF FITNESS FOR A PARTICULAR OR THE ABSENCE OF LATENT OR OTHER OR THE PRESENCE OF ABSENCE OF WHETHER OR NOT DISCOVERABLE SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED SO SUCH EXCLUSION MAY NOT APPLY TO YOU Limitation on Liability EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES Termination This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License Individuals or entities who have received Adaptations or Collections from You under this will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses and will survive any termination of this License Subject to the above terms and the license granted here is Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time
Definition: license.txt:56
SMTP\$Version
$Version
Definition: class.smtp.php:84
SMTP\DEBUG_LOWLEVEL
const DEBUG_LOWLEVEL
Definition: class.smtp.php:76
SMTP\quit
quit($close_on_error=true)
Definition: class.smtp.php:831
SMTP\getDebugOutput
getDebugOutput()
Definition: class.smtp.php:1177
SMTP\hmac
hmac($data, $key)
Definition: class.smtp.php:561
SMTP\noop
noop()
Definition: class.smtp.php:968
SMTP\$Timeout
$Timeout
Definition: class.smtp.php:144
$s
$s
Definition: embed.php:13
SMTP\$SMTP_PORT
$SMTP_PORT
Definition: class.smtp.php:92
SMTP\recordLastTransactionID
recordLastTransactionID()
Definition: class.smtp.php:1247
SMTP\CRLF
const CRLF
Definition: class.smtp.php:39
SMTP\getDebugLevel
getDebugLevel()
Definition: class.smtp.php:1195
SMTP\getLastReply
getLastReply()
Definition: class.smtp.php:1070
SMTP\sendCommand
sendCommand($command, $commandstring, $expect)
Definition: class.smtp.php:880
SMTP\$error
$error
Definition: class.smtp.php:179
SMTP\connect
connect($host, $port=null, $timeout=30, $options=array())
Definition: class.smtp.php:262
SMTP\data
data($msg_data)
Definition: class.smtp.php:643
SMTP\parseHelloFields
parseHelloFields($type)
Definition: class.smtp.php:766
SMTP\close
close()
Definition: class.smtp.php:618
SMTP\recipient
recipient($address)
Definition: class.smtp.php:851
SMTP\$smtp_conn
$smtp_conn
Definition: class.smtp.php:173
SMTP\errorHandler
errorHandler($errno, $errmsg, $errfile='', $errline=0)
Definition: class.smtp.php:1225
SMTP\setDebugLevel
setDebugLevel($level=0)
Definition: class.smtp.php:1186
SMTP\DEBUG_OFF
const DEBUG_OFF
Definition: class.smtp.php:56
SMTP\getServerExtList
getServerExtList()
Definition: class.smtp.php:1019
SMTP\DEFAULT_SMTP_PORT
const DEFAULT_SMTP_PORT
Definition: class.smtp.php:45
empty
Attr AllowedRel this is empty
Definition: Attr.AllowedRel.txt:7
SMTP\startTLS
startTLS()
Definition: class.smtp.php:353
SMTP\sendAndMail
sendAndMail($from)
Definition: class.smtp.php:946
as
as
Definition: Filter.ExtractStyleBlocks.Escaping.txt:10
SMTP\$CRLF
$CRLF
Definition: class.smtp.php:100
SMTP\client_send
client_send($data)
Definition: class.smtp.php:995
SMTP\$do_verp
$do_verp
Definition: class.smtp.php:135
or
Voluntary License Schemes The Licensor waives the right to collect whether individually or
Definition: license.txt:37
SMTP\$Timelimit
$Timelimit
Definition: class.smtp.php:151
SMTP\$Debugoutput
$Debugoutput
Definition: class.smtp.php:127