]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/phpmailer/class.smtp.php
Release 6.5.6
[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     // Start authentication
253     fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
254
255     $rply = $this->get_lines();
256     $code = substr($rply,0,3);
257
258     if($code != 334) {
259       $GLOBALS['log']->fatal("SMTP -> ERROR:AUTH not accepted from server. Code: $code Reply: $rply");
260       if($this->do_debug >= 1) {
261         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
262       }
263       return false;
264     }
265
266     // Send encoded username
267     fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
268
269     $rply = $this->get_lines();
270     $code = substr($rply,0,3);
271
272     if($code != 334) {
273       $GLOBALS['log']->fatal("SMTP -> ERROR:Username not accepted from server. Code: $code Reply: $rply ");
274       if($this->do_debug >= 1) {
275         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
276       }
277       return false;
278     }
279
280     // Send encoded password
281     $password = from_html($password);
282     fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
283
284     $rply = $this->get_lines();
285     $code = substr($rply,0,3);
286
287     if($code != 235) {
288       $GLOBALS['log']->fatal("SMTP -> ERROR:Password not accepted from server. Code: $code Reply: $rply ");
289       if($this->do_debug >= 1) {
290         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
291       }
292       return false;
293     }
294
295     return true;
296   }
297
298   /**
299    * Returns true if connected to a server otherwise false
300    * @access public
301    * @return bool
302    */
303   public function Connected() {
304     if(!empty($this->smtp_conn)) {
305       $sock_status = socket_get_status($this->smtp_conn);
306       if($sock_status["eof"]) {
307         // the socket is valid but we are not connected
308         if($this->do_debug >= 1) {
309             echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
310         }
311         $this->Close();
312         return false;
313       }
314       return true; // everything looks good
315     }
316     return false;
317   }
318
319   /**
320    * Closes the socket and cleans up the state of the class.
321    * It is not considered good to use this function without
322    * first trying to use QUIT.
323    * @access public
324    * @return void
325    */
326   public function Close() {
327     $this->error = null; // so there is no confusion
328     $this->helo_rply = null;
329     if(!empty($this->smtp_conn)) {
330       // close the connection and cleanup
331       fclose($this->smtp_conn);
332       $this->smtp_conn = 0;
333     }
334   }
335
336   /////////////////////////////////////////////////
337   // SMTP COMMANDS
338   /////////////////////////////////////////////////
339
340   /**
341    * Issues a data command and sends the msg_data to the server
342    * finializing the mail transaction. $msg_data is the message
343    * that is to be send with the headers. Each header needs to be
344    * on a single line followed by a <CRLF> with the message headers
345    * and the message body being seperated by and additional <CRLF>.
346    *
347    * Implements rfc 821: DATA <CRLF>
348    *
349    * SMTP CODE INTERMEDIATE: 354
350    *     [data]
351    *     <CRLF>.<CRLF>
352    *     SMTP CODE SUCCESS: 250
353    *     SMTP CODE FAILURE: 552,554,451,452
354    * SMTP CODE FAILURE: 451,554
355    * SMTP CODE ERROR  : 500,501,503,421
356    * @access public
357    * @return bool
358    */
359   public function Data($msg_data) {
360     $this->error = null; // so no confusion is caused
361
362     if(!$this->connected()) {
363       $this->error = array(
364               "error" => "Called Data() without being connected");
365       return false;
366     }
367
368     fputs($this->smtp_conn,"DATA" . $this->CRLF);
369
370     $rply = $this->get_lines();
371     $code = substr($rply,0,3);
372
373     if($this->do_debug >= 2) {
374       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
375     }
376
377     if($code != 354) {
378       $this->error =
379         array("error" => "DATA command not accepted from server",
380               "smtp_code" => $code,
381               "smtp_msg" => substr($rply,4));
382       if($this->do_debug >= 1) {
383         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
384       }
385       return false;
386     }
387
388     /* the server is ready to accept data!
389      * according to rfc 821 we should not send more than 1000
390      * including the CRLF
391      * characters on a single line so we will break the data up
392      * into lines by \r and/or \n then if needed we will break
393      * each of those into smaller lines to fit within the limit.
394      * in addition we will be looking for lines that start with
395      * a period '.' and append and additional period '.' to that
396      * line. NOTE: this does not count towards limit.
397      */
398
399     // normalize the line breaks so we know the explode works
400     $msg_data = str_replace("\r\n","\n",$msg_data);
401     $msg_data = str_replace("\r","\n",$msg_data);
402     $lines = explode("\n",$msg_data);
403
404     /* we need to find a good way to determine is headers are
405      * in the msg_data or if it is a straight msg body
406      * currently I am assuming rfc 822 definitions of msg headers
407      * and if the first field of the first line (':' sperated)
408      * does not contain a space then it _should_ be a header
409      * and we can process all lines before a blank "" line as
410      * headers.
411      */
412
413     $field = substr($lines[0],0,strpos($lines[0],":"));
414     $in_headers = false;
415     if(!empty($field) && !strstr($field," ")) {
416       $in_headers = true;
417     }
418
419     $max_line_length = 998; // used below; set here for ease in change
420
421     while(list(,$line) = @each($lines)) {
422       $lines_out = null;
423       if($line == "" && $in_headers) {
424         $in_headers = false;
425       }
426       // ok we need to break this line up into several smaller lines
427       while(strlen($line) > $max_line_length) {
428         $pos = strrpos(substr($line,0,$max_line_length)," ");
429
430         // Patch to fix DOS attack
431         if(!$pos) {
432           $pos = $max_line_length - 1;
433           $lines_out[] = substr($line,0,$pos);
434           $line = substr($line,$pos);
435         } else {
436           $lines_out[] = substr($line,0,$pos);
437           $line = substr($line,$pos + 1);
438         }
439
440         /* if processing headers add a LWSP-char to the front of new line
441          * rfc 822 on long msg headers
442          */
443         if($in_headers) {
444           $line = "\t" . $line;
445         }
446       }
447       $lines_out[] = $line;
448
449       // send the lines to the server
450       while(list(,$line_out) = @each($lines_out)) {
451         if(strlen($line_out) > 0)
452         {
453           if(substr($line_out, 0, 1) == ".") {
454             $line_out = "." . $line_out;
455           }
456         }
457         fputs($this->smtp_conn,$line_out . $this->CRLF);
458       }
459     }
460
461     // message data has been sent
462     fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
463
464     $rply = $this->get_lines();
465     $code = substr($rply,0,3);
466
467     if($this->do_debug >= 2) {
468       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
469     }
470
471     if($code != 250) {
472       $this->error =
473         array("error" => "DATA not accepted from server",
474               "smtp_code" => $code,
475               "smtp_msg" => substr($rply,4));
476       if($this->do_debug >= 1) {
477         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
478       }
479       return false;
480     }
481     return true;
482   }
483
484   /**
485    * Sends the HELO command to the smtp server.
486    * This makes sure that we and the server are in
487    * the same known state.
488    *
489    * Implements from rfc 821: HELO <SP> <domain> <CRLF>
490    *
491    * SMTP CODE SUCCESS: 250
492    * SMTP CODE ERROR  : 500, 501, 504, 421
493    * @access public
494    * @return bool
495    */
496   public function Hello($host = '') {
497     $this->error = null; // so no confusion is caused
498
499     if(!$this->connected()) {
500       $this->error = array(
501             "error" => "Called Hello() without being connected");
502       return false;
503     }
504
505     // if hostname for HELO was not specified send default
506     if(empty($host)) {
507       // determine appropriate default to send to server
508       $host = "localhost";
509     }
510
511     // Send extended hello first (RFC 2821)
512     if(!$this->SendHello("EHLO", $host)) {
513       if(!$this->SendHello("HELO", $host)) {
514         return false;
515       }
516     }
517
518     return true;
519   }
520
521   /**
522    * Sends a HELO/EHLO command.
523    * @access private
524    * @return bool
525    */
526   private function SendHello($hello, $host) {
527     fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
528
529     $rply = $this->get_lines();
530     $code = substr($rply,0,3);
531
532     if($this->do_debug >= 2) {
533       echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
534     }
535
536     if($code != 250) {
537       $this->error =
538         array("error" => $hello . " not accepted from server",
539               "smtp_code" => $code,
540               "smtp_msg" => substr($rply,4));
541       if($this->do_debug >= 1) {
542         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
543       }
544       return false;
545     }
546
547     $this->helo_rply = $rply;
548
549     return true;
550   }
551
552   /**
553    * Starts a mail transaction from the email address specified in
554    * $from. Returns true if successful or false otherwise. If True
555    * the mail transaction is started and then one or more Recipient
556    * commands may be called followed by a Data command.
557    *
558    * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
559    *
560    * SMTP CODE SUCCESS: 250
561    * SMTP CODE SUCCESS: 552,451,452
562    * SMTP CODE SUCCESS: 500,501,421
563    * @access public
564    * @return bool
565    */
566   public function Mail($from) {
567     $this->error = null; // so no confusion is caused
568
569     if(!$this->connected()) {
570       $this->error = array(
571               "error" => "Called Mail() without being connected");
572       return false;
573     }
574
575     $useVerp = ($this->do_verp ? "XVERP" : "");
576     fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
577
578     $rply = $this->get_lines();
579     $code = substr($rply,0,3);
580
581     if($this->do_debug >= 2) {
582       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
583     }
584
585     if($code != 250) {
586       $this->error =
587         array("error" => "MAIL not accepted from server",
588               "smtp_code" => $code,
589               "smtp_msg" => substr($rply,4));
590       if($this->do_debug >= 1) {
591         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
592       }
593       return false;
594     }
595     return true;
596   }
597
598   /**
599    * Sends the quit command to the server and then closes the socket
600    * if there is no error or the $close_on_error argument is true.
601    *
602    * Implements from rfc 821: QUIT <CRLF>
603    *
604    * SMTP CODE SUCCESS: 221
605    * SMTP CODE ERROR  : 500
606    * @access public
607    * @return bool
608    */
609   public function Quit($close_on_error = true) {
610     $this->error = null; // so there is no confusion
611
612     if(!$this->connected()) {
613       $this->error = array(
614               "error" => "Called Quit() without being connected");
615       return false;
616     }
617
618     // send the quit command to the server
619     fputs($this->smtp_conn,"quit" . $this->CRLF);
620
621     // get any good-bye messages
622     $byemsg = $this->get_lines();
623
624     if($this->do_debug >= 2) {
625       echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
626     }
627
628     $rval = true;
629     $e = null;
630
631     $code = substr($byemsg,0,3);
632     if($code != 221) {
633       // use e as a tmp var cause Close will overwrite $this->error
634       $e = array("error" => "SMTP server rejected quit command",
635                  "smtp_code" => $code,
636                  "smtp_rply" => substr($byemsg,4));
637       $rval = false;
638       if($this->do_debug >= 1) {
639         echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
640       }
641     }
642
643     if(empty($e) || $close_on_error) {
644       $this->Close();
645     }
646
647     return $rval;
648   }
649
650   /**
651    * Sends the command RCPT to the SMTP server with the TO: argument of $to.
652    * Returns true if the recipient was accepted false if it was rejected.
653    *
654    * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
655    *
656    * SMTP CODE SUCCESS: 250,251
657    * SMTP CODE FAILURE: 550,551,552,553,450,451,452
658    * SMTP CODE ERROR  : 500,501,503,421
659    * @access public
660    * @return bool
661    */
662   public function Recipient($to) {
663     $this->error = null; // so no confusion is caused
664
665     if(!$this->connected()) {
666       $this->error = array(
667               "error" => "Called Recipient() without being connected");
668       return false;
669     }
670
671     fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
672
673     $rply = $this->get_lines();
674     $code = substr($rply,0,3);
675
676     if($this->do_debug >= 2) {
677       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
678     }
679
680     if($code != 250 && $code != 251) {
681       $GLOBALS['log']->fatal("SMTP -> ERROR: RCPT not accepted from server. Code: $code Reply: $rply ");
682       if($this->do_debug >= 1) {
683         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
684       }
685       return false;
686     }
687     return true;
688   }
689
690   /**
691    * Sends the RSET command to abort and transaction that is
692    * currently in progress. Returns true if successful false
693    * otherwise.
694    *
695    * Implements rfc 821: RSET <CRLF>
696    *
697    * SMTP CODE SUCCESS: 250
698    * SMTP CODE ERROR  : 500,501,504,421
699    * @access public
700    * @return bool
701    */
702   public function Reset() {
703     $this->error = null; // so no confusion is caused
704
705     if(!$this->connected()) {
706       $this->error = array(
707               "error" => "Called Reset() without being connected");
708       return false;
709     }
710
711     fputs($this->smtp_conn,"RSET" . $this->CRLF);
712
713     $rply = $this->get_lines();
714     $code = substr($rply,0,3);
715
716     if($this->do_debug >= 2) {
717       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
718     }
719
720     if($code != 250) {
721       $this->error =
722         array("error" => "RSET failed",
723               "smtp_code" => $code,
724               "smtp_msg" => substr($rply,4));
725       if($this->do_debug >= 1) {
726         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
727       }
728       return false;
729     }
730
731     return true;
732   }
733
734   /**
735    * Starts a mail transaction from the email address specified in
736    * $from. Returns true if successful or false otherwise. If True
737    * the mail transaction is started and then one or more Recipient
738    * commands may be called followed by a Data command. This command
739    * will send the message to the users terminal if they are logged
740    * in and send them an email.
741    *
742    * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
743    *
744    * SMTP CODE SUCCESS: 250
745    * SMTP CODE SUCCESS: 552,451,452
746    * SMTP CODE SUCCESS: 500,501,502,421
747    * @access public
748    * @return bool
749    */
750   public function SendAndMail($from) {
751     $this->error = null; // so no confusion is caused
752
753     if(!$this->connected()) {
754       $this->error = array(
755           "error" => "Called SendAndMail() without being connected");
756       return false;
757     }
758
759     fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
760
761     $rply = $this->get_lines();
762     $code = substr($rply,0,3);
763
764     if($this->do_debug >= 2) {
765       echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
766     }
767
768     if($code != 250) {
769       $this->error =
770         array("error" => "SAML not accepted from server",
771               "smtp_code" => $code,
772               "smtp_msg" => substr($rply,4));
773       if($this->do_debug >= 1) {
774         echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
775       }
776       return false;
777     }
778     return true;
779   }
780
781   /**
782    * This is an optional command for SMTP that this class does not
783    * support. This method is here to make the RFC821 Definition
784    * complete for this class and __may__ be implimented in the future
785    *
786    * Implements from rfc 821: TURN <CRLF>
787    *
788    * SMTP CODE SUCCESS: 250
789    * SMTP CODE FAILURE: 502
790    * SMTP CODE ERROR  : 500, 503
791    * @access public
792    * @return bool
793    */
794   public function Turn() {
795     $this->error = array("error" => "This method, TURN, of the SMTP ".
796                                     "is not implemented");
797     if($this->do_debug >= 1) {
798       echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
799     }
800     return false;
801   }
802
803   /**
804   * Get the current error
805   * @access public
806   * @return array
807   */
808   public function getError() {
809     return $this->error;
810   }
811
812   /////////////////////////////////////////////////
813   // INTERNAL FUNCTIONS
814   /////////////////////////////////////////////////
815
816   /**
817    * Read in as many lines as possible
818    * either before eof or socket timeout occurs on the operation.
819    * With SMTP we can tell if we have more lines to read if the
820    * 4th character is '-' symbol. If it is a space then we don't
821    * need to read anything else.
822    * @access private
823    * @return string
824    */
825   private function get_lines() {
826
827     // Avoid infinite loop if we don't have a resource to read.
828     if (!is_resource($this->smtp_conn)) {
829       $GLOBALS['log']->warn('SMTP Connection is not a valid resource');
830         return "";
831     }
832
833     $data = "";
834     while(!feof($this->smtp_conn)) {
835       $str = @fgets($this->smtp_conn,515);
836       if($this->do_debug >= 4) {
837         echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
838         echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
839       }
840       $data .= $str;
841       if($this->do_debug >= 4) {
842         echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
843       }
844       // if 4th character is a space, we are done reading, break the loop
845       if(substr($str,3,1) == " ") { break; }
846     }
847     return $data;
848   }
849
850 }
851
852 ?>