Project

General

Profile

1
<?php
2
////////////////////////////////////////////////////
3
// SMTP - PHP SMTP class
4
//
5
// Version 1.02
6
//
7
// Define an SMTP class that can be used to connect
8
// and communicate with any SMTP server. It implements
9
// all the SMTP functions defined in RFC821 except TURN.
10
//
11
// Author: Chris Ryan
12
//
13
// License: LGPL, see LICENSE
14
////////////////////////////////////////////////////
15

    
16
/**
17
 * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
18
 * commands except TURN which will always return a not implemented
19
 * error. SMTP also provides some utility methods for sending mail
20
 * to an SMTP server.
21
 * @package PHPMailer
22
 * @author Chris Ryan
23
 */
24
class SMTP
25
{
26
    /**
27
     *  SMTP server port
28
     *  @var int
29
     */
30
    var $SMTP_PORT = 25;
31
    
32
    /**
33
     *  SMTP reply line ending
34
     *  @var string
35
     */
36
    var $CRLF = "\r\n";
37
    
38
    /**
39
     *  Sets whether debugging is turned on
40
     *  @var bool
41
     */
42
    var $do_debug;       # the level of debug to perform
43

    
44
    /**#@+
45
     * @access private
46
     */
47
    var $smtp_conn;      # the socket to the server
48
    var $error;          # error if any on the last call
49
    var $helo_rply;      # the reply the server sent to us for HELO
50
    /**#@-*/
51

    
52
    /**
53
     * Initialize the class so that the data is in a known state.
54
     * @access public
55
     * @return void
56
     */
57
    function SMTP() {
58
        $this->smtp_conn = 0;
59
        $this->error = null;
60
        $this->helo_rply = null;
61

    
62
        $this->do_debug = 0;
63
    }
64

    
65
    /*************************************************************
66
     *                    CONNECTION FUNCTIONS                  *
67
     ***********************************************************/
68

    
69
    /**
70
     * Connect to the server specified on the port specified.
71
     * If the port is not specified use the default SMTP_PORT.
72
     * If tval is specified then a connection will try and be
73
     * established with the server for that number of seconds.
74
     * If tval is not specified the default is 30 seconds to
75
     * try on the connection.
76
     *
77
     * SMTP CODE SUCCESS: 220
78
     * SMTP CODE FAILURE: 421
79
     * @access public
80
     * @return bool
81
     */
82
    function Connect($host,$port=0,$tval=30) {
83
        # set the error val to null so there is no confusion
84
        $this->error = null;
85

    
86
        # make sure we are __not__ connected
87
        if($this->connected()) {
88
            # ok we are connected! what should we do?
89
            # for now we will just give an error saying we
90
            # are already connected
91
            $this->error =
92
                array("error" => "Already connected to a server");
93
            return false;
94
        }
95

    
96
        if(empty($port)) {
97
            $port = $this->SMTP_PORT;
98
        }
99

    
100
        #connect to the smtp server
101
        $this->smtp_conn = fsockopen($host,    # the host of the server
102
                                     $port,    # the port to use
103
                                     $errno,   # error number if any
104
                                     $errstr,  # error message if any
105
                                     $tval);   # give up after ? secs
106
        # verify we connected properly
107
        if(empty($this->smtp_conn)) {
108
            $this->error = array("error" => "Failed to connect to server",
109
                                 "errno" => $errno,
110
                                 "errstr" => $errstr);
111
            if($this->do_debug >= 1) {
112
                echo "SMTP -> ERROR: " . $this->error["error"] .
113
                         ": $errstr ($errno)" . $this->CRLF;
114
            }
115
            return false;
116
        }
117

    
118
        # sometimes the SMTP server takes a little longer to respond
119
        # so we will give it a longer timeout for the first read
120
        // Windows still does not have support for this timeout function
121
        if(substr(PHP_OS, 0, 3) != "WIN")
122
           socket_set_timeout($this->smtp_conn, $tval, 0);
123

    
124
        # get any announcement stuff
125
        $announce = $this->get_lines();
126

    
127
        # set the timeout  of any socket functions at 1/10 of a second
128
        //if(function_exists("socket_set_timeout"))
129
        //   socket_set_timeout($this->smtp_conn, 0, 100000);
130

    
131
        if($this->do_debug >= 2) {
132
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce;
133
        }
134

    
135
        return true;
136
    }
137

    
138
    /**
139
     * Performs SMTP authentication.  Must be run after running the
140
     * Hello() method.  Returns true if successfully authenticated.
141
     * @access public
142
     * @return bool
143
     */
144
    function Authenticate($username, $password) {
145
        // Start authentication
146
        fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
147

    
148
        $rply = $this->get_lines();
149
        $code = substr($rply,0,3);
150

    
151
        if($code != 334) {
152
            $this->error =
153
                array("error" => "AUTH not accepted from server",
154
                      "smtp_code" => $code,
155
                      "smtp_msg" => substr($rply,4));
156
            if($this->do_debug >= 1) {
157
                echo "SMTP -> ERROR: " . $this->error["error"] .
158
                         ": " . $rply . $this->CRLF;
159
            }
160
            return false;
161
        }
162

    
163
        // Send encoded username
164
        fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
165

    
166
        $rply = $this->get_lines();
167
        $code = substr($rply,0,3);
168

    
169
        if($code != 334) {
170
            $this->error =
171
                array("error" => "Username not accepted from server",
172
                      "smtp_code" => $code,
173
                      "smtp_msg" => substr($rply,4));
174
            if($this->do_debug >= 1) {
175
                echo "SMTP -> ERROR: " . $this->error["error"] .
176
                         ": " . $rply . $this->CRLF;
177
            }
178
            return false;
179
        }
180

    
181
        // Send encoded password
182
        fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
183

    
184
        $rply = $this->get_lines();
185
        $code = substr($rply,0,3);
186

    
187
        if($code != 235) {
188
            $this->error =
189
                array("error" => "Password not accepted from server",
190
                      "smtp_code" => $code,
191
                      "smtp_msg" => substr($rply,4));
192
            if($this->do_debug >= 1) {
193
                echo "SMTP -> ERROR: " . $this->error["error"] .
194
                         ": " . $rply . $this->CRLF;
195
            }
196
            return false;
197
        }
198

    
199
        return true;
200
    }
201

    
202
    /**
203
     * Returns true if connected to a server otherwise false
204
     * @access private
205
     * @return bool
206
     */
207
    function Connected() {
208
        if(!empty($this->smtp_conn)) {
209
            $sock_status = socket_get_status($this->smtp_conn);
210
            if($sock_status["eof"]) {
211
                # hmm this is an odd situation... the socket is
212
                # valid but we aren't connected anymore
213
                if($this->do_debug >= 1) {
214
                    echo "SMTP -> NOTICE:" . $this->CRLF .
215
                         "EOF caught while checking if connected";
216
                }
217
                $this->Close();
218
                return false;
219
            }
220
            return true; # everything looks good
221
        }
222
        return false;
223
    }
224

    
225
    /**
226
     * Closes the socket and cleans up the state of the class.
227
     * It is not considered good to use this function without
228
     * first trying to use QUIT.
229
     * @access public
230
     * @return void
231
     */
232
    function Close() {
233
        $this->error = null; # so there is no confusion
234
        $this->helo_rply = null;
235
        if(!empty($this->smtp_conn)) {
236
            # close the connection and cleanup
237
            fclose($this->smtp_conn);
238
            $this->smtp_conn = 0;
239
        }
240
    }
241

    
242

    
243
    /***************************************************************
244
     *                        SMTP COMMANDS                       *
245
     *************************************************************/
246

    
247
    /**
248
     * Issues a data command and sends the msg_data to the server
249
     * finializing the mail transaction. $msg_data is the message
250
     * that is to be send with the headers. Each header needs to be
251
     * on a single line followed by a <CRLF> with the message headers
252
     * and the message body being seperated by and additional <CRLF>.
253
     *
254
     * Implements rfc 821: DATA <CRLF>
255
     *
256
     * SMTP CODE INTERMEDIATE: 354
257
     *     [data]
258
     *     <CRLF>.<CRLF>
259
     *     SMTP CODE SUCCESS: 250
260
     *     SMTP CODE FAILURE: 552,554,451,452
261
     * SMTP CODE FAILURE: 451,554
262
     * SMTP CODE ERROR  : 500,501,503,421
263
     * @access public
264
     * @return bool
265
     */
266
    function Data($msg_data) {
267
        $this->error = null; # so no confusion is caused
268

    
269
        if(!$this->connected()) {
270
            $this->error = array(
271
                    "error" => "Called Data() without being connected");
272
            return false;
273
        }
274

    
275
        fputs($this->smtp_conn,"DATA" . $this->CRLF);
276

    
277
        $rply = $this->get_lines();
278
        $code = substr($rply,0,3);
279

    
280
        if($this->do_debug >= 2) {
281
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
282
        }
283

    
284
        if($code != 354) {
285
            $this->error =
286
                array("error" => "DATA command not accepted from server",
287
                      "smtp_code" => $code,
288
                      "smtp_msg" => substr($rply,4));
289
            if($this->do_debug >= 1) {
290
                echo "SMTP -> ERROR: " . $this->error["error"] .
291
                         ": " . $rply . $this->CRLF;
292
            }
293
            return false;
294
        }
295

    
296
        # the server is ready to accept data!
297
        # according to rfc 821 we should not send more than 1000
298
        # including the CRLF
299
        # characters on a single line so we will break the data up
300
        # into lines by \r and/or \n then if needed we will break
301
        # each of those into smaller lines to fit within the limit.
302
        # in addition we will be looking for lines that start with
303
        # a period '.' and append and additional period '.' to that
304
        # line. NOTE: this does not count towards are limit.
305

    
306
        # normalize the line breaks so we know the explode works
307
        $msg_data = str_replace("\r\n","\n",$msg_data);
308
        $msg_data = str_replace("\r","\n",$msg_data);
309
        $lines = explode("\n",$msg_data);
310

    
311
        # we need to find a good way to determine is headers are
312
        # in the msg_data or if it is a straight msg body
313
        # currently I'm assuming rfc 822 definitions of msg headers
314
        # and if the first field of the first line (':' sperated)
315
        # does not contain a space then it _should_ be a header
316
        # and we can process all lines before a blank "" line as
317
        # headers.
318
        $field = substr($lines[0],0,strpos($lines[0],":"));
319
        $in_headers = false;
320
        if(!empty($field) && !strstr($field," ")) {
321
            $in_headers = true;
322
        }
323

    
324
        $max_line_length = 998; # used below; set here for ease in change
325

    
326
        while(list(,$line) = @each($lines)) {
327
            $lines_out = null;
328
            if($line == "" && $in_headers) {
329
                $in_headers = false;
330
            }
331
            # ok we need to break this line up into several
332
            # smaller lines
333
            while(strlen($line) > $max_line_length) {
334
                $pos = strrpos(substr($line,0,$max_line_length)," ");
335

    
336
                # Patch to fix DOS attack
337
                if(!$pos) {
338
                    $pos = $max_line_length - 1;
339
                }
340

    
341
                $lines_out[] = substr($line,0,$pos);
342
                $line = substr($line,$pos + 1);
343
                # if we are processing headers we need to
344
                # add a LWSP-char to the front of the new line
345
                # rfc 822 on long msg headers
346
                if($in_headers) {
347
                    $line = "\t" . $line;
348
                }
349
            }
350
            $lines_out[] = $line;
351

    
352
            # now send the lines to the server
353
            while(list(,$line_out) = @each($lines_out)) {
354
                if(strlen($line_out) > 0)
355
                {
356
                    if(substr($line_out, 0, 1) == ".") {
357
                        $line_out = "." . $line_out;
358
                    }
359
                }
360
                fputs($this->smtp_conn,$line_out . $this->CRLF);
361
            }
362
        }
363

    
364
        # ok all the message data has been sent so lets get this
365
        # over with aleady
366
        fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
367

    
368
        $rply = $this->get_lines();
369
        $code = substr($rply,0,3);
370

    
371
        if($this->do_debug >= 2) {
372
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
373
        }
374

    
375
        if($code != 250) {
376
            $this->error =
377
                array("error" => "DATA not accepted from server",
378
                      "smtp_code" => $code,
379
                      "smtp_msg" => substr($rply,4));
380
            if($this->do_debug >= 1) {
381
                echo "SMTP -> ERROR: " . $this->error["error"] .
382
                         ": " . $rply . $this->CRLF;
383
            }
384
            return false;
385
        }
386
        return true;
387
    }
388

    
389
    /**
390
     * Expand takes the name and asks the server to list all the
391
     * people who are members of the _list_. Expand will return
392
     * back and array of the result or false if an error occurs.
393
     * Each value in the array returned has the format of:
394
     *     [ <full-name> <sp> ] <path>
395
     * The definition of <path> is defined in rfc 821
396
     *
397
     * Implements rfc 821: EXPN <SP> <string> <CRLF>
398
     *
399
     * SMTP CODE SUCCESS: 250
400
     * SMTP CODE FAILURE: 550
401
     * SMTP CODE ERROR  : 500,501,502,504,421
402
     * @access public
403
     * @return string array
404
     */
405
    function Expand($name) {
406
        $this->error = null; # so no confusion is caused
407

    
408
        if(!$this->connected()) {
409
            $this->error = array(
410
                    "error" => "Called Expand() without being connected");
411
            return false;
412
        }
413

    
414
        fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF);
415

    
416
        $rply = $this->get_lines();
417
        $code = substr($rply,0,3);
418

    
419
        if($this->do_debug >= 2) {
420
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
421
        }
422

    
423
        if($code != 250) {
424
            $this->error =
425
                array("error" => "EXPN not accepted from server",
426
                      "smtp_code" => $code,
427
                      "smtp_msg" => substr($rply,4));
428
            if($this->do_debug >= 1) {
429
                echo "SMTP -> ERROR: " . $this->error["error"] .
430
                         ": " . $rply . $this->CRLF;
431
            }
432
            return false;
433
        }
434

    
435
        # parse the reply and place in our array to return to user
436
        $entries = explode($this->CRLF,$rply);
437
        while(list(,$l) = @each($entries)) {
438
            $list[] = substr($l,4);
439
        }
440

    
441
        return $list;
442
    }
