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