"copied"
[mailer.git] / 0.2.1-FINAL / inc / phpmailer / class.smtp.php
1 <?php
2 /*~ class.smtp.php
3 .---------------------------------------------------------------------------.
4 |  Software: PHPMailer - PHP email class                                    |
5 |   Version: 2.0.2                                                          |
6 |   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
7 |      Info: http://phpmailer.sourceforge.net                               |
8 |   Support: http://sourceforge.net/projects/phpmailer/                     |
9 | ------------------------------------------------------------------------- |
10 |    Author: Andy Prevost (project admininistrator)                         |
11 |    Author: Brent R. Matzelle (original founder)                           |
12 | Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved.               |
13 | Copyright (c) 2001-2003, Brent R. Matzelle                                |
14 | ------------------------------------------------------------------------- |
15 |   License: Distributed under the Lesser General Public License (LGPL)     |
16 |            http://www.gnu.org/copyleft/lesser.html                        |
17 | This program is distributed in the hope that it will be useful - WITHOUT  |
18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
19 | FITNESS FOR A PARTICULAR PURPOSE.                                         |
20 | ------------------------------------------------------------------------- |
21 | We offer a number of paid services (www.codeworxtech.com):                |
22 | - Web Hosting on highly optimized fast and secure servers                 |
23 | - Technology Consulting                                                   |
24 | - Oursourcing (highly qualified programmers and graphic designers)        |
25 '---------------------------------------------------------------------------'
26
27 /**
28  * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
29  * commands except TURN which will always return a not implemented
30  * error. SMTP also provides some utility methods for sending mail
31  * to an SMTP server.
32  * @package PHPMailer
33  * @author Chris Ryan
34  */
35
36 class SMTP
37 {
38   /**
39    *  SMTP server port
40    *  @var int
41    */
42   var $SMTP_PORT = 25;
43
44   /**
45    *  SMTP reply line ending
46    *  @var string
47    */
48   var $CRLF = "\r\n";
49
50   /**
51    *  Sets whether debugging is turned on
52    *  @var bool
53    */
54   var $do_debug;       # the level of debug to perform
55
56   /**
57    *  Sets VERP use on/off (default is off)
58    *  @var bool
59    */
60   var $do_verp = false;
61
62   /**#@+
63    * @access private
64    */
65   var $smtp_conn;      # the socket to the server
66   var $error;          # error if any on the last call
67   var $helo_rply;      # the reply the server sent to us for HELO
68   /**#@-*/
69
70   /**
71    * Initialize the class so that the data is in a known state.
72    * @access public
73    * @return void
74    */
75   function SMTP() {
76     $this->smtp_conn = 0;
77     $this->error = null;
78     $this->helo_rply = null;
79
80     $this->do_debug = 0;
81   }
82
83   /*************************************************************
84    *                    CONNECTION FUNCTIONS                  *
85    ***********************************************************/
86
87   /**
88    * Connect to the server specified on the port specified.
89    * If the port is not specified use the default SMTP_PORT.
90    * If tval is specified then a connection will try and be
91    * established with the server for that number of seconds.
92    * If tval is not specified the default is 30 seconds to
93    * try on the connection.
94    *
95    * SMTP CODE SUCCESS: 220
96    * SMTP CODE FAILURE: 421
97    * @access public
98    * @return bool
99    */
100   function Connect($host,$port=0,$tval=30) {
101     # set the error val to null so there is no confusion
102     $this->error = null;
103
104     # make sure we are __not__ connected
105     if($this->connected()) {
106       # ok we are connected! what should we do?
107       # for now we will just give an error saying we
108       # are already connected
109       $this->error = array("error" => "Already connected to a server");
110       return false;
111     }
112
113     if(empty($port)) {
114       $port = $this->SMTP_PORT;
115     }
116
117     #connect to the smtp server
118     $this->smtp_conn = fsockopen($host,    # the host of the server
119                                  $port,    # the port to use
120                                  $errno,   # error number if any
121                                  $errstr,  # error message if any
122                                  $tval);   # give up after ? secs
123     # verify we connected properly
124     if(empty($this->smtp_conn)) {
125       $this->error = array("error" => "Failed to connect to server",
126                            "errno" => $errno,
127                            "errstr" => $errstr);
128       if($this->do_debug >= 1) {
129         echo "SMTP -> ERROR: " . $this->error["error"] .
130                  ": $errstr ($errno)" . $this->CRLF;
131       }
132       return false;
133     }
134
135     # sometimes the SMTP server takes a little longer to respond
136     # so we will give it a longer timeout for the first read
137     // Windows still does not have support for this timeout function
138     if(substr(PHP_OS, 0, 3) != "WIN")
139      socket_set_timeout($this->smtp_conn, $tval, 0);
140
141     # get any announcement stuff
142     $announce = $this->get_lines();
143
144     # set the timeout  of any socket functions at 1/10 of a second
145     //if(function_exists("socket_set_timeout"))
146     //   socket_set_timeout($this->smtp_conn, 0, 100000);
147
148     if($this->do_debug >= 2) {
149       echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce;
150     }
151
152     return true;
153   }
154
155   /**
156    * Performs SMTP authentication.  Must be run after running the
157    * Hello() method.  Returns true if successfully authenticated.
158    * @access public
159    * @return bool
160    */
161   function Authenticate($username, $password) {
162     // Start authentication
163     fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
164
165     $rply = $this->get_lines();
166     $code = substr($rply,0,3);
167
168     if($code != 334) {
169       $this->error =
170         array("error" => "AUTH not accepted from server",
171               "smtp_code" => $code,
172               "smtp_msg" => substr($rply,4));
173       if($this->do_debug >= 1) {
174         echo "SMTP -> ERROR: " . $this->error["error"] .
175                  ": " . $rply . $this->CRLF;
176       }
177       return false;
178     }
179
180     // Send encoded username
181     fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
182
183     $rply = $this->get_lines();
184     $code = substr($rply,0,3);
185
186     if($code != 334) {
187       $this->error =
188         array("error" => "Username not accepted from server",
189               "smtp_code" => $code,
190               "smtp_msg" => substr($rply,4));
191       if($this->do_debug >= 1) {
192         echo "SMTP -> ERROR: " . $this->error["error"] .
193                  ": " . $rply . $this->CRLF;
194       }
195       return false;
196     }
197
198     // Send encoded password
199     fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
200
201     $rply = $this->get_lines();
202     $code = substr($rply,0,3);
203
204     if($code != 235) {
205       $this->error =
206         array("error" => "Password not accepted from server",
207               "smtp_code" => $code,
208               "smtp_msg" => substr($rply,4));
209       if($this->do_debug >= 1) {
210         echo "SMTP -> ERROR: " . $this->error["error"] .
211                  ": " . $rply . $this->CRLF;
212       }
213       return false;
214     }
215
216     return true;
217   }
218
219   /**
220    * Returns true if connected to a server otherwise false
221    * @access private
222    * @return bool
223    */
224   function Connected() {
225     if(!empty($this->smtp_conn)) {
226       $sock_status = socket_get_status($this->smtp_conn);
227       if($sock_status["eof"]) {
228         # hmm this is an odd situation... the socket is
229         # valid but we are not connected anymore
230         if($this->do_debug >= 1) {
231             echo "SMTP -> NOTICE:" . $this->CRLF .
232                  "EOF caught while checking if connected";
233         }
234         $this->Close();
235         return false;
236       }
237       return true; # everything looks good
238     }
239     return false;
240   }
241
242   /**
243    * Closes the socket and cleans up the state of the class.
244    * It is not considered good to use this function without
245    * first trying to use QUIT.
246    * @access public
247    * @return void
248    */
249   function Close() {
250     $this->error = null; # so there is no confusion
251     $this->helo_rply = null;
252     if(!empty($this->smtp_conn)) {
253       # close the connection and cleanup
254       fclose($this->smtp_conn);
255       $this->smtp_conn = 0;
256     }
257   }
258
259   /***************************************************************
260    *                        SMTP COMMANDS                       *
261    *************************************************************/
262
263   /**
264    * Issues a data command and sends the msg_data to the server
265    * finializing the mail transaction. $msg_data is the message
266    * that is to be send with the headers. Each header needs to be
267    * on a single line followed by a <CRLF> with the message headers
268    * and the message body being seperated by and additional <CRLF>.
269    *
270    * Implements rfc 821: DATA <CRLF>
271    *
272    * SMTP CODE INTERMEDIATE: 354
273    *     [data]
274    *     <CRLF>.<CRLF>
275    *     SMTP CODE SUCCESS: 250
276    *     SMTP CODE FAILURE: 552,554,451,452
277    * SMTP CODE FAILURE: 451,554
278    * SMTP CODE ERROR  : 500,501,503,421
279    * @access public
280    * @return bool
281    */
282   function Data($msg_data) {
283     $this->error = null; # so no confusion is caused
284
285     if(!$this->connected()) {
286       $this->error = array(
287               "error" => "Called Data() without being connected");
288       return false;
289     }
290
291     fputs($this->smtp_conn,"DATA" . $this->CRLF);
292
293     $rply = $this->get_lines();
294     $code = substr($rply,0,3);
295
296     if($this->do_debug >= 2) {
297       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
298     }
299
300     if($code != 354) {
301       $this->error =
302         array("error" => "DATA command not accepted from server",
303               "smtp_code" => $code,
304               "smtp_msg" => substr($rply,4));
305       if($this->do_debug >= 1) {
306         echo "SMTP -> ERROR: " . $this->error["error"] .
307                  ": " . $rply . $this->CRLF;
308       }
309       return false;
310     }
311
312     # the server is ready to accept data!
313     # according to rfc 821 we should not send more than 1000
314     # including the CRLF
315     # characters on a single line so we will break the data up
316     # into lines by \r and/or \n then if needed we will break
317     # each of those into smaller lines to fit within the limit.
318     # in addition we will be looking for lines that start with
319     # a period '.' and append and additional period '.' to that
320     # line. NOTE: this does not count towards are limit.
321
322     # normalize the line breaks so we know the explode works
323     $msg_data = str_replace("\r\n","\n",$msg_data);
324     $msg_data = str_replace("\r","\n",$msg_data);
325     $lines = explode("\n",$msg_data);
326
327     # we need to find a good way to determine is headers are
328     # in the msg_data or if it is a straight msg body
329     # currently I am assuming rfc 822 definitions of msg headers
330     # and if the first field of the first line (':' sperated)
331     # does not contain a space then it _should_ be a header
332     # and we can process all lines before a blank "" line as
333     # headers.
334     $field = substr($lines[0],0,strpos($lines[0],":"));
335     $in_headers = false;
336     if(!empty($field) && !strstr($field," ")) {
337       $in_headers = true;
338     }
339
340     $max_line_length = 998; # used below; set here for ease in change
341
342     while(list(,$line) = @each($lines)) {
343       $lines_out = null;
344       if($line == "" && $in_headers) {
345         $in_headers = false;
346       }
347       # ok we need to break this line up into several
348       # smaller lines
349       while(strlen($line) > $max_line_length) {
350         $pos = strrpos(substr($line,0,$max_line_length)," ");
351
352         # Patch to fix DOS attack
353         if(!$pos) {
354           $pos = $max_line_length - 1;
355         }
356
357         $lines_out[] = substr($line,0,$pos);
358         $line = substr($line,$pos + 1);
359         # if we are processing headers we need to
360         # add a LWSP-char to the front of the new line
361         # rfc 822 on long msg headers
362         if($in_headers) {
363           $line = "\t" . $line;
364         }
365       }
366       $lines_out[] = $line;
367
368       # now send the lines to the server
369       while(list(,$line_out) = @each($lines_out)) {
370         if(strlen($line_out) > 0)
371         {
372           if(substr($line_out, 0, 1) == ".") {
373             $line_out = "." . $line_out;
374           }
375         }
376         fputs($this->smtp_conn,$line_out . $this->CRLF);
377       }
378     }
379
380     # ok all the message data has been sent so lets get this
381     # over with aleady
382     fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
383
384     $rply = $this->get_lines();
385     $code = substr($rply,0,3);
386
387     if($this->do_debug >= 2) {
388       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
389     }
390
391     if($code != 250) {
392       $this->error =
393         array("error" => "DATA not accepted from server",
394               "smtp_code" => $code,
395               "smtp_msg" => substr($rply,4));
396       if($this->do_debug >= 1) {
397         echo "SMTP -> ERROR: " . $this->error["error"] .
398                  ": " . $rply . $this->CRLF;
399       }
400       return false;
401     }
402     return true;
403   }
404
405   /**
406    * Expand takes the name and asks the server to list all the
407    * people who are members of the _list_. Expand will return
408    * back and array of the result or false if an error occurs.
409    * Each value in the array returned has the format of:
410    *     [ <full-name> <sp> ] <path>
411    * The definition of <path> is defined in rfc 821
412    *
413    * Implements rfc 821: EXPN <SP> <string> <CRLF>
414    *
415    * SMTP CODE SUCCESS: 250
416    * SMTP CODE FAILURE: 550
417    * SMTP CODE ERROR  : 500,501,502,504,421
418    * @access public
419    * @return string array
420    */
421   function Expand($name) {
422     $this->error = null; # so no confusion is caused
423
424     if(!$this->connected()) {
425       $this->error = array(
426             "error" => "Called Expand() without being connected");
427       return false;
428     }
429
430     fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF);
431
432     $rply = $this->get_lines();
433     $code = substr($rply,0,3);
434
435     if($this->do_debug >= 2) {
436       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
437     }
438
439     if($code != 250) {
440       $this->error =
441         array("error" => "EXPN not accepted from server",
442               "smtp_code" => $code,
443               "smtp_msg" => substr($rply,4));
444       if($this->do_debug >= 1) {
445         echo "SMTP -> ERROR: " . $this->error["error"] .
446                  ": " . $rply . $this->CRLF;
447       }
448       return false;
449     }
450
451     # parse the reply and place in our array to return to user
452     $entries = explode($this->CRLF,$rply);
453     while(list(,$l) = @each($entries)) {
454       $list[] = substr($l,4);
455     }
456
457     return $list;
458   }
459
460   /**
461    * Sends the HELO command to the smtp server.
462    * This makes sure that we and the server are in
463    * the same known state.
464    *
465    * Implements from rfc 821: HELO <SP> <domain> <CRLF>
466    *
467    * SMTP CODE SUCCESS: 250
468    * SMTP CODE ERROR  : 500, 501, 504, 421
469    * @access public
470    * @return bool
471    */
472   function Hello($host="") {
473     $this->error = null; # so no confusion is caused
474
475     if(!$this->connected()) {
476       $this->error = array(
477             "error" => "Called Hello() without being connected");
478       return false;
479     }
480
481     # if a hostname for the HELO was not specified determine
482     # a suitable one to send
483     if(empty($host)) {
484       # we need to determine some sort of appopiate default
485       # to send to the server
486       $host = "localhost";
487     }
488
489     // Send extended hello first (RFC 2821)
490     if(!$this->SendHello("EHLO", $host))
491     {
492       if(!$this->SendHello("HELO", $host))
493           return false;
494     }
495
496     return true;
497   }
498
499   /**
500    * Sends a HELO/EHLO command.
501    * @access private
502    * @return bool
503    */
504   function SendHello($hello, $host) {
505     fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
506
507     $rply = $this->get_lines();
508     $code = substr($rply,0,3);
509
510     if($this->do_debug >= 2) {
511       echo "SMTP -> FROM SERVER: " . $this->CRLF . $rply;
512     }
513
514     if($code != 250) {
515       $this->error =
516         array("error" => $hello . " not accepted from server",
517               "smtp_code" => $code,
518               "smtp_msg" => substr($rply,4));
519       if($this->do_debug >= 1) {
520         echo "SMTP -> ERROR: " . $this->error["error"] .
521                  ": " . $rply . $this->CRLF;
522       }
523       return false;
524     }
525
526     $this->helo_rply = $rply;
527
528     return true;
529   }
530
531   /**
532    * Gets help information on the keyword specified. If the keyword
533    * is not specified then returns generic help, ussually contianing
534    * A list of keywords that help is available on. This function
535    * returns the results back to the user. It is up to the user to
536    * handle the returned data. If an error occurs then false is
537    * returned with $this->error set appropiately.
538    *
539    * Implements rfc 821: HELP [ <SP> <string> ] <CRLF>
540    *
541    * SMTP CODE SUCCESS: 211,214
542    * SMTP CODE ERROR  : 500,501,502,504,421
543    * @access public
544    * @return string
545    */
546   function Help($keyword="") {
547     $this->error = null; # to avoid confusion
548
549     if(!$this->connected()) {
550       $this->error = array(
551               "error" => "Called Help() without being connected");
552       return false;
553     }
554
555     $extra = "";
556     if(!empty($keyword)) {
557       $extra = " " . $keyword;
558     }
559
560     fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF);
561
562     $rply = $this->get_lines();
563     $code = substr($rply,0,3);
564
565     if($this->do_debug >= 2) {
566       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
567     }
568
569     if($code != 211 && $code != 214) {
570       $this->error =
571         array("error" => "HELP not accepted from server",
572               "smtp_code" => $code,
573               "smtp_msg" => substr($rply,4));
574       if($this->do_debug >= 1) {
575         echo "SMTP -> ERROR: " . $this->error["error"] .
576                  ": " . $rply . $this->CRLF;
577       }
578       return false;
579     }
580
581     return $rply;
582   }
583
584   /**
585    * Starts a mail transaction from the email address specified in
586    * $from. Returns true if successful or false otherwise. If True
587    * the mail transaction is started and then one or more Recipient
588    * commands may be called followed by a Data command.
589    *
590    * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
591    *
592    * SMTP CODE SUCCESS: 250
593    * SMTP CODE SUCCESS: 552,451,452
594    * SMTP CODE SUCCESS: 500,501,421
595    * @access public
596    * @return bool
597    */
598   function Mail($from) {
599     $this->error = null; # so no confusion is caused
600
601     if(!$this->connected()) {
602       $this->error = array(
603               "error" => "Called Mail() without being connected");
604       return false;
605     }
606
607     $useVerp = ($this->do_verp ? "XVERP" : "");
608     fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
609
610     $rply = $this->get_lines();
611     $code = substr($rply,0,3);
612
613     if($this->do_debug >= 2) {
614       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
615     }
616
617     if($code != 250) {
618       $this->error =
619         array("error" => "MAIL not accepted from server",
620               "smtp_code" => $code,
621               "smtp_msg" => substr($rply,4));
622       if($this->do_debug >= 1) {
623         echo "SMTP -> ERROR: " . $this->error["error"] .
624                  ": " . $rply . $this->CRLF;
625       }
626       return false;
627     }
628     return true;
629   }
630
631   /**
632    * Sends the command NOOP to the SMTP server.
633    *
634    * Implements from rfc 821: NOOP <CRLF>
635    *
636    * SMTP CODE SUCCESS: 250
637    * SMTP CODE ERROR  : 500, 421
638    * @access public
639    * @return bool
640    */
641   function Noop() {
642     $this->error = null; # so no confusion is caused
643
644     if(!$this->connected()) {
645       $this->error = array(
646               "error" => "Called Noop() without being connected");
647       return false;
648     }
649
650     fputs($this->smtp_conn,"NOOP" . $this->CRLF);
651
652     $rply = $this->get_lines();
653     $code = substr($rply,0,3);
654
655     if($this->do_debug >= 2) {
656       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
657     }
658
659     if($code != 250) {
660       $this->error =
661         array("error" => "NOOP not accepted from server",
662               "smtp_code" => $code,
663               "smtp_msg" => substr($rply,4));
664       if($this->do_debug >= 1) {
665         echo "SMTP -> ERROR: " . $this->error["error"] .
666                  ": " . $rply . $this->CRLF;
667       }
668       return false;
669     }
670     return true;
671   }
672
673   /**
674    * Sends the quit command to the server and then closes the socket
675    * if there is no error or the $close_on_error argument is true.
676    *
677    * Implements from rfc 821: QUIT <CRLF>
678    *
679    * SMTP CODE SUCCESS: 221
680    * SMTP CODE ERROR  : 500
681    * @access public
682    * @return bool
683    */
684   function Quit($close_on_error=true) {
685     $this->error = null; # so there is no confusion
686
687     if(!$this->connected()) {
688       $this->error = array(
689               "error" => "Called Quit() without being connected");
690       return false;
691     }
692
693     # send the quit command to the server
694     fputs($this->smtp_conn,"quit" . $this->CRLF);
695
696     # get any good-bye messages
697     $byemsg = $this->get_lines();
698
699     if($this->do_debug >= 2) {
700       echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg;
701     }
702
703     $rval = true;
704     $e = null;
705
706     $code = substr($byemsg,0,3);
707     if($code != 221) {
708       # use e as a tmp var cause Close will overwrite $this->error
709       $e = array("error" => "SMTP server rejected quit command",
710                  "smtp_code" => $code,
711                  "smtp_rply" => substr($byemsg,4));
712       $rval = false;
713       if($this->do_debug >= 1) {
714         echo "SMTP -> ERROR: " . $e["error"] . ": " .
715                  $byemsg . $this->CRLF;
716       }
717     }
718
719     if(empty($e) || $close_on_error) {
720       $this->Close();
721     }
722
723     return $rval;
724   }
725
726   /**
727    * Sends the command RCPT to the SMTP server with the TO: argument of $to.
728    * Returns true if the recipient was accepted false if it was rejected.
729    *
730    * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
731    *
732    * SMTP CODE SUCCESS: 250,251
733    * SMTP CODE FAILURE: 550,551,552,553,450,451,452
734    * SMTP CODE ERROR  : 500,501,503,421
735    * @access public
736    * @return bool
737    */
738   function Recipient($to) {
739     $this->error = null; # so no confusion is caused
740
741     if(!$this->connected()) {
742       $this->error = array(
743               "error" => "Called Recipient() without being connected");
744       return false;
745     }
746
747     fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
748
749     $rply = $this->get_lines();
750     $code = substr($rply,0,3);
751
752     if($this->do_debug >= 2) {
753       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
754     }
755
756     if($code != 250 && $code != 251) {
757       $this->error =
758         array("error" => "RCPT not accepted from server",
759               "smtp_code" => $code,
760               "smtp_msg" => substr($rply,4));
761       if($this->do_debug >= 1) {
762         echo "SMTP -> ERROR: " . $this->error["error"] .
763                  ": " . $rply . $this->CRLF;
764       }
765       return false;
766     }
767     return true;
768   }
769
770   /**
771    * Sends the RSET command to abort and transaction that is
772    * currently in progress. Returns true if successful false
773    * otherwise.
774    *
775    * Implements rfc 821: RSET <CRLF>
776    *
777    * SMTP CODE SUCCESS: 250
778    * SMTP CODE ERROR  : 500,501,504,421
779    * @access public
780    * @return bool
781    */
782   function Reset() {
783     $this->error = null; # so no confusion is caused
784
785     if(!$this->connected()) {
786       $this->error = array(
787               "error" => "Called Reset() without being connected");
788       return false;
789     }
790
791     fputs($this->smtp_conn,"RSET" . $this->CRLF);
792
793     $rply = $this->get_lines();
794     $code = substr($rply,0,3);
795
796     if($this->do_debug >= 2) {
797       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
798     }
799
800     if($code != 250) {
801       $this->error =
802         array("error" => "RSET failed",
803               "smtp_code" => $code,
804               "smtp_msg" => substr($rply,4));
805       if($this->do_debug >= 1) {
806         echo "SMTP -> ERROR: " . $this->error["error"] .
807                  ": " . $rply . $this->CRLF;
808       }
809       return false;
810     }
811
812     return true;
813   }
814
815   /**
816    * Starts a mail transaction from the email address specified in
817    * $from. Returns true if successful or false otherwise. If True
818    * the mail transaction is started and then one or more Recipient
819    * commands may be called followed by a Data command. This command
820    * will send the message to the users terminal if they are logged
821    * in.
822    *
823    * Implements rfc 821: SEND <SP> FROM:<reverse-path> <CRLF>
824    *
825    * SMTP CODE SUCCESS: 250
826    * SMTP CODE SUCCESS: 552,451,452
827    * SMTP CODE SUCCESS: 500,501,502,421
828    * @access public
829    * @return bool
830    */
831   function Send($from) {
832     $this->error = null; # so no confusion is caused
833
834     if(!$this->connected()) {
835       $this->error = array(
836               "error" => "Called Send() without being connected");
837       return false;
838     }
839
840     fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF);
841
842     $rply = $this->get_lines();
843     $code = substr($rply,0,3);
844
845     if($this->do_debug >= 2) {
846       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
847     }
848
849     if($code != 250) {
850       $this->error =
851         array("error" => "SEND not accepted from server",
852               "smtp_code" => $code,
853               "smtp_msg" => substr($rply,4));
854       if($this->do_debug >= 1) {
855         echo "SMTP -> ERROR: " . $this->error["error"] .
856                  ": " . $rply . $this->CRLF;
857       }
858       return false;
859     }
860     return true;
861   }
862
863   /**
864    * Starts a mail transaction from the email address specified in
865    * $from. Returns true if successful or false otherwise. If True
866    * the mail transaction is started and then one or more Recipient
867    * commands may be called followed by a Data command. This command
868    * will send the message to the users terminal if they are logged
869    * in and send them an email.
870    *
871    * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
872    *
873    * SMTP CODE SUCCESS: 250
874    * SMTP CODE SUCCESS: 552,451,452
875    * SMTP CODE SUCCESS: 500,501,502,421
876    * @access public
877    * @return bool
878    */
879   function SendAndMail($from) {
880     $this->error = null; # so no confusion is caused
881
882     if(!$this->connected()) {
883       $this->error = array(
884           "error" => "Called SendAndMail() without being connected");
885       return false;
886     }
887
888     fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
889
890     $rply = $this->get_lines();
891     $code = substr($rply,0,3);
892
893     if($this->do_debug >= 2) {
894       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
895     }
896
897     if($code != 250) {
898       $this->error =
899         array("error" => "SAML not accepted from server",
900               "smtp_code" => $code,
901               "smtp_msg" => substr($rply,4));
902       if($this->do_debug >= 1) {
903         echo "SMTP -> ERROR: " . $this->error["error"] .
904                  ": " . $rply . $this->CRLF;
905       }
906       return false;
907     }
908     return true;
909   }
910
911   /**
912    * Starts a mail transaction from the email address specified in
913    * $from. Returns true if successful or false otherwise. If True
914    * the mail transaction is started and then one or more Recipient
915    * commands may be called followed by a Data command. This command
916    * will send the message to the users terminal if they are logged
917    * in or mail it to them if they are not.
918    *
919    * Implements rfc 821: SOML <SP> FROM:<reverse-path> <CRLF>
920    *
921    * SMTP CODE SUCCESS: 250
922    * SMTP CODE SUCCESS: 552,451,452
923    * SMTP CODE SUCCESS: 500,501,502,421
924    * @access public
925    * @return bool
926    */
927   function SendOrMail($from) {
928     $this->error = null; # so no confusion is caused
929
930     if(!$this->connected()) {
931       $this->error = array(
932           "error" => "Called SendOrMail() without being connected");
933       return false;
934     }
935
936     fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF);
937
938     $rply = $this->get_lines();
939     $code = substr($rply,0,3);
940
941     if($this->do_debug >= 2) {
942       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
943     }
944
945     if($code != 250) {
946       $this->error =
947         array("error" => "SOML not accepted from server",
948               "smtp_code" => $code,
949               "smtp_msg" => substr($rply,4));
950       if($this->do_debug >= 1) {
951         echo "SMTP -> ERROR: " . $this->error["error"] .
952                  ": " . $rply . $this->CRLF;
953       }
954       return false;
955     }
956     return true;
957   }
958
959   /**
960    * This is an optional command for SMTP that this class does not
961    * support. This method is here to make the RFC821 Definition
962    * complete for this class and __may__ be implimented in the future
963    *
964    * Implements from rfc 821: TURN <CRLF>
965    *
966    * SMTP CODE SUCCESS: 250
967    * SMTP CODE FAILURE: 502
968    * SMTP CODE ERROR  : 500, 503
969    * @access public
970    * @return bool
971    */
972   function Turn() {
973     $this->error = array("error" => "This method, TURN, of the SMTP ".
974                                     "is not implemented");
975     if($this->do_debug >= 1) {
976       echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF;
977     }
978     return false;
979   }
980
981   /**
982    * Verifies that the name is recognized by the server.
983    * Returns false if the name could not be verified otherwise
984    * the response from the server is returned.
985    *
986    * Implements rfc 821: VRFY <SP> <string> <CRLF>
987    *
988    * SMTP CODE SUCCESS: 250,251
989    * SMTP CODE FAILURE: 550,551,553
990    * SMTP CODE ERROR  : 500,501,502,421
991    * @access public
992    * @return int
993    */
994   function Verify($name) {
995     $this->error = null; # so no confusion is caused
996
997     if(!$this->connected()) {
998       $this->error = array(
999               "error" => "Called Verify() without being connected");
1000       return false;
1001     }
1002
1003     fputs($this->smtp_conn,"VRFY " . $name . $this->CRLF);
1004
1005     $rply = $this->get_lines();
1006     $code = substr($rply,0,3);
1007
1008     if($this->do_debug >= 2) {
1009       echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
1010     }
1011
1012     if($code != 250 && $code != 251) {
1013       $this->error =
1014         array("error" => "VRFY failed on name '$name'",
1015               "smtp_code" => $code,
1016               "smtp_msg" => substr($rply,4));
1017       if($this->do_debug >= 1) {
1018         echo "SMTP -> ERROR: " . $this->error["error"] .
1019                  ": " . $rply . $this->CRLF;
1020       }
1021       return false;
1022     }
1023     return $rply;
1024   }
1025
1026   /*******************************************************************
1027    *                       INTERNAL FUNCTIONS                       *
1028    ******************************************************************/
1029
1030   /**
1031    * Read in as many lines as possible
1032    * either before eof or socket timeout occurs on the operation.
1033    * With SMTP we can tell if we have more lines to read if the
1034    * 4th character is '-' symbol. If it is a space then we don't
1035    * need to read anything else.
1036    * @access private
1037    * @return string
1038    */
1039   function get_lines() {
1040     $data = "";
1041     while($str = @fgets($this->smtp_conn,515)) {
1042       if($this->do_debug >= 4) {
1043         echo "SMTP -> get_lines(): \$data was \"$data\"" .
1044                  $this->CRLF;
1045         echo "SMTP -> get_lines(): \$str is \"$str\"" .
1046                  $this->CRLF;
1047       }
1048       $data .= $str;
1049       if($this->do_debug >= 4) {
1050         echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF;
1051       }
1052       # if the 4th character is a space then we are done reading
1053       # so just break the loop
1054       if(substr($str,3,1) == " ") { break; }
1055     }
1056     return $data;
1057   }
1058
1059 }
1060
1061
1062  ?>