File: 1.08.0a/server/base/phpmailer/class.smtp.php (View as HTML)

  1: <?php
  2: /*~ class.smtp.php
  3: .---------------------------------------------------------------------------.
  4: |  Software: PHPMailer - PHP email class                                    |
  5: |   Version: 5.0.0                                                          |
  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: |     Admin: Andy Prevost (project admininistrator)                         |
 11: |   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
 12: |          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |
 13: |   Founder: Brent R. Matzelle (original founder)                           |
 14: | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
 15: | Copyright (c) 2001-2003, Brent R. Matzelle                                |
 16: | ------------------------------------------------------------------------- |
 17: |   License: Distributed under the Lesser General Public License (LGPL)     |
 18: |            http://www.gnu.org/copyleft/lesser.html                        |
 19: | This program is distributed in the hope that it will be useful - WITHOUT  |
 20: | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
 21: | FITNESS FOR A PARTICULAR PURPOSE.                                         |
 22: | ------------------------------------------------------------------------- |
 23: | We offer a number of paid services (www.codeworxtech.com):                |
 24: | - Web Hosting on highly optimized fast and secure servers                 |
 25: | - Technology Consulting                                                   |
 26: | - Oursourcing (highly qualified programmers and graphic designers)        |
 27: '---------------------------------------------------------------------------'
 28: */
 29: 
 30: /**
 31:  * PHPMailer - PHP SMTP email transport class
 32:  * NOTE: Designed for use with PHP version 5 and up
 33:  * @package PHPMailer
 34:  * @author Andy Prevost
 35:  * @author Marcus Bointon
 36:  * @copyright 2004 - 2008 Andy Prevost
 37:  * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
 38:  * @version $Id: class.smtp.php 240 2009-03-31 04:40:33Z codeworxtech $
 39:  */
 40: 
 41: /**
 42:  * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
 43:  * commands except TURN which will always return a not implemented
 44:  * error. SMTP also provides some utility methods for sending mail
 45:  * to an SMTP server.
 46:  * original author: Chris Ryan
 47:  */
 48: 
 49: class SMTP {
 50:   /**
 51:    *  SMTP server port
 52:    *  @var int
 53:    */
 54:   public $SMTP_PORT = 25;
 55: 
 56:   /**
 57:    *  SMTP reply line ending
 58:    *  @var string
 59:    */
 60:   public $CRLF = "\r\n";
 61: 
 62:   /**
 63:    *  Sets whether debugging is turned on
 64:    *  @var bool
 65:    */
 66:   public $do_debug;       // the level of debug to perform
 67: 
 68:   /**
 69:    *  Sets VERP use on/off (default is off)
 70:    *  @var bool
 71:    */
 72:   public $do_verp = false;
 73: 
 74:   /////////////////////////////////////////////////
 75:   // PROPERTIES, PRIVATE AND PROTECTED
 76:   /////////////////////////////////////////////////
 77: 
 78:   private $smtp_conn; // the socket to the server
 79:   private $error;     // error if any on the last call
 80:   private $helo_rply; // the reply the server sent to us for HELO
 81: 
 82:   /**
 83:    * Initialize the class so that the data is in a known state.
 84:    * @access public
 85:    * @return void
 86:    */
 87:   public function __construct() {
 88:     $this->smtp_conn = 0;
 89:     $this->error = null;
 90:     $this->helo_rply = null;
 91: 
 92:     $this->do_debug = 0;
 93:   }
 94: 
 95:   /////////////////////////////////////////////////
 96:   // CONNECTION FUNCTIONS
 97:   /////////////////////////////////////////////////
 98: 
 99:   /**
100:    * Connect to the server specified on the port specified.
101:    * If the port is not specified use the default SMTP_PORT.
102:    * If tval is specified then a connection will try and be
103:    * established with the server for that number of seconds.
104:    * If tval is not specified the default is 30 seconds to
105:    * try on the connection.
106:    *
107:    * SMTP CODE SUCCESS: 220
108:    * SMTP CODE FAILURE: 421
109:    * @access public
110:    * @return bool
111:    */
112:   public function Connect($host, $port = 0, $tval = 30) {
113:     // set the error val to null so there is no confusion
114:     $this->error = null;
115: 
116:     // make sure we are __not__ connected
117:     if($this->connected()) {
118:       // already connected, generate error
119:       $this->error = array("error" => "Already connected to a server");
120:       return false;
121:     }
122: 
123:     if(empty($port)) {
124:       $port = $this->SMTP_PORT;
125:     }
126: 
127:     // connect to the smtp server
128:     $this->smtp_conn = @fsockopen($host,    // the host of the server
129:                                  $port,    // the port to use
130:                                  $errno,   // error number if any
131:                                  $errstr,  // error message if any
132:                                  $tval);   // give up after ? secs
133:     // verify we connected properly
134:     if(empty($this->smtp_conn)) {
135:       $this->error = array("error" => "Failed to connect to server",
136:                            "errno" => $errno,
137:                            "errstr" => $errstr);
138:       if($this->do_debug >= 1) {
139:         echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
140:       }
141:       return false;
142:     }
143: 
144:     // SMTP server can take longer to respond, give longer timeout for first read
145:     // Windows does not have support for this timeout function
146:     if(substr(PHP_OS, 0, 3) != "WIN")
147:      socket_set_timeout($this->smtp_conn, $tval, 0);
148: 
149:     // get any announcement
150:     $announce = $this->get_lines();
151: 
152:     if($this->do_debug >= 2) {
153:       echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
154:     }
155: 
156:     return true;
157:   }
158: 
159:   /**
160:    * Initiate a TLS communication with the server.
161:    *
162:    * SMTP CODE 220 Ready to start TLS
163:    * SMTP CODE 501 Syntax error (no parameters allowed)
164:    * SMTP CODE 454 TLS not available due to temporary reason
165:    * @access public
166:    * @return bool success
167:    */
168:   public function StartTLS() {
169:     $this->error = null; # to avoid confusion
170: 
171:     if(!$this->connected()) {
172:       $this->error = array("error" => "Called StartTLS() without being connected");
173:       return false;
174:     }
175: 
176:     fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
177: 
178:     $rply = $this->get_lines();
179:     $code = substr($rply,0,3);
180: 
181:     if($this->do_debug >= 2) {
182:       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
183:     }
184: 
185:     if($code != 220) {
186:       $this->error =
187:          array("error"     => "STARTTLS not accepted from server",
188:                "smtp_code" => $code,
189:                "smtp_msg"  => substr($rply,4));
190:       if($this->do_debug >= 1) {
191:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
192:       }
193:       return false;
194:     }
195: 
196:     // Begin encrypted connection
197:     if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
198:       return false;
199:     }
200: 
201:     return true;
202:   }
203: 
204:   /**
205:    * Performs SMTP authentication.  Must be run after running the
206:    * Hello() method.  Returns true if successfully authenticated.
207:    * @access public
208:    * @return bool
209:    */
210:   public function Authenticate($username, $password) {
211:     // Start authentication
212:     fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
213: 
214:     $rply = $this->get_lines();
215:     $code = substr($rply,0,3);
216: 
217:     if($code != 334) {
218:       $this->error =
219:         array("error" => "AUTH not accepted from server",
220:               "smtp_code" => $code,
221:               "smtp_msg" => substr($rply,4));
222:       if($this->do_debug >= 1) {
223:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
224:       }
225:       return false;
226:     }
227: 
228:     // Send encoded username
229:     fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
230: 
231:     $rply = $this->get_lines();
232:     $code = substr($rply,0,3);
233: 
234:     if($code != 334) {
235:       $this->error =
236:         array("error" => "Username not accepted from server",
237:               "smtp_code" => $code,
238:               "smtp_msg" => substr($rply,4));
239:       if($this->do_debug >= 1) {
240:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
241:       }
242:       return false;
243:     }
244: 
245:     // Send encoded password
246:     fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
247: 
248:     $rply = $this->get_lines();
249:     $code = substr($rply,0,3);
250: 
251:     if($code != 235) {
252:       $this->error =
253:         array("error" => "Password not accepted from server",
254:               "smtp_code" => $code,
255:               "smtp_msg" => substr($rply,4));
256:       if($this->do_debug >= 1) {
257:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
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:         // the socket is valid but we are not connected
275:         if($this->do_debug >= 1) {
276:             echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
277:         }
278:         $this->Close();
279:         return false;
280:       }
281:       return true; // everything looks good
282:     }
283:     return false;
284:   }
285: 
286:   /**
287:    * Closes the socket and cleans up the state of the class.
288:    * It is not considered good to use this function without
289:    * first trying to use QUIT.
290:    * @access public
291:    * @return void
292:    */
293:   public function Close() {
294:     $this->error = null; // so there is no confusion
295:     $this->helo_rply = null;
296:     if(!empty($this->smtp_conn)) {
297:       // close the connection and cleanup
298:       fclose($this->smtp_conn);
299:       $this->smtp_conn = 0;
300:     }
301:   }
302: 
303:   /////////////////////////////////////////////////
304:   // SMTP COMMANDS
305:   /////////////////////////////////////////////////
306: 
307:   /**
308:    * Issues a data command and sends the msg_data to the server
309:    * finializing the mail transaction. $msg_data is the message
310:    * that is to be send with the headers. Each header needs to be
311:    * on a single line followed by a <CRLF> with the message headers
312:    * and the message body being seperated by and additional <CRLF>.
313:    *
314:    * Implements rfc 821: DATA <CRLF>
315:    *
316:    * SMTP CODE INTERMEDIATE: 354
317:    *     [data]
318:    *     <CRLF>.<CRLF>
319:    *     SMTP CODE SUCCESS: 250
320:    *     SMTP CODE FAILURE: 552,554,451,452
321:    * SMTP CODE FAILURE: 451,554
322:    * SMTP CODE ERROR  : 500,501,503,421
323:    * @access public
324:    * @return bool
325:    */
326:   public function Data($msg_data) {
327:     $this->error = null; // so no confusion is caused
328: 
329:     if(!$this->connected()) {
330:       $this->error = array(
331:               "error" => "Called Data() without being connected");
332:       return false;
333:     }
334: 
335:     fputs($this->smtp_conn,"DATA" . $this->CRLF);
336: 
337:     $rply = $this->get_lines();
338:     $code = substr($rply,0,3);
339: 
340:     if($this->do_debug >= 2) {
341:       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
342:     }
343: 
344:     if($code != 354) {
345:       $this->error =
346:         array("error" => "DATA command not accepted from server",
347:               "smtp_code" => $code,
348:               "smtp_msg" => substr($rply,4));
349:       if($this->do_debug >= 1) {
350:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
351:       }
352:       return false;
353:     }
354: 
355:     /* the server is ready to accept data!
356:      * according to rfc 821 we should not send more than 1000
357:      * including the CRLF
358:      * characters on a single line so we will break the data up
359:      * into lines by \r and/or \n then if needed we will break
360:      * each of those into smaller lines to fit within the limit.
361:      * in addition we will be looking for lines that start with
362:      * a period '.' and append and additional period '.' to that
363:      * line. NOTE: this does not count towards limit.
364:      */
365: 
366:     // normalize the line breaks so we know the explode works
367:     $msg_data = str_replace("\r\n","\n",$msg_data);
368:     $msg_data = str_replace("\r","\n",$msg_data);
369:     $lines = explode("\n",$msg_data);
370: 
371:     /* we need to find a good way to determine is headers are
372:      * in the msg_data or if it is a straight msg body
373:      * currently I am assuming rfc 822 definitions of msg headers
374:      * and if the first field of the first line (':' sperated)
375:      * does not contain a space then it _should_ be a header
376:      * and we can process all lines before a blank "" line as
377:      * headers.
378:      */
379: 
380:     $field = substr($lines[0],0,strpos($lines[0],":"));
381:     $in_headers = false;
382:     if(!empty($field) && !strstr($field," ")) {
383:       $in_headers = true;
384:     }
385: 
386:     $max_line_length = 998; // used below; set here for ease in change
387: 
388:     while(list(,$line) = @each($lines)) {
389:       $lines_out = null;
390:       if($line == "" && $in_headers) {
391:         $in_headers = false;
392:       }
393:       // ok we need to break this line up into several smaller lines
394:       while(strlen($line) > $max_line_length) {
395:         $pos = strrpos(substr($line,0,$max_line_length)," ");
396: 
397:         // Patch to fix DOS attack
398:         if(!$pos) {
399:           $pos = $max_line_length - 1;
400:           $lines_out[] = substr($line,0,$pos);
401:           $line = substr($line,$pos);
402:         } else {
403:           $lines_out[] = substr($line,0,$pos);
404:           $line = substr($line,$pos + 1);
405:         }
406: 
407:         /* if processing headers add a LWSP-char to the front of new line
408:          * rfc 822 on long msg headers
409:          */
410:         if($in_headers) {
411:           $line = "\t" . $line;
412:         }
413:       }
414:       $lines_out[] = $line;
415: 
416:       // send the lines to the server
417:       while(list(,$line_out) = @each($lines_out)) {
418:         if(strlen($line_out) > 0)
419:         {
420:           if(substr($line_out, 0, 1) == ".") {
421:             $line_out = "." . $line_out;
422:           }
423:         }
424:         fputs($this->smtp_conn,$line_out . $this->CRLF);
425:       }
426:     }
427: 
428:     // message data has been sent
429:     fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
430: 
431:     $rply = $this->get_lines();
432:     $code = substr($rply,0,3);
433: 
434:     if($this->do_debug >= 2) {
435:       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
436:     }
437: 
438:     if($code != 250) {
439:       $this->error =
440:         array("error" => "DATA not accepted from server",
441:               "smtp_code" => $code,
442:               "smtp_msg" => substr($rply,4));
443:       if($this->do_debug >= 1) {
444:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
445:       }
446:       return false;
447:     }
448:     return true;
449:   }
450: 
451:   /**
452:    * Sends the HELO command to the smtp server.
453:    * This makes sure that we and the server are in
454:    * the same known state.
455:    *
456:    * Implements from rfc 821: HELO <SP> <domain> <CRLF>
457:    *
458:    * SMTP CODE SUCCESS: 250
459:    * SMTP CODE ERROR  : 500, 501, 504, 421
460:    * @access public
461:    * @return bool
462:    */
463:   public function Hello($host = '') {
464:     $this->error = null; // so no confusion is caused
465: 
466:     if(!$this->connected()) {
467:       $this->error = array(
468:             "error" => "Called Hello() without being connected");
469:       return false;
470:     }
471: 
472:     // if hostname for HELO was not specified send default
473:     if(empty($host)) {
474:       // determine appropriate default to send to server
475:       $host = "localhost";
476:     }
477: 
478:     // Send extended hello first (RFC 2821)
479:     if(!$this->SendHello("EHLO", $host)) {
480:       if(!$this->SendHello("HELO", $host)) {
481:         return false;
482:       }
483:     }
484: 
485:     return true;
486:   }
487: 
488:   /**
489:    * Sends a HELO/EHLO command.
490:    * @access private
491:    * @return bool
492:    */
493:   private function SendHello($hello, $host) {
494:     fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
495: 
496:     $rply = $this->get_lines();
497:     $code = substr($rply,0,3);
498: 
499:     if($this->do_debug >= 2) {
500:       echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
501:     }
502: 
503:     if($code != 250) {
504:       $this->error =
505:         array("error" => $hello . " not accepted from server",
506:               "smtp_code" => $code,
507:               "smtp_msg" => substr($rply,4));
508:       if($this->do_debug >= 1) {
509:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
510:       }
511:       return false;
512:     }
513: 
514:     $this->helo_rply = $rply;
515: 
516:     return true;
517:   }
518: 
519:   /**
520:    * Starts a mail transaction from the email address specified in
521:    * $from. Returns true if successful or false otherwise. If True
522:    * the mail transaction is started and then one or more Recipient
523:    * commands may be called followed by a Data command.
524:    *
525:    * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
526:    *
527:    * SMTP CODE SUCCESS: 250
528:    * SMTP CODE SUCCESS: 552,451,452
529:    * SMTP CODE SUCCESS: 500,501,421
530:    * @access public
531:    * @return bool
532:    */
533:   public function Mail($from) {
534:     $this->error = null; // so no confusion is caused
535: 
536:     if(!$this->connected()) {
537:       $this->error = array(
538:               "error" => "Called Mail() without being connected");
539:       return false;
540:     }
541: 
542:     $useVerp = ($this->do_verp ? "XVERP" : "");
543:     fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
544: 
545:     $rply = $this->get_lines();
546:     $code = substr($rply,0,3);
547: 
548:     if($this->do_debug >= 2) {
549:       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
550:     }
551: 
552:     if($code != 250) {
553:       $this->error =
554:         array("error" => "MAIL not accepted from server",
555:               "smtp_code" => $code,
556:               "smtp_msg" => substr($rply,4));
557:       if($this->do_debug >= 1) {
558:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
559:       }
560:       return false;
561:     }
562:     return true;
563:   }
564: 
565:   /**
566:    * Sends the quit command to the server and then closes the socket
567:    * if there is no error or the $close_on_error argument is true.
568:    *
569:    * Implements from rfc 821: QUIT <CRLF>
570:    *
571:    * SMTP CODE SUCCESS: 221
572:    * SMTP CODE ERROR  : 500
573:    * @access public
574:    * @return bool
575:    */
576:   public function Quit($close_on_error = true) {
577:     $this->error = null; // so there is no confusion
578: 
579:     if(!$this->connected()) {
580:       $this->error = array(
581:               "error" => "Called Quit() without being connected");
582:       return false;
583:     }
584: 
585:     // send the quit command to the server
586:     fputs($this->smtp_conn,"quit" . $this->CRLF);
587: 
588:     // get any good-bye messages
589:     $byemsg = $this->get_lines();
590: 
591:     if($this->do_debug >= 2) {
592:       echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
593:     }
594: 
595:     $rval = true;
596:     $e = null;
597: 
598:     $code = substr($byemsg,0,3);
599:     if($code != 221) {
600:       // use e as a tmp var cause Close will overwrite $this->error
601:       $e = array("error" => "SMTP server rejected quit command",
602:                  "smtp_code" => $code,
603:                  "smtp_rply" => substr($byemsg,4));
604:       $rval = false;
605:       if($this->do_debug >= 1) {
606:         echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
607:       }
608:     }
609: 
610:     if(empty($e) || $close_on_error) {
611:       $this->Close();
612:     }
613: 
614:     return $rval;
615:   }
616: 
617:   /**
618:    * Sends the command RCPT to the SMTP server with the TO: argument of $to.
619:    * Returns true if the recipient was accepted false if it was rejected.
620:    *
621:    * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
622:    *
623:    * SMTP CODE SUCCESS: 250,251
624:    * SMTP CODE FAILURE: 550,551,552,553,450,451,452
625:    * SMTP CODE ERROR  : 500,501,503,421
626:    * @access public
627:    * @return bool
628:    */
629:   public function Recipient($to) {
630:     $this->error = null; // so no confusion is caused
631: 
632:     if(!$this->connected()) {
633:       $this->error = array(
634:               "error" => "Called Recipient() without being connected");
635:       return false;
636:     }
637: 
638:     fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
639: 
640:     $rply = $this->get_lines();
641:     $code = substr($rply,0,3);
642: 
643:     if($this->do_debug >= 2) {
644:       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
645:     }
646: 
647:     if($code != 250 && $code != 251) {
648:       $this->error =
649:         array("error" => "RCPT not accepted from server",
650:               "smtp_code" => $code,
651:               "smtp_msg" => substr($rply,4));
652:       if($this->do_debug >= 1) {
653:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
654:       }
655:       return false;
656:     }
657:     return true;
658:   }
659: 
660:   /**
661:    * Sends the RSET command to abort and transaction that is
662:    * currently in progress. Returns true if successful false
663:    * otherwise.
664:    *
665:    * Implements rfc 821: RSET <CRLF>
666:    *
667:    * SMTP CODE SUCCESS: 250
668:    * SMTP CODE ERROR  : 500,501,504,421
669:    * @access public
670:    * @return bool
671:    */
672:   public function Reset() {
673:     $this->error = null; // so no confusion is caused
674: 
675:     if(!$this->connected()) {
676:       $this->error = array(
677:               "error" => "Called Reset() without being connected");
678:       return false;
679:     }
680: 
681:     fputs($this->smtp_conn,"RSET" . $this->CRLF);
682: 
683:     $rply = $this->get_lines();
684:     $code = substr($rply,0,3);
685: 
686:     if($this->do_debug >= 2) {
687:       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
688:     }
689: 
690:     if($code != 250) {
691:       $this->error =
692:         array("error" => "RSET failed",
693:               "smtp_code" => $code,
694:               "smtp_msg" => substr($rply,4));
695:       if($this->do_debug >= 1) {
696:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
697:       }
698:       return false;
699:     }
700: 
701:     return true;
702:   }
703: 
704:   /**
705:    * Starts a mail transaction from the email address specified in
706:    * $from. Returns true if successful or false otherwise. If True
707:    * the mail transaction is started and then one or more Recipient
708:    * commands may be called followed by a Data command. This command
709:    * will send the message to the users terminal if they are logged
710:    * in and send them an email.
711:    *
712:    * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
713:    *
714:    * SMTP CODE SUCCESS: 250
715:    * SMTP CODE SUCCESS: 552,451,452
716:    * SMTP CODE SUCCESS: 500,501,502,421
717:    * @access public
718:    * @return bool
719:    */
720:   public function SendAndMail($from) {
721:     $this->error = null; // so no confusion is caused
722: 
723:     if(!$this->connected()) {
724:       $this->error = array(
725:           "error" => "Called SendAndMail() without being connected");
726:       return false;
727:     }
728: 
729:     fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
730: 
731:     $rply = $this->get_lines();
732:     $code = substr($rply,0,3);
733: 
734:     if($this->do_debug >= 2) {
735:       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
736:     }
737: 
738:     if($code != 250) {
739:       $this->error =
740:         array("error" => "SAML not accepted from server",
741:               "smtp_code" => $code,
742:               "smtp_msg" => substr($rply,4));
743:       if($this->do_debug >= 1) {
744:         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
745:       }
746:       return false;
747:     }
748:     return true;
749:   }
750: 
751:   /**
752:    * This is an optional command for SMTP that this class does not
753:    * support. This method is here to make the RFC821 Definition
754:    * complete for this class and __may__ be implimented in the future
755:    *
756:    * Implements from rfc 821: TURN <CRLF>
757:    *
758:    * SMTP CODE SUCCESS: 250
759:    * SMTP CODE FAILURE: 502
760:    * SMTP CODE ERROR  : 500, 503
761:    * @access public
762:    * @return bool
763:    */
764:   public function Turn() {
765:     $this->error = array("error" => "This method, TURN, of the SMTP ".
766:                                     "is not implemented");
767:     if($this->do_debug >= 1) {
768:       echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
769:     }
770:     return false;
771:   }
772: 
773:   /**
774:   * Get the current error
775:   * @access public
776:   * @return array
777:   */
778:   public function getError() {
779:     return $this->error;
780:   }
781: 
782:   /////////////////////////////////////////////////
783:   // INTERNAL FUNCTIONS
784:   /////////////////////////////////////////////////
785: 
786:   /**
787:    * Read in as many lines as possible
788:    * either before eof or socket timeout occurs on the operation.
789:    * With SMTP we can tell if we have more lines to read if the
790:    * 4th character is '-' symbol. If it is a space then we don't
791:    * need to read anything else.
792:    * @access private
793:    * @return string
794:    */
795:   private function get_lines() {
796:     $data = "";
797:     while($str = @fgets($this->smtp_conn,515)) {
798:       if($this->do_debug >= 4) {
799:         echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
800:         echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
801:       }
802:       $data .= $str;
803:       if($this->do_debug >= 4) {
804:         echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
805:       }
806:       // if 4th character is a space, we are done reading, break the loop
807:       if(substr($str,3,1) == " ") { break; }
808:     }
809:     return $data;
810:   }
811: 
812: }
813: 
814: ?>