443

    
444
    /**
445
     * Sends the HELO command to the smtp server.
446
     * This makes sure that we and the server are in
447
     * the same known state.
448
     *
449
     * Implements from rfc 821: HELO <SP> <domain> <CRLF>
450
     *
451
     * SMTP CODE SUCCESS: 250
452
     * SMTP CODE ERROR  : 500, 501, 504, 421
453
     * @access public
454
     * @return bool
455
     */
456
    function Hello($host="") {
457
        $this->error = null; # so no confusion is caused
458

    
459
        if(!$this->connected()) {
460
            $this->error = array(
461
                    "error" => "Called Hello() without being connected");
462
            return false;
463
        }
464

    
465
        # if a hostname for the HELO wasn't specified determine
466
        # a suitable one to send
467
        if(empty($host)) {
468
            # we need to determine some sort of appopiate default
469
            # to send to the server
470
            $host = "localhost";
471
        }
472

    
473
        // Send extended hello first (RFC 2821)
474
        if(!$this->SendHello("EHLO", $host))
475
        {
476
            if(!$this->SendHello("HELO", $host))
477
                return false;
478
        }
479

    
480
        return true;
481
    }
482

    
483
    /**
484
     * Sends a HELO/EHLO command.
485
     * @access private
486
     * @return bool
487
     */
