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