Wordpress 2.6.2
[autoinstalls/wordpress.git] / wp-includes / class-smtp.php
1 <?php
2 /**
3  * SMTP - PHP SMTP class
4  *
5  * Define an SMTP class that can be used to connect and communicate with any
6  * SMTP server. It implements all the SMTP functions defined in RFC821 except
7  * TURN.
8  *
9  * @version 1.02
10  * @author Chris Ryan
11  * @license LGPL
12  * @package PHPMailer
13  */
14
15 /**
16  * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
17  * commands except TURN which will always return a not implemented
18  * error. SMTP also provides some utility methods for sending mail
19  * to an SMTP server.
20  *
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 separated 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  ?>