488
    function SendHello($hello, $host) {
489
        fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
490

    
491
        $rply = $this->get_lines();
492
        $code = substr($rply,0,3);
493

    
494
        if($this->do_debug >= 2) {
495
            echo "SMTP -> FROM SERVER: " . $this->CRLF . $rply;
496
        }
497

    
498
        if($code != 250) {
499
            $this->error =
500
                array("error" => $hello . " not accepted from server",
501
                      "smtp_code" => $code,
502
                      "smtp_msg" => substr($rply,4));
503
            if($this->do_debug >= 1) {
504
                echo "SMTP -> ERROR: " . $this->error["error"] .
505
                         ": " . $rply . $this->CRLF;
506
            }
507
            return false;
508
        }
509

    
510
        $this->helo_rply = $rply;
511
        
512
        return true;
513
    }
514

    
515
    /**
516
     * Gets help information on the keyword specified. If the keyword
517
     * is not specified then returns generic help, ussually contianing
518
     * A list of keywords that help is available on. This function
519
     * returns the results back to the user. It is up to the user to
520
     * handle the returned data. If an error occurs then false is
521
     * returned with $this->error set appropiately.
522
     *
523
     * Implements rfc 821: HELP [ <SP> <string> ] <CRLF>
524
     *
525
     * SMTP CODE SUCCESS: 211,214
526
     * SMTP CODE ERROR  : 500,501,502,504,421
527
     * @access public
528
     * @return string
529
     */
