~canonical-sysadmins/wordpress/4.6

« back to all changes in this revision

Viewing changes to wp-includes/class-smtp.php

  • Committer: Ryan Finnie
  • Date: 2015-08-31 16:09:47 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: ryan.finnie@canonical.com-20150831160947-1h6rfxby9z1ec62u
Merge WP4.3 from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
<?php
2
2
/**
3
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>
 
4
 * PHP Version 5
 
5
 * @package PHPMailer
 
6
 * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
 
7
 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
10
8
 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
11
9
 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
12
 
 * @copyright 2013 Marcus Bointon
13
 
 * @copyright 2004 - 2008 Andy Prevost
 
10
 * @author Brent R. Matzelle (original founder)
 
11
 * @copyright 2014 Marcus Bointon
14
12
 * @copyright 2010 - 2012 Jim Jagielski
15
 
 * @license   http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
 
13
 * @copyright 2004 - 2009 Andy Prevost
 
14
 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
 
15
 * @note This program is distributed in the hope that it will be useful - WITHOUT
 
16
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
17
 * FITNESS FOR A PARTICULAR PURPOSE.
16
18
 */
17
19
 
18
20
/**
19
21
 * 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)
 
22
 * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server.
 
23
 * @package PHPMailer
 
24
 * @author Chris Ryan
 
25
 * @author Marcus Bointon <phpmailer@synchromedia.co.uk>
32
26
 */
