File: 1.01.4b/server/base/phpmailer/class.smtp.php (View as HTML)

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