530
    function Help($keyword="") {
531
        $this->error = null; # to avoid confusion
532

    
533
        if(!$this->connected()) {
534
            $this->error = array(
535
                    "error" => "Called Help() without being connected");
536
            return false;
537
        }
538

    
539
        $extra = "";
540
        if(!empty($keyword)) {
541
            $extra = " " . $keyword;
542
        }
543

    
544
        fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF);
545

    
546
        $rply = $this->get_lines();
547
        $code = substr($rply,0,3);
548

    
549
        if($this->do_debug >= 2) {
550
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
551
        }
552

    
553
        if($code != 211 && $code != 214) {
554
            $this->error =
555
                array("error" => "HELP not accepted from server",
556
                      "smtp_code" => $code,
557
                      "smtp_msg" => substr($rply,4));
558
            if($this->do_debug >= 1) {
559
                echo "SMTP -> ERROR: " . $this->error["error"] .
560
                         ": " . $rply . $this->CRLF;
561
            }
562
            return false;
563
        }
564

    
565
        return $rply;
566
    }
567

    
568
    /**
569
     * Starts a mail transaction from the email address specified in
570
     * $from. Returns true if successful or false otherwise. If True
571
     * the mail transaction is started and then one or more Recipient
572
     * commands may be called followed by a Data command.
573
     *
574
     * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
575
     *
576
     * SMTP CODE SUCCESS: 250
577
     * SMTP CODE SUCCESS: 552,451,452
578
     * SMTP CODE SUCCESS: 500,501,421
579
     * @access public
580
     * @return bool
581
     */