33
 
 
34
27
class SMTP
35
28
{
36
29
    /**
37
 
     * The PHPMailer SMTP Version number.
 
30
     * The PHPMailer SMTP version number.
 
31
     * @type string
38
32
     */
39
 
    const VERSION = '5.2.7';
 
33
    const VERSION = '5.2.10';
40
34
 
41
35
    /**
42
36
     * SMTP line break constant.
 
37
     * @type string
43
38
     */
44
39
    const CRLF = "\r\n";
45
40
 
46
41
    /**
47
42
     * The SMTP port to use if one is not specified.
 
43
     * @type integer
48
44
     */
49
45
    const DEFAULT_SMTP_PORT = 25;
50
46
 
51
47
    /**
 
48
     * The maximum line length allowed by RFC 2822 section 2.1.1
 
49
     * @type integer
 
50
     */
 
51
    const MAX_LINE_LENGTH = 998;
 
52
 
 
53
    /**
 
54
     * Debug level for no output
 
55
     */
 
56
    const DEBUG_OFF = 0;
 
57
 
 
58
    /**
 
59
     * Debug level to show client -> server messages
 
60
     */
 
61
    const DEBUG_CLIENT = 1;
 
62
 
 
63
    /**
 
64
     * Debug level to show client -> server and server -> client messages
 
65
     */
 
66
    const DEBUG_SERVER = 2;
 
67
 
 
68
    /**
 
69
     * Debug level to show connection status, client -> server and server -> client messages
 
70
     */
 
71
    const DEBUG_CONNECTION = 3;
 
72
 
 
73
    /**
 
74
     * Debug level to show all messages
 
75
     */
 
76
    const DEBUG_LOWLEVEL = 4;
 
77
 
 
78
    /**
52
79
     * The PHPMailer SMTP Version number.
53
80
     * @type string
54
 
     * @deprecated This should be a constant
 
81
     * @deprecated Use the `VERSION` constant instead
55
82
     * @see SMTP::VERSION
56
83
     */
57
 
    public $Version = '5.2.7';
 
84
    public $Version = '5.2.10';
58
85
 
59
86
    /**
60
87
     * SMTP server port number.
61
 
     * @type int
62
 
     * @deprecated This is only ever ued as default value, so should be a constant
 
88
     * @type integer
 
89
     * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead
63
90
     * @see SMTP::DEFAULT_SMTP_PORT
64
91
     */
65
92
    public $SMTP_PORT = 25;
66
93
 
67
94
    /**
68
 
     * SMTP reply line ending
 
95
     * SMTP reply line ending.
69
96
     * @type string
70
 
     * @deprecated Use the class constant instead
 
97
     * @deprecated Use the `CRLF` constant instead
71
98
     * @see SMTP::CRLF
72
99
     */
73
100
    public $CRLF = "\r\n";
74
101
 
75
102
    /**
76
103
     * Debug output level.
77
 
     * Options: 0 for no output, 1 for commands, 2 for data and commands
78
 
     * @type int
 
104
     * Options:
 
105
     * * self::DEBUG_OFF (`0`) No debug output, default
 
106
     * * self::DEBUG_CLIENT (`1`) Client commands
 
107
     * * self::DEBUG_SERVER (`2`) Client commands and server responses
 
108
     * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status
 
109
     * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages
 
110
     * @type integer
79
111
     */
80
 
    public $do_debug = 0;
 
112
    public $do_debug = self::DEBUG_OFF;
81
113
 
82
114
    /**
83
 
     * The function/method to use for debugging output.
84
 
     * Options: 'echo', 'html' or 'error_log'
85
 
     * @type string
 
115
     * How to handle debug output.
 
116
     * Options:
 
117
     * * `echo` Output plain-text as-is, appropriate for CLI
 
118
     * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
 
119
     * * `error_log` Output to error log as configured in php.ini
 
120
     *
 
121
     * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
 
122
     * <code>
 
123
     * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
 
124
     * </code>
 
125
     * @type string|callable
86
126
     */
87
127
    public $Debugoutput = 'echo';
88
128
 
89
129
    /**
90
130
     * Whether to use VERP.
91
 
     * @type bool
 
131
     * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
 
132
     * @link http://www.postfix.org/VERP_README.html Info on VERP
 
133
     * @type boolean
92
134
     */
93
135
    public $do_verp = false;
94
136
 
95
137
    /**
96
 
     * The SMTP timeout value for reads, in seconds.
97
 
     * @type int
 
138
     * The timeout value for connection, in seconds.
 
139
     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
 
140
     * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure.
 
141
     * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2
 
142
     * @type integer
98
143
     */
99
 
    public $Timeout = 15;
 
144
    public $Timeout = 300;
100
145
 
101
146
    /**
102
 
     * The SMTP timelimit value for reads, in seconds.
103
 
     * @type int
 
147
     * How long to wait for commands to complete, in seconds.
 
148
     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
 
149
     * @type integer
104
150
     */
105
 
    public $Timelimit = 30;
 
151
    public $Timelimit = 300;
106
152
 
107
153
    /**
108
154
     * The socket for the server connection.
111
157
    protected $smtp_conn;
112
158
 
113
159
    /**
114
 
     * Error message, if any, for the last call.
115
 
     * @type string
 
160
     * Error information, if any, for the last SMTP command.
 
161
     * @type array
116
162
     */
117
 
    protected $error = '';
 
163
    protected $error = array(
 
164
        'error' => '',
 
165
        'detail' => '',
 
166
        'smtp_code' => '',
 
167
        'smtp_code_ex' => ''
 
168
    );
118
169
 
119
170
    /**
120
171
     * The reply the server sent to us for HELO.
121
 
     * @type string
122
 
     */
123
 
    protected $helo_rply = '';
 
172
     * If null, no HELO string has yet been received.
 
173
     * @type string|null
 
174
     */
 
175
    protected $helo_rply = null;
 
176
 
 
177
    /**
 
178
     * The set of SMTP extensions sent in reply to EHLO command.
 
179
     * Indexes of the array are extension names.
 
180
     * Value at index 'HELO' or 'EHLO' (according to command that was sent)
 
181
     * represents the server name. In case of HELO it is the only element of the array.
 
182
     * Other values can be boolean TRUE or an array containing extension options.
 
183
     * If null, no HELO/EHLO string has yet been received.
 
184
     * @type array|null
 
185
     */
 
186
    protected $server_caps = null;
124
187
 
125
188
    /**
126
189
     * The most recent reply received from the server.
129
192
    protected $last_reply = '';
130
193
 
131
194
    /**
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
195
     * Output debugging info via a user-selected method.
 
196
     * @see SMTP::$Debugoutput
 
197
     * @see SMTP::$do_debug
146
198
     * @param string $str Debug string to output
 
199
     * @param integer $level The debug level of this message; see DEBUG_* constants
147
200
     * @return void
148
201
     */
149
 
    protected function edebug($str)
 
202
    protected function edebug($str, $level = 0)
150
203
    {
 
204
        if ($level > $this->do_debug) {
 
205
            return;
 
206
        }
 
207
        //Avoid clash with built-in function names
 
208
        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
 
209
            call_user_func($this->Debugoutput, $str, $this->do_debug);
 
210
            return;
 
211
        }
151
212
        switch ($this->Debugoutput) {
152
213
            case 'error_log':
153
214
                //Don't output, just log
164
225
                break;
165
226
            case 'echo':
166
227
            default:
167
 
                //Just echoes whatever was received
168
 
                echo $str;
 
228
                //Normalize line breaks
 
229
                $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
 
230
                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
 
231
                    "\n",
 
232
                    "\n                   \t                  ",
 
233
                    trim($str)
 
234
                )."\n";
169
235
        }
170
236
    }
171
237
 
172
238
    /**
173
239
     * 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
 
240
     * @param string $host SMTP server IP or host name
 
241
     * @param integer $port The port number to connect to
 
242
     * @param integer $timeout How long to wait for the connection to open
177
243
     * @param array $options An array of options for stream_context_create()
178
244
     * @access public
179
 
     * @return bool
 
245
     * @return boolean
180
246
     */
181
247
    public function connect($host, $port = null, $timeout = 30, $options = array())
