WordPress.org

Make WordPress Core

Ticket #3862: phpmailer.diff

File phpmailer.diff, 84.8 KB (added by ryan, 7 years ago)

class-phpmailer.php, class-smtp.php, new wp_mail()

  • wp-includes/class-phpmailer.php

     
     1<?php 
     2//////////////////////////////////////////////////// 
     3// PHPMailer - PHP email class 
     4// 
     5// Class for sending email using either 
     6// sendmail, PHP mail(), or SMTP.  Methods are 
     7// based upon the standard AspEmail(tm) classes. 
     8// 
     9// Copyright (C) 2001 - 2003  Brent R. Matzelle 
     10// 
     11// License: LGPL, see LICENSE 
     12//////////////////////////////////////////////////// 
     13 
     14/** 
     15 * PHPMailer - PHP email transport class 
     16 * @package PHPMailer 
     17 * @author Brent R. Matzelle 
     18 * @copyright 2001 - 2003 Brent R. Matzelle 
     19 */ 
     20class PHPMailer 
     21{ 
     22    ///////////////////////////////////////////////// 
     23    // PUBLIC VARIABLES 
     24    ///////////////////////////////////////////////// 
     25 
     26    /** 
     27     * Email priority (1 = High, 3 = Normal, 5 = low). 
     28     * @var int 
     29     */ 
     30    var $Priority          = 3; 
     31 
     32    /** 
     33     * Sets the CharSet of the message. 
     34     * @var string 
     35     */ 
     36    var $CharSet           = "UTF-8"; 
     37 
     38    /** 
     39     * Sets the Content-type of the message. 
     40     * @var string 
     41     */ 
     42    var $ContentType        = "text/plain"; 
     43 
     44    /** 
     45     * Sets the Encoding of the message. Options for this are "8bit", 
     46     * "7bit", "binary", "base64", and "quoted-printable". 
     47     * @var string 
     48     */ 
     49    var $Encoding          = "8bit"; 
     50 
     51    /** 
     52     * Holds the most recent mailer error message. 
     53     * @var string 
     54     */ 
     55    var $ErrorInfo         = ""; 
     56 
     57    /** 
     58     * Sets the From email address for the message. 
     59     * @var string 
     60     */ 
     61    var $From               = "support@wordpress.com"; 
     62 
     63    /** 
     64     * Sets the From name of the message. 
     65     * @var string 
     66     */ 
     67    var $FromName           = "Support"; 
     68 
     69    /** 
     70     * Sets the Sender email (Return-Path) of the message.  If not empty, 
     71     * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. 
     72     * @var string 
     73     */ 
     74    var $Sender            = ""; 
     75 
     76    /** 
     77     * Sets the Subject of the message. 
     78     * @var string 
     79     */ 
     80    var $Subject           = ""; 
     81 
     82    /** 
     83     * Sets the Body of the message.  This can be either an HTML or text body. 
     84     * If HTML then run IsHTML(true). 
     85     * @var string 
     86     */ 
     87    var $Body               = ""; 
     88 
     89    /** 
     90     * Sets the text-only body of the message.  This automatically sets the 
     91     * email to multipart/alternative.  This body can be read by mail 
     92     * clients that do not have HTML email capability such as mutt. Clients 
     93     * that can read HTML will view the normal Body. 
     94     * @var string 
     95     */ 
     96    var $AltBody           = ""; 
     97 
     98    /** 
     99     * Sets word wrapping on the body of the message to a given number of  
     100     * characters. 
     101     * @var int 
     102     */ 
     103    var $WordWrap          = 0; 
     104 
     105    /** 
     106     * Method to send mail: ("mail", "sendmail", or "smtp"). 
     107     * @var string 
     108     */ 
     109    var $Mailer            = "mail"; 
     110 
     111    /** 
     112     * Sets the path of the sendmail program. 
     113     * @var string 
     114     */ 
     115    var $Sendmail          = "/usr/sbin/sendmail"; 
     116     
     117    /** 
     118     * Path to PHPMailer plugins.  This is now only useful if the SMTP class  
     119     * is in a different directory than the PHP include path.   
     120     * @var string 
     121     */ 
     122    var $PluginDir         = ""; 
     123 
     124    /** 
     125     *  Holds PHPMailer version. 
     126     *  @var string 
     127     */ 
     128    var $Version           = "1.73"; 
     129 
     130    /** 
     131     * Sets the email address that a reading confirmation will be sent. 
     132     * @var string 
     133     */ 
     134    var $ConfirmReadingTo  = ""; 
     135 
     136    /** 
     137     *  Sets the hostname to use in Message-Id and Received headers 
     138     *  and as default HELO string. If empty, the value returned 
     139     *  by SERVER_NAME is used or 'localhost.localdomain'. 
     140     *  @var string 
     141     */ 
     142    var $Hostname          = ""; 
     143 
     144    ///////////////////////////////////////////////// 
     145    // SMTP VARIABLES 
     146    ///////////////////////////////////////////////// 
     147 
     148    /** 
     149     *  Sets the SMTP hosts.  All hosts must be separated by a 
     150     *  semicolon.  You can also specify a different port 
     151     *  for each host by using this format: [hostname:port] 
     152     *  (e.g. "smtp1.example.com:25;smtp2.example.com"). 
     153     *  Hosts will be tried in order. 
     154     *  @var string 
     155     */ 
     156    var $Host        = "localhost"; 
     157 
     158    /** 
     159     *  Sets the default SMTP server port. 
     160     *  @var int 
     161     */ 
     162    var $Port        = 25; 
     163 
     164    /** 
     165     *  Sets the SMTP HELO of the message (Default is $Hostname). 
     166     *  @var string 
     167     */ 
     168    var $Helo        = ""; 
     169 
     170    /** 
     171     *  Sets SMTP authentication. Utilizes the Username and Password variables. 
     172     *  @var bool 
     173     */ 
     174    var $SMTPAuth     = false; 
     175 
     176    /** 
     177     *  Sets SMTP username. 
     178     *  @var string 
     179     */ 
     180    var $Username     = ""; 
     181 
     182    /** 
     183     *  Sets SMTP password. 
     184     *  @var string 
     185     */ 
     186    var $Password     = ""; 
     187 
     188    /** 
     189     *  Sets the SMTP server timeout in seconds. This function will not  
     190     *  work with the win32 version. 
     191     *  @var int 
     192     */ 
     193    var $Timeout      = 10; 
     194 
     195    /** 
     196     *  Sets SMTP class debugging on or off. 
     197     *  @var bool 
     198     */ 
     199    var $SMTPDebug    = false; 
     200 
     201    /** 
     202     * Prevents the SMTP connection from being closed after each mail  
     203     * sending.  If this is set to true then to close the connection  
     204     * requires an explicit call to SmtpClose().  
     205     * @var bool 
     206     */ 
     207    var $SMTPKeepAlive = false; 
     208 
     209    /**#@+ 
     210     * @access private 
     211     */ 
     212    var $smtp            = NULL; 
     213    var $to              = array(); 
     214    var $cc              = array(); 
     215    var $bcc             = array(); 
     216    var $ReplyTo         = array(); 
     217    var $attachment      = array(); 
     218    var $CustomHeader    = array(); 
     219    var $message_type    = ""; 
     220    var $boundary        = array(); 
     221    var $language        = array(); 
     222    var $error_count     = 0; 
     223    var $LE              = "\n"; 
     224    /**#@-*/ 
     225     
     226    ///////////////////////////////////////////////// 
     227    // VARIABLE METHODS 
     228    ///////////////////////////////////////////////// 
     229 
     230    /** 
     231     * Sets message type to HTML.   
     232     * @param bool $bool 
     233     * @return void 
     234     */ 
     235    function IsHTML($bool) { 
     236        if($bool == true) 
     237            $this->ContentType = "text/html"; 
     238        else 
     239            $this->ContentType = "text/plain"; 
     240    } 
     241 
     242    /** 
     243     * Sets Mailer to send message using SMTP. 
     244     * @return void 
     245     */ 
     246    function IsSMTP() { 
     247        $this->Mailer = "smtp"; 
     248    } 
     249 
     250    /** 
     251     * Sets Mailer to send message using PHP mail() function. 
     252     * @return void 
     253     */ 
     254    function IsMail() { 
     255        $this->Mailer = "mail"; 
     256    } 
     257 
     258    /** 
     259     * Sets Mailer to send message using the $Sendmail program. 
     260     * @return void 
     261     */ 
     262    function IsSendmail() { 
     263        $this->Mailer = "sendmail"; 
     264    } 
     265 
     266    /** 
     267     * Sets Mailer to send message using the qmail MTA.  
     268     * @return void 
     269     */ 
     270    function IsQmail() { 
     271        $this->Sendmail = "/var/qmail/bin/sendmail"; 
     272        $this->Mailer = "sendmail"; 
     273    } 
     274 
     275 
     276    ///////////////////////////////////////////////// 
     277    // RECIPIENT METHODS 
     278    ///////////////////////////////////////////////// 
     279 
     280    /** 
     281     * Adds a "To" address.   
     282     * @param string $address 
     283     * @param string $name 
     284     * @return void 
     285     */ 
     286    function AddAddress($address, $name = "") { 
     287        $cur = count($this->to); 
     288        $this->to[$cur][0] = trim($address); 
     289        $this->to[$cur][1] = $name; 
     290    } 
     291 
     292    /** 
     293     * Adds a "Cc" address. Note: this function works 
     294     * with the SMTP mailer on win32, not with the "mail" 
     295     * mailer.   
     296     * @param string $address 
     297     * @param string $name 
     298     * @return void 
     299    */ 
     300    function AddCC($address, $name = "") { 
     301        $cur = count($this->cc); 
     302        $this->cc[$cur][0] = trim($address); 
     303        $this->cc[$cur][1] = $name; 
     304    } 
     305 
     306    /** 
     307     * Adds a "Bcc" address. Note: this function works 
     308     * with the SMTP mailer on win32, not with the "mail" 
     309     * mailer.   
     310     * @param string $address 
     311     * @param string $name 
     312     * @return void 
     313     */ 
     314    function AddBCC($address, $name = "") { 
     315        $cur = count($this->bcc); 
     316        $this->bcc[$cur][0] = trim($address); 
     317        $this->bcc[$cur][1] = $name; 
     318    } 
     319 
     320    /** 
     321     * Adds a "Reply-to" address.   
     322     * @param string $address 
     323     * @param string $name 
     324     * @return void 
     325     */ 
     326    function AddReplyTo($address, $name = "") { 
     327        $cur = count($this->ReplyTo); 
     328        $this->ReplyTo[$cur][0] = trim($address); 
     329        $this->ReplyTo[$cur][1] = $name; 
     330    } 
     331 
     332 
     333    ///////////////////////////////////////////////// 
     334    // MAIL SENDING METHODS 
     335    ///////////////////////////////////////////////// 
     336 
     337    /** 
     338     * Creates message and assigns Mailer. If the message is 
     339     * not sent successfully then it returns false.  Use the ErrorInfo 
     340     * variable to view description of the error.   
     341     * @return bool 
     342     */ 
     343    function Send() { 
     344        $header = ""; 
     345        $body = ""; 
     346        $result = true; 
     347 
     348        if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) 
     349        { 
     350            $this->SetError($this->Lang("provide_address")); 
     351            return false; 
     352        } 
     353 
     354        // Set whether the message is multipart/alternative 
     355        if(!empty($this->AltBody)) 
     356            $this->ContentType = "multipart/alternative"; 
     357 
     358        $this->error_count = 0; // reset errors 
     359        $this->SetMessageType(); 
     360        $header .= $this->CreateHeader(); 
     361        $body = $this->CreateBody(); 
     362 
     363        if($body == "") { return false; } 
     364 
     365        // Choose the mailer 
     366        switch($this->Mailer) 
     367        { 
     368            case "sendmail": 
     369                $result = $this->SendmailSend($header, $body); 
     370                break; 
     371            case "mail": 
     372                $result = $this->MailSend($header, $body); 
     373                break; 
     374            case "smtp": 
     375                $result = $this->SmtpSend($header, $body); 
     376                break; 
     377            default: 
     378            $this->SetError($this->Mailer . $this->Lang("mailer_not_supported")); 
     379                $result = false; 
     380                break; 
     381        } 
     382 
     383        return $result; 
     384    } 
     385     
     386    /** 
     387     * Sends mail using the $Sendmail program.   
     388     * @access private 
     389     * @return bool 
     390     */ 
     391    function SendmailSend($header, $body) { 
     392        if ($this->Sender != "") 
     393            $sendmail = sprintf("%s -oi -f %s -t", $this->Sendmail, $this->Sender); 
     394        else 
     395            $sendmail = sprintf("%s -oi -t", $this->Sendmail); 
     396 
     397        if(!@$mail = popen($sendmail, "w")) 
     398        { 
     399            $this->SetError($this->Lang("execute") . $this->Sendmail); 
     400            return false; 
     401        } 
     402 
     403        fputs($mail, $header); 
     404        fputs($mail, $body); 
     405         
     406        $result = pclose($mail) >> 8 & 0xFF; 
     407        if($result != 0) 
     408        { 
     409            $this->SetError($this->Lang("execute") . $this->Sendmail); 
     410            return false; 
     411        } 
     412 
     413        return true; 
     414    } 
     415 
     416    /** 
     417     * Sends mail using the PHP mail() function.   
     418     * @access private 
     419     * @return bool 
     420     */ 
     421    function MailSend($header, $body) { 
     422        $to = ""; 
     423        for($i = 0; $i < count($this->to); $i++) 
     424        { 
     425            if($i != 0) { $to .= ", "; } 
     426            $to .= $this->to[$i][0]; 
     427        } 
     428 
     429        if ($this->Sender != "" && strlen(ini_get("safe_mode"))< 1) 
     430        { 
     431            $old_from = ini_get("sendmail_from"); 
     432            ini_set("sendmail_from", $this->Sender); 
     433            $params = sprintf("-oi -f %s", $this->Sender); 
     434            $rt = @mail($to, $this->EncodeHeader($this->Subject), $body,  
     435                        $header, $params); 
     436        } 
     437        else 
     438            $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, $header); 
     439 
     440        if (isset($old_from)) 
     441            ini_set("sendmail_from", $old_from); 
     442 
     443        if(!$rt) 
     444        { 
     445            $this->SetError($this->Lang("instantiate")); 
     446            return false; 
     447        } 
     448 
     449        return true; 
     450    } 
     451 
     452    /** 
     453     * Sends mail via SMTP using PhpSMTP (Author: 
     454     * Chris Ryan).  Returns bool.  Returns false if there is a 
     455     * bad MAIL FROM, RCPT, or DATA input. 
     456     * @access private 
     457     * @return bool 
     458     */ 
     459    function SmtpSend($header, $body) { 
     460        include_once($this->PluginDir . "class.smtp.php"); 
     461        $error = ""; 
     462        $bad_rcpt = array(); 
     463 
     464        if(!$this->SmtpConnect()) 
     465            return false; 
     466 
     467        $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender; 
     468        if(!$this->smtp->Mail($smtp_from)) 
     469        { 
     470            $error = $this->Lang("from_failed") . $smtp_from; 
     471            $this->SetError($error); 
     472            $this->smtp->Reset(); 
     473            return false; 
     474        } 
     475 
     476        // Attempt to send attach all recipients 
     477        for($i = 0; $i < count($this->to); $i++) 
     478        { 
     479            if(!$this->smtp->Recipient($this->to[$i][0])) 
     480                $bad_rcpt[] = $this->to[$i][0]; 
     481        } 
     482        for($i = 0; $i < count($this->cc); $i++) 
     483        { 
     484            if(!$this->smtp->Recipient($this->cc[$i][0])) 
     485                $bad_rcpt[] = $this->cc[$i][0]; 
     486        } 
     487        for($i = 0; $i < count($this->bcc); $i++) 
     488        { 
     489            if(!$this->smtp->Recipient($this->bcc[$i][0])) 
     490                $bad_rcpt[] = $this->bcc[$i][0]; 
     491        } 
     492 
     493        if(count($bad_rcpt) > 0) // Create error message 
     494        { 
     495            for($i = 0; $i < count($bad_rcpt); $i++) 
     496            { 
     497                if($i != 0) { $error .= ", "; } 
     498                $error .= $bad_rcpt[$i]; 
     499            } 
     500            $error = $this->Lang("recipients_failed") . $error; 
     501            $this->SetError($error); 
     502            $this->smtp->Reset(); 
     503            return false; 
     504        } 
     505 
     506        if(!$this->smtp->Data($header . $body)) 
     507        { 
     508            $this->SetError($this->Lang("data_not_accepted")); 
     509            $this->smtp->Reset(); 
     510            return false; 
     511        } 
     512        if($this->SMTPKeepAlive == true) 
     513            $this->smtp->Reset(); 
     514        else 
     515            $this->SmtpClose(); 
     516 
     517        return true; 
     518    } 
     519 
     520    /** 
     521     * Initiates a connection to an SMTP server.  Returns false if the  
     522     * operation failed. 
     523     * @access private 
     524     * @return bool 
     525     */ 
     526    function SmtpConnect() { 
     527        if($this->smtp == NULL) { $this->smtp = new SMTP(); } 
     528 
     529        $this->smtp->do_debug = $this->SMTPDebug; 
     530        $hosts = explode(";", $this->Host); 
     531        $index = 0; 
     532        $connection = ($this->smtp->Connected());  
     533 
     534        // Retry while there is no connection 
     535        while($index < count($hosts) && $connection == false) 
     536        { 
     537            if(strstr($hosts[$index], ":")) 
     538                list($host, $port) = explode(":", $hosts[$index]); 
     539            else 
     540            { 
     541                $host = $hosts[$index]; 
     542                $port = $this->Port; 
     543            } 
     544 
     545            if($this->smtp->Connect($host, $port, $this->Timeout)) 
     546            { 
     547                if ($this->Helo != '') 
     548                    $this->smtp->Hello($this->Helo); 
     549                else 
     550                    $this->smtp->Hello($this->ServerHostname()); 
     551         
     552                if($this->SMTPAuth) 
     553                { 
     554                    if(!$this->smtp->Authenticate($this->Username,  
     555                                                  $this->Password)) 
     556                    { 
     557                        $this->SetError($this->Lang("authenticate")); 
     558                        $this->smtp->Reset(); 
     559                        $connection = false; 
     560                    } 
     561                } 
     562                $connection = true; 
     563            } 
     564            $index++; 
     565        } 
     566        if(!$connection) 
     567            $this->SetError($this->Lang("connect_host")); 
     568 
     569        return $connection; 
     570    } 
     571 
     572    /** 
     573     * Closes the active SMTP session if one exists. 
     574     * @return void 
     575     */ 
     576    function SmtpClose() { 
     577        if($this->smtp != NULL) 
     578        { 
     579            if($this->smtp->Connected()) 
     580            { 
     581                $this->smtp->Quit(); 
     582                $this->smtp->Close(); 
     583            } 
     584        } 
     585    } 
     586 
     587    /** 
     588     * Sets the language for all class error messages.  Returns false  
     589     * if it cannot load the language file.  The default language type 
     590     * is English. 
     591     * @param string $lang_type Type of language (e.g. Portuguese: "br") 
     592     * @param string $lang_path Path to the language file directory 
     593     * @access public 
     594     * @return bool 
     595     */ 
     596    function SetLanguage($lang_type, $lang_path = "language/") { 
     597        if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php')) 
     598            include($lang_path.'phpmailer.lang-'.$lang_type.'.php'); 
     599        else if(file_exists($lang_path.'phpmailer.lang-en.php')) 
     600            include($lang_path.'phpmailer.lang-en.php'); 
     601        else 
     602        { 
     603            $this->SetError("Could not load language file"); 
     604            return false; 
     605        } 
     606        $this->language = $PHPMAILER_LANG; 
     607     
     608        return true; 
     609    } 
     610 
     611    ///////////////////////////////////////////////// 
     612    // MESSAGE CREATION METHODS 
     613    ///////////////////////////////////////////////// 
     614 
     615    /** 
     616     * Creates recipient headers.   
     617     * @access private 
     618     * @return string 
     619     */ 
     620    function AddrAppend($type, $addr) { 
     621        $addr_str = $type . ": "; 
     622        $addr_str .= $this->AddrFormat($addr[0]); 
     623        if(count($addr) > 1) 
     624        { 
     625            for($i = 1; $i < count($addr); $i++) 
     626                $addr_str .= ", " . $this->AddrFormat($addr[$i]); 
     627        } 
     628        $addr_str .= $this->LE; 
     629 
     630        return $addr_str; 
     631    } 
     632     
     633    /** 
     634     * Formats an address correctly.  
     635     * @access private 
     636     * @return string 
     637     */ 
     638    function AddrFormat($addr) { 
     639        if(empty($addr[1])) 
     640            $formatted = $addr[0]; 
     641        else 
     642        { 
     643            $formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" .  
     644                         $addr[0] . ">"; 
     645        } 
     646 
     647        return $formatted; 
     648    } 
     649 
     650    /** 
     651     * Wraps message for use with mailers that do not 
     652     * automatically perform wrapping and for quoted-printable. 
     653     * Original written by philippe.   
     654     * @access private 
     655     * @return string 
     656     */ 
     657    function WrapText($message, $length, $qp_mode = false) { 
     658        $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; 
     659 
     660        $message = $this->FixEOL($message); 
     661        if (substr($message, -1) == $this->LE) 
     662            $message = substr($message, 0, -1); 
     663 
     664        $line = explode($this->LE, $message); 
     665        $message = ""; 
     666        for ($i=0 ;$i < count($line); $i++) 
     667        { 
     668          $line_part = explode(" ", $line[$i]); 
     669          $buf = ""; 
     670          for ($e = 0; $e<count($line_part); $e++) 
     671          { 
     672              $word = $line_part[$e]; 
     673              if ($qp_mode and (strlen($word) > $length)) 
     674              { 
     675                $space_left = $length - strlen($buf) - 1; 
     676                if ($e != 0) 
     677                { 
     678                    if ($space_left > 20) 
     679                    { 
     680                        $len = $space_left; 
     681                        if (substr($word, $len - 1, 1) == "=") 
     682                          $len--; 
     683                        elseif (substr($word, $len - 2, 1) == "=") 
     684                          $len -= 2; 
     685                        $part = substr($word, 0, $len); 
     686                        $word = substr($word, $len); 
     687                        $buf .= " " . $part; 
     688                        $message .= $buf . sprintf("=%s", $this->LE); 
     689                    } 
     690                    else 
     691                    { 
     692                        $message .= $buf . $soft_break; 
     693                    } 
     694                    $buf = ""; 
     695                } 
     696                while (strlen($word) > 0) 
     697                { 
     698                    $len = $length; 
     699                    if (substr($word, $len - 1, 1) == "=") 
     700                        $len--; 
     701                    elseif (substr($word, $len - 2, 1) == "=") 
     702                        $len -= 2; 
     703                    $part = substr($word, 0, $len); 
     704                    $word = substr($word, $len); 
     705 
     706                    if (strlen($word) > 0) 
     707                        $message .= $part . sprintf("=%s", $this->LE); 
     708                    else 
     709                        $buf = $part; 
     710                } 
     711              } 
     712              else 
     713              { 
     714                $buf_o = $buf; 
     715                $buf .= ($e == 0) ? $word : (" " . $word);  
     716 
     717                if (strlen($buf) > $length and $buf_o != "") 
     718                { 
     719                    $message .= $buf_o . $soft_break; 
     720                    $buf = $word; 
     721                } 
     722              } 
     723          } 
     724          $message .= $buf . $this->LE; 
     725        } 
     726 
     727        return $message; 
     728    } 
     729     
     730    /** 
     731     * Set the body wrapping. 
     732     * @access private 
     733     * @return void 
     734     */ 
     735    function SetWordWrap() { 
     736        if($this->WordWrap < 1) 
     737            return; 
     738             
     739        switch($this->message_type) 
     740        { 
     741           case "alt": 
     742              // fall through 
     743           case "alt_attachments": 
     744              $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); 
     745              break; 
     746           default: 
     747              $this->Body = $this->WrapText($this->Body, $this->WordWrap); 
     748              break; 
     749        } 
     750    } 
     751 
     752    /** 
     753     * Assembles message header.   
     754     * @access private 
     755     * @return string 
     756     */ 
     757    function CreateHeader() { 
     758        $result = ""; 
     759         
     760        // Set the boundaries 
     761        $uniq_id = md5(uniqid(time())); 
     762        $this->boundary[1] = "b1_" . $uniq_id; 
     763        $this->boundary[2] = "b2_" . $uniq_id; 
     764 
     765        $result .= $this->HeaderLine("Date", $this->RFCDate()); 
     766        if($this->Sender == "") 
     767            $result .= $this->HeaderLine("Return-Path", trim($this->From)); 
     768        else 
     769            $result .= $this->HeaderLine("Return-Path", trim($this->Sender)); 
     770         
     771        // To be created automatically by mail() 
     772        if($this->Mailer != "mail") 
     773        { 
     774            if(count($this->to) > 0) 
     775                $result .= $this->AddrAppend("To", $this->to); 
     776            else if (count($this->cc) == 0) 
     777                $result .= $this->HeaderLine("To", "undisclosed-recipients:;"); 
     778            if(count($this->cc) > 0) 
     779                $result .= $this->AddrAppend("Cc", $this->cc); 
     780        } 
     781 
     782        $from = array(); 
     783        $from[0][0] = trim($this->From); 
     784        $from[0][1] = $this->FromName; 
     785        $result .= $this->AddrAppend("From", $from);  
     786 
     787        // sendmail and mail() extract Bcc from the header before sending 
     788        if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0)) 
     789            $result .= $this->AddrAppend("Bcc", $this->bcc); 
     790 
     791        if(count($this->ReplyTo) > 0) 
     792            $result .= $this->AddrAppend("Reply-to", $this->ReplyTo); 
     793 
     794        // mail() sets the subject itself 
     795        if($this->Mailer != "mail") 
     796            $result .= $this->HeaderLine("Subject", $this->EncodeHeader(trim($this->Subject))); 
     797 
     798        $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); 
     799        $result .= $this->HeaderLine("X-Priority", $this->Priority); 
     800         
     801        if($this->ConfirmReadingTo != "") 
     802        { 
     803            $result .= $this->HeaderLine("Disposition-Notification-To",  
     804                       "<" . trim($this->ConfirmReadingTo) . ">"); 
     805        } 
     806 
     807        // Add custom headers 
     808        for($index = 0; $index < count($this->CustomHeader); $index++) 
     809        { 
     810            $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]),  
     811                       $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); 
     812        } 
     813        $result .= $this->HeaderLine("MIME-Version", "1.0"); 
     814 
     815        switch($this->message_type) 
     816        { 
     817            case "plain": 
     818                $result .= $this->HeaderLine("Content-Transfer-Encoding", $this->Encoding); 
     819                $result .= sprintf("Content-Type: %s; charset=\"%s\"", 
     820                                    $this->ContentType, $this->CharSet); 
     821                break; 
     822            case "attachments": 
     823                // fall through 
     824            case "alt_attachments": 
     825                if($this->InlineImageExists()) 
     826                { 
     827                    $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s",  
     828                                    "multipart/related", $this->LE, $this->LE,  
     829                                    $this->boundary[1], $this->LE); 
     830                } 
     831                else 
     832                { 
     833                    $result .= $this->HeaderLine("Content-Type", "multipart/mixed;"); 
     834                    $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 
     835                } 
     836                break; 
     837            case "alt": 
     838                $result .= $this->HeaderLine("Content-Type", "multipart/alternative;"); 
     839                $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 
     840                break; 
     841        } 
     842 
     843        if($this->Mailer != "mail") 
     844            $result .= $this->LE.$this->LE; 
     845 
     846        return $result; 
     847    } 
     848 
     849    /** 
     850     * Assembles the message body.  Returns an empty string on failure. 
     851     * @access private 
     852     * @return string 
     853     */ 
     854    function CreateBody() { 
     855        $result = ""; 
     856 
     857        $this->SetWordWrap(); 
     858 
     859        switch($this->message_type) 
     860        { 
     861            case "alt": 
     862                $result .= $this->GetBoundary($this->boundary[1], "",  
     863                                              "text/plain", ""); 
     864                $result .= $this->EncodeString($this->AltBody, $this->Encoding); 
     865                $result .= $this->LE.$this->LE; 
     866                $result .= $this->GetBoundary($this->boundary[1], "",  
     867                                              "text/html", ""); 
     868                 
     869                $result .= $this->EncodeString($this->Body, $this->Encoding); 
     870                $result .= $this->LE.$this->LE; 
     871     
     872                $result .= $this->EndBoundary($this->boundary[1]); 
     873                break; 
     874            case "plain": 
     875                $result .= $this->EncodeString($this->Body, $this->Encoding); 
     876                break; 
     877            case "attachments": 
     878                $result .= $this->GetBoundary($this->boundary[1], "", "", ""); 
     879                $result .= $this->EncodeString($this->Body, $this->Encoding); 
     880                $result .= $this->LE; 
     881      
     882                $result .= $this->AttachAll(); 
     883                break; 
     884            case "alt_attachments": 
     885                $result .= sprintf("--%s%s", $this->boundary[1], $this->LE); 
     886                $result .= sprintf("Content-Type: %s;%s" . 
     887                                   "\tboundary=\"%s\"%s", 
     888                                   "multipart/alternative", $this->LE,  
     889                                   $this->boundary[2], $this->LE.$this->LE); 
     890     
     891                // Create text body 
     892                $result .= $this->GetBoundary($this->boundary[2], "",  
     893                                              "text/plain", "") . $this->LE; 
     894 
     895                $result .= $this->EncodeString($this->AltBody, $this->Encoding); 
     896                $result .= $this->LE.$this->LE; 
     897     
     898                // Create the HTML body 
     899                $result .= $this->GetBoundary($this->boundary[2], "",  
     900                                              "text/html", "") . $this->LE; 
     901     
     902                $result .= $this->EncodeString($this->Body, $this->Encoding); 
     903                $result .= $this->LE.$this->LE; 
     904 
     905                $result .= $this->EndBoundary($this->boundary[2]); 
     906                 
     907                $result .= $this->AttachAll(); 
     908                break; 
     909        } 
     910        if($this->IsError()) 
     911            $result = ""; 
     912 
     913        return $result; 
     914    } 
     915 
     916    /** 
     917     * Returns the start of a message boundary. 
     918     * @access private 
     919     */ 
     920    function GetBoundary($boundary, $charSet, $contentType, $encoding) { 
     921        $result = ""; 
     922        if($charSet == "") { $charSet = $this->CharSet; } 
     923        if($contentType == "") { $contentType = $this->ContentType; } 
     924        if($encoding == "") { $encoding = $this->Encoding; } 
     925 
     926        $result .= $this->TextLine("--" . $boundary); 
     927        $result .= sprintf("Content-Type: %s; charset = \"%s\"",  
     928                            $contentType, $charSet); 
     929        $result .= $this->LE; 
     930        $result .= $this->HeaderLine("Content-Transfer-Encoding", $encoding); 
     931        $result .= $this->LE; 
     932        
     933        return $result; 
     934    } 
     935     
     936    /** 
     937     * Returns the end of a message boundary. 
     938     * @access private 
     939     */ 
     940    function EndBoundary($boundary) { 
     941        return $this->LE . "--" . $boundary . "--" . $this->LE;  
     942    } 
     943     
     944    /** 
     945     * Sets the message type. 
     946     * @access private 
     947     * @return void 
     948     */ 
     949    function SetMessageType() { 
     950        if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) 
     951            $this->message_type = "plain"; 
     952        else 
     953        { 
     954            if(count($this->attachment) > 0) 
     955                $this->message_type = "attachments"; 
     956            if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) 
     957                $this->message_type = "alt"; 
     958            if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) 
     959                $this->message_type = "alt_attachments"; 
     960        } 
     961    } 
     962 
     963    /** 
     964     * Returns a formatted header line. 
     965     * @access private 
     966     * @return string 
     967     */ 
     968    function HeaderLine($name, $value) { 
     969        return $name . ": " . $value . $this->LE; 
     970    } 
     971 
     972    /** 
     973     * Returns a formatted mail line. 
     974     * @access private 
     975     * @return string 
     976     */ 
     977    function TextLine($value) { 
     978        return $value . $this->LE; 
     979    } 
     980 
     981    ///////////////////////////////////////////////// 
     982    // ATTACHMENT METHODS 
     983    ///////////////////////////////////////////////// 
     984 
     985    /** 
     986     * Adds an attachment from a path on the filesystem. 
     987     * Returns false if the file could not be found 
     988     * or accessed. 
     989     * @param string $path Path to the attachment. 
     990     * @param string $name Overrides the attachment name. 
     991     * @param string $encoding File encoding (see $Encoding). 
     992     * @param string $type File extension (MIME) type. 
     993     * @return bool 
     994     */ 
     995    function AddAttachment($path, $name = "", $encoding = "base64",  
     996                           $type = "application/octet-stream") { 
     997        if(!@is_file($path)) 
     998        { 
     999            $this->SetError($this->Lang("file_access") . $path); 
     1000            return false; 
     1001        } 
     1002 
     1003        $filename = basename($path); 
     1004        if($name == "") 
     1005            $name = $filename; 
     1006 
     1007        $cur = count($this->attachment); 
     1008        $this->attachment[$cur][0] = $path; 
     1009        $this->attachment[$cur][1] = $filename; 
     1010        $this->attachment[$cur][2] = $name; 
     1011        $this->attachment[$cur][3] = $encoding; 
     1012        $this->attachment[$cur][4] = $type; 
     1013        $this->attachment[$cur][5] = false; // isStringAttachment 
     1014        $this->attachment[$cur][6] = "attachment"; 
     1015        $this->attachment[$cur][7] = 0; 
     1016 
     1017        return true; 
     1018    } 
     1019 
     1020    /** 
     1021     * Attaches all fs, string, and binary attachments to the message. 
     1022     * Returns an empty string on failure. 
     1023     * @access private 
     1024     * @return string 
     1025     */ 
     1026    function AttachAll() { 
     1027        // Return text of body 
     1028        $mime = array(); 
     1029 
     1030        // Add all attachments 
     1031        for($i = 0; $i < count($this->attachment); $i++) 
     1032        { 
     1033            // Check for string attachment 
     1034            $bString = $this->attachment[$i][5]; 
     1035            if ($bString) 
     1036                $string = $this->attachment[$i][0]; 
     1037            else 
     1038                $path = $this->attachment[$i][0]; 
     1039 
     1040            $filename    = $this->attachment[$i][1]; 
     1041            $name        = $this->attachment[$i][2]; 
     1042            $encoding    = $this->attachment[$i][3]; 
     1043            $type        = $this->attachment[$i][4]; 
     1044            $disposition = $this->attachment[$i][6]; 
     1045            $cid         = $this->attachment[$i][7]; 
     1046             
     1047            $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE); 
     1048            $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE); 
     1049            $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); 
     1050 
     1051            if($disposition == "inline") 
     1052                $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); 
     1053 
     1054            $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s",  
     1055                              $disposition, $name, $this->LE.$this->LE); 
     1056 
     1057            // Encode as string attachment 
     1058            if($bString) 
     1059            { 
     1060                $mime[] = $this->EncodeString($string, $encoding); 
     1061                if($this->IsError()) { return ""; } 
     1062                $mime[] = $this->LE.$this->LE; 
     1063            } 
     1064            else 
     1065            { 
     1066                $mime[] = $this->EncodeFile($path, $encoding);                 
     1067                if($this->IsError()) { return ""; } 
     1068                $mime[] = $this->LE.$this->LE; 
     1069            } 
     1070        } 
     1071 
     1072        $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE); 
     1073 
     1074        return join("", $mime); 
     1075    } 
     1076     
     1077    /** 
     1078     * Encodes attachment in requested format.  Returns an 
     1079     * empty string on failure. 
     1080     * @access private 
     1081     * @return string 
     1082     */ 
     1083    function EncodeFile ($path, $encoding = "base64") { 
     1084        if(!@$fd = fopen($path, "rb")) 
     1085        { 
     1086            $this->SetError($this->Lang("file_open") . $path); 
     1087            return ""; 
     1088        } 
     1089        $magic_quotes = get_magic_quotes_runtime(); 
     1090        set_magic_quotes_runtime(0); 
     1091        $file_buffer = fread($fd, filesize($path)); 
     1092        $file_buffer = $this->EncodeString($file_buffer, $encoding); 
     1093        fclose($fd); 
     1094        set_magic_quotes_runtime($magic_quotes); 
     1095 
     1096        return $file_buffer; 
     1097    } 
     1098 
     1099    /** 
     1100     * Encodes string to requested format. Returns an 
     1101     * empty string on failure. 
     1102     * @access private 
     1103     * @return string 
     1104     */ 
     1105    function EncodeString ($str, $encoding = "base64") { 
     1106        $encoded = ""; 
     1107        switch(strtolower($encoding)) { 
     1108          case "base64": 
     1109              // chunk_split is found in PHP >= 3.0.6 
     1110              $encoded = chunk_split(base64_encode($str), 76, $this->LE); 
     1111              break; 
     1112          case "7bit": 
     1113          case "8bit": 
     1114              $encoded = $this->FixEOL($str); 
     1115              if (substr($encoded, -(strlen($this->LE))) != $this->LE) 
     1116                $encoded .= $this->LE; 
     1117              break; 
     1118          case "binary": 
     1119              $encoded = $str; 
     1120              break; 
     1121          case "quoted-printable": 
     1122              $encoded = $this->EncodeQP($str); 
     1123              break; 
     1124          default: 
     1125              $this->SetError($this->Lang("encoding") . $encoding); 
     1126              break; 
     1127        } 
     1128        return $encoded; 
     1129    } 
     1130 
     1131    /** 
     1132     * Encode a header string to best of Q, B, quoted or none.   
     1133     * @access private 
     1134     * @return string 
     1135     */ 
     1136    function EncodeHeader ($str, $position = 'text') { 
     1137      $x = 0; 
     1138       
     1139      switch (strtolower($position)) { 
     1140        case 'phrase': 
     1141          if (!preg_match('/[\200-\377]/', $str)) { 
     1142            // Can't use addslashes as we don't know what value has magic_quotes_sybase. 
     1143            $encoded = addcslashes($str, "\0..\37\177\\\""); 
     1144 
     1145            if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) 
     1146              return ($encoded); 
     1147            else 
     1148              return ("\"$encoded\""); 
     1149          } 
     1150          $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); 
     1151          break; 
     1152        case 'comment': 
     1153          $x = preg_match_all('/[()"]/', $str, $matches); 
     1154          // Fall-through 
     1155        case 'text': 
     1156        default: 
     1157          $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); 
     1158          break; 
     1159      } 
     1160 
     1161      if ($x == 0) 
     1162        return ($str); 
     1163 
     1164      $maxlen = 75 - 7 - strlen($this->CharSet); 
     1165      // Try to select the encoding which should produce the shortest output 
     1166      if (strlen($str)/3 < $x) { 
     1167        $encoding = 'B'; 
     1168        $encoded = base64_encode($str); 
     1169        $maxlen -= $maxlen % 4; 
     1170        $encoded = trim(chunk_split($encoded, $maxlen, "\n")); 
     1171      } else { 
     1172        $encoding = 'Q'; 
     1173        $encoded = $this->EncodeQ($str, $position); 
     1174        $encoded = $this->WrapText($encoded, $maxlen, true); 
     1175        $encoded = str_replace("=".$this->LE, "\n", trim($encoded)); 
     1176      } 
     1177 
     1178      $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); 
     1179      $encoded = trim(str_replace("\n", $this->LE, $encoded)); 
     1180       
     1181      return $encoded; 
     1182    } 
     1183     
     1184    /** 
     1185     * Encode string to quoted-printable.   
     1186     * @access private 
     1187     * @return string 
     1188     */ 
     1189    function EncodeQP ($str) { 
     1190        $encoded = $this->FixEOL($str); 
     1191        if (substr($encoded, -(strlen($this->LE))) != $this->LE) 
     1192            $encoded .= $this->LE; 
     1193 
     1194        // Replace every high ascii, control and = characters 
     1195        $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e', 
     1196                  "'='.sprintf('%02X', ord('\\1'))", $encoded); 
     1197        // Replace every spaces and tabs when it's the last character on a line 
     1198        $encoded = preg_replace("/([\011\040])".$this->LE."/e", 
     1199                  "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded); 
     1200 
     1201        // Maximum line length of 76 characters before CRLF (74 + space + '=') 
     1202        $encoded = $this->WrapText($encoded, 74, true); 
     1203 
     1204        return $encoded; 
     1205    } 
     1206 
     1207    /** 
     1208     * Encode string to q encoding.   
     1209     * @access private 
     1210     * @return string 
     1211     */ 
     1212    function EncodeQ ($str, $position = "text") { 
     1213        // There should not be any EOL in the string 
     1214        $encoded = preg_replace("[\r\n]", "", $str); 
     1215 
     1216        switch (strtolower($position)) { 
     1217          case "phrase": 
     1218            $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); 
     1219            break; 
     1220          case "comment": 
     1221            $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); 
     1222          case "text": 
     1223          default: 
     1224            // Replace every high ascii, control =, ? and _ characters 
     1225            $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', 
     1226                  "'='.sprintf('%02X', ord('\\1'))", $encoded); 
     1227            break; 
     1228        } 
     1229         
     1230        // Replace every spaces to _ (more readable than =20) 
     1231        $encoded = str_replace(" ", "_", $encoded); 
     1232 
     1233        return $encoded; 
     1234    } 
     1235 
     1236    /** 
     1237     * Adds a string or binary attachment (non-filesystem) to the list. 
     1238     * This method can be used to attach ascii or binary data, 
     1239     * such as a BLOB record from a database. 
     1240     * @param string $string String attachment data. 
     1241     * @param string $filename Name of the attachment. 
     1242     * @param string $encoding File encoding (see $Encoding). 
     1243     * @param string $type File extension (MIME) type. 
     1244     * @return void 
     1245     */ 
     1246    function AddStringAttachment($string, $filename, $encoding = "base64",  
     1247                                 $type = "application/octet-stream") { 
     1248        // Append to $attachment array 
     1249        $cur = count($this->attachment); 
     1250        $this->attachment[$cur][0] = $string; 
     1251        $this->attachment[$cur][1] = $filename; 
     1252        $this->attachment[$cur][2] = $filename; 
     1253        $this->attachment[$cur][3] = $encoding; 
     1254        $this->attachment[$cur][4] = $type; 
     1255        $this->attachment[$cur][5] = true; // isString 
     1256        $this->attachment[$cur][6] = "attachment"; 
     1257        $this->attachment[$cur][7] = 0; 
     1258    } 
     1259     
     1260    /** 
     1261     * Adds an embedded attachment.  This can include images, sounds, and  
     1262     * just about any other document.  Make sure to set the $type to an  
     1263     * image type.  For JPEG images use "image/jpeg" and for GIF images  
     1264     * use "image/gif". 
     1265     * @param string $path Path to the attachment. 
     1266     * @param string $cid Content ID of the attachment.  Use this to identify  
     1267     *        the Id for accessing the image in an HTML form. 
     1268     * @param string $name Overrides the attachment name. 
     1269     * @param string $encoding File encoding (see $Encoding). 
     1270     * @param string $type File extension (MIME) type.   
     1271     * @return bool 
     1272     */ 
     1273    function AddEmbeddedImage($path, $cid, $name = "", $encoding = "base64",  
     1274                              $type = "application/octet-stream") { 
     1275     
     1276        if(!@is_file($path)) 
     1277        { 
     1278            $this->SetError($this->Lang("file_access") . $path); 
     1279            return false; 
     1280        } 
     1281 
     1282        $filename = basename($path); 
     1283        if($name == "") 
     1284            $name = $filename; 
     1285 
     1286        // Append to $attachment array 
     1287        $cur = count($this->attachment); 
     1288        $this->attachment[$cur][0] = $path; 
     1289        $this->attachment[$cur][1] = $filename; 
     1290        $this->attachment[$cur][2] = $name; 
     1291        $this->attachment[$cur][3] = $encoding; 
     1292        $this->attachment[$cur][4] = $type; 
     1293        $this->attachment[$cur][5] = false; // isStringAttachment 
     1294        $this->attachment[$cur][6] = "inline"; 
     1295        $this->attachment[$cur][7] = $cid; 
     1296     
     1297        return true; 
     1298    } 
     1299     
     1300    /** 
     1301     * Returns true if an inline attachment is present. 
     1302     * @access private 
     1303     * @return bool 
     1304     */ 
     1305    function InlineImageExists() { 
     1306        $result = false; 
     1307        for($i = 0; $i < count($this->attachment); $i++) 
     1308        { 
     1309            if($this->attachment[$i][6] == "inline") 
     1310            { 
     1311                $result = true; 
     1312                break; 
     1313            } 
     1314        } 
     1315         
     1316        return $result; 
     1317    } 
     1318 
     1319    ///////////////////////////////////////////////// 
     1320    // MESSAGE RESET METHODS 
     1321    ///////////////////////////////////////////////// 
     1322 
     1323    /** 
     1324     * Clears all recipients assigned in the TO array.  Returns void. 
     1325     * @return void 
     1326     */ 
     1327    function ClearAddresses() { 
     1328        $this->to = array(); 
     1329    } 
     1330 
     1331    /** 
     1332     * Clears all recipients assigned in the CC array.  Returns void. 
     1333     * @return void 
     1334     */ 
     1335    function ClearCCs() { 
     1336        $this->cc = array(); 
     1337    } 
     1338 
     1339    /** 
     1340     * Clears all recipients assigned in the BCC array.  Returns void. 
     1341     * @return void 
     1342     */ 
     1343    function ClearBCCs() { 
     1344        $this->bcc = array(); 
     1345    } 
     1346 
     1347    /** 
     1348     * Clears all recipients assigned in the ReplyTo array.  Returns void. 
     1349     * @return void 
     1350     */ 
     1351    function ClearReplyTos() { 
     1352        $this->ReplyTo = array(); 
     1353    } 
     1354 
     1355    /** 
     1356     * Clears all recipients assigned in the TO, CC and BCC 
     1357     * array.  Returns void. 
     1358     * @return void 
     1359     */ 
     1360    function ClearAllRecipients() { 
     1361        $this->to = array(); 
     1362        $this->cc = array(); 
     1363        $this->bcc = array(); 
     1364    } 
     1365 
     1366    /** 
     1367     * Clears all previously set filesystem, string, and binary 
     1368     * attachments.  Returns void. 
     1369     * @return void 
     1370     */ 
     1371    function ClearAttachments() { 
     1372        $this->attachment = array(); 
     1373    } 
     1374 
     1375    /** 
     1376     * Clears all custom headers.  Returns void. 
     1377     * @return void 
     1378     */ 
     1379    function ClearCustomHeaders() { 
     1380        $this->CustomHeader = array(); 
     1381    } 
     1382 
     1383 
     1384    ///////////////////////////////////////////////// 
     1385    // MISCELLANEOUS METHODS 
     1386    ///////////////////////////////////////////////// 
     1387 
     1388    /** 
     1389     * Adds the error message to the error container. 
     1390     * Returns void. 
     1391     * @access private 
     1392     * @return void 
     1393     */ 
     1394    function SetError($msg) { 
     1395        $this->error_count++; 
     1396        $this->ErrorInfo = $msg; 
     1397    } 
     1398 
     1399    /** 
     1400     * Returns the proper RFC 822 formatted date.  
     1401     * @access private 
     1402     * @return string 
     1403     */ 
     1404    function RFCDate() { 
     1405        $tz = date("Z"); 
     1406        $tzs = ($tz < 0) ? "-" : "+"; 
     1407        $tz = abs($tz); 
     1408        $tz = ($tz/3600)*100 + ($tz%3600)/60; 
     1409        $result = sprintf("%s %s%04d", date("D, j M Y H:i:s"), $tzs, $tz); 
     1410 
     1411        return $result; 
     1412    } 
     1413     
     1414    /** 
     1415     * Returns the appropriate server variable.  Should work with both  
     1416     * PHP 4.1.0+ as well as older versions.  Returns an empty string  
     1417     * if nothing is found. 
     1418     * @access private 
     1419     * @return mixed 
     1420     */ 
     1421    function ServerVar($varName) { 
     1422        global $HTTP_SERVER_VARS; 
     1423        global $HTTP_ENV_VARS; 
     1424 
     1425        if(!isset($_SERVER)) 
     1426        { 
     1427            $_SERVER = $HTTP_SERVER_VARS; 
     1428            if(!isset($_SERVER["REMOTE_ADDR"])) 
     1429                $_SERVER = $HTTP_ENV_VARS; // must be Apache 
     1430        } 
     1431         
     1432        if(isset($_SERVER[$varName])) 
     1433            return $_SERVER[$varName]; 
     1434        else 
     1435            return ""; 
     1436    } 
     1437 
     1438    /** 
     1439     * Returns the server hostname or 'localhost.localdomain' if unknown. 
     1440     * @access private 
     1441     * @return string 
     1442     */ 
     1443    function ServerHostname() { 
     1444        if ($this->Hostname != "") 
     1445            $result = $this->Hostname; 
     1446        elseif ($this->ServerVar('SERVER_NAME') != "") 
     1447            $result = $this->ServerVar('SERVER_NAME'); 
     1448        else 
     1449            $result = "localhost.localdomain"; 
     1450 
     1451        return $result; 
     1452    } 
     1453 
     1454    /** 
     1455     * Returns a message in the appropriate language. 
     1456     * @access private 
     1457     * @return string 
     1458     */ 
     1459    function Lang($key) { 
     1460        if(count($this->language) < 1) 
     1461            $this->SetLanguage("en"); // set the default language 
     1462     
     1463        if(isset($this->language[$key])) 
     1464            return $this->language[$key]; 
     1465        else 
     1466            return "Language string failed to load: " . $key; 
     1467    } 
     1468     
     1469    /** 
     1470     * Returns true if an error occurred. 
     1471     * @return bool 
     1472     */ 
     1473    function IsError() { 
     1474        return ($this->error_count > 0); 
     1475    } 
     1476 
     1477    /** 
     1478     * Changes every end of line from CR or LF to CRLF.   
     1479     * @access private 
     1480     * @return string 
     1481     */ 
     1482    function FixEOL($str) { 
     1483        $str = str_replace("\r\n", "\n", $str); 
     1484        $str = str_replace("\r", "\n", $str); 
     1485        $str = str_replace("\n", $this->LE, $str); 
     1486        return $str; 
     1487    } 
     1488 
     1489    /** 
     1490     * Adds a custom header.  
     1491     * @return void 
     1492     */ 
     1493    function AddCustomHeader($custom_header) { 
     1494        $this->CustomHeader[] = explode(":", $custom_header, 2); 
     1495    } 
     1496} 
     1497 
     1498?> 
  • wp-includes/pluggable.php

     
    156156 
    157157if ( !function_exists('wp_mail') ) : 
    158158function wp_mail($to, $subject, $message, $headers = '') { 
    159         if( $headers == '' ) { 
     159        global $phpmailer; 
     160        error_log("mailing $subject\n", 0); 
     161        if ( !is_object( $phpmailer ) ) { 
     162                require_once(ABSPATH . WPINC . '/class-phpmailer.php'); 
     163                require_once(ABSPATH . WPINC . '/class-smtp.php'); 
     164                $phpmailer = new PHPMailer(); 
     165        } 
     166                 
     167        $mail = compact('to', 'subject', 'message', 'headers'); 
     168        $mail = apply_filters('wp_mail', $mail); 
     169        extract($mail); 
     170 
     171        if ( $headers == '' ) { 
    160172                $headers = "MIME-Version: 1.0\n" . 
    161173                        "From: wordpress@" . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME'])) . "\n" .  
    162174                        "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n"; 
    163175        } 
    164176 
    165         return @mail($to, $subject, $message, $headers); 
     177        $phpmailer->ClearAddresses(); 
     178        $phpmailer->ClearCCs(); 
     179        $phpmailer->ClearBCCs(); 
     180        $phpmailer->ClearReplyTos(); 
     181        $phpmailer->ClearAllRecipients(); 
     182        $phpmailer->ClearCustomHeaders(); 
     183 
     184        $phpmailer->FromName = "WordPress"; 
     185        $phpmailer->AddAddress("$to", ""); 
     186        $phpmailer->Subject = $subject; 
     187        $phpmailer->Body    = $message; 
     188        $phpmailer->IsHTML(false); 
     189        $phpmailer->IsMail(); // set mailer to use php mail() 
     190 
     191        do_action_ref_array('phpmailer_init', array(&$phpmailer)); 
     192 
     193        $mailheaders = (array) explode( "\n", $headers ); 
     194        foreach ( $mailheaders as $line ) { 
     195                $header = explode( ":", $line ); 
     196                switch ( trim( $header[0] ) ) { 
     197                        case "From": 
     198                                $from = trim( str_replace( '"', '', $header[1] ) ); 
     199                                if ( strpos( $from, '<' ) ) { 
     200                                        $phpmailer->FromName = str_replace( '"', '', substr( $header[1], 0, strpos( $header[1], '<' ) - 1 ) ); 
     201                                        $from = trim( substr( $from, strpos( $from, '<' ) + 1 ) ); 
     202                                        $from = str_replace( '>', '', $from ); 
     203                                } else { 
     204                                        $phpmailer->FromName = $from; 
     205                                } 
     206                                $phpmailer->From = trim( $from ); 
     207                                break; 
     208                        default: 
     209                                if ( $line != '' && $header[0] != 'MIME-Version' && $header[0] != 'Content-Type' ) 
     210                                        $phpmailer->AddCustomHeader( $line ); 
     211                                break; 
     212                } 
     213        } 
     214 
     215        $result = @$phpmailer->Send(); 
     216        error_log("mailing result $result\n", 0); 
     217        return $result; 
    166218} 
    167219endif; 
    168220 
  • wp-includes/class-smtp.php

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