582
    function Mail($from) {
583
        $this->error = null; # so no confusion is caused
584

    
585
        if(!$this->connected()) {
586
            $this->error = array(
587
                    "error" => "Called Mail() without being connected");
588
            return false;
589
        }
590

    
591
        fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $this->CRLF);
592

    
593
        $rply = $this->get_lines();
594
        $code = substr($rply,0,3);
595

    
596
        if($this->do_debug >= 2) {
597
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
598
        }
599

    
600
        if($code != 250) {
601
            $this->error =
602
                array("error" => "MAIL not accepted from server",
603
                      "smtp_code" => $code,
604
                      "smtp_msg" => substr($rply,4));
605
            if($this->do_debug >= 1) {
606
                echo "SMTP -> ERROR: " . $this->error["error"] .
607
                         ": " . $rply . $this->CRLF;
608
            }
609
            return false;
610
        }
611
        return true;
612
    }
613

    
614
    /**
615
     * Sends the command NOOP to the SMTP server.
616
     *
617
     * Implements from rfc 821: NOOP <CRLF>
618
     *
619
     * SMTP CODE SUCCESS: 250
620
     * SMTP CODE ERROR  : 500, 421
621
     * @access public
622
     * @return bool
623
     */
624
    function Noop() {
625
        $this->error = null; # so no confusion is caused
626

    
627
        if(!$this->connected()) {
628
            $this->error = array(
629
                    "error" => "Called Noop() without being connected");
630
            return false;
631
        }
632

    
633
        fputs($this->smtp_conn,"NOOP" . $this->CRLF);
634

    
635
        $rply = $this->get_lines();
636
        $code = substr($rply,0,3);
637

    
638
        if($this->do_debug >= 2) {
639
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
640
        }
641

    
642
        if($code != 250) {
643
            $this->error =
644
                array("error" => "NOOP not accepted from server",
645
                      "smtp_code" => $code,
646
                      "smtp_msg" => substr($rply,4));
647
            if($this->do_debug >= 1) {
648
                echo "SMTP -> ERROR: " . $this->error["error"] .
649
                         ": " . $rply . $this->CRLF;
650
            }
651
            return false;
652
        }
653
        return true;
654
    }