182
248
    {
 
249
        static $streamok;
 
250
        //This is enabled by default since 5.0.0 but some providers disable it
 
251
        //Check this once and cache the result
 
252
        if (is_null($streamok)) {
 
253
            $streamok = function_exists('stream_socket_client');
 
254
        }
183
255
        // Clear errors to avoid confusion
184
 
        $this->error = null;
185
 
 
 
256
        $this->setError('');
186
257
        // Make sure we are __not__ connected
187
258
        if ($this->connected()) {
188
259
            // Already connected, generate error
189
 
            $this->error = array('error' => 'Already connected to a server');
 
260
            $this->setError('Already connected to a server');
190
261
            return false;
191
262
        }
192
 
 
193
263
        if (empty($port)) {
194
264
            $port = self::DEFAULT_SMTP_PORT;
195
265
        }
196
 
 
197
266
        // Connect to the SMTP server
 
267
        $this->edebug(
 
268
            "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true),
 
269
            self::DEBUG_CONNECTION
 
270
        );
198
271
        $errno = 0;
199
272
        $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
 
 
 
273
        if ($streamok) {
 
274
            $socket_context = stream_context_create($options);
 
275
            //Suppress errors; connection failures are handled at a higher level
 
276
            $this->smtp_conn = @stream_socket_client(
 
277
                $host . ":" . $port,
 
278
                $errno,
 
279
                $errstr,
 
280
                $timeout,
 
281
                STREAM_CLIENT_CONNECT,
 
282
                $socket_context
 
283
            );
 
284
        } else {
 
285
            //Fall back to fsockopen which should work in more places, but is missing some features
 
286
            $this->edebug(
 
287
                "Connection: stream_socket_client not available, falling back to fsockopen",
 
288
                self::DEBUG_CONNECTION
 
289
            );
 
290
            $this->smtp_conn = fsockopen(
 
291
                $host,
 
292
                $port,
 
293
                $errno,
 
294
                $errstr,
 
295
                $timeout
 
296
            );
 
297
        }
211
298
        // 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
 
            }
 
299
        if (!is_resource($this->smtp_conn)) {
 
300
            $this->setError(
 
301
                'Failed to connect to server',
 
302
                $errno,
 
303
                $errstr
 
304
            );
 
305
            $this->edebug(
 
306
                'SMTP ERROR: ' . $this->error['error']
 
307
                . ": $errstr ($errno)",
 
308
                self::DEBUG_CLIENT
 
309
            );
224
310
            return false;
225
311
        }
226
 
 
 
312
        $this->edebug('Connection: opened', self::DEBUG_CONNECTION);
227
313
        // SMTP server can take longer to respond, give longer timeout for first read
228
314
        // Windows does not have support for this timeout function
229
315
        if (substr(PHP_OS, 0, 3) != 'WIN') {
230
316
            $max = ini_get('max_execution_time');
231
 
            if ($max != 0 && $timeout > $max) { // Don't bother if unlimited
 
317
            // Don't bother if unlimited
 
318
            if ($max != 0 && $timeout > $max) {
232
319
                @set_time_limit($timeout);
233
320
            }
234
321
            stream_set_timeout($this->smtp_conn, $timeout, 0);
235
322
        }
236
 
 
237
323
        // Get any announcement
238
324
        $announce = $this->get_lines();
239
 
 
240
 
        if ($this->do_debug >= 2) {
241
 
            $this->edebug('SMTP -> FROM SERVER:' . $announce);
242
 
        }
243
 
 
 
325
        $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
244
326
        return true;
245
327
    }
246
328
 
247
329
    /**
248
330
     * Initiate a TLS (encrypted) session.
249
331
     * @access public
250
 
     * @return bool
 
332
     * @return boolean
251
333
     */
252
334
    public function startTLS()
253
335
    {
254
 
        if (!$this->sendCommand("STARTTLS", "STARTTLS", 220)) {
 
336
        if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
255
337
            return false;
256
338
        }
257
339
        // Begin encrypted connection
259
341
            $this->smtp_conn,
260
342
            true,
261
343
            STREAM_CRYPTO_METHOD_TLS_CLIENT
262
 
        )
263
 
        ) {
 
344
        )) {
264
345
            return false;
265
346
        }
266
347
        return true;
276
357
     * @param string $realm       The auth realm for NTLM
277
358
     * @param string $workstation The auth workstation for NTLM
278
359
     * @access public
279
 
     * @return bool True if successfully authenticated.
 
360
     * @return boolean True if successfully authenticated.
280
361
     */
281
362
    public function authenticate(
282
363
        $username,
283
364
        $password,
284
 
        $authtype = 'LOGIN',
 
365
        $authtype = null,
285
366
        $realm = '',
286
367
        $workstation = ''
287
368
    ) {
288
 
        if (empty($authtype)) {
 
369
        if (!$this->server_caps) {
 
370
            $this->setError('Authentication is not allowed before HELO/EHLO');
 
371
            return false;
 
372
        }
 
373
 
 
374
        if (array_key_exists('EHLO', $this->server_caps)) {
 
375
        // SMTP extensions are available. Let's try to find a proper authentication method
 
376
 
 
377
            if (!array_key_exists('AUTH', $this->server_caps)) {
 
378
                $this->setError('Authentication is not allowed at this stage');
 
379
                // 'at this stage' means that auth may be allowed after the stage changes
 
380
                // e.g. after STARTTLS
 
381
                return false;
 
382
            }
 
383
 
 
384
            self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL);
 
385
            self::edebug(
 
386
                'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']),
 
387
                self::DEBUG_LOWLEVEL
 
388
            );
 
