Mercurial > hg > rc1
comparison vendor/pear/net_smtp/Net/SMTP.php @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
| author | Charlie Root |
|---|---|
| date | Thu, 04 Jan 2018 15:50:29 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:1e000243b222 |
|---|---|
| 1 <?php | |
| 2 /** vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ | |
| 3 // +----------------------------------------------------------------------+ | |
| 4 // | PHP Version 5 and 7 | | |
| 5 // +----------------------------------------------------------------------+ | |
| 6 // | Copyright (c) 1997-2015 Jon Parise and Chuck Hagenbuch | | |
| 7 // +----------------------------------------------------------------------+ | |
| 8 // | This source file is subject to version 3.01 of the PHP license, | | |
| 9 // | that is bundled with this package in the file LICENSE, and is | | |
| 10 // | available at through the world-wide-web at | | |
| 11 // | http://www.php.net/license/3_01.txt. | | |
| 12 // | If you did not receive a copy of the PHP license and are unable to | | |
| 13 // | obtain it through the world-wide-web, please send a note to | | |
| 14 // | license@php.net so we can mail you a copy immediately. | | |
| 15 // +----------------------------------------------------------------------+ | |
| 16 // | Authors: Chuck Hagenbuch <chuck@horde.org> | | |
| 17 // | Jon Parise <jon@php.net> | | |
| 18 // | Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> | | |
| 19 // +----------------------------------------------------------------------+ | |
| 20 | |
| 21 require_once 'PEAR.php'; | |
| 22 require_once 'Net/Socket.php'; | |
| 23 | |
| 24 /** | |
| 25 * Provides an implementation of the SMTP protocol using PEAR's | |
| 26 * Net_Socket class. | |
| 27 * | |
| 28 * @package Net_SMTP | |
| 29 * @author Chuck Hagenbuch <chuck@horde.org> | |
| 30 * @author Jon Parise <jon@php.net> | |
| 31 * @author Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> | |
| 32 * | |
| 33 * @example basic.php A basic implementation of the Net_SMTP package. | |
| 34 */ | |
| 35 class Net_SMTP | |
| 36 { | |
| 37 /** | |
| 38 * The server to connect to. | |
| 39 * @var string | |
| 40 */ | |
| 41 public $host = 'localhost'; | |
| 42 | |
| 43 /** | |
| 44 * The port to connect to. | |
| 45 * @var int | |
| 46 */ | |
| 47 public $port = 25; | |
| 48 | |
| 49 /** | |
| 50 * The value to give when sending EHLO or HELO. | |
| 51 * @var string | |
| 52 */ | |
| 53 public $localhost = 'localhost'; | |
| 54 | |
| 55 /** | |
| 56 * List of supported authentication methods, in preferential order. | |
| 57 * @var array | |
| 58 */ | |
| 59 public $auth_methods = array(); | |
| 60 | |
| 61 /** | |
| 62 * Use SMTP command pipelining (specified in RFC 2920) if the SMTP | |
| 63 * server supports it. | |
| 64 * | |
| 65 * When pipeling is enabled, rcptTo(), mailFrom(), sendFrom(), | |
| 66 * somlFrom() and samlFrom() do not wait for a response from the | |
| 67 * SMTP server but return immediately. | |
| 68 * | |
| 69 * @var bool | |
| 70 */ | |
| 71 public $pipelining = false; | |
| 72 | |
| 73 /** | |
| 74 * Number of pipelined commands. | |
| 75 * @var int | |
| 76 */ | |
| 77 protected $pipelined_commands = 0; | |
| 78 | |
| 79 /** | |
| 80 * Should debugging output be enabled? | |
| 81 * @var boolean | |
| 82 */ | |
| 83 protected $debug = false; | |
| 84 | |
| 85 /** | |
| 86 * Debug output handler. | |
| 87 * @var callback | |
| 88 */ | |
| 89 protected $debug_handler = null; | |
| 90 | |
| 91 /** | |
| 92 * The socket resource being used to connect to the SMTP server. | |
| 93 * @var resource | |
| 94 */ | |
| 95 protected $socket = null; | |
| 96 | |
| 97 /** | |
| 98 * Array of socket options that will be passed to Net_Socket::connect(). | |
| 99 * @see stream_context_create() | |
| 100 * @var array | |
| 101 */ | |
| 102 protected $socket_options = null; | |
| 103 | |
| 104 /** | |
| 105 * The socket I/O timeout value in seconds. | |
| 106 * @var int | |
| 107 */ | |
| 108 protected $timeout = 0; | |
| 109 | |
| 110 /** | |
| 111 * The most recent server response code. | |
| 112 * @var int | |
| 113 */ | |
| 114 protected $code = -1; | |
| 115 | |
| 116 /** | |
| 117 * The most recent server response arguments. | |
| 118 * @var array | |
| 119 */ | |
| 120 protected $arguments = array(); | |
| 121 | |
| 122 /** | |
| 123 * Stores the SMTP server's greeting string. | |
| 124 * @var string | |
| 125 */ | |
| 126 protected $greeting = null; | |
| 127 | |
| 128 /** | |
| 129 * Stores detected features of the SMTP server. | |
| 130 * @var array | |
| 131 */ | |
| 132 protected $esmtp = array(); | |
| 133 | |
| 134 /** | |
| 135 * Instantiates a new Net_SMTP object, overriding any defaults | |
| 136 * with parameters that are passed in. | |
| 137 * | |
| 138 * If you have SSL support in PHP, you can connect to a server | |
| 139 * over SSL using an 'ssl://' prefix: | |
| 140 * | |
| 141 * // 465 is a common smtps port. | |
| 142 * $smtp = new Net_SMTP('ssl://mail.host.com', 465); | |
| 143 * $smtp->connect(); | |
| 144 * | |
| 145 * @param string $host The server to connect to. | |
| 146 * @param integer $port The port to connect to. | |
| 147 * @param string $localhost The value to give when sending EHLO or HELO. | |
| 148 * @param boolean $pipelining Use SMTP command pipelining | |
| 149 * @param integer $timeout Socket I/O timeout in seconds. | |
| 150 * @param array $socket_options Socket stream_context_create() options. | |
| 151 * | |
| 152 * @since 1.0 | |
| 153 */ | |
| 154 public function __construct($host = null, $port = null, $localhost = null, | |
| 155 $pipelining = false, $timeout = 0, $socket_options = null | |
| 156 ) { | |
| 157 if (isset($host)) { | |
| 158 $this->host = $host; | |
| 159 } | |
| 160 if (isset($port)) { | |
| 161 $this->port = $port; | |
| 162 } | |
| 163 if (isset($localhost)) { | |
| 164 $this->localhost = $localhost; | |
| 165 } | |
| 166 | |
| 167 $this->pipelining = $pipelining; | |
| 168 $this->socket = new Net_Socket(); | |
| 169 $this->socket_options = $socket_options; | |
| 170 $this->timeout = $timeout; | |
| 171 | |
| 172 /* Include the Auth_SASL package. If the package is available, we | |
| 173 * enable the authentication methods that depend upon it. */ | |
| 174 if (@include_once 'Auth/SASL.php') { | |
| 175 $this->setAuthMethod('CRAM-MD5', array($this, 'authCramMD5')); | |
| 176 $this->setAuthMethod('DIGEST-MD5', array($this, 'authDigestMD5')); | |
| 177 } | |
| 178 | |
| 179 /* These standard authentication methods are always available. */ | |
| 180 $this->setAuthMethod('LOGIN', array($this, 'authLogin'), false); | |
| 181 $this->setAuthMethod('PLAIN', array($this, 'authPlain'), false); | |
| 182 } | |
| 183 | |
| 184 /** | |
| 185 * Set the socket I/O timeout value in seconds plus microseconds. | |
| 186 * | |
| 187 * @param integer $seconds Timeout value in seconds. | |
| 188 * @param integer $microseconds Additional value in microseconds. | |
| 189 * | |
| 190 * @since 1.5.0 | |
| 191 */ | |
| 192 public function setTimeout($seconds, $microseconds = 0) | |
| 193 { | |
| 194 return $this->socket->setTimeout($seconds, $microseconds); | |
| 195 } | |
| 196 | |
| 197 /** | |
| 198 * Set the value of the debugging flag. | |
| 199 * | |
| 200 * @param boolean $debug New value for the debugging flag. | |
| 201 * @param callback $handler Debug handler callback | |
| 202 * | |
| 203 * @since 1.1.0 | |
| 204 */ | |
| 205 public function setDebug($debug, $handler = null) | |
| 206 { | |
| 207 $this->debug = $debug; | |
| 208 $this->debug_handler = $handler; | |
| 209 } | |
| 210 | |
| 211 /** | |
| 212 * Write the given debug text to the current debug output handler. | |
| 213 * | |
| 214 * @param string $message Debug mesage text. | |
| 215 * | |
| 216 * @since 1.3.3 | |
| 217 */ | |
| 218 protected function debug($message) | |
| 219 { | |
| 220 if ($this->debug) { | |
| 221 if ($this->debug_handler) { | |
| 222 call_user_func_array( | |
| 223 $this->debug_handler, array(&$this, $message) | |
| 224 ); | |
| 225 } else { | |
| 226 echo "DEBUG: $message\n"; | |
| 227 } | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 /** | |
| 232 * Send the given string of data to the server. | |
| 233 * | |
| 234 * @param string $data The string of data to send. | |
| 235 * | |
| 236 * @return mixed The number of bytes that were actually written, | |
| 237 * or a PEAR_Error object on failure. | |
| 238 * | |
| 239 * @since 1.1.0 | |
| 240 */ | |
| 241 protected function send($data) | |
| 242 { | |
| 243 $this->debug("Send: $data"); | |
| 244 | |
| 245 $result = $this->socket->write($data); | |
| 246 if (!$result || PEAR::isError($result)) { | |
| 247 $msg = $result ? $result->getMessage() : "unknown error"; | |
| 248 return PEAR::raiseError("Failed to write to socket: $msg"); | |
| 249 } | |
| 250 | |
| 251 return $result; | |
| 252 } | |
| 253 | |
| 254 /** | |
| 255 * Send a command to the server with an optional string of | |
| 256 * arguments. A carriage return / linefeed (CRLF) sequence will | |
| 257 * be appended to each command string before it is sent to the | |
| 258 * SMTP server - an error will be thrown if the command string | |
| 259 * already contains any newline characters. Use send() for | |
| 260 * commands that must contain newlines. | |
| 261 * | |
| 262 * @param string $command The SMTP command to send to the server. | |
| 263 * @param string $args A string of optional arguments to append | |
| 264 * to the command. | |
| 265 * | |
| 266 * @return mixed The result of the send() call. | |
| 267 * | |
| 268 * @since 1.1.0 | |
| 269 */ | |
| 270 protected function put($command, $args = '') | |
| 271 { | |
| 272 if (!empty($args)) { | |
| 273 $command .= ' ' . $args; | |
| 274 } | |
| 275 | |
| 276 if (strcspn($command, "\r\n") !== strlen($command)) { | |
| 277 return PEAR::raiseError('Commands cannot contain newlines'); | |
| 278 } | |
| 279 | |
| 280 return $this->send($command . "\r\n"); | |
| 281 } | |
| 282 | |
| 283 /** | |
| 284 * Read a reply from the SMTP server. The reply consists of a response | |
| 285 * code and a response message. | |
| 286 * | |
| 287 * @param mixed $valid The set of valid response codes. These | |
| 288 * may be specified as an array of integer | |
| 289 * values or as a single integer value. | |
| 290 * @param bool $later Do not parse the response now, but wait | |
| 291 * until the last command in the pipelined | |
| 292 * command group | |
| 293 * | |
| 294 * @return mixed True if the server returned a valid response code or | |
| 295 * a PEAR_Error object is an error condition is reached. | |
| 296 * | |
| 297 * @since 1.1.0 | |
| 298 * | |
| 299 * @see getResponse | |
| 300 */ | |
| 301 protected function parseResponse($valid, $later = false) | |
| 302 { | |
| 303 $this->code = -1; | |
| 304 $this->arguments = array(); | |
| 305 | |
| 306 if ($later) { | |
| 307 $this->pipelined_commands++; | |
| 308 return true; | |
| 309 } | |
| 310 | |
| 311 for ($i = 0; $i <= $this->pipelined_commands; $i++) { | |
| 312 while ($line = $this->socket->readLine()) { | |
| 313 $this->debug("Recv: $line"); | |
| 314 | |
| 315 /* If we receive an empty line, the connection was closed. */ | |
| 316 if (empty($line)) { | |
| 317 $this->disconnect(); | |
| 318 return PEAR::raiseError('Connection was closed'); | |
| 319 } | |
| 320 | |
| 321 /* Read the code and store the rest in the arguments array. */ | |
| 322 $code = substr($line, 0, 3); | |
| 323 $this->arguments[] = trim(substr($line, 4)); | |
| 324 | |
| 325 /* Check the syntax of the response code. */ | |
| 326 if (is_numeric($code)) { | |
| 327 $this->code = (int)$code; | |
| 328 } else { | |
| 329 $this->code = -1; | |
| 330 break; | |
| 331 } | |
| 332 | |
| 333 /* If this is not a multiline response, we're done. */ | |
| 334 if (substr($line, 3, 1) != '-') { | |
| 335 break; | |
| 336 } | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 $this->pipelined_commands = 0; | |
| 341 | |
| 342 /* Compare the server's response code with the valid code/codes. */ | |
| 343 if (is_int($valid) && ($this->code === $valid)) { | |
| 344 return true; | |
| 345 } elseif (is_array($valid) && in_array($this->code, $valid, true)) { | |
| 346 return true; | |
| 347 } | |
| 348 | |
| 349 return PEAR::raiseError('Invalid response code received from server', $this->code); | |
| 350 } | |
| 351 | |
| 352 /** | |
| 353 * Issue an SMTP command and verify its response. | |
| 354 * | |
| 355 * @param string $command The SMTP command string or data. | |
| 356 * @param mixed $valid The set of valid response codes. These | |
| 357 * may be specified as an array of integer | |
| 358 * values or as a single integer value. | |
| 359 * | |
| 360 * @return mixed True on success or a PEAR_Error object on failure. | |
| 361 * | |
| 362 * @since 1.6.0 | |
| 363 */ | |
| 364 public function command($command, $valid) | |
| 365 { | |
| 366 if (PEAR::isError($error = $this->put($command))) { | |
| 367 return $error; | |
| 368 } | |
| 369 if (PEAR::isError($error = $this->parseResponse($valid))) { | |
| 370 return $error; | |
| 371 } | |
| 372 | |
| 373 return true; | |
| 374 } | |
| 375 | |
| 376 /** | |
| 377 * Return a 2-tuple containing the last response from the SMTP server. | |
| 378 * | |
| 379 * @return array A two-element array: the first element contains the | |
| 380 * response code as an integer and the second element | |
| 381 * contains the response's arguments as a string. | |
| 382 * | |
| 383 * @since 1.1.0 | |
| 384 */ | |
| 385 public function getResponse() | |
| 386 { | |
| 387 return array($this->code, join("\n", $this->arguments)); | |
| 388 } | |
| 389 | |
| 390 /** | |
| 391 * Return the SMTP server's greeting string. | |
| 392 * | |
| 393 * @return string A string containing the greeting string, or null if | |
| 394 * a greeting has not been received. | |
| 395 * | |
| 396 * @since 1.3.3 | |
| 397 */ | |
| 398 public function getGreeting() | |
| 399 { | |
| 400 return $this->greeting; | |
| 401 } | |
| 402 | |
| 403 /** | |
| 404 * Attempt to connect to the SMTP server. | |
| 405 * | |
| 406 * @param int $timeout The timeout value (in seconds) for the | |
| 407 * socket connection attempt. | |
| 408 * @param bool $persistent Should a persistent socket connection | |
| 409 * be used? | |
| 410 * | |
| 411 * @return mixed Returns a PEAR_Error with an error message on any | |
| 412 * kind of failure, or true on success. | |
| 413 * @since 1.0 | |
| 414 */ | |
| 415 public function connect($timeout = null, $persistent = false) | |
| 416 { | |
| 417 $this->greeting = null; | |
| 418 | |
| 419 $result = $this->socket->connect( | |
| 420 $this->host, $this->port, $persistent, $timeout, $this->socket_options | |
| 421 ); | |
| 422 | |
| 423 if (PEAR::isError($result)) { | |
| 424 return PEAR::raiseError( | |
| 425 'Failed to connect socket: ' . $result->getMessage() | |
| 426 ); | |
| 427 } | |
| 428 | |
| 429 /* | |
| 430 * Now that we're connected, reset the socket's timeout value for | |
| 431 * future I/O operations. This allows us to have different socket | |
| 432 * timeout values for the initial connection (our $timeout parameter) | |
| 433 * and all other socket operations. | |
| 434 */ | |
| 435 if ($this->timeout > 0) { | |
| 436 if (PEAR::isError($error = $this->setTimeout($this->timeout))) { | |
| 437 return $error; | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 if (PEAR::isError($error = $this->parseResponse(220))) { | |
| 442 return $error; | |
| 443 } | |
| 444 | |
| 445 /* Extract and store a copy of the server's greeting string. */ | |
| 446 list(, $this->greeting) = $this->getResponse(); | |
| 447 | |
| 448 if (PEAR::isError($error = $this->negotiate())) { | |
| 449 return $error; | |
| 450 } | |
| 451 | |
| 452 return true; | |
| 453 } | |
| 454 | |
| 455 /** | |
| 456 * Attempt to disconnect from the SMTP server. | |
| 457 * | |
| 458 * @return mixed Returns a PEAR_Error with an error message on any | |
| 459 * kind of failure, or true on success. | |
| 460 * @since 1.0 | |
| 461 */ | |
| 462 public function disconnect() | |
| 463 { | |
| 464 if (PEAR::isError($error = $this->put('QUIT'))) { | |
| 465 return $error; | |
| 466 } | |
| 467 if (PEAR::isError($error = $this->parseResponse(221))) { | |
| 468 return $error; | |
| 469 } | |
| 470 if (PEAR::isError($error = $this->socket->disconnect())) { | |
| 471 return PEAR::raiseError( | |
| 472 'Failed to disconnect socket: ' . $error->getMessage() | |
| 473 ); | |
| 474 } | |
| 475 | |
| 476 return true; | |
| 477 } | |
| 478 | |
| 479 /** | |
| 480 * Attempt to send the EHLO command and obtain a list of ESMTP | |
| 481 * extensions available, and failing that just send HELO. | |
| 482 * | |
| 483 * @return mixed Returns a PEAR_Error with an error message on any | |
| 484 * kind of failure, or true on success. | |
| 485 * | |
| 486 * @since 1.1.0 | |
| 487 */ | |
| 488 protected function negotiate() | |
| 489 { | |
| 490 if (PEAR::isError($error = $this->put('EHLO', $this->localhost))) { | |
| 491 return $error; | |
| 492 } | |
| 493 | |
| 494 if (PEAR::isError($this->parseResponse(250))) { | |
| 495 /* If the EHLO failed, try the simpler HELO command. */ | |
| 496 if (PEAR::isError($error = $this->put('HELO', $this->localhost))) { | |
| 497 return $error; | |
| 498 } | |
| 499 if (PEAR::isError($this->parseResponse(250))) { | |
| 500 return PEAR::raiseError('HELO was not accepted', $this->code); | |
| 501 } | |
| 502 | |
| 503 return true; | |
| 504 } | |
| 505 | |
| 506 foreach ($this->arguments as $argument) { | |
| 507 $verb = strtok($argument, ' '); | |
| 508 $len = strlen($verb); | |
| 509 $arguments = substr($argument, $len + 1, strlen($argument) - $len - 1); | |
| 510 $this->esmtp[$verb] = $arguments; | |
| 511 } | |
| 512 | |
| 513 if (!isset($this->esmtp['PIPELINING'])) { | |
| 514 $this->pipelining = false; | |
| 515 } | |
| 516 | |
| 517 return true; | |
| 518 } | |
| 519 | |
| 520 /** | |
| 521 * Returns the name of the best authentication method that the server | |
| 522 * has advertised. | |
| 523 * | |
| 524 * @return mixed Returns a string containing the name of the best | |
| 525 * supported authentication method or a PEAR_Error object | |
| 526 * if a failure condition is encountered. | |
| 527 * @since 1.1.0 | |
| 528 */ | |
| 529 protected function getBestAuthMethod() | |
| 530 { | |
| 531 $available_methods = explode(' ', $this->esmtp['AUTH']); | |
| 532 | |
| 533 foreach ($this->auth_methods as $method => $callback) { | |
| 534 if (in_array($method, $available_methods)) { | |
| 535 return $method; | |
| 536 } | |
| 537 } | |
| 538 | |
| 539 return PEAR::raiseError('No supported authentication methods'); | |
| 540 } | |
| 541 | |
| 542 /** | |
| 543 * Attempt to do SMTP authentication. | |
| 544 * | |
| 545 * @param string $uid The userid to authenticate as. | |
| 546 * @param string $pwd The password to authenticate with. | |
| 547 * @param string $method The requested authentication method. If none is | |
| 548 * specified, the best supported method will be used. | |
| 549 * @param bool $tls Flag indicating whether or not TLS should be attempted. | |
| 550 * @param string $authz An optional authorization identifier. If specified, this | |
| 551 * identifier will be used as the authorization proxy. | |
| 552 * | |
| 553 * @return mixed Returns a PEAR_Error with an error message on any | |
| 554 * kind of failure, or true on success. | |
| 555 * @since 1.0 | |
| 556 */ | |
| 557 public function auth($uid, $pwd , $method = '', $tls = true, $authz = '') | |
| 558 { | |
| 559 /* We can only attempt a TLS connection if one has been requested, | |
| 560 * we're running PHP 5.1.0 or later, have access to the OpenSSL | |
| 561 * extension, are connected to an SMTP server which supports the | |
| 562 * STARTTLS extension, and aren't already connected over a secure | |
| 563 * (SSL) socket connection. */ | |
| 564 if ($tls && version_compare(PHP_VERSION, '5.1.0', '>=') | |
| 565 && extension_loaded('openssl') && isset($this->esmtp['STARTTLS']) | |
| 566 && strncasecmp($this->host, 'ssl://', 6) !== 0 | |
| 567 ) { | |
| 568 /* Start the TLS connection attempt. */ | |
| 569 if (PEAR::isError($result = $this->put('STARTTLS'))) { | |
| 570 return $result; | |
| 571 } | |
| 572 if (PEAR::isError($result = $this->parseResponse(220))) { | |
| 573 return $result; | |
| 574 } | |
| 575 if (isset($this->socket_options['ssl']['crypto_method'])) { | |
| 576 $crypto_method = $this->socket_options['ssl']['crypto_method']; | |
| 577 } else { | |
| 578 /* STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT constant does not exist | |
| 579 * and STREAM_CRYPTO_METHOD_SSLv23_CLIENT constant is | |
| 580 * inconsistent across PHP versions. */ | |
| 581 $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT | |
| 582 | @STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | |
| 583 | @STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; | |
| 584 } | |
| 585 if (PEAR::isError($result = $this->socket->enableCrypto(true, $crypto_method))) { | |
| 586 return $result; | |
| 587 } elseif ($result !== true) { | |
| 588 return PEAR::raiseError('STARTTLS failed'); | |
| 589 } | |
| 590 | |
| 591 /* Send EHLO again to recieve the AUTH string from the | |
| 592 * SMTP server. */ | |
| 593 $this->negotiate(); | |
| 594 } | |
| 595 | |
| 596 if (empty($this->esmtp['AUTH'])) { | |
| 597 return PEAR::raiseError('SMTP server does not support authentication'); | |
| 598 } | |
| 599 | |
| 600 /* If no method has been specified, get the name of the best | |
| 601 * supported method advertised by the SMTP server. */ | |
| 602 if (empty($method)) { | |
| 603 if (PEAR::isError($method = $this->getBestAuthMethod())) { | |
| 604 /* Return the PEAR_Error object from _getBestAuthMethod(). */ | |
| 605 return $method; | |
| 606 } | |
| 607 } else { | |
| 608 $method = strtoupper($method); | |
| 609 if (!array_key_exists($method, $this->auth_methods)) { | |
| 610 return PEAR::raiseError("$method is not a supported authentication method"); | |
| 611 } | |
| 612 } | |
| 613 | |
| 614 if (!isset($this->auth_methods[$method])) { | |
| 615 return PEAR::raiseError("$method is not a supported authentication method"); | |
| 616 } | |
| 617 | |
| 618 if (!is_callable($this->auth_methods[$method], false)) { | |
| 619 return PEAR::raiseError("$method authentication method cannot be called"); | |
| 620 } | |
| 621 | |
| 622 if (is_array($this->auth_methods[$method])) { | |
| 623 list($object, $method) = $this->auth_methods[$method]; | |
| 624 $result = $object->{$method}($uid, $pwd, $authz, $this); | |
| 625 } else { | |
| 626 $func = $this->auth_methods[$method]; | |
| 627 $result = $func($uid, $pwd, $authz, $this); | |
| 628 } | |
| 629 | |
| 630 /* If an error was encountered, return the PEAR_Error object. */ | |
| 631 if (PEAR::isError($result)) { | |
| 632 return $result; | |
| 633 } | |
| 634 | |
| 635 return true; | |
| 636 } | |
| 637 | |
| 638 /** | |
| 639 * Add a new authentication method. | |
| 640 * | |
| 641 * @param string $name The authentication method name (e.g. 'PLAIN') | |
| 642 * @param mixed $callback The authentication callback (given as the name of a | |
| 643 * function or as an (object, method name) array). | |
| 644 * @param bool $prepend Should the new method be prepended to the list of | |
| 645 * available methods? This is the default behavior, | |
| 646 * giving the new method the highest priority. | |
| 647 * | |
| 648 * @return mixed True on success or a PEAR_Error object on failure. | |
| 649 * | |
| 650 * @since 1.6.0 | |
| 651 */ | |
| 652 public function setAuthMethod($name, $callback, $prepend = true) | |
| 653 { | |
| 654 if (!is_string($name)) { | |
| 655 return PEAR::raiseError('Method name is not a string'); | |
| 656 } | |
| 657 | |
| 658 if (!is_string($callback) && !is_array($callback)) { | |
| 659 return PEAR::raiseError('Method callback must be string or array'); | |
| 660 } | |
| 661 | |
| 662 if (is_array($callback)) { | |
| 663 if (!is_object($callback[0]) || !is_string($callback[1])) { | |
| 664 return PEAR::raiseError('Bad mMethod callback array'); | |
| 665 } | |
| 666 } | |
| 667 | |
| 668 if ($prepend) { | |
| 669 $this->auth_methods = array_merge( | |
| 670 array($name => $callback), $this->auth_methods | |
| 671 ); | |
| 672 } else { | |
| 673 $this->auth_methods[$name] = $callback; | |
| 674 } | |
| 675 | |
| 676 return true; | |
| 677 } | |
| 678 | |
| 679 /** | |
| 680 * Authenticates the user using the DIGEST-MD5 method. | |
| 681 * | |
| 682 * @param string $uid The userid to authenticate as. | |
| 683 * @param string $pwd The password to authenticate with. | |
| 684 * @param string $authz The optional authorization proxy identifier. | |
| 685 * | |
| 686 * @return mixed Returns a PEAR_Error with an error message on any | |
| 687 * kind of failure, or true on success. | |
| 688 * @since 1.1.0 | |
| 689 */ | |
| 690 protected function authDigestMD5($uid, $pwd, $authz = '') | |
| 691 { | |
| 692 if (PEAR::isError($error = $this->put('AUTH', 'DIGEST-MD5'))) { | |
| 693 return $error; | |
| 694 } | |
| 695 /* 334: Continue authentication request */ | |
| 696 if (PEAR::isError($error = $this->parseResponse(334))) { | |
| 697 /* 503: Error: already authenticated */ | |
| 698 if ($this->code === 503) { | |
| 699 return true; | |
| 700 } | |
| 701 return $error; | |
| 702 } | |
| 703 | |
| 704 $auth_sasl = new Auth_SASL; | |
| 705 $digest = $auth_sasl->factory('digest-md5'); | |
| 706 $challenge = base64_decode($this->arguments[0]); | |
| 707 $auth_str = base64_encode( | |
| 708 $digest->getResponse($uid, $pwd, $challenge, $this->host, "smtp", $authz) | |
| 709 ); | |
| 710 | |
| 711 if (PEAR::isError($error = $this->put($auth_str))) { | |
| 712 return $error; | |
| 713 } | |
| 714 /* 334: Continue authentication request */ | |
| 715 if (PEAR::isError($error = $this->parseResponse(334))) { | |
| 716 return $error; | |
| 717 } | |
| 718 | |
| 719 /* We don't use the protocol's third step because SMTP doesn't | |
| 720 * allow subsequent authentication, so we just silently ignore | |
| 721 * it. */ | |
| 722 if (PEAR::isError($error = $this->put(''))) { | |
| 723 return $error; | |
| 724 } | |
| 725 /* 235: Authentication successful */ | |
| 726 if (PEAR::isError($error = $this->parseResponse(235))) { | |
| 727 return $error; | |
| 728 } | |
| 729 } | |
| 730 | |
| 731 /** | |
| 732 * Authenticates the user using the CRAM-MD5 method. | |
| 733 * | |
| 734 * @param string $uid The userid to authenticate as. | |
| 735 * @param string $pwd The password to authenticate with. | |
| 736 * @param string $authz The optional authorization proxy identifier. | |
| 737 * | |
| 738 * @return mixed Returns a PEAR_Error with an error message on any | |
| 739 * kind of failure, or true on success. | |
| 740 * @since 1.1.0 | |
| 741 */ | |
| 742 protected function authCRAMMD5($uid, $pwd, $authz = '') | |
| 743 { | |
| 744 if (PEAR::isError($error = $this->put('AUTH', 'CRAM-MD5'))) { | |
| 745 return $error; | |
| 746 } | |
| 747 /* 334: Continue authentication request */ | |
| 748 if (PEAR::isError($error = $this->parseResponse(334))) { | |
| 749 /* 503: Error: already authenticated */ | |
| 750 if ($this->code === 503) { | |
| 751 return true; | |
| 752 } | |
| 753 return $error; | |
| 754 } | |
| 755 | |
| 756 $auth_sasl = new Auth_SASL; | |
| 757 $challenge = base64_decode($this->arguments[0]); | |
| 758 $cram = $auth_sasl->factory('cram-md5'); | |
| 759 $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge)); | |
| 760 | |
| 761 if (PEAR::isError($error = $this->put($auth_str))) { | |
| 762 return $error; | |
| 763 } | |
| 764 | |
| 765 /* 235: Authentication successful */ | |
| 766 if (PEAR::isError($error = $this->parseResponse(235))) { | |
| 767 return $error; | |
| 768 } | |
| 769 } | |
| 770 | |
| 771 /** | |
| 772 * Authenticates the user using the LOGIN method. | |
| 773 * | |
| 774 * @param string $uid The userid to authenticate as. | |
| 775 * @param string $pwd The password to authenticate with. | |
| 776 * @param string $authz The optional authorization proxy identifier. | |
| 777 * | |
| 778 * @return mixed Returns a PEAR_Error with an error message on any | |
| 779 * kind of failure, or true on success. | |
| 780 * @since 1.1.0 | |
| 781 */ | |
| 782 protected function authLogin($uid, $pwd, $authz = '') | |
| 783 { | |
| 784 if (PEAR::isError($error = $this->put('AUTH', 'LOGIN'))) { | |
| 785 return $error; | |
| 786 } | |
| 787 /* 334: Continue authentication request */ | |
| 788 if (PEAR::isError($error = $this->parseResponse(334))) { | |
| 789 /* 503: Error: already authenticated */ | |
| 790 if ($this->code === 503) { | |
| 791 return true; | |
| 792 } | |
| 793 return $error; | |
| 794 } | |
| 795 | |
| 796 if (PEAR::isError($error = $this->put(base64_encode($uid)))) { | |
| 797 return $error; | |
| 798 } | |
| 799 /* 334: Continue authentication request */ | |
| 800 if (PEAR::isError($error = $this->parseResponse(334))) { | |
| 801 return $error; | |
| 802 } | |
| 803 | |
| 804 if (PEAR::isError($error = $this->put(base64_encode($pwd)))) { | |
| 805 return $error; | |
| 806 } | |
| 807 | |
| 808 /* 235: Authentication successful */ | |
| 809 if (PEAR::isError($error = $this->parseResponse(235))) { | |
| 810 return $error; | |
| 811 } | |
| 812 | |
| 813 return true; | |
| 814 } | |
| 815 | |
| 816 /** | |
| 817 * Authenticates the user using the PLAIN method. | |
| 818 * | |
| 819 * @param string $uid The userid to authenticate as. | |
| 820 * @param string $pwd The password to authenticate with. | |
| 821 * @param string $authz The optional authorization proxy identifier. | |
| 822 * | |
| 823 * @return mixed Returns a PEAR_Error with an error message on any | |
| 824 * kind of failure, or true on success. | |
| 825 * @since 1.1.0 | |
| 826 */ | |
| 827 protected function authPlain($uid, $pwd, $authz = '') | |
| 828 { | |
| 829 if (PEAR::isError($error = $this->put('AUTH', 'PLAIN'))) { | |
| 830 return $error; | |
| 831 } | |
| 832 /* 334: Continue authentication request */ | |
| 833 if (PEAR::isError($error = $this->parseResponse(334))) { | |
| 834 /* 503: Error: already authenticated */ | |
| 835 if ($this->code === 503) { | |
| 836 return true; | |
| 837 } | |
| 838 return $error; | |
| 839 } | |
| 840 | |
| 841 $auth_str = base64_encode($authz . chr(0) . $uid . chr(0) . $pwd); | |
| 842 | |
| 843 if (PEAR::isError($error = $this->put($auth_str))) { | |
| 844 return $error; | |
| 845 } | |
| 846 | |
| 847 /* 235: Authentication successful */ | |
| 848 if (PEAR::isError($error = $this->parseResponse(235))) { | |
| 849 return $error; | |
| 850 } | |
| 851 | |
| 852 return true; | |
| 853 } | |
| 854 | |
| 855 /** | |
| 856 * Send the HELO command. | |
| 857 * | |
| 858 * @param string $domain The domain name to say we are. | |
| 859 * | |
| 860 * @return mixed Returns a PEAR_Error with an error message on any | |
| 861 * kind of failure, or true on success. | |
| 862 * @since 1.0 | |
| 863 */ | |
| 864 public function helo($domain) | |
| 865 { | |
| 866 if (PEAR::isError($error = $this->put('HELO', $domain))) { | |
| 867 return $error; | |
| 868 } | |
| 869 if (PEAR::isError($error = $this->parseResponse(250))) { | |
| 870 return $error; | |
| 871 } | |
| 872 | |
| 873 return true; | |
| 874 } | |
| 875 | |
| 876 /** | |
| 877 * Return the list of SMTP service extensions advertised by the server. | |
| 878 * | |
| 879 * @return array The list of SMTP service extensions. | |
| 880 * @since 1.3 | |
| 881 */ | |
| 882 public function getServiceExtensions() | |
| 883 { | |
| 884 return $this->esmtp; | |
| 885 } | |
| 886 | |
| 887 /** | |
| 888 * Send the MAIL FROM: command. | |
| 889 * | |
| 890 * @param string $sender The sender (reverse path) to set. | |
| 891 * @param string $params String containing additional MAIL parameters, | |
| 892 * such as the NOTIFY flags defined by RFC 1891 | |
| 893 * or the VERP protocol. | |
| 894 * | |
| 895 * If $params is an array, only the 'verp' option | |
| 896 * is supported. If 'verp' is true, the XVERP | |
| 897 * parameter is appended to the MAIL command. | |
| 898 * If the 'verp' value is a string, the full | |
| 899 * XVERP=value parameter is appended. | |
| 900 * | |
| 901 * @return mixed Returns a PEAR_Error with an error message on any | |
| 902 * kind of failure, or true on success. | |
| 903 * @since 1.0 | |
| 904 */ | |
| 905 public function mailFrom($sender, $params = null) | |
| 906 { | |
| 907 $args = "FROM:<$sender>"; | |
| 908 | |
| 909 /* Support the deprecated array form of $params. */ | |
| 910 if (is_array($params) && isset($params['verp'])) { | |
| 911 if ($params['verp'] === true) { | |
| 912 $args .= ' XVERP'; | |
| 913 } elseif (trim($params['verp'])) { | |
| 914 $args .= ' XVERP=' . $params['verp']; | |
| 915 } | |
| 916 } elseif (is_string($params) && !empty($params)) { | |
| 917 $args .= ' ' . $params; | |
| 918 } | |
| 919 | |
| 920 if (PEAR::isError($error = $this->put('MAIL', $args))) { | |
| 921 return $error; | |
| 922 } | |
| 923 if (PEAR::isError($error = $this->parseResponse(250, $this->pipelining))) { | |
| 924 return $error; | |
| 925 } | |
| 926 | |
| 927 return true; | |
| 928 } | |
| 929 | |
| 930 /** | |
| 931 * Send the RCPT TO: command. | |
| 932 * | |
| 933 * @param string $recipient The recipient (forward path) to add. | |
| 934 * @param string $params String containing additional RCPT parameters, | |
| 935 * such as the NOTIFY flags defined by RFC 1891. | |
| 936 * | |
| 937 * @return mixed Returns a PEAR_Error with an error message on any | |
| 938 * kind of failure, or true on success. | |
| 939 * | |
| 940 * @since 1.0 | |
| 941 */ | |
| 942 public function rcptTo($recipient, $params = null) | |
| 943 { | |
| 944 $args = "TO:<$recipient>"; | |
| 945 if (is_string($params)) { | |
| 946 $args .= ' ' . $params; | |
| 947 } | |
| 948 | |
| 949 if (PEAR::isError($error = $this->put('RCPT', $args))) { | |
| 950 return $error; | |
| 951 } | |
| 952 if (PEAR::isError($error = $this->parseResponse(array(250, 251), $this->pipelining))) { | |
| 953 return $error; | |
| 954 } | |
| 955 | |
| 956 return true; | |
| 957 } | |
| 958 | |
| 959 /** | |
| 960 * Quote the data so that it meets SMTP standards. | |
| 961 * | |
| 962 * This is provided as a separate public function to facilitate | |
| 963 * easier overloading for the cases where it is desirable to | |
| 964 * customize the quoting behavior. | |
| 965 * | |
| 966 * @param string &$data The message text to quote. The string must be passed | |
| 967 * by reference, and the text will be modified in place. | |
| 968 * | |
| 969 * @since 1.2 | |
| 970 */ | |
| 971 public function quotedata(&$data) | |
| 972 { | |
| 973 /* Because a single leading period (.) signifies an end to the | |
| 974 * data, legitimate leading periods need to be "doubled" ('..'). */ | |
| 975 $data = preg_replace('/^\./m', '..', $data); | |
| 976 | |
| 977 /* Change Unix (\n) and Mac (\r) linefeeds into CRLF's (\r\n). */ | |
| 978 $data = preg_replace('/(?:\r\n|\n|\r(?!\n))/', "\r\n", $data); | |
| 979 } | |
| 980 | |
| 981 /** | |
| 982 * Send the DATA command. | |
| 983 * | |
| 984 * @param mixed $data The message data, either as a string or an open | |
| 985 * file resource. | |
| 986 * @param string $headers The message headers. If $headers is provided, | |
| 987 * $data is assumed to contain only body data. | |
| 988 * | |
| 989 * @return mixed Returns a PEAR_Error with an error message on any | |
| 990 * kind of failure, or true on success. | |
| 991 * @since 1.0 | |
| 992 */ | |
| 993 public function data($data, $headers = null) | |
| 994 { | |
| 995 /* Verify that $data is a supported type. */ | |
| 996 if (!is_string($data) && !is_resource($data)) { | |
| 997 return PEAR::raiseError('Expected a string or file resource'); | |
| 998 } | |
| 999 | |
| 1000 /* Start by considering the size of the optional headers string. We | |
| 1001 * also account for the addition 4 character "\r\n\r\n" separator | |
| 1002 * sequence. */ | |
| 1003 $size = $headers_size = (is_null($headers)) ? 0 : strlen($headers) + 4; | |
| 1004 | |
| 1005 if (is_resource($data)) { | |
| 1006 $stat = fstat($data); | |
| 1007 if ($stat === false) { | |
| 1008 return PEAR::raiseError('Failed to get file size'); | |
| 1009 } | |
| 1010 $size += $stat['size']; | |
| 1011 } else { | |
| 1012 $size += strlen($data); | |
| 1013 } | |
| 1014 | |
| 1015 /* RFC 1870, section 3, subsection 3 states "a value of zero indicates | |
| 1016 * that no fixed maximum message size is in force". Furthermore, it | |
| 1017 * says that if "the parameter is omitted no information is conveyed | |
| 1018 * about the server's fixed maximum message size". */ | |
| 1019 $limit = (isset($this->esmtp['SIZE'])) ? $this->esmtp['SIZE'] : 0; | |
| 1020 if ($limit > 0 && $size >= $limit) { | |
| 1021 $this->disconnect(); | |
| 1022 return PEAR::raiseError('Message size exceeds server limit'); | |
| 1023 } | |
| 1024 | |
| 1025 /* Initiate the DATA command. */ | |
| 1026 if (PEAR::isError($error = $this->put('DATA'))) { | |
| 1027 return $error; | |
| 1028 } | |
| 1029 if (PEAR::isError($error = $this->parseResponse(354))) { | |
| 1030 return $error; | |
| 1031 } | |
| 1032 | |
| 1033 /* If we have a separate headers string, send it first. */ | |
| 1034 if (!is_null($headers)) { | |
| 1035 $this->quotedata($headers); | |
| 1036 if (PEAR::isError($result = $this->send($headers . "\r\n\r\n"))) { | |
| 1037 return $result; | |
| 1038 } | |
| 1039 | |
| 1040 /* Subtract the headers size now that they've been sent. */ | |
| 1041 $size -= $headers_size; | |
| 1042 } | |
| 1043 | |
| 1044 /* Now we can send the message body data. */ | |
| 1045 if (is_resource($data)) { | |
| 1046 /* Stream the contents of the file resource out over our socket | |
| 1047 * connection, line by line. Each line must be run through the | |
| 1048 * quoting routine. */ | |
| 1049 while (strlen($line = fread($data, 8192)) > 0) { | |
| 1050 /* If the last character is an newline, we need to grab the | |
| 1051 * next character to check to see if it is a period. */ | |
| 1052 while (!feof($data)) { | |
| 1053 $char = fread($data, 1); | |
| 1054 $line .= $char; | |
| 1055 if ($char != "\n") { | |
| 1056 break; | |
| 1057 } | |
| 1058 } | |
| 1059 $this->quotedata($line); | |
| 1060 if (PEAR::isError($result = $this->send($line))) { | |
| 1061 return $result; | |
| 1062 } | |
| 1063 } | |
| 1064 | |
| 1065 $last = $line; | |
| 1066 } else { | |
| 1067 /* | |
| 1068 * Break up the data by sending one chunk (up to 512k) at a time. | |
| 1069 * This approach reduces our peak memory usage. | |
| 1070 */ | |
| 1071 for ($offset = 0; $offset < $size;) { | |
| 1072 $end = $offset + 512000; | |
| 1073 | |
| 1074 /* | |
| 1075 * Ensure we don't read beyond our data size or span multiple | |
| 1076 * lines. quotedata() can't properly handle character data | |
| 1077 * that's split across two line break boundaries. | |
| 1078 */ | |
| 1079 if ($end >= $size) { | |
| 1080 $end = $size; | |
| 1081 } else { | |
| 1082 for (; $end < $size; $end++) { | |
| 1083 if ($data[$end] != "\n") { | |
| 1084 break; | |
| 1085 } | |
| 1086 } | |
| 1087 } | |
| 1088 | |
| 1089 /* Extract our chunk and run it through the quoting routine. */ | |
| 1090 $chunk = substr($data, $offset, $end - $offset); | |
| 1091 $this->quotedata($chunk); | |
| 1092 | |
| 1093 /* If we run into a problem along the way, abort. */ | |
| 1094 if (PEAR::isError($result = $this->send($chunk))) { | |
| 1095 return $result; | |
| 1096 } | |
| 1097 | |
| 1098 /* Advance the offset to the end of this chunk. */ | |
| 1099 $offset = $end; | |
| 1100 } | |
| 1101 | |
| 1102 $last = $chunk; | |
| 1103 } | |
| 1104 | |
| 1105 /* Don't add another CRLF sequence if it's already in the data */ | |
| 1106 $terminator = (substr($last, -2) == "\r\n" ? '' : "\r\n") . ".\r\n"; | |
| 1107 | |
| 1108 /* Finally, send the DATA terminator sequence. */ | |
| 1109 if (PEAR::isError($result = $this->send($terminator))) { | |
| 1110 return $result; | |
| 1111 } | |
| 1112 | |
| 1113 /* Verify that the data was successfully received by the server. */ | |
| 1114 if (PEAR::isError($error = $this->parseResponse(250, $this->pipelining))) { | |
| 1115 return $error; | |
| 1116 } | |
| 1117 | |
| 1118 return true; | |
| 1119 } | |
| 1120 | |
| 1121 /** | |
| 1122 * Send the SEND FROM: command. | |
| 1123 * | |
| 1124 * @param string $path The reverse path to send. | |
| 1125 * | |
| 1126 * @return mixed Returns a PEAR_Error with an error message on any | |
| 1127 * kind of failure, or true on success. | |
| 1128 * @since 1.2.6 | |
| 1129 */ | |
| 1130 public function sendFrom($path) | |
| 1131 { | |
| 1132 if (PEAR::isError($error = $this->put('SEND', "FROM:<$path>"))) { | |
| 1133 return $error; | |
| 1134 } | |
| 1135 if (PEAR::isError($error = $this->parseResponse(250, $this->pipelining))) { | |
| 1136 return $error; | |
| 1137 } | |
| 1138 | |
| 1139 return true; | |
| 1140 } | |
| 1141 | |
| 1142 /** | |
| 1143 * Send the SOML FROM: command. | |
| 1144 * | |
| 1145 * @param string $path The reverse path to send. | |
| 1146 * | |
| 1147 * @return mixed Returns a PEAR_Error with an error message on any | |
| 1148 * kind of failure, or true on success. | |
| 1149 * @since 1.2.6 | |
| 1150 */ | |
| 1151 public function somlFrom($path) | |
| 1152 { | |
| 1153 if (PEAR::isError($error = $this->put('SOML', "FROM:<$path>"))) { | |
| 1154 return $error; | |
| 1155 } | |
| 1156 if (PEAR::isError($error = $this->parseResponse(250, $this->pipelining))) { | |
| 1157 return $error; | |
| 1158 } | |
| 1159 | |
| 1160 return true; | |
| 1161 } | |
| 1162 | |
| 1163 /** | |
| 1164 * Send the SAML FROM: command. | |
| 1165 * | |
| 1166 * @param string $path The reverse path to send. | |
| 1167 * | |
| 1168 * @return mixed Returns a PEAR_Error with an error message on any | |
| 1169 * kind of failure, or true on success. | |
| 1170 * @since 1.2.6 | |
| 1171 */ | |
| 1172 public function samlFrom($path) | |
| 1173 { | |
| 1174 if (PEAR::isError($error = $this->put('SAML', "FROM:<$path>"))) { | |
| 1175 return $error; | |
| 1176 } | |
| 1177 if (PEAR::isError($error = $this->parseResponse(250, $this->pipelining))) { | |
| 1178 return $error; | |
| 1179 } | |
| 1180 | |
| 1181 return true; | |
| 1182 } | |
| 1183 | |
| 1184 /** | |
| 1185 * Send the RSET command. | |
| 1186 * | |
| 1187 * @return mixed Returns a PEAR_Error with an error message on any | |
| 1188 * kind of failure, or true on success. | |
| 1189 * @since 1.0 | |
| 1190 */ | |
| 1191 public function rset() | |
| 1192 { | |
| 1193 if (PEAR::isError($error = $this->put('RSET'))) { | |
| 1194 return $error; | |
| 1195 } | |
| 1196 if (PEAR::isError($error = $this->parseResponse(250, $this->pipelining))) { | |
| 1197 return $error; | |
| 1198 } | |
| 1199 | |
| 1200 return true; | |
| 1201 } | |
| 1202 | |
| 1203 /** | |
| 1204 * Send the VRFY command. | |
| 1205 * | |
| 1206 * @param string $string The string to verify | |
| 1207 * | |
| 1208 * @return mixed Returns a PEAR_Error with an error message on any | |
| 1209 * kind of failure, or true on success. | |
| 1210 * @since 1.0 | |
| 1211 */ | |
| 1212 public function vrfy($string) | |
| 1213 { | |
| 1214 /* Note: 251 is also a valid response code */ | |
| 1215 if (PEAR::isError($error = $this->put('VRFY', $string))) { | |
| 1216 return $error; | |
| 1217 } | |
| 1218 if (PEAR::isError($error = $this->parseResponse(array(250, 252)))) { | |
| 1219 return $error; | |
| 1220 } | |
| 1221 | |
| 1222 return true; | |
| 1223 } | |
| 1224 | |
| 1225 /** | |
| 1226 * Send the NOOP command. | |
| 1227 * | |
| 1228 * @return mixed Returns a PEAR_Error with an error message on any | |
| 1229 * kind of failure, or true on success. | |
| 1230 * @since 1.0 | |
| 1231 */ | |
| 1232 public function noop() | |
| 1233 { | |
| 1234 if (PEAR::isError($error = $this->put('NOOP'))) { | |
| 1235 return $error; | |
| 1236 } | |
| 1237 if (PEAR::isError($error = $this->parseResponse(250))) { | |
| 1238 return $error; | |
| 1239 } | |
| 1240 | |
| 1241 return true; | |
| 1242 } | |
| 1243 | |
| 1244 /** | |
| 1245 * Backwards-compatibility method. identifySender()'s functionality is | |
| 1246 * now handled internally. | |
| 1247 * | |
| 1248 * @return boolean This method always return true. | |
| 1249 * | |
| 1250 * @since 1.0 | |
| 1251 */ | |
| 1252 public function identifySender() | |
| 1253 { | |
| 1254 return true; | |
| 1255 } | |
| 1256 } |