655

    
656
    /**
657
     * Sends the quit command to the server and then closes the socket
658
     * if there is no error or the $close_on_error argument is true.
659
     *
660
     * Implements from rfc 821: QUIT <CRLF>
661
     *
662
     * SMTP CODE SUCCESS: 221
663
     * SMTP CODE ERROR  : 500
664
     * @access public
665
     * @return bool
666
     */
667
    function Quit($close_on_error=true) {
668
        $this->error = null; # so there is no confusion
669

    
670
        if(!$this->connected()) {
671
            $this->error = array(
672
                    "error" => "Called Quit() without being connected");
673
            return false;
674
        }
675

    
676
        # send the quit command to the server
677
        fputs($this->smtp_conn,"quit" . $this->CRLF);
678

    
679
        # get any good-bye messages
680
        $byemsg = $this->get_lines();
681

    
682
        if($this->do_debug >= 2) {
683
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg;
684
        }
685

    
686
        $rval = true;
687
        $e = null;
688

    
689
        $code = substr($byemsg,0,3);
690
        if($code != 221) {
691
            # use e as a tmp var cause Close will overwrite $this->error
692
            $e = array("error" => "SMTP server rejected quit command",
693
                       "smtp_code" => $code,
694
                       "smtp_rply" => substr($byemsg,4));
695
            $rval = false;
696
            if($this->do_debug >= 1) {
697
                echo "SMTP -> ERROR: " . $e["error"] . ": " .
698
                         $byemsg . $this->CRLF;
699
            }
700
        }
701

    
702
        if(empty($e) || $close_on_error) {
703
            $this->Close();
704
        }
705

    
706
        return $rval;
707
    }
708

    
709
    /**
710
     * Sends the command RCPT to the SMTP server with the TO: argument of $to.
711
     * Returns true if the recipient was accepted false if it was rejected.
712
     *
713
     * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
714
     *
715
     * SMTP CODE SUCCESS: 250,251
716
     * SMTP CODE FAILURE: 550,551,552,553,450,451,452
717
     * SMTP CODE ERROR  : 500,501,503,421
718
     * @access public
719
     * @return bool
720
     */
721
    function Recipient($to) {
722
        $this->error = null; # so no confusion is caused
723

    
724
        if(!$this->connected()) {
725
            $this->error = array(
726
                    "error" => "Called Recipient() without being connected");
727
            return false;
728
        }
729

    
730
        fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
731

    
732
        $rply = $this->get_lines();
733
        $code = substr($rply,0,3);
734

    
735
        if($this->do_debug >= 2) {
736
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
737
        }
738

    
739
        if($code != 250 && $code != 251) {
740
            $this->error =
741
                array("error" => "RCPT not accepted from server",
742
                      "smtp_code" => $code,
743
                      "smtp_msg" => substr($rply,4));
744
            if($this->do_debug >= 1) {
745
                echo "SMTP -> ERROR: " . $this->error["error"] .
746
                         ": " . $rply . $this->CRLF;
747
            }
748
            return false;
749
        }
750
        return true;
751
    }
752

    
753
    /**
754
     * Sends the RSET command to abort and transaction that is
755
     * currently in progress. Returns true if successful false
756
     * otherwise.
757
     *
758
     * Implements rfc 821: RSET <CRLF>
759
     *
760
     * SMTP CODE SUCCESS: 250
761
     * SMTP CODE ERROR  : 500,501,504,421
762
     * @access public
763
     * @return bool
764
     */
765
    function Reset() {
766
        $this->error = null; # so no confusion is caused
767

    
768
        if(!$this->connected()) {
769
            $this->error = array(
770
                    "error" => "Called Reset() without being connected");
771
            return false;
772
        }
773

    
774
        fputs($this->smtp_conn,"RSET" . $this->CRLF);
775

    
776
        $rply = $this->get_lines();
777
        $code = substr($rply,0,3);
778

    
779
        if($this->do_debug >= 2) {
780
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
781
        }
782

    
783
        if($code != 250) {
784
            $this->error =
785
                array("error" => "RSET failed",
786
                      "smtp_code" => $code,
787
                      "smtp_msg" => substr($rply,4));
788
            if($this->do_debug >= 1) {
789
                echo "SMTP -> ERROR: " . $this->error["error"] .
790
                         ": " . $rply . $this->CRLF;
791
            }
792
            return false;
793
        }
794

    
795
        return true;
796
    }