389
 
 
390
            if (empty($authtype)) {
 
391
                foreach (array('LOGIN', 'CRAM-MD5', 'PLAIN') as $method) {
 
392
                    if (in_array($method, $this->server_caps['AUTH'])) {
 
393
                        $authtype = $method;
 
394
                        break;
 
395
                    }
 
396
                }
 
397
                if (empty($authtype)) {
 
398
                    $this->setError('No supported authentication methods found');
 
399
                    return false;
 
400
                }
 
401
                self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL);
 
402
            }
 
403
 
 
404
            if (!in_array($authtype, $this->server_caps['AUTH'])) {
 
405
                $this->setError("The requested authentication method \"$authtype\" is not supported by the server");
 
406
                return false;
 
407
            }
 
408
        } elseif (empty($authtype)) {
289
409
            $authtype = 'LOGIN';
290
410
        }
291
 
 
292
411
        switch ($authtype) {
293
412
            case 'PLAIN':
294
413
                // Start authentication
317
436
                    return false;
318
437
                }
319
438
                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
439
            case 'CRAM-MD5':
374
440
                // Start authentication
375
441
                if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
383
449
 
384
450
                // send encoded credentials
385
451
                return $this->sendCommand('Username', base64_encode($response), 235);
386
 
                break;
 
452
            default:
 
453
                $this->setError("Authentication method \"$authtype\" is not supported");
 
454
                return false;
387
455
        }
388
456
        return true;
389
457
    }
411
479
        // Eliminates the need to install mhash to compute a HMAC
412
480
        // by Lance Rushing
413
481
 
414
 
        $b = 64; // byte length for md5
415
 
        if (strlen($key) > $b) {
 
482
        $bytelen = 64; // byte length for md5
 
483
        if (strlen($key) > $bytelen) {
416
484
            $key = pack('H*', md5($key));
417
485
        }
418
 
        $key = str_pad($key, $b, chr(0x00));
419
 
        $ipad = str_pad('', $b, chr(0x36));
420
 
        $opad = str_pad('', $b, chr(0x5c));
 
486
        $key = str_pad($key, $bytelen, chr(0x00));
 
487
        $ipad = str_pad('', $bytelen, chr(0x36));
 
488
        $opad = str_pad('', $bytelen, chr(0x5c));
421
489
        $k_ipad = $key ^ $ipad;
422
490
        $k_opad = $key ^ $opad;
423
491
 
427
495
    /**
428
496
     * Check connection state.
429
497
     * @access public
430
 
     * @return bool True if connected.
 
498
     * @return boolean True if connected.
431
499
     */
432
500
    public function connected()
433
501
    {
434
 
        if (!empty($this->smtp_conn)) {
 
502
        if (is_resource($this->smtp_conn)) {
435
503
            $sock_status = stream_get_meta_data($this->smtp_conn);
436
504
            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
 
                }
 
505
                // The socket is valid but we are not connected
 
506
                $this->edebug(
 
507
                    'SMTP NOTICE: EOF caught while checking if connected',
 
508
                    self::DEBUG_CLIENT
 
509
                );
443
510
                $this->close();
444
511
                return false;
445
512
            }
457
524
     */
458
525
    public function close()
459
526
    {
460
 
        $this->error = null; // so there is no confusion
 
527
        $this->setError('');
 
528
        $this->server_caps = null;
461
529
        $this->helo_rply = null;
462
 
        if (!empty($this->smtp_conn)) {
 
530
        if (is_resource($this->smtp_conn)) {
463
531
            // close the connection and cleanup
464
532
            fclose($this->smtp_conn);
465
 
            $this->smtp_conn = 0;
 
533
            $this->smtp_conn = null; //Makes for cleaner serialization
 
534
            $this->edebug('Connection: closed', self::DEBUG_CONNECTION);
466
535
        }
467
536
    }
468
537
 
476
545
     * Implements rfc 821: DATA <CRLF>
477
546
     * @param string $msg_data Message data to send
478
547
     * @access public
479
 
     * @return bool
 
548
     * @return boolean
480
549
     */
481
550
    public function data($msg_data)
482
551
    {
 
552
        //This will use the standard timelimit
483
553
        if (!$this->sendCommand('DATA', 'DATA', 354)) {
484
554
            return false;
485
555
        }
486
556
 
487
557
        /* 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.
 
558
         * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF)
 
559
         * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into
 
560
         * smaller lines to fit within the limit.
 
561
         * We will also look for lines that start with a '.' and prepend an additional '.'.
 
562
         * NOTE: this does not count towards line-length limit.
496
563
         */
497
564
 
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);
 
565
        // Normalize line breaks before exploding
 
566
        $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data));
502
567
 
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.
 
568
        /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
 
569
         * of the first line (':' separated) does not contain a space then it _should_ be a header and we will
 
570
         * process all lines before a blank line as headers.
510
571
         */
511
572
 
512
573
        $field = substr($lines[0], 0, strpos($lines[0], ':'));
513
574
        $in_headers = false;
514
 
        if (!empty($field) && !strstr($field, ' ')) {
 
575
        if (!empty($field) && strpos($field, ' ') === false) {
515
576
            $in_headers = true;
516
577
        }
517
578
 
518
 
        //RFC 2822 section 2.1.1 limit
519
 
        $max_line_length = 998;
520
 
 
521
579
        foreach ($lines as $line) {
522
 
            $lines_out = null;
523
 
            if ($line == '' && $in_headers) {
 
580
            $lines_out = array();
 
581
            if ($in_headers and $line == '') {
524
582
                $in_headers = false;
525
583
            }
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
 
584
            //Break this line up into several smaller lines if it's too long
 
585
            //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len),
 
586
            while (isset($line[self::MAX_LINE_LENGTH])) {
 
587
                //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on
 
588
                //so as to avoid breaking in the middle of a word
 
589
                $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' ');
 
590
                //Deliberately matches both false and 0
531
591
                if (!$pos) {
532
 
                    $pos = $max_line_length - 1;
 
592
                    //No nice break found, add a hard break
 
593
                    $pos = self::MAX_LINE_LENGTH - 1;
533
594
                    $lines_out[] = substr($line, 0, $pos);
534
595
                    $line = substr($line, $pos);
535
596
                } else {
 
597
                    //Break at the found point
536
598
                    $lines_out[] = substr($line, 0, $pos);
 
599
                    //Move along by the amount we dealt with
537
600
                    $line = substr($line, $pos + 1);
538
601
                }
539
 
 
540
 
                /* If processing headers add a LWSP-char to the front of new line
541
 
                 * rfc822 on long msg headers
542
 
                 */
 
602
                //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1
543
603
                if ($in_headers) {
544
604
                    $line = "\t" . $line;
545
605
                }
546
606
            }
547
607
            $lines_out[] = $line;
548
608
 
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
 
                    }
 
609
            //Send the lines to the server
 
610
            foreach ($lines_out as $line_out) {
 
611
                //RFC2821 section 4.5.2
 
612
                if (!empty($line_out) and $line_out[0] == '.') {
 
613
                    $line_out = '.' . $line_out;
555
614
                }
556
615
                $this->client_send($line_out . self::CRLF);
557
616
            }
558
617
        }
559
618
 
560
 
        // Message data has been sent, complete the command
561
 
        return $this->sendCommand('DATA END', '.', 250);
 
619
        //Message data has been sent, complete the command
 
620
        //Increase timelimit for end of DATA command
 
621
        $savetimelimit = $this->Timelimit;
 
622
        $this->Timelimit = $this->Timelimit * 2;
 
623
        $result = $this->sendCommand('DATA END', '.', 250);
 
624
        //Restore timelimit
 
625
        $this->Timelimit = $savetimelimit;
 
626
        return $result;
562
627
    }
563
628
 
564
629
    /**
565
630
     * Send an SMTP HELO or EHLO command.
566
631
     * Used to identify the sending server to the receiving server.
567
632
     * This makes sure that client and server are in a known state.
568
 
     * Implements from RFC 821: HELO <SP> <domain> <CRLF>
 
633
     * Implements RFC 821: HELO <SP> <domain> <CRLF>
569
634
     * and RFC 2821 EHLO.
570
635
     * @param string $host The host name or IP to connect to
571
636
     * @access public
572
 
     * @return bool
 
637
     * @return boolean
573
638
     */
574
639
    public function hello($host = '')
575
640
    {
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;
 
641
        //Try extended hello first (RFC 2821)
 
642
        return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host));
584
643
    }
585
644
 
586
645
    /**
588
647
     * Low-level implementation used by hello()
589
648
     * @see hello()
590
649
     * @param string $hello The HELO string
591
 
     * @param string $host  The hostname to say we are
 
650
     * @param string $host The hostname to say we are
592
651
     * @access protected
593
 
     * @return bool
 
652
     * @return boolean
594
653
     */
595
654
    protected function sendHello($hello, $host)
596
655
    {
597
656
        $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250);
598
657
        $this->helo_rply = $this->last_reply;
 
658
        if ($noerror) {
 
659
            $this->parseHelloFields($hello);
 
660
        } else {
 
661
            $this->server_caps = null;
 
662
        }
599
663
        return $noerror;
600
664
    }
601
665
 