797

    
798
    /**
799
     * Starts a mail transaction from the email address specified in
800
     * $from. Returns true if successful or false otherwise. If True
801
     * the mail transaction is started and then one or more Recipient
802
     * commands may be called followed by a Data command. This command
803
     * will send the message to the users terminal if they are logged
804
     * in.
805
     *
806
     * Implements rfc 821: SEND <SP> FROM:<reverse-path> <CRLF>
807
     *
808
     * SMTP CODE SUCCESS: 250
809
     * SMTP CODE SUCCESS: 552,451,452
810
     * SMTP CODE SUCCESS: 500,501,502,421
811
     * @access public
812
     * @return bool
813
     */
814
    function Send($from) {
815
        $this->error = null; # so no confusion is caused
816

    
817
        if(!$this->connected()) {
818
            $this->error = array(
819
                    "error" => "Called Send() without being connected");
820
            return false;
821
        }
822

    
823
        fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF);
824

    
825
        $rply = $this->get_lines();
826
        $code = substr($rply,0,3);
827

    
828
        if($this->do_debug >= 2) {
829
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
830
        }
831

    
832
        if($code != 250) {
833
            $this->error =
834
                array("error" => "SEND not accepted from server",
835
                      "smtp_code" => $code,
836
                      "smtp_msg" => substr($rply,4));
837
            if($this->do_debug >= 1) {
838
                echo "SMTP -> ERROR: " . $this->error["error"] .
839
                         ": " . $rply . $this->CRLF;
840
            }
841
            return false;
842
        }
843
        return true;
844
    }
845

    
846
    /**
847
     * Starts a mail transaction from the email address specified in
848
     * $from. Returns true if successful or false otherwise. If True
849
     * the mail transaction is started and then one or more Recipient
850
     * commands may be called followed by a Data command. This command
851
     * will send the message to the users terminal if they are logged
852
     * in and send them an email.
853
     *
854
     * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
855
     *
856
     * SMTP CODE SUCCESS: 250
857
     * SMTP CODE SUCCESS: 552,451,452
858
     * SMTP CODE SUCCESS: 500,501,502,421
859
     * @access public
860
     * @return bool
861
     */
862
    function SendAndMail($from) {
863
        $this->error = null; # so no confusion is caused
864

    
865
        if(!$this->connected()) {
866
            $this->error = array(
867
                "error" => "Called SendAndMail() without being connected");
868
            return false;
869
        }
870

    
871
        fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
872

    
873
        $rply = $this->get_lines();
874
        $code = substr($rply,0,3);
875

    
876
        if($this->do_debug >= 2) {
877
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
878
        }
879

    
880
        if($code != 250) {
881
            $this->error =
882
                array("error" => "SAML not accepted from server",
883
                      "smtp_code" => $code,
884
                      "smtp_msg" => substr($rply,4));
885
            if($this->do_debug >= 1) {
886
                echo "SMTP -> ERROR: " . $this->error["error"] .
887
                         ": " . $rply . $this->CRLF;
888
            }
889
            return false;
890
        }
891
        return true;
892
    }
893

    
894
    /**
895
     * Starts a mail transaction from the email address specified in
896
     * $from. Returns true if successful or false otherwise. If True
897
     * the mail transaction is started and then one or more Recipient
898
     * commands may be called followed by a Data command. This command
899
     * will send the message to the users terminal if they are logged
900
     * in or mail it to them if they are not.
901
     *
902
     * Implements rfc 821: SOML <SP> FROM:<reverse-path> <CRLF>
903
     *
904
     * SMTP CODE SUCCESS: 250
905
     * SMTP CODE SUCCESS: 552,451,452
906
     * SMTP CODE SUCCESS: 500,501,502,421
907
     * @access public
908
     * @return bool
909
     */
910
    function SendOrMail($from) {
911
        $this->error = null; # so no confusion is caused
912

    
913
        if(!$this->connected()) {
914
            $this->error = array(
915
                "error" => "Called SendOrMail() without being connected");
916
            return false;
917
        }
918

    
919
        fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF);