602
666
    /**
 
667
     * Parse a reply to HELO/EHLO command to discover server extensions.
 
668
     * In case of HELO, the only parameter that can be discovered is a server name.
 
669
     * @access protected
 
670
     * @param string $type - 'HELO' or 'EHLO'
 
671
     */
 
672
    protected function parseHelloFields($type)
 
673
    {
 
674
        $this->server_caps = array();
 
675
        $lines = explode("\n", $this->last_reply);
 
676
        foreach ($lines as $n => $s) {
 
677
            $s = trim(substr($s, 4));
 
678
            if (!$s) {
 
679
                continue;
 
680
            }
 
681
            $fields = explode(' ', $s);
 
682
            if (!empty($fields)) {
 
683
                if (!$n) {
 
684
                    $name = $type;
 
685
                    $fields = $fields[0];
 
686
                } else {
 
687
                    $name = array_shift($fields);
 
688
                    if ($name == 'SIZE') {
 
689
                        $fields = ($fields) ? $fields[0] : 0;
 
690
                    }
 
691
                }
 
692
                $this->server_caps[$name] = ($fields ? $fields : true);
 
693
            }
 
694
        }
 
695
    }
 
696
 
 
697
    /**
603
698
     * Send an SMTP MAIL command.
604
699
     * Starts a mail transaction from the email address specified in
605
700
     * $from. Returns true if successful or false otherwise. If True
608
703
     * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
609
704
     * @param string $from Source address of this message
610
705
     * @access public
611
 
     * @return bool
 
706
     * @return boolean
612
707
     */
613
708
    public function mail($from)
614
709
    {
624
719
     * Send an SMTP QUIT command.
625
720
     * Closes the socket if there is no error or the $close_on_error argument is true.
626
721
     * Implements from rfc 821: QUIT <CRLF>
627
 
     * @param bool $close_on_error Should the connection close if an error occurs?
 
722
     * @param boolean $close_on_error Should the connection close if an error occurs?
628
723
     * @access public
629
 
     * @return bool
 
724
     * @return boolean
630
725
     */
631
726
    public function quit($close_on_error = true)
632
727
    {
633
728
        $noerror = $this->sendCommand('QUIT', 'QUIT', 221);
634
 
        $e = $this->error; //Save any error
 
729
        $err = $this->error; //Save any error
635
730
        if ($noerror or $close_on_error) {
636
731
            $this->close();
637
 
            $this->error = $e; //Restore any error from the quit command
 
732
            $this->error = $err; //Restore any error from the quit command
638
733
        }
639
734
        return $noerror;
640
735
    }
641
736
 
642
737
    /**
643
738
     * Send an SMTP RCPT command.
644
 
     * Sets the TO argument to $to.
 
739
     * Sets the TO argument to $toaddr.
645
740
     * Returns true if the recipient was accepted false if it was rejected.
646
741
     * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
647
 
     * @param string $to The address the message is being sent to
 
742
     * @param string $toaddr The address the message is being sent to
648
743
     * @access public
649
 
     * @return bool
 
744
     * @return boolean
650
745
     */
651
 
    public function recipient($to)
 
746
    public function recipient($toaddr)
652
747
    {
653
748
        return $this->sendCommand(
654
 
            'RCPT TO ',
655
 
            'RCPT TO:<' . $to . '>',
 
749
            'RCPT TO',
 
750
            'RCPT TO:<' . $toaddr . '>',
656
751
            array(250, 251)
657
752
        );
658
753
    }
662
757
     * Abort any transaction that is currently in progress.
663
758
     * Implements rfc 821: RSET <CRLF>
664
759
     * @access public
665
 
     * @return bool True on success.
 
760
     * @return boolean True on success.
666
761
     */
667
762
    public function reset()
668
763
    {
673
768
     * Send a command to an SMTP server and check its return code.
674
769
     * @param string $command       The command name - not sent to the server
675
770
     * @param string $commandstring The actual command to send
676
 
     * @param int|array $expect     One or more expected integer success codes
 
771
     * @param integer|array $expect     One or more expected integer success codes
677
772
     * @access protected
678
 
     * @return bool True on success.
 
773
     * @return boolean True on success.
679
774
     */
680
775
    protected function sendCommand($command, $commandstring, $expect)
681
776
    {
682
777
        if (!$this->connected()) {
683
 
            $this->error = array(
684
 
                "error" => "Called $command without being connected"
685
 
            );
 
778
            $this->setError("Called $command without being connected");
686
779
            return false;
687
780
        }
688
781
        $this->client_send($commandstring . self::CRLF);
689
782
 
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);
 
783
        $this->last_reply = $this->get_lines();
 
784
        // Fetch SMTP code and possible error code explanation
 
785
        $matches = array();
 
786
        if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) {
 
787
            $code = $matches[1];
 
788
            $code_ex = (count($matches) > 2 ? $matches[2] : null);
 
789
            // Cut off error code from each response line
 
790
            $detail = preg_replace(
 
791
                "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m",
 
792
                '',
 
793
                $this->last_reply
 
794
            );
 
795
        } else {
 
796
            // Fall back to simple parsing if regex fails
 
797
            $code = substr($this->last_reply, 0, 3);
 
798
            $code_ex = null;
 
799
            $detail = substr($this->last_reply, 4);
695
800
        }
696
801
 
 
802
        $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
 
803
 
697
804
        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
 
            }
 
805
            $this->setError(
 
806
                "$command command failed",
 
807
                $detail,
 
808
                $code,
 
809
                $code_ex
 
810
            );
 
811
            $this->edebug(
 
812
                'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply,
 
813
                self::DEBUG_CLIENT
 
814
            );
709
815
            return false;
710
816
        }
711
817
 
712
 
        $this->last_reply = $reply;
713
 
        $this->error = null;
 
818
        $this->setError('');
714
819
        return true;
715
820
    }
716
821
 
725
830
     * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
726
831
     * @param string $from The address the message is from
727
832
     * @access public
728
 
     * @return bool
 
833
     * @return boolean
729
834
     */
730
835
    public function sendAndMail($from)
731
836
    {
732
 
        return $this->sendCommand("SAML", "SAML FROM:$from", 250);
 
837
        return $this->sendCommand('SAML', "SAML FROM:$from", 250);
733
838
    }
734
839
 
735
840
    /**
736
841
     * Send an SMTP VRFY command.
737
842
     * @param string $name The name to verify
738
843
     * @access public
739
 
     * @return bool
 
844
     * @return boolean
740
845
     */
741
846
    public function verify($name)
742
847
    {
743
 
        return $this->sendCommand("VRFY", "VRFY $name", array(250, 251));
 
848
        return $this->sendCommand('VRFY', "VRFY $name", array(250, 251));
744
849
    }
745
850
 
746
851
    /**
747
852
     * Send an SMTP NOOP command.
748
853
     * Used to keep keep-alives alive, doesn't actually do anything
749
854
     * @access public
750
 
     * @return bool
 
855
     * @return boolean
751
856
     */
752
857
    public function noop()
753
858
    {
754
 
        return $this->sendCommand("NOOP", "NOOP", 250);
 
859
        return $this->sendCommand('NOOP', 'NOOP', 250);
755
860
    }
756
861
 
757
862
    /**
758
863
     * Send an SMTP TURN command.
759
864
     * 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
 
865
     * This method is here to make the RFC821 Definition complete for this class
 
866
     * and _may_ be implemented in future
762
867
     * Implements from rfc 821: TURN <CRLF>
763
868
     * @access public
764
 
     * @return bool
 
869
     * @return boolean
765
870
     */
766
871
    public function turn()
767
872
    {
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
 
        }
 
873
        $this->setError('The SMTP TURN command is not implemented');
 
874
        $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT);
774
875
        return false;
775
876
    }
776
877
 
778
879
     * Send raw data to the server.
779
880
     * @param string $data The data to send
780
881
     * @access public
781
 
     * @return int|bool The number of bytes sent to the server or FALSE on error
 
882
     * @return integer|boolean The number of bytes sent to the server or false on error
782
883
     */
783
884
    public function client_send($data)
784
885
    {
785
 
        if ($this->do_debug >= 1) {
786
 
            $this->edebug("CLIENT -> SMTP: $data");
787
 
        }
 
886
        $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
788
887
        return fwrite($this->smtp_conn, $data);
789
888
    }
790
889
 
799
898
    }
800
899
 
801
900
    /**
 
901
     * Get SMTP extensions available on the server
 
902
     * @access public
 
903
     * @return array|null
 
904
     */
 
905
    public function getServerExtList()
 
906
    {
 
907
        return $this->server_caps;
 
908
    }
 
909
 
 
910
    /**
 
911
     * A multipurpose method
 
912
     * The method works in three ways, dependent on argument value and current state
 
913
     *   1. HELO/EHLO was not sent - returns null and set up $this->error
 
914
     *   2. HELO was sent
 
915
     *     $name = 'HELO': returns server name
 
916
     *     $name = 'EHLO': returns boolean false
 
917
     *     $name = any string: returns null and set up $this->error
 
918
     *   3. EHLO was sent
 
919
     *     $name = 'HELO'|'EHLO': returns server name
 
920
     *     $name = any string: if extension $name exists, returns boolean True
 
921
     *       or its options. Otherwise returns boolean False
 
922
     * In other words, one can use this method to detect 3 conditions:
 
923
     *  - null returned: handshake was not or we don't know about ext (refer to $this->error)
 
924
     *  - false returned: the requested feature exactly not exists
 
925
     *  - positive value returned: the requested feature exists
 
926
     * @param string $name Name of SMTP extension or 'HELO'|'EHLO'
 
927
     * @return mixed
 
928
     */
 
929
    public function getServerExt($name)
 