920

    
921
        $rply = $this->get_lines();
922
        $code = substr($rply,0,3);
923

    
924
        if($this->do_debug >= 2) {
925
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
926
        }
927

    
928
        if($code != 250) {
929
            $this->error =
930
                array("error" => "SOML not accepted from server",
931
                      "smtp_code" => $code,
932
                      "smtp_msg" => substr($rply,4));
933
            if($this->do_debug >= 1) {
934
                echo "SMTP -> ERROR: " . $this->error["error"] .
935
                         ": " . $rply . $this->CRLF;
936
            }
937
            return false;
938
        }
939
        return true;
940
    }
941

    
942
    /**
943
     * This is an optional command for SMTP that this class does not
944
     * support. This method is here to make the RFC821 Definition
945
     * complete for this class and __may__ be implimented in the future
946
     *
947
     * Implements from rfc 821: TURN <CRLF>
948
     *
949
     * SMTP CODE SUCCESS: 250
950
     * SMTP CODE FAILURE: 502
951
     * SMTP CODE ERROR  : 500, 503
952
     * @access public
953
     * @return bool
954
     */
955
    function Turn() {
956
        $this->error = array("error" => "This method, TURN, of the SMTP ".
957
                                        "is not implemented");
958
        if($this->do_debug >= 1) {
959
            echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF;
960
        }
961
        return false;
962
    }
963

    
964
    /**
965
     * Verifies that the name is recognized by the server.
966
     * Returns false if the name could not be verified otherwise
967
     * the response from the server is returned.
968
     *
969
     * Implements rfc 821: VRFY <SP> <string> <CRLF>
970
     *
971
     * SMTP CODE SUCCESS: 250,251
972
     * SMTP CODE FAILURE: 550,551,553
973
     * SMTP CODE ERROR  : 500,501,502,421
974
     * @access public
975
     * @return int
976
     */
977
    function Verify($name) {
978
        $this->error = null; # so no confusion is caused
979

    
980
        if(!$this->connected()) {
981
            $this->error = array(
982
                    "error" => "Called Verify() without being connected");
983
            return false;
984
        }
985

    
986
        fputs($this->smtp_conn,"VRFY " . $name . $this->CRLF);
987

    
988
        $rply = $this->get_lines();
989
        $code = substr($rply,0,3);
990

    
991
        if($this->do_debug >= 2) {
992
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
993
        }
994

    
995
        if($code != 250 && $code != 251) {
996
            $this->error =
997
                array("error" => "VRFY failed on name '$name'",
998
                      "smtp_code" => $code,
999
                      "smtp_msg" => substr($rply,4));
1000
            if($this->do_debug >= 1) {
1001
                echo "SMTP -> ERROR: " . $this->error["error"] .
1002
                         ": " . $rply . $this->CRLF;
1003
            }
1004
            return false;
1005
        }
1006
        return $rply;
1007
    }
1008

    
1009
    /*******************************************************************
1010
     *                       INTERNAL FUNCTIONS                       *
1011
     ******************************************************************/
1012

    
1013
    /**
1014
     * Read in as many lines as possible
1015
     * either before eof or socket timeout occurs on the operation.
1016
     * With SMTP we can tell if we have more lines to read if the
1017
     * 4th character is '-' symbol. If it is a space then we don't
1018
     * need to read anything else.
1019
     * @access private
1020
     * @return string
1021
     */
1022
    function get_lines() {
1023
        $data = "";
1024
        while($str = fgets($this->smtp_conn,515)) {
1025
            if($this->do_debug >= 4) {
1026
                echo "SMTP -> get_lines(): \$data was \"$data\"" .
1027
                         $this->CRLF;
1028
                echo "SMTP -> get_lines(): \$str is \"$str\"" .
1029
                         $this->CRLF;
1030
            }
1031
            $data .= $str;
1032
            if($this->do_debug >= 4) {
1033
                echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF;
1034
            }
1035
            # if the 4th character is a space then we are done reading
1036
            # so just break the loop
1037
            if(substr($str,3,1) == " ") { break; }
1038
        }
1039
        return $data;
1040
    }
1041

    
1042
}
1043

    
1044

    
1045
 ?>
(4-4/4)