930
    {
 
931
        if (!$this->server_caps) {
 
932
            $this->setError('No HELO/EHLO was sent');
 
933
            return null;
 
934
        }
 
935
 
 
936
        // the tight logic knot ;)
 
937
        if (!array_key_exists($name, $this->server_caps)) {
 
938
            if ($name == 'HELO') {
 
939
                return $this->server_caps['EHLO'];
 
940
            }
 
941
            if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) {
 
942
                return false;
 
943
            }
 
944
            $this->setError('HELO handshake was used. Client knows nothing about server extensions');
 
945
            return null;
 
946
        }
 
947
 
 
948
        return $this->server_caps[$name];
 
949
    }
 
950
 
 
951
    /**
802
952
     * Get the last reply from the server.
803
953
     * @access public
804
954
     * @return string
819
969
     */
820
970
    protected function get_lines()
821
971
    {
 
972
        // If the connection is bad, give up straight away
 
973
        if (!is_resource($this->smtp_conn)) {
 
974
            return '';
 
975
        }
822
976
        $data = '';
823
977
        $endtime = 0;
824
 
        // If the connection is bad, give up now
825
 
        if (!is_resource($this->smtp_conn)) {
826
 
            return $data;
827
 
        }
828
978
        stream_set_timeout($this->smtp_conn, $this->Timeout);
829
979
        if ($this->Timelimit > 0) {
830
980
            $endtime = time() + $this->Timelimit;
831
981
        }
832
982
        while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
833
983
            $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
 
            }
 
984
            $this->edebug("SMTP -> get_lines(): \$data was \"$data\"", self::DEBUG_LOWLEVEL);
 
985
            $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
838
986
            $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) == ' ') {
 
987
            $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
 
988
            // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen
 
989
            if ((isset($str[3]) and $str[3] == ' ')) {
844
990
                break;
845
991
            }
846
992
            // Timed-out? Log and break
847
993
            $info = stream_get_meta_data($this->smtp_conn);
848
994
            if ($info['timed_out']) {
849
 
                if ($this->do_debug >= 4) {
850
 
                    $this->edebug(
851
 
                        'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)'
852
 
                    );
853
 
                }
 
995
                $this->edebug(
 
996
                    'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)',
 
997
                    self::DEBUG_LOWLEVEL
 
998
                );
854
999
                break;
855
1000
            }
856
1001
            // 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
 
                }
 
1002
            if ($endtime and time() > $endtime) {
 
1003
                $this->edebug(
 
1004
                    'SMTP -> get_lines(): timelimit reached ('.
 
1005
                    $this->Timelimit . ' sec)',
 
1006
                    self::DEBUG_LOWLEVEL
 
1007
                );
 
1008
                break;
867
1009
            }
868
1010
        }
869
1011
        return $data;
871
1013
 
872
1014
    /**
873
1015
     * Enable or disable VERP address generation.
874
 
     * @param bool $enabled
 
1016
     * @param boolean $enabled
875
1017
     */
876
1018
    public function setVerp($enabled = false)
877
1019
    {
880
1022
 
881
1023
    /**
882
1024
     * Get VERP address generation mode.
883
 
     * @return bool
 
1025
     * @return boolean
884
1026
     */
885
1027
    public function getVerp()
886
1028
    {
888
1030
    }
889
1031
 
890
1032
    /**
 
1033
     * Set error messages and codes.
 
1034
     * @param string $message The error message
 
1035
     * @param string $detail Further detail on the error
 
1036
     * @param string $smtp_code An associated SMTP error code
 
1037
     * @param string $smtp_code_ex Extended SMTP code
 
1038
     */
 
1039
    protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '')
 
1040
    {
 
1041
        $this->error = array(
 
1042
            'error' => $message,
 
1043
            'detail' => $detail,
 
1044
            'smtp_code' => $smtp_code,
 
1045
            'smtp_code_ex' => $smtp_code_ex
 
1046
        );
 
1047
    }
 
1048
 
 
1049
    /**
891
1050
     * Set debug output method.
892
 
     * @param string $method The function/method to use for debugging output.
 
1051
     * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it.
893
1052
     */
894
1053
    public function setDebugOutput($method = 'echo')
895
1054
    {
907
1066
 
908
1067
    /**
909
1068
     * Set debug output level.
910
 
     * @param int $level
 
1069
     * @param integer $level
911
1070
     */
912
1071
    public function setDebugLevel($level = 0)
913
1072
    {
916
1075
 
917
1076
    /**
918
1077
     * Get debug output level.
919
 
     * @return int
 
1078
     * @return integer
920
1079
     */
921
1080
    public function getDebugLevel()
922
1081
    {
925
1084
 
926
1085
    /**
927
1086
     * Set SMTP timeout.
928
 
     * @param int $timeout
 
1087
     * @param integer $timeout
929
1088
     */
930
1089
    public function setTimeout($timeout = 0)
931
1090
    {
934
1093
 
935
1094
    /**
936
1095
     * Get SMTP timeout.
937
 
     * @return int
 
1096
     * @return integer
938
1097
     */
939
1098
    public function getTimeout()
940
